blob: d3aaf0283f70acc1a6e200886b0314a45c05627b [file] [log] [blame]
Xin Jin313708b2015-07-09 13:43:04 -07001/*
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.flowobjective.impl.composition;
17
18import org.onlab.packet.IpPrefix;
19import org.onosproject.net.flow.DefaultTrafficSelector;
20import org.onosproject.net.flow.DefaultTrafficTreatment;
21import org.onosproject.net.flow.TrafficSelector;
22import org.onosproject.net.flow.TrafficTreatment;
23import org.onosproject.net.flow.criteria.Criterion;
Xin Jin313708b2015-07-09 13:43:04 -070024import org.onosproject.net.flow.criteria.OchSignalCriterion;
25import org.onosproject.net.flow.criteria.EthCriterion;
26import org.onosproject.net.flow.criteria.VlanIdCriterion;
27import org.onosproject.net.flow.criteria.VlanPcpCriterion;
28import org.onosproject.net.flow.criteria.MplsCriterion;
29import org.onosproject.net.flow.criteria.IPCriterion;
HIGUCHI Yutad275afd2015-09-09 09:57:34 +090030import org.onosproject.net.flow.criteria.IPv6FlowLabelCriterion;
Yafit Hadar5796d972015-10-15 13:16:11 +030031import org.onosproject.net.flow.criteria.OduSignalIdCriterion;
Xin Jin313708b2015-07-09 13:43:04 -070032import org.onosproject.net.flow.criteria.Criteria;
33import org.onosproject.net.flow.instructions.Instruction;
34import org.onosproject.net.flow.instructions.L0ModificationInstruction;
Yafit Hadar5796d972015-10-15 13:16:11 +030035import org.onosproject.net.flow.instructions.L1ModificationInstruction;
Xin Jin313708b2015-07-09 13:43:04 -070036import org.onosproject.net.flow.instructions.L2ModificationInstruction;
37import org.onosproject.net.flow.instructions.L3ModificationInstruction;
38import org.onosproject.net.flowobjective.DefaultForwardingObjective;
39import org.onosproject.net.flowobjective.ForwardingObjective;
40
41import java.util.ArrayList;
42import java.util.Collection;
43import java.util.HashMap;
44import java.util.HashSet;
45import java.util.List;
46import java.util.Map;
47import java.util.Set;
48import java.util.Stack;
49
50/**
51 * Provide util functions for FlowObjectiveComposition.
52 */
53public final class FlowObjectiveCompositionUtil {
54
55 private FlowObjectiveCompositionUtil() {}
56
57 // only work with VERSATILE
58 public static ForwardingObjective composeParallel(ForwardingObjective fo1, ForwardingObjective fo2) {
59
60 TrafficSelector trafficSelector = intersectTrafficSelector(fo1.selector(), fo2.selector());
61 if (trafficSelector == null) {
62 return null;
63 }
64
65 TrafficTreatment trafficTreatment = unionTrafficTreatment(fo1.treatment(), fo2.treatment());
66
67 return DefaultForwardingObjective.builder()
68 .fromApp(fo1.appId())
69 .makePermanent()
70 .withFlag(ForwardingObjective.Flag.VERSATILE)
71 .withPriority(fo1.priority() + fo2.priority())
72 .withSelector(trafficSelector)
73 .withTreatment(trafficTreatment)
74 .add();
75 }
76
77 public static ForwardingObjective composeSequential(ForwardingObjective fo1,
78 ForwardingObjective fo2,
79 int priorityMultiplier) {
80
81 TrafficSelector revertTrafficSelector = revertTreatmentSelector(fo1.treatment(), fo2.selector());
82 if (revertTrafficSelector == null) {
83 return null;
84 }
85
86 TrafficSelector trafficSelector = intersectTrafficSelector(fo1.selector(), revertTrafficSelector);
87 if (trafficSelector == null) {
88 return null;
89 }
90
91 TrafficTreatment trafficTreatment = unionTrafficTreatment(fo1.treatment(), fo2.treatment());
92
93 return DefaultForwardingObjective.builder()
94 .fromApp(fo1.appId())
95 .makePermanent()
96 .withFlag(ForwardingObjective.Flag.VERSATILE)
97 .withPriority(fo1.priority() * priorityMultiplier + fo2.priority())
98 .withSelector(trafficSelector)
99 .withTreatment(trafficTreatment)
100 .add();
101 }
102
103 public static ForwardingObjective composeOverride(ForwardingObjective fo, int priorityAddend) {
104 return DefaultForwardingObjective.builder()
105 .fromApp(fo.appId())
106 .makePermanent()
107 .withFlag(fo.flag())
108 .withPriority(fo.priority() + priorityAddend)
109 .withSelector(fo.selector())
110 .withTreatment(fo.treatment())
111 .add();
112 }
113
114 public static TrafficSelector intersectTrafficSelector(TrafficSelector ts1, TrafficSelector ts2) {
115
116 TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder();
117
118 Set<Criterion.Type> ts1IntersectTs2 = getTypeSet(ts1);
119 ts1IntersectTs2.retainAll(getTypeSet(ts2));
120 for (Criterion.Type type : ts1IntersectTs2) {
121 Criterion criterion = intersectCriterion(ts1.getCriterion(type), ts2.getCriterion(type));
122 if (criterion == null) {
123 return null;
124 } else {
125 selectorBuilder.add(criterion);
126 }
127 }
128
129 Set<Criterion.Type> ts1MinusTs2 = getTypeSet(ts1);
130 ts1MinusTs2.removeAll(getTypeSet(ts2));
131 for (Criterion.Type type : ts1MinusTs2) {
132 selectorBuilder.add(ts1.getCriterion(type));
133 }
134
135 Set<Criterion.Type> ts2MinusTs1 = getTypeSet(ts2);
136 ts2MinusTs1.removeAll(getTypeSet(ts1));
137 for (Criterion.Type type : ts2MinusTs1) {
138 selectorBuilder.add(ts2.getCriterion(type));
139 }
140
141 return selectorBuilder.build();
142 }
143
144 public static TrafficTreatment unionTrafficTreatment(TrafficTreatment tt1, TrafficTreatment tt2) {
145
146 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
147
148 for (Instruction instruction : tt1.allInstructions()) {
149 treatmentBuilder.add(instruction);
150 }
151
152 for (Instruction instruction : tt2.allInstructions()) {
153 treatmentBuilder.add(instruction);
154 }
155
156 return treatmentBuilder.build();
157 }
158
Yafit Hadar5796d972015-10-15 13:16:11 +0300159 //CHECKSTYLE:OFF
Xin Jin313708b2015-07-09 13:43:04 -0700160 public static TrafficSelector revertTreatmentSelector(TrafficTreatment trafficTreatment,
161 TrafficSelector trafficSelector) {
162
163 TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder();
164
165 Map<Criterion.Type, Criterion> criterionMap = new HashMap<>();
166 for (Criterion criterion : trafficSelector.criteria()) {
167 criterionMap.put(criterion.type(), criterion);
168 }
169
170 for (Instruction instruction : trafficTreatment.allInstructions()) {
171 switch (instruction.type()) {
Xin Jin313708b2015-07-09 13:43:04 -0700172 case OUTPUT:
173 break;
174 case GROUP:
175 break;
176 case L0MODIFICATION: {
177 L0ModificationInstruction l0 = (L0ModificationInstruction) instruction;
178 switch (l0.subtype()) {
Xin Jin313708b2015-07-09 13:43:04 -0700179 case OCH:
180 if (criterionMap.containsKey(Criterion.Type.OCH_SIGID)) {
181 if (((OchSignalCriterion) criterionMap.get((Criterion.Type.OCH_SIGID))).lambda()
182 .equals(((L0ModificationInstruction.ModOchSignalInstruction) l0).lambda())) {
183 criterionMap.remove(Criterion.Type.OCH_SIGID);
184 } else {
185 return null;
186 }
Xin Jin313708b2015-07-09 13:43:04 -0700187 }
188 default:
189 break;
190 }
191 break;
192 }
Yafit Hadar5796d972015-10-15 13:16:11 +0300193 case L1MODIFICATION: {
194 L1ModificationInstruction l1 = (L1ModificationInstruction) instruction;
195 switch (l1.subtype()) {
196 case ODU_SIGID:
197 if (criterionMap.containsKey(Criterion.Type.ODU_SIGID)) {
198 if (((OduSignalIdCriterion) criterionMap.get((Criterion.Type.ODU_SIGID))).oduSignalId()
199 .equals(((L1ModificationInstruction.ModOduSignalIdInstruction) l1)
200 .oduSignalId())) {
201 criterionMap.remove(Criterion.Type.ODU_SIGID);
202 } else {
203 return null;
204 }
Ray Milkey125572b2016-02-22 16:48:17 -0800205 }
Yafit Hadar5796d972015-10-15 13:16:11 +0300206 default:
207 break;
208 }
209 break;
210 }
Xin Jin313708b2015-07-09 13:43:04 -0700211 case L2MODIFICATION: {
212 L2ModificationInstruction l2 = (L2ModificationInstruction) instruction;
213 switch (l2.subtype()) {
214 case ETH_SRC:
215 if (criterionMap.containsKey(Criterion.Type.ETH_SRC)) {
216 if (((EthCriterion) criterionMap.get((Criterion.Type.ETH_SRC))).mac()
217 .equals(((L2ModificationInstruction.ModEtherInstruction) l2).mac())) {
218 criterionMap.remove(Criterion.Type.ETH_SRC);
219 } else {
220 return null;
221 }
222 } else {
223 break;
224 }
225 case ETH_DST:
226 if (criterionMap.containsKey(Criterion.Type.ETH_DST)) {
227 if (((EthCriterion) criterionMap.get((Criterion.Type.ETH_DST))).mac()
228 .equals(((L2ModificationInstruction.ModEtherInstruction) l2).mac())) {
229 criterionMap.remove(Criterion.Type.ETH_DST);
230 } else {
231 return null;
232 }
233 } else {
234 break;
235 }
236 case VLAN_ID:
237 if (criterionMap.containsKey(Criterion.Type.VLAN_VID)) {
238 if (((VlanIdCriterion) criterionMap.get((Criterion.Type.VLAN_VID))).vlanId()
239 .equals(((L2ModificationInstruction.ModVlanIdInstruction) l2).vlanId())) {
240 criterionMap.remove(Criterion.Type.VLAN_VID);
241 } else {
242 return null;
243 }
244 } else {
245 break;
246 }
247 case VLAN_PCP:
248 if (criterionMap.containsKey(Criterion.Type.VLAN_PCP)) {
249 if (((VlanPcpCriterion) criterionMap.get((Criterion.Type.VLAN_PCP))).priority()
250 == ((L2ModificationInstruction.ModVlanPcpInstruction) l2).vlanPcp()) {
251 criterionMap.remove(Criterion.Type.VLAN_PCP);
252 } else {
253 return null;
254 }
255 } else {
256 break;
257 }
258 case MPLS_LABEL:
259 if (criterionMap.containsKey(Criterion.Type.MPLS_LABEL)) {
260 if (((MplsCriterion) criterionMap.get((Criterion.Type.MPLS_LABEL))).label()
Ray Milkey125572b2016-02-22 16:48:17 -0800261 .equals(((L2ModificationInstruction.ModMplsLabelInstruction) l2).label())) {
Xin Jin313708b2015-07-09 13:43:04 -0700262 criterionMap.remove(Criterion.Type.ETH_DST);
263 } else {
264 return null;
265 }
266 } else {
267 break;
268 }
269 default:
270 break;
271 }
272 break;
273 }
274 case TABLE:
275 break;
276 case L3MODIFICATION: {
277 L3ModificationInstruction l3 = (L3ModificationInstruction) instruction;
278 switch (l3.subtype()) {
279 case IPV4_SRC:
280 if (criterionMap.containsKey(Criterion.Type.IPV4_SRC)) {
281 if (((IPCriterion) criterionMap.get(Criterion.Type.IPV4_SRC)).ip()
282 .contains(((L3ModificationInstruction.ModIPInstruction) l3).ip())) {
283 criterionMap.remove(Criterion.Type.IPV4_SRC);
284 } else {
285 return null;
286 }
287 } else {
288 break;
289 }
290 case IPV4_DST:
291 if (criterionMap.containsKey(Criterion.Type.IPV4_DST)) {
292 if (((IPCriterion) criterionMap.get(Criterion.Type.IPV4_DST)).ip()
293 .contains(((L3ModificationInstruction.ModIPInstruction) l3).ip())) {
294 criterionMap.remove(Criterion.Type.IPV4_DST);
295 } else {
296 return null;
297 }
298 } else {
299 break;
300 }
301 case IPV6_SRC:
302 if (criterionMap.containsKey(Criterion.Type.IPV6_SRC)) {
303 if (((IPCriterion) criterionMap.get(Criterion.Type.IPV6_SRC)).ip()
304 .contains(((L3ModificationInstruction.ModIPInstruction) l3).ip())) {
305 criterionMap.remove(Criterion.Type.IPV6_SRC);
306 } else {
307 return null;
308 }
309 } else {
310 break;
311 }
312 case IPV6_DST:
313 if (criterionMap.containsKey(Criterion.Type.IPV6_DST)) {
314 if (((IPCriterion) criterionMap.get(Criterion.Type.IPV6_DST)).ip()
315 .contains(((L3ModificationInstruction.ModIPInstruction) l3).ip())) {
316 criterionMap.remove(Criterion.Type.IPV6_DST);
317 } else {
318 return null;
319 }
320 } else {
321 break;
322 }
323 case IPV6_FLABEL:
324 if (criterionMap.containsKey(Criterion.Type.IPV6_FLABEL)) {
HIGUCHI Yutad275afd2015-09-09 09:57:34 +0900325 if (((IPv6FlowLabelCriterion) criterionMap.get(Criterion.Type.IPV6_FLABEL)).flowLabel()
326 == (((L3ModificationInstruction.ModIPv6FlowLabelInstruction) l3).flowLabel())) {
Xin Jin313708b2015-07-09 13:43:04 -0700327 criterionMap.remove(Criterion.Type.IPV4_SRC);
328 } else {
329 return null;
330 }
331 } else {
332 break;
333 }
334 default:
335 break;
336 }
337 break;
338 }
339 case METADATA:
340 break;
341 default:
342 break;
343 }
344 }
345
346 for (Criterion criterion : criterionMap.values()) {
347 selectorBuilder.add(criterion);
348 }
349
350 return selectorBuilder.build();
351 }
Yafit Hadar5796d972015-10-15 13:16:11 +0300352 //CHECKSTYLE:ON
Xin Jin313708b2015-07-09 13:43:04 -0700353
354 public static Set<Criterion.Type> getTypeSet(TrafficSelector trafficSelector) {
355 Set<Criterion.Type> typeSet = new HashSet<>();
356 for (Criterion criterion : trafficSelector.criteria()) {
357 typeSet.add(criterion.type());
358 }
359 return typeSet;
360 }
361
362 public static Criterion intersectCriterion(Criterion c1, Criterion c2) {
363 switch (c1.type()) {
364 case IPV4_SRC: {
365 IpPrefix ipPrefix = intersectIpPrefix(((IPCriterion) c1).ip(), ((IPCriterion) c2).ip());
366 if (ipPrefix == null) {
367 return null;
368 } else {
369 return Criteria.matchIPSrc(ipPrefix);
370 }
371 }
372 case IPV4_DST: {
373 IpPrefix ipPrefix = intersectIpPrefix(((IPCriterion) c1).ip(), ((IPCriterion) c2).ip());
374 if (ipPrefix == null) {
375 return null;
376 } else {
377 return Criteria.matchIPDst(ipPrefix);
378 }
379 }
380 case IPV6_SRC: {
381 IpPrefix ipPrefix = intersectIpPrefix(((IPCriterion) c1).ip(), ((IPCriterion) c2).ip());
382 if (ipPrefix == null) {
383 return null;
384 } else {
385 return Criteria.matchIPv6Src(ipPrefix);
386 }
387 }
388 case IPV6_DST: {
389 IpPrefix ipPrefix = intersectIpPrefix(((IPCriterion) c1).ip(), ((IPCriterion) c2).ip());
390 if (ipPrefix == null) {
391 return null;
392 } else {
393 return Criteria.matchIPv6Dst(ipPrefix);
394 }
395 }
396 default:
397 if (!c1.equals(c2)) {
398 return null;
399 } else {
400 return c1;
401 }
402 }
403 }
404
405 public static IpPrefix intersectIpPrefix(IpPrefix ip1, IpPrefix ip2) {
406 if (ip1.contains(ip2)) {
407 return ip1;
408 } else if (ip2.contains(ip1)) {
409 return ip2;
410 } else {
411 return null;
412 }
413 }
414
415 public static FlowObjectiveCompositionTree parsePolicyString(String policy) {
416 List<FlowObjectiveCompositionTree> postfix = transformToPostfixForm(policy);
417 return buildPolicyTree(postfix);
418 }
419
420 private static List<FlowObjectiveCompositionTree> transformToPostfixForm(String policy) {
421 Stack<Character> stack = new Stack<>();
422 List<FlowObjectiveCompositionTree> postfix = new ArrayList<>();
423
424 for (int i = 0; i < policy.length(); i++) {
425 Character ch = policy.charAt(i);
426 if (Character.isDigit(ch)) {
427
428 int applicationId = ch - '0';
429 while (i + 1 < policy.length() && Character.isDigit(policy.charAt(i + 1))) {
430 i++;
431 applicationId = applicationId * 10 + policy.charAt(i) - '0';
432 }
433
434 postfix.add(new FlowObjectiveCompositionTree((short) applicationId));
435 } else if (ch == '(') {
436 stack.push(ch);
437 } else if (ch == ')') {
438 while (stack.peek() != '(') {
439 postfix.add(new FlowObjectiveCompositionTree(stack.pop()));
440 }
441 stack.pop();
442 } else {
443 while (!stack.isEmpty() && compareOperatorPriority(stack.peek(), ch)) {
444 postfix.add(new FlowObjectiveCompositionTree(stack.pop()));
445 }
446 stack.push(ch);
447 }
448 }
449 while (!stack.isEmpty()) {
450 postfix.add(new FlowObjectiveCompositionTree(stack.pop()));
451 }
452
453 return postfix;
454 }
455
456 private static boolean compareOperatorPriority(char peek, char cur) {
457 if (peek == '/' && (cur == '+' || cur == '>' || cur == '/')) {
458 return true;
459 } else if (peek == '>' && (cur == '+' || cur == '>')) {
460 return true;
461 } else if (peek == '+' && cur == '+') {
462 return true;
463 }
464 return false;
465 }
466
467 private static FlowObjectiveCompositionTree buildPolicyTree(List<FlowObjectiveCompositionTree> postfix) {
468 Stack<FlowObjectiveCompositionTree> stack = new Stack<>();
469 for (FlowObjectiveCompositionTree node : postfix) {
470 if (node.operator == FlowObjectiveCompositionManager.PolicyOperator.Application) {
471 stack.push(node);
472 } else {
473 node.rightChild = stack.pop();
474 node.leftChild = stack.pop();
475 stack.push(node);
476 }
477 }
478 return stack.pop();
479 }
480
481 public static Collection<ForwardingObjective> minusForwardingObjectives(Collection<ForwardingObjective> fo1,
482 Collection<ForwardingObjective> fo2) {
483 Map<Integer, ForwardingObjective> map = new HashMap<>();
484 for (ForwardingObjective fo : fo1) {
485 map.put(fo.id(), fo);
486 }
487 for (ForwardingObjective fo : fo2) {
488 map.remove(fo.id());
489 }
490 return map.values();
491 }
492
493
494}