[ONOS-3946] Implement IcmpHandler for OpenstackRoutingService
- Process Icmp packet sent from Host to external network for OpenstackGateway Node
- Process Arp packet sent from physical  router to gateway

Change-Id: Ifcde71a9ca10180682811c9e1bcf58f991b36443
diff --git a/apps/openstackinterface/app/src/main/java/org/onosproject/openstackinterface/web/OpenstackRouterCodec.java b/apps/openstackinterface/app/src/main/java/org/onosproject/openstackinterface/web/OpenstackRouterCodec.java
index 6a1750e..ae791b9 100644
--- a/apps/openstackinterface/app/src/main/java/org/onosproject/openstackinterface/web/OpenstackRouterCodec.java
+++ b/apps/openstackinterface/app/src/main/java/org/onosproject/openstackinterface/web/OpenstackRouterCodec.java
@@ -68,7 +68,6 @@
         String tenantId = checkNotNull(routerInfo.path(TENANT_ID).asText());
         String id = checkNotNull(routerInfo.path(ID).asText());
         String name = checkNotNull(routerInfo.path(NAME).asText());
-        String status = checkNotNull(routerInfo.path(STATUS).asText());
         String adminStateUp = checkNotNull(routerInfo.path(ADMIN_STATE_UP).asText());
 
         OpenstackExternalGateway.Builder osExtBuiler = new OpenstackExternalGateway.Builder();
@@ -98,7 +97,7 @@
                 .tenantId(tenantId)
                 .id(id)
                 .name(name)
-                .status(OpenstackRouter.RouterStatus.valueOf(status))
+                .status(OpenstackRouter.RouterStatus.ACTIVE)
                 .adminStateUp(Boolean.valueOf(adminStateUp))
                 .gatewayExternalInfo(osExtBuiler.build());
 
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 0ab8681..d23f5f3 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
@@ -27,12 +27,13 @@
 /**
  * Contains OpenstackPort Information.
  */
-public class OpenstackPortInfo {
+public final class OpenstackPortInfo {
     private final Ip4Address hostIp;
     private final MacAddress hostMac;
     private final DeviceId deviceId;
     private final long vni;
     private final Ip4Address gatewayIP;
+    private final String networkId;
     private final Collection<String> securityGroups;
 
     /**
@@ -46,12 +47,13 @@
      * @param securityGroups security group list
      */
     public OpenstackPortInfo(Ip4Address hostIp, MacAddress hostMac, DeviceId deviceId, long vni,
-                             Ip4Address gatewayIP, Collection<String> securityGroups) {
+                             Ip4Address gatewayIP, String networkId, Collection<String> securityGroups) {
         this.hostIp = hostIp;
         this.hostMac = hostMac;
         this.deviceId = deviceId;
         this.vni = vni;
         this.gatewayIP = gatewayIP;
+        this.networkId = networkId;
         this.securityGroups = securityGroups;
     }
 
@@ -101,6 +103,15 @@
     }
 
     /**
+     * Returns network ID.
+     *
+     * @return network ID
+     */
+    public String networkId() {
+        return  networkId;
+    }
+
+    /**
      * Returns Security Group ID list.
      *
      * @return list of Security Group ID
@@ -129,11 +140,12 @@
         private long vni;
         private Ip4Address gatewayIP;
         private Collection<String> securityGroups;
+        private String networkId;
 
         /**
          * Sets the IP address of the port.
          *
-         * @param gatewayIP
+         * @param gatewayIP gateway IP
          * @return Builder reference
          */
         public Builder setGatewayIP(Ip4Address gatewayIP) {
@@ -142,6 +154,17 @@
         }
 
         /**
+         * Sets the network ID.
+         *
+         * @param networkId network id
+         * @return Builder reference
+         */
+        public Builder setNetworkId(String networkId) {
+            this.networkId = checkNotNull(networkId, "networkId cannot be null");
+            return this;
+        }
+
+        /**
          * Sets the host IP address of the port.
          *
          * @param hostIp host IP address
@@ -202,16 +225,7 @@
          * @return OpenstackPortInfo reference
          */
         public OpenstackPortInfo build() {
-            return new OpenstackPortInfo(this);
+            return new OpenstackPortInfo(hostIp, hostMac, deviceId, vni, gatewayIP, networkId, securityGroups);
         }
     }
-
-    private OpenstackPortInfo(Builder builder) {
-        hostIp = builder.hostIp;
-        hostMac = builder.hostMac;
-        deviceId = builder.deviceId;
-        vni = builder.vni;
-        gatewayIP = builder.gatewayIP;
-        securityGroups = builder.securityGroups;
-    }
 }
