blob: 2606f4872f748f3921b720110a2ee1f99dbcd8a1 [file] [log] [blame]
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -08001/*
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 */
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -070016package org.onosproject.segmentrouting.grouphandler;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080017
18import static com.google.common.base.Preconditions.checkNotNull;
19import static org.slf4j.LoggerFactory.getLogger;
20
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -070021import java.net.URI;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080022import java.util.ArrayList;
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070023import java.util.Collections;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080024import java.util.HashMap;
25import java.util.HashSet;
26import java.util.List;
sangho1e575652015-05-14 00:39:53 -070027import java.util.Map;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080028import java.util.Set;
Srikanth Vavilapalli23181912015-05-04 09:48:09 -070029import java.util.stream.Collectors;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080030
Charles Chanc42e84e2015-10-20 16:24:19 -070031import org.onlab.packet.Ip4Prefix;
32import org.onlab.packet.IpPrefix;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080033import org.onlab.packet.MacAddress;
sangho32a59322015-02-17 12:07:41 -080034import org.onlab.packet.MplsLabel;
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -070035import org.onlab.util.KryoNamespace;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080036import org.onosproject.core.ApplicationId;
37import org.onosproject.net.DeviceId;
38import org.onosproject.net.Link;
39import org.onosproject.net.PortNumber;
40import org.onosproject.net.flow.DefaultTrafficTreatment;
41import org.onosproject.net.flow.TrafficTreatment;
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070042import org.onosproject.net.flowobjective.DefaultNextObjective;
43import org.onosproject.net.flowobjective.FlowObjectiveService;
44import org.onosproject.net.flowobjective.NextObjective;
Srikanth Vavilapallif3a8bc02015-05-22 13:47:31 -070045import org.onosproject.net.flowobjective.Objective;
46import org.onosproject.net.flowobjective.ObjectiveContext;
47import org.onosproject.net.flowobjective.ObjectiveError;
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -070048import org.onosproject.net.group.DefaultGroupKey;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080049import org.onosproject.net.group.GroupKey;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080050import org.onosproject.net.link.LinkService;
Srikanth Vavilapalli23181912015-05-04 09:48:09 -070051import org.onosproject.store.service.EventuallyConsistentMap;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080052import org.slf4j.Logger;
53
54/**
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070055 * Default ECMP group handler creation module. This component creates a set of
56 * ECMP groups for every neighbor that this device is connected to based on
57 * whether the current device is an edge device or a transit device.
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080058 */
59public class DefaultGroupHandler {
Srikanth Vavilapallif3a8bc02015-05-22 13:47:31 -070060 protected static final Logger log = getLogger(DefaultGroupHandler.class);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080061
62 protected final DeviceId deviceId;
63 protected final ApplicationId appId;
64 protected final DeviceProperties deviceConfig;
65 protected final List<Integer> allSegmentIds;
66 protected final int nodeSegmentId;
67 protected final boolean isEdgeRouter;
68 protected final MacAddress nodeMacAddr;
69 protected LinkService linkService;
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070070 protected FlowObjectiveService flowObjectiveService;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080071
Thomas Vachuska6cdbdd82015-05-15 09:10:58 -070072 protected HashMap<DeviceId, Set<PortNumber>> devicePortMap = new HashMap<>();
73 protected HashMap<PortNumber, DeviceId> portDeviceMap = new HashMap<>();
Srikanth Vavilapalli23181912015-05-04 09:48:09 -070074 //protected HashMap<NeighborSet, Integer> deviceNextObjectiveIds =
75 // new HashMap<NeighborSet, Integer>();
76 protected EventuallyConsistentMap<
77 NeighborSetNextObjectiveStoreKey, Integer> nsNextObjStore = null;
Charles Chanc42e84e2015-10-20 16:24:19 -070078 protected EventuallyConsistentMap<
79 SubnetNextObjectiveStoreKey, Integer> subnetNextObjStore = null;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080080
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -070081 protected KryoNamespace.Builder kryo = new KryoNamespace.Builder()
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070082 .register(URI.class).register(HashSet.class)
83 .register(DeviceId.class).register(PortNumber.class)
84 .register(NeighborSet.class).register(PolicyGroupIdentifier.class)
85 .register(PolicyGroupParams.class)
86 .register(GroupBucketIdentifier.class)
87 .register(GroupBucketIdentifier.BucketOutputType.class);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080088
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070089 protected DefaultGroupHandler(DeviceId deviceId, ApplicationId appId,
90 DeviceProperties config,
91 LinkService linkService,
Srikanth Vavilapalli23181912015-05-04 09:48:09 -070092 FlowObjectiveService flowObjService,
93 EventuallyConsistentMap<
Charles Chanc42e84e2015-10-20 16:24:19 -070094 NeighborSetNextObjectiveStoreKey,
95 Integer> nsNextObjStore,
96 EventuallyConsistentMap<SubnetNextObjectiveStoreKey,
97 Integer> subnetNextObjStore) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080098 this.deviceId = checkNotNull(deviceId);
99 this.appId = checkNotNull(appId);
100 this.deviceConfig = checkNotNull(config);
101 this.linkService = checkNotNull(linkService);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800102 allSegmentIds = checkNotNull(config.getAllDeviceSegmentIds());
103 nodeSegmentId = config.getSegmentId(deviceId);
104 isEdgeRouter = config.isEdgeDevice(deviceId);
105 nodeMacAddr = checkNotNull(config.getDeviceMac(deviceId));
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700106 this.flowObjectiveService = flowObjService;
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700107 this.nsNextObjStore = nsNextObjStore;
Charles Chanc42e84e2015-10-20 16:24:19 -0700108 this.subnetNextObjStore = subnetNextObjStore;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800109
110 populateNeighborMaps();
111 }
112
113 /**
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700114 * Creates a group handler object based on the type of device. If device is
115 * of edge type it returns edge group handler, else it returns transit group
116 * handler.
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800117 *
118 * @param deviceId device identifier
119 * @param appId application identifier
120 * @param config interface to retrieve the device properties
121 * @param linkService link service object
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700122 * @param flowObjService flow objective service object
Charles Chanc42e84e2015-10-20 16:24:19 -0700123 * @param nsNextObjStore NeighborSet next objective store map
124 * @param subnetNextObjStore subnet next objective store map
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800125 * @return default group handler type
126 */
127 public static DefaultGroupHandler createGroupHandler(DeviceId deviceId,
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700128 ApplicationId appId,
129 DeviceProperties config,
130 LinkService linkService,
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700131 FlowObjectiveService flowObjService,
Charles Chanc42e84e2015-10-20 16:24:19 -0700132 EventuallyConsistentMap<
133 NeighborSetNextObjectiveStoreKey,
134 Integer> nsNextObjStore,
135 EventuallyConsistentMap<SubnetNextObjectiveStoreKey,
136 Integer> subnetNextObjStore) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800137 if (config.isEdgeDevice(deviceId)) {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700138 return new DefaultEdgeGroupHandler(deviceId, appId, config,
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700139 linkService,
140 flowObjService,
Charles Chanc42e84e2015-10-20 16:24:19 -0700141 nsNextObjStore,
142 subnetNextObjStore);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800143 } else {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700144 return new DefaultTransitGroupHandler(deviceId, appId, config,
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700145 linkService,
146 flowObjService,
Charles Chanc42e84e2015-10-20 16:24:19 -0700147 nsNextObjStore,
148 subnetNextObjStore);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800149 }
150 }
151
152 /**
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700153 * Creates the auto created groups for this device based on the current
154 * snapshot of the topology.
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800155 */
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700156 // Empty implementations to be overridden by derived classes
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800157 public void createGroups() {
158 }
159
160 /**
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700161 * Performs group creation or update procedures when a new link is
162 * discovered on this device.
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800163 *
164 * @param newLink new neighbor link
165 */
166 public void linkUp(Link newLink) {
sanghob35a6192015-04-01 13:05:26 -0700167
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800168 if (newLink.type() != Link.Type.DIRECT) {
169 log.warn("linkUp: unknown link type");
170 return;
171 }
172
173 if (!newLink.src().deviceId().equals(deviceId)) {
174 log.warn("linkUp: deviceId{} doesn't match with link src{}",
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700175 deviceId, newLink.src().deviceId());
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800176 return;
177 }
178
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700179 log.debug("Device {} linkUp at local port {} to neighbor {}", deviceId,
180 newLink.src().port(), newLink.dst().deviceId());
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700181 addNeighborAtPort(newLink.dst().deviceId(),
182 newLink.src().port());
183 /*if (devicePortMap.get(newLink.dst().deviceId()) == null) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800184 // New Neighbor
185 newNeighbor(newLink);
186 } else {
187 // Old Neighbor
188 newPortToExistingNeighbor(newLink);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700189 }*/
190 Set<NeighborSet> nsSet = nsNextObjStore.keySet()
191 .stream()
192 .filter((nsStoreEntry) -> (nsStoreEntry.deviceId().equals(deviceId)))
193 .map((nsStoreEntry) -> (nsStoreEntry.neighborSet()))
194 .filter((ns) -> (ns.getDeviceIds()
195 .contains(newLink.dst().deviceId())))
196 .collect(Collectors.toSet());
197 log.trace("linkUp: nsNextObjStore contents for device {}:",
sangho0b2b6d12015-05-20 22:16:38 -0700198 deviceId,
199 nsSet);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700200 for (NeighborSet ns : nsSet) {
201 // Create the new bucket to be updated
202 TrafficTreatment.Builder tBuilder =
203 DefaultTrafficTreatment.builder();
204 tBuilder.setOutput(newLink.src().port())
205 .setEthDst(deviceConfig.getDeviceMac(
206 newLink.dst().deviceId()))
207 .setEthSrc(nodeMacAddr);
208 if (ns.getEdgeLabel() != NeighborSet.NO_EDGE_LABEL) {
209 tBuilder.pushMpls()
210 .setMpls(MplsLabel.
211 mplsLabel(ns.getEdgeLabel()));
212 }
213
214 Integer nextId = nsNextObjStore.
215 get(new NeighborSetNextObjectiveStoreKey(deviceId, ns));
216 if (nextId != null) {
217 NextObjective.Builder nextObjBuilder = DefaultNextObjective
218 .builder().withId(nextId)
219 .withType(NextObjective.Type.HASHED).fromApp(appId);
220
221 nextObjBuilder.addTreatment(tBuilder.build());
222
223 log.debug("linkUp in device {}: Adding Bucket "
224 + "with Port {} to next object id {}",
225 deviceId,
226 newLink.src().port(),
227 nextId);
Srikanth Vavilapallif3a8bc02015-05-22 13:47:31 -0700228 NextObjective nextObjective = nextObjBuilder.
229 add(new SRNextObjectiveContext(deviceId));
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700230 flowObjectiveService.next(deviceId, nextObjective);
231 }
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800232 }
233 }
234
235 /**
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700236 * Performs group recovery procedures when a port goes down on this device.
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800237 *
238 * @param port port number that has gone down
239 */
240 public void portDown(PortNumber port) {
241 if (portDeviceMap.get(port) == null) {
242 log.warn("portDown: unknown port");
243 return;
244 }
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700245 log.debug("Device {} portDown {} to neighbor {}", deviceId, port,
246 portDeviceMap.get(port));
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700247 /*Set<NeighborSet> nsSet = computeImpactedNeighborsetForPortEvent(portDeviceMap
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700248 .get(port),
249 devicePortMap
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700250 .keySet());*/
251 Set<NeighborSet> nsSet = nsNextObjStore.keySet()
252 .stream()
253 .filter((nsStoreEntry) -> (nsStoreEntry.deviceId().equals(deviceId)))
254 .map((nsStoreEntry) -> (nsStoreEntry.neighborSet()))
255 .filter((ns) -> (ns.getDeviceIds()
256 .contains(portDeviceMap.get(port))))
257 .collect(Collectors.toSet());
258 log.trace("portDown: nsNextObjStore contents for device {}:",
259 deviceId,
260 nsSet);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800261 for (NeighborSet ns : nsSet) {
262 // Create the bucket to be removed
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700263 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment
264 .builder();
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800265 tBuilder.setOutput(port)
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700266 .setEthDst(deviceConfig.getDeviceMac(portDeviceMap
267 .get(port))).setEthSrc(nodeMacAddr);
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700268 if (ns.getEdgeLabel() != NeighborSet.NO_EDGE_LABEL) {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700269 tBuilder.pushMpls().setMpls(MplsLabel.mplsLabel(ns
270 .getEdgeLabel()));
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700271 }
sangho834e4b02015-05-01 09:38:25 -0700272
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700273 Integer nextId = nsNextObjStore.
274 get(new NeighborSetNextObjectiveStoreKey(deviceId, ns));
sangho834e4b02015-05-01 09:38:25 -0700275 if (nextId != null) {
276 NextObjective.Builder nextObjBuilder = DefaultNextObjective
277 .builder().withType(NextObjective.Type.SIMPLE).withId(nextId).fromApp(appId);
278
279 nextObjBuilder.addTreatment(tBuilder.build());
280
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700281 log.debug("portDown in device {}: Removing Bucket "
282 + "with Port {} to next object id {}",
283 deviceId,
284 port,
285 nextId);
Srikanth Vavilapallif3a8bc02015-05-22 13:47:31 -0700286 NextObjective nextObjective = nextObjBuilder.
287 remove(new SRNextObjectiveContext(deviceId));
sangho834e4b02015-05-01 09:38:25 -0700288
289 flowObjectiveService.next(deviceId, nextObjective);
290 }
291
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800292 }
293
294 devicePortMap.get(portDeviceMap.get(port)).remove(port);
295 portDeviceMap.remove(port);
296 }
297
298 /**
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700299 * Returns the next objective associated with the neighborset.
300 * If there is no next objective for this neighborset, this API
301 * would create a next objective and return.
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800302 *
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700303 * @param ns neighborset
304 * @return int if found or -1
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800305 */
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700306 public int getNextObjectiveId(NeighborSet ns) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700307 Integer nextId = nsNextObjStore.
308 get(new NeighborSetNextObjectiveStoreKey(deviceId, ns));
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700309 if (nextId == null) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700310 log.trace("getNextObjectiveId in device{}: Next objective id "
311 + "not found for {} and creating", deviceId, ns);
312 log.trace("getNextObjectiveId: nsNextObjStore contents for device {}: {}",
313 deviceId,
314 nsNextObjStore.entrySet()
315 .stream()
316 .filter((nsStoreEntry) ->
317 (nsStoreEntry.getKey().deviceId().equals(deviceId)))
318 .collect(Collectors.toList()));
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700319 createGroupsFromNeighborsets(Collections.singleton(ns));
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700320 nextId = nsNextObjStore.
321 get(new NeighborSetNextObjectiveStoreKey(deviceId, ns));
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700322 if (nextId == null) {
323 log.warn("getNextObjectiveId: unable to create next objective");
324 return -1;
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700325 } else {
326 log.debug("getNextObjectiveId in device{}: Next objective id {} "
Sho SHIMIZUaf973432015-09-11 14:24:50 -0700327 + "created for {}", deviceId, nextId, ns);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700328 }
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700329 } else {
330 log.trace("getNextObjectiveId in device{}: Next objective id {} "
Sho SHIMIZUaf973432015-09-11 14:24:50 -0700331 + "found for {}", deviceId, nextId, ns);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700332 }
Sho SHIMIZUaf973432015-09-11 14:24:50 -0700333 return nextId;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800334 }
335
sangho0b2b6d12015-05-20 22:16:38 -0700336 /**
Charles Chanc42e84e2015-10-20 16:24:19 -0700337 * Returns the next objective associated with the neighborset.
338 * If there is no next objective for this neighborset, this API
339 * would create a next objective and return.
340 *
341 * @param prefix subnet information
342 * @return int if found or -1
343 */
344 public int getSubnetNextObjectiveId(IpPrefix prefix) {
345 Integer nextId = subnetNextObjStore.
346 get(new SubnetNextObjectiveStoreKey(deviceId, prefix));
347 if (nextId == null) {
348 log.trace("getSubnetNextObjectiveId in device{}: Next objective id "
349 + "not found for {} and creating", deviceId, prefix);
350 log.trace("getSubnetNextObjectiveId: subnetNextObjStore contents for device {}: {}",
351 deviceId,
352 subnetNextObjStore.entrySet()
353 .stream()
354 .filter((subnetStoreEntry) ->
355 (subnetStoreEntry.getKey().deviceId().equals(deviceId)))
356 .collect(Collectors.toList()));
357 createGroupsFromSubnetConfig();
358 nextId = subnetNextObjStore.
359 get(new SubnetNextObjectiveStoreKey(deviceId, prefix));
360 if (nextId == null) {
361 log.warn("subnetNextObjStore: unable to create next objective");
362 return -1;
363 } else {
364 log.debug("subnetNextObjStore in device{}: Next objective id {} "
365 + "created for {}", deviceId, nextId, prefix);
366 }
367 } else {
368 log.trace("subnetNextObjStore in device{}: Next objective id {} "
369 + "found for {}", deviceId, nextId, prefix);
370 }
371 return nextId;
372 }
373
374 /**
sangho0b2b6d12015-05-20 22:16:38 -0700375 * Checks if the next objective ID (group) for the neighbor set exists or not.
376 *
377 * @param ns neighbor set to check
378 * @return true if it exists, false otherwise
379 */
380 public boolean hasNextObjectiveId(NeighborSet ns) {
381 Integer nextId = nsNextObjStore.
382 get(new NeighborSetNextObjectiveStoreKey(deviceId, ns));
383 if (nextId == null) {
384 return false;
385 }
386
387 return true;
388 }
389
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700390 // Empty implementation
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800391 protected void newNeighbor(Link newLink) {
392 }
393
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700394 // Empty implementation
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800395 protected void newPortToExistingNeighbor(Link newLink) {
396 }
397
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700398 // Empty implementation
399 protected Set<NeighborSet>
400 computeImpactedNeighborsetForPortEvent(DeviceId impactedNeighbor,
401 Set<DeviceId> updatedNeighbors) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800402 return null;
403 }
404
405 private void populateNeighborMaps() {
406 Set<Link> outgoingLinks = linkService.getDeviceEgressLinks(deviceId);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700407 for (Link link : outgoingLinks) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800408 if (link.type() != Link.Type.DIRECT) {
409 continue;
410 }
411 addNeighborAtPort(link.dst().deviceId(), link.src().port());
412 }
413 }
414
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700415 protected void addNeighborAtPort(DeviceId neighborId,
416 PortNumber portToNeighbor) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800417 // Update DeviceToPort database
418 log.debug("Device {} addNeighborAtPort: neighbor {} at port {}",
419 deviceId, neighborId, portToNeighbor);
420 if (devicePortMap.get(neighborId) != null) {
421 devicePortMap.get(neighborId).add(portToNeighbor);
422 } else {
Sho SHIMIZU6cfc02d2015-09-11 11:19:11 -0700423 Set<PortNumber> ports = new HashSet<>();
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800424 ports.add(portToNeighbor);
425 devicePortMap.put(neighborId, ports);
426 }
427
428 // Update portToDevice database
429 if (portDeviceMap.get(portToNeighbor) == null) {
430 portDeviceMap.put(portToNeighbor, neighborId);
431 }
432 }
433
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700434 protected Set<Set<DeviceId>> getPowerSetOfNeighbors(Set<DeviceId> neighbors) {
Sho SHIMIZU6cfc02d2015-09-11 11:19:11 -0700435 List<DeviceId> list = new ArrayList<>(neighbors);
436 Set<Set<DeviceId>> sets = new HashSet<>();
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800437 // get the number of elements in the neighbors
438 int elements = list.size();
439 // the number of members of a power set is 2^n
440 // including the empty set
441 int powerElements = (1 << elements);
442
443 // run a binary counter for the number of power elements
444 // NOTE: Exclude empty set
445 for (long i = 1; i < powerElements; i++) {
Sho SHIMIZU6cfc02d2015-09-11 11:19:11 -0700446 Set<DeviceId> neighborSubSet = new HashSet<>();
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800447 for (int j = 0; j < elements; j++) {
448 if ((i >> j) % 2 == 1) {
449 neighborSubSet.add(list.get(j));
450 }
451 }
452 sets.add(neighborSubSet);
453 }
454 return sets;
455 }
456
457 private boolean isSegmentIdSameAsNodeSegmentId(DeviceId deviceId, int sId) {
458 return (deviceConfig.getSegmentId(deviceId) == sId);
459 }
460
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700461 protected List<Integer> getSegmentIdsTobePairedWithNeighborSet(Set<DeviceId> neighbors) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800462
Sho SHIMIZU6cfc02d2015-09-11 11:19:11 -0700463 List<Integer> nsSegmentIds = new ArrayList<>();
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800464
sanghob35a6192015-04-01 13:05:26 -0700465 // Always pair up with no edge label
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700466 // If (neighbors.size() == 1) {
sanghob35a6192015-04-01 13:05:26 -0700467 nsSegmentIds.add(-1);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700468 // }
sanghob35a6192015-04-01 13:05:26 -0700469
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800470 // Filter out SegmentIds matching with the
471 // nodes in the combo
472 for (Integer sId : allSegmentIds) {
473 if (sId.equals(nodeSegmentId)) {
474 continue;
475 }
476 boolean filterOut = false;
477 // Check if the edge label being set is of
478 // any node in the Neighbor set
479 for (DeviceId deviceId : neighbors) {
480 if (isSegmentIdSameAsNodeSegmentId(deviceId, sId)) {
481 filterOut = true;
482 break;
483 }
484 }
485 if (!filterOut) {
486 nsSegmentIds.add(sId);
487 }
488 }
489 return nsSegmentIds;
490 }
491
sangho1e575652015-05-14 00:39:53 -0700492 /**
493 * Creates Groups from a set of NeighborSet given.
494 *
495 * @param nsSet a set of NeighborSet
496 */
497 public void createGroupsFromNeighborsets(Set<NeighborSet> nsSet) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800498 for (NeighborSet ns : nsSet) {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700499 int nextId = flowObjectiveService.allocateNextId();
500 NextObjective.Builder nextObjBuilder = DefaultNextObjective
501 .builder().withId(nextId)
502 .withType(NextObjective.Type.HASHED).fromApp(appId);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800503 for (DeviceId d : ns.getDeviceIds()) {
sangho834e4b02015-05-01 09:38:25 -0700504 if (devicePortMap.get(d) == null) {
505 log.warn("Device {} is not in the port map yet", d);
506 return;
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700507 } else if (devicePortMap.get(d).size() == 0) {
508 log.warn("There are no ports for "
509 + "the Device {} in the port map yet", d);
510 return;
sangho834e4b02015-05-01 09:38:25 -0700511 }
512
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800513 for (PortNumber sp : devicePortMap.get(d)) {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700514 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment
515 .builder();
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800516 tBuilder.setOutput(sp)
517 .setEthDst(deviceConfig.getDeviceMac(d))
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700518 .setEthSrc(nodeMacAddr);
519 if (ns.getEdgeLabel() != NeighborSet.NO_EDGE_LABEL) {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700520 tBuilder.pushMpls().setMpls(MplsLabel.mplsLabel(ns
sangho834e4b02015-05-01 09:38:25 -0700521 .getEdgeLabel()));
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700522 }
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700523 nextObjBuilder.addTreatment(tBuilder.build());
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800524 }
525 }
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800526
Srikanth Vavilapallif3a8bc02015-05-22 13:47:31 -0700527 NextObjective nextObj = nextObjBuilder.
528 add(new SRNextObjectiveContext(deviceId));
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700529 flowObjectiveService.next(deviceId, nextObj);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700530 log.debug("createGroupsFromNeighborsets: Submited "
sangho1e575652015-05-14 00:39:53 -0700531 + "next objective {} in device {}",
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700532 nextId, deviceId);
533 nsNextObjStore.put(new NeighborSetNextObjectiveStoreKey(deviceId, ns),
534 nextId);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800535 }
536 }
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700537
Charles Chanc42e84e2015-10-20 16:24:19 -0700538 public void createGroupsFromSubnetConfig() {
539 Map<Ip4Prefix, List<PortNumber>> subnetPortMap =
540 this.deviceConfig.getSubnetPortsMap(this.deviceId);
541
542 // Construct a broadcast group for each subnet
543 subnetPortMap.forEach((subnet, ports) -> {
544 int nextId = flowObjectiveService.allocateNextId();
545
546 NextObjective.Builder nextObjBuilder = DefaultNextObjective
547 .builder().withId(nextId)
548 .withType(NextObjective.Type.BROADCAST).fromApp(appId);
549
550 ports.forEach(port -> {
551 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
552 tBuilder.setOutput(port);
553 nextObjBuilder.addTreatment(tBuilder.build());
554 });
555
556 NextObjective nextObj = nextObjBuilder.add();
557 flowObjectiveService.next(deviceId, nextObj);
558 log.debug("createGroupFromSubnetConfig: Submited "
559 + "next objective {} in device {}",
560 nextId, deviceId);
561 SubnetNextObjectiveStoreKey key =
562 new SubnetNextObjectiveStoreKey(deviceId, subnet);
563 subnetNextObjStore.put(key, nextId);
564 });
565 }
566
sanghob35a6192015-04-01 13:05:26 -0700567 public GroupKey getGroupKey(Object obj) {
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700568 return new DefaultGroupKey(kryo.build().serialize(obj));
569 }
sanghob35a6192015-04-01 13:05:26 -0700570
sangho1e575652015-05-14 00:39:53 -0700571 /**
572 * Removes groups for the next objective ID given.
573 *
574 * @param objectiveId next objective ID to remove
575 * @return true if succeeds, false otherwise
576 */
577 public boolean removeGroup(int objectiveId) {
578
579 if (nsNextObjStore.containsValue(objectiveId)) {
580 NextObjective.Builder nextObjBuilder = DefaultNextObjective
581 .builder().withId(objectiveId)
582 .withType(NextObjective.Type.HASHED).fromApp(appId);
Srikanth Vavilapallif3a8bc02015-05-22 13:47:31 -0700583 NextObjective nextObjective = nextObjBuilder.
584 remove(new SRNextObjectiveContext(deviceId));
sangho1e575652015-05-14 00:39:53 -0700585 flowObjectiveService.next(deviceId, nextObjective);
586
587 for (Map.Entry<NeighborSetNextObjectiveStoreKey, Integer> entry: nsNextObjStore.entrySet()) {
588 if (entry.getValue().equals(objectiveId)) {
589 nsNextObjStore.remove(entry.getKey());
590 break;
591 }
592 }
sangho0b2b6d12015-05-20 22:16:38 -0700593 return true;
sangho1e575652015-05-14 00:39:53 -0700594 }
595
596 return false;
597 }
Srikanth Vavilapallif3a8bc02015-05-22 13:47:31 -0700598
599 protected static class SRNextObjectiveContext implements ObjectiveContext {
600 final DeviceId deviceId;
601
602 SRNextObjectiveContext(DeviceId deviceId) {
603 this.deviceId = deviceId;
604 }
605 @Override
606 public void onSuccess(Objective objective) {
607 log.debug("Next objective operation successful in device {}",
608 deviceId);
609 }
610
611 @Override
612 public void onError(Objective objective, ObjectiveError error) {
613 log.warn("Next objective {} operation failed with error: {} in device {}",
614 objective, error, deviceId);
615 }
616 }
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800617}