blob: 2cc5aae10a9172c80b008812f065ad6817fe116a [file] [log] [blame]
sangho80f11cb2015-04-01 13:05:26 -07001/*
Charles Chand6d25332016-02-26 22:19:52 -08002 * Copyright 2015-2016 Open Networking Laboratory
sangho80f11cb2015-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;
sangho27462c62015-05-14 00:39:53 -070023import org.apache.felix.scr.annotations.Service;
sangho80f11cb2015-04-01 13:05:26 -070024import org.onlab.packet.Ethernet;
Charles Chanf4586112015-11-09 16:37:23 -080025import org.onlab.packet.MacAddress;
Saurav Das7c305372015-10-28 12:39:42 -070026import org.onlab.packet.VlanId;
Charles Chan77277672015-10-20 16:24:19 -070027import org.onlab.packet.IPv4;
28import org.onlab.packet.Ip4Address;
29import org.onlab.packet.Ip4Prefix;
30import org.onlab.packet.IpAddress;
31import org.onlab.packet.IpPrefix;
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -070032import org.onlab.util.KryoNamespace;
sangho80f11cb2015-04-01 13:05:26 -070033import org.onosproject.core.ApplicationId;
34import org.onosproject.core.CoreService;
35import org.onosproject.event.Event;
Charles Chan77277672015-10-20 16:24:19 -070036import org.onosproject.net.ConnectPoint;
Charles Chanf4586112015-11-09 16:37:23 -080037import org.onosproject.net.PortNumber;
Charles Chan72f556a2015-10-05 17:50:33 -070038import org.onosproject.net.config.ConfigFactory;
39import org.onosproject.net.config.NetworkConfigEvent;
40import org.onosproject.net.config.NetworkConfigRegistry;
41import org.onosproject.net.config.NetworkConfigListener;
42import org.onosproject.net.config.basics.SubjectFactories;
Charles Chanf4586112015-11-09 16:37:23 -080043import org.onosproject.net.flow.DefaultTrafficSelector;
44import org.onosproject.net.flow.DefaultTrafficTreatment;
45import org.onosproject.net.flow.TrafficSelector;
46import org.onosproject.net.flow.TrafficTreatment;
47import org.onosproject.net.flowobjective.DefaultForwardingObjective;
48import org.onosproject.net.flowobjective.ForwardingObjective;
49import org.onosproject.net.flowobjective.Objective;
50import org.onosproject.net.flowobjective.ObjectiveContext;
51import org.onosproject.net.flowobjective.ObjectiveError;
52import org.onosproject.net.host.HostEvent;
53import org.onosproject.net.host.HostListener;
Charles Chande6655c2015-12-23 00:15:11 -080054import org.onosproject.net.packet.PacketPriority;
Charles Chan319d1a22015-11-03 10:42:14 -080055import org.onosproject.segmentrouting.config.DeviceConfigNotFoundException;
56import org.onosproject.segmentrouting.config.DeviceConfiguration;
Charles Chan82ab1932016-01-30 23:22:37 -080057import org.onosproject.segmentrouting.config.SegmentRoutingDeviceConfig;
58import org.onosproject.segmentrouting.config.SegmentRoutingAppConfig;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070059import org.onosproject.segmentrouting.grouphandler.DefaultGroupHandler;
60import org.onosproject.segmentrouting.grouphandler.NeighborSet;
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -070061import org.onosproject.segmentrouting.grouphandler.NeighborSetNextObjectiveStoreKey;
Saurav Das2d94d312015-11-24 23:21:05 -080062import org.onosproject.segmentrouting.grouphandler.PortNextObjectiveStoreKey;
sangho80f11cb2015-04-01 13:05:26 -070063import org.onosproject.mastership.MastershipService;
64import org.onosproject.net.Device;
65import org.onosproject.net.DeviceId;
66import org.onosproject.net.Link;
sangho80f11cb2015-04-01 13:05:26 -070067import org.onosproject.net.Port;
68import org.onosproject.net.device.DeviceEvent;
69import org.onosproject.net.device.DeviceListener;
70import org.onosproject.net.device.DeviceService;
Srikanth Vavilapalli64505482015-04-21 13:04:13 -070071import org.onosproject.net.flowobjective.FlowObjectiveService;
sangho80f11cb2015-04-01 13:05:26 -070072import org.onosproject.net.host.HostService;
sangho80f11cb2015-04-01 13:05:26 -070073import org.onosproject.net.link.LinkEvent;
74import org.onosproject.net.link.LinkListener;
75import org.onosproject.net.link.LinkService;
76import org.onosproject.net.packet.InboundPacket;
77import org.onosproject.net.packet.PacketContext;
78import org.onosproject.net.packet.PacketProcessor;
79import org.onosproject.net.packet.PacketService;
Charles Chan77277672015-10-20 16:24:19 -070080import org.onosproject.segmentrouting.grouphandler.SubnetNextObjectiveStoreKey;
Charles Chanb7f75ac2016-01-11 18:28:54 -080081import org.onosproject.segmentrouting.grouphandler.XConnectNextObjectiveStoreKey;
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -070082import org.onosproject.store.service.EventuallyConsistentMap;
83import org.onosproject.store.service.EventuallyConsistentMapBuilder;
84import org.onosproject.store.service.StorageService;
85import org.onosproject.store.service.WallClockTimestamp;
sangho80f11cb2015-04-01 13:05:26 -070086import org.slf4j.Logger;
87import org.slf4j.LoggerFactory;
88
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -070089import java.net.URI;
Saurav Das7c305372015-10-28 12:39:42 -070090import java.util.Collections;
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -070091import java.util.HashSet;
sangho27462c62015-05-14 00:39:53 -070092import java.util.List;
sangho80f11cb2015-04-01 13:05:26 -070093import java.util.Map;
Charles Chande6655c2015-12-23 00:15:11 -080094import java.util.Optional;
Saurav Das7c305372015-10-28 12:39:42 -070095import java.util.Set;
sangho80f11cb2015-04-01 13:05:26 -070096import java.util.concurrent.ConcurrentHashMap;
97import java.util.concurrent.ConcurrentLinkedQueue;
98import java.util.concurrent.Executors;
99import java.util.concurrent.ScheduledExecutorService;
100import java.util.concurrent.ScheduledFuture;
101import java.util.concurrent.TimeUnit;
102
Charles Chand6d25332016-02-26 22:19:52 -0800103import static com.google.common.base.Preconditions.checkState;
104
sangho27462c62015-05-14 00:39:53 -0700105@Service
sangho80f11cb2015-04-01 13:05:26 -0700106@Component(immediate = true)
Charles Chanb7f75ac2016-01-11 18:28:54 -0800107/**
108 * Segment routing manager.
109 */
sangho27462c62015-05-14 00:39:53 -0700110public class SegmentRoutingManager implements SegmentRoutingService {
sangho80f11cb2015-04-01 13:05:26 -0700111
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700112 private static Logger log = LoggerFactory
113 .getLogger(SegmentRoutingManager.class);
sangho80f11cb2015-04-01 13:05:26 -0700114
115 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
116 protected CoreService coreService;
117
118 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
sangho80f11cb2015-04-01 13:05:26 -0700119 protected PacketService packetService;
120
121 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
sangho80f11cb2015-04-01 13:05:26 -0700122 protected HostService hostService;
123
124 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
125 protected DeviceService deviceService;
126
127 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700128 protected FlowObjectiveService flowObjectiveService;
sangho80f11cb2015-04-01 13:05:26 -0700129
130 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
131 protected LinkService linkService;
132
133 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
sangho80f11cb2015-04-01 13:05:26 -0700134 protected MastershipService mastershipService;
sangho27462c62015-05-14 00:39:53 -0700135
Charles Chan82ab1932016-01-30 23:22:37 -0800136 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
137 protected StorageService storageService;
138
139 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
140 protected NetworkConfigRegistry cfgService;
141
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700142 protected ArpHandler arpHandler = null;
143 protected IcmpHandler icmpHandler = null;
144 protected IpHandler ipHandler = null;
145 protected RoutingRulePopulator routingRulePopulator = null;
sangho80f11cb2015-04-01 13:05:26 -0700146 protected ApplicationId appId;
sangho9b169e32015-04-14 16:27:13 -0700147 protected DeviceConfiguration deviceConfiguration = null;
sangho80f11cb2015-04-01 13:05:26 -0700148
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700149 private DefaultRoutingHandler defaultRoutingHandler = null;
sangho27462c62015-05-14 00:39:53 -0700150 private TunnelHandler tunnelHandler = null;
151 private PolicyHandler policyHandler = null;
Charles Chan2b078ae2015-10-14 11:24:40 -0700152 private InternalPacketProcessor processor = null;
153 private InternalLinkListener linkListener = null;
154 private InternalDeviceListener deviceListener = null;
Charles Chan82ab1932016-01-30 23:22:37 -0800155 private NetworkConfigEventHandler netcfgHandler = null;
sangho80f11cb2015-04-01 13:05:26 -0700156 private InternalEventHandler eventHandler = new InternalEventHandler();
Charles Chan82ab1932016-01-30 23:22:37 -0800157 private final InternalHostListener hostListener = new InternalHostListener();
sangho80f11cb2015-04-01 13:05:26 -0700158
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700159 private ScheduledExecutorService executorService = Executors
160 .newScheduledThreadPool(1);
sangho80f11cb2015-04-01 13:05:26 -0700161
Saurav Das2d94d312015-11-24 23:21:05 -0800162 @SuppressWarnings("unused")
sangho80f11cb2015-04-01 13:05:26 -0700163 private static ScheduledFuture<?> eventHandlerFuture = null;
Saurav Das2d94d312015-11-24 23:21:05 -0800164 @SuppressWarnings("rawtypes")
sangho80f11cb2015-04-01 13:05:26 -0700165 private ConcurrentLinkedQueue<Event> eventQueue = new ConcurrentLinkedQueue<Event>();
Charles Chanf4586112015-11-09 16:37:23 -0800166 private Map<DeviceId, DefaultGroupHandler> groupHandlerMap =
Charles Chanb7f75ac2016-01-11 18:28:54 -0800167 new ConcurrentHashMap<>();
168 /**
169 * Per device next objective ID store with (device id + neighbor set) as key.
170 */
171 public EventuallyConsistentMap<NeighborSetNextObjectiveStoreKey, Integer>
Charles Chanf4586112015-11-09 16:37:23 -0800172 nsNextObjStore = null;
Charles Chanb7f75ac2016-01-11 18:28:54 -0800173 /**
174 * Per device next objective ID store with (device id + subnet) as key.
175 */
176 public EventuallyConsistentMap<SubnetNextObjectiveStoreKey, Integer>
Charles Chanf4586112015-11-09 16:37:23 -0800177 subnetNextObjStore = null;
Charles Chanb7f75ac2016-01-11 18:28:54 -0800178 /**
179 * Per device next objective ID store with (device id + port) as key.
180 */
181 public EventuallyConsistentMap<PortNextObjectiveStoreKey, Integer>
Saurav Das2d94d312015-11-24 23:21:05 -0800182 portNextObjStore = null;
Charles Chanb7f75ac2016-01-11 18:28:54 -0800183 /**
184 * Per cross-connect objective ID store with VLAN ID as key.
185 */
186 public EventuallyConsistentMap<XConnectNextObjectiveStoreKey, Integer>
187 xConnectNextObjStore = null;
Saurav Das7c305372015-10-28 12:39:42 -0700188 // Per device, per-subnet assigned-vlans store, with (device id + subnet
189 // IPv4 prefix) as key
190 private EventuallyConsistentMap<SubnetAssignedVidStoreKey, VlanId>
Charles Chanb7f75ac2016-01-11 18:28:54 -0800191 subnetVidStore = null;
Saurav Das2d94d312015-11-24 23:21:05 -0800192 private EventuallyConsistentMap<String, Tunnel> tunnelStore = null;
193 private EventuallyConsistentMap<String, Policy> policyStore = null;
sangho4a5c42a2015-05-20 22:16:38 -0700194
Charles Chane7c61022015-10-07 14:21:45 -0700195 private final InternalConfigListener cfgListener =
196 new InternalConfigListener(this);
197
Charles Chan82ab1932016-01-30 23:22:37 -0800198 private final ConfigFactory<DeviceId, SegmentRoutingDeviceConfig> cfgDeviceFactory =
199 new ConfigFactory<DeviceId, SegmentRoutingDeviceConfig>(SubjectFactories.DEVICE_SUBJECT_FACTORY,
200 SegmentRoutingDeviceConfig.class,
Charles Chan72f556a2015-10-05 17:50:33 -0700201 "segmentrouting") {
202 @Override
Charles Chan82ab1932016-01-30 23:22:37 -0800203 public SegmentRoutingDeviceConfig createConfig() {
204 return new SegmentRoutingDeviceConfig();
Charles Chan72f556a2015-10-05 17:50:33 -0700205 }
206 };
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700207
Charles Chan82ab1932016-01-30 23:22:37 -0800208 private final ConfigFactory<ApplicationId, SegmentRoutingAppConfig> cfgAppFactory =
209 new ConfigFactory<ApplicationId, SegmentRoutingAppConfig>(SubjectFactories.APP_SUBJECT_FACTORY,
210 SegmentRoutingAppConfig.class,
211 "segmentrouting") {
212 @Override
213 public SegmentRoutingAppConfig createConfig() {
214 return new SegmentRoutingAppConfig();
215 }
216 };
Charles Chanf4586112015-11-09 16:37:23 -0800217
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700218 private Object threadSchedulerLock = new Object();
219 private static int numOfEventsQueued = 0;
220 private static int numOfEventsExecuted = 0;
sangho80f11cb2015-04-01 13:05:26 -0700221 private static int numOfHandlerExecution = 0;
222 private static int numOfHandlerScheduled = 0;
223
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700224 private KryoNamespace.Builder kryoBuilder = null;
Charles Chan1963f4f2016-02-18 14:22:42 -0800225 /**
226 * Segment Routing App ID.
227 */
228 public static final String SR_APP_ID = "org.onosproject.segmentrouting";
Charles Chanb7f75ac2016-01-11 18:28:54 -0800229 /**
230 * The starting value of per-subnet VLAN ID assignment.
231 */
Saurav Das7c305372015-10-28 12:39:42 -0700232 private static final short ASSIGNED_VLAN_START = 4093;
Charles Chanb7f75ac2016-01-11 18:28:54 -0800233 /**
234 * The default VLAN ID assigned to the interfaces without subnet config.
235 */
Saurav Das7c305372015-10-28 12:39:42 -0700236 public static final short ASSIGNED_VLAN_NO_SUBNET = 4094;
237
sangho80f11cb2015-04-01 13:05:26 -0700238 @Activate
239 protected void activate() {
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700240 appId = coreService
Charles Chan82ab1932016-01-30 23:22:37 -0800241 .registerApplication(SR_APP_ID);
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700242
243 kryoBuilder = new KryoNamespace.Builder()
244 .register(NeighborSetNextObjectiveStoreKey.class,
Charles Chan77277672015-10-20 16:24:19 -0700245 SubnetNextObjectiveStoreKey.class,
246 SubnetAssignedVidStoreKey.class,
sangho4a5c42a2015-05-20 22:16:38 -0700247 NeighborSet.class,
248 DeviceId.class,
249 URI.class,
250 WallClockTimestamp.class,
251 org.onosproject.cluster.NodeId.class,
252 HashSet.class,
253 Tunnel.class,
254 DefaultTunnel.class,
255 Policy.class,
256 TunnelPolicy.class,
Saurav Das7c305372015-10-28 12:39:42 -0700257 Policy.Type.class,
Charles Chan77277672015-10-20 16:24:19 -0700258 VlanId.class,
259 Ip4Address.class,
260 Ip4Prefix.class,
261 IpAddress.Version.class,
262 ConnectPoint.class
sangho4a5c42a2015-05-20 22:16:38 -0700263 );
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700264
265 log.debug("Creating EC map nsnextobjectivestore");
266 EventuallyConsistentMapBuilder<NeighborSetNextObjectiveStoreKey, Integer>
267 nsNextObjMapBuilder = storageService.eventuallyConsistentMapBuilder();
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700268 nsNextObjStore = nsNextObjMapBuilder
269 .withName("nsnextobjectivestore")
270 .withSerializer(kryoBuilder)
Madan Jampani675ae202015-06-24 19:05:56 -0700271 .withTimestampProvider((k, v) -> new WallClockTimestamp())
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700272 .build();
273 log.trace("Current size {}", nsNextObjStore.size());
274
Charles Chan77277672015-10-20 16:24:19 -0700275 log.debug("Creating EC map subnetnextobjectivestore");
276 EventuallyConsistentMapBuilder<SubnetNextObjectiveStoreKey, Integer>
277 subnetNextObjMapBuilder = storageService.eventuallyConsistentMapBuilder();
Charles Chan77277672015-10-20 16:24:19 -0700278 subnetNextObjStore = subnetNextObjMapBuilder
279 .withName("subnetnextobjectivestore")
280 .withSerializer(kryoBuilder)
281 .withTimestampProvider((k, v) -> new WallClockTimestamp())
282 .build();
283
Saurav Das2d94d312015-11-24 23:21:05 -0800284 log.debug("Creating EC map subnetnextobjectivestore");
285 EventuallyConsistentMapBuilder<PortNextObjectiveStoreKey, Integer>
286 portNextObjMapBuilder = storageService.eventuallyConsistentMapBuilder();
287 portNextObjStore = portNextObjMapBuilder
288 .withName("portnextobjectivestore")
289 .withSerializer(kryoBuilder)
290 .withTimestampProvider((k, v) -> new WallClockTimestamp())
291 .build();
292
Charles Chanb7f75ac2016-01-11 18:28:54 -0800293 log.debug("Creating EC map xconnectnextobjectivestore");
294 EventuallyConsistentMapBuilder<XConnectNextObjectiveStoreKey, Integer>
295 xConnectNextObjStoreBuilder = storageService.eventuallyConsistentMapBuilder();
296 xConnectNextObjStore = xConnectNextObjStoreBuilder
297 .withName("xconnectnextobjectivestore")
298 .withSerializer(kryoBuilder)
299 .withTimestampProvider((k, v) -> new WallClockTimestamp())
300 .build();
301
sangho4a5c42a2015-05-20 22:16:38 -0700302 EventuallyConsistentMapBuilder<String, Tunnel> tunnelMapBuilder =
303 storageService.eventuallyConsistentMapBuilder();
sangho4a5c42a2015-05-20 22:16:38 -0700304 tunnelStore = tunnelMapBuilder
305 .withName("tunnelstore")
306 .withSerializer(kryoBuilder)
Madan Jampani675ae202015-06-24 19:05:56 -0700307 .withTimestampProvider((k, v) -> new WallClockTimestamp())
sangho4a5c42a2015-05-20 22:16:38 -0700308 .build();
309
310 EventuallyConsistentMapBuilder<String, Policy> policyMapBuilder =
311 storageService.eventuallyConsistentMapBuilder();
sangho4a5c42a2015-05-20 22:16:38 -0700312 policyStore = policyMapBuilder
313 .withName("policystore")
314 .withSerializer(kryoBuilder)
Madan Jampani675ae202015-06-24 19:05:56 -0700315 .withTimestampProvider((k, v) -> new WallClockTimestamp())
sangho4a5c42a2015-05-20 22:16:38 -0700316 .build();
317
Saurav Das7c305372015-10-28 12:39:42 -0700318 EventuallyConsistentMapBuilder<SubnetAssignedVidStoreKey, VlanId>
319 subnetVidStoreMapBuilder = storageService.eventuallyConsistentMapBuilder();
Saurav Das7c305372015-10-28 12:39:42 -0700320 subnetVidStore = subnetVidStoreMapBuilder
321 .withName("subnetvidstore")
322 .withSerializer(kryoBuilder)
323 .withTimestampProvider((k, v) -> new WallClockTimestamp())
324 .build();
325
Charles Chan2b078ae2015-10-14 11:24:40 -0700326 processor = new InternalPacketProcessor();
327 linkListener = new InternalLinkListener();
328 deviceListener = new InternalDeviceListener();
Charles Chan82ab1932016-01-30 23:22:37 -0800329 netcfgHandler = new NetworkConfigEventHandler(this);
Charles Chan2b078ae2015-10-14 11:24:40 -0700330
Charles Chand6d25332016-02-26 22:19:52 -0800331 cfgService.addListener(cfgListener);
332 cfgService.registerConfigFactory(cfgDeviceFactory);
333 cfgService.registerConfigFactory(cfgAppFactory);
Charles Chan82ab1932016-01-30 23:22:37 -0800334 hostService.addListener(hostListener);
Charles Chan2b078ae2015-10-14 11:24:40 -0700335 packetService.addProcessor(processor, PacketProcessor.director(2));
336 linkService.addListener(linkListener);
337 deviceService.addListener(deviceListener);
338
Charles Chande6655c2015-12-23 00:15:11 -0800339 // Request ARP packet-in
340 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
341 selector.matchEthType(Ethernet.TYPE_ARP);
342 packetService.requestPackets(selector.build(), PacketPriority.CONTROL, appId, Optional.empty());
343
Charles Chan2b078ae2015-10-14 11:24:40 -0700344 cfgListener.configureNetwork();
345
sangho80f11cb2015-04-01 13:05:26 -0700346 log.info("Started");
347 }
348
349 @Deactivate
350 protected void deactivate() {
Charles Chan72f556a2015-10-05 17:50:33 -0700351 cfgService.removeListener(cfgListener);
Charles Chan82ab1932016-01-30 23:22:37 -0800352 cfgService.unregisterConfigFactory(cfgDeviceFactory);
353 cfgService.unregisterConfigFactory(cfgAppFactory);
Charles Chan72f556a2015-10-05 17:50:33 -0700354
Charles Chande6655c2015-12-23 00:15:11 -0800355 // Withdraw ARP packet-in
356 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
357 selector.matchEthType(Ethernet.TYPE_ARP);
358 packetService.cancelPackets(selector.build(), PacketPriority.CONTROL, appId, Optional.empty());
359
sangho80f11cb2015-04-01 13:05:26 -0700360 packetService.removeProcessor(processor);
Charles Chan2b078ae2015-10-14 11:24:40 -0700361 linkService.removeListener(linkListener);
362 deviceService.removeListener(deviceListener);
sangho80f11cb2015-04-01 13:05:26 -0700363 processor = null;
Charles Chan2b078ae2015-10-14 11:24:40 -0700364 linkListener = null;
365 deviceService = null;
366
367 groupHandlerMap.clear();
368
sangho80f11cb2015-04-01 13:05:26 -0700369 log.info("Stopped");
370 }
371
sangho27462c62015-05-14 00:39:53 -0700372
373 @Override
374 public List<Tunnel> getTunnels() {
375 return tunnelHandler.getTunnels();
376 }
377
378 @Override
sanghobd812f82015-06-29 14:58:47 -0700379 public TunnelHandler.Result createTunnel(Tunnel tunnel) {
380 return tunnelHandler.createTunnel(tunnel);
sangho27462c62015-05-14 00:39:53 -0700381 }
382
383 @Override
sanghobd812f82015-06-29 14:58:47 -0700384 public TunnelHandler.Result removeTunnel(Tunnel tunnel) {
sangho27462c62015-05-14 00:39:53 -0700385 for (Policy policy: policyHandler.getPolicies()) {
386 if (policy.type() == Policy.Type.TUNNEL_FLOW) {
387 TunnelPolicy tunnelPolicy = (TunnelPolicy) policy;
388 if (tunnelPolicy.tunnelId().equals(tunnel.id())) {
389 log.warn("Cannot remove the tunnel used by a policy");
sanghobd812f82015-06-29 14:58:47 -0700390 return TunnelHandler.Result.TUNNEL_IN_USE;
sangho27462c62015-05-14 00:39:53 -0700391 }
392 }
393 }
sanghobd812f82015-06-29 14:58:47 -0700394 return tunnelHandler.removeTunnel(tunnel);
sangho27462c62015-05-14 00:39:53 -0700395 }
396
397 @Override
sanghobd812f82015-06-29 14:58:47 -0700398 public PolicyHandler.Result removePolicy(Policy policy) {
399 return policyHandler.removePolicy(policy);
sangho27462c62015-05-14 00:39:53 -0700400 }
401
402 @Override
sanghobd812f82015-06-29 14:58:47 -0700403 public PolicyHandler.Result createPolicy(Policy policy) {
404 return policyHandler.createPolicy(policy);
sangho27462c62015-05-14 00:39:53 -0700405 }
406
407 @Override
408 public List<Policy> getPolicies() {
409 return policyHandler.getPolicies();
410 }
411
sangho80f1f892015-05-19 11:57:42 -0700412 /**
413 * Returns the tunnel object with the tunnel ID.
414 *
415 * @param tunnelId Tunnel ID
416 * @return Tunnel reference
417 */
sangho27462c62015-05-14 00:39:53 -0700418 public Tunnel getTunnel(String tunnelId) {
419 return tunnelHandler.getTunnel(tunnelId);
420 }
421
sangho80f11cb2015-04-01 13:05:26 -0700422 /**
Saurav Das7c305372015-10-28 12:39:42 -0700423 * Returns the vlan-id assigned to the subnet configured for a device.
424 * If no vlan-id has been assigned, a new one is assigned out of a pool of ids,
425 * if and only if this controller instance is the master for the device.
426 * <p>
427 * USAGE: The assigned vlans are meant to be applied to untagged packets on those
428 * switches/pipelines that need this functionality. These vids are meant
429 * to be used internally within a switch, and thus need to be unique only
430 * on a switch level. Note that packets never go out on the wire with these
431 * vlans. Currently, vlan ids are assigned from value 4093 down.
432 * Vlan id 4094 expected to be used for all ports that are not assigned subnets.
433 * Vlan id 4095 is reserved and unused. Only a single vlan id is assigned
434 * per subnet.
sangho80f11cb2015-04-01 13:05:26 -0700435 *
Saurav Das7c305372015-10-28 12:39:42 -0700436 * @param deviceId switch dpid
437 * @param subnet IPv4 prefix for which assigned vlan is desired
438 * @return VlanId assigned for the subnet on the device, or
439 * null if no vlan assignment was found and this instance is not
440 * the master for the device.
sangho80f11cb2015-04-01 13:05:26 -0700441 */
Charles Chanb7f75ac2016-01-11 18:28:54 -0800442 // TODO: We should avoid assigning VLAN IDs that are used by VLAN cross-connection.
Saurav Das7c305372015-10-28 12:39:42 -0700443 public VlanId getSubnetAssignedVlanId(DeviceId deviceId, Ip4Prefix subnet) {
444 VlanId assignedVid = subnetVidStore.get(new SubnetAssignedVidStoreKey(
445 deviceId, subnet));
446 if (assignedVid != null) {
447 log.debug("Query for subnet:{} on device:{} returned assigned-vlan "
448 + "{}", subnet, deviceId, assignedVid);
449 return assignedVid;
450 }
451 //check mastership for the right to assign a vlan
452 if (!mastershipService.isLocalMaster(deviceId)) {
453 log.warn("This controller instance is not the master for device {}. "
454 + "Cannot assign vlan-id for subnet {}", deviceId, subnet);
455 return null;
456 }
457 // vlan assignment is expensive but done only once
Charles Chanc6ad7752015-10-29 14:58:10 -0700458 Set<Ip4Prefix> configuredSubnets = deviceConfiguration.getSubnets(deviceId);
Saurav Das7c305372015-10-28 12:39:42 -0700459 Set<Short> assignedVlans = new HashSet<>();
460 Set<Ip4Prefix> unassignedSubnets = new HashSet<>();
461 for (Ip4Prefix sub : configuredSubnets) {
462 VlanId v = subnetVidStore.get(new SubnetAssignedVidStoreKey(deviceId,
463 sub));
464 if (v != null) {
465 assignedVlans.add(v.toShort());
466 } else {
467 unassignedSubnets.add(sub);
468 }
469 }
470 short nextAssignedVlan = ASSIGNED_VLAN_START;
471 if (!assignedVlans.isEmpty()) {
472 nextAssignedVlan = (short) (Collections.min(assignedVlans) - 1);
473 }
474 for (Ip4Prefix unsub : unassignedSubnets) {
Charles Chan82ab1932016-01-30 23:22:37 -0800475 // Special case for default route. Assign default VLAN ID to /32 and /0 subnets
476 if (unsub.prefixLength() == IpPrefix.MAX_INET_MASK_LENGTH ||
477 unsub.prefixLength() == 0) {
478 subnetVidStore.put(new SubnetAssignedVidStoreKey(deviceId, unsub),
479 VlanId.vlanId(ASSIGNED_VLAN_NO_SUBNET));
480 } else {
481 subnetVidStore.put(new SubnetAssignedVidStoreKey(deviceId, unsub),
482 VlanId.vlanId(nextAssignedVlan--));
483 log.info("Assigned vlan: {} to subnet: {} on device: {}",
484 nextAssignedVlan + 1, unsub, deviceId);
485 }
sangho80f11cb2015-04-01 13:05:26 -0700486 }
487
Saurav Das7c305372015-10-28 12:39:42 -0700488 return subnetVidStore.get(new SubnetAssignedVidStoreKey(deviceId, subnet));
sangho80f11cb2015-04-01 13:05:26 -0700489 }
490
sangho27462c62015-05-14 00:39:53 -0700491 /**
Saurav Das7c305372015-10-28 12:39:42 -0700492 * Returns the next objective ID for the given NeighborSet.
Saurav Das4c35fc42015-11-20 15:27:53 -0800493 * If the nextObjective does not exist, a new one is created and
Saurav Das2d94d312015-11-24 23:21:05 -0800494 * its id is returned.
sangho27462c62015-05-14 00:39:53 -0700495 *
sangho80f1f892015-05-19 11:57:42 -0700496 * @param deviceId Device ID
497 * @param ns NegighborSet
Saurav Das4c35fc42015-11-20 15:27:53 -0800498 * @param meta metadata passed into the creation of a Next Objective
499 * @return next objective ID or -1 if an error was encountered during the
500 * creation of the nextObjective
sangho27462c62015-05-14 00:39:53 -0700501 */
Saurav Das4c35fc42015-11-20 15:27:53 -0800502 public int getNextObjectiveId(DeviceId deviceId, NeighborSet ns,
503 TrafficSelector meta) {
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700504 if (groupHandlerMap.get(deviceId) != null) {
505 log.trace("getNextObjectiveId query in device {}", deviceId);
506 return groupHandlerMap
Saurav Das4c35fc42015-11-20 15:27:53 -0800507 .get(deviceId).getNextObjectiveId(ns, meta);
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700508 } else {
Saurav Das2d94d312015-11-24 23:21:05 -0800509 log.warn("getNextObjectiveId query - groupHandler for device {} "
510 + "not found", deviceId);
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700511 return -1;
512 }
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700513 }
514
Charles Chan77277672015-10-20 16:24:19 -0700515 /**
Saurav Das2d94d312015-11-24 23:21:05 -0800516 * Returns the next objective ID for the given subnet prefix. It is expected
517 * that the next-objective has been pre-created from configuration.
Charles Chan77277672015-10-20 16:24:19 -0700518 *
519 * @param deviceId Device ID
520 * @param prefix Subnet
Saurav Das2d94d312015-11-24 23:21:05 -0800521 * @return next objective ID or -1 if it was not found
Charles Chan77277672015-10-20 16:24:19 -0700522 */
523 public int getSubnetNextObjectiveId(DeviceId deviceId, IpPrefix prefix) {
524 if (groupHandlerMap.get(deviceId) != null) {
525 log.trace("getSubnetNextObjectiveId query in device {}", deviceId);
526 return groupHandlerMap
527 .get(deviceId).getSubnetNextObjectiveId(prefix);
528 } else {
Saurav Das2d94d312015-11-24 23:21:05 -0800529 log.warn("getSubnetNextObjectiveId query - groupHandler for "
530 + "device {} not found", deviceId);
531 return -1;
532 }
533 }
534
535 /**
536 * Returns the next objective ID for the given portNumber, given the treatment.
537 * There could be multiple different treatments to the same outport, which
538 * would result in different objectives. If the next object
539 * does not exist, a new one is created and its id is returned.
540 *
541 * @param deviceId Device ID
542 * @param portNum port number on device for which NextObjective is queried
543 * @param treatment the actions to apply on the packets (should include outport)
544 * @param meta metadata passed into the creation of a Next Objective if necessary
545 * @return next objective ID or -1 if it was not found
546 */
547 public int getPortNextObjectiveId(DeviceId deviceId, PortNumber portNum,
548 TrafficTreatment treatment,
549 TrafficSelector meta) {
550 DefaultGroupHandler ghdlr = groupHandlerMap.get(deviceId);
551 if (ghdlr != null) {
552 return ghdlr.getPortNextObjectiveId(portNum, treatment, meta);
553 } else {
Charles Chanb7f75ac2016-01-11 18:28:54 -0800554 log.warn("getPortNextObjectiveId query - groupHandler for device {}"
555 + " not found", deviceId);
556 return -1;
557 }
558 }
559
560 /**
561 * Returns the next objective ID of type broadcast associated with the VLAN
562 * cross-connection.
563 *
564 * @param deviceId Device ID for the cross-connection
565 * @param vlanId VLAN ID for the cross-connection
566 * @return next objective ID or -1 if it was not found
567 */
568 public int getXConnectNextObjectiveId(DeviceId deviceId, VlanId vlanId) {
569 DefaultGroupHandler ghdlr = groupHandlerMap.get(deviceId);
570 if (ghdlr != null) {
571 return ghdlr.getXConnectNextObjectiveId(vlanId);
572 } else {
573 log.warn("getPortNextObjectiveId query - groupHandler for device {}"
Saurav Das2d94d312015-11-24 23:21:05 -0800574 + " not found", deviceId);
Charles Chan77277672015-10-20 16:24:19 -0700575 return -1;
576 }
577 }
578
sangho80f11cb2015-04-01 13:05:26 -0700579 private class InternalPacketProcessor implements PacketProcessor {
sangho80f11cb2015-04-01 13:05:26 -0700580 @Override
581 public void process(PacketContext context) {
582
583 if (context.isHandled()) {
584 return;
585 }
586
587 InboundPacket pkt = context.inPacket();
588 Ethernet ethernet = pkt.parsed();
Saurav Das2d94d312015-11-24 23:21:05 -0800589 log.trace("Rcvd pktin: {}", ethernet);
sangho80f11cb2015-04-01 13:05:26 -0700590 if (ethernet.getEtherType() == Ethernet.TYPE_ARP) {
591 arpHandler.processPacketIn(pkt);
592 } else if (ethernet.getEtherType() == Ethernet.TYPE_IPV4) {
593 IPv4 ipPacket = (IPv4) ethernet.getPayload();
594 ipHandler.addToPacketBuffer(ipPacket);
595 if (ipPacket.getProtocol() == IPv4.PROTOCOL_ICMP) {
596 icmpHandler.processPacketIn(pkt);
597 } else {
598 ipHandler.processPacketIn(pkt);
599 }
600 }
601 }
602 }
603
604 private class InternalLinkListener implements LinkListener {
605 @Override
606 public void event(LinkEvent event) {
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700607 if (event.type() == LinkEvent.Type.LINK_ADDED
608 || event.type() == LinkEvent.Type.LINK_REMOVED) {
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700609 log.debug("Event {} received from Link Service", event.type());
sangho80f11cb2015-04-01 13:05:26 -0700610 scheduleEventHandlerIfNotScheduled(event);
611 }
612 }
613 }
614
615 private class InternalDeviceListener implements DeviceListener {
sangho80f11cb2015-04-01 13:05:26 -0700616 @Override
617 public void event(DeviceEvent event) {
sangho80f11cb2015-04-01 13:05:26 -0700618 switch (event.type()) {
619 case DEVICE_ADDED:
620 case PORT_REMOVED:
sanghofb7c7292015-04-13 15:15:58 -0700621 case DEVICE_UPDATED:
622 case DEVICE_AVAILABILITY_CHANGED:
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700623 log.debug("Event {} received from Device Service", event.type());
sangho80f11cb2015-04-01 13:05:26 -0700624 scheduleEventHandlerIfNotScheduled(event);
625 break;
626 default:
627 }
628 }
629 }
630
Saurav Das2d94d312015-11-24 23:21:05 -0800631 @SuppressWarnings("rawtypes")
sangho80f11cb2015-04-01 13:05:26 -0700632 private void scheduleEventHandlerIfNotScheduled(Event event) {
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700633 synchronized (threadSchedulerLock) {
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700634 eventQueue.add(event);
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700635 numOfEventsQueued++;
636
637 if ((numOfHandlerScheduled - numOfHandlerExecution) == 0) {
638 //No pending scheduled event handling threads. So start a new one.
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700639 eventHandlerFuture = executorService
640 .schedule(eventHandler, 100, TimeUnit.MILLISECONDS);
641 numOfHandlerScheduled++;
642 }
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700643 log.trace("numOfEventsQueued {}, numOfEventHanlderScheduled {}",
644 numOfEventsQueued,
645 numOfHandlerScheduled);
sangho80f11cb2015-04-01 13:05:26 -0700646 }
sangho80f11cb2015-04-01 13:05:26 -0700647 }
648
649 private class InternalEventHandler implements Runnable {
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700650 @Override
sangho80f11cb2015-04-01 13:05:26 -0700651 public void run() {
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700652 try {
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700653 while (true) {
Saurav Das2d94d312015-11-24 23:21:05 -0800654 @SuppressWarnings("rawtypes")
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700655 Event event = null;
656 synchronized (threadSchedulerLock) {
657 if (!eventQueue.isEmpty()) {
658 event = eventQueue.poll();
659 numOfEventsExecuted++;
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700660 } else {
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700661 numOfHandlerExecution++;
662 log.debug("numOfHandlerExecution {} numOfEventsExecuted {}",
663 numOfHandlerExecution, numOfEventsExecuted);
664 break;
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700665 }
sanghofb7c7292015-04-13 15:15:58 -0700666 }
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700667 if (event.type() == LinkEvent.Type.LINK_ADDED) {
668 processLinkAdded((Link) event.subject());
669 } else if (event.type() == LinkEvent.Type.LINK_REMOVED) {
670 processLinkRemoved((Link) event.subject());
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700671 } else if (event.type() == DeviceEvent.Type.DEVICE_ADDED ||
672 event.type() == DeviceEvent.Type.DEVICE_AVAILABILITY_CHANGED ||
673 event.type() == DeviceEvent.Type.DEVICE_UPDATED) {
Saurav Das62af8802015-12-04 10:52:59 -0800674 DeviceId deviceId = ((Device) event.subject()).id();
675 if (deviceService.isAvailable(deviceId)) {
Saurav Dasc28b3432015-10-30 17:45:38 -0700676 log.info("Processing device event {} for available device {}",
677 event.type(), ((Device) event.subject()).id());
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700678 processDeviceAdded((Device) event.subject());
Saurav Das62af8802015-12-04 10:52:59 -0800679 } /* else {
680 if (event.type() == DeviceEvent.Type.DEVICE_AVAILABILITY_CHANGED) {
681 // availability changed and not available - dev gone
682 DefaultGroupHandler groupHandler = groupHandlerMap.get(deviceId);
683 if (groupHandler != null) {
684 groupHandler.removeAllGroups();
685 }
686 }
687 }*/
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700688 } else if (event.type() == DeviceEvent.Type.PORT_REMOVED) {
689 processPortRemoved((Device) event.subject(),
690 ((DeviceEvent) event).port());
691 } else {
692 log.warn("Unhandled event type: {}", event.type());
693 }
sangho80f11cb2015-04-01 13:05:26 -0700694 }
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700695 } catch (Exception e) {
696 log.error("SegmentRouting event handler "
697 + "thread thrown an exception: {}", e);
sangho80f11cb2015-04-01 13:05:26 -0700698 }
sangho80f11cb2015-04-01 13:05:26 -0700699 }
700 }
701
sangho80f11cb2015-04-01 13:05:26 -0700702 private void processLinkAdded(Link link) {
703 log.debug("A new link {} was added", link.toString());
Charles Chan319d1a22015-11-03 10:42:14 -0800704 if (!deviceConfiguration.isConfigured(link.src().deviceId())) {
705 log.warn("Source device of this link is not configured.");
706 return;
707 }
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700708 //Irrespective whether the local is a MASTER or not for this device,
709 //create group handler instance and push default TTP flow rules.
710 //Because in a multi-instance setup, instances can initiate
711 //groups for any devices. Also the default TTP rules are needed
712 //to be pushed before inserting any IP table entries for any device
713 DefaultGroupHandler groupHandler = groupHandlerMap.get(link.src()
714 .deviceId());
715 if (groupHandler != null) {
Saurav Das4c35fc42015-11-20 15:27:53 -0800716 groupHandler.linkUp(link, mastershipService.isLocalMaster(
717 link.src().deviceId()));
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700718 } else {
719 Device device = deviceService.getDevice(link.src().deviceId());
720 if (device != null) {
721 log.warn("processLinkAdded: Link Added "
722 + "Notification without Device Added "
723 + "event, still handling it");
724 processDeviceAdded(device);
725 groupHandler = groupHandlerMap.get(link.src()
726 .deviceId());
Saurav Das4c35fc42015-11-20 15:27:53 -0800727 groupHandler.linkUp(link, mastershipService.isLocalMaster(device.id()));
sangho80f11cb2015-04-01 13:05:26 -0700728 }
729 }
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700730
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700731 log.trace("Starting optimized route population process");
732 defaultRoutingHandler.populateRoutingRulesForLinkStatusChange(null);
733 //log.trace("processLinkAdded: re-starting route population process");
734 //defaultRoutingHandler.startPopulationProcess();
sangho80f11cb2015-04-01 13:05:26 -0700735 }
736
737 private void processLinkRemoved(Link link) {
738 log.debug("A link {} was removed", link.toString());
sangho2165d222015-05-01 09:38:25 -0700739 DefaultGroupHandler groupHandler = groupHandlerMap.get(link.src().deviceId());
740 if (groupHandler != null) {
Saurav Das62af8802015-12-04 10:52:59 -0800741 groupHandler.portDown(link.src().port(),
742 mastershipService.isLocalMaster(link.src().deviceId()));
sangho2165d222015-05-01 09:38:25 -0700743 }
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700744 log.trace("Starting optimized route population process");
745 defaultRoutingHandler.populateRoutingRulesForLinkStatusChange(link);
746 //log.trace("processLinkRemoved: re-starting route population process");
747 //defaultRoutingHandler.startPopulationProcess();
sangho80f11cb2015-04-01 13:05:26 -0700748 }
749
750 private void processDeviceAdded(Device device) {
751 log.debug("A new device with ID {} was added", device.id());
Charles Chan319d1a22015-11-03 10:42:14 -0800752 if (deviceConfiguration == null || !deviceConfiguration.isConfigured(device.id())) {
Saurav Das8ec0ec42015-11-03 14:39:27 -0800753 log.warn("Device configuration uploading. Device {} will be "
754 + "processed after config completes.", device.id());
755 return;
756 }
Saurav Dasc28b3432015-10-30 17:45:38 -0700757 // Irrespective of whether the local is a MASTER or not for this device,
758 // we need to create a SR-group-handler instance. This is because in a
759 // multi-instance setup, any instance can initiate forwarding/next-objectives
760 // for any switch (even if this instance is a SLAVE or not even connected
761 // to the switch). To handle this, a default-group-handler instance is necessary
762 // per switch.
Saurav Das8ec0ec42015-11-03 14:39:27 -0800763 if (groupHandlerMap.get(device.id()) == null) {
Charles Chan319d1a22015-11-03 10:42:14 -0800764 DefaultGroupHandler groupHandler;
765 try {
766 groupHandler = DefaultGroupHandler.
767 createGroupHandler(device.id(),
768 appId,
769 deviceConfiguration,
770 linkService,
771 flowObjectiveService,
Charles Chande6655c2015-12-23 00:15:11 -0800772 this);
Charles Chan319d1a22015-11-03 10:42:14 -0800773 } catch (DeviceConfigNotFoundException e) {
774 log.warn(e.getMessage() + " Aborting processDeviceAdded.");
775 return;
776 }
Saurav Das8ec0ec42015-11-03 14:39:27 -0800777 groupHandlerMap.put(device.id(), groupHandler);
778 // Also, in some cases, drivers may need extra
779 // information to process rules (eg. Router IP/MAC); and so, we send
780 // port addressing rules to the driver as well irrespective of whether
781 // this instance is the master or not.
782 defaultRoutingHandler.populatePortAddressingRules(device.id());
Charles Chand4a99c52015-11-18 16:51:08 -0800783 hostListener.readInitialHosts();
Saurav Das8ec0ec42015-11-03 14:39:27 -0800784 }
Charles Chan77277672015-10-20 16:24:19 -0700785 if (mastershipService.isLocalMaster(device.id())) {
Saurav Das8ec0ec42015-11-03 14:39:27 -0800786 DefaultGroupHandler groupHandler = groupHandlerMap.get(device.id());
Charles Chan77277672015-10-20 16:24:19 -0700787 groupHandler.createGroupsFromSubnetConfig();
Charles Chanf4586112015-11-09 16:37:23 -0800788 routingRulePopulator.populateSubnetBroadcastRule(device.id());
Charles Chanb7f75ac2016-01-11 18:28:54 -0800789 groupHandler.createGroupsForXConnect(device.id());
790 routingRulePopulator.populateXConnectBroadcastRule(device.id());
Charles Chan77277672015-10-20 16:24:19 -0700791 }
Charles Chan82ab1932016-01-30 23:22:37 -0800792
793 netcfgHandler.initVRouters(device.id());
sangho80f11cb2015-04-01 13:05:26 -0700794 }
795
796 private void processPortRemoved(Device device, Port port) {
797 log.debug("Port {} was removed", port.toString());
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700798 DefaultGroupHandler groupHandler = groupHandlerMap.get(device.id());
sangho80f11cb2015-04-01 13:05:26 -0700799 if (groupHandler != null) {
Saurav Das62af8802015-12-04 10:52:59 -0800800 groupHandler.portDown(port.number(),
801 mastershipService.isLocalMaster(device.id()));
sangho80f11cb2015-04-01 13:05:26 -0700802 }
803 }
sangho27462c62015-05-14 00:39:53 -0700804
Charles Chan72f556a2015-10-05 17:50:33 -0700805 private class InternalConfigListener implements NetworkConfigListener {
Charles Chane7c61022015-10-07 14:21:45 -0700806 SegmentRoutingManager segmentRoutingManager;
807
Charles Chanb7f75ac2016-01-11 18:28:54 -0800808 /**
809 * Constructs the internal network config listener.
810 *
811 * @param srMgr segment routing manager
812 */
Charles Chane7c61022015-10-07 14:21:45 -0700813 public InternalConfigListener(SegmentRoutingManager srMgr) {
814 this.segmentRoutingManager = srMgr;
815 }
816
Charles Chanb7f75ac2016-01-11 18:28:54 -0800817 /**
818 * Reads network config and initializes related data structure accordingly.
819 */
Charles Chane7c61022015-10-07 14:21:45 -0700820 public void configureNetwork() {
Charles Chan43547ca2016-02-10 20:46:58 -0800821 deviceConfiguration = new DeviceConfiguration(appId,
822 segmentRoutingManager.cfgService);
Charles Chane7c61022015-10-07 14:21:45 -0700823
824 arpHandler = new ArpHandler(segmentRoutingManager);
825 icmpHandler = new IcmpHandler(segmentRoutingManager);
826 ipHandler = new IpHandler(segmentRoutingManager);
827 routingRulePopulator = new RoutingRulePopulator(segmentRoutingManager);
828 defaultRoutingHandler = new DefaultRoutingHandler(segmentRoutingManager);
829
830 tunnelHandler = new TunnelHandler(linkService, deviceConfiguration,
831 groupHandlerMap, tunnelStore);
832 policyHandler = new PolicyHandler(appId, deviceConfiguration,
833 flowObjectiveService,
834 tunnelHandler, policyStore);
835
Charles Chane7c61022015-10-07 14:21:45 -0700836 for (Device device : deviceService.getDevices()) {
Saurav Dasc28b3432015-10-30 17:45:38 -0700837 // Irrespective of whether the local is a MASTER or not for this device,
838 // we need to create a SR-group-handler instance. This is because in a
839 // multi-instance setup, any instance can initiate forwarding/next-objectives
840 // for any switch (even if this instance is a SLAVE or not even connected
841 // to the switch). To handle this, a default-group-handler instance is necessary
842 // per switch.
Saurav Das8ec0ec42015-11-03 14:39:27 -0800843 if (groupHandlerMap.get(device.id()) == null) {
Charles Chan319d1a22015-11-03 10:42:14 -0800844 DefaultGroupHandler groupHandler;
845 try {
846 groupHandler = DefaultGroupHandler.
847 createGroupHandler(device.id(),
848 appId,
849 deviceConfiguration,
850 linkService,
851 flowObjectiveService,
Charles Chande6655c2015-12-23 00:15:11 -0800852 segmentRoutingManager);
Charles Chan319d1a22015-11-03 10:42:14 -0800853 } catch (DeviceConfigNotFoundException e) {
854 log.warn(e.getMessage() + " Aborting configureNetwork.");
855 return;
856 }
Saurav Das8ec0ec42015-11-03 14:39:27 -0800857 groupHandlerMap.put(device.id(), groupHandler);
Saurav Dasc28b3432015-10-30 17:45:38 -0700858
Saurav Das8ec0ec42015-11-03 14:39:27 -0800859 // Also, in some cases, drivers may need extra
860 // information to process rules (eg. Router IP/MAC); and so, we send
861 // port addressing rules to the driver as well, irrespective of whether
862 // this instance is the master or not.
863 defaultRoutingHandler.populatePortAddressingRules(device.id());
Charles Chand4a99c52015-11-18 16:51:08 -0800864 hostListener.readInitialHosts();
Saurav Das8ec0ec42015-11-03 14:39:27 -0800865 }
Charles Chan77277672015-10-20 16:24:19 -0700866 if (mastershipService.isLocalMaster(device.id())) {
Saurav Das8ec0ec42015-11-03 14:39:27 -0800867 DefaultGroupHandler groupHandler = groupHandlerMap.get(device.id());
Charles Chan77277672015-10-20 16:24:19 -0700868 groupHandler.createGroupsFromSubnetConfig();
Charles Chanf4586112015-11-09 16:37:23 -0800869 routingRulePopulator.populateSubnetBroadcastRule(device.id());
Charles Chanb7f75ac2016-01-11 18:28:54 -0800870 groupHandler.createGroupsForXConnect(device.id());
871 routingRulePopulator.populateXConnectBroadcastRule(device.id());
Charles Chan77277672015-10-20 16:24:19 -0700872 }
Charles Chane7c61022015-10-07 14:21:45 -0700873 }
874
875 defaultRoutingHandler.startPopulationProcess();
876 }
877
Charles Chan72f556a2015-10-05 17:50:33 -0700878 @Override
879 public void event(NetworkConfigEvent event) {
Charles Chan82ab1932016-01-30 23:22:37 -0800880 // TODO move this part to NetworkConfigEventHandler
881 if (event.configClass().equals(SegmentRoutingDeviceConfig.class)) {
882 switch (event.type()) {
883 case CONFIG_ADDED:
884 log.info("Segment Routing Config added.");
885 configureNetwork();
886 break;
887 case CONFIG_UPDATED:
888 log.info("Segment Routing Config updated.");
889 // TODO support dynamic configuration
890 break;
891 default:
892 break;
Charles Chan2b078ae2015-10-14 11:24:40 -0700893 }
Charles Chan82ab1932016-01-30 23:22:37 -0800894 } else if (event.configClass().equals(SegmentRoutingAppConfig.class)) {
Charles Chand6d25332016-02-26 22:19:52 -0800895 checkState(netcfgHandler != null, "NetworkConfigEventHandler is not initialized");
Charles Chan82ab1932016-01-30 23:22:37 -0800896 switch (event.type()) {
897 case CONFIG_ADDED:
898 netcfgHandler.processVRouterConfigAdded(event);
899 break;
900 case CONFIG_UPDATED:
901 netcfgHandler.processVRouterConfigUpdated(event);
902 break;
903 case CONFIG_REMOVED:
904 netcfgHandler.processVRouterConfigRemoved(event);
905 break;
906 default:
907 break;
Charles Chan2b078ae2015-10-14 11:24:40 -0700908 }
Charles Chan72f556a2015-10-05 17:50:33 -0700909 }
910 }
911 }
Charles Chanf4586112015-11-09 16:37:23 -0800912
Charles Chand4a99c52015-11-18 16:51:08 -0800913 // TODO Move bridging table population to a separate class
Charles Chanf4586112015-11-09 16:37:23 -0800914 private class InternalHostListener implements HostListener {
Charles Chand4a99c52015-11-18 16:51:08 -0800915 private void readInitialHosts() {
916 hostService.getHosts().forEach(host -> {
917 MacAddress mac = host.mac();
918 VlanId vlanId = host.vlan();
919 DeviceId deviceId = host.location().deviceId();
920 PortNumber port = host.location().port();
921 Set<IpAddress> ips = host.ipAddresses();
922 log.debug("Host {}/{} is added at {}:{}", mac, vlanId, deviceId, port);
923
924 // Populate bridging table entry
925 ForwardingObjective.Builder fob =
Saurav Das2d94d312015-11-24 23:21:05 -0800926 getForwardingObjectiveBuilder(deviceId, mac, vlanId, port);
Charles Chand4a99c52015-11-18 16:51:08 -0800927 flowObjectiveService.forward(deviceId, fob.add(
928 new BridgingTableObjectiveContext(mac, vlanId)
929 ));
930
931 // Populate IP table entry
932 ips.forEach(ip -> {
933 if (ip.isIp4()) {
934 routingRulePopulator.populateIpRuleForHost(
935 deviceId, ip.getIp4Address(), mac, port);
936 }
937 });
938 });
939 }
940
Charles Chanf4586112015-11-09 16:37:23 -0800941 private ForwardingObjective.Builder getForwardingObjectiveBuilder(
Saurav Das2d94d312015-11-24 23:21:05 -0800942 DeviceId deviceId, MacAddress mac, VlanId vlanId,
943 PortNumber outport) {
Charles Chande6655c2015-12-23 00:15:11 -0800944 // Get assigned VLAN for the subnet
Saurav Das2d94d312015-11-24 23:21:05 -0800945 VlanId outvlan = null;
946 Ip4Prefix subnet = deviceConfiguration.getPortSubnet(deviceId, outport);
947 if (subnet == null) {
948 outvlan = VlanId.vlanId(ASSIGNED_VLAN_NO_SUBNET);
949 } else {
950 outvlan = getSubnetAssignedVlanId(deviceId, subnet);
951 }
Charles Chande6655c2015-12-23 00:15:11 -0800952
953 // match rule
954 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
955 sbuilder.matchEthDst(mac);
956 /*
957 * Note: for untagged packets, match on the assigned VLAN.
958 * for tagged packets, match on its incoming VLAN.
959 */
960 if (vlanId.equals(VlanId.NONE)) {
961 sbuilder.matchVlanId(outvlan);
962 } else {
963 sbuilder.matchVlanId(vlanId);
964 }
965
966 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
967 tbuilder.immediate().popVlan();
968 tbuilder.immediate().setOutput(outport);
969
970 // for switch pipelines that need it, provide outgoing vlan as metadata
Saurav Das2d94d312015-11-24 23:21:05 -0800971 TrafficSelector meta = DefaultTrafficSelector.builder()
972 .matchVlanId(outvlan).build();
973
974 // All forwarding is via Groups. Drivers can re-purpose to flow-actions if needed.
975 int portNextObjId = getPortNextObjectiveId(deviceId, outport,
976 tbuilder.build(),
977 meta);
Charles Chanf4586112015-11-09 16:37:23 -0800978
979 return DefaultForwardingObjective.builder()
980 .withFlag(ForwardingObjective.Flag.SPECIFIC)
981 .withSelector(sbuilder.build())
Saurav Das2d94d312015-11-24 23:21:05 -0800982 .nextStep(portNextObjId)
Charles Chanf4586112015-11-09 16:37:23 -0800983 .withPriority(100)
984 .fromApp(appId)
985 .makePermanent();
986 }
987
988 private void processHostAddedEvent(HostEvent event) {
989 MacAddress mac = event.subject().mac();
990 VlanId vlanId = event.subject().vlan();
991 DeviceId deviceId = event.subject().location().deviceId();
992 PortNumber port = event.subject().location().port();
993 Set<IpAddress> ips = event.subject().ipAddresses();
Saurav Das2d94d312015-11-24 23:21:05 -0800994 log.info("Host {}/{} is added at {}:{}", mac, vlanId, deviceId, port);
Charles Chanf4586112015-11-09 16:37:23 -0800995
Charles Chan57bd98c2016-02-22 19:27:29 -0800996 if (!deviceConfiguration.suppressHost()
Charles Chan43547ca2016-02-10 20:46:58 -0800997 .contains(new ConnectPoint(deviceId, port))) {
998 // Populate bridging table entry
999 log.debug("Populate L2 table entry for host {} at {}:{}",
1000 mac, deviceId, port);
1001 ForwardingObjective.Builder fob =
1002 getForwardingObjectiveBuilder(deviceId, mac, vlanId, port);
1003 flowObjectiveService.forward(deviceId, fob.add(
1004 new BridgingTableObjectiveContext(mac, vlanId)
1005 ));
Charles Chanf4586112015-11-09 16:37:23 -08001006
Charles Chan43547ca2016-02-10 20:46:58 -08001007 // Populate IP table entry
1008 ips.forEach(ip -> {
1009 if (ip.isIp4()) {
1010 routingRulePopulator.populateIpRuleForHost(
1011 deviceId, ip.getIp4Address(), mac, port);
1012 }
1013 });
1014 }
Charles Chanf4586112015-11-09 16:37:23 -08001015 }
1016
1017 private void processHostRemoveEvent(HostEvent event) {
1018 MacAddress mac = event.subject().mac();
1019 VlanId vlanId = event.subject().vlan();
1020 DeviceId deviceId = event.subject().location().deviceId();
1021 PortNumber port = event.subject().location().port();
1022 Set<IpAddress> ips = event.subject().ipAddresses();
1023 log.debug("Host {}/{} is removed from {}:{}", mac, vlanId, deviceId, port);
1024
Charles Chan57bd98c2016-02-22 19:27:29 -08001025 if (!deviceConfiguration.suppressHost()
Charles Chan43547ca2016-02-10 20:46:58 -08001026 .contains(new ConnectPoint(deviceId, port))) {
1027 // Revoke bridging table entry
1028 ForwardingObjective.Builder fob =
1029 getForwardingObjectiveBuilder(deviceId, mac, vlanId, port);
1030 flowObjectiveService.forward(deviceId, fob.remove(
1031 new BridgingTableObjectiveContext(mac, vlanId)
1032 ));
Charles Chanf4586112015-11-09 16:37:23 -08001033
Charles Chan43547ca2016-02-10 20:46:58 -08001034 // Revoke IP table entry
1035 ips.forEach(ip -> {
1036 if (ip.isIp4()) {
1037 routingRulePopulator.revokeIpRuleForHost(
1038 deviceId, ip.getIp4Address(), mac, port);
1039 }
1040 });
1041 }
Charles Chanf4586112015-11-09 16:37:23 -08001042 }
1043
1044 private void processHostMovedEvent(HostEvent event) {
1045 MacAddress mac = event.subject().mac();
1046 VlanId vlanId = event.subject().vlan();
1047 DeviceId prevDeviceId = event.prevSubject().location().deviceId();
1048 PortNumber prevPort = event.prevSubject().location().port();
1049 Set<IpAddress> prevIps = event.prevSubject().ipAddresses();
1050 DeviceId newDeviceId = event.subject().location().deviceId();
1051 PortNumber newPort = event.subject().location().port();
1052 Set<IpAddress> newIps = event.subject().ipAddresses();
1053 log.debug("Host {}/{} is moved from {}:{} to {}:{}",
1054 mac, vlanId, prevDeviceId, prevPort, newDeviceId, newPort);
1055
Charles Chan57bd98c2016-02-22 19:27:29 -08001056 if (!deviceConfiguration.suppressHost()
Charles Chan43547ca2016-02-10 20:46:58 -08001057 .contains(new ConnectPoint(prevDeviceId, prevPort))) {
1058 // Revoke previous bridging table entry
1059 ForwardingObjective.Builder prevFob =
1060 getForwardingObjectiveBuilder(prevDeviceId, mac, vlanId, prevPort);
1061 flowObjectiveService.forward(prevDeviceId, prevFob.remove(
1062 new BridgingTableObjectiveContext(mac, vlanId)
1063 ));
Charles Chanf4586112015-11-09 16:37:23 -08001064
Charles Chan43547ca2016-02-10 20:46:58 -08001065 // Revoke previous IP table entry
1066 prevIps.forEach(ip -> {
1067 if (ip.isIp4()) {
1068 routingRulePopulator.revokeIpRuleForHost(
1069 prevDeviceId, ip.getIp4Address(), mac, prevPort);
1070 }
1071 });
1072 }
Charles Chanf4586112015-11-09 16:37:23 -08001073
Charles Chan57bd98c2016-02-22 19:27:29 -08001074 if (!deviceConfiguration.suppressHost()
Charles Chan43547ca2016-02-10 20:46:58 -08001075 .contains(new ConnectPoint(newDeviceId, newPort))) {
1076 // Populate new bridging table entry
1077 ForwardingObjective.Builder newFob =
1078 getForwardingObjectiveBuilder(newDeviceId, mac, vlanId, newPort);
1079 flowObjectiveService.forward(newDeviceId, newFob.add(
1080 new BridgingTableObjectiveContext(mac, vlanId)
1081 ));
Charles Chanf4586112015-11-09 16:37:23 -08001082
Charles Chan43547ca2016-02-10 20:46:58 -08001083 // Populate new IP table entry
1084 newIps.forEach(ip -> {
1085 if (ip.isIp4()) {
1086 routingRulePopulator.populateIpRuleForHost(
1087 newDeviceId, ip.getIp4Address(), mac, newPort);
1088 }
1089 });
1090 }
Charles Chanf4586112015-11-09 16:37:23 -08001091 }
1092
1093 private void processHostUpdatedEvent(HostEvent event) {
1094 MacAddress mac = event.subject().mac();
1095 VlanId vlanId = event.subject().vlan();
1096 DeviceId prevDeviceId = event.prevSubject().location().deviceId();
1097 PortNumber prevPort = event.prevSubject().location().port();
1098 Set<IpAddress> prevIps = event.prevSubject().ipAddresses();
1099 DeviceId newDeviceId = event.subject().location().deviceId();
1100 PortNumber newPort = event.subject().location().port();
1101 Set<IpAddress> newIps = event.subject().ipAddresses();
1102 log.debug("Host {}/{} is updated", mac, vlanId);
1103
Charles Chan57bd98c2016-02-22 19:27:29 -08001104 if (!deviceConfiguration.suppressHost()
Charles Chan43547ca2016-02-10 20:46:58 -08001105 .contains(new ConnectPoint(prevDeviceId, prevPort))) {
1106 // 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 Chanf4586112015-11-09 16:37:23 -08001114
Charles Chan57bd98c2016-02-22 19:27:29 -08001115 if (!deviceConfiguration.suppressHost()
Charles Chan43547ca2016-02-10 20:46:58 -08001116 .contains(new ConnectPoint(newDeviceId, newPort))) {
1117 // 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 Chanf4586112015-11-09 16:37:23 -08001125 }
1126
1127 @Override
1128 public void event(HostEvent event) {
1129 // Do not proceed without mastership
1130 DeviceId deviceId = event.subject().location().deviceId();
1131 if (!mastershipService.isLocalMaster(deviceId)) {
1132 return;
1133 }
1134
1135 switch (event.type()) {
1136 case HOST_ADDED:
1137 processHostAddedEvent(event);
1138 break;
1139 case HOST_MOVED:
1140 processHostMovedEvent(event);
1141 break;
1142 case HOST_REMOVED:
1143 processHostRemoveEvent(event);
1144 break;
1145 case HOST_UPDATED:
1146 processHostUpdatedEvent(event);
1147 break;
1148 default:
1149 log.warn("Unsupported host event type: {}", event.type());
1150 break;
1151 }
1152 }
1153 }
1154
1155 private static class BridgingTableObjectiveContext implements ObjectiveContext {
1156 final MacAddress mac;
1157 final VlanId vlanId;
1158
1159 BridgingTableObjectiveContext(MacAddress mac, VlanId vlanId) {
1160 this.mac = mac;
1161 this.vlanId = vlanId;
1162 }
1163
1164 @Override
1165 public void onSuccess(Objective objective) {
1166 if (objective.op() == Objective.Operation.ADD) {
1167 log.debug("Successfully populate bridging table entry for {}/{}",
1168 mac, vlanId);
1169 } else {
1170 log.debug("Successfully revoke bridging table entry for {}/{}",
1171 mac, vlanId);
1172 }
1173 }
1174
1175 @Override
1176 public void onError(Objective objective, ObjectiveError error) {
1177 if (objective.op() == Objective.Operation.ADD) {
1178 log.debug("Fail to populate bridging table entry for {}/{}. {}",
1179 mac, vlanId, error);
1180 } else {
1181 log.debug("Fail to revoke bridging table entry for {}/{}. {}",
1182 mac, vlanId, error);
1183 }
1184 }
1185 }
sangho80f11cb2015-04-01 13:05:26 -07001186}