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