Supports dpdk-based vm creation in OpenstackNetworking service.

Change-Id: I39c30cde5b455952a4c7ed0147903324c6598880
diff --git a/apps/openstacknetworking/api/src/main/java/org/onosproject/openstacknetworking/api/Constants.java b/apps/openstacknetworking/api/src/main/java/org/onosproject/openstacknetworking/api/Constants.java
index d890e5c..e966db1 100644
--- a/apps/openstacknetworking/api/src/main/java/org/onosproject/openstacknetworking/api/Constants.java
+++ b/apps/openstacknetworking/api/src/main/java/org/onosproject/openstacknetworking/api/Constants.java
@@ -28,6 +28,17 @@
     private Constants() {
     }
 
+    /**
+     * List of valid openstack port types.
+     */
+    public enum VnicType {
+        NORMAL,
+        DIRECT,
+        UNSUPPORTED
+    }
+    public static final String PORT_NAME_PREFIX_VM = "tap";
+    public static final String PORT_NAME_VHOST_USER_PREFIX_VM = "vhu";
+
     public static final String OPENSTACK_NETWORKING_APP_ID = "org.onosproject.openstacknetworking";
 
     public static final String ARP_BROADCAST_MODE = "broadcast";
diff --git a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackNetworkManager.java b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackNetworkManager.java
index 2418745..92257fd 100644
--- a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackNetworkManager.java
+++ b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackNetworkManager.java
@@ -75,8 +75,8 @@
 import static org.onosproject.net.AnnotationKeys.PORT_NAME;
 import static org.onosproject.openstacknetworking.api.Constants.DIRECT;
 import static org.onosproject.openstacknetworking.api.Constants.PCISLOT;
-import static org.onosproject.openstacknetworking.api.Constants.portNamePrefixMap;
 import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getIntfNameFromPciAddress;
