ONOS-7402 Broadcast objective type support by FabricNextPipeliner.
Change-Id: I08b544a82e257091a079648c07b1dc6fb72c9ab9
diff --git a/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/pipeliner/FabricNextPipeliner.java b/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/pipeliner/FabricNextPipeliner.java
index 3b66b1b..d8dcc8a 100644
--- a/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/pipeliner/FabricNextPipeliner.java
+++ b/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/pipeliner/FabricNextPipeliner.java
@@ -17,6 +17,7 @@
package org.onosproject.pipelines.fabric.pipeliner;
import org.onlab.packet.VlanId;
+import org.onlab.util.ImmutableByteSequence;
import org.onosproject.net.DeviceId;
import org.onosproject.net.PortNumber;
import org.onosproject.net.driver.Driver;
@@ -37,10 +38,14 @@
import org.onosproject.net.flowobjective.ObjectiveError;
import org.onosproject.net.group.DefaultGroupBucket;
import org.onosproject.net.group.DefaultGroupDescription;
+import org.onosproject.net.group.DefaultGroupKey;
import org.onosproject.net.group.GroupBucket;
import org.onosproject.net.group.GroupBuckets;
import org.onosproject.net.group.GroupDescription;
+import org.onosproject.net.group.GroupKey;
+import org.onosproject.net.pi.runtime.PiAction;
import org.onosproject.net.pi.runtime.PiActionGroupId;
+import org.onosproject.net.pi.runtime.PiActionParam;
import org.onosproject.net.pi.runtime.PiGroupKey;
import org.onosproject.pipelines.fabric.FabricConstants;
import org.slf4j.Logger;
@@ -77,6 +82,9 @@
case HASHED:
processHashedNext(nextObjective, resultBuilder);
break;
+ case BROADCAST:
+ processBroadcastNext(nextObjective, resultBuilder);
+ break;
default:
log.warn("Unsupported next type {}", nextObjective);
resultBuilder.setError(ObjectiveError.UNSUPPORTED);
@@ -292,4 +300,62 @@
.matchPi(nextIdCriterion)
.build();
}
+
+ private void processBroadcastNext(NextObjective next, PipelinerTranslationResult.Builder resultBuilder) {
+ int groupId = next.id();
+ List<GroupBucket> bucketList = next.next().stream()
+ .filter(treatment -> treatment != null)
+ .map(DefaultGroupBucket::createAllGroupBucket)
+ .collect(Collectors.toList());
+
+ if (bucketList.size() != next.next().size()) {
+ // some action not converted
+ // set error
+ log.warn("Expected bucket size {}, got {}", next.next().size(), bucketList.size());
+ resultBuilder.setError(ObjectiveError.BADPARAMS);
+ return;
+ }
+
+ GroupBuckets buckets = new GroupBuckets(bucketList);
+ //Used DefaultGroupKey instead of PiGroupKey
+ //as we don't have any action profile to apply to the groups of ALL type
+ GroupKey groupKey = new DefaultGroupKey(FabricPipeliner.KRYO.serialize(groupId));
+
+ resultBuilder.addGroup(new DefaultGroupDescription(deviceId,
+ GroupDescription.Type.ALL,
+ buckets,
+ groupKey,
+ groupId,
+ next.appId()));
+ //flow rule
+ TrafficSelector selector = buildNextIdSelector(next.id());
+ PiActionParam groupIdParam = new PiActionParam(FabricConstants.GID,
+ ImmutableByteSequence.copyFrom(groupId));
+
+ PiAction setMcGroupAction = PiAction.builder()
+ .withId(FabricConstants.FABRIC_INGRESS_NEXT_SET_MCAST_GROUP)
+ .withParameter(groupIdParam)
+ .build();
+ TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+ .piTableAction(setMcGroupAction)
+ .build();
+
+ resultBuilder.addFlowRule(DefaultFlowRule.builder()
+ .withSelector(selector)
+ .withTreatment(treatment)
+ .forTable(FabricConstants.FABRIC_INGRESS_NEXT_MULTICAST)
+ .makePermanent()
+ .withPriority(next.priority())
+ .forDevice(deviceId)
+ .fromApp(next.appId())
+ .build());
+
+ // Egress VLAN handling
+ next.next().forEach(trafficTreatment -> {
+ PortNumber outputPort = getOutputPort(trafficTreatment);
+ if (includesPopVlanInst(trafficTreatment) && outputPort != null) {
+ processVlanPopRule(outputPort, next, resultBuilder);
+ }
+ });
+ }
}
diff --git a/pipelines/fabric/src/test/java/org/onosproject/pipelines/fabric/pipeliner/FabricNextPipelinerTest.java b/pipelines/fabric/src/test/java/org/onosproject/pipelines/fabric/pipeliner/FabricNextPipelinerTest.java
index e2a6af8..bfae578 100644
--- a/pipelines/fabric/src/test/java/org/onosproject/pipelines/fabric/pipeliner/FabricNextPipelinerTest.java
+++ b/pipelines/fabric/src/test/java/org/onosproject/pipelines/fabric/pipeliner/FabricNextPipelinerTest.java
@@ -17,8 +17,8 @@
package org.onosproject.pipelines.fabric.pipeliner;
import com.google.common.collect.ImmutableList;
-import org.junit.Ignore;
import org.junit.Test;
+import org.onlab.util.ImmutableByteSequence;
import org.onosproject.net.flow.DefaultFlowRule;
import org.onosproject.net.flow.DefaultTrafficSelector;
import org.onosproject.net.flow.DefaultTrafficTreatment;
@@ -30,10 +30,14 @@
import org.onosproject.net.flowobjective.NextObjective;
import org.onosproject.net.group.DefaultGroupBucket;
import org.onosproject.net.group.DefaultGroupDescription;
+import org.onosproject.net.group.DefaultGroupKey;
import org.onosproject.net.group.GroupBucket;
import org.onosproject.net.group.GroupBuckets;
import org.onosproject.net.group.GroupDescription;
+import org.onosproject.net.group.GroupKey;
+import org.onosproject.net.pi.runtime.PiAction;
import org.onosproject.net.pi.runtime.PiActionGroupId;
+import org.onosproject.net.pi.runtime.PiActionParam;
import org.onosproject.net.pi.runtime.PiGroupKey;
import org.onosproject.pipelines.fabric.FabricConstants;
@@ -257,8 +261,113 @@
* Test program output group for Broadcast table.
*/
@Test
- @Ignore
public void testBroadcastOutput() {
+ TrafficTreatment treatment1 = DefaultTrafficTreatment.builder()
+ .setOutput(PORT_1)
+ .build();
+ TrafficTreatment treatment2 = DefaultTrafficTreatment.builder()
+ .popVlan()
+ .setOutput(PORT_2)
+ .build();
+ NextObjective nextObjective = DefaultNextObjective.builder()
+ .withId(NEXT_ID_1)
+ .withPriority(PRIORITY)
+ .addTreatment(treatment1)
+ .addTreatment(treatment2)
+ .withMeta(VLAN_META)
+ .withType(NextObjective.Type.BROADCAST)
+ .makePermanent()
+ .fromApp(APP_ID)
+ .add();
+ PipelinerTranslationResult result = pipeliner.pipelinerNext.next(nextObjective);
+
+ // Should generate 1 flow, 1 group and 2 buckets in it
+ List<FlowRule> flowRulesInstalled = (List<FlowRule>) result.flowRules();
+ List<GroupDescription> groupsInstalled = (List<GroupDescription>) result.groups();
+ assertEquals(3, flowRulesInstalled.size());
+ assertEquals(1, groupsInstalled.size());
+ assertEquals(2, groupsInstalled.get(0).buckets().buckets().size());
+
+ //create the expected flow rule
+ PiCriterion nextIdCriterion = PiCriterion.builder()
+ .matchExact(FabricConstants.FABRIC_METADATA_NEXT_ID, NEXT_ID_1)
+ .build();
+ TrafficSelector nextIdSelector = DefaultTrafficSelector.builder()
+ .matchPi(nextIdCriterion)
+ .build();
+
+ PiActionParam groupIdParam = new PiActionParam(FabricConstants.GID,
+ ImmutableByteSequence.copyFrom(NEXT_ID_1));
+ PiAction setMcGroupAction = PiAction.builder()
+ .withId(FabricConstants.FABRIC_INGRESS_NEXT_SET_MCAST_GROUP)
+ .withParameter(groupIdParam)
+ .build();
+ TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+ .piTableAction(setMcGroupAction)
+ .build();
+ FlowRule expectedFlowRule = DefaultFlowRule.builder()
+ .forDevice(DEVICE_ID)
+ .fromApp(APP_ID)
+ .makePermanent()
+ .withPriority(nextObjective.priority())
+ .forTable(FabricConstants.FABRIC_INGRESS_NEXT_MULTICAST)
+ .withSelector(nextIdSelector)
+ .withTreatment(treatment)
+ .build();
+
+ // VLAN meta table
+ FlowRule vmFlowRule = flowRulesInstalled.get(0);
+ assertTrue(vmFlowRule.exactMatch(vlanMetaFlowRule));
+
+ FlowRule actualFlowRule = flowRulesInstalled.get(1);
+ assertTrue(expectedFlowRule.exactMatch(actualFlowRule));
+
+ //prepare expected egress rule for the egress vlan pipeline
+ PiCriterion egressVlanTableMatch = PiCriterion.builder()
+ .matchExact(FabricConstants.STANDARD_METADATA_EGRESS_PORT,
+ (short) PORT_2.toLong())
+ .build();
+ TrafficSelector selectorForEgressVlan = DefaultTrafficSelector.builder()
+ .matchPi(egressVlanTableMatch)
+ .matchVlanId(VLAN_100)
+ .build();
+ TrafficTreatment treatmentForEgressVlan = DefaultTrafficTreatment.builder()
+ .popVlan()
+ .build();
+ FlowRule expectedEgressVlanRule = DefaultFlowRule.builder()
+ .withSelector(selectorForEgressVlan)
+ .withTreatment(treatmentForEgressVlan)
+ .forTable(FabricConstants.FABRIC_EGRESS_EGRESS_NEXT_EGRESS_VLAN)
+ .makePermanent()
+ .withPriority(nextObjective.priority())
+ .forDevice(DEVICE_ID)
+ .fromApp(APP_ID)
+ .build();
+ //egress vlan table
+ FlowRule actualEgressVlanFlowRule = flowRulesInstalled.get(2);
+ assertTrue(expectedEgressVlanRule.exactMatch(actualEgressVlanFlowRule));
+
+ //create the expected group
+ GroupDescription actualGroup = groupsInstalled.get(0);
+ List<TrafficTreatment> treatments = ImmutableList.of(treatment1, treatment2);
+
+ List<GroupBucket> buckets = treatments.stream()
+ .map(DefaultGroupBucket::createAllGroupBucket)
+ .collect(Collectors.toList());
+
+ GroupBuckets groupBuckets = new GroupBuckets(buckets);
+
+ GroupKey groupKey = new DefaultGroupKey(FabricPipeliner.KRYO.serialize(NEXT_ID_1));
+
+ GroupDescription expectedGroup = new DefaultGroupDescription(
+ DEVICE_ID,
+ GroupDescription.Type.ALL,
+ groupBuckets,
+ groupKey,
+ NEXT_ID_1,
+ APP_ID
+ );
+ assertEquals(expectedGroup, actualGroup);
}
}