blob: 1474709172547c361481c4a0fa48543f055382b7 [file] [log] [blame]
Xin Jin313708b2015-07-09 13:43:04 -07001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2015-present Open Networking Laboratory
Xin Jin313708b2015-07-09 13:43:04 -07003 *
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
159 public static TrafficSelector revertTreatmentSelector(TrafficTreatment trafficTreatment,
160 TrafficSelector trafficSelector) {
161
162 TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder();
163
164 Map<Criterion.Type, Criterion> criterionMap = new HashMap<>();
165 for (Criterion criterion : trafficSelector.criteria()) {
166 criterionMap.put(criterion.type(), criterion);
167 }
168
169 for (Instruction instruction : trafficTreatment.allInstructions()) {
170 switch (instruction.type()) {
Xin Jin313708b2015-07-09 13:43:04 -0700171 case OUTPUT:
172 break;
173 case GROUP:
174 break;
175 case L0MODIFICATION: {
176 L0ModificationInstruction l0 = (L0ModificationInstruction) instruction;
177 switch (l0.subtype()) {
Xin Jin313708b2015-07-09 13:43:04 -0700178 case OCH:
179 if (criterionMap.containsKey(Criterion.Type.OCH_SIGID)) {
180 if (((OchSignalCriterion) criterionMap.get((Criterion.Type.OCH_SIGID))).lambda()
181 .equals(((L0ModificationInstruction.ModOchSignalInstruction) l0).lambda())) {
182 criterionMap.remove(Criterion.Type.OCH_SIGID);
183 } else {
184 return null;
185 }
Xin Jin313708b2015-07-09 13:43:04 -0700186 }
187 default:
188 break;
189 }
190 break;
191 }
Yafit Hadar5796d972015-10-15 13:16:11 +0300192 case L1MODIFICATION: {
193 L1ModificationInstruction l1 = (L1ModificationInstruction) instruction;
194 switch (l1.subtype()) {
195 case ODU_SIGID:
196 if (criterionMap.containsKey(Criterion.Type.ODU_SIGID)) {
197 if (((OduSignalIdCriterion) criterionMap.get((Criterion.Type.ODU_SIGID))).oduSignalId()
198 .equals(((L1ModificationInstruction.ModOduSignalIdInstruction) l1)
199 .oduSignalId())) {
200 criterionMap.remove(Criterion.Type.ODU_SIGID);
201 } else {
202 return null;
203 }
Ray Milkey125572b2016-02-22 16:48:17 -0800204 }
Yafit Hadar5796d972015-10-15 13:16:11 +0300205 default:
206 break;
207 }
208 break;
209 }
Xin Jin313708b2015-07-09 13:43:04 -0700210 case L2MODIFICATION: {
211 L2ModificationInstruction l2 = (L2ModificationInstruction) instruction;
212 switch (l2.subtype()) {
213 case ETH_SRC:
214 if (criterionMap.containsKey(Criterion.Type.ETH_SRC)) {
215 if (((EthCriterion) criterionMap.get((Criterion.Type.ETH_SRC))).mac()
216 .equals(((L2ModificationInstruction.ModEtherInstruction) l2).mac())) {
217 criterionMap.remove(Criterion.Type.ETH_SRC);
218 } else {
219 return null;
220 }
221 } else {
222 break;
223 }
224 case ETH_DST:
225 if (criterionMap.containsKey(Criterion.Type.ETH_DST)) {
226 if (((EthCriterion) criterionMap.get((Criterion.Type.ETH_DST))).mac()
227 .equals(((L2ModificationInstruction.ModEtherInstruction) l2).mac())) {
228 criterionMap.remove(Criterion.Type.ETH_DST);
229 } else {
230 return null;
231 }
232 } else {
233 break;
234 }
235 case VLAN_ID:
236 if (criterionMap.containsKey(Criterion.Type.VLAN_VID)) {
237 if (((VlanIdCriterion) criterionMap.get((Criterion.Type.VLAN_VID))).vlanId()
238 .equals(((L2ModificationInstruction.ModVlanIdInstruction) l2).vlanId())) {
239 criterionMap.remove(Criterion.Type.VLAN_VID);
240 } else {
241 return null;
242 }
243 } else {
244 break;
245 }
246 case VLAN_PCP:
247 if (criterionMap.containsKey(Criterion.Type.VLAN_PCP)) {
248 if (((VlanPcpCriterion) criterionMap.get((Criterion.Type.VLAN_PCP))).priority()
249 == ((L2ModificationInstruction.ModVlanPcpInstruction) l2).vlanPcp()) {
250 criterionMap.remove(Criterion.Type.VLAN_PCP);
251 } else {
252 return null;
253 }
254 } else {
255 break;
256 }
257 case MPLS_LABEL:
258 if (criterionMap.containsKey(Criterion.Type.MPLS_LABEL)) {
259 if (((MplsCriterion) criterionMap.get((Criterion.Type.MPLS_LABEL))).label()
Ray Milkey125572b2016-02-22 16:48:17 -0800260 .equals(((L2ModificationInstruction.ModMplsLabelInstruction) l2).label())) {
Xin Jin313708b2015-07-09 13:43:04 -0700261 criterionMap.remove(Criterion.Type.ETH_DST);
262 } else {
263 return null;
264 }
265 } else {
266 break;
267 }
268 default:
269 break;
270 }
271 break;
272 }
273 case TABLE:
274 break;
275 case L3MODIFICATION: {
276 L3ModificationInstruction l3 = (L3ModificationInstruction) instruction;
277 switch (l3.subtype()) {
278 case IPV4_SRC:
279 if (criterionMap.containsKey(Criterion.Type.IPV4_SRC)) {
280 if (((IPCriterion) criterionMap.get(Criterion.Type.IPV4_SRC)).ip()
281 .contains(((L3ModificationInstruction.ModIPInstruction) l3).ip())) {
282 criterionMap.remove(Criterion.Type.IPV4_SRC);
283 } else {
284 return null;
285 }
286 } else {
287 break;
288 }
289 case IPV4_DST:
290 if (criterionMap.containsKey(Criterion.Type.IPV4_DST)) {
291 if (((IPCriterion) criterionMap.get(Criterion.Type.IPV4_DST)).ip()
292 .contains(((L3ModificationInstruction.ModIPInstruction) l3).ip())) {
293 criterionMap.remove(Criterion.Type.IPV4_DST);
294 } else {
295 return null;
296 }
297 } else {
298 break;
299 }
300 case IPV6_SRC:
301 if (criterionMap.containsKey(Criterion.Type.IPV6_SRC)) {
302 if (((IPCriterion) criterionMap.get(Criterion.Type.IPV6_SRC)).ip()
303 .contains(((L3ModificationInstruction.ModIPInstruction) l3).ip())) {
304 criterionMap.remove(Criterion.Type.IPV6_SRC);
305 } else {
306 return null;
307 }
308 } else {
309 break;
310 }
311 case IPV6_DST:
312 if (criterionMap.containsKey(Criterion.Type.IPV6_DST)) {
313 if (((IPCriterion) criterionMap.get(Criterion.Type.IPV6_DST)).ip()
314 .contains(((L3ModificationInstruction.ModIPInstruction) l3).ip())) {
315 criterionMap.remove(Criterion.Type.IPV6_DST);
316 } else {
317 return null;
318 }
319 } else {
320 break;
321 }
322 case IPV6_FLABEL:
323 if (criterionMap.containsKey(Criterion.Type.IPV6_FLABEL)) {
HIGUCHI Yutad275afd2015-09-09 09:57:34 +0900324 if (((IPv6FlowLabelCriterion) criterionMap.get(Criterion.Type.IPV6_FLABEL)).flowLabel()
325 == (((L3ModificationInstruction.ModIPv6FlowLabelInstruction) l3).flowLabel())) {
Xin Jin313708b2015-07-09 13:43:04 -0700326 criterionMap.remove(Criterion.Type.IPV4_SRC);
327 } else {
328 return null;
329 }
330 } else {
331 break;
332 }
333 default:
334 break;
335 }
336 break;
337 }
338 case METADATA:
339 break;
340 default:
341 break;
342 }
343 }
344
345 for (Criterion criterion : criterionMap.values()) {
346 selectorBuilder.add(criterion);
347 }
348
349 return selectorBuilder.build();
350 }
Yafit Hadar5796d972015-10-15 13:16:11 +0300351 //CHECKSTYLE:ON
Xin Jin313708b2015-07-09 13:43:04 -0700352
353 public static Set<Criterion.Type> getTypeSet(TrafficSelector trafficSelector) {
354 Set<Criterion.Type> typeSet = new HashSet<>();
355 for (Criterion criterion : trafficSelector.criteria()) {
356 typeSet.add(criterion.type());
357 }
358 return typeSet;
359 }
360
361 public static Criterion intersectCriterion(Criterion c1, Criterion c2) {
362 switch (c1.type()) {
363 case IPV4_SRC: {
364 IpPrefix ipPrefix = intersectIpPrefix(((IPCriterion) c1).ip(), ((IPCriterion) c2).ip());
365 if (ipPrefix == null) {
366 return null;
367 } else {
368 return Criteria.matchIPSrc(ipPrefix);
369 }
370 }
371 case IPV4_DST: {
372 IpPrefix ipPrefix = intersectIpPrefix(((IPCriterion) c1).ip(), ((IPCriterion) c2).ip());
373 if (ipPrefix == null) {
374 return null;
375 } else {
376 return Criteria.matchIPDst(ipPrefix);
377 }
378 }
379 case IPV6_SRC: {
380 IpPrefix ipPrefix = intersectIpPrefix(((IPCriterion) c1).ip(), ((IPCriterion) c2).ip());
381 if (ipPrefix == null) {
382 return null;
383 } else {
384 return Criteria.matchIPv6Src(ipPrefix);
385 }
386 }
387 case IPV6_DST: {
388 IpPrefix ipPrefix = intersectIpPrefix(((IPCriterion) c1).ip(), ((IPCriterion) c2).ip());
389 if (ipPrefix == null) {
390 return null;
391 } else {
392 return Criteria.matchIPv6Dst(ipPrefix);
393 }
394 }
395 default:
396 if (!c1.equals(c2)) {
397 return null;
398 } else {
399 return c1;
400 }
401 }
402 }
403
404 public static IpPrefix intersectIpPrefix(IpPrefix ip1, IpPrefix ip2) {
405 if (ip1.contains(ip2)) {
406 return ip1;
407 } else if (ip2.contains(ip1)) {
408 return ip2;
409 } else {
410 return null;
411 }
412 }
413
414 public static FlowObjectiveCompositionTree parsePolicyString(String policy) {
415 List<FlowObjectiveCompositionTree> postfix = transformToPostfixForm(policy);
416 return buildPolicyTree(postfix);
417 }
418
419 private static List<FlowObjectiveCompositionTree> transformToPostfixForm(String policy) {
420 Stack<Character> stack = new Stack<>();
421 List<FlowObjectiveCompositionTree> postfix = new ArrayList<>();
422
423 for (int i = 0; i < policy.length(); i++) {
424 Character ch = policy.charAt(i);
425 if (Character.isDigit(ch)) {
426
427 int applicationId = ch - '0';
428 while (i + 1 < policy.length() && Character.isDigit(policy.charAt(i + 1))) {
429 i++;
430 applicationId = applicationId * 10 + policy.charAt(i) - '0';
431 }
432
433 postfix.add(new FlowObjectiveCompositionTree((short) applicationId));
434 } else if (ch == '(') {
435 stack.push(ch);
436 } else if (ch == ')') {
437 while (stack.peek() != '(') {
438 postfix.add(new FlowObjectiveCompositionTree(stack.pop()));
439 }
440 stack.pop();
441 } else {
442 while (!stack.isEmpty() && compareOperatorPriority(stack.peek(), ch)) {
443 postfix.add(new FlowObjectiveCompositionTree(stack.pop()));
444 }
445 stack.push(ch);
446 }
447 }
448 while (!stack.isEmpty()) {
449 postfix.add(new FlowObjectiveCompositionTree(stack.pop()));
450 }
451
452 return postfix;
453 }
454
455 private static boolean compareOperatorPriority(char peek, char cur) {
456 if (peek == '/' && (cur == '+' || cur == '>' || cur == '/')) {
457 return true;
458 } else if (peek == '>' && (cur == '+' || cur == '>')) {
459 return true;
460 } else if (peek == '+' && cur == '+') {
461 return true;
462 }
463 return false;
464 }
465
466 private static FlowObjectiveCompositionTree buildPolicyTree(List<FlowObjectiveCompositionTree> postfix) {
467 Stack<FlowObjectiveCompositionTree> stack = new Stack<>();
468 for (FlowObjectiveCompositionTree node : postfix) {
469 if (node.operator == FlowObjectiveCompositionManager.PolicyOperator.Application) {
470 stack.push(node);
471 } else {
472 node.rightChild = stack.pop();
473 node.leftChild = stack.pop();
474 stack.push(node);
475 }
476 }
477 return stack.pop();
478 }
479
480 public static Collection<ForwardingObjective> minusForwardingObjectives(Collection<ForwardingObjective> fo1,
481 Collection<ForwardingObjective> fo2) {
482 Map<Integer, ForwardingObjective> map = new HashMap<>();
483 for (ForwardingObjective fo : fo1) {
484 map.put(fo.id(), fo);
485 }
486 for (ForwardingObjective fo : fo2) {
487 map.remove(fo.id());
488 }
489 return map.values();
490 }
491
492
493}