ONOS-5182 Refactored SONA to cache network states

Change-Id: Ib316fa5fa5d36e9da370a1578ac55de4a8dd9b04
diff --git a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingArpHandler.java b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingArpHandler.java
index 0bf93dc..03810c3 100644
--- a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingArpHandler.java
+++ b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingArpHandler.java
@@ -32,39 +32,41 @@
 import org.onosproject.net.packet.PacketContext;
 import org.onosproject.net.packet.PacketProcessor;
 import org.onosproject.net.packet.PacketService;
-import org.onosproject.openstackinterface.OpenstackInterfaceService;
-import org.onosproject.openstackinterface.OpenstackPort;
+import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
 import org.onosproject.scalablegateway.api.ScalableGatewayService;
 import org.onosproject.openstacknetworking.api.Constants;
 import org.slf4j.Logger;
 
 import java.nio.ByteBuffer;
+import java.util.Objects;
 import java.util.concurrent.ExecutorService;
 
 import static java.util.concurrent.Executors.newSingleThreadExecutor;
 import static org.onlab.util.Tools.groupedThreads;
-import static org.onosproject.openstacknetworking.api.Constants.DEVICE_OWNER_FLOATING_IP;
-import static org.onosproject.openstacknetworking.api.Constants.DEVICE_OWNER_ROUTER_GATEWAY;
 import static org.slf4j.LoggerFactory.getLogger;
 
 /**
- * Handle ARP, ICMP and NAT packets from gateway nodes.
+ * Handle ARP requests from gateway nodes.
  */
 @Component(immediate = true)
 public class OpenstackRoutingArpHandler {
+
     private final Logger log = getLogger(getClass());
 
+    private static final String DEVICE_OWNER_ROUTER_GW = "network:router_gateway";
+    private static final String DEVICE_OWNER_FLOATING_IP = "network:floatingip";
+
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected PacketService packetService;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected OpenstackInterfaceService openstackService;
-
-    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected ScalableGatewayService gatewayService;
 
-    private final ExecutorService executorService =
-            newSingleThreadExecutor(groupedThreads("onos/openstackrouting", "packet-event", log));
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected OpenstackNetworkService osNetworkService;
+
+    private final ExecutorService eventExecutor = newSingleThreadExecutor(
+            groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
 
     private final InternalPacketProcessor packetProcessor = new InternalPacketProcessor();
 
@@ -77,21 +79,25 @@
     @Deactivate
     protected void deactivate() {
         packetService.removeProcessor(packetProcessor);
+        eventExecutor.shutdown();
         log.info("Stopped");
     }
 
     private void processArpPacket(PacketContext context, Ethernet ethernet) {
         ARP arp = (ARP) ethernet.getPayload();
-        log.trace("arpEvent called from {} to {}",
-                Ip4Address.valueOf(arp.getSenderProtocolAddress()).toString(),
-                Ip4Address.valueOf(arp.getTargetProtocolAddress()).toString());
-
         if (arp.getOpCode() != ARP.OP_REQUEST) {
             return;
         }
 
+        if (log.isTraceEnabled()) {
+            log.trace("ARP request received from {} for {}",
+                    Ip4Address.valueOf(arp.getSenderProtocolAddress()).toString(),
+                    Ip4Address.valueOf(arp.getTargetProtocolAddress()).toString());
+        }
+
         IpAddress targetIp = Ip4Address.valueOf(arp.getTargetProtocolAddress());
-        if (getTargetMacForTargetIp(targetIp.getIp4Address()) == MacAddress.NONE) {
+        if (!isServiceIp(targetIp.getIp4Address())) {
+            log.trace("Unknown target ARP request for {}, ignore it", targetIp);
             return;
         }
 
@@ -107,6 +113,8 @@
                 context.inPacket().receivedFrom().deviceId(),
                 treatment,
                 ByteBuffer.wrap(ethReply.serialize())));
+
+        context.block();
     }
 
     private class InternalPacketProcessor implements PacketProcessor {
@@ -125,19 +133,20 @@
             Ethernet ethernet = pkt.parsed();
             if (ethernet != null &&
                     ethernet.getEtherType() == Ethernet.TYPE_ARP) {
-                executorService.execute(() -> processArpPacket(context, ethernet));
+                eventExecutor.execute(() -> processArpPacket(context, ethernet));
             }
         }
     }
 
-    // TODO make a cache for the MAC, not a good idea to REST call every time it gets ARP request
-    private MacAddress getTargetMacForTargetIp(Ip4Address targetIp) {
-        OpenstackPort port = openstackService.ports().stream()
-                .filter(p -> p.deviceOwner().equals(DEVICE_OWNER_ROUTER_GATEWAY) ||
-                        p.deviceOwner().equals(DEVICE_OWNER_FLOATING_IP))
-                .filter(p -> p.fixedIps().containsValue(targetIp.getIp4Address()))
-                .findAny().orElse(null);
-
-        return port == null ? MacAddress.NONE : port.macAddress();
+    private boolean isServiceIp(IpAddress targetIp) {
+        // FIXME use floating IP and external gateway information of router instead
+        // once openstack4j fixed
+        return osNetworkService.ports().stream()
+                .filter(osPort -> Objects.equals(osPort.getDeviceOwner(),
+                        DEVICE_OWNER_ROUTER_GW) ||
+                        Objects.equals(osPort.getDeviceOwner(),
+                                DEVICE_OWNER_FLOATING_IP))
+                .flatMap(osPort -> osPort.getFixedIps().stream())
+                .anyMatch(ip -> IpAddress.valueOf(ip.getIpAddress()).equals(targetIp));
     }
 }