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