blob: f6bf649cb2f526ea228591e9244e959d0084dac8 [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 Chan0b4e6182015-11-03 10:42:14 -080054import org.onosproject.segmentrouting.config.DeviceConfigNotFoundException;
55import org.onosproject.segmentrouting.config.DeviceConfiguration;
Charles Chand6832882015-10-05 17:50:33 -070056import org.onosproject.segmentrouting.config.SegmentRoutingConfig;
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -070057import org.onosproject.segmentrouting.grouphandler.DefaultGroupHandler;
58import org.onosproject.segmentrouting.grouphandler.NeighborSet;
Srikanth Vavilapalli23181912015-05-04 09:48:09 -070059import org.onosproject.segmentrouting.grouphandler.NeighborSetNextObjectiveStoreKey;
sanghob35a6192015-04-01 13:05:26 -070060import org.onosproject.mastership.MastershipService;
61import org.onosproject.net.Device;
62import org.onosproject.net.DeviceId;
63import org.onosproject.net.Link;
sanghob35a6192015-04-01 13:05:26 -070064import org.onosproject.net.Port;
65import org.onosproject.net.device.DeviceEvent;
66import org.onosproject.net.device.DeviceListener;
67import org.onosproject.net.device.DeviceService;
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070068import org.onosproject.net.flowobjective.FlowObjectiveService;
sanghob35a6192015-04-01 13:05:26 -070069import org.onosproject.net.host.HostService;
70import org.onosproject.net.intent.IntentService;
71import org.onosproject.net.link.LinkEvent;
72import org.onosproject.net.link.LinkListener;
73import org.onosproject.net.link.LinkService;
74import org.onosproject.net.packet.InboundPacket;
75import org.onosproject.net.packet.PacketContext;
76import org.onosproject.net.packet.PacketProcessor;
77import org.onosproject.net.packet.PacketService;
78import org.onosproject.net.topology.TopologyService;
Charles Chanc42e84e2015-10-20 16:24:19 -070079import org.onosproject.segmentrouting.grouphandler.SubnetNextObjectiveStoreKey;
Srikanth Vavilapalli23181912015-05-04 09:48:09 -070080import org.onosproject.store.service.EventuallyConsistentMap;
81import org.onosproject.store.service.EventuallyConsistentMapBuilder;
82import org.onosproject.store.service.StorageService;
83import org.onosproject.store.service.WallClockTimestamp;
sanghob35a6192015-04-01 13:05:26 -070084import org.slf4j.Logger;
85import org.slf4j.LoggerFactory;
86
Srikanth Vavilapalli23181912015-05-04 09:48:09 -070087import java.net.URI;
Saurav Das0e99e2b2015-10-28 12:39:42 -070088import java.util.Collections;
Srikanth Vavilapalli23181912015-05-04 09:48:09 -070089import java.util.HashSet;
sangho1e575652015-05-14 00:39:53 -070090import java.util.List;
sanghob35a6192015-04-01 13:05:26 -070091import java.util.Map;
Saurav Das0e99e2b2015-10-28 12:39:42 -070092import java.util.Set;
sanghob35a6192015-04-01 13:05:26 -070093import java.util.concurrent.ConcurrentHashMap;
94import java.util.concurrent.ConcurrentLinkedQueue;
95import java.util.concurrent.Executors;
96import java.util.concurrent.ScheduledExecutorService;
97import java.util.concurrent.ScheduledFuture;
98import java.util.concurrent.TimeUnit;
99
100@SuppressWarnings("ALL")
sangho1e575652015-05-14 00:39:53 -0700101@Service
sanghob35a6192015-04-01 13:05:26 -0700102@Component(immediate = true)
sangho1e575652015-05-14 00:39:53 -0700103public class SegmentRoutingManager implements SegmentRoutingService {
sanghob35a6192015-04-01 13:05:26 -0700104
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700105 private static Logger log = LoggerFactory
106 .getLogger(SegmentRoutingManager.class);
sanghob35a6192015-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 Vavilapallif5b234a2015-04-21 13:04:13 -0700127 protected FlowObjectiveService flowObjectiveService;
sanghob35a6192015-04-01 13:05:26 -0700128
129 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
130 protected LinkService linkService;
131
132 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
sanghob35a6192015-04-01 13:05:26 -0700133 protected MastershipService mastershipService;
sangho1e575652015-05-14 00:39:53 -0700134
Srikanth Vavilapalli4db76e32015-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;
sanghob35a6192015-04-01 13:05:26 -0700139 protected ApplicationId appId;
sangho666cd6d2015-04-14 16:27:13 -0700140 protected DeviceConfiguration deviceConfiguration = null;
sanghob35a6192015-04-01 13:05:26 -0700141
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700142 private DefaultRoutingHandler defaultRoutingHandler = null;
sangho1e575652015-05-14 00:39:53 -0700143 private TunnelHandler tunnelHandler = null;
144 private PolicyHandler policyHandler = null;
Charles Chanb8e10c82015-10-14 11:24:40 -0700145 private InternalPacketProcessor processor = null;
146 private InternalLinkListener linkListener = null;
147 private InternalDeviceListener deviceListener = null;
sanghob35a6192015-04-01 13:05:26 -0700148 private InternalEventHandler eventHandler = new InternalEventHandler();
149
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700150 private ScheduledExecutorService executorService = Executors
151 .newScheduledThreadPool(1);
sanghob35a6192015-04-01 13:05:26 -0700152
153 private static ScheduledFuture<?> eventHandlerFuture = null;
154 private ConcurrentLinkedQueue<Event> eventQueue = new ConcurrentLinkedQueue<Event>();
Charles Chan68aa62d2015-11-09 16:37:23 -0800155 private Map<DeviceId, DefaultGroupHandler> groupHandlerMap =
156 new ConcurrentHashMap<DeviceId, DefaultGroupHandler>();
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700157 // Per device next objective ID store with (device id + neighbor set) as key
Charles Chan68aa62d2015-11-09 16:37:23 -0800158 private EventuallyConsistentMap<NeighborSetNextObjectiveStoreKey, Integer>
159 nsNextObjStore = null;
160 private EventuallyConsistentMap<SubnetNextObjectiveStoreKey, Integer>
161 subnetNextObjStore = null;
sangho0b2b6d12015-05-20 22:16:38 -0700162 private EventuallyConsistentMap<String, Tunnel> tunnelStore = null;
163 private EventuallyConsistentMap<String, Policy> policyStore = null;
Saurav Das0e99e2b2015-10-28 12:39:42 -0700164 // Per device, per-subnet assigned-vlans store, with (device id + subnet
165 // IPv4 prefix) as key
166 private EventuallyConsistentMap<SubnetAssignedVidStoreKey, VlanId>
167 subnetVidStore = null;
sangho0b2b6d12015-05-20 22:16:38 -0700168
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700169 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
170 protected StorageService storageService;
sanghob35a6192015-04-01 13:05:26 -0700171
Charles Chand6832882015-10-05 17:50:33 -0700172 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
173 protected NetworkConfigRegistry cfgService;
174
Charles Chan4636be02015-10-07 14:21:45 -0700175 private final InternalConfigListener cfgListener =
176 new InternalConfigListener(this);
177
Charles Chand6832882015-10-05 17:50:33 -0700178 private final ConfigFactory cfgFactory =
179 new ConfigFactory(SubjectFactories.DEVICE_SUBJECT_FACTORY,
180 SegmentRoutingConfig.class,
181 "segmentrouting") {
182 @Override
183 public SegmentRoutingConfig createConfig() {
184 return new SegmentRoutingConfig();
185 }
186 };
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700187
Charles Chan68aa62d2015-11-09 16:37:23 -0800188 private final HostListener hostListener = new InternalHostListener();
189
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700190 private Object threadSchedulerLock = new Object();
191 private static int numOfEventsQueued = 0;
192 private static int numOfEventsExecuted = 0;
sanghob35a6192015-04-01 13:05:26 -0700193 private static int numOfHandlerExecution = 0;
194 private static int numOfHandlerScheduled = 0;
195
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700196 private KryoNamespace.Builder kryoBuilder = null;
197
Saurav Das0e99e2b2015-10-28 12:39:42 -0700198 private static final short ASSIGNED_VLAN_START = 4093;
199 public static final short ASSIGNED_VLAN_NO_SUBNET = 4094;
200
sanghob35a6192015-04-01 13:05:26 -0700201 @Activate
202 protected void activate() {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700203 appId = coreService
204 .registerApplication("org.onosproject.segmentrouting");
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700205
206 kryoBuilder = new KryoNamespace.Builder()
207 .register(NeighborSetNextObjectiveStoreKey.class,
Charles Chanc42e84e2015-10-20 16:24:19 -0700208 SubnetNextObjectiveStoreKey.class,
209 SubnetAssignedVidStoreKey.class,
sangho0b2b6d12015-05-20 22:16:38 -0700210 NeighborSet.class,
211 DeviceId.class,
212 URI.class,
213 WallClockTimestamp.class,
214 org.onosproject.cluster.NodeId.class,
215 HashSet.class,
216 Tunnel.class,
217 DefaultTunnel.class,
218 Policy.class,
219 TunnelPolicy.class,
Saurav Das0e99e2b2015-10-28 12:39:42 -0700220 Policy.Type.class,
Charles Chanc42e84e2015-10-20 16:24:19 -0700221 VlanId.class,
222 Ip4Address.class,
223 Ip4Prefix.class,
224 IpAddress.Version.class,
225 ConnectPoint.class
sangho0b2b6d12015-05-20 22:16:38 -0700226 );
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700227
228 log.debug("Creating EC map nsnextobjectivestore");
229 EventuallyConsistentMapBuilder<NeighborSetNextObjectiveStoreKey, Integer>
230 nsNextObjMapBuilder = storageService.eventuallyConsistentMapBuilder();
231
232 nsNextObjStore = nsNextObjMapBuilder
233 .withName("nsnextobjectivestore")
234 .withSerializer(kryoBuilder)
Madan Jampanibcf1a482015-06-24 19:05:56 -0700235 .withTimestampProvider((k, v) -> new WallClockTimestamp())
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700236 .build();
237 log.trace("Current size {}", nsNextObjStore.size());
238
Charles Chanc42e84e2015-10-20 16:24:19 -0700239 log.debug("Creating EC map subnetnextobjectivestore");
240 EventuallyConsistentMapBuilder<SubnetNextObjectiveStoreKey, Integer>
241 subnetNextObjMapBuilder = storageService.eventuallyConsistentMapBuilder();
242
243 subnetNextObjStore = subnetNextObjMapBuilder
244 .withName("subnetnextobjectivestore")
245 .withSerializer(kryoBuilder)
246 .withTimestampProvider((k, v) -> new WallClockTimestamp())
247 .build();
248
sangho0b2b6d12015-05-20 22:16:38 -0700249 EventuallyConsistentMapBuilder<String, Tunnel> tunnelMapBuilder =
250 storageService.eventuallyConsistentMapBuilder();
251
252 tunnelStore = tunnelMapBuilder
253 .withName("tunnelstore")
254 .withSerializer(kryoBuilder)
Madan Jampanibcf1a482015-06-24 19:05:56 -0700255 .withTimestampProvider((k, v) -> new WallClockTimestamp())
sangho0b2b6d12015-05-20 22:16:38 -0700256 .build();
257
258 EventuallyConsistentMapBuilder<String, Policy> policyMapBuilder =
259 storageService.eventuallyConsistentMapBuilder();
260
261 policyStore = policyMapBuilder
262 .withName("policystore")
263 .withSerializer(kryoBuilder)
Madan Jampanibcf1a482015-06-24 19:05:56 -0700264 .withTimestampProvider((k, v) -> new WallClockTimestamp())
sangho0b2b6d12015-05-20 22:16:38 -0700265 .build();
266
Saurav Das0e99e2b2015-10-28 12:39:42 -0700267 EventuallyConsistentMapBuilder<SubnetAssignedVidStoreKey, VlanId>
268 subnetVidStoreMapBuilder = storageService.eventuallyConsistentMapBuilder();
269
270 subnetVidStore = subnetVidStoreMapBuilder
271 .withName("subnetvidstore")
272 .withSerializer(kryoBuilder)
273 .withTimestampProvider((k, v) -> new WallClockTimestamp())
274 .build();
275
Charles Chand6832882015-10-05 17:50:33 -0700276 cfgService.addListener(cfgListener);
277 cfgService.registerConfigFactory(cfgFactory);
Charles Chand6832882015-10-05 17:50:33 -0700278
Charles Chan68aa62d2015-11-09 16:37:23 -0800279 hostService.addListener(hostListener);
280
Charles Chanb8e10c82015-10-14 11:24:40 -0700281 processor = new InternalPacketProcessor();
282 linkListener = new InternalLinkListener();
283 deviceListener = new InternalDeviceListener();
284
285 packetService.addProcessor(processor, PacketProcessor.director(2));
286 linkService.addListener(linkListener);
287 deviceService.addListener(deviceListener);
288
289 cfgListener.configureNetwork();
290
sanghob35a6192015-04-01 13:05:26 -0700291 log.info("Started");
292 }
293
294 @Deactivate
295 protected void deactivate() {
Charles Chand6832882015-10-05 17:50:33 -0700296 cfgService.removeListener(cfgListener);
297 cfgService.unregisterConfigFactory(cfgFactory);
298
sanghob35a6192015-04-01 13:05:26 -0700299 packetService.removeProcessor(processor);
Charles Chanb8e10c82015-10-14 11:24:40 -0700300 linkService.removeListener(linkListener);
301 deviceService.removeListener(deviceListener);
sanghob35a6192015-04-01 13:05:26 -0700302 processor = null;
Charles Chanb8e10c82015-10-14 11:24:40 -0700303 linkListener = null;
304 deviceService = null;
305
306 groupHandlerMap.clear();
307
sanghob35a6192015-04-01 13:05:26 -0700308 log.info("Stopped");
309 }
310
sangho1e575652015-05-14 00:39:53 -0700311
312 @Override
313 public List<Tunnel> getTunnels() {
314 return tunnelHandler.getTunnels();
315 }
316
317 @Override
sangho71abe1b2015-06-29 14:58:47 -0700318 public TunnelHandler.Result createTunnel(Tunnel tunnel) {
319 return tunnelHandler.createTunnel(tunnel);
sangho1e575652015-05-14 00:39:53 -0700320 }
321
322 @Override
sangho71abe1b2015-06-29 14:58:47 -0700323 public TunnelHandler.Result removeTunnel(Tunnel tunnel) {
sangho1e575652015-05-14 00:39:53 -0700324 for (Policy policy: policyHandler.getPolicies()) {
325 if (policy.type() == Policy.Type.TUNNEL_FLOW) {
326 TunnelPolicy tunnelPolicy = (TunnelPolicy) policy;
327 if (tunnelPolicy.tunnelId().equals(tunnel.id())) {
328 log.warn("Cannot remove the tunnel used by a policy");
sangho71abe1b2015-06-29 14:58:47 -0700329 return TunnelHandler.Result.TUNNEL_IN_USE;
sangho1e575652015-05-14 00:39:53 -0700330 }
331 }
332 }
sangho71abe1b2015-06-29 14:58:47 -0700333 return tunnelHandler.removeTunnel(tunnel);
sangho1e575652015-05-14 00:39:53 -0700334 }
335
336 @Override
sangho71abe1b2015-06-29 14:58:47 -0700337 public PolicyHandler.Result removePolicy(Policy policy) {
338 return policyHandler.removePolicy(policy);
sangho1e575652015-05-14 00:39:53 -0700339 }
340
341 @Override
sangho71abe1b2015-06-29 14:58:47 -0700342 public PolicyHandler.Result createPolicy(Policy policy) {
343 return policyHandler.createPolicy(policy);
sangho1e575652015-05-14 00:39:53 -0700344 }
345
346 @Override
347 public List<Policy> getPolicies() {
348 return policyHandler.getPolicies();
349 }
350
sanghof9d0bf12015-05-19 11:57:42 -0700351 /**
352 * Returns the tunnel object with the tunnel ID.
353 *
354 * @param tunnelId Tunnel ID
355 * @return Tunnel reference
356 */
sangho1e575652015-05-14 00:39:53 -0700357 public Tunnel getTunnel(String tunnelId) {
358 return tunnelHandler.getTunnel(tunnelId);
359 }
360
sanghob35a6192015-04-01 13:05:26 -0700361 /**
Saurav Das0e99e2b2015-10-28 12:39:42 -0700362 * Returns the vlan-id assigned to the subnet configured for a device.
363 * If no vlan-id has been assigned, a new one is assigned out of a pool of ids,
364 * if and only if this controller instance is the master for the device.
365 * <p>
366 * USAGE: The assigned vlans are meant to be applied to untagged packets on those
367 * switches/pipelines that need this functionality. These vids are meant
368 * to be used internally within a switch, and thus need to be unique only
369 * on a switch level. Note that packets never go out on the wire with these
370 * vlans. Currently, vlan ids are assigned from value 4093 down.
371 * Vlan id 4094 expected to be used for all ports that are not assigned subnets.
372 * Vlan id 4095 is reserved and unused. Only a single vlan id is assigned
373 * per subnet.
374 * XXX This method should avoid any vlans configured on the ports, but
375 * currently the app works only on untagged packets and as a result
376 * ignores any vlan configuration.
sanghob35a6192015-04-01 13:05:26 -0700377 *
Saurav Das0e99e2b2015-10-28 12:39:42 -0700378 * @param deviceId switch dpid
379 * @param subnet IPv4 prefix for which assigned vlan is desired
380 * @return VlanId assigned for the subnet on the device, or
381 * null if no vlan assignment was found and this instance is not
382 * the master for the device.
sanghob35a6192015-04-01 13:05:26 -0700383 */
Saurav Das0e99e2b2015-10-28 12:39:42 -0700384 public VlanId getSubnetAssignedVlanId(DeviceId deviceId, Ip4Prefix subnet) {
385 VlanId assignedVid = subnetVidStore.get(new SubnetAssignedVidStoreKey(
386 deviceId, subnet));
387 if (assignedVid != null) {
388 log.debug("Query for subnet:{} on device:{} returned assigned-vlan "
389 + "{}", subnet, deviceId, assignedVid);
390 return assignedVid;
391 }
392 //check mastership for the right to assign a vlan
393 if (!mastershipService.isLocalMaster(deviceId)) {
394 log.warn("This controller instance is not the master for device {}. "
395 + "Cannot assign vlan-id for subnet {}", deviceId, subnet);
396 return null;
397 }
398 // vlan assignment is expensive but done only once
Charles Chan9f676b62015-10-29 14:58:10 -0700399 Set<Ip4Prefix> configuredSubnets = deviceConfiguration.getSubnets(deviceId);
Saurav Das0e99e2b2015-10-28 12:39:42 -0700400 Set<Short> assignedVlans = new HashSet<>();
401 Set<Ip4Prefix> unassignedSubnets = new HashSet<>();
402 for (Ip4Prefix sub : configuredSubnets) {
403 VlanId v = subnetVidStore.get(new SubnetAssignedVidStoreKey(deviceId,
404 sub));
405 if (v != null) {
406 assignedVlans.add(v.toShort());
407 } else {
408 unassignedSubnets.add(sub);
409 }
410 }
411 short nextAssignedVlan = ASSIGNED_VLAN_START;
412 if (!assignedVlans.isEmpty()) {
413 nextAssignedVlan = (short) (Collections.min(assignedVlans) - 1);
414 }
415 for (Ip4Prefix unsub : unassignedSubnets) {
416 subnetVidStore.put(new SubnetAssignedVidStoreKey(deviceId, unsub),
417 VlanId.vlanId(nextAssignedVlan--));
418 log.info("Assigned vlan: {} to subnet: {} on device: {}",
419 nextAssignedVlan + 1, unsub, deviceId);
sanghob35a6192015-04-01 13:05:26 -0700420 }
421
Saurav Das0e99e2b2015-10-28 12:39:42 -0700422 return subnetVidStore.get(new SubnetAssignedVidStoreKey(deviceId, subnet));
sanghob35a6192015-04-01 13:05:26 -0700423 }
424
sangho1e575652015-05-14 00:39:53 -0700425 /**
Saurav Das0e99e2b2015-10-28 12:39:42 -0700426 * Returns the next objective ID for the given NeighborSet.
Saurav Das8a0732e2015-11-20 15:27:53 -0800427 * If the nextObjective does not exist, a new one is created and
428 * it's id is returned.
429 * TODO move the side-effect creation of a Next Objective into a new method
sangho1e575652015-05-14 00:39:53 -0700430 *
sanghof9d0bf12015-05-19 11:57:42 -0700431 * @param deviceId Device ID
432 * @param ns NegighborSet
Saurav Das8a0732e2015-11-20 15:27:53 -0800433 * @param meta metadata passed into the creation of a Next Objective
434 * @return next objective ID or -1 if an error was encountered during the
435 * creation of the nextObjective
sangho1e575652015-05-14 00:39:53 -0700436 */
Saurav Das8a0732e2015-11-20 15:27:53 -0800437 public int getNextObjectiveId(DeviceId deviceId, NeighborSet ns,
438 TrafficSelector meta) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700439 if (groupHandlerMap.get(deviceId) != null) {
440 log.trace("getNextObjectiveId query in device {}", deviceId);
441 return groupHandlerMap
Saurav Das8a0732e2015-11-20 15:27:53 -0800442 .get(deviceId).getNextObjectiveId(ns, meta);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700443 } else {
444 log.warn("getNextObjectiveId query in device {} not found", deviceId);
445 return -1;
446 }
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700447 }
448
Charles Chanc42e84e2015-10-20 16:24:19 -0700449 /**
450 * Returns the next objective ID for the Subnet given. If the nextObjectiveID does not exist,
451 * a new one is created and returned.
452 *
453 * @param deviceId Device ID
454 * @param prefix Subnet
455 * @return next objective ID
456 */
457 public int getSubnetNextObjectiveId(DeviceId deviceId, IpPrefix prefix) {
458 if (groupHandlerMap.get(deviceId) != null) {
459 log.trace("getSubnetNextObjectiveId query in device {}", deviceId);
460 return groupHandlerMap
461 .get(deviceId).getSubnetNextObjectiveId(prefix);
462 } else {
463 log.warn("getSubnetNextObjectiveId query in device {} not found", deviceId);
464 return -1;
465 }
466 }
467
sanghob35a6192015-04-01 13:05:26 -0700468 private class InternalPacketProcessor implements PacketProcessor {
sanghob35a6192015-04-01 13:05:26 -0700469 @Override
470 public void process(PacketContext context) {
471
472 if (context.isHandled()) {
473 return;
474 }
475
476 InboundPacket pkt = context.inPacket();
477 Ethernet ethernet = pkt.parsed();
478
479 if (ethernet.getEtherType() == Ethernet.TYPE_ARP) {
480 arpHandler.processPacketIn(pkt);
481 } else if (ethernet.getEtherType() == Ethernet.TYPE_IPV4) {
482 IPv4 ipPacket = (IPv4) ethernet.getPayload();
483 ipHandler.addToPacketBuffer(ipPacket);
484 if (ipPacket.getProtocol() == IPv4.PROTOCOL_ICMP) {
485 icmpHandler.processPacketIn(pkt);
486 } else {
487 ipHandler.processPacketIn(pkt);
488 }
489 }
490 }
491 }
492
493 private class InternalLinkListener implements LinkListener {
494 @Override
495 public void event(LinkEvent event) {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700496 if (event.type() == LinkEvent.Type.LINK_ADDED
497 || event.type() == LinkEvent.Type.LINK_REMOVED) {
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700498 log.debug("Event {} received from Link Service", event.type());
sanghob35a6192015-04-01 13:05:26 -0700499 scheduleEventHandlerIfNotScheduled(event);
500 }
501 }
502 }
503
504 private class InternalDeviceListener implements DeviceListener {
sanghob35a6192015-04-01 13:05:26 -0700505 @Override
506 public void event(DeviceEvent event) {
sanghob35a6192015-04-01 13:05:26 -0700507 switch (event.type()) {
508 case DEVICE_ADDED:
509 case PORT_REMOVED:
sangho20eff1d2015-04-13 15:15:58 -0700510 case DEVICE_UPDATED:
511 case DEVICE_AVAILABILITY_CHANGED:
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700512 log.debug("Event {} received from Device Service", event.type());
sanghob35a6192015-04-01 13:05:26 -0700513 scheduleEventHandlerIfNotScheduled(event);
514 break;
515 default:
516 }
517 }
518 }
519
sanghob35a6192015-04-01 13:05:26 -0700520 private void scheduleEventHandlerIfNotScheduled(Event event) {
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700521 synchronized (threadSchedulerLock) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700522 eventQueue.add(event);
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700523 numOfEventsQueued++;
524
525 if ((numOfHandlerScheduled - numOfHandlerExecution) == 0) {
526 //No pending scheduled event handling threads. So start a new one.
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700527 eventHandlerFuture = executorService
528 .schedule(eventHandler, 100, TimeUnit.MILLISECONDS);
529 numOfHandlerScheduled++;
530 }
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700531 log.trace("numOfEventsQueued {}, numOfEventHanlderScheduled {}",
532 numOfEventsQueued,
533 numOfHandlerScheduled);
sanghob35a6192015-04-01 13:05:26 -0700534 }
sanghob35a6192015-04-01 13:05:26 -0700535 }
536
537 private class InternalEventHandler implements Runnable {
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700538 @Override
sanghob35a6192015-04-01 13:05:26 -0700539 public void run() {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700540 try {
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700541 while (true) {
542 Event event = null;
543 synchronized (threadSchedulerLock) {
544 if (!eventQueue.isEmpty()) {
545 event = eventQueue.poll();
546 numOfEventsExecuted++;
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700547 } else {
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700548 numOfHandlerExecution++;
549 log.debug("numOfHandlerExecution {} numOfEventsExecuted {}",
550 numOfHandlerExecution, numOfEventsExecuted);
551 break;
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700552 }
sangho20eff1d2015-04-13 15:15:58 -0700553 }
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700554 if (event.type() == LinkEvent.Type.LINK_ADDED) {
555 processLinkAdded((Link) event.subject());
556 } else if (event.type() == LinkEvent.Type.LINK_REMOVED) {
557 processLinkRemoved((Link) event.subject());
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700558 } else if (event.type() == DeviceEvent.Type.DEVICE_ADDED ||
559 event.type() == DeviceEvent.Type.DEVICE_AVAILABILITY_CHANGED ||
560 event.type() == DeviceEvent.Type.DEVICE_UPDATED) {
561 if (deviceService.isAvailable(((Device) event.subject()).id())) {
Saurav Das837e0bb2015-10-30 17:45:38 -0700562 log.info("Processing device event {} for available device {}",
563 event.type(), ((Device) event.subject()).id());
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700564 processDeviceAdded((Device) event.subject());
565 }
566 } else if (event.type() == DeviceEvent.Type.PORT_REMOVED) {
567 processPortRemoved((Device) event.subject(),
568 ((DeviceEvent) event).port());
569 } else {
570 log.warn("Unhandled event type: {}", event.type());
571 }
sanghob35a6192015-04-01 13:05:26 -0700572 }
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700573 } catch (Exception e) {
574 log.error("SegmentRouting event handler "
575 + "thread thrown an exception: {}", e);
sanghob35a6192015-04-01 13:05:26 -0700576 }
sanghob35a6192015-04-01 13:05:26 -0700577 }
578 }
579
sanghob35a6192015-04-01 13:05:26 -0700580 private void processLinkAdded(Link link) {
581 log.debug("A new link {} was added", link.toString());
Charles Chan0b4e6182015-11-03 10:42:14 -0800582 if (!deviceConfiguration.isConfigured(link.src().deviceId())) {
583 log.warn("Source device of this link is not configured.");
584 return;
585 }
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700586 //Irrespective whether the local is a MASTER or not for this device,
587 //create group handler instance and push default TTP flow rules.
588 //Because in a multi-instance setup, instances can initiate
589 //groups for any devices. Also the default TTP rules are needed
590 //to be pushed before inserting any IP table entries for any device
591 DefaultGroupHandler groupHandler = groupHandlerMap.get(link.src()
592 .deviceId());
593 if (groupHandler != null) {
Saurav Das8a0732e2015-11-20 15:27:53 -0800594 groupHandler.linkUp(link, mastershipService.isLocalMaster(
595 link.src().deviceId()));
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700596 } else {
597 Device device = deviceService.getDevice(link.src().deviceId());
598 if (device != null) {
599 log.warn("processLinkAdded: Link Added "
600 + "Notification without Device Added "
601 + "event, still handling it");
602 processDeviceAdded(device);
603 groupHandler = groupHandlerMap.get(link.src()
604 .deviceId());
Saurav Das8a0732e2015-11-20 15:27:53 -0800605 groupHandler.linkUp(link, mastershipService.isLocalMaster(device.id()));
sanghob35a6192015-04-01 13:05:26 -0700606 }
607 }
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700608
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700609 log.trace("Starting optimized route population process");
610 defaultRoutingHandler.populateRoutingRulesForLinkStatusChange(null);
611 //log.trace("processLinkAdded: re-starting route population process");
612 //defaultRoutingHandler.startPopulationProcess();
sanghob35a6192015-04-01 13:05:26 -0700613 }
614
615 private void processLinkRemoved(Link link) {
616 log.debug("A link {} was removed", link.toString());
sangho834e4b02015-05-01 09:38:25 -0700617 DefaultGroupHandler groupHandler = groupHandlerMap.get(link.src().deviceId());
618 if (groupHandler != null) {
619 groupHandler.portDown(link.src().port());
620 }
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700621 log.trace("Starting optimized route population process");
622 defaultRoutingHandler.populateRoutingRulesForLinkStatusChange(link);
623 //log.trace("processLinkRemoved: re-starting route population process");
624 //defaultRoutingHandler.startPopulationProcess();
sanghob35a6192015-04-01 13:05:26 -0700625 }
626
627 private void processDeviceAdded(Device device) {
628 log.debug("A new device with ID {} was added", device.id());
Charles Chan0b4e6182015-11-03 10:42:14 -0800629 if (deviceConfiguration == null || !deviceConfiguration.isConfigured(device.id())) {
Saurav Das2857f382015-11-03 14:39:27 -0800630 log.warn("Device configuration uploading. Device {} will be "
631 + "processed after config completes.", device.id());
632 return;
633 }
Saurav Das837e0bb2015-10-30 17:45:38 -0700634 // Irrespective of whether the local is a MASTER or not for this device,
635 // we need to create a SR-group-handler instance. This is because in a
636 // multi-instance setup, any instance can initiate forwarding/next-objectives
637 // for any switch (even if this instance is a SLAVE or not even connected
638 // to the switch). To handle this, a default-group-handler instance is necessary
639 // per switch.
Saurav Das2857f382015-11-03 14:39:27 -0800640 if (groupHandlerMap.get(device.id()) == null) {
Charles Chan0b4e6182015-11-03 10:42:14 -0800641 DefaultGroupHandler groupHandler;
642 try {
643 groupHandler = DefaultGroupHandler.
644 createGroupHandler(device.id(),
645 appId,
646 deviceConfiguration,
647 linkService,
648 flowObjectiveService,
649 nsNextObjStore,
650 subnetNextObjStore);
651 } catch (DeviceConfigNotFoundException e) {
652 log.warn(e.getMessage() + " Aborting processDeviceAdded.");
653 return;
654 }
Saurav Das2857f382015-11-03 14:39:27 -0800655 groupHandlerMap.put(device.id(), groupHandler);
656 // Also, in some cases, drivers may need extra
657 // information to process rules (eg. Router IP/MAC); and so, we send
658 // port addressing rules to the driver as well irrespective of whether
659 // this instance is the master or not.
660 defaultRoutingHandler.populatePortAddressingRules(device.id());
661 }
Charles Chanc42e84e2015-10-20 16:24:19 -0700662 if (mastershipService.isLocalMaster(device.id())) {
Saurav Das2857f382015-11-03 14:39:27 -0800663 DefaultGroupHandler groupHandler = groupHandlerMap.get(device.id());
Charles Chanc42e84e2015-10-20 16:24:19 -0700664 groupHandler.createGroupsFromSubnetConfig();
Charles Chan68aa62d2015-11-09 16:37:23 -0800665 routingRulePopulator.populateSubnetBroadcastRule(device.id());
Charles Chanc42e84e2015-10-20 16:24:19 -0700666 }
sanghob35a6192015-04-01 13:05:26 -0700667 }
668
669 private void processPortRemoved(Device device, Port port) {
670 log.debug("Port {} was removed", port.toString());
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700671 DefaultGroupHandler groupHandler = groupHandlerMap.get(device.id());
sanghob35a6192015-04-01 13:05:26 -0700672 if (groupHandler != null) {
673 groupHandler.portDown(port.number());
674 }
675 }
sangho1e575652015-05-14 00:39:53 -0700676
Charles Chand6832882015-10-05 17:50:33 -0700677 private class InternalConfigListener implements NetworkConfigListener {
Charles Chan4636be02015-10-07 14:21:45 -0700678 SegmentRoutingManager segmentRoutingManager;
679
680 public InternalConfigListener(SegmentRoutingManager srMgr) {
681 this.segmentRoutingManager = srMgr;
682 }
683
684 public void configureNetwork() {
685 deviceConfiguration = new DeviceConfiguration(segmentRoutingManager.cfgService);
686
687 arpHandler = new ArpHandler(segmentRoutingManager);
688 icmpHandler = new IcmpHandler(segmentRoutingManager);
689 ipHandler = new IpHandler(segmentRoutingManager);
690 routingRulePopulator = new RoutingRulePopulator(segmentRoutingManager);
691 defaultRoutingHandler = new DefaultRoutingHandler(segmentRoutingManager);
692
693 tunnelHandler = new TunnelHandler(linkService, deviceConfiguration,
694 groupHandlerMap, tunnelStore);
695 policyHandler = new PolicyHandler(appId, deviceConfiguration,
696 flowObjectiveService,
697 tunnelHandler, policyStore);
698
Charles Chan4636be02015-10-07 14:21:45 -0700699 for (Device device : deviceService.getDevices()) {
Saurav Das837e0bb2015-10-30 17:45:38 -0700700 // Irrespective of whether the local is a MASTER or not for this device,
701 // we need to create a SR-group-handler instance. This is because in a
702 // multi-instance setup, any instance can initiate forwarding/next-objectives
703 // for any switch (even if this instance is a SLAVE or not even connected
704 // to the switch). To handle this, a default-group-handler instance is necessary
705 // per switch.
Saurav Das2857f382015-11-03 14:39:27 -0800706 if (groupHandlerMap.get(device.id()) == null) {
Charles Chan0b4e6182015-11-03 10:42:14 -0800707 DefaultGroupHandler groupHandler;
708 try {
709 groupHandler = DefaultGroupHandler.
710 createGroupHandler(device.id(),
711 appId,
712 deviceConfiguration,
713 linkService,
714 flowObjectiveService,
715 nsNextObjStore,
716 subnetNextObjStore);
717 } catch (DeviceConfigNotFoundException e) {
718 log.warn(e.getMessage() + " Aborting configureNetwork.");
719 return;
720 }
Saurav Das2857f382015-11-03 14:39:27 -0800721 groupHandlerMap.put(device.id(), groupHandler);
Saurav Das837e0bb2015-10-30 17:45:38 -0700722
Saurav Das2857f382015-11-03 14:39:27 -0800723 // Also, in some cases, drivers may need extra
724 // information to process rules (eg. Router IP/MAC); and so, we send
725 // port addressing rules to the driver as well, irrespective of whether
726 // this instance is the master or not.
727 defaultRoutingHandler.populatePortAddressingRules(device.id());
728 }
Charles Chanc42e84e2015-10-20 16:24:19 -0700729 if (mastershipService.isLocalMaster(device.id())) {
Saurav Das2857f382015-11-03 14:39:27 -0800730 DefaultGroupHandler groupHandler = groupHandlerMap.get(device.id());
Charles Chanc42e84e2015-10-20 16:24:19 -0700731 groupHandler.createGroupsFromSubnetConfig();
Charles Chan68aa62d2015-11-09 16:37:23 -0800732 routingRulePopulator.populateSubnetBroadcastRule(device.id());
Charles Chanc42e84e2015-10-20 16:24:19 -0700733 }
Charles Chan4636be02015-10-07 14:21:45 -0700734 }
735
736 defaultRoutingHandler.startPopulationProcess();
737 }
738
Charles Chand6832882015-10-05 17:50:33 -0700739 @Override
740 public void event(NetworkConfigEvent event) {
Charles Chanb8e10c82015-10-14 11:24:40 -0700741 if (event.configClass().equals(SegmentRoutingConfig.class)) {
742 if (event.type() == NetworkConfigEvent.Type.CONFIG_ADDED) {
743 log.info("Network configuration added.");
744 configureNetwork();
745 }
746 if (event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED) {
747 log.info("Network configuration updated.");
748 // TODO support dynamic configuration
749 }
Charles Chand6832882015-10-05 17:50:33 -0700750 }
751 }
752 }
Charles Chan68aa62d2015-11-09 16:37:23 -0800753
754 private class InternalHostListener implements HostListener {
755 private ForwardingObjective.Builder getForwardingObjectiveBuilder(
756 MacAddress mac, VlanId vlanId, PortNumber port) {
757 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
758 sbuilder.matchEthDst(mac);
759 sbuilder.matchVlanId(vlanId);
760
761 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
762 // TODO Move popVlan from flow action to group action
763 tbuilder.immediate().popVlan();
764 tbuilder.immediate().setOutput(port);
765
766 return DefaultForwardingObjective.builder()
767 .withFlag(ForwardingObjective.Flag.SPECIFIC)
768 .withSelector(sbuilder.build())
769 .withTreatment(tbuilder.build())
770 .withPriority(100)
771 .fromApp(appId)
772 .makePermanent();
773 }
774
775 private void processHostAddedEvent(HostEvent event) {
776 MacAddress mac = event.subject().mac();
777 VlanId vlanId = event.subject().vlan();
778 DeviceId deviceId = event.subject().location().deviceId();
779 PortNumber port = event.subject().location().port();
780 Set<IpAddress> ips = event.subject().ipAddresses();
781 log.debug("Host {}/{} is added at {}:{}", mac, vlanId, deviceId, port);
782
783 // TODO Move bridging table population to a separate class
784 // Populate bridging table entry
785 ForwardingObjective.Builder fob =
786 getForwardingObjectiveBuilder(mac, vlanId, port);
787 flowObjectiveService.forward(deviceId, fob.add(
788 new BridgingTableObjectiveContext(mac, vlanId)
789 ));
790
791 // Populate IP table entry
792 ips.forEach(ip -> {
793 if (ip.isIp4()) {
794 routingRulePopulator.populateIpRuleForHost(
795 deviceId, ip.getIp4Address(), mac, port);
796 }
797 });
798 }
799
800 private void processHostRemoveEvent(HostEvent event) {
801 MacAddress mac = event.subject().mac();
802 VlanId vlanId = event.subject().vlan();
803 DeviceId deviceId = event.subject().location().deviceId();
804 PortNumber port = event.subject().location().port();
805 Set<IpAddress> ips = event.subject().ipAddresses();
806 log.debug("Host {}/{} is removed from {}:{}", mac, vlanId, deviceId, port);
807
808 // Revoke bridging table entry
809 ForwardingObjective.Builder fob =
810 getForwardingObjectiveBuilder(mac, vlanId, port);
811 flowObjectiveService.forward(deviceId, fob.remove(
812 new BridgingTableObjectiveContext(mac, vlanId)
813 ));
814
815 // Revoke IP table entry
816 ips.forEach(ip -> {
817 if (ip.isIp4()) {
818 routingRulePopulator.revokeIpRuleForHost(
819 deviceId, ip.getIp4Address(), mac, port);
820 }
821 });
822 }
823
824 private void processHostMovedEvent(HostEvent event) {
825 MacAddress mac = event.subject().mac();
826 VlanId vlanId = event.subject().vlan();
827 DeviceId prevDeviceId = event.prevSubject().location().deviceId();
828 PortNumber prevPort = event.prevSubject().location().port();
829 Set<IpAddress> prevIps = event.prevSubject().ipAddresses();
830 DeviceId newDeviceId = event.subject().location().deviceId();
831 PortNumber newPort = event.subject().location().port();
832 Set<IpAddress> newIps = event.subject().ipAddresses();
833 log.debug("Host {}/{} is moved from {}:{} to {}:{}",
834 mac, vlanId, prevDeviceId, prevPort, newDeviceId, newPort);
835
836 // Revoke previous bridging table entry
837 ForwardingObjective.Builder prevFob =
838 getForwardingObjectiveBuilder(mac, vlanId, prevPort);
839 flowObjectiveService.forward(prevDeviceId, prevFob.remove(
840 new BridgingTableObjectiveContext(mac, vlanId)
841 ));
842
843 // Revoke previous IP table entry
844 prevIps.forEach(ip -> {
845 if (ip.isIp4()) {
846 routingRulePopulator.revokeIpRuleForHost(
847 prevDeviceId, ip.getIp4Address(), mac, prevPort);
848 }
849 });
850
851 // Populate new bridging table entry
852 ForwardingObjective.Builder newFob =
853 getForwardingObjectiveBuilder(mac, vlanId, prevPort);
854 flowObjectiveService.forward(newDeviceId, newFob.add(
855 new BridgingTableObjectiveContext(mac, vlanId)
856 ));
857
858 // Populate new IP table entry
859 newIps.forEach(ip -> {
860 if (ip.isIp4()) {
861 routingRulePopulator.populateIpRuleForHost(
862 newDeviceId, ip.getIp4Address(), mac, newPort);
863 }
864 });
865 }
866
867 private void processHostUpdatedEvent(HostEvent event) {
868 MacAddress mac = event.subject().mac();
869 VlanId vlanId = event.subject().vlan();
870 DeviceId prevDeviceId = event.prevSubject().location().deviceId();
871 PortNumber prevPort = event.prevSubject().location().port();
872 Set<IpAddress> prevIps = event.prevSubject().ipAddresses();
873 DeviceId newDeviceId = event.subject().location().deviceId();
874 PortNumber newPort = event.subject().location().port();
875 Set<IpAddress> newIps = event.subject().ipAddresses();
876 log.debug("Host {}/{} is updated", mac, vlanId);
877
878 // Revoke previous IP table entry
879 prevIps.forEach(ip -> {
880 if (ip.isIp4()) {
881 routingRulePopulator.revokeIpRuleForHost(
882 prevDeviceId, ip.getIp4Address(), mac, prevPort);
883 }
884 });
885
886 // Populate new IP table entry
887 newIps.forEach(ip -> {
888 if (ip.isIp4()) {
889 routingRulePopulator.populateIpRuleForHost(
890 newDeviceId, ip.getIp4Address(), mac, newPort);
891 }
892 });
893 }
894
895 @Override
896 public void event(HostEvent event) {
897 // Do not proceed without mastership
898 DeviceId deviceId = event.subject().location().deviceId();
899 if (!mastershipService.isLocalMaster(deviceId)) {
900 return;
901 }
902
903 switch (event.type()) {
904 case HOST_ADDED:
905 processHostAddedEvent(event);
906 break;
907 case HOST_MOVED:
908 processHostMovedEvent(event);
909 break;
910 case HOST_REMOVED:
911 processHostRemoveEvent(event);
912 break;
913 case HOST_UPDATED:
914 processHostUpdatedEvent(event);
915 break;
916 default:
917 log.warn("Unsupported host event type: {}", event.type());
918 break;
919 }
920 }
921 }
922
923 private static class BridgingTableObjectiveContext implements ObjectiveContext {
924 final MacAddress mac;
925 final VlanId vlanId;
926
927 BridgingTableObjectiveContext(MacAddress mac, VlanId vlanId) {
928 this.mac = mac;
929 this.vlanId = vlanId;
930 }
931
932 @Override
933 public void onSuccess(Objective objective) {
934 if (objective.op() == Objective.Operation.ADD) {
935 log.debug("Successfully populate bridging table entry for {}/{}",
936 mac, vlanId);
937 } else {
938 log.debug("Successfully revoke bridging table entry for {}/{}",
939 mac, vlanId);
940 }
941 }
942
943 @Override
944 public void onError(Objective objective, ObjectiveError error) {
945 if (objective.op() == Objective.Operation.ADD) {
946 log.debug("Fail to populate bridging table entry for {}/{}. {}",
947 mac, vlanId, error);
948 } else {
949 log.debug("Fail to revoke bridging table entry for {}/{}. {}",
950 mac, vlanId, error);
951 }
952 }
953 }
sanghob35a6192015-04-01 13:05:26 -0700954}