+import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.vnicType;
 import static org.slf4j.LoggerFactory.getLogger;
 
 /**
@@ -113,7 +113,6 @@
     private static final String ERR_NOT_FOUND = " does not exist";
     private static final String ERR_IN_USE = " still in use";
     private static final String ERR_DUPLICATE = " already exists";
-    private static final String PORT_NAME_PREFIX_VM = "tap";
 
     private static final int PREFIX_LENGTH = 32;
 
@@ -325,29 +324,34 @@
             return null;
         }
 
-        if (port.annotations().value(PORT_NAME).startsWith(PORT_NAME_PREFIX_VM)) {
-            Optional<Port> osPort = osNetworkStore.ports()
-                    .stream()
-                    .filter(p -> p.getId().contains(portName.substring(3)))
-                    .findFirst();
-            return osPort.orElse(null);
-        } else if (isDirectPort(portName)) {
-            //Additional prefixes will be added
-            Optional<Port> osPort = osNetworkStore.ports()
-                    .stream()
-                    .filter(p -> p.getvNicType().equals(DIRECT) && p.getProfile().get(PCISLOT) != null)
-                    .filter(p -> getIntfNameFromPciAddress(p).equals(portName))
-                    .findFirst();
-            return osPort.orElse(null);
-        } else {
+        try {
+            Optional<Port> osPort;
+            switch (vnicType(portName)) {
+                case NORMAL:
+                    osPort = osNetworkStore.ports()
+                            .stream()
+                            .filter(p -> p.getId().contains(portName.substring(3)))
+                            .findFirst();
+                    return osPort.orElse(null);
+
+                case DIRECT:
+                    //Additional prefixes will be added
+                    osPort = osNetworkStore.ports()
+                            .stream()
+                            .filter(p -> p.getvNicType().equals(DIRECT) && p.getProfile().get(PCISLOT) != null)
+                            .filter(p -> getIntfNameFromPciAddress(p).equals(portName))
+                            .findFirst();
+                    return osPort.orElse(null);
+
+                default:
+                    return null;
+            }
+        } catch (IllegalArgumentException e) {
+            log.error("IllegalArgumentException occurred because of {}", e);
             return null;
         }
     }
 
-    private boolean isDirectPort(String portName) {
-        return portNamePrefixMap().values().stream().filter(p -> portName.startsWith(p)).findAny().isPresent();
-    }
-
     @Override
     public Set<Port> ports() {
         return ImmutableSet.copyOf(osNetworkStore.ports());
diff --git a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingHostProvider.java b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingHostProvider.java
index 01e1099..40413d7 100644
--- a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingHostProvider.java
+++ b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingHostProvider.java
@@ -46,6 +46,7 @@
 import org.onosproject.net.host.HostService;
 import org.onosproject.net.provider.AbstractProvider;
 import org.onosproject.net.provider.ProviderId;
+import org.onosproject.openstacknetworking.api.Constants;
 import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
 import org.onosproject.openstacknode.api.OpenstackNode;
 import org.onosproject.openstacknode.api.OpenstackNodeEvent;
@@ -69,7 +70,10 @@
 import static org.onosproject.openstacknetworking.api.Constants.ANNOTATION_PORT_ID;
 import static org.onosproject.openstacknetworking.api.Constants.ANNOTATION_SEGMENT_ID;
 import static org.onosproject.openstacknetworking.api.Constants.OPENSTACK_NETWORKING_APP_ID;
+import static org.onosproject.openstacknetworking.api.Constants.PORT_NAME_PREFIX_VM;
+import static org.onosproject.openstacknetworking.api.Constants.PORT_NAME_VHOST_USER_PREFIX_VM;
 import static org.onosproject.openstacknetworking.api.Constants.portNamePrefixMap;
+import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.vnicType;
 import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.CONTROLLER;
 
 @Service
@@ -79,7 +83,6 @@
 
     private final Logger log = LoggerFactory.getLogger(getClass());
 
-    private static final String PORT_NAME_PREFIX_VM = "tap";
     private static final String ERR_ADD_HOST = "Failed to add host: ";
     private static final String SONA_HOST_SCHEME = "sona";
 
@@ -315,7 +318,9 @@
             String portName = port.annotations().value(PORT_NAME);
 
             return !Strings.isNullOrEmpty(portName) &&
-                    (portName.startsWith(PORT_NAME_PREFIX_VM) || isDirectPort(portName));
+                    (portName.startsWith(PORT_NAME_PREFIX_VM) ||
+                            isDirectPort(portName) ||
+                            portName.startsWith(PORT_NAME_VHOST_USER_PREFIX_VM));
         }
 
         private boolean isDirectPort(String portName) {
@@ -385,9 +390,9 @@
 
         private void processCompleteNode(OpenstackNode osNode) {
             deviceService.getPorts(osNode.intgBridge()).stream()
-                    .filter(port -> port.annotations().value(PORT_NAME)
-                            .startsWith(PORT_NAME_PREFIX_VM) &&
-                            port.isEnabled())
+                    .filter(port -> vnicType(port.annotations().value(PORT_NAME)).equals(Constants.VnicType.NORMAL) ||
+                            vnicType(port.annotations().value(PORT_NAME)).equals(Constants.VnicType.DIRECT))
+                    .filter(Port::isEnabled)
                     .forEach(port -> {
                         log.debug("Instance port {} is detected from {}",
                                 port.annotations().value(PORT_NAME),
@@ -395,18 +400,6 @@
                         processPortAdded(port);
                     });
 
-            portNamePrefixMap().values().forEach(portNamePrefix ->
-                    deviceService.getPorts(osNode.intgBridge()).stream()
-                    .filter(port -> port.annotations().value(PORT_NAME)
-                            .startsWith(portNamePrefix) &&
-                            port.isEnabled())
-                    .forEach(port -> {
-                        log.debug("Instance port {} is detected from {}",
-                                port.annotations().value(portNamePrefix),
-                                osNode.hostname());
-                        processPortAdded(port);
-                    }));
-
             Tools.stream(hostService.getHosts())
                     .filter(host -> deviceService.getPort(
                             host.location().deviceId(),
diff --git a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/util/OpenstackNetworkingUtil.java b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/util/OpenstackNetworkingUtil.java
index ca9647f..32f4fdf 100644
--- a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/util/OpenstackNetworkingUtil.java
+++ b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/util/OpenstackNetworkingUtil.java
@@ -25,6 +25,7 @@
 import org.onosproject.cfg.ConfigProperty;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.device.DeviceService;
+import org.onosproject.openstacknetworking.api.Constants.VnicType;
 import org.onosproject.openstacknetworking.api.InstancePort;
 import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
 import org.onosproject.openstacknetworking.api.OpenstackRouterAdminService;
@@ -71,6 +72,8 @@
 import static org.onosproject.net.AnnotationKeys.PORT_NAME;
 import static org.onosproject.openstacknetworking.api.Constants.PCISLOT;
 import static org.onosproject.openstacknetworking.api.Constants.PCI_VENDOR_INFO;
+import static org.onosproject.openstacknetworking.api.Constants.PORT_NAME_PREFIX_VM;
+import static org.onosproject.openstacknetworking.api.Constants.PORT_NAME_VHOST_USER_PREFIX_VM;
 import static org.onosproject.openstacknetworking.api.Constants.portNamePrefixMap;
 import static org.openstack4j.core.transport.ObjectMapperSingleton.getContext;
 
@@ -467,6 +470,21 @@
                 Objects.equals(routerInterface1.getTenantId(), routerInterface2.getTenantId());
     }
 
+    public static VnicType vnicType(String portName) {
+        if (portName.startsWith(PORT_NAME_PREFIX_VM) ||
+                portName.startsWith(PORT_NAME_VHOST_USER_PREFIX_VM)) {
+            return VnicType.NORMAL;
+        } else if (isDirectPort(portName)) {
+            return VnicType.DIRECT;
+        } else {
+            return VnicType.UNSUPPORTED;
+        }
+    }
+
+    private static boolean isDirectPort(String portName) {
+        return portNamePrefixMap().values().stream().filter(p -> portName.startsWith(p)).findAny().isPresent();
+    }
+
     /**
      * Builds up and a complete endpoint URL from gateway node.
      *
diff --git a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/web/OpenstackPortWebResource.java b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/web/OpenstackPortWebResource.java
index 94c30e7..d5b2e2d 100644
--- a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/web/OpenstackPortWebResource.java
+++ b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/web/OpenstackPortWebResource.java
@@ -15,7 +15,11 @@
  */
 package org.onosproject.openstacknetworking.web;
 
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
 import org.onosproject.openstacknetworking.api.OpenstackNetworkAdminService;
