blob: 09bfc5008a0f1589ea08b10aedcae3bffc45ec72 [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 Vavilapalli64505482015-04-21 13:04:13 -070024import org.onlab.packet.VlanId;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070025import org.onosproject.segmentrouting.grouphandler.NeighborSet;
sangho80f11cb2015-04-01 13:05:26 -070026import org.onosproject.net.DeviceId;
27import org.onosproject.net.Link;
28import org.onosproject.net.PortNumber;
sangho80f11cb2015-04-01 13:05:26 -070029import org.onosproject.net.flow.DefaultTrafficSelector;
30import org.onosproject.net.flow.DefaultTrafficTreatment;
sangho80f11cb2015-04-01 13:05:26 -070031import org.onosproject.net.flow.TrafficSelector;
32import org.onosproject.net.flow.TrafficTreatment;
Srikanth Vavilapalli64505482015-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;
sangho80f11cb2015-04-01 13:05:26 -070039import org.slf4j.Logger;
40import org.slf4j.LoggerFactory;
41
42import java.util.ArrayList;
sangho80f11cb2015-04-01 13:05:26 -070043import java.util.List;
44import java.util.Set;
sanghofb7c7292015-04-13 15:15:58 -070045import java.util.concurrent.atomic.AtomicLong;
sangho80f11cb2015-04-01 13:05:26 -070046
47import static com.google.common.base.Preconditions.checkNotNull;
48
49public class RoutingRulePopulator {
50
Srikanth Vavilapalli64505482015-04-21 13:04:13 -070051 private static final Logger log = LoggerFactory
52 .getLogger(RoutingRulePopulator.class);
sangho80f11cb2015-04-01 13:05:26 -070053
sanghofb7c7292015-04-13 15:15:58 -070054 private AtomicLong rulePopulationCounter;
sangho9b169e32015-04-14 16:27:13 -070055 private SegmentRoutingManager srManager;
56 private DeviceConfiguration config;
sangho80f11cb2015-04-01 13:05:26 -070057 /**
58 * Creates a RoutingRulePopulator object.
59 *
Thomas Vachuska8a075092015-04-15 18:20:08 -070060 * @param srManager segment routing manager reference
sangho80f11cb2015-04-01 13:05:26 -070061 */
62 public RoutingRulePopulator(SegmentRoutingManager srManager) {
63 this.srManager = srManager;
sangho9b169e32015-04-14 16:27:13 -070064 this.config = checkNotNull(srManager.deviceConfiguration);
sanghofb7c7292015-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 Vachuska7cfc6202015-04-30 18:13:25 -070077 *
78 * @return number of rules
sanghofb7c7292015-04-13 15:15:58 -070079 */
80 public long getCounter() {
81 return rulePopulationCounter.get();
sangho80f11cb2015-04-01 13:05:26 -070082 }
83
84 /**
Srikanth Vavilapalli64505482015-04-21 13:04:13 -070085 * Populates IP flow rules for specific hosts directly connected to the
86 * switch.
sangho80f11cb2015-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)
sangho9b169e32015-04-14 16:27:13 -0700102 .setEthSrc(config.getDeviceMac(deviceId))
sangho80f11cb2015-04-01 13:05:26 -0700103 .setOutput(outPort);
104
105 TrafficTreatment treatment = tbuilder.build();
106 TrafficSelector selector = sbuilder.build();
107
Srikanth Vavilapalli64505482015-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);
sangho80f11cb2015-04-01 13:05:26 -0700112
Srikanth Vavilapalli64505482015-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());
sanghofb7c7292015-04-13 15:15:58 -0700116 rulePopulationCounter.incrementAndGet();
sangho80f11cb2015-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 Vavilapalli37a461b2015-04-07 15:12:32 -0700123 * @param subnets subnet information
sangho80f11cb2015-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 Vavilapalli64505482015-04-21 13:04:13 -0700128 public boolean populateIpRuleForSubnet(DeviceId deviceId,
129 List<Ip4Prefix> subnets,
130 DeviceId destSw,
131 Set<DeviceId> nextHops) {
sangho80f11cb2015-04-01 13:05:26 -0700132
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700133 for (IpPrefix subnet : subnets) {
sangho80f11cb2015-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 Vavilapalli64505482015-04-21 13:04:13 -0700151 public boolean populateIpRuleForRouter(DeviceId deviceId,
152 IpPrefix ipPrefix, DeviceId destSw,
153 Set<DeviceId> nextHops) {
sangho80f11cb2015-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 Vavilapalli64505482015-04-21 13:04:13 -0700163 // If the next hop is the same as the final destination, then MPLS label
164 // is not set.
sangho80f11cb2015-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();
sangho9b169e32015-04-14 16:27:13 -0700170 ns = new NeighborSet(nextHops, config.getSegmentId(destSw));
sangho80f11cb2015-04-01 13:05:26 -0700171 }
172
sangho80f11cb2015-04-01 13:05:26 -0700173 TrafficTreatment treatment = tbuilder.build();
174 TrafficSelector selector = sbuilder.build();
175
sangho2165d222015-05-01 09:38:25 -0700176 if (srManager.getNextObjectiveId(deviceId, ns) <= 0) {
177 log.warn("No next objective in {} for ns: {}", deviceId, ns);
178 return false;
179 }
180
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700181 ForwardingObjective.Builder fwdBuilder = DefaultForwardingObjective
182 .builder()
183 .fromApp(srManager.appId)
184 .makePermanent()
185 .nextStep(srManager.getNextObjectiveId(deviceId, ns))
186 .withTreatment(treatment)
187 .withSelector(selector)
188 .withPriority(100)
189 .withFlag(ForwardingObjective.Flag.SPECIFIC);
190 log.debug("Installing IPv4 forwarding objective "
sangho2165d222015-05-01 09:38:25 -0700191 + "for router IP/subnet {} in switch {}",
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700192 ipPrefix,
193 deviceId);
194 srManager.flowObjectiveService.forward(deviceId, fwdBuilder.add());
sanghofb7c7292015-04-13 15:15:58 -0700195 rulePopulationCounter.incrementAndGet();
sangho80f11cb2015-04-01 13:05:26 -0700196
197 return true;
198 }
199
sangho80f11cb2015-04-01 13:05:26 -0700200 /**
201 * Populates MPLS flow rules to all transit routers.
202 *
203 * @param deviceId device ID of the switch to set the rules
204 * @param destSwId destination switch device ID
205 * @param nextHops next hops switch ID list
206 * @return true if all rules are set successfully, false otherwise
207 */
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700208 public boolean populateMplsRule(DeviceId deviceId, DeviceId destSwId,
209 Set<DeviceId> nextHops) {
sangho80f11cb2015-04-01 13:05:26 -0700210
211 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700212 List<ForwardingObjective.Builder> fwdObjBuilders = new ArrayList<ForwardingObjective.Builder>();
sangho80f11cb2015-04-01 13:05:26 -0700213
214 // TODO Handle the case of Bos == false
sangho9b169e32015-04-14 16:27:13 -0700215 sbuilder.matchMplsLabel(MplsLabel.mplsLabel(config.getSegmentId(destSwId)));
sangho80f11cb2015-04-01 13:05:26 -0700216 sbuilder.matchEthType(Ethernet.MPLS_UNICAST);
217
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700218 // If the next hop is the destination router, do PHP
sangho80f11cb2015-04-01 13:05:26 -0700219 if (nextHops.size() == 1 && destSwId.equals(nextHops.toArray()[0])) {
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700220 ForwardingObjective.Builder fwdObjBosBuilder =
221 getMplsForwardingObjective(deviceId,
222 destSwId,
223 nextHops,
224 true,
225 true);
226 // TODO: Check with Sangho on why we need this
227 ForwardingObjective.Builder fwdObjNoBosBuilder =
228 getMplsForwardingObjective(deviceId,
229 destSwId,
230 nextHops,
231 true,
232 false);
233 if (fwdObjBosBuilder != null) {
234 fwdObjBuilders.add(fwdObjBosBuilder);
sangho80f11cb2015-04-01 13:05:26 -0700235 } else {
236 log.warn("Failed to set MPLS rules.");
237 return false;
238 }
239 } else {
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700240 ForwardingObjective.Builder fwdObjBosBuilder =
241 getMplsForwardingObjective(deviceId,
242 destSwId,
243 nextHops,
244 false,
245 true);
246 // TODO: Check with Sangho on why we need this
247 ForwardingObjective.Builder fwdObjNoBosBuilder =
248 getMplsForwardingObjective(deviceId,
249 destSwId,
250 nextHops,
251 false,
252 false);
253 if (fwdObjBosBuilder != null) {
254 fwdObjBuilders.add(fwdObjBosBuilder);
sangho80f11cb2015-04-01 13:05:26 -0700255 } else {
256 log.warn("Failed to set MPLS rules.");
257 return false;
258 }
259 }
260
261 TrafficSelector selector = sbuilder.build();
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700262 for (ForwardingObjective.Builder fwdObjBuilder : fwdObjBuilders) {
263 ((Builder) ((Builder) fwdObjBuilder.fromApp(srManager.appId)
264 .makePermanent()).withSelector(selector)
265 .withPriority(100))
266 .withFlag(ForwardingObjective.Flag.SPECIFIC);
267 log.debug("Installing MPLS forwarding objective in switch {}",
268 deviceId);
269 srManager.flowObjectiveService.forward(deviceId,
270 fwdObjBuilder.add());
sanghofb7c7292015-04-13 15:15:58 -0700271 rulePopulationCounter.incrementAndGet();
sangho80f11cb2015-04-01 13:05:26 -0700272 }
273
274 return true;
275 }
276
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700277 private ForwardingObjective.Builder getMplsForwardingObjective(DeviceId deviceId,
278 DeviceId destSw,
279 Set<DeviceId> nextHops,
280 boolean phpRequired,
281 boolean isBos) {
sangho80f11cb2015-04-01 13:05:26 -0700282
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700283 ForwardingObjective.Builder fwdBuilder = DefaultForwardingObjective
284 .builder().withFlag(ForwardingObjective.Flag.SPECIFIC);
sangho80f11cb2015-04-01 13:05:26 -0700285
286 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
287
288 if (phpRequired) {
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700289 log.debug("getMplsForwardingObjective: php required");
sangho80f11cb2015-04-01 13:05:26 -0700290 tbuilder.copyTtlIn();
291 if (isBos) {
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700292 tbuilder.popMpls(Ethernet.TYPE_IPV4).decNwTtl();
sangho80f11cb2015-04-01 13:05:26 -0700293 } else {
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700294 tbuilder.popMpls(Ethernet.MPLS_UNICAST).decMplsTtl();
sangho80f11cb2015-04-01 13:05:26 -0700295 }
296 } else {
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700297 log.debug("getMplsForwardingObjective: php not required");
sangho80f11cb2015-04-01 13:05:26 -0700298 tbuilder.decMplsTtl();
299 }
300
sangho9b169e32015-04-14 16:27:13 -0700301 if (!isECMPSupportedInTransitRouter() && !config.isEdgeDevice(deviceId)) {
sangho80f11cb2015-04-01 13:05:26 -0700302 Link link = selectOneLink(deviceId, nextHops);
sangho9b169e32015-04-14 16:27:13 -0700303 DeviceId nextHop = (DeviceId) nextHops.toArray()[0];
sangho80f11cb2015-04-01 13:05:26 -0700304 if (link == null) {
305 log.warn("No link from {} to {}", deviceId, nextHops);
306 return null;
307 }
sangho9b169e32015-04-14 16:27:13 -0700308 tbuilder.setEthSrc(config.getDeviceMac(deviceId))
309 .setEthDst(config.getDeviceMac(nextHop))
sangho80f11cb2015-04-01 13:05:26 -0700310 .setOutput(link.src().port());
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700311 fwdBuilder.withTreatment(tbuilder.build());
sangho80f11cb2015-04-01 13:05:26 -0700312 } else {
313 NeighborSet ns = new NeighborSet(nextHops);
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700314 fwdBuilder.nextStep(srManager
315 .getNextObjectiveId(deviceId, ns));
sangho80f11cb2015-04-01 13:05:26 -0700316 }
317
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700318 return fwdBuilder;
sangho80f11cb2015-04-01 13:05:26 -0700319 }
320
sangho9b169e32015-04-14 16:27:13 -0700321 private boolean isECMPSupportedInTransitRouter() {
322
323 // TODO: remove this function when objectives subsystem is supported.
324 return false;
325 }
326
sangho80f11cb2015-04-01 13:05:26 -0700327 /**
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700328 * Populates VLAN flows rules. All packets are forwarded to TMAC table.
sangho80f11cb2015-04-01 13:05:26 -0700329 *
330 * @param deviceId switch ID to set the rules
331 */
332 public void populateTableVlan(DeviceId deviceId) {
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700333 FilteringObjective.Builder fob = DefaultFilteringObjective.builder();
334 fob.withKey(Criteria.matchInPort(PortNumber.ALL))
335 .addCondition(Criteria.matchVlanId(VlanId.NONE));
336 fob.permit().fromApp(srManager.appId);
337 log.debug("populateTableVlan: Installing filtering objective for untagged packets");
338 srManager.flowObjectiveService.filter(deviceId, fob.add());
sangho80f11cb2015-04-01 13:05:26 -0700339 }
340
341 /**
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700342 * Populates TMAC table rules. IP packets are forwarded to IP table. MPLS
343 * packets are forwarded to MPLS table.
sangho80f11cb2015-04-01 13:05:26 -0700344 *
345 * @param deviceId switch ID to set the rules
346 */
347 public void populateTableTMac(DeviceId deviceId) {
348
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700349 FilteringObjective.Builder fob = DefaultFilteringObjective.builder();
350 fob.withKey(Criteria.matchInPort(PortNumber.ALL))
351 .addCondition(Criteria.matchEthDst(config
352 .getDeviceMac(deviceId)));
353 fob.permit().fromApp(srManager.appId);
354 log.debug("populateTableVlan: Installing filtering objective for router mac");
355 srManager.flowObjectiveService.filter(deviceId, fob.add());
sangho80f11cb2015-04-01 13:05:26 -0700356 }
357
sangho80f11cb2015-04-01 13:05:26 -0700358 private Link selectOneLink(DeviceId srcId, Set<DeviceId> destIds) {
359
360 Set<Link> links = srManager.linkService.getDeviceEgressLinks(srcId);
361 DeviceId destId = (DeviceId) destIds.toArray()[0];
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700362 for (Link link : links) {
sangho80f11cb2015-04-01 13:05:26 -0700363 if (link.dst().deviceId().equals(destId)) {
364 return link;
365 }
366 }
367
368 return null;
369 }
370
371}