blob: 8c84e39a0da591d057028dcc9a4ad3687f8491bd [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
sangho27462c62015-05-14 00:39:53 -0700101 tbuilder.deferred()
102 .setEthDst(hostMac)
sangho9b169e32015-04-14 16:27:13 -0700103 .setEthSrc(config.getDeviceMac(deviceId))
sangho80f11cb2015-04-01 13:05:26 -0700104 .setOutput(outPort);
105
106 TrafficTreatment treatment = tbuilder.build();
107 TrafficSelector selector = sbuilder.build();
108
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700109 ForwardingObjective.Builder fwdBuilder = DefaultForwardingObjective
110 .builder().fromApp(srManager.appId).makePermanent()
111 .withSelector(selector).withTreatment(treatment)
112 .withPriority(100).withFlag(ForwardingObjective.Flag.SPECIFIC);
sangho80f11cb2015-04-01 13:05:26 -0700113
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700114 log.debug("Installing IPv4 forwarding objective "
115 + "for host {} in switch {}", hostIp, deviceId);
116 srManager.flowObjectiveService.forward(deviceId, fwdBuilder.add());
sanghofb7c7292015-04-13 15:15:58 -0700117 rulePopulationCounter.incrementAndGet();
sangho80f11cb2015-04-01 13:05:26 -0700118 }
119
120 /**
121 * Populates IP flow rules for the subnets of the destination router.
122 *
123 * @param deviceId switch ID to set the rules
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700124 * @param subnets subnet information
sangho80f11cb2015-04-01 13:05:26 -0700125 * @param destSw destination switch ID
126 * @param nextHops next hop switch ID list
127 * @return true if all rules are set successfully, false otherwise
128 */
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700129 public boolean populateIpRuleForSubnet(DeviceId deviceId,
130 List<Ip4Prefix> subnets,
131 DeviceId destSw,
132 Set<DeviceId> nextHops) {
sangho80f11cb2015-04-01 13:05:26 -0700133
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700134 for (IpPrefix subnet : subnets) {
sangho80f11cb2015-04-01 13:05:26 -0700135 if (!populateIpRuleForRouter(deviceId, subnet, destSw, nextHops)) {
136 return false;
137 }
138 }
139
140 return true;
141 }
142
143 /**
144 * Populates IP flow rules for the router IP address.
145 *
146 * @param deviceId device ID to set the rules
147 * @param ipPrefix the IP address of the destination router
148 * @param destSw device ID of the destination router
149 * @param nextHops next hop switch ID list
150 * @return true if all rules are set successfully, false otherwise
151 */
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700152 public boolean populateIpRuleForRouter(DeviceId deviceId,
153 IpPrefix ipPrefix, DeviceId destSw,
154 Set<DeviceId> nextHops) {
sangho80f11cb2015-04-01 13:05:26 -0700155
156 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
157 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
158
159 sbuilder.matchIPDst(ipPrefix);
160 sbuilder.matchEthType(Ethernet.TYPE_IPV4);
161
162 NeighborSet ns = null;
163
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700164 // If the next hop is the same as the final destination, then MPLS label
165 // is not set.
sangho80f11cb2015-04-01 13:05:26 -0700166 if (nextHops.size() == 1 && nextHops.toArray()[0].equals(destSw)) {
sangho27462c62015-05-14 00:39:53 -0700167 tbuilder.deferred().decNwTtl();
sangho80f11cb2015-04-01 13:05:26 -0700168 ns = new NeighborSet(nextHops);
169 } else {
sangho27462c62015-05-14 00:39:53 -0700170 tbuilder.deferred().copyTtlOut();
sangho9b169e32015-04-14 16:27:13 -0700171 ns = new NeighborSet(nextHops, config.getSegmentId(destSw));
sangho80f11cb2015-04-01 13:05:26 -0700172 }
173
sangho80f11cb2015-04-01 13:05:26 -0700174 TrafficTreatment treatment = tbuilder.build();
175 TrafficSelector selector = sbuilder.build();
176
sangho2165d222015-05-01 09:38:25 -0700177 if (srManager.getNextObjectiveId(deviceId, ns) <= 0) {
178 log.warn("No next objective in {} for ns: {}", deviceId, ns);
179 return false;
180 }
181
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700182 ForwardingObjective.Builder fwdBuilder = DefaultForwardingObjective
183 .builder()
184 .fromApp(srManager.appId)
185 .makePermanent()
186 .nextStep(srManager.getNextObjectiveId(deviceId, ns))
187 .withTreatment(treatment)
188 .withSelector(selector)
189 .withPriority(100)
190 .withFlag(ForwardingObjective.Flag.SPECIFIC);
191 log.debug("Installing IPv4 forwarding objective "
sangho2165d222015-05-01 09:38:25 -0700192 + "for router IP/subnet {} in switch {}",
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700193 ipPrefix,
194 deviceId);
195 srManager.flowObjectiveService.forward(deviceId, fwdBuilder.add());
sanghofb7c7292015-04-13 15:15:58 -0700196 rulePopulationCounter.incrementAndGet();
sangho80f11cb2015-04-01 13:05:26 -0700197
198 return true;
199 }
200
sangho80f11cb2015-04-01 13:05:26 -0700201 /**
202 * Populates MPLS flow rules to all transit routers.
203 *
204 * @param deviceId device ID of the switch to set the rules
205 * @param destSwId destination switch device ID
206 * @param nextHops next hops switch ID list
207 * @return true if all rules are set successfully, false otherwise
208 */
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700209 public boolean populateMplsRule(DeviceId deviceId, DeviceId destSwId,
210 Set<DeviceId> nextHops) {
sangho80f11cb2015-04-01 13:05:26 -0700211
212 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700213 List<ForwardingObjective.Builder> fwdObjBuilders = new ArrayList<ForwardingObjective.Builder>();
sangho80f11cb2015-04-01 13:05:26 -0700214
215 // TODO Handle the case of Bos == false
sangho9b169e32015-04-14 16:27:13 -0700216 sbuilder.matchMplsLabel(MplsLabel.mplsLabel(config.getSegmentId(destSwId)));
sangho80f11cb2015-04-01 13:05:26 -0700217 sbuilder.matchEthType(Ethernet.MPLS_UNICAST);
218
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700219 // If the next hop is the destination router, do PHP
sangho80f11cb2015-04-01 13:05:26 -0700220 if (nextHops.size() == 1 && destSwId.equals(nextHops.toArray()[0])) {
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700221 log.debug("populateMplsRule: Installing MPLS forwarding objective for "
222 + "label {} in switch {} with PHP",
223 config.getSegmentId(destSwId),
224 deviceId);
225
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700226 ForwardingObjective.Builder fwdObjBosBuilder =
227 getMplsForwardingObjective(deviceId,
228 destSwId,
229 nextHops,
230 true,
231 true);
232 // TODO: Check with Sangho on why we need this
233 ForwardingObjective.Builder fwdObjNoBosBuilder =
234 getMplsForwardingObjective(deviceId,
235 destSwId,
236 nextHops,
237 true,
238 false);
239 if (fwdObjBosBuilder != null) {
240 fwdObjBuilders.add(fwdObjBosBuilder);
sangho80f11cb2015-04-01 13:05:26 -0700241 } else {
242 log.warn("Failed to set MPLS rules.");
243 return false;
244 }
245 } else {
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700246 log.debug("Installing MPLS forwarding objective for "
247 + "label {} in switch {} without PHP",
248 config.getSegmentId(destSwId),
249 deviceId);
250
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700251 ForwardingObjective.Builder fwdObjBosBuilder =
252 getMplsForwardingObjective(deviceId,
253 destSwId,
254 nextHops,
255 false,
256 true);
257 // TODO: Check with Sangho on why we need this
258 ForwardingObjective.Builder fwdObjNoBosBuilder =
259 getMplsForwardingObjective(deviceId,
260 destSwId,
261 nextHops,
262 false,
263 false);
264 if (fwdObjBosBuilder != null) {
265 fwdObjBuilders.add(fwdObjBosBuilder);
sangho80f11cb2015-04-01 13:05:26 -0700266 } else {
267 log.warn("Failed to set MPLS rules.");
268 return false;
269 }
270 }
271
272 TrafficSelector selector = sbuilder.build();
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700273 for (ForwardingObjective.Builder fwdObjBuilder : fwdObjBuilders) {
274 ((Builder) ((Builder) fwdObjBuilder.fromApp(srManager.appId)
275 .makePermanent()).withSelector(selector)
276 .withPriority(100))
277 .withFlag(ForwardingObjective.Flag.SPECIFIC);
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700278 srManager.flowObjectiveService.forward(deviceId,
279 fwdObjBuilder.add());
sanghofb7c7292015-04-13 15:15:58 -0700280 rulePopulationCounter.incrementAndGet();
sangho80f11cb2015-04-01 13:05:26 -0700281 }
282
283 return true;
284 }
285
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700286 private ForwardingObjective.Builder getMplsForwardingObjective(DeviceId deviceId,
287 DeviceId destSw,
288 Set<DeviceId> nextHops,
289 boolean phpRequired,
290 boolean isBos) {
sangho80f11cb2015-04-01 13:05:26 -0700291
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700292 ForwardingObjective.Builder fwdBuilder = DefaultForwardingObjective
293 .builder().withFlag(ForwardingObjective.Flag.SPECIFIC);
sangho80f11cb2015-04-01 13:05:26 -0700294
295 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
296
297 if (phpRequired) {
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700298 log.debug("getMplsForwardingObjective: php required");
sangho27462c62015-05-14 00:39:53 -0700299 tbuilder.deferred().copyTtlIn();
sangho80f11cb2015-04-01 13:05:26 -0700300 if (isBos) {
sangho27462c62015-05-14 00:39:53 -0700301 tbuilder.deferred().popMpls(Ethernet.TYPE_IPV4).decNwTtl();
sangho80f11cb2015-04-01 13:05:26 -0700302 } else {
sangho27462c62015-05-14 00:39:53 -0700303 tbuilder.deferred().popMpls(Ethernet.MPLS_UNICAST).decMplsTtl();
sangho80f11cb2015-04-01 13:05:26 -0700304 }
305 } else {
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700306 log.debug("getMplsForwardingObjective: php not required");
sangho27462c62015-05-14 00:39:53 -0700307 tbuilder.deferred().decMplsTtl();
sangho80f11cb2015-04-01 13:05:26 -0700308 }
309
sangho9b169e32015-04-14 16:27:13 -0700310 if (!isECMPSupportedInTransitRouter() && !config.isEdgeDevice(deviceId)) {
sangho28d0b6d2015-05-07 13:30:57 -0700311 PortNumber port = selectOnePort(deviceId, nextHops);
sangho9b169e32015-04-14 16:27:13 -0700312 DeviceId nextHop = (DeviceId) nextHops.toArray()[0];
sangho28d0b6d2015-05-07 13:30:57 -0700313 if (port == null) {
sangho80f11cb2015-04-01 13:05:26 -0700314 log.warn("No link from {} to {}", deviceId, nextHops);
315 return null;
316 }
sangho27462c62015-05-14 00:39:53 -0700317 tbuilder.deferred()
318 .setEthSrc(config.getDeviceMac(deviceId))
sangho9b169e32015-04-14 16:27:13 -0700319 .setEthDst(config.getDeviceMac(nextHop))
sangho28d0b6d2015-05-07 13:30:57 -0700320 .setOutput(port);
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700321 fwdBuilder.withTreatment(tbuilder.build());
sangho80f11cb2015-04-01 13:05:26 -0700322 } else {
323 NeighborSet ns = new NeighborSet(nextHops);
sangho3cd8db62015-05-06 11:42:31 -0700324 fwdBuilder.withTreatment(tbuilder.build());
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700325 fwdBuilder.nextStep(srManager
326 .getNextObjectiveId(deviceId, ns));
sangho80f11cb2015-04-01 13:05:26 -0700327 }
328
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700329 return fwdBuilder;
sangho80f11cb2015-04-01 13:05:26 -0700330 }
331
sangho9b169e32015-04-14 16:27:13 -0700332 private boolean isECMPSupportedInTransitRouter() {
333
334 // TODO: remove this function when objectives subsystem is supported.
335 return false;
336 }
337
sangho80f11cb2015-04-01 13:05:26 -0700338 /**
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700339 * Populates VLAN flows rules. All packets are forwarded to TMAC table.
sangho80f11cb2015-04-01 13:05:26 -0700340 *
341 * @param deviceId switch ID to set the rules
342 */
343 public void populateTableVlan(DeviceId deviceId) {
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700344 FilteringObjective.Builder fob = DefaultFilteringObjective.builder();
345 fob.withKey(Criteria.matchInPort(PortNumber.ALL))
346 .addCondition(Criteria.matchVlanId(VlanId.NONE));
347 fob.permit().fromApp(srManager.appId);
348 log.debug("populateTableVlan: Installing filtering objective for untagged packets");
349 srManager.flowObjectiveService.filter(deviceId, fob.add());
sangho80f11cb2015-04-01 13:05:26 -0700350 }
351
352 /**
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700353 * Populates TMAC table rules. IP packets are forwarded to IP table. MPLS
354 * packets are forwarded to MPLS table.
sangho80f11cb2015-04-01 13:05:26 -0700355 *
356 * @param deviceId switch ID to set the rules
357 */
358 public void populateTableTMac(DeviceId deviceId) {
359
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700360 FilteringObjective.Builder fob = DefaultFilteringObjective.builder();
361 fob.withKey(Criteria.matchInPort(PortNumber.ALL))
362 .addCondition(Criteria.matchEthDst(config
363 .getDeviceMac(deviceId)));
364 fob.permit().fromApp(srManager.appId);
365 log.debug("populateTableVlan: Installing filtering objective for router mac");
366 srManager.flowObjectiveService.filter(deviceId, fob.add());
sangho80f11cb2015-04-01 13:05:26 -0700367 }
368
sangho28d0b6d2015-05-07 13:30:57 -0700369 private PortNumber selectOnePort(DeviceId srcId, Set<DeviceId> destIds) {
sangho80f11cb2015-04-01 13:05:26 -0700370
sangho28d0b6d2015-05-07 13:30:57 -0700371 Set<Link> links = srManager.linkService.getDeviceLinks(srcId);
372 for (DeviceId destId: destIds) {
373 for (Link link : links) {
374 if (link.dst().deviceId().equals(destId)) {
375 return link.src().port();
376 } else if (link.src().deviceId().equals(destId)) {
377 return link.dst().port();
378 }
sangho80f11cb2015-04-01 13:05:26 -0700379 }
380 }
381
382 return null;
383 }
384
385}