+import org.onosproject.openstacknode.api.OpenstackNode;
+import org.onosproject.openstacknode.api.OpenstackNodeService;
 import org.onosproject.rest.AbstractWebResource;
 import org.openstack4j.openstack.networking.domain.NeutronPort;
 import org.slf4j.Logger;
@@ -49,9 +53,12 @@
 
     private static final String MESSAGE = "Received ports %s request";
     private static final String PORTS = "ports";
+    private static final String VIF_TYPE = "vif_type";
+    private static final String VHOSTUSER = "vhostuser";
+    private static final String SOCKET_DIR = "socket_dir";
 
-    private final OpenstackNetworkAdminService adminService =
-                                        get(OpenstackNetworkAdminService.class);
+    private final OpenstackNetworkAdminService adminService = get(OpenstackNetworkAdminService.class);
+    private final OpenstackNodeService nodeService = get(OpenstackNodeService.class);
 
     @Context
     private UriInfo uriInfo;
@@ -101,8 +108,25 @@
                                  jsonToModelEntity(input, NeutronPort.class);
 
         adminService.updatePort(port);
+        ObjectMapper mapper = new ObjectMapper();
+        ObjectNode jsonNode = mapper.createObjectNode();
 
-        return status(Response.Status.OK).build();
+        OpenstackNode node = nodeService.node(port.getHostId());
+        if (node == null) {
+            return status(Response.Status.OK).build();
+        } else if (node.datapathType().equals(OpenstackNode.DatapathType.NETDEV)) {
+            log.debug("UpdatePort for port {} called in netdev device {} " +
+                            "so sends vif type as a payload of the response",
+                    port.getId(), node.hostname());
+            jsonNode.put(VIF_TYPE, VHOSTUSER);
+
+            if (node.socketDir() != null) {
+                jsonNode.put(SOCKET_DIR, node.socketDir());
+            }
+            return status(Response.Status.OK).entity(jsonNode.toString()).build();
+        } else {
+            return status(Response.Status.OK).build();
+        }
     }
 
     /**
diff --git a/apps/openstacknetworking/app/src/test/java/org/onosproject/openstacknetworking/util/OpenstackNetworkingUtilTest.java b/apps/openstacknetworking/app/src/test/java/org/onosproject/openstacknetworking/util/OpenstackNetworkingUtilTest.java
index 0e291f8..daf0a9a 100644
--- a/apps/openstacknetworking/app/src/test/java/org/onosproject/openstacknetworking/util/OpenstackNetworkingUtilTest.java
+++ b/apps/openstacknetworking/app/src/test/java/org/onosproject/openstacknetworking/util/OpenstackNetworkingUtilTest.java
@@ -36,6 +36,7 @@
 import org.onosproject.net.PortNumber;
 import org.onosproject.net.device.DeviceService;
 import org.onosproject.net.device.DeviceServiceAdapter;
+import org.onosproject.openstacknetworking.api.Constants;
 import org.onosproject.openstacknetworking.api.InstancePort;
 import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
 import org.onosproject.openstacknetworking.api.OpenstackRouterAdminService;
@@ -84,6 +85,7 @@
 import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.prettyJson;
 import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.routerInterfacesEquals;
 import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.swapStaleLocation;
+import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.vnicType;
 
 public final class OpenstackNetworkingUtilTest {
 
@@ -438,6 +440,22 @@
 
     }
 
+    /**
+     * Tests the vnicType method.
+     */
+    @Test
+    public void testVnicType() {
+        String portNameNormalTap = "tap123456789ab";
+        String portNameNormalVhu = "tap123456789ab";
+        String portNameNormalCavium = "enp1f2s3";
+        String portNameUnsupported = "123456789ab";
+
+        assertEquals(vnicType(portNameNormalTap), Constants.VnicType.NORMAL);
+        assertEquals(vnicType(portNameNormalVhu), Constants.VnicType.NORMAL);
+        assertEquals(vnicType(portNameNormalCavium), Constants.VnicType.DIRECT);
+        assertEquals(vnicType(portNameUnsupported), Constants.VnicType.UNSUPPORTED);
+    }
+
     private DeviceId genDeviceId(int index) {
         return DeviceId.deviceId("of:compute-" + index);
     }
