[ONOS-3801] Implements L3 REST call json parser
- Nullability check for RouterCodec, RoutingInterfaceCodec, RoutingWebResource.
- Copyright fixed.
- externalFixedIps() method in OpenstackExternalGateway class returns the immutable Map.

Change-Id: I841cc1774a074e167ffe327c6e81d3f245cc8ee0
diff --git a/apps/openstackrouting/src/main/java/org/onosproject/openstackrouting/OpenstackExternalGateway.java b/apps/openstackrouting/src/main/java/org/onosproject/openstackrouting/OpenstackExternalGateway.java
index c435ab7..ac70701 100644
--- a/apps/openstackrouting/src/main/java/org/onosproject/openstackrouting/OpenstackExternalGateway.java
+++ b/apps/openstackrouting/src/main/java/org/onosproject/openstackrouting/OpenstackExternalGateway.java
@@ -15,9 +15,11 @@
  */
 package org.onosproject.openstackrouting;
 
+import com.google.common.collect.ImmutableMap;
 import org.onlab.packet.Ip4Address;
 
 import java.util.HashMap;
+import java.util.Map;
 
 /**
  * A configurable external gateway modes extension model in openstack router.
@@ -26,15 +28,18 @@
 
     private String networkId;
     private boolean enablePnat;
-    private HashMap<String, Ip4Address> externalFixedIps;
+    private Map<String, Ip4Address> externalFixedIps;
 
     private OpenstackExternalGateway(String networkId, boolean enablePnat,
-                                     HashMap externalFixedIps) {
+                                     Map<String, Ip4Address> externalFixedIps) {
         this.networkId = networkId;
         this.enablePnat = enablePnat;
         this.externalFixedIps = externalFixedIps;
     }
 
+    public static OpenstackExternalGateway.Builder builder() {
+        return new Builder();
+    }
     /**
      * Returns network ID.
      *
@@ -53,13 +58,17 @@
         return enablePnat;
     }
 
+    public Map<String, Ip4Address> externalFixedIps() {
+        return ImmutableMap.copyOf(externalFixedIps);
+    }
+
     /**
      * An Openstack External Gateway Builder class.
      */
     public static final class Builder {
         private String networkId;
         private boolean enablePnat;
-        private HashMap<String, Ip4Address> externalFixedIps;
+        private Map<String, Ip4Address> externalFixedIps;
 
         Builder() {
             externalFixedIps = new HashMap<>();
@@ -90,11 +99,12 @@
         /**
          * Sets external fixed IP address information.
          *
-         * @param externalFixedIPs External fixed IP information
+         * @param externalFixedIps External fixed IP information
          * @return Builder object
          */
-        public Builder externalFixedIps(HashMap<String, Ip4Address> externalFixedIPs) {
-            this.externalFixedIps.putAll(externalFixedIPs);
+
+        public Builder externalFixedIps(Map<String, Ip4Address> externalFixedIps) {
+            this.externalFixedIps.putAll(externalFixedIps);
             return this;
         }
 
diff --git a/apps/openstackrouting/src/main/java/org/onosproject/openstackrouting/OpenstackIcmpHandler.java b/apps/openstackrouting/src/main/java/org/onosproject/openstackrouting/OpenstackIcmpHandler.java
index 7186903..67c6724 100644
--- a/apps/openstackrouting/src/main/java/org/onosproject/openstackrouting/OpenstackIcmpHandler.java
+++ b/apps/openstackrouting/src/main/java/org/onosproject/openstackrouting/OpenstackIcmpHandler.java
@@ -31,4 +31,4 @@
     public void run() {
 
     }
-}
+}
\ No newline at end of file
diff --git a/apps/openstackrouting/src/main/java/org/onosproject/openstackrouting/OpenstackPnatHandler.java b/apps/openstackrouting/src/main/java/org/onosproject/openstackrouting/OpenstackPnatHandler.java
index 60ec31b..e1c9df8 100644
--- a/apps/openstackrouting/src/main/java/org/onosproject/openstackrouting/OpenstackPnatHandler.java
+++ b/apps/openstackrouting/src/main/java/org/onosproject/openstackrouting/OpenstackPnatHandler.java
@@ -31,4 +31,4 @@
     public void run() {
 
     }
-}
+}
\ No newline at end of file
diff --git a/apps/openstackrouting/src/main/java/org/onosproject/openstackrouting/OpenstackRouter.java b/apps/openstackrouting/src/main/java/org/onosproject/openstackrouting/OpenstackRouter.java
index 213ca28..fc858fc 100644
--- a/apps/openstackrouting/src/main/java/org/onosproject/openstackrouting/OpenstackRouter.java
+++ b/apps/openstackrouting/src/main/java/org/onosproject/openstackrouting/OpenstackRouter.java
@@ -44,6 +44,10 @@
 
     }
 
