blob: 9716b524ac55731373257a66865c4207f67c607c [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 Chanc42e84e2015-10-20 16:24:19 -070025import org.onlab.packet.IPv4;
Charles Chanc42e84e2015-10-20 16:24:19 -070026import org.onlab.packet.Ip4Prefix;
27import org.onlab.packet.IpAddress;
28import org.onlab.packet.IpPrefix;
Jonathan Hartc19f7c12016-04-12 15:39:44 -070029import org.onlab.packet.MacAddress;
30import org.onlab.packet.VlanId;
Srikanth Vavilapalli23181912015-05-04 09:48:09 -070031import org.onlab.util.KryoNamespace;
Saurav Das80980c72016-03-23 11:22:49 -070032import org.onosproject.cfg.ComponentConfigService;
sanghob35a6192015-04-01 13:05:26 -070033import org.onosproject.core.ApplicationId;
34import org.onosproject.core.CoreService;
35import org.onosproject.event.Event;
Jonathan Hartc19f7c12016-04-12 15:39:44 -070036import org.onosproject.mastership.MastershipService;
Charles Chanc42e84e2015-10-20 16:24:19 -070037import org.onosproject.net.ConnectPoint;
Jonathan Hartc19f7c12016-04-12 15:39:44 -070038import org.onosproject.net.Device;
39import org.onosproject.net.DeviceId;
40import org.onosproject.net.Link;
41import org.onosproject.net.Port;
Charles Chan68aa62d2015-11-09 16:37:23 -080042import org.onosproject.net.PortNumber;
Charles Chand6832882015-10-05 17:50:33 -070043import org.onosproject.net.config.ConfigFactory;
44import org.onosproject.net.config.NetworkConfigEvent;
Charles Chand6832882015-10-05 17:50:33 -070045import org.onosproject.net.config.NetworkConfigListener;
Jonathan Hartc19f7c12016-04-12 15:39:44 -070046import org.onosproject.net.config.NetworkConfigRegistry;
Charles Chand6832882015-10-05 17:50:33 -070047import org.onosproject.net.config.basics.SubjectFactories;
Jonathan Hartc19f7c12016-04-12 15:39:44 -070048import org.onosproject.net.device.DeviceEvent;
49import org.onosproject.net.device.DeviceListener;
50import org.onosproject.net.device.DeviceService;
Charles Chan68aa62d2015-11-09 16:37:23 -080051import org.onosproject.net.flow.DefaultTrafficSelector;
52import org.onosproject.net.flow.DefaultTrafficTreatment;
53import org.onosproject.net.flow.TrafficSelector;
54import org.onosproject.net.flow.TrafficTreatment;
55import org.onosproject.net.flowobjective.DefaultForwardingObjective;
Jonathan Hartc19f7c12016-04-12 15:39:44 -070056import org.onosproject.net.flowobjective.FlowObjectiveService;
Charles Chan68aa62d2015-11-09 16:37:23 -080057import org.onosproject.net.flowobjective.ForwardingObjective;
58import org.onosproject.net.flowobjective.Objective;
59import org.onosproject.net.flowobjective.ObjectiveContext;
60import org.onosproject.net.flowobjective.ObjectiveError;
61import org.onosproject.net.host.HostEvent;
62import org.onosproject.net.host.HostListener;
sanghob35a6192015-04-01 13:05:26 -070063import org.onosproject.net.host.HostService;
sanghob35a6192015-04-01 13:05:26 -070064import org.onosproject.net.link.LinkEvent;
65import org.onosproject.net.link.LinkListener;
66import org.onosproject.net.link.LinkService;
67import org.onosproject.net.packet.InboundPacket;
68import org.onosproject.net.packet.PacketContext;
Jonathan Hartc19f7c12016-04-12 15:39:44 -070069import org.onosproject.net.packet.PacketPriority;
sanghob35a6192015-04-01 13:05:26 -070070import org.onosproject.net.packet.PacketProcessor;
71import org.onosproject.net.packet.PacketService;
Jonathan Hartc19f7c12016-04-12 15:39:44 -070072import org.onosproject.segmentrouting.config.DeviceConfigNotFoundException;
73import org.onosproject.segmentrouting.config.DeviceConfiguration;
74import org.onosproject.segmentrouting.config.SegmentRoutingAppConfig;
75import org.onosproject.segmentrouting.config.SegmentRoutingDeviceConfig;
76import org.onosproject.segmentrouting.grouphandler.DefaultGroupHandler;
77import org.onosproject.segmentrouting.grouphandler.NeighborSet;
78import org.onosproject.segmentrouting.grouphandler.NeighborSetNextObjectiveStoreKey;
79import org.onosproject.segmentrouting.grouphandler.PortNextObjectiveStoreKey;
Charles Chanc42e84e2015-10-20 16:24:19 -070080import org.onosproject.segmentrouting.grouphandler.SubnetNextObjectiveStoreKey;
Charles Chane849c192016-01-11 18:28:54 -080081import org.onosproject.segmentrouting.grouphandler.XConnectNextObjectiveStoreKey;
Jonathan Hartc19f7c12016-04-12 15:39:44 -070082import org.onosproject.store.serializers.KryoNamespaces;
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
Saurav Das0e99e2b2015-10-28 12:39:42 -070090import java.util.Collections;
Srikanth Vavilapalli23181912015-05-04 09:48:09 -070091import java.util.HashSet;
sangho1e575652015-05-14 00:39:53 -070092import java.util.List;
sanghob35a6192015-04-01 13:05:26 -070093import java.util.Map;
Charles Chan188ebf52015-12-23 00:15:11 -080094import java.util.Optional;
Saurav Das0e99e2b2015-10-28 12:39:42 -070095import java.util.Set;
sanghob35a6192015-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
Charles Chan3e783d02016-02-26 22:19:52 -0800103import static com.google.common.base.Preconditions.checkState;
104
Jonathan Hartc19f7c12016-04-12 15:39:44 -0700105
Charles Chane849c192016-01-11 18:28:54 -0800106/**
107 * Segment routing manager.
108 */
Jonathan Hartc19f7c12016-04-12 15:39:44 -0700109@Service
110@Component(immediate = true)
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
Charles Chan116188d2016-02-18 14:22:42 -0800228 /**
229 * Segment Routing App ID.
230 */
231 public static final String SR_APP_ID = "org.onosproject.segmentrouting";
Charles Chane849c192016-01-11 18:28:54 -0800232 /**
233 * The starting value of per-subnet VLAN ID assignment.
234 */
Saurav Das0e99e2b2015-10-28 12:39:42 -0700235 private static final short ASSIGNED_VLAN_START = 4093;
Charles Chane849c192016-01-11 18:28:54 -0800236 /**
237 * The default VLAN ID assigned to the interfaces without subnet config.
238 */
Saurav Das0e99e2b2015-10-28 12:39:42 -0700239 public static final short ASSIGNED_VLAN_NO_SUBNET = 4094;
240
sanghob35a6192015-04-01 13:05:26 -0700241 @Activate
242 protected void activate() {
Jonathan Hartc19f7c12016-04-12 15:39:44 -0700243 appId = coreService.registerApplication(SR_APP_ID);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700244
245 log.debug("Creating EC map nsnextobjectivestore");
246 EventuallyConsistentMapBuilder<NeighborSetNextObjectiveStoreKey, Integer>
247 nsNextObjMapBuilder = storageService.eventuallyConsistentMapBuilder();
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700248 nsNextObjStore = nsNextObjMapBuilder
249 .withName("nsnextobjectivestore")
Jonathan Hartc19f7c12016-04-12 15:39:44 -0700250 .withSerializer(createSerializer())
Madan Jampanibcf1a482015-06-24 19:05:56 -0700251 .withTimestampProvider((k, v) -> new WallClockTimestamp())
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700252 .build();
253 log.trace("Current size {}", nsNextObjStore.size());
254
Charles Chanc42e84e2015-10-20 16:24:19 -0700255 log.debug("Creating EC map subnetnextobjectivestore");
256 EventuallyConsistentMapBuilder<SubnetNextObjectiveStoreKey, Integer>
257 subnetNextObjMapBuilder = storageService.eventuallyConsistentMapBuilder();
Charles Chanc42e84e2015-10-20 16:24:19 -0700258 subnetNextObjStore = subnetNextObjMapBuilder
259 .withName("subnetnextobjectivestore")
Jonathan Hartc19f7c12016-04-12 15:39:44 -0700260 .withSerializer(createSerializer())
Charles Chanc42e84e2015-10-20 16:24:19 -0700261 .withTimestampProvider((k, v) -> new WallClockTimestamp())
262 .build();
263
Saurav Das4ce45962015-11-24 23:21:05 -0800264 log.debug("Creating EC map subnetnextobjectivestore");
265 EventuallyConsistentMapBuilder<PortNextObjectiveStoreKey, Integer>
266 portNextObjMapBuilder = storageService.eventuallyConsistentMapBuilder();
267 portNextObjStore = portNextObjMapBuilder
268 .withName("portnextobjectivestore")
Jonathan Hartc19f7c12016-04-12 15:39:44 -0700269 .withSerializer(createSerializer())
Saurav Das4ce45962015-11-24 23:21:05 -0800270 .withTimestampProvider((k, v) -> new WallClockTimestamp())
271 .build();
272
Charles Chane849c192016-01-11 18:28:54 -0800273 log.debug("Creating EC map xconnectnextobjectivestore");
274 EventuallyConsistentMapBuilder<XConnectNextObjectiveStoreKey, Integer>
275 xConnectNextObjStoreBuilder = storageService.eventuallyConsistentMapBuilder();
276 xConnectNextObjStore = xConnectNextObjStoreBuilder
277 .withName("xconnectnextobjectivestore")
Jonathan Hartc19f7c12016-04-12 15:39:44 -0700278 .withSerializer(createSerializer())
Charles Chane849c192016-01-11 18:28:54 -0800279 .withTimestampProvider((k, v) -> new WallClockTimestamp())
280 .build();
281
sangho0b2b6d12015-05-20 22:16:38 -0700282 EventuallyConsistentMapBuilder<String, Tunnel> tunnelMapBuilder =
283 storageService.eventuallyConsistentMapBuilder();
sangho0b2b6d12015-05-20 22:16:38 -0700284 tunnelStore = tunnelMapBuilder
285 .withName("tunnelstore")
Jonathan Hartc19f7c12016-04-12 15:39:44 -0700286 .withSerializer(createSerializer())
Madan Jampanibcf1a482015-06-24 19:05:56 -0700287 .withTimestampProvider((k, v) -> new WallClockTimestamp())
sangho0b2b6d12015-05-20 22:16:38 -0700288 .build();
289
290 EventuallyConsistentMapBuilder<String, Policy> policyMapBuilder =
291 storageService.eventuallyConsistentMapBuilder();
sangho0b2b6d12015-05-20 22:16:38 -0700292 policyStore = policyMapBuilder
293 .withName("policystore")
Jonathan Hartc19f7c12016-04-12 15:39:44 -0700294 .withSerializer(createSerializer())
Madan Jampanibcf1a482015-06-24 19:05:56 -0700295 .withTimestampProvider((k, v) -> new WallClockTimestamp())
sangho0b2b6d12015-05-20 22:16:38 -0700296 .build();
297
Saurav Das0e99e2b2015-10-28 12:39:42 -0700298 EventuallyConsistentMapBuilder<SubnetAssignedVidStoreKey, VlanId>
299 subnetVidStoreMapBuilder = storageService.eventuallyConsistentMapBuilder();
Saurav Das0e99e2b2015-10-28 12:39:42 -0700300 subnetVidStore = subnetVidStoreMapBuilder
301 .withName("subnetvidstore")
Jonathan Hartc19f7c12016-04-12 15:39:44 -0700302 .withSerializer(createSerializer())
Saurav Das0e99e2b2015-10-28 12:39:42 -0700303 .withTimestampProvider((k, v) -> new WallClockTimestamp())
304 .build();
305
Saurav Das80980c72016-03-23 11:22:49 -0700306 compCfgService.preSetProperty("org.onosproject.net.group.impl.GroupManager",
307 "purgeOnDisconnection", "true");
308 compCfgService.preSetProperty("org.onosproject.net.flow.impl.FlowRuleManager",
309 "purgeOnDisconnection", "true");
310
Charles Chanb8e10c82015-10-14 11:24:40 -0700311 processor = new InternalPacketProcessor();
312 linkListener = new InternalLinkListener();
313 deviceListener = new InternalDeviceListener();
Charles Chan5270ed02016-01-30 23:22:37 -0800314 netcfgHandler = new NetworkConfigEventHandler(this);
Charles Chanb8e10c82015-10-14 11:24:40 -0700315
Charles Chan3e783d02016-02-26 22:19:52 -0800316 cfgService.addListener(cfgListener);
317 cfgService.registerConfigFactory(cfgDeviceFactory);
318 cfgService.registerConfigFactory(cfgAppFactory);
Charles Chan5270ed02016-01-30 23:22:37 -0800319 hostService.addListener(hostListener);
Charles Chanb8e10c82015-10-14 11:24:40 -0700320 packetService.addProcessor(processor, PacketProcessor.director(2));
321 linkService.addListener(linkListener);
322 deviceService.addListener(deviceListener);
323
Charles Chan188ebf52015-12-23 00:15:11 -0800324 // Request ARP packet-in
325 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
326 selector.matchEthType(Ethernet.TYPE_ARP);
327 packetService.requestPackets(selector.build(), PacketPriority.CONTROL, appId, Optional.empty());
328
Charles Chanb8e10c82015-10-14 11:24:40 -0700329 cfgListener.configureNetwork();
330
sanghob35a6192015-04-01 13:05:26 -0700331 log.info("Started");
332 }
333
Jonathan Hartc19f7c12016-04-12 15:39:44 -0700334 private KryoNamespace.Builder createSerializer() {
335 return new KryoNamespace.Builder()
336 .register(KryoNamespaces.API)
337 .register(NeighborSetNextObjectiveStoreKey.class,
338 SubnetNextObjectiveStoreKey.class,
339 SubnetAssignedVidStoreKey.class,
340 NeighborSet.class,
341 Tunnel.class,
342 DefaultTunnel.class,
343 Policy.class,
344 TunnelPolicy.class,
345 Policy.Type.class,
346 PortNextObjectiveStoreKey.class,
347 XConnectNextObjectiveStoreKey.class
348 );
349 }
350
sanghob35a6192015-04-01 13:05:26 -0700351 @Deactivate
352 protected void deactivate() {
Charles Chand6832882015-10-05 17:50:33 -0700353 cfgService.removeListener(cfgListener);
Charles Chan5270ed02016-01-30 23:22:37 -0800354 cfgService.unregisterConfigFactory(cfgDeviceFactory);
355 cfgService.unregisterConfigFactory(cfgAppFactory);
Charles Chand6832882015-10-05 17:50:33 -0700356
Charles Chan188ebf52015-12-23 00:15:11 -0800357 // Withdraw ARP packet-in
358 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
359 selector.matchEthType(Ethernet.TYPE_ARP);
360 packetService.cancelPackets(selector.build(), PacketPriority.CONTROL, appId, Optional.empty());
361
sanghob35a6192015-04-01 13:05:26 -0700362 packetService.removeProcessor(processor);
Charles Chanb8e10c82015-10-14 11:24:40 -0700363 linkService.removeListener(linkListener);
364 deviceService.removeListener(deviceListener);
sanghob35a6192015-04-01 13:05:26 -0700365 processor = null;
Charles Chanb8e10c82015-10-14 11:24:40 -0700366 linkListener = null;
367 deviceService = null;
368
369 groupHandlerMap.clear();
370
sanghob35a6192015-04-01 13:05:26 -0700371 log.info("Stopped");
372 }
373
sangho1e575652015-05-14 00:39:53 -0700374
375 @Override
376 public List<Tunnel> getTunnels() {
377 return tunnelHandler.getTunnels();
378 }
379
380 @Override
sangho71abe1b2015-06-29 14:58:47 -0700381 public TunnelHandler.Result createTunnel(Tunnel tunnel) {
382 return tunnelHandler.createTunnel(tunnel);
sangho1e575652015-05-14 00:39:53 -0700383 }
384
385 @Override
sangho71abe1b2015-06-29 14:58:47 -0700386 public TunnelHandler.Result removeTunnel(Tunnel tunnel) {
sangho1e575652015-05-14 00:39:53 -0700387 for (Policy policy: policyHandler.getPolicies()) {
388 if (policy.type() == Policy.Type.TUNNEL_FLOW) {
389 TunnelPolicy tunnelPolicy = (TunnelPolicy) policy;
390 if (tunnelPolicy.tunnelId().equals(tunnel.id())) {
391 log.warn("Cannot remove the tunnel used by a policy");
sangho71abe1b2015-06-29 14:58:47 -0700392 return TunnelHandler.Result.TUNNEL_IN_USE;
sangho1e575652015-05-14 00:39:53 -0700393 }
394 }
395 }
sangho71abe1b2015-06-29 14:58:47 -0700396 return tunnelHandler.removeTunnel(tunnel);
sangho1e575652015-05-14 00:39:53 -0700397 }
398
399 @Override
sangho71abe1b2015-06-29 14:58:47 -0700400 public PolicyHandler.Result removePolicy(Policy policy) {
401 return policyHandler.removePolicy(policy);
sangho1e575652015-05-14 00:39:53 -0700402 }
403
404 @Override
sangho71abe1b2015-06-29 14:58:47 -0700405 public PolicyHandler.Result createPolicy(Policy policy) {
406 return policyHandler.createPolicy(policy);
sangho1e575652015-05-14 00:39:53 -0700407 }
408
409 @Override
410 public List<Policy> getPolicies() {
411 return policyHandler.getPolicies();
412 }
413
sanghof9d0bf12015-05-19 11:57:42 -0700414 /**
415 * Returns the tunnel object with the tunnel ID.
416 *
417 * @param tunnelId Tunnel ID
418 * @return Tunnel reference
419 */
sangho1e575652015-05-14 00:39:53 -0700420 public Tunnel getTunnel(String tunnelId) {
421 return tunnelHandler.getTunnel(tunnelId);
422 }
423
sanghob35a6192015-04-01 13:05:26 -0700424 /**
Saurav Das0e99e2b2015-10-28 12:39:42 -0700425 * Returns the vlan-id assigned to the subnet configured for a device.
426 * If no vlan-id has been assigned, a new one is assigned out of a pool of ids,
427 * if and only if this controller instance is the master for the device.
428 * <p>
429 * USAGE: The assigned vlans are meant to be applied to untagged packets on those
430 * switches/pipelines that need this functionality. These vids are meant
431 * to be used internally within a switch, and thus need to be unique only
432 * on a switch level. Note that packets never go out on the wire with these
433 * vlans. Currently, vlan ids are assigned from value 4093 down.
434 * Vlan id 4094 expected to be used for all ports that are not assigned subnets.
435 * Vlan id 4095 is reserved and unused. Only a single vlan id is assigned
436 * per subnet.
sanghob35a6192015-04-01 13:05:26 -0700437 *
Saurav Das0e99e2b2015-10-28 12:39:42 -0700438 * @param deviceId switch dpid
439 * @param subnet IPv4 prefix for which assigned vlan is desired
440 * @return VlanId assigned for the subnet on the device, or
441 * null if no vlan assignment was found and this instance is not
442 * the master for the device.
sanghob35a6192015-04-01 13:05:26 -0700443 */
Charles Chane849c192016-01-11 18:28:54 -0800444 // TODO: We should avoid assigning VLAN IDs that are used by VLAN cross-connection.
Saurav Das0e99e2b2015-10-28 12:39:42 -0700445 public VlanId getSubnetAssignedVlanId(DeviceId deviceId, Ip4Prefix subnet) {
446 VlanId assignedVid = subnetVidStore.get(new SubnetAssignedVidStoreKey(
447 deviceId, subnet));
448 if (assignedVid != null) {
449 log.debug("Query for subnet:{} on device:{} returned assigned-vlan "
450 + "{}", subnet, deviceId, assignedVid);
451 return assignedVid;
452 }
453 //check mastership for the right to assign a vlan
454 if (!mastershipService.isLocalMaster(deviceId)) {
455 log.warn("This controller instance is not the master for device {}. "
456 + "Cannot assign vlan-id for subnet {}", deviceId, subnet);
457 return null;
458 }
459 // vlan assignment is expensive but done only once
Charles Chan9f676b62015-10-29 14:58:10 -0700460 Set<Ip4Prefix> configuredSubnets = deviceConfiguration.getSubnets(deviceId);
Saurav Das0e99e2b2015-10-28 12:39:42 -0700461 Set<Short> assignedVlans = new HashSet<>();
462 Set<Ip4Prefix> unassignedSubnets = new HashSet<>();
463 for (Ip4Prefix sub : configuredSubnets) {
464 VlanId v = subnetVidStore.get(new SubnetAssignedVidStoreKey(deviceId,
465 sub));
466 if (v != null) {
467 assignedVlans.add(v.toShort());
468 } else {
469 unassignedSubnets.add(sub);
470 }
471 }
472 short nextAssignedVlan = ASSIGNED_VLAN_START;
473 if (!assignedVlans.isEmpty()) {
474 nextAssignedVlan = (short) (Collections.min(assignedVlans) - 1);
475 }
476 for (Ip4Prefix unsub : unassignedSubnets) {
Charles Chan5270ed02016-01-30 23:22:37 -0800477 // Special case for default route. Assign default VLAN ID to /32 and /0 subnets
478 if (unsub.prefixLength() == IpPrefix.MAX_INET_MASK_LENGTH ||
479 unsub.prefixLength() == 0) {
480 subnetVidStore.put(new SubnetAssignedVidStoreKey(deviceId, unsub),
481 VlanId.vlanId(ASSIGNED_VLAN_NO_SUBNET));
482 } else {
483 subnetVidStore.put(new SubnetAssignedVidStoreKey(deviceId, unsub),
484 VlanId.vlanId(nextAssignedVlan--));
485 log.info("Assigned vlan: {} to subnet: {} on device: {}",
486 nextAssignedVlan + 1, unsub, deviceId);
487 }
sanghob35a6192015-04-01 13:05:26 -0700488 }
489
Saurav Das0e99e2b2015-10-28 12:39:42 -0700490 return subnetVidStore.get(new SubnetAssignedVidStoreKey(deviceId, subnet));
sanghob35a6192015-04-01 13:05:26 -0700491 }
492
sangho1e575652015-05-14 00:39:53 -0700493 /**
Saurav Das0e99e2b2015-10-28 12:39:42 -0700494 * Returns the next objective ID for the given NeighborSet.
Saurav Das8a0732e2015-11-20 15:27:53 -0800495 * If the nextObjective does not exist, a new one is created and
Saurav Das4ce45962015-11-24 23:21:05 -0800496 * its id is returned.
sangho1e575652015-05-14 00:39:53 -0700497 *
sanghof9d0bf12015-05-19 11:57:42 -0700498 * @param deviceId Device ID
499 * @param ns NegighborSet
Saurav Das8a0732e2015-11-20 15:27:53 -0800500 * @param meta metadata passed into the creation of a Next Objective
501 * @return next objective ID or -1 if an error was encountered during the
502 * creation of the nextObjective
sangho1e575652015-05-14 00:39:53 -0700503 */
Saurav Das8a0732e2015-11-20 15:27:53 -0800504 public int getNextObjectiveId(DeviceId deviceId, NeighborSet ns,
505 TrafficSelector meta) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700506 if (groupHandlerMap.get(deviceId) != null) {
507 log.trace("getNextObjectiveId query in device {}", deviceId);
508 return groupHandlerMap
Saurav Das8a0732e2015-11-20 15:27:53 -0800509 .get(deviceId).getNextObjectiveId(ns, meta);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700510 } else {
Saurav Das4ce45962015-11-24 23:21:05 -0800511 log.warn("getNextObjectiveId query - groupHandler for device {} "
512 + "not found", deviceId);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700513 return -1;
514 }
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700515 }
516
Charles Chanc42e84e2015-10-20 16:24:19 -0700517 /**
Saurav Das4ce45962015-11-24 23:21:05 -0800518 * Returns the next objective ID for the given subnet prefix. It is expected
519 * that the next-objective has been pre-created from configuration.
Charles Chanc42e84e2015-10-20 16:24:19 -0700520 *
521 * @param deviceId Device ID
522 * @param prefix Subnet
Saurav Das4ce45962015-11-24 23:21:05 -0800523 * @return next objective ID or -1 if it was not found
Charles Chanc42e84e2015-10-20 16:24:19 -0700524 */
525 public int getSubnetNextObjectiveId(DeviceId deviceId, IpPrefix prefix) {
526 if (groupHandlerMap.get(deviceId) != null) {
527 log.trace("getSubnetNextObjectiveId query in device {}", deviceId);
528 return groupHandlerMap
529 .get(deviceId).getSubnetNextObjectiveId(prefix);
530 } else {
Saurav Das4ce45962015-11-24 23:21:05 -0800531 log.warn("getSubnetNextObjectiveId query - groupHandler for "
532 + "device {} not found", deviceId);
533 return -1;
534 }
535 }
536
537 /**
538 * Returns the next objective ID for the given portNumber, given the treatment.
539 * There could be multiple different treatments to the same outport, which
540 * would result in different objectives. If the next object
541 * does not exist, a new one is created and its id is returned.
542 *
543 * @param deviceId Device ID
544 * @param portNum port number on device for which NextObjective is queried
545 * @param treatment the actions to apply on the packets (should include outport)
546 * @param meta metadata passed into the creation of a Next Objective if necessary
547 * @return next objective ID or -1 if it was not found
548 */
549 public int getPortNextObjectiveId(DeviceId deviceId, PortNumber portNum,
550 TrafficTreatment treatment,
551 TrafficSelector meta) {
552 DefaultGroupHandler ghdlr = groupHandlerMap.get(deviceId);
553 if (ghdlr != null) {
554 return ghdlr.getPortNextObjectiveId(portNum, treatment, meta);
555 } else {
Charles Chane849c192016-01-11 18:28:54 -0800556 log.warn("getPortNextObjectiveId query - groupHandler for device {}"
557 + " not found", deviceId);
558 return -1;
559 }
560 }
561
562 /**
563 * Returns the next objective ID of type broadcast associated with the VLAN
564 * cross-connection.
565 *
566 * @param deviceId Device ID for the cross-connection
567 * @param vlanId VLAN ID for the cross-connection
568 * @return next objective ID or -1 if it was not found
569 */
570 public int getXConnectNextObjectiveId(DeviceId deviceId, VlanId vlanId) {
571 DefaultGroupHandler ghdlr = groupHandlerMap.get(deviceId);
572 if (ghdlr != null) {
573 return ghdlr.getXConnectNextObjectiveId(vlanId);
574 } else {
575 log.warn("getPortNextObjectiveId query - groupHandler for device {}"
Saurav Das4ce45962015-11-24 23:21:05 -0800576 + " not found", deviceId);
Charles Chanc42e84e2015-10-20 16:24:19 -0700577 return -1;
578 }
579 }
580
sanghob35a6192015-04-01 13:05:26 -0700581 private class InternalPacketProcessor implements PacketProcessor {
sanghob35a6192015-04-01 13:05:26 -0700582 @Override
583 public void process(PacketContext context) {
584
585 if (context.isHandled()) {
586 return;
587 }
588
589 InboundPacket pkt = context.inPacket();
590 Ethernet ethernet = pkt.parsed();
Saurav Das4ce45962015-11-24 23:21:05 -0800591 log.trace("Rcvd pktin: {}", ethernet);
sanghob35a6192015-04-01 13:05:26 -0700592 if (ethernet.getEtherType() == Ethernet.TYPE_ARP) {
593 arpHandler.processPacketIn(pkt);
594 } else if (ethernet.getEtherType() == Ethernet.TYPE_IPV4) {
595 IPv4 ipPacket = (IPv4) ethernet.getPayload();
596 ipHandler.addToPacketBuffer(ipPacket);
597 if (ipPacket.getProtocol() == IPv4.PROTOCOL_ICMP) {
598 icmpHandler.processPacketIn(pkt);
599 } else {
600 ipHandler.processPacketIn(pkt);
601 }
602 }
603 }
604 }
605
606 private class InternalLinkListener implements LinkListener {
607 @Override
608 public void event(LinkEvent event) {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700609 if (event.type() == LinkEvent.Type.LINK_ADDED
610 || event.type() == LinkEvent.Type.LINK_REMOVED) {
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700611 log.debug("Event {} received from Link Service", event.type());
sanghob35a6192015-04-01 13:05:26 -0700612 scheduleEventHandlerIfNotScheduled(event);
613 }
614 }
615 }
616
617 private class InternalDeviceListener implements DeviceListener {
sanghob35a6192015-04-01 13:05:26 -0700618 @Override
619 public void event(DeviceEvent event) {
sanghob35a6192015-04-01 13:05:26 -0700620 switch (event.type()) {
621 case DEVICE_ADDED:
622 case PORT_REMOVED:
sangho20eff1d2015-04-13 15:15:58 -0700623 case DEVICE_UPDATED:
624 case DEVICE_AVAILABILITY_CHANGED:
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700625 log.debug("Event {} received from Device Service", event.type());
sanghob35a6192015-04-01 13:05:26 -0700626 scheduleEventHandlerIfNotScheduled(event);
627 break;
628 default:
629 }
630 }
631 }
632
Saurav Das4ce45962015-11-24 23:21:05 -0800633 @SuppressWarnings("rawtypes")
sanghob35a6192015-04-01 13:05:26 -0700634 private void scheduleEventHandlerIfNotScheduled(Event event) {
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700635 synchronized (threadSchedulerLock) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700636 eventQueue.add(event);
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700637 numOfEventsQueued++;
638
639 if ((numOfHandlerScheduled - numOfHandlerExecution) == 0) {
640 //No pending scheduled event handling threads. So start a new one.
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700641 eventHandlerFuture = executorService
642 .schedule(eventHandler, 100, TimeUnit.MILLISECONDS);
643 numOfHandlerScheduled++;
644 }
Jonathan Hartc19f7c12016-04-12 15:39:44 -0700645 log.trace("numOfEventsQueued {}, numOfEventHandlerScheduled {}",
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700646 numOfEventsQueued,
647 numOfHandlerScheduled);
sanghob35a6192015-04-01 13:05:26 -0700648 }
sanghob35a6192015-04-01 13:05:26 -0700649 }
650
651 private class InternalEventHandler implements Runnable {
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700652 @Override
sanghob35a6192015-04-01 13:05:26 -0700653 public void run() {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700654 try {
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700655 while (true) {
Saurav Das4ce45962015-11-24 23:21:05 -0800656 @SuppressWarnings("rawtypes")
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700657 Event event = null;
658 synchronized (threadSchedulerLock) {
659 if (!eventQueue.isEmpty()) {
660 event = eventQueue.poll();
661 numOfEventsExecuted++;
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700662 } else {
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700663 numOfHandlerExecution++;
664 log.debug("numOfHandlerExecution {} numOfEventsExecuted {}",
665 numOfHandlerExecution, numOfEventsExecuted);
666 break;
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700667 }
sangho20eff1d2015-04-13 15:15:58 -0700668 }
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700669 if (event.type() == LinkEvent.Type.LINK_ADDED) {
670 processLinkAdded((Link) event.subject());
671 } else if (event.type() == LinkEvent.Type.LINK_REMOVED) {
672 processLinkRemoved((Link) event.subject());
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700673 } else if (event.type() == DeviceEvent.Type.DEVICE_ADDED ||
674 event.type() == DeviceEvent.Type.DEVICE_AVAILABILITY_CHANGED ||
675 event.type() == DeviceEvent.Type.DEVICE_UPDATED) {
Saurav Das423fe2b2015-12-04 10:52:59 -0800676 DeviceId deviceId = ((Device) event.subject()).id();
677 if (deviceService.isAvailable(deviceId)) {
Saurav Das837e0bb2015-10-30 17:45:38 -0700678 log.info("Processing device event {} for available device {}",
679 event.type(), ((Device) event.subject()).id());
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700680 processDeviceAdded((Device) event.subject());
Saurav Das80980c72016-03-23 11:22:49 -0700681 } else {
682 log.info("Processing device event {} for unavailable device {}",
683 event.type(), ((Device) event.subject()).id());
684 processDeviceRemoved((Device) event.subject());
685 }
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700686 } else if (event.type() == DeviceEvent.Type.PORT_REMOVED) {
687 processPortRemoved((Device) event.subject(),
688 ((DeviceEvent) event).port());
689 } else {
690 log.warn("Unhandled event type: {}", event.type());
691 }
sanghob35a6192015-04-01 13:05:26 -0700692 }
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700693 } catch (Exception e) {
694 log.error("SegmentRouting event handler "
695 + "thread thrown an exception: {}", e);
sanghob35a6192015-04-01 13:05:26 -0700696 }
sanghob35a6192015-04-01 13:05:26 -0700697 }
698 }
699
sanghob35a6192015-04-01 13:05:26 -0700700 private void processLinkAdded(Link link) {
701 log.debug("A new link {} was added", link.toString());
Charles Chan0b4e6182015-11-03 10:42:14 -0800702 if (!deviceConfiguration.isConfigured(link.src().deviceId())) {
703 log.warn("Source device of this link is not configured.");
704 return;
705 }
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700706 //Irrespective whether the local is a MASTER or not for this device,
707 //create group handler instance and push default TTP flow rules.
708 //Because in a multi-instance setup, instances can initiate
709 //groups for any devices. Also the default TTP rules are needed
710 //to be pushed before inserting any IP table entries for any device
711 DefaultGroupHandler groupHandler = groupHandlerMap.get(link.src()
712 .deviceId());
713 if (groupHandler != null) {
Saurav Das8a0732e2015-11-20 15:27:53 -0800714 groupHandler.linkUp(link, mastershipService.isLocalMaster(
715 link.src().deviceId()));
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700716 } else {
717 Device device = deviceService.getDevice(link.src().deviceId());
718 if (device != null) {
719 log.warn("processLinkAdded: Link Added "
720 + "Notification without Device Added "
721 + "event, still handling it");
722 processDeviceAdded(device);
723 groupHandler = groupHandlerMap.get(link.src()
724 .deviceId());
Saurav Das8a0732e2015-11-20 15:27:53 -0800725 groupHandler.linkUp(link, mastershipService.isLocalMaster(device.id()));
sanghob35a6192015-04-01 13:05:26 -0700726 }
727 }
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700728
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700729 log.trace("Starting optimized route population process");
730 defaultRoutingHandler.populateRoutingRulesForLinkStatusChange(null);
731 //log.trace("processLinkAdded: re-starting route population process");
732 //defaultRoutingHandler.startPopulationProcess();
sanghob35a6192015-04-01 13:05:26 -0700733 }
734
735 private void processLinkRemoved(Link link) {
736 log.debug("A link {} was removed", link.toString());
sangho834e4b02015-05-01 09:38:25 -0700737 DefaultGroupHandler groupHandler = groupHandlerMap.get(link.src().deviceId());
738 if (groupHandler != null) {
Saurav Das423fe2b2015-12-04 10:52:59 -0800739 groupHandler.portDown(link.src().port(),
740 mastershipService.isLocalMaster(link.src().deviceId()));
sangho834e4b02015-05-01 09:38:25 -0700741 }
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700742 log.trace("Starting optimized route population process");
743 defaultRoutingHandler.populateRoutingRulesForLinkStatusChange(link);
744 //log.trace("processLinkRemoved: re-starting route population process");
745 //defaultRoutingHandler.startPopulationProcess();
sanghob35a6192015-04-01 13:05:26 -0700746 }
747
748 private void processDeviceAdded(Device device) {
749 log.debug("A new device with ID {} was added", device.id());
Charles Chan0b4e6182015-11-03 10:42:14 -0800750 if (deviceConfiguration == null || !deviceConfiguration.isConfigured(device.id())) {
Saurav Das2857f382015-11-03 14:39:27 -0800751 log.warn("Device configuration uploading. Device {} will be "
752 + "processed after config completes.", device.id());
753 return;
754 }
Saurav Das837e0bb2015-10-30 17:45:38 -0700755 // Irrespective of whether the local is a MASTER or not for this device,
756 // we need to create a SR-group-handler instance. This is because in a
757 // multi-instance setup, any instance can initiate forwarding/next-objectives
758 // for any switch (even if this instance is a SLAVE or not even connected
759 // to the switch). To handle this, a default-group-handler instance is necessary
760 // per switch.
Saurav Das2857f382015-11-03 14:39:27 -0800761 if (groupHandlerMap.get(device.id()) == null) {
Charles Chan0b4e6182015-11-03 10:42:14 -0800762 DefaultGroupHandler groupHandler;
763 try {
764 groupHandler = DefaultGroupHandler.
765 createGroupHandler(device.id(),
766 appId,
767 deviceConfiguration,
768 linkService,
769 flowObjectiveService,
Charles Chan188ebf52015-12-23 00:15:11 -0800770 this);
Charles Chan0b4e6182015-11-03 10:42:14 -0800771 } catch (DeviceConfigNotFoundException e) {
772 log.warn(e.getMessage() + " Aborting processDeviceAdded.");
773 return;
774 }
Saurav Das2857f382015-11-03 14:39:27 -0800775 groupHandlerMap.put(device.id(), groupHandler);
776 // Also, in some cases, drivers may need extra
777 // information to process rules (eg. Router IP/MAC); and so, we send
778 // port addressing rules to the driver as well irrespective of whether
779 // this instance is the master or not.
780 defaultRoutingHandler.populatePortAddressingRules(device.id());
Charles Chand6d581a2015-11-18 16:51:08 -0800781 hostListener.readInitialHosts();
Saurav Das2857f382015-11-03 14:39:27 -0800782 }
Charles Chanc42e84e2015-10-20 16:24:19 -0700783 if (mastershipService.isLocalMaster(device.id())) {
Saurav Das2857f382015-11-03 14:39:27 -0800784 DefaultGroupHandler groupHandler = groupHandlerMap.get(device.id());
Charles Chanc42e84e2015-10-20 16:24:19 -0700785 groupHandler.createGroupsFromSubnetConfig();
Charles Chan68aa62d2015-11-09 16:37:23 -0800786 routingRulePopulator.populateSubnetBroadcastRule(device.id());
Charles Chane849c192016-01-11 18:28:54 -0800787 groupHandler.createGroupsForXConnect(device.id());
788 routingRulePopulator.populateXConnectBroadcastRule(device.id());
Charles Chanc42e84e2015-10-20 16:24:19 -0700789 }
Charles Chan5270ed02016-01-30 23:22:37 -0800790
791 netcfgHandler.initVRouters(device.id());
sanghob35a6192015-04-01 13:05:26 -0700792 }
793
Saurav Das80980c72016-03-23 11:22:49 -0700794 private void processDeviceRemoved(Device device) {
795 nsNextObjStore.entrySet().stream()
796 .filter(entry -> entry.getKey().deviceId().equals(device.id()))
797 .forEach(entry -> {
798 nsNextObjStore.remove(entry.getKey());
799 });
800
801 subnetNextObjStore.entrySet().stream()
802 .filter(entry -> entry.getKey().deviceId().equals(device.id()))
803 .forEach(entry -> {
804 subnetNextObjStore.remove(entry.getKey());
805 });
806
807 portNextObjStore.entrySet().stream()
808 .filter(entry -> entry.getKey().deviceId().equals(device.id()))
809 .forEach(entry -> {
810 portNextObjStore.remove(entry.getKey());
811 });
812
813 xConnectNextObjStore.entrySet().stream()
814 .filter(entry -> entry.getKey().deviceId().equals(device.id()))
815 .forEach(entry -> {
816 xConnectNextObjStore.remove(entry.getKey());
817 });
818
819 subnetVidStore.entrySet().stream()
820 .filter(entry -> entry.getKey().deviceId().equals(device.id()))
821 .forEach(entry -> {
822 subnetVidStore.remove(entry.getKey());
823 });
824
825 groupHandlerMap.remove(device.id());
826
827 defaultRoutingHandler.purgeEcmpGraph(device.id());
828 }
829
sanghob35a6192015-04-01 13:05:26 -0700830 private void processPortRemoved(Device device, Port port) {
831 log.debug("Port {} was removed", port.toString());
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700832 DefaultGroupHandler groupHandler = groupHandlerMap.get(device.id());
sanghob35a6192015-04-01 13:05:26 -0700833 if (groupHandler != null) {
Saurav Das423fe2b2015-12-04 10:52:59 -0800834 groupHandler.portDown(port.number(),
835 mastershipService.isLocalMaster(device.id()));
sanghob35a6192015-04-01 13:05:26 -0700836 }
837 }
sangho1e575652015-05-14 00:39:53 -0700838
Charles Chand6832882015-10-05 17:50:33 -0700839 private class InternalConfigListener implements NetworkConfigListener {
Charles Chan4636be02015-10-07 14:21:45 -0700840 SegmentRoutingManager segmentRoutingManager;
841
Charles Chane849c192016-01-11 18:28:54 -0800842 /**
843 * Constructs the internal network config listener.
844 *
845 * @param srMgr segment routing manager
846 */
Charles Chan4636be02015-10-07 14:21:45 -0700847 public InternalConfigListener(SegmentRoutingManager srMgr) {
848 this.segmentRoutingManager = srMgr;
849 }
850
Charles Chane849c192016-01-11 18:28:54 -0800851 /**
852 * Reads network config and initializes related data structure accordingly.
853 */
Charles Chan4636be02015-10-07 14:21:45 -0700854 public void configureNetwork() {
Charles Chanf2565a92016-02-10 20:46:58 -0800855 deviceConfiguration = new DeviceConfiguration(appId,
856 segmentRoutingManager.cfgService);
Charles Chan4636be02015-10-07 14:21:45 -0700857
858 arpHandler = new ArpHandler(segmentRoutingManager);
859 icmpHandler = new IcmpHandler(segmentRoutingManager);
860 ipHandler = new IpHandler(segmentRoutingManager);
861 routingRulePopulator = new RoutingRulePopulator(segmentRoutingManager);
862 defaultRoutingHandler = new DefaultRoutingHandler(segmentRoutingManager);
863
864 tunnelHandler = new TunnelHandler(linkService, deviceConfiguration,
865 groupHandlerMap, tunnelStore);
866 policyHandler = new PolicyHandler(appId, deviceConfiguration,
867 flowObjectiveService,
868 tunnelHandler, policyStore);
869
Charles Chan4636be02015-10-07 14:21:45 -0700870 for (Device device : deviceService.getDevices()) {
Saurav Das837e0bb2015-10-30 17:45:38 -0700871 // Irrespective of whether the local is a MASTER or not for this device,
872 // we need to create a SR-group-handler instance. This is because in a
873 // multi-instance setup, any instance can initiate forwarding/next-objectives
874 // for any switch (even if this instance is a SLAVE or not even connected
875 // to the switch). To handle this, a default-group-handler instance is necessary
876 // per switch.
Saurav Das2857f382015-11-03 14:39:27 -0800877 if (groupHandlerMap.get(device.id()) == null) {
Charles Chan0b4e6182015-11-03 10:42:14 -0800878 DefaultGroupHandler groupHandler;
879 try {
880 groupHandler = DefaultGroupHandler.
881 createGroupHandler(device.id(),
882 appId,
883 deviceConfiguration,
884 linkService,
885 flowObjectiveService,
Charles Chan188ebf52015-12-23 00:15:11 -0800886 segmentRoutingManager);
Charles Chan0b4e6182015-11-03 10:42:14 -0800887 } catch (DeviceConfigNotFoundException e) {
888 log.warn(e.getMessage() + " Aborting configureNetwork.");
889 return;
890 }
Saurav Das2857f382015-11-03 14:39:27 -0800891 groupHandlerMap.put(device.id(), groupHandler);
Saurav Das837e0bb2015-10-30 17:45:38 -0700892
Saurav Das2857f382015-11-03 14:39:27 -0800893 // Also, in some cases, drivers may need extra
894 // information to process rules (eg. Router IP/MAC); and so, we send
895 // port addressing rules to the driver as well, irrespective of whether
896 // this instance is the master or not.
897 defaultRoutingHandler.populatePortAddressingRules(device.id());
Charles Chand6d581a2015-11-18 16:51:08 -0800898 hostListener.readInitialHosts();
Saurav Das2857f382015-11-03 14:39:27 -0800899 }
Charles Chanc42e84e2015-10-20 16:24:19 -0700900 if (mastershipService.isLocalMaster(device.id())) {
Saurav Das2857f382015-11-03 14:39:27 -0800901 DefaultGroupHandler groupHandler = groupHandlerMap.get(device.id());
Charles Chanc42e84e2015-10-20 16:24:19 -0700902 groupHandler.createGroupsFromSubnetConfig();
Charles Chan68aa62d2015-11-09 16:37:23 -0800903 routingRulePopulator.populateSubnetBroadcastRule(device.id());
Charles Chane849c192016-01-11 18:28:54 -0800904 groupHandler.createGroupsForXConnect(device.id());
905 routingRulePopulator.populateXConnectBroadcastRule(device.id());
Charles Chanc42e84e2015-10-20 16:24:19 -0700906 }
Charles Chan4636be02015-10-07 14:21:45 -0700907 }
908
909 defaultRoutingHandler.startPopulationProcess();
910 }
911
Charles Chand6832882015-10-05 17:50:33 -0700912 @Override
913 public void event(NetworkConfigEvent event) {
Charles Chan5270ed02016-01-30 23:22:37 -0800914 // TODO move this part to NetworkConfigEventHandler
915 if (event.configClass().equals(SegmentRoutingDeviceConfig.class)) {
916 switch (event.type()) {
917 case CONFIG_ADDED:
918 log.info("Segment Routing Config added.");
919 configureNetwork();
920 break;
921 case CONFIG_UPDATED:
922 log.info("Segment Routing Config updated.");
923 // TODO support dynamic configuration
924 break;
925 default:
926 break;
Charles Chanb8e10c82015-10-14 11:24:40 -0700927 }
Charles Chan5270ed02016-01-30 23:22:37 -0800928 } else if (event.configClass().equals(SegmentRoutingAppConfig.class)) {
Charles Chan3e783d02016-02-26 22:19:52 -0800929 checkState(netcfgHandler != null, "NetworkConfigEventHandler is not initialized");
Charles Chan5270ed02016-01-30 23:22:37 -0800930 switch (event.type()) {
931 case CONFIG_ADDED:
932 netcfgHandler.processVRouterConfigAdded(event);
933 break;
934 case CONFIG_UPDATED:
935 netcfgHandler.processVRouterConfigUpdated(event);
936 break;
937 case CONFIG_REMOVED:
938 netcfgHandler.processVRouterConfigRemoved(event);
939 break;
940 default:
941 break;
Charles Chanb8e10c82015-10-14 11:24:40 -0700942 }
Charles Chand6832882015-10-05 17:50:33 -0700943 }
944 }
945 }
Charles Chan68aa62d2015-11-09 16:37:23 -0800946
Charles Chand6d581a2015-11-18 16:51:08 -0800947 // TODO Move bridging table population to a separate class
Charles Chan68aa62d2015-11-09 16:37:23 -0800948 private class InternalHostListener implements HostListener {
Charles Chand6d581a2015-11-18 16:51:08 -0800949 private void readInitialHosts() {
950 hostService.getHosts().forEach(host -> {
951 MacAddress mac = host.mac();
952 VlanId vlanId = host.vlan();
953 DeviceId deviceId = host.location().deviceId();
954 PortNumber port = host.location().port();
955 Set<IpAddress> ips = host.ipAddresses();
956 log.debug("Host {}/{} is added at {}:{}", mac, vlanId, deviceId, port);
957
958 // Populate bridging table entry
959 ForwardingObjective.Builder fob =
Saurav Das4ce45962015-11-24 23:21:05 -0800960 getForwardingObjectiveBuilder(deviceId, mac, vlanId, port);
Charles Chand6d581a2015-11-18 16:51:08 -0800961 flowObjectiveService.forward(deviceId, fob.add(
962 new BridgingTableObjectiveContext(mac, vlanId)
963 ));
964
965 // Populate IP table entry
966 ips.forEach(ip -> {
967 if (ip.isIp4()) {
968 routingRulePopulator.populateIpRuleForHost(
969 deviceId, ip.getIp4Address(), mac, port);
970 }
971 });
972 });
973 }
974
Charles Chan68aa62d2015-11-09 16:37:23 -0800975 private ForwardingObjective.Builder getForwardingObjectiveBuilder(
Saurav Das4ce45962015-11-24 23:21:05 -0800976 DeviceId deviceId, MacAddress mac, VlanId vlanId,
977 PortNumber outport) {
Charles Chan188ebf52015-12-23 00:15:11 -0800978 // Get assigned VLAN for the subnet
Saurav Das4ce45962015-11-24 23:21:05 -0800979 VlanId outvlan = null;
980 Ip4Prefix subnet = deviceConfiguration.getPortSubnet(deviceId, outport);
981 if (subnet == null) {
982 outvlan = VlanId.vlanId(ASSIGNED_VLAN_NO_SUBNET);
983 } else {
984 outvlan = getSubnetAssignedVlanId(deviceId, subnet);
985 }
Charles Chan188ebf52015-12-23 00:15:11 -0800986
987 // match rule
988 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
989 sbuilder.matchEthDst(mac);
990 /*
991 * Note: for untagged packets, match on the assigned VLAN.
992 * for tagged packets, match on its incoming VLAN.
993 */
994 if (vlanId.equals(VlanId.NONE)) {
995 sbuilder.matchVlanId(outvlan);
996 } else {
997 sbuilder.matchVlanId(vlanId);
998 }
999
1000 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
1001 tbuilder.immediate().popVlan();
1002 tbuilder.immediate().setOutput(outport);
1003
1004 // for switch pipelines that need it, provide outgoing vlan as metadata
Saurav Das4ce45962015-11-24 23:21:05 -08001005 TrafficSelector meta = DefaultTrafficSelector.builder()
1006 .matchVlanId(outvlan).build();
1007
1008 // All forwarding is via Groups. Drivers can re-purpose to flow-actions if needed.
1009 int portNextObjId = getPortNextObjectiveId(deviceId, outport,
1010 tbuilder.build(),
1011 meta);
Charles Chan68aa62d2015-11-09 16:37:23 -08001012
1013 return DefaultForwardingObjective.builder()
1014 .withFlag(ForwardingObjective.Flag.SPECIFIC)
1015 .withSelector(sbuilder.build())
Saurav Das4ce45962015-11-24 23:21:05 -08001016 .nextStep(portNextObjId)
Charles Chan68aa62d2015-11-09 16:37:23 -08001017 .withPriority(100)
1018 .fromApp(appId)
1019 .makePermanent();
1020 }
1021
1022 private void processHostAddedEvent(HostEvent event) {
1023 MacAddress mac = event.subject().mac();
1024 VlanId vlanId = event.subject().vlan();
1025 DeviceId deviceId = event.subject().location().deviceId();
1026 PortNumber port = event.subject().location().port();
1027 Set<IpAddress> ips = event.subject().ipAddresses();
Saurav Das4ce45962015-11-24 23:21:05 -08001028 log.info("Host {}/{} is added at {}:{}", mac, vlanId, deviceId, port);
Charles Chan68aa62d2015-11-09 16:37:23 -08001029
Charles Chand9681e72016-02-22 19:27:29 -08001030 if (!deviceConfiguration.suppressHost()
Charles Chanf2565a92016-02-10 20:46:58 -08001031 .contains(new ConnectPoint(deviceId, port))) {
1032 // Populate bridging table entry
1033 log.debug("Populate L2 table entry for host {} at {}:{}",
1034 mac, deviceId, port);
1035 ForwardingObjective.Builder fob =
1036 getForwardingObjectiveBuilder(deviceId, mac, vlanId, port);
1037 flowObjectiveService.forward(deviceId, fob.add(
1038 new BridgingTableObjectiveContext(mac, vlanId)
1039 ));
Charles Chan68aa62d2015-11-09 16:37:23 -08001040
Charles Chanf2565a92016-02-10 20:46:58 -08001041 // Populate IP table entry
1042 ips.forEach(ip -> {
1043 if (ip.isIp4()) {
1044 routingRulePopulator.populateIpRuleForHost(
1045 deviceId, ip.getIp4Address(), mac, port);
1046 }
1047 });
1048 }
Charles Chan68aa62d2015-11-09 16:37:23 -08001049 }
1050
1051 private void processHostRemoveEvent(HostEvent event) {
1052 MacAddress mac = event.subject().mac();
1053 VlanId vlanId = event.subject().vlan();
1054 DeviceId deviceId = event.subject().location().deviceId();
1055 PortNumber port = event.subject().location().port();
1056 Set<IpAddress> ips = event.subject().ipAddresses();
1057 log.debug("Host {}/{} is removed from {}:{}", mac, vlanId, deviceId, port);
1058
Charles Chand9681e72016-02-22 19:27:29 -08001059 if (!deviceConfiguration.suppressHost()
Charles Chanf2565a92016-02-10 20:46:58 -08001060 .contains(new ConnectPoint(deviceId, port))) {
1061 // Revoke bridging table entry
1062 ForwardingObjective.Builder fob =
1063 getForwardingObjectiveBuilder(deviceId, mac, vlanId, port);
1064 flowObjectiveService.forward(deviceId, fob.remove(
1065 new BridgingTableObjectiveContext(mac, vlanId)
1066 ));
Charles Chan68aa62d2015-11-09 16:37:23 -08001067
Charles Chanf2565a92016-02-10 20:46:58 -08001068 // Revoke IP table entry
1069 ips.forEach(ip -> {
1070 if (ip.isIp4()) {
1071 routingRulePopulator.revokeIpRuleForHost(
1072 deviceId, ip.getIp4Address(), mac, port);
1073 }
1074 });
1075 }
Charles Chan68aa62d2015-11-09 16:37:23 -08001076 }
1077
1078 private void processHostMovedEvent(HostEvent event) {
1079 MacAddress mac = event.subject().mac();
1080 VlanId vlanId = event.subject().vlan();
1081 DeviceId prevDeviceId = event.prevSubject().location().deviceId();
1082 PortNumber prevPort = event.prevSubject().location().port();
1083 Set<IpAddress> prevIps = event.prevSubject().ipAddresses();
1084 DeviceId newDeviceId = event.subject().location().deviceId();
1085 PortNumber newPort = event.subject().location().port();
1086 Set<IpAddress> newIps = event.subject().ipAddresses();
1087 log.debug("Host {}/{} is moved from {}:{} to {}:{}",
1088 mac, vlanId, prevDeviceId, prevPort, newDeviceId, newPort);
1089
Charles Chand9681e72016-02-22 19:27:29 -08001090 if (!deviceConfiguration.suppressHost()
Charles Chanf2565a92016-02-10 20:46:58 -08001091 .contains(new ConnectPoint(prevDeviceId, prevPort))) {
1092 // Revoke previous bridging table entry
1093 ForwardingObjective.Builder prevFob =
1094 getForwardingObjectiveBuilder(prevDeviceId, mac, vlanId, prevPort);
1095 flowObjectiveService.forward(prevDeviceId, prevFob.remove(
1096 new BridgingTableObjectiveContext(mac, vlanId)
1097 ));
Charles Chan68aa62d2015-11-09 16:37:23 -08001098
Charles Chanf2565a92016-02-10 20:46:58 -08001099 // Revoke previous IP table entry
1100 prevIps.forEach(ip -> {
1101 if (ip.isIp4()) {
1102 routingRulePopulator.revokeIpRuleForHost(
1103 prevDeviceId, ip.getIp4Address(), mac, prevPort);
1104 }
1105 });
1106 }
Charles Chan68aa62d2015-11-09 16:37:23 -08001107
Charles Chand9681e72016-02-22 19:27:29 -08001108 if (!deviceConfiguration.suppressHost()
Charles Chanf2565a92016-02-10 20:46:58 -08001109 .contains(new ConnectPoint(newDeviceId, newPort))) {
1110 // Populate new bridging table entry
1111 ForwardingObjective.Builder newFob =
1112 getForwardingObjectiveBuilder(newDeviceId, mac, vlanId, newPort);
1113 flowObjectiveService.forward(newDeviceId, newFob.add(
1114 new BridgingTableObjectiveContext(mac, vlanId)
1115 ));
Charles Chan68aa62d2015-11-09 16:37:23 -08001116
Charles Chanf2565a92016-02-10 20:46:58 -08001117 // Populate new IP table entry
1118 newIps.forEach(ip -> {
1119 if (ip.isIp4()) {
1120 routingRulePopulator.populateIpRuleForHost(
1121 newDeviceId, ip.getIp4Address(), mac, newPort);
1122 }
1123 });
1124 }
Charles Chan68aa62d2015-11-09 16:37:23 -08001125 }
1126
1127 private void processHostUpdatedEvent(HostEvent event) {
1128 MacAddress mac = event.subject().mac();
1129 VlanId vlanId = event.subject().vlan();
1130 DeviceId prevDeviceId = event.prevSubject().location().deviceId();
1131 PortNumber prevPort = event.prevSubject().location().port();
1132 Set<IpAddress> prevIps = event.prevSubject().ipAddresses();
1133 DeviceId newDeviceId = event.subject().location().deviceId();
1134 PortNumber newPort = event.subject().location().port();
1135 Set<IpAddress> newIps = event.subject().ipAddresses();
1136 log.debug("Host {}/{} is updated", mac, vlanId);
1137
Charles Chand9681e72016-02-22 19:27:29 -08001138 if (!deviceConfiguration.suppressHost()
Charles Chanf2565a92016-02-10 20:46:58 -08001139 .contains(new ConnectPoint(prevDeviceId, prevPort))) {
1140 // Revoke previous IP table entry
1141 prevIps.forEach(ip -> {
1142 if (ip.isIp4()) {
1143 routingRulePopulator.revokeIpRuleForHost(
1144 prevDeviceId, ip.getIp4Address(), mac, prevPort);
1145 }
1146 });
1147 }
Charles Chan68aa62d2015-11-09 16:37:23 -08001148
Charles Chand9681e72016-02-22 19:27:29 -08001149 if (!deviceConfiguration.suppressHost()
Charles Chanf2565a92016-02-10 20:46:58 -08001150 .contains(new ConnectPoint(newDeviceId, newPort))) {
1151 // Populate new IP table entry
1152 newIps.forEach(ip -> {
1153 if (ip.isIp4()) {
1154 routingRulePopulator.populateIpRuleForHost(
1155 newDeviceId, ip.getIp4Address(), mac, newPort);
1156 }
1157 });
1158 }
Charles Chan68aa62d2015-11-09 16:37:23 -08001159 }
1160
1161 @Override
1162 public void event(HostEvent event) {
1163 // Do not proceed without mastership
1164 DeviceId deviceId = event.subject().location().deviceId();
1165 if (!mastershipService.isLocalMaster(deviceId)) {
1166 return;
1167 }
1168
1169 switch (event.type()) {
1170 case HOST_ADDED:
1171 processHostAddedEvent(event);
1172 break;
1173 case HOST_MOVED:
1174 processHostMovedEvent(event);
1175 break;
1176 case HOST_REMOVED:
1177 processHostRemoveEvent(event);
1178 break;
1179 case HOST_UPDATED:
1180 processHostUpdatedEvent(event);
1181 break;
1182 default:
1183 log.warn("Unsupported host event type: {}", event.type());
1184 break;
1185 }
1186 }
1187 }
1188
1189 private static class BridgingTableObjectiveContext implements ObjectiveContext {
1190 final MacAddress mac;
1191 final VlanId vlanId;
1192
1193 BridgingTableObjectiveContext(MacAddress mac, VlanId vlanId) {
1194 this.mac = mac;
1195 this.vlanId = vlanId;
1196 }
1197
1198 @Override
1199 public void onSuccess(Objective objective) {
1200 if (objective.op() == Objective.Operation.ADD) {
1201 log.debug("Successfully populate bridging table entry for {}/{}",
1202 mac, vlanId);
1203 } else {
1204 log.debug("Successfully revoke bridging table entry for {}/{}",
1205 mac, vlanId);
1206 }
1207 }
1208
1209 @Override
1210 public void onError(Objective objective, ObjectiveError error) {
1211 if (objective.op() == Objective.Operation.ADD) {
1212 log.debug("Fail to populate bridging table entry for {}/{}. {}",
1213 mac, vlanId, error);
1214 } else {
1215 log.debug("Fail to revoke bridging table entry for {}/{}. {}",
1216 mac, vlanId, error);
1217 }
1218 }
1219 }
sanghob35a6192015-04-01 13:05:26 -07001220}