diff --git a/apps/openstacknetworking/network-cfg.json b/apps/openstacknetworking/network-cfg.json
index 170d482..142ec8a 100644
--- a/apps/openstacknetworking/network-cfg.json
+++ b/apps/openstacknetworking/network-cfg.json
@@ -1,40 +1,50 @@
 {
     "apps" : {
-      "org.onosproject.openstackswitching" : {
-          "openstackswitching" : {
-                "do_not_push_flows" : "false",
-                "neutron_server" : "http://192.168.56.103:9696/v2.0/",
-                "keystone_server" : "http://192.168.56.103:5000/v2.0/",
-                "user_name" : "admin",
-                "password" : "nova",
-                "physicalRouterMac" : "00:00:00:00:00:20",
+        "org.onosproject.openstackrouting" : {
+            "openstackrouting" : {
+                "physicalRouterMac" : "2a:a1:8a:89:dd:a4",
+                "gatewayBridgeId" : "of:0000000000000003",
+                "gatewayExternalInterfaceName" : "veth0",
+                "gatewayExternalInterfaceMac" : "be:15:c6:b0:df:9f"
+            }
+        },
+        "org.onosproject.openstacknode" : {
+            "openstacknode" : {
                 "nodes" : [
-                  {
-                      "hostname" : "compute-01",
-                                  "ovsdbIp" : "192.168.56.102",
-                                  "ovsdbPort" : "6640",
-                                  "bridgeId" : "of:0000000000000001",
-                                  "openstackNodeType" : "COMPUTENODE"
-                              },
-                              {
-                                  "hostname" : "compute-02",
-                                  "ovsdbIp" : "192.168.56.101",
-                                  "ovsdbPort" : "6640",
-                                  "bridgeId" : "of:0000000000000002",
-                                  "openstackNodeType" : "COMPUTENODE"
-                              },
-                              {
-                                  "hostname" : "network",
-                                  "ovsdbIp" : "192.168.56.106",
-                                  "ovsdbPort" : "6640",
-                                  "bridgeId" : "of:0000000000000003",
-                                  "openstackNodeType" : "GATEWAYNODE",
-                                  "externalIfName" : "eth3",
-                                  "externalIfMacAddress" : "00:00:00:00:00:11"
-                              }
+                            {
+                                    "hostname" : "compute-01",
+                                    "ovsdbIp" : "192.168.56.112",
+                                    "ovsdbPort" : "6640",
+                                    "bridgeId" : "of:0000000000000001",
+                                    "openstackNodeType" : "COMPUTENODE"
+                            },
+                            {
+                                    "hostname" : "compute-02",
+                                    "ovsdbIp" : "192.168.56.113",
+                                    "ovsdbPort" : "6640",
+                                    "bridgeId" : "of:0000000000000002",
+                                    "openstackNodeType" : "COMPUTENODE"
+                            },
+                            {
+                                    "hostname" : "network",
+                                    "ovsdbIp" : "192.168.56.114",
+                                    "ovsdbPort" : "6640",
+                                    "bridgeId" : "of:0000000000000003",
+                                    "openstackNodeType" : "GATEWAYNODE",
+                                    "gatewayExternalInterfaceName" : "veth0",
+                                    "gatewayExternalInterfaceMac" : "be:15:c6:b0:df:9f"
+                            }
                 ]
-              }
-          }
+            }
+        },
+        "org.onosproject.openstackinterface" : {
+            "openstackinterface" : {
+                 "neutron_server" : "http://192.168.56.111:9696/v2.0/",
+                 "keystone_server" : "http://192.168.56.111:5000/v2.0/",
+                 "user_name" : "admin",
+                 "password" : "nova"
+             }
+         }
     },
     "devices" : {
         "of:0000000000000001" : {
@@ -49,3 +59,4 @@
         }
     }
 }
+
diff --git a/apps/openstacknetworking/openstackrouting/src/main/java/org/onosproject/openstacknetworking/routing/OpenstackIcmpHandler.java b/apps/openstacknetworking/openstackrouting/src/main/java/org/onosproject/openstacknetworking/routing/OpenstackIcmpHandler.java
index 3cc11f0..9d8bd71 100644
--- a/apps/openstacknetworking/openstackrouting/src/main/java/org/onosproject/openstacknetworking/routing/OpenstackIcmpHandler.java
+++ b/apps/openstacknetworking/openstackrouting/src/main/java/org/onosproject/openstacknetworking/routing/OpenstackIcmpHandler.java
@@ -5,7 +5,7 @@
  * 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
+ * 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,
@@ -15,21 +15,260 @@
  */
 package org.onosproject.openstacknetworking.routing;
 
+import com.google.common.collect.Maps;
+import org.onlab.packet.Ethernet;
+import org.onlab.packet.ICMP;
+import org.onlab.packet.IPv4;
+import org.onlab.packet.Ip4Address;
+import org.onlab.packet.MacAddress;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.Port;
+import org.onosproject.net.PortNumber;
+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.packet.DefaultOutboundPacket;
+import org.onosproject.net.packet.OutboundPacket;
 import org.onosproject.net.packet.PacketContext;
+import org.onosproject.net.packet.PacketPriority;
+import org.onosproject.net.packet.PacketService;
+import org.onosproject.openstackinterface.OpenstackInterfaceService;
+import org.onosproject.openstackinterface.OpenstackPort;
+import org.onosproject.openstacknetworking.OpenstackPortInfo;
+import org.onosproject.openstacknetworking.OpenstackSwitchingService;
+import org.slf4j.Logger;
+
+import java.nio.ByteBuffer;
+import java.util.Map;
+import java.util.Optional;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import static org.slf4j.LoggerFactory.getLogger;
+
 
 /**
- * Handle ICMP packet processing for Managing Flow Rules In Openstack Nodes.
+ * Handle ICMP packet sent from Openstack Gateway nodes.
  */
