CORD-643 Fixed VTN ARP proxy fails to reply when onos-cord restarted

- Fixed to update ARP proxy entry by SERVICE_NETWORK event not HOST event
- Fixed to read service entries from the existing network list at startup

Change-Id: Ided9dfee335f1110303ab191f9537eb566166c0a
diff --git a/src/main/java/org/opencord/cordvtn/impl/CordVtnArpProxy.java b/src/main/java/org/opencord/cordvtn/impl/CordVtnArpProxy.java
index 7b906e9..1d7562b 100644
--- a/src/main/java/org/opencord/cordvtn/impl/CordVtnArpProxy.java
+++ b/src/main/java/org/opencord/cordvtn/impl/CordVtnArpProxy.java
@@ -15,7 +15,6 @@
  */
 package org.opencord.cordvtn.impl;
 
-import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Maps;
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
@@ -28,6 +27,8 @@
 import org.onlab.packet.Ip4Address;
 import org.onlab.packet.IpAddress;
 import org.onlab.packet.MacAddress;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.Host;
 import org.onosproject.net.PortNumber;
@@ -38,15 +39,19 @@
 import org.onosproject.net.flow.DefaultTrafficTreatment;
 import org.onosproject.net.flow.TrafficSelector;
 import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.host.HostService;
 import org.onosproject.net.packet.DefaultOutboundPacket;
 import org.onosproject.net.packet.PacketContext;
 import org.onosproject.net.packet.PacketPriority;
 import org.onosproject.net.packet.PacketProcessor;
 import org.onosproject.net.packet.PacketService;
+import org.opencord.cordvtn.api.Constants;
 import org.opencord.cordvtn.api.CordVtnConfig;
 import org.opencord.cordvtn.api.core.Instance;
+import org.opencord.cordvtn.api.core.ServiceNetworkEvent;
+import org.opencord.cordvtn.api.core.ServiceNetworkListener;
+import org.opencord.cordvtn.api.core.ServiceNetworkService;
 import org.opencord.cordvtn.api.net.ServiceNetwork;
-import org.opencord.cordvtn.impl.handler.AbstractInstanceHandler;
 import org.slf4j.Logger;
 
 import java.nio.ByteBuffer;
@@ -54,6 +59,7 @@
 import java.util.Optional;
 import java.util.Set;
 
+import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Preconditions.checkNotNull;
 import static org.opencord.cordvtn.api.net.ServiceNetwork.NetworkType.*;
 import static org.slf4j.LoggerFactory.getLogger;
@@ -62,39 +68,57 @@
  * Handles ARP requests for virtual network service IPs.
  */
 @Component(immediate = true)
-public class CordVtnArpProxy extends AbstractInstanceHandler {
+public class CordVtnArpProxy {
     protected final Logger log = getLogger(getClass());
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected PacketService packetService;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected CordVtnNodeManager nodeManager;
+    protected CoreService coreService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected HostService hostService;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected NetworkConfigService configService;
 
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected CordVtnNodeManager nodeManager;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected ServiceNetworkService snetService;
+
     private final PacketProcessor packetProcessor = new InternalPacketProcessor();
     private final Map<Ip4Address, MacAddress> gateways = Maps.newConcurrentMap();
 
     private MacAddress privateGatewayMac = MacAddress.NONE;
     private NetworkConfigListener configListener = new InternalConfigListener();
+    private ServiceNetworkListener snetListener = new InternalServiceNetworkListener();
+    private ApplicationId appId;
 
     @Activate
     protected void activate() {
-        super.activate();
+        appId = coreService.registerApplication(Constants.CORDVTN_APP_ID);
         configService.addListener(configListener);
         readConfiguration();
 
         packetService.addProcessor(packetProcessor, PacketProcessor.director(0));
         requestPacket();
+
+        snetService.addListener(snetListener);
+        snetService.serviceNetworks().forEach(net -> {
+            if (net.serviceIp() != null) {
+                addGateway(net.serviceIp(), privateGatewayMac);
+            }
+        });
     }
 
     @Deactivate
     protected void deactivate() {
+        snetService.removeListener(snetListener);
         packetService.removeProcessor(packetProcessor);
         configService.removeListener(configListener);
-        super.deactivate();
     }
 
     /**
@@ -105,10 +129,11 @@
                 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
                 .build();
 
-        packetService.requestPackets(selector,
-                                     PacketPriority.CONTROL,
-                                     appId,
-                                     Optional.empty());
+        packetService.requestPackets(
+                selector,
+                PacketPriority.CONTROL,
+                appId,
+                Optional.empty());
     }
 
     /**
@@ -119,10 +144,11 @@
                 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
                 .build();
 
-        packetService.cancelPackets(selector,
-                                    PacketPriority.CONTROL,
-                                    appId,
-                                    Optional.empty());
+        packetService.cancelPackets(
+                selector,
+                PacketPriority.CONTROL,
+                appId,
+                Optional.empty());
     }
 
     /**
@@ -133,7 +159,11 @@
      */
     private void addGateway(IpAddress gatewayIp, MacAddress gatewayMac) {
         checkNotNull(gatewayIp);
-        checkNotNull(gatewayMac);
+        checkArgument(gatewayMac != null && gatewayMac != MacAddress.NONE,
+                      "privateGatewayMac is not configured");
+        log.debug("Added ARP proxy entry IP:{} MAC:{}",
+                  gatewayIp,
+                  privateGatewayMac);
         gateways.put(gatewayIp.getIp4Address(), gatewayMac);
     }
 
@@ -144,6 +174,9 @@
      */
     private void removeGateway(IpAddress gatewayIp) {
         checkNotNull(gatewayIp);
+        log.debug("Removed ARP proxy entry IP:{} MAC:{}",
+                  gatewayIp,
+                  privateGatewayMac);
         gateways.remove(gatewayIp.getIp4Address());
     }
 
@@ -346,37 +379,40 @@
         }
     }
 
