blob: 59fc4ca7281e846d6abda9a919162fb4854e2a7f [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;
Srikanth Vavilapallif3a8bc02015-05-22 13:47:31 -070038import org.onosproject.net.flowobjective.Objective;
39import org.onosproject.net.flowobjective.ObjectiveError;
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070040import org.onosproject.net.flowobjective.ForwardingObjective.Builder;
Srikanth Vavilapallif3a8bc02015-05-22 13:47:31 -070041import org.onosproject.net.flowobjective.ObjectiveContext;
sanghob35a6192015-04-01 13:05:26 -070042import org.slf4j.Logger;
43import org.slf4j.LoggerFactory;
44
45import java.util.ArrayList;
sanghob35a6192015-04-01 13:05:26 -070046import java.util.List;
47import java.util.Set;
sangho20eff1d2015-04-13 15:15:58 -070048import java.util.concurrent.atomic.AtomicLong;
sanghob35a6192015-04-01 13:05:26 -070049
50import static com.google.common.base.Preconditions.checkNotNull;
51
52public class RoutingRulePopulator {
53
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070054 private static final Logger log = LoggerFactory
55 .getLogger(RoutingRulePopulator.class);
sanghob35a6192015-04-01 13:05:26 -070056
sangho20eff1d2015-04-13 15:15:58 -070057 private AtomicLong rulePopulationCounter;
sangho666cd6d2015-04-14 16:27:13 -070058 private SegmentRoutingManager srManager;
59 private DeviceConfiguration config;
sanghob35a6192015-04-01 13:05:26 -070060 /**
61 * Creates a RoutingRulePopulator object.
62 *
Thomas Vachuskae10f56b2015-04-15 18:20:08 -070063 * @param srManager segment routing manager reference
sanghob35a6192015-04-01 13:05:26 -070064 */
65 public RoutingRulePopulator(SegmentRoutingManager srManager) {
66 this.srManager = srManager;
sangho666cd6d2015-04-14 16:27:13 -070067 this.config = checkNotNull(srManager.deviceConfiguration);
sangho20eff1d2015-04-13 15:15:58 -070068 this.rulePopulationCounter = new AtomicLong(0);
69 }
70
71 /**
72 * Resets the population counter.
73 */
74 public void resetCounter() {
75 rulePopulationCounter.set(0);
76 }
77
78 /**
79 * Returns the number of rules populated.
Thomas Vachuska266b4432015-04-30 18:13:25 -070080 *
81 * @return number of rules
sangho20eff1d2015-04-13 15:15:58 -070082 */
83 public long getCounter() {
84 return rulePopulationCounter.get();
sanghob35a6192015-04-01 13:05:26 -070085 }
86
87 /**
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070088 * Populates IP flow rules for specific hosts directly connected to the
89 * switch.
sanghob35a6192015-04-01 13:05:26 -070090 *
91 * @param deviceId switch ID to set the rules
92 * @param hostIp host IP address
93 * @param hostMac host MAC address
94 * @param outPort port where the host is connected
95 */
96 public void populateIpRuleForHost(DeviceId deviceId, Ip4Address hostIp,
97 MacAddress hostMac, PortNumber outPort) {
98 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
99 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
100
101 sbuilder.matchIPDst(IpPrefix.valueOf(hostIp, 32));
102 sbuilder.matchEthType(Ethernet.TYPE_IPV4);
103
sangho1e575652015-05-14 00:39:53 -0700104 tbuilder.deferred()
105 .setEthDst(hostMac)
sangho666cd6d2015-04-14 16:27:13 -0700106 .setEthSrc(config.getDeviceMac(deviceId))
sanghob35a6192015-04-01 13:05:26 -0700107 .setOutput(outPort);
108
109 TrafficTreatment treatment = tbuilder.build();
110 TrafficSelector selector = sbuilder.build();
111
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700112 ForwardingObjective.Builder fwdBuilder = DefaultForwardingObjective
113 .builder().fromApp(srManager.appId).makePermanent()
114 .withSelector(selector).withTreatment(treatment)
115 .withPriority(100).withFlag(ForwardingObjective.Flag.SPECIFIC);
sanghob35a6192015-04-01 13:05:26 -0700116
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700117 log.debug("Installing IPv4 forwarding objective "
118 + "for host {} in switch {}", hostIp, deviceId);
Srikanth Vavilapallif3a8bc02015-05-22 13:47:31 -0700119 srManager.flowObjectiveService.
120 forward(deviceId,
121 fwdBuilder.
122 add(new SRObjectiveContext(deviceId,
123 SRObjectiveContext.ObjectiveType.FORWARDING)));
sangho20eff1d2015-04-13 15:15:58 -0700124 rulePopulationCounter.incrementAndGet();
sanghob35a6192015-04-01 13:05:26 -0700125 }
126
127 /**
128 * Populates IP flow rules for the subnets of the destination router.
129 *
130 * @param deviceId switch ID to set the rules
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700131 * @param subnets subnet information
sanghob35a6192015-04-01 13:05:26 -0700132 * @param destSw destination switch ID
133 * @param nextHops next hop switch ID list
134 * @return true if all rules are set successfully, false otherwise
135 */
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700136 public boolean populateIpRuleForSubnet(DeviceId deviceId,
137 List<Ip4Prefix> subnets,
138 DeviceId destSw,
139 Set<DeviceId> nextHops) {
sanghob35a6192015-04-01 13:05:26 -0700140
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700141 for (IpPrefix subnet : subnets) {
sanghob35a6192015-04-01 13:05:26 -0700142 if (!populateIpRuleForRouter(deviceId, subnet, destSw, nextHops)) {
143 return false;
144 }
145 }
146
147 return true;
148 }
149
150 /**
151 * Populates IP flow rules for the router IP address.
152 *
153 * @param deviceId device ID to set the rules
154 * @param ipPrefix the IP address of the destination router
155 * @param destSw device ID of the destination router
156 * @param nextHops next hop switch ID list
157 * @return true if all rules are set successfully, false otherwise
158 */
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700159 public boolean populateIpRuleForRouter(DeviceId deviceId,
160 IpPrefix ipPrefix, DeviceId destSw,
161 Set<DeviceId> nextHops) {
sanghob35a6192015-04-01 13:05:26 -0700162
163 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
164 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
165
166 sbuilder.matchIPDst(ipPrefix);
167 sbuilder.matchEthType(Ethernet.TYPE_IPV4);
168
169 NeighborSet ns = null;
170
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700171 // If the next hop is the same as the final destination, then MPLS label
172 // is not set.
sanghob35a6192015-04-01 13:05:26 -0700173 if (nextHops.size() == 1 && nextHops.toArray()[0].equals(destSw)) {
sangho1e575652015-05-14 00:39:53 -0700174 tbuilder.deferred().decNwTtl();
sanghob35a6192015-04-01 13:05:26 -0700175 ns = new NeighborSet(nextHops);
176 } else {
sangho1e575652015-05-14 00:39:53 -0700177 tbuilder.deferred().copyTtlOut();
sangho666cd6d2015-04-14 16:27:13 -0700178 ns = new NeighborSet(nextHops, config.getSegmentId(destSw));
sanghob35a6192015-04-01 13:05:26 -0700179 }
180
sanghob35a6192015-04-01 13:05:26 -0700181 TrafficTreatment treatment = tbuilder.build();
182 TrafficSelector selector = sbuilder.build();
183
sangho834e4b02015-05-01 09:38:25 -0700184 if (srManager.getNextObjectiveId(deviceId, ns) <= 0) {
185 log.warn("No next objective in {} for ns: {}", deviceId, ns);
186 return false;
187 }
188
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700189 ForwardingObjective.Builder fwdBuilder = DefaultForwardingObjective
190 .builder()
191 .fromApp(srManager.appId)
192 .makePermanent()
193 .nextStep(srManager.getNextObjectiveId(deviceId, ns))
194 .withTreatment(treatment)
195 .withSelector(selector)
196 .withPriority(100)
197 .withFlag(ForwardingObjective.Flag.SPECIFIC);
198 log.debug("Installing IPv4 forwarding objective "
sangho834e4b02015-05-01 09:38:25 -0700199 + "for router IP/subnet {} in switch {}",
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700200 ipPrefix,
201 deviceId);
Srikanth Vavilapallif3a8bc02015-05-22 13:47:31 -0700202 srManager.flowObjectiveService.
203 forward(deviceId,
204 fwdBuilder.
205 add(new SRObjectiveContext(deviceId,
206 SRObjectiveContext.ObjectiveType.FORWARDING)));
sangho20eff1d2015-04-13 15:15:58 -0700207 rulePopulationCounter.incrementAndGet();
sanghob35a6192015-04-01 13:05:26 -0700208
209 return true;
210 }
211
sanghob35a6192015-04-01 13:05:26 -0700212 /**
213 * Populates MPLS flow rules to all transit routers.
214 *
215 * @param deviceId device ID of the switch to set the rules
216 * @param destSwId destination switch device ID
217 * @param nextHops next hops switch ID list
218 * @return true if all rules are set successfully, false otherwise
219 */
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700220 public boolean populateMplsRule(DeviceId deviceId, DeviceId destSwId,
221 Set<DeviceId> nextHops) {
sanghob35a6192015-04-01 13:05:26 -0700222
223 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700224 List<ForwardingObjective.Builder> fwdObjBuilders = new ArrayList<ForwardingObjective.Builder>();
sanghob35a6192015-04-01 13:05:26 -0700225
226 // TODO Handle the case of Bos == false
sangho666cd6d2015-04-14 16:27:13 -0700227 sbuilder.matchMplsLabel(MplsLabel.mplsLabel(config.getSegmentId(destSwId)));
sanghob35a6192015-04-01 13:05:26 -0700228 sbuilder.matchEthType(Ethernet.MPLS_UNICAST);
229
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700230 // If the next hop is the destination router, do PHP
sanghob35a6192015-04-01 13:05:26 -0700231 if (nextHops.size() == 1 && destSwId.equals(nextHops.toArray()[0])) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700232 log.debug("populateMplsRule: Installing MPLS forwarding objective for "
233 + "label {} in switch {} with PHP",
234 config.getSegmentId(destSwId),
235 deviceId);
236
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700237 ForwardingObjective.Builder fwdObjBosBuilder =
238 getMplsForwardingObjective(deviceId,
239 destSwId,
240 nextHops,
241 true,
242 true);
243 // TODO: Check with Sangho on why we need this
244 ForwardingObjective.Builder fwdObjNoBosBuilder =
245 getMplsForwardingObjective(deviceId,
246 destSwId,
247 nextHops,
248 true,
249 false);
250 if (fwdObjBosBuilder != null) {
251 fwdObjBuilders.add(fwdObjBosBuilder);
sanghob35a6192015-04-01 13:05:26 -0700252 } else {
253 log.warn("Failed to set MPLS rules.");
254 return false;
255 }
256 } else {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700257 log.debug("Installing MPLS forwarding objective for "
258 + "label {} in switch {} without PHP",
259 config.getSegmentId(destSwId),
260 deviceId);
261
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700262 ForwardingObjective.Builder fwdObjBosBuilder =
263 getMplsForwardingObjective(deviceId,
264 destSwId,
265 nextHops,
266 false,
267 true);
268 // TODO: Check with Sangho on why we need this
269 ForwardingObjective.Builder fwdObjNoBosBuilder =
270 getMplsForwardingObjective(deviceId,
271 destSwId,
272 nextHops,
273 false,
274 false);
275 if (fwdObjBosBuilder != null) {
276 fwdObjBuilders.add(fwdObjBosBuilder);
sanghob35a6192015-04-01 13:05:26 -0700277 } else {
278 log.warn("Failed to set MPLS rules.");
279 return false;
280 }
281 }
282
283 TrafficSelector selector = sbuilder.build();
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700284 for (ForwardingObjective.Builder fwdObjBuilder : fwdObjBuilders) {
285 ((Builder) ((Builder) fwdObjBuilder.fromApp(srManager.appId)
286 .makePermanent()).withSelector(selector)
287 .withPriority(100))
288 .withFlag(ForwardingObjective.Flag.SPECIFIC);
Srikanth Vavilapallif3a8bc02015-05-22 13:47:31 -0700289 srManager.flowObjectiveService.
290 forward(deviceId,
291 fwdObjBuilder.
292 add(new SRObjectiveContext(deviceId,
293 SRObjectiveContext.ObjectiveType.FORWARDING)));
sangho20eff1d2015-04-13 15:15:58 -0700294 rulePopulationCounter.incrementAndGet();
sanghob35a6192015-04-01 13:05:26 -0700295 }
296
297 return true;
298 }
299
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700300 private ForwardingObjective.Builder getMplsForwardingObjective(DeviceId deviceId,
301 DeviceId destSw,
302 Set<DeviceId> nextHops,
303 boolean phpRequired,
304 boolean isBos) {
sanghob35a6192015-04-01 13:05:26 -0700305
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700306 ForwardingObjective.Builder fwdBuilder = DefaultForwardingObjective
307 .builder().withFlag(ForwardingObjective.Flag.SPECIFIC);
sanghob35a6192015-04-01 13:05:26 -0700308
309 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
310
311 if (phpRequired) {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700312 log.debug("getMplsForwardingObjective: php required");
sangho1e575652015-05-14 00:39:53 -0700313 tbuilder.deferred().copyTtlIn();
sanghob35a6192015-04-01 13:05:26 -0700314 if (isBos) {
sangho1e575652015-05-14 00:39:53 -0700315 tbuilder.deferred().popMpls(Ethernet.TYPE_IPV4).decNwTtl();
sanghob35a6192015-04-01 13:05:26 -0700316 } else {
sangho1e575652015-05-14 00:39:53 -0700317 tbuilder.deferred().popMpls(Ethernet.MPLS_UNICAST).decMplsTtl();
sanghob35a6192015-04-01 13:05:26 -0700318 }
319 } else {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700320 log.debug("getMplsForwardingObjective: php not required");
sangho1e575652015-05-14 00:39:53 -0700321 tbuilder.deferred().decMplsTtl();
sanghob35a6192015-04-01 13:05:26 -0700322 }
323
sangho666cd6d2015-04-14 16:27:13 -0700324 if (!isECMPSupportedInTransitRouter() && !config.isEdgeDevice(deviceId)) {
sangho45b009c2015-05-07 13:30:57 -0700325 PortNumber port = selectOnePort(deviceId, nextHops);
sangho666cd6d2015-04-14 16:27:13 -0700326 DeviceId nextHop = (DeviceId) nextHops.toArray()[0];
sangho45b009c2015-05-07 13:30:57 -0700327 if (port == null) {
sanghob35a6192015-04-01 13:05:26 -0700328 log.warn("No link from {} to {}", deviceId, nextHops);
329 return null;
330 }
sangho1e575652015-05-14 00:39:53 -0700331 tbuilder.deferred()
332 .setEthSrc(config.getDeviceMac(deviceId))
sangho666cd6d2015-04-14 16:27:13 -0700333 .setEthDst(config.getDeviceMac(nextHop))
sangho45b009c2015-05-07 13:30:57 -0700334 .setOutput(port);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700335 fwdBuilder.withTreatment(tbuilder.build());
sanghob35a6192015-04-01 13:05:26 -0700336 } else {
337 NeighborSet ns = new NeighborSet(nextHops);
sangho5f1e4572015-05-06 11:42:31 -0700338 fwdBuilder.withTreatment(tbuilder.build());
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700339 fwdBuilder.nextStep(srManager
340 .getNextObjectiveId(deviceId, ns));
sanghob35a6192015-04-01 13:05:26 -0700341 }
342
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700343 return fwdBuilder;
sanghob35a6192015-04-01 13:05:26 -0700344 }
345
sangho666cd6d2015-04-14 16:27:13 -0700346 private boolean isECMPSupportedInTransitRouter() {
347
348 // TODO: remove this function when objectives subsystem is supported.
349 return false;
350 }
351
sanghob35a6192015-04-01 13:05:26 -0700352 /**
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700353 * Populates VLAN flows rules. All packets are forwarded to TMAC table.
sanghob35a6192015-04-01 13:05:26 -0700354 *
355 * @param deviceId switch ID to set the rules
356 */
357 public void populateTableVlan(DeviceId deviceId) {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700358 FilteringObjective.Builder fob = DefaultFilteringObjective.builder();
359 fob.withKey(Criteria.matchInPort(PortNumber.ALL))
360 .addCondition(Criteria.matchVlanId(VlanId.NONE));
361 fob.permit().fromApp(srManager.appId);
362 log.debug("populateTableVlan: Installing filtering objective for untagged packets");
Srikanth Vavilapallif3a8bc02015-05-22 13:47:31 -0700363 srManager.flowObjectiveService.
364 filter(deviceId,
365 fob.add(new SRObjectiveContext(deviceId,
366 SRObjectiveContext.ObjectiveType.FILTER)));
sanghob35a6192015-04-01 13:05:26 -0700367 }
368
369 /**
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700370 * Populates TMAC table rules. IP packets are forwarded to IP table. MPLS
371 * packets are forwarded to MPLS table.
sanghob35a6192015-04-01 13:05:26 -0700372 *
373 * @param deviceId switch ID to set the rules
374 */
375 public void populateTableTMac(DeviceId deviceId) {
376
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700377 FilteringObjective.Builder fob = DefaultFilteringObjective.builder();
378 fob.withKey(Criteria.matchInPort(PortNumber.ALL))
379 .addCondition(Criteria.matchEthDst(config
380 .getDeviceMac(deviceId)));
381 fob.permit().fromApp(srManager.appId);
382 log.debug("populateTableVlan: Installing filtering objective for router mac");
Srikanth Vavilapallif3a8bc02015-05-22 13:47:31 -0700383 srManager.flowObjectiveService.
384 filter(deviceId,
385 fob.add(new SRObjectiveContext(deviceId,
386 SRObjectiveContext.ObjectiveType.FILTER)));
sanghob35a6192015-04-01 13:05:26 -0700387 }
388
sangho45b009c2015-05-07 13:30:57 -0700389 private PortNumber selectOnePort(DeviceId srcId, Set<DeviceId> destIds) {
sanghob35a6192015-04-01 13:05:26 -0700390
sangho45b009c2015-05-07 13:30:57 -0700391 Set<Link> links = srManager.linkService.getDeviceLinks(srcId);
392 for (DeviceId destId: destIds) {
393 for (Link link : links) {
394 if (link.dst().deviceId().equals(destId)) {
395 return link.src().port();
396 } else if (link.src().deviceId().equals(destId)) {
397 return link.dst().port();
398 }
sanghob35a6192015-04-01 13:05:26 -0700399 }
400 }
401
402 return null;
403 }
404
Srikanth Vavilapallif3a8bc02015-05-22 13:47:31 -0700405 private static class SRObjectiveContext implements ObjectiveContext {
406 enum ObjectiveType {
407 FILTER,
408 FORWARDING
409 }
410 final DeviceId deviceId;
411 final ObjectiveType type;
412
413 SRObjectiveContext(DeviceId deviceId, ObjectiveType type) {
414 this.deviceId = deviceId;
415 this.type = type;
416 }
417 @Override
418 public void onSuccess(Objective objective) {
419 log.debug("{} objective operation successful in device {}",
420 type.name(), deviceId);
421 }
422
423 @Override
424 public void onError(Objective objective, ObjectiveError error) {
425 log.warn("{} objective {} operation failed with error: {} in device {}",
426 type.name(), objective, error, deviceId);
427 }
428 }
429
sanghob35a6192015-04-01 13:05:26 -0700430}