blob: eac46cc9a56f89e7734da20f4db52ce0aceaed35 [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;
25import org.onlab.packet.Ethernet;
Dusan Pajin6b887c92015-07-01 18:32:49 +020026import org.onlab.packet.VlanId;
Michele Santuari4b6019e2014-12-19 11:31:45 +010027import org.onosproject.core.ApplicationId;
28import org.onosproject.core.CoreService;
29import org.onosproject.net.ConnectPoint;
30import org.onosproject.net.DeviceId;
31import org.onosproject.net.Link;
32import org.onosproject.net.PortNumber;
33import org.onosproject.net.flow.DefaultFlowRule;
34import org.onosproject.net.flow.DefaultTrafficSelector;
35import org.onosproject.net.flow.DefaultTrafficTreatment;
36import org.onosproject.net.flow.FlowRule;
Michele Santuari4b6019e2014-12-19 11:31:45 +010037import org.onosproject.net.flow.TrafficSelector;
38import org.onosproject.net.flow.TrafficTreatment;
Michele Santuari4b6019e2014-12-19 11:31:45 +010039import org.onosproject.net.flow.criteria.Criterion;
Sho SHIMIZUfbc80e52015-04-28 10:41:58 -070040import org.onosproject.net.flow.criteria.EthTypeCriterion;
Dusan Pajin6b887c92015-07-01 18:32:49 +020041import org.onosproject.net.flow.instructions.Instruction;
42import org.onosproject.net.flow.instructions.L2ModificationInstruction;
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080043import org.onosproject.net.intent.FlowRuleIntent;
44import org.onosproject.net.intent.Intent;
45import org.onosproject.net.intent.IntentCompiler;
Michele Santuari4b6019e2014-12-19 11:31:45 +010046import org.onosproject.net.intent.IntentExtensionService;
Michele Santuari4b6019e2014-12-19 11:31:45 +010047import org.onosproject.net.intent.MplsPathIntent;
48import org.onosproject.net.link.LinkStore;
Brian O'Connor6de2e202015-05-21 14:30:41 -070049import org.onosproject.net.resource.link.DefaultLinkResourceRequest;
50import org.onosproject.net.resource.link.LinkResourceAllocations;
51import org.onosproject.net.resource.link.LinkResourceRequest;
52import org.onosproject.net.resource.link.LinkResourceService;
53import org.onosproject.net.resource.link.MplsLabel;
54import org.onosproject.net.resource.link.MplsLabelResourceAllocation;
Michele Santuari4b6019e2014-12-19 11:31:45 +010055import org.onosproject.net.resource.ResourceAllocation;
56import org.onosproject.net.resource.ResourceType;
57import org.slf4j.Logger;
58
Sho SHIMIZU98ffca82015-05-11 08:39:24 -070059import java.util.Collections;
Brian O'Connor64a0369d2015-02-20 22:02:59 -080060import java.util.Iterator;
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080061import java.util.LinkedList;
Brian O'Connor64a0369d2015-02-20 22:02:59 -080062import java.util.List;
63import java.util.Set;
Michele Santuari4b6019e2014-12-19 11:31:45 +010064
Ray Milkey71ade562015-02-18 15:08:07 -080065import static com.google.common.base.Preconditions.checkNotNull;
66import static org.slf4j.LoggerFactory.getLogger;
67
Michele Santuari4b6019e2014-12-19 11:31:45 +010068@Component(immediate = true)
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080069public class MplsPathIntentCompiler implements IntentCompiler<MplsPathIntent> {
Michele Santuari4b6019e2014-12-19 11:31:45 +010070
71 private final Logger log = getLogger(getClass());
72
73 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080074 protected IntentExtensionService intentExtensionService;
Michele Santuari4b6019e2014-12-19 11:31:45 +010075
76 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
77 protected CoreService coreService;
78
79 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
80 protected LinkResourceService resourceService;
81
82 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
83 protected LinkStore linkStore;
84
85 protected ApplicationId appId;
86
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080087 @Override
88 public List<Intent> compile(MplsPathIntent intent, List<Intent> installable,
89 Set<LinkResourceAllocations> resources) {
90 LinkResourceAllocations allocations = assignMplsLabel(intent);
91 List<FlowRule> rules = generateRules(intent, allocations);
92
Sho SHIMIZU98ffca82015-05-11 08:39:24 -070093 return Collections.singletonList(new FlowRuleIntent(appId, rules, intent.resources()));
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080094 }
95
Michele Santuari4b6019e2014-12-19 11:31:45 +010096 @Activate
97 public void activate() {
98 appId = coreService.registerApplication("org.onosproject.net.intent");
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080099 intentExtensionService.registerCompiler(MplsPathIntent.class, this);
Michele Santuari4b6019e2014-12-19 11:31:45 +0100100 }
101
102 @Deactivate
103 public void deactivate() {
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800104 intentExtensionService.unregisterCompiler(MplsPathIntent.class);
Michele Santuari4b6019e2014-12-19 11:31:45 +0100105 }
106
107 private LinkResourceAllocations assignMplsLabel(MplsPathIntent intent) {
Michele Santuari4b6019e2014-12-19 11:31:45 +0100108 // TODO: do it better... Suggestions?
109 Set<Link> linkRequest = Sets.newHashSetWithExpectedSize(intent.path()
110 .links().size() - 2);
111 for (int i = 1; i <= intent.path().links().size() - 2; i++) {
112 Link link = intent.path().links().get(i);
113 linkRequest.add(link);
114 // add the inverse link. I want that the label is reserved both for
115 // the direct and inverse link
116 linkRequest.add(linkStore.getLink(link.dst(), link.src()));
117 }
118
119 LinkResourceRequest.Builder request = DefaultLinkResourceRequest
120 .builder(intent.id(), linkRequest).addMplsRequest();
121 LinkResourceAllocations reqMpls = resourceService
122 .requestResources(request.build());
123 return reqMpls;
124 }
125
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800126 private MplsLabel getMplsLabel(LinkResourceAllocations allocations, Link link) {
Michele Santuari4b6019e2014-12-19 11:31:45 +0100127 for (ResourceAllocation allocation : allocations
128 .getResourceAllocation(link)) {
129 if (allocation.type() == ResourceType.MPLS_LABEL) {
130 return ((MplsLabelResourceAllocation) allocation).mplsLabel();
131
132 }
133 }
134 log.warn("MPLS label was not assigned successfully");
135 return null;
136 }
137
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800138 private List<FlowRule> generateRules(MplsPathIntent intent,
139 LinkResourceAllocations allocations) {
Michele Santuari4b6019e2014-12-19 11:31:45 +0100140
141 Iterator<Link> links = intent.path().links().iterator();
142 Link srcLink = links.next();
143 ConnectPoint prev = srcLink.dst();
144
145 Link link = links.next();
146 // List of flow rules to be installed
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800147 List<FlowRule> rules = new LinkedList<>();
Michele Santuari4b6019e2014-12-19 11:31:45 +0100148
149 // Ingress traffic
150 // Get the new MPLS label
151 MplsLabel mpls = getMplsLabel(allocations, link);
152 checkNotNull(mpls);
153 MplsLabel prevLabel = mpls;
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800154 rules.add(ingressFlow(prev.port(), link, intent, mpls));
Michele Santuari4b6019e2014-12-19 11:31:45 +0100155
156 prev = link.dst();
157
158 while (links.hasNext()) {
159
160 link = links.next();
161
162 if (links.hasNext()) {
163 // Transit traffic
164 // Get the new MPLS label
165 mpls = getMplsLabel(allocations, link);
166 checkNotNull(mpls);
167 rules.add(transitFlow(prev.port(), link, intent,
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800168 prevLabel, mpls));
Michele Santuari4b6019e2014-12-19 11:31:45 +0100169 prevLabel = mpls;
170
171 } else {
172 // Egress traffic
173 rules.add(egressFlow(prev.port(), link, intent,
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800174 prevLabel));
Michele Santuari4b6019e2014-12-19 11:31:45 +0100175 }
176
177 prev = link.dst();
178 }
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800179 return rules;
Michele Santuari4b6019e2014-12-19 11:31:45 +0100180 }
181
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800182 private FlowRule ingressFlow(PortNumber inPort, Link link,
183 MplsPathIntent intent, MplsLabel label) {
Michele Santuari4b6019e2014-12-19 11:31:45 +0100184
185 TrafficSelector.Builder ingressSelector = DefaultTrafficSelector
186 .builder(intent.selector());
187 TrafficTreatment.Builder treat = DefaultTrafficTreatment.builder();
188 ingressSelector.matchInPort(inPort);
189
190 if (intent.ingressLabel().isPresent()) {
191 ingressSelector.matchEthType(Ethernet.MPLS_UNICAST)
192 .matchMplsLabel(intent.ingressLabel().get());
193
194 // Swap the MPLS label
195 treat.setMpls(label.label());
196 } else {
197 // Push and set the MPLS label
198 treat.pushMpls().setMpls(label.label());
199 }
200 // Add the output action
201 treat.setOutput(link.src().port());
202
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800203 return createFlowRule(intent, link.src().deviceId(), ingressSelector.build(), treat.build());
Michele Santuari4b6019e2014-12-19 11:31:45 +0100204 }
205
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800206 private FlowRule transitFlow(PortNumber inPort, Link link,
207 MplsPathIntent intent,
208 MplsLabel prevLabel,
209 MplsLabel outLabel) {
Michele Santuari4b6019e2014-12-19 11:31:45 +0100210
211 // Ignore the ingress Traffic Selector and use only the MPLS label
212 // assigned in the previous link
213 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
214 selector.matchInPort(inPort).matchEthType(Ethernet.MPLS_UNICAST)
215 .matchMplsLabel(prevLabel.label());
216 TrafficTreatment.Builder treat = DefaultTrafficTreatment.builder();
217
218 // Set the new label only if the label on the packet is
219 // different
220 if (prevLabel.equals(outLabel)) {
221 treat.setMpls(outLabel.label());
222 }
223
224 treat.setOutput(link.src().port());
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800225 return createFlowRule(intent, link.src().deviceId(), selector.build(), treat.build());
Michele Santuari4b6019e2014-12-19 11:31:45 +0100226 }
227
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800228 private FlowRule egressFlow(PortNumber inPort, Link link,
229 MplsPathIntent intent,
230 MplsLabel prevLabel) {
Michele Santuari4b6019e2014-12-19 11:31:45 +0100231 // egress point: either set the egress MPLS label or pop the
232 // MPLS label based on the intent annotations
233
234 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
235 selector.matchInPort(inPort).matchEthType(Ethernet.MPLS_UNICAST)
236 .matchMplsLabel(prevLabel.label());
237
238 // apply the intent's treatments
239 TrafficTreatment.Builder treat = DefaultTrafficTreatment.builder(intent
240 .treatment());
241
Dusan Pajin6b887c92015-07-01 18:32:49 +0200242 // check if the treatement is popVlan or setVlan (rewrite),
243 // than selector needs to match any VlanId
244 for (Instruction instruct : intent.treatment().allInstructions()) {
245 if (instruct instanceof L2ModificationInstruction) {
246 L2ModificationInstruction l2Mod = (L2ModificationInstruction) instruct;
247 if (l2Mod.subtype() == L2ModificationInstruction.L2SubType.VLAN_PUSH) {
248 break;
249 }
250 if (l2Mod.subtype() == L2ModificationInstruction.L2SubType.VLAN_POP ||
251 l2Mod.subtype() == L2ModificationInstruction.L2SubType.VLAN_ID) {
252 selector.matchVlanId(VlanId.ANY);
253 }
254 }
255 }
256
Michele Santuari4b6019e2014-12-19 11:31:45 +0100257 if (intent.egressLabel().isPresent()) {
258 treat.setMpls(intent.egressLabel().get());
259 } else {
260 // if the ingress ethertype is defined, the egress traffic
261 // will be use that value, otherwise the IPv4 ethertype is used.
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800262 Criterion c = intent.selector().getCriterion(Criterion.Type.ETH_TYPE);
Sho SHIMIZUfbc80e52015-04-28 10:41:58 -0700263 if (c != null && c instanceof EthTypeCriterion) {
264 EthTypeCriterion ethertype = (EthTypeCriterion) c;
alshabibcaf1ca22015-06-25 15:18:16 -0700265 treat.popMpls(ethertype.ethType().toShort());
Michele Santuari4b6019e2014-12-19 11:31:45 +0100266 } else {
267 treat.popMpls(Ethernet.TYPE_IPV4);
268 }
269
270 }
271 treat.setOutput(link.src().port());
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800272 return createFlowRule(intent, link.src().deviceId(),
273 selector.build(), treat.build());
Michele Santuari4b6019e2014-12-19 11:31:45 +0100274 }
275
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800276 protected FlowRule createFlowRule(MplsPathIntent intent, DeviceId deviceId,
277 TrafficSelector selector, TrafficTreatment treat) {
Ray Milkeyd13a37b2015-06-12 11:55:17 -0700278 return DefaultFlowRule.builder()
279 .forDevice(deviceId)
280 .withSelector(selector)
281 .withTreatment(treat)
282 .withPriority(intent.priority())
283 .fromApp(appId)
284 .makePermanent()
285 .build();
Michele Santuari4b6019e2014-12-19 11:31:45 +0100286 }
287}