blob: 7092093c700fa813bb1a3c962035957dff4fbb2c [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
sangho834e4b02015-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 Vavilapallif5b234a2015-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 "
sangho834e4b02015-05-01 09:38:25 -0700191 + "for router IP/subnet {} in switch {}",
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700192 ipPrefix,
193 deviceId);
194 srManager.flowObjectiveService.forward(deviceId, fwdBuilder.add());
sangho20eff1d2015-04-13 15:15:58 -0700195 rulePopulationCounter.incrementAndGet();
sanghob35a6192015-04-01 13:05:26 -0700196
197 return true;
198 }
199
sanghob35a6192015-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 Vavilapallif5b234a2015-04-21 13:04:13 -0700208 public boolean populateMplsRule(DeviceId deviceId, DeviceId destSwId,
209 Set<DeviceId> nextHops) {
sanghob35a6192015-04-01 13:05:26 -0700210
211 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700212 List<ForwardingObjective.Builder> fwdObjBuilders = new ArrayList<ForwardingObjective.Builder>();
sanghob35a6192015-04-01 13:05:26 -0700213
214 // TODO Handle the case of Bos == false
sangho666cd6d2015-04-14 16:27:13 -0700215 sbuilder.matchMplsLabel(MplsLabel.mplsLabel(config.getSegmentId(destSwId)));
sanghob35a6192015-04-01 13:05:26 -0700216 sbuilder.matchEthType(Ethernet.MPLS_UNICAST);
217
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700218 // If the next hop is the destination router, do PHP
sanghob35a6192015-04-01 13:05:26 -0700219 if (nextHops.size() == 1 && destSwId.equals(nextHops.toArray()[0])) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700220 log.debug("populateMplsRule: Installing MPLS forwarding objective for "
221 + "label {} in switch {} with PHP",
222 config.getSegmentId(destSwId),
223 deviceId);
224
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700225 ForwardingObjective.Builder fwdObjBosBuilder =
226 getMplsForwardingObjective(deviceId,
227 destSwId,
228 nextHops,
229 true,
230 true);
231 // TODO: Check with Sangho on why we need this
232 ForwardingObjective.Builder fwdObjNoBosBuilder =
233 getMplsForwardingObjective(deviceId,
234 destSwId,
235 nextHops,
236 true,
237 false);
238 if (fwdObjBosBuilder != null) {
239 fwdObjBuilders.add(fwdObjBosBuilder);
sanghob35a6192015-04-01 13:05:26 -0700240 } else {
241 log.warn("Failed to set MPLS rules.");
242 return false;
243 }
244 } else {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700245 log.debug("Installing MPLS forwarding objective for "
246 + "label {} in switch {} without PHP",
247 config.getSegmentId(destSwId),
248 deviceId);
249
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700250 ForwardingObjective.Builder fwdObjBosBuilder =
251 getMplsForwardingObjective(deviceId,
252 destSwId,
253 nextHops,
254 false,
255 true);
256 // TODO: Check with Sangho on why we need this
257 ForwardingObjective.Builder fwdObjNoBosBuilder =
258 getMplsForwardingObjective(deviceId,
259 destSwId,
260 nextHops,
261 false,
262 false);
263 if (fwdObjBosBuilder != null) {
264 fwdObjBuilders.add(fwdObjBosBuilder);
sanghob35a6192015-04-01 13:05:26 -0700265 } else {
266 log.warn("Failed to set MPLS rules.");
267 return false;
268 }
269 }
270
271 TrafficSelector selector = sbuilder.build();
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700272 for (ForwardingObjective.Builder fwdObjBuilder : fwdObjBuilders) {
273 ((Builder) ((Builder) fwdObjBuilder.fromApp(srManager.appId)
274 .makePermanent()).withSelector(selector)
275 .withPriority(100))
276 .withFlag(ForwardingObjective.Flag.SPECIFIC);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700277 srManager.flowObjectiveService.forward(deviceId,
278 fwdObjBuilder.add());
sangho20eff1d2015-04-13 15:15:58 -0700279 rulePopulationCounter.incrementAndGet();
sanghob35a6192015-04-01 13:05:26 -0700280 }
281
282 return true;
283 }
284
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700285 private ForwardingObjective.Builder getMplsForwardingObjective(DeviceId deviceId,
286 DeviceId destSw,
287 Set<DeviceId> nextHops,
288 boolean phpRequired,
289 boolean isBos) {
sanghob35a6192015-04-01 13:05:26 -0700290
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700291 ForwardingObjective.Builder fwdBuilder = DefaultForwardingObjective
292 .builder().withFlag(ForwardingObjective.Flag.SPECIFIC);
sanghob35a6192015-04-01 13:05:26 -0700293
294 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
295
296 if (phpRequired) {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700297 log.debug("getMplsForwardingObjective: php required");
sanghob35a6192015-04-01 13:05:26 -0700298 tbuilder.copyTtlIn();
299 if (isBos) {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700300 tbuilder.popMpls(Ethernet.TYPE_IPV4).decNwTtl();
sanghob35a6192015-04-01 13:05:26 -0700301 } else {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700302 tbuilder.popMpls(Ethernet.MPLS_UNICAST).decMplsTtl();
sanghob35a6192015-04-01 13:05:26 -0700303 }
304 } else {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700305 log.debug("getMplsForwardingObjective: php not required");
sanghob35a6192015-04-01 13:05:26 -0700306 tbuilder.decMplsTtl();
307 }
308
sangho666cd6d2015-04-14 16:27:13 -0700309 if (!isECMPSupportedInTransitRouter() && !config.isEdgeDevice(deviceId)) {
sangho45b009c2015-05-07 13:30:57 -0700310 PortNumber port = selectOnePort(deviceId, nextHops);
sangho666cd6d2015-04-14 16:27:13 -0700311 DeviceId nextHop = (DeviceId) nextHops.toArray()[0];
sangho45b009c2015-05-07 13:30:57 -0700312 if (port == null) {
sanghob35a6192015-04-01 13:05:26 -0700313 log.warn("No link from {} to {}", deviceId, nextHops);
314 return null;
315 }
sangho666cd6d2015-04-14 16:27:13 -0700316 tbuilder.setEthSrc(config.getDeviceMac(deviceId))
317 .setEthDst(config.getDeviceMac(nextHop))
sangho45b009c2015-05-07 13:30:57 -0700318 .setOutput(port);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700319 fwdBuilder.withTreatment(tbuilder.build());
sanghob35a6192015-04-01 13:05:26 -0700320 } else {
321 NeighborSet ns = new NeighborSet(nextHops);
sangho5f1e4572015-05-06 11:42:31 -0700322 fwdBuilder.withTreatment(tbuilder.build());
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700323 fwdBuilder.nextStep(srManager
324 .getNextObjectiveId(deviceId, ns));
sanghob35a6192015-04-01 13:05:26 -0700325 }
326
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700327 return fwdBuilder;
sanghob35a6192015-04-01 13:05:26 -0700328 }
329
sangho666cd6d2015-04-14 16:27:13 -0700330 private boolean isECMPSupportedInTransitRouter() {
331
332 // TODO: remove this function when objectives subsystem is supported.
333 return false;
334 }
335
sanghob35a6192015-04-01 13:05:26 -0700336 /**
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700337 * Populates VLAN flows rules. All packets are forwarded to TMAC table.
sanghob35a6192015-04-01 13:05:26 -0700338 *
339 * @param deviceId switch ID to set the rules
340 */
341 public void populateTableVlan(DeviceId deviceId) {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700342 FilteringObjective.Builder fob = DefaultFilteringObjective.builder();
343 fob.withKey(Criteria.matchInPort(PortNumber.ALL))
344 .addCondition(Criteria.matchVlanId(VlanId.NONE));
345 fob.permit().fromApp(srManager.appId);
346 log.debug("populateTableVlan: Installing filtering objective for untagged packets");
347 srManager.flowObjectiveService.filter(deviceId, fob.add());
sanghob35a6192015-04-01 13:05:26 -0700348 }
349
350 /**
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700351 * Populates TMAC table rules. IP packets are forwarded to IP table. MPLS
352 * packets are forwarded to MPLS table.
sanghob35a6192015-04-01 13:05:26 -0700353 *
354 * @param deviceId switch ID to set the rules
355 */
356 public void populateTableTMac(DeviceId deviceId) {
357
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700358 FilteringObjective.Builder fob = DefaultFilteringObjective.builder();
359 fob.withKey(Criteria.matchInPort(PortNumber.ALL))
360 .addCondition(Criteria.matchEthDst(config
361 .getDeviceMac(deviceId)));
362 fob.permit().fromApp(srManager.appId);
363 log.debug("populateTableVlan: Installing filtering objective for router mac");
364 srManager.flowObjectiveService.filter(deviceId, fob.add());
sanghob35a6192015-04-01 13:05:26 -0700365 }
366
sangho45b009c2015-05-07 13:30:57 -0700367 private PortNumber selectOnePort(DeviceId srcId, Set<DeviceId> destIds) {
sanghob35a6192015-04-01 13:05:26 -0700368
sangho45b009c2015-05-07 13:30:57 -0700369 Set<Link> links = srManager.linkService.getDeviceLinks(srcId);
370 for (DeviceId destId: destIds) {
371 for (Link link : links) {
372 if (link.dst().deviceId().equals(destId)) {
373 return link.src().port();
374 } else if (link.src().deviceId().equals(destId)) {
375 return link.dst().port();
376 }
sanghob35a6192015-04-01 13:05:26 -0700377 }
378 }
379
380 return null;
381 }
382
383}