-public class OpenstackIcmpHandler implements Runnable {
+public class OpenstackIcmpHandler {
+    protected final Logger log = getLogger(getClass());
 
-    volatile PacketContext context;
-    private OpenstackRoutingRulePopulator rulePopulator;
-    OpenstackIcmpHandler(OpenstackRoutingRulePopulator rulePopulator, PacketContext context) {
-        this.context = context;
-        this.rulePopulator = rulePopulator;
+    private final PacketService packetService;
+    private final DeviceService deviceService;
+    private final Map<String, OpenstackPortInfo> icmpInfoMap = Maps.newHashMap();
+    private final OpenstackSwitchingService openstackSwitchingService;
+    private final OpenstackInterfaceService openstackService;
+    private final OpenstackRoutingConfig config;
+    private static final MacAddress GATEWAY_MAC = MacAddress.valueOf("1f:1f:1f:1f:1f:1f");
+    private static final String NETWORK_ROUTER_INTERFACE = "network:router_interface";
+    private static final String PORTNAME = "portName";
+
+    /**
+     * Default constructor.
+     *
+     * @param packetService packet service
+     * @param deviceService device service
+     * @param openstackService openstackInterface service
+     * @param config openstackRoutingConfig
+     * @param openstackSwitchingService openstackSwitching service
+     */
+    OpenstackIcmpHandler(PacketService packetService, DeviceService deviceService,
+                         OpenstackInterfaceService openstackService, OpenstackRoutingConfig config,
+                         OpenstackSwitchingService openstackSwitchingService) {
+        this.packetService = packetService;
+        this.deviceService = deviceService;
+        this.openstackService = checkNotNull(openstackService);
+        this.config = checkNotNull(config);
+        this.openstackSwitchingService = checkNotNull(openstackSwitchingService);
     }
 
-    @Override
-    public void run() {
+    /**
+     * Requests ICMP packet.
+     *
+     * @param appId Application Id
+     */
+    public void requestPacket(ApplicationId appId) {
+        TrafficSelector icmpSelector = DefaultTrafficSelector.builder()
+                .matchEthType(Ethernet.TYPE_IPV4)
+                .matchIPProtocol(IPv4.PROTOCOL_ICMP)
+                .build();
+
+        packetService.requestPackets(icmpSelector,
+                PacketPriority.CONTROL,
+                appId,
+                Optional.of(DeviceId.deviceId(config.gatewayBridgeId())));
     }
-}
\ No newline at end of file
+
+    /**
+     * Handles ICMP packet.
+     *
+     * @param context packet context
+     * @param ethernet ethernet
+     */
+    public void processIcmpPacket(PacketContext context, Ethernet ethernet) {
+        checkNotNull(context, "context can not be null");
+        checkNotNull(ethernet, "ethernet can not be null");
+
+        IPv4 ipPacket = (IPv4) ethernet.getPayload();
+
+        log.debug("icmpEvent called from ip {}, mac {}", Ip4Address.valueOf(ipPacket.getSourceAddress()).toString(),
+                ethernet.getSourceMAC().toString());
+
+        ICMP icmp = (ICMP) ipPacket.getPayload();
+        short icmpId = getIcmpId(icmp);
+
+        DeviceId deviceId = context.inPacket().receivedFrom().deviceId();
+        if (icmp.getIcmpType() == ICMP.TYPE_ECHO_REQUEST) {
+            //TODO: Considers icmp between internal subnets which are belonged to the same router.
+
+            OpenstackPortInfo openstackPortInfo =
+                    getOpenstackPortInfo(Ip4Address.valueOf(ipPacket.getSourceAddress()), ethernet.getSourceMAC());
+
+            checkNotNull(openstackPortInfo, "openstackPortInfo can not be null");
+
+            if (ipPacket.getDestinationAddress() == openstackPortInfo.gatewayIP().toInt()) {
+                processIcmpPacketSentToGateway(ipPacket, icmp, openstackPortInfo);
+            } else {
+                Ip4Address pNatIpAddress = pNatIpForPort(openstackPortInfo);
+                checkNotNull(pNatIpAddress, "pNatIpAddress can not be null");
+
+                sendRequestPacketToExt(ipPacket, icmp, deviceId, pNatIpAddress);
+
+                String icmpInfoKey = String.valueOf(icmpId)
+                        .concat(String.valueOf(pNatIpAddress.toInt()))
+                        .concat(String.valueOf(ipPacket.getDestinationAddress()));
+                icmpInfoMap.putIfAbsent(icmpInfoKey, openstackPortInfo);
+            }
+        } else if (icmp.getIcmpType() == ICMP.TYPE_ECHO_REPLY) {
+            String icmpInfoKey = String.valueOf(icmpId)
+                    .concat(String.valueOf(ipPacket.getDestinationAddress()))
+                    .concat(String.valueOf(ipPacket.getSourceAddress()));
+
+            processResponsePacketFromExternalToHost(ipPacket, icmp, icmpInfoMap.get(icmpInfoKey));
+
+            icmpInfoMap.remove(icmpInfoKey);
+        }
+    }
+
+    private void processIcmpPacketSentToGateway(IPv4 icmpRequestIpv4, ICMP icmpRequest,
+                                                OpenstackPortInfo openstackPortInfo) {
+        icmpRequest.setIcmpType(ICMP.TYPE_ECHO_REPLY)
+                .resetChecksum();
+
+        icmpRequestIpv4.setSourceAddress(icmpRequestIpv4.getDestinationAddress())
+                .setDestinationAddress(openstackPortInfo.ip().toInt())
+                .resetChecksum();
+
+        icmpRequestIpv4.setPayload(icmpRequest);
+
+        Ethernet icmpResponseEth = new Ethernet();
+
+        icmpResponseEth.setEtherType(Ethernet.TYPE_IPV4)
+                .setSourceMACAddress(GATEWAY_MAC)
+                .setDestinationMACAddress(openstackPortInfo.mac())
+                .setPayload(icmpRequestIpv4);
+
+        sendResponsePacketToHost(icmpResponseEth, openstackPortInfo);
+    }
+
+    private void sendRequestPacketToExt(IPv4 icmpRequestIpv4, ICMP icmpRequest, DeviceId deviceId,
+                                        Ip4Address pNatIpAddress) {
+        icmpRequest.resetChecksum();
+        icmpRequestIpv4.setSourceAddress(pNatIpAddress.toInt())
+                .resetChecksum();
+        icmpRequestIpv4.setPayload(icmpRequest);
+
+        Ethernet icmpRequestEth = new Ethernet();
+
+        icmpRequestEth.setEtherType(Ethernet.TYPE_IPV4)
+                .setSourceMACAddress(MacAddress.valueOf(config.gatewayExternalInterfaceMac()))
+                .setDestinationMACAddress(MacAddress.valueOf(config.physicalRouterMac()))
+                .setPayload(icmpRequestIpv4);
+
+        TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+                .setOutput(getPortForAnnotationPortName(DeviceId.deviceId(config.gatewayBridgeId()),
+                        config.gatewayExternalInterfaceName()))
+                .build();
+
+        OutboundPacket packet = new DefaultOutboundPacket(deviceId,
+                treatment, ByteBuffer.wrap(icmpRequestEth.serialize()));
+
+        packetService.emit(packet);
+    }
+
+    private void processResponsePacketFromExternalToHost(IPv4 icmpResponseIpv4, ICMP icmpResponse,
+                                                         OpenstackPortInfo openstackPortInfo) {
+        icmpResponse.resetChecksum();
+
+        icmpResponseIpv4.setDestinationAddress(openstackPortInfo.ip().toInt())
+                .resetChecksum();
+        icmpResponseIpv4.setPayload(icmpResponse);
+
+        Ethernet icmpResponseEth = new Ethernet();
+
+        icmpResponseEth.setEtherType(Ethernet.TYPE_IPV4)
+                .setSourceMACAddress(GATEWAY_MAC)
+                .setDestinationMACAddress(openstackPortInfo.mac())
+                .setPayload(icmpResponseIpv4);
+
+        sendResponsePacketToHost(icmpResponseEth, openstackPortInfo);
+    }
+
+    private void sendResponsePacketToHost(Ethernet icmpResponseEth, OpenstackPortInfo openstackPortInfo) {
+        Map.Entry<String, OpenstackPortInfo> entry = openstackSwitchingService.openstackPortInfo().entrySet().stream()
+                .filter(e -> e.getValue().mac().equals(openstackPortInfo.mac()))
+                .findAny().orElse(null);
+
+        if (entry == null) {
+            return;
+        }
+
+        TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+                .setOutput(getPortForAnnotationPortName(openstackPortInfo.deviceId(), entry.getKey()))
+                .build();
+
+        OutboundPacket packet = new DefaultOutboundPacket(openstackPortInfo.deviceId(),
+                treatment, ByteBuffer.wrap(icmpResponseEth.serialize()));
+
+        packetService.emit(packet);
+    }
+
+    private OpenstackPortInfo getOpenstackPortInfo(Ip4Address sourceIp, MacAddress sourceMac) {
+        checkNotNull(openstackSwitchingService.openstackPortInfo(), "openstackportinfo collection can not be null");
+
+        return openstackSwitchingService.openstackPortInfo().values()
+                .stream().filter(p -> p.ip().equals(sourceIp) && p.mac().equals(sourceMac))
+                .findAny().orElse(null);
+    }
+
+    private short getIcmpId(ICMP icmp) {
+        return ByteBuffer.wrap(icmp.serialize(), 4, 2).getShort();
+    }
+
+    private Ip4Address pNatIpForPort(OpenstackPortInfo openstackPortInfo) {
+
+        OpenstackPort openstackPort = openstackService.ports().stream()
+                .filter(p -> p.deviceOwner().equals(NETWORK_ROUTER_INTERFACE) &&
+                        p.networkId().equals(openstackPortInfo.networkId()))
+                .findAny().orElse(null);
+
+        checkNotNull(openstackPort, "openstackPort can not be null");
+
+        return openstackService.router(openstackPort.deviceId())
+                .gatewayExternalInfo().externalFixedIps().values()
+                .stream().findAny().orElse(null);
+    }
+
+    private PortNumber getPortForAnnotationPortName(DeviceId deviceId, String match) {
+        Port port = deviceService.getPorts(deviceId).stream()
+                .filter(p -> p.annotations().value(PORTNAME).equals(match))
+                .findAny().orElse(null);
+
+        checkNotNull(port, "port cannot be null");
+
+        return port.number();
+    }
+}
diff --git a/apps/openstacknetworking/openstackrouting/src/main/java/org/onosproject/openstacknetworking/routing/OpenstackRoutingArpHandler.java b/apps/openstacknetworking/openstackrouting/src/main/java/org/onosproject/openstacknetworking/routing/OpenstackRoutingArpHandler.java
new file mode 100644
index 0000000..8ae7282
--- /dev/null
+++ b/apps/openstacknetworking/openstackrouting/src/main/java/org/onosproject/openstacknetworking/routing/OpenstackRoutingArpHandler.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright 2016 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.routing;
+
+import org.onlab.packet.ARP;
+import org.onlab.packet.EthType;
+import org.onlab.packet.Ethernet;
+import org.onlab.packet.IPv4;
+import org.onlab.packet.Ip4Address;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.MacAddress;
+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.packet.DefaultOutboundPacket;
+import org.onosproject.net.packet.PacketContext;
+import org.onosproject.net.packet.PacketPriority;
+import org.onosproject.net.packet.PacketService;
+import org.onosproject.openstackinterface.OpenstackInterfaceService;
+import org.onosproject.openstackinterface.OpenstackPort;
+import org.slf4j.Logger;
+
+import java.nio.ByteBuffer;
+import java.util.Optional;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Handle ARP packet sent from Openstack Gateway nodes.
+ */
+public class OpenstackRoutingArpHandler {
+    protected final Logger log = getLogger(getClass());
+
+    private final PacketService packetService;
+    private final OpenstackInterfaceService openstackService;
+    private final OpenstackRoutingConfig config;
+    private static final String NETWORK_ROUTER_GATEWAY = "network:router_gateway";
+
+    /**
+     * Default constructor.
+     *
+     * @param packetService packet service
+     * @param openstackService openstackInterface service
+     * @param config openstackRoutingConfig
+     */
+    OpenstackRoutingArpHandler(PacketService packetService, OpenstackInterfaceService openstackService,
+                               OpenstackRoutingConfig config) {
+        this.packetService = packetService;
+        this.openstackService = checkNotNull(openstackService);
+        this.config = checkNotNull(config);
+    }
+
+    /**
+     * Requests ARP packet to GatewayNode.
+     *
+     * @param appId application id
+     */
+    public void requestPacket(ApplicationId appId) {
+
+        TrafficSelector arpSelector = DefaultTrafficSelector.builder()
+                .matchEthType(EthType.EtherType.ARP.ethType().toShort())
+                .build();
+
+        packetService.requestPackets(arpSelector,
+                PacketPriority.CONTROL,
+                appId,
+                Optional.of(DeviceId.deviceId(config.gatewayBridgeId())));
+    }
+
+    /**
+     * Handles ARP packet.
+     *
+     * @param context packet context
+     * @param ethernet ethernet
+     */
+    public void processArpPacketFromRouter(PacketContext context, Ethernet ethernet) {
+        checkNotNull(context, "context can not be null");
+        checkNotNull(ethernet, "ethernet can not be null");
+
+        log.info("arpEvent called from {} to {}",
+                Ip4Address.valueOf(((IPv4) ethernet.getPayload()).getSourceAddress()).toString(),
+                Ip4Address.valueOf(((IPv4) ethernet.getPayload()).getDestinationAddress()).toString());
+        ARP arp = (ARP) ethernet.getPayload();
+
+        if (arp.getOpCode() != ARP.OP_REQUEST) {
+            return;
+        }
+
+        IpAddress targetIp = Ip4Address.valueOf(arp.getTargetProtocolAddress());
+        MacAddress targetMac = getTargetMacForTargetIp(targetIp.getIp4Address());
+
+        if (targetMac == MacAddress.NONE) {
+            return;
+        }
+
+        Ethernet ethReply = ARP.buildArpReply(targetIp.getIp4Address(),
+                targetMac, ethernet);
+
+        TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+                .setOutput(context.inPacket().receivedFrom().port())
+                .build();
+
+        packetService.emit(new DefaultOutboundPacket(
+                context.inPacket().receivedFrom().deviceId(),
+                treatment,
+                ByteBuffer.wrap(ethReply.serialize())));
+    }
+
+    private MacAddress getTargetMacForTargetIp(Ip4Address targetIp) {
+        OpenstackPort port = openstackService.ports().stream()
+                .filter(p -> p.deviceOwner().equals(NETWORK_ROUTER_GATEWAY))
+                .filter(p -> p.fixedIps().containsValue(targetIp.getIp4Address()))
+                .findAny().orElse(null);
+
+        if (port == null) {
+            return MacAddress.NONE;
+        }
+        return port.macAddress();
+    }
+}
diff --git a/apps/openstacknetworking/openstackrouting/src/main/java/org/onosproject/openstacknetworking/routing/OpenstackRoutingConfig.java b/apps/openstacknetworking/openstackrouting/src/main/java/org/onosproject/openstacknetworking/routing/OpenstackRoutingConfig.java
new file mode 100644
index 0000000..0656a94
--- /dev/null
+++ b/apps/openstacknetworking/openstackrouting/src/main/java/org/onosproject/openstacknetworking/routing/OpenstackRoutingConfig.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2016 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.routing;
+
+import org.onosproject.core.ApplicationId;
+import org.onosproject.net.config.Config;
+import org.slf4j.Logger;
+
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Configuration object for OpenstackRouting service.
+ */
+public class OpenstackRoutingConfig extends Config<ApplicationId> {
+    protected final Logger log = getLogger(getClass());
+
+    public static final String PHYSICAL_ROUTER_MAC = "physicalRouterMac";
+    public static final String GATEWAY_BRIDGE_ID = "gatewayBridgeId";
+    public static final String GATEWAY_EXTERNAL_INTERFACE_NAME = "gatewayExternalInterfaceName";
+    public static final String GATEWAY_EXTERNAL_INTERFACE_MAC = "gatewayExternalInterfaceMac";
+
+    /**
+     * Returns physical router mac.
+     *
+     * @return physical router mac
+     */
+    public String physicalRouterMac() {
+        return this.get("physicalRouterMac", "");
+    }
+
+    /**
+     * Returns gateway's bridge id.
+     *
+     * @return bridge id
+     */
+    public String gatewayBridgeId() {
+        return this.get("gatewayBridgeId", "");
+    }
+
+    /**
+     * Returns gateway's external interface name.
+     *
+     * @return external interface name
+     */
+    public String gatewayExternalInterfaceName() {
+        return this.get("gatewayExternalInterfaceName", "");
+    }
+
+    /**
+     * Returns gateway's external interface mac.
+     *
+     * @return external interface mac
+     */
+    public String gatewayExternalInterfaceMac() {
+        return this.get("gatewayExternalInterfaceMac", "");
+    }
+}
diff --git a/apps/openstacknetworking/openstackrouting/src/main/java/org/onosproject/openstacknetworking/routing/OpenstackRoutingManager.java b/apps/openstacknetworking/openstackrouting/src/main/java/org/onosproject/openstacknetworking/routing/OpenstackRoutingManager.java
index b1c0a74..2ab19ac 100644
--- a/apps/openstacknetworking/openstackrouting/src/main/java/org/onosproject/openstacknetworking/routing/OpenstackRoutingManager.java
+++ b/apps/openstacknetworking/openstackrouting/src/main/java/org/onosproject/openstacknetworking/routing/OpenstackRoutingManager.java
@@ -32,6 +32,12 @@
 import org.onosproject.core.CoreService;
 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.config.basics.SubjectFactories;
 import org.onosproject.net.device.DeviceService;
 import org.onosproject.net.driver.DriverService;
 import org.onosproject.net.flowobjective.FlowObjectiveService;
@@ -45,6 +51,7 @@
 import org.onosproject.openstackinterface.OpenstackRouter;
 import org.onosproject.openstackinterface.OpenstackRouterInterface;
 import org.onosproject.openstacknetworking.OpenstackRoutingService;
+import org.onosproject.openstacknetworking.OpenstackSwitchingService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -80,24 +87,44 @@
     protected OpenstackInterfaceService openstackService;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected OpenstackSwitchingService openstackSwitchingService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected FlowObjectiveService flowObjectiveService;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected DriverService driverService;
 
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected NetworkConfigService configService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected NetworkConfigRegistry configRegistry;
+
+
+
     private ApplicationId appId;
     private Map<String, OpenstackRouterInterface> routerInterfaceMap = Maps.newHashMap();
     private Map<Integer, String> portNumMap = initPortNumMap();
     private static final String APP_ID = "org.onosproject.openstackrouting";
     private static final String PORT_NAME = "portName";
     private static final String DEVICE_OWNER_ROUTER_INTERFACE = "network:router_interface";
+    private final ConfigFactory configFactory =
+            new ConfigFactory(SubjectFactories.APP_SUBJECT_FACTORY, OpenstackRoutingConfig.class, "openstackrouting") {
+                @Override
+                public OpenstackRoutingConfig createConfig() {
+                    return new OpenstackRoutingConfig();
+                }
+            };
+    private final NetworkConfigListener configListener = new InternalConfigListener();
 
-    // TODO: This will be replaced to get the information from openstackswitchingservice.
-    private static final String EXTERNAL_INTERFACE_NAME = "veth0";
+    private OpenstackRoutingConfig config;
+    private static final int PNAT_PORT_NUM_START = 1024;
+    private static final int PNAT_PORT_NUM_END = 65535;
 
     private Map<Integer, String> initPortNumMap() {
         Map<Integer, String> map = Maps.newHashMap();
-        for (int i = 1024; i < 65535; i++) {
+        for (int i = PNAT_PORT_NUM_START; i < PNAT_PORT_NUM_END; i++) {
             map.put(i, "");
         }
         return map;
@@ -108,17 +135,30 @@
             Executors.newSingleThreadExecutor(groupedThreads("onos/openstackrouting", "L3-event"));
     private ExecutorService icmpEventExecutorService =
             Executors.newSingleThreadExecutor(groupedThreads("onos/openstackrouting", "icmp-event"));
+    private ExecutorService arpEventExecutorService =
+            Executors.newSingleThreadExecutor(groupedThreads("onos/openstackrouting", "arp-event"));
+    private OpenstackIcmpHandler openstackIcmpHandler;
+    private OpenstackRoutingArpHandler openstackArpHandler;
 
     @Activate
     protected void activate() {
         appId = coreService.registerApplication(APP_ID);
         packetService.addProcessor(internalPacketProcessor, PacketProcessor.director(1));
+        configRegistry.registerConfigFactory(configFactory);
+        configService.addListener(configListener);
+
+        readConfiguration();
+
         log.info("onos-openstackrouting started");
     }
 
     @Deactivate
     protected void deactivate() {
         packetService.removeProcessor(internalPacketProcessor);
+        l3EventExecutorService.shutdown();
+        icmpEventExecutorService.shutdown();
+        arpEventExecutorService.shutdown();
+
         log.info("onos-openstackrouting stopped");
     }
 
@@ -155,16 +195,16 @@
 
     @Override
     public void updateRouterInterface(OpenstackRouterInterface routerInterface) {
-        routerInterfaceMap.putIfAbsent(routerInterface.portId(), routerInterface);
+        routerInterfaceMap.putIfAbsent(routerInterface.id(), routerInterface);
         List<OpenstackRouterInterface> routerInterfaces = Lists.newArrayList();
         routerInterfaces.add(routerInterface);
-        checkExternalConnection(getOpenstackRouter(routerInterface.portId()), routerInterfaces);
+        checkExternalConnection(getOpenstackRouter(routerInterface.id()), routerInterfaces);
     }
 
     @Override
     public void removeRouterInterface(OpenstackRouterInterface routerInterface) {
         OpenstackRoutingRulePopulator rulePopulator = new OpenstackRoutingRulePopulator(appId,
-                openstackService, flowObjectiveService, deviceService, driverService);
+                openstackService, flowObjectiveService, deviceService, driverService, config);
         rulePopulator.removeExternalRules(routerInterface);
         routerInterfaceMap.remove(routerInterface.portId());
     }
@@ -181,10 +221,10 @@
 
     private OpenstackRouterInterface portToRouterInterface(OpenstackPort p) {
         OpenstackRouterInterface.Builder osBuilder = new OpenstackRouterInterface.Builder()
-                .id(checkNotNull(p.id()))
+                .id(checkNotNull(p.deviceId()))
                 .tenantId(checkNotNull(openstackService.network(p.networkId()).tenantId()))
                 .subnetId(checkNotNull(p.fixedIps().keySet().stream().findFirst().orElse(null)).toString())
-                .portId(checkNotNull(p.deviceId()));
+                .portId(checkNotNull(p.id()));
 
         return osBuilder.build();
     }
@@ -196,19 +236,26 @@
 
             if (context.isHandled()) {
                 return;
+            } else if (!context.inPacket().receivedFrom().deviceId().toString()
+                    .equals(config.gatewayBridgeId())) {
+                return;
             }
 
             InboundPacket pkt = context.inPacket();
             Ethernet ethernet = pkt.parsed();
 
-            if (ethernet != null && ethernet.getEtherType() == Ethernet.TYPE_IPV4) {
+            //TODO: Considers IPv6 later.
+            if (ethernet == null) {
+                return;
+            } else if (ethernet.getEtherType() == Ethernet.TYPE_IPV4) {
                 IPv4 iPacket = (IPv4) ethernet.getPayload();
                 OpenstackRoutingRulePopulator rulePopulator = new OpenstackRoutingRulePopulator(appId,
-                        openstackService, flowObjectiveService, deviceService,
-                        driverService);
+                        openstackService, flowObjectiveService, deviceService, driverService, config);
                 switch (iPacket.getProtocol()) {
                     case IPv4.PROTOCOL_ICMP:
-                        icmpEventExecutorService.execute(new OpenstackIcmpHandler(rulePopulator, context));
+
+                        icmpEventExecutorService.submit(() ->
+                                openstackIcmpHandler.processIcmpPacket(context, ethernet));
                         break;
                     case IPv4.PROTOCOL_UDP:
                         // don't process DHCP
@@ -219,7 +266,8 @@
                         }
                     default:
                         int portNum = getPortNum(ethernet.getSourceMAC(), iPacket.getDestinationAddress());
-                        Port port = getExternalPort(pkt.receivedFrom().deviceId(), EXTERNAL_INTERFACE_NAME);
+                        Port port =
+                                getExternalPort(pkt.receivedFrom().deviceId(), config.gatewayExternalInterfaceName());
                         if (port == null) {
                             log.warn("There`s no external interface");
                             break;
@@ -230,7 +278,9 @@
                                 portNum, openstackPort, port));
                         break;
                 }
-
+            } else if (ethernet.getEtherType() == Ethernet.TYPE_ARP) {
+                arpEventExecutorService.submit(() ->
+                        openstackArpHandler.processArpPacketFromRouter(context, ethernet));
             }
         }
 
