blob: 58d3262a9a0b8adee3e486fa3ebae4c393acae32 [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
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -070018import org.onlab.packet.Ip4Prefix;
sanghob35a6192015-04-01 13:05:26 -070019import org.onlab.packet.IpPrefix;
20import org.onosproject.net.Device;
21import org.onosproject.net.DeviceId;
22import org.onosproject.net.MastershipRole;
23import org.onosproject.net.flow.FlowRule;
24import org.slf4j.Logger;
25import org.slf4j.LoggerFactory;
26
27import java.util.ArrayList;
28import java.util.HashMap;
29import java.util.HashSet;
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -070030import java.util.List;
sanghob35a6192015-04-01 13:05:26 -070031import java.util.Set;
32
33import static com.google.common.base.Preconditions.checkNotNull;
34
35public class DefaultRoutingHandler {
36
37 private static Logger log = LoggerFactory.getLogger(DefaultRoutingHandler.class);
38
39 private SegmentRoutingManager srManager;
40 private RoutingRulePopulator rulePopulator;
41 private NetworkConfigHandler config;
42 private Status populationStatus;
43
44 /**
45 * Represents the default routing population status.
46 */
47 public enum Status {
48 // population process is not started yet.
49 IDLE,
50
51 // population process started.
52 STARTED,
53
54 // population process was aborted due to errors, mostly for groups not found.
55 ABORTED,
56
57 // population process was finished successfully.
58 SUCCEEDED
59 }
60
61 /**
62 * Creates a DefaultRoutingHandler object.
63 *
64 * @param srManager SegmentRoutingManager object
65 */
66 public DefaultRoutingHandler(SegmentRoutingManager srManager) {
67 this.srManager = srManager;
68 this.rulePopulator = checkNotNull(srManager.routingRulePopulator);
69 this.config = checkNotNull(srManager.networkConfigHandler);
70 this.populationStatus = Status.IDLE;
71 }
72
73 /**
74 * Populates all routing rules to all connected routers, including default
75 * routing rules, adjacency rules, and policy rules if any.
76 *
77 * @return true if it succeeds in populating all rules, otherwise false
78 */
79 public boolean populateAllRoutingRules() {
80
81 populationStatus = Status.STARTED;
82 log.info("Starts to populate routing rules");
83
84 for (Device sw : srManager.deviceService.getDevices()) {
85 if (srManager.mastershipService.
86 getLocalRole(sw.id()) != MastershipRole.MASTER) {
87 continue;
88 }
89
90 ECMPShortestPathGraph ecmpSPG = new ECMPShortestPathGraph(sw.id(), srManager);
91 if (!populateEcmpRoutingRules(sw, ecmpSPG)) {
92 populationStatus = Status.ABORTED;
93 log.debug("Abort routing rule population");
94 return false;
95 }
96
97 // TODO: Set adjacency routing rule for all switches
98 }
99
100 populationStatus = Status.SUCCEEDED;
101 log.info("Completes routing rule population");
102 return true;
103 }
104
105 private boolean populateEcmpRoutingRules(Device sw,
106 ECMPShortestPathGraph ecmpSPG) {
107
108 HashMap<Integer, HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>>> switchVia =
109 ecmpSPG.getAllLearnedSwitchesAndVia();
110 for (Integer itrIdx : switchVia.keySet()) {
111 HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>> swViaMap =
112 switchVia.get(itrIdx);
113 for (DeviceId targetSw : swViaMap.keySet()) {
114 DeviceId destSw = sw.id();
115 Set<DeviceId> nextHops = new HashSet<>();
116
117 for (ArrayList<DeviceId> via : swViaMap.get(targetSw)) {
118 if (via.isEmpty()) {
119 nextHops.add(destSw);
120 } else {
121 nextHops.add(via.get(0));
122 }
123 }
124 if (!populateEcmpRoutingRulePartial(targetSw, destSw, nextHops)) {
125 return false;
126 }
127 }
128 }
129
130 return true;
131 }
132
133 private boolean populateEcmpRoutingRulePartial(DeviceId targetSw, DeviceId destSw,
134 Set<DeviceId> nextHops) {
135 boolean result;
136
137 if (nextHops.isEmpty()) {
138 nextHops.add(destSw);
139 }
140
141 // If both target switch and dest switch are edge routers, then set IP rule
142 // for both subnet and router IP.
143 if (config.isEdgeRouter(targetSw) && config.isEdgeRouter(destSw)) {
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700144 List<Ip4Prefix> subnets = config.getSubnetInfo(destSw);
145 result = rulePopulator.populateIpRuleForSubnet(targetSw,
146 subnets,
147 destSw,
148 nextHops);
sanghob35a6192015-04-01 13:05:26 -0700149 if (!result) {
150 return false;
151 }
152
153 IpPrefix routerIp = config.getRouterIpAddress(destSw);
154 result = rulePopulator.populateIpRuleForRouter(targetSw, routerIp, destSw, nextHops);
155 if (!result) {
156 return false;
157 }
158
159 // If the target switch is an edge router, then set IP rules for the router IP.
160 } else if (config.isEdgeRouter(targetSw)) {
161 IpPrefix routerIp = config.getRouterIpAddress(destSw);
162 result = rulePopulator.populateIpRuleForRouter(targetSw, routerIp, destSw, nextHops);
163 if (!result) {
164 return false;
165 }
166
167 // If the target switch is an transit router, then set MPLS rules only.
168 } else if (config.isTransitRouter(targetSw)) {
169 result = rulePopulator.populateMplsRule(targetSw, destSw, nextHops);
170 if (!result) {
171 return false;
172 }
173 } else {
174 log.warn("The switch {} is neither an edge router nor a transit router.", targetSw);
175 return false;
176 }
177
178 return true;
179 }
180
181 /**
182 * Populates table miss entries for all tables, and pipeline rules for
183 * VLAN and TACM tables.
184 *
185 * @param deviceId Switch ID to set the rules
186 */
187 public void populateTtpRules(DeviceId deviceId) {
188
189 rulePopulator.populateTableMissEntry(deviceId, FlowRule.Type.VLAN,
190 true, false, false, FlowRule.Type.DEFAULT);
191 rulePopulator.populateTableMissEntry(deviceId, FlowRule.Type.ETHER,
192 true, false, false, FlowRule.Type.DEFAULT);
193 rulePopulator.populateTableMissEntry(deviceId, FlowRule.Type.IP,
194 false, true, true, FlowRule.Type.ACL);
195 rulePopulator.populateTableMissEntry(deviceId, FlowRule.Type.MPLS,
196 false, true, true, FlowRule.Type.ACL);
197 rulePopulator.populateTableMissEntry(deviceId, FlowRule.Type.ACL,
198 false, false, false, FlowRule.Type.DEFAULT);
199
200 rulePopulator.populateTableVlan(deviceId);
201 rulePopulator.populateTableTMac(deviceId);
202 }
203
204 /**
205 * Start the flow rule population process if it was never started.
206 * The process finishes successfully when all flow rules are set and
207 * stops with ABORTED status when any groups required for flows is not
208 * set yet.
209 */
210 public void startPopulationProcess() {
211 synchronized (populationStatus) {
212 if (populationStatus == Status.IDLE ||
213 populationStatus == Status.SUCCEEDED) {
214 populationStatus = Status.STARTED;
215 populateAllRoutingRules();
216 }
217 }
218 }
219
220 /**
221 * Resume the flow rule population process if it was aborted for any reason.
222 * Mostly the process is aborted when the groups required are not set yet.
223 */
224 public void resumePopulationProcess() {
225 synchronized (populationStatus) {
226 if (populationStatus == Status.ABORTED) {
227 populationStatus = Status.STARTED;
228 // TODO: we need to restart from the point aborted instead of restarting.
229 populateAllRoutingRules();
230 }
231 }
232 }
233}