Implemented dummy Neutron ML2 plugin handler

- Added REST handler for Neutron ML2 ONOS mech driver
- Made cordvtn ARP proxy to handle request for host, too
- Now cordvtn utilizes openstackSwitching only as a Neutron REST client

Change-Id: I6890b6651ddcb9d8cf33fb326e9f0eb721b536a5
diff --git a/apps/cordvtn/src/main/java/org/onosproject/cordvtn/CordVtn.java b/apps/cordvtn/src/main/java/org/onosproject/cordvtn/CordVtn.java
index 2996557..e27aa74 100644
--- a/apps/cordvtn/src/main/java/org/onosproject/cordvtn/CordVtn.java
+++ b/apps/cordvtn/src/main/java/org/onosproject/cordvtn/CordVtn.java
@@ -172,7 +172,7 @@
                                                  mastershipService,
                                                  DEFAULT_TUNNEL);
 
-        arpProxy = new CordVtnArpProxy(appId, packetService);
+        arpProxy = new CordVtnArpProxy(appId, packetService, hostService);
         packetService.addProcessor(packetProcessor, PacketProcessor.director(0));
         arpProxy.requestPacket();
 
diff --git a/apps/cordvtn/src/main/java/org/onosproject/cordvtn/CordVtnArpProxy.java b/apps/cordvtn/src/main/java/org/onosproject/cordvtn/CordVtnArpProxy.java
index 3c92404..5f444e0 100644
--- a/apps/cordvtn/src/main/java/org/onosproject/cordvtn/CordVtnArpProxy.java
+++ b/apps/cordvtn/src/main/java/org/onosproject/cordvtn/CordVtnArpProxy.java
@@ -28,6 +28,7 @@
 import org.onosproject.net.flow.DefaultTrafficTreatment;
 import org.onosproject.net.flow.TrafficSelector;
 import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.host.HostService;
 import org.onosproject.net.packet.DefaultOutboundPacket;
 import org.onosproject.net.packet.PacketContext;
 import org.onosproject.net.packet.PacketPriority;
@@ -50,6 +51,7 @@
 
     private final ApplicationId appId;
     private final PacketService packetService;
+    private final HostService hostService;
 
     private Set<Ip4Address> serviceIPs = Sets.newHashSet();
 
@@ -59,9 +61,10 @@
      * @param appId application id
      * @param packetService packet service
      */
