Refactor: split the flow rule setup logic for compute and ctrl nodes

Change-Id: I30d5b2a63615fad3f5fd8281edbf46574809cb13
diff --git a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingArpHandler.java b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingArpHandler.java
index c016447..42c1c77 100644
--- a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingArpHandler.java
+++ b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingArpHandler.java
@@ -60,6 +60,8 @@
 import org.onosproject.openstacknetworking.api.OpenstackRouterListener;
 import org.onosproject.openstacknetworking.api.OpenstackRouterService;
 import org.onosproject.openstacknode.api.OpenstackNode;
+import org.onosproject.openstacknode.api.OpenstackNodeEvent;
+import org.onosproject.openstacknode.api.OpenstackNodeListener;
 import org.onosproject.openstacknode.api.OpenstackNodeService;
 import org.openstack4j.model.network.ExternalGateway;
 import org.openstack4j.model.network.NetFloatingIP;
@@ -84,8 +86,10 @@
 import static org.onosproject.openstacknetworking.api.Constants.ARP_PROXY_MODE;
 import static org.onosproject.openstacknetworking.api.Constants.DEFAULT_ARP_MODE_STR;
 import static org.onosproject.openstacknetworking.api.Constants.DEFAULT_GATEWAY_MAC_STR;
+import static org.onosproject.openstacknetworking.api.Constants.DHCP_ARP_TABLE;
 import static org.onosproject.openstacknetworking.api.Constants.GW_COMMON_TABLE;
 import static org.onosproject.openstacknetworking.api.Constants.OPENSTACK_NETWORKING_APP_ID;
+import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ARP_CONTROL_RULE;
 import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ARP_GATEWAY_RULE;
 import static org.onosproject.openstacknetworking.impl.HostBasedInstancePort.ANNOTATION_NETWORK_ID;
 import static org.onosproject.openstacknetworking.impl.HostBasedInstancePort.ANNOTATION_PORT_ID;
@@ -144,6 +148,7 @@
 
     private final OpenstackRouterListener osRouterListener = new InternalRouterEventListener();
     private final HostListener hostListener = new InternalHostListener();
+    private final OpenstackNodeListener osNodeListener = new InternalNodeEventListener();
 
     private ApplicationId appId;
     private NodeId localNodeId;
@@ -161,6 +166,7 @@
         localNodeId = clusterService.getLocalNode().id();
         osRouterService.addListener(osRouterListener);
         hostService.addListener(hostListener);
+        osNodeService.addListener(osNodeListener);
         leadershipService.runForLeadership(appId.name());
         packetService.addProcessor(packetProcessor, PacketProcessor.director(1));
         log.info("Started");
@@ -171,6 +177,7 @@
         packetService.removeProcessor(packetProcessor);
         hostService.removeListener(hostListener);
         osRouterService.removeListener(osRouterListener);
+        osNodeService.removeListener(osNodeListener);
         leadershipService.withdraw(appId.name());
         eventExecutor.shutdown();
         configService.unregisterProperties(getClass(), false);
@@ -565,4 +572,92 @@
                     host.annotations().value(ANNOTATION_PORT_ID) != null;
         }
     }
+
+    private class InternalNodeEventListener implements OpenstackNodeListener {
+
+        @Override
+        public boolean isRelevant(OpenstackNodeEvent event) {
+            // do not allow to proceed without leadership
+            NodeId leader = leadershipService.getLeader(appId.name());
+            return Objects.equals(localNodeId, leader);
+        }
+
+        @Override
+        public void event(OpenstackNodeEvent event) {
+            OpenstackNode osNode = event.subject();
+            switch (event.type()) {
+                case OPENSTACK_NODE_COMPLETE:
+                    if (osNode.type().equals(GATEWAY)) {
+                        setDefaultArpRule(osNode, true);
+                    }
+                    break;
+                case OPENSTACK_NODE_INCOMPLETE:
+                    if (osNode.type().equals(GATEWAY)) {
+                        setDefaultArpRule(osNode, false);
+                    }
+                    break;
+                default:
+                    break;
+            }
+        }
+
+        private void setDefaultArpRule(OpenstackNode osNode, boolean install) {
+            switch (arpMode) {
+                case ARP_PROXY_MODE:
+                    setDefaultArpRuleForProxyMode(osNode, install);
+                    break;
+                case ARP_BROADCAST_MODE:
+                    setDefaultArpRuleForBroadcastMode(osNode, install);
+                    break;
+                default:
+                    log.warn("Invalid ARP mode {}. Please use either " +
+                            "broadcast or proxy mode.", arpMode);
+                    break;
+            }
+        }
+
+        private void setDefaultArpRuleForProxyMode(OpenstackNode osNode, boolean install) {
+            TrafficSelector selector = DefaultTrafficSelector.builder()
+                    .matchEthType(EthType.EtherType.ARP.ethType().toShort())
+                    .build();
+
+            TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+                    .punt()
+                    .build();
+
+            osFlowRuleService.setRule(
+                    appId,
+                    osNode.intgBridge(),
+                    selector,
+                    treatment,
+                    PRIORITY_ARP_CONTROL_RULE,
+                    DHCP_ARP_TABLE,
+                    install
+            );
+        }
+
+        private void setDefaultArpRuleForBroadcastMode(OpenstackNode osNode, boolean install) {
+            // we only match ARP_REPLY in gateway node, because controller
+            // somehow need to process ARP_REPLY which is issued from
+            // external router...
+            TrafficSelector selector = DefaultTrafficSelector.builder()
+                    .matchEthType(EthType.EtherType.ARP.ethType().toShort())
+                    .matchArpOp(ARP.OP_REPLY)
+                    .build();
+
+            TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+                    .punt()
+                    .build();
+
+            osFlowRuleService.setRule(
+                    appId,
+                    osNode.intgBridge(),
+                    selector,
+                    treatment,
+                    PRIORITY_ARP_CONTROL_RULE,
+                    DHCP_ARP_TABLE,
+                    install
+            );
+        }
+    }
 }
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 c354f19..f2c2eda 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
@@ -86,7 +86,6 @@
 import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ARP_SUBNET_RULE;
 import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.buildExtension;
 import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.COMPUTE;
