blob: bc394b84b59dfff61b7c0d1651b1773afc0a9db4 [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;
Saurav Das4ce45962015-11-24 23:21:05 -080083 protected EventuallyConsistentMap<
84 PortNextObjectiveStoreKey, Integer> portNextObjStore = null;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080085
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -070086 protected KryoNamespace.Builder kryo = new KryoNamespace.Builder()
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070087 .register(URI.class).register(HashSet.class)
88 .register(DeviceId.class).register(PortNumber.class)
89 .register(NeighborSet.class).register(PolicyGroupIdentifier.class)
90 .register(PolicyGroupParams.class)
91 .register(GroupBucketIdentifier.class)
92 .register(GroupBucketIdentifier.BucketOutputType.class);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080093
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070094 protected DefaultGroupHandler(DeviceId deviceId, ApplicationId appId,
95 DeviceProperties config,
96 LinkService linkService,
Srikanth Vavilapalli23181912015-05-04 09:48:09 -070097 FlowObjectiveService flowObjService,
Saurav Das4ce45962015-11-24 23:21:05 -080098 EventuallyConsistentMap<NeighborSetNextObjectiveStoreKey,
Charles Chanc42e84e2015-10-20 16:24:19 -070099 Integer> nsNextObjStore,
100 EventuallyConsistentMap<SubnetNextObjectiveStoreKey,
Saurav Das4ce45962015-11-24 23:21:05 -0800101 Integer> subnetNextObjStore,
102 EventuallyConsistentMap<PortNextObjectiveStoreKey,
103 Integer> portNextObjStore) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800104 this.deviceId = checkNotNull(deviceId);
105 this.appId = checkNotNull(appId);
106 this.deviceConfig = checkNotNull(config);
107 this.linkService = checkNotNull(linkService);
Charles Chan0b4e6182015-11-03 10:42:14 -0800108 this.allSegmentIds = checkNotNull(config.getAllDeviceSegmentIds());
109 try {
110 this.nodeSegmentId = config.getSegmentId(deviceId);
111 this.isEdgeRouter = config.isEdgeDevice(deviceId);
112 this.nodeMacAddr = checkNotNull(config.getDeviceMac(deviceId));
113 } catch (DeviceConfigNotFoundException e) {
114 log.warn(e.getMessage()
115 + " Skipping value assignment in DefaultGroupHandler");
116 }
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700117 this.flowObjectiveService = flowObjService;
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700118 this.nsNextObjStore = nsNextObjStore;
Charles Chanc42e84e2015-10-20 16:24:19 -0700119 this.subnetNextObjStore = subnetNextObjStore;
Saurav Das4ce45962015-11-24 23:21:05 -0800120 this.portNextObjStore = portNextObjStore;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800121
122 populateNeighborMaps();
123 }
124
125 /**
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700126 * Creates a group handler object based on the type of device. If device is
127 * of edge type it returns edge group handler, else it returns transit group
128 * handler.
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800129 *
130 * @param deviceId device identifier
131 * @param appId application identifier
132 * @param config interface to retrieve the device properties
133 * @param linkService link service object
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700134 * @param flowObjService flow objective service object
Charles Chanc42e84e2015-10-20 16:24:19 -0700135 * @param nsNextObjStore NeighborSet next objective store map
136 * @param subnetNextObjStore subnet next objective store map
Charles Chan0b4e6182015-11-03 10:42:14 -0800137 * @throws DeviceConfigNotFoundException if the device configuration is not found
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800138 * @return default group handler type
139 */
Saurav Das4ce45962015-11-24 23:21:05 -0800140 public static DefaultGroupHandler createGroupHandler(
141 DeviceId deviceId,
142 ApplicationId appId,
143 DeviceProperties config,
144 LinkService linkService,
145 FlowObjectiveService flowObjService,
146 EventuallyConsistentMap<NeighborSetNextObjectiveStoreKey,
147 Integer> nsNextObjStore,
148 EventuallyConsistentMap<SubnetNextObjectiveStoreKey,
149 Integer> subnetNextObjStore,
150 EventuallyConsistentMap<PortNextObjectiveStoreKey,
151 Integer> portNextObjStore)
152 throws DeviceConfigNotFoundException {
Charles Chan0b4e6182015-11-03 10:42:14 -0800153 // handle possible exception in the caller
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800154 if (config.isEdgeDevice(deviceId)) {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700155 return new DefaultEdgeGroupHandler(deviceId, appId, config,
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700156 linkService,
157 flowObjService,
Charles Chanc42e84e2015-10-20 16:24:19 -0700158 nsNextObjStore,
Saurav Das4ce45962015-11-24 23:21:05 -0800159 subnetNextObjStore,
160 portNextObjStore);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800161 } else {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700162 return new DefaultTransitGroupHandler(deviceId, appId, config,
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700163 linkService,
164 flowObjService,
Charles Chanc42e84e2015-10-20 16:24:19 -0700165 nsNextObjStore,
Saurav Das4ce45962015-11-24 23:21:05 -0800166 subnetNextObjStore,
167 portNextObjStore);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800168 }
169 }
170
171 /**
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700172 * Creates the auto created groups for this device based on the current
173 * snapshot of the topology.
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800174 */
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700175 // Empty implementations to be overridden by derived classes
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800176 public void createGroups() {
177 }
178
179 /**
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700180 * Performs group creation or update procedures when a new link is
181 * discovered on this device.
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800182 *
183 * @param newLink new neighbor link
184 */
Saurav Das8a0732e2015-11-20 15:27:53 -0800185 public void linkUp(Link newLink, boolean isMaster) {
sanghob35a6192015-04-01 13:05:26 -0700186
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800187 if (newLink.type() != Link.Type.DIRECT) {
188 log.warn("linkUp: unknown link type");
189 return;
190 }
191
192 if (!newLink.src().deviceId().equals(deviceId)) {
193 log.warn("linkUp: deviceId{} doesn't match with link src{}",
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700194 deviceId, newLink.src().deviceId());
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800195 return;
196 }
197
Saurav Das8a0732e2015-11-20 15:27:53 -0800198 log.info("* LinkUP: Device {} linkUp at local port {} to neighbor {}", deviceId,
199 newLink.src().port(), newLink.dst().deviceId());
Charles Chan0b4e6182015-11-03 10:42:14 -0800200 MacAddress dstMac;
201 try {
202 dstMac = deviceConfig.getDeviceMac(newLink.dst().deviceId());
203 } catch (DeviceConfigNotFoundException e) {
204 log.warn(e.getMessage() + " Aborting linkUp.");
205 return;
206 }
207
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700208 addNeighborAtPort(newLink.dst().deviceId(),
209 newLink.src().port());
210 /*if (devicePortMap.get(newLink.dst().deviceId()) == null) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800211 // New Neighbor
212 newNeighbor(newLink);
213 } else {
214 // Old Neighbor
215 newPortToExistingNeighbor(newLink);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700216 }*/
217 Set<NeighborSet> nsSet = nsNextObjStore.keySet()
218 .stream()
219 .filter((nsStoreEntry) -> (nsStoreEntry.deviceId().equals(deviceId)))
220 .map((nsStoreEntry) -> (nsStoreEntry.neighborSet()))
221 .filter((ns) -> (ns.getDeviceIds()
222 .contains(newLink.dst().deviceId())))
223 .collect(Collectors.toSet());
224 log.trace("linkUp: nsNextObjStore contents for device {}:",
sangho0b2b6d12015-05-20 22:16:38 -0700225 deviceId,
226 nsSet);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700227 for (NeighborSet ns : nsSet) {
228 // Create the new bucket to be updated
229 TrafficTreatment.Builder tBuilder =
230 DefaultTrafficTreatment.builder();
231 tBuilder.setOutput(newLink.src().port())
Charles Chan0b4e6182015-11-03 10:42:14 -0800232 .setEthDst(dstMac)
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700233 .setEthSrc(nodeMacAddr);
234 if (ns.getEdgeLabel() != NeighborSet.NO_EDGE_LABEL) {
235 tBuilder.pushMpls()
Charles Chan68aa62d2015-11-09 16:37:23 -0800236 .copyTtlOut()
237 .setMpls(MplsLabel.mplsLabel(ns.getEdgeLabel()));
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700238 }
239
240 Integer nextId = nsNextObjStore.
241 get(new NeighborSetNextObjectiveStoreKey(deviceId, ns));
Saurav Das4ce45962015-11-24 23:21:05 -0800242 if (nextId != null && isMaster) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700243 NextObjective.Builder nextObjBuilder = DefaultNextObjective
244 .builder().withId(nextId)
245 .withType(NextObjective.Type.HASHED).fromApp(appId);
246
247 nextObjBuilder.addTreatment(tBuilder.build());
Saurav Das8a0732e2015-11-20 15:27:53 -0800248 log.info("**linkUp in device {}: Adding Bucket "
Saurav Das4ce45962015-11-24 23:21:05 -0800249 + "with Port {} to next object id {}",
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700250 deviceId,
251 newLink.src().port(),
Saurav Das4ce45962015-11-24 23:21:05 -0800252 nextId);
253 NextObjective nextObjective = nextObjBuilder.
254 addToExisting(new SRNextObjectiveContext(deviceId));
255 flowObjectiveService.next(deviceId, nextObjective);
256 } else if (isMaster) {
Saurav Das8a0732e2015-11-20 15:27:53 -0800257 log.warn("linkUp in device {}, but global store has no record "
258 + "for neighbor-set {}", deviceId, ns);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700259 }
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800260 }
261 }
262
263 /**
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700264 * Performs group recovery procedures when a port goes down on this device.
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800265 *
266 * @param port port number that has gone down
267 */
268 public void portDown(PortNumber port) {
269 if (portDeviceMap.get(port) == null) {
270 log.warn("portDown: unknown port");
271 return;
272 }
Charles Chan0b4e6182015-11-03 10:42:14 -0800273
274 MacAddress dstMac;
275 try {
276 dstMac = deviceConfig.getDeviceMac(portDeviceMap.get(port));
277 } catch (DeviceConfigNotFoundException e) {
278 log.warn(e.getMessage() + " Aborting portDown.");
279 return;
280 }
281
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700282 log.debug("Device {} portDown {} to neighbor {}", deviceId, port,
283 portDeviceMap.get(port));
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700284 /*Set<NeighborSet> nsSet = computeImpactedNeighborsetForPortEvent(portDeviceMap
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700285 .get(port),
286 devicePortMap
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700287 .keySet());*/
288 Set<NeighborSet> nsSet = nsNextObjStore.keySet()
289 .stream()
290 .filter((nsStoreEntry) -> (nsStoreEntry.deviceId().equals(deviceId)))
291 .map((nsStoreEntry) -> (nsStoreEntry.neighborSet()))
292 .filter((ns) -> (ns.getDeviceIds()
293 .contains(portDeviceMap.get(port))))
294 .collect(Collectors.toSet());
295 log.trace("portDown: nsNextObjStore contents for device {}:",
296 deviceId,
297 nsSet);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800298 for (NeighborSet ns : nsSet) {
299 // Create the bucket to be removed
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700300 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment
301 .builder();
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800302 tBuilder.setOutput(port)
Charles Chan0b4e6182015-11-03 10:42:14 -0800303 .setEthDst(dstMac)
304 .setEthSrc(nodeMacAddr);
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700305 if (ns.getEdgeLabel() != NeighborSet.NO_EDGE_LABEL) {
Charles Chan68aa62d2015-11-09 16:37:23 -0800306 tBuilder.pushMpls()
307 .copyTtlOut()
308 .setMpls(MplsLabel.mplsLabel(ns.getEdgeLabel()));
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700309 }
sangho834e4b02015-05-01 09:38:25 -0700310
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700311 Integer nextId = nsNextObjStore.
312 get(new NeighborSetNextObjectiveStoreKey(deviceId, ns));
sangho834e4b02015-05-01 09:38:25 -0700313 if (nextId != null) {
314 NextObjective.Builder nextObjBuilder = DefaultNextObjective
315 .builder().withType(NextObjective.Type.SIMPLE).withId(nextId).fromApp(appId);
316
317 nextObjBuilder.addTreatment(tBuilder.build());
318
Saurav Das8a0732e2015-11-20 15:27:53 -0800319 log.info("**portDown in device {}: Removing Bucket "
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700320 + "with Port {} to next object id {}",
321 deviceId,
322 port,
323 nextId);
Saurav Das8a0732e2015-11-20 15:27:53 -0800324 // should do removefromexisting and only if master
325 /*NextObjective nextObjective = nextObjBuilder.
Srikanth Vavilapallif3a8bc02015-05-22 13:47:31 -0700326 remove(new SRNextObjectiveContext(deviceId));
sangho834e4b02015-05-01 09:38:25 -0700327
Saurav Das8a0732e2015-11-20 15:27:53 -0800328 flowObjectiveService.next(deviceId, nextObjective);*/
sangho834e4b02015-05-01 09:38:25 -0700329 }
330
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800331 }
332
333 devicePortMap.get(portDeviceMap.get(port)).remove(port);
334 portDeviceMap.remove(port);
335 }
336
337 /**
Saurav Das4ce45962015-11-24 23:21:05 -0800338 * Returns the next objective of type hashed associated with the neighborset.
339 * If there is no next objective for this neighborset, this method
Saurav Das8a0732e2015-11-20 15:27:53 -0800340 * would create a next objective and return. Optionally metadata can be
341 * passed in for the creation of the next objective.
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800342 *
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700343 * @param ns neighborset
Saurav Das8a0732e2015-11-20 15:27:53 -0800344 * @param meta metadata passed into the creation of a Next Objective
345 * @return int if found or -1 if there are errors in the creation of the
346 * neighbor set.
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800347 */
Saurav Das8a0732e2015-11-20 15:27:53 -0800348 public int getNextObjectiveId(NeighborSet ns, TrafficSelector meta) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700349 Integer nextId = nsNextObjStore.
350 get(new NeighborSetNextObjectiveStoreKey(deviceId, ns));
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700351 if (nextId == null) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700352 log.trace("getNextObjectiveId in device{}: Next objective id "
353 + "not found for {} and creating", deviceId, ns);
354 log.trace("getNextObjectiveId: nsNextObjStore contents for device {}: {}",
355 deviceId,
356 nsNextObjStore.entrySet()
357 .stream()
358 .filter((nsStoreEntry) ->
359 (nsStoreEntry.getKey().deviceId().equals(deviceId)))
360 .collect(Collectors.toList()));
Saurav Das8a0732e2015-11-20 15:27:53 -0800361 createGroupsFromNeighborsets(Collections.singleton(ns), meta);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700362 nextId = nsNextObjStore.
363 get(new NeighborSetNextObjectiveStoreKey(deviceId, ns));
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700364 if (nextId == null) {
365 log.warn("getNextObjectiveId: unable to create next objective");
366 return -1;
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700367 } else {
368 log.debug("getNextObjectiveId in device{}: Next objective id {} "
Sho SHIMIZUaf973432015-09-11 14:24:50 -0700369 + "created for {}", deviceId, nextId, ns);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700370 }
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700371 } else {
372 log.trace("getNextObjectiveId in device{}: Next objective id {} "
Sho SHIMIZUaf973432015-09-11 14:24:50 -0700373 + "found for {}", deviceId, nextId, ns);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700374 }
Sho SHIMIZUaf973432015-09-11 14:24:50 -0700375 return nextId;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800376 }
377
sangho0b2b6d12015-05-20 22:16:38 -0700378 /**
Saurav Das4ce45962015-11-24 23:21:05 -0800379 * Returns the next objective of type broadcast associated with the subnet,
380 * or -1 if no such objective exists. Note that this method does NOT create
381 * the next objective as a side-effect. It is expected that is objective is
382 * created at startup from network configuration.
Charles Chanc42e84e2015-10-20 16:24:19 -0700383 *
384 * @param prefix subnet information
385 * @return int if found or -1
386 */
387 public int getSubnetNextObjectiveId(IpPrefix prefix) {
388 Integer nextId = subnetNextObjStore.
389 get(new SubnetNextObjectiveStoreKey(deviceId, prefix));
Charles Chan9f676b62015-10-29 14:58:10 -0700390
391 return (nextId != null) ? nextId : -1;
Charles Chanc42e84e2015-10-20 16:24:19 -0700392 }
393
394 /**
Saurav Das4ce45962015-11-24 23:21:05 -0800395 * Returns the next objective of type simple associated with the port on the
396 * device, given the treatment. Different treatments to the same port result
397 * in different next objectives. If no such objective exists, this method
398 * creates one and returns the id. Optionally metadata can be passed in for
399 * the creation of the objective.
400 *
401 * @param portNum the port number for the simple next objective
402 * @param treatment the actions to apply on the packets (should include outport)
403 * @param meta optional metadata passed into the creation of the next objective
404 * @return int if found or created, -1 if there are errors during the
405 * creation of the next objective.
406 */
407 public int getPortNextObjectiveId(PortNumber portNum, TrafficTreatment treatment,
408 TrafficSelector meta) {
409 Integer nextId = portNextObjStore.
410 get(new PortNextObjectiveStoreKey(deviceId, portNum, treatment));
411 if (nextId == null) {
412 log.trace("getPortNextObjectiveId in device{}: Next objective id "
413 + "not found for {} and {} creating", deviceId, portNum);
414 createGroupFromPort(portNum, treatment, meta);
415 nextId = portNextObjStore.get(
416 new PortNextObjectiveStoreKey(deviceId, portNum, treatment));
417 if (nextId == null) {
418 log.warn("getPortNextObjectiveId: unable to create next obj"
419 + "for dev:{} port{}", deviceId, portNum);
420 return -1;
421 }
422 }
423 return nextId;
424 }
425
426 /**
sangho0b2b6d12015-05-20 22:16:38 -0700427 * Checks if the next objective ID (group) for the neighbor set exists or not.
428 *
429 * @param ns neighbor set to check
430 * @return true if it exists, false otherwise
431 */
432 public boolean hasNextObjectiveId(NeighborSet ns) {
433 Integer nextId = nsNextObjStore.
434 get(new NeighborSetNextObjectiveStoreKey(deviceId, ns));
435 if (nextId == null) {
436 return false;
437 }
438
439 return true;
440 }
441
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700442 // Empty implementation
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800443 protected void newNeighbor(Link newLink) {
444 }
445
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700446 // Empty implementation
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800447 protected void newPortToExistingNeighbor(Link newLink) {
448 }
449
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700450 // Empty implementation
451 protected Set<NeighborSet>
452 computeImpactedNeighborsetForPortEvent(DeviceId impactedNeighbor,
453 Set<DeviceId> updatedNeighbors) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800454 return null;
455 }
456
457 private void populateNeighborMaps() {
458 Set<Link> outgoingLinks = linkService.getDeviceEgressLinks(deviceId);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700459 for (Link link : outgoingLinks) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800460 if (link.type() != Link.Type.DIRECT) {
461 continue;
462 }
463 addNeighborAtPort(link.dst().deviceId(), link.src().port());
464 }
465 }
466
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700467 protected void addNeighborAtPort(DeviceId neighborId,
468 PortNumber portToNeighbor) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800469 // Update DeviceToPort database
470 log.debug("Device {} addNeighborAtPort: neighbor {} at port {}",
471 deviceId, neighborId, portToNeighbor);
Saurav Das8a0732e2015-11-20 15:27:53 -0800472 Set<PortNumber> ports = Collections
473 .newSetFromMap(new ConcurrentHashMap<PortNumber, Boolean>());
474 ports.add(portToNeighbor);
475 Set<PortNumber> portnums = devicePortMap.putIfAbsent(neighborId, ports);
476 if (portnums != null) {
477 portnums.add(portToNeighbor);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800478 }
479
480 // Update portToDevice database
Saurav Das8a0732e2015-11-20 15:27:53 -0800481 DeviceId prev = portDeviceMap.putIfAbsent(portToNeighbor, neighborId);
482 if (prev != null) {
483 log.warn("Device: {} port: {} has neighbor: {}. NOT updating "
484 + "to neighbor: {}", deviceId, portToNeighbor, prev, neighborId);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800485 }
486 }
487
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700488 protected Set<Set<DeviceId>> getPowerSetOfNeighbors(Set<DeviceId> neighbors) {
Sho SHIMIZU6cfc02d2015-09-11 11:19:11 -0700489 List<DeviceId> list = new ArrayList<>(neighbors);
490 Set<Set<DeviceId>> sets = new HashSet<>();
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800491 // get the number of elements in the neighbors
492 int elements = list.size();
493 // the number of members of a power set is 2^n
494 // including the empty set
495 int powerElements = (1 << elements);
496
497 // run a binary counter for the number of power elements
498 // NOTE: Exclude empty set
499 for (long i = 1; i < powerElements; i++) {
Sho SHIMIZU6cfc02d2015-09-11 11:19:11 -0700500 Set<DeviceId> neighborSubSet = new HashSet<>();
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800501 for (int j = 0; j < elements; j++) {
502 if ((i >> j) % 2 == 1) {
503 neighborSubSet.add(list.get(j));
504 }
505 }
506 sets.add(neighborSubSet);
507 }
508 return sets;
509 }
510
511 private boolean isSegmentIdSameAsNodeSegmentId(DeviceId deviceId, int sId) {
Charles Chan0b4e6182015-11-03 10:42:14 -0800512 int segmentId;
513 try {
514 segmentId = deviceConfig.getSegmentId(deviceId);
515 } catch (DeviceConfigNotFoundException e) {
516 log.warn(e.getMessage() + " Aborting isSegmentIdSameAsNodeSegmentId.");
517 return false;
518 }
519
520 return segmentId == sId;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800521 }
522
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700523 protected List<Integer> getSegmentIdsTobePairedWithNeighborSet(Set<DeviceId> neighbors) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800524
Sho SHIMIZU6cfc02d2015-09-11 11:19:11 -0700525 List<Integer> nsSegmentIds = new ArrayList<>();
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800526
sanghob35a6192015-04-01 13:05:26 -0700527 // Always pair up with no edge label
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700528 // If (neighbors.size() == 1) {
sanghob35a6192015-04-01 13:05:26 -0700529 nsSegmentIds.add(-1);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700530 // }
sanghob35a6192015-04-01 13:05:26 -0700531
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800532 // Filter out SegmentIds matching with the
533 // nodes in the combo
534 for (Integer sId : allSegmentIds) {
535 if (sId.equals(nodeSegmentId)) {
536 continue;
537 }
538 boolean filterOut = false;
539 // Check if the edge label being set is of
540 // any node in the Neighbor set
541 for (DeviceId deviceId : neighbors) {
542 if (isSegmentIdSameAsNodeSegmentId(deviceId, sId)) {
543 filterOut = true;
544 break;
545 }
546 }
547 if (!filterOut) {
548 nsSegmentIds.add(sId);
549 }
550 }
551 return nsSegmentIds;
552 }
553
sangho1e575652015-05-14 00:39:53 -0700554 /**
555 * Creates Groups from a set of NeighborSet given.
556 *
557 * @param nsSet a set of NeighborSet
Saurav Das8a0732e2015-11-20 15:27:53 -0800558 * @param meta metadata passed into the creation of a Next Objective
sangho1e575652015-05-14 00:39:53 -0700559 */
Saurav Das8a0732e2015-11-20 15:27:53 -0800560 public void createGroupsFromNeighborsets(Set<NeighborSet> nsSet,
561 TrafficSelector meta) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800562 for (NeighborSet ns : nsSet) {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700563 int nextId = flowObjectiveService.allocateNextId();
564 NextObjective.Builder nextObjBuilder = DefaultNextObjective
565 .builder().withId(nextId)
566 .withType(NextObjective.Type.HASHED).fromApp(appId);
Saurav Das8a0732e2015-11-20 15:27:53 -0800567 for (DeviceId neighborId : ns.getDeviceIds()) {
568 if (devicePortMap.get(neighborId) == null) {
569 log.warn("Neighbor {} is not in the port map yet for dev:{}",
570 neighborId, deviceId);
sangho834e4b02015-05-01 09:38:25 -0700571 return;
Saurav Das8a0732e2015-11-20 15:27:53 -0800572 } else if (devicePortMap.get(neighborId).size() == 0) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700573 log.warn("There are no ports for "
Saurav Das8a0732e2015-11-20 15:27:53 -0800574 + "the Device {} in the port map yet", neighborId);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700575 return;
sangho834e4b02015-05-01 09:38:25 -0700576 }
577
Saurav Das8a0732e2015-11-20 15:27:53 -0800578 MacAddress neighborMac;
Charles Chan0b4e6182015-11-03 10:42:14 -0800579 try {
Saurav Das8a0732e2015-11-20 15:27:53 -0800580 neighborMac = deviceConfig.getDeviceMac(neighborId);
Charles Chan0b4e6182015-11-03 10:42:14 -0800581 } catch (DeviceConfigNotFoundException e) {
582 log.warn(e.getMessage() + " Aborting createGroupsFromNeighborsets.");
583 return;
584 }
585
Saurav Das8a0732e2015-11-20 15:27:53 -0800586 for (PortNumber sp : devicePortMap.get(neighborId)) {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700587 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment
588 .builder();
Saurav Das8a0732e2015-11-20 15:27:53 -0800589 tBuilder.setEthDst(neighborMac)
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700590 .setEthSrc(nodeMacAddr);
591 if (ns.getEdgeLabel() != NeighborSet.NO_EDGE_LABEL) {
Charles Chan68aa62d2015-11-09 16:37:23 -0800592 tBuilder.pushMpls()
593 .copyTtlOut()
594 .setMpls(MplsLabel.mplsLabel(ns.getEdgeLabel()));
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700595 }
Saurav Das8a0732e2015-11-20 15:27:53 -0800596 tBuilder.setOutput(sp);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700597 nextObjBuilder.addTreatment(tBuilder.build());
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800598 }
599 }
Saurav Das8a0732e2015-11-20 15:27:53 -0800600 if (meta != null) {
Saurav Das4ce45962015-11-24 23:21:05 -0800601 nextObjBuilder.withMeta(meta);
Saurav Das8a0732e2015-11-20 15:27:53 -0800602 }
Srikanth Vavilapallif3a8bc02015-05-22 13:47:31 -0700603 NextObjective nextObj = nextObjBuilder.
604 add(new SRNextObjectiveContext(deviceId));
Saurav Das8a0732e2015-11-20 15:27:53 -0800605 log.info("**createGroupsFromNeighborsets: Submited "
606 + "next objective {} in device {}",
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700607 nextId, deviceId);
Saurav Das8a0732e2015-11-20 15:27:53 -0800608 flowObjectiveService.next(deviceId, nextObj);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700609 nsNextObjStore.put(new NeighborSetNextObjectiveStoreKey(deviceId, ns),
610 nextId);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800611 }
612 }
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700613
Saurav Das4ce45962015-11-24 23:21:05 -0800614 /**
615 * Creates broadcast groups for all ports in the same configured subnet.
616 *
617 */
Charles Chanc42e84e2015-10-20 16:24:19 -0700618 public void createGroupsFromSubnetConfig() {
619 Map<Ip4Prefix, List<PortNumber>> subnetPortMap =
620 this.deviceConfig.getSubnetPortsMap(this.deviceId);
Charles Chanc42e84e2015-10-20 16:24:19 -0700621 // Construct a broadcast group for each subnet
622 subnetPortMap.forEach((subnet, ports) -> {
Charles Chan9f676b62015-10-29 14:58:10 -0700623 SubnetNextObjectiveStoreKey key =
624 new SubnetNextObjectiveStoreKey(deviceId, subnet);
625
626 if (subnetNextObjStore.containsKey(key)) {
627 log.debug("Broadcast group for device {} and subnet {} exists",
628 deviceId, subnet);
629 return;
630 }
631
Charles Chanc42e84e2015-10-20 16:24:19 -0700632 int nextId = flowObjectiveService.allocateNextId();
633
634 NextObjective.Builder nextObjBuilder = DefaultNextObjective
635 .builder().withId(nextId)
636 .withType(NextObjective.Type.BROADCAST).fromApp(appId);
637
638 ports.forEach(port -> {
639 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
Saurav Das4f980082015-11-05 13:39:15 -0800640 tBuilder.popVlan();
Charles Chanc42e84e2015-10-20 16:24:19 -0700641 tBuilder.setOutput(port);
642 nextObjBuilder.addTreatment(tBuilder.build());
643 });
644
645 NextObjective nextObj = nextObjBuilder.add();
646 flowObjectiveService.next(deviceId, nextObj);
647 log.debug("createGroupFromSubnetConfig: Submited "
648 + "next objective {} in device {}",
649 nextId, deviceId);
Charles Chan9f676b62015-10-29 14:58:10 -0700650
Charles Chanc42e84e2015-10-20 16:24:19 -0700651 subnetNextObjStore.put(key, nextId);
652 });
653 }
654
Saurav Das4ce45962015-11-24 23:21:05 -0800655
656 /**
657 * Create simple next objective for a single port. The treatments can include
658 * all outgoing actions that need to happen on the packet.
659 *
660 * @param portNum the outgoing port on the device
661 * @param treatment the actions to apply on the packets (should include outport)
662 * @param meta optional data to pass to the driver
663 */
664 public void createGroupFromPort(PortNumber portNum, TrafficTreatment treatment,
665 TrafficSelector meta) {
666 int nextId = flowObjectiveService.allocateNextId();
667 PortNextObjectiveStoreKey key = new PortNextObjectiveStoreKey(
668 deviceId, portNum, treatment);
669
670 NextObjective.Builder nextObjBuilder = DefaultNextObjective
671 .builder().withId(nextId)
672 .withType(NextObjective.Type.SIMPLE)
673 .addTreatment(treatment)
674 .fromApp(appId)
675 .withMeta(meta);
676
677 NextObjective nextObj = nextObjBuilder.add();
678 flowObjectiveService.next(deviceId, nextObj);
679 log.debug("createGroupFromPort: Submited next objective {} in device {} "
680 + "for port {}", nextId, deviceId, portNum);
681
682 portNextObjStore.put(key, nextId);
683 }
684
685
sanghob35a6192015-04-01 13:05:26 -0700686 public GroupKey getGroupKey(Object obj) {
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700687 return new DefaultGroupKey(kryo.build().serialize(obj));
688 }
sanghob35a6192015-04-01 13:05:26 -0700689
sangho1e575652015-05-14 00:39:53 -0700690 /**
691 * Removes groups for the next objective ID given.
692 *
693 * @param objectiveId next objective ID to remove
694 * @return true if succeeds, false otherwise
695 */
696 public boolean removeGroup(int objectiveId) {
697
698 if (nsNextObjStore.containsValue(objectiveId)) {
699 NextObjective.Builder nextObjBuilder = DefaultNextObjective
700 .builder().withId(objectiveId)
701 .withType(NextObjective.Type.HASHED).fromApp(appId);
Srikanth Vavilapallif3a8bc02015-05-22 13:47:31 -0700702 NextObjective nextObjective = nextObjBuilder.
703 remove(new SRNextObjectiveContext(deviceId));
Saurav Das8a0732e2015-11-20 15:27:53 -0800704 log.info("**removeGroup: Submited "
705 + "next objective {} in device {}",
706 objectiveId, deviceId);
sangho1e575652015-05-14 00:39:53 -0700707 flowObjectiveService.next(deviceId, nextObjective);
708
709 for (Map.Entry<NeighborSetNextObjectiveStoreKey, Integer> entry: nsNextObjStore.entrySet()) {
710 if (entry.getValue().equals(objectiveId)) {
711 nsNextObjStore.remove(entry.getKey());
712 break;
713 }
714 }
sangho0b2b6d12015-05-20 22:16:38 -0700715 return true;
sangho1e575652015-05-14 00:39:53 -0700716 }
717
718 return false;
719 }
Srikanth Vavilapallif3a8bc02015-05-22 13:47:31 -0700720
721 protected static class SRNextObjectiveContext implements ObjectiveContext {
722 final DeviceId deviceId;
723
724 SRNextObjectiveContext(DeviceId deviceId) {
725 this.deviceId = deviceId;
726 }
727 @Override
728 public void onSuccess(Objective objective) {
Saurav Das8a0732e2015-11-20 15:27:53 -0800729 log.info("Next objective {} operation successful in device {}",
730 objective.id(), deviceId);
Srikanth Vavilapallif3a8bc02015-05-22 13:47:31 -0700731 }
732
733 @Override
734 public void onError(Objective objective, ObjectiveError error) {
735 log.warn("Next objective {} operation failed with error: {} in device {}",
Saurav Das8a0732e2015-11-20 15:27:53 -0800736 objective.id(), error, deviceId);
Srikanth Vavilapallif3a8bc02015-05-22 13:47:31 -0700737 }
738 }
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800739}