84fe516879a3110ae94c982b63abf82c83b7e347
[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.MacAddress;
26 import org.onlab.packet.VlanId;
27 import org.onlab.packet.IPv4;
28 import org.onlab.packet.Ip4Address;
29 import org.onlab.packet.Ip4Prefix;
30 import org.onlab.packet.IpAddress;
31 import org.onlab.packet.IpPrefix;
32 import org.onlab.util.KryoNamespace;
33 import org.onosproject.core.ApplicationId;
34 import org.onosproject.core.CoreService;
35 import org.onosproject.event.Event;
36 import org.onosproject.net.ConnectPoint;
37 import org.onosproject.net.PortNumber;
38 import org.onosproject.net.config.ConfigFactory;
39 import org.onosproject.net.config.NetworkConfigEvent;
40 import org.onosproject.net.config.NetworkConfigRegistry;
41 import org.onosproject.net.config.NetworkConfigListener;
42 import org.onosproject.net.config.basics.SubjectFactories;
43 import org.onosproject.net.flow.DefaultTrafficSelector;
44 import org.onosproject.net.flow.DefaultTrafficTreatment;
45 import org.onosproject.net.flow.TrafficSelector;
46 import org.onosproject.net.flow.TrafficTreatment;
47 import org.onosproject.net.flowobjective.DefaultForwardingObjective;
48 import org.onosproject.net.flowobjective.ForwardingObjective;
49 import org.onosproject.net.flowobjective.Objective;
50 import org.onosproject.net.flowobjective.ObjectiveContext;
51 import org.onosproject.net.flowobjective.ObjectiveError;
52 import org.onosproject.net.host.HostEvent;
53 import org.onosproject.net.host.HostListener;
54 import org.onosproject.segmentrouting.config.DeviceConfigNotFoundException;
55 import org.onosproject.segmentrouting.config.DeviceConfiguration;
56 import org.onosproject.segmentrouting.config.SegmentRoutingConfig;
57 import org.onosproject.segmentrouting.grouphandler.DefaultGroupHandler;
58 import org.onosproject.segmentrouting.grouphandler.NeighborSet;
59 import org.onosproject.segmentrouting.grouphandler.NeighborSetNextObjectiveStoreKey;
60 import org.onosproject.mastership.MastershipService;
61 import org.onosproject.net.Device;
62 import org.onosproject.net.DeviceId;
63 import org.onosproject.net.Link;
64 import org.onosproject.net.Port;
65 import org.onosproject.net.device.DeviceEvent;
66 import org.onosproject.net.device.DeviceListener;
67 import org.onosproject.net.device.DeviceService;
68 import org.onosproject.net.flowobjective.FlowObjectiveService;
69 import org.onosproject.net.host.HostService;
70 import org.onosproject.net.intent.IntentService;
71 import org.onosproject.net.link.LinkEvent;
72 import org.onosproject.net.link.LinkListener;
73 import org.onosproject.net.link.LinkService;
74 import org.onosproject.net.packet.InboundPacket;
75 import org.onosproject.net.packet.PacketContext;
76 import org.onosproject.net.packet.PacketProcessor;
77 import org.onosproject.net.packet.PacketService;
78 import org.onosproject.net.topology.TopologyService;
79 import org.onosproject.segmentrouting.grouphandler.SubnetNextObjectiveStoreKey;
80 import org.onosproject.store.service.EventuallyConsistentMap;
81 import org.onosproject.store.service.EventuallyConsistentMapBuilder;
82 import org.onosproject.store.service.StorageService;
83 import org.onosproject.store.service.WallClockTimestamp;
84 import org.slf4j.Logger;
85 import org.slf4j.LoggerFactory;
86
87 import java.net.URI;
88 import java.util.Collections;
89 import java.util.HashSet;
90 import java.util.List;
91 import java.util.Map;
92 import java.util.Set;
93 import java.util.concurrent.ConcurrentHashMap;
94 import java.util.concurrent.ConcurrentLinkedQueue;
95 import java.util.concurrent.Executors;
96 import java.util.concurrent.ScheduledExecutorService;
97 import java.util.concurrent.ScheduledFuture;
98 import java.util.concurrent.TimeUnit;
99
100 @SuppressWarnings("ALL")
101 @Service
102 @Component(immediate = true)
103 public class SegmentRoutingManager implements SegmentRoutingService {
104
105     private static Logger log = LoggerFactory
106             .getLogger(SegmentRoutingManager.class);
107
108     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
109     protected CoreService coreService;
110
111     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
112     protected TopologyService topologyService;
113
114     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
115     protected PacketService packetService;
116
117     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
118     protected IntentService intentService;
119
120     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
121     protected HostService hostService;
122
123     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
124     protected DeviceService deviceService;
125
126     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
127     protected FlowObjectiveService flowObjectiveService;
128
129     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
130     protected LinkService linkService;
131
132     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
133     protected MastershipService mastershipService;
134
135     protected ArpHandler arpHandler = null;
136     protected IcmpHandler icmpHandler = null;
137     protected IpHandler ipHandler = null;
138     protected RoutingRulePopulator routingRulePopulator = null;
139     protected ApplicationId appId;
140     protected DeviceConfiguration deviceConfiguration = null;
141
142     private DefaultRoutingHandler defaultRoutingHandler = null;
143     private TunnelHandler tunnelHandler = null;
144     private PolicyHandler policyHandler = null;
145     private InternalPacketProcessor processor = null;
146     private InternalLinkListener linkListener = null;
147     private InternalDeviceListener deviceListener = null;
148     private InternalEventHandler eventHandler = new InternalEventHandler();
149
150     private ScheduledExecutorService executorService = Executors
151             .newScheduledThreadPool(1);
152
153     private static ScheduledFuture<?> eventHandlerFuture = null;
154     private ConcurrentLinkedQueue<Event> eventQueue = new ConcurrentLinkedQueue<Event>();
155     private Map<DeviceId, DefaultGroupHandler> groupHandlerMap =
156             new ConcurrentHashMap<DeviceId, DefaultGroupHandler>();
157     // Per device next objective ID store with (device id + neighbor set) as key
158     private EventuallyConsistentMap<NeighborSetNextObjectiveStoreKey, Integer>
159             nsNextObjStore = null;
160     private EventuallyConsistentMap<SubnetNextObjectiveStoreKey, Integer>
161             subnetNextObjStore = null;
162     private EventuallyConsistentMap<String, Tunnel> tunnelStore = null;
163     private EventuallyConsistentMap<String, Policy> policyStore = null;
164     // Per device, per-subnet assigned-vlans store, with (device id + subnet
165     // IPv4 prefix) as key
166     private EventuallyConsistentMap<SubnetAssignedVidStoreKey, VlanId>
167         subnetVidStore = null;
168
169     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
170     protected StorageService storageService;
171
172     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
173     protected NetworkConfigRegistry cfgService;
174
175     private final InternalConfigListener cfgListener =
176             new InternalConfigListener(this);
177
178     private final ConfigFactory cfgFactory =
179             new ConfigFactory(SubjectFactories.DEVICE_SUBJECT_FACTORY,
180                               SegmentRoutingConfig.class,
181                               "segmentrouting") {
182                 @Override
183                 public SegmentRoutingConfig createConfig() {
184                     return new SegmentRoutingConfig();
185                 }
186             };
187
188     private final HostListener hostListener = new InternalHostListener();
189
190     private Object threadSchedulerLock = new Object();
191     private static int numOfEventsQueued = 0;
192     private static int numOfEventsExecuted = 0;
193     private static int numOfHandlerExecution = 0;
194     private static int numOfHandlerScheduled = 0;
195
196     private KryoNamespace.Builder kryoBuilder = null;
197
198     private static final short ASSIGNED_VLAN_START = 4093;
199     public static final short ASSIGNED_VLAN_NO_SUBNET = 4094;
200
201     @Activate
202     protected void activate() {
203         appId = coreService
204                 .registerApplication("org.onosproject.segmentrouting");
205
206         kryoBuilder = new KryoNamespace.Builder()
207             .register(NeighborSetNextObjectiveStoreKey.class,
208                     SubnetNextObjectiveStoreKey.class,
209                     SubnetAssignedVidStoreKey.class,
210                     NeighborSet.class,
211                     DeviceId.class,
212                     URI.class,
213                     WallClockTimestamp.class,
214                     org.onosproject.cluster.NodeId.class,
215                     HashSet.class,
216                     Tunnel.class,
217                     DefaultTunnel.class,
218                     Policy.class,
219                     TunnelPolicy.class,
220                     Policy.Type.class,
221                     VlanId.class,
222                     Ip4Address.class,
223                     Ip4Prefix.class,
224                     IpAddress.Version.class,
225                     ConnectPoint.class
226             );
227
228         log.debug("Creating EC map nsnextobjectivestore");
229         EventuallyConsistentMapBuilder<NeighborSetNextObjectiveStoreKey, Integer>
230                 nsNextObjMapBuilder = storageService.eventuallyConsistentMapBuilder();
231
232         nsNextObjStore = nsNextObjMapBuilder
233                 .withName("nsnextobjectivestore")
234                 .withSerializer(kryoBuilder)
235                 .withTimestampProvider((k, v) -> new WallClockTimestamp())
236                 .build();
237         log.trace("Current size {}", nsNextObjStore.size());
238
239         log.debug("Creating EC map subnetnextobjectivestore");
240         EventuallyConsistentMapBuilder<SubnetNextObjectiveStoreKey, Integer>
241                 subnetNextObjMapBuilder = storageService.eventuallyConsistentMapBuilder();
242
243         subnetNextObjStore = subnetNextObjMapBuilder
244                 .withName("subnetnextobjectivestore")
245                 .withSerializer(kryoBuilder)
246                 .withTimestampProvider((k, v) -> new WallClockTimestamp())
247                 .build();
248
249         EventuallyConsistentMapBuilder<String, Tunnel> tunnelMapBuilder =
250                 storageService.eventuallyConsistentMapBuilder();
251
252         tunnelStore = tunnelMapBuilder
253                 .withName("tunnelstore")
254                 .withSerializer(kryoBuilder)
255                 .withTimestampProvider((k, v) -> new WallClockTimestamp())
256                 .build();
257
258         EventuallyConsistentMapBuilder<String, Policy> policyMapBuilder =
259                 storageService.eventuallyConsistentMapBuilder();
260
261         policyStore = policyMapBuilder
262                 .withName("policystore")
263                 .withSerializer(kryoBuilder)
264                 .withTimestampProvider((k, v) -> new WallClockTimestamp())
265                 .build();
266
267         EventuallyConsistentMapBuilder<SubnetAssignedVidStoreKey, VlanId>
268             subnetVidStoreMapBuilder = storageService.eventuallyConsistentMapBuilder();
269
270         subnetVidStore = subnetVidStoreMapBuilder
271                 .withName("subnetvidstore")
272                 .withSerializer(kryoBuilder)
273                 .withTimestampProvider((k, v) -> new WallClockTimestamp())
274                 .build();
275
276         cfgService.addListener(cfgListener);
277         cfgService.registerConfigFactory(cfgFactory);
278
279         hostService.addListener(hostListener);
280
281         processor = new InternalPacketProcessor();
282         linkListener = new InternalLinkListener();
283         deviceListener = new InternalDeviceListener();
284
285         packetService.addProcessor(processor, PacketProcessor.director(2));
286         linkService.addListener(linkListener);
287         deviceService.addListener(deviceListener);
288
289         cfgListener.configureNetwork();
290
291         log.info("Started");
292     }
293
294     @Deactivate
295     protected void deactivate() {
296         cfgService.removeListener(cfgListener);
297         cfgService.unregisterConfigFactory(cfgFactory);
298
299         packetService.removeProcessor(processor);
300         linkService.removeListener(linkListener);
301         deviceService.removeListener(deviceListener);
302         processor = null;
303         linkListener = null;
304         deviceService = null;
305
306         groupHandlerMap.clear();
307
308         log.info("Stopped");
309     }
310
311
312     @Override
313     public List<Tunnel> getTunnels() {
314         return tunnelHandler.getTunnels();
315     }
316
317     @Override
318     public TunnelHandler.Result createTunnel(Tunnel tunnel) {
319         return tunnelHandler.createTunnel(tunnel);
320     }
321
322     @Override
323     public TunnelHandler.Result removeTunnel(Tunnel tunnel) {
324         for (Policy policy: policyHandler.getPolicies()) {
325             if (policy.type() == Policy.Type.TUNNEL_FLOW) {
326                 TunnelPolicy tunnelPolicy = (TunnelPolicy) policy;
327                 if (tunnelPolicy.tunnelId().equals(tunnel.id())) {
328                     log.warn("Cannot remove the tunnel used by a policy");
329                     return TunnelHandler.Result.TUNNEL_IN_USE;
330                 }
331             }
332         }
333         return tunnelHandler.removeTunnel(tunnel);
334     }
335
336     @Override
337     public PolicyHandler.Result removePolicy(Policy policy) {
338         return policyHandler.removePolicy(policy);
339     }
340
341     @Override
342     public PolicyHandler.Result createPolicy(Policy policy) {
343         return policyHandler.createPolicy(policy);
344     }
345
346     @Override
347     public List<Policy> getPolicies() {
348         return policyHandler.getPolicies();
349     }
350
351     /**
352      * Returns the tunnel object with the tunnel ID.
353      *
354      * @param tunnelId Tunnel ID
355      * @return Tunnel reference
356      */
357     public Tunnel getTunnel(String tunnelId) {
358         return tunnelHandler.getTunnel(tunnelId);
359     }
360
361     /**
362      * Returns the vlan-id assigned to the subnet configured for a device.
363      * If no vlan-id has been assigned, a new one is assigned out of a pool of ids,
364      * if and only if this controller instance is the master for the device.
365      * <p>
366      * USAGE: The assigned vlans are meant to be applied to untagged packets on those
367      * switches/pipelines that need this functionality. These vids are meant
368      * to be used internally within a switch, and thus need to be unique only
369      * on a switch level. Note that packets never go out on the wire with these
370      * vlans. Currently, vlan ids are assigned from value 4093 down.
371      * Vlan id 4094 expected to be used for all ports that are not assigned subnets.
372      * Vlan id 4095 is reserved and unused. Only a single vlan id is assigned
373      * per subnet.
374      * XXX This method should avoid any vlans configured on the ports, but
375      *     currently the app works only on untagged packets and as a result
376      *     ignores any vlan configuration.
377      *
378      * @param deviceId switch dpid
379      * @param subnet IPv4 prefix for which assigned vlan is desired
380      * @return VlanId assigned for the subnet on the device, or
381      *         null if no vlan assignment was found and this instance is not
382      *         the master for the device.
383      */
384     public VlanId getSubnetAssignedVlanId(DeviceId deviceId, Ip4Prefix subnet) {
385         VlanId assignedVid = subnetVidStore.get(new SubnetAssignedVidStoreKey(
386                                                         deviceId, subnet));
387         if (assignedVid != null) {
388             log.debug("Query for subnet:{} on device:{} returned assigned-vlan "
389                     + "{}", subnet, deviceId, assignedVid);
390             return assignedVid;
391         }
392         //check mastership for the right to assign a vlan
393         if (!mastershipService.isLocalMaster(deviceId)) {
394             log.warn("This controller instance is not the master for device {}. "
395                     + "Cannot assign vlan-id for subnet {}", deviceId, subnet);
396             return null;
397         }
398         // vlan assignment is expensive but done only once
399         Set<Ip4Prefix> configuredSubnets = deviceConfiguration.getSubnets(deviceId);
400         Set<Short> assignedVlans = new HashSet<>();
401         Set<Ip4Prefix> unassignedSubnets = new HashSet<>();
402         for (Ip4Prefix sub : configuredSubnets) {
403             VlanId v = subnetVidStore.get(new SubnetAssignedVidStoreKey(deviceId,
404                                                                         sub));
405             if (v != null) {
406                 assignedVlans.add(v.toShort());
407             } else {
408                 unassignedSubnets.add(sub);
409             }
410         }
411         short nextAssignedVlan = ASSIGNED_VLAN_START;
412         if (!assignedVlans.isEmpty()) {
413             nextAssignedVlan = (short) (Collections.min(assignedVlans) - 1);
414         }
415         for (Ip4Prefix unsub : unassignedSubnets) {
416             subnetVidStore.put(new SubnetAssignedVidStoreKey(deviceId, unsub),
417                                VlanId.vlanId(nextAssignedVlan--));
418             log.info("Assigned vlan: {} to subnet: {} on device: {}",
419                       nextAssignedVlan + 1, unsub, deviceId);
420         }
421
422         return subnetVidStore.get(new SubnetAssignedVidStoreKey(deviceId, subnet));
423     }
424
425     /**
426      * Returns the next objective ID for the given NeighborSet.
427      * If the nextObjectiveID does not exist, a new one is created and returned.
428      *
429      * @param deviceId Device ID
430      * @param ns NegighborSet
431      * @return next objective ID
432      */
433     public int getNextObjectiveId(DeviceId deviceId, NeighborSet ns) {
434         if (groupHandlerMap.get(deviceId) != null) {
435             log.trace("getNextObjectiveId query in device {}", deviceId);
436             return groupHandlerMap
437                     .get(deviceId).getNextObjectiveId(ns);
438         } else {
439             log.warn("getNextObjectiveId query in device {} not found", deviceId);
440             return -1;
441         }
442     }
443
444     /**
445      * Returns the next objective ID for the Subnet given. If the nextObjectiveID does not exist,
446      * a new one is created and returned.
447      *
448      * @param deviceId Device ID
449      * @param prefix Subnet
450      * @return next objective ID
451      */
452     public int getSubnetNextObjectiveId(DeviceId deviceId, IpPrefix prefix) {
453         if (groupHandlerMap.get(deviceId) != null) {
454             log.trace("getSubnetNextObjectiveId query in device {}", deviceId);
455             return groupHandlerMap
456                     .get(deviceId).getSubnetNextObjectiveId(prefix);
457         } else {
458             log.warn("getSubnetNextObjectiveId query in device {} not found", deviceId);
459             return -1;
460         }
461     }
462
463     private class InternalPacketProcessor implements PacketProcessor {
464         @Override
465         public void process(PacketContext context) {
466
467             if (context.isHandled()) {
468                 return;
469             }
470
471             InboundPacket pkt = context.inPacket();
472             Ethernet ethernet = pkt.parsed();
473
474             if (ethernet.getEtherType() == Ethernet.TYPE_ARP) {
475                 arpHandler.processPacketIn(pkt);
476             } else if (ethernet.getEtherType() == Ethernet.TYPE_IPV4) {
477                 IPv4 ipPacket = (IPv4) ethernet.getPayload();
478                 ipHandler.addToPacketBuffer(ipPacket);
479                 if (ipPacket.getProtocol() == IPv4.PROTOCOL_ICMP) {
480                     icmpHandler.processPacketIn(pkt);
481                 } else {
482                     ipHandler.processPacketIn(pkt);
483                 }
484             }
485         }
486     }
487
488     private class InternalLinkListener implements LinkListener {
489         @Override
490         public void event(LinkEvent event) {
491             if (event.type() == LinkEvent.Type.LINK_ADDED
492                     || event.type() == LinkEvent.Type.LINK_REMOVED) {
493                 log.debug("Event {} received from Link Service", event.type());
494                 scheduleEventHandlerIfNotScheduled(event);
495             }
496         }
497     }
498
499     private class InternalDeviceListener implements DeviceListener {
500         @Override
501         public void event(DeviceEvent event) {
502             switch (event.type()) {
503             case DEVICE_ADDED:
504             case PORT_REMOVED:
505             case DEVICE_UPDATED:
506             case DEVICE_AVAILABILITY_CHANGED:
507                 log.debug("Event {} received from Device Service", event.type());
508                 scheduleEventHandlerIfNotScheduled(event);
509                 break;
510             default:
511             }
512         }
513     }
514
515     private void scheduleEventHandlerIfNotScheduled(Event event) {
516         synchronized (threadSchedulerLock) {
517             eventQueue.add(event);
518             numOfEventsQueued++;
519
520             if ((numOfHandlerScheduled - numOfHandlerExecution) == 0) {
521                 //No pending scheduled event handling threads. So start a new one.
522                 eventHandlerFuture = executorService
523                         .schedule(eventHandler, 100, TimeUnit.MILLISECONDS);
524                 numOfHandlerScheduled++;
525             }
526             log.trace("numOfEventsQueued {}, numOfEventHanlderScheduled {}",
527                       numOfEventsQueued,
528                       numOfHandlerScheduled);
529         }
530     }
531
532     private class InternalEventHandler implements Runnable {
533         @Override
534         public void run() {
535             try {
536                 while (true) {
537                     Event event = null;
538                     synchronized (threadSchedulerLock) {
539                         if (!eventQueue.isEmpty()) {
540                             event = eventQueue.poll();
541                             numOfEventsExecuted++;
542                         } else {
543                             numOfHandlerExecution++;
544                             log.debug("numOfHandlerExecution {} numOfEventsExecuted {}",
545                                       numOfHandlerExecution, numOfEventsExecuted);
546                             break;
547                         }
548                     }
549                     if (event.type() == LinkEvent.Type.LINK_ADDED) {
550                         processLinkAdded((Link) event.subject());
551                     } else if (event.type() == LinkEvent.Type.LINK_REMOVED) {
552                         processLinkRemoved((Link) event.subject());
553                     } else if (event.type() == DeviceEvent.Type.DEVICE_ADDED ||
554                             event.type() == DeviceEvent.Type.DEVICE_AVAILABILITY_CHANGED ||
555                             event.type() == DeviceEvent.Type.DEVICE_UPDATED) {
556                         if (deviceService.isAvailable(((Device) event.subject()).id())) {
557                             log.info("Processing device event {} for available device {}",
558                                      event.type(), ((Device) event.subject()).id());
559                             processDeviceAdded((Device) event.subject());
560                         }
561                     } else if (event.type() == DeviceEvent.Type.PORT_REMOVED) {
562                         processPortRemoved((Device) event.subject(),
563                                            ((DeviceEvent) event).port());
564                     } else {
565                         log.warn("Unhandled event type: {}", event.type());
566                     }
567                 }
568             } catch (Exception e) {
569                 log.error("SegmentRouting event handler "
570                         + "thread thrown an exception: {}", e);
571             }
572         }
573     }
574
575     private void processLinkAdded(Link link) {
576         log.debug("A new link {} was added", link.toString());
577         if (!deviceConfiguration.isConfigured(link.src().deviceId())) {
578             log.warn("Source device of this link is not configured.");
579             return;
580         }
581         //Irrespective whether the local is a MASTER or not for this device,
582         //create group handler instance and push default TTP flow rules.
583         //Because in a multi-instance setup, instances can initiate
584         //groups for any devices. Also the default TTP rules are needed
585         //to be pushed before inserting any IP table entries for any device
586         DefaultGroupHandler groupHandler = groupHandlerMap.get(link.src()
587                 .deviceId());
588         if (groupHandler != null) {
589             groupHandler.linkUp(link);
590         } else {
591             Device device = deviceService.getDevice(link.src().deviceId());
592             if (device != null) {
593                 log.warn("processLinkAdded: Link Added "
594                         + "Notification without Device Added "
595                         + "event, still handling it");
596                 processDeviceAdded(device);
597                 groupHandler = groupHandlerMap.get(link.src()
598                                                    .deviceId());
599                 groupHandler.linkUp(link);
600             }
601         }
602
603         log.trace("Starting optimized route population process");
604         defaultRoutingHandler.populateRoutingRulesForLinkStatusChange(null);
605         //log.trace("processLinkAdded: re-starting route population process");
606         //defaultRoutingHandler.startPopulationProcess();
607     }
608
609     private void processLinkRemoved(Link link) {
610         log.debug("A link {} was removed", link.toString());
611         DefaultGroupHandler groupHandler = groupHandlerMap.get(link.src().deviceId());
612         if (groupHandler != null) {
613             groupHandler.portDown(link.src().port());
614         }
615         log.trace("Starting optimized route population process");
616         defaultRoutingHandler.populateRoutingRulesForLinkStatusChange(link);
617         //log.trace("processLinkRemoved: re-starting route population process");
618         //defaultRoutingHandler.startPopulationProcess();
619     }
620
621     private void processDeviceAdded(Device device) {
622         log.debug("A new device with ID {} was added", device.id());
623         if (deviceConfiguration == null || !deviceConfiguration.isConfigured(device.id())) {
624             log.warn("Device configuration uploading. Device {} will be "
625                     + "processed after config completes.", device.id());
626             return;
627         }
628         // Irrespective of whether the local is a MASTER or not for this device,
629         // we need to create a SR-group-handler instance. This is because in a
630         // multi-instance setup, any instance can initiate forwarding/next-objectives
631         // for any switch (even if this instance is a SLAVE or not even connected
632         // to the switch). To handle this, a default-group-handler instance is necessary
633         // per switch.
634         if (groupHandlerMap.get(device.id()) == null) {
635             DefaultGroupHandler groupHandler;
636             try {
637                 groupHandler = DefaultGroupHandler.
638                         createGroupHandler(device.id(),
639                                            appId,
640                                            deviceConfiguration,
641                                            linkService,
642                                            flowObjectiveService,
643                                            nsNextObjStore,
644                                            subnetNextObjStore);
645             } catch (DeviceConfigNotFoundException e) {
646                 log.warn(e.getMessage() + " Aborting processDeviceAdded.");
647                 return;
648             }
649             groupHandlerMap.put(device.id(), groupHandler);
650             // Also, in some cases, drivers may need extra
651             // information to process rules (eg. Router IP/MAC); and so, we send
652             // port addressing rules to the driver as well irrespective of whether
653             // this instance is the master or not.
654             defaultRoutingHandler.populatePortAddressingRules(device.id());
655         }
656         if (mastershipService.isLocalMaster(device.id())) {
657             DefaultGroupHandler groupHandler = groupHandlerMap.get(device.id());
658             groupHandler.createGroupsFromSubnetConfig();
659             routingRulePopulator.populateSubnetBroadcastRule(device.id());
660         }
661     }
662
663     private void processPortRemoved(Device device, Port port) {
664         log.debug("Port {} was removed", port.toString());
665         DefaultGroupHandler groupHandler = groupHandlerMap.get(device.id());
666         if (groupHandler != null) {
667             groupHandler.portDown(port.number());
668         }
669     }
670
671     private class InternalConfigListener implements NetworkConfigListener {
672         SegmentRoutingManager segmentRoutingManager;
673
674         public InternalConfigListener(SegmentRoutingManager srMgr) {
675             this.segmentRoutingManager = srMgr;
676         }
677
678         public void configureNetwork() {
679             deviceConfiguration = new DeviceConfiguration(segmentRoutingManager.cfgService);
680
681             arpHandler = new ArpHandler(segmentRoutingManager);
682             icmpHandler = new IcmpHandler(segmentRoutingManager);
683             ipHandler = new IpHandler(segmentRoutingManager);
684             routingRulePopulator = new RoutingRulePopulator(segmentRoutingManager);
685             defaultRoutingHandler = new DefaultRoutingHandler(segmentRoutingManager);
686
687             tunnelHandler = new TunnelHandler(linkService, deviceConfiguration,
688                                               groupHandlerMap, tunnelStore);
689             policyHandler = new PolicyHandler(appId, deviceConfiguration,
690                                               flowObjectiveService,
691                                               tunnelHandler, policyStore);
692
693             for (Device device : deviceService.getDevices()) {
694                 // Irrespective of whether the local is a MASTER or not for this device,
695                 // we need to create a SR-group-handler instance. This is because in a
696                 // multi-instance setup, any instance can initiate forwarding/next-objectives
697                 // for any switch (even if this instance is a SLAVE or not even connected
698                 // to the switch). To handle this, a default-group-handler instance is necessary
699                 // per switch.
700                 if (groupHandlerMap.get(device.id()) == null) {
701                     DefaultGroupHandler groupHandler;
702                     try {
703                         groupHandler = DefaultGroupHandler.
704                                 createGroupHandler(device.id(),
705                                                    appId,
706                                                    deviceConfiguration,
707                                                    linkService,
708                                                    flowObjectiveService,
709                                                    nsNextObjStore,
710                                                    subnetNextObjStore);
711                     } catch (DeviceConfigNotFoundException e) {
712                         log.warn(e.getMessage() + " Aborting configureNetwork.");
713                         return;
714                     }
715                     groupHandlerMap.put(device.id(), groupHandler);
716
717                     // Also, in some cases, drivers may need extra
718                     // information to process rules (eg. Router IP/MAC); and so, we send
719                     // port addressing rules to the driver as well, irrespective of whether
720                     // this instance is the master or not.
721                     defaultRoutingHandler.populatePortAddressingRules(device.id());
722                 }
723                 if (mastershipService.isLocalMaster(device.id())) {
724                     DefaultGroupHandler groupHandler = groupHandlerMap.get(device.id());
725                     groupHandler.createGroupsFromSubnetConfig();
726                     routingRulePopulator.populateSubnetBroadcastRule(device.id());
727                 }
728             }
729
730             defaultRoutingHandler.startPopulationProcess();
731         }
732
733         @Override
734         public void event(NetworkConfigEvent event) {
735             if (event.configClass().equals(SegmentRoutingConfig.class)) {
736                 if (event.type() == NetworkConfigEvent.Type.CONFIG_ADDED) {
737                     log.info("Network configuration added.");
738                     configureNetwork();
739                 }
740                 if (event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED) {
741                     log.info("Network configuration updated.");
742                     // TODO support dynamic configuration
743                 }
744             }
745         }
746     }
747
748     private class InternalHostListener implements HostListener {
749         private ForwardingObjective.Builder getForwardingObjectiveBuilder(
750                 MacAddress mac, VlanId vlanId, PortNumber port) {
751             TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
752             sbuilder.matchEthDst(mac);
753             sbuilder.matchVlanId(vlanId);
754
755             TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
756             // TODO Move popVlan from flow action to group action
757             tbuilder.immediate().popVlan();
758             tbuilder.immediate().setOutput(port);
759
760             return DefaultForwardingObjective.builder()
761                     .withFlag(ForwardingObjective.Flag.SPECIFIC)
762                     .withSelector(sbuilder.build())
763                     .withTreatment(tbuilder.build())
764                     .withPriority(100)
765                     .fromApp(appId)
766                     .makePermanent();
767         }
768
769         private void processHostAddedEvent(HostEvent event) {
770             MacAddress mac = event.subject().mac();
771             VlanId vlanId = event.subject().vlan();
772             DeviceId deviceId = event.subject().location().deviceId();
773             PortNumber port = event.subject().location().port();
774             Set<IpAddress> ips = event.subject().ipAddresses();
775             log.debug("Host {}/{} is added at {}:{}", mac, vlanId, deviceId, port);
776
777             // TODO Move bridging table population to a separate class
778             // Populate bridging table entry
779             ForwardingObjective.Builder fob =
780                     getForwardingObjectiveBuilder(mac, vlanId, port);
781             flowObjectiveService.forward(deviceId, fob.add(
782                     new BridgingTableObjectiveContext(mac, vlanId)
783             ));
784
785             // Populate IP table entry
786             ips.forEach(ip -> {
787                 if (ip.isIp4()) {
788                     routingRulePopulator.populateIpRuleForHost(
789                             deviceId, ip.getIp4Address(), mac, port);
790                 }
791             });
792         }
793
794         private void processHostRemoveEvent(HostEvent event) {
795             MacAddress mac = event.subject().mac();
796             VlanId vlanId = event.subject().vlan();
797             DeviceId deviceId = event.subject().location().deviceId();
798             PortNumber port = event.subject().location().port();
799             Set<IpAddress> ips = event.subject().ipAddresses();
800             log.debug("Host {}/{} is removed from {}:{}", mac, vlanId, deviceId, port);
801
802             // Revoke bridging table entry
803             ForwardingObjective.Builder fob =
804                     getForwardingObjectiveBuilder(mac, vlanId, port);
805             flowObjectiveService.forward(deviceId, fob.remove(
806                     new BridgingTableObjectiveContext(mac, vlanId)
807             ));
808
809             // Revoke IP table entry
810             ips.forEach(ip -> {
811                 if (ip.isIp4()) {
812                     routingRulePopulator.revokeIpRuleForHost(
813                             deviceId, ip.getIp4Address(), mac, port);
814                 }
815             });
816         }
817
818         private void processHostMovedEvent(HostEvent event) {
819             MacAddress mac = event.subject().mac();
820             VlanId vlanId = event.subject().vlan();
821             DeviceId prevDeviceId = event.prevSubject().location().deviceId();
822             PortNumber prevPort = event.prevSubject().location().port();
823             Set<IpAddress> prevIps = event.prevSubject().ipAddresses();
824             DeviceId newDeviceId = event.subject().location().deviceId();
825             PortNumber newPort = event.subject().location().port();
826             Set<IpAddress> newIps = event.subject().ipAddresses();
827             log.debug("Host {}/{} is moved from {}:{} to {}:{}",
828                     mac, vlanId, prevDeviceId, prevPort, newDeviceId, newPort);
829
830             // Revoke previous bridging table entry
831             ForwardingObjective.Builder prevFob =
832                     getForwardingObjectiveBuilder(mac, vlanId, prevPort);
833             flowObjectiveService.forward(prevDeviceId, prevFob.remove(
834                     new BridgingTableObjectiveContext(mac, vlanId)
835             ));
836
837             // Revoke previous IP table entry
838             prevIps.forEach(ip -> {
839                 if (ip.isIp4()) {
840                     routingRulePopulator.revokeIpRuleForHost(
841                             prevDeviceId, ip.getIp4Address(), mac, prevPort);
842                 }
843             });
844
845             // Populate new bridging table entry
846             ForwardingObjective.Builder newFob =
847                     getForwardingObjectiveBuilder(mac, vlanId, prevPort);
848             flowObjectiveService.forward(newDeviceId, newFob.add(
849                     new BridgingTableObjectiveContext(mac, vlanId)
850             ));
851
852             // Populate new IP table entry
853             newIps.forEach(ip -> {
854                 if (ip.isIp4()) {
855                     routingRulePopulator.populateIpRuleForHost(
856                             newDeviceId, ip.getIp4Address(), mac, newPort);
857                 }
858             });
859         }
860
861         private void processHostUpdatedEvent(HostEvent event) {
862             MacAddress mac = event.subject().mac();
863             VlanId vlanId = event.subject().vlan();
864             DeviceId prevDeviceId = event.prevSubject().location().deviceId();
865             PortNumber prevPort = event.prevSubject().location().port();
866             Set<IpAddress> prevIps = event.prevSubject().ipAddresses();
867             DeviceId newDeviceId = event.subject().location().deviceId();
868             PortNumber newPort = event.subject().location().port();
869             Set<IpAddress> newIps = event.subject().ipAddresses();
870             log.debug("Host {}/{} is updated", mac, vlanId);
871
872             // Revoke previous IP table entry
873             prevIps.forEach(ip -> {
874                 if (ip.isIp4()) {
875                     routingRulePopulator.revokeIpRuleForHost(
876                             prevDeviceId, ip.getIp4Address(), mac, prevPort);
877                 }
878             });
879
880             // Populate new IP table entry
881             newIps.forEach(ip -> {
882                 if (ip.isIp4()) {
883                     routingRulePopulator.populateIpRuleForHost(
884                             newDeviceId, ip.getIp4Address(), mac, newPort);
885                 }
886             });
887         }
888
889         @Override
890         public void event(HostEvent event) {
891             // Do not proceed without mastership
892             DeviceId deviceId = event.subject().location().deviceId();
893             if (!mastershipService.isLocalMaster(deviceId)) {
894                 return;
895             }
896
897             switch (event.type()) {
898                 case HOST_ADDED:
899                     processHostAddedEvent(event);
900                     break;
901                 case HOST_MOVED:
902                     processHostMovedEvent(event);
903                     break;
904                 case HOST_REMOVED:
905                     processHostRemoveEvent(event);
906                     break;
907                 case HOST_UPDATED:
908                     processHostUpdatedEvent(event);
909                     break;
910                 default:
911                     log.warn("Unsupported host event type: {}", event.type());
912                     break;
913             }
914         }
915     }
916
917     private static class BridgingTableObjectiveContext implements ObjectiveContext {
918         final MacAddress mac;
919         final VlanId vlanId;
920
921         BridgingTableObjectiveContext(MacAddress mac, VlanId vlanId) {
922             this.mac = mac;
923             this.vlanId = vlanId;
924         }
925
926         @Override
927         public void onSuccess(Objective objective) {
928             if (objective.op() == Objective.Operation.ADD) {
929                 log.debug("Successfully populate bridging table entry for {}/{}",
930                         mac, vlanId);
931             } else {
932                 log.debug("Successfully revoke bridging table entry for {}/{}",
933                         mac, vlanId);
934             }
935         }
936
937         @Override
938         public void onError(Objective objective, ObjectiveError error) {
939             if (objective.op() == Objective.Operation.ADD) {
940                 log.debug("Fail to populate bridging table entry for {}/{}. {}",
941                         mac, vlanId, error);
942             } else {
943                 log.debug("Fail to revoke bridging table entry for {}/{}. {}",
944                          mac, vlanId, error);
945             }
946         }
947     }
948 }