-import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.GATEWAY;
 
 /**
  * Handles ARP packet from VMs.
@@ -433,73 +432,75 @@
             OpenstackNode osNode = event.subject();
             switch (event.type()) {
                 case OPENSTACK_NODE_COMPLETE:
-                    setDefaultArpRule(osNode, true);
+                    if (osNode.type().equals(COMPUTE)) {
+                        setDefaultArpRule(osNode, true);
+                    }
                     break;
                 case OPENSTACK_NODE_INCOMPLETE:
-                    setDefaultArpRule(osNode, false);
+                    if (osNode.type().equals(COMPUTE)) {
+                        setDefaultArpRule(osNode, false);
+                    }
                     break;
-                case OPENSTACK_NODE_CREATED:
-                case OPENSTACK_NODE_UPDATED:
-                case OPENSTACK_NODE_REMOVED:
                 default:
                     break;
             }
         }
 
-        private void setDefaultArpRule(OpenstackNode openstackNode, boolean install) {
-            if (arpMode.equals(ARP_PROXY_MODE)) {
-
-                TrafficSelector selector = DefaultTrafficSelector.builder()
-                        .matchEthType(EthType.EtherType.ARP.ethType().toShort())
-                        .build();
-
-                TrafficTreatment treatment = DefaultTrafficTreatment.builder()
-                        .punt()
-                        .build();
-
-                osFlowRuleService.setRule(
-                        appId,
-                        openstackNode.intgBridge(),
-                        selector,
-                        treatment,
-                        PRIORITY_ARP_CONTROL_RULE,
-                        DHCP_ARP_TABLE,
-                        install
-                );
-            } else if (arpMode.equals(ARP_BROADCAST_MODE)) {
-
-                TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder()
-                        .matchEthType(EthType.EtherType.ARP.ethType().toShort());
-
-                TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
-
-                // we only match ARP_REPLY in gateway node, because controller
-                // somehow need to process ARP_REPLY which is issued from
-                // external router...
-                // TODO: following code needs to be moved to OpenstackRoutingArpHandler sooner or later
-                if (openstackNode.type().equals(GATEWAY)) {
-                    selectorBuilder.matchArpOp(ARP.OP_REPLY);
-                    treatmentBuilder.punt();
-                }
-
-                if (openstackNode.type().equals(COMPUTE)) {
-                    selectorBuilder.matchArpOp(ARP.OP_REQUEST);
-                    treatmentBuilder.setOutput(PortNumber.FLOOD);
-                }
-
-                osFlowRuleService.setRule(
-                        appId,
-                        openstackNode.intgBridge(),
-                        selectorBuilder.build(),
-                        treatmentBuilder.build(),
-                        PRIORITY_ARP_SUBNET_RULE,
-                        DHCP_ARP_TABLE,
-                        install
-                );
-            } else {
-                log.warn("Invalid ARP mode {}. Please use either broadcast or proxy mode.", arpMode);
+        private void setDefaultArpRule(OpenstackNode osNode, boolean install) {
+            switch (arpMode) {
+                case ARP_PROXY_MODE:
+                    setDefaultArpRuleForProxyMode(osNode, install);
+                    break;
+                case ARP_BROADCAST_MODE:
+                    setDefaultArpRuleForBroadcastMode(osNode, install);
+                    break;
+                default:
+                    log.warn("Invalid ARP mode {}. Please use either " +
+                            "broadcast or proxy mode.", arpMode);
+                    break;
             }
         }
+
+        private void setDefaultArpRuleForProxyMode(OpenstackNode osNode, boolean install) {
+            TrafficSelector selector = DefaultTrafficSelector.builder()
+                    .matchEthType(EthType.EtherType.ARP.ethType().toShort())
+                    .build();
+
+            TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+                    .punt()
+                    .build();
+
+            osFlowRuleService.setRule(
+                    appId,
+                    osNode.intgBridge(),
+                    selector,
+                    treatment,
+                    PRIORITY_ARP_CONTROL_RULE,
+                    DHCP_ARP_TABLE,
+                    install
+            );
+        }
+
+        private void setDefaultArpRuleForBroadcastMode(OpenstackNode osNode, boolean install) {
+            TrafficSelector selector = DefaultTrafficSelector.builder()
+                    .matchEthType(EthType.EtherType.ARP.ethType().toShort())
+                    .matchArpOp(ARP.OP_REQUEST)
+                    .build();
+
+            TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+                    .setOutput(PortNumber.FLOOD)
+                    .build();
+
+            osFlowRuleService.setRule(
+                    appId,
+                    osNode.intgBridge(),
+                    selector,
+                    treatment,
+                    PRIORITY_ARP_SUBNET_RULE,
+                    DHCP_ARP_TABLE,
+                    install
+            );
+        }
     }
 
     /**