blob: 5bd90c3338d7e8bbb9f4f7b4c7f5aff83797e761 [file] [log] [blame]
Yi Tsenga64f0c82017-02-03 11:17:15 -08001/*
2 * Copyright 2016-present 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;
17
18import com.google.common.collect.HashMultimap;
Thomas Szyrkowiec770093f2017-05-05 13:06:53 +020019import com.google.common.collect.ImmutableList;
Yi Tsenga64f0c82017-02-03 11:17:15 -080020import com.google.common.collect.ImmutableMap;
21import com.google.common.collect.Lists;
22import com.google.common.collect.SetMultimap;
23import com.google.common.collect.Sets;
24import org.apache.felix.scr.annotations.Activate;
25import org.apache.felix.scr.annotations.Component;
26import org.apache.felix.scr.annotations.Deactivate;
27import org.apache.felix.scr.annotations.Reference;
28import org.apache.felix.scr.annotations.ReferenceCardinality;
29import org.onlab.util.Identifier;
30import org.onosproject.core.ApplicationId;
31import org.onosproject.core.CoreService;
32import org.onosproject.net.ConnectPoint;
33import org.onosproject.net.DeviceId;
34import org.onosproject.net.PortNumber;
Thomas Szyrkowiec770093f2017-05-05 13:06:53 +020035import org.onosproject.net.domain.DomainService;
Yi Tsenga64f0c82017-02-03 11:17:15 -080036import org.onosproject.net.flow.DefaultTrafficTreatment;
37import org.onosproject.net.flow.TrafficSelector;
38import org.onosproject.net.flow.TrafficTreatment;
39import org.onosproject.net.flow.criteria.Criterion;
40import org.onosproject.net.flow.criteria.EthCriterion;
41import org.onosproject.net.flow.instructions.Instruction;
42import org.onosproject.net.flowobjective.DefaultFilteringObjective;
43import org.onosproject.net.flowobjective.DefaultForwardingObjective;
44import org.onosproject.net.flowobjective.DefaultNextObjective;
45import org.onosproject.net.flowobjective.FilteringObjective;
46import org.onosproject.net.flowobjective.FlowObjectiveService;
47import org.onosproject.net.flowobjective.ForwardingObjective;
48import org.onosproject.net.flowobjective.NextObjective;
49import org.onosproject.net.flowobjective.Objective;
50import org.onosproject.net.intent.FlowObjectiveIntent;
51import org.onosproject.net.intent.Intent;
52import org.onosproject.net.intent.IntentCompiler;
53import org.onosproject.net.intent.LinkCollectionIntent;
54import org.onosproject.net.intent.constraint.EncapsulationConstraint;
55import org.onosproject.net.resource.ResourceService;
56import org.onosproject.net.resource.impl.LabelAllocator;
57
58import java.util.ArrayList;
Yi Tsenga64f0c82017-02-03 11:17:15 -080059import java.util.List;
60import java.util.Map;
61import java.util.Optional;
62import java.util.Set;
63
Thomas Szyrkowiec770093f2017-05-05 13:06:53 +020064import static org.onosproject.net.domain.DomainId.LOCAL;
Yi Tsenga64f0c82017-02-03 11:17:15 -080065import static org.onosproject.net.flow.instructions.Instruction.Type.OUTPUT;
66
67/**
68 * Compiler to produce flow objectives from link collections.
69 */
70@Component(immediate = true)
71public class LinkCollectionIntentObjectiveCompiler
72 extends LinkCollectionCompiler<Objective>
73 implements IntentCompiler<LinkCollectionIntent> {
74
75 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
76 protected IntentConfigurableRegistrator registrator;
77
78 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
79 protected CoreService coreService;
80
81 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
82 protected FlowObjectiveService flowObjectiveService;
83
84 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
85 protected ResourceService resourceService;
86
Thomas Szyrkowiec770093f2017-05-05 13:06:53 +020087 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
88 protected DomainService domainService;
89
Yi Tsenga64f0c82017-02-03 11:17:15 -080090 private ApplicationId appId;
91
92 @Activate
93 public void activate() {
94 appId = coreService.registerApplication("org.onosproject.net.intent");
95 registrator.registerCompiler(LinkCollectionIntent.class, this, true);
96 if (labelAllocator == null) {
97 labelAllocator = new LabelAllocator(resourceService);
98 }
99 }
100
101
102 @Deactivate
103 public void deactivate() {
104 registrator.unregisterCompiler(LinkCollectionIntent.class, true);
105 }
106
107 @Override
108 public List<Intent> compile(LinkCollectionIntent intent, List<Intent> installable) {
109
110 SetMultimap<DeviceId, PortNumber> inputPorts = HashMultimap.create();
111 SetMultimap<DeviceId, PortNumber> outputPorts = HashMultimap.create();
112 Map<ConnectPoint, Identifier<?>> labels = ImmutableMap.of();
113
114 Optional<EncapsulationConstraint> encapConstraint = this.getIntentEncapConstraint(intent);
115
116 computePorts(intent, inputPorts, outputPorts);
117
118 if (encapConstraint.isPresent()) {
119 labels = labelAllocator.assignLabelToPorts(intent.links(),
120 intent.id(),
121 encapConstraint.get().encapType());
122 }
123
Thomas Szyrkowiec770093f2017-05-05 13:06:53 +0200124 ImmutableList.Builder<Intent> intentList = ImmutableList.builder();
125 if (this.isDomainProcessingEnabled(intent)) {
126 intentList.addAll(this.getDomainIntents(intent, domainService));
127 }
128
Yi Tsenga64f0c82017-02-03 11:17:15 -0800129 List<Objective> objectives = new ArrayList<>();
130 List<DeviceId> devices = new ArrayList<>();
Thomas Szyrkowiec770093f2017-05-05 13:06:53 +0200131 for (DeviceId deviceId : outputPorts.keySet()) {
132 // add only objectives that are not inside of a domain
133 if (LOCAL.equals(domainService.getDomain(deviceId))) {
134 List<Objective> deviceObjectives =
135 createRules(intent,
136 deviceId,
137 inputPorts.get(deviceId),
138 outputPorts.get(deviceId),
139 labels);
140 deviceObjectives.forEach(objective -> {
141 objectives.add(objective);
142 devices.add(deviceId);
143 });
144 }
Yi Tsenga64f0c82017-02-03 11:17:15 -0800145 }
Thomas Szyrkowiec770093f2017-05-05 13:06:53 +0200146 // if any objectives have been created
147 if (!objectives.isEmpty()) {
148 intentList.add(new FlowObjectiveIntent(appId, intent.key(), devices,
149 objectives,
150 intent.resources(),
151 intent.resourceGroup()));
152 }
153 return intentList.build();
Yi Tsenga64f0c82017-02-03 11:17:15 -0800154 }
155
156 @Override
Yi Tseng84c5a3d2017-04-14 16:42:59 -0700157 boolean optimizeTreatments() {
158 return false;
159 }
160
161 @Override
Yi Tsenga64f0c82017-02-03 11:17:15 -0800162 protected List<Objective> createRules(LinkCollectionIntent intent,
163 DeviceId deviceId,
164 Set<PortNumber> inPorts,
165 Set<PortNumber> outPorts,
166 Map<ConnectPoint, Identifier<?>> labels) {
167
168 List<Objective> objectives = new ArrayList<>(inPorts.size() * 2);
169
170 /*
171 * Looking for the encapsulation constraint
172 */
173 Optional<EncapsulationConstraint> encapConstraint = this.getIntentEncapConstraint(intent);
174
175 inPorts.forEach(inport -> {
176
177 ForwardingInstructions instructions = this.createForwardingInstruction(
178 encapConstraint,
179 intent,
180 inport,
181 outPorts,
182 deviceId,
183 labels
184 );
185
186 Set<TrafficTreatment> treatmentsWithDifferentPort =
187 Sets.newHashSet();
188
189 TrafficTreatment.Builder treatmentBuilder =
190 DefaultTrafficTreatment.builder();
191
192 for (Instruction inst : instructions.treatment().allInstructions()) {
193 if (inst.type() == OUTPUT) {
194 treatmentBuilder.add(inst);
195 treatmentsWithDifferentPort.add(treatmentBuilder.build());
196 treatmentBuilder = DefaultTrafficTreatment.builder();
197 } else {
198 treatmentBuilder.add(inst);
199 }
200 }
201
202 EthCriterion ethDst = (EthCriterion) instructions.selector()
203 .getCriterion(Criterion.Type.ETH_DST);
204 boolean broadcastObjective = ethDst != null &&
205 (ethDst.mac().isBroadcast() || ethDst.mac().isMulticast());
206
207 if (treatmentsWithDifferentPort.size() < 2 && !broadcastObjective) {
208 objectives.addAll(createSimpleNextObjective(instructions, intent));
209 } else {
210 objectives.addAll(createBroadcastObjective(instructions,
211 treatmentsWithDifferentPort,
212 intent));
213 }
214 });
215
216 return objectives;
217 }
218
219 private List<Objective> createBroadcastObjective(ForwardingInstructions instructions,
220 Set<TrafficTreatment> treatmentsWithDifferentPort,
221 LinkCollectionIntent intent) {
222 List<Objective> objectives = Lists.newArrayList();
223 FilteringObjective filteringObjective;
224 ForwardingObjective forwardingObjective;
225 NextObjective nextObjective;
226
227 Integer nextId = flowObjectiveService.allocateNextId();
228
229 forwardingObjective = buildForwardingObjective(instructions.selector(),
230 nextId, intent.priority());
231
232 DefaultNextObjective.Builder nxBuilder = DefaultNextObjective.builder();
233 nxBuilder.withId(nextId)
234 .withMeta(instructions.selector())
235 .withType(NextObjective.Type.BROADCAST)
236 .fromApp(appId)
237 .withPriority(intent.priority())
238 .makePermanent();
239
240 treatmentsWithDifferentPort.forEach(nxBuilder::addTreatment);
241 nextObjective = nxBuilder.add();
242
243 filteringObjective = buildFilteringObjective(instructions.selector(), intent.priority());
244
245 objectives.add(filteringObjective);
246 objectives.add(forwardingObjective);
247 objectives.add(nextObjective);
248
249 return objectives;
250 }
251
252 private List<Objective> createSimpleNextObjective(ForwardingInstructions instructions,
253 LinkCollectionIntent intent) {
254 List<Objective> objectives = Lists.newArrayList();
255 FilteringObjective filteringObjective;
256 ForwardingObjective forwardingObjective;
257 NextObjective nextObjective;
258
259 Integer nextId = flowObjectiveService.allocateNextId();
260
261 forwardingObjective = buildForwardingObjective(instructions.selector(),
262 nextId, intent.priority());
263
264 DefaultNextObjective.Builder nxBuilder = DefaultNextObjective.builder();
265 nextObjective = nxBuilder.withId(nextId)
266 .withMeta(instructions.selector())
267 .addTreatment(instructions.treatment())
268 .withType(NextObjective.Type.SIMPLE)
269 .fromApp(appId)
270 .makePermanent()
271 .withPriority(intent.priority())
272 .add();
273
274 filteringObjective = buildFilteringObjective(instructions.selector(), intent.priority());
275
276 objectives.add(filteringObjective);
277 objectives.add(forwardingObjective);
278 objectives.add(nextObjective);
279
280 return objectives;
281 }
282
283 private ForwardingObjective buildForwardingObjective(TrafficSelector selector, Integer nextId, int priority) {
284 return DefaultForwardingObjective.builder()
285 .withMeta(selector)
286 .withSelector(selector)
287 .nextStep(nextId)
288 .fromApp(appId)
289 .withPriority(priority)
290 .withFlag(ForwardingObjective.Flag.SPECIFIC)
291 .makePermanent()
292 .add();
293 }
294
295 private FilteringObjective buildFilteringObjective(TrafficSelector selector, int priority) {
296 FilteringObjective.Builder builder = DefaultFilteringObjective.builder();
297 builder.fromApp(appId)
298 .permit()
299 .makePermanent()
300 .withPriority(priority);
301
302 Criterion inPortCriterion =
303 selector.getCriterion(Criterion.Type.IN_PORT);
304
305 if (inPortCriterion != null) {
306 builder.withKey(inPortCriterion);
307 }
308
309 selector.criteria().forEach(builder::addCondition);
310 return builder.add();
311 }
312
313}