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.VlanId;
26 import org.onlab.packet.IPv4;
27 import org.onlab.packet.Ip4Address;
28 import org.onlab.packet.Ip4Prefix;
29 import org.onlab.packet.IpAddress;
30 import org.onlab.packet.IpPrefix;
31 import org.onlab.util.KryoNamespace;
32 import org.onosproject.core.ApplicationId;
33 import org.onosproject.core.CoreService;
34 import org.onosproject.event.Event;
35 import org.onosproject.net.ConnectPoint;
36 import org.onosproject.net.config.ConfigFactory;
37 import org.onosproject.net.config.NetworkConfigEvent;
38 import org.onosproject.net.config.NetworkConfigRegistry;
39 import org.onosproject.net.config.NetworkConfigListener;
40 import org.onosproject.net.config.basics.SubjectFactories;
41 import org.onosproject.segmentrouting.config.SegmentRoutingConfig;
42 import org.onosproject.segmentrouting.grouphandler.DefaultGroupHandler;
43 import org.onosproject.segmentrouting.grouphandler.NeighborSet;
44 import org.onosproject.segmentrouting.grouphandler.NeighborSetNextObjectiveStoreKey;
45 import org.onosproject.mastership.MastershipService;
46 import org.onosproject.net.Device;
47 import org.onosproject.net.DeviceId;
48 import org.onosproject.net.Link;
49 import org.onosproject.net.Port;
50 import org.onosproject.net.device.DeviceEvent;
51 import org.onosproject.net.device.DeviceListener;
52 import org.onosproject.net.device.DeviceService;
53 import org.onosproject.net.flowobjective.FlowObjectiveService;
54 import org.onosproject.net.host.HostService;
55 import org.onosproject.net.intent.IntentService;
56 import org.onosproject.net.link.LinkEvent;
57 import org.onosproject.net.link.LinkListener;
58 import org.onosproject.net.link.LinkService;
59 import org.onosproject.net.packet.InboundPacket;
60 import org.onosproject.net.packet.PacketContext;
61 import org.onosproject.net.packet.PacketProcessor;
62 import org.onosproject.net.packet.PacketService;
63 import org.onosproject.net.topology.TopologyService;
64 import org.onosproject.segmentrouting.grouphandler.SubnetNextObjectiveStoreKey;
65 import org.onosproject.store.service.EventuallyConsistentMap;
66 import org.onosproject.store.service.EventuallyConsistentMapBuilder;
67 import org.onosproject.store.service.StorageService;
68 import org.onosproject.store.service.WallClockTimestamp;
69 import org.slf4j.Logger;
70 import org.slf4j.LoggerFactory;
73 import java.util.Collections;
74 import java.util.HashSet;
75 import java.util.List;
78 import java.util.concurrent.ConcurrentHashMap;
79 import java.util.concurrent.ConcurrentLinkedQueue;
80 import java.util.concurrent.Executors;
81 import java.util.concurrent.ScheduledExecutorService;
82 import java.util.concurrent.ScheduledFuture;
83 import java.util.concurrent.TimeUnit;
85 @SuppressWarnings("ALL")
87 @Component(immediate = true)
88 public class SegmentRoutingManager implements SegmentRoutingService {
90 private static Logger log = LoggerFactory
91 .getLogger(SegmentRoutingManager.class);
93 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
94 protected CoreService coreService;
96 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
97 protected TopologyService topologyService;
99 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
100 protected PacketService packetService;
102 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
103 protected IntentService intentService;
105 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
106 protected HostService hostService;
108 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
109 protected DeviceService deviceService;
111 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
112 protected FlowObjectiveService flowObjectiveService;
114 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
115 protected LinkService linkService;
117 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
118 protected MastershipService mastershipService;
120 protected ArpHandler arpHandler = null;
121 protected IcmpHandler icmpHandler = null;
122 protected IpHandler ipHandler = null;
123 protected RoutingRulePopulator routingRulePopulator = null;
124 protected ApplicationId appId;
125 protected DeviceConfiguration deviceConfiguration = null;
127 private DefaultRoutingHandler defaultRoutingHandler = null;
128 private TunnelHandler tunnelHandler = null;
129 private PolicyHandler policyHandler = null;
130 private InternalPacketProcessor processor = null;
131 private InternalLinkListener linkListener = null;
132 private InternalDeviceListener deviceListener = null;
133 private InternalEventHandler eventHandler = new InternalEventHandler();
135 private ScheduledExecutorService executorService = Executors
136 .newScheduledThreadPool(1);
138 private static ScheduledFuture<?> eventHandlerFuture = null;
139 private ConcurrentLinkedQueue<Event> eventQueue = new ConcurrentLinkedQueue<Event>();
140 private Map<DeviceId, DefaultGroupHandler> groupHandlerMap = new ConcurrentHashMap<DeviceId, DefaultGroupHandler>();
141 // Per device next objective ID store with (device id + neighbor set) as key
142 private EventuallyConsistentMap<NeighborSetNextObjectiveStoreKey,
143 Integer> nsNextObjStore = null;
144 private EventuallyConsistentMap<SubnetNextObjectiveStoreKey, Integer> subnetNextObjStore = null;
145 private EventuallyConsistentMap<String, Tunnel> tunnelStore = null;
146 private EventuallyConsistentMap<String, Policy> policyStore = null;
147 // Per device, per-subnet assigned-vlans store, with (device id + subnet
148 // IPv4 prefix) as key
149 private EventuallyConsistentMap<SubnetAssignedVidStoreKey, VlanId>
150 subnetVidStore = null;
152 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
153 protected StorageService storageService;
155 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
156 protected NetworkConfigRegistry cfgService;
158 private final InternalConfigListener cfgListener =
159 new InternalConfigListener(this);
161 private final ConfigFactory cfgFactory =
162 new ConfigFactory(SubjectFactories.DEVICE_SUBJECT_FACTORY,
163 SegmentRoutingConfig.class,
166 public SegmentRoutingConfig createConfig() {
167 return new SegmentRoutingConfig();
171 private Object threadSchedulerLock = new Object();
172 private static int numOfEventsQueued = 0;
173 private static int numOfEventsExecuted = 0;
174 private static int numOfHandlerExecution = 0;
175 private static int numOfHandlerScheduled = 0;
177 private KryoNamespace.Builder kryoBuilder = null;
179 private static final short ASSIGNED_VLAN_START = 4093;
180 public static final short ASSIGNED_VLAN_NO_SUBNET = 4094;
183 protected void activate() {
185 .registerApplication("org.onosproject.segmentrouting");
187 kryoBuilder = new KryoNamespace.Builder()
188 .register(NeighborSetNextObjectiveStoreKey.class,
189 SubnetNextObjectiveStoreKey.class,
190 SubnetAssignedVidStoreKey.class,
194 WallClockTimestamp.class,
195 org.onosproject.cluster.NodeId.class,
205 IpAddress.Version.class,
209 log.debug("Creating EC map nsnextobjectivestore");
210 EventuallyConsistentMapBuilder<NeighborSetNextObjectiveStoreKey, Integer>
211 nsNextObjMapBuilder = storageService.eventuallyConsistentMapBuilder();
213 nsNextObjStore = nsNextObjMapBuilder
214 .withName("nsnextobjectivestore")
215 .withSerializer(kryoBuilder)
216 .withTimestampProvider((k, v) -> new WallClockTimestamp())
218 log.trace("Current size {}", nsNextObjStore.size());
220 log.debug("Creating EC map subnetnextobjectivestore");
221 EventuallyConsistentMapBuilder<SubnetNextObjectiveStoreKey, Integer>
222 subnetNextObjMapBuilder = storageService.eventuallyConsistentMapBuilder();
224 subnetNextObjStore = subnetNextObjMapBuilder
225 .withName("subnetnextobjectivestore")
226 .withSerializer(kryoBuilder)
227 .withTimestampProvider((k, v) -> new WallClockTimestamp())
230 EventuallyConsistentMapBuilder<String, Tunnel> tunnelMapBuilder =
231 storageService.eventuallyConsistentMapBuilder();
233 tunnelStore = tunnelMapBuilder
234 .withName("tunnelstore")
235 .withSerializer(kryoBuilder)
236 .withTimestampProvider((k, v) -> new WallClockTimestamp())
239 EventuallyConsistentMapBuilder<String, Policy> policyMapBuilder =
240 storageService.eventuallyConsistentMapBuilder();
242 policyStore = policyMapBuilder
243 .withName("policystore")
244 .withSerializer(kryoBuilder)
245 .withTimestampProvider((k, v) -> new WallClockTimestamp())
248 EventuallyConsistentMapBuilder<SubnetAssignedVidStoreKey, VlanId>
249 subnetVidStoreMapBuilder = storageService.eventuallyConsistentMapBuilder();
251 subnetVidStore = subnetVidStoreMapBuilder
252 .withName("subnetvidstore")
253 .withSerializer(kryoBuilder)
254 .withTimestampProvider((k, v) -> new WallClockTimestamp())
257 cfgService.addListener(cfgListener);
258 cfgService.registerConfigFactory(cfgFactory);
260 processor = new InternalPacketProcessor();
261 linkListener = new InternalLinkListener();
262 deviceListener = new InternalDeviceListener();
264 packetService.addProcessor(processor, PacketProcessor.director(2));
265 linkService.addListener(linkListener);
266 deviceService.addListener(deviceListener);
268 cfgListener.configureNetwork();
274 protected void deactivate() {
275 cfgService.removeListener(cfgListener);
276 cfgService.unregisterConfigFactory(cfgFactory);
278 packetService.removeProcessor(processor);
279 linkService.removeListener(linkListener);
280 deviceService.removeListener(deviceListener);
283 deviceService = null;
285 groupHandlerMap.clear();
292 public List<Tunnel> getTunnels() {
293 return tunnelHandler.getTunnels();
297 public TunnelHandler.Result createTunnel(Tunnel tunnel) {
298 return tunnelHandler.createTunnel(tunnel);
302 public TunnelHandler.Result removeTunnel(Tunnel tunnel) {
303 for (Policy policy: policyHandler.getPolicies()) {
304 if (policy.type() == Policy.Type.TUNNEL_FLOW) {
305 TunnelPolicy tunnelPolicy = (TunnelPolicy) policy;
306 if (tunnelPolicy.tunnelId().equals(tunnel.id())) {
307 log.warn("Cannot remove the tunnel used by a policy");
308 return TunnelHandler.Result.TUNNEL_IN_USE;
312 return tunnelHandler.removeTunnel(tunnel);
316 public PolicyHandler.Result removePolicy(Policy policy) {
317 return policyHandler.removePolicy(policy);
321 public PolicyHandler.Result createPolicy(Policy policy) {
322 return policyHandler.createPolicy(policy);
326 public List<Policy> getPolicies() {
327 return policyHandler.getPolicies();
331 * Returns the tunnel object with the tunnel ID.
333 * @param tunnelId Tunnel ID
334 * @return Tunnel reference
336 public Tunnel getTunnel(String tunnelId) {
337 return tunnelHandler.getTunnel(tunnelId);
341 * Returns the vlan-id assigned to the subnet configured for a device.
342 * If no vlan-id has been assigned, a new one is assigned out of a pool of ids,
343 * if and only if this controller instance is the master for the device.
345 * USAGE: The assigned vlans are meant to be applied to untagged packets on those
346 * switches/pipelines that need this functionality. These vids are meant
347 * to be used internally within a switch, and thus need to be unique only
348 * on a switch level. Note that packets never go out on the wire with these
349 * vlans. Currently, vlan ids are assigned from value 4093 down.
350 * Vlan id 4094 expected to be used for all ports that are not assigned subnets.
351 * Vlan id 4095 is reserved and unused. Only a single vlan id is assigned
353 * XXX This method should avoid any vlans configured on the ports, but
354 * currently the app works only on untagged packets and as a result
355 * ignores any vlan configuration.
357 * @param deviceId switch dpid
358 * @param subnet IPv4 prefix for which assigned vlan is desired
359 * @return VlanId assigned for the subnet on the device, or
360 * null if no vlan assignment was found and this instance is not
361 * the master for the device.
363 public VlanId getSubnetAssignedVlanId(DeviceId deviceId, Ip4Prefix subnet) {
364 VlanId assignedVid = subnetVidStore.get(new SubnetAssignedVidStoreKey(
366 if (assignedVid != null) {
367 log.debug("Query for subnet:{} on device:{} returned assigned-vlan "
368 + "{}", subnet, deviceId, assignedVid);
371 //check mastership for the right to assign a vlan
372 if (!mastershipService.isLocalMaster(deviceId)) {
373 log.warn("This controller instance is not the master for device {}. "
374 + "Cannot assign vlan-id for subnet {}", deviceId, subnet);
377 // vlan assignment is expensive but done only once
378 Set<Ip4Prefix> configuredSubnets = deviceConfiguration.getSubnets(deviceId);
379 Set<Short> assignedVlans = new HashSet<>();
380 Set<Ip4Prefix> unassignedSubnets = new HashSet<>();
381 for (Ip4Prefix sub : configuredSubnets) {
382 VlanId v = subnetVidStore.get(new SubnetAssignedVidStoreKey(deviceId,
385 assignedVlans.add(v.toShort());
387 unassignedSubnets.add(sub);
390 short nextAssignedVlan = ASSIGNED_VLAN_START;
391 if (!assignedVlans.isEmpty()) {
392 nextAssignedVlan = (short) (Collections.min(assignedVlans) - 1);
394 for (Ip4Prefix unsub : unassignedSubnets) {
395 subnetVidStore.put(new SubnetAssignedVidStoreKey(deviceId, unsub),
396 VlanId.vlanId(nextAssignedVlan--));
397 log.info("Assigned vlan: {} to subnet: {} on device: {}",
398 nextAssignedVlan + 1, unsub, deviceId);
401 return subnetVidStore.get(new SubnetAssignedVidStoreKey(deviceId, subnet));
405 * Returns the next objective ID for the given NeighborSet.
406 * If the nextObjectiveID does not exist, a new one is created and returned.
408 * @param deviceId Device ID
409 * @param ns NegighborSet
410 * @return next objective ID
412 public int getNextObjectiveId(DeviceId deviceId, NeighborSet ns) {
413 if (groupHandlerMap.get(deviceId) != null) {
414 log.trace("getNextObjectiveId query in device {}", deviceId);
415 return groupHandlerMap
416 .get(deviceId).getNextObjectiveId(ns);
418 log.warn("getNextObjectiveId query in device {} not found", deviceId);
424 * Returns the next objective ID for the Subnet given. If the nextObjectiveID does not exist,
425 * a new one is created and returned.
427 * @param deviceId Device ID
428 * @param prefix Subnet
429 * @return next objective ID
431 public int getSubnetNextObjectiveId(DeviceId deviceId, IpPrefix prefix) {
432 if (groupHandlerMap.get(deviceId) != null) {
433 log.trace("getSubnetNextObjectiveId query in device {}", deviceId);
434 return groupHandlerMap
435 .get(deviceId).getSubnetNextObjectiveId(prefix);
437 log.warn("getSubnetNextObjectiveId query in device {} not found", deviceId);
442 private class InternalPacketProcessor implements PacketProcessor {
444 public void process(PacketContext context) {
446 if (context.isHandled()) {
450 InboundPacket pkt = context.inPacket();
451 Ethernet ethernet = pkt.parsed();
453 if (ethernet.getEtherType() == Ethernet.TYPE_ARP) {
454 arpHandler.processPacketIn(pkt);
455 } else if (ethernet.getEtherType() == Ethernet.TYPE_IPV4) {
456 IPv4 ipPacket = (IPv4) ethernet.getPayload();
457 ipHandler.addToPacketBuffer(ipPacket);
458 if (ipPacket.getProtocol() == IPv4.PROTOCOL_ICMP) {
459 icmpHandler.processPacketIn(pkt);
461 ipHandler.processPacketIn(pkt);
467 private class InternalLinkListener implements LinkListener {
469 public void event(LinkEvent event) {
470 if (event.type() == LinkEvent.Type.LINK_ADDED
471 || event.type() == LinkEvent.Type.LINK_REMOVED) {
472 log.debug("Event {} received from Link Service", event.type());
473 scheduleEventHandlerIfNotScheduled(event);
478 private class InternalDeviceListener implements DeviceListener {
480 public void event(DeviceEvent event) {
481 switch (event.type()) {
485 case DEVICE_AVAILABILITY_CHANGED:
486 log.debug("Event {} received from Device Service", event.type());
487 scheduleEventHandlerIfNotScheduled(event);
494 private void scheduleEventHandlerIfNotScheduled(Event event) {
495 synchronized (threadSchedulerLock) {
496 eventQueue.add(event);
499 if ((numOfHandlerScheduled - numOfHandlerExecution) == 0) {
500 //No pending scheduled event handling threads. So start a new one.
501 eventHandlerFuture = executorService
502 .schedule(eventHandler, 100, TimeUnit.MILLISECONDS);
503 numOfHandlerScheduled++;
505 log.trace("numOfEventsQueued {}, numOfEventHanlderScheduled {}",
507 numOfHandlerScheduled);
511 private class InternalEventHandler implements Runnable {
517 synchronized (threadSchedulerLock) {
518 if (!eventQueue.isEmpty()) {
519 event = eventQueue.poll();
520 numOfEventsExecuted++;
522 numOfHandlerExecution++;
523 log.debug("numOfHandlerExecution {} numOfEventsExecuted {}",
524 numOfHandlerExecution, numOfEventsExecuted);
528 if (event.type() == LinkEvent.Type.LINK_ADDED) {
529 processLinkAdded((Link) event.subject());
530 } else if (event.type() == LinkEvent.Type.LINK_REMOVED) {
531 processLinkRemoved((Link) event.subject());
532 } else if (event.type() == DeviceEvent.Type.DEVICE_ADDED ||
533 event.type() == DeviceEvent.Type.DEVICE_AVAILABILITY_CHANGED ||
534 event.type() == DeviceEvent.Type.DEVICE_UPDATED) {
535 if (deviceService.isAvailable(((Device) event.subject()).id())) {
536 log.info("Processing device event {} for available device {}",
537 event.type(), ((Device) event.subject()).id());
538 processDeviceAdded((Device) event.subject());
540 } else if (event.type() == DeviceEvent.Type.PORT_REMOVED) {
541 processPortRemoved((Device) event.subject(),
542 ((DeviceEvent) event).port());
544 log.warn("Unhandled event type: {}", event.type());
547 } catch (Exception e) {
548 log.error("SegmentRouting event handler "
549 + "thread thrown an exception: {}", e);
554 private void processLinkAdded(Link link) {
555 log.debug("A new link {} was added", link.toString());
557 //Irrespective whether the local is a MASTER or not for this device,
558 //create group handler instance and push default TTP flow rules.
559 //Because in a multi-instance setup, instances can initiate
560 //groups for any devices. Also the default TTP rules are needed
561 //to be pushed before inserting any IP table entries for any device
562 DefaultGroupHandler groupHandler = groupHandlerMap.get(link.src()
564 if (groupHandler != null) {
565 groupHandler.linkUp(link);
567 Device device = deviceService.getDevice(link.src().deviceId());
568 if (device != null) {
569 log.warn("processLinkAdded: Link Added "
570 + "Notification without Device Added "
571 + "event, still handling it");
572 processDeviceAdded(device);
573 groupHandler = groupHandlerMap.get(link.src()
575 groupHandler.linkUp(link);
579 log.trace("Starting optimized route population process");
580 defaultRoutingHandler.populateRoutingRulesForLinkStatusChange(null);
581 //log.trace("processLinkAdded: re-starting route population process");
582 //defaultRoutingHandler.startPopulationProcess();
585 private void processLinkRemoved(Link link) {
586 log.debug("A link {} was removed", link.toString());
587 DefaultGroupHandler groupHandler = groupHandlerMap.get(link.src().deviceId());
588 if (groupHandler != null) {
589 groupHandler.portDown(link.src().port());
591 log.trace("Starting optimized route population process");
592 defaultRoutingHandler.populateRoutingRulesForLinkStatusChange(link);
593 //log.trace("processLinkRemoved: re-starting route population process");
594 //defaultRoutingHandler.startPopulationProcess();
597 private void processDeviceAdded(Device device) {
598 log.debug("A new device with ID {} was added", device.id());
599 if (deviceConfiguration == null) {
600 log.warn("Device configuration uploading. Device {} will be "
601 + "processed after config completes.", device.id());
604 // Irrespective of whether the local is a MASTER or not for this device,
605 // we need to create a SR-group-handler instance. This is because in a
606 // multi-instance setup, any instance can initiate forwarding/next-objectives
607 // for any switch (even if this instance is a SLAVE or not even connected
608 // to the switch). To handle this, a default-group-handler instance is necessary
610 if (groupHandlerMap.get(device.id()) == null) {
611 DefaultGroupHandler groupHandler = DefaultGroupHandler.
612 createGroupHandler(device.id(),
616 flowObjectiveService,
619 groupHandlerMap.put(device.id(), groupHandler);
620 // Also, in some cases, drivers may need extra
621 // information to process rules (eg. Router IP/MAC); and so, we send
622 // port addressing rules to the driver as well irrespective of whether
623 // this instance is the master or not.
624 defaultRoutingHandler.populatePortAddressingRules(device.id());
626 if (mastershipService.isLocalMaster(device.id())) {
627 DefaultGroupHandler groupHandler = groupHandlerMap.get(device.id());
628 groupHandler.createGroupsFromSubnetConfig();
632 private void processPortRemoved(Device device, Port port) {
633 log.debug("Port {} was removed", port.toString());
634 DefaultGroupHandler groupHandler = groupHandlerMap.get(device.id());
635 if (groupHandler != null) {
636 groupHandler.portDown(port.number());
640 private class InternalConfigListener implements NetworkConfigListener {
641 SegmentRoutingManager segmentRoutingManager;
643 public InternalConfigListener(SegmentRoutingManager srMgr) {
644 this.segmentRoutingManager = srMgr;
647 public void configureNetwork() {
648 deviceConfiguration = new DeviceConfiguration(segmentRoutingManager.cfgService);
650 arpHandler = new ArpHandler(segmentRoutingManager);
651 icmpHandler = new IcmpHandler(segmentRoutingManager);
652 ipHandler = new IpHandler(segmentRoutingManager);
653 routingRulePopulator = new RoutingRulePopulator(segmentRoutingManager);
654 defaultRoutingHandler = new DefaultRoutingHandler(segmentRoutingManager);
656 tunnelHandler = new TunnelHandler(linkService, deviceConfiguration,
657 groupHandlerMap, tunnelStore);
658 policyHandler = new PolicyHandler(appId, deviceConfiguration,
659 flowObjectiveService,
660 tunnelHandler, policyStore);
662 for (Device device : deviceService.getDevices()) {
663 // Irrespective of whether the local is a MASTER or not for this device,
664 // we need to create a SR-group-handler instance. This is because in a
665 // multi-instance setup, any instance can initiate forwarding/next-objectives
666 // for any switch (even if this instance is a SLAVE or not even connected
667 // to the switch). To handle this, a default-group-handler instance is necessary
669 if (groupHandlerMap.get(device.id()) == null) {
670 DefaultGroupHandler groupHandler = DefaultGroupHandler
671 .createGroupHandler(device.id(), appId,
672 deviceConfiguration, linkService,
673 flowObjectiveService,
676 groupHandlerMap.put(device.id(), groupHandler);
678 // Also, in some cases, drivers may need extra
679 // information to process rules (eg. Router IP/MAC); and so, we send
680 // port addressing rules to the driver as well, irrespective of whether
681 // this instance is the master or not.
682 defaultRoutingHandler.populatePortAddressingRules(device.id());
684 if (mastershipService.isLocalMaster(device.id())) {
685 DefaultGroupHandler groupHandler = groupHandlerMap.get(device.id());
686 groupHandler.createGroupsFromSubnetConfig();
690 defaultRoutingHandler.startPopulationProcess();
694 public void event(NetworkConfigEvent event) {
695 if (event.configClass().equals(SegmentRoutingConfig.class)) {
696 if (event.type() == NetworkConfigEvent.Type.CONFIG_ADDED) {
697 log.info("Network configuration added.");
700 if (event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED) {
701 log.info("Network configuration updated.");
702 // TODO support dynamic configuration