blob: 9ad1fe5141f971bd19af900664e6cf5066ae1b3d [file] [log] [blame]
Michele Santuari4b6019e2014-12-19 11:31:45 +01001package org.onosproject.net.intent.impl;
2
Michele Santuari4b6019e2014-12-19 11:31:45 +01003import java.util.Iterator;
4import java.util.List;
5import java.util.Set;
6
7import org.apache.felix.scr.annotations.Activate;
8import org.apache.felix.scr.annotations.Component;
9import org.apache.felix.scr.annotations.Deactivate;
10import org.apache.felix.scr.annotations.Reference;
11import org.apache.felix.scr.annotations.ReferenceCardinality;
12import org.onlab.packet.Ethernet;
13import org.onosproject.core.ApplicationId;
14import org.onosproject.core.CoreService;
15import org.onosproject.net.ConnectPoint;
16import org.onosproject.net.DeviceId;
17import org.onosproject.net.Link;
18import org.onosproject.net.PortNumber;
19import org.onosproject.net.flow.DefaultFlowRule;
20import org.onosproject.net.flow.DefaultTrafficSelector;
21import org.onosproject.net.flow.DefaultTrafficTreatment;
22import org.onosproject.net.flow.FlowRule;
Ray Milkey71ade562015-02-18 15:08:07 -080023import org.onosproject.net.flow.FlowRuleOperation;
Michele Santuari4b6019e2014-12-19 11:31:45 +010024import org.onosproject.net.flow.TrafficSelector;
25import org.onosproject.net.flow.TrafficTreatment;
Michele Santuari4b6019e2014-12-19 11:31:45 +010026import org.onosproject.net.flow.criteria.Criteria.EthTypeCriterion;
27import org.onosproject.net.flow.criteria.Criterion;
28import org.onosproject.net.flow.criteria.Criterion.Type;
29import org.onosproject.net.intent.IntentExtensionService;
30import org.onosproject.net.intent.IntentInstaller;
31import org.onosproject.net.intent.MplsPathIntent;
32import org.onosproject.net.link.LinkStore;
33import org.onosproject.net.resource.DefaultLinkResourceRequest;
34import org.onosproject.net.resource.LinkResourceAllocations;
35import org.onosproject.net.resource.LinkResourceRequest;
36import org.onosproject.net.resource.LinkResourceService;
37import org.onosproject.net.resource.MplsLabel;
38import org.onosproject.net.resource.MplsLabelResourceAllocation;
39import org.onosproject.net.resource.ResourceAllocation;
40import org.onosproject.net.resource.ResourceType;
41import org.slf4j.Logger;
42
Ray Milkey71ade562015-02-18 15:08:07 -080043import com.google.common.collect.ImmutableSet;
Michele Santuari4b6019e2014-12-19 11:31:45 +010044import com.google.common.collect.Lists;
45import com.google.common.collect.Sets;
46
Ray Milkey71ade562015-02-18 15:08:07 -080047import static com.google.common.base.Preconditions.checkNotNull;
48import static org.slf4j.LoggerFactory.getLogger;
49
Michele Santuari4b6019e2014-12-19 11:31:45 +010050/**
51 * Installer for {@link MplsPathIntent packet path connectivity intents}.
52 */
53@Component(immediate = true)
54public class MplsPathIntentInstaller implements IntentInstaller<MplsPathIntent> {
55
56 private final Logger log = getLogger(getClass());
57
58 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
59 protected IntentExtensionService intentManager;
60
61 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
62 protected CoreService coreService;
63
64 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
65 protected LinkResourceService resourceService;
66
67 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
68 protected LinkStore linkStore;
69
70 protected ApplicationId appId;
71
72 @Activate
73 public void activate() {
74 appId = coreService.registerApplication("org.onosproject.net.intent");
75 intentManager.registerInstaller(MplsPathIntent.class, this);
76 }
77
78 @Deactivate
79 public void deactivate() {
80 intentManager.unregisterInstaller(MplsPathIntent.class);
81 }
82
83 @Override
Ray Milkey71ade562015-02-18 15:08:07 -080084 public List<Set<FlowRuleOperation>> install(MplsPathIntent intent) {
Michele Santuari4b6019e2014-12-19 11:31:45 +010085 LinkResourceAllocations allocations = assignMplsLabel(intent);
Ray Milkey71ade562015-02-18 15:08:07 -080086 return generateRules(intent, allocations, FlowRuleOperation.Type.ADD);
Michele Santuari4b6019e2014-12-19 11:31:45 +010087
88 }
89
90 @Override
Ray Milkey71ade562015-02-18 15:08:07 -080091 public List<Set<FlowRuleOperation>> uninstall(MplsPathIntent intent) {
Michele Santuari4b6019e2014-12-19 11:31:45 +010092 LinkResourceAllocations allocations = resourceService
93 .getAllocations(intent.id());
94 resourceService.releaseResources(allocations);
95
Ray Milkey71ade562015-02-18 15:08:07 -080096 return generateRules(intent, allocations, FlowRuleOperation.Type.REMOVE);
Michele Santuari4b6019e2014-12-19 11:31:45 +010097 }
98
99 @Override
Ray Milkey71ade562015-02-18 15:08:07 -0800100 public List<Set<FlowRuleOperation>> replace(MplsPathIntent oldIntent,
101 MplsPathIntent newIntent) {
Michele Santuari4b6019e2014-12-19 11:31:45 +0100102
Ray Milkey71ade562015-02-18 15:08:07 -0800103 List<Set<FlowRuleOperation>> batches = Lists.newArrayList();
Michele Santuari4b6019e2014-12-19 11:31:45 +0100104 batches.addAll(uninstall(oldIntent));
105 batches.addAll(install(newIntent));
106 return batches;
107 }
108
109 private LinkResourceAllocations assignMplsLabel(MplsPathIntent intent) {
110
111 // TODO: do it better... Suggestions?
112 Set<Link> linkRequest = Sets.newHashSetWithExpectedSize(intent.path()
113 .links().size() - 2);
114 for (int i = 1; i <= intent.path().links().size() - 2; i++) {
115 Link link = intent.path().links().get(i);
116 linkRequest.add(link);
117 // add the inverse link. I want that the label is reserved both for
118 // the direct and inverse link
119 linkRequest.add(linkStore.getLink(link.dst(), link.src()));
120 }
121
122 LinkResourceRequest.Builder request = DefaultLinkResourceRequest
123 .builder(intent.id(), linkRequest).addMplsRequest();
124 LinkResourceAllocations reqMpls = resourceService
125 .requestResources(request.build());
126 return reqMpls;
127 }
128
129 private MplsLabel getMplsLabel(LinkResourceAllocations allocations,
130 Link link) {
131
132 for (ResourceAllocation allocation : allocations
133 .getResourceAllocation(link)) {
134 if (allocation.type() == ResourceType.MPLS_LABEL) {
135 return ((MplsLabelResourceAllocation) allocation).mplsLabel();
136
137 }
138 }
139 log.warn("MPLS label was not assigned successfully");
140 return null;
141 }
142
Ray Milkey71ade562015-02-18 15:08:07 -0800143 private List<Set<FlowRuleOperation>> generateRules(MplsPathIntent intent,
Michele Santuari4b6019e2014-12-19 11:31:45 +0100144 LinkResourceAllocations allocations,
Ray Milkey71ade562015-02-18 15:08:07 -0800145 FlowRuleOperation.Type operation) {
Michele Santuari4b6019e2014-12-19 11:31:45 +0100146
147 Iterator<Link> links = intent.path().links().iterator();
148 Link srcLink = links.next();
149 ConnectPoint prev = srcLink.dst();
150
151 Link link = links.next();
152 // List of flow rules to be installed
Ray Milkey71ade562015-02-18 15:08:07 -0800153 Set<FlowRuleOperation> rules = Sets.newHashSet();
Michele Santuari4b6019e2014-12-19 11:31:45 +0100154
155 // Ingress traffic
156 // Get the new MPLS label
157 MplsLabel mpls = getMplsLabel(allocations, link);
158 checkNotNull(mpls);
159 MplsLabel prevLabel = mpls;
160 rules.add(ingressFlow(prev.port(), link, intent, mpls, operation));
161
162 prev = link.dst();
163
164 while (links.hasNext()) {
165
166 link = links.next();
167
168 if (links.hasNext()) {
169 // Transit traffic
170 // Get the new MPLS label
171 mpls = getMplsLabel(allocations, link);
172 checkNotNull(mpls);
173 rules.add(transitFlow(prev.port(), link, intent,
174 prevLabel, mpls, operation));
175 prevLabel = mpls;
176
177 } else {
178 // Egress traffic
179 rules.add(egressFlow(prev.port(), link, intent,
180 prevLabel, operation));
181 }
182
183 prev = link.dst();
184 }
Ray Milkey71ade562015-02-18 15:08:07 -0800185 return Lists.newArrayList(ImmutableSet.of(rules));
Michele Santuari4b6019e2014-12-19 11:31:45 +0100186 }
187
Ray Milkey71ade562015-02-18 15:08:07 -0800188 private FlowRuleOperation ingressFlow(PortNumber inPort, Link link,
Michele Santuari4b6019e2014-12-19 11:31:45 +0100189 MplsPathIntent intent,
190 MplsLabel label,
Ray Milkey71ade562015-02-18 15:08:07 -0800191 FlowRuleOperation.Type operation) {
Michele Santuari4b6019e2014-12-19 11:31:45 +0100192
193 TrafficSelector.Builder ingressSelector = DefaultTrafficSelector
194 .builder(intent.selector());
195 TrafficTreatment.Builder treat = DefaultTrafficTreatment.builder();
196 ingressSelector.matchInPort(inPort);
197
198 if (intent.ingressLabel().isPresent()) {
199 ingressSelector.matchEthType(Ethernet.MPLS_UNICAST)
200 .matchMplsLabel(intent.ingressLabel().get());
201
202 // Swap the MPLS label
203 treat.setMpls(label.label());
204 } else {
205 // Push and set the MPLS label
206 treat.pushMpls().setMpls(label.label());
207 }
208 // Add the output action
209 treat.setOutput(link.src().port());
210
Ray Milkey71ade562015-02-18 15:08:07 -0800211 return flowRuleOperation(intent, link.src().deviceId(),
212 ingressSelector.build(), treat.build(),
213 operation);
Michele Santuari4b6019e2014-12-19 11:31:45 +0100214 }
215
Ray Milkey71ade562015-02-18 15:08:07 -0800216 private FlowRuleOperation transitFlow(PortNumber inPort, Link link,
Michele Santuari4b6019e2014-12-19 11:31:45 +0100217 MplsPathIntent intent,
218 MplsLabel prevLabel,
219 MplsLabel outLabel,
Ray Milkey71ade562015-02-18 15:08:07 -0800220 FlowRuleOperation.Type operation) {
Michele Santuari4b6019e2014-12-19 11:31:45 +0100221
222 // Ignore the ingress Traffic Selector and use only the MPLS label
223 // assigned in the previous link
224 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
225 selector.matchInPort(inPort).matchEthType(Ethernet.MPLS_UNICAST)
226 .matchMplsLabel(prevLabel.label());
227 TrafficTreatment.Builder treat = DefaultTrafficTreatment.builder();
228
229 // Set the new label only if the label on the packet is
230 // different
231 if (prevLabel.equals(outLabel)) {
232 treat.setMpls(outLabel.label());
233 }
234
235 treat.setOutput(link.src().port());
Ray Milkey71ade562015-02-18 15:08:07 -0800236 return flowRuleOperation(intent, link.src().deviceId(),
237 selector.build(), treat.build(), operation);
Michele Santuari4b6019e2014-12-19 11:31:45 +0100238 }
239
Ray Milkey71ade562015-02-18 15:08:07 -0800240 private FlowRuleOperation egressFlow(PortNumber inPort, Link link,
Michele Santuari4b6019e2014-12-19 11:31:45 +0100241 MplsPathIntent intent,
242 MplsLabel prevLabel,
Ray Milkey71ade562015-02-18 15:08:07 -0800243 FlowRuleOperation.Type operation) {
Michele Santuari4b6019e2014-12-19 11:31:45 +0100244 // egress point: either set the egress MPLS label or pop the
245 // MPLS label based on the intent annotations
246
247 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
248 selector.matchInPort(inPort).matchEthType(Ethernet.MPLS_UNICAST)
249 .matchMplsLabel(prevLabel.label());
250
251 // apply the intent's treatments
252 TrafficTreatment.Builder treat = DefaultTrafficTreatment.builder(intent
253 .treatment());
254
255 if (intent.egressLabel().isPresent()) {
256 treat.setMpls(intent.egressLabel().get());
257 } else {
258 // if the ingress ethertype is defined, the egress traffic
259 // will be use that value, otherwise the IPv4 ethertype is used.
260 Criterion c = intent.selector().getCriterion(Type.ETH_TYPE);
261 if (c != null && c instanceof EthTypeCriterion) {
262 EthTypeCriterion ethertype = (EthTypeCriterion) c;
263 treat.popMpls((short) ethertype.ethType());
264 } else {
265 treat.popMpls(Ethernet.TYPE_IPV4);
266 }
267
268 }
269 treat.setOutput(link.src().port());
Ray Milkey71ade562015-02-18 15:08:07 -0800270 return flowRuleOperation(intent, link.src().deviceId(),
271 selector.build(), treat.build(), operation);
Michele Santuari4b6019e2014-12-19 11:31:45 +0100272 }
273
Ray Milkey71ade562015-02-18 15:08:07 -0800274 protected FlowRuleOperation flowRuleOperation(MplsPathIntent intent,
Michele Santuari4b6019e2014-12-19 11:31:45 +0100275 DeviceId deviceId,
276 TrafficSelector selector,
277 TrafficTreatment treat,
Ray Milkey71ade562015-02-18 15:08:07 -0800278 FlowRuleOperation.Type operation) {
Michele Santuari4b6019e2014-12-19 11:31:45 +0100279 FlowRule rule = new DefaultFlowRule(
280 deviceId,
281 selector,
282 treat,
283 123, // FIXME 123
284 appId,
285 0,
286 true);
Ray Milkey71ade562015-02-18 15:08:07 -0800287 return new FlowRuleOperation(rule, operation);
Michele Santuari4b6019e2014-12-19 11:31:45 +0100288
289 }
290}