-    public CordVtnArpProxy(ApplicationId appId, PacketService packetService) {
+    public CordVtnArpProxy(ApplicationId appId, PacketService packetService, HostService hostService) {
         this.appId = appId;
         this.packetService = packetService;
+        this.hostService = hostService;
     }
 
     /**
@@ -124,14 +127,16 @@
      */
     public void processArpPacket(PacketContext context, Ethernet ethPacket, MacAddress gatewayMac) {
         ARP arpPacket = (ARP) ethPacket.getPayload();
-        Ip4Address targetIp = Ip4Address.valueOf(arpPacket.getTargetProtocolAddress());
-
-        if (arpPacket.getOpCode() != ARP.OP_REQUEST || !serviceIPs.contains(targetIp)) {
+        if (arpPacket.getOpCode() != ARP.OP_REQUEST) {
            return;
         }
 
-        if (gatewayMac.equals(MacAddress.NONE)) {
-            log.debug("Gateway mac address is not set, ignoring ARP request");
+        Ip4Address targetIp = Ip4Address.valueOf(arpPacket.getTargetProtocolAddress());
+        MacAddress macAddr = serviceIPs.contains(targetIp) ?
+                gatewayMac : getMacFromHostService(targetIp);
+
+        if (macAddr.equals(MacAddress.NONE)) {
+            log.debug("Failed to find MAC for {}", targetIp.toString());
             context.block();
             return;
         }
@@ -205,4 +210,27 @@
         eth.setPayload(arp);
         return eth;
     }
+
+    /**
+     * Returns MAC address of a host with a given target IP address by asking to
+     * host service. It does not support overlapping IP.
+     *
+     * @param targetIp target ip
+     * @return mac address, or NONE mac address if it fails to find the mac
+     */
+    private MacAddress getMacFromHostService(IpAddress targetIp) {
+        checkNotNull(targetIp);
+
+        Host host = hostService.getHostsByIp(targetIp)
+                .stream()
+                .findFirst()
+                .orElse(null);
+
+        if (host != null) {
+            log.debug("Found MAC from host service for {}", targetIp.toString());
+            return host.mac();
+        } else {
+            return MacAddress.NONE;
+        }
+    }
 }
diff --git a/apps/cordvtn/src/main/java/org/onosproject/cordvtn/rest/CordVtnWebApplication.java b/apps/cordvtn/src/main/java/org/onosproject/cordvtn/rest/CordVtnWebApplication.java
index 51dd3c6..fcb39a5 100644
--- a/apps/cordvtn/src/main/java/org/onosproject/cordvtn/rest/CordVtnWebApplication.java
+++ b/apps/cordvtn/src/main/java/org/onosproject/cordvtn/rest/CordVtnWebApplication.java
@@ -26,6 +26,9 @@
 public class CordVtnWebApplication extends AbstractWebApplication {
     @Override
     public Set<Class<?>> getClasses() {
-        return getClasses(ServiceDependencyWebResource.class);
+        return getClasses(ServiceDependencyWebResource.class,
+                          NeutronMl2NetworksWebResource.class,
+                          NeutronMl2SubnetsWebResource.class,
+                          NeutronMl2PortsWebResource.class);
     }
 }
diff --git a/apps/cordvtn/src/main/java/org/onosproject/cordvtn/rest/NeutronMl2NetworksWebResource.java b/apps/cordvtn/src/main/java/org/onosproject/cordvtn/rest/NeutronMl2NetworksWebResource.java
new file mode 100644
index 0000000..16bbc61
--- /dev/null
+++ b/apps/cordvtn/src/main/java/org/onosproject/cordvtn/rest/NeutronMl2NetworksWebResource.java
@@ -0,0 +1,66 @@
+/*
+ * 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.cordvtn.rest;
+
+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;
+
+/**
+ * Dummy Neutron ML2 mechanism driver.
+ * It just returns OK for networks resource requests.
+ */
+@Path("networks")
+public class NeutronMl2NetworksWebResource extends AbstractWebResource {
+    protected final Logger log = LoggerFactory.getLogger(getClass());
+    private static final String NETWORKS_MESSAGE = "Received networks %s";
+
+    @POST
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response createNetwork(InputStream input) {
+        log.debug(String.format(NETWORKS_MESSAGE, "create"));
+        return Response.status(Response.Status.OK).build();
+    }
+
+    @PUT
+    @Path("{id}")
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response updateNetwork(@PathParam("id") String id, InputStream input) {
+        log.debug(String.format(NETWORKS_MESSAGE, "update"));
+        return Response.status(Response.Status.OK).build();
+    }
+
+    @DELETE
+    @Path("{id}")
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response deleteNetwork(@PathParam("id") String id) {
+        log.debug(String.format(NETWORKS_MESSAGE, "delete"));
+        return Response.status(Response.Status.OK).build();
+    }
+}
diff --git a/apps/cordvtn/src/main/java/org/onosproject/cordvtn/rest/NeutronMl2PortsWebResource.java b/apps/cordvtn/src/main/java/org/onosproject/cordvtn/rest/NeutronMl2PortsWebResource.java
new file mode 100644
index 0000000..5fa60e5
--- /dev/null
+++ b/apps/cordvtn/src/main/java/org/onosproject/cordvtn/rest/NeutronMl2PortsWebResource.java
@@ -0,0 +1,66 @@
+/*
+ * 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.cordvtn.rest;
+
+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;
+
+/**
+ * Dummy Neutron ML2 mechanism driver.
+ * It just returns OK for ports resource requests.
+ */
+@Path("ports")
+public class NeutronMl2PortsWebResource extends AbstractWebResource {
+    protected final Logger log = LoggerFactory.getLogger(getClass());
+    private static final String PORTS_MESSAGE = "Received ports %s";
+
+    @POST
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response createPorts(InputStream input) {
+        log.debug(String.format(PORTS_MESSAGE, "create"));
+        return Response.status(Response.Status.OK).build();
+    }
+
+    @PUT
+    @Path("{id}")
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response updatePorts(@PathParam("id") String id, InputStream input) {
+        log.debug(String.format(PORTS_MESSAGE, "update"));
+        return Response.status(Response.Status.OK).build();
+    }
+
+    @Path("{id}")
+    @DELETE
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response deletePorts(@PathParam("id") String id) {
+        log.debug(String.format(PORTS_MESSAGE, "delete"));
+        return Response.status(Response.Status.OK).build();
+    }
+}
diff --git a/apps/cordvtn/src/main/java/org/onosproject/cordvtn/rest/NeutronMl2SubnetsWebResource.java b/apps/cordvtn/src/main/java/org/onosproject/cordvtn/rest/NeutronMl2SubnetsWebResource.java
new file mode 100644
index 0000000..188ec9d
--- /dev/null
+++ b/apps/cordvtn/src/main/java/org/onosproject/cordvtn/rest/NeutronMl2SubnetsWebResource.java
@@ -0,0 +1,68 @@
+/*
+ * 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.cordvtn.rest;
+
+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;
+
+/**
+ * Dummy Neutron ML2 mechanism driver.
+ * It just returns OK for subnets resource requests.
+ */
+@Path("subnets")
+public class NeutronMl2SubnetsWebResource extends AbstractWebResource {
+    protected final Logger log = LoggerFactory.getLogger(getClass());
+    private static final String SUBNETS_MESSAGE = "Received subnets %s";
+
+    @POST
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response createSubnet(InputStream input) {
+        log.debug(String.format(SUBNETS_MESSAGE, "create"));
+        return Response.status(Response.Status.OK).build();
+    }
+
+
+    @PUT
+    @Path("{id}")
+    @Produces(MediaType.APPLICATION_JSON)
+    @Consumes(MediaType.APPLICATION_JSON)
+    public Response updateSubnet(@PathParam("id") String id, InputStream input) {
+        log.debug(String.format(SUBNETS_MESSAGE, "update"));
+        return Response.status(Response.Status.OK).build();
+
+    }
+
+    @DELETE
+    @Path("{id}")
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response deleteSubnet(@PathParam("id") String id) {
+        log.debug(String.format(SUBNETS_MESSAGE, "delete"));
+        return Response.status(Response.Status.OK).build();
+    }
+}