blob: c4a91c7526202c8d5e517de3491c0f1fca2222b1 [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;
32import java.util.Set;
HIGUCHI Yuta84a25fc2015-09-08 16:16:31 +090033import java.util.concurrent.locks.Lock;
34import java.util.concurrent.locks.ReentrantLock;
sanghob35a6192015-04-01 13:05:26 -070035
36import static com.google.common.base.Preconditions.checkNotNull;
37
38public class DefaultRoutingHandler {
39
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070040 private static Logger log = LoggerFactory
41 .getLogger(DefaultRoutingHandler.class);
sanghob35a6192015-04-01 13:05:26 -070042
43 private SegmentRoutingManager srManager;
44 private RoutingRulePopulator rulePopulator;
sangho20eff1d2015-04-13 15:15:58 -070045 private HashMap<DeviceId, ECMPShortestPathGraph> currentEcmpSpgMap;
sangho45b009c2015-05-07 13:30:57 -070046 private HashMap<DeviceId, ECMPShortestPathGraph> updatedEcmpSpgMap;
sangho666cd6d2015-04-14 16:27:13 -070047 private DeviceConfiguration config;
HIGUCHI Yuta84a25fc2015-09-08 16:16:31 +090048 private final Lock statusLock = new ReentrantLock();
49 private volatile Status populationStatus;
sanghob35a6192015-04-01 13:05:26 -070050
51 /**
52 * Represents the default routing population status.
53 */
54 public enum Status {
55 // population process is not started yet.
56 IDLE,
57
58 // population process started.
59 STARTED,
60
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070061 // population process was aborted due to errors, mostly for groups not
62 // found.
sanghob35a6192015-04-01 13:05:26 -070063 ABORTED,
64
65 // population process was finished successfully.
66 SUCCEEDED
67 }
68
69 /**
70 * Creates a DefaultRoutingHandler object.
71 *
72 * @param srManager SegmentRoutingManager object
73 */
74 public DefaultRoutingHandler(SegmentRoutingManager srManager) {
75 this.srManager = srManager;
76 this.rulePopulator = checkNotNull(srManager.routingRulePopulator);
sangho666cd6d2015-04-14 16:27:13 -070077 this.config = checkNotNull(srManager.deviceConfiguration);
sanghob35a6192015-04-01 13:05:26 -070078 this.populationStatus = Status.IDLE;
sangho20eff1d2015-04-13 15:15:58 -070079 this.currentEcmpSpgMap = Maps.newHashMap();
sanghob35a6192015-04-01 13:05:26 -070080 }
81
82 /**
83 * Populates all routing rules to all connected routers, including default
84 * routing rules, adjacency rules, and policy rules if any.
85 *
86 * @return true if it succeeds in populating all rules, otherwise false
87 */
88 public boolean populateAllRoutingRules() {
89
HIGUCHI Yuta84a25fc2015-09-08 16:16:31 +090090 statusLock.lock();
91 try {
92 populationStatus = Status.STARTED;
93 rulePopulator.resetCounter();
Saurav Dasa07f2032015-10-19 14:37:36 -070094 log.info("Starting to populate segment-routing rules");
HIGUCHI Yuta84a25fc2015-09-08 16:16:31 +090095 log.debug("populateAllRoutingRules: populationStatus is STARTED");
sanghob35a6192015-04-01 13:05:26 -070096
HIGUCHI Yuta84a25fc2015-09-08 16:16:31 +090097 for (Device sw : srManager.deviceService.getDevices()) {
Charles Chanc42e84e2015-10-20 16:24:19 -070098 if (!srManager.mastershipService.isLocalMaster(sw.id())) {
HIGUCHI Yuta84a25fc2015-09-08 16:16:31 +090099 log.debug("populateAllRoutingRules: skipping device {}...we are not master",
100 sw.id());
101 continue;
102 }
103
104 ECMPShortestPathGraph ecmpSpg = new ECMPShortestPathGraph(sw.id(), srManager);
105 if (!populateEcmpRoutingRules(sw.id(), ecmpSpg)) {
106 log.debug("populateAllRoutingRules: populationStatus is ABORTED");
107 populationStatus = Status.ABORTED;
108 log.debug("Abort routing rule population");
109 return false;
110 }
111 currentEcmpSpgMap.put(sw.id(), ecmpSpg);
112
113 // TODO: Set adjacency routing rule for all switches
sanghob35a6192015-04-01 13:05:26 -0700114 }
115
HIGUCHI Yuta84a25fc2015-09-08 16:16:31 +0900116 log.debug("populateAllRoutingRules: populationStatus is SUCCEEDED");
117 populationStatus = Status.SUCCEEDED;
Saurav Dasa07f2032015-10-19 14:37:36 -0700118 log.info("Completed routing rule population. Total # of rules pushed : {}",
HIGUCHI Yuta84a25fc2015-09-08 16:16:31 +0900119 rulePopulator.getCounter());
120 return true;
121 } finally {
122 statusLock.unlock();
sanghob35a6192015-04-01 13:05:26 -0700123 }
sanghob35a6192015-04-01 13:05:26 -0700124 }
125
sangho20eff1d2015-04-13 15:15:58 -0700126 /**
127 * Populates the routing rules according to the route changes due to the link
128 * failure or link add. It computes the routes changed due to the link changes and
129 * repopulates the rules only for the routes.
130 *
131 * @param linkFail link failed, null for link added
132 * @return true if it succeeds to populate all rules, false otherwise
133 */
134 public boolean populateRoutingRulesForLinkStatusChange(Link linkFail) {
135
HIGUCHI Yuta84a25fc2015-09-08 16:16:31 +0900136 statusLock.lock();
137 try {
sangho20eff1d2015-04-13 15:15:58 -0700138
139 if (populationStatus == Status.STARTED) {
sangho52abe3a2015-05-05 14:13:34 -0700140 log.warn("Previous rule population is not finished.");
sangho20eff1d2015-04-13 15:15:58 -0700141 return true;
142 }
143
sangho45b009c2015-05-07 13:30:57 -0700144 // Take the snapshots of the links
145 updatedEcmpSpgMap = new HashMap<>();
146 for (Device sw : srManager.deviceService.getDevices()) {
Charles Chanc42e84e2015-10-20 16:24:19 -0700147 if (!srManager.mastershipService.isLocalMaster(sw.id())) {
sangho45b009c2015-05-07 13:30:57 -0700148 continue;
149 }
150 ECMPShortestPathGraph ecmpSpgUpdated =
151 new ECMPShortestPathGraph(sw.id(), srManager);
152 updatedEcmpSpgMap.put(sw.id(), ecmpSpgUpdated);
153 }
154
sangho52abe3a2015-05-05 14:13:34 -0700155 log.info("Starts rule population from link change");
156
sangho20eff1d2015-04-13 15:15:58 -0700157 Set<ArrayList<DeviceId>> routeChanges;
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700158 log.trace("populateRoutingRulesForLinkStatusChange: "
159 + "populationStatus is STARTED");
sangho20eff1d2015-04-13 15:15:58 -0700160 populationStatus = Status.STARTED;
161 if (linkFail == null) {
162 // Compare all routes of existing ECMP SPG with the new ones
163 routeChanges = computeRouteChange();
164 } else {
165 // Compare existing ECMP SPG only with the link removed
166 routeChanges = computeDamagedRoutes(linkFail);
167 }
168
169 if (routeChanges.isEmpty()) {
sangho52abe3a2015-05-05 14:13:34 -0700170 log.info("No route changes for the link status change");
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700171 log.debug("populateRoutingRulesForLinkStatusChange: populationStatus is SUCCEEDED");
sangho20eff1d2015-04-13 15:15:58 -0700172 populationStatus = Status.SUCCEEDED;
173 return true;
174 }
175
176 if (repopulateRoutingRulesForRoutes(routeChanges)) {
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 log.info("Complete to repopulate the rules. # of rules populated : {}",
180 rulePopulator.getCounter());
181 return true;
182 } else {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700183 log.debug("populateRoutingRulesForLinkStatusChange: populationStatus is ABORTED");
sangho20eff1d2015-04-13 15:15:58 -0700184 populationStatus = Status.ABORTED;
185 log.warn("Failed to repopulate the rules.");
186 return false;
187 }
HIGUCHI Yuta84a25fc2015-09-08 16:16:31 +0900188 } finally {
189 statusLock.unlock();
sangho20eff1d2015-04-13 15:15:58 -0700190 }
191 }
192
193 private boolean repopulateRoutingRulesForRoutes(Set<ArrayList<DeviceId>> routes) {
194 rulePopulator.resetCounter();
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700195 HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>> routesBydevice =
196 new HashMap<>();
sangho20eff1d2015-04-13 15:15:58 -0700197 for (ArrayList<DeviceId> link: routes) {
sangho834e4b02015-05-01 09:38:25 -0700198 // When only the source device is defined, reinstall routes to all other devices
sangho20eff1d2015-04-13 15:15:58 -0700199 if (link.size() == 1) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700200 log.trace("repopulateRoutingRulesForRoutes: running ECMP graph for device {}", link.get(0));
sangho20eff1d2015-04-13 15:15:58 -0700201 ECMPShortestPathGraph ecmpSpg = new ECMPShortestPathGraph(link.get(0), srManager);
202 if (populateEcmpRoutingRules(link.get(0), ecmpSpg)) {
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700203 log.debug("Populating flow rules from {} to all is successful",
204 link.get(0));
sangho20eff1d2015-04-13 15:15:58 -0700205 currentEcmpSpgMap.put(link.get(0), ecmpSpg);
sangho52abe3a2015-05-05 14:13:34 -0700206 } else {
sangho45b009c2015-05-07 13:30:57 -0700207 log.warn("Failed to populate the flow rules from {} to all", link.get(0));
sangho52abe3a2015-05-05 14:13:34 -0700208 return false;
sangho20eff1d2015-04-13 15:15:58 -0700209 }
sangho45b009c2015-05-07 13:30:57 -0700210 } else {
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700211 ArrayList<ArrayList<DeviceId>> deviceRoutes =
212 routesBydevice.get(link.get(1));
213 if (deviceRoutes == null) {
214 deviceRoutes = new ArrayList<>();
215 routesBydevice.put(link.get(1), deviceRoutes);
216 }
217 deviceRoutes.add(link);
218 }
219 }
220
221 for (DeviceId impactedDevice : routesBydevice.keySet()) {
222 ArrayList<ArrayList<DeviceId>> deviceRoutes =
223 routesBydevice.get(impactedDevice);
224 for (ArrayList<DeviceId> link: deviceRoutes) {
225 log.debug("repopulate RoutingRules For Routes {} -> {}",
226 link.get(0), link.get(1));
sangho45b009c2015-05-07 13:30:57 -0700227 DeviceId src = link.get(0);
228 DeviceId dst = link.get(1);
sangho45b009c2015-05-07 13:30:57 -0700229 ECMPShortestPathGraph ecmpSpg = updatedEcmpSpgMap.get(dst);
230 HashMap<Integer, HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>>> switchVia =
231 ecmpSpg.getAllLearnedSwitchesAndVia();
232 for (Integer itrIdx : switchVia.keySet()) {
233 HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>> swViaMap =
234 switchVia.get(itrIdx);
235 for (DeviceId targetSw : swViaMap.keySet()) {
236 if (!targetSw.equals(src)) {
237 continue;
238 }
239 Set<DeviceId> nextHops = new HashSet<>();
240 for (ArrayList<DeviceId> via : swViaMap.get(targetSw)) {
241 if (via.isEmpty()) {
242 nextHops.add(dst);
243 } else {
244 nextHops.add(via.get(0));
245 }
246 }
247 if (!populateEcmpRoutingRulePartial(targetSw, dst, nextHops)) {
248 return false;
sangho20eff1d2015-04-13 15:15:58 -0700249 }
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700250 log.debug("Populating flow rules from {} to {} is successful",
251 targetSw, dst);
sangho20eff1d2015-04-13 15:15:58 -0700252 }
sangho20eff1d2015-04-13 15:15:58 -0700253 }
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700254 //currentEcmpSpgMap.put(dst, ecmpSpg);
sangho20eff1d2015-04-13 15:15:58 -0700255 }
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700256 //Only if all the flows for all impacted routes to a
257 //specific target are pushed successfully, update the
258 //ECMP graph for that target. (Or else the next event
259 //would not see any changes in the ECMP graphs)
260 currentEcmpSpgMap.put(impactedDevice,
261 updatedEcmpSpgMap.get(impactedDevice));
sangho20eff1d2015-04-13 15:15:58 -0700262 }
263 return true;
264 }
265
266 private Set<ArrayList<DeviceId>> computeDamagedRoutes(Link linkFail) {
267
268 Set<ArrayList<DeviceId>> routes = new HashSet<>();
269
270 for (Device sw : srManager.deviceService.getDevices()) {
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700271 log.debug("Computing the impacted routes for device {} due to link fail",
272 sw.id());
Charles Chanc42e84e2015-10-20 16:24:19 -0700273 if (!srManager.mastershipService.isLocalMaster(sw.id())) {
sangho20eff1d2015-04-13 15:15:58 -0700274 continue;
275 }
276 ECMPShortestPathGraph ecmpSpg = currentEcmpSpgMap.get(sw.id());
277 if (ecmpSpg == null) {
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700278 log.error("No existing ECMP graph for switch {}", sw.id());
sangho20eff1d2015-04-13 15:15:58 -0700279 continue;
280 }
281 HashMap<Integer, HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>>> switchVia =
282 ecmpSpg.getAllLearnedSwitchesAndVia();
283 for (Integer itrIdx : switchVia.keySet()) {
284 HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>> swViaMap =
285 switchVia.get(itrIdx);
286 for (DeviceId targetSw : swViaMap.keySet()) {
287 DeviceId destSw = sw.id();
288 Set<ArrayList<DeviceId>> subLinks =
289 computeLinks(targetSw, destSw, swViaMap);
290 for (ArrayList<DeviceId> alink: subLinks) {
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700291 if ((alink.get(0).equals(linkFail.src().deviceId()) &&
292 alink.get(1).equals(linkFail.dst().deviceId()))
293 ||
294 (alink.get(0).equals(linkFail.dst().deviceId()) &&
295 alink.get(1).equals(linkFail.src().deviceId()))) {
296 log.debug("Impacted route:{}->{}", targetSw, destSw);
sangho20eff1d2015-04-13 15:15:58 -0700297 ArrayList<DeviceId> aRoute = new ArrayList<>();
298 aRoute.add(targetSw);
299 aRoute.add(destSw);
300 routes.add(aRoute);
301 break;
302 }
303 }
304 }
305 }
sangho45b009c2015-05-07 13:30:57 -0700306
sangho20eff1d2015-04-13 15:15:58 -0700307 }
308
309 return routes;
310 }
311
312 private Set<ArrayList<DeviceId>> computeRouteChange() {
313
314 Set<ArrayList<DeviceId>> routes = new HashSet<>();
315
316 for (Device sw : srManager.deviceService.getDevices()) {
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700317 log.debug("Computing the impacted routes for device {}",
318 sw.id());
Charles Chanc42e84e2015-10-20 16:24:19 -0700319 if (!srManager.mastershipService.isLocalMaster(sw.id())) {
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700320 log.debug("No mastership for {} and skip route optimization",
321 sw.id());
sangho20eff1d2015-04-13 15:15:58 -0700322 continue;
323 }
sangho45b009c2015-05-07 13:30:57 -0700324
325 log.trace("link of {} - ", sw.id());
326 for (Link link: srManager.linkService.getDeviceLinks(sw.id())) {
327 log.trace("{} -> {} ", link.src().deviceId(), link.dst().deviceId());
328 }
329
330 log.debug("Checking route change for switch {}", sw.id());
sangho20eff1d2015-04-13 15:15:58 -0700331 ECMPShortestPathGraph ecmpSpg = currentEcmpSpgMap.get(sw.id());
332 if (ecmpSpg == null) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700333 log.debug("No existing ECMP graph for device {}", sw.id());
sangho20eff1d2015-04-13 15:15:58 -0700334 ArrayList<DeviceId> route = new ArrayList<>();
335 route.add(sw.id());
336 routes.add(route);
337 continue;
338 }
sangho45b009c2015-05-07 13:30:57 -0700339 ECMPShortestPathGraph newEcmpSpg = updatedEcmpSpgMap.get(sw.id());
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700340 //currentEcmpSpgMap.put(sw.id(), newEcmpSpg);
sangho20eff1d2015-04-13 15:15:58 -0700341 HashMap<Integer, HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>>> switchVia =
342 ecmpSpg.getAllLearnedSwitchesAndVia();
343 HashMap<Integer, HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>>> switchViaUpdated =
344 newEcmpSpg.getAllLearnedSwitchesAndVia();
345
sangho45b009c2015-05-07 13:30:57 -0700346 for (Integer itrIdx : switchViaUpdated.keySet()) {
347 HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>> swViaMapUpdated =
348 switchViaUpdated.get(itrIdx);
349 for (DeviceId srcSw : swViaMapUpdated.keySet()) {
350 ArrayList<ArrayList<DeviceId>> viaUpdated = swViaMapUpdated.get(srcSw);
351 ArrayList<ArrayList<DeviceId>> via = getVia(switchVia, srcSw);
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700352 if ((via == null) || !viaUpdated.equals(via)) {
353 log.debug("Impacted route:{}->{}", srcSw, sw.id());
sangho20eff1d2015-04-13 15:15:58 -0700354 ArrayList<DeviceId> route = new ArrayList<>();
355 route.add(srcSw);
356 route.add(sw.id());
357 routes.add(route);
358 }
359 }
360 }
sangho45b009c2015-05-07 13:30:57 -0700361 }
sangho20eff1d2015-04-13 15:15:58 -0700362
sangho45b009c2015-05-07 13:30:57 -0700363 for (ArrayList<DeviceId> link: routes) {
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700364 log.trace("Route changes - ");
sangho45b009c2015-05-07 13:30:57 -0700365 if (link.size() == 1) {
366 log.trace(" : {} - all", link.get(0));
367 } else {
368 log.trace(" : {} - {}", link.get(0), link.get(1));
369 }
sangho20eff1d2015-04-13 15:15:58 -0700370 }
371
372 return routes;
373 }
374
375 private ArrayList<ArrayList<DeviceId>> getVia(HashMap<Integer, HashMap<DeviceId,
376 ArrayList<ArrayList<DeviceId>>>> switchVia, DeviceId srcSw) {
377 for (Integer itrIdx : switchVia.keySet()) {
378 HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>> swViaMap =
379 switchVia.get(itrIdx);
380 if (swViaMap.get(srcSw) == null) {
381 continue;
382 } else {
383 return swViaMap.get(srcSw);
384 }
385 }
386
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700387 return null;
sangho20eff1d2015-04-13 15:15:58 -0700388 }
389
390 private Set<ArrayList<DeviceId>> computeLinks(DeviceId src,
391 DeviceId dst,
392 HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>> viaMap) {
393 Set<ArrayList<DeviceId>> subLinks = Sets.newHashSet();
394 for (ArrayList<DeviceId> via : viaMap.get(src)) {
395 DeviceId linkSrc = src;
396 DeviceId linkDst = dst;
397 for (DeviceId viaDevice: via) {
398 ArrayList<DeviceId> link = new ArrayList<>();
399 linkDst = viaDevice;
400 link.add(linkSrc);
401 link.add(linkDst);
402 subLinks.add(link);
403 linkSrc = viaDevice;
404 }
405 ArrayList<DeviceId> link = new ArrayList<>();
406 link.add(linkSrc);
407 link.add(dst);
408 subLinks.add(link);
409 }
410
411 return subLinks;
412 }
413
414 private boolean populateEcmpRoutingRules(DeviceId destSw,
sanghob35a6192015-04-01 13:05:26 -0700415 ECMPShortestPathGraph ecmpSPG) {
416
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700417 HashMap<Integer, HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>>> switchVia = ecmpSPG
418 .getAllLearnedSwitchesAndVia();
sanghob35a6192015-04-01 13:05:26 -0700419 for (Integer itrIdx : switchVia.keySet()) {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700420 HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>> swViaMap = switchVia
421 .get(itrIdx);
sanghob35a6192015-04-01 13:05:26 -0700422 for (DeviceId targetSw : swViaMap.keySet()) {
sanghob35a6192015-04-01 13:05:26 -0700423 Set<DeviceId> nextHops = new HashSet<>();
Saurav Dasa07f2032015-10-19 14:37:36 -0700424 log.debug("** Iter: {} root: {} target: {}", itrIdx, destSw, targetSw);
sanghob35a6192015-04-01 13:05:26 -0700425 for (ArrayList<DeviceId> via : swViaMap.get(targetSw)) {
426 if (via.isEmpty()) {
427 nextHops.add(destSw);
428 } else {
429 nextHops.add(via.get(0));
430 }
431 }
432 if (!populateEcmpRoutingRulePartial(targetSw, destSw, nextHops)) {
433 return false;
434 }
435 }
436 }
437
438 return true;
439 }
440
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700441 private boolean populateEcmpRoutingRulePartial(DeviceId targetSw,
442 DeviceId destSw,
443 Set<DeviceId> nextHops) {
sanghob35a6192015-04-01 13:05:26 -0700444 boolean result;
445
446 if (nextHops.isEmpty()) {
447 nextHops.add(destSw);
448 }
449
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700450 // If both target switch and dest switch are edge routers, then set IP
sangho52abe3a2015-05-05 14:13:34 -0700451 // rule for both subnet and router IP.
sangho666cd6d2015-04-14 16:27:13 -0700452 if (config.isEdgeDevice(targetSw) && config.isEdgeDevice(destSw)) {
Charles Chan9f676b62015-10-29 14:58:10 -0700453 Set<Ip4Prefix> subnets = config.getSubnets(destSw);
Saurav Dasa07f2032015-10-19 14:37:36 -0700454 log.debug("* populateEcmpRoutingRulePartial in device {} towards {} for subnets {}",
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700455 targetSw, destSw, subnets);
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700456 result = rulePopulator.populateIpRuleForSubnet(targetSw,
457 subnets,
458 destSw,
459 nextHops);
sanghob35a6192015-04-01 13:05:26 -0700460 if (!result) {
461 return false;
462 }
463
sangho666cd6d2015-04-14 16:27:13 -0700464 Ip4Address routerIp = config.getRouterIp(destSw);
465 IpPrefix routerIpPrefix = IpPrefix.valueOf(routerIp, IpPrefix.MAX_INET_MASK_LENGTH);
Saurav Dasa07f2032015-10-19 14:37:36 -0700466 log.debug("* populateEcmpRoutingRulePartial in device {} towards {} for router IP {}",
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700467 targetSw, destSw, routerIpPrefix);
sangho666cd6d2015-04-14 16:27:13 -0700468 result = rulePopulator.populateIpRuleForRouter(targetSw, routerIpPrefix, destSw, nextHops);
sanghob35a6192015-04-01 13:05:26 -0700469 if (!result) {
470 return false;
471 }
472
sangho52abe3a2015-05-05 14:13:34 -0700473 // If the target switch is an edge router, then set IP rules for the router IP.
sangho666cd6d2015-04-14 16:27:13 -0700474 } else if (config.isEdgeDevice(targetSw)) {
475 Ip4Address routerIp = config.getRouterIp(destSw);
476 IpPrefix routerIpPrefix = IpPrefix.valueOf(routerIp, IpPrefix.MAX_INET_MASK_LENGTH);
Saurav Dasa07f2032015-10-19 14:37:36 -0700477 log.debug("* populateEcmpRoutingRulePartial in device {} towards {} for router IP {}",
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700478 targetSw, destSw, routerIpPrefix);
sangho666cd6d2015-04-14 16:27:13 -0700479 result = rulePopulator.populateIpRuleForRouter(targetSw, routerIpPrefix, destSw, nextHops);
sanghob35a6192015-04-01 13:05:26 -0700480 if (!result) {
481 return false;
482 }
sangho52abe3a2015-05-05 14:13:34 -0700483 }
sanghob35a6192015-04-01 13:05:26 -0700484
sangho52abe3a2015-05-05 14:13:34 -0700485 // Populates MPLS rules to all routers
Saurav Dasa07f2032015-10-19 14:37:36 -0700486 log.debug("* populateEcmpRoutingRulePartial in device{} towards {} for all MPLS rules",
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700487 targetSw, destSw);
sangho52abe3a2015-05-05 14:13:34 -0700488 result = rulePopulator.populateMplsRule(targetSw, destSw, nextHops);
489 if (!result) {
490 return false;
sanghob35a6192015-04-01 13:05:26 -0700491 }
492
493 return true;
494 }
495
496 /**
Saurav Das822c4e22015-10-23 10:51:11 -0700497 * Populates filtering rules for permitting Router DstMac and VLAN.
sanghob35a6192015-04-01 13:05:26 -0700498 *
499 * @param deviceId Switch ID to set the rules
500 */
Saurav Das822c4e22015-10-23 10:51:11 -0700501 public void populatePortAddressingRules(DeviceId deviceId) {
502 rulePopulator.populateRouterMacVlanFilters(deviceId);
503 rulePopulator.populateRouterIpPunts(deviceId);
sanghob35a6192015-04-01 13:05:26 -0700504 }
505
506 /**
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700507 * Start the flow rule population process if it was never started. The
508 * process finishes successfully when all flow rules are set and stops with
509 * ABORTED status when any groups required for flows is not set yet.
sanghob35a6192015-04-01 13:05:26 -0700510 */
511 public void startPopulationProcess() {
HIGUCHI Yuta84a25fc2015-09-08 16:16:31 +0900512 statusLock.lock();
513 try {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700514 if (populationStatus == Status.IDLE
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700515 || populationStatus == Status.SUCCEEDED
516 || populationStatus == Status.ABORTED) {
sanghob35a6192015-04-01 13:05:26 -0700517 populationStatus = Status.STARTED;
518 populateAllRoutingRules();
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700519 } else {
520 log.warn("Not initiating startPopulationProcess as populationStatus is {}",
521 populationStatus);
sanghob35a6192015-04-01 13:05:26 -0700522 }
HIGUCHI Yuta84a25fc2015-09-08 16:16:31 +0900523 } finally {
524 statusLock.unlock();
sanghob35a6192015-04-01 13:05:26 -0700525 }
526 }
527
528 /**
529 * Resume the flow rule population process if it was aborted for any reason.
530 * Mostly the process is aborted when the groups required are not set yet.
Saurav Dasa07f2032015-10-19 14:37:36 -0700531 * XXX is this called?
532 *
sanghob35a6192015-04-01 13:05:26 -0700533 */
534 public void resumePopulationProcess() {
HIGUCHI Yuta84a25fc2015-09-08 16:16:31 +0900535 statusLock.lock();
536 try {
sanghob35a6192015-04-01 13:05:26 -0700537 if (populationStatus == Status.ABORTED) {
538 populationStatus = Status.STARTED;
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700539 // TODO: we need to restart from the point aborted instead of
540 // restarting.
sanghob35a6192015-04-01 13:05:26 -0700541 populateAllRoutingRules();
542 }
HIGUCHI Yuta84a25fc2015-09-08 16:16:31 +0900543 } finally {
544 statusLock.unlock();
sanghob35a6192015-04-01 13:05:26 -0700545 }
546 }
547}