From 24fda8acfd1fbf846656793913333a304975c53f Mon Sep 17 00:00:00 2001 From: Esin Karaman Date: Fri, 26 Jan 2018 11:52:28 +0000 Subject: [PATCH] ONOS-7402 Broadcast objective type support by FabricNextPipeliner. Change-Id: I08b544a82e257091a079648c07b1dc6fb72c9ab9 --- .../fabric/pipeliner/FabricNextPipeliner.java | 66 ++++++++++ .../pipeliner/FabricNextPipelinerTest.java | 113 +++++++++++++++++- 2 files changed, 177 insertions(+), 2 deletions(-) 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 3b66b1bbfb..d8dcc8a116 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.Objective; 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 @@ public class FabricNextPipeliner { 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 @@ public class FabricNextPipeliner { .matchPi(nextIdCriterion) .build(); } + + private void processBroadcastNext(NextObjective next, PipelinerTranslationResult.Builder resultBuilder) { + int groupId = next.id(); + List 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 e2a6af8b16..bfae578be9 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.DefaultNextObjective; 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 @@ public class FabricNextPipelinerTest extends FabricPipelinerTest { * 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 flowRulesInstalled = (List) result.flowRules(); + List groupsInstalled = (List) 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 treatments = ImmutableList.of(treatment1, treatment2); + + List 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); } }