blob: 9f2e84ea228ad52349c3c66876a20fa01a739abf [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
sangho20eff1d2015-04-13 15:15:58 -070018import com.google.common.collect.Maps;
19import com.google.common.collect.Sets;
sangho666cd6d2015-04-14 16:27:13 -070020import org.onlab.packet.Ip4Address;
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -070021import org.onlab.packet.Ip4Prefix;
sanghob35a6192015-04-01 13:05:26 -070022import org.onlab.packet.IpPrefix;
23import org.onosproject.net.Device;
24import org.onosproject.net.DeviceId;
sangho20eff1d2015-04-13 15:15:58 -070025import org.onosproject.net.Link;
Charles Chan0b4e6182015-11-03 10:42:14 -080026import org.onosproject.segmentrouting.config.DeviceConfigNotFoundException;
27import org.onosproject.segmentrouting.config.DeviceConfiguration;
sanghob35a6192015-04-01 13:05:26 -070028import org.slf4j.Logger;
29import org.slf4j.LoggerFactory;
30
31import java.util.ArrayList;
32import java.util.HashMap;
33import java.util.HashSet;
34import java.util.Set;
Saurav Das59232cf2016-04-27 18:35:50 -070035import java.util.concurrent.Executors;
36import java.util.concurrent.ScheduledExecutorService;
37import java.util.concurrent.TimeUnit;
HIGUCHI Yuta84a25fc2015-09-08 16:16:31 +090038import java.util.concurrent.locks.Lock;
39import java.util.concurrent.locks.ReentrantLock;
sanghob35a6192015-04-01 13:05:26 -070040
41import static com.google.common.base.Preconditions.checkNotNull;
42
Charles Chane849c192016-01-11 18:28:54 -080043/**
44 * Default routing handler that is responsible for route computing and
45 * routing rule population.
46 */
sanghob35a6192015-04-01 13:05:26 -070047public class DefaultRoutingHandler {
48
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070049 private static Logger log = LoggerFactory
50 .getLogger(DefaultRoutingHandler.class);
sanghob35a6192015-04-01 13:05:26 -070051
52 private SegmentRoutingManager srManager;
53 private RoutingRulePopulator rulePopulator;
Shashikanth VH013a7bc2015-12-11 01:32:44 +053054 private HashMap<DeviceId, EcmpShortestPathGraph> currentEcmpSpgMap;
55 private HashMap<DeviceId, EcmpShortestPathGraph> updatedEcmpSpgMap;
sangho666cd6d2015-04-14 16:27:13 -070056 private DeviceConfiguration config;
HIGUCHI Yuta84a25fc2015-09-08 16:16:31 +090057 private final Lock statusLock = new ReentrantLock();
58 private volatile Status populationStatus;
Saurav Das59232cf2016-04-27 18:35:50 -070059 private static final int MAX_RETRY_ATTEMPTS = 5;
60 private ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1);
sanghob35a6192015-04-01 13:05:26 -070061
62 /**
63 * Represents the default routing population status.
64 */
65 public enum Status {
66 // population process is not started yet.
67 IDLE,
68
69 // population process started.
70 STARTED,
71
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070072 // population process was aborted due to errors, mostly for groups not
73 // found.
sanghob35a6192015-04-01 13:05:26 -070074 ABORTED,
75
76 // population process was finished successfully.
77 SUCCEEDED
78 }
79
80 /**
81 * Creates a DefaultRoutingHandler object.
82 *
83 * @param srManager SegmentRoutingManager object
84 */
85 public DefaultRoutingHandler(SegmentRoutingManager srManager) {
86 this.srManager = srManager;
87 this.rulePopulator = checkNotNull(srManager.routingRulePopulator);
sangho666cd6d2015-04-14 16:27:13 -070088 this.config = checkNotNull(srManager.deviceConfiguration);
sanghob35a6192015-04-01 13:05:26 -070089 this.populationStatus = Status.IDLE;
sangho20eff1d2015-04-13 15:15:58 -070090 this.currentEcmpSpgMap = Maps.newHashMap();
sanghob35a6192015-04-01 13:05:26 -070091 }
92
93 /**
94 * Populates all routing rules to all connected routers, including default
95 * routing rules, adjacency rules, and policy rules if any.
96 *
97 * @return true if it succeeds in populating all rules, otherwise false
98 */
99 public boolean populateAllRoutingRules() {
100
HIGUCHI Yuta84a25fc2015-09-08 16:16:31 +0900101 statusLock.lock();
102 try {
103 populationStatus = Status.STARTED;
104 rulePopulator.resetCounter();
Saurav Dasa07f2032015-10-19 14:37:36 -0700105 log.info("Starting to populate segment-routing rules");
HIGUCHI Yuta84a25fc2015-09-08 16:16:31 +0900106 log.debug("populateAllRoutingRules: populationStatus is STARTED");
sanghob35a6192015-04-01 13:05:26 -0700107
HIGUCHI Yuta84a25fc2015-09-08 16:16:31 +0900108 for (Device sw : srManager.deviceService.getDevices()) {
Charles Chanc42e84e2015-10-20 16:24:19 -0700109 if (!srManager.mastershipService.isLocalMaster(sw.id())) {
HIGUCHI Yuta84a25fc2015-09-08 16:16:31 +0900110 log.debug("populateAllRoutingRules: skipping device {}...we are not master",
111 sw.id());
112 continue;
113 }
114
Shashikanth VH013a7bc2015-12-11 01:32:44 +0530115 EcmpShortestPathGraph ecmpSpg = new EcmpShortestPathGraph(sw.id(), srManager);
HIGUCHI Yuta84a25fc2015-09-08 16:16:31 +0900116 if (!populateEcmpRoutingRules(sw.id(), ecmpSpg)) {
117 log.debug("populateAllRoutingRules: populationStatus is ABORTED");
118 populationStatus = Status.ABORTED;
119 log.debug("Abort routing rule population");
120 return false;
121 }
122 currentEcmpSpgMap.put(sw.id(), ecmpSpg);
123
124 // TODO: Set adjacency routing rule for all switches
sanghob35a6192015-04-01 13:05:26 -0700125 }
126
HIGUCHI Yuta84a25fc2015-09-08 16:16:31 +0900127 log.debug("populateAllRoutingRules: populationStatus is SUCCEEDED");
128 populationStatus = Status.SUCCEEDED;
Saurav Dasa07f2032015-10-19 14:37:36 -0700129 log.info("Completed routing rule population. Total # of rules pushed : {}",
HIGUCHI Yuta84a25fc2015-09-08 16:16:31 +0900130 rulePopulator.getCounter());
131 return true;
132 } finally {
133 statusLock.unlock();
sanghob35a6192015-04-01 13:05:26 -0700134 }
sanghob35a6192015-04-01 13:05:26 -0700135 }
136
sangho20eff1d2015-04-13 15:15:58 -0700137 /**
138 * Populates the routing rules according to the route changes due to the link
139 * failure or link add. It computes the routes changed due to the link changes and
140 * repopulates the rules only for the routes.
141 *
142 * @param linkFail link failed, null for link added
143 * @return true if it succeeds to populate all rules, false otherwise
144 */
145 public boolean populateRoutingRulesForLinkStatusChange(Link linkFail) {
146
HIGUCHI Yuta84a25fc2015-09-08 16:16:31 +0900147 statusLock.lock();
148 try {
sangho20eff1d2015-04-13 15:15:58 -0700149
150 if (populationStatus == Status.STARTED) {
sangho52abe3a2015-05-05 14:13:34 -0700151 log.warn("Previous rule population is not finished.");
sangho20eff1d2015-04-13 15:15:58 -0700152 return true;
153 }
154
sangho45b009c2015-05-07 13:30:57 -0700155 // Take the snapshots of the links
156 updatedEcmpSpgMap = new HashMap<>();
157 for (Device sw : srManager.deviceService.getDevices()) {
Charles Chanc42e84e2015-10-20 16:24:19 -0700158 if (!srManager.mastershipService.isLocalMaster(sw.id())) {
sangho45b009c2015-05-07 13:30:57 -0700159 continue;
160 }
Shashikanth VH013a7bc2015-12-11 01:32:44 +0530161 EcmpShortestPathGraph ecmpSpgUpdated =
162 new EcmpShortestPathGraph(sw.id(), srManager);
sangho45b009c2015-05-07 13:30:57 -0700163 updatedEcmpSpgMap.put(sw.id(), ecmpSpgUpdated);
164 }
165
sangho52abe3a2015-05-05 14:13:34 -0700166 log.info("Starts rule population from link change");
167
sangho20eff1d2015-04-13 15:15:58 -0700168 Set<ArrayList<DeviceId>> routeChanges;
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700169 log.trace("populateRoutingRulesForLinkStatusChange: "
170 + "populationStatus is STARTED");
sangho20eff1d2015-04-13 15:15:58 -0700171 populationStatus = Status.STARTED;
172 if (linkFail == null) {
173 // Compare all routes of existing ECMP SPG with the new ones
174 routeChanges = computeRouteChange();
175 } else {
176 // Compare existing ECMP SPG only with the link removed
177 routeChanges = computeDamagedRoutes(linkFail);
178 }
179
180 if (routeChanges.isEmpty()) {
sangho52abe3a2015-05-05 14:13:34 -0700181 log.info("No route changes for the link status change");
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700182 log.debug("populateRoutingRulesForLinkStatusChange: populationStatus is SUCCEEDED");
sangho20eff1d2015-04-13 15:15:58 -0700183 populationStatus = Status.SUCCEEDED;
184 return true;
185 }
186
187 if (repopulateRoutingRulesForRoutes(routeChanges)) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700188 log.debug("populateRoutingRulesForLinkStatusChange: populationStatus is SUCCEEDED");
sangho20eff1d2015-04-13 15:15:58 -0700189 populationStatus = Status.SUCCEEDED;
190 log.info("Complete to repopulate the rules. # of rules populated : {}",
191 rulePopulator.getCounter());
192 return true;
193 } else {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700194 log.debug("populateRoutingRulesForLinkStatusChange: populationStatus is ABORTED");
sangho20eff1d2015-04-13 15:15:58 -0700195 populationStatus = Status.ABORTED;
196 log.warn("Failed to repopulate the rules.");
197 return false;
198 }
HIGUCHI Yuta84a25fc2015-09-08 16:16:31 +0900199 } finally {
200 statusLock.unlock();
sangho20eff1d2015-04-13 15:15:58 -0700201 }
202 }
203
204 private boolean repopulateRoutingRulesForRoutes(Set<ArrayList<DeviceId>> routes) {
205 rulePopulator.resetCounter();
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700206 HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>> routesBydevice =
207 new HashMap<>();
sangho20eff1d2015-04-13 15:15:58 -0700208 for (ArrayList<DeviceId> link: routes) {
sangho834e4b02015-05-01 09:38:25 -0700209 // When only the source device is defined, reinstall routes to all other devices
sangho20eff1d2015-04-13 15:15:58 -0700210 if (link.size() == 1) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700211 log.trace("repopulateRoutingRulesForRoutes: running ECMP graph for device {}", link.get(0));
Shashikanth VH013a7bc2015-12-11 01:32:44 +0530212 EcmpShortestPathGraph ecmpSpg = new EcmpShortestPathGraph(link.get(0), srManager);
sangho20eff1d2015-04-13 15:15:58 -0700213 if (populateEcmpRoutingRules(link.get(0), ecmpSpg)) {
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700214 log.debug("Populating flow rules from {} to all is successful",
215 link.get(0));
sangho20eff1d2015-04-13 15:15:58 -0700216 currentEcmpSpgMap.put(link.get(0), ecmpSpg);
sangho52abe3a2015-05-05 14:13:34 -0700217 } else {
sangho45b009c2015-05-07 13:30:57 -0700218 log.warn("Failed to populate the flow rules from {} to all", link.get(0));
sangho52abe3a2015-05-05 14:13:34 -0700219 return false;
sangho20eff1d2015-04-13 15:15:58 -0700220 }
sangho45b009c2015-05-07 13:30:57 -0700221 } else {
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700222 ArrayList<ArrayList<DeviceId>> deviceRoutes =
223 routesBydevice.get(link.get(1));
224 if (deviceRoutes == null) {
225 deviceRoutes = new ArrayList<>();
226 routesBydevice.put(link.get(1), deviceRoutes);
227 }
228 deviceRoutes.add(link);
229 }
230 }
231
232 for (DeviceId impactedDevice : routesBydevice.keySet()) {
233 ArrayList<ArrayList<DeviceId>> deviceRoutes =
234 routesBydevice.get(impactedDevice);
235 for (ArrayList<DeviceId> link: deviceRoutes) {
236 log.debug("repopulate RoutingRules For Routes {} -> {}",
237 link.get(0), link.get(1));
sangho45b009c2015-05-07 13:30:57 -0700238 DeviceId src = link.get(0);
239 DeviceId dst = link.get(1);
Shashikanth VH013a7bc2015-12-11 01:32:44 +0530240 EcmpShortestPathGraph ecmpSpg = updatedEcmpSpgMap.get(dst);
sangho45b009c2015-05-07 13:30:57 -0700241 HashMap<Integer, HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>>> switchVia =
242 ecmpSpg.getAllLearnedSwitchesAndVia();
243 for (Integer itrIdx : switchVia.keySet()) {
244 HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>> swViaMap =
245 switchVia.get(itrIdx);
246 for (DeviceId targetSw : swViaMap.keySet()) {
247 if (!targetSw.equals(src)) {
248 continue;
249 }
250 Set<DeviceId> nextHops = new HashSet<>();
251 for (ArrayList<DeviceId> via : swViaMap.get(targetSw)) {
252 if (via.isEmpty()) {
253 nextHops.add(dst);
254 } else {
255 nextHops.add(via.get(0));
256 }
257 }
258 if (!populateEcmpRoutingRulePartial(targetSw, dst, nextHops)) {
259 return false;
sangho20eff1d2015-04-13 15:15:58 -0700260 }
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700261 log.debug("Populating flow rules from {} to {} is successful",
262 targetSw, dst);
sangho20eff1d2015-04-13 15:15:58 -0700263 }
sangho20eff1d2015-04-13 15:15:58 -0700264 }
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700265 //currentEcmpSpgMap.put(dst, ecmpSpg);
sangho20eff1d2015-04-13 15:15:58 -0700266 }
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700267 //Only if all the flows for all impacted routes to a
268 //specific target are pushed successfully, update the
269 //ECMP graph for that target. (Or else the next event
270 //would not see any changes in the ECMP graphs)
271 currentEcmpSpgMap.put(impactedDevice,
272 updatedEcmpSpgMap.get(impactedDevice));
sangho20eff1d2015-04-13 15:15:58 -0700273 }
274 return true;
275 }
276
277 private Set<ArrayList<DeviceId>> computeDamagedRoutes(Link linkFail) {
278
279 Set<ArrayList<DeviceId>> routes = new HashSet<>();
280
281 for (Device sw : srManager.deviceService.getDevices()) {
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700282 log.debug("Computing the impacted routes for device {} due to link fail",
283 sw.id());
Charles Chanc42e84e2015-10-20 16:24:19 -0700284 if (!srManager.mastershipService.isLocalMaster(sw.id())) {
sangho20eff1d2015-04-13 15:15:58 -0700285 continue;
286 }
Shashikanth VH013a7bc2015-12-11 01:32:44 +0530287 EcmpShortestPathGraph ecmpSpg = currentEcmpSpgMap.get(sw.id());
sangho20eff1d2015-04-13 15:15:58 -0700288 if (ecmpSpg == null) {
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700289 log.error("No existing ECMP graph for switch {}", sw.id());
sangho20eff1d2015-04-13 15:15:58 -0700290 continue;
291 }
292 HashMap<Integer, HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>>> switchVia =
293 ecmpSpg.getAllLearnedSwitchesAndVia();
294 for (Integer itrIdx : switchVia.keySet()) {
295 HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>> swViaMap =
296 switchVia.get(itrIdx);
297 for (DeviceId targetSw : swViaMap.keySet()) {
298 DeviceId destSw = sw.id();
299 Set<ArrayList<DeviceId>> subLinks =
300 computeLinks(targetSw, destSw, swViaMap);
301 for (ArrayList<DeviceId> alink: subLinks) {
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700302 if ((alink.get(0).equals(linkFail.src().deviceId()) &&
303 alink.get(1).equals(linkFail.dst().deviceId()))
304 ||
305 (alink.get(0).equals(linkFail.dst().deviceId()) &&
306 alink.get(1).equals(linkFail.src().deviceId()))) {
307 log.debug("Impacted route:{}->{}", targetSw, destSw);
sangho20eff1d2015-04-13 15:15:58 -0700308 ArrayList<DeviceId> aRoute = new ArrayList<>();
309 aRoute.add(targetSw);
310 aRoute.add(destSw);
311 routes.add(aRoute);
312 break;
313 }
314 }
315 }
316 }
sangho45b009c2015-05-07 13:30:57 -0700317
sangho20eff1d2015-04-13 15:15:58 -0700318 }
319
320 return routes;
321 }
322
323 private Set<ArrayList<DeviceId>> computeRouteChange() {
324
325 Set<ArrayList<DeviceId>> routes = new HashSet<>();
326
327 for (Device sw : srManager.deviceService.getDevices()) {
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700328 log.debug("Computing the impacted routes for device {}",
329 sw.id());
Charles Chanc42e84e2015-10-20 16:24:19 -0700330 if (!srManager.mastershipService.isLocalMaster(sw.id())) {
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700331 log.debug("No mastership for {} and skip route optimization",
332 sw.id());
sangho20eff1d2015-04-13 15:15:58 -0700333 continue;
334 }
sangho45b009c2015-05-07 13:30:57 -0700335
336 log.trace("link of {} - ", sw.id());
337 for (Link link: srManager.linkService.getDeviceLinks(sw.id())) {
338 log.trace("{} -> {} ", link.src().deviceId(), link.dst().deviceId());
339 }
340
341 log.debug("Checking route change for switch {}", sw.id());
Shashikanth VH013a7bc2015-12-11 01:32:44 +0530342 EcmpShortestPathGraph ecmpSpg = currentEcmpSpgMap.get(sw.id());
sangho20eff1d2015-04-13 15:15:58 -0700343 if (ecmpSpg == null) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700344 log.debug("No existing ECMP graph for device {}", sw.id());
sangho20eff1d2015-04-13 15:15:58 -0700345 ArrayList<DeviceId> route = new ArrayList<>();
346 route.add(sw.id());
347 routes.add(route);
348 continue;
349 }
Shashikanth VH013a7bc2015-12-11 01:32:44 +0530350 EcmpShortestPathGraph newEcmpSpg = updatedEcmpSpgMap.get(sw.id());
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700351 //currentEcmpSpgMap.put(sw.id(), newEcmpSpg);
sangho20eff1d2015-04-13 15:15:58 -0700352 HashMap<Integer, HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>>> switchVia =
353 ecmpSpg.getAllLearnedSwitchesAndVia();
354 HashMap<Integer, HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>>> switchViaUpdated =
355 newEcmpSpg.getAllLearnedSwitchesAndVia();
356
sangho45b009c2015-05-07 13:30:57 -0700357 for (Integer itrIdx : switchViaUpdated.keySet()) {
358 HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>> swViaMapUpdated =
359 switchViaUpdated.get(itrIdx);
360 for (DeviceId srcSw : swViaMapUpdated.keySet()) {
361 ArrayList<ArrayList<DeviceId>> viaUpdated = swViaMapUpdated.get(srcSw);
362 ArrayList<ArrayList<DeviceId>> via = getVia(switchVia, srcSw);
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700363 if ((via == null) || !viaUpdated.equals(via)) {
364 log.debug("Impacted route:{}->{}", srcSw, sw.id());
sangho20eff1d2015-04-13 15:15:58 -0700365 ArrayList<DeviceId> route = new ArrayList<>();
366 route.add(srcSw);
367 route.add(sw.id());
368 routes.add(route);
369 }
370 }
371 }
sangho45b009c2015-05-07 13:30:57 -0700372 }
sangho20eff1d2015-04-13 15:15:58 -0700373
sangho45b009c2015-05-07 13:30:57 -0700374 for (ArrayList<DeviceId> link: routes) {
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700375 log.trace("Route changes - ");
sangho45b009c2015-05-07 13:30:57 -0700376 if (link.size() == 1) {
377 log.trace(" : {} - all", link.get(0));
378 } else {
379 log.trace(" : {} - {}", link.get(0), link.get(1));
380 }
sangho20eff1d2015-04-13 15:15:58 -0700381 }
382
383 return routes;
384 }
385
386 private ArrayList<ArrayList<DeviceId>> getVia(HashMap<Integer, HashMap<DeviceId,
387 ArrayList<ArrayList<DeviceId>>>> switchVia, DeviceId srcSw) {
388 for (Integer itrIdx : switchVia.keySet()) {
389 HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>> swViaMap =
390 switchVia.get(itrIdx);
391 if (swViaMap.get(srcSw) == null) {
392 continue;
393 } else {
394 return swViaMap.get(srcSw);
395 }
396 }
397
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700398 return null;
sangho20eff1d2015-04-13 15:15:58 -0700399 }
400
401 private Set<ArrayList<DeviceId>> computeLinks(DeviceId src,
402 DeviceId dst,
403 HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>> viaMap) {
404 Set<ArrayList<DeviceId>> subLinks = Sets.newHashSet();
405 for (ArrayList<DeviceId> via : viaMap.get(src)) {
406 DeviceId linkSrc = src;
407 DeviceId linkDst = dst;
408 for (DeviceId viaDevice: via) {
409 ArrayList<DeviceId> link = new ArrayList<>();
410 linkDst = viaDevice;
411 link.add(linkSrc);
412 link.add(linkDst);
413 subLinks.add(link);
414 linkSrc = viaDevice;
415 }
416 ArrayList<DeviceId> link = new ArrayList<>();
417 link.add(linkSrc);
418 link.add(dst);
419 subLinks.add(link);
420 }
421
422 return subLinks;
423 }
424
425 private boolean populateEcmpRoutingRules(DeviceId destSw,
Shashikanth VH013a7bc2015-12-11 01:32:44 +0530426 EcmpShortestPathGraph ecmpSPG) {
sanghob35a6192015-04-01 13:05:26 -0700427
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700428 HashMap<Integer, HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>>> switchVia = ecmpSPG
429 .getAllLearnedSwitchesAndVia();
sanghob35a6192015-04-01 13:05:26 -0700430 for (Integer itrIdx : switchVia.keySet()) {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700431 HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>> swViaMap = switchVia
432 .get(itrIdx);
sanghob35a6192015-04-01 13:05:26 -0700433 for (DeviceId targetSw : swViaMap.keySet()) {
sanghob35a6192015-04-01 13:05:26 -0700434 Set<DeviceId> nextHops = new HashSet<>();
Saurav Dasa07f2032015-10-19 14:37:36 -0700435 log.debug("** Iter: {} root: {} target: {}", itrIdx, destSw, targetSw);
sanghob35a6192015-04-01 13:05:26 -0700436 for (ArrayList<DeviceId> via : swViaMap.get(targetSw)) {
437 if (via.isEmpty()) {
438 nextHops.add(destSw);
439 } else {
440 nextHops.add(via.get(0));
441 }
442 }
443 if (!populateEcmpRoutingRulePartial(targetSw, destSw, nextHops)) {
444 return false;
445 }
446 }
447 }
448
449 return true;
450 }
451
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700452 private boolean populateEcmpRoutingRulePartial(DeviceId targetSw,
453 DeviceId destSw,
454 Set<DeviceId> nextHops) {
sanghob35a6192015-04-01 13:05:26 -0700455 boolean result;
456
457 if (nextHops.isEmpty()) {
458 nextHops.add(destSw);
459 }
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700460 // If both target switch and dest switch are edge routers, then set IP
sangho52abe3a2015-05-05 14:13:34 -0700461 // rule for both subnet and router IP.
Charles Chan0b4e6182015-11-03 10:42:14 -0800462 boolean targetIsEdge;
463 boolean destIsEdge;
464 Ip4Address destRouterIp;
465
466 try {
467 targetIsEdge = config.isEdgeDevice(targetSw);
468 destIsEdge = config.isEdgeDevice(destSw);
469 destRouterIp = config.getRouterIp(destSw);
470 } catch (DeviceConfigNotFoundException e) {
471 log.warn(e.getMessage() + " Aborting populateEcmpRoutingRulePartial.");
472 return false;
473 }
474
475 if (targetIsEdge && destIsEdge) {
Charles Chan9f676b62015-10-29 14:58:10 -0700476 Set<Ip4Prefix> subnets = config.getSubnets(destSw);
Saurav Dasa07f2032015-10-19 14:37:36 -0700477 log.debug("* populateEcmpRoutingRulePartial in device {} towards {} for subnets {}",
Saurav Das8a0732e2015-11-20 15:27:53 -0800478 targetSw, destSw, subnets);
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700479 result = rulePopulator.populateIpRuleForSubnet(targetSw,
480 subnets,
481 destSw,
482 nextHops);
sanghob35a6192015-04-01 13:05:26 -0700483 if (!result) {
484 return false;
485 }
486
Charles Chan0b4e6182015-11-03 10:42:14 -0800487 Ip4Address routerIp = destRouterIp;
sangho666cd6d2015-04-14 16:27:13 -0700488 IpPrefix routerIpPrefix = IpPrefix.valueOf(routerIp, IpPrefix.MAX_INET_MASK_LENGTH);
Saurav Dasa07f2032015-10-19 14:37:36 -0700489 log.debug("* populateEcmpRoutingRulePartial in device {} towards {} for router IP {}",
Saurav Das8a0732e2015-11-20 15:27:53 -0800490 targetSw, destSw, routerIpPrefix);
sangho666cd6d2015-04-14 16:27:13 -0700491 result = rulePopulator.populateIpRuleForRouter(targetSw, routerIpPrefix, destSw, nextHops);
sanghob35a6192015-04-01 13:05:26 -0700492 if (!result) {
493 return false;
494 }
495
Charles Chan0b4e6182015-11-03 10:42:14 -0800496 } else if (targetIsEdge) {
Saurav Das8a0732e2015-11-20 15:27:53 -0800497 // If the target switch is an edge router, then set IP rules for the router IP.
Charles Chan0b4e6182015-11-03 10:42:14 -0800498 Ip4Address routerIp = destRouterIp;
sangho666cd6d2015-04-14 16:27:13 -0700499 IpPrefix routerIpPrefix = IpPrefix.valueOf(routerIp, IpPrefix.MAX_INET_MASK_LENGTH);
Saurav Dasa07f2032015-10-19 14:37:36 -0700500 log.debug("* populateEcmpRoutingRulePartial in device {} towards {} for router IP {}",
Saurav Das8a0732e2015-11-20 15:27:53 -0800501 targetSw, destSw, routerIpPrefix);
sangho666cd6d2015-04-14 16:27:13 -0700502 result = rulePopulator.populateIpRuleForRouter(targetSw, routerIpPrefix, destSw, nextHops);
sanghob35a6192015-04-01 13:05:26 -0700503 if (!result) {
504 return false;
505 }
sangho52abe3a2015-05-05 14:13:34 -0700506 }
sangho52abe3a2015-05-05 14:13:34 -0700507 // Populates MPLS rules to all routers
Saurav Dasa07f2032015-10-19 14:37:36 -0700508 log.debug("* populateEcmpRoutingRulePartial in device{} towards {} for all MPLS rules",
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700509 targetSw, destSw);
sangho52abe3a2015-05-05 14:13:34 -0700510 result = rulePopulator.populateMplsRule(targetSw, destSw, nextHops);
511 if (!result) {
512 return false;
sanghob35a6192015-04-01 13:05:26 -0700513 }
sanghob35a6192015-04-01 13:05:26 -0700514 return true;
515 }
516
517 /**
Saurav Das822c4e22015-10-23 10:51:11 -0700518 * Populates filtering rules for permitting Router DstMac and VLAN.
sanghob35a6192015-04-01 13:05:26 -0700519 *
520 * @param deviceId Switch ID to set the rules
521 */
Saurav Das822c4e22015-10-23 10:51:11 -0700522 public void populatePortAddressingRules(DeviceId deviceId) {
Charles Chane849c192016-01-11 18:28:54 -0800523 rulePopulator.populateXConnectVlanFilters(deviceId);
Saurav Das822c4e22015-10-23 10:51:11 -0700524 rulePopulator.populateRouterIpPunts(deviceId);
Saurav Das59232cf2016-04-27 18:35:50 -0700525
526 // Although device is added, sometimes device store does not have the
527 // ports for this device yet. It results in missing filtering rules in the
528 // switch. We will attempt it a few times. If it still does not work,
529 // user can manually repopulate using CLI command sr-reroute-network
530 boolean success = rulePopulator.populateRouterMacVlanFilters(deviceId);
531 if (!success) {
532 executorService.schedule(new RetryFilters(deviceId), 200, TimeUnit.MILLISECONDS);
533 }
sanghob35a6192015-04-01 13:05:26 -0700534 }
535
536 /**
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700537 * Start the flow rule population process if it was never started. The
538 * process finishes successfully when all flow rules are set and stops with
539 * ABORTED status when any groups required for flows is not set yet.
sanghob35a6192015-04-01 13:05:26 -0700540 */
541 public void startPopulationProcess() {
HIGUCHI Yuta84a25fc2015-09-08 16:16:31 +0900542 statusLock.lock();
543 try {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700544 if (populationStatus == Status.IDLE
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700545 || populationStatus == Status.SUCCEEDED
546 || populationStatus == Status.ABORTED) {
sanghob35a6192015-04-01 13:05:26 -0700547 populationStatus = Status.STARTED;
548 populateAllRoutingRules();
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700549 } else {
550 log.warn("Not initiating startPopulationProcess as populationStatus is {}",
551 populationStatus);
sanghob35a6192015-04-01 13:05:26 -0700552 }
HIGUCHI Yuta84a25fc2015-09-08 16:16:31 +0900553 } finally {
554 statusLock.unlock();
sanghob35a6192015-04-01 13:05:26 -0700555 }
556 }
557
558 /**
559 * Resume the flow rule population process if it was aborted for any reason.
560 * Mostly the process is aborted when the groups required are not set yet.
Saurav Dasa07f2032015-10-19 14:37:36 -0700561 * XXX is this called?
562 *
sanghob35a6192015-04-01 13:05:26 -0700563 */
564 public void resumePopulationProcess() {
HIGUCHI Yuta84a25fc2015-09-08 16:16:31 +0900565 statusLock.lock();
566 try {
sanghob35a6192015-04-01 13:05:26 -0700567 if (populationStatus == Status.ABORTED) {
568 populationStatus = Status.STARTED;
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700569 // TODO: we need to restart from the point aborted instead of
570 // restarting.
sanghob35a6192015-04-01 13:05:26 -0700571 populateAllRoutingRules();
572 }
HIGUCHI Yuta84a25fc2015-09-08 16:16:31 +0900573 } finally {
574 statusLock.unlock();
sanghob35a6192015-04-01 13:05:26 -0700575 }
576 }
Saurav Das80980c72016-03-23 11:22:49 -0700577
578 public void purgeEcmpGraph(DeviceId deviceId) {
579 currentEcmpSpgMap.remove(deviceId);
Saurav Das7a1ffca2016-03-28 19:00:18 -0700580 if (updatedEcmpSpgMap != null) {
581 updatedEcmpSpgMap.remove(deviceId);
582 }
Saurav Das80980c72016-03-23 11:22:49 -0700583 }
Saurav Das59232cf2016-04-27 18:35:50 -0700584
585 private class RetryFilters implements Runnable {
586 int attempts = MAX_RETRY_ATTEMPTS;
587 DeviceId devId;
588
589 public RetryFilters(DeviceId deviceId) {
590 devId = deviceId;
591 }
592
593 @Override
594 public void run() {
595 boolean success = rulePopulator.populateRouterMacVlanFilters(devId);
596 if (!success && --attempts > 0) {
597 executorService.schedule(this, 200, TimeUnit.MILLISECONDS);
598 } else if (attempts == 0) {
599 log.error("Unable to populate MacVlan filters in dev:{}", devId);
600 }
601 }
602
603 }
604
sanghob35a6192015-04-01 13:05:26 -0700605}