b82752d6234f4e015ac0c2c58c32b4e096c962c4
[onosfw.git] /
1 /*
2  * Copyright 2015 Open Networking Laboratory
3  *
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
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16 package org.onosproject.segmentrouting;
17
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;
71
72 import java.net.URI;
73 import java.util.Collections;
74 import java.util.HashSet;
75 import java.util.List;
76 import java.util.Map;
77 import java.util.Set;
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;
84
85 @SuppressWarnings("ALL")
86 @Service
87 @Component(immediate = true)
88 public class SegmentRoutingManager implements SegmentRoutingService {
89
90     private static Logger log = LoggerFactory
91             .getLogger(SegmentRoutingManager.class);
92
93     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
94     protected CoreService coreService;
95
96     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
97     protected TopologyService topologyService;
98
99     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
100     protected PacketService packetService;
101
102     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
103     protected IntentService intentService;
104
105     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
106     protected HostService hostService;
107
108     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
109     protected DeviceService deviceService;
110
111     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
112     protected FlowObjectiveService flowObjectiveService;
113
114     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
115     protected LinkService linkService;
116
117     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
118     protected MastershipService mastershipService;
119
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;
126
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();
134
135     private ScheduledExecutorService executorService = Executors
136             .newScheduledThreadPool(1);
137
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;
151
152     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
153     protected StorageService storageService;
154
155     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
156     protected NetworkConfigRegistry cfgService;
157
158     private final InternalConfigListener cfgListener =
159             new InternalConfigListener(this);
160
161     private final ConfigFactory cfgFactory =
162             new ConfigFactory(SubjectFactories.DEVICE_SUBJECT_FACTORY,
163                               SegmentRoutingConfig.class,
164                               "segmentrouting") {
165                 @Override
166                 public SegmentRoutingConfig createConfig() {
167                     return new SegmentRoutingConfig();
168                 }
169             };
170
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;
176
177     private KryoNamespace.Builder kryoBuilder = null;
178
179     private static final short ASSIGNED_VLAN_START = 4093;
180     public static final short ASSIGNED_VLAN_NO_SUBNET = 4094;
181
182     @Activate
183     protected void activate() {
184         appId = coreService
185                 .registerApplication("org.onosproject.segmentrouting");
186
187         kryoBuilder = new KryoNamespace.Builder()
188             .register(NeighborSetNextObjectiveStoreKey.class,
189                     SubnetNextObjectiveStoreKey.class,
190                     SubnetAssignedVidStoreKey.class,
191                     NeighborSet.class,
192                     DeviceId.class,
193                     URI.class,
194                     WallClockTimestamp.class,
195                     org.onosproject.cluster.NodeId.class,
196                     HashSet.class,
197                     Tunnel.class,
198                     DefaultTunnel.class,
199                     Policy.class,
200                     TunnelPolicy.class,
201                     Policy.Type.class,
202                     VlanId.class,
203                     Ip4Address.class,
204                     Ip4Prefix.class,
205                     IpAddress.Version.class,
206                     ConnectPoint.class
207             );
208
209         log.debug("Creating EC map nsnextobjectivestore");
210         EventuallyConsistentMapBuilder<NeighborSetNextObjectiveStoreKey, Integer>
211                 nsNextObjMapBuilder = storageService.eventuallyConsistentMapBuilder();
212
213         nsNextObjStore = nsNextObjMapBuilder
214                 .withName("nsnextobjectivestore")
215                 .withSerializer(kryoBuilder)
216                 .withTimestampProvider((k, v) -> new WallClockTimestamp())
217                 .build();
218         log.trace("Current size {}", nsNextObjStore.size());
219
220         log.debug("Creating EC map subnetnextobjectivestore");
221         EventuallyConsistentMapBuilder<SubnetNextObjectiveStoreKey, Integer>
222                 subnetNextObjMapBuilder = storageService.eventuallyConsistentMapBuilder();
223
224         subnetNextObjStore = subnetNextObjMapBuilder
225                 .withName("subnetnextobjectivestore")
226                 .withSerializer(kryoBuilder)
227                 .withTimestampProvider((k, v) -> new WallClockTimestamp())
228                 .build();
229
230         EventuallyConsistentMapBuilder<String, Tunnel> tunnelMapBuilder =
231                 storageService.eventuallyConsistentMapBuilder();
232
233         tunnelStore = tunnelMapBuilder
234                 .withName("tunnelstore")
235                 .withSerializer(kryoBuilder)
236                 .withTimestampProvider((k, v) -> new WallClockTimestamp())
237                 .build();
238
239         EventuallyConsistentMapBuilder<String, Policy> policyMapBuilder =
240                 storageService.eventuallyConsistentMapBuilder();
241
242         policyStore = policyMapBuilder
243                 .withName("policystore")
244                 .withSerializer(kryoBuilder)
245                 .withTimestampProvider((k, v) -> new WallClockTimestamp())
246                 .build();
247
248         EventuallyConsistentMapBuilder<SubnetAssignedVidStoreKey, VlanId>
249             subnetVidStoreMapBuilder = storageService.eventuallyConsistentMapBuilder();
250
251         subnetVidStore = subnetVidStoreMapBuilder
252                 .withName("subnetvidstore")
253                 .withSerializer(kryoBuilder)
254                 .withTimestampProvider((k, v) -> new WallClockTimestamp())
255                 .build();
256
257         cfgService.addListener(cfgListener);
258         cfgService.registerConfigFactory(cfgFactory);
259
260         processor = new InternalPacketProcessor();
261         linkListener = new InternalLinkListener();
262         deviceListener = new InternalDeviceListener();
263
264         packetService.addProcessor(processor, PacketProcessor.director(2));
265         linkService.addListener(linkListener);
266         deviceService.addListener(deviceListener);
267
268         cfgListener.configureNetwork();
269
270         log.info("Started");
271     }
272
273     @Deactivate
274     protected void deactivate() {
275         cfgService.removeListener(cfgListener);
276         cfgService.unregisterConfigFactory(cfgFactory);
277
278         packetService.removeProcessor(processor);
279         linkService.removeListener(linkListener);
280         deviceService.removeListener(deviceListener);
281         processor = null;
282         linkListener = null;
283         deviceService = null;
284
285         groupHandlerMap.clear();
286
287         log.info("Stopped");
288     }
289
290
291     @Override
292     public List<Tunnel> getTunnels() {
293         return tunnelHandler.getTunnels();
294     }
295
296     @Override
297     public TunnelHandler.Result createTunnel(Tunnel tunnel) {
298         return tunnelHandler.createTunnel(tunnel);
299     }
300
301     @Override
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;
309                 }
310             }
311         }
312         return tunnelHandler.removeTunnel(tunnel);
313     }
314
315     @Override
316     public PolicyHandler.Result removePolicy(Policy policy) {
317         return policyHandler.removePolicy(policy);
318     }
319
320     @Override
321     public PolicyHandler.Result createPolicy(Policy policy) {
322         return policyHandler.createPolicy(policy);
323     }
324
325     @Override
326     public List<Policy> getPolicies() {
327         return policyHandler.getPolicies();
328     }
329
330     /**
331      * Returns the tunnel object with the tunnel ID.
332      *
333      * @param tunnelId Tunnel ID
334      * @return Tunnel reference
335      */
336     public Tunnel getTunnel(String tunnelId) {
337         return tunnelHandler.getTunnel(tunnelId);
338     }
339
340     /**
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.
344      * <p>
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
352      * per subnet.
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.
356      *
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.
362      */
363     public VlanId getSubnetAssignedVlanId(DeviceId deviceId, Ip4Prefix subnet) {
364         VlanId assignedVid = subnetVidStore.get(new SubnetAssignedVidStoreKey(
365                                                         deviceId, subnet));
366         if (assignedVid != null) {
367             log.debug("Query for subnet:{} on device:{} returned assigned-vlan "
368                     + "{}", subnet, deviceId, assignedVid);
369             return assignedVid;
370         }
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);
375             return null;
376         }
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,
383                                                                         sub));
384             if (v != null) {
385                 assignedVlans.add(v.toShort());
386             } else {
387                 unassignedSubnets.add(sub);
388             }
389         }
390         short nextAssignedVlan = ASSIGNED_VLAN_START;
391         if (!assignedVlans.isEmpty()) {
392             nextAssignedVlan = (short) (Collections.min(assignedVlans) - 1);
393         }
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);
399         }
400
401         return subnetVidStore.get(new SubnetAssignedVidStoreKey(deviceId, subnet));
402     }
403
404     /**
405      * Returns the next objective ID for the given NeighborSet.
406      * If the nextObjectiveID does not exist, a new one is created and returned.
407      *
408      * @param deviceId Device ID
409      * @param ns NegighborSet
410      * @return next objective ID
411      */
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);
417         } else {
418             log.warn("getNextObjectiveId query in device {} not found", deviceId);
419             return -1;
420         }
421     }
422
423     /**
424      * Returns the next objective ID for the Subnet given. If the nextObjectiveID does not exist,
425      * a new one is created and returned.
426      *
427      * @param deviceId Device ID
428      * @param prefix Subnet
429      * @return next objective ID
430      */
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);
436         } else {
437             log.warn("getSubnetNextObjectiveId query in device {} not found", deviceId);
438             return -1;
439         }
440     }
441
442     private class InternalPacketProcessor implements PacketProcessor {
443         @Override
444         public void process(PacketContext context) {
445
446             if (context.isHandled()) {
447                 return;
448             }
449
450             InboundPacket pkt = context.inPacket();
451             Ethernet ethernet = pkt.parsed();
452
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);
460                 } else {
461                     ipHandler.processPacketIn(pkt);
462                 }
463             }
464         }
465     }
466
467     private class InternalLinkListener implements LinkListener {
468         @Override
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);
474             }
475         }
476     }
477
478     private class InternalDeviceListener implements DeviceListener {
479         @Override
480         public void event(DeviceEvent event) {
481             switch (event.type()) {
482             case DEVICE_ADDED:
483             case PORT_REMOVED:
484             case DEVICE_UPDATED:
485             case DEVICE_AVAILABILITY_CHANGED:
486                 log.debug("Event {} received from Device Service", event.type());
487                 scheduleEventHandlerIfNotScheduled(event);
488                 break;
489             default:
490             }
491         }
492     }
493
494     private void scheduleEventHandlerIfNotScheduled(Event event) {
495         synchronized (threadSchedulerLock) {
496             eventQueue.add(event);
497             numOfEventsQueued++;
498
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++;
504             }
505             log.trace("numOfEventsQueued {}, numOfEventHanlderScheduled {}",
506                       numOfEventsQueued,
507                       numOfHandlerScheduled);
508         }
509     }
510
511     private class InternalEventHandler implements Runnable {
512         @Override
513         public void run() {
514             try {
515                 while (true) {
516                     Event event = null;
517                     synchronized (threadSchedulerLock) {
518                         if (!eventQueue.isEmpty()) {
519                             event = eventQueue.poll();
520                             numOfEventsExecuted++;
521                         } else {
522                             numOfHandlerExecution++;
523                             log.debug("numOfHandlerExecution {} numOfEventsExecuted {}",
524                                       numOfHandlerExecution, numOfEventsExecuted);
525                             break;
526                         }
527                     }
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());
539                         }
540                     } else if (event.type() == DeviceEvent.Type.PORT_REMOVED) {
541                         processPortRemoved((Device) event.subject(),
542                                            ((DeviceEvent) event).port());
543                     } else {
544                         log.warn("Unhandled event type: {}", event.type());
545                     }
546                 }
547             } catch (Exception e) {
548                 log.error("SegmentRouting event handler "
549                         + "thread thrown an exception: {}", e);
550             }
551         }
552     }
553
554     private void processLinkAdded(Link link) {
555         log.debug("A new link {} was added", link.toString());
556
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()
563                 .deviceId());
564         if (groupHandler != null) {
565             groupHandler.linkUp(link);
566         } else {
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()
574                                                    .deviceId());
575                 groupHandler.linkUp(link);
576             }
577         }
578
579         log.trace("Starting optimized route population process");
580         defaultRoutingHandler.populateRoutingRulesForLinkStatusChange(null);
581         //log.trace("processLinkAdded: re-starting route population process");
582         //defaultRoutingHandler.startPopulationProcess();
583     }
584
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());
590         }
591         log.trace("Starting optimized route population process");
592         defaultRoutingHandler.populateRoutingRulesForLinkStatusChange(link);
593         //log.trace("processLinkRemoved: re-starting route population process");
594         //defaultRoutingHandler.startPopulationProcess();
595     }
596
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());
602             return;
603         }
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
609         // per switch.
610         if (groupHandlerMap.get(device.id()) == null) {
611             DefaultGroupHandler groupHandler = DefaultGroupHandler.
612                     createGroupHandler(device.id(),
613                                        appId,
614                                        deviceConfiguration,
615                                        linkService,
616                                        flowObjectiveService,
617                                        nsNextObjStore,
618                                        subnetNextObjStore);
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());
625         }
626         if (mastershipService.isLocalMaster(device.id())) {
627             DefaultGroupHandler groupHandler = groupHandlerMap.get(device.id());
628             groupHandler.createGroupsFromSubnetConfig();
629         }
630     }
631
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());
637         }
638     }
639
640     private class InternalConfigListener implements NetworkConfigListener {
641         SegmentRoutingManager segmentRoutingManager;
642
643         public InternalConfigListener(SegmentRoutingManager srMgr) {
644             this.segmentRoutingManager = srMgr;
645         }
646
647         public void configureNetwork() {
648             deviceConfiguration = new DeviceConfiguration(segmentRoutingManager.cfgService);
649
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);
655
656             tunnelHandler = new TunnelHandler(linkService, deviceConfiguration,
657                                               groupHandlerMap, tunnelStore);
658             policyHandler = new PolicyHandler(appId, deviceConfiguration,
659                                               flowObjectiveService,
660                                               tunnelHandler, policyStore);
661
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
668                 // per switch.
669                 if (groupHandlerMap.get(device.id()) == null) {
670                     DefaultGroupHandler groupHandler = DefaultGroupHandler
671                             .createGroupHandler(device.id(), appId,
672                                                 deviceConfiguration, linkService,
673                                                 flowObjectiveService,
674                                                 nsNextObjStore,
675                                                 subnetNextObjStore);
676                     groupHandlerMap.put(device.id(), groupHandler);
677
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());
683                 }
684                 if (mastershipService.isLocalMaster(device.id())) {
685                     DefaultGroupHandler groupHandler = groupHandlerMap.get(device.id());
686                     groupHandler.createGroupsFromSubnetConfig();
687                 }
688             }
689
690             defaultRoutingHandler.startPopulationProcess();
691         }
692
693         @Override
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.");
698                     configureNetwork();
699                 }
700                 if (event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED) {
701                     log.info("Network configuration updated.");
702                     // TODO support dynamic configuration
703                 }
704             }
705         }
706     }
707 }