blob: e645165378364461af56bf3219e2361352efbf8b [file] [log] [blame]
sangho80f11cb2015-04-01 13:05:26 -07001/*
2 * Copyright 2015 Open Networking Laboratory
3 *
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
sanghofb7c7292015-04-13 15:15:58 -070018import com.google.common.collect.Maps;
19import com.google.common.collect.Sets;
sangho9b169e32015-04-14 16:27:13 -070020import org.onlab.packet.Ip4Address;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070021import org.onlab.packet.Ip4Prefix;
sangho80f11cb2015-04-01 13:05:26 -070022import org.onlab.packet.IpPrefix;
23import org.onosproject.net.Device;
24import org.onosproject.net.DeviceId;
sanghofb7c7292015-04-13 15:15:58 -070025import org.onosproject.net.Link;
Charles Chan319d1a22015-11-03 10:42:14 -080026import org.onosproject.segmentrouting.config.DeviceConfigNotFoundException;
27import org.onosproject.segmentrouting.config.DeviceConfiguration;
sangho80f11cb2015-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 Yuta16d8fd52015-09-08 16:16:31 +090035import java.util.concurrent.locks.Lock;
36import java.util.concurrent.locks.ReentrantLock;
sangho80f11cb2015-04-01 13:05:26 -070037
38import static com.google.common.base.Preconditions.checkNotNull;
39
40public class DefaultRoutingHandler {
41
Srikanth Vavilapalli64505482015-04-21 13:04:13 -070042 private static Logger log = LoggerFactory
43 .getLogger(DefaultRoutingHandler.class);
sangho80f11cb2015-04-01 13:05:26 -070044
45 private SegmentRoutingManager srManager;
46 private RoutingRulePopulator rulePopulator;
sanghofb7c7292015-04-13 15:15:58 -070047 private HashMap<DeviceId, ECMPShortestPathGraph> currentEcmpSpgMap;
sangho28d0b6d2015-05-07 13:30:57 -070048 private HashMap<DeviceId, ECMPShortestPathGraph> updatedEcmpSpgMap;
sangho9b169e32015-04-14 16:27:13 -070049 private DeviceConfiguration config;
HIGUCHI Yuta16d8fd52015-09-08 16:16:31 +090050 private final Lock statusLock = new ReentrantLock();
51 private volatile Status populationStatus;
sangho80f11cb2015-04-01 13:05:26 -070052
53 /**
54 * Represents the default routing population status.
55 */
56 public enum Status {
57 // population process is not started yet.
58 IDLE,
59
60 // population process started.
61 STARTED,
62
Srikanth Vavilapalli64505482015-04-21 13:04:13 -070063 // population process was aborted due to errors, mostly for groups not
64 // found.
sangho80f11cb2015-04-01 13:05:26 -070065 ABORTED,
66
67 // population process was finished successfully.
68 SUCCEEDED
69 }
70
71 /**
72 * Creates a DefaultRoutingHandler object.
73 *
74 * @param srManager SegmentRoutingManager object
75 */
76 public DefaultRoutingHandler(SegmentRoutingManager srManager) {
77 this.srManager = srManager;
78 this.rulePopulator = checkNotNull(srManager.routingRulePopulator);
sangho9b169e32015-04-14 16:27:13 -070079 this.config = checkNotNull(srManager.deviceConfiguration);
sangho80f11cb2015-04-01 13:05:26 -070080 this.populationStatus = Status.IDLE;
sanghofb7c7292015-04-13 15:15:58 -070081 this.currentEcmpSpgMap = Maps.newHashMap();
sangho80f11cb2015-04-01 13:05:26 -070082 }
83
84 /**
85 * Populates all routing rules to all connected routers, including default
86 * routing rules, adjacency rules, and policy rules if any.
87 *
88 * @return true if it succeeds in populating all rules, otherwise false
89 */
90 public boolean populateAllRoutingRules() {
91
HIGUCHI Yuta16d8fd52015-09-08 16:16:31 +090092 statusLock.lock();
93 try {
94 populationStatus = Status.STARTED;
95 rulePopulator.resetCounter();
Saurav Das88979182015-10-19 14:37:36 -070096 log.info("Starting to populate segment-routing rules");
HIGUCHI Yuta16d8fd52015-09-08 16:16:31 +090097 log.debug("populateAllRoutingRules: populationStatus is STARTED");
sangho80f11cb2015-04-01 13:05:26 -070098
HIGUCHI Yuta16d8fd52015-09-08 16:16:31 +090099 for (Device sw : srManager.deviceService.getDevices()) {
Charles Chan77277672015-10-20 16:24:19 -0700100 if (!srManager.mastershipService.isLocalMaster(sw.id())) {
HIGUCHI Yuta16d8fd52015-09-08 16:16:31 +0900101 log.debug("populateAllRoutingRules: skipping device {}...we are not master",
102 sw.id());
103 continue;
104 }
105
106 ECMPShortestPathGraph ecmpSpg = new ECMPShortestPathGraph(sw.id(), srManager);
107 if (!populateEcmpRoutingRules(sw.id(), ecmpSpg)) {
108 log.debug("populateAllRoutingRules: populationStatus is ABORTED");
109 populationStatus = Status.ABORTED;
110 log.debug("Abort routing rule population");
111 return false;
112 }
113 currentEcmpSpgMap.put(sw.id(), ecmpSpg);
114
115 // TODO: Set adjacency routing rule for all switches
sangho80f11cb2015-04-01 13:05:26 -0700116 }
117
HIGUCHI Yuta16d8fd52015-09-08 16:16:31 +0900118 log.debug("populateAllRoutingRules: populationStatus is SUCCEEDED");
119 populationStatus = Status.SUCCEEDED;
Saurav Das88979182015-10-19 14:37:36 -0700120 log.info("Completed routing rule population. Total # of rules pushed : {}",
HIGUCHI Yuta16d8fd52015-09-08 16:16:31 +0900121 rulePopulator.getCounter());
122 return true;
123 } finally {
124 statusLock.unlock();
sangho80f11cb2015-04-01 13:05:26 -0700125 }
sangho80f11cb2015-04-01 13:05:26 -0700126 }
127
sanghofb7c7292015-04-13 15:15:58 -0700128 /**
129 * Populates the routing rules according to the route changes due to the link
130 * failure or link add. It computes the routes changed due to the link changes and
131 * repopulates the rules only for the routes.
132 *
133 * @param linkFail link failed, null for link added
134 * @return true if it succeeds to populate all rules, false otherwise
135 */
136 public boolean populateRoutingRulesForLinkStatusChange(Link linkFail) {
137
HIGUCHI Yuta16d8fd52015-09-08 16:16:31 +0900138 statusLock.lock();
139 try {
sanghofb7c7292015-04-13 15:15:58 -0700140
141 if (populationStatus == Status.STARTED) {
sanghodf0153f2015-05-05 14:13:34 -0700142 log.warn("Previous rule population is not finished.");
sanghofb7c7292015-04-13 15:15:58 -0700143 return true;
144 }
145
sangho28d0b6d2015-05-07 13:30:57 -0700146 // Take the snapshots of the links
147 updatedEcmpSpgMap = new HashMap<>();
148 for (Device sw : srManager.deviceService.getDevices()) {
Charles Chan77277672015-10-20 16:24:19 -0700149 if (!srManager.mastershipService.isLocalMaster(sw.id())) {
sangho28d0b6d2015-05-07 13:30:57 -0700150 continue;
151 }
152 ECMPShortestPathGraph ecmpSpgUpdated =
153 new ECMPShortestPathGraph(sw.id(), srManager);
154 updatedEcmpSpgMap.put(sw.id(), ecmpSpgUpdated);
155 }
156
sanghodf0153f2015-05-05 14:13:34 -0700157 log.info("Starts rule population from link change");
158
sanghofb7c7292015-04-13 15:15:58 -0700159 Set<ArrayList<DeviceId>> routeChanges;
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700160 log.trace("populateRoutingRulesForLinkStatusChange: "
161 + "populationStatus is STARTED");
sanghofb7c7292015-04-13 15:15:58 -0700162 populationStatus = Status.STARTED;
163 if (linkFail == null) {
164 // Compare all routes of existing ECMP SPG with the new ones
165 routeChanges = computeRouteChange();
166 } else {
167 // Compare existing ECMP SPG only with the link removed
168 routeChanges = computeDamagedRoutes(linkFail);
169 }
170
171 if (routeChanges.isEmpty()) {
sanghodf0153f2015-05-05 14:13:34 -0700172 log.info("No route changes for the link status change");
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700173 log.debug("populateRoutingRulesForLinkStatusChange: populationStatus is SUCCEEDED");
sanghofb7c7292015-04-13 15:15:58 -0700174 populationStatus = Status.SUCCEEDED;
175 return true;
176 }
177
178 if (repopulateRoutingRulesForRoutes(routeChanges)) {
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700179 log.debug("populateRoutingRulesForLinkStatusChange: populationStatus is SUCCEEDED");
sanghofb7c7292015-04-13 15:15:58 -0700180 populationStatus = Status.SUCCEEDED;
181 log.info("Complete to repopulate the rules. # of rules populated : {}",
182 rulePopulator.getCounter());
183 return true;
184 } else {
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700185 log.debug("populateRoutingRulesForLinkStatusChange: populationStatus is ABORTED");
sanghofb7c7292015-04-13 15:15:58 -0700186 populationStatus = Status.ABORTED;
187 log.warn("Failed to repopulate the rules.");
188 return false;
189 }
HIGUCHI Yuta16d8fd52015-09-08 16:16:31 +0900190 } finally {
191 statusLock.unlock();
sanghofb7c7292015-04-13 15:15:58 -0700192 }
193 }
194
195 private boolean repopulateRoutingRulesForRoutes(Set<ArrayList<DeviceId>> routes) {
196 rulePopulator.resetCounter();
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700197 HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>> routesBydevice =
198 new HashMap<>();
sanghofb7c7292015-04-13 15:15:58 -0700199 for (ArrayList<DeviceId> link: routes) {
sangho2165d222015-05-01 09:38:25 -0700200 // When only the source device is defined, reinstall routes to all other devices
sanghofb7c7292015-04-13 15:15:58 -0700201 if (link.size() == 1) {
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700202 log.trace("repopulateRoutingRulesForRoutes: running ECMP graph for device {}", link.get(0));
sanghofb7c7292015-04-13 15:15:58 -0700203 ECMPShortestPathGraph ecmpSpg = new ECMPShortestPathGraph(link.get(0), srManager);
204 if (populateEcmpRoutingRules(link.get(0), ecmpSpg)) {
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700205 log.debug("Populating flow rules from {} to all is successful",
206 link.get(0));
sanghofb7c7292015-04-13 15:15:58 -0700207 currentEcmpSpgMap.put(link.get(0), ecmpSpg);
sanghodf0153f2015-05-05 14:13:34 -0700208 } else {
sangho28d0b6d2015-05-07 13:30:57 -0700209 log.warn("Failed to populate the flow rules from {} to all", link.get(0));
sanghodf0153f2015-05-05 14:13:34 -0700210 return false;
sanghofb7c7292015-04-13 15:15:58 -0700211 }
sangho28d0b6d2015-05-07 13:30:57 -0700212 } else {
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700213 ArrayList<ArrayList<DeviceId>> deviceRoutes =
214 routesBydevice.get(link.get(1));
215 if (deviceRoutes == null) {
216 deviceRoutes = new ArrayList<>();
217 routesBydevice.put(link.get(1), deviceRoutes);
218 }
219 deviceRoutes.add(link);
220 }
221 }
222
223 for (DeviceId impactedDevice : routesBydevice.keySet()) {
224 ArrayList<ArrayList<DeviceId>> deviceRoutes =
225 routesBydevice.get(impactedDevice);
226 for (ArrayList<DeviceId> link: deviceRoutes) {
227 log.debug("repopulate RoutingRules For Routes {} -> {}",
228 link.get(0), link.get(1));
sangho28d0b6d2015-05-07 13:30:57 -0700229 DeviceId src = link.get(0);
230 DeviceId dst = link.get(1);
sangho28d0b6d2015-05-07 13:30:57 -0700231 ECMPShortestPathGraph ecmpSpg = updatedEcmpSpgMap.get(dst);
232 HashMap<Integer, HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>>> switchVia =
233 ecmpSpg.getAllLearnedSwitchesAndVia();
234 for (Integer itrIdx : switchVia.keySet()) {
235 HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>> swViaMap =
236 switchVia.get(itrIdx);
237 for (DeviceId targetSw : swViaMap.keySet()) {
238 if (!targetSw.equals(src)) {
239 continue;
240 }
241 Set<DeviceId> nextHops = new HashSet<>();
242 for (ArrayList<DeviceId> via : swViaMap.get(targetSw)) {
243 if (via.isEmpty()) {
244 nextHops.add(dst);
245 } else {
246 nextHops.add(via.get(0));
247 }
248 }
249 if (!populateEcmpRoutingRulePartial(targetSw, dst, nextHops)) {
250 return false;
sanghofb7c7292015-04-13 15:15:58 -0700251 }
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700252 log.debug("Populating flow rules from {} to {} is successful",
253 targetSw, dst);
sanghofb7c7292015-04-13 15:15:58 -0700254 }
sanghofb7c7292015-04-13 15:15:58 -0700255 }
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700256 //currentEcmpSpgMap.put(dst, ecmpSpg);
sanghofb7c7292015-04-13 15:15:58 -0700257 }
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700258 //Only if all the flows for all impacted routes to a
259 //specific target are pushed successfully, update the
260 //ECMP graph for that target. (Or else the next event
261 //would not see any changes in the ECMP graphs)
262 currentEcmpSpgMap.put(impactedDevice,
263 updatedEcmpSpgMap.get(impactedDevice));
sanghofb7c7292015-04-13 15:15:58 -0700264 }
265 return true;
266 }
267
268 private Set<ArrayList<DeviceId>> computeDamagedRoutes(Link linkFail) {
269
270 Set<ArrayList<DeviceId>> routes = new HashSet<>();
271
272 for (Device sw : srManager.deviceService.getDevices()) {
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700273 log.debug("Computing the impacted routes for device {} due to link fail",
274 sw.id());
Charles Chan77277672015-10-20 16:24:19 -0700275 if (!srManager.mastershipService.isLocalMaster(sw.id())) {
sanghofb7c7292015-04-13 15:15:58 -0700276 continue;
277 }
278 ECMPShortestPathGraph ecmpSpg = currentEcmpSpgMap.get(sw.id());
279 if (ecmpSpg == null) {
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700280 log.error("No existing ECMP graph for switch {}", sw.id());
sanghofb7c7292015-04-13 15:15:58 -0700281 continue;
282 }
283 HashMap<Integer, HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>>> switchVia =
284 ecmpSpg.getAllLearnedSwitchesAndVia();
285 for (Integer itrIdx : switchVia.keySet()) {
286 HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>> swViaMap =
287 switchVia.get(itrIdx);
288 for (DeviceId targetSw : swViaMap.keySet()) {
289 DeviceId destSw = sw.id();
290 Set<ArrayList<DeviceId>> subLinks =
291 computeLinks(targetSw, destSw, swViaMap);
292 for (ArrayList<DeviceId> alink: subLinks) {
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700293 if ((alink.get(0).equals(linkFail.src().deviceId()) &&
294 alink.get(1).equals(linkFail.dst().deviceId()))
295 ||
296 (alink.get(0).equals(linkFail.dst().deviceId()) &&
297 alink.get(1).equals(linkFail.src().deviceId()))) {
298 log.debug("Impacted route:{}->{}", targetSw, destSw);
sanghofb7c7292015-04-13 15:15:58 -0700299 ArrayList<DeviceId> aRoute = new ArrayList<>();
300 aRoute.add(targetSw);
301 aRoute.add(destSw);
302 routes.add(aRoute);
303 break;
304 }
305 }
306 }
307 }
sangho28d0b6d2015-05-07 13:30:57 -0700308
sanghofb7c7292015-04-13 15:15:58 -0700309 }
310
311 return routes;
312 }
313
314 private Set<ArrayList<DeviceId>> computeRouteChange() {
315
316 Set<ArrayList<DeviceId>> routes = new HashSet<>();
317
318 for (Device sw : srManager.deviceService.getDevices()) {
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700319 log.debug("Computing the impacted routes for device {}",
320 sw.id());
Charles Chan77277672015-10-20 16:24:19 -0700321 if (!srManager.mastershipService.isLocalMaster(sw.id())) {
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700322 log.debug("No mastership for {} and skip route optimization",
323 sw.id());
sanghofb7c7292015-04-13 15:15:58 -0700324 continue;
325 }
sangho28d0b6d2015-05-07 13:30:57 -0700326
327 log.trace("link of {} - ", sw.id());
328 for (Link link: srManager.linkService.getDeviceLinks(sw.id())) {
329 log.trace("{} -> {} ", link.src().deviceId(), link.dst().deviceId());
330 }
331
332 log.debug("Checking route change for switch {}", sw.id());
sanghofb7c7292015-04-13 15:15:58 -0700333 ECMPShortestPathGraph ecmpSpg = currentEcmpSpgMap.get(sw.id());
334 if (ecmpSpg == null) {
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700335 log.debug("No existing ECMP graph for device {}", sw.id());
sanghofb7c7292015-04-13 15:15:58 -0700336 ArrayList<DeviceId> route = new ArrayList<>();
337 route.add(sw.id());
338 routes.add(route);
339 continue;
340 }
sangho28d0b6d2015-05-07 13:30:57 -0700341 ECMPShortestPathGraph newEcmpSpg = updatedEcmpSpgMap.get(sw.id());
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700342 //currentEcmpSpgMap.put(sw.id(), newEcmpSpg);
sanghofb7c7292015-04-13 15:15:58 -0700343 HashMap<Integer, HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>>> switchVia =
344 ecmpSpg.getAllLearnedSwitchesAndVia();
345 HashMap<Integer, HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>>> switchViaUpdated =
346 newEcmpSpg.getAllLearnedSwitchesAndVia();
347
sangho28d0b6d2015-05-07 13:30:57 -0700348 for (Integer itrIdx : switchViaUpdated.keySet()) {
349 HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>> swViaMapUpdated =
350 switchViaUpdated.get(itrIdx);
351 for (DeviceId srcSw : swViaMapUpdated.keySet()) {
352 ArrayList<ArrayList<DeviceId>> viaUpdated = swViaMapUpdated.get(srcSw);
353 ArrayList<ArrayList<DeviceId>> via = getVia(switchVia, srcSw);
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700354 if ((via == null) || !viaUpdated.equals(via)) {
355 log.debug("Impacted route:{}->{}", srcSw, sw.id());
sanghofb7c7292015-04-13 15:15:58 -0700356 ArrayList<DeviceId> route = new ArrayList<>();
357 route.add(srcSw);
358 route.add(sw.id());
359 routes.add(route);
360 }
361 }
362 }
sangho28d0b6d2015-05-07 13:30:57 -0700363 }
sanghofb7c7292015-04-13 15:15:58 -0700364
sangho28d0b6d2015-05-07 13:30:57 -0700365 for (ArrayList<DeviceId> link: routes) {
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700366 log.trace("Route changes - ");
sangho28d0b6d2015-05-07 13:30:57 -0700367 if (link.size() == 1) {
368 log.trace(" : {} - all", link.get(0));
369 } else {
370 log.trace(" : {} - {}", link.get(0), link.get(1));
371 }
sanghofb7c7292015-04-13 15:15:58 -0700372 }
373
374 return routes;
375 }
376
377 private ArrayList<ArrayList<DeviceId>> getVia(HashMap<Integer, HashMap<DeviceId,
378 ArrayList<ArrayList<DeviceId>>>> switchVia, DeviceId srcSw) {
379 for (Integer itrIdx : switchVia.keySet()) {
380 HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>> swViaMap =
381 switchVia.get(itrIdx);
382 if (swViaMap.get(srcSw) == null) {
383 continue;
384 } else {
385 return swViaMap.get(srcSw);
386 }
387 }
388
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700389 return null;
sanghofb7c7292015-04-13 15:15:58 -0700390 }
391
392 private Set<ArrayList<DeviceId>> computeLinks(DeviceId src,
393 DeviceId dst,
394 HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>> viaMap) {
395 Set<ArrayList<DeviceId>> subLinks = Sets.newHashSet();
396 for (ArrayList<DeviceId> via : viaMap.get(src)) {
397 DeviceId linkSrc = src;
398 DeviceId linkDst = dst;
399 for (DeviceId viaDevice: via) {
400 ArrayList<DeviceId> link = new ArrayList<>();
401 linkDst = viaDevice;
402 link.add(linkSrc);
403 link.add(linkDst);
404 subLinks.add(link);
405 linkSrc = viaDevice;
406 }
407 ArrayList<DeviceId> link = new ArrayList<>();
408 link.add(linkSrc);
409 link.add(dst);
410 subLinks.add(link);
411 }
412
413 return subLinks;
414 }
415
416 private boolean populateEcmpRoutingRules(DeviceId destSw,
sangho80f11cb2015-04-01 13:05:26 -0700417 ECMPShortestPathGraph ecmpSPG) {
418
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700419 HashMap<Integer, HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>>> switchVia = ecmpSPG
420 .getAllLearnedSwitchesAndVia();
sangho80f11cb2015-04-01 13:05:26 -0700421 for (Integer itrIdx : switchVia.keySet()) {
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700422 HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>> swViaMap = switchVia
423 .get(itrIdx);
sangho80f11cb2015-04-01 13:05:26 -0700424 for (DeviceId targetSw : swViaMap.keySet()) {
sangho80f11cb2015-04-01 13:05:26 -0700425 Set<DeviceId> nextHops = new HashSet<>();
Saurav Das88979182015-10-19 14:37:36 -0700426 log.debug("** Iter: {} root: {} target: {}", itrIdx, destSw, targetSw);
sangho80f11cb2015-04-01 13:05:26 -0700427 for (ArrayList<DeviceId> via : swViaMap.get(targetSw)) {
428 if (via.isEmpty()) {
429 nextHops.add(destSw);
430 } else {
431 nextHops.add(via.get(0));
432 }
433 }
434 if (!populateEcmpRoutingRulePartial(targetSw, destSw, nextHops)) {
435 return false;
436 }
437 }
438 }
439
440 return true;
441 }
442
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700443 private boolean populateEcmpRoutingRulePartial(DeviceId targetSw,
444 DeviceId destSw,
445 Set<DeviceId> nextHops) {
sangho80f11cb2015-04-01 13:05:26 -0700446 boolean result;
447
448 if (nextHops.isEmpty()) {
449 nextHops.add(destSw);
450 }
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700451 // If both target switch and dest switch are edge routers, then set IP
sanghodf0153f2015-05-05 14:13:34 -0700452 // rule for both subnet and router IP.
Charles Chan319d1a22015-11-03 10:42:14 -0800453 boolean targetIsEdge;
454 boolean destIsEdge;
455 Ip4Address destRouterIp;
456
457 try {
458 targetIsEdge = config.isEdgeDevice(targetSw);
459 destIsEdge = config.isEdgeDevice(destSw);
460 destRouterIp = config.getRouterIp(destSw);
461 } catch (DeviceConfigNotFoundException e) {
462 log.warn(e.getMessage() + " Aborting populateEcmpRoutingRulePartial.");
463 return false;
464 }
465
466 if (targetIsEdge && destIsEdge) {
Charles Chanc6ad7752015-10-29 14:58:10 -0700467 Set<Ip4Prefix> subnets = config.getSubnets(destSw);
Saurav Das88979182015-10-19 14:37:36 -0700468 log.debug("* populateEcmpRoutingRulePartial in device {} towards {} for subnets {}",
Saurav Das4c35fc42015-11-20 15:27:53 -0800469 targetSw, destSw, subnets);
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700470 result = rulePopulator.populateIpRuleForSubnet(targetSw,
471 subnets,
472 destSw,
473 nextHops);
sangho80f11cb2015-04-01 13:05:26 -0700474 if (!result) {
475 return false;
476 }
477
Charles Chan319d1a22015-11-03 10:42:14 -0800478 Ip4Address routerIp = destRouterIp;
sangho9b169e32015-04-14 16:27:13 -0700479 IpPrefix routerIpPrefix = IpPrefix.valueOf(routerIp, IpPrefix.MAX_INET_MASK_LENGTH);
Saurav Das88979182015-10-19 14:37:36 -0700480 log.debug("* populateEcmpRoutingRulePartial in device {} towards {} for router IP {}",
Saurav Das4c35fc42015-11-20 15:27:53 -0800481 targetSw, destSw, routerIpPrefix);
sangho9b169e32015-04-14 16:27:13 -0700482 result = rulePopulator.populateIpRuleForRouter(targetSw, routerIpPrefix, destSw, nextHops);
sangho80f11cb2015-04-01 13:05:26 -0700483 if (!result) {
484 return false;
485 }
486
Charles Chan319d1a22015-11-03 10:42:14 -0800487 } else if (targetIsEdge) {
Saurav Das4c35fc42015-11-20 15:27:53 -0800488 // If the target switch is an edge router, then set IP rules for the router IP.
Charles Chan319d1a22015-11-03 10:42:14 -0800489 Ip4Address routerIp = destRouterIp;
sangho9b169e32015-04-14 16:27:13 -0700490 IpPrefix routerIpPrefix = IpPrefix.valueOf(routerIp, IpPrefix.MAX_INET_MASK_LENGTH);
Saurav Das88979182015-10-19 14:37:36 -0700491 log.debug("* populateEcmpRoutingRulePartial in device {} towards {} for router IP {}",
Saurav Das4c35fc42015-11-20 15:27:53 -0800492 targetSw, destSw, routerIpPrefix);
sangho9b169e32015-04-14 16:27:13 -0700493 result = rulePopulator.populateIpRuleForRouter(targetSw, routerIpPrefix, destSw, nextHops);
sangho80f11cb2015-04-01 13:05:26 -0700494 if (!result) {
495 return false;
496 }
sanghodf0153f2015-05-05 14:13:34 -0700497 }
sanghodf0153f2015-05-05 14:13:34 -0700498 // Populates MPLS rules to all routers
Saurav Das88979182015-10-19 14:37:36 -0700499 log.debug("* populateEcmpRoutingRulePartial in device{} towards {} for all MPLS rules",
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700500 targetSw, destSw);
sanghodf0153f2015-05-05 14:13:34 -0700501 result = rulePopulator.populateMplsRule(targetSw, destSw, nextHops);
502 if (!result) {
503 return false;
sangho80f11cb2015-04-01 13:05:26 -0700504 }
sangho80f11cb2015-04-01 13:05:26 -0700505 return true;
506 }
507
508 /**
Saurav Das9f1c42e2015-10-23 10:51:11 -0700509 * Populates filtering rules for permitting Router DstMac and VLAN.
sangho80f11cb2015-04-01 13:05:26 -0700510 *
511 * @param deviceId Switch ID to set the rules
512 */
Saurav Das9f1c42e2015-10-23 10:51:11 -0700513 public void populatePortAddressingRules(DeviceId deviceId) {
514 rulePopulator.populateRouterMacVlanFilters(deviceId);
515 rulePopulator.populateRouterIpPunts(deviceId);
Charles Chand4a99c52015-11-18 16:51:08 -0800516 rulePopulator.populateArpPunts(deviceId);
sangho80f11cb2015-04-01 13:05:26 -0700517 }
518
519 /**
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700520 * Start the flow rule population process if it was never started. The
521 * process finishes successfully when all flow rules are set and stops with
522 * ABORTED status when any groups required for flows is not set yet.
sangho80f11cb2015-04-01 13:05:26 -0700523 */
524 public void startPopulationProcess() {
HIGUCHI Yuta16d8fd52015-09-08 16:16:31 +0900525 statusLock.lock();
526 try {
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700527 if (populationStatus == Status.IDLE
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700528 || populationStatus == Status.SUCCEEDED
529 || populationStatus == Status.ABORTED) {
sangho80f11cb2015-04-01 13:05:26 -0700530 populationStatus = Status.STARTED;
531 populateAllRoutingRules();
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700532 } else {
533 log.warn("Not initiating startPopulationProcess as populationStatus is {}",
534 populationStatus);
sangho80f11cb2015-04-01 13:05:26 -0700535 }
HIGUCHI Yuta16d8fd52015-09-08 16:16:31 +0900536 } finally {
537 statusLock.unlock();
sangho80f11cb2015-04-01 13:05:26 -0700538 }
539 }
540
541 /**
542 * Resume the flow rule population process if it was aborted for any reason.
543 * Mostly the process is aborted when the groups required are not set yet.
Saurav Das88979182015-10-19 14:37:36 -0700544 * XXX is this called?
545 *
sangho80f11cb2015-04-01 13:05:26 -0700546 */
547 public void resumePopulationProcess() {
HIGUCHI Yuta16d8fd52015-09-08 16:16:31 +0900548 statusLock.lock();
549 try {
sangho80f11cb2015-04-01 13:05:26 -0700550 if (populationStatus == Status.ABORTED) {
551 populationStatus = Status.STARTED;
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700552 // TODO: we need to restart from the point aborted instead of
553 // restarting.
sangho80f11cb2015-04-01 13:05:26 -0700554 populateAllRoutingRules();
555 }
HIGUCHI Yuta16d8fd52015-09-08 16:16:31 +0900556 } finally {
557 statusLock.unlock();
sangho80f11cb2015-04-01 13:05:26 -0700558 }
559 }
560}