+    public static OpenstackRouter.Builder builder() {
+        return new Builder();
+    }
+
     /**
      * Returns tenant ID.
      *
diff --git a/apps/openstackrouting/src/main/java/org/onosproject/openstackrouting/OpenstackRoutingManager.java b/apps/openstackrouting/src/main/java/org/onosproject/openstackrouting/OpenstackRoutingManager.java
index ae41bf2..5bfc5ea 100644
--- a/apps/openstackrouting/src/main/java/org/onosproject/openstackrouting/OpenstackRoutingManager.java
+++ b/apps/openstackrouting/src/main/java/org/onosproject/openstackrouting/OpenstackRoutingManager.java
@@ -124,10 +124,9 @@
     }
 
     @Override
-    public void deleteRouterInterface(String id) {
+    public void removeRouterInterface(OpenstackRouterInterface openstackRouterInterface) {
 
     }
-
     private class InternalPacketProcessor implements PacketProcessor {
 
         @Override
diff --git a/apps/openstackrouting/src/main/java/org/onosproject/openstackrouting/OpenstackRoutingService.java b/apps/openstackrouting/src/main/java/org/onosproject/openstackrouting/OpenstackRoutingService.java
index aca25fb..3840cb2 100644
--- a/apps/openstackrouting/src/main/java/org/onosproject/openstackrouting/OpenstackRoutingService.java
+++ b/apps/openstackrouting/src/main/java/org/onosproject/openstackrouting/OpenstackRoutingService.java
@@ -77,11 +77,11 @@
     void updateRouterInterface(OpenstackRouterInterface openstackRouterInterface);
 
     /**
-     * Removes flow rules corresponding to the router information deleted by Openstack.
+     * Removes flow rules corresponding to the router information removed by Openstack.
      *
-     * @param id Deleted router`s ID
+     * @param openstackRouterInterface Router information
      */
-    void deleteRouterInterface(String id);
+    void removeRouterInterface(OpenstackRouterInterface openstackRouterInterface);
 
 
 }
diff --git a/apps/openstackswitching/app/src/main/java/org/onosproject/openstackswitching/impl/OpenstackPortInfo.java b/apps/openstackswitching/api/src/main/java/org/onosproject/openstackswitching/OpenstackPortInfo.java
similarity index 81%
rename from apps/openstackswitching/app/src/main/java/org/onosproject/openstackswitching/impl/OpenstackPortInfo.java
rename to apps/openstackswitching/api/src/main/java/org/onosproject/openstackswitching/OpenstackPortInfo.java
index 1b6250e..45b6f59 100644
--- a/apps/openstackswitching/app/src/main/java/org/onosproject/openstackswitching/impl/OpenstackPortInfo.java
+++ b/apps/openstackswitching/api/src/main/java/org/onosproject/openstackswitching/OpenstackPortInfo.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2014-2015 Open Networking Laboratory
+ * Copyright 2015 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.
@@ -13,30 +13,29 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.onosproject.openstackswitching.impl;
+package org.onosproject.openstackswitching;
 
 import org.onlab.packet.Ip4Address;
 import org.onlab.packet.MacAddress;
 import org.onosproject.net.DeviceId;
-
 import static com.google.common.base.Preconditions.checkNotNull;
 
 /**
  * Contains OpenstackPort Information.
  */
