blob: 32e03decec9df9972e67847c8202e672098812f2 [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 Chan82ab1932016-01-30 23:22:37 -080057import org.onosproject.segmentrouting.config.SegmentRoutingDeviceConfig;
58import org.onosproject.segmentrouting.config.SegmentRoutingAppConfig;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070059import org.onosproject.segmentrouting.grouphandler.DefaultGroupHandler;
60import org.onosproject.segmentrouting.grouphandler.NeighborSet;
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -070061import org.onosproject.segmentrouting.grouphandler.NeighborSetNextObjectiveStoreKey;
Saurav Das2d94d312015-11-24 23:21:05 -080062import org.onosproject.segmentrouting.grouphandler.PortNextObjectiveStoreKey;
sangho80f11cb2015-04-01 13:05:26 -070063import org.onosproject.mastership.MastershipService;
64import org.onosproject.net.Device;
65import org.onosproject.net.DeviceId;
66import org.onosproject.net.Link;
sangho80f11cb2015-04-01 13:05:26 -070067import org.onosproject.net.Port;
68import org.onosproject.net.device.DeviceEvent;
69import org.onosproject.net.device.DeviceListener;
70import org.onosproject.net.device.DeviceService;
Srikanth Vavilapalli64505482015-04-21 13:04:13 -070071import org.onosproject.net.flowobjective.FlowObjectiveService;
sangho80f11cb2015-04-01 13:05:26 -070072import org.onosproject.net.host.HostService;
sangho80f11cb2015-04-01 13:05:26 -070073import org.onosproject.net.link.LinkEvent;
74import org.onosproject.net.link.LinkListener;
75import org.onosproject.net.link.LinkService;
76import org.onosproject.net.packet.InboundPacket;
77import org.onosproject.net.packet.PacketContext;
78import org.onosproject.net.packet.PacketProcessor;
79import org.onosproject.net.packet.PacketService;
Charles Chan77277672015-10-20 16:24:19 -070080import org.onosproject.segmentrouting.grouphandler.SubnetNextObjectiveStoreKey;
Charles Chanb7f75ac2016-01-11 18:28:54 -080081import org.onosproject.segmentrouting.grouphandler.XConnectNextObjectiveStoreKey;
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -070082import org.onosproject.store.service.EventuallyConsistentMap;
83import org.onosproject.store.service.EventuallyConsistentMapBuilder;
84import org.onosproject.store.service.StorageService;
85import org.onosproject.store.service.WallClockTimestamp;
sangho80f11cb2015-04-01 13:05:26 -070086import org.slf4j.Logger;
87import org.slf4j.LoggerFactory;
88
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -070089import java.net.URI;
Saurav Das7c305372015-10-28 12:39:42 -070090import java.util.Collections;
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -070091import java.util.HashSet;
sangho27462c62015-05-14 00:39:53 -070092import java.util.List;
sangho80f11cb2015-04-01 13:05:26 -070093import java.util.Map;
Charles Chande6655c2015-12-23 00:15:11 -080094import java.util.Optional;
Saurav Das7c305372015-10-28 12:39:42 -070095import java.util.Set;
sangho80f11cb2015-04-01 13:05:26 -070096import java.util.concurrent.ConcurrentHashMap;
97import java.util.concurrent.ConcurrentLinkedQueue;
98import java.util.concurrent.Executors;
99import java.util.concurrent.ScheduledExecutorService;
100import java.util.concurrent.ScheduledFuture;
101import java.util.concurrent.TimeUnit;
102
sangho27462c62015-05-14 00:39:53 -0700103@Service
sangho80f11cb2015-04-01 13:05:26 -0700104@Component(immediate = true)
Charles Chanb7f75ac2016-01-11 18:28:54 -0800105/**
106 * Segment routing manager.
107 */
sangho27462c62015-05-14 00:39:53 -0700108public class SegmentRoutingManager implements SegmentRoutingService {
sangho80f11cb2015-04-01 13:05:26 -0700109
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700110 private static Logger log = LoggerFactory
111 .getLogger(SegmentRoutingManager.class);
sangho80f11cb2015-04-01 13:05:26 -0700112
113 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
114 protected CoreService coreService;
115
116 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
sangho80f11cb2015-04-01 13:05:26 -0700117 protected PacketService packetService;
118
119 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
sangho80f11cb2015-04-01 13:05:26 -0700120 protected HostService hostService;
121
122 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
123 protected DeviceService deviceService;
124
125 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700126 protected FlowObjectiveService flowObjectiveService;
sangho80f11cb2015-04-01 13:05:26 -0700127
128 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
129 protected LinkService linkService;
130
131 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
sangho80f11cb2015-04-01 13:05:26 -0700132 protected MastershipService mastershipService;
sangho27462c62015-05-14 00:39:53 -0700133
Charles Chan82ab1932016-01-30 23:22:37 -0800134 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
135 protected StorageService storageService;
136
137 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
138 protected NetworkConfigRegistry cfgService;
139
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700140 protected ArpHandler arpHandler = null;
141 protected IcmpHandler icmpHandler = null;
142 protected IpHandler ipHandler = null;
143 protected RoutingRulePopulator routingRulePopulator = null;
sangho80f11cb2015-04-01 13:05:26 -0700144 protected ApplicationId appId;
sangho9b169e32015-04-14 16:27:13 -0700145 protected DeviceConfiguration deviceConfiguration = null;
sangho80f11cb2015-04-01 13:05:26 -0700146
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700147 private DefaultRoutingHandler defaultRoutingHandler = null;
sangho27462c62015-05-14 00:39:53 -0700148 private TunnelHandler tunnelHandler = null;
149 private PolicyHandler policyHandler = null;
Charles Chan2b078ae2015-10-14 11:24:40 -0700150 private InternalPacketProcessor processor = null;
151 private InternalLinkListener linkListener = null;
152 private InternalDeviceListener deviceListener = null;
Charles Chan82ab1932016-01-30 23:22:37 -0800153 private NetworkConfigEventHandler netcfgHandler = null;
sangho80f11cb2015-04-01 13:05:26 -0700154 private InternalEventHandler eventHandler = new InternalEventHandler();
Charles Chan82ab1932016-01-30 23:22:37 -0800155 private final InternalHostListener hostListener = new InternalHostListener();
sangho80f11cb2015-04-01 13:05:26 -0700156
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700157 private ScheduledExecutorService executorService = Executors
158 .newScheduledThreadPool(1);
sangho80f11cb2015-04-01 13:05:26 -0700159
Saurav Das2d94d312015-11-24 23:21:05 -0800160 @SuppressWarnings("unused")
sangho80f11cb2015-04-01 13:05:26 -0700161 private static ScheduledFuture<?> eventHandlerFuture = null;
Saurav Das2d94d312015-11-24 23:21:05 -0800162 @SuppressWarnings("rawtypes")
sangho80f11cb2015-04-01 13:05:26 -0700163 private ConcurrentLinkedQueue<Event> eventQueue = new ConcurrentLinkedQueue<Event>();
Charles Chanf4586112015-11-09 16:37:23 -0800164 private Map<DeviceId, DefaultGroupHandler> groupHandlerMap =
Charles Chanb7f75ac2016-01-11 18:28:54 -0800165 new ConcurrentHashMap<>();
166 /**
167 * Per device next objective ID store with (device id + neighbor set) as key.
168 */
169 public EventuallyConsistentMap<NeighborSetNextObjectiveStoreKey, Integer>
Charles Chanf4586112015-11-09 16:37:23 -0800170 nsNextObjStore = null;
Charles Chanb7f75ac2016-01-11 18:28:54 -0800171 /**
172 * Per device next objective ID store with (device id + subnet) as key.
173 */
174 public EventuallyConsistentMap<SubnetNextObjectiveStoreKey, Integer>
Charles Chanf4586112015-11-09 16:37:23 -0800175 subnetNextObjStore = null;
Charles Chanb7f75ac2016-01-11 18:28:54 -0800176 /**
177 * Per device next objective ID store with (device id + port) as key.
178 */
179 public EventuallyConsistentMap<PortNextObjectiveStoreKey, Integer>
Saurav Das2d94d312015-11-24 23:21:05 -0800180 portNextObjStore = null;
Charles Chanb7f75ac2016-01-11 18:28:54 -0800181 /**
182 * Per cross-connect objective ID store with VLAN ID as key.
183 */
184 public EventuallyConsistentMap<XConnectNextObjectiveStoreKey, Integer>
185 xConnectNextObjStore = null;
Saurav Das7c305372015-10-28 12:39:42 -0700186 // Per device, per-subnet assigned-vlans store, with (device id + subnet
187 // IPv4 prefix) as key
188 private EventuallyConsistentMap<SubnetAssignedVidStoreKey, VlanId>
Charles Chanb7f75ac2016-01-11 18:28:54 -0800189 subnetVidStore = null;
Saurav Das2d94d312015-11-24 23:21:05 -0800190 private EventuallyConsistentMap<String, Tunnel> tunnelStore = null;
191 private EventuallyConsistentMap<String, Policy> policyStore = null;
sangho4a5c42a2015-05-20 22:16:38 -0700192
Charles Chane7c61022015-10-07 14:21:45 -0700193 private final InternalConfigListener cfgListener =
194 new InternalConfigListener(this);
195
Charles Chan82ab1932016-01-30 23:22:37 -0800196 private final ConfigFactory<DeviceId, SegmentRoutingDeviceConfig> cfgDeviceFactory =
197 new ConfigFactory<DeviceId, SegmentRoutingDeviceConfig>(SubjectFactories.DEVICE_SUBJECT_FACTORY,
198 SegmentRoutingDeviceConfig.class,
Charles Chan72f556a2015-10-05 17:50:33 -0700199 "segmentrouting") {
200 @Override
Charles Chan82ab1932016-01-30 23:22:37 -0800201 public SegmentRoutingDeviceConfig createConfig() {
202 return new SegmentRoutingDeviceConfig();
Charles Chan72f556a2015-10-05 17:50:33 -0700203 }
204 };
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700205
Charles Chan82ab1932016-01-30 23:22:37 -0800206 private final ConfigFactory<ApplicationId, SegmentRoutingAppConfig> cfgAppFactory =
207 new ConfigFactory<ApplicationId, SegmentRoutingAppConfig>(SubjectFactories.APP_SUBJECT_FACTORY,
208 SegmentRoutingAppConfig.class,
209 "segmentrouting") {
210 @Override
211 public SegmentRoutingAppConfig createConfig() {
212 return new SegmentRoutingAppConfig();
213 }
214 };
Charles Chanf4586112015-11-09 16:37:23 -0800215
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700216 private Object threadSchedulerLock = new Object();
217 private static int numOfEventsQueued = 0;
218 private static int numOfEventsExecuted = 0;
sangho80f11cb2015-04-01 13:05:26 -0700219 private static int numOfHandlerExecution = 0;
220 private static int numOfHandlerScheduled = 0;
221
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700222 private KryoNamespace.Builder kryoBuilder = null;
223
Charles Chanb7f75ac2016-01-11 18:28:54 -0800224 /**
225 * The starting value of per-subnet VLAN ID assignment.
226 */
Saurav Das7c305372015-10-28 12:39:42 -0700227 private static final short ASSIGNED_VLAN_START = 4093;
Charles Chanb7f75ac2016-01-11 18:28:54 -0800228 /**
229 * The default VLAN ID assigned to the interfaces without subnet config.
230 */
Saurav Das7c305372015-10-28 12:39:42 -0700231 public static final short ASSIGNED_VLAN_NO_SUBNET = 4094;
232
sangho80f11cb2015-04-01 13:05:26 -0700233 @Activate
234 protected void activate() {
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700235 appId = coreService
Charles Chan82ab1932016-01-30 23:22:37 -0800236 .registerApplication(SR_APP_ID);
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700237
238 kryoBuilder = new KryoNamespace.Builder()
239 .register(NeighborSetNextObjectiveStoreKey.class,
Charles Chan77277672015-10-20 16:24:19 -0700240 SubnetNextObjectiveStoreKey.class,
241 SubnetAssignedVidStoreKey.class,
sangho4a5c42a2015-05-20 22:16:38 -0700242 NeighborSet.class,
243 DeviceId.class,
244 URI.class,
245 WallClockTimestamp.class,
246 org.onosproject.cluster.NodeId.class,
247 HashSet.class,
248 Tunnel.class,
249 DefaultTunnel.class,
250 Policy.class,
251 TunnelPolicy.class,
Saurav Das7c305372015-10-28 12:39:42 -0700252 Policy.Type.class,
Charles Chan77277672015-10-20 16:24:19 -0700253 VlanId.class,
254 Ip4Address.class,
255 Ip4Prefix.class,
256 IpAddress.Version.class,
257 ConnectPoint.class
sangho4a5c42a2015-05-20 22:16:38 -0700258 );
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700259
260 log.debug("Creating EC map nsnextobjectivestore");
261 EventuallyConsistentMapBuilder<NeighborSetNextObjectiveStoreKey, Integer>
262 nsNextObjMapBuilder = storageService.eventuallyConsistentMapBuilder();
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700263 nsNextObjStore = nsNextObjMapBuilder
264 .withName("nsnextobjectivestore")
265 .withSerializer(kryoBuilder)
Madan Jampani675ae202015-06-24 19:05:56 -0700266 .withTimestampProvider((k, v) -> new WallClockTimestamp())
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700267 .build();
268 log.trace("Current size {}", nsNextObjStore.size());
269
Charles Chan77277672015-10-20 16:24:19 -0700270 log.debug("Creating EC map subnetnextobjectivestore");
271 EventuallyConsistentMapBuilder<SubnetNextObjectiveStoreKey, Integer>
272 subnetNextObjMapBuilder = storageService.eventuallyConsistentMapBuilder();
Charles Chan77277672015-10-20 16:24:19 -0700273 subnetNextObjStore = subnetNextObjMapBuilder
274 .withName("subnetnextobjectivestore")
275 .withSerializer(kryoBuilder)
276 .withTimestampProvider((k, v) -> new WallClockTimestamp())
277 .build();
278
Saurav Das2d94d312015-11-24 23:21:05 -0800279 log.debug("Creating EC map subnetnextobjectivestore");
280 EventuallyConsistentMapBuilder<PortNextObjectiveStoreKey, Integer>
281 portNextObjMapBuilder = storageService.eventuallyConsistentMapBuilder();
282 portNextObjStore = portNextObjMapBuilder
283 .withName("portnextobjectivestore")
284 .withSerializer(kryoBuilder)
285 .withTimestampProvider((k, v) -> new WallClockTimestamp())
286 .build();
287
Charles Chanb7f75ac2016-01-11 18:28:54 -0800288 log.debug("Creating EC map xconnectnextobjectivestore");
289 EventuallyConsistentMapBuilder<XConnectNextObjectiveStoreKey, Integer>
290 xConnectNextObjStoreBuilder = storageService.eventuallyConsistentMapBuilder();
291 xConnectNextObjStore = xConnectNextObjStoreBuilder
292 .withName("xconnectnextobjectivestore")
293 .withSerializer(kryoBuilder)
294 .withTimestampProvider((k, v) -> new WallClockTimestamp())
295 .build();
296
sangho4a5c42a2015-05-20 22:16:38 -0700297 EventuallyConsistentMapBuilder<String, Tunnel> tunnelMapBuilder =
298 storageService.eventuallyConsistentMapBuilder();
sangho4a5c42a2015-05-20 22:16:38 -0700299 tunnelStore = tunnelMapBuilder
300 .withName("tunnelstore")
301 .withSerializer(kryoBuilder)
Madan Jampani675ae202015-06-24 19:05:56 -0700302 .withTimestampProvider((k, v) -> new WallClockTimestamp())
sangho4a5c42a2015-05-20 22:16:38 -0700303 .build();
304
305 EventuallyConsistentMapBuilder<String, Policy> policyMapBuilder =
306 storageService.eventuallyConsistentMapBuilder();
sangho4a5c42a2015-05-20 22:16:38 -0700307 policyStore = policyMapBuilder
308 .withName("policystore")
309 .withSerializer(kryoBuilder)
Madan Jampani675ae202015-06-24 19:05:56 -0700310 .withTimestampProvider((k, v) -> new WallClockTimestamp())
sangho4a5c42a2015-05-20 22:16:38 -0700311 .build();
312
Saurav Das7c305372015-10-28 12:39:42 -0700313 EventuallyConsistentMapBuilder<SubnetAssignedVidStoreKey, VlanId>
314 subnetVidStoreMapBuilder = storageService.eventuallyConsistentMapBuilder();
Saurav Das7c305372015-10-28 12:39:42 -0700315 subnetVidStore = subnetVidStoreMapBuilder
316 .withName("subnetvidstore")
317 .withSerializer(kryoBuilder)
318 .withTimestampProvider((k, v) -> new WallClockTimestamp())
319 .build();
320
Charles Chan72f556a2015-10-05 17:50:33 -0700321 cfgService.addListener(cfgListener);
Charles Chan82ab1932016-01-30 23:22:37 -0800322 cfgService.registerConfigFactory(cfgDeviceFactory);
323 cfgService.registerConfigFactory(cfgAppFactory);
Charles Chanf4586112015-11-09 16:37:23 -0800324
Charles Chan2b078ae2015-10-14 11:24:40 -0700325 processor = new InternalPacketProcessor();
326 linkListener = new InternalLinkListener();
327 deviceListener = new InternalDeviceListener();
Charles Chan82ab1932016-01-30 23:22:37 -0800328 netcfgHandler = new NetworkConfigEventHandler(this);
Charles Chan2b078ae2015-10-14 11:24:40 -0700329
Charles Chan82ab1932016-01-30 23:22:37 -0800330 hostService.addListener(hostListener);
Charles Chan2b078ae2015-10-14 11:24:40 -0700331 packetService.addProcessor(processor, PacketProcessor.director(2));
332 linkService.addListener(linkListener);
333 deviceService.addListener(deviceListener);
334
Charles Chande6655c2015-12-23 00:15:11 -0800335 // Request ARP packet-in
336 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
337 selector.matchEthType(Ethernet.TYPE_ARP);
338 packetService.requestPackets(selector.build(), PacketPriority.CONTROL, appId, Optional.empty());
339
Charles Chan2b078ae2015-10-14 11:24:40 -0700340 cfgListener.configureNetwork();
341
sangho80f11cb2015-04-01 13:05:26 -0700342 log.info("Started");
343 }
344
345 @Deactivate
346 protected void deactivate() {
Charles Chan72f556a2015-10-05 17:50:33 -0700347 cfgService.removeListener(cfgListener);
Charles Chan82ab1932016-01-30 23:22:37 -0800348 cfgService.unregisterConfigFactory(cfgDeviceFactory);
349 cfgService.unregisterConfigFactory(cfgAppFactory);
Charles Chan72f556a2015-10-05 17:50:33 -0700350
Charles Chande6655c2015-12-23 00:15:11 -0800351 // Withdraw ARP packet-in
352 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
353 selector.matchEthType(Ethernet.TYPE_ARP);
354 packetService.cancelPackets(selector.build(), PacketPriority.CONTROL, appId, Optional.empty());
355
sangho80f11cb2015-04-01 13:05:26 -0700356 packetService.removeProcessor(processor);
Charles Chan2b078ae2015-10-14 11:24:40 -0700357 linkService.removeListener(linkListener);
358 deviceService.removeListener(deviceListener);
sangho80f11cb2015-04-01 13:05:26 -0700359 processor = null;
Charles Chan2b078ae2015-10-14 11:24:40 -0700360 linkListener = null;
361 deviceService = null;
362
363 groupHandlerMap.clear();
364
sangho80f11cb2015-04-01 13:05:26 -0700365 log.info("Stopped");
366 }
367
sangho27462c62015-05-14 00:39:53 -0700368
369 @Override
370 public List<Tunnel> getTunnels() {
371 return tunnelHandler.getTunnels();
372 }
373
374 @Override
sanghobd812f82015-06-29 14:58:47 -0700375 public TunnelHandler.Result createTunnel(Tunnel tunnel) {
376 return tunnelHandler.createTunnel(tunnel);
sangho27462c62015-05-14 00:39:53 -0700377 }
378
379 @Override
sanghobd812f82015-06-29 14:58:47 -0700380 public TunnelHandler.Result removeTunnel(Tunnel tunnel) {
sangho27462c62015-05-14 00:39:53 -0700381 for (Policy policy: policyHandler.getPolicies()) {
382 if (policy.type() == Policy.Type.TUNNEL_FLOW) {
383 TunnelPolicy tunnelPolicy = (TunnelPolicy) policy;
384 if (tunnelPolicy.tunnelId().equals(tunnel.id())) {
385 log.warn("Cannot remove the tunnel used by a policy");
sanghobd812f82015-06-29 14:58:47 -0700386 return TunnelHandler.Result.TUNNEL_IN_USE;
sangho27462c62015-05-14 00:39:53 -0700387 }
388 }
389 }
sanghobd812f82015-06-29 14:58:47 -0700390 return tunnelHandler.removeTunnel(tunnel);
sangho27462c62015-05-14 00:39:53 -0700391 }
392
393 @Override
sanghobd812f82015-06-29 14:58:47 -0700394 public PolicyHandler.Result removePolicy(Policy policy) {
395 return policyHandler.removePolicy(policy);
sangho27462c62015-05-14 00:39:53 -0700396 }
397
398 @Override
sanghobd812f82015-06-29 14:58:47 -0700399 public PolicyHandler.Result createPolicy(Policy policy) {
400 return policyHandler.createPolicy(policy);
sangho27462c62015-05-14 00:39:53 -0700401 }
402
403 @Override
404 public List<Policy> getPolicies() {
405 return policyHandler.getPolicies();
406 }
407
sangho80f1f892015-05-19 11:57:42 -0700408 /**
409 * Returns the tunnel object with the tunnel ID.
410 *
411 * @param tunnelId Tunnel ID
412 * @return Tunnel reference
413 */
sangho27462c62015-05-14 00:39:53 -0700414 public Tunnel getTunnel(String tunnelId) {
415 return tunnelHandler.getTunnel(tunnelId);
416 }
417
sangho80f11cb2015-04-01 13:05:26 -0700418 /**
Saurav Das7c305372015-10-28 12:39:42 -0700419 * Returns the vlan-id assigned to the subnet configured for a device.
420 * If no vlan-id has been assigned, a new one is assigned out of a pool of ids,
421 * if and only if this controller instance is the master for the device.
422 * <p>
423 * USAGE: The assigned vlans are meant to be applied to untagged packets on those
424 * switches/pipelines that need this functionality. These vids are meant
425 * to be used internally within a switch, and thus need to be unique only
426 * on a switch level. Note that packets never go out on the wire with these
427 * vlans. Currently, vlan ids are assigned from value 4093 down.
428 * Vlan id 4094 expected to be used for all ports that are not assigned subnets.
429 * Vlan id 4095 is reserved and unused. Only a single vlan id is assigned
430 * per subnet.
sangho80f11cb2015-04-01 13:05:26 -0700431 *
Saurav Das7c305372015-10-28 12:39:42 -0700432 * @param deviceId switch dpid
433 * @param subnet IPv4 prefix for which assigned vlan is desired
434 * @return VlanId assigned for the subnet on the device, or
435 * null if no vlan assignment was found and this instance is not
436 * the master for the device.
sangho80f11cb2015-04-01 13:05:26 -0700437 */
Charles Chanb7f75ac2016-01-11 18:28:54 -0800438 // TODO: We should avoid assigning VLAN IDs that are used by VLAN cross-connection.
Saurav Das7c305372015-10-28 12:39:42 -0700439 public VlanId getSubnetAssignedVlanId(DeviceId deviceId, Ip4Prefix subnet) {
440 VlanId assignedVid = subnetVidStore.get(new SubnetAssignedVidStoreKey(
441 deviceId, subnet));
442 if (assignedVid != null) {
443 log.debug("Query for subnet:{} on device:{} returned assigned-vlan "
444 + "{}", subnet, deviceId, assignedVid);
445 return assignedVid;
446 }
447 //check mastership for the right to assign a vlan
448 if (!mastershipService.isLocalMaster(deviceId)) {
449 log.warn("This controller instance is not the master for device {}. "
450 + "Cannot assign vlan-id for subnet {}", deviceId, subnet);
451 return null;
452 }
453 // vlan assignment is expensive but done only once
Charles Chanc6ad7752015-10-29 14:58:10 -0700454 Set<Ip4Prefix> configuredSubnets = deviceConfiguration.getSubnets(deviceId);
Saurav Das7c305372015-10-28 12:39:42 -0700455 Set<Short> assignedVlans = new HashSet<>();
456 Set<Ip4Prefix> unassignedSubnets = new HashSet<>();
457 for (Ip4Prefix sub : configuredSubnets) {
458 VlanId v = subnetVidStore.get(new SubnetAssignedVidStoreKey(deviceId,
459 sub));
460 if (v != null) {
461 assignedVlans.add(v.toShort());
462 } else {
463 unassignedSubnets.add(sub);
464 }
465 }
466 short nextAssignedVlan = ASSIGNED_VLAN_START;
467 if (!assignedVlans.isEmpty()) {
468 nextAssignedVlan = (short) (Collections.min(assignedVlans) - 1);
469 }
470 for (Ip4Prefix unsub : unassignedSubnets) {
Charles Chan82ab1932016-01-30 23:22:37 -0800471 // Special case for default route. Assign default VLAN ID to /32 and /0 subnets
472 if (unsub.prefixLength() == IpPrefix.MAX_INET_MASK_LENGTH ||
473 unsub.prefixLength() == 0) {
474 subnetVidStore.put(new SubnetAssignedVidStoreKey(deviceId, unsub),
475 VlanId.vlanId(ASSIGNED_VLAN_NO_SUBNET));
476 } else {
477 subnetVidStore.put(new SubnetAssignedVidStoreKey(deviceId, unsub),
478 VlanId.vlanId(nextAssignedVlan--));
479 log.info("Assigned vlan: {} to subnet: {} on device: {}",
480 nextAssignedVlan + 1, unsub, deviceId);
481 }
sangho80f11cb2015-04-01 13:05:26 -0700482 }
483
Saurav Das7c305372015-10-28 12:39:42 -0700484 return subnetVidStore.get(new SubnetAssignedVidStoreKey(deviceId, subnet));
sangho80f11cb2015-04-01 13:05:26 -0700485 }
486
sangho27462c62015-05-14 00:39:53 -0700487 /**
Saurav Das7c305372015-10-28 12:39:42 -0700488 * Returns the next objective ID for the given NeighborSet.
Saurav Das4c35fc42015-11-20 15:27:53 -0800489 * If the nextObjective does not exist, a new one is created and
Saurav Das2d94d312015-11-24 23:21:05 -0800490 * its id is returned.
sangho27462c62015-05-14 00:39:53 -0700491 *
sangho80f1f892015-05-19 11:57:42 -0700492 * @param deviceId Device ID
493 * @param ns NegighborSet
Saurav Das4c35fc42015-11-20 15:27:53 -0800494 * @param meta metadata passed into the creation of a Next Objective
495 * @return next objective ID or -1 if an error was encountered during the
496 * creation of the nextObjective
sangho27462c62015-05-14 00:39:53 -0700497 */
Saurav Das4c35fc42015-11-20 15:27:53 -0800498 public int getNextObjectiveId(DeviceId deviceId, NeighborSet ns,
499 TrafficSelector meta) {
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700500 if (groupHandlerMap.get(deviceId) != null) {
501 log.trace("getNextObjectiveId query in device {}", deviceId);
502 return groupHandlerMap
Saurav Das4c35fc42015-11-20 15:27:53 -0800503 .get(deviceId).getNextObjectiveId(ns, meta);
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700504 } else {
Saurav Das2d94d312015-11-24 23:21:05 -0800505 log.warn("getNextObjectiveId query - groupHandler for device {} "
506 + "not found", deviceId);
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700507 return -1;
508 }
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700509 }
510
Charles Chan77277672015-10-20 16:24:19 -0700511 /**
Saurav Das2d94d312015-11-24 23:21:05 -0800512 * Returns the next objective ID for the given subnet prefix. It is expected
513 * that the next-objective has been pre-created from configuration.
Charles Chan77277672015-10-20 16:24:19 -0700514 *
515 * @param deviceId Device ID
516 * @param prefix Subnet
Saurav Das2d94d312015-11-24 23:21:05 -0800517 * @return next objective ID or -1 if it was not found
Charles Chan77277672015-10-20 16:24:19 -0700518 */
519 public int getSubnetNextObjectiveId(DeviceId deviceId, IpPrefix prefix) {
520 if (groupHandlerMap.get(deviceId) != null) {
521 log.trace("getSubnetNextObjectiveId query in device {}", deviceId);
522 return groupHandlerMap
523 .get(deviceId).getSubnetNextObjectiveId(prefix);
524 } else {
Saurav Das2d94d312015-11-24 23:21:05 -0800525 log.warn("getSubnetNextObjectiveId query - groupHandler for "
526 + "device {} not found", deviceId);
527 return -1;
528 }
529 }
530
531 /**
532 * Returns the next objective ID for the given portNumber, given the treatment.
533 * There could be multiple different treatments to the same outport, which
534 * would result in different objectives. If the next object
535 * does not exist, a new one is created and its id is returned.
536 *
537 * @param deviceId Device ID
538 * @param portNum port number on device for which NextObjective is queried
539 * @param treatment the actions to apply on the packets (should include outport)
540 * @param meta metadata passed into the creation of a Next Objective if necessary
541 * @return next objective ID or -1 if it was not found
542 */
543 public int getPortNextObjectiveId(DeviceId deviceId, PortNumber portNum,
544 TrafficTreatment treatment,
545 TrafficSelector meta) {
546 DefaultGroupHandler ghdlr = groupHandlerMap.get(deviceId);
547 if (ghdlr != null) {
548 return ghdlr.getPortNextObjectiveId(portNum, treatment, meta);
549 } else {
Charles Chanb7f75ac2016-01-11 18:28:54 -0800550 log.warn("getPortNextObjectiveId query - groupHandler for device {}"
551 + " not found", deviceId);
552 return -1;
553 }
554 }
555
556 /**
557 * Returns the next objective ID of type broadcast associated with the VLAN
558 * cross-connection.
559 *
560 * @param deviceId Device ID for the cross-connection
561 * @param vlanId VLAN ID for the cross-connection
562 * @return next objective ID or -1 if it was not found
563 */
564 public int getXConnectNextObjectiveId(DeviceId deviceId, VlanId vlanId) {
565 DefaultGroupHandler ghdlr = groupHandlerMap.get(deviceId);
566 if (ghdlr != null) {
567 return ghdlr.getXConnectNextObjectiveId(vlanId);
568 } else {
569 log.warn("getPortNextObjectiveId query - groupHandler for device {}"
Saurav Das2d94d312015-11-24 23:21:05 -0800570 + " not found", deviceId);
Charles Chan77277672015-10-20 16:24:19 -0700571 return -1;
572 }
573 }
574
sangho80f11cb2015-04-01 13:05:26 -0700575 private class InternalPacketProcessor implements PacketProcessor {
sangho80f11cb2015-04-01 13:05:26 -0700576 @Override
577 public void process(PacketContext context) {
578
579 if (context.isHandled()) {
580 return;
581 }
582
583 InboundPacket pkt = context.inPacket();
584 Ethernet ethernet = pkt.parsed();
Saurav Das2d94d312015-11-24 23:21:05 -0800585 log.trace("Rcvd pktin: {}", ethernet);
sangho80f11cb2015-04-01 13:05:26 -0700586 if (ethernet.getEtherType() == Ethernet.TYPE_ARP) {
587 arpHandler.processPacketIn(pkt);
588 } else if (ethernet.getEtherType() == Ethernet.TYPE_IPV4) {
589 IPv4 ipPacket = (IPv4) ethernet.getPayload();
590 ipHandler.addToPacketBuffer(ipPacket);
591 if (ipPacket.getProtocol() == IPv4.PROTOCOL_ICMP) {
592 icmpHandler.processPacketIn(pkt);
593 } else {
594 ipHandler.processPacketIn(pkt);
595 }
596 }
597 }
598 }
599
600 private class InternalLinkListener implements LinkListener {
601 @Override
602 public void event(LinkEvent event) {
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700603 if (event.type() == LinkEvent.Type.LINK_ADDED
604 || event.type() == LinkEvent.Type.LINK_REMOVED) {
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700605 log.debug("Event {} received from Link Service", event.type());
sangho80f11cb2015-04-01 13:05:26 -0700606 scheduleEventHandlerIfNotScheduled(event);
607 }
608 }
609 }
610
611 private class InternalDeviceListener implements DeviceListener {
sangho80f11cb2015-04-01 13:05:26 -0700612 @Override
613 public void event(DeviceEvent event) {
sangho80f11cb2015-04-01 13:05:26 -0700614 switch (event.type()) {
615 case DEVICE_ADDED:
616 case PORT_REMOVED:
sanghofb7c7292015-04-13 15:15:58 -0700617 case DEVICE_UPDATED:
618 case DEVICE_AVAILABILITY_CHANGED:
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700619 log.debug("Event {} received from Device Service", event.type());
sangho80f11cb2015-04-01 13:05:26 -0700620 scheduleEventHandlerIfNotScheduled(event);
621 break;
622 default:
623 }
624 }
625 }
626
Saurav Das2d94d312015-11-24 23:21:05 -0800627 @SuppressWarnings("rawtypes")
sangho80f11cb2015-04-01 13:05:26 -0700628 private void scheduleEventHandlerIfNotScheduled(Event event) {
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700629 synchronized (threadSchedulerLock) {
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700630 eventQueue.add(event);
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700631 numOfEventsQueued++;
632
633 if ((numOfHandlerScheduled - numOfHandlerExecution) == 0) {
634 //No pending scheduled event handling threads. So start a new one.
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700635 eventHandlerFuture = executorService
636 .schedule(eventHandler, 100, TimeUnit.MILLISECONDS);
637 numOfHandlerScheduled++;
638 }
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700639 log.trace("numOfEventsQueued {}, numOfEventHanlderScheduled {}",
640 numOfEventsQueued,
641 numOfHandlerScheduled);
sangho80f11cb2015-04-01 13:05:26 -0700642 }
sangho80f11cb2015-04-01 13:05:26 -0700643 }
644
645 private class InternalEventHandler implements Runnable {
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700646 @Override
sangho80f11cb2015-04-01 13:05:26 -0700647 public void run() {
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700648 try {
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700649 while (true) {
Saurav Das2d94d312015-11-24 23:21:05 -0800650 @SuppressWarnings("rawtypes")
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700651 Event event = null;
652 synchronized (threadSchedulerLock) {
653 if (!eventQueue.isEmpty()) {
654 event = eventQueue.poll();
655 numOfEventsExecuted++;
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700656 } else {
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700657 numOfHandlerExecution++;
658 log.debug("numOfHandlerExecution {} numOfEventsExecuted {}",
659 numOfHandlerExecution, numOfEventsExecuted);
660 break;
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700661 }
sanghofb7c7292015-04-13 15:15:58 -0700662 }
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700663 if (event.type() == LinkEvent.Type.LINK_ADDED) {
664 processLinkAdded((Link) event.subject());
665 } else if (event.type() == LinkEvent.Type.LINK_REMOVED) {
666 processLinkRemoved((Link) event.subject());
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700667 } else if (event.type() == DeviceEvent.Type.DEVICE_ADDED ||
668 event.type() == DeviceEvent.Type.DEVICE_AVAILABILITY_CHANGED ||
669 event.type() == DeviceEvent.Type.DEVICE_UPDATED) {
Saurav Das62af8802015-12-04 10:52:59 -0800670 DeviceId deviceId = ((Device) event.subject()).id();
671 if (deviceService.isAvailable(deviceId)) {
Saurav Dasc28b3432015-10-30 17:45:38 -0700672 log.info("Processing device event {} for available device {}",
673 event.type(), ((Device) event.subject()).id());
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700674 processDeviceAdded((Device) event.subject());
Saurav Das62af8802015-12-04 10:52:59 -0800675 } /* else {
676 if (event.type() == DeviceEvent.Type.DEVICE_AVAILABILITY_CHANGED) {
677 // availability changed and not available - dev gone
678 DefaultGroupHandler groupHandler = groupHandlerMap.get(deviceId);
679 if (groupHandler != null) {
680 groupHandler.removeAllGroups();
681 }
682 }
683 }*/
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700684 } else if (event.type() == DeviceEvent.Type.PORT_REMOVED) {
685 processPortRemoved((Device) event.subject(),
686 ((DeviceEvent) event).port());
687 } else {
688 log.warn("Unhandled event type: {}", event.type());
689 }
sangho80f11cb2015-04-01 13:05:26 -0700690 }
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700691 } catch (Exception e) {
692 log.error("SegmentRouting event handler "
693 + "thread thrown an exception: {}", e);
sangho80f11cb2015-04-01 13:05:26 -0700694 }
sangho80f11cb2015-04-01 13:05:26 -0700695 }
696 }
697
sangho80f11cb2015-04-01 13:05:26 -0700698 private void processLinkAdded(Link link) {
699 log.debug("A new link {} was added", link.toString());
Charles Chan319d1a22015-11-03 10:42:14 -0800700 if (!deviceConfiguration.isConfigured(link.src().deviceId())) {
701 log.warn("Source device of this link is not configured.");
702 return;
703 }
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700704 //Irrespective whether the local is a MASTER or not for this device,
705 //create group handler instance and push default TTP flow rules.
706 //Because in a multi-instance setup, instances can initiate
707 //groups for any devices. Also the default TTP rules are needed
708 //to be pushed before inserting any IP table entries for any device
709 DefaultGroupHandler groupHandler = groupHandlerMap.get(link.src()
710 .deviceId());
711 if (groupHandler != null) {
Saurav Das4c35fc42015-11-20 15:27:53 -0800712 groupHandler.linkUp(link, mastershipService.isLocalMaster(
713 link.src().deviceId()));
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700714 } else {
715 Device device = deviceService.getDevice(link.src().deviceId());
716 if (device != null) {
717 log.warn("processLinkAdded: Link Added "
718 + "Notification without Device Added "
719 + "event, still handling it");
720 processDeviceAdded(device);
721 groupHandler = groupHandlerMap.get(link.src()
722 .deviceId());
Saurav Das4c35fc42015-11-20 15:27:53 -0800723 groupHandler.linkUp(link, mastershipService.isLocalMaster(device.id()));
sangho80f11cb2015-04-01 13:05:26 -0700724 }
725 }
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700726
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700727 log.trace("Starting optimized route population process");
728 defaultRoutingHandler.populateRoutingRulesForLinkStatusChange(null);
729 //log.trace("processLinkAdded: re-starting route population process");
730 //defaultRoutingHandler.startPopulationProcess();
sangho80f11cb2015-04-01 13:05:26 -0700731 }
732
733 private void processLinkRemoved(Link link) {
734 log.debug("A link {} was removed", link.toString());
sangho2165d222015-05-01 09:38:25 -0700735 DefaultGroupHandler groupHandler = groupHandlerMap.get(link.src().deviceId());
736 if (groupHandler != null) {
Saurav Das62af8802015-12-04 10:52:59 -0800737 groupHandler.portDown(link.src().port(),
738 mastershipService.isLocalMaster(link.src().deviceId()));
sangho2165d222015-05-01 09:38:25 -0700739 }
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700740 log.trace("Starting optimized route population process");
741 defaultRoutingHandler.populateRoutingRulesForLinkStatusChange(link);
742 //log.trace("processLinkRemoved: re-starting route population process");
743 //defaultRoutingHandler.startPopulationProcess();
sangho80f11cb2015-04-01 13:05:26 -0700744 }
745
746 private void processDeviceAdded(Device device) {
747 log.debug("A new device with ID {} was added", device.id());
Charles Chan319d1a22015-11-03 10:42:14 -0800748 if (deviceConfiguration == null || !deviceConfiguration.isConfigured(device.id())) {
Saurav Das8ec0ec42015-11-03 14:39:27 -0800749 log.warn("Device configuration uploading. Device {} will be "
750 + "processed after config completes.", device.id());
751 return;
752 }
Saurav Dasc28b3432015-10-30 17:45:38 -0700753 // Irrespective of whether the local is a MASTER or not for this device,
754 // we need to create a SR-group-handler instance. This is because in a
755 // multi-instance setup, any instance can initiate forwarding/next-objectives
756 // for any switch (even if this instance is a SLAVE or not even connected
757 // to the switch). To handle this, a default-group-handler instance is necessary
758 // per switch.
Saurav Das8ec0ec42015-11-03 14:39:27 -0800759 if (groupHandlerMap.get(device.id()) == null) {
Charles Chan319d1a22015-11-03 10:42:14 -0800760 DefaultGroupHandler groupHandler;
761 try {
762 groupHandler = DefaultGroupHandler.
763 createGroupHandler(device.id(),
764 appId,
765 deviceConfiguration,
766 linkService,
767 flowObjectiveService,
Charles Chande6655c2015-12-23 00:15:11 -0800768 this);
Charles Chan319d1a22015-11-03 10:42:14 -0800769 } catch (DeviceConfigNotFoundException e) {
770 log.warn(e.getMessage() + " Aborting processDeviceAdded.");
771 return;
772 }
Saurav Das8ec0ec42015-11-03 14:39:27 -0800773 groupHandlerMap.put(device.id(), groupHandler);
774 // Also, in some cases, drivers may need extra
775 // information to process rules (eg. Router IP/MAC); and so, we send
776 // port addressing rules to the driver as well irrespective of whether
777 // this instance is the master or not.
778 defaultRoutingHandler.populatePortAddressingRules(device.id());
Charles Chand4a99c52015-11-18 16:51:08 -0800779 hostListener.readInitialHosts();
Saurav Das8ec0ec42015-11-03 14:39:27 -0800780 }
Charles Chan77277672015-10-20 16:24:19 -0700781 if (mastershipService.isLocalMaster(device.id())) {
Saurav Das8ec0ec42015-11-03 14:39:27 -0800782 DefaultGroupHandler groupHandler = groupHandlerMap.get(device.id());
Charles Chan77277672015-10-20 16:24:19 -0700783 groupHandler.createGroupsFromSubnetConfig();
Charles Chanf4586112015-11-09 16:37:23 -0800784 routingRulePopulator.populateSubnetBroadcastRule(device.id());
Charles Chanb7f75ac2016-01-11 18:28:54 -0800785 groupHandler.createGroupsForXConnect(device.id());
786 routingRulePopulator.populateXConnectBroadcastRule(device.id());
Charles Chan77277672015-10-20 16:24:19 -0700787 }
Charles Chan82ab1932016-01-30 23:22:37 -0800788
789 netcfgHandler.initVRouters(device.id());
sangho80f11cb2015-04-01 13:05:26 -0700790 }
791
792 private void processPortRemoved(Device device, Port port) {
793 log.debug("Port {} was removed", port.toString());
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700794 DefaultGroupHandler groupHandler = groupHandlerMap.get(device.id());
sangho80f11cb2015-04-01 13:05:26 -0700795 if (groupHandler != null) {
Saurav Das62af8802015-12-04 10:52:59 -0800796 groupHandler.portDown(port.number(),
797 mastershipService.isLocalMaster(device.id()));
sangho80f11cb2015-04-01 13:05:26 -0700798 }
799 }
sangho27462c62015-05-14 00:39:53 -0700800
Charles Chan72f556a2015-10-05 17:50:33 -0700801 private class InternalConfigListener implements NetworkConfigListener {
Charles Chane7c61022015-10-07 14:21:45 -0700802 SegmentRoutingManager segmentRoutingManager;
803
Charles Chanb7f75ac2016-01-11 18:28:54 -0800804 /**
805 * Constructs the internal network config listener.
806 *
807 * @param srMgr segment routing manager
808 */
Charles Chane7c61022015-10-07 14:21:45 -0700809 public InternalConfigListener(SegmentRoutingManager srMgr) {
810 this.segmentRoutingManager = srMgr;
811 }
812
Charles Chanb7f75ac2016-01-11 18:28:54 -0800813 /**
814 * Reads network config and initializes related data structure accordingly.
815 */
Charles Chane7c61022015-10-07 14:21:45 -0700816 public void configureNetwork() {
817 deviceConfiguration = new DeviceConfiguration(segmentRoutingManager.cfgService);
818
819 arpHandler = new ArpHandler(segmentRoutingManager);
820 icmpHandler = new IcmpHandler(segmentRoutingManager);
821 ipHandler = new IpHandler(segmentRoutingManager);
822 routingRulePopulator = new RoutingRulePopulator(segmentRoutingManager);
823 defaultRoutingHandler = new DefaultRoutingHandler(segmentRoutingManager);
824
825 tunnelHandler = new TunnelHandler(linkService, deviceConfiguration,
826 groupHandlerMap, tunnelStore);
827 policyHandler = new PolicyHandler(appId, deviceConfiguration,
828 flowObjectiveService,
829 tunnelHandler, policyStore);
830
Charles Chane7c61022015-10-07 14:21:45 -0700831 for (Device device : deviceService.getDevices()) {
Saurav Dasc28b3432015-10-30 17:45:38 -0700832 // Irrespective of whether the local is a MASTER or not for this device,
833 // we need to create a SR-group-handler instance. This is because in a
834 // multi-instance setup, any instance can initiate forwarding/next-objectives
835 // for any switch (even if this instance is a SLAVE or not even connected
836 // to the switch). To handle this, a default-group-handler instance is necessary
837 // per switch.
Saurav Das8ec0ec42015-11-03 14:39:27 -0800838 if (groupHandlerMap.get(device.id()) == null) {
Charles Chan319d1a22015-11-03 10:42:14 -0800839 DefaultGroupHandler groupHandler;
840 try {
841 groupHandler = DefaultGroupHandler.
842 createGroupHandler(device.id(),
843 appId,
844 deviceConfiguration,
845 linkService,
846 flowObjectiveService,
Charles Chande6655c2015-12-23 00:15:11 -0800847 segmentRoutingManager);
Charles Chan319d1a22015-11-03 10:42:14 -0800848 } catch (DeviceConfigNotFoundException e) {
849 log.warn(e.getMessage() + " Aborting configureNetwork.");
850 return;
851 }
Saurav Das8ec0ec42015-11-03 14:39:27 -0800852 groupHandlerMap.put(device.id(), groupHandler);
Saurav Dasc28b3432015-10-30 17:45:38 -0700853
Saurav Das8ec0ec42015-11-03 14:39:27 -0800854 // Also, in some cases, drivers may need extra
855 // information to process rules (eg. Router IP/MAC); and so, we send
856 // port addressing rules to the driver as well, irrespective of whether
857 // this instance is the master or not.
858 defaultRoutingHandler.populatePortAddressingRules(device.id());
Charles Chand4a99c52015-11-18 16:51:08 -0800859 hostListener.readInitialHosts();
Saurav Das8ec0ec42015-11-03 14:39:27 -0800860 }
Charles Chan77277672015-10-20 16:24:19 -0700861 if (mastershipService.isLocalMaster(device.id())) {
Saurav Das8ec0ec42015-11-03 14:39:27 -0800862 DefaultGroupHandler groupHandler = groupHandlerMap.get(device.id());
Charles Chan77277672015-10-20 16:24:19 -0700863 groupHandler.createGroupsFromSubnetConfig();
Charles Chanf4586112015-11-09 16:37:23 -0800864 routingRulePopulator.populateSubnetBroadcastRule(device.id());
Charles Chanb7f75ac2016-01-11 18:28:54 -0800865 groupHandler.createGroupsForXConnect(device.id());
866 routingRulePopulator.populateXConnectBroadcastRule(device.id());
Charles Chan77277672015-10-20 16:24:19 -0700867 }
Charles Chane7c61022015-10-07 14:21:45 -0700868 }
869
870 defaultRoutingHandler.startPopulationProcess();
871 }
872
Charles Chan72f556a2015-10-05 17:50:33 -0700873 @Override
874 public void event(NetworkConfigEvent event) {
Charles Chan82ab1932016-01-30 23:22:37 -0800875 // TODO move this part to NetworkConfigEventHandler
876 if (event.configClass().equals(SegmentRoutingDeviceConfig.class)) {
877 switch (event.type()) {
878 case CONFIG_ADDED:
879 log.info("Segment Routing Config added.");
880 configureNetwork();
881 break;
882 case CONFIG_UPDATED:
883 log.info("Segment Routing Config updated.");
884 // TODO support dynamic configuration
885 break;
886 default:
887 break;
Charles Chan2b078ae2015-10-14 11:24:40 -0700888 }
Charles Chan82ab1932016-01-30 23:22:37 -0800889 } else if (event.configClass().equals(SegmentRoutingAppConfig.class)) {
890 switch (event.type()) {
891 case CONFIG_ADDED:
892 netcfgHandler.processVRouterConfigAdded(event);
893 break;
894 case CONFIG_UPDATED:
895 netcfgHandler.processVRouterConfigUpdated(event);
896 break;
897 case CONFIG_REMOVED:
898 netcfgHandler.processVRouterConfigRemoved(event);
899 break;
900 default:
901 break;
Charles Chan2b078ae2015-10-14 11:24:40 -0700902 }
Charles Chan72f556a2015-10-05 17:50:33 -0700903 }
904 }
905 }
Charles Chanf4586112015-11-09 16:37:23 -0800906
Charles Chand4a99c52015-11-18 16:51:08 -0800907 // TODO Move bridging table population to a separate class
Charles Chanf4586112015-11-09 16:37:23 -0800908 private class InternalHostListener implements HostListener {
Charles Chand4a99c52015-11-18 16:51:08 -0800909 private void readInitialHosts() {
910 hostService.getHosts().forEach(host -> {
911 MacAddress mac = host.mac();
912 VlanId vlanId = host.vlan();
913 DeviceId deviceId = host.location().deviceId();
914 PortNumber port = host.location().port();
915 Set<IpAddress> ips = host.ipAddresses();
916 log.debug("Host {}/{} is added at {}:{}", mac, vlanId, deviceId, port);
917
918 // Populate bridging table entry
919 ForwardingObjective.Builder fob =
Saurav Das2d94d312015-11-24 23:21:05 -0800920 getForwardingObjectiveBuilder(deviceId, mac, vlanId, port);
Charles Chand4a99c52015-11-18 16:51:08 -0800921 flowObjectiveService.forward(deviceId, fob.add(
922 new BridgingTableObjectiveContext(mac, vlanId)
923 ));
924
925 // Populate IP table entry
926 ips.forEach(ip -> {
927 if (ip.isIp4()) {
928 routingRulePopulator.populateIpRuleForHost(
929 deviceId, ip.getIp4Address(), mac, port);
930 }
931 });
932 });
933 }
934
Charles Chanf4586112015-11-09 16:37:23 -0800935 private ForwardingObjective.Builder getForwardingObjectiveBuilder(
Saurav Das2d94d312015-11-24 23:21:05 -0800936 DeviceId deviceId, MacAddress mac, VlanId vlanId,
937 PortNumber outport) {
Charles Chande6655c2015-12-23 00:15:11 -0800938 // Get assigned VLAN for the subnet
Saurav Das2d94d312015-11-24 23:21:05 -0800939 VlanId outvlan = null;
940 Ip4Prefix subnet = deviceConfiguration.getPortSubnet(deviceId, outport);
941 if (subnet == null) {
942 outvlan = VlanId.vlanId(ASSIGNED_VLAN_NO_SUBNET);
943 } else {
944 outvlan = getSubnetAssignedVlanId(deviceId, subnet);
945 }
Charles Chande6655c2015-12-23 00:15:11 -0800946
947 // match rule
948 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
949 sbuilder.matchEthDst(mac);
950 /*
951 * Note: for untagged packets, match on the assigned VLAN.
952 * for tagged packets, match on its incoming VLAN.
953 */
954 if (vlanId.equals(VlanId.NONE)) {
955 sbuilder.matchVlanId(outvlan);
956 } else {
957 sbuilder.matchVlanId(vlanId);
958 }
959
960 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
961 tbuilder.immediate().popVlan();
962 tbuilder.immediate().setOutput(outport);
963
964 // for switch pipelines that need it, provide outgoing vlan as metadata
Saurav Das2d94d312015-11-24 23:21:05 -0800965 TrafficSelector meta = DefaultTrafficSelector.builder()
966 .matchVlanId(outvlan).build();
967
968 // All forwarding is via Groups. Drivers can re-purpose to flow-actions if needed.
969 int portNextObjId = getPortNextObjectiveId(deviceId, outport,
970 tbuilder.build(),
971 meta);
Charles Chanf4586112015-11-09 16:37:23 -0800972
973 return DefaultForwardingObjective.builder()
974 .withFlag(ForwardingObjective.Flag.SPECIFIC)
975 .withSelector(sbuilder.build())
Saurav Das2d94d312015-11-24 23:21:05 -0800976 .nextStep(portNextObjId)
Charles Chanf4586112015-11-09 16:37:23 -0800977 .withPriority(100)
978 .fromApp(appId)
979 .makePermanent();
980 }
981
982 private void processHostAddedEvent(HostEvent event) {
983 MacAddress mac = event.subject().mac();
984 VlanId vlanId = event.subject().vlan();
985 DeviceId deviceId = event.subject().location().deviceId();
986 PortNumber port = event.subject().location().port();
987 Set<IpAddress> ips = event.subject().ipAddresses();
Saurav Das2d94d312015-11-24 23:21:05 -0800988 log.info("Host {}/{} is added at {}:{}", mac, vlanId, deviceId, port);
Charles Chanf4586112015-11-09 16:37:23 -0800989
Charles Chanf4586112015-11-09 16:37:23 -0800990 // Populate bridging table entry
Saurav Das2d94d312015-11-24 23:21:05 -0800991 log.debug("Populate L2 table entry for host {} at {}:{}",
992 mac, deviceId, port);
Charles Chanf4586112015-11-09 16:37:23 -0800993 ForwardingObjective.Builder fob =
Saurav Das2d94d312015-11-24 23:21:05 -0800994 getForwardingObjectiveBuilder(deviceId, mac, vlanId, port);
Charles Chanf4586112015-11-09 16:37:23 -0800995 flowObjectiveService.forward(deviceId, fob.add(
996 new BridgingTableObjectiveContext(mac, vlanId)
997 ));
998
999 // Populate IP table entry
1000 ips.forEach(ip -> {
1001 if (ip.isIp4()) {
1002 routingRulePopulator.populateIpRuleForHost(
1003 deviceId, ip.getIp4Address(), mac, port);
1004 }
1005 });
1006 }
1007
1008 private void processHostRemoveEvent(HostEvent event) {
1009 MacAddress mac = event.subject().mac();
1010 VlanId vlanId = event.subject().vlan();
1011 DeviceId deviceId = event.subject().location().deviceId();
1012 PortNumber port = event.subject().location().port();
1013 Set<IpAddress> ips = event.subject().ipAddresses();
1014 log.debug("Host {}/{} is removed from {}:{}", mac, vlanId, deviceId, port);
1015
1016 // Revoke bridging table entry
1017 ForwardingObjective.Builder fob =
Saurav Das2d94d312015-11-24 23:21:05 -08001018 getForwardingObjectiveBuilder(deviceId, mac, vlanId, port);
Charles Chanf4586112015-11-09 16:37:23 -08001019 flowObjectiveService.forward(deviceId, fob.remove(
1020 new BridgingTableObjectiveContext(mac, vlanId)
1021 ));
1022
1023 // Revoke IP table entry
1024 ips.forEach(ip -> {
1025 if (ip.isIp4()) {
1026 routingRulePopulator.revokeIpRuleForHost(
1027 deviceId, ip.getIp4Address(), mac, port);
1028 }
1029 });
1030 }
1031
1032 private void processHostMovedEvent(HostEvent event) {
1033 MacAddress mac = event.subject().mac();
1034 VlanId vlanId = event.subject().vlan();
1035 DeviceId prevDeviceId = event.prevSubject().location().deviceId();
1036 PortNumber prevPort = event.prevSubject().location().port();
1037 Set<IpAddress> prevIps = event.prevSubject().ipAddresses();
1038 DeviceId newDeviceId = event.subject().location().deviceId();
1039 PortNumber newPort = event.subject().location().port();
1040 Set<IpAddress> newIps = event.subject().ipAddresses();
1041 log.debug("Host {}/{} is moved from {}:{} to {}:{}",
1042 mac, vlanId, prevDeviceId, prevPort, newDeviceId, newPort);
1043
1044 // Revoke previous bridging table entry
1045 ForwardingObjective.Builder prevFob =
Saurav Das2d94d312015-11-24 23:21:05 -08001046 getForwardingObjectiveBuilder(prevDeviceId, mac, vlanId, prevPort);
Charles Chanf4586112015-11-09 16:37:23 -08001047 flowObjectiveService.forward(prevDeviceId, prevFob.remove(
1048 new BridgingTableObjectiveContext(mac, vlanId)
1049 ));
1050
1051 // Revoke previous IP table entry
1052 prevIps.forEach(ip -> {
1053 if (ip.isIp4()) {
1054 routingRulePopulator.revokeIpRuleForHost(
1055 prevDeviceId, ip.getIp4Address(), mac, prevPort);
1056 }
1057 });
1058
1059 // Populate new bridging table entry
1060 ForwardingObjective.Builder newFob =
Saurav Das2d94d312015-11-24 23:21:05 -08001061 getForwardingObjectiveBuilder(newDeviceId, mac, vlanId, newPort);
Charles Chanf4586112015-11-09 16:37:23 -08001062 flowObjectiveService.forward(newDeviceId, newFob.add(
1063 new BridgingTableObjectiveContext(mac, vlanId)
1064 ));
1065
1066 // Populate new IP table entry
1067 newIps.forEach(ip -> {
1068 if (ip.isIp4()) {
1069 routingRulePopulator.populateIpRuleForHost(
1070 newDeviceId, ip.getIp4Address(), mac, newPort);
1071 }
1072 });
1073 }
1074
1075 private void processHostUpdatedEvent(HostEvent event) {
1076 MacAddress mac = event.subject().mac();
1077 VlanId vlanId = event.subject().vlan();
1078 DeviceId prevDeviceId = event.prevSubject().location().deviceId();
1079 PortNumber prevPort = event.prevSubject().location().port();
1080 Set<IpAddress> prevIps = event.prevSubject().ipAddresses();
1081 DeviceId newDeviceId = event.subject().location().deviceId();
1082 PortNumber newPort = event.subject().location().port();
1083 Set<IpAddress> newIps = event.subject().ipAddresses();
1084 log.debug("Host {}/{} is updated", mac, vlanId);
1085
1086 // Revoke previous IP table entry
1087 prevIps.forEach(ip -> {
1088 if (ip.isIp4()) {
1089 routingRulePopulator.revokeIpRuleForHost(
1090 prevDeviceId, ip.getIp4Address(), mac, prevPort);
1091 }
1092 });
1093
1094 // Populate new IP table entry
1095 newIps.forEach(ip -> {
1096 if (ip.isIp4()) {
1097 routingRulePopulator.populateIpRuleForHost(
1098 newDeviceId, ip.getIp4Address(), mac, newPort);
1099 }
1100 });
1101 }
1102
1103 @Override
1104 public void event(HostEvent event) {
1105 // Do not proceed without mastership
1106 DeviceId deviceId = event.subject().location().deviceId();
1107 if (!mastershipService.isLocalMaster(deviceId)) {
1108 return;
1109 }
1110
1111 switch (event.type()) {
1112 case HOST_ADDED:
1113 processHostAddedEvent(event);
1114 break;
1115 case HOST_MOVED:
1116 processHostMovedEvent(event);
1117 break;
1118 case HOST_REMOVED:
1119 processHostRemoveEvent(event);
1120 break;
1121 case HOST_UPDATED:
1122 processHostUpdatedEvent(event);
1123 break;
1124 default:
1125 log.warn("Unsupported host event type: {}", event.type());
1126 break;
1127 }
1128 }
1129 }
1130
1131 private static class BridgingTableObjectiveContext implements ObjectiveContext {
1132 final MacAddress mac;
1133 final VlanId vlanId;
1134
1135 BridgingTableObjectiveContext(MacAddress mac, VlanId vlanId) {
1136 this.mac = mac;
1137 this.vlanId = vlanId;
1138 }
1139
1140 @Override
1141 public void onSuccess(Objective objective) {
1142 if (objective.op() == Objective.Operation.ADD) {
1143 log.debug("Successfully populate bridging table entry for {}/{}",
1144 mac, vlanId);
1145 } else {
1146 log.debug("Successfully revoke bridging table entry for {}/{}",
1147 mac, vlanId);
1148 }
1149 }
1150
1151 @Override
1152 public void onError(Objective objective, ObjectiveError error) {
1153 if (objective.op() == Objective.Operation.ADD) {
1154 log.debug("Fail to populate bridging table entry for {}/{}. {}",
1155 mac, vlanId, error);
1156 } else {
1157 log.debug("Fail to revoke bridging table entry for {}/{}. {}",
1158 mac, vlanId, error);
1159 }
1160 }
1161 }
sangho80f11cb2015-04-01 13:05:26 -07001162}