blob: e73a0d85e3bd75532637b45078d1fde936fbabe8 [file] [log] [blame]
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -08001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2015-present Open Networking Laboratory
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -08003 *
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
Charles Chan59cc16d2017-02-02 16:20:42 -080018
Pier Ventre917127a2016-10-31 16:49:19 -070019import com.google.common.collect.Iterables;
20import org.apache.commons.lang3.RandomUtils;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080021import org.onlab.packet.MacAddress;
sangho32a59322015-02-17 12:07:41 -080022import org.onlab.packet.MplsLabel;
Saurav Das423fe2b2015-12-04 10:52:59 -080023import org.onlab.packet.VlanId;
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -070024import org.onlab.util.KryoNamespace;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080025import org.onosproject.core.ApplicationId;
Charles Chan59cc16d2017-02-02 16:20:42 -080026import org.onosproject.incubator.net.intf.Interface;
27import org.onosproject.net.ConnectPoint;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080028import org.onosproject.net.DeviceId;
29import org.onosproject.net.Link;
30import org.onosproject.net.PortNumber;
Saurav Das423fe2b2015-12-04 10:52:59 -080031import org.onosproject.net.flow.DefaultTrafficSelector;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080032import org.onosproject.net.flow.DefaultTrafficTreatment;
Saurav Das8a0732e2015-11-20 15:27:53 -080033import org.onosproject.net.flow.TrafficSelector;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080034import org.onosproject.net.flow.TrafficTreatment;
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070035import org.onosproject.net.flowobjective.DefaultNextObjective;
Charles Chan216e3c82016-04-23 14:48:16 -070036import org.onosproject.net.flowobjective.DefaultObjectiveContext;
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070037import org.onosproject.net.flowobjective.FlowObjectiveService;
38import org.onosproject.net.flowobjective.NextObjective;
Srikanth Vavilapallif3a8bc02015-05-22 13:47:31 -070039import org.onosproject.net.flowobjective.ObjectiveContext;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080040import org.onosproject.net.link.LinkService;
Saurav Das423fe2b2015-12-04 10:52:59 -080041import org.onosproject.segmentrouting.SegmentRoutingManager;
Charles Chan0b4e6182015-11-03 10:42:14 -080042import org.onosproject.segmentrouting.config.DeviceConfigNotFoundException;
43import org.onosproject.segmentrouting.config.DeviceProperties;
Charles Chand2990362016-04-18 13:44:03 -070044import org.onosproject.segmentrouting.storekey.NeighborSetNextObjectiveStoreKey;
45import org.onosproject.segmentrouting.storekey.PortNextObjectiveStoreKey;
Charles Chan59cc16d2017-02-02 16:20:42 -080046import org.onosproject.segmentrouting.storekey.VlanNextObjectiveStoreKey;
Srikanth Vavilapalli23181912015-05-04 09:48:09 -070047import org.onosproject.store.service.EventuallyConsistentMap;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080048import org.slf4j.Logger;
49
Pier Ventre917127a2016-10-31 16:49:19 -070050import java.net.URI;
51import java.util.ArrayList;
Charles Chan7ffd81f2017-02-08 15:52:08 -080052import java.util.Collection;
Pier Ventre917127a2016-10-31 16:49:19 -070053import java.util.Collections;
54import java.util.HashSet;
55import java.util.List;
56import java.util.Map;
57import java.util.Set;
58import java.util.concurrent.ConcurrentHashMap;
59import java.util.stream.Collectors;
60
61import static com.google.common.base.Preconditions.checkNotNull;
Charles Chan59cc16d2017-02-02 16:20:42 -080062import static org.onosproject.segmentrouting.SegmentRoutingManager.INTERNAL_VLAN;
Pier Ventre917127a2016-10-31 16:49:19 -070063import static org.slf4j.LoggerFactory.getLogger;
64
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080065/**
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070066 * Default ECMP group handler creation module. This component creates a set of
67 * ECMP groups for every neighbor that this device is connected to based on
68 * whether the current device is an edge device or a transit device.
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080069 */
70public class DefaultGroupHandler {
Srikanth Vavilapallif3a8bc02015-05-22 13:47:31 -070071 protected static final Logger log = getLogger(DefaultGroupHandler.class);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080072
73 protected final DeviceId deviceId;
74 protected final ApplicationId appId;
75 protected final DeviceProperties deviceConfig;
76 protected final List<Integer> allSegmentIds;
Pier Ventree0ae7a32016-11-23 09:57:42 -080077 protected int ipv4NodeSegmentId = -1;
78 protected int ipv6NodeSegmentId = -1;
Charles Chan0b4e6182015-11-03 10:42:14 -080079 protected boolean isEdgeRouter = false;
80 protected MacAddress nodeMacAddr = null;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080081 protected LinkService linkService;
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070082 protected FlowObjectiveService flowObjectiveService;
Saurav Das423fe2b2015-12-04 10:52:59 -080083 // local store for neighbor-device-ids and the set of ports on this device
84 // that connect to the same neighbor
Saurav Das8a0732e2015-11-20 15:27:53 -080085 protected ConcurrentHashMap<DeviceId, Set<PortNumber>> devicePortMap =
86 new ConcurrentHashMap<>();
Saurav Das1a129a02016-11-18 15:21:57 -080087 // local store for ports on this device connected to neighbor-device-id
Saurav Das8a0732e2015-11-20 15:27:53 -080088 protected ConcurrentHashMap<PortNumber, DeviceId> portDeviceMap =
89 new ConcurrentHashMap<>();
Saurav Das1a129a02016-11-18 15:21:57 -080090 // distributed store for (device+neighborset) mapped to next-id
Charles Chane849c192016-01-11 18:28:54 -080091 protected EventuallyConsistentMap<NeighborSetNextObjectiveStoreKey, Integer>
92 nsNextObjStore = null;
Saurav Das1a129a02016-11-18 15:21:57 -080093 // distributed store for (device+subnet-ip-prefix) mapped to next-id
Charles Chan59cc16d2017-02-02 16:20:42 -080094 protected EventuallyConsistentMap<VlanNextObjectiveStoreKey, Integer>
95 vlanNextObjStore = null;
Saurav Das1a129a02016-11-18 15:21:57 -080096 // distributed store for (device+port+treatment) mapped to next-id
Charles Chane849c192016-01-11 18:28:54 -080097 protected EventuallyConsistentMap<PortNextObjectiveStoreKey, Integer>
98 portNextObjStore = null;
Charles Chan188ebf52015-12-23 00:15:11 -080099 private SegmentRoutingManager srManager;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800100
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700101 protected KryoNamespace.Builder kryo = new KryoNamespace.Builder()
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700102 .register(URI.class).register(HashSet.class)
103 .register(DeviceId.class).register(PortNumber.class)
104 .register(NeighborSet.class).register(PolicyGroupIdentifier.class)
105 .register(PolicyGroupParams.class)
106 .register(GroupBucketIdentifier.class)
107 .register(GroupBucketIdentifier.BucketOutputType.class);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800108
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700109 protected DefaultGroupHandler(DeviceId deviceId, ApplicationId appId,
110 DeviceProperties config,
111 LinkService linkService,
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700112 FlowObjectiveService flowObjService,
Charles Chan188ebf52015-12-23 00:15:11 -0800113 SegmentRoutingManager srManager) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800114 this.deviceId = checkNotNull(deviceId);
115 this.appId = checkNotNull(appId);
116 this.deviceConfig = checkNotNull(config);
117 this.linkService = checkNotNull(linkService);
Charles Chan0b4e6182015-11-03 10:42:14 -0800118 this.allSegmentIds = checkNotNull(config.getAllDeviceSegmentIds());
119 try {
Pier Ventree0ae7a32016-11-23 09:57:42 -0800120 this.ipv4NodeSegmentId = config.getIPv4SegmentId(deviceId);
121 this.ipv6NodeSegmentId = config.getIPv6SegmentId(deviceId);
Charles Chan0b4e6182015-11-03 10:42:14 -0800122 this.isEdgeRouter = config.isEdgeDevice(deviceId);
123 this.nodeMacAddr = checkNotNull(config.getDeviceMac(deviceId));
124 } catch (DeviceConfigNotFoundException e) {
125 log.warn(e.getMessage()
126 + " Skipping value assignment in DefaultGroupHandler");
127 }
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700128 this.flowObjectiveService = flowObjService;
Ray Milkeye4afdb52017-04-05 09:42:04 -0700129 this.nsNextObjStore = srManager.nsNextObjStore();
130 this.vlanNextObjStore = srManager.vlanNextObjStore();
131 this.portNextObjStore = srManager.portNextObjStore();
Charles Chan188ebf52015-12-23 00:15:11 -0800132 this.srManager = srManager;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800133
134 populateNeighborMaps();
135 }
136
137 /**
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700138 * Creates a group handler object based on the type of device. If device is
139 * of edge type it returns edge group handler, else it returns transit group
140 * handler.
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800141 *
142 * @param deviceId device identifier
143 * @param appId application identifier
144 * @param config interface to retrieve the device properties
145 * @param linkService link service object
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700146 * @param flowObjService flow objective service object
Charles Chane849c192016-01-11 18:28:54 -0800147 * @param srManager segment routing manager
Charles Chan0b4e6182015-11-03 10:42:14 -0800148 * @throws DeviceConfigNotFoundException if the device configuration is not found
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800149 * @return default group handler type
150 */
Saurav Das4ce45962015-11-24 23:21:05 -0800151 public static DefaultGroupHandler createGroupHandler(
152 DeviceId deviceId,
153 ApplicationId appId,
154 DeviceProperties config,
155 LinkService linkService,
156 FlowObjectiveService flowObjService,
Charles Chan188ebf52015-12-23 00:15:11 -0800157 SegmentRoutingManager srManager)
Saurav Das4ce45962015-11-24 23:21:05 -0800158 throws DeviceConfigNotFoundException {
Charles Chan0b4e6182015-11-03 10:42:14 -0800159 // handle possible exception in the caller
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800160 if (config.isEdgeDevice(deviceId)) {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700161 return new DefaultEdgeGroupHandler(deviceId, appId, config,
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700162 linkService,
163 flowObjService,
Charles Chan188ebf52015-12-23 00:15:11 -0800164 srManager
165 );
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800166 } else {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700167 return new DefaultTransitGroupHandler(deviceId, appId, config,
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700168 linkService,
169 flowObjService,
Charles Chan188ebf52015-12-23 00:15:11 -0800170 srManager);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800171 }
172 }
173
174 /**
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700175 * Creates the auto created groups for this device based on the current
176 * snapshot of the topology.
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800177 */
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700178 // Empty implementations to be overridden by derived classes
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800179 public void createGroups() {
180 }
181
182 /**
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700183 * Performs group creation or update procedures when a new link is
184 * discovered on this device.
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800185 *
186 * @param newLink new neighbor link
Charles Chane849c192016-01-11 18:28:54 -0800187 * @param isMaster true if local instance is the master
188 *
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800189 */
Saurav Das8a0732e2015-11-20 15:27:53 -0800190 public void linkUp(Link newLink, boolean isMaster) {
sanghob35a6192015-04-01 13:05:26 -0700191
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800192 if (newLink.type() != Link.Type.DIRECT) {
Charles Chanb1f8c762017-03-29 16:39:05 -0700193 // NOTE: A DIRECT link might be transiently marked as INDIRECT
194 // if BDDP is received before LLDP. We can safely ignore that
195 // until the LLDP is received and the link is marked as DIRECT.
196 log.info("Ignore link {}->{}. Link type is {} instead of DIRECT.",
197 newLink.src(), newLink.dst(), newLink.type());
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800198 return;
199 }
200
201 if (!newLink.src().deviceId().equals(deviceId)) {
Charles Chanb1f8c762017-03-29 16:39:05 -0700202 log.warn("linkUp: deviceId{} doesn't match with link src {}",
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700203 deviceId, newLink.src().deviceId());
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800204 return;
205 }
206
Saurav Das8a0732e2015-11-20 15:27:53 -0800207 log.info("* LinkUP: Device {} linkUp at local port {} to neighbor {}", deviceId,
208 newLink.src().port(), newLink.dst().deviceId());
Saurav Das59232cf2016-04-27 18:35:50 -0700209 // ensure local state is updated even if linkup is aborted later on
210 addNeighborAtPort(newLink.dst().deviceId(),
211 newLink.src().port());
212
Charles Chan0b4e6182015-11-03 10:42:14 -0800213 MacAddress dstMac;
214 try {
215 dstMac = deviceConfig.getDeviceMac(newLink.dst().deviceId());
216 } catch (DeviceConfigNotFoundException e) {
217 log.warn(e.getMessage() + " Aborting linkUp.");
218 return;
219 }
220
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700221 /*if (devicePortMap.get(newLink.dst().deviceId()) == null) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800222 // New Neighbor
223 newNeighbor(newLink);
224 } else {
225 // Old Neighbor
226 newPortToExistingNeighbor(newLink);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700227 }*/
228 Set<NeighborSet> nsSet = nsNextObjStore.keySet()
229 .stream()
230 .filter((nsStoreEntry) -> (nsStoreEntry.deviceId().equals(deviceId)))
231 .map((nsStoreEntry) -> (nsStoreEntry.neighborSet()))
232 .filter((ns) -> (ns.getDeviceIds()
233 .contains(newLink.dst().deviceId())))
234 .collect(Collectors.toSet());
235 log.trace("linkUp: nsNextObjStore contents for device {}:",
sangho0b2b6d12015-05-20 22:16:38 -0700236 deviceId,
237 nsSet);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700238 for (NeighborSet ns : nsSet) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700239 Integer nextId = nsNextObjStore.
240 get(new NeighborSetNextObjectiveStoreKey(deviceId, ns));
Saurav Das4ce45962015-11-24 23:21:05 -0800241 if (nextId != null && isMaster) {
Saurav Das423fe2b2015-12-04 10:52:59 -0800242 // Create the new bucket to be updated
243 TrafficTreatment.Builder tBuilder =
244 DefaultTrafficTreatment.builder();
245 tBuilder.setOutput(newLink.src().port())
246 .setEthDst(dstMac)
247 .setEthSrc(nodeMacAddr);
248 if (ns.getEdgeLabel() != NeighborSet.NO_EDGE_LABEL) {
249 tBuilder.pushMpls()
250 .copyTtlOut()
251 .setMpls(MplsLabel.mplsLabel(ns.getEdgeLabel()));
252 }
253 // setup metadata to pass to nextObjective - indicate the vlan on egress
254 // if needed by the switch pipeline. Since hashed next-hops are always to
255 // other neighboring routers, there is no subnet assigned on those ports.
256 TrafficSelector.Builder metabuilder = DefaultTrafficSelector.builder();
Charles Chan59cc16d2017-02-02 16:20:42 -0800257 metabuilder.matchVlanId(INTERNAL_VLAN);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700258
Saurav Das423fe2b2015-12-04 10:52:59 -0800259 NextObjective.Builder nextObjBuilder = DefaultNextObjective.builder()
260 .withId(nextId)
261 .withType(NextObjective.Type.HASHED)
262 .addTreatment(tBuilder.build())
263 .withMeta(metabuilder.build())
264 .fromApp(appId);
Saurav Das8a0732e2015-11-20 15:27:53 -0800265 log.info("**linkUp in device {}: Adding Bucket "
Saurav Das4ce45962015-11-24 23:21:05 -0800266 + "with Port {} to next object id {}",
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700267 deviceId,
268 newLink.src().port(),
Saurav Das4ce45962015-11-24 23:21:05 -0800269 nextId);
Charles Chan216e3c82016-04-23 14:48:16 -0700270
271 ObjectiveContext context = new DefaultObjectiveContext(
Saurav Das1ce0a7b2016-10-21 14:06:29 -0700272 (objective) -> log.debug("LinkUp addedTo NextObj {} on {}",
Charles Chan216e3c82016-04-23 14:48:16 -0700273 nextId, deviceId),
274 (objective, error) ->
Saurav Das1ce0a7b2016-10-21 14:06:29 -0700275 log.warn("LinkUp failed to addTo NextObj {} on {}: {}",
Charles Chan216e3c82016-04-23 14:48:16 -0700276 nextId, deviceId, error));
277 NextObjective nextObjective = nextObjBuilder.addToExisting(context);
Saurav Das4ce45962015-11-24 23:21:05 -0800278 flowObjectiveService.next(deviceId, nextObjective);
279 } else if (isMaster) {
Saurav Das8a0732e2015-11-20 15:27:53 -0800280 log.warn("linkUp in device {}, but global store has no record "
281 + "for neighbor-set {}", deviceId, ns);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700282 }
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800283 }
284 }
285
286 /**
Saurav Das1a129a02016-11-18 15:21:57 -0800287 * Performs hash group recovery procedures when a switch-to-switch
288 * port goes down on this device.
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800289 *
290 * @param port port number that has gone down
Charles Chane849c192016-01-11 18:28:54 -0800291 * @param isMaster true if local instance is the master
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800292 */
Saurav Das423fe2b2015-12-04 10:52:59 -0800293 public void portDown(PortNumber port, boolean isMaster) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800294 if (portDeviceMap.get(port) == null) {
295 log.warn("portDown: unknown port");
296 return;
297 }
Charles Chan0b4e6182015-11-03 10:42:14 -0800298
299 MacAddress dstMac;
300 try {
301 dstMac = deviceConfig.getDeviceMac(portDeviceMap.get(port));
302 } catch (DeviceConfigNotFoundException e) {
303 log.warn(e.getMessage() + " Aborting portDown.");
304 return;
305 }
306
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700307 log.debug("Device {} portDown {} to neighbor {}", deviceId, port,
308 portDeviceMap.get(port));
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700309 /*Set<NeighborSet> nsSet = computeImpactedNeighborsetForPortEvent(portDeviceMap
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700310 .get(port),
311 devicePortMap
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700312 .keySet());*/
313 Set<NeighborSet> nsSet = nsNextObjStore.keySet()
314 .stream()
315 .filter((nsStoreEntry) -> (nsStoreEntry.deviceId().equals(deviceId)))
316 .map((nsStoreEntry) -> (nsStoreEntry.neighborSet()))
317 .filter((ns) -> (ns.getDeviceIds()
318 .contains(portDeviceMap.get(port))))
319 .collect(Collectors.toSet());
Saurav Das423fe2b2015-12-04 10:52:59 -0800320 log.debug("portDown: nsNextObjStore contents for device {}:{}",
321 deviceId, nsSet);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800322 for (NeighborSet ns : nsSet) {
Saurav Das80980c72016-03-23 11:22:49 -0700323 NeighborSetNextObjectiveStoreKey nsStoreKey =
324 new NeighborSetNextObjectiveStoreKey(deviceId, ns);
325 Integer nextId = nsNextObjStore.get(nsStoreKey);
Saurav Das423fe2b2015-12-04 10:52:59 -0800326 if (nextId != null && isMaster) {
Saurav Das8a0732e2015-11-20 15:27:53 -0800327 log.info("**portDown in device {}: Removing Bucket "
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700328 + "with Port {} to next object id {}",
329 deviceId,
330 port,
331 nextId);
Saurav Das423fe2b2015-12-04 10:52:59 -0800332 // Create the bucket to be removed
333 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment
334 .builder();
335 tBuilder.setOutput(port)
336 .setEthDst(dstMac)
337 .setEthSrc(nodeMacAddr);
338 if (ns.getEdgeLabel() != NeighborSet.NO_EDGE_LABEL) {
339 tBuilder.pushMpls()
340 .copyTtlOut()
341 .setMpls(MplsLabel.mplsLabel(ns.getEdgeLabel()));
342 }
343 NextObjective.Builder nextObjBuilder = DefaultNextObjective
344 .builder()
345 .withType(NextObjective.Type.HASHED) //same as original
346 .withId(nextId)
347 .fromApp(appId)
348 .addTreatment(tBuilder.build());
Saurav Das1ce0a7b2016-10-21 14:06:29 -0700349 ObjectiveContext context = new DefaultObjectiveContext(
350 (objective) -> log.debug("portDown removedFrom NextObj {} on {}",
351 nextId, deviceId),
352 (objective, error) ->
353 log.warn("portDown failed to removeFrom NextObj {} on {}: {}",
354 nextId, deviceId, error));
Saurav Das423fe2b2015-12-04 10:52:59 -0800355 NextObjective nextObjective = nextObjBuilder.
Saurav Das1ce0a7b2016-10-21 14:06:29 -0700356 removeFromExisting(context);
sangho834e4b02015-05-01 09:38:25 -0700357
Saurav Das423fe2b2015-12-04 10:52:59 -0800358 flowObjectiveService.next(deviceId, nextObjective);
sangho834e4b02015-05-01 09:38:25 -0700359 }
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800360 }
361
362 devicePortMap.get(portDeviceMap.get(port)).remove(port);
363 portDeviceMap.remove(port);
364 }
365
366 /**
Saurav Dasb0ae6ee2017-03-04 16:08:47 -0800367 * Adds or removes a port that has been configured with a vlan to a broadcast group
368 * for bridging. Should only be called by the master instance for this device.
Saurav Das1a129a02016-11-18 15:21:57 -0800369 *
370 * @param port the port on this device that needs to be added/removed to a bcast group
Saurav Dasb0ae6ee2017-03-04 16:08:47 -0800371 * @param vlanId the vlan id corresponding to the broadcast domain/group
372 * @param popVlan indicates if packets should be sent out untagged or not out
373 * of the port. If true, indicates an access (untagged) or native vlan
374 * configuration. If false, indicates a trunk (tagged) vlan config.
Saurav Das1a129a02016-11-18 15:21:57 -0800375 * @param portUp true if port is enabled, false if disabled
Saurav Das1a129a02016-11-18 15:21:57 -0800376 */
Saurav Dasb0ae6ee2017-03-04 16:08:47 -0800377 public void processEdgePort(PortNumber port, VlanId vlanId,
378 boolean popVlan, boolean portUp) {
Saurav Das1a129a02016-11-18 15:21:57 -0800379 //get the next id for the subnet and edit it.
Charles Chan59cc16d2017-02-02 16:20:42 -0800380 Integer nextId = getVlanNextObjectiveId(vlanId);
Saurav Das1a129a02016-11-18 15:21:57 -0800381 if (nextId == -1) {
382 if (portUp) {
383 log.debug("**Creating flooding group for first port enabled in"
Charles Chan59cc16d2017-02-02 16:20:42 -0800384 + " subnet {} on dev {} port {}", vlanId, deviceId, port);
385 createBcastGroupFromVlan(vlanId, Collections.singleton(port));
Saurav Das1a129a02016-11-18 15:21:57 -0800386 } else {
387 log.warn("Could not find flooding group for subnet {} on dev:{} when"
Charles Chan59cc16d2017-02-02 16:20:42 -0800388 + " removing port:{}", vlanId, deviceId, port);
Saurav Das1a129a02016-11-18 15:21:57 -0800389 }
390 return;
391 }
392
393 log.info("**port{} in device {}: {} Bucket with Port {} to"
394 + " next-id {}", (portUp) ? "UP" : "DOWN", deviceId,
395 (portUp) ? "Adding" : "Removing",
396 port, nextId);
397 // Create the bucket to be added or removed
398 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
Saurav Dasb0ae6ee2017-03-04 16:08:47 -0800399 if (popVlan) {
400 tBuilder.popVlan();
401 }
Saurav Das1a129a02016-11-18 15:21:57 -0800402 tBuilder.setOutput(port);
403
Saurav Das1a129a02016-11-18 15:21:57 -0800404 TrafficSelector metadata =
Saurav Dasb0ae6ee2017-03-04 16:08:47 -0800405 DefaultTrafficSelector.builder().matchVlanId(vlanId).build();
Saurav Das1a129a02016-11-18 15:21:57 -0800406
407 NextObjective.Builder nextObjBuilder = DefaultNextObjective
408 .builder().withId(nextId)
409 .withType(NextObjective.Type.BROADCAST).fromApp(appId)
410 .addTreatment(tBuilder.build())
411 .withMeta(metadata);
412
413 ObjectiveContext context = new DefaultObjectiveContext(
414 (objective) -> log.debug("port {} successfully {} NextObj {} on {}",
415 port, (portUp) ? "addedTo" : "removedFrom",
416 nextId, deviceId),
417 (objective, error) ->
418 log.warn("port {} failed to {} NextObj {} on {}: {}",
419 port, (portUp) ? "addTo" : "removeFrom",
420 nextId, deviceId, error));
421
422 NextObjective nextObj = (portUp) ? nextObjBuilder.addToExisting(context)
423 : nextObjBuilder.removeFromExisting(context);
424 log.debug("edgePort processed: Submited next objective {} in device {}",
425 nextId, deviceId);
426 flowObjectiveService.next(deviceId, nextObj);
427 }
428
429 /**
Saurav Das4ce45962015-11-24 23:21:05 -0800430 * Returns the next objective of type hashed associated with the neighborset.
431 * If there is no next objective for this neighborset, this method
Saurav Das8a0732e2015-11-20 15:27:53 -0800432 * would create a next objective and return. Optionally metadata can be
433 * passed in for the creation of the next objective.
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800434 *
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700435 * @param ns neighborset
Saurav Das8a0732e2015-11-20 15:27:53 -0800436 * @param meta metadata passed into the creation of a Next Objective
Pier Ventre917127a2016-10-31 16:49:19 -0700437 * @param isBos if Bos is set
Saurav Das8a0732e2015-11-20 15:27:53 -0800438 * @return int if found or -1 if there are errors in the creation of the
439 * neighbor set.
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800440 */
Pier Ventre917127a2016-10-31 16:49:19 -0700441 public int getNextObjectiveId(NeighborSet ns, TrafficSelector meta, boolean isBos) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700442 Integer nextId = nsNextObjStore.
443 get(new NeighborSetNextObjectiveStoreKey(deviceId, ns));
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700444 if (nextId == null) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700445 log.trace("getNextObjectiveId in device{}: Next objective id "
446 + "not found for {} and creating", deviceId, ns);
447 log.trace("getNextObjectiveId: nsNextObjStore contents for device {}: {}",
448 deviceId,
449 nsNextObjStore.entrySet()
450 .stream()
451 .filter((nsStoreEntry) ->
452 (nsStoreEntry.getKey().deviceId().equals(deviceId)))
453 .collect(Collectors.toList()));
Pier Ventre917127a2016-10-31 16:49:19 -0700454 createGroupsFromNeighborsets(Collections.singleton(ns), meta, isBos);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700455 nextId = nsNextObjStore.
456 get(new NeighborSetNextObjectiveStoreKey(deviceId, ns));
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700457 if (nextId == null) {
458 log.warn("getNextObjectiveId: unable to create next objective");
459 return -1;
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700460 } else {
461 log.debug("getNextObjectiveId in device{}: Next objective id {} "
Sho SHIMIZUaf973432015-09-11 14:24:50 -0700462 + "created for {}", deviceId, nextId, ns);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700463 }
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700464 } else {
465 log.trace("getNextObjectiveId in device{}: Next objective id {} "
Sho SHIMIZUaf973432015-09-11 14:24:50 -0700466 + "found for {}", deviceId, nextId, ns);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700467 }
Sho SHIMIZUaf973432015-09-11 14:24:50 -0700468 return nextId;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800469 }
470
sangho0b2b6d12015-05-20 22:16:38 -0700471 /**
Charles Chan59cc16d2017-02-02 16:20:42 -0800472 * Returns the next objective of type broadcast associated with the vlan,
Saurav Das4ce45962015-11-24 23:21:05 -0800473 * or -1 if no such objective exists. Note that this method does NOT create
474 * the next objective as a side-effect. It is expected that is objective is
Saurav Das1a129a02016-11-18 15:21:57 -0800475 * created at startup from network configuration. Typically this is used
476 * for L2 flooding within the subnet configured on the switch.
Charles Chanc42e84e2015-10-20 16:24:19 -0700477 *
Charles Chan59cc16d2017-02-02 16:20:42 -0800478 * @param vlanId vlan id
Charles Chanc42e84e2015-10-20 16:24:19 -0700479 * @return int if found or -1
480 */
Charles Chan59cc16d2017-02-02 16:20:42 -0800481 public int getVlanNextObjectiveId(VlanId vlanId) {
482 Integer nextId = vlanNextObjStore.
483 get(new VlanNextObjectiveStoreKey(deviceId, vlanId));
Charles Chan9f676b62015-10-29 14:58:10 -0700484
485 return (nextId != null) ? nextId : -1;
Charles Chanc42e84e2015-10-20 16:24:19 -0700486 }
487
488 /**
Saurav Das4ce45962015-11-24 23:21:05 -0800489 * Returns the next objective of type simple associated with the port on the
490 * device, given the treatment. Different treatments to the same port result
491 * in different next objectives. If no such objective exists, this method
492 * creates one and returns the id. Optionally metadata can be passed in for
Saurav Das1a129a02016-11-18 15:21:57 -0800493 * the creation of the objective. Typically this is used for L2 and L3 forwarding
494 * to compute nodes and containers/VMs on the compute nodes directly attached
495 * to the switch.
Saurav Das4ce45962015-11-24 23:21:05 -0800496 *
497 * @param portNum the port number for the simple next objective
498 * @param treatment the actions to apply on the packets (should include outport)
499 * @param meta optional metadata passed into the creation of the next objective
500 * @return int if found or created, -1 if there are errors during the
501 * creation of the next objective.
502 */
503 public int getPortNextObjectiveId(PortNumber portNum, TrafficTreatment treatment,
504 TrafficSelector meta) {
Charles Chane849c192016-01-11 18:28:54 -0800505 Integer nextId = portNextObjStore
Saurav Das76ae6812017-03-15 15:15:14 -0700506 .get(new PortNextObjectiveStoreKey(deviceId, portNum, treatment, meta));
Saurav Das4ce45962015-11-24 23:21:05 -0800507 if (nextId == null) {
Saurav Das76ae6812017-03-15 15:15:14 -0700508 log.debug("getPortNextObjectiveId in device{}: Next objective id "
Saurav Das4ce45962015-11-24 23:21:05 -0800509 + "not found for {} and {} creating", deviceId, portNum);
510 createGroupFromPort(portNum, treatment, meta);
511 nextId = portNextObjStore.get(
Saurav Das76ae6812017-03-15 15:15:14 -0700512 new PortNextObjectiveStoreKey(deviceId, portNum, treatment, meta));
Saurav Das4ce45962015-11-24 23:21:05 -0800513 if (nextId == null) {
514 log.warn("getPortNextObjectiveId: unable to create next obj"
Charles Chane849c192016-01-11 18:28:54 -0800515 + "for dev:{} port:{}", deviceId, portNum);
516 return -1;
517 }
518 }
519 return nextId;
520 }
521
522 /**
sangho0b2b6d12015-05-20 22:16:38 -0700523 * Checks if the next objective ID (group) for the neighbor set exists or not.
524 *
525 * @param ns neighbor set to check
526 * @return true if it exists, false otherwise
527 */
528 public boolean hasNextObjectiveId(NeighborSet ns) {
529 Integer nextId = nsNextObjStore.
530 get(new NeighborSetNextObjectiveStoreKey(deviceId, ns));
531 if (nextId == null) {
532 return false;
533 }
534
535 return true;
536 }
537
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700538 // Empty implementation
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800539 protected void newNeighbor(Link newLink) {
540 }
541
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700542 // Empty implementation
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800543 protected void newPortToExistingNeighbor(Link newLink) {
544 }
545
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700546 // Empty implementation
547 protected Set<NeighborSet>
548 computeImpactedNeighborsetForPortEvent(DeviceId impactedNeighbor,
549 Set<DeviceId> updatedNeighbors) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800550 return null;
551 }
552
553 private void populateNeighborMaps() {
554 Set<Link> outgoingLinks = linkService.getDeviceEgressLinks(deviceId);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700555 for (Link link : outgoingLinks) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800556 if (link.type() != Link.Type.DIRECT) {
557 continue;
558 }
559 addNeighborAtPort(link.dst().deviceId(), link.src().port());
560 }
561 }
562
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700563 protected void addNeighborAtPort(DeviceId neighborId,
564 PortNumber portToNeighbor) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800565 // Update DeviceToPort database
566 log.debug("Device {} addNeighborAtPort: neighbor {} at port {}",
567 deviceId, neighborId, portToNeighbor);
Saurav Das8a0732e2015-11-20 15:27:53 -0800568 Set<PortNumber> ports = Collections
569 .newSetFromMap(new ConcurrentHashMap<PortNumber, Boolean>());
570 ports.add(portToNeighbor);
571 Set<PortNumber> portnums = devicePortMap.putIfAbsent(neighborId, ports);
572 if (portnums != null) {
573 portnums.add(portToNeighbor);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800574 }
575
576 // Update portToDevice database
Saurav Das8a0732e2015-11-20 15:27:53 -0800577 DeviceId prev = portDeviceMap.putIfAbsent(portToNeighbor, neighborId);
578 if (prev != null) {
579 log.warn("Device: {} port: {} has neighbor: {}. NOT updating "
580 + "to neighbor: {}", deviceId, portToNeighbor, prev, neighborId);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800581 }
582 }
583
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700584 protected Set<Set<DeviceId>> getPowerSetOfNeighbors(Set<DeviceId> neighbors) {
Sho SHIMIZU6cfc02d2015-09-11 11:19:11 -0700585 List<DeviceId> list = new ArrayList<>(neighbors);
586 Set<Set<DeviceId>> sets = new HashSet<>();
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800587 // get the number of elements in the neighbors
588 int elements = list.size();
589 // the number of members of a power set is 2^n
590 // including the empty set
591 int powerElements = (1 << elements);
592
593 // run a binary counter for the number of power elements
594 // NOTE: Exclude empty set
595 for (long i = 1; i < powerElements; i++) {
Sho SHIMIZU6cfc02d2015-09-11 11:19:11 -0700596 Set<DeviceId> neighborSubSet = new HashSet<>();
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800597 for (int j = 0; j < elements; j++) {
598 if ((i >> j) % 2 == 1) {
599 neighborSubSet.add(list.get(j));
600 }
601 }
602 sets.add(neighborSubSet);
603 }
604 return sets;
605 }
606
607 private boolean isSegmentIdSameAsNodeSegmentId(DeviceId deviceId, int sId) {
Charles Chan0b4e6182015-11-03 10:42:14 -0800608 int segmentId;
609 try {
Pier Ventre917127a2016-10-31 16:49:19 -0700610 // IPv6 sid is not inserted. this part of the code is not used for now.
Pier Ventree0ae7a32016-11-23 09:57:42 -0800611 segmentId = deviceConfig.getIPv4SegmentId(deviceId);
Charles Chan0b4e6182015-11-03 10:42:14 -0800612 } catch (DeviceConfigNotFoundException e) {
613 log.warn(e.getMessage() + " Aborting isSegmentIdSameAsNodeSegmentId.");
614 return false;
615 }
616
617 return segmentId == sId;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800618 }
619
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700620 protected List<Integer> getSegmentIdsTobePairedWithNeighborSet(Set<DeviceId> neighbors) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800621
Sho SHIMIZU6cfc02d2015-09-11 11:19:11 -0700622 List<Integer> nsSegmentIds = new ArrayList<>();
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800623
sanghob35a6192015-04-01 13:05:26 -0700624 // Always pair up with no edge label
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700625 // If (neighbors.size() == 1) {
sanghob35a6192015-04-01 13:05:26 -0700626 nsSegmentIds.add(-1);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700627 // }
sanghob35a6192015-04-01 13:05:26 -0700628
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800629 // Filter out SegmentIds matching with the
630 // nodes in the combo
631 for (Integer sId : allSegmentIds) {
Pier Ventree0ae7a32016-11-23 09:57:42 -0800632 if (sId.equals(this.ipv4NodeSegmentId)) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800633 continue;
634 }
635 boolean filterOut = false;
636 // Check if the edge label being set is of
637 // any node in the Neighbor set
638 for (DeviceId deviceId : neighbors) {
639 if (isSegmentIdSameAsNodeSegmentId(deviceId, sId)) {
640 filterOut = true;
641 break;
642 }
643 }
644 if (!filterOut) {
645 nsSegmentIds.add(sId);
646 }
647 }
648 return nsSegmentIds;
649 }
650
sangho1e575652015-05-14 00:39:53 -0700651 /**
Saurav Das1a129a02016-11-18 15:21:57 -0800652 * Creates hash groups from a set of NeighborSet given.
sangho1e575652015-05-14 00:39:53 -0700653 *
654 * @param nsSet a set of NeighborSet
Saurav Das8a0732e2015-11-20 15:27:53 -0800655 * @param meta metadata passed into the creation of a Next Objective
Pier Ventre917127a2016-10-31 16:49:19 -0700656 * @param isBos if BoS is set
sangho1e575652015-05-14 00:39:53 -0700657 */
Saurav Das8a0732e2015-11-20 15:27:53 -0800658 public void createGroupsFromNeighborsets(Set<NeighborSet> nsSet,
Pier Ventre917127a2016-10-31 16:49:19 -0700659 TrafficSelector meta,
660 boolean isBos) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800661 for (NeighborSet ns : nsSet) {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700662 int nextId = flowObjectiveService.allocateNextId();
Pier Ventre917127a2016-10-31 16:49:19 -0700663 NextObjective.Type type = NextObjective.Type.HASHED;
664 Set<DeviceId> neighbors = ns.getDeviceIds();
665 // If Bos == False and MPLS-ECMP == false, we have
666 // to use simple group and we will pick a single neighbor.
667 if (!isBos && !srManager.getMplsEcmp()) {
668 type = NextObjective.Type.SIMPLE;
669 neighbors = Collections.singleton(ns.getFirstNeighbor());
670 }
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700671 NextObjective.Builder nextObjBuilder = DefaultNextObjective
Pier Ventre917127a2016-10-31 16:49:19 -0700672 .builder()
673 .withId(nextId)
674 .withType(type)
675 .fromApp(appId);
676 // For each neighbor, we have to update the sent actions
677 for (DeviceId neighborId : neighbors) {
Saurav Das8a0732e2015-11-20 15:27:53 -0800678 if (devicePortMap.get(neighborId) == null) {
679 log.warn("Neighbor {} is not in the port map yet for dev:{}",
680 neighborId, deviceId);
sangho834e4b02015-05-01 09:38:25 -0700681 return;
Jon Hallcbd1b392017-01-18 20:15:44 -0800682 } else if (devicePortMap.get(neighborId).isEmpty()) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700683 log.warn("There are no ports for "
Saurav Das8a0732e2015-11-20 15:27:53 -0800684 + "the Device {} in the port map yet", neighborId);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700685 return;
sangho834e4b02015-05-01 09:38:25 -0700686 }
687
Saurav Das8a0732e2015-11-20 15:27:53 -0800688 MacAddress neighborMac;
Charles Chan0b4e6182015-11-03 10:42:14 -0800689 try {
Saurav Das8a0732e2015-11-20 15:27:53 -0800690 neighborMac = deviceConfig.getDeviceMac(neighborId);
Charles Chan0b4e6182015-11-03 10:42:14 -0800691 } catch (DeviceConfigNotFoundException e) {
692 log.warn(e.getMessage() + " Aborting createGroupsFromNeighborsets.");
693 return;
694 }
Pier Ventre917127a2016-10-31 16:49:19 -0700695 // For each port, we have to create a new treatment
696 Set<PortNumber> neighborPorts = devicePortMap.get(neighborId);
697 // In this case we are using a SIMPLE group. We randomly pick a port
698 if (!isBos && !srManager.getMplsEcmp()) {
699 int size = devicePortMap.get(neighborId).size();
700 int index = RandomUtils.nextInt(0, size);
701 neighborPorts = Collections.singleton(
702 Iterables.get(devicePortMap.get(neighborId), index)
703 );
704 }
705 for (PortNumber sp : neighborPorts) {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700706 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment
707 .builder();
Saurav Das8a0732e2015-11-20 15:27:53 -0800708 tBuilder.setEthDst(neighborMac)
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700709 .setEthSrc(nodeMacAddr);
710 if (ns.getEdgeLabel() != NeighborSet.NO_EDGE_LABEL) {
Charles Chan68aa62d2015-11-09 16:37:23 -0800711 tBuilder.pushMpls()
712 .copyTtlOut()
713 .setMpls(MplsLabel.mplsLabel(ns.getEdgeLabel()));
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700714 }
Saurav Das8a0732e2015-11-20 15:27:53 -0800715 tBuilder.setOutput(sp);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700716 nextObjBuilder.addTreatment(tBuilder.build());
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800717 }
718 }
Saurav Das8a0732e2015-11-20 15:27:53 -0800719 if (meta != null) {
Saurav Das4ce45962015-11-24 23:21:05 -0800720 nextObjBuilder.withMeta(meta);
Saurav Das8a0732e2015-11-20 15:27:53 -0800721 }
Charles Chan216e3c82016-04-23 14:48:16 -0700722
723 ObjectiveContext context = new DefaultObjectiveContext(
Pier Ventre917127a2016-10-31 16:49:19 -0700724 (objective) ->
725 log.debug("createGroupsFromNeighborsets installed NextObj {} on {}",
Charles Chan216e3c82016-04-23 14:48:16 -0700726 nextId, deviceId),
727 (objective, error) ->
728 log.warn("createGroupsFromNeighborsets failed to install NextObj {} on {}: {}",
Pier Ventre917127a2016-10-31 16:49:19 -0700729 nextId, deviceId, error)
730 );
Charles Chan216e3c82016-04-23 14:48:16 -0700731 NextObjective nextObj = nextObjBuilder.add(context);
732 log.debug("**createGroupsFromNeighborsets: Submited "
Saurav Das8a0732e2015-11-20 15:27:53 -0800733 + "next objective {} in device {}",
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700734 nextId, deviceId);
Saurav Das8a0732e2015-11-20 15:27:53 -0800735 flowObjectiveService.next(deviceId, nextObj);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700736 nsNextObjStore.put(new NeighborSetNextObjectiveStoreKey(deviceId, ns),
737 nextId);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800738 }
739 }
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700740
Saurav Das4ce45962015-11-24 23:21:05 -0800741 /**
Saurav Das1a129a02016-11-18 15:21:57 -0800742 * Creates broadcast groups for all ports in the same subnet for
743 * all configured subnets.
Saurav Das4ce45962015-11-24 23:21:05 -0800744 */
Charles Chan59cc16d2017-02-02 16:20:42 -0800745 public void createGroupsFromVlanConfig() {
746 Set<Interface> interfaces = srManager.interfaceService.getInterfaces();
Charles Chan59cc16d2017-02-02 16:20:42 -0800747
Charles Chan7ffd81f2017-02-08 15:52:08 -0800748 srManager.getVlanPortMap(deviceId).asMap().forEach((vlanId, ports) -> {
Charles Chan59cc16d2017-02-02 16:20:42 -0800749 createBcastGroupFromVlan(vlanId, ports);
Pier Ventre10bd8d12016-11-26 21:05:22 -0800750 });
Saurav Das1a129a02016-11-18 15:21:57 -0800751 }
Charles Chan9f676b62015-10-29 14:58:10 -0700752
Saurav Das1a129a02016-11-18 15:21:57 -0800753 /**
Charles Chan59cc16d2017-02-02 16:20:42 -0800754 * Creates a single broadcast group from a given vlan id and list of ports.
Saurav Das1a129a02016-11-18 15:21:57 -0800755 *
Charles Chan59cc16d2017-02-02 16:20:42 -0800756 * @param vlanId vlan id
Saurav Das1a129a02016-11-18 15:21:57 -0800757 * @param ports list of ports in the subnet
758 */
Charles Chan7ffd81f2017-02-08 15:52:08 -0800759 public void createBcastGroupFromVlan(VlanId vlanId, Collection<PortNumber> ports) {
Charles Chan59cc16d2017-02-02 16:20:42 -0800760 VlanNextObjectiveStoreKey key = new VlanNextObjectiveStoreKey(deviceId, vlanId);
Charles Chan9f676b62015-10-29 14:58:10 -0700761
Charles Chan59cc16d2017-02-02 16:20:42 -0800762 if (vlanNextObjStore.containsKey(key)) {
Saurav Das1a129a02016-11-18 15:21:57 -0800763 log.debug("Broadcast group for device {} and subnet {} exists",
Charles Chan59cc16d2017-02-02 16:20:42 -0800764 deviceId, vlanId);
Saurav Das1a129a02016-11-18 15:21:57 -0800765 return;
766 }
Charles Chan188ebf52015-12-23 00:15:11 -0800767
Saurav Das1a129a02016-11-18 15:21:57 -0800768 TrafficSelector metadata =
Charles Chan59cc16d2017-02-02 16:20:42 -0800769 DefaultTrafficSelector.builder().matchVlanId(vlanId).build();
Charles Chanc42e84e2015-10-20 16:24:19 -0700770
Saurav Das1a129a02016-11-18 15:21:57 -0800771 int nextId = flowObjectiveService.allocateNextId();
Charles Chanc42e84e2015-10-20 16:24:19 -0700772
Saurav Das1a129a02016-11-18 15:21:57 -0800773 NextObjective.Builder nextObjBuilder = DefaultNextObjective
774 .builder().withId(nextId)
775 .withType(NextObjective.Type.BROADCAST).fromApp(appId)
776 .withMeta(metadata);
Charles Chanc42e84e2015-10-20 16:24:19 -0700777
Saurav Das1a129a02016-11-18 15:21:57 -0800778 ports.forEach(port -> {
779 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
Charles Chan7ffd81f2017-02-08 15:52:08 -0800780 if (toPopVlan(port, vlanId)) {
781 tBuilder.popVlan();
782 }
Saurav Das1a129a02016-11-18 15:21:57 -0800783 tBuilder.setOutput(port);
784 nextObjBuilder.addTreatment(tBuilder.build());
Charles Chanc42e84e2015-10-20 16:24:19 -0700785 });
Saurav Das1a129a02016-11-18 15:21:57 -0800786
787 NextObjective nextObj = nextObjBuilder.add();
788 flowObjectiveService.next(deviceId, nextObj);
Charles Chan59cc16d2017-02-02 16:20:42 -0800789 log.debug("createBcastGroupFromVlan: Submited next objective {} in device {}",
Saurav Das1a129a02016-11-18 15:21:57 -0800790 nextId, deviceId);
791
Charles Chan59cc16d2017-02-02 16:20:42 -0800792 vlanNextObjStore.put(key, nextId);
Charles Chanc42e84e2015-10-20 16:24:19 -0700793 }
794
Charles Chane849c192016-01-11 18:28:54 -0800795 /**
Charles Chan7ffd81f2017-02-08 15:52:08 -0800796 * Determine if we should pop given vlan before sending packets to the given port.
797 *
798 * @param portNumber port number
799 * @param vlanId vlan id
800 * @return true if the vlan id is not contained in any vlanTagged config
801 */
802 private boolean toPopVlan(PortNumber portNumber, VlanId vlanId) {
803 return srManager.interfaceService.getInterfacesByPort(new ConnectPoint(deviceId, portNumber))
804 .stream().noneMatch(intf -> intf.vlanTagged().contains(vlanId));
805 }
806
807 /**
Saurav Das4ce45962015-11-24 23:21:05 -0800808 * Create simple next objective for a single port. The treatments can include
809 * all outgoing actions that need to happen on the packet.
810 *
811 * @param portNum the outgoing port on the device
812 * @param treatment the actions to apply on the packets (should include outport)
813 * @param meta optional data to pass to the driver
814 */
815 public void createGroupFromPort(PortNumber portNum, TrafficTreatment treatment,
816 TrafficSelector meta) {
817 int nextId = flowObjectiveService.allocateNextId();
818 PortNextObjectiveStoreKey key = new PortNextObjectiveStoreKey(
Saurav Das76ae6812017-03-15 15:15:14 -0700819 deviceId, portNum, treatment, meta);
Saurav Das4ce45962015-11-24 23:21:05 -0800820
821 NextObjective.Builder nextObjBuilder = DefaultNextObjective
822 .builder().withId(nextId)
823 .withType(NextObjective.Type.SIMPLE)
824 .addTreatment(treatment)
825 .fromApp(appId)
826 .withMeta(meta);
827
828 NextObjective nextObj = nextObjBuilder.add();
829 flowObjectiveService.next(deviceId, nextObj);
830 log.debug("createGroupFromPort: Submited next objective {} in device {} "
831 + "for port {}", nextId, deviceId, portNum);
832
833 portNextObjStore.put(key, nextId);
834 }
835
sangho1e575652015-05-14 00:39:53 -0700836 /**
837 * Removes groups for the next objective ID given.
838 *
839 * @param objectiveId next objective ID to remove
840 * @return true if succeeds, false otherwise
841 */
842 public boolean removeGroup(int objectiveId) {
843
844 if (nsNextObjStore.containsValue(objectiveId)) {
845 NextObjective.Builder nextObjBuilder = DefaultNextObjective
846 .builder().withId(objectiveId)
847 .withType(NextObjective.Type.HASHED).fromApp(appId);
Charles Chan216e3c82016-04-23 14:48:16 -0700848 ObjectiveContext context = new DefaultObjectiveContext(
849 (objective) -> log.debug("RemoveGroup removes NextObj {} on {}",
850 objectiveId, deviceId),
851 (objective, error) ->
852 log.warn("RemoveGroup failed to remove NextObj {} on {}: {}",
853 objectiveId, deviceId, error));
854 NextObjective nextObjective = nextObjBuilder.remove(context);
Saurav Das8a0732e2015-11-20 15:27:53 -0800855 log.info("**removeGroup: Submited "
856 + "next objective {} in device {}",
857 objectiveId, deviceId);
sangho1e575652015-05-14 00:39:53 -0700858 flowObjectiveService.next(deviceId, nextObjective);
859
860 for (Map.Entry<NeighborSetNextObjectiveStoreKey, Integer> entry: nsNextObjStore.entrySet()) {
861 if (entry.getValue().equals(objectiveId)) {
862 nsNextObjStore.remove(entry.getKey());
863 break;
864 }
865 }
sangho0b2b6d12015-05-20 22:16:38 -0700866 return true;
sangho1e575652015-05-14 00:39:53 -0700867 }
868
869 return false;
870 }
Srikanth Vavilapallif3a8bc02015-05-22 13:47:31 -0700871
Charles Chane849c192016-01-11 18:28:54 -0800872 /**
873 * Removes all groups from all next objective stores.
874 */
Saurav Das423fe2b2015-12-04 10:52:59 -0800875 public void removeAllGroups() {
876 for (Map.Entry<NeighborSetNextObjectiveStoreKey, Integer> entry:
877 nsNextObjStore.entrySet()) {
878 removeGroup(entry.getValue());
879 }
880 for (Map.Entry<PortNextObjectiveStoreKey, Integer> entry:
881 portNextObjStore.entrySet()) {
882 removeGroup(entry.getValue());
883 }
Charles Chan59cc16d2017-02-02 16:20:42 -0800884 for (Map.Entry<VlanNextObjectiveStoreKey, Integer> entry:
885 vlanNextObjStore.entrySet()) {
Saurav Das423fe2b2015-12-04 10:52:59 -0800886 removeGroup(entry.getValue());
887 }
888 // should probably clean local stores port-neighbor
889 }
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800890}