blob: 2d2102bbb35ba53128fb4c3febcecafb16ab86b6 [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.Ethernet;
19import org.onlab.packet.Ip4Address;
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -070020import org.onlab.packet.Ip4Prefix;
sanghob35a6192015-04-01 13:05:26 -070021import org.onlab.packet.IpPrefix;
22import org.onlab.packet.MacAddress;
sanghob35a6192015-04-01 13:05:26 -070023import org.onlab.packet.MplsLabel;
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070024import org.onlab.packet.VlanId;
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -070025import org.onosproject.segmentrouting.grouphandler.NeighborSet;
sanghob35a6192015-04-01 13:05:26 -070026import org.onosproject.net.DeviceId;
27import org.onosproject.net.Link;
28import org.onosproject.net.PortNumber;
sanghob35a6192015-04-01 13:05:26 -070029import org.onosproject.net.flow.DefaultTrafficSelector;
30import org.onosproject.net.flow.DefaultTrafficTreatment;
sanghob35a6192015-04-01 13:05:26 -070031import org.onosproject.net.flow.TrafficSelector;
32import org.onosproject.net.flow.TrafficTreatment;
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070033import org.onosproject.net.flow.criteria.Criteria;
34import org.onosproject.net.flowobjective.DefaultFilteringObjective;
35import org.onosproject.net.flowobjective.DefaultForwardingObjective;
36import org.onosproject.net.flowobjective.FilteringObjective;
37import org.onosproject.net.flowobjective.ForwardingObjective;
38import org.onosproject.net.flowobjective.ForwardingObjective.Builder;
sanghob35a6192015-04-01 13:05:26 -070039import org.slf4j.Logger;
40import org.slf4j.LoggerFactory;
41
42import java.util.ArrayList;
sanghob35a6192015-04-01 13:05:26 -070043import java.util.List;
44import java.util.Set;
sangho20eff1d2015-04-13 15:15:58 -070045import java.util.concurrent.atomic.AtomicLong;
sanghob35a6192015-04-01 13:05:26 -070046
47import static com.google.common.base.Preconditions.checkNotNull;
48
49public class RoutingRulePopulator {
50
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070051 private static final Logger log = LoggerFactory
52 .getLogger(RoutingRulePopulator.class);
sanghob35a6192015-04-01 13:05:26 -070053
sangho20eff1d2015-04-13 15:15:58 -070054 private AtomicLong rulePopulationCounter;
sangho666cd6d2015-04-14 16:27:13 -070055 private SegmentRoutingManager srManager;
56 private DeviceConfiguration config;
sanghob35a6192015-04-01 13:05:26 -070057 /**
58 * Creates a RoutingRulePopulator object.
59 *
Thomas Vachuskae10f56b2015-04-15 18:20:08 -070060 * @param srManager segment routing manager reference
sanghob35a6192015-04-01 13:05:26 -070061 */
62 public RoutingRulePopulator(SegmentRoutingManager srManager) {
63 this.srManager = srManager;
sangho666cd6d2015-04-14 16:27:13 -070064 this.config = checkNotNull(srManager.deviceConfiguration);
sangho20eff1d2015-04-13 15:15:58 -070065 this.rulePopulationCounter = new AtomicLong(0);
66 }
67
68 /**
69 * Resets the population counter.
70 */
71 public void resetCounter() {
72 rulePopulationCounter.set(0);
73 }
74
75 /**
76 * Returns the number of rules populated.
77 */
78 public long getCounter() {
79 return rulePopulationCounter.get();
sanghob35a6192015-04-01 13:05:26 -070080 }
81
82 /**
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070083 * Populates IP flow rules for specific hosts directly connected to the
84 * switch.
sanghob35a6192015-04-01 13:05:26 -070085 *
86 * @param deviceId switch ID to set the rules
87 * @param hostIp host IP address
88 * @param hostMac host MAC address
89 * @param outPort port where the host is connected
90 */
91 public void populateIpRuleForHost(DeviceId deviceId, Ip4Address hostIp,
92 MacAddress hostMac, PortNumber outPort) {
93 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
94 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
95
96 sbuilder.matchIPDst(IpPrefix.valueOf(hostIp, 32));
97 sbuilder.matchEthType(Ethernet.TYPE_IPV4);
98
99 tbuilder.setEthDst(hostMac)
sangho666cd6d2015-04-14 16:27:13 -0700100 .setEthSrc(config.getDeviceMac(deviceId))
sanghob35a6192015-04-01 13:05:26 -0700101 .setOutput(outPort);
102
103 TrafficTreatment treatment = tbuilder.build();
104 TrafficSelector selector = sbuilder.build();
105
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700106 ForwardingObjective.Builder fwdBuilder = DefaultForwardingObjective
107 .builder().fromApp(srManager.appId).makePermanent()
108 .withSelector(selector).withTreatment(treatment)
109 .withPriority(100).withFlag(ForwardingObjective.Flag.SPECIFIC);
sanghob35a6192015-04-01 13:05:26 -0700110
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700111 log.debug("Installing IPv4 forwarding objective "
112 + "for host {} in switch {}", hostIp, deviceId);
113 srManager.flowObjectiveService.forward(deviceId, fwdBuilder.add());
sangho20eff1d2015-04-13 15:15:58 -0700114 rulePopulationCounter.incrementAndGet();
sanghob35a6192015-04-01 13:05:26 -0700115 }
116
117 /**
118 * Populates IP flow rules for the subnets of the destination router.
119 *
120 * @param deviceId switch ID to set the rules
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700121 * @param subnets subnet information
sanghob35a6192015-04-01 13:05:26 -0700122 * @param destSw destination switch ID
123 * @param nextHops next hop switch ID list
124 * @return true if all rules are set successfully, false otherwise
125 */
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700126 public boolean populateIpRuleForSubnet(DeviceId deviceId,
127 List<Ip4Prefix> subnets,
128 DeviceId destSw,
129 Set<DeviceId> nextHops) {
sanghob35a6192015-04-01 13:05:26 -0700130
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700131 for (IpPrefix subnet : subnets) {
sanghob35a6192015-04-01 13:05:26 -0700132 if (!populateIpRuleForRouter(deviceId, subnet, destSw, nextHops)) {
133 return false;
134 }
135 }
136
137 return true;
138 }
139
140 /**
141 * Populates IP flow rules for the router IP address.
142 *
143 * @param deviceId device ID to set the rules
144 * @param ipPrefix the IP address of the destination router
145 * @param destSw device ID of the destination router
146 * @param nextHops next hop switch ID list
147 * @return true if all rules are set successfully, false otherwise
148 */
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700149 public boolean populateIpRuleForRouter(DeviceId deviceId,
150 IpPrefix ipPrefix, DeviceId destSw,
151 Set<DeviceId> nextHops) {
sanghob35a6192015-04-01 13:05:26 -0700152
153 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
154 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
155
156 sbuilder.matchIPDst(ipPrefix);
157 sbuilder.matchEthType(Ethernet.TYPE_IPV4);
158
159 NeighborSet ns = null;
160
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700161 // If the next hop is the same as the final destination, then MPLS label
162 // is not set.
sanghob35a6192015-04-01 13:05:26 -0700163 if (nextHops.size() == 1 && nextHops.toArray()[0].equals(destSw)) {
164 tbuilder.decNwTtl();
165 ns = new NeighborSet(nextHops);
166 } else {
167 tbuilder.copyTtlOut();
sangho666cd6d2015-04-14 16:27:13 -0700168 ns = new NeighborSet(nextHops, config.getSegmentId(destSw));
sanghob35a6192015-04-01 13:05:26 -0700169 }
170
sanghob35a6192015-04-01 13:05:26 -0700171 TrafficTreatment treatment = tbuilder.build();
172 TrafficSelector selector = sbuilder.build();
173
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700174 ForwardingObjective.Builder fwdBuilder = DefaultForwardingObjective
175 .builder()
176 .fromApp(srManager.appId)
177 .makePermanent()
178 .nextStep(srManager.getNextObjectiveId(deviceId, ns))
179 .withTreatment(treatment)
180 .withSelector(selector)
181 .withPriority(100)
182 .withFlag(ForwardingObjective.Flag.SPECIFIC);
183 log.debug("Installing IPv4 forwarding objective "
184 + "for router IP/subnet {} in switch {}",
185 ipPrefix,
186 deviceId);
187 srManager.flowObjectiveService.forward(deviceId, fwdBuilder.add());
sangho20eff1d2015-04-13 15:15:58 -0700188 rulePopulationCounter.incrementAndGet();
sanghob35a6192015-04-01 13:05:26 -0700189
190 return true;
191 }
192
sanghob35a6192015-04-01 13:05:26 -0700193 /**
194 * Populates MPLS flow rules to all transit routers.
195 *
196 * @param deviceId device ID of the switch to set the rules
197 * @param destSwId destination switch device ID
198 * @param nextHops next hops switch ID list
199 * @return true if all rules are set successfully, false otherwise
200 */
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700201 public boolean populateMplsRule(DeviceId deviceId, DeviceId destSwId,
202 Set<DeviceId> nextHops) {
sanghob35a6192015-04-01 13:05:26 -0700203
204 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700205 List<ForwardingObjective.Builder> fwdObjBuilders = new ArrayList<ForwardingObjective.Builder>();
sanghob35a6192015-04-01 13:05:26 -0700206
207 // TODO Handle the case of Bos == false
sangho666cd6d2015-04-14 16:27:13 -0700208 sbuilder.matchMplsLabel(MplsLabel.mplsLabel(config.getSegmentId(destSwId)));
sanghob35a6192015-04-01 13:05:26 -0700209 sbuilder.matchEthType(Ethernet.MPLS_UNICAST);
210
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700211 // If the next hop is the destination router, do PHP
sanghob35a6192015-04-01 13:05:26 -0700212 if (nextHops.size() == 1 && destSwId.equals(nextHops.toArray()[0])) {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700213 ForwardingObjective.Builder fwdObjBosBuilder =
214 getMplsForwardingObjective(deviceId,
215 destSwId,
216 nextHops,
217 true,
218 true);
219 // TODO: Check with Sangho on why we need this
220 ForwardingObjective.Builder fwdObjNoBosBuilder =
221 getMplsForwardingObjective(deviceId,
222 destSwId,
223 nextHops,
224 true,
225 false);
226 if (fwdObjBosBuilder != null) {
227 fwdObjBuilders.add(fwdObjBosBuilder);
sanghob35a6192015-04-01 13:05:26 -0700228 } else {
229 log.warn("Failed to set MPLS rules.");
230 return false;
231 }
232 } else {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700233 ForwardingObjective.Builder fwdObjBosBuilder =
234 getMplsForwardingObjective(deviceId,
235 destSwId,
236 nextHops,
237 false,
238 true);
239 // TODO: Check with Sangho on why we need this
240 ForwardingObjective.Builder fwdObjNoBosBuilder =
241 getMplsForwardingObjective(deviceId,
242 destSwId,
243 nextHops,
244 false,
245 false);
246 if (fwdObjBosBuilder != null) {
247 fwdObjBuilders.add(fwdObjBosBuilder);
sanghob35a6192015-04-01 13:05:26 -0700248 } else {
249 log.warn("Failed to set MPLS rules.");
250 return false;
251 }
252 }
253
254 TrafficSelector selector = sbuilder.build();
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700255 for (ForwardingObjective.Builder fwdObjBuilder : fwdObjBuilders) {
256 ((Builder) ((Builder) fwdObjBuilder.fromApp(srManager.appId)
257 .makePermanent()).withSelector(selector)
258 .withPriority(100))
259 .withFlag(ForwardingObjective.Flag.SPECIFIC);
260 log.debug("Installing MPLS forwarding objective in switch {}",
261 deviceId);
262 srManager.flowObjectiveService.forward(deviceId,
263 fwdObjBuilder.add());
sangho20eff1d2015-04-13 15:15:58 -0700264 rulePopulationCounter.incrementAndGet();
sanghob35a6192015-04-01 13:05:26 -0700265 }
266
267 return true;
268 }
269
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700270 private ForwardingObjective.Builder getMplsForwardingObjective(DeviceId deviceId,
271 DeviceId destSw,
272 Set<DeviceId> nextHops,
273 boolean phpRequired,
274 boolean isBos) {
sanghob35a6192015-04-01 13:05:26 -0700275
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700276 ForwardingObjective.Builder fwdBuilder = DefaultForwardingObjective
277 .builder().withFlag(ForwardingObjective.Flag.SPECIFIC);
sanghob35a6192015-04-01 13:05:26 -0700278
279 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
280
281 if (phpRequired) {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700282 log.debug("getMplsForwardingObjective: php required");
sanghob35a6192015-04-01 13:05:26 -0700283 tbuilder.copyTtlIn();
284 if (isBos) {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700285 tbuilder.popMpls(Ethernet.TYPE_IPV4).decNwTtl();
sanghob35a6192015-04-01 13:05:26 -0700286 } else {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700287 tbuilder.popMpls(Ethernet.MPLS_UNICAST).decMplsTtl();
sanghob35a6192015-04-01 13:05:26 -0700288 }
289 } else {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700290 log.debug("getMplsForwardingObjective: php not required");
sanghob35a6192015-04-01 13:05:26 -0700291 tbuilder.decMplsTtl();
292 }
293
sangho666cd6d2015-04-14 16:27:13 -0700294 if (!isECMPSupportedInTransitRouter() && !config.isEdgeDevice(deviceId)) {
sanghob35a6192015-04-01 13:05:26 -0700295 Link link = selectOneLink(deviceId, nextHops);
sangho666cd6d2015-04-14 16:27:13 -0700296 DeviceId nextHop = (DeviceId) nextHops.toArray()[0];
sanghob35a6192015-04-01 13:05:26 -0700297 if (link == null) {
298 log.warn("No link from {} to {}", deviceId, nextHops);
299 return null;
300 }
sangho666cd6d2015-04-14 16:27:13 -0700301 tbuilder.setEthSrc(config.getDeviceMac(deviceId))
302 .setEthDst(config.getDeviceMac(nextHop))
sanghob35a6192015-04-01 13:05:26 -0700303 .setOutput(link.src().port());
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700304 fwdBuilder.withTreatment(tbuilder.build());
sanghob35a6192015-04-01 13:05:26 -0700305 } else {
306 NeighborSet ns = new NeighborSet(nextHops);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700307 fwdBuilder.nextStep(srManager
308 .getNextObjectiveId(deviceId, ns));
sanghob35a6192015-04-01 13:05:26 -0700309 }
310
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700311 return fwdBuilder;
sanghob35a6192015-04-01 13:05:26 -0700312 }
313
sangho666cd6d2015-04-14 16:27:13 -0700314 private boolean isECMPSupportedInTransitRouter() {
315
316 // TODO: remove this function when objectives subsystem is supported.
317 return false;
318 }
319
sanghob35a6192015-04-01 13:05:26 -0700320 /**
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700321 * Populates VLAN flows rules. All packets are forwarded to TMAC table.
sanghob35a6192015-04-01 13:05:26 -0700322 *
323 * @param deviceId switch ID to set the rules
324 */
325 public void populateTableVlan(DeviceId deviceId) {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700326 FilteringObjective.Builder fob = DefaultFilteringObjective.builder();
327 fob.withKey(Criteria.matchInPort(PortNumber.ALL))
328 .addCondition(Criteria.matchVlanId(VlanId.NONE));
329 fob.permit().fromApp(srManager.appId);
330 log.debug("populateTableVlan: Installing filtering objective for untagged packets");
331 srManager.flowObjectiveService.filter(deviceId, fob.add());
sanghob35a6192015-04-01 13:05:26 -0700332 }
333
334 /**
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700335 * Populates TMAC table rules. IP packets are forwarded to IP table. MPLS
336 * packets are forwarded to MPLS table.
sanghob35a6192015-04-01 13:05:26 -0700337 *
338 * @param deviceId switch ID to set the rules
339 */
340 public void populateTableTMac(DeviceId deviceId) {
341
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700342 FilteringObjective.Builder fob = DefaultFilteringObjective.builder();
343 fob.withKey(Criteria.matchInPort(PortNumber.ALL))
344 .addCondition(Criteria.matchEthDst(config
345 .getDeviceMac(deviceId)));
346 fob.permit().fromApp(srManager.appId);
347 log.debug("populateTableVlan: Installing filtering objective for router mac");
348 srManager.flowObjectiveService.filter(deviceId, fob.add());
sanghob35a6192015-04-01 13:05:26 -0700349 }
350
sanghob35a6192015-04-01 13:05:26 -0700351 private Link selectOneLink(DeviceId srcId, Set<DeviceId> destIds) {
352
353 Set<Link> links = srManager.linkService.getDeviceEgressLinks(srcId);
354 DeviceId destId = (DeviceId) destIds.toArray()[0];
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700355 for (Link link : links) {
sanghob35a6192015-04-01 13:05:26 -0700356 if (link.dst().deviceId().equals(destId)) {
357 return link;
358 }
359 }
360
361 return null;
362 }
363
364}