blob: 5fd1c85d69d7acece2d4cee52c90cdd8032c543d [file] [log] [blame]
Sho SHIMIZUee2aa652015-02-25 18:56:43 -08001/*
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.net.intent.impl.compiler;
Michele Santuari4b6019e2014-12-19 11:31:45 +010017
Brian O'Connor64a0369d2015-02-20 22:02:59 -080018import com.google.common.collect.Sets;
Dusan Pajin6b887c92015-07-01 18:32:49 +020019
Michele Santuari4b6019e2014-12-19 11:31:45 +010020import org.apache.felix.scr.annotations.Activate;
21import org.apache.felix.scr.annotations.Component;
22import org.apache.felix.scr.annotations.Deactivate;
23import org.apache.felix.scr.annotations.Reference;
24import org.apache.felix.scr.annotations.ReferenceCardinality;
Michele Santuari316d8cf2015-07-14 17:24:54 +020025import org.onlab.packet.EthType;
Michele Santuari4b6019e2014-12-19 11:31:45 +010026import org.onlab.packet.Ethernet;
Dusan Pajin6b887c92015-07-01 18:32:49 +020027import org.onlab.packet.VlanId;
Michele Santuari4b6019e2014-12-19 11:31:45 +010028import org.onosproject.core.ApplicationId;
29import org.onosproject.core.CoreService;
30import org.onosproject.net.ConnectPoint;
31import org.onosproject.net.DeviceId;
32import org.onosproject.net.Link;
33import org.onosproject.net.PortNumber;
34import org.onosproject.net.flow.DefaultFlowRule;
35import org.onosproject.net.flow.DefaultTrafficSelector;
36import org.onosproject.net.flow.DefaultTrafficTreatment;
37import org.onosproject.net.flow.FlowRule;
Michele Santuari4b6019e2014-12-19 11:31:45 +010038import org.onosproject.net.flow.TrafficSelector;
39import org.onosproject.net.flow.TrafficTreatment;
Michele Santuari4b6019e2014-12-19 11:31:45 +010040import org.onosproject.net.flow.criteria.Criterion;
Sho SHIMIZUfbc80e52015-04-28 10:41:58 -070041import org.onosproject.net.flow.criteria.EthTypeCriterion;
Dusan Pajin6b887c92015-07-01 18:32:49 +020042import org.onosproject.net.flow.instructions.Instruction;
43import org.onosproject.net.flow.instructions.L2ModificationInstruction;
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080044import org.onosproject.net.intent.FlowRuleIntent;
45import org.onosproject.net.intent.Intent;
46import org.onosproject.net.intent.IntentCompiler;
Michele Santuari4b6019e2014-12-19 11:31:45 +010047import org.onosproject.net.intent.IntentExtensionService;
Michele Santuari4b6019e2014-12-19 11:31:45 +010048import org.onosproject.net.intent.MplsPathIntent;
49import org.onosproject.net.link.LinkStore;
Brian O'Connor6de2e202015-05-21 14:30:41 -070050import org.onosproject.net.resource.link.DefaultLinkResourceRequest;
51import org.onosproject.net.resource.link.LinkResourceAllocations;
52import org.onosproject.net.resource.link.LinkResourceRequest;
53import org.onosproject.net.resource.link.LinkResourceService;
54import org.onosproject.net.resource.link.MplsLabel;
55import org.onosproject.net.resource.link.MplsLabelResourceAllocation;
Michele Santuari4b6019e2014-12-19 11:31:45 +010056import org.onosproject.net.resource.ResourceAllocation;
57import org.onosproject.net.resource.ResourceType;
58import org.slf4j.Logger;
59
Sho SHIMIZU98ffca82015-05-11 08:39:24 -070060import java.util.Collections;
Brian O'Connor64a0369d2015-02-20 22:02:59 -080061import java.util.Iterator;
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080062import java.util.LinkedList;
Brian O'Connor64a0369d2015-02-20 22:02:59 -080063import java.util.List;
64import java.util.Set;
Michele Santuari4b6019e2014-12-19 11:31:45 +010065
Ray Milkey71ade562015-02-18 15:08:07 -080066import static com.google.common.base.Preconditions.checkNotNull;
67import static org.slf4j.LoggerFactory.getLogger;
68
Michele Santuari4b6019e2014-12-19 11:31:45 +010069@Component(immediate = true)
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080070public class MplsPathIntentCompiler implements IntentCompiler<MplsPathIntent> {
Michele Santuari4b6019e2014-12-19 11:31:45 +010071
72 private final Logger log = getLogger(getClass());
73
74 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080075 protected IntentExtensionService intentExtensionService;
Michele Santuari4b6019e2014-12-19 11:31:45 +010076
77 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
78 protected CoreService coreService;
79
80 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
81 protected LinkResourceService resourceService;
82
83 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
84 protected LinkStore linkStore;
85
86 protected ApplicationId appId;
87
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080088 @Override
89 public List<Intent> compile(MplsPathIntent intent, List<Intent> installable,
90 Set<LinkResourceAllocations> resources) {
91 LinkResourceAllocations allocations = assignMplsLabel(intent);
92 List<FlowRule> rules = generateRules(intent, allocations);
93
Sho SHIMIZU98ffca82015-05-11 08:39:24 -070094 return Collections.singletonList(new FlowRuleIntent(appId, rules, intent.resources()));
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080095 }
96
Michele Santuari4b6019e2014-12-19 11:31:45 +010097 @Activate
98 public void activate() {
99 appId = coreService.registerApplication("org.onosproject.net.intent");
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800100 intentExtensionService.registerCompiler(MplsPathIntent.class, this);
Michele Santuari4b6019e2014-12-19 11:31:45 +0100101 }
102
103 @Deactivate
104 public void deactivate() {
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800105 intentExtensionService.unregisterCompiler(MplsPathIntent.class);
Michele Santuari4b6019e2014-12-19 11:31:45 +0100106 }
107
108 private LinkResourceAllocations assignMplsLabel(MplsPathIntent intent) {
Michele Santuari4b6019e2014-12-19 11:31:45 +0100109 // TODO: do it better... Suggestions?
110 Set<Link> linkRequest = Sets.newHashSetWithExpectedSize(intent.path()
111 .links().size() - 2);
112 for (int i = 1; i <= intent.path().links().size() - 2; i++) {
113 Link link = intent.path().links().get(i);
114 linkRequest.add(link);
115 // add the inverse link. I want that the label is reserved both for
116 // the direct and inverse link
117 linkRequest.add(linkStore.getLink(link.dst(), link.src()));
118 }
119
120 LinkResourceRequest.Builder request = DefaultLinkResourceRequest
121 .builder(intent.id(), linkRequest).addMplsRequest();
122 LinkResourceAllocations reqMpls = resourceService
123 .requestResources(request.build());
124 return reqMpls;
125 }
126
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800127 private MplsLabel getMplsLabel(LinkResourceAllocations allocations, Link link) {
Michele Santuari4b6019e2014-12-19 11:31:45 +0100128 for (ResourceAllocation allocation : allocations
129 .getResourceAllocation(link)) {
130 if (allocation.type() == ResourceType.MPLS_LABEL) {
131 return ((MplsLabelResourceAllocation) allocation).mplsLabel();
132
133 }
134 }
135 log.warn("MPLS label was not assigned successfully");
136 return null;
137 }
138
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800139 private List<FlowRule> generateRules(MplsPathIntent intent,
140 LinkResourceAllocations allocations) {
Michele Santuari4b6019e2014-12-19 11:31:45 +0100141
142 Iterator<Link> links = intent.path().links().iterator();
143 Link srcLink = links.next();
144 ConnectPoint prev = srcLink.dst();
145
146 Link link = links.next();
147 // List of flow rules to be installed
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800148 List<FlowRule> rules = new LinkedList<>();
Michele Santuari4b6019e2014-12-19 11:31:45 +0100149
150 // Ingress traffic
151 // Get the new MPLS label
152 MplsLabel mpls = getMplsLabel(allocations, link);
153 checkNotNull(mpls);
154 MplsLabel prevLabel = mpls;
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800155 rules.add(ingressFlow(prev.port(), link, intent, mpls));
Michele Santuari4b6019e2014-12-19 11:31:45 +0100156
157 prev = link.dst();
158
159 while (links.hasNext()) {
160
161 link = links.next();
162
163 if (links.hasNext()) {
164 // Transit traffic
165 // Get the new MPLS label
166 mpls = getMplsLabel(allocations, link);
167 checkNotNull(mpls);
168 rules.add(transitFlow(prev.port(), link, intent,
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800169 prevLabel, mpls));
Michele Santuari4b6019e2014-12-19 11:31:45 +0100170 prevLabel = mpls;
171
172 } else {
173 // Egress traffic
174 rules.add(egressFlow(prev.port(), link, intent,
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800175 prevLabel));
Michele Santuari4b6019e2014-12-19 11:31:45 +0100176 }
177
178 prev = link.dst();
179 }
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800180 return rules;
Michele Santuari4b6019e2014-12-19 11:31:45 +0100181 }
182
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800183 private FlowRule ingressFlow(PortNumber inPort, Link link,
184 MplsPathIntent intent, MplsLabel label) {
Michele Santuari4b6019e2014-12-19 11:31:45 +0100185
186 TrafficSelector.Builder ingressSelector = DefaultTrafficSelector
187 .builder(intent.selector());
188 TrafficTreatment.Builder treat = DefaultTrafficTreatment.builder();
189 ingressSelector.matchInPort(inPort);
190
191 if (intent.ingressLabel().isPresent()) {
192 ingressSelector.matchEthType(Ethernet.MPLS_UNICAST)
193 .matchMplsLabel(intent.ingressLabel().get());
194
195 // Swap the MPLS label
196 treat.setMpls(label.label());
197 } else {
198 // Push and set the MPLS label
199 treat.pushMpls().setMpls(label.label());
200 }
201 // Add the output action
202 treat.setOutput(link.src().port());
203
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800204 return createFlowRule(intent, link.src().deviceId(), ingressSelector.build(), treat.build());
Michele Santuari4b6019e2014-12-19 11:31:45 +0100205 }
206
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800207 private FlowRule transitFlow(PortNumber inPort, Link link,
208 MplsPathIntent intent,
209 MplsLabel prevLabel,
210 MplsLabel outLabel) {
Michele Santuari4b6019e2014-12-19 11:31:45 +0100211
212 // Ignore the ingress Traffic Selector and use only the MPLS label
213 // assigned in the previous link
214 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
215 selector.matchInPort(inPort).matchEthType(Ethernet.MPLS_UNICAST)
216 .matchMplsLabel(prevLabel.label());
217 TrafficTreatment.Builder treat = DefaultTrafficTreatment.builder();
218
219 // Set the new label only if the label on the packet is
220 // different
Michele Santuari316d8cf2015-07-14 17:24:54 +0200221 if (!prevLabel.equals(outLabel)) {
Michele Santuari4b6019e2014-12-19 11:31:45 +0100222 treat.setMpls(outLabel.label());
223 }
224
225 treat.setOutput(link.src().port());
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800226 return createFlowRule(intent, link.src().deviceId(), selector.build(), treat.build());
Michele Santuari4b6019e2014-12-19 11:31:45 +0100227 }
228
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800229 private FlowRule egressFlow(PortNumber inPort, Link link,
230 MplsPathIntent intent,
231 MplsLabel prevLabel) {
Michele Santuari4b6019e2014-12-19 11:31:45 +0100232 // egress point: either set the egress MPLS label or pop the
233 // MPLS label based on the intent annotations
234
235 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
236 selector.matchInPort(inPort).matchEthType(Ethernet.MPLS_UNICAST)
237 .matchMplsLabel(prevLabel.label());
238
239 // apply the intent's treatments
240 TrafficTreatment.Builder treat = DefaultTrafficTreatment.builder(intent
241 .treatment());
242
Dusan Pajin6b887c92015-07-01 18:32:49 +0200243 // check if the treatement is popVlan or setVlan (rewrite),
244 // than selector needs to match any VlanId
245 for (Instruction instruct : intent.treatment().allInstructions()) {
246 if (instruct instanceof L2ModificationInstruction) {
247 L2ModificationInstruction l2Mod = (L2ModificationInstruction) instruct;
248 if (l2Mod.subtype() == L2ModificationInstruction.L2SubType.VLAN_PUSH) {
249 break;
250 }
251 if (l2Mod.subtype() == L2ModificationInstruction.L2SubType.VLAN_POP ||
252 l2Mod.subtype() == L2ModificationInstruction.L2SubType.VLAN_ID) {
253 selector.matchVlanId(VlanId.ANY);
254 }
255 }
256 }
257
Michele Santuari4b6019e2014-12-19 11:31:45 +0100258 if (intent.egressLabel().isPresent()) {
259 treat.setMpls(intent.egressLabel().get());
260 } else {
Michele Santuari316d8cf2015-07-14 17:24:54 +0200261 treat.popMpls(outputEthType(intent.selector()));
Michele Santuari4b6019e2014-12-19 11:31:45 +0100262 }
263 treat.setOutput(link.src().port());
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800264 return createFlowRule(intent, link.src().deviceId(),
265 selector.build(), treat.build());
Michele Santuari4b6019e2014-12-19 11:31:45 +0100266 }
267
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800268 protected FlowRule createFlowRule(MplsPathIntent intent, DeviceId deviceId,
269 TrafficSelector selector, TrafficTreatment treat) {
Ray Milkeyd13a37b2015-06-12 11:55:17 -0700270 return DefaultFlowRule.builder()
271 .forDevice(deviceId)
272 .withSelector(selector)
273 .withTreatment(treat)
274 .withPriority(intent.priority())
275 .fromApp(appId)
276 .makePermanent()
277 .build();
Michele Santuari4b6019e2014-12-19 11:31:45 +0100278 }
Michele Santuari316d8cf2015-07-14 17:24:54 +0200279
280 // if the ingress ethertype is defined, the egress traffic
281 // will be use that value, otherwise the IPv4 ethertype is used.
282 private EthType outputEthType(TrafficSelector selector) {
283 Criterion c = selector.getCriterion(Criterion.Type.ETH_TYPE);
284 if (c != null && c instanceof EthTypeCriterion) {
285 EthTypeCriterion ethertype = (EthTypeCriterion) c;
286 return ethertype.ethType();
287 } else {
288 return EthType.EtherType.IPV4.ethType();
289 }
290 }
Michele Santuari4b6019e2014-12-19 11:31:45 +0100291}