blob: e00d865c8559b9fdfdfe739cc3baca034c666442 [file] [log] [blame]
sangho80f11cb2015-04-01 13:05:26 -07001/*
Brian O'Connor0947d7e2017-08-03 21:12:30 -07002 * Copyright 2015-present Open Networking Foundation
sangho80f11cb2015-04-01 13:05:26 -07003 *
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 */
16package org.onosproject.segmentrouting;
17
Ray Milkeyae0068a2017-08-15 11:02:29 -070018import java.util.List;
19import java.util.Map;
20import java.util.Map.Entry;
21import java.util.Optional;
22import java.util.Set;
23import java.util.concurrent.ConcurrentHashMap;
24import java.util.concurrent.ConcurrentLinkedQueue;
25import java.util.concurrent.Executors;
26import java.util.concurrent.ScheduledExecutorService;
27import java.util.concurrent.ScheduledFuture;
28import java.util.concurrent.TimeUnit;
29import java.util.concurrent.atomic.AtomicBoolean;
30import java.util.stream.Collectors;
31
sangho80f11cb2015-04-01 13:05:26 -070032import org.apache.felix.scr.annotations.Activate;
33import org.apache.felix.scr.annotations.Component;
34import org.apache.felix.scr.annotations.Deactivate;
35import org.apache.felix.scr.annotations.Reference;
36import org.apache.felix.scr.annotations.ReferenceCardinality;
sangho27462c62015-05-14 00:39:53 -070037import org.apache.felix.scr.annotations.Service;
sangho80f11cb2015-04-01 13:05:26 -070038import org.onlab.packet.Ethernet;
Pier Ventreb6b81d52016-12-02 08:16:05 -080039import org.onlab.packet.ICMP6;
Charles Chan77277672015-10-20 16:24:19 -070040import org.onlab.packet.IPv4;
Pier Ventreb6a7f342016-11-26 21:05:22 -080041import org.onlab.packet.IPv6;
Charles Chan77277672015-10-20 16:24:19 -070042import org.onlab.packet.IpPrefix;
Jonathan Hart54541d12016-04-12 15:39:44 -070043import org.onlab.packet.VlanId;
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -070044import org.onlab.util.KryoNamespace;
Saurav Dasc3604f12016-03-23 11:22:49 -070045import org.onosproject.cfg.ComponentConfigService;
sangho80f11cb2015-04-01 13:05:26 -070046import org.onosproject.core.ApplicationId;
47import org.onosproject.core.CoreService;
48import org.onosproject.event.Event;
Jonathan Hart54541d12016-04-12 15:39:44 -070049import org.onosproject.mastership.MastershipService;
Pier Ventreb6a7f342016-11-26 21:05:22 -080050import org.onosproject.net.ConnectPoint;
Jonathan Hart54541d12016-04-12 15:39:44 -070051import org.onosproject.net.Device;
52import org.onosproject.net.DeviceId;
53import org.onosproject.net.Link;
54import org.onosproject.net.Port;
Charles Chanf4586112015-11-09 16:37:23 -080055import org.onosproject.net.PortNumber;
Charles Chan72f556a2015-10-05 17:50:33 -070056import org.onosproject.net.config.ConfigFactory;
57import org.onosproject.net.config.NetworkConfigEvent;
Charles Chan72f556a2015-10-05 17:50:33 -070058import org.onosproject.net.config.NetworkConfigListener;
Jonathan Hart54541d12016-04-12 15:39:44 -070059import org.onosproject.net.config.NetworkConfigRegistry;
Ray Milkeyae0068a2017-08-15 11:02:29 -070060import org.onosproject.net.config.basics.InterfaceConfig;
61import org.onosproject.net.config.basics.McastConfig;
Charles Chan72f556a2015-10-05 17:50:33 -070062import org.onosproject.net.config.basics.SubjectFactories;
Jonathan Hart54541d12016-04-12 15:39:44 -070063import org.onosproject.net.device.DeviceEvent;
64import org.onosproject.net.device.DeviceListener;
65import org.onosproject.net.device.DeviceService;
Charles Chanf4586112015-11-09 16:37:23 -080066import org.onosproject.net.flow.TrafficSelector;
67import org.onosproject.net.flow.TrafficTreatment;
Jonathan Hart54541d12016-04-12 15:39:44 -070068import org.onosproject.net.flowobjective.FlowObjectiveService;
Charles Chanf4586112015-11-09 16:37:23 -080069import org.onosproject.net.host.HostEvent;
70import org.onosproject.net.host.HostListener;
Pier Ventreb6a7f342016-11-26 21:05:22 -080071import org.onosproject.net.host.HostService;
Ray Milkeyae0068a2017-08-15 11:02:29 -070072import org.onosproject.net.intf.Interface;
73import org.onosproject.net.intf.InterfaceService;
Pier Ventreb6a7f342016-11-26 21:05:22 -080074import org.onosproject.net.link.LinkEvent;
75import org.onosproject.net.link.LinkListener;
76import org.onosproject.net.link.LinkService;
Charles Chanc91c8782016-03-30 17:54:24 -070077import org.onosproject.net.mcast.McastEvent;
78import org.onosproject.net.mcast.McastListener;
79import org.onosproject.net.mcast.MulticastRouteService;
Ray Milkeyae0068a2017-08-15 11:02:29 -070080import org.onosproject.net.neighbour.NeighbourResolutionService;
Pier Ventreb6a7f342016-11-26 21:05:22 -080081import org.onosproject.net.packet.InboundPacket;
82import org.onosproject.net.packet.PacketContext;
83import org.onosproject.net.packet.PacketProcessor;
84import org.onosproject.net.packet.PacketService;
Pier Ventref3cf5b92016-11-09 14:17:26 -080085import org.onosproject.net.topology.PathService;
Charles Chanc91c8782016-03-30 17:54:24 -070086import org.onosproject.net.topology.TopologyService;
Ray Milkeyae0068a2017-08-15 11:02:29 -070087import org.onosproject.routeservice.RouteEvent;
88import org.onosproject.routeservice.RouteListener;
89import org.onosproject.routeservice.RouteService;
Charles Chanc91c8782016-03-30 17:54:24 -070090import org.onosproject.segmentrouting.config.DeviceConfigNotFoundException;
91import org.onosproject.segmentrouting.config.DeviceConfiguration;
Pier Ventre6b19e482016-11-07 16:21:04 -080092import org.onosproject.segmentrouting.config.PwaasConfig;
Pier Ventre6b19e482016-11-07 16:21:04 -080093import org.onosproject.segmentrouting.config.SegmentRoutingAppConfig;
Ray Milkeyae0068a2017-08-15 11:02:29 -070094import org.onosproject.segmentrouting.config.SegmentRoutingDeviceConfig;
Charles Chan82f19972016-05-17 13:13:55 -070095import org.onosproject.segmentrouting.config.XConnectConfig;
Charles Chanc91c8782016-03-30 17:54:24 -070096import org.onosproject.segmentrouting.grouphandler.DefaultGroupHandler;
Saurav Das261c3002017-06-13 15:35:54 -070097import org.onosproject.segmentrouting.grouphandler.DestinationSet;
98import org.onosproject.segmentrouting.grouphandler.NextNeighbors;
Ray Milkeyae0068a2017-08-15 11:02:29 -070099import org.onosproject.segmentrouting.pwaas.L2TunnelHandler;
Saurav Das261c3002017-06-13 15:35:54 -0700100import org.onosproject.segmentrouting.storekey.DestinationSetNextObjectiveStoreKey;
Charles Chan1eaf4802016-04-18 13:44:03 -0700101import org.onosproject.segmentrouting.storekey.PortNextObjectiveStoreKey;
Charles Chan10b0fb72017-02-02 16:20:42 -0800102import org.onosproject.segmentrouting.storekey.VlanNextObjectiveStoreKey;
Charles Chan82f19972016-05-17 13:13:55 -0700103import org.onosproject.segmentrouting.storekey.XConnectStoreKey;
Jonathan Hart54541d12016-04-12 15:39:44 -0700104import org.onosproject.store.serializers.KryoNamespaces;
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700105import org.onosproject.store.service.EventuallyConsistentMap;
106import org.onosproject.store.service.EventuallyConsistentMapBuilder;
107import org.onosproject.store.service.StorageService;
108import org.onosproject.store.service.WallClockTimestamp;
sangho80f11cb2015-04-01 13:05:26 -0700109import org.slf4j.Logger;
110import org.slf4j.LoggerFactory;
111
Ray Milkeyae0068a2017-08-15 11:02:29 -0700112import com.google.common.collect.HashMultimap;
113import com.google.common.collect.ImmutableMap;
114import com.google.common.collect.Maps;
115import com.google.common.collect.Multimap;
sangho80f11cb2015-04-01 13:05:26 -0700116
Charles Chand6d25332016-02-26 22:19:52 -0800117import static com.google.common.base.Preconditions.checkState;
Pier Ventreadb4ae62016-11-23 09:57:42 -0800118import static org.onlab.packet.Ethernet.TYPE_ARP;
Yuta HIGUCHIebee2f12016-07-21 16:54:33 -0700119import static org.onlab.util.Tools.groupedThreads;
Charles Chand6d25332016-02-26 22:19:52 -0800120
Charles Chanb7f75ac2016-01-11 18:28:54 -0800121/**
122 * Segment routing manager.
123 */
Jonathan Hart54541d12016-04-12 15:39:44 -0700124@Service
125@Component(immediate = true)
sangho27462c62015-05-14 00:39:53 -0700126public class SegmentRoutingManager implements SegmentRoutingService {
sangho80f11cb2015-04-01 13:05:26 -0700127
Charles Chan46fdfaf2016-11-09 20:51:44 -0800128 private static Logger log = LoggerFactory.getLogger(SegmentRoutingManager.class);
sangho80f11cb2015-04-01 13:05:26 -0700129
130 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Charles Chandebfea32016-10-24 14:52:01 -0700131 private ComponentConfigService compCfgService;
sangho80f11cb2015-04-01 13:05:26 -0700132
133 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Pier Ventreb6a7f342016-11-26 21:05:22 -0800134 private NeighbourResolutionService neighbourResolutionService;
135
136 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Pier Ventref3cf5b92016-11-09 14:17:26 -0800137 public PathService pathService;
138
139 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Charles Chandebfea32016-10-24 14:52:01 -0700140 CoreService coreService;
sangho80f11cb2015-04-01 13:05:26 -0700141
142 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Charles Chandebfea32016-10-24 14:52:01 -0700143 PacketService packetService;
sangho80f11cb2015-04-01 13:05:26 -0700144
145 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Charles Chandebfea32016-10-24 14:52:01 -0700146 HostService hostService;
sangho80f11cb2015-04-01 13:05:26 -0700147
148 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Charles Chandebfea32016-10-24 14:52:01 -0700149 DeviceService deviceService;
sangho80f11cb2015-04-01 13:05:26 -0700150
151 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Pier Ventref3cf5b92016-11-09 14:17:26 -0800152 public FlowObjectiveService flowObjectiveService;
sangho80f11cb2015-04-01 13:05:26 -0700153
154 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Charles Chandebfea32016-10-24 14:52:01 -0700155 LinkService linkService;
sangho27462c62015-05-14 00:39:53 -0700156
Charles Chan82ab1932016-01-30 23:22:37 -0800157 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Pier Ventref3cf5b92016-11-09 14:17:26 -0800158 public MastershipService mastershipService;
Charles Chandebfea32016-10-24 14:52:01 -0700159
160 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Pier Ventref3cf5b92016-11-09 14:17:26 -0800161 public StorageService storageService;
Charles Chandebfea32016-10-24 14:52:01 -0700162
163 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
164 MulticastRouteService multicastRouteService;
165
166 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
167 TopologyService topologyService;
168
169 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Charles Chandebfea32016-10-24 14:52:01 -0700170 RouteService routeService;
Charles Chan82ab1932016-01-30 23:22:37 -0800171
172 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Charles Chan46fdfaf2016-11-09 20:51:44 -0800173 public NetworkConfigRegistry cfgService;
Charles Chan82ab1932016-01-30 23:22:37 -0800174
Saurav Dasc3604f12016-03-23 11:22:49 -0700175 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Charles Chan46fdfaf2016-11-09 20:51:44 -0800176 public InterfaceService interfaceService;
177
Charles Chandebfea32016-10-24 14:52:01 -0700178 ArpHandler arpHandler = null;
179 IcmpHandler icmpHandler = null;
180 IpHandler ipHandler = null;
181 RoutingRulePopulator routingRulePopulator = null;
Ray Milkeyb85de082017-04-05 09:42:04 -0700182 ApplicationId appId;
183 DeviceConfiguration deviceConfiguration = null;
sangho80f11cb2015-04-01 13:05:26 -0700184
Charles Chandebfea32016-10-24 14:52:01 -0700185 DefaultRoutingHandler defaultRoutingHandler = null;
sangho27462c62015-05-14 00:39:53 -0700186 private TunnelHandler tunnelHandler = null;
187 private PolicyHandler policyHandler = null;
Charles Chan2b078ae2015-10-14 11:24:40 -0700188 private InternalPacketProcessor processor = null;
189 private InternalLinkListener linkListener = null;
190 private InternalDeviceListener deviceListener = null;
Charles Chan82f19972016-05-17 13:13:55 -0700191 private AppConfigHandler appCfgHandler = null;
Charles Chandebfea32016-10-24 14:52:01 -0700192 XConnectHandler xConnectHandler = null;
Charles Chan1eaf4802016-04-18 13:44:03 -0700193 private McastHandler mcastHandler = null;
Charles Chan3ed34d82017-06-22 18:03:14 -0700194 private HostHandler hostHandler = null;
Pier Ventreb6a7f342016-11-26 21:05:22 -0800195 private RouteHandler routeHandler = null;
Pier Ventreb6b81d52016-12-02 08:16:05 -0800196 private SegmentRoutingNeighbourDispatcher neighbourHandler = null;
Pier Ventre6b19e482016-11-07 16:21:04 -0800197 private L2TunnelHandler l2TunnelHandler = null;
sangho80f11cb2015-04-01 13:05:26 -0700198 private InternalEventHandler eventHandler = new InternalEventHandler();
Charles Chan82ab1932016-01-30 23:22:37 -0800199 private final InternalHostListener hostListener = new InternalHostListener();
Charles Chanc91c8782016-03-30 17:54:24 -0700200 private final InternalConfigListener cfgListener = new InternalConfigListener(this);
201 private final InternalMcastListener mcastListener = new InternalMcastListener();
Charles Chandebfea32016-10-24 14:52:01 -0700202 private final InternalRouteEventListener routeListener = new InternalRouteEventListener();
sangho80f11cb2015-04-01 13:05:26 -0700203
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700204 private ScheduledExecutorService executorService = Executors
Yuta HIGUCHIebee2f12016-07-21 16:54:33 -0700205 .newScheduledThreadPool(1, groupedThreads("SegmentRoutingManager", "event-%d", log));
sangho80f11cb2015-04-01 13:05:26 -0700206
Saurav Das2d94d312015-11-24 23:21:05 -0800207 @SuppressWarnings("unused")
sangho80f11cb2015-04-01 13:05:26 -0700208 private static ScheduledFuture<?> eventHandlerFuture = null;
Saurav Das2d94d312015-11-24 23:21:05 -0800209 @SuppressWarnings("rawtypes")
Yuta HIGUCHIebee2f12016-07-21 16:54:33 -0700210 private ConcurrentLinkedQueue<Event> eventQueue = new ConcurrentLinkedQueue<>();
Charles Chanf4586112015-11-09 16:37:23 -0800211 private Map<DeviceId, DefaultGroupHandler> groupHandlerMap =
Charles Chanb7f75ac2016-01-11 18:28:54 -0800212 new ConcurrentHashMap<>();
213 /**
Saurav Das261c3002017-06-13 15:35:54 -0700214 * Per device next objective ID store with (device id + destination set) as key.
Charles Chan53de91f2017-08-22 15:07:34 -0700215 * Used to keep track on MPLS group information.
Charles Chanb7f75ac2016-01-11 18:28:54 -0800216 */
Saurav Das261c3002017-06-13 15:35:54 -0700217 EventuallyConsistentMap<DestinationSetNextObjectiveStoreKey, NextNeighbors>
218 dsNextObjStore = null;
Charles Chanb7f75ac2016-01-11 18:28:54 -0800219 /**
Charles Chan53de91f2017-08-22 15:07:34 -0700220 * Per device next objective ID store with (device id + vlanid) as key.
221 * Used to keep track on L2 flood group information.
Charles Chanb7f75ac2016-01-11 18:28:54 -0800222 */
Ray Milkeyb85de082017-04-05 09:42:04 -0700223 EventuallyConsistentMap<VlanNextObjectiveStoreKey, Integer>
Charles Chan10b0fb72017-02-02 16:20:42 -0800224 vlanNextObjStore = null;
Charles Chanb7f75ac2016-01-11 18:28:54 -0800225 /**
Charles Chan53de91f2017-08-22 15:07:34 -0700226 * Per device next objective ID store with (device id + port + treatment + meta) as key.
227 * Used to keep track on L2 interface group and L3 unicast group information.
Charles Chanb7f75ac2016-01-11 18:28:54 -0800228 */
Ray Milkeyb85de082017-04-05 09:42:04 -0700229 EventuallyConsistentMap<PortNextObjectiveStoreKey, Integer>
Saurav Das2d94d312015-11-24 23:21:05 -0800230 portNextObjStore = null;
Charles Chan10b0fb72017-02-02 16:20:42 -0800231
Saurav Das62ae6792017-05-15 15:34:25 -0700232 // Local store for all links seen and their present status, used for
233 // optimized routing. The existence of the link in the keys is enough to know
234 // if the link has been "seen-before" by this instance of the controller.
235 // The boolean value indicates if the link is currently up or not.
236 // XXX Currently the optimized routing logic depends on "forgetting" a link
237 // when a switch goes down, but "remembering" it when only the link goes down.
238 // Consider changing this logic so we can use the Link Service instead of
239 // a local cache.
240 private Map<Link, Boolean> seenLinks = new ConcurrentHashMap<>();
241
Saurav Das2d94d312015-11-24 23:21:05 -0800242 private EventuallyConsistentMap<String, Tunnel> tunnelStore = null;
243 private EventuallyConsistentMap<String, Policy> policyStore = null;
sangho4a5c42a2015-05-20 22:16:38 -0700244
Saurav Das261c3002017-06-13 15:35:54 -0700245 private AtomicBoolean programmingScheduled = new AtomicBoolean();
246
Charles Chanc91c8782016-03-30 17:54:24 -0700247 private final ConfigFactory<DeviceId, SegmentRoutingDeviceConfig> deviceConfigFactory =
Charles Chan82f19972016-05-17 13:13:55 -0700248 new ConfigFactory<DeviceId, SegmentRoutingDeviceConfig>(
249 SubjectFactories.DEVICE_SUBJECT_FACTORY,
Charles Chanc91c8782016-03-30 17:54:24 -0700250 SegmentRoutingDeviceConfig.class, "segmentrouting") {
Charles Chan72f556a2015-10-05 17:50:33 -0700251 @Override
Charles Chan82ab1932016-01-30 23:22:37 -0800252 public SegmentRoutingDeviceConfig createConfig() {
253 return new SegmentRoutingDeviceConfig();
Charles Chan72f556a2015-10-05 17:50:33 -0700254 }
255 };
Pier Ventre6b19e482016-11-07 16:21:04 -0800256
Charles Chanc91c8782016-03-30 17:54:24 -0700257 private final ConfigFactory<ApplicationId, SegmentRoutingAppConfig> appConfigFactory =
Charles Chan82f19972016-05-17 13:13:55 -0700258 new ConfigFactory<ApplicationId, SegmentRoutingAppConfig>(
259 SubjectFactories.APP_SUBJECT_FACTORY,
Charles Chanc91c8782016-03-30 17:54:24 -0700260 SegmentRoutingAppConfig.class, "segmentrouting") {
Charles Chan82ab1932016-01-30 23:22:37 -0800261 @Override
262 public SegmentRoutingAppConfig createConfig() {
263 return new SegmentRoutingAppConfig();
264 }
265 };
Pier Ventre6b19e482016-11-07 16:21:04 -0800266
Charles Chan82f19972016-05-17 13:13:55 -0700267 private final ConfigFactory<ApplicationId, XConnectConfig> xConnectConfigFactory =
268 new ConfigFactory<ApplicationId, XConnectConfig>(
269 SubjectFactories.APP_SUBJECT_FACTORY,
270 XConnectConfig.class, "xconnect") {
271 @Override
272 public XConnectConfig createConfig() {
273 return new XConnectConfig();
274 }
275 };
Pier Ventre6b19e482016-11-07 16:21:04 -0800276
Charles Chanc91c8782016-03-30 17:54:24 -0700277 private ConfigFactory<ApplicationId, McastConfig> mcastConfigFactory =
Charles Chan82f19972016-05-17 13:13:55 -0700278 new ConfigFactory<ApplicationId, McastConfig>(
279 SubjectFactories.APP_SUBJECT_FACTORY,
Charles Chanc91c8782016-03-30 17:54:24 -0700280 McastConfig.class, "multicast") {
281 @Override
282 public McastConfig createConfig() {
283 return new McastConfig();
284 }
285 };
286
Pier Ventre6b19e482016-11-07 16:21:04 -0800287 private final ConfigFactory<ApplicationId, PwaasConfig> pwaasConfigFactory =
288 new ConfigFactory<ApplicationId, PwaasConfig>(
289 SubjectFactories.APP_SUBJECT_FACTORY,
290 PwaasConfig.class, "pwaas") {
291 @Override
292 public PwaasConfig createConfig() {
293 return new PwaasConfig();
294 }
295 };
296
Charles Chan3ed34d82017-06-22 18:03:14 -0700297 private static final Object THREAD_SCHED_LOCK = new Object();
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700298 private static int numOfEventsQueued = 0;
299 private static int numOfEventsExecuted = 0;
sangho80f11cb2015-04-01 13:05:26 -0700300 private static int numOfHandlerExecution = 0;
301 private static int numOfHandlerScheduled = 0;
302
Charles Chan1963f4f2016-02-18 14:22:42 -0800303 /**
304 * Segment Routing App ID.
305 */
Charles Chan46fdfaf2016-11-09 20:51:44 -0800306 public static final String APP_NAME = "org.onosproject.segmentrouting";
Charles Chan10b0fb72017-02-02 16:20:42 -0800307
Charles Chanb7f75ac2016-01-11 18:28:54 -0800308 /**
309 * The default VLAN ID assigned to the interfaces without subnet config.
310 */
Charles Chan10b0fb72017-02-02 16:20:42 -0800311 public static final VlanId INTERNAL_VLAN = VlanId.vlanId((short) 4094);
Saurav Das7c305372015-10-28 12:39:42 -0700312
sangho80f11cb2015-04-01 13:05:26 -0700313 @Activate
314 protected void activate() {
Charles Chan46fdfaf2016-11-09 20:51:44 -0800315 appId = coreService.registerApplication(APP_NAME);
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700316
317 log.debug("Creating EC map nsnextobjectivestore");
Saurav Das261c3002017-06-13 15:35:54 -0700318 EventuallyConsistentMapBuilder<DestinationSetNextObjectiveStoreKey, NextNeighbors>
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700319 nsNextObjMapBuilder = storageService.eventuallyConsistentMapBuilder();
Saurav Das261c3002017-06-13 15:35:54 -0700320 dsNextObjStore = nsNextObjMapBuilder
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700321 .withName("nsnextobjectivestore")
Jonathan Hart54541d12016-04-12 15:39:44 -0700322 .withSerializer(createSerializer())
Madan Jampani675ae202015-06-24 19:05:56 -0700323 .withTimestampProvider((k, v) -> new WallClockTimestamp())
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700324 .build();
Saurav Das261c3002017-06-13 15:35:54 -0700325 log.trace("Current size {}", dsNextObjStore.size());
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700326
Charles Chan10b0fb72017-02-02 16:20:42 -0800327 log.debug("Creating EC map vlannextobjectivestore");
328 EventuallyConsistentMapBuilder<VlanNextObjectiveStoreKey, Integer>
329 vlanNextObjMapBuilder = storageService.eventuallyConsistentMapBuilder();
330 vlanNextObjStore = vlanNextObjMapBuilder
331 .withName("vlannextobjectivestore")
Jonathan Hart54541d12016-04-12 15:39:44 -0700332 .withSerializer(createSerializer())
Charles Chan77277672015-10-20 16:24:19 -0700333 .withTimestampProvider((k, v) -> new WallClockTimestamp())
334 .build();
335
Saurav Das2d94d312015-11-24 23:21:05 -0800336 log.debug("Creating EC map subnetnextobjectivestore");
337 EventuallyConsistentMapBuilder<PortNextObjectiveStoreKey, Integer>
338 portNextObjMapBuilder = storageService.eventuallyConsistentMapBuilder();
339 portNextObjStore = portNextObjMapBuilder
340 .withName("portnextobjectivestore")
Jonathan Hart54541d12016-04-12 15:39:44 -0700341 .withSerializer(createSerializer())
Saurav Das2d94d312015-11-24 23:21:05 -0800342 .withTimestampProvider((k, v) -> new WallClockTimestamp())
343 .build();
344
sangho4a5c42a2015-05-20 22:16:38 -0700345 EventuallyConsistentMapBuilder<String, Tunnel> tunnelMapBuilder =
346 storageService.eventuallyConsistentMapBuilder();
sangho4a5c42a2015-05-20 22:16:38 -0700347 tunnelStore = tunnelMapBuilder
348 .withName("tunnelstore")
Jonathan Hart54541d12016-04-12 15:39:44 -0700349 .withSerializer(createSerializer())
Madan Jampani675ae202015-06-24 19:05:56 -0700350 .withTimestampProvider((k, v) -> new WallClockTimestamp())
sangho4a5c42a2015-05-20 22:16:38 -0700351 .build();
352
353 EventuallyConsistentMapBuilder<String, Policy> policyMapBuilder =
354 storageService.eventuallyConsistentMapBuilder();
sangho4a5c42a2015-05-20 22:16:38 -0700355 policyStore = policyMapBuilder
356 .withName("policystore")
Jonathan Hart54541d12016-04-12 15:39:44 -0700357 .withSerializer(createSerializer())
Madan Jampani675ae202015-06-24 19:05:56 -0700358 .withTimestampProvider((k, v) -> new WallClockTimestamp())
sangho4a5c42a2015-05-20 22:16:38 -0700359 .build();
360
Saurav Dasc3604f12016-03-23 11:22:49 -0700361 compCfgService.preSetProperty("org.onosproject.net.group.impl.GroupManager",
Pier Luigib9632ba2017-01-12 18:14:58 -0800362 "purgeOnDisconnection", "true");
Saurav Dasc3604f12016-03-23 11:22:49 -0700363 compCfgService.preSetProperty("org.onosproject.net.flow.impl.FlowRuleManager",
Pier Luigib9632ba2017-01-12 18:14:58 -0800364 "purgeOnDisconnection", "true");
Pier Luigib9632ba2017-01-12 18:14:58 -0800365 compCfgService.preSetProperty("org.onosproject.provider.host.impl.HostLocationProvider",
366 "requestInterceptsEnabled", "false");
Charles Chanc1909e12017-08-08 15:13:37 -0700367 compCfgService.preSetProperty("org.onosproject.net.neighbour.impl.NeighbourResolutionManager",
Pier Luigibc976df2017-01-12 22:46:39 -0800368 "requestInterceptsEnabled", "false");
Charles Chan9597f8d2017-07-24 15:56:10 -0700369 compCfgService.preSetProperty("org.onosproject.dhcprelay.DhcpRelayManager",
Pier Luigibc976df2017-01-12 22:46:39 -0800370 "arpEnabled", "false");
Pier Luigi0ebeb312017-02-02 22:31:34 -0800371 compCfgService.preSetProperty("org.onosproject.net.host.impl.HostManager",
372 "greedyLearningIpv6", "true");
Charles Chancf8ea472017-02-28 15:15:17 -0800373 compCfgService.preSetProperty("org.onosproject.routing.cpr.ControlPlaneRedirectManager",
374 "forceUnprovision", "true");
Charles Chanc7b73c72017-08-10 16:57:28 -0700375 compCfgService.preSetProperty("org.onosproject.routeservice.store.RouteStoreImpl",
Charles Chan4c95c0d2017-07-20 16:16:25 -0700376 "distributed", "true");
Charles Chan804772f2017-08-14 11:42:11 -0700377 compCfgService.preSetProperty("org.onosproject.provider.host.impl.HostLocationProvider",
378 "multihomingEnabled", "true");
Saurav Dasc3604f12016-03-23 11:22:49 -0700379
Charles Chan2b078ae2015-10-14 11:24:40 -0700380 processor = new InternalPacketProcessor();
381 linkListener = new InternalLinkListener();
382 deviceListener = new InternalDeviceListener();
Charles Chan82f19972016-05-17 13:13:55 -0700383 appCfgHandler = new AppConfigHandler(this);
384 xConnectHandler = new XConnectHandler(this);
Charles Chan1eaf4802016-04-18 13:44:03 -0700385 mcastHandler = new McastHandler(this);
386 hostHandler = new HostHandler(this);
Charles Chandebfea32016-10-24 14:52:01 -0700387 routeHandler = new RouteHandler(this);
Pier Ventreb6b81d52016-12-02 08:16:05 -0800388 neighbourHandler = new SegmentRoutingNeighbourDispatcher(this);
Pier Ventre6b19e482016-11-07 16:21:04 -0800389 l2TunnelHandler = new L2TunnelHandler(this);
Charles Chan2b078ae2015-10-14 11:24:40 -0700390
Charles Chand6d25332016-02-26 22:19:52 -0800391 cfgService.addListener(cfgListener);
Charles Chanc91c8782016-03-30 17:54:24 -0700392 cfgService.registerConfigFactory(deviceConfigFactory);
393 cfgService.registerConfigFactory(appConfigFactory);
Charles Chan82f19972016-05-17 13:13:55 -0700394 cfgService.registerConfigFactory(xConnectConfigFactory);
Charles Chanc91c8782016-03-30 17:54:24 -0700395 cfgService.registerConfigFactory(mcastConfigFactory);
Pier Ventre6b19e482016-11-07 16:21:04 -0800396 cfgService.registerConfigFactory(pwaasConfigFactory);
Charles Chan82ab1932016-01-30 23:22:37 -0800397 hostService.addListener(hostListener);
Charles Chan2b078ae2015-10-14 11:24:40 -0700398 packetService.addProcessor(processor, PacketProcessor.director(2));
399 linkService.addListener(linkListener);
400 deviceService.addListener(deviceListener);
Charles Chanc91c8782016-03-30 17:54:24 -0700401 multicastRouteService.addListener(mcastListener);
Charles Chanfd48c222017-06-19 00:43:31 -0700402 routeService.addListener(routeListener);
Charles Chan2b078ae2015-10-14 11:24:40 -0700403
404 cfgListener.configureNetwork();
405
sangho80f11cb2015-04-01 13:05:26 -0700406 log.info("Started");
407 }
408
Jonathan Hart54541d12016-04-12 15:39:44 -0700409 private KryoNamespace.Builder createSerializer() {
410 return new KryoNamespace.Builder()
411 .register(KryoNamespaces.API)
Saurav Das261c3002017-06-13 15:35:54 -0700412 .register(DestinationSetNextObjectiveStoreKey.class,
Charles Chan10b0fb72017-02-02 16:20:42 -0800413 VlanNextObjectiveStoreKey.class,
Saurav Das261c3002017-06-13 15:35:54 -0700414 DestinationSet.class,
415 NextNeighbors.class,
Jonathan Hart54541d12016-04-12 15:39:44 -0700416 Tunnel.class,
417 DefaultTunnel.class,
418 Policy.class,
419 TunnelPolicy.class,
420 Policy.Type.class,
421 PortNextObjectiveStoreKey.class,
Charles Chan82f19972016-05-17 13:13:55 -0700422 XConnectStoreKey.class
Jonathan Hart54541d12016-04-12 15:39:44 -0700423 );
424 }
425
sangho80f11cb2015-04-01 13:05:26 -0700426 @Deactivate
427 protected void deactivate() {
Charles Chan72f556a2015-10-05 17:50:33 -0700428 cfgService.removeListener(cfgListener);
Charles Chanc91c8782016-03-30 17:54:24 -0700429 cfgService.unregisterConfigFactory(deviceConfigFactory);
430 cfgService.unregisterConfigFactory(appConfigFactory);
Charles Chandebfea32016-10-24 14:52:01 -0700431 cfgService.unregisterConfigFactory(xConnectConfigFactory);
Charles Chanc91c8782016-03-30 17:54:24 -0700432 cfgService.unregisterConfigFactory(mcastConfigFactory);
Pier Ventre6b19e482016-11-07 16:21:04 -0800433 cfgService.unregisterConfigFactory(pwaasConfigFactory);
Charles Chan72f556a2015-10-05 17:50:33 -0700434
Charles Chanfd48c222017-06-19 00:43:31 -0700435 hostService.removeListener(hostListener);
sangho80f11cb2015-04-01 13:05:26 -0700436 packetService.removeProcessor(processor);
Charles Chan2b078ae2015-10-14 11:24:40 -0700437 linkService.removeListener(linkListener);
438 deviceService.removeListener(deviceListener);
Charles Chanc91c8782016-03-30 17:54:24 -0700439 multicastRouteService.removeListener(mcastListener);
Charles Chandebfea32016-10-24 14:52:01 -0700440 routeService.removeListener(routeListener);
Charles Chanc91c8782016-03-30 17:54:24 -0700441
Charles Chan2e71ef32017-02-23 15:44:08 -0800442 neighbourResolutionService.unregisterNeighbourHandlers(appId);
443
sangho80f11cb2015-04-01 13:05:26 -0700444 processor = null;
Charles Chan2b078ae2015-10-14 11:24:40 -0700445 linkListener = null;
Charles Chanc91c8782016-03-30 17:54:24 -0700446 deviceListener = null;
Charles Chan2b078ae2015-10-14 11:24:40 -0700447 groupHandlerMap.clear();
448
Saurav Das261c3002017-06-13 15:35:54 -0700449 dsNextObjStore.destroy();
Charles Chan10b0fb72017-02-02 16:20:42 -0800450 vlanNextObjStore.destroy();
Charles Chanc91c8782016-03-30 17:54:24 -0700451 portNextObjStore.destroy();
Charles Chanc91c8782016-03-30 17:54:24 -0700452 tunnelStore.destroy();
453 policyStore.destroy();
sangho80f11cb2015-04-01 13:05:26 -0700454 log.info("Stopped");
455 }
456
sangho27462c62015-05-14 00:39:53 -0700457 @Override
458 public List<Tunnel> getTunnels() {
459 return tunnelHandler.getTunnels();
460 }
461
462 @Override
sanghobd812f82015-06-29 14:58:47 -0700463 public TunnelHandler.Result createTunnel(Tunnel tunnel) {
464 return tunnelHandler.createTunnel(tunnel);
sangho27462c62015-05-14 00:39:53 -0700465 }
466
467 @Override
sanghobd812f82015-06-29 14:58:47 -0700468 public TunnelHandler.Result removeTunnel(Tunnel tunnel) {
sangho27462c62015-05-14 00:39:53 -0700469 for (Policy policy: policyHandler.getPolicies()) {
470 if (policy.type() == Policy.Type.TUNNEL_FLOW) {
471 TunnelPolicy tunnelPolicy = (TunnelPolicy) policy;
472 if (tunnelPolicy.tunnelId().equals(tunnel.id())) {
473 log.warn("Cannot remove the tunnel used by a policy");
sanghobd812f82015-06-29 14:58:47 -0700474 return TunnelHandler.Result.TUNNEL_IN_USE;
sangho27462c62015-05-14 00:39:53 -0700475 }
476 }
477 }
sanghobd812f82015-06-29 14:58:47 -0700478 return tunnelHandler.removeTunnel(tunnel);
sangho27462c62015-05-14 00:39:53 -0700479 }
480
481 @Override
sanghobd812f82015-06-29 14:58:47 -0700482 public PolicyHandler.Result removePolicy(Policy policy) {
483 return policyHandler.removePolicy(policy);
sangho27462c62015-05-14 00:39:53 -0700484 }
485
486 @Override
sanghobd812f82015-06-29 14:58:47 -0700487 public PolicyHandler.Result createPolicy(Policy policy) {
488 return policyHandler.createPolicy(policy);
sangho27462c62015-05-14 00:39:53 -0700489 }
490
491 @Override
492 public List<Policy> getPolicies() {
493 return policyHandler.getPolicies();
494 }
495
Saurav Das07c74602016-04-27 18:35:50 -0700496 @Override
497 public void rerouteNetwork() {
498 cfgListener.configureNetwork();
Saurav Das07c74602016-04-27 18:35:50 -0700499 }
500
Charles Chand7844e52016-10-20 17:02:44 -0700501 @Override
Pier Ventreb6a7f342016-11-26 21:05:22 -0800502 public Map<DeviceId, Set<IpPrefix>> getDeviceSubnetMap() {
503 Map<DeviceId, Set<IpPrefix>> deviceSubnetMap = Maps.newHashMap();
Charles Chand7844e52016-10-20 17:02:44 -0700504 deviceService.getAvailableDevices().forEach(device -> {
505 deviceSubnetMap.put(device.id(), deviceConfiguration.getSubnets(device.id()));
506 });
507 return deviceSubnetMap;
508 }
509
Saurav Das62ae6792017-05-15 15:34:25 -0700510
511 @Override
512 public ImmutableMap<DeviceId, EcmpShortestPathGraph> getCurrentEcmpSpg() {
513 if (defaultRoutingHandler != null) {
514 return defaultRoutingHandler.getCurrentEmcpSpgMap();
515 } else {
516 return null;
517 }
518 }
519
520 @Override
Saurav Das261c3002017-06-13 15:35:54 -0700521 public ImmutableMap<DestinationSetNextObjectiveStoreKey, NextNeighbors> getDestinationSet() {
522 if (dsNextObjStore != null) {
523 return ImmutableMap.copyOf(dsNextObjStore.entrySet());
Saurav Das62ae6792017-05-15 15:34:25 -0700524 } else {
525 return ImmutableMap.of();
526 }
527 }
528
Saurav Dasfbe74572017-08-03 18:30:35 -0700529 @Override
530 public void verifyGroups(DeviceId id) {
531 DefaultGroupHandler gh = groupHandlerMap.get(id);
532 if (gh != null) {
533 gh.triggerBucketCorrector();
534 }
535 }
536
sangho80f1f892015-05-19 11:57:42 -0700537 /**
Ray Milkeyb85de082017-04-05 09:42:04 -0700538 * Extracts the application ID from the manager.
539 *
540 * @return application ID
541 */
542 public ApplicationId appId() {
543 return appId;
544 }
545
546 /**
547 * Returns the device configuration.
548 *
549 * @return device configuration
550 */
551 public DeviceConfiguration deviceConfiguration() {
552 return deviceConfiguration;
553 }
554
555 /**
Saurav Das261c3002017-06-13 15:35:54 -0700556 * Per device next objective ID store with (device id + destination set) as key.
Charles Chan53de91f2017-08-22 15:07:34 -0700557 * Used to keep track on MPLS group information.
Ray Milkeyb85de082017-04-05 09:42:04 -0700558 *
559 * @return next objective ID store
560 */
Saurav Das261c3002017-06-13 15:35:54 -0700561 public EventuallyConsistentMap<DestinationSetNextObjectiveStoreKey, NextNeighbors>
562 dsNextObjStore() {
563 return dsNextObjStore;
Ray Milkeyb85de082017-04-05 09:42:04 -0700564 }
565
566 /**
Charles Chan53de91f2017-08-22 15:07:34 -0700567 * Per device next objective ID store with (device id + vlanid) as key.
568 * Used to keep track on L2 flood group information.
Ray Milkeyb85de082017-04-05 09:42:04 -0700569 *
570 * @return vlan next object store
571 */
572 public EventuallyConsistentMap<VlanNextObjectiveStoreKey, Integer> vlanNextObjStore() {
573 return vlanNextObjStore;
574 }
575
576 /**
Charles Chan53de91f2017-08-22 15:07:34 -0700577 * Per device next objective ID store with (device id + port + treatment + meta) as key.
578 * Used to keep track on L2 interface group and L3 unicast group information.
Ray Milkeyb85de082017-04-05 09:42:04 -0700579 *
580 * @return port next object store.
581 */
582 public EventuallyConsistentMap<PortNextObjectiveStoreKey, Integer> portNextObjStore() {
583 return portNextObjStore;
584 }
585
586 /**
Saurav Das261c3002017-06-13 15:35:54 -0700587 * Returns the MPLS-ECMP configuration which indicates whether ECMP on
588 * labeled packets should be programmed or not.
Pier Ventre7a78de22016-10-31 15:00:01 -0700589 *
590 * @return MPLS-ECMP value
591 */
592 public boolean getMplsEcmp() {
593 SegmentRoutingAppConfig segmentRoutingAppConfig = cfgService
594 .getConfig(this.appId, SegmentRoutingAppConfig.class);
595 return segmentRoutingAppConfig != null && segmentRoutingAppConfig.mplsEcmp();
596 }
597
598 /**
sangho80f1f892015-05-19 11:57:42 -0700599 * Returns the tunnel object with the tunnel ID.
600 *
601 * @param tunnelId Tunnel ID
602 * @return Tunnel reference
603 */
sangho27462c62015-05-14 00:39:53 -0700604 public Tunnel getTunnel(String tunnelId) {
605 return tunnelHandler.getTunnel(tunnelId);
606 }
607
Charles Chan90772a72017-02-08 15:52:08 -0800608 // TODO Consider moving these to InterfaceService
sangho80f11cb2015-04-01 13:05:26 -0700609 /**
Charles Chan10b0fb72017-02-02 16:20:42 -0800610 * Returns untagged VLAN configured on given connect point.
Charles Chan90772a72017-02-08 15:52:08 -0800611 * <p>
612 * Only returns the first match if there are multiple untagged VLAN configured
613 * on the connect point.
sangho80f11cb2015-04-01 13:05:26 -0700614 *
Charles Chan10b0fb72017-02-02 16:20:42 -0800615 * @param connectPoint connect point
616 * @return untagged VLAN or null if not configured
sangho80f11cb2015-04-01 13:05:26 -0700617 */
Charles Chan3ed34d82017-06-22 18:03:14 -0700618 VlanId getUntaggedVlanId(ConnectPoint connectPoint) {
Charles Chan10b0fb72017-02-02 16:20:42 -0800619 return interfaceService.getInterfacesByPort(connectPoint).stream()
620 .filter(intf -> !intf.vlanUntagged().equals(VlanId.NONE))
621 .map(Interface::vlanUntagged)
622 .findFirst().orElse(null);
sangho80f11cb2015-04-01 13:05:26 -0700623 }
624
sangho27462c62015-05-14 00:39:53 -0700625 /**
Charles Chan90772a72017-02-08 15:52:08 -0800626 * Returns tagged VLAN configured on given connect point.
627 * <p>
628 * Returns all matches if there are multiple tagged VLAN configured
629 * on the connect point.
630 *
631 * @param connectPoint connect point
632 * @return tagged VLAN or empty set if not configured
633 */
Charles Chan3ed34d82017-06-22 18:03:14 -0700634 Set<VlanId> getTaggedVlanId(ConnectPoint connectPoint) {
Charles Chan90772a72017-02-08 15:52:08 -0800635 Set<Interface> interfaces = interfaceService.getInterfacesByPort(connectPoint);
636 return interfaces.stream()
637 .map(Interface::vlanTagged)
Charles Chan3ed34d82017-06-22 18:03:14 -0700638 .flatMap(Set::stream)
Charles Chan90772a72017-02-08 15:52:08 -0800639 .collect(Collectors.toSet());
640 }
641
642 /**
643 * Returns native VLAN configured on given connect point.
644 * <p>
645 * Only returns the first match if there are multiple native VLAN configured
646 * on the connect point.
647 *
648 * @param connectPoint connect point
649 * @return native VLAN or null if not configured
650 */
Charles Chan3ed34d82017-06-22 18:03:14 -0700651 VlanId getNativeVlanId(ConnectPoint connectPoint) {
Charles Chan90772a72017-02-08 15:52:08 -0800652 Set<Interface> interfaces = interfaceService.getInterfacesByPort(connectPoint);
653 return interfaces.stream()
654 .filter(intf -> !intf.vlanNative().equals(VlanId.NONE))
655 .map(Interface::vlanNative)
656 .findFirst()
657 .orElse(null);
658 }
659
660 /**
Charles Chand9265a32017-06-16 15:19:24 -0700661 * Returns internal VLAN for untagged hosts on given connect point.
662 * <p>
663 * The internal VLAN is either vlan-untagged for an access port,
664 * or vlan-native for a trunk port.
665 *
666 * @param connectPoint connect point
667 * @return internal VLAN or null if both vlan-untagged and vlan-native are undefined
668 */
Charles Chan3ed34d82017-06-22 18:03:14 -0700669 VlanId getInternalVlanId(ConnectPoint connectPoint) {
Charles Chand9265a32017-06-16 15:19:24 -0700670 VlanId untaggedVlanId = getUntaggedVlanId(connectPoint);
671 VlanId nativeVlanId = getNativeVlanId(connectPoint);
672 return untaggedVlanId != null ? untaggedVlanId : nativeVlanId;
673 }
674
675 /**
Charles Chan3ed34d82017-06-22 18:03:14 -0700676 * Returns optional pair device ID of given device.
677 *
678 * @param deviceId device ID
679 * @return optional pair device ID. Might be empty if pair device is not configured
680 */
681 Optional<DeviceId> getPairDeviceId(DeviceId deviceId) {
682 SegmentRoutingDeviceConfig deviceConfig =
683 cfgService.getConfig(deviceId, SegmentRoutingDeviceConfig.class);
684 return Optional.ofNullable(deviceConfig).map(SegmentRoutingDeviceConfig::pairDeviceId);
685 }
686 /**
687 * Returns optional pair device local port of given device.
688 *
689 * @param deviceId device ID
690 * @return optional pair device ID. Might be empty if pair device is not configured
691 */
692 Optional<PortNumber> getPairLocalPorts(DeviceId deviceId) {
693 SegmentRoutingDeviceConfig deviceConfig =
694 cfgService.getConfig(deviceId, SegmentRoutingDeviceConfig.class);
695 return Optional.ofNullable(deviceConfig).map(SegmentRoutingDeviceConfig::pairLocalPort);
696 }
697
698 /**
Charles Chan90772a72017-02-08 15:52:08 -0800699 * Returns vlan port map of given device.
700 *
701 * @param deviceId device id
702 * @return vlan-port multimap
703 */
704 public Multimap<VlanId, PortNumber> getVlanPortMap(DeviceId deviceId) {
705 HashMultimap<VlanId, PortNumber> vlanPortMap = HashMultimap.create();
706
707 interfaceService.getInterfaces().stream()
708 .filter(intf -> intf.connectPoint().deviceId().equals(deviceId))
709 .forEach(intf -> {
710 vlanPortMap.put(intf.vlanUntagged(), intf.connectPoint().port());
Charles Chan3ed34d82017-06-22 18:03:14 -0700711 intf.vlanTagged().forEach(vlanTagged ->
712 vlanPortMap.put(vlanTagged, intf.connectPoint().port())
713 );
Charles Chan90772a72017-02-08 15:52:08 -0800714 vlanPortMap.put(intf.vlanNative(), intf.connectPoint().port());
715 });
716 vlanPortMap.removeAll(VlanId.NONE);
717
718 return vlanPortMap;
719 }
720
721 /**
Saurav Das2d94d312015-11-24 23:21:05 -0800722 * Returns the next objective ID for the given subnet prefix. It is expected
Charles Chan10b0fb72017-02-02 16:20:42 -0800723 * Returns the next objective ID for the given vlan id. It is expected
Saurav Das2d94d312015-11-24 23:21:05 -0800724 * that the next-objective has been pre-created from configuration.
Charles Chan77277672015-10-20 16:24:19 -0700725 *
726 * @param deviceId Device ID
Charles Chan10b0fb72017-02-02 16:20:42 -0800727 * @param vlanId VLAN ID
Saurav Das2d94d312015-11-24 23:21:05 -0800728 * @return next objective ID or -1 if it was not found
Charles Chan77277672015-10-20 16:24:19 -0700729 */
Charles Chan3ed34d82017-06-22 18:03:14 -0700730 int getVlanNextObjectiveId(DeviceId deviceId, VlanId vlanId) {
Charles Chan77277672015-10-20 16:24:19 -0700731 if (groupHandlerMap.get(deviceId) != null) {
Charles Chan10b0fb72017-02-02 16:20:42 -0800732 log.trace("getVlanNextObjectiveId query in device {}", deviceId);
733 return groupHandlerMap.get(deviceId).getVlanNextObjectiveId(vlanId);
Charles Chan77277672015-10-20 16:24:19 -0700734 } else {
Charles Chan10b0fb72017-02-02 16:20:42 -0800735 log.warn("getVlanNextObjectiveId query - groupHandler for "
Saurav Das2d94d312015-11-24 23:21:05 -0800736 + "device {} not found", deviceId);
737 return -1;
738 }
739 }
740
741 /**
742 * Returns the next objective ID for the given portNumber, given the treatment.
743 * There could be multiple different treatments to the same outport, which
Saurav Das2cb38292017-03-29 19:09:17 -0700744 * would result in different objectives. If the next object does not exist,
745 * and should be created, a new one is created and its id is returned.
Saurav Das2d94d312015-11-24 23:21:05 -0800746 *
747 * @param deviceId Device ID
748 * @param portNum port number on device for which NextObjective is queried
749 * @param treatment the actions to apply on the packets (should include outport)
750 * @param meta metadata passed into the creation of a Next Objective if necessary
Saurav Das2cb38292017-03-29 19:09:17 -0700751 * @param createIfMissing true if a next object should be created if not found
Saurav Das07c74602016-04-27 18:35:50 -0700752 * @return next objective ID or -1 if an error occurred during retrieval or creation
Saurav Das2d94d312015-11-24 23:21:05 -0800753 */
754 public int getPortNextObjectiveId(DeviceId deviceId, PortNumber portNum,
755 TrafficTreatment treatment,
Saurav Das2cb38292017-03-29 19:09:17 -0700756 TrafficSelector meta,
757 boolean createIfMissing) {
Saurav Das2d94d312015-11-24 23:21:05 -0800758 DefaultGroupHandler ghdlr = groupHandlerMap.get(deviceId);
759 if (ghdlr != null) {
Saurav Das2cb38292017-03-29 19:09:17 -0700760 return ghdlr.getPortNextObjectiveId(portNum, treatment, meta, createIfMissing);
Saurav Das2d94d312015-11-24 23:21:05 -0800761 } else {
Charles Chanb7f75ac2016-01-11 18:28:54 -0800762 log.warn("getPortNextObjectiveId query - groupHandler for device {}"
763 + " not found", deviceId);
764 return -1;
765 }
766 }
767
Saurav Das62ae6792017-05-15 15:34:25 -0700768 /**
769 * Returns the group handler object for the specified device id.
770 *
771 * @param devId the device identifier
772 * @return the groupHandler object for the device id, or null if not found
773 */
Charles Chan3ed34d82017-06-22 18:03:14 -0700774 DefaultGroupHandler getGroupHandler(DeviceId devId) {
Saurav Das62ae6792017-05-15 15:34:25 -0700775 return groupHandlerMap.get(devId);
776 }
777
778 /**
Saurav Dasfbe74572017-08-03 18:30:35 -0700779 * Returns the default routing handler object.
780 *
781 * @return the default routing handler object
782 */
783 public DefaultRoutingHandler getRoutingHandler() {
784 return defaultRoutingHandler;
785 }
786
787 /**
Saurav Das62ae6792017-05-15 15:34:25 -0700788 * Returns true if this controller instance has seen this link before. The
789 * link may not be currently up, but as long as the link had been seen before
790 * this method will return true. The one exception is when the link was
791 * indeed seen before, but this controller instance was forced to forget it
792 * by a call to purgeSeenLink method.
793 *
794 * @param link the infrastructure link being queried
795 * @return true if this controller instance has seen this link before
796 */
Charles Chan3ed34d82017-06-22 18:03:14 -0700797 boolean isSeenLink(Link link) {
Saurav Das62ae6792017-05-15 15:34:25 -0700798 return seenLinks.containsKey(link);
799 }
800
801 /**
802 * Updates the seen link store. Updates can be for links that are currently
803 * available or not.
804 *
805 * @param link the link to update in the seen-link local store
806 * @param up the status of the link, true if up, false if down
807 */
Charles Chan3ed34d82017-06-22 18:03:14 -0700808 void updateSeenLink(Link link, boolean up) {
Saurav Das62ae6792017-05-15 15:34:25 -0700809 seenLinks.put(link, up);
810 }
811
812 /**
813 * Returns the status of a seen-link (up or down). If the link has not
814 * been seen-before, a null object is returned.
815 *
816 * @param link the infrastructure link being queried
817 * @return null if the link was not seen-before;
818 * true if the seen-link is up;
819 * false if the seen-link is down
820 */
Charles Chan3ed34d82017-06-22 18:03:14 -0700821 Boolean isSeenLinkUp(Link link) {
Saurav Das62ae6792017-05-15 15:34:25 -0700822 return seenLinks.get(link);
823 }
824
825 /**
826 * Makes this controller instance forget a previously seen before link.
827 *
828 * @param link the infrastructure link to purge
829 */
Charles Chan3ed34d82017-06-22 18:03:14 -0700830 private void purgeSeenLink(Link link) {
Saurav Das62ae6792017-05-15 15:34:25 -0700831 seenLinks.remove(link);
832 }
833
834 /**
835 * Returns the status of a link as parallel link. A parallel link
836 * is defined as a link which has common src and dst switches as another
837 * seen-link that is currently enabled. It is not necessary for the link being
838 * queried to be a seen-link.
839 *
840 * @param link the infrastructure link being queried
841 * @return true if a seen-link exists that is up, and shares the
842 * same src and dst switches as the link being queried
843 */
Charles Chan3ed34d82017-06-22 18:03:14 -0700844 private boolean isParallelLink(Link link) {
Saurav Das62ae6792017-05-15 15:34:25 -0700845 for (Entry<Link, Boolean> seen : seenLinks.entrySet()) {
846 Link seenLink = seen.getKey();
847 if (seenLink.equals(link)) {
848 continue;
849 }
850 if (seenLink.src().deviceId().equals(link.src().deviceId()) &&
851 seenLink.dst().deviceId().equals(link.dst().deviceId()) &&
852 seen.getValue()) {
853 return true;
854 }
855 }
856 return false;
857 }
858
Saurav Das261c3002017-06-13 15:35:54 -0700859 /**
860 * Returns true if the link being queried is a bidirectional link. A bidi
861 * link is defined as a link, whose reverse link - ie. the link in the reverse
862 * direction - has been seen-before and is up. It is not necessary for the link
863 * being queried to be a seen-link.
864 *
865 * @param link the infrastructure link being queried
866 * @return true if another unidirectional link exists in the reverse direction,
867 * has been seen-before and is up
868 */
869 public boolean isBidirectional(Link link) {
870 Link reverseLink = linkService.getLink(link.dst(), link.src());
871 if (reverseLink == null) {
872 return false;
873 }
874 Boolean result = isSeenLinkUp(reverseLink);
875 if (result == null) {
876 return false;
877 }
878 return result.booleanValue();
879 }
880
881 /**
882 * Determines if the given link should be avoided in routing calculations
883 * by policy or design.
884 *
885 * @param link the infrastructure link being queried
886 * @return true if link should be avoided
887 */
888 public boolean avoidLink(Link link) {
889 // XXX currently only avoids all pair-links. In the future can be
890 // extended to avoid any generic link
891 DeviceId src = link.src().deviceId();
892 PortNumber srcPort = link.src().port();
893 if (deviceConfiguration == null || !deviceConfiguration.isConfigured(src)) {
894 log.warn("Device {} not configured..cannot avoid link {}", src, link);
895 return false;
896 }
897 DeviceId pairDev;
898 PortNumber pairLocalPort, pairRemotePort = null;
899 try {
900 pairDev = deviceConfiguration.getPairDeviceId(src);
901 pairLocalPort = deviceConfiguration.getPairLocalPort(src);
902 if (pairDev != null) {
903 pairRemotePort = deviceConfiguration.getPairLocalPort(pairDev);
904 }
905 } catch (DeviceConfigNotFoundException e) {
906 log.warn("Pair dev for dev {} not configured..cannot avoid link {}",
907 src, link);
908 return false;
909 }
910
911 if (srcPort.equals(pairLocalPort) &&
912 link.dst().deviceId().equals(pairDev) &&
913 link.dst().port().equals(pairRemotePort)) {
914 return true;
915 }
916 return false;
917 }
918
sangho80f11cb2015-04-01 13:05:26 -0700919 private class InternalPacketProcessor implements PacketProcessor {
sangho80f11cb2015-04-01 13:05:26 -0700920 @Override
921 public void process(PacketContext context) {
922
923 if (context.isHandled()) {
924 return;
925 }
926
927 InboundPacket pkt = context.inPacket();
928 Ethernet ethernet = pkt.parsed();
Pier Luigi37a35432017-02-01 13:50:04 -0800929
930 if (ethernet == null) {
931 return;
932 }
933
Saurav Das261c3002017-06-13 15:35:54 -0700934 log.trace("Rcvd pktin from {}: {}", context.inPacket().receivedFrom(),
935 ethernet);
Pier Ventreadb4ae62016-11-23 09:57:42 -0800936 if (ethernet.getEtherType() == TYPE_ARP) {
Saurav Das62ae6792017-05-15 15:34:25 -0700937 log.warn("Received unexpected ARP packet on {}",
938 context.inPacket().receivedFrom());
Saurav Das368cf212017-03-15 15:15:14 -0700939 log.trace("{}", ethernet);
Pier Ventre6b2c1b32016-12-09 17:26:04 -0800940 return;
sangho80f11cb2015-04-01 13:05:26 -0700941 } else if (ethernet.getEtherType() == Ethernet.TYPE_IPV4) {
Pier Ventreb6b81d52016-12-02 08:16:05 -0800942 IPv4 ipv4Packet = (IPv4) ethernet.getPayload();
943 //ipHandler.addToPacketBuffer(ipv4Packet);
944 if (ipv4Packet.getProtocol() == IPv4.PROTOCOL_ICMP) {
945 icmpHandler.processIcmp(ethernet, pkt.receivedFrom());
sangho80f11cb2015-04-01 13:05:26 -0700946 } else {
Charles Chand041ad82017-01-13 17:20:44 -0800947 // NOTE: We don't support IP learning at this moment so this
948 // is not necessary. Also it causes duplication of DHCP packets.
Pier Ventre6b2c1b32016-12-09 17:26:04 -0800949 // ipHandler.processPacketIn(ipv4Packet, pkt.receivedFrom());
sangho80f11cb2015-04-01 13:05:26 -0700950 }
Pier Ventreb6a7f342016-11-26 21:05:22 -0800951 } else if (ethernet.getEtherType() == Ethernet.TYPE_IPV6) {
952 IPv6 ipv6Packet = (IPv6) ethernet.getPayload();
Pier Ventreb6b81d52016-12-02 08:16:05 -0800953 //ipHandler.addToPacketBuffer(ipv6Packet);
Pier Luigi37a35432017-02-01 13:50:04 -0800954 // We deal with the packet only if the packet is a ICMP6 ECHO/REPLY
Pier Ventreb6b81d52016-12-02 08:16:05 -0800955 if (ipv6Packet.getNextHeader() == IPv6.PROTOCOL_ICMP6) {
956 ICMP6 icmp6Packet = (ICMP6) ipv6Packet.getPayload();
957 if (icmp6Packet.getIcmpType() == ICMP6.ECHO_REQUEST ||
958 icmp6Packet.getIcmpType() == ICMP6.ECHO_REPLY) {
959 icmpHandler.processIcmpv6(ethernet, pkt.receivedFrom());
960 } else {
Saurav Das62ae6792017-05-15 15:34:25 -0700961 log.trace("Received ICMPv6 0x{} - not handled",
Charles Chand3727b72017-03-13 13:10:30 -0700962 Integer.toHexString(icmp6Packet.getIcmpType() & 0xff));
Pier Ventreb6b81d52016-12-02 08:16:05 -0800963 }
964 } else {
965 // NOTE: We don't support IP learning at this moment so this
966 // is not necessary. Also it causes duplication of DHCPv6 packets.
967 // ipHandler.processPacketIn(ipv6Packet, pkt.receivedFrom());
968 }
sangho80f11cb2015-04-01 13:05:26 -0700969 }
970 }
971 }
972
973 private class InternalLinkListener implements LinkListener {
974 @Override
975 public void event(LinkEvent event) {
Charles Chan0cff8aa2017-03-29 16:39:05 -0700976 if (event.type() == LinkEvent.Type.LINK_ADDED ||
977 event.type() == LinkEvent.Type.LINK_UPDATED ||
978 event.type() == LinkEvent.Type.LINK_REMOVED) {
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700979 log.debug("Event {} received from Link Service", event.type());
sangho80f11cb2015-04-01 13:05:26 -0700980 scheduleEventHandlerIfNotScheduled(event);
981 }
982 }
983 }
984
985 private class InternalDeviceListener implements DeviceListener {
sangho80f11cb2015-04-01 13:05:26 -0700986 @Override
987 public void event(DeviceEvent event) {
sangho80f11cb2015-04-01 13:05:26 -0700988 switch (event.type()) {
989 case DEVICE_ADDED:
Saurav Dasf0f592d2016-11-18 15:21:57 -0800990 case PORT_UPDATED:
991 case PORT_ADDED:
sanghofb7c7292015-04-13 15:15:58 -0700992 case DEVICE_UPDATED:
993 case DEVICE_AVAILABILITY_CHANGED:
Saurav Das62ae6792017-05-15 15:34:25 -0700994 log.trace("Event {} received from Device Service", event.type());
sangho80f11cb2015-04-01 13:05:26 -0700995 scheduleEventHandlerIfNotScheduled(event);
996 break;
997 default:
998 }
999 }
1000 }
1001
Saurav Das2d94d312015-11-24 23:21:05 -08001002 @SuppressWarnings("rawtypes")
sangho80f11cb2015-04-01 13:05:26 -07001003 private void scheduleEventHandlerIfNotScheduled(Event event) {
Charles Chan3ed34d82017-06-22 18:03:14 -07001004 synchronized (THREAD_SCHED_LOCK) {
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -07001005 eventQueue.add(event);
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -07001006 numOfEventsQueued++;
1007
1008 if ((numOfHandlerScheduled - numOfHandlerExecution) == 0) {
1009 //No pending scheduled event handling threads. So start a new one.
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -07001010 eventHandlerFuture = executorService
1011 .schedule(eventHandler, 100, TimeUnit.MILLISECONDS);
1012 numOfHandlerScheduled++;
1013 }
Jonathan Hart54541d12016-04-12 15:39:44 -07001014 log.trace("numOfEventsQueued {}, numOfEventHandlerScheduled {}",
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -07001015 numOfEventsQueued,
1016 numOfHandlerScheduled);
sangho80f11cb2015-04-01 13:05:26 -07001017 }
sangho80f11cb2015-04-01 13:05:26 -07001018 }
1019
1020 private class InternalEventHandler implements Runnable {
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -07001021 @Override
sangho80f11cb2015-04-01 13:05:26 -07001022 public void run() {
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -07001023 try {
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -07001024 while (true) {
Saurav Das2d94d312015-11-24 23:21:05 -08001025 @SuppressWarnings("rawtypes")
Charles Chan3ed34d82017-06-22 18:03:14 -07001026 Event event;
1027 synchronized (THREAD_SCHED_LOCK) {
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -07001028 if (!eventQueue.isEmpty()) {
1029 event = eventQueue.poll();
1030 numOfEventsExecuted++;
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -07001031 } else {
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -07001032 numOfHandlerExecution++;
1033 log.debug("numOfHandlerExecution {} numOfEventsExecuted {}",
1034 numOfHandlerExecution, numOfEventsExecuted);
1035 break;
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -07001036 }
sanghofb7c7292015-04-13 15:15:58 -07001037 }
Charles Chan0cff8aa2017-03-29 16:39:05 -07001038 if (event.type() == LinkEvent.Type.LINK_ADDED ||
1039 event.type() == LinkEvent.Type.LINK_UPDATED) {
Saurav Das62ae6792017-05-15 15:34:25 -07001040 // Note: do not update seenLinks here, otherwise every
1041 // link, even one seen for the first time, will be appear
1042 // to be a previously seen link
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -07001043 processLinkAdded((Link) event.subject());
1044 } else if (event.type() == LinkEvent.Type.LINK_REMOVED) {
Pier Ventre6d593892016-09-13 21:33:40 -07001045 Link linkRemoved = (Link) event.subject();
Saurav Das62ae6792017-05-15 15:34:25 -07001046 if (linkRemoved.type() == Link.Type.DIRECT) {
1047 updateSeenLink(linkRemoved, false);
1048 }
1049 // device availability check helps to ensure that
1050 // multiple link-removed events are actually treated as a
1051 // single switch removed event. purgeSeenLink is necessary
1052 // so we do rerouting (instead of rehashing) when switch
1053 // comes back.
Pier Ventre6d593892016-09-13 21:33:40 -07001054 if (linkRemoved.src().elementId() instanceof DeviceId &&
1055 !deviceService.isAvailable(linkRemoved.src().deviceId())) {
Saurav Das62ae6792017-05-15 15:34:25 -07001056 purgeSeenLink(linkRemoved);
Pier Ventre6d593892016-09-13 21:33:40 -07001057 continue;
1058 }
1059 if (linkRemoved.dst().elementId() instanceof DeviceId &&
1060 !deviceService.isAvailable(linkRemoved.dst().deviceId())) {
Saurav Das62ae6792017-05-15 15:34:25 -07001061 purgeSeenLink(linkRemoved);
Pier Ventre6d593892016-09-13 21:33:40 -07001062 continue;
1063 }
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -07001064 processLinkRemoved((Link) event.subject());
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -07001065 } else if (event.type() == DeviceEvent.Type.DEVICE_ADDED ||
1066 event.type() == DeviceEvent.Type.DEVICE_AVAILABILITY_CHANGED ||
1067 event.type() == DeviceEvent.Type.DEVICE_UPDATED) {
Saurav Das62af8802015-12-04 10:52:59 -08001068 DeviceId deviceId = ((Device) event.subject()).id();
1069 if (deviceService.isAvailable(deviceId)) {
Saurav Dasc28b3432015-10-30 17:45:38 -07001070 log.info("Processing device event {} for available device {}",
1071 event.type(), ((Device) event.subject()).id());
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -07001072 processDeviceAdded((Device) event.subject());
Saurav Dasc3604f12016-03-23 11:22:49 -07001073 } else {
1074 log.info("Processing device event {} for unavailable device {}",
1075 event.type(), ((Device) event.subject()).id());
1076 processDeviceRemoved((Device) event.subject());
1077 }
Saurav Dasf0f592d2016-11-18 15:21:57 -08001078 } else if (event.type() == DeviceEvent.Type.PORT_ADDED) {
Saurav Dasd1872b02016-12-02 15:43:47 -08001079 // typically these calls come when device is added first time
1080 // so port filtering rules are handled at the device_added event.
1081 // port added calls represent all ports on the device,
1082 // enabled or not.
Saurav Das62ae6792017-05-15 15:34:25 -07001083 log.trace("** PORT ADDED {}/{} -> {}",
Saurav Dasd1872b02016-12-02 15:43:47 -08001084 ((DeviceEvent) event).subject().id(),
1085 ((DeviceEvent) event).port().number(),
1086 event.type());
Saurav Dasf0f592d2016-11-18 15:21:57 -08001087 } else if (event.type() == DeviceEvent.Type.PORT_UPDATED) {
Saurav Dasd1872b02016-12-02 15:43:47 -08001088 // these calls happen for every subsequent event
1089 // ports enabled, disabled, switch goes away, comes back
Saurav Dasf0f592d2016-11-18 15:21:57 -08001090 log.info("** PORT UPDATED {}/{} -> {}",
1091 event.subject(),
1092 ((DeviceEvent) event).port(),
1093 event.type());
1094 processPortUpdated(((Device) event.subject()),
1095 ((DeviceEvent) event).port());
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -07001096 } else {
1097 log.warn("Unhandled event type: {}", event.type());
1098 }
sangho80f11cb2015-04-01 13:05:26 -07001099 }
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -07001100 } catch (Exception e) {
1101 log.error("SegmentRouting event handler "
1102 + "thread thrown an exception: {}", e);
sangho80f11cb2015-04-01 13:05:26 -07001103 }
sangho80f11cb2015-04-01 13:05:26 -07001104 }
1105 }
1106
sangho80f11cb2015-04-01 13:05:26 -07001107 private void processLinkAdded(Link link) {
Saurav Dasb149be12016-06-07 10:08:06 -07001108 log.info("** LINK ADDED {}", link.toString());
Charles Chan319d1a22015-11-03 10:42:14 -08001109 if (!deviceConfiguration.isConfigured(link.src().deviceId())) {
Saurav Das261c3002017-06-13 15:35:54 -07001110 log.warn("Source device of this link is not configured..not processing");
Charles Chan319d1a22015-11-03 10:42:14 -08001111 return;
1112 }
Saurav Das62ae6792017-05-15 15:34:25 -07001113 if (link.type() != Link.Type.DIRECT) {
1114 // NOTE: A DIRECT link might be transiently marked as INDIRECT
1115 // if BDDP is received before LLDP. We can safely ignore that
1116 // until the LLDP is received and the link is marked as DIRECT.
1117 log.info("Ignore link {}->{}. Link type is {} instead of DIRECT.",
1118 link.src(), link.dst(), link.type());
1119 return;
1120 }
1121
1122 //Irrespective of whether the local is a MASTER or not for this device,
1123 //create group handler instance and push default TTP flow rules if needed,
1124 //as in a multi-instance setup, instances can initiate groups for any device.
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -07001125 DefaultGroupHandler groupHandler = groupHandlerMap.get(link.src()
1126 .deviceId());
1127 if (groupHandler != null) {
Saurav Das62ae6792017-05-15 15:34:25 -07001128 groupHandler.portUpForLink(link);
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -07001129 } else {
1130 Device device = deviceService.getDevice(link.src().deviceId());
1131 if (device != null) {
1132 log.warn("processLinkAdded: Link Added "
1133 + "Notification without Device Added "
1134 + "event, still handling it");
1135 processDeviceAdded(device);
1136 groupHandler = groupHandlerMap.get(link.src()
1137 .deviceId());
Saurav Das62ae6792017-05-15 15:34:25 -07001138 groupHandler.portUpForLink(link);
sangho80f11cb2015-04-01 13:05:26 -07001139 }
1140 }
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -07001141
Saurav Das261c3002017-06-13 15:35:54 -07001142 /*// process link only if it is bidirectional
1143 if (!isBidirectional(link)) {
1144 log.debug("Link not bidirectional.. waiting for other direction "
1145 + "src {} --> dst {} ", link.dst(), link.src());
1146 // note that if we are not processing for routing, it should at least
1147 // be considered a seen-link
1148 updateSeenLink(link, true);
1149 return;
1150 }
1151 TO DO this ensure that rehash is still done correctly even if link is
1152 not processed for rerouting - perhaps rehash in both directions when
1153 it ultimately becomes bidi?
1154 */
1155
1156 log.debug("Starting optimized route population process for link "
1157 + "{} --> {}", link.src(), link.dst());
Saurav Das62ae6792017-05-15 15:34:25 -07001158 boolean seenBefore = isSeenLink(link);
1159 defaultRoutingHandler.populateRoutingRulesForLinkStatusChange(null, link, null);
Saurav Das261c3002017-06-13 15:35:54 -07001160
1161 // It's possible that linkUp causes no route-path change as ECMP graph does
1162 // not change if the link is a parallel link (same src-dst as another link.
1163 // However we still need to update ECMP hash groups to include new buckets
1164 // for the link that has come up.
Saurav Das62ae6792017-05-15 15:34:25 -07001165 if (mastershipService.isLocalMaster(link.src().deviceId())) {
Saurav Das261c3002017-06-13 15:35:54 -07001166 if (!seenBefore && isParallelLink(link)) {
Saurav Das62ae6792017-05-15 15:34:25 -07001167 // if link seen first time, we need to ensure hash-groups have all ports
Saurav Das261c3002017-06-13 15:35:54 -07001168 log.debug("Attempting retryHash for paralled first-time link {}", link);
Saurav Das62ae6792017-05-15 15:34:25 -07001169 groupHandler.retryHash(link, false, true);
1170 } else {
1171 //seen before-link
1172 if (isParallelLink(link)) {
Saurav Das261c3002017-06-13 15:35:54 -07001173 log.debug("Attempting retryHash for paralled seen-before "
1174 + "link {}", link);
Saurav Das62ae6792017-05-15 15:34:25 -07001175 groupHandler.retryHash(link, false, false);
1176 }
1177 }
1178 }
Charles Chan72779502016-04-23 17:36:10 -07001179
1180 mcastHandler.init();
sangho80f11cb2015-04-01 13:05:26 -07001181 }
1182
1183 private void processLinkRemoved(Link link) {
Saurav Dasb149be12016-06-07 10:08:06 -07001184 log.info("** LINK REMOVED {}", link.toString());
Saurav Das62ae6792017-05-15 15:34:25 -07001185 defaultRoutingHandler.populateRoutingRulesForLinkStatusChange(link, null, null);
1186
1187 // update local groupHandler stores
sangho2165d222015-05-01 09:38:25 -07001188 DefaultGroupHandler groupHandler = groupHandlerMap.get(link.src().deviceId());
1189 if (groupHandler != null) {
Saurav Das62ae6792017-05-15 15:34:25 -07001190 if (mastershipService.isLocalMaster(link.src().deviceId()) &&
1191 isParallelLink(link)) {
1192 groupHandler.retryHash(link, true, false);
1193 }
1194 // ensure local stores are updated
1195 groupHandler.portDown(link.src().port());
1196 } else {
1197 log.warn("group handler not found for dev:{} when removing link: {}",
1198 link.src().deviceId(), link);
sangho2165d222015-05-01 09:38:25 -07001199 }
Charles Chan72779502016-04-23 17:36:10 -07001200
1201 mcastHandler.processLinkDown(link);
sangho80f11cb2015-04-01 13:05:26 -07001202 }
1203
1204 private void processDeviceAdded(Device device) {
Saurav Dasb149be12016-06-07 10:08:06 -07001205 log.info("** DEVICE ADDED with ID {}", device.id());
Charles Chan9bd6aea2017-06-27 18:48:32 -07001206
1207 // NOTE: Punt ARP/NDP even when the device is not configured.
1208 // Host learning without network config is required for CORD config generator.
1209 routingRulePopulator.populateIpPunts(device.id());
1210 routingRulePopulator.populateArpNdpPunts(device.id());
1211
Charles Chan319d1a22015-11-03 10:42:14 -08001212 if (deviceConfiguration == null || !deviceConfiguration.isConfigured(device.id())) {
Saurav Das261c3002017-06-13 15:35:54 -07001213 log.warn("Device configuration unavailable. Device {} will be "
1214 + "processed after configuration.", device.id());
Saurav Das8ec0ec42015-11-03 14:39:27 -08001215 return;
1216 }
Charles Chan72779502016-04-23 17:36:10 -07001217 processDeviceAddedInternal(device.id());
1218 }
1219
1220 private void processDeviceAddedInternal(DeviceId deviceId) {
Saurav Dasc28b3432015-10-30 17:45:38 -07001221 // Irrespective of whether the local is a MASTER or not for this device,
1222 // we need to create a SR-group-handler instance. This is because in a
1223 // multi-instance setup, any instance can initiate forwarding/next-objectives
1224 // for any switch (even if this instance is a SLAVE or not even connected
1225 // to the switch). To handle this, a default-group-handler instance is necessary
1226 // per switch.
Charles Chan72779502016-04-23 17:36:10 -07001227 log.debug("Current groupHandlerMap devs: {}", groupHandlerMap.keySet());
1228 if (groupHandlerMap.get(deviceId) == null) {
Charles Chan319d1a22015-11-03 10:42:14 -08001229 DefaultGroupHandler groupHandler;
1230 try {
1231 groupHandler = DefaultGroupHandler.
Charles Chan72779502016-04-23 17:36:10 -07001232 createGroupHandler(deviceId,
1233 appId,
1234 deviceConfiguration,
1235 linkService,
1236 flowObjectiveService,
1237 this);
Charles Chan319d1a22015-11-03 10:42:14 -08001238 } catch (DeviceConfigNotFoundException e) {
1239 log.warn(e.getMessage() + " Aborting processDeviceAdded.");
1240 return;
1241 }
Charles Chan72779502016-04-23 17:36:10 -07001242 log.debug("updating groupHandlerMap with new config for device: {}",
1243 deviceId);
1244 groupHandlerMap.put(deviceId, groupHandler);
Saurav Das8ec0ec42015-11-03 14:39:27 -08001245 }
Saurav Dasb149be12016-06-07 10:08:06 -07001246
Charles Chan72779502016-04-23 17:36:10 -07001247 if (mastershipService.isLocalMaster(deviceId)) {
Saurav Dasf9332192017-02-18 14:05:44 -08001248 defaultRoutingHandler.populatePortAddressingRules(deviceId);
Charles Chandebfea32016-10-24 14:52:01 -07001249 hostHandler.init(deviceId);
Charles Chan82f19972016-05-17 13:13:55 -07001250 xConnectHandler.init(deviceId);
Charles Chan72779502016-04-23 17:36:10 -07001251 DefaultGroupHandler groupHandler = groupHandlerMap.get(deviceId);
Charles Chan10b0fb72017-02-02 16:20:42 -08001252 groupHandler.createGroupsFromVlanConfig();
Charles Chan72779502016-04-23 17:36:10 -07001253 routingRulePopulator.populateSubnetBroadcastRule(deviceId);
Charles Chan77277672015-10-20 16:24:19 -07001254 }
Charles Chan82ab1932016-01-30 23:22:37 -08001255
Charles Chandebfea32016-10-24 14:52:01 -07001256 appCfgHandler.init(deviceId);
1257 routeHandler.init(deviceId);
sangho80f11cb2015-04-01 13:05:26 -07001258 }
1259
Saurav Dasc3604f12016-03-23 11:22:49 -07001260 private void processDeviceRemoved(Device device) {
Saurav Das261c3002017-06-13 15:35:54 -07001261 dsNextObjStore.entrySet().stream()
Saurav Dasc3604f12016-03-23 11:22:49 -07001262 .filter(entry -> entry.getKey().deviceId().equals(device.id()))
1263 .forEach(entry -> {
Saurav Das261c3002017-06-13 15:35:54 -07001264 dsNextObjStore.remove(entry.getKey());
Saurav Dasc3604f12016-03-23 11:22:49 -07001265 });
Charles Chan10b0fb72017-02-02 16:20:42 -08001266 vlanNextObjStore.entrySet().stream()
Saurav Dasc3604f12016-03-23 11:22:49 -07001267 .filter(entry -> entry.getKey().deviceId().equals(device.id()))
Charles Chan3ed34d82017-06-22 18:03:14 -07001268 .forEach(entry -> vlanNextObjStore.remove(entry.getKey()));
Saurav Dasc3604f12016-03-23 11:22:49 -07001269 portNextObjStore.entrySet().stream()
1270 .filter(entry -> entry.getKey().deviceId().equals(device.id()))
Charles Chan3ed34d82017-06-22 18:03:14 -07001271 .forEach(entry -> portNextObjStore.remove(entry.getKey()));
Charles Chan17d75d82017-06-15 00:44:51 -07001272
1273 seenLinks.keySet().removeIf(key -> key.src().deviceId().equals(device.id()) ||
1274 key.dst().deviceId().equals(device.id()));
1275
Saurav Dasfbe74572017-08-03 18:30:35 -07001276 DefaultGroupHandler gh = groupHandlerMap.remove(device.id());
1277 if (gh != null) {
1278 gh.shutdown();
1279 }
Saurav Dasc3604f12016-03-23 11:22:49 -07001280 defaultRoutingHandler.purgeEcmpGraph(device.id());
Saurav Das62ae6792017-05-15 15:34:25 -07001281 // Note that a switch going down is associated with all of its links
1282 // going down as well, but it is treated as a single switch down event
1283 // while the link-downs are ignored.
1284 defaultRoutingHandler
1285 .populateRoutingRulesForLinkStatusChange(null, null, device.id());
Charles Chan72779502016-04-23 17:36:10 -07001286 mcastHandler.removeDevice(device.id());
Charles Chan82f19972016-05-17 13:13:55 -07001287 xConnectHandler.removeDevice(device.id());
Saurav Dasc3604f12016-03-23 11:22:49 -07001288 }
1289
Saurav Dasf0f592d2016-11-18 15:21:57 -08001290 private void processPortUpdated(Device device, Port port) {
1291 if (deviceConfiguration == null || !deviceConfiguration.isConfigured(device.id())) {
1292 log.warn("Device configuration uploading. Not handling port event for"
1293 + "dev: {} port: {}", device.id(), port.number());
1294 return;
1295 }
Saurav Dasf9332192017-02-18 14:05:44 -08001296
1297 if (!mastershipService.isLocalMaster(device.id())) {
1298 log.debug("Not master for dev:{} .. not handling port updated event"
1299 + "for port {}", device.id(), port.number());
1300 return;
1301 }
1302
1303 // first we handle filtering rules associated with the port
1304 if (port.isEnabled()) {
1305 log.info("Switchport {}/{} enabled..programming filters",
1306 device.id(), port.number());
Charles Chan43be46b2017-02-26 22:59:35 -08001307 routingRulePopulator.processSinglePortFilters(device.id(), port.number(), true);
Saurav Dasf9332192017-02-18 14:05:44 -08001308 } else {
1309 log.info("Switchport {}/{} disabled..removing filters",
1310 device.id(), port.number());
Charles Chan43be46b2017-02-26 22:59:35 -08001311 routingRulePopulator.processSinglePortFilters(device.id(), port.number(), false);
Saurav Dasf9332192017-02-18 14:05:44 -08001312 }
Saurav Dasf0f592d2016-11-18 15:21:57 -08001313
1314 // portUpdated calls are for ports that have gone down or up. For switch
1315 // to switch ports, link-events should take care of any re-routing or
1316 // group editing necessary for port up/down. Here we only process edge ports
1317 // that are already configured.
Saurav Das3fb28272017-03-04 16:08:47 -08001318 ConnectPoint cp = new ConnectPoint(device.id(), port.number());
1319 VlanId untaggedVlan = getUntaggedVlanId(cp);
1320 VlanId nativeVlan = getNativeVlanId(cp);
1321 Set<VlanId> taggedVlans = getTaggedVlanId(cp);
Charles Chan10b0fb72017-02-02 16:20:42 -08001322
Saurav Das3fb28272017-03-04 16:08:47 -08001323 if (untaggedVlan == null && nativeVlan == null && taggedVlans.isEmpty()) {
Saurav Das62ae6792017-05-15 15:34:25 -07001324 log.debug("Not handling port updated event for non-edge port (unconfigured) "
Saurav Dasf0f592d2016-11-18 15:21:57 -08001325 + "dev/port: {}/{}", device.id(), port.number());
1326 return;
1327 }
Saurav Das3fb28272017-03-04 16:08:47 -08001328 if (untaggedVlan != null) {
1329 processEdgePort(device, port, untaggedVlan, true);
1330 }
1331 if (nativeVlan != null) {
1332 processEdgePort(device, port, nativeVlan, true);
1333 }
1334 if (!taggedVlans.isEmpty()) {
1335 taggedVlans.forEach(tag -> processEdgePort(device, port, tag, false));
1336 }
Saurav Dasf0f592d2016-11-18 15:21:57 -08001337 }
1338
Saurav Das3fb28272017-03-04 16:08:47 -08001339 private void processEdgePort(Device device, Port port, VlanId vlanId,
1340 boolean popVlan) {
Saurav Dasf0f592d2016-11-18 15:21:57 -08001341 boolean portUp = port.isEnabled();
1342 if (portUp) {
Saurav Das3fb28272017-03-04 16:08:47 -08001343 log.info("Device:EdgePort {}:{} is enabled in vlan: {}", device.id(),
Charles Chan10b0fb72017-02-02 16:20:42 -08001344 port.number(), vlanId);
Saurav Dasf0f592d2016-11-18 15:21:57 -08001345 } else {
Saurav Das3fb28272017-03-04 16:08:47 -08001346 log.info("Device:EdgePort {}:{} is disabled in vlan: {}", device.id(),
Charles Chan10b0fb72017-02-02 16:20:42 -08001347 port.number(), vlanId);
Saurav Dasf0f592d2016-11-18 15:21:57 -08001348 }
1349
Srikanth Vavilapalli64505482015-04-21 13:04:13 -07001350 DefaultGroupHandler groupHandler = groupHandlerMap.get(device.id());
sangho80f11cb2015-04-01 13:05:26 -07001351 if (groupHandler != null) {
Saurav Das3fb28272017-03-04 16:08:47 -08001352 groupHandler.processEdgePort(port.number(), vlanId, popVlan, portUp);
Saurav Dasf0f592d2016-11-18 15:21:57 -08001353 } else {
1354 log.warn("Group handler not found for dev:{}. Not handling edge port"
1355 + " {} event for port:{}", device.id(),
1356 (portUp) ? "UP" : "DOWN", port.number());
sangho80f11cb2015-04-01 13:05:26 -07001357 }
1358 }
sangho27462c62015-05-14 00:39:53 -07001359
Pier Ventreb6a7f342016-11-26 21:05:22 -08001360 /**
1361 * Registers the given connect point with the NRS, this is necessary
1362 * to receive the NDP and ARP packets from the NRS.
1363 *
1364 * @param portToRegister connect point to register
1365 */
1366 public void registerConnectPoint(ConnectPoint portToRegister) {
Charles Chan2e71ef32017-02-23 15:44:08 -08001367 neighbourResolutionService.registerNeighbourHandler(
Pier Ventreb6a7f342016-11-26 21:05:22 -08001368 portToRegister,
1369 neighbourHandler,
1370 appId
1371 );
1372 }
1373
Charles Chan72f556a2015-10-05 17:50:33 -07001374 private class InternalConfigListener implements NetworkConfigListener {
Saurav Das261c3002017-06-13 15:35:54 -07001375 private static final long PROGRAM_DELAY = 2;
Charles Chan46fdfaf2016-11-09 20:51:44 -08001376 SegmentRoutingManager srManager;
Charles Chane7c61022015-10-07 14:21:45 -07001377
Charles Chanb7f75ac2016-01-11 18:28:54 -08001378 /**
1379 * Constructs the internal network config listener.
1380 *
Charles Chan46fdfaf2016-11-09 20:51:44 -08001381 * @param srManager segment routing manager
Charles Chanb7f75ac2016-01-11 18:28:54 -08001382 */
Charles Chan3ed34d82017-06-22 18:03:14 -07001383 InternalConfigListener(SegmentRoutingManager srManager) {
Charles Chan46fdfaf2016-11-09 20:51:44 -08001384 this.srManager = srManager;
Charles Chane7c61022015-10-07 14:21:45 -07001385 }
1386
Charles Chanb7f75ac2016-01-11 18:28:54 -08001387 /**
1388 * Reads network config and initializes related data structure accordingly.
1389 */
Charles Chane7c61022015-10-07 14:21:45 -07001390 public void configureNetwork() {
Saurav Das261c3002017-06-13 15:35:54 -07001391 if (deviceConfiguration == null) {
1392 deviceConfiguration = new DeviceConfiguration(srManager);
1393 } else {
1394 deviceConfiguration.updateConfig();
1395 }
Charles Chane7c61022015-10-07 14:21:45 -07001396
Charles Chan46fdfaf2016-11-09 20:51:44 -08001397 arpHandler = new ArpHandler(srManager);
1398 icmpHandler = new IcmpHandler(srManager);
1399 ipHandler = new IpHandler(srManager);
1400 routingRulePopulator = new RoutingRulePopulator(srManager);
1401 defaultRoutingHandler = new DefaultRoutingHandler(srManager);
Charles Chane7c61022015-10-07 14:21:45 -07001402
1403 tunnelHandler = new TunnelHandler(linkService, deviceConfiguration,
1404 groupHandlerMap, tunnelStore);
1405 policyHandler = new PolicyHandler(appId, deviceConfiguration,
1406 flowObjectiveService,
1407 tunnelHandler, policyStore);
Saurav Das261c3002017-06-13 15:35:54 -07001408 // add a small delay to absorb multiple network config added notifications
1409 if (!programmingScheduled.get()) {
1410 programmingScheduled.set(true);
1411 executorService.schedule(new ConfigChange(), PROGRAM_DELAY,
1412 TimeUnit.SECONDS);
Charles Chane7c61022015-10-07 14:21:45 -07001413 }
Charles Chan72779502016-04-23 17:36:10 -07001414 mcastHandler.init();
Charles Chane7c61022015-10-07 14:21:45 -07001415 }
1416
Charles Chan72f556a2015-10-05 17:50:33 -07001417 @Override
1418 public void event(NetworkConfigEvent event) {
Charles Chan82ab1932016-01-30 23:22:37 -08001419 // TODO move this part to NetworkConfigEventHandler
1420 if (event.configClass().equals(SegmentRoutingDeviceConfig.class)) {
1421 switch (event.type()) {
1422 case CONFIG_ADDED:
Charles Chan68363b12017-06-26 15:25:09 -07001423 log.info("Segment Routing Device Config added for {}", event.subject());
Charles Chan82ab1932016-01-30 23:22:37 -08001424 configureNetwork();
1425 break;
1426 case CONFIG_UPDATED:
Charles Chan68363b12017-06-26 15:25:09 -07001427 log.info("Segment Routing Config updated for {}", event.subject());
1428 // TODO support dynamic configuration
1429 break;
1430 default:
1431 break;
1432 }
1433 } else if (event.configClass().equals(InterfaceConfig.class)) {
1434 switch (event.type()) {
1435 case CONFIG_ADDED:
1436 log.info("Interface Config added for {}", event.subject());
1437 configureNetwork();
1438 break;
1439 case CONFIG_UPDATED:
1440 log.info("Interface Config updated for {}", event.subject());
Charles Chan82ab1932016-01-30 23:22:37 -08001441 // TODO support dynamic configuration
1442 break;
1443 default:
1444 break;
Charles Chan2b078ae2015-10-14 11:24:40 -07001445 }
Charles Chan82ab1932016-01-30 23:22:37 -08001446 } else if (event.configClass().equals(SegmentRoutingAppConfig.class)) {
Charles Chan82f19972016-05-17 13:13:55 -07001447 checkState(appCfgHandler != null, "NetworkConfigEventHandler is not initialized");
Charles Chan82ab1932016-01-30 23:22:37 -08001448 switch (event.type()) {
1449 case CONFIG_ADDED:
Charles Chan82f19972016-05-17 13:13:55 -07001450 appCfgHandler.processAppConfigAdded(event);
Charles Chan82ab1932016-01-30 23:22:37 -08001451 break;
1452 case CONFIG_UPDATED:
Charles Chan82f19972016-05-17 13:13:55 -07001453 appCfgHandler.processAppConfigUpdated(event);
Charles Chan82ab1932016-01-30 23:22:37 -08001454 break;
1455 case CONFIG_REMOVED:
Charles Chan82f19972016-05-17 13:13:55 -07001456 appCfgHandler.processAppConfigRemoved(event);
1457 break;
1458 default:
1459 break;
1460 }
Charles Chandebfea32016-10-24 14:52:01 -07001461 configureNetwork();
Charles Chan82f19972016-05-17 13:13:55 -07001462 } else if (event.configClass().equals(XConnectConfig.class)) {
1463 checkState(xConnectHandler != null, "XConnectHandler is not initialized");
1464 switch (event.type()) {
1465 case CONFIG_ADDED:
1466 xConnectHandler.processXConnectConfigAdded(event);
1467 break;
1468 case CONFIG_UPDATED:
1469 xConnectHandler.processXConnectConfigUpdated(event);
1470 break;
1471 case CONFIG_REMOVED:
1472 xConnectHandler.processXConnectConfigRemoved(event);
Charles Chan82ab1932016-01-30 23:22:37 -08001473 break;
1474 default:
1475 break;
Charles Chan2b078ae2015-10-14 11:24:40 -07001476 }
Pier Ventre6b19e482016-11-07 16:21:04 -08001477 } else if (event.configClass().equals(PwaasConfig.class)) {
1478 checkState(l2TunnelHandler != null, "L2TunnelHandler is not initialized");
1479 switch (event.type()) {
1480 case CONFIG_ADDED:
1481 l2TunnelHandler.processPwaasConfigAdded(event);
1482 break;
1483 case CONFIG_UPDATED:
1484 l2TunnelHandler.processPwaasConfigUpdated(event);
1485 break;
1486 case CONFIG_REMOVED:
1487 l2TunnelHandler.processPwaasConfigRemoved(event);
1488 break;
1489 default:
1490 break;
1491 }
Charles Chan72f556a2015-10-05 17:50:33 -07001492 }
1493 }
Saurav Das261c3002017-06-13 15:35:54 -07001494
1495 private final class ConfigChange implements Runnable {
1496 @Override
1497 public void run() {
1498 programmingScheduled.set(false);
1499 for (Device device : deviceService.getDevices()) {
1500 processDeviceAdded(device);
1501 }
1502 defaultRoutingHandler.startPopulationProcess();
1503 }
1504 }
Charles Chan72f556a2015-10-05 17:50:33 -07001505 }
Charles Chanf4586112015-11-09 16:37:23 -08001506
1507 private class InternalHostListener implements HostListener {
Charles Chanf4586112015-11-09 16:37:23 -08001508 @Override
1509 public void event(HostEvent event) {
Charles Chanf4586112015-11-09 16:37:23 -08001510 switch (event.type()) {
1511 case HOST_ADDED:
Charles Chan1eaf4802016-04-18 13:44:03 -07001512 hostHandler.processHostAddedEvent(event);
Charles Chanf4586112015-11-09 16:37:23 -08001513 break;
1514 case HOST_MOVED:
Charles Chan1eaf4802016-04-18 13:44:03 -07001515 hostHandler.processHostMovedEvent(event);
Charles Chanf4586112015-11-09 16:37:23 -08001516 break;
1517 case HOST_REMOVED:
Charles Chand9265a32017-06-16 15:19:24 -07001518 hostHandler.processHostRemovedEvent(event);
Charles Chanf4586112015-11-09 16:37:23 -08001519 break;
1520 case HOST_UPDATED:
Charles Chan1eaf4802016-04-18 13:44:03 -07001521 hostHandler.processHostUpdatedEvent(event);
Charles Chanf4586112015-11-09 16:37:23 -08001522 break;
1523 default:
1524 log.warn("Unsupported host event type: {}", event.type());
1525 break;
1526 }
1527 }
1528 }
1529
Charles Chanc91c8782016-03-30 17:54:24 -07001530 private class InternalMcastListener implements McastListener {
1531 @Override
1532 public void event(McastEvent event) {
1533 switch (event.type()) {
1534 case SOURCE_ADDED:
Charles Chan1eaf4802016-04-18 13:44:03 -07001535 mcastHandler.processSourceAdded(event);
Charles Chanc91c8782016-03-30 17:54:24 -07001536 break;
1537 case SINK_ADDED:
Charles Chan1eaf4802016-04-18 13:44:03 -07001538 mcastHandler.processSinkAdded(event);
Charles Chanc91c8782016-03-30 17:54:24 -07001539 break;
1540 case SINK_REMOVED:
Charles Chan1eaf4802016-04-18 13:44:03 -07001541 mcastHandler.processSinkRemoved(event);
Charles Chanc91c8782016-03-30 17:54:24 -07001542 break;
1543 case ROUTE_ADDED:
1544 case ROUTE_REMOVED:
1545 default:
1546 break;
1547 }
1548 }
1549 }
Charles Chan41f5ec02016-06-13 18:54:31 -07001550
Charles Chandebfea32016-10-24 14:52:01 -07001551 private class InternalRouteEventListener implements RouteListener {
1552 @Override
1553 public void event(RouteEvent event) {
1554 switch (event.type()) {
1555 case ROUTE_ADDED:
1556 routeHandler.processRouteAdded(event);
1557 break;
1558 case ROUTE_UPDATED:
1559 routeHandler.processRouteUpdated(event);
1560 break;
1561 case ROUTE_REMOVED:
1562 routeHandler.processRouteRemoved(event);
1563 break;
1564 default:
1565 break;
1566 }
1567 }
1568 }
Saurav Das62ae6792017-05-15 15:34:25 -07001569
sangho80f11cb2015-04-01 13:05:26 -07001570}