blob: 0e8f220f387e9117b00731baa71ab62353dec9fe [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
Pier Ventre917127a2016-10-31 16:49:19 -070018import com.google.common.collect.Iterables;
19import org.apache.commons.lang3.RandomUtils;
Charles Chanc42e84e2015-10-20 16:24:19 -070020import org.onlab.packet.Ip4Prefix;
21import org.onlab.packet.IpPrefix;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080022import org.onlab.packet.MacAddress;
sangho32a59322015-02-17 12:07:41 -080023import org.onlab.packet.MplsLabel;
Saurav Das423fe2b2015-12-04 10:52:59 -080024import org.onlab.packet.VlanId;
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -070025import org.onlab.util.KryoNamespace;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080026import org.onosproject.core.ApplicationId;
27import org.onosproject.net.DeviceId;
28import org.onosproject.net.Link;
29import org.onosproject.net.PortNumber;
Saurav Das423fe2b2015-12-04 10:52:59 -080030import org.onosproject.net.flow.DefaultTrafficSelector;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080031import org.onosproject.net.flow.DefaultTrafficTreatment;
Saurav Das8a0732e2015-11-20 15:27:53 -080032import org.onosproject.net.flow.TrafficSelector;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080033import org.onosproject.net.flow.TrafficTreatment;
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070034import org.onosproject.net.flowobjective.DefaultNextObjective;
Charles Chan216e3c82016-04-23 14:48:16 -070035import org.onosproject.net.flowobjective.DefaultObjectiveContext;
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070036import org.onosproject.net.flowobjective.FlowObjectiveService;
37import org.onosproject.net.flowobjective.NextObjective;
Srikanth Vavilapallif3a8bc02015-05-22 13:47:31 -070038import org.onosproject.net.flowobjective.ObjectiveContext;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080039import org.onosproject.net.link.LinkService;
Saurav Das423fe2b2015-12-04 10:52:59 -080040import org.onosproject.segmentrouting.SegmentRoutingManager;
Charles Chan0b4e6182015-11-03 10:42:14 -080041import org.onosproject.segmentrouting.config.DeviceConfigNotFoundException;
42import org.onosproject.segmentrouting.config.DeviceProperties;
Charles Chand2990362016-04-18 13:44:03 -070043import org.onosproject.segmentrouting.storekey.NeighborSetNextObjectiveStoreKey;
44import org.onosproject.segmentrouting.storekey.PortNextObjectiveStoreKey;
45import org.onosproject.segmentrouting.storekey.SubnetNextObjectiveStoreKey;
Srikanth Vavilapalli23181912015-05-04 09:48:09 -070046import org.onosproject.store.service.EventuallyConsistentMap;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080047import org.slf4j.Logger;
48
Pier Ventre917127a2016-10-31 16:49:19 -070049import java.net.URI;
50import java.util.ArrayList;
51import java.util.Collections;
52import java.util.HashSet;
53import java.util.List;
54import java.util.Map;
55import java.util.Set;
56import java.util.concurrent.ConcurrentHashMap;
57import java.util.stream.Collectors;
58
59import static com.google.common.base.Preconditions.checkNotNull;
60import static org.slf4j.LoggerFactory.getLogger;
61
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080062/**
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;
Pier Ventree0ae7a32016-11-23 09:57:42 -080074 protected int ipv4NodeSegmentId = -1;
75 protected int ipv6NodeSegmentId = -1;
Charles Chan0b4e6182015-11-03 10:42:14 -080076 protected boolean isEdgeRouter = false;
77 protected MacAddress nodeMacAddr = null;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080078 protected LinkService linkService;
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070079 protected FlowObjectiveService flowObjectiveService;
Saurav Das423fe2b2015-12-04 10:52:59 -080080 // local store for neighbor-device-ids and the set of ports on this device
81 // that connect to the same neighbor
Saurav Das8a0732e2015-11-20 15:27:53 -080082 protected ConcurrentHashMap<DeviceId, Set<PortNumber>> devicePortMap =
83 new ConcurrentHashMap<>();
Saurav Das1a129a02016-11-18 15:21:57 -080084 // local store for ports on this device connected to neighbor-device-id
Saurav Das8a0732e2015-11-20 15:27:53 -080085 protected ConcurrentHashMap<PortNumber, DeviceId> portDeviceMap =
86 new ConcurrentHashMap<>();
Saurav Das1a129a02016-11-18 15:21:57 -080087 // distributed store for (device+neighborset) mapped to next-id
Charles Chane849c192016-01-11 18:28:54 -080088 protected EventuallyConsistentMap<NeighborSetNextObjectiveStoreKey, Integer>
89 nsNextObjStore = null;
Saurav Das1a129a02016-11-18 15:21:57 -080090 // distributed store for (device+subnet-ip-prefix) mapped to next-id
Charles Chane849c192016-01-11 18:28:54 -080091 protected EventuallyConsistentMap<SubnetNextObjectiveStoreKey, Integer>
92 subnetNextObjStore = null;
Saurav Das1a129a02016-11-18 15:21:57 -080093 // distributed store for (device+port+treatment) mapped to next-id
Charles Chane849c192016-01-11 18:28:54 -080094 protected EventuallyConsistentMap<PortNextObjectiveStoreKey, Integer>
95 portNextObjStore = null;
Charles Chan188ebf52015-12-23 00:15:11 -080096 private SegmentRoutingManager srManager;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080097
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -070098 protected KryoNamespace.Builder kryo = new KryoNamespace.Builder()
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070099 .register(URI.class).register(HashSet.class)
100 .register(DeviceId.class).register(PortNumber.class)
101 .register(NeighborSet.class).register(PolicyGroupIdentifier.class)
102 .register(PolicyGroupParams.class)
103 .register(GroupBucketIdentifier.class)
104 .register(GroupBucketIdentifier.BucketOutputType.class);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800105
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700106 protected DefaultGroupHandler(DeviceId deviceId, ApplicationId appId,
107 DeviceProperties config,
108 LinkService linkService,
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700109 FlowObjectiveService flowObjService,
Charles Chan188ebf52015-12-23 00:15:11 -0800110 SegmentRoutingManager srManager) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800111 this.deviceId = checkNotNull(deviceId);
112 this.appId = checkNotNull(appId);
113 this.deviceConfig = checkNotNull(config);
114 this.linkService = checkNotNull(linkService);
Charles Chan0b4e6182015-11-03 10:42:14 -0800115 this.allSegmentIds = checkNotNull(config.getAllDeviceSegmentIds());
116 try {
Pier Ventree0ae7a32016-11-23 09:57:42 -0800117 this.ipv4NodeSegmentId = config.getIPv4SegmentId(deviceId);
118 this.ipv6NodeSegmentId = config.getIPv6SegmentId(deviceId);
Charles Chan0b4e6182015-11-03 10:42:14 -0800119 this.isEdgeRouter = config.isEdgeDevice(deviceId);
120 this.nodeMacAddr = checkNotNull(config.getDeviceMac(deviceId));
121 } catch (DeviceConfigNotFoundException e) {
122 log.warn(e.getMessage()
123 + " Skipping value assignment in DefaultGroupHandler");
124 }
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700125 this.flowObjectiveService = flowObjService;
Charles Chane849c192016-01-11 18:28:54 -0800126 this.nsNextObjStore = srManager.nsNextObjStore;
127 this.subnetNextObjStore = srManager.subnetNextObjStore;
128 this.portNextObjStore = srManager.portNextObjStore;
Charles Chan188ebf52015-12-23 00:15:11 -0800129 this.srManager = srManager;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800130
131 populateNeighborMaps();
132 }
133
134 /**
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700135 * Creates a group handler object based on the type of device. If device is
136 * of edge type it returns edge group handler, else it returns transit group
137 * handler.
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800138 *
139 * @param deviceId device identifier
140 * @param appId application identifier
141 * @param config interface to retrieve the device properties
142 * @param linkService link service object
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700143 * @param flowObjService flow objective service object
Charles Chane849c192016-01-11 18:28:54 -0800144 * @param srManager segment routing manager
Charles Chan0b4e6182015-11-03 10:42:14 -0800145 * @throws DeviceConfigNotFoundException if the device configuration is not found
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800146 * @return default group handler type
147 */
Saurav Das4ce45962015-11-24 23:21:05 -0800148 public static DefaultGroupHandler createGroupHandler(
149 DeviceId deviceId,
150 ApplicationId appId,
151 DeviceProperties config,
152 LinkService linkService,
153 FlowObjectiveService flowObjService,
Charles Chan188ebf52015-12-23 00:15:11 -0800154 SegmentRoutingManager srManager)
Saurav Das4ce45962015-11-24 23:21:05 -0800155 throws DeviceConfigNotFoundException {
Charles Chan0b4e6182015-11-03 10:42:14 -0800156 // handle possible exception in the caller
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800157 if (config.isEdgeDevice(deviceId)) {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700158 return new DefaultEdgeGroupHandler(deviceId, appId, config,
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700159 linkService,
160 flowObjService,
Charles Chan188ebf52015-12-23 00:15:11 -0800161 srManager
162 );
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800163 } else {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700164 return new DefaultTransitGroupHandler(deviceId, appId, config,
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700165 linkService,
166 flowObjService,
Charles Chan188ebf52015-12-23 00:15:11 -0800167 srManager);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800168 }
169 }
170
171 /**
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700172 * Creates the auto created groups for this device based on the current
173 * snapshot of the topology.
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800174 */
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700175 // Empty implementations to be overridden by derived classes
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800176 public void createGroups() {
177 }
178
179 /**
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700180 * Performs group creation or update procedures when a new link is
181 * discovered on this device.
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800182 *
183 * @param newLink new neighbor link
Charles Chane849c192016-01-11 18:28:54 -0800184 * @param isMaster true if local instance is the master
185 *
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800186 */
Saurav Das8a0732e2015-11-20 15:27:53 -0800187 public void linkUp(Link newLink, boolean isMaster) {
sanghob35a6192015-04-01 13:05:26 -0700188
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800189 if (newLink.type() != Link.Type.DIRECT) {
190 log.warn("linkUp: unknown link type");
191 return;
192 }
193
194 if (!newLink.src().deviceId().equals(deviceId)) {
195 log.warn("linkUp: deviceId{} doesn't match with link src{}",
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700196 deviceId, newLink.src().deviceId());
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800197 return;
198 }
199
Saurav Das8a0732e2015-11-20 15:27:53 -0800200 log.info("* LinkUP: Device {} linkUp at local port {} to neighbor {}", deviceId,
201 newLink.src().port(), newLink.dst().deviceId());
Saurav Das59232cf2016-04-27 18:35:50 -0700202 // ensure local state is updated even if linkup is aborted later on
203 addNeighborAtPort(newLink.dst().deviceId(),
204 newLink.src().port());
205
Charles Chan0b4e6182015-11-03 10:42:14 -0800206 MacAddress dstMac;
207 try {
208 dstMac = deviceConfig.getDeviceMac(newLink.dst().deviceId());
209 } catch (DeviceConfigNotFoundException e) {
210 log.warn(e.getMessage() + " Aborting linkUp.");
211 return;
212 }
213
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700214 /*if (devicePortMap.get(newLink.dst().deviceId()) == null) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800215 // New Neighbor
216 newNeighbor(newLink);
217 } else {
218 // Old Neighbor
219 newPortToExistingNeighbor(newLink);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700220 }*/
221 Set<NeighborSet> nsSet = nsNextObjStore.keySet()
222 .stream()
223 .filter((nsStoreEntry) -> (nsStoreEntry.deviceId().equals(deviceId)))
224 .map((nsStoreEntry) -> (nsStoreEntry.neighborSet()))
225 .filter((ns) -> (ns.getDeviceIds()
226 .contains(newLink.dst().deviceId())))
227 .collect(Collectors.toSet());
228 log.trace("linkUp: nsNextObjStore contents for device {}:",
sangho0b2b6d12015-05-20 22:16:38 -0700229 deviceId,
230 nsSet);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700231 for (NeighborSet ns : nsSet) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700232 Integer nextId = nsNextObjStore.
233 get(new NeighborSetNextObjectiveStoreKey(deviceId, ns));
Saurav Das4ce45962015-11-24 23:21:05 -0800234 if (nextId != null && isMaster) {
Saurav Das423fe2b2015-12-04 10:52:59 -0800235 // Create the new bucket to be updated
236 TrafficTreatment.Builder tBuilder =
237 DefaultTrafficTreatment.builder();
238 tBuilder.setOutput(newLink.src().port())
239 .setEthDst(dstMac)
240 .setEthSrc(nodeMacAddr);
241 if (ns.getEdgeLabel() != NeighborSet.NO_EDGE_LABEL) {
242 tBuilder.pushMpls()
243 .copyTtlOut()
244 .setMpls(MplsLabel.mplsLabel(ns.getEdgeLabel()));
245 }
246 // setup metadata to pass to nextObjective - indicate the vlan on egress
247 // if needed by the switch pipeline. Since hashed next-hops are always to
248 // other neighboring routers, there is no subnet assigned on those ports.
249 TrafficSelector.Builder metabuilder = DefaultTrafficSelector.builder();
250 metabuilder.matchVlanId(
251 VlanId.vlanId(SegmentRoutingManager.ASSIGNED_VLAN_NO_SUBNET));
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700252
Saurav Das423fe2b2015-12-04 10:52:59 -0800253 NextObjective.Builder nextObjBuilder = DefaultNextObjective.builder()
254 .withId(nextId)
255 .withType(NextObjective.Type.HASHED)
256 .addTreatment(tBuilder.build())
257 .withMeta(metabuilder.build())
258 .fromApp(appId);
Saurav Das8a0732e2015-11-20 15:27:53 -0800259 log.info("**linkUp in device {}: Adding Bucket "
Saurav Das4ce45962015-11-24 23:21:05 -0800260 + "with Port {} to next object id {}",
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700261 deviceId,
262 newLink.src().port(),
Saurav Das4ce45962015-11-24 23:21:05 -0800263 nextId);
Charles Chan216e3c82016-04-23 14:48:16 -0700264
265 ObjectiveContext context = new DefaultObjectiveContext(
Saurav Das1ce0a7b2016-10-21 14:06:29 -0700266 (objective) -> log.debug("LinkUp addedTo NextObj {} on {}",
Charles Chan216e3c82016-04-23 14:48:16 -0700267 nextId, deviceId),
268 (objective, error) ->
Saurav Das1ce0a7b2016-10-21 14:06:29 -0700269 log.warn("LinkUp failed to addTo NextObj {} on {}: {}",
Charles Chan216e3c82016-04-23 14:48:16 -0700270 nextId, deviceId, error));
271 NextObjective nextObjective = nextObjBuilder.addToExisting(context);
Saurav Das4ce45962015-11-24 23:21:05 -0800272 flowObjectiveService.next(deviceId, nextObjective);
273 } else if (isMaster) {
Saurav Das8a0732e2015-11-20 15:27:53 -0800274 log.warn("linkUp in device {}, but global store has no record "
275 + "for neighbor-set {}", deviceId, ns);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700276 }
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800277 }
278 }
279
280 /**
Saurav Das1a129a02016-11-18 15:21:57 -0800281 * Performs hash group recovery procedures when a switch-to-switch
282 * port goes down on this device.
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800283 *
284 * @param port port number that has gone down
Charles Chane849c192016-01-11 18:28:54 -0800285 * @param isMaster true if local instance is the master
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800286 */
Saurav Das423fe2b2015-12-04 10:52:59 -0800287 public void portDown(PortNumber port, boolean isMaster) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800288 if (portDeviceMap.get(port) == null) {
289 log.warn("portDown: unknown port");
290 return;
291 }
Charles Chan0b4e6182015-11-03 10:42:14 -0800292
293 MacAddress dstMac;
294 try {
295 dstMac = deviceConfig.getDeviceMac(portDeviceMap.get(port));
296 } catch (DeviceConfigNotFoundException e) {
297 log.warn(e.getMessage() + " Aborting portDown.");
298 return;
299 }
300
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700301 log.debug("Device {} portDown {} to neighbor {}", deviceId, port,
302 portDeviceMap.get(port));
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700303 /*Set<NeighborSet> nsSet = computeImpactedNeighborsetForPortEvent(portDeviceMap
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700304 .get(port),
305 devicePortMap
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700306 .keySet());*/
307 Set<NeighborSet> nsSet = nsNextObjStore.keySet()
308 .stream()
309 .filter((nsStoreEntry) -> (nsStoreEntry.deviceId().equals(deviceId)))
310 .map((nsStoreEntry) -> (nsStoreEntry.neighborSet()))
311 .filter((ns) -> (ns.getDeviceIds()
312 .contains(portDeviceMap.get(port))))
313 .collect(Collectors.toSet());
Saurav Das423fe2b2015-12-04 10:52:59 -0800314 log.debug("portDown: nsNextObjStore contents for device {}:{}",
315 deviceId, nsSet);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800316 for (NeighborSet ns : nsSet) {
Saurav Das80980c72016-03-23 11:22:49 -0700317 NeighborSetNextObjectiveStoreKey nsStoreKey =
318 new NeighborSetNextObjectiveStoreKey(deviceId, ns);
319 Integer nextId = nsNextObjStore.get(nsStoreKey);
Saurav Das423fe2b2015-12-04 10:52:59 -0800320 if (nextId != null && isMaster) {
Saurav Das8a0732e2015-11-20 15:27:53 -0800321 log.info("**portDown in device {}: Removing Bucket "
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700322 + "with Port {} to next object id {}",
323 deviceId,
324 port,
325 nextId);
Saurav Das423fe2b2015-12-04 10:52:59 -0800326 // Create the bucket to be removed
327 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment
328 .builder();
329 tBuilder.setOutput(port)
330 .setEthDst(dstMac)
331 .setEthSrc(nodeMacAddr);
332 if (ns.getEdgeLabel() != NeighborSet.NO_EDGE_LABEL) {
333 tBuilder.pushMpls()
334 .copyTtlOut()
335 .setMpls(MplsLabel.mplsLabel(ns.getEdgeLabel()));
336 }
337 NextObjective.Builder nextObjBuilder = DefaultNextObjective
338 .builder()
339 .withType(NextObjective.Type.HASHED) //same as original
340 .withId(nextId)
341 .fromApp(appId)
342 .addTreatment(tBuilder.build());
Saurav Das1ce0a7b2016-10-21 14:06:29 -0700343 ObjectiveContext context = new DefaultObjectiveContext(
344 (objective) -> log.debug("portDown removedFrom NextObj {} on {}",
345 nextId, deviceId),
346 (objective, error) ->
347 log.warn("portDown failed to removeFrom NextObj {} on {}: {}",
348 nextId, deviceId, error));
Saurav Das423fe2b2015-12-04 10:52:59 -0800349 NextObjective nextObjective = nextObjBuilder.
Saurav Das1ce0a7b2016-10-21 14:06:29 -0700350 removeFromExisting(context);
sangho834e4b02015-05-01 09:38:25 -0700351
Saurav Das423fe2b2015-12-04 10:52:59 -0800352 flowObjectiveService.next(deviceId, nextObjective);
sangho834e4b02015-05-01 09:38:25 -0700353 }
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800354 }
355
356 devicePortMap.get(portDeviceMap.get(port)).remove(port);
357 portDeviceMap.remove(port);
358 }
359
360 /**
Saurav Das1a129a02016-11-18 15:21:57 -0800361 * Adds or removes a port that has been configured with a subnet to a broadcast group
362 * for bridging. Note that this does not create the broadcast group itself.
Saurav Das018605f2017-02-18 14:05:44 -0800363 * Should only be called by the master instance for this device/port.
Saurav Das1a129a02016-11-18 15:21:57 -0800364 *
365 * @param port the port on this device that needs to be added/removed to a bcast group
366 * @param subnet the subnet corresponding to the broadcast group
367 * @param portUp true if port is enabled, false if disabled
Saurav Das1a129a02016-11-18 15:21:57 -0800368 */
Saurav Das018605f2017-02-18 14:05:44 -0800369 public void processEdgePort(PortNumber port, Ip4Prefix subnet, boolean portUp) {
Saurav Das1a129a02016-11-18 15:21:57 -0800370 //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
Pier Ventre917127a2016-10-31 16:49:19 -0700428 * @param isBos if Bos is set
Saurav Das8a0732e2015-11-20 15:27:53 -0800429 * @return int if found or -1 if there are errors in the creation of the
430 * neighbor set.
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800431 */
Pier Ventre917127a2016-10-31 16:49:19 -0700432 public int getNextObjectiveId(NeighborSet ns, TrafficSelector meta, boolean isBos) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700433 Integer nextId = nsNextObjStore.
434 get(new NeighborSetNextObjectiveStoreKey(deviceId, ns));
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700435 if (nextId == null) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700436 log.trace("getNextObjectiveId in device{}: Next objective id "
437 + "not found for {} and creating", deviceId, ns);
438 log.trace("getNextObjectiveId: nsNextObjStore contents for device {}: {}",
439 deviceId,
440 nsNextObjStore.entrySet()
441 .stream()
442 .filter((nsStoreEntry) ->
443 (nsStoreEntry.getKey().deviceId().equals(deviceId)))
444 .collect(Collectors.toList()));
Pier Ventre917127a2016-10-31 16:49:19 -0700445 createGroupsFromNeighborsets(Collections.singleton(ns), meta, isBos);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700446 nextId = nsNextObjStore.
447 get(new NeighborSetNextObjectiveStoreKey(deviceId, ns));
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700448 if (nextId == null) {
449 log.warn("getNextObjectiveId: unable to create next objective");
450 return -1;
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700451 } else {
452 log.debug("getNextObjectiveId in device{}: Next objective id {} "
Sho SHIMIZUaf973432015-09-11 14:24:50 -0700453 + "created for {}", deviceId, nextId, ns);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700454 }
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700455 } else {
456 log.trace("getNextObjectiveId in device{}: Next objective id {} "
Sho SHIMIZUaf973432015-09-11 14:24:50 -0700457 + "found for {}", deviceId, nextId, ns);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700458 }
Sho SHIMIZUaf973432015-09-11 14:24:50 -0700459 return nextId;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800460 }
461
sangho0b2b6d12015-05-20 22:16:38 -0700462 /**
Saurav Das4ce45962015-11-24 23:21:05 -0800463 * Returns the next objective of type broadcast associated with the subnet,
464 * or -1 if no such objective exists. Note that this method does NOT create
465 * the next objective as a side-effect. It is expected that is objective is
Saurav Das1a129a02016-11-18 15:21:57 -0800466 * created at startup from network configuration. Typically this is used
467 * for L2 flooding within the subnet configured on the switch.
Charles Chanc42e84e2015-10-20 16:24:19 -0700468 *
469 * @param prefix subnet information
470 * @return int if found or -1
471 */
472 public int getSubnetNextObjectiveId(IpPrefix prefix) {
473 Integer nextId = subnetNextObjStore.
474 get(new SubnetNextObjectiveStoreKey(deviceId, prefix));
Charles Chan9f676b62015-10-29 14:58:10 -0700475
476 return (nextId != null) ? nextId : -1;
Charles Chanc42e84e2015-10-20 16:24:19 -0700477 }
478
479 /**
Saurav Das4ce45962015-11-24 23:21:05 -0800480 * Returns the next objective of type simple associated with the port on the
481 * device, given the treatment. Different treatments to the same port result
482 * in different next objectives. If no such objective exists, this method
483 * creates one and returns the id. Optionally metadata can be passed in for
Saurav Das1a129a02016-11-18 15:21:57 -0800484 * the creation of the objective. Typically this is used for L2 and L3 forwarding
485 * to compute nodes and containers/VMs on the compute nodes directly attached
486 * to the switch.
Saurav Das4ce45962015-11-24 23:21:05 -0800487 *
488 * @param portNum the port number for the simple next objective
489 * @param treatment the actions to apply on the packets (should include outport)
490 * @param meta optional metadata passed into the creation of the next objective
491 * @return int if found or created, -1 if there are errors during the
492 * creation of the next objective.
493 */
494 public int getPortNextObjectiveId(PortNumber portNum, TrafficTreatment treatment,
495 TrafficSelector meta) {
Charles Chane849c192016-01-11 18:28:54 -0800496 Integer nextId = portNextObjStore
497 .get(new PortNextObjectiveStoreKey(deviceId, portNum, treatment));
Saurav Das4ce45962015-11-24 23:21:05 -0800498 if (nextId == null) {
499 log.trace("getPortNextObjectiveId in device{}: Next objective id "
500 + "not found for {} and {} creating", deviceId, portNum);
501 createGroupFromPort(portNum, treatment, meta);
502 nextId = portNextObjStore.get(
503 new PortNextObjectiveStoreKey(deviceId, portNum, treatment));
504 if (nextId == null) {
505 log.warn("getPortNextObjectiveId: unable to create next obj"
Charles Chane849c192016-01-11 18:28:54 -0800506 + "for dev:{} port:{}", deviceId, portNum);
507 return -1;
508 }
509 }
510 return nextId;
511 }
512
513 /**
sangho0b2b6d12015-05-20 22:16:38 -0700514 * Checks if the next objective ID (group) for the neighbor set exists or not.
515 *
516 * @param ns neighbor set to check
517 * @return true if it exists, false otherwise
518 */
519 public boolean hasNextObjectiveId(NeighborSet ns) {
520 Integer nextId = nsNextObjStore.
521 get(new NeighborSetNextObjectiveStoreKey(deviceId, ns));
522 if (nextId == null) {
523 return false;
524 }
525
526 return true;
527 }
528
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700529 // Empty implementation
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800530 protected void newNeighbor(Link newLink) {
531 }
532
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700533 // Empty implementation
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800534 protected void newPortToExistingNeighbor(Link newLink) {
535 }
536
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700537 // Empty implementation
538 protected Set<NeighborSet>
539 computeImpactedNeighborsetForPortEvent(DeviceId impactedNeighbor,
540 Set<DeviceId> updatedNeighbors) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800541 return null;
542 }
543
544 private void populateNeighborMaps() {
545 Set<Link> outgoingLinks = linkService.getDeviceEgressLinks(deviceId);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700546 for (Link link : outgoingLinks) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800547 if (link.type() != Link.Type.DIRECT) {
548 continue;
549 }
550 addNeighborAtPort(link.dst().deviceId(), link.src().port());
551 }
552 }
553
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700554 protected void addNeighborAtPort(DeviceId neighborId,
555 PortNumber portToNeighbor) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800556 // Update DeviceToPort database
557 log.debug("Device {} addNeighborAtPort: neighbor {} at port {}",
558 deviceId, neighborId, portToNeighbor);
Saurav Das8a0732e2015-11-20 15:27:53 -0800559 Set<PortNumber> ports = Collections
560 .newSetFromMap(new ConcurrentHashMap<PortNumber, Boolean>());
561 ports.add(portToNeighbor);
562 Set<PortNumber> portnums = devicePortMap.putIfAbsent(neighborId, ports);
563 if (portnums != null) {
564 portnums.add(portToNeighbor);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800565 }
566
567 // Update portToDevice database
Saurav Das8a0732e2015-11-20 15:27:53 -0800568 DeviceId prev = portDeviceMap.putIfAbsent(portToNeighbor, neighborId);
569 if (prev != null) {
570 log.warn("Device: {} port: {} has neighbor: {}. NOT updating "
571 + "to neighbor: {}", deviceId, portToNeighbor, prev, neighborId);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800572 }
573 }
574
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700575 protected Set<Set<DeviceId>> getPowerSetOfNeighbors(Set<DeviceId> neighbors) {
Sho SHIMIZU6cfc02d2015-09-11 11:19:11 -0700576 List<DeviceId> list = new ArrayList<>(neighbors);
577 Set<Set<DeviceId>> sets = new HashSet<>();
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800578 // get the number of elements in the neighbors
579 int elements = list.size();
580 // the number of members of a power set is 2^n
581 // including the empty set
582 int powerElements = (1 << elements);
583
584 // run a binary counter for the number of power elements
585 // NOTE: Exclude empty set
586 for (long i = 1; i < powerElements; i++) {
Sho SHIMIZU6cfc02d2015-09-11 11:19:11 -0700587 Set<DeviceId> neighborSubSet = new HashSet<>();
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800588 for (int j = 0; j < elements; j++) {
589 if ((i >> j) % 2 == 1) {
590 neighborSubSet.add(list.get(j));
591 }
592 }
593 sets.add(neighborSubSet);
594 }
595 return sets;
596 }
597
598 private boolean isSegmentIdSameAsNodeSegmentId(DeviceId deviceId, int sId) {
Charles Chan0b4e6182015-11-03 10:42:14 -0800599 int segmentId;
600 try {
Pier Ventre917127a2016-10-31 16:49:19 -0700601 // IPv6 sid is not inserted. this part of the code is not used for now.
Pier Ventree0ae7a32016-11-23 09:57:42 -0800602 segmentId = deviceConfig.getIPv4SegmentId(deviceId);
Charles Chan0b4e6182015-11-03 10:42:14 -0800603 } catch (DeviceConfigNotFoundException e) {
604 log.warn(e.getMessage() + " Aborting isSegmentIdSameAsNodeSegmentId.");
605 return false;
606 }
607
608 return segmentId == sId;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800609 }
610
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700611 protected List<Integer> getSegmentIdsTobePairedWithNeighborSet(Set<DeviceId> neighbors) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800612
Sho SHIMIZU6cfc02d2015-09-11 11:19:11 -0700613 List<Integer> nsSegmentIds = new ArrayList<>();
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800614
sanghob35a6192015-04-01 13:05:26 -0700615 // Always pair up with no edge label
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700616 // If (neighbors.size() == 1) {
sanghob35a6192015-04-01 13:05:26 -0700617 nsSegmentIds.add(-1);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700618 // }
sanghob35a6192015-04-01 13:05:26 -0700619
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800620 // Filter out SegmentIds matching with the
621 // nodes in the combo
622 for (Integer sId : allSegmentIds) {
Pier Ventree0ae7a32016-11-23 09:57:42 -0800623 if (sId.equals(this.ipv4NodeSegmentId)) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800624 continue;
625 }
626 boolean filterOut = false;
627 // Check if the edge label being set is of
628 // any node in the Neighbor set
629 for (DeviceId deviceId : neighbors) {
630 if (isSegmentIdSameAsNodeSegmentId(deviceId, sId)) {
631 filterOut = true;
632 break;
633 }
634 }
635 if (!filterOut) {
636 nsSegmentIds.add(sId);
637 }
638 }
639 return nsSegmentIds;
640 }
641
sangho1e575652015-05-14 00:39:53 -0700642 /**
Saurav Das1a129a02016-11-18 15:21:57 -0800643 * Creates hash groups from a set of NeighborSet given.
sangho1e575652015-05-14 00:39:53 -0700644 *
645 * @param nsSet a set of NeighborSet
Saurav Das8a0732e2015-11-20 15:27:53 -0800646 * @param meta metadata passed into the creation of a Next Objective
Pier Ventre917127a2016-10-31 16:49:19 -0700647 * @param isBos if BoS is set
sangho1e575652015-05-14 00:39:53 -0700648 */
Saurav Das8a0732e2015-11-20 15:27:53 -0800649 public void createGroupsFromNeighborsets(Set<NeighborSet> nsSet,
Pier Ventre917127a2016-10-31 16:49:19 -0700650 TrafficSelector meta,
651 boolean isBos) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800652 for (NeighborSet ns : nsSet) {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700653 int nextId = flowObjectiveService.allocateNextId();
Pier Ventre917127a2016-10-31 16:49:19 -0700654 NextObjective.Type type = NextObjective.Type.HASHED;
655 Set<DeviceId> neighbors = ns.getDeviceIds();
656 // If Bos == False and MPLS-ECMP == false, we have
657 // to use simple group and we will pick a single neighbor.
658 if (!isBos && !srManager.getMplsEcmp()) {
659 type = NextObjective.Type.SIMPLE;
660 neighbors = Collections.singleton(ns.getFirstNeighbor());
661 }
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700662 NextObjective.Builder nextObjBuilder = DefaultNextObjective
Pier Ventre917127a2016-10-31 16:49:19 -0700663 .builder()
664 .withId(nextId)
665 .withType(type)
666 .fromApp(appId);
667 // For each neighbor, we have to update the sent actions
668 for (DeviceId neighborId : neighbors) {
Saurav Das8a0732e2015-11-20 15:27:53 -0800669 if (devicePortMap.get(neighborId) == null) {
670 log.warn("Neighbor {} is not in the port map yet for dev:{}",
671 neighborId, deviceId);
sangho834e4b02015-05-01 09:38:25 -0700672 return;
Jon Hallcbd1b392017-01-18 20:15:44 -0800673 } else if (devicePortMap.get(neighborId).isEmpty()) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700674 log.warn("There are no ports for "
Saurav Das8a0732e2015-11-20 15:27:53 -0800675 + "the Device {} in the port map yet", neighborId);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700676 return;
sangho834e4b02015-05-01 09:38:25 -0700677 }
678
Saurav Das8a0732e2015-11-20 15:27:53 -0800679 MacAddress neighborMac;
Charles Chan0b4e6182015-11-03 10:42:14 -0800680 try {
Saurav Das8a0732e2015-11-20 15:27:53 -0800681 neighborMac = deviceConfig.getDeviceMac(neighborId);
Charles Chan0b4e6182015-11-03 10:42:14 -0800682 } catch (DeviceConfigNotFoundException e) {
683 log.warn(e.getMessage() + " Aborting createGroupsFromNeighborsets.");
684 return;
685 }
Pier Ventre917127a2016-10-31 16:49:19 -0700686 // For each port, we have to create a new treatment
687 Set<PortNumber> neighborPorts = devicePortMap.get(neighborId);
688 // In this case we are using a SIMPLE group. We randomly pick a port
689 if (!isBos && !srManager.getMplsEcmp()) {
690 int size = devicePortMap.get(neighborId).size();
691 int index = RandomUtils.nextInt(0, size);
692 neighborPorts = Collections.singleton(
693 Iterables.get(devicePortMap.get(neighborId), index)
694 );
695 }
696 for (PortNumber sp : neighborPorts) {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700697 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment
698 .builder();
Saurav Das8a0732e2015-11-20 15:27:53 -0800699 tBuilder.setEthDst(neighborMac)
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700700 .setEthSrc(nodeMacAddr);
701 if (ns.getEdgeLabel() != NeighborSet.NO_EDGE_LABEL) {
Charles Chan68aa62d2015-11-09 16:37:23 -0800702 tBuilder.pushMpls()
703 .copyTtlOut()
704 .setMpls(MplsLabel.mplsLabel(ns.getEdgeLabel()));
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700705 }
Saurav Das8a0732e2015-11-20 15:27:53 -0800706 tBuilder.setOutput(sp);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700707 nextObjBuilder.addTreatment(tBuilder.build());
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800708 }
709 }
Saurav Das8a0732e2015-11-20 15:27:53 -0800710 if (meta != null) {
Saurav Das4ce45962015-11-24 23:21:05 -0800711 nextObjBuilder.withMeta(meta);
Saurav Das8a0732e2015-11-20 15:27:53 -0800712 }
Charles Chan216e3c82016-04-23 14:48:16 -0700713
714 ObjectiveContext context = new DefaultObjectiveContext(
Pier Ventre917127a2016-10-31 16:49:19 -0700715 (objective) ->
716 log.debug("createGroupsFromNeighborsets installed NextObj {} on {}",
Charles Chan216e3c82016-04-23 14:48:16 -0700717 nextId, deviceId),
718 (objective, error) ->
719 log.warn("createGroupsFromNeighborsets failed to install NextObj {} on {}: {}",
Pier Ventre917127a2016-10-31 16:49:19 -0700720 nextId, deviceId, error)
721 );
Charles Chan216e3c82016-04-23 14:48:16 -0700722 NextObjective nextObj = nextObjBuilder.add(context);
723 log.debug("**createGroupsFromNeighborsets: Submited "
Saurav Das8a0732e2015-11-20 15:27:53 -0800724 + "next objective {} in device {}",
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700725 nextId, deviceId);
Saurav Das8a0732e2015-11-20 15:27:53 -0800726 flowObjectiveService.next(deviceId, nextObj);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700727 nsNextObjStore.put(new NeighborSetNextObjectiveStoreKey(deviceId, ns),
728 nextId);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800729 }
730 }
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700731
Saurav Das4ce45962015-11-24 23:21:05 -0800732 /**
Saurav Das1a129a02016-11-18 15:21:57 -0800733 * Creates broadcast groups for all ports in the same subnet for
734 * all configured subnets.
Saurav Das4ce45962015-11-24 23:21:05 -0800735 */
Charles Chanc42e84e2015-10-20 16:24:19 -0700736 public void createGroupsFromSubnetConfig() {
Pier Ventre10bd8d12016-11-26 21:05:22 -0800737 Map<IpPrefix, List<PortNumber>> subnetPortMap;
Saurav Das7a1ffca2016-03-28 19:00:18 -0700738 try {
739 subnetPortMap = this.deviceConfig.getSubnetPortsMap(this.deviceId);
740 } catch (DeviceConfigNotFoundException e) {
741 log.warn(e.getMessage()
742 + " Not creating broadcast groups for device: " + deviceId);
743 return;
744 }
Charles Chanc42e84e2015-10-20 16:24:19 -0700745 // Construct a broadcast group for each subnet
Pier Ventre10bd8d12016-11-26 21:05:22 -0800746 subnetPortMap.forEach((subnet, ports) -> {
747 if (subnet.isIp4()) {
748 createBcastGroupFromSubnet(subnet.getIp4Prefix(), ports);
749 }
750 });
Saurav Das1a129a02016-11-18 15:21:57 -0800751 }
Charles Chan9f676b62015-10-29 14:58:10 -0700752
Saurav Das1a129a02016-11-18 15:21:57 -0800753 /**
754 * Creates a single broadcast group from a given subnet and list of ports.
755 *
756 * @param subnet a configured subnet
757 * @param ports list of ports in the subnet
758 */
759 public void createBcastGroupFromSubnet(Ip4Prefix subnet, List<PortNumber> ports) {
760 SubnetNextObjectiveStoreKey key =
761 new SubnetNextObjectiveStoreKey(deviceId, subnet);
Charles Chan9f676b62015-10-29 14:58:10 -0700762
Saurav Das1a129a02016-11-18 15:21:57 -0800763 if (subnetNextObjStore.containsKey(key)) {
764 log.debug("Broadcast group for device {} and subnet {} exists",
765 deviceId, subnet);
766 return;
767 }
Charles Chan188ebf52015-12-23 00:15:11 -0800768
Saurav Das1a129a02016-11-18 15:21:57 -0800769 VlanId assignedVlanId =
770 srManager.getSubnetAssignedVlanId(this.deviceId, subnet);
771 TrafficSelector metadata =
772 DefaultTrafficSelector.builder().matchVlanId(assignedVlanId).build();
Charles Chanc42e84e2015-10-20 16:24:19 -0700773
Saurav Das1a129a02016-11-18 15:21:57 -0800774 int nextId = flowObjectiveService.allocateNextId();
Charles Chanc42e84e2015-10-20 16:24:19 -0700775
Saurav Das1a129a02016-11-18 15:21:57 -0800776 NextObjective.Builder nextObjBuilder = DefaultNextObjective
777 .builder().withId(nextId)
778 .withType(NextObjective.Type.BROADCAST).fromApp(appId)
779 .withMeta(metadata);
Charles Chanc42e84e2015-10-20 16:24:19 -0700780
Saurav Das1a129a02016-11-18 15:21:57 -0800781 ports.forEach(port -> {
782 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
783 tBuilder.popVlan();
784 tBuilder.setOutput(port);
785 nextObjBuilder.addTreatment(tBuilder.build());
Charles Chanc42e84e2015-10-20 16:24:19 -0700786 });
Saurav Das1a129a02016-11-18 15:21:57 -0800787
788 NextObjective nextObj = nextObjBuilder.add();
789 flowObjectiveService.next(deviceId, nextObj);
790 log.debug("createBcastGroupFromSubnet: Submited next objective {} in device {}",
791 nextId, deviceId);
792
793 subnetNextObjStore.put(key, nextId);
Charles Chanc42e84e2015-10-20 16:24:19 -0700794 }
795
Charles Chane849c192016-01-11 18:28:54 -0800796 /**
Saurav Das4ce45962015-11-24 23:21:05 -0800797 * Create simple next objective for a single port. The treatments can include
798 * all outgoing actions that need to happen on the packet.
799 *
800 * @param portNum the outgoing port on the device
801 * @param treatment the actions to apply on the packets (should include outport)
802 * @param meta optional data to pass to the driver
803 */
804 public void createGroupFromPort(PortNumber portNum, TrafficTreatment treatment,
805 TrafficSelector meta) {
806 int nextId = flowObjectiveService.allocateNextId();
807 PortNextObjectiveStoreKey key = new PortNextObjectiveStoreKey(
808 deviceId, portNum, treatment);
809
810 NextObjective.Builder nextObjBuilder = DefaultNextObjective
811 .builder().withId(nextId)
812 .withType(NextObjective.Type.SIMPLE)
813 .addTreatment(treatment)
814 .fromApp(appId)
815 .withMeta(meta);
816
817 NextObjective nextObj = nextObjBuilder.add();
818 flowObjectiveService.next(deviceId, nextObj);
819 log.debug("createGroupFromPort: Submited next objective {} in device {} "
820 + "for port {}", nextId, deviceId, portNum);
821
822 portNextObjStore.put(key, nextId);
823 }
824
sangho1e575652015-05-14 00:39:53 -0700825 /**
826 * Removes groups for the next objective ID given.
827 *
828 * @param objectiveId next objective ID to remove
829 * @return true if succeeds, false otherwise
830 */
831 public boolean removeGroup(int objectiveId) {
832
833 if (nsNextObjStore.containsValue(objectiveId)) {
834 NextObjective.Builder nextObjBuilder = DefaultNextObjective
835 .builder().withId(objectiveId)
836 .withType(NextObjective.Type.HASHED).fromApp(appId);
Charles Chan216e3c82016-04-23 14:48:16 -0700837 ObjectiveContext context = new DefaultObjectiveContext(
838 (objective) -> log.debug("RemoveGroup removes NextObj {} on {}",
839 objectiveId, deviceId),
840 (objective, error) ->
841 log.warn("RemoveGroup failed to remove NextObj {} on {}: {}",
842 objectiveId, deviceId, error));
843 NextObjective nextObjective = nextObjBuilder.remove(context);
Saurav Das8a0732e2015-11-20 15:27:53 -0800844 log.info("**removeGroup: Submited "
845 + "next objective {} in device {}",
846 objectiveId, deviceId);
sangho1e575652015-05-14 00:39:53 -0700847 flowObjectiveService.next(deviceId, nextObjective);
848
849 for (Map.Entry<NeighborSetNextObjectiveStoreKey, Integer> entry: nsNextObjStore.entrySet()) {
850 if (entry.getValue().equals(objectiveId)) {
851 nsNextObjStore.remove(entry.getKey());
852 break;
853 }
854 }
sangho0b2b6d12015-05-20 22:16:38 -0700855 return true;
sangho1e575652015-05-14 00:39:53 -0700856 }
857
858 return false;
859 }
Srikanth Vavilapallif3a8bc02015-05-22 13:47:31 -0700860
Charles Chane849c192016-01-11 18:28:54 -0800861 /**
862 * Removes all groups from all next objective stores.
863 */
Saurav Das423fe2b2015-12-04 10:52:59 -0800864 public void removeAllGroups() {
865 for (Map.Entry<NeighborSetNextObjectiveStoreKey, Integer> entry:
866 nsNextObjStore.entrySet()) {
867 removeGroup(entry.getValue());
868 }
869 for (Map.Entry<PortNextObjectiveStoreKey, Integer> entry:
870 portNextObjStore.entrySet()) {
871 removeGroup(entry.getValue());
872 }
873 for (Map.Entry<SubnetNextObjectiveStoreKey, Integer> entry:
874 subnetNextObjStore.entrySet()) {
875 removeGroup(entry.getValue());
876 }
877 // should probably clean local stores port-neighbor
878 }
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800879}