blob: fce4e50b063748bdfe763b9694bf22f99e7e06fa [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.net.ConnectPoint;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080027import org.onosproject.net.DeviceId;
28import org.onosproject.net.Link;
29import org.onosproject.net.PortNumber;
Saurav Das423fe2b2015-12-04 10:52:59 -080030import org.onosproject.net.flow.DefaultTrafficSelector;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080031import org.onosproject.net.flow.DefaultTrafficTreatment;
Saurav Das8a0732e2015-11-20 15:27:53 -080032import org.onosproject.net.flow.TrafficSelector;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080033import org.onosproject.net.flow.TrafficTreatment;
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070034import org.onosproject.net.flowobjective.DefaultNextObjective;
Charles Chan216e3c82016-04-23 14:48:16 -070035import org.onosproject.net.flowobjective.DefaultObjectiveContext;
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070036import org.onosproject.net.flowobjective.FlowObjectiveService;
37import org.onosproject.net.flowobjective.NextObjective;
Srikanth Vavilapallif3a8bc02015-05-22 13:47:31 -070038import org.onosproject.net.flowobjective.ObjectiveContext;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080039import org.onosproject.net.link.LinkService;
Saurav Das423fe2b2015-12-04 10:52:59 -080040import org.onosproject.segmentrouting.SegmentRoutingManager;
Charles Chan0b4e6182015-11-03 10:42:14 -080041import org.onosproject.segmentrouting.config.DeviceConfigNotFoundException;
42import org.onosproject.segmentrouting.config.DeviceProperties;
Charles Chand2990362016-04-18 13:44:03 -070043import org.onosproject.segmentrouting.storekey.NeighborSetNextObjectiveStoreKey;
44import org.onosproject.segmentrouting.storekey.PortNextObjectiveStoreKey;
Charles Chan59cc16d2017-02-02 16:20:42 -080045import org.onosproject.segmentrouting.storekey.VlanNextObjectiveStoreKey;
Srikanth Vavilapalli23181912015-05-04 09:48:09 -070046import org.onosproject.store.service.EventuallyConsistentMap;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080047import org.slf4j.Logger;
48
Pier Ventre917127a2016-10-31 16:49:19 -070049import java.net.URI;
50import java.util.ArrayList;
Charles Chan7ffd81f2017-02-08 15:52:08 -080051import java.util.Collection;
Pier Ventre917127a2016-10-31 16:49:19 -070052import 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 Chan59cc16d2017-02-02 16:20:42 -080061import static org.onosproject.segmentrouting.SegmentRoutingManager.INTERNAL_VLAN;
Pier Ventre917127a2016-10-31 16:49:19 -070062import static org.slf4j.LoggerFactory.getLogger;
63
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080064/**
Srikanth Vavilapallif5b234a2015-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 Vavilapallied12ae52015-02-09 14:43:19 -080068 */
69public class DefaultGroupHandler {
Srikanth Vavilapallif3a8bc02015-05-22 13:47:31 -070070 protected static final Logger log = getLogger(DefaultGroupHandler.class);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080071
72 protected final DeviceId deviceId;
73 protected final ApplicationId appId;
74 protected final DeviceProperties deviceConfig;
75 protected final List<Integer> allSegmentIds;
Pier Ventree0ae7a32016-11-23 09:57:42 -080076 protected int ipv4NodeSegmentId = -1;
77 protected int ipv6NodeSegmentId = -1;
Charles Chan0b4e6182015-11-03 10:42:14 -080078 protected boolean isEdgeRouter = false;
79 protected MacAddress nodeMacAddr = null;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080080 protected LinkService linkService;
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070081 protected FlowObjectiveService flowObjectiveService;
Saurav Das423fe2b2015-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 Das8a0732e2015-11-20 15:27:53 -080084 protected ConcurrentHashMap<DeviceId, Set<PortNumber>> devicePortMap =
85 new ConcurrentHashMap<>();
Saurav Das1a129a02016-11-18 15:21:57 -080086 // local store for ports on this device connected to neighbor-device-id
Saurav Das8a0732e2015-11-20 15:27:53 -080087 protected ConcurrentHashMap<PortNumber, DeviceId> portDeviceMap =
88 new ConcurrentHashMap<>();
Saurav Das1a129a02016-11-18 15:21:57 -080089 // distributed store for (device+neighborset) mapped to next-id
Charles Chane849c192016-01-11 18:28:54 -080090 protected EventuallyConsistentMap<NeighborSetNextObjectiveStoreKey, Integer>
91 nsNextObjStore = null;
Saurav Das1a129a02016-11-18 15:21:57 -080092 // distributed store for (device+subnet-ip-prefix) mapped to next-id
Charles Chan59cc16d2017-02-02 16:20:42 -080093 protected EventuallyConsistentMap<VlanNextObjectiveStoreKey, Integer>
94 vlanNextObjStore = null;
Saurav Das1a129a02016-11-18 15:21:57 -080095 // distributed store for (device+port+treatment) mapped to next-id
Charles Chane849c192016-01-11 18:28:54 -080096 protected EventuallyConsistentMap<PortNextObjectiveStoreKey, Integer>
97 portNextObjStore = null;
Charles Chan188ebf52015-12-23 00:15:11 -080098 private SegmentRoutingManager srManager;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080099
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700100 protected KryoNamespace.Builder kryo = new KryoNamespace.Builder()
Srikanth Vavilapallif5b234a2015-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 Vavilapallied12ae52015-02-09 14:43:19 -0800107
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700108 protected DefaultGroupHandler(DeviceId deviceId, ApplicationId appId,
109 DeviceProperties config,
110 LinkService linkService,
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700111 FlowObjectiveService flowObjService,
Charles Chan188ebf52015-12-23 00:15:11 -0800112 SegmentRoutingManager srManager) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800113 this.deviceId = checkNotNull(deviceId);
114 this.appId = checkNotNull(appId);
115 this.deviceConfig = checkNotNull(config);
116 this.linkService = checkNotNull(linkService);
Charles Chan0b4e6182015-11-03 10:42:14 -0800117 this.allSegmentIds = checkNotNull(config.getAllDeviceSegmentIds());
118 try {
Pier Ventree0ae7a32016-11-23 09:57:42 -0800119 this.ipv4NodeSegmentId = config.getIPv4SegmentId(deviceId);
120 this.ipv6NodeSegmentId = config.getIPv6SegmentId(deviceId);
Charles Chan0b4e6182015-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 Vavilapallif5b234a2015-04-21 13:04:13 -0700127 this.flowObjectiveService = flowObjService;
Ray Milkeye4afdb52017-04-05 09:42:04 -0700128 this.nsNextObjStore = srManager.nsNextObjStore();
129 this.vlanNextObjStore = srManager.vlanNextObjStore();
130 this.portNextObjStore = srManager.portNextObjStore();
Charles Chan188ebf52015-12-23 00:15:11 -0800131 this.srManager = srManager;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800132
133 populateNeighborMaps();
134 }
135
136 /**
Srikanth Vavilapallif5b234a2015-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 Vavilapallied12ae52015-02-09 14:43:19 -0800140 *
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 Vavilapallif5b234a2015-04-21 13:04:13 -0700145 * @param flowObjService flow objective service object
Charles Chane849c192016-01-11 18:28:54 -0800146 * @param srManager segment routing manager
Charles Chan0b4e6182015-11-03 10:42:14 -0800147 * @throws DeviceConfigNotFoundException if the device configuration is not found
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800148 * @return default group handler type
149 */
Saurav Das4ce45962015-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 Chan188ebf52015-12-23 00:15:11 -0800156 SegmentRoutingManager srManager)
Saurav Das4ce45962015-11-24 23:21:05 -0800157 throws DeviceConfigNotFoundException {
Charles Chan0b4e6182015-11-03 10:42:14 -0800158 // handle possible exception in the caller
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800159 if (config.isEdgeDevice(deviceId)) {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700160 return new DefaultEdgeGroupHandler(deviceId, appId, config,
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700161 linkService,
162 flowObjService,
Charles Chan188ebf52015-12-23 00:15:11 -0800163 srManager
164 );
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800165 } else {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700166 return new DefaultTransitGroupHandler(deviceId, appId, config,
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700167 linkService,
168 flowObjService,
Charles Chan188ebf52015-12-23 00:15:11 -0800169 srManager);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800170 }
171 }
172
173 /**
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700174 * Creates the auto created groups for this device based on the current
175 * snapshot of the topology.
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800176 */
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700177 // Empty implementations to be overridden by derived classes
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800178 public void createGroups() {
179 }
180
181 /**
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700182 * Performs group creation or update procedures when a new link is
183 * discovered on this device.
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800184 *
185 * @param newLink new neighbor link
Charles Chane849c192016-01-11 18:28:54 -0800186 * @param isMaster true if local instance is the master
187 *
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800188 */
Saurav Das8a0732e2015-11-20 15:27:53 -0800189 public void linkUp(Link newLink, boolean isMaster) {
sanghob35a6192015-04-01 13:05:26 -0700190
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800191 if (newLink.type() != Link.Type.DIRECT) {
Charles Chanb1f8c762017-03-29 16:39:05 -0700192 // NOTE: A DIRECT link might be transiently marked as INDIRECT
193 // if BDDP is received before LLDP. We can safely ignore that
194 // until the LLDP is received and the link is marked as DIRECT.
195 log.info("Ignore link {}->{}. Link type is {} instead of DIRECT.",
196 newLink.src(), newLink.dst(), newLink.type());
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800197 return;
198 }
199
200 if (!newLink.src().deviceId().equals(deviceId)) {
Charles Chanb1f8c762017-03-29 16:39:05 -0700201 log.warn("linkUp: deviceId{} doesn't match with link src {}",
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700202 deviceId, newLink.src().deviceId());
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800203 return;
204 }
205
Saurav Das8a0732e2015-11-20 15:27:53 -0800206 log.info("* LinkUP: Device {} linkUp at local port {} to neighbor {}", deviceId,
207 newLink.src().port(), newLink.dst().deviceId());
Saurav Das59232cf2016-04-27 18:35:50 -0700208 // ensure local state is updated even if linkup is aborted later on
209 addNeighborAtPort(newLink.dst().deviceId(),
210 newLink.src().port());
211
Charles Chan0b4e6182015-11-03 10:42:14 -0800212 MacAddress dstMac;
213 try {
214 dstMac = deviceConfig.getDeviceMac(newLink.dst().deviceId());
215 } catch (DeviceConfigNotFoundException e) {
216 log.warn(e.getMessage() + " Aborting linkUp.");
217 return;
218 }
219
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700220 /*if (devicePortMap.get(newLink.dst().deviceId()) == null) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800221 // New Neighbor
222 newNeighbor(newLink);
223 } else {
224 // Old Neighbor
225 newPortToExistingNeighbor(newLink);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700226 }*/
227 Set<NeighborSet> nsSet = nsNextObjStore.keySet()
228 .stream()
229 .filter((nsStoreEntry) -> (nsStoreEntry.deviceId().equals(deviceId)))
230 .map((nsStoreEntry) -> (nsStoreEntry.neighborSet()))
231 .filter((ns) -> (ns.getDeviceIds()
232 .contains(newLink.dst().deviceId())))
233 .collect(Collectors.toSet());
234 log.trace("linkUp: nsNextObjStore contents for device {}:",
sangho0b2b6d12015-05-20 22:16:38 -0700235 deviceId,
236 nsSet);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700237 for (NeighborSet ns : nsSet) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700238 Integer nextId = nsNextObjStore.
239 get(new NeighborSetNextObjectiveStoreKey(deviceId, ns));
Saurav Das4ce45962015-11-24 23:21:05 -0800240 if (nextId != null && isMaster) {
Saurav Das423fe2b2015-12-04 10:52:59 -0800241 // Create the new bucket to be updated
242 TrafficTreatment.Builder tBuilder =
243 DefaultTrafficTreatment.builder();
244 tBuilder.setOutput(newLink.src().port())
245 .setEthDst(dstMac)
246 .setEthSrc(nodeMacAddr);
247 if (ns.getEdgeLabel() != NeighborSet.NO_EDGE_LABEL) {
248 tBuilder.pushMpls()
249 .copyTtlOut()
250 .setMpls(MplsLabel.mplsLabel(ns.getEdgeLabel()));
251 }
252 // setup metadata to pass to nextObjective - indicate the vlan on egress
253 // if needed by the switch pipeline. Since hashed next-hops are always to
254 // other neighboring routers, there is no subnet assigned on those ports.
255 TrafficSelector.Builder metabuilder = DefaultTrafficSelector.builder();
Charles Chan59cc16d2017-02-02 16:20:42 -0800256 metabuilder.matchVlanId(INTERNAL_VLAN);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700257
Saurav Das423fe2b2015-12-04 10:52:59 -0800258 NextObjective.Builder nextObjBuilder = DefaultNextObjective.builder()
259 .withId(nextId)
260 .withType(NextObjective.Type.HASHED)
261 .addTreatment(tBuilder.build())
262 .withMeta(metabuilder.build())
263 .fromApp(appId);
Saurav Das8a0732e2015-11-20 15:27:53 -0800264 log.info("**linkUp in device {}: Adding Bucket "
Saurav Das4ce45962015-11-24 23:21:05 -0800265 + "with Port {} to next object id {}",
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700266 deviceId,
267 newLink.src().port(),
Saurav Das4ce45962015-11-24 23:21:05 -0800268 nextId);
Charles Chan216e3c82016-04-23 14:48:16 -0700269
270 ObjectiveContext context = new DefaultObjectiveContext(
Saurav Das1ce0a7b2016-10-21 14:06:29 -0700271 (objective) -> log.debug("LinkUp addedTo NextObj {} on {}",
Charles Chan216e3c82016-04-23 14:48:16 -0700272 nextId, deviceId),
273 (objective, error) ->
Saurav Das1ce0a7b2016-10-21 14:06:29 -0700274 log.warn("LinkUp failed to addTo NextObj {} on {}: {}",
Charles Chan216e3c82016-04-23 14:48:16 -0700275 nextId, deviceId, error));
276 NextObjective nextObjective = nextObjBuilder.addToExisting(context);
Saurav Das4ce45962015-11-24 23:21:05 -0800277 flowObjectiveService.next(deviceId, nextObjective);
278 } else if (isMaster) {
Saurav Das8a0732e2015-11-20 15:27:53 -0800279 log.warn("linkUp in device {}, but global store has no record "
280 + "for neighbor-set {}", deviceId, ns);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700281 }
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800282 }
283 }
284
285 /**
Saurav Das1a129a02016-11-18 15:21:57 -0800286 * Performs hash group recovery procedures when a switch-to-switch
287 * port goes down on this device.
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800288 *
289 * @param port port number that has gone down
Charles Chane849c192016-01-11 18:28:54 -0800290 * @param isMaster true if local instance is the master
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800291 */
Saurav Das423fe2b2015-12-04 10:52:59 -0800292 public void portDown(PortNumber port, boolean isMaster) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800293 if (portDeviceMap.get(port) == null) {
294 log.warn("portDown: unknown port");
295 return;
296 }
Charles Chan0b4e6182015-11-03 10:42:14 -0800297
298 MacAddress dstMac;
299 try {
300 dstMac = deviceConfig.getDeviceMac(portDeviceMap.get(port));
301 } catch (DeviceConfigNotFoundException e) {
302 log.warn(e.getMessage() + " Aborting portDown.");
303 return;
304 }
305
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700306 log.debug("Device {} portDown {} to neighbor {}", deviceId, port,
307 portDeviceMap.get(port));
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700308 /*Set<NeighborSet> nsSet = computeImpactedNeighborsetForPortEvent(portDeviceMap
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700309 .get(port),
310 devicePortMap
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700311 .keySet());*/
312 Set<NeighborSet> nsSet = nsNextObjStore.keySet()
313 .stream()
314 .filter((nsStoreEntry) -> (nsStoreEntry.deviceId().equals(deviceId)))
315 .map((nsStoreEntry) -> (nsStoreEntry.neighborSet()))
316 .filter((ns) -> (ns.getDeviceIds()
317 .contains(portDeviceMap.get(port))))
318 .collect(Collectors.toSet());
Saurav Das423fe2b2015-12-04 10:52:59 -0800319 log.debug("portDown: nsNextObjStore contents for device {}:{}",
320 deviceId, nsSet);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800321 for (NeighborSet ns : nsSet) {
Saurav Das80980c72016-03-23 11:22:49 -0700322 NeighborSetNextObjectiveStoreKey nsStoreKey =
323 new NeighborSetNextObjectiveStoreKey(deviceId, ns);
324 Integer nextId = nsNextObjStore.get(nsStoreKey);
Saurav Das423fe2b2015-12-04 10:52:59 -0800325 if (nextId != null && isMaster) {
Saurav Das8a0732e2015-11-20 15:27:53 -0800326 log.info("**portDown in device {}: Removing Bucket "
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700327 + "with Port {} to next object id {}",
328 deviceId,
329 port,
330 nextId);
Saurav Das423fe2b2015-12-04 10:52:59 -0800331 // Create the bucket to be removed
332 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment
333 .builder();
334 tBuilder.setOutput(port)
335 .setEthDst(dstMac)
336 .setEthSrc(nodeMacAddr);
337 if (ns.getEdgeLabel() != NeighborSet.NO_EDGE_LABEL) {
338 tBuilder.pushMpls()
339 .copyTtlOut()
340 .setMpls(MplsLabel.mplsLabel(ns.getEdgeLabel()));
341 }
342 NextObjective.Builder nextObjBuilder = DefaultNextObjective
343 .builder()
344 .withType(NextObjective.Type.HASHED) //same as original
345 .withId(nextId)
346 .fromApp(appId)
347 .addTreatment(tBuilder.build());
Saurav Das1ce0a7b2016-10-21 14:06:29 -0700348 ObjectiveContext context = new DefaultObjectiveContext(
349 (objective) -> log.debug("portDown removedFrom NextObj {} on {}",
350 nextId, deviceId),
351 (objective, error) ->
352 log.warn("portDown failed to removeFrom NextObj {} on {}: {}",
353 nextId, deviceId, error));
Saurav Das423fe2b2015-12-04 10:52:59 -0800354 NextObjective nextObjective = nextObjBuilder.
Saurav Das1ce0a7b2016-10-21 14:06:29 -0700355 removeFromExisting(context);
sangho834e4b02015-05-01 09:38:25 -0700356
Saurav Das423fe2b2015-12-04 10:52:59 -0800357 flowObjectiveService.next(deviceId, nextObjective);
sangho834e4b02015-05-01 09:38:25 -0700358 }
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800359 }
360
361 devicePortMap.get(portDeviceMap.get(port)).remove(port);
362 portDeviceMap.remove(port);
363 }
364
365 /**
Saurav Dasb0ae6ee2017-03-04 16:08:47 -0800366 * Adds or removes a port that has been configured with a vlan to a broadcast group
367 * for bridging. Should only be called by the master instance for this device.
Saurav Das1a129a02016-11-18 15:21:57 -0800368 *
369 * @param port the port on this device that needs to be added/removed to a bcast group
Saurav Dasb0ae6ee2017-03-04 16:08:47 -0800370 * @param vlanId the vlan id corresponding to the broadcast domain/group
371 * @param popVlan indicates if packets should be sent out untagged or not out
372 * of the port. If true, indicates an access (untagged) or native vlan
373 * configuration. If false, indicates a trunk (tagged) vlan config.
Saurav Das1a129a02016-11-18 15:21:57 -0800374 * @param portUp true if port is enabled, false if disabled
Saurav Das1a129a02016-11-18 15:21:57 -0800375 */
Saurav Dasb0ae6ee2017-03-04 16:08:47 -0800376 public void processEdgePort(PortNumber port, VlanId vlanId,
377 boolean popVlan, boolean portUp) {
Saurav Das1a129a02016-11-18 15:21:57 -0800378 //get the next id for the subnet and edit it.
Charles Chan59cc16d2017-02-02 16:20:42 -0800379 Integer nextId = getVlanNextObjectiveId(vlanId);
Saurav Das1a129a02016-11-18 15:21:57 -0800380 if (nextId == -1) {
381 if (portUp) {
382 log.debug("**Creating flooding group for first port enabled in"
Charles Chan59cc16d2017-02-02 16:20:42 -0800383 + " subnet {} on dev {} port {}", vlanId, deviceId, port);
384 createBcastGroupFromVlan(vlanId, Collections.singleton(port));
Saurav Das1a129a02016-11-18 15:21:57 -0800385 } else {
386 log.warn("Could not find flooding group for subnet {} on dev:{} when"
Charles Chan59cc16d2017-02-02 16:20:42 -0800387 + " removing port:{}", vlanId, deviceId, port);
Saurav Das1a129a02016-11-18 15:21:57 -0800388 }
389 return;
390 }
391
392 log.info("**port{} in device {}: {} Bucket with Port {} to"
393 + " next-id {}", (portUp) ? "UP" : "DOWN", deviceId,
394 (portUp) ? "Adding" : "Removing",
395 port, nextId);
396 // Create the bucket to be added or removed
397 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
Saurav Dasb0ae6ee2017-03-04 16:08:47 -0800398 if (popVlan) {
399 tBuilder.popVlan();
400 }
Saurav Das1a129a02016-11-18 15:21:57 -0800401 tBuilder.setOutput(port);
402
Saurav Das1a129a02016-11-18 15:21:57 -0800403 TrafficSelector metadata =
Saurav Dasb0ae6ee2017-03-04 16:08:47 -0800404 DefaultTrafficSelector.builder().matchVlanId(vlanId).build();
Saurav Das1a129a02016-11-18 15:21:57 -0800405
406 NextObjective.Builder nextObjBuilder = DefaultNextObjective
407 .builder().withId(nextId)
408 .withType(NextObjective.Type.BROADCAST).fromApp(appId)
409 .addTreatment(tBuilder.build())
410 .withMeta(metadata);
411
412 ObjectiveContext context = new DefaultObjectiveContext(
413 (objective) -> log.debug("port {} successfully {} NextObj {} on {}",
414 port, (portUp) ? "addedTo" : "removedFrom",
415 nextId, deviceId),
416 (objective, error) ->
417 log.warn("port {} failed to {} NextObj {} on {}: {}",
418 port, (portUp) ? "addTo" : "removeFrom",
419 nextId, deviceId, error));
420
421 NextObjective nextObj = (portUp) ? nextObjBuilder.addToExisting(context)
422 : nextObjBuilder.removeFromExisting(context);
423 log.debug("edgePort processed: Submited next objective {} in device {}",
424 nextId, deviceId);
425 flowObjectiveService.next(deviceId, nextObj);
426 }
427
428 /**
Saurav Das4ce45962015-11-24 23:21:05 -0800429 * Returns the next objective of type hashed associated with the neighborset.
430 * If there is no next objective for this neighborset, this method
Saurav Das8a0732e2015-11-20 15:27:53 -0800431 * would create a next objective and return. Optionally metadata can be
432 * passed in for the creation of the next objective.
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800433 *
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700434 * @param ns neighborset
Saurav Das8a0732e2015-11-20 15:27:53 -0800435 * @param meta metadata passed into the creation of a Next Objective
Pier Ventre917127a2016-10-31 16:49:19 -0700436 * @param isBos if Bos is set
Saurav Das8a0732e2015-11-20 15:27:53 -0800437 * @return int if found or -1 if there are errors in the creation of the
438 * neighbor set.
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800439 */
Pier Ventre917127a2016-10-31 16:49:19 -0700440 public int getNextObjectiveId(NeighborSet ns, TrafficSelector meta, boolean isBos) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700441 Integer nextId = nsNextObjStore.
442 get(new NeighborSetNextObjectiveStoreKey(deviceId, ns));
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700443 if (nextId == null) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700444 log.trace("getNextObjectiveId in device{}: Next objective id "
445 + "not found for {} and creating", deviceId, ns);
446 log.trace("getNextObjectiveId: nsNextObjStore contents for device {}: {}",
447 deviceId,
448 nsNextObjStore.entrySet()
449 .stream()
450 .filter((nsStoreEntry) ->
451 (nsStoreEntry.getKey().deviceId().equals(deviceId)))
452 .collect(Collectors.toList()));
Pier Ventre917127a2016-10-31 16:49:19 -0700453 createGroupsFromNeighborsets(Collections.singleton(ns), meta, isBos);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700454 nextId = nsNextObjStore.
455 get(new NeighborSetNextObjectiveStoreKey(deviceId, ns));
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700456 if (nextId == null) {
457 log.warn("getNextObjectiveId: unable to create next objective");
458 return -1;
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700459 } else {
460 log.debug("getNextObjectiveId in device{}: Next objective id {} "
Sho SHIMIZUaf973432015-09-11 14:24:50 -0700461 + "created for {}", deviceId, nextId, ns);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700462 }
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700463 } else {
464 log.trace("getNextObjectiveId in device{}: Next objective id {} "
Sho SHIMIZUaf973432015-09-11 14:24:50 -0700465 + "found for {}", deviceId, nextId, ns);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700466 }
Sho SHIMIZUaf973432015-09-11 14:24:50 -0700467 return nextId;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800468 }
469
sangho0b2b6d12015-05-20 22:16:38 -0700470 /**
Charles Chan59cc16d2017-02-02 16:20:42 -0800471 * Returns the next objective of type broadcast associated with the vlan,
Saurav Das4ce45962015-11-24 23:21:05 -0800472 * or -1 if no such objective exists. Note that this method does NOT create
473 * the next objective as a side-effect. It is expected that is objective is
Saurav Das1a129a02016-11-18 15:21:57 -0800474 * created at startup from network configuration. Typically this is used
475 * for L2 flooding within the subnet configured on the switch.
Charles Chanc42e84e2015-10-20 16:24:19 -0700476 *
Charles Chan59cc16d2017-02-02 16:20:42 -0800477 * @param vlanId vlan id
Charles Chanc42e84e2015-10-20 16:24:19 -0700478 * @return int if found or -1
479 */
Charles Chan59cc16d2017-02-02 16:20:42 -0800480 public int getVlanNextObjectiveId(VlanId vlanId) {
481 Integer nextId = vlanNextObjStore.
482 get(new VlanNextObjectiveStoreKey(deviceId, vlanId));
Charles Chan9f676b62015-10-29 14:58:10 -0700483
484 return (nextId != null) ? nextId : -1;
Charles Chanc42e84e2015-10-20 16:24:19 -0700485 }
486
487 /**
Saurav Das4ce45962015-11-24 23:21:05 -0800488 * Returns the next objective of type simple associated with the port on the
489 * device, given the treatment. Different treatments to the same port result
490 * in different next objectives. If no such objective exists, this method
Saurav Das961beb22017-03-29 19:09:17 -0700491 * creates one (if requested) and returns the id. Optionally metadata can be passed in for
Saurav Das1a129a02016-11-18 15:21:57 -0800492 * the creation of the objective. Typically this is used for L2 and L3 forwarding
493 * to compute nodes and containers/VMs on the compute nodes directly attached
494 * to the switch.
Saurav Das4ce45962015-11-24 23:21:05 -0800495 *
496 * @param portNum the port number for the simple next objective
497 * @param treatment the actions to apply on the packets (should include outport)
498 * @param meta optional metadata passed into the creation of the next objective
Saurav Das961beb22017-03-29 19:09:17 -0700499 * @param createIfMissing true if a next object should be created if not found
Saurav Das4ce45962015-11-24 23:21:05 -0800500 * @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,
Saurav Das961beb22017-03-29 19:09:17 -0700504 TrafficSelector meta, boolean createIfMissing) {
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 Das961beb22017-03-29 19:09:17 -0700507 if (nextId != null) {
508 return nextId;
509 }
510 log.debug("getPortNextObjectiveId in device {}: Next objective id "
511 + "not found for port: {} .. {}", deviceId, portNum,
512 (createIfMissing) ? "creating" : "aborting");
513 if (!createIfMissing) {
514 return -1;
515 }
516 // create missing next objective
517 createGroupFromPort(portNum, treatment, meta);
518 nextId = portNextObjStore.get(new PortNextObjectiveStoreKey(deviceId, portNum,
519 treatment, meta));
Saurav Das4ce45962015-11-24 23:21:05 -0800520 if (nextId == null) {
Saurav Das961beb22017-03-29 19:09:17 -0700521 log.warn("getPortNextObjectiveId: unable to create next obj"
522 + "for dev:{} port:{}", deviceId, portNum);
523 return -1;
Charles Chane849c192016-01-11 18:28:54 -0800524 }
525 return nextId;
526 }
527
528 /**
sangho0b2b6d12015-05-20 22:16:38 -0700529 * Checks if the next objective ID (group) for the neighbor set exists or not.
530 *
531 * @param ns neighbor set to check
532 * @return true if it exists, false otherwise
533 */
534 public boolean hasNextObjectiveId(NeighborSet ns) {
535 Integer nextId = nsNextObjStore.
536 get(new NeighborSetNextObjectiveStoreKey(deviceId, ns));
537 if (nextId == null) {
538 return false;
539 }
540
541 return true;
542 }
543
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700544 // Empty implementation
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800545 protected void newNeighbor(Link newLink) {
546 }
547
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700548 // Empty implementation
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800549 protected void newPortToExistingNeighbor(Link newLink) {
550 }
551
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700552 // Empty implementation
553 protected Set<NeighborSet>
554 computeImpactedNeighborsetForPortEvent(DeviceId impactedNeighbor,
555 Set<DeviceId> updatedNeighbors) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800556 return null;
557 }
558
559 private void populateNeighborMaps() {
560 Set<Link> outgoingLinks = linkService.getDeviceEgressLinks(deviceId);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700561 for (Link link : outgoingLinks) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800562 if (link.type() != Link.Type.DIRECT) {
563 continue;
564 }
565 addNeighborAtPort(link.dst().deviceId(), link.src().port());
566 }
567 }
568
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700569 protected void addNeighborAtPort(DeviceId neighborId,
570 PortNumber portToNeighbor) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800571 // Update DeviceToPort database
572 log.debug("Device {} addNeighborAtPort: neighbor {} at port {}",
573 deviceId, neighborId, portToNeighbor);
Saurav Das8a0732e2015-11-20 15:27:53 -0800574 Set<PortNumber> ports = Collections
575 .newSetFromMap(new ConcurrentHashMap<PortNumber, Boolean>());
576 ports.add(portToNeighbor);
577 Set<PortNumber> portnums = devicePortMap.putIfAbsent(neighborId, ports);
578 if (portnums != null) {
579 portnums.add(portToNeighbor);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800580 }
581
582 // Update portToDevice database
Saurav Das8a0732e2015-11-20 15:27:53 -0800583 DeviceId prev = portDeviceMap.putIfAbsent(portToNeighbor, neighborId);
584 if (prev != null) {
585 log.warn("Device: {} port: {} has neighbor: {}. NOT updating "
586 + "to neighbor: {}", deviceId, portToNeighbor, prev, neighborId);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800587 }
588 }
589
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700590 protected Set<Set<DeviceId>> getPowerSetOfNeighbors(Set<DeviceId> neighbors) {
Sho SHIMIZU6cfc02d2015-09-11 11:19:11 -0700591 List<DeviceId> list = new ArrayList<>(neighbors);
592 Set<Set<DeviceId>> sets = new HashSet<>();
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800593 // get the number of elements in the neighbors
594 int elements = list.size();
595 // the number of members of a power set is 2^n
596 // including the empty set
597 int powerElements = (1 << elements);
598
599 // run a binary counter for the number of power elements
600 // NOTE: Exclude empty set
601 for (long i = 1; i < powerElements; i++) {
Sho SHIMIZU6cfc02d2015-09-11 11:19:11 -0700602 Set<DeviceId> neighborSubSet = new HashSet<>();
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800603 for (int j = 0; j < elements; j++) {
604 if ((i >> j) % 2 == 1) {
605 neighborSubSet.add(list.get(j));
606 }
607 }
608 sets.add(neighborSubSet);
609 }
610 return sets;
611 }
612
613 private boolean isSegmentIdSameAsNodeSegmentId(DeviceId deviceId, int sId) {
Charles Chan0b4e6182015-11-03 10:42:14 -0800614 int segmentId;
615 try {
Pier Ventre917127a2016-10-31 16:49:19 -0700616 // IPv6 sid is not inserted. this part of the code is not used for now.
Pier Ventree0ae7a32016-11-23 09:57:42 -0800617 segmentId = deviceConfig.getIPv4SegmentId(deviceId);
Charles Chan0b4e6182015-11-03 10:42:14 -0800618 } catch (DeviceConfigNotFoundException e) {
619 log.warn(e.getMessage() + " Aborting isSegmentIdSameAsNodeSegmentId.");
620 return false;
621 }
622
623 return segmentId == sId;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800624 }
625
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700626 protected List<Integer> getSegmentIdsTobePairedWithNeighborSet(Set<DeviceId> neighbors) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800627
Sho SHIMIZU6cfc02d2015-09-11 11:19:11 -0700628 List<Integer> nsSegmentIds = new ArrayList<>();
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800629
sanghob35a6192015-04-01 13:05:26 -0700630 // Always pair up with no edge label
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700631 // If (neighbors.size() == 1) {
sanghob35a6192015-04-01 13:05:26 -0700632 nsSegmentIds.add(-1);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700633 // }
sanghob35a6192015-04-01 13:05:26 -0700634
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800635 // Filter out SegmentIds matching with the
636 // nodes in the combo
637 for (Integer sId : allSegmentIds) {
Pier Ventree0ae7a32016-11-23 09:57:42 -0800638 if (sId.equals(this.ipv4NodeSegmentId)) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800639 continue;
640 }
641 boolean filterOut = false;
642 // Check if the edge label being set is of
643 // any node in the Neighbor set
644 for (DeviceId deviceId : neighbors) {
645 if (isSegmentIdSameAsNodeSegmentId(deviceId, sId)) {
646 filterOut = true;
647 break;
648 }
649 }
650 if (!filterOut) {
651 nsSegmentIds.add(sId);
652 }
653 }
654 return nsSegmentIds;
655 }
656
sangho1e575652015-05-14 00:39:53 -0700657 /**
Saurav Das1a129a02016-11-18 15:21:57 -0800658 * Creates hash groups from a set of NeighborSet given.
sangho1e575652015-05-14 00:39:53 -0700659 *
660 * @param nsSet a set of NeighborSet
Saurav Das8a0732e2015-11-20 15:27:53 -0800661 * @param meta metadata passed into the creation of a Next Objective
Pier Ventre917127a2016-10-31 16:49:19 -0700662 * @param isBos if BoS is set
sangho1e575652015-05-14 00:39:53 -0700663 */
Saurav Das8a0732e2015-11-20 15:27:53 -0800664 public void createGroupsFromNeighborsets(Set<NeighborSet> nsSet,
Pier Ventre917127a2016-10-31 16:49:19 -0700665 TrafficSelector meta,
666 boolean isBos) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800667 for (NeighborSet ns : nsSet) {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700668 int nextId = flowObjectiveService.allocateNextId();
Pier Ventre917127a2016-10-31 16:49:19 -0700669 NextObjective.Type type = NextObjective.Type.HASHED;
670 Set<DeviceId> neighbors = ns.getDeviceIds();
671 // If Bos == False and MPLS-ECMP == false, we have
672 // to use simple group and we will pick a single neighbor.
673 if (!isBos && !srManager.getMplsEcmp()) {
674 type = NextObjective.Type.SIMPLE;
675 neighbors = Collections.singleton(ns.getFirstNeighbor());
676 }
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700677 NextObjective.Builder nextObjBuilder = DefaultNextObjective
Pier Ventre917127a2016-10-31 16:49:19 -0700678 .builder()
679 .withId(nextId)
680 .withType(type)
681 .fromApp(appId);
682 // For each neighbor, we have to update the sent actions
683 for (DeviceId neighborId : neighbors) {
Saurav Das8a0732e2015-11-20 15:27:53 -0800684 if (devicePortMap.get(neighborId) == null) {
685 log.warn("Neighbor {} is not in the port map yet for dev:{}",
686 neighborId, deviceId);
sangho834e4b02015-05-01 09:38:25 -0700687 return;
Jon Hallcbd1b392017-01-18 20:15:44 -0800688 } else if (devicePortMap.get(neighborId).isEmpty()) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700689 log.warn("There are no ports for "
Saurav Das8a0732e2015-11-20 15:27:53 -0800690 + "the Device {} in the port map yet", neighborId);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700691 return;
sangho834e4b02015-05-01 09:38:25 -0700692 }
693
Saurav Das8a0732e2015-11-20 15:27:53 -0800694 MacAddress neighborMac;
Charles Chan0b4e6182015-11-03 10:42:14 -0800695 try {
Saurav Das8a0732e2015-11-20 15:27:53 -0800696 neighborMac = deviceConfig.getDeviceMac(neighborId);
Charles Chan0b4e6182015-11-03 10:42:14 -0800697 } catch (DeviceConfigNotFoundException e) {
698 log.warn(e.getMessage() + " Aborting createGroupsFromNeighborsets.");
699 return;
700 }
Pier Ventre917127a2016-10-31 16:49:19 -0700701 // For each port, we have to create a new treatment
702 Set<PortNumber> neighborPorts = devicePortMap.get(neighborId);
703 // In this case we are using a SIMPLE group. We randomly pick a port
704 if (!isBos && !srManager.getMplsEcmp()) {
705 int size = devicePortMap.get(neighborId).size();
706 int index = RandomUtils.nextInt(0, size);
707 neighborPorts = Collections.singleton(
708 Iterables.get(devicePortMap.get(neighborId), index)
709 );
710 }
711 for (PortNumber sp : neighborPorts) {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700712 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment
713 .builder();
Saurav Das8a0732e2015-11-20 15:27:53 -0800714 tBuilder.setEthDst(neighborMac)
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700715 .setEthSrc(nodeMacAddr);
716 if (ns.getEdgeLabel() != NeighborSet.NO_EDGE_LABEL) {
Charles Chan68aa62d2015-11-09 16:37:23 -0800717 tBuilder.pushMpls()
718 .copyTtlOut()
719 .setMpls(MplsLabel.mplsLabel(ns.getEdgeLabel()));
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700720 }
Saurav Das8a0732e2015-11-20 15:27:53 -0800721 tBuilder.setOutput(sp);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700722 nextObjBuilder.addTreatment(tBuilder.build());
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800723 }
724 }
Saurav Das8a0732e2015-11-20 15:27:53 -0800725 if (meta != null) {
Saurav Das4ce45962015-11-24 23:21:05 -0800726 nextObjBuilder.withMeta(meta);
Saurav Das8a0732e2015-11-20 15:27:53 -0800727 }
Charles Chan216e3c82016-04-23 14:48:16 -0700728
729 ObjectiveContext context = new DefaultObjectiveContext(
Pier Ventre917127a2016-10-31 16:49:19 -0700730 (objective) ->
Saurav Das961beb22017-03-29 19:09:17 -0700731 log.debug("createGroupsFromNeighborsets installed "
732 + "NextObj {} on {}", nextId, deviceId),
Charles Chan216e3c82016-04-23 14:48:16 -0700733 (objective, error) ->
Saurav Das961beb22017-03-29 19:09:17 -0700734 log.warn("createGroupsFromNeighborsets failed to install"
735 + " NextObj {} on {}: {}", nextId, deviceId, error)
736 );
Charles Chan216e3c82016-04-23 14:48:16 -0700737 NextObjective nextObj = nextObjBuilder.add(context);
738 log.debug("**createGroupsFromNeighborsets: Submited "
Saurav Das8a0732e2015-11-20 15:27:53 -0800739 + "next objective {} in device {}",
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700740 nextId, deviceId);
Saurav Das8a0732e2015-11-20 15:27:53 -0800741 flowObjectiveService.next(deviceId, nextObj);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700742 nsNextObjStore.put(new NeighborSetNextObjectiveStoreKey(deviceId, ns),
743 nextId);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800744 }
745 }
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700746
Saurav Das4ce45962015-11-24 23:21:05 -0800747 /**
Saurav Das1a129a02016-11-18 15:21:57 -0800748 * Creates broadcast groups for all ports in the same subnet for
749 * all configured subnets.
Saurav Das4ce45962015-11-24 23:21:05 -0800750 */
Charles Chan59cc16d2017-02-02 16:20:42 -0800751 public void createGroupsFromVlanConfig() {
Charles Chan7ffd81f2017-02-08 15:52:08 -0800752 srManager.getVlanPortMap(deviceId).asMap().forEach((vlanId, ports) -> {
Charles Chan59cc16d2017-02-02 16:20:42 -0800753 createBcastGroupFromVlan(vlanId, ports);
Pier Ventre10bd8d12016-11-26 21:05:22 -0800754 });
Saurav Das1a129a02016-11-18 15:21:57 -0800755 }
Charles Chan9f676b62015-10-29 14:58:10 -0700756
Saurav Das1a129a02016-11-18 15:21:57 -0800757 /**
Charles Chan59cc16d2017-02-02 16:20:42 -0800758 * Creates a single broadcast group from a given vlan id and list of ports.
Saurav Das1a129a02016-11-18 15:21:57 -0800759 *
Charles Chan59cc16d2017-02-02 16:20:42 -0800760 * @param vlanId vlan id
Saurav Das1a129a02016-11-18 15:21:57 -0800761 * @param ports list of ports in the subnet
762 */
Charles Chan7ffd81f2017-02-08 15:52:08 -0800763 public void createBcastGroupFromVlan(VlanId vlanId, Collection<PortNumber> ports) {
Charles Chan59cc16d2017-02-02 16:20:42 -0800764 VlanNextObjectiveStoreKey key = new VlanNextObjectiveStoreKey(deviceId, vlanId);
Charles Chan9f676b62015-10-29 14:58:10 -0700765
Charles Chan59cc16d2017-02-02 16:20:42 -0800766 if (vlanNextObjStore.containsKey(key)) {
Saurav Das1a129a02016-11-18 15:21:57 -0800767 log.debug("Broadcast group for device {} and subnet {} exists",
Charles Chan59cc16d2017-02-02 16:20:42 -0800768 deviceId, vlanId);
Saurav Das1a129a02016-11-18 15:21:57 -0800769 return;
770 }
Charles Chan188ebf52015-12-23 00:15:11 -0800771
Saurav Das1a129a02016-11-18 15:21:57 -0800772 TrafficSelector metadata =
Charles Chan59cc16d2017-02-02 16:20:42 -0800773 DefaultTrafficSelector.builder().matchVlanId(vlanId).build();
Charles Chanc42e84e2015-10-20 16:24:19 -0700774
Saurav Das1a129a02016-11-18 15:21:57 -0800775 int nextId = flowObjectiveService.allocateNextId();
Charles Chanc42e84e2015-10-20 16:24:19 -0700776
Saurav Das1a129a02016-11-18 15:21:57 -0800777 NextObjective.Builder nextObjBuilder = DefaultNextObjective
778 .builder().withId(nextId)
779 .withType(NextObjective.Type.BROADCAST).fromApp(appId)
780 .withMeta(metadata);
Charles Chanc42e84e2015-10-20 16:24:19 -0700781
Saurav Das1a129a02016-11-18 15:21:57 -0800782 ports.forEach(port -> {
783 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
Charles Chan7ffd81f2017-02-08 15:52:08 -0800784 if (toPopVlan(port, vlanId)) {
785 tBuilder.popVlan();
786 }
Saurav Das1a129a02016-11-18 15:21:57 -0800787 tBuilder.setOutput(port);
788 nextObjBuilder.addTreatment(tBuilder.build());
Charles Chanc42e84e2015-10-20 16:24:19 -0700789 });
Saurav Das1a129a02016-11-18 15:21:57 -0800790
Saurav Das961beb22017-03-29 19:09:17 -0700791 ObjectiveContext context = new DefaultObjectiveContext(
792 (objective) ->
793 log.debug("createBroadcastGroupFromVlan installed "
794 + "NextObj {} on {}", nextId, deviceId),
795 (objective, error) ->
796 log.warn("createBroadcastGroupFromVlan failed to install"
797 + " NextObj {} on {}: {}", nextId, deviceId, error)
798 );
799 NextObjective nextObj = nextObjBuilder.add(context);
Saurav Das1a129a02016-11-18 15:21:57 -0800800 flowObjectiveService.next(deviceId, nextObj);
Charles Chan59cc16d2017-02-02 16:20:42 -0800801 log.debug("createBcastGroupFromVlan: Submited next objective {} in device {}",
Saurav Das1a129a02016-11-18 15:21:57 -0800802 nextId, deviceId);
803
Charles Chan59cc16d2017-02-02 16:20:42 -0800804 vlanNextObjStore.put(key, nextId);
Charles Chanc42e84e2015-10-20 16:24:19 -0700805 }
806
Charles Chane849c192016-01-11 18:28:54 -0800807 /**
Charles Chan7ffd81f2017-02-08 15:52:08 -0800808 * Determine if we should pop given vlan before sending packets to the given port.
809 *
810 * @param portNumber port number
811 * @param vlanId vlan id
812 * @return true if the vlan id is not contained in any vlanTagged config
813 */
814 private boolean toPopVlan(PortNumber portNumber, VlanId vlanId) {
815 return srManager.interfaceService.getInterfacesByPort(new ConnectPoint(deviceId, portNumber))
816 .stream().noneMatch(intf -> intf.vlanTagged().contains(vlanId));
817 }
818
819 /**
Saurav Das4ce45962015-11-24 23:21:05 -0800820 * Create simple next objective for a single port. The treatments can include
821 * all outgoing actions that need to happen on the packet.
822 *
823 * @param portNum the outgoing port on the device
824 * @param treatment the actions to apply on the packets (should include outport)
825 * @param meta optional data to pass to the driver
826 */
827 public void createGroupFromPort(PortNumber portNum, TrafficTreatment treatment,
828 TrafficSelector meta) {
829 int nextId = flowObjectiveService.allocateNextId();
830 PortNextObjectiveStoreKey key = new PortNextObjectiveStoreKey(
Saurav Das76ae6812017-03-15 15:15:14 -0700831 deviceId, portNum, treatment, meta);
Saurav Das4ce45962015-11-24 23:21:05 -0800832
833 NextObjective.Builder nextObjBuilder = DefaultNextObjective
834 .builder().withId(nextId)
835 .withType(NextObjective.Type.SIMPLE)
836 .addTreatment(treatment)
837 .fromApp(appId)
838 .withMeta(meta);
839
Saurav Das961beb22017-03-29 19:09:17 -0700840 ObjectiveContext context = new DefaultObjectiveContext(
841 (objective) ->
842 log.debug("createGroupFromPort installed "
843 + "NextObj {} on {}", nextId, deviceId),
844 (objective, error) ->
845 log.warn("createGroupFromPort failed to install"
846 + " NextObj {} on {}: {}", nextId, deviceId, error)
847 );
848 NextObjective nextObj = nextObjBuilder.add(context);
Saurav Das4ce45962015-11-24 23:21:05 -0800849 flowObjectiveService.next(deviceId, nextObj);
850 log.debug("createGroupFromPort: Submited next objective {} in device {} "
851 + "for port {}", nextId, deviceId, portNum);
852
853 portNextObjStore.put(key, nextId);
854 }
855
sangho1e575652015-05-14 00:39:53 -0700856 /**
857 * Removes groups for the next objective ID given.
858 *
859 * @param objectiveId next objective ID to remove
860 * @return true if succeeds, false otherwise
861 */
862 public boolean removeGroup(int objectiveId) {
863
864 if (nsNextObjStore.containsValue(objectiveId)) {
865 NextObjective.Builder nextObjBuilder = DefaultNextObjective
866 .builder().withId(objectiveId)
867 .withType(NextObjective.Type.HASHED).fromApp(appId);
Charles Chan216e3c82016-04-23 14:48:16 -0700868 ObjectiveContext context = new DefaultObjectiveContext(
869 (objective) -> log.debug("RemoveGroup removes NextObj {} on {}",
870 objectiveId, deviceId),
871 (objective, error) ->
872 log.warn("RemoveGroup failed to remove NextObj {} on {}: {}",
873 objectiveId, deviceId, error));
874 NextObjective nextObjective = nextObjBuilder.remove(context);
Saurav Das8a0732e2015-11-20 15:27:53 -0800875 log.info("**removeGroup: Submited "
876 + "next objective {} in device {}",
877 objectiveId, deviceId);
sangho1e575652015-05-14 00:39:53 -0700878 flowObjectiveService.next(deviceId, nextObjective);
879
880 for (Map.Entry<NeighborSetNextObjectiveStoreKey, Integer> entry: nsNextObjStore.entrySet()) {
881 if (entry.getValue().equals(objectiveId)) {
882 nsNextObjStore.remove(entry.getKey());
883 break;
884 }
885 }
sangho0b2b6d12015-05-20 22:16:38 -0700886 return true;
sangho1e575652015-05-14 00:39:53 -0700887 }
888
889 return false;
890 }
Srikanth Vavilapallif3a8bc02015-05-22 13:47:31 -0700891
Charles Chane849c192016-01-11 18:28:54 -0800892 /**
893 * Removes all groups from all next objective stores.
894 */
Saurav Das423fe2b2015-12-04 10:52:59 -0800895 public void removeAllGroups() {
896 for (Map.Entry<NeighborSetNextObjectiveStoreKey, Integer> entry:
897 nsNextObjStore.entrySet()) {
898 removeGroup(entry.getValue());
899 }
900 for (Map.Entry<PortNextObjectiveStoreKey, Integer> entry:
901 portNextObjStore.entrySet()) {
902 removeGroup(entry.getValue());
903 }
Charles Chan59cc16d2017-02-02 16:20:42 -0800904 for (Map.Entry<VlanNextObjectiveStoreKey, Integer> entry:
905 vlanNextObjStore.entrySet()) {
Saurav Das423fe2b2015-12-04 10:52:59 -0800906 removeGroup(entry.getValue());
907 }
908 // should probably clean local stores port-neighbor
909 }
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800910}