QMX switches require the unicast flow being installed before multicast flow in TMAC table
Change-Id: I2258f7ecceb9a151c4ce65518e9553fe371cf3ac
diff --git a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/mcast/McastHandler.java b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/mcast/McastHandler.java
index 3cab53b..b323c17 100644
--- a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/mcast/McastHandler.java
+++ b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/mcast/McastHandler.java
@@ -733,7 +733,7 @@
}
FilteringObjective.Builder filtObjBuilder =
- filterObjBuilder(deviceId, port, assignedVlan, mcastIp, routerMac);
+ filterObjBuilder(port, assignedVlan, mcastIp, routerMac);
ObjectiveContext context = new DefaultObjectiveContext(
(objective) -> log.debug("Successfully add filter on {}/{}, vlan {}",
deviceId, port.toLong(), assignedVlan),
@@ -996,14 +996,13 @@
/**
* Creates a filtering objective builder for multicast.
*
- * @param deviceId Device ID
* @param ingressPort ingress port of the multicast stream
* @param assignedVlan assigned VLAN ID
* @param routerMac router MAC. This is carried in metadata and used from some switches that
* need to put unicast entry before multicast entry in TMAC table.
* @return filtering objective builder
*/
- private FilteringObjective.Builder filterObjBuilder(DeviceId deviceId, PortNumber ingressPort,
+ private FilteringObjective.Builder filterObjBuilder(PortNumber ingressPort,
VlanId assignedVlan, IpAddress mcastIp, MacAddress routerMac) {
FilteringObjective.Builder filtBuilder = DefaultFilteringObjective.builder();
@@ -1367,7 +1366,7 @@
}
FilteringObjective.Builder filtObjBuilder =
- filterObjBuilder(deviceId, port, assignedVlan, mcastIp, routerMac);
+ filterObjBuilder(port, assignedVlan, mcastIp, routerMac);
ObjectiveContext context = new DefaultObjectiveContext(
(objective) -> log.debug("Successfully removed filter on {}/{}, vlan {}",
deviceId, port.toLong(), assignedVlan),
diff --git a/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/CpqdOfdpa2Pipeline.java b/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/CpqdOfdpa2Pipeline.java
index 8957bff..9c22b37 100644
--- a/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/CpqdOfdpa2Pipeline.java
+++ b/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/CpqdOfdpa2Pipeline.java
@@ -20,6 +20,7 @@
import org.onlab.packet.Ethernet;
import org.onlab.packet.IpAddress;
import org.onlab.packet.IpPrefix;
+import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
import org.onosproject.core.ApplicationId;
import org.onosproject.core.GroupId;
@@ -318,6 +319,7 @@
EthCriterion ethCriterion,
VlanIdCriterion vidCriterion,
VlanId assignedVlan,
+ MacAddress unicastMac,
ApplicationId applicationId) {
// Consider PortNumber.ANY as wildcard. Match ETH_DST only
if (portCriterion != null && portCriterion.port() == PortNumber.ANY) {
@@ -326,7 +328,7 @@
// Multicast MAC
if (ethCriterion.mask() != null) {
- return processMcastEthDstFilter(ethCriterion, assignedVlan, applicationId);
+ return processMcastEthDstFilter(ethCriterion, assignedVlan, unicastMac, applicationId);
}
//handling untagged packets via assigned VLAN
diff --git a/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/CpqdOfdpa2VlanPipeline.java b/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/CpqdOfdpa2VlanPipeline.java
index 36be98d..1c4cdcd 100644
--- a/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/CpqdOfdpa2VlanPipeline.java
+++ b/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/CpqdOfdpa2VlanPipeline.java
@@ -25,6 +25,7 @@
import com.google.common.collect.ImmutableList;
import org.onlab.packet.Ethernet;
+import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
import org.onosproject.core.ApplicationId;
import org.onosproject.net.Port;
@@ -92,6 +93,7 @@
EthCriterion ethCriterion,
VlanIdCriterion vidCriterion,
VlanId assignedVlan,
+ MacAddress unicastMac,
ApplicationId applicationId) {
// Consider PortNumber.ANY as wildcard. Match ETH_DST only
if (portCriterion != null && portCriterion.port() == PortNumber.ANY) {
@@ -100,7 +102,7 @@
// Multicast MAC
if (ethCriterion.mask() != null) {
- return processMcastEthDstFilter(ethCriterion, assignedVlan, applicationId);
+ return processMcastEthDstFilter(ethCriterion, assignedVlan, unicastMac, applicationId);
}
//handling untagged packets via assigned VLAN
diff --git a/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/Ofdpa2Pipeline.java b/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/Ofdpa2Pipeline.java
index 232e5c6..034e3d1 100644
--- a/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/Ofdpa2Pipeline.java
+++ b/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/Ofdpa2Pipeline.java
@@ -22,6 +22,7 @@
import org.onlab.packet.EthType.EtherType;
import org.onlab.packet.IpAddress;
import org.onlab.packet.IpPrefix;
+import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
import org.onlab.util.KryoNamespace;
import org.onosproject.core.ApplicationId;
@@ -65,6 +66,7 @@
import org.onosproject.net.flow.instructions.L2ModificationInstruction;
import org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType;
import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanIdInstruction;
+import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModEtherInstruction;
import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModMplsHeaderInstruction;
import org.onosproject.net.flow.instructions.L3ModificationInstruction;
import org.onosproject.net.flow.instructions.L3ModificationInstruction.L3SubType;
@@ -258,6 +260,16 @@
return true;
}
+ /**
+ * Determines whether this driver requires unicast flow to be installed before multicast flow
+ * in TMAC table.
+ *
+ * @return true if required
+ */
+ protected boolean requireUnicastBeforeMulticast() {
+ return false;
+ }
+
//////////////////////////////////////
// Flow Objectives
//////////////////////////////////////
@@ -473,16 +485,16 @@
// NOTE: it is possible that a filtering objective only has vidCriterion
log.warn("filtering objective missing dstMac, cannot program TMAC table");
} else {
+ MacAddress unicastMac = readEthDstFromTreatment(filt.meta());
List<List<FlowRule>> allStages = processEthDstFilter(portCriterion, ethCriterion,
- vidCriterion, assignedVlan, applicationId);
+ vidCriterion, assignedVlan, unicastMac, applicationId);
for (List<FlowRule> flowRules : allStages) {
- log.trace("Starting a new flow rule stage");
+ log.trace("Starting a new flow rule stage for TMAC table flow");
ops.newStage();
for (FlowRule flowRule : flowRules) {
log.trace("{} flow rules in TMAC table: {} for dev: {}",
(install) ? "adding" : "removing", flowRules, deviceId);
-
if (install) {
ops = ops.add(flowRule);
} else {
@@ -505,7 +517,7 @@
List<List<FlowRule>> allStages = processVlanIdFilter(
portCriterion, vidCriterion, assignedVlan, applicationId);
for (List<FlowRule> flowRules : allStages) {
- log.trace("Starting a new flow rule stage");
+ log.trace("Starting a new flow rule stage for VLAN table flow");
ops.newStage();
for (FlowRule flowRule : flowRules) {
@@ -651,12 +663,15 @@
/**
* Allows routed packets with correct destination MAC to be directed
- * to unicast-IP routing table or MPLS forwarding table.
+ * to unicast routing table, multicast routing table or MPLS forwarding table.
*
* @param portCriterion port on device for which this filter is programmed
* @param ethCriterion dstMac of device for which is filter is programmed
* @param vidCriterion vlan assigned to port, or NONE for untagged
* @param assignedVlan assigned vlan-id for untagged packets
+ * @param unicastMac some switches require a unicast TMAC flow to be programmed before multicast
+ * TMAC flow. This MAC address will be used for the unicast TMAC flow.
+ * This is unused if the filtering objective is a unicast.
* @param applicationId for application programming this filter
* @return stages of flow rules for port-vlan filters
@@ -665,6 +680,7 @@
EthCriterion ethCriterion,
VlanIdCriterion vidCriterion,
VlanId assignedVlan,
+ MacAddress unicastMac,
ApplicationId applicationId) {
// Consider PortNumber.ANY as wildcard. Match ETH_DST only
if (portCriterion != null && PortNumber.ANY.equals(portCriterion.port())) {
@@ -673,7 +689,7 @@
// Multicast MAC
if (ethCriterion.mask() != null) {
- return processMcastEthDstFilter(ethCriterion, assignedVlan, applicationId);
+ return processMcastEthDstFilter(ethCriterion, assignedVlan, unicastMac, applicationId);
}
//handling untagged packets via assigned VLAN
@@ -907,13 +923,35 @@
List<List<FlowRule>> processMcastEthDstFilter(EthCriterion ethCriterion,
VlanId assignedVlan,
+ MacAddress unicastMac,
ApplicationId applicationId) {
- ImmutableList.Builder<FlowRule> builder = ImmutableList.builder();
- TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
- TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
+ ImmutableList.Builder<FlowRule> unicastFlows = ImmutableList.builder();
+ ImmutableList.Builder<FlowRule> multicastFlows = ImmutableList.builder();
+ TrafficSelector.Builder selector;
+ TrafficTreatment.Builder treatment;
FlowRule rule;
if (IPV4_MULTICAST.equals(ethCriterion.mac())) {
+ if (requireUnicastBeforeMulticast()) {
+ selector = DefaultTrafficSelector.builder();
+ treatment = DefaultTrafficTreatment.builder();
+ selector.matchEthType(Ethernet.TYPE_IPV4);
+ selector.matchEthDst(unicastMac);
+ selector.matchVlanId(assignedVlan);
+ treatment.transition(UNICAST_ROUTING_TABLE);
+ rule = DefaultFlowRule.builder()
+ .forDevice(deviceId)
+ .withSelector(selector.build())
+ .withTreatment(treatment.build())
+ .withPriority(DEFAULT_PRIORITY)
+ .fromApp(applicationId)
+ .makePermanent()
+ .forTable(TMAC_TABLE).build();
+ unicastFlows.add(rule);
+ }
+
+ selector = DefaultTrafficSelector.builder();
+ treatment = DefaultTrafficTreatment.builder();
selector.matchEthType(Ethernet.TYPE_IPV4);
selector.matchEthDstMasked(ethCriterion.mac(), ethCriterion.mask());
selector.matchVlanId(assignedVlan);
@@ -926,10 +964,28 @@
.fromApp(applicationId)
.makePermanent()
.forTable(TMAC_TABLE).build();
- builder.add(rule);
+ multicastFlows.add(rule);
}
if (IPV6_MULTICAST.equals(ethCriterion.mac())) {
+ if (requireUnicastBeforeMulticast()) {
+ selector = DefaultTrafficSelector.builder();
+ treatment = DefaultTrafficTreatment.builder();
+ selector.matchEthType(Ethernet.TYPE_IPV6);
+ selector.matchEthDst(unicastMac);
+ selector.matchVlanId(assignedVlan);
+ treatment.transition(UNICAST_ROUTING_TABLE);
+ rule = DefaultFlowRule.builder()
+ .forDevice(deviceId)
+ .withSelector(selector.build())
+ .withTreatment(treatment.build())
+ .withPriority(DEFAULT_PRIORITY)
+ .fromApp(applicationId)
+ .makePermanent()
+ .forTable(TMAC_TABLE).build();
+ unicastFlows.add(rule);
+ }
+
selector = DefaultTrafficSelector.builder();
treatment = DefaultTrafficTreatment.builder();
selector.matchEthType(Ethernet.TYPE_IPV6);
@@ -944,9 +1000,9 @@
.fromApp(applicationId)
.makePermanent()
.forTable(TMAC_TABLE).build();
- builder.add(rule);
+ multicastFlows.add(rule);
}
- return ImmutableList.of(builder.build());
+ return ImmutableList.of(unicastFlows.build(), multicastFlows.build());
}
private Collection<FlowRule> processForward(ForwardingObjective fwd) {
@@ -1684,6 +1740,21 @@
return null;
}
+ private static MacAddress readEthDstFromTreatment(TrafficTreatment treatment) {
+ if (treatment == null) {
+ return null;
+ }
+ for (Instruction i : treatment.allInstructions()) {
+ if (i instanceof ModEtherInstruction) {
+ ModEtherInstruction modEtherInstruction = (ModEtherInstruction) i;
+ if (modEtherInstruction.subtype() == L2SubType.ETH_DST) {
+ return modEtherInstruction.mac();
+ }
+ }
+ }
+ return null;
+ }
+
/**
* Utility class that retries sending flows a fixed number of times, even if
* some of the attempts are successful. Used only for forwarding objectives.
diff --git a/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/Ofdpa3QmxPipeline.java b/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/Ofdpa3QmxPipeline.java
index d989217..418cfbf 100644
--- a/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/Ofdpa3QmxPipeline.java
+++ b/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/Ofdpa3QmxPipeline.java
@@ -41,4 +41,9 @@
protected boolean supportIpv6L4Dst() {
return false;
}
+
+ @Override
+ protected boolean requireUnicastBeforeMulticast() {
+ return true;
+ }
}