diff --git a/apps/openstacknetworking/app/src/test/java/org/onosproject/openstacknetworking/web/OpenstackPortWebResourceTest.java b/apps/openstacknetworking/app/src/test/java/org/onosproject/openstacknetworking/web/OpenstackPortWebResourceTest.java
index e3f4bf0..7d7a603 100644
--- a/apps/openstacknetworking/app/src/test/java/org/onosproject/openstacknetworking/web/OpenstackPortWebResourceTest.java
+++ b/apps/openstacknetworking/app/src/test/java/org/onosproject/openstacknetworking/web/OpenstackPortWebResourceTest.java
@@ -21,6 +21,7 @@
 import org.onlab.osgi.ServiceDirectory;
 import org.onlab.osgi.TestServiceDirectory;
 import org.onosproject.openstacknetworking.api.OpenstackNetworkAdminService;
+import org.onosproject.openstacknode.api.OpenstackNodeService;
 import org.onosproject.rest.resources.ResourceTest;
 
 import javax.ws.rs.client.Entity;
@@ -45,6 +46,8 @@
 
     final OpenstackNetworkAdminService mockOpenstackNetworkAdminService =
             createMock(OpenstackNetworkAdminService.class);
+    final OpenstackNodeService mockOpenstackNodeService =
+            createMock(OpenstackNodeService.class);
     private static final String PATH = "ports";
 
     /**
@@ -59,10 +62,9 @@
      */
     @Before
     public void setUpTest() {
-        ServiceDirectory testDirectory =
-                new TestServiceDirectory()
-                        .add(OpenstackNetworkAdminService.class,
-                                mockOpenstackNetworkAdminService);
+        ServiceDirectory testDirectory = new TestServiceDirectory()
+                .add(OpenstackNetworkAdminService.class, mockOpenstackNetworkAdminService)
+                .add(OpenstackNodeService.class, mockOpenstackNodeService);
         setServiceDirectory(testDirectory);
 
     }