Pier Ventre

Add support for vlan based intents in the Corsa driver

Changes:
- Improves processSpecific in AbstractCorsaPipeline in order to support
Intents without an explicit match on the Ethertype;
- Implements vlan based circuits in CorsaPipelineV3 through the management
of the FwdObjective without Treatment;
- Distinguish Groups from simple actions;
- Corsa group are identified using the actions of the treatment;
- handling of the pending next similar to DefaultSingleTablePipeline

Change-Id: Iff0f70d56c64193524c6640f31ffb3f5629499dc
...@@ -93,14 +93,14 @@ public abstract class AbstractCorsaPipeline extends AbstractHandlerBehaviour imp ...@@ -93,14 +93,14 @@ public abstract class AbstractCorsaPipeline extends AbstractHandlerBehaviour imp
93 private ServiceDirectory serviceDirectory; 93 private ServiceDirectory serviceDirectory;
94 protected FlowRuleService flowRuleService; 94 protected FlowRuleService flowRuleService;
95 private CoreService coreService; 95 private CoreService coreService;
96 - private GroupService groupService; 96 + protected GroupService groupService;
97 protected MeterService meterService; 97 protected MeterService meterService;
98 - private FlowObjectiveStore flowObjectiveStore; 98 + protected FlowObjectiveStore flowObjectiveStore;
99 protected DeviceId deviceId; 99 protected DeviceId deviceId;
100 protected ApplicationId appId; 100 protected ApplicationId appId;
101 protected DeviceService deviceService; 101 protected DeviceService deviceService;
102 102
103 - private KryoNamespace appKryo = new KryoNamespace.Builder() 103 + protected KryoNamespace appKryo = new KryoNamespace.Builder()
104 .register(GroupKey.class) 104 .register(GroupKey.class)
105 .register(DefaultGroupKey.class) 105 .register(DefaultGroupKey.class)
106 .register(CorsaGroup.class) 106 .register(CorsaGroup.class)
...@@ -108,6 +108,8 @@ public abstract class AbstractCorsaPipeline extends AbstractHandlerBehaviour imp ...@@ -108,6 +108,8 @@ public abstract class AbstractCorsaPipeline extends AbstractHandlerBehaviour imp
108 .build("AbstractCorsaPipeline"); 108 .build("AbstractCorsaPipeline");
109 109
110 private Cache<GroupKey, NextObjective> pendingGroups; 110 private Cache<GroupKey, NextObjective> pendingGroups;
111 + protected Cache<Integer, NextObjective> pendingNext;
112 +
111 113
112 private ScheduledExecutorService groupChecker = 114 private ScheduledExecutorService groupChecker =
113 Executors.newScheduledThreadPool(2, groupedThreads("onos/pipeliner", 115 Executors.newScheduledThreadPool(2, groupedThreads("onos/pipeliner",
...@@ -131,6 +133,16 @@ public abstract class AbstractCorsaPipeline extends AbstractHandlerBehaviour imp ...@@ -131,6 +133,16 @@ public abstract class AbstractCorsaPipeline extends AbstractHandlerBehaviour imp
131 } 133 }
132 }).build(); 134 }).build();
133 135
136 + pendingNext = CacheBuilder.newBuilder()
137 + .expireAfterWrite(20, TimeUnit.SECONDS)
138 + .removalListener((RemovalNotification<Integer, NextObjective> notification) -> {
139 + if (notification.getCause() == RemovalCause.EXPIRED) {
140 + notification.getValue().context()
141 + .ifPresent(c -> c.onError(notification.getValue(),
142 + ObjectiveError.FLOWINSTALLATIONFAILED));
143 + }
144 + }).build();
145 +
134 groupChecker.scheduleAtFixedRate(new GroupChecker(), 0, 500, TimeUnit.MILLISECONDS); 146 groupChecker.scheduleAtFixedRate(new GroupChecker(), 0, 500, TimeUnit.MILLISECONDS);
135 147
136 coreService = serviceDirectory.get(CoreService.class); 148 coreService = serviceDirectory.get(CoreService.class);
...@@ -304,6 +316,7 @@ public abstract class AbstractCorsaPipeline extends AbstractHandlerBehaviour imp ...@@ -304,6 +316,7 @@ public abstract class AbstractCorsaPipeline extends AbstractHandlerBehaviour imp
304 316
305 @Override 317 @Override
306 public void forward(ForwardingObjective fwd) { 318 public void forward(ForwardingObjective fwd) {
319 +
307 Collection<FlowRule> rules; 320 Collection<FlowRule> rules;
308 FlowRuleOperations.Builder flowBuilder = FlowRuleOperations.builder(); 321 FlowRuleOperations.Builder flowBuilder = FlowRuleOperations.builder();
309 322
...@@ -354,16 +367,20 @@ public abstract class AbstractCorsaPipeline extends AbstractHandlerBehaviour imp ...@@ -354,16 +367,20 @@ public abstract class AbstractCorsaPipeline extends AbstractHandlerBehaviour imp
354 private Collection<FlowRule> processSpecific(ForwardingObjective fwd) { 367 private Collection<FlowRule> processSpecific(ForwardingObjective fwd) {
355 log.debug("Processing specific forwarding objective"); 368 log.debug("Processing specific forwarding objective");
356 TrafficSelector selector = fwd.selector(); 369 TrafficSelector selector = fwd.selector();
357 - EthTypeCriterion ethType = 370 + EthTypeCriterion ethTypeCriterion =
358 (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE); 371 (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE);
359 - if (ethType != null) { 372 + VlanIdCriterion vlanIdCriterion =
360 - short et = ethType.ethType().toShort(); 373 + (VlanIdCriterion) selector.getCriterion(Criterion.Type.VLAN_VID);
374 + if (ethTypeCriterion != null) {
375 + short et = ethTypeCriterion.ethType().toShort();
361 if (et == Ethernet.TYPE_IPV4) { 376 if (et == Ethernet.TYPE_IPV4) {
362 return processSpecificRoute(fwd); 377 return processSpecificRoute(fwd);
363 } else if (et == Ethernet.TYPE_VLAN) { 378 } else if (et == Ethernet.TYPE_VLAN) {
364 /* The ForwardingObjective must specify VLAN ethtype in order to use the Transit Circuit */ 379 /* The ForwardingObjective must specify VLAN ethtype in order to use the Transit Circuit */
365 return processSpecificSwitch(fwd); 380 return processSpecificSwitch(fwd);
366 } 381 }
382 + } else if (vlanIdCriterion != null) {
383 + return processSpecificSwitch(fwd);
367 } 384 }
368 385
369 fail(fwd, ObjectiveError.UNSUPPORTED); 386 fail(fwd, ObjectiveError.UNSUPPORTED);
...@@ -464,6 +481,41 @@ public abstract class AbstractCorsaPipeline extends AbstractHandlerBehaviour imp ...@@ -464,6 +481,41 @@ public abstract class AbstractCorsaPipeline extends AbstractHandlerBehaviour imp
464 //Hook for modifying Route flow rule 481 //Hook for modifying Route flow rule
465 protected abstract Builder processSpecificRoutingRule(Builder rb); 482 protected abstract Builder processSpecificRoutingRule(Builder rb);
466 483
484 + protected enum CorsaTrafficTreatmentType {
485 + /**
486 + * If the treatment has to be handled as group.
487 + */
488 + GROUP,
489 + /**
490 + * If the treatment has to be handled as simple set of actions.
491 + */
492 + ACTIONS
493 + }
494 +
495 + /**
496 + * Helper class to encapsulate both traffic treatment and
497 + * type of treatment.
498 + */
499 + protected class CorsaTrafficTreatment {
500 +
501 + private CorsaTrafficTreatmentType type;
502 + private TrafficTreatment trafficTreatment;
503 +
504 + public CorsaTrafficTreatment(CorsaTrafficTreatmentType treatmentType, TrafficTreatment trafficTreatment) {
505 + this.type = treatmentType;
506 + this.trafficTreatment = trafficTreatment;
507 + }
508 +
509 + public CorsaTrafficTreatmentType type() {
510 + return type;
511 + }
512 +
513 + public TrafficTreatment treatment() {
514 + return trafficTreatment;
515 + }
516 +
517 + }
518 +
467 @Override 519 @Override
468 public void next(NextObjective nextObjective) { 520 public void next(NextObjective nextObjective) {
469 switch (nextObjective.type()) { 521 switch (nextObjective.type()) {
...@@ -471,20 +523,25 @@ public abstract class AbstractCorsaPipeline extends AbstractHandlerBehaviour imp ...@@ -471,20 +523,25 @@ public abstract class AbstractCorsaPipeline extends AbstractHandlerBehaviour imp
471 Collection<TrafficTreatment> treatments = nextObjective.next(); 523 Collection<TrafficTreatment> treatments = nextObjective.next();
472 if (treatments.size() == 1) { 524 if (treatments.size() == 1) {
473 TrafficTreatment treatment = treatments.iterator().next(); 525 TrafficTreatment treatment = treatments.iterator().next();
474 - treatment = processNextTreatment(treatment); 526 + CorsaTrafficTreatment corsaTreatment = processNextTreatment(treatment);
475 - GroupBucket bucket =
476 - DefaultGroupBucket.createIndirectGroupBucket(treatment);
477 final GroupKey key = new DefaultGroupKey(appKryo.serialize(nextObjective.id())); 527 final GroupKey key = new DefaultGroupKey(appKryo.serialize(nextObjective.id()));
478 - GroupDescription groupDescription 528 + if (corsaTreatment.type() == CorsaTrafficTreatmentType.GROUP) {
479 - = new DefaultGroupDescription(deviceId, 529 + GroupBucket bucket = DefaultGroupBucket.createIndirectGroupBucket(corsaTreatment.treatment());
530 + GroupBuckets buckets = new GroupBuckets(Collections.singletonList(bucket));
531 + // group id == null, let group service determine group id
532 + GroupDescription groupDescription = new DefaultGroupDescription(deviceId,
480 GroupDescription.Type.INDIRECT, 533 GroupDescription.Type.INDIRECT,
481 - new GroupBuckets(Collections 534 + buckets,
482 - .singletonList(bucket)),
483 key, 535 key,
484 - null, // let group service determine group id 536 + null,
485 nextObjective.appId()); 537 nextObjective.appId());
486 groupService.addGroup(groupDescription); 538 groupService.addGroup(groupDescription);
487 pendingGroups.put(key, nextObjective); 539 pendingGroups.put(key, nextObjective);
540 + } else if (corsaTreatment.type() == CorsaTrafficTreatmentType.ACTIONS) {
541 + pendingNext.put(nextObjective.id(), nextObjective);
542 + flowObjectiveStore.putNextGroup(nextObjective.id(), new CorsaGroup(key));
543 + nextObjective.context().ifPresent(context -> context.onSuccess(nextObjective));
544 + }
488 } 545 }
489 break; 546 break;
490 case HASHED: 547 case HASHED:
...@@ -501,8 +558,8 @@ public abstract class AbstractCorsaPipeline extends AbstractHandlerBehaviour imp ...@@ -501,8 +558,8 @@ public abstract class AbstractCorsaPipeline extends AbstractHandlerBehaviour imp
501 } 558 }
502 559
503 //Hook for altering the NextObjective treatment 560 //Hook for altering the NextObjective treatment
504 - protected TrafficTreatment processNextTreatment(TrafficTreatment treatment) { 561 + protected CorsaTrafficTreatment processNextTreatment(TrafficTreatment treatment) {
505 - return treatment; 562 + return new CorsaTrafficTreatment(CorsaTrafficTreatmentType.GROUP, treatment);
506 } 563 }
507 564
508 //Init helper: Table Miss = Drop 565 //Init helper: Table Miss = Drop
......
...@@ -30,9 +30,12 @@ import org.onosproject.net.flow.criteria.EthCriterion; ...@@ -30,9 +30,12 @@ import org.onosproject.net.flow.criteria.EthCriterion;
30 import org.onosproject.net.flow.criteria.IPCriterion; 30 import org.onosproject.net.flow.criteria.IPCriterion;
31 import org.onosproject.net.flow.criteria.PortCriterion; 31 import org.onosproject.net.flow.criteria.PortCriterion;
32 import org.onosproject.net.flow.criteria.VlanIdCriterion; 32 import org.onosproject.net.flow.criteria.VlanIdCriterion;
33 +import org.onosproject.net.flow.instructions.Instruction;
33 import org.onosproject.net.flow.instructions.L2ModificationInstruction; 34 import org.onosproject.net.flow.instructions.L2ModificationInstruction;
34 import org.onosproject.net.flowobjective.FilteringObjective; 35 import org.onosproject.net.flowobjective.FilteringObjective;
35 import org.onosproject.net.flowobjective.ForwardingObjective; 36 import org.onosproject.net.flowobjective.ForwardingObjective;
37 +import org.onosproject.net.flowobjective.NextObjective;
38 +import org.onosproject.net.flowobjective.ObjectiveError;
36 import org.onosproject.net.meter.Band; 39 import org.onosproject.net.meter.Band;
37 import org.onosproject.net.meter.DefaultBand; 40 import org.onosproject.net.meter.DefaultBand;
38 import org.onosproject.net.meter.DefaultMeterRequest; 41 import org.onosproject.net.meter.DefaultMeterRequest;
...@@ -69,9 +72,11 @@ public class CorsaPipelineV3 extends AbstractCorsaPipeline { ...@@ -69,9 +72,11 @@ public class CorsaPipelineV3 extends AbstractCorsaPipeline {
69 protected MeterId defaultMeterId = null; 72 protected MeterId defaultMeterId = null;
70 73
71 @Override 74 @Override
72 - protected TrafficTreatment processNextTreatment(TrafficTreatment treatment) { 75 + protected CorsaTrafficTreatment processNextTreatment(TrafficTreatment treatment) {
73 TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder(); 76 TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder();
74 77
78 +
79 +
75 treatment.immediate().stream() 80 treatment.immediate().stream()
76 .filter(i -> { 81 .filter(i -> {
77 switch (i.type()) { 82 switch (i.type()) {
...@@ -87,7 +92,48 @@ public class CorsaPipelineV3 extends AbstractCorsaPipeline { ...@@ -87,7 +92,48 @@ public class CorsaPipelineV3 extends AbstractCorsaPipeline {
87 return false; 92 return false;
88 } 93 }
89 }).forEach(i -> tb.add(i)); 94 }).forEach(i -> tb.add(i));
90 - return tb.build(); 95 +
96 + TrafficTreatment t = tb.build();
97 +
98 +
99 + boolean isPresentModVlanId = false;
100 + boolean isPresentModEthSrc = false;
101 + boolean isPresentModEthDst = false;
102 + boolean isPresentOutpuPort = false;
103 +
104 + for (Instruction instruction : t.immediate()) {
105 + switch (instruction.type()) {
106 + case L2MODIFICATION:
107 + L2ModificationInstruction l2i = (L2ModificationInstruction) instruction;
108 + if (l2i instanceof L2ModificationInstruction.ModVlanIdInstruction) {
109 + isPresentModVlanId = true;
110 + }
111 +
112 + if (l2i instanceof L2ModificationInstruction.ModEtherInstruction) {
113 + L2ModificationInstruction.L2SubType subType = l2i.subtype();
114 + if (subType.equals(L2ModificationInstruction.L2SubType.ETH_SRC)) {
115 + isPresentModEthSrc = true;
116 + } else if (subType.equals(L2ModificationInstruction.L2SubType.ETH_DST)) {
117 + isPresentModEthDst = true;
118 + }
119 + }
120 + case OUTPUT:
121 + isPresentOutpuPort = true;
122 + default:
123 + }
124 + }
125 + CorsaTrafficTreatmentType type = CorsaTrafficTreatmentType.ACTIONS;
126 + /**
127 + * This represents the allowed group for CorsaPipelinev3
128 + */
129 + if (isPresentModVlanId &&
130 + isPresentModEthSrc &&
131 + isPresentModEthDst &&
132 + isPresentOutpuPort) {
133 + type = CorsaTrafficTreatmentType.GROUP;
134 + }
135 + CorsaTrafficTreatment corsaTreatment = new CorsaTrafficTreatment(type, t);
136 + return corsaTreatment;
91 } 137 }
92 138
93 @Override 139 @Override
...@@ -115,9 +161,37 @@ public class CorsaPipelineV3 extends AbstractCorsaPipeline { ...@@ -115,9 +161,37 @@ public class CorsaPipelineV3 extends AbstractCorsaPipeline {
115 .withPriority(fwd.priority()) 161 .withPriority(fwd.priority())
116 .forDevice(deviceId) 162 .forDevice(deviceId)
117 .withSelector(filteredSelector) 163 .withSelector(filteredSelector)
118 - .withTreatment(fwd.treatment())
119 .forTable(VLAN_CIRCUIT_TABLE); 164 .forTable(VLAN_CIRCUIT_TABLE);
120 165
166 + if (fwd.treatment() != null) {
167 + ruleBuilder.withTreatment(fwd.treatment());
168 + } else {
169 + if (fwd.nextId() != null) {
170 + NextObjective nextObjective = pendingNext.getIfPresent(fwd.nextId());
171 + if (nextObjective != null) {
172 + pendingNext.invalidate(fwd.nextId());
173 + TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder()
174 + .setVlanPcp((byte) 0)
175 + .setQueue(0)
176 + .meter(defaultMeterId);
177 + nextObjective.next().forEach(trafficTreatment -> {
178 + trafficTreatment.allInstructions().forEach(instruction -> {
179 + treatment.add(instruction);
180 + });
181 + });
182 + ruleBuilder.withTreatment(treatment.build());
183 + } else {
184 + log.warn("The group left!");
185 + fwd.context().ifPresent(c -> c.onError(fwd, ObjectiveError.GROUPMISSING));
186 + return ImmutableSet.of();
187 + }
188 + } else {
189 + log.warn("Missing NextObjective ID for ForwardingObjective {}", fwd.id());
190 + fail(fwd, ObjectiveError.BADPARAMS);
191 + return ImmutableSet.of();
192 + }
193 + }
194 +
121 if (fwd.permanent()) { 195 if (fwd.permanent()) {
122 ruleBuilder.makePermanent(); 196 ruleBuilder.makePermanent();
123 } else { 197 } else {
......
...@@ -29,6 +29,7 @@ import org.onosproject.net.flow.TrafficTreatment; ...@@ -29,6 +29,7 @@ import org.onosproject.net.flow.TrafficTreatment;
29 import org.onosproject.net.flow.criteria.Criterion; 29 import org.onosproject.net.flow.criteria.Criterion;
30 import org.onosproject.net.flow.criteria.IPCriterion; 30 import org.onosproject.net.flow.criteria.IPCriterion;
31 import org.onosproject.net.flow.criteria.IPProtocolCriterion; 31 import org.onosproject.net.flow.criteria.IPProtocolCriterion;
32 +import org.onosproject.net.flow.instructions.Instruction;
32 import org.onosproject.net.flow.instructions.Instructions; 33 import org.onosproject.net.flow.instructions.Instructions;
33 import org.onosproject.net.flow.instructions.L2ModificationInstruction; 34 import org.onosproject.net.flow.instructions.L2ModificationInstruction;
34 import org.onosproject.net.flowobjective.ForwardingObjective; 35 import org.onosproject.net.flowobjective.ForwardingObjective;
...@@ -226,9 +227,8 @@ public class CorsaPipelineV39 extends CorsaPipelineV3 { ...@@ -226,9 +227,8 @@ public class CorsaPipelineV39 extends CorsaPipelineV3 {
226 } 227 }
227 228
228 @Override 229 @Override
229 - protected TrafficTreatment processNextTreatment(TrafficTreatment treatment) { 230 + protected CorsaTrafficTreatment processNextTreatment(TrafficTreatment treatment) {
230 TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder(); 231 TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder();
231 - tb.add(Instructions.popVlan());
232 treatment.immediate().stream() 232 treatment.immediate().stream()
233 .filter(i -> { 233 .filter(i -> {
234 switch (i.type()) { 234 switch (i.type()) {
...@@ -236,7 +236,6 @@ public class CorsaPipelineV39 extends CorsaPipelineV3 { ...@@ -236,7 +236,6 @@ public class CorsaPipelineV39 extends CorsaPipelineV3 {
236 L2ModificationInstruction l2i = (L2ModificationInstruction) i; 236 L2ModificationInstruction l2i = (L2ModificationInstruction) i;
237 if (l2i.subtype() == VLAN_ID || 237 if (l2i.subtype() == VLAN_ID ||
238 l2i.subtype() == VLAN_POP || 238 l2i.subtype() == VLAN_POP ||
239 - l2i.subtype() == VLAN_POP ||
240 l2i.subtype() == ETH_DST || 239 l2i.subtype() == ETH_DST ||
241 l2i.subtype() == ETH_SRC) { 240 l2i.subtype() == ETH_SRC) {
242 return true; 241 return true;
...@@ -247,6 +246,51 @@ public class CorsaPipelineV39 extends CorsaPipelineV3 { ...@@ -247,6 +246,51 @@ public class CorsaPipelineV39 extends CorsaPipelineV3 {
247 return false; 246 return false;
248 } 247 }
249 }).forEach(i -> tb.add(i)); 248 }).forEach(i -> tb.add(i));
250 - return tb.build(); 249 +
250 + TrafficTreatment t = tb.build();
251 +
252 + boolean isPresentModVlanId = false;
253 + boolean isPresentModEthSrc = false;
254 + boolean isPresentModEthDst = false;
255 + boolean isPresentOutpuPort = false;
256 +
257 + for (Instruction instruction : t.immediate()) {
258 + switch (instruction.type()) {
259 + case L2MODIFICATION:
260 + L2ModificationInstruction l2i = (L2ModificationInstruction) instruction;
261 + if (l2i instanceof L2ModificationInstruction.ModVlanIdInstruction) {
262 + isPresentModVlanId = true;
263 + }
264 +
265 + if (l2i instanceof L2ModificationInstruction.ModEtherInstruction) {
266 + L2ModificationInstruction.L2SubType subType = l2i.subtype();
267 + if (subType.equals(L2ModificationInstruction.L2SubType.ETH_SRC)) {
268 + isPresentModEthSrc = true;
269 + } else if (subType.equals(L2ModificationInstruction.L2SubType.ETH_DST)) {
270 + isPresentModEthDst = true;
271 + }
272 + }
273 + case OUTPUT:
274 + isPresentOutpuPort = true;
275 + default:
276 + }
277 + }
278 + CorsaTrafficTreatmentType type = CorsaTrafficTreatmentType.ACTIONS;
279 + /**
280 + * These are the allowed groups for CorsaPipelinev39
281 + */
282 + if (isPresentModVlanId && isPresentModEthSrc && isPresentModEthDst && isPresentOutpuPort) {
283 + type = CorsaTrafficTreatmentType.GROUP;
284 +
285 + } else if ((!isPresentModVlanId && isPresentModEthSrc && isPresentModEthDst && isPresentOutpuPort) ||
286 + (!isPresentModVlanId && !isPresentModEthSrc && isPresentModEthDst && isPresentOutpuPort) ||
287 + (!isPresentModVlanId && !isPresentModEthSrc && !isPresentModEthDst && isPresentOutpuPort)) {
288 + type = CorsaTrafficTreatmentType.GROUP;
289 + TrafficTreatment.Builder tb2 = DefaultTrafficTreatment.builder(t);
290 + tb2.add(Instructions.popVlan());
291 + t = tb2.build();
292 + }
293 + CorsaTrafficTreatment corsaTreatment = new CorsaTrafficTreatment(type, t);
294 + return corsaTreatment;
251 } 295 }
252 } 296 }
......