@@ -265,9 +315,9 @@
 
     private void initiateL3Rule(OpenstackRouter router, OpenstackRouterInterface routerInterface) {
         long vni = Long.parseLong(openstackService.network(openstackService
-                .port(routerInterface.id()).networkId()).segmentId());
+                .port(routerInterface.portId()).networkId()).segmentId());
         OpenstackRoutingRulePopulator rulePopulator = new OpenstackRoutingRulePopulator(appId,
-                openstackService, flowObjectiveService, deviceService, driverService);
+                openstackService, flowObjectiveService, deviceService, driverService, config);
         rulePopulator.populateExternalRules(vni, router, routerInterface);
     }
 
@@ -288,4 +338,50 @@
                 .equals(ip4Address) ? openstackPort : null;
     }
 
+    private void readConfiguration() {
+        config = configService.getConfig(appId, OpenstackRoutingConfig.class);
+        if (config == null) {
+            log.error("No configuration found");
+            return;
+        }
+
+        checkNotNull(config.physicalRouterMac());
+        checkNotNull(config.gatewayBridgeId());
+        checkNotNull(config.gatewayExternalInterfaceMac());
+        checkNotNull(config.gatewayExternalInterfaceName());
+
+        log.debug("Configured info: {}, {}, {}, {}", config.physicalRouterMac(), config.gatewayBridgeId(),
+                config.gatewayExternalInterfaceMac(), config.gatewayExternalInterfaceName());
+
+        reloadInitL3Rules();
+
+        openstackIcmpHandler = new OpenstackIcmpHandler(packetService, deviceService,
+                openstackService, config, openstackSwitchingService);
+        openstackArpHandler = new OpenstackRoutingArpHandler(packetService, openstackService, config);
+
+        openstackIcmpHandler.requestPacket(appId);
+        openstackArpHandler.requestPacket(appId);
+
+        log.info("OpenstackRouting configured");
+    }
+
+    private class InternalConfigListener implements NetworkConfigListener {
+
+        @Override
+        public void event(NetworkConfigEvent event) {
+            if (!event.configClass().equals(OpenstackRoutingConfig.class)) {
+                return;
+            }
+
+            switch (event.type()) {
+                case CONFIG_ADDED:
+                case CONFIG_UPDATED:
+                    l3EventExecutorService.execute(OpenstackRoutingManager.this::readConfiguration);
+                    break;
+                default:
+                    log.debug("Unsupported event type {}", event.type().toString());
+                    break;
+            }
+        }
+    }
 }
