Improved openstackSwitching ARP handler
Save REST calls by checking if the target IP is owned by a known host first.
Change-Id: Id1ac0e5e13d635b5216d50c7cafaed1179a7410e
diff --git a/apps/openstackswitching/app/src/main/java/org/onosproject/openstackswitching/OpenstackArpHandler.java b/apps/openstackswitching/app/src/main/java/org/onosproject/openstackswitching/OpenstackArpHandler.java
index 944d12a..b0a4c43 100644
--- a/apps/openstackswitching/app/src/main/java/org/onosproject/openstackswitching/OpenstackArpHandler.java
+++ b/apps/openstackswitching/app/src/main/java/org/onosproject/openstackswitching/OpenstackArpHandler.java
@@ -18,12 +18,14 @@
import org.onlab.packet.ARP;
import org.onlab.packet.Ethernet;
import org.onlab.packet.Ip4Address;
+import org.onlab.packet.IpAddress;
import org.onlab.packet.MacAddress;
+import org.onosproject.net.Host;
import org.onosproject.net.flow.DefaultTrafficTreatment;
import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.host.HostService;
import org.onosproject.net.packet.DefaultOutboundPacket;
import org.onosproject.net.packet.InboundPacket;
-import org.onosproject.net.packet.OutboundPacket;
import org.onosproject.net.packet.PacketService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -40,69 +42,106 @@
.getLogger(OpenstackArpHandler.class);
private PacketService packetService;
private OpenstackRestHandler restHandler;
+ private HostService hostService;
/**
* Returns OpenstackArpHandler reference.
*
* @param restHandler rest API handler reference
* @param packetService PacketService reference
+ * @param hostService host service
*/
- public OpenstackArpHandler(OpenstackRestHandler restHandler, PacketService packetService) {
+ public OpenstackArpHandler(OpenstackRestHandler restHandler, PacketService packetService,
+ HostService hostService) {
this.restHandler = checkNotNull(restHandler);
this.packetService = packetService;
+ this.hostService = hostService;
}
/**
- * Processes ARP packets.
+ * Processes ARP request packets.
+ * It checks if the target IP is owned by a known host first and then ask to
+ * OpenStack if it's not. This ARP proxy does not support overlapping IP.
*
* @param pkt ARP request packet
*/
public void processPacketIn(InboundPacket pkt) {
- Ethernet ethernet = pkt.parsed();
- ARP arp = (ARP) ethernet.getPayload();
+ Ethernet ethRequest = pkt.parsed();
+ ARP arp = (ARP) ethRequest.getPayload();
- if (arp.getOpCode() == ARP.OP_REQUEST) {
- byte[] srcMacAddress = arp.getSenderHardwareAddress();
- byte[] srcIPAddress = arp.getSenderProtocolAddress();
- byte[] dstIPAddress = arp.getTargetProtocolAddress();
+ if (arp.getOpCode() != ARP.OP_REQUEST) {
+ return;
+ }
- //Searches the Dst MAC Address based on openstackPortMap
- MacAddress macAddress = null;
+ IpAddress targetIp = Ip4Address.valueOf(arp.getTargetProtocolAddress());
+ MacAddress dstMac = getMacFromHostService(targetIp);
+ if (dstMac == null) {
+ dstMac = getMacFromOpenstack(targetIp);
+ }
- OpenstackPort openstackPort = restHandler.getPorts().stream().
- filter(e -> e.fixedIps().containsValue(Ip4Address.valueOf(
- dstIPAddress))).findAny().orElse(null);
+ if (dstMac == null) {
+ log.debug("Failed to find MAC address for {}", targetIp.toString());
+ return;
+ }
- if (openstackPort != null) {
- macAddress = openstackPort.macAddress();
- log.debug("Found MACAddress: {}", macAddress.toString());
- } else {
- return;
- }
+ Ethernet ethReply = ARP.buildArpReply(targetIp.getIp4Address(),
+ dstMac,
+ ethRequest);
- //Creates a response packet
- ARP arpReply = new ARP();
- arpReply.setOpCode(ARP.OP_REPLY)
- .setHardwareAddressLength(arp.getHardwareAddressLength())
- .setHardwareType(arp.getHardwareType())
- .setProtocolAddressLength(arp.getProtocolAddressLength())
- .setProtocolType(arp.getProtocolType())
- .setSenderHardwareAddress(macAddress.toBytes())
- .setSenderProtocolAddress(dstIPAddress)
- .setTargetHardwareAddress(srcMacAddress)
- .setTargetProtocolAddress(srcIPAddress);
+ TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+ .setOutput(pkt.receivedFrom().port())
+ .build();
- //Sends a response packet
- ethernet.setDestinationMACAddress(srcMacAddress)
- .setSourceMACAddress(macAddress)
- .setEtherType(Ethernet.TYPE_ARP)
- .setPayload(arpReply);
+ packetService.emit(new DefaultOutboundPacket(
+ pkt.receivedFrom().deviceId(),
+ treatment,
+ ByteBuffer.wrap(ethReply.serialize())));
+ }
- TrafficTreatment.Builder builder = DefaultTrafficTreatment.builder();
- builder.setOutput(pkt.receivedFrom().port());
- OutboundPacket packet = new DefaultOutboundPacket(pkt.receivedFrom().deviceId(),
- builder.build(), ByteBuffer.wrap(ethernet.serialize()));
- packetService.emit(packet);
+ /**
+ * Returns MAC address of a host with a given target IP address by asking to
+ * OpenStack. It does not support overlapping IP.
+ *
+ * @param targetIp target ip address
+ * @return mac address, or null if it fails to fetch the mac
+ */
+ private MacAddress getMacFromOpenstack(IpAddress targetIp) {
+ checkNotNull(targetIp);
+
+ OpenstackPort openstackPort = restHandler.getPorts()
+ .stream()
+ .filter(port -> port.fixedIps().containsValue(targetIp))
+ .findFirst()
+ .orElse(null);
+
+ if (openstackPort != null) {
+ log.debug("Found MAC from OpenStack for {}", targetIp.toString());
+ return openstackPort.macAddress();
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Returns MAC address of a host with a given target IP address by asking to
+ * host service. It does not support overlapping IP.
+ *
+ * @param targetIp target ip
+ * @return mac address, or null if it fails to find the mac
+ */
+ private MacAddress getMacFromHostService(IpAddress targetIp) {
+ checkNotNull(targetIp);
+
+ Host host = hostService.getHostsByIp(targetIp)
+ .stream()
+ .findFirst()
+ .orElse(null);
+
+ if (host != null) {
+ log.debug("Found MAC from host service for {}", targetIp.toString());
+ return host.mac();
+ } else {
+ return null;
}
}
}
diff --git a/apps/openstackswitching/app/src/main/java/org/onosproject/openstackswitching/OpenstackSwitchingManager.java b/apps/openstackswitching/app/src/main/java/org/onosproject/openstackswitching/OpenstackSwitchingManager.java
index d5a8c81..09c5197 100644
--- a/apps/openstackswitching/app/src/main/java/org/onosproject/openstackswitching/OpenstackSwitchingManager.java
+++ b/apps/openstackswitching/app/src/main/java/org/onosproject/openstackswitching/OpenstackSwitchingManager.java
@@ -394,7 +394,7 @@
InboundPacket pkt = context.inPacket();
Ethernet ethernet = pkt.parsed();
- if (ethernet.getEtherType() == Ethernet.TYPE_ARP) {
+ if (ethernet != null && ethernet.getEtherType() == Ethernet.TYPE_ARP) {
arpHandler.processPacketIn(pkt);
}
}
@@ -483,7 +483,7 @@
}
doNotPushFlows = cfg.doNotPushFlows();
restHandler = new OpenstackRestHandler(cfg);
- arpHandler = new OpenstackArpHandler(restHandler, packetService);
+ arpHandler = new OpenstackArpHandler(restHandler, packetService, hostService);
initializeFlowRules();
}