blob: 895c446c82386aee6acfd4cddea7846628294299 [file] [log] [blame]
sanghob35a6192015-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
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;
sanghob35a6192015-04-01 13:05:26 -070026import org.slf4j.Logger;
27import org.slf4j.LoggerFactory;
28
29import java.util.ArrayList;
30import java.util.HashMap;
31import java.util.HashSet;
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -070032import java.util.List;
sanghob35a6192015-04-01 13:05:26 -070033import java.util.Set;
HIGUCHI Yuta84a25fc2015-09-08 16:16:31 +090034import java.util.concurrent.locks.Lock;
35import java.util.concurrent.locks.ReentrantLock;
sanghob35a6192015-04-01 13:05:26 -070036
37import static com.google.common.base.Preconditions.checkNotNull;
38
39public class DefaultRoutingHandler {
40
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070041 private static Logger log = LoggerFactory
42 .getLogger(DefaultRoutingHandler.class);
sanghob35a6192015-04-01 13:05:26 -070043
44 private SegmentRoutingManager srManager;
45 private RoutingRulePopulator rulePopulator;
sangho20eff1d2015-04-13 15:15:58 -070046 private HashMap<DeviceId, ECMPShortestPathGraph> currentEcmpSpgMap;
sangho45b009c2015-05-07 13:30:57 -070047 private HashMap<DeviceId, ECMPShortestPathGraph> updatedEcmpSpgMap;
sangho666cd6d2015-04-14 16:27:13 -070048 private DeviceConfiguration config;
HIGUCHI Yuta84a25fc2015-09-08 16:16:31 +090049 private final Lock statusLock = new ReentrantLock();
50 private volatile Status populationStatus;
sanghob35a6192015-04-01 13:05:26 -070051
52 /**
53 * Represents the default routing population status.
54 */
55 public enum Status {
56 // population process is not started yet.
57 IDLE,
58
59 // population process started.
60 STARTED,
61
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070062 // population process was aborted due to errors, mostly for groups not
63 // found.
sanghob35a6192015-04-01 13:05:26 -070064 ABORTED,
65
66 // population process was finished successfully.
67 SUCCEEDED
68 }
69
70 /**
71 * Creates a DefaultRoutingHandler object.
72 *
73 * @param srManager SegmentRoutingManager object
74 */
75 public DefaultRoutingHandler(SegmentRoutingManager srManager) {
76 this.srManager = srManager;
77 this.rulePopulator = checkNotNull(srManager.routingRulePopulator);
sangho666cd6d2015-04-14 16:27:13 -070078 this.config = checkNotNull(srManager.deviceConfiguration);
sanghob35a6192015-04-01 13:05:26 -070079 this.populationStatus = Status.IDLE;
sangho20eff1d2015-04-13 15:15:58 -070080 this.currentEcmpSpgMap = Maps.newHashMap();
sanghob35a6192015-04-01 13:05:26 -070081 }
82
83 /**
84 * Populates all routing rules to all connected routers, including default
85 * routing rules, adjacency rules, and policy rules if any.
86 *
87 * @return true if it succeeds in populating all rules, otherwise false
88 */
89 public boolean populateAllRoutingRules() {
90
HIGUCHI Yuta84a25fc2015-09-08 16:16:31 +090091 statusLock.lock();
92 try {
93 populationStatus = Status.STARTED;
94 rulePopulator.resetCounter();
Saurav Dasa07f2032015-10-19 14:37:36 -070095 log.info("Starting to populate segment-routing rules");
HIGUCHI Yuta84a25fc2015-09-08 16:16:31 +090096 log.debug("populateAllRoutingRules: populationStatus is STARTED");
sanghob35a6192015-04-01 13:05:26 -070097
HIGUCHI Yuta84a25fc2015-09-08 16:16:31 +090098 for (Device sw : srManager.deviceService.getDevices()) {
Charles Chanc42e84e2015-10-20 16:24:19 -070099 if (!srManager.mastershipService.isLocalMaster(sw.id())) {
HIGUCHI Yuta84a25fc2015-09-08 16:16:31 +0900100 log.debug("populateAllRoutingRules: skipping device {}...we are not master",
101 sw.id());
102 continue;
103 }
104
105 ECMPShortestPathGraph ecmpSpg = new ECMPShortestPathGraph(sw.id(), srManager);
106 if (!populateEcmpRoutingRules(sw.id(), ecmpSpg)) {
107 log.debug("populateAllRoutingRules: populationStatus is ABORTED");
108 populationStatus = Status.ABORTED;
109 log.debug("Abort routing rule population");
110 return false;
111 }
112 currentEcmpSpgMap.put(sw.id(), ecmpSpg);
113
114 // TODO: Set adjacency routing rule for all switches
sanghob35a6192015-04-01 13:05:26 -0700115 }
116
HIGUCHI Yuta84a25fc2015-09-08 16:16:31 +0900117 log.debug("populateAllRoutingRules: populationStatus is SUCCEEDED");
118 populationStatus = Status.SUCCEEDED;
Saurav Dasa07f2032015-10-19 14:37:36 -0700119 log.info("Completed routing rule population. Total # of rules pushed : {}",
HIGUCHI Yuta84a25fc2015-09-08 16:16:31 +0900120 rulePopulator.getCounter());
121 return true;
122 } finally {
123 statusLock.unlock();
sanghob35a6192015-04-01 13:05:26 -0700124 }
sanghob35a6192015-04-01 13:05:26 -0700125 }
126
sangho20eff1d2015-04-13 15:15:58 -0700127 /**
128 * Populates the routing rules according to the route changes due to the link
129 * failure or link add. It computes the routes changed due to the link changes and
130 * repopulates the rules only for the routes.
131 *
132 * @param linkFail link failed, null for link added
133 * @return true if it succeeds to populate all rules, false otherwise
134 */
135 public boolean populateRoutingRulesForLinkStatusChange(Link linkFail) {
136
HIGUCHI Yuta84a25fc2015-09-08 16:16:31 +0900137 statusLock.lock();
138 try {
sangho20eff1d2015-04-13 15:15:58 -0700139
140 if (populationStatus == Status.STARTED) {
sangho52abe3a2015-05-05 14:13:34 -0700141 log.warn("Previous rule population is not finished.");
sangho20eff1d2015-04-13 15:15:58 -0700142 return true;
143 }
144
sangho45b009c2015-05-07 13:30:57 -0700145 // Take the snapshots of the links
146 updatedEcmpSpgMap = new HashMap<>();
147 for (Device sw : srManager.deviceService.getDevices()) {
Charles Chanc42e84e2015-10-20 16:24:19 -0700148 if (!srManager.mastershipService.isLocalMaster(sw.id())) {
sangho45b009c2015-05-07 13:30:57 -0700149 continue;
150 }
151 ECMPShortestPathGraph ecmpSpgUpdated =
152 new ECMPShortestPathGraph(sw.id(), srManager);
153 updatedEcmpSpgMap.put(sw.id(), ecmpSpgUpdated);
154 }
155
sangho52abe3a2015-05-05 14:13:34 -0700156 log.info("Starts rule population from link change");
157
sangho20eff1d2015-04-13 15:15:58 -0700158 Set<ArrayList<DeviceId>> routeChanges;
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700159 log.trace("populateRoutingRulesForLinkStatusChange: "
160 + "populationStatus is STARTED");
sangho20eff1d2015-04-13 15:15:58 -0700161 populationStatus = Status.STARTED;
162 if (linkFail == null) {
163 // Compare all routes of existing ECMP SPG with the new ones
164 routeChanges = computeRouteChange();
165 } else {
166 // Compare existing ECMP SPG only with the link removed
167 routeChanges = computeDamagedRoutes(linkFail);
168 }
169
170 if (routeChanges.isEmpty()) {
sangho52abe3a2015-05-05 14:13:34 -0700171 log.info("No route changes for the link status change");
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700172 log.debug("populateRoutingRulesForLinkStatusChange: populationStatus is SUCCEEDED");
sangho20eff1d2015-04-13 15:15:58 -0700173 populationStatus = Status.SUCCEEDED;
174 return true;
175 }
176
177 if (repopulateRoutingRulesForRoutes(routeChanges)) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700178 log.debug("populateRoutingRulesForLinkStatusChange: populationStatus is SUCCEEDED");
sangho20eff1d2015-04-13 15:15:58 -0700179 populationStatus = Status.SUCCEEDED;
180 log.info("Complete to repopulate the rules. # of rules populated : {}",
181 rulePopulator.getCounter());
182 return true;
183 } else {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700184 log.debug("populateRoutingRulesForLinkStatusChange: populationStatus is ABORTED");
sangho20eff1d2015-04-13 15:15:58 -0700185 populationStatus = Status.ABORTED;
186 log.warn("Failed to repopulate the rules.");
187 return false;
188 }
HIGUCHI Yuta84a25fc2015-09-08 16:16:31 +0900189 } finally {
190 statusLock.unlock();
sangho20eff1d2015-04-13 15:15:58 -0700191 }
192 }
193
194 private boolean repopulateRoutingRulesForRoutes(Set<ArrayList<DeviceId>> routes) {
195 rulePopulator.resetCounter();
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700196 HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>> routesBydevice =
197 new HashMap<>();
sangho20eff1d2015-04-13 15:15:58 -0700198 for (ArrayList<DeviceId> link: routes) {
sangho834e4b02015-05-01 09:38:25 -0700199 // When only the source device is defined, reinstall routes to all other devices
sangho20eff1d2015-04-13 15:15:58 -0700200 if (link.size() == 1) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700201 log.trace("repopulateRoutingRulesForRoutes: running ECMP graph for device {}", link.get(0));
sangho20eff1d2015-04-13 15:15:58 -0700202 ECMPShortestPathGraph ecmpSpg = new ECMPShortestPathGraph(link.get(0), srManager);
203 if (populateEcmpRoutingRules(link.get(0), ecmpSpg)) {
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700204 log.debug("Populating flow rules from {} to all is successful",
205 link.get(0));
sangho20eff1d2015-04-13 15:15:58 -0700206 currentEcmpSpgMap.put(link.get(0), ecmpSpg);
sangho52abe3a2015-05-05 14:13:34 -0700207 } else {
sangho45b009c2015-05-07 13:30:57 -0700208 log.warn("Failed to populate the flow rules from {} to all", link.get(0));
sangho52abe3a2015-05-05 14:13:34 -0700209 return false;
sangho20eff1d2015-04-13 15:15:58 -0700210 }
sangho45b009c2015-05-07 13:30:57 -0700211 } else {
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700212 ArrayList<ArrayList<DeviceId>> deviceRoutes =
213 routesBydevice.get(link.get(1));
214 if (deviceRoutes == null) {
215 deviceRoutes = new ArrayList<>();
216 routesBydevice.put(link.get(1), deviceRoutes);
217 }
218 deviceRoutes.add(link);
219 }
220 }
221
222 for (DeviceId impactedDevice : routesBydevice.keySet()) {
223 ArrayList<ArrayList<DeviceId>> deviceRoutes =
224 routesBydevice.get(impactedDevice);
225 for (ArrayList<DeviceId> link: deviceRoutes) {
226 log.debug("repopulate RoutingRules For Routes {} -> {}",
227 link.get(0), link.get(1));
sangho45b009c2015-05-07 13:30:57 -0700228 DeviceId src = link.get(0);
229 DeviceId dst = link.get(1);
sangho45b009c2015-05-07 13:30:57 -0700230 ECMPShortestPathGraph ecmpSpg = updatedEcmpSpgMap.get(dst);
231 HashMap<Integer, HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>>> switchVia =
232 ecmpSpg.getAllLearnedSwitchesAndVia();
233 for (Integer itrIdx : switchVia.keySet()) {
234 HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>> swViaMap =
235 switchVia.get(itrIdx);
236 for (DeviceId targetSw : swViaMap.keySet()) {
237 if (!targetSw.equals(src)) {
238 continue;
239 }
240 Set<DeviceId> nextHops = new HashSet<>();
241 for (ArrayList<DeviceId> via : swViaMap.get(targetSw)) {
242 if (via.isEmpty()) {
243 nextHops.add(dst);
244 } else {
245 nextHops.add(via.get(0));
246 }
247 }
248 if (!populateEcmpRoutingRulePartial(targetSw, dst, nextHops)) {
249 return false;
sangho20eff1d2015-04-13 15:15:58 -0700250 }
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700251 log.debug("Populating flow rules from {} to {} is successful",
252 targetSw, dst);
sangho20eff1d2015-04-13 15:15:58 -0700253 }
sangho20eff1d2015-04-13 15:15:58 -0700254 }
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700255 //currentEcmpSpgMap.put(dst, ecmpSpg);
sangho20eff1d2015-04-13 15:15:58 -0700256 }
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700257 //Only if all the flows for all impacted routes to a
258 //specific target are pushed successfully, update the
259 //ECMP graph for that target. (Or else the next event
260 //would not see any changes in the ECMP graphs)
261 currentEcmpSpgMap.put(impactedDevice,
262 updatedEcmpSpgMap.get(impactedDevice));
sangho20eff1d2015-04-13 15:15:58 -0700263 }
264 return true;
265 }
266
267 private Set<ArrayList<DeviceId>> computeDamagedRoutes(Link linkFail) {
268
269 Set<ArrayList<DeviceId>> routes = new HashSet<>();
270
271 for (Device sw : srManager.deviceService.getDevices()) {
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700272 log.debug("Computing the impacted routes for device {} due to link fail",
273 sw.id());
Charles Chanc42e84e2015-10-20 16:24:19 -0700274 if (!srManager.mastershipService.isLocalMaster(sw.id())) {
sangho20eff1d2015-04-13 15:15:58 -0700275 continue;
276 }
277 ECMPShortestPathGraph ecmpSpg = currentEcmpSpgMap.get(sw.id());
278 if (ecmpSpg == null) {
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700279 log.error("No existing ECMP graph for switch {}", sw.id());
sangho20eff1d2015-04-13 15:15:58 -0700280 continue;
281 }
282 HashMap<Integer, HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>>> switchVia =
283 ecmpSpg.getAllLearnedSwitchesAndVia();
284 for (Integer itrIdx : switchVia.keySet()) {
285 HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>> swViaMap =
286 switchVia.get(itrIdx);
287 for (DeviceId targetSw : swViaMap.keySet()) {
288 DeviceId destSw = sw.id();
289 Set<ArrayList<DeviceId>> subLinks =
290 computeLinks(targetSw, destSw, swViaMap);
291 for (ArrayList<DeviceId> alink: subLinks) {
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700292 if ((alink.get(0).equals(linkFail.src().deviceId()) &&
293 alink.get(1).equals(linkFail.dst().deviceId()))
294 ||
295 (alink.get(0).equals(linkFail.dst().deviceId()) &&
296 alink.get(1).equals(linkFail.src().deviceId()))) {
297 log.debug("Impacted route:{}->{}", targetSw, destSw);
sangho20eff1d2015-04-13 15:15:58 -0700298 ArrayList<DeviceId> aRoute = new ArrayList<>();
299 aRoute.add(targetSw);
300 aRoute.add(destSw);
301 routes.add(aRoute);
302 break;
303 }
304 }
305 }
306 }
sangho45b009c2015-05-07 13:30:57 -0700307
sangho20eff1d2015-04-13 15:15:58 -0700308 }
309
310 return routes;
311 }
312
313 private Set<ArrayList<DeviceId>> computeRouteChange() {
314
315 Set<ArrayList<DeviceId>> routes = new HashSet<>();
316
317 for (Device sw : srManager.deviceService.getDevices()) {
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700318 log.debug("Computing the impacted routes for device {}",
319 sw.id());
Charles Chanc42e84e2015-10-20 16:24:19 -0700320 if (!srManager.mastershipService.isLocalMaster(sw.id())) {
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700321 log.debug("No mastership for {} and skip route optimization",
322 sw.id());
sangho20eff1d2015-04-13 15:15:58 -0700323 continue;
324 }
sangho45b009c2015-05-07 13:30:57 -0700325
326 log.trace("link of {} - ", sw.id());
327 for (Link link: srManager.linkService.getDeviceLinks(sw.id())) {
328 log.trace("{} -> {} ", link.src().deviceId(), link.dst().deviceId());
329 }
330
331 log.debug("Checking route change for switch {}", sw.id());
sangho20eff1d2015-04-13 15:15:58 -0700332 ECMPShortestPathGraph ecmpSpg = currentEcmpSpgMap.get(sw.id());
333 if (ecmpSpg == null) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700334 log.debug("No existing ECMP graph for device {}", sw.id());
sangho20eff1d2015-04-13 15:15:58 -0700335 ArrayList<DeviceId> route = new ArrayList<>();
336 route.add(sw.id());
337 routes.add(route);
338 continue;
339 }
sangho45b009c2015-05-07 13:30:57 -0700340 ECMPShortestPathGraph newEcmpSpg = updatedEcmpSpgMap.get(sw.id());
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700341 //currentEcmpSpgMap.put(sw.id(), newEcmpSpg);
sangho20eff1d2015-04-13 15:15:58 -0700342 HashMap<Integer, HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>>> switchVia =
343 ecmpSpg.getAllLearnedSwitchesAndVia();
344 HashMap<Integer, HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>>> switchViaUpdated =
345 newEcmpSpg.getAllLearnedSwitchesAndVia();
346
sangho45b009c2015-05-07 13:30:57 -0700347 for (Integer itrIdx : switchViaUpdated.keySet()) {
348 HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>> swViaMapUpdated =
349 switchViaUpdated.get(itrIdx);
350 for (DeviceId srcSw : swViaMapUpdated.keySet()) {
351 ArrayList<ArrayList<DeviceId>> viaUpdated = swViaMapUpdated.get(srcSw);
352 ArrayList<ArrayList<DeviceId>> via = getVia(switchVia, srcSw);
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700353 if ((via == null) || !viaUpdated.equals(via)) {
354 log.debug("Impacted route:{}->{}", srcSw, sw.id());
sangho20eff1d2015-04-13 15:15:58 -0700355 ArrayList<DeviceId> route = new ArrayList<>();
356 route.add(srcSw);
357 route.add(sw.id());
358 routes.add(route);
359 }
360 }
361 }
sangho45b009c2015-05-07 13:30:57 -0700362 }
sangho20eff1d2015-04-13 15:15:58 -0700363
sangho45b009c2015-05-07 13:30:57 -0700364 for (ArrayList<DeviceId> link: routes) {
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700365 log.trace("Route changes - ");
sangho45b009c2015-05-07 13:30:57 -0700366 if (link.size() == 1) {
367 log.trace(" : {} - all", link.get(0));
368 } else {
369 log.trace(" : {} - {}", link.get(0), link.get(1));
370 }
sangho20eff1d2015-04-13 15:15:58 -0700371 }
372
373 return routes;
374 }
375
376 private ArrayList<ArrayList<DeviceId>> getVia(HashMap<Integer, HashMap<DeviceId,
377 ArrayList<ArrayList<DeviceId>>>> switchVia, DeviceId srcSw) {
378 for (Integer itrIdx : switchVia.keySet()) {
379 HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>> swViaMap =
380 switchVia.get(itrIdx);
381 if (swViaMap.get(srcSw) == null) {
382 continue;
383 } else {
384 return swViaMap.get(srcSw);
385 }
386 }
387
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700388 return null;
sangho20eff1d2015-04-13 15:15:58 -0700389 }
390
391 private Set<ArrayList<DeviceId>> computeLinks(DeviceId src,
392 DeviceId dst,
393 HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>> viaMap) {
394 Set<ArrayList<DeviceId>> subLinks = Sets.newHashSet();
395 for (ArrayList<DeviceId> via : viaMap.get(src)) {
396 DeviceId linkSrc = src;
397 DeviceId linkDst = dst;
398 for (DeviceId viaDevice: via) {
399 ArrayList<DeviceId> link = new ArrayList<>();
400 linkDst = viaDevice;
401 link.add(linkSrc);
402 link.add(linkDst);
403 subLinks.add(link);
404 linkSrc = viaDevice;
405 }
406 ArrayList<DeviceId> link = new ArrayList<>();
407 link.add(linkSrc);
408 link.add(dst);
409 subLinks.add(link);
410 }
411
412 return subLinks;
413 }
414
415 private boolean populateEcmpRoutingRules(DeviceId destSw,
sanghob35a6192015-04-01 13:05:26 -0700416 ECMPShortestPathGraph ecmpSPG) {
417
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700418 HashMap<Integer, HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>>> switchVia = ecmpSPG
419 .getAllLearnedSwitchesAndVia();
sanghob35a6192015-04-01 13:05:26 -0700420 for (Integer itrIdx : switchVia.keySet()) {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700421 HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>> swViaMap = switchVia
422 .get(itrIdx);
sanghob35a6192015-04-01 13:05:26 -0700423 for (DeviceId targetSw : swViaMap.keySet()) {
sanghob35a6192015-04-01 13:05:26 -0700424 Set<DeviceId> nextHops = new HashSet<>();
Saurav Dasa07f2032015-10-19 14:37:36 -0700425 log.debug("** Iter: {} root: {} target: {}", itrIdx, destSw, targetSw);
sanghob35a6192015-04-01 13:05:26 -0700426 for (ArrayList<DeviceId> via : swViaMap.get(targetSw)) {
427 if (via.isEmpty()) {
428 nextHops.add(destSw);
429 } else {
430 nextHops.add(via.get(0));
431 }
432 }
433 if (!populateEcmpRoutingRulePartial(targetSw, destSw, nextHops)) {
434 return false;
435 }
436 }
437 }
438
439 return true;
440 }
441
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700442 private boolean populateEcmpRoutingRulePartial(DeviceId targetSw,
443 DeviceId destSw,
444 Set<DeviceId> nextHops) {
sanghob35a6192015-04-01 13:05:26 -0700445 boolean result;
446
447 if (nextHops.isEmpty()) {
448 nextHops.add(destSw);
449 }
450
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700451 // If both target switch and dest switch are edge routers, then set IP
sangho52abe3a2015-05-05 14:13:34 -0700452 // rule for both subnet and router IP.
sangho666cd6d2015-04-14 16:27:13 -0700453 if (config.isEdgeDevice(targetSw) && config.isEdgeDevice(destSw)) {
454 List<Ip4Prefix> subnets = config.getSubnets(destSw);
Saurav Dasa07f2032015-10-19 14:37:36 -0700455 log.debug("* populateEcmpRoutingRulePartial in device {} towards {} for subnets {}",
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700456 targetSw, destSw, subnets);
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700457 result = rulePopulator.populateIpRuleForSubnet(targetSw,
458 subnets,
459 destSw,
460 nextHops);
sanghob35a6192015-04-01 13:05:26 -0700461 if (!result) {
462 return false;
463 }
464
sangho666cd6d2015-04-14 16:27:13 -0700465 Ip4Address routerIp = config.getRouterIp(destSw);
466 IpPrefix routerIpPrefix = IpPrefix.valueOf(routerIp, IpPrefix.MAX_INET_MASK_LENGTH);
Saurav Dasa07f2032015-10-19 14:37:36 -0700467 log.debug("* populateEcmpRoutingRulePartial in device {} towards {} for router IP {}",
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700468 targetSw, destSw, routerIpPrefix);
sangho666cd6d2015-04-14 16:27:13 -0700469 result = rulePopulator.populateIpRuleForRouter(targetSw, routerIpPrefix, destSw, nextHops);
sanghob35a6192015-04-01 13:05:26 -0700470 if (!result) {
471 return false;
472 }
473
sangho52abe3a2015-05-05 14:13:34 -0700474 // If the target switch is an edge router, then set IP rules for the router IP.
sangho666cd6d2015-04-14 16:27:13 -0700475 } else if (config.isEdgeDevice(targetSw)) {
476 Ip4Address routerIp = config.getRouterIp(destSw);
477 IpPrefix routerIpPrefix = IpPrefix.valueOf(routerIp, IpPrefix.MAX_INET_MASK_LENGTH);
Saurav Dasa07f2032015-10-19 14:37:36 -0700478 log.debug("* populateEcmpRoutingRulePartial in device {} towards {} for router IP {}",
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700479 targetSw, destSw, routerIpPrefix);
sangho666cd6d2015-04-14 16:27:13 -0700480 result = rulePopulator.populateIpRuleForRouter(targetSw, routerIpPrefix, destSw, nextHops);
sanghob35a6192015-04-01 13:05:26 -0700481 if (!result) {
482 return false;
483 }
sangho52abe3a2015-05-05 14:13:34 -0700484 }
sanghob35a6192015-04-01 13:05:26 -0700485
sangho52abe3a2015-05-05 14:13:34 -0700486 // Populates MPLS rules to all routers
Saurav Dasa07f2032015-10-19 14:37:36 -0700487 log.debug("* populateEcmpRoutingRulePartial in device{} towards {} for all MPLS rules",
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700488 targetSw, destSw);
sangho52abe3a2015-05-05 14:13:34 -0700489 result = rulePopulator.populateMplsRule(targetSw, destSw, nextHops);
490 if (!result) {
491 return false;
sanghob35a6192015-04-01 13:05:26 -0700492 }
493
494 return true;
495 }
496
497 /**
Saurav Das822c4e22015-10-23 10:51:11 -0700498 * Populates filtering rules for permitting Router DstMac and VLAN.
sanghob35a6192015-04-01 13:05:26 -0700499 *
500 * @param deviceId Switch ID to set the rules
501 */
Saurav Das822c4e22015-10-23 10:51:11 -0700502 public void populatePortAddressingRules(DeviceId deviceId) {
503 rulePopulator.populateRouterMacVlanFilters(deviceId);
504 rulePopulator.populateRouterIpPunts(deviceId);
sanghob35a6192015-04-01 13:05:26 -0700505 }
506
507 /**
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700508 * Start the flow rule population process if it was never started. The
509 * process finishes successfully when all flow rules are set and stops with
510 * ABORTED status when any groups required for flows is not set yet.
sanghob35a6192015-04-01 13:05:26 -0700511 */
512 public void startPopulationProcess() {
HIGUCHI Yuta84a25fc2015-09-08 16:16:31 +0900513 statusLock.lock();
514 try {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700515 if (populationStatus == Status.IDLE
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700516 || populationStatus == Status.SUCCEEDED
517 || populationStatus == Status.ABORTED) {
sanghob35a6192015-04-01 13:05:26 -0700518 populationStatus = Status.STARTED;
519 populateAllRoutingRules();
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700520 } else {
521 log.warn("Not initiating startPopulationProcess as populationStatus is {}",
522 populationStatus);
sanghob35a6192015-04-01 13:05:26 -0700523 }
HIGUCHI Yuta84a25fc2015-09-08 16:16:31 +0900524 } finally {
525 statusLock.unlock();
sanghob35a6192015-04-01 13:05:26 -0700526 }
527 }
528
529 /**
530 * Resume the flow rule population process if it was aborted for any reason.
531 * Mostly the process is aborted when the groups required are not set yet.
Saurav Dasa07f2032015-10-19 14:37:36 -0700532 * XXX is this called?
533 *
sanghob35a6192015-04-01 13:05:26 -0700534 */
535 public void resumePopulationProcess() {
HIGUCHI Yuta84a25fc2015-09-08 16:16:31 +0900536 statusLock.lock();
537 try {
sanghob35a6192015-04-01 13:05:26 -0700538 if (populationStatus == Status.ABORTED) {
539 populationStatus = Status.STARTED;
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700540 // TODO: we need to restart from the point aborted instead of
541 // restarting.
sanghob35a6192015-04-01 13:05:26 -0700542 populateAllRoutingRules();
543 }
HIGUCHI Yuta84a25fc2015-09-08 16:16:31 +0900544 } finally {
545 statusLock.unlock();
sanghob35a6192015-04-01 13:05:26 -0700546 }
547 }
548}