blob: 787f934731f49c4decd48ec70d35dca16c94cd0d [file] [log] [blame]
sangho80f11cb2015-04-01 13:05:26 -07001/*
2 * Copyright 2015 Open Networking Laboratory
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
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;
Saurav Das7c305372015-10-28 12:39:42 -070025import org.onlab.packet.VlanId;
Charles Chan77277672015-10-20 16:24:19 -070026import org.onlab.packet.IPv4;
27import org.onlab.packet.Ip4Address;
28import org.onlab.packet.Ip4Prefix;
29import org.onlab.packet.IpAddress;
30import org.onlab.packet.IpPrefix;
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -070031import org.onlab.util.KryoNamespace;
sangho80f11cb2015-04-01 13:05:26 -070032import org.onosproject.core.ApplicationId;
33import org.onosproject.core.CoreService;
34import org.onosproject.event.Event;
Charles Chan77277672015-10-20 16:24:19 -070035import org.onosproject.net.ConnectPoint;
Charles Chan72f556a2015-10-05 17:50:33 -070036import org.onosproject.net.config.ConfigFactory;
37import org.onosproject.net.config.NetworkConfigEvent;
38import org.onosproject.net.config.NetworkConfigRegistry;
39import org.onosproject.net.config.NetworkConfigListener;
40import org.onosproject.net.config.basics.SubjectFactories;
Charles Chan319d1a22015-11-03 10:42:14 -080041import org.onosproject.segmentrouting.config.DeviceConfigNotFoundException;
42import org.onosproject.segmentrouting.config.DeviceConfiguration;
Charles Chan72f556a2015-10-05 17:50:33 -070043import org.onosproject.segmentrouting.config.SegmentRoutingConfig;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070044import org.onosproject.segmentrouting.grouphandler.DefaultGroupHandler;
45import org.onosproject.segmentrouting.grouphandler.NeighborSet;
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -070046import org.onosproject.segmentrouting.grouphandler.NeighborSetNextObjectiveStoreKey;
sangho80f11cb2015-04-01 13:05:26 -070047import org.onosproject.mastership.MastershipService;
48import org.onosproject.net.Device;
49import org.onosproject.net.DeviceId;
50import org.onosproject.net.Link;
sangho80f11cb2015-04-01 13:05:26 -070051import org.onosproject.net.Port;
52import org.onosproject.net.device.DeviceEvent;
53import org.onosproject.net.device.DeviceListener;
54import org.onosproject.net.device.DeviceService;
Srikanth Vavilapalli64505482015-04-21 13:04:13 -070055import org.onosproject.net.flowobjective.FlowObjectiveService;
sangho80f11cb2015-04-01 13:05:26 -070056import org.onosproject.net.host.HostService;
57import org.onosproject.net.intent.IntentService;
58import org.onosproject.net.link.LinkEvent;
59import org.onosproject.net.link.LinkListener;
60import org.onosproject.net.link.LinkService;
61import org.onosproject.net.packet.InboundPacket;
62import org.onosproject.net.packet.PacketContext;
63import org.onosproject.net.packet.PacketProcessor;
64import org.onosproject.net.packet.PacketService;
65import org.onosproject.net.topology.TopologyService;
Charles Chan77277672015-10-20 16:24:19 -070066import org.onosproject.segmentrouting.grouphandler.SubnetNextObjectiveStoreKey;
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -070067import org.onosproject.store.service.EventuallyConsistentMap;
68import org.onosproject.store.service.EventuallyConsistentMapBuilder;
69import org.onosproject.store.service.StorageService;
70import org.onosproject.store.service.WallClockTimestamp;
sangho80f11cb2015-04-01 13:05:26 -070071import org.slf4j.Logger;
72import org.slf4j.LoggerFactory;
73
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -070074import java.net.URI;
Saurav Das7c305372015-10-28 12:39:42 -070075import java.util.Collections;
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -070076import java.util.HashSet;
sangho27462c62015-05-14 00:39:53 -070077import java.util.List;
sangho80f11cb2015-04-01 13:05:26 -070078import java.util.Map;
Saurav Das7c305372015-10-28 12:39:42 -070079import java.util.Set;
sangho80f11cb2015-04-01 13:05:26 -070080import java.util.concurrent.ConcurrentHashMap;
81import java.util.concurrent.ConcurrentLinkedQueue;
82import java.util.concurrent.Executors;
83import java.util.concurrent.ScheduledExecutorService;
84import java.util.concurrent.ScheduledFuture;
85import java.util.concurrent.TimeUnit;
86
87@SuppressWarnings("ALL")
sangho27462c62015-05-14 00:39:53 -070088@Service
sangho80f11cb2015-04-01 13:05:26 -070089@Component(immediate = true)
sangho27462c62015-05-14 00:39:53 -070090public class SegmentRoutingManager implements SegmentRoutingService {
sangho80f11cb2015-04-01 13:05:26 -070091
Srikanth Vavilapalli64505482015-04-21 13:04:13 -070092 private static Logger log = LoggerFactory
93 .getLogger(SegmentRoutingManager.class);
sangho80f11cb2015-04-01 13:05:26 -070094
95 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
96 protected CoreService coreService;
97
98 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
99 protected TopologyService topologyService;
100
101 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
102 protected PacketService packetService;
103
104 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
105 protected IntentService intentService;
106
107 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
108 protected HostService hostService;
109
110 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
111 protected DeviceService deviceService;
112
113 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700114 protected FlowObjectiveService flowObjectiveService;
sangho80f11cb2015-04-01 13:05:26 -0700115
116 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
117 protected LinkService linkService;
118
119 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
sangho80f11cb2015-04-01 13:05:26 -0700120 protected MastershipService mastershipService;
sangho27462c62015-05-14 00:39:53 -0700121
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700122 protected ArpHandler arpHandler = null;
123 protected IcmpHandler icmpHandler = null;
124 protected IpHandler ipHandler = null;
125 protected RoutingRulePopulator routingRulePopulator = null;
sangho80f11cb2015-04-01 13:05:26 -0700126 protected ApplicationId appId;
sangho9b169e32015-04-14 16:27:13 -0700127 protected DeviceConfiguration deviceConfiguration = null;
sangho80f11cb2015-04-01 13:05:26 -0700128
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700129 private DefaultRoutingHandler defaultRoutingHandler = null;
sangho27462c62015-05-14 00:39:53 -0700130 private TunnelHandler tunnelHandler = null;
131 private PolicyHandler policyHandler = null;
Charles Chan2b078ae2015-10-14 11:24:40 -0700132 private InternalPacketProcessor processor = null;
133 private InternalLinkListener linkListener = null;
134 private InternalDeviceListener deviceListener = null;
sangho80f11cb2015-04-01 13:05:26 -0700135 private InternalEventHandler eventHandler = new InternalEventHandler();
136
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700137 private ScheduledExecutorService executorService = Executors
138 .newScheduledThreadPool(1);
sangho80f11cb2015-04-01 13:05:26 -0700139
140 private static ScheduledFuture<?> eventHandlerFuture = null;
141 private ConcurrentLinkedQueue<Event> eventQueue = new ConcurrentLinkedQueue<Event>();
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700142 private Map<DeviceId, DefaultGroupHandler> groupHandlerMap = new ConcurrentHashMap<DeviceId, DefaultGroupHandler>();
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700143 // Per device next objective ID store with (device id + neighbor set) as key
144 private EventuallyConsistentMap<NeighborSetNextObjectiveStoreKey,
145 Integer> nsNextObjStore = null;
Charles Chan77277672015-10-20 16:24:19 -0700146 private EventuallyConsistentMap<SubnetNextObjectiveStoreKey, Integer> subnetNextObjStore = null;
sangho4a5c42a2015-05-20 22:16:38 -0700147 private EventuallyConsistentMap<String, Tunnel> tunnelStore = null;
148 private EventuallyConsistentMap<String, Policy> policyStore = null;
Saurav Das7c305372015-10-28 12:39:42 -0700149 // Per device, per-subnet assigned-vlans store, with (device id + subnet
150 // IPv4 prefix) as key
151 private EventuallyConsistentMap<SubnetAssignedVidStoreKey, VlanId>
152 subnetVidStore = null;
sangho4a5c42a2015-05-20 22:16:38 -0700153
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700154 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
155 protected StorageService storageService;
sangho80f11cb2015-04-01 13:05:26 -0700156
Charles Chan72f556a2015-10-05 17:50:33 -0700157 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
158 protected NetworkConfigRegistry cfgService;
159
Charles Chane7c61022015-10-07 14:21:45 -0700160 private final InternalConfigListener cfgListener =
161 new InternalConfigListener(this);
162
Charles Chan72f556a2015-10-05 17:50:33 -0700163 private final ConfigFactory cfgFactory =
164 new ConfigFactory(SubjectFactories.DEVICE_SUBJECT_FACTORY,
165 SegmentRoutingConfig.class,
166 "segmentrouting") {
167 @Override
168 public SegmentRoutingConfig createConfig() {
169 return new SegmentRoutingConfig();
170 }
171 };
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700172
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700173 private Object threadSchedulerLock = new Object();
174 private static int numOfEventsQueued = 0;
175 private static int numOfEventsExecuted = 0;
sangho80f11cb2015-04-01 13:05:26 -0700176 private static int numOfHandlerExecution = 0;
177 private static int numOfHandlerScheduled = 0;
178
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700179 private KryoNamespace.Builder kryoBuilder = null;
180
Saurav Das7c305372015-10-28 12:39:42 -0700181 private static final short ASSIGNED_VLAN_START = 4093;
182 public static final short ASSIGNED_VLAN_NO_SUBNET = 4094;
183
sangho80f11cb2015-04-01 13:05:26 -0700184 @Activate
185 protected void activate() {
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700186 appId = coreService
187 .registerApplication("org.onosproject.segmentrouting");
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700188
189 kryoBuilder = new KryoNamespace.Builder()
190 .register(NeighborSetNextObjectiveStoreKey.class,
Charles Chan77277672015-10-20 16:24:19 -0700191 SubnetNextObjectiveStoreKey.class,
192 SubnetAssignedVidStoreKey.class,
sangho4a5c42a2015-05-20 22:16:38 -0700193 NeighborSet.class,
194 DeviceId.class,
195 URI.class,
196 WallClockTimestamp.class,
197 org.onosproject.cluster.NodeId.class,
198 HashSet.class,
199 Tunnel.class,
200 DefaultTunnel.class,
201 Policy.class,
202 TunnelPolicy.class,
Saurav Das7c305372015-10-28 12:39:42 -0700203 Policy.Type.class,
Charles Chan77277672015-10-20 16:24:19 -0700204 VlanId.class,
205 Ip4Address.class,
206 Ip4Prefix.class,
207 IpAddress.Version.class,
208 ConnectPoint.class
sangho4a5c42a2015-05-20 22:16:38 -0700209 );
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700210
211 log.debug("Creating EC map nsnextobjectivestore");
212 EventuallyConsistentMapBuilder<NeighborSetNextObjectiveStoreKey, Integer>
213 nsNextObjMapBuilder = storageService.eventuallyConsistentMapBuilder();
214
215 nsNextObjStore = nsNextObjMapBuilder
216 .withName("nsnextobjectivestore")
217 .withSerializer(kryoBuilder)
Madan Jampani675ae202015-06-24 19:05:56 -0700218 .withTimestampProvider((k, v) -> new WallClockTimestamp())
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700219 .build();
220 log.trace("Current size {}", nsNextObjStore.size());
221
Charles Chan77277672015-10-20 16:24:19 -0700222 log.debug("Creating EC map subnetnextobjectivestore");
223 EventuallyConsistentMapBuilder<SubnetNextObjectiveStoreKey, Integer>
224 subnetNextObjMapBuilder = storageService.eventuallyConsistentMapBuilder();
225
226 subnetNextObjStore = subnetNextObjMapBuilder
227 .withName("subnetnextobjectivestore")
228 .withSerializer(kryoBuilder)
229 .withTimestampProvider((k, v) -> new WallClockTimestamp())
230 .build();
231
sangho4a5c42a2015-05-20 22:16:38 -0700232 EventuallyConsistentMapBuilder<String, Tunnel> tunnelMapBuilder =
233 storageService.eventuallyConsistentMapBuilder();
234
235 tunnelStore = tunnelMapBuilder
236 .withName("tunnelstore")
237 .withSerializer(kryoBuilder)
Madan Jampani675ae202015-06-24 19:05:56 -0700238 .withTimestampProvider((k, v) -> new WallClockTimestamp())
sangho4a5c42a2015-05-20 22:16:38 -0700239 .build();
240
241 EventuallyConsistentMapBuilder<String, Policy> policyMapBuilder =
242 storageService.eventuallyConsistentMapBuilder();
243
244 policyStore = policyMapBuilder
245 .withName("policystore")
246 .withSerializer(kryoBuilder)
Madan Jampani675ae202015-06-24 19:05:56 -0700247 .withTimestampProvider((k, v) -> new WallClockTimestamp())
sangho4a5c42a2015-05-20 22:16:38 -0700248 .build();
249
Saurav Das7c305372015-10-28 12:39:42 -0700250 EventuallyConsistentMapBuilder<SubnetAssignedVidStoreKey, VlanId>
251 subnetVidStoreMapBuilder = storageService.eventuallyConsistentMapBuilder();
252
253 subnetVidStore = subnetVidStoreMapBuilder
254 .withName("subnetvidstore")
255 .withSerializer(kryoBuilder)
256 .withTimestampProvider((k, v) -> new WallClockTimestamp())
257 .build();
258
Charles Chan72f556a2015-10-05 17:50:33 -0700259 cfgService.addListener(cfgListener);
260 cfgService.registerConfigFactory(cfgFactory);
Charles Chan72f556a2015-10-05 17:50:33 -0700261
Charles Chan2b078ae2015-10-14 11:24:40 -0700262 processor = new InternalPacketProcessor();
263 linkListener = new InternalLinkListener();
264 deviceListener = new InternalDeviceListener();
265
266 packetService.addProcessor(processor, PacketProcessor.director(2));
267 linkService.addListener(linkListener);
268 deviceService.addListener(deviceListener);
269
270 cfgListener.configureNetwork();
271
sangho80f11cb2015-04-01 13:05:26 -0700272 log.info("Started");
273 }
274
275 @Deactivate
276 protected void deactivate() {
Charles Chan72f556a2015-10-05 17:50:33 -0700277 cfgService.removeListener(cfgListener);
278 cfgService.unregisterConfigFactory(cfgFactory);
279
sangho80f11cb2015-04-01 13:05:26 -0700280 packetService.removeProcessor(processor);
Charles Chan2b078ae2015-10-14 11:24:40 -0700281 linkService.removeListener(linkListener);
282 deviceService.removeListener(deviceListener);
sangho80f11cb2015-04-01 13:05:26 -0700283 processor = null;
Charles Chan2b078ae2015-10-14 11:24:40 -0700284 linkListener = null;
285 deviceService = null;
286
287 groupHandlerMap.clear();
288
sangho80f11cb2015-04-01 13:05:26 -0700289 log.info("Stopped");
290 }
291
sangho27462c62015-05-14 00:39:53 -0700292
293 @Override
294 public List<Tunnel> getTunnels() {
295 return tunnelHandler.getTunnels();
296 }
297
298 @Override
sanghobd812f82015-06-29 14:58:47 -0700299 public TunnelHandler.Result createTunnel(Tunnel tunnel) {
300 return tunnelHandler.createTunnel(tunnel);
sangho27462c62015-05-14 00:39:53 -0700301 }
302
303 @Override
sanghobd812f82015-06-29 14:58:47 -0700304 public TunnelHandler.Result removeTunnel(Tunnel tunnel) {
sangho27462c62015-05-14 00:39:53 -0700305 for (Policy policy: policyHandler.getPolicies()) {
306 if (policy.type() == Policy.Type.TUNNEL_FLOW) {
307 TunnelPolicy tunnelPolicy = (TunnelPolicy) policy;
308 if (tunnelPolicy.tunnelId().equals(tunnel.id())) {
309 log.warn("Cannot remove the tunnel used by a policy");
sanghobd812f82015-06-29 14:58:47 -0700310 return TunnelHandler.Result.TUNNEL_IN_USE;
sangho27462c62015-05-14 00:39:53 -0700311 }
312 }
313 }
sanghobd812f82015-06-29 14:58:47 -0700314 return tunnelHandler.removeTunnel(tunnel);
sangho27462c62015-05-14 00:39:53 -0700315 }
316
317 @Override
sanghobd812f82015-06-29 14:58:47 -0700318 public PolicyHandler.Result removePolicy(Policy policy) {
319 return policyHandler.removePolicy(policy);
sangho27462c62015-05-14 00:39:53 -0700320 }
321
322 @Override
sanghobd812f82015-06-29 14:58:47 -0700323 public PolicyHandler.Result createPolicy(Policy policy) {
324 return policyHandler.createPolicy(policy);
sangho27462c62015-05-14 00:39:53 -0700325 }
326
327 @Override
328 public List<Policy> getPolicies() {
329 return policyHandler.getPolicies();
330 }
331
sangho80f1f892015-05-19 11:57:42 -0700332 /**
333 * Returns the tunnel object with the tunnel ID.
334 *
335 * @param tunnelId Tunnel ID
336 * @return Tunnel reference
337 */
sangho27462c62015-05-14 00:39:53 -0700338 public Tunnel getTunnel(String tunnelId) {
339 return tunnelHandler.getTunnel(tunnelId);
340 }
341
sangho80f11cb2015-04-01 13:05:26 -0700342 /**
Saurav Das7c305372015-10-28 12:39:42 -0700343 * Returns the vlan-id assigned to the subnet configured for a device.
344 * If no vlan-id has been assigned, a new one is assigned out of a pool of ids,
345 * if and only if this controller instance is the master for the device.
346 * <p>
347 * USAGE: The assigned vlans are meant to be applied to untagged packets on those
348 * switches/pipelines that need this functionality. These vids are meant
349 * to be used internally within a switch, and thus need to be unique only
350 * on a switch level. Note that packets never go out on the wire with these
351 * vlans. Currently, vlan ids are assigned from value 4093 down.
352 * Vlan id 4094 expected to be used for all ports that are not assigned subnets.
353 * Vlan id 4095 is reserved and unused. Only a single vlan id is assigned
354 * per subnet.
355 * XXX This method should avoid any vlans configured on the ports, but
356 * currently the app works only on untagged packets and as a result
357 * ignores any vlan configuration.
sangho80f11cb2015-04-01 13:05:26 -0700358 *
Saurav Das7c305372015-10-28 12:39:42 -0700359 * @param deviceId switch dpid
360 * @param subnet IPv4 prefix for which assigned vlan is desired
361 * @return VlanId assigned for the subnet on the device, or
362 * null if no vlan assignment was found and this instance is not
363 * the master for the device.
sangho80f11cb2015-04-01 13:05:26 -0700364 */
Saurav Das7c305372015-10-28 12:39:42 -0700365 public VlanId getSubnetAssignedVlanId(DeviceId deviceId, Ip4Prefix subnet) {
366 VlanId assignedVid = subnetVidStore.get(new SubnetAssignedVidStoreKey(
367 deviceId, subnet));
368 if (assignedVid != null) {
369 log.debug("Query for subnet:{} on device:{} returned assigned-vlan "
370 + "{}", subnet, deviceId, assignedVid);
371 return assignedVid;
372 }
373 //check mastership for the right to assign a vlan
374 if (!mastershipService.isLocalMaster(deviceId)) {
375 log.warn("This controller instance is not the master for device {}. "
376 + "Cannot assign vlan-id for subnet {}", deviceId, subnet);
377 return null;
378 }
379 // vlan assignment is expensive but done only once
Charles Chanc6ad7752015-10-29 14:58:10 -0700380 Set<Ip4Prefix> configuredSubnets = deviceConfiguration.getSubnets(deviceId);
Saurav Das7c305372015-10-28 12:39:42 -0700381 Set<Short> assignedVlans = new HashSet<>();
382 Set<Ip4Prefix> unassignedSubnets = new HashSet<>();
383 for (Ip4Prefix sub : configuredSubnets) {
384 VlanId v = subnetVidStore.get(new SubnetAssignedVidStoreKey(deviceId,
385 sub));
386 if (v != null) {
387 assignedVlans.add(v.toShort());
388 } else {
389 unassignedSubnets.add(sub);
390 }
391 }
392 short nextAssignedVlan = ASSIGNED_VLAN_START;
393 if (!assignedVlans.isEmpty()) {
394 nextAssignedVlan = (short) (Collections.min(assignedVlans) - 1);
395 }
396 for (Ip4Prefix unsub : unassignedSubnets) {
397 subnetVidStore.put(new SubnetAssignedVidStoreKey(deviceId, unsub),
398 VlanId.vlanId(nextAssignedVlan--));
399 log.info("Assigned vlan: {} to subnet: {} on device: {}",
400 nextAssignedVlan + 1, unsub, deviceId);
sangho80f11cb2015-04-01 13:05:26 -0700401 }
402
Saurav Das7c305372015-10-28 12:39:42 -0700403 return subnetVidStore.get(new SubnetAssignedVidStoreKey(deviceId, subnet));
sangho80f11cb2015-04-01 13:05:26 -0700404 }
405
sangho27462c62015-05-14 00:39:53 -0700406 /**
Saurav Das7c305372015-10-28 12:39:42 -0700407 * Returns the next objective ID for the given NeighborSet.
408 * If the nextObjectiveID does not exist, a new one is created and returned.
sangho27462c62015-05-14 00:39:53 -0700409 *
sangho80f1f892015-05-19 11:57:42 -0700410 * @param deviceId Device ID
411 * @param ns NegighborSet
412 * @return next objective ID
sangho27462c62015-05-14 00:39:53 -0700413 */
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700414 public int getNextObjectiveId(DeviceId deviceId, NeighborSet ns) {
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700415 if (groupHandlerMap.get(deviceId) != null) {
416 log.trace("getNextObjectiveId query in device {}", deviceId);
417 return groupHandlerMap
418 .get(deviceId).getNextObjectiveId(ns);
419 } else {
420 log.warn("getNextObjectiveId query in device {} not found", deviceId);
421 return -1;
422 }
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700423 }
424
Charles Chan77277672015-10-20 16:24:19 -0700425 /**
426 * Returns the next objective ID for the Subnet given. If the nextObjectiveID does not exist,
427 * a new one is created and returned.
428 *
429 * @param deviceId Device ID
430 * @param prefix Subnet
431 * @return next objective ID
432 */
433 public int getSubnetNextObjectiveId(DeviceId deviceId, IpPrefix prefix) {
434 if (groupHandlerMap.get(deviceId) != null) {
435 log.trace("getSubnetNextObjectiveId query in device {}", deviceId);
436 return groupHandlerMap
437 .get(deviceId).getSubnetNextObjectiveId(prefix);
438 } else {
439 log.warn("getSubnetNextObjectiveId query in device {} not found", deviceId);
440 return -1;
441 }
442 }
443
sangho80f11cb2015-04-01 13:05:26 -0700444 private class InternalPacketProcessor implements PacketProcessor {
sangho80f11cb2015-04-01 13:05:26 -0700445 @Override
446 public void process(PacketContext context) {
447
448 if (context.isHandled()) {
449 return;
450 }
451
452 InboundPacket pkt = context.inPacket();
453 Ethernet ethernet = pkt.parsed();
454
455 if (ethernet.getEtherType() == Ethernet.TYPE_ARP) {
456 arpHandler.processPacketIn(pkt);
457 } else if (ethernet.getEtherType() == Ethernet.TYPE_IPV4) {
458 IPv4 ipPacket = (IPv4) ethernet.getPayload();
459 ipHandler.addToPacketBuffer(ipPacket);
460 if (ipPacket.getProtocol() == IPv4.PROTOCOL_ICMP) {
461 icmpHandler.processPacketIn(pkt);
462 } else {
463 ipHandler.processPacketIn(pkt);
464 }
465 }
466 }
467 }
468
469 private class InternalLinkListener implements LinkListener {
470 @Override
471 public void event(LinkEvent event) {
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700472 if (event.type() == LinkEvent.Type.LINK_ADDED
473 || event.type() == LinkEvent.Type.LINK_REMOVED) {
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700474 log.debug("Event {} received from Link Service", event.type());
sangho80f11cb2015-04-01 13:05:26 -0700475 scheduleEventHandlerIfNotScheduled(event);
476 }
477 }
478 }
479
480 private class InternalDeviceListener implements DeviceListener {
sangho80f11cb2015-04-01 13:05:26 -0700481 @Override
482 public void event(DeviceEvent event) {
sangho80f11cb2015-04-01 13:05:26 -0700483 switch (event.type()) {
484 case DEVICE_ADDED:
485 case PORT_REMOVED:
sanghofb7c7292015-04-13 15:15:58 -0700486 case DEVICE_UPDATED:
487 case DEVICE_AVAILABILITY_CHANGED:
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700488 log.debug("Event {} received from Device Service", event.type());
sangho80f11cb2015-04-01 13:05:26 -0700489 scheduleEventHandlerIfNotScheduled(event);
490 break;
491 default:
492 }
493 }
494 }
495
sangho80f11cb2015-04-01 13:05:26 -0700496 private void scheduleEventHandlerIfNotScheduled(Event event) {
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700497 synchronized (threadSchedulerLock) {
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700498 eventQueue.add(event);
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700499 numOfEventsQueued++;
500
501 if ((numOfHandlerScheduled - numOfHandlerExecution) == 0) {
502 //No pending scheduled event handling threads. So start a new one.
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700503 eventHandlerFuture = executorService
504 .schedule(eventHandler, 100, TimeUnit.MILLISECONDS);
505 numOfHandlerScheduled++;
506 }
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700507 log.trace("numOfEventsQueued {}, numOfEventHanlderScheduled {}",
508 numOfEventsQueued,
509 numOfHandlerScheduled);
sangho80f11cb2015-04-01 13:05:26 -0700510 }
sangho80f11cb2015-04-01 13:05:26 -0700511 }
512
513 private class InternalEventHandler implements Runnable {
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700514 @Override
sangho80f11cb2015-04-01 13:05:26 -0700515 public void run() {
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700516 try {
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700517 while (true) {
518 Event event = null;
519 synchronized (threadSchedulerLock) {
520 if (!eventQueue.isEmpty()) {
521 event = eventQueue.poll();
522 numOfEventsExecuted++;
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700523 } else {
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700524 numOfHandlerExecution++;
525 log.debug("numOfHandlerExecution {} numOfEventsExecuted {}",
526 numOfHandlerExecution, numOfEventsExecuted);
527 break;
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700528 }
sanghofb7c7292015-04-13 15:15:58 -0700529 }
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700530 if (event.type() == LinkEvent.Type.LINK_ADDED) {
531 processLinkAdded((Link) event.subject());
532 } else if (event.type() == LinkEvent.Type.LINK_REMOVED) {
533 processLinkRemoved((Link) event.subject());
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700534 } else if (event.type() == DeviceEvent.Type.DEVICE_ADDED ||
535 event.type() == DeviceEvent.Type.DEVICE_AVAILABILITY_CHANGED ||
536 event.type() == DeviceEvent.Type.DEVICE_UPDATED) {
537 if (deviceService.isAvailable(((Device) event.subject()).id())) {
Saurav Dasc28b3432015-10-30 17:45:38 -0700538 log.info("Processing device event {} for available device {}",
539 event.type(), ((Device) event.subject()).id());
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700540 processDeviceAdded((Device) event.subject());
541 }
542 } else if (event.type() == DeviceEvent.Type.PORT_REMOVED) {
543 processPortRemoved((Device) event.subject(),
544 ((DeviceEvent) event).port());
545 } else {
546 log.warn("Unhandled event type: {}", event.type());
547 }
sangho80f11cb2015-04-01 13:05:26 -0700548 }
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700549 } catch (Exception e) {
550 log.error("SegmentRouting event handler "
551 + "thread thrown an exception: {}", e);
sangho80f11cb2015-04-01 13:05:26 -0700552 }
sangho80f11cb2015-04-01 13:05:26 -0700553 }
554 }
555
sangho80f11cb2015-04-01 13:05:26 -0700556 private void processLinkAdded(Link link) {
557 log.debug("A new link {} was added", link.toString());
Charles Chan319d1a22015-11-03 10:42:14 -0800558 if (!deviceConfiguration.isConfigured(link.src().deviceId())) {
559 log.warn("Source device of this link is not configured.");
560 return;
561 }
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700562 //Irrespective whether the local is a MASTER or not for this device,
563 //create group handler instance and push default TTP flow rules.
564 //Because in a multi-instance setup, instances can initiate
565 //groups for any devices. Also the default TTP rules are needed
566 //to be pushed before inserting any IP table entries for any device
567 DefaultGroupHandler groupHandler = groupHandlerMap.get(link.src()
568 .deviceId());
569 if (groupHandler != null) {
570 groupHandler.linkUp(link);
571 } else {
572 Device device = deviceService.getDevice(link.src().deviceId());
573 if (device != null) {
574 log.warn("processLinkAdded: Link Added "
575 + "Notification without Device Added "
576 + "event, still handling it");
577 processDeviceAdded(device);
578 groupHandler = groupHandlerMap.get(link.src()
579 .deviceId());
sangho80f11cb2015-04-01 13:05:26 -0700580 groupHandler.linkUp(link);
581 }
582 }
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700583
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700584 log.trace("Starting optimized route population process");
585 defaultRoutingHandler.populateRoutingRulesForLinkStatusChange(null);
586 //log.trace("processLinkAdded: re-starting route population process");
587 //defaultRoutingHandler.startPopulationProcess();
sangho80f11cb2015-04-01 13:05:26 -0700588 }
589
590 private void processLinkRemoved(Link link) {
591 log.debug("A link {} was removed", link.toString());
sangho2165d222015-05-01 09:38:25 -0700592 DefaultGroupHandler groupHandler = groupHandlerMap.get(link.src().deviceId());
593 if (groupHandler != null) {
594 groupHandler.portDown(link.src().port());
595 }
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700596 log.trace("Starting optimized route population process");
597 defaultRoutingHandler.populateRoutingRulesForLinkStatusChange(link);
598 //log.trace("processLinkRemoved: re-starting route population process");
599 //defaultRoutingHandler.startPopulationProcess();
sangho80f11cb2015-04-01 13:05:26 -0700600 }
601
602 private void processDeviceAdded(Device device) {
603 log.debug("A new device with ID {} was added", device.id());
Charles Chan319d1a22015-11-03 10:42:14 -0800604 if (deviceConfiguration == null || !deviceConfiguration.isConfigured(device.id())) {
Saurav Das8ec0ec42015-11-03 14:39:27 -0800605 log.warn("Device configuration uploading. Device {} will be "
606 + "processed after config completes.", device.id());
607 return;
608 }
Saurav Dasc28b3432015-10-30 17:45:38 -0700609 // Irrespective of whether the local is a MASTER or not for this device,
610 // we need to create a SR-group-handler instance. This is because in a
611 // multi-instance setup, any instance can initiate forwarding/next-objectives
612 // for any switch (even if this instance is a SLAVE or not even connected
613 // to the switch). To handle this, a default-group-handler instance is necessary
614 // per switch.
Saurav Das8ec0ec42015-11-03 14:39:27 -0800615 if (groupHandlerMap.get(device.id()) == null) {
Charles Chan319d1a22015-11-03 10:42:14 -0800616 DefaultGroupHandler groupHandler;
617 try {
618 groupHandler = DefaultGroupHandler.
619 createGroupHandler(device.id(),
620 appId,
621 deviceConfiguration,
622 linkService,
623 flowObjectiveService,
624 nsNextObjStore,
625 subnetNextObjStore);
626 } catch (DeviceConfigNotFoundException e) {
627 log.warn(e.getMessage() + " Aborting processDeviceAdded.");
628 return;
629 }
Saurav Das8ec0ec42015-11-03 14:39:27 -0800630 groupHandlerMap.put(device.id(), groupHandler);
631 // Also, in some cases, drivers may need extra
632 // information to process rules (eg. Router IP/MAC); and so, we send
633 // port addressing rules to the driver as well irrespective of whether
634 // this instance is the master or not.
635 defaultRoutingHandler.populatePortAddressingRules(device.id());
636 }
Charles Chan77277672015-10-20 16:24:19 -0700637 if (mastershipService.isLocalMaster(device.id())) {
Saurav Das8ec0ec42015-11-03 14:39:27 -0800638 DefaultGroupHandler groupHandler = groupHandlerMap.get(device.id());
Charles Chan77277672015-10-20 16:24:19 -0700639 groupHandler.createGroupsFromSubnetConfig();
640 }
sangho80f11cb2015-04-01 13:05:26 -0700641 }
642
643 private void processPortRemoved(Device device, Port port) {
644 log.debug("Port {} was removed", port.toString());
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700645 DefaultGroupHandler groupHandler = groupHandlerMap.get(device.id());
sangho80f11cb2015-04-01 13:05:26 -0700646 if (groupHandler != null) {
647 groupHandler.portDown(port.number());
648 }
649 }
sangho27462c62015-05-14 00:39:53 -0700650
Charles Chan72f556a2015-10-05 17:50:33 -0700651 private class InternalConfigListener implements NetworkConfigListener {
Charles Chane7c61022015-10-07 14:21:45 -0700652 SegmentRoutingManager segmentRoutingManager;
653
654 public InternalConfigListener(SegmentRoutingManager srMgr) {
655 this.segmentRoutingManager = srMgr;
656 }
657
658 public void configureNetwork() {
659 deviceConfiguration = new DeviceConfiguration(segmentRoutingManager.cfgService);
660
661 arpHandler = new ArpHandler(segmentRoutingManager);
662 icmpHandler = new IcmpHandler(segmentRoutingManager);
663 ipHandler = new IpHandler(segmentRoutingManager);
664 routingRulePopulator = new RoutingRulePopulator(segmentRoutingManager);
665 defaultRoutingHandler = new DefaultRoutingHandler(segmentRoutingManager);
666
667 tunnelHandler = new TunnelHandler(linkService, deviceConfiguration,
668 groupHandlerMap, tunnelStore);
669 policyHandler = new PolicyHandler(appId, deviceConfiguration,
670 flowObjectiveService,
671 tunnelHandler, policyStore);
672
Charles Chane7c61022015-10-07 14:21:45 -0700673 for (Device device : deviceService.getDevices()) {
Saurav Dasc28b3432015-10-30 17:45:38 -0700674 // Irrespective of whether the local is a MASTER or not for this device,
675 // we need to create a SR-group-handler instance. This is because in a
676 // multi-instance setup, any instance can initiate forwarding/next-objectives
677 // for any switch (even if this instance is a SLAVE or not even connected
678 // to the switch). To handle this, a default-group-handler instance is necessary
679 // per switch.
Saurav Das8ec0ec42015-11-03 14:39:27 -0800680 if (groupHandlerMap.get(device.id()) == null) {
Charles Chan319d1a22015-11-03 10:42:14 -0800681 DefaultGroupHandler groupHandler;
682 try {
683 groupHandler = DefaultGroupHandler.
684 createGroupHandler(device.id(),
685 appId,
686 deviceConfiguration,
687 linkService,
688 flowObjectiveService,
689 nsNextObjStore,
690 subnetNextObjStore);
691 } catch (DeviceConfigNotFoundException e) {
692 log.warn(e.getMessage() + " Aborting configureNetwork.");
693 return;
694 }
Saurav Das8ec0ec42015-11-03 14:39:27 -0800695 groupHandlerMap.put(device.id(), groupHandler);
Saurav Dasc28b3432015-10-30 17:45:38 -0700696
Saurav Das8ec0ec42015-11-03 14:39:27 -0800697 // Also, in some cases, drivers may need extra
698 // information to process rules (eg. Router IP/MAC); and so, we send
699 // port addressing rules to the driver as well, irrespective of whether
700 // this instance is the master or not.
701 defaultRoutingHandler.populatePortAddressingRules(device.id());
702 }
Charles Chan77277672015-10-20 16:24:19 -0700703 if (mastershipService.isLocalMaster(device.id())) {
Saurav Das8ec0ec42015-11-03 14:39:27 -0800704 DefaultGroupHandler groupHandler = groupHandlerMap.get(device.id());
Charles Chan77277672015-10-20 16:24:19 -0700705 groupHandler.createGroupsFromSubnetConfig();
706 }
Charles Chane7c61022015-10-07 14:21:45 -0700707 }
708
709 defaultRoutingHandler.startPopulationProcess();
710 }
711
Charles Chan72f556a2015-10-05 17:50:33 -0700712 @Override
713 public void event(NetworkConfigEvent event) {
Charles Chan2b078ae2015-10-14 11:24:40 -0700714 if (event.configClass().equals(SegmentRoutingConfig.class)) {
715 if (event.type() == NetworkConfigEvent.Type.CONFIG_ADDED) {
716 log.info("Network configuration added.");
717 configureNetwork();
718 }
719 if (event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED) {
720 log.info("Network configuration updated.");
721 // TODO support dynamic configuration
722 }
Charles Chan72f556a2015-10-05 17:50:33 -0700723 }
724 }
725 }
sangho80f11cb2015-04-01 13:05:26 -0700726}