787f934731f49c4decd48ec70d35dca16c94cd0d
[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.DeviceConfigNotFoundException;
42 import org.onosproject.segmentrouting.config.DeviceConfiguration;
43 import org.onosproject.segmentrouting.config.SegmentRoutingConfig;
44 import org.onosproject.segmentrouting.grouphandler.DefaultGroupHandler;
45 import org.onosproject.segmentrouting.grouphandler.NeighborSet;
46 import org.onosproject.segmentrouting.grouphandler.NeighborSetNextObjectiveStoreKey;
47 import org.onosproject.mastership.MastershipService;
48 import org.onosproject.net.Device;
49 import org.onosproject.net.DeviceId;
50 import org.onosproject.net.Link;
51 import org.onosproject.net.Port;
52 import org.onosproject.net.device.DeviceEvent;
53 import org.onosproject.net.device.DeviceListener;
54 import org.onosproject.net.device.DeviceService;
55 import org.onosproject.net.flowobjective.FlowObjectiveService;
56 import org.onosproject.net.host.HostService;
57 import org.onosproject.net.intent.IntentService;
58 import org.onosproject.net.link.LinkEvent;
59 import org.onosproject.net.link.LinkListener;
60 import org.onosproject.net.link.LinkService;
61 import org.onosproject.net.packet.InboundPacket;
62 import org.onosproject.net.packet.PacketContext;
63 import org.onosproject.net.packet.PacketProcessor;
64 import org.onosproject.net.packet.PacketService;
65 import org.onosproject.net.topology.TopologyService;
66 import org.onosproject.segmentrouting.grouphandler.SubnetNextObjectiveStoreKey;
67 import org.onosproject.store.service.EventuallyConsistentMap;
68 import org.onosproject.store.service.EventuallyConsistentMapBuilder;
69 import org.onosproject.store.service.StorageService;
70 import org.onosproject.store.service.WallClockTimestamp;
71 import org.slf4j.Logger;
72 import org.slf4j.LoggerFactory;
73
74 import java.net.URI;
75 import java.util.Collections;
76 import java.util.HashSet;
77 import java.util.List;
78 import java.util.Map;
79 import java.util.Set;
80 import java.util.concurrent.ConcurrentHashMap;
81 import java.util.concurrent.ConcurrentLinkedQueue;
82 import java.util.concurrent.Executors;
83 import java.util.concurrent.ScheduledExecutorService;
84 import java.util.concurrent.ScheduledFuture;
85 import java.util.concurrent.TimeUnit;
86
87 @SuppressWarnings("ALL")
88 @Service
89 @Component(immediate = true)
90 public class SegmentRoutingManager implements SegmentRoutingService {
91
92     private static Logger log = LoggerFactory
93             .getLogger(SegmentRoutingManager.class);
94
95     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
96     protected CoreService coreService;
97
98     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
99     protected TopologyService topologyService;
100
101     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
102     protected PacketService packetService;
103
104     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
105     protected IntentService intentService;
106
107     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
108     protected HostService hostService;
109
110     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
111     protected DeviceService deviceService;
112
113     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
114     protected FlowObjectiveService flowObjectiveService;
115
116     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
117     protected LinkService linkService;
118
119     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
120     protected MastershipService mastershipService;
121
122     protected ArpHandler arpHandler = null;
123     protected IcmpHandler icmpHandler = null;
124     protected IpHandler ipHandler = null;
125     protected RoutingRulePopulator routingRulePopulator = null;
126     protected ApplicationId appId;
127     protected DeviceConfiguration deviceConfiguration = null;
128
129     private DefaultRoutingHandler defaultRoutingHandler = null;
130     private TunnelHandler tunnelHandler = null;
131     private PolicyHandler policyHandler = null;
132     private InternalPacketProcessor processor = null;
133     private InternalLinkListener linkListener = null;
134     private InternalDeviceListener deviceListener = null;
135     private InternalEventHandler eventHandler = new InternalEventHandler();
136
137     private ScheduledExecutorService executorService = Executors
138             .newScheduledThreadPool(1);
139
140     private static ScheduledFuture<?> eventHandlerFuture = null;
141     private ConcurrentLinkedQueue<Event> eventQueue = new ConcurrentLinkedQueue<Event>();
142     private Map<DeviceId, DefaultGroupHandler> groupHandlerMap = new ConcurrentHashMap<DeviceId, DefaultGroupHandler>();
143     // Per device next objective ID store with (device id + neighbor set) as key
144     private EventuallyConsistentMap<NeighborSetNextObjectiveStoreKey,
145         Integer> nsNextObjStore = null;
146     private EventuallyConsistentMap<SubnetNextObjectiveStoreKey, Integer> subnetNextObjStore = null;
147     private EventuallyConsistentMap<String, Tunnel> tunnelStore = null;
148     private EventuallyConsistentMap<String, Policy> policyStore = null;
149     // Per device, per-subnet assigned-vlans store, with (device id + subnet
150     // IPv4 prefix) as key
151     private EventuallyConsistentMap<SubnetAssignedVidStoreKey, VlanId>
152         subnetVidStore = null;
153
154     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
155     protected StorageService storageService;
156
157     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
158     protected NetworkConfigRegistry cfgService;
159
160     private final InternalConfigListener cfgListener =
161             new InternalConfigListener(this);
162
163     private final ConfigFactory cfgFactory =
164             new ConfigFactory(SubjectFactories.DEVICE_SUBJECT_FACTORY,
165                               SegmentRoutingConfig.class,
166                               "segmentrouting") {
167                 @Override
168                 public SegmentRoutingConfig createConfig() {
169                     return new SegmentRoutingConfig();
170                 }
171             };
172
173     private Object threadSchedulerLock = new Object();
174     private static int numOfEventsQueued = 0;
175     private static int numOfEventsExecuted = 0;
176     private static int numOfHandlerExecution = 0;
177     private static int numOfHandlerScheduled = 0;
178
179     private KryoNamespace.Builder kryoBuilder = null;
180
181     private static final short ASSIGNED_VLAN_START = 4093;
182     public static final short ASSIGNED_VLAN_NO_SUBNET = 4094;
183
184     @Activate
185     protected void activate() {
186         appId = coreService
187                 .registerApplication("org.onosproject.segmentrouting");
188
189         kryoBuilder = new KryoNamespace.Builder()
190             .register(NeighborSetNextObjectiveStoreKey.class,
191                     SubnetNextObjectiveStoreKey.class,
192                     SubnetAssignedVidStoreKey.class,
193                     NeighborSet.class,
194                     DeviceId.class,
195                     URI.class,
196                     WallClockTimestamp.class,
197                     org.onosproject.cluster.NodeId.class,
198                     HashSet.class,
199                     Tunnel.class,
200                     DefaultTunnel.class,
201                     Policy.class,
202                     TunnelPolicy.class,
203                     Policy.Type.class,
204                     VlanId.class,
205                     Ip4Address.class,
206                     Ip4Prefix.class,
207                     IpAddress.Version.class,
208                     ConnectPoint.class
209             );
210
211         log.debug("Creating EC map nsnextobjectivestore");
212         EventuallyConsistentMapBuilder<NeighborSetNextObjectiveStoreKey, Integer>
213                 nsNextObjMapBuilder = storageService.eventuallyConsistentMapBuilder();
214
215         nsNextObjStore = nsNextObjMapBuilder
216                 .withName("nsnextobjectivestore")
217                 .withSerializer(kryoBuilder)
218                 .withTimestampProvider((k, v) -> new WallClockTimestamp())
219                 .build();
220         log.trace("Current size {}", nsNextObjStore.size());
221
222         log.debug("Creating EC map subnetnextobjectivestore");
223         EventuallyConsistentMapBuilder<SubnetNextObjectiveStoreKey, Integer>
224                 subnetNextObjMapBuilder = storageService.eventuallyConsistentMapBuilder();
225
226         subnetNextObjStore = subnetNextObjMapBuilder
227                 .withName("subnetnextobjectivestore")
228                 .withSerializer(kryoBuilder)
229                 .withTimestampProvider((k, v) -> new WallClockTimestamp())
230                 .build();
231
232         EventuallyConsistentMapBuilder<String, Tunnel> tunnelMapBuilder =
233                 storageService.eventuallyConsistentMapBuilder();
234
235         tunnelStore = tunnelMapBuilder
236                 .withName("tunnelstore")
237                 .withSerializer(kryoBuilder)
238                 .withTimestampProvider((k, v) -> new WallClockTimestamp())
239                 .build();
240
241         EventuallyConsistentMapBuilder<String, Policy> policyMapBuilder =
242                 storageService.eventuallyConsistentMapBuilder();
243
244         policyStore = policyMapBuilder
245                 .withName("policystore")
246                 .withSerializer(kryoBuilder)
247                 .withTimestampProvider((k, v) -> new WallClockTimestamp())
248                 .build();
249
250         EventuallyConsistentMapBuilder<SubnetAssignedVidStoreKey, VlanId>
251             subnetVidStoreMapBuilder = storageService.eventuallyConsistentMapBuilder();
252
253         subnetVidStore = subnetVidStoreMapBuilder
254                 .withName("subnetvidstore")
255                 .withSerializer(kryoBuilder)
256                 .withTimestampProvider((k, v) -> new WallClockTimestamp())
257                 .build();
258
259         cfgService.addListener(cfgListener);
260         cfgService.registerConfigFactory(cfgFactory);
261
262         processor = new InternalPacketProcessor();
263         linkListener = new InternalLinkListener();
264         deviceListener = new InternalDeviceListener();
265
266         packetService.addProcessor(processor, PacketProcessor.director(2));
267         linkService.addListener(linkListener);
268         deviceService.addListener(deviceListener);
269
270         cfgListener.configureNetwork();
271
272         log.info("Started");
273     }
274
275     @Deactivate
276     protected void deactivate() {
277         cfgService.removeListener(cfgListener);
278         cfgService.unregisterConfigFactory(cfgFactory);
279
280         packetService.removeProcessor(processor);
281         linkService.removeListener(linkListener);
282         deviceService.removeListener(deviceListener);
283         processor = null;
284         linkListener = null;
285         deviceService = null;
286
287         groupHandlerMap.clear();
288
289         log.info("Stopped");
290     }
291
292
293     @Override
294     public List<Tunnel> getTunnels() {
295         return tunnelHandler.getTunnels();
296     }
297
298     @Override
299     public TunnelHandler.Result createTunnel(Tunnel tunnel) {
300         return tunnelHandler.createTunnel(tunnel);
301     }
302
303     @Override
304     public TunnelHandler.Result removeTunnel(Tunnel tunnel) {
305         for (Policy policy: policyHandler.getPolicies()) {
306             if (policy.type() == Policy.Type.TUNNEL_FLOW) {
307                 TunnelPolicy tunnelPolicy = (TunnelPolicy) policy;
308                 if (tunnelPolicy.tunnelId().equals(tunnel.id())) {
309                     log.warn("Cannot remove the tunnel used by a policy");
310                     return TunnelHandler.Result.TUNNEL_IN_USE;
311                 }
312             }
313         }
314         return tunnelHandler.removeTunnel(tunnel);
315     }
316
317     @Override
318     public PolicyHandler.Result removePolicy(Policy policy) {
319         return policyHandler.removePolicy(policy);
320     }
321
322     @Override
323     public PolicyHandler.Result createPolicy(Policy policy) {
324         return policyHandler.createPolicy(policy);
325     }
326
327     @Override
328     public List<Policy> getPolicies() {
329         return policyHandler.getPolicies();
330     }
331
332     /**
333      * Returns the tunnel object with the tunnel ID.
334      *
335      * @param tunnelId Tunnel ID
336      * @return Tunnel reference
337      */
338     public Tunnel getTunnel(String tunnelId) {
339         return tunnelHandler.getTunnel(tunnelId);
340     }
341
342     /**
343      * Returns the vlan-id assigned to the subnet configured for a device.
344      * If no vlan-id has been assigned, a new one is assigned out of a pool of ids,
345      * if and only if this controller instance is the master for the device.
346      * <p>
347      * USAGE: The assigned vlans are meant to be applied to untagged packets on those
348      * switches/pipelines that need this functionality. These vids are meant
349      * to be used internally within a switch, and thus need to be unique only
350      * on a switch level. Note that packets never go out on the wire with these
351      * vlans. Currently, vlan ids are assigned from value 4093 down.
352      * Vlan id 4094 expected to be used for all ports that are not assigned subnets.
353      * Vlan id 4095 is reserved and unused. Only a single vlan id is assigned
354      * per subnet.
355      * XXX This method should avoid any vlans configured on the ports, but
356      *     currently the app works only on untagged packets and as a result
357      *     ignores any vlan configuration.
358      *
359      * @param deviceId switch dpid
360      * @param subnet IPv4 prefix for which assigned vlan is desired
361      * @return VlanId assigned for the subnet on the device, or
362      *         null if no vlan assignment was found and this instance is not
363      *         the master for the device.
364      */
365     public VlanId getSubnetAssignedVlanId(DeviceId deviceId, Ip4Prefix subnet) {
366         VlanId assignedVid = subnetVidStore.get(new SubnetAssignedVidStoreKey(
367                                                         deviceId, subnet));
368         if (assignedVid != null) {
369             log.debug("Query for subnet:{} on device:{} returned assigned-vlan "
370                     + "{}", subnet, deviceId, assignedVid);
371             return assignedVid;
372         }
373         //check mastership for the right to assign a vlan
374         if (!mastershipService.isLocalMaster(deviceId)) {
375             log.warn("This controller instance is not the master for device {}. "
376                     + "Cannot assign vlan-id for subnet {}", deviceId, subnet);
377             return null;
378         }
379         // vlan assignment is expensive but done only once
380         Set<Ip4Prefix> configuredSubnets = deviceConfiguration.getSubnets(deviceId);
381         Set<Short> assignedVlans = new HashSet<>();
382         Set<Ip4Prefix> unassignedSubnets = new HashSet<>();
383         for (Ip4Prefix sub : configuredSubnets) {
384             VlanId v = subnetVidStore.get(new SubnetAssignedVidStoreKey(deviceId,
385                                                                         sub));
386             if (v != null) {
387                 assignedVlans.add(v.toShort());
388             } else {
389                 unassignedSubnets.add(sub);
390             }
391         }
392         short nextAssignedVlan = ASSIGNED_VLAN_START;
393         if (!assignedVlans.isEmpty()) {
394             nextAssignedVlan = (short) (Collections.min(assignedVlans) - 1);
395         }
396         for (Ip4Prefix unsub : unassignedSubnets) {
397             subnetVidStore.put(new SubnetAssignedVidStoreKey(deviceId, unsub),
398                                VlanId.vlanId(nextAssignedVlan--));
399             log.info("Assigned vlan: {} to subnet: {} on device: {}",
400                       nextAssignedVlan + 1, unsub, deviceId);
401         }
402
403         return subnetVidStore.get(new SubnetAssignedVidStoreKey(deviceId, subnet));
404     }
405
406     /**
407      * Returns the next objective ID for the given NeighborSet.
408      * If the nextObjectiveID does not exist, a new one is created and returned.
409      *
410      * @param deviceId Device ID
411      * @param ns NegighborSet
412      * @return next objective ID
413      */
414     public int getNextObjectiveId(DeviceId deviceId, NeighborSet ns) {
415         if (groupHandlerMap.get(deviceId) != null) {
416             log.trace("getNextObjectiveId query in device {}", deviceId);
417             return groupHandlerMap
418                     .get(deviceId).getNextObjectiveId(ns);
419         } else {
420             log.warn("getNextObjectiveId query in device {} not found", deviceId);
421             return -1;
422         }
423     }
424
425     /**
426      * Returns the next objective ID for the Subnet given. If the nextObjectiveID does not exist,
427      * a new one is created and returned.
428      *
429      * @param deviceId Device ID
430      * @param prefix Subnet
431      * @return next objective ID
432      */
433     public int getSubnetNextObjectiveId(DeviceId deviceId, IpPrefix prefix) {
434         if (groupHandlerMap.get(deviceId) != null) {
435             log.trace("getSubnetNextObjectiveId query in device {}", deviceId);
436             return groupHandlerMap
437                     .get(deviceId).getSubnetNextObjectiveId(prefix);
438         } else {
439             log.warn("getSubnetNextObjectiveId query in device {} not found", deviceId);
440             return -1;
441         }
442     }
443
444     private class InternalPacketProcessor implements PacketProcessor {
445         @Override
446         public void process(PacketContext context) {
447
448             if (context.isHandled()) {
449                 return;
450             }
451
452             InboundPacket pkt = context.inPacket();
453             Ethernet ethernet = pkt.parsed();
454
455             if (ethernet.getEtherType() == Ethernet.TYPE_ARP) {
456                 arpHandler.processPacketIn(pkt);
457             } else if (ethernet.getEtherType() == Ethernet.TYPE_IPV4) {
458                 IPv4 ipPacket = (IPv4) ethernet.getPayload();
459                 ipHandler.addToPacketBuffer(ipPacket);
460                 if (ipPacket.getProtocol() == IPv4.PROTOCOL_ICMP) {
461                     icmpHandler.processPacketIn(pkt);
462                 } else {
463                     ipHandler.processPacketIn(pkt);
464                 }
465             }
466         }
467     }
468
469     private class InternalLinkListener implements LinkListener {
470         @Override
471         public void event(LinkEvent event) {
472             if (event.type() == LinkEvent.Type.LINK_ADDED
473                     || event.type() == LinkEvent.Type.LINK_REMOVED) {
474                 log.debug("Event {} received from Link Service", event.type());
475                 scheduleEventHandlerIfNotScheduled(event);
476             }
477         }
478     }
479
480     private class InternalDeviceListener implements DeviceListener {
481         @Override
482         public void event(DeviceEvent event) {
483             switch (event.type()) {
484             case DEVICE_ADDED:
485             case PORT_REMOVED:
486             case DEVICE_UPDATED:
487             case DEVICE_AVAILABILITY_CHANGED:
488                 log.debug("Event {} received from Device Service", event.type());
489                 scheduleEventHandlerIfNotScheduled(event);
490                 break;
491             default:
492             }
493         }
494     }
495
496     private void scheduleEventHandlerIfNotScheduled(Event event) {
497         synchronized (threadSchedulerLock) {
498             eventQueue.add(event);
499             numOfEventsQueued++;
500
501             if ((numOfHandlerScheduled - numOfHandlerExecution) == 0) {
502                 //No pending scheduled event handling threads. So start a new one.
503                 eventHandlerFuture = executorService
504                         .schedule(eventHandler, 100, TimeUnit.MILLISECONDS);
505                 numOfHandlerScheduled++;
506             }
507             log.trace("numOfEventsQueued {}, numOfEventHanlderScheduled {}",
508                       numOfEventsQueued,
509                       numOfHandlerScheduled);
510         }
511     }
512
513     private class InternalEventHandler implements Runnable {
514         @Override
515         public void run() {
516             try {
517                 while (true) {
518                     Event event = null;
519                     synchronized (threadSchedulerLock) {
520                         if (!eventQueue.isEmpty()) {
521                             event = eventQueue.poll();
522                             numOfEventsExecuted++;
523                         } else {
524                             numOfHandlerExecution++;
525                             log.debug("numOfHandlerExecution {} numOfEventsExecuted {}",
526                                       numOfHandlerExecution, numOfEventsExecuted);
527                             break;
528                         }
529                     }
530                     if (event.type() == LinkEvent.Type.LINK_ADDED) {
531                         processLinkAdded((Link) event.subject());
532                     } else if (event.type() == LinkEvent.Type.LINK_REMOVED) {
533                         processLinkRemoved((Link) event.subject());
534                     } else if (event.type() == DeviceEvent.Type.DEVICE_ADDED ||
535                             event.type() == DeviceEvent.Type.DEVICE_AVAILABILITY_CHANGED ||
536                             event.type() == DeviceEvent.Type.DEVICE_UPDATED) {
537                         if (deviceService.isAvailable(((Device) event.subject()).id())) {
538                             log.info("Processing device event {} for available device {}",
539                                      event.type(), ((Device) event.subject()).id());
540                             processDeviceAdded((Device) event.subject());
541                         }
542                     } else if (event.type() == DeviceEvent.Type.PORT_REMOVED) {
543                         processPortRemoved((Device) event.subject(),
544                                            ((DeviceEvent) event).port());
545                     } else {
546                         log.warn("Unhandled event type: {}", event.type());
547                     }
548                 }
549             } catch (Exception e) {
550                 log.error("SegmentRouting event handler "
551                         + "thread thrown an exception: {}", e);
552             }
553         }
554     }
555
556     private void processLinkAdded(Link link) {
557         log.debug("A new link {} was added", link.toString());
558         if (!deviceConfiguration.isConfigured(link.src().deviceId())) {
559             log.warn("Source device of this link is not configured.");
560             return;
561         }
562         //Irrespective whether the local is a MASTER or not for this device,
563         //create group handler instance and push default TTP flow rules.
564         //Because in a multi-instance setup, instances can initiate
565         //groups for any devices. Also the default TTP rules are needed
566         //to be pushed before inserting any IP table entries for any device
567         DefaultGroupHandler groupHandler = groupHandlerMap.get(link.src()
568                 .deviceId());
569         if (groupHandler != null) {
570             groupHandler.linkUp(link);
571         } else {
572             Device device = deviceService.getDevice(link.src().deviceId());
573             if (device != null) {
574                 log.warn("processLinkAdded: Link Added "
575                         + "Notification without Device Added "
576                         + "event, still handling it");
577                 processDeviceAdded(device);
578                 groupHandler = groupHandlerMap.get(link.src()
579                                                    .deviceId());
580                 groupHandler.linkUp(link);
581             }
582         }
583
584         log.trace("Starting optimized route population process");
585         defaultRoutingHandler.populateRoutingRulesForLinkStatusChange(null);
586         //log.trace("processLinkAdded: re-starting route population process");
587         //defaultRoutingHandler.startPopulationProcess();
588     }
589
590     private void processLinkRemoved(Link link) {
591         log.debug("A link {} was removed", link.toString());
592         DefaultGroupHandler groupHandler = groupHandlerMap.get(link.src().deviceId());
593         if (groupHandler != null) {
594             groupHandler.portDown(link.src().port());
595         }
596         log.trace("Starting optimized route population process");
597         defaultRoutingHandler.populateRoutingRulesForLinkStatusChange(link);
598         //log.trace("processLinkRemoved: re-starting route population process");
599         //defaultRoutingHandler.startPopulationProcess();
600     }
601
602     private void processDeviceAdded(Device device) {
603         log.debug("A new device with ID {} was added", device.id());
604         if (deviceConfiguration == null || !deviceConfiguration.isConfigured(device.id())) {
605             log.warn("Device configuration uploading. Device {} will be "
606                     + "processed after config completes.", device.id());
607             return;
608         }
609         // Irrespective of whether the local is a MASTER or not for this device,
610         // we need to create a SR-group-handler instance. This is because in a
611         // multi-instance setup, any instance can initiate forwarding/next-objectives
612         // for any switch (even if this instance is a SLAVE or not even connected
613         // to the switch). To handle this, a default-group-handler instance is necessary
614         // per switch.
615         if (groupHandlerMap.get(device.id()) == null) {
616             DefaultGroupHandler groupHandler;
617             try {
618                 groupHandler = DefaultGroupHandler.
619                         createGroupHandler(device.id(),
620                                            appId,
621                                            deviceConfiguration,
622                                            linkService,
623                                            flowObjectiveService,
624                                            nsNextObjStore,
625                                            subnetNextObjStore);
626             } catch (DeviceConfigNotFoundException e) {
627                 log.warn(e.getMessage() + " Aborting processDeviceAdded.");
628                 return;
629             }
630             groupHandlerMap.put(device.id(), groupHandler);
631             // Also, in some cases, drivers may need extra
632             // information to process rules (eg. Router IP/MAC); and so, we send
633             // port addressing rules to the driver as well irrespective of whether
634             // this instance is the master or not.
635             defaultRoutingHandler.populatePortAddressingRules(device.id());
636         }
637         if (mastershipService.isLocalMaster(device.id())) {
638             DefaultGroupHandler groupHandler = groupHandlerMap.get(device.id());
639             groupHandler.createGroupsFromSubnetConfig();
640         }
641     }
642
643     private void processPortRemoved(Device device, Port port) {
644         log.debug("Port {} was removed", port.toString());
645         DefaultGroupHandler groupHandler = groupHandlerMap.get(device.id());
646         if (groupHandler != null) {
647             groupHandler.portDown(port.number());
648         }
649     }
650
651     private class InternalConfigListener implements NetworkConfigListener {
652         SegmentRoutingManager segmentRoutingManager;
653
654         public InternalConfigListener(SegmentRoutingManager srMgr) {
655             this.segmentRoutingManager = srMgr;
656         }
657
658         public void configureNetwork() {
659             deviceConfiguration = new DeviceConfiguration(segmentRoutingManager.cfgService);
660
661             arpHandler = new ArpHandler(segmentRoutingManager);
662             icmpHandler = new IcmpHandler(segmentRoutingManager);
663             ipHandler = new IpHandler(segmentRoutingManager);
664             routingRulePopulator = new RoutingRulePopulator(segmentRoutingManager);
665             defaultRoutingHandler = new DefaultRoutingHandler(segmentRoutingManager);
666
667             tunnelHandler = new TunnelHandler(linkService, deviceConfiguration,
668                                               groupHandlerMap, tunnelStore);
669             policyHandler = new PolicyHandler(appId, deviceConfiguration,
670                                               flowObjectiveService,
671                                               tunnelHandler, policyStore);
672
673             for (Device device : deviceService.getDevices()) {
674                 // Irrespective of whether the local is a MASTER or not for this device,
675                 // we need to create a SR-group-handler instance. This is because in a
676                 // multi-instance setup, any instance can initiate forwarding/next-objectives
677                 // for any switch (even if this instance is a SLAVE or not even connected
678                 // to the switch). To handle this, a default-group-handler instance is necessary
679                 // per switch.
680                 if (groupHandlerMap.get(device.id()) == null) {
681                     DefaultGroupHandler groupHandler;
682                     try {
683                         groupHandler = DefaultGroupHandler.
684                                 createGroupHandler(device.id(),
685                                                    appId,
686                                                    deviceConfiguration,
687                                                    linkService,
688                                                    flowObjectiveService,
689                                                    nsNextObjStore,
690                                                    subnetNextObjStore);
691                     } catch (DeviceConfigNotFoundException e) {
692                         log.warn(e.getMessage() + " Aborting configureNetwork.");
693                         return;
694                     }
695                     groupHandlerMap.put(device.id(), groupHandler);
696
697                     // Also, in some cases, drivers may need extra
698                     // information to process rules (eg. Router IP/MAC); and so, we send
699                     // port addressing rules to the driver as well, irrespective of whether
700                     // this instance is the master or not.
701                     defaultRoutingHandler.populatePortAddressingRules(device.id());
702                 }
703                 if (mastershipService.isLocalMaster(device.id())) {
704                     DefaultGroupHandler groupHandler = groupHandlerMap.get(device.id());
705                     groupHandler.createGroupsFromSubnetConfig();
706                 }
707             }
708
709             defaultRoutingHandler.startPopulationProcess();
710         }
711
712         @Override
713         public void event(NetworkConfigEvent event) {
714             if (event.configClass().equals(SegmentRoutingConfig.class)) {
715                 if (event.type() == NetworkConfigEvent.Type.CONFIG_ADDED) {
716                     log.info("Network configuration added.");
717                     configureNetwork();
718                 }
719                 if (event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED) {
720                     log.info("Network configuration updated.");
721                     // TODO support dynamic configuration
722                 }
723             }
724         }
725     }
726 }