blob: a3de7f36d8cd4c91e5b353670771f927349d8e1a [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;
HIGUCHI Yuta84a25fc2015-09-08 16:16:31 +090035import java.util.concurrent.locks.Lock;
36import java.util.concurrent.locks.ReentrantLock;
sanghob35a6192015-04-01 13:05:26 -070037
38import static com.google.common.base.Preconditions.checkNotNull;
39
Charles Chane849c192016-01-11 18:28:54 -080040/**
41 * Default routing handler that is responsible for route computing and
42 * routing rule population.
43 */
sanghob35a6192015-04-01 13:05:26 -070044public class DefaultRoutingHandler {
45
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070046 private static Logger log = LoggerFactory
47 .getLogger(DefaultRoutingHandler.class);
sanghob35a6192015-04-01 13:05:26 -070048
49 private SegmentRoutingManager srManager;
50 private RoutingRulePopulator rulePopulator;
Shashikanth VH013a7bc2015-12-11 01:32:44 +053051 private HashMap<DeviceId, EcmpShortestPathGraph> currentEcmpSpgMap;
52 private HashMap<DeviceId, EcmpShortestPathGraph> updatedEcmpSpgMap;
sangho666cd6d2015-04-14 16:27:13 -070053 private DeviceConfiguration config;
HIGUCHI Yuta84a25fc2015-09-08 16:16:31 +090054 private final Lock statusLock = new ReentrantLock();
55 private volatile Status populationStatus;
sanghob35a6192015-04-01 13:05:26 -070056
57 /**
58 * Represents the default routing population status.
59 */
60 public enum Status {
61 // population process is not started yet.
62 IDLE,
63
64 // population process started.
65 STARTED,
66
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070067 // population process was aborted due to errors, mostly for groups not
68 // found.
sanghob35a6192015-04-01 13:05:26 -070069 ABORTED,
70
71 // population process was finished successfully.
72 SUCCEEDED
73 }
74
75 /**
76 * Creates a DefaultRoutingHandler object.
77 *
78 * @param srManager SegmentRoutingManager object
79 */
80 public DefaultRoutingHandler(SegmentRoutingManager srManager) {
81 this.srManager = srManager;
82 this.rulePopulator = checkNotNull(srManager.routingRulePopulator);
sangho666cd6d2015-04-14 16:27:13 -070083 this.config = checkNotNull(srManager.deviceConfiguration);
sanghob35a6192015-04-01 13:05:26 -070084 this.populationStatus = Status.IDLE;
sangho20eff1d2015-04-13 15:15:58 -070085 this.currentEcmpSpgMap = Maps.newHashMap();
sanghob35a6192015-04-01 13:05:26 -070086 }
87
88 /**
89 * Populates all routing rules to all connected routers, including default
90 * routing rules, adjacency rules, and policy rules if any.
91 *
92 * @return true if it succeeds in populating all rules, otherwise false
93 */
94 public boolean populateAllRoutingRules() {
95
HIGUCHI Yuta84a25fc2015-09-08 16:16:31 +090096 statusLock.lock();
97 try {
98 populationStatus = Status.STARTED;
99 rulePopulator.resetCounter();
Saurav Dasa07f2032015-10-19 14:37:36 -0700100 log.info("Starting to populate segment-routing rules");
HIGUCHI Yuta84a25fc2015-09-08 16:16:31 +0900101 log.debug("populateAllRoutingRules: populationStatus is STARTED");
sanghob35a6192015-04-01 13:05:26 -0700102
HIGUCHI Yuta84a25fc2015-09-08 16:16:31 +0900103 for (Device sw : srManager.deviceService.getDevices()) {
Charles Chanc42e84e2015-10-20 16:24:19 -0700104 if (!srManager.mastershipService.isLocalMaster(sw.id())) {
HIGUCHI Yuta84a25fc2015-09-08 16:16:31 +0900105 log.debug("populateAllRoutingRules: skipping device {}...we are not master",
106 sw.id());
107 continue;
108 }
109
Shashikanth VH013a7bc2015-12-11 01:32:44 +0530110 EcmpShortestPathGraph ecmpSpg = new EcmpShortestPathGraph(sw.id(), srManager);
HIGUCHI Yuta84a25fc2015-09-08 16:16:31 +0900111 if (!populateEcmpRoutingRules(sw.id(), ecmpSpg)) {
112 log.debug("populateAllRoutingRules: populationStatus is ABORTED");
113 populationStatus = Status.ABORTED;
114 log.debug("Abort routing rule population");
115 return false;
116 }
117 currentEcmpSpgMap.put(sw.id(), ecmpSpg);
118
119 // TODO: Set adjacency routing rule for all switches
sanghob35a6192015-04-01 13:05:26 -0700120 }
121
HIGUCHI Yuta84a25fc2015-09-08 16:16:31 +0900122 log.debug("populateAllRoutingRules: populationStatus is SUCCEEDED");
123 populationStatus = Status.SUCCEEDED;
Saurav Dasa07f2032015-10-19 14:37:36 -0700124 log.info("Completed routing rule population. Total # of rules pushed : {}",
HIGUCHI Yuta84a25fc2015-09-08 16:16:31 +0900125 rulePopulator.getCounter());
126 return true;
127 } finally {
128 statusLock.unlock();
sanghob35a6192015-04-01 13:05:26 -0700129 }
sanghob35a6192015-04-01 13:05:26 -0700130 }
131
sangho20eff1d2015-04-13 15:15:58 -0700132 /**
133 * Populates the routing rules according to the route changes due to the link
134 * failure or link add. It computes the routes changed due to the link changes and
135 * repopulates the rules only for the routes.
136 *
137 * @param linkFail link failed, null for link added
138 * @return true if it succeeds to populate all rules, false otherwise
139 */
140 public boolean populateRoutingRulesForLinkStatusChange(Link linkFail) {
141
HIGUCHI Yuta84a25fc2015-09-08 16:16:31 +0900142 statusLock.lock();
143 try {
sangho20eff1d2015-04-13 15:15:58 -0700144
145 if (populationStatus == Status.STARTED) {
sangho52abe3a2015-05-05 14:13:34 -0700146 log.warn("Previous rule population is not finished.");
sangho20eff1d2015-04-13 15:15:58 -0700147 return true;
148 }
149
sangho45b009c2015-05-07 13:30:57 -0700150 // Take the snapshots of the links
151 updatedEcmpSpgMap = new HashMap<>();
152 for (Device sw : srManager.deviceService.getDevices()) {
Charles Chanc42e84e2015-10-20 16:24:19 -0700153 if (!srManager.mastershipService.isLocalMaster(sw.id())) {
sangho45b009c2015-05-07 13:30:57 -0700154 continue;
155 }
Shashikanth VH013a7bc2015-12-11 01:32:44 +0530156 EcmpShortestPathGraph ecmpSpgUpdated =
157 new EcmpShortestPathGraph(sw.id(), srManager);
sangho45b009c2015-05-07 13:30:57 -0700158 updatedEcmpSpgMap.put(sw.id(), ecmpSpgUpdated);
159 }
160
sangho52abe3a2015-05-05 14:13:34 -0700161 log.info("Starts rule population from link change");
162
sangho20eff1d2015-04-13 15:15:58 -0700163 Set<ArrayList<DeviceId>> routeChanges;
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700164 log.trace("populateRoutingRulesForLinkStatusChange: "
165 + "populationStatus is STARTED");
sangho20eff1d2015-04-13 15:15:58 -0700166 populationStatus = Status.STARTED;
167 if (linkFail == null) {
168 // Compare all routes of existing ECMP SPG with the new ones
169 routeChanges = computeRouteChange();
170 } else {
171 // Compare existing ECMP SPG only with the link removed
172 routeChanges = computeDamagedRoutes(linkFail);
173 }
174
175 if (routeChanges.isEmpty()) {
sangho52abe3a2015-05-05 14:13:34 -0700176 log.info("No route changes for the link status change");
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700177 log.debug("populateRoutingRulesForLinkStatusChange: populationStatus is SUCCEEDED");
sangho20eff1d2015-04-13 15:15:58 -0700178 populationStatus = Status.SUCCEEDED;
179 return true;
180 }
181
182 if (repopulateRoutingRulesForRoutes(routeChanges)) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700183 log.debug("populateRoutingRulesForLinkStatusChange: populationStatus is SUCCEEDED");
sangho20eff1d2015-04-13 15:15:58 -0700184 populationStatus = Status.SUCCEEDED;
185 log.info("Complete to repopulate the rules. # of rules populated : {}",
186 rulePopulator.getCounter());
187 return true;
188 } else {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700189 log.debug("populateRoutingRulesForLinkStatusChange: populationStatus is ABORTED");
sangho20eff1d2015-04-13 15:15:58 -0700190 populationStatus = Status.ABORTED;
191 log.warn("Failed to repopulate the rules.");
192 return false;
193 }
HIGUCHI Yuta84a25fc2015-09-08 16:16:31 +0900194 } finally {
195 statusLock.unlock();
sangho20eff1d2015-04-13 15:15:58 -0700196 }
197 }
198
199 private boolean repopulateRoutingRulesForRoutes(Set<ArrayList<DeviceId>> routes) {
200 rulePopulator.resetCounter();
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700201 HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>> routesBydevice =
202 new HashMap<>();
sangho20eff1d2015-04-13 15:15:58 -0700203 for (ArrayList<DeviceId> link: routes) {
sangho834e4b02015-05-01 09:38:25 -0700204 // When only the source device is defined, reinstall routes to all other devices
sangho20eff1d2015-04-13 15:15:58 -0700205 if (link.size() == 1) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700206 log.trace("repopulateRoutingRulesForRoutes: running ECMP graph for device {}", link.get(0));
Shashikanth VH013a7bc2015-12-11 01:32:44 +0530207 EcmpShortestPathGraph ecmpSpg = new EcmpShortestPathGraph(link.get(0), srManager);
sangho20eff1d2015-04-13 15:15:58 -0700208 if (populateEcmpRoutingRules(link.get(0), ecmpSpg)) {
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700209 log.debug("Populating flow rules from {} to all is successful",
210 link.get(0));
sangho20eff1d2015-04-13 15:15:58 -0700211 currentEcmpSpgMap.put(link.get(0), ecmpSpg);
sangho52abe3a2015-05-05 14:13:34 -0700212 } else {
sangho45b009c2015-05-07 13:30:57 -0700213 log.warn("Failed to populate the flow rules from {} to all", link.get(0));
sangho52abe3a2015-05-05 14:13:34 -0700214 return false;
sangho20eff1d2015-04-13 15:15:58 -0700215 }
sangho45b009c2015-05-07 13:30:57 -0700216 } else {
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700217 ArrayList<ArrayList<DeviceId>> deviceRoutes =
218 routesBydevice.get(link.get(1));
219 if (deviceRoutes == null) {
220 deviceRoutes = new ArrayList<>();
221 routesBydevice.put(link.get(1), deviceRoutes);
222 }
223 deviceRoutes.add(link);
224 }
225 }
226
227 for (DeviceId impactedDevice : routesBydevice.keySet()) {
228 ArrayList<ArrayList<DeviceId>> deviceRoutes =
229 routesBydevice.get(impactedDevice);
230 for (ArrayList<DeviceId> link: deviceRoutes) {
231 log.debug("repopulate RoutingRules For Routes {} -> {}",
232 link.get(0), link.get(1));
sangho45b009c2015-05-07 13:30:57 -0700233 DeviceId src = link.get(0);
234 DeviceId dst = link.get(1);
Shashikanth VH013a7bc2015-12-11 01:32:44 +0530235 EcmpShortestPathGraph ecmpSpg = updatedEcmpSpgMap.get(dst);
sangho45b009c2015-05-07 13:30:57 -0700236 HashMap<Integer, HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>>> switchVia =
237 ecmpSpg.getAllLearnedSwitchesAndVia();
238 for (Integer itrIdx : switchVia.keySet()) {
239 HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>> swViaMap =
240 switchVia.get(itrIdx);
241 for (DeviceId targetSw : swViaMap.keySet()) {
242 if (!targetSw.equals(src)) {
243 continue;
244 }
245 Set<DeviceId> nextHops = new HashSet<>();
246 for (ArrayList<DeviceId> via : swViaMap.get(targetSw)) {
247 if (via.isEmpty()) {
248 nextHops.add(dst);
249 } else {
250 nextHops.add(via.get(0));
251 }
252 }
253 if (!populateEcmpRoutingRulePartial(targetSw, dst, nextHops)) {
254 return false;
sangho20eff1d2015-04-13 15:15:58 -0700255 }
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700256 log.debug("Populating flow rules from {} to {} is successful",
257 targetSw, dst);
sangho20eff1d2015-04-13 15:15:58 -0700258 }
sangho20eff1d2015-04-13 15:15:58 -0700259 }
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700260 //currentEcmpSpgMap.put(dst, ecmpSpg);
sangho20eff1d2015-04-13 15:15:58 -0700261 }
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700262 //Only if all the flows for all impacted routes to a
263 //specific target are pushed successfully, update the
264 //ECMP graph for that target. (Or else the next event
265 //would not see any changes in the ECMP graphs)
266 currentEcmpSpgMap.put(impactedDevice,
267 updatedEcmpSpgMap.get(impactedDevice));
sangho20eff1d2015-04-13 15:15:58 -0700268 }
269 return true;
270 }
271
272 private Set<ArrayList<DeviceId>> computeDamagedRoutes(Link linkFail) {
273
274 Set<ArrayList<DeviceId>> routes = new HashSet<>();
275
276 for (Device sw : srManager.deviceService.getDevices()) {
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700277 log.debug("Computing the impacted routes for device {} due to link fail",
278 sw.id());
Charles Chanc42e84e2015-10-20 16:24:19 -0700279 if (!srManager.mastershipService.isLocalMaster(sw.id())) {
sangho20eff1d2015-04-13 15:15:58 -0700280 continue;
281 }
Shashikanth VH013a7bc2015-12-11 01:32:44 +0530282 EcmpShortestPathGraph ecmpSpg = currentEcmpSpgMap.get(sw.id());
sangho20eff1d2015-04-13 15:15:58 -0700283 if (ecmpSpg == null) {
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700284 log.error("No existing ECMP graph for switch {}", sw.id());
sangho20eff1d2015-04-13 15:15:58 -0700285 continue;
286 }
287 HashMap<Integer, HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>>> switchVia =
288 ecmpSpg.getAllLearnedSwitchesAndVia();
289 for (Integer itrIdx : switchVia.keySet()) {
290 HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>> swViaMap =
291 switchVia.get(itrIdx);
292 for (DeviceId targetSw : swViaMap.keySet()) {
293 DeviceId destSw = sw.id();
294 Set<ArrayList<DeviceId>> subLinks =
295 computeLinks(targetSw, destSw, swViaMap);
296 for (ArrayList<DeviceId> alink: subLinks) {
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700297 if ((alink.get(0).equals(linkFail.src().deviceId()) &&
298 alink.get(1).equals(linkFail.dst().deviceId()))
299 ||
300 (alink.get(0).equals(linkFail.dst().deviceId()) &&
301 alink.get(1).equals(linkFail.src().deviceId()))) {
302 log.debug("Impacted route:{}->{}", targetSw, destSw);
sangho20eff1d2015-04-13 15:15:58 -0700303 ArrayList<DeviceId> aRoute = new ArrayList<>();
304 aRoute.add(targetSw);
305 aRoute.add(destSw);
306 routes.add(aRoute);
307 break;
308 }
309 }
310 }
311 }
sangho45b009c2015-05-07 13:30:57 -0700312
sangho20eff1d2015-04-13 15:15:58 -0700313 }
314
315 return routes;
316 }
317
318 private Set<ArrayList<DeviceId>> computeRouteChange() {
319
320 Set<ArrayList<DeviceId>> routes = new HashSet<>();
321
322 for (Device sw : srManager.deviceService.getDevices()) {
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700323 log.debug("Computing the impacted routes for device {}",
324 sw.id());
Charles Chanc42e84e2015-10-20 16:24:19 -0700325 if (!srManager.mastershipService.isLocalMaster(sw.id())) {
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700326 log.debug("No mastership for {} and skip route optimization",
327 sw.id());
sangho20eff1d2015-04-13 15:15:58 -0700328 continue;
329 }
sangho45b009c2015-05-07 13:30:57 -0700330
331 log.trace("link of {} - ", sw.id());
332 for (Link link: srManager.linkService.getDeviceLinks(sw.id())) {
333 log.trace("{} -> {} ", link.src().deviceId(), link.dst().deviceId());
334 }
335
336 log.debug("Checking route change for switch {}", sw.id());
Shashikanth VH013a7bc2015-12-11 01:32:44 +0530337 EcmpShortestPathGraph ecmpSpg = currentEcmpSpgMap.get(sw.id());
sangho20eff1d2015-04-13 15:15:58 -0700338 if (ecmpSpg == null) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700339 log.debug("No existing ECMP graph for device {}", sw.id());
sangho20eff1d2015-04-13 15:15:58 -0700340 ArrayList<DeviceId> route = new ArrayList<>();
341 route.add(sw.id());
342 routes.add(route);
343 continue;
344 }
Shashikanth VH013a7bc2015-12-11 01:32:44 +0530345 EcmpShortestPathGraph newEcmpSpg = updatedEcmpSpgMap.get(sw.id());
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700346 //currentEcmpSpgMap.put(sw.id(), newEcmpSpg);
sangho20eff1d2015-04-13 15:15:58 -0700347 HashMap<Integer, HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>>> switchVia =
348 ecmpSpg.getAllLearnedSwitchesAndVia();
349 HashMap<Integer, HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>>> switchViaUpdated =
350 newEcmpSpg.getAllLearnedSwitchesAndVia();
351
sangho45b009c2015-05-07 13:30:57 -0700352 for (Integer itrIdx : switchViaUpdated.keySet()) {
353 HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>> swViaMapUpdated =
354 switchViaUpdated.get(itrIdx);
355 for (DeviceId srcSw : swViaMapUpdated.keySet()) {
356 ArrayList<ArrayList<DeviceId>> viaUpdated = swViaMapUpdated.get(srcSw);
357 ArrayList<ArrayList<DeviceId>> via = getVia(switchVia, srcSw);
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700358 if ((via == null) || !viaUpdated.equals(via)) {
359 log.debug("Impacted route:{}->{}", srcSw, sw.id());
sangho20eff1d2015-04-13 15:15:58 -0700360 ArrayList<DeviceId> route = new ArrayList<>();
361 route.add(srcSw);
362 route.add(sw.id());
363 routes.add(route);
364 }
365 }
366 }
sangho45b009c2015-05-07 13:30:57 -0700367 }
sangho20eff1d2015-04-13 15:15:58 -0700368
sangho45b009c2015-05-07 13:30:57 -0700369 for (ArrayList<DeviceId> link: routes) {
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700370 log.trace("Route changes - ");
sangho45b009c2015-05-07 13:30:57 -0700371 if (link.size() == 1) {
372 log.trace(" : {} - all", link.get(0));
373 } else {
374 log.trace(" : {} - {}", link.get(0), link.get(1));
375 }
sangho20eff1d2015-04-13 15:15:58 -0700376 }
377
378 return routes;
379 }
380
381 private ArrayList<ArrayList<DeviceId>> getVia(HashMap<Integer, HashMap<DeviceId,
382 ArrayList<ArrayList<DeviceId>>>> switchVia, DeviceId srcSw) {
383 for (Integer itrIdx : switchVia.keySet()) {
384 HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>> swViaMap =
385 switchVia.get(itrIdx);
386 if (swViaMap.get(srcSw) == null) {
387 continue;
388 } else {
389 return swViaMap.get(srcSw);
390 }
391 }
392
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700393 return null;
sangho20eff1d2015-04-13 15:15:58 -0700394 }
395
396 private Set<ArrayList<DeviceId>> computeLinks(DeviceId src,
397 DeviceId dst,
398 HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>> viaMap) {
399 Set<ArrayList<DeviceId>> subLinks = Sets.newHashSet();
400 for (ArrayList<DeviceId> via : viaMap.get(src)) {
401 DeviceId linkSrc = src;
402 DeviceId linkDst = dst;
403 for (DeviceId viaDevice: via) {
404 ArrayList<DeviceId> link = new ArrayList<>();
405 linkDst = viaDevice;
406 link.add(linkSrc);
407 link.add(linkDst);
408 subLinks.add(link);
409 linkSrc = viaDevice;
410 }
411 ArrayList<DeviceId> link = new ArrayList<>();
412 link.add(linkSrc);
413 link.add(dst);
414 subLinks.add(link);
415 }
416
417 return subLinks;
418 }
419
420 private boolean populateEcmpRoutingRules(DeviceId destSw,
Shashikanth VH013a7bc2015-12-11 01:32:44 +0530421 EcmpShortestPathGraph ecmpSPG) {
sanghob35a6192015-04-01 13:05:26 -0700422
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700423 HashMap<Integer, HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>>> switchVia = ecmpSPG
424 .getAllLearnedSwitchesAndVia();
sanghob35a6192015-04-01 13:05:26 -0700425 for (Integer itrIdx : switchVia.keySet()) {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700426 HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>> swViaMap = switchVia
427 .get(itrIdx);
sanghob35a6192015-04-01 13:05:26 -0700428 for (DeviceId targetSw : swViaMap.keySet()) {
sanghob35a6192015-04-01 13:05:26 -0700429 Set<DeviceId> nextHops = new HashSet<>();
Saurav Dasa07f2032015-10-19 14:37:36 -0700430 log.debug("** Iter: {} root: {} target: {}", itrIdx, destSw, targetSw);
sanghob35a6192015-04-01 13:05:26 -0700431 for (ArrayList<DeviceId> via : swViaMap.get(targetSw)) {
432 if (via.isEmpty()) {
433 nextHops.add(destSw);
434 } else {
435 nextHops.add(via.get(0));
436 }
437 }
438 if (!populateEcmpRoutingRulePartial(targetSw, destSw, nextHops)) {
439 return false;
440 }
441 }
442 }
443
444 return true;
445 }
446
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700447 private boolean populateEcmpRoutingRulePartial(DeviceId targetSw,
448 DeviceId destSw,
449 Set<DeviceId> nextHops) {
sanghob35a6192015-04-01 13:05:26 -0700450 boolean result;
451
452 if (nextHops.isEmpty()) {
453 nextHops.add(destSw);
454 }
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700455 // If both target switch and dest switch are edge routers, then set IP
sangho52abe3a2015-05-05 14:13:34 -0700456 // rule for both subnet and router IP.
Charles Chan0b4e6182015-11-03 10:42:14 -0800457 boolean targetIsEdge;
458 boolean destIsEdge;
459 Ip4Address destRouterIp;
460
461 try {
462 targetIsEdge = config.isEdgeDevice(targetSw);
463 destIsEdge = config.isEdgeDevice(destSw);
464 destRouterIp = config.getRouterIp(destSw);
465 } catch (DeviceConfigNotFoundException e) {
466 log.warn(e.getMessage() + " Aborting populateEcmpRoutingRulePartial.");
467 return false;
468 }
469
470 if (targetIsEdge && destIsEdge) {
Charles Chan9f676b62015-10-29 14:58:10 -0700471 Set<Ip4Prefix> subnets = config.getSubnets(destSw);
Saurav Dasa07f2032015-10-19 14:37:36 -0700472 log.debug("* populateEcmpRoutingRulePartial in device {} towards {} for subnets {}",
Saurav Das8a0732e2015-11-20 15:27:53 -0800473 targetSw, destSw, subnets);
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700474 result = rulePopulator.populateIpRuleForSubnet(targetSw,
475 subnets,
476 destSw,
477 nextHops);
sanghob35a6192015-04-01 13:05:26 -0700478 if (!result) {
479 return false;
480 }
481
Charles Chan0b4e6182015-11-03 10:42:14 -0800482 Ip4Address routerIp = destRouterIp;
sangho666cd6d2015-04-14 16:27:13 -0700483 IpPrefix routerIpPrefix = IpPrefix.valueOf(routerIp, IpPrefix.MAX_INET_MASK_LENGTH);
Saurav Dasa07f2032015-10-19 14:37:36 -0700484 log.debug("* populateEcmpRoutingRulePartial in device {} towards {} for router IP {}",
Saurav Das8a0732e2015-11-20 15:27:53 -0800485 targetSw, destSw, routerIpPrefix);
sangho666cd6d2015-04-14 16:27:13 -0700486 result = rulePopulator.populateIpRuleForRouter(targetSw, routerIpPrefix, destSw, nextHops);
sanghob35a6192015-04-01 13:05:26 -0700487 if (!result) {
488 return false;
489 }
490
Charles Chan0b4e6182015-11-03 10:42:14 -0800491 } else if (targetIsEdge) {
Saurav Das8a0732e2015-11-20 15:27:53 -0800492 // If the target switch is an edge router, then set IP rules for the router IP.
Charles Chan0b4e6182015-11-03 10:42:14 -0800493 Ip4Address routerIp = destRouterIp;
sangho666cd6d2015-04-14 16:27:13 -0700494 IpPrefix routerIpPrefix = IpPrefix.valueOf(routerIp, IpPrefix.MAX_INET_MASK_LENGTH);
Saurav Dasa07f2032015-10-19 14:37:36 -0700495 log.debug("* populateEcmpRoutingRulePartial in device {} towards {} for router IP {}",
Saurav Das8a0732e2015-11-20 15:27:53 -0800496 targetSw, destSw, routerIpPrefix);
sangho666cd6d2015-04-14 16:27:13 -0700497 result = rulePopulator.populateIpRuleForRouter(targetSw, routerIpPrefix, destSw, nextHops);
sanghob35a6192015-04-01 13:05:26 -0700498 if (!result) {
499 return false;
500 }
sangho52abe3a2015-05-05 14:13:34 -0700501 }
sangho52abe3a2015-05-05 14:13:34 -0700502 // Populates MPLS rules to all routers
Saurav Dasa07f2032015-10-19 14:37:36 -0700503 log.debug("* populateEcmpRoutingRulePartial in device{} towards {} for all MPLS rules",
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700504 targetSw, destSw);
sangho52abe3a2015-05-05 14:13:34 -0700505 result = rulePopulator.populateMplsRule(targetSw, destSw, nextHops);
506 if (!result) {
507 return false;
sanghob35a6192015-04-01 13:05:26 -0700508 }
sanghob35a6192015-04-01 13:05:26 -0700509 return true;
510 }
511
512 /**
Saurav Das822c4e22015-10-23 10:51:11 -0700513 * Populates filtering rules for permitting Router DstMac and VLAN.
sanghob35a6192015-04-01 13:05:26 -0700514 *
515 * @param deviceId Switch ID to set the rules
516 */
Saurav Das822c4e22015-10-23 10:51:11 -0700517 public void populatePortAddressingRules(DeviceId deviceId) {
518 rulePopulator.populateRouterMacVlanFilters(deviceId);
Charles Chane849c192016-01-11 18:28:54 -0800519 rulePopulator.populateXConnectVlanFilters(deviceId);
Saurav Das822c4e22015-10-23 10:51:11 -0700520 rulePopulator.populateRouterIpPunts(deviceId);
sanghob35a6192015-04-01 13:05:26 -0700521 }
522
523 /**
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700524 * Start the flow rule population process if it was never started. The
525 * process finishes successfully when all flow rules are set and stops with
526 * ABORTED status when any groups required for flows is not set yet.
sanghob35a6192015-04-01 13:05:26 -0700527 */
528 public void startPopulationProcess() {
HIGUCHI Yuta84a25fc2015-09-08 16:16:31 +0900529 statusLock.lock();
530 try {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700531 if (populationStatus == Status.IDLE
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700532 || populationStatus == Status.SUCCEEDED
533 || populationStatus == Status.ABORTED) {
sanghob35a6192015-04-01 13:05:26 -0700534 populationStatus = Status.STARTED;
535 populateAllRoutingRules();
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700536 } else {
537 log.warn("Not initiating startPopulationProcess as populationStatus is {}",
538 populationStatus);
sanghob35a6192015-04-01 13:05:26 -0700539 }
HIGUCHI Yuta84a25fc2015-09-08 16:16:31 +0900540 } finally {
541 statusLock.unlock();
sanghob35a6192015-04-01 13:05:26 -0700542 }
543 }
544
545 /**
546 * Resume the flow rule population process if it was aborted for any reason.
547 * Mostly the process is aborted when the groups required are not set yet.
Saurav Dasa07f2032015-10-19 14:37:36 -0700548 * XXX is this called?
549 *
sanghob35a6192015-04-01 13:05:26 -0700550 */
551 public void resumePopulationProcess() {
HIGUCHI Yuta84a25fc2015-09-08 16:16:31 +0900552 statusLock.lock();
553 try {
sanghob35a6192015-04-01 13:05:26 -0700554 if (populationStatus == Status.ABORTED) {
555 populationStatus = Status.STARTED;
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700556 // TODO: we need to restart from the point aborted instead of
557 // restarting.
sanghob35a6192015-04-01 13:05:26 -0700558 populateAllRoutingRules();
559 }
HIGUCHI Yuta84a25fc2015-09-08 16:16:31 +0900560 } finally {
561 statusLock.unlock();
sanghob35a6192015-04-01 13:05:26 -0700562 }
563 }
Saurav Das80980c72016-03-23 11:22:49 -0700564
565 public void purgeEcmpGraph(DeviceId deviceId) {
566 currentEcmpSpgMap.remove(deviceId);
Saurav Das7a1ffca2016-03-28 19:00:18 -0700567 if (updatedEcmpSpgMap != null) {
568 updatedEcmpSpgMap.remove(deviceId);
569 }
Saurav Das80980c72016-03-23 11:22:49 -0700570 }
sanghob35a6192015-04-01 13:05:26 -0700571}