blob: e792bf6663dd62618405a8a4fb59db6ed244fd76 [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.HashSet;
25import java.util.List;
sangho1e575652015-05-14 00:39:53 -070026import java.util.Map;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080027import java.util.Set;
Saurav Das8a0732e2015-11-20 15:27:53 -080028import java.util.concurrent.ConcurrentHashMap;
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;
Saurav Das8a0732e2015-11-20 15:27:53 -080041import org.onosproject.net.flow.TrafficSelector;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080042import org.onosproject.net.flow.TrafficTreatment;
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070043import org.onosproject.net.flowobjective.DefaultNextObjective;
44import org.onosproject.net.flowobjective.FlowObjectiveService;
45import org.onosproject.net.flowobjective.NextObjective;
Srikanth Vavilapallif3a8bc02015-05-22 13:47:31 -070046import org.onosproject.net.flowobjective.Objective;
47import org.onosproject.net.flowobjective.ObjectiveContext;
48import org.onosproject.net.flowobjective.ObjectiveError;
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -070049import org.onosproject.net.group.DefaultGroupKey;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080050import org.onosproject.net.group.GroupKey;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080051import org.onosproject.net.link.LinkService;
Charles Chan0b4e6182015-11-03 10:42:14 -080052import org.onosproject.segmentrouting.config.DeviceConfigNotFoundException;
53import org.onosproject.segmentrouting.config.DeviceProperties;
Srikanth Vavilapalli23181912015-05-04 09:48:09 -070054import org.onosproject.store.service.EventuallyConsistentMap;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080055import org.slf4j.Logger;
56
57/**
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070058 * Default ECMP group handler creation module. This component creates a set of
59 * ECMP groups for every neighbor that this device is connected to based on
60 * whether the current device is an edge device or a transit device.
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080061 */
62public class DefaultGroupHandler {
Srikanth Vavilapallif3a8bc02015-05-22 13:47:31 -070063 protected static final Logger log = getLogger(DefaultGroupHandler.class);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080064
65 protected final DeviceId deviceId;
66 protected final ApplicationId appId;
67 protected final DeviceProperties deviceConfig;
68 protected final List<Integer> allSegmentIds;
Charles Chan0b4e6182015-11-03 10:42:14 -080069 protected int nodeSegmentId = -1;
70 protected boolean isEdgeRouter = false;
71 protected MacAddress nodeMacAddr = null;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080072 protected LinkService linkService;
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070073 protected FlowObjectiveService flowObjectiveService;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080074
Saurav Das8a0732e2015-11-20 15:27:53 -080075 protected ConcurrentHashMap<DeviceId, Set<PortNumber>> devicePortMap =
76 new ConcurrentHashMap<>();
77 protected ConcurrentHashMap<PortNumber, DeviceId> portDeviceMap =
78 new ConcurrentHashMap<>();
Srikanth Vavilapalli23181912015-05-04 09:48:09 -070079 protected EventuallyConsistentMap<
80 NeighborSetNextObjectiveStoreKey, Integer> nsNextObjStore = null;
Charles Chanc42e84e2015-10-20 16:24:19 -070081 protected EventuallyConsistentMap<
82 SubnetNextObjectiveStoreKey, Integer> subnetNextObjStore = null;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080083
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -070084 protected KryoNamespace.Builder kryo = new KryoNamespace.Builder()
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070085 .register(URI.class).register(HashSet.class)
86 .register(DeviceId.class).register(PortNumber.class)
87 .register(NeighborSet.class).register(PolicyGroupIdentifier.class)
88 .register(PolicyGroupParams.class)
89 .register(GroupBucketIdentifier.class)
90 .register(GroupBucketIdentifier.BucketOutputType.class);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080091
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070092 protected DefaultGroupHandler(DeviceId deviceId, ApplicationId appId,
93 DeviceProperties config,
94 LinkService linkService,
Srikanth Vavilapalli23181912015-05-04 09:48:09 -070095 FlowObjectiveService flowObjService,
96 EventuallyConsistentMap<
Charles Chanc42e84e2015-10-20 16:24:19 -070097 NeighborSetNextObjectiveStoreKey,
98 Integer> nsNextObjStore,
99 EventuallyConsistentMap<SubnetNextObjectiveStoreKey,
100 Integer> subnetNextObjStore) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800101 this.deviceId = checkNotNull(deviceId);
102 this.appId = checkNotNull(appId);
103 this.deviceConfig = checkNotNull(config);
104 this.linkService = checkNotNull(linkService);
Charles Chan0b4e6182015-11-03 10:42:14 -0800105 this.allSegmentIds = checkNotNull(config.getAllDeviceSegmentIds());
106 try {
107 this.nodeSegmentId = config.getSegmentId(deviceId);
108 this.isEdgeRouter = config.isEdgeDevice(deviceId);
109 this.nodeMacAddr = checkNotNull(config.getDeviceMac(deviceId));
110 } catch (DeviceConfigNotFoundException e) {
111 log.warn(e.getMessage()
112 + " Skipping value assignment in DefaultGroupHandler");
113 }
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700114 this.flowObjectiveService = flowObjService;
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700115 this.nsNextObjStore = nsNextObjStore;
Charles Chanc42e84e2015-10-20 16:24:19 -0700116 this.subnetNextObjStore = subnetNextObjStore;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800117
118 populateNeighborMaps();
119 }
120
121 /**
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700122 * Creates a group handler object based on the type of device. If device is
123 * of edge type it returns edge group handler, else it returns transit group
124 * handler.
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800125 *
126 * @param deviceId device identifier
127 * @param appId application identifier
128 * @param config interface to retrieve the device properties
129 * @param linkService link service object
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700130 * @param flowObjService flow objective service object
Charles Chanc42e84e2015-10-20 16:24:19 -0700131 * @param nsNextObjStore NeighborSet next objective store map
132 * @param subnetNextObjStore subnet next objective store map
Charles Chan0b4e6182015-11-03 10:42:14 -0800133 * @throws DeviceConfigNotFoundException if the device configuration is not found
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800134 * @return default group handler type
135 */
136 public static DefaultGroupHandler createGroupHandler(DeviceId deviceId,
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700137 ApplicationId appId,
138 DeviceProperties config,
139 LinkService linkService,
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700140 FlowObjectiveService flowObjService,
Charles Chanc42e84e2015-10-20 16:24:19 -0700141 EventuallyConsistentMap<
142 NeighborSetNextObjectiveStoreKey,
143 Integer> nsNextObjStore,
144 EventuallyConsistentMap<SubnetNextObjectiveStoreKey,
Charles Chan0b4e6182015-11-03 10:42:14 -0800145 Integer> subnetNextObjStore)
146 throws DeviceConfigNotFoundException {
147 // handle possible exception in the caller
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800148 if (config.isEdgeDevice(deviceId)) {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700149 return new DefaultEdgeGroupHandler(deviceId, appId, config,
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700150 linkService,
151 flowObjService,
Charles Chanc42e84e2015-10-20 16:24:19 -0700152 nsNextObjStore,
153 subnetNextObjStore);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800154 } else {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700155 return new DefaultTransitGroupHandler(deviceId, appId, config,
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700156 linkService,
157 flowObjService,
Charles Chanc42e84e2015-10-20 16:24:19 -0700158 nsNextObjStore,
159 subnetNextObjStore);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800160 }
161 }
162
163 /**
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700164 * Creates the auto created groups for this device based on the current
165 * snapshot of the topology.
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800166 */
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700167 // Empty implementations to be overridden by derived classes
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800168 public void createGroups() {
169 }
170
171 /**
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700172 * Performs group creation or update procedures when a new link is
173 * discovered on this device.
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800174 *
175 * @param newLink new neighbor link
176 */
Saurav Das8a0732e2015-11-20 15:27:53 -0800177 public void linkUp(Link newLink, boolean isMaster) {
sanghob35a6192015-04-01 13:05:26 -0700178
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800179 if (newLink.type() != Link.Type.DIRECT) {
180 log.warn("linkUp: unknown link type");
181 return;
182 }
183
184 if (!newLink.src().deviceId().equals(deviceId)) {
185 log.warn("linkUp: deviceId{} doesn't match with link src{}",
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700186 deviceId, newLink.src().deviceId());
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800187 return;
188 }
189
Saurav Das8a0732e2015-11-20 15:27:53 -0800190 log.info("* LinkUP: Device {} linkUp at local port {} to neighbor {}", deviceId,
191 newLink.src().port(), newLink.dst().deviceId());
Charles Chan0b4e6182015-11-03 10:42:14 -0800192 MacAddress dstMac;
193 try {
194 dstMac = deviceConfig.getDeviceMac(newLink.dst().deviceId());
195 } catch (DeviceConfigNotFoundException e) {
196 log.warn(e.getMessage() + " Aborting linkUp.");
197 return;
198 }
199
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700200 addNeighborAtPort(newLink.dst().deviceId(),
201 newLink.src().port());
202 /*if (devicePortMap.get(newLink.dst().deviceId()) == null) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800203 // New Neighbor
204 newNeighbor(newLink);
205 } else {
206 // Old Neighbor
207 newPortToExistingNeighbor(newLink);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700208 }*/
209 Set<NeighborSet> nsSet = nsNextObjStore.keySet()
210 .stream()
211 .filter((nsStoreEntry) -> (nsStoreEntry.deviceId().equals(deviceId)))
212 .map((nsStoreEntry) -> (nsStoreEntry.neighborSet()))
213 .filter((ns) -> (ns.getDeviceIds()
214 .contains(newLink.dst().deviceId())))
215 .collect(Collectors.toSet());
216 log.trace("linkUp: nsNextObjStore contents for device {}:",
sangho0b2b6d12015-05-20 22:16:38 -0700217 deviceId,
218 nsSet);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700219 for (NeighborSet ns : nsSet) {
220 // Create the new bucket to be updated
221 TrafficTreatment.Builder tBuilder =
222 DefaultTrafficTreatment.builder();
223 tBuilder.setOutput(newLink.src().port())
Charles Chan0b4e6182015-11-03 10:42:14 -0800224 .setEthDst(dstMac)
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700225 .setEthSrc(nodeMacAddr);
226 if (ns.getEdgeLabel() != NeighborSet.NO_EDGE_LABEL) {
227 tBuilder.pushMpls()
Charles Chan68aa62d2015-11-09 16:37:23 -0800228 .copyTtlOut()
229 .setMpls(MplsLabel.mplsLabel(ns.getEdgeLabel()));
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700230 }
231
232 Integer nextId = nsNextObjStore.
233 get(new NeighborSetNextObjectiveStoreKey(deviceId, ns));
234 if (nextId != null) {
235 NextObjective.Builder nextObjBuilder = DefaultNextObjective
236 .builder().withId(nextId)
237 .withType(NextObjective.Type.HASHED).fromApp(appId);
238
239 nextObjBuilder.addTreatment(tBuilder.build());
240
Saurav Das8a0732e2015-11-20 15:27:53 -0800241 log.info("**linkUp in device {}: Adding Bucket "
242 + "with Port {} to next object id {} and amIMaster:{}",
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700243 deviceId,
244 newLink.src().port(),
Saurav Das8a0732e2015-11-20 15:27:53 -0800245 nextId, isMaster);
246
247 if (isMaster) {
248 NextObjective nextObjective = nextObjBuilder.
249 addToExisting(new SRNextObjectiveContext(deviceId));
250 flowObjectiveService.next(deviceId, nextObjective);
251 }
252 } else {
253 log.warn("linkUp in device {}, but global store has no record "
254 + "for neighbor-set {}", deviceId, ns);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700255 }
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800256 }
257 }
258
259 /**
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700260 * Performs group recovery procedures when a port goes down on this device.
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800261 *
262 * @param port port number that has gone down
263 */
264 public void portDown(PortNumber port) {
265 if (portDeviceMap.get(port) == null) {
266 log.warn("portDown: unknown port");
267 return;
268 }
Charles Chan0b4e6182015-11-03 10:42:14 -0800269
270 MacAddress dstMac;
271 try {
272 dstMac = deviceConfig.getDeviceMac(portDeviceMap.get(port));
273 } catch (DeviceConfigNotFoundException e) {
274 log.warn(e.getMessage() + " Aborting portDown.");
275 return;
276 }
277
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700278 log.debug("Device {} portDown {} to neighbor {}", deviceId, port,
279 portDeviceMap.get(port));
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700280 /*Set<NeighborSet> nsSet = computeImpactedNeighborsetForPortEvent(portDeviceMap
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700281 .get(port),
282 devicePortMap
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700283 .keySet());*/
284 Set<NeighborSet> nsSet = nsNextObjStore.keySet()
285 .stream()
286 .filter((nsStoreEntry) -> (nsStoreEntry.deviceId().equals(deviceId)))
287 .map((nsStoreEntry) -> (nsStoreEntry.neighborSet()))
288 .filter((ns) -> (ns.getDeviceIds()
289 .contains(portDeviceMap.get(port))))
290 .collect(Collectors.toSet());
291 log.trace("portDown: nsNextObjStore contents for device {}:",
292 deviceId,
293 nsSet);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800294 for (NeighborSet ns : nsSet) {
295 // Create the bucket to be removed
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700296 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment
297 .builder();
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800298 tBuilder.setOutput(port)
Charles Chan0b4e6182015-11-03 10:42:14 -0800299 .setEthDst(dstMac)
300 .setEthSrc(nodeMacAddr);
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700301 if (ns.getEdgeLabel() != NeighborSet.NO_EDGE_LABEL) {
Charles Chan68aa62d2015-11-09 16:37:23 -0800302 tBuilder.pushMpls()
303 .copyTtlOut()
304 .setMpls(MplsLabel.mplsLabel(ns.getEdgeLabel()));
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700305 }
sangho834e4b02015-05-01 09:38:25 -0700306
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700307 Integer nextId = nsNextObjStore.
308 get(new NeighborSetNextObjectiveStoreKey(deviceId, ns));
sangho834e4b02015-05-01 09:38:25 -0700309 if (nextId != null) {
310 NextObjective.Builder nextObjBuilder = DefaultNextObjective
311 .builder().withType(NextObjective.Type.SIMPLE).withId(nextId).fromApp(appId);
312
313 nextObjBuilder.addTreatment(tBuilder.build());
314
Saurav Das8a0732e2015-11-20 15:27:53 -0800315 log.info("**portDown in device {}: Removing Bucket "
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700316 + "with Port {} to next object id {}",
317 deviceId,
318 port,
319 nextId);
Saurav Das8a0732e2015-11-20 15:27:53 -0800320 // should do removefromexisting and only if master
321 /*NextObjective nextObjective = nextObjBuilder.
Srikanth Vavilapallif3a8bc02015-05-22 13:47:31 -0700322 remove(new SRNextObjectiveContext(deviceId));
sangho834e4b02015-05-01 09:38:25 -0700323
Saurav Das8a0732e2015-11-20 15:27:53 -0800324 flowObjectiveService.next(deviceId, nextObjective);*/
sangho834e4b02015-05-01 09:38:25 -0700325 }
326
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800327 }
328
329 devicePortMap.get(portDeviceMap.get(port)).remove(port);
330 portDeviceMap.remove(port);
331 }
332
333 /**
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700334 * Returns the next objective associated with the neighborset.
335 * If there is no next objective for this neighborset, this API
Saurav Das8a0732e2015-11-20 15:27:53 -0800336 * would create a next objective and return. Optionally metadata can be
337 * passed in for the creation of the next objective.
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800338 *
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700339 * @param ns neighborset
Saurav Das8a0732e2015-11-20 15:27:53 -0800340 * @param meta metadata passed into the creation of a Next Objective
341 * @return int if found or -1 if there are errors in the creation of the
342 * neighbor set.
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800343 */
Saurav Das8a0732e2015-11-20 15:27:53 -0800344 public int getNextObjectiveId(NeighborSet ns, TrafficSelector meta) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700345 Integer nextId = nsNextObjStore.
346 get(new NeighborSetNextObjectiveStoreKey(deviceId, ns));
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700347 if (nextId == null) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700348 log.trace("getNextObjectiveId in device{}: Next objective id "
349 + "not found for {} and creating", deviceId, ns);
350 log.trace("getNextObjectiveId: nsNextObjStore contents for device {}: {}",
351 deviceId,
352 nsNextObjStore.entrySet()
353 .stream()
354 .filter((nsStoreEntry) ->
355 (nsStoreEntry.getKey().deviceId().equals(deviceId)))
356 .collect(Collectors.toList()));
Saurav Das8a0732e2015-11-20 15:27:53 -0800357 createGroupsFromNeighborsets(Collections.singleton(ns), meta);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700358 nextId = nsNextObjStore.
359 get(new NeighborSetNextObjectiveStoreKey(deviceId, ns));
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700360 if (nextId == null) {
361 log.warn("getNextObjectiveId: unable to create next objective");
362 return -1;
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700363 } else {
364 log.debug("getNextObjectiveId in device{}: Next objective id {} "
Sho SHIMIZUaf973432015-09-11 14:24:50 -0700365 + "created for {}", deviceId, nextId, ns);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700366 }
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700367 } else {
368 log.trace("getNextObjectiveId in device{}: Next objective id {} "
Sho SHIMIZUaf973432015-09-11 14:24:50 -0700369 + "found for {}", deviceId, nextId, ns);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700370 }
Sho SHIMIZUaf973432015-09-11 14:24:50 -0700371 return nextId;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800372 }
373
sangho0b2b6d12015-05-20 22:16:38 -0700374 /**
Charles Chan9f676b62015-10-29 14:58:10 -0700375 * Returns the next objective associated with the subnet.
376 * If there is no next objective for this subnet, this API
Charles Chanc42e84e2015-10-20 16:24:19 -0700377 * would create a next objective and return.
378 *
379 * @param prefix subnet information
380 * @return int if found or -1
381 */
382 public int getSubnetNextObjectiveId(IpPrefix prefix) {
383 Integer nextId = subnetNextObjStore.
384 get(new SubnetNextObjectiveStoreKey(deviceId, prefix));
Charles Chan9f676b62015-10-29 14:58:10 -0700385
386 return (nextId != null) ? nextId : -1;
Charles Chanc42e84e2015-10-20 16:24:19 -0700387 }
388
389 /**
sangho0b2b6d12015-05-20 22:16:38 -0700390 * Checks if the next objective ID (group) for the neighbor set exists or not.
391 *
392 * @param ns neighbor set to check
393 * @return true if it exists, false otherwise
394 */
395 public boolean hasNextObjectiveId(NeighborSet ns) {
396 Integer nextId = nsNextObjStore.
397 get(new NeighborSetNextObjectiveStoreKey(deviceId, ns));
398 if (nextId == null) {
399 return false;
400 }
401
402 return true;
403 }
404
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700405 // Empty implementation
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800406 protected void newNeighbor(Link newLink) {
407 }
408
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700409 // Empty implementation
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800410 protected void newPortToExistingNeighbor(Link newLink) {
411 }
412
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700413 // Empty implementation
414 protected Set<NeighborSet>
415 computeImpactedNeighborsetForPortEvent(DeviceId impactedNeighbor,
416 Set<DeviceId> updatedNeighbors) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800417 return null;
418 }
419
420 private void populateNeighborMaps() {
421 Set<Link> outgoingLinks = linkService.getDeviceEgressLinks(deviceId);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700422 for (Link link : outgoingLinks) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800423 if (link.type() != Link.Type.DIRECT) {
424 continue;
425 }
426 addNeighborAtPort(link.dst().deviceId(), link.src().port());
427 }
428 }
429
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700430 protected void addNeighborAtPort(DeviceId neighborId,
431 PortNumber portToNeighbor) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800432 // Update DeviceToPort database
433 log.debug("Device {} addNeighborAtPort: neighbor {} at port {}",
434 deviceId, neighborId, portToNeighbor);
Saurav Das8a0732e2015-11-20 15:27:53 -0800435 Set<PortNumber> ports = Collections
436 .newSetFromMap(new ConcurrentHashMap<PortNumber, Boolean>());
437 ports.add(portToNeighbor);
438 Set<PortNumber> portnums = devicePortMap.putIfAbsent(neighborId, ports);
439 if (portnums != null) {
440 portnums.add(portToNeighbor);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800441 }
442
443 // Update portToDevice database
Saurav Das8a0732e2015-11-20 15:27:53 -0800444 DeviceId prev = portDeviceMap.putIfAbsent(portToNeighbor, neighborId);
445 if (prev != null) {
446 log.warn("Device: {} port: {} has neighbor: {}. NOT updating "
447 + "to neighbor: {}", deviceId, portToNeighbor, prev, neighborId);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800448 }
449 }
450
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700451 protected Set<Set<DeviceId>> getPowerSetOfNeighbors(Set<DeviceId> neighbors) {
Sho SHIMIZU6cfc02d2015-09-11 11:19:11 -0700452 List<DeviceId> list = new ArrayList<>(neighbors);
453 Set<Set<DeviceId>> sets = new HashSet<>();
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800454 // get the number of elements in the neighbors
455 int elements = list.size();
456 // the number of members of a power set is 2^n
457 // including the empty set
458 int powerElements = (1 << elements);
459
460 // run a binary counter for the number of power elements
461 // NOTE: Exclude empty set
462 for (long i = 1; i < powerElements; i++) {
Sho SHIMIZU6cfc02d2015-09-11 11:19:11 -0700463 Set<DeviceId> neighborSubSet = new HashSet<>();
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800464 for (int j = 0; j < elements; j++) {
465 if ((i >> j) % 2 == 1) {
466 neighborSubSet.add(list.get(j));
467 }
468 }
469 sets.add(neighborSubSet);
470 }
471 return sets;
472 }
473
474 private boolean isSegmentIdSameAsNodeSegmentId(DeviceId deviceId, int sId) {
Charles Chan0b4e6182015-11-03 10:42:14 -0800475 int segmentId;
476 try {
477 segmentId = deviceConfig.getSegmentId(deviceId);
478 } catch (DeviceConfigNotFoundException e) {
479 log.warn(e.getMessage() + " Aborting isSegmentIdSameAsNodeSegmentId.");
480 return false;
481 }
482
483 return segmentId == sId;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800484 }
485
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700486 protected List<Integer> getSegmentIdsTobePairedWithNeighborSet(Set<DeviceId> neighbors) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800487
Sho SHIMIZU6cfc02d2015-09-11 11:19:11 -0700488 List<Integer> nsSegmentIds = new ArrayList<>();
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800489
sanghob35a6192015-04-01 13:05:26 -0700490 // Always pair up with no edge label
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700491 // If (neighbors.size() == 1) {
sanghob35a6192015-04-01 13:05:26 -0700492 nsSegmentIds.add(-1);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700493 // }
sanghob35a6192015-04-01 13:05:26 -0700494
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800495 // Filter out SegmentIds matching with the
496 // nodes in the combo
497 for (Integer sId : allSegmentIds) {
498 if (sId.equals(nodeSegmentId)) {
499 continue;
500 }
501 boolean filterOut = false;
502 // Check if the edge label being set is of
503 // any node in the Neighbor set
504 for (DeviceId deviceId : neighbors) {
505 if (isSegmentIdSameAsNodeSegmentId(deviceId, sId)) {
506 filterOut = true;
507 break;
508 }
509 }
510 if (!filterOut) {
511 nsSegmentIds.add(sId);
512 }
513 }
514 return nsSegmentIds;
515 }
516
sangho1e575652015-05-14 00:39:53 -0700517 /**
518 * Creates Groups from a set of NeighborSet given.
519 *
520 * @param nsSet a set of NeighborSet
Saurav Das8a0732e2015-11-20 15:27:53 -0800521 * @param meta metadata passed into the creation of a Next Objective
sangho1e575652015-05-14 00:39:53 -0700522 */
Saurav Das8a0732e2015-11-20 15:27:53 -0800523 public void createGroupsFromNeighborsets(Set<NeighborSet> nsSet,
524 TrafficSelector meta) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800525 for (NeighborSet ns : nsSet) {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700526 int nextId = flowObjectiveService.allocateNextId();
527 NextObjective.Builder nextObjBuilder = DefaultNextObjective
528 .builder().withId(nextId)
529 .withType(NextObjective.Type.HASHED).fromApp(appId);
Saurav Das8a0732e2015-11-20 15:27:53 -0800530 for (DeviceId neighborId : ns.getDeviceIds()) {
531 if (devicePortMap.get(neighborId) == null) {
532 log.warn("Neighbor {} is not in the port map yet for dev:{}",
533 neighborId, deviceId);
sangho834e4b02015-05-01 09:38:25 -0700534 return;
Saurav Das8a0732e2015-11-20 15:27:53 -0800535 } else if (devicePortMap.get(neighborId).size() == 0) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700536 log.warn("There are no ports for "
Saurav Das8a0732e2015-11-20 15:27:53 -0800537 + "the Device {} in the port map yet", neighborId);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700538 return;
sangho834e4b02015-05-01 09:38:25 -0700539 }
540
Saurav Das8a0732e2015-11-20 15:27:53 -0800541 MacAddress neighborMac;
Charles Chan0b4e6182015-11-03 10:42:14 -0800542 try {
Saurav Das8a0732e2015-11-20 15:27:53 -0800543 neighborMac = deviceConfig.getDeviceMac(neighborId);
Charles Chan0b4e6182015-11-03 10:42:14 -0800544 } catch (DeviceConfigNotFoundException e) {
545 log.warn(e.getMessage() + " Aborting createGroupsFromNeighborsets.");
546 return;
547 }
548
Saurav Das8a0732e2015-11-20 15:27:53 -0800549 for (PortNumber sp : devicePortMap.get(neighborId)) {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700550 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment
551 .builder();
Saurav Das8a0732e2015-11-20 15:27:53 -0800552 tBuilder.setEthDst(neighborMac)
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700553 .setEthSrc(nodeMacAddr);
554 if (ns.getEdgeLabel() != NeighborSet.NO_EDGE_LABEL) {
Charles Chan68aa62d2015-11-09 16:37:23 -0800555 tBuilder.pushMpls()
556 .copyTtlOut()
557 .setMpls(MplsLabel.mplsLabel(ns.getEdgeLabel()));
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700558 }
Saurav Das8a0732e2015-11-20 15:27:53 -0800559 tBuilder.setOutput(sp);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700560 nextObjBuilder.addTreatment(tBuilder.build());
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800561 }
562 }
Saurav Das8a0732e2015-11-20 15:27:53 -0800563 if (meta != null) {
564 nextObjBuilder.setMeta(meta);
565 }
Srikanth Vavilapallif3a8bc02015-05-22 13:47:31 -0700566 NextObjective nextObj = nextObjBuilder.
567 add(new SRNextObjectiveContext(deviceId));
Saurav Das8a0732e2015-11-20 15:27:53 -0800568 log.info("**createGroupsFromNeighborsets: Submited "
569 + "next objective {} in device {}",
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700570 nextId, deviceId);
Saurav Das8a0732e2015-11-20 15:27:53 -0800571 flowObjectiveService.next(deviceId, nextObj);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700572 nsNextObjStore.put(new NeighborSetNextObjectiveStoreKey(deviceId, ns),
573 nextId);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800574 }
575 }
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700576
Saurav Das8a0732e2015-11-20 15:27:53 -0800577
Charles Chanc42e84e2015-10-20 16:24:19 -0700578 public void createGroupsFromSubnetConfig() {
579 Map<Ip4Prefix, List<PortNumber>> subnetPortMap =
580 this.deviceConfig.getSubnetPortsMap(this.deviceId);
Charles Chanc42e84e2015-10-20 16:24:19 -0700581 // Construct a broadcast group for each subnet
582 subnetPortMap.forEach((subnet, ports) -> {
Charles Chan9f676b62015-10-29 14:58:10 -0700583 SubnetNextObjectiveStoreKey key =
584 new SubnetNextObjectiveStoreKey(deviceId, subnet);
585
586 if (subnetNextObjStore.containsKey(key)) {
587 log.debug("Broadcast group for device {} and subnet {} exists",
588 deviceId, subnet);
589 return;
590 }
591
Charles Chanc42e84e2015-10-20 16:24:19 -0700592 int nextId = flowObjectiveService.allocateNextId();
593
594 NextObjective.Builder nextObjBuilder = DefaultNextObjective
595 .builder().withId(nextId)
596 .withType(NextObjective.Type.BROADCAST).fromApp(appId);
597
598 ports.forEach(port -> {
599 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
Saurav Das4f980082015-11-05 13:39:15 -0800600 tBuilder.popVlan();
Charles Chanc42e84e2015-10-20 16:24:19 -0700601 tBuilder.setOutput(port);
602 nextObjBuilder.addTreatment(tBuilder.build());
603 });
604
605 NextObjective nextObj = nextObjBuilder.add();
606 flowObjectiveService.next(deviceId, nextObj);
607 log.debug("createGroupFromSubnetConfig: Submited "
608 + "next objective {} in device {}",
609 nextId, deviceId);
Charles Chan9f676b62015-10-29 14:58:10 -0700610
Charles Chanc42e84e2015-10-20 16:24:19 -0700611 subnetNextObjStore.put(key, nextId);
612 });
613 }
614
sanghob35a6192015-04-01 13:05:26 -0700615 public GroupKey getGroupKey(Object obj) {
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700616 return new DefaultGroupKey(kryo.build().serialize(obj));
617 }
sanghob35a6192015-04-01 13:05:26 -0700618
sangho1e575652015-05-14 00:39:53 -0700619 /**
620 * Removes groups for the next objective ID given.
621 *
622 * @param objectiveId next objective ID to remove
623 * @return true if succeeds, false otherwise
624 */
625 public boolean removeGroup(int objectiveId) {
626
627 if (nsNextObjStore.containsValue(objectiveId)) {
628 NextObjective.Builder nextObjBuilder = DefaultNextObjective
629 .builder().withId(objectiveId)
630 .withType(NextObjective.Type.HASHED).fromApp(appId);
Srikanth Vavilapallif3a8bc02015-05-22 13:47:31 -0700631 NextObjective nextObjective = nextObjBuilder.
632 remove(new SRNextObjectiveContext(deviceId));
Saurav Das8a0732e2015-11-20 15:27:53 -0800633 log.info("**removeGroup: Submited "
634 + "next objective {} in device {}",
635 objectiveId, deviceId);
sangho1e575652015-05-14 00:39:53 -0700636 flowObjectiveService.next(deviceId, nextObjective);
637
638 for (Map.Entry<NeighborSetNextObjectiveStoreKey, Integer> entry: nsNextObjStore.entrySet()) {
639 if (entry.getValue().equals(objectiveId)) {
640 nsNextObjStore.remove(entry.getKey());
641 break;
642 }
643 }
sangho0b2b6d12015-05-20 22:16:38 -0700644 return true;
sangho1e575652015-05-14 00:39:53 -0700645 }
646
647 return false;
648 }
Srikanth Vavilapallif3a8bc02015-05-22 13:47:31 -0700649
650 protected static class SRNextObjectiveContext implements ObjectiveContext {
651 final DeviceId deviceId;
652
653 SRNextObjectiveContext(DeviceId deviceId) {
654 this.deviceId = deviceId;
655 }
656 @Override
657 public void onSuccess(Objective objective) {
Saurav Das8a0732e2015-11-20 15:27:53 -0800658 log.info("Next objective {} operation successful in device {}",
659 objective.id(), deviceId);
Srikanth Vavilapallif3a8bc02015-05-22 13:47:31 -0700660 }
661
662 @Override
663 public void onError(Objective objective, ObjectiveError error) {
664 log.warn("Next objective {} operation failed with error: {} in device {}",
Saurav Das8a0732e2015-11-20 15:27:53 -0800665 objective.id(), error, deviceId);
Srikanth Vavilapallif3a8bc02015-05-22 13:47:31 -0700666 }
667 }
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800668}