Refactored OpenstackSwitching app

[DONE]
- Restructured to activate or deactivate switching and routing app separately
- Fixed to add or remove host when port is detected or vanished
- Use openstack node service to get integration bridges and data IP

[TODO]
- Remove use of OpenstackPortInfo
- Support installing flow rules for exising VMs
- Call security group update method when port update triggered from OpenStack

Change-Id: Ic0b2ac3f7ab07f0e20c97c6edfdd1928b9767baf
diff --git a/BUCK b/BUCK
index 2573600..d2e4aec 100644
--- a/BUCK
+++ b/BUCK
@@ -117,8 +117,8 @@
     '//apps/mlb:onos-apps-mlb-oar',
     '//apps/openstackinterface:onos-apps-openstackinterface-oar',
     '//apps/openstacknetworking:onos-apps-openstacknetworking-oar',
-    '//apps/openstacknetworking/openstackrouting:onos-apps-openstacknetworking-openstackrouting-oar',
-    '//apps/openstacknetworking/openstackswitching:onos-apps-openstacknetworking-openstackswitching-oar',
+    '//apps/openstacknetworking/routing:onos-apps-openstacknetworking-routing-oar',
+    '//apps/openstacknetworking/switching:onos-apps-openstacknetworking-switching-oar',
     '//apps/mobility:onos-apps-mobility-oar',
     '//apps/optical:onos-apps-optical-oar',
     '//apps/newoptical:onos-apps-newoptical-oar',
diff --git a/apps/openstacknetworking/BUCK b/apps/openstacknetworking/BUCK
index 03639d1..3176898 100644
--- a/apps/openstacknetworking/BUCK
+++ b/apps/openstacknetworking/BUCK
@@ -8,5 +8,5 @@
   category = 'Utility',
   url = 'http://onosproject.org',
   included_bundles = BUNDLES,
-  required_apps = [ 'org.onosproject.openstackinterface' ],
+  required_apps = [ 'org.onosproject.openstackrouting', 'org.onosproject.openstackswitching' ]
 )
diff --git a/apps/openstacknetworking/api/src/main/java/org/onosproject/openstacknetworking/OpenstackPortInfo.java b/apps/openstacknetworking/api/src/main/java/org/onosproject/openstacknetworking/OpenstackPortInfo.java
index 6217bf3..b40b865 100644
--- a/apps/openstacknetworking/api/src/main/java/org/onosproject/openstacknetworking/OpenstackPortInfo.java
+++ b/apps/openstacknetworking/api/src/main/java/org/onosproject/openstacknetworking/OpenstackPortInfo.java
@@ -19,14 +19,12 @@
 import org.onlab.packet.MacAddress;
 import org.onosproject.net.DeviceId;
 
-import java.util.Collection;
-import java.util.Collections;
-
 import static com.google.common.base.Preconditions.checkNotNull;
 
 /**
  * Contains OpenstackPort Information.
  */
+// TODO remove this
 public final class OpenstackPortInfo {
     private final Ip4Address hostIp;
     private final MacAddress hostMac;
@@ -34,7 +32,6 @@
     private final long vni;
     private final Ip4Address gatewayIP;
     private final String networkId;
-    private final Collection<String> securityGroups;
 
     /**
      * Returns OpenstackPortInfo reference.
@@ -45,17 +42,15 @@
      * @param vni  tunnel ID
      * @param gatewayIP gateway IP address
      * @param networkId network identifier
-     * @param securityGroups security group list
      */
     public OpenstackPortInfo(Ip4Address hostIp, MacAddress hostMac, DeviceId deviceId, long vni,
-                             Ip4Address gatewayIP, String networkId, Collection<String> securityGroups) {
+                             Ip4Address gatewayIP, String networkId) {
         this.hostIp = hostIp;
         this.hostMac = hostMac;
         this.deviceId = deviceId;
         this.vni = vni;
         this.gatewayIP = gatewayIP;
         this.networkId = networkId;
-        this.securityGroups = securityGroups;
     }
 
     /**
@@ -113,15 +108,6 @@
     }
 
     /**
-     * Returns Security Group ID list.
-     *
-     * @return list of Security Group ID
-     */
-    public Collection<String> securityGroups() {
-        return Collections.unmodifiableCollection(securityGroups);
-    }
-
-    /**
      * Returns the builder of the OpenstackPortInfo.
      *
      * @return OpenstackPortInfo builder reference
@@ -140,7 +126,6 @@
         private DeviceId deviceId;
         private long vni;
         private Ip4Address gatewayIP;
-        private Collection<String> securityGroups;
         private String networkId;
 
         /**
@@ -210,23 +195,12 @@
         }
 
         /**
-         * Sets the security group ID list.
-         *
-         * @param securityGroups security group ID list
-         * @return Builder reference
-         */
-        public Builder setSecurityGroups(Collection<String> securityGroups) {
-            this.securityGroups = securityGroups;
-            return this;
-        }
-
-        /**
          * Builds the OpenstackPortInfo reference.
          *
          * @return OpenstackPortInfo reference
          */
         public OpenstackPortInfo build() {
-            return new OpenstackPortInfo(hostIp, hostMac, deviceId, vni, gatewayIP, networkId, securityGroups);
+            return new OpenstackPortInfo(hostIp, hostMac, deviceId, vni, gatewayIP, networkId);
         }
     }
 }
diff --git a/apps/openstacknetworking/api/src/main/java/org/onosproject/openstacknetworking/OpenstackSwitchingService.java b/apps/openstacknetworking/api/src/main/java/org/onosproject/openstacknetworking/OpenstackSwitchingService.java
index 31dd9aa..c9f32ab 100644
--- a/apps/openstacknetworking/api/src/main/java/org/onosproject/openstacknetworking/OpenstackSwitchingService.java
+++ b/apps/openstacknetworking/api/src/main/java/org/onosproject/openstacknetworking/OpenstackSwitchingService.java
@@ -15,57 +15,19 @@
  */
 package org.onosproject.openstacknetworking;
 
-import org.onosproject.openstackinterface.OpenstackNetwork;
-import org.onosproject.openstackinterface.OpenstackPort;
-import org.onosproject.openstackinterface.OpenstackSubnet;
-
 import java.util.Map;
 
 /**
  * Handles port management REST API from Openstack for VMs.
  */
+// TODO remove this
 public interface OpenstackSwitchingService {
 
     /**
-     * Store the port information created by Openstack.
-     *
-     * @param openstackPort port information
-     */
-    void createPorts(OpenstackPort openstackPort);
-
-    /**
-     * Removes flow rules corresponding to the port removed by Openstack.
-     *
-     * @param uuid UUID
-     */
-    void removePort(String uuid);
-
-    /**
-     * Updates flow rules corresponding to the port information updated by Openstack.
-     *
-     * @param openstackPort OpenStack port
-     */
-    void updatePort(OpenstackPort openstackPort);
-
-    /**
-     * Stores the network information created by openstack.
-     *
-     * @param openstackNetwork network information
-     */
-    void createNetwork(OpenstackNetwork openstackNetwork);
-
-    /**
-     * Stores the subnet information created by openstack.
-     *
-     * @param openstackSubnet subnet information
-     */
-    void createSubnet(OpenstackSubnet openstackSubnet);
-
-    /**
      * Retruns OpenstackPortInfo map.
      *
      * @return OpenstackPortInfo map
      */
+    // TODO remove this
     Map<String, OpenstackPortInfo> openstackPortInfo();
-
 }
