[CORD-2456] Multicast support in t3
Change-Id: I3559495a695aa27cc8c8f6f3a9f465f442200e8a
(cherry picked from commit 6f50a754fd1ba0f2259c95c410de8e43c76f86a8)
diff --git a/src/main/java/org/onosproject/t3/cli/T3CliUtils.java b/src/main/java/org/onosproject/t3/cli/T3CliUtils.java
index e2375a7..30e1ca0 100644
--- a/src/main/java/org/onosproject/t3/cli/T3CliUtils.java
+++ b/src/main/java/org/onosproject/t3/cli/T3CliUtils.java
@@ -111,7 +111,8 @@
//Prints the flows for a given trace and a specified level of verbosity
private static StringBuilder printFlows(StaticPacketTrace trace, boolean verbose, ConnectPoint connectPoint,
StringBuilder tracePrint) {
- tracePrint.append("Flows");
+ tracePrint.append("Flows ");
+ tracePrint.append(trace.getFlowsForDevice(connectPoint.deviceId()).size());
tracePrint.append("\n");
trace.getFlowsForDevice(connectPoint.deviceId()).forEach(f -> {
if (verbose) {
diff --git a/src/main/java/org/onosproject/t3/impl/TroubleshootManager.java b/src/main/java/org/onosproject/t3/impl/TroubleshootManager.java
index b89732d..2c41382 100644
--- a/src/main/java/org/onosproject/t3/impl/TroubleshootManager.java
+++ b/src/main/java/org/onosproject/t3/impl/TroubleshootManager.java
@@ -39,6 +39,7 @@
import org.onosproject.net.config.basics.InterfaceConfig;
import org.onosproject.net.device.DeviceService;
import org.onosproject.net.driver.DriverService;
+import org.onosproject.net.edge.EdgePortService;
import org.onosproject.net.flow.DefaultTrafficSelector;
import org.onosproject.net.flow.FlowEntry;
import org.onosproject.net.flow.FlowRule;
@@ -86,6 +87,7 @@
import static org.onosproject.net.flow.instructions.L2ModificationInstruction.ModMplsHeaderInstruction;
import static org.onosproject.net.flow.instructions.L2ModificationInstruction.ModMplsLabelInstruction;
import static org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanIdInstruction;
+import static org.onosproject.t3.impl.TroubleshootUtils.compareMac;
import static org.slf4j.LoggerFactory.getLogger;
/**
@@ -125,6 +127,9 @@
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected NetworkConfigService networkConfigService;
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected EdgePortService edgePortService;
+
@Override
public StaticPacketTrace trace(HostId sourceHost, HostId destinationHost, EtherType etherType) {
Host source = hostService.getHost(sourceHost);
@@ -394,7 +399,17 @@
//continue the trace along the path
getTrace(completePath, dst, trace);
}
-
+ } else if (edgePortService.isEdgePoint(outputPath.getOutput()) &&
+ trace.getInitialPacket().getCriterion(Criterion.Type.ETH_DST) != null &&
+ ((EthCriterion) trace.getInitialPacket().getCriterion(Criterion.Type.ETH_DST))
+ .mac().isMulticast()) {
+ trace.addResultMessage("Packet is multicast and reached output " + outputPath.getOutput() +
+ " which is enabled and is edge port");
+ computePath(completePath, trace, outputPath.getOutput());
+ completePath.clear();
+ if (!hasOtherOutput(in.deviceId(), trace, outputPath.getOutput())) {
+ return trace;
+ }
} else if (deviceService.getPort(cp).isEnabled()) {
EthTypeCriterion ethTypeCriterion = (EthTypeCriterion) trace.getInitialPacket()
.getCriterion(Criterion.Type.ETH_TYPE);
@@ -423,6 +438,7 @@
return trace;
}
+
/**
* If the initial packet comes tagged with a Vlan we output it with that to ONOS.
* If ONOS applied a vlan we remove it.
@@ -430,6 +446,7 @@
* @param outputPath the output
* @param trace the trace we are building
*/
+
private void handleVlanToController(GroupsInDevice outputPath, StaticPacketTrace trace) {
VlanIdCriterion initialVid = (VlanIdCriterion) trace.getInitialPacket().getCriterion(Criterion.Type.VLAN_VID);
@@ -450,6 +467,20 @@
}
/**
+ * Checks if the device has other outputs than the given connect point.
+ *
+ * @param inDeviceId the device
+ * @param trace the trace we are building
+ * @param cp an output connect point
+ * @return true if the device has other outputs.
+ */
+ private boolean hasOtherOutput(DeviceId inDeviceId, StaticPacketTrace trace, ConnectPoint cp) {
+ return trace.getGroupOuputs(inDeviceId).stream().filter(groupsInDevice -> {
+ return !groupsInDevice.getOutput().equals(cp);
+ }).count() > 0;
+ }
+
+ /**
* Checks if the path contains the device.
*
* @param completePath the path
@@ -1075,28 +1106,72 @@
* @return true if the packet matches the flow.
*/
private boolean match(TrafficSelector packet, FlowEntry flowEntry) {
- //TODO handle MAC matching
return flowEntry.selector().criteria().stream().allMatch(criterion -> {
Criterion.Type type = criterion.type();
//If the criterion has IP we need to do LPM to establish matching.
if (type.equals(Criterion.Type.IPV4_SRC) || type.equals(Criterion.Type.IPV4_DST) ||
type.equals(Criterion.Type.IPV6_SRC) || type.equals(Criterion.Type.IPV6_DST)) {
- IPCriterion ipCriterion = (IPCriterion) criterion;
- IPCriterion matchCriterion = (IPCriterion) packet.getCriterion(ipCriterion.type());
- //if the packet does not have an IPv4 or IPv6 criterion we return false
- if (matchCriterion == null) {
- return false;
- }
- try {
- Subnet subnet = Subnet.createInstance(ipCriterion.ip().toString());
- return subnet.isInSubnet(matchCriterion.ip().address().toInetAddress());
- } catch (UnknownHostException e) {
- return false;
- }
+ return matchIp(packet, (IPCriterion) criterion);
//we check that the packet contains the criterion provided by the flow rule.
+ } else if (type.equals(Criterion.Type.ETH_SRC_MASKED)) {
+ return matchMac(packet, (EthCriterion) criterion, false);
+ } else if (type.equals(Criterion.Type.ETH_DST_MASKED)) {
+ return matchMac(packet, (EthCriterion) criterion, true);
} else {
return packet.criteria().contains(criterion);
}
});
}
+
+ /**
+ * Checks if the packet has an dst or src IP and if that IP matches the subnet of the ip criterion.
+ *
+ * @param packet the incoming packet
+ * @param criterion the criterion to match
+ * @return true if match
+ */
+ private boolean matchIp(TrafficSelector packet, IPCriterion criterion) {
+ IPCriterion matchCriterion = (IPCriterion) packet.getCriterion(criterion.type());
+ //if the packet does not have an IPv4 or IPv6 criterion we return true
+ if (matchCriterion == null) {
+ return false;
+ }
+ try {
+ log.debug("Checking if {} is under {}", matchCriterion.ip(), criterion.ip());
+ Subnet subnet = Subnet.createInstance(criterion.ip().toString());
+ return subnet.isInSubnet(matchCriterion.ip().address().toInetAddress());
+ } catch (UnknownHostException e) {
+ return false;
+ }
+ }
+
+ /**
+ * Checks if the packet has a dst or src MAC and if that Mac matches the mask of the mac criterion.
+ *
+ * @param packet the incoming packet
+ * @param hitCriterion the criterion to match
+ * @param dst true if we are checking DST MAC
+ * @return true if match
+ */
+ private boolean matchMac(TrafficSelector packet, EthCriterion hitCriterion, boolean dst) {
+ //Packet can have only one EthCriterion
+ EthCriterion matchCriterion;
+ if (dst) {
+ matchCriterion = (EthCriterion) packet.criteria().stream().filter(criterion1 -> {
+ return criterion1.type().equals(Criterion.Type.ETH_DST_MASKED) ||
+ criterion1.type().equals(Criterion.Type.ETH_DST);
+ }).findFirst().orElse(null);
+ } else {
+ matchCriterion = (EthCriterion) packet.criteria().stream().filter(criterion1 -> {
+ return criterion1.type().equals(Criterion.Type.ETH_SRC_MASKED) ||
+ criterion1.type().equals(Criterion.Type.ETH_SRC);
+ }).findFirst().orElse(null);
+ }
+ //if the packet does not have an ETH criterion we return true
+ if (matchCriterion == null) {
+ return true;
+ }
+ log.debug("Checking if {} is under {}/{}", matchCriterion.mac(), hitCriterion.mac(), hitCriterion.mask());
+ return compareMac(matchCriterion.mac(), hitCriterion.mac(), hitCriterion.mask());
+ }
}
diff --git a/src/main/java/org/onosproject/t3/impl/TroubleshootUtils.java b/src/main/java/org/onosproject/t3/impl/TroubleshootUtils.java
index f89a413..57758b3 100644
--- a/src/main/java/org/onosproject/t3/impl/TroubleshootUtils.java
+++ b/src/main/java/org/onosproject/t3/impl/TroubleshootUtils.java
@@ -17,6 +17,7 @@
package org.onosproject.t3.impl;
import com.google.common.collect.ImmutableMap;
+import org.onlab.packet.MacAddress;
import java.util.Map;
@@ -43,4 +44,36 @@
.put("accton-ofdpa3", true)
.put("znyx-ofdpa", true)
.build();
+
+ /**
+ * Checks if the Mac Address is inside a range between the min MAC and the mask.
+ * @param macAddress the MAC address to check
+ * @param minAddr the min MAC address
+ * @param maskAddr the mask
+ * @return true if in range, false otherwise.
+ */
+ static boolean compareMac(MacAddress macAddress, MacAddress minAddr, MacAddress maskAddr) {
+ byte[] mac = macAddress.toBytes();
+ byte[] min = minAddr.toBytes();
+ byte[] mask = maskAddr.toBytes();
+ boolean inRange = true;
+
+ int i = 0;
+
+ //if mask is 00 stop
+ while (inRange && i < mask.length && (mask[i] & 0xFF) != 0) {
+ int ibmac = mac[i] & 0xFF;
+ int ibmin = min[i] & 0xFF;
+ int ibmask = mask[i] & 0xFF;
+ if (ibmask == 255) {
+ inRange = ibmac == ibmin;
+ } else if (ibmac < ibmin || ibmac >= ibmask) {
+ inRange = false;
+ break;
+ }
+ i++;
+ }
+
+ return inRange;
+ }
}