blob: 6f06d60b99a74a1a7efeed6822a8483a06a72996 [file] [log] [blame]
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -08001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2015-present Open Networking Foundation
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -08003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -070016package org.onosproject.segmentrouting.grouphandler;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080017
Charles Chan59cc16d2017-02-02 16:20:42 -080018
Saurav Das7bcbe702017-06-13 15:35:54 -070019import com.google.common.collect.ImmutableSet;
Pier Ventre917127a2016-10-31 16:49:19 -070020import com.google.common.collect.Iterables;
Saurav Dasc88d4662017-05-15 15:34:25 -070021import com.google.common.collect.Sets;
22
Pier Ventre917127a2016-10-31 16:49:19 -070023import org.apache.commons.lang3.RandomUtils;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080024import org.onlab.packet.MacAddress;
sangho32a59322015-02-17 12:07:41 -080025import org.onlab.packet.MplsLabel;
Saurav Das423fe2b2015-12-04 10:52:59 -080026import org.onlab.packet.VlanId;
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -070027import org.onlab.util.KryoNamespace;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080028import org.onosproject.core.ApplicationId;
Charles Chan59cc16d2017-02-02 16:20:42 -080029import org.onosproject.net.ConnectPoint;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080030import org.onosproject.net.DeviceId;
31import org.onosproject.net.Link;
32import org.onosproject.net.PortNumber;
Saurav Das423fe2b2015-12-04 10:52:59 -080033import org.onosproject.net.flow.DefaultTrafficSelector;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080034import org.onosproject.net.flow.DefaultTrafficTreatment;
Saurav Das8a0732e2015-11-20 15:27:53 -080035import org.onosproject.net.flow.TrafficSelector;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080036import org.onosproject.net.flow.TrafficTreatment;
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070037import org.onosproject.net.flowobjective.DefaultNextObjective;
Charles Chan216e3c82016-04-23 14:48:16 -070038import org.onosproject.net.flowobjective.DefaultObjectiveContext;
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070039import org.onosproject.net.flowobjective.FlowObjectiveService;
40import org.onosproject.net.flowobjective.NextObjective;
Srikanth Vavilapallif3a8bc02015-05-22 13:47:31 -070041import org.onosproject.net.flowobjective.ObjectiveContext;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080042import org.onosproject.net.link.LinkService;
Saurav Dasceccf242017-08-03 18:30:35 -070043import org.onosproject.segmentrouting.DefaultRoutingHandler;
Saurav Das423fe2b2015-12-04 10:52:59 -080044import org.onosproject.segmentrouting.SegmentRoutingManager;
Charles Chan0b4e6182015-11-03 10:42:14 -080045import org.onosproject.segmentrouting.config.DeviceConfigNotFoundException;
46import org.onosproject.segmentrouting.config.DeviceProperties;
Saurav Das7bcbe702017-06-13 15:35:54 -070047import org.onosproject.segmentrouting.storekey.DestinationSetNextObjectiveStoreKey;
Charles Chand2990362016-04-18 13:44:03 -070048import org.onosproject.segmentrouting.storekey.PortNextObjectiveStoreKey;
Charles Chan59cc16d2017-02-02 16:20:42 -080049import org.onosproject.segmentrouting.storekey.VlanNextObjectiveStoreKey;
Srikanth Vavilapalli23181912015-05-04 09:48:09 -070050import org.onosproject.store.service.EventuallyConsistentMap;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080051import org.slf4j.Logger;
52
Pier Ventre917127a2016-10-31 16:49:19 -070053import java.net.URI;
Charles Chan7ffd81f2017-02-08 15:52:08 -080054import java.util.Collection;
Pier Ventre917127a2016-10-31 16:49:19 -070055import java.util.Collections;
Saurav Dasc88d4662017-05-15 15:34:25 -070056import java.util.HashMap;
Pier Ventre917127a2016-10-31 16:49:19 -070057import java.util.HashSet;
58import java.util.List;
59import java.util.Map;
60import java.util.Set;
61import java.util.concurrent.ConcurrentHashMap;
Saurav Das1547b3f2017-05-05 17:01:08 -070062import java.util.concurrent.ScheduledExecutorService;
63import java.util.concurrent.TimeUnit;
Pier Ventre917127a2016-10-31 16:49:19 -070064import java.util.stream.Collectors;
65
66import static com.google.common.base.Preconditions.checkNotNull;
Saurav Das1547b3f2017-05-05 17:01:08 -070067import static java.util.concurrent.Executors.newScheduledThreadPool;
68import static org.onlab.util.Tools.groupedThreads;
Charles Chan59cc16d2017-02-02 16:20:42 -080069import static org.onosproject.segmentrouting.SegmentRoutingManager.INTERNAL_VLAN;
Pier Ventre917127a2016-10-31 16:49:19 -070070import static org.slf4j.LoggerFactory.getLogger;
71
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080072/**
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070073 * Default ECMP group handler creation module. This component creates a set of
74 * ECMP groups for every neighbor that this device is connected to based on
75 * whether the current device is an edge device or a transit device.
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080076 */
77public class DefaultGroupHandler {
Srikanth Vavilapallif3a8bc02015-05-22 13:47:31 -070078 protected static final Logger log = getLogger(DefaultGroupHandler.class);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080079
Saurav Dasceccf242017-08-03 18:30:35 -070080 private static final long VERIFY_INTERVAL = 30; // secs
81
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080082 protected final DeviceId deviceId;
83 protected final ApplicationId appId;
84 protected final DeviceProperties deviceConfig;
85 protected final List<Integer> allSegmentIds;
Pier Ventree0ae7a32016-11-23 09:57:42 -080086 protected int ipv4NodeSegmentId = -1;
87 protected int ipv6NodeSegmentId = -1;
Charles Chan0b4e6182015-11-03 10:42:14 -080088 protected boolean isEdgeRouter = false;
89 protected MacAddress nodeMacAddr = null;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080090 protected LinkService linkService;
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070091 protected FlowObjectiveService flowObjectiveService;
Saurav Dasc88d4662017-05-15 15:34:25 -070092 /**
93 * local store for neighbor-device-ids and the set of ports on this device
94 * that connect to the same neighbor.
95 */
Saurav Das8a0732e2015-11-20 15:27:53 -080096 protected ConcurrentHashMap<DeviceId, Set<PortNumber>> devicePortMap =
97 new ConcurrentHashMap<>();
Saurav Dasc88d4662017-05-15 15:34:25 -070098 /**
99 * local store for ports on this device connected to neighbor-device-id.
100 */
Saurav Das8a0732e2015-11-20 15:27:53 -0800101 protected ConcurrentHashMap<PortNumber, DeviceId> portDeviceMap =
102 new ConcurrentHashMap<>();
Saurav Dasc88d4662017-05-15 15:34:25 -0700103
Saurav Das7bcbe702017-06-13 15:35:54 -0700104 // distributed store for (device+destination-set) mapped to next-id and neighbors
105 protected EventuallyConsistentMap<DestinationSetNextObjectiveStoreKey, NextNeighbors>
106 dsNextObjStore = null;
Saurav Das1a129a02016-11-18 15:21:57 -0800107 // distributed store for (device+subnet-ip-prefix) mapped to next-id
Charles Chan59cc16d2017-02-02 16:20:42 -0800108 protected EventuallyConsistentMap<VlanNextObjectiveStoreKey, Integer>
109 vlanNextObjStore = null;
Saurav Das1a129a02016-11-18 15:21:57 -0800110 // distributed store for (device+port+treatment) mapped to next-id
Charles Chane849c192016-01-11 18:28:54 -0800111 protected EventuallyConsistentMap<PortNextObjectiveStoreKey, Integer>
112 portNextObjStore = null;
Charles Chan188ebf52015-12-23 00:15:11 -0800113 private SegmentRoutingManager srManager;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800114
Saurav Das1547b3f2017-05-05 17:01:08 -0700115 private ScheduledExecutorService executorService
Saurav Dasceccf242017-08-03 18:30:35 -0700116 = newScheduledThreadPool(1, groupedThreads("bktCorrector", "bktC-%d", log));
Saurav Das1547b3f2017-05-05 17:01:08 -0700117
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700118 protected KryoNamespace.Builder kryo = new KryoNamespace.Builder()
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700119 .register(URI.class).register(HashSet.class)
Saurav Das7bcbe702017-06-13 15:35:54 -0700120 .register(DeviceId.class).register(PortNumber.class)
121 .register(DestinationSet.class).register(PolicyGroupIdentifier.class)
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700122 .register(PolicyGroupParams.class)
123 .register(GroupBucketIdentifier.class)
124 .register(GroupBucketIdentifier.BucketOutputType.class);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800125
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700126 protected DefaultGroupHandler(DeviceId deviceId, ApplicationId appId,
127 DeviceProperties config,
128 LinkService linkService,
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700129 FlowObjectiveService flowObjService,
Charles Chan188ebf52015-12-23 00:15:11 -0800130 SegmentRoutingManager srManager) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800131 this.deviceId = checkNotNull(deviceId);
132 this.appId = checkNotNull(appId);
133 this.deviceConfig = checkNotNull(config);
134 this.linkService = checkNotNull(linkService);
Charles Chan0b4e6182015-11-03 10:42:14 -0800135 this.allSegmentIds = checkNotNull(config.getAllDeviceSegmentIds());
136 try {
Pier Ventree0ae7a32016-11-23 09:57:42 -0800137 this.ipv4NodeSegmentId = config.getIPv4SegmentId(deviceId);
138 this.ipv6NodeSegmentId = config.getIPv6SegmentId(deviceId);
Charles Chan0b4e6182015-11-03 10:42:14 -0800139 this.isEdgeRouter = config.isEdgeDevice(deviceId);
140 this.nodeMacAddr = checkNotNull(config.getDeviceMac(deviceId));
141 } catch (DeviceConfigNotFoundException e) {
142 log.warn(e.getMessage()
143 + " Skipping value assignment in DefaultGroupHandler");
144 }
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700145 this.flowObjectiveService = flowObjService;
Saurav Das7bcbe702017-06-13 15:35:54 -0700146 this.dsNextObjStore = srManager.dsNextObjStore();
Ray Milkeye4afdb52017-04-05 09:42:04 -0700147 this.vlanNextObjStore = srManager.vlanNextObjStore();
148 this.portNextObjStore = srManager.portNextObjStore();
Charles Chan188ebf52015-12-23 00:15:11 -0800149 this.srManager = srManager;
Saurav Dasceccf242017-08-03 18:30:35 -0700150 executorService.scheduleWithFixedDelay(new BucketCorrector(), 10,
151 VERIFY_INTERVAL,
152 TimeUnit.SECONDS);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800153 populateNeighborMaps();
154 }
155
156 /**
Saurav Dasceccf242017-08-03 18:30:35 -0700157 * Gracefully shuts down a groupHandler. Typically called when the handler is
158 * no longer needed.
159 */
160 public void shutdown() {
161 executorService.shutdown();
162 }
163
164 /**
Saurav Dasc88d4662017-05-15 15:34:25 -0700165 * Creates a group handler object.
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800166 *
167 * @param deviceId device identifier
168 * @param appId application identifier
169 * @param config interface to retrieve the device properties
170 * @param linkService link service object
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700171 * @param flowObjService flow objective service object
Charles Chane849c192016-01-11 18:28:54 -0800172 * @param srManager segment routing manager
Charles Chan0b4e6182015-11-03 10:42:14 -0800173 * @throws DeviceConfigNotFoundException if the device configuration is not found
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800174 * @return default group handler type
175 */
Saurav Das4ce45962015-11-24 23:21:05 -0800176 public static DefaultGroupHandler createGroupHandler(
Saurav Dasceccf242017-08-03 18:30:35 -0700177 DeviceId deviceId,
178 ApplicationId appId,
179 DeviceProperties config,
180 LinkService linkService,
181 FlowObjectiveService flowObjService,
182 SegmentRoutingManager srManager)
183 throws DeviceConfigNotFoundException {
Saurav Dasc88d4662017-05-15 15:34:25 -0700184 return new DefaultGroupHandler(deviceId, appId, config,
185 linkService,
186 flowObjService,
187 srManager);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800188 }
189
190 /**
Saurav Dasc88d4662017-05-15 15:34:25 -0700191 * Updates local stores for link-src device/port to neighbor (link-dst).
192 *
193 * @param link the infrastructure link
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800194 */
Saurav Dasc88d4662017-05-15 15:34:25 -0700195 public void portUpForLink(Link link) {
Saurav Dasceccf242017-08-03 18:30:35 -0700196 if (!link.src().deviceId().equals(deviceId)) {
197 log.warn("linkUp: deviceId{} doesn't match with link src {}",
198 deviceId, link.src().deviceId());
199 return;
200 }
Saurav Dasc88d4662017-05-15 15:34:25 -0700201
Saurav Dasceccf242017-08-03 18:30:35 -0700202 log.info("* portUpForLink: Device {} linkUp at local port {} to "
203 + "neighbor {}", deviceId, link.src().port(), link.dst().deviceId());
204 // ensure local state is updated even if linkup is aborted later on
205 addNeighborAtPort(link.dst().deviceId(),
206 link.src().port());
207 }
Saurav Dasc88d4662017-05-15 15:34:25 -0700208
Saurav Dasceccf242017-08-03 18:30:35 -0700209 /**
210 * Updates local stores for port that has gone down.
211 *
212 * @param port port number that has gone down
213 */
214 public void portDown(PortNumber port) {
215 if (portDeviceMap.get(port) == null) {
216 log.warn("portDown: unknown port");
217 return;
218 }
Saurav Dasc88d4662017-05-15 15:34:25 -0700219
Saurav Dasceccf242017-08-03 18:30:35 -0700220 log.debug("Device {} portDown {} to neighbor {}", deviceId, port,
221 portDeviceMap.get(port));
222 devicePortMap.get(portDeviceMap.get(port)).remove(port);
223 portDeviceMap.remove(port);
224 }
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800225
226 /**
Saurav Dasc88d4662017-05-15 15:34:25 -0700227 * Checks all groups in the src-device of link for neighbor sets that include
228 * the dst-device of link, and edits the hash groups according to link up
229 * or down. Should only be called by the master instance of the src-switch
230 * of link. Typically used when there are no route-path changes due to the
231 * link up or down, as the ECMPspg does not change.
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800232 *
Saurav Dasc88d4662017-05-15 15:34:25 -0700233 * @param link the infrastructure link that has gone down or come up
234 * @param linkDown true if link has gone down
235 * @param firstTime true if link has come up for the first time i.e a link
236 * not seen-before
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800237 */
Saurav Dasc88d4662017-05-15 15:34:25 -0700238 public void retryHash(Link link, boolean linkDown, boolean firstTime) {
Charles Chan0b4e6182015-11-03 10:42:14 -0800239 MacAddress dstMac;
240 try {
Saurav Dasc88d4662017-05-15 15:34:25 -0700241 dstMac = deviceConfig.getDeviceMac(link.dst().deviceId());
Charles Chan0b4e6182015-11-03 10:42:14 -0800242 } catch (DeviceConfigNotFoundException e) {
Saurav Dasc88d4662017-05-15 15:34:25 -0700243 log.warn(e.getMessage() + " Aborting retryHash.");
Charles Chan0b4e6182015-11-03 10:42:14 -0800244 return;
245 }
Saurav Das7bcbe702017-06-13 15:35:54 -0700246 // find all the destinationSets related to link
247 Set<DestinationSetNextObjectiveStoreKey> dsKeySet = dsNextObjStore.entrySet()
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700248 .stream()
Saurav Das7bcbe702017-06-13 15:35:54 -0700249 .filter(entry -> entry.getKey().deviceId().equals(deviceId))
250 .filter(entry -> entry.getValue().containsNextHop(link.dst().deviceId()))
251 .map(entry -> entry.getKey())
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700252 .collect(Collectors.toSet());
Saurav Dasc88d4662017-05-15 15:34:25 -0700253
Saurav Das7bcbe702017-06-13 15:35:54 -0700254 log.debug("retryHash: dsNextObjStore contents for linkSrc {} -> linkDst {}: {}",
255 deviceId, link.dst().deviceId(), dsKeySet);
256
257 for (DestinationSetNextObjectiveStoreKey dsKey : dsKeySet) {
258 NextNeighbors nextHops = dsNextObjStore.get(dsKey);
259 if (nextHops == null) {
Saurav Dasc88d4662017-05-15 15:34:25 -0700260 log.warn("retryHash in device {}, but global store has no record "
Saurav Das7bcbe702017-06-13 15:35:54 -0700261 + "for dsKey:{}", deviceId, dsKey);
Saurav Dasc88d4662017-05-15 15:34:25 -0700262 continue;
263 }
Saurav Das7bcbe702017-06-13 15:35:54 -0700264 int nextId = nextHops.nextId();
265 Set<DeviceId> dstSet = nextHops.getDstForNextHop(link.dst().deviceId());
Saurav Dasc88d4662017-05-15 15:34:25 -0700266 if (!linkDown) {
Saurav Das7bcbe702017-06-13 15:35:54 -0700267 dstSet.forEach(dst -> {
268 int edgeLabel = dsKey.destinationSet().getEdgeLabel(dst);
269 addToHashedNextObjective(link.src().port(), dstMac,
Saurav Dasceccf242017-08-03 18:30:35 -0700270 edgeLabel, nextId);
Saurav Das7bcbe702017-06-13 15:35:54 -0700271 });
272
Saurav Dasc88d4662017-05-15 15:34:25 -0700273 if (firstTime) {
274 // some links may have come up before the next-objective was created
275 // we take this opportunity to ensure other ports to same next-hop-dst
276 // are part of the hash group (see CORD-1180). Duplicate additions
277 // to the same hash group are avoided by the driver.
278 for (PortNumber p : devicePortMap.get(link.dst().deviceId())) {
279 if (p.equals(link.src().port())) {
280 continue;
281 }
Saurav Das7bcbe702017-06-13 15:35:54 -0700282 dstSet.forEach(dst -> {
283 int edgeLabel = dsKey.destinationSet().getEdgeLabel(dst);
Saurav Dasceccf242017-08-03 18:30:35 -0700284 addToHashedNextObjective(p, dstMac, edgeLabel, nextId);
Saurav Das7bcbe702017-06-13 15:35:54 -0700285 });
Saurav Dasc88d4662017-05-15 15:34:25 -0700286 }
287 }
288 } else {
Saurav Das7bcbe702017-06-13 15:35:54 -0700289 dstSet.forEach(dst -> {
290 int edgeLabel = dsKey.destinationSet().getEdgeLabel(dst);
291 removeFromHashedNextObjective(link.src().port(), dstMac,
292 edgeLabel, nextId);
293 });
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700294 }
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800295 }
Saurav Das1547b3f2017-05-05 17:01:08 -0700296 }
297
Saurav Dasc88d4662017-05-15 15:34:25 -0700298 /**
299 * Makes a call to the FlowObjective service to add a single bucket to
300 * a hashed group.
301 *
302 * @param outport port to add to hash group
303 * @param dstMac destination mac address of next-hop
Saurav Das7bcbe702017-06-13 15:35:54 -0700304 * @param edgeLabel the label to use in the bucket
Saurav Dasc88d4662017-05-15 15:34:25 -0700305 * @param nextId id for next-objective to which the bucket will be added
Saurav Dasceccf242017-08-03 18:30:35 -0700306 *
Saurav Dasc88d4662017-05-15 15:34:25 -0700307 */
Saurav Das1547b3f2017-05-05 17:01:08 -0700308 private void addToHashedNextObjective(PortNumber outport, MacAddress dstMac,
Saurav Dasceccf242017-08-03 18:30:35 -0700309 int edgeLabel, Integer nextId) {
Saurav Das1547b3f2017-05-05 17:01:08 -0700310 // Create the new bucket to be updated
311 TrafficTreatment.Builder tBuilder =
312 DefaultTrafficTreatment.builder();
313 tBuilder.setOutput(outport)
314 .setEthDst(dstMac)
315 .setEthSrc(nodeMacAddr);
Saurav Das7bcbe702017-06-13 15:35:54 -0700316 if (edgeLabel != DestinationSet.NO_EDGE_LABEL) {
Saurav Das1547b3f2017-05-05 17:01:08 -0700317 tBuilder.pushMpls()
318 .copyTtlOut()
Saurav Das7bcbe702017-06-13 15:35:54 -0700319 .setMpls(MplsLabel.mplsLabel(edgeLabel));
Saurav Das1547b3f2017-05-05 17:01:08 -0700320 }
321 // setup metadata to pass to nextObjective - indicate the vlan on egress
322 // if needed by the switch pipeline. Since hashed next-hops are always to
323 // other neighboring routers, there is no subnet assigned on those ports.
324 TrafficSelector.Builder metabuilder = DefaultTrafficSelector.builder();
325 metabuilder.matchVlanId(INTERNAL_VLAN);
326
327 NextObjective.Builder nextObjBuilder = DefaultNextObjective.builder()
328 .withId(nextId)
329 .withType(NextObjective.Type.HASHED)
330 .addTreatment(tBuilder.build())
331 .withMeta(metabuilder.build())
332 .fromApp(appId);
Saurav Dasceccf242017-08-03 18:30:35 -0700333 log.debug("addToHash in device {}: Adding Bucket with port/label {}/{} "
334 + "to nextId {}", deviceId, outport, edgeLabel, nextId);
Saurav Das1547b3f2017-05-05 17:01:08 -0700335
336 ObjectiveContext context = new DefaultObjectiveContext(
Saurav Dasceccf242017-08-03 18:30:35 -0700337 (objective) -> log.debug("addToHash addedTo NextObj {} on {}",
Saurav Dasc88d4662017-05-15 15:34:25 -0700338 nextId, deviceId),
Saurav Das1547b3f2017-05-05 17:01:08 -0700339 (objective, error) ->
Saurav Dasceccf242017-08-03 18:30:35 -0700340 log.warn("addToHash failed to addTo NextObj {} on {}: {}",
Saurav Dasc88d4662017-05-15 15:34:25 -0700341 nextId, deviceId, error));
Saurav Das1547b3f2017-05-05 17:01:08 -0700342 NextObjective nextObjective = nextObjBuilder.addToExisting(context);
343 flowObjectiveService.next(deviceId, nextObjective);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800344 }
345
346 /**
Saurav Dasceccf242017-08-03 18:30:35 -0700347 * Makes a call to the FlowObjective service to remove a single bucket from
348 * a hashed group.
349 *
350 * @param port port to remove from hash group
351 * @param dstMac destination mac address of next-hop
352 * @param edgeLabel the label to use in the bucket
353 * @param nextId id for next-objective from which the bucket will be removed
354 */
355 private void removeFromHashedNextObjective(PortNumber port, MacAddress dstMac,
356 int edgeLabel, Integer nextId) {
357 // Create the bucket to be removed
358 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment
359 .builder();
360 tBuilder.setOutput(port)
361 .setEthDst(dstMac)
362 .setEthSrc(nodeMacAddr);
363 if (edgeLabel != DestinationSet.NO_EDGE_LABEL) {
364 tBuilder.pushMpls()
365 .copyTtlOut()
366 .setMpls(MplsLabel.mplsLabel(edgeLabel));
367 }
368 log.info("{} in device {}: Removing Bucket with Port {} to next object id {}",
369 "removeFromHash", deviceId, port, nextId);
370 NextObjective.Builder nextObjBuilder = DefaultNextObjective
371 .builder()
372 .withType(NextObjective.Type.HASHED) //same as original
373 .withId(nextId)
374 .fromApp(appId)
375 .addTreatment(tBuilder.build());
376 ObjectiveContext context = new DefaultObjectiveContext(
377 (objective) -> log.debug("port {} removedFrom NextObj {} on {}",
378 port, nextId, deviceId),
379 (objective, error) ->
380 log.warn("port {} failed to removeFrom NextObj {} on {}: {}",
381 port, nextId, deviceId, error));
382 NextObjective nextObjective = nextObjBuilder.
383 removeFromExisting(context);
Saurav Dasc88d4662017-05-15 15:34:25 -0700384
Saurav Dasceccf242017-08-03 18:30:35 -0700385 flowObjectiveService.next(deviceId, nextObjective);
386 }
Saurav Dasc88d4662017-05-15 15:34:25 -0700387
388 /**
389 * Checks all the hash-groups in the target-switch meant for the destination
390 * switch, and either adds or removes buckets to make the neighbor-set
391 * match the given next-hops. Typically called by the master instance of the
392 * destination switch, which may be different from the master instance of the
393 * target switch where hash-group changes are made.
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800394 *
Saurav Dasc88d4662017-05-15 15:34:25 -0700395 * @param targetSw the switch in which the hash groups will be edited
396 * @param nextHops the current next hops for the target switch to reach
397 * the dest sw
398 * @param destSw the destination switch
399 * @param revoke true if hash groups need to remove buckets from the
400 * the groups to match the current next hops
401 * @return true if calls are made to edit buckets, or if no edits are required
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800402 */
Saurav Dasc88d4662017-05-15 15:34:25 -0700403 public boolean fixHashGroups(DeviceId targetSw, Set<DeviceId> nextHops,
404 DeviceId destSw, boolean revoke) {
405 // temporary storage of keys to be updated
Saurav Das7bcbe702017-06-13 15:35:54 -0700406 Map<DestinationSetNextObjectiveStoreKey, Set<DeviceId>> tempStore =
Saurav Dasc88d4662017-05-15 15:34:25 -0700407 new HashMap<>();
408 boolean foundNextObjective = false;
Charles Chan0b4e6182015-11-03 10:42:14 -0800409
Saurav Das7bcbe702017-06-13 15:35:54 -0700410 // retrieve hash-groups meant for destSw, which have destinationSets
Saurav Dasc88d4662017-05-15 15:34:25 -0700411 // with different neighbors than the given next-hops
Saurav Das7bcbe702017-06-13 15:35:54 -0700412 for (DestinationSetNextObjectiveStoreKey dskey : dsNextObjStore.keySet()) {
413 if (!dskey.deviceId().equals(targetSw) ||
414 !dskey.destinationSet().getDestinationSwitches().contains(destSw)) {
Saurav Dasc88d4662017-05-15 15:34:25 -0700415 continue;
416 }
417 foundNextObjective = true;
Saurav Das7bcbe702017-06-13 15:35:54 -0700418 NextNeighbors nhops = dsNextObjStore.get(dskey);
419 Set<DeviceId> currNeighbors = nhops.nextHops(destSw);
420 int edgeLabel = dskey.destinationSet().getEdgeLabel(destSw);
421 Integer nextId = nhops.nextId();
Charles Chan0b4e6182015-11-03 10:42:14 -0800422
Saurav Dasc88d4662017-05-15 15:34:25 -0700423 Set<DeviceId> diff;
424 if (revoke) {
425 diff = Sets.difference(currNeighbors, nextHops);
426 log.debug("targetSw:{} -> dstSw:{} in nextId:{} has current next "
427 + "hops:{} ..removing {}", targetSw, destSw, nextId,
428 currNeighbors, diff);
429 } else {
430 diff = Sets.difference(nextHops, currNeighbors);
431 log.debug("targetSw:{} -> dstSw:{} in nextId:{} has current next "
432 + "hops:{} ..adding {}", targetSw, destSw, nextId,
433 currNeighbors, diff);
434 }
435 for (DeviceId neighbor : diff) {
436 MacAddress dstMac;
437 try {
438 dstMac = deviceConfig.getDeviceMac(neighbor);
439 } catch (DeviceConfigNotFoundException e) {
440 log.warn(e.getMessage() + " Aborting fixHashGroup for nextId:"
Saurav Das7bcbe702017-06-13 15:35:54 -0700441 + nextId);
Saurav Dasc88d4662017-05-15 15:34:25 -0700442 return false;
Saurav Das423fe2b2015-12-04 10:52:59 -0800443 }
Saurav Dasc88d4662017-05-15 15:34:25 -0700444 if (devicePortMap.get(neighbor) == null ||
445 devicePortMap.get(neighbor).isEmpty()) {
446 log.warn("No ports found in dev:{} for neighbor:{} .. cannot "
447 + "fix hash group for nextId: {}",
448 deviceId, neighbor, nextId);
449 return false;
450 }
451 if (revoke) {
452 for (PortNumber port : devicePortMap.get(neighbor)) {
453 log.info("fixHashGroup in device {}: Removing Bucket "
454 + "with Port {} to next object id {}",
455 deviceId, port, nextId);
456 removeFromHashedNextObjective(port, dstMac,
Saurav Das7bcbe702017-06-13 15:35:54 -0700457 edgeLabel,
Saurav Dasc88d4662017-05-15 15:34:25 -0700458 nextId);
459 }
460 // to update neighbor set with changes made
Saurav Das7bcbe702017-06-13 15:35:54 -0700461 tempStore.put(dskey, Sets.difference(currNeighbors, diff));
Saurav Dasc88d4662017-05-15 15:34:25 -0700462 } else {
463 for (PortNumber port : devicePortMap.get(neighbor)) {
464 log.info("fixHashGroup in device {}: Adding Bucket "
465 + "with Port {} to next object id {}",
466 deviceId, port, nextId);
Saurav Dasceccf242017-08-03 18:30:35 -0700467 addToHashedNextObjective(port, dstMac, edgeLabel, nextId);
Saurav Dasc88d4662017-05-15 15:34:25 -0700468 }
469 // to update neighbor set with changes made
Saurav Das7bcbe702017-06-13 15:35:54 -0700470 tempStore.put(dskey, Sets.union(currNeighbors, diff));
Saurav Dasc88d4662017-05-15 15:34:25 -0700471 }
sangho834e4b02015-05-01 09:38:25 -0700472 }
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800473 }
474
Saurav Dasc88d4662017-05-15 15:34:25 -0700475 if (!foundNextObjective) {
476 log.debug("Cannot find any nextObjectives for route targetSw:{} "
477 + "-> dstSw:{}", targetSw, destSw);
478 return true; // nothing to do, return true so ECMPspg is updated
479 }
480
Saurav Das7bcbe702017-06-13 15:35:54 -0700481 // update the dsNextObjectiveStore with new destinationSet to nextId mappings
482 for (DestinationSetNextObjectiveStoreKey key : tempStore.keySet()) {
483 NextNeighbors oldHops = dsNextObjStore.get(key);
484 if (oldHops == null) {
Saurav Dasc88d4662017-05-15 15:34:25 -0700485 continue;
486 }
Saurav Das7bcbe702017-06-13 15:35:54 -0700487 Set<DeviceId> newNeighbors = tempStore.get(key);
488 Set<DeviceId> oldNeighbors = ImmutableSet.copyOf(oldHops.nextHops(destSw));
489 oldHops.dstNextHops().put(destSw, newNeighbors);
490 log.debug("Updating nsNextObjStore: oldHops:{} -> newHops:{} :: nextId:{}",
491 oldNeighbors, newNeighbors, oldHops.nextId());
Saurav Dasc88d4662017-05-15 15:34:25 -0700492 }
493
494 return true;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800495 }
496
Saurav Dasceccf242017-08-03 18:30:35 -0700497 /**
498 * Updates the DestinationSetNextObjectiveStore with any per-destination nexthops
499 * that are not already in the store for the given DestinationSet. Note that
500 * this method does not remove existing next hops for the destinations in the
501 * DestinationSet.
502 *
503 * @param ds the DestinationSet for which the next hops need to be updated
504 * @param newDstNextHops a map of per-destination next hops to update the
505 * destinationSet with
506 * @return true if successful in updating all next hops
507 */
508 private boolean updateNextHops(DestinationSet ds,
Saurav Das7bcbe702017-06-13 15:35:54 -0700509 Map<DeviceId, Set<DeviceId>> newDstNextHops) {
510 DestinationSetNextObjectiveStoreKey key =
511 new DestinationSetNextObjectiveStoreKey(deviceId, ds);
512 NextNeighbors currNext = dsNextObjStore.get(key);
513 Map<DeviceId, Set<DeviceId>> currDstNextHops = currNext.dstNextHops();
514
515 // add newDstNextHops to currDstNextHops for each dst
516 boolean success = true;
517 for (DeviceId dstSw : ds.getDestinationSwitches()) {
518 Set<DeviceId> currNhops = currDstNextHops.get(dstSw);
519 Set<DeviceId> newNhops = newDstNextHops.get(dstSw);
520 currNhops = (currNhops == null) ? Sets.newHashSet() : currNhops;
521 newNhops = (newNhops == null) ? Sets.newHashSet() : newNhops;
522 int edgeLabel = ds.getEdgeLabel(dstSw);
523 int nextId = currNext.nextId();
524
525 // new next hops should be added
526 boolean suc = updateAllPortsToNextHop(Sets.difference(newNhops, currNhops),
527 edgeLabel, nextId, false);
528 if (suc) {
529 currNhops.addAll(newNhops);
530 currDstNextHops.put(dstSw, currNhops); // this is only a local change
531 }
532 success &= suc;
533 }
534
535 if (success) {
536 // update global store
537 dsNextObjStore.put(key, new NextNeighbors(currDstNextHops,
538 currNext.nextId()));
539 log.debug("Updated device:{} ds:{} new next-hops: {}", deviceId, ds,
540 dsNextObjStore.get(key));
541 }
542 return success;
543 }
544
Saurav Dasceccf242017-08-03 18:30:35 -0700545 /**
546 * Adds or removes buckets for all ports to a set of neighbor devices.
547 *
548 * @param neighbors set of neighbor device ids
549 * @param edgeLabel MPLS label to use in buckets
550 * @param nextId the nextObjective to change
551 * @param revoke true if buckets need to be removed, false if they need to
552 * be added
553 * @return true if successful in adding or removing buckets for all ports
554 * to the neighbors
555 */
556 private boolean updateAllPortsToNextHop(Set<DeviceId> neighbors, int edgeLabel,
Saurav Das7bcbe702017-06-13 15:35:54 -0700557 int nextId, boolean revoke) {
Saurav Dasceccf242017-08-03 18:30:35 -0700558 for (DeviceId neighbor : neighbors) {
Saurav Das7bcbe702017-06-13 15:35:54 -0700559 MacAddress dstMac;
560 try {
561 dstMac = deviceConfig.getDeviceMac(neighbor);
562 } catch (DeviceConfigNotFoundException e) {
563 log.warn(e.getMessage() + " Aborting fixHashGroup for nextId:"
564 + nextId);
565 return false;
566 }
567 if (devicePortMap.get(neighbor) == null ||
568 devicePortMap.get(neighbor).isEmpty()) {
569 log.warn("No ports found in dev:{} for neighbor:{} .. cannot "
570 + "fix hash group for nextId: {}",
571 deviceId, neighbor, nextId);
572 return false;
573 }
574 if (revoke) {
575 for (PortNumber port : devicePortMap.get(neighbor)) {
576 log.debug("fixHashGroup in device {}: Removing Bucket "
577 + "with Port {} edgeLabel:{} to next object id {}",
578 deviceId, port, edgeLabel, nextId);
579 removeFromHashedNextObjective(port, dstMac,
580 edgeLabel,
581 nextId);
582 }
583 } else {
584 for (PortNumber port : devicePortMap.get(neighbor)) {
585 log.debug("fixHashGroup in device {}: Adding Bucket "
586 + "with Port {} edgeLabel: {} to next object id {}",
587 deviceId, port, edgeLabel, nextId);
Saurav Dasceccf242017-08-03 18:30:35 -0700588 addToHashedNextObjective(port, dstMac, edgeLabel, nextId);
Saurav Das7bcbe702017-06-13 15:35:54 -0700589 }
590 }
591 }
592 return true;
593 }
594
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800595 /**
Saurav Dasb0ae6ee2017-03-04 16:08:47 -0800596 * Adds or removes a port that has been configured with a vlan to a broadcast group
597 * for bridging. Should only be called by the master instance for this device.
Saurav Das1a129a02016-11-18 15:21:57 -0800598 *
599 * @param port the port on this device that needs to be added/removed to a bcast group
Saurav Dasb0ae6ee2017-03-04 16:08:47 -0800600 * @param vlanId the vlan id corresponding to the broadcast domain/group
601 * @param popVlan indicates if packets should be sent out untagged or not out
602 * of the port. If true, indicates an access (untagged) or native vlan
603 * configuration. If false, indicates a trunk (tagged) vlan config.
Saurav Das1a129a02016-11-18 15:21:57 -0800604 * @param portUp true if port is enabled, false if disabled
Saurav Das1a129a02016-11-18 15:21:57 -0800605 */
Saurav Dasb0ae6ee2017-03-04 16:08:47 -0800606 public void processEdgePort(PortNumber port, VlanId vlanId,
607 boolean popVlan, boolean portUp) {
Saurav Das1a129a02016-11-18 15:21:57 -0800608 //get the next id for the subnet and edit it.
Charles Chan59cc16d2017-02-02 16:20:42 -0800609 Integer nextId = getVlanNextObjectiveId(vlanId);
Saurav Das1a129a02016-11-18 15:21:57 -0800610 if (nextId == -1) {
611 if (portUp) {
612 log.debug("**Creating flooding group for first port enabled in"
Charles Chan59cc16d2017-02-02 16:20:42 -0800613 + " subnet {} on dev {} port {}", vlanId, deviceId, port);
614 createBcastGroupFromVlan(vlanId, Collections.singleton(port));
Saurav Das1a129a02016-11-18 15:21:57 -0800615 } else {
616 log.warn("Could not find flooding group for subnet {} on dev:{} when"
Charles Chan59cc16d2017-02-02 16:20:42 -0800617 + " removing port:{}", vlanId, deviceId, port);
Saurav Das1a129a02016-11-18 15:21:57 -0800618 }
619 return;
620 }
621
622 log.info("**port{} in device {}: {} Bucket with Port {} to"
623 + " next-id {}", (portUp) ? "UP" : "DOWN", deviceId,
624 (portUp) ? "Adding" : "Removing",
625 port, nextId);
626 // Create the bucket to be added or removed
627 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
Saurav Dasb0ae6ee2017-03-04 16:08:47 -0800628 if (popVlan) {
629 tBuilder.popVlan();
630 }
Saurav Das1a129a02016-11-18 15:21:57 -0800631 tBuilder.setOutput(port);
632
Saurav Das1a129a02016-11-18 15:21:57 -0800633 TrafficSelector metadata =
Saurav Dasb0ae6ee2017-03-04 16:08:47 -0800634 DefaultTrafficSelector.builder().matchVlanId(vlanId).build();
Saurav Das1a129a02016-11-18 15:21:57 -0800635
636 NextObjective.Builder nextObjBuilder = DefaultNextObjective
637 .builder().withId(nextId)
638 .withType(NextObjective.Type.BROADCAST).fromApp(appId)
639 .addTreatment(tBuilder.build())
640 .withMeta(metadata);
641
642 ObjectiveContext context = new DefaultObjectiveContext(
643 (objective) -> log.debug("port {} successfully {} NextObj {} on {}",
644 port, (portUp) ? "addedTo" : "removedFrom",
645 nextId, deviceId),
646 (objective, error) ->
647 log.warn("port {} failed to {} NextObj {} on {}: {}",
648 port, (portUp) ? "addTo" : "removeFrom",
649 nextId, deviceId, error));
650
651 NextObjective nextObj = (portUp) ? nextObjBuilder.addToExisting(context)
652 : nextObjBuilder.removeFromExisting(context);
653 log.debug("edgePort processed: Submited next objective {} in device {}",
654 nextId, deviceId);
655 flowObjectiveService.next(deviceId, nextObj);
656 }
657
658 /**
Saurav Das7bcbe702017-06-13 15:35:54 -0700659 * Returns the next objective of type hashed associated with the destination set.
660 * In addition, updates the existing next-objective if new route-route paths found
661 * have resulted in the addition of new next-hops to a particular destination.
662 * If there is no existing next objective for this destination set, this method
663 * would create a next objective and return the nextId. Optionally metadata can be
Saurav Das8a0732e2015-11-20 15:27:53 -0800664 * passed in for the creation of the next objective.
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800665 *
Saurav Das7bcbe702017-06-13 15:35:54 -0700666 * @param ds destination set
667 * @param nextHops a map of per destination next hops
Saurav Das8a0732e2015-11-20 15:27:53 -0800668 * @param meta metadata passed into the creation of a Next Objective
Pier Ventre917127a2016-10-31 16:49:19 -0700669 * @param isBos if Bos is set
Saurav Das8a0732e2015-11-20 15:27:53 -0800670 * @return int if found or -1 if there are errors in the creation of the
671 * neighbor set.
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800672 */
Saurav Das7bcbe702017-06-13 15:35:54 -0700673 public int getNextObjectiveId(DestinationSet ds,
674 Map<DeviceId, Set<DeviceId>> nextHops,
675 TrafficSelector meta, boolean isBos) {
676 NextNeighbors next = dsNextObjStore.
677 get(new DestinationSetNextObjectiveStoreKey(deviceId, ds));
678 if (next == null) {
679 log.debug("getNextObjectiveId in device{}: Next objective id "
680 + "not found for {} ... creating", deviceId, ds);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700681 log.trace("getNextObjectiveId: nsNextObjStore contents for device {}: {}",
682 deviceId,
Saurav Das7bcbe702017-06-13 15:35:54 -0700683 dsNextObjStore.entrySet()
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700684 .stream()
685 .filter((nsStoreEntry) ->
686 (nsStoreEntry.getKey().deviceId().equals(deviceId)))
687 .collect(Collectors.toList()));
Saurav Das7bcbe702017-06-13 15:35:54 -0700688
689 createGroupFromDestinationSet(ds, nextHops, meta, isBos);
690 next = dsNextObjStore.
691 get(new DestinationSetNextObjectiveStoreKey(deviceId, ds));
692 if (next == null) {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700693 log.warn("getNextObjectiveId: unable to create next objective");
Saurav Das7bcbe702017-06-13 15:35:54 -0700694 // failure in creating group
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700695 return -1;
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700696 } else {
697 log.debug("getNextObjectiveId in device{}: Next objective id {} "
Saurav Das7bcbe702017-06-13 15:35:54 -0700698 + "created for {}", deviceId, next.nextId(), ds);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700699 }
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700700 } else {
701 log.trace("getNextObjectiveId in device{}: Next objective id {} "
Saurav Das7bcbe702017-06-13 15:35:54 -0700702 + "found for {}", deviceId, next.nextId(), ds);
703 // should fix hash groups too if next-hops have changed
704 if (!next.dstNextHops().equals(nextHops)) {
705 log.debug("Nexthops have changed for dev:{} nextId:{} ..updating",
706 deviceId, next.nextId());
707 if (!updateNextHops(ds, nextHops)) {
708 // failure in updating group
709 return -1;
710 }
711 }
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700712 }
Saurav Das7bcbe702017-06-13 15:35:54 -0700713 return next.nextId();
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800714 }
715
sangho0b2b6d12015-05-20 22:16:38 -0700716 /**
Charles Chan59cc16d2017-02-02 16:20:42 -0800717 * Returns the next objective of type broadcast associated with the vlan,
Saurav Das4ce45962015-11-24 23:21:05 -0800718 * or -1 if no such objective exists. Note that this method does NOT create
719 * the next objective as a side-effect. It is expected that is objective is
Saurav Das1a129a02016-11-18 15:21:57 -0800720 * created at startup from network configuration. Typically this is used
721 * for L2 flooding within the subnet configured on the switch.
Charles Chanc42e84e2015-10-20 16:24:19 -0700722 *
Charles Chan59cc16d2017-02-02 16:20:42 -0800723 * @param vlanId vlan id
Charles Chanc42e84e2015-10-20 16:24:19 -0700724 * @return int if found or -1
725 */
Charles Chan59cc16d2017-02-02 16:20:42 -0800726 public int getVlanNextObjectiveId(VlanId vlanId) {
727 Integer nextId = vlanNextObjStore.
728 get(new VlanNextObjectiveStoreKey(deviceId, vlanId));
Charles Chan9f676b62015-10-29 14:58:10 -0700729
730 return (nextId != null) ? nextId : -1;
Charles Chanc42e84e2015-10-20 16:24:19 -0700731 }
732
733 /**
Saurav Das4ce45962015-11-24 23:21:05 -0800734 * Returns the next objective of type simple associated with the port on the
735 * device, given the treatment. Different treatments to the same port result
736 * in different next objectives. If no such objective exists, this method
Saurav Das961beb22017-03-29 19:09:17 -0700737 * creates one (if requested) and returns the id. Optionally metadata can be passed in for
Saurav Das1a129a02016-11-18 15:21:57 -0800738 * the creation of the objective. Typically this is used for L2 and L3 forwarding
739 * to compute nodes and containers/VMs on the compute nodes directly attached
740 * to the switch.
Saurav Das4ce45962015-11-24 23:21:05 -0800741 *
742 * @param portNum the port number for the simple next objective
743 * @param treatment the actions to apply on the packets (should include outport)
744 * @param meta optional metadata passed into the creation of the next objective
Saurav Das961beb22017-03-29 19:09:17 -0700745 * @param createIfMissing true if a next object should be created if not found
Saurav Das4ce45962015-11-24 23:21:05 -0800746 * @return int if found or created, -1 if there are errors during the
747 * creation of the next objective.
748 */
749 public int getPortNextObjectiveId(PortNumber portNum, TrafficTreatment treatment,
Saurav Das961beb22017-03-29 19:09:17 -0700750 TrafficSelector meta, boolean createIfMissing) {
Charles Chane849c192016-01-11 18:28:54 -0800751 Integer nextId = portNextObjStore
Saurav Das76ae6812017-03-15 15:15:14 -0700752 .get(new PortNextObjectiveStoreKey(deviceId, portNum, treatment, meta));
Saurav Das961beb22017-03-29 19:09:17 -0700753 if (nextId != null) {
754 return nextId;
755 }
756 log.debug("getPortNextObjectiveId in device {}: Next objective id "
757 + "not found for port: {} .. {}", deviceId, portNum,
758 (createIfMissing) ? "creating" : "aborting");
759 if (!createIfMissing) {
760 return -1;
761 }
762 // create missing next objective
763 createGroupFromPort(portNum, treatment, meta);
764 nextId = portNextObjStore.get(new PortNextObjectiveStoreKey(deviceId, portNum,
765 treatment, meta));
Saurav Das4ce45962015-11-24 23:21:05 -0800766 if (nextId == null) {
Saurav Das961beb22017-03-29 19:09:17 -0700767 log.warn("getPortNextObjectiveId: unable to create next obj"
768 + "for dev:{} port:{}", deviceId, portNum);
769 return -1;
Charles Chane849c192016-01-11 18:28:54 -0800770 }
771 return nextId;
772 }
773
774 /**
sangho0b2b6d12015-05-20 22:16:38 -0700775 * Checks if the next objective ID (group) for the neighbor set exists or not.
776 *
777 * @param ns neighbor set to check
778 * @return true if it exists, false otherwise
779 */
Saurav Das7bcbe702017-06-13 15:35:54 -0700780 public boolean hasNextObjectiveId(DestinationSet ns) {
781 NextNeighbors nextHops = dsNextObjStore.
782 get(new DestinationSetNextObjectiveStoreKey(deviceId, ns));
783 if (nextHops == null) {
sangho0b2b6d12015-05-20 22:16:38 -0700784 return false;
785 }
786
787 return true;
788 }
789
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800790 private void populateNeighborMaps() {
791 Set<Link> outgoingLinks = linkService.getDeviceEgressLinks(deviceId);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700792 for (Link link : outgoingLinks) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800793 if (link.type() != Link.Type.DIRECT) {
794 continue;
795 }
796 addNeighborAtPort(link.dst().deviceId(), link.src().port());
797 }
798 }
799
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700800 protected void addNeighborAtPort(DeviceId neighborId,
801 PortNumber portToNeighbor) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800802 // Update DeviceToPort database
803 log.debug("Device {} addNeighborAtPort: neighbor {} at port {}",
804 deviceId, neighborId, portToNeighbor);
Saurav Das8a0732e2015-11-20 15:27:53 -0800805 Set<PortNumber> ports = Collections
806 .newSetFromMap(new ConcurrentHashMap<PortNumber, Boolean>());
807 ports.add(portToNeighbor);
808 Set<PortNumber> portnums = devicePortMap.putIfAbsent(neighborId, ports);
809 if (portnums != null) {
810 portnums.add(portToNeighbor);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800811 }
812
813 // Update portToDevice database
Saurav Das8a0732e2015-11-20 15:27:53 -0800814 DeviceId prev = portDeviceMap.putIfAbsent(portToNeighbor, neighborId);
815 if (prev != null) {
Saurav Dasc88d4662017-05-15 15:34:25 -0700816 log.debug("Device: {} port: {} already has neighbor: {} ",
817 deviceId, portToNeighbor, prev, neighborId);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800818 }
819 }
820
sangho1e575652015-05-14 00:39:53 -0700821 /**
Saurav Das7bcbe702017-06-13 15:35:54 -0700822 * Creates a NextObjective for a hash group in this device from a given
823 * DestinationSet.
sangho1e575652015-05-14 00:39:53 -0700824 *
Saurav Das7bcbe702017-06-13 15:35:54 -0700825 * @param ds the DestinationSet
826 * @param neighbors a map for each destination and its next-hops
Saurav Das8a0732e2015-11-20 15:27:53 -0800827 * @param meta metadata passed into the creation of a Next Objective
Pier Ventre917127a2016-10-31 16:49:19 -0700828 * @param isBos if BoS is set
sangho1e575652015-05-14 00:39:53 -0700829 */
Saurav Das7bcbe702017-06-13 15:35:54 -0700830 public void createGroupFromDestinationSet(DestinationSet ds,
831 Map<DeviceId, Set<DeviceId>> neighbors,
832 TrafficSelector meta,
833 boolean isBos) {
834 int nextId = flowObjectiveService.allocateNextId();
835 NextObjective.Type type = NextObjective.Type.HASHED;
836 if (neighbors == null || neighbors.isEmpty()) {
837 log.warn("createGroupsFromDestinationSet: needs at least one neighbor"
838 + "to create group in dev:{} for ds: {} with next-hops {}",
839 deviceId, ds, neighbors);
840 return;
841 }
842 // If Bos == False and MPLS-ECMP == false, we have
843 // to use simple group and we will pick a single neighbor for a single dest.
844 if (!isBos && !srManager.getMplsEcmp()) {
845 type = NextObjective.Type.SIMPLE;
846 }
847
848 NextObjective.Builder nextObjBuilder = DefaultNextObjective
849 .builder()
850 .withId(nextId)
851 .withType(type)
852 .fromApp(appId);
853 if (meta != null) {
854 nextObjBuilder.withMeta(meta);
855 }
856
857 // create treatment buckets for each neighbor for each dst Device
858 // except in the special case where we only want to pick a single
859 // neighbor for a simple group
860 boolean foundSingleNeighbor = false;
861 boolean treatmentAdded = false;
862 Map<DeviceId, Set<DeviceId>> dstNextHops = new ConcurrentHashMap<>();
863 for (DeviceId dst : ds.getDestinationSwitches()) {
864 Set<DeviceId> nextHops = neighbors.get(dst);
865 if (nextHops == null || nextHops.isEmpty()) {
866 continue;
Pier Ventre917127a2016-10-31 16:49:19 -0700867 }
Saurav Das7bcbe702017-06-13 15:35:54 -0700868
869 if (foundSingleNeighbor) {
870 break;
871 }
872
873 for (DeviceId neighborId : nextHops) {
Saurav Das8a0732e2015-11-20 15:27:53 -0800874 if (devicePortMap.get(neighborId) == null) {
875 log.warn("Neighbor {} is not in the port map yet for dev:{}",
876 neighborId, deviceId);
sangho834e4b02015-05-01 09:38:25 -0700877 return;
Jon Hallcbd1b392017-01-18 20:15:44 -0800878 } else if (devicePortMap.get(neighborId).isEmpty()) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700879 log.warn("There are no ports for "
Saurav Das8a0732e2015-11-20 15:27:53 -0800880 + "the Device {} in the port map yet", neighborId);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700881 return;
sangho834e4b02015-05-01 09:38:25 -0700882 }
883
Saurav Das8a0732e2015-11-20 15:27:53 -0800884 MacAddress neighborMac;
Charles Chan0b4e6182015-11-03 10:42:14 -0800885 try {
Saurav Das8a0732e2015-11-20 15:27:53 -0800886 neighborMac = deviceConfig.getDeviceMac(neighborId);
Charles Chan0b4e6182015-11-03 10:42:14 -0800887 } catch (DeviceConfigNotFoundException e) {
Saurav Das7bcbe702017-06-13 15:35:54 -0700888 log.warn(e.getMessage() + " Aborting createGroupsFromDestinationset.");
Charles Chan0b4e6182015-11-03 10:42:14 -0800889 return;
890 }
Saurav Das7bcbe702017-06-13 15:35:54 -0700891 // For each port to the neighbor, we create a new treatment
Pier Ventre917127a2016-10-31 16:49:19 -0700892 Set<PortNumber> neighborPorts = devicePortMap.get(neighborId);
893 // In this case we are using a SIMPLE group. We randomly pick a port
894 if (!isBos && !srManager.getMplsEcmp()) {
895 int size = devicePortMap.get(neighborId).size();
896 int index = RandomUtils.nextInt(0, size);
897 neighborPorts = Collections.singleton(
Saurav Das7bcbe702017-06-13 15:35:54 -0700898 Iterables.get(devicePortMap.get(neighborId),
899 index));
900 foundSingleNeighbor = true;
Pier Ventre917127a2016-10-31 16:49:19 -0700901 }
902 for (PortNumber sp : neighborPorts) {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700903 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment
904 .builder();
Saurav Das7bcbe702017-06-13 15:35:54 -0700905 tBuilder.setEthDst(neighborMac).setEthSrc(nodeMacAddr);
906 int edgeLabel = ds.getEdgeLabel(dst);
907 if (edgeLabel != DestinationSet.NO_EDGE_LABEL) {
Charles Chan68aa62d2015-11-09 16:37:23 -0800908 tBuilder.pushMpls()
Saurav Das7bcbe702017-06-13 15:35:54 -0700909 .copyTtlOut()
910 .setMpls(MplsLabel.mplsLabel(edgeLabel));
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700911 }
Saurav Das8a0732e2015-11-20 15:27:53 -0800912 tBuilder.setOutput(sp);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700913 nextObjBuilder.addTreatment(tBuilder.build());
Saurav Das7bcbe702017-06-13 15:35:54 -0700914 treatmentAdded = true;
915 //update store
916 Set<DeviceId> existingNeighbors = dstNextHops.get(dst);
917 if (existingNeighbors == null) {
918 existingNeighbors = new HashSet<>();
919 }
920 existingNeighbors.add(neighborId);
921 dstNextHops.put(dst, existingNeighbors);
922 log.debug("creating treatment for port/label {}/{} in next:{}",
923 sp, edgeLabel, nextId);
924 }
925
926 if (foundSingleNeighbor) {
927 break;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800928 }
929 }
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800930 }
Saurav Das7bcbe702017-06-13 15:35:54 -0700931
932 if (!treatmentAdded) {
933 log.warn("Could not createGroup from DestinationSet {} without any"
934 + "next hops {}", ds, neighbors);
935 return;
936 }
937 ObjectiveContext context = new DefaultObjectiveContext(
938 (objective) ->
939 log.debug("createGroupsFromDestinationSet installed "
940 + "NextObj {} on {}", nextId, deviceId),
941 (objective, error) ->
942 log.warn("createGroupsFromDestinationSet failed to install"
943 + " NextObj {} on {}: {}", nextId, deviceId, error)
944 );
945 NextObjective nextObj = nextObjBuilder.add(context);
946 log.debug(".. createGroupsFromDestinationSet: Submitted "
947 + "next objective {} in device {}", nextId, deviceId);
948 flowObjectiveService.next(deviceId, nextObj);
949 //update store
950 dsNextObjStore.put(new DestinationSetNextObjectiveStoreKey(deviceId, ds),
951 new NextNeighbors(dstNextHops, nextId));
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800952 }
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700953
Saurav Das4ce45962015-11-24 23:21:05 -0800954 /**
Saurav Das1a129a02016-11-18 15:21:57 -0800955 * Creates broadcast groups for all ports in the same subnet for
956 * all configured subnets.
Saurav Das4ce45962015-11-24 23:21:05 -0800957 */
Charles Chan59cc16d2017-02-02 16:20:42 -0800958 public void createGroupsFromVlanConfig() {
Charles Chan7ffd81f2017-02-08 15:52:08 -0800959 srManager.getVlanPortMap(deviceId).asMap().forEach((vlanId, ports) -> {
Charles Chan59cc16d2017-02-02 16:20:42 -0800960 createBcastGroupFromVlan(vlanId, ports);
Pier Ventre10bd8d12016-11-26 21:05:22 -0800961 });
Saurav Das1a129a02016-11-18 15:21:57 -0800962 }
Charles Chan9f676b62015-10-29 14:58:10 -0700963
Saurav Das1a129a02016-11-18 15:21:57 -0800964 /**
Charles Chan59cc16d2017-02-02 16:20:42 -0800965 * Creates a single broadcast group from a given vlan id and list of ports.
Saurav Das1a129a02016-11-18 15:21:57 -0800966 *
Charles Chan59cc16d2017-02-02 16:20:42 -0800967 * @param vlanId vlan id
Saurav Das1a129a02016-11-18 15:21:57 -0800968 * @param ports list of ports in the subnet
969 */
Charles Chan7ffd81f2017-02-08 15:52:08 -0800970 public void createBcastGroupFromVlan(VlanId vlanId, Collection<PortNumber> ports) {
Charles Chan59cc16d2017-02-02 16:20:42 -0800971 VlanNextObjectiveStoreKey key = new VlanNextObjectiveStoreKey(deviceId, vlanId);
Charles Chan9f676b62015-10-29 14:58:10 -0700972
Charles Chan59cc16d2017-02-02 16:20:42 -0800973 if (vlanNextObjStore.containsKey(key)) {
Saurav Das1a129a02016-11-18 15:21:57 -0800974 log.debug("Broadcast group for device {} and subnet {} exists",
Charles Chan59cc16d2017-02-02 16:20:42 -0800975 deviceId, vlanId);
Saurav Das1a129a02016-11-18 15:21:57 -0800976 return;
977 }
Charles Chan188ebf52015-12-23 00:15:11 -0800978
Saurav Das1a129a02016-11-18 15:21:57 -0800979 TrafficSelector metadata =
Charles Chan59cc16d2017-02-02 16:20:42 -0800980 DefaultTrafficSelector.builder().matchVlanId(vlanId).build();
Charles Chanc42e84e2015-10-20 16:24:19 -0700981
Saurav Das1a129a02016-11-18 15:21:57 -0800982 int nextId = flowObjectiveService.allocateNextId();
Charles Chanc42e84e2015-10-20 16:24:19 -0700983
Saurav Das1a129a02016-11-18 15:21:57 -0800984 NextObjective.Builder nextObjBuilder = DefaultNextObjective
985 .builder().withId(nextId)
986 .withType(NextObjective.Type.BROADCAST).fromApp(appId)
987 .withMeta(metadata);
Charles Chanc42e84e2015-10-20 16:24:19 -0700988
Saurav Das1a129a02016-11-18 15:21:57 -0800989 ports.forEach(port -> {
990 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
Charles Chan7ffd81f2017-02-08 15:52:08 -0800991 if (toPopVlan(port, vlanId)) {
992 tBuilder.popVlan();
993 }
Saurav Das1a129a02016-11-18 15:21:57 -0800994 tBuilder.setOutput(port);
995 nextObjBuilder.addTreatment(tBuilder.build());
Charles Chanc42e84e2015-10-20 16:24:19 -0700996 });
Saurav Das1a129a02016-11-18 15:21:57 -0800997
Saurav Das961beb22017-03-29 19:09:17 -0700998 ObjectiveContext context = new DefaultObjectiveContext(
999 (objective) ->
1000 log.debug("createBroadcastGroupFromVlan installed "
1001 + "NextObj {} on {}", nextId, deviceId),
1002 (objective, error) ->
1003 log.warn("createBroadcastGroupFromVlan failed to install"
1004 + " NextObj {} on {}: {}", nextId, deviceId, error)
1005 );
1006 NextObjective nextObj = nextObjBuilder.add(context);
Saurav Das1a129a02016-11-18 15:21:57 -08001007 flowObjectiveService.next(deviceId, nextObj);
Charles Chan59cc16d2017-02-02 16:20:42 -08001008 log.debug("createBcastGroupFromVlan: Submited next objective {} in device {}",
Saurav Das1a129a02016-11-18 15:21:57 -08001009 nextId, deviceId);
1010
Charles Chan59cc16d2017-02-02 16:20:42 -08001011 vlanNextObjStore.put(key, nextId);
Charles Chanc42e84e2015-10-20 16:24:19 -07001012 }
1013
Charles Chane849c192016-01-11 18:28:54 -08001014 /**
Charles Chan7ffd81f2017-02-08 15:52:08 -08001015 * Determine if we should pop given vlan before sending packets to the given port.
1016 *
1017 * @param portNumber port number
1018 * @param vlanId vlan id
1019 * @return true if the vlan id is not contained in any vlanTagged config
1020 */
1021 private boolean toPopVlan(PortNumber portNumber, VlanId vlanId) {
Saurav Das7bcbe702017-06-13 15:35:54 -07001022 return srManager.interfaceService
1023 .getInterfacesByPort(new ConnectPoint(deviceId, portNumber))
Charles Chan7ffd81f2017-02-08 15:52:08 -08001024 .stream().noneMatch(intf -> intf.vlanTagged().contains(vlanId));
1025 }
1026
1027 /**
Saurav Das4ce45962015-11-24 23:21:05 -08001028 * Create simple next objective for a single port. The treatments can include
1029 * all outgoing actions that need to happen on the packet.
1030 *
1031 * @param portNum the outgoing port on the device
1032 * @param treatment the actions to apply on the packets (should include outport)
1033 * @param meta optional data to pass to the driver
1034 */
1035 public void createGroupFromPort(PortNumber portNum, TrafficTreatment treatment,
1036 TrafficSelector meta) {
1037 int nextId = flowObjectiveService.allocateNextId();
1038 PortNextObjectiveStoreKey key = new PortNextObjectiveStoreKey(
Saurav Das76ae6812017-03-15 15:15:14 -07001039 deviceId, portNum, treatment, meta);
Saurav Das4ce45962015-11-24 23:21:05 -08001040
1041 NextObjective.Builder nextObjBuilder = DefaultNextObjective
1042 .builder().withId(nextId)
1043 .withType(NextObjective.Type.SIMPLE)
1044 .addTreatment(treatment)
1045 .fromApp(appId)
1046 .withMeta(meta);
1047
Saurav Das961beb22017-03-29 19:09:17 -07001048 ObjectiveContext context = new DefaultObjectiveContext(
1049 (objective) ->
1050 log.debug("createGroupFromPort installed "
1051 + "NextObj {} on {}", nextId, deviceId),
1052 (objective, error) ->
1053 log.warn("createGroupFromPort failed to install"
1054 + " NextObj {} on {}: {}", nextId, deviceId, error)
1055 );
1056 NextObjective nextObj = nextObjBuilder.add(context);
Saurav Das4ce45962015-11-24 23:21:05 -08001057 flowObjectiveService.next(deviceId, nextObj);
1058 log.debug("createGroupFromPort: Submited next objective {} in device {} "
1059 + "for port {}", nextId, deviceId, portNum);
1060
1061 portNextObjStore.put(key, nextId);
1062 }
1063
sangho1e575652015-05-14 00:39:53 -07001064 /**
1065 * Removes groups for the next objective ID given.
1066 *
1067 * @param objectiveId next objective ID to remove
1068 * @return true if succeeds, false otherwise
1069 */
1070 public boolean removeGroup(int objectiveId) {
Saurav Das7bcbe702017-06-13 15:35:54 -07001071 for (Map.Entry<DestinationSetNextObjectiveStoreKey, NextNeighbors> e :
1072 dsNextObjStore.entrySet()) {
1073 if (e.getValue().nextId() != objectiveId) {
1074 continue;
1075 }
sangho1e575652015-05-14 00:39:53 -07001076 NextObjective.Builder nextObjBuilder = DefaultNextObjective
1077 .builder().withId(objectiveId)
1078 .withType(NextObjective.Type.HASHED).fromApp(appId);
Charles Chan216e3c82016-04-23 14:48:16 -07001079 ObjectiveContext context = new DefaultObjectiveContext(
1080 (objective) -> log.debug("RemoveGroup removes NextObj {} on {}",
1081 objectiveId, deviceId),
1082 (objective, error) ->
1083 log.warn("RemoveGroup failed to remove NextObj {} on {}: {}",
1084 objectiveId, deviceId, error));
1085 NextObjective nextObjective = nextObjBuilder.remove(context);
Saurav Das8a0732e2015-11-20 15:27:53 -08001086 log.info("**removeGroup: Submited "
1087 + "next objective {} in device {}",
1088 objectiveId, deviceId);
sangho1e575652015-05-14 00:39:53 -07001089 flowObjectiveService.next(deviceId, nextObjective);
1090
Saurav Das7bcbe702017-06-13 15:35:54 -07001091 dsNextObjStore.remove(e.getKey());
sangho0b2b6d12015-05-20 22:16:38 -07001092 return true;
sangho1e575652015-05-14 00:39:53 -07001093 }
1094
1095 return false;
1096 }
Srikanth Vavilapallif3a8bc02015-05-22 13:47:31 -07001097
Charles Chane849c192016-01-11 18:28:54 -08001098 /**
1099 * Removes all groups from all next objective stores.
1100 */
Saurav Das7bcbe702017-06-13 15:35:54 -07001101 /*public void removeAllGroups() {
1102 for (Map.Entry<NeighborSetNextObjectiveStoreKey, NextNeighbors> entry:
Saurav Das423fe2b2015-12-04 10:52:59 -08001103 nsNextObjStore.entrySet()) {
Saurav Das7bcbe702017-06-13 15:35:54 -07001104 removeGroup(entry.getValue().nextId());
Saurav Das423fe2b2015-12-04 10:52:59 -08001105 }
1106 for (Map.Entry<PortNextObjectiveStoreKey, Integer> entry:
1107 portNextObjStore.entrySet()) {
1108 removeGroup(entry.getValue());
1109 }
Charles Chan59cc16d2017-02-02 16:20:42 -08001110 for (Map.Entry<VlanNextObjectiveStoreKey, Integer> entry:
1111 vlanNextObjStore.entrySet()) {
Saurav Das423fe2b2015-12-04 10:52:59 -08001112 removeGroup(entry.getValue());
1113 }
Saurav Das7bcbe702017-06-13 15:35:54 -07001114 }*/ //XXX revisit
1115
Saurav Dasceccf242017-08-03 18:30:35 -07001116 /**
1117 * Triggers a one time bucket verification operation on all hash groups
1118 * on this device.
1119 */
1120 public void triggerBucketCorrector() {
1121 BucketCorrector bc = new BucketCorrector();
1122 bc.run();
1123 }
1124
Saurav Das1547b3f2017-05-05 17:01:08 -07001125
1126 /**
Saurav Dasceccf242017-08-03 18:30:35 -07001127 *
1128 *
Saurav Das1547b3f2017-05-05 17:01:08 -07001129 */
Saurav Dasceccf242017-08-03 18:30:35 -07001130 protected final class BucketCorrector implements Runnable {
1131 Integer nextId;
Saurav Das1547b3f2017-05-05 17:01:08 -07001132
Saurav Dasceccf242017-08-03 18:30:35 -07001133 BucketCorrector() {
1134 this.nextId = null;
1135 }
1136
1137 BucketCorrector(Integer nextId) {
1138 this.nextId = nextId;
Saurav Das1547b3f2017-05-05 17:01:08 -07001139 }
1140
1141 @Override
1142 public void run() {
Saurav Dasceccf242017-08-03 18:30:35 -07001143 if (!srManager.mastershipService.isLocalMaster(deviceId)) {
1144 return;
Saurav Das1547b3f2017-05-05 17:01:08 -07001145 }
Saurav Dasceccf242017-08-03 18:30:35 -07001146 DefaultRoutingHandler rh = srManager.getRoutingHandler();
1147 if (rh == null) {
1148 return;
1149 }
1150 if (!rh.isRoutingStable()) {
1151 return;
1152 }
1153 rh.acquireRoutingLock();
1154 try {
1155 log.debug("running bucket corrector for dev: {}", deviceId);
1156 Set<DestinationSetNextObjectiveStoreKey> dsKeySet = dsNextObjStore.entrySet()
1157 .stream()
1158 .filter(entry -> entry.getKey().deviceId().equals(deviceId))
1159 .map(entry -> entry.getKey())
1160 .collect(Collectors.toSet());
1161 for (DestinationSetNextObjectiveStoreKey dsKey : dsKeySet) {
1162 NextNeighbors next = dsNextObjStore.get(dsKey);
1163 if (next == null) {
1164 continue;
1165 }
1166 int nid = next.nextId();
1167 if (nextId != null && nextId != nid) {
1168 continue;
1169 }
1170 log.debug("bkt-corr: dsNextObjStore for device {}: {}",
1171 deviceId, dsKey, next);
1172 TrafficSelector.Builder metabuilder = DefaultTrafficSelector.builder();
1173 metabuilder.matchVlanId(INTERNAL_VLAN);
1174 NextObjective.Builder nextObjBuilder = DefaultNextObjective.builder()
1175 .withId(nid)
1176 .withType(NextObjective.Type.HASHED)
1177 .withMeta(metabuilder.build())
1178 .fromApp(appId);
1179
1180 next.dstNextHops().forEach((dstDev, nextHops) -> {
1181 int edgeLabel = dsKey.destinationSet().getEdgeLabel(dstDev);
1182 nextHops.forEach(neighbor -> {
1183 MacAddress neighborMac;
1184 try {
1185 neighborMac = deviceConfig.getDeviceMac(neighbor);
1186 } catch (DeviceConfigNotFoundException e) {
1187 log.warn(e.getMessage() + " Aborting neighbor"
1188 + neighbor);
1189 return;
1190 }
1191 devicePortMap.get(neighbor).forEach(port -> {
1192 log.debug("verify in device {} nextId {}: bucket with"
1193 + " port/label {}/{} to dst {} via {}",
1194 deviceId, nid, port, edgeLabel,
1195 dstDev, neighbor);
1196 nextObjBuilder.addTreatment(treatmentBuilder(port,
1197 neighborMac, edgeLabel));
1198 });
1199 });
1200 });
1201
1202 NextObjective nextObjective = nextObjBuilder.verify();
1203 flowObjectiveService.next(deviceId, nextObjective);
1204 }
1205 } finally {
1206 rh.releaseRoutingLock();
1207 }
1208
1209 }
1210
1211 TrafficTreatment treatmentBuilder(PortNumber outport, MacAddress dstMac,
1212 int edgeLabel) {
1213 TrafficTreatment.Builder tBuilder =
1214 DefaultTrafficTreatment.builder();
1215 tBuilder.setOutput(outport)
1216 .setEthDst(dstMac)
1217 .setEthSrc(nodeMacAddr);
1218 if (edgeLabel != DestinationSet.NO_EDGE_LABEL) {
1219 tBuilder.pushMpls()
1220 .copyTtlOut()
1221 .setMpls(MplsLabel.mplsLabel(edgeLabel));
1222 }
1223 return tBuilder.build();
Saurav Das1547b3f2017-05-05 17:01:08 -07001224 }
1225 }
1226
Saurav Dasceccf242017-08-03 18:30:35 -07001227}