blob: 9d60b2791a36573f44f0d11340e96cdee5b125d5 [file] [log] [blame]
sanghob35a6192015-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;
sangho1e575652015-05-14 00:39:53 -070023import org.apache.felix.scr.annotations.Service;
sanghob35a6192015-04-01 13:05:26 -070024import org.onlab.packet.Ethernet;
Saurav Das0e99e2b2015-10-28 12:39:42 -070025import org.onlab.packet.VlanId;
Charles Chanc42e84e2015-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 Vavilapalli23181912015-05-04 09:48:09 -070031import org.onlab.util.KryoNamespace;
sanghob35a6192015-04-01 13:05:26 -070032import org.onosproject.core.ApplicationId;
33import org.onosproject.core.CoreService;
34import org.onosproject.event.Event;
Charles Chanc42e84e2015-10-20 16:24:19 -070035import org.onosproject.net.ConnectPoint;
Charles Chand6832882015-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;
41import org.onosproject.segmentrouting.config.SegmentRoutingConfig;
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -070042import org.onosproject.segmentrouting.grouphandler.DefaultGroupHandler;
43import org.onosproject.segmentrouting.grouphandler.NeighborSet;
Srikanth Vavilapalli23181912015-05-04 09:48:09 -070044import org.onosproject.segmentrouting.grouphandler.NeighborSetNextObjectiveStoreKey;
sanghob35a6192015-04-01 13:05:26 -070045import org.onosproject.mastership.MastershipService;
46import org.onosproject.net.Device;
47import org.onosproject.net.DeviceId;
48import org.onosproject.net.Link;
sanghob35a6192015-04-01 13:05:26 -070049import org.onosproject.net.Port;
50import org.onosproject.net.device.DeviceEvent;
51import org.onosproject.net.device.DeviceListener;
52import org.onosproject.net.device.DeviceService;
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070053import org.onosproject.net.flowobjective.FlowObjectiveService;
sanghob35a6192015-04-01 13:05:26 -070054import org.onosproject.net.host.HostService;
55import org.onosproject.net.intent.IntentService;
56import org.onosproject.net.link.LinkEvent;
57import org.onosproject.net.link.LinkListener;
58import org.onosproject.net.link.LinkService;
59import org.onosproject.net.packet.InboundPacket;
60import org.onosproject.net.packet.PacketContext;
61import org.onosproject.net.packet.PacketProcessor;
62import org.onosproject.net.packet.PacketService;
63import org.onosproject.net.topology.TopologyService;
Charles Chanc42e84e2015-10-20 16:24:19 -070064import org.onosproject.segmentrouting.grouphandler.SubnetNextObjectiveStoreKey;
Srikanth Vavilapalli23181912015-05-04 09:48:09 -070065import org.onosproject.store.service.EventuallyConsistentMap;
66import org.onosproject.store.service.EventuallyConsistentMapBuilder;
67import org.onosproject.store.service.StorageService;
68import org.onosproject.store.service.WallClockTimestamp;
sanghob35a6192015-04-01 13:05:26 -070069import org.slf4j.Logger;
70import org.slf4j.LoggerFactory;
71
Srikanth Vavilapalli23181912015-05-04 09:48:09 -070072import java.net.URI;
Saurav Das0e99e2b2015-10-28 12:39:42 -070073import java.util.Collections;
Srikanth Vavilapalli23181912015-05-04 09:48:09 -070074import java.util.HashSet;
sangho1e575652015-05-14 00:39:53 -070075import java.util.List;
sanghob35a6192015-04-01 13:05:26 -070076import java.util.Map;
Saurav Das0e99e2b2015-10-28 12:39:42 -070077import java.util.Set;
sanghob35a6192015-04-01 13:05:26 -070078import java.util.concurrent.ConcurrentHashMap;
79import java.util.concurrent.ConcurrentLinkedQueue;
80import java.util.concurrent.Executors;
81import java.util.concurrent.ScheduledExecutorService;
82import java.util.concurrent.ScheduledFuture;
83import java.util.concurrent.TimeUnit;
84
85@SuppressWarnings("ALL")
sangho1e575652015-05-14 00:39:53 -070086@Service
sanghob35a6192015-04-01 13:05:26 -070087@Component(immediate = true)
sangho1e575652015-05-14 00:39:53 -070088public class SegmentRoutingManager implements SegmentRoutingService {
sanghob35a6192015-04-01 13:05:26 -070089
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070090 private static Logger log = LoggerFactory
91 .getLogger(SegmentRoutingManager.class);
sanghob35a6192015-04-01 13:05:26 -070092
93 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
94 protected CoreService coreService;
95
96 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
97 protected TopologyService topologyService;
98
99 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
100 protected PacketService packetService;
101
102 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
103 protected IntentService intentService;
104
105 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
106 protected HostService hostService;
107
108 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
109 protected DeviceService deviceService;
110
111 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700112 protected FlowObjectiveService flowObjectiveService;
sanghob35a6192015-04-01 13:05:26 -0700113
114 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
115 protected LinkService linkService;
116
117 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
sanghob35a6192015-04-01 13:05:26 -0700118 protected MastershipService mastershipService;
sangho1e575652015-05-14 00:39:53 -0700119
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700120 protected ArpHandler arpHandler = null;
121 protected IcmpHandler icmpHandler = null;
122 protected IpHandler ipHandler = null;
123 protected RoutingRulePopulator routingRulePopulator = null;
sanghob35a6192015-04-01 13:05:26 -0700124 protected ApplicationId appId;
sangho666cd6d2015-04-14 16:27:13 -0700125 protected DeviceConfiguration deviceConfiguration = null;
sanghob35a6192015-04-01 13:05:26 -0700126
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700127 private DefaultRoutingHandler defaultRoutingHandler = null;
sangho1e575652015-05-14 00:39:53 -0700128 private TunnelHandler tunnelHandler = null;
129 private PolicyHandler policyHandler = null;
Charles Chanb8e10c82015-10-14 11:24:40 -0700130 private InternalPacketProcessor processor = null;
131 private InternalLinkListener linkListener = null;
132 private InternalDeviceListener deviceListener = null;
sanghob35a6192015-04-01 13:05:26 -0700133 private InternalEventHandler eventHandler = new InternalEventHandler();
134
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700135 private ScheduledExecutorService executorService = Executors
136 .newScheduledThreadPool(1);
sanghob35a6192015-04-01 13:05:26 -0700137
138 private static ScheduledFuture<?> eventHandlerFuture = null;
139 private ConcurrentLinkedQueue<Event> eventQueue = new ConcurrentLinkedQueue<Event>();
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700140 private Map<DeviceId, DefaultGroupHandler> groupHandlerMap = new ConcurrentHashMap<DeviceId, DefaultGroupHandler>();
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700141 // Per device next objective ID store with (device id + neighbor set) as key
142 private EventuallyConsistentMap<NeighborSetNextObjectiveStoreKey,
143 Integer> nsNextObjStore = null;
Charles Chanc42e84e2015-10-20 16:24:19 -0700144 private EventuallyConsistentMap<SubnetNextObjectiveStoreKey, Integer> subnetNextObjStore = null;
sangho0b2b6d12015-05-20 22:16:38 -0700145 private EventuallyConsistentMap<String, Tunnel> tunnelStore = null;
146 private EventuallyConsistentMap<String, Policy> policyStore = null;
Saurav Das0e99e2b2015-10-28 12:39:42 -0700147 // Per device, per-subnet assigned-vlans store, with (device id + subnet
148 // IPv4 prefix) as key
149 private EventuallyConsistentMap<SubnetAssignedVidStoreKey, VlanId>
150 subnetVidStore = null;
sangho0b2b6d12015-05-20 22:16:38 -0700151
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700152 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
153 protected StorageService storageService;
sanghob35a6192015-04-01 13:05:26 -0700154
Charles Chand6832882015-10-05 17:50:33 -0700155 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
156 protected NetworkConfigRegistry cfgService;
157
Charles Chan4636be02015-10-07 14:21:45 -0700158 private final InternalConfigListener cfgListener =
159 new InternalConfigListener(this);
160
Charles Chand6832882015-10-05 17:50:33 -0700161 private final ConfigFactory cfgFactory =
162 new ConfigFactory(SubjectFactories.DEVICE_SUBJECT_FACTORY,
163 SegmentRoutingConfig.class,
164 "segmentrouting") {
165 @Override
166 public SegmentRoutingConfig createConfig() {
167 return new SegmentRoutingConfig();
168 }
169 };
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700170
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700171 private Object threadSchedulerLock = new Object();
172 private static int numOfEventsQueued = 0;
173 private static int numOfEventsExecuted = 0;
sanghob35a6192015-04-01 13:05:26 -0700174 private static int numOfHandlerExecution = 0;
175 private static int numOfHandlerScheduled = 0;
176
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700177 private KryoNamespace.Builder kryoBuilder = null;
178
Saurav Das0e99e2b2015-10-28 12:39:42 -0700179 private static final short ASSIGNED_VLAN_START = 4093;
180 public static final short ASSIGNED_VLAN_NO_SUBNET = 4094;
181
sanghob35a6192015-04-01 13:05:26 -0700182 @Activate
183 protected void activate() {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700184 appId = coreService
185 .registerApplication("org.onosproject.segmentrouting");
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700186
187 kryoBuilder = new KryoNamespace.Builder()
188 .register(NeighborSetNextObjectiveStoreKey.class,
Charles Chanc42e84e2015-10-20 16:24:19 -0700189 SubnetNextObjectiveStoreKey.class,
190 SubnetAssignedVidStoreKey.class,
sangho0b2b6d12015-05-20 22:16:38 -0700191 NeighborSet.class,
192 DeviceId.class,
193 URI.class,
194 WallClockTimestamp.class,
195 org.onosproject.cluster.NodeId.class,
196 HashSet.class,
197 Tunnel.class,
198 DefaultTunnel.class,
199 Policy.class,
200 TunnelPolicy.class,
Saurav Das0e99e2b2015-10-28 12:39:42 -0700201 Policy.Type.class,
Charles Chanc42e84e2015-10-20 16:24:19 -0700202 VlanId.class,
203 Ip4Address.class,
204 Ip4Prefix.class,
205 IpAddress.Version.class,
206 ConnectPoint.class
sangho0b2b6d12015-05-20 22:16:38 -0700207 );
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700208
209 log.debug("Creating EC map nsnextobjectivestore");
210 EventuallyConsistentMapBuilder<NeighborSetNextObjectiveStoreKey, Integer>
211 nsNextObjMapBuilder = storageService.eventuallyConsistentMapBuilder();
212
213 nsNextObjStore = nsNextObjMapBuilder
214 .withName("nsnextobjectivestore")
215 .withSerializer(kryoBuilder)
Madan Jampanibcf1a482015-06-24 19:05:56 -0700216 .withTimestampProvider((k, v) -> new WallClockTimestamp())
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700217 .build();
218 log.trace("Current size {}", nsNextObjStore.size());
219
Charles Chanc42e84e2015-10-20 16:24:19 -0700220 log.debug("Creating EC map subnetnextobjectivestore");
221 EventuallyConsistentMapBuilder<SubnetNextObjectiveStoreKey, Integer>
222 subnetNextObjMapBuilder = storageService.eventuallyConsistentMapBuilder();
223
224 subnetNextObjStore = subnetNextObjMapBuilder
225 .withName("subnetnextobjectivestore")
226 .withSerializer(kryoBuilder)
227 .withTimestampProvider((k, v) -> new WallClockTimestamp())
228 .build();
229
sangho0b2b6d12015-05-20 22:16:38 -0700230 EventuallyConsistentMapBuilder<String, Tunnel> tunnelMapBuilder =
231 storageService.eventuallyConsistentMapBuilder();
232
233 tunnelStore = tunnelMapBuilder
234 .withName("tunnelstore")
235 .withSerializer(kryoBuilder)
Madan Jampanibcf1a482015-06-24 19:05:56 -0700236 .withTimestampProvider((k, v) -> new WallClockTimestamp())
sangho0b2b6d12015-05-20 22:16:38 -0700237 .build();
238
239 EventuallyConsistentMapBuilder<String, Policy> policyMapBuilder =
240 storageService.eventuallyConsistentMapBuilder();
241
242 policyStore = policyMapBuilder
243 .withName("policystore")
244 .withSerializer(kryoBuilder)
Madan Jampanibcf1a482015-06-24 19:05:56 -0700245 .withTimestampProvider((k, v) -> new WallClockTimestamp())
sangho0b2b6d12015-05-20 22:16:38 -0700246 .build();
247
Saurav Das0e99e2b2015-10-28 12:39:42 -0700248 EventuallyConsistentMapBuilder<SubnetAssignedVidStoreKey, VlanId>
249 subnetVidStoreMapBuilder = storageService.eventuallyConsistentMapBuilder();
250
251 subnetVidStore = subnetVidStoreMapBuilder
252 .withName("subnetvidstore")
253 .withSerializer(kryoBuilder)
254 .withTimestampProvider((k, v) -> new WallClockTimestamp())
255 .build();
256
Charles Chand6832882015-10-05 17:50:33 -0700257 cfgService.addListener(cfgListener);
258 cfgService.registerConfigFactory(cfgFactory);
Charles Chand6832882015-10-05 17:50:33 -0700259
Charles Chanb8e10c82015-10-14 11:24:40 -0700260 processor = new InternalPacketProcessor();
261 linkListener = new InternalLinkListener();
262 deviceListener = new InternalDeviceListener();
263
264 packetService.addProcessor(processor, PacketProcessor.director(2));
265 linkService.addListener(linkListener);
266 deviceService.addListener(deviceListener);
267
268 cfgListener.configureNetwork();
269
sanghob35a6192015-04-01 13:05:26 -0700270 log.info("Started");
271 }
272
273 @Deactivate
274 protected void deactivate() {
Charles Chand6832882015-10-05 17:50:33 -0700275 cfgService.removeListener(cfgListener);
276 cfgService.unregisterConfigFactory(cfgFactory);
277
sanghob35a6192015-04-01 13:05:26 -0700278 packetService.removeProcessor(processor);
Charles Chanb8e10c82015-10-14 11:24:40 -0700279 linkService.removeListener(linkListener);
280 deviceService.removeListener(deviceListener);
sanghob35a6192015-04-01 13:05:26 -0700281 processor = null;
Charles Chanb8e10c82015-10-14 11:24:40 -0700282 linkListener = null;
283 deviceService = null;
284
285 groupHandlerMap.clear();
286
sanghob35a6192015-04-01 13:05:26 -0700287 log.info("Stopped");
288 }
289
sangho1e575652015-05-14 00:39:53 -0700290
291 @Override
292 public List<Tunnel> getTunnels() {
293 return tunnelHandler.getTunnels();
294 }
295
296 @Override
sangho71abe1b2015-06-29 14:58:47 -0700297 public TunnelHandler.Result createTunnel(Tunnel tunnel) {
298 return tunnelHandler.createTunnel(tunnel);
sangho1e575652015-05-14 00:39:53 -0700299 }
300
301 @Override
sangho71abe1b2015-06-29 14:58:47 -0700302 public TunnelHandler.Result removeTunnel(Tunnel tunnel) {
sangho1e575652015-05-14 00:39:53 -0700303 for (Policy policy: policyHandler.getPolicies()) {
304 if (policy.type() == Policy.Type.TUNNEL_FLOW) {
305 TunnelPolicy tunnelPolicy = (TunnelPolicy) policy;
306 if (tunnelPolicy.tunnelId().equals(tunnel.id())) {
307 log.warn("Cannot remove the tunnel used by a policy");
sangho71abe1b2015-06-29 14:58:47 -0700308 return TunnelHandler.Result.TUNNEL_IN_USE;
sangho1e575652015-05-14 00:39:53 -0700309 }
310 }
311 }
sangho71abe1b2015-06-29 14:58:47 -0700312 return tunnelHandler.removeTunnel(tunnel);
sangho1e575652015-05-14 00:39:53 -0700313 }
314
315 @Override
sangho71abe1b2015-06-29 14:58:47 -0700316 public PolicyHandler.Result removePolicy(Policy policy) {
317 return policyHandler.removePolicy(policy);
sangho1e575652015-05-14 00:39:53 -0700318 }
319
320 @Override
sangho71abe1b2015-06-29 14:58:47 -0700321 public PolicyHandler.Result createPolicy(Policy policy) {
322 return policyHandler.createPolicy(policy);
sangho1e575652015-05-14 00:39:53 -0700323 }
324
325 @Override
326 public List<Policy> getPolicies() {
327 return policyHandler.getPolicies();
328 }
329
sanghof9d0bf12015-05-19 11:57:42 -0700330 /**
331 * Returns the tunnel object with the tunnel ID.
332 *
333 * @param tunnelId Tunnel ID
334 * @return Tunnel reference
335 */
sangho1e575652015-05-14 00:39:53 -0700336 public Tunnel getTunnel(String tunnelId) {
337 return tunnelHandler.getTunnel(tunnelId);
338 }
339
sanghob35a6192015-04-01 13:05:26 -0700340 /**
Saurav Das0e99e2b2015-10-28 12:39:42 -0700341 * Returns the vlan-id assigned to the subnet configured for a device.
342 * If no vlan-id has been assigned, a new one is assigned out of a pool of ids,
343 * if and only if this controller instance is the master for the device.
344 * <p>
345 * USAGE: The assigned vlans are meant to be applied to untagged packets on those
346 * switches/pipelines that need this functionality. These vids are meant
347 * to be used internally within a switch, and thus need to be unique only
348 * on a switch level. Note that packets never go out on the wire with these
349 * vlans. Currently, vlan ids are assigned from value 4093 down.
350 * Vlan id 4094 expected to be used for all ports that are not assigned subnets.
351 * Vlan id 4095 is reserved and unused. Only a single vlan id is assigned
352 * per subnet.
353 * XXX This method should avoid any vlans configured on the ports, but
354 * currently the app works only on untagged packets and as a result
355 * ignores any vlan configuration.
sanghob35a6192015-04-01 13:05:26 -0700356 *
Saurav Das0e99e2b2015-10-28 12:39:42 -0700357 * @param deviceId switch dpid
358 * @param subnet IPv4 prefix for which assigned vlan is desired
359 * @return VlanId assigned for the subnet on the device, or
360 * null if no vlan assignment was found and this instance is not
361 * the master for the device.
sanghob35a6192015-04-01 13:05:26 -0700362 */
Saurav Das0e99e2b2015-10-28 12:39:42 -0700363 public VlanId getSubnetAssignedVlanId(DeviceId deviceId, Ip4Prefix subnet) {
364 VlanId assignedVid = subnetVidStore.get(new SubnetAssignedVidStoreKey(
365 deviceId, subnet));
366 if (assignedVid != null) {
367 log.debug("Query for subnet:{} on device:{} returned assigned-vlan "
368 + "{}", subnet, deviceId, assignedVid);
369 return assignedVid;
370 }
371 //check mastership for the right to assign a vlan
372 if (!mastershipService.isLocalMaster(deviceId)) {
373 log.warn("This controller instance is not the master for device {}. "
374 + "Cannot assign vlan-id for subnet {}", deviceId, subnet);
375 return null;
376 }
377 // vlan assignment is expensive but done only once
Charles Chan9f676b62015-10-29 14:58:10 -0700378 Set<Ip4Prefix> configuredSubnets = deviceConfiguration.getSubnets(deviceId);
Saurav Das0e99e2b2015-10-28 12:39:42 -0700379 Set<Short> assignedVlans = new HashSet<>();
380 Set<Ip4Prefix> unassignedSubnets = new HashSet<>();
381 for (Ip4Prefix sub : configuredSubnets) {
382 VlanId v = subnetVidStore.get(new SubnetAssignedVidStoreKey(deviceId,
383 sub));
384 if (v != null) {
385 assignedVlans.add(v.toShort());
386 } else {
387 unassignedSubnets.add(sub);
388 }
389 }
390 short nextAssignedVlan = ASSIGNED_VLAN_START;
391 if (!assignedVlans.isEmpty()) {
392 nextAssignedVlan = (short) (Collections.min(assignedVlans) - 1);
393 }
394 for (Ip4Prefix unsub : unassignedSubnets) {
395 subnetVidStore.put(new SubnetAssignedVidStoreKey(deviceId, unsub),
396 VlanId.vlanId(nextAssignedVlan--));
397 log.info("Assigned vlan: {} to subnet: {} on device: {}",
398 nextAssignedVlan + 1, unsub, deviceId);
sanghob35a6192015-04-01 13:05:26 -0700399 }
400
Saurav Das0e99e2b2015-10-28 12:39:42 -0700401 return subnetVidStore.get(new SubnetAssignedVidStoreKey(deviceId, subnet));
sanghob35a6192015-04-01 13:05:26 -0700402 }
403
sangho1e575652015-05-14 00:39:53 -0700404 /**
Saurav Das0e99e2b2015-10-28 12:39:42 -0700405 * Returns the next objective ID for the given NeighborSet.
406 * If the nextObjectiveID does not exist, a new one is created and returned.
sangho1e575652015-05-14 00:39:53 -0700407 *
sanghof9d0bf12015-05-19 11:57:42 -0700408 * @param deviceId Device ID
409 * @param ns NegighborSet
410 * @return next objective ID
sangho1e575652015-05-14 00:39:53 -0700411 */
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700412 public int getNextObjectiveId(DeviceId deviceId, NeighborSet ns) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700413 if (groupHandlerMap.get(deviceId) != null) {
414 log.trace("getNextObjectiveId query in device {}", deviceId);
415 return groupHandlerMap
416 .get(deviceId).getNextObjectiveId(ns);
417 } else {
418 log.warn("getNextObjectiveId query in device {} not found", deviceId);
419 return -1;
420 }
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700421 }
422
Charles Chanc42e84e2015-10-20 16:24:19 -0700423 /**
424 * Returns the next objective ID for the Subnet given. If the nextObjectiveID does not exist,
425 * a new one is created and returned.
426 *
427 * @param deviceId Device ID
428 * @param prefix Subnet
429 * @return next objective ID
430 */
431 public int getSubnetNextObjectiveId(DeviceId deviceId, IpPrefix prefix) {
432 if (groupHandlerMap.get(deviceId) != null) {
433 log.trace("getSubnetNextObjectiveId query in device {}", deviceId);
434 return groupHandlerMap
435 .get(deviceId).getSubnetNextObjectiveId(prefix);
436 } else {
437 log.warn("getSubnetNextObjectiveId query in device {} not found", deviceId);
438 return -1;
439 }
440 }
441
sanghob35a6192015-04-01 13:05:26 -0700442 private class InternalPacketProcessor implements PacketProcessor {
sanghob35a6192015-04-01 13:05:26 -0700443 @Override
444 public void process(PacketContext context) {
445
446 if (context.isHandled()) {
447 return;
448 }
449
450 InboundPacket pkt = context.inPacket();
451 Ethernet ethernet = pkt.parsed();
452
453 if (ethernet.getEtherType() == Ethernet.TYPE_ARP) {
454 arpHandler.processPacketIn(pkt);
455 } else if (ethernet.getEtherType() == Ethernet.TYPE_IPV4) {
456 IPv4 ipPacket = (IPv4) ethernet.getPayload();
457 ipHandler.addToPacketBuffer(ipPacket);
458 if (ipPacket.getProtocol() == IPv4.PROTOCOL_ICMP) {
459 icmpHandler.processPacketIn(pkt);
460 } else {
461 ipHandler.processPacketIn(pkt);
462 }
463 }
464 }
465 }
466
467 private class InternalLinkListener implements LinkListener {
468 @Override
469 public void event(LinkEvent event) {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700470 if (event.type() == LinkEvent.Type.LINK_ADDED
471 || event.type() == LinkEvent.Type.LINK_REMOVED) {
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700472 log.debug("Event {} received from Link Service", event.type());
sanghob35a6192015-04-01 13:05:26 -0700473 scheduleEventHandlerIfNotScheduled(event);
474 }
475 }
476 }
477
478 private class InternalDeviceListener implements DeviceListener {
sanghob35a6192015-04-01 13:05:26 -0700479 @Override
480 public void event(DeviceEvent event) {
sanghob35a6192015-04-01 13:05:26 -0700481 switch (event.type()) {
482 case DEVICE_ADDED:
483 case PORT_REMOVED:
sangho20eff1d2015-04-13 15:15:58 -0700484 case DEVICE_UPDATED:
485 case DEVICE_AVAILABILITY_CHANGED:
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700486 log.debug("Event {} received from Device Service", event.type());
sanghob35a6192015-04-01 13:05:26 -0700487 scheduleEventHandlerIfNotScheduled(event);
488 break;
489 default:
490 }
491 }
492 }
493
sanghob35a6192015-04-01 13:05:26 -0700494 private void scheduleEventHandlerIfNotScheduled(Event event) {
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700495 synchronized (threadSchedulerLock) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700496 eventQueue.add(event);
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700497 numOfEventsQueued++;
498
499 if ((numOfHandlerScheduled - numOfHandlerExecution) == 0) {
500 //No pending scheduled event handling threads. So start a new one.
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700501 eventHandlerFuture = executorService
502 .schedule(eventHandler, 100, TimeUnit.MILLISECONDS);
503 numOfHandlerScheduled++;
504 }
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700505 log.trace("numOfEventsQueued {}, numOfEventHanlderScheduled {}",
506 numOfEventsQueued,
507 numOfHandlerScheduled);
sanghob35a6192015-04-01 13:05:26 -0700508 }
sanghob35a6192015-04-01 13:05:26 -0700509 }
510
511 private class InternalEventHandler implements Runnable {
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700512 @Override
sanghob35a6192015-04-01 13:05:26 -0700513 public void run() {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700514 try {
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700515 while (true) {
516 Event event = null;
517 synchronized (threadSchedulerLock) {
518 if (!eventQueue.isEmpty()) {
519 event = eventQueue.poll();
520 numOfEventsExecuted++;
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700521 } else {
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700522 numOfHandlerExecution++;
523 log.debug("numOfHandlerExecution {} numOfEventsExecuted {}",
524 numOfHandlerExecution, numOfEventsExecuted);
525 break;
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700526 }
sangho20eff1d2015-04-13 15:15:58 -0700527 }
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700528 if (event.type() == LinkEvent.Type.LINK_ADDED) {
529 processLinkAdded((Link) event.subject());
530 } else if (event.type() == LinkEvent.Type.LINK_REMOVED) {
531 processLinkRemoved((Link) event.subject());
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700532 } else if (event.type() == DeviceEvent.Type.DEVICE_ADDED ||
533 event.type() == DeviceEvent.Type.DEVICE_AVAILABILITY_CHANGED ||
534 event.type() == DeviceEvent.Type.DEVICE_UPDATED) {
535 if (deviceService.isAvailable(((Device) event.subject()).id())) {
Saurav Das837e0bb2015-10-30 17:45:38 -0700536 log.info("Processing device event {} for available device {}",
537 event.type(), ((Device) event.subject()).id());
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700538 processDeviceAdded((Device) event.subject());
539 }
540 } else if (event.type() == DeviceEvent.Type.PORT_REMOVED) {
541 processPortRemoved((Device) event.subject(),
542 ((DeviceEvent) event).port());
543 } else {
544 log.warn("Unhandled event type: {}", event.type());
545 }
sanghob35a6192015-04-01 13:05:26 -0700546 }
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700547 } catch (Exception e) {
548 log.error("SegmentRouting event handler "
549 + "thread thrown an exception: {}", e);
sanghob35a6192015-04-01 13:05:26 -0700550 }
sanghob35a6192015-04-01 13:05:26 -0700551 }
552 }
553
sanghob35a6192015-04-01 13:05:26 -0700554 private void processLinkAdded(Link link) {
555 log.debug("A new link {} was added", link.toString());
556
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700557 //Irrespective whether the local is a MASTER or not for this device,
558 //create group handler instance and push default TTP flow rules.
559 //Because in a multi-instance setup, instances can initiate
560 //groups for any devices. Also the default TTP rules are needed
561 //to be pushed before inserting any IP table entries for any device
562 DefaultGroupHandler groupHandler = groupHandlerMap.get(link.src()
563 .deviceId());
564 if (groupHandler != null) {
565 groupHandler.linkUp(link);
566 } else {
567 Device device = deviceService.getDevice(link.src().deviceId());
568 if (device != null) {
569 log.warn("processLinkAdded: Link Added "
570 + "Notification without Device Added "
571 + "event, still handling it");
572 processDeviceAdded(device);
573 groupHandler = groupHandlerMap.get(link.src()
574 .deviceId());
sanghob35a6192015-04-01 13:05:26 -0700575 groupHandler.linkUp(link);
576 }
577 }
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700578
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700579 log.trace("Starting optimized route population process");
580 defaultRoutingHandler.populateRoutingRulesForLinkStatusChange(null);
581 //log.trace("processLinkAdded: re-starting route population process");
582 //defaultRoutingHandler.startPopulationProcess();
sanghob35a6192015-04-01 13:05:26 -0700583 }
584
585 private void processLinkRemoved(Link link) {
586 log.debug("A link {} was removed", link.toString());
sangho834e4b02015-05-01 09:38:25 -0700587 DefaultGroupHandler groupHandler = groupHandlerMap.get(link.src().deviceId());
588 if (groupHandler != null) {
589 groupHandler.portDown(link.src().port());
590 }
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700591 log.trace("Starting optimized route population process");
592 defaultRoutingHandler.populateRoutingRulesForLinkStatusChange(link);
593 //log.trace("processLinkRemoved: re-starting route population process");
594 //defaultRoutingHandler.startPopulationProcess();
sanghob35a6192015-04-01 13:05:26 -0700595 }
596
597 private void processDeviceAdded(Device device) {
598 log.debug("A new device with ID {} was added", device.id());
Saurav Das837e0bb2015-10-30 17:45:38 -0700599 // Irrespective of whether the local is a MASTER or not for this device,
600 // we need to create a SR-group-handler instance. This is because in a
601 // multi-instance setup, any instance can initiate forwarding/next-objectives
602 // for any switch (even if this instance is a SLAVE or not even connected
603 // to the switch). To handle this, a default-group-handler instance is necessary
604 // per switch.
Charles Chanc42e84e2015-10-20 16:24:19 -0700605 DefaultGroupHandler groupHandler = DefaultGroupHandler.
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700606 createGroupHandler(device.id(),
607 appId,
608 deviceConfiguration,
609 linkService,
610 flowObjectiveService,
Charles Chanc42e84e2015-10-20 16:24:19 -0700611 nsNextObjStore,
612 subnetNextObjStore);
613 groupHandlerMap.put(device.id(), groupHandler);
Saurav Das837e0bb2015-10-30 17:45:38 -0700614
615 // Also, in some cases, drivers may need extra
616 // information to process rules (eg. Router IP/MAC); and so, we send
617 // port addressing rules to the driver as well irrespective of whether
618 // this instance is the master or not.
Saurav Das822c4e22015-10-23 10:51:11 -0700619 defaultRoutingHandler.populatePortAddressingRules(device.id());
Charles Chanc42e84e2015-10-20 16:24:19 -0700620
621 if (mastershipService.isLocalMaster(device.id())) {
622 groupHandler.createGroupsFromSubnetConfig();
623 }
sanghob35a6192015-04-01 13:05:26 -0700624 }
625
626 private void processPortRemoved(Device device, Port port) {
627 log.debug("Port {} was removed", port.toString());
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700628 DefaultGroupHandler groupHandler = groupHandlerMap.get(device.id());
sanghob35a6192015-04-01 13:05:26 -0700629 if (groupHandler != null) {
630 groupHandler.portDown(port.number());
631 }
632 }
sangho1e575652015-05-14 00:39:53 -0700633
Charles Chand6832882015-10-05 17:50:33 -0700634 private class InternalConfigListener implements NetworkConfigListener {
Charles Chan4636be02015-10-07 14:21:45 -0700635 SegmentRoutingManager segmentRoutingManager;
636
637 public InternalConfigListener(SegmentRoutingManager srMgr) {
638 this.segmentRoutingManager = srMgr;
639 }
640
641 public void configureNetwork() {
642 deviceConfiguration = new DeviceConfiguration(segmentRoutingManager.cfgService);
643
644 arpHandler = new ArpHandler(segmentRoutingManager);
645 icmpHandler = new IcmpHandler(segmentRoutingManager);
646 ipHandler = new IpHandler(segmentRoutingManager);
647 routingRulePopulator = new RoutingRulePopulator(segmentRoutingManager);
648 defaultRoutingHandler = new DefaultRoutingHandler(segmentRoutingManager);
649
650 tunnelHandler = new TunnelHandler(linkService, deviceConfiguration,
651 groupHandlerMap, tunnelStore);
652 policyHandler = new PolicyHandler(appId, deviceConfiguration,
653 flowObjectiveService,
654 tunnelHandler, policyStore);
655
Charles Chan4636be02015-10-07 14:21:45 -0700656 for (Device device : deviceService.getDevices()) {
Saurav Das837e0bb2015-10-30 17:45:38 -0700657 // Irrespective of whether the local is a MASTER or not for this device,
658 // we need to create a SR-group-handler instance. This is because in a
659 // multi-instance setup, any instance can initiate forwarding/next-objectives
660 // for any switch (even if this instance is a SLAVE or not even connected
661 // to the switch). To handle this, a default-group-handler instance is necessary
662 // per switch.
Charles Chan4636be02015-10-07 14:21:45 -0700663 DefaultGroupHandler groupHandler = DefaultGroupHandler
664 .createGroupHandler(device.id(), appId,
665 deviceConfiguration, linkService,
666 flowObjectiveService,
Charles Chanc42e84e2015-10-20 16:24:19 -0700667 nsNextObjStore,
668 subnetNextObjStore);
Charles Chan4636be02015-10-07 14:21:45 -0700669 groupHandlerMap.put(device.id(), groupHandler);
Saurav Das837e0bb2015-10-30 17:45:38 -0700670
671 // Also, in some cases, drivers may need extra
672 // information to process rules (eg. Router IP/MAC); and so, we send
673 // port addressing rules to the driver as well, irrespective of whether
674 // this instance is the master or not.
Saurav Das822c4e22015-10-23 10:51:11 -0700675 defaultRoutingHandler.populatePortAddressingRules(device.id());
Charles Chanc42e84e2015-10-20 16:24:19 -0700676
677 if (mastershipService.isLocalMaster(device.id())) {
678 groupHandler.createGroupsFromSubnetConfig();
679 }
Charles Chan4636be02015-10-07 14:21:45 -0700680 }
681
682 defaultRoutingHandler.startPopulationProcess();
683 }
684
Charles Chand6832882015-10-05 17:50:33 -0700685 @Override
686 public void event(NetworkConfigEvent event) {
Charles Chanb8e10c82015-10-14 11:24:40 -0700687 if (event.configClass().equals(SegmentRoutingConfig.class)) {
688 if (event.type() == NetworkConfigEvent.Type.CONFIG_ADDED) {
689 log.info("Network configuration added.");
690 configureNetwork();
691 }
692 if (event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED) {
693 log.info("Network configuration updated.");
694 // TODO support dynamic configuration
695 }
Charles Chand6832882015-10-05 17:50:33 -0700696 }
697 }
698 }
sanghob35a6192015-04-01 13:05:26 -0700699}