blob: e5cf69fedf8b21b3ad22224b74704694529354c4 [file] [log] [blame]
sangho80f11cb2015-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.Ethernet;
19import org.onlab.packet.Ip4Address;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070020import org.onlab.packet.Ip4Prefix;
sangho80f11cb2015-04-01 13:05:26 -070021import org.onlab.packet.IpPrefix;
22import org.onlab.packet.MacAddress;
sangho80f11cb2015-04-01 13:05:26 -070023import org.onlab.packet.MplsLabel;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070024import org.onosproject.segmentrouting.grouphandler.NeighborSet;
sangho80f11cb2015-04-01 13:05:26 -070025import org.onosproject.net.DeviceId;
26import org.onosproject.net.Link;
27import org.onosproject.net.PortNumber;
28import org.onosproject.net.flow.DefaultFlowRule;
29import org.onosproject.net.flow.DefaultTrafficSelector;
30import org.onosproject.net.flow.DefaultTrafficTreatment;
31import org.onosproject.net.flow.FlowRule;
32import org.onosproject.net.flow.TrafficSelector;
33import org.onosproject.net.flow.TrafficTreatment;
34import org.onosproject.net.group.DefaultGroupKey;
35import org.onosproject.net.group.Group;
36import org.slf4j.Logger;
37import org.slf4j.LoggerFactory;
38
39import java.util.ArrayList;
40import java.util.Collection;
41import java.util.List;
42import java.util.Set;
43
44import static com.google.common.base.Preconditions.checkNotNull;
45
46public class RoutingRulePopulator {
47
48 private static final Logger log = LoggerFactory.getLogger(RoutingRulePopulator.class);
49
50 private SegmentRoutingManager srManager;
51 private NetworkConfigHandler config;
52
53 /**
54 * Creates a RoutingRulePopulator object.
55 *
Thomas Vachuska8a075092015-04-15 18:20:08 -070056 * @param srManager segment routing manager reference
sangho80f11cb2015-04-01 13:05:26 -070057 */
58 public RoutingRulePopulator(SegmentRoutingManager srManager) {
59 this.srManager = srManager;
60 this.config = checkNotNull(srManager.networkConfigHandler);
61 }
62
63 /**
64 * Populates IP flow rules for specific hosts directly connected to the switch.
65 *
66 * @param deviceId switch ID to set the rules
67 * @param hostIp host IP address
68 * @param hostMac host MAC address
69 * @param outPort port where the host is connected
70 */
71 public void populateIpRuleForHost(DeviceId deviceId, Ip4Address hostIp,
72 MacAddress hostMac, PortNumber outPort) {
73 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
74 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
75
76 sbuilder.matchIPDst(IpPrefix.valueOf(hostIp, 32));
77 sbuilder.matchEthType(Ethernet.TYPE_IPV4);
78
79 tbuilder.setEthDst(hostMac)
80 .setEthSrc(config.getRouterMacAddress(deviceId))
81 .setOutput(outPort);
82
83 TrafficTreatment treatment = tbuilder.build();
84 TrafficSelector selector = sbuilder.build();
85
86 FlowRule f = new DefaultFlowRule(deviceId, selector, treatment, 100,
87 srManager.appId, 600, false, FlowRule.Type.IP);
88
89 srManager.flowRuleService.applyFlowRules(f);
90 log.debug("Flow rule {} is set to switch {}", f, deviceId);
91 }
92
93 /**
94 * Populates IP flow rules for the subnets of the destination router.
95 *
96 * @param deviceId switch ID to set the rules
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070097 * @param subnets subnet information
sangho80f11cb2015-04-01 13:05:26 -070098 * @param destSw destination switch ID
99 * @param nextHops next hop switch ID list
100 * @return true if all rules are set successfully, false otherwise
101 */
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700102 public boolean populateIpRuleForSubnet(DeviceId deviceId, List<Ip4Prefix> subnets,
sangho80f11cb2015-04-01 13:05:26 -0700103 DeviceId destSw, Set<DeviceId> nextHops) {
104
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700105 //List<IpPrefix> subnets = extractSubnet(subnetInfo);
sangho80f11cb2015-04-01 13:05:26 -0700106 for (IpPrefix subnet: subnets) {
107 if (!populateIpRuleForRouter(deviceId, subnet, destSw, nextHops)) {
108 return false;
109 }
110 }
111
112 return true;
113 }
114
115 /**
116 * Populates IP flow rules for the router IP address.
117 *
118 * @param deviceId device ID to set the rules
119 * @param ipPrefix the IP address of the destination router
120 * @param destSw device ID of the destination router
121 * @param nextHops next hop switch ID list
122 * @return true if all rules are set successfully, false otherwise
123 */
124 public boolean populateIpRuleForRouter(DeviceId deviceId, IpPrefix ipPrefix,
125 DeviceId destSw, Set<DeviceId> nextHops) {
126
127 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
128 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
129
130 sbuilder.matchIPDst(ipPrefix);
131 sbuilder.matchEthType(Ethernet.TYPE_IPV4);
132
133 NeighborSet ns = null;
134
135 //If the next hop is the same as the final destination, then MPLS label is not set.
136 if (nextHops.size() == 1 && nextHops.toArray()[0].equals(destSw)) {
137 tbuilder.decNwTtl();
138 ns = new NeighborSet(nextHops);
139 } else {
140 tbuilder.copyTtlOut();
141 ns = new NeighborSet(nextHops, config.getMplsId(destSw));
142 }
143
144 DefaultGroupKey groupKey = (DefaultGroupKey) srManager.getGroupKey(ns);
145 if (groupKey == null) {
146 log.warn("Group key is not found for ns {}", ns);
147 return false;
148 }
149 Group group = srManager.groupService.getGroup(deviceId, groupKey);
150 if (group != null) {
151 tbuilder.group(group.id());
152 } else {
153 log.warn("No group found for NeighborSet {} from {} to {}",
154 ns, deviceId, destSw);
155 return false;
156 }
157
158 TrafficTreatment treatment = tbuilder.build();
159 TrafficSelector selector = sbuilder.build();
160
161 FlowRule f = new DefaultFlowRule(deviceId, selector, treatment, 100,
162 srManager.appId, 600, false, FlowRule.Type.IP);
163
164 srManager.flowRuleService.applyFlowRules(f);
165 log.debug("IP flow rule {} is set to switch {}", f, deviceId);
166
167 return true;
168 }
169
170
171 /**
172 * Populates MPLS flow rules to all transit routers.
173 *
174 * @param deviceId device ID of the switch to set the rules
175 * @param destSwId destination switch device ID
176 * @param nextHops next hops switch ID list
177 * @return true if all rules are set successfully, false otherwise
178 */
179 public boolean populateMplsRule(DeviceId deviceId, DeviceId destSwId, Set<DeviceId> nextHops) {
180
181 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
182 Collection<TrafficTreatment> treatments = new ArrayList<>();
183
184 // TODO Handle the case of Bos == false
185 sbuilder.matchMplsLabel(MplsLabel.mplsLabel(config.getMplsId(destSwId)));
186 sbuilder.matchEthType(Ethernet.MPLS_UNICAST);
187
188 //If the next hop is the destination router, do PHP
189 if (nextHops.size() == 1 && destSwId.equals(nextHops.toArray()[0])) {
190 TrafficTreatment treatmentBos =
191 getMplsTreatment(deviceId, destSwId, nextHops, true, true);
192 TrafficTreatment treatment =
193 getMplsTreatment(deviceId, destSwId, nextHops, true, false);
194 if (treatmentBos != null) {
195 treatments.add(treatmentBos);
196 } else {
197 log.warn("Failed to set MPLS rules.");
198 return false;
199 }
200 } else {
201 TrafficTreatment treatmentBos =
202 getMplsTreatment(deviceId, destSwId, nextHops, false, true);
203 TrafficTreatment treatment =
204 getMplsTreatment(deviceId, destSwId, nextHops, false, false);
205
206 if (treatmentBos != null) {
207 treatments.add(treatmentBos);
208 } else {
209 log.warn("Failed to set MPLS rules.");
210 return false;
211 }
212 }
213
214 TrafficSelector selector = sbuilder.build();
215 for (TrafficTreatment treatment: treatments) {
216 FlowRule f = new DefaultFlowRule(deviceId, selector, treatment, 100,
217 srManager.appId, 600, false, FlowRule.Type.MPLS);
218 srManager.flowRuleService.applyFlowRules(f);
219 log.debug("MPLS rule {} is set to {}", f, deviceId);
220 }
221
222 return true;
223 }
224
225
226 private TrafficTreatment getMplsTreatment(DeviceId deviceId, DeviceId destSw,
227 Set<DeviceId> nextHops,
228 boolean phpRequired, boolean isBos) {
229
230 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
231
232 if (phpRequired) {
233 tbuilder.copyTtlIn();
234 if (isBos) {
235 tbuilder.popMpls(Ethernet.TYPE_IPV4)
236 .decNwTtl();
237 } else {
238 tbuilder.popMpls(Ethernet.MPLS_UNICAST)
239 .decMplsTtl();
240 }
241 } else {
242 tbuilder.decMplsTtl();
243 }
244
245 if (config.isEcmpNotSupportedInTransit(deviceId)
246 && config.isTransitRouter(deviceId)) {
247 Link link = selectOneLink(deviceId, nextHops);
248 if (link == null) {
249 log.warn("No link from {} to {}", deviceId, nextHops);
250 return null;
251 }
252 tbuilder.setEthSrc(config.getRouterMacAddress(deviceId))
253 .setEthDst(config.getRouterMacAddress(link.dst().deviceId()))
254 .setOutput(link.src().port());
255 } else {
256 NeighborSet ns = new NeighborSet(nextHops);
257 DefaultGroupKey groupKey = (DefaultGroupKey) srManager.getGroupKey(ns);
258 if (groupKey == null) {
259 log.warn("Group key is not found for ns {}", ns);
260 return null;
261 }
262 Group group = srManager.groupService.getGroup(deviceId, groupKey);
263 if (group != null) {
264 tbuilder.group(group.id());
265 } else {
266 log.warn("No group found for ns {} key {} in {}", ns,
267 srManager.getGroupKey(ns), deviceId);
268 return null;
269 }
270 }
271
272 return tbuilder.build();
273 }
274
275 /**
276 * Populates VLAN flows rules.
277 * All packets are forwarded to TMAC table.
278 *
279 * @param deviceId switch ID to set the rules
280 */
281 public void populateTableVlan(DeviceId deviceId) {
282 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
283 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
284
285 tbuilder.transition(FlowRule.Type.ETHER);
286
287 TrafficTreatment treatment = tbuilder.build();
288 TrafficSelector selector = sbuilder.build();
289
290 FlowRule f = new DefaultFlowRule(deviceId, selector, treatment, 100,
291 srManager.appId, 600, false, FlowRule.Type.VLAN);
292
293 srManager.flowRuleService.applyFlowRules(f);
294
295 log.debug("Vlan flow rule {} is set to switch {}", f, deviceId);
296 }
297
298 /**
299 * Populates TMAC table rules.
300 * IP packets are forwarded to IP table.
301 * MPLS packets are forwarded to MPLS table.
302 *
303 * @param deviceId switch ID to set the rules
304 */
305 public void populateTableTMac(DeviceId deviceId) {
306
307 // flow rule for IP packets
308 TrafficSelector selectorIp = DefaultTrafficSelector.builder()
309 .matchEthType(Ethernet.TYPE_IPV4)
310 .matchEthDst(config.getRouterMacAddress(deviceId))
311 .build();
312 TrafficTreatment treatmentIp = DefaultTrafficTreatment.builder()
313 .transition(FlowRule.Type.IP)
314 .build();
315
316 FlowRule flowIp = new DefaultFlowRule(deviceId, selectorIp, treatmentIp, 100,
317 srManager.appId, 600, false, FlowRule.Type.ETHER);
318
319 srManager.flowRuleService.applyFlowRules(flowIp);
320
321 // flow rule for MPLS packets
322 TrafficSelector selectorMpls = DefaultTrafficSelector.builder()
323 .matchEthType(Ethernet.MPLS_UNICAST)
324 .matchEthDst(config.getRouterMacAddress(deviceId))
325 .build();
326 TrafficTreatment treatmentMpls = DefaultTrafficTreatment.builder()
327 .transition(FlowRule.Type.MPLS)
328 .build();
329
330 FlowRule flowMpls = new DefaultFlowRule(deviceId, selectorMpls, treatmentMpls, 100,
331 srManager.appId, 600, false, FlowRule.Type.ETHER);
332
333 srManager.flowRuleService.applyFlowRules(flowMpls);
334
335 }
336
337 /**
338 * Populates a table miss entry.
339 *
340 * @param deviceId switch ID to set rules
341 * @param tableToAdd table to set the rules
342 * @param toControllerNow flag to send packets to controller immediately
343 * @param toControllerWrite flag to send packets to controller at the end of pipeline
344 * @param toTable flag to send packets to a specific table
345 * @param tableToSend table type to send packets when the toTable flag is set
346 */
347 public void populateTableMissEntry(DeviceId deviceId, FlowRule.Type tableToAdd, boolean toControllerNow,
348 boolean toControllerWrite,
349 boolean toTable, FlowRule.Type tableToSend) {
350 // TODO: Change arguments to EnumSet
351 TrafficSelector selector = DefaultTrafficSelector.builder()
352 .build();
353 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
354
355 if (toControllerNow) {
356 tBuilder.setOutput(PortNumber.CONTROLLER);
357 }
358
359 if (toControllerWrite) {
360 tBuilder.deferred().setOutput(PortNumber.CONTROLLER);
361 }
362
363 if (toTable) {
364 tBuilder.transition(tableToSend);
365 }
366
367 FlowRule flow = new DefaultFlowRule(deviceId, selector, tBuilder.build(), 0,
368 srManager.appId, 600, false, tableToAdd);
369
370 srManager.flowRuleService.applyFlowRules(flow);
371
372 }
373
sangho80f11cb2015-04-01 13:05:26 -0700374 private Link selectOneLink(DeviceId srcId, Set<DeviceId> destIds) {
375
376 Set<Link> links = srManager.linkService.getDeviceEgressLinks(srcId);
377 DeviceId destId = (DeviceId) destIds.toArray()[0];
378 for (Link link: links) {
379 if (link.dst().deviceId().equals(destId)) {
380 return link;
381 }
382 }
383
384 return null;
385 }
386
387}