blob: 0f20451fdd2af034ed9191b48fc32abf6a8fe8f8 [file] [log] [blame]
sanghob35a6192015-04-01 13:05:26 -07001/*
2 * Copyright 2015 Open Networking Laboratory
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.onosproject.segmentrouting;
17
18import org.apache.felix.scr.annotations.Activate;
19import org.apache.felix.scr.annotations.Component;
20import org.apache.felix.scr.annotations.Deactivate;
21import org.apache.felix.scr.annotations.Reference;
22import org.apache.felix.scr.annotations.ReferenceCardinality;
sangho1e575652015-05-14 00:39:53 -070023import org.apache.felix.scr.annotations.Service;
sanghob35a6192015-04-01 13:05:26 -070024import org.onlab.packet.Ethernet;
Charles Chan68aa62d2015-11-09 16:37:23 -080025import org.onlab.packet.MacAddress;
Saurav Das0e99e2b2015-10-28 12:39:42 -070026import org.onlab.packet.VlanId;
Charles Chanc42e84e2015-10-20 16:24:19 -070027import org.onlab.packet.IPv4;
28import org.onlab.packet.Ip4Address;
29import org.onlab.packet.Ip4Prefix;
30import org.onlab.packet.IpAddress;
31import org.onlab.packet.IpPrefix;
Srikanth Vavilapalli23181912015-05-04 09:48:09 -070032import org.onlab.util.KryoNamespace;
sanghob35a6192015-04-01 13:05:26 -070033import org.onosproject.core.ApplicationId;
34import org.onosproject.core.CoreService;
35import org.onosproject.event.Event;
Charles Chanc42e84e2015-10-20 16:24:19 -070036import org.onosproject.net.ConnectPoint;
Charles Chan68aa62d2015-11-09 16:37:23 -080037import org.onosproject.net.PortNumber;
Charles Chand6832882015-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 Chan68aa62d2015-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 Chan188ebf52015-12-23 00:15:11 -080054import org.onosproject.net.packet.PacketPriority;
Charles Chan0b4e6182015-11-03 10:42:14 -080055import org.onosproject.segmentrouting.config.DeviceConfigNotFoundException;
56import org.onosproject.segmentrouting.config.DeviceConfiguration;
Charles Chand6832882015-10-05 17:50:33 -070057import org.onosproject.segmentrouting.config.SegmentRoutingConfig;
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -070058import org.onosproject.segmentrouting.grouphandler.DefaultGroupHandler;
59import org.onosproject.segmentrouting.grouphandler.NeighborSet;
Srikanth Vavilapalli23181912015-05-04 09:48:09 -070060import org.onosproject.segmentrouting.grouphandler.NeighborSetNextObjectiveStoreKey;
Saurav Das4ce45962015-11-24 23:21:05 -080061import org.onosproject.segmentrouting.grouphandler.PortNextObjectiveStoreKey;
sanghob35a6192015-04-01 13:05:26 -070062import org.onosproject.mastership.MastershipService;
63import org.onosproject.net.Device;
64import org.onosproject.net.DeviceId;
65import org.onosproject.net.Link;
sanghob35a6192015-04-01 13:05:26 -070066import org.onosproject.net.Port;
67import org.onosproject.net.device.DeviceEvent;
68import org.onosproject.net.device.DeviceListener;
69import org.onosproject.net.device.DeviceService;
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070070import org.onosproject.net.flowobjective.FlowObjectiveService;
sanghob35a6192015-04-01 13:05:26 -070071import org.onosproject.net.host.HostService;
72import org.onosproject.net.intent.IntentService;
73import 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;
80import org.onosproject.net.topology.TopologyService;
Charles Chanc42e84e2015-10-20 16:24:19 -070081import org.onosproject.segmentrouting.grouphandler.SubnetNextObjectiveStoreKey;
Srikanth Vavilapalli23181912015-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;
sanghob35a6192015-04-01 13:05:26 -070086import org.slf4j.Logger;
87import org.slf4j.LoggerFactory;
88
Srikanth Vavilapalli23181912015-05-04 09:48:09 -070089import java.net.URI;
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
sangho1e575652015-05-14 00:39:53 -0700103@Service
sanghob35a6192015-04-01 13:05:26 -0700104@Component(immediate = true)
sangho1e575652015-05-14 00:39:53 -0700105public class SegmentRoutingManager implements SegmentRoutingService {
sanghob35a6192015-04-01 13:05:26 -0700106
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700107 private static Logger log = LoggerFactory
108 .getLogger(SegmentRoutingManager.class);
sanghob35a6192015-04-01 13:05:26 -0700109
110 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
111 protected CoreService coreService;
112
113 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
114 protected TopologyService topologyService;
115
116 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
117 protected PacketService packetService;
118
119 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
120 protected IntentService intentService;
121
122 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
123 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
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700137 protected ArpHandler arpHandler = null;
138 protected IcmpHandler icmpHandler = null;
139 protected IpHandler ipHandler = null;
140 protected RoutingRulePopulator routingRulePopulator = null;
sanghob35a6192015-04-01 13:05:26 -0700141 protected ApplicationId appId;
sangho666cd6d2015-04-14 16:27:13 -0700142 protected DeviceConfiguration deviceConfiguration = null;
sanghob35a6192015-04-01 13:05:26 -0700143
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700144 private DefaultRoutingHandler defaultRoutingHandler = null;
sangho1e575652015-05-14 00:39:53 -0700145 private TunnelHandler tunnelHandler = null;
146 private PolicyHandler policyHandler = null;
Charles Chanb8e10c82015-10-14 11:24:40 -0700147 private InternalPacketProcessor processor = null;
148 private InternalLinkListener linkListener = null;
149 private InternalDeviceListener deviceListener = null;
sanghob35a6192015-04-01 13:05:26 -0700150 private InternalEventHandler eventHandler = new InternalEventHandler();
151
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700152 private ScheduledExecutorService executorService = Executors
153 .newScheduledThreadPool(1);
sanghob35a6192015-04-01 13:05:26 -0700154
Saurav Das4ce45962015-11-24 23:21:05 -0800155 @SuppressWarnings("unused")
sanghob35a6192015-04-01 13:05:26 -0700156 private static ScheduledFuture<?> eventHandlerFuture = null;
Saurav Das4ce45962015-11-24 23:21:05 -0800157 @SuppressWarnings("rawtypes")
sanghob35a6192015-04-01 13:05:26 -0700158 private ConcurrentLinkedQueue<Event> eventQueue = new ConcurrentLinkedQueue<Event>();
Charles Chan68aa62d2015-11-09 16:37:23 -0800159 private Map<DeviceId, DefaultGroupHandler> groupHandlerMap =
160 new ConcurrentHashMap<DeviceId, DefaultGroupHandler>();
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700161 // Per device next objective ID store with (device id + neighbor set) as key
Charles Chan68aa62d2015-11-09 16:37:23 -0800162 private EventuallyConsistentMap<NeighborSetNextObjectiveStoreKey, Integer>
163 nsNextObjStore = null;
Saurav Das4ce45962015-11-24 23:21:05 -0800164 // Per device next objective ID store with (device id + subnet) as key
Charles Chan68aa62d2015-11-09 16:37:23 -0800165 private EventuallyConsistentMap<SubnetNextObjectiveStoreKey, Integer>
166 subnetNextObjStore = null;
Saurav Das4ce45962015-11-24 23:21:05 -0800167 // Per device next objective ID store with (device id + port) as key
168 private EventuallyConsistentMap<PortNextObjectiveStoreKey, Integer>
169 portNextObjStore = null;
Saurav Das0e99e2b2015-10-28 12:39:42 -0700170 // Per device, per-subnet assigned-vlans store, with (device id + subnet
171 // IPv4 prefix) as key
172 private EventuallyConsistentMap<SubnetAssignedVidStoreKey, VlanId>
173 subnetVidStore = null;
Saurav Das4ce45962015-11-24 23:21:05 -0800174 private EventuallyConsistentMap<String, Tunnel> tunnelStore = null;
175 private EventuallyConsistentMap<String, Policy> policyStore = null;
sangho0b2b6d12015-05-20 22:16:38 -0700176
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700177 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
178 protected StorageService storageService;
sanghob35a6192015-04-01 13:05:26 -0700179
Charles Chand6832882015-10-05 17:50:33 -0700180 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
181 protected NetworkConfigRegistry cfgService;
182
Charles Chan4636be02015-10-07 14:21:45 -0700183 private final InternalConfigListener cfgListener =
184 new InternalConfigListener(this);
185
Saurav Das4ce45962015-11-24 23:21:05 -0800186 @SuppressWarnings({ "unchecked", "rawtypes" })
Charles Chand6832882015-10-05 17:50:33 -0700187 private final ConfigFactory cfgFactory =
188 new ConfigFactory(SubjectFactories.DEVICE_SUBJECT_FACTORY,
189 SegmentRoutingConfig.class,
190 "segmentrouting") {
191 @Override
192 public SegmentRoutingConfig createConfig() {
193 return new SegmentRoutingConfig();
194 }
195 };
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700196
Charles Chand6d581a2015-11-18 16:51:08 -0800197 private final InternalHostListener hostListener = new InternalHostListener();
Charles Chan68aa62d2015-11-09 16:37:23 -0800198
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700199 private Object threadSchedulerLock = new Object();
200 private static int numOfEventsQueued = 0;
201 private static int numOfEventsExecuted = 0;
sanghob35a6192015-04-01 13:05:26 -0700202 private static int numOfHandlerExecution = 0;
203 private static int numOfHandlerScheduled = 0;
204
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700205 private KryoNamespace.Builder kryoBuilder = null;
206
Saurav Das0e99e2b2015-10-28 12:39:42 -0700207 private static final short ASSIGNED_VLAN_START = 4093;
208 public static final short ASSIGNED_VLAN_NO_SUBNET = 4094;
209
sanghob35a6192015-04-01 13:05:26 -0700210 @Activate
211 protected void activate() {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700212 appId = coreService
213 .registerApplication("org.onosproject.segmentrouting");
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700214
215 kryoBuilder = new KryoNamespace.Builder()
216 .register(NeighborSetNextObjectiveStoreKey.class,
Charles Chanc42e84e2015-10-20 16:24:19 -0700217 SubnetNextObjectiveStoreKey.class,
218 SubnetAssignedVidStoreKey.class,
sangho0b2b6d12015-05-20 22:16:38 -0700219 NeighborSet.class,
220 DeviceId.class,
221 URI.class,
222 WallClockTimestamp.class,
223 org.onosproject.cluster.NodeId.class,
224 HashSet.class,
225 Tunnel.class,
226 DefaultTunnel.class,
227 Policy.class,
228 TunnelPolicy.class,
Saurav Das0e99e2b2015-10-28 12:39:42 -0700229 Policy.Type.class,
Charles Chanc42e84e2015-10-20 16:24:19 -0700230 VlanId.class,
231 Ip4Address.class,
232 Ip4Prefix.class,
233 IpAddress.Version.class,
234 ConnectPoint.class
sangho0b2b6d12015-05-20 22:16:38 -0700235 );
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700236
237 log.debug("Creating EC map nsnextobjectivestore");
238 EventuallyConsistentMapBuilder<NeighborSetNextObjectiveStoreKey, Integer>
239 nsNextObjMapBuilder = storageService.eventuallyConsistentMapBuilder();
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700240 nsNextObjStore = nsNextObjMapBuilder
241 .withName("nsnextobjectivestore")
242 .withSerializer(kryoBuilder)
Madan Jampanibcf1a482015-06-24 19:05:56 -0700243 .withTimestampProvider((k, v) -> new WallClockTimestamp())
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700244 .build();
245 log.trace("Current size {}", nsNextObjStore.size());
246
Charles Chanc42e84e2015-10-20 16:24:19 -0700247 log.debug("Creating EC map subnetnextobjectivestore");
248 EventuallyConsistentMapBuilder<SubnetNextObjectiveStoreKey, Integer>
249 subnetNextObjMapBuilder = storageService.eventuallyConsistentMapBuilder();
Charles Chanc42e84e2015-10-20 16:24:19 -0700250 subnetNextObjStore = subnetNextObjMapBuilder
251 .withName("subnetnextobjectivestore")
252 .withSerializer(kryoBuilder)
253 .withTimestampProvider((k, v) -> new WallClockTimestamp())
254 .build();
255
Saurav Das4ce45962015-11-24 23:21:05 -0800256 log.debug("Creating EC map subnetnextobjectivestore");
257 EventuallyConsistentMapBuilder<PortNextObjectiveStoreKey, Integer>
258 portNextObjMapBuilder = storageService.eventuallyConsistentMapBuilder();
259 portNextObjStore = portNextObjMapBuilder
260 .withName("portnextobjectivestore")
261 .withSerializer(kryoBuilder)
262 .withTimestampProvider((k, v) -> new WallClockTimestamp())
263 .build();
264
sangho0b2b6d12015-05-20 22:16:38 -0700265 EventuallyConsistentMapBuilder<String, Tunnel> tunnelMapBuilder =
266 storageService.eventuallyConsistentMapBuilder();
sangho0b2b6d12015-05-20 22:16:38 -0700267 tunnelStore = tunnelMapBuilder
268 .withName("tunnelstore")
269 .withSerializer(kryoBuilder)
Madan Jampanibcf1a482015-06-24 19:05:56 -0700270 .withTimestampProvider((k, v) -> new WallClockTimestamp())
sangho0b2b6d12015-05-20 22:16:38 -0700271 .build();
272
273 EventuallyConsistentMapBuilder<String, Policy> policyMapBuilder =
274 storageService.eventuallyConsistentMapBuilder();
sangho0b2b6d12015-05-20 22:16:38 -0700275 policyStore = policyMapBuilder
276 .withName("policystore")
277 .withSerializer(kryoBuilder)
Madan Jampanibcf1a482015-06-24 19:05:56 -0700278 .withTimestampProvider((k, v) -> new WallClockTimestamp())
sangho0b2b6d12015-05-20 22:16:38 -0700279 .build();
280
Saurav Das0e99e2b2015-10-28 12:39:42 -0700281 EventuallyConsistentMapBuilder<SubnetAssignedVidStoreKey, VlanId>
282 subnetVidStoreMapBuilder = storageService.eventuallyConsistentMapBuilder();
Saurav Das0e99e2b2015-10-28 12:39:42 -0700283 subnetVidStore = subnetVidStoreMapBuilder
284 .withName("subnetvidstore")
285 .withSerializer(kryoBuilder)
286 .withTimestampProvider((k, v) -> new WallClockTimestamp())
287 .build();
288
Charles Chand6832882015-10-05 17:50:33 -0700289 cfgService.addListener(cfgListener);
290 cfgService.registerConfigFactory(cfgFactory);
Charles Chand6832882015-10-05 17:50:33 -0700291
Charles Chan68aa62d2015-11-09 16:37:23 -0800292 hostService.addListener(hostListener);
293
Charles Chanb8e10c82015-10-14 11:24:40 -0700294 processor = new InternalPacketProcessor();
295 linkListener = new InternalLinkListener();
296 deviceListener = new InternalDeviceListener();
297
298 packetService.addProcessor(processor, PacketProcessor.director(2));
299 linkService.addListener(linkListener);
300 deviceService.addListener(deviceListener);
301
Charles Chan188ebf52015-12-23 00:15:11 -0800302 // Request ARP packet-in
303 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
304 selector.matchEthType(Ethernet.TYPE_ARP);
305 packetService.requestPackets(selector.build(), PacketPriority.CONTROL, appId, Optional.empty());
306
Charles Chanb8e10c82015-10-14 11:24:40 -0700307 cfgListener.configureNetwork();
308
sanghob35a6192015-04-01 13:05:26 -0700309 log.info("Started");
310 }
311
312 @Deactivate
313 protected void deactivate() {
Charles Chand6832882015-10-05 17:50:33 -0700314 cfgService.removeListener(cfgListener);
315 cfgService.unregisterConfigFactory(cfgFactory);
316
Charles Chan188ebf52015-12-23 00:15:11 -0800317 // Withdraw ARP packet-in
318 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
319 selector.matchEthType(Ethernet.TYPE_ARP);
320 packetService.cancelPackets(selector.build(), PacketPriority.CONTROL, appId, Optional.empty());
321
sanghob35a6192015-04-01 13:05:26 -0700322 packetService.removeProcessor(processor);
Charles Chanb8e10c82015-10-14 11:24:40 -0700323 linkService.removeListener(linkListener);
324 deviceService.removeListener(deviceListener);
sanghob35a6192015-04-01 13:05:26 -0700325 processor = null;
Charles Chanb8e10c82015-10-14 11:24:40 -0700326 linkListener = null;
327 deviceService = null;
328
329 groupHandlerMap.clear();
330
sanghob35a6192015-04-01 13:05:26 -0700331 log.info("Stopped");
332 }
333
sangho1e575652015-05-14 00:39:53 -0700334
335 @Override
336 public List<Tunnel> getTunnels() {
337 return tunnelHandler.getTunnels();
338 }
339
340 @Override
sangho71abe1b2015-06-29 14:58:47 -0700341 public TunnelHandler.Result createTunnel(Tunnel tunnel) {
342 return tunnelHandler.createTunnel(tunnel);
sangho1e575652015-05-14 00:39:53 -0700343 }
344
345 @Override
sangho71abe1b2015-06-29 14:58:47 -0700346 public TunnelHandler.Result removeTunnel(Tunnel tunnel) {
sangho1e575652015-05-14 00:39:53 -0700347 for (Policy policy: policyHandler.getPolicies()) {
348 if (policy.type() == Policy.Type.TUNNEL_FLOW) {
349 TunnelPolicy tunnelPolicy = (TunnelPolicy) policy;
350 if (tunnelPolicy.tunnelId().equals(tunnel.id())) {
351 log.warn("Cannot remove the tunnel used by a policy");
sangho71abe1b2015-06-29 14:58:47 -0700352 return TunnelHandler.Result.TUNNEL_IN_USE;
sangho1e575652015-05-14 00:39:53 -0700353 }
354 }
355 }
sangho71abe1b2015-06-29 14:58:47 -0700356 return tunnelHandler.removeTunnel(tunnel);
sangho1e575652015-05-14 00:39:53 -0700357 }
358
359 @Override
sangho71abe1b2015-06-29 14:58:47 -0700360 public PolicyHandler.Result removePolicy(Policy policy) {
361 return policyHandler.removePolicy(policy);
sangho1e575652015-05-14 00:39:53 -0700362 }
363
364 @Override
sangho71abe1b2015-06-29 14:58:47 -0700365 public PolicyHandler.Result createPolicy(Policy policy) {
366 return policyHandler.createPolicy(policy);
sangho1e575652015-05-14 00:39:53 -0700367 }
368
369 @Override
370 public List<Policy> getPolicies() {
371 return policyHandler.getPolicies();
372 }
373
sanghof9d0bf12015-05-19 11:57:42 -0700374 /**
375 * Returns the tunnel object with the tunnel ID.
376 *
377 * @param tunnelId Tunnel ID
378 * @return Tunnel reference
379 */
sangho1e575652015-05-14 00:39:53 -0700380 public Tunnel getTunnel(String tunnelId) {
381 return tunnelHandler.getTunnel(tunnelId);
382 }
383
sanghob35a6192015-04-01 13:05:26 -0700384 /**
Saurav Das0e99e2b2015-10-28 12:39:42 -0700385 * Returns the vlan-id assigned to the subnet configured for a device.
386 * If no vlan-id has been assigned, a new one is assigned out of a pool of ids,
387 * if and only if this controller instance is the master for the device.
388 * <p>
389 * USAGE: The assigned vlans are meant to be applied to untagged packets on those
390 * switches/pipelines that need this functionality. These vids are meant
391 * to be used internally within a switch, and thus need to be unique only
392 * on a switch level. Note that packets never go out on the wire with these
393 * vlans. Currently, vlan ids are assigned from value 4093 down.
394 * Vlan id 4094 expected to be used for all ports that are not assigned subnets.
395 * Vlan id 4095 is reserved and unused. Only a single vlan id is assigned
396 * per subnet.
397 * XXX This method should avoid any vlans configured on the ports, but
398 * currently the app works only on untagged packets and as a result
399 * ignores any vlan configuration.
sanghob35a6192015-04-01 13:05:26 -0700400 *
Saurav Das0e99e2b2015-10-28 12:39:42 -0700401 * @param deviceId switch dpid
402 * @param subnet IPv4 prefix for which assigned vlan is desired
403 * @return VlanId assigned for the subnet on the device, or
404 * null if no vlan assignment was found and this instance is not
405 * the master for the device.
sanghob35a6192015-04-01 13:05:26 -0700406 */
Saurav Das0e99e2b2015-10-28 12:39:42 -0700407 public VlanId getSubnetAssignedVlanId(DeviceId deviceId, Ip4Prefix subnet) {
408 VlanId assignedVid = subnetVidStore.get(new SubnetAssignedVidStoreKey(
409 deviceId, subnet));
410 if (assignedVid != null) {
411 log.debug("Query for subnet:{} on device:{} returned assigned-vlan "
412 + "{}", subnet, deviceId, assignedVid);
413 return assignedVid;
414 }
415 //check mastership for the right to assign a vlan
416 if (!mastershipService.isLocalMaster(deviceId)) {
417 log.warn("This controller instance is not the master for device {}. "
418 + "Cannot assign vlan-id for subnet {}", deviceId, subnet);
419 return null;
420 }
421 // vlan assignment is expensive but done only once
Charles Chan9f676b62015-10-29 14:58:10 -0700422 Set<Ip4Prefix> configuredSubnets = deviceConfiguration.getSubnets(deviceId);
Saurav Das0e99e2b2015-10-28 12:39:42 -0700423 Set<Short> assignedVlans = new HashSet<>();
424 Set<Ip4Prefix> unassignedSubnets = new HashSet<>();
425 for (Ip4Prefix sub : configuredSubnets) {
426 VlanId v = subnetVidStore.get(new SubnetAssignedVidStoreKey(deviceId,
427 sub));
428 if (v != null) {
429 assignedVlans.add(v.toShort());
430 } else {
431 unassignedSubnets.add(sub);
432 }
433 }
434 short nextAssignedVlan = ASSIGNED_VLAN_START;
435 if (!assignedVlans.isEmpty()) {
436 nextAssignedVlan = (short) (Collections.min(assignedVlans) - 1);
437 }
438 for (Ip4Prefix unsub : unassignedSubnets) {
439 subnetVidStore.put(new SubnetAssignedVidStoreKey(deviceId, unsub),
440 VlanId.vlanId(nextAssignedVlan--));
441 log.info("Assigned vlan: {} to subnet: {} on device: {}",
442 nextAssignedVlan + 1, unsub, deviceId);
sanghob35a6192015-04-01 13:05:26 -0700443 }
444
Saurav Das0e99e2b2015-10-28 12:39:42 -0700445 return subnetVidStore.get(new SubnetAssignedVidStoreKey(deviceId, subnet));
sanghob35a6192015-04-01 13:05:26 -0700446 }
447
sangho1e575652015-05-14 00:39:53 -0700448 /**
Saurav Das0e99e2b2015-10-28 12:39:42 -0700449 * Returns the next objective ID for the given NeighborSet.
Saurav Das8a0732e2015-11-20 15:27:53 -0800450 * If the nextObjective does not exist, a new one is created and
Saurav Das4ce45962015-11-24 23:21:05 -0800451 * its id is returned.
sangho1e575652015-05-14 00:39:53 -0700452 *
sanghof9d0bf12015-05-19 11:57:42 -0700453 * @param deviceId Device ID
454 * @param ns NegighborSet
Saurav Das8a0732e2015-11-20 15:27:53 -0800455 * @param meta metadata passed into the creation of a Next Objective
456 * @return next objective ID or -1 if an error was encountered during the
457 * creation of the nextObjective
sangho1e575652015-05-14 00:39:53 -0700458 */
Saurav Das8a0732e2015-11-20 15:27:53 -0800459 public int getNextObjectiveId(DeviceId deviceId, NeighborSet ns,
460 TrafficSelector meta) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700461 if (groupHandlerMap.get(deviceId) != null) {
462 log.trace("getNextObjectiveId query in device {}", deviceId);
463 return groupHandlerMap
Saurav Das8a0732e2015-11-20 15:27:53 -0800464 .get(deviceId).getNextObjectiveId(ns, meta);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700465 } else {
Saurav Das4ce45962015-11-24 23:21:05 -0800466 log.warn("getNextObjectiveId query - groupHandler for device {} "
467 + "not found", deviceId);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700468 return -1;
469 }
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700470 }
471
Charles Chanc42e84e2015-10-20 16:24:19 -0700472 /**
Saurav Das4ce45962015-11-24 23:21:05 -0800473 * Returns the next objective ID for the given subnet prefix. It is expected
474 * that the next-objective has been pre-created from configuration.
Charles Chanc42e84e2015-10-20 16:24:19 -0700475 *
476 * @param deviceId Device ID
477 * @param prefix Subnet
Saurav Das4ce45962015-11-24 23:21:05 -0800478 * @return next objective ID or -1 if it was not found
Charles Chanc42e84e2015-10-20 16:24:19 -0700479 */
480 public int getSubnetNextObjectiveId(DeviceId deviceId, IpPrefix prefix) {
481 if (groupHandlerMap.get(deviceId) != null) {
482 log.trace("getSubnetNextObjectiveId query in device {}", deviceId);
483 return groupHandlerMap
484 .get(deviceId).getSubnetNextObjectiveId(prefix);
485 } else {
Saurav Das4ce45962015-11-24 23:21:05 -0800486 log.warn("getSubnetNextObjectiveId query - groupHandler for "
487 + "device {} not found", deviceId);
488 return -1;
489 }
490 }
491
492 /**
493 * Returns the next objective ID for the given portNumber, given the treatment.
494 * There could be multiple different treatments to the same outport, which
495 * would result in different objectives. If the next object
496 * does not exist, a new one is created and its id is returned.
497 *
498 * @param deviceId Device ID
499 * @param portNum port number on device for which NextObjective is queried
500 * @param treatment the actions to apply on the packets (should include outport)
501 * @param meta metadata passed into the creation of a Next Objective if necessary
502 * @return next objective ID or -1 if it was not found
503 */
504 public int getPortNextObjectiveId(DeviceId deviceId, PortNumber portNum,
505 TrafficTreatment treatment,
506 TrafficSelector meta) {
507 DefaultGroupHandler ghdlr = groupHandlerMap.get(deviceId);
508 if (ghdlr != null) {
509 return ghdlr.getPortNextObjectiveId(portNum, treatment, meta);
510 } else {
511 log.warn("getPortNextObjectiveId query - groupHandler for device {}"
512 + " not found", deviceId);
Charles Chanc42e84e2015-10-20 16:24:19 -0700513 return -1;
514 }
515 }
516
sanghob35a6192015-04-01 13:05:26 -0700517 private class InternalPacketProcessor implements PacketProcessor {
sanghob35a6192015-04-01 13:05:26 -0700518 @Override
519 public void process(PacketContext context) {
520
521 if (context.isHandled()) {
522 return;
523 }
524
525 InboundPacket pkt = context.inPacket();
526 Ethernet ethernet = pkt.parsed();
Saurav Das4ce45962015-11-24 23:21:05 -0800527 log.trace("Rcvd pktin: {}", ethernet);
sanghob35a6192015-04-01 13:05:26 -0700528 if (ethernet.getEtherType() == Ethernet.TYPE_ARP) {
529 arpHandler.processPacketIn(pkt);
530 } else if (ethernet.getEtherType() == Ethernet.TYPE_IPV4) {
531 IPv4 ipPacket = (IPv4) ethernet.getPayload();
532 ipHandler.addToPacketBuffer(ipPacket);
533 if (ipPacket.getProtocol() == IPv4.PROTOCOL_ICMP) {
534 icmpHandler.processPacketIn(pkt);
535 } else {
536 ipHandler.processPacketIn(pkt);
537 }
538 }
539 }
540 }
541
542 private class InternalLinkListener implements LinkListener {
543 @Override
544 public void event(LinkEvent event) {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700545 if (event.type() == LinkEvent.Type.LINK_ADDED
546 || event.type() == LinkEvent.Type.LINK_REMOVED) {
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700547 log.debug("Event {} received from Link Service", event.type());
sanghob35a6192015-04-01 13:05:26 -0700548 scheduleEventHandlerIfNotScheduled(event);
549 }
550 }
551 }
552
553 private class InternalDeviceListener implements DeviceListener {
sanghob35a6192015-04-01 13:05:26 -0700554 @Override
555 public void event(DeviceEvent event) {
sanghob35a6192015-04-01 13:05:26 -0700556 switch (event.type()) {
557 case DEVICE_ADDED:
558 case PORT_REMOVED:
sangho20eff1d2015-04-13 15:15:58 -0700559 case DEVICE_UPDATED:
560 case DEVICE_AVAILABILITY_CHANGED:
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700561 log.debug("Event {} received from Device Service", event.type());
sanghob35a6192015-04-01 13:05:26 -0700562 scheduleEventHandlerIfNotScheduled(event);
563 break;
564 default:
565 }
566 }
567 }
568
Saurav Das4ce45962015-11-24 23:21:05 -0800569 @SuppressWarnings("rawtypes")
sanghob35a6192015-04-01 13:05:26 -0700570 private void scheduleEventHandlerIfNotScheduled(Event event) {
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700571 synchronized (threadSchedulerLock) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700572 eventQueue.add(event);
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700573 numOfEventsQueued++;
574
575 if ((numOfHandlerScheduled - numOfHandlerExecution) == 0) {
576 //No pending scheduled event handling threads. So start a new one.
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700577 eventHandlerFuture = executorService
578 .schedule(eventHandler, 100, TimeUnit.MILLISECONDS);
579 numOfHandlerScheduled++;
580 }
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700581 log.trace("numOfEventsQueued {}, numOfEventHanlderScheduled {}",
582 numOfEventsQueued,
583 numOfHandlerScheduled);
sanghob35a6192015-04-01 13:05:26 -0700584 }
sanghob35a6192015-04-01 13:05:26 -0700585 }
586
587 private class InternalEventHandler implements Runnable {
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700588 @Override
sanghob35a6192015-04-01 13:05:26 -0700589 public void run() {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700590 try {
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700591 while (true) {
Saurav Das4ce45962015-11-24 23:21:05 -0800592 @SuppressWarnings("rawtypes")
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700593 Event event = null;
594 synchronized (threadSchedulerLock) {
595 if (!eventQueue.isEmpty()) {
596 event = eventQueue.poll();
597 numOfEventsExecuted++;
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700598 } else {
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700599 numOfHandlerExecution++;
600 log.debug("numOfHandlerExecution {} numOfEventsExecuted {}",
601 numOfHandlerExecution, numOfEventsExecuted);
602 break;
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700603 }
sangho20eff1d2015-04-13 15:15:58 -0700604 }
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700605 if (event.type() == LinkEvent.Type.LINK_ADDED) {
606 processLinkAdded((Link) event.subject());
607 } else if (event.type() == LinkEvent.Type.LINK_REMOVED) {
608 processLinkRemoved((Link) event.subject());
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700609 } else if (event.type() == DeviceEvent.Type.DEVICE_ADDED ||
610 event.type() == DeviceEvent.Type.DEVICE_AVAILABILITY_CHANGED ||
611 event.type() == DeviceEvent.Type.DEVICE_UPDATED) {
Saurav Das423fe2b2015-12-04 10:52:59 -0800612 DeviceId deviceId = ((Device) event.subject()).id();
613 if (deviceService.isAvailable(deviceId)) {
Saurav Das837e0bb2015-10-30 17:45:38 -0700614 log.info("Processing device event {} for available device {}",
615 event.type(), ((Device) event.subject()).id());
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700616 processDeviceAdded((Device) event.subject());
Saurav Das423fe2b2015-12-04 10:52:59 -0800617 } /* else {
618 if (event.type() == DeviceEvent.Type.DEVICE_AVAILABILITY_CHANGED) {
619 // availability changed and not available - dev gone
620 DefaultGroupHandler groupHandler = groupHandlerMap.get(deviceId);
621 if (groupHandler != null) {
622 groupHandler.removeAllGroups();
623 }
624 }
625 }*/
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700626 } else if (event.type() == DeviceEvent.Type.PORT_REMOVED) {
627 processPortRemoved((Device) event.subject(),
628 ((DeviceEvent) event).port());
629 } else {
630 log.warn("Unhandled event type: {}", event.type());
631 }
sanghob35a6192015-04-01 13:05:26 -0700632 }
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700633 } catch (Exception e) {
634 log.error("SegmentRouting event handler "
635 + "thread thrown an exception: {}", e);
sanghob35a6192015-04-01 13:05:26 -0700636 }
sanghob35a6192015-04-01 13:05:26 -0700637 }
638 }
639
sanghob35a6192015-04-01 13:05:26 -0700640 private void processLinkAdded(Link link) {
641 log.debug("A new link {} was added", link.toString());
Charles Chan0b4e6182015-11-03 10:42:14 -0800642 if (!deviceConfiguration.isConfigured(link.src().deviceId())) {
643 log.warn("Source device of this link is not configured.");
644 return;
645 }
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700646 //Irrespective whether the local is a MASTER or not for this device,
647 //create group handler instance and push default TTP flow rules.
648 //Because in a multi-instance setup, instances can initiate
649 //groups for any devices. Also the default TTP rules are needed
650 //to be pushed before inserting any IP table entries for any device
651 DefaultGroupHandler groupHandler = groupHandlerMap.get(link.src()
652 .deviceId());
653 if (groupHandler != null) {
Saurav Das8a0732e2015-11-20 15:27:53 -0800654 groupHandler.linkUp(link, mastershipService.isLocalMaster(
655 link.src().deviceId()));
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700656 } else {
657 Device device = deviceService.getDevice(link.src().deviceId());
658 if (device != null) {
659 log.warn("processLinkAdded: Link Added "
660 + "Notification without Device Added "
661 + "event, still handling it");
662 processDeviceAdded(device);
663 groupHandler = groupHandlerMap.get(link.src()
664 .deviceId());
Saurav Das8a0732e2015-11-20 15:27:53 -0800665 groupHandler.linkUp(link, mastershipService.isLocalMaster(device.id()));
sanghob35a6192015-04-01 13:05:26 -0700666 }
667 }
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700668
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700669 log.trace("Starting optimized route population process");
670 defaultRoutingHandler.populateRoutingRulesForLinkStatusChange(null);
671 //log.trace("processLinkAdded: re-starting route population process");
672 //defaultRoutingHandler.startPopulationProcess();
sanghob35a6192015-04-01 13:05:26 -0700673 }
674
675 private void processLinkRemoved(Link link) {
676 log.debug("A link {} was removed", link.toString());
sangho834e4b02015-05-01 09:38:25 -0700677 DefaultGroupHandler groupHandler = groupHandlerMap.get(link.src().deviceId());
678 if (groupHandler != null) {
Saurav Das423fe2b2015-12-04 10:52:59 -0800679 groupHandler.portDown(link.src().port(),
680 mastershipService.isLocalMaster(link.src().deviceId()));
sangho834e4b02015-05-01 09:38:25 -0700681 }
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700682 log.trace("Starting optimized route population process");
683 defaultRoutingHandler.populateRoutingRulesForLinkStatusChange(link);
684 //log.trace("processLinkRemoved: re-starting route population process");
685 //defaultRoutingHandler.startPopulationProcess();
sanghob35a6192015-04-01 13:05:26 -0700686 }
687
688 private void processDeviceAdded(Device device) {
689 log.debug("A new device with ID {} was added", device.id());
Charles Chan0b4e6182015-11-03 10:42:14 -0800690 if (deviceConfiguration == null || !deviceConfiguration.isConfigured(device.id())) {
Saurav Das2857f382015-11-03 14:39:27 -0800691 log.warn("Device configuration uploading. Device {} will be "
692 + "processed after config completes.", device.id());
693 return;
694 }
Saurav Das837e0bb2015-10-30 17:45:38 -0700695 // Irrespective of whether the local is a MASTER or not for this device,
696 // we need to create a SR-group-handler instance. This is because in a
697 // multi-instance setup, any instance can initiate forwarding/next-objectives
698 // for any switch (even if this instance is a SLAVE or not even connected
699 // to the switch). To handle this, a default-group-handler instance is necessary
700 // per switch.
Saurav Das2857f382015-11-03 14:39:27 -0800701 if (groupHandlerMap.get(device.id()) == null) {
Charles Chan0b4e6182015-11-03 10:42:14 -0800702 DefaultGroupHandler groupHandler;
703 try {
704 groupHandler = DefaultGroupHandler.
705 createGroupHandler(device.id(),
706 appId,
707 deviceConfiguration,
708 linkService,
709 flowObjectiveService,
710 nsNextObjStore,
Saurav Das4ce45962015-11-24 23:21:05 -0800711 subnetNextObjStore,
Charles Chan188ebf52015-12-23 00:15:11 -0800712 portNextObjStore,
713 this);
Charles Chan0b4e6182015-11-03 10:42:14 -0800714 } catch (DeviceConfigNotFoundException e) {
715 log.warn(e.getMessage() + " Aborting processDeviceAdded.");
716 return;
717 }
Saurav Das2857f382015-11-03 14:39:27 -0800718 groupHandlerMap.put(device.id(), groupHandler);
719 // Also, in some cases, drivers may need extra
720 // information to process rules (eg. Router IP/MAC); and so, we send
721 // port addressing rules to the driver as well irrespective of whether
722 // this instance is the master or not.
723 defaultRoutingHandler.populatePortAddressingRules(device.id());
Charles Chand6d581a2015-11-18 16:51:08 -0800724 hostListener.readInitialHosts();
Saurav Das2857f382015-11-03 14:39:27 -0800725 }
Charles Chanc42e84e2015-10-20 16:24:19 -0700726 if (mastershipService.isLocalMaster(device.id())) {
Saurav Das2857f382015-11-03 14:39:27 -0800727 DefaultGroupHandler groupHandler = groupHandlerMap.get(device.id());
Charles Chanc42e84e2015-10-20 16:24:19 -0700728 groupHandler.createGroupsFromSubnetConfig();
Charles Chan68aa62d2015-11-09 16:37:23 -0800729 routingRulePopulator.populateSubnetBroadcastRule(device.id());
Charles Chanc42e84e2015-10-20 16:24:19 -0700730 }
sanghob35a6192015-04-01 13:05:26 -0700731 }
732
733 private void processPortRemoved(Device device, Port port) {
734 log.debug("Port {} was removed", port.toString());
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700735 DefaultGroupHandler groupHandler = groupHandlerMap.get(device.id());
sanghob35a6192015-04-01 13:05:26 -0700736 if (groupHandler != null) {
Saurav Das423fe2b2015-12-04 10:52:59 -0800737 groupHandler.portDown(port.number(),
738 mastershipService.isLocalMaster(device.id()));
sanghob35a6192015-04-01 13:05:26 -0700739 }
740 }
sangho1e575652015-05-14 00:39:53 -0700741
Charles Chand6832882015-10-05 17:50:33 -0700742 private class InternalConfigListener implements NetworkConfigListener {
Charles Chan4636be02015-10-07 14:21:45 -0700743 SegmentRoutingManager segmentRoutingManager;
744
745 public InternalConfigListener(SegmentRoutingManager srMgr) {
746 this.segmentRoutingManager = srMgr;
747 }
748
749 public void configureNetwork() {
750 deviceConfiguration = new DeviceConfiguration(segmentRoutingManager.cfgService);
751
752 arpHandler = new ArpHandler(segmentRoutingManager);
753 icmpHandler = new IcmpHandler(segmentRoutingManager);
754 ipHandler = new IpHandler(segmentRoutingManager);
755 routingRulePopulator = new RoutingRulePopulator(segmentRoutingManager);
756 defaultRoutingHandler = new DefaultRoutingHandler(segmentRoutingManager);
757
758 tunnelHandler = new TunnelHandler(linkService, deviceConfiguration,
759 groupHandlerMap, tunnelStore);
760 policyHandler = new PolicyHandler(appId, deviceConfiguration,
761 flowObjectiveService,
762 tunnelHandler, policyStore);
763
Charles Chan4636be02015-10-07 14:21:45 -0700764 for (Device device : deviceService.getDevices()) {
Saurav Das837e0bb2015-10-30 17:45:38 -0700765 // Irrespective of whether the local is a MASTER or not for this device,
766 // we need to create a SR-group-handler instance. This is because in a
767 // multi-instance setup, any instance can initiate forwarding/next-objectives
768 // for any switch (even if this instance is a SLAVE or not even connected
769 // to the switch). To handle this, a default-group-handler instance is necessary
770 // per switch.
Saurav Das2857f382015-11-03 14:39:27 -0800771 if (groupHandlerMap.get(device.id()) == null) {
Charles Chan0b4e6182015-11-03 10:42:14 -0800772 DefaultGroupHandler groupHandler;
773 try {
774 groupHandler = DefaultGroupHandler.
775 createGroupHandler(device.id(),
776 appId,
777 deviceConfiguration,
778 linkService,
779 flowObjectiveService,
780 nsNextObjStore,
Saurav Das4ce45962015-11-24 23:21:05 -0800781 subnetNextObjStore,
Charles Chan188ebf52015-12-23 00:15:11 -0800782 portNextObjStore,
783 segmentRoutingManager);
Charles Chan0b4e6182015-11-03 10:42:14 -0800784 } catch (DeviceConfigNotFoundException e) {
785 log.warn(e.getMessage() + " Aborting configureNetwork.");
786 return;
787 }
Saurav Das2857f382015-11-03 14:39:27 -0800788 groupHandlerMap.put(device.id(), groupHandler);
Saurav Das837e0bb2015-10-30 17:45:38 -0700789
Saurav Das2857f382015-11-03 14:39:27 -0800790 // Also, in some cases, drivers may need extra
791 // information to process rules (eg. Router IP/MAC); and so, we send
792 // port addressing rules to the driver as well, irrespective of whether
793 // this instance is the master or not.
794 defaultRoutingHandler.populatePortAddressingRules(device.id());
Charles Chand6d581a2015-11-18 16:51:08 -0800795 hostListener.readInitialHosts();
Saurav Das2857f382015-11-03 14:39:27 -0800796 }
Charles Chanc42e84e2015-10-20 16:24:19 -0700797 if (mastershipService.isLocalMaster(device.id())) {
Saurav Das2857f382015-11-03 14:39:27 -0800798 DefaultGroupHandler groupHandler = groupHandlerMap.get(device.id());
Charles Chanc42e84e2015-10-20 16:24:19 -0700799 groupHandler.createGroupsFromSubnetConfig();
Charles Chan68aa62d2015-11-09 16:37:23 -0800800 routingRulePopulator.populateSubnetBroadcastRule(device.id());
Charles Chanc42e84e2015-10-20 16:24:19 -0700801 }
Charles Chan4636be02015-10-07 14:21:45 -0700802 }
803
804 defaultRoutingHandler.startPopulationProcess();
805 }
806
Charles Chand6832882015-10-05 17:50:33 -0700807 @Override
808 public void event(NetworkConfigEvent event) {
Charles Chanb8e10c82015-10-14 11:24:40 -0700809 if (event.configClass().equals(SegmentRoutingConfig.class)) {
810 if (event.type() == NetworkConfigEvent.Type.CONFIG_ADDED) {
811 log.info("Network configuration added.");
812 configureNetwork();
813 }
814 if (event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED) {
815 log.info("Network configuration updated.");
816 // TODO support dynamic configuration
817 }
Charles Chand6832882015-10-05 17:50:33 -0700818 }
819 }
820 }
Charles Chan68aa62d2015-11-09 16:37:23 -0800821
Charles Chand6d581a2015-11-18 16:51:08 -0800822 // TODO Move bridging table population to a separate class
Charles Chan68aa62d2015-11-09 16:37:23 -0800823 private class InternalHostListener implements HostListener {
Charles Chand6d581a2015-11-18 16:51:08 -0800824 private void readInitialHosts() {
825 hostService.getHosts().forEach(host -> {
826 MacAddress mac = host.mac();
827 VlanId vlanId = host.vlan();
828 DeviceId deviceId = host.location().deviceId();
829 PortNumber port = host.location().port();
830 Set<IpAddress> ips = host.ipAddresses();
831 log.debug("Host {}/{} is added at {}:{}", mac, vlanId, deviceId, port);
832
833 // Populate bridging table entry
834 ForwardingObjective.Builder fob =
Saurav Das4ce45962015-11-24 23:21:05 -0800835 getForwardingObjectiveBuilder(deviceId, mac, vlanId, port);
Charles Chand6d581a2015-11-18 16:51:08 -0800836 flowObjectiveService.forward(deviceId, fob.add(
837 new BridgingTableObjectiveContext(mac, vlanId)
838 ));
839
840 // Populate IP table entry
841 ips.forEach(ip -> {
842 if (ip.isIp4()) {
843 routingRulePopulator.populateIpRuleForHost(
844 deviceId, ip.getIp4Address(), mac, port);
845 }
846 });
847 });
848 }
849
Charles Chan68aa62d2015-11-09 16:37:23 -0800850 private ForwardingObjective.Builder getForwardingObjectiveBuilder(
Saurav Das4ce45962015-11-24 23:21:05 -0800851 DeviceId deviceId, MacAddress mac, VlanId vlanId,
852 PortNumber outport) {
Charles Chan188ebf52015-12-23 00:15:11 -0800853 // Get assigned VLAN for the subnet
Saurav Das4ce45962015-11-24 23:21:05 -0800854 VlanId outvlan = null;
855 Ip4Prefix subnet = deviceConfiguration.getPortSubnet(deviceId, outport);
856 if (subnet == null) {
857 outvlan = VlanId.vlanId(ASSIGNED_VLAN_NO_SUBNET);
858 } else {
859 outvlan = getSubnetAssignedVlanId(deviceId, subnet);
860 }
Charles Chan188ebf52015-12-23 00:15:11 -0800861
862 // match rule
863 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
864 sbuilder.matchEthDst(mac);
865 /*
866 * Note: for untagged packets, match on the assigned VLAN.
867 * for tagged packets, match on its incoming VLAN.
868 */
869 if (vlanId.equals(VlanId.NONE)) {
870 sbuilder.matchVlanId(outvlan);
871 } else {
872 sbuilder.matchVlanId(vlanId);
873 }
874
875 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
876 tbuilder.immediate().popVlan();
877 tbuilder.immediate().setOutput(outport);
878
879 // for switch pipelines that need it, provide outgoing vlan as metadata
Saurav Das4ce45962015-11-24 23:21:05 -0800880 TrafficSelector meta = DefaultTrafficSelector.builder()
881 .matchVlanId(outvlan).build();
882
883 // All forwarding is via Groups. Drivers can re-purpose to flow-actions if needed.
884 int portNextObjId = getPortNextObjectiveId(deviceId, outport,
885 tbuilder.build(),
886 meta);
Charles Chan68aa62d2015-11-09 16:37:23 -0800887
888 return DefaultForwardingObjective.builder()
889 .withFlag(ForwardingObjective.Flag.SPECIFIC)
890 .withSelector(sbuilder.build())
Saurav Das4ce45962015-11-24 23:21:05 -0800891 .nextStep(portNextObjId)
Charles Chan68aa62d2015-11-09 16:37:23 -0800892 .withPriority(100)
893 .fromApp(appId)
894 .makePermanent();
895 }
896
897 private void processHostAddedEvent(HostEvent event) {
898 MacAddress mac = event.subject().mac();
899 VlanId vlanId = event.subject().vlan();
900 DeviceId deviceId = event.subject().location().deviceId();
901 PortNumber port = event.subject().location().port();
902 Set<IpAddress> ips = event.subject().ipAddresses();
Saurav Das4ce45962015-11-24 23:21:05 -0800903 log.info("Host {}/{} is added at {}:{}", mac, vlanId, deviceId, port);
Charles Chan68aa62d2015-11-09 16:37:23 -0800904
Charles Chan68aa62d2015-11-09 16:37:23 -0800905 // Populate bridging table entry
Saurav Das4ce45962015-11-24 23:21:05 -0800906 log.debug("Populate L2 table entry for host {} at {}:{}",
907 mac, deviceId, port);
Charles Chan68aa62d2015-11-09 16:37:23 -0800908 ForwardingObjective.Builder fob =
Saurav Das4ce45962015-11-24 23:21:05 -0800909 getForwardingObjectiveBuilder(deviceId, mac, vlanId, port);
Charles Chan68aa62d2015-11-09 16:37:23 -0800910 flowObjectiveService.forward(deviceId, fob.add(
911 new BridgingTableObjectiveContext(mac, vlanId)
912 ));
913
914 // Populate IP table entry
915 ips.forEach(ip -> {
916 if (ip.isIp4()) {
917 routingRulePopulator.populateIpRuleForHost(
918 deviceId, ip.getIp4Address(), mac, port);
919 }
920 });
921 }
922
923 private void processHostRemoveEvent(HostEvent event) {
924 MacAddress mac = event.subject().mac();
925 VlanId vlanId = event.subject().vlan();
926 DeviceId deviceId = event.subject().location().deviceId();
927 PortNumber port = event.subject().location().port();
928 Set<IpAddress> ips = event.subject().ipAddresses();
929 log.debug("Host {}/{} is removed from {}:{}", mac, vlanId, deviceId, port);
930
931 // Revoke bridging table entry
932 ForwardingObjective.Builder fob =
Saurav Das4ce45962015-11-24 23:21:05 -0800933 getForwardingObjectiveBuilder(deviceId, mac, vlanId, port);
Charles Chan68aa62d2015-11-09 16:37:23 -0800934 flowObjectiveService.forward(deviceId, fob.remove(
935 new BridgingTableObjectiveContext(mac, vlanId)
936 ));
937
938 // Revoke IP table entry
939 ips.forEach(ip -> {
940 if (ip.isIp4()) {
941 routingRulePopulator.revokeIpRuleForHost(
942 deviceId, ip.getIp4Address(), mac, port);
943 }
944 });
945 }
946
947 private void processHostMovedEvent(HostEvent event) {
948 MacAddress mac = event.subject().mac();
949 VlanId vlanId = event.subject().vlan();
950 DeviceId prevDeviceId = event.prevSubject().location().deviceId();
951 PortNumber prevPort = event.prevSubject().location().port();
952 Set<IpAddress> prevIps = event.prevSubject().ipAddresses();
953 DeviceId newDeviceId = event.subject().location().deviceId();
954 PortNumber newPort = event.subject().location().port();
955 Set<IpAddress> newIps = event.subject().ipAddresses();
956 log.debug("Host {}/{} is moved from {}:{} to {}:{}",
957 mac, vlanId, prevDeviceId, prevPort, newDeviceId, newPort);
958
959 // Revoke previous bridging table entry
960 ForwardingObjective.Builder prevFob =
Saurav Das4ce45962015-11-24 23:21:05 -0800961 getForwardingObjectiveBuilder(prevDeviceId, mac, vlanId, prevPort);
Charles Chan68aa62d2015-11-09 16:37:23 -0800962 flowObjectiveService.forward(prevDeviceId, prevFob.remove(
963 new BridgingTableObjectiveContext(mac, vlanId)
964 ));
965
966 // Revoke previous IP table entry
967 prevIps.forEach(ip -> {
968 if (ip.isIp4()) {
969 routingRulePopulator.revokeIpRuleForHost(
970 prevDeviceId, ip.getIp4Address(), mac, prevPort);
971 }
972 });
973
974 // Populate new bridging table entry
975 ForwardingObjective.Builder newFob =
Saurav Das4ce45962015-11-24 23:21:05 -0800976 getForwardingObjectiveBuilder(newDeviceId, mac, vlanId, newPort);
Charles Chan68aa62d2015-11-09 16:37:23 -0800977 flowObjectiveService.forward(newDeviceId, newFob.add(
978 new BridgingTableObjectiveContext(mac, vlanId)
979 ));
980
981 // Populate new IP table entry
982 newIps.forEach(ip -> {
983 if (ip.isIp4()) {
984 routingRulePopulator.populateIpRuleForHost(
985 newDeviceId, ip.getIp4Address(), mac, newPort);
986 }
987 });
988 }
989
990 private void processHostUpdatedEvent(HostEvent event) {
991 MacAddress mac = event.subject().mac();
992 VlanId vlanId = event.subject().vlan();
993 DeviceId prevDeviceId = event.prevSubject().location().deviceId();
994 PortNumber prevPort = event.prevSubject().location().port();
995 Set<IpAddress> prevIps = event.prevSubject().ipAddresses();
996 DeviceId newDeviceId = event.subject().location().deviceId();
997 PortNumber newPort = event.subject().location().port();
998 Set<IpAddress> newIps = event.subject().ipAddresses();
999 log.debug("Host {}/{} is updated", mac, vlanId);
1000
1001 // Revoke previous IP table entry
1002 prevIps.forEach(ip -> {
1003 if (ip.isIp4()) {
1004 routingRulePopulator.revokeIpRuleForHost(
1005 prevDeviceId, ip.getIp4Address(), mac, prevPort);
1006 }
1007 });
1008
1009 // Populate new IP table entry
1010 newIps.forEach(ip -> {
1011 if (ip.isIp4()) {
1012 routingRulePopulator.populateIpRuleForHost(
1013 newDeviceId, ip.getIp4Address(), mac, newPort);
1014 }
1015 });
1016 }
1017
1018 @Override
1019 public void event(HostEvent event) {
1020 // Do not proceed without mastership
1021 DeviceId deviceId = event.subject().location().deviceId();
1022 if (!mastershipService.isLocalMaster(deviceId)) {
1023 return;
1024 }
1025
1026 switch (event.type()) {
1027 case HOST_ADDED:
1028 processHostAddedEvent(event);
1029 break;
1030 case HOST_MOVED:
1031 processHostMovedEvent(event);
1032 break;
1033 case HOST_REMOVED:
1034 processHostRemoveEvent(event);
1035 break;
1036 case HOST_UPDATED:
1037 processHostUpdatedEvent(event);
1038 break;
1039 default:
1040 log.warn("Unsupported host event type: {}", event.type());
1041 break;
1042 }
1043 }
1044 }
1045
1046 private static class BridgingTableObjectiveContext implements ObjectiveContext {
1047 final MacAddress mac;
1048 final VlanId vlanId;
1049
1050 BridgingTableObjectiveContext(MacAddress mac, VlanId vlanId) {
1051 this.mac = mac;
1052 this.vlanId = vlanId;
1053 }
1054
1055 @Override
1056 public void onSuccess(Objective objective) {
1057 if (objective.op() == Objective.Operation.ADD) {
1058 log.debug("Successfully populate bridging table entry for {}/{}",
1059 mac, vlanId);
1060 } else {
1061 log.debug("Successfully revoke bridging table entry for {}/{}",
1062 mac, vlanId);
1063 }
1064 }
1065
1066 @Override
1067 public void onError(Objective objective, ObjectiveError error) {
1068 if (objective.op() == Objective.Operation.ADD) {
1069 log.debug("Fail to populate bridging table entry for {}/{}. {}",
1070 mac, vlanId, error);
1071 } else {
1072 log.debug("Fail to revoke bridging table entry for {}/{}. {}",
1073 mac, vlanId, error);
1074 }
1075 }
1076 }
sanghob35a6192015-04-01 13:05:26 -07001077}