blob: d6eae35dcc2cb56df6e09d33bbff4345e6911fc1 [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;
Michele Santuari4b6019e2014-12-19 11:31:45 +010019import org.apache.felix.scr.annotations.Activate;
20import org.apache.felix.scr.annotations.Component;
21import org.apache.felix.scr.annotations.Deactivate;
22import org.apache.felix.scr.annotations.Reference;
23import org.apache.felix.scr.annotations.ReferenceCardinality;
24import org.onlab.packet.Ethernet;
25import org.onosproject.core.ApplicationId;
26import org.onosproject.core.CoreService;
27import org.onosproject.net.ConnectPoint;
28import org.onosproject.net.DeviceId;
29import org.onosproject.net.Link;
30import org.onosproject.net.PortNumber;
31import org.onosproject.net.flow.DefaultFlowRule;
32import org.onosproject.net.flow.DefaultTrafficSelector;
33import org.onosproject.net.flow.DefaultTrafficTreatment;
34import org.onosproject.net.flow.FlowRule;
Michele Santuari4b6019e2014-12-19 11:31:45 +010035import org.onosproject.net.flow.TrafficSelector;
36import org.onosproject.net.flow.TrafficTreatment;
Michele Santuari4b6019e2014-12-19 11:31:45 +010037import org.onosproject.net.flow.criteria.Criterion;
Sho SHIMIZUfbc80e52015-04-28 10:41:58 -070038import org.onosproject.net.flow.criteria.EthTypeCriterion;
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080039import org.onosproject.net.intent.FlowRuleIntent;
40import org.onosproject.net.intent.Intent;
41import org.onosproject.net.intent.IntentCompiler;
Michele Santuari4b6019e2014-12-19 11:31:45 +010042import org.onosproject.net.intent.IntentExtensionService;
Michele Santuari4b6019e2014-12-19 11:31:45 +010043import org.onosproject.net.intent.MplsPathIntent;
44import org.onosproject.net.link.LinkStore;
Brian O'Connor6de2e202015-05-21 14:30:41 -070045import org.onosproject.net.resource.link.DefaultLinkResourceRequest;
46import org.onosproject.net.resource.link.LinkResourceAllocations;
47import org.onosproject.net.resource.link.LinkResourceRequest;
48import org.onosproject.net.resource.link.LinkResourceService;
49import org.onosproject.net.resource.link.MplsLabel;
50import org.onosproject.net.resource.link.MplsLabelResourceAllocation;
Michele Santuari4b6019e2014-12-19 11:31:45 +010051import org.onosproject.net.resource.ResourceAllocation;
52import org.onosproject.net.resource.ResourceType;
53import org.slf4j.Logger;
54
Sho SHIMIZU98ffca82015-05-11 08:39:24 -070055import java.util.Collections;
Brian O'Connor64a0369d2015-02-20 22:02:59 -080056import java.util.Iterator;
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080057import java.util.LinkedList;
Brian O'Connor64a0369d2015-02-20 22:02:59 -080058import java.util.List;
59import java.util.Set;
Michele Santuari4b6019e2014-12-19 11:31:45 +010060
Ray Milkey71ade562015-02-18 15:08:07 -080061import static com.google.common.base.Preconditions.checkNotNull;
62import static org.slf4j.LoggerFactory.getLogger;
63
Michele Santuari4b6019e2014-12-19 11:31:45 +010064@Component(immediate = true)
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080065public class MplsPathIntentCompiler implements IntentCompiler<MplsPathIntent> {
Michele Santuari4b6019e2014-12-19 11:31:45 +010066
67 private final Logger log = getLogger(getClass());
68
69 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080070 protected IntentExtensionService intentExtensionService;
Michele Santuari4b6019e2014-12-19 11:31:45 +010071
72 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
73 protected CoreService coreService;
74
75 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
76 protected LinkResourceService resourceService;
77
78 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
79 protected LinkStore linkStore;
80
81 protected ApplicationId appId;
82
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080083 @Override
84 public List<Intent> compile(MplsPathIntent intent, List<Intent> installable,
85 Set<LinkResourceAllocations> resources) {
86 LinkResourceAllocations allocations = assignMplsLabel(intent);
87 List<FlowRule> rules = generateRules(intent, allocations);
88
Sho SHIMIZU98ffca82015-05-11 08:39:24 -070089 return Collections.singletonList(new FlowRuleIntent(appId, rules, intent.resources()));
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080090 }
91
Michele Santuari4b6019e2014-12-19 11:31:45 +010092 @Activate
93 public void activate() {
94 appId = coreService.registerApplication("org.onosproject.net.intent");
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080095 intentExtensionService.registerCompiler(MplsPathIntent.class, this);
Michele Santuari4b6019e2014-12-19 11:31:45 +010096 }
97
98 @Deactivate
99 public void deactivate() {
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800100 intentExtensionService.unregisterCompiler(MplsPathIntent.class);
Michele Santuari4b6019e2014-12-19 11:31:45 +0100101 }
102
103 private LinkResourceAllocations assignMplsLabel(MplsPathIntent intent) {
Michele Santuari4b6019e2014-12-19 11:31:45 +0100104 // TODO: do it better... Suggestions?
105 Set<Link> linkRequest = Sets.newHashSetWithExpectedSize(intent.path()
106 .links().size() - 2);
107 for (int i = 1; i <= intent.path().links().size() - 2; i++) {
108 Link link = intent.path().links().get(i);
109 linkRequest.add(link);
110 // add the inverse link. I want that the label is reserved both for
111 // the direct and inverse link
112 linkRequest.add(linkStore.getLink(link.dst(), link.src()));
113 }
114
115 LinkResourceRequest.Builder request = DefaultLinkResourceRequest
116 .builder(intent.id(), linkRequest).addMplsRequest();
117 LinkResourceAllocations reqMpls = resourceService
118 .requestResources(request.build());
119 return reqMpls;
120 }
121
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800122 private MplsLabel getMplsLabel(LinkResourceAllocations allocations, Link link) {
Michele Santuari4b6019e2014-12-19 11:31:45 +0100123 for (ResourceAllocation allocation : allocations
124 .getResourceAllocation(link)) {
125 if (allocation.type() == ResourceType.MPLS_LABEL) {
126 return ((MplsLabelResourceAllocation) allocation).mplsLabel();
127
128 }
129 }
130 log.warn("MPLS label was not assigned successfully");
131 return null;
132 }
133
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800134 private List<FlowRule> generateRules(MplsPathIntent intent,
135 LinkResourceAllocations allocations) {
Michele Santuari4b6019e2014-12-19 11:31:45 +0100136
137 Iterator<Link> links = intent.path().links().iterator();
138 Link srcLink = links.next();
139 ConnectPoint prev = srcLink.dst();
140
141 Link link = links.next();
142 // List of flow rules to be installed
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800143 List<FlowRule> rules = new LinkedList<>();
Michele Santuari4b6019e2014-12-19 11:31:45 +0100144
145 // Ingress traffic
146 // Get the new MPLS label
147 MplsLabel mpls = getMplsLabel(allocations, link);
148 checkNotNull(mpls);
149 MplsLabel prevLabel = mpls;
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800150 rules.add(ingressFlow(prev.port(), link, intent, mpls));
Michele Santuari4b6019e2014-12-19 11:31:45 +0100151
152 prev = link.dst();
153
154 while (links.hasNext()) {
155
156 link = links.next();
157
158 if (links.hasNext()) {
159 // Transit traffic
160 // Get the new MPLS label
161 mpls = getMplsLabel(allocations, link);
162 checkNotNull(mpls);
163 rules.add(transitFlow(prev.port(), link, intent,
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800164 prevLabel, mpls));
Michele Santuari4b6019e2014-12-19 11:31:45 +0100165 prevLabel = mpls;
166
167 } else {
168 // Egress traffic
169 rules.add(egressFlow(prev.port(), link, intent,
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800170 prevLabel));
Michele Santuari4b6019e2014-12-19 11:31:45 +0100171 }
172
173 prev = link.dst();
174 }
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800175 return rules;
Michele Santuari4b6019e2014-12-19 11:31:45 +0100176 }
177
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800178 private FlowRule ingressFlow(PortNumber inPort, Link link,
179 MplsPathIntent intent, MplsLabel label) {
Michele Santuari4b6019e2014-12-19 11:31:45 +0100180
181 TrafficSelector.Builder ingressSelector = DefaultTrafficSelector
182 .builder(intent.selector());
183 TrafficTreatment.Builder treat = DefaultTrafficTreatment.builder();
184 ingressSelector.matchInPort(inPort);
185
186 if (intent.ingressLabel().isPresent()) {
187 ingressSelector.matchEthType(Ethernet.MPLS_UNICAST)
188 .matchMplsLabel(intent.ingressLabel().get());
189
190 // Swap the MPLS label
191 treat.setMpls(label.label());
192 } else {
193 // Push and set the MPLS label
194 treat.pushMpls().setMpls(label.label());
195 }
196 // Add the output action
197 treat.setOutput(link.src().port());
198
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800199 return createFlowRule(intent, link.src().deviceId(), ingressSelector.build(), treat.build());
Michele Santuari4b6019e2014-12-19 11:31:45 +0100200 }
201
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800202 private FlowRule transitFlow(PortNumber inPort, Link link,
203 MplsPathIntent intent,
204 MplsLabel prevLabel,
205 MplsLabel outLabel) {
Michele Santuari4b6019e2014-12-19 11:31:45 +0100206
207 // Ignore the ingress Traffic Selector and use only the MPLS label
208 // assigned in the previous link
209 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
210 selector.matchInPort(inPort).matchEthType(Ethernet.MPLS_UNICAST)
211 .matchMplsLabel(prevLabel.label());
212 TrafficTreatment.Builder treat = DefaultTrafficTreatment.builder();
213
214 // Set the new label only if the label on the packet is
215 // different
216 if (prevLabel.equals(outLabel)) {
217 treat.setMpls(outLabel.label());
218 }
219
220 treat.setOutput(link.src().port());
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800221 return createFlowRule(intent, link.src().deviceId(), selector.build(), treat.build());
Michele Santuari4b6019e2014-12-19 11:31:45 +0100222 }
223
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800224 private FlowRule egressFlow(PortNumber inPort, Link link,
225 MplsPathIntent intent,
226 MplsLabel prevLabel) {
Michele Santuari4b6019e2014-12-19 11:31:45 +0100227 // egress point: either set the egress MPLS label or pop the
228 // MPLS label based on the intent annotations
229
230 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
231 selector.matchInPort(inPort).matchEthType(Ethernet.MPLS_UNICAST)
232 .matchMplsLabel(prevLabel.label());
233
234 // apply the intent's treatments
235 TrafficTreatment.Builder treat = DefaultTrafficTreatment.builder(intent
236 .treatment());
237
238 if (intent.egressLabel().isPresent()) {
239 treat.setMpls(intent.egressLabel().get());
240 } else {
241 // if the ingress ethertype is defined, the egress traffic
242 // will be use that value, otherwise the IPv4 ethertype is used.
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800243 Criterion c = intent.selector().getCriterion(Criterion.Type.ETH_TYPE);
Sho SHIMIZUfbc80e52015-04-28 10:41:58 -0700244 if (c != null && c instanceof EthTypeCriterion) {
245 EthTypeCriterion ethertype = (EthTypeCriterion) c;
Michele Santuari4b6019e2014-12-19 11:31:45 +0100246 treat.popMpls((short) ethertype.ethType());
247 } else {
248 treat.popMpls(Ethernet.TYPE_IPV4);
249 }
250
251 }
252 treat.setOutput(link.src().port());
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800253 return createFlowRule(intent, link.src().deviceId(),
254 selector.build(), treat.build());
Michele Santuari4b6019e2014-12-19 11:31:45 +0100255 }
256
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800257 protected FlowRule createFlowRule(MplsPathIntent intent, DeviceId deviceId,
258 TrafficSelector selector, TrafficTreatment treat) {
259 return new DefaultFlowRule(deviceId, selector, treat, intent.priority(), appId, 0, true);
Michele Santuari4b6019e2014-12-19 11:31:45 +0100260 }
261}