blob: b394db5e4f329a7733652771e32f3ee776744e1c [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;
Charles Chan0b4e6182015-11-03 10:42:14 -080051import org.onosproject.segmentrouting.config.DeviceConfigNotFoundException;
52import org.onosproject.segmentrouting.config.DeviceProperties;
Srikanth Vavilapalli23181912015-05-04 09:48:09 -070053import org.onosproject.store.service.EventuallyConsistentMap;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080054import org.slf4j.Logger;
55
56/**
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070057 * Default ECMP group handler creation module. This component creates a set of
58 * ECMP groups for every neighbor that this device is connected to based on
59 * whether the current device is an edge device or a transit device.
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080060 */
61public class DefaultGroupHandler {
Srikanth Vavilapallif3a8bc02015-05-22 13:47:31 -070062 protected static final Logger log = getLogger(DefaultGroupHandler.class);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080063
64 protected final DeviceId deviceId;
65 protected final ApplicationId appId;
66 protected final DeviceProperties deviceConfig;
67 protected final List<Integer> allSegmentIds;
Charles Chan0b4e6182015-11-03 10:42:14 -080068 protected int nodeSegmentId = -1;
69 protected boolean isEdgeRouter = false;
70 protected MacAddress nodeMacAddr = null;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080071 protected LinkService linkService;
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070072 protected FlowObjectiveService flowObjectiveService;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080073
Thomas Vachuska6cdbdd82015-05-15 09:10:58 -070074 protected HashMap<DeviceId, Set<PortNumber>> devicePortMap = new HashMap<>();
75 protected HashMap<PortNumber, DeviceId> portDeviceMap = new HashMap<>();
Srikanth Vavilapalli23181912015-05-04 09:48:09 -070076 //protected HashMap<NeighborSet, Integer> deviceNextObjectiveIds =
77 // new HashMap<NeighborSet, Integer>();
78 protected EventuallyConsistentMap<
79 NeighborSetNextObjectiveStoreKey, Integer> nsNextObjStore = null;
Charles Chanc42e84e2015-10-20 16:24:19 -070080 protected EventuallyConsistentMap<
81 SubnetNextObjectiveStoreKey, Integer> subnetNextObjStore = null;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080082
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -070083 protected KryoNamespace.Builder kryo = new KryoNamespace.Builder()
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070084 .register(URI.class).register(HashSet.class)
85 .register(DeviceId.class).register(PortNumber.class)
86 .register(NeighborSet.class).register(PolicyGroupIdentifier.class)
87 .register(PolicyGroupParams.class)
88 .register(GroupBucketIdentifier.class)
89 .register(GroupBucketIdentifier.BucketOutputType.class);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080090
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070091 protected DefaultGroupHandler(DeviceId deviceId, ApplicationId appId,
92 DeviceProperties config,
93 LinkService linkService,
Srikanth Vavilapalli23181912015-05-04 09:48:09 -070094 FlowObjectiveService flowObjService,
95 EventuallyConsistentMap<
Charles Chanc42e84e2015-10-20 16:24:19 -070096 NeighborSetNextObjectiveStoreKey,
97 Integer> nsNextObjStore,
98 EventuallyConsistentMap<SubnetNextObjectiveStoreKey,
99 Integer> subnetNextObjStore) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800100 this.deviceId = checkNotNull(deviceId);
101 this.appId = checkNotNull(appId);
102 this.deviceConfig = checkNotNull(config);
103 this.linkService = checkNotNull(linkService);
Charles Chan0b4e6182015-11-03 10:42:14 -0800104 this.allSegmentIds = checkNotNull(config.getAllDeviceSegmentIds());
105 try {
106 this.nodeSegmentId = config.getSegmentId(deviceId);
107 this.isEdgeRouter = config.isEdgeDevice(deviceId);
108 this.nodeMacAddr = checkNotNull(config.getDeviceMac(deviceId));
109 } catch (DeviceConfigNotFoundException e) {
110 log.warn(e.getMessage()
111 + " Skipping value assignment in DefaultGroupHandler");
112 }
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700113 this.flowObjectiveService = flowObjService;
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700114 this.nsNextObjStore = nsNextObjStore;
Charles Chanc42e84e2015-10-20 16:24:19 -0700115 this.subnetNextObjStore = subnetNextObjStore;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800116
117 populateNeighborMaps();
118 }
119
120 /**
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700121 * Creates a group handler object based on the type of device. If device is
122 * of edge type it returns edge group handler, else it returns transit group
123 * handler.
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800124 *
125 * @param deviceId device identifier
126 * @param appId application identifier
127 * @param config interface to retrieve the device properties
128 * @param linkService link service object
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700129 * @param flowObjService flow objective service object
Charles Chanc42e84e2015-10-20 16:24:19 -0700130 * @param nsNextObjStore NeighborSet next objective store map
131 * @param subnetNextObjStore subnet next objective store map
Charles Chan0b4e6182015-11-03 10:42:14 -0800132 * @throws DeviceConfigNotFoundException if the device configuration is not found
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800133 * @return default group handler type
134 */
135 public static DefaultGroupHandler createGroupHandler(DeviceId deviceId,
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700136 ApplicationId appId,
137 DeviceProperties config,
138 LinkService linkService,
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700139 FlowObjectiveService flowObjService,
Charles Chanc42e84e2015-10-20 16:24:19 -0700140 EventuallyConsistentMap<
141 NeighborSetNextObjectiveStoreKey,
142 Integer> nsNextObjStore,
143 EventuallyConsistentMap<SubnetNextObjectiveStoreKey,
Charles Chan0b4e6182015-11-03 10:42:14 -0800144 Integer> subnetNextObjStore)
145 throws DeviceConfigNotFoundException {
146 // handle possible exception in the caller
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800147 if (config.isEdgeDevice(deviceId)) {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700148 return new DefaultEdgeGroupHandler(deviceId, appId, config,
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700149 linkService,
150 flowObjService,
Charles Chanc42e84e2015-10-20 16:24:19 -0700151 nsNextObjStore,
152 subnetNextObjStore);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800153 } else {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700154 return new DefaultTransitGroupHandler(deviceId, appId, config,
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700155 linkService,
156 flowObjService,
Charles Chanc42e84e2015-10-20 16:24:19 -0700157 nsNextObjStore,
158 subnetNextObjStore);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800159 }
160 }
161
162 /**
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700163 * Creates the auto created groups for this device based on the current
164 * snapshot of the topology.
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800165 */
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700166 // Empty implementations to be overridden by derived classes
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800167 public void createGroups() {
168 }
169
170 /**
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700171 * Performs group creation or update procedures when a new link is
172 * discovered on this device.
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800173 *
174 * @param newLink new neighbor link
175 */
176 public void linkUp(Link newLink) {
sanghob35a6192015-04-01 13:05:26 -0700177
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800178 if (newLink.type() != Link.Type.DIRECT) {
179 log.warn("linkUp: unknown link type");
180 return;
181 }
182
183 if (!newLink.src().deviceId().equals(deviceId)) {
184 log.warn("linkUp: deviceId{} doesn't match with link src{}",
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700185 deviceId, newLink.src().deviceId());
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800186 return;
187 }
188
Charles Chan0b4e6182015-11-03 10:42:14 -0800189 MacAddress dstMac;
190 try {
191 dstMac = deviceConfig.getDeviceMac(newLink.dst().deviceId());
192 } catch (DeviceConfigNotFoundException e) {
193 log.warn(e.getMessage() + " Aborting linkUp.");
194 return;
195 }
196
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700197 log.debug("Device {} linkUp at local port {} to neighbor {}", deviceId,
198 newLink.src().port(), newLink.dst().deviceId());
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700199 addNeighborAtPort(newLink.dst().deviceId(),
200 newLink.src().port());
201 /*if (devicePortMap.get(newLink.dst().deviceId()) == null) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800202 // New Neighbor
203 newNeighbor(newLink);
204 } else {
205 // Old Neighbor
206 newPortToExistingNeighbor(newLink);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700207 }*/
208 Set<NeighborSet> nsSet = nsNextObjStore.keySet()
209 .stream()
210 .filter((nsStoreEntry) -> (nsStoreEntry.deviceId().equals(deviceId)))
211 .map((nsStoreEntry) -> (nsStoreEntry.neighborSet()))
212 .filter((ns) -> (ns.getDeviceIds()
213 .contains(newLink.dst().deviceId())))
214 .collect(Collectors.toSet());
215 log.trace("linkUp: nsNextObjStore contents for device {}:",
sangho0b2b6d12015-05-20 22:16:38 -0700216 deviceId,
217 nsSet);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700218 for (NeighborSet ns : nsSet) {
219 // Create the new bucket to be updated
220 TrafficTreatment.Builder tBuilder =
221 DefaultTrafficTreatment.builder();
222 tBuilder.setOutput(newLink.src().port())
Charles Chan0b4e6182015-11-03 10:42:14 -0800223 .setEthDst(dstMac)
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700224 .setEthSrc(nodeMacAddr);
225 if (ns.getEdgeLabel() != NeighborSet.NO_EDGE_LABEL) {
226 tBuilder.pushMpls()
Charles Chan68aa62d2015-11-09 16:37:23 -0800227 .copyTtlOut()
228 .setMpls(MplsLabel.mplsLabel(ns.getEdgeLabel()));
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700229 }
230
231 Integer nextId = nsNextObjStore.
232 get(new NeighborSetNextObjectiveStoreKey(deviceId, ns));
233 if (nextId != null) {
234 NextObjective.Builder nextObjBuilder = DefaultNextObjective
235 .builder().withId(nextId)
236 .withType(NextObjective.Type.HASHED).fromApp(appId);
237
238 nextObjBuilder.addTreatment(tBuilder.build());
239
240 log.debug("linkUp in device {}: Adding Bucket "
241 + "with Port {} to next object id {}",
242 deviceId,
243 newLink.src().port(),
244 nextId);
Srikanth Vavilapallif3a8bc02015-05-22 13:47:31 -0700245 NextObjective nextObjective = nextObjBuilder.
246 add(new SRNextObjectiveContext(deviceId));
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700247 flowObjectiveService.next(deviceId, nextObjective);
248 }
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800249 }
250 }
251
252 /**
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700253 * Performs group recovery procedures when a port goes down on this device.
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800254 *
255 * @param port port number that has gone down
256 */
257 public void portDown(PortNumber port) {
258 if (portDeviceMap.get(port) == null) {
259 log.warn("portDown: unknown port");
260 return;
261 }
Charles Chan0b4e6182015-11-03 10:42:14 -0800262
263 MacAddress dstMac;
264 try {
265 dstMac = deviceConfig.getDeviceMac(portDeviceMap.get(port));
266 } catch (DeviceConfigNotFoundException e) {
267 log.warn(e.getMessage() + " Aborting portDown.");
268 return;
269 }
270
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700271 log.debug("Device {} portDown {} to neighbor {}", deviceId, port,
272 portDeviceMap.get(port));
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700273 /*Set<NeighborSet> nsSet = computeImpactedNeighborsetForPortEvent(portDeviceMap
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700274 .get(port),
275 devicePortMap
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700276 .keySet());*/
277 Set<NeighborSet> nsSet = nsNextObjStore.keySet()
278 .stream()
279 .filter((nsStoreEntry) -> (nsStoreEntry.deviceId().equals(deviceId)))
280 .map((nsStoreEntry) -> (nsStoreEntry.neighborSet()))
281 .filter((ns) -> (ns.getDeviceIds()
282 .contains(portDeviceMap.get(port))))
283 .collect(Collectors.toSet());
284 log.trace("portDown: nsNextObjStore contents for device {}:",
285 deviceId,
286 nsSet);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800287 for (NeighborSet ns : nsSet) {
288 // Create the bucket to be removed
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700289 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment
290 .builder();
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800291 tBuilder.setOutput(port)
Charles Chan0b4e6182015-11-03 10:42:14 -0800292 .setEthDst(dstMac)
293 .setEthSrc(nodeMacAddr);
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700294 if (ns.getEdgeLabel() != NeighborSet.NO_EDGE_LABEL) {
Charles Chan68aa62d2015-11-09 16:37:23 -0800295 tBuilder.pushMpls()
296 .copyTtlOut()
297 .setMpls(MplsLabel.mplsLabel(ns.getEdgeLabel()));
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700298 }
sangho834e4b02015-05-01 09:38:25 -0700299
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700300 Integer nextId = nsNextObjStore.
301 get(new NeighborSetNextObjectiveStoreKey(deviceId, ns));
sangho834e4b02015-05-01 09:38:25 -0700302 if (nextId != null) {
303 NextObjective.Builder nextObjBuilder = DefaultNextObjective
304 .builder().withType(NextObjective.Type.SIMPLE).withId(nextId).fromApp(appId);
305
306 nextObjBuilder.addTreatment(tBuilder.build());
307
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700308 log.debug("portDown in device {}: Removing Bucket "
309 + "with Port {} to next object id {}",
310 deviceId,
311 port,
312 nextId);
Srikanth Vavilapallif3a8bc02015-05-22 13:47:31 -0700313 NextObjective nextObjective = nextObjBuilder.
314 remove(new SRNextObjectiveContext(deviceId));
sangho834e4b02015-05-01 09:38:25 -0700315
316 flowObjectiveService.next(deviceId, nextObjective);
317 }
318
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800319 }
320
321 devicePortMap.get(portDeviceMap.get(port)).remove(port);
322 portDeviceMap.remove(port);
323 }
324
325 /**
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700326 * Returns the next objective associated with the neighborset.
327 * If there is no next objective for this neighborset, this API
328 * would create a next objective and return.
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800329 *
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700330 * @param ns neighborset
331 * @return int if found or -1
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800332 */
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700333 public int getNextObjectiveId(NeighborSet ns) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700334 Integer nextId = nsNextObjStore.
335 get(new NeighborSetNextObjectiveStoreKey(deviceId, ns));
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700336 if (nextId == null) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700337 log.trace("getNextObjectiveId in device{}: Next objective id "
338 + "not found for {} and creating", deviceId, ns);
339 log.trace("getNextObjectiveId: nsNextObjStore contents for device {}: {}",
340 deviceId,
341 nsNextObjStore.entrySet()
342 .stream()
343 .filter((nsStoreEntry) ->
344 (nsStoreEntry.getKey().deviceId().equals(deviceId)))
345 .collect(Collectors.toList()));
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700346 createGroupsFromNeighborsets(Collections.singleton(ns));
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700347 nextId = nsNextObjStore.
348 get(new NeighborSetNextObjectiveStoreKey(deviceId, ns));
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700349 if (nextId == null) {
350 log.warn("getNextObjectiveId: unable to create next objective");
351 return -1;
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700352 } else {
353 log.debug("getNextObjectiveId in device{}: Next objective id {} "
Sho SHIMIZUaf973432015-09-11 14:24:50 -0700354 + "created for {}", deviceId, nextId, ns);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700355 }
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700356 } else {
357 log.trace("getNextObjectiveId in device{}: Next objective id {} "
Sho SHIMIZUaf973432015-09-11 14:24:50 -0700358 + "found for {}", deviceId, nextId, ns);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700359 }
Sho SHIMIZUaf973432015-09-11 14:24:50 -0700360 return nextId;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800361 }
362
sangho0b2b6d12015-05-20 22:16:38 -0700363 /**
Charles Chan9f676b62015-10-29 14:58:10 -0700364 * Returns the next objective associated with the subnet.
365 * If there is no next objective for this subnet, this API
Charles Chanc42e84e2015-10-20 16:24:19 -0700366 * would create a next objective and return.
367 *
368 * @param prefix subnet information
369 * @return int if found or -1
370 */
371 public int getSubnetNextObjectiveId(IpPrefix prefix) {
372 Integer nextId = subnetNextObjStore.
373 get(new SubnetNextObjectiveStoreKey(deviceId, prefix));
Charles Chan9f676b62015-10-29 14:58:10 -0700374
375 return (nextId != null) ? nextId : -1;
Charles Chanc42e84e2015-10-20 16:24:19 -0700376 }
377
378 /**
sangho0b2b6d12015-05-20 22:16:38 -0700379 * Checks if the next objective ID (group) for the neighbor set exists or not.
380 *
381 * @param ns neighbor set to check
382 * @return true if it exists, false otherwise
383 */
384 public boolean hasNextObjectiveId(NeighborSet ns) {
385 Integer nextId = nsNextObjStore.
386 get(new NeighborSetNextObjectiveStoreKey(deviceId, ns));
387 if (nextId == null) {
388 return false;
389 }
390
391 return true;
392 }
393
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700394 // Empty implementation
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800395 protected void newNeighbor(Link newLink) {
396 }
397
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700398 // Empty implementation
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800399 protected void newPortToExistingNeighbor(Link newLink) {
400 }
401
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700402 // Empty implementation
403 protected Set<NeighborSet>
404 computeImpactedNeighborsetForPortEvent(DeviceId impactedNeighbor,
405 Set<DeviceId> updatedNeighbors) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800406 return null;
407 }
408
409 private void populateNeighborMaps() {
410 Set<Link> outgoingLinks = linkService.getDeviceEgressLinks(deviceId);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700411 for (Link link : outgoingLinks) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800412 if (link.type() != Link.Type.DIRECT) {
413 continue;
414 }
415 addNeighborAtPort(link.dst().deviceId(), link.src().port());
416 }
417 }
418
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700419 protected void addNeighborAtPort(DeviceId neighborId,
420 PortNumber portToNeighbor) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800421 // Update DeviceToPort database
422 log.debug("Device {} addNeighborAtPort: neighbor {} at port {}",
423 deviceId, neighborId, portToNeighbor);
424 if (devicePortMap.get(neighborId) != null) {
425 devicePortMap.get(neighborId).add(portToNeighbor);
426 } else {
Sho SHIMIZU6cfc02d2015-09-11 11:19:11 -0700427 Set<PortNumber> ports = new HashSet<>();
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800428 ports.add(portToNeighbor);
429 devicePortMap.put(neighborId, ports);
430 }
431
432 // Update portToDevice database
433 if (portDeviceMap.get(portToNeighbor) == null) {
434 portDeviceMap.put(portToNeighbor, neighborId);
435 }
436 }
437
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700438 protected Set<Set<DeviceId>> getPowerSetOfNeighbors(Set<DeviceId> neighbors) {
Sho SHIMIZU6cfc02d2015-09-11 11:19:11 -0700439 List<DeviceId> list = new ArrayList<>(neighbors);
440 Set<Set<DeviceId>> sets = new HashSet<>();
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800441 // get the number of elements in the neighbors
442 int elements = list.size();
443 // the number of members of a power set is 2^n
444 // including the empty set
445 int powerElements = (1 << elements);
446
447 // run a binary counter for the number of power elements
448 // NOTE: Exclude empty set
449 for (long i = 1; i < powerElements; i++) {
Sho SHIMIZU6cfc02d2015-09-11 11:19:11 -0700450 Set<DeviceId> neighborSubSet = new HashSet<>();
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800451 for (int j = 0; j < elements; j++) {
452 if ((i >> j) % 2 == 1) {
453 neighborSubSet.add(list.get(j));
454 }
455 }
456 sets.add(neighborSubSet);
457 }
458 return sets;
459 }
460
461 private boolean isSegmentIdSameAsNodeSegmentId(DeviceId deviceId, int sId) {
Charles Chan0b4e6182015-11-03 10:42:14 -0800462 int segmentId;
463 try {
464 segmentId = deviceConfig.getSegmentId(deviceId);
465 } catch (DeviceConfigNotFoundException e) {
466 log.warn(e.getMessage() + " Aborting isSegmentIdSameAsNodeSegmentId.");
467 return false;
468 }
469
470 return segmentId == sId;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800471 }
472
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700473 protected List<Integer> getSegmentIdsTobePairedWithNeighborSet(Set<DeviceId> neighbors) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800474
Sho SHIMIZU6cfc02d2015-09-11 11:19:11 -0700475 List<Integer> nsSegmentIds = new ArrayList<>();
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800476
sanghob35a6192015-04-01 13:05:26 -0700477 // Always pair up with no edge label
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700478 // If (neighbors.size() == 1) {
sanghob35a6192015-04-01 13:05:26 -0700479 nsSegmentIds.add(-1);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700480 // }
sanghob35a6192015-04-01 13:05:26 -0700481
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800482 // Filter out SegmentIds matching with the
483 // nodes in the combo
484 for (Integer sId : allSegmentIds) {
485 if (sId.equals(nodeSegmentId)) {
486 continue;
487 }
488 boolean filterOut = false;
489 // Check if the edge label being set is of
490 // any node in the Neighbor set
491 for (DeviceId deviceId : neighbors) {
492 if (isSegmentIdSameAsNodeSegmentId(deviceId, sId)) {
493 filterOut = true;
494 break;
495 }
496 }
497 if (!filterOut) {
498 nsSegmentIds.add(sId);
499 }
500 }
501 return nsSegmentIds;
502 }
503
sangho1e575652015-05-14 00:39:53 -0700504 /**
505 * Creates Groups from a set of NeighborSet given.
506 *
507 * @param nsSet a set of NeighborSet
508 */
509 public void createGroupsFromNeighborsets(Set<NeighborSet> nsSet) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800510 for (NeighborSet ns : nsSet) {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700511 int nextId = flowObjectiveService.allocateNextId();
512 NextObjective.Builder nextObjBuilder = DefaultNextObjective
513 .builder().withId(nextId)
514 .withType(NextObjective.Type.HASHED).fromApp(appId);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800515 for (DeviceId d : ns.getDeviceIds()) {
sangho834e4b02015-05-01 09:38:25 -0700516 if (devicePortMap.get(d) == null) {
517 log.warn("Device {} is not in the port map yet", d);
518 return;
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700519 } else if (devicePortMap.get(d).size() == 0) {
520 log.warn("There are no ports for "
521 + "the Device {} in the port map yet", d);
522 return;
sangho834e4b02015-05-01 09:38:25 -0700523 }
524
Charles Chan0b4e6182015-11-03 10:42:14 -0800525 MacAddress deviceMac;
526 try {
527 deviceMac = deviceConfig.getDeviceMac(d);
528 } catch (DeviceConfigNotFoundException e) {
529 log.warn(e.getMessage() + " Aborting createGroupsFromNeighborsets.");
530 return;
531 }
532
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800533 for (PortNumber sp : devicePortMap.get(d)) {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700534 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment
535 .builder();
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800536 tBuilder.setOutput(sp)
Charles Chan0b4e6182015-11-03 10:42:14 -0800537 .setEthDst(deviceMac)
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700538 .setEthSrc(nodeMacAddr);
539 if (ns.getEdgeLabel() != NeighborSet.NO_EDGE_LABEL) {
Charles Chan68aa62d2015-11-09 16:37:23 -0800540 tBuilder.pushMpls()
541 .copyTtlOut()
542 .setMpls(MplsLabel.mplsLabel(ns.getEdgeLabel()));
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700543 }
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700544 nextObjBuilder.addTreatment(tBuilder.build());
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800545 }
546 }
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800547
Srikanth Vavilapallif3a8bc02015-05-22 13:47:31 -0700548 NextObjective nextObj = nextObjBuilder.
549 add(new SRNextObjectiveContext(deviceId));
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700550 flowObjectiveService.next(deviceId, nextObj);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700551 log.debug("createGroupsFromNeighborsets: Submited "
sangho1e575652015-05-14 00:39:53 -0700552 + "next objective {} in device {}",
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700553 nextId, deviceId);
554 nsNextObjStore.put(new NeighborSetNextObjectiveStoreKey(deviceId, ns),
555 nextId);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800556 }
557 }
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700558
Charles Chanc42e84e2015-10-20 16:24:19 -0700559 public void createGroupsFromSubnetConfig() {
560 Map<Ip4Prefix, List<PortNumber>> subnetPortMap =
561 this.deviceConfig.getSubnetPortsMap(this.deviceId);
562
563 // Construct a broadcast group for each subnet
564 subnetPortMap.forEach((subnet, ports) -> {
Charles Chan9f676b62015-10-29 14:58:10 -0700565 SubnetNextObjectiveStoreKey key =
566 new SubnetNextObjectiveStoreKey(deviceId, subnet);
567
568 if (subnetNextObjStore.containsKey(key)) {
569 log.debug("Broadcast group for device {} and subnet {} exists",
570 deviceId, subnet);
571 return;
572 }
573
Charles Chanc42e84e2015-10-20 16:24:19 -0700574 int nextId = flowObjectiveService.allocateNextId();
575
576 NextObjective.Builder nextObjBuilder = DefaultNextObjective
577 .builder().withId(nextId)
578 .withType(NextObjective.Type.BROADCAST).fromApp(appId);
579
580 ports.forEach(port -> {
581 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
Saurav Das4f980082015-11-05 13:39:15 -0800582 tBuilder.popVlan();
Charles Chanc42e84e2015-10-20 16:24:19 -0700583 tBuilder.setOutput(port);
584 nextObjBuilder.addTreatment(tBuilder.build());
585 });
586
587 NextObjective nextObj = nextObjBuilder.add();
588 flowObjectiveService.next(deviceId, nextObj);
589 log.debug("createGroupFromSubnetConfig: Submited "
590 + "next objective {} in device {}",
591 nextId, deviceId);
Charles Chan9f676b62015-10-29 14:58:10 -0700592
Charles Chanc42e84e2015-10-20 16:24:19 -0700593 subnetNextObjStore.put(key, nextId);
594 });
595 }
596
sanghob35a6192015-04-01 13:05:26 -0700597 public GroupKey getGroupKey(Object obj) {
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700598 return new DefaultGroupKey(kryo.build().serialize(obj));
599 }
sanghob35a6192015-04-01 13:05:26 -0700600
sangho1e575652015-05-14 00:39:53 -0700601 /**
602 * Removes groups for the next objective ID given.
603 *
604 * @param objectiveId next objective ID to remove
605 * @return true if succeeds, false otherwise
606 */
607 public boolean removeGroup(int objectiveId) {
608
609 if (nsNextObjStore.containsValue(objectiveId)) {
610 NextObjective.Builder nextObjBuilder = DefaultNextObjective
611 .builder().withId(objectiveId)
612 .withType(NextObjective.Type.HASHED).fromApp(appId);
Srikanth Vavilapallif3a8bc02015-05-22 13:47:31 -0700613 NextObjective nextObjective = nextObjBuilder.
614 remove(new SRNextObjectiveContext(deviceId));
sangho1e575652015-05-14 00:39:53 -0700615 flowObjectiveService.next(deviceId, nextObjective);
616
617 for (Map.Entry<NeighborSetNextObjectiveStoreKey, Integer> entry: nsNextObjStore.entrySet()) {
618 if (entry.getValue().equals(objectiveId)) {
619 nsNextObjStore.remove(entry.getKey());
620 break;
621 }
622 }
sangho0b2b6d12015-05-20 22:16:38 -0700623 return true;
sangho1e575652015-05-14 00:39:53 -0700624 }
625
626 return false;
627 }
Srikanth Vavilapallif3a8bc02015-05-22 13:47:31 -0700628
629 protected static class SRNextObjectiveContext implements ObjectiveContext {
630 final DeviceId deviceId;
631
632 SRNextObjectiveContext(DeviceId deviceId) {
633 this.deviceId = deviceId;
634 }
635 @Override
636 public void onSuccess(Objective objective) {
637 log.debug("Next objective operation successful in device {}",
638 deviceId);
639 }
640
641 @Override
642 public void onError(Objective objective, ObjectiveError error) {
643 log.warn("Next objective {} operation failed with error: {} in device {}",
644 objective, error, deviceId);
645 }
646 }
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800647}