diff --git a/apps/openstacknetworking/openstackrouting/src/main/java/org/onosproject/openstacknetworking/routing/OpenstackRoutingRulePopulator.java b/apps/openstacknetworking/openstackrouting/src/main/java/org/onosproject/openstacknetworking/routing/OpenstackRoutingRulePopulator.java
index b226001..ab1d360 100644
--- a/apps/openstacknetworking/openstackrouting/src/main/java/org/onosproject/openstacknetworking/routing/OpenstackRoutingRulePopulator.java
+++ b/apps/openstacknetworking/openstackrouting/src/main/java/org/onosproject/openstacknetworking/routing/OpenstackRoutingRulePopulator.java
@@ -71,6 +71,7 @@
     private final OpenstackInterfaceService openstackService;
     private final DeviceService deviceService;
     private final DriverService driverService;
+    private final OpenstackRoutingConfig config;
 
     private static final String PORTNAME_PREFIX_VM = "tap";
     private static final String PORTNAME_PREFIX_ROUTER = "qr";
@@ -93,9 +94,6 @@
     private OpenstackRouter router;
     private OpenstackRouterInterface routerInterface;
 
-    // TODO: This will be replaced to get the information from openstackswitchingservice.
-    private static final String EXTERNAL_INTERFACE_NAME = "veth0";
-
     /**
      * The constructor of openstackRoutingRulePopulator.
      *
@@ -104,20 +102,23 @@
      * @param flowObjectiveService FlowObjectiveService
      * @param deviceService DeviceService
      * @param driverService DriverService
+     * @param config OpenstackRoutingConfig
      */
     public OpenstackRoutingRulePopulator(ApplicationId appId, OpenstackInterfaceService openstackService,
-                                         FlowObjectiveService flowObjectiveService,
-                                         DeviceService deviceService, DriverService driverService) {
+                                         FlowObjectiveService flowObjectiveService, DeviceService deviceService,
+                                         DriverService driverService, OpenstackRoutingConfig config) {
         this.appId = appId;
         this.flowObjectiveService = flowObjectiveService;
-        this.openstackService = openstackService;
+        this.openstackService = checkNotNull(openstackService);
         this.deviceService = deviceService;
         this.driverService = driverService;
+        this.config = config;
     }
 
     /**
      * Populates flow rules for Pnat configurations.
-     *  @param inboundPacket Packet-in event packet
+     *
+     * @param inboundPacket Packet-in event packet
      * @param openstackPort Target VM information
      * @param portNum Pnat port number
      * @param externalIp external ip address
@@ -168,6 +169,7 @@
                 tBuilder.setUdpSrc(TpPort.tpPort(portNum));
                 break;
             default:
+                log.debug("Unsupported IPv4 protocol {}");
                 break;
         }
 
@@ -188,7 +190,7 @@
 
     private Port getPortNumOfExternalInterface() {
         return deviceService.getPorts(inboundPacket.receivedFrom().deviceId()).stream()
-                .filter(p -> p.annotations().value(PORTNAME).equals(EXTERNAL_INTERFACE_NAME))
+                .filter(p -> p.annotations().value(PORTNAME).equals(config.gatewayExternalInterfaceName()))
                 .findAny().orElse(null);
     }
 
@@ -239,7 +241,15 @@
         flowObjectiveService.forward(inboundPacket.receivedFrom().deviceId(), fo);
     }
 
-    private ExtensionTreatment buildNiciraExtenstion(DeviceId id, Ip4Address hostIp) {
+    /**
+     * Returns NiciraExtension treatment.
+     *
+     * @param id device id
+     * @param hostIp host ip
+     * @return NiciraExtension treatment
+     */
+
+    public 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);
@@ -257,7 +267,13 @@
         return extensionInstruction;
     }
 
