blob: 62722f020f43fc692e500823e694e6615126eba6 [file] [log] [blame]
sangho80f11cb2015-04-01 13:05:26 -07001/*
2 * Copyright 2015 Open Networking Laboratory
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.onosproject.segmentrouting;
17
18import org.apache.felix.scr.annotations.Activate;
19import org.apache.felix.scr.annotations.Component;
20import org.apache.felix.scr.annotations.Deactivate;
21import org.apache.felix.scr.annotations.Reference;
22import org.apache.felix.scr.annotations.ReferenceCardinality;
sangho27462c62015-05-14 00:39:53 -070023import org.apache.felix.scr.annotations.Service;
sangho80f11cb2015-04-01 13:05:26 -070024import org.onlab.packet.Ethernet;
Charles Chanf4586112015-11-09 16:37:23 -080025import org.onlab.packet.MacAddress;
Saurav Das7c305372015-10-28 12:39:42 -070026import org.onlab.packet.VlanId;
Charles Chan77277672015-10-20 16:24:19 -070027import org.onlab.packet.IPv4;
28import org.onlab.packet.Ip4Address;
29import org.onlab.packet.Ip4Prefix;
30import org.onlab.packet.IpAddress;
31import org.onlab.packet.IpPrefix;
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -070032import org.onlab.util.KryoNamespace;
sangho80f11cb2015-04-01 13:05:26 -070033import org.onosproject.core.ApplicationId;
34import org.onosproject.core.CoreService;
35import org.onosproject.event.Event;
Charles Chan77277672015-10-20 16:24:19 -070036import org.onosproject.net.ConnectPoint;
Charles Chanf4586112015-11-09 16:37:23 -080037import org.onosproject.net.PortNumber;
Charles Chan72f556a2015-10-05 17:50:33 -070038import org.onosproject.net.config.ConfigFactory;
39import org.onosproject.net.config.NetworkConfigEvent;
40import org.onosproject.net.config.NetworkConfigRegistry;
41import org.onosproject.net.config.NetworkConfigListener;
42import org.onosproject.net.config.basics.SubjectFactories;
Charles Chanf4586112015-11-09 16:37:23 -080043import org.onosproject.net.flow.DefaultTrafficSelector;
44import org.onosproject.net.flow.DefaultTrafficTreatment;
45import org.onosproject.net.flow.TrafficSelector;
46import org.onosproject.net.flow.TrafficTreatment;
47import org.onosproject.net.flowobjective.DefaultForwardingObjective;
48import org.onosproject.net.flowobjective.ForwardingObjective;
49import org.onosproject.net.flowobjective.Objective;
50import org.onosproject.net.flowobjective.ObjectiveContext;
51import org.onosproject.net.flowobjective.ObjectiveError;
52import org.onosproject.net.host.HostEvent;
53import org.onosproject.net.host.HostListener;
Charles Chan319d1a22015-11-03 10:42:14 -080054import org.onosproject.segmentrouting.config.DeviceConfigNotFoundException;
55import org.onosproject.segmentrouting.config.DeviceConfiguration;
Charles Chan72f556a2015-10-05 17:50:33 -070056import org.onosproject.segmentrouting.config.SegmentRoutingConfig;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070057import org.onosproject.segmentrouting.grouphandler.DefaultGroupHandler;
58import org.onosproject.segmentrouting.grouphandler.NeighborSet;
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -070059import org.onosproject.segmentrouting.grouphandler.NeighborSetNextObjectiveStoreKey;
Saurav Das2d94d312015-11-24 23:21:05 -080060import org.onosproject.segmentrouting.grouphandler.PortNextObjectiveStoreKey;
sangho80f11cb2015-04-01 13:05:26 -070061import org.onosproject.mastership.MastershipService;
62import org.onosproject.net.Device;
63import org.onosproject.net.DeviceId;
64import org.onosproject.net.Link;
sangho80f11cb2015-04-01 13:05:26 -070065import org.onosproject.net.Port;
66import org.onosproject.net.device.DeviceEvent;
67import org.onosproject.net.device.DeviceListener;
68import org.onosproject.net.device.DeviceService;
Srikanth Vavilapalli64505482015-04-21 13:04:13 -070069import org.onosproject.net.flowobjective.FlowObjectiveService;
sangho80f11cb2015-04-01 13:05:26 -070070import org.onosproject.net.host.HostService;
71import org.onosproject.net.intent.IntentService;
72import org.onosproject.net.link.LinkEvent;
73import org.onosproject.net.link.LinkListener;
74import org.onosproject.net.link.LinkService;
75import org.onosproject.net.packet.InboundPacket;
76import org.onosproject.net.packet.PacketContext;
77import org.onosproject.net.packet.PacketProcessor;
78import org.onosproject.net.packet.PacketService;
79import org.onosproject.net.topology.TopologyService;
Charles Chan77277672015-10-20 16:24:19 -070080import org.onosproject.segmentrouting.grouphandler.SubnetNextObjectiveStoreKey;
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -070081import org.onosproject.store.service.EventuallyConsistentMap;
82import org.onosproject.store.service.EventuallyConsistentMapBuilder;
83import org.onosproject.store.service.StorageService;
84import org.onosproject.store.service.WallClockTimestamp;
sangho80f11cb2015-04-01 13:05:26 -070085import org.slf4j.Logger;
86import org.slf4j.LoggerFactory;
87
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -070088import java.net.URI;
Saurav Das7c305372015-10-28 12:39:42 -070089import java.util.Collections;
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -070090import java.util.HashSet;
sangho27462c62015-05-14 00:39:53 -070091import java.util.List;
sangho80f11cb2015-04-01 13:05:26 -070092import java.util.Map;
Saurav Das7c305372015-10-28 12:39:42 -070093import java.util.Set;
sangho80f11cb2015-04-01 13:05:26 -070094import java.util.concurrent.ConcurrentHashMap;
95import java.util.concurrent.ConcurrentLinkedQueue;
96import java.util.concurrent.Executors;
97import java.util.concurrent.ScheduledExecutorService;
98import java.util.concurrent.ScheduledFuture;
99import java.util.concurrent.TimeUnit;
100
sangho27462c62015-05-14 00:39:53 -0700101@Service
sangho80f11cb2015-04-01 13:05:26 -0700102@Component(immediate = true)
sangho27462c62015-05-14 00:39:53 -0700103public class SegmentRoutingManager implements SegmentRoutingService {
sangho80f11cb2015-04-01 13:05:26 -0700104
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700105 private static Logger log = LoggerFactory
106 .getLogger(SegmentRoutingManager.class);
sangho80f11cb2015-04-01 13:05:26 -0700107
108 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
109 protected CoreService coreService;
110
111 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
112 protected TopologyService topologyService;
113
114 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
115 protected PacketService packetService;
116
117 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
118 protected IntentService intentService;
119
120 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
121 protected HostService hostService;
122
123 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
124 protected DeviceService deviceService;
125
126 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700127 protected FlowObjectiveService flowObjectiveService;
sangho80f11cb2015-04-01 13:05:26 -0700128
129 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
130 protected LinkService linkService;
131
132 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
sangho80f11cb2015-04-01 13:05:26 -0700133 protected MastershipService mastershipService;
sangho27462c62015-05-14 00:39:53 -0700134
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700135 protected ArpHandler arpHandler = null;
136 protected IcmpHandler icmpHandler = null;
137 protected IpHandler ipHandler = null;
138 protected RoutingRulePopulator routingRulePopulator = null;
sangho80f11cb2015-04-01 13:05:26 -0700139 protected ApplicationId appId;
sangho9b169e32015-04-14 16:27:13 -0700140 protected DeviceConfiguration deviceConfiguration = null;
sangho80f11cb2015-04-01 13:05:26 -0700141
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700142 private DefaultRoutingHandler defaultRoutingHandler = null;
sangho27462c62015-05-14 00:39:53 -0700143 private TunnelHandler tunnelHandler = null;
144 private PolicyHandler policyHandler = null;
Charles Chan2b078ae2015-10-14 11:24:40 -0700145 private InternalPacketProcessor processor = null;
146 private InternalLinkListener linkListener = null;
147 private InternalDeviceListener deviceListener = null;
sangho80f11cb2015-04-01 13:05:26 -0700148 private InternalEventHandler eventHandler = new InternalEventHandler();
149
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700150 private ScheduledExecutorService executorService = Executors
151 .newScheduledThreadPool(1);
sangho80f11cb2015-04-01 13:05:26 -0700152
Saurav Das2d94d312015-11-24 23:21:05 -0800153 @SuppressWarnings("unused")
sangho80f11cb2015-04-01 13:05:26 -0700154 private static ScheduledFuture<?> eventHandlerFuture = null;
Saurav Das2d94d312015-11-24 23:21:05 -0800155 @SuppressWarnings("rawtypes")
sangho80f11cb2015-04-01 13:05:26 -0700156 private ConcurrentLinkedQueue<Event> eventQueue = new ConcurrentLinkedQueue<Event>();
Charles Chanf4586112015-11-09 16:37:23 -0800157 private Map<DeviceId, DefaultGroupHandler> groupHandlerMap =
158 new ConcurrentHashMap<DeviceId, DefaultGroupHandler>();
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700159 // Per device next objective ID store with (device id + neighbor set) as key
Charles Chanf4586112015-11-09 16:37:23 -0800160 private EventuallyConsistentMap<NeighborSetNextObjectiveStoreKey, Integer>
161 nsNextObjStore = null;
Saurav Das2d94d312015-11-24 23:21:05 -0800162 // Per device next objective ID store with (device id + subnet) as key
Charles Chanf4586112015-11-09 16:37:23 -0800163 private EventuallyConsistentMap<SubnetNextObjectiveStoreKey, Integer>
164 subnetNextObjStore = null;
Saurav Das2d94d312015-11-24 23:21:05 -0800165 // Per device next objective ID store with (device id + port) as key
166 private EventuallyConsistentMap<PortNextObjectiveStoreKey, Integer>
167 portNextObjStore = null;
Saurav Das7c305372015-10-28 12:39:42 -0700168 // Per device, per-subnet assigned-vlans store, with (device id + subnet
169 // IPv4 prefix) as key
170 private EventuallyConsistentMap<SubnetAssignedVidStoreKey, VlanId>
171 subnetVidStore = null;
Saurav Das2d94d312015-11-24 23:21:05 -0800172 private EventuallyConsistentMap<String, Tunnel> tunnelStore = null;
173 private EventuallyConsistentMap<String, Policy> policyStore = null;
sangho4a5c42a2015-05-20 22:16:38 -0700174
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700175 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
176 protected StorageService storageService;
sangho80f11cb2015-04-01 13:05:26 -0700177
Charles Chan72f556a2015-10-05 17:50:33 -0700178 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
179 protected NetworkConfigRegistry cfgService;
180
Charles Chane7c61022015-10-07 14:21:45 -0700181 private final InternalConfigListener cfgListener =
182 new InternalConfigListener(this);
183
Saurav Das2d94d312015-11-24 23:21:05 -0800184 @SuppressWarnings({ "unchecked", "rawtypes" })
Charles Chan72f556a2015-10-05 17:50:33 -0700185 private final ConfigFactory cfgFactory =
186 new ConfigFactory(SubjectFactories.DEVICE_SUBJECT_FACTORY,
187 SegmentRoutingConfig.class,
188 "segmentrouting") {
189 @Override
190 public SegmentRoutingConfig createConfig() {
191 return new SegmentRoutingConfig();
192 }
193 };
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700194
Charles Chand4a99c52015-11-18 16:51:08 -0800195 private final InternalHostListener hostListener = new InternalHostListener();
Charles Chanf4586112015-11-09 16:37:23 -0800196
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700197 private Object threadSchedulerLock = new Object();
198 private static int numOfEventsQueued = 0;
199 private static int numOfEventsExecuted = 0;
sangho80f11cb2015-04-01 13:05:26 -0700200 private static int numOfHandlerExecution = 0;
201 private static int numOfHandlerScheduled = 0;
202
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700203 private KryoNamespace.Builder kryoBuilder = null;
204
Saurav Das7c305372015-10-28 12:39:42 -0700205 private static final short ASSIGNED_VLAN_START = 4093;
206 public static final short ASSIGNED_VLAN_NO_SUBNET = 4094;
207
sangho80f11cb2015-04-01 13:05:26 -0700208 @Activate
209 protected void activate() {
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700210 appId = coreService
211 .registerApplication("org.onosproject.segmentrouting");
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700212
213 kryoBuilder = new KryoNamespace.Builder()
214 .register(NeighborSetNextObjectiveStoreKey.class,
Charles Chan77277672015-10-20 16:24:19 -0700215 SubnetNextObjectiveStoreKey.class,
216 SubnetAssignedVidStoreKey.class,
sangho4a5c42a2015-05-20 22:16:38 -0700217 NeighborSet.class,
218 DeviceId.class,
219 URI.class,
220 WallClockTimestamp.class,
221 org.onosproject.cluster.NodeId.class,
222 HashSet.class,
223 Tunnel.class,
224 DefaultTunnel.class,
225 Policy.class,
226 TunnelPolicy.class,
Saurav Das7c305372015-10-28 12:39:42 -0700227 Policy.Type.class,
Charles Chan77277672015-10-20 16:24:19 -0700228 VlanId.class,
229 Ip4Address.class,
230 Ip4Prefix.class,
231 IpAddress.Version.class,
232 ConnectPoint.class
sangho4a5c42a2015-05-20 22:16:38 -0700233 );
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700234
235 log.debug("Creating EC map nsnextobjectivestore");
236 EventuallyConsistentMapBuilder<NeighborSetNextObjectiveStoreKey, Integer>
237 nsNextObjMapBuilder = storageService.eventuallyConsistentMapBuilder();
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700238 nsNextObjStore = nsNextObjMapBuilder
239 .withName("nsnextobjectivestore")
240 .withSerializer(kryoBuilder)
Madan Jampani675ae202015-06-24 19:05:56 -0700241 .withTimestampProvider((k, v) -> new WallClockTimestamp())
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700242 .build();
243 log.trace("Current size {}", nsNextObjStore.size());
244
Charles Chan77277672015-10-20 16:24:19 -0700245 log.debug("Creating EC map subnetnextobjectivestore");
246 EventuallyConsistentMapBuilder<SubnetNextObjectiveStoreKey, Integer>
247 subnetNextObjMapBuilder = storageService.eventuallyConsistentMapBuilder();
Charles Chan77277672015-10-20 16:24:19 -0700248 subnetNextObjStore = subnetNextObjMapBuilder
249 .withName("subnetnextobjectivestore")
250 .withSerializer(kryoBuilder)
251 .withTimestampProvider((k, v) -> new WallClockTimestamp())
252 .build();
253
Saurav Das2d94d312015-11-24 23:21:05 -0800254 log.debug("Creating EC map subnetnextobjectivestore");
255 EventuallyConsistentMapBuilder<PortNextObjectiveStoreKey, Integer>
256 portNextObjMapBuilder = storageService.eventuallyConsistentMapBuilder();
257 portNextObjStore = portNextObjMapBuilder
258 .withName("portnextobjectivestore")
259 .withSerializer(kryoBuilder)
260 .withTimestampProvider((k, v) -> new WallClockTimestamp())
261 .build();
262
sangho4a5c42a2015-05-20 22:16:38 -0700263 EventuallyConsistentMapBuilder<String, Tunnel> tunnelMapBuilder =
264 storageService.eventuallyConsistentMapBuilder();
sangho4a5c42a2015-05-20 22:16:38 -0700265 tunnelStore = tunnelMapBuilder
266 .withName("tunnelstore")
267 .withSerializer(kryoBuilder)
Madan Jampani675ae202015-06-24 19:05:56 -0700268 .withTimestampProvider((k, v) -> new WallClockTimestamp())
sangho4a5c42a2015-05-20 22:16:38 -0700269 .build();
270
271 EventuallyConsistentMapBuilder<String, Policy> policyMapBuilder =
272 storageService.eventuallyConsistentMapBuilder();
sangho4a5c42a2015-05-20 22:16:38 -0700273 policyStore = policyMapBuilder
274 .withName("policystore")
275 .withSerializer(kryoBuilder)
Madan Jampani675ae202015-06-24 19:05:56 -0700276 .withTimestampProvider((k, v) -> new WallClockTimestamp())
sangho4a5c42a2015-05-20 22:16:38 -0700277 .build();
278
Saurav Das7c305372015-10-28 12:39:42 -0700279 EventuallyConsistentMapBuilder<SubnetAssignedVidStoreKey, VlanId>
280 subnetVidStoreMapBuilder = storageService.eventuallyConsistentMapBuilder();
Saurav Das7c305372015-10-28 12:39:42 -0700281 subnetVidStore = subnetVidStoreMapBuilder
282 .withName("subnetvidstore")
283 .withSerializer(kryoBuilder)
284 .withTimestampProvider((k, v) -> new WallClockTimestamp())
285 .build();
286
Charles Chan72f556a2015-10-05 17:50:33 -0700287 cfgService.addListener(cfgListener);
288 cfgService.registerConfigFactory(cfgFactory);
Charles Chan72f556a2015-10-05 17:50:33 -0700289
Charles Chanf4586112015-11-09 16:37:23 -0800290 hostService.addListener(hostListener);
291
Charles Chan2b078ae2015-10-14 11:24:40 -0700292 processor = new InternalPacketProcessor();
293 linkListener = new InternalLinkListener();
294 deviceListener = new InternalDeviceListener();
295
296 packetService.addProcessor(processor, PacketProcessor.director(2));
297 linkService.addListener(linkListener);
298 deviceService.addListener(deviceListener);
299
300 cfgListener.configureNetwork();
301
sangho80f11cb2015-04-01 13:05:26 -0700302 log.info("Started");
303 }
304
305 @Deactivate
306 protected void deactivate() {
Charles Chan72f556a2015-10-05 17:50:33 -0700307 cfgService.removeListener(cfgListener);
308 cfgService.unregisterConfigFactory(cfgFactory);
309
sangho80f11cb2015-04-01 13:05:26 -0700310 packetService.removeProcessor(processor);
Charles Chan2b078ae2015-10-14 11:24:40 -0700311 linkService.removeListener(linkListener);
312 deviceService.removeListener(deviceListener);
sangho80f11cb2015-04-01 13:05:26 -0700313 processor = null;
Charles Chan2b078ae2015-10-14 11:24:40 -0700314 linkListener = null;
315 deviceService = null;
316
317 groupHandlerMap.clear();
318
sangho80f11cb2015-04-01 13:05:26 -0700319 log.info("Stopped");
320 }
321
sangho27462c62015-05-14 00:39:53 -0700322
323 @Override
324 public List<Tunnel> getTunnels() {
325 return tunnelHandler.getTunnels();
326 }
327
328 @Override
sanghobd812f82015-06-29 14:58:47 -0700329 public TunnelHandler.Result createTunnel(Tunnel tunnel) {
330 return tunnelHandler.createTunnel(tunnel);
sangho27462c62015-05-14 00:39:53 -0700331 }
332
333 @Override
sanghobd812f82015-06-29 14:58:47 -0700334 public TunnelHandler.Result removeTunnel(Tunnel tunnel) {
sangho27462c62015-05-14 00:39:53 -0700335 for (Policy policy: policyHandler.getPolicies()) {
336 if (policy.type() == Policy.Type.TUNNEL_FLOW) {
337 TunnelPolicy tunnelPolicy = (TunnelPolicy) policy;
338 if (tunnelPolicy.tunnelId().equals(tunnel.id())) {
339 log.warn("Cannot remove the tunnel used by a policy");
sanghobd812f82015-06-29 14:58:47 -0700340 return TunnelHandler.Result.TUNNEL_IN_USE;
sangho27462c62015-05-14 00:39:53 -0700341 }
342 }
343 }
sanghobd812f82015-06-29 14:58:47 -0700344 return tunnelHandler.removeTunnel(tunnel);
sangho27462c62015-05-14 00:39:53 -0700345 }
346
347 @Override
sanghobd812f82015-06-29 14:58:47 -0700348 public PolicyHandler.Result removePolicy(Policy policy) {
349 return policyHandler.removePolicy(policy);
sangho27462c62015-05-14 00:39:53 -0700350 }
351
352 @Override
sanghobd812f82015-06-29 14:58:47 -0700353 public PolicyHandler.Result createPolicy(Policy policy) {
354 return policyHandler.createPolicy(policy);
sangho27462c62015-05-14 00:39:53 -0700355 }
356
357 @Override
358 public List<Policy> getPolicies() {
359 return policyHandler.getPolicies();
360 }
361
sangho80f1f892015-05-19 11:57:42 -0700362 /**
363 * Returns the tunnel object with the tunnel ID.
364 *
365 * @param tunnelId Tunnel ID
366 * @return Tunnel reference
367 */
sangho27462c62015-05-14 00:39:53 -0700368 public Tunnel getTunnel(String tunnelId) {
369 return tunnelHandler.getTunnel(tunnelId);
370 }
371
sangho80f11cb2015-04-01 13:05:26 -0700372 /**
Saurav Das7c305372015-10-28 12:39:42 -0700373 * Returns the vlan-id assigned to the subnet configured for a device.
374 * If no vlan-id has been assigned, a new one is assigned out of a pool of ids,
375 * if and only if this controller instance is the master for the device.
376 * <p>
377 * USAGE: The assigned vlans are meant to be applied to untagged packets on those
378 * switches/pipelines that need this functionality. These vids are meant
379 * to be used internally within a switch, and thus need to be unique only
380 * on a switch level. Note that packets never go out on the wire with these
381 * vlans. Currently, vlan ids are assigned from value 4093 down.
382 * Vlan id 4094 expected to be used for all ports that are not assigned subnets.
383 * Vlan id 4095 is reserved and unused. Only a single vlan id is assigned
384 * per subnet.
385 * XXX This method should avoid any vlans configured on the ports, but
386 * currently the app works only on untagged packets and as a result
387 * ignores any vlan configuration.
sangho80f11cb2015-04-01 13:05:26 -0700388 *
Saurav Das7c305372015-10-28 12:39:42 -0700389 * @param deviceId switch dpid
390 * @param subnet IPv4 prefix for which assigned vlan is desired
391 * @return VlanId assigned for the subnet on the device, or
392 * null if no vlan assignment was found and this instance is not
393 * the master for the device.
sangho80f11cb2015-04-01 13:05:26 -0700394 */
Saurav Das7c305372015-10-28 12:39:42 -0700395 public VlanId getSubnetAssignedVlanId(DeviceId deviceId, Ip4Prefix subnet) {
396 VlanId assignedVid = subnetVidStore.get(new SubnetAssignedVidStoreKey(
397 deviceId, subnet));
398 if (assignedVid != null) {
399 log.debug("Query for subnet:{} on device:{} returned assigned-vlan "
400 + "{}", subnet, deviceId, assignedVid);
401 return assignedVid;
402 }
403 //check mastership for the right to assign a vlan
404 if (!mastershipService.isLocalMaster(deviceId)) {
405 log.warn("This controller instance is not the master for device {}. "
406 + "Cannot assign vlan-id for subnet {}", deviceId, subnet);
407 return null;
408 }
409 // vlan assignment is expensive but done only once
Charles Chanc6ad7752015-10-29 14:58:10 -0700410 Set<Ip4Prefix> configuredSubnets = deviceConfiguration.getSubnets(deviceId);
Saurav Das7c305372015-10-28 12:39:42 -0700411 Set<Short> assignedVlans = new HashSet<>();
412 Set<Ip4Prefix> unassignedSubnets = new HashSet<>();
413 for (Ip4Prefix sub : configuredSubnets) {
414 VlanId v = subnetVidStore.get(new SubnetAssignedVidStoreKey(deviceId,
415 sub));
416 if (v != null) {
417 assignedVlans.add(v.toShort());
418 } else {
419 unassignedSubnets.add(sub);
420 }
421 }
422 short nextAssignedVlan = ASSIGNED_VLAN_START;
423 if (!assignedVlans.isEmpty()) {
424 nextAssignedVlan = (short) (Collections.min(assignedVlans) - 1);
425 }
426 for (Ip4Prefix unsub : unassignedSubnets) {
427 subnetVidStore.put(new SubnetAssignedVidStoreKey(deviceId, unsub),
428 VlanId.vlanId(nextAssignedVlan--));
429 log.info("Assigned vlan: {} to subnet: {} on device: {}",
430 nextAssignedVlan + 1, unsub, deviceId);
sangho80f11cb2015-04-01 13:05:26 -0700431 }
432
Saurav Das7c305372015-10-28 12:39:42 -0700433 return subnetVidStore.get(new SubnetAssignedVidStoreKey(deviceId, subnet));
sangho80f11cb2015-04-01 13:05:26 -0700434 }
435
sangho27462c62015-05-14 00:39:53 -0700436 /**
Saurav Das7c305372015-10-28 12:39:42 -0700437 * Returns the next objective ID for the given NeighborSet.
Saurav Das4c35fc42015-11-20 15:27:53 -0800438 * If the nextObjective does not exist, a new one is created and
Saurav Das2d94d312015-11-24 23:21:05 -0800439 * its id is returned.
sangho27462c62015-05-14 00:39:53 -0700440 *
sangho80f1f892015-05-19 11:57:42 -0700441 * @param deviceId Device ID
442 * @param ns NegighborSet
Saurav Das4c35fc42015-11-20 15:27:53 -0800443 * @param meta metadata passed into the creation of a Next Objective
444 * @return next objective ID or -1 if an error was encountered during the
445 * creation of the nextObjective
sangho27462c62015-05-14 00:39:53 -0700446 */
Saurav Das4c35fc42015-11-20 15:27:53 -0800447 public int getNextObjectiveId(DeviceId deviceId, NeighborSet ns,
448 TrafficSelector meta) {
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700449 if (groupHandlerMap.get(deviceId) != null) {
450 log.trace("getNextObjectiveId query in device {}", deviceId);
451 return groupHandlerMap
Saurav Das4c35fc42015-11-20 15:27:53 -0800452 .get(deviceId).getNextObjectiveId(ns, meta);
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700453 } else {
Saurav Das2d94d312015-11-24 23:21:05 -0800454 log.warn("getNextObjectiveId query - groupHandler for device {} "
455 + "not found", deviceId);
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700456 return -1;
457 }
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700458 }
459
Charles Chan77277672015-10-20 16:24:19 -0700460 /**
Saurav Das2d94d312015-11-24 23:21:05 -0800461 * Returns the next objective ID for the given subnet prefix. It is expected
462 * that the next-objective has been pre-created from configuration.
Charles Chan77277672015-10-20 16:24:19 -0700463 *
464 * @param deviceId Device ID
465 * @param prefix Subnet
Saurav Das2d94d312015-11-24 23:21:05 -0800466 * @return next objective ID or -1 if it was not found
Charles Chan77277672015-10-20 16:24:19 -0700467 */
468 public int getSubnetNextObjectiveId(DeviceId deviceId, IpPrefix prefix) {
469 if (groupHandlerMap.get(deviceId) != null) {
470 log.trace("getSubnetNextObjectiveId query in device {}", deviceId);
471 return groupHandlerMap
472 .get(deviceId).getSubnetNextObjectiveId(prefix);
473 } else {
Saurav Das2d94d312015-11-24 23:21:05 -0800474 log.warn("getSubnetNextObjectiveId query - groupHandler for "
475 + "device {} not found", deviceId);
476 return -1;
477 }
478 }
479
480 /**
481 * Returns the next objective ID for the given portNumber, given the treatment.
482 * There could be multiple different treatments to the same outport, which
483 * would result in different objectives. If the next object
484 * does not exist, a new one is created and its id is returned.
485 *
486 * @param deviceId Device ID
487 * @param portNum port number on device for which NextObjective is queried
488 * @param treatment the actions to apply on the packets (should include outport)
489 * @param meta metadata passed into the creation of a Next Objective if necessary
490 * @return next objective ID or -1 if it was not found
491 */
492 public int getPortNextObjectiveId(DeviceId deviceId, PortNumber portNum,
493 TrafficTreatment treatment,
494 TrafficSelector meta) {
495 DefaultGroupHandler ghdlr = groupHandlerMap.get(deviceId);
496 if (ghdlr != null) {
497 return ghdlr.getPortNextObjectiveId(portNum, treatment, meta);
498 } else {
499 log.warn("getPortNextObjectiveId query - groupHandler for device {}"
500 + " not found", deviceId);
Charles Chan77277672015-10-20 16:24:19 -0700501 return -1;
502 }
503 }
504
sangho80f11cb2015-04-01 13:05:26 -0700505 private class InternalPacketProcessor implements PacketProcessor {
sangho80f11cb2015-04-01 13:05:26 -0700506 @Override
507 public void process(PacketContext context) {
508
509 if (context.isHandled()) {
510 return;
511 }
512
513 InboundPacket pkt = context.inPacket();
514 Ethernet ethernet = pkt.parsed();
Saurav Das2d94d312015-11-24 23:21:05 -0800515 log.trace("Rcvd pktin: {}", ethernet);
sangho80f11cb2015-04-01 13:05:26 -0700516 if (ethernet.getEtherType() == Ethernet.TYPE_ARP) {
517 arpHandler.processPacketIn(pkt);
518 } else if (ethernet.getEtherType() == Ethernet.TYPE_IPV4) {
519 IPv4 ipPacket = (IPv4) ethernet.getPayload();
520 ipHandler.addToPacketBuffer(ipPacket);
521 if (ipPacket.getProtocol() == IPv4.PROTOCOL_ICMP) {
522 icmpHandler.processPacketIn(pkt);
523 } else {
524 ipHandler.processPacketIn(pkt);
525 }
526 }
527 }
528 }
529
530 private class InternalLinkListener implements LinkListener {
531 @Override
532 public void event(LinkEvent event) {
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700533 if (event.type() == LinkEvent.Type.LINK_ADDED
534 || event.type() == LinkEvent.Type.LINK_REMOVED) {
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700535 log.debug("Event {} received from Link Service", event.type());
sangho80f11cb2015-04-01 13:05:26 -0700536 scheduleEventHandlerIfNotScheduled(event);
537 }
538 }
539 }
540
541 private class InternalDeviceListener implements DeviceListener {
sangho80f11cb2015-04-01 13:05:26 -0700542 @Override
543 public void event(DeviceEvent event) {
sangho80f11cb2015-04-01 13:05:26 -0700544 switch (event.type()) {
545 case DEVICE_ADDED:
546 case PORT_REMOVED:
sanghofb7c7292015-04-13 15:15:58 -0700547 case DEVICE_UPDATED:
548 case DEVICE_AVAILABILITY_CHANGED:
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700549 log.debug("Event {} received from Device Service", event.type());
sangho80f11cb2015-04-01 13:05:26 -0700550 scheduleEventHandlerIfNotScheduled(event);
551 break;
552 default:
553 }
554 }
555 }
556
Saurav Das2d94d312015-11-24 23:21:05 -0800557 @SuppressWarnings("rawtypes")
sangho80f11cb2015-04-01 13:05:26 -0700558 private void scheduleEventHandlerIfNotScheduled(Event event) {
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700559 synchronized (threadSchedulerLock) {
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700560 eventQueue.add(event);
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700561 numOfEventsQueued++;
562
563 if ((numOfHandlerScheduled - numOfHandlerExecution) == 0) {
564 //No pending scheduled event handling threads. So start a new one.
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700565 eventHandlerFuture = executorService
566 .schedule(eventHandler, 100, TimeUnit.MILLISECONDS);
567 numOfHandlerScheduled++;
568 }
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700569 log.trace("numOfEventsQueued {}, numOfEventHanlderScheduled {}",
570 numOfEventsQueued,
571 numOfHandlerScheduled);
sangho80f11cb2015-04-01 13:05:26 -0700572 }
sangho80f11cb2015-04-01 13:05:26 -0700573 }
574
575 private class InternalEventHandler implements Runnable {
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700576 @Override
sangho80f11cb2015-04-01 13:05:26 -0700577 public void run() {
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700578 try {
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700579 while (true) {
Saurav Das2d94d312015-11-24 23:21:05 -0800580 @SuppressWarnings("rawtypes")
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700581 Event event = null;
582 synchronized (threadSchedulerLock) {
583 if (!eventQueue.isEmpty()) {
584 event = eventQueue.poll();
585 numOfEventsExecuted++;
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700586 } else {
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700587 numOfHandlerExecution++;
588 log.debug("numOfHandlerExecution {} numOfEventsExecuted {}",
589 numOfHandlerExecution, numOfEventsExecuted);
590 break;
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700591 }
sanghofb7c7292015-04-13 15:15:58 -0700592 }
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700593 if (event.type() == LinkEvent.Type.LINK_ADDED) {
594 processLinkAdded((Link) event.subject());
595 } else if (event.type() == LinkEvent.Type.LINK_REMOVED) {
596 processLinkRemoved((Link) event.subject());
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700597 } else if (event.type() == DeviceEvent.Type.DEVICE_ADDED ||
598 event.type() == DeviceEvent.Type.DEVICE_AVAILABILITY_CHANGED ||
599 event.type() == DeviceEvent.Type.DEVICE_UPDATED) {
600 if (deviceService.isAvailable(((Device) event.subject()).id())) {
Saurav Dasc28b3432015-10-30 17:45:38 -0700601 log.info("Processing device event {} for available device {}",
602 event.type(), ((Device) event.subject()).id());
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700603 processDeviceAdded((Device) event.subject());
604 }
605 } else if (event.type() == DeviceEvent.Type.PORT_REMOVED) {
606 processPortRemoved((Device) event.subject(),
607 ((DeviceEvent) event).port());
608 } else {
609 log.warn("Unhandled event type: {}", event.type());
610 }
sangho80f11cb2015-04-01 13:05:26 -0700611 }
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700612 } catch (Exception e) {
613 log.error("SegmentRouting event handler "
614 + "thread thrown an exception: {}", e);
sangho80f11cb2015-04-01 13:05:26 -0700615 }
sangho80f11cb2015-04-01 13:05:26 -0700616 }
617 }
618
sangho80f11cb2015-04-01 13:05:26 -0700619 private void processLinkAdded(Link link) {
620 log.debug("A new link {} was added", link.toString());
Charles Chan319d1a22015-11-03 10:42:14 -0800621 if (!deviceConfiguration.isConfigured(link.src().deviceId())) {
622 log.warn("Source device of this link is not configured.");
623 return;
624 }
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700625 //Irrespective whether the local is a MASTER or not for this device,
626 //create group handler instance and push default TTP flow rules.
627 //Because in a multi-instance setup, instances can initiate
628 //groups for any devices. Also the default TTP rules are needed
629 //to be pushed before inserting any IP table entries for any device
630 DefaultGroupHandler groupHandler = groupHandlerMap.get(link.src()
631 .deviceId());
632 if (groupHandler != null) {
Saurav Das4c35fc42015-11-20 15:27:53 -0800633 groupHandler.linkUp(link, mastershipService.isLocalMaster(
634 link.src().deviceId()));
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700635 } else {
636 Device device = deviceService.getDevice(link.src().deviceId());
637 if (device != null) {
638 log.warn("processLinkAdded: Link Added "
639 + "Notification without Device Added "
640 + "event, still handling it");
641 processDeviceAdded(device);
642 groupHandler = groupHandlerMap.get(link.src()
643 .deviceId());
Saurav Das4c35fc42015-11-20 15:27:53 -0800644 groupHandler.linkUp(link, mastershipService.isLocalMaster(device.id()));
sangho80f11cb2015-04-01 13:05:26 -0700645 }
646 }
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700647
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700648 log.trace("Starting optimized route population process");
649 defaultRoutingHandler.populateRoutingRulesForLinkStatusChange(null);
650 //log.trace("processLinkAdded: re-starting route population process");
651 //defaultRoutingHandler.startPopulationProcess();
sangho80f11cb2015-04-01 13:05:26 -0700652 }
653
654 private void processLinkRemoved(Link link) {
655 log.debug("A link {} was removed", link.toString());
sangho2165d222015-05-01 09:38:25 -0700656 DefaultGroupHandler groupHandler = groupHandlerMap.get(link.src().deviceId());
657 if (groupHandler != null) {
658 groupHandler.portDown(link.src().port());
659 }
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700660 log.trace("Starting optimized route population process");
661 defaultRoutingHandler.populateRoutingRulesForLinkStatusChange(link);
662 //log.trace("processLinkRemoved: re-starting route population process");
663 //defaultRoutingHandler.startPopulationProcess();
sangho80f11cb2015-04-01 13:05:26 -0700664 }
665
666 private void processDeviceAdded(Device device) {
667 log.debug("A new device with ID {} was added", device.id());
Charles Chan319d1a22015-11-03 10:42:14 -0800668 if (deviceConfiguration == null || !deviceConfiguration.isConfigured(device.id())) {
Saurav Das8ec0ec42015-11-03 14:39:27 -0800669 log.warn("Device configuration uploading. Device {} will be "
670 + "processed after config completes.", device.id());
671 return;
672 }
Saurav Dasc28b3432015-10-30 17:45:38 -0700673 // Irrespective of whether the local is a MASTER or not for this device,
674 // we need to create a SR-group-handler instance. This is because in a
675 // multi-instance setup, any instance can initiate forwarding/next-objectives
676 // for any switch (even if this instance is a SLAVE or not even connected
677 // to the switch). To handle this, a default-group-handler instance is necessary
678 // per switch.
Saurav Das8ec0ec42015-11-03 14:39:27 -0800679 if (groupHandlerMap.get(device.id()) == null) {
Charles Chan319d1a22015-11-03 10:42:14 -0800680 DefaultGroupHandler groupHandler;
681 try {
682 groupHandler = DefaultGroupHandler.
683 createGroupHandler(device.id(),
684 appId,
685 deviceConfiguration,
686 linkService,
687 flowObjectiveService,
688 nsNextObjStore,
Saurav Das2d94d312015-11-24 23:21:05 -0800689 subnetNextObjStore,
690 portNextObjStore);
Charles Chan319d1a22015-11-03 10:42:14 -0800691 } catch (DeviceConfigNotFoundException e) {
692 log.warn(e.getMessage() + " Aborting processDeviceAdded.");
693 return;
694 }
Saurav Das8ec0ec42015-11-03 14:39:27 -0800695 groupHandlerMap.put(device.id(), groupHandler);
696 // Also, in some cases, drivers may need extra
697 // information to process rules (eg. Router IP/MAC); and so, we send
698 // port addressing rules to the driver as well irrespective of whether
699 // this instance is the master or not.
700 defaultRoutingHandler.populatePortAddressingRules(device.id());
Charles Chand4a99c52015-11-18 16:51:08 -0800701 hostListener.readInitialHosts();
Saurav Das8ec0ec42015-11-03 14:39:27 -0800702 }
Charles Chan77277672015-10-20 16:24:19 -0700703 if (mastershipService.isLocalMaster(device.id())) {
Saurav Das8ec0ec42015-11-03 14:39:27 -0800704 DefaultGroupHandler groupHandler = groupHandlerMap.get(device.id());
Charles Chan77277672015-10-20 16:24:19 -0700705 groupHandler.createGroupsFromSubnetConfig();
Charles Chanf4586112015-11-09 16:37:23 -0800706 routingRulePopulator.populateSubnetBroadcastRule(device.id());
Charles Chan77277672015-10-20 16:24:19 -0700707 }
sangho80f11cb2015-04-01 13:05:26 -0700708 }
709
710 private void processPortRemoved(Device device, Port port) {
711 log.debug("Port {} was removed", port.toString());
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700712 DefaultGroupHandler groupHandler = groupHandlerMap.get(device.id());
sangho80f11cb2015-04-01 13:05:26 -0700713 if (groupHandler != null) {
714 groupHandler.portDown(port.number());
715 }
716 }
sangho27462c62015-05-14 00:39:53 -0700717
Charles Chan72f556a2015-10-05 17:50:33 -0700718 private class InternalConfigListener implements NetworkConfigListener {
Charles Chane7c61022015-10-07 14:21:45 -0700719 SegmentRoutingManager segmentRoutingManager;
720
721 public InternalConfigListener(SegmentRoutingManager srMgr) {
722 this.segmentRoutingManager = srMgr;
723 }
724
725 public void configureNetwork() {
726 deviceConfiguration = new DeviceConfiguration(segmentRoutingManager.cfgService);
727
728 arpHandler = new ArpHandler(segmentRoutingManager);
729 icmpHandler = new IcmpHandler(segmentRoutingManager);
730 ipHandler = new IpHandler(segmentRoutingManager);
731 routingRulePopulator = new RoutingRulePopulator(segmentRoutingManager);
732 defaultRoutingHandler = new DefaultRoutingHandler(segmentRoutingManager);
733
734 tunnelHandler = new TunnelHandler(linkService, deviceConfiguration,
735 groupHandlerMap, tunnelStore);
736 policyHandler = new PolicyHandler(appId, deviceConfiguration,
737 flowObjectiveService,
738 tunnelHandler, policyStore);
739
Charles Chane7c61022015-10-07 14:21:45 -0700740 for (Device device : deviceService.getDevices()) {
Saurav Dasc28b3432015-10-30 17:45:38 -0700741 // Irrespective of whether the local is a MASTER or not for this device,
742 // we need to create a SR-group-handler instance. This is because in a
743 // multi-instance setup, any instance can initiate forwarding/next-objectives
744 // for any switch (even if this instance is a SLAVE or not even connected
745 // to the switch). To handle this, a default-group-handler instance is necessary
746 // per switch.
Saurav Das8ec0ec42015-11-03 14:39:27 -0800747 if (groupHandlerMap.get(device.id()) == null) {
Charles Chan319d1a22015-11-03 10:42:14 -0800748 DefaultGroupHandler groupHandler;
749 try {
750 groupHandler = DefaultGroupHandler.
751 createGroupHandler(device.id(),
752 appId,
753 deviceConfiguration,
754 linkService,
755 flowObjectiveService,
756 nsNextObjStore,
Saurav Das2d94d312015-11-24 23:21:05 -0800757 subnetNextObjStore,
758 portNextObjStore);
Charles Chan319d1a22015-11-03 10:42:14 -0800759 } catch (DeviceConfigNotFoundException e) {
760 log.warn(e.getMessage() + " Aborting configureNetwork.");
761 return;
762 }
Saurav Das8ec0ec42015-11-03 14:39:27 -0800763 groupHandlerMap.put(device.id(), groupHandler);
Saurav Dasc28b3432015-10-30 17:45:38 -0700764
Saurav Das8ec0ec42015-11-03 14:39:27 -0800765 // Also, in some cases, drivers may need extra
766 // information to process rules (eg. Router IP/MAC); and so, we send
767 // port addressing rules to the driver as well, irrespective of whether
768 // this instance is the master or not.
769 defaultRoutingHandler.populatePortAddressingRules(device.id());
Charles Chand4a99c52015-11-18 16:51:08 -0800770 hostListener.readInitialHosts();
Saurav Das8ec0ec42015-11-03 14:39:27 -0800771 }
Charles Chan77277672015-10-20 16:24:19 -0700772 if (mastershipService.isLocalMaster(device.id())) {
Saurav Das8ec0ec42015-11-03 14:39:27 -0800773 DefaultGroupHandler groupHandler = groupHandlerMap.get(device.id());
Charles Chan77277672015-10-20 16:24:19 -0700774 groupHandler.createGroupsFromSubnetConfig();
Charles Chanf4586112015-11-09 16:37:23 -0800775 routingRulePopulator.populateSubnetBroadcastRule(device.id());
Charles Chan77277672015-10-20 16:24:19 -0700776 }
Charles Chane7c61022015-10-07 14:21:45 -0700777 }
778
779 defaultRoutingHandler.startPopulationProcess();
780 }
781
Charles Chan72f556a2015-10-05 17:50:33 -0700782 @Override
783 public void event(NetworkConfigEvent event) {
Charles Chan2b078ae2015-10-14 11:24:40 -0700784 if (event.configClass().equals(SegmentRoutingConfig.class)) {
785 if (event.type() == NetworkConfigEvent.Type.CONFIG_ADDED) {
786 log.info("Network configuration added.");
787 configureNetwork();
788 }
789 if (event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED) {
790 log.info("Network configuration updated.");
791 // TODO support dynamic configuration
792 }
Charles Chan72f556a2015-10-05 17:50:33 -0700793 }
794 }
795 }
Charles Chanf4586112015-11-09 16:37:23 -0800796
Charles Chand4a99c52015-11-18 16:51:08 -0800797 // TODO Move bridging table population to a separate class
Charles Chanf4586112015-11-09 16:37:23 -0800798 private class InternalHostListener implements HostListener {
Charles Chand4a99c52015-11-18 16:51:08 -0800799 private void readInitialHosts() {
800 hostService.getHosts().forEach(host -> {
801 MacAddress mac = host.mac();
802 VlanId vlanId = host.vlan();
803 DeviceId deviceId = host.location().deviceId();
804 PortNumber port = host.location().port();
805 Set<IpAddress> ips = host.ipAddresses();
806 log.debug("Host {}/{} is added at {}:{}", mac, vlanId, deviceId, port);
807
808 // Populate bridging table entry
809 ForwardingObjective.Builder fob =
Saurav Das2d94d312015-11-24 23:21:05 -0800810 getForwardingObjectiveBuilder(deviceId, mac, vlanId, port);
Charles Chand4a99c52015-11-18 16:51:08 -0800811 flowObjectiveService.forward(deviceId, fob.add(
812 new BridgingTableObjectiveContext(mac, vlanId)
813 ));
814
815 // Populate IP table entry
816 ips.forEach(ip -> {
817 if (ip.isIp4()) {
818 routingRulePopulator.populateIpRuleForHost(
819 deviceId, ip.getIp4Address(), mac, port);
820 }
821 });
822 });
823 }
824
Charles Chanf4586112015-11-09 16:37:23 -0800825 private ForwardingObjective.Builder getForwardingObjectiveBuilder(
Saurav Das2d94d312015-11-24 23:21:05 -0800826 DeviceId deviceId, MacAddress mac, VlanId vlanId,
827 PortNumber outport) {
828 // match rule
Charles Chanf4586112015-11-09 16:37:23 -0800829 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
830 sbuilder.matchEthDst(mac);
831 sbuilder.matchVlanId(vlanId);
832
833 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
Charles Chanf4586112015-11-09 16:37:23 -0800834 tbuilder.immediate().popVlan();
Saurav Das2d94d312015-11-24 23:21:05 -0800835 tbuilder.immediate().setOutput(outport);
836
837 // for switch pipelines that need it, provide outgoing vlan as metadata
838 VlanId outvlan = null;
839 Ip4Prefix subnet = deviceConfiguration.getPortSubnet(deviceId, outport);
840 if (subnet == null) {
841 outvlan = VlanId.vlanId(ASSIGNED_VLAN_NO_SUBNET);
842 } else {
843 outvlan = getSubnetAssignedVlanId(deviceId, subnet);
844 }
845 TrafficSelector meta = DefaultTrafficSelector.builder()
846 .matchVlanId(outvlan).build();
847
848 // All forwarding is via Groups. Drivers can re-purpose to flow-actions if needed.
849 int portNextObjId = getPortNextObjectiveId(deviceId, outport,
850 tbuilder.build(),
851 meta);
Charles Chanf4586112015-11-09 16:37:23 -0800852
853 return DefaultForwardingObjective.builder()
854 .withFlag(ForwardingObjective.Flag.SPECIFIC)
855 .withSelector(sbuilder.build())
Saurav Das2d94d312015-11-24 23:21:05 -0800856 .nextStep(portNextObjId)
Charles Chanf4586112015-11-09 16:37:23 -0800857 .withPriority(100)
858 .fromApp(appId)
859 .makePermanent();
860 }
861
862 private void processHostAddedEvent(HostEvent event) {
863 MacAddress mac = event.subject().mac();
864 VlanId vlanId = event.subject().vlan();
865 DeviceId deviceId = event.subject().location().deviceId();
866 PortNumber port = event.subject().location().port();
867 Set<IpAddress> ips = event.subject().ipAddresses();
Saurav Das2d94d312015-11-24 23:21:05 -0800868 log.info("Host {}/{} is added at {}:{}", mac, vlanId, deviceId, port);
Charles Chanf4586112015-11-09 16:37:23 -0800869
Charles Chanf4586112015-11-09 16:37:23 -0800870 // Populate bridging table entry
Saurav Das2d94d312015-11-24 23:21:05 -0800871 log.debug("Populate L2 table entry for host {} at {}:{}",
872 mac, deviceId, port);
Charles Chanf4586112015-11-09 16:37:23 -0800873 ForwardingObjective.Builder fob =
Saurav Das2d94d312015-11-24 23:21:05 -0800874 getForwardingObjectiveBuilder(deviceId, mac, vlanId, port);
Charles Chanf4586112015-11-09 16:37:23 -0800875 flowObjectiveService.forward(deviceId, fob.add(
876 new BridgingTableObjectiveContext(mac, vlanId)
877 ));
878
879 // Populate IP table entry
880 ips.forEach(ip -> {
881 if (ip.isIp4()) {
882 routingRulePopulator.populateIpRuleForHost(
883 deviceId, ip.getIp4Address(), mac, port);
884 }
885 });
886 }
887
888 private void processHostRemoveEvent(HostEvent event) {
889 MacAddress mac = event.subject().mac();
890 VlanId vlanId = event.subject().vlan();
891 DeviceId deviceId = event.subject().location().deviceId();
892 PortNumber port = event.subject().location().port();
893 Set<IpAddress> ips = event.subject().ipAddresses();
894 log.debug("Host {}/{} is removed from {}:{}", mac, vlanId, deviceId, port);
895
896 // Revoke bridging table entry
897 ForwardingObjective.Builder fob =
Saurav Das2d94d312015-11-24 23:21:05 -0800898 getForwardingObjectiveBuilder(deviceId, mac, vlanId, port);
Charles Chanf4586112015-11-09 16:37:23 -0800899 flowObjectiveService.forward(deviceId, fob.remove(
900 new BridgingTableObjectiveContext(mac, vlanId)
901 ));
902
903 // Revoke IP table entry
904 ips.forEach(ip -> {
905 if (ip.isIp4()) {
906 routingRulePopulator.revokeIpRuleForHost(
907 deviceId, ip.getIp4Address(), mac, port);
908 }
909 });
910 }
911
912 private void processHostMovedEvent(HostEvent event) {
913 MacAddress mac = event.subject().mac();
914 VlanId vlanId = event.subject().vlan();
915 DeviceId prevDeviceId = event.prevSubject().location().deviceId();
916 PortNumber prevPort = event.prevSubject().location().port();
917 Set<IpAddress> prevIps = event.prevSubject().ipAddresses();
918 DeviceId newDeviceId = event.subject().location().deviceId();
919 PortNumber newPort = event.subject().location().port();
920 Set<IpAddress> newIps = event.subject().ipAddresses();
921 log.debug("Host {}/{} is moved from {}:{} to {}:{}",
922 mac, vlanId, prevDeviceId, prevPort, newDeviceId, newPort);
923
924 // Revoke previous bridging table entry
925 ForwardingObjective.Builder prevFob =
Saurav Das2d94d312015-11-24 23:21:05 -0800926 getForwardingObjectiveBuilder(prevDeviceId, mac, vlanId, prevPort);
Charles Chanf4586112015-11-09 16:37:23 -0800927 flowObjectiveService.forward(prevDeviceId, prevFob.remove(
928 new BridgingTableObjectiveContext(mac, vlanId)
929 ));
930
931 // Revoke previous IP table entry
932 prevIps.forEach(ip -> {
933 if (ip.isIp4()) {
934 routingRulePopulator.revokeIpRuleForHost(
935 prevDeviceId, ip.getIp4Address(), mac, prevPort);
936 }
937 });
938
939 // Populate new bridging table entry
940 ForwardingObjective.Builder newFob =
Saurav Das2d94d312015-11-24 23:21:05 -0800941 getForwardingObjectiveBuilder(newDeviceId, mac, vlanId, newPort);
Charles Chanf4586112015-11-09 16:37:23 -0800942 flowObjectiveService.forward(newDeviceId, newFob.add(
943 new BridgingTableObjectiveContext(mac, vlanId)
944 ));
945
946 // Populate new IP table entry
947 newIps.forEach(ip -> {
948 if (ip.isIp4()) {
949 routingRulePopulator.populateIpRuleForHost(
950 newDeviceId, ip.getIp4Address(), mac, newPort);
951 }
952 });
953 }
954
955 private void processHostUpdatedEvent(HostEvent event) {
956 MacAddress mac = event.subject().mac();
957 VlanId vlanId = event.subject().vlan();
958 DeviceId prevDeviceId = event.prevSubject().location().deviceId();
959 PortNumber prevPort = event.prevSubject().location().port();
960 Set<IpAddress> prevIps = event.prevSubject().ipAddresses();
961 DeviceId newDeviceId = event.subject().location().deviceId();
962 PortNumber newPort = event.subject().location().port();
963 Set<IpAddress> newIps = event.subject().ipAddresses();
964 log.debug("Host {}/{} is updated", mac, vlanId);
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 IP table entry
975 newIps.forEach(ip -> {
976 if (ip.isIp4()) {
977 routingRulePopulator.populateIpRuleForHost(
978 newDeviceId, ip.getIp4Address(), mac, newPort);
979 }
980 });
981 }
982
983 @Override
984 public void event(HostEvent event) {
985 // Do not proceed without mastership
986 DeviceId deviceId = event.subject().location().deviceId();
987 if (!mastershipService.isLocalMaster(deviceId)) {
988 return;
989 }
990
991 switch (event.type()) {
992 case HOST_ADDED:
993 processHostAddedEvent(event);
994 break;
995 case HOST_MOVED:
996 processHostMovedEvent(event);
997 break;
998 case HOST_REMOVED:
999 processHostRemoveEvent(event);
1000 break;
1001 case HOST_UPDATED:
1002 processHostUpdatedEvent(event);
1003 break;
1004 default:
1005 log.warn("Unsupported host event type: {}", event.type());
1006 break;
1007 }
1008 }
1009 }
1010
1011 private static class BridgingTableObjectiveContext implements ObjectiveContext {
1012 final MacAddress mac;
1013 final VlanId vlanId;
1014
1015 BridgingTableObjectiveContext(MacAddress mac, VlanId vlanId) {
1016 this.mac = mac;
1017 this.vlanId = vlanId;
1018 }
1019
1020 @Override
1021 public void onSuccess(Objective objective) {
1022 if (objective.op() == Objective.Operation.ADD) {
1023 log.debug("Successfully populate bridging table entry for {}/{}",
1024 mac, vlanId);
1025 } else {
1026 log.debug("Successfully revoke bridging table entry for {}/{}",
1027 mac, vlanId);
1028 }
1029 }
1030
1031 @Override
1032 public void onError(Objective objective, ObjectiveError error) {
1033 if (objective.op() == Objective.Operation.ADD) {
1034 log.debug("Fail to populate bridging table entry for {}/{}. {}",
1035 mac, vlanId, error);
1036 } else {
1037 log.debug("Fail to revoke bridging table entry for {}/{}. {}",
1038 mac, vlanId, error);
1039 }
1040 }
1041 }
sangho80f11cb2015-04-01 13:05:26 -07001042}