2 * Copyright 2015 Open Networking Laboratory
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package org.onosproject.segmentrouting;
18 import org.apache.felix.scr.annotations.Activate;
19 import org.apache.felix.scr.annotations.Component;
20 import org.apache.felix.scr.annotations.Deactivate;
21 import org.apache.felix.scr.annotations.Reference;
22 import org.apache.felix.scr.annotations.ReferenceCardinality;
23 import org.apache.felix.scr.annotations.Service;
24 import org.onlab.packet.Ethernet;
25 import org.onlab.packet.MacAddress;
26 import org.onlab.packet.VlanId;
27 import org.onlab.packet.IPv4;
28 import org.onlab.packet.Ip4Address;
29 import org.onlab.packet.Ip4Prefix;
30 import org.onlab.packet.IpAddress;
31 import org.onlab.packet.IpPrefix;
32 import org.onlab.util.KryoNamespace;
33 import org.onosproject.core.ApplicationId;
34 import org.onosproject.core.CoreService;
35 import org.onosproject.event.Event;
36 import org.onosproject.net.ConnectPoint;
37 import org.onosproject.net.PortNumber;
38 import org.onosproject.net.config.ConfigFactory;
39 import org.onosproject.net.config.NetworkConfigEvent;
40 import org.onosproject.net.config.NetworkConfigRegistry;
41 import org.onosproject.net.config.NetworkConfigListener;
42 import org.onosproject.net.config.basics.SubjectFactories;
43 import org.onosproject.net.flow.DefaultTrafficSelector;
44 import org.onosproject.net.flow.DefaultTrafficTreatment;
45 import org.onosproject.net.flow.TrafficSelector;
46 import org.onosproject.net.flow.TrafficTreatment;
47 import org.onosproject.net.flowobjective.DefaultForwardingObjective;
48 import org.onosproject.net.flowobjective.ForwardingObjective;
49 import org.onosproject.net.flowobjective.Objective;
50 import org.onosproject.net.flowobjective.ObjectiveContext;
51 import org.onosproject.net.flowobjective.ObjectiveError;
52 import org.onosproject.net.host.HostEvent;
53 import org.onosproject.net.host.HostListener;
54 import org.onosproject.segmentrouting.config.DeviceConfigNotFoundException;
55 import org.onosproject.segmentrouting.config.DeviceConfiguration;
56 import org.onosproject.segmentrouting.config.SegmentRoutingConfig;
57 import org.onosproject.segmentrouting.grouphandler.DefaultGroupHandler;
58 import org.onosproject.segmentrouting.grouphandler.NeighborSet;
59 import org.onosproject.segmentrouting.grouphandler.NeighborSetNextObjectiveStoreKey;
60 import org.onosproject.mastership.MastershipService;
61 import org.onosproject.net.Device;
62 import org.onosproject.net.DeviceId;
63 import org.onosproject.net.Link;
64 import org.onosproject.net.Port;
65 import org.onosproject.net.device.DeviceEvent;
66 import org.onosproject.net.device.DeviceListener;
67 import org.onosproject.net.device.DeviceService;
68 import org.onosproject.net.flowobjective.FlowObjectiveService;
69 import org.onosproject.net.host.HostService;
70 import org.onosproject.net.intent.IntentService;
71 import org.onosproject.net.link.LinkEvent;
72 import org.onosproject.net.link.LinkListener;
73 import org.onosproject.net.link.LinkService;
74 import org.onosproject.net.packet.InboundPacket;
75 import org.onosproject.net.packet.PacketContext;
76 import org.onosproject.net.packet.PacketProcessor;
77 import org.onosproject.net.packet.PacketService;
78 import org.onosproject.net.topology.TopologyService;
79 import org.onosproject.segmentrouting.grouphandler.SubnetNextObjectiveStoreKey;
80 import org.onosproject.store.service.EventuallyConsistentMap;
81 import org.onosproject.store.service.EventuallyConsistentMapBuilder;
82 import org.onosproject.store.service.StorageService;
83 import org.onosproject.store.service.WallClockTimestamp;
84 import org.slf4j.Logger;
85 import org.slf4j.LoggerFactory;
88 import java.util.Collections;
89 import java.util.HashSet;
90 import java.util.List;
93 import java.util.concurrent.ConcurrentHashMap;
94 import java.util.concurrent.ConcurrentLinkedQueue;
95 import java.util.concurrent.Executors;
96 import java.util.concurrent.ScheduledExecutorService;
97 import java.util.concurrent.ScheduledFuture;
98 import java.util.concurrent.TimeUnit;
100 @SuppressWarnings("ALL")
102 @Component(immediate = true)
103 public class SegmentRoutingManager implements SegmentRoutingService {
105 private static Logger log = LoggerFactory
106 .getLogger(SegmentRoutingManager.class);
108 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
109 protected CoreService coreService;
111 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
112 protected TopologyService topologyService;
114 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
115 protected PacketService packetService;
117 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
118 protected IntentService intentService;
120 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
121 protected HostService hostService;
123 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
124 protected DeviceService deviceService;
126 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
127 protected FlowObjectiveService flowObjectiveService;
129 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
130 protected LinkService linkService;
132 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
133 protected MastershipService mastershipService;
135 protected ArpHandler arpHandler = null;
136 protected IcmpHandler icmpHandler = null;
137 protected IpHandler ipHandler = null;
138 protected RoutingRulePopulator routingRulePopulator = null;
139 protected ApplicationId appId;
140 protected DeviceConfiguration deviceConfiguration = null;
142 private DefaultRoutingHandler defaultRoutingHandler = null;
143 private TunnelHandler tunnelHandler = null;
144 private PolicyHandler policyHandler = null;
145 private InternalPacketProcessor processor = null;
146 private InternalLinkListener linkListener = null;
147 private InternalDeviceListener deviceListener = null;
148 private InternalEventHandler eventHandler = new InternalEventHandler();
150 private ScheduledExecutorService executorService = Executors
151 .newScheduledThreadPool(1);
153 private static ScheduledFuture<?> eventHandlerFuture = null;
154 private ConcurrentLinkedQueue<Event> eventQueue = new ConcurrentLinkedQueue<Event>();
155 private Map<DeviceId, DefaultGroupHandler> groupHandlerMap =
156 new ConcurrentHashMap<DeviceId, DefaultGroupHandler>();
157 // Per device next objective ID store with (device id + neighbor set) as key
158 private EventuallyConsistentMap<NeighborSetNextObjectiveStoreKey, Integer>
159 nsNextObjStore = null;
160 private EventuallyConsistentMap<SubnetNextObjectiveStoreKey, Integer>
161 subnetNextObjStore = null;
162 private EventuallyConsistentMap<String, Tunnel> tunnelStore = null;
163 private EventuallyConsistentMap<String, Policy> policyStore = null;
164 // Per device, per-subnet assigned-vlans store, with (device id + subnet
165 // IPv4 prefix) as key
166 private EventuallyConsistentMap<SubnetAssignedVidStoreKey, VlanId>
167 subnetVidStore = null;
169 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
170 protected StorageService storageService;
172 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
173 protected NetworkConfigRegistry cfgService;
175 private final InternalConfigListener cfgListener =
176 new InternalConfigListener(this);
178 private final ConfigFactory cfgFactory =
179 new ConfigFactory(SubjectFactories.DEVICE_SUBJECT_FACTORY,
180 SegmentRoutingConfig.class,
183 public SegmentRoutingConfig createConfig() {
184 return new SegmentRoutingConfig();
188 private final HostListener hostListener = new InternalHostListener();
190 private Object threadSchedulerLock = new Object();
191 private static int numOfEventsQueued = 0;
192 private static int numOfEventsExecuted = 0;
193 private static int numOfHandlerExecution = 0;
194 private static int numOfHandlerScheduled = 0;
196 private KryoNamespace.Builder kryoBuilder = null;
198 private static final short ASSIGNED_VLAN_START = 4093;
199 public static final short ASSIGNED_VLAN_NO_SUBNET = 4094;
202 protected void activate() {
204 .registerApplication("org.onosproject.segmentrouting");
206 kryoBuilder = new KryoNamespace.Builder()
207 .register(NeighborSetNextObjectiveStoreKey.class,
208 SubnetNextObjectiveStoreKey.class,
209 SubnetAssignedVidStoreKey.class,
213 WallClockTimestamp.class,
214 org.onosproject.cluster.NodeId.class,
224 IpAddress.Version.class,
228 log.debug("Creating EC map nsnextobjectivestore");
229 EventuallyConsistentMapBuilder<NeighborSetNextObjectiveStoreKey, Integer>
230 nsNextObjMapBuilder = storageService.eventuallyConsistentMapBuilder();
232 nsNextObjStore = nsNextObjMapBuilder
233 .withName("nsnextobjectivestore")
234 .withSerializer(kryoBuilder)
235 .withTimestampProvider((k, v) -> new WallClockTimestamp())
237 log.trace("Current size {}", nsNextObjStore.size());
239 log.debug("Creating EC map subnetnextobjectivestore");
240 EventuallyConsistentMapBuilder<SubnetNextObjectiveStoreKey, Integer>
241 subnetNextObjMapBuilder = storageService.eventuallyConsistentMapBuilder();
243 subnetNextObjStore = subnetNextObjMapBuilder
244 .withName("subnetnextobjectivestore")
245 .withSerializer(kryoBuilder)
246 .withTimestampProvider((k, v) -> new WallClockTimestamp())
249 EventuallyConsistentMapBuilder<String, Tunnel> tunnelMapBuilder =
250 storageService.eventuallyConsistentMapBuilder();
252 tunnelStore = tunnelMapBuilder
253 .withName("tunnelstore")
254 .withSerializer(kryoBuilder)
255 .withTimestampProvider((k, v) -> new WallClockTimestamp())
258 EventuallyConsistentMapBuilder<String, Policy> policyMapBuilder =
259 storageService.eventuallyConsistentMapBuilder();
261 policyStore = policyMapBuilder
262 .withName("policystore")
263 .withSerializer(kryoBuilder)
264 .withTimestampProvider((k, v) -> new WallClockTimestamp())
267 EventuallyConsistentMapBuilder<SubnetAssignedVidStoreKey, VlanId>
268 subnetVidStoreMapBuilder = storageService.eventuallyConsistentMapBuilder();
270 subnetVidStore = subnetVidStoreMapBuilder
271 .withName("subnetvidstore")
272 .withSerializer(kryoBuilder)
273 .withTimestampProvider((k, v) -> new WallClockTimestamp())
276 cfgService.addListener(cfgListener);
277 cfgService.registerConfigFactory(cfgFactory);
279 hostService.addListener(hostListener);
281 processor = new InternalPacketProcessor();
282 linkListener = new InternalLinkListener();
283 deviceListener = new InternalDeviceListener();
285 packetService.addProcessor(processor, PacketProcessor.director(2));
286 linkService.addListener(linkListener);
287 deviceService.addListener(deviceListener);
289 cfgListener.configureNetwork();
295 protected void deactivate() {
296 cfgService.removeListener(cfgListener);
297 cfgService.unregisterConfigFactory(cfgFactory);
299 packetService.removeProcessor(processor);
300 linkService.removeListener(linkListener);
301 deviceService.removeListener(deviceListener);
304 deviceService = null;
306 groupHandlerMap.clear();
313 public List<Tunnel> getTunnels() {
314 return tunnelHandler.getTunnels();
318 public TunnelHandler.Result createTunnel(Tunnel tunnel) {
319 return tunnelHandler.createTunnel(tunnel);
323 public TunnelHandler.Result removeTunnel(Tunnel tunnel) {
324 for (Policy policy: policyHandler.getPolicies()) {
325 if (policy.type() == Policy.Type.TUNNEL_FLOW) {
326 TunnelPolicy tunnelPolicy = (TunnelPolicy) policy;
327 if (tunnelPolicy.tunnelId().equals(tunnel.id())) {
328 log.warn("Cannot remove the tunnel used by a policy");
329 return TunnelHandler.Result.TUNNEL_IN_USE;
333 return tunnelHandler.removeTunnel(tunnel);
337 public PolicyHandler.Result removePolicy(Policy policy) {
338 return policyHandler.removePolicy(policy);
342 public PolicyHandler.Result createPolicy(Policy policy) {
343 return policyHandler.createPolicy(policy);
347 public List<Policy> getPolicies() {
348 return policyHandler.getPolicies();
352 * Returns the tunnel object with the tunnel ID.
354 * @param tunnelId Tunnel ID
355 * @return Tunnel reference
357 public Tunnel getTunnel(String tunnelId) {
358 return tunnelHandler.getTunnel(tunnelId);
362 * Returns the vlan-id assigned to the subnet configured for a device.
363 * If no vlan-id has been assigned, a new one is assigned out of a pool of ids,
364 * if and only if this controller instance is the master for the device.
366 * USAGE: The assigned vlans are meant to be applied to untagged packets on those
367 * switches/pipelines that need this functionality. These vids are meant
368 * to be used internally within a switch, and thus need to be unique only
369 * on a switch level. Note that packets never go out on the wire with these
370 * vlans. Currently, vlan ids are assigned from value 4093 down.
371 * Vlan id 4094 expected to be used for all ports that are not assigned subnets.
372 * Vlan id 4095 is reserved and unused. Only a single vlan id is assigned
374 * XXX This method should avoid any vlans configured on the ports, but
375 * currently the app works only on untagged packets and as a result
376 * ignores any vlan configuration.
378 * @param deviceId switch dpid
379 * @param subnet IPv4 prefix for which assigned vlan is desired
380 * @return VlanId assigned for the subnet on the device, or
381 * null if no vlan assignment was found and this instance is not
382 * the master for the device.
384 public VlanId getSubnetAssignedVlanId(DeviceId deviceId, Ip4Prefix subnet) {
385 VlanId assignedVid = subnetVidStore.get(new SubnetAssignedVidStoreKey(
387 if (assignedVid != null) {
388 log.debug("Query for subnet:{} on device:{} returned assigned-vlan "
389 + "{}", subnet, deviceId, assignedVid);
392 //check mastership for the right to assign a vlan
393 if (!mastershipService.isLocalMaster(deviceId)) {
394 log.warn("This controller instance is not the master for device {}. "
395 + "Cannot assign vlan-id for subnet {}", deviceId, subnet);
398 // vlan assignment is expensive but done only once
399 Set<Ip4Prefix> configuredSubnets = deviceConfiguration.getSubnets(deviceId);
400 Set<Short> assignedVlans = new HashSet<>();
401 Set<Ip4Prefix> unassignedSubnets = new HashSet<>();
402 for (Ip4Prefix sub : configuredSubnets) {
403 VlanId v = subnetVidStore.get(new SubnetAssignedVidStoreKey(deviceId,
406 assignedVlans.add(v.toShort());
408 unassignedSubnets.add(sub);
411 short nextAssignedVlan = ASSIGNED_VLAN_START;
412 if (!assignedVlans.isEmpty()) {
413 nextAssignedVlan = (short) (Collections.min(assignedVlans) - 1);
415 for (Ip4Prefix unsub : unassignedSubnets) {
416 subnetVidStore.put(new SubnetAssignedVidStoreKey(deviceId, unsub),
417 VlanId.vlanId(nextAssignedVlan--));
418 log.info("Assigned vlan: {} to subnet: {} on device: {}",
419 nextAssignedVlan + 1, unsub, deviceId);
422 return subnetVidStore.get(new SubnetAssignedVidStoreKey(deviceId, subnet));
426 * Returns the next objective ID for the given NeighborSet.
427 * If the nextObjectiveID does not exist, a new one is created and returned.
429 * @param deviceId Device ID
430 * @param ns NegighborSet
431 * @return next objective ID
433 public int getNextObjectiveId(DeviceId deviceId, NeighborSet ns) {
434 if (groupHandlerMap.get(deviceId) != null) {
435 log.trace("getNextObjectiveId query in device {}", deviceId);
436 return groupHandlerMap
437 .get(deviceId).getNextObjectiveId(ns);
439 log.warn("getNextObjectiveId query in device {} not found", deviceId);
445 * Returns the next objective ID for the Subnet given. If the nextObjectiveID does not exist,
446 * a new one is created and returned.
448 * @param deviceId Device ID
449 * @param prefix Subnet
450 * @return next objective ID
452 public int getSubnetNextObjectiveId(DeviceId deviceId, IpPrefix prefix) {
453 if (groupHandlerMap.get(deviceId) != null) {
454 log.trace("getSubnetNextObjectiveId query in device {}", deviceId);
455 return groupHandlerMap
456 .get(deviceId).getSubnetNextObjectiveId(prefix);
458 log.warn("getSubnetNextObjectiveId query in device {} not found", deviceId);
463 private class InternalPacketProcessor implements PacketProcessor {
465 public void process(PacketContext context) {
467 if (context.isHandled()) {
471 InboundPacket pkt = context.inPacket();
472 Ethernet ethernet = pkt.parsed();
474 if (ethernet.getEtherType() == Ethernet.TYPE_ARP) {
475 arpHandler.processPacketIn(pkt);
476 } else if (ethernet.getEtherType() == Ethernet.TYPE_IPV4) {
477 IPv4 ipPacket = (IPv4) ethernet.getPayload();
478 ipHandler.addToPacketBuffer(ipPacket);
479 if (ipPacket.getProtocol() == IPv4.PROTOCOL_ICMP) {
480 icmpHandler.processPacketIn(pkt);
482 ipHandler.processPacketIn(pkt);
488 private class InternalLinkListener implements LinkListener {
490 public void event(LinkEvent event) {
491 if (event.type() == LinkEvent.Type.LINK_ADDED
492 || event.type() == LinkEvent.Type.LINK_REMOVED) {
493 log.debug("Event {} received from Link Service", event.type());
494 scheduleEventHandlerIfNotScheduled(event);
499 private class InternalDeviceListener implements DeviceListener {
501 public void event(DeviceEvent event) {
502 switch (event.type()) {
506 case DEVICE_AVAILABILITY_CHANGED:
507 log.debug("Event {} received from Device Service", event.type());
508 scheduleEventHandlerIfNotScheduled(event);
515 private void scheduleEventHandlerIfNotScheduled(Event event) {
516 synchronized (threadSchedulerLock) {
517 eventQueue.add(event);
520 if ((numOfHandlerScheduled - numOfHandlerExecution) == 0) {
521 //No pending scheduled event handling threads. So start a new one.
522 eventHandlerFuture = executorService
523 .schedule(eventHandler, 100, TimeUnit.MILLISECONDS);
524 numOfHandlerScheduled++;
526 log.trace("numOfEventsQueued {}, numOfEventHanlderScheduled {}",
528 numOfHandlerScheduled);
532 private class InternalEventHandler implements Runnable {
538 synchronized (threadSchedulerLock) {
539 if (!eventQueue.isEmpty()) {
540 event = eventQueue.poll();
541 numOfEventsExecuted++;
543 numOfHandlerExecution++;
544 log.debug("numOfHandlerExecution {} numOfEventsExecuted {}",
545 numOfHandlerExecution, numOfEventsExecuted);
549 if (event.type() == LinkEvent.Type.LINK_ADDED) {
550 processLinkAdded((Link) event.subject());
551 } else if (event.type() == LinkEvent.Type.LINK_REMOVED) {
552 processLinkRemoved((Link) event.subject());
553 } else if (event.type() == DeviceEvent.Type.DEVICE_ADDED ||
554 event.type() == DeviceEvent.Type.DEVICE_AVAILABILITY_CHANGED ||
555 event.type() == DeviceEvent.Type.DEVICE_UPDATED) {
556 if (deviceService.isAvailable(((Device) event.subject()).id())) {
557 log.info("Processing device event {} for available device {}",
558 event.type(), ((Device) event.subject()).id());
559 processDeviceAdded((Device) event.subject());
561 } else if (event.type() == DeviceEvent.Type.PORT_REMOVED) {
562 processPortRemoved((Device) event.subject(),
563 ((DeviceEvent) event).port());
565 log.warn("Unhandled event type: {}", event.type());
568 } catch (Exception e) {
569 log.error("SegmentRouting event handler "
570 + "thread thrown an exception: {}", e);
575 private void processLinkAdded(Link link) {
576 log.debug("A new link {} was added", link.toString());
577 if (!deviceConfiguration.isConfigured(link.src().deviceId())) {
578 log.warn("Source device of this link is not configured.");
581 //Irrespective whether the local is a MASTER or not for this device,
582 //create group handler instance and push default TTP flow rules.
583 //Because in a multi-instance setup, instances can initiate
584 //groups for any devices. Also the default TTP rules are needed
585 //to be pushed before inserting any IP table entries for any device
586 DefaultGroupHandler groupHandler = groupHandlerMap.get(link.src()
588 if (groupHandler != null) {
589 groupHandler.linkUp(link);
591 Device device = deviceService.getDevice(link.src().deviceId());
592 if (device != null) {
593 log.warn("processLinkAdded: Link Added "
594 + "Notification without Device Added "
595 + "event, still handling it");
596 processDeviceAdded(device);
597 groupHandler = groupHandlerMap.get(link.src()
599 groupHandler.linkUp(link);
603 log.trace("Starting optimized route population process");
604 defaultRoutingHandler.populateRoutingRulesForLinkStatusChange(null);
605 //log.trace("processLinkAdded: re-starting route population process");
606 //defaultRoutingHandler.startPopulationProcess();
609 private void processLinkRemoved(Link link) {
610 log.debug("A link {} was removed", link.toString());
611 DefaultGroupHandler groupHandler = groupHandlerMap.get(link.src().deviceId());
612 if (groupHandler != null) {
613 groupHandler.portDown(link.src().port());
615 log.trace("Starting optimized route population process");
616 defaultRoutingHandler.populateRoutingRulesForLinkStatusChange(link);
617 //log.trace("processLinkRemoved: re-starting route population process");
618 //defaultRoutingHandler.startPopulationProcess();
621 private void processDeviceAdded(Device device) {
622 log.debug("A new device with ID {} was added", device.id());
623 if (deviceConfiguration == null || !deviceConfiguration.isConfigured(device.id())) {
624 log.warn("Device configuration uploading. Device {} will be "
625 + "processed after config completes.", device.id());
628 // Irrespective of whether the local is a MASTER or not for this device,
629 // we need to create a SR-group-handler instance. This is because in a
630 // multi-instance setup, any instance can initiate forwarding/next-objectives
631 // for any switch (even if this instance is a SLAVE or not even connected
632 // to the switch). To handle this, a default-group-handler instance is necessary
634 if (groupHandlerMap.get(device.id()) == null) {
635 DefaultGroupHandler groupHandler;
637 groupHandler = DefaultGroupHandler.
638 createGroupHandler(device.id(),
642 flowObjectiveService,
645 } catch (DeviceConfigNotFoundException e) {
646 log.warn(e.getMessage() + " Aborting processDeviceAdded.");
649 groupHandlerMap.put(device.id(), groupHandler);
650 // Also, in some cases, drivers may need extra
651 // information to process rules (eg. Router IP/MAC); and so, we send
652 // port addressing rules to the driver as well irrespective of whether
653 // this instance is the master or not.
654 defaultRoutingHandler.populatePortAddressingRules(device.id());
656 if (mastershipService.isLocalMaster(device.id())) {
657 DefaultGroupHandler groupHandler = groupHandlerMap.get(device.id());
658 groupHandler.createGroupsFromSubnetConfig();
659 routingRulePopulator.populateSubnetBroadcastRule(device.id());
663 private void processPortRemoved(Device device, Port port) {
664 log.debug("Port {} was removed", port.toString());
665 DefaultGroupHandler groupHandler = groupHandlerMap.get(device.id());
666 if (groupHandler != null) {
667 groupHandler.portDown(port.number());
671 private class InternalConfigListener implements NetworkConfigListener {
672 SegmentRoutingManager segmentRoutingManager;
674 public InternalConfigListener(SegmentRoutingManager srMgr) {
675 this.segmentRoutingManager = srMgr;
678 public void configureNetwork() {
679 deviceConfiguration = new DeviceConfiguration(segmentRoutingManager.cfgService);
681 arpHandler = new ArpHandler(segmentRoutingManager);
682 icmpHandler = new IcmpHandler(segmentRoutingManager);
683 ipHandler = new IpHandler(segmentRoutingManager);
684 routingRulePopulator = new RoutingRulePopulator(segmentRoutingManager);
685 defaultRoutingHandler = new DefaultRoutingHandler(segmentRoutingManager);
687 tunnelHandler = new TunnelHandler(linkService, deviceConfiguration,
688 groupHandlerMap, tunnelStore);
689 policyHandler = new PolicyHandler(appId, deviceConfiguration,
690 flowObjectiveService,
691 tunnelHandler, policyStore);
693 for (Device device : deviceService.getDevices()) {
694 // Irrespective of whether the local is a MASTER or not for this device,
695 // we need to create a SR-group-handler instance. This is because in a
696 // multi-instance setup, any instance can initiate forwarding/next-objectives
697 // for any switch (even if this instance is a SLAVE or not even connected
698 // to the switch). To handle this, a default-group-handler instance is necessary
700 if (groupHandlerMap.get(device.id()) == null) {
701 DefaultGroupHandler groupHandler;
703 groupHandler = DefaultGroupHandler.
704 createGroupHandler(device.id(),
708 flowObjectiveService,
711 } catch (DeviceConfigNotFoundException e) {
712 log.warn(e.getMessage() + " Aborting configureNetwork.");
715 groupHandlerMap.put(device.id(), groupHandler);
717 // Also, in some cases, drivers may need extra
718 // information to process rules (eg. Router IP/MAC); and so, we send
719 // port addressing rules to the driver as well, irrespective of whether
720 // this instance is the master or not.
721 defaultRoutingHandler.populatePortAddressingRules(device.id());
723 if (mastershipService.isLocalMaster(device.id())) {
724 DefaultGroupHandler groupHandler = groupHandlerMap.get(device.id());
725 groupHandler.createGroupsFromSubnetConfig();
726 routingRulePopulator.populateSubnetBroadcastRule(device.id());
730 defaultRoutingHandler.startPopulationProcess();
734 public void event(NetworkConfigEvent event) {
735 if (event.configClass().equals(SegmentRoutingConfig.class)) {
736 if (event.type() == NetworkConfigEvent.Type.CONFIG_ADDED) {
737 log.info("Network configuration added.");
740 if (event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED) {
741 log.info("Network configuration updated.");
742 // TODO support dynamic configuration
748 private class InternalHostListener implements HostListener {
749 private ForwardingObjective.Builder getForwardingObjectiveBuilder(
750 MacAddress mac, VlanId vlanId, PortNumber port) {
751 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
752 sbuilder.matchEthDst(mac);
753 sbuilder.matchVlanId(vlanId);
755 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
756 // TODO Move popVlan from flow action to group action
757 tbuilder.immediate().popVlan();
758 tbuilder.immediate().setOutput(port);
760 return DefaultForwardingObjective.builder()
761 .withFlag(ForwardingObjective.Flag.SPECIFIC)
762 .withSelector(sbuilder.build())
763 .withTreatment(tbuilder.build())
769 private void processHostAddedEvent(HostEvent event) {
770 MacAddress mac = event.subject().mac();
771 VlanId vlanId = event.subject().vlan();
772 DeviceId deviceId = event.subject().location().deviceId();
773 PortNumber port = event.subject().location().port();
774 Set<IpAddress> ips = event.subject().ipAddresses();
775 log.debug("Host {}/{} is added at {}:{}", mac, vlanId, deviceId, port);
777 // TODO Move bridging table population to a separate class
778 // Populate bridging table entry
779 ForwardingObjective.Builder fob =
780 getForwardingObjectiveBuilder(mac, vlanId, port);
781 flowObjectiveService.forward(deviceId, fob.add(
782 new BridgingTableObjectiveContext(mac, vlanId)
785 // Populate IP table entry
788 routingRulePopulator.populateIpRuleForHost(
789 deviceId, ip.getIp4Address(), mac, port);
794 private void processHostRemoveEvent(HostEvent event) {
795 MacAddress mac = event.subject().mac();
796 VlanId vlanId = event.subject().vlan();
797 DeviceId deviceId = event.subject().location().deviceId();
798 PortNumber port = event.subject().location().port();
799 Set<IpAddress> ips = event.subject().ipAddresses();
800 log.debug("Host {}/{} is removed from {}:{}", mac, vlanId, deviceId, port);
802 // Revoke bridging table entry
803 ForwardingObjective.Builder fob =
804 getForwardingObjectiveBuilder(mac, vlanId, port);
805 flowObjectiveService.forward(deviceId, fob.remove(
806 new BridgingTableObjectiveContext(mac, vlanId)
809 // Revoke IP table entry
812 routingRulePopulator.revokeIpRuleForHost(
813 deviceId, ip.getIp4Address(), mac, port);
818 private void processHostMovedEvent(HostEvent event) {
819 MacAddress mac = event.subject().mac();
820 VlanId vlanId = event.subject().vlan();
821 DeviceId prevDeviceId = event.prevSubject().location().deviceId();
822 PortNumber prevPort = event.prevSubject().location().port();
823 Set<IpAddress> prevIps = event.prevSubject().ipAddresses();
824 DeviceId newDeviceId = event.subject().location().deviceId();
825 PortNumber newPort = event.subject().location().port();
826 Set<IpAddress> newIps = event.subject().ipAddresses();
827 log.debug("Host {}/{} is moved from {}:{} to {}:{}",
828 mac, vlanId, prevDeviceId, prevPort, newDeviceId, newPort);
830 // Revoke previous bridging table entry
831 ForwardingObjective.Builder prevFob =
832 getForwardingObjectiveBuilder(mac, vlanId, prevPort);
833 flowObjectiveService.forward(prevDeviceId, prevFob.remove(
834 new BridgingTableObjectiveContext(mac, vlanId)
837 // Revoke previous IP table entry
838 prevIps.forEach(ip -> {
840 routingRulePopulator.revokeIpRuleForHost(
841 prevDeviceId, ip.getIp4Address(), mac, prevPort);
845 // Populate new bridging table entry
846 ForwardingObjective.Builder newFob =
847 getForwardingObjectiveBuilder(mac, vlanId, prevPort);
848 flowObjectiveService.forward(newDeviceId, newFob.add(
849 new BridgingTableObjectiveContext(mac, vlanId)
852 // Populate new IP table entry
853 newIps.forEach(ip -> {
855 routingRulePopulator.populateIpRuleForHost(
856 newDeviceId, ip.getIp4Address(), mac, newPort);
861 private void processHostUpdatedEvent(HostEvent event) {
862 MacAddress mac = event.subject().mac();
863 VlanId vlanId = event.subject().vlan();
864 DeviceId prevDeviceId = event.prevSubject().location().deviceId();
865 PortNumber prevPort = event.prevSubject().location().port();
866 Set<IpAddress> prevIps = event.prevSubject().ipAddresses();
867 DeviceId newDeviceId = event.subject().location().deviceId();
868 PortNumber newPort = event.subject().location().port();
869 Set<IpAddress> newIps = event.subject().ipAddresses();
870 log.debug("Host {}/{} is updated", mac, vlanId);
872 // Revoke previous IP table entry
873 prevIps.forEach(ip -> {
875 routingRulePopulator.revokeIpRuleForHost(
876 prevDeviceId, ip.getIp4Address(), mac, prevPort);
880 // Populate new IP table entry
881 newIps.forEach(ip -> {
883 routingRulePopulator.populateIpRuleForHost(
884 newDeviceId, ip.getIp4Address(), mac, newPort);
890 public void event(HostEvent event) {
891 // Do not proceed without mastership
892 DeviceId deviceId = event.subject().location().deviceId();
893 if (!mastershipService.isLocalMaster(deviceId)) {
897 switch (event.type()) {
899 processHostAddedEvent(event);
902 processHostMovedEvent(event);
905 processHostRemoveEvent(event);
908 processHostUpdatedEvent(event);
911 log.warn("Unsupported host event type: {}", event.type());
917 private static class BridgingTableObjectiveContext implements ObjectiveContext {
918 final MacAddress mac;
921 BridgingTableObjectiveContext(MacAddress mac, VlanId vlanId) {
923 this.vlanId = vlanId;
927 public void onSuccess(Objective objective) {
928 if (objective.op() == Objective.Operation.ADD) {
929 log.debug("Successfully populate bridging table entry for {}/{}",
932 log.debug("Successfully revoke bridging table entry for {}/{}",
938 public void onError(Objective objective, ObjectiveError error) {
939 if (objective.op() == Objective.Operation.ADD) {
940 log.debug("Fail to populate bridging table entry for {}/{}. {}",
943 log.debug("Fail to revoke bridging table entry for {}/{}. {}",