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