blob: 9ea59785afc43c27a9f9de7ace613e421dcd22d8 [file] [log] [blame]
sanghob35a6192015-04-01 13:05:26 -07001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2015-present Open Networking Laboratory
sanghob35a6192015-04-01 13:05:26 -07003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.onosproject.segmentrouting;
17
18import org.apache.felix.scr.annotations.Activate;
19import org.apache.felix.scr.annotations.Component;
20import org.apache.felix.scr.annotations.Deactivate;
21import org.apache.felix.scr.annotations.Reference;
22import org.apache.felix.scr.annotations.ReferenceCardinality;
sangho1e575652015-05-14 00:39:53 -070023import org.apache.felix.scr.annotations.Service;
sanghob35a6192015-04-01 13:05:26 -070024import org.onlab.packet.Ethernet;
Charles Chan68aa62d2015-11-09 16:37:23 -080025import org.onlab.packet.MacAddress;
Saurav Das0e99e2b2015-10-28 12:39:42 -070026import org.onlab.packet.VlanId;
Charles Chanc42e84e2015-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 Vavilapalli23181912015-05-04 09:48:09 -070032import org.onlab.util.KryoNamespace;
Saurav Das80980c72016-03-23 11:22:49 -070033import org.onosproject.cfg.ComponentConfigService;
sanghob35a6192015-04-01 13:05:26 -070034import org.onosproject.core.ApplicationId;
35import org.onosproject.core.CoreService;
36import org.onosproject.event.Event;
Charles Chanc42e84e2015-10-20 16:24:19 -070037import org.onosproject.net.ConnectPoint;
Charles Chan68aa62d2015-11-09 16:37:23 -080038import org.onosproject.net.PortNumber;
Charles Chand6832882015-10-05 17:50:33 -070039import org.onosproject.net.config.ConfigFactory;
40import org.onosproject.net.config.NetworkConfigEvent;
41import org.onosproject.net.config.NetworkConfigRegistry;
42import org.onosproject.net.config.NetworkConfigListener;
43import org.onosproject.net.config.basics.SubjectFactories;
Charles Chan68aa62d2015-11-09 16:37:23 -080044import org.onosproject.net.flow.DefaultTrafficSelector;
45import org.onosproject.net.flow.DefaultTrafficTreatment;
46import org.onosproject.net.flow.TrafficSelector;
47import org.onosproject.net.flow.TrafficTreatment;
48import org.onosproject.net.flowobjective.DefaultForwardingObjective;
49import org.onosproject.net.flowobjective.ForwardingObjective;
50import org.onosproject.net.flowobjective.Objective;
51import org.onosproject.net.flowobjective.ObjectiveContext;
52import org.onosproject.net.flowobjective.ObjectiveError;
53import org.onosproject.net.host.HostEvent;
54import org.onosproject.net.host.HostListener;
Charles Chan188ebf52015-12-23 00:15:11 -080055import org.onosproject.net.packet.PacketPriority;
Charles Chan0b4e6182015-11-03 10:42:14 -080056import org.onosproject.segmentrouting.config.DeviceConfigNotFoundException;
57import org.onosproject.segmentrouting.config.DeviceConfiguration;
Charles Chan5270ed02016-01-30 23:22:37 -080058import org.onosproject.segmentrouting.config.SegmentRoutingDeviceConfig;
59import org.onosproject.segmentrouting.config.SegmentRoutingAppConfig;
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -070060import org.onosproject.segmentrouting.grouphandler.DefaultGroupHandler;
61import org.onosproject.segmentrouting.grouphandler.NeighborSet;
Srikanth Vavilapalli23181912015-05-04 09:48:09 -070062import org.onosproject.segmentrouting.grouphandler.NeighborSetNextObjectiveStoreKey;
Saurav Das4ce45962015-11-24 23:21:05 -080063import org.onosproject.segmentrouting.grouphandler.PortNextObjectiveStoreKey;
sanghob35a6192015-04-01 13:05:26 -070064import org.onosproject.mastership.MastershipService;
65import org.onosproject.net.Device;
66import org.onosproject.net.DeviceId;
67import org.onosproject.net.Link;
sanghob35a6192015-04-01 13:05:26 -070068import org.onosproject.net.Port;
69import org.onosproject.net.device.DeviceEvent;
70import org.onosproject.net.device.DeviceListener;
71import org.onosproject.net.device.DeviceService;
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070072import org.onosproject.net.flowobjective.FlowObjectiveService;
sanghob35a6192015-04-01 13:05:26 -070073import org.onosproject.net.host.HostService;
sanghob35a6192015-04-01 13:05:26 -070074import org.onosproject.net.link.LinkEvent;
75import org.onosproject.net.link.LinkListener;
76import org.onosproject.net.link.LinkService;
77import org.onosproject.net.packet.InboundPacket;
78import org.onosproject.net.packet.PacketContext;
79import org.onosproject.net.packet.PacketProcessor;
80import org.onosproject.net.packet.PacketService;
Charles Chanc42e84e2015-10-20 16:24:19 -070081import org.onosproject.segmentrouting.grouphandler.SubnetNextObjectiveStoreKey;
Charles Chane849c192016-01-11 18:28:54 -080082import org.onosproject.segmentrouting.grouphandler.XConnectNextObjectiveStoreKey;
Srikanth Vavilapalli23181912015-05-04 09:48:09 -070083import org.onosproject.store.service.EventuallyConsistentMap;
84import org.onosproject.store.service.EventuallyConsistentMapBuilder;
85import org.onosproject.store.service.StorageService;
86import org.onosproject.store.service.WallClockTimestamp;
sanghob35a6192015-04-01 13:05:26 -070087import org.slf4j.Logger;
88import org.slf4j.LoggerFactory;
89
Srikanth Vavilapalli23181912015-05-04 09:48:09 -070090import java.net.URI;
Saurav Das0e99e2b2015-10-28 12:39:42 -070091import java.util.Collections;
Srikanth Vavilapalli23181912015-05-04 09:48:09 -070092import java.util.HashSet;
sangho1e575652015-05-14 00:39:53 -070093import java.util.List;
sanghob35a6192015-04-01 13:05:26 -070094import java.util.Map;
Charles Chan188ebf52015-12-23 00:15:11 -080095import java.util.Optional;
Saurav Das0e99e2b2015-10-28 12:39:42 -070096import java.util.Set;
sanghob35a6192015-04-01 13:05:26 -070097import java.util.concurrent.ConcurrentHashMap;
98import java.util.concurrent.ConcurrentLinkedQueue;
99import java.util.concurrent.Executors;
100import java.util.concurrent.ScheduledExecutorService;
101import java.util.concurrent.ScheduledFuture;
102import java.util.concurrent.TimeUnit;
103
Charles Chan3e783d02016-02-26 22:19:52 -0800104import static com.google.common.base.Preconditions.checkState;
105
sangho1e575652015-05-14 00:39:53 -0700106@Service
sanghob35a6192015-04-01 13:05:26 -0700107@Component(immediate = true)
Charles Chane849c192016-01-11 18:28:54 -0800108/**
109 * Segment routing manager.
110 */
sangho1e575652015-05-14 00:39:53 -0700111public class SegmentRoutingManager implements SegmentRoutingService {
sanghob35a6192015-04-01 13:05:26 -0700112
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700113 private static Logger log = LoggerFactory
114 .getLogger(SegmentRoutingManager.class);
sanghob35a6192015-04-01 13:05:26 -0700115
116 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
117 protected CoreService coreService;
118
119 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
sanghob35a6192015-04-01 13:05:26 -0700120 protected PacketService packetService;
121
122 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
sanghob35a6192015-04-01 13:05:26 -0700123 protected HostService hostService;
124
125 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
126 protected DeviceService deviceService;
127
128 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700129 protected FlowObjectiveService flowObjectiveService;
sanghob35a6192015-04-01 13:05:26 -0700130
131 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
132 protected LinkService linkService;
133
134 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
sanghob35a6192015-04-01 13:05:26 -0700135 protected MastershipService mastershipService;
sangho1e575652015-05-14 00:39:53 -0700136
Charles Chan5270ed02016-01-30 23:22:37 -0800137 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
138 protected StorageService storageService;
139
140 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
141 protected NetworkConfigRegistry cfgService;
142
Saurav Das80980c72016-03-23 11:22:49 -0700143 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
144 protected ComponentConfigService compCfgService;
145
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700146 protected ArpHandler arpHandler = null;
147 protected IcmpHandler icmpHandler = null;
148 protected IpHandler ipHandler = null;
149 protected RoutingRulePopulator routingRulePopulator = null;
sanghob35a6192015-04-01 13:05:26 -0700150 protected ApplicationId appId;
sangho666cd6d2015-04-14 16:27:13 -0700151 protected DeviceConfiguration deviceConfiguration = null;
sanghob35a6192015-04-01 13:05:26 -0700152
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700153 private DefaultRoutingHandler defaultRoutingHandler = null;
sangho1e575652015-05-14 00:39:53 -0700154 private TunnelHandler tunnelHandler = null;
155 private PolicyHandler policyHandler = null;
Charles Chanb8e10c82015-10-14 11:24:40 -0700156 private InternalPacketProcessor processor = null;
157 private InternalLinkListener linkListener = null;
158 private InternalDeviceListener deviceListener = null;
Charles Chan5270ed02016-01-30 23:22:37 -0800159 private NetworkConfigEventHandler netcfgHandler = null;
sanghob35a6192015-04-01 13:05:26 -0700160 private InternalEventHandler eventHandler = new InternalEventHandler();
Charles Chan5270ed02016-01-30 23:22:37 -0800161 private final InternalHostListener hostListener = new InternalHostListener();
sanghob35a6192015-04-01 13:05:26 -0700162
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700163 private ScheduledExecutorService executorService = Executors
164 .newScheduledThreadPool(1);
sanghob35a6192015-04-01 13:05:26 -0700165
Saurav Das4ce45962015-11-24 23:21:05 -0800166 @SuppressWarnings("unused")
sanghob35a6192015-04-01 13:05:26 -0700167 private static ScheduledFuture<?> eventHandlerFuture = null;
Saurav Das4ce45962015-11-24 23:21:05 -0800168 @SuppressWarnings("rawtypes")
sanghob35a6192015-04-01 13:05:26 -0700169 private ConcurrentLinkedQueue<Event> eventQueue = new ConcurrentLinkedQueue<Event>();
Charles Chan68aa62d2015-11-09 16:37:23 -0800170 private Map<DeviceId, DefaultGroupHandler> groupHandlerMap =
Charles Chane849c192016-01-11 18:28:54 -0800171 new ConcurrentHashMap<>();
172 /**
173 * Per device next objective ID store with (device id + neighbor set) as key.
174 */
175 public EventuallyConsistentMap<NeighborSetNextObjectiveStoreKey, Integer>
Charles Chan68aa62d2015-11-09 16:37:23 -0800176 nsNextObjStore = null;
Charles Chane849c192016-01-11 18:28:54 -0800177 /**
178 * Per device next objective ID store with (device id + subnet) as key.
179 */
180 public EventuallyConsistentMap<SubnetNextObjectiveStoreKey, Integer>
Charles Chan68aa62d2015-11-09 16:37:23 -0800181 subnetNextObjStore = null;
Charles Chane849c192016-01-11 18:28:54 -0800182 /**
183 * Per device next objective ID store with (device id + port) as key.
184 */
185 public EventuallyConsistentMap<PortNextObjectiveStoreKey, Integer>
Saurav Das4ce45962015-11-24 23:21:05 -0800186 portNextObjStore = null;
Charles Chane849c192016-01-11 18:28:54 -0800187 /**
188 * Per cross-connect objective ID store with VLAN ID as key.
189 */
190 public EventuallyConsistentMap<XConnectNextObjectiveStoreKey, Integer>
191 xConnectNextObjStore = null;
Saurav Das0e99e2b2015-10-28 12:39:42 -0700192 // Per device, per-subnet assigned-vlans store, with (device id + subnet
193 // IPv4 prefix) as key
194 private EventuallyConsistentMap<SubnetAssignedVidStoreKey, VlanId>
Charles Chane849c192016-01-11 18:28:54 -0800195 subnetVidStore = null;
Saurav Das4ce45962015-11-24 23:21:05 -0800196 private EventuallyConsistentMap<String, Tunnel> tunnelStore = null;
197 private EventuallyConsistentMap<String, Policy> policyStore = null;
sangho0b2b6d12015-05-20 22:16:38 -0700198
Charles Chan4636be02015-10-07 14:21:45 -0700199 private final InternalConfigListener cfgListener =
200 new InternalConfigListener(this);
201
Charles Chan5270ed02016-01-30 23:22:37 -0800202 private final ConfigFactory<DeviceId, SegmentRoutingDeviceConfig> cfgDeviceFactory =
203 new ConfigFactory<DeviceId, SegmentRoutingDeviceConfig>(SubjectFactories.DEVICE_SUBJECT_FACTORY,
204 SegmentRoutingDeviceConfig.class,
Charles Chand6832882015-10-05 17:50:33 -0700205 "segmentrouting") {
206 @Override
Charles Chan5270ed02016-01-30 23:22:37 -0800207 public SegmentRoutingDeviceConfig createConfig() {
208 return new SegmentRoutingDeviceConfig();
Charles Chand6832882015-10-05 17:50:33 -0700209 }
210 };
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700211
Charles Chan5270ed02016-01-30 23:22:37 -0800212 private final ConfigFactory<ApplicationId, SegmentRoutingAppConfig> cfgAppFactory =
213 new ConfigFactory<ApplicationId, SegmentRoutingAppConfig>(SubjectFactories.APP_SUBJECT_FACTORY,
214 SegmentRoutingAppConfig.class,
215 "segmentrouting") {
216 @Override
217 public SegmentRoutingAppConfig createConfig() {
218 return new SegmentRoutingAppConfig();
219 }
220 };
Charles Chan68aa62d2015-11-09 16:37:23 -0800221
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700222 private Object threadSchedulerLock = new Object();
223 private static int numOfEventsQueued = 0;
224 private static int numOfEventsExecuted = 0;
sanghob35a6192015-04-01 13:05:26 -0700225 private static int numOfHandlerExecution = 0;
226 private static int numOfHandlerScheduled = 0;
227
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700228 private KryoNamespace.Builder kryoBuilder = null;
Charles Chan116188d2016-02-18 14:22:42 -0800229 /**
230 * Segment Routing App ID.
231 */
232 public static final String SR_APP_ID = "org.onosproject.segmentrouting";
Charles Chane849c192016-01-11 18:28:54 -0800233 /**
234 * The starting value of per-subnet VLAN ID assignment.
235 */
Saurav Das0e99e2b2015-10-28 12:39:42 -0700236 private static final short ASSIGNED_VLAN_START = 4093;
Charles Chane849c192016-01-11 18:28:54 -0800237 /**
238 * The default VLAN ID assigned to the interfaces without subnet config.
239 */
Saurav Das0e99e2b2015-10-28 12:39:42 -0700240 public static final short ASSIGNED_VLAN_NO_SUBNET = 4094;
241
sanghob35a6192015-04-01 13:05:26 -0700242 @Activate
243 protected void activate() {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700244 appId = coreService
Charles Chan5270ed02016-01-30 23:22:37 -0800245 .registerApplication(SR_APP_ID);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700246
247 kryoBuilder = new KryoNamespace.Builder()
248 .register(NeighborSetNextObjectiveStoreKey.class,
Charles Chanc42e84e2015-10-20 16:24:19 -0700249 SubnetNextObjectiveStoreKey.class,
250 SubnetAssignedVidStoreKey.class,
sangho0b2b6d12015-05-20 22:16:38 -0700251 NeighborSet.class,
252 DeviceId.class,
253 URI.class,
254 WallClockTimestamp.class,
255 org.onosproject.cluster.NodeId.class,
256 HashSet.class,
257 Tunnel.class,
258 DefaultTunnel.class,
259 Policy.class,
260 TunnelPolicy.class,
Saurav Das0e99e2b2015-10-28 12:39:42 -0700261 Policy.Type.class,
Charles Chanc42e84e2015-10-20 16:24:19 -0700262 VlanId.class,
263 Ip4Address.class,
264 Ip4Prefix.class,
265 IpAddress.Version.class,
266 ConnectPoint.class
sangho0b2b6d12015-05-20 22:16:38 -0700267 );
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700268
269 log.debug("Creating EC map nsnextobjectivestore");
270 EventuallyConsistentMapBuilder<NeighborSetNextObjectiveStoreKey, Integer>
271 nsNextObjMapBuilder = storageService.eventuallyConsistentMapBuilder();
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700272 nsNextObjStore = nsNextObjMapBuilder
273 .withName("nsnextobjectivestore")
274 .withSerializer(kryoBuilder)
Madan Jampanibcf1a482015-06-24 19:05:56 -0700275 .withTimestampProvider((k, v) -> new WallClockTimestamp())
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700276 .build();
277 log.trace("Current size {}", nsNextObjStore.size());
278
Charles Chanc42e84e2015-10-20 16:24:19 -0700279 log.debug("Creating EC map subnetnextobjectivestore");
280 EventuallyConsistentMapBuilder<SubnetNextObjectiveStoreKey, Integer>
281 subnetNextObjMapBuilder = storageService.eventuallyConsistentMapBuilder();
Charles Chanc42e84e2015-10-20 16:24:19 -0700282 subnetNextObjStore = subnetNextObjMapBuilder
283 .withName("subnetnextobjectivestore")
284 .withSerializer(kryoBuilder)
285 .withTimestampProvider((k, v) -> new WallClockTimestamp())
286 .build();
287
Saurav Das4ce45962015-11-24 23:21:05 -0800288 log.debug("Creating EC map subnetnextobjectivestore");
289 EventuallyConsistentMapBuilder<PortNextObjectiveStoreKey, Integer>
290 portNextObjMapBuilder = storageService.eventuallyConsistentMapBuilder();
291 portNextObjStore = portNextObjMapBuilder
292 .withName("portnextobjectivestore")
293 .withSerializer(kryoBuilder)
294 .withTimestampProvider((k, v) -> new WallClockTimestamp())
295 .build();
296
Charles Chane849c192016-01-11 18:28:54 -0800297 log.debug("Creating EC map xconnectnextobjectivestore");
298 EventuallyConsistentMapBuilder<XConnectNextObjectiveStoreKey, Integer>
299 xConnectNextObjStoreBuilder = storageService.eventuallyConsistentMapBuilder();
300 xConnectNextObjStore = xConnectNextObjStoreBuilder
301 .withName("xconnectnextobjectivestore")
302 .withSerializer(kryoBuilder)
303 .withTimestampProvider((k, v) -> new WallClockTimestamp())
304 .build();
305
sangho0b2b6d12015-05-20 22:16:38 -0700306 EventuallyConsistentMapBuilder<String, Tunnel> tunnelMapBuilder =
307 storageService.eventuallyConsistentMapBuilder();
sangho0b2b6d12015-05-20 22:16:38 -0700308 tunnelStore = tunnelMapBuilder
309 .withName("tunnelstore")
310 .withSerializer(kryoBuilder)
Madan Jampanibcf1a482015-06-24 19:05:56 -0700311 .withTimestampProvider((k, v) -> new WallClockTimestamp())
sangho0b2b6d12015-05-20 22:16:38 -0700312 .build();
313
314 EventuallyConsistentMapBuilder<String, Policy> policyMapBuilder =
315 storageService.eventuallyConsistentMapBuilder();
sangho0b2b6d12015-05-20 22:16:38 -0700316 policyStore = policyMapBuilder
317 .withName("policystore")
318 .withSerializer(kryoBuilder)
Madan Jampanibcf1a482015-06-24 19:05:56 -0700319 .withTimestampProvider((k, v) -> new WallClockTimestamp())
sangho0b2b6d12015-05-20 22:16:38 -0700320 .build();
321
Saurav Das0e99e2b2015-10-28 12:39:42 -0700322 EventuallyConsistentMapBuilder<SubnetAssignedVidStoreKey, VlanId>
323 subnetVidStoreMapBuilder = storageService.eventuallyConsistentMapBuilder();
Saurav Das0e99e2b2015-10-28 12:39:42 -0700324 subnetVidStore = subnetVidStoreMapBuilder
325 .withName("subnetvidstore")
326 .withSerializer(kryoBuilder)
327 .withTimestampProvider((k, v) -> new WallClockTimestamp())
328 .build();
329
Saurav Das80980c72016-03-23 11:22:49 -0700330 compCfgService.preSetProperty("org.onosproject.net.group.impl.GroupManager",
331 "purgeOnDisconnection", "true");
332 compCfgService.preSetProperty("org.onosproject.net.flow.impl.FlowRuleManager",
333 "purgeOnDisconnection", "true");
334
Charles Chanb8e10c82015-10-14 11:24:40 -0700335 processor = new InternalPacketProcessor();
336 linkListener = new InternalLinkListener();
337 deviceListener = new InternalDeviceListener();
Charles Chan5270ed02016-01-30 23:22:37 -0800338 netcfgHandler = new NetworkConfigEventHandler(this);
Charles Chanb8e10c82015-10-14 11:24:40 -0700339
Charles Chan3e783d02016-02-26 22:19:52 -0800340 cfgService.addListener(cfgListener);
341 cfgService.registerConfigFactory(cfgDeviceFactory);
342 cfgService.registerConfigFactory(cfgAppFactory);
Charles Chan5270ed02016-01-30 23:22:37 -0800343 hostService.addListener(hostListener);
Charles Chanb8e10c82015-10-14 11:24:40 -0700344 packetService.addProcessor(processor, PacketProcessor.director(2));
345 linkService.addListener(linkListener);
346 deviceService.addListener(deviceListener);
347
Charles Chan188ebf52015-12-23 00:15:11 -0800348 // Request ARP packet-in
349 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
350 selector.matchEthType(Ethernet.TYPE_ARP);
351 packetService.requestPackets(selector.build(), PacketPriority.CONTROL, appId, Optional.empty());
352
Charles Chanb8e10c82015-10-14 11:24:40 -0700353 cfgListener.configureNetwork();
354
sanghob35a6192015-04-01 13:05:26 -0700355 log.info("Started");
356 }
357
358 @Deactivate
359 protected void deactivate() {
Charles Chand6832882015-10-05 17:50:33 -0700360 cfgService.removeListener(cfgListener);
Charles Chan5270ed02016-01-30 23:22:37 -0800361 cfgService.unregisterConfigFactory(cfgDeviceFactory);
362 cfgService.unregisterConfigFactory(cfgAppFactory);
Charles Chand6832882015-10-05 17:50:33 -0700363
Charles Chan188ebf52015-12-23 00:15:11 -0800364 // Withdraw ARP packet-in
365 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
366 selector.matchEthType(Ethernet.TYPE_ARP);
367 packetService.cancelPackets(selector.build(), PacketPriority.CONTROL, appId, Optional.empty());
368
sanghob35a6192015-04-01 13:05:26 -0700369 packetService.removeProcessor(processor);
Charles Chanb8e10c82015-10-14 11:24:40 -0700370 linkService.removeListener(linkListener);
371 deviceService.removeListener(deviceListener);
sanghob35a6192015-04-01 13:05:26 -0700372 processor = null;
Charles Chanb8e10c82015-10-14 11:24:40 -0700373 linkListener = null;
374 deviceService = null;
375
376 groupHandlerMap.clear();
377
sanghob35a6192015-04-01 13:05:26 -0700378 log.info("Stopped");
379 }
380
sangho1e575652015-05-14 00:39:53 -0700381
382 @Override
383 public List<Tunnel> getTunnels() {
384 return tunnelHandler.getTunnels();
385 }
386
387 @Override
sangho71abe1b2015-06-29 14:58:47 -0700388 public TunnelHandler.Result createTunnel(Tunnel tunnel) {
389 return tunnelHandler.createTunnel(tunnel);
sangho1e575652015-05-14 00:39:53 -0700390 }
391
392 @Override
sangho71abe1b2015-06-29 14:58:47 -0700393 public TunnelHandler.Result removeTunnel(Tunnel tunnel) {
sangho1e575652015-05-14 00:39:53 -0700394 for (Policy policy: policyHandler.getPolicies()) {
395 if (policy.type() == Policy.Type.TUNNEL_FLOW) {
396 TunnelPolicy tunnelPolicy = (TunnelPolicy) policy;
397 if (tunnelPolicy.tunnelId().equals(tunnel.id())) {
398 log.warn("Cannot remove the tunnel used by a policy");
sangho71abe1b2015-06-29 14:58:47 -0700399 return TunnelHandler.Result.TUNNEL_IN_USE;
sangho1e575652015-05-14 00:39:53 -0700400 }
401 }
402 }
sangho71abe1b2015-06-29 14:58:47 -0700403 return tunnelHandler.removeTunnel(tunnel);
sangho1e575652015-05-14 00:39:53 -0700404 }
405
406 @Override
sangho71abe1b2015-06-29 14:58:47 -0700407 public PolicyHandler.Result removePolicy(Policy policy) {
408 return policyHandler.removePolicy(policy);
sangho1e575652015-05-14 00:39:53 -0700409 }
410
411 @Override
sangho71abe1b2015-06-29 14:58:47 -0700412 public PolicyHandler.Result createPolicy(Policy policy) {
413 return policyHandler.createPolicy(policy);
sangho1e575652015-05-14 00:39:53 -0700414 }
415
416 @Override
417 public List<Policy> getPolicies() {
418 return policyHandler.getPolicies();
419 }
420
sanghof9d0bf12015-05-19 11:57:42 -0700421 /**
422 * Returns the tunnel object with the tunnel ID.
423 *
424 * @param tunnelId Tunnel ID
425 * @return Tunnel reference
426 */
sangho1e575652015-05-14 00:39:53 -0700427 public Tunnel getTunnel(String tunnelId) {
428 return tunnelHandler.getTunnel(tunnelId);
429 }
430
sanghob35a6192015-04-01 13:05:26 -0700431 /**
Saurav Das0e99e2b2015-10-28 12:39:42 -0700432 * Returns the vlan-id assigned to the subnet configured for a device.
433 * If no vlan-id has been assigned, a new one is assigned out of a pool of ids,
434 * if and only if this controller instance is the master for the device.
435 * <p>
436 * USAGE: The assigned vlans are meant to be applied to untagged packets on those
437 * switches/pipelines that need this functionality. These vids are meant
438 * to be used internally within a switch, and thus need to be unique only
439 * on a switch level. Note that packets never go out on the wire with these
440 * vlans. Currently, vlan ids are assigned from value 4093 down.
441 * Vlan id 4094 expected to be used for all ports that are not assigned subnets.
442 * Vlan id 4095 is reserved and unused. Only a single vlan id is assigned
443 * per subnet.
sanghob35a6192015-04-01 13:05:26 -0700444 *
Saurav Das0e99e2b2015-10-28 12:39:42 -0700445 * @param deviceId switch dpid
446 * @param subnet IPv4 prefix for which assigned vlan is desired
447 * @return VlanId assigned for the subnet on the device, or
448 * null if no vlan assignment was found and this instance is not
449 * the master for the device.
sanghob35a6192015-04-01 13:05:26 -0700450 */
Charles Chane849c192016-01-11 18:28:54 -0800451 // TODO: We should avoid assigning VLAN IDs that are used by VLAN cross-connection.
Saurav Das0e99e2b2015-10-28 12:39:42 -0700452 public VlanId getSubnetAssignedVlanId(DeviceId deviceId, Ip4Prefix subnet) {
453 VlanId assignedVid = subnetVidStore.get(new SubnetAssignedVidStoreKey(
454 deviceId, subnet));
455 if (assignedVid != null) {
456 log.debug("Query for subnet:{} on device:{} returned assigned-vlan "
457 + "{}", subnet, deviceId, assignedVid);
458 return assignedVid;
459 }
460 //check mastership for the right to assign a vlan
461 if (!mastershipService.isLocalMaster(deviceId)) {
462 log.warn("This controller instance is not the master for device {}. "
463 + "Cannot assign vlan-id for subnet {}", deviceId, subnet);
464 return null;
465 }
466 // vlan assignment is expensive but done only once
Charles Chan9f676b62015-10-29 14:58:10 -0700467 Set<Ip4Prefix> configuredSubnets = deviceConfiguration.getSubnets(deviceId);
Saurav Das0e99e2b2015-10-28 12:39:42 -0700468 Set<Short> assignedVlans = new HashSet<>();
469 Set<Ip4Prefix> unassignedSubnets = new HashSet<>();
470 for (Ip4Prefix sub : configuredSubnets) {
471 VlanId v = subnetVidStore.get(new SubnetAssignedVidStoreKey(deviceId,
472 sub));
473 if (v != null) {
474 assignedVlans.add(v.toShort());
475 } else {
476 unassignedSubnets.add(sub);
477 }
478 }
479 short nextAssignedVlan = ASSIGNED_VLAN_START;
480 if (!assignedVlans.isEmpty()) {
481 nextAssignedVlan = (short) (Collections.min(assignedVlans) - 1);
482 }
483 for (Ip4Prefix unsub : unassignedSubnets) {
Charles Chan5270ed02016-01-30 23:22:37 -0800484 // Special case for default route. Assign default VLAN ID to /32 and /0 subnets
485 if (unsub.prefixLength() == IpPrefix.MAX_INET_MASK_LENGTH ||
486 unsub.prefixLength() == 0) {
487 subnetVidStore.put(new SubnetAssignedVidStoreKey(deviceId, unsub),
488 VlanId.vlanId(ASSIGNED_VLAN_NO_SUBNET));
489 } else {
490 subnetVidStore.put(new SubnetAssignedVidStoreKey(deviceId, unsub),
491 VlanId.vlanId(nextAssignedVlan--));
492 log.info("Assigned vlan: {} to subnet: {} on device: {}",
493 nextAssignedVlan + 1, unsub, deviceId);
494 }
sanghob35a6192015-04-01 13:05:26 -0700495 }
496
Saurav Das0e99e2b2015-10-28 12:39:42 -0700497 return subnetVidStore.get(new SubnetAssignedVidStoreKey(deviceId, subnet));
sanghob35a6192015-04-01 13:05:26 -0700498 }
499
sangho1e575652015-05-14 00:39:53 -0700500 /**
Saurav Das0e99e2b2015-10-28 12:39:42 -0700501 * Returns the next objective ID for the given NeighborSet.
Saurav Das8a0732e2015-11-20 15:27:53 -0800502 * If the nextObjective does not exist, a new one is created and
Saurav Das4ce45962015-11-24 23:21:05 -0800503 * its id is returned.
sangho1e575652015-05-14 00:39:53 -0700504 *
sanghof9d0bf12015-05-19 11:57:42 -0700505 * @param deviceId Device ID
506 * @param ns NegighborSet
Saurav Das8a0732e2015-11-20 15:27:53 -0800507 * @param meta metadata passed into the creation of a Next Objective
508 * @return next objective ID or -1 if an error was encountered during the
509 * creation of the nextObjective
sangho1e575652015-05-14 00:39:53 -0700510 */
Saurav Das8a0732e2015-11-20 15:27:53 -0800511 public int getNextObjectiveId(DeviceId deviceId, NeighborSet ns,
512 TrafficSelector meta) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700513 if (groupHandlerMap.get(deviceId) != null) {
514 log.trace("getNextObjectiveId query in device {}", deviceId);
515 return groupHandlerMap
Saurav Das8a0732e2015-11-20 15:27:53 -0800516 .get(deviceId).getNextObjectiveId(ns, meta);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700517 } else {
Saurav Das4ce45962015-11-24 23:21:05 -0800518 log.warn("getNextObjectiveId query - groupHandler for device {} "
519 + "not found", deviceId);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700520 return -1;
521 }
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700522 }
523
Charles Chanc42e84e2015-10-20 16:24:19 -0700524 /**
Saurav Das4ce45962015-11-24 23:21:05 -0800525 * Returns the next objective ID for the given subnet prefix. It is expected
526 * that the next-objective has been pre-created from configuration.
Charles Chanc42e84e2015-10-20 16:24:19 -0700527 *
528 * @param deviceId Device ID
529 * @param prefix Subnet
Saurav Das4ce45962015-11-24 23:21:05 -0800530 * @return next objective ID or -1 if it was not found
Charles Chanc42e84e2015-10-20 16:24:19 -0700531 */
532 public int getSubnetNextObjectiveId(DeviceId deviceId, IpPrefix prefix) {
533 if (groupHandlerMap.get(deviceId) != null) {
534 log.trace("getSubnetNextObjectiveId query in device {}", deviceId);
535 return groupHandlerMap
536 .get(deviceId).getSubnetNextObjectiveId(prefix);
537 } else {
Saurav Das4ce45962015-11-24 23:21:05 -0800538 log.warn("getSubnetNextObjectiveId query - groupHandler for "
539 + "device {} not found", deviceId);
540 return -1;
541 }
542 }
543
544 /**
545 * Returns the next objective ID for the given portNumber, given the treatment.
546 * There could be multiple different treatments to the same outport, which
547 * would result in different objectives. If the next object
548 * does not exist, a new one is created and its id is returned.
549 *
550 * @param deviceId Device ID
551 * @param portNum port number on device for which NextObjective is queried
552 * @param treatment the actions to apply on the packets (should include outport)
553 * @param meta metadata passed into the creation of a Next Objective if necessary
554 * @return next objective ID or -1 if it was not found
555 */
556 public int getPortNextObjectiveId(DeviceId deviceId, PortNumber portNum,
557 TrafficTreatment treatment,
558 TrafficSelector meta) {
559 DefaultGroupHandler ghdlr = groupHandlerMap.get(deviceId);
560 if (ghdlr != null) {
561 return ghdlr.getPortNextObjectiveId(portNum, treatment, meta);
562 } else {
Charles Chane849c192016-01-11 18:28:54 -0800563 log.warn("getPortNextObjectiveId query - groupHandler for device {}"
564 + " not found", deviceId);
565 return -1;
566 }
567 }
568
569 /**
570 * Returns the next objective ID of type broadcast associated with the VLAN
571 * cross-connection.
572 *
573 * @param deviceId Device ID for the cross-connection
574 * @param vlanId VLAN ID for the cross-connection
575 * @return next objective ID or -1 if it was not found
576 */
577 public int getXConnectNextObjectiveId(DeviceId deviceId, VlanId vlanId) {
578 DefaultGroupHandler ghdlr = groupHandlerMap.get(deviceId);
579 if (ghdlr != null) {
580 return ghdlr.getXConnectNextObjectiveId(vlanId);
581 } else {
582 log.warn("getPortNextObjectiveId query - groupHandler for device {}"
Saurav Das4ce45962015-11-24 23:21:05 -0800583 + " not found", deviceId);
Charles Chanc42e84e2015-10-20 16:24:19 -0700584 return -1;
585 }
586 }
587
sanghob35a6192015-04-01 13:05:26 -0700588 private class InternalPacketProcessor implements PacketProcessor {
sanghob35a6192015-04-01 13:05:26 -0700589 @Override
590 public void process(PacketContext context) {
591
592 if (context.isHandled()) {
593 return;
594 }
595
596 InboundPacket pkt = context.inPacket();
597 Ethernet ethernet = pkt.parsed();
Saurav Das4ce45962015-11-24 23:21:05 -0800598 log.trace("Rcvd pktin: {}", ethernet);
sanghob35a6192015-04-01 13:05:26 -0700599 if (ethernet.getEtherType() == Ethernet.TYPE_ARP) {
600 arpHandler.processPacketIn(pkt);
601 } else if (ethernet.getEtherType() == Ethernet.TYPE_IPV4) {
602 IPv4 ipPacket = (IPv4) ethernet.getPayload();
603 ipHandler.addToPacketBuffer(ipPacket);
604 if (ipPacket.getProtocol() == IPv4.PROTOCOL_ICMP) {
605 icmpHandler.processPacketIn(pkt);
606 } else {
607 ipHandler.processPacketIn(pkt);
608 }
609 }
610 }
611 }
612
613 private class InternalLinkListener implements LinkListener {
614 @Override
615 public void event(LinkEvent event) {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700616 if (event.type() == LinkEvent.Type.LINK_ADDED
617 || event.type() == LinkEvent.Type.LINK_REMOVED) {
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700618 log.debug("Event {} received from Link Service", event.type());
sanghob35a6192015-04-01 13:05:26 -0700619 scheduleEventHandlerIfNotScheduled(event);
620 }
621 }
622 }
623
624 private class InternalDeviceListener implements DeviceListener {
sanghob35a6192015-04-01 13:05:26 -0700625 @Override
626 public void event(DeviceEvent event) {
sanghob35a6192015-04-01 13:05:26 -0700627 switch (event.type()) {
628 case DEVICE_ADDED:
629 case PORT_REMOVED:
sangho20eff1d2015-04-13 15:15:58 -0700630 case DEVICE_UPDATED:
631 case DEVICE_AVAILABILITY_CHANGED:
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700632 log.debug("Event {} received from Device Service", event.type());
sanghob35a6192015-04-01 13:05:26 -0700633 scheduleEventHandlerIfNotScheduled(event);
634 break;
635 default:
636 }
637 }
638 }
639
Saurav Das4ce45962015-11-24 23:21:05 -0800640 @SuppressWarnings("rawtypes")
sanghob35a6192015-04-01 13:05:26 -0700641 private void scheduleEventHandlerIfNotScheduled(Event event) {
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700642 synchronized (threadSchedulerLock) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700643 eventQueue.add(event);
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700644 numOfEventsQueued++;
645
646 if ((numOfHandlerScheduled - numOfHandlerExecution) == 0) {
647 //No pending scheduled event handling threads. So start a new one.
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700648 eventHandlerFuture = executorService
649 .schedule(eventHandler, 100, TimeUnit.MILLISECONDS);
650 numOfHandlerScheduled++;
651 }
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700652 log.trace("numOfEventsQueued {}, numOfEventHanlderScheduled {}",
653 numOfEventsQueued,
654 numOfHandlerScheduled);
sanghob35a6192015-04-01 13:05:26 -0700655 }
sanghob35a6192015-04-01 13:05:26 -0700656 }
657
658 private class InternalEventHandler implements Runnable {
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700659 @Override
sanghob35a6192015-04-01 13:05:26 -0700660 public void run() {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700661 try {
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700662 while (true) {
Saurav Das4ce45962015-11-24 23:21:05 -0800663 @SuppressWarnings("rawtypes")
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700664 Event event = null;
665 synchronized (threadSchedulerLock) {
666 if (!eventQueue.isEmpty()) {
667 event = eventQueue.poll();
668 numOfEventsExecuted++;
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700669 } else {
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700670 numOfHandlerExecution++;
671 log.debug("numOfHandlerExecution {} numOfEventsExecuted {}",
672 numOfHandlerExecution, numOfEventsExecuted);
673 break;
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700674 }
sangho20eff1d2015-04-13 15:15:58 -0700675 }
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700676 if (event.type() == LinkEvent.Type.LINK_ADDED) {
677 processLinkAdded((Link) event.subject());
678 } else if (event.type() == LinkEvent.Type.LINK_REMOVED) {
679 processLinkRemoved((Link) event.subject());
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700680 } else if (event.type() == DeviceEvent.Type.DEVICE_ADDED ||
681 event.type() == DeviceEvent.Type.DEVICE_AVAILABILITY_CHANGED ||
682 event.type() == DeviceEvent.Type.DEVICE_UPDATED) {
Saurav Das423fe2b2015-12-04 10:52:59 -0800683 DeviceId deviceId = ((Device) event.subject()).id();
684 if (deviceService.isAvailable(deviceId)) {
Saurav Das837e0bb2015-10-30 17:45:38 -0700685 log.info("Processing device event {} for available device {}",
686 event.type(), ((Device) event.subject()).id());
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700687 processDeviceAdded((Device) event.subject());
Saurav Das80980c72016-03-23 11:22:49 -0700688 } else {
689 log.info("Processing device event {} for unavailable device {}",
690 event.type(), ((Device) event.subject()).id());
691 processDeviceRemoved((Device) event.subject());
692 }
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700693 } else if (event.type() == DeviceEvent.Type.PORT_REMOVED) {
694 processPortRemoved((Device) event.subject(),
695 ((DeviceEvent) event).port());
696 } else {
697 log.warn("Unhandled event type: {}", event.type());
698 }
sanghob35a6192015-04-01 13:05:26 -0700699 }
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700700 } catch (Exception e) {
701 log.error("SegmentRouting event handler "
702 + "thread thrown an exception: {}", e);
sanghob35a6192015-04-01 13:05:26 -0700703 }
sanghob35a6192015-04-01 13:05:26 -0700704 }
705 }
706
sanghob35a6192015-04-01 13:05:26 -0700707 private void processLinkAdded(Link link) {
708 log.debug("A new link {} was added", link.toString());
Charles Chan0b4e6182015-11-03 10:42:14 -0800709 if (!deviceConfiguration.isConfigured(link.src().deviceId())) {
710 log.warn("Source device of this link is not configured.");
711 return;
712 }
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700713 //Irrespective whether the local is a MASTER or not for this device,
714 //create group handler instance and push default TTP flow rules.
715 //Because in a multi-instance setup, instances can initiate
716 //groups for any devices. Also the default TTP rules are needed
717 //to be pushed before inserting any IP table entries for any device
718 DefaultGroupHandler groupHandler = groupHandlerMap.get(link.src()
719 .deviceId());
720 if (groupHandler != null) {
Saurav Das8a0732e2015-11-20 15:27:53 -0800721 groupHandler.linkUp(link, mastershipService.isLocalMaster(
722 link.src().deviceId()));
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700723 } else {
724 Device device = deviceService.getDevice(link.src().deviceId());
725 if (device != null) {
726 log.warn("processLinkAdded: Link Added "
727 + "Notification without Device Added "
728 + "event, still handling it");
729 processDeviceAdded(device);
730 groupHandler = groupHandlerMap.get(link.src()
731 .deviceId());
Saurav Das8a0732e2015-11-20 15:27:53 -0800732 groupHandler.linkUp(link, mastershipService.isLocalMaster(device.id()));
sanghob35a6192015-04-01 13:05:26 -0700733 }
734 }
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700735
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700736 log.trace("Starting optimized route population process");
737 defaultRoutingHandler.populateRoutingRulesForLinkStatusChange(null);
738 //log.trace("processLinkAdded: re-starting route population process");
739 //defaultRoutingHandler.startPopulationProcess();
sanghob35a6192015-04-01 13:05:26 -0700740 }
741
742 private void processLinkRemoved(Link link) {
743 log.debug("A link {} was removed", link.toString());
sangho834e4b02015-05-01 09:38:25 -0700744 DefaultGroupHandler groupHandler = groupHandlerMap.get(link.src().deviceId());
745 if (groupHandler != null) {
Saurav Das423fe2b2015-12-04 10:52:59 -0800746 groupHandler.portDown(link.src().port(),
747 mastershipService.isLocalMaster(link.src().deviceId()));
sangho834e4b02015-05-01 09:38:25 -0700748 }
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700749 log.trace("Starting optimized route population process");
750 defaultRoutingHandler.populateRoutingRulesForLinkStatusChange(link);
751 //log.trace("processLinkRemoved: re-starting route population process");
752 //defaultRoutingHandler.startPopulationProcess();
sanghob35a6192015-04-01 13:05:26 -0700753 }
754
755 private void processDeviceAdded(Device device) {
756 log.debug("A new device with ID {} was added", device.id());
Charles Chan0b4e6182015-11-03 10:42:14 -0800757 if (deviceConfiguration == null || !deviceConfiguration.isConfigured(device.id())) {
Saurav Das2857f382015-11-03 14:39:27 -0800758 log.warn("Device configuration uploading. Device {} will be "
759 + "processed after config completes.", device.id());
760 return;
761 }
Saurav Das837e0bb2015-10-30 17:45:38 -0700762 // Irrespective of whether the local is a MASTER or not for this device,
763 // we need to create a SR-group-handler instance. This is because in a
764 // multi-instance setup, any instance can initiate forwarding/next-objectives
765 // for any switch (even if this instance is a SLAVE or not even connected
766 // to the switch). To handle this, a default-group-handler instance is necessary
767 // per switch.
Saurav Das2857f382015-11-03 14:39:27 -0800768 if (groupHandlerMap.get(device.id()) == null) {
Charles Chan0b4e6182015-11-03 10:42:14 -0800769 DefaultGroupHandler groupHandler;
770 try {
771 groupHandler = DefaultGroupHandler.
772 createGroupHandler(device.id(),
773 appId,
774 deviceConfiguration,
775 linkService,
776 flowObjectiveService,
Charles Chan188ebf52015-12-23 00:15:11 -0800777 this);
Charles Chan0b4e6182015-11-03 10:42:14 -0800778 } catch (DeviceConfigNotFoundException e) {
779 log.warn(e.getMessage() + " Aborting processDeviceAdded.");
780 return;
781 }
Saurav Das2857f382015-11-03 14:39:27 -0800782 groupHandlerMap.put(device.id(), groupHandler);
783 // Also, in some cases, drivers may need extra
784 // information to process rules (eg. Router IP/MAC); and so, we send
785 // port addressing rules to the driver as well irrespective of whether
786 // this instance is the master or not.
787 defaultRoutingHandler.populatePortAddressingRules(device.id());
Charles Chand6d581a2015-11-18 16:51:08 -0800788 hostListener.readInitialHosts();
Saurav Das2857f382015-11-03 14:39:27 -0800789 }
Charles Chanc42e84e2015-10-20 16:24:19 -0700790 if (mastershipService.isLocalMaster(device.id())) {
Saurav Das2857f382015-11-03 14:39:27 -0800791 DefaultGroupHandler groupHandler = groupHandlerMap.get(device.id());
Charles Chanc42e84e2015-10-20 16:24:19 -0700792 groupHandler.createGroupsFromSubnetConfig();
Charles Chan68aa62d2015-11-09 16:37:23 -0800793 routingRulePopulator.populateSubnetBroadcastRule(device.id());
Charles Chane849c192016-01-11 18:28:54 -0800794 groupHandler.createGroupsForXConnect(device.id());
795 routingRulePopulator.populateXConnectBroadcastRule(device.id());
Charles Chanc42e84e2015-10-20 16:24:19 -0700796 }
Charles Chan5270ed02016-01-30 23:22:37 -0800797
798 netcfgHandler.initVRouters(device.id());
sanghob35a6192015-04-01 13:05:26 -0700799 }
800
Saurav Das80980c72016-03-23 11:22:49 -0700801 private void processDeviceRemoved(Device device) {
802 nsNextObjStore.entrySet().stream()
803 .filter(entry -> entry.getKey().deviceId().equals(device.id()))
804 .forEach(entry -> {
805 nsNextObjStore.remove(entry.getKey());
806 });
807
808 subnetNextObjStore.entrySet().stream()
809 .filter(entry -> entry.getKey().deviceId().equals(device.id()))
810 .forEach(entry -> {
811 subnetNextObjStore.remove(entry.getKey());
812 });
813
814 portNextObjStore.entrySet().stream()
815 .filter(entry -> entry.getKey().deviceId().equals(device.id()))
816 .forEach(entry -> {
817 portNextObjStore.remove(entry.getKey());
818 });
819
820 xConnectNextObjStore.entrySet().stream()
821 .filter(entry -> entry.getKey().deviceId().equals(device.id()))
822 .forEach(entry -> {
823 xConnectNextObjStore.remove(entry.getKey());
824 });
825
826 subnetVidStore.entrySet().stream()
827 .filter(entry -> entry.getKey().deviceId().equals(device.id()))
828 .forEach(entry -> {
829 subnetVidStore.remove(entry.getKey());
830 });
831
832 groupHandlerMap.remove(device.id());
833
834 defaultRoutingHandler.purgeEcmpGraph(device.id());
835 }
836
sanghob35a6192015-04-01 13:05:26 -0700837 private void processPortRemoved(Device device, Port port) {
838 log.debug("Port {} was removed", port.toString());
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700839 DefaultGroupHandler groupHandler = groupHandlerMap.get(device.id());
sanghob35a6192015-04-01 13:05:26 -0700840 if (groupHandler != null) {
Saurav Das423fe2b2015-12-04 10:52:59 -0800841 groupHandler.portDown(port.number(),
842 mastershipService.isLocalMaster(device.id()));
sanghob35a6192015-04-01 13:05:26 -0700843 }
844 }
sangho1e575652015-05-14 00:39:53 -0700845
Charles Chand6832882015-10-05 17:50:33 -0700846 private class InternalConfigListener implements NetworkConfigListener {
Charles Chan4636be02015-10-07 14:21:45 -0700847 SegmentRoutingManager segmentRoutingManager;
848
Charles Chane849c192016-01-11 18:28:54 -0800849 /**
850 * Constructs the internal network config listener.
851 *
852 * @param srMgr segment routing manager
853 */
Charles Chan4636be02015-10-07 14:21:45 -0700854 public InternalConfigListener(SegmentRoutingManager srMgr) {
855 this.segmentRoutingManager = srMgr;
856 }
857
Charles Chane849c192016-01-11 18:28:54 -0800858 /**
859 * Reads network config and initializes related data structure accordingly.
860 */
Charles Chan4636be02015-10-07 14:21:45 -0700861 public void configureNetwork() {
Charles Chanf2565a92016-02-10 20:46:58 -0800862 deviceConfiguration = new DeviceConfiguration(appId,
863 segmentRoutingManager.cfgService);
Charles Chan4636be02015-10-07 14:21:45 -0700864
865 arpHandler = new ArpHandler(segmentRoutingManager);
866 icmpHandler = new IcmpHandler(segmentRoutingManager);
867 ipHandler = new IpHandler(segmentRoutingManager);
868 routingRulePopulator = new RoutingRulePopulator(segmentRoutingManager);
869 defaultRoutingHandler = new DefaultRoutingHandler(segmentRoutingManager);
870
871 tunnelHandler = new TunnelHandler(linkService, deviceConfiguration,
872 groupHandlerMap, tunnelStore);
873 policyHandler = new PolicyHandler(appId, deviceConfiguration,
874 flowObjectiveService,
875 tunnelHandler, policyStore);
876
Charles Chan4636be02015-10-07 14:21:45 -0700877 for (Device device : deviceService.getDevices()) {
Saurav Das837e0bb2015-10-30 17:45:38 -0700878 // Irrespective of whether the local is a MASTER or not for this device,
879 // we need to create a SR-group-handler instance. This is because in a
880 // multi-instance setup, any instance can initiate forwarding/next-objectives
881 // for any switch (even if this instance is a SLAVE or not even connected
882 // to the switch). To handle this, a default-group-handler instance is necessary
883 // per switch.
Saurav Das2857f382015-11-03 14:39:27 -0800884 if (groupHandlerMap.get(device.id()) == null) {
Charles Chan0b4e6182015-11-03 10:42:14 -0800885 DefaultGroupHandler groupHandler;
886 try {
887 groupHandler = DefaultGroupHandler.
888 createGroupHandler(device.id(),
889 appId,
890 deviceConfiguration,
891 linkService,
892 flowObjectiveService,
Charles Chan188ebf52015-12-23 00:15:11 -0800893 segmentRoutingManager);
Charles Chan0b4e6182015-11-03 10:42:14 -0800894 } catch (DeviceConfigNotFoundException e) {
895 log.warn(e.getMessage() + " Aborting configureNetwork.");
896 return;
897 }
Saurav Das2857f382015-11-03 14:39:27 -0800898 groupHandlerMap.put(device.id(), groupHandler);
Saurav Das837e0bb2015-10-30 17:45:38 -0700899
Saurav Das2857f382015-11-03 14:39:27 -0800900 // Also, in some cases, drivers may need extra
901 // information to process rules (eg. Router IP/MAC); and so, we send
902 // port addressing rules to the driver as well, irrespective of whether
903 // this instance is the master or not.
904 defaultRoutingHandler.populatePortAddressingRules(device.id());
Charles Chand6d581a2015-11-18 16:51:08 -0800905 hostListener.readInitialHosts();
Saurav Das2857f382015-11-03 14:39:27 -0800906 }
Charles Chanc42e84e2015-10-20 16:24:19 -0700907 if (mastershipService.isLocalMaster(device.id())) {
Saurav Das2857f382015-11-03 14:39:27 -0800908 DefaultGroupHandler groupHandler = groupHandlerMap.get(device.id());
Charles Chanc42e84e2015-10-20 16:24:19 -0700909 groupHandler.createGroupsFromSubnetConfig();
Charles Chan68aa62d2015-11-09 16:37:23 -0800910 routingRulePopulator.populateSubnetBroadcastRule(device.id());
Charles Chane849c192016-01-11 18:28:54 -0800911 groupHandler.createGroupsForXConnect(device.id());
912 routingRulePopulator.populateXConnectBroadcastRule(device.id());
Charles Chanc42e84e2015-10-20 16:24:19 -0700913 }
Charles Chan4636be02015-10-07 14:21:45 -0700914 }
915
916 defaultRoutingHandler.startPopulationProcess();
917 }
918
Charles Chand6832882015-10-05 17:50:33 -0700919 @Override
920 public void event(NetworkConfigEvent event) {
Charles Chan5270ed02016-01-30 23:22:37 -0800921 // TODO move this part to NetworkConfigEventHandler
922 if (event.configClass().equals(SegmentRoutingDeviceConfig.class)) {
923 switch (event.type()) {
924 case CONFIG_ADDED:
925 log.info("Segment Routing Config added.");
926 configureNetwork();
927 break;
928 case CONFIG_UPDATED:
929 log.info("Segment Routing Config updated.");
930 // TODO support dynamic configuration
931 break;
932 default:
933 break;
Charles Chanb8e10c82015-10-14 11:24:40 -0700934 }
Charles Chan5270ed02016-01-30 23:22:37 -0800935 } else if (event.configClass().equals(SegmentRoutingAppConfig.class)) {
Charles Chan3e783d02016-02-26 22:19:52 -0800936 checkState(netcfgHandler != null, "NetworkConfigEventHandler is not initialized");
Charles Chan5270ed02016-01-30 23:22:37 -0800937 switch (event.type()) {
938 case CONFIG_ADDED:
939 netcfgHandler.processVRouterConfigAdded(event);
940 break;
941 case CONFIG_UPDATED:
942 netcfgHandler.processVRouterConfigUpdated(event);
943 break;
944 case CONFIG_REMOVED:
945 netcfgHandler.processVRouterConfigRemoved(event);
946 break;
947 default:
948 break;
Charles Chanb8e10c82015-10-14 11:24:40 -0700949 }
Charles Chand6832882015-10-05 17:50:33 -0700950 }
951 }
952 }
Charles Chan68aa62d2015-11-09 16:37:23 -0800953
Charles Chand6d581a2015-11-18 16:51:08 -0800954 // TODO Move bridging table population to a separate class
Charles Chan68aa62d2015-11-09 16:37:23 -0800955 private class InternalHostListener implements HostListener {
Charles Chand6d581a2015-11-18 16:51:08 -0800956 private void readInitialHosts() {
957 hostService.getHosts().forEach(host -> {
958 MacAddress mac = host.mac();
959 VlanId vlanId = host.vlan();
960 DeviceId deviceId = host.location().deviceId();
961 PortNumber port = host.location().port();
962 Set<IpAddress> ips = host.ipAddresses();
963 log.debug("Host {}/{} is added at {}:{}", mac, vlanId, deviceId, port);
964
965 // Populate bridging table entry
966 ForwardingObjective.Builder fob =
Saurav Das4ce45962015-11-24 23:21:05 -0800967 getForwardingObjectiveBuilder(deviceId, mac, vlanId, port);
Charles Chand6d581a2015-11-18 16:51:08 -0800968 flowObjectiveService.forward(deviceId, fob.add(
969 new BridgingTableObjectiveContext(mac, vlanId)
970 ));
971
972 // Populate IP table entry
973 ips.forEach(ip -> {
974 if (ip.isIp4()) {
975 routingRulePopulator.populateIpRuleForHost(
976 deviceId, ip.getIp4Address(), mac, port);
977 }
978 });
979 });
980 }
981
Charles Chan68aa62d2015-11-09 16:37:23 -0800982 private ForwardingObjective.Builder getForwardingObjectiveBuilder(
Saurav Das4ce45962015-11-24 23:21:05 -0800983 DeviceId deviceId, MacAddress mac, VlanId vlanId,
984 PortNumber outport) {
Charles Chan188ebf52015-12-23 00:15:11 -0800985 // Get assigned VLAN for the subnet
Saurav Das4ce45962015-11-24 23:21:05 -0800986 VlanId outvlan = null;
987 Ip4Prefix subnet = deviceConfiguration.getPortSubnet(deviceId, outport);
988 if (subnet == null) {
989 outvlan = VlanId.vlanId(ASSIGNED_VLAN_NO_SUBNET);
990 } else {
991 outvlan = getSubnetAssignedVlanId(deviceId, subnet);
992 }
Charles Chan188ebf52015-12-23 00:15:11 -0800993
994 // match rule
995 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
996 sbuilder.matchEthDst(mac);
997 /*
998 * Note: for untagged packets, match on the assigned VLAN.
999 * for tagged packets, match on its incoming VLAN.
1000 */
1001 if (vlanId.equals(VlanId.NONE)) {
1002 sbuilder.matchVlanId(outvlan);
1003 } else {
1004 sbuilder.matchVlanId(vlanId);
1005 }
1006
1007 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
1008 tbuilder.immediate().popVlan();
1009 tbuilder.immediate().setOutput(outport);
1010
1011 // for switch pipelines that need it, provide outgoing vlan as metadata
Saurav Das4ce45962015-11-24 23:21:05 -08001012 TrafficSelector meta = DefaultTrafficSelector.builder()
1013 .matchVlanId(outvlan).build();
1014
1015 // All forwarding is via Groups. Drivers can re-purpose to flow-actions if needed.
1016 int portNextObjId = getPortNextObjectiveId(deviceId, outport,
1017 tbuilder.build(),
1018 meta);
Charles Chan68aa62d2015-11-09 16:37:23 -08001019
1020 return DefaultForwardingObjective.builder()
1021 .withFlag(ForwardingObjective.Flag.SPECIFIC)
1022 .withSelector(sbuilder.build())
Saurav Das4ce45962015-11-24 23:21:05 -08001023 .nextStep(portNextObjId)
Charles Chan68aa62d2015-11-09 16:37:23 -08001024 .withPriority(100)
1025 .fromApp(appId)
1026 .makePermanent();
1027 }
1028
1029 private void processHostAddedEvent(HostEvent event) {
1030 MacAddress mac = event.subject().mac();
1031 VlanId vlanId = event.subject().vlan();
1032 DeviceId deviceId = event.subject().location().deviceId();
1033 PortNumber port = event.subject().location().port();
1034 Set<IpAddress> ips = event.subject().ipAddresses();
Saurav Das4ce45962015-11-24 23:21:05 -08001035 log.info("Host {}/{} is added at {}:{}", mac, vlanId, deviceId, port);
Charles Chan68aa62d2015-11-09 16:37:23 -08001036
Charles Chand9681e72016-02-22 19:27:29 -08001037 if (!deviceConfiguration.suppressHost()
Charles Chanf2565a92016-02-10 20:46:58 -08001038 .contains(new ConnectPoint(deviceId, port))) {
1039 // Populate bridging table entry
1040 log.debug("Populate L2 table entry for host {} at {}:{}",
1041 mac, deviceId, port);
1042 ForwardingObjective.Builder fob =
1043 getForwardingObjectiveBuilder(deviceId, mac, vlanId, port);
1044 flowObjectiveService.forward(deviceId, fob.add(
1045 new BridgingTableObjectiveContext(mac, vlanId)
1046 ));
Charles Chan68aa62d2015-11-09 16:37:23 -08001047
Charles Chanf2565a92016-02-10 20:46:58 -08001048 // Populate IP table entry
1049 ips.forEach(ip -> {
1050 if (ip.isIp4()) {
1051 routingRulePopulator.populateIpRuleForHost(
1052 deviceId, ip.getIp4Address(), mac, port);
1053 }
1054 });
1055 }
Charles Chan68aa62d2015-11-09 16:37:23 -08001056 }
1057
1058 private void processHostRemoveEvent(HostEvent event) {
1059 MacAddress mac = event.subject().mac();
1060 VlanId vlanId = event.subject().vlan();
1061 DeviceId deviceId = event.subject().location().deviceId();
1062 PortNumber port = event.subject().location().port();
1063 Set<IpAddress> ips = event.subject().ipAddresses();
1064 log.debug("Host {}/{} is removed from {}:{}", mac, vlanId, deviceId, port);
1065
Charles Chand9681e72016-02-22 19:27:29 -08001066 if (!deviceConfiguration.suppressHost()
Charles Chanf2565a92016-02-10 20:46:58 -08001067 .contains(new ConnectPoint(deviceId, port))) {
1068 // Revoke bridging table entry
1069 ForwardingObjective.Builder fob =
1070 getForwardingObjectiveBuilder(deviceId, mac, vlanId, port);
1071 flowObjectiveService.forward(deviceId, fob.remove(
1072 new BridgingTableObjectiveContext(mac, vlanId)
1073 ));
Charles Chan68aa62d2015-11-09 16:37:23 -08001074
Charles Chanf2565a92016-02-10 20:46:58 -08001075 // Revoke IP table entry
1076 ips.forEach(ip -> {
1077 if (ip.isIp4()) {
1078 routingRulePopulator.revokeIpRuleForHost(
1079 deviceId, ip.getIp4Address(), mac, port);
1080 }
1081 });
1082 }
Charles Chan68aa62d2015-11-09 16:37:23 -08001083 }
1084
1085 private void processHostMovedEvent(HostEvent event) {
1086 MacAddress mac = event.subject().mac();
1087 VlanId vlanId = event.subject().vlan();
1088 DeviceId prevDeviceId = event.prevSubject().location().deviceId();
1089 PortNumber prevPort = event.prevSubject().location().port();
1090 Set<IpAddress> prevIps = event.prevSubject().ipAddresses();
1091 DeviceId newDeviceId = event.subject().location().deviceId();
1092 PortNumber newPort = event.subject().location().port();
1093 Set<IpAddress> newIps = event.subject().ipAddresses();
1094 log.debug("Host {}/{} is moved from {}:{} to {}:{}",
1095 mac, vlanId, prevDeviceId, prevPort, newDeviceId, newPort);
1096
Charles Chand9681e72016-02-22 19:27:29 -08001097 if (!deviceConfiguration.suppressHost()
Charles Chanf2565a92016-02-10 20:46:58 -08001098 .contains(new ConnectPoint(prevDeviceId, prevPort))) {
1099 // Revoke previous bridging table entry
1100 ForwardingObjective.Builder prevFob =
1101 getForwardingObjectiveBuilder(prevDeviceId, mac, vlanId, prevPort);
1102 flowObjectiveService.forward(prevDeviceId, prevFob.remove(
1103 new BridgingTableObjectiveContext(mac, vlanId)
1104 ));
Charles Chan68aa62d2015-11-09 16:37:23 -08001105
Charles Chanf2565a92016-02-10 20:46:58 -08001106 // Revoke previous IP table entry
1107 prevIps.forEach(ip -> {
1108 if (ip.isIp4()) {
1109 routingRulePopulator.revokeIpRuleForHost(
1110 prevDeviceId, ip.getIp4Address(), mac, prevPort);
1111 }
1112 });
1113 }
Charles Chan68aa62d2015-11-09 16:37:23 -08001114
Charles Chand9681e72016-02-22 19:27:29 -08001115 if (!deviceConfiguration.suppressHost()
Charles Chanf2565a92016-02-10 20:46:58 -08001116 .contains(new ConnectPoint(newDeviceId, newPort))) {
1117 // Populate new bridging table entry
1118 ForwardingObjective.Builder newFob =
1119 getForwardingObjectiveBuilder(newDeviceId, mac, vlanId, newPort);
1120 flowObjectiveService.forward(newDeviceId, newFob.add(
1121 new BridgingTableObjectiveContext(mac, vlanId)
1122 ));
Charles Chan68aa62d2015-11-09 16:37:23 -08001123
Charles Chanf2565a92016-02-10 20:46:58 -08001124 // Populate new IP table entry
1125 newIps.forEach(ip -> {
1126 if (ip.isIp4()) {
1127 routingRulePopulator.populateIpRuleForHost(
1128 newDeviceId, ip.getIp4Address(), mac, newPort);
1129 }
1130 });
1131 }
Charles Chan68aa62d2015-11-09 16:37:23 -08001132 }
1133
1134 private void processHostUpdatedEvent(HostEvent event) {
1135 MacAddress mac = event.subject().mac();
1136 VlanId vlanId = event.subject().vlan();
1137 DeviceId prevDeviceId = event.prevSubject().location().deviceId();
1138 PortNumber prevPort = event.prevSubject().location().port();
1139 Set<IpAddress> prevIps = event.prevSubject().ipAddresses();
1140 DeviceId newDeviceId = event.subject().location().deviceId();
1141 PortNumber newPort = event.subject().location().port();
1142 Set<IpAddress> newIps = event.subject().ipAddresses();
1143 log.debug("Host {}/{} is updated", mac, vlanId);
1144
Charles Chand9681e72016-02-22 19:27:29 -08001145 if (!deviceConfiguration.suppressHost()
Charles Chanf2565a92016-02-10 20:46:58 -08001146 .contains(new ConnectPoint(prevDeviceId, prevPort))) {
1147 // Revoke previous IP table entry
1148 prevIps.forEach(ip -> {
1149 if (ip.isIp4()) {
1150 routingRulePopulator.revokeIpRuleForHost(
1151 prevDeviceId, ip.getIp4Address(), mac, prevPort);
1152 }
1153 });
1154 }
Charles Chan68aa62d2015-11-09 16:37:23 -08001155
Charles Chand9681e72016-02-22 19:27:29 -08001156 if (!deviceConfiguration.suppressHost()
Charles Chanf2565a92016-02-10 20:46:58 -08001157 .contains(new ConnectPoint(newDeviceId, newPort))) {
1158 // Populate new IP table entry
1159 newIps.forEach(ip -> {
1160 if (ip.isIp4()) {
1161 routingRulePopulator.populateIpRuleForHost(
1162 newDeviceId, ip.getIp4Address(), mac, newPort);
1163 }
1164 });
1165 }
Charles Chan68aa62d2015-11-09 16:37:23 -08001166 }
1167
1168 @Override
1169 public void event(HostEvent event) {
1170 // Do not proceed without mastership
1171 DeviceId deviceId = event.subject().location().deviceId();
1172 if (!mastershipService.isLocalMaster(deviceId)) {
1173 return;
1174 }
1175
1176 switch (event.type()) {
1177 case HOST_ADDED:
1178 processHostAddedEvent(event);
1179 break;
1180 case HOST_MOVED:
1181 processHostMovedEvent(event);
1182 break;
1183 case HOST_REMOVED:
1184 processHostRemoveEvent(event);
1185 break;
1186 case HOST_UPDATED:
1187 processHostUpdatedEvent(event);
1188 break;
1189 default:
1190 log.warn("Unsupported host event type: {}", event.type());
1191 break;
1192 }
1193 }
1194 }
1195
1196 private static class BridgingTableObjectiveContext implements ObjectiveContext {
1197 final MacAddress mac;
1198 final VlanId vlanId;
1199
1200 BridgingTableObjectiveContext(MacAddress mac, VlanId vlanId) {
1201 this.mac = mac;
1202 this.vlanId = vlanId;
1203 }
1204
1205 @Override
1206 public void onSuccess(Objective objective) {
1207 if (objective.op() == Objective.Operation.ADD) {
1208 log.debug("Successfully populate bridging table entry for {}/{}",
1209 mac, vlanId);
1210 } else {
1211 log.debug("Successfully revoke bridging table entry for {}/{}",
1212 mac, vlanId);
1213 }
1214 }
1215
1216 @Override
1217 public void onError(Objective objective, ObjectiveError error) {
1218 if (objective.op() == Objective.Operation.ADD) {
1219 log.debug("Fail to populate bridging table entry for {}/{}. {}",
1220 mac, vlanId, error);
1221 } else {
1222 log.debug("Fail to revoke bridging table entry for {}/{}. {}",
1223 mac, vlanId, error);
1224 }
1225 }
1226 }
sanghob35a6192015-04-01 13:05:26 -07001227}