blob: d9437105562686495b171be445bfa2c028350664 [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;
Pier Ventree0ae7a32016-11-23 09:57:42 -080072 protected int ipv4NodeSegmentId = -1;
73 protected int ipv6NodeSegmentId = -1;
Charles Chan0b4e6182015-11-03 10:42:14 -080074 protected boolean isEdgeRouter = false;
75 protected MacAddress nodeMacAddr = null;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080076 protected LinkService linkService;
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070077 protected FlowObjectiveService flowObjectiveService;
Saurav Das423fe2b2015-12-04 10:52:59 -080078 // local store for neighbor-device-ids and the set of ports on this device
79 // that connect to the same neighbor
Saurav Das8a0732e2015-11-20 15:27:53 -080080 protected ConcurrentHashMap<DeviceId, Set<PortNumber>> devicePortMap =
81 new ConcurrentHashMap<>();
Saurav Das1a129a02016-11-18 15:21:57 -080082 // local store for ports on this device connected to neighbor-device-id
Saurav Das8a0732e2015-11-20 15:27:53 -080083 protected ConcurrentHashMap<PortNumber, DeviceId> portDeviceMap =
84 new ConcurrentHashMap<>();
Saurav Das1a129a02016-11-18 15:21:57 -080085 // distributed store for (device+neighborset) mapped to next-id
Charles Chane849c192016-01-11 18:28:54 -080086 protected EventuallyConsistentMap<NeighborSetNextObjectiveStoreKey, Integer>
87 nsNextObjStore = null;
Saurav Das1a129a02016-11-18 15:21:57 -080088 // distributed store for (device+subnet-ip-prefix) mapped to next-id
Charles Chane849c192016-01-11 18:28:54 -080089 protected EventuallyConsistentMap<SubnetNextObjectiveStoreKey, Integer>
90 subnetNextObjStore = null;
Saurav Das1a129a02016-11-18 15:21:57 -080091 // distributed store for (device+port+treatment) mapped to next-id
Charles Chane849c192016-01-11 18:28:54 -080092 protected EventuallyConsistentMap<PortNextObjectiveStoreKey, Integer>
93 portNextObjStore = 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 {
Pier Ventree0ae7a32016-11-23 09:57:42 -0800115 this.ipv4NodeSegmentId = config.getIPv4SegmentId(deviceId);
116 this.ipv6NodeSegmentId = config.getIPv6SegmentId(deviceId);
Charles Chan0b4e6182015-11-03 10:42:14 -0800117 this.isEdgeRouter = config.isEdgeDevice(deviceId);
118 this.nodeMacAddr = checkNotNull(config.getDeviceMac(deviceId));
119 } catch (DeviceConfigNotFoundException e) {
120 log.warn(e.getMessage()
121 + " Skipping value assignment in DefaultGroupHandler");
122 }
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700123 this.flowObjectiveService = flowObjService;
Charles Chane849c192016-01-11 18:28:54 -0800124 this.nsNextObjStore = srManager.nsNextObjStore;
125 this.subnetNextObjStore = srManager.subnetNextObjStore;
126 this.portNextObjStore = srManager.portNextObjStore;
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(
Saurav Das1ce0a7b2016-10-21 14:06:29 -0700264 (objective) -> log.debug("LinkUp addedTo NextObj {} on {}",
Charles Chan216e3c82016-04-23 14:48:16 -0700265 nextId, deviceId),
266 (objective, error) ->
Saurav Das1ce0a7b2016-10-21 14:06:29 -0700267 log.warn("LinkUp failed to addTo NextObj {} on {}: {}",
Charles Chan216e3c82016-04-23 14:48:16 -0700268 nextId, deviceId, error));
269 NextObjective nextObjective = nextObjBuilder.addToExisting(context);
Saurav Das4ce45962015-11-24 23:21:05 -0800270 flowObjectiveService.next(deviceId, nextObjective);
271 } else if (isMaster) {
Saurav Das8a0732e2015-11-20 15:27:53 -0800272 log.warn("linkUp in device {}, but global store has no record "
273 + "for neighbor-set {}", deviceId, ns);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700274 }
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800275 }
276 }
277
278 /**
Saurav Das1a129a02016-11-18 15:21:57 -0800279 * Performs hash group recovery procedures when a switch-to-switch
280 * port goes down on this device.
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800281 *
282 * @param port port number that has gone down
Charles Chane849c192016-01-11 18:28:54 -0800283 * @param isMaster true if local instance is the master
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800284 */
Saurav Das423fe2b2015-12-04 10:52:59 -0800285 public void portDown(PortNumber port, boolean isMaster) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800286 if (portDeviceMap.get(port) == null) {
287 log.warn("portDown: unknown port");
288 return;
289 }
Charles Chan0b4e6182015-11-03 10:42:14 -0800290
291 MacAddress dstMac;
292 try {
293 dstMac = deviceConfig.getDeviceMac(portDeviceMap.get(port));
294 } catch (DeviceConfigNotFoundException e) {
295 log.warn(e.getMessage() + " Aborting portDown.");
296 return;
297 }
298
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700299 log.debug("Device {} portDown {} to neighbor {}", deviceId, port,
300 portDeviceMap.get(port));
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700301 /*Set<NeighborSet> nsSet = computeImpactedNeighborsetForPortEvent(portDeviceMap
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700302 .get(port),
303 devicePortMap
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700304 .keySet());*/
305 Set<NeighborSet> nsSet = nsNextObjStore.keySet()
306 .stream()
307 .filter((nsStoreEntry) -> (nsStoreEntry.deviceId().equals(deviceId)))
308 .map((nsStoreEntry) -> (nsStoreEntry.neighborSet()))
309 .filter((ns) -> (ns.getDeviceIds()
310 .contains(portDeviceMap.get(port))))
311 .collect(Collectors.toSet());
Saurav Das423fe2b2015-12-04 10:52:59 -0800312 log.debug("portDown: nsNextObjStore contents for device {}:{}",
313 deviceId, nsSet);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800314 for (NeighborSet ns : nsSet) {
Saurav Das80980c72016-03-23 11:22:49 -0700315 NeighborSetNextObjectiveStoreKey nsStoreKey =
316 new NeighborSetNextObjectiveStoreKey(deviceId, ns);
317 Integer nextId = nsNextObjStore.get(nsStoreKey);
Saurav Das423fe2b2015-12-04 10:52:59 -0800318 if (nextId != null && isMaster) {
Saurav Das8a0732e2015-11-20 15:27:53 -0800319 log.info("**portDown in device {}: Removing Bucket "
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700320 + "with Port {} to next object id {}",
321 deviceId,
322 port,
323 nextId);
Saurav Das423fe2b2015-12-04 10:52:59 -0800324 // Create the bucket to be removed
325 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment
326 .builder();
327 tBuilder.setOutput(port)
328 .setEthDst(dstMac)
329 .setEthSrc(nodeMacAddr);
330 if (ns.getEdgeLabel() != NeighborSet.NO_EDGE_LABEL) {
331 tBuilder.pushMpls()
332 .copyTtlOut()
333 .setMpls(MplsLabel.mplsLabel(ns.getEdgeLabel()));
334 }
335 NextObjective.Builder nextObjBuilder = DefaultNextObjective
336 .builder()
337 .withType(NextObjective.Type.HASHED) //same as original
338 .withId(nextId)
339 .fromApp(appId)
340 .addTreatment(tBuilder.build());
Saurav Das1ce0a7b2016-10-21 14:06:29 -0700341 ObjectiveContext context = new DefaultObjectiveContext(
342 (objective) -> log.debug("portDown removedFrom NextObj {} on {}",
343 nextId, deviceId),
344 (objective, error) ->
345 log.warn("portDown failed to removeFrom NextObj {} on {}: {}",
346 nextId, deviceId, error));
Saurav Das423fe2b2015-12-04 10:52:59 -0800347 NextObjective nextObjective = nextObjBuilder.
Saurav Das1ce0a7b2016-10-21 14:06:29 -0700348 removeFromExisting(context);
sangho834e4b02015-05-01 09:38:25 -0700349
Saurav Das423fe2b2015-12-04 10:52:59 -0800350 flowObjectiveService.next(deviceId, nextObjective);
sangho834e4b02015-05-01 09:38:25 -0700351 }
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800352 }
353
354 devicePortMap.get(portDeviceMap.get(port)).remove(port);
355 portDeviceMap.remove(port);
356 }
357
358 /**
Saurav Das1a129a02016-11-18 15:21:57 -0800359 * Adds or removes a port that has been configured with a subnet to a broadcast group
360 * for bridging. Note that this does not create the broadcast group itself.
361 *
362 * @param port the port on this device that needs to be added/removed to a bcast group
363 * @param subnet the subnet corresponding to the broadcast group
364 * @param portUp true if port is enabled, false if disabled
365 * @param isMaster true if local instance is the master
366 */
367 public void processEdgePort(PortNumber port, Ip4Prefix subnet,
368 boolean portUp, boolean isMaster) {
369 if (!isMaster) {
370 return;
371 }
372 //get the next id for the subnet and edit it.
373 Integer nextId = getSubnetNextObjectiveId(subnet);
374 if (nextId == -1) {
375 if (portUp) {
376 log.debug("**Creating flooding group for first port enabled in"
377 + " subnet {} on dev {} port {}", subnet, deviceId, port);
378 createBcastGroupFromSubnet(subnet, Collections.singletonList(port));
379 } else {
380 log.warn("Could not find flooding group for subnet {} on dev:{} when"
381 + " removing port:{}", subnet, deviceId, port);
382 }
383 return;
384 }
385
386 log.info("**port{} in device {}: {} Bucket with Port {} to"
387 + " next-id {}", (portUp) ? "UP" : "DOWN", deviceId,
388 (portUp) ? "Adding" : "Removing",
389 port, nextId);
390 // Create the bucket to be added or removed
391 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
392 tBuilder.popVlan();
393 tBuilder.setOutput(port);
394
395 VlanId assignedVlanId =
396 srManager.getSubnetAssignedVlanId(this.deviceId, subnet);
397 TrafficSelector metadata =
398 DefaultTrafficSelector.builder().matchVlanId(assignedVlanId).build();
399
400 NextObjective.Builder nextObjBuilder = DefaultNextObjective
401 .builder().withId(nextId)
402 .withType(NextObjective.Type.BROADCAST).fromApp(appId)
403 .addTreatment(tBuilder.build())
404 .withMeta(metadata);
405
406 ObjectiveContext context = new DefaultObjectiveContext(
407 (objective) -> log.debug("port {} successfully {} NextObj {} on {}",
408 port, (portUp) ? "addedTo" : "removedFrom",
409 nextId, deviceId),
410 (objective, error) ->
411 log.warn("port {} failed to {} NextObj {} on {}: {}",
412 port, (portUp) ? "addTo" : "removeFrom",
413 nextId, deviceId, error));
414
415 NextObjective nextObj = (portUp) ? nextObjBuilder.addToExisting(context)
416 : nextObjBuilder.removeFromExisting(context);
417 log.debug("edgePort processed: Submited next objective {} in device {}",
418 nextId, deviceId);
419 flowObjectiveService.next(deviceId, nextObj);
420 }
421
422 /**
Saurav Das4ce45962015-11-24 23:21:05 -0800423 * Returns the next objective of type hashed associated with the neighborset.
424 * If there is no next objective for this neighborset, this method
Saurav Das8a0732e2015-11-20 15:27:53 -0800425 * would create a next objective and return. Optionally metadata can be
426 * passed in for the creation of the next objective.
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800427 *
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700428 * @param ns neighborset
Saurav Das8a0732e2015-11-20 15:27:53 -0800429 * @param meta metadata passed into the creation of a Next Objective
430 * @return int if found or -1 if there are errors in the creation of the
431 * neighbor set.
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800432 */
Saurav Das8a0732e2015-11-20 15:27:53 -0800433 public int getNextObjectiveId(NeighborSet ns, TrafficSelector meta) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700434 Integer nextId = nsNextObjStore.
435 get(new NeighborSetNextObjectiveStoreKey(deviceId, ns));
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700436 if (nextId == null) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700437 log.trace("getNextObjectiveId in device{}: Next objective id "
438 + "not found for {} and creating", deviceId, ns);
439 log.trace("getNextObjectiveId: nsNextObjStore contents for device {}: {}",
440 deviceId,
441 nsNextObjStore.entrySet()
442 .stream()
443 .filter((nsStoreEntry) ->
444 (nsStoreEntry.getKey().deviceId().equals(deviceId)))
445 .collect(Collectors.toList()));
Saurav Das8a0732e2015-11-20 15:27:53 -0800446 createGroupsFromNeighborsets(Collections.singleton(ns), meta);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700447 nextId = nsNextObjStore.
448 get(new NeighborSetNextObjectiveStoreKey(deviceId, ns));
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700449 if (nextId == null) {
450 log.warn("getNextObjectiveId: unable to create next objective");
451 return -1;
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700452 } else {
453 log.debug("getNextObjectiveId in device{}: Next objective id {} "
Sho SHIMIZUaf973432015-09-11 14:24:50 -0700454 + "created for {}", deviceId, nextId, ns);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700455 }
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700456 } else {
457 log.trace("getNextObjectiveId in device{}: Next objective id {} "
Sho SHIMIZUaf973432015-09-11 14:24:50 -0700458 + "found for {}", deviceId, nextId, ns);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700459 }
Sho SHIMIZUaf973432015-09-11 14:24:50 -0700460 return nextId;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800461 }
462
sangho0b2b6d12015-05-20 22:16:38 -0700463 /**
Saurav Das4ce45962015-11-24 23:21:05 -0800464 * Returns the next objective of type broadcast associated with the subnet,
465 * or -1 if no such objective exists. Note that this method does NOT create
466 * the next objective as a side-effect. It is expected that is objective is
Saurav Das1a129a02016-11-18 15:21:57 -0800467 * created at startup from network configuration. Typically this is used
468 * for L2 flooding within the subnet configured on the switch.
Charles Chanc42e84e2015-10-20 16:24:19 -0700469 *
470 * @param prefix subnet information
471 * @return int if found or -1
472 */
473 public int getSubnetNextObjectiveId(IpPrefix prefix) {
474 Integer nextId = subnetNextObjStore.
475 get(new SubnetNextObjectiveStoreKey(deviceId, prefix));
Charles Chan9f676b62015-10-29 14:58:10 -0700476
477 return (nextId != null) ? nextId : -1;
Charles Chanc42e84e2015-10-20 16:24:19 -0700478 }
479
480 /**
Saurav Das4ce45962015-11-24 23:21:05 -0800481 * Returns the next objective of type simple associated with the port on the
482 * device, given the treatment. Different treatments to the same port result
483 * in different next objectives. If no such objective exists, this method
484 * creates one and returns the id. Optionally metadata can be passed in for
Saurav Das1a129a02016-11-18 15:21:57 -0800485 * the creation of the objective. Typically this is used for L2 and L3 forwarding
486 * to compute nodes and containers/VMs on the compute nodes directly attached
487 * to the switch.
Saurav Das4ce45962015-11-24 23:21:05 -0800488 *
489 * @param portNum the port number for the simple next objective
490 * @param treatment the actions to apply on the packets (should include outport)
491 * @param meta optional metadata passed into the creation of the next objective
492 * @return int if found or created, -1 if there are errors during the
493 * creation of the next objective.
494 */
495 public int getPortNextObjectiveId(PortNumber portNum, TrafficTreatment treatment,
496 TrafficSelector meta) {
Charles Chane849c192016-01-11 18:28:54 -0800497 Integer nextId = portNextObjStore
498 .get(new PortNextObjectiveStoreKey(deviceId, portNum, treatment));
Saurav Das4ce45962015-11-24 23:21:05 -0800499 if (nextId == null) {
500 log.trace("getPortNextObjectiveId in device{}: Next objective id "
501 + "not found for {} and {} creating", deviceId, portNum);
502 createGroupFromPort(portNum, treatment, meta);
503 nextId = portNextObjStore.get(
504 new PortNextObjectiveStoreKey(deviceId, portNum, treatment));
505 if (nextId == null) {
506 log.warn("getPortNextObjectiveId: unable to create next obj"
Charles Chane849c192016-01-11 18:28:54 -0800507 + "for dev:{} port:{}", deviceId, portNum);
508 return -1;
509 }
510 }
511 return nextId;
512 }
513
514 /**
sangho0b2b6d12015-05-20 22:16:38 -0700515 * Checks if the next objective ID (group) for the neighbor set exists or not.
516 *
517 * @param ns neighbor set to check
518 * @return true if it exists, false otherwise
519 */
520 public boolean hasNextObjectiveId(NeighborSet ns) {
521 Integer nextId = nsNextObjStore.
522 get(new NeighborSetNextObjectiveStoreKey(deviceId, ns));
523 if (nextId == null) {
524 return false;
525 }
526
527 return true;
528 }
529
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700530 // Empty implementation
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800531 protected void newNeighbor(Link newLink) {
532 }
533
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700534 // Empty implementation
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800535 protected void newPortToExistingNeighbor(Link newLink) {
536 }
537
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700538 // Empty implementation
539 protected Set<NeighborSet>
540 computeImpactedNeighborsetForPortEvent(DeviceId impactedNeighbor,
541 Set<DeviceId> updatedNeighbors) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800542 return null;
543 }
544
545 private void populateNeighborMaps() {
546 Set<Link> outgoingLinks = linkService.getDeviceEgressLinks(deviceId);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700547 for (Link link : outgoingLinks) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800548 if (link.type() != Link.Type.DIRECT) {
549 continue;
550 }
551 addNeighborAtPort(link.dst().deviceId(), link.src().port());
552 }
553 }
554
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700555 protected void addNeighborAtPort(DeviceId neighborId,
556 PortNumber portToNeighbor) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800557 // Update DeviceToPort database
558 log.debug("Device {} addNeighborAtPort: neighbor {} at port {}",
559 deviceId, neighborId, portToNeighbor);
Saurav Das8a0732e2015-11-20 15:27:53 -0800560 Set<PortNumber> ports = Collections
561 .newSetFromMap(new ConcurrentHashMap<PortNumber, Boolean>());
562 ports.add(portToNeighbor);
563 Set<PortNumber> portnums = devicePortMap.putIfAbsent(neighborId, ports);
564 if (portnums != null) {
565 portnums.add(portToNeighbor);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800566 }
567
568 // Update portToDevice database
Saurav Das8a0732e2015-11-20 15:27:53 -0800569 DeviceId prev = portDeviceMap.putIfAbsent(portToNeighbor, neighborId);
570 if (prev != null) {
571 log.warn("Device: {} port: {} has neighbor: {}. NOT updating "
572 + "to neighbor: {}", deviceId, portToNeighbor, prev, neighborId);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800573 }
574 }
575
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700576 protected Set<Set<DeviceId>> getPowerSetOfNeighbors(Set<DeviceId> neighbors) {
Sho SHIMIZU6cfc02d2015-09-11 11:19:11 -0700577 List<DeviceId> list = new ArrayList<>(neighbors);
578 Set<Set<DeviceId>> sets = new HashSet<>();
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800579 // get the number of elements in the neighbors
580 int elements = list.size();
581 // the number of members of a power set is 2^n
582 // including the empty set
583 int powerElements = (1 << elements);
584
585 // run a binary counter for the number of power elements
586 // NOTE: Exclude empty set
587 for (long i = 1; i < powerElements; i++) {
Sho SHIMIZU6cfc02d2015-09-11 11:19:11 -0700588 Set<DeviceId> neighborSubSet = new HashSet<>();
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800589 for (int j = 0; j < elements; j++) {
590 if ((i >> j) % 2 == 1) {
591 neighborSubSet.add(list.get(j));
592 }
593 }
594 sets.add(neighborSubSet);
595 }
596 return sets;
597 }
598
599 private boolean isSegmentIdSameAsNodeSegmentId(DeviceId deviceId, int sId) {
Charles Chan0b4e6182015-11-03 10:42:14 -0800600 int segmentId;
601 try {
Pier Ventree0ae7a32016-11-23 09:57:42 -0800602 /*
603 * IPv6 sid is not inserted. this part of the code is not used for now.
604 */
605 segmentId = deviceConfig.getIPv4SegmentId(deviceId);
Charles Chan0b4e6182015-11-03 10:42:14 -0800606 } catch (DeviceConfigNotFoundException e) {
607 log.warn(e.getMessage() + " Aborting isSegmentIdSameAsNodeSegmentId.");
608 return false;
609 }
610
611 return segmentId == sId;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800612 }
613
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700614 protected List<Integer> getSegmentIdsTobePairedWithNeighborSet(Set<DeviceId> neighbors) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800615
Sho SHIMIZU6cfc02d2015-09-11 11:19:11 -0700616 List<Integer> nsSegmentIds = new ArrayList<>();
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800617
sanghob35a6192015-04-01 13:05:26 -0700618 // Always pair up with no edge label
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700619 // If (neighbors.size() == 1) {
sanghob35a6192015-04-01 13:05:26 -0700620 nsSegmentIds.add(-1);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700621 // }
sanghob35a6192015-04-01 13:05:26 -0700622
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800623 // Filter out SegmentIds matching with the
624 // nodes in the combo
625 for (Integer sId : allSegmentIds) {
Pier Ventree0ae7a32016-11-23 09:57:42 -0800626 if (sId.equals(this.ipv4NodeSegmentId)) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800627 continue;
628 }
629 boolean filterOut = false;
630 // Check if the edge label being set is of
631 // any node in the Neighbor set
632 for (DeviceId deviceId : neighbors) {
633 if (isSegmentIdSameAsNodeSegmentId(deviceId, sId)) {
634 filterOut = true;
635 break;
636 }
637 }
638 if (!filterOut) {
639 nsSegmentIds.add(sId);
640 }
641 }
642 return nsSegmentIds;
643 }
644
sangho1e575652015-05-14 00:39:53 -0700645 /**
Saurav Das1a129a02016-11-18 15:21:57 -0800646 * Creates hash groups from a set of NeighborSet given.
sangho1e575652015-05-14 00:39:53 -0700647 *
648 * @param nsSet a set of NeighborSet
Saurav Das8a0732e2015-11-20 15:27:53 -0800649 * @param meta metadata passed into the creation of a Next Objective
sangho1e575652015-05-14 00:39:53 -0700650 */
Saurav Das8a0732e2015-11-20 15:27:53 -0800651 public void createGroupsFromNeighborsets(Set<NeighborSet> nsSet,
652 TrafficSelector meta) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800653 for (NeighborSet ns : nsSet) {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700654 int nextId = flowObjectiveService.allocateNextId();
655 NextObjective.Builder nextObjBuilder = DefaultNextObjective
656 .builder().withId(nextId)
657 .withType(NextObjective.Type.HASHED).fromApp(appId);
Saurav Das8a0732e2015-11-20 15:27:53 -0800658 for (DeviceId neighborId : ns.getDeviceIds()) {
659 if (devicePortMap.get(neighborId) == null) {
660 log.warn("Neighbor {} is not in the port map yet for dev:{}",
661 neighborId, deviceId);
sangho834e4b02015-05-01 09:38:25 -0700662 return;
Jon Hallcbd1b392017-01-18 20:15:44 -0800663 } else if (devicePortMap.get(neighborId).isEmpty()) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700664 log.warn("There are no ports for "
Saurav Das8a0732e2015-11-20 15:27:53 -0800665 + "the Device {} in the port map yet", neighborId);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700666 return;
sangho834e4b02015-05-01 09:38:25 -0700667 }
668
Saurav Das8a0732e2015-11-20 15:27:53 -0800669 MacAddress neighborMac;
Charles Chan0b4e6182015-11-03 10:42:14 -0800670 try {
Saurav Das8a0732e2015-11-20 15:27:53 -0800671 neighborMac = deviceConfig.getDeviceMac(neighborId);
Charles Chan0b4e6182015-11-03 10:42:14 -0800672 } catch (DeviceConfigNotFoundException e) {
673 log.warn(e.getMessage() + " Aborting createGroupsFromNeighborsets.");
674 return;
675 }
676
Saurav Das8a0732e2015-11-20 15:27:53 -0800677 for (PortNumber sp : devicePortMap.get(neighborId)) {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700678 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment
679 .builder();
Saurav Das8a0732e2015-11-20 15:27:53 -0800680 tBuilder.setEthDst(neighborMac)
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700681 .setEthSrc(nodeMacAddr);
682 if (ns.getEdgeLabel() != NeighborSet.NO_EDGE_LABEL) {
Charles Chan68aa62d2015-11-09 16:37:23 -0800683 tBuilder.pushMpls()
684 .copyTtlOut()
685 .setMpls(MplsLabel.mplsLabel(ns.getEdgeLabel()));
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700686 }
Saurav Das8a0732e2015-11-20 15:27:53 -0800687 tBuilder.setOutput(sp);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700688 nextObjBuilder.addTreatment(tBuilder.build());
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800689 }
690 }
Saurav Das8a0732e2015-11-20 15:27:53 -0800691 if (meta != null) {
Saurav Das4ce45962015-11-24 23:21:05 -0800692 nextObjBuilder.withMeta(meta);
Saurav Das8a0732e2015-11-20 15:27:53 -0800693 }
Charles Chan216e3c82016-04-23 14:48:16 -0700694
695 ObjectiveContext context = new DefaultObjectiveContext(
696 (objective) -> log.debug("createGroupsFromNeighborsets installed NextObj {} on {}",
697 nextId, deviceId),
698 (objective, error) ->
699 log.warn("createGroupsFromNeighborsets failed to install NextObj {} on {}: {}",
700 nextId, deviceId, error));
701 NextObjective nextObj = nextObjBuilder.add(context);
702 log.debug("**createGroupsFromNeighborsets: Submited "
Saurav Das8a0732e2015-11-20 15:27:53 -0800703 + "next objective {} in device {}",
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700704 nextId, deviceId);
Saurav Das8a0732e2015-11-20 15:27:53 -0800705 flowObjectiveService.next(deviceId, nextObj);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700706 nsNextObjStore.put(new NeighborSetNextObjectiveStoreKey(deviceId, ns),
707 nextId);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800708 }
709 }
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700710
Saurav Das4ce45962015-11-24 23:21:05 -0800711 /**
Saurav Das1a129a02016-11-18 15:21:57 -0800712 * Creates broadcast groups for all ports in the same subnet for
713 * all configured subnets.
Saurav Das4ce45962015-11-24 23:21:05 -0800714 */
Charles Chanc42e84e2015-10-20 16:24:19 -0700715 public void createGroupsFromSubnetConfig() {
Pier Ventre10bd8d12016-11-26 21:05:22 -0800716 Map<IpPrefix, List<PortNumber>> subnetPortMap;
Saurav Das7a1ffca2016-03-28 19:00:18 -0700717 try {
718 subnetPortMap = this.deviceConfig.getSubnetPortsMap(this.deviceId);
719 } catch (DeviceConfigNotFoundException e) {
720 log.warn(e.getMessage()
721 + " Not creating broadcast groups for device: " + deviceId);
722 return;
723 }
Charles Chanc42e84e2015-10-20 16:24:19 -0700724 // Construct a broadcast group for each subnet
Pier Ventre10bd8d12016-11-26 21:05:22 -0800725 subnetPortMap.forEach((subnet, ports) -> {
726 if (subnet.isIp4()) {
727 createBcastGroupFromSubnet(subnet.getIp4Prefix(), ports);
728 }
729 });
Saurav Das1a129a02016-11-18 15:21:57 -0800730 }
Charles Chan9f676b62015-10-29 14:58:10 -0700731
Saurav Das1a129a02016-11-18 15:21:57 -0800732 /**
733 * Creates a single broadcast group from a given subnet and list of ports.
734 *
735 * @param subnet a configured subnet
736 * @param ports list of ports in the subnet
737 */
738 public void createBcastGroupFromSubnet(Ip4Prefix subnet, List<PortNumber> ports) {
739 SubnetNextObjectiveStoreKey key =
740 new SubnetNextObjectiveStoreKey(deviceId, subnet);
Charles Chan9f676b62015-10-29 14:58:10 -0700741
Saurav Das1a129a02016-11-18 15:21:57 -0800742 if (subnetNextObjStore.containsKey(key)) {
743 log.debug("Broadcast group for device {} and subnet {} exists",
744 deviceId, subnet);
745 return;
746 }
Charles Chan188ebf52015-12-23 00:15:11 -0800747
Saurav Das1a129a02016-11-18 15:21:57 -0800748 VlanId assignedVlanId =
749 srManager.getSubnetAssignedVlanId(this.deviceId, subnet);
750 TrafficSelector metadata =
751 DefaultTrafficSelector.builder().matchVlanId(assignedVlanId).build();
Charles Chanc42e84e2015-10-20 16:24:19 -0700752
Saurav Das1a129a02016-11-18 15:21:57 -0800753 int nextId = flowObjectiveService.allocateNextId();
Charles Chanc42e84e2015-10-20 16:24:19 -0700754
Saurav Das1a129a02016-11-18 15:21:57 -0800755 NextObjective.Builder nextObjBuilder = DefaultNextObjective
756 .builder().withId(nextId)
757 .withType(NextObjective.Type.BROADCAST).fromApp(appId)
758 .withMeta(metadata);
Charles Chanc42e84e2015-10-20 16:24:19 -0700759
Saurav Das1a129a02016-11-18 15:21:57 -0800760 ports.forEach(port -> {
761 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
762 tBuilder.popVlan();
763 tBuilder.setOutput(port);
764 nextObjBuilder.addTreatment(tBuilder.build());
Charles Chanc42e84e2015-10-20 16:24:19 -0700765 });
Saurav Das1a129a02016-11-18 15:21:57 -0800766
767 NextObjective nextObj = nextObjBuilder.add();
768 flowObjectiveService.next(deviceId, nextObj);
769 log.debug("createBcastGroupFromSubnet: Submited next objective {} in device {}",
770 nextId, deviceId);
771
772 subnetNextObjStore.put(key, nextId);
Charles Chanc42e84e2015-10-20 16:24:19 -0700773 }
774
Charles Chane849c192016-01-11 18:28:54 -0800775 /**
Saurav Das4ce45962015-11-24 23:21:05 -0800776 * Create simple next objective for a single port. The treatments can include
777 * all outgoing actions that need to happen on the packet.
778 *
779 * @param portNum the outgoing port on the device
780 * @param treatment the actions to apply on the packets (should include outport)
781 * @param meta optional data to pass to the driver
782 */
783 public void createGroupFromPort(PortNumber portNum, TrafficTreatment treatment,
784 TrafficSelector meta) {
785 int nextId = flowObjectiveService.allocateNextId();
786 PortNextObjectiveStoreKey key = new PortNextObjectiveStoreKey(
787 deviceId, portNum, treatment);
788
789 NextObjective.Builder nextObjBuilder = DefaultNextObjective
790 .builder().withId(nextId)
791 .withType(NextObjective.Type.SIMPLE)
792 .addTreatment(treatment)
793 .fromApp(appId)
794 .withMeta(meta);
795
796 NextObjective nextObj = nextObjBuilder.add();
797 flowObjectiveService.next(deviceId, nextObj);
798 log.debug("createGroupFromPort: Submited next objective {} in device {} "
799 + "for port {}", nextId, deviceId, portNum);
800
801 portNextObjStore.put(key, nextId);
802 }
803
sangho1e575652015-05-14 00:39:53 -0700804 /**
805 * Removes groups for the next objective ID given.
806 *
807 * @param objectiveId next objective ID to remove
808 * @return true if succeeds, false otherwise
809 */
810 public boolean removeGroup(int objectiveId) {
811
812 if (nsNextObjStore.containsValue(objectiveId)) {
813 NextObjective.Builder nextObjBuilder = DefaultNextObjective
814 .builder().withId(objectiveId)
815 .withType(NextObjective.Type.HASHED).fromApp(appId);
Charles Chan216e3c82016-04-23 14:48:16 -0700816 ObjectiveContext context = new DefaultObjectiveContext(
817 (objective) -> log.debug("RemoveGroup removes NextObj {} on {}",
818 objectiveId, deviceId),
819 (objective, error) ->
820 log.warn("RemoveGroup failed to remove NextObj {} on {}: {}",
821 objectiveId, deviceId, error));
822 NextObjective nextObjective = nextObjBuilder.remove(context);
Saurav Das8a0732e2015-11-20 15:27:53 -0800823 log.info("**removeGroup: Submited "
824 + "next objective {} in device {}",
825 objectiveId, deviceId);
sangho1e575652015-05-14 00:39:53 -0700826 flowObjectiveService.next(deviceId, nextObjective);
827
828 for (Map.Entry<NeighborSetNextObjectiveStoreKey, Integer> entry: nsNextObjStore.entrySet()) {
829 if (entry.getValue().equals(objectiveId)) {
830 nsNextObjStore.remove(entry.getKey());
831 break;
832 }
833 }
sangho0b2b6d12015-05-20 22:16:38 -0700834 return true;
sangho1e575652015-05-14 00:39:53 -0700835 }
836
837 return false;
838 }
Srikanth Vavilapallif3a8bc02015-05-22 13:47:31 -0700839
Charles Chane849c192016-01-11 18:28:54 -0800840 /**
841 * Removes all groups from all next objective stores.
842 */
Saurav Das423fe2b2015-12-04 10:52:59 -0800843 public void removeAllGroups() {
844 for (Map.Entry<NeighborSetNextObjectiveStoreKey, Integer> entry:
845 nsNextObjStore.entrySet()) {
846 removeGroup(entry.getValue());
847 }
848 for (Map.Entry<PortNextObjectiveStoreKey, Integer> entry:
849 portNextObjStore.entrySet()) {
850 removeGroup(entry.getValue());
851 }
852 for (Map.Entry<SubnetNextObjectiveStoreKey, Integer> entry:
853 subnetNextObjStore.entrySet()) {
854 removeGroup(entry.getValue());
855 }
856 // should probably clean local stores port-neighbor
857 }
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800858}