-public final class OpenstackPortInfo {
-
+public class OpenstackPortInfo {
     private final Ip4Address hostIp;
-    private final DeviceId deviceId;
     private final MacAddress hostMac;
+    private final DeviceId deviceId;
     private final long vni;
+    private final Ip4Address gatewayIP;
 
-    public OpenstackPortInfo(Ip4Address hostIp, MacAddress hostMac, DeviceId deviceId,
-                             long vni) {
+    public OpenstackPortInfo(Ip4Address hostIp, MacAddress hostMac, DeviceId deviceId, long vni, Ip4Address gatewayIP) {
         this.hostIp = hostIp;
         this.hostMac = hostMac;
         this.deviceId = deviceId;
         this.vni = vni;
+        this.gatewayIP = gatewayIP;
     }
 
     public Ip4Address ip() {
@@ -55,6 +54,10 @@
         return vni;
     }
 
+    public Ip4Address gatewayIP() {
+        return gatewayIP;
+    }
+
     public static OpenstackPortInfo.Builder builder() {
         return new Builder();
     }
@@ -64,6 +67,12 @@
         private MacAddress hostMac;
         private DeviceId deviceId;
         private long vni;
+        private Ip4Address gatewayIP;
+
+        public Builder setGatewayIP(Ip4Address gatewayIP) {
+            this.gatewayIP = checkNotNull(gatewayIP, "gatewayIP cannot be null");
+            return this;
+        }
 
         public Builder setHostIp(Ip4Address hostIp) {
             this.hostIp = checkNotNull(hostIp, "hostIp cannot be null");
@@ -94,5 +103,6 @@
         hostMac = builder.hostMac;
         deviceId = builder.deviceId;
         vni = builder.vni;
+        gatewayIP = builder.gatewayIP;
     }
 }
diff --git a/apps/openstackswitching/api/src/main/java/org/onosproject/openstackswitching/OpenstackSwitchingService.java b/apps/openstackswitching/api/src/main/java/org/onosproject/openstackswitching/OpenstackSwitchingService.java
index 8960dcd..f81ddae 100644
--- a/apps/openstackswitching/api/src/main/java/org/onosproject/openstackswitching/OpenstackSwitchingService.java
+++ b/apps/openstackswitching/api/src/main/java/org/onosproject/openstackswitching/OpenstackSwitchingService.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2015 Open Networking Laboratory
+ * Copyright 2015-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.
@@ -16,6 +16,8 @@
 package org.onosproject.openstackswitching;
 
 import org.onosproject.net.Port;
+import org.onosproject.openstackrouting.OpenstackRouter;
+import org.onosproject.openstackrouting.OpenstackRouterInterface;
 
 import java.util.Collection;
 
@@ -68,6 +70,12 @@
     Collection<OpenstackPort> ports(String networkId);
 
     /**
+     * Returns port information list.
+     *
+     * @return port information list
+     */
+    Collection<OpenstackPort> ports();
+    /**
      * Returns port information for the port given.
      *
      * @param port port reference
@@ -99,4 +107,68 @@
      * @return subnet information, or null if not present
      */
     OpenstackSubnet subnet(String subnetId);
+
+    /**
+     * Sends the created router information to OpenstackRouting service.
+     *
+     * @param openstackRouter Router Information
+     */
+    void createRouter(OpenstackRouter openstackRouter);
+    /**
+     * Sends the updated router information to OpenstackRouting service.
+     *
+     * @param routerId Router ID
+     */
+    void updateRouter(String  routerId);
+    /**
+     * Sends the removed router information to OpenstackRouting service.
+     *
+     * @param routerId Router ID
+     */
+    void deleteRouter(String routerId);
+
+    /**
+     * Sends the updated router interface information to OpenstackRouting service.
+     *
+     * @param openstackRouterInterface Router interface information
+     */
+    void updateRouterInterface(OpenstackRouterInterface openstackRouterInterface);
+
+    /**
+     * Sends the removed router interface information to OpenstackRouting service.
+     *
+     * @param openstackRouterInterface Router interface information
+     */
+    void removeRouterInterface(OpenstackRouterInterface openstackRouterInterface);
+
+    /**
+     * Returns the router information list.
+     *
+     * @return router information list
+     */
+    Collection<OpenstackRouter> routers();
+
+    /**
+     * Returns the router information for the router ID given.
+     *
+     * @param routerId router ID
+     * @return router information
+     */
+    OpenstackRouter router(String routerId);
+
+    /**
+     * Returns the OpensatckPortInfo list.
+     *
+     * @return OpensatckPortInfo list
+     */
+    Collection<OpenstackPortInfo> portInfos();
+
+    /**
+     * Returns the MacAddress for physical router.
+     *
+     * @return physical router mac
+     */
+    String physicalRouterMac();
+
+
 }
diff --git a/apps/openstackswitching/app/features.xml b/apps/openstackswitching/app/features.xml
index 1a9c9a4..a4e2639 100644
--- a/apps/openstackswitching/app/features.xml
+++ b/apps/openstackswitching/app/features.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
 <!--
-  ~ Copyright 2015 Open Networking Laboratory
+  ~ Copyright 2015-16 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.
@@ -22,6 +22,7 @@
         <bundle>mvn:${project.groupId}/onos-app-openstackswitching/${project.version}</bundle>
         <bundle>mvn:${project.groupId}/onos-app-dhcp-api/${project.version}</bundle>
         <bundle>mvn:${project.groupId}/onos-app-dhcp/${project.version}</bundle>
+        <bundle>mvn:${project.groupId}/onos-app-openstackrouting/${project.version}</bundle>
         <bundle>mvn:com.sun.jersey/jersey-client/1.19</bundle>
     </feature>
 </features>
diff --git a/apps/openstackswitching/app/src/main/java/org/onosproject/openstackswitching/impl/OpenstackArpHandler.java b/apps/openstackswitching/app/src/main/java/org/onosproject/openstackswitching/impl/OpenstackArpHandler.java
index 3bbe98b..7fb489a 100644
--- a/apps/openstackswitching/app/src/main/java/org/onosproject/openstackswitching/impl/OpenstackArpHandler.java
+++ b/apps/openstackswitching/app/src/main/java/org/onosproject/openstackswitching/impl/OpenstackArpHandler.java
@@ -1,5 +1,5 @@
 /*
-* Copyright 2015 Open Networking Laboratory
+* Copyright 2015-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.
@@ -28,9 +28,11 @@
 import org.onosproject.net.packet.InboundPacket;
 import org.onosproject.net.packet.PacketService;
 import org.onosproject.openstackswitching.OpenstackPort;
+import org.onosproject.openstackswitching.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;
 
@@ -41,6 +43,7 @@
 
     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 OpenstackRestHandler restHandler;
     private HostService hostService;
@@ -66,7 +69,7 @@
      *
      * @param pkt ARP request packet
      */
-    public void processPacketIn(InboundPacket pkt) {
+    public void processPacketIn(InboundPacket pkt, Collection<OpenstackPortInfo> openstackPortInfoCollection) {
         Ethernet ethRequest = pkt.parsed();
         ARP arp = (ARP) ethRequest.getPayload();
 
@@ -74,10 +77,21 @@
             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 = getMacFromHostService(targetIp);
-        if (dstMac == null) {
-            dstMac = getMacFromOpenstack(targetIp);
+
+        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) {
diff --git a/apps/openstackswitching/app/src/main/java/org/onosproject/openstackswitching/impl/OpenstackRestHandler.java b/apps/openstackswitching/app/src/main/java/org/onosproject/openstackswitching/impl/OpenstackRestHandler.java
index edf14b0..ad8328e 100644
--- a/apps/openstackswitching/app/src/main/java/org/onosproject/openstackswitching/impl/OpenstackRestHandler.java
+++ b/apps/openstackswitching/app/src/main/java/org/onosproject/openstackswitching/impl/OpenstackRestHandler.java
@@ -21,12 +21,14 @@
 import com.google.common.collect.Lists;
 import com.sun.jersey.api.client.Client;
 import com.sun.jersey.api.client.WebResource;
+import org.onosproject.openstackrouting.OpenstackRouter;
 import org.onosproject.openstackswitching.OpenstackNetwork;
 import org.onosproject.openstackswitching.OpenstackPort;
 import org.onosproject.openstackswitching.OpenstackSubnet;
 import org.onosproject.openstackswitching.web.OpenstackNetworkCodec;
 import org.onosproject.openstackswitching.web.OpenstackPortCodec;
 import org.onosproject.openstackswitching.web.OpenstackSecurityGroupCodec;
+import org.onosproject.openstackswitching.web.OpenstackRouterCodec;
 import org.onosproject.openstackswitching.web.OpenstackSubnetCodec;
 import org.slf4j.Logger;
 import javax.ws.rs.core.MediaType;
@@ -51,6 +53,7 @@
     private static final String URI_SECURITY_GROUPS = "security-groups";
     private static final String URI_TOKENS = "tokens";
 
+    private static final String PATH_ROUTERS = "routers";
     private static final String PATH_NETWORKS = "networks";
     private static final String PATH_PORTS = "ports";
     private static final String PATH_SUBNETS = "subnets";
@@ -137,6 +140,30 @@
         return openstackPorts;
     }
 
+    public Collection<OpenstackRouter> getRouters() {
+        WebResource.Builder builder = getClientBuilder(neutronUrl + PATH_ROUTERS);
+        String response = builder.accept(MediaType.APPLICATION_JSON_TYPE).
+                header(HEADER_AUTH_TOKEN, getToken()).get(String.class);
+
+        ObjectMapper mapper = new ObjectMapper();
+        List<OpenstackRouter> openstackRouters = Lists.newArrayList();
+
+        try {
+            ObjectNode node = (ObjectNode) mapper.readTree(response);
+            ArrayNode routerList = (ArrayNode) node.path(PATH_ROUTERS);
+            OpenstackRouterCodec openstackRouterCodec = new OpenstackRouterCodec();
+            routerList.forEach(r -> openstackRouters
+                    .add(openstackRouterCodec.decode((ObjectNode) r, null)));
+        } catch (IOException e) {
+            log.warn("getRouters()", e);
+        }
+
+        log.debug("router response:" + response);
+        openstackRouters.forEach(r -> log.debug("router ID: {}", r.id()));
+
+        return openstackRouters;
+    }
+
     /**
      * Returns Subnet information in Neutron.
      *
diff --git a/apps/openstackswitching/app/src/main/java/org/onosproject/openstackswitching/impl/OpenstackSwitchingConfig.java b/apps/openstackswitching/app/src/main/java/org/onosproject/openstackswitching/impl/OpenstackSwitchingConfig.java
index eec14f5..11eff61 100644
--- a/apps/openstackswitching/app/src/main/java/org/onosproject/openstackswitching/impl/OpenstackSwitchingConfig.java
+++ b/apps/openstackswitching/app/src/main/java/org/onosproject/openstackswitching/impl/OpenstackSwitchingConfig.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2014 Open Networking Laboratory
+ * Copyright 2015-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.
@@ -28,6 +28,7 @@
     public static final String KEYSTONE_SERVER = "keystone_server";
     public static final String USER_NAME = "user_name";
     public static final String PASSWORD = "password";
+    public static final String PHYSICAL_ROUTER_MAC = "physicalRouterMac";
 
     /**
      * Returns the flag whether the app pushes flows or not.
@@ -76,6 +77,14 @@
     }
 
     /**
+     * Returns the MacAddress for physical router.
+     *
+     * @return physical router mac
+     */
+    public String physicalRouterMac() {
+        return get(PHYSICAL_ROUTER_MAC, "");
+    }
+    /**
      * Sets the flag whether the app pushes flows or not.
      *
      * @param flag the flag whether the app pushes flows or not
diff --git a/apps/openstackswitching/app/src/main/java/org/onosproject/openstackswitching/impl/OpenstackSwitchingManager.java b/apps/openstackswitching/app/src/main/java/org/onosproject/openstackswitching/impl/OpenstackSwitchingManager.java
index 572a395..572e204 100644
--- a/apps/openstackswitching/app/src/main/java/org/onosproject/openstackswitching/impl/OpenstackSwitchingManager.java
+++ b/apps/openstackswitching/app/src/main/java/org/onosproject/openstackswitching/impl/OpenstackSwitchingManager.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2015 Open Networking Laboratory
+ * Copyright 2015-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.
@@ -50,8 +50,12 @@
 import org.onosproject.net.packet.PacketContext;
 import org.onosproject.net.packet.PacketProcessor;
 import org.onosproject.net.packet.PacketService;
+import org.onosproject.openstackrouting.OpenstackRouter;
+import org.onosproject.openstackrouting.OpenstackRouterInterface;
+import org.onosproject.openstackrouting.OpenstackRoutingService;
 import org.onosproject.openstackswitching.OpenstackNetwork;
 import org.onosproject.openstackswitching.OpenstackPort;
+import org.onosproject.openstackswitching.OpenstackPortInfo;
 import org.onosproject.openstackswitching.OpenstackSubnet;
 import org.onosproject.openstackswitching.OpenstackSwitchingService;
 import org.slf4j.Logger;
@@ -103,11 +107,14 @@
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected DriverService driverService;
 
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected OpenstackRoutingService openstackRoutingService;
+
     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";
 
     private ApplicationId appId;
@@ -116,6 +123,7 @@
     private Ip4Address keystoneServer;
     private String userName;
     private String password;
+    private String physicalRouterMac;
     private OpenstackArpHandler arpHandler;
     private OpenstackRestHandler restHandler;
 
@@ -139,7 +147,6 @@
             }
     );
 
-
     private Map<String, OpenstackPortInfo> openstackPortInfoMap = Maps.newHashMap();
 
     @Activate
@@ -172,9 +179,12 @@
 
     @Override
     public void createPorts(OpenstackPort openstackPort) {
-        if (!openstackPort.fixedIps().isEmpty()
-                && !openstackPort.deviceOwner().equals(DEVICE_OWNER_GATEWAY)) {
-            registerDhcpInfo(openstackPort);
+
+        if (!openstackPort.deviceOwner().equals(ROUTER_INTERFACE)
+            && !openstackPort.deviceOwner().equals(DEVICE_OWNER_GATEWAY)) {
+            if (!openstackPort.fixedIps().isEmpty()) {
+                registerDhcpInfo(openstackPort);
+            }
         }
 
         if (!openstackPort.securityGroups().isEmpty()) {
@@ -236,6 +246,11 @@
     }
 
     @Override
+    public Collection<OpenstackPort> ports() {
+        return restHandler.getPorts();
+    }
+
+    @Override
     public OpenstackPort port(Port port) {
         Collection<OpenstackPort> ports = restHandler.getPorts();
         String uuid = port.annotations().value(PORTNAME).substring(3);
@@ -291,6 +306,57 @@
         }
     }
 
+    @Override
+    public void createRouter(OpenstackRouter openstackRouter) {
+        openstackRoutingService.createRouter(openstackRouter);
+    }
+    @Override
+    public void updateRouter(String routerId) {
+        openstackRoutingService.updateRouter(router(routerId));
+    }
+
+    @Override
+    public void removeRouterInterface(OpenstackRouterInterface openstackRouterInterface) {
+        openstackRoutingService.removeRouterInterface(openstackRouterInterface);
+    }
+    @Override
+    public void deleteRouter(String id) {
+        openstackRoutingService.deleteRouter(id);
+    }
+
+    @Override
+    public void updateRouterInterface(OpenstackRouterInterface openstackRouterInterface) {
+        openstackRoutingService.updateRouterInterface(openstackRouterInterface);
+    }
+
+    @Override
+    public OpenstackRouter router(String routerId) {
+        Collection<OpenstackRouter> openstackRouters = restHandler.getRouters();
+        try {
+            return openstackRouters.stream()
+                    .filter(r -> r.id().equals(routerId))
+                    .findAny().get();
+        } catch (NoSuchElementException e) {
+            log.warn("There is no router info for subnet ID {}", routerId);
+            return null;
+        }
+    }
+
+    @Override
+    public Collection<OpenstackRouter> routers() {
+        return restHandler.getRouters();
+    }
+
+    @Override
+    public Collection<OpenstackPortInfo> portInfos() {
+        return openstackPortInfoMap.values();
+    }
+
+    @Override
+    public String physicalRouterMac() {
+        return physicalRouterMac;
+    }
+
     private void processDeviceAdded(Device device) {
         log.debug("device {} is added", device.id());
     }
@@ -301,8 +367,11 @@
                 OpenstackSwitchingRulePopulator rulePopulator =
                         new OpenstackSwitchingRulePopulator(appId, flowObjectiveService,
                                 deviceService, restHandler, driverService);
+
                 rulePopulator.populateSwitchingRules(doNotPushFlows, device, port);
-                updatePortMap(device.id(), port, restHandler.getNetworks(), rulePopulator.openstackPort(port));
+                updatePortMap(device.id(), port, restHandler.getNetworks(), restHandler.getSubnets(),
+                        rulePopulator.openstackPort(port));
+
                 //In case portupdate event is driven by vm shutoff from openstack
             } else if (!port.isEnabled() && openstackPortInfoMap.containsKey(port.annotations().value(PORTNAME))) {
                 log.debug("Flowrules according to the port {} were removed", port.number().toString());
@@ -327,6 +396,7 @@
                         deviceService, restHandler, driverService);
 
         Collection<OpenstackNetwork> networks = restHandler.getNetworks();
+        Collection<OpenstackSubnet> subnets = restHandler.getSubnets();
 
         deviceService.getDevices().forEach(device -> {
                     log.debug("device {} num of ports {} ", device.id(),
@@ -339,7 +409,7 @@
                                         if (osPort != null && !osPort.deviceOwner().equals(DEVICE_OWNER_GATEWAY)) {
                                             if (!doNotPushFlows) {
                                                 rulePopulator.populateSwitchingRules(doNotPushFlows, device, vmPort);
-                                                updatePortMap(device.id(), vmPort, networks, osPort);
+                                                updatePortMap(device.id(), vmPort, networks, subnets, osPort);
                                             }
                                             registerDhcpInfo(osPort);
                                         } else {
@@ -352,16 +422,23 @@
     }
 
     private void updatePortMap(DeviceId deviceId, Port port, Collection<OpenstackNetwork> networks,
-                               OpenstackPort openstackPort) {
+                               Collection<OpenstackSubnet> subnets, OpenstackPort openstackPort) {
         long vni = Long.parseLong(networks.stream()
                 .filter(n -> n.id().equals(openstackPort.networkId()))
                 .findAny().orElse(null).segmentId());
 
+        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);
+                .setVni(vni)
+                .setGatewayIP(gatewayIPAddress);
 
         openstackPortInfoMap.putIfAbsent(port.annotations().value(PORTNAME),
                 portBuilder.build());
@@ -420,7 +497,6 @@
 
         @Override
         public void process(PacketContext context) {
-
             if (context.isHandled()) {
                 return;
             }
@@ -429,7 +505,7 @@
             Ethernet ethernet = pkt.parsed();
 
             if (ethernet != null && ethernet.getEtherType() == Ethernet.TYPE_ARP) {
-                arpHandler.processPacketIn(pkt);
+                arpHandler.processPacketIn(pkt, openstackPortInfoMap.values());
             }
         }
     }
@@ -510,6 +586,7 @@
                 return;
             }
             doNotPushFlows = cfg.doNotPushFlows();
+            physicalRouterMac = cfg.physicalRouterMac();
             restHandler = new OpenstackRestHandler(cfg);
             arpHandler = new OpenstackArpHandler(restHandler, packetService, hostService);
             initializeFlowRules();
diff --git a/apps/openstackswitching/app/src/main/java/org/onosproject/openstackswitching/impl/OpenstackSwitchingRulePopulator.java b/apps/openstackswitching/app/src/main/java/org/onosproject/openstackswitching/impl/OpenstackSwitchingRulePopulator.java
index a02f9f5..0ebfe19 100644
--- a/apps/openstackswitching/app/src/main/java/org/onosproject/openstackswitching/impl/OpenstackSwitchingRulePopulator.java
+++ b/apps/openstackswitching/app/src/main/java/org/onosproject/openstackswitching/impl/OpenstackSwitchingRulePopulator.java
@@ -42,6 +42,7 @@
 import org.onosproject.net.flowobjective.ForwardingObjective;
 import org.onosproject.openstackswitching.OpenstackNetwork;
 import org.onosproject.openstackswitching.OpenstackPort;
+import org.onosproject.openstackswitching.OpenstackPortInfo;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
diff --git a/apps/openstackswitching/app/src/main/java/org/onosproject/openstackswitching/web/OpensatckRouterWebResource.java b/apps/openstackswitching/app/src/main/java/org/onosproject/openstackswitching/web/OpensatckRouterWebResource.java
new file mode 100644
index 0000000..aa9dfe4
--- /dev/null
+++ b/apps/openstackswitching/app/src/main/java/org/onosproject/openstackswitching/web/OpensatckRouterWebResource.java
@@ -0,0 +1,172 @@
+/*
+ * 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.openstackswitching.web;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.onosproject.openstackrouting.OpenstackRouter;
+import org.onosproject.openstackrouting.OpenstackRouterInterface;
+import org.onosproject.openstackswitching.OpenstackSwitchingService;
+import org.onosproject.rest.AbstractWebResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.io.InputStream;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Handles REST API call of Neturon L3 plugin.
+ */
+
+@Path("routers")
+public class OpensatckRouterWebResource extends AbstractWebResource {
+    protected static final Logger log = LoggerFactory
+            .getLogger(OpenstackNetworkWebResource.class);
+
+    private static final OpenstackRouterInterfaceCodec ROUTER_INTERFACE_CODEC
+            = new OpenstackRouterInterfaceCodec();
+    private static final OpenstackRouterCodec ROUTER_CODEC
+            = new OpenstackRouterCodec();
+
+    @POST
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response createRouter(InputStream input) {
+        checkNotNull(input);
+        try {
+            ObjectMapper mapper = new ObjectMapper();
+            ObjectNode routerNode = (ObjectNode) mapper.readTree(input);
+
+            OpenstackRouter openstackRouter
+                    = ROUTER_CODEC.decode(routerNode, this);
+
+            OpenstackSwitchingService switchingService
+                    = getService(OpenstackSwitchingService.class);
+            switchingService.createRouter(openstackRouter);
+
+            log.debug("REST API CREATE router is called {}", input.toString());
+            return Response.status(Response.Status.OK).build();
+        } catch (Exception e) {
+            log.error("Create Router failed because of exception {}",
+                    e.toString());
+            return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(e.toString())
+                    .build();
+        }
+    }
+
+    @PUT
+    @Path("{id}")
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response updateRouter(@PathParam("id") String id) {
+        checkNotNull(id);
+        try {
+            OpenstackSwitchingService switchingService
+                    = getService(OpenstackSwitchingService.class);
+            switchingService.updateRouter(id);
+
+            log.debug("REST API UPDATE router is called from router {}", id);
+            return Response.status(Response.Status.OK).build();
+        } catch (Exception e) {
+            log.error("Updates Router failed because of exception {}",
+                    e.toString());
+            return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(e.toString())
+                    .build();
+        }
+    }
+
+    @PUT
+    @Path("{id}/add_router_interface")
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response addRouterInterface(InputStream input) {
+        checkNotNull(input);
+        try {
+            ObjectMapper mapper = new ObjectMapper();
+            ObjectNode routerIfNode = (ObjectNode) mapper.readTree(input);
+
+            OpenstackRouterInterface openstackRouterInterface
+                    = ROUTER_INTERFACE_CODEC.decode(routerIfNode, this);
+
+            OpenstackSwitchingService switchingService
+                    = getService(OpenstackSwitchingService.class);
+            switchingService.updateRouterInterface(openstackRouterInterface);
+
+            log.debug("REST API AddRouterInterface is called from router {} portId: {}, subnetId: {}, tenantId: {}",
+                    openstackRouterInterface.id(), openstackRouterInterface.portId(),
+                    openstackRouterInterface.subnetId(), openstackRouterInterface.tenantId());
+
+            return Response.status(Response.Status.OK).build();
+        } catch (Exception e) {
+            log.error("AddRouterInterface failed because of exception {}",
+                    e.toString());
+            return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(e.toString())
+                    .build();
+        }
+    }
+
+    @DELETE
+    @Path("{id}")
+    public Response deleteRouter(@PathParam("id") String id) {
+        checkNotNull(id);
+        OpenstackSwitchingService switchingService =
+                getService(OpenstackSwitchingService.class);
+        switchingService.deleteRouter(id);
+
+        log.debug("REST API DELETE routers is called {}", id);
+        return Response.status(Response.Status.OK).build();
+    }
+
+    @PUT
+    @Path("{id}/remove_router_interface")
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response removeRouterInterface(@PathParam("id") String id, InputStream input) {
+        checkNotNull(id);
+        checkNotNull(input);
+        try {
+            ObjectMapper mapper = new ObjectMapper();
+            ObjectNode routerIfNode = (ObjectNode) mapper.readTree(input);
+
+            OpenstackRouterInterface openstackRouterInterface
+                    = ROUTER_INTERFACE_CODEC.decode(routerIfNode, this);
+
+            OpenstackSwitchingService switchingService
+                    = getService(OpenstackSwitchingService.class);
+            switchingService.removeRouterInterface(openstackRouterInterface);
+
+            log.debug("REST API RemoveRouterInterface is called from router {} portId: {}, subnetId: {}," +
+                    "tenantId: {}", openstackRouterInterface.id(), openstackRouterInterface.portId(),
+                    openstackRouterInterface.subnetId(), openstackRouterInterface.tenantId());
+
+            return Response.status(Response.Status.OK).build();
+        } catch (Exception e) {
+            log.error("RemoveRouterInterface failed because of exception {}",
+                    e.toString());
+            return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(e.toString())
+                    .build();
+        }
+    }
+}
diff --git a/apps/openstackswitching/app/src/main/java/org/onosproject/openstackswitching/web/OpenstackPortWebResource.java b/apps/openstackswitching/app/src/main/java/org/onosproject/openstackswitching/web/OpenstackPortWebResource.java
index 4e23753..206e4b1 100644
--- a/apps/openstackswitching/app/src/main/java/org/onosproject/openstackswitching/web/OpenstackPortWebResource.java
+++ b/apps/openstackswitching/app/src/main/java/org/onosproject/openstackswitching/web/OpenstackPortWebResource.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2015 Open Networking Laboratory
+ * Copyright 2015-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.
diff --git a/apps/openstackswitching/app/src/main/java/org/onosproject/openstackswitching/web/OpenstackRouterCodec.java b/apps/openstackswitching/app/src/main/java/org/onosproject/openstackswitching/web/OpenstackRouterCodec.java
new file mode 100644
index 0000000..afcf560
--- /dev/null
+++ b/apps/openstackswitching/app/src/main/java/org/onosproject/openstackswitching/web/OpenstackRouterCodec.java
@@ -0,0 +1,108 @@
+/*
+ * 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.openstackswitching.web;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.google.common.collect.Maps;
+import org.onlab.packet.Ip4Address;
+import org.onosproject.codec.CodecContext;
+import org.onosproject.codec.JsonCodec;
+import org.onosproject.openstackrouting.OpenstackExternalGateway;
+import org.onosproject.openstackrouting.OpenstackRouter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Map;
+/**
+ * Implementation of the OpenstackRouter Codec.
+ */
+public class OpenstackRouterCodec extends JsonCodec<OpenstackRouter> {
+    protected static final Logger log = LoggerFactory
+            .getLogger(OpenstackNetworkCodec.class);
+
+    private static final String ROUTER = "router";
+    private static final String TENANT_ID = "tenant_id";
+    private static final String NETWORK_ID = "network_id";
+    private static final String ID = "id";
+    private static final String NAME = "name";
+    private static final String STATUS = "status";
+    private static final String ADMIN_STATE_UP = "admin_state_up";
+    private static final String EXTERNAL_GW_INFO = "external_gateway_info";
+    private static final String EXTERNAL_FIXED_IPS = "external_fixed_ips";
+    private static final String SUBNET_ID = "subnet_id";
+    private static final String IP_ADDRESS = "ip_address";
+
+    /**
+     * Decodes the OpenstackRouter.
+     *
+     * @param json    JSON to decode
+     * @param context decoding context
+     * @return OpenstackRouter
+     */
+    @Override
+    public OpenstackRouter decode(ObjectNode json, CodecContext context) {
+
+        if (json == null || !json.isObject()) {
+            return null;
+        }
+        JsonNode routerInfo = json.get(ROUTER);
+        if (routerInfo == null) {
+            routerInfo = json;
+        }
+
+        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 = OpenstackExternalGateway.builder();
+
+        if (!routerInfo.path(EXTERNAL_GW_INFO).isMissingNode()) {
+            String externalGatewayNetId = checkNotNull(routerInfo.path(EXTERNAL_GW_INFO).path(NETWORK_ID).asText());
+            Map<String, Ip4Address> fixedIpMap = Maps.newHashMap();
+
+
+            if (!routerInfo.path(EXTERNAL_GW_INFO).path(EXTERNAL_FIXED_IPS).isMissingNode()) {
+                ArrayNode fixedIpList = (ArrayNode) routerInfo.path(EXTERNAL_GW_INFO).path(EXTERNAL_FIXED_IPS);
+
+                for (JsonNode fixedIpInfo : fixedIpList) {
+                    String subnetId = checkNotNull(fixedIpInfo.path(SUBNET_ID).asText());
+                    String ipAddressStr = checkNotNull(fixedIpInfo.path(IP_ADDRESS).asText());
+                    if (!fixedIpInfo.path(IP_ADDRESS).isMissingNode() && ipAddressStr != null) {
+                        fixedIpMap.put(subnetId, Ip4Address.valueOf(ipAddressStr));
+                    }
+                }
+            }
+
+            osExtBuiler.networkId(externalGatewayNetId)
+                    .enablePnat(true)
+                    .externalFixedIps(fixedIpMap);
+        }
+        OpenstackRouter.Builder osBuilder = new OpenstackRouter.Builder()
+                .tenantId(tenantId)
+                .id(id)
+                .name(name)
+                .status(OpenstackRouter.RouterStatus.valueOf(status))
+                .adminStateUp(Boolean.valueOf(adminStateUp))
+                .gatewayExternalInfo(osExtBuiler.build());
+
+        return osBuilder.build();
+    }
+}
diff --git a/apps/openstackswitching/app/src/main/java/org/onosproject/openstackswitching/web/OpenstackRouterInterfaceCodec.java b/apps/openstackswitching/app/src/main/java/org/onosproject/openstackswitching/web/OpenstackRouterInterfaceCodec.java
new file mode 100644
index 0000000..88de443
--- /dev/null
+++ b/apps/openstackswitching/app/src/main/java/org/onosproject/openstackswitching/web/OpenstackRouterInterfaceCodec.java
@@ -0,0 +1,65 @@
+/*
+ * 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.openstackswitching.web;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.onosproject.codec.CodecContext;
+import org.onosproject.codec.JsonCodec;
+import org.onosproject.openstackrouting.OpenstackRouterInterface;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import static com.google.common.base.Preconditions.checkNotNull;
+/**
+ * Implementation of the OpenstackRouterInterface Codec.
+ */
+public class OpenstackRouterInterfaceCodec extends JsonCodec<OpenstackRouterInterface> {
+    protected static final Logger log = LoggerFactory
+            .getLogger(OpenstackNetworkCodec.class);
+
+    private static final String ID = "id";
+    private static final String TENANT_ID = "tenant_id";
+    private static final String SUBNET_ID = "subnet_id";
+    private static final String PORT_ID = "port_id";
+
+    /**
+     * Decodes the OpenstackRouterInterface.
+     *
+     * @param json    JSON to decode
+     * @param context decoding context
+     * @return OpenstackRouterInterface
+     */
+    @Override
+    public OpenstackRouterInterface decode(ObjectNode json, CodecContext context) {
+        if (json == null || !json.isObject()) {
+            return null;
+        }
+        JsonNode routerIfInfo = json;
+
+        String id = checkNotNull(routerIfInfo.path(ID).asText());
+        String tenantId = checkNotNull(routerIfInfo.path(TENANT_ID).asText());
+        String subnetId = checkNotNull(routerIfInfo.path(SUBNET_ID).asText());
+        String portId = checkNotNull(routerIfInfo.path(PORT_ID).asText());
+
+        OpenstackRouterInterface.Builder osBuilder = new OpenstackRouterInterface.Builder()
+                .id(id)
+                .tenantId(tenantId)
+                .subnetId(subnetId)
+                .portId(portId);
+
+        return osBuilder.build();
+    }
+}
diff --git a/apps/openstackswitching/app/src/main/webapp/WEB-INF/web.xml b/apps/openstackswitching/app/src/main/webapp/WEB-INF/web.xml
index 4f50ef7..923eff6 100644
--- a/apps/openstackswitching/app/src/main/webapp/WEB-INF/web.xml
+++ b/apps/openstackswitching/app/src/main/webapp/WEB-INF/web.xml
@@ -32,7 +32,8 @@
             <param-value>
                 org.onosproject.openstackswitching.web.OpenstackPortWebResource,
                 org.onosproject.openstackswitching.web.OpenstackNetworkWebResource,
-                org.onosproject.openstackswitching.web.OpenstackSubnetWebResource
+                org.onosproject.openstackswitching.web.OpenstackSubnetWebResource,
+                org.onosproject.openstackswitching.web.OpensatckRouterWebResource
             </param-value>
         </init-param>
         <load-on-startup>1</load-on-startup>
diff --git a/apps/openstackswitching/pom.xml b/apps/openstackswitching/pom.xml
index 04122bf..459ec61 100644
--- a/apps/openstackswitching/pom.xml
+++ b/apps/openstackswitching/pom.xml
@@ -37,6 +37,11 @@
     </modules>
 
     <dependencies>
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-app-openstackrouting</artifactId>
+            <version>${project.version}</version>
+        </dependency>
     </dependencies>