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