blob: 13991535df1fe9fe572df634e0e11a6a50cc9bec [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
18import static com.google.common.base.Preconditions.checkNotNull;
19import static org.slf4j.LoggerFactory.getLogger;
20
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -070021import java.net.URI;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080022import java.util.ArrayList;
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070023import java.util.Collections;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080024import java.util.HashSet;
25import java.util.List;
sangho1e575652015-05-14 00:39:53 -070026import java.util.Map;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080027import java.util.Set;
Saurav Das8a0732e2015-11-20 15:27:53 -080028import java.util.concurrent.ConcurrentHashMap;
Srikanth Vavilapalli23181912015-05-04 09:48:09 -070029import java.util.stream.Collectors;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080030
Charles Chanc42e84e2015-10-20 16:24:19 -070031import org.onlab.packet.Ip4Prefix;
32import org.onlab.packet.IpPrefix;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080033import org.onlab.packet.MacAddress;
sangho32a59322015-02-17 12:07:41 -080034import org.onlab.packet.MplsLabel;
Saurav Das423fe2b2015-12-04 10:52:59 -080035import org.onlab.packet.VlanId;
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -070036import org.onlab.util.KryoNamespace;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080037import org.onosproject.core.ApplicationId;
Charles Chane849c192016-01-11 18:28:54 -080038import org.onosproject.net.ConnectPoint;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080039import org.onosproject.net.DeviceId;
40import org.onosproject.net.Link;
41import org.onosproject.net.PortNumber;
Saurav Das423fe2b2015-12-04 10:52:59 -080042import org.onosproject.net.flow.DefaultTrafficSelector;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080043import org.onosproject.net.flow.DefaultTrafficTreatment;
Saurav Das8a0732e2015-11-20 15:27:53 -080044import org.onosproject.net.flow.TrafficSelector;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080045import org.onosproject.net.flow.TrafficTreatment;
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070046import org.onosproject.net.flowobjective.DefaultNextObjective;
Charles Chan216e3c82016-04-23 14:48:16 -070047import org.onosproject.net.flowobjective.DefaultObjectiveContext;
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070048import org.onosproject.net.flowobjective.FlowObjectiveService;
49import org.onosproject.net.flowobjective.NextObjective;
Srikanth Vavilapallif3a8bc02015-05-22 13:47:31 -070050import org.onosproject.net.flowobjective.ObjectiveContext;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080051import org.onosproject.net.link.LinkService;
Saurav Das423fe2b2015-12-04 10:52:59 -080052import org.onosproject.segmentrouting.SegmentRoutingManager;
Charles Chan0b4e6182015-11-03 10:42:14 -080053import org.onosproject.segmentrouting.config.DeviceConfigNotFoundException;
54import org.onosproject.segmentrouting.config.DeviceProperties;
Charles Chand2990362016-04-18 13:44:03 -070055import org.onosproject.segmentrouting.storekey.NeighborSetNextObjectiveStoreKey;
56import org.onosproject.segmentrouting.storekey.PortNextObjectiveStoreKey;
57import org.onosproject.segmentrouting.storekey.SubnetNextObjectiveStoreKey;
58import org.onosproject.segmentrouting.storekey.XConnectNextObjectiveStoreKey;
Srikanth Vavilapalli23181912015-05-04 09:48:09 -070059import org.onosproject.store.service.EventuallyConsistentMap;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080060import org.slf4j.Logger;
61
62/**
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070063 * Default ECMP group handler creation module. This component creates a set of
64 * ECMP groups for every neighbor that this device is connected to based on
65 * whether the current device is an edge device or a transit device.
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080066 */
67public class DefaultGroupHandler {
Srikanth Vavilapallif3a8bc02015-05-22 13:47:31 -070068 protected static final Logger log = getLogger(DefaultGroupHandler.class);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080069
70 protected final DeviceId deviceId;
71 protected final ApplicationId appId;
72 protected final DeviceProperties deviceConfig;
73 protected final List<Integer> allSegmentIds;
Charles Chan0b4e6182015-11-03 10:42:14 -080074 protected int nodeSegmentId = -1;
75 protected boolean isEdgeRouter = false;
76 protected MacAddress nodeMacAddr = null;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080077 protected LinkService linkService;
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070078 protected FlowObjectiveService flowObjectiveService;
Saurav Das423fe2b2015-12-04 10:52:59 -080079 // local store for neighbor-device-ids and the set of ports on this device
80 // that connect to the same neighbor
Saurav Das8a0732e2015-11-20 15:27:53 -080081 protected ConcurrentHashMap<DeviceId, Set<PortNumber>> devicePortMap =
82 new ConcurrentHashMap<>();
Saurav Das423fe2b2015-12-04 10:52:59 -080083 //local store for ports on this device connected to neighbor-device-id
Saurav Das8a0732e2015-11-20 15:27:53 -080084 protected ConcurrentHashMap<PortNumber, DeviceId> portDeviceMap =
85 new ConcurrentHashMap<>();
Charles Chane849c192016-01-11 18:28:54 -080086 protected EventuallyConsistentMap<NeighborSetNextObjectiveStoreKey, Integer>
87 nsNextObjStore = null;
88 protected EventuallyConsistentMap<SubnetNextObjectiveStoreKey, Integer>
89 subnetNextObjStore = null;
90 protected EventuallyConsistentMap<PortNextObjectiveStoreKey, Integer>
91 portNextObjStore = null;
92 protected EventuallyConsistentMap<XConnectNextObjectiveStoreKey, Integer>
93 xConnectNextObjStore = null;
Charles Chan188ebf52015-12-23 00:15:11 -080094 private SegmentRoutingManager srManager;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080095
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -070096 protected KryoNamespace.Builder kryo = new KryoNamespace.Builder()
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070097 .register(URI.class).register(HashSet.class)
98 .register(DeviceId.class).register(PortNumber.class)
99 .register(NeighborSet.class).register(PolicyGroupIdentifier.class)
100 .register(PolicyGroupParams.class)
101 .register(GroupBucketIdentifier.class)
102 .register(GroupBucketIdentifier.BucketOutputType.class);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800103
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700104 protected DefaultGroupHandler(DeviceId deviceId, ApplicationId appId,
105 DeviceProperties config,
106 LinkService linkService,
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700107 FlowObjectiveService flowObjService,
Charles Chan188ebf52015-12-23 00:15:11 -0800108 SegmentRoutingManager srManager) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800109 this.deviceId = checkNotNull(deviceId);
110 this.appId = checkNotNull(appId);
111 this.deviceConfig = checkNotNull(config);
112 this.linkService = checkNotNull(linkService);
Charles Chan0b4e6182015-11-03 10:42:14 -0800113 this.allSegmentIds = checkNotNull(config.getAllDeviceSegmentIds());
114 try {
115 this.nodeSegmentId = config.getSegmentId(deviceId);
116 this.isEdgeRouter = config.isEdgeDevice(deviceId);
117 this.nodeMacAddr = checkNotNull(config.getDeviceMac(deviceId));
118 } catch (DeviceConfigNotFoundException e) {
119 log.warn(e.getMessage()
120 + " Skipping value assignment in DefaultGroupHandler");
121 }
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700122 this.flowObjectiveService = flowObjService;
Charles Chane849c192016-01-11 18:28:54 -0800123 this.nsNextObjStore = srManager.nsNextObjStore;
124 this.subnetNextObjStore = srManager.subnetNextObjStore;
125 this.portNextObjStore = srManager.portNextObjStore;
126 this.xConnectNextObjStore = srManager.xConnectNextObjStore;
Charles Chan188ebf52015-12-23 00:15:11 -0800127 this.srManager = srManager;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800128
129 populateNeighborMaps();
130 }
131
132 /**
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700133 * Creates a group handler object based on the type of device. If device is
134 * of edge type it returns edge group handler, else it returns transit group
135 * handler.
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800136 *
137 * @param deviceId device identifier
138 * @param appId application identifier
139 * @param config interface to retrieve the device properties
140 * @param linkService link service object
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700141 * @param flowObjService flow objective service object
Charles Chane849c192016-01-11 18:28:54 -0800142 * @param srManager segment routing manager
Charles Chan0b4e6182015-11-03 10:42:14 -0800143 * @throws DeviceConfigNotFoundException if the device configuration is not found
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800144 * @return default group handler type
145 */
Saurav Das4ce45962015-11-24 23:21:05 -0800146 public static DefaultGroupHandler createGroupHandler(
147 DeviceId deviceId,
148 ApplicationId appId,
149 DeviceProperties config,
150 LinkService linkService,
151 FlowObjectiveService flowObjService,
Charles Chan188ebf52015-12-23 00:15:11 -0800152 SegmentRoutingManager srManager)
Saurav Das4ce45962015-11-24 23:21:05 -0800153 throws DeviceConfigNotFoundException {
Charles Chan0b4e6182015-11-03 10:42:14 -0800154 // handle possible exception in the caller
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800155 if (config.isEdgeDevice(deviceId)) {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700156 return new DefaultEdgeGroupHandler(deviceId, appId, config,
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700157 linkService,
158 flowObjService,
Charles Chan188ebf52015-12-23 00:15:11 -0800159 srManager
160 );
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800161 } else {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700162 return new DefaultTransitGroupHandler(deviceId, appId, config,
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700163 linkService,
164 flowObjService,
Charles Chan188ebf52015-12-23 00:15:11 -0800165 srManager);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800166 }
167 }
168
169 /**
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700170 * Creates the auto created groups for this device based on the current
171 * snapshot of the topology.
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800172 */
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700173 // Empty implementations to be overridden by derived classes
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800174 public void createGroups() {
175 }
176
177 /**
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700178 * Performs group creation or update procedures when a new link is
179 * discovered on this device.
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800180 *
181 * @param newLink new neighbor link
Charles Chane849c192016-01-11 18:28:54 -0800182 * @param isMaster true if local instance is the master
183 *
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800184 */
Saurav Das8a0732e2015-11-20 15:27:53 -0800185 public void linkUp(Link newLink, boolean isMaster) {
sanghob35a6192015-04-01 13:05:26 -0700186
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800187 if (newLink.type() != Link.Type.DIRECT) {
188 log.warn("linkUp: unknown link type");
189 return;
190 }
191
192 if (!newLink.src().deviceId().equals(deviceId)) {
193 log.warn("linkUp: deviceId{} doesn't match with link src{}",
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700194 deviceId, newLink.src().deviceId());
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800195 return;
196 }
197
Saurav Das8a0732e2015-11-20 15:27:53 -0800198 log.info("* LinkUP: Device {} linkUp at local port {} to neighbor {}", deviceId,
199 newLink.src().port(), newLink.dst().deviceId());
Saurav Das59232cf2016-04-27 18:35:50 -0700200 // ensure local state is updated even if linkup is aborted later on
201 addNeighborAtPort(newLink.dst().deviceId(),
202 newLink.src().port());
203
Charles Chan0b4e6182015-11-03 10:42:14 -0800204 MacAddress dstMac;
205 try {
206 dstMac = deviceConfig.getDeviceMac(newLink.dst().deviceId());
207 } catch (DeviceConfigNotFoundException e) {
208 log.warn(e.getMessage() + " Aborting linkUp.");
209 return;
210 }
211
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700212 /*if (devicePortMap.get(newLink.dst().deviceId()) == null) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800213 // New Neighbor
214 newNeighbor(newLink);
215 } else {
216 // Old Neighbor
217 newPortToExistingNeighbor(newLink);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700218 }*/
219 Set<NeighborSet> nsSet = nsNextObjStore.keySet()
220 .stream()
221 .filter((nsStoreEntry) -> (nsStoreEntry.deviceId().equals(deviceId)))
222 .map((nsStoreEntry) -> (nsStoreEntry.neighborSet()))
223 .filter((ns) -> (ns.getDeviceIds()
224 .contains(newLink.dst().deviceId())))
225 .collect(Collectors.toSet());
226 log.trace("linkUp: nsNextObjStore contents for device {}:",
sangho0b2b6d12015-05-20 22:16:38 -0700227 deviceId,
228 nsSet);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700229 for (NeighborSet ns : nsSet) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700230 Integer nextId = nsNextObjStore.
231 get(new NeighborSetNextObjectiveStoreKey(deviceId, ns));
Saurav Das4ce45962015-11-24 23:21:05 -0800232 if (nextId != null && isMaster) {
Saurav Das423fe2b2015-12-04 10:52:59 -0800233 // Create the new bucket to be updated
234 TrafficTreatment.Builder tBuilder =
235 DefaultTrafficTreatment.builder();
236 tBuilder.setOutput(newLink.src().port())
237 .setEthDst(dstMac)
238 .setEthSrc(nodeMacAddr);
239 if (ns.getEdgeLabel() != NeighborSet.NO_EDGE_LABEL) {
240 tBuilder.pushMpls()
241 .copyTtlOut()
242 .setMpls(MplsLabel.mplsLabel(ns.getEdgeLabel()));
243 }
244 // setup metadata to pass to nextObjective - indicate the vlan on egress
245 // if needed by the switch pipeline. Since hashed next-hops are always to
246 // other neighboring routers, there is no subnet assigned on those ports.
247 TrafficSelector.Builder metabuilder = DefaultTrafficSelector.builder();
248 metabuilder.matchVlanId(
249 VlanId.vlanId(SegmentRoutingManager.ASSIGNED_VLAN_NO_SUBNET));
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700250
Saurav Das423fe2b2015-12-04 10:52:59 -0800251 NextObjective.Builder nextObjBuilder = DefaultNextObjective.builder()
252 .withId(nextId)
253 .withType(NextObjective.Type.HASHED)
254 .addTreatment(tBuilder.build())
255 .withMeta(metabuilder.build())
256 .fromApp(appId);
Saurav Das8a0732e2015-11-20 15:27:53 -0800257 log.info("**linkUp in device {}: Adding Bucket "
Saurav Das4ce45962015-11-24 23:21:05 -0800258 + "with Port {} to next object id {}",
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700259 deviceId,
260 newLink.src().port(),
Saurav Das4ce45962015-11-24 23:21:05 -0800261 nextId);
Charles Chan216e3c82016-04-23 14:48:16 -0700262
263 ObjectiveContext context = new DefaultObjectiveContext(
264 (objective) -> log.debug("LinkUp installed NextObj {} on {}",
265 nextId, deviceId),
266 (objective, error) ->
267 log.warn("LinkUp failed to install NextObj {} on {}: {}",
268 nextId, deviceId, error));
269 NextObjective nextObjective = nextObjBuilder.addToExisting(context);
Saurav Das4ce45962015-11-24 23:21:05 -0800270 flowObjectiveService.next(deviceId, nextObjective);
Saurav Das423fe2b2015-12-04 10:52:59 -0800271
272 // the addition of a bucket may actually change the neighborset
273 // update the global store
274 /*
275 Set<DeviceId> neighbors = new HashSet<DeviceId>(ns.getDeviceIds());
276 boolean newadd = neighbors.add(newLink.dst().deviceId());
277 if (newadd) {
278 NeighborSet nsnew = new NeighborSet(neighbors, ns.getEdgeLabel());
279 nsNextObjStore.put(new NeighborSetNextObjectiveStoreKey(deviceId, nsnew),
280 nextId);
281 nsNextObjStore.remove(new NeighborSetNextObjectiveStoreKey(deviceId, ns));
282 }*/
Saurav Das4ce45962015-11-24 23:21:05 -0800283 } else if (isMaster) {
Saurav Das8a0732e2015-11-20 15:27:53 -0800284 log.warn("linkUp in device {}, but global store has no record "
285 + "for neighbor-set {}", deviceId, ns);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700286 }
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800287 }
288 }
289
290 /**
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700291 * Performs group recovery procedures when a port goes down on this device.
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800292 *
293 * @param port port number that has gone down
Charles Chane849c192016-01-11 18:28:54 -0800294 * @param isMaster true if local instance is the master
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800295 */
Saurav Das423fe2b2015-12-04 10:52:59 -0800296 public void portDown(PortNumber port, boolean isMaster) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800297 if (portDeviceMap.get(port) == null) {
298 log.warn("portDown: unknown port");
299 return;
300 }
Charles Chan0b4e6182015-11-03 10:42:14 -0800301
Saurav Das80980c72016-03-23 11:22:49 -0700302 @SuppressWarnings("unused")
Charles Chan0b4e6182015-11-03 10:42:14 -0800303 MacAddress dstMac;
304 try {
305 dstMac = deviceConfig.getDeviceMac(portDeviceMap.get(port));
306 } catch (DeviceConfigNotFoundException e) {
307 log.warn(e.getMessage() + " Aborting portDown.");
308 return;
309 }
310
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700311 log.debug("Device {} portDown {} to neighbor {}", deviceId, port,
312 portDeviceMap.get(port));
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700313 /*Set<NeighborSet> nsSet = computeImpactedNeighborsetForPortEvent(portDeviceMap
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700314 .get(port),
315 devicePortMap
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700316 .keySet());*/
317 Set<NeighborSet> nsSet = nsNextObjStore.keySet()
318 .stream()
319 .filter((nsStoreEntry) -> (nsStoreEntry.deviceId().equals(deviceId)))
320 .map((nsStoreEntry) -> (nsStoreEntry.neighborSet()))
321 .filter((ns) -> (ns.getDeviceIds()
322 .contains(portDeviceMap.get(port))))
323 .collect(Collectors.toSet());
Saurav Das423fe2b2015-12-04 10:52:59 -0800324 log.debug("portDown: nsNextObjStore contents for device {}:{}",
325 deviceId, nsSet);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800326 for (NeighborSet ns : nsSet) {
Saurav Das80980c72016-03-23 11:22:49 -0700327 NeighborSetNextObjectiveStoreKey nsStoreKey =
328 new NeighborSetNextObjectiveStoreKey(deviceId, ns);
329 Integer nextId = nsNextObjStore.get(nsStoreKey);
Saurav Das423fe2b2015-12-04 10:52:59 -0800330 if (nextId != null && isMaster) {
Saurav Das80980c72016-03-23 11:22:49 -0700331 // XXX This is a workaround for BUG (CORD-611) in current switches.
332 // Should be temporary because this workaround prevents correct
333 // functionality in LAG recovery.
334 log.info("**portDown port:{} in device {}: Invalidating nextId {}",
335 port, deviceId, nextId);
336 nsNextObjStore.remove(nsStoreKey);
337 /*
Saurav Das8a0732e2015-11-20 15:27:53 -0800338 log.info("**portDown in device {}: Removing Bucket "
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700339 + "with Port {} to next object id {}",
340 deviceId,
341 port,
342 nextId);
Saurav Das423fe2b2015-12-04 10:52:59 -0800343 // Create the bucket to be removed
344 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment
345 .builder();
346 tBuilder.setOutput(port)
347 .setEthDst(dstMac)
348 .setEthSrc(nodeMacAddr);
349 if (ns.getEdgeLabel() != NeighborSet.NO_EDGE_LABEL) {
350 tBuilder.pushMpls()
351 .copyTtlOut()
352 .setMpls(MplsLabel.mplsLabel(ns.getEdgeLabel()));
353 }
354 NextObjective.Builder nextObjBuilder = DefaultNextObjective
355 .builder()
356 .withType(NextObjective.Type.HASHED) //same as original
357 .withId(nextId)
358 .fromApp(appId)
359 .addTreatment(tBuilder.build());
360 NextObjective nextObjective = nextObjBuilder.
361 removeFromExisting(new SRNextObjectiveContext(deviceId));
sangho834e4b02015-05-01 09:38:25 -0700362
Saurav Das423fe2b2015-12-04 10:52:59 -0800363 flowObjectiveService.next(deviceId, nextObjective);
Saurav Das80980c72016-03-23 11:22:49 -0700364 */
Saurav Das423fe2b2015-12-04 10:52:59 -0800365 // the removal of a bucket may actually change the neighborset
366 // update the global store
367 /*
368 Set<DeviceId> neighbors = new HashSet<DeviceId>(ns.getDeviceIds());
369 boolean removed = neighbors.remove(portDeviceMap.get(port));
370 if (removed) {
371 NeighborSet nsnew = new NeighborSet(neighbors, ns.getEdgeLabel());
372 nsNextObjStore.put(new NeighborSetNextObjectiveStoreKey(deviceId, nsnew),
373 nextId);
374 nsNextObjStore.remove(new NeighborSetNextObjectiveStoreKey(deviceId, ns));
375 }*/
sangho834e4b02015-05-01 09:38:25 -0700376 }
377
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800378 }
379
380 devicePortMap.get(portDeviceMap.get(port)).remove(port);
381 portDeviceMap.remove(port);
382 }
383
384 /**
Saurav Das4ce45962015-11-24 23:21:05 -0800385 * Returns the next objective of type hashed associated with the neighborset.
386 * If there is no next objective for this neighborset, this method
Saurav Das8a0732e2015-11-20 15:27:53 -0800387 * would create a next objective and return. Optionally metadata can be
388 * passed in for the creation of the next objective.
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800389 *
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700390 * @param ns neighborset
Saurav Das8a0732e2015-11-20 15:27:53 -0800391 * @param meta metadata passed into the creation of a Next Objective
392 * @return int if found or -1 if there are errors in the creation of the
393 * neighbor set.
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800394 */
Saurav Das8a0732e2015-11-20 15:27:53 -0800395 public int getNextObjectiveId(NeighborSet ns, TrafficSelector meta) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700396 Integer nextId = nsNextObjStore.
397 get(new NeighborSetNextObjectiveStoreKey(deviceId, ns));
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700398 if (nextId == null) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700399 log.trace("getNextObjectiveId in device{}: Next objective id "
400 + "not found for {} and creating", deviceId, ns);
401 log.trace("getNextObjectiveId: nsNextObjStore contents for device {}: {}",
402 deviceId,
403 nsNextObjStore.entrySet()
404 .stream()
405 .filter((nsStoreEntry) ->
406 (nsStoreEntry.getKey().deviceId().equals(deviceId)))
407 .collect(Collectors.toList()));
Saurav Das8a0732e2015-11-20 15:27:53 -0800408 createGroupsFromNeighborsets(Collections.singleton(ns), meta);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700409 nextId = nsNextObjStore.
410 get(new NeighborSetNextObjectiveStoreKey(deviceId, ns));
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700411 if (nextId == null) {
412 log.warn("getNextObjectiveId: unable to create next objective");
413 return -1;
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700414 } else {
415 log.debug("getNextObjectiveId in device{}: Next objective id {} "
Sho SHIMIZUaf973432015-09-11 14:24:50 -0700416 + "created for {}", deviceId, nextId, ns);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700417 }
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700418 } else {
419 log.trace("getNextObjectiveId in device{}: Next objective id {} "
Sho SHIMIZUaf973432015-09-11 14:24:50 -0700420 + "found for {}", deviceId, nextId, ns);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700421 }
Sho SHIMIZUaf973432015-09-11 14:24:50 -0700422 return nextId;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800423 }
424
sangho0b2b6d12015-05-20 22:16:38 -0700425 /**
Saurav Das4ce45962015-11-24 23:21:05 -0800426 * Returns the next objective of type broadcast associated with the subnet,
427 * or -1 if no such objective exists. Note that this method does NOT create
428 * the next objective as a side-effect. It is expected that is objective is
429 * created at startup from network configuration.
Charles Chanc42e84e2015-10-20 16:24:19 -0700430 *
431 * @param prefix subnet information
432 * @return int if found or -1
433 */
434 public int getSubnetNextObjectiveId(IpPrefix prefix) {
435 Integer nextId = subnetNextObjStore.
436 get(new SubnetNextObjectiveStoreKey(deviceId, prefix));
Charles Chan9f676b62015-10-29 14:58:10 -0700437
438 return (nextId != null) ? nextId : -1;
Charles Chanc42e84e2015-10-20 16:24:19 -0700439 }
440
441 /**
Saurav Das4ce45962015-11-24 23:21:05 -0800442 * Returns the next objective of type simple associated with the port on the
443 * device, given the treatment. Different treatments to the same port result
444 * in different next objectives. If no such objective exists, this method
445 * creates one and returns the id. Optionally metadata can be passed in for
446 * the creation of the objective.
447 *
448 * @param portNum the port number for the simple next objective
449 * @param treatment the actions to apply on the packets (should include outport)
450 * @param meta optional metadata passed into the creation of the next objective
451 * @return int if found or created, -1 if there are errors during the
452 * creation of the next objective.
453 */
454 public int getPortNextObjectiveId(PortNumber portNum, TrafficTreatment treatment,
455 TrafficSelector meta) {
Charles Chane849c192016-01-11 18:28:54 -0800456 Integer nextId = portNextObjStore
457 .get(new PortNextObjectiveStoreKey(deviceId, portNum, treatment));
Saurav Das4ce45962015-11-24 23:21:05 -0800458 if (nextId == null) {
459 log.trace("getPortNextObjectiveId in device{}: Next objective id "
460 + "not found for {} and {} creating", deviceId, portNum);
461 createGroupFromPort(portNum, treatment, meta);
462 nextId = portNextObjStore.get(
463 new PortNextObjectiveStoreKey(deviceId, portNum, treatment));
464 if (nextId == null) {
465 log.warn("getPortNextObjectiveId: unable to create next obj"
Charles Chane849c192016-01-11 18:28:54 -0800466 + "for dev:{} port:{}", deviceId, portNum);
467 return -1;
468 }
469 }
470 return nextId;
471 }
472
473 /**
474 * Returns the next objective ID of type broadcast associated with the VLAN
475 * cross-connection.
476 *
477 * @param vlanId VLAN ID for the cross-connection
478 * @return int if found or created, -1 if there are errors during the
479 * creation of the next objective
480 */
481 public int getXConnectNextObjectiveId(VlanId vlanId) {
482 Integer nextId = xConnectNextObjStore
483 .get(new XConnectNextObjectiveStoreKey(deviceId, vlanId));
484 if (nextId == null) {
485 log.trace("getXConnectNextObjectiveId: Next objective id "
486 + "not found for device {} and vlan {}. Creating", deviceId, vlanId);
487 createGroupsForXConnect(deviceId);
488 nextId = xConnectNextObjStore.get(
489 new XConnectNextObjectiveStoreKey(deviceId, vlanId));
490 if (nextId == null) {
491 log.warn("getXConnectNextObjectiveId: Next objective id "
492 + "not found for device {} and vlan {}.", deviceId, vlanId);
Saurav Das4ce45962015-11-24 23:21:05 -0800493 return -1;
494 }
495 }
496 return nextId;
497 }
498
499 /**
sangho0b2b6d12015-05-20 22:16:38 -0700500 * Checks if the next objective ID (group) for the neighbor set exists or not.
501 *
502 * @param ns neighbor set to check
503 * @return true if it exists, false otherwise
504 */
505 public boolean hasNextObjectiveId(NeighborSet ns) {
506 Integer nextId = nsNextObjStore.
507 get(new NeighborSetNextObjectiveStoreKey(deviceId, ns));
508 if (nextId == null) {
509 return false;
510 }
511
512 return true;
513 }
514
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700515 // Empty implementation
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800516 protected void newNeighbor(Link newLink) {
517 }
518
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700519 // Empty implementation
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800520 protected void newPortToExistingNeighbor(Link newLink) {
521 }
522
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700523 // Empty implementation
524 protected Set<NeighborSet>
525 computeImpactedNeighborsetForPortEvent(DeviceId impactedNeighbor,
526 Set<DeviceId> updatedNeighbors) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800527 return null;
528 }
529
530 private void populateNeighborMaps() {
531 Set<Link> outgoingLinks = linkService.getDeviceEgressLinks(deviceId);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700532 for (Link link : outgoingLinks) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800533 if (link.type() != Link.Type.DIRECT) {
534 continue;
535 }
536 addNeighborAtPort(link.dst().deviceId(), link.src().port());
537 }
538 }
539
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700540 protected void addNeighborAtPort(DeviceId neighborId,
541 PortNumber portToNeighbor) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800542 // Update DeviceToPort database
543 log.debug("Device {} addNeighborAtPort: neighbor {} at port {}",
544 deviceId, neighborId, portToNeighbor);
Saurav Das8a0732e2015-11-20 15:27:53 -0800545 Set<PortNumber> ports = Collections
546 .newSetFromMap(new ConcurrentHashMap<PortNumber, Boolean>());
547 ports.add(portToNeighbor);
548 Set<PortNumber> portnums = devicePortMap.putIfAbsent(neighborId, ports);
549 if (portnums != null) {
550 portnums.add(portToNeighbor);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800551 }
552
553 // Update portToDevice database
Saurav Das8a0732e2015-11-20 15:27:53 -0800554 DeviceId prev = portDeviceMap.putIfAbsent(portToNeighbor, neighborId);
555 if (prev != null) {
556 log.warn("Device: {} port: {} has neighbor: {}. NOT updating "
557 + "to neighbor: {}", deviceId, portToNeighbor, prev, neighborId);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800558 }
559 }
560
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700561 protected Set<Set<DeviceId>> getPowerSetOfNeighbors(Set<DeviceId> neighbors) {
Sho SHIMIZU6cfc02d2015-09-11 11:19:11 -0700562 List<DeviceId> list = new ArrayList<>(neighbors);
563 Set<Set<DeviceId>> sets = new HashSet<>();
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800564 // get the number of elements in the neighbors
565 int elements = list.size();
566 // the number of members of a power set is 2^n
567 // including the empty set
568 int powerElements = (1 << elements);
569
570 // run a binary counter for the number of power elements
571 // NOTE: Exclude empty set
572 for (long i = 1; i < powerElements; i++) {
Sho SHIMIZU6cfc02d2015-09-11 11:19:11 -0700573 Set<DeviceId> neighborSubSet = new HashSet<>();
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800574 for (int j = 0; j < elements; j++) {
575 if ((i >> j) % 2 == 1) {
576 neighborSubSet.add(list.get(j));
577 }
578 }
579 sets.add(neighborSubSet);
580 }
581 return sets;
582 }
583
584 private boolean isSegmentIdSameAsNodeSegmentId(DeviceId deviceId, int sId) {
Charles Chan0b4e6182015-11-03 10:42:14 -0800585 int segmentId;
586 try {
587 segmentId = deviceConfig.getSegmentId(deviceId);
588 } catch (DeviceConfigNotFoundException e) {
589 log.warn(e.getMessage() + " Aborting isSegmentIdSameAsNodeSegmentId.");
590 return false;
591 }
592
593 return segmentId == sId;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800594 }
595
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700596 protected List<Integer> getSegmentIdsTobePairedWithNeighborSet(Set<DeviceId> neighbors) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800597
Sho SHIMIZU6cfc02d2015-09-11 11:19:11 -0700598 List<Integer> nsSegmentIds = new ArrayList<>();
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800599
sanghob35a6192015-04-01 13:05:26 -0700600 // Always pair up with no edge label
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700601 // If (neighbors.size() == 1) {
sanghob35a6192015-04-01 13:05:26 -0700602 nsSegmentIds.add(-1);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700603 // }
sanghob35a6192015-04-01 13:05:26 -0700604
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800605 // Filter out SegmentIds matching with the
606 // nodes in the combo
607 for (Integer sId : allSegmentIds) {
608 if (sId.equals(nodeSegmentId)) {
609 continue;
610 }
611 boolean filterOut = false;
612 // Check if the edge label being set is of
613 // any node in the Neighbor set
614 for (DeviceId deviceId : neighbors) {
615 if (isSegmentIdSameAsNodeSegmentId(deviceId, sId)) {
616 filterOut = true;
617 break;
618 }
619 }
620 if (!filterOut) {
621 nsSegmentIds.add(sId);
622 }
623 }
624 return nsSegmentIds;
625 }
626
sangho1e575652015-05-14 00:39:53 -0700627 /**
628 * Creates Groups from a set of NeighborSet given.
629 *
630 * @param nsSet a set of NeighborSet
Saurav Das8a0732e2015-11-20 15:27:53 -0800631 * @param meta metadata passed into the creation of a Next Objective
sangho1e575652015-05-14 00:39:53 -0700632 */
Saurav Das8a0732e2015-11-20 15:27:53 -0800633 public void createGroupsFromNeighborsets(Set<NeighborSet> nsSet,
634 TrafficSelector meta) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800635 for (NeighborSet ns : nsSet) {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700636 int nextId = flowObjectiveService.allocateNextId();
637 NextObjective.Builder nextObjBuilder = DefaultNextObjective
638 .builder().withId(nextId)
639 .withType(NextObjective.Type.HASHED).fromApp(appId);
Saurav Das8a0732e2015-11-20 15:27:53 -0800640 for (DeviceId neighborId : ns.getDeviceIds()) {
641 if (devicePortMap.get(neighborId) == null) {
642 log.warn("Neighbor {} is not in the port map yet for dev:{}",
643 neighborId, deviceId);
sangho834e4b02015-05-01 09:38:25 -0700644 return;
Saurav Das8a0732e2015-11-20 15:27:53 -0800645 } else if (devicePortMap.get(neighborId).size() == 0) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700646 log.warn("There are no ports for "
Saurav Das8a0732e2015-11-20 15:27:53 -0800647 + "the Device {} in the port map yet", neighborId);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700648 return;
sangho834e4b02015-05-01 09:38:25 -0700649 }
650
Saurav Das8a0732e2015-11-20 15:27:53 -0800651 MacAddress neighborMac;
Charles Chan0b4e6182015-11-03 10:42:14 -0800652 try {
Saurav Das8a0732e2015-11-20 15:27:53 -0800653 neighborMac = deviceConfig.getDeviceMac(neighborId);
Charles Chan0b4e6182015-11-03 10:42:14 -0800654 } catch (DeviceConfigNotFoundException e) {
655 log.warn(e.getMessage() + " Aborting createGroupsFromNeighborsets.");
656 return;
657 }
658
Saurav Das8a0732e2015-11-20 15:27:53 -0800659 for (PortNumber sp : devicePortMap.get(neighborId)) {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700660 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment
661 .builder();
Saurav Das8a0732e2015-11-20 15:27:53 -0800662 tBuilder.setEthDst(neighborMac)
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700663 .setEthSrc(nodeMacAddr);
664 if (ns.getEdgeLabel() != NeighborSet.NO_EDGE_LABEL) {
Charles Chan68aa62d2015-11-09 16:37:23 -0800665 tBuilder.pushMpls()
666 .copyTtlOut()
667 .setMpls(MplsLabel.mplsLabel(ns.getEdgeLabel()));
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700668 }
Saurav Das8a0732e2015-11-20 15:27:53 -0800669 tBuilder.setOutput(sp);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700670 nextObjBuilder.addTreatment(tBuilder.build());
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800671 }
672 }
Saurav Das8a0732e2015-11-20 15:27:53 -0800673 if (meta != null) {
Saurav Das4ce45962015-11-24 23:21:05 -0800674 nextObjBuilder.withMeta(meta);
Saurav Das8a0732e2015-11-20 15:27:53 -0800675 }
Charles Chan216e3c82016-04-23 14:48:16 -0700676
677 ObjectiveContext context = new DefaultObjectiveContext(
678 (objective) -> log.debug("createGroupsFromNeighborsets installed NextObj {} on {}",
679 nextId, deviceId),
680 (objective, error) ->
681 log.warn("createGroupsFromNeighborsets failed to install NextObj {} on {}: {}",
682 nextId, deviceId, error));
683 NextObjective nextObj = nextObjBuilder.add(context);
684 log.debug("**createGroupsFromNeighborsets: Submited "
Saurav Das8a0732e2015-11-20 15:27:53 -0800685 + "next objective {} in device {}",
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700686 nextId, deviceId);
Saurav Das8a0732e2015-11-20 15:27:53 -0800687 flowObjectiveService.next(deviceId, nextObj);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700688 nsNextObjStore.put(new NeighborSetNextObjectiveStoreKey(deviceId, ns),
689 nextId);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800690 }
691 }
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700692
Saurav Das4ce45962015-11-24 23:21:05 -0800693 /**
694 * Creates broadcast groups for all ports in the same configured subnet.
Saurav Das4ce45962015-11-24 23:21:05 -0800695 */
Charles Chanc42e84e2015-10-20 16:24:19 -0700696 public void createGroupsFromSubnetConfig() {
Saurav Das7a1ffca2016-03-28 19:00:18 -0700697 Map<Ip4Prefix, List<PortNumber>> subnetPortMap;
698 try {
699 subnetPortMap = this.deviceConfig.getSubnetPortsMap(this.deviceId);
700 } catch (DeviceConfigNotFoundException e) {
701 log.warn(e.getMessage()
702 + " Not creating broadcast groups for device: " + deviceId);
703 return;
704 }
Charles Chanc42e84e2015-10-20 16:24:19 -0700705 // Construct a broadcast group for each subnet
706 subnetPortMap.forEach((subnet, ports) -> {
Charles Chan9f676b62015-10-29 14:58:10 -0700707 SubnetNextObjectiveStoreKey key =
708 new SubnetNextObjectiveStoreKey(deviceId, subnet);
709
710 if (subnetNextObjStore.containsKey(key)) {
711 log.debug("Broadcast group for device {} and subnet {} exists",
712 deviceId, subnet);
713 return;
714 }
715
Charles Chan188ebf52015-12-23 00:15:11 -0800716 VlanId assignedVlanId =
717 srManager.getSubnetAssignedVlanId(this.deviceId, subnet);
718 TrafficSelector metadata =
719 DefaultTrafficSelector.builder().matchVlanId(assignedVlanId).build();
720
Charles Chanc42e84e2015-10-20 16:24:19 -0700721 int nextId = flowObjectiveService.allocateNextId();
722
723 NextObjective.Builder nextObjBuilder = DefaultNextObjective
724 .builder().withId(nextId)
Charles Chan188ebf52015-12-23 00:15:11 -0800725 .withType(NextObjective.Type.BROADCAST).fromApp(appId)
726 .withMeta(metadata);
Charles Chanc42e84e2015-10-20 16:24:19 -0700727
728 ports.forEach(port -> {
729 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
Saurav Das4f980082015-11-05 13:39:15 -0800730 tBuilder.popVlan();
Charles Chanc42e84e2015-10-20 16:24:19 -0700731 tBuilder.setOutput(port);
732 nextObjBuilder.addTreatment(tBuilder.build());
733 });
734
735 NextObjective nextObj = nextObjBuilder.add();
736 flowObjectiveService.next(deviceId, nextObj);
737 log.debug("createGroupFromSubnetConfig: Submited "
738 + "next objective {} in device {}",
739 nextId, deviceId);
Charles Chan9f676b62015-10-29 14:58:10 -0700740
Charles Chanc42e84e2015-10-20 16:24:19 -0700741 subnetNextObjStore.put(key, nextId);
742 });
743 }
744
Charles Chane849c192016-01-11 18:28:54 -0800745 /**
746 * Creates broadcast groups for VLAN cross-connect ports.
747 *
748 * @param deviceId the DPID of the switch
749 */
750 public void createGroupsForXConnect(DeviceId deviceId) {
751 Map<VlanId, List<ConnectPoint>> xConnectsForDevice = deviceConfig.getXConnects();
752
753 xConnectsForDevice.forEach((vlanId, connectPoints) -> {
754 // Only proceed the xConnect for given device
755 for (ConnectPoint connectPoint : connectPoints) {
756 if (!connectPoint.deviceId().equals(deviceId)) {
757 return;
758 }
759 }
760
761 // Check if the next obj is already in the store
762 XConnectNextObjectiveStoreKey key =
763 new XConnectNextObjectiveStoreKey(deviceId, vlanId);
764 if (xConnectNextObjStore.containsKey(key)) {
765 log.debug("Cross-connect Broadcast group for device {} and vlanId {} exists",
766 deviceId, vlanId);
767 return;
768 }
769
770 TrafficSelector metadata =
771 DefaultTrafficSelector.builder().matchVlanId(vlanId).build();
772 int nextId = flowObjectiveService.allocateNextId();
773
774 NextObjective.Builder nextObjBuilder = DefaultNextObjective
775 .builder().withId(nextId)
776 .withType(NextObjective.Type.BROADCAST).fromApp(appId)
777 .withMeta(metadata);
778
779 connectPoints.forEach(connectPoint -> {
780 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
781 tBuilder.setOutput(connectPoint.port());
782 nextObjBuilder.addTreatment(tBuilder.build());
783 });
784
785 NextObjective nextObj = nextObjBuilder.add();
786 flowObjectiveService.next(deviceId, nextObj);
787 log.debug("createGroupsForXConnect: Submited next objective {} in device {}",
788 nextId, deviceId);
789 xConnectNextObjStore.put(key, nextId);
790 });
791 }
792
Saurav Das4ce45962015-11-24 23:21:05 -0800793
794 /**
795 * Create simple next objective for a single port. The treatments can include
796 * all outgoing actions that need to happen on the packet.
797 *
798 * @param portNum the outgoing port on the device
799 * @param treatment the actions to apply on the packets (should include outport)
800 * @param meta optional data to pass to the driver
801 */
802 public void createGroupFromPort(PortNumber portNum, TrafficTreatment treatment,
803 TrafficSelector meta) {
804 int nextId = flowObjectiveService.allocateNextId();
805 PortNextObjectiveStoreKey key = new PortNextObjectiveStoreKey(
806 deviceId, portNum, treatment);
807
808 NextObjective.Builder nextObjBuilder = DefaultNextObjective
809 .builder().withId(nextId)
810 .withType(NextObjective.Type.SIMPLE)
811 .addTreatment(treatment)
812 .fromApp(appId)
813 .withMeta(meta);
814
815 NextObjective nextObj = nextObjBuilder.add();
816 flowObjectiveService.next(deviceId, nextObj);
817 log.debug("createGroupFromPort: Submited next objective {} in device {} "
818 + "for port {}", nextId, deviceId, portNum);
819
820 portNextObjStore.put(key, nextId);
821 }
822
sangho1e575652015-05-14 00:39:53 -0700823 /**
824 * Removes groups for the next objective ID given.
825 *
826 * @param objectiveId next objective ID to remove
827 * @return true if succeeds, false otherwise
828 */
829 public boolean removeGroup(int objectiveId) {
830
831 if (nsNextObjStore.containsValue(objectiveId)) {
832 NextObjective.Builder nextObjBuilder = DefaultNextObjective
833 .builder().withId(objectiveId)
834 .withType(NextObjective.Type.HASHED).fromApp(appId);
Charles Chan216e3c82016-04-23 14:48:16 -0700835 ObjectiveContext context = new DefaultObjectiveContext(
836 (objective) -> log.debug("RemoveGroup removes NextObj {} on {}",
837 objectiveId, deviceId),
838 (objective, error) ->
839 log.warn("RemoveGroup failed to remove NextObj {} on {}: {}",
840 objectiveId, deviceId, error));
841 NextObjective nextObjective = nextObjBuilder.remove(context);
Saurav Das8a0732e2015-11-20 15:27:53 -0800842 log.info("**removeGroup: Submited "
843 + "next objective {} in device {}",
844 objectiveId, deviceId);
sangho1e575652015-05-14 00:39:53 -0700845 flowObjectiveService.next(deviceId, nextObjective);
846
847 for (Map.Entry<NeighborSetNextObjectiveStoreKey, Integer> entry: nsNextObjStore.entrySet()) {
848 if (entry.getValue().equals(objectiveId)) {
849 nsNextObjStore.remove(entry.getKey());
850 break;
851 }
852 }
sangho0b2b6d12015-05-20 22:16:38 -0700853 return true;
sangho1e575652015-05-14 00:39:53 -0700854 }
855
856 return false;
857 }
Srikanth Vavilapallif3a8bc02015-05-22 13:47:31 -0700858
Charles Chane849c192016-01-11 18:28:54 -0800859 /**
860 * Removes all groups from all next objective stores.
861 */
Saurav Das423fe2b2015-12-04 10:52:59 -0800862 public void removeAllGroups() {
863 for (Map.Entry<NeighborSetNextObjectiveStoreKey, Integer> entry:
864 nsNextObjStore.entrySet()) {
865 removeGroup(entry.getValue());
866 }
867 for (Map.Entry<PortNextObjectiveStoreKey, Integer> entry:
868 portNextObjStore.entrySet()) {
869 removeGroup(entry.getValue());
870 }
871 for (Map.Entry<SubnetNextObjectiveStoreKey, Integer> entry:
872 subnetNextObjStore.entrySet()) {
873 removeGroup(entry.getValue());
874 }
875 // should probably clean local stores port-neighbor
876 }
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800877}