blob: bdc8aa812bc129f5621da55b1aa0212d293ec2d4 [file] [log] [blame]
sanghob35a6192015-04-01 13:05:26 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2015-present Open Networking Foundation
sanghob35a6192015-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
Charles Chan7ffd81f2017-02-08 15:52:08 -080018import com.google.common.collect.HashMultimap;
Saurav Dasc88d4662017-05-15 15:34:25 -070019import com.google.common.collect.ImmutableMap;
Charles Chanc81c45b2016-10-20 17:02:44 -070020import com.google.common.collect.Maps;
Charles Chan7ffd81f2017-02-08 15:52:08 -080021import com.google.common.collect.Multimap;
sanghob35a6192015-04-01 13:05:26 -070022import org.apache.felix.scr.annotations.Activate;
23import org.apache.felix.scr.annotations.Component;
24import org.apache.felix.scr.annotations.Deactivate;
25import org.apache.felix.scr.annotations.Reference;
26import org.apache.felix.scr.annotations.ReferenceCardinality;
sangho1e575652015-05-14 00:39:53 -070027import org.apache.felix.scr.annotations.Service;
sanghob35a6192015-04-01 13:05:26 -070028import org.onlab.packet.Ethernet;
Pier Ventre735b8c82016-12-02 08:16:05 -080029import org.onlab.packet.ICMP6;
Charles Chanc42e84e2015-10-20 16:24:19 -070030import org.onlab.packet.IPv4;
Pier Ventre10bd8d12016-11-26 21:05:22 -080031import org.onlab.packet.IPv6;
Charles Chanc42e84e2015-10-20 16:24:19 -070032import org.onlab.packet.IpPrefix;
Jonathan Hartc19f7c12016-04-12 15:39:44 -070033import org.onlab.packet.VlanId;
Srikanth Vavilapalli23181912015-05-04 09:48:09 -070034import org.onlab.util.KryoNamespace;
Saurav Das80980c72016-03-23 11:22:49 -070035import org.onosproject.cfg.ComponentConfigService;
sanghob35a6192015-04-01 13:05:26 -070036import org.onosproject.core.ApplicationId;
37import org.onosproject.core.CoreService;
38import org.onosproject.event.Event;
Charles Chan278ce832017-06-26 15:25:09 -070039import org.onosproject.incubator.net.config.basics.InterfaceConfig;
Charles Chand55e84d2016-03-30 17:54:24 -070040import org.onosproject.incubator.net.config.basics.McastConfig;
Pier Luigi721b6622017-02-03 13:34:21 -080041import org.onosproject.incubator.net.intf.Interface;
Charles Chan2c15aca2016-11-09 20:51:44 -080042import org.onosproject.incubator.net.intf.InterfaceService;
Charles Chan03a73e02016-10-24 14:52:01 -070043import org.onosproject.incubator.net.routing.RouteEvent;
44import org.onosproject.incubator.net.routing.RouteListener;
45import org.onosproject.incubator.net.routing.RouteService;
Pier Ventre735b8c82016-12-02 08:16:05 -080046import org.onosproject.incubator.net.neighbour.NeighbourResolutionService;
Jonathan Hartc19f7c12016-04-12 15:39:44 -070047import org.onosproject.mastership.MastershipService;
Pier Ventre10bd8d12016-11-26 21:05:22 -080048import org.onosproject.net.ConnectPoint;
Jonathan Hartc19f7c12016-04-12 15:39:44 -070049import org.onosproject.net.Device;
50import org.onosproject.net.DeviceId;
51import org.onosproject.net.Link;
52import org.onosproject.net.Port;
Charles Chan68aa62d2015-11-09 16:37:23 -080053import org.onosproject.net.PortNumber;
Charles Chand6832882015-10-05 17:50:33 -070054import org.onosproject.net.config.ConfigFactory;
55import org.onosproject.net.config.NetworkConfigEvent;
Charles Chand6832882015-10-05 17:50:33 -070056import org.onosproject.net.config.NetworkConfigListener;
Jonathan Hartc19f7c12016-04-12 15:39:44 -070057import org.onosproject.net.config.NetworkConfigRegistry;
Charles Chand6832882015-10-05 17:50:33 -070058import org.onosproject.net.config.basics.SubjectFactories;
Jonathan Hartc19f7c12016-04-12 15:39:44 -070059import org.onosproject.net.device.DeviceEvent;
60import org.onosproject.net.device.DeviceListener;
61import org.onosproject.net.device.DeviceService;
Charles Chan68aa62d2015-11-09 16:37:23 -080062import org.onosproject.net.flow.TrafficSelector;
63import org.onosproject.net.flow.TrafficTreatment;
Jonathan Hartc19f7c12016-04-12 15:39:44 -070064import org.onosproject.net.flowobjective.FlowObjectiveService;
Charles Chan68aa62d2015-11-09 16:37:23 -080065import org.onosproject.net.host.HostEvent;
66import org.onosproject.net.host.HostListener;
Pier Ventre10bd8d12016-11-26 21:05:22 -080067import org.onosproject.net.host.HostService;
68import org.onosproject.net.link.LinkEvent;
69import org.onosproject.net.link.LinkListener;
70import org.onosproject.net.link.LinkService;
Charles Chand55e84d2016-03-30 17:54:24 -070071import org.onosproject.net.mcast.McastEvent;
72import org.onosproject.net.mcast.McastListener;
73import org.onosproject.net.mcast.MulticastRouteService;
Pier Ventre10bd8d12016-11-26 21:05:22 -080074import org.onosproject.net.packet.InboundPacket;
75import org.onosproject.net.packet.PacketContext;
76import org.onosproject.net.packet.PacketProcessor;
77import org.onosproject.net.packet.PacketService;
Pier Ventre42287df2016-11-09 14:17:26 -080078import org.onosproject.net.topology.PathService;
Charles Chand55e84d2016-03-30 17:54:24 -070079import org.onosproject.net.topology.TopologyService;
80import org.onosproject.segmentrouting.config.DeviceConfigNotFoundException;
81import org.onosproject.segmentrouting.config.DeviceConfiguration;
Pier Ventref34966c2016-11-07 16:21:04 -080082import org.onosproject.segmentrouting.config.PwaasConfig;
Pier Ventre10bd8d12016-11-26 21:05:22 -080083import org.onosproject.segmentrouting.config.SegmentRoutingDeviceConfig;
Pier Ventref34966c2016-11-07 16:21:04 -080084import org.onosproject.segmentrouting.config.SegmentRoutingAppConfig;
Charles Chanfc5c7802016-05-17 13:13:55 -070085import org.onosproject.segmentrouting.config.XConnectConfig;
Charles Chand55e84d2016-03-30 17:54:24 -070086import org.onosproject.segmentrouting.grouphandler.DefaultGroupHandler;
87import org.onosproject.segmentrouting.grouphandler.NeighborSet;
Charles Chand2990362016-04-18 13:44:03 -070088import org.onosproject.segmentrouting.storekey.NeighborSetNextObjectiveStoreKey;
89import org.onosproject.segmentrouting.storekey.PortNextObjectiveStoreKey;
Charles Chand2990362016-04-18 13:44:03 -070090import org.onosproject.segmentrouting.storekey.SubnetAssignedVidStoreKey;
Charles Chan59cc16d2017-02-02 16:20:42 -080091import org.onosproject.segmentrouting.storekey.VlanNextObjectiveStoreKey;
Charles Chanfc5c7802016-05-17 13:13:55 -070092import org.onosproject.segmentrouting.storekey.XConnectStoreKey;
Pier Ventref34966c2016-11-07 16:21:04 -080093import org.onosproject.segmentrouting.pwaas.L2TunnelHandler;
Jonathan Hartc19f7c12016-04-12 15:39:44 -070094import org.onosproject.store.serializers.KryoNamespaces;
Srikanth Vavilapalli23181912015-05-04 09:48:09 -070095import org.onosproject.store.service.EventuallyConsistentMap;
96import org.onosproject.store.service.EventuallyConsistentMapBuilder;
97import org.onosproject.store.service.StorageService;
98import org.onosproject.store.service.WallClockTimestamp;
sanghob35a6192015-04-01 13:05:26 -070099import org.slf4j.Logger;
100import org.slf4j.LoggerFactory;
101
sangho1e575652015-05-14 00:39:53 -0700102import java.util.List;
sanghob35a6192015-04-01 13:05:26 -0700103import java.util.Map;
Saurav Dasc88d4662017-05-15 15:34:25 -0700104import java.util.Map.Entry;
Saurav Das0e99e2b2015-10-28 12:39:42 -0700105import java.util.Set;
sanghob35a6192015-04-01 13:05:26 -0700106import java.util.concurrent.ConcurrentHashMap;
107import java.util.concurrent.ConcurrentLinkedQueue;
108import java.util.concurrent.Executors;
109import java.util.concurrent.ScheduledExecutorService;
110import java.util.concurrent.ScheduledFuture;
111import java.util.concurrent.TimeUnit;
Charles Chan7ffd81f2017-02-08 15:52:08 -0800112import java.util.stream.Collectors;
sanghob35a6192015-04-01 13:05:26 -0700113
Charles Chan3e783d02016-02-26 22:19:52 -0800114import static com.google.common.base.Preconditions.checkState;
Pier Ventree0ae7a32016-11-23 09:57:42 -0800115import static org.onlab.packet.Ethernet.TYPE_ARP;
Yuta HIGUCHI1624df12016-07-21 16:54:33 -0700116import static org.onlab.util.Tools.groupedThreads;
Charles Chan3e783d02016-02-26 22:19:52 -0800117
Charles Chane849c192016-01-11 18:28:54 -0800118/**
119 * Segment routing manager.
120 */
Jonathan Hartc19f7c12016-04-12 15:39:44 -0700121@Service
122@Component(immediate = true)
sangho1e575652015-05-14 00:39:53 -0700123public class SegmentRoutingManager implements SegmentRoutingService {
sanghob35a6192015-04-01 13:05:26 -0700124
Charles Chan2c15aca2016-11-09 20:51:44 -0800125 private static Logger log = LoggerFactory.getLogger(SegmentRoutingManager.class);
sanghob35a6192015-04-01 13:05:26 -0700126
127 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Charles Chan03a73e02016-10-24 14:52:01 -0700128 private ComponentConfigService compCfgService;
sanghob35a6192015-04-01 13:05:26 -0700129
130 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Pier Ventre10bd8d12016-11-26 21:05:22 -0800131 private NeighbourResolutionService neighbourResolutionService;
132
133 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Pier Ventre42287df2016-11-09 14:17:26 -0800134 public PathService pathService;
135
136 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Charles Chan03a73e02016-10-24 14:52:01 -0700137 CoreService coreService;
sanghob35a6192015-04-01 13:05:26 -0700138
139 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Charles Chan03a73e02016-10-24 14:52:01 -0700140 PacketService packetService;
sanghob35a6192015-04-01 13:05:26 -0700141
142 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Charles Chan03a73e02016-10-24 14:52:01 -0700143 HostService hostService;
sanghob35a6192015-04-01 13:05:26 -0700144
145 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Charles Chan03a73e02016-10-24 14:52:01 -0700146 DeviceService deviceService;
sanghob35a6192015-04-01 13:05:26 -0700147
148 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Pier Ventre42287df2016-11-09 14:17:26 -0800149 public FlowObjectiveService flowObjectiveService;
sanghob35a6192015-04-01 13:05:26 -0700150
151 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Charles Chan03a73e02016-10-24 14:52:01 -0700152 LinkService linkService;
sangho1e575652015-05-14 00:39:53 -0700153
Charles Chan5270ed02016-01-30 23:22:37 -0800154 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Pier Ventre42287df2016-11-09 14:17:26 -0800155 public MastershipService mastershipService;
Charles Chan03a73e02016-10-24 14:52:01 -0700156
157 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Pier Ventre42287df2016-11-09 14:17:26 -0800158 public StorageService storageService;
Charles Chan03a73e02016-10-24 14:52:01 -0700159
160 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
161 MulticastRouteService multicastRouteService;
162
163 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
164 TopologyService topologyService;
165
166 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Charles Chan03a73e02016-10-24 14:52:01 -0700167 RouteService routeService;
Charles Chan5270ed02016-01-30 23:22:37 -0800168
169 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Charles Chan2c15aca2016-11-09 20:51:44 -0800170 public NetworkConfigRegistry cfgService;
Charles Chan5270ed02016-01-30 23:22:37 -0800171
Saurav Das80980c72016-03-23 11:22:49 -0700172 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Charles Chan2c15aca2016-11-09 20:51:44 -0800173 public InterfaceService interfaceService;
174
Charles Chan03a73e02016-10-24 14:52:01 -0700175 ArpHandler arpHandler = null;
176 IcmpHandler icmpHandler = null;
177 IpHandler ipHandler = null;
178 RoutingRulePopulator routingRulePopulator = null;
Ray Milkeye4afdb52017-04-05 09:42:04 -0700179 ApplicationId appId;
180 DeviceConfiguration deviceConfiguration = null;
sanghob35a6192015-04-01 13:05:26 -0700181
Charles Chan03a73e02016-10-24 14:52:01 -0700182 DefaultRoutingHandler defaultRoutingHandler = null;
sangho1e575652015-05-14 00:39:53 -0700183 private TunnelHandler tunnelHandler = null;
184 private PolicyHandler policyHandler = null;
Charles Chanb8e10c82015-10-14 11:24:40 -0700185 private InternalPacketProcessor processor = null;
186 private InternalLinkListener linkListener = null;
187 private InternalDeviceListener deviceListener = null;
Charles Chanfc5c7802016-05-17 13:13:55 -0700188 private AppConfigHandler appCfgHandler = null;
Charles Chan03a73e02016-10-24 14:52:01 -0700189 XConnectHandler xConnectHandler = null;
Charles Chand2990362016-04-18 13:44:03 -0700190 private McastHandler mcastHandler = null;
Charles Chan03a73e02016-10-24 14:52:01 -0700191 HostHandler hostHandler = null;
Pier Ventre10bd8d12016-11-26 21:05:22 -0800192 private RouteHandler routeHandler = null;
Pier Ventre735b8c82016-12-02 08:16:05 -0800193 private SegmentRoutingNeighbourDispatcher neighbourHandler = null;
Pier Ventref34966c2016-11-07 16:21:04 -0800194 private L2TunnelHandler l2TunnelHandler = null;
sanghob35a6192015-04-01 13:05:26 -0700195 private InternalEventHandler eventHandler = new InternalEventHandler();
Charles Chan5270ed02016-01-30 23:22:37 -0800196 private final InternalHostListener hostListener = new InternalHostListener();
Charles Chand55e84d2016-03-30 17:54:24 -0700197 private final InternalConfigListener cfgListener = new InternalConfigListener(this);
198 private final InternalMcastListener mcastListener = new InternalMcastListener();
Charles Chan03a73e02016-10-24 14:52:01 -0700199 private final InternalRouteEventListener routeListener = new InternalRouteEventListener();
sanghob35a6192015-04-01 13:05:26 -0700200
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700201 private ScheduledExecutorService executorService = Executors
Yuta HIGUCHI1624df12016-07-21 16:54:33 -0700202 .newScheduledThreadPool(1, groupedThreads("SegmentRoutingManager", "event-%d", log));
sanghob35a6192015-04-01 13:05:26 -0700203
Saurav Das4ce45962015-11-24 23:21:05 -0800204 @SuppressWarnings("unused")
sanghob35a6192015-04-01 13:05:26 -0700205 private static ScheduledFuture<?> eventHandlerFuture = null;
Saurav Das4ce45962015-11-24 23:21:05 -0800206 @SuppressWarnings("rawtypes")
Yuta HIGUCHI1624df12016-07-21 16:54:33 -0700207 private ConcurrentLinkedQueue<Event> eventQueue = new ConcurrentLinkedQueue<>();
Charles Chan68aa62d2015-11-09 16:37:23 -0800208 private Map<DeviceId, DefaultGroupHandler> groupHandlerMap =
Charles Chane849c192016-01-11 18:28:54 -0800209 new ConcurrentHashMap<>();
210 /**
211 * Per device next objective ID store with (device id + neighbor set) as key.
212 */
Ray Milkeye4afdb52017-04-05 09:42:04 -0700213 EventuallyConsistentMap<NeighborSetNextObjectiveStoreKey, Integer>
Charles Chan68aa62d2015-11-09 16:37:23 -0800214 nsNextObjStore = null;
Charles Chane849c192016-01-11 18:28:54 -0800215 /**
216 * Per device next objective ID store with (device id + subnet) as key.
217 */
Ray Milkeye4afdb52017-04-05 09:42:04 -0700218 EventuallyConsistentMap<VlanNextObjectiveStoreKey, Integer>
Charles Chan59cc16d2017-02-02 16:20:42 -0800219 vlanNextObjStore = null;
Charles Chane849c192016-01-11 18:28:54 -0800220 /**
221 * Per device next objective ID store with (device id + port) as key.
222 */
Ray Milkeye4afdb52017-04-05 09:42:04 -0700223 EventuallyConsistentMap<PortNextObjectiveStoreKey, Integer>
Saurav Das4ce45962015-11-24 23:21:05 -0800224 portNextObjStore = null;
Charles Chan59cc16d2017-02-02 16:20:42 -0800225
Saurav Dasc88d4662017-05-15 15:34:25 -0700226 // Local store for all links seen and their present status, used for
227 // optimized routing. The existence of the link in the keys is enough to know
228 // if the link has been "seen-before" by this instance of the controller.
229 // The boolean value indicates if the link is currently up or not.
230 // XXX Currently the optimized routing logic depends on "forgetting" a link
231 // when a switch goes down, but "remembering" it when only the link goes down.
232 // Consider changing this logic so we can use the Link Service instead of
233 // a local cache.
234 private Map<Link, Boolean> seenLinks = new ConcurrentHashMap<>();
235
Saurav Das4ce45962015-11-24 23:21:05 -0800236 private EventuallyConsistentMap<String, Tunnel> tunnelStore = null;
237 private EventuallyConsistentMap<String, Policy> policyStore = null;
sangho0b2b6d12015-05-20 22:16:38 -0700238
Charles Chand55e84d2016-03-30 17:54:24 -0700239 private final ConfigFactory<DeviceId, SegmentRoutingDeviceConfig> deviceConfigFactory =
Charles Chanfc5c7802016-05-17 13:13:55 -0700240 new ConfigFactory<DeviceId, SegmentRoutingDeviceConfig>(
241 SubjectFactories.DEVICE_SUBJECT_FACTORY,
Charles Chand55e84d2016-03-30 17:54:24 -0700242 SegmentRoutingDeviceConfig.class, "segmentrouting") {
Charles Chand6832882015-10-05 17:50:33 -0700243 @Override
Charles Chan5270ed02016-01-30 23:22:37 -0800244 public SegmentRoutingDeviceConfig createConfig() {
245 return new SegmentRoutingDeviceConfig();
Charles Chand6832882015-10-05 17:50:33 -0700246 }
247 };
Pier Ventref34966c2016-11-07 16:21:04 -0800248
Charles Chand55e84d2016-03-30 17:54:24 -0700249 private final ConfigFactory<ApplicationId, SegmentRoutingAppConfig> appConfigFactory =
Charles Chanfc5c7802016-05-17 13:13:55 -0700250 new ConfigFactory<ApplicationId, SegmentRoutingAppConfig>(
251 SubjectFactories.APP_SUBJECT_FACTORY,
Charles Chand55e84d2016-03-30 17:54:24 -0700252 SegmentRoutingAppConfig.class, "segmentrouting") {
Charles Chan5270ed02016-01-30 23:22:37 -0800253 @Override
254 public SegmentRoutingAppConfig createConfig() {
255 return new SegmentRoutingAppConfig();
256 }
257 };
Pier Ventref34966c2016-11-07 16:21:04 -0800258
Charles Chanfc5c7802016-05-17 13:13:55 -0700259 private final ConfigFactory<ApplicationId, XConnectConfig> xConnectConfigFactory =
260 new ConfigFactory<ApplicationId, XConnectConfig>(
261 SubjectFactories.APP_SUBJECT_FACTORY,
262 XConnectConfig.class, "xconnect") {
263 @Override
264 public XConnectConfig createConfig() {
265 return new XConnectConfig();
266 }
267 };
Pier Ventref34966c2016-11-07 16:21:04 -0800268
Charles Chand55e84d2016-03-30 17:54:24 -0700269 private ConfigFactory<ApplicationId, McastConfig> mcastConfigFactory =
Charles Chanfc5c7802016-05-17 13:13:55 -0700270 new ConfigFactory<ApplicationId, McastConfig>(
271 SubjectFactories.APP_SUBJECT_FACTORY,
Charles Chand55e84d2016-03-30 17:54:24 -0700272 McastConfig.class, "multicast") {
273 @Override
274 public McastConfig createConfig() {
275 return new McastConfig();
276 }
277 };
278
Pier Ventref34966c2016-11-07 16:21:04 -0800279 private final ConfigFactory<ApplicationId, PwaasConfig> pwaasConfigFactory =
280 new ConfigFactory<ApplicationId, PwaasConfig>(
281 SubjectFactories.APP_SUBJECT_FACTORY,
282 PwaasConfig.class, "pwaas") {
283 @Override
284 public PwaasConfig createConfig() {
285 return new PwaasConfig();
286 }
287 };
288
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700289 private Object threadSchedulerLock = new Object();
290 private static int numOfEventsQueued = 0;
291 private static int numOfEventsExecuted = 0;
sanghob35a6192015-04-01 13:05:26 -0700292 private static int numOfHandlerExecution = 0;
293 private static int numOfHandlerScheduled = 0;
294
Charles Chan116188d2016-02-18 14:22:42 -0800295 /**
296 * Segment Routing App ID.
297 */
Charles Chan2c15aca2016-11-09 20:51:44 -0800298 public static final String APP_NAME = "org.onosproject.segmentrouting";
Charles Chan59cc16d2017-02-02 16:20:42 -0800299
Charles Chane849c192016-01-11 18:28:54 -0800300 /**
301 * The default VLAN ID assigned to the interfaces without subnet config.
302 */
Charles Chan59cc16d2017-02-02 16:20:42 -0800303 public static final VlanId INTERNAL_VLAN = VlanId.vlanId((short) 4094);
Saurav Das0e99e2b2015-10-28 12:39:42 -0700304
sanghob35a6192015-04-01 13:05:26 -0700305 @Activate
306 protected void activate() {
Charles Chan2c15aca2016-11-09 20:51:44 -0800307 appId = coreService.registerApplication(APP_NAME);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700308
309 log.debug("Creating EC map nsnextobjectivestore");
310 EventuallyConsistentMapBuilder<NeighborSetNextObjectiveStoreKey, Integer>
311 nsNextObjMapBuilder = storageService.eventuallyConsistentMapBuilder();
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700312 nsNextObjStore = nsNextObjMapBuilder
313 .withName("nsnextobjectivestore")
Jonathan Hartc19f7c12016-04-12 15:39:44 -0700314 .withSerializer(createSerializer())
Madan Jampanibcf1a482015-06-24 19:05:56 -0700315 .withTimestampProvider((k, v) -> new WallClockTimestamp())
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700316 .build();
317 log.trace("Current size {}", nsNextObjStore.size());
318
Charles Chan59cc16d2017-02-02 16:20:42 -0800319 log.debug("Creating EC map vlannextobjectivestore");
320 EventuallyConsistentMapBuilder<VlanNextObjectiveStoreKey, Integer>
321 vlanNextObjMapBuilder = storageService.eventuallyConsistentMapBuilder();
322 vlanNextObjStore = vlanNextObjMapBuilder
323 .withName("vlannextobjectivestore")
Jonathan Hartc19f7c12016-04-12 15:39:44 -0700324 .withSerializer(createSerializer())
Charles Chanc42e84e2015-10-20 16:24:19 -0700325 .withTimestampProvider((k, v) -> new WallClockTimestamp())
326 .build();
327
Saurav Das4ce45962015-11-24 23:21:05 -0800328 log.debug("Creating EC map subnetnextobjectivestore");
329 EventuallyConsistentMapBuilder<PortNextObjectiveStoreKey, Integer>
330 portNextObjMapBuilder = storageService.eventuallyConsistentMapBuilder();
331 portNextObjStore = portNextObjMapBuilder
332 .withName("portnextobjectivestore")
Jonathan Hartc19f7c12016-04-12 15:39:44 -0700333 .withSerializer(createSerializer())
Saurav Das4ce45962015-11-24 23:21:05 -0800334 .withTimestampProvider((k, v) -> new WallClockTimestamp())
335 .build();
336
sangho0b2b6d12015-05-20 22:16:38 -0700337 EventuallyConsistentMapBuilder<String, Tunnel> tunnelMapBuilder =
338 storageService.eventuallyConsistentMapBuilder();
sangho0b2b6d12015-05-20 22:16:38 -0700339 tunnelStore = tunnelMapBuilder
340 .withName("tunnelstore")
Jonathan Hartc19f7c12016-04-12 15:39:44 -0700341 .withSerializer(createSerializer())
Madan Jampanibcf1a482015-06-24 19:05:56 -0700342 .withTimestampProvider((k, v) -> new WallClockTimestamp())
sangho0b2b6d12015-05-20 22:16:38 -0700343 .build();
344
345 EventuallyConsistentMapBuilder<String, Policy> policyMapBuilder =
346 storageService.eventuallyConsistentMapBuilder();
sangho0b2b6d12015-05-20 22:16:38 -0700347 policyStore = policyMapBuilder
348 .withName("policystore")
Jonathan Hartc19f7c12016-04-12 15:39:44 -0700349 .withSerializer(createSerializer())
Madan Jampanibcf1a482015-06-24 19:05:56 -0700350 .withTimestampProvider((k, v) -> new WallClockTimestamp())
sangho0b2b6d12015-05-20 22:16:38 -0700351 .build();
352
Saurav Das80980c72016-03-23 11:22:49 -0700353 compCfgService.preSetProperty("org.onosproject.net.group.impl.GroupManager",
Pier Luigi9e5c5ca2017-01-12 18:14:58 -0800354 "purgeOnDisconnection", "true");
Saurav Das80980c72016-03-23 11:22:49 -0700355 compCfgService.preSetProperty("org.onosproject.net.flow.impl.FlowRuleManager",
Pier Luigi9e5c5ca2017-01-12 18:14:58 -0800356 "purgeOnDisconnection", "true");
Pier Luigi9e5c5ca2017-01-12 18:14:58 -0800357 compCfgService.preSetProperty("org.onosproject.provider.host.impl.HostLocationProvider",
358 "requestInterceptsEnabled", "false");
Pier Luigi7e415132017-01-12 22:46:39 -0800359 compCfgService.preSetProperty("org.onosproject.incubator.net.neighbour.impl.NeighbourResolutionManager",
360 "requestInterceptsEnabled", "false");
Charles Chanc760f382017-07-24 15:56:10 -0700361 compCfgService.preSetProperty("org.onosproject.dhcprelay.DhcpRelayManager",
Pier Luigi7e415132017-01-12 22:46:39 -0800362 "arpEnabled", "false");
Pier Luigi9b1d6262017-02-02 22:31:34 -0800363 compCfgService.preSetProperty("org.onosproject.net.host.impl.HostManager",
364 "greedyLearningIpv6", "true");
Charles Chanc6d227e2017-02-28 15:15:17 -0800365 compCfgService.preSetProperty("org.onosproject.routing.cpr.ControlPlaneRedirectManager",
366 "forceUnprovision", "true");
Charles Chan73316522017-07-20 16:16:25 -0700367 compCfgService.preSetProperty("org.onosproject.incubator.store.routing.impl.RouteStoreImpl",
368 "distributed", "true");
Saurav Das80980c72016-03-23 11:22:49 -0700369
Charles Chanb8e10c82015-10-14 11:24:40 -0700370 processor = new InternalPacketProcessor();
371 linkListener = new InternalLinkListener();
372 deviceListener = new InternalDeviceListener();
Charles Chanfc5c7802016-05-17 13:13:55 -0700373 appCfgHandler = new AppConfigHandler(this);
374 xConnectHandler = new XConnectHandler(this);
Charles Chand2990362016-04-18 13:44:03 -0700375 mcastHandler = new McastHandler(this);
376 hostHandler = new HostHandler(this);
Charles Chan03a73e02016-10-24 14:52:01 -0700377 routeHandler = new RouteHandler(this);
Pier Ventre735b8c82016-12-02 08:16:05 -0800378 neighbourHandler = new SegmentRoutingNeighbourDispatcher(this);
Pier Ventref34966c2016-11-07 16:21:04 -0800379 l2TunnelHandler = new L2TunnelHandler(this);
Charles Chanb8e10c82015-10-14 11:24:40 -0700380
Charles Chan3e783d02016-02-26 22:19:52 -0800381 cfgService.addListener(cfgListener);
Charles Chand55e84d2016-03-30 17:54:24 -0700382 cfgService.registerConfigFactory(deviceConfigFactory);
383 cfgService.registerConfigFactory(appConfigFactory);
Charles Chanfc5c7802016-05-17 13:13:55 -0700384 cfgService.registerConfigFactory(xConnectConfigFactory);
Charles Chand55e84d2016-03-30 17:54:24 -0700385 cfgService.registerConfigFactory(mcastConfigFactory);
Pier Ventref34966c2016-11-07 16:21:04 -0800386 cfgService.registerConfigFactory(pwaasConfigFactory);
Charles Chan5270ed02016-01-30 23:22:37 -0800387 hostService.addListener(hostListener);
Charles Chanb8e10c82015-10-14 11:24:40 -0700388 packetService.addProcessor(processor, PacketProcessor.director(2));
389 linkService.addListener(linkListener);
390 deviceService.addListener(deviceListener);
Charles Chand55e84d2016-03-30 17:54:24 -0700391 multicastRouteService.addListener(mcastListener);
Charles Chanc7a8a682017-06-19 00:43:31 -0700392 routeService.addListener(routeListener);
Charles Chanb8e10c82015-10-14 11:24:40 -0700393
394 cfgListener.configureNetwork();
395
sanghob35a6192015-04-01 13:05:26 -0700396 log.info("Started");
397 }
398
Jonathan Hartc19f7c12016-04-12 15:39:44 -0700399 private KryoNamespace.Builder createSerializer() {
400 return new KryoNamespace.Builder()
401 .register(KryoNamespaces.API)
402 .register(NeighborSetNextObjectiveStoreKey.class,
Charles Chan59cc16d2017-02-02 16:20:42 -0800403 VlanNextObjectiveStoreKey.class,
Jonathan Hartc19f7c12016-04-12 15:39:44 -0700404 SubnetAssignedVidStoreKey.class,
405 NeighborSet.class,
406 Tunnel.class,
407 DefaultTunnel.class,
408 Policy.class,
409 TunnelPolicy.class,
410 Policy.Type.class,
411 PortNextObjectiveStoreKey.class,
Charles Chanfc5c7802016-05-17 13:13:55 -0700412 XConnectStoreKey.class
Jonathan Hartc19f7c12016-04-12 15:39:44 -0700413 );
414 }
415
sanghob35a6192015-04-01 13:05:26 -0700416 @Deactivate
417 protected void deactivate() {
Charles Chand6832882015-10-05 17:50:33 -0700418 cfgService.removeListener(cfgListener);
Charles Chand55e84d2016-03-30 17:54:24 -0700419 cfgService.unregisterConfigFactory(deviceConfigFactory);
420 cfgService.unregisterConfigFactory(appConfigFactory);
Charles Chan03a73e02016-10-24 14:52:01 -0700421 cfgService.unregisterConfigFactory(xConnectConfigFactory);
Charles Chand55e84d2016-03-30 17:54:24 -0700422 cfgService.unregisterConfigFactory(mcastConfigFactory);
Pier Ventref34966c2016-11-07 16:21:04 -0800423 cfgService.unregisterConfigFactory(pwaasConfigFactory);
Charles Chand6832882015-10-05 17:50:33 -0700424
Charles Chanc7a8a682017-06-19 00:43:31 -0700425 hostService.removeListener(hostListener);
sanghob35a6192015-04-01 13:05:26 -0700426 packetService.removeProcessor(processor);
Charles Chanb8e10c82015-10-14 11:24:40 -0700427 linkService.removeListener(linkListener);
428 deviceService.removeListener(deviceListener);
Charles Chand55e84d2016-03-30 17:54:24 -0700429 multicastRouteService.removeListener(mcastListener);
Charles Chan03a73e02016-10-24 14:52:01 -0700430 routeService.removeListener(routeListener);
Charles Chand55e84d2016-03-30 17:54:24 -0700431
Charles Chan0aa674e2017-02-23 15:44:08 -0800432 neighbourResolutionService.unregisterNeighbourHandlers(appId);
433
sanghob35a6192015-04-01 13:05:26 -0700434 processor = null;
Charles Chanb8e10c82015-10-14 11:24:40 -0700435 linkListener = null;
Charles Chand55e84d2016-03-30 17:54:24 -0700436 deviceListener = null;
Charles Chanb8e10c82015-10-14 11:24:40 -0700437 groupHandlerMap.clear();
438
Charles Chand55e84d2016-03-30 17:54:24 -0700439 nsNextObjStore.destroy();
Charles Chan59cc16d2017-02-02 16:20:42 -0800440 vlanNextObjStore.destroy();
Charles Chand55e84d2016-03-30 17:54:24 -0700441 portNextObjStore.destroy();
Charles Chand55e84d2016-03-30 17:54:24 -0700442 tunnelStore.destroy();
443 policyStore.destroy();
sanghob35a6192015-04-01 13:05:26 -0700444 log.info("Stopped");
445 }
446
sangho1e575652015-05-14 00:39:53 -0700447 @Override
448 public List<Tunnel> getTunnels() {
449 return tunnelHandler.getTunnels();
450 }
451
452 @Override
sangho71abe1b2015-06-29 14:58:47 -0700453 public TunnelHandler.Result createTunnel(Tunnel tunnel) {
454 return tunnelHandler.createTunnel(tunnel);
sangho1e575652015-05-14 00:39:53 -0700455 }
456
457 @Override
sangho71abe1b2015-06-29 14:58:47 -0700458 public TunnelHandler.Result removeTunnel(Tunnel tunnel) {
sangho1e575652015-05-14 00:39:53 -0700459 for (Policy policy: policyHandler.getPolicies()) {
460 if (policy.type() == Policy.Type.TUNNEL_FLOW) {
461 TunnelPolicy tunnelPolicy = (TunnelPolicy) policy;
462 if (tunnelPolicy.tunnelId().equals(tunnel.id())) {
463 log.warn("Cannot remove the tunnel used by a policy");
sangho71abe1b2015-06-29 14:58:47 -0700464 return TunnelHandler.Result.TUNNEL_IN_USE;
sangho1e575652015-05-14 00:39:53 -0700465 }
466 }
467 }
sangho71abe1b2015-06-29 14:58:47 -0700468 return tunnelHandler.removeTunnel(tunnel);
sangho1e575652015-05-14 00:39:53 -0700469 }
470
471 @Override
sangho71abe1b2015-06-29 14:58:47 -0700472 public PolicyHandler.Result removePolicy(Policy policy) {
473 return policyHandler.removePolicy(policy);
sangho1e575652015-05-14 00:39:53 -0700474 }
475
476 @Override
sangho71abe1b2015-06-29 14:58:47 -0700477 public PolicyHandler.Result createPolicy(Policy policy) {
478 return policyHandler.createPolicy(policy);
sangho1e575652015-05-14 00:39:53 -0700479 }
480
481 @Override
482 public List<Policy> getPolicies() {
483 return policyHandler.getPolicies();
484 }
485
Saurav Das59232cf2016-04-27 18:35:50 -0700486 @Override
487 public void rerouteNetwork() {
488 cfgListener.configureNetwork();
489 for (Device device : deviceService.getDevices()) {
Saurav Das018605f2017-02-18 14:05:44 -0800490 if (mastershipService.isLocalMaster(device.id())) {
491 defaultRoutingHandler.populatePortAddressingRules(device.id());
492 }
Saurav Das59232cf2016-04-27 18:35:50 -0700493 }
494 defaultRoutingHandler.startPopulationProcess();
495 }
496
Charles Chanc81c45b2016-10-20 17:02:44 -0700497 @Override
Pier Ventre10bd8d12016-11-26 21:05:22 -0800498 public Map<DeviceId, Set<IpPrefix>> getDeviceSubnetMap() {
499 Map<DeviceId, Set<IpPrefix>> deviceSubnetMap = Maps.newHashMap();
Charles Chanc81c45b2016-10-20 17:02:44 -0700500 deviceService.getAvailableDevices().forEach(device -> {
501 deviceSubnetMap.put(device.id(), deviceConfiguration.getSubnets(device.id()));
502 });
503 return deviceSubnetMap;
504 }
505
Saurav Dasc88d4662017-05-15 15:34:25 -0700506
507 @Override
508 public ImmutableMap<DeviceId, EcmpShortestPathGraph> getCurrentEcmpSpg() {
509 if (defaultRoutingHandler != null) {
510 return defaultRoutingHandler.getCurrentEmcpSpgMap();
511 } else {
512 return null;
513 }
514 }
515
516 @Override
517 public ImmutableMap<NeighborSetNextObjectiveStoreKey, Integer> getNeighborSet() {
518 if (nsNextObjStore != null) {
519 return ImmutableMap.copyOf(nsNextObjStore.entrySet());
520 } else {
521 return ImmutableMap.of();
522 }
523 }
524
sanghof9d0bf12015-05-19 11:57:42 -0700525 /**
Ray Milkeye4afdb52017-04-05 09:42:04 -0700526 * Extracts the application ID from the manager.
527 *
528 * @return application ID
529 */
530 public ApplicationId appId() {
531 return appId;
532 }
533
534 /**
535 * Returns the device configuration.
536 *
537 * @return device configuration
538 */
539 public DeviceConfiguration deviceConfiguration() {
540 return deviceConfiguration;
541 }
542
543 /**
544 * Per device next objective ID store with (device id + neighbor set) as key.
545 *
546 * @return next objective ID store
547 */
548 public EventuallyConsistentMap<NeighborSetNextObjectiveStoreKey, Integer> nsNextObjStore() {
549 return nsNextObjStore;
550 }
551
552 /**
553 * Per device next objective ID store with (device id + subnet) as key.
554 *
555 * @return vlan next object store
556 */
557 public EventuallyConsistentMap<VlanNextObjectiveStoreKey, Integer> vlanNextObjStore() {
558 return vlanNextObjStore;
559 }
560
561 /**
562 * Per device next objective ID store with (device id + port) as key.
563 *
564 * @return port next object store.
565 */
566 public EventuallyConsistentMap<PortNextObjectiveStoreKey, Integer> portNextObjStore() {
567 return portNextObjStore;
568 }
569
570 /**
Pier Ventre98161782016-10-31 15:00:01 -0700571 * Returns the MPLS-ECMP configuration.
572 *
573 * @return MPLS-ECMP value
574 */
575 public boolean getMplsEcmp() {
576 SegmentRoutingAppConfig segmentRoutingAppConfig = cfgService
577 .getConfig(this.appId, SegmentRoutingAppConfig.class);
578 return segmentRoutingAppConfig != null && segmentRoutingAppConfig.mplsEcmp();
579 }
580
581 /**
sanghof9d0bf12015-05-19 11:57:42 -0700582 * Returns the tunnel object with the tunnel ID.
583 *
584 * @param tunnelId Tunnel ID
585 * @return Tunnel reference
586 */
sangho1e575652015-05-14 00:39:53 -0700587 public Tunnel getTunnel(String tunnelId) {
588 return tunnelHandler.getTunnel(tunnelId);
589 }
590
Charles Chan7ffd81f2017-02-08 15:52:08 -0800591 // TODO Consider moving these to InterfaceService
sanghob35a6192015-04-01 13:05:26 -0700592 /**
Charles Chan59cc16d2017-02-02 16:20:42 -0800593 * Returns untagged VLAN configured on given connect point.
Charles Chan7ffd81f2017-02-08 15:52:08 -0800594 * <p>
595 * Only returns the first match if there are multiple untagged VLAN configured
596 * on the connect point.
sanghob35a6192015-04-01 13:05:26 -0700597 *
Charles Chan59cc16d2017-02-02 16:20:42 -0800598 * @param connectPoint connect point
599 * @return untagged VLAN or null if not configured
sanghob35a6192015-04-01 13:05:26 -0700600 */
Charles Chan59cc16d2017-02-02 16:20:42 -0800601 public VlanId getUntaggedVlanId(ConnectPoint connectPoint) {
602 return interfaceService.getInterfacesByPort(connectPoint).stream()
603 .filter(intf -> !intf.vlanUntagged().equals(VlanId.NONE))
604 .map(Interface::vlanUntagged)
605 .findFirst().orElse(null);
sanghob35a6192015-04-01 13:05:26 -0700606 }
607
sangho1e575652015-05-14 00:39:53 -0700608 /**
Charles Chan7ffd81f2017-02-08 15:52:08 -0800609 * Returns tagged VLAN configured on given connect point.
610 * <p>
611 * Returns all matches if there are multiple tagged VLAN configured
612 * on the connect point.
613 *
614 * @param connectPoint connect point
615 * @return tagged VLAN or empty set if not configured
616 */
617 public Set<VlanId> getTaggedVlanId(ConnectPoint connectPoint) {
618 Set<Interface> interfaces = interfaceService.getInterfacesByPort(connectPoint);
619 return interfaces.stream()
620 .map(Interface::vlanTagged)
621 .flatMap(vlanIds -> vlanIds.stream())
622 .collect(Collectors.toSet());
623 }
624
625 /**
626 * Returns native VLAN configured on given connect point.
627 * <p>
628 * Only returns the first match if there are multiple native VLAN configured
629 * on the connect point.
630 *
631 * @param connectPoint connect point
632 * @return native VLAN or null if not configured
633 */
634 public VlanId getNativeVlanId(ConnectPoint connectPoint) {
635 Set<Interface> interfaces = interfaceService.getInterfacesByPort(connectPoint);
636 return interfaces.stream()
637 .filter(intf -> !intf.vlanNative().equals(VlanId.NONE))
638 .map(Interface::vlanNative)
639 .findFirst()
640 .orElse(null);
641 }
642
643 /**
644 * Returns vlan port map of given device.
645 *
646 * @param deviceId device id
647 * @return vlan-port multimap
648 */
649 public Multimap<VlanId, PortNumber> getVlanPortMap(DeviceId deviceId) {
650 HashMultimap<VlanId, PortNumber> vlanPortMap = HashMultimap.create();
651
652 interfaceService.getInterfaces().stream()
653 .filter(intf -> intf.connectPoint().deviceId().equals(deviceId))
654 .forEach(intf -> {
655 vlanPortMap.put(intf.vlanUntagged(), intf.connectPoint().port());
656 intf.vlanTagged().forEach(vlanTagged -> {
657 vlanPortMap.put(vlanTagged, intf.connectPoint().port());
658 });
659 vlanPortMap.put(intf.vlanNative(), intf.connectPoint().port());
660 });
661 vlanPortMap.removeAll(VlanId.NONE);
662
663 return vlanPortMap;
664 }
665
666 /**
Saurav Das4ce45962015-11-24 23:21:05 -0800667 * Returns the next objective ID for the given subnet prefix. It is expected
Charles Chan59cc16d2017-02-02 16:20:42 -0800668 * Returns the next objective ID for the given vlan id. It is expected
Saurav Das4ce45962015-11-24 23:21:05 -0800669 * that the next-objective has been pre-created from configuration.
Charles Chanc42e84e2015-10-20 16:24:19 -0700670 *
671 * @param deviceId Device ID
Charles Chan59cc16d2017-02-02 16:20:42 -0800672 * @param vlanId VLAN ID
Saurav Das4ce45962015-11-24 23:21:05 -0800673 * @return next objective ID or -1 if it was not found
Charles Chanc42e84e2015-10-20 16:24:19 -0700674 */
Charles Chan59cc16d2017-02-02 16:20:42 -0800675 public int getVlanNextObjectiveId(DeviceId deviceId, VlanId vlanId) {
Charles Chanc42e84e2015-10-20 16:24:19 -0700676 if (groupHandlerMap.get(deviceId) != null) {
Charles Chan59cc16d2017-02-02 16:20:42 -0800677 log.trace("getVlanNextObjectiveId query in device {}", deviceId);
678 return groupHandlerMap.get(deviceId).getVlanNextObjectiveId(vlanId);
Charles Chanc42e84e2015-10-20 16:24:19 -0700679 } else {
Charles Chan59cc16d2017-02-02 16:20:42 -0800680 log.warn("getVlanNextObjectiveId query - groupHandler for "
Saurav Das4ce45962015-11-24 23:21:05 -0800681 + "device {} not found", deviceId);
682 return -1;
683 }
684 }
685
686 /**
687 * Returns the next objective ID for the given portNumber, given the treatment.
688 * There could be multiple different treatments to the same outport, which
Saurav Das961beb22017-03-29 19:09:17 -0700689 * would result in different objectives. If the next object does not exist,
690 * and should be created, a new one is created and its id is returned.
Saurav Das4ce45962015-11-24 23:21:05 -0800691 *
692 * @param deviceId Device ID
693 * @param portNum port number on device for which NextObjective is queried
694 * @param treatment the actions to apply on the packets (should include outport)
695 * @param meta metadata passed into the creation of a Next Objective if necessary
Saurav Das961beb22017-03-29 19:09:17 -0700696 * @param createIfMissing true if a next object should be created if not found
Saurav Das59232cf2016-04-27 18:35:50 -0700697 * @return next objective ID or -1 if an error occurred during retrieval or creation
Saurav Das4ce45962015-11-24 23:21:05 -0800698 */
699 public int getPortNextObjectiveId(DeviceId deviceId, PortNumber portNum,
700 TrafficTreatment treatment,
Saurav Das961beb22017-03-29 19:09:17 -0700701 TrafficSelector meta,
702 boolean createIfMissing) {
Saurav Das4ce45962015-11-24 23:21:05 -0800703 DefaultGroupHandler ghdlr = groupHandlerMap.get(deviceId);
704 if (ghdlr != null) {
Saurav Das961beb22017-03-29 19:09:17 -0700705 return ghdlr.getPortNextObjectiveId(portNum, treatment, meta, createIfMissing);
Saurav Das4ce45962015-11-24 23:21:05 -0800706 } else {
Charles Chane849c192016-01-11 18:28:54 -0800707 log.warn("getPortNextObjectiveId query - groupHandler for device {}"
708 + " not found", deviceId);
709 return -1;
710 }
711 }
712
Saurav Dasc88d4662017-05-15 15:34:25 -0700713 /**
714 * Returns the group handler object for the specified device id.
715 *
716 * @param devId the device identifier
717 * @return the groupHandler object for the device id, or null if not found
718 */
719 public DefaultGroupHandler getGroupHandler(DeviceId devId) {
720 return groupHandlerMap.get(devId);
721 }
722
723 /**
724 * Returns true if this controller instance has seen this link before. The
725 * link may not be currently up, but as long as the link had been seen before
726 * this method will return true. The one exception is when the link was
727 * indeed seen before, but this controller instance was forced to forget it
728 * by a call to purgeSeenLink method.
729 *
730 * @param link the infrastructure link being queried
731 * @return true if this controller instance has seen this link before
732 */
733 public boolean isSeenLink(Link link) {
734 return seenLinks.containsKey(link);
735 }
736
737 /**
738 * Updates the seen link store. Updates can be for links that are currently
739 * available or not.
740 *
741 * @param link the link to update in the seen-link local store
742 * @param up the status of the link, true if up, false if down
743 */
744 public void updateSeenLink(Link link, boolean up) {
745 seenLinks.put(link, up);
746 }
747
748 /**
749 * Returns the status of a seen-link (up or down). If the link has not
750 * been seen-before, a null object is returned.
751 *
752 * @param link the infrastructure link being queried
753 * @return null if the link was not seen-before;
754 * true if the seen-link is up;
755 * false if the seen-link is down
756 */
757 public Boolean isSeenLinkUp(Link link) {
758 return seenLinks.get(link);
759 }
760
761 /**
762 * Makes this controller instance forget a previously seen before link.
763 *
764 * @param link the infrastructure link to purge
765 */
766 public void purgeSeenLink(Link link) {
767 seenLinks.remove(link);
768 }
769
770 /**
771 * Returns the status of a link as parallel link. A parallel link
772 * is defined as a link which has common src and dst switches as another
773 * seen-link that is currently enabled. It is not necessary for the link being
774 * queried to be a seen-link.
775 *
776 * @param link the infrastructure link being queried
777 * @return true if a seen-link exists that is up, and shares the
778 * same src and dst switches as the link being queried
779 */
780 public boolean isParallelLink(Link link) {
781 for (Entry<Link, Boolean> seen : seenLinks.entrySet()) {
782 Link seenLink = seen.getKey();
783 if (seenLink.equals(link)) {
784 continue;
785 }
786 if (seenLink.src().deviceId().equals(link.src().deviceId()) &&
787 seenLink.dst().deviceId().equals(link.dst().deviceId()) &&
788 seen.getValue()) {
789 return true;
790 }
791 }
792 return false;
793 }
794
sanghob35a6192015-04-01 13:05:26 -0700795 private class InternalPacketProcessor implements PacketProcessor {
sanghob35a6192015-04-01 13:05:26 -0700796 @Override
797 public void process(PacketContext context) {
798
799 if (context.isHandled()) {
800 return;
801 }
802
803 InboundPacket pkt = context.inPacket();
804 Ethernet ethernet = pkt.parsed();
Pier Luigi7dad71c2017-02-01 13:50:04 -0800805
806 if (ethernet == null) {
807 return;
808 }
809
Saurav Das4ce45962015-11-24 23:21:05 -0800810 log.trace("Rcvd pktin: {}", ethernet);
Pier Ventree0ae7a32016-11-23 09:57:42 -0800811 if (ethernet.getEtherType() == TYPE_ARP) {
Saurav Dasc88d4662017-05-15 15:34:25 -0700812 log.warn("Received unexpected ARP packet on {}",
813 context.inPacket().receivedFrom());
Saurav Das76ae6812017-03-15 15:15:14 -0700814 log.trace("{}", ethernet);
Pier Ventre968da122016-12-09 17:26:04 -0800815 return;
sanghob35a6192015-04-01 13:05:26 -0700816 } else if (ethernet.getEtherType() == Ethernet.TYPE_IPV4) {
Pier Ventre735b8c82016-12-02 08:16:05 -0800817 IPv4 ipv4Packet = (IPv4) ethernet.getPayload();
818 //ipHandler.addToPacketBuffer(ipv4Packet);
819 if (ipv4Packet.getProtocol() == IPv4.PROTOCOL_ICMP) {
820 icmpHandler.processIcmp(ethernet, pkt.receivedFrom());
sanghob35a6192015-04-01 13:05:26 -0700821 } else {
Charles Chan50035632017-01-13 17:20:44 -0800822 // NOTE: We don't support IP learning at this moment so this
823 // is not necessary. Also it causes duplication of DHCP packets.
Pier Ventre968da122016-12-09 17:26:04 -0800824 // ipHandler.processPacketIn(ipv4Packet, pkt.receivedFrom());
sanghob35a6192015-04-01 13:05:26 -0700825 }
Pier Ventre10bd8d12016-11-26 21:05:22 -0800826 } else if (ethernet.getEtherType() == Ethernet.TYPE_IPV6) {
827 IPv6 ipv6Packet = (IPv6) ethernet.getPayload();
Pier Ventre735b8c82016-12-02 08:16:05 -0800828 //ipHandler.addToPacketBuffer(ipv6Packet);
Pier Luigi7dad71c2017-02-01 13:50:04 -0800829 // We deal with the packet only if the packet is a ICMP6 ECHO/REPLY
Pier Ventre735b8c82016-12-02 08:16:05 -0800830 if (ipv6Packet.getNextHeader() == IPv6.PROTOCOL_ICMP6) {
831 ICMP6 icmp6Packet = (ICMP6) ipv6Packet.getPayload();
832 if (icmp6Packet.getIcmpType() == ICMP6.ECHO_REQUEST ||
833 icmp6Packet.getIcmpType() == ICMP6.ECHO_REPLY) {
834 icmpHandler.processIcmpv6(ethernet, pkt.receivedFrom());
835 } else {
Saurav Dasc88d4662017-05-15 15:34:25 -0700836 log.trace("Received ICMPv6 0x{} - not handled",
Charles Chan0ed44fb2017-03-13 13:10:30 -0700837 Integer.toHexString(icmp6Packet.getIcmpType() & 0xff));
Pier Ventre735b8c82016-12-02 08:16:05 -0800838 }
839 } else {
840 // NOTE: We don't support IP learning at this moment so this
841 // is not necessary. Also it causes duplication of DHCPv6 packets.
842 // ipHandler.processPacketIn(ipv6Packet, pkt.receivedFrom());
843 }
sanghob35a6192015-04-01 13:05:26 -0700844 }
845 }
846 }
847
848 private class InternalLinkListener implements LinkListener {
849 @Override
850 public void event(LinkEvent event) {
Charles Chanb1f8c762017-03-29 16:39:05 -0700851 if (event.type() == LinkEvent.Type.LINK_ADDED ||
852 event.type() == LinkEvent.Type.LINK_UPDATED ||
853 event.type() == LinkEvent.Type.LINK_REMOVED) {
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700854 log.debug("Event {} received from Link Service", event.type());
sanghob35a6192015-04-01 13:05:26 -0700855 scheduleEventHandlerIfNotScheduled(event);
856 }
857 }
858 }
859
860 private class InternalDeviceListener implements DeviceListener {
sanghob35a6192015-04-01 13:05:26 -0700861 @Override
862 public void event(DeviceEvent event) {
sanghob35a6192015-04-01 13:05:26 -0700863 switch (event.type()) {
864 case DEVICE_ADDED:
Saurav Das1a129a02016-11-18 15:21:57 -0800865 case PORT_UPDATED:
866 case PORT_ADDED:
sangho20eff1d2015-04-13 15:15:58 -0700867 case DEVICE_UPDATED:
868 case DEVICE_AVAILABILITY_CHANGED:
Saurav Dasc88d4662017-05-15 15:34:25 -0700869 log.trace("Event {} received from Device Service", event.type());
sanghob35a6192015-04-01 13:05:26 -0700870 scheduleEventHandlerIfNotScheduled(event);
871 break;
872 default:
873 }
874 }
875 }
876
Saurav Das4ce45962015-11-24 23:21:05 -0800877 @SuppressWarnings("rawtypes")
sanghob35a6192015-04-01 13:05:26 -0700878 private void scheduleEventHandlerIfNotScheduled(Event event) {
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700879 synchronized (threadSchedulerLock) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700880 eventQueue.add(event);
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700881 numOfEventsQueued++;
882
883 if ((numOfHandlerScheduled - numOfHandlerExecution) == 0) {
884 //No pending scheduled event handling threads. So start a new one.
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700885 eventHandlerFuture = executorService
886 .schedule(eventHandler, 100, TimeUnit.MILLISECONDS);
887 numOfHandlerScheduled++;
888 }
Jonathan Hartc19f7c12016-04-12 15:39:44 -0700889 log.trace("numOfEventsQueued {}, numOfEventHandlerScheduled {}",
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700890 numOfEventsQueued,
891 numOfHandlerScheduled);
sanghob35a6192015-04-01 13:05:26 -0700892 }
sanghob35a6192015-04-01 13:05:26 -0700893 }
894
895 private class InternalEventHandler implements Runnable {
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700896 @Override
sanghob35a6192015-04-01 13:05:26 -0700897 public void run() {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700898 try {
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700899 while (true) {
Saurav Das4ce45962015-11-24 23:21:05 -0800900 @SuppressWarnings("rawtypes")
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700901 Event event = null;
902 synchronized (threadSchedulerLock) {
903 if (!eventQueue.isEmpty()) {
904 event = eventQueue.poll();
905 numOfEventsExecuted++;
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700906 } else {
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700907 numOfHandlerExecution++;
908 log.debug("numOfHandlerExecution {} numOfEventsExecuted {}",
909 numOfHandlerExecution, numOfEventsExecuted);
910 break;
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700911 }
sangho20eff1d2015-04-13 15:15:58 -0700912 }
Charles Chanb1f8c762017-03-29 16:39:05 -0700913 if (event.type() == LinkEvent.Type.LINK_ADDED ||
914 event.type() == LinkEvent.Type.LINK_UPDATED) {
Saurav Dasc88d4662017-05-15 15:34:25 -0700915 // Note: do not update seenLinks here, otherwise every
916 // link, even one seen for the first time, will be appear
917 // to be a previously seen link
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700918 processLinkAdded((Link) event.subject());
919 } else if (event.type() == LinkEvent.Type.LINK_REMOVED) {
Pier Ventre2c515312016-09-13 21:33:40 -0700920 Link linkRemoved = (Link) event.subject();
Saurav Dasc88d4662017-05-15 15:34:25 -0700921 if (linkRemoved.type() == Link.Type.DIRECT) {
922 updateSeenLink(linkRemoved, false);
923 }
924 // device availability check helps to ensure that
925 // multiple link-removed events are actually treated as a
926 // single switch removed event. purgeSeenLink is necessary
927 // so we do rerouting (instead of rehashing) when switch
928 // comes back.
Pier Ventre2c515312016-09-13 21:33:40 -0700929 if (linkRemoved.src().elementId() instanceof DeviceId &&
930 !deviceService.isAvailable(linkRemoved.src().deviceId())) {
Saurav Dasc88d4662017-05-15 15:34:25 -0700931 purgeSeenLink(linkRemoved);
Pier Ventre2c515312016-09-13 21:33:40 -0700932 continue;
933 }
934 if (linkRemoved.dst().elementId() instanceof DeviceId &&
935 !deviceService.isAvailable(linkRemoved.dst().deviceId())) {
Saurav Dasc88d4662017-05-15 15:34:25 -0700936 purgeSeenLink(linkRemoved);
Pier Ventre2c515312016-09-13 21:33:40 -0700937 continue;
938 }
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700939 processLinkRemoved((Link) event.subject());
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700940 } else if (event.type() == DeviceEvent.Type.DEVICE_ADDED ||
941 event.type() == DeviceEvent.Type.DEVICE_AVAILABILITY_CHANGED ||
942 event.type() == DeviceEvent.Type.DEVICE_UPDATED) {
Saurav Das423fe2b2015-12-04 10:52:59 -0800943 DeviceId deviceId = ((Device) event.subject()).id();
944 if (deviceService.isAvailable(deviceId)) {
Saurav Das837e0bb2015-10-30 17:45:38 -0700945 log.info("Processing device event {} for available device {}",
946 event.type(), ((Device) event.subject()).id());
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700947 processDeviceAdded((Device) event.subject());
Saurav Das80980c72016-03-23 11:22:49 -0700948 } else {
949 log.info("Processing device event {} for unavailable device {}",
950 event.type(), ((Device) event.subject()).id());
951 processDeviceRemoved((Device) event.subject());
952 }
Saurav Das1a129a02016-11-18 15:21:57 -0800953 } else if (event.type() == DeviceEvent.Type.PORT_ADDED) {
Saurav Dasd2fded02016-12-02 15:43:47 -0800954 // typically these calls come when device is added first time
955 // so port filtering rules are handled at the device_added event.
956 // port added calls represent all ports on the device,
957 // enabled or not.
Saurav Dasc88d4662017-05-15 15:34:25 -0700958 log.trace("** PORT ADDED {}/{} -> {}",
Saurav Dasd2fded02016-12-02 15:43:47 -0800959 ((DeviceEvent) event).subject().id(),
960 ((DeviceEvent) event).port().number(),
961 event.type());
Saurav Das1a129a02016-11-18 15:21:57 -0800962 } else if (event.type() == DeviceEvent.Type.PORT_UPDATED) {
Saurav Dasd2fded02016-12-02 15:43:47 -0800963 // these calls happen for every subsequent event
964 // ports enabled, disabled, switch goes away, comes back
Saurav Das1a129a02016-11-18 15:21:57 -0800965 log.info("** PORT UPDATED {}/{} -> {}",
966 event.subject(),
967 ((DeviceEvent) event).port(),
968 event.type());
969 processPortUpdated(((Device) event.subject()),
970 ((DeviceEvent) event).port());
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700971 } else {
972 log.warn("Unhandled event type: {}", event.type());
973 }
sanghob35a6192015-04-01 13:05:26 -0700974 }
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700975 } catch (Exception e) {
976 log.error("SegmentRouting event handler "
977 + "thread thrown an exception: {}", e);
sanghob35a6192015-04-01 13:05:26 -0700978 }
sanghob35a6192015-04-01 13:05:26 -0700979 }
980 }
981
sanghob35a6192015-04-01 13:05:26 -0700982 private void processLinkAdded(Link link) {
Saurav Dasb5c236e2016-06-07 10:08:06 -0700983 log.info("** LINK ADDED {}", link.toString());
Charles Chan0b4e6182015-11-03 10:42:14 -0800984 if (!deviceConfiguration.isConfigured(link.src().deviceId())) {
985 log.warn("Source device of this link is not configured.");
986 return;
987 }
Saurav Dasc88d4662017-05-15 15:34:25 -0700988 if (link.type() != Link.Type.DIRECT) {
989 // NOTE: A DIRECT link might be transiently marked as INDIRECT
990 // if BDDP is received before LLDP. We can safely ignore that
991 // until the LLDP is received and the link is marked as DIRECT.
992 log.info("Ignore link {}->{}. Link type is {} instead of DIRECT.",
993 link.src(), link.dst(), link.type());
994 return;
995 }
996
997 //Irrespective of whether the local is a MASTER or not for this device,
998 //create group handler instance and push default TTP flow rules if needed,
999 //as in a multi-instance setup, instances can initiate groups for any device.
Srikanth Vavilapalli23181912015-05-04 09:48:09 -07001000 DefaultGroupHandler groupHandler = groupHandlerMap.get(link.src()
1001 .deviceId());
1002 if (groupHandler != null) {
Saurav Dasc88d4662017-05-15 15:34:25 -07001003 groupHandler.portUpForLink(link);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -07001004 } else {
1005 Device device = deviceService.getDevice(link.src().deviceId());
1006 if (device != null) {
1007 log.warn("processLinkAdded: Link Added "
1008 + "Notification without Device Added "
1009 + "event, still handling it");
1010 processDeviceAdded(device);
1011 groupHandler = groupHandlerMap.get(link.src()
1012 .deviceId());
Saurav Dasc88d4662017-05-15 15:34:25 -07001013 groupHandler.portUpForLink(link);
sanghob35a6192015-04-01 13:05:26 -07001014 }
1015 }
Srikanth Vavilapalli23181912015-05-04 09:48:09 -07001016
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -07001017 log.trace("Starting optimized route population process");
Saurav Dasc88d4662017-05-15 15:34:25 -07001018 boolean seenBefore = isSeenLink(link);
1019 defaultRoutingHandler.populateRoutingRulesForLinkStatusChange(null, link, null);
1020 if (mastershipService.isLocalMaster(link.src().deviceId())) {
1021 if (!seenBefore) {
1022 // if link seen first time, we need to ensure hash-groups have all ports
1023 groupHandler.retryHash(link, false, true);
1024 } else {
1025 //seen before-link
1026 if (isParallelLink(link)) {
1027 groupHandler.retryHash(link, false, false);
1028 }
1029 }
1030 }
Charles Chan2199c302016-04-23 17:36:10 -07001031
1032 mcastHandler.init();
sanghob35a6192015-04-01 13:05:26 -07001033 }
1034
1035 private void processLinkRemoved(Link link) {
Saurav Dasb5c236e2016-06-07 10:08:06 -07001036 log.info("** LINK REMOVED {}", link.toString());
Saurav Dasc88d4662017-05-15 15:34:25 -07001037 defaultRoutingHandler.populateRoutingRulesForLinkStatusChange(link, null, null);
1038
1039 // update local groupHandler stores
sangho834e4b02015-05-01 09:38:25 -07001040 DefaultGroupHandler groupHandler = groupHandlerMap.get(link.src().deviceId());
1041 if (groupHandler != null) {
Saurav Dasc88d4662017-05-15 15:34:25 -07001042 if (mastershipService.isLocalMaster(link.src().deviceId()) &&
1043 isParallelLink(link)) {
1044 groupHandler.retryHash(link, true, false);
1045 }
1046 // ensure local stores are updated
1047 groupHandler.portDown(link.src().port());
1048 } else {
1049 log.warn("group handler not found for dev:{} when removing link: {}",
1050 link.src().deviceId(), link);
sangho834e4b02015-05-01 09:38:25 -07001051 }
Charles Chan2199c302016-04-23 17:36:10 -07001052
1053 mcastHandler.processLinkDown(link);
sanghob35a6192015-04-01 13:05:26 -07001054 }
1055
1056 private void processDeviceAdded(Device device) {
Saurav Dasb5c236e2016-06-07 10:08:06 -07001057 log.info("** DEVICE ADDED with ID {}", device.id());
Charles Chan91ccbf72017-06-27 18:48:32 -07001058
1059 // NOTE: Punt ARP/NDP even when the device is not configured.
1060 // Host learning without network config is required for CORD config generator.
1061 routingRulePopulator.populateIpPunts(device.id());
1062 routingRulePopulator.populateArpNdpPunts(device.id());
1063
Charles Chan0b4e6182015-11-03 10:42:14 -08001064 if (deviceConfiguration == null || !deviceConfiguration.isConfigured(device.id())) {
Saurav Das2857f382015-11-03 14:39:27 -08001065 log.warn("Device configuration uploading. Device {} will be "
1066 + "processed after config completes.", device.id());
1067 return;
1068 }
Charles Chan2199c302016-04-23 17:36:10 -07001069 processDeviceAddedInternal(device.id());
1070 }
1071
1072 private void processDeviceAddedInternal(DeviceId deviceId) {
Saurav Das837e0bb2015-10-30 17:45:38 -07001073 // Irrespective of whether the local is a MASTER or not for this device,
1074 // we need to create a SR-group-handler instance. This is because in a
1075 // multi-instance setup, any instance can initiate forwarding/next-objectives
1076 // for any switch (even if this instance is a SLAVE or not even connected
1077 // to the switch). To handle this, a default-group-handler instance is necessary
1078 // per switch.
Charles Chan2199c302016-04-23 17:36:10 -07001079 log.debug("Current groupHandlerMap devs: {}", groupHandlerMap.keySet());
1080 if (groupHandlerMap.get(deviceId) == null) {
Charles Chan0b4e6182015-11-03 10:42:14 -08001081 DefaultGroupHandler groupHandler;
1082 try {
1083 groupHandler = DefaultGroupHandler.
Charles Chan2199c302016-04-23 17:36:10 -07001084 createGroupHandler(deviceId,
1085 appId,
1086 deviceConfiguration,
1087 linkService,
1088 flowObjectiveService,
1089 this);
Charles Chan0b4e6182015-11-03 10:42:14 -08001090 } catch (DeviceConfigNotFoundException e) {
1091 log.warn(e.getMessage() + " Aborting processDeviceAdded.");
1092 return;
1093 }
Charles Chan2199c302016-04-23 17:36:10 -07001094 log.debug("updating groupHandlerMap with new config for device: {}",
1095 deviceId);
1096 groupHandlerMap.put(deviceId, groupHandler);
Saurav Das2857f382015-11-03 14:39:27 -08001097 }
Saurav Dasb5c236e2016-06-07 10:08:06 -07001098
Charles Chan2199c302016-04-23 17:36:10 -07001099 if (mastershipService.isLocalMaster(deviceId)) {
Saurav Das018605f2017-02-18 14:05:44 -08001100 defaultRoutingHandler.populatePortAddressingRules(deviceId);
Charles Chan03a73e02016-10-24 14:52:01 -07001101 hostHandler.init(deviceId);
Charles Chanfc5c7802016-05-17 13:13:55 -07001102 xConnectHandler.init(deviceId);
Charles Chan2199c302016-04-23 17:36:10 -07001103 DefaultGroupHandler groupHandler = groupHandlerMap.get(deviceId);
Charles Chan59cc16d2017-02-02 16:20:42 -08001104 groupHandler.createGroupsFromVlanConfig();
Charles Chan2199c302016-04-23 17:36:10 -07001105 routingRulePopulator.populateSubnetBroadcastRule(deviceId);
Charles Chanc42e84e2015-10-20 16:24:19 -07001106 }
Charles Chan5270ed02016-01-30 23:22:37 -08001107
Charles Chan03a73e02016-10-24 14:52:01 -07001108 appCfgHandler.init(deviceId);
1109 routeHandler.init(deviceId);
sanghob35a6192015-04-01 13:05:26 -07001110 }
1111
Saurav Das80980c72016-03-23 11:22:49 -07001112 private void processDeviceRemoved(Device device) {
1113 nsNextObjStore.entrySet().stream()
1114 .filter(entry -> entry.getKey().deviceId().equals(device.id()))
1115 .forEach(entry -> {
1116 nsNextObjStore.remove(entry.getKey());
1117 });
Charles Chan59cc16d2017-02-02 16:20:42 -08001118 vlanNextObjStore.entrySet().stream()
Saurav Das80980c72016-03-23 11:22:49 -07001119 .filter(entry -> entry.getKey().deviceId().equals(device.id()))
1120 .forEach(entry -> {
Charles Chan59cc16d2017-02-02 16:20:42 -08001121 vlanNextObjStore.remove(entry.getKey());
Saurav Das80980c72016-03-23 11:22:49 -07001122 });
Saurav Das80980c72016-03-23 11:22:49 -07001123 portNextObjStore.entrySet().stream()
1124 .filter(entry -> entry.getKey().deviceId().equals(device.id()))
1125 .forEach(entry -> {
1126 portNextObjStore.remove(entry.getKey());
1127 });
Charles Chaned3742352017-06-15 00:44:51 -07001128
1129 seenLinks.keySet().removeIf(key -> key.src().deviceId().equals(device.id()) ||
1130 key.dst().deviceId().equals(device.id()));
1131
Saurav Das80980c72016-03-23 11:22:49 -07001132 groupHandlerMap.remove(device.id());
Saurav Das80980c72016-03-23 11:22:49 -07001133 defaultRoutingHandler.purgeEcmpGraph(device.id());
Saurav Dasc88d4662017-05-15 15:34:25 -07001134 // Note that a switch going down is associated with all of its links
1135 // going down as well, but it is treated as a single switch down event
1136 // while the link-downs are ignored.
1137 defaultRoutingHandler
1138 .populateRoutingRulesForLinkStatusChange(null, null, device.id());
Charles Chan2199c302016-04-23 17:36:10 -07001139 mcastHandler.removeDevice(device.id());
Charles Chanfc5c7802016-05-17 13:13:55 -07001140 xConnectHandler.removeDevice(device.id());
Saurav Das80980c72016-03-23 11:22:49 -07001141 }
1142
Saurav Das1a129a02016-11-18 15:21:57 -08001143 private void processPortUpdated(Device device, Port port) {
1144 if (deviceConfiguration == null || !deviceConfiguration.isConfigured(device.id())) {
1145 log.warn("Device configuration uploading. Not handling port event for"
1146 + "dev: {} port: {}", device.id(), port.number());
1147 return;
1148 }
Saurav Das018605f2017-02-18 14:05:44 -08001149
1150 if (!mastershipService.isLocalMaster(device.id())) {
1151 log.debug("Not master for dev:{} .. not handling port updated event"
1152 + "for port {}", device.id(), port.number());
1153 return;
1154 }
1155
1156 // first we handle filtering rules associated with the port
1157 if (port.isEnabled()) {
1158 log.info("Switchport {}/{} enabled..programming filters",
1159 device.id(), port.number());
Charles Chan7e4f8192017-02-26 22:59:35 -08001160 routingRulePopulator.processSinglePortFilters(device.id(), port.number(), true);
Saurav Das018605f2017-02-18 14:05:44 -08001161 } else {
1162 log.info("Switchport {}/{} disabled..removing filters",
1163 device.id(), port.number());
Charles Chan7e4f8192017-02-26 22:59:35 -08001164 routingRulePopulator.processSinglePortFilters(device.id(), port.number(), false);
Saurav Das018605f2017-02-18 14:05:44 -08001165 }
Saurav Das1a129a02016-11-18 15:21:57 -08001166
1167 // portUpdated calls are for ports that have gone down or up. For switch
1168 // to switch ports, link-events should take care of any re-routing or
1169 // group editing necessary for port up/down. Here we only process edge ports
1170 // that are already configured.
Saurav Dasb0ae6ee2017-03-04 16:08:47 -08001171 ConnectPoint cp = new ConnectPoint(device.id(), port.number());
1172 VlanId untaggedVlan = getUntaggedVlanId(cp);
1173 VlanId nativeVlan = getNativeVlanId(cp);
1174 Set<VlanId> taggedVlans = getTaggedVlanId(cp);
Charles Chan59cc16d2017-02-02 16:20:42 -08001175
Saurav Dasb0ae6ee2017-03-04 16:08:47 -08001176 if (untaggedVlan == null && nativeVlan == null && taggedVlans.isEmpty()) {
Saurav Dasc88d4662017-05-15 15:34:25 -07001177 log.debug("Not handling port updated event for non-edge port (unconfigured) "
Saurav Das1a129a02016-11-18 15:21:57 -08001178 + "dev/port: {}/{}", device.id(), port.number());
1179 return;
1180 }
Saurav Dasb0ae6ee2017-03-04 16:08:47 -08001181 if (untaggedVlan != null) {
1182 processEdgePort(device, port, untaggedVlan, true);
1183 }
1184 if (nativeVlan != null) {
1185 processEdgePort(device, port, nativeVlan, true);
1186 }
1187 if (!taggedVlans.isEmpty()) {
1188 taggedVlans.forEach(tag -> processEdgePort(device, port, tag, false));
1189 }
Saurav Das1a129a02016-11-18 15:21:57 -08001190 }
1191
Saurav Dasb0ae6ee2017-03-04 16:08:47 -08001192 private void processEdgePort(Device device, Port port, VlanId vlanId,
1193 boolean popVlan) {
Saurav Das1a129a02016-11-18 15:21:57 -08001194 boolean portUp = port.isEnabled();
1195 if (portUp) {
Saurav Dasb0ae6ee2017-03-04 16:08:47 -08001196 log.info("Device:EdgePort {}:{} is enabled in vlan: {}", device.id(),
Charles Chan59cc16d2017-02-02 16:20:42 -08001197 port.number(), vlanId);
Saurav Das1a129a02016-11-18 15:21:57 -08001198 } else {
Saurav Dasb0ae6ee2017-03-04 16:08:47 -08001199 log.info("Device:EdgePort {}:{} is disabled in vlan: {}", device.id(),
Charles Chan59cc16d2017-02-02 16:20:42 -08001200 port.number(), vlanId);
Saurav Das1a129a02016-11-18 15:21:57 -08001201 }
1202
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -07001203 DefaultGroupHandler groupHandler = groupHandlerMap.get(device.id());
sanghob35a6192015-04-01 13:05:26 -07001204 if (groupHandler != null) {
Saurav Dasb0ae6ee2017-03-04 16:08:47 -08001205 groupHandler.processEdgePort(port.number(), vlanId, popVlan, portUp);
Saurav Das1a129a02016-11-18 15:21:57 -08001206 } else {
1207 log.warn("Group handler not found for dev:{}. Not handling edge port"
1208 + " {} event for port:{}", device.id(),
1209 (portUp) ? "UP" : "DOWN", port.number());
sanghob35a6192015-04-01 13:05:26 -07001210 }
1211 }
sangho1e575652015-05-14 00:39:53 -07001212
Pier Ventre10bd8d12016-11-26 21:05:22 -08001213 /**
1214 * Registers the given connect point with the NRS, this is necessary
1215 * to receive the NDP and ARP packets from the NRS.
1216 *
1217 * @param portToRegister connect point to register
1218 */
1219 public void registerConnectPoint(ConnectPoint portToRegister) {
Charles Chan0aa674e2017-02-23 15:44:08 -08001220 neighbourResolutionService.registerNeighbourHandler(
Pier Ventre10bd8d12016-11-26 21:05:22 -08001221 portToRegister,
1222 neighbourHandler,
1223 appId
1224 );
1225 }
1226
Charles Chand6832882015-10-05 17:50:33 -07001227 private class InternalConfigListener implements NetworkConfigListener {
Charles Chan2c15aca2016-11-09 20:51:44 -08001228 SegmentRoutingManager srManager;
Charles Chan4636be02015-10-07 14:21:45 -07001229
Charles Chane849c192016-01-11 18:28:54 -08001230 /**
1231 * Constructs the internal network config listener.
1232 *
Charles Chan2c15aca2016-11-09 20:51:44 -08001233 * @param srManager segment routing manager
Charles Chane849c192016-01-11 18:28:54 -08001234 */
Charles Chan2c15aca2016-11-09 20:51:44 -08001235 public InternalConfigListener(SegmentRoutingManager srManager) {
1236 this.srManager = srManager;
Charles Chan4636be02015-10-07 14:21:45 -07001237 }
1238
Charles Chane849c192016-01-11 18:28:54 -08001239 /**
1240 * Reads network config and initializes related data structure accordingly.
1241 */
Charles Chan4636be02015-10-07 14:21:45 -07001242 public void configureNetwork() {
Pier Ventre10bd8d12016-11-26 21:05:22 -08001243
Charles Chan2c15aca2016-11-09 20:51:44 -08001244 deviceConfiguration = new DeviceConfiguration(srManager);
Charles Chan4636be02015-10-07 14:21:45 -07001245
Charles Chan2c15aca2016-11-09 20:51:44 -08001246 arpHandler = new ArpHandler(srManager);
1247 icmpHandler = new IcmpHandler(srManager);
1248 ipHandler = new IpHandler(srManager);
1249 routingRulePopulator = new RoutingRulePopulator(srManager);
1250 defaultRoutingHandler = new DefaultRoutingHandler(srManager);
Charles Chan4636be02015-10-07 14:21:45 -07001251
1252 tunnelHandler = new TunnelHandler(linkService, deviceConfiguration,
1253 groupHandlerMap, tunnelStore);
1254 policyHandler = new PolicyHandler(appId, deviceConfiguration,
1255 flowObjectiveService,
1256 tunnelHandler, policyStore);
1257
Charles Chan4636be02015-10-07 14:21:45 -07001258 for (Device device : deviceService.getDevices()) {
Charles Chanf3b3d812017-07-12 18:47:58 -07001259 processDeviceAdded(device);
Charles Chan4636be02015-10-07 14:21:45 -07001260 }
1261
1262 defaultRoutingHandler.startPopulationProcess();
Charles Chan2199c302016-04-23 17:36:10 -07001263 mcastHandler.init();
Charles Chan4636be02015-10-07 14:21:45 -07001264 }
1265
Charles Chand6832882015-10-05 17:50:33 -07001266 @Override
1267 public void event(NetworkConfigEvent event) {
Charles Chan5270ed02016-01-30 23:22:37 -08001268 // TODO move this part to NetworkConfigEventHandler
1269 if (event.configClass().equals(SegmentRoutingDeviceConfig.class)) {
1270 switch (event.type()) {
1271 case CONFIG_ADDED:
Charles Chan278ce832017-06-26 15:25:09 -07001272 log.info("Segment Routing Device Config added for {}", event.subject());
Charles Chan5270ed02016-01-30 23:22:37 -08001273 configureNetwork();
1274 break;
1275 case CONFIG_UPDATED:
Charles Chan278ce832017-06-26 15:25:09 -07001276 log.info("Segment Routing Config updated for {}", event.subject());
1277 // TODO support dynamic configuration
1278 break;
1279 default:
1280 break;
1281 }
1282 } else if (event.configClass().equals(InterfaceConfig.class)) {
1283 switch (event.type()) {
1284 case CONFIG_ADDED:
1285 log.info("Interface Config added for {}", event.subject());
1286 configureNetwork();
1287 break;
1288 case CONFIG_UPDATED:
1289 log.info("Interface Config updated for {}", event.subject());
Charles Chan5270ed02016-01-30 23:22:37 -08001290 // TODO support dynamic configuration
1291 break;
1292 default:
1293 break;
Charles Chanb8e10c82015-10-14 11:24:40 -07001294 }
Charles Chan5270ed02016-01-30 23:22:37 -08001295 } else if (event.configClass().equals(SegmentRoutingAppConfig.class)) {
Charles Chanfc5c7802016-05-17 13:13:55 -07001296 checkState(appCfgHandler != null, "NetworkConfigEventHandler is not initialized");
Charles Chan5270ed02016-01-30 23:22:37 -08001297 switch (event.type()) {
1298 case CONFIG_ADDED:
Charles Chanfc5c7802016-05-17 13:13:55 -07001299 appCfgHandler.processAppConfigAdded(event);
Charles Chan5270ed02016-01-30 23:22:37 -08001300 break;
1301 case CONFIG_UPDATED:
Charles Chanfc5c7802016-05-17 13:13:55 -07001302 appCfgHandler.processAppConfigUpdated(event);
Charles Chan5270ed02016-01-30 23:22:37 -08001303 break;
1304 case CONFIG_REMOVED:
Charles Chanfc5c7802016-05-17 13:13:55 -07001305 appCfgHandler.processAppConfigRemoved(event);
1306 break;
1307 default:
1308 break;
1309 }
Charles Chan03a73e02016-10-24 14:52:01 -07001310 configureNetwork();
Charles Chanfc5c7802016-05-17 13:13:55 -07001311 } else if (event.configClass().equals(XConnectConfig.class)) {
1312 checkState(xConnectHandler != null, "XConnectHandler is not initialized");
1313 switch (event.type()) {
1314 case CONFIG_ADDED:
1315 xConnectHandler.processXConnectConfigAdded(event);
1316 break;
1317 case CONFIG_UPDATED:
1318 xConnectHandler.processXConnectConfigUpdated(event);
1319 break;
1320 case CONFIG_REMOVED:
1321 xConnectHandler.processXConnectConfigRemoved(event);
Charles Chan5270ed02016-01-30 23:22:37 -08001322 break;
1323 default:
1324 break;
Charles Chanb8e10c82015-10-14 11:24:40 -07001325 }
Pier Ventref34966c2016-11-07 16:21:04 -08001326 } else if (event.configClass().equals(PwaasConfig.class)) {
1327 checkState(l2TunnelHandler != null, "L2TunnelHandler is not initialized");
1328 switch (event.type()) {
1329 case CONFIG_ADDED:
1330 l2TunnelHandler.processPwaasConfigAdded(event);
1331 break;
1332 case CONFIG_UPDATED:
1333 l2TunnelHandler.processPwaasConfigUpdated(event);
1334 break;
1335 case CONFIG_REMOVED:
1336 l2TunnelHandler.processPwaasConfigRemoved(event);
1337 break;
1338 default:
1339 break;
1340 }
Charles Chand6832882015-10-05 17:50:33 -07001341 }
1342 }
1343 }
Charles Chan68aa62d2015-11-09 16:37:23 -08001344
1345 private class InternalHostListener implements HostListener {
Charles Chan68aa62d2015-11-09 16:37:23 -08001346 @Override
1347 public void event(HostEvent event) {
1348 // Do not proceed without mastership
1349 DeviceId deviceId = event.subject().location().deviceId();
1350 if (!mastershipService.isLocalMaster(deviceId)) {
1351 return;
1352 }
1353
1354 switch (event.type()) {
1355 case HOST_ADDED:
Charles Chand2990362016-04-18 13:44:03 -07001356 hostHandler.processHostAddedEvent(event);
Charles Chan68aa62d2015-11-09 16:37:23 -08001357 break;
1358 case HOST_MOVED:
Charles Chand2990362016-04-18 13:44:03 -07001359 hostHandler.processHostMovedEvent(event);
Charles Chan68aa62d2015-11-09 16:37:23 -08001360 break;
1361 case HOST_REMOVED:
Charles Chand2990362016-04-18 13:44:03 -07001362 hostHandler.processHostRemoveEvent(event);
Charles Chan68aa62d2015-11-09 16:37:23 -08001363 break;
1364 case HOST_UPDATED:
Charles Chand2990362016-04-18 13:44:03 -07001365 hostHandler.processHostUpdatedEvent(event);
Charles Chan68aa62d2015-11-09 16:37:23 -08001366 break;
1367 default:
1368 log.warn("Unsupported host event type: {}", event.type());
1369 break;
1370 }
1371 }
1372 }
1373
Charles Chand55e84d2016-03-30 17:54:24 -07001374 private class InternalMcastListener implements McastListener {
1375 @Override
1376 public void event(McastEvent event) {
1377 switch (event.type()) {
1378 case SOURCE_ADDED:
Charles Chand2990362016-04-18 13:44:03 -07001379 mcastHandler.processSourceAdded(event);
Charles Chand55e84d2016-03-30 17:54:24 -07001380 break;
1381 case SINK_ADDED:
Charles Chand2990362016-04-18 13:44:03 -07001382 mcastHandler.processSinkAdded(event);
Charles Chand55e84d2016-03-30 17:54:24 -07001383 break;
1384 case SINK_REMOVED:
Charles Chand2990362016-04-18 13:44:03 -07001385 mcastHandler.processSinkRemoved(event);
Charles Chand55e84d2016-03-30 17:54:24 -07001386 break;
1387 case ROUTE_ADDED:
1388 case ROUTE_REMOVED:
1389 default:
1390 break;
1391 }
1392 }
1393 }
Charles Chan35fd1a72016-06-13 18:54:31 -07001394
Charles Chan03a73e02016-10-24 14:52:01 -07001395 private class InternalRouteEventListener implements RouteListener {
1396 @Override
1397 public void event(RouteEvent event) {
1398 switch (event.type()) {
1399 case ROUTE_ADDED:
1400 routeHandler.processRouteAdded(event);
1401 break;
1402 case ROUTE_UPDATED:
1403 routeHandler.processRouteUpdated(event);
1404 break;
1405 case ROUTE_REMOVED:
1406 routeHandler.processRouteRemoved(event);
1407 break;
1408 default:
1409 break;
1410 }
1411 }
1412 }
Saurav Dasc88d4662017-05-15 15:34:25 -07001413
sanghob35a6192015-04-01 13:05:26 -07001414}