blob: 592c0b14e67b81cfc38575a1992570470c4c6e41 [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;
Charles Chanf4586112015-11-09 16:37:23 -080025import org.onlab.packet.MacAddress;
Saurav Das7c305372015-10-28 12:39:42 -070026import org.onlab.packet.VlanId;
Charles Chan77277672015-10-20 16:24:19 -070027import org.onlab.packet.IPv4;
28import org.onlab.packet.Ip4Address;
29import org.onlab.packet.Ip4Prefix;
30import org.onlab.packet.IpAddress;
31import org.onlab.packet.IpPrefix;
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -070032import org.onlab.util.KryoNamespace;
sangho80f11cb2015-04-01 13:05:26 -070033import org.onosproject.core.ApplicationId;
34import org.onosproject.core.CoreService;
35import org.onosproject.event.Event;
Charles Chan77277672015-10-20 16:24:19 -070036import org.onosproject.net.ConnectPoint;
Charles Chanf4586112015-11-09 16:37:23 -080037import org.onosproject.net.PortNumber;
Charles Chan72f556a2015-10-05 17:50:33 -070038import org.onosproject.net.config.ConfigFactory;
39import org.onosproject.net.config.NetworkConfigEvent;
40import org.onosproject.net.config.NetworkConfigRegistry;
41import org.onosproject.net.config.NetworkConfigListener;
42import org.onosproject.net.config.basics.SubjectFactories;
Charles Chanf4586112015-11-09 16:37:23 -080043import org.onosproject.net.flow.DefaultTrafficSelector;
44import org.onosproject.net.flow.DefaultTrafficTreatment;
45import org.onosproject.net.flow.TrafficSelector;
46import org.onosproject.net.flow.TrafficTreatment;
47import org.onosproject.net.flowobjective.DefaultForwardingObjective;
48import org.onosproject.net.flowobjective.ForwardingObjective;
49import org.onosproject.net.flowobjective.Objective;
50import org.onosproject.net.flowobjective.ObjectiveContext;
51import org.onosproject.net.flowobjective.ObjectiveError;
52import org.onosproject.net.host.HostEvent;
53import org.onosproject.net.host.HostListener;
Charles Chande6655c2015-12-23 00:15:11 -080054import org.onosproject.net.packet.PacketPriority;
Charles Chan319d1a22015-11-03 10:42:14 -080055import org.onosproject.segmentrouting.config.DeviceConfigNotFoundException;
56import org.onosproject.segmentrouting.config.DeviceConfiguration;
Charles Chan72f556a2015-10-05 17:50:33 -070057import org.onosproject.segmentrouting.config.SegmentRoutingConfig;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070058import org.onosproject.segmentrouting.grouphandler.DefaultGroupHandler;
59import org.onosproject.segmentrouting.grouphandler.NeighborSet;
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -070060import org.onosproject.segmentrouting.grouphandler.NeighborSetNextObjectiveStoreKey;
Saurav Das2d94d312015-11-24 23:21:05 -080061import org.onosproject.segmentrouting.grouphandler.PortNextObjectiveStoreKey;
sangho80f11cb2015-04-01 13:05:26 -070062import org.onosproject.mastership.MastershipService;
63import org.onosproject.net.Device;
64import org.onosproject.net.DeviceId;
65import org.onosproject.net.Link;
sangho80f11cb2015-04-01 13:05:26 -070066import org.onosproject.net.Port;
67import org.onosproject.net.device.DeviceEvent;
68import org.onosproject.net.device.DeviceListener;
69import org.onosproject.net.device.DeviceService;
Srikanth Vavilapalli64505482015-04-21 13:04:13 -070070import org.onosproject.net.flowobjective.FlowObjectiveService;
sangho80f11cb2015-04-01 13:05:26 -070071import org.onosproject.net.host.HostService;
sangho80f11cb2015-04-01 13:05:26 -070072import org.onosproject.net.link.LinkEvent;
73import org.onosproject.net.link.LinkListener;
74import org.onosproject.net.link.LinkService;
75import org.onosproject.net.packet.InboundPacket;
76import org.onosproject.net.packet.PacketContext;
77import org.onosproject.net.packet.PacketProcessor;
78import org.onosproject.net.packet.PacketService;
Charles Chan77277672015-10-20 16:24:19 -070079import org.onosproject.segmentrouting.grouphandler.SubnetNextObjectiveStoreKey;
Charles Chanb7f75ac2016-01-11 18:28:54 -080080import org.onosproject.segmentrouting.grouphandler.XConnectNextObjectiveStoreKey;
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
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -070088import java.net.URI;
Saurav Das7c305372015-10-28 12:39:42 -070089import java.util.Collections;
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -070090import java.util.HashSet;
sangho27462c62015-05-14 00:39:53 -070091import java.util.List;
sangho80f11cb2015-04-01 13:05:26 -070092import java.util.Map;
Charles Chande6655c2015-12-23 00:15:11 -080093import java.util.Optional;
Saurav Das7c305372015-10-28 12:39:42 -070094import java.util.Set;
sangho80f11cb2015-04-01 13:05:26 -070095import java.util.concurrent.ConcurrentHashMap;
96import java.util.concurrent.ConcurrentLinkedQueue;
97import java.util.concurrent.Executors;
98import java.util.concurrent.ScheduledExecutorService;
99import java.util.concurrent.ScheduledFuture;
100import java.util.concurrent.TimeUnit;
101
sangho27462c62015-05-14 00:39:53 -0700102@Service
sangho80f11cb2015-04-01 13:05:26 -0700103@Component(immediate = true)
Charles Chanb7f75ac2016-01-11 18:28:54 -0800104/**
105 * Segment routing manager.
106 */
sangho27462c62015-05-14 00:39:53 -0700107public class SegmentRoutingManager implements SegmentRoutingService {
sangho80f11cb2015-04-01 13:05:26 -0700108
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700109 private static Logger log = LoggerFactory
110 .getLogger(SegmentRoutingManager.class);
sangho80f11cb2015-04-01 13:05:26 -0700111
112 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
113 protected CoreService coreService;
114
115 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
sangho80f11cb2015-04-01 13:05:26 -0700116 protected PacketService packetService;
117
118 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
sangho80f11cb2015-04-01 13:05:26 -0700119 protected HostService hostService;
120
121 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
122 protected DeviceService deviceService;
123
124 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700125 protected FlowObjectiveService flowObjectiveService;
sangho80f11cb2015-04-01 13:05:26 -0700126
127 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
128 protected LinkService linkService;
129
130 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
sangho80f11cb2015-04-01 13:05:26 -0700131 protected MastershipService mastershipService;
sangho27462c62015-05-14 00:39:53 -0700132
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700133 protected ArpHandler arpHandler = null;
134 protected IcmpHandler icmpHandler = null;
135 protected IpHandler ipHandler = null;
136 protected RoutingRulePopulator routingRulePopulator = null;
sangho80f11cb2015-04-01 13:05:26 -0700137 protected ApplicationId appId;
sangho9b169e32015-04-14 16:27:13 -0700138 protected DeviceConfiguration deviceConfiguration = null;
sangho80f11cb2015-04-01 13:05:26 -0700139
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700140 private DefaultRoutingHandler defaultRoutingHandler = null;
sangho27462c62015-05-14 00:39:53 -0700141 private TunnelHandler tunnelHandler = null;
142 private PolicyHandler policyHandler = null;
Charles Chan2b078ae2015-10-14 11:24:40 -0700143 private InternalPacketProcessor processor = null;
144 private InternalLinkListener linkListener = null;
145 private InternalDeviceListener deviceListener = null;
sangho80f11cb2015-04-01 13:05:26 -0700146 private InternalEventHandler eventHandler = new InternalEventHandler();
147
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700148 private ScheduledExecutorService executorService = Executors
149 .newScheduledThreadPool(1);
sangho80f11cb2015-04-01 13:05:26 -0700150
Saurav Das2d94d312015-11-24 23:21:05 -0800151 @SuppressWarnings("unused")
sangho80f11cb2015-04-01 13:05:26 -0700152 private static ScheduledFuture<?> eventHandlerFuture = null;
Saurav Das2d94d312015-11-24 23:21:05 -0800153 @SuppressWarnings("rawtypes")
sangho80f11cb2015-04-01 13:05:26 -0700154 private ConcurrentLinkedQueue<Event> eventQueue = new ConcurrentLinkedQueue<Event>();
Charles Chanf4586112015-11-09 16:37:23 -0800155 private Map<DeviceId, DefaultGroupHandler> groupHandlerMap =
Charles Chanb7f75ac2016-01-11 18:28:54 -0800156 new ConcurrentHashMap<>();
157 /**
158 * Per device next objective ID store with (device id + neighbor set) as key.
159 */
160 public EventuallyConsistentMap<NeighborSetNextObjectiveStoreKey, Integer>
Charles Chanf4586112015-11-09 16:37:23 -0800161 nsNextObjStore = null;
Charles Chanb7f75ac2016-01-11 18:28:54 -0800162 /**
163 * Per device next objective ID store with (device id + subnet) as key.
164 */
165 public EventuallyConsistentMap<SubnetNextObjectiveStoreKey, Integer>
Charles Chanf4586112015-11-09 16:37:23 -0800166 subnetNextObjStore = null;
Charles Chanb7f75ac2016-01-11 18:28:54 -0800167 /**
168 * Per device next objective ID store with (device id + port) as key.
169 */
170 public EventuallyConsistentMap<PortNextObjectiveStoreKey, Integer>
Saurav Das2d94d312015-11-24 23:21:05 -0800171 portNextObjStore = null;
Charles Chanb7f75ac2016-01-11 18:28:54 -0800172 /**
173 * Per cross-connect objective ID store with VLAN ID as key.
174 */
175 public EventuallyConsistentMap<XConnectNextObjectiveStoreKey, Integer>
176 xConnectNextObjStore = null;
Saurav Das7c305372015-10-28 12:39:42 -0700177 // Per device, per-subnet assigned-vlans store, with (device id + subnet
178 // IPv4 prefix) as key
179 private EventuallyConsistentMap<SubnetAssignedVidStoreKey, VlanId>
Charles Chanb7f75ac2016-01-11 18:28:54 -0800180 subnetVidStore = null;
Saurav Das2d94d312015-11-24 23:21:05 -0800181 private EventuallyConsistentMap<String, Tunnel> tunnelStore = null;
182 private EventuallyConsistentMap<String, Policy> policyStore = null;
sangho4a5c42a2015-05-20 22:16:38 -0700183
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700184 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
185 protected StorageService storageService;
sangho80f11cb2015-04-01 13:05:26 -0700186
Charles Chan72f556a2015-10-05 17:50:33 -0700187 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
188 protected NetworkConfigRegistry cfgService;
189
Charles Chane7c61022015-10-07 14:21:45 -0700190 private final InternalConfigListener cfgListener =
191 new InternalConfigListener(this);
192
Saurav Das2d94d312015-11-24 23:21:05 -0800193 @SuppressWarnings({ "unchecked", "rawtypes" })
Charles Chan72f556a2015-10-05 17:50:33 -0700194 private final ConfigFactory cfgFactory =
195 new ConfigFactory(SubjectFactories.DEVICE_SUBJECT_FACTORY,
196 SegmentRoutingConfig.class,
197 "segmentrouting") {
198 @Override
199 public SegmentRoutingConfig createConfig() {
200 return new SegmentRoutingConfig();
201 }
202 };
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700203
Charles Chand4a99c52015-11-18 16:51:08 -0800204 private final InternalHostListener hostListener = new InternalHostListener();
Charles Chanf4586112015-11-09 16:37:23 -0800205
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700206 private Object threadSchedulerLock = new Object();
207 private static int numOfEventsQueued = 0;
208 private static int numOfEventsExecuted = 0;
sangho80f11cb2015-04-01 13:05:26 -0700209 private static int numOfHandlerExecution = 0;
210 private static int numOfHandlerScheduled = 0;
211
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700212 private KryoNamespace.Builder kryoBuilder = null;
213
Charles Chanb7f75ac2016-01-11 18:28:54 -0800214 /**
215 * The starting value of per-subnet VLAN ID assignment.
216 */
Saurav Das7c305372015-10-28 12:39:42 -0700217 private static final short ASSIGNED_VLAN_START = 4093;
Charles Chanb7f75ac2016-01-11 18:28:54 -0800218 /**
219 * The default VLAN ID assigned to the interfaces without subnet config.
220 */
Saurav Das7c305372015-10-28 12:39:42 -0700221 public static final short ASSIGNED_VLAN_NO_SUBNET = 4094;
222
sangho80f11cb2015-04-01 13:05:26 -0700223 @Activate
224 protected void activate() {
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700225 appId = coreService
226 .registerApplication("org.onosproject.segmentrouting");
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700227
228 kryoBuilder = new KryoNamespace.Builder()
229 .register(NeighborSetNextObjectiveStoreKey.class,
Charles Chan77277672015-10-20 16:24:19 -0700230 SubnetNextObjectiveStoreKey.class,
231 SubnetAssignedVidStoreKey.class,
sangho4a5c42a2015-05-20 22:16:38 -0700232 NeighborSet.class,
233 DeviceId.class,
234 URI.class,
235 WallClockTimestamp.class,
236 org.onosproject.cluster.NodeId.class,
237 HashSet.class,
238 Tunnel.class,
239 DefaultTunnel.class,
240 Policy.class,
241 TunnelPolicy.class,
Saurav Das7c305372015-10-28 12:39:42 -0700242 Policy.Type.class,
Charles Chan77277672015-10-20 16:24:19 -0700243 VlanId.class,
244 Ip4Address.class,
245 Ip4Prefix.class,
246 IpAddress.Version.class,
247 ConnectPoint.class
sangho4a5c42a2015-05-20 22:16:38 -0700248 );
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700249
250 log.debug("Creating EC map nsnextobjectivestore");
251 EventuallyConsistentMapBuilder<NeighborSetNextObjectiveStoreKey, Integer>
252 nsNextObjMapBuilder = storageService.eventuallyConsistentMapBuilder();
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700253 nsNextObjStore = nsNextObjMapBuilder
254 .withName("nsnextobjectivestore")
255 .withSerializer(kryoBuilder)
Madan Jampani675ae202015-06-24 19:05:56 -0700256 .withTimestampProvider((k, v) -> new WallClockTimestamp())
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700257 .build();
258 log.trace("Current size {}", nsNextObjStore.size());
259
Charles Chan77277672015-10-20 16:24:19 -0700260 log.debug("Creating EC map subnetnextobjectivestore");
261 EventuallyConsistentMapBuilder<SubnetNextObjectiveStoreKey, Integer>
262 subnetNextObjMapBuilder = storageService.eventuallyConsistentMapBuilder();
Charles Chan77277672015-10-20 16:24:19 -0700263 subnetNextObjStore = subnetNextObjMapBuilder
264 .withName("subnetnextobjectivestore")
265 .withSerializer(kryoBuilder)
266 .withTimestampProvider((k, v) -> new WallClockTimestamp())
267 .build();
268
Saurav Das2d94d312015-11-24 23:21:05 -0800269 log.debug("Creating EC map subnetnextobjectivestore");
270 EventuallyConsistentMapBuilder<PortNextObjectiveStoreKey, Integer>
271 portNextObjMapBuilder = storageService.eventuallyConsistentMapBuilder();
272 portNextObjStore = portNextObjMapBuilder
273 .withName("portnextobjectivestore")
274 .withSerializer(kryoBuilder)
275 .withTimestampProvider((k, v) -> new WallClockTimestamp())
276 .build();
277
Charles Chanb7f75ac2016-01-11 18:28:54 -0800278 log.debug("Creating EC map xconnectnextobjectivestore");
279 EventuallyConsistentMapBuilder<XConnectNextObjectiveStoreKey, Integer>
280 xConnectNextObjStoreBuilder = storageService.eventuallyConsistentMapBuilder();
281 xConnectNextObjStore = xConnectNextObjStoreBuilder
282 .withName("xconnectnextobjectivestore")
283 .withSerializer(kryoBuilder)
284 .withTimestampProvider((k, v) -> new WallClockTimestamp())
285 .build();
286
sangho4a5c42a2015-05-20 22:16:38 -0700287 EventuallyConsistentMapBuilder<String, Tunnel> tunnelMapBuilder =
288 storageService.eventuallyConsistentMapBuilder();
sangho4a5c42a2015-05-20 22:16:38 -0700289 tunnelStore = tunnelMapBuilder
290 .withName("tunnelstore")
291 .withSerializer(kryoBuilder)
Madan Jampani675ae202015-06-24 19:05:56 -0700292 .withTimestampProvider((k, v) -> new WallClockTimestamp())
sangho4a5c42a2015-05-20 22:16:38 -0700293 .build();
294
295 EventuallyConsistentMapBuilder<String, Policy> policyMapBuilder =
296 storageService.eventuallyConsistentMapBuilder();
sangho4a5c42a2015-05-20 22:16:38 -0700297 policyStore = policyMapBuilder
298 .withName("policystore")
299 .withSerializer(kryoBuilder)
Madan Jampani675ae202015-06-24 19:05:56 -0700300 .withTimestampProvider((k, v) -> new WallClockTimestamp())
sangho4a5c42a2015-05-20 22:16:38 -0700301 .build();
302
Saurav Das7c305372015-10-28 12:39:42 -0700303 EventuallyConsistentMapBuilder<SubnetAssignedVidStoreKey, VlanId>
304 subnetVidStoreMapBuilder = storageService.eventuallyConsistentMapBuilder();
Saurav Das7c305372015-10-28 12:39:42 -0700305 subnetVidStore = subnetVidStoreMapBuilder
306 .withName("subnetvidstore")
307 .withSerializer(kryoBuilder)
308 .withTimestampProvider((k, v) -> new WallClockTimestamp())
309 .build();
310
Charles Chan72f556a2015-10-05 17:50:33 -0700311 cfgService.addListener(cfgListener);
312 cfgService.registerConfigFactory(cfgFactory);
Charles Chan72f556a2015-10-05 17:50:33 -0700313
Charles Chanf4586112015-11-09 16:37:23 -0800314 hostService.addListener(hostListener);
315
Charles Chan2b078ae2015-10-14 11:24:40 -0700316 processor = new InternalPacketProcessor();
317 linkListener = new InternalLinkListener();
318 deviceListener = new InternalDeviceListener();
319
320 packetService.addProcessor(processor, PacketProcessor.director(2));
321 linkService.addListener(linkListener);
322 deviceService.addListener(deviceListener);
323
Charles Chande6655c2015-12-23 00:15:11 -0800324 // Request ARP packet-in
325 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
326 selector.matchEthType(Ethernet.TYPE_ARP);
327 packetService.requestPackets(selector.build(), PacketPriority.CONTROL, appId, Optional.empty());
328
Charles Chan2b078ae2015-10-14 11:24:40 -0700329 cfgListener.configureNetwork();
330
sangho80f11cb2015-04-01 13:05:26 -0700331 log.info("Started");
332 }
333
334 @Deactivate
335 protected void deactivate() {
Charles Chan72f556a2015-10-05 17:50:33 -0700336 cfgService.removeListener(cfgListener);
337 cfgService.unregisterConfigFactory(cfgFactory);
338
Charles Chande6655c2015-12-23 00:15:11 -0800339 // Withdraw ARP packet-in
340 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
341 selector.matchEthType(Ethernet.TYPE_ARP);
342 packetService.cancelPackets(selector.build(), PacketPriority.CONTROL, appId, Optional.empty());
343
sangho80f11cb2015-04-01 13:05:26 -0700344 packetService.removeProcessor(processor);
Charles Chan2b078ae2015-10-14 11:24:40 -0700345 linkService.removeListener(linkListener);
346 deviceService.removeListener(deviceListener);
sangho80f11cb2015-04-01 13:05:26 -0700347 processor = null;
Charles Chan2b078ae2015-10-14 11:24:40 -0700348 linkListener = null;
349 deviceService = null;
350
351 groupHandlerMap.clear();
352
sangho80f11cb2015-04-01 13:05:26 -0700353 log.info("Stopped");
354 }
355
sangho27462c62015-05-14 00:39:53 -0700356
357 @Override
358 public List<Tunnel> getTunnels() {
359 return tunnelHandler.getTunnels();
360 }
361
362 @Override
sanghobd812f82015-06-29 14:58:47 -0700363 public TunnelHandler.Result createTunnel(Tunnel tunnel) {
364 return tunnelHandler.createTunnel(tunnel);
sangho27462c62015-05-14 00:39:53 -0700365 }
366
367 @Override
sanghobd812f82015-06-29 14:58:47 -0700368 public TunnelHandler.Result removeTunnel(Tunnel tunnel) {
sangho27462c62015-05-14 00:39:53 -0700369 for (Policy policy: policyHandler.getPolicies()) {
370 if (policy.type() == Policy.Type.TUNNEL_FLOW) {
371 TunnelPolicy tunnelPolicy = (TunnelPolicy) policy;
372 if (tunnelPolicy.tunnelId().equals(tunnel.id())) {
373 log.warn("Cannot remove the tunnel used by a policy");
sanghobd812f82015-06-29 14:58:47 -0700374 return TunnelHandler.Result.TUNNEL_IN_USE;
sangho27462c62015-05-14 00:39:53 -0700375 }
376 }
377 }
sanghobd812f82015-06-29 14:58:47 -0700378 return tunnelHandler.removeTunnel(tunnel);
sangho27462c62015-05-14 00:39:53 -0700379 }
380
381 @Override
sanghobd812f82015-06-29 14:58:47 -0700382 public PolicyHandler.Result removePolicy(Policy policy) {
383 return policyHandler.removePolicy(policy);
sangho27462c62015-05-14 00:39:53 -0700384 }
385
386 @Override
sanghobd812f82015-06-29 14:58:47 -0700387 public PolicyHandler.Result createPolicy(Policy policy) {
388 return policyHandler.createPolicy(policy);
sangho27462c62015-05-14 00:39:53 -0700389 }
390
391 @Override
392 public List<Policy> getPolicies() {
393 return policyHandler.getPolicies();
394 }
395
sangho80f1f892015-05-19 11:57:42 -0700396 /**
397 * Returns the tunnel object with the tunnel ID.
398 *
399 * @param tunnelId Tunnel ID
400 * @return Tunnel reference
401 */
sangho27462c62015-05-14 00:39:53 -0700402 public Tunnel getTunnel(String tunnelId) {
403 return tunnelHandler.getTunnel(tunnelId);
404 }
405
sangho80f11cb2015-04-01 13:05:26 -0700406 /**
Saurav Das7c305372015-10-28 12:39:42 -0700407 * Returns the vlan-id assigned to the subnet configured for a device.
408 * If no vlan-id has been assigned, a new one is assigned out of a pool of ids,
409 * if and only if this controller instance is the master for the device.
410 * <p>
411 * USAGE: The assigned vlans are meant to be applied to untagged packets on those
412 * switches/pipelines that need this functionality. These vids are meant
413 * to be used internally within a switch, and thus need to be unique only
414 * on a switch level. Note that packets never go out on the wire with these
415 * vlans. Currently, vlan ids are assigned from value 4093 down.
416 * Vlan id 4094 expected to be used for all ports that are not assigned subnets.
417 * Vlan id 4095 is reserved and unused. Only a single vlan id is assigned
418 * per subnet.
sangho80f11cb2015-04-01 13:05:26 -0700419 *
Saurav Das7c305372015-10-28 12:39:42 -0700420 * @param deviceId switch dpid
421 * @param subnet IPv4 prefix for which assigned vlan is desired
422 * @return VlanId assigned for the subnet on the device, or
423 * null if no vlan assignment was found and this instance is not
424 * the master for the device.
sangho80f11cb2015-04-01 13:05:26 -0700425 */
Charles Chanb7f75ac2016-01-11 18:28:54 -0800426 // TODO: We should avoid assigning VLAN IDs that are used by VLAN cross-connection.
Saurav Das7c305372015-10-28 12:39:42 -0700427 public VlanId getSubnetAssignedVlanId(DeviceId deviceId, Ip4Prefix subnet) {
428 VlanId assignedVid = subnetVidStore.get(new SubnetAssignedVidStoreKey(
429 deviceId, subnet));
430 if (assignedVid != null) {
431 log.debug("Query for subnet:{} on device:{} returned assigned-vlan "
432 + "{}", subnet, deviceId, assignedVid);
433 return assignedVid;
434 }
435 //check mastership for the right to assign a vlan
436 if (!mastershipService.isLocalMaster(deviceId)) {
437 log.warn("This controller instance is not the master for device {}. "
438 + "Cannot assign vlan-id for subnet {}", deviceId, subnet);
439 return null;
440 }
441 // vlan assignment is expensive but done only once
Charles Chanc6ad7752015-10-29 14:58:10 -0700442 Set<Ip4Prefix> configuredSubnets = deviceConfiguration.getSubnets(deviceId);
Saurav Das7c305372015-10-28 12:39:42 -0700443 Set<Short> assignedVlans = new HashSet<>();
444 Set<Ip4Prefix> unassignedSubnets = new HashSet<>();
445 for (Ip4Prefix sub : configuredSubnets) {
446 VlanId v = subnetVidStore.get(new SubnetAssignedVidStoreKey(deviceId,
447 sub));
448 if (v != null) {
449 assignedVlans.add(v.toShort());
450 } else {
451 unassignedSubnets.add(sub);
452 }
453 }
454 short nextAssignedVlan = ASSIGNED_VLAN_START;
455 if (!assignedVlans.isEmpty()) {
456 nextAssignedVlan = (short) (Collections.min(assignedVlans) - 1);
457 }
458 for (Ip4Prefix unsub : unassignedSubnets) {
459 subnetVidStore.put(new SubnetAssignedVidStoreKey(deviceId, unsub),
460 VlanId.vlanId(nextAssignedVlan--));
461 log.info("Assigned vlan: {} to subnet: {} on device: {}",
462 nextAssignedVlan + 1, unsub, deviceId);
sangho80f11cb2015-04-01 13:05:26 -0700463 }
464
Saurav Das7c305372015-10-28 12:39:42 -0700465 return subnetVidStore.get(new SubnetAssignedVidStoreKey(deviceId, subnet));
sangho80f11cb2015-04-01 13:05:26 -0700466 }
467
sangho27462c62015-05-14 00:39:53 -0700468 /**
Saurav Das7c305372015-10-28 12:39:42 -0700469 * Returns the next objective ID for the given NeighborSet.
Saurav Das4c35fc42015-11-20 15:27:53 -0800470 * If the nextObjective does not exist, a new one is created and
Saurav Das2d94d312015-11-24 23:21:05 -0800471 * its id is returned.
sangho27462c62015-05-14 00:39:53 -0700472 *
sangho80f1f892015-05-19 11:57:42 -0700473 * @param deviceId Device ID
474 * @param ns NegighborSet
Saurav Das4c35fc42015-11-20 15:27:53 -0800475 * @param meta metadata passed into the creation of a Next Objective
476 * @return next objective ID or -1 if an error was encountered during the
477 * creation of the nextObjective
sangho27462c62015-05-14 00:39:53 -0700478 */
Saurav Das4c35fc42015-11-20 15:27:53 -0800479 public int getNextObjectiveId(DeviceId deviceId, NeighborSet ns,
480 TrafficSelector meta) {
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700481 if (groupHandlerMap.get(deviceId) != null) {
482 log.trace("getNextObjectiveId query in device {}", deviceId);
483 return groupHandlerMap
Saurav Das4c35fc42015-11-20 15:27:53 -0800484 .get(deviceId).getNextObjectiveId(ns, meta);
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700485 } else {
Saurav Das2d94d312015-11-24 23:21:05 -0800486 log.warn("getNextObjectiveId query - groupHandler for device {} "
487 + "not found", deviceId);
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700488 return -1;
489 }
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700490 }
491
Charles Chan77277672015-10-20 16:24:19 -0700492 /**
Saurav Das2d94d312015-11-24 23:21:05 -0800493 * Returns the next objective ID for the given subnet prefix. It is expected
494 * that the next-objective has been pre-created from configuration.
Charles Chan77277672015-10-20 16:24:19 -0700495 *
496 * @param deviceId Device ID
497 * @param prefix Subnet
Saurav Das2d94d312015-11-24 23:21:05 -0800498 * @return next objective ID or -1 if it was not found
Charles Chan77277672015-10-20 16:24:19 -0700499 */
500 public int getSubnetNextObjectiveId(DeviceId deviceId, IpPrefix prefix) {
501 if (groupHandlerMap.get(deviceId) != null) {
502 log.trace("getSubnetNextObjectiveId query in device {}", deviceId);
503 return groupHandlerMap
504 .get(deviceId).getSubnetNextObjectiveId(prefix);
505 } else {
Saurav Das2d94d312015-11-24 23:21:05 -0800506 log.warn("getSubnetNextObjectiveId query - groupHandler for "
507 + "device {} not found", deviceId);
508 return -1;
509 }
510 }
511
512 /**
513 * Returns the next objective ID for the given portNumber, given the treatment.
514 * There could be multiple different treatments to the same outport, which
515 * would result in different objectives. If the next object
516 * does not exist, a new one is created and its id is returned.
517 *
518 * @param deviceId Device ID
519 * @param portNum port number on device for which NextObjective is queried
520 * @param treatment the actions to apply on the packets (should include outport)
521 * @param meta metadata passed into the creation of a Next Objective if necessary
522 * @return next objective ID or -1 if it was not found
523 */
524 public int getPortNextObjectiveId(DeviceId deviceId, PortNumber portNum,
525 TrafficTreatment treatment,
526 TrafficSelector meta) {
527 DefaultGroupHandler ghdlr = groupHandlerMap.get(deviceId);
528 if (ghdlr != null) {
529 return ghdlr.getPortNextObjectiveId(portNum, treatment, meta);
530 } else {
Charles Chanb7f75ac2016-01-11 18:28:54 -0800531 log.warn("getPortNextObjectiveId query - groupHandler for device {}"
532 + " not found", deviceId);
533 return -1;
534 }
535 }
536
537 /**
538 * Returns the next objective ID of type broadcast associated with the VLAN
539 * cross-connection.
540 *
541 * @param deviceId Device ID for the cross-connection
542 * @param vlanId VLAN ID for the cross-connection
543 * @return next objective ID or -1 if it was not found
544 */
545 public int getXConnectNextObjectiveId(DeviceId deviceId, VlanId vlanId) {
546 DefaultGroupHandler ghdlr = groupHandlerMap.get(deviceId);
547 if (ghdlr != null) {
548 return ghdlr.getXConnectNextObjectiveId(vlanId);
549 } else {
550 log.warn("getPortNextObjectiveId query - groupHandler for device {}"
Saurav Das2d94d312015-11-24 23:21:05 -0800551 + " not found", deviceId);
Charles Chan77277672015-10-20 16:24:19 -0700552 return -1;
553 }
554 }
555
sangho80f11cb2015-04-01 13:05:26 -0700556 private class InternalPacketProcessor implements PacketProcessor {
sangho80f11cb2015-04-01 13:05:26 -0700557 @Override
558 public void process(PacketContext context) {
559
560 if (context.isHandled()) {
561 return;
562 }
563
564 InboundPacket pkt = context.inPacket();
565 Ethernet ethernet = pkt.parsed();
Saurav Das2d94d312015-11-24 23:21:05 -0800566 log.trace("Rcvd pktin: {}", ethernet);
sangho80f11cb2015-04-01 13:05:26 -0700567 if (ethernet.getEtherType() == Ethernet.TYPE_ARP) {
568 arpHandler.processPacketIn(pkt);
569 } else if (ethernet.getEtherType() == Ethernet.TYPE_IPV4) {
570 IPv4 ipPacket = (IPv4) ethernet.getPayload();
571 ipHandler.addToPacketBuffer(ipPacket);
572 if (ipPacket.getProtocol() == IPv4.PROTOCOL_ICMP) {
573 icmpHandler.processPacketIn(pkt);
574 } else {
575 ipHandler.processPacketIn(pkt);
576 }
577 }
578 }
579 }
580
581 private class InternalLinkListener implements LinkListener {
582 @Override
583 public void event(LinkEvent event) {
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700584 if (event.type() == LinkEvent.Type.LINK_ADDED
585 || event.type() == LinkEvent.Type.LINK_REMOVED) {
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700586 log.debug("Event {} received from Link Service", event.type());
sangho80f11cb2015-04-01 13:05:26 -0700587 scheduleEventHandlerIfNotScheduled(event);
588 }
589 }
590 }
591
592 private class InternalDeviceListener implements DeviceListener {
sangho80f11cb2015-04-01 13:05:26 -0700593 @Override
594 public void event(DeviceEvent event) {
sangho80f11cb2015-04-01 13:05:26 -0700595 switch (event.type()) {
596 case DEVICE_ADDED:
597 case PORT_REMOVED:
sanghofb7c7292015-04-13 15:15:58 -0700598 case DEVICE_UPDATED:
599 case DEVICE_AVAILABILITY_CHANGED:
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700600 log.debug("Event {} received from Device Service", event.type());
sangho80f11cb2015-04-01 13:05:26 -0700601 scheduleEventHandlerIfNotScheduled(event);
602 break;
603 default:
604 }
605 }
606 }
607
Saurav Das2d94d312015-11-24 23:21:05 -0800608 @SuppressWarnings("rawtypes")
sangho80f11cb2015-04-01 13:05:26 -0700609 private void scheduleEventHandlerIfNotScheduled(Event event) {
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700610 synchronized (threadSchedulerLock) {
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700611 eventQueue.add(event);
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700612 numOfEventsQueued++;
613
614 if ((numOfHandlerScheduled - numOfHandlerExecution) == 0) {
615 //No pending scheduled event handling threads. So start a new one.
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700616 eventHandlerFuture = executorService
617 .schedule(eventHandler, 100, TimeUnit.MILLISECONDS);
618 numOfHandlerScheduled++;
619 }
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700620 log.trace("numOfEventsQueued {}, numOfEventHanlderScheduled {}",
621 numOfEventsQueued,
622 numOfHandlerScheduled);
sangho80f11cb2015-04-01 13:05:26 -0700623 }
sangho80f11cb2015-04-01 13:05:26 -0700624 }
625
626 private class InternalEventHandler implements Runnable {
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700627 @Override
sangho80f11cb2015-04-01 13:05:26 -0700628 public void run() {
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700629 try {
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700630 while (true) {
Saurav Das2d94d312015-11-24 23:21:05 -0800631 @SuppressWarnings("rawtypes")
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700632 Event event = null;
633 synchronized (threadSchedulerLock) {
634 if (!eventQueue.isEmpty()) {
635 event = eventQueue.poll();
636 numOfEventsExecuted++;
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700637 } else {
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700638 numOfHandlerExecution++;
639 log.debug("numOfHandlerExecution {} numOfEventsExecuted {}",
640 numOfHandlerExecution, numOfEventsExecuted);
641 break;
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700642 }
sanghofb7c7292015-04-13 15:15:58 -0700643 }
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700644 if (event.type() == LinkEvent.Type.LINK_ADDED) {
645 processLinkAdded((Link) event.subject());
646 } else if (event.type() == LinkEvent.Type.LINK_REMOVED) {
647 processLinkRemoved((Link) event.subject());
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700648 } else if (event.type() == DeviceEvent.Type.DEVICE_ADDED ||
649 event.type() == DeviceEvent.Type.DEVICE_AVAILABILITY_CHANGED ||
650 event.type() == DeviceEvent.Type.DEVICE_UPDATED) {
Saurav Das62af8802015-12-04 10:52:59 -0800651 DeviceId deviceId = ((Device) event.subject()).id();
652 if (deviceService.isAvailable(deviceId)) {
Saurav Dasc28b3432015-10-30 17:45:38 -0700653 log.info("Processing device event {} for available device {}",
654 event.type(), ((Device) event.subject()).id());
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700655 processDeviceAdded((Device) event.subject());
Saurav Das62af8802015-12-04 10:52:59 -0800656 } /* else {
657 if (event.type() == DeviceEvent.Type.DEVICE_AVAILABILITY_CHANGED) {
658 // availability changed and not available - dev gone
659 DefaultGroupHandler groupHandler = groupHandlerMap.get(deviceId);
660 if (groupHandler != null) {
661 groupHandler.removeAllGroups();
662 }
663 }
664 }*/
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700665 } else if (event.type() == DeviceEvent.Type.PORT_REMOVED) {
666 processPortRemoved((Device) event.subject(),
667 ((DeviceEvent) event).port());
668 } else {
669 log.warn("Unhandled event type: {}", event.type());
670 }
sangho80f11cb2015-04-01 13:05:26 -0700671 }
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700672 } catch (Exception e) {
673 log.error("SegmentRouting event handler "
674 + "thread thrown an exception: {}", e);
sangho80f11cb2015-04-01 13:05:26 -0700675 }
sangho80f11cb2015-04-01 13:05:26 -0700676 }
677 }
678
sangho80f11cb2015-04-01 13:05:26 -0700679 private void processLinkAdded(Link link) {
680 log.debug("A new link {} was added", link.toString());
Charles Chan319d1a22015-11-03 10:42:14 -0800681 if (!deviceConfiguration.isConfigured(link.src().deviceId())) {
682 log.warn("Source device of this link is not configured.");
683 return;
684 }
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700685 //Irrespective whether the local is a MASTER or not for this device,
686 //create group handler instance and push default TTP flow rules.
687 //Because in a multi-instance setup, instances can initiate
688 //groups for any devices. Also the default TTP rules are needed
689 //to be pushed before inserting any IP table entries for any device
690 DefaultGroupHandler groupHandler = groupHandlerMap.get(link.src()
691 .deviceId());
692 if (groupHandler != null) {
Saurav Das4c35fc42015-11-20 15:27:53 -0800693 groupHandler.linkUp(link, mastershipService.isLocalMaster(
694 link.src().deviceId()));
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700695 } else {
696 Device device = deviceService.getDevice(link.src().deviceId());
697 if (device != null) {
698 log.warn("processLinkAdded: Link Added "
699 + "Notification without Device Added "
700 + "event, still handling it");
701 processDeviceAdded(device);
702 groupHandler = groupHandlerMap.get(link.src()
703 .deviceId());
Saurav Das4c35fc42015-11-20 15:27:53 -0800704 groupHandler.linkUp(link, mastershipService.isLocalMaster(device.id()));
sangho80f11cb2015-04-01 13:05:26 -0700705 }
706 }
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700707
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700708 log.trace("Starting optimized route population process");
709 defaultRoutingHandler.populateRoutingRulesForLinkStatusChange(null);
710 //log.trace("processLinkAdded: re-starting route population process");
711 //defaultRoutingHandler.startPopulationProcess();
sangho80f11cb2015-04-01 13:05:26 -0700712 }
713
714 private void processLinkRemoved(Link link) {
715 log.debug("A link {} was removed", link.toString());
sangho2165d222015-05-01 09:38:25 -0700716 DefaultGroupHandler groupHandler = groupHandlerMap.get(link.src().deviceId());
717 if (groupHandler != null) {
Saurav Das62af8802015-12-04 10:52:59 -0800718 groupHandler.portDown(link.src().port(),
719 mastershipService.isLocalMaster(link.src().deviceId()));
sangho2165d222015-05-01 09:38:25 -0700720 }
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700721 log.trace("Starting optimized route population process");
722 defaultRoutingHandler.populateRoutingRulesForLinkStatusChange(link);
723 //log.trace("processLinkRemoved: re-starting route population process");
724 //defaultRoutingHandler.startPopulationProcess();
sangho80f11cb2015-04-01 13:05:26 -0700725 }
726
727 private void processDeviceAdded(Device device) {
728 log.debug("A new device with ID {} was added", device.id());
Charles Chan319d1a22015-11-03 10:42:14 -0800729 if (deviceConfiguration == null || !deviceConfiguration.isConfigured(device.id())) {
Saurav Das8ec0ec42015-11-03 14:39:27 -0800730 log.warn("Device configuration uploading. Device {} will be "
731 + "processed after config completes.", device.id());
732 return;
733 }
Saurav Dasc28b3432015-10-30 17:45:38 -0700734 // Irrespective of whether the local is a MASTER or not for this device,
735 // we need to create a SR-group-handler instance. This is because in a
736 // multi-instance setup, any instance can initiate forwarding/next-objectives
737 // for any switch (even if this instance is a SLAVE or not even connected
738 // to the switch). To handle this, a default-group-handler instance is necessary
739 // per switch.
Saurav Das8ec0ec42015-11-03 14:39:27 -0800740 if (groupHandlerMap.get(device.id()) == null) {
Charles Chan319d1a22015-11-03 10:42:14 -0800741 DefaultGroupHandler groupHandler;
742 try {
743 groupHandler = DefaultGroupHandler.
744 createGroupHandler(device.id(),
745 appId,
746 deviceConfiguration,
747 linkService,
748 flowObjectiveService,
Charles Chande6655c2015-12-23 00:15:11 -0800749 this);
Charles Chan319d1a22015-11-03 10:42:14 -0800750 } catch (DeviceConfigNotFoundException e) {
751 log.warn(e.getMessage() + " Aborting processDeviceAdded.");
752 return;
753 }
Saurav Das8ec0ec42015-11-03 14:39:27 -0800754 groupHandlerMap.put(device.id(), groupHandler);
755 // Also, in some cases, drivers may need extra
756 // information to process rules (eg. Router IP/MAC); and so, we send
757 // port addressing rules to the driver as well irrespective of whether
758 // this instance is the master or not.
759 defaultRoutingHandler.populatePortAddressingRules(device.id());
Charles Chand4a99c52015-11-18 16:51:08 -0800760 hostListener.readInitialHosts();
Saurav Das8ec0ec42015-11-03 14:39:27 -0800761 }
Charles Chan77277672015-10-20 16:24:19 -0700762 if (mastershipService.isLocalMaster(device.id())) {
Saurav Das8ec0ec42015-11-03 14:39:27 -0800763 DefaultGroupHandler groupHandler = groupHandlerMap.get(device.id());
Charles Chan77277672015-10-20 16:24:19 -0700764 groupHandler.createGroupsFromSubnetConfig();
Charles Chanf4586112015-11-09 16:37:23 -0800765 routingRulePopulator.populateSubnetBroadcastRule(device.id());
Charles Chanb7f75ac2016-01-11 18:28:54 -0800766 groupHandler.createGroupsForXConnect(device.id());
767 routingRulePopulator.populateXConnectBroadcastRule(device.id());
Charles Chan77277672015-10-20 16:24:19 -0700768 }
sangho80f11cb2015-04-01 13:05:26 -0700769 }
770
771 private void processPortRemoved(Device device, Port port) {
772 log.debug("Port {} was removed", port.toString());
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700773 DefaultGroupHandler groupHandler = groupHandlerMap.get(device.id());
sangho80f11cb2015-04-01 13:05:26 -0700774 if (groupHandler != null) {
Saurav Das62af8802015-12-04 10:52:59 -0800775 groupHandler.portDown(port.number(),
776 mastershipService.isLocalMaster(device.id()));
sangho80f11cb2015-04-01 13:05:26 -0700777 }
778 }
sangho27462c62015-05-14 00:39:53 -0700779
Charles Chan72f556a2015-10-05 17:50:33 -0700780 private class InternalConfigListener implements NetworkConfigListener {
Charles Chane7c61022015-10-07 14:21:45 -0700781 SegmentRoutingManager segmentRoutingManager;
782
Charles Chanb7f75ac2016-01-11 18:28:54 -0800783 /**
784 * Constructs the internal network config listener.
785 *
786 * @param srMgr segment routing manager
787 */
Charles Chane7c61022015-10-07 14:21:45 -0700788 public InternalConfigListener(SegmentRoutingManager srMgr) {
789 this.segmentRoutingManager = srMgr;
790 }
791
Charles Chanb7f75ac2016-01-11 18:28:54 -0800792 /**
793 * Reads network config and initializes related data structure accordingly.
794 */
Charles Chane7c61022015-10-07 14:21:45 -0700795 public void configureNetwork() {
796 deviceConfiguration = new DeviceConfiguration(segmentRoutingManager.cfgService);
797
798 arpHandler = new ArpHandler(segmentRoutingManager);
799 icmpHandler = new IcmpHandler(segmentRoutingManager);
800 ipHandler = new IpHandler(segmentRoutingManager);
801 routingRulePopulator = new RoutingRulePopulator(segmentRoutingManager);
802 defaultRoutingHandler = new DefaultRoutingHandler(segmentRoutingManager);
803
804 tunnelHandler = new TunnelHandler(linkService, deviceConfiguration,
805 groupHandlerMap, tunnelStore);
806 policyHandler = new PolicyHandler(appId, deviceConfiguration,
807 flowObjectiveService,
808 tunnelHandler, policyStore);
809
Charles Chane7c61022015-10-07 14:21:45 -0700810 for (Device device : deviceService.getDevices()) {
Saurav Dasc28b3432015-10-30 17:45:38 -0700811 // Irrespective of whether the local is a MASTER or not for this device,
812 // we need to create a SR-group-handler instance. This is because in a
813 // multi-instance setup, any instance can initiate forwarding/next-objectives
814 // for any switch (even if this instance is a SLAVE or not even connected
815 // to the switch). To handle this, a default-group-handler instance is necessary
816 // per switch.
Saurav Das8ec0ec42015-11-03 14:39:27 -0800817 if (groupHandlerMap.get(device.id()) == null) {
Charles Chan319d1a22015-11-03 10:42:14 -0800818 DefaultGroupHandler groupHandler;
819 try {
820 groupHandler = DefaultGroupHandler.
821 createGroupHandler(device.id(),
822 appId,
823 deviceConfiguration,
824 linkService,
825 flowObjectiveService,
Charles Chande6655c2015-12-23 00:15:11 -0800826 segmentRoutingManager);
Charles Chan319d1a22015-11-03 10:42:14 -0800827 } catch (DeviceConfigNotFoundException e) {
828 log.warn(e.getMessage() + " Aborting configureNetwork.");
829 return;
830 }
Saurav Das8ec0ec42015-11-03 14:39:27 -0800831 groupHandlerMap.put(device.id(), groupHandler);
Saurav Dasc28b3432015-10-30 17:45:38 -0700832
Saurav Das8ec0ec42015-11-03 14:39:27 -0800833 // Also, in some cases, drivers may need extra
834 // information to process rules (eg. Router IP/MAC); and so, we send
835 // port addressing rules to the driver as well, irrespective of whether
836 // this instance is the master or not.
837 defaultRoutingHandler.populatePortAddressingRules(device.id());
Charles Chand4a99c52015-11-18 16:51:08 -0800838 hostListener.readInitialHosts();
Saurav Das8ec0ec42015-11-03 14:39:27 -0800839 }
Charles Chan77277672015-10-20 16:24:19 -0700840 if (mastershipService.isLocalMaster(device.id())) {
Saurav Das8ec0ec42015-11-03 14:39:27 -0800841 DefaultGroupHandler groupHandler = groupHandlerMap.get(device.id());
Charles Chan77277672015-10-20 16:24:19 -0700842 groupHandler.createGroupsFromSubnetConfig();
Charles Chanf4586112015-11-09 16:37:23 -0800843 routingRulePopulator.populateSubnetBroadcastRule(device.id());
Charles Chanb7f75ac2016-01-11 18:28:54 -0800844 groupHandler.createGroupsForXConnect(device.id());
845 routingRulePopulator.populateXConnectBroadcastRule(device.id());
Charles Chan77277672015-10-20 16:24:19 -0700846 }
Charles Chane7c61022015-10-07 14:21:45 -0700847 }
848
849 defaultRoutingHandler.startPopulationProcess();
850 }
851
Charles Chan72f556a2015-10-05 17:50:33 -0700852 @Override
853 public void event(NetworkConfigEvent event) {
Charles Chan2b078ae2015-10-14 11:24:40 -0700854 if (event.configClass().equals(SegmentRoutingConfig.class)) {
855 if (event.type() == NetworkConfigEvent.Type.CONFIG_ADDED) {
856 log.info("Network configuration added.");
857 configureNetwork();
858 }
859 if (event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED) {
860 log.info("Network configuration updated.");
861 // TODO support dynamic configuration
862 }
Charles Chan72f556a2015-10-05 17:50:33 -0700863 }
864 }
865 }
Charles Chanf4586112015-11-09 16:37:23 -0800866
Charles Chand4a99c52015-11-18 16:51:08 -0800867 // TODO Move bridging table population to a separate class
Charles Chanf4586112015-11-09 16:37:23 -0800868 private class InternalHostListener implements HostListener {
Charles Chand4a99c52015-11-18 16:51:08 -0800869 private void readInitialHosts() {
870 hostService.getHosts().forEach(host -> {
871 MacAddress mac = host.mac();
872 VlanId vlanId = host.vlan();
873 DeviceId deviceId = host.location().deviceId();
874 PortNumber port = host.location().port();
875 Set<IpAddress> ips = host.ipAddresses();
876 log.debug("Host {}/{} is added at {}:{}", mac, vlanId, deviceId, port);
877
878 // Populate bridging table entry
879 ForwardingObjective.Builder fob =
Saurav Das2d94d312015-11-24 23:21:05 -0800880 getForwardingObjectiveBuilder(deviceId, mac, vlanId, port);
Charles Chand4a99c52015-11-18 16:51:08 -0800881 flowObjectiveService.forward(deviceId, fob.add(
882 new BridgingTableObjectiveContext(mac, vlanId)
883 ));
884
885 // Populate IP table entry
886 ips.forEach(ip -> {
887 if (ip.isIp4()) {
888 routingRulePopulator.populateIpRuleForHost(
889 deviceId, ip.getIp4Address(), mac, port);
890 }
891 });
892 });
893 }
894
Charles Chanf4586112015-11-09 16:37:23 -0800895 private ForwardingObjective.Builder getForwardingObjectiveBuilder(
Saurav Das2d94d312015-11-24 23:21:05 -0800896 DeviceId deviceId, MacAddress mac, VlanId vlanId,
897 PortNumber outport) {
Charles Chande6655c2015-12-23 00:15:11 -0800898 // Get assigned VLAN for the subnet
Saurav Das2d94d312015-11-24 23:21:05 -0800899 VlanId outvlan = null;
900 Ip4Prefix subnet = deviceConfiguration.getPortSubnet(deviceId, outport);
901 if (subnet == null) {
902 outvlan = VlanId.vlanId(ASSIGNED_VLAN_NO_SUBNET);
903 } else {
904 outvlan = getSubnetAssignedVlanId(deviceId, subnet);
905 }
Charles Chande6655c2015-12-23 00:15:11 -0800906
907 // match rule
908 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
909 sbuilder.matchEthDst(mac);
910 /*
911 * Note: for untagged packets, match on the assigned VLAN.
912 * for tagged packets, match on its incoming VLAN.
913 */
914 if (vlanId.equals(VlanId.NONE)) {
915 sbuilder.matchVlanId(outvlan);
916 } else {
917 sbuilder.matchVlanId(vlanId);
918 }
919
920 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
921 tbuilder.immediate().popVlan();
922 tbuilder.immediate().setOutput(outport);
923
924 // for switch pipelines that need it, provide outgoing vlan as metadata
Saurav Das2d94d312015-11-24 23:21:05 -0800925 TrafficSelector meta = DefaultTrafficSelector.builder()
926 .matchVlanId(outvlan).build();
927
928 // All forwarding is via Groups. Drivers can re-purpose to flow-actions if needed.
929 int portNextObjId = getPortNextObjectiveId(deviceId, outport,
930 tbuilder.build(),
931 meta);
Charles Chanf4586112015-11-09 16:37:23 -0800932
933 return DefaultForwardingObjective.builder()
934 .withFlag(ForwardingObjective.Flag.SPECIFIC)
935 .withSelector(sbuilder.build())
Saurav Das2d94d312015-11-24 23:21:05 -0800936 .nextStep(portNextObjId)
Charles Chanf4586112015-11-09 16:37:23 -0800937 .withPriority(100)
938 .fromApp(appId)
939 .makePermanent();
940 }
941
942 private void processHostAddedEvent(HostEvent event) {
943 MacAddress mac = event.subject().mac();
944 VlanId vlanId = event.subject().vlan();
945 DeviceId deviceId = event.subject().location().deviceId();
946 PortNumber port = event.subject().location().port();
947 Set<IpAddress> ips = event.subject().ipAddresses();
Saurav Das2d94d312015-11-24 23:21:05 -0800948 log.info("Host {}/{} is added at {}:{}", mac, vlanId, deviceId, port);
Charles Chanf4586112015-11-09 16:37:23 -0800949
Charles Chanf4586112015-11-09 16:37:23 -0800950 // Populate bridging table entry
Saurav Das2d94d312015-11-24 23:21:05 -0800951 log.debug("Populate L2 table entry for host {} at {}:{}",
952 mac, deviceId, port);
Charles Chanf4586112015-11-09 16:37:23 -0800953 ForwardingObjective.Builder fob =
Saurav Das2d94d312015-11-24 23:21:05 -0800954 getForwardingObjectiveBuilder(deviceId, mac, vlanId, port);
Charles Chanf4586112015-11-09 16:37:23 -0800955 flowObjectiveService.forward(deviceId, fob.add(
956 new BridgingTableObjectiveContext(mac, vlanId)
957 ));
958
959 // Populate IP table entry
960 ips.forEach(ip -> {
961 if (ip.isIp4()) {
962 routingRulePopulator.populateIpRuleForHost(
963 deviceId, ip.getIp4Address(), mac, port);
964 }
965 });
966 }
967
968 private void processHostRemoveEvent(HostEvent event) {
969 MacAddress mac = event.subject().mac();
970 VlanId vlanId = event.subject().vlan();
971 DeviceId deviceId = event.subject().location().deviceId();
972 PortNumber port = event.subject().location().port();
973 Set<IpAddress> ips = event.subject().ipAddresses();
974 log.debug("Host {}/{} is removed from {}:{}", mac, vlanId, deviceId, port);
975
976 // Revoke bridging table entry
977 ForwardingObjective.Builder fob =
Saurav Das2d94d312015-11-24 23:21:05 -0800978 getForwardingObjectiveBuilder(deviceId, mac, vlanId, port);
Charles Chanf4586112015-11-09 16:37:23 -0800979 flowObjectiveService.forward(deviceId, fob.remove(
980 new BridgingTableObjectiveContext(mac, vlanId)
981 ));
982
983 // Revoke IP table entry
984 ips.forEach(ip -> {
985 if (ip.isIp4()) {
986 routingRulePopulator.revokeIpRuleForHost(
987 deviceId, ip.getIp4Address(), mac, port);
988 }
989 });
990 }
991
992 private void processHostMovedEvent(HostEvent event) {
993 MacAddress mac = event.subject().mac();
994 VlanId vlanId = event.subject().vlan();
995 DeviceId prevDeviceId = event.prevSubject().location().deviceId();
996 PortNumber prevPort = event.prevSubject().location().port();
997 Set<IpAddress> prevIps = event.prevSubject().ipAddresses();
998 DeviceId newDeviceId = event.subject().location().deviceId();
999 PortNumber newPort = event.subject().location().port();
1000 Set<IpAddress> newIps = event.subject().ipAddresses();
1001 log.debug("Host {}/{} is moved from {}:{} to {}:{}",
1002 mac, vlanId, prevDeviceId, prevPort, newDeviceId, newPort);
1003
1004 // Revoke previous bridging table entry
1005 ForwardingObjective.Builder prevFob =
Saurav Das2d94d312015-11-24 23:21:05 -08001006 getForwardingObjectiveBuilder(prevDeviceId, mac, vlanId, prevPort);
Charles Chanf4586112015-11-09 16:37:23 -08001007 flowObjectiveService.forward(prevDeviceId, prevFob.remove(
1008 new BridgingTableObjectiveContext(mac, vlanId)
1009 ));
1010
1011 // Revoke previous IP table entry
1012 prevIps.forEach(ip -> {
1013 if (ip.isIp4()) {
1014 routingRulePopulator.revokeIpRuleForHost(
1015 prevDeviceId, ip.getIp4Address(), mac, prevPort);
1016 }
1017 });
1018
1019 // Populate new bridging table entry
1020 ForwardingObjective.Builder newFob =
Saurav Das2d94d312015-11-24 23:21:05 -08001021 getForwardingObjectiveBuilder(newDeviceId, mac, vlanId, newPort);
Charles Chanf4586112015-11-09 16:37:23 -08001022 flowObjectiveService.forward(newDeviceId, newFob.add(
1023 new BridgingTableObjectiveContext(mac, vlanId)
1024 ));
1025
1026 // Populate new IP table entry
1027 newIps.forEach(ip -> {
1028 if (ip.isIp4()) {
1029 routingRulePopulator.populateIpRuleForHost(
1030 newDeviceId, ip.getIp4Address(), mac, newPort);
1031 }
1032 });
1033 }
1034
1035 private void processHostUpdatedEvent(HostEvent event) {
1036 MacAddress mac = event.subject().mac();
1037 VlanId vlanId = event.subject().vlan();
1038 DeviceId prevDeviceId = event.prevSubject().location().deviceId();
1039 PortNumber prevPort = event.prevSubject().location().port();
1040 Set<IpAddress> prevIps = event.prevSubject().ipAddresses();
1041 DeviceId newDeviceId = event.subject().location().deviceId();
1042 PortNumber newPort = event.subject().location().port();
1043 Set<IpAddress> newIps = event.subject().ipAddresses();
1044 log.debug("Host {}/{} is updated", mac, vlanId);
1045
1046 // Revoke previous IP table entry
1047 prevIps.forEach(ip -> {
1048 if (ip.isIp4()) {
1049 routingRulePopulator.revokeIpRuleForHost(
1050 prevDeviceId, ip.getIp4Address(), mac, prevPort);
1051 }
1052 });
1053
1054 // Populate new IP table entry
1055 newIps.forEach(ip -> {
1056 if (ip.isIp4()) {
1057 routingRulePopulator.populateIpRuleForHost(
1058 newDeviceId, ip.getIp4Address(), mac, newPort);
1059 }
1060 });
1061 }
1062
1063 @Override
1064 public void event(HostEvent event) {
1065 // Do not proceed without mastership
1066 DeviceId deviceId = event.subject().location().deviceId();
1067 if (!mastershipService.isLocalMaster(deviceId)) {
1068 return;
1069 }
1070
1071 switch (event.type()) {
1072 case HOST_ADDED:
1073 processHostAddedEvent(event);
1074 break;
1075 case HOST_MOVED:
1076 processHostMovedEvent(event);
1077 break;
1078 case HOST_REMOVED:
1079 processHostRemoveEvent(event);
1080 break;
1081 case HOST_UPDATED:
1082 processHostUpdatedEvent(event);
1083 break;
1084 default:
1085 log.warn("Unsupported host event type: {}", event.type());
1086 break;
1087 }
1088 }
1089 }
1090
1091 private static class BridgingTableObjectiveContext implements ObjectiveContext {
1092 final MacAddress mac;
1093 final VlanId vlanId;
1094
1095 BridgingTableObjectiveContext(MacAddress mac, VlanId vlanId) {
1096 this.mac = mac;
1097 this.vlanId = vlanId;
1098 }
1099
1100 @Override
1101 public void onSuccess(Objective objective) {
1102 if (objective.op() == Objective.Operation.ADD) {
1103 log.debug("Successfully populate bridging table entry for {}/{}",
1104 mac, vlanId);
1105 } else {
1106 log.debug("Successfully revoke bridging table entry for {}/{}",
1107 mac, vlanId);
1108 }
1109 }
1110
1111 @Override
1112 public void onError(Objective objective, ObjectiveError error) {
1113 if (objective.op() == Objective.Operation.ADD) {
1114 log.debug("Fail to populate bridging table entry for {}/{}. {}",
1115 mac, vlanId, error);
1116 } else {
1117 log.debug("Fail to revoke bridging table entry for {}/{}. {}",
1118 mac, vlanId, error);
1119 }
1120 }
1121 }
sangho80f11cb2015-04-01 13:05:26 -07001122}