CORD-248 Provide host management network connectivity to a VM
Change-Id: I6f632e118bd11f4f469aae0476d2d35fc2b7c3eb
diff --git a/src/main/java/org/opencord/cordvtn/impl/CordVtnArpProxy.java b/src/main/java/org/opencord/cordvtn/impl/CordVtnArpProxy.java
index 9e8d313..1697f1a 100644
--- a/src/main/java/org/opencord/cordvtn/impl/CordVtnArpProxy.java
+++ b/src/main/java/org/opencord/cordvtn/impl/CordVtnArpProxy.java
@@ -28,6 +28,8 @@
import org.onlab.packet.Ip4Address;
import org.onlab.packet.IpAddress;
import org.onlab.packet.MacAddress;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.PortNumber;
import org.onosproject.net.packet.PacketProcessor;
import org.onosproject.xosclient.api.VtnService;
import org.opencord.cordvtn.api.CordVtnConfig;
@@ -50,6 +52,7 @@
import static com.google.common.base.Preconditions.checkNotNull;
import static org.onosproject.xosclient.api.VtnServiceApi.NetworkType.PRIVATE;
+import static org.onosproject.xosclient.api.VtnServiceApi.ServiceType.MANAGEMENT;
import static org.slf4j.LoggerFactory.getLogger;
/**
@@ -62,6 +65,9 @@
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected PacketService packetService;
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected CordVtnNodeManager nodeManager;
+
private final PacketProcessor packetProcessor = new InternalPacketProcessor();
private final Map<Ip4Address, MacAddress> gateways = Maps.newConcurrentMap();
@@ -132,31 +138,26 @@
/**
* Emits ARP reply with fake MAC address for a given ARP request.
- * It only handles requests for the registered service IPs, and the other
- * requests can be handled by other ARP handlers like openstackSwitching or
- * proxyArp, for example.
+ * It only handles requests for the registered gateway IPs and host IPs.
*
* @param context packet context
* @param ethPacket ethernet packet
*/
- private void processArpPacket(PacketContext context, Ethernet ethPacket) {
+ private void processArpRequest(PacketContext context, Ethernet ethPacket) {
ARP arpPacket = (ARP) ethPacket.getPayload();
- if (arpPacket.getOpCode() != ARP.OP_REQUEST) {
- return;
- }
-
Ip4Address targetIp = Ip4Address.valueOf(arpPacket.getTargetProtocolAddress());
MacAddress gatewayMac = gateways.get(targetIp);
- MacAddress replyMac = gatewayMac != null ? gatewayMac : getMacFromHostService(targetIp);
+ MacAddress replyMac = gatewayMac != null ? gatewayMac :
+ getMacFromHostService(targetIp);
if (replyMac.equals(MacAddress.NONE)) {
- log.debug("Failed to find MAC for {}", targetIp.toString());
- context.block();
+ log.trace("Failed to find MAC for {}", targetIp);
+ forwardManagementArpRequest(context, ethPacket);
return;
}
- log.trace("Send ARP reply for {} with {}", targetIp.toString(), replyMac.toString());
+ log.trace("Send ARP reply for {} with {}", targetIp, replyMac);
Ethernet ethReply = ARP.buildArpReply(
targetIp,
replyMac,
@@ -174,6 +175,62 @@
context.block();
}
+ private void processArpReply(PacketContext context, Ethernet ethPacket) {
+ ARP arpPacket = (ARP) ethPacket.getPayload();
+ Ip4Address targetIp = Ip4Address.valueOf(arpPacket.getTargetProtocolAddress());
+
+ DeviceId deviceId = context.inPacket().receivedFrom().deviceId();
+ Host host = hostService.getHostsByIp(targetIp).stream()
+ .filter(h -> h.location().deviceId().equals(deviceId))
+ .findFirst()
+ .orElse(null);
+
+ if (host == null) {
+ // do nothing for the unknown ARP reply
+ log.trace("No host found for {} in {}", targetIp, deviceId);
+ context.block();
+ return;
+ }
+
+ TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+ .setOutput(host.location().port())
+ .build();
+
+ packetService.emit(new DefaultOutboundPacket(
+ deviceId,
+ treatment,
+ ByteBuffer.wrap(ethPacket.serialize())));
+
+ context.block();
+ }
+
+ private void forwardManagementArpRequest(PacketContext context, Ethernet ethPacket) {
+ DeviceId deviceId = context.inPacket().receivedFrom().deviceId();
+ PortNumber hostMgmtPort = nodeManager.hostManagementPort(deviceId);
+ Host host = hostService.getConnectedHosts(context.inPacket().receivedFrom())
+ .stream()
+ .findFirst().orElse(null);
+
+ if (host == null ||
+ !Instance.of(host).serviceType().equals(MANAGEMENT) ||
+ hostMgmtPort == null) {
+ context.block();
+ return;
+ }
+
+ TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+ .setOutput(hostMgmtPort)
+ .build();
+
+ packetService.emit(new DefaultOutboundPacket(
+ context.inPacket().receivedFrom().deviceId(),
+ treatment,
+ ByteBuffer.wrap(ethPacket.serialize())));
+
+ log.trace("Forward ARP request to management network");
+ context.block();
+ }
+
/**
* Emits gratuitous ARP when a gateway mac address has been changed.
*
@@ -183,7 +240,7 @@
private void sendGratuitousArp(IpAddress gatewayIp, Set<Instance> instances) {
MacAddress gatewayMac = gateways.get(gatewayIp.getIp4Address());
if (gatewayMac == null) {
- log.debug("Gateway {} is not registered to ARP proxy", gatewayIp.toString());
+ log.debug("Gateway {} is not registered to ARP proxy", gatewayIp);
return;
}
@@ -246,7 +303,7 @@
.orElse(null);
if (host != null) {
- log.trace("Found MAC from host service for {}", targetIp.toString());
+ log.trace("Found MAC from host service for {}", targetIp);
return host.mac();
} else {
return MacAddress.NONE;
@@ -264,7 +321,18 @@
if (ethPacket == null || ethPacket.getEtherType() != Ethernet.TYPE_ARP) {
return;
}
- processArpPacket(context, ethPacket);
+
+ ARP arpPacket = (ARP) ethPacket.getPayload();
+ switch (arpPacket.getOpCode()) {
+ case ARP.OP_REQUEST:
+ processArpRequest(context, ethPacket);
+ break;
+ case ARP.OP_REPLY:
+ processArpReply(context, ethPacket);
+ break;
+ default:
+ break;
+ }
}
}