blob: 2b1a8c22cf7fb74073c5ab97009dce31a0ba7a81 [file] [log] [blame]
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -07001/*
Brian O'Connor43b53542016-04-09 01:19:45 -07002 * Copyright 2015-present Open Networking Laboratory
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -07003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.onosproject.segmentrouting.grouphandler;
17
Charles Chan10b0fb72017-02-02 16:20:42 -080018
Pier Ventre229fd0b2016-10-31 16:49:19 -070019import com.google.common.collect.Iterables;
20import org.apache.commons.lang3.RandomUtils;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070021import org.onlab.packet.MacAddress;
22import org.onlab.packet.MplsLabel;
Saurav Das62af8802015-12-04 10:52:59 -080023import org.onlab.packet.VlanId;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070024import org.onlab.util.KryoNamespace;
25import org.onosproject.core.ApplicationId;
Charles Chan10b0fb72017-02-02 16:20:42 -080026import org.onosproject.incubator.net.intf.Interface;
27import org.onosproject.net.ConnectPoint;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070028import org.onosproject.net.DeviceId;
29import org.onosproject.net.Link;
30import org.onosproject.net.PortNumber;
Saurav Das62af8802015-12-04 10:52:59 -080031import org.onosproject.net.flow.DefaultTrafficSelector;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070032import org.onosproject.net.flow.DefaultTrafficTreatment;
Saurav Das4c35fc42015-11-20 15:27:53 -080033import org.onosproject.net.flow.TrafficSelector;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070034import org.onosproject.net.flow.TrafficTreatment;
Srikanth Vavilapalli64505482015-04-21 13:04:13 -070035import org.onosproject.net.flowobjective.DefaultNextObjective;
Charles Chana4ee4f92016-04-23 14:48:16 -070036import org.onosproject.net.flowobjective.DefaultObjectiveContext;
Srikanth Vavilapalli64505482015-04-21 13:04:13 -070037import org.onosproject.net.flowobjective.FlowObjectiveService;
38import org.onosproject.net.flowobjective.NextObjective;
Srikanth Vavilapalli8c83f1d2015-05-22 13:47:31 -070039import org.onosproject.net.flowobjective.ObjectiveContext;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070040import org.onosproject.net.link.LinkService;
Saurav Das62af8802015-12-04 10:52:59 -080041import org.onosproject.segmentrouting.SegmentRoutingManager;
Charles Chan319d1a22015-11-03 10:42:14 -080042import org.onosproject.segmentrouting.config.DeviceConfigNotFoundException;
43import org.onosproject.segmentrouting.config.DeviceProperties;
Charles Chan1eaf4802016-04-18 13:44:03 -070044import org.onosproject.segmentrouting.storekey.NeighborSetNextObjectiveStoreKey;
45import org.onosproject.segmentrouting.storekey.PortNextObjectiveStoreKey;
Charles Chan10b0fb72017-02-02 16:20:42 -080046import org.onosproject.segmentrouting.storekey.VlanNextObjectiveStoreKey;
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -070047import org.onosproject.store.service.EventuallyConsistentMap;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070048import org.slf4j.Logger;
49
Pier Ventre229fd0b2016-10-31 16:49:19 -070050import java.net.URI;
51import java.util.ArrayList;
52import java.util.Collections;
53import java.util.HashSet;
54import java.util.List;
55import java.util.Map;
56import java.util.Set;
57import java.util.concurrent.ConcurrentHashMap;
58import java.util.stream.Collectors;
59
60import static com.google.common.base.Preconditions.checkNotNull;
Charles Chan10b0fb72017-02-02 16:20:42 -080061import static org.onosproject.segmentrouting.SegmentRoutingManager.INTERNAL_VLAN;
Pier Ventre229fd0b2016-10-31 16:49:19 -070062import static org.slf4j.LoggerFactory.getLogger;
63
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070064/**
Srikanth Vavilapalli64505482015-04-21 13:04:13 -070065 * Default ECMP group handler creation module. This component creates a set of
66 * ECMP groups for every neighbor that this device is connected to based on
67 * whether the current device is an edge device or a transit device.
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070068 */
69public class DefaultGroupHandler {
Srikanth Vavilapalli8c83f1d2015-05-22 13:47:31 -070070 protected static final Logger log = getLogger(DefaultGroupHandler.class);
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070071
72 protected final DeviceId deviceId;
73 protected final ApplicationId appId;
74 protected final DeviceProperties deviceConfig;
75 protected final List<Integer> allSegmentIds;
Pier Ventreadb4ae62016-11-23 09:57:42 -080076 protected int ipv4NodeSegmentId = -1;
77 protected int ipv6NodeSegmentId = -1;
Charles Chan319d1a22015-11-03 10:42:14 -080078 protected boolean isEdgeRouter = false;
79 protected MacAddress nodeMacAddr = null;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070080 protected LinkService linkService;
Srikanth Vavilapalli64505482015-04-21 13:04:13 -070081 protected FlowObjectiveService flowObjectiveService;
Saurav Das62af8802015-12-04 10:52:59 -080082 // local store for neighbor-device-ids and the set of ports on this device
83 // that connect to the same neighbor
Saurav Das4c35fc42015-11-20 15:27:53 -080084 protected ConcurrentHashMap<DeviceId, Set<PortNumber>> devicePortMap =
85 new ConcurrentHashMap<>();
Saurav Dasf0f592d2016-11-18 15:21:57 -080086 // local store for ports on this device connected to neighbor-device-id
Saurav Das4c35fc42015-11-20 15:27:53 -080087 protected ConcurrentHashMap<PortNumber, DeviceId> portDeviceMap =
88 new ConcurrentHashMap<>();
Saurav Dasf0f592d2016-11-18 15:21:57 -080089 // distributed store for (device+neighborset) mapped to next-id
Charles Chanb7f75ac2016-01-11 18:28:54 -080090 protected EventuallyConsistentMap<NeighborSetNextObjectiveStoreKey, Integer>
91 nsNextObjStore = null;
Saurav Dasf0f592d2016-11-18 15:21:57 -080092 // distributed store for (device+subnet-ip-prefix) mapped to next-id
Charles Chan10b0fb72017-02-02 16:20:42 -080093 protected EventuallyConsistentMap<VlanNextObjectiveStoreKey, Integer>
94 vlanNextObjStore = null;
Saurav Dasf0f592d2016-11-18 15:21:57 -080095 // distributed store for (device+port+treatment) mapped to next-id
Charles Chanb7f75ac2016-01-11 18:28:54 -080096 protected EventuallyConsistentMap<PortNextObjectiveStoreKey, Integer>
97 portNextObjStore = null;
Charles Chande6655c2015-12-23 00:15:11 -080098 private SegmentRoutingManager srManager;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070099
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700100 protected KryoNamespace.Builder kryo = new KryoNamespace.Builder()
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700101 .register(URI.class).register(HashSet.class)
102 .register(DeviceId.class).register(PortNumber.class)
103 .register(NeighborSet.class).register(PolicyGroupIdentifier.class)
104 .register(PolicyGroupParams.class)
105 .register(GroupBucketIdentifier.class)
106 .register(GroupBucketIdentifier.BucketOutputType.class);
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700107
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700108 protected DefaultGroupHandler(DeviceId deviceId, ApplicationId appId,
109 DeviceProperties config,
110 LinkService linkService,
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700111 FlowObjectiveService flowObjService,
Charles Chande6655c2015-12-23 00:15:11 -0800112 SegmentRoutingManager srManager) {
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700113 this.deviceId = checkNotNull(deviceId);
114 this.appId = checkNotNull(appId);
115 this.deviceConfig = checkNotNull(config);
116 this.linkService = checkNotNull(linkService);
Charles Chan319d1a22015-11-03 10:42:14 -0800117 this.allSegmentIds = checkNotNull(config.getAllDeviceSegmentIds());
118 try {
Pier Ventreadb4ae62016-11-23 09:57:42 -0800119 this.ipv4NodeSegmentId = config.getIPv4SegmentId(deviceId);
120 this.ipv6NodeSegmentId = config.getIPv6SegmentId(deviceId);
Charles Chan319d1a22015-11-03 10:42:14 -0800121 this.isEdgeRouter = config.isEdgeDevice(deviceId);
122 this.nodeMacAddr = checkNotNull(config.getDeviceMac(deviceId));
123 } catch (DeviceConfigNotFoundException e) {
124 log.warn(e.getMessage()
125 + " Skipping value assignment in DefaultGroupHandler");
126 }
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700127 this.flowObjectiveService = flowObjService;
Charles Chanb7f75ac2016-01-11 18:28:54 -0800128 this.nsNextObjStore = srManager.nsNextObjStore;
Charles Chan10b0fb72017-02-02 16:20:42 -0800129 this.vlanNextObjStore = srManager.vlanNextObjStore;
Charles Chanb7f75ac2016-01-11 18:28:54 -0800130 this.portNextObjStore = srManager.portNextObjStore;
Charles Chande6655c2015-12-23 00:15:11 -0800131 this.srManager = srManager;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700132
133 populateNeighborMaps();
134 }
135
136 /**
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700137 * Creates a group handler object based on the type of device. If device is
138 * of edge type it returns edge group handler, else it returns transit group
139 * handler.
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700140 *
141 * @param deviceId device identifier
142 * @param appId application identifier
143 * @param config interface to retrieve the device properties
144 * @param linkService link service object
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700145 * @param flowObjService flow objective service object
Charles Chanb7f75ac2016-01-11 18:28:54 -0800146 * @param srManager segment routing manager
Charles Chan319d1a22015-11-03 10:42:14 -0800147 * @throws DeviceConfigNotFoundException if the device configuration is not found
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700148 * @return default group handler type
149 */
Saurav Das2d94d312015-11-24 23:21:05 -0800150 public static DefaultGroupHandler createGroupHandler(
151 DeviceId deviceId,
152 ApplicationId appId,
153 DeviceProperties config,
154 LinkService linkService,
155 FlowObjectiveService flowObjService,
Charles Chande6655c2015-12-23 00:15:11 -0800156 SegmentRoutingManager srManager)
Saurav Das2d94d312015-11-24 23:21:05 -0800157 throws DeviceConfigNotFoundException {
Charles Chan319d1a22015-11-03 10:42:14 -0800158 // handle possible exception in the caller
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700159 if (config.isEdgeDevice(deviceId)) {
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700160 return new DefaultEdgeGroupHandler(deviceId, appId, config,
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700161 linkService,
162 flowObjService,
Charles Chande6655c2015-12-23 00:15:11 -0800163 srManager
164 );
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700165 } else {
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700166 return new DefaultTransitGroupHandler(deviceId, appId, config,
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700167 linkService,
168 flowObjService,
Charles Chande6655c2015-12-23 00:15:11 -0800169 srManager);
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700170 }
171 }
172
173 /**
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700174 * Creates the auto created groups for this device based on the current
175 * snapshot of the topology.
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700176 */
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700177 // Empty implementations to be overridden by derived classes
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700178 public void createGroups() {
179 }
180
181 /**
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700182 * Performs group creation or update procedures when a new link is
183 * discovered on this device.
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700184 *
185 * @param newLink new neighbor link
Charles Chanb7f75ac2016-01-11 18:28:54 -0800186 * @param isMaster true if local instance is the master
187 *
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700188 */
Saurav Das4c35fc42015-11-20 15:27:53 -0800189 public void linkUp(Link newLink, boolean isMaster) {
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700190
191 if (newLink.type() != Link.Type.DIRECT) {
192 log.warn("linkUp: unknown link type");
193 return;
194 }
195
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700196 if (!newLink.src().deviceId().equals(deviceId)) {
197 log.warn("linkUp: deviceId{} doesn't match with link src{}",
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700198 deviceId, newLink.src().deviceId());
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700199 return;
200 }
201
Saurav Das4c35fc42015-11-20 15:27:53 -0800202 log.info("* LinkUP: Device {} linkUp at local port {} to neighbor {}", deviceId,
203 newLink.src().port(), newLink.dst().deviceId());
Saurav Das07c74602016-04-27 18:35:50 -0700204 // ensure local state is updated even if linkup is aborted later on
205 addNeighborAtPort(newLink.dst().deviceId(),
206 newLink.src().port());
207
Charles Chan319d1a22015-11-03 10:42:14 -0800208 MacAddress dstMac;
209 try {
210 dstMac = deviceConfig.getDeviceMac(newLink.dst().deviceId());
211 } catch (DeviceConfigNotFoundException e) {
212 log.warn(e.getMessage() + " Aborting linkUp.");
213 return;
214 }
215
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700216 /*if (devicePortMap.get(newLink.dst().deviceId()) == null) {
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700217 // New Neighbor
218 newNeighbor(newLink);
219 } else {
220 // Old Neighbor
221 newPortToExistingNeighbor(newLink);
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700222 }*/
223 Set<NeighborSet> nsSet = nsNextObjStore.keySet()
224 .stream()
225 .filter((nsStoreEntry) -> (nsStoreEntry.deviceId().equals(deviceId)))
226 .map((nsStoreEntry) -> (nsStoreEntry.neighborSet()))
227 .filter((ns) -> (ns.getDeviceIds()
228 .contains(newLink.dst().deviceId())))
229 .collect(Collectors.toSet());
230 log.trace("linkUp: nsNextObjStore contents for device {}:",
sangho4a5c42a2015-05-20 22:16:38 -0700231 deviceId,
232 nsSet);
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700233 for (NeighborSet ns : nsSet) {
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700234 Integer nextId = nsNextObjStore.
235 get(new NeighborSetNextObjectiveStoreKey(deviceId, ns));
Saurav Das2d94d312015-11-24 23:21:05 -0800236 if (nextId != null && isMaster) {
Saurav Das62af8802015-12-04 10:52:59 -0800237 // Create the new bucket to be updated
238 TrafficTreatment.Builder tBuilder =
239 DefaultTrafficTreatment.builder();
240 tBuilder.setOutput(newLink.src().port())
241 .setEthDst(dstMac)
242 .setEthSrc(nodeMacAddr);
243 if (ns.getEdgeLabel() != NeighborSet.NO_EDGE_LABEL) {
244 tBuilder.pushMpls()
245 .copyTtlOut()
246 .setMpls(MplsLabel.mplsLabel(ns.getEdgeLabel()));
247 }
248 // setup metadata to pass to nextObjective - indicate the vlan on egress
249 // if needed by the switch pipeline. Since hashed next-hops are always to
250 // other neighboring routers, there is no subnet assigned on those ports.
251 TrafficSelector.Builder metabuilder = DefaultTrafficSelector.builder();
Charles Chan10b0fb72017-02-02 16:20:42 -0800252 metabuilder.matchVlanId(INTERNAL_VLAN);
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700253
Saurav Das62af8802015-12-04 10:52:59 -0800254 NextObjective.Builder nextObjBuilder = DefaultNextObjective.builder()
255 .withId(nextId)
256 .withType(NextObjective.Type.HASHED)
257 .addTreatment(tBuilder.build())
258 .withMeta(metabuilder.build())
259 .fromApp(appId);
Saurav Das4c35fc42015-11-20 15:27:53 -0800260 log.info("**linkUp in device {}: Adding Bucket "
Saurav Das2d94d312015-11-24 23:21:05 -0800261 + "with Port {} to next object id {}",
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700262 deviceId,
263 newLink.src().port(),
Saurav Das2d94d312015-11-24 23:21:05 -0800264 nextId);
Charles Chana4ee4f92016-04-23 14:48:16 -0700265
266 ObjectiveContext context = new DefaultObjectiveContext(
Saurav Dasd44e8802016-10-21 14:06:29 -0700267 (objective) -> log.debug("LinkUp addedTo NextObj {} on {}",
Charles Chana4ee4f92016-04-23 14:48:16 -0700268 nextId, deviceId),
269 (objective, error) ->
Saurav Dasd44e8802016-10-21 14:06:29 -0700270 log.warn("LinkUp failed to addTo NextObj {} on {}: {}",
Charles Chana4ee4f92016-04-23 14:48:16 -0700271 nextId, deviceId, error));
272 NextObjective nextObjective = nextObjBuilder.addToExisting(context);
Saurav Das2d94d312015-11-24 23:21:05 -0800273 flowObjectiveService.next(deviceId, nextObjective);
274 } else if (isMaster) {
Saurav Das4c35fc42015-11-20 15:27:53 -0800275 log.warn("linkUp in device {}, but global store has no record "
276 + "for neighbor-set {}", deviceId, ns);
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700277 }
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700278 }
279 }
280
281 /**
Saurav Dasf0f592d2016-11-18 15:21:57 -0800282 * Performs hash group recovery procedures when a switch-to-switch
283 * port goes down on this device.
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700284 *
285 * @param port port number that has gone down
Charles Chanb7f75ac2016-01-11 18:28:54 -0800286 * @param isMaster true if local instance is the master
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700287 */
Saurav Das62af8802015-12-04 10:52:59 -0800288 public void portDown(PortNumber port, boolean isMaster) {
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700289 if (portDeviceMap.get(port) == null) {
290 log.warn("portDown: unknown port");
291 return;
292 }
Charles Chan319d1a22015-11-03 10:42:14 -0800293
294 MacAddress dstMac;
295 try {
296 dstMac = deviceConfig.getDeviceMac(portDeviceMap.get(port));
297 } catch (DeviceConfigNotFoundException e) {
298 log.warn(e.getMessage() + " Aborting portDown.");
299 return;
300 }
301
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700302 log.debug("Device {} portDown {} to neighbor {}", deviceId, port,
303 portDeviceMap.get(port));
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700304 /*Set<NeighborSet> nsSet = computeImpactedNeighborsetForPortEvent(portDeviceMap
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700305 .get(port),
306 devicePortMap
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700307 .keySet());*/
308 Set<NeighborSet> nsSet = nsNextObjStore.keySet()
309 .stream()
310 .filter((nsStoreEntry) -> (nsStoreEntry.deviceId().equals(deviceId)))
311 .map((nsStoreEntry) -> (nsStoreEntry.neighborSet()))
312 .filter((ns) -> (ns.getDeviceIds()
313 .contains(portDeviceMap.get(port))))
314 .collect(Collectors.toSet());
Saurav Das62af8802015-12-04 10:52:59 -0800315 log.debug("portDown: nsNextObjStore contents for device {}:{}",
316 deviceId, nsSet);
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700317 for (NeighborSet ns : nsSet) {
Saurav Dasc3604f12016-03-23 11:22:49 -0700318 NeighborSetNextObjectiveStoreKey nsStoreKey =
319 new NeighborSetNextObjectiveStoreKey(deviceId, ns);
320 Integer nextId = nsNextObjStore.get(nsStoreKey);
Saurav Das62af8802015-12-04 10:52:59 -0800321 if (nextId != null && isMaster) {
Saurav Das4c35fc42015-11-20 15:27:53 -0800322 log.info("**portDown in device {}: Removing Bucket "
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700323 + "with Port {} to next object id {}",
324 deviceId,
325 port,
326 nextId);
Saurav Das62af8802015-12-04 10:52:59 -0800327 // Create the bucket to be removed
328 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment
329 .builder();
330 tBuilder.setOutput(port)
331 .setEthDst(dstMac)
332 .setEthSrc(nodeMacAddr);
333 if (ns.getEdgeLabel() != NeighborSet.NO_EDGE_LABEL) {
334 tBuilder.pushMpls()
335 .copyTtlOut()
336 .setMpls(MplsLabel.mplsLabel(ns.getEdgeLabel()));
337 }
338 NextObjective.Builder nextObjBuilder = DefaultNextObjective
339 .builder()
340 .withType(NextObjective.Type.HASHED) //same as original
341 .withId(nextId)
342 .fromApp(appId)
343 .addTreatment(tBuilder.build());
Saurav Dasd44e8802016-10-21 14:06:29 -0700344 ObjectiveContext context = new DefaultObjectiveContext(
345 (objective) -> log.debug("portDown removedFrom NextObj {} on {}",
346 nextId, deviceId),
347 (objective, error) ->
348 log.warn("portDown failed to removeFrom NextObj {} on {}: {}",
349 nextId, deviceId, error));
Saurav Das62af8802015-12-04 10:52:59 -0800350 NextObjective nextObjective = nextObjBuilder.
Saurav Dasd44e8802016-10-21 14:06:29 -0700351 removeFromExisting(context);
sangho2165d222015-05-01 09:38:25 -0700352
Saurav Das62af8802015-12-04 10:52:59 -0800353 flowObjectiveService.next(deviceId, nextObjective);
sangho2165d222015-05-01 09:38:25 -0700354 }
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700355 }
356
357 devicePortMap.get(portDeviceMap.get(port)).remove(port);
358 portDeviceMap.remove(port);
359 }
360
361 /**
Saurav Dasf0f592d2016-11-18 15:21:57 -0800362 * Adds or removes a port that has been configured with a subnet to a broadcast group
363 * for bridging. Note that this does not create the broadcast group itself.
Saurav Dasf9332192017-02-18 14:05:44 -0800364 * Should only be called by the master instance for this device/port.
Saurav Dasf0f592d2016-11-18 15:21:57 -0800365 *
366 * @param port the port on this device that needs to be added/removed to a bcast group
Charles Chan10b0fb72017-02-02 16:20:42 -0800367 * @param vlanId the vlan id corresponding to the broadcast group
Saurav Dasf0f592d2016-11-18 15:21:57 -0800368 * @param portUp true if port is enabled, false if disabled
Saurav Dasf0f592d2016-11-18 15:21:57 -0800369 */
Charles Chan10b0fb72017-02-02 16:20:42 -0800370 public void processEdgePort(PortNumber port, VlanId vlanId, boolean portUp) {
Saurav Dasf0f592d2016-11-18 15:21:57 -0800371 //get the next id for the subnet and edit it.
Charles Chan10b0fb72017-02-02 16:20:42 -0800372 Integer nextId = getVlanNextObjectiveId(vlanId);
Saurav Dasf0f592d2016-11-18 15:21:57 -0800373 if (nextId == -1) {
374 if (portUp) {
375 log.debug("**Creating flooding group for first port enabled in"
Charles Chan10b0fb72017-02-02 16:20:42 -0800376 + " subnet {} on dev {} port {}", vlanId, deviceId, port);
377 createBcastGroupFromVlan(vlanId, Collections.singleton(port));
Saurav Dasf0f592d2016-11-18 15:21:57 -0800378 } else {
379 log.warn("Could not find flooding group for subnet {} on dev:{} when"
Charles Chan10b0fb72017-02-02 16:20:42 -0800380 + " removing port:{}", vlanId, deviceId, port);
Saurav Dasf0f592d2016-11-18 15:21:57 -0800381 }
382 return;
383 }
384
385 log.info("**port{} in device {}: {} Bucket with Port {} to"
386 + " next-id {}", (portUp) ? "UP" : "DOWN", deviceId,
387 (portUp) ? "Adding" : "Removing",
388 port, nextId);
389 // Create the bucket to be added or removed
390 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
391 tBuilder.popVlan();
392 tBuilder.setOutput(port);
393
Charles Chan10b0fb72017-02-02 16:20:42 -0800394 VlanId untaggedVlan = srManager.getUntaggedVlanId(new ConnectPoint(deviceId, port));
395 VlanId assignedVlanId = (untaggedVlan != null) ? untaggedVlan : INTERNAL_VLAN;
396
Saurav Dasf0f592d2016-11-18 15:21:57 -0800397 TrafficSelector metadata =
398 DefaultTrafficSelector.builder().matchVlanId(assignedVlanId).build();
399
400 NextObjective.Builder nextObjBuilder = DefaultNextObjective
401 .builder().withId(nextId)
402 .withType(NextObjective.Type.BROADCAST).fromApp(appId)
403 .addTreatment(tBuilder.build())
404 .withMeta(metadata);
405
406 ObjectiveContext context = new DefaultObjectiveContext(
407 (objective) -> log.debug("port {} successfully {} NextObj {} on {}",
408 port, (portUp) ? "addedTo" : "removedFrom",
409 nextId, deviceId),
410 (objective, error) ->
411 log.warn("port {} failed to {} NextObj {} on {}: {}",
412 port, (portUp) ? "addTo" : "removeFrom",
413 nextId, deviceId, error));
414
415 NextObjective nextObj = (portUp) ? nextObjBuilder.addToExisting(context)
416 : nextObjBuilder.removeFromExisting(context);
417 log.debug("edgePort processed: Submited next objective {} in device {}",
418 nextId, deviceId);
419 flowObjectiveService.next(deviceId, nextObj);
420 }
421
422 /**
Saurav Das2d94d312015-11-24 23:21:05 -0800423 * Returns the next objective of type hashed associated with the neighborset.
424 * If there is no next objective for this neighborset, this method
Saurav Das4c35fc42015-11-20 15:27:53 -0800425 * would create a next objective and return. Optionally metadata can be
426 * passed in for the creation of the next objective.
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700427 *
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700428 * @param ns neighborset
Saurav Das4c35fc42015-11-20 15:27:53 -0800429 * @param meta metadata passed into the creation of a Next Objective
Pier Ventre229fd0b2016-10-31 16:49:19 -0700430 * @param isBos if Bos is set
Saurav Das4c35fc42015-11-20 15:27:53 -0800431 * @return int if found or -1 if there are errors in the creation of the
432 * neighbor set.
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700433 */
Pier Ventre229fd0b2016-10-31 16:49:19 -0700434 public int getNextObjectiveId(NeighborSet ns, TrafficSelector meta, boolean isBos) {
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700435 Integer nextId = nsNextObjStore.
436 get(new NeighborSetNextObjectiveStoreKey(deviceId, ns));
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700437 if (nextId == null) {
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700438 log.trace("getNextObjectiveId in device{}: Next objective id "
439 + "not found for {} and creating", deviceId, ns);
440 log.trace("getNextObjectiveId: nsNextObjStore contents for device {}: {}",
441 deviceId,
442 nsNextObjStore.entrySet()
443 .stream()
444 .filter((nsStoreEntry) ->
445 (nsStoreEntry.getKey().deviceId().equals(deviceId)))
446 .collect(Collectors.toList()));
Pier Ventre229fd0b2016-10-31 16:49:19 -0700447 createGroupsFromNeighborsets(Collections.singleton(ns), meta, isBos);
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700448 nextId = nsNextObjStore.
449 get(new NeighborSetNextObjectiveStoreKey(deviceId, ns));
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700450 if (nextId == null) {
451 log.warn("getNextObjectiveId: unable to create next objective");
452 return -1;
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700453 } else {
454 log.debug("getNextObjectiveId in device{}: Next objective id {} "
Sho SHIMIZUd1793352015-09-11 14:24:50 -0700455 + "created for {}", deviceId, nextId, ns);
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700456 }
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700457 } else {
458 log.trace("getNextObjectiveId in device{}: Next objective id {} "
Sho SHIMIZUd1793352015-09-11 14:24:50 -0700459 + "found for {}", deviceId, nextId, ns);
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700460 }
Sho SHIMIZUd1793352015-09-11 14:24:50 -0700461 return nextId;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700462 }
463
sangho4a5c42a2015-05-20 22:16:38 -0700464 /**
Charles Chan10b0fb72017-02-02 16:20:42 -0800465 * Returns the next objective of type broadcast associated with the vlan,
Saurav Das2d94d312015-11-24 23:21:05 -0800466 * or -1 if no such objective exists. Note that this method does NOT create
467 * the next objective as a side-effect. It is expected that is objective is
Saurav Dasf0f592d2016-11-18 15:21:57 -0800468 * created at startup from network configuration. Typically this is used
469 * for L2 flooding within the subnet configured on the switch.
Charles Chan77277672015-10-20 16:24:19 -0700470 *
Charles Chan10b0fb72017-02-02 16:20:42 -0800471 * @param vlanId vlan id
Charles Chan77277672015-10-20 16:24:19 -0700472 * @return int if found or -1
473 */
Charles Chan10b0fb72017-02-02 16:20:42 -0800474 public int getVlanNextObjectiveId(VlanId vlanId) {
475 Integer nextId = vlanNextObjStore.
476 get(new VlanNextObjectiveStoreKey(deviceId, vlanId));
Charles Chanc6ad7752015-10-29 14:58:10 -0700477
478 return (nextId != null) ? nextId : -1;
Charles Chan77277672015-10-20 16:24:19 -0700479 }
480
481 /**
Saurav Das2d94d312015-11-24 23:21:05 -0800482 * Returns the next objective of type simple associated with the port on the
483 * device, given the treatment. Different treatments to the same port result
484 * in different next objectives. If no such objective exists, this method
485 * creates one and returns the id. Optionally metadata can be passed in for
Saurav Dasf0f592d2016-11-18 15:21:57 -0800486 * the creation of the objective. Typically this is used for L2 and L3 forwarding
487 * to compute nodes and containers/VMs on the compute nodes directly attached
488 * to the switch.
Saurav Das2d94d312015-11-24 23:21:05 -0800489 *
490 * @param portNum the port number for the simple next objective
491 * @param treatment the actions to apply on the packets (should include outport)
492 * @param meta optional metadata passed into the creation of the next objective
493 * @return int if found or created, -1 if there are errors during the
494 * creation of the next objective.
495 */
496 public int getPortNextObjectiveId(PortNumber portNum, TrafficTreatment treatment,
497 TrafficSelector meta) {
Charles Chanb7f75ac2016-01-11 18:28:54 -0800498 Integer nextId = portNextObjStore
499 .get(new PortNextObjectiveStoreKey(deviceId, portNum, treatment));
Saurav Das2d94d312015-11-24 23:21:05 -0800500 if (nextId == null) {
501 log.trace("getPortNextObjectiveId in device{}: Next objective id "
502 + "not found for {} and {} creating", deviceId, portNum);
503 createGroupFromPort(portNum, treatment, meta);
504 nextId = portNextObjStore.get(
505 new PortNextObjectiveStoreKey(deviceId, portNum, treatment));
506 if (nextId == null) {
507 log.warn("getPortNextObjectiveId: unable to create next obj"
Charles Chanb7f75ac2016-01-11 18:28:54 -0800508 + "for dev:{} port:{}", deviceId, portNum);
509 return -1;
510 }
511 }
512 return nextId;
513 }
514
515 /**
sangho4a5c42a2015-05-20 22:16:38 -0700516 * Checks if the next objective ID (group) for the neighbor set exists or not.
517 *
518 * @param ns neighbor set to check
519 * @return true if it exists, false otherwise
520 */
521 public boolean hasNextObjectiveId(NeighborSet ns) {
522 Integer nextId = nsNextObjStore.
523 get(new NeighborSetNextObjectiveStoreKey(deviceId, ns));
524 if (nextId == null) {
525 return false;
526 }
527
528 return true;
529 }
530
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700531 // Empty implementation
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700532 protected void newNeighbor(Link newLink) {
533 }
534
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700535 // Empty implementation
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700536 protected void newPortToExistingNeighbor(Link newLink) {
537 }
538
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700539 // Empty implementation
540 protected Set<NeighborSet>
541 computeImpactedNeighborsetForPortEvent(DeviceId impactedNeighbor,
542 Set<DeviceId> updatedNeighbors) {
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700543 return null;
544 }
545
546 private void populateNeighborMaps() {
547 Set<Link> outgoingLinks = linkService.getDeviceEgressLinks(deviceId);
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700548 for (Link link : outgoingLinks) {
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700549 if (link.type() != Link.Type.DIRECT) {
550 continue;
551 }
552 addNeighborAtPort(link.dst().deviceId(), link.src().port());
553 }
554 }
555
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700556 protected void addNeighborAtPort(DeviceId neighborId,
557 PortNumber portToNeighbor) {
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700558 // Update DeviceToPort database
559 log.debug("Device {} addNeighborAtPort: neighbor {} at port {}",
560 deviceId, neighborId, portToNeighbor);
Saurav Das4c35fc42015-11-20 15:27:53 -0800561 Set<PortNumber> ports = Collections
562 .newSetFromMap(new ConcurrentHashMap<PortNumber, Boolean>());
563 ports.add(portToNeighbor);
564 Set<PortNumber> portnums = devicePortMap.putIfAbsent(neighborId, ports);
565 if (portnums != null) {
566 portnums.add(portToNeighbor);
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700567 }
568
569 // Update portToDevice database
Saurav Das4c35fc42015-11-20 15:27:53 -0800570 DeviceId prev = portDeviceMap.putIfAbsent(portToNeighbor, neighborId);
571 if (prev != null) {
572 log.warn("Device: {} port: {} has neighbor: {}. NOT updating "
573 + "to neighbor: {}", deviceId, portToNeighbor, prev, neighborId);
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700574 }
575 }
576
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700577 protected Set<Set<DeviceId>> getPowerSetOfNeighbors(Set<DeviceId> neighbors) {
Sho SHIMIZU47b8aa22015-09-11 11:19:11 -0700578 List<DeviceId> list = new ArrayList<>(neighbors);
579 Set<Set<DeviceId>> sets = new HashSet<>();
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700580 // get the number of elements in the neighbors
581 int elements = list.size();
582 // the number of members of a power set is 2^n
583 // including the empty set
584 int powerElements = (1 << elements);
585
586 // run a binary counter for the number of power elements
587 // NOTE: Exclude empty set
588 for (long i = 1; i < powerElements; i++) {
Sho SHIMIZU47b8aa22015-09-11 11:19:11 -0700589 Set<DeviceId> neighborSubSet = new HashSet<>();
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700590 for (int j = 0; j < elements; j++) {
591 if ((i >> j) % 2 == 1) {
592 neighborSubSet.add(list.get(j));
593 }
594 }
595 sets.add(neighborSubSet);
596 }
597 return sets;
598 }
599
600 private boolean isSegmentIdSameAsNodeSegmentId(DeviceId deviceId, int sId) {
Charles Chan319d1a22015-11-03 10:42:14 -0800601 int segmentId;
602 try {
Pier Ventre229fd0b2016-10-31 16:49:19 -0700603 // IPv6 sid is not inserted. this part of the code is not used for now.
Pier Ventreadb4ae62016-11-23 09:57:42 -0800604 segmentId = deviceConfig.getIPv4SegmentId(deviceId);
Charles Chan319d1a22015-11-03 10:42:14 -0800605 } catch (DeviceConfigNotFoundException e) {
606 log.warn(e.getMessage() + " Aborting isSegmentIdSameAsNodeSegmentId.");
607 return false;
608 }
609
610 return segmentId == sId;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700611 }
612
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700613 protected List<Integer> getSegmentIdsTobePairedWithNeighborSet(Set<DeviceId> neighbors) {
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700614
Sho SHIMIZU47b8aa22015-09-11 11:19:11 -0700615 List<Integer> nsSegmentIds = new ArrayList<>();
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700616
617 // Always pair up with no edge label
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700618 // If (neighbors.size() == 1) {
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700619 nsSegmentIds.add(-1);
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700620 // }
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700621
622 // Filter out SegmentIds matching with the
623 // nodes in the combo
624 for (Integer sId : allSegmentIds) {
Pier Ventreadb4ae62016-11-23 09:57:42 -0800625 if (sId.equals(this.ipv4NodeSegmentId)) {
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700626 continue;
627 }
628 boolean filterOut = false;
629 // Check if the edge label being set is of
630 // any node in the Neighbor set
631 for (DeviceId deviceId : neighbors) {
632 if (isSegmentIdSameAsNodeSegmentId(deviceId, sId)) {
633 filterOut = true;
634 break;
635 }
636 }
637 if (!filterOut) {
638 nsSegmentIds.add(sId);
639 }
640 }
641 return nsSegmentIds;
642 }
643
sangho27462c62015-05-14 00:39:53 -0700644 /**
Saurav Dasf0f592d2016-11-18 15:21:57 -0800645 * Creates hash groups from a set of NeighborSet given.
sangho27462c62015-05-14 00:39:53 -0700646 *
647 * @param nsSet a set of NeighborSet
Saurav Das4c35fc42015-11-20 15:27:53 -0800648 * @param meta metadata passed into the creation of a Next Objective
Pier Ventre229fd0b2016-10-31 16:49:19 -0700649 * @param isBos if BoS is set
sangho27462c62015-05-14 00:39:53 -0700650 */
Saurav Das4c35fc42015-11-20 15:27:53 -0800651 public void createGroupsFromNeighborsets(Set<NeighborSet> nsSet,
Pier Ventre229fd0b2016-10-31 16:49:19 -0700652 TrafficSelector meta,
653 boolean isBos) {
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700654 for (NeighborSet ns : nsSet) {
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700655 int nextId = flowObjectiveService.allocateNextId();
Pier Ventre229fd0b2016-10-31 16:49:19 -0700656 NextObjective.Type type = NextObjective.Type.HASHED;
657 Set<DeviceId> neighbors = ns.getDeviceIds();
658 // If Bos == False and MPLS-ECMP == false, we have
659 // to use simple group and we will pick a single neighbor.
660 if (!isBos && !srManager.getMplsEcmp()) {
661 type = NextObjective.Type.SIMPLE;
662 neighbors = Collections.singleton(ns.getFirstNeighbor());
663 }
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700664 NextObjective.Builder nextObjBuilder = DefaultNextObjective
Pier Ventre229fd0b2016-10-31 16:49:19 -0700665 .builder()
666 .withId(nextId)
667 .withType(type)
668 .fromApp(appId);
669 // For each neighbor, we have to update the sent actions
670 for (DeviceId neighborId : neighbors) {
Saurav Das4c35fc42015-11-20 15:27:53 -0800671 if (devicePortMap.get(neighborId) == null) {
672 log.warn("Neighbor {} is not in the port map yet for dev:{}",
673 neighborId, deviceId);
sangho2165d222015-05-01 09:38:25 -0700674 return;
Jon Hall31d84782017-01-18 20:15:44 -0800675 } else if (devicePortMap.get(neighborId).isEmpty()) {
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700676 log.warn("There are no ports for "
Saurav Das4c35fc42015-11-20 15:27:53 -0800677 + "the Device {} in the port map yet", neighborId);
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700678 return;
sangho2165d222015-05-01 09:38:25 -0700679 }
680
Saurav Das4c35fc42015-11-20 15:27:53 -0800681 MacAddress neighborMac;
Charles Chan319d1a22015-11-03 10:42:14 -0800682 try {
Saurav Das4c35fc42015-11-20 15:27:53 -0800683 neighborMac = deviceConfig.getDeviceMac(neighborId);
Charles Chan319d1a22015-11-03 10:42:14 -0800684 } catch (DeviceConfigNotFoundException e) {
685 log.warn(e.getMessage() + " Aborting createGroupsFromNeighborsets.");
686 return;
687 }
Pier Ventre229fd0b2016-10-31 16:49:19 -0700688 // For each port, we have to create a new treatment
689 Set<PortNumber> neighborPorts = devicePortMap.get(neighborId);
690 // In this case we are using a SIMPLE group. We randomly pick a port
691 if (!isBos && !srManager.getMplsEcmp()) {
692 int size = devicePortMap.get(neighborId).size();
693 int index = RandomUtils.nextInt(0, size);
694 neighborPorts = Collections.singleton(
695 Iterables.get(devicePortMap.get(neighborId), index)
696 );
697 }
698 for (PortNumber sp : neighborPorts) {
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700699 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment
700 .builder();
Saurav Das4c35fc42015-11-20 15:27:53 -0800701 tBuilder.setEthDst(neighborMac)
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700702 .setEthSrc(nodeMacAddr);
703 if (ns.getEdgeLabel() != NeighborSet.NO_EDGE_LABEL) {
Charles Chanf4586112015-11-09 16:37:23 -0800704 tBuilder.pushMpls()
705 .copyTtlOut()
706 .setMpls(MplsLabel.mplsLabel(ns.getEdgeLabel()));
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700707 }
Saurav Das4c35fc42015-11-20 15:27:53 -0800708 tBuilder.setOutput(sp);
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700709 nextObjBuilder.addTreatment(tBuilder.build());
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700710 }
711 }
Saurav Das4c35fc42015-11-20 15:27:53 -0800712 if (meta != null) {
Saurav Das2d94d312015-11-24 23:21:05 -0800713 nextObjBuilder.withMeta(meta);
Saurav Das4c35fc42015-11-20 15:27:53 -0800714 }
Charles Chana4ee4f92016-04-23 14:48:16 -0700715
716 ObjectiveContext context = new DefaultObjectiveContext(
Pier Ventre229fd0b2016-10-31 16:49:19 -0700717 (objective) ->
718 log.debug("createGroupsFromNeighborsets installed NextObj {} on {}",
Charles Chana4ee4f92016-04-23 14:48:16 -0700719 nextId, deviceId),
720 (objective, error) ->
721 log.warn("createGroupsFromNeighborsets failed to install NextObj {} on {}: {}",
Pier Ventre229fd0b2016-10-31 16:49:19 -0700722 nextId, deviceId, error)
723 );
Charles Chana4ee4f92016-04-23 14:48:16 -0700724 NextObjective nextObj = nextObjBuilder.add(context);
725 log.debug("**createGroupsFromNeighborsets: Submited "
Saurav Das4c35fc42015-11-20 15:27:53 -0800726 + "next objective {} in device {}",
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700727 nextId, deviceId);
Saurav Das4c35fc42015-11-20 15:27:53 -0800728 flowObjectiveService.next(deviceId, nextObj);
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700729 nsNextObjStore.put(new NeighborSetNextObjectiveStoreKey(deviceId, ns),
730 nextId);
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700731 }
732 }
733
Saurav Das2d94d312015-11-24 23:21:05 -0800734 /**
Saurav Dasf0f592d2016-11-18 15:21:57 -0800735 * Creates broadcast groups for all ports in the same subnet for
736 * all configured subnets.
Saurav Das2d94d312015-11-24 23:21:05 -0800737 */
Charles Chan10b0fb72017-02-02 16:20:42 -0800738 public void createGroupsFromVlanConfig() {
739 Set<Interface> interfaces = srManager.interfaceService.getInterfaces();
740 Set<VlanId> vlans =
741 interfaces.stream()
742 .filter(intf -> intf.connectPoint().deviceId().equals(deviceId) &&
743 !intf.vlanUntagged().equals(VlanId.NONE))
744 .map(Interface::vlanUntagged)
745 .collect(Collectors.toSet());
746
747 vlans.forEach(vlanId -> {
748 Set<PortNumber> ports = interfaces.stream()
749 .filter(intf -> intf.connectPoint().deviceId().equals(deviceId) &&
750 intf.vlanUntagged().equals(vlanId))
751 .map(Interface::connectPoint)
752 .map(ConnectPoint::port)
753 .collect(Collectors.toSet());
754 createBcastGroupFromVlan(vlanId, ports);
Pier Ventreb6a7f342016-11-26 21:05:22 -0800755 });
Saurav Dasf0f592d2016-11-18 15:21:57 -0800756 }
Charles Chanc6ad7752015-10-29 14:58:10 -0700757
Saurav Dasf0f592d2016-11-18 15:21:57 -0800758 /**
Charles Chan10b0fb72017-02-02 16:20:42 -0800759 * Creates a single broadcast group from a given vlan id and list of ports.
Saurav Dasf0f592d2016-11-18 15:21:57 -0800760 *
Charles Chan10b0fb72017-02-02 16:20:42 -0800761 * @param vlanId vlan id
Saurav Dasf0f592d2016-11-18 15:21:57 -0800762 * @param ports list of ports in the subnet
763 */
Charles Chan10b0fb72017-02-02 16:20:42 -0800764 public void createBcastGroupFromVlan(VlanId vlanId, Set<PortNumber> ports) {
765 VlanNextObjectiveStoreKey key = new VlanNextObjectiveStoreKey(deviceId, vlanId);
Charles Chanc6ad7752015-10-29 14:58:10 -0700766
Charles Chan10b0fb72017-02-02 16:20:42 -0800767 if (vlanNextObjStore.containsKey(key)) {
Saurav Dasf0f592d2016-11-18 15:21:57 -0800768 log.debug("Broadcast group for device {} and subnet {} exists",
Charles Chan10b0fb72017-02-02 16:20:42 -0800769 deviceId, vlanId);
Saurav Dasf0f592d2016-11-18 15:21:57 -0800770 return;
771 }
Charles Chande6655c2015-12-23 00:15:11 -0800772
Saurav Dasf0f592d2016-11-18 15:21:57 -0800773 TrafficSelector metadata =
Charles Chan10b0fb72017-02-02 16:20:42 -0800774 DefaultTrafficSelector.builder().matchVlanId(vlanId).build();
Charles Chan77277672015-10-20 16:24:19 -0700775
Saurav Dasf0f592d2016-11-18 15:21:57 -0800776 int nextId = flowObjectiveService.allocateNextId();
Charles Chan77277672015-10-20 16:24:19 -0700777
Saurav Dasf0f592d2016-11-18 15:21:57 -0800778 NextObjective.Builder nextObjBuilder = DefaultNextObjective
779 .builder().withId(nextId)
780 .withType(NextObjective.Type.BROADCAST).fromApp(appId)
781 .withMeta(metadata);
Charles Chan77277672015-10-20 16:24:19 -0700782
Saurav Dasf0f592d2016-11-18 15:21:57 -0800783 ports.forEach(port -> {
784 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
785 tBuilder.popVlan();
786 tBuilder.setOutput(port);
787 nextObjBuilder.addTreatment(tBuilder.build());
Charles Chan77277672015-10-20 16:24:19 -0700788 });
Saurav Dasf0f592d2016-11-18 15:21:57 -0800789
790 NextObjective nextObj = nextObjBuilder.add();
791 flowObjectiveService.next(deviceId, nextObj);
Charles Chan10b0fb72017-02-02 16:20:42 -0800792 log.debug("createBcastGroupFromVlan: Submited next objective {} in device {}",
Saurav Dasf0f592d2016-11-18 15:21:57 -0800793 nextId, deviceId);
794
Charles Chan10b0fb72017-02-02 16:20:42 -0800795 vlanNextObjStore.put(key, nextId);
Charles Chan77277672015-10-20 16:24:19 -0700796 }
797
Charles Chanb7f75ac2016-01-11 18:28:54 -0800798 /**
Saurav Das2d94d312015-11-24 23:21:05 -0800799 * Create simple next objective for a single port. The treatments can include
800 * all outgoing actions that need to happen on the packet.
801 *
802 * @param portNum the outgoing port on the device
803 * @param treatment the actions to apply on the packets (should include outport)
804 * @param meta optional data to pass to the driver
805 */
806 public void createGroupFromPort(PortNumber portNum, TrafficTreatment treatment,
807 TrafficSelector meta) {
808 int nextId = flowObjectiveService.allocateNextId();
809 PortNextObjectiveStoreKey key = new PortNextObjectiveStoreKey(
810 deviceId, portNum, treatment);
811
812 NextObjective.Builder nextObjBuilder = DefaultNextObjective
813 .builder().withId(nextId)
814 .withType(NextObjective.Type.SIMPLE)
815 .addTreatment(treatment)
816 .fromApp(appId)
817 .withMeta(meta);
818
819 NextObjective nextObj = nextObjBuilder.add();
820 flowObjectiveService.next(deviceId, nextObj);
821 log.debug("createGroupFromPort: Submited next objective {} in device {} "
822 + "for port {}", nextId, deviceId, portNum);
823
824 portNextObjStore.put(key, nextId);
825 }
826
sangho27462c62015-05-14 00:39:53 -0700827 /**
828 * Removes groups for the next objective ID given.
829 *
830 * @param objectiveId next objective ID to remove
831 * @return true if succeeds, false otherwise
832 */
833 public boolean removeGroup(int objectiveId) {
834
835 if (nsNextObjStore.containsValue(objectiveId)) {
836 NextObjective.Builder nextObjBuilder = DefaultNextObjective
837 .builder().withId(objectiveId)
838 .withType(NextObjective.Type.HASHED).fromApp(appId);
Charles Chana4ee4f92016-04-23 14:48:16 -0700839 ObjectiveContext context = new DefaultObjectiveContext(
840 (objective) -> log.debug("RemoveGroup removes NextObj {} on {}",
841 objectiveId, deviceId),
842 (objective, error) ->
843 log.warn("RemoveGroup failed to remove NextObj {} on {}: {}",
844 objectiveId, deviceId, error));
845 NextObjective nextObjective = nextObjBuilder.remove(context);
Saurav Das4c35fc42015-11-20 15:27:53 -0800846 log.info("**removeGroup: Submited "
847 + "next objective {} in device {}",
848 objectiveId, deviceId);
sangho27462c62015-05-14 00:39:53 -0700849 flowObjectiveService.next(deviceId, nextObjective);
850
851 for (Map.Entry<NeighborSetNextObjectiveStoreKey, Integer> entry: nsNextObjStore.entrySet()) {
852 if (entry.getValue().equals(objectiveId)) {
853 nsNextObjStore.remove(entry.getKey());
854 break;
855 }
856 }
sangho4a5c42a2015-05-20 22:16:38 -0700857 return true;
sangho27462c62015-05-14 00:39:53 -0700858 }
859
860 return false;
861 }
Srikanth Vavilapalli8c83f1d2015-05-22 13:47:31 -0700862
Charles Chanb7f75ac2016-01-11 18:28:54 -0800863 /**
864 * Removes all groups from all next objective stores.
865 */
Saurav Das62af8802015-12-04 10:52:59 -0800866 public void removeAllGroups() {
867 for (Map.Entry<NeighborSetNextObjectiveStoreKey, Integer> entry:
868 nsNextObjStore.entrySet()) {
869 removeGroup(entry.getValue());
870 }
871 for (Map.Entry<PortNextObjectiveStoreKey, Integer> entry:
872 portNextObjStore.entrySet()) {
873 removeGroup(entry.getValue());
874 }
Charles Chan10b0fb72017-02-02 16:20:42 -0800875 for (Map.Entry<VlanNextObjectiveStoreKey, Integer> entry:
876 vlanNextObjStore.entrySet()) {
Saurav Das62af8802015-12-04 10:52:59 -0800877 removeGroup(entry.getValue());
878 }
879 // should probably clean local stores port-neighbor
880 }
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700881}