blob: 2b87fca105e16add02b1af2f0ff53c779cbffd84 [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
18import org.apache.felix.scr.annotations.Activate;
19import org.apache.felix.scr.annotations.Component;
20import org.apache.felix.scr.annotations.Deactivate;
21import org.apache.felix.scr.annotations.Reference;
22import org.apache.felix.scr.annotations.ReferenceCardinality;
sangho27462c62015-05-14 00:39:53 -070023import org.apache.felix.scr.annotations.Service;
sangho80f11cb2015-04-01 13:05:26 -070024import org.onlab.packet.Ethernet;
Charles Chan77277672015-10-20 16:24:19 -070025import org.onlab.packet.IPv4;
Charles Chan77277672015-10-20 16:24:19 -070026import org.onlab.packet.Ip4Prefix;
Charles Chan77277672015-10-20 16:24:19 -070027import org.onlab.packet.IpPrefix;
Jonathan Hart54541d12016-04-12 15:39:44 -070028import org.onlab.packet.VlanId;
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -070029import org.onlab.util.KryoNamespace;
Saurav Dasc3604f12016-03-23 11:22:49 -070030import org.onosproject.cfg.ComponentConfigService;
sangho80f11cb2015-04-01 13:05:26 -070031import org.onosproject.core.ApplicationId;
32import org.onosproject.core.CoreService;
33import org.onosproject.event.Event;
Charles Chanc91c8782016-03-30 17:54:24 -070034import org.onosproject.incubator.net.config.basics.McastConfig;
Jonathan Hart54541d12016-04-12 15:39:44 -070035import org.onosproject.mastership.MastershipService;
Jonathan Hart54541d12016-04-12 15:39:44 -070036import org.onosproject.net.Device;
37import org.onosproject.net.DeviceId;
38import org.onosproject.net.Link;
39import org.onosproject.net.Port;
Charles Chanf4586112015-11-09 16:37:23 -080040import org.onosproject.net.PortNumber;
Charles Chan72f556a2015-10-05 17:50:33 -070041import org.onosproject.net.config.ConfigFactory;
42import org.onosproject.net.config.NetworkConfigEvent;
Charles Chan72f556a2015-10-05 17:50:33 -070043import org.onosproject.net.config.NetworkConfigListener;
Jonathan Hart54541d12016-04-12 15:39:44 -070044import org.onosproject.net.config.NetworkConfigRegistry;
Charles Chan72f556a2015-10-05 17:50:33 -070045import org.onosproject.net.config.basics.SubjectFactories;
Jonathan Hart54541d12016-04-12 15:39:44 -070046import org.onosproject.net.device.DeviceEvent;
47import org.onosproject.net.device.DeviceListener;
48import org.onosproject.net.device.DeviceService;
Charles Chanf4586112015-11-09 16:37:23 -080049import org.onosproject.net.flow.DefaultTrafficSelector;
Charles Chanf4586112015-11-09 16:37:23 -080050import org.onosproject.net.flow.TrafficSelector;
51import org.onosproject.net.flow.TrafficTreatment;
Jonathan Hart54541d12016-04-12 15:39:44 -070052import org.onosproject.net.flowobjective.FlowObjectiveService;
Charles Chanf4586112015-11-09 16:37:23 -080053import org.onosproject.net.host.HostEvent;
54import org.onosproject.net.host.HostListener;
Charles Chanc91c8782016-03-30 17:54:24 -070055import org.onosproject.net.mcast.McastEvent;
56import org.onosproject.net.mcast.McastListener;
57import org.onosproject.net.mcast.MulticastRouteService;
58import org.onosproject.net.packet.PacketPriority;
59import org.onosproject.net.topology.TopologyService;
60import org.onosproject.segmentrouting.config.DeviceConfigNotFoundException;
61import org.onosproject.segmentrouting.config.DeviceConfiguration;
62import org.onosproject.segmentrouting.config.SegmentRoutingDeviceConfig;
63import org.onosproject.segmentrouting.config.SegmentRoutingAppConfig;
Charles Chan82f19972016-05-17 13:13:55 -070064import org.onosproject.segmentrouting.config.XConnectConfig;
Charles Chanc91c8782016-03-30 17:54:24 -070065import org.onosproject.segmentrouting.grouphandler.DefaultGroupHandler;
66import org.onosproject.segmentrouting.grouphandler.NeighborSet;
Charles Chan1eaf4802016-04-18 13:44:03 -070067import org.onosproject.segmentrouting.storekey.NeighborSetNextObjectiveStoreKey;
68import org.onosproject.segmentrouting.storekey.PortNextObjectiveStoreKey;
sangho80f11cb2015-04-01 13:05:26 -070069import org.onosproject.net.host.HostService;
sangho80f11cb2015-04-01 13:05:26 -070070import org.onosproject.net.link.LinkEvent;
71import org.onosproject.net.link.LinkListener;
72import org.onosproject.net.link.LinkService;
73import org.onosproject.net.packet.InboundPacket;
74import org.onosproject.net.packet.PacketContext;
75import org.onosproject.net.packet.PacketProcessor;
76import org.onosproject.net.packet.PacketService;
Charles Chan1eaf4802016-04-18 13:44:03 -070077import org.onosproject.segmentrouting.storekey.SubnetAssignedVidStoreKey;
78import org.onosproject.segmentrouting.storekey.SubnetNextObjectiveStoreKey;
Charles Chan82f19972016-05-17 13:13:55 -070079import org.onosproject.segmentrouting.storekey.XConnectStoreKey;
Jonathan Hart54541d12016-04-12 15:39:44 -070080import org.onosproject.store.serializers.KryoNamespaces;
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -070081import org.onosproject.store.service.EventuallyConsistentMap;
82import org.onosproject.store.service.EventuallyConsistentMapBuilder;
83import org.onosproject.store.service.StorageService;
84import org.onosproject.store.service.WallClockTimestamp;
sangho80f11cb2015-04-01 13:05:26 -070085import org.slf4j.Logger;
86import org.slf4j.LoggerFactory;
87
Saurav Das7c305372015-10-28 12:39:42 -070088import java.util.Collections;
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -070089import java.util.HashSet;
sangho27462c62015-05-14 00:39:53 -070090import java.util.List;
sangho80f11cb2015-04-01 13:05:26 -070091import java.util.Map;
Charles Chande6655c2015-12-23 00:15:11 -080092import java.util.Optional;
Saurav Das7c305372015-10-28 12:39:42 -070093import java.util.Set;
sangho80f11cb2015-04-01 13:05:26 -070094import java.util.concurrent.ConcurrentHashMap;
95import java.util.concurrent.ConcurrentLinkedQueue;
96import java.util.concurrent.Executors;
97import java.util.concurrent.ScheduledExecutorService;
98import java.util.concurrent.ScheduledFuture;
99import java.util.concurrent.TimeUnit;
100
Charles Chand6d25332016-02-26 22:19:52 -0800101import static com.google.common.base.Preconditions.checkState;
102
Jonathan Hart54541d12016-04-12 15:39:44 -0700103
Charles Chanb7f75ac2016-01-11 18:28:54 -0800104/**
105 * Segment routing manager.
106 */
Jonathan Hart54541d12016-04-12 15:39:44 -0700107@Service
108@Component(immediate = true)
sangho27462c62015-05-14 00:39:53 -0700109public class SegmentRoutingManager implements SegmentRoutingService {
sangho80f11cb2015-04-01 13:05:26 -0700110
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700111 private static Logger log = LoggerFactory
112 .getLogger(SegmentRoutingManager.class);
sangho80f11cb2015-04-01 13:05:26 -0700113
114 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
115 protected CoreService coreService;
116
117 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
sangho80f11cb2015-04-01 13:05:26 -0700118 protected PacketService packetService;
119
120 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
sangho80f11cb2015-04-01 13:05:26 -0700121 protected HostService hostService;
122
123 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
124 protected DeviceService deviceService;
125
126 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700127 protected FlowObjectiveService flowObjectiveService;
sangho80f11cb2015-04-01 13:05:26 -0700128
129 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
130 protected LinkService linkService;
131
132 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
sangho80f11cb2015-04-01 13:05:26 -0700133 protected MastershipService mastershipService;
sangho27462c62015-05-14 00:39:53 -0700134
Charles Chan82ab1932016-01-30 23:22:37 -0800135 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
136 protected StorageService storageService;
137
138 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
139 protected NetworkConfigRegistry cfgService;
140
Saurav Dasc3604f12016-03-23 11:22:49 -0700141 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
142 protected ComponentConfigService compCfgService;
143
Charles Chanc91c8782016-03-30 17:54:24 -0700144 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
145 protected MulticastRouteService multicastRouteService;
146
147 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
148 protected TopologyService topologyService;
149
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700150 protected ArpHandler arpHandler = null;
151 protected IcmpHandler icmpHandler = null;
152 protected IpHandler ipHandler = null;
153 protected RoutingRulePopulator routingRulePopulator = null;
sangho80f11cb2015-04-01 13:05:26 -0700154 protected ApplicationId appId;
sangho9b169e32015-04-14 16:27:13 -0700155 protected DeviceConfiguration deviceConfiguration = null;
sangho80f11cb2015-04-01 13:05:26 -0700156
Charles Chanc22cef32016-04-29 14:38:22 -0700157 protected DefaultRoutingHandler defaultRoutingHandler = null;
sangho27462c62015-05-14 00:39:53 -0700158 private TunnelHandler tunnelHandler = null;
159 private PolicyHandler policyHandler = null;
Charles Chan2b078ae2015-10-14 11:24:40 -0700160 private InternalPacketProcessor processor = null;
161 private InternalLinkListener linkListener = null;
162 private InternalDeviceListener deviceListener = null;
Charles Chan82f19972016-05-17 13:13:55 -0700163 private AppConfigHandler appCfgHandler = null;
164 protected XConnectHandler xConnectHandler = null;
Charles Chan1eaf4802016-04-18 13:44:03 -0700165 private McastHandler mcastHandler = null;
166 private HostHandler hostHandler = null;
sangho80f11cb2015-04-01 13:05:26 -0700167 private InternalEventHandler eventHandler = new InternalEventHandler();
Charles Chan82ab1932016-01-30 23:22:37 -0800168 private final InternalHostListener hostListener = new InternalHostListener();
Charles Chanc91c8782016-03-30 17:54:24 -0700169 private final InternalConfigListener cfgListener = new InternalConfigListener(this);
170 private final InternalMcastListener mcastListener = new InternalMcastListener();
sangho80f11cb2015-04-01 13:05:26 -0700171
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700172 private ScheduledExecutorService executorService = Executors
173 .newScheduledThreadPool(1);
sangho80f11cb2015-04-01 13:05:26 -0700174
Saurav Das2d94d312015-11-24 23:21:05 -0800175 @SuppressWarnings("unused")
sangho80f11cb2015-04-01 13:05:26 -0700176 private static ScheduledFuture<?> eventHandlerFuture = null;
Saurav Das2d94d312015-11-24 23:21:05 -0800177 @SuppressWarnings("rawtypes")
sangho80f11cb2015-04-01 13:05:26 -0700178 private ConcurrentLinkedQueue<Event> eventQueue = new ConcurrentLinkedQueue<Event>();
Charles Chanf4586112015-11-09 16:37:23 -0800179 private Map<DeviceId, DefaultGroupHandler> groupHandlerMap =
Charles Chanb7f75ac2016-01-11 18:28:54 -0800180 new ConcurrentHashMap<>();
181 /**
182 * Per device next objective ID store with (device id + neighbor set) as key.
183 */
184 public EventuallyConsistentMap<NeighborSetNextObjectiveStoreKey, Integer>
Charles Chanf4586112015-11-09 16:37:23 -0800185 nsNextObjStore = null;
Charles Chanb7f75ac2016-01-11 18:28:54 -0800186 /**
187 * Per device next objective ID store with (device id + subnet) as key.
188 */
189 public EventuallyConsistentMap<SubnetNextObjectiveStoreKey, Integer>
Charles Chanf4586112015-11-09 16:37:23 -0800190 subnetNextObjStore = null;
Charles Chanb7f75ac2016-01-11 18:28:54 -0800191 /**
192 * Per device next objective ID store with (device id + port) as key.
193 */
194 public EventuallyConsistentMap<PortNextObjectiveStoreKey, Integer>
Saurav Das2d94d312015-11-24 23:21:05 -0800195 portNextObjStore = null;
Saurav Das7c305372015-10-28 12:39:42 -0700196 // Per device, per-subnet assigned-vlans store, with (device id + subnet
197 // IPv4 prefix) as key
198 private EventuallyConsistentMap<SubnetAssignedVidStoreKey, VlanId>
Charles Chanb7f75ac2016-01-11 18:28:54 -0800199 subnetVidStore = null;
Saurav Das2d94d312015-11-24 23:21:05 -0800200 private EventuallyConsistentMap<String, Tunnel> tunnelStore = null;
201 private EventuallyConsistentMap<String, Policy> policyStore = null;
sangho4a5c42a2015-05-20 22:16:38 -0700202
Charles Chanc91c8782016-03-30 17:54:24 -0700203 private final ConfigFactory<DeviceId, SegmentRoutingDeviceConfig> deviceConfigFactory =
Charles Chan82f19972016-05-17 13:13:55 -0700204 new ConfigFactory<DeviceId, SegmentRoutingDeviceConfig>(
205 SubjectFactories.DEVICE_SUBJECT_FACTORY,
Charles Chanc91c8782016-03-30 17:54:24 -0700206 SegmentRoutingDeviceConfig.class, "segmentrouting") {
Charles Chan72f556a2015-10-05 17:50:33 -0700207 @Override
Charles Chan82ab1932016-01-30 23:22:37 -0800208 public SegmentRoutingDeviceConfig createConfig() {
209 return new SegmentRoutingDeviceConfig();
Charles Chan72f556a2015-10-05 17:50:33 -0700210 }
211 };
Charles Chanc91c8782016-03-30 17:54:24 -0700212 private final ConfigFactory<ApplicationId, SegmentRoutingAppConfig> appConfigFactory =
Charles Chan82f19972016-05-17 13:13:55 -0700213 new ConfigFactory<ApplicationId, SegmentRoutingAppConfig>(
214 SubjectFactories.APP_SUBJECT_FACTORY,
Charles Chanc91c8782016-03-30 17:54:24 -0700215 SegmentRoutingAppConfig.class, "segmentrouting") {
Charles Chan82ab1932016-01-30 23:22:37 -0800216 @Override
217 public SegmentRoutingAppConfig createConfig() {
218 return new SegmentRoutingAppConfig();
219 }
220 };
Charles Chan82f19972016-05-17 13:13:55 -0700221 private final ConfigFactory<ApplicationId, XConnectConfig> xConnectConfigFactory =
222 new ConfigFactory<ApplicationId, XConnectConfig>(
223 SubjectFactories.APP_SUBJECT_FACTORY,
224 XConnectConfig.class, "xconnect") {
225 @Override
226 public XConnectConfig createConfig() {
227 return new XConnectConfig();
228 }
229 };
Charles Chanc91c8782016-03-30 17:54:24 -0700230 private ConfigFactory<ApplicationId, McastConfig> mcastConfigFactory =
Charles Chan82f19972016-05-17 13:13:55 -0700231 new ConfigFactory<ApplicationId, McastConfig>(
232 SubjectFactories.APP_SUBJECT_FACTORY,
Charles Chanc91c8782016-03-30 17:54:24 -0700233 McastConfig.class, "multicast") {
234 @Override
235 public McastConfig createConfig() {
236 return new McastConfig();
237 }
238 };
239
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700240 private Object threadSchedulerLock = new Object();
241 private static int numOfEventsQueued = 0;
242 private static int numOfEventsExecuted = 0;
sangho80f11cb2015-04-01 13:05:26 -0700243 private static int numOfHandlerExecution = 0;
244 private static int numOfHandlerScheduled = 0;
245
Charles Chan1963f4f2016-02-18 14:22:42 -0800246 /**
247 * Segment Routing App ID.
248 */
249 public static final String SR_APP_ID = "org.onosproject.segmentrouting";
Charles Chanb7f75ac2016-01-11 18:28:54 -0800250 /**
251 * The starting value of per-subnet VLAN ID assignment.
252 */
Saurav Das7c305372015-10-28 12:39:42 -0700253 private static final short ASSIGNED_VLAN_START = 4093;
Charles Chanb7f75ac2016-01-11 18:28:54 -0800254 /**
255 * The default VLAN ID assigned to the interfaces without subnet config.
256 */
Saurav Das7c305372015-10-28 12:39:42 -0700257 public static final short ASSIGNED_VLAN_NO_SUBNET = 4094;
258
sangho80f11cb2015-04-01 13:05:26 -0700259 @Activate
260 protected void activate() {
Jonathan Hart54541d12016-04-12 15:39:44 -0700261 appId = coreService.registerApplication(SR_APP_ID);
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700262
263 log.debug("Creating EC map nsnextobjectivestore");
264 EventuallyConsistentMapBuilder<NeighborSetNextObjectiveStoreKey, Integer>
265 nsNextObjMapBuilder = storageService.eventuallyConsistentMapBuilder();
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700266 nsNextObjStore = nsNextObjMapBuilder
267 .withName("nsnextobjectivestore")
Jonathan Hart54541d12016-04-12 15:39:44 -0700268 .withSerializer(createSerializer())
Madan Jampani675ae202015-06-24 19:05:56 -0700269 .withTimestampProvider((k, v) -> new WallClockTimestamp())
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700270 .build();
271 log.trace("Current size {}", nsNextObjStore.size());
272
Charles Chan77277672015-10-20 16:24:19 -0700273 log.debug("Creating EC map subnetnextobjectivestore");
274 EventuallyConsistentMapBuilder<SubnetNextObjectiveStoreKey, Integer>
275 subnetNextObjMapBuilder = storageService.eventuallyConsistentMapBuilder();
Charles Chan77277672015-10-20 16:24:19 -0700276 subnetNextObjStore = subnetNextObjMapBuilder
277 .withName("subnetnextobjectivestore")
Jonathan Hart54541d12016-04-12 15:39:44 -0700278 .withSerializer(createSerializer())
Charles Chan77277672015-10-20 16:24:19 -0700279 .withTimestampProvider((k, v) -> new WallClockTimestamp())
280 .build();
281
Saurav Das2d94d312015-11-24 23:21:05 -0800282 log.debug("Creating EC map subnetnextobjectivestore");
283 EventuallyConsistentMapBuilder<PortNextObjectiveStoreKey, Integer>
284 portNextObjMapBuilder = storageService.eventuallyConsistentMapBuilder();
285 portNextObjStore = portNextObjMapBuilder
286 .withName("portnextobjectivestore")
Jonathan Hart54541d12016-04-12 15:39:44 -0700287 .withSerializer(createSerializer())
Saurav Das2d94d312015-11-24 23:21:05 -0800288 .withTimestampProvider((k, v) -> new WallClockTimestamp())
289 .build();
290
sangho4a5c42a2015-05-20 22:16:38 -0700291 EventuallyConsistentMapBuilder<String, Tunnel> tunnelMapBuilder =
292 storageService.eventuallyConsistentMapBuilder();
sangho4a5c42a2015-05-20 22:16:38 -0700293 tunnelStore = tunnelMapBuilder
294 .withName("tunnelstore")
Jonathan Hart54541d12016-04-12 15:39:44 -0700295 .withSerializer(createSerializer())
Madan Jampani675ae202015-06-24 19:05:56 -0700296 .withTimestampProvider((k, v) -> new WallClockTimestamp())
sangho4a5c42a2015-05-20 22:16:38 -0700297 .build();
298
299 EventuallyConsistentMapBuilder<String, Policy> policyMapBuilder =
300 storageService.eventuallyConsistentMapBuilder();
sangho4a5c42a2015-05-20 22:16:38 -0700301 policyStore = policyMapBuilder
302 .withName("policystore")
Jonathan Hart54541d12016-04-12 15:39:44 -0700303 .withSerializer(createSerializer())
Madan Jampani675ae202015-06-24 19:05:56 -0700304 .withTimestampProvider((k, v) -> new WallClockTimestamp())
sangho4a5c42a2015-05-20 22:16:38 -0700305 .build();
306
Saurav Das7c305372015-10-28 12:39:42 -0700307 EventuallyConsistentMapBuilder<SubnetAssignedVidStoreKey, VlanId>
308 subnetVidStoreMapBuilder = storageService.eventuallyConsistentMapBuilder();
Saurav Das7c305372015-10-28 12:39:42 -0700309 subnetVidStore = subnetVidStoreMapBuilder
310 .withName("subnetvidstore")
Jonathan Hart54541d12016-04-12 15:39:44 -0700311 .withSerializer(createSerializer())
Saurav Das7c305372015-10-28 12:39:42 -0700312 .withTimestampProvider((k, v) -> new WallClockTimestamp())
313 .build();
314
Saurav Dasc3604f12016-03-23 11:22:49 -0700315 compCfgService.preSetProperty("org.onosproject.net.group.impl.GroupManager",
316 "purgeOnDisconnection", "true");
317 compCfgService.preSetProperty("org.onosproject.net.flow.impl.FlowRuleManager",
318 "purgeOnDisconnection", "true");
319
Charles Chan2b078ae2015-10-14 11:24:40 -0700320 processor = new InternalPacketProcessor();
321 linkListener = new InternalLinkListener();
322 deviceListener = new InternalDeviceListener();
Charles Chan82f19972016-05-17 13:13:55 -0700323 appCfgHandler = new AppConfigHandler(this);
324 xConnectHandler = new XConnectHandler(this);
Charles Chan1eaf4802016-04-18 13:44:03 -0700325 mcastHandler = new McastHandler(this);
326 hostHandler = new HostHandler(this);
Charles Chan2b078ae2015-10-14 11:24:40 -0700327
Charles Chand6d25332016-02-26 22:19:52 -0800328 cfgService.addListener(cfgListener);
Charles Chanc91c8782016-03-30 17:54:24 -0700329 cfgService.registerConfigFactory(deviceConfigFactory);
330 cfgService.registerConfigFactory(appConfigFactory);
Charles Chan82f19972016-05-17 13:13:55 -0700331 cfgService.registerConfigFactory(xConnectConfigFactory);
Charles Chanc91c8782016-03-30 17:54:24 -0700332 cfgService.registerConfigFactory(mcastConfigFactory);
Charles Chan82ab1932016-01-30 23:22:37 -0800333 hostService.addListener(hostListener);
Charles Chan2b078ae2015-10-14 11:24:40 -0700334 packetService.addProcessor(processor, PacketProcessor.director(2));
335 linkService.addListener(linkListener);
336 deviceService.addListener(deviceListener);
Charles Chanc91c8782016-03-30 17:54:24 -0700337 multicastRouteService.addListener(mcastListener);
Charles Chan2b078ae2015-10-14 11:24:40 -0700338
Charles Chande6655c2015-12-23 00:15:11 -0800339 // Request ARP packet-in
340 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
341 selector.matchEthType(Ethernet.TYPE_ARP);
342 packetService.requestPackets(selector.build(), PacketPriority.CONTROL, appId, Optional.empty());
343
Charles Chan2b078ae2015-10-14 11:24:40 -0700344 cfgListener.configureNetwork();
345
sangho80f11cb2015-04-01 13:05:26 -0700346 log.info("Started");
347 }
348
Jonathan Hart54541d12016-04-12 15:39:44 -0700349 private KryoNamespace.Builder createSerializer() {
350 return new KryoNamespace.Builder()
351 .register(KryoNamespaces.API)
352 .register(NeighborSetNextObjectiveStoreKey.class,
353 SubnetNextObjectiveStoreKey.class,
354 SubnetAssignedVidStoreKey.class,
355 NeighborSet.class,
356 Tunnel.class,
357 DefaultTunnel.class,
358 Policy.class,
359 TunnelPolicy.class,
360 Policy.Type.class,
361 PortNextObjectiveStoreKey.class,
Charles Chan82f19972016-05-17 13:13:55 -0700362 XConnectStoreKey.class
Jonathan Hart54541d12016-04-12 15:39:44 -0700363 );
364 }
365
sangho80f11cb2015-04-01 13:05:26 -0700366 @Deactivate
367 protected void deactivate() {
Charles Chan72f556a2015-10-05 17:50:33 -0700368 cfgService.removeListener(cfgListener);
Charles Chanc91c8782016-03-30 17:54:24 -0700369 cfgService.unregisterConfigFactory(deviceConfigFactory);
370 cfgService.unregisterConfigFactory(appConfigFactory);
371 cfgService.unregisterConfigFactory(mcastConfigFactory);
Charles Chan72f556a2015-10-05 17:50:33 -0700372
Charles Chande6655c2015-12-23 00:15:11 -0800373 // Withdraw ARP packet-in
374 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
375 selector.matchEthType(Ethernet.TYPE_ARP);
376 packetService.cancelPackets(selector.build(), PacketPriority.CONTROL, appId, Optional.empty());
377
sangho80f11cb2015-04-01 13:05:26 -0700378 packetService.removeProcessor(processor);
Charles Chan2b078ae2015-10-14 11:24:40 -0700379 linkService.removeListener(linkListener);
380 deviceService.removeListener(deviceListener);
Charles Chanc91c8782016-03-30 17:54:24 -0700381 multicastRouteService.removeListener(mcastListener);
382
sangho80f11cb2015-04-01 13:05:26 -0700383 processor = null;
Charles Chan2b078ae2015-10-14 11:24:40 -0700384 linkListener = null;
Charles Chanc91c8782016-03-30 17:54:24 -0700385 deviceListener = null;
Charles Chan2b078ae2015-10-14 11:24:40 -0700386 groupHandlerMap.clear();
387
Charles Chanc91c8782016-03-30 17:54:24 -0700388 nsNextObjStore.destroy();
389 subnetNextObjStore.destroy();
390 portNextObjStore.destroy();
Charles Chanc91c8782016-03-30 17:54:24 -0700391 tunnelStore.destroy();
392 policyStore.destroy();
393 subnetVidStore.destroy();
sangho80f11cb2015-04-01 13:05:26 -0700394 log.info("Stopped");
395 }
396
sangho27462c62015-05-14 00:39:53 -0700397
398 @Override
399 public List<Tunnel> getTunnels() {
400 return tunnelHandler.getTunnels();
401 }
402
403 @Override
sanghobd812f82015-06-29 14:58:47 -0700404 public TunnelHandler.Result createTunnel(Tunnel tunnel) {
405 return tunnelHandler.createTunnel(tunnel);
sangho27462c62015-05-14 00:39:53 -0700406 }
407
408 @Override
sanghobd812f82015-06-29 14:58:47 -0700409 public TunnelHandler.Result removeTunnel(Tunnel tunnel) {
sangho27462c62015-05-14 00:39:53 -0700410 for (Policy policy: policyHandler.getPolicies()) {
411 if (policy.type() == Policy.Type.TUNNEL_FLOW) {
412 TunnelPolicy tunnelPolicy = (TunnelPolicy) policy;
413 if (tunnelPolicy.tunnelId().equals(tunnel.id())) {
414 log.warn("Cannot remove the tunnel used by a policy");
sanghobd812f82015-06-29 14:58:47 -0700415 return TunnelHandler.Result.TUNNEL_IN_USE;
sangho27462c62015-05-14 00:39:53 -0700416 }
417 }
418 }
sanghobd812f82015-06-29 14:58:47 -0700419 return tunnelHandler.removeTunnel(tunnel);
sangho27462c62015-05-14 00:39:53 -0700420 }
421
422 @Override
sanghobd812f82015-06-29 14:58:47 -0700423 public PolicyHandler.Result removePolicy(Policy policy) {
424 return policyHandler.removePolicy(policy);
sangho27462c62015-05-14 00:39:53 -0700425 }
426
427 @Override
sanghobd812f82015-06-29 14:58:47 -0700428 public PolicyHandler.Result createPolicy(Policy policy) {
429 return policyHandler.createPolicy(policy);
sangho27462c62015-05-14 00:39:53 -0700430 }
431
432 @Override
433 public List<Policy> getPolicies() {
434 return policyHandler.getPolicies();
435 }
436
Saurav Das07c74602016-04-27 18:35:50 -0700437 @Override
438 public void rerouteNetwork() {
439 cfgListener.configureNetwork();
440 for (Device device : deviceService.getDevices()) {
441 defaultRoutingHandler.populatePortAddressingRules(device.id());
442 }
443 defaultRoutingHandler.startPopulationProcess();
444 }
445
sangho80f1f892015-05-19 11:57:42 -0700446 /**
447 * Returns the tunnel object with the tunnel ID.
448 *
449 * @param tunnelId Tunnel ID
450 * @return Tunnel reference
451 */
sangho27462c62015-05-14 00:39:53 -0700452 public Tunnel getTunnel(String tunnelId) {
453 return tunnelHandler.getTunnel(tunnelId);
454 }
455
sangho80f11cb2015-04-01 13:05:26 -0700456 /**
Saurav Das7c305372015-10-28 12:39:42 -0700457 * Returns the vlan-id assigned to the subnet configured for a device.
458 * If no vlan-id has been assigned, a new one is assigned out of a pool of ids,
459 * if and only if this controller instance is the master for the device.
460 * <p>
461 * USAGE: The assigned vlans are meant to be applied to untagged packets on those
462 * switches/pipelines that need this functionality. These vids are meant
463 * to be used internally within a switch, and thus need to be unique only
464 * on a switch level. Note that packets never go out on the wire with these
465 * vlans. Currently, vlan ids are assigned from value 4093 down.
466 * Vlan id 4094 expected to be used for all ports that are not assigned subnets.
467 * Vlan id 4095 is reserved and unused. Only a single vlan id is assigned
468 * per subnet.
sangho80f11cb2015-04-01 13:05:26 -0700469 *
Saurav Das7c305372015-10-28 12:39:42 -0700470 * @param deviceId switch dpid
471 * @param subnet IPv4 prefix for which assigned vlan is desired
472 * @return VlanId assigned for the subnet on the device, or
473 * null if no vlan assignment was found and this instance is not
474 * the master for the device.
sangho80f11cb2015-04-01 13:05:26 -0700475 */
Charles Chanb7f75ac2016-01-11 18:28:54 -0800476 // TODO: We should avoid assigning VLAN IDs that are used by VLAN cross-connection.
Saurav Das7c305372015-10-28 12:39:42 -0700477 public VlanId getSubnetAssignedVlanId(DeviceId deviceId, Ip4Prefix subnet) {
478 VlanId assignedVid = subnetVidStore.get(new SubnetAssignedVidStoreKey(
479 deviceId, subnet));
480 if (assignedVid != null) {
481 log.debug("Query for subnet:{} on device:{} returned assigned-vlan "
482 + "{}", subnet, deviceId, assignedVid);
483 return assignedVid;
484 }
485 //check mastership for the right to assign a vlan
486 if (!mastershipService.isLocalMaster(deviceId)) {
487 log.warn("This controller instance is not the master for device {}. "
488 + "Cannot assign vlan-id for subnet {}", deviceId, subnet);
489 return null;
490 }
491 // vlan assignment is expensive but done only once
Charles Chanc6ad7752015-10-29 14:58:10 -0700492 Set<Ip4Prefix> configuredSubnets = deviceConfiguration.getSubnets(deviceId);
Saurav Das7c305372015-10-28 12:39:42 -0700493 Set<Short> assignedVlans = new HashSet<>();
494 Set<Ip4Prefix> unassignedSubnets = new HashSet<>();
495 for (Ip4Prefix sub : configuredSubnets) {
496 VlanId v = subnetVidStore.get(new SubnetAssignedVidStoreKey(deviceId,
497 sub));
498 if (v != null) {
499 assignedVlans.add(v.toShort());
500 } else {
501 unassignedSubnets.add(sub);
502 }
503 }
504 short nextAssignedVlan = ASSIGNED_VLAN_START;
505 if (!assignedVlans.isEmpty()) {
506 nextAssignedVlan = (short) (Collections.min(assignedVlans) - 1);
507 }
508 for (Ip4Prefix unsub : unassignedSubnets) {
Charles Chan82ab1932016-01-30 23:22:37 -0800509 // Special case for default route. Assign default VLAN ID to /32 and /0 subnets
510 if (unsub.prefixLength() == IpPrefix.MAX_INET_MASK_LENGTH ||
511 unsub.prefixLength() == 0) {
512 subnetVidStore.put(new SubnetAssignedVidStoreKey(deviceId, unsub),
513 VlanId.vlanId(ASSIGNED_VLAN_NO_SUBNET));
514 } else {
515 subnetVidStore.put(new SubnetAssignedVidStoreKey(deviceId, unsub),
516 VlanId.vlanId(nextAssignedVlan--));
517 log.info("Assigned vlan: {} to subnet: {} on device: {}",
518 nextAssignedVlan + 1, unsub, deviceId);
519 }
sangho80f11cb2015-04-01 13:05:26 -0700520 }
521
Saurav Das7c305372015-10-28 12:39:42 -0700522 return subnetVidStore.get(new SubnetAssignedVidStoreKey(deviceId, subnet));
sangho80f11cb2015-04-01 13:05:26 -0700523 }
524
sangho27462c62015-05-14 00:39:53 -0700525 /**
Saurav Das7c305372015-10-28 12:39:42 -0700526 * Returns the next objective ID for the given NeighborSet.
Saurav Das4c35fc42015-11-20 15:27:53 -0800527 * If the nextObjective does not exist, a new one is created and
Saurav Das2d94d312015-11-24 23:21:05 -0800528 * its id is returned.
sangho27462c62015-05-14 00:39:53 -0700529 *
sangho80f1f892015-05-19 11:57:42 -0700530 * @param deviceId Device ID
531 * @param ns NegighborSet
Saurav Das4c35fc42015-11-20 15:27:53 -0800532 * @param meta metadata passed into the creation of a Next Objective
533 * @return next objective ID or -1 if an error was encountered during the
534 * creation of the nextObjective
sangho27462c62015-05-14 00:39:53 -0700535 */
Saurav Das4c35fc42015-11-20 15:27:53 -0800536 public int getNextObjectiveId(DeviceId deviceId, NeighborSet ns,
537 TrafficSelector meta) {
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700538 if (groupHandlerMap.get(deviceId) != null) {
539 log.trace("getNextObjectiveId query in device {}", deviceId);
540 return groupHandlerMap
Saurav Das4c35fc42015-11-20 15:27:53 -0800541 .get(deviceId).getNextObjectiveId(ns, meta);
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700542 } else {
Saurav Das2d94d312015-11-24 23:21:05 -0800543 log.warn("getNextObjectiveId query - groupHandler for device {} "
544 + "not found", deviceId);
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700545 return -1;
546 }
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700547 }
548
Charles Chan77277672015-10-20 16:24:19 -0700549 /**
Saurav Das2d94d312015-11-24 23:21:05 -0800550 * Returns the next objective ID for the given subnet prefix. It is expected
551 * that the next-objective has been pre-created from configuration.
Charles Chan77277672015-10-20 16:24:19 -0700552 *
553 * @param deviceId Device ID
554 * @param prefix Subnet
Saurav Das2d94d312015-11-24 23:21:05 -0800555 * @return next objective ID or -1 if it was not found
Charles Chan77277672015-10-20 16:24:19 -0700556 */
557 public int getSubnetNextObjectiveId(DeviceId deviceId, IpPrefix prefix) {
558 if (groupHandlerMap.get(deviceId) != null) {
559 log.trace("getSubnetNextObjectiveId query in device {}", deviceId);
560 return groupHandlerMap
561 .get(deviceId).getSubnetNextObjectiveId(prefix);
562 } else {
Saurav Das2d94d312015-11-24 23:21:05 -0800563 log.warn("getSubnetNextObjectiveId query - groupHandler for "
564 + "device {} not found", deviceId);
565 return -1;
566 }
567 }
568
569 /**
570 * Returns the next objective ID for the given portNumber, given the treatment.
571 * There could be multiple different treatments to the same outport, which
572 * would result in different objectives. If the next object
573 * does not exist, a new one is created and its id is returned.
574 *
575 * @param deviceId Device ID
576 * @param portNum port number on device for which NextObjective is queried
577 * @param treatment the actions to apply on the packets (should include outport)
578 * @param meta metadata passed into the creation of a Next Objective if necessary
Saurav Das07c74602016-04-27 18:35:50 -0700579 * @return next objective ID or -1 if an error occurred during retrieval or creation
Saurav Das2d94d312015-11-24 23:21:05 -0800580 */
581 public int getPortNextObjectiveId(DeviceId deviceId, PortNumber portNum,
582 TrafficTreatment treatment,
583 TrafficSelector meta) {
584 DefaultGroupHandler ghdlr = groupHandlerMap.get(deviceId);
585 if (ghdlr != null) {
586 return ghdlr.getPortNextObjectiveId(portNum, treatment, meta);
587 } else {
Charles Chanb7f75ac2016-01-11 18:28:54 -0800588 log.warn("getPortNextObjectiveId query - groupHandler for device {}"
589 + " not found", deviceId);
590 return -1;
591 }
592 }
593
sangho80f11cb2015-04-01 13:05:26 -0700594 private class InternalPacketProcessor implements PacketProcessor {
sangho80f11cb2015-04-01 13:05:26 -0700595 @Override
596 public void process(PacketContext context) {
597
598 if (context.isHandled()) {
599 return;
600 }
601
602 InboundPacket pkt = context.inPacket();
603 Ethernet ethernet = pkt.parsed();
Saurav Das2d94d312015-11-24 23:21:05 -0800604 log.trace("Rcvd pktin: {}", ethernet);
sangho80f11cb2015-04-01 13:05:26 -0700605 if (ethernet.getEtherType() == Ethernet.TYPE_ARP) {
606 arpHandler.processPacketIn(pkt);
607 } else if (ethernet.getEtherType() == Ethernet.TYPE_IPV4) {
608 IPv4 ipPacket = (IPv4) ethernet.getPayload();
609 ipHandler.addToPacketBuffer(ipPacket);
610 if (ipPacket.getProtocol() == IPv4.PROTOCOL_ICMP) {
611 icmpHandler.processPacketIn(pkt);
612 } else {
613 ipHandler.processPacketIn(pkt);
614 }
615 }
616 }
617 }
618
619 private class InternalLinkListener implements LinkListener {
620 @Override
621 public void event(LinkEvent event) {
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700622 if (event.type() == LinkEvent.Type.LINK_ADDED
623 || event.type() == LinkEvent.Type.LINK_REMOVED) {
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700624 log.debug("Event {} received from Link Service", event.type());
sangho80f11cb2015-04-01 13:05:26 -0700625 scheduleEventHandlerIfNotScheduled(event);
626 }
627 }
628 }
629
630 private class InternalDeviceListener implements DeviceListener {
sangho80f11cb2015-04-01 13:05:26 -0700631 @Override
632 public void event(DeviceEvent event) {
sangho80f11cb2015-04-01 13:05:26 -0700633 switch (event.type()) {
634 case DEVICE_ADDED:
635 case PORT_REMOVED:
sanghofb7c7292015-04-13 15:15:58 -0700636 case DEVICE_UPDATED:
637 case DEVICE_AVAILABILITY_CHANGED:
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700638 log.debug("Event {} received from Device Service", event.type());
sangho80f11cb2015-04-01 13:05:26 -0700639 scheduleEventHandlerIfNotScheduled(event);
640 break;
641 default:
642 }
643 }
644 }
645
Saurav Das2d94d312015-11-24 23:21:05 -0800646 @SuppressWarnings("rawtypes")
sangho80f11cb2015-04-01 13:05:26 -0700647 private void scheduleEventHandlerIfNotScheduled(Event event) {
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700648 synchronized (threadSchedulerLock) {
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700649 eventQueue.add(event);
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700650 numOfEventsQueued++;
651
652 if ((numOfHandlerScheduled - numOfHandlerExecution) == 0) {
653 //No pending scheduled event handling threads. So start a new one.
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700654 eventHandlerFuture = executorService
655 .schedule(eventHandler, 100, TimeUnit.MILLISECONDS);
656 numOfHandlerScheduled++;
657 }
Jonathan Hart54541d12016-04-12 15:39:44 -0700658 log.trace("numOfEventsQueued {}, numOfEventHandlerScheduled {}",
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700659 numOfEventsQueued,
660 numOfHandlerScheduled);
sangho80f11cb2015-04-01 13:05:26 -0700661 }
sangho80f11cb2015-04-01 13:05:26 -0700662 }
663
664 private class InternalEventHandler implements Runnable {
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700665 @Override
sangho80f11cb2015-04-01 13:05:26 -0700666 public void run() {
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700667 try {
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700668 while (true) {
Saurav Das2d94d312015-11-24 23:21:05 -0800669 @SuppressWarnings("rawtypes")
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700670 Event event = null;
671 synchronized (threadSchedulerLock) {
672 if (!eventQueue.isEmpty()) {
673 event = eventQueue.poll();
674 numOfEventsExecuted++;
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700675 } else {
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700676 numOfHandlerExecution++;
677 log.debug("numOfHandlerExecution {} numOfEventsExecuted {}",
678 numOfHandlerExecution, numOfEventsExecuted);
679 break;
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700680 }
sanghofb7c7292015-04-13 15:15:58 -0700681 }
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700682 if (event.type() == LinkEvent.Type.LINK_ADDED) {
683 processLinkAdded((Link) event.subject());
684 } else if (event.type() == LinkEvent.Type.LINK_REMOVED) {
685 processLinkRemoved((Link) event.subject());
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700686 } else if (event.type() == DeviceEvent.Type.DEVICE_ADDED ||
687 event.type() == DeviceEvent.Type.DEVICE_AVAILABILITY_CHANGED ||
688 event.type() == DeviceEvent.Type.DEVICE_UPDATED) {
Saurav Das62af8802015-12-04 10:52:59 -0800689 DeviceId deviceId = ((Device) event.subject()).id();
690 if (deviceService.isAvailable(deviceId)) {
Saurav Dasc28b3432015-10-30 17:45:38 -0700691 log.info("Processing device event {} for available device {}",
692 event.type(), ((Device) event.subject()).id());
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700693 processDeviceAdded((Device) event.subject());
Saurav Dasc3604f12016-03-23 11:22:49 -0700694 } else {
695 log.info("Processing device event {} for unavailable device {}",
696 event.type(), ((Device) event.subject()).id());
697 processDeviceRemoved((Device) event.subject());
698 }
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700699 } else if (event.type() == DeviceEvent.Type.PORT_REMOVED) {
700 processPortRemoved((Device) event.subject(),
701 ((DeviceEvent) event).port());
Saurav Dasb149be12016-06-07 10:08:06 -0700702 } else if (event.type() == DeviceEvent.Type.PORT_ADDED ||
703 event.type() == DeviceEvent.Type.PORT_UPDATED) {
704 log.info("** PORT ADDED OR UPDATED {}/{} -> {}",
705 (Device) event.subject(),
706 ((DeviceEvent) event).port(),
707 event.type());
708 /* XXX create method for single port filtering rules
709 if (defaultRoutingHandler != null) {
710 defaultRoutingHandler.populatePortAddressingRules(
711 ((Device) event.subject()).id());
712 }*/
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700713 } else {
714 log.warn("Unhandled event type: {}", event.type());
715 }
sangho80f11cb2015-04-01 13:05:26 -0700716 }
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700717 } catch (Exception e) {
718 log.error("SegmentRouting event handler "
719 + "thread thrown an exception: {}", e);
sangho80f11cb2015-04-01 13:05:26 -0700720 }
sangho80f11cb2015-04-01 13:05:26 -0700721 }
722 }
723
sangho80f11cb2015-04-01 13:05:26 -0700724 private void processLinkAdded(Link link) {
Saurav Dasb149be12016-06-07 10:08:06 -0700725 log.info("** LINK ADDED {}", link.toString());
Charles Chan319d1a22015-11-03 10:42:14 -0800726 if (!deviceConfiguration.isConfigured(link.src().deviceId())) {
727 log.warn("Source device of this link is not configured.");
728 return;
729 }
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700730 //Irrespective whether the local is a MASTER or not for this device,
731 //create group handler instance and push default TTP flow rules.
732 //Because in a multi-instance setup, instances can initiate
733 //groups for any devices. Also the default TTP rules are needed
734 //to be pushed before inserting any IP table entries for any device
735 DefaultGroupHandler groupHandler = groupHandlerMap.get(link.src()
736 .deviceId());
737 if (groupHandler != null) {
Saurav Das4c35fc42015-11-20 15:27:53 -0800738 groupHandler.linkUp(link, mastershipService.isLocalMaster(
739 link.src().deviceId()));
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700740 } else {
741 Device device = deviceService.getDevice(link.src().deviceId());
742 if (device != null) {
743 log.warn("processLinkAdded: Link Added "
744 + "Notification without Device Added "
745 + "event, still handling it");
746 processDeviceAdded(device);
747 groupHandler = groupHandlerMap.get(link.src()
748 .deviceId());
Saurav Das4c35fc42015-11-20 15:27:53 -0800749 groupHandler.linkUp(link, mastershipService.isLocalMaster(device.id()));
sangho80f11cb2015-04-01 13:05:26 -0700750 }
751 }
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700752
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700753 log.trace("Starting optimized route population process");
754 defaultRoutingHandler.populateRoutingRulesForLinkStatusChange(null);
755 //log.trace("processLinkAdded: re-starting route population process");
756 //defaultRoutingHandler.startPopulationProcess();
Charles Chan72779502016-04-23 17:36:10 -0700757
758 mcastHandler.init();
sangho80f11cb2015-04-01 13:05:26 -0700759 }
760
761 private void processLinkRemoved(Link link) {
Saurav Dasb149be12016-06-07 10:08:06 -0700762 log.info("** LINK REMOVED {}", link.toString());
sangho2165d222015-05-01 09:38:25 -0700763 DefaultGroupHandler groupHandler = groupHandlerMap.get(link.src().deviceId());
764 if (groupHandler != null) {
Saurav Das62af8802015-12-04 10:52:59 -0800765 groupHandler.portDown(link.src().port(),
766 mastershipService.isLocalMaster(link.src().deviceId()));
sangho2165d222015-05-01 09:38:25 -0700767 }
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700768 log.trace("Starting optimized route population process");
769 defaultRoutingHandler.populateRoutingRulesForLinkStatusChange(link);
770 //log.trace("processLinkRemoved: re-starting route population process");
771 //defaultRoutingHandler.startPopulationProcess();
Charles Chan72779502016-04-23 17:36:10 -0700772
773 mcastHandler.processLinkDown(link);
sangho80f11cb2015-04-01 13:05:26 -0700774 }
775
776 private void processDeviceAdded(Device device) {
Saurav Dasb149be12016-06-07 10:08:06 -0700777 log.info("** DEVICE ADDED with ID {}", device.id());
Charles Chan319d1a22015-11-03 10:42:14 -0800778 if (deviceConfiguration == null || !deviceConfiguration.isConfigured(device.id())) {
Saurav Das8ec0ec42015-11-03 14:39:27 -0800779 log.warn("Device configuration uploading. Device {} will be "
780 + "processed after config completes.", device.id());
781 return;
782 }
Charles Chan72779502016-04-23 17:36:10 -0700783 processDeviceAddedInternal(device.id());
784 }
785
786 private void processDeviceAddedInternal(DeviceId deviceId) {
Saurav Dasc28b3432015-10-30 17:45:38 -0700787 // Irrespective of whether the local is a MASTER or not for this device,
788 // we need to create a SR-group-handler instance. This is because in a
789 // multi-instance setup, any instance can initiate forwarding/next-objectives
790 // for any switch (even if this instance is a SLAVE or not even connected
791 // to the switch). To handle this, a default-group-handler instance is necessary
792 // per switch.
Charles Chan72779502016-04-23 17:36:10 -0700793 log.debug("Current groupHandlerMap devs: {}", groupHandlerMap.keySet());
794 if (groupHandlerMap.get(deviceId) == null) {
Charles Chan319d1a22015-11-03 10:42:14 -0800795 DefaultGroupHandler groupHandler;
796 try {
797 groupHandler = DefaultGroupHandler.
Charles Chan72779502016-04-23 17:36:10 -0700798 createGroupHandler(deviceId,
799 appId,
800 deviceConfiguration,
801 linkService,
802 flowObjectiveService,
803 this);
Charles Chan319d1a22015-11-03 10:42:14 -0800804 } catch (DeviceConfigNotFoundException e) {
805 log.warn(e.getMessage() + " Aborting processDeviceAdded.");
806 return;
807 }
Charles Chan72779502016-04-23 17:36:10 -0700808 log.debug("updating groupHandlerMap with new config for device: {}",
809 deviceId);
810 groupHandlerMap.put(deviceId, groupHandler);
Saurav Das8ec0ec42015-11-03 14:39:27 -0800811 }
Saurav Dasb149be12016-06-07 10:08:06 -0700812 // Also, in some cases, drivers may need extra
813 // information to process rules (eg. Router IP/MAC); and so, we send
814 // port addressing rules to the driver as well irrespective of whether
815 // this instance is the master or not.
816 defaultRoutingHandler.populatePortAddressingRules(deviceId);
817
Charles Chan72779502016-04-23 17:36:10 -0700818 if (mastershipService.isLocalMaster(deviceId)) {
819 hostHandler.readInitialHosts(deviceId);
Charles Chan82f19972016-05-17 13:13:55 -0700820 xConnectHandler.init(deviceId);
Charles Chan72779502016-04-23 17:36:10 -0700821 DefaultGroupHandler groupHandler = groupHandlerMap.get(deviceId);
Charles Chan77277672015-10-20 16:24:19 -0700822 groupHandler.createGroupsFromSubnetConfig();
Charles Chan72779502016-04-23 17:36:10 -0700823 routingRulePopulator.populateSubnetBroadcastRule(deviceId);
Charles Chan77277672015-10-20 16:24:19 -0700824 }
Charles Chan82ab1932016-01-30 23:22:37 -0800825
Charles Chan82f19972016-05-17 13:13:55 -0700826 appCfgHandler.initVRouters(deviceId);
sangho80f11cb2015-04-01 13:05:26 -0700827 }
828
Saurav Dasc3604f12016-03-23 11:22:49 -0700829 private void processDeviceRemoved(Device device) {
830 nsNextObjStore.entrySet().stream()
831 .filter(entry -> entry.getKey().deviceId().equals(device.id()))
832 .forEach(entry -> {
833 nsNextObjStore.remove(entry.getKey());
834 });
Saurav Dasc3604f12016-03-23 11:22:49 -0700835 subnetNextObjStore.entrySet().stream()
836 .filter(entry -> entry.getKey().deviceId().equals(device.id()))
837 .forEach(entry -> {
838 subnetNextObjStore.remove(entry.getKey());
839 });
Saurav Dasc3604f12016-03-23 11:22:49 -0700840 portNextObjStore.entrySet().stream()
841 .filter(entry -> entry.getKey().deviceId().equals(device.id()))
842 .forEach(entry -> {
843 portNextObjStore.remove(entry.getKey());
844 });
Saurav Dasc3604f12016-03-23 11:22:49 -0700845 subnetVidStore.entrySet().stream()
846 .filter(entry -> entry.getKey().deviceId().equals(device.id()))
847 .forEach(entry -> {
848 subnetVidStore.remove(entry.getKey());
849 });
Saurav Dasc3604f12016-03-23 11:22:49 -0700850 groupHandlerMap.remove(device.id());
Saurav Dasc3604f12016-03-23 11:22:49 -0700851 defaultRoutingHandler.purgeEcmpGraph(device.id());
Charles Chan72779502016-04-23 17:36:10 -0700852 mcastHandler.removeDevice(device.id());
Charles Chan82f19972016-05-17 13:13:55 -0700853 xConnectHandler.removeDevice(device.id());
Saurav Dasc3604f12016-03-23 11:22:49 -0700854 }
855
sangho80f11cb2015-04-01 13:05:26 -0700856 private void processPortRemoved(Device device, Port port) {
Saurav Dasb149be12016-06-07 10:08:06 -0700857 log.info("Port {} was removed", port.toString());
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700858 DefaultGroupHandler groupHandler = groupHandlerMap.get(device.id());
sangho80f11cb2015-04-01 13:05:26 -0700859 if (groupHandler != null) {
Saurav Das62af8802015-12-04 10:52:59 -0800860 groupHandler.portDown(port.number(),
861 mastershipService.isLocalMaster(device.id()));
sangho80f11cb2015-04-01 13:05:26 -0700862 }
863 }
sangho27462c62015-05-14 00:39:53 -0700864
Charles Chan72f556a2015-10-05 17:50:33 -0700865 private class InternalConfigListener implements NetworkConfigListener {
Charles Chane7c61022015-10-07 14:21:45 -0700866 SegmentRoutingManager segmentRoutingManager;
867
Charles Chanb7f75ac2016-01-11 18:28:54 -0800868 /**
869 * Constructs the internal network config listener.
870 *
871 * @param srMgr segment routing manager
872 */
Charles Chane7c61022015-10-07 14:21:45 -0700873 public InternalConfigListener(SegmentRoutingManager srMgr) {
874 this.segmentRoutingManager = srMgr;
875 }
876
Charles Chanb7f75ac2016-01-11 18:28:54 -0800877 /**
878 * Reads network config and initializes related data structure accordingly.
879 */
Charles Chane7c61022015-10-07 14:21:45 -0700880 public void configureNetwork() {
Charles Chan43547ca2016-02-10 20:46:58 -0800881 deviceConfiguration = new DeviceConfiguration(appId,
882 segmentRoutingManager.cfgService);
Charles Chane7c61022015-10-07 14:21:45 -0700883
884 arpHandler = new ArpHandler(segmentRoutingManager);
885 icmpHandler = new IcmpHandler(segmentRoutingManager);
886 ipHandler = new IpHandler(segmentRoutingManager);
887 routingRulePopulator = new RoutingRulePopulator(segmentRoutingManager);
888 defaultRoutingHandler = new DefaultRoutingHandler(segmentRoutingManager);
889
890 tunnelHandler = new TunnelHandler(linkService, deviceConfiguration,
891 groupHandlerMap, tunnelStore);
892 policyHandler = new PolicyHandler(appId, deviceConfiguration,
893 flowObjectiveService,
894 tunnelHandler, policyStore);
895
Charles Chane7c61022015-10-07 14:21:45 -0700896 for (Device device : deviceService.getDevices()) {
Charles Chan72779502016-04-23 17:36:10 -0700897 processDeviceAddedInternal(device.id());
Charles Chane7c61022015-10-07 14:21:45 -0700898 }
899
900 defaultRoutingHandler.startPopulationProcess();
Charles Chan72779502016-04-23 17:36:10 -0700901 mcastHandler.init();
Charles Chane7c61022015-10-07 14:21:45 -0700902 }
903
Charles Chan72f556a2015-10-05 17:50:33 -0700904 @Override
905 public void event(NetworkConfigEvent event) {
Charles Chan82ab1932016-01-30 23:22:37 -0800906 // TODO move this part to NetworkConfigEventHandler
907 if (event.configClass().equals(SegmentRoutingDeviceConfig.class)) {
908 switch (event.type()) {
909 case CONFIG_ADDED:
910 log.info("Segment Routing Config added.");
911 configureNetwork();
912 break;
913 case CONFIG_UPDATED:
914 log.info("Segment Routing Config updated.");
915 // TODO support dynamic configuration
916 break;
917 default:
918 break;
Charles Chan2b078ae2015-10-14 11:24:40 -0700919 }
Charles Chan82ab1932016-01-30 23:22:37 -0800920 } else if (event.configClass().equals(SegmentRoutingAppConfig.class)) {
Charles Chan82f19972016-05-17 13:13:55 -0700921 checkState(appCfgHandler != null, "NetworkConfigEventHandler is not initialized");
Charles Chan82ab1932016-01-30 23:22:37 -0800922 switch (event.type()) {
923 case CONFIG_ADDED:
Charles Chan82f19972016-05-17 13:13:55 -0700924 appCfgHandler.processAppConfigAdded(event);
Charles Chan82ab1932016-01-30 23:22:37 -0800925 break;
926 case CONFIG_UPDATED:
Charles Chan82f19972016-05-17 13:13:55 -0700927 appCfgHandler.processAppConfigUpdated(event);
Charles Chan82ab1932016-01-30 23:22:37 -0800928 break;
929 case CONFIG_REMOVED:
Charles Chan82f19972016-05-17 13:13:55 -0700930 appCfgHandler.processAppConfigRemoved(event);
931 break;
932 default:
933 break;
934 }
935 } else if (event.configClass().equals(XConnectConfig.class)) {
936 checkState(xConnectHandler != null, "XConnectHandler is not initialized");
937 switch (event.type()) {
938 case CONFIG_ADDED:
939 xConnectHandler.processXConnectConfigAdded(event);
940 break;
941 case CONFIG_UPDATED:
942 xConnectHandler.processXConnectConfigUpdated(event);
943 break;
944 case CONFIG_REMOVED:
945 xConnectHandler.processXConnectConfigRemoved(event);
Charles Chan82ab1932016-01-30 23:22:37 -0800946 break;
947 default:
948 break;
Charles Chan2b078ae2015-10-14 11:24:40 -0700949 }
Charles Chan72f556a2015-10-05 17:50:33 -0700950 }
951 }
952 }
Charles Chanf4586112015-11-09 16:37:23 -0800953
954 private class InternalHostListener implements HostListener {
Charles Chanf4586112015-11-09 16:37:23 -0800955 @Override
956 public void event(HostEvent event) {
957 // Do not proceed without mastership
958 DeviceId deviceId = event.subject().location().deviceId();
959 if (!mastershipService.isLocalMaster(deviceId)) {
960 return;
961 }
962
963 switch (event.type()) {
964 case HOST_ADDED:
Charles Chan1eaf4802016-04-18 13:44:03 -0700965 hostHandler.processHostAddedEvent(event);
Charles Chanf4586112015-11-09 16:37:23 -0800966 break;
967 case HOST_MOVED:
Charles Chan1eaf4802016-04-18 13:44:03 -0700968 hostHandler.processHostMovedEvent(event);
Charles Chanf4586112015-11-09 16:37:23 -0800969 break;
970 case HOST_REMOVED:
Charles Chan1eaf4802016-04-18 13:44:03 -0700971 hostHandler.processHostRemoveEvent(event);
Charles Chanf4586112015-11-09 16:37:23 -0800972 break;
973 case HOST_UPDATED:
Charles Chan1eaf4802016-04-18 13:44:03 -0700974 hostHandler.processHostUpdatedEvent(event);
Charles Chanf4586112015-11-09 16:37:23 -0800975 break;
976 default:
977 log.warn("Unsupported host event type: {}", event.type());
978 break;
979 }
980 }
981 }
982
Charles Chanc91c8782016-03-30 17:54:24 -0700983 private class InternalMcastListener implements McastListener {
984 @Override
985 public void event(McastEvent event) {
986 switch (event.type()) {
987 case SOURCE_ADDED:
Charles Chan1eaf4802016-04-18 13:44:03 -0700988 mcastHandler.processSourceAdded(event);
Charles Chanc91c8782016-03-30 17:54:24 -0700989 break;
990 case SINK_ADDED:
Charles Chan1eaf4802016-04-18 13:44:03 -0700991 mcastHandler.processSinkAdded(event);
Charles Chanc91c8782016-03-30 17:54:24 -0700992 break;
993 case SINK_REMOVED:
Charles Chan1eaf4802016-04-18 13:44:03 -0700994 mcastHandler.processSinkRemoved(event);
Charles Chanc91c8782016-03-30 17:54:24 -0700995 break;
996 case ROUTE_ADDED:
997 case ROUTE_REMOVED:
998 default:
999 break;
1000 }
1001 }
1002 }
sangho80f11cb2015-04-01 13:05:26 -07001003}