blob: a09b0e4ef94cfa011b79c8213726bb8f11e0a7ee [file] [log] [blame]
sangho80f11cb2015-04-01 13:05:26 -07001/*
Brian O'Connor43b53542016-04-09 01:19:45 -07002 * Copyright 2015-present Open Networking Laboratory
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
Charles Chand7844e52016-10-20 17:02:44 -070018import com.google.common.collect.Maps;
sangho80f11cb2015-04-01 13:05:26 -070019import org.apache.felix.scr.annotations.Activate;
20import org.apache.felix.scr.annotations.Component;
21import org.apache.felix.scr.annotations.Deactivate;
22import org.apache.felix.scr.annotations.Reference;
23import org.apache.felix.scr.annotations.ReferenceCardinality;
sangho27462c62015-05-14 00:39:53 -070024import org.apache.felix.scr.annotations.Service;
sangho80f11cb2015-04-01 13:05:26 -070025import org.onlab.packet.Ethernet;
Charles Chan77277672015-10-20 16:24:19 -070026import org.onlab.packet.IPv4;
Charles Chan77277672015-10-20 16:24:19 -070027import org.onlab.packet.Ip4Prefix;
Charles Chan77277672015-10-20 16:24:19 -070028import org.onlab.packet.IpPrefix;
Jonathan Hart54541d12016-04-12 15:39:44 -070029import org.onlab.packet.VlanId;
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -070030import org.onlab.util.KryoNamespace;
Saurav Dasc3604f12016-03-23 11:22:49 -070031import org.onosproject.cfg.ComponentConfigService;
sangho80f11cb2015-04-01 13:05:26 -070032import org.onosproject.core.ApplicationId;
33import org.onosproject.core.CoreService;
34import org.onosproject.event.Event;
Charles Chanc91c8782016-03-30 17:54:24 -070035import org.onosproject.incubator.net.config.basics.McastConfig;
Charles Chan46fdfaf2016-11-09 20:51:44 -080036import org.onosproject.incubator.net.intf.InterfaceService;
Charles Chandebfea32016-10-24 14:52:01 -070037import org.onosproject.incubator.net.routing.RouteEvent;
38import org.onosproject.incubator.net.routing.RouteListener;
39import org.onosproject.incubator.net.routing.RouteService;
Jonathan Hart54541d12016-04-12 15:39:44 -070040import org.onosproject.mastership.MastershipService;
Jonathan Hart54541d12016-04-12 15:39:44 -070041import org.onosproject.net.Device;
42import org.onosproject.net.DeviceId;
43import org.onosproject.net.Link;
44import org.onosproject.net.Port;
Charles Chanf4586112015-11-09 16:37:23 -080045import org.onosproject.net.PortNumber;
Charles Chan72f556a2015-10-05 17:50:33 -070046import org.onosproject.net.config.ConfigFactory;
47import org.onosproject.net.config.NetworkConfigEvent;
Charles Chan72f556a2015-10-05 17:50:33 -070048import org.onosproject.net.config.NetworkConfigListener;
Jonathan Hart54541d12016-04-12 15:39:44 -070049import org.onosproject.net.config.NetworkConfigRegistry;
Charles Chan72f556a2015-10-05 17:50:33 -070050import org.onosproject.net.config.basics.SubjectFactories;
Jonathan Hart54541d12016-04-12 15:39:44 -070051import org.onosproject.net.device.DeviceEvent;
52import org.onosproject.net.device.DeviceListener;
53import org.onosproject.net.device.DeviceService;
Charles Chanf4586112015-11-09 16:37:23 -080054import org.onosproject.net.flow.TrafficSelector;
55import org.onosproject.net.flow.TrafficTreatment;
Jonathan Hart54541d12016-04-12 15:39:44 -070056import org.onosproject.net.flowobjective.FlowObjectiveService;
Charles Chanf4586112015-11-09 16:37:23 -080057import org.onosproject.net.host.HostEvent;
58import org.onosproject.net.host.HostListener;
Charles Chanc91c8782016-03-30 17:54:24 -070059import org.onosproject.net.mcast.McastEvent;
60import org.onosproject.net.mcast.McastListener;
61import org.onosproject.net.mcast.MulticastRouteService;
Charles Chanc91c8782016-03-30 17:54:24 -070062import org.onosproject.net.topology.TopologyService;
63import org.onosproject.segmentrouting.config.DeviceConfigNotFoundException;
64import org.onosproject.segmentrouting.config.DeviceConfiguration;
65import org.onosproject.segmentrouting.config.SegmentRoutingDeviceConfig;
66import org.onosproject.segmentrouting.config.SegmentRoutingAppConfig;
Charles Chan82f19972016-05-17 13:13:55 -070067import org.onosproject.segmentrouting.config.XConnectConfig;
Charles Chanc91c8782016-03-30 17:54:24 -070068import org.onosproject.segmentrouting.grouphandler.DefaultGroupHandler;
69import org.onosproject.segmentrouting.grouphandler.NeighborSet;
Charles Chan1eaf4802016-04-18 13:44:03 -070070import org.onosproject.segmentrouting.storekey.NeighborSetNextObjectiveStoreKey;
71import org.onosproject.segmentrouting.storekey.PortNextObjectiveStoreKey;
sangho80f11cb2015-04-01 13:05:26 -070072import org.onosproject.net.host.HostService;
sangho80f11cb2015-04-01 13:05:26 -070073import org.onosproject.net.link.LinkEvent;
74import org.onosproject.net.link.LinkListener;
75import org.onosproject.net.link.LinkService;
76import org.onosproject.net.packet.InboundPacket;
77import org.onosproject.net.packet.PacketContext;
78import org.onosproject.net.packet.PacketProcessor;
79import org.onosproject.net.packet.PacketService;
Charles Chan1eaf4802016-04-18 13:44:03 -070080import org.onosproject.segmentrouting.storekey.SubnetAssignedVidStoreKey;
81import org.onosproject.segmentrouting.storekey.SubnetNextObjectiveStoreKey;
Charles Chan82f19972016-05-17 13:13:55 -070082import org.onosproject.segmentrouting.storekey.XConnectStoreKey;
Jonathan Hart54541d12016-04-12 15:39:44 -070083import org.onosproject.store.serializers.KryoNamespaces;
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -070084import org.onosproject.store.service.EventuallyConsistentMap;
85import org.onosproject.store.service.EventuallyConsistentMapBuilder;
86import org.onosproject.store.service.StorageService;
87import org.onosproject.store.service.WallClockTimestamp;
Charles Chan41f5ec02016-06-13 18:54:31 -070088import org.opencord.cordconfig.CordConfigEvent;
89import org.opencord.cordconfig.CordConfigListener;
90import org.opencord.cordconfig.CordConfigService;
sangho80f11cb2015-04-01 13:05:26 -070091import org.slf4j.Logger;
92import org.slf4j.LoggerFactory;
93
Saurav Das7c305372015-10-28 12:39:42 -070094import java.util.Collections;
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -070095import java.util.HashSet;
sangho27462c62015-05-14 00:39:53 -070096import java.util.List;
sangho80f11cb2015-04-01 13:05:26 -070097import java.util.Map;
Saurav Das7c305372015-10-28 12:39:42 -070098import java.util.Set;
sangho80f11cb2015-04-01 13:05:26 -070099import java.util.concurrent.ConcurrentHashMap;
100import java.util.concurrent.ConcurrentLinkedQueue;
101import java.util.concurrent.Executors;
102import java.util.concurrent.ScheduledExecutorService;
103import java.util.concurrent.ScheduledFuture;
104import java.util.concurrent.TimeUnit;
105
Charles Chand6d25332016-02-26 22:19:52 -0800106import static com.google.common.base.Preconditions.checkState;
Yuta HIGUCHIebee2f12016-07-21 16:54:33 -0700107import static org.onlab.util.Tools.groupedThreads;
Charles Chand6d25332016-02-26 22:19:52 -0800108
Charles Chanb7f75ac2016-01-11 18:28:54 -0800109/**
110 * Segment routing manager.
111 */
Jonathan Hart54541d12016-04-12 15:39:44 -0700112@Service
113@Component(immediate = true)
sangho27462c62015-05-14 00:39:53 -0700114public class SegmentRoutingManager implements SegmentRoutingService {
sangho80f11cb2015-04-01 13:05:26 -0700115
Charles Chan46fdfaf2016-11-09 20:51:44 -0800116 private static Logger log = LoggerFactory.getLogger(SegmentRoutingManager.class);
sangho80f11cb2015-04-01 13:05:26 -0700117
118 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Charles Chandebfea32016-10-24 14:52:01 -0700119 private ComponentConfigService compCfgService;
sangho80f11cb2015-04-01 13:05:26 -0700120
121 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Charles Chandebfea32016-10-24 14:52:01 -0700122 CoreService coreService;
sangho80f11cb2015-04-01 13:05:26 -0700123
124 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Charles Chandebfea32016-10-24 14:52:01 -0700125 PacketService packetService;
sangho80f11cb2015-04-01 13:05:26 -0700126
127 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Charles Chandebfea32016-10-24 14:52:01 -0700128 HostService hostService;
sangho80f11cb2015-04-01 13:05:26 -0700129
130 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Charles Chandebfea32016-10-24 14:52:01 -0700131 DeviceService deviceService;
sangho80f11cb2015-04-01 13:05:26 -0700132
133 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Charles Chandebfea32016-10-24 14:52:01 -0700134 FlowObjectiveService flowObjectiveService;
sangho80f11cb2015-04-01 13:05:26 -0700135
136 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Charles Chandebfea32016-10-24 14:52:01 -0700137 LinkService linkService;
sangho27462c62015-05-14 00:39:53 -0700138
Charles Chan82ab1932016-01-30 23:22:37 -0800139 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Charles Chandebfea32016-10-24 14:52:01 -0700140 MastershipService mastershipService;
141
142 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
143 StorageService storageService;
144
145 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
146 MulticastRouteService multicastRouteService;
147
148 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
149 TopologyService topologyService;
150
151 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
152 CordConfigService cordConfigService;
153
154 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
155 RouteService routeService;
Charles Chan82ab1932016-01-30 23:22:37 -0800156
157 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Charles Chan46fdfaf2016-11-09 20:51:44 -0800158 public NetworkConfigRegistry cfgService;
Charles Chan82ab1932016-01-30 23:22:37 -0800159
Saurav Dasc3604f12016-03-23 11:22:49 -0700160 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Charles Chan46fdfaf2016-11-09 20:51:44 -0800161 public InterfaceService interfaceService;
162
Charles Chandebfea32016-10-24 14:52:01 -0700163 ArpHandler arpHandler = null;
164 IcmpHandler icmpHandler = null;
165 IpHandler ipHandler = null;
166 RoutingRulePopulator routingRulePopulator = null;
Charles Chan46fdfaf2016-11-09 20:51:44 -0800167 public ApplicationId appId;
sangho9b169e32015-04-14 16:27:13 -0700168 protected DeviceConfiguration deviceConfiguration = null;
sangho80f11cb2015-04-01 13:05:26 -0700169
Charles Chandebfea32016-10-24 14:52:01 -0700170 DefaultRoutingHandler defaultRoutingHandler = null;
sangho27462c62015-05-14 00:39:53 -0700171 private TunnelHandler tunnelHandler = null;
172 private PolicyHandler policyHandler = null;
Charles Chan2b078ae2015-10-14 11:24:40 -0700173 private InternalPacketProcessor processor = null;
174 private InternalLinkListener linkListener = null;
175 private InternalDeviceListener deviceListener = null;
Charles Chan82f19972016-05-17 13:13:55 -0700176 private AppConfigHandler appCfgHandler = null;
Charles Chandebfea32016-10-24 14:52:01 -0700177 XConnectHandler xConnectHandler = null;
Charles Chan1eaf4802016-04-18 13:44:03 -0700178 private McastHandler mcastHandler = null;
Charles Chandebfea32016-10-24 14:52:01 -0700179 HostHandler hostHandler = null;
Charles Chan41f5ec02016-06-13 18:54:31 -0700180 private CordConfigHandler cordConfigHandler = null;
Charles Chandebfea32016-10-24 14:52:01 -0700181 RouteHandler routeHandler = null;
sangho80f11cb2015-04-01 13:05:26 -0700182 private InternalEventHandler eventHandler = new InternalEventHandler();
Charles Chan82ab1932016-01-30 23:22:37 -0800183 private final InternalHostListener hostListener = new InternalHostListener();
Charles Chanc91c8782016-03-30 17:54:24 -0700184 private final InternalConfigListener cfgListener = new InternalConfigListener(this);
185 private final InternalMcastListener mcastListener = new InternalMcastListener();
Charles Chan41f5ec02016-06-13 18:54:31 -0700186 private final InternalCordConfigListener cordConfigListener = new InternalCordConfigListener();
Charles Chandebfea32016-10-24 14:52:01 -0700187 private final InternalRouteEventListener routeListener = new InternalRouteEventListener();
sangho80f11cb2015-04-01 13:05:26 -0700188
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700189 private ScheduledExecutorService executorService = Executors
Yuta HIGUCHIebee2f12016-07-21 16:54:33 -0700190 .newScheduledThreadPool(1, groupedThreads("SegmentRoutingManager", "event-%d", log));
sangho80f11cb2015-04-01 13:05:26 -0700191
Saurav Das2d94d312015-11-24 23:21:05 -0800192 @SuppressWarnings("unused")
sangho80f11cb2015-04-01 13:05:26 -0700193 private static ScheduledFuture<?> eventHandlerFuture = null;
Saurav Das2d94d312015-11-24 23:21:05 -0800194 @SuppressWarnings("rawtypes")
Yuta HIGUCHIebee2f12016-07-21 16:54:33 -0700195 private ConcurrentLinkedQueue<Event> eventQueue = new ConcurrentLinkedQueue<>();
Charles Chanf4586112015-11-09 16:37:23 -0800196 private Map<DeviceId, DefaultGroupHandler> groupHandlerMap =
Charles Chanb7f75ac2016-01-11 18:28:54 -0800197 new ConcurrentHashMap<>();
198 /**
199 * Per device next objective ID store with (device id + neighbor set) as key.
200 */
201 public EventuallyConsistentMap<NeighborSetNextObjectiveStoreKey, Integer>
Charles Chanf4586112015-11-09 16:37:23 -0800202 nsNextObjStore = null;
Charles Chanb7f75ac2016-01-11 18:28:54 -0800203 /**
204 * Per device next objective ID store with (device id + subnet) as key.
205 */
206 public EventuallyConsistentMap<SubnetNextObjectiveStoreKey, Integer>
Charles Chanf4586112015-11-09 16:37:23 -0800207 subnetNextObjStore = null;
Charles Chanb7f75ac2016-01-11 18:28:54 -0800208 /**
209 * Per device next objective ID store with (device id + port) as key.
210 */
211 public EventuallyConsistentMap<PortNextObjectiveStoreKey, Integer>
Saurav Das2d94d312015-11-24 23:21:05 -0800212 portNextObjStore = null;
Saurav Das7c305372015-10-28 12:39:42 -0700213 // Per device, per-subnet assigned-vlans store, with (device id + subnet
214 // IPv4 prefix) as key
215 private EventuallyConsistentMap<SubnetAssignedVidStoreKey, VlanId>
Charles Chanb7f75ac2016-01-11 18:28:54 -0800216 subnetVidStore = null;
Saurav Das2d94d312015-11-24 23:21:05 -0800217 private EventuallyConsistentMap<String, Tunnel> tunnelStore = null;
218 private EventuallyConsistentMap<String, Policy> policyStore = null;
sangho4a5c42a2015-05-20 22:16:38 -0700219
Charles Chanc91c8782016-03-30 17:54:24 -0700220 private final ConfigFactory<DeviceId, SegmentRoutingDeviceConfig> deviceConfigFactory =
Charles Chan82f19972016-05-17 13:13:55 -0700221 new ConfigFactory<DeviceId, SegmentRoutingDeviceConfig>(
222 SubjectFactories.DEVICE_SUBJECT_FACTORY,
Charles Chanc91c8782016-03-30 17:54:24 -0700223 SegmentRoutingDeviceConfig.class, "segmentrouting") {
Charles Chan72f556a2015-10-05 17:50:33 -0700224 @Override
Charles Chan82ab1932016-01-30 23:22:37 -0800225 public SegmentRoutingDeviceConfig createConfig() {
226 return new SegmentRoutingDeviceConfig();
Charles Chan72f556a2015-10-05 17:50:33 -0700227 }
228 };
Charles Chanc91c8782016-03-30 17:54:24 -0700229 private final ConfigFactory<ApplicationId, SegmentRoutingAppConfig> appConfigFactory =
Charles Chan82f19972016-05-17 13:13:55 -0700230 new ConfigFactory<ApplicationId, SegmentRoutingAppConfig>(
231 SubjectFactories.APP_SUBJECT_FACTORY,
Charles Chanc91c8782016-03-30 17:54:24 -0700232 SegmentRoutingAppConfig.class, "segmentrouting") {
Charles Chan82ab1932016-01-30 23:22:37 -0800233 @Override
234 public SegmentRoutingAppConfig createConfig() {
235 return new SegmentRoutingAppConfig();
236 }
237 };
Charles Chan82f19972016-05-17 13:13:55 -0700238 private final ConfigFactory<ApplicationId, XConnectConfig> xConnectConfigFactory =
239 new ConfigFactory<ApplicationId, XConnectConfig>(
240 SubjectFactories.APP_SUBJECT_FACTORY,
241 XConnectConfig.class, "xconnect") {
242 @Override
243 public XConnectConfig createConfig() {
244 return new XConnectConfig();
245 }
246 };
Charles Chanc91c8782016-03-30 17:54:24 -0700247 private ConfigFactory<ApplicationId, McastConfig> mcastConfigFactory =
Charles Chan82f19972016-05-17 13:13:55 -0700248 new ConfigFactory<ApplicationId, McastConfig>(
249 SubjectFactories.APP_SUBJECT_FACTORY,
Charles Chanc91c8782016-03-30 17:54:24 -0700250 McastConfig.class, "multicast") {
251 @Override
252 public McastConfig createConfig() {
253 return new McastConfig();
254 }
255 };
256
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700257 private Object threadSchedulerLock = new Object();
258 private static int numOfEventsQueued = 0;
259 private static int numOfEventsExecuted = 0;
sangho80f11cb2015-04-01 13:05:26 -0700260 private static int numOfHandlerExecution = 0;
261 private static int numOfHandlerScheduled = 0;
262
Charles Chan1963f4f2016-02-18 14:22:42 -0800263 /**
264 * Segment Routing App ID.
265 */
Charles Chan46fdfaf2016-11-09 20:51:44 -0800266 public static final String APP_NAME = "org.onosproject.segmentrouting";
Charles Chanb7f75ac2016-01-11 18:28:54 -0800267 /**
268 * The starting value of per-subnet VLAN ID assignment.
269 */
Saurav Das7c305372015-10-28 12:39:42 -0700270 private static final short ASSIGNED_VLAN_START = 4093;
Charles Chanb7f75ac2016-01-11 18:28:54 -0800271 /**
272 * The default VLAN ID assigned to the interfaces without subnet config.
273 */
Saurav Das7c305372015-10-28 12:39:42 -0700274 public static final short ASSIGNED_VLAN_NO_SUBNET = 4094;
275
sangho80f11cb2015-04-01 13:05:26 -0700276 @Activate
277 protected void activate() {
Charles Chan46fdfaf2016-11-09 20:51:44 -0800278 appId = coreService.registerApplication(APP_NAME);
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700279
280 log.debug("Creating EC map nsnextobjectivestore");
281 EventuallyConsistentMapBuilder<NeighborSetNextObjectiveStoreKey, Integer>
282 nsNextObjMapBuilder = storageService.eventuallyConsistentMapBuilder();
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700283 nsNextObjStore = nsNextObjMapBuilder
284 .withName("nsnextobjectivestore")
Jonathan Hart54541d12016-04-12 15:39:44 -0700285 .withSerializer(createSerializer())
Madan Jampani675ae202015-06-24 19:05:56 -0700286 .withTimestampProvider((k, v) -> new WallClockTimestamp())
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700287 .build();
288 log.trace("Current size {}", nsNextObjStore.size());
289
Charles Chan77277672015-10-20 16:24:19 -0700290 log.debug("Creating EC map subnetnextobjectivestore");
291 EventuallyConsistentMapBuilder<SubnetNextObjectiveStoreKey, Integer>
292 subnetNextObjMapBuilder = storageService.eventuallyConsistentMapBuilder();
Charles Chan77277672015-10-20 16:24:19 -0700293 subnetNextObjStore = subnetNextObjMapBuilder
294 .withName("subnetnextobjectivestore")
Jonathan Hart54541d12016-04-12 15:39:44 -0700295 .withSerializer(createSerializer())
Charles Chan77277672015-10-20 16:24:19 -0700296 .withTimestampProvider((k, v) -> new WallClockTimestamp())
297 .build();
298
Saurav Das2d94d312015-11-24 23:21:05 -0800299 log.debug("Creating EC map subnetnextobjectivestore");
300 EventuallyConsistentMapBuilder<PortNextObjectiveStoreKey, Integer>
301 portNextObjMapBuilder = storageService.eventuallyConsistentMapBuilder();
302 portNextObjStore = portNextObjMapBuilder
303 .withName("portnextobjectivestore")
Jonathan Hart54541d12016-04-12 15:39:44 -0700304 .withSerializer(createSerializer())
Saurav Das2d94d312015-11-24 23:21:05 -0800305 .withTimestampProvider((k, v) -> new WallClockTimestamp())
306 .build();
307
sangho4a5c42a2015-05-20 22:16:38 -0700308 EventuallyConsistentMapBuilder<String, Tunnel> tunnelMapBuilder =
309 storageService.eventuallyConsistentMapBuilder();
sangho4a5c42a2015-05-20 22:16:38 -0700310 tunnelStore = tunnelMapBuilder
311 .withName("tunnelstore")
Jonathan Hart54541d12016-04-12 15:39:44 -0700312 .withSerializer(createSerializer())
Madan Jampani675ae202015-06-24 19:05:56 -0700313 .withTimestampProvider((k, v) -> new WallClockTimestamp())
sangho4a5c42a2015-05-20 22:16:38 -0700314 .build();
315
316 EventuallyConsistentMapBuilder<String, Policy> policyMapBuilder =
317 storageService.eventuallyConsistentMapBuilder();
sangho4a5c42a2015-05-20 22:16:38 -0700318 policyStore = policyMapBuilder
319 .withName("policystore")
Jonathan Hart54541d12016-04-12 15:39:44 -0700320 .withSerializer(createSerializer())
Madan Jampani675ae202015-06-24 19:05:56 -0700321 .withTimestampProvider((k, v) -> new WallClockTimestamp())
sangho4a5c42a2015-05-20 22:16:38 -0700322 .build();
323
Saurav Das7c305372015-10-28 12:39:42 -0700324 EventuallyConsistentMapBuilder<SubnetAssignedVidStoreKey, VlanId>
325 subnetVidStoreMapBuilder = storageService.eventuallyConsistentMapBuilder();
Saurav Das7c305372015-10-28 12:39:42 -0700326 subnetVidStore = subnetVidStoreMapBuilder
327 .withName("subnetvidstore")
Jonathan Hart54541d12016-04-12 15:39:44 -0700328 .withSerializer(createSerializer())
Saurav Das7c305372015-10-28 12:39:42 -0700329 .withTimestampProvider((k, v) -> new WallClockTimestamp())
330 .build();
331
Saurav Dasc3604f12016-03-23 11:22:49 -0700332 compCfgService.preSetProperty("org.onosproject.net.group.impl.GroupManager",
Pier Luigib9632ba2017-01-12 18:14:58 -0800333 "purgeOnDisconnection", "true");
Saurav Dasc3604f12016-03-23 11:22:49 -0700334 compCfgService.preSetProperty("org.onosproject.net.flow.impl.FlowRuleManager",
Pier Luigib9632ba2017-01-12 18:14:58 -0800335 "purgeOnDisconnection", "true");
Charles Chandebfea32016-10-24 14:52:01 -0700336 compCfgService.preSetProperty("org.onosproject.vrouter.Vrouter",
Pier Luigib9632ba2017-01-12 18:14:58 -0800337 "fibInstalledEnabled", "false");
338 compCfgService.preSetProperty("org.onosproject.provider.host.impl.HostLocationProvider",
339 "requestInterceptsEnabled", "false");
Saurav Dasc3604f12016-03-23 11:22:49 -0700340
Charles Chan2b078ae2015-10-14 11:24:40 -0700341 processor = new InternalPacketProcessor();
342 linkListener = new InternalLinkListener();
343 deviceListener = new InternalDeviceListener();
Charles Chan82f19972016-05-17 13:13:55 -0700344 appCfgHandler = new AppConfigHandler(this);
345 xConnectHandler = new XConnectHandler(this);
Charles Chan1eaf4802016-04-18 13:44:03 -0700346 mcastHandler = new McastHandler(this);
347 hostHandler = new HostHandler(this);
Charles Chan41f5ec02016-06-13 18:54:31 -0700348 cordConfigHandler = new CordConfigHandler(this);
Charles Chandebfea32016-10-24 14:52:01 -0700349 routeHandler = new RouteHandler(this);
Charles Chan2b078ae2015-10-14 11:24:40 -0700350
Charles Chand6d25332016-02-26 22:19:52 -0800351 cfgService.addListener(cfgListener);
Charles Chanc91c8782016-03-30 17:54:24 -0700352 cfgService.registerConfigFactory(deviceConfigFactory);
353 cfgService.registerConfigFactory(appConfigFactory);
Charles Chan82f19972016-05-17 13:13:55 -0700354 cfgService.registerConfigFactory(xConnectConfigFactory);
Charles Chanc91c8782016-03-30 17:54:24 -0700355 cfgService.registerConfigFactory(mcastConfigFactory);
Charles Chan82ab1932016-01-30 23:22:37 -0800356 hostService.addListener(hostListener);
Charles Chan2b078ae2015-10-14 11:24:40 -0700357 packetService.addProcessor(processor, PacketProcessor.director(2));
358 linkService.addListener(linkListener);
359 deviceService.addListener(deviceListener);
Charles Chanc91c8782016-03-30 17:54:24 -0700360 multicastRouteService.addListener(mcastListener);
Charles Chan41f5ec02016-06-13 18:54:31 -0700361 cordConfigService.addListener(cordConfigListener);
Charles Chan2b078ae2015-10-14 11:24:40 -0700362
363 cfgListener.configureNetwork();
364
Charles Chandebfea32016-10-24 14:52:01 -0700365 routeService.addListener(routeListener);
366
sangho80f11cb2015-04-01 13:05:26 -0700367 log.info("Started");
368 }
369
Jonathan Hart54541d12016-04-12 15:39:44 -0700370 private KryoNamespace.Builder createSerializer() {
371 return new KryoNamespace.Builder()
372 .register(KryoNamespaces.API)
373 .register(NeighborSetNextObjectiveStoreKey.class,
374 SubnetNextObjectiveStoreKey.class,
375 SubnetAssignedVidStoreKey.class,
376 NeighborSet.class,
377 Tunnel.class,
378 DefaultTunnel.class,
379 Policy.class,
380 TunnelPolicy.class,
381 Policy.Type.class,
382 PortNextObjectiveStoreKey.class,
Charles Chan82f19972016-05-17 13:13:55 -0700383 XConnectStoreKey.class
Jonathan Hart54541d12016-04-12 15:39:44 -0700384 );
385 }
386
sangho80f11cb2015-04-01 13:05:26 -0700387 @Deactivate
388 protected void deactivate() {
Charles Chan72f556a2015-10-05 17:50:33 -0700389 cfgService.removeListener(cfgListener);
Charles Chanc91c8782016-03-30 17:54:24 -0700390 cfgService.unregisterConfigFactory(deviceConfigFactory);
391 cfgService.unregisterConfigFactory(appConfigFactory);
Charles Chandebfea32016-10-24 14:52:01 -0700392 cfgService.unregisterConfigFactory(xConnectConfigFactory);
Charles Chanc91c8782016-03-30 17:54:24 -0700393 cfgService.unregisterConfigFactory(mcastConfigFactory);
Charles Chan72f556a2015-10-05 17:50:33 -0700394
sangho80f11cb2015-04-01 13:05:26 -0700395 packetService.removeProcessor(processor);
Charles Chan2b078ae2015-10-14 11:24:40 -0700396 linkService.removeListener(linkListener);
397 deviceService.removeListener(deviceListener);
Charles Chanc91c8782016-03-30 17:54:24 -0700398 multicastRouteService.removeListener(mcastListener);
Charles Chan41f5ec02016-06-13 18:54:31 -0700399 cordConfigService.removeListener(cordConfigListener);
Charles Chandebfea32016-10-24 14:52:01 -0700400 routeService.removeListener(routeListener);
Charles Chanc91c8782016-03-30 17:54:24 -0700401
sangho80f11cb2015-04-01 13:05:26 -0700402 processor = null;
Charles Chan2b078ae2015-10-14 11:24:40 -0700403 linkListener = null;
Charles Chanc91c8782016-03-30 17:54:24 -0700404 deviceListener = null;
Charles Chan2b078ae2015-10-14 11:24:40 -0700405 groupHandlerMap.clear();
406
Charles Chanc91c8782016-03-30 17:54:24 -0700407 nsNextObjStore.destroy();
408 subnetNextObjStore.destroy();
409 portNextObjStore.destroy();
Charles Chanc91c8782016-03-30 17:54:24 -0700410 tunnelStore.destroy();
411 policyStore.destroy();
412 subnetVidStore.destroy();
sangho80f11cb2015-04-01 13:05:26 -0700413 log.info("Stopped");
414 }
415
sangho27462c62015-05-14 00:39:53 -0700416 @Override
417 public List<Tunnel> getTunnels() {
418 return tunnelHandler.getTunnels();
419 }
420
421 @Override
sanghobd812f82015-06-29 14:58:47 -0700422 public TunnelHandler.Result createTunnel(Tunnel tunnel) {
423 return tunnelHandler.createTunnel(tunnel);
sangho27462c62015-05-14 00:39:53 -0700424 }
425
426 @Override
sanghobd812f82015-06-29 14:58:47 -0700427 public TunnelHandler.Result removeTunnel(Tunnel tunnel) {
sangho27462c62015-05-14 00:39:53 -0700428 for (Policy policy: policyHandler.getPolicies()) {
429 if (policy.type() == Policy.Type.TUNNEL_FLOW) {
430 TunnelPolicy tunnelPolicy = (TunnelPolicy) policy;
431 if (tunnelPolicy.tunnelId().equals(tunnel.id())) {
432 log.warn("Cannot remove the tunnel used by a policy");
sanghobd812f82015-06-29 14:58:47 -0700433 return TunnelHandler.Result.TUNNEL_IN_USE;
sangho27462c62015-05-14 00:39:53 -0700434 }
435 }
436 }
sanghobd812f82015-06-29 14:58:47 -0700437 return tunnelHandler.removeTunnel(tunnel);
sangho27462c62015-05-14 00:39:53 -0700438 }
439
440 @Override
sanghobd812f82015-06-29 14:58:47 -0700441 public PolicyHandler.Result removePolicy(Policy policy) {
442 return policyHandler.removePolicy(policy);
sangho27462c62015-05-14 00:39:53 -0700443 }
444
445 @Override
sanghobd812f82015-06-29 14:58:47 -0700446 public PolicyHandler.Result createPolicy(Policy policy) {
447 return policyHandler.createPolicy(policy);
sangho27462c62015-05-14 00:39:53 -0700448 }
449
450 @Override
451 public List<Policy> getPolicies() {
452 return policyHandler.getPolicies();
453 }
454
Saurav Das07c74602016-04-27 18:35:50 -0700455 @Override
456 public void rerouteNetwork() {
457 cfgListener.configureNetwork();
458 for (Device device : deviceService.getDevices()) {
459 defaultRoutingHandler.populatePortAddressingRules(device.id());
460 }
461 defaultRoutingHandler.startPopulationProcess();
462 }
463
Charles Chand7844e52016-10-20 17:02:44 -0700464 @Override
465 public Map<DeviceId, Set<Ip4Prefix>> getDeviceSubnetMap() {
466 Map<DeviceId, Set<Ip4Prefix>> deviceSubnetMap = Maps.newHashMap();
467 deviceService.getAvailableDevices().forEach(device -> {
468 deviceSubnetMap.put(device.id(), deviceConfiguration.getSubnets(device.id()));
469 });
470 return deviceSubnetMap;
471 }
472
sangho80f1f892015-05-19 11:57:42 -0700473 /**
Pier Ventre7a78de22016-10-31 15:00:01 -0700474 * Returns the MPLS-ECMP configuration.
475 *
476 * @return MPLS-ECMP value
477 */
478 public boolean getMplsEcmp() {
479 SegmentRoutingAppConfig segmentRoutingAppConfig = cfgService
480 .getConfig(this.appId, SegmentRoutingAppConfig.class);
481 return segmentRoutingAppConfig != null && segmentRoutingAppConfig.mplsEcmp();
482 }
483
484 /**
sangho80f1f892015-05-19 11:57:42 -0700485 * Returns the tunnel object with the tunnel ID.
486 *
487 * @param tunnelId Tunnel ID
488 * @return Tunnel reference
489 */
sangho27462c62015-05-14 00:39:53 -0700490 public Tunnel getTunnel(String tunnelId) {
491 return tunnelHandler.getTunnel(tunnelId);
492 }
493
sangho80f11cb2015-04-01 13:05:26 -0700494 /**
Saurav Das7c305372015-10-28 12:39:42 -0700495 * Returns the vlan-id assigned to the subnet configured for a device.
496 * If no vlan-id has been assigned, a new one is assigned out of a pool of ids,
497 * if and only if this controller instance is the master for the device.
498 * <p>
499 * USAGE: The assigned vlans are meant to be applied to untagged packets on those
500 * switches/pipelines that need this functionality. These vids are meant
501 * to be used internally within a switch, and thus need to be unique only
502 * on a switch level. Note that packets never go out on the wire with these
503 * vlans. Currently, vlan ids are assigned from value 4093 down.
504 * Vlan id 4094 expected to be used for all ports that are not assigned subnets.
505 * Vlan id 4095 is reserved and unused. Only a single vlan id is assigned
506 * per subnet.
sangho80f11cb2015-04-01 13:05:26 -0700507 *
Saurav Das7c305372015-10-28 12:39:42 -0700508 * @param deviceId switch dpid
509 * @param subnet IPv4 prefix for which assigned vlan is desired
510 * @return VlanId assigned for the subnet on the device, or
511 * null if no vlan assignment was found and this instance is not
512 * the master for the device.
sangho80f11cb2015-04-01 13:05:26 -0700513 */
Charles Chanb7f75ac2016-01-11 18:28:54 -0800514 // TODO: We should avoid assigning VLAN IDs that are used by VLAN cross-connection.
Saurav Das7c305372015-10-28 12:39:42 -0700515 public VlanId getSubnetAssignedVlanId(DeviceId deviceId, Ip4Prefix subnet) {
516 VlanId assignedVid = subnetVidStore.get(new SubnetAssignedVidStoreKey(
517 deviceId, subnet));
518 if (assignedVid != null) {
519 log.debug("Query for subnet:{} on device:{} returned assigned-vlan "
520 + "{}", subnet, deviceId, assignedVid);
521 return assignedVid;
522 }
523 //check mastership for the right to assign a vlan
524 if (!mastershipService.isLocalMaster(deviceId)) {
525 log.warn("This controller instance is not the master for device {}. "
526 + "Cannot assign vlan-id for subnet {}", deviceId, subnet);
527 return null;
528 }
529 // vlan assignment is expensive but done only once
Charles Chanc6ad7752015-10-29 14:58:10 -0700530 Set<Ip4Prefix> configuredSubnets = deviceConfiguration.getSubnets(deviceId);
Saurav Das7c305372015-10-28 12:39:42 -0700531 Set<Short> assignedVlans = new HashSet<>();
532 Set<Ip4Prefix> unassignedSubnets = new HashSet<>();
533 for (Ip4Prefix sub : configuredSubnets) {
534 VlanId v = subnetVidStore.get(new SubnetAssignedVidStoreKey(deviceId,
535 sub));
536 if (v != null) {
537 assignedVlans.add(v.toShort());
538 } else {
539 unassignedSubnets.add(sub);
540 }
541 }
542 short nextAssignedVlan = ASSIGNED_VLAN_START;
543 if (!assignedVlans.isEmpty()) {
544 nextAssignedVlan = (short) (Collections.min(assignedVlans) - 1);
545 }
546 for (Ip4Prefix unsub : unassignedSubnets) {
Charles Chan82ab1932016-01-30 23:22:37 -0800547 // Special case for default route. Assign default VLAN ID to /32 and /0 subnets
548 if (unsub.prefixLength() == IpPrefix.MAX_INET_MASK_LENGTH ||
549 unsub.prefixLength() == 0) {
550 subnetVidStore.put(new SubnetAssignedVidStoreKey(deviceId, unsub),
551 VlanId.vlanId(ASSIGNED_VLAN_NO_SUBNET));
552 } else {
553 subnetVidStore.put(new SubnetAssignedVidStoreKey(deviceId, unsub),
554 VlanId.vlanId(nextAssignedVlan--));
555 log.info("Assigned vlan: {} to subnet: {} on device: {}",
556 nextAssignedVlan + 1, unsub, deviceId);
557 }
sangho80f11cb2015-04-01 13:05:26 -0700558 }
559
Saurav Das7c305372015-10-28 12:39:42 -0700560 return subnetVidStore.get(new SubnetAssignedVidStoreKey(deviceId, subnet));
sangho80f11cb2015-04-01 13:05:26 -0700561 }
562
sangho27462c62015-05-14 00:39:53 -0700563 /**
Saurav Das7c305372015-10-28 12:39:42 -0700564 * Returns the next objective ID for the given NeighborSet.
Saurav Das4c35fc42015-11-20 15:27:53 -0800565 * If the nextObjective does not exist, a new one is created and
Saurav Das2d94d312015-11-24 23:21:05 -0800566 * its id is returned.
sangho27462c62015-05-14 00:39:53 -0700567 *
sangho80f1f892015-05-19 11:57:42 -0700568 * @param deviceId Device ID
569 * @param ns NegighborSet
Saurav Das4c35fc42015-11-20 15:27:53 -0800570 * @param meta metadata passed into the creation of a Next Objective
571 * @return next objective ID or -1 if an error was encountered during the
572 * creation of the nextObjective
sangho27462c62015-05-14 00:39:53 -0700573 */
Saurav Das4c35fc42015-11-20 15:27:53 -0800574 public int getNextObjectiveId(DeviceId deviceId, NeighborSet ns,
575 TrafficSelector meta) {
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700576 if (groupHandlerMap.get(deviceId) != null) {
577 log.trace("getNextObjectiveId query in device {}", deviceId);
578 return groupHandlerMap
Saurav Das4c35fc42015-11-20 15:27:53 -0800579 .get(deviceId).getNextObjectiveId(ns, meta);
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700580 } else {
Saurav Das2d94d312015-11-24 23:21:05 -0800581 log.warn("getNextObjectiveId query - groupHandler for device {} "
582 + "not found", deviceId);
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700583 return -1;
584 }
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700585 }
586
Charles Chan77277672015-10-20 16:24:19 -0700587 /**
Saurav Das2d94d312015-11-24 23:21:05 -0800588 * Returns the next objective ID for the given subnet prefix. It is expected
589 * that the next-objective has been pre-created from configuration.
Charles Chan77277672015-10-20 16:24:19 -0700590 *
591 * @param deviceId Device ID
592 * @param prefix Subnet
Saurav Das2d94d312015-11-24 23:21:05 -0800593 * @return next objective ID or -1 if it was not found
Charles Chan77277672015-10-20 16:24:19 -0700594 */
595 public int getSubnetNextObjectiveId(DeviceId deviceId, IpPrefix prefix) {
596 if (groupHandlerMap.get(deviceId) != null) {
597 log.trace("getSubnetNextObjectiveId query in device {}", deviceId);
598 return groupHandlerMap
599 .get(deviceId).getSubnetNextObjectiveId(prefix);
600 } else {
Saurav Das2d94d312015-11-24 23:21:05 -0800601 log.warn("getSubnetNextObjectiveId query - groupHandler for "
602 + "device {} not found", deviceId);
603 return -1;
604 }
605 }
606
607 /**
608 * Returns the next objective ID for the given portNumber, given the treatment.
609 * There could be multiple different treatments to the same outport, which
610 * would result in different objectives. If the next object
611 * does not exist, a new one is created and its id is returned.
612 *
613 * @param deviceId Device ID
614 * @param portNum port number on device for which NextObjective is queried
615 * @param treatment the actions to apply on the packets (should include outport)
616 * @param meta metadata passed into the creation of a Next Objective if necessary
Saurav Das07c74602016-04-27 18:35:50 -0700617 * @return next objective ID or -1 if an error occurred during retrieval or creation
Saurav Das2d94d312015-11-24 23:21:05 -0800618 */
619 public int getPortNextObjectiveId(DeviceId deviceId, PortNumber portNum,
620 TrafficTreatment treatment,
621 TrafficSelector meta) {
622 DefaultGroupHandler ghdlr = groupHandlerMap.get(deviceId);
623 if (ghdlr != null) {
624 return ghdlr.getPortNextObjectiveId(portNum, treatment, meta);
625 } else {
Charles Chanb7f75ac2016-01-11 18:28:54 -0800626 log.warn("getPortNextObjectiveId query - groupHandler for device {}"
627 + " not found", deviceId);
628 return -1;
629 }
630 }
631
sangho80f11cb2015-04-01 13:05:26 -0700632 private class InternalPacketProcessor implements PacketProcessor {
sangho80f11cb2015-04-01 13:05:26 -0700633 @Override
634 public void process(PacketContext context) {
635
636 if (context.isHandled()) {
637 return;
638 }
639
640 InboundPacket pkt = context.inPacket();
641 Ethernet ethernet = pkt.parsed();
Saurav Das2d94d312015-11-24 23:21:05 -0800642 log.trace("Rcvd pktin: {}", ethernet);
sangho80f11cb2015-04-01 13:05:26 -0700643 if (ethernet.getEtherType() == Ethernet.TYPE_ARP) {
644 arpHandler.processPacketIn(pkt);
645 } else if (ethernet.getEtherType() == Ethernet.TYPE_IPV4) {
646 IPv4 ipPacket = (IPv4) ethernet.getPayload();
647 ipHandler.addToPacketBuffer(ipPacket);
648 if (ipPacket.getProtocol() == IPv4.PROTOCOL_ICMP) {
649 icmpHandler.processPacketIn(pkt);
650 } else {
651 ipHandler.processPacketIn(pkt);
652 }
653 }
654 }
655 }
656
657 private class InternalLinkListener implements LinkListener {
658 @Override
659 public void event(LinkEvent event) {
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700660 if (event.type() == LinkEvent.Type.LINK_ADDED
661 || event.type() == LinkEvent.Type.LINK_REMOVED) {
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700662 log.debug("Event {} received from Link Service", event.type());
sangho80f11cb2015-04-01 13:05:26 -0700663 scheduleEventHandlerIfNotScheduled(event);
664 }
665 }
666 }
667
668 private class InternalDeviceListener implements DeviceListener {
sangho80f11cb2015-04-01 13:05:26 -0700669 @Override
670 public void event(DeviceEvent event) {
sangho80f11cb2015-04-01 13:05:26 -0700671 switch (event.type()) {
672 case DEVICE_ADDED:
Saurav Dasf0f592d2016-11-18 15:21:57 -0800673 case PORT_UPDATED:
674 case PORT_ADDED:
sanghofb7c7292015-04-13 15:15:58 -0700675 case DEVICE_UPDATED:
676 case DEVICE_AVAILABILITY_CHANGED:
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700677 log.debug("Event {} received from Device Service", event.type());
sangho80f11cb2015-04-01 13:05:26 -0700678 scheduleEventHandlerIfNotScheduled(event);
679 break;
680 default:
681 }
682 }
683 }
684
Saurav Das2d94d312015-11-24 23:21:05 -0800685 @SuppressWarnings("rawtypes")
sangho80f11cb2015-04-01 13:05:26 -0700686 private void scheduleEventHandlerIfNotScheduled(Event event) {
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700687 synchronized (threadSchedulerLock) {
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700688 eventQueue.add(event);
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700689 numOfEventsQueued++;
690
691 if ((numOfHandlerScheduled - numOfHandlerExecution) == 0) {
692 //No pending scheduled event handling threads. So start a new one.
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700693 eventHandlerFuture = executorService
694 .schedule(eventHandler, 100, TimeUnit.MILLISECONDS);
695 numOfHandlerScheduled++;
696 }
Jonathan Hart54541d12016-04-12 15:39:44 -0700697 log.trace("numOfEventsQueued {}, numOfEventHandlerScheduled {}",
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700698 numOfEventsQueued,
699 numOfHandlerScheduled);
sangho80f11cb2015-04-01 13:05:26 -0700700 }
sangho80f11cb2015-04-01 13:05:26 -0700701 }
702
703 private class InternalEventHandler implements Runnable {
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700704 @Override
sangho80f11cb2015-04-01 13:05:26 -0700705 public void run() {
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700706 try {
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700707 while (true) {
Saurav Das2d94d312015-11-24 23:21:05 -0800708 @SuppressWarnings("rawtypes")
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700709 Event event = null;
710 synchronized (threadSchedulerLock) {
711 if (!eventQueue.isEmpty()) {
712 event = eventQueue.poll();
713 numOfEventsExecuted++;
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700714 } else {
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700715 numOfHandlerExecution++;
716 log.debug("numOfHandlerExecution {} numOfEventsExecuted {}",
717 numOfHandlerExecution, numOfEventsExecuted);
718 break;
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700719 }
sanghofb7c7292015-04-13 15:15:58 -0700720 }
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700721 if (event.type() == LinkEvent.Type.LINK_ADDED) {
722 processLinkAdded((Link) event.subject());
723 } else if (event.type() == LinkEvent.Type.LINK_REMOVED) {
Pier Ventre6d593892016-09-13 21:33:40 -0700724 Link linkRemoved = (Link) event.subject();
725 if (linkRemoved.src().elementId() instanceof DeviceId &&
726 !deviceService.isAvailable(linkRemoved.src().deviceId())) {
727 continue;
728 }
729 if (linkRemoved.dst().elementId() instanceof DeviceId &&
730 !deviceService.isAvailable(linkRemoved.dst().deviceId())) {
731 continue;
732 }
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700733 processLinkRemoved((Link) event.subject());
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700734 } else if (event.type() == DeviceEvent.Type.DEVICE_ADDED ||
735 event.type() == DeviceEvent.Type.DEVICE_AVAILABILITY_CHANGED ||
736 event.type() == DeviceEvent.Type.DEVICE_UPDATED) {
Saurav Das62af8802015-12-04 10:52:59 -0800737 DeviceId deviceId = ((Device) event.subject()).id();
738 if (deviceService.isAvailable(deviceId)) {
Saurav Dasc28b3432015-10-30 17:45:38 -0700739 log.info("Processing device event {} for available device {}",
740 event.type(), ((Device) event.subject()).id());
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700741 processDeviceAdded((Device) event.subject());
Saurav Dasc3604f12016-03-23 11:22:49 -0700742 } else {
743 log.info("Processing device event {} for unavailable device {}",
744 event.type(), ((Device) event.subject()).id());
745 processDeviceRemoved((Device) event.subject());
746 }
Saurav Dasf0f592d2016-11-18 15:21:57 -0800747 } else if (event.type() == DeviceEvent.Type.PORT_ADDED) {
Saurav Dasd1872b02016-12-02 15:43:47 -0800748 // typically these calls come when device is added first time
749 // so port filtering rules are handled at the device_added event.
750 // port added calls represent all ports on the device,
751 // enabled or not.
Saurav Dasf0f592d2016-11-18 15:21:57 -0800752 log.debug("** PORT ADDED {}/{} -> {}",
Saurav Dasd1872b02016-12-02 15:43:47 -0800753 ((DeviceEvent) event).subject().id(),
754 ((DeviceEvent) event).port().number(),
755 event.type());
Saurav Dasf0f592d2016-11-18 15:21:57 -0800756 } else if (event.type() == DeviceEvent.Type.PORT_UPDATED) {
Saurav Dasd1872b02016-12-02 15:43:47 -0800757 // these calls happen for every subsequent event
758 // ports enabled, disabled, switch goes away, comes back
Saurav Dasf0f592d2016-11-18 15:21:57 -0800759 log.info("** PORT UPDATED {}/{} -> {}",
760 event.subject(),
761 ((DeviceEvent) event).port(),
762 event.type());
763 processPortUpdated(((Device) event.subject()),
764 ((DeviceEvent) event).port());
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700765 } else {
766 log.warn("Unhandled event type: {}", event.type());
767 }
sangho80f11cb2015-04-01 13:05:26 -0700768 }
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700769 } catch (Exception e) {
770 log.error("SegmentRouting event handler "
771 + "thread thrown an exception: {}", e);
sangho80f11cb2015-04-01 13:05:26 -0700772 }
sangho80f11cb2015-04-01 13:05:26 -0700773 }
774 }
775
sangho80f11cb2015-04-01 13:05:26 -0700776 private void processLinkAdded(Link link) {
Saurav Dasb149be12016-06-07 10:08:06 -0700777 log.info("** LINK ADDED {}", link.toString());
Charles Chan319d1a22015-11-03 10:42:14 -0800778 if (!deviceConfiguration.isConfigured(link.src().deviceId())) {
779 log.warn("Source device of this link is not configured.");
780 return;
781 }
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700782 //Irrespective whether the local is a MASTER or not for this device,
783 //create group handler instance and push default TTP flow rules.
784 //Because in a multi-instance setup, instances can initiate
785 //groups for any devices. Also the default TTP rules are needed
786 //to be pushed before inserting any IP table entries for any device
787 DefaultGroupHandler groupHandler = groupHandlerMap.get(link.src()
788 .deviceId());
789 if (groupHandler != null) {
Saurav Das4c35fc42015-11-20 15:27:53 -0800790 groupHandler.linkUp(link, mastershipService.isLocalMaster(
791 link.src().deviceId()));
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700792 } else {
793 Device device = deviceService.getDevice(link.src().deviceId());
794 if (device != null) {
795 log.warn("processLinkAdded: Link Added "
796 + "Notification without Device Added "
797 + "event, still handling it");
798 processDeviceAdded(device);
799 groupHandler = groupHandlerMap.get(link.src()
800 .deviceId());
Saurav Das4c35fc42015-11-20 15:27:53 -0800801 groupHandler.linkUp(link, mastershipService.isLocalMaster(device.id()));
sangho80f11cb2015-04-01 13:05:26 -0700802 }
803 }
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700804
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700805 log.trace("Starting optimized route population process");
806 defaultRoutingHandler.populateRoutingRulesForLinkStatusChange(null);
807 //log.trace("processLinkAdded: re-starting route population process");
808 //defaultRoutingHandler.startPopulationProcess();
Charles Chan72779502016-04-23 17:36:10 -0700809
810 mcastHandler.init();
sangho80f11cb2015-04-01 13:05:26 -0700811 }
812
813 private void processLinkRemoved(Link link) {
Saurav Dasb149be12016-06-07 10:08:06 -0700814 log.info("** LINK REMOVED {}", link.toString());
sangho2165d222015-05-01 09:38:25 -0700815 DefaultGroupHandler groupHandler = groupHandlerMap.get(link.src().deviceId());
816 if (groupHandler != null) {
Saurav Das62af8802015-12-04 10:52:59 -0800817 groupHandler.portDown(link.src().port(),
818 mastershipService.isLocalMaster(link.src().deviceId()));
sangho2165d222015-05-01 09:38:25 -0700819 }
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700820 log.trace("Starting optimized route population process");
821 defaultRoutingHandler.populateRoutingRulesForLinkStatusChange(link);
822 //log.trace("processLinkRemoved: re-starting route population process");
823 //defaultRoutingHandler.startPopulationProcess();
Charles Chan72779502016-04-23 17:36:10 -0700824
825 mcastHandler.processLinkDown(link);
sangho80f11cb2015-04-01 13:05:26 -0700826 }
827
828 private void processDeviceAdded(Device device) {
Saurav Dasb149be12016-06-07 10:08:06 -0700829 log.info("** DEVICE ADDED with ID {}", device.id());
Charles Chan319d1a22015-11-03 10:42:14 -0800830 if (deviceConfiguration == null || !deviceConfiguration.isConfigured(device.id())) {
Saurav Das8ec0ec42015-11-03 14:39:27 -0800831 log.warn("Device configuration uploading. Device {} will be "
832 + "processed after config completes.", device.id());
833 return;
834 }
Charles Chan72779502016-04-23 17:36:10 -0700835 processDeviceAddedInternal(device.id());
836 }
837
838 private void processDeviceAddedInternal(DeviceId deviceId) {
Saurav Dasc28b3432015-10-30 17:45:38 -0700839 // Irrespective of whether the local is a MASTER or not for this device,
840 // we need to create a SR-group-handler instance. This is because in a
841 // multi-instance setup, any instance can initiate forwarding/next-objectives
842 // for any switch (even if this instance is a SLAVE or not even connected
843 // to the switch). To handle this, a default-group-handler instance is necessary
844 // per switch.
Charles Chan72779502016-04-23 17:36:10 -0700845 log.debug("Current groupHandlerMap devs: {}", groupHandlerMap.keySet());
846 if (groupHandlerMap.get(deviceId) == null) {
Charles Chan319d1a22015-11-03 10:42:14 -0800847 DefaultGroupHandler groupHandler;
848 try {
849 groupHandler = DefaultGroupHandler.
Charles Chan72779502016-04-23 17:36:10 -0700850 createGroupHandler(deviceId,
851 appId,
852 deviceConfiguration,
853 linkService,
854 flowObjectiveService,
855 this);
Charles Chan319d1a22015-11-03 10:42:14 -0800856 } catch (DeviceConfigNotFoundException e) {
857 log.warn(e.getMessage() + " Aborting processDeviceAdded.");
858 return;
859 }
Charles Chan72779502016-04-23 17:36:10 -0700860 log.debug("updating groupHandlerMap with new config for device: {}",
861 deviceId);
862 groupHandlerMap.put(deviceId, groupHandler);
Saurav Das8ec0ec42015-11-03 14:39:27 -0800863 }
Saurav Dasb149be12016-06-07 10:08:06 -0700864 // Also, in some cases, drivers may need extra
865 // information to process rules (eg. Router IP/MAC); and so, we send
866 // port addressing rules to the driver as well irrespective of whether
867 // this instance is the master or not.
868 defaultRoutingHandler.populatePortAddressingRules(deviceId);
869
Charles Chan72779502016-04-23 17:36:10 -0700870 if (mastershipService.isLocalMaster(deviceId)) {
Charles Chandebfea32016-10-24 14:52:01 -0700871 hostHandler.init(deviceId);
Charles Chan82f19972016-05-17 13:13:55 -0700872 xConnectHandler.init(deviceId);
Charles Chan41f5ec02016-06-13 18:54:31 -0700873 cordConfigHandler.init(deviceId);
Charles Chan72779502016-04-23 17:36:10 -0700874 DefaultGroupHandler groupHandler = groupHandlerMap.get(deviceId);
Charles Chan77277672015-10-20 16:24:19 -0700875 groupHandler.createGroupsFromSubnetConfig();
Charles Chan72779502016-04-23 17:36:10 -0700876 routingRulePopulator.populateSubnetBroadcastRule(deviceId);
Charles Chan77277672015-10-20 16:24:19 -0700877 }
Charles Chan82ab1932016-01-30 23:22:37 -0800878
Charles Chandebfea32016-10-24 14:52:01 -0700879 appCfgHandler.init(deviceId);
880 routeHandler.init(deviceId);
sangho80f11cb2015-04-01 13:05:26 -0700881 }
882
Saurav Dasc3604f12016-03-23 11:22:49 -0700883 private void processDeviceRemoved(Device device) {
884 nsNextObjStore.entrySet().stream()
885 .filter(entry -> entry.getKey().deviceId().equals(device.id()))
886 .forEach(entry -> {
887 nsNextObjStore.remove(entry.getKey());
888 });
Saurav Dasc3604f12016-03-23 11:22:49 -0700889 subnetNextObjStore.entrySet().stream()
890 .filter(entry -> entry.getKey().deviceId().equals(device.id()))
891 .forEach(entry -> {
892 subnetNextObjStore.remove(entry.getKey());
893 });
Saurav Dasc3604f12016-03-23 11:22:49 -0700894 portNextObjStore.entrySet().stream()
895 .filter(entry -> entry.getKey().deviceId().equals(device.id()))
896 .forEach(entry -> {
897 portNextObjStore.remove(entry.getKey());
898 });
Saurav Dasc3604f12016-03-23 11:22:49 -0700899 subnetVidStore.entrySet().stream()
900 .filter(entry -> entry.getKey().deviceId().equals(device.id()))
901 .forEach(entry -> {
902 subnetVidStore.remove(entry.getKey());
903 });
Saurav Dasc3604f12016-03-23 11:22:49 -0700904 groupHandlerMap.remove(device.id());
Saurav Dasc3604f12016-03-23 11:22:49 -0700905 defaultRoutingHandler.purgeEcmpGraph(device.id());
Charles Chan72779502016-04-23 17:36:10 -0700906 mcastHandler.removeDevice(device.id());
Charles Chan82f19972016-05-17 13:13:55 -0700907 xConnectHandler.removeDevice(device.id());
Saurav Dasc3604f12016-03-23 11:22:49 -0700908 }
909
Saurav Dasf0f592d2016-11-18 15:21:57 -0800910 private void processPortUpdated(Device device, Port port) {
911 if (deviceConfiguration == null || !deviceConfiguration.isConfigured(device.id())) {
912 log.warn("Device configuration uploading. Not handling port event for"
913 + "dev: {} port: {}", device.id(), port.number());
914 return;
915 }
916 /* XXX create method for single port filtering rules which are needed
917 for both switch-to-switch ports and edge ports
918 if (defaultRoutingHandler != null) {
919 defaultRoutingHandler.populatePortAddressingRules(
920 ((Device) event.subject()).id());
921 }*/
922
923 // portUpdated calls are for ports that have gone down or up. For switch
924 // to switch ports, link-events should take care of any re-routing or
925 // group editing necessary for port up/down. Here we only process edge ports
926 // that are already configured.
927 Ip4Prefix configuredSubnet = deviceConfiguration.getPortSubnet(device.id(),
928 port.number());
929 if (configuredSubnet == null) {
930 log.debug("Not handling port updated event for unconfigured port "
931 + "dev/port: {}/{}", device.id(), port.number());
932 return;
933 }
934 processEdgePort(device, port, configuredSubnet);
935 }
936
937 private void processEdgePort(Device device, Port port, Ip4Prefix subnet) {
938 boolean portUp = port.isEnabled();
939 if (portUp) {
940 log.info("Device:EdgePort {}:{} is enabled in subnet: {}", device.id(),
941 port.number(), subnet);
942 } else {
943 log.info("Device:EdgePort {}:{} is disabled in subnet: {}", device.id(),
944 port.number(), subnet);
945 }
946
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700947 DefaultGroupHandler groupHandler = groupHandlerMap.get(device.id());
sangho80f11cb2015-04-01 13:05:26 -0700948 if (groupHandler != null) {
Saurav Dasf0f592d2016-11-18 15:21:57 -0800949 groupHandler.processEdgePort(port.number(), subnet, portUp,
Saurav Das62af8802015-12-04 10:52:59 -0800950 mastershipService.isLocalMaster(device.id()));
Saurav Dasf0f592d2016-11-18 15:21:57 -0800951 } else {
952 log.warn("Group handler not found for dev:{}. Not handling edge port"
953 + " {} event for port:{}", device.id(),
954 (portUp) ? "UP" : "DOWN", port.number());
sangho80f11cb2015-04-01 13:05:26 -0700955 }
956 }
sangho27462c62015-05-14 00:39:53 -0700957
Charles Chan72f556a2015-10-05 17:50:33 -0700958 private class InternalConfigListener implements NetworkConfigListener {
Charles Chan46fdfaf2016-11-09 20:51:44 -0800959 SegmentRoutingManager srManager;
Charles Chane7c61022015-10-07 14:21:45 -0700960
Charles Chanb7f75ac2016-01-11 18:28:54 -0800961 /**
962 * Constructs the internal network config listener.
963 *
Charles Chan46fdfaf2016-11-09 20:51:44 -0800964 * @param srManager segment routing manager
Charles Chanb7f75ac2016-01-11 18:28:54 -0800965 */
Charles Chan46fdfaf2016-11-09 20:51:44 -0800966 public InternalConfigListener(SegmentRoutingManager srManager) {
967 this.srManager = srManager;
Charles Chane7c61022015-10-07 14:21:45 -0700968 }
969
Charles Chanb7f75ac2016-01-11 18:28:54 -0800970 /**
971 * Reads network config and initializes related data structure accordingly.
972 */
Charles Chane7c61022015-10-07 14:21:45 -0700973 public void configureNetwork() {
Charles Chan46fdfaf2016-11-09 20:51:44 -0800974 deviceConfiguration = new DeviceConfiguration(srManager);
Charles Chane7c61022015-10-07 14:21:45 -0700975
Charles Chan46fdfaf2016-11-09 20:51:44 -0800976 arpHandler = new ArpHandler(srManager);
977 icmpHandler = new IcmpHandler(srManager);
978 ipHandler = new IpHandler(srManager);
979 routingRulePopulator = new RoutingRulePopulator(srManager);
980 defaultRoutingHandler = new DefaultRoutingHandler(srManager);
Charles Chane7c61022015-10-07 14:21:45 -0700981
982 tunnelHandler = new TunnelHandler(linkService, deviceConfiguration,
983 groupHandlerMap, tunnelStore);
984 policyHandler = new PolicyHandler(appId, deviceConfiguration,
985 flowObjectiveService,
986 tunnelHandler, policyStore);
987
Charles Chane7c61022015-10-07 14:21:45 -0700988 for (Device device : deviceService.getDevices()) {
Charles Chan72779502016-04-23 17:36:10 -0700989 processDeviceAddedInternal(device.id());
Charles Chane7c61022015-10-07 14:21:45 -0700990 }
991
992 defaultRoutingHandler.startPopulationProcess();
Charles Chan72779502016-04-23 17:36:10 -0700993 mcastHandler.init();
Charles Chane7c61022015-10-07 14:21:45 -0700994 }
995
Charles Chan72f556a2015-10-05 17:50:33 -0700996 @Override
997 public void event(NetworkConfigEvent event) {
Charles Chan82ab1932016-01-30 23:22:37 -0800998 // TODO move this part to NetworkConfigEventHandler
999 if (event.configClass().equals(SegmentRoutingDeviceConfig.class)) {
1000 switch (event.type()) {
1001 case CONFIG_ADDED:
1002 log.info("Segment Routing Config added.");
1003 configureNetwork();
1004 break;
1005 case CONFIG_UPDATED:
1006 log.info("Segment Routing Config updated.");
1007 // TODO support dynamic configuration
1008 break;
1009 default:
1010 break;
Charles Chan2b078ae2015-10-14 11:24:40 -07001011 }
Charles Chan82ab1932016-01-30 23:22:37 -08001012 } else if (event.configClass().equals(SegmentRoutingAppConfig.class)) {
Charles Chan82f19972016-05-17 13:13:55 -07001013 checkState(appCfgHandler != null, "NetworkConfigEventHandler is not initialized");
Charles Chan82ab1932016-01-30 23:22:37 -08001014 switch (event.type()) {
1015 case CONFIG_ADDED:
Charles Chan82f19972016-05-17 13:13:55 -07001016 appCfgHandler.processAppConfigAdded(event);
Charles Chan82ab1932016-01-30 23:22:37 -08001017 break;
1018 case CONFIG_UPDATED:
Charles Chan82f19972016-05-17 13:13:55 -07001019 appCfgHandler.processAppConfigUpdated(event);
Charles Chan82ab1932016-01-30 23:22:37 -08001020 break;
1021 case CONFIG_REMOVED:
Charles Chan82f19972016-05-17 13:13:55 -07001022 appCfgHandler.processAppConfigRemoved(event);
1023 break;
1024 default:
1025 break;
1026 }
Charles Chandebfea32016-10-24 14:52:01 -07001027 configureNetwork();
Charles Chan82f19972016-05-17 13:13:55 -07001028 } else if (event.configClass().equals(XConnectConfig.class)) {
1029 checkState(xConnectHandler != null, "XConnectHandler is not initialized");
1030 switch (event.type()) {
1031 case CONFIG_ADDED:
1032 xConnectHandler.processXConnectConfigAdded(event);
1033 break;
1034 case CONFIG_UPDATED:
1035 xConnectHandler.processXConnectConfigUpdated(event);
1036 break;
1037 case CONFIG_REMOVED:
1038 xConnectHandler.processXConnectConfigRemoved(event);
Charles Chan82ab1932016-01-30 23:22:37 -08001039 break;
1040 default:
1041 break;
Charles Chan2b078ae2015-10-14 11:24:40 -07001042 }
Charles Chan72f556a2015-10-05 17:50:33 -07001043 }
1044 }
1045 }
Charles Chanf4586112015-11-09 16:37:23 -08001046
1047 private class InternalHostListener implements HostListener {
Charles Chanf4586112015-11-09 16:37:23 -08001048 @Override
1049 public void event(HostEvent event) {
1050 // Do not proceed without mastership
1051 DeviceId deviceId = event.subject().location().deviceId();
1052 if (!mastershipService.isLocalMaster(deviceId)) {
1053 return;
1054 }
1055
1056 switch (event.type()) {
1057 case HOST_ADDED:
Charles Chan1eaf4802016-04-18 13:44:03 -07001058 hostHandler.processHostAddedEvent(event);
Charles Chanf4586112015-11-09 16:37:23 -08001059 break;
1060 case HOST_MOVED:
Charles Chan1eaf4802016-04-18 13:44:03 -07001061 hostHandler.processHostMovedEvent(event);
Charles Chanf4586112015-11-09 16:37:23 -08001062 break;
1063 case HOST_REMOVED:
Charles Chan1eaf4802016-04-18 13:44:03 -07001064 hostHandler.processHostRemoveEvent(event);
Charles Chanf4586112015-11-09 16:37:23 -08001065 break;
1066 case HOST_UPDATED:
Charles Chan1eaf4802016-04-18 13:44:03 -07001067 hostHandler.processHostUpdatedEvent(event);
Charles Chanf4586112015-11-09 16:37:23 -08001068 break;
1069 default:
1070 log.warn("Unsupported host event type: {}", event.type());
1071 break;
1072 }
1073 }
1074 }
1075
Charles Chanc91c8782016-03-30 17:54:24 -07001076 private class InternalMcastListener implements McastListener {
1077 @Override
1078 public void event(McastEvent event) {
1079 switch (event.type()) {
1080 case SOURCE_ADDED:
Charles Chan1eaf4802016-04-18 13:44:03 -07001081 mcastHandler.processSourceAdded(event);
Charles Chanc91c8782016-03-30 17:54:24 -07001082 break;
1083 case SINK_ADDED:
Charles Chan1eaf4802016-04-18 13:44:03 -07001084 mcastHandler.processSinkAdded(event);
Charles Chanc91c8782016-03-30 17:54:24 -07001085 break;
1086 case SINK_REMOVED:
Charles Chan1eaf4802016-04-18 13:44:03 -07001087 mcastHandler.processSinkRemoved(event);
Charles Chanc91c8782016-03-30 17:54:24 -07001088 break;
1089 case ROUTE_ADDED:
1090 case ROUTE_REMOVED:
1091 default:
1092 break;
1093 }
1094 }
1095 }
Charles Chan41f5ec02016-06-13 18:54:31 -07001096
1097 private class InternalCordConfigListener implements CordConfigListener {
1098 @Override
1099 public void event(CordConfigEvent event) {
1100 switch (event.type()) {
1101 case ACCESS_AGENT_ADDED:
1102 cordConfigHandler.processAccessAgentAddedEvent(event);
1103 break;
1104 case ACCESS_AGENT_UPDATED:
1105 cordConfigHandler.processAccessAgentUpdatedEvent(event);
1106 break;
1107 case ACCESS_AGENT_REMOVED:
1108 cordConfigHandler.processAccessAgentRemovedEvent(event);
1109 break;
1110 case ACCESS_DEVICE_ADDED:
1111 case ACCESS_DEVICE_UPDATED:
1112 case ACCESS_DEVICE_REMOVED:
1113 default:
1114 break;
1115 }
1116 }
1117 }
Charles Chandebfea32016-10-24 14:52:01 -07001118
1119 private class InternalRouteEventListener implements RouteListener {
1120 @Override
1121 public void event(RouteEvent event) {
1122 switch (event.type()) {
1123 case ROUTE_ADDED:
1124 routeHandler.processRouteAdded(event);
1125 break;
1126 case ROUTE_UPDATED:
1127 routeHandler.processRouteUpdated(event);
1128 break;
1129 case ROUTE_REMOVED:
1130 routeHandler.processRouteRemoved(event);
1131 break;
1132 default:
1133 break;
1134 }
1135 }
1136 }
sangho80f11cb2015-04-01 13:05:26 -07001137}