blob: b76a04c2cfce7259a6f9889353619908970b661d [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;
38import org.onosproject.net.DeviceId;
39import org.onosproject.net.Link;
40import org.onosproject.net.PortNumber;
Saurav Das423fe2b2015-12-04 10:52:59 -080041import org.onosproject.net.flow.DefaultTrafficSelector;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080042import org.onosproject.net.flow.DefaultTrafficTreatment;
Saurav Das8a0732e2015-11-20 15:27:53 -080043import org.onosproject.net.flow.TrafficSelector;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080044import org.onosproject.net.flow.TrafficTreatment;
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070045import org.onosproject.net.flowobjective.DefaultNextObjective;
Charles Chan216e3c82016-04-23 14:48:16 -070046import org.onosproject.net.flowobjective.DefaultObjectiveContext;
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070047import org.onosproject.net.flowobjective.FlowObjectiveService;
48import org.onosproject.net.flowobjective.NextObjective;
Srikanth Vavilapallif3a8bc02015-05-22 13:47:31 -070049import org.onosproject.net.flowobjective.ObjectiveContext;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080050import org.onosproject.net.link.LinkService;
Saurav Das423fe2b2015-12-04 10:52:59 -080051import org.onosproject.segmentrouting.SegmentRoutingManager;
Charles Chan0b4e6182015-11-03 10:42:14 -080052import org.onosproject.segmentrouting.config.DeviceConfigNotFoundException;
53import org.onosproject.segmentrouting.config.DeviceProperties;
Charles Chand2990362016-04-18 13:44:03 -070054import org.onosproject.segmentrouting.storekey.NeighborSetNextObjectiveStoreKey;
55import org.onosproject.segmentrouting.storekey.PortNextObjectiveStoreKey;
56import org.onosproject.segmentrouting.storekey.SubnetNextObjectiveStoreKey;
Srikanth Vavilapalli23181912015-05-04 09:48:09 -070057import org.onosproject.store.service.EventuallyConsistentMap;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080058import org.slf4j.Logger;
59
60/**
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070061 * Default ECMP group handler creation module. This component creates a set of
62 * ECMP groups for every neighbor that this device is connected to based on
63 * whether the current device is an edge device or a transit device.
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080064 */
65public class DefaultGroupHandler {
Srikanth Vavilapallif3a8bc02015-05-22 13:47:31 -070066 protected static final Logger log = getLogger(DefaultGroupHandler.class);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080067
68 protected final DeviceId deviceId;
69 protected final ApplicationId appId;
70 protected final DeviceProperties deviceConfig;
71 protected final List<Integer> allSegmentIds;
Charles Chan0b4e6182015-11-03 10:42:14 -080072 protected int nodeSegmentId = -1;
73 protected boolean isEdgeRouter = false;
74 protected MacAddress nodeMacAddr = null;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080075 protected LinkService linkService;
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070076 protected FlowObjectiveService flowObjectiveService;
Saurav Das423fe2b2015-12-04 10:52:59 -080077 // local store for neighbor-device-ids and the set of ports on this device
78 // that connect to the same neighbor
Saurav Das8a0732e2015-11-20 15:27:53 -080079 protected ConcurrentHashMap<DeviceId, Set<PortNumber>> devicePortMap =
80 new ConcurrentHashMap<>();
Saurav Das1a129a02016-11-18 15:21:57 -080081 // local store for ports on this device connected to neighbor-device-id
Saurav Das8a0732e2015-11-20 15:27:53 -080082 protected ConcurrentHashMap<PortNumber, DeviceId> portDeviceMap =
83 new ConcurrentHashMap<>();
Saurav Das1a129a02016-11-18 15:21:57 -080084 // distributed store for (device+neighborset) mapped to next-id
Charles Chane849c192016-01-11 18:28:54 -080085 protected EventuallyConsistentMap<NeighborSetNextObjectiveStoreKey, Integer>
86 nsNextObjStore = null;
Saurav Das1a129a02016-11-18 15:21:57 -080087 // distributed store for (device+subnet-ip-prefix) mapped to next-id
Charles Chane849c192016-01-11 18:28:54 -080088 protected EventuallyConsistentMap<SubnetNextObjectiveStoreKey, Integer>
89 subnetNextObjStore = null;
Saurav Das1a129a02016-11-18 15:21:57 -080090 // distributed store for (device+port+treatment) mapped to next-id
Charles Chane849c192016-01-11 18:28:54 -080091 protected EventuallyConsistentMap<PortNextObjectiveStoreKey, Integer>
92 portNextObjStore = null;
Charles Chan188ebf52015-12-23 00:15:11 -080093 private SegmentRoutingManager srManager;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080094
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -070095 protected KryoNamespace.Builder kryo = new KryoNamespace.Builder()
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070096 .register(URI.class).register(HashSet.class)
97 .register(DeviceId.class).register(PortNumber.class)
98 .register(NeighborSet.class).register(PolicyGroupIdentifier.class)
99 .register(PolicyGroupParams.class)
100 .register(GroupBucketIdentifier.class)
101 .register(GroupBucketIdentifier.BucketOutputType.class);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800102
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700103 protected DefaultGroupHandler(DeviceId deviceId, ApplicationId appId,
104 DeviceProperties config,
105 LinkService linkService,
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700106 FlowObjectiveService flowObjService,
Charles Chan188ebf52015-12-23 00:15:11 -0800107 SegmentRoutingManager srManager) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800108 this.deviceId = checkNotNull(deviceId);
109 this.appId = checkNotNull(appId);
110 this.deviceConfig = checkNotNull(config);
111 this.linkService = checkNotNull(linkService);
Charles Chan0b4e6182015-11-03 10:42:14 -0800112 this.allSegmentIds = checkNotNull(config.getAllDeviceSegmentIds());
113 try {
114 this.nodeSegmentId = config.getSegmentId(deviceId);
115 this.isEdgeRouter = config.isEdgeDevice(deviceId);
116 this.nodeMacAddr = checkNotNull(config.getDeviceMac(deviceId));
117 } catch (DeviceConfigNotFoundException e) {
118 log.warn(e.getMessage()
119 + " Skipping value assignment in DefaultGroupHandler");
120 }
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700121 this.flowObjectiveService = flowObjService;
Charles Chane849c192016-01-11 18:28:54 -0800122 this.nsNextObjStore = srManager.nsNextObjStore;
123 this.subnetNextObjStore = srManager.subnetNextObjStore;
124 this.portNextObjStore = srManager.portNextObjStore;
Charles Chan188ebf52015-12-23 00:15:11 -0800125 this.srManager = srManager;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800126
127 populateNeighborMaps();
128 }
129
130 /**
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700131 * Creates a group handler object based on the type of device. If device is
132 * of edge type it returns edge group handler, else it returns transit group
133 * handler.
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800134 *
135 * @param deviceId device identifier
136 * @param appId application identifier
137 * @param config interface to retrieve the device properties
138 * @param linkService link service object
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700139 * @param flowObjService flow objective service object
Charles Chane849c192016-01-11 18:28:54 -0800140 * @param srManager segment routing manager
Charles Chan0b4e6182015-11-03 10:42:14 -0800141 * @throws DeviceConfigNotFoundException if the device configuration is not found
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800142 * @return default group handler type
143 */
Saurav Das4ce45962015-11-24 23:21:05 -0800144 public static DefaultGroupHandler createGroupHandler(
145 DeviceId deviceId,
146 ApplicationId appId,
147 DeviceProperties config,
148 LinkService linkService,
149 FlowObjectiveService flowObjService,
Charles Chan188ebf52015-12-23 00:15:11 -0800150 SegmentRoutingManager srManager)
Saurav Das4ce45962015-11-24 23:21:05 -0800151 throws DeviceConfigNotFoundException {
Charles Chan0b4e6182015-11-03 10:42:14 -0800152 // handle possible exception in the caller
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800153 if (config.isEdgeDevice(deviceId)) {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700154 return new DefaultEdgeGroupHandler(deviceId, appId, config,
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700155 linkService,
156 flowObjService,
Charles Chan188ebf52015-12-23 00:15:11 -0800157 srManager
158 );
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800159 } else {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700160 return new DefaultTransitGroupHandler(deviceId, appId, config,
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700161 linkService,
162 flowObjService,
Charles Chan188ebf52015-12-23 00:15:11 -0800163 srManager);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800164 }
165 }
166
167 /**
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700168 * Creates the auto created groups for this device based on the current
169 * snapshot of the topology.
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800170 */
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700171 // Empty implementations to be overridden by derived classes
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800172 public void createGroups() {
173 }
174
175 /**
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700176 * Performs group creation or update procedures when a new link is
177 * discovered on this device.
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800178 *
179 * @param newLink new neighbor link
Charles Chane849c192016-01-11 18:28:54 -0800180 * @param isMaster true if local instance is the master
181 *
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800182 */
Saurav Das8a0732e2015-11-20 15:27:53 -0800183 public void linkUp(Link newLink, boolean isMaster) {
sanghob35a6192015-04-01 13:05:26 -0700184
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800185 if (newLink.type() != Link.Type.DIRECT) {
186 log.warn("linkUp: unknown link type");
187 return;
188 }
189
190 if (!newLink.src().deviceId().equals(deviceId)) {
191 log.warn("linkUp: deviceId{} doesn't match with link src{}",
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700192 deviceId, newLink.src().deviceId());
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800193 return;
194 }
195
Saurav Das8a0732e2015-11-20 15:27:53 -0800196 log.info("* LinkUP: Device {} linkUp at local port {} to neighbor {}", deviceId,
197 newLink.src().port(), newLink.dst().deviceId());
Saurav Das59232cf2016-04-27 18:35:50 -0700198 // ensure local state is updated even if linkup is aborted later on
199 addNeighborAtPort(newLink.dst().deviceId(),
200 newLink.src().port());
201
Charles Chan0b4e6182015-11-03 10:42:14 -0800202 MacAddress dstMac;
203 try {
204 dstMac = deviceConfig.getDeviceMac(newLink.dst().deviceId());
205 } catch (DeviceConfigNotFoundException e) {
206 log.warn(e.getMessage() + " Aborting linkUp.");
207 return;
208 }
209
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700210 /*if (devicePortMap.get(newLink.dst().deviceId()) == null) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800211 // New Neighbor
212 newNeighbor(newLink);
213 } else {
214 // Old Neighbor
215 newPortToExistingNeighbor(newLink);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700216 }*/
217 Set<NeighborSet> nsSet = nsNextObjStore.keySet()
218 .stream()
219 .filter((nsStoreEntry) -> (nsStoreEntry.deviceId().equals(deviceId)))
220 .map((nsStoreEntry) -> (nsStoreEntry.neighborSet()))
221 .filter((ns) -> (ns.getDeviceIds()
222 .contains(newLink.dst().deviceId())))
223 .collect(Collectors.toSet());
224 log.trace("linkUp: nsNextObjStore contents for device {}:",
sangho0b2b6d12015-05-20 22:16:38 -0700225 deviceId,
226 nsSet);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700227 for (NeighborSet ns : nsSet) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700228 Integer nextId = nsNextObjStore.
229 get(new NeighborSetNextObjectiveStoreKey(deviceId, ns));
Saurav Das4ce45962015-11-24 23:21:05 -0800230 if (nextId != null && isMaster) {
Saurav Das423fe2b2015-12-04 10:52:59 -0800231 // Create the new bucket to be updated
232 TrafficTreatment.Builder tBuilder =
233 DefaultTrafficTreatment.builder();
234 tBuilder.setOutput(newLink.src().port())
235 .setEthDst(dstMac)
236 .setEthSrc(nodeMacAddr);
237 if (ns.getEdgeLabel() != NeighborSet.NO_EDGE_LABEL) {
238 tBuilder.pushMpls()
239 .copyTtlOut()
240 .setMpls(MplsLabel.mplsLabel(ns.getEdgeLabel()));
241 }
242 // setup metadata to pass to nextObjective - indicate the vlan on egress
243 // if needed by the switch pipeline. Since hashed next-hops are always to
244 // other neighboring routers, there is no subnet assigned on those ports.
245 TrafficSelector.Builder metabuilder = DefaultTrafficSelector.builder();
246 metabuilder.matchVlanId(
247 VlanId.vlanId(SegmentRoutingManager.ASSIGNED_VLAN_NO_SUBNET));
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700248
Saurav Das423fe2b2015-12-04 10:52:59 -0800249 NextObjective.Builder nextObjBuilder = DefaultNextObjective.builder()
250 .withId(nextId)
251 .withType(NextObjective.Type.HASHED)
252 .addTreatment(tBuilder.build())
253 .withMeta(metabuilder.build())
254 .fromApp(appId);
Saurav Das8a0732e2015-11-20 15:27:53 -0800255 log.info("**linkUp in device {}: Adding Bucket "
Saurav Das4ce45962015-11-24 23:21:05 -0800256 + "with Port {} to next object id {}",
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700257 deviceId,
258 newLink.src().port(),
Saurav Das4ce45962015-11-24 23:21:05 -0800259 nextId);
Charles Chan216e3c82016-04-23 14:48:16 -0700260
261 ObjectiveContext context = new DefaultObjectiveContext(
Saurav Das1ce0a7b2016-10-21 14:06:29 -0700262 (objective) -> log.debug("LinkUp addedTo NextObj {} on {}",
Charles Chan216e3c82016-04-23 14:48:16 -0700263 nextId, deviceId),
264 (objective, error) ->
Saurav Das1ce0a7b2016-10-21 14:06:29 -0700265 log.warn("LinkUp failed to addTo NextObj {} on {}: {}",
Charles Chan216e3c82016-04-23 14:48:16 -0700266 nextId, deviceId, error));
267 NextObjective nextObjective = nextObjBuilder.addToExisting(context);
Saurav Das4ce45962015-11-24 23:21:05 -0800268 flowObjectiveService.next(deviceId, nextObjective);
269 } else if (isMaster) {
Saurav Das8a0732e2015-11-20 15:27:53 -0800270 log.warn("linkUp in device {}, but global store has no record "
271 + "for neighbor-set {}", deviceId, ns);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700272 }
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800273 }
274 }
275
276 /**
Saurav Das1a129a02016-11-18 15:21:57 -0800277 * Performs hash group recovery procedures when a switch-to-switch
278 * port goes down on this device.
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800279 *
280 * @param port port number that has gone down
Charles Chane849c192016-01-11 18:28:54 -0800281 * @param isMaster true if local instance is the master
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800282 */
Saurav Das423fe2b2015-12-04 10:52:59 -0800283 public void portDown(PortNumber port, boolean isMaster) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800284 if (portDeviceMap.get(port) == null) {
285 log.warn("portDown: unknown port");
286 return;
287 }
Charles Chan0b4e6182015-11-03 10:42:14 -0800288
289 MacAddress dstMac;
290 try {
291 dstMac = deviceConfig.getDeviceMac(portDeviceMap.get(port));
292 } catch (DeviceConfigNotFoundException e) {
293 log.warn(e.getMessage() + " Aborting portDown.");
294 return;
295 }
296
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700297 log.debug("Device {} portDown {} to neighbor {}", deviceId, port,
298 portDeviceMap.get(port));
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700299 /*Set<NeighborSet> nsSet = computeImpactedNeighborsetForPortEvent(portDeviceMap
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700300 .get(port),
301 devicePortMap
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700302 .keySet());*/
303 Set<NeighborSet> nsSet = nsNextObjStore.keySet()
304 .stream()
305 .filter((nsStoreEntry) -> (nsStoreEntry.deviceId().equals(deviceId)))
306 .map((nsStoreEntry) -> (nsStoreEntry.neighborSet()))
307 .filter((ns) -> (ns.getDeviceIds()
308 .contains(portDeviceMap.get(port))))
309 .collect(Collectors.toSet());
Saurav Das423fe2b2015-12-04 10:52:59 -0800310 log.debug("portDown: nsNextObjStore contents for device {}:{}",
311 deviceId, nsSet);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800312 for (NeighborSet ns : nsSet) {
Saurav Das80980c72016-03-23 11:22:49 -0700313 NeighborSetNextObjectiveStoreKey nsStoreKey =
314 new NeighborSetNextObjectiveStoreKey(deviceId, ns);
315 Integer nextId = nsNextObjStore.get(nsStoreKey);
Saurav Das423fe2b2015-12-04 10:52:59 -0800316 if (nextId != null && isMaster) {
Saurav Das8a0732e2015-11-20 15:27:53 -0800317 log.info("**portDown in device {}: Removing Bucket "
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700318 + "with Port {} to next object id {}",
319 deviceId,
320 port,
321 nextId);
Saurav Das423fe2b2015-12-04 10:52:59 -0800322 // Create the bucket to be removed
323 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment
324 .builder();
325 tBuilder.setOutput(port)
326 .setEthDst(dstMac)
327 .setEthSrc(nodeMacAddr);
328 if (ns.getEdgeLabel() != NeighborSet.NO_EDGE_LABEL) {
329 tBuilder.pushMpls()
330 .copyTtlOut()
331 .setMpls(MplsLabel.mplsLabel(ns.getEdgeLabel()));
332 }
333 NextObjective.Builder nextObjBuilder = DefaultNextObjective
334 .builder()
335 .withType(NextObjective.Type.HASHED) //same as original
336 .withId(nextId)
337 .fromApp(appId)
338 .addTreatment(tBuilder.build());
Saurav Das1ce0a7b2016-10-21 14:06:29 -0700339 ObjectiveContext context = new DefaultObjectiveContext(
340 (objective) -> log.debug("portDown removedFrom NextObj {} on {}",
341 nextId, deviceId),
342 (objective, error) ->
343 log.warn("portDown failed to removeFrom NextObj {} on {}: {}",
344 nextId, deviceId, error));
Saurav Das423fe2b2015-12-04 10:52:59 -0800345 NextObjective nextObjective = nextObjBuilder.
Saurav Das1ce0a7b2016-10-21 14:06:29 -0700346 removeFromExisting(context);
sangho834e4b02015-05-01 09:38:25 -0700347
Saurav Das423fe2b2015-12-04 10:52:59 -0800348 flowObjectiveService.next(deviceId, nextObjective);
sangho834e4b02015-05-01 09:38:25 -0700349 }
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800350 }
351
352 devicePortMap.get(portDeviceMap.get(port)).remove(port);
353 portDeviceMap.remove(port);
354 }
355
356 /**
Saurav Das1a129a02016-11-18 15:21:57 -0800357 * Adds or removes a port that has been configured with a subnet to a broadcast group
358 * for bridging. Note that this does not create the broadcast group itself.
359 *
360 * @param port the port on this device that needs to be added/removed to a bcast group
361 * @param subnet the subnet corresponding to the broadcast group
362 * @param portUp true if port is enabled, false if disabled
363 * @param isMaster true if local instance is the master
364 */
365 public void processEdgePort(PortNumber port, Ip4Prefix subnet,
366 boolean portUp, boolean isMaster) {
367 if (!isMaster) {
368 return;
369 }
370 //get the next id for the subnet and edit it.
371 Integer nextId = getSubnetNextObjectiveId(subnet);
372 if (nextId == -1) {
373 if (portUp) {
374 log.debug("**Creating flooding group for first port enabled in"
375 + " subnet {} on dev {} port {}", subnet, deviceId, port);
376 createBcastGroupFromSubnet(subnet, Collections.singletonList(port));
377 } else {
378 log.warn("Could not find flooding group for subnet {} on dev:{} when"
379 + " removing port:{}", subnet, deviceId, port);
380 }
381 return;
382 }
383
384 log.info("**port{} in device {}: {} Bucket with Port {} to"
385 + " next-id {}", (portUp) ? "UP" : "DOWN", deviceId,
386 (portUp) ? "Adding" : "Removing",
387 port, nextId);
388 // Create the bucket to be added or removed
389 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
390 tBuilder.popVlan();
391 tBuilder.setOutput(port);
392
393 VlanId assignedVlanId =
394 srManager.getSubnetAssignedVlanId(this.deviceId, subnet);
395 TrafficSelector metadata =
396 DefaultTrafficSelector.builder().matchVlanId(assignedVlanId).build();
397
398 NextObjective.Builder nextObjBuilder = DefaultNextObjective
399 .builder().withId(nextId)
400 .withType(NextObjective.Type.BROADCAST).fromApp(appId)
401 .addTreatment(tBuilder.build())
402 .withMeta(metadata);
403
404 ObjectiveContext context = new DefaultObjectiveContext(
405 (objective) -> log.debug("port {} successfully {} NextObj {} on {}",
406 port, (portUp) ? "addedTo" : "removedFrom",
407 nextId, deviceId),
408 (objective, error) ->
409 log.warn("port {} failed to {} NextObj {} on {}: {}",
410 port, (portUp) ? "addTo" : "removeFrom",
411 nextId, deviceId, error));
412
413 NextObjective nextObj = (portUp) ? nextObjBuilder.addToExisting(context)
414 : nextObjBuilder.removeFromExisting(context);
415 log.debug("edgePort processed: Submited next objective {} in device {}",
416 nextId, deviceId);
417 flowObjectiveService.next(deviceId, nextObj);
418 }
419
420 /**
Saurav Das4ce45962015-11-24 23:21:05 -0800421 * Returns the next objective of type hashed associated with the neighborset.
422 * If there is no next objective for this neighborset, this method
Saurav Das8a0732e2015-11-20 15:27:53 -0800423 * would create a next objective and return. Optionally metadata can be
424 * passed in for the creation of the next objective.
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800425 *
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700426 * @param ns neighborset
Saurav Das8a0732e2015-11-20 15:27:53 -0800427 * @param meta metadata passed into the creation of a Next Objective
428 * @return int if found or -1 if there are errors in the creation of the
429 * neighbor set.
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800430 */
Saurav Das8a0732e2015-11-20 15:27:53 -0800431 public int getNextObjectiveId(NeighborSet ns, TrafficSelector meta) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700432 Integer nextId = nsNextObjStore.
433 get(new NeighborSetNextObjectiveStoreKey(deviceId, ns));
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700434 if (nextId == null) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700435 log.trace("getNextObjectiveId in device{}: Next objective id "
436 + "not found for {} and creating", deviceId, ns);
437 log.trace("getNextObjectiveId: nsNextObjStore contents for device {}: {}",
438 deviceId,
439 nsNextObjStore.entrySet()
440 .stream()
441 .filter((nsStoreEntry) ->
442 (nsStoreEntry.getKey().deviceId().equals(deviceId)))
443 .collect(Collectors.toList()));
Saurav Das8a0732e2015-11-20 15:27:53 -0800444 createGroupsFromNeighborsets(Collections.singleton(ns), meta);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700445 nextId = nsNextObjStore.
446 get(new NeighborSetNextObjectiveStoreKey(deviceId, ns));
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700447 if (nextId == null) {
448 log.warn("getNextObjectiveId: unable to create next objective");
449 return -1;
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700450 } else {
451 log.debug("getNextObjectiveId in device{}: Next objective id {} "
Sho SHIMIZUaf973432015-09-11 14:24:50 -0700452 + "created for {}", deviceId, nextId, ns);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700453 }
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700454 } else {
455 log.trace("getNextObjectiveId in device{}: Next objective id {} "
Sho SHIMIZUaf973432015-09-11 14:24:50 -0700456 + "found for {}", deviceId, nextId, ns);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700457 }
Sho SHIMIZUaf973432015-09-11 14:24:50 -0700458 return nextId;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800459 }
460
sangho0b2b6d12015-05-20 22:16:38 -0700461 /**
Saurav Das4ce45962015-11-24 23:21:05 -0800462 * Returns the next objective of type broadcast associated with the subnet,
463 * or -1 if no such objective exists. Note that this method does NOT create
464 * the next objective as a side-effect. It is expected that is objective is
Saurav Das1a129a02016-11-18 15:21:57 -0800465 * created at startup from network configuration. Typically this is used
466 * for L2 flooding within the subnet configured on the switch.
Charles Chanc42e84e2015-10-20 16:24:19 -0700467 *
468 * @param prefix subnet information
469 * @return int if found or -1
470 */
471 public int getSubnetNextObjectiveId(IpPrefix prefix) {
472 Integer nextId = subnetNextObjStore.
473 get(new SubnetNextObjectiveStoreKey(deviceId, prefix));
Charles Chan9f676b62015-10-29 14:58:10 -0700474
475 return (nextId != null) ? nextId : -1;
Charles Chanc42e84e2015-10-20 16:24:19 -0700476 }
477
478 /**
Saurav Das4ce45962015-11-24 23:21:05 -0800479 * Returns the next objective of type simple associated with the port on the
480 * device, given the treatment. Different treatments to the same port result
481 * in different next objectives. If no such objective exists, this method
482 * creates one and returns the id. Optionally metadata can be passed in for
Saurav Das1a129a02016-11-18 15:21:57 -0800483 * the creation of the objective. Typically this is used for L2 and L3 forwarding
484 * to compute nodes and containers/VMs on the compute nodes directly attached
485 * to the switch.
Saurav Das4ce45962015-11-24 23:21:05 -0800486 *
487 * @param portNum the port number for the simple next objective
488 * @param treatment the actions to apply on the packets (should include outport)
489 * @param meta optional metadata passed into the creation of the next objective
490 * @return int if found or created, -1 if there are errors during the
491 * creation of the next objective.
492 */
493 public int getPortNextObjectiveId(PortNumber portNum, TrafficTreatment treatment,
494 TrafficSelector meta) {
Charles Chane849c192016-01-11 18:28:54 -0800495 Integer nextId = portNextObjStore
496 .get(new PortNextObjectiveStoreKey(deviceId, portNum, treatment));
Saurav Das4ce45962015-11-24 23:21:05 -0800497 if (nextId == null) {
498 log.trace("getPortNextObjectiveId in device{}: Next objective id "
499 + "not found for {} and {} creating", deviceId, portNum);
500 createGroupFromPort(portNum, treatment, meta);
501 nextId = portNextObjStore.get(
502 new PortNextObjectiveStoreKey(deviceId, portNum, treatment));
503 if (nextId == null) {
504 log.warn("getPortNextObjectiveId: unable to create next obj"
Charles Chane849c192016-01-11 18:28:54 -0800505 + "for dev:{} port:{}", deviceId, portNum);
506 return -1;
507 }
508 }
509 return nextId;
510 }
511
512 /**
sangho0b2b6d12015-05-20 22:16:38 -0700513 * Checks if the next objective ID (group) for the neighbor set exists or not.
514 *
515 * @param ns neighbor set to check
516 * @return true if it exists, false otherwise
517 */
518 public boolean hasNextObjectiveId(NeighborSet ns) {
519 Integer nextId = nsNextObjStore.
520 get(new NeighborSetNextObjectiveStoreKey(deviceId, ns));
521 if (nextId == null) {
522 return false;
523 }
524
525 return true;
526 }
527
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700528 // Empty implementation
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800529 protected void newNeighbor(Link newLink) {
530 }
531
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700532 // Empty implementation
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800533 protected void newPortToExistingNeighbor(Link newLink) {
534 }
535
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700536 // Empty implementation
537 protected Set<NeighborSet>
538 computeImpactedNeighborsetForPortEvent(DeviceId impactedNeighbor,
539 Set<DeviceId> updatedNeighbors) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800540 return null;
541 }
542
543 private void populateNeighborMaps() {
544 Set<Link> outgoingLinks = linkService.getDeviceEgressLinks(deviceId);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700545 for (Link link : outgoingLinks) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800546 if (link.type() != Link.Type.DIRECT) {
547 continue;
548 }
549 addNeighborAtPort(link.dst().deviceId(), link.src().port());
550 }
551 }
552
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700553 protected void addNeighborAtPort(DeviceId neighborId,
554 PortNumber portToNeighbor) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800555 // Update DeviceToPort database
556 log.debug("Device {} addNeighborAtPort: neighbor {} at port {}",
557 deviceId, neighborId, portToNeighbor);
Saurav Das8a0732e2015-11-20 15:27:53 -0800558 Set<PortNumber> ports = Collections
559 .newSetFromMap(new ConcurrentHashMap<PortNumber, Boolean>());
560 ports.add(portToNeighbor);
561 Set<PortNumber> portnums = devicePortMap.putIfAbsent(neighborId, ports);
562 if (portnums != null) {
563 portnums.add(portToNeighbor);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800564 }
565
566 // Update portToDevice database
Saurav Das8a0732e2015-11-20 15:27:53 -0800567 DeviceId prev = portDeviceMap.putIfAbsent(portToNeighbor, neighborId);
568 if (prev != null) {
569 log.warn("Device: {} port: {} has neighbor: {}. NOT updating "
570 + "to neighbor: {}", deviceId, portToNeighbor, prev, neighborId);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800571 }
572 }
573
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700574 protected Set<Set<DeviceId>> getPowerSetOfNeighbors(Set<DeviceId> neighbors) {
Sho SHIMIZU6cfc02d2015-09-11 11:19:11 -0700575 List<DeviceId> list = new ArrayList<>(neighbors);
576 Set<Set<DeviceId>> sets = new HashSet<>();
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800577 // get the number of elements in the neighbors
578 int elements = list.size();
579 // the number of members of a power set is 2^n
580 // including the empty set
581 int powerElements = (1 << elements);
582
583 // run a binary counter for the number of power elements
584 // NOTE: Exclude empty set
585 for (long i = 1; i < powerElements; i++) {
Sho SHIMIZU6cfc02d2015-09-11 11:19:11 -0700586 Set<DeviceId> neighborSubSet = new HashSet<>();
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800587 for (int j = 0; j < elements; j++) {
588 if ((i >> j) % 2 == 1) {
589 neighborSubSet.add(list.get(j));
590 }
591 }
592 sets.add(neighborSubSet);
593 }
594 return sets;
595 }
596
597 private boolean isSegmentIdSameAsNodeSegmentId(DeviceId deviceId, int sId) {
Charles Chan0b4e6182015-11-03 10:42:14 -0800598 int segmentId;
599 try {
600 segmentId = deviceConfig.getSegmentId(deviceId);
601 } catch (DeviceConfigNotFoundException e) {
602 log.warn(e.getMessage() + " Aborting isSegmentIdSameAsNodeSegmentId.");
603 return false;
604 }
605
606 return segmentId == sId;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800607 }
608
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700609 protected List<Integer> getSegmentIdsTobePairedWithNeighborSet(Set<DeviceId> neighbors) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800610
Sho SHIMIZU6cfc02d2015-09-11 11:19:11 -0700611 List<Integer> nsSegmentIds = new ArrayList<>();
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800612
sanghob35a6192015-04-01 13:05:26 -0700613 // Always pair up with no edge label
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700614 // If (neighbors.size() == 1) {
sanghob35a6192015-04-01 13:05:26 -0700615 nsSegmentIds.add(-1);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700616 // }
sanghob35a6192015-04-01 13:05:26 -0700617
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800618 // Filter out SegmentIds matching with the
619 // nodes in the combo
620 for (Integer sId : allSegmentIds) {
621 if (sId.equals(nodeSegmentId)) {
622 continue;
623 }
624 boolean filterOut = false;
625 // Check if the edge label being set is of
626 // any node in the Neighbor set
627 for (DeviceId deviceId : neighbors) {
628 if (isSegmentIdSameAsNodeSegmentId(deviceId, sId)) {
629 filterOut = true;
630 break;
631 }
632 }
633 if (!filterOut) {
634 nsSegmentIds.add(sId);
635 }
636 }
637 return nsSegmentIds;
638 }
639
sangho1e575652015-05-14 00:39:53 -0700640 /**
Saurav Das1a129a02016-11-18 15:21:57 -0800641 * Creates hash groups from a set of NeighborSet given.
sangho1e575652015-05-14 00:39:53 -0700642 *
643 * @param nsSet a set of NeighborSet
Saurav Das8a0732e2015-11-20 15:27:53 -0800644 * @param meta metadata passed into the creation of a Next Objective
sangho1e575652015-05-14 00:39:53 -0700645 */
Saurav Das8a0732e2015-11-20 15:27:53 -0800646 public void createGroupsFromNeighborsets(Set<NeighborSet> nsSet,
647 TrafficSelector meta) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800648 for (NeighborSet ns : nsSet) {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700649 int nextId = flowObjectiveService.allocateNextId();
650 NextObjective.Builder nextObjBuilder = DefaultNextObjective
651 .builder().withId(nextId)
652 .withType(NextObjective.Type.HASHED).fromApp(appId);
Saurav Das8a0732e2015-11-20 15:27:53 -0800653 for (DeviceId neighborId : ns.getDeviceIds()) {
654 if (devicePortMap.get(neighborId) == null) {
655 log.warn("Neighbor {} is not in the port map yet for dev:{}",
656 neighborId, deviceId);
sangho834e4b02015-05-01 09:38:25 -0700657 return;
Jon Hallcbd1b392017-01-18 20:15:44 -0800658 } else if (devicePortMap.get(neighborId).isEmpty()) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700659 log.warn("There are no ports for "
Saurav Das8a0732e2015-11-20 15:27:53 -0800660 + "the Device {} in the port map yet", neighborId);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700661 return;
sangho834e4b02015-05-01 09:38:25 -0700662 }
663
Saurav Das8a0732e2015-11-20 15:27:53 -0800664 MacAddress neighborMac;
Charles Chan0b4e6182015-11-03 10:42:14 -0800665 try {
Saurav Das8a0732e2015-11-20 15:27:53 -0800666 neighborMac = deviceConfig.getDeviceMac(neighborId);
Charles Chan0b4e6182015-11-03 10:42:14 -0800667 } catch (DeviceConfigNotFoundException e) {
668 log.warn(e.getMessage() + " Aborting createGroupsFromNeighborsets.");
669 return;
670 }
671
Saurav Das8a0732e2015-11-20 15:27:53 -0800672 for (PortNumber sp : devicePortMap.get(neighborId)) {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700673 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment
674 .builder();
Saurav Das8a0732e2015-11-20 15:27:53 -0800675 tBuilder.setEthDst(neighborMac)
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700676 .setEthSrc(nodeMacAddr);
677 if (ns.getEdgeLabel() != NeighborSet.NO_EDGE_LABEL) {
Charles Chan68aa62d2015-11-09 16:37:23 -0800678 tBuilder.pushMpls()
679 .copyTtlOut()
680 .setMpls(MplsLabel.mplsLabel(ns.getEdgeLabel()));
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700681 }
Saurav Das8a0732e2015-11-20 15:27:53 -0800682 tBuilder.setOutput(sp);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700683 nextObjBuilder.addTreatment(tBuilder.build());
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800684 }
685 }
Saurav Das8a0732e2015-11-20 15:27:53 -0800686 if (meta != null) {
Saurav Das4ce45962015-11-24 23:21:05 -0800687 nextObjBuilder.withMeta(meta);
Saurav Das8a0732e2015-11-20 15:27:53 -0800688 }
Charles Chan216e3c82016-04-23 14:48:16 -0700689
690 ObjectiveContext context = new DefaultObjectiveContext(
691 (objective) -> log.debug("createGroupsFromNeighborsets installed NextObj {} on {}",
692 nextId, deviceId),
693 (objective, error) ->
694 log.warn("createGroupsFromNeighborsets failed to install NextObj {} on {}: {}",
695 nextId, deviceId, error));
696 NextObjective nextObj = nextObjBuilder.add(context);
697 log.debug("**createGroupsFromNeighborsets: Submited "
Saurav Das8a0732e2015-11-20 15:27:53 -0800698 + "next objective {} in device {}",
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700699 nextId, deviceId);
Saurav Das8a0732e2015-11-20 15:27:53 -0800700 flowObjectiveService.next(deviceId, nextObj);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700701 nsNextObjStore.put(new NeighborSetNextObjectiveStoreKey(deviceId, ns),
702 nextId);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800703 }
704 }
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700705
Saurav Das4ce45962015-11-24 23:21:05 -0800706 /**
Saurav Das1a129a02016-11-18 15:21:57 -0800707 * Creates broadcast groups for all ports in the same subnet for
708 * all configured subnets.
Saurav Das4ce45962015-11-24 23:21:05 -0800709 */
Charles Chanc42e84e2015-10-20 16:24:19 -0700710 public void createGroupsFromSubnetConfig() {
Saurav Das7a1ffca2016-03-28 19:00:18 -0700711 Map<Ip4Prefix, List<PortNumber>> subnetPortMap;
712 try {
713 subnetPortMap = this.deviceConfig.getSubnetPortsMap(this.deviceId);
714 } catch (DeviceConfigNotFoundException e) {
715 log.warn(e.getMessage()
716 + " Not creating broadcast groups for device: " + deviceId);
717 return;
718 }
Charles Chanc42e84e2015-10-20 16:24:19 -0700719 // Construct a broadcast group for each subnet
Saurav Das1a129a02016-11-18 15:21:57 -0800720 subnetPortMap.forEach((subnet, ports) -> createBcastGroupFromSubnet(subnet, ports));
721 }
Charles Chan9f676b62015-10-29 14:58:10 -0700722
Saurav Das1a129a02016-11-18 15:21:57 -0800723 /**
724 * Creates a single broadcast group from a given subnet and list of ports.
725 *
726 * @param subnet a configured subnet
727 * @param ports list of ports in the subnet
728 */
729 public void createBcastGroupFromSubnet(Ip4Prefix subnet, List<PortNumber> ports) {
730 SubnetNextObjectiveStoreKey key =
731 new SubnetNextObjectiveStoreKey(deviceId, subnet);
Charles Chan9f676b62015-10-29 14:58:10 -0700732
Saurav Das1a129a02016-11-18 15:21:57 -0800733 if (subnetNextObjStore.containsKey(key)) {
734 log.debug("Broadcast group for device {} and subnet {} exists",
735 deviceId, subnet);
736 return;
737 }
Charles Chan188ebf52015-12-23 00:15:11 -0800738
Saurav Das1a129a02016-11-18 15:21:57 -0800739 VlanId assignedVlanId =
740 srManager.getSubnetAssignedVlanId(this.deviceId, subnet);
741 TrafficSelector metadata =
742 DefaultTrafficSelector.builder().matchVlanId(assignedVlanId).build();
Charles Chanc42e84e2015-10-20 16:24:19 -0700743
Saurav Das1a129a02016-11-18 15:21:57 -0800744 int nextId = flowObjectiveService.allocateNextId();
Charles Chanc42e84e2015-10-20 16:24:19 -0700745
Saurav Das1a129a02016-11-18 15:21:57 -0800746 NextObjective.Builder nextObjBuilder = DefaultNextObjective
747 .builder().withId(nextId)
748 .withType(NextObjective.Type.BROADCAST).fromApp(appId)
749 .withMeta(metadata);
Charles Chanc42e84e2015-10-20 16:24:19 -0700750
Saurav Das1a129a02016-11-18 15:21:57 -0800751 ports.forEach(port -> {
752 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
753 tBuilder.popVlan();
754 tBuilder.setOutput(port);
755 nextObjBuilder.addTreatment(tBuilder.build());
Charles Chanc42e84e2015-10-20 16:24:19 -0700756 });
Saurav Das1a129a02016-11-18 15:21:57 -0800757
758 NextObjective nextObj = nextObjBuilder.add();
759 flowObjectiveService.next(deviceId, nextObj);
760 log.debug("createBcastGroupFromSubnet: Submited next objective {} in device {}",
761 nextId, deviceId);
762
763 subnetNextObjStore.put(key, nextId);
Charles Chanc42e84e2015-10-20 16:24:19 -0700764 }
765
Charles Chane849c192016-01-11 18:28:54 -0800766 /**
Saurav Das4ce45962015-11-24 23:21:05 -0800767 * Create simple next objective for a single port. The treatments can include
768 * all outgoing actions that need to happen on the packet.
769 *
770 * @param portNum the outgoing port on the device
771 * @param treatment the actions to apply on the packets (should include outport)
772 * @param meta optional data to pass to the driver
773 */
774 public void createGroupFromPort(PortNumber portNum, TrafficTreatment treatment,
775 TrafficSelector meta) {
776 int nextId = flowObjectiveService.allocateNextId();
777 PortNextObjectiveStoreKey key = new PortNextObjectiveStoreKey(
778 deviceId, portNum, treatment);
779
780 NextObjective.Builder nextObjBuilder = DefaultNextObjective
781 .builder().withId(nextId)
782 .withType(NextObjective.Type.SIMPLE)
783 .addTreatment(treatment)
784 .fromApp(appId)
785 .withMeta(meta);
786
787 NextObjective nextObj = nextObjBuilder.add();
788 flowObjectiveService.next(deviceId, nextObj);
789 log.debug("createGroupFromPort: Submited next objective {} in device {} "
790 + "for port {}", nextId, deviceId, portNum);
791
792 portNextObjStore.put(key, nextId);
793 }
794
sangho1e575652015-05-14 00:39:53 -0700795 /**
796 * Removes groups for the next objective ID given.
797 *
798 * @param objectiveId next objective ID to remove
799 * @return true if succeeds, false otherwise
800 */
801 public boolean removeGroup(int objectiveId) {
802
803 if (nsNextObjStore.containsValue(objectiveId)) {
804 NextObjective.Builder nextObjBuilder = DefaultNextObjective
805 .builder().withId(objectiveId)
806 .withType(NextObjective.Type.HASHED).fromApp(appId);
Charles Chan216e3c82016-04-23 14:48:16 -0700807 ObjectiveContext context = new DefaultObjectiveContext(
808 (objective) -> log.debug("RemoveGroup removes NextObj {} on {}",
809 objectiveId, deviceId),
810 (objective, error) ->
811 log.warn("RemoveGroup failed to remove NextObj {} on {}: {}",
812 objectiveId, deviceId, error));
813 NextObjective nextObjective = nextObjBuilder.remove(context);
Saurav Das8a0732e2015-11-20 15:27:53 -0800814 log.info("**removeGroup: Submited "
815 + "next objective {} in device {}",
816 objectiveId, deviceId);
sangho1e575652015-05-14 00:39:53 -0700817 flowObjectiveService.next(deviceId, nextObjective);
818
819 for (Map.Entry<NeighborSetNextObjectiveStoreKey, Integer> entry: nsNextObjStore.entrySet()) {
820 if (entry.getValue().equals(objectiveId)) {
821 nsNextObjStore.remove(entry.getKey());
822 break;
823 }
824 }
sangho0b2b6d12015-05-20 22:16:38 -0700825 return true;
sangho1e575652015-05-14 00:39:53 -0700826 }
827
828 return false;
829 }
Srikanth Vavilapallif3a8bc02015-05-22 13:47:31 -0700830
Charles Chane849c192016-01-11 18:28:54 -0800831 /**
832 * Removes all groups from all next objective stores.
833 */
Saurav Das423fe2b2015-12-04 10:52:59 -0800834 public void removeAllGroups() {
835 for (Map.Entry<NeighborSetNextObjectiveStoreKey, Integer> entry:
836 nsNextObjStore.entrySet()) {
837 removeGroup(entry.getValue());
838 }
839 for (Map.Entry<PortNextObjectiveStoreKey, Integer> entry:
840 portNextObjStore.entrySet()) {
841 removeGroup(entry.getValue());
842 }
843 for (Map.Entry<SubnetNextObjectiveStoreKey, Integer> entry:
844 subnetNextObjStore.entrySet()) {
845 removeGroup(entry.getValue());
846 }
847 // should probably clean local stores port-neighbor
848 }
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800849}