blob: 154127e72d966acede7f49f57497f0a8f9233a1b [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.
Thomas Vachuska266b4432015-04-30 18:13:25 -070077 *
78 * @return number of rules
sangho20eff1d2015-04-13 15:15:58 -070079 */
80 public long getCounter() {
81 return rulePopulationCounter.get();
sanghob35a6192015-04-01 13:05:26 -070082 }
83
84 /**
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070085 * Populates IP flow rules for specific hosts directly connected to the
86 * switch.
sanghob35a6192015-04-01 13:05:26 -070087 *
88 * @param deviceId switch ID to set the rules
89 * @param hostIp host IP address
90 * @param hostMac host MAC address
91 * @param outPort port where the host is connected
92 */
93 public void populateIpRuleForHost(DeviceId deviceId, Ip4Address hostIp,
94 MacAddress hostMac, PortNumber outPort) {
95 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
96 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
97
98 sbuilder.matchIPDst(IpPrefix.valueOf(hostIp, 32));
99 sbuilder.matchEthType(Ethernet.TYPE_IPV4);
100
101 tbuilder.setEthDst(hostMac)
sangho666cd6d2015-04-14 16:27:13 -0700102 .setEthSrc(config.getDeviceMac(deviceId))
sanghob35a6192015-04-01 13:05:26 -0700103 .setOutput(outPort);
104
105 TrafficTreatment treatment = tbuilder.build();
106 TrafficSelector selector = sbuilder.build();
107
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700108 ForwardingObjective.Builder fwdBuilder = DefaultForwardingObjective
109 .builder().fromApp(srManager.appId).makePermanent()
110 .withSelector(selector).withTreatment(treatment)
111 .withPriority(100).withFlag(ForwardingObjective.Flag.SPECIFIC);
sanghob35a6192015-04-01 13:05:26 -0700112
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700113 log.debug("Installing IPv4 forwarding objective "
114 + "for host {} in switch {}", hostIp, deviceId);
115 srManager.flowObjectiveService.forward(deviceId, fwdBuilder.add());
sangho20eff1d2015-04-13 15:15:58 -0700116 rulePopulationCounter.incrementAndGet();
sanghob35a6192015-04-01 13:05:26 -0700117 }
118
119 /**
120 * Populates IP flow rules for the subnets of the destination router.
121 *
122 * @param deviceId switch ID to set the rules
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700123 * @param subnets subnet information
sanghob35a6192015-04-01 13:05:26 -0700124 * @param destSw destination switch ID
125 * @param nextHops next hop switch ID list
126 * @return true if all rules are set successfully, false otherwise
127 */
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700128 public boolean populateIpRuleForSubnet(DeviceId deviceId,
129 List<Ip4Prefix> subnets,
130 DeviceId destSw,
131 Set<DeviceId> nextHops) {
sanghob35a6192015-04-01 13:05:26 -0700132
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700133 for (IpPrefix subnet : subnets) {
sanghob35a6192015-04-01 13:05:26 -0700134 if (!populateIpRuleForRouter(deviceId, subnet, destSw, nextHops)) {
135 return false;
136 }
137 }
138
139 return true;
140 }
141
142 /**
143 * Populates IP flow rules for the router IP address.
144 *
145 * @param deviceId device ID to set the rules
146 * @param ipPrefix the IP address of the destination router
147 * @param destSw device ID of the destination router
148 * @param nextHops next hop switch ID list
149 * @return true if all rules are set successfully, false otherwise
150 */
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700151 public boolean populateIpRuleForRouter(DeviceId deviceId,
152 IpPrefix ipPrefix, DeviceId destSw,
153 Set<DeviceId> nextHops) {
sanghob35a6192015-04-01 13:05:26 -0700154
155 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
156 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
157
158 sbuilder.matchIPDst(ipPrefix);
159 sbuilder.matchEthType(Ethernet.TYPE_IPV4);
160
161 NeighborSet ns = null;
162
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700163 // If the next hop is the same as the final destination, then MPLS label
164 // is not set.
sanghob35a6192015-04-01 13:05:26 -0700165 if (nextHops.size() == 1 && nextHops.toArray()[0].equals(destSw)) {
166 tbuilder.decNwTtl();
167 ns = new NeighborSet(nextHops);
168 } else {
169 tbuilder.copyTtlOut();
sangho666cd6d2015-04-14 16:27:13 -0700170 ns = new NeighborSet(nextHops, config.getSegmentId(destSw));
sanghob35a6192015-04-01 13:05:26 -0700171 }
172
sanghob35a6192015-04-01 13:05:26 -0700173 TrafficTreatment treatment = tbuilder.build();
174 TrafficSelector selector = sbuilder.build();
175
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700176 ForwardingObjective.Builder fwdBuilder = DefaultForwardingObjective
177 .builder()
178 .fromApp(srManager.appId)
179 .makePermanent()
180 .nextStep(srManager.getNextObjectiveId(deviceId, ns))
181 .withTreatment(treatment)
182 .withSelector(selector)
183 .withPriority(100)
184 .withFlag(ForwardingObjective.Flag.SPECIFIC);
185 log.debug("Installing IPv4 forwarding objective "
186 + "for router IP/subnet {} in switch {}",
187 ipPrefix,
188 deviceId);
189 srManager.flowObjectiveService.forward(deviceId, fwdBuilder.add());
sangho20eff1d2015-04-13 15:15:58 -0700190 rulePopulationCounter.incrementAndGet();
sanghob35a6192015-04-01 13:05:26 -0700191
192 return true;
193 }
194
sanghob35a6192015-04-01 13:05:26 -0700195 /**
196 * Populates MPLS flow rules to all transit routers.
197 *
198 * @param deviceId device ID of the switch to set the rules
199 * @param destSwId destination switch device ID
200 * @param nextHops next hops switch ID list
201 * @return true if all rules are set successfully, false otherwise
202 */
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700203 public boolean populateMplsRule(DeviceId deviceId, DeviceId destSwId,
204 Set<DeviceId> nextHops) {
sanghob35a6192015-04-01 13:05:26 -0700205
206 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700207 List<ForwardingObjective.Builder> fwdObjBuilders = new ArrayList<ForwardingObjective.Builder>();
sanghob35a6192015-04-01 13:05:26 -0700208
209 // TODO Handle the case of Bos == false
sangho666cd6d2015-04-14 16:27:13 -0700210 sbuilder.matchMplsLabel(MplsLabel.mplsLabel(config.getSegmentId(destSwId)));
sanghob35a6192015-04-01 13:05:26 -0700211 sbuilder.matchEthType(Ethernet.MPLS_UNICAST);
212
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700213 // If the next hop is the destination router, do PHP
sanghob35a6192015-04-01 13:05:26 -0700214 if (nextHops.size() == 1 && destSwId.equals(nextHops.toArray()[0])) {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700215 ForwardingObjective.Builder fwdObjBosBuilder =
216 getMplsForwardingObjective(deviceId,
217 destSwId,
218 nextHops,
219 true,
220 true);
221 // TODO: Check with Sangho on why we need this
222 ForwardingObjective.Builder fwdObjNoBosBuilder =
223 getMplsForwardingObjective(deviceId,
224 destSwId,
225 nextHops,
226 true,
227 false);
228 if (fwdObjBosBuilder != null) {
229 fwdObjBuilders.add(fwdObjBosBuilder);
sanghob35a6192015-04-01 13:05:26 -0700230 } else {
231 log.warn("Failed to set MPLS rules.");
232 return false;
233 }
234 } else {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700235 ForwardingObjective.Builder fwdObjBosBuilder =
236 getMplsForwardingObjective(deviceId,
237 destSwId,
238 nextHops,
239 false,
240 true);
241 // TODO: Check with Sangho on why we need this
242 ForwardingObjective.Builder fwdObjNoBosBuilder =
243 getMplsForwardingObjective(deviceId,
244 destSwId,
245 nextHops,
246 false,
247 false);
248 if (fwdObjBosBuilder != null) {
249 fwdObjBuilders.add(fwdObjBosBuilder);
sanghob35a6192015-04-01 13:05:26 -0700250 } else {
251 log.warn("Failed to set MPLS rules.");
252 return false;
253 }
254 }
255
256 TrafficSelector selector = sbuilder.build();
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700257 for (ForwardingObjective.Builder fwdObjBuilder : fwdObjBuilders) {
258 ((Builder) ((Builder) fwdObjBuilder.fromApp(srManager.appId)
259 .makePermanent()).withSelector(selector)
260 .withPriority(100))
261 .withFlag(ForwardingObjective.Flag.SPECIFIC);
262 log.debug("Installing MPLS forwarding objective in switch {}",
263 deviceId);
264 srManager.flowObjectiveService.forward(deviceId,
265 fwdObjBuilder.add());
sangho20eff1d2015-04-13 15:15:58 -0700266 rulePopulationCounter.incrementAndGet();
sanghob35a6192015-04-01 13:05:26 -0700267 }
268
269 return true;
270 }
271
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700272 private ForwardingObjective.Builder getMplsForwardingObjective(DeviceId deviceId,
273 DeviceId destSw,
274 Set<DeviceId> nextHops,
275 boolean phpRequired,
276 boolean isBos) {
sanghob35a6192015-04-01 13:05:26 -0700277
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700278 ForwardingObjective.Builder fwdBuilder = DefaultForwardingObjective
279 .builder().withFlag(ForwardingObjective.Flag.SPECIFIC);
sanghob35a6192015-04-01 13:05:26 -0700280
281 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
282
283 if (phpRequired) {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700284 log.debug("getMplsForwardingObjective: php required");
sanghob35a6192015-04-01 13:05:26 -0700285 tbuilder.copyTtlIn();
286 if (isBos) {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700287 tbuilder.popMpls(Ethernet.TYPE_IPV4).decNwTtl();
sanghob35a6192015-04-01 13:05:26 -0700288 } else {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700289 tbuilder.popMpls(Ethernet.MPLS_UNICAST).decMplsTtl();
sanghob35a6192015-04-01 13:05:26 -0700290 }
291 } else {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700292 log.debug("getMplsForwardingObjective: php not required");
sanghob35a6192015-04-01 13:05:26 -0700293 tbuilder.decMplsTtl();
294 }
295
sangho666cd6d2015-04-14 16:27:13 -0700296 if (!isECMPSupportedInTransitRouter() && !config.isEdgeDevice(deviceId)) {
sanghob35a6192015-04-01 13:05:26 -0700297 Link link = selectOneLink(deviceId, nextHops);
sangho666cd6d2015-04-14 16:27:13 -0700298 DeviceId nextHop = (DeviceId) nextHops.toArray()[0];
sanghob35a6192015-04-01 13:05:26 -0700299 if (link == null) {
300 log.warn("No link from {} to {}", deviceId, nextHops);
301 return null;
302 }
sangho666cd6d2015-04-14 16:27:13 -0700303 tbuilder.setEthSrc(config.getDeviceMac(deviceId))
304 .setEthDst(config.getDeviceMac(nextHop))
sanghob35a6192015-04-01 13:05:26 -0700305 .setOutput(link.src().port());
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700306 fwdBuilder.withTreatment(tbuilder.build());
sanghob35a6192015-04-01 13:05:26 -0700307 } else {
308 NeighborSet ns = new NeighborSet(nextHops);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700309 fwdBuilder.nextStep(srManager
310 .getNextObjectiveId(deviceId, ns));
sanghob35a6192015-04-01 13:05:26 -0700311 }
312
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700313 return fwdBuilder;
sanghob35a6192015-04-01 13:05:26 -0700314 }
315
sangho666cd6d2015-04-14 16:27:13 -0700316 private boolean isECMPSupportedInTransitRouter() {
317
318 // TODO: remove this function when objectives subsystem is supported.
319 return false;
320 }
321
sanghob35a6192015-04-01 13:05:26 -0700322 /**
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700323 * Populates VLAN flows rules. All packets are forwarded to TMAC table.
sanghob35a6192015-04-01 13:05:26 -0700324 *
325 * @param deviceId switch ID to set the rules
326 */
327 public void populateTableVlan(DeviceId deviceId) {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700328 FilteringObjective.Builder fob = DefaultFilteringObjective.builder();
329 fob.withKey(Criteria.matchInPort(PortNumber.ALL))
330 .addCondition(Criteria.matchVlanId(VlanId.NONE));
331 fob.permit().fromApp(srManager.appId);
332 log.debug("populateTableVlan: Installing filtering objective for untagged packets");
333 srManager.flowObjectiveService.filter(deviceId, fob.add());
sanghob35a6192015-04-01 13:05:26 -0700334 }
335
336 /**
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700337 * Populates TMAC table rules. IP packets are forwarded to IP table. MPLS
338 * packets are forwarded to MPLS table.
sanghob35a6192015-04-01 13:05:26 -0700339 *
340 * @param deviceId switch ID to set the rules
341 */
342 public void populateTableTMac(DeviceId deviceId) {
343
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700344 FilteringObjective.Builder fob = DefaultFilteringObjective.builder();
345 fob.withKey(Criteria.matchInPort(PortNumber.ALL))
346 .addCondition(Criteria.matchEthDst(config
347 .getDeviceMac(deviceId)));
348 fob.permit().fromApp(srManager.appId);
349 log.debug("populateTableVlan: Installing filtering objective for router mac");
350 srManager.flowObjectiveService.filter(deviceId, fob.add());
sanghob35a6192015-04-01 13:05:26 -0700351 }
352
sanghob35a6192015-04-01 13:05:26 -0700353 private Link selectOneLink(DeviceId srcId, Set<DeviceId> destIds) {
354
355 Set<Link> links = srManager.linkService.getDeviceEgressLinks(srcId);
356 DeviceId destId = (DeviceId) destIds.toArray()[0];
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700357 for (Link link : links) {
sanghob35a6192015-04-01 13:05:26 -0700358 if (link.dst().deviceId().equals(destId)) {
359 return link;
360 }
361 }
362
363 return null;
364 }
365
366}