[ONOS-6038] [ONOS-6036]Support Neutron network/port admin state up/down configuration

Change-Id: I4b4251131b38d719ee1980741bbf30750f403407
diff --git a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingHandler.java b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingHandler.java
index 8370250..4bb42a0 100644
--- a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingHandler.java
+++ b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingHandler.java
@@ -23,6 +23,7 @@
 import org.apache.felix.scr.annotations.Reference;
 import org.apache.felix.scr.annotations.ReferenceCardinality;
 import org.onlab.packet.Ethernet;
+import org.onlab.packet.MacAddress;
 import org.onlab.packet.VlanId;
 import org.onosproject.core.ApplicationId;
 import org.onosproject.core.CoreService;
@@ -37,22 +38,34 @@
 import org.onosproject.openstacknetworking.api.InstancePortListener;
 import org.onosproject.openstacknetworking.api.InstancePortService;
 import org.onosproject.openstacknetworking.api.OpenstackFlowRuleService;
+import org.onosproject.openstacknetworking.api.OpenstackNetworkEvent;
+import org.onosproject.openstacknetworking.api.OpenstackNetworkListener;
 import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
 import org.onosproject.openstacknode.api.OpenstackNode;
 import org.onosproject.openstacknode.api.OpenstackNodeService;
 import org.openstack4j.model.network.Network;
+import org.openstack4j.model.network.NetworkType;
+import org.openstack4j.model.network.Port;
 import org.slf4j.Logger;
 
 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.ACL_TABLE;
 import static org.onosproject.openstacknetworking.api.Constants.FORWARDING_TABLE;
 import static org.onosproject.openstacknetworking.api.Constants.OPENSTACK_NETWORKING_APP_ID;
+import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ADMIN_RULE;
 import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_SWITCHING_RULE;
 import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_TUNNEL_TAG_RULE;
 import static org.onosproject.openstacknetworking.api.Constants.SRC_VNI_TABLE;
+import static org.onosproject.openstacknetworking.api.OpenstackNetworkEvent.Type.OPENSTACK_NETWORK_CREATED;
+import static org.onosproject.openstacknetworking.api.OpenstackNetworkEvent.Type.OPENSTACK_NETWORK_REMOVED;
+import static org.onosproject.openstacknetworking.api.OpenstackNetworkEvent.Type.OPENSTACK_NETWORK_UPDATED;
+import static org.onosproject.openstacknetworking.api.OpenstackNetworkEvent.Type.OPENSTACK_PORT_CREATED;
+import static org.onosproject.openstacknetworking.api.OpenstackNetworkEvent.Type.OPENSTACK_PORT_REMOVED;
+import static org.onosproject.openstacknetworking.api.OpenstackNetworkEvent.Type.OPENSTACK_PORT_UPDATED;
 import static org.onosproject.openstacknetworking.impl.RulePopulatorUtil.buildExtension;
 import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.COMPUTE;
 import static org.slf4j.LoggerFactory.getLogger;
@@ -93,12 +106,15 @@
     private final ExecutorService eventExecutor = newSingleThreadExecutor(
             groupedThreads(this.getClass().getSimpleName(), "event-handler"));
     private final InstancePortListener instancePortListener = new InternalInstancePortListener();
+    private final InternalOpenstackNetworkListener osNetworkListener =
+            new InternalOpenstackNetworkListener();
     private ApplicationId appId;
 
     @Activate
     protected void activate() {
         appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
         instancePortService.addListener(instancePortListener);
+        osNetworkService.addListener(osNetworkListener);
 
         log.info("Started");
     }
@@ -106,6 +122,7 @@
     @Deactivate
     protected void deactivate() {
         instancePortService.removeListener(instancePortListener);
+        osNetworkService.removeListener(osNetworkListener);
         eventExecutor.shutdown();
 
         log.info("Stopped");
@@ -265,6 +282,57 @@
 
     }
 
+    private void setNetworkAdminRules(Network network, boolean install) {
+        TrafficSelector selector;
+        if (network.getNetworkType() == NetworkType.VXLAN) {
+
+            selector = DefaultTrafficSelector.builder()
+                    .matchTunnelId(Long.valueOf(network.getProviderSegID()))
+                    .build();
+        } else {
+            selector = DefaultTrafficSelector.builder()
+                    .matchVlanId(VlanId.vlanId(network.getProviderSegID()))
+                    .build();
+        }
+
+        TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+                .drop()
+                .build();
+
+        osNodeService.completeNodes().stream()
+                .filter(osNode -> osNode.type() == COMPUTE)
+                .forEach(osNode -> {
+                    osFlowRuleService.setRule(
+                            appId,
+                            osNode.intgBridge(),
+                            selector,
+                            treatment,
+                            PRIORITY_ADMIN_RULE,
+                            ACL_TABLE,
+                            install);
+                });
+    }
+
+    private void setPortAdminRules(Port port, boolean install) {
+        InstancePort instancePort = instancePortService.instancePort(MacAddress.valueOf(port.getMacAddress()));
+        TrafficSelector selector = DefaultTrafficSelector.builder()
+                .matchInPort(instancePort.portNumber())
+                .build();
+
+        TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+                .drop()
+                .build();
+
+        osFlowRuleService.setRule(
+                appId,
+                instancePort.deviceId(),
+                selector,
+                treatment,
+                PRIORITY_ADMIN_RULE,
+                SRC_VNI_TABLE,
+                install);
+    }
+
     private VlanId getVlanId(InstancePort instPort) {
         Network osNet = osNetworkService.network(instPort.networkId());
 
@@ -334,4 +402,32 @@
             // TODO add something else if needed
         }
     }
+
+    private class InternalOpenstackNetworkListener implements OpenstackNetworkListener {
+
+        @Override
+        public boolean isRelevant(OpenstackNetworkEvent event) {
+            return !(event.subject() == null && event.port() == null);
+        }
+
+        @Override
+        public void event(OpenstackNetworkEvent event) {
+
+            if ((event.type() == OPENSTACK_NETWORK_CREATED ||
+                    event.type() == OPENSTACK_NETWORK_UPDATED) && !event.subject().isAdminStateUp()) {
+                setNetworkAdminRules(event.subject(), true);
+            } else if ((event.type() == OPENSTACK_NETWORK_UPDATED && event.subject().isAdminStateUp()) ||
+                    (event.type() == OPENSTACK_NETWORK_REMOVED && !event.subject().isAdminStateUp())) {
+                setNetworkAdminRules(event.subject(), false);
+            }
+
+            if ((event.type() == OPENSTACK_PORT_CREATED ||
+                    event.type() == OPENSTACK_PORT_UPDATED) && !event.port().isAdminStateUp()) {
+                setPortAdminRules(event.port(), true);
+            } else if ((event.type() == OPENSTACK_PORT_UPDATED && event.port().isAdminStateUp()) ||
+                    (event.type() == OPENSTACK_PORT_REMOVED && !event.port().isAdminStateUp())) {
+                setPortAdminRules(event.port(), false);
+            }
+        }
+    }
 }