-    private PortNumber getTunnelPort(DeviceId deviceId) {
+    /**
+     * Returns port number of vxlan tunnel.
+     *
+     * @param deviceId device id
+     * @return port number of vxlan tunnel
+     */
+    public PortNumber getTunnelPort(DeviceId deviceId) {
         Port port = deviceService.getPorts(deviceId).stream()
                 .filter(p -> p.annotations().value(PORTNAME).equals(PORTNAME_PREFIX_TUNNEL))
                 .findAny().orElse(null);
@@ -343,16 +359,11 @@
     }
 
     private Device getGatewayNode() {
-        return checkNotNull(StreamSupport.stream(deviceService.getAvailableDevices().spliterator(), false)
-                .filter(d -> checkGatewayNode(d.id()))
-                .findAny()
-                .orElse(null));
+        return checkNotNull(deviceService.getDevice(DeviceId.deviceId(config.gatewayBridgeId())));
     }
 
     private boolean checkGatewayNode(DeviceId deviceId) {
-        return !deviceService.getPorts(deviceId).stream().anyMatch(port ->
-                port.annotations().value(PORTNAME).startsWith(PORTNAME_PREFIX_ROUTER) ||
-                        port.annotations().value(PORTNAME).startsWith(PORTNAME_PREFIX_VM));
+        return deviceId.toString().equals(config.gatewayBridgeId());
     }
 
     private long getVni(OpenstackPort openstackPort) {
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
index 2c88b3a..7cc974f 100644
--- 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
@@ -94,6 +94,7 @@
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected DriverService driverService;
 
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected OpenstackInterfaceService openstackService;
 
     public static final String PORTNAME_PREFIX_VM = "tap";
@@ -126,6 +127,7 @@
         packetService.addProcessor(internalPacketProcessor, PacketProcessor.director(1));
         deviceService.addListener(internalDeviceListener);
         hostService.addListener(internalHostListener);
+        arpHandler = new OpenstackArpHandler(openstackService, packetService, hostService);
 
         arpHandler = new OpenstackArpHandler(openstackService, packetService, hostService);
         sgRulePopulator = new OpenstackSecurityGroupRulePopulator(appId, openstackService, flowObjectiveService);
@@ -204,10 +206,12 @@
 
     @Override
     public void createNetwork(OpenstackNetwork openstackNetwork) {
+        //TODO
     }
 
     @Override
     public void createSubnet(OpenstackSubnet openstackSubnet) {
+        //TODO
     }
 
     @Override
@@ -296,9 +300,17 @@
 
     private void updatePortMap(DeviceId deviceId, String portName, Collection<OpenstackNetwork> networks,
                                Collection<OpenstackSubnet> subnets, OpenstackPort openstackPort) {
-        long vni = Long.parseLong(networks.stream()
+        long vni;
+        OpenstackNetwork openstackNetwork = networks.stream()
                 .filter(n -> n.id().equals(openstackPort.networkId()))
-                .findAny().orElse(null).segmentId());
+                .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()))
@@ -312,6 +324,7 @@
                 .setHostMac(openstackPort.macAddress())
                 .setVni(vni)
                 .setGatewayIP(gatewayIPAddress)
+                .setNetworkId(openstackPort.networkId())
                 .setSecurityGroups(openstackPort.securityGroups());
 
         openstackPortInfoMap.put(portName, portBuilder.build());
@@ -321,7 +334,6 @@
                 securityGroupMap.put(sgId, openstackService.getSecurityGroup(sgId));
             }
         });
-
     }
 
     private void processHostRemoved(Host host) {
@@ -440,6 +452,7 @@
                         processPortRemoved((Device) deviceEvent.subject(), deviceEvent.port());
                         break;
                     default:
+                        log.debug("Unsupported deviceEvent type {}", deviceEvent.type().toString());
                         break;
                 }
             } else if (event instanceof HostEvent) {
@@ -450,6 +463,7 @@
                         processHostRemoved((Host) hostEvent.subject());
                         break;
                     default:
+                        log.debug("Unsupported hostEvent type {}", hostEvent.type().toString());
                         break;
                 }
             }