diff --git a/apps/openstacknetworking/app/app.xml b/apps/openstacknetworking/app/app.xml
deleted file mode 100644
index 181c6af..0000000
--- a/apps/openstacknetworking/app/app.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-  ~ Copyright 2016-present Open Networking Laboratory
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~     http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-<app name="org.onosproject.openstacknetworking" origin="ON.Lab" version="${project.version}"
-     category="Utility" url="http://onosproject.org" title="OpenStack Networking App"
-     featuresRepo="mvn:${project.groupId}/${project.artifactId}/${project.version}/xml/features"
-     features="${project.artifactId}"
-     apps="org.onosproject.openstackswitching,org.onosproject.openstackrouting">
-    <description>${project.description}</description>
-    <artifact>mvn:${project.groupId}/onos-app-openstacknetworking-api/${project.version}</artifact>
-    <artifact>mvn:${project.groupId}/onos-app-openstacknetworking-web/${project.version}</artifact>
-</app>
diff --git a/apps/openstacknetworking/app/pom.xml b/apps/openstacknetworking/app/pom.xml
deleted file mode 100644
index 21a622d..0000000
--- a/apps/openstacknetworking/app/pom.xml
+++ /dev/null
@@ -1,59 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-  ~ Copyright 2016-present Open Networking Laboratory
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~     http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-<project xmlns="http://maven.apache.org/POM/4.0.0"
-         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-    <modelVersion>4.0.0</modelVersion>
-
-    <parent>
-        <groupId>org.onosproject</groupId>
-        <artifactId>onos-app-openstacknetworking</artifactId>
-        <version>1.7.0-SNAPSHOT</version>
-    </parent>
-
-    <artifactId>onos-app-openstacknetworking-app</artifactId>
-    <packaging>pom</packaging>
-
-    <properties>
-        <onos.app.readme>Openstack Networking Application.</onos.app.readme>
-    </properties>
-
-    <description>SONA Openstack Networking main Application</description>
-
-    <dependencies>
-        <dependency>
-            <groupId>org.onosproject</groupId>
-            <artifactId>onos-app-openstackswitching</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>org.onosproject</groupId>
-            <artifactId>onos-app-openstackrouting</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>org.onosproject</groupId>
-            <artifactId>onos-app-openstacknetworking-api</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>org.onosproject</groupId>
-            <artifactId>onos-app-openstacknetworking-web</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-    </dependencies>
-</project>
diff --git a/apps/openstacknetworking/openstackrouting/app.xml b/apps/openstacknetworking/openstackrouting/app.xml
deleted file mode 100644
index a2a373c..0000000
--- a/apps/openstacknetworking/openstackrouting/app.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-  ~ Copyright 2016-present Open Networking Laboratory
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~     http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-<app name="org.onosproject.openstackrouting" origin="ON.Lab" version="${project.version}"
-     category="default" url="http://onosproject.org"
-     featuresRepo="mvn:${project.groupId}/${project.artifactId}/${project.version}/xml/features"
-     features="${project.artifactId}" >
-    <description>${project.description}</description>
-    <artifact>mvn:${project.groupId}/onos-app-openstackrouting/${project.version}</artifact>
-    <artifact>mvn:${project.groupId}/onos-app-openstacknetworking-api/${project.version}</artifact>
-</app>
diff --git a/apps/openstacknetworking/openstackrouting/features.xml b/apps/openstacknetworking/openstackrouting/features.xml
deleted file mode 100644
index 4c9eca4..0000000
--- a/apps/openstacknetworking/openstackrouting/features.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
-<!--
-  ~ Copyright 2016-present Open Networking Laboratory
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~     http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-<features xmlns="http://karaf.apache.org/xmlns/features/v1.2.0" name="${project.artifactId}-${project.version}">
-    <feature name="${project.artifactId}" version="${project.version}"
-             description="${project.description}">
-        <feature>onos-api</feature>
-        <bundle>mvn:${project.groupId}/onos-app-openstackrouting/${project.version}</bundle>
-        <bundle>mvn:${project.groupId}/onos-app-openstacknetworking-api/${project.version}</bundle>
-    </feature>
-</features>
diff --git a/apps/openstacknetworking/openstackswitching/app.xml b/apps/openstacknetworking/openstackswitching/app.xml
deleted file mode 100644
index 657b70a..0000000
--- a/apps/openstacknetworking/openstackswitching/app.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-  ~ Copyright 2016-present Open Networking Laboratory
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~     http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-<app name="org.onosproject.openstackswitching" origin="ON.Lab" version="${project.version}"
-     category="default" url="http://onosproject.org"
-     featuresRepo="mvn:${project.groupId}/${project.artifactId}/${project.version}/xml/features"
-     features="${project.artifactId}"
-     apps="org.onosproject.dhcp">
-    <description>${project.description}</description>
-    <artifact>mvn:${project.groupId}/onos-app-openstackswitching/${project.version}</artifact>
-    <artifact>mvn:${project.groupId}/onos-app-openstacknetworking-api/${project.version}</artifact>
-</app>
diff --git a/apps/openstacknetworking/openstackswitching/features.xml b/apps/openstacknetworking/openstackswitching/features.xml
deleted file mode 100644
index ddbe726..0000000
--- a/apps/openstacknetworking/openstackswitching/features.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
-<!--
-  ~ Copyright 2016-present Open Networking Laboratory
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~     http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-<features xmlns="http://karaf.apache.org/xmlns/features/v1.2.0" name="${project.artifactId}-${project.version}">
-    <feature name="${project.artifactId}" version="${project.version}"
-             description="${project.description}">
-        <feature>onos-api</feature>
-        <bundle>mvn:${project.groupId}/onos-app-openstacknetworking-api/${project.version}</bundle>
-        <bundle>mvn:${project.groupId}/onos-app-openstackswitching/${project.version}</bundle>
-    </feature>
-</features>
diff --git a/apps/openstacknetworking/openstackswitching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackArpHandler.java b/apps/openstacknetworking/openstackswitching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackArpHandler.java
deleted file mode 100644
index 48398fd..0000000
--- a/apps/openstacknetworking/openstackswitching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackArpHandler.java
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
-* Copyright 2016-present Open Networking Laboratory
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-*     http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
-package org.onosproject.openstacknetworking.switching;
-
-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.PacketService;
-import org.onosproject.openstackinterface.OpenstackInterfaceService;
-import org.onosproject.openstackinterface.OpenstackPort;
-import org.onosproject.openstacknetworking.OpenstackPortInfo;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import java.nio.ByteBuffer;
-import java.util.Collection;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-/**
- * Handles ARP packet from VMs.
- */
-public class OpenstackArpHandler {
-
-    private static Logger log = LoggerFactory
-            .getLogger(OpenstackArpHandler.class);
-    private static final MacAddress GATEWAY_MAC = MacAddress.valueOf("1f:1f:1f:1f:1f:1f");
-    private PacketService packetService;
-    private OpenstackInterfaceService openstackService;
-    private HostService hostService;
-
-    /**
-     * Returns OpenstackArpHandler reference.
-     *
-     * @param openstackService OpenstackNetworkingService reference
-     * @param packetService PacketService reference
-     * @param hostService host service
-     */
-    public OpenstackArpHandler(OpenstackInterfaceService openstackService, PacketService packetService,
-                               HostService hostService) {
-        this.openstackService = openstackService;
-        this.packetService = packetService;
-        this.hostService = hostService;
-    }
-
-    /**
-     * 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
-     * @param openstackPortInfoCollection collection of port information
-     */
-    public void processPacketIn(InboundPacket pkt, Collection<OpenstackPortInfo> openstackPortInfoCollection) {
-        Ethernet ethRequest = pkt.parsed();
-        ARP arp = (ARP) ethRequest.getPayload();
-
-        if (arp.getOpCode() != ARP.OP_REQUEST) {
-            return;
-        }
-
-        IpAddress sourceIp = Ip4Address.valueOf(arp.getSenderProtocolAddress());
-        MacAddress srcMac = MacAddress.valueOf(arp.getSenderHardwareAddress());
-        OpenstackPortInfo portInfo = openstackPortInfoCollection.stream()
-                .filter(p -> p.ip().equals(sourceIp) && p.mac().equals(srcMac)).findFirst().orElse(null);
-        IpAddress targetIp = Ip4Address.valueOf(arp.getTargetProtocolAddress());
-
-        MacAddress dstMac;
-
-        if (targetIp.equals(portInfo == null ? null : portInfo.gatewayIP())) {
-            dstMac = GATEWAY_MAC;
-        } else {
-            dstMac = getMacFromHostService(targetIp);
-            if (dstMac == null) {
-                dstMac = getMacFromOpenstack(targetIp);
-            }
-        }
-
-        if (dstMac == null) {
-            log.debug("Failed to find MAC address for {}", targetIp.toString());
-            return;
-        }
-
-        Ethernet ethReply = ARP.buildArpReply(targetIp.getIp4Address(),
-                                              dstMac,
-                                              ethRequest);
-
-        TrafficTreatment treatment = DefaultTrafficTreatment.builder()
-                .setOutput(pkt.receivedFrom().port())
-                .build();
-
-        packetService.emit(new DefaultOutboundPacket(
-                pkt.receivedFrom().deviceId(),
-                treatment,
-                ByteBuffer.wrap(ethReply.serialize())));
-    }
-
-    /**
-     * 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 = openstackService.ports()
-                .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/openstacknetworking/openstackswitching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackSecurityGroupRulePopulator.java b/apps/openstacknetworking/openstackswitching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackSecurityGroupRulePopulator.java
deleted file mode 100644
index dcc1c52..0000000
--- a/apps/openstacknetworking/openstackswitching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackSecurityGroupRulePopulator.java
+++ /dev/null
@@ -1,274 +0,0 @@
-/*
-* Copyright 2016-present Open Networking Laboratory
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-*     http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
-
-package org.onosproject.openstacknetworking.switching;
-
-import org.onlab.packet.Ethernet;
-import org.onlab.packet.IPv4;
-import org.onlab.packet.Ip4Address;
-import org.onlab.packet.Ip4Prefix;
-import org.onlab.packet.IpAddress;
-import org.onlab.packet.IpPrefix;
-import org.onlab.packet.TpPort;
-import org.onosproject.core.ApplicationId;
-import org.onosproject.net.DeviceId;
-import org.onosproject.net.flow.DefaultTrafficSelector;
-import org.onosproject.net.flow.DefaultTrafficTreatment;
-import org.onosproject.net.flow.TrafficSelector;
-import org.onosproject.net.flow.TrafficTreatment;
-import org.onosproject.net.flowobjective.DefaultForwardingObjective;
-import org.onosproject.net.flowobjective.FlowObjectiveService;
-import org.onosproject.net.flowobjective.ForwardingObjective;
-import org.onosproject.openstackinterface.OpenstackInterfaceService;
-import org.onosproject.openstackinterface.OpenstackSecurityGroup;
-import org.onosproject.openstackinterface.OpenstackSecurityGroupRule;
-import org.onosproject.openstacknetworking.OpenstackPortInfo;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.util.Map;
-
-/**
- * Populates flows rules for Security Groups of VMs.
- *
- */
-public class OpenstackSecurityGroupRulePopulator {
-
-    private static Logger log = LoggerFactory
-            .getLogger(OpenstackSecurityGroupRulePopulator.class);
-
-    private OpenstackInterfaceService openstackService;
-    private FlowObjectiveService flowObjectiveService;
-
-    private ApplicationId appId;
-
-    private static final String PROTO_ICMP = "ICMP";
-    private static final String PROTO_TCP = "TCP";
-    private static final String PROTO_UDP = "UDP";
-
-    private static final String ETHTYPE_IPV4 = "IPV4";
-
-    private static final IpPrefix IP_PREFIX_ANY = Ip4Prefix.valueOf("0.0.0.0/0");
-
-    private static final int ACL_RULE_PRIORITY = 30000;
-
-    /**
-     * Constructor.
-     *
-     * @param appId application ID
-     * @param openstackService OpenStack interface service
-     * @param flowObjectiveService flow objective service
-     */
-    public OpenstackSecurityGroupRulePopulator(ApplicationId appId, OpenstackInterfaceService openstackService,
-                                               FlowObjectiveService flowObjectiveService) {
-        this.appId = appId;
-        this.openstackService = openstackService;
-        this.flowObjectiveService = flowObjectiveService;
-    }
-
-    /**
-     * Populates flow rules for security groups.
-     *
-     * @param id Device ID
-     * @param sgId Security Group ID
-     * @param vmIp VM IP address
-     * @param portInfoMap Port Info map
-     */
-    public void populateSecurityGroupRules(DeviceId id, String sgId, Ip4Address vmIp,
-                                           Map<String, OpenstackPortInfo> portInfoMap) {
-        OpenstackSecurityGroup securityGroup = openstackService.securityGroup(sgId);
-        if (securityGroup != null) {
-            securityGroup.rules().stream().forEach(sgRule -> {
-                if (sgRule.remoteGroupId() != null && !sgRule.remoteGroupId().equals("null")) {
-                    openstackService.ports().stream()
-                        .filter(port -> port.securityGroups().contains(sgRule.remoteGroupId()))
-                        .flatMap(port -> port.fixedIps().values().stream())
-                        .forEach(remoteIp -> setSecurityGroupRule(id, sgRule,
-                                vmIp, IpPrefix.valueOf((IpAddress) remoteIp, 32)));
-                } else {
-                    setSecurityGroupRule(id, sgRule, vmIp, sgRule.remoteIpPrefix());
-                }
-            });
-
-            openstackService.ports().stream().forEach(osPort ->
-                osPort.securityGroups().stream().forEach(remoteVmSgId -> {
-                    OpenstackSecurityGroup remoteVmSg = openstackService.securityGroup(remoteVmSgId);
-                    remoteVmSg.rules().stream()
-                        .filter(remoteVmSgRule -> remoteVmSgRule.remoteGroupId().equals(sgId))
-                        .forEach(remoteVmSgRule -> {
-                            Ip4Address remoteVmIp =
-                                    (Ip4Address) osPort.fixedIps().values().stream().findAny().orElse(null);
-                            OpenstackPortInfo osPortInfo = portInfoMap.get(OpenstackSwitchingManager.PORTNAME_PREFIX_VM
-                                    + osPort.id().substring(0, 11));
-                            if (osPortInfo != null && remoteVmIp != null) {
-                                setSecurityGroupRule(osPortInfo.deviceId(), remoteVmSgRule, remoteVmIp,
-                                        IpPrefix.valueOf(vmIp, 32));
-                            }
-                        });
-                }));
-        }
-    }
-
-    /**
-     * Removes flow rules for security groups.
-     *
-     * @param id Device ID
-     * @param sgId Security Group ID to remove
-     * @param vmIp VM IP address
-     * @param portInfoMap port info map
-     * @param securityGroupMap security group info map
-     */
-    public void removeSecurityGroupRules(DeviceId id, String sgId, Ip4Address vmIp,
-                                         Map<String, OpenstackPortInfo> portInfoMap,
-                                         Map<String, OpenstackSecurityGroup> securityGroupMap) {
-        OpenstackSecurityGroup securityGroup = securityGroupMap.get(sgId);
-        if (securityGroup != null) {
-            securityGroup.rules().stream().forEach(sgRule -> {
-                if (sgRule.remoteGroupId() != null && !sgRule.remoteGroupId().equals("null")) {
-                    portInfoMap.values().stream()
-                            .filter(portInfo -> portInfo.securityGroups().contains(sgRule.remoteGroupId()))
-                            .map(OpenstackPortInfo::ip)
-                            .forEach(remoteIp -> {
-                                removeSecurityGroupRule(id, sgRule, vmIp, IpPrefix.valueOf(remoteIp, 32));
-                            });
-                } else {
-                    removeSecurityGroupRule(id, sgRule, vmIp, sgRule.remoteIpPrefix());
-                }
-            });
-
-            portInfoMap.values().stream()
-                .forEach(portInfo -> portInfo.securityGroups()
-                    .forEach(remoteVmSgId -> {
-                        OpenstackSecurityGroup remoteVmSg = securityGroupMap.get(remoteVmSgId);
-                        remoteVmSg.rules().stream()
-                            .filter(remoteVmSgRule -> remoteVmSgRule.remoteGroupId().equals(sgId))
-                            .forEach(remoteVmSgRule -> removeSecurityGroupRule(portInfo.deviceId(),
-                                    remoteVmSgRule, portInfo.ip(), IpPrefix.valueOf(vmIp, 32)));
-                    }));
-        }
-    }
-
-    private void setSecurityGroupRule(DeviceId id, OpenstackSecurityGroupRule sgRule,
-                                      Ip4Address vmIp, IpPrefix remoteIp) {
-        ForwardingObjective.Builder foBuilder = buildFlowObjective(id, sgRule, vmIp, remoteIp);
-        if (foBuilder != null) {
-            flowObjectiveService.forward(id, foBuilder.add());
-        }
-    }
-
-    private void removeSecurityGroupRule(DeviceId id, OpenstackSecurityGroupRule sgRule,
-                                      Ip4Address vmIp, IpPrefix remoteIp) {
-        ForwardingObjective.Builder foBuilder = buildFlowObjective(id, sgRule, vmIp, remoteIp);
-        if (foBuilder != null) {
-            flowObjectiveService.forward(id, foBuilder.remove());
-        }
-    }
-
-    ForwardingObjective.Builder buildFlowObjective(DeviceId id, OpenstackSecurityGroupRule sgRule,
-                                           Ip4Address vmIp, IpPrefix remoteIp) {
-        if (remoteIp != null && remoteIp.equals(IpPrefix.valueOf(vmIp, 32))) {
-            return null;
-        }
-        TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
-        TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
-
-        buildMatchs(sBuilder, sgRule, vmIp, remoteIp);
-
-        ForwardingObjective.Builder foBuilder = DefaultForwardingObjective.builder()
-                .withSelector(sBuilder.build())
-                .withTreatment(tBuilder.build())
-                .withPriority(ACL_RULE_PRIORITY)
-                .withFlag(ForwardingObjective.Flag.SPECIFIC)
-                .fromApp(appId);
-
-        return foBuilder;
-    }
-
-    private void buildMatchs(TrafficSelector.Builder sBuilder, OpenstackSecurityGroupRule sgRule,
-                             Ip4Address vmIp, IpPrefix remoteIp) {
-        buildMatchEthType(sBuilder, sgRule.ethertype());
-        buildMatchDirection(sBuilder, sgRule.direction(), vmIp);
-        buildMatchProto(sBuilder, sgRule.protocol());
-        buildMatchPort(sBuilder, sgRule.protocol(), sgRule.direction(), sgRule.portRangeMax(), sgRule.portRangeMin());
-        buildMatchRemoteIp(sBuilder, remoteIp, sgRule.direction());
-    }
-
-    private void buildMatchDirection(TrafficSelector.Builder sBuilder,
-                                     OpenstackSecurityGroupRule.Direction direction, Ip4Address vmIp) {
-        if (direction.equals(OpenstackSecurityGroupRule.Direction.EGRESS)) {
-            sBuilder.matchIPSrc(IpPrefix.valueOf(vmIp, 32));
-        } else {
-            sBuilder.matchIPDst(IpPrefix.valueOf(vmIp, 32));
-        }
-    }
-
-    private void buildMatchEthType(TrafficSelector.Builder sBuilder, String ethertype) {
-        // Either IpSrc or IpDst (or both) is set by default, and we need to set EthType as IPv4.
-        sBuilder.matchEthType(Ethernet.TYPE_IPV4);
-        if (ethertype != null && ethertype != "null" &&
-                !ethertype.toUpperCase().equals(ETHTYPE_IPV4)) {
-            log.error("EthType {} is not supported yet in Security Group", ethertype);
-        }
-    }
-
-    private void buildMatchRemoteIp(TrafficSelector.Builder sBuilder, IpPrefix remoteIpPrefix,
-                                                       OpenstackSecurityGroupRule.Direction direction) {
-        if (remoteIpPrefix != null && !remoteIpPrefix.getIp4Prefix().equals(IP_PREFIX_ANY)) {
-            if (direction.equals(OpenstackSecurityGroupRule.Direction.EGRESS)) {
-                sBuilder.matchIPDst(remoteIpPrefix);
-            } else {
-                sBuilder.matchIPSrc(remoteIpPrefix);
-            }
-        }
-    }
-
-    private void buildMatchProto(TrafficSelector.Builder sBuilder, String protocol) {
-        if (protocol != null) {
-            switch (protocol.toUpperCase()) {
-                case PROTO_ICMP:
-                    sBuilder.matchIPProtocol(IPv4.PROTOCOL_ICMP);
-                    break;
-                case PROTO_TCP:
-                    sBuilder.matchIPProtocol(IPv4.PROTOCOL_TCP);
-                    break;
-                case PROTO_UDP:
-                    sBuilder.matchIPProtocol(IPv4.PROTOCOL_UDP);
-                    break;
-                default:
-            }
-        }
-    }
-
-    private void buildMatchPort(TrafficSelector.Builder sBuilder, String protocol,
-                                                   OpenstackSecurityGroupRule.Direction direction,
-                                                   int portMin, int portMax) {
-        if (portMin > 0 && portMax > 0 && portMin == portMax) {
-            if (protocol.toUpperCase().equals(PROTO_TCP)) {
-                if (direction.equals(OpenstackSecurityGroupRule.Direction.EGRESS)) {
-                    sBuilder.matchTcpDst(TpPort.tpPort(portMax));
-                } else {
-                    sBuilder.matchTcpSrc(TpPort.tpPort(portMax));
-                }
-            } else if (protocol.toUpperCase().equals(PROTO_UDP)) {
-                if (direction.equals(OpenstackSecurityGroupRule.Direction.EGRESS)) {
-                    sBuilder.matchUdpDst(TpPort.tpPort(portMax));
-                } else {
-                    sBuilder.matchUdpSrc(TpPort.tpPort(portMax));
-                }
-            }
-        }
-    }
-}
diff --git a/apps/openstacknetworking/openstackswitching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackSwitchingManager.java b/apps/openstacknetworking/openstackswitching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackSwitchingManager.java
deleted file mode 100644
index 7f543a0..0000000
--- a/apps/openstacknetworking/openstackswitching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackSwitchingManager.java
+++ /dev/null
@@ -1,535 +0,0 @@
-/*
- * Copyright 2016-present Open Networking Laboratory
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.onosproject.openstacknetworking.switching;
-
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Maps;
-import org.apache.felix.scr.annotations.Activate;
-import org.apache.felix.scr.annotations.Component;
-import org.apache.felix.scr.annotations.Deactivate;
-import org.apache.felix.scr.annotations.Reference;
-import org.apache.felix.scr.annotations.ReferenceCardinality;
-import org.apache.felix.scr.annotations.Service;
-import org.onlab.packet.Ethernet;
-import org.onlab.packet.Ip4Address;
-import org.onlab.packet.IpPrefix;
-import org.onosproject.core.ApplicationId;
-import org.onosproject.core.CoreService;
-import org.onosproject.dhcp.DhcpService;
-import org.onosproject.dhcp.IpAssignment;
-import org.onosproject.event.AbstractEvent;
-import org.onosproject.net.Device;
-import org.onosproject.net.DeviceId;
-import org.onosproject.net.Port;
-import org.onosproject.net.config.ConfigFactory;
-import org.onosproject.net.config.NetworkConfigEvent;
-import org.onosproject.net.config.NetworkConfigListener;
-import org.onosproject.net.config.NetworkConfigRegistry;
-import org.onosproject.net.config.NetworkConfigService;
-import org.onosproject.net.device.DeviceEvent;
-import org.onosproject.net.device.DeviceListener;
-import org.onosproject.net.device.DeviceService;
-import org.onosproject.net.driver.DriverService;
-import org.onosproject.net.flowobjective.FlowObjectiveService;
-import org.onosproject.net.host.HostEvent;
-import org.onosproject.net.host.HostListener;
-import org.onosproject.net.host.HostService;
-import org.onosproject.net.packet.InboundPacket;
-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.OpenstackNetwork;
-import org.onosproject.openstackinterface.OpenstackPort;
-import org.onosproject.openstackinterface.OpenstackSecurityGroup;
-import org.onosproject.openstackinterface.OpenstackSubnet;
-import org.onosproject.openstacknetworking.OpenstackPortInfo;
-import org.onosproject.openstacknetworking.OpenstackSubjectFactories;
-import org.onosproject.openstacknetworking.OpenstackNetworkingConfig;
-import org.onosproject.openstacknetworking.OpenstackSwitchingService;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.util.Date;
-import java.util.Collection;
-import java.util.Map;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-
-import static org.onlab.util.Tools.groupedThreads;
-import static org.onosproject.dhcp.IpAssignment.AssignmentStatus.Option_RangeNotEnforced;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkNotNull;
-
-@Service
-@Component(immediate = true)
-/**
- * Populates forwarding rules for VMs created by Openstack.
- */
-public class OpenstackSwitchingManager implements OpenstackSwitchingService {
-
-    private final Logger log = LoggerFactory.getLogger(getClass());
-
-    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected CoreService coreService;
-
-    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected PacketService packetService;
-
-    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected DeviceService deviceService;
-
-    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected HostService hostService;
-
-    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected FlowObjectiveService flowObjectiveService;
-
-    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected DhcpService dhcpService;
-
-    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected DriverService driverService;
-
-    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected NetworkConfigRegistry networkConfig;
-
-    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected OpenstackInterfaceService openstackService;
-
-    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected NetworkConfigService configService;
-
-    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected NetworkConfigRegistry configRegistry;
-
-    public static final String PORTNAME_PREFIX_VM = "tap";
-    public static final String PORTNAME_PREFIX_ROUTER = "qr-";
-    public static final String PORTNAME_PREFIX_TUNNEL = "vxlan";
-    public static final String PORTNAME = "portName";
-    private static final String ROUTER_INTERFACE = "network:router_interface";
-    public static final String DEVICE_OWNER_GATEWAY = "network:router_gateway";
-    public static final Ip4Address DNS_SERVER_IP = Ip4Address.valueOf("8.8.8.8");
-    private static final String FORWARD_SLASH = "/";
-    private static final int DHCP_INFINITE_LEASE = -1;
-    public static final String SONA_DRIVER_NAME = "sona";
-
-
-    private ApplicationId appId;
-
-    private OpenstackArpHandler arpHandler;
-    private OpenstackSecurityGroupRulePopulator sgRulePopulator;
-
-    private ExecutorService deviceEventExecutorService =
-            Executors.newSingleThreadExecutor(groupedThreads("onos/openstackswitching", "device-event"));
-
-    private ExecutorService configEventExecutorService =
-            Executors.newSingleThreadExecutor(groupedThreads("onos/openstackswitching", "config-event"));
-
-    private InternalPacketProcessor internalPacketProcessor = new InternalPacketProcessor();
-    private InternalDeviceListener internalDeviceListener = new InternalDeviceListener();
-    private InternalHostListener internalHostListener = new InternalHostListener();
-
-    private final Map<String, OpenstackPortInfo> openstackPortInfoMap = Maps.newHashMap();
-    private Map<String, OpenstackSecurityGroup> securityGroupMap = Maps.newConcurrentMap();
-
-    private final ConfigFactory configFactory =
-            new ConfigFactory(OpenstackSubjectFactories.USER_DEFINED_SUBJECT_FACTORY, OpenstackNetworkingConfig.class,
-                    "config") {
-                @Override
-                public OpenstackNetworkingConfig createConfig() {
-                    return new OpenstackNetworkingConfig();
-                }
-            };
-    private final NetworkConfigListener configListener = new InternalConfigListener();
-
-    private OpenstackNetworkingConfig config;
-
-    @Activate
-    protected void activate() {
-        appId = coreService
-                .registerApplication("org.onosproject.openstackswitching");
-
-        packetService.addProcessor(internalPacketProcessor, PacketProcessor.director(1));
-        deviceService.addListener(internalDeviceListener);
-        hostService.addListener(internalHostListener);
-        configRegistry.registerConfigFactory(configFactory);
-        configService.addListener(configListener);
-
-        arpHandler = new OpenstackArpHandler(openstackService, packetService, hostService);
-        sgRulePopulator = new OpenstackSecurityGroupRulePopulator(appId, openstackService, flowObjectiveService);
-
-        networkConfig.registerConfigFactory(configFactory);
-        networkConfig.addListener(configListener);
-
-        readConfiguration();
-
-        log.info("Started");
-    }
-
-    @Deactivate
-    protected void deactivate() {
-        packetService.removeProcessor(internalPacketProcessor);
-        deviceService.removeListener(internalDeviceListener);
-
-        deviceEventExecutorService.shutdown();
-        configEventExecutorService.shutdown();
-        hostService.removeListener(internalHostListener);
-        configService.removeListener(configListener);
-        configRegistry.unregisterConfigFactory(configFactory);
-
-        log.info("Stopped");
-    }
-
-    @Override
-    public void createPorts(OpenstackPort openstackPort) {
-
-        if (!openstackPort.deviceOwner().equals(ROUTER_INTERFACE)
-                && !openstackPort.deviceOwner().equals(DEVICE_OWNER_GATEWAY)
-                && !openstackPort.fixedIps().isEmpty()) {
-                registerDhcpInfo(openstackPort);
-        }
-    }
-
-    @Override
-    public void removePort(String uuid) {
-        // When VMs are remvoed, the flow rules for the VMs are removed using ONOS port update event.
-        // But, when router is removed, no ONOS port event occurs and we need to use Neutron port event.
-        // Here we should not touch any rules for VMs.
-        log.debug("port {} was removed", uuid);
-
-        String routerPortName = PORTNAME_PREFIX_ROUTER + uuid.substring(0, 11);
-        OpenstackPortInfo routerPortInfo = openstackPortInfoMap.get(routerPortName);
-        if (routerPortInfo != null) {
-            dhcpService.removeStaticMapping(routerPortInfo.mac());
-            deviceService.getPorts(routerPortInfo.deviceId()).forEach(port -> {
-                String pName = port.annotations().value(PORTNAME);
-                if (pName.equals(routerPortName)) {
-                    OpenstackSwitchingRulePopulator rulePopulator =
-                            new OpenstackSwitchingRulePopulator(appId, flowObjectiveService,
-                                    deviceService, openstackService, driverService, config);
-
-                    rulePopulator.removeSwitchingRules(port, openstackPortInfoMap);
-                    openstackPortInfoMap.remove(routerPortName);
-                    return;
-                }
-            });
-        }
-    }
-
-    @Override
-    public void updatePort(OpenstackPort openstackPort) {
-        if (openstackPort.status().equals(OpenstackPort.PortStatus.ACTIVE)) {
-            String portName = PORTNAME_PREFIX_VM + openstackPort.id().substring(0, 11);
-            OpenstackPortInfo osPortInfo = openstackPortInfoMap.get(portName);
-            if (osPortInfo != null) {
-                // Remove all security group rules based on the ones stored in security group map.
-                osPortInfo.securityGroups().stream().forEach(
-                        sgId -> sgRulePopulator.removeSecurityGroupRules(osPortInfo.deviceId(), sgId,
-                                osPortInfo.ip(), openstackPortInfoMap, securityGroupMap));
-                // Add all security group rules based on the updated security group.
-                openstackPort.securityGroups().stream().forEach(
-                        sgId -> sgRulePopulator.populateSecurityGroupRules(osPortInfo.deviceId(), sgId,
-                                osPortInfo.ip(), openstackPortInfoMap));
-                updatePortMap(osPortInfo.deviceId(), portName, openstackService.networks(),
-                        openstackService.subnets(), openstackPort);
-            }
-        }
-    }
-
-    @Override
-    public void createNetwork(OpenstackNetwork openstackNetwork) {
-        //TODO
-    }
-
-    @Override
-    public void createSubnet(OpenstackSubnet openstackSubnet) {
-        //TODO
-    }
-
-    @Override
-    public Map<String, OpenstackPortInfo> openstackPortInfo() {
-        return ImmutableMap.copyOf(this.openstackPortInfoMap);
-    }
-
-    private void processPortUpdated(Device device, Port port) {
-        String portName = port.annotations().value(PORTNAME);
-        synchronized (openstackPortInfoMap) {
-            if (portName.startsWith(PORTNAME_PREFIX_VM)) {
-                if (port.isEnabled()) {
-                    OpenstackSwitchingRulePopulator rulePopulator =
-                            new OpenstackSwitchingRulePopulator(appId, flowObjectiveService,
-                                    deviceService, openstackService, driverService, config);
-
-                    rulePopulator.populateSwitchingRules(device, port);
-                    OpenstackPort openstackPort = rulePopulator.openstackPort(port);
-                    Ip4Address vmIp = (Ip4Address) openstackPort.fixedIps().values().stream()
-                            .findAny().orElseGet(null);
-                    openstackPort.securityGroups().stream().forEach(
-                            sgId -> sgRulePopulator.populateSecurityGroupRules(device.id(), sgId, vmIp,
-                                    openstackPortInfoMap));
-                    updatePortMap(device.id(), port.annotations().value(PORTNAME),
-                            openstackService.networks(), openstackService.subnets(), openstackPort);
-
-                    //In case portupdate event is driven by vm shutoff from openstack
-                } else if (!port.isEnabled() && openstackPortInfoMap.containsKey(portName)) {
-                    log.debug("Flowrules according to the port {} were removed", port.number());
-                    OpenstackSwitchingRulePopulator rulePopulator =
-                            new OpenstackSwitchingRulePopulator(appId, flowObjectiveService,
-                                    deviceService, openstackService, driverService, config);
-                    rulePopulator.removeSwitchingRules(port, openstackPortInfoMap);
-                    openstackPortInfoMap.get(portName).securityGroups().stream().forEach(
-                            sgId -> sgRulePopulator.removeSecurityGroupRules(device.id(), sgId,
-                                    openstackPortInfoMap.get(portName).ip(), openstackPortInfoMap, securityGroupMap));
-                    dhcpService.removeStaticMapping(openstackPortInfoMap.get(port.annotations().value(PORTNAME)).mac());
-                    openstackPortInfoMap.remove(port.annotations().value(PORTNAME));
-                }
-            }
-        }
-    }
-
-    private void processPortRemoved(Port port) {
-        log.debug("port {} is removed", port.toString());
-    }
-
-    private void initializeFlowRules() {
-        OpenstackSwitchingRulePopulator rulePopulator =
-                new OpenstackSwitchingRulePopulator(appId, flowObjectiveService,
-                        deviceService, openstackService, driverService, config);
-
-        Collection<OpenstackNetwork> networks = openstackService.networks();
-        Collection<OpenstackSubnet> subnets = openstackService.subnets();
-
-        deviceService.getDevices().forEach(device -> {
-                log.debug("device {} num of ports {} ", device.id(),
-                        deviceService.getPorts(device.id()).size());
-                deviceService.getPorts(device.id()).stream()
-                        .filter(port -> port.annotations().value(PORTNAME).startsWith(PORTNAME_PREFIX_VM) ||
-                                port.annotations().value(PORTNAME).startsWith(PORTNAME_PREFIX_ROUTER))
-                        .forEach(vmPort -> {
-                                OpenstackPort osPort = rulePopulator.openstackPort(vmPort);
-                                if (osPort != null && !osPort.deviceOwner().equals(DEVICE_OWNER_GATEWAY)) {
-                                    rulePopulator.populateSwitchingRules(device, vmPort);
-                                    Ip4Address vmIp = (Ip4Address) osPort.fixedIps().values().stream()
-                                            .findAny().orElseGet(null);
-                                    osPort.securityGroups().stream().forEach(
-                                            sgId -> sgRulePopulator.populateSecurityGroupRules(device.id(),
-                                                    sgId, vmIp, openstackPortInfoMap));
-                                    updatePortMap(device.id(), vmPort.annotations().value(PORTNAME), networks,
-                                            subnets, osPort);
-                                    registerDhcpInfo(osPort);
-                                } else {
-                                    log.warn("No openstackPort information for port {}", vmPort);
-                                }
-                            }
-                        );
-                }
-        );
-    }
-
-    private void updatePortMap(DeviceId deviceId, String portName, Collection<OpenstackNetwork> networks,
-                               Collection<OpenstackSubnet> subnets, OpenstackPort openstackPort) {
-        long vni;
-        OpenstackNetwork openstackNetwork = networks.stream()
-                .filter(n -> n.id().equals(openstackPort.networkId()))
-                .findAny().orElse(null);
-        if (openstackNetwork != null) {
-            vni = Long.parseLong(openstackNetwork.segmentId());
-        } else {
-            log.debug("updatePortMap failed because there's no OpenstackNetwork matches {}", openstackPort.networkId());
-            return;
-        }
-
-
-        OpenstackSubnet openstackSubnet = subnets.stream()
-                .filter(n -> n.networkId().equals(openstackPort.networkId()))
-                .findFirst().get();
-
-        Ip4Address gatewayIPAddress = Ip4Address.valueOf(openstackSubnet.gatewayIp());
-
-        OpenstackPortInfo.Builder portBuilder = OpenstackPortInfo.builder()
-                .setDeviceId(deviceId)
-                .setHostIp((Ip4Address) openstackPort.fixedIps().values().stream().findFirst().orElse(null))
-                .setHostMac(openstackPort.macAddress())
-                .setVni(vni)
-                .setGatewayIP(gatewayIPAddress)
-                .setNetworkId(openstackPort.networkId())
-                .setSecurityGroups(openstackPort.securityGroups());
-
-        openstackPortInfoMap.put(portName, portBuilder.build());
-
-        openstackPort.securityGroups().stream().forEach(sgId -> {
-            if (!securityGroupMap.containsKey(sgId)) {
-                securityGroupMap.put(sgId, openstackService.securityGroup(sgId));
-            }
-        });
-    }
-
-    private void registerDhcpInfo(OpenstackPort openstackPort) {
-        checkNotNull(openstackPort);
-        checkArgument(!openstackPort.fixedIps().isEmpty());
-
-        OpenstackSubnet openstackSubnet = openstackService.subnets().stream()
-                .filter(n -> n.networkId().equals(openstackPort.networkId()))
-                .findFirst().orElse(null);
-        if (openstackSubnet == null) {
-            log.warn("Failed to find subnet for {}", openstackPort);
-            return;
-        }
-
-        Ip4Address ipAddress = openstackPort.fixedIps().values().stream().findFirst().get();
-        IpPrefix subnetPrefix = IpPrefix.valueOf(openstackSubnet.cidr());
-        Ip4Address broadcast = Ip4Address.makeMaskedAddress(
-                ipAddress,
-                subnetPrefix.prefixLength());
-
-        // TODO: supports multiple DNS servers
-        Ip4Address domainServer = openstackSubnet.dnsNameservers().isEmpty() ?
-                DNS_SERVER_IP : openstackSubnet.dnsNameservers().get(0);
-
-        IpAssignment ipAssignment = IpAssignment.builder()
-                .ipAddress(ipAddress)
-                .leasePeriod(DHCP_INFINITE_LEASE)
-                .timestamp(new Date())
-                .subnetMask(Ip4Address.makeMaskPrefix(subnetPrefix.prefixLength()))
-                .broadcast(broadcast)
-                .domainServer(domainServer)
-                .assignmentStatus(Option_RangeNotEnforced)
-                .routerAddress(Ip4Address.valueOf(openstackSubnet.gatewayIp()))
-                .build();
-
-        dhcpService.setStaticMapping(openstackPort.macAddress(), ipAssignment);
-    }
-
-    private class InternalPacketProcessor implements PacketProcessor {
-
-        @Override
-        public void process(PacketContext context) {
-            // FIXME: use GatewayNode list to check if the ARP packet is from GatewayNode's
-            if (context.isHandled()) {
-                return;
-            } else if (!SONA_DRIVER_NAME.equals(driverService
-                    .getDriver(context.inPacket().receivedFrom().deviceId()).name())) {
-                return;
-            }
-
-            InboundPacket pkt = context.inPacket();
-            Ethernet ethernet = pkt.parsed();
-
-            if (ethernet != null && ethernet.getEtherType() == Ethernet.TYPE_ARP) {
-                arpHandler.processPacketIn(pkt, openstackPortInfoMap.values());
-            }
-        }
-    }
-
-    private class InternalHostListener implements HostListener {
-
-        @Override
-        public void event(HostEvent hostEvent) {
-            deviceEventExecutorService.execute(new InternalEventHandler(hostEvent));
-        }
-    }
-
-    private class InternalDeviceListener implements DeviceListener {
-
-        @Override
-        public void event(DeviceEvent deviceEvent) {
-            deviceEventExecutorService.execute(new InternalEventHandler(deviceEvent));
-        }
-    }
-
-    private class InternalEventHandler implements Runnable {
-
-        volatile AbstractEvent event;
-
-        InternalEventHandler(AbstractEvent event) {
-            this.event = event;
-        }
-
-        @Override
-        public void run() {
-
-            if (event instanceof  DeviceEvent) {
-                DeviceEvent deviceEvent = (DeviceEvent) event;
-
-                switch (deviceEvent.type()) {
-                    case DEVICE_ADDED:
-                        log.debug("device {} is added", deviceEvent.subject().id());
-                        break;
-                    case DEVICE_AVAILABILITY_CHANGED:
-                        Device device = deviceEvent.subject();
-                        if (deviceService.isAvailable(device.id())) {
-                            log.debug("device {} is added", device.id());
-                        }
-                        break;
-                    case PORT_ADDED:
-                        processPortUpdated(deviceEvent.subject(), deviceEvent.port());
-                        break;
-                    case PORT_UPDATED:
-                        processPortUpdated(deviceEvent.subject(), deviceEvent.port());
-                        break;
-                    case PORT_REMOVED:
-                        processPortRemoved(deviceEvent.port());
-                        break;
-                    default:
-                        log.debug("Unsupported deviceEvent type {}", deviceEvent.type().toString());
-                        break;
-                }
-            } else if (event instanceof HostEvent) {
-                HostEvent hostEvent = (HostEvent) event;
-
-                switch (hostEvent.type()) {
-                    case HOST_REMOVED:
-                        log.debug("host {} was removed", hostEvent.subject().toString());
-                        break;
-                    default:
-                        log.debug("Unsupported hostEvent type {}", hostEvent.type().toString());
-                        break;
-                }
-            }
-        }
-    }
-
-    private void readConfiguration() {
-        config = configService.getConfig("openstacknetworking", OpenstackNetworkingConfig.class);
-        if (config == null) {
-            log.error("No configuration found");
-            return;
-        }
-
-        arpHandler = new OpenstackArpHandler(openstackService, packetService, hostService);
-        sgRulePopulator = new OpenstackSecurityGroupRulePopulator(appId, openstackService, flowObjectiveService);
-
-        initializeFlowRules();
-    }
-
-    private class InternalConfigListener implements NetworkConfigListener {
-
-        @Override
-        public void event(NetworkConfigEvent event) {
-            if (!event.configClass().equals(OpenstackNetworkingConfig.class)) {
-                return;
-            }
-
-            if (event.type().equals(NetworkConfigEvent.Type.CONFIG_ADDED) ||
-                    event.type().equals(NetworkConfigEvent.Type.CONFIG_UPDATED)) {
-                configEventExecutorService.execute(OpenstackSwitchingManager.this::readConfiguration);
-
-            }
-        }
-    }
-}
diff --git a/apps/openstacknetworking/openstackswitching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackSwitchingRulePopulator.java b/apps/openstacknetworking/openstackswitching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackSwitchingRulePopulator.java
deleted file mode 100644
index 5f072bd..0000000
--- a/apps/openstacknetworking/openstackswitching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackSwitchingRulePopulator.java
+++ /dev/null
@@ -1,502 +0,0 @@
-/*
-* Copyright 2016-present Open Networking Laboratory
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-*     http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
-
-package org.onosproject.openstacknetworking.switching;
-
-import org.onlab.packet.Ethernet;
-import org.onlab.packet.Ip4Address;
-import org.onosproject.core.ApplicationId;
-import org.onosproject.net.Device;
-import org.onosproject.net.DeviceId;
-import org.onosproject.net.Port;
-import org.onosproject.net.PortNumber;
-import org.onosproject.net.behaviour.ExtensionTreatmentResolver;
-import org.onosproject.net.device.DeviceService;
-import org.onosproject.net.driver.DefaultDriverData;
-import org.onosproject.net.driver.DefaultDriverHandler;
-import org.onosproject.net.driver.Driver;
-import org.onosproject.net.driver.DriverHandler;
-import org.onosproject.net.driver.DriverService;
-import org.onosproject.net.flow.DefaultTrafficSelector;
-import org.onosproject.net.flow.DefaultTrafficTreatment;
-import org.onosproject.net.flow.TrafficSelector;
-import org.onosproject.net.flow.TrafficTreatment;
-import org.onosproject.net.flow.instructions.ExtensionTreatment;
-import org.onosproject.net.flow.instructions.ExtensionPropertyException;
-import org.onosproject.net.flow.instructions.ExtensionTreatmentType;
-import org.onosproject.net.flowobjective.DefaultForwardingObjective;
-import org.onosproject.net.flowobjective.FlowObjectiveService;
-import org.onosproject.net.flowobjective.ForwardingObjective;
-import org.onosproject.openstackinterface.OpenstackInterfaceService;
-import org.onosproject.openstackinterface.OpenstackNetwork;
-import org.onosproject.openstackinterface.OpenstackPort;
-import org.onosproject.openstacknetworking.OpenstackNetworkingConfig;
-import org.onosproject.openstacknetworking.OpenstackPortInfo;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.util.Collection;
-import java.util.Map;
-
-/**
- * Populates switching flow rules.
- */
-public class OpenstackSwitchingRulePopulator {
-
-    private static Logger log = LoggerFactory
-            .getLogger(OpenstackSwitchingRulePopulator.class);
-    private static final int SWITCHING_RULE_PRIORITY = 30000;
-    private static final int TUNNELTAG_RULE_PRIORITY = 30000;
-    private static final String PORT_NAME = "portName";
-    private static final String TUNNEL_DST = "tunnelDst";
-    private FlowObjectiveService flowObjectiveService;
-    private DriverService driverService;
-    private DeviceService deviceService;
-    private ApplicationId appId;
-    private OpenstackNetworkingConfig config;
-
-    private Collection<OpenstackNetwork> openstackNetworkList;
-    private Collection<OpenstackPort> openstackPortList;
-
-    /**
-     * Creates OpenstackSwitchingRulPopulator.
-     *
-     * @param appId application id
-     * @param flowObjectiveService FlowObjectiveService reference
-     * @param deviceService DeviceService reference
-     * @param openstackService openstack interface service
-     * @param driverService DriverService reference
-     * @param config OpenstackRoutingConfig
-     */
-    public OpenstackSwitchingRulePopulator(ApplicationId appId,
-                                           FlowObjectiveService flowObjectiveService,
-                                           DeviceService deviceService,
-                                           OpenstackInterfaceService openstackService,
-                                           DriverService driverService,
-                                           OpenstackNetworkingConfig config) {
-        this.flowObjectiveService = flowObjectiveService;
-        this.deviceService = deviceService;
-        this.driverService = driverService;
-        this.appId = appId;
-        this.config = config;
-
-        openstackNetworkList = openstackService.networks();
-        openstackPortList = openstackService.ports();
-    }
-
-
-    /**
-     * Populates flow rules for the VM created.
-     *
-     * @param device device to populate rules to
-     * @param port port for the VM created
-     */
-    public void populateSwitchingRules(Device device, Port port) {
-        populateFlowRulesForTunnelTag(device, port);
-        populateFlowRulesForTrafficToSameCnode(device, port);
-        populateFlowRulesForTrafficToDifferentCnode(device, port);
-    }
-
-    /**
-     * Populate the flow rules for tagging tunnelId according to which inport is came from.
-     *
-     * @param device device to put the rules
-     * @param port port info of the VM
-     */
-    private void populateFlowRulesForTunnelTag(Device device, Port port) {
-        Ip4Address vmIp = getFixedIpAddressForPort(port.annotations().value(PORT_NAME));
-        String portName = port.annotations().value(PORT_NAME);
-        String vni = getVniForPort(portName);
-
-        if (vmIp != null) {
-            setFlowRuleForTunnelTag(device.id(), port, vni);
-        }
-    }
-
-    private void setFlowRuleForTunnelTag(DeviceId deviceId, Port port, String vni) {
-
-        TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
-        TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
-
-        sBuilder.matchEthType(Ethernet.TYPE_IPV4)
-                .matchInPort(port.number());
-
-        tBuilder.setTunnelId(Long.parseLong(vni));
-
-        ForwardingObjective fo = DefaultForwardingObjective.builder()
-                .withSelector(sBuilder.build())
-                .withTreatment(tBuilder.build())
-                .withPriority(TUNNELTAG_RULE_PRIORITY)
-                .withFlag(ForwardingObjective.Flag.SPECIFIC)
-                .fromApp(appId)
-                .add();
-
-        flowObjectiveService.forward(deviceId, fo);
-    }
-
-    /**
-     * Populates the flow rules for traffic to VMs in the same Cnode as the sender.
-     *
-     * @param device device to put the rules
-     * @param port port info of the VM
-     */
-    private void populateFlowRulesForTrafficToSameCnode(Device device, Port port) {
-        Ip4Address vmIp = getFixedIpAddressForPort(port.annotations().value(PORT_NAME));
-        String portName = port.annotations().value(PORT_NAME);
-        String vni = getVniForPort(portName);
-
-        if (vmIp != null) {
-            setFlowRuleForVMsInSameCnode(vmIp, device.id(), port, vni);
-        }
-    }
-
-    /**
-     * Sets the flow rules for traffic between VMs in the same Cnode.
-     *
-     * @param ip4Address VM IP address
-     * @param id device ID to put rules
-     * @param port VM port
-     * @param vni VM VNI
-     */
-    private void setFlowRuleForVMsInSameCnode(Ip4Address ip4Address, DeviceId id,
-                                              Port port, String vni) {
-
-        //For L2 Switching Case
-        TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
-        TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
-
-        sBuilder.matchEthType(Ethernet.TYPE_IPV4)
-                .matchIPDst(ip4Address.toIpPrefix())
-                .matchTunnelId(Long.parseLong(vni));
-
-        tBuilder.setOutput(port.number());
-
-        ForwardingObjective fo = DefaultForwardingObjective.builder()
-                .withSelector(sBuilder.build())
-                .withTreatment(tBuilder.build())
-                .withPriority(SWITCHING_RULE_PRIORITY)
-                .withFlag(ForwardingObjective.Flag.SPECIFIC)
-                .fromApp(appId)
-                .add();
-
-        flowObjectiveService.forward(id, fo);
-    }
-
-    /**
-     * Populates the flow rules for traffic to VMs in different Cnode using
-     * Nicira extention.
-     *
-     * @param device device to put rules
-     * @param port port information of the VM
-     */
-    private void populateFlowRulesForTrafficToDifferentCnode(Device device, Port port) {
-        String portName = port.annotations().value(PORT_NAME);
-        Ip4Address fixedIp = getFixedIpAddressForPort(portName);
-        String vni = getVniForPort(portName);
-        Ip4Address hostDpIpAddress = config.nodes().get(device.id());
-
-        if (hostDpIpAddress == null) {
-            log.debug("There's no openstack node information for device id {}", device.id().toString());
-            return;
-        }
-
-        deviceService.getAvailableDevices().forEach(d -> {
-            if (!d.equals(device)) {
-                deviceService.getPorts(d.id()).forEach(p -> {
-                    String pName = p.annotations().value(PORT_NAME);
-                    if (!p.equals(port) && vni.equals(getVniForPort(pName))) {
-                        Ip4Address hostxDpIpAddress = config.nodes().get(d.id());
-
-                        Ip4Address fixedIpx = getFixedIpAddressForPort(pName);
-                        if (port.isEnabled()) {
-                            setVxLanFlowRule(vni, device.id(), hostxDpIpAddress, fixedIpx);
-                            setVxLanFlowRule(vni, d.id(), hostDpIpAddress, fixedIp);
-                        }
-                    }
-                });
-            }
-        });
-    }
-
-    /**
-     * Sets the flow rules between traffic from VMs in different Cnode.
-     *
-     * @param vni  VNI
-     * @param deviceId device ID
-     * @param hostIp host IP of the VM
-     * @param vmIp fixed IP of the VM
-     */
-    private void setVxLanFlowRule(String vni, DeviceId deviceId, Ip4Address hostIp,
-                                  Ip4Address vmIp) {
-        TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
-        TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
-
-        sBuilder.matchEthType(Ethernet.TYPE_IPV4)
-                .matchTunnelId(Long.parseLong(vni))
-                .matchIPDst(vmIp.toIpPrefix());
-        tBuilder.extension(buildNiciraExtenstion(deviceId, hostIp), deviceId)
-                .setOutput(getTunnelPort(deviceId));
-
-        ForwardingObjective fo = DefaultForwardingObjective.builder()
-                .withSelector(sBuilder.build())
-                .withTreatment(tBuilder.build())
-                .withPriority(SWITCHING_RULE_PRIORITY)
-                .withFlag(ForwardingObjective.Flag.SPECIFIC)
-                .fromApp(appId)
-                .add();
-
-        flowObjectiveService.forward(deviceId, fo);
-    }
-
-    /**
-     * Returns OpenstackPort object for the Port reference given.
-     *
-     * @param port Port object
-     * @return OpenstackPort reference, or null when not found
-     */
-    public OpenstackPort openstackPort(Port port) {
-        String uuid = port.annotations().value(PORT_NAME).substring(3);
-        return openstackPortList.stream().filter(p -> p.id().startsWith(uuid))
-                .findAny().orElse(null);
-    }
-
-    /**
-     * Remove flows rules for the removed VM.
-     *
-     * @param removedPort removedport info
-     * @param openstackPortInfoMap openstackPortInfoMap
-     */
-    public void removeSwitchingRules(Port removedPort, Map<String,
-            OpenstackPortInfo> openstackPortInfoMap) {
-        OpenstackPortInfo openstackPortInfo = openstackPortInfoMap
-                .get(removedPort.annotations().value(PORT_NAME));
-
-        DeviceId deviceId = openstackPortInfo.deviceId();
-        Ip4Address vmIp = openstackPortInfo.ip();
-        PortNumber portNumber = removedPort.number();
-        long vni = openstackPortInfo.vni();
-
-        removeFlowRuleForTunnelTag(deviceId, portNumber);
-        removeFlowRuleForVMsInSameCnode(deviceId, vmIp, vni);
-        removeFlowRuleForVMsInDiffrentCnode(removedPort, deviceId, vmIp, vni, openstackPortInfoMap);
-    }
-
-    /**
-     * Removes flow rules for tagging tunnelId.
-     *
-     * @param deviceId device id
-     * @param portNumber port number
-     */
-    private void removeFlowRuleForTunnelTag(DeviceId deviceId, PortNumber portNumber) {
-        TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
-        TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
-
-        sBuilder.matchEthType(Ethernet.TYPE_IPV4)
-                .matchInPort(portNumber);
-
-        ForwardingObjective fo = DefaultForwardingObjective.builder()
-                .withSelector(sBuilder.build())
-                .withTreatment(tBuilder.build())
-                .withPriority(TUNNELTAG_RULE_PRIORITY)
-                .withFlag(ForwardingObjective.Flag.SPECIFIC)
-                .fromApp(appId)
-                .remove();
-
-        flowObjectiveService.forward(deviceId, fo);
-    }
-
-    /**
-     * Removes the flow rules for traffic between VMs in the same Cnode.
-     *
-     * @param deviceId device id on which removed VM was run
-     * @param vmIp ip of the removed VM
-     * @param vni vni which removed VM was belonged
-     */
-    private void removeFlowRuleForVMsInSameCnode(DeviceId deviceId, Ip4Address vmIp, long vni) {
-        TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
-
-        sBuilder.matchEthType(Ethernet.TYPE_IPV4)
-                .matchIPDst(vmIp.toIpPrefix())
-                .matchTunnelId(vni);
-
-        ForwardingObjective fo = DefaultForwardingObjective.builder()
-                .withSelector(sBuilder.build())
-                .withTreatment(DefaultTrafficTreatment.builder().build())
-                .withFlag(ForwardingObjective.Flag.SPECIFIC)
-                .withPriority(SWITCHING_RULE_PRIORITY)
-                .fromApp(appId)
-                .remove();
-
-        flowObjectiveService.forward(deviceId, fo);
-    }
-
-    /**
-     * Removes the flow rules for traffic between VMs in the different Cnode.
-     *
-     * @param removedPort removedport info
-     * @param deviceId device id on which removed VM was run
-     * @param vmIp ip of the removed VM
-     * @param vni vni which removed VM was belonged
-     * @param openstackPortInfoMap openstackPortInfoMap
-     */
-    private void removeFlowRuleForVMsInDiffrentCnode(Port removedPort, DeviceId deviceId, Ip4Address vmIp,
-                                                     long vni, Map<String, OpenstackPortInfo> openstackPortInfoMap) {
-
-        final boolean anyPortRemainedInSameCnode
-                = checkIfAnyPortRemainedInSameCnode(removedPort, deviceId, vni, openstackPortInfoMap);
-
-        openstackPortInfoMap.forEach((port, portInfo) -> {
-            if (portInfo.vni() == vni && !portInfo.deviceId().equals(deviceId)) {
-                removeVxLanFlowRule(portInfo.deviceId(), vmIp, vni);
-                if (!anyPortRemainedInSameCnode) {
-                    removeVxLanFlowRule(deviceId, portInfo.ip(), vni);
-                }
-            }
-        });
-    }
-
-    /**
-     * Removes the flow rules between traffic from VMs in different Cnode.
-     *
-     * @param deviceId device id
-     * @param vmIp ip
-     * @param vni vni which removed VM was belonged
-     */
-    private void removeVxLanFlowRule(DeviceId deviceId, Ip4Address vmIp, long vni) {
-        TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
-
-        sBuilder.matchEthType(Ethernet.TYPE_IPV4)
-                .matchTunnelId(vni)
-                .matchIPDst(vmIp.toIpPrefix());
-
-        ForwardingObjective fo = DefaultForwardingObjective.builder()
-                .withSelector(sBuilder.build())
-                .withTreatment(DefaultTrafficTreatment.builder().build())
-                .withFlag(ForwardingObjective.Flag.SPECIFIC)
-                .withPriority(SWITCHING_RULE_PRIORITY)
-                .fromApp(appId)
-                .remove();
-
-        flowObjectiveService.forward(deviceId, fo);
-    }
-
-    /**
-     * Checks if there is any port remained with same vni at the device, on which the removed VM was run.
-     *
-     * @param removedPort removedport info
-     * @param deviceId device id on which removed VM was run
-     * @param vni vni which removed VM was belonged
-     * @param openstackPortInfoMap openstackPortInfoMap
-     * @return true if there is, false otherwise
-     */
-    private boolean checkIfAnyPortRemainedInSameCnode(Port removedPort, DeviceId deviceId, long vni,
-                                                    Map<String, OpenstackPortInfo> openstackPortInfoMap) {
-
-        for (Map.Entry<String, OpenstackPortInfo> entry : openstackPortInfoMap.entrySet()) {
-            if (!removedPort.annotations().value(PORT_NAME).equals(entry.getKey())) {
-                if (entry.getValue().vni() == vni && entry.getValue().deviceId().equals(deviceId)) {
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
-
-    /**
-     * Returns the VNI of the VM of the port.
-     *
-     * @param portName VM port
-     * @return VNI
-     */
-    private String getVniForPort(String portName) {
-        String uuid = portName.substring(3);
-        OpenstackPort port = openstackPortList.stream()
-                .filter(p -> p.id().startsWith(uuid))
-                .findAny().orElse(null);
-        if (port == null) {
-            log.debug("No port information for port {}", portName);
-            return null;
-        }
-
-        OpenstackNetwork network = openstackNetworkList.stream()
-                .filter(n -> n.id().equals(port.networkId()))
-                .findAny().orElse(null);
-        if (network == null) {
-            log.warn("No VNI information for network {}", port.networkId());
-            return null;
-        }
-
-        return network.segmentId();
-    }
-
-    /**
-     * Returns the Fixed IP address of the VM.
-     *
-     * @param portName VM port info
-     * @return IP address of the VM
-     */
-    private Ip4Address getFixedIpAddressForPort(String portName) {
-
-        String uuid = portName.substring(3);
-        OpenstackPort port = openstackPortList.stream()
-                .filter(p -> p.id().startsWith(uuid))
-                .findFirst().orElse(null);
-
-        if (port == null) {
-            log.error("There is no port information for port name {}", portName);
-            return null;
-        }
-
-        if (port.fixedIps().isEmpty()) {
-            log.error("There is no fixed IP info in the port information");
-            return null;
-        }
-
-        return (Ip4Address) port.fixedIps().values().toArray()[0];
-    }
-
-    private ExtensionTreatment buildNiciraExtenstion(DeviceId id, Ip4Address hostIp) {
-        Driver driver = driverService.getDriver(id);
-        DriverHandler driverHandler = new DefaultDriverHandler(new DefaultDriverData(driver, id));
-        ExtensionTreatmentResolver resolver = driverHandler.behaviour(ExtensionTreatmentResolver.class);
-
-        ExtensionTreatment extensionInstruction =
-                resolver.getExtensionInstruction(
-                        ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_SET_TUNNEL_DST.type());
-
-        try {
-            extensionInstruction.setPropertyValue(TUNNEL_DST, hostIp);
-        } catch (ExtensionPropertyException e) {
-            log.error("Error setting Nicira extension setting {}", e);
-        }
-
-        return  extensionInstruction;
-    }
-
-    private PortNumber getTunnelPort(DeviceId deviceId) {
-        Port port = deviceService.getPorts(deviceId).stream()
-                .filter(p -> p.annotations().value(PORT_NAME).equals(
-                        OpenstackSwitchingManager.PORTNAME_PREFIX_TUNNEL))
-                .findAny().orElse(null);
-
-        if (port == null) {
-            log.error("No TunnelPort was created.");
-            return null;
-        }
-        return port.number();
-    }
-
-}
diff --git a/apps/openstacknetworking/pom.xml b/apps/openstacknetworking/pom.xml
index f0a6530..d232273 100644
--- a/apps/openstacknetworking/pom.xml
+++ b/apps/openstacknetworking/pom.xml
@@ -29,11 +29,10 @@
     <packaging>pom</packaging>
 
     <modules>
-        <module>app</module>
-        <module>web</module>
         <module>api</module>
-        <module>openstackswitching</module>
-        <module>openstackrouting</module>
+        <module>web</module>
+        <module>switching</module>
+        <module>routing</module>
     </modules>
 
     <description>SONA Openstack Networking Application</description>
diff --git a/apps/openstacknetworking/openstackrouting/BUCK b/apps/openstacknetworking/routing/BUCK
similarity index 62%
rename from apps/openstacknetworking/openstackrouting/BUCK
rename to apps/openstacknetworking/routing/BUCK
index da4f812..fe48a99 100644
--- a/apps/openstacknetworking/openstackrouting/BUCK
+++ b/apps/openstacknetworking/routing/BUCK
@@ -4,12 +4,13 @@
     '//apps/openstackinterface/api:onos-apps-openstackinterface-api',
     '//apps/openstacknetworking/api:onos-apps-openstacknetworking-api',
     '//apps/scalablegateway:onos-apps-scalablegateway',
+    '//apps/openstacknode:onos-apps-openstacknode',
 ]
 
 BUNDLES = [
-    '//apps/openstackinterface/api:onos-apps-openstackinterface-api',
     '//apps/openstacknetworking/api:onos-apps-openstacknetworking-api',
-    '//apps/openstacknetworking/openstackrouting:onos-apps-openstacknetworking-openstackrouting',
+    '//apps/openstacknetworking/web:onos-apps-openstacknetworking-web',
+    '//apps/openstacknetworking/routing:onos-apps-openstacknetworking-routing',
 ]
 
 osgi_jar_with_tests (
@@ -17,9 +18,11 @@
 )
 
 onos_app (
+    app_name = 'org.onosproject.openstackrouting',
     title = 'OpenStack Routing App',
     category = 'Utility',
     url = 'http://onosproject.org',
     description = 'OpenStack routing application.',
     included_bundles = BUNDLES,
+    required_apps = [ 'org.onosproject.openstackinterface', 'org.onosproject.openstacknode', 'org.onosproject.scalablegateway' ]
 )
diff --git a/apps/openstacknetworking/app/features.xml b/apps/openstacknetworking/routing/features.xml
similarity index 92%
copy from apps/openstacknetworking/app/features.xml
copy to apps/openstacknetworking/routing/features.xml
index 2043fc6..f9be32e 100644
--- a/apps/openstacknetworking/app/features.xml
+++ b/apps/openstacknetworking/routing/features.xml
@@ -20,5 +20,6 @@
         <feature>onos-api</feature>
         <bundle>mvn:${project.groupId}/onos-app-openstacknetworking-api/${project.version}</bundle>
         <bundle>mvn:${project.groupId}/onos-app-openstacknetworking-web/${project.version}</bundle>
+        <bundle>mvn:${project.groupId}/onos-app-openstackrouting/${project.version}</bundle>
     </feature>
 </features>
diff --git a/apps/openstacknetworking/openstackrouting/pom.xml b/apps/openstacknetworking/routing/pom.xml
similarity index 83%
rename from apps/openstacknetworking/openstackrouting/pom.xml
rename to apps/openstacknetworking/routing/pom.xml
index 3b74025..cc4f7d0 100644
--- a/apps/openstacknetworking/openstackrouting/pom.xml
+++ b/apps/openstacknetworking/routing/pom.xml
@@ -28,6 +28,17 @@
     <artifactId>onos-app-openstackrouting</artifactId>
     <packaging>bundle</packaging>
 
+    <properties>
+        <onos.app.name>org.onosproject.openstackrouting</onos.app.name>
+        <onos.app.title>Openstack Switching App</onos.app.title>
+        <onos.app.category>Traffic Steering</onos.app.category>
+        <onos.app.url>http://onosproject.org</onos.app.url>
+        <onos.app.requires>
+            org.onosproject.openstackinterface,
+            org.onosproject.openstacknode
+        </onos.app.requires>
+    </properties>
+
     <dependencies>
         <dependency>
             <groupId>org.osgi</groupId>
diff --git a/apps/openstacknetworking/openstackrouting/src/main/java/org/onosproject/openstacknetworking/routing/OpenstackFloatingIPHandler.java b/apps/openstacknetworking/routing/src/main/java/org/onosproject/openstacknetworking/routing/OpenstackFloatingIPHandler.java
similarity index 100%
rename from apps/openstacknetworking/openstackrouting/src/main/java/org/onosproject/openstacknetworking/routing/OpenstackFloatingIPHandler.java
rename to apps/openstacknetworking/routing/src/main/java/org/onosproject/openstacknetworking/routing/OpenstackFloatingIPHandler.java
diff --git a/apps/openstacknetworking/openstackrouting/src/main/java/org/onosproject/openstacknetworking/routing/OpenstackIcmpHandler.java b/apps/openstacknetworking/routing/src/main/java/org/onosproject/openstacknetworking/routing/OpenstackIcmpHandler.java
similarity index 100%
rename from apps/openstacknetworking/openstackrouting/src/main/java/org/onosproject/openstacknetworking/routing/OpenstackIcmpHandler.java
rename to apps/openstacknetworking/routing/src/main/java/org/onosproject/openstacknetworking/routing/OpenstackIcmpHandler.java
diff --git a/apps/openstacknetworking/openstackrouting/src/main/java/org/onosproject/openstacknetworking/routing/OpenstackPnatHandler.java b/apps/openstacknetworking/routing/src/main/java/org/onosproject/openstacknetworking/routing/OpenstackPnatHandler.java
similarity index 100%
rename from apps/openstacknetworking/openstackrouting/src/main/java/org/onosproject/openstacknetworking/routing/OpenstackPnatHandler.java
rename to apps/openstacknetworking/routing/src/main/java/org/onosproject/openstacknetworking/routing/OpenstackPnatHandler.java
diff --git a/apps/openstacknetworking/openstackrouting/src/main/java/org/onosproject/openstacknetworking/routing/OpenstackRoutingArpHandler.java b/apps/openstacknetworking/routing/src/main/java/org/onosproject/openstacknetworking/routing/OpenstackRoutingArpHandler.java
similarity index 100%
rename from apps/openstacknetworking/openstackrouting/src/main/java/org/onosproject/openstacknetworking/routing/OpenstackRoutingArpHandler.java
rename to apps/openstacknetworking/routing/src/main/java/org/onosproject/openstacknetworking/routing/OpenstackRoutingArpHandler.java
diff --git a/apps/openstacknetworking/openstackrouting/src/main/java/org/onosproject/openstacknetworking/routing/OpenstackRoutingManager.java b/apps/openstacknetworking/routing/src/main/java/org/onosproject/openstacknetworking/routing/OpenstackRoutingManager.java
similarity index 100%
rename from apps/openstacknetworking/openstackrouting/src/main/java/org/onosproject/openstacknetworking/routing/OpenstackRoutingManager.java
rename to apps/openstacknetworking/routing/src/main/java/org/onosproject/openstacknetworking/routing/OpenstackRoutingManager.java
diff --git a/apps/openstacknetworking/openstackrouting/src/main/java/org/onosproject/openstacknetworking/routing/OpenstackRoutingRulePopulator.java b/apps/openstacknetworking/routing/src/main/java/org/onosproject/openstacknetworking/routing/OpenstackRoutingRulePopulator.java
similarity index 100%
rename from apps/openstacknetworking/openstackrouting/src/main/java/org/onosproject/openstacknetworking/routing/OpenstackRoutingRulePopulator.java
rename to apps/openstacknetworking/routing/src/main/java/org/onosproject/openstacknetworking/routing/OpenstackRoutingRulePopulator.java
diff --git a/apps/openstacknetworking/openstackrouting/src/main/java/org/onosproject/openstacknetworking/routing/package-info.java b/apps/openstacknetworking/routing/src/main/java/org/onosproject/openstacknetworking/routing/package-info.java
similarity index 100%
rename from apps/openstacknetworking/openstackrouting/src/main/java/org/onosproject/openstacknetworking/routing/package-info.java
rename to apps/openstacknetworking/routing/src/main/java/org/onosproject/openstacknetworking/routing/package-info.java
diff --git a/apps/openstacknetworking/openstackswitching/BUCK b/apps/openstacknetworking/switching/BUCK
similarity index 62%
rename from apps/openstacknetworking/openstackswitching/BUCK
rename to apps/openstacknetworking/switching/BUCK
index 42d7c07..5e991af 100644
--- a/apps/openstacknetworking/openstackswitching/BUCK
+++ b/apps/openstacknetworking/switching/BUCK
@@ -3,14 +3,14 @@
     '//core/store/serializers:onos-core-serializers',
     '//apps/openstackinterface/api:onos-apps-openstackinterface-api',
     '//apps/openstacknetworking/api:onos-apps-openstacknetworking-api',
+    '//apps/openstacknode:onos-apps-openstacknode',
     '//apps/dhcp/api:onos-apps-dhcp-api',
 ]
 
 BUNDLES = [
-    '//apps/openstackinterface/api:onos-apps-openstackinterface-api',
     '//apps/openstacknetworking/api:onos-apps-openstacknetworking-api',
-    '//apps/openstacknetworking/openstackswitching:onos-apps-openstacknetworking-openstackswitching',
-    '//apps/dhcp/api:onos-apps-dhcp-api',
+    '//apps/openstacknetworking/web:onos-apps-openstacknetworking-web',
+    '//apps/openstacknetworking/switching:onos-apps-openstacknetworking-switching',
 ]
 
 osgi_jar_with_tests (
@@ -18,9 +18,11 @@
 )
 
 onos_app (
+    app_name = 'org.onosproject.openstackswitching',
     title = 'OpenStack Switching App',
     category = 'Utility',
     url = 'http://onosproject.org',
     description = 'OpenStack Switching application.',
     included_bundles = BUNDLES,
+    required_apps = [ 'org.onosproject.openstackinterface', 'org.onosproject.openstacknode', 'org.onosproject.dhcp' ]
 )
diff --git a/apps/openstacknetworking/app/features.xml b/apps/openstacknetworking/switching/features.xml
similarity index 92%
rename from apps/openstacknetworking/app/features.xml
rename to apps/openstacknetworking/switching/features.xml
index 2043fc6..1792b61 100644
--- a/apps/openstacknetworking/app/features.xml
+++ b/apps/openstacknetworking/switching/features.xml
@@ -20,5 +20,6 @@
         <feature>onos-api</feature>
         <bundle>mvn:${project.groupId}/onos-app-openstacknetworking-api/${project.version}</bundle>
         <bundle>mvn:${project.groupId}/onos-app-openstacknetworking-web/${project.version}</bundle>
+        <bundle>mvn:${project.groupId}/onos-app-openstackswitching/${project.version}</bundle>
     </feature>
 </features>
diff --git a/apps/openstacknetworking/openstackswitching/pom.xml b/apps/openstacknetworking/switching/pom.xml
similarity index 76%
rename from apps/openstacknetworking/openstackswitching/pom.xml
rename to apps/openstacknetworking/switching/pom.xml
index af2d55b..4135e19 100644
--- a/apps/openstacknetworking/openstackswitching/pom.xml
+++ b/apps/openstacknetworking/switching/pom.xml
@@ -28,8 +28,24 @@
     <artifactId>onos-app-openstackswitching</artifactId>
     <packaging>bundle</packaging>
 
+    <properties>
+        <onos.app.name>org.onosproject.openstackswitching</onos.app.name>
+        <onos.app.title>Openstack Switching App</onos.app.title>
+        <onos.app.category>Traffic Steering</onos.app.category>
+        <onos.app.url>http://onosproject.org</onos.app.url>
+        <onos.app.requires>
+            org.onosproject.dhcp,
+            org.onosproject.openstackinterface,
+            org.onosproject.openstacknode
+        </onos.app.requires>
+    </properties>
+
     <dependencies>
         <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.compendium</artifactId>
+        </dependency>
+        <dependency>
             <groupId>org.onosproject</groupId>
             <artifactId>onos-app-openstacknetworking-api</artifactId>
             <version>${project.version}</version>
@@ -41,6 +57,11 @@
         </dependency>
         <dependency>
             <groupId>org.onosproject</groupId>
+            <artifactId>onos-app-openstacknode</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.onosproject</groupId>
             <artifactId>onos-app-dhcp</artifactId>
             <version>${project.version}</version>
         </dependency>
diff --git a/apps/openstacknetworking/switching/src/main/java/org/onosproject/openstacknetworking/switching/AbstractVmHandler.java b/apps/openstacknetworking/switching/src/main/java/org/onosproject/openstacknetworking/switching/AbstractVmHandler.java
new file mode 100644
index 0000000..9bf2baa
--- /dev/null
+++ b/apps/openstacknetworking/switching/src/main/java/org/onosproject/openstacknetworking/switching/AbstractVmHandler.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.openstacknetworking.switching;
+
+import org.onlab.osgi.DefaultServiceDirectory;
+import org.onlab.osgi.ServiceDirectory;
+import org.onlab.packet.Ip4Address;
+import org.onlab.util.Tools;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
+import org.onosproject.mastership.MastershipService;
+import org.onosproject.net.Host;
+import org.onosproject.net.host.HostEvent;
+import org.onosproject.net.host.HostListener;
+import org.onosproject.net.host.HostService;
+import org.slf4j.Logger;
+
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+import java.util.concurrent.ExecutorService;
+import java.util.stream.Collectors;
+
+import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
+import static org.onlab.util.Tools.groupedThreads;
+import static org.onosproject.openstacknetworking.switching.Constants.*;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Provides abstract virtual machine handler.
+ */
+public abstract class AbstractVmHandler {
+    protected final Logger log = getLogger(getClass());
+
+    protected final ExecutorService eventExecutor = newSingleThreadScheduledExecutor(
+            groupedThreads(this.getClass().getSimpleName(), "event-handler"));
+
+    protected CoreService coreService;
+    protected MastershipService mastershipService;
+    protected HostService hostService;
+
+    protected ApplicationId appId;
+    protected HostListener hostListener = new InternalHostListener();
+
+    protected void activate() {
+        ServiceDirectory services = new DefaultServiceDirectory();
+        coreService = services.get(CoreService.class);
+        mastershipService = services.get(MastershipService.class);
+        hostService = services.get(HostService.class);
+
+        appId = coreService.registerApplication(Constants.APP_ID);
+        hostService.addListener(hostListener);
+
+        log.info("Started");
+    }
+
+    protected void deactivate() {
+        hostService.removeListener(hostListener);
+        eventExecutor.shutdown();
+
+        log.info("Stopped");
+    }
+
+    abstract void hostDetected(Host host);
+
+    abstract void hostRemoved(Host host);
+
+    protected boolean isValidHost(Host host) {
+        return !host.ipAddresses().isEmpty() &&
+                host.annotations().value(VXLAN_ID) != null &&
+                host.annotations().value(NETWORK_ID) != null &&
+                host.annotations().value(TENANT_ID) != null &&
+                host.annotations().value(PORT_ID) != null;
+    }
+
+    protected Set<Host> getVmsInDifferentCnode(Host host) {
+        return Tools.stream(hostService.getHosts())
+                .filter(h -> !h.location().deviceId().equals(host.location().deviceId()))
+                .filter(this::isValidHost)
+                .filter(h -> Objects.equals(getVni(h), getVni(host)))
+                .collect(Collectors.toSet());
+    }
+
+    protected Optional<Host> getVmByPortId(String portId) {
+        return Tools.stream(hostService.getHosts())
+                .filter(this::isValidHost)
+                .filter(host -> host.annotations().value(PORT_ID).equals(portId))
+                .findFirst();
+    }
+
+    protected Ip4Address getIp(Host host) {
+        return host.ipAddresses().stream().findFirst().get().getIp4Address();
+    }
+
+    protected String getVni(Host host) {
+        return host.annotations().value(VXLAN_ID);
+    }
+
+    protected String getTenantId(Host host) {
+        return host.annotations().value(TENANT_ID);
+    }
+
+    private class InternalHostListener implements HostListener {
+
+        @Override
+        public void event(HostEvent event) {
+            Host host = event.subject();
+            if (!mastershipService.isLocalMaster(host.location().deviceId())) {
+                // do not allow to proceed without mastership
+                return;
+            }
+
+            if (!isValidHost(host)) {
+                log.debug("Invalid host event, ignore it {}", host);
+                return;
+            }
+
+            switch (event.type()) {
+                case HOST_UPDATED:
+                case HOST_ADDED:
+                    eventExecutor.execute(() -> hostDetected(host));
+                    break;
+                case HOST_REMOVED:
+                    eventExecutor.execute(() -> hostRemoved(host));
+                    break;
+                default:
+                    break;
+            }
+        }
+    }
+}
diff --git a/apps/openstacknetworking/switching/src/main/java/org/onosproject/openstacknetworking/switching/Constants.java b/apps/openstacknetworking/switching/src/main/java/org/onosproject/openstacknetworking/switching/Constants.java
new file mode 100644
index 0000000..b173f29
--- /dev/null
+++ b/apps/openstacknetworking/switching/src/main/java/org/onosproject/openstacknetworking/switching/Constants.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.openstacknetworking.switching;
+
+import org.onlab.packet.Ip4Address;
+import org.onlab.packet.Ip4Prefix;
+import org.onlab.packet.IpPrefix;
+
+/**
+ * Provides constants used in OpenStack node services.
+ */
+public final class Constants {
+
+    private Constants() {
+    }
+
+    public static final String APP_ID = "org.onosproject.openstackswitching";
+
+    public static final String PORTNAME_PREFIX_VM = "tap";
+    public static final String PORTNAME_PREFIX_ROUTER = "qr-";
+    public static final String PORTNAME_PREFIX_TUNNEL = "vxlan";
+
+    // TODO remove this
+    public static final String ROUTER_INTERFACE = "network:router_interface";
+    public static final String DEVICE_OWNER_GATEWAY = "network:router_gateway";
+
+    public static final Ip4Address DNS_SERVER_IP = Ip4Address.valueOf("8.8.8.8");
+    public static final IpPrefix IP_PREFIX_ANY = Ip4Prefix.valueOf("0.0.0.0/0");
+    public static final int DHCP_INFINITE_LEASE = -1;
+
+    public static final String NETWORK_ID = "networkId";
+    public static final String PORT_ID = "portId";
+    public static final String VXLAN_ID = "vxlanId";
+    public static final String TENANT_ID = "tenantId";
+    public static final String GATEWAY_IP = "gatewayIp";
+    public static final String CREATE_TIME = "createTime";
+
+    public static final int SWITCHING_RULE_PRIORITY = 30000;
+    public static final int TUNNELTAG_RULE_PRIORITY = 30000;
+    public static final int ACL_RULE_PRIORITY = 30000;
+}
\ No newline at end of file
diff --git a/apps/openstacknetworking/switching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackArpHandler.java b/apps/openstacknetworking/switching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackArpHandler.java
new file mode 100644
index 0000000..c855403
--- /dev/null
+++ b/apps/openstacknetworking/switching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackArpHandler.java
@@ -0,0 +1,221 @@
+/*
+* Copyright 2016-present Open Networking Laboratory
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package org.onosproject.openstacknetworking.switching;
+
+import com.google.common.base.Strings;
+import com.google.common.collect.Sets;
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Modified;
+import org.apache.felix.scr.annotations.Property;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+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.onlab.util.Tools;
+import org.onosproject.net.Host;
+import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.packet.DefaultOutboundPacket;
+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.OpenstackNetwork;
+import org.onosproject.openstackinterface.OpenstackPort;
+import org.osgi.service.component.ComponentContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import java.nio.ByteBuffer;
+import java.util.Dictionary;
+import java.util.Set;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.onosproject.openstacknetworking.switching.Constants.*;
+
+/**
+ * Handles ARP packet from VMs.
+ */
+@Component(immediate = true)
+public final class OpenstackArpHandler extends AbstractVmHandler {
+
+    private final Logger log = LoggerFactory.getLogger(getClass());
+
+    private static final String GATEWAY_MAC = "gatewayMac";
+    private static final String DEFAULT_GATEWAY_MAC = "1f:1f:1f:1f:1f:1f";
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected PacketService packetService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected OpenstackInterfaceService openstackService;
+
+    @Property(name = GATEWAY_MAC, value = DEFAULT_GATEWAY_MAC,
+            label = "Fake MAC address for virtual network subnet gateway")
+    private String gatewayMac = DEFAULT_GATEWAY_MAC;
+
+    private final InternalPacketProcessor packetProcessor = new InternalPacketProcessor();
+    private final Set<Ip4Address> gateways = Sets.newConcurrentHashSet();
+
+    @Activate
+    protected void activate() {
+        packetService.addProcessor(packetProcessor, PacketProcessor.director(0));
+        super.activate();
+    }
+
+    @Deactivate
+    protected void deactivate() {
+        packetService.removeProcessor(packetProcessor);
+        super.deactivate();
+    }
+
+    @Modified
+    protected void modified(ComponentContext context) {
+        Dictionary<?, ?> properties = context.getProperties();
+        String updatedMac;
+
+        updatedMac = Tools.get(properties, GATEWAY_MAC);
+        if (!Strings.isNullOrEmpty(updatedMac) && !updatedMac.equals(gatewayMac)) {
+            gatewayMac = updatedMac;
+        }
+
+        log.info("Modified");
+    }
+
+    /**
+     * 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 context packet context
+     * @param ethPacket ethernet packet
+     */
+    private void processPacketIn(PacketContext context, Ethernet ethPacket) {
+        ARP arpPacket = (ARP) ethPacket.getPayload();
+        if (arpPacket.getOpCode() != ARP.OP_REQUEST) {
+            return;
+        }
+
+        Ip4Address targetIp = Ip4Address.valueOf(arpPacket.getTargetProtocolAddress());
+        MacAddress replyMac = gateways.contains(targetIp) ? MacAddress.valueOf(gatewayMac) :
+                getMacFromHostService(targetIp);
+        if (replyMac.equals(MacAddress.NONE)) {
+            replyMac = getMacFromOpenstack(targetIp);
+        }
+
+        if (replyMac == MacAddress.NONE) {
+            log.debug("Failed to find MAC address for {}", targetIp.toString());
+            return;
+        }
+
+        Ethernet ethReply = ARP.buildArpReply(
+                targetIp.getIp4Address(),
+                replyMac,
+                ethPacket);
+
+        TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+                .setOutput(context.inPacket().receivedFrom().port())
+                .build();
+
+        packetService.emit(new DefaultOutboundPacket(
+                context.inPacket().receivedFrom().deviceId(),
+                treatment,
+                ByteBuffer.wrap(ethReply.serialize())));
+    }
+
+    /**
+     * 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 = openstackService.ports()
+                .stream()
+                .filter(port -> port.fixedIps().containsValue(targetIp.getIp4Address()))
+                .findFirst()
+                .orElse(null);
+
+        if (openstackPort != null) {
+            log.debug("Found MAC from OpenStack for {}", targetIp.toString());
+            return openstackPort.macAddress();
+        } else {
+            return MacAddress.NONE;
+        }
+    }
+
+    /**
+     * 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 MacAddress.NONE;
+        }
+    }
+
+    @Override
+    protected void hostDetected(Host host) {
+        OpenstackNetwork osNet = openstackService.network(host.annotations().value(NETWORK_ID));
+        if (osNet == null) {
+            log.warn("Failed to get OpenStack network for {}", host);
+            return;
+        }
+        osNet.subnets().stream()
+                .forEach(subnet -> gateways.add(Ip4Address.valueOf(subnet.gatewayIp())));
+    }
+
+    @Override
+    protected void hostRemoved(Host host) {
+        // TODO remove subnet gateway from gateways if no hosts exists on that subnet
+    }
+
+    private class InternalPacketProcessor implements PacketProcessor {
+
+        @Override
+        public void process(PacketContext context) {
+            if (context.isHandled()) {
+                return;
+            }
+
+            Ethernet ethPacket = context.inPacket().parsed();
+            if (ethPacket == null || ethPacket.getEtherType() != Ethernet.TYPE_ARP) {
+                return;
+            }
+            processPacketIn(context, ethPacket);
+        }
+    }
+}
diff --git a/apps/openstacknetworking/switching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackSecurityGroupRulePopulator.java b/apps/openstacknetworking/switching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackSecurityGroupRulePopulator.java
new file mode 100644
index 0000000..7477404
--- /dev/null
+++ b/apps/openstacknetworking/switching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackSecurityGroupRulePopulator.java
@@ -0,0 +1,365 @@
+/*
+* Copyright 2016-present Open Networking Laboratory
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+package org.onosproject.openstacknetworking.switching;
+
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.onlab.packet.Ethernet;
+import org.onlab.packet.IPv4;
+import org.onlab.packet.Ip4Address;
+import org.onlab.packet.IpPrefix;
+import org.onlab.packet.TpPort;
+import org.onlab.util.Tools;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.Host;
+import org.onosproject.net.flow.DefaultTrafficSelector;
+import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.flowobjective.DefaultForwardingObjective;
+import org.onosproject.net.flowobjective.FlowObjectiveService;
+import org.onosproject.net.flowobjective.ForwardingObjective;
+import org.onosproject.openstackinterface.OpenstackInterfaceService;
+import org.onosproject.openstackinterface.OpenstackPort;
+import org.onosproject.openstackinterface.OpenstackSecurityGroup;
+import org.onosproject.openstackinterface.OpenstackSecurityGroupRule;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import static org.onosproject.openstacknetworking.switching.Constants.*;
+
+/**
+ * Populates flows rules for Security Groups of VMs.
+ *
+ */
+@Component(immediate = true)
+public class OpenstackSecurityGroupRulePopulator extends AbstractVmHandler {
+
+    private final Logger log = LoggerFactory.getLogger(getClass());
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected OpenstackInterfaceService openstackService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected FlowObjectiveService flowObjectiveService;
+
+    private static final String PROTO_ICMP = "ICMP";
+    private static final String PROTO_TCP = "TCP";
+    private static final String PROTO_UDP = "UDP";
+    private static final String ETHTYPE_IPV4 = "IPV4";
+
+    private final Map<Host, Set<SecurityGroupRule>> securityGroupRuleMap = Maps.newConcurrentMap();
+
+    @Activate
+    protected void activate() {
+        super.activate();
+    }
+
+    @Deactivate
+    protected void deactivate() {
+        super.deactivate();
+    }
+
+    // TODO call this when port is updated from OpenStack
+    public void updateSecurityGroup(OpenstackPort osPort) {
+        if (!osPort.status().equals(OpenstackPort.PortStatus.ACTIVE)) {
+            return;
+        }
+
+        Optional<Host> host = getVmByPortId(osPort.id());
+        if (!host.isPresent()) {
+            log.warn("No host found with {}", osPort);
+            return;
+        }
+        eventExecutor.execute(() -> updateSecurityGroupRules(host.get(), true));
+    }
+
+    /**
+     * Populates security group rules for all VMs in the supplied tenant ID.
+     * VMs in the same tenant tend to be engaged to each other by sharing the
+     * same security groups or setting the remote to another security group.
+     * To make the implementation simpler and robust, it tries to reinstall
+     * security group rules for all the VMs in the same tenant whenever a new
+     * VM is detected or port is updated.
+     *
+     * @param tenantId tenant id to update security group rules
+     */
+    private void populateSecurityGroupRules(String tenantId, boolean install) {
+        securityGroupRuleMap.entrySet().stream()
+                .filter(entry -> getTenantId(entry.getKey()).equals(tenantId))
+                .forEach(entry -> {
+                    Host local = entry.getKey();
+                    entry.getValue().stream().forEach(sgRule -> {
+                        setSecurityGroupRule(local.location().deviceId(),
+                                sgRule.rule(),
+                                getIp(local),
+                                sgRule.remoteIp(), install);
+                    });
+                });
+        log.debug("Updated security group rules for {}", tenantId);
+    }
+
+    private void setSecurityGroupRule(DeviceId deviceId, OpenstackSecurityGroupRule sgRule,
+                                      Ip4Address vmIp, IpPrefix remoteIp,
+                                      boolean install) {
+        ForwardingObjective.Builder foBuilder = buildFlowObjective(sgRule, vmIp, remoteIp);
+        if (foBuilder == null) {
+            return;
+        }
+
+        if (install) {
+            flowObjectiveService.forward(deviceId, foBuilder.add());
+        } else {
+            flowObjectiveService.forward(deviceId, foBuilder.remove());
+        }
+    }
+
+    private ForwardingObjective.Builder buildFlowObjective(OpenstackSecurityGroupRule sgRule,
+                                                           Ip4Address vmIp,
+                                                           IpPrefix remoteIp) {
+        if (remoteIp != null && remoteIp.equals(IpPrefix.valueOf(vmIp, 32))) {
+            // do nothing if the remote IP is my IP
+            return null;
+        }
+
+        TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
+        buildMatchs(sBuilder, sgRule, vmIp, remoteIp);
+
+        return DefaultForwardingObjective.builder()
+                .withSelector(sBuilder.build())
+                .withTreatment(DefaultTrafficTreatment.builder().build())
+                .withPriority(ACL_RULE_PRIORITY)
+                .withFlag(ForwardingObjective.Flag.SPECIFIC)
+                .fromApp(appId);
+    }
+
+    private void buildMatchs(TrafficSelector.Builder sBuilder, OpenstackSecurityGroupRule sgRule,
+                             Ip4Address vmIp, IpPrefix remoteIp) {
+        buildMatchEthType(sBuilder, sgRule.ethertype());
+        buildMatchDirection(sBuilder, sgRule.direction(), vmIp);
+        buildMatchProto(sBuilder, sgRule.protocol());
+        buildMatchPort(sBuilder, sgRule.protocol(), sgRule.direction(),
+                sgRule.portRangeMax(), sgRule.portRangeMin());
+        buildMatchRemoteIp(sBuilder, remoteIp, sgRule.direction());
+    }
+
+    private void buildMatchDirection(TrafficSelector.Builder sBuilder,
+                                     OpenstackSecurityGroupRule.Direction direction,
+                                     Ip4Address vmIp) {
+        if (direction.equals(OpenstackSecurityGroupRule.Direction.EGRESS)) {
+            sBuilder.matchIPSrc(IpPrefix.valueOf(vmIp, 32));
+        } else {
+            sBuilder.matchIPDst(IpPrefix.valueOf(vmIp, 32));
+        }
+    }
+
+    private void buildMatchEthType(TrafficSelector.Builder sBuilder, String etherType) {
+        // Either IpSrc or IpDst (or both) is set by default, and we need to set EthType as IPv4.
+        sBuilder.matchEthType(Ethernet.TYPE_IPV4);
+        if (etherType != null && !Objects.equals(etherType, "null") &&
+                !etherType.toUpperCase().equals(ETHTYPE_IPV4)) {
+            log.debug("EthType {} is not supported yet in Security Group", etherType);
+        }
+    }
+
+    private void buildMatchRemoteIp(TrafficSelector.Builder sBuilder, IpPrefix remoteIpPrefix,
+                                    OpenstackSecurityGroupRule.Direction direction) {
+        if (remoteIpPrefix != null && !remoteIpPrefix.getIp4Prefix().equals(IP_PREFIX_ANY)) {
+            if (direction.equals(OpenstackSecurityGroupRule.Direction.EGRESS)) {
+                sBuilder.matchIPDst(remoteIpPrefix);
+            } else {
+                sBuilder.matchIPSrc(remoteIpPrefix);
+            }
+        }
+    }
+
+    private void buildMatchProto(TrafficSelector.Builder sBuilder, String protocol) {
+        if (protocol != null) {
+            switch (protocol.toUpperCase()) {
+                case PROTO_ICMP:
+                    sBuilder.matchIPProtocol(IPv4.PROTOCOL_ICMP);
+                    break;
+                case PROTO_TCP:
+                    sBuilder.matchIPProtocol(IPv4.PROTOCOL_TCP);
+                    break;
+                case PROTO_UDP:
+                    sBuilder.matchIPProtocol(IPv4.PROTOCOL_UDP);
+                    break;
+                default:
+            }
+        }
+    }
+
+    private void buildMatchPort(TrafficSelector.Builder sBuilder, String protocol,
+                                OpenstackSecurityGroupRule.Direction direction,
+                                int portMin, int portMax) {
+        if (portMin > 0 && portMax > 0 && portMin == portMax) {
+            if (protocol.toUpperCase().equals(PROTO_TCP)) {
+                if (direction.equals(OpenstackSecurityGroupRule.Direction.EGRESS)) {
+                    sBuilder.matchTcpDst(TpPort.tpPort(portMax));
+                } else {
+                    sBuilder.matchTcpSrc(TpPort.tpPort(portMax));
+                }
+            } else if (protocol.toUpperCase().equals(PROTO_UDP)) {
+                if (direction.equals(OpenstackSecurityGroupRule.Direction.EGRESS)) {
+                    sBuilder.matchUdpDst(TpPort.tpPort(portMax));
+                } else {
+                    sBuilder.matchUdpSrc(TpPort.tpPort(portMax));
+                }
+            }
+        }
+    }
+
+    private void updateSecurityGroupRulesMap(Host host) {
+        OpenstackPort osPort = openstackService.port(host.annotations().value(PORT_ID));
+        if (osPort == null) {
+            log.debug("Failed to get OpenStack port information for {}", host);
+            return;
+        }
+
+        Set<SecurityGroupRule> rules = Sets.newHashSet();
+        osPort.securityGroups().stream().forEach(sgId -> {
+            OpenstackSecurityGroup osSecGroup = openstackService.securityGroup(sgId);
+            if (osSecGroup != null) {
+                osSecGroup.rules().stream().forEach(rule -> rules.addAll(getSgRules(rule)));
+            } else {
+                // TODO handle the case that the security group removed
+                log.warn("Failed to get security group {}", sgId);
+            }
+        });
+        securityGroupRuleMap.put(host, rules);
+    }
+
+    /**
+     * Returns set of security group rules with individual remote IP by
+     * converting remote group to actual IP address.
+     *
+     * @param sgRule security group rule
+     * @return set of security group rules
+     */
+    private Set<SecurityGroupRule> getSgRules(OpenstackSecurityGroupRule sgRule) {
+        Set<SecurityGroupRule> sgRules = Sets.newHashSet();
+        if (sgRule.remoteGroupId() != null && !sgRule.remoteGroupId().equals("null")) {
+            sgRules = getRemoteIps(sgRule.tenantId(), sgRule.remoteGroupId())
+                    .stream()
+                    .map(remoteIp -> new SecurityGroupRule(sgRule, remoteIp))
+                    .collect(Collectors.toSet());
+        } else {
+            sgRules.add(new SecurityGroupRule(sgRule, sgRule.remoteIpPrefix()));
+        }
+        return sgRules;
+    }
+
+    /**
+     * Returns a set of host IP addresses engaged with supplied security group ID.
+     * It only searches a VM in the same tenant boundary.
+     *
+     * @param tenantId tenant id
+     * @param sgId security group id
+     * @return set of ip addresses in ip prefix format
+     */
+    private Set<IpPrefix> getRemoteIps(String tenantId, String sgId) {
+        Set<IpPrefix> remoteIps = Sets.newHashSet();
+        securityGroupRuleMap.entrySet().stream()
+                .filter(entry -> Objects.equals(getTenantId(entry.getKey()), tenantId))
+                .forEach(entry -> {
+                    if (entry.getValue().stream()
+                            .anyMatch(rule -> rule.rule().secuityGroupId().equals(sgId))) {
+                        remoteIps.add(IpPrefix.valueOf(getIp(entry.getKey()), 32));
+                    }
+                });
+        return remoteIps;
+    }
+
+    private void updateSecurityGroupRules(Host host, boolean isHostAdded) {
+        String tenantId = getTenantId(host);
+        populateSecurityGroupRules(tenantId, false);
+
+        if (isHostAdded) {
+            updateSecurityGroupRulesMap(host);
+        } else {
+            securityGroupRuleMap.remove(host);
+        }
+
+        Tools.stream(hostService.getHosts())
+                .filter(h -> Objects.equals(getTenantId(h), getTenantId(host)))
+                .forEach(this::updateSecurityGroupRulesMap);
+
+        populateSecurityGroupRules(tenantId, true);
+    }
+
+    @Override
+    protected void hostDetected(Host host) {
+        updateSecurityGroupRules(host, true);
+        log.info("Applied security group rules for {}", host);
+    }
+
+    @Override
+    protected void hostRemoved(Host host) {
+        updateSecurityGroupRules(host, false);
+        log.info("Applied security group rules for {}", host);
+    }
+
+    private final class SecurityGroupRule {
+        private final OpenstackSecurityGroupRule rule;
+        private final IpPrefix remoteIp;
+
+        private SecurityGroupRule(OpenstackSecurityGroupRule rule, IpPrefix remoteIp) {
+            this.rule = rule;
+            this.remoteIp = remoteIp;
+        }
+
+        private OpenstackSecurityGroupRule rule() {
+            return rule;
+        }
+
+        private IpPrefix remoteIp() {
+            return remoteIp;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+
+            if (obj instanceof SecurityGroupRule) {
+                SecurityGroupRule that = (SecurityGroupRule) obj;
+                if (Objects.equals(rule, that.rule) &&
+                        Objects.equals(remoteIp, that.remoteIp)) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(rule, remoteIp);
+        }
+    }
+}
diff --git a/apps/openstacknetworking/switching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackSwitchingManager.java b/apps/openstacknetworking/switching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackSwitchingManager.java
new file mode 100644
index 0000000..24ab533
--- /dev/null
+++ b/apps/openstacknetworking/switching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackSwitchingManager.java
@@ -0,0 +1,303 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.openstacknetworking.switching;
+
+import com.google.common.base.Strings;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.apache.felix.scr.annotations.Service;
+import org.onlab.packet.Ip4Address;
+import org.onlab.packet.IpPrefix;
+import org.onlab.packet.VlanId;
+import org.onlab.util.Tools;
+import org.onosproject.core.CoreService;
+import org.onosproject.dhcp.DhcpService;
+import org.onosproject.dhcp.IpAssignment;
+import org.onosproject.mastership.MastershipService;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.DefaultAnnotations;
+import org.onosproject.net.Device;
+import org.onosproject.net.Host;
+import org.onosproject.net.HostId;
+import org.onosproject.net.HostLocation;
+import org.onosproject.net.Port;
+import org.onosproject.net.device.DeviceEvent;
+import org.onosproject.net.device.DeviceListener;
+import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.host.DefaultHostDescription;
+import org.onosproject.net.host.HostDescription;
+import org.onosproject.net.host.HostProvider;
+import org.onosproject.net.host.HostProviderRegistry;
+import org.onosproject.net.host.HostProviderService;
+import org.onosproject.net.host.HostService;
+import org.onosproject.net.provider.AbstractProvider;
+import org.onosproject.net.provider.ProviderId;
+import org.onosproject.openstackinterface.OpenstackInterfaceService;
+import org.onosproject.openstackinterface.OpenstackNetwork;
+import org.onosproject.openstackinterface.OpenstackPort;
+import org.onosproject.openstackinterface.OpenstackSubnet;
+import org.onosproject.openstacknetworking.OpenstackPortInfo;
+import org.onosproject.openstacknetworking.OpenstackSwitchingService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Date;
+import java.util.Map;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import static org.onlab.util.Tools.groupedThreads;
+import static org.onosproject.dhcp.IpAssignment.AssignmentStatus.Option_RangeNotEnforced;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.onosproject.net.AnnotationKeys.PORT_NAME;
+import static org.onosproject.openstacknetworking.switching.Constants.*;
+
+@Service
+@Component(immediate = true)
+/**
+ * Populates forwarding rules for VMs created by Openstack.
+ */
+public final class OpenstackSwitchingManager extends AbstractProvider
+        implements OpenstackSwitchingService, HostProvider {
+
+    private final Logger log = LoggerFactory.getLogger(getClass());
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected CoreService coreService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected DeviceService deviceService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected HostProviderRegistry hostProviderRegistry;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected DhcpService dhcpService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected HostService hostService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected MastershipService mastershipService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected OpenstackInterfaceService openstackService;
+
+    private final ExecutorService deviceEventExecutor =
+            Executors.newSingleThreadExecutor(groupedThreads("onos/openstackswitching", "device-event"));
+    private final ExecutorService configEventExecutor =
+            Executors.newSingleThreadExecutor(groupedThreads("onos/openstackswitching", "config-event"));
+    private final InternalDeviceListener internalDeviceListener = new InternalDeviceListener();
+
+    private HostProviderService hostProvider;
+
+    /**
+     * Creates OpenStack switching host provider.
+     */
+    public OpenstackSwitchingManager() {
+        super(new ProviderId("host", APP_ID));
+    }
+
+    @Activate
+    protected void activate() {
+        coreService.registerApplication(APP_ID);
+        deviceService.addListener(internalDeviceListener);
+        hostProvider = hostProviderRegistry.register(this);
+
+        log.info("Started");
+    }
+
+    @Deactivate
+    protected void deactivate() {
+        hostProviderRegistry.unregister(this);
+        deviceService.removeListener(internalDeviceListener);
+
+        deviceEventExecutor.shutdown();
+        configEventExecutor.shutdown();
+
+        log.info("Stopped");
+    }
+
+    @Override
+    public void triggerProbe(Host host) {
+        // no probe is required
+    }
+
+    @Override
+    // TODO remove this and openstackPortInfo
+    public Map<String, OpenstackPortInfo> openstackPortInfo() {
+        Map<String, OpenstackPortInfo> portInfoMap = Maps.newHashMap();
+
+        Tools.stream(hostService.getHosts()).filter(this::isValidHost).forEach(host -> {
+            Port port = deviceService.getPort(
+                    host.location().deviceId(),
+                    host.location().port());
+
+            OpenstackPortInfo portInfo = OpenstackPortInfo.builder()
+                    .setDeviceId(host.location().deviceId())
+                    .setHostMac(host.mac())
+                    .setNetworkId(host.annotations().value(NETWORK_ID))
+                    .setGatewayIP(Ip4Address.valueOf(host.annotations().value(GATEWAY_IP)))
+                    .setVni(Long.valueOf(host.annotations().value(VXLAN_ID)))
+                    .setHostIp(host.ipAddresses().stream().findFirst().get().getIp4Address())
+                    .build();
+
+            portInfoMap.put(port.annotations().value(PORT_NAME), portInfo);
+        });
+
+        return portInfoMap;
+    }
+
+    // TODO remove this and openstackPortInfo
+    private boolean isValidHost(Host host) {
+        return !host.ipAddresses().isEmpty() &&
+                host.annotations().value(VXLAN_ID) != null &&
+                host.annotations().value(NETWORK_ID) != null &&
+                host.annotations().value(TENANT_ID) != null &&
+                host.annotations().value(GATEWAY_IP) != null &&
+                host.annotations().value(PORT_ID) != null;
+    }
+
+    private void processPortAdded(Port port) {
+        OpenstackPort osPort = openstackService.port(port);
+        if (osPort == null) {
+            log.warn("Failed to get OpenStack port for {}", port);
+            return;
+        }
+
+        OpenstackNetwork osNet = openstackService.network(osPort.networkId());
+        if (osNet == null) {
+            log.warn("Failed to get OpenStack network {}",
+                    osPort.networkId());
+            return;
+        }
+
+        registerDhcpInfo(osPort);
+        ConnectPoint connectPoint = new ConnectPoint(port.element().id(), port.number());
+        // TODO remove this and openstackPortInfo
+        String gatewayIp = osNet.subnets().stream().findFirst().get().gatewayIp();
+
+        // Added CREATE_TIME intentionally to trigger HOST_UPDATED event for the
+        // existing instances.
+        DefaultAnnotations.Builder annotations = DefaultAnnotations.builder()
+                .set(NETWORK_ID, osPort.networkId())
+                .set(PORT_ID, osPort.id())
+                .set(VXLAN_ID, osNet.segmentId())
+                .set(TENANT_ID, osNet.tenantId())
+                // TODO remove this and openstackPortInfo
+                .set(GATEWAY_IP, gatewayIp)
+                .set(CREATE_TIME, String.valueOf(System.currentTimeMillis()));
+
+        HostDescription hostDesc = new DefaultHostDescription(
+                osPort.macAddress(),
+                VlanId.NONE,
+                new HostLocation(connectPoint, System.currentTimeMillis()),
+                Sets.newHashSet(osPort.fixedIps().values()),
+                annotations.build());
+
+        HostId hostId = HostId.hostId(osPort.macAddress());
+        hostProvider.hostDetected(hostId, hostDesc, false);
+    }
+
+    private void processPortRemoved(Port port) {
+        ConnectPoint connectPoint = new ConnectPoint(port.element().id(), port.number());
+        hostService.getConnectedHosts(connectPoint).stream()
+                .forEach(host -> {
+                    dhcpService.removeStaticMapping(host.mac());
+                    hostProvider.hostVanished(host.id());
+                });
+    }
+
+    private void registerDhcpInfo(OpenstackPort openstackPort) {
+        checkNotNull(openstackPort);
+        checkArgument(!openstackPort.fixedIps().isEmpty());
+
+        OpenstackSubnet openstackSubnet = openstackService.subnets().stream()
+                .filter(n -> n.networkId().equals(openstackPort.networkId()))
+                .findFirst().orElse(null);
+        if (openstackSubnet == null) {
+            log.warn("Failed to find subnet for {}", openstackPort);
+            return;
+        }
+
+        Ip4Address ipAddress = openstackPort.fixedIps().values().stream().findFirst().get();
+        IpPrefix subnetPrefix = IpPrefix.valueOf(openstackSubnet.cidr());
+        Ip4Address broadcast = Ip4Address.makeMaskedAddress(
+                ipAddress,
+                subnetPrefix.prefixLength());
+
+        // TODO: supports multiple DNS servers
+        Ip4Address domainServer = openstackSubnet.dnsNameservers().isEmpty() ?
+                DNS_SERVER_IP : openstackSubnet.dnsNameservers().get(0);
+
+        IpAssignment ipAssignment = IpAssignment.builder()
+                .ipAddress(ipAddress)
+                .leasePeriod(DHCP_INFINITE_LEASE)
+                .timestamp(new Date())
+                .subnetMask(Ip4Address.makeMaskPrefix(subnetPrefix.prefixLength()))
+                .broadcast(broadcast)
+                .domainServer(domainServer)
+                .assignmentStatus(Option_RangeNotEnforced)
+                .routerAddress(Ip4Address.valueOf(openstackSubnet.gatewayIp()))
+                .build();
+
+        dhcpService.setStaticMapping(openstackPort.macAddress(), ipAssignment);
+    }
+
+    private class InternalDeviceListener implements DeviceListener {
+
+        @Override
+        public void event(DeviceEvent event) {
+            Device device = event.subject();
+            if (!mastershipService.isLocalMaster(device.id())) {
+                // do not allow to proceed without mastership
+                return;
+            }
+
+            Port port = event.port();
+            if (port == null) {
+                return;
+            }
+
+            String portName = port.annotations().value(PORT_NAME);
+            if (Strings.isNullOrEmpty(portName) ||
+                    !portName.startsWith(PORTNAME_PREFIX_VM)) {
+                // handles VM connected port event only
+                return;
+            }
+
+            switch (event.type()) {
+                case PORT_UPDATED:
+                    if (!event.port().isEnabled()) {
+                        deviceEventExecutor.execute(() -> processPortRemoved(event.port()));
+                    }
+                    break;
+                case PORT_ADDED:
+                    deviceEventExecutor.execute(() -> processPortAdded(event.port()));
+                    break;
+                default:
+                    break;
+            }
+        }
+    }
+}
diff --git a/apps/openstacknetworking/switching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackSwitchingRulePopulator.java b/apps/openstacknetworking/switching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackSwitchingRulePopulator.java
new file mode 100644
index 0000000..732be7d
--- /dev/null
+++ b/apps/openstacknetworking/switching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackSwitchingRulePopulator.java
@@ -0,0 +1,293 @@
+/*
+* Copyright 2016-present Open Networking Laboratory
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+package org.onosproject.openstacknetworking.switching;
+
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.onlab.packet.Ethernet;
+import org.onlab.packet.Ip4Address;
+import org.onlab.packet.IpAddress;
+import org.onosproject.net.Device;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.Host;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.behaviour.ExtensionTreatmentResolver;
+import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.flow.DefaultTrafficSelector;
+import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.flow.instructions.ExtensionTreatment;
+import org.onosproject.net.flow.instructions.ExtensionPropertyException;
+import org.onosproject.net.flowobjective.DefaultForwardingObjective;
+import org.onosproject.net.flowobjective.FlowObjectiveService;
+import org.onosproject.net.flowobjective.ForwardingObjective;
+import org.onosproject.openstacknode.OpenstackNodeService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Objects;
+import java.util.Optional;
+
+import static org.onosproject.net.flow.instructions.ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_SET_TUNNEL_DST;
+import static org.onosproject.openstacknetworking.switching.Constants.*;
+
+/**
+ * Populates switching flow rules.
+ */
+@Component(immediate = true)
+public final class OpenstackSwitchingRulePopulator extends AbstractVmHandler {
+
+    private final Logger log = LoggerFactory.getLogger(getClass());
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected DeviceService deviceService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected FlowObjectiveService flowObjectiveService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected OpenstackNodeService nodeService;
+
+
+    private static final String TUNNEL_DST = "tunnelDst";
+
+    @Activate
+    protected void activate() {
+        super.activate();
+    }
+
+    @Deactivate
+    protected void deactivate() {
+        super.deactivate();
+    }
+
+    private void populateSwitchingRules(Host host) {
+        populateFlowRulesForTunnelTag(host);
+        populateFlowRulesForTrafficToSameCnode(host);
+        populateFlowRulesForTrafficToDifferentCnode(host);
+
+        log.debug("Populated switching rule for {}", host);
+    }
+
+    private void populateFlowRulesForTunnelTag(Host host) {
+        TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
+        TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
+
+        sBuilder.matchEthType(Ethernet.TYPE_IPV4)
+                .matchInPort(host.location().port());
+
+        tBuilder.setTunnelId(Long.valueOf(getVni(host)));
+
+        ForwardingObjective fo = DefaultForwardingObjective.builder()
+                .withSelector(sBuilder.build())
+                .withTreatment(tBuilder.build())
+                .withPriority(TUNNELTAG_RULE_PRIORITY)
+                .withFlag(ForwardingObjective.Flag.SPECIFIC)
+                .fromApp(appId)
+                .add();
+
+        flowObjectiveService.forward(host.location().deviceId(), fo);
+    }
+
+    private void populateFlowRulesForTrafficToSameCnode(Host host) {
+        //For L2 Switching Case
+        TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
+        TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
+
+        sBuilder.matchEthType(Ethernet.TYPE_IPV4)
+                .matchIPDst(getIp(host).toIpPrefix())
+                .matchTunnelId(Long.valueOf(getVni(host)));
+
+        tBuilder.setOutput(host.location().port());
+
+        ForwardingObjective fo = DefaultForwardingObjective.builder()
+                .withSelector(sBuilder.build())
+                .withTreatment(tBuilder.build())
+                .withPriority(SWITCHING_RULE_PRIORITY)
+                .withFlag(ForwardingObjective.Flag.SPECIFIC)
+                .fromApp(appId)
+                .add();
+
+        flowObjectiveService.forward(host.location().deviceId(), fo);
+    }
+
+    private void populateFlowRulesForTrafficToDifferentCnode(Host host) {
+        Ip4Address localVmIp = getIp(host);
+        DeviceId localDeviceId = host.location().deviceId();
+        Optional<IpAddress> localDataIp = nodeService.dataIp(localDeviceId);
+
+        if (!localDataIp.isPresent()) {
+            log.debug("Failed to get data IP for device {}",
+                    host.location().deviceId());
+            return;
+        }
+
+        String vni = getVni(host);
+        getVmsInDifferentCnode(host).forEach(remoteVm -> {
+            Optional<IpAddress> remoteDataIp = nodeService.dataIp(remoteVm.location().deviceId());
+            if (remoteDataIp.isPresent()) {
+                setVxLanFlowRule(vni,
+                        localDeviceId,
+                        remoteDataIp.get().getIp4Address(),
+                        getIp(remoteVm));
+
+                setVxLanFlowRule(vni,
+                        remoteVm.location().deviceId(),
+                        localDataIp.get().getIp4Address(),
+                        localVmIp);
+            }
+        });
+    }
+
+    private void setVxLanFlowRule(String vni, DeviceId deviceId, Ip4Address remoteIp,
+                                  Ip4Address vmIp) {
+        Optional<PortNumber> tunnelPort = nodeService.tunnelPort(deviceId);
+        if (!tunnelPort.isPresent()) {
+            log.warn("Failed to get tunnel port from {}", deviceId);
+            return;
+        }
+
+        TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
+        TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
+
+        sBuilder.matchEthType(Ethernet.TYPE_IPV4)
+                .matchTunnelId(Long.parseLong(vni))
+                .matchIPDst(vmIp.toIpPrefix());
+        tBuilder.extension(buildNiciraExtenstion(deviceId, remoteIp), deviceId)
+                .setOutput(tunnelPort.get());
+
+        ForwardingObjective fo = DefaultForwardingObjective.builder()
+                .withSelector(sBuilder.build())
+                .withTreatment(tBuilder.build())
+                .withPriority(SWITCHING_RULE_PRIORITY)
+                .withFlag(ForwardingObjective.Flag.SPECIFIC)
+                .fromApp(appId)
+                .add();
+
+        flowObjectiveService.forward(deviceId, fo);
+    }
+
+    private void removeSwitchingRules(Host host) {
+        removeFlowRuleForTunnelTag(host);
+        removeFlowRuleForVMsInSameCnode(host);
+        removeFlowRuleForVMsInDiffrentCnode(host);
+
+        log.debug("Removed switching rule for {}", host);
+    }
+
+    private void removeFlowRuleForTunnelTag(Host host) {
+        TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
+        TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
+
+        sBuilder.matchEthType(Ethernet.TYPE_IPV4)
+                .matchInPort(host.location().port());
+
+        ForwardingObjective fo = DefaultForwardingObjective.builder()
+                .withSelector(sBuilder.build())
+                .withTreatment(tBuilder.build())
+                .withPriority(TUNNELTAG_RULE_PRIORITY)
+                .withFlag(ForwardingObjective.Flag.SPECIFIC)
+                .fromApp(appId)
+                .remove();
+
+        flowObjectiveService.forward(host.location().deviceId(), fo);
+    }
+
+    private void removeFlowRuleForVMsInSameCnode(Host host) {
+        TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
+        sBuilder.matchEthType(Ethernet.TYPE_IPV4)
+                .matchIPDst(getIp(host).toIpPrefix())
+                .matchTunnelId(Long.valueOf(getVni(host)));
+
+        ForwardingObjective fo = DefaultForwardingObjective.builder()
+                .withSelector(sBuilder.build())
+                .withTreatment(DefaultTrafficTreatment.builder().build())
+                .withFlag(ForwardingObjective.Flag.SPECIFIC)
+                .withPriority(SWITCHING_RULE_PRIORITY)
+                .fromApp(appId)
+                .remove();
+
+        flowObjectiveService.forward(host.location().deviceId(), fo);
+    }
+
+    private void removeFlowRuleForVMsInDiffrentCnode(Host host) {
+        DeviceId deviceId = host.location().deviceId();
+        final boolean anyPortRemainedInSameCnode = hostService.getConnectedHosts(deviceId)
+                .stream()
+                .filter(this::isValidHost)
+                .anyMatch(h -> Objects.equals(getVni(h), getVni(host)));
+
+        getVmsInDifferentCnode(host).forEach(h -> {
+           removeVxLanFlowRule(h.location().deviceId(), getIp(host), getVni(host));
+           if (!anyPortRemainedInSameCnode) {
+               removeVxLanFlowRule(deviceId, getIp(h), getVni(host));
+           }
+       });
+    }
+
+    private void removeVxLanFlowRule(DeviceId deviceId, Ip4Address vmIp, String vni) {
+        TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
+
+        sBuilder.matchEthType(Ethernet.TYPE_IPV4)
+                .matchTunnelId(Long.valueOf(vni))
+                .matchIPDst(vmIp.toIpPrefix());
+
+        ForwardingObjective fo = DefaultForwardingObjective.builder()
+                .withSelector(sBuilder.build())
+                .withTreatment(DefaultTrafficTreatment.builder().build())
+                .withFlag(ForwardingObjective.Flag.SPECIFIC)
+                .withPriority(SWITCHING_RULE_PRIORITY)
+                .fromApp(appId)
+                .remove();
+
+        flowObjectiveService.forward(deviceId, fo);
+    }
+
+    private ExtensionTreatment buildNiciraExtenstion(DeviceId deviceId, Ip4Address remoteIp) {
+        Device device = deviceService.getDevice(deviceId);
+        if (device != null && !device.is(ExtensionTreatmentResolver.class)) {
+            log.error("The extension treatment is not supported");
+            return null;
+        }
+
+        ExtensionTreatmentResolver resolver = device.as(ExtensionTreatmentResolver.class);
+        ExtensionTreatment treatment = resolver.getExtensionInstruction(NICIRA_SET_TUNNEL_DST.type());
+        try {
+            treatment.setPropertyValue(TUNNEL_DST, remoteIp);
+            return treatment;
+        } catch (ExtensionPropertyException e) {
+            log.warn("Failed to get tunnelDst extension treatment for {}", deviceId);
+            return null;
+        }
+    }
+
+    @Override
+    protected void hostDetected(Host host) {
+        populateSwitchingRules(host);
+        log.info("Added new virtual machine to switching service {}", host);
+    }
+
+    @Override
+    protected void hostRemoved(Host host) {
+        removeSwitchingRules(host);
+        log.info("Removed virtual machine from switching service {}", host);
+    }
+}
diff --git a/apps/openstacknetworking/openstackswitching/src/main/java/org/onosproject/openstacknetworking/switching/package-info.java b/apps/openstacknetworking/switching/src/main/java/org/onosproject/openstacknetworking/switching/package-info.java
similarity index 100%
rename from apps/openstacknetworking/openstackswitching/src/main/java/org/onosproject/openstacknetworking/switching/package-info.java
rename to apps/openstacknetworking/switching/src/main/java/org/onosproject/openstacknetworking/switching/package-info.java
diff --git a/apps/openstacknetworking/web/src/main/java/org/onosproject/openstacknetworking/web/OpenstackPortWebResource.java b/apps/openstacknetworking/web/src/main/java/org/onosproject/openstacknetworking/web/OpenstackPortWebResource.java
index af46e7b..e23a3ee 100644
--- a/apps/openstacknetworking/web/src/main/java/org/onosproject/openstacknetworking/web/OpenstackPortWebResource.java
+++ b/apps/openstacknetworking/web/src/main/java/org/onosproject/openstacknetworking/web/OpenstackPortWebResource.java
@@ -15,16 +15,7 @@
  */
 package org.onosproject.openstacknetworking.web;
 
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.node.ObjectNode;
-import org.onosproject.openstackinterface.OpenstackPort;
-import org.onosproject.openstackinterface.web.OpenstackPortCodec;
-import org.onosproject.openstacknetworking.OpenstackPortInfo;
-import org.onosproject.openstacknetworking.OpenstackRoutingService;
-import org.onosproject.openstacknetworking.OpenstackSwitchingService;
 import org.onosproject.rest.AbstractWebResource;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 import javax.ws.rs.Consumes;
 import javax.ws.rs.DELETE;
@@ -43,47 +34,16 @@
 @Path("ports")
 public class OpenstackPortWebResource extends AbstractWebResource {
 
-    private final Logger log = LoggerFactory.getLogger(getClass());
-    private static final String PORTNAME_PREFIX_VM = "tap";
-    private static final OpenstackPortCodec PORT_CODEC = new OpenstackPortCodec();
-
     @POST
     @Consumes(MediaType.APPLICATION_JSON)
     @Produces(MediaType.APPLICATION_JSON)
     public Response createPorts(InputStream input) {
-        try {
-            ObjectMapper mapper = new ObjectMapper();
-            ObjectNode portNode = (ObjectNode) mapper.readTree(input);
-
-            OpenstackPort openstackPort = PORT_CODEC.decode(portNode, this);
-            OpenstackSwitchingService switchingService =
-                    getService(OpenstackSwitchingService.class);
-            switchingService.createPorts(openstackPort);
-
-            log.debug("REST API ports is called with {}", portNode.toString());
-            return Response.status(Response.Status.OK).build();
-
-        } catch (Exception e) {
-            log.error("Creates Port failed because of exception {}",
-                    e.toString());
-            return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(e.toString())
-                    .build();
-        }
+        return Response.status(Response.Status.OK).build();
     }
 
     @Path("{portUUID}")
     @DELETE
     public Response deletePorts(@PathParam("portUUID") String id) {
-        OpenstackSwitchingService switchingService =
-                getService(OpenstackSwitchingService.class);
-        OpenstackPortInfo portInfo = switchingService.openstackPortInfo()
-                .get(PORTNAME_PREFIX_VM.concat(id.substring(0, 11)));
-        OpenstackRoutingService routingService =
-                getService(OpenstackRoutingService.class);
-        routingService.checkDisassociatedFloatingIp(id, portInfo);
-
-        switchingService.removePort(id);
-
         return Response.noContent().build();
     }
 
@@ -92,23 +52,7 @@
     @Consumes(MediaType.APPLICATION_JSON)
     @Produces(MediaType.APPLICATION_JSON)
     public Response updatePorts(InputStream input) {
-        try {
-            ObjectMapper mapper = new ObjectMapper();
-            ObjectNode portNode = (ObjectNode) mapper.readTree(input);
-
-            OpenstackPort openstackPort = PORT_CODEC.decode(portNode, this);
-            OpenstackSwitchingService switchingService =
-                    getService(OpenstackSwitchingService.class);
-            switchingService.updatePort(openstackPort);
-
-            log.debug("REST API update port is called with {}", portNode.toString());
-            return Response.status(Response.Status.OK).build();
-
-        } catch (Exception e) {
-            log.error("Update Port failed because of exception {}",
-                    e.toString());
-            return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(e.toString())
-                    .build();
-        }
+        // TODO call security group update here
+        return Response.status(Response.Status.OK).build();
     }
 }
diff --git a/apps/openstacknode/BUCK b/apps/openstacknode/BUCK
index e614257..c9ad7ac 100644
--- a/apps/openstacknode/BUCK
+++ b/apps/openstacknode/BUCK
@@ -16,5 +16,5 @@
     category = 'Utility',
     url = 'http://onosproject.org',
     description = 'SONA Openstack Node Bootstrap Application.',
-    required_app = [ 'org.onosproject.ovsdb-base' ],
+    required_apps = [ 'org.onosproject.ovsdb-base', 'org.onosproject.drivers.ovsdb' ]
 )
diff --git a/apps/openstacknode/pom.xml b/apps/openstacknode/pom.xml
index 5524b22..71cb5b2 100644
--- a/apps/openstacknode/pom.xml
+++ b/apps/openstacknode/pom.xml
@@ -38,7 +38,8 @@
         <onos.app.url>http://onosproject.org</onos.app.url>
         <onos.app.readme>SONA Openstack Node Bootstrap Application</onos.app.readme>
         <onos.app.requires>
-            org.onosproject.ovsdb-base
+            org.onosproject.ovsdb-base,
+            org.onosproject.drivers.ovsdb
         </onos.app.requires>
     </properties>
 
diff --git a/apps/openstacknode/src/main/java/org/onosproject/openstacknode/OpenstackNodeManager.java b/apps/openstacknode/src/main/java/org/onosproject/openstacknode/OpenstackNodeManager.java
index 1995111..039c3ed 100644
--- a/apps/openstacknode/src/main/java/org/onosproject/openstacknode/OpenstackNodeManager.java
+++ b/apps/openstacknode/src/main/java/org/onosproject/openstacknode/OpenstackNodeManager.java
@@ -242,7 +242,7 @@
         deviceService.removeListener(deviceListener);
         nodeStore.removeListener(nodeStoreListener);
 
-        componentConfigService.unregisterProperties(getClass(), true);
+        componentConfigService.unregisterProperties(getClass(), false);
         configRegistry.unregisterConfigFactory(configFactory);
 
         leadershipService.withdraw(appId.name());
diff --git a/tools/package/BUCK b/tools/package/BUCK
index 66b0b4f..d6d1fb4 100644
--- a/tools/package/BUCK
+++ b/tools/package/BUCK
@@ -54,8 +54,8 @@
   '//apps/mlb:onos-apps-mlb-oar',
   '//apps/openstackinterface:onos-apps-openstackinterface-oar',
   '//apps/openstacknetworking:onos-apps-openstacknetworking-oar',
-  '//apps/openstacknetworking/openstackrouting:onos-apps-openstacknetworking-openstackrouting-oar',
-  '//apps/openstacknetworking/openstackswitching:onos-apps-openstacknetworking-openstackswitching-oar',
+  '//apps/openstacknetworking/routing:onos-apps-openstacknetworking-routing-oar',
+  '//apps/openstacknetworking/switching:onos-apps-openstacknetworking-switching-oar',
   '//apps/mobility:onos-apps-mobility-oar',
   '//apps/optical:onos-apps-optical-oar',
   '//apps/pathpainter:onos-apps-pathpainter-oar',