blob: 40ee55fceaf3b2cda814e2bf8559a7b399f779d2 [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.onosproject.net.MastershipRole;
sanghob35a6192015-04-01 13:05:26 -070027import org.slf4j.Logger;
28import org.slf4j.LoggerFactory;
29
30import java.util.ArrayList;
31import java.util.HashMap;
32import java.util.HashSet;
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -070033import java.util.List;
sanghob35a6192015-04-01 13:05:26 -070034import 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
40public class DefaultRoutingHandler {
41
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070042 private static Logger log = LoggerFactory
43 .getLogger(DefaultRoutingHandler.class);
sanghob35a6192015-04-01 13:05:26 -070044
45 private SegmentRoutingManager srManager;
46 private RoutingRulePopulator rulePopulator;
sangho20eff1d2015-04-13 15:15:58 -070047 private HashMap<DeviceId, ECMPShortestPathGraph> currentEcmpSpgMap;
sangho45b009c2015-05-07 13:30:57 -070048 private HashMap<DeviceId, ECMPShortestPathGraph> updatedEcmpSpgMap;
sangho666cd6d2015-04-14 16:27:13 -070049 private DeviceConfiguration config;
HIGUCHI Yuta84a25fc2015-09-08 16:16:31 +090050 private final Lock statusLock = new ReentrantLock();
51 private volatile Status populationStatus;
sanghob35a6192015-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 Vavilapallif5b234a2015-04-21 13:04:13 -070063 // population process was aborted due to errors, mostly for groups not
64 // found.
sanghob35a6192015-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);
sangho666cd6d2015-04-14 16:27:13 -070079 this.config = checkNotNull(srManager.deviceConfiguration);
sanghob35a6192015-04-01 13:05:26 -070080 this.populationStatus = Status.IDLE;
sangho20eff1d2015-04-13 15:15:58 -070081 this.currentEcmpSpgMap = Maps.newHashMap();
sanghob35a6192015-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 Yuta84a25fc2015-09-08 16:16:31 +090092 statusLock.lock();
93 try {
94 populationStatus = Status.STARTED;
95 rulePopulator.resetCounter();
Saurav Dasa07f2032015-10-19 14:37:36 -070096 log.info("Starting to populate segment-routing rules");
HIGUCHI Yuta84a25fc2015-09-08 16:16:31 +090097 log.debug("populateAllRoutingRules: populationStatus is STARTED");
sanghob35a6192015-04-01 13:05:26 -070098
HIGUCHI Yuta84a25fc2015-09-08 16:16:31 +090099 for (Device sw : srManager.deviceService.getDevices()) {
100 if (srManager.mastershipService.getLocalRole(sw.id()) != MastershipRole.MASTER) {
101 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
sanghob35a6192015-04-01 13:05:26 -0700116 }
117
HIGUCHI Yuta84a25fc2015-09-08 16:16:31 +0900118 log.debug("populateAllRoutingRules: populationStatus is SUCCEEDED");
119 populationStatus = Status.SUCCEEDED;
Saurav Dasa07f2032015-10-19 14:37:36 -0700120 log.info("Completed routing rule population. Total # of rules pushed : {}",
HIGUCHI Yuta84a25fc2015-09-08 16:16:31 +0900121 rulePopulator.getCounter());
122 return true;
123 } finally {
124 statusLock.unlock();
sanghob35a6192015-04-01 13:05:26 -0700125 }
sanghob35a6192015-04-01 13:05:26 -0700126 }
127
sangho20eff1d2015-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 Yuta84a25fc2015-09-08 16:16:31 +0900138 statusLock.lock();
139 try {
sangho20eff1d2015-04-13 15:15:58 -0700140
141 if (populationStatus == Status.STARTED) {
sangho52abe3a2015-05-05 14:13:34 -0700142 log.warn("Previous rule population is not finished.");
sangho20eff1d2015-04-13 15:15:58 -0700143 return true;
144 }
145
sangho45b009c2015-05-07 13:30:57 -0700146 // Take the snapshots of the links
147 updatedEcmpSpgMap = new HashMap<>();
148 for (Device sw : srManager.deviceService.getDevices()) {
149 if (srManager.mastershipService.
150 getLocalRole(sw.id()) != MastershipRole.MASTER) {
151 continue;
152 }
153 ECMPShortestPathGraph ecmpSpgUpdated =
154 new ECMPShortestPathGraph(sw.id(), srManager);
155 updatedEcmpSpgMap.put(sw.id(), ecmpSpgUpdated);
156 }
157
sangho52abe3a2015-05-05 14:13:34 -0700158 log.info("Starts rule population from link change");
159
sangho20eff1d2015-04-13 15:15:58 -0700160 Set<ArrayList<DeviceId>> routeChanges;
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700161 log.trace("populateRoutingRulesForLinkStatusChange: "
162 + "populationStatus is STARTED");
sangho20eff1d2015-04-13 15:15:58 -0700163 populationStatus = Status.STARTED;
164 if (linkFail == null) {
165 // Compare all routes of existing ECMP SPG with the new ones
166 routeChanges = computeRouteChange();
167 } else {
168 // Compare existing ECMP SPG only with the link removed
169 routeChanges = computeDamagedRoutes(linkFail);
170 }
171
172 if (routeChanges.isEmpty()) {
sangho52abe3a2015-05-05 14:13:34 -0700173 log.info("No route changes for the link status change");
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700174 log.debug("populateRoutingRulesForLinkStatusChange: populationStatus is SUCCEEDED");
sangho20eff1d2015-04-13 15:15:58 -0700175 populationStatus = Status.SUCCEEDED;
176 return true;
177 }
178
179 if (repopulateRoutingRulesForRoutes(routeChanges)) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700180 log.debug("populateRoutingRulesForLinkStatusChange: populationStatus is SUCCEEDED");
sangho20eff1d2015-04-13 15:15:58 -0700181 populationStatus = Status.SUCCEEDED;
182 log.info("Complete to repopulate the rules. # of rules populated : {}",
183 rulePopulator.getCounter());
184 return true;
185 } else {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700186 log.debug("populateRoutingRulesForLinkStatusChange: populationStatus is ABORTED");
sangho20eff1d2015-04-13 15:15:58 -0700187 populationStatus = Status.ABORTED;
188 log.warn("Failed to repopulate the rules.");
189 return false;
190 }
HIGUCHI Yuta84a25fc2015-09-08 16:16:31 +0900191 } finally {
192 statusLock.unlock();
sangho20eff1d2015-04-13 15:15:58 -0700193 }
194 }
195
196 private boolean repopulateRoutingRulesForRoutes(Set<ArrayList<DeviceId>> routes) {
197 rulePopulator.resetCounter();
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700198 HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>> routesBydevice =
199 new HashMap<>();
sangho20eff1d2015-04-13 15:15:58 -0700200 for (ArrayList<DeviceId> link: routes) {
sangho834e4b02015-05-01 09:38:25 -0700201 // When only the source device is defined, reinstall routes to all other devices
sangho20eff1d2015-04-13 15:15:58 -0700202 if (link.size() == 1) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700203 log.trace("repopulateRoutingRulesForRoutes: running ECMP graph for device {}", link.get(0));
sangho20eff1d2015-04-13 15:15:58 -0700204 ECMPShortestPathGraph ecmpSpg = new ECMPShortestPathGraph(link.get(0), srManager);
205 if (populateEcmpRoutingRules(link.get(0), ecmpSpg)) {
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700206 log.debug("Populating flow rules from {} to all is successful",
207 link.get(0));
sangho20eff1d2015-04-13 15:15:58 -0700208 currentEcmpSpgMap.put(link.get(0), ecmpSpg);
sangho52abe3a2015-05-05 14:13:34 -0700209 } else {
sangho45b009c2015-05-07 13:30:57 -0700210 log.warn("Failed to populate the flow rules from {} to all", link.get(0));
sangho52abe3a2015-05-05 14:13:34 -0700211 return false;
sangho20eff1d2015-04-13 15:15:58 -0700212 }
sangho45b009c2015-05-07 13:30:57 -0700213 } else {
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700214 ArrayList<ArrayList<DeviceId>> deviceRoutes =
215 routesBydevice.get(link.get(1));
216 if (deviceRoutes == null) {
217 deviceRoutes = new ArrayList<>();
218 routesBydevice.put(link.get(1), deviceRoutes);
219 }
220 deviceRoutes.add(link);
221 }
222 }
223
224 for (DeviceId impactedDevice : routesBydevice.keySet()) {
225 ArrayList<ArrayList<DeviceId>> deviceRoutes =
226 routesBydevice.get(impactedDevice);
227 for (ArrayList<DeviceId> link: deviceRoutes) {
228 log.debug("repopulate RoutingRules For Routes {} -> {}",
229 link.get(0), link.get(1));
sangho45b009c2015-05-07 13:30:57 -0700230 DeviceId src = link.get(0);
231 DeviceId dst = link.get(1);
sangho45b009c2015-05-07 13:30:57 -0700232 ECMPShortestPathGraph ecmpSpg = updatedEcmpSpgMap.get(dst);
233 HashMap<Integer, HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>>> switchVia =
234 ecmpSpg.getAllLearnedSwitchesAndVia();
235 for (Integer itrIdx : switchVia.keySet()) {
236 HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>> swViaMap =
237 switchVia.get(itrIdx);
238 for (DeviceId targetSw : swViaMap.keySet()) {
239 if (!targetSw.equals(src)) {
240 continue;
241 }
242 Set<DeviceId> nextHops = new HashSet<>();
243 for (ArrayList<DeviceId> via : swViaMap.get(targetSw)) {
244 if (via.isEmpty()) {
245 nextHops.add(dst);
246 } else {
247 nextHops.add(via.get(0));
248 }
249 }
250 if (!populateEcmpRoutingRulePartial(targetSw, dst, nextHops)) {
251 return false;
sangho20eff1d2015-04-13 15:15:58 -0700252 }
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700253 log.debug("Populating flow rules from {} to {} is successful",
254 targetSw, dst);
sangho20eff1d2015-04-13 15:15:58 -0700255 }
sangho20eff1d2015-04-13 15:15:58 -0700256 }
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700257 //currentEcmpSpgMap.put(dst, ecmpSpg);
sangho20eff1d2015-04-13 15:15:58 -0700258 }
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700259 //Only if all the flows for all impacted routes to a
260 //specific target are pushed successfully, update the
261 //ECMP graph for that target. (Or else the next event
262 //would not see any changes in the ECMP graphs)
263 currentEcmpSpgMap.put(impactedDevice,
264 updatedEcmpSpgMap.get(impactedDevice));
sangho20eff1d2015-04-13 15:15:58 -0700265 }
266 return true;
267 }
268
269 private Set<ArrayList<DeviceId>> computeDamagedRoutes(Link linkFail) {
270
271 Set<ArrayList<DeviceId>> routes = new HashSet<>();
272
273 for (Device sw : srManager.deviceService.getDevices()) {
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700274 log.debug("Computing the impacted routes for device {} due to link fail",
275 sw.id());
sangho20eff1d2015-04-13 15:15:58 -0700276 if (srManager.mastershipService.
277 getLocalRole(sw.id()) != MastershipRole.MASTER) {
278 continue;
279 }
280 ECMPShortestPathGraph ecmpSpg = currentEcmpSpgMap.get(sw.id());
281 if (ecmpSpg == null) {
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700282 log.error("No existing ECMP graph for switch {}", sw.id());
sangho20eff1d2015-04-13 15:15:58 -0700283 continue;
284 }
285 HashMap<Integer, HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>>> switchVia =
286 ecmpSpg.getAllLearnedSwitchesAndVia();
287 for (Integer itrIdx : switchVia.keySet()) {
288 HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>> swViaMap =
289 switchVia.get(itrIdx);
290 for (DeviceId targetSw : swViaMap.keySet()) {
291 DeviceId destSw = sw.id();
292 Set<ArrayList<DeviceId>> subLinks =
293 computeLinks(targetSw, destSw, swViaMap);
294 for (ArrayList<DeviceId> alink: subLinks) {
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700295 if ((alink.get(0).equals(linkFail.src().deviceId()) &&
296 alink.get(1).equals(linkFail.dst().deviceId()))
297 ||
298 (alink.get(0).equals(linkFail.dst().deviceId()) &&
299 alink.get(1).equals(linkFail.src().deviceId()))) {
300 log.debug("Impacted route:{}->{}", targetSw, destSw);
sangho20eff1d2015-04-13 15:15:58 -0700301 ArrayList<DeviceId> aRoute = new ArrayList<>();
302 aRoute.add(targetSw);
303 aRoute.add(destSw);
304 routes.add(aRoute);
305 break;
306 }
307 }
308 }
309 }
sangho45b009c2015-05-07 13:30:57 -0700310
sangho20eff1d2015-04-13 15:15:58 -0700311 }
312
313 return routes;
314 }
315
316 private Set<ArrayList<DeviceId>> computeRouteChange() {
317
318 Set<ArrayList<DeviceId>> routes = new HashSet<>();
319
320 for (Device sw : srManager.deviceService.getDevices()) {
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700321 log.debug("Computing the impacted routes for device {}",
322 sw.id());
sangho20eff1d2015-04-13 15:15:58 -0700323 if (srManager.mastershipService.
324 getLocalRole(sw.id()) != MastershipRole.MASTER) {
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700325 log.debug("No mastership for {} and skip route optimization",
326 sw.id());
sangho20eff1d2015-04-13 15:15:58 -0700327 continue;
328 }
sangho45b009c2015-05-07 13:30:57 -0700329
330 log.trace("link of {} - ", sw.id());
331 for (Link link: srManager.linkService.getDeviceLinks(sw.id())) {
332 log.trace("{} -> {} ", link.src().deviceId(), link.dst().deviceId());
333 }
334
335 log.debug("Checking route change for switch {}", sw.id());
sangho20eff1d2015-04-13 15:15:58 -0700336 ECMPShortestPathGraph ecmpSpg = currentEcmpSpgMap.get(sw.id());
337 if (ecmpSpg == null) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700338 log.debug("No existing ECMP graph for device {}", sw.id());
sangho20eff1d2015-04-13 15:15:58 -0700339 ArrayList<DeviceId> route = new ArrayList<>();
340 route.add(sw.id());
341 routes.add(route);
342 continue;
343 }
sangho45b009c2015-05-07 13:30:57 -0700344 ECMPShortestPathGraph newEcmpSpg = updatedEcmpSpgMap.get(sw.id());
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700345 //currentEcmpSpgMap.put(sw.id(), newEcmpSpg);
sangho20eff1d2015-04-13 15:15:58 -0700346 HashMap<Integer, HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>>> switchVia =
347 ecmpSpg.getAllLearnedSwitchesAndVia();
348 HashMap<Integer, HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>>> switchViaUpdated =
349 newEcmpSpg.getAllLearnedSwitchesAndVia();
350
sangho45b009c2015-05-07 13:30:57 -0700351 for (Integer itrIdx : switchViaUpdated.keySet()) {
352 HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>> swViaMapUpdated =
353 switchViaUpdated.get(itrIdx);
354 for (DeviceId srcSw : swViaMapUpdated.keySet()) {
355 ArrayList<ArrayList<DeviceId>> viaUpdated = swViaMapUpdated.get(srcSw);
356 ArrayList<ArrayList<DeviceId>> via = getVia(switchVia, srcSw);
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700357 if ((via == null) || !viaUpdated.equals(via)) {
358 log.debug("Impacted route:{}->{}", srcSw, sw.id());
sangho20eff1d2015-04-13 15:15:58 -0700359 ArrayList<DeviceId> route = new ArrayList<>();
360 route.add(srcSw);
361 route.add(sw.id());
362 routes.add(route);
363 }
364 }
365 }
sangho45b009c2015-05-07 13:30:57 -0700366 }
sangho20eff1d2015-04-13 15:15:58 -0700367
sangho45b009c2015-05-07 13:30:57 -0700368 for (ArrayList<DeviceId> link: routes) {
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700369 log.trace("Route changes - ");
sangho45b009c2015-05-07 13:30:57 -0700370 if (link.size() == 1) {
371 log.trace(" : {} - all", link.get(0));
372 } else {
373 log.trace(" : {} - {}", link.get(0), link.get(1));
374 }
sangho20eff1d2015-04-13 15:15:58 -0700375 }
376
377 return routes;
378 }
379
380 private ArrayList<ArrayList<DeviceId>> getVia(HashMap<Integer, HashMap<DeviceId,
381 ArrayList<ArrayList<DeviceId>>>> switchVia, DeviceId srcSw) {
382 for (Integer itrIdx : switchVia.keySet()) {
383 HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>> swViaMap =
384 switchVia.get(itrIdx);
385 if (swViaMap.get(srcSw) == null) {
386 continue;
387 } else {
388 return swViaMap.get(srcSw);
389 }
390 }
391
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700392 return null;
sangho20eff1d2015-04-13 15:15:58 -0700393 }
394
395 private Set<ArrayList<DeviceId>> computeLinks(DeviceId src,
396 DeviceId dst,
397 HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>> viaMap) {
398 Set<ArrayList<DeviceId>> subLinks = Sets.newHashSet();
399 for (ArrayList<DeviceId> via : viaMap.get(src)) {
400 DeviceId linkSrc = src;
401 DeviceId linkDst = dst;
402 for (DeviceId viaDevice: via) {
403 ArrayList<DeviceId> link = new ArrayList<>();
404 linkDst = viaDevice;
405 link.add(linkSrc);
406 link.add(linkDst);
407 subLinks.add(link);
408 linkSrc = viaDevice;
409 }
410 ArrayList<DeviceId> link = new ArrayList<>();
411 link.add(linkSrc);
412 link.add(dst);
413 subLinks.add(link);
414 }
415
416 return subLinks;
417 }
418
419 private boolean populateEcmpRoutingRules(DeviceId destSw,
sanghob35a6192015-04-01 13:05:26 -0700420 ECMPShortestPathGraph ecmpSPG) {
421
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700422 HashMap<Integer, HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>>> switchVia = ecmpSPG
423 .getAllLearnedSwitchesAndVia();
sanghob35a6192015-04-01 13:05:26 -0700424 for (Integer itrIdx : switchVia.keySet()) {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700425 HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>> swViaMap = switchVia
426 .get(itrIdx);
sanghob35a6192015-04-01 13:05:26 -0700427 for (DeviceId targetSw : swViaMap.keySet()) {
sanghob35a6192015-04-01 13:05:26 -0700428 Set<DeviceId> nextHops = new HashSet<>();
Saurav Dasa07f2032015-10-19 14:37:36 -0700429 log.debug("** Iter: {} root: {} target: {}", itrIdx, destSw, targetSw);
sanghob35a6192015-04-01 13:05:26 -0700430 for (ArrayList<DeviceId> via : swViaMap.get(targetSw)) {
431 if (via.isEmpty()) {
432 nextHops.add(destSw);
433 } else {
434 nextHops.add(via.get(0));
435 }
436 }
437 if (!populateEcmpRoutingRulePartial(targetSw, destSw, nextHops)) {
438 return false;
439 }
440 }
441 }
442
443 return true;
444 }
445
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700446 private boolean populateEcmpRoutingRulePartial(DeviceId targetSw,
447 DeviceId destSw,
448 Set<DeviceId> nextHops) {
sanghob35a6192015-04-01 13:05:26 -0700449 boolean result;
450
451 if (nextHops.isEmpty()) {
452 nextHops.add(destSw);
453 }
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.
sangho666cd6d2015-04-14 16:27:13 -0700457 if (config.isEdgeDevice(targetSw) && config.isEdgeDevice(destSw)) {
458 List<Ip4Prefix> subnets = config.getSubnets(destSw);
Saurav Dasa07f2032015-10-19 14:37:36 -0700459 log.debug("* populateEcmpRoutingRulePartial in device {} towards {} for subnets {}",
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700460 targetSw, destSw, subnets);
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700461 result = rulePopulator.populateIpRuleForSubnet(targetSw,
462 subnets,
463 destSw,
464 nextHops);
sanghob35a6192015-04-01 13:05:26 -0700465 if (!result) {
466 return false;
467 }
468
sangho666cd6d2015-04-14 16:27:13 -0700469 Ip4Address routerIp = config.getRouterIp(destSw);
470 IpPrefix routerIpPrefix = IpPrefix.valueOf(routerIp, IpPrefix.MAX_INET_MASK_LENGTH);
Saurav Dasa07f2032015-10-19 14:37:36 -0700471 log.debug("* populateEcmpRoutingRulePartial in device {} towards {} for router IP {}",
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700472 targetSw, destSw, routerIpPrefix);
sangho666cd6d2015-04-14 16:27:13 -0700473 result = rulePopulator.populateIpRuleForRouter(targetSw, routerIpPrefix, destSw, nextHops);
sanghob35a6192015-04-01 13:05:26 -0700474 if (!result) {
475 return false;
476 }
477
sangho52abe3a2015-05-05 14:13:34 -0700478 // If the target switch is an edge router, then set IP rules for the router IP.
sangho666cd6d2015-04-14 16:27:13 -0700479 } else if (config.isEdgeDevice(targetSw)) {
480 Ip4Address routerIp = config.getRouterIp(destSw);
481 IpPrefix routerIpPrefix = IpPrefix.valueOf(routerIp, IpPrefix.MAX_INET_MASK_LENGTH);
Saurav Dasa07f2032015-10-19 14:37:36 -0700482 log.debug("* populateEcmpRoutingRulePartial in device {} towards {} for router IP {}",
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700483 targetSw, destSw, routerIpPrefix);
sangho666cd6d2015-04-14 16:27:13 -0700484 result = rulePopulator.populateIpRuleForRouter(targetSw, routerIpPrefix, destSw, nextHops);
sanghob35a6192015-04-01 13:05:26 -0700485 if (!result) {
486 return false;
487 }
sangho52abe3a2015-05-05 14:13:34 -0700488 }
sanghob35a6192015-04-01 13:05:26 -0700489
sangho52abe3a2015-05-05 14:13:34 -0700490 // Populates MPLS rules to all routers
Saurav Dasa07f2032015-10-19 14:37:36 -0700491 log.debug("* populateEcmpRoutingRulePartial in device{} towards {} for all MPLS rules",
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700492 targetSw, destSw);
sangho52abe3a2015-05-05 14:13:34 -0700493 result = rulePopulator.populateMplsRule(targetSw, destSw, nextHops);
494 if (!result) {
495 return false;
sanghob35a6192015-04-01 13:05:26 -0700496 }
497
498 return true;
499 }
500
501 /**
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700502 * Populates table miss entries for all tables, and pipeline rules for VLAN
Saurav Dasa07f2032015-10-19 14:37:36 -0700503 * and TCAM tables. XXX rename/rethink
sanghob35a6192015-04-01 13:05:26 -0700504 *
505 * @param deviceId Switch ID to set the rules
506 */
507 public void populateTtpRules(DeviceId deviceId) {
sanghob35a6192015-04-01 13:05:26 -0700508 rulePopulator.populateTableVlan(deviceId);
509 rulePopulator.populateTableTMac(deviceId);
510 }
511
512 /**
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700513 * Start the flow rule population process if it was never started. The
514 * process finishes successfully when all flow rules are set and stops with
515 * ABORTED status when any groups required for flows is not set yet.
sanghob35a6192015-04-01 13:05:26 -0700516 */
517 public void startPopulationProcess() {
HIGUCHI Yuta84a25fc2015-09-08 16:16:31 +0900518 statusLock.lock();
519 try {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700520 if (populationStatus == Status.IDLE
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700521 || populationStatus == Status.SUCCEEDED
522 || populationStatus == Status.ABORTED) {
sanghob35a6192015-04-01 13:05:26 -0700523 populationStatus = Status.STARTED;
524 populateAllRoutingRules();
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700525 } else {
526 log.warn("Not initiating startPopulationProcess as populationStatus is {}",
527 populationStatus);
sanghob35a6192015-04-01 13:05:26 -0700528 }
HIGUCHI Yuta84a25fc2015-09-08 16:16:31 +0900529 } finally {
530 statusLock.unlock();
sanghob35a6192015-04-01 13:05:26 -0700531 }
532 }
533
534 /**
535 * Resume the flow rule population process if it was aborted for any reason.
536 * Mostly the process is aborted when the groups required are not set yet.
Saurav Dasa07f2032015-10-19 14:37:36 -0700537 * XXX is this called?
538 *
sanghob35a6192015-04-01 13:05:26 -0700539 */
540 public void resumePopulationProcess() {
HIGUCHI Yuta84a25fc2015-09-08 16:16:31 +0900541 statusLock.lock();
542 try {
sanghob35a6192015-04-01 13:05:26 -0700543 if (populationStatus == Status.ABORTED) {
544 populationStatus = Status.STARTED;
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700545 // TODO: we need to restart from the point aborted instead of
546 // restarting.
sanghob35a6192015-04-01 13:05:26 -0700547 populateAllRoutingRules();
548 }
HIGUCHI Yuta84a25fc2015-09-08 16:16:31 +0900549 } finally {
550 statusLock.unlock();
sanghob35a6192015-04-01 13:05:26 -0700551 }
552 }
553}