Fix: resolve ARP resolution issue in ARP broadcast mode for VLAN
Change-Id: I2ce61b07aec9639e98c5a182244200df3b978cfc
diff --git a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingArpHandler.java b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingArpHandler.java
index 06265bd..9afae59 100644
--- a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingArpHandler.java
+++ b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingArpHandler.java
@@ -15,7 +15,6 @@
*/
package org.onosproject.openstacknetworking.impl;
-import com.google.common.base.Strings;
import org.onlab.packet.ARP;
import org.onlab.packet.EthType;
import org.onlab.packet.Ethernet;
@@ -290,27 +289,15 @@
* by adding a fake gateway MAC address as Source Hardware Address.
*
* @param osSubnet openstack subnet
+ * @param network openstack network
* @param install flag which indicates whether to install rule or remove rule
+ * @param osNode openstack node
*/
- private void setFakeGatewayArpRule(Subnet osSubnet, boolean install, OpenstackNode osNode) {
+ private void setFakeGatewayArpRule(Subnet osSubnet, Network network,
+ boolean install, OpenstackNode osNode) {
if (ARP_BROADCAST_MODE.equals(getArpMode())) {
- // do not remove fake gateway ARP rules, if there is another gateway
- // which has the same subnet that to be removed
- // this only occurs if we have duplicated subnets associated with
- // different networks
- if (!install) {
- long numOfDupGws = osNetworkService.subnets().stream()
- .filter(s -> !s.getId().equals(osSubnet.getId()))
- .filter(s -> s.getGateway() != null)
- .filter(s -> s.getGateway().equals(osSubnet.getGateway()))
- .count();
- if (numOfDupGws > 0) {
- return;
- }
- }
-
String gateway = osSubnet.getGateway();
if (gateway == null) {
return;
@@ -319,11 +306,24 @@
TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
- NetworkType type = NetworkType.valueOf(osNetworkService.networkType(osSubnet.getNetworkId()));
-
- if (type.equals(NetworkType.VLAN)) {
- sBuilder.matchVlanId(VlanId.vlanId(osNetworkService.segmentId(osSubnet.getNetworkId())));
+ if (NetworkType.VLAN == network.getNetworkType()) {
+ sBuilder.matchVlanId(VlanId.vlanId(network.getProviderSegID()));
tBuilder.popVlan();
+ } else if (NetworkType.VXLAN == network.getNetworkType()) {
+ // do not remove fake gateway ARP rules, if there is another gateway
+ // which has the same subnet that to be removed
+ // this only occurs if we have duplicated subnets associated with
+ // different networks
+ if (!install) {
+ long numOfDupGws = osNetworkService.subnets().stream()
+ .filter(s -> !s.getId().equals(osSubnet.getId()))
+ .filter(s -> s.getGateway() != null)
+ .filter(s -> s.getGateway().equals(osSubnet.getGateway()))
+ .count();
+ if (numOfDupGws > 0) {
+ return;
+ }
+ }
}
sBuilder.matchEthType(EthType.EtherType.ARP.ethType().toShort())
@@ -376,8 +376,7 @@
setRemoteArpRequestRuleForVxlan(port, install);
break;
case VLAN:
- // since VLAN ARP packet can be broadcasted to all hosts that connected with L2 network,
- // there is no need to add any flow rules to handle ARP request
+ setArpRequestRuleForVlan(port, install);
break;
default:
break;
@@ -428,6 +427,36 @@
}
/**
+ * Installs flow rules to match ARP request packets for VLAN.
+ *
+ * @param port instance port
+ * @param install installation flag
+ */
+ private void setArpRequestRuleForVlan(InstancePort port, boolean install) {
+ TrafficSelector selector = getArpRequestSelectorForVlan(port);
+
+ setLocalArpRequestTreatmentForVlan(selector, port, install);
+ setRemoteArpRequestTreatmentForVlan(selector, port, install);
+ }
+
+ /**
+ * Obtains the ARP request selector for VLAN.
+ *
+ * @param port instance port
+ * @return traffic selector
+ */
+ private TrafficSelector getArpRequestSelectorForVlan(InstancePort port) {
+ String segId = osNetworkService.segmentId(port.networkId());
+
+ return DefaultTrafficSelector.builder()
+ .matchEthType(EthType.EtherType.ARP.ethType().toShort())
+ .matchArpOp(ARP.OP_REQUEST)
+ .matchArpTpa(port.ipAddress().getIp4Address())
+ .matchVlanId(VlanId.vlanId(segId))
+ .build();
+ }
+
+ /**
* Installs flow rules to match ARP reply packets only for VxLAN.
*
* @param port instance port
@@ -437,7 +466,9 @@
OpenstackNode localNode = osNodeService.node(port.deviceId());
- TrafficSelector selector = setArpReplyRuleForVnet(port, install);
+ TrafficSelector selector = getArpReplySelectorForVxlan(port);
+
+ setLocalArpReplyTreatmentForVxlan(selector, port, install);
setRemoteArpTreatmentForVxlan(selector, port, localNode, install);
}
@@ -449,20 +480,85 @@
*/
private void setArpReplyRuleForVlan(InstancePort port, boolean install) {
- TrafficSelector selector = setArpReplyRuleForVnet(port, install);
- setRemoteArpTreatmentForVlan(selector, port, install);
+ TrafficSelector selector = getArpReplySelectorForVlan(port);
+
+ setLocalArpReplyTreatmentForVlan(selector, port, install);
+ setRemoteArpReplyTreatmentForVlan(selector, port, install);
}
// a helper method
- private TrafficSelector setArpReplyRuleForVnet(InstancePort port, boolean install) {
- TrafficSelector selector = DefaultTrafficSelector.builder()
+ private TrafficSelector getArpReplySelectorForVxlan(InstancePort port) {
+ return getArpReplySelectorForVnet(port, NetworkType.VXLAN);
+ }
+
+ // a helper method
+ private TrafficSelector getArpReplySelectorForVlan(InstancePort port) {
+ return getArpReplySelectorForVnet(port, NetworkType.VLAN);
+ }
+
+ // a helper method
+ private TrafficSelector getArpReplySelectorForVnet(InstancePort port,
+ NetworkType type) {
+
+ TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
+
+ if (type == NetworkType.VLAN) {
+ String segId = osNetworkService.network(port.networkId()).getProviderSegID();
+ sBuilder.matchVlanId(VlanId.vlanId(segId));
+ }
+
+ return sBuilder
.matchEthType(EthType.EtherType.ARP.ethType().toShort())
.matchArpOp(ARP.OP_REPLY)
.matchArpTpa(port.ipAddress().getIp4Address())
.matchArpTha(port.macAddress())
.build();
+ }
+ // a helper method
+ private void setLocalArpReplyTreatmentForVxlan(TrafficSelector selector,
+ InstancePort port,
+ boolean install) {
+ setLocalArpReplyTreatmentForVnet(selector, port, NetworkType.VXLAN, install);
+ }
+
+ // a helper method
+ private void setLocalArpReplyTreatmentForVlan(TrafficSelector selector,
+ InstancePort port,
+ boolean install) {
+ setLocalArpReplyTreatmentForVnet(selector, port, NetworkType.VLAN, install);
+ }
+
+ // a helper method
+ private void setLocalArpReplyTreatmentForVnet(TrafficSelector selector,
+ InstancePort port,
+ NetworkType type,
+ boolean install) {
+ TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
+
+ if (type == NetworkType.VLAN) {
+ tBuilder.popVlan();
+ }
+
+ tBuilder.setOutput(port.portNumber());
+
+ osFlowRuleService.setRule(
+ appId,
+ port.deviceId(),
+ selector,
+ tBuilder.build(),
+ PRIORITY_ARP_REPLY_RULE,
+ ARP_TABLE,
+ install
+ );
+ }
+
+ // a helper method
+ private void setLocalArpRequestTreatmentForVlan(TrafficSelector selector,
+ InstancePort port,
+ boolean install) {
TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+ .popVlan()
.setOutput(port.portNumber())
.build();
@@ -471,12 +567,10 @@
port.deviceId(),
selector,
treatment,
- PRIORITY_ARP_REPLY_RULE,
+ PRIORITY_ARP_REQUEST_RULE,
ARP_TABLE,
install
);
-
- return selector;
}
// a helper method
@@ -509,9 +603,36 @@
}
// a helper method
+ private void setRemoteArpRequestTreatmentForVlan(TrafficSelector selector,
+ InstancePort port,
+ boolean install) {
+ setRemoteArpTreatmentForVlan(selector, port, ARP.OP_REQUEST, install);
+ }
+
+ // a helper method
+ private void setRemoteArpReplyTreatmentForVlan(TrafficSelector selector,
+ InstancePort port,
+ boolean install) {
+ setRemoteArpTreatmentForVlan(selector, port, ARP.OP_REPLY, install);
+ }
+
+ // a helper method
private void setRemoteArpTreatmentForVlan(TrafficSelector selector,
InstancePort port,
+ short arpOp,
boolean install) {
+
+ int priority;
+ if (arpOp == ARP.OP_REQUEST) {
+ priority = PRIORITY_ARP_REQUEST_RULE;
+ } else if (arpOp == ARP.OP_REPLY) {
+ priority = PRIORITY_ARP_REPLY_RULE;
+ } else {
+ // if ARP op does not match with any operation mode, we simply
+ // configure the ARP request rule priority
+ priority = PRIORITY_ARP_REQUEST_RULE;
+ }
+
for (OpenstackNode remoteNode : osNodeService.completeNodes(COMPUTE)) {
if (!remoteNode.intgBridge().equals(port.deviceId()) && remoteNode.vlanIntf() != null) {
TrafficTreatment treatmentToRemote = DefaultTrafficTreatment.builder()
@@ -523,7 +644,7 @@
remoteNode.intgBridge(),
selector,
treatmentToRemote,
- PRIORITY_ARP_REQUEST_RULE,
+ priority,
ARP_TABLE,
install);
}
@@ -573,28 +694,18 @@
@Override
public boolean isRelevant(OpenstackNetworkEvent event) {
- return event.subnet() != null;
- }
-
- private boolean isRelevantHelper(Subnet osSubnet) {
- Network network = osNetworkService.network(osSubnet.getNetworkId());
+ Network network = event.subject();
if (network == null) {
log.warn("Network is not specified.");
return false;
} else {
- if (network.getNetworkType().equals(NetworkType.FLAT)) {
- return false;
- }
+ return network.getNetworkType() != NetworkType.FLAT;
}
+ }
- // do not allow to proceed without leadership
- NodeId leader = leadershipService.getLeader(appId.name());
- if (!Objects.equals(localNodeId, leader)) {
- return false;
- }
-
- return !Strings.isNullOrEmpty(osSubnet.getGateway());
+ private boolean isRelevantHelper() {
+ return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
}
@Override
@@ -604,21 +715,23 @@
case OPENSTACK_SUBNET_UPDATED:
eventExecutor.execute(() -> {
- if (!isRelevantHelper(event.subnet())) {
+ if (!isRelevantHelper()) {
return;
}
- setFakeGatewayArpRule(event.subnet(), true, null);
+ setFakeGatewayArpRule(event.subnet(), event.subject(),
+ true, null);
});
break;
case OPENSTACK_SUBNET_REMOVED:
eventExecutor.execute(() -> {
- if (!isRelevantHelper(event.subnet())) {
+ if (!isRelevantHelper()) {
return;
}
- setFakeGatewayArpRule(event.subnet(), false, null);
+ setFakeGatewayArpRule(event.subnet(), event.subject(),
+ false, null);
});
break;
case OPENSTACK_NETWORK_CREATED:
@@ -692,11 +805,14 @@
// ARP packets generated by FLAT typed VM should not be
// delegated to switch to handle
osNetworkService.subnets().stream().filter(subnet ->
- osNetworkService.network(subnet.getNetworkId()) != null &&
- osNetworkService.network(subnet.getNetworkId())
- .getNetworkType() != NetworkType.FLAT)
- .forEach(subnet ->
- setFakeGatewayArpRule(subnet, install, osNode));
+ osNetworkService.network(subnet.getNetworkId()) != null &&
+ osNetworkService.network(subnet.getNetworkId())
+ .getNetworkType() != NetworkType.FLAT)
+ .forEach(subnet -> {
+ String netId = subnet.getNetworkId();
+ Network net = osNetworkService.network(netId);
+ setFakeGatewayArpRule(subnet, net, install, osNode);
+ });
break;
default:
log.warn("Invalid ARP mode {}. Please use either " +