blob: a689aecab29264b86a520b2a2111dfc6f3a6c4ac [file] [log] [blame]
sanghob35a6192015-04-01 13:05:26 -07001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2015-present Open Networking Laboratory
sanghob35a6192015-04-01 13:05:26 -07003 *
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 */
16package org.onosproject.segmentrouting;
17
Saurav Dasd2fded02016-12-02 15:43:47 -080018import com.google.common.base.MoreObjects;
Charles Chan93e71ba2016-04-29 14:38:22 -070019import com.google.common.collect.ImmutableSet;
Saurav Das4e3224f2016-11-29 14:27:25 -080020import com.google.common.collect.Lists;
sangho20eff1d2015-04-13 15:15:58 -070021import com.google.common.collect.Maps;
22import com.google.common.collect.Sets;
sangho666cd6d2015-04-14 16:27:13 -070023import org.onlab.packet.Ip4Address;
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -070024import org.onlab.packet.Ip4Prefix;
Pier Ventree0ae7a32016-11-23 09:57:42 -080025import org.onlab.packet.Ip6Address;
sanghob35a6192015-04-01 13:05:26 -070026import org.onlab.packet.IpPrefix;
Charles Chan93e71ba2016-04-29 14:38:22 -070027import org.onosproject.net.ConnectPoint;
sanghob35a6192015-04-01 13:05:26 -070028import org.onosproject.net.Device;
29import org.onosproject.net.DeviceId;
sangho20eff1d2015-04-13 15:15:58 -070030import org.onosproject.net.Link;
Charles Chan0b4e6182015-11-03 10:42:14 -080031import org.onosproject.segmentrouting.config.DeviceConfigNotFoundException;
32import org.onosproject.segmentrouting.config.DeviceConfiguration;
sanghob35a6192015-04-01 13:05:26 -070033import org.slf4j.Logger;
34import org.slf4j.LoggerFactory;
35
36import java.util.ArrayList;
37import java.util.HashMap;
38import java.util.HashSet;
Saurav Dasd2fded02016-12-02 15:43:47 -080039import java.util.Objects;
sanghob35a6192015-04-01 13:05:26 -070040import java.util.Set;
Saurav Das59232cf2016-04-27 18:35:50 -070041import java.util.concurrent.ScheduledExecutorService;
42import java.util.concurrent.TimeUnit;
HIGUCHI Yuta84a25fc2015-09-08 16:16:31 +090043import java.util.concurrent.locks.Lock;
44import java.util.concurrent.locks.ReentrantLock;
sanghob35a6192015-04-01 13:05:26 -070045
Saurav Dasd2fded02016-12-02 15:43:47 -080046import static com.google.common.base.MoreObjects.toStringHelper;
Pier Ventree0ae7a32016-11-23 09:57:42 -080047import static com.google.common.base.Preconditions.checkNotNull;
48import static java.util.concurrent.Executors.newScheduledThreadPool;
49import static org.onlab.util.Tools.groupedThreads;
sanghob35a6192015-04-01 13:05:26 -070050
Charles Chane849c192016-01-11 18:28:54 -080051/**
52 * Default routing handler that is responsible for route computing and
53 * routing rule population.
54 */
sanghob35a6192015-04-01 13:05:26 -070055public class DefaultRoutingHandler {
Saurav Dasd2fded02016-12-02 15:43:47 -080056 private static final int MAX_CONSTANT_RETRY_ATTEMPTS = 4;
57 private static final int RETRY_INTERVAL_MS = 500;
Charles Chan93e71ba2016-04-29 14:38:22 -070058 private static final String ECMPSPG_MISSING = "ECMP shortest path graph not found";
59 private static Logger log = LoggerFactory.getLogger(DefaultRoutingHandler.class);
sanghob35a6192015-04-01 13:05:26 -070060
61 private SegmentRoutingManager srManager;
62 private RoutingRulePopulator rulePopulator;
Shashikanth VH013a7bc2015-12-11 01:32:44 +053063 private HashMap<DeviceId, EcmpShortestPathGraph> currentEcmpSpgMap;
64 private HashMap<DeviceId, EcmpShortestPathGraph> updatedEcmpSpgMap;
sangho666cd6d2015-04-14 16:27:13 -070065 private DeviceConfiguration config;
HIGUCHI Yuta84a25fc2015-09-08 16:16:31 +090066 private final Lock statusLock = new ReentrantLock();
67 private volatile Status populationStatus;
Yuta HIGUCHI1624df12016-07-21 16:54:33 -070068 private ScheduledExecutorService executorService
Saurav Dasd2fded02016-12-02 15:43:47 -080069 = newScheduledThreadPool(1, groupedThreads("retryftr", "retry-%d", log));
sanghob35a6192015-04-01 13:05:26 -070070
71 /**
72 * Represents the default routing population status.
73 */
74 public enum Status {
75 // population process is not started yet.
76 IDLE,
77
78 // population process started.
79 STARTED,
80
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070081 // population process was aborted due to errors, mostly for groups not
82 // found.
sanghob35a6192015-04-01 13:05:26 -070083 ABORTED,
84
85 // population process was finished successfully.
86 SUCCEEDED
87 }
88
89 /**
90 * Creates a DefaultRoutingHandler object.
91 *
92 * @param srManager SegmentRoutingManager object
93 */
94 public DefaultRoutingHandler(SegmentRoutingManager srManager) {
95 this.srManager = srManager;
96 this.rulePopulator = checkNotNull(srManager.routingRulePopulator);
sangho666cd6d2015-04-14 16:27:13 -070097 this.config = checkNotNull(srManager.deviceConfiguration);
sanghob35a6192015-04-01 13:05:26 -070098 this.populationStatus = Status.IDLE;
sangho20eff1d2015-04-13 15:15:58 -070099 this.currentEcmpSpgMap = Maps.newHashMap();
sanghob35a6192015-04-01 13:05:26 -0700100 }
101
102 /**
103 * Populates all routing rules to all connected routers, including default
104 * routing rules, adjacency rules, and policy rules if any.
105 *
106 * @return true if it succeeds in populating all rules, otherwise false
107 */
108 public boolean populateAllRoutingRules() {
109
HIGUCHI Yuta84a25fc2015-09-08 16:16:31 +0900110 statusLock.lock();
111 try {
112 populationStatus = Status.STARTED;
113 rulePopulator.resetCounter();
Saurav Dasa07f2032015-10-19 14:37:36 -0700114 log.info("Starting to populate segment-routing rules");
HIGUCHI Yuta84a25fc2015-09-08 16:16:31 +0900115 log.debug("populateAllRoutingRules: populationStatus is STARTED");
sanghob35a6192015-04-01 13:05:26 -0700116
HIGUCHI Yuta84a25fc2015-09-08 16:16:31 +0900117 for (Device sw : srManager.deviceService.getDevices()) {
Charles Chanc42e84e2015-10-20 16:24:19 -0700118 if (!srManager.mastershipService.isLocalMaster(sw.id())) {
HIGUCHI Yuta84a25fc2015-09-08 16:16:31 +0900119 log.debug("populateAllRoutingRules: skipping device {}...we are not master",
120 sw.id());
121 continue;
122 }
123
Shashikanth VH013a7bc2015-12-11 01:32:44 +0530124 EcmpShortestPathGraph ecmpSpg = new EcmpShortestPathGraph(sw.id(), srManager);
Charles Chan93e71ba2016-04-29 14:38:22 -0700125 if (!populateEcmpRoutingRules(sw.id(), ecmpSpg, ImmutableSet.of())) {
HIGUCHI Yuta84a25fc2015-09-08 16:16:31 +0900126 log.debug("populateAllRoutingRules: populationStatus is ABORTED");
127 populationStatus = Status.ABORTED;
128 log.debug("Abort routing rule population");
129 return false;
130 }
131 currentEcmpSpgMap.put(sw.id(), ecmpSpg);
132
133 // TODO: Set adjacency routing rule for all switches
sanghob35a6192015-04-01 13:05:26 -0700134 }
135
HIGUCHI Yuta84a25fc2015-09-08 16:16:31 +0900136 log.debug("populateAllRoutingRules: populationStatus is SUCCEEDED");
137 populationStatus = Status.SUCCEEDED;
Saurav Dasa07f2032015-10-19 14:37:36 -0700138 log.info("Completed routing rule population. Total # of rules pushed : {}",
HIGUCHI Yuta84a25fc2015-09-08 16:16:31 +0900139 rulePopulator.getCounter());
140 return true;
141 } finally {
142 statusLock.unlock();
sanghob35a6192015-04-01 13:05:26 -0700143 }
sanghob35a6192015-04-01 13:05:26 -0700144 }
145
sangho20eff1d2015-04-13 15:15:58 -0700146 /**
147 * Populates the routing rules according to the route changes due to the link
148 * failure or link add. It computes the routes changed due to the link changes and
Saurav Das4e3224f2016-11-29 14:27:25 -0800149 * repopulates the rules only for these routes. Note that when a switch goes
150 * away, all of its links fail as well, but this is handled as a single
151 * switch removal event.
sangho20eff1d2015-04-13 15:15:58 -0700152 *
Saurav Das4e3224f2016-11-29 14:27:25 -0800153 * @param failedLink the single failed link, or null for other conditions
154 * such as an added link or a removed switch
sangho20eff1d2015-04-13 15:15:58 -0700155 * @return true if it succeeds to populate all rules, false otherwise
156 */
Saurav Das4e3224f2016-11-29 14:27:25 -0800157 public boolean populateRoutingRulesForLinkStatusChange(Link failedLink) {
sangho20eff1d2015-04-13 15:15:58 -0700158
HIGUCHI Yuta84a25fc2015-09-08 16:16:31 +0900159 statusLock.lock();
160 try {
sangho20eff1d2015-04-13 15:15:58 -0700161
162 if (populationStatus == Status.STARTED) {
sangho52abe3a2015-05-05 14:13:34 -0700163 log.warn("Previous rule population is not finished.");
sangho20eff1d2015-04-13 15:15:58 -0700164 return true;
165 }
166
sangho45b009c2015-05-07 13:30:57 -0700167 // Take the snapshots of the links
168 updatedEcmpSpgMap = new HashMap<>();
169 for (Device sw : srManager.deviceService.getDevices()) {
Charles Chanc42e84e2015-10-20 16:24:19 -0700170 if (!srManager.mastershipService.isLocalMaster(sw.id())) {
sangho45b009c2015-05-07 13:30:57 -0700171 continue;
172 }
Shashikanth VH013a7bc2015-12-11 01:32:44 +0530173 EcmpShortestPathGraph ecmpSpgUpdated =
174 new EcmpShortestPathGraph(sw.id(), srManager);
sangho45b009c2015-05-07 13:30:57 -0700175 updatedEcmpSpgMap.put(sw.id(), ecmpSpgUpdated);
176 }
177
sangho52abe3a2015-05-05 14:13:34 -0700178 log.info("Starts rule population from link change");
179
sangho20eff1d2015-04-13 15:15:58 -0700180 Set<ArrayList<DeviceId>> routeChanges;
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700181 log.trace("populateRoutingRulesForLinkStatusChange: "
182 + "populationStatus is STARTED");
sangho20eff1d2015-04-13 15:15:58 -0700183 populationStatus = Status.STARTED;
Saurav Das4e3224f2016-11-29 14:27:25 -0800184 // try optimized re-routing
185 if (failedLink == null) {
186 // Compare all routes of existing ECMP SPG to new ECMP SPG
sangho20eff1d2015-04-13 15:15:58 -0700187 routeChanges = computeRouteChange();
188 } else {
189 // Compare existing ECMP SPG only with the link removed
Saurav Das4e3224f2016-11-29 14:27:25 -0800190 routeChanges = computeDamagedRoutes(failedLink);
sangho20eff1d2015-04-13 15:15:58 -0700191 }
192
Saurav Das4e3224f2016-11-29 14:27:25 -0800193 // do full re-routing if optimized routing returns null routeChanges
Saurav Dasb5c236e2016-06-07 10:08:06 -0700194 if (routeChanges == null) {
195 return populateAllRoutingRules();
196 }
197
sangho20eff1d2015-04-13 15:15:58 -0700198 if (routeChanges.isEmpty()) {
sangho52abe3a2015-05-05 14:13:34 -0700199 log.info("No route changes for the link status change");
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700200 log.debug("populateRoutingRulesForLinkStatusChange: populationStatus is SUCCEEDED");
sangho20eff1d2015-04-13 15:15:58 -0700201 populationStatus = Status.SUCCEEDED;
202 return true;
203 }
204
205 if (repopulateRoutingRulesForRoutes(routeChanges)) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700206 log.debug("populateRoutingRulesForLinkStatusChange: populationStatus is SUCCEEDED");
sangho20eff1d2015-04-13 15:15:58 -0700207 populationStatus = Status.SUCCEEDED;
208 log.info("Complete to repopulate the rules. # of rules populated : {}",
209 rulePopulator.getCounter());
210 return true;
211 } else {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700212 log.debug("populateRoutingRulesForLinkStatusChange: populationStatus is ABORTED");
sangho20eff1d2015-04-13 15:15:58 -0700213 populationStatus = Status.ABORTED;
214 log.warn("Failed to repopulate the rules.");
215 return false;
216 }
HIGUCHI Yuta84a25fc2015-09-08 16:16:31 +0900217 } finally {
218 statusLock.unlock();
sangho20eff1d2015-04-13 15:15:58 -0700219 }
220 }
221
222 private boolean repopulateRoutingRulesForRoutes(Set<ArrayList<DeviceId>> routes) {
223 rulePopulator.resetCounter();
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700224 HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>> routesBydevice =
225 new HashMap<>();
sangho20eff1d2015-04-13 15:15:58 -0700226 for (ArrayList<DeviceId> link: routes) {
sangho834e4b02015-05-01 09:38:25 -0700227 // When only the source device is defined, reinstall routes to all other devices
sangho20eff1d2015-04-13 15:15:58 -0700228 if (link.size() == 1) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700229 log.trace("repopulateRoutingRulesForRoutes: running ECMP graph for device {}", link.get(0));
Shashikanth VH013a7bc2015-12-11 01:32:44 +0530230 EcmpShortestPathGraph ecmpSpg = new EcmpShortestPathGraph(link.get(0), srManager);
Charles Chan93e71ba2016-04-29 14:38:22 -0700231 if (populateEcmpRoutingRules(link.get(0), ecmpSpg, ImmutableSet.of())) {
Saurav Das25190812016-05-27 13:54:07 -0700232 log.debug("Populating flow rules from all to dest:{} is successful",
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700233 link.get(0));
sangho20eff1d2015-04-13 15:15:58 -0700234 currentEcmpSpgMap.put(link.get(0), ecmpSpg);
sangho52abe3a2015-05-05 14:13:34 -0700235 } else {
Saurav Das25190812016-05-27 13:54:07 -0700236 log.warn("Failed to populate the flow rules from all to dest:{}", link.get(0));
sangho52abe3a2015-05-05 14:13:34 -0700237 return false;
sangho20eff1d2015-04-13 15:15:58 -0700238 }
sangho45b009c2015-05-07 13:30:57 -0700239 } else {
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700240 ArrayList<ArrayList<DeviceId>> deviceRoutes =
241 routesBydevice.get(link.get(1));
242 if (deviceRoutes == null) {
243 deviceRoutes = new ArrayList<>();
244 routesBydevice.put(link.get(1), deviceRoutes);
245 }
246 deviceRoutes.add(link);
247 }
248 }
249
250 for (DeviceId impactedDevice : routesBydevice.keySet()) {
251 ArrayList<ArrayList<DeviceId>> deviceRoutes =
252 routesBydevice.get(impactedDevice);
253 for (ArrayList<DeviceId> link: deviceRoutes) {
254 log.debug("repopulate RoutingRules For Routes {} -> {}",
255 link.get(0), link.get(1));
sangho45b009c2015-05-07 13:30:57 -0700256 DeviceId src = link.get(0);
257 DeviceId dst = link.get(1);
Shashikanth VH013a7bc2015-12-11 01:32:44 +0530258 EcmpShortestPathGraph ecmpSpg = updatedEcmpSpgMap.get(dst);
sangho45b009c2015-05-07 13:30:57 -0700259 HashMap<Integer, HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>>> switchVia =
260 ecmpSpg.getAllLearnedSwitchesAndVia();
261 for (Integer itrIdx : switchVia.keySet()) {
262 HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>> swViaMap =
263 switchVia.get(itrIdx);
264 for (DeviceId targetSw : swViaMap.keySet()) {
265 if (!targetSw.equals(src)) {
266 continue;
267 }
268 Set<DeviceId> nextHops = new HashSet<>();
269 for (ArrayList<DeviceId> via : swViaMap.get(targetSw)) {
270 if (via.isEmpty()) {
271 nextHops.add(dst);
272 } else {
273 nextHops.add(via.get(0));
274 }
275 }
Charles Chan93e71ba2016-04-29 14:38:22 -0700276 if (!populateEcmpRoutingRulePartial(targetSw, dst,
277 nextHops, ImmutableSet.of())) {
sangho45b009c2015-05-07 13:30:57 -0700278 return false;
sangho20eff1d2015-04-13 15:15:58 -0700279 }
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700280 log.debug("Populating flow rules from {} to {} is successful",
281 targetSw, dst);
sangho20eff1d2015-04-13 15:15:58 -0700282 }
sangho20eff1d2015-04-13 15:15:58 -0700283 }
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700284 //currentEcmpSpgMap.put(dst, ecmpSpg);
sangho20eff1d2015-04-13 15:15:58 -0700285 }
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700286 //Only if all the flows for all impacted routes to a
287 //specific target are pushed successfully, update the
Saurav Das4e3224f2016-11-29 14:27:25 -0800288 //ECMP graph for that target. Or else the next event
289 //would not see any changes in the ECMP graphs.
290 //In another case, the target switch has gone away, so
291 //routes can't be installed. In that case, the current map
292 //is updated here, without any flows being pushed.
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700293 currentEcmpSpgMap.put(impactedDevice,
294 updatedEcmpSpgMap.get(impactedDevice));
sangho20eff1d2015-04-13 15:15:58 -0700295 }
296 return true;
297 }
298
Saurav Dasb5c236e2016-06-07 10:08:06 -0700299 /**
Saurav Das4e3224f2016-11-29 14:27:25 -0800300 * Computes set of affected routes due to failed link. Assumes
Saurav Dasb5c236e2016-06-07 10:08:06 -0700301 * previous ecmp shortest-path graph exists for a switch in order to compute
302 * affected routes. If such a graph does not exist, the method returns null.
303 *
304 * @param linkFail the failed link
305 * @return the set of affected routes which may be empty if no routes were
306 * affected, or null if no previous ecmp spg was found for comparison
307 */
sangho20eff1d2015-04-13 15:15:58 -0700308 private Set<ArrayList<DeviceId>> computeDamagedRoutes(Link linkFail) {
309
310 Set<ArrayList<DeviceId>> routes = new HashSet<>();
311
312 for (Device sw : srManager.deviceService.getDevices()) {
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700313 log.debug("Computing the impacted routes for device {} due to link fail",
314 sw.id());
Charles Chanc42e84e2015-10-20 16:24:19 -0700315 if (!srManager.mastershipService.isLocalMaster(sw.id())) {
Saurav Dasb5c236e2016-06-07 10:08:06 -0700316 log.debug("No mastership for {} .. skipping route optimization",
317 sw.id());
sangho20eff1d2015-04-13 15:15:58 -0700318 continue;
319 }
Shashikanth VH013a7bc2015-12-11 01:32:44 +0530320 EcmpShortestPathGraph ecmpSpg = currentEcmpSpgMap.get(sw.id());
sangho20eff1d2015-04-13 15:15:58 -0700321 if (ecmpSpg == null) {
Saurav Dasb5c236e2016-06-07 10:08:06 -0700322 log.warn("No existing ECMP graph for switch {}. Aborting optimized"
323 + " rerouting and opting for full-reroute", sw.id());
324 return null;
sangho20eff1d2015-04-13 15:15:58 -0700325 }
326 HashMap<Integer, HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>>> switchVia =
327 ecmpSpg.getAllLearnedSwitchesAndVia();
328 for (Integer itrIdx : switchVia.keySet()) {
Saurav Dasb5c236e2016-06-07 10:08:06 -0700329 log.trace("Iterindex# {}", itrIdx);
sangho20eff1d2015-04-13 15:15:58 -0700330 HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>> swViaMap =
331 switchVia.get(itrIdx);
332 for (DeviceId targetSw : swViaMap.keySet()) {
Saurav Das4e3224f2016-11-29 14:27:25 -0800333 DeviceId rootSw = sw.id();
Saurav Dasb5c236e2016-06-07 10:08:06 -0700334 if (log.isTraceEnabled()) {
Saurav Das4e3224f2016-11-29 14:27:25 -0800335 log.trace("TargetSwitch {} --> RootSwitch {}", targetSw, rootSw);
Saurav Dasb5c236e2016-06-07 10:08:06 -0700336 for (ArrayList<DeviceId> via : swViaMap.get(targetSw)) {
337 log.trace(" Via:");
Pier Ventree0ae7a32016-11-23 09:57:42 -0800338 via.forEach(e -> log.trace(" {}", e));
Saurav Dasb5c236e2016-06-07 10:08:06 -0700339 }
340 }
sangho20eff1d2015-04-13 15:15:58 -0700341 Set<ArrayList<DeviceId>> subLinks =
Saurav Das4e3224f2016-11-29 14:27:25 -0800342 computeLinks(targetSw, rootSw, swViaMap);
sangho20eff1d2015-04-13 15:15:58 -0700343 for (ArrayList<DeviceId> alink: subLinks) {
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700344 if ((alink.get(0).equals(linkFail.src().deviceId()) &&
345 alink.get(1).equals(linkFail.dst().deviceId()))
346 ||
347 (alink.get(0).equals(linkFail.dst().deviceId()) &&
348 alink.get(1).equals(linkFail.src().deviceId()))) {
Saurav Das4e3224f2016-11-29 14:27:25 -0800349 log.debug("Impacted route:{}->{}", targetSw, rootSw);
sangho20eff1d2015-04-13 15:15:58 -0700350 ArrayList<DeviceId> aRoute = new ArrayList<>();
351 aRoute.add(targetSw);
Saurav Das4e3224f2016-11-29 14:27:25 -0800352 aRoute.add(rootSw);
sangho20eff1d2015-04-13 15:15:58 -0700353 routes.add(aRoute);
354 break;
355 }
356 }
357 }
358 }
sangho45b009c2015-05-07 13:30:57 -0700359
sangho20eff1d2015-04-13 15:15:58 -0700360 }
361
362 return routes;
363 }
364
Saurav Das4e3224f2016-11-29 14:27:25 -0800365 /**
366 * Computes set of affected routes due to new links or failed switches.
367 *
368 * @return the set of affected routes which may be empty if no routes were
369 * affected
370 */
sangho20eff1d2015-04-13 15:15:58 -0700371 private Set<ArrayList<DeviceId>> computeRouteChange() {
372
Saurav Das4e3224f2016-11-29 14:27:25 -0800373 ImmutableSet.Builder<ArrayList<DeviceId>> changedRoutesBuilder =
374 ImmutableSet.builder();
sangho20eff1d2015-04-13 15:15:58 -0700375
376 for (Device sw : srManager.deviceService.getDevices()) {
Saurav Das4e3224f2016-11-29 14:27:25 -0800377 DeviceId rootSw = sw.id();
378 log.debug("Computing the impacted routes for device {}", rootSw);
379 if (!srManager.mastershipService.isLocalMaster(rootSw)) {
Saurav Dasb5c236e2016-06-07 10:08:06 -0700380 log.debug("No mastership for {} ... skipping route optimization",
Saurav Das4e3224f2016-11-29 14:27:25 -0800381 rootSw);
sangho20eff1d2015-04-13 15:15:58 -0700382 continue;
383 }
Saurav Dasb5c236e2016-06-07 10:08:06 -0700384 if (log.isTraceEnabled()) {
Saurav Das4e3224f2016-11-29 14:27:25 -0800385 log.trace("link of {} - ", rootSw);
386 for (Link link: srManager.linkService.getDeviceLinks(rootSw)) {
Saurav Dasb5c236e2016-06-07 10:08:06 -0700387 log.trace("{} -> {} ", link.src().deviceId(), link.dst().deviceId());
388 }
sangho45b009c2015-05-07 13:30:57 -0700389 }
Saurav Das4e3224f2016-11-29 14:27:25 -0800390 EcmpShortestPathGraph currEcmpSpg = currentEcmpSpgMap.get(rootSw);
391 if (currEcmpSpg == null) {
392 log.debug("No existing ECMP graph for device {}", rootSw);
393 changedRoutesBuilder.add(Lists.newArrayList(rootSw));
sangho20eff1d2015-04-13 15:15:58 -0700394 continue;
395 }
Saurav Das4e3224f2016-11-29 14:27:25 -0800396 EcmpShortestPathGraph newEcmpSpg = updatedEcmpSpgMap.get(rootSw);
397 if (log.isTraceEnabled()) {
398 log.trace("Root switch: {}", rootSw);
399 log.trace(" Current/Existing SPG: {}", currEcmpSpg);
400 log.trace(" New/Updated SPG: {}", newEcmpSpg);
401 }
402 // first use the updated/new map to compare to current/existing map
403 // as new links may have come up
404 changedRoutesBuilder.addAll(compareGraphs(newEcmpSpg, currEcmpSpg, rootSw));
405 // then use the current/existing map to compare to updated/new map
406 // as switch may have been removed
407 changedRoutesBuilder.addAll(compareGraphs(currEcmpSpg, newEcmpSpg, rootSw));
408 }
sangho20eff1d2015-04-13 15:15:58 -0700409
Saurav Das4e3224f2016-11-29 14:27:25 -0800410 Set<ArrayList<DeviceId>> changedRoutes = changedRoutesBuilder.build();
411 for (ArrayList<DeviceId> route: changedRoutes) {
412 log.debug("Route changes Target -> Root");
413 if (route.size() == 1) {
414 log.debug(" : all -> {}", route.get(0));
415 } else {
416 log.debug(" : {} -> {}", route.get(0), route.get(1));
417 }
418 }
419 return changedRoutes;
420 }
421
422 /**
423 * For the root switch, searches all the target nodes reachable in the base
424 * graph, and compares paths to the ones in the comp graph.
425 *
426 * @param base the graph that is indexed for all reachable target nodes
427 * from the root node
428 * @param comp the graph that the base graph is compared to
429 * @param rootSw both ecmp graphs are calculated for the root node
430 * @return all the routes that have changed in the base graph
431 */
432 private Set<ArrayList<DeviceId>> compareGraphs(EcmpShortestPathGraph base,
433 EcmpShortestPathGraph comp,
434 DeviceId rootSw) {
435 ImmutableSet.Builder<ArrayList<DeviceId>> changedRoutesBuilder =
436 ImmutableSet.builder();
437 HashMap<Integer, HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>>> baseMap =
438 base.getAllLearnedSwitchesAndVia();
439 HashMap<Integer, HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>>> compMap =
440 comp.getAllLearnedSwitchesAndVia();
441 for (Integer itrIdx : baseMap.keySet()) {
442 HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>> baseViaMap =
443 baseMap.get(itrIdx);
444 for (DeviceId targetSw : baseViaMap.keySet()) {
445 ArrayList<ArrayList<DeviceId>> basePath = baseViaMap.get(targetSw);
446 ArrayList<ArrayList<DeviceId>> compPath = getVia(compMap, targetSw);
447 if ((compPath == null) || !basePath.equals(compPath)) {
448 log.debug("Impacted route:{} -> {}", targetSw, rootSw);
449 ArrayList<DeviceId> route = new ArrayList<>();
450 route.add(targetSw);
451 route.add(rootSw);
452 changedRoutesBuilder.add(route);
sangho20eff1d2015-04-13 15:15:58 -0700453 }
454 }
sangho45b009c2015-05-07 13:30:57 -0700455 }
Saurav Das4e3224f2016-11-29 14:27:25 -0800456 return changedRoutesBuilder.build();
sangho20eff1d2015-04-13 15:15:58 -0700457 }
458
459 private ArrayList<ArrayList<DeviceId>> getVia(HashMap<Integer, HashMap<DeviceId,
Saurav Das4e3224f2016-11-29 14:27:25 -0800460 ArrayList<ArrayList<DeviceId>>>> switchVia, DeviceId targetSw) {
sangho20eff1d2015-04-13 15:15:58 -0700461 for (Integer itrIdx : switchVia.keySet()) {
462 HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>> swViaMap =
463 switchVia.get(itrIdx);
Saurav Das4e3224f2016-11-29 14:27:25 -0800464 if (swViaMap.get(targetSw) == null) {
sangho20eff1d2015-04-13 15:15:58 -0700465 continue;
466 } else {
Saurav Das4e3224f2016-11-29 14:27:25 -0800467 return swViaMap.get(targetSw);
sangho20eff1d2015-04-13 15:15:58 -0700468 }
469 }
470
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700471 return null;
sangho20eff1d2015-04-13 15:15:58 -0700472 }
473
474 private Set<ArrayList<DeviceId>> computeLinks(DeviceId src,
475 DeviceId dst,
476 HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>> viaMap) {
477 Set<ArrayList<DeviceId>> subLinks = Sets.newHashSet();
478 for (ArrayList<DeviceId> via : viaMap.get(src)) {
479 DeviceId linkSrc = src;
480 DeviceId linkDst = dst;
481 for (DeviceId viaDevice: via) {
482 ArrayList<DeviceId> link = new ArrayList<>();
483 linkDst = viaDevice;
484 link.add(linkSrc);
485 link.add(linkDst);
486 subLinks.add(link);
487 linkSrc = viaDevice;
488 }
489 ArrayList<DeviceId> link = new ArrayList<>();
490 link.add(linkSrc);
491 link.add(dst);
492 subLinks.add(link);
493 }
494
495 return subLinks;
496 }
497
Charles Chan93e71ba2016-04-29 14:38:22 -0700498 /**
499 * Populate ECMP rules for subnets from all switches to destination.
500 *
501 * @param destSw Device ID of destination switch
502 * @param ecmpSPG ECMP shortest path graph
503 * @param subnets Subnets to be populated. If empty, populate all configured subnets.
504 * @return true if succeed
505 */
sangho20eff1d2015-04-13 15:15:58 -0700506 private boolean populateEcmpRoutingRules(DeviceId destSw,
Charles Chan93e71ba2016-04-29 14:38:22 -0700507 EcmpShortestPathGraph ecmpSPG,
508 Set<Ip4Prefix> subnets) {
sanghob35a6192015-04-01 13:05:26 -0700509
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700510 HashMap<Integer, HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>>> switchVia = ecmpSPG
511 .getAllLearnedSwitchesAndVia();
sanghob35a6192015-04-01 13:05:26 -0700512 for (Integer itrIdx : switchVia.keySet()) {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700513 HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>> swViaMap = switchVia
514 .get(itrIdx);
sanghob35a6192015-04-01 13:05:26 -0700515 for (DeviceId targetSw : swViaMap.keySet()) {
sanghob35a6192015-04-01 13:05:26 -0700516 Set<DeviceId> nextHops = new HashSet<>();
Saurav Dasa07f2032015-10-19 14:37:36 -0700517 log.debug("** Iter: {} root: {} target: {}", itrIdx, destSw, targetSw);
sanghob35a6192015-04-01 13:05:26 -0700518 for (ArrayList<DeviceId> via : swViaMap.get(targetSw)) {
519 if (via.isEmpty()) {
520 nextHops.add(destSw);
521 } else {
522 nextHops.add(via.get(0));
523 }
524 }
Charles Chan93e71ba2016-04-29 14:38:22 -0700525 if (!populateEcmpRoutingRulePartial(targetSw, destSw, nextHops, subnets)) {
sanghob35a6192015-04-01 13:05:26 -0700526 return false;
527 }
528 }
529 }
530
531 return true;
532 }
533
Charles Chan93e71ba2016-04-29 14:38:22 -0700534 /**
535 * Populate ECMP rules for subnets from target to destination via nexthops.
536 *
Saurav Das25190812016-05-27 13:54:07 -0700537 * @param targetSw Device ID of target switch in which rules will be programmed
538 * @param destSw Device ID of final destination switch to which the rules will forward
539 * @param nextHops List of next hops via which destSw will be reached
Charles Chan93e71ba2016-04-29 14:38:22 -0700540 * @param subnets Subnets to be populated. If empty, populate all configured subnets.
541 * @return true if succeed
542 */
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700543 private boolean populateEcmpRoutingRulePartial(DeviceId targetSw,
544 DeviceId destSw,
Charles Chan93e71ba2016-04-29 14:38:22 -0700545 Set<DeviceId> nextHops,
546 Set<Ip4Prefix> subnets) {
sanghob35a6192015-04-01 13:05:26 -0700547 boolean result;
548
549 if (nextHops.isEmpty()) {
550 nextHops.add(destSw);
551 }
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700552 // If both target switch and dest switch are edge routers, then set IP
sangho52abe3a2015-05-05 14:13:34 -0700553 // rule for both subnet and router IP.
Charles Chan0b4e6182015-11-03 10:42:14 -0800554 boolean targetIsEdge;
555 boolean destIsEdge;
Pier Ventree0ae7a32016-11-23 09:57:42 -0800556 Ip4Address destRouterIpv4;
557 Ip6Address destRouterIpv6;
Charles Chan0b4e6182015-11-03 10:42:14 -0800558
559 try {
560 targetIsEdge = config.isEdgeDevice(targetSw);
561 destIsEdge = config.isEdgeDevice(destSw);
Pier Ventree0ae7a32016-11-23 09:57:42 -0800562 destRouterIpv4 = config.getRouterIpv4(destSw);
563 destRouterIpv6 = config.getRouterIpv6(destSw);
Charles Chan0b4e6182015-11-03 10:42:14 -0800564 } catch (DeviceConfigNotFoundException e) {
565 log.warn(e.getMessage() + " Aborting populateEcmpRoutingRulePartial.");
566 return false;
567 }
568
569 if (targetIsEdge && destIsEdge) {
Charles Chan93e71ba2016-04-29 14:38:22 -0700570 subnets = (subnets != null && !subnets.isEmpty()) ? subnets : config.getSubnets(destSw);
Saurav Dasa07f2032015-10-19 14:37:36 -0700571 log.debug("* populateEcmpRoutingRulePartial in device {} towards {} for subnets {}",
Saurav Das8a0732e2015-11-20 15:27:53 -0800572 targetSw, destSw, subnets);
Charles Chan93e71ba2016-04-29 14:38:22 -0700573 result = rulePopulator.populateIpRuleForSubnet(targetSw, subnets,
574 destSw, nextHops);
sanghob35a6192015-04-01 13:05:26 -0700575 if (!result) {
576 return false;
577 }
578
Pier Ventree0ae7a32016-11-23 09:57:42 -0800579 IpPrefix routerIpPrefix = destRouterIpv4.toIpPrefix();
Saurav Dasa07f2032015-10-19 14:37:36 -0700580 log.debug("* populateEcmpRoutingRulePartial in device {} towards {} for router IP {}",
Saurav Das8a0732e2015-11-20 15:27:53 -0800581 targetSw, destSw, routerIpPrefix);
sangho666cd6d2015-04-14 16:27:13 -0700582 result = rulePopulator.populateIpRuleForRouter(targetSw, routerIpPrefix, destSw, nextHops);
sanghob35a6192015-04-01 13:05:26 -0700583 if (!result) {
584 return false;
585 }
Pier Ventree0ae7a32016-11-23 09:57:42 -0800586 /*
587 * If present we deal with IPv6 loopback.
588 */
589 if (destRouterIpv6 != null) {
590 routerIpPrefix = destRouterIpv6.toIpPrefix();
591 log.debug("* populateEcmpRoutingRulePartial in device {} towards {} for v6 router IP {}",
592 targetSw, destSw, routerIpPrefix);
593 result = rulePopulator.populateIpRuleForRouter(targetSw, routerIpPrefix, destSw, nextHops);
594 if (!result) {
595 return false;
596 }
597 }
sanghob35a6192015-04-01 13:05:26 -0700598
Charles Chan0b4e6182015-11-03 10:42:14 -0800599 } else if (targetIsEdge) {
Saurav Das8a0732e2015-11-20 15:27:53 -0800600 // If the target switch is an edge router, then set IP rules for the router IP.
Pier Ventree0ae7a32016-11-23 09:57:42 -0800601 IpPrefix routerIpPrefix = destRouterIpv4.toIpPrefix();
Saurav Dasa07f2032015-10-19 14:37:36 -0700602 log.debug("* populateEcmpRoutingRulePartial in device {} towards {} for router IP {}",
Saurav Das8a0732e2015-11-20 15:27:53 -0800603 targetSw, destSw, routerIpPrefix);
sangho666cd6d2015-04-14 16:27:13 -0700604 result = rulePopulator.populateIpRuleForRouter(targetSw, routerIpPrefix, destSw, nextHops);
sanghob35a6192015-04-01 13:05:26 -0700605 if (!result) {
606 return false;
607 }
Pier Ventree0ae7a32016-11-23 09:57:42 -0800608 if (destRouterIpv6 != null) {
609 routerIpPrefix = destRouterIpv6.toIpPrefix();
610 log.debug("* populateEcmpRoutingRulePartial in device {} towards {} for v6 router IP {}",
611 targetSw, destSw, routerIpPrefix);
612 result = rulePopulator.populateIpRuleForRouter(targetSw, routerIpPrefix, destSw, nextHops);
613 if (!result) {
614 return false;
615 }
616 }
sangho52abe3a2015-05-05 14:13:34 -0700617 }
sangho52abe3a2015-05-05 14:13:34 -0700618 // Populates MPLS rules to all routers
Saurav Dasa07f2032015-10-19 14:37:36 -0700619 log.debug("* populateEcmpRoutingRulePartial in device{} towards {} for all MPLS rules",
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700620 targetSw, destSw);
Pier Ventree0ae7a32016-11-23 09:57:42 -0800621 result = rulePopulator.populateMplsRule(targetSw, destSw, nextHops, destRouterIpv4);
sangho52abe3a2015-05-05 14:13:34 -0700622 if (!result) {
623 return false;
sanghob35a6192015-04-01 13:05:26 -0700624 }
Pier Ventree0ae7a32016-11-23 09:57:42 -0800625 /*
626 * If present we will populate the MPLS rules for the IPv6 sid.
627 */
628 if (destRouterIpv6 != null) {
629 result = rulePopulator.populateMplsRule(targetSw, destSw, nextHops, destRouterIpv6);
630 if (!result) {
631 return false;
632 }
633 }
sanghob35a6192015-04-01 13:05:26 -0700634 return true;
635 }
636
637 /**
Saurav Das822c4e22015-10-23 10:51:11 -0700638 * Populates filtering rules for permitting Router DstMac and VLAN.
sanghob35a6192015-04-01 13:05:26 -0700639 *
640 * @param deviceId Switch ID to set the rules
641 */
Saurav Das822c4e22015-10-23 10:51:11 -0700642 public void populatePortAddressingRules(DeviceId deviceId) {
Saurav Das822c4e22015-10-23 10:51:11 -0700643 rulePopulator.populateRouterIpPunts(deviceId);
Pier Luigi9e5c5ca2017-01-12 18:14:58 -0800644 rulePopulator.populateArpNdpPunts(deviceId);
Saurav Das59232cf2016-04-27 18:35:50 -0700645
646 // Although device is added, sometimes device store does not have the
647 // ports for this device yet. It results in missing filtering rules in the
648 // switch. We will attempt it a few times. If it still does not work,
649 // user can manually repopulate using CLI command sr-reroute-network
Saurav Dasd2fded02016-12-02 15:43:47 -0800650 PortFilterInfo firstRun = rulePopulator.populateRouterMacVlanFilters(deviceId);
651 if (firstRun == null) {
652 firstRun = new PortFilterInfo(0, 0, 0);
Saurav Das59232cf2016-04-27 18:35:50 -0700653 }
Saurav Dasd2fded02016-12-02 15:43:47 -0800654 executorService.schedule(new RetryFilters(deviceId, firstRun),
655 RETRY_INTERVAL_MS, TimeUnit.MILLISECONDS);
sanghob35a6192015-04-01 13:05:26 -0700656 }
657
658 /**
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700659 * Start the flow rule population process if it was never started. The
660 * process finishes successfully when all flow rules are set and stops with
661 * ABORTED status when any groups required for flows is not set yet.
sanghob35a6192015-04-01 13:05:26 -0700662 */
663 public void startPopulationProcess() {
HIGUCHI Yuta84a25fc2015-09-08 16:16:31 +0900664 statusLock.lock();
665 try {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700666 if (populationStatus == Status.IDLE
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700667 || populationStatus == Status.SUCCEEDED
668 || populationStatus == Status.ABORTED) {
sanghob35a6192015-04-01 13:05:26 -0700669 populationStatus = Status.STARTED;
670 populateAllRoutingRules();
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700671 } else {
672 log.warn("Not initiating startPopulationProcess as populationStatus is {}",
673 populationStatus);
sanghob35a6192015-04-01 13:05:26 -0700674 }
HIGUCHI Yuta84a25fc2015-09-08 16:16:31 +0900675 } finally {
676 statusLock.unlock();
sanghob35a6192015-04-01 13:05:26 -0700677 }
678 }
679
680 /**
681 * Resume the flow rule population process if it was aborted for any reason.
682 * Mostly the process is aborted when the groups required are not set yet.
Saurav Dasa07f2032015-10-19 14:37:36 -0700683 * XXX is this called?
684 *
sanghob35a6192015-04-01 13:05:26 -0700685 */
686 public void resumePopulationProcess() {
HIGUCHI Yuta84a25fc2015-09-08 16:16:31 +0900687 statusLock.lock();
688 try {
sanghob35a6192015-04-01 13:05:26 -0700689 if (populationStatus == Status.ABORTED) {
690 populationStatus = Status.STARTED;
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700691 // TODO: we need to restart from the point aborted instead of
692 // restarting.
sanghob35a6192015-04-01 13:05:26 -0700693 populateAllRoutingRules();
694 }
HIGUCHI Yuta84a25fc2015-09-08 16:16:31 +0900695 } finally {
696 statusLock.unlock();
sanghob35a6192015-04-01 13:05:26 -0700697 }
698 }
Saurav Das80980c72016-03-23 11:22:49 -0700699
Charles Chan93e71ba2016-04-29 14:38:22 -0700700 /**
701 * Populate rules of given subnet at given location.
702 *
703 * @param cp connect point of the subnet being added
704 * @param subnets subnet being added
705 * @return true if succeed
706 */
707 protected boolean populateSubnet(ConnectPoint cp, Set<Ip4Prefix> subnets) {
708 statusLock.lock();
709 try {
710 EcmpShortestPathGraph ecmpSpg = currentEcmpSpgMap.get(cp.deviceId());
711 if (ecmpSpg == null) {
712 log.warn("Fail to populating subnet {}: {}", subnets, ECMPSPG_MISSING);
713 return false;
714 }
715 return populateEcmpRoutingRules(cp.deviceId(), ecmpSpg, subnets);
716 } finally {
717 statusLock.unlock();
718 }
719 }
720
721 /**
722 * Revoke rules of given subnet at given location.
723 *
724 * @param subnets subnet being removed
725 * @return true if succeed
726 */
727 protected boolean revokeSubnet(Set<Ip4Prefix> subnets) {
728 statusLock.lock();
729 try {
730 return srManager.routingRulePopulator.revokeIpRuleForSubnet(subnets);
731 } finally {
732 statusLock.unlock();
733 }
734 }
735
736 protected void purgeEcmpGraph(DeviceId deviceId) {
Saurav Das80980c72016-03-23 11:22:49 -0700737 currentEcmpSpgMap.remove(deviceId);
Saurav Das7a1ffca2016-03-28 19:00:18 -0700738 if (updatedEcmpSpgMap != null) {
739 updatedEcmpSpgMap.remove(deviceId);
740 }
Pier Ventre2c515312016-09-13 21:33:40 -0700741 this.populateRoutingRulesForLinkStatusChange(null);
Saurav Das80980c72016-03-23 11:22:49 -0700742 }
Saurav Das59232cf2016-04-27 18:35:50 -0700743
Saurav Dasd2fded02016-12-02 15:43:47 -0800744 /**
745 * Utility class used to temporarily store information about the ports on a
746 * device processed for filtering objectives.
747 *
748 */
749 public final class PortFilterInfo {
750 int disabledPorts = 0, suppressedPorts = 0, filteredPorts = 0;
Saurav Das59232cf2016-04-27 18:35:50 -0700751
Saurav Dasd2fded02016-12-02 15:43:47 -0800752 public PortFilterInfo(int disabledPorts, int suppressedPorts,
753 int filteredPorts) {
754 this.disabledPorts = disabledPorts;
755 this.filteredPorts = filteredPorts;
756 this.suppressedPorts = suppressedPorts;
757 }
758
759 @Override
760 public int hashCode() {
761 return Objects.hash(disabledPorts, filteredPorts, suppressedPorts);
762 }
763
764 @Override
765 public boolean equals(Object obj) {
766 if (this == obj) {
767 return true;
768 }
769 if ((obj == null) || (!(obj instanceof PortFilterInfo))) {
770 return false;
771 }
772 PortFilterInfo other = (PortFilterInfo) obj;
773 return ((disabledPorts == other.disabledPorts) &&
774 (filteredPorts == other.filteredPorts) &&
775 (suppressedPorts == other.suppressedPorts));
776 }
777
778 @Override
779 public String toString() {
780 MoreObjects.ToStringHelper helper = toStringHelper(this)
781 .add("disabledPorts", disabledPorts)
782 .add("suppressedPorts", suppressedPorts)
783 .add("filteredPorts", filteredPorts);
784 return helper.toString();
785 }
786 }
787
788 /**
789 * RetryFilters populates filtering objectives for a device and keeps retrying
790 * till the number of ports filtered are constant for a predefined number
791 * of attempts.
792 */
793 protected final class RetryFilters implements Runnable {
794 int constantAttempts = MAX_CONSTANT_RETRY_ATTEMPTS;
795 DeviceId devId;
796 int counter;
797 PortFilterInfo prevRun;
798
799 private RetryFilters(DeviceId deviceId, PortFilterInfo previousRun) {
Saurav Das59232cf2016-04-27 18:35:50 -0700800 devId = deviceId;
Saurav Dasd2fded02016-12-02 15:43:47 -0800801 prevRun = previousRun;
802 counter = 0;
Saurav Das59232cf2016-04-27 18:35:50 -0700803 }
804
805 @Override
806 public void run() {
Saurav Dasd2fded02016-12-02 15:43:47 -0800807 log.info("RETRY FILTER ATTEMPT {} ** dev:{}", ++counter, devId);
808 PortFilterInfo thisRun = rulePopulator.populateRouterMacVlanFilters(devId);
809 boolean sameResult = prevRun.equals(thisRun);
810 log.debug("dev:{} prevRun:{} thisRun:{} sameResult:{}", devId, prevRun,
811 thisRun, sameResult);
812 if (thisRun == null || !sameResult || (sameResult && --constantAttempts > 0)) {
813 executorService.schedule(this, RETRY_INTERVAL_MS, TimeUnit.MILLISECONDS);
814 if (!sameResult) {
815 constantAttempts = MAX_CONSTANT_RETRY_ATTEMPTS; //reset
816 }
Saurav Das59232cf2016-04-27 18:35:50 -0700817 }
Saurav Dasd2fded02016-12-02 15:43:47 -0800818 prevRun = (thisRun == null) ? prevRun : thisRun;
Saurav Das59232cf2016-04-27 18:35:50 -0700819 }
Saurav Das59232cf2016-04-27 18:35:50 -0700820 }
821
sanghob35a6192015-04-01 13:05:26 -0700822}