-    @Override
-    public void instanceDetected(Instance instance) {
-        // TODO remove this when XOS provides access agent information
-        // and handle it the same way wit the other instances
-        if (instance.netType() == ACCESS_AGENT) {
-            return;
+    private class InternalServiceNetworkListener implements ServiceNetworkListener {
+
+        @Override
+        public boolean isRelevant(ServiceNetworkEvent event) {
+            ServiceNetwork snet = event.subject();
+            if (snet.type() == PUBLIC ||
+                    snet.type() == MANAGEMENT_HOST ||
+                    snet.type() == MANAGEMENT_LOCAL ||
+                    snet.type() == ACCESS_AGENT) {
+                return false;
+            }
+            return true;
         }
 
-        ServiceNetwork snet = getServiceNetwork(instance);
-        if (snet.type() != PUBLIC && snet.type() != MANAGEMENT_HOST &&
-                snet.type() != MANAGEMENT_LOCAL) {
-            log.trace("Added IP:{} MAC:{}", snet.serviceIp(), privateGatewayMac);
-            addGateway(snet.serviceIp(), privateGatewayMac);
-            // send gratuitous ARP for the existing VMs when ONOS is restarted
-            sendGratuitousArp(snet.serviceIp(), ImmutableSet.of(instance));
-        }
-    }
-
-    @Override
-    public void instanceRemoved(Instance instance) {
-        // TODO remove this when XOS provides access agent information
-        // and handle it the same way wit the other instances
-        if (instance.netType() == ACCESS_AGENT) {
-            return;
-        }
-
-        ServiceNetwork vtnNet = getServiceNetwork(instance);
-        // remove this network gateway from proxy ARP if no instance presents
-        if (vtnNet.type() == PRIVATE &&
-                getInstances(vtnNet.id()).isEmpty()) {
-            removeGateway(vtnNet.serviceIp());
+        @Override
+        public void event(ServiceNetworkEvent event) {
+            ServiceNetwork snet = event.subject();
+            switch (event.type()) {
+                case SERVICE_NETWORK_CREATED:
+                case SERVICE_NETWORK_UPDATED:
+                    if (snet.serviceIp() != null) {
+                        addGateway(snet.serviceIp(), privateGatewayMac);
+                    }
+                    break;
+                case SERVICE_NETWORK_REMOVED:
+                    removeGateway(snet.serviceIp());
+                    break;
+                case SERVICE_PORT_CREATED:
+                case SERVICE_PORT_UPDATED:
+                case SERVICE_PORT_REMOVED:
+                default:
+                    // do nothing for the other events
+                    break;
+            }
         }
     }
 
@@ -388,12 +424,10 @@
         }
 
         privateGatewayMac = config.privateGatewayMac();
-        log.debug("Added private gateway MAC {}", privateGatewayMac);
+        log.debug("Set default service IP MAC address {}", privateGatewayMac);
 
         config.publicGateways().entrySet().stream().forEach(entry -> {
             addGateway(entry.getKey(), entry.getValue());
-            log.debug("Added public gateway IP {}, MAC {}",
-                      entry.getKey(), entry.getValue());
         });
         // TODO send gratuitous arp in case the MAC is changed
     }
@@ -401,10 +435,12 @@
     private class InternalConfigListener implements NetworkConfigListener {
 
         @Override
+        public boolean isRelevant(NetworkConfigEvent event) {
+            return event.configClass().equals(CordVtnConfig.class);
+        }
+
+        @Override
         public void event(NetworkConfigEvent event) {
-            if (!event.configClass().equals(CordVtnConfig.class)) {
-                return;
-            }
 
             switch (event.type()) {
                 case CONFIG_ADDED:
diff --git a/src/main/java/org/opencord/cordvtn/impl/CordVtnDhcpProxy.java b/src/main/java/org/opencord/cordvtn/impl/CordVtnDhcpProxy.java
index e1f8fbf..d78be9b 100644
--- a/src/main/java/org/opencord/cordvtn/impl/CordVtnDhcpProxy.java
+++ b/src/main/java/org/opencord/cordvtn/impl/CordVtnDhcpProxy.java
@@ -446,16 +446,18 @@
             return;
         }
         dhcpServerMac = config.privateGatewayMac();
-        log.debug("Added DHCP server MAC {}", dhcpServerMac);
+        log.debug("Set default DHCP server MAC address {}", dhcpServerMac);
     }
 
     private class InternalConfigListener implements NetworkConfigListener {
 
         @Override
+        public boolean isRelevant(NetworkConfigEvent event) {
+            return event.configClass().equals(CordVtnConfig.class);
+        }
+
+        @Override
         public void event(NetworkConfigEvent event) {
-            if (!event.configClass().equals(CordVtnConfig.class)) {
-                return;
-            }
 
             switch (event.type()) {
                 case CONFIG_ADDED: