tapv2: multiple improvements

- change interface naming scheme
- rework netlink code
- add option to set link address, namespace

Change-Id: Icf667babb3077a07617b0b87c45c957e345cb4d1
Signed-off-by: Damjan Marion <damarion@cisco.com>
diff --git a/src/vat/api_format.c b/src/vat/api_format.c
index d39a61a..4b2602d 100644
--- a/src/vat/api_format.c
+++ b/src/vat/api_format.c
@@ -7810,8 +7810,11 @@
   vl_api_tap_create_v2_t *mp;
   u8 mac_address[6];
   u8 random_mac = 1;
-  u8 *tap_name = 0;
-  u8 *host_namespace = 0;
+  u32 id = ~0;
+  u8 *host_if_name = 0;
+  u8 *host_ns = 0;
+  u8 host_mac_addr[6];
+  u8 host_mac_addr_set = 0;
   u8 *host_bridge = 0;
   ip4_address_t host_ip4_addr;
   u32 host_ip4_prefix_len = 0;
@@ -7829,10 +7832,15 @@
 	{
 	  random_mac = 0;
 	}
-      else if (unformat (i, "name %s", &tap_name))
+      else if (unformat (i, "id %s", &id))
 	;
-      else if (unformat (i, "host-ns %s", &host_namespace))
+      else if (unformat (i, "host-if-name %s", &host_if_name))
 	;
+      else if (unformat (i, "host-ns %s", &host_ns))
+	;
+      else if (unformat (i, "host-mac-addr %U", unformat_ethernet_address,
+			 host_mac_addr))
+	host_mac_addr_set = 1;
       else if (unformat (i, "host-bridge %s", &host_bridge))
 	;
       else if (unformat (i, "host-ip4-addr %U/%d", unformat_ip4_address,
@@ -7849,17 +7857,12 @@
 	break;
     }
 
-  if (tap_name == 0)
-    {
-      errmsg ("missing tap name. ");
-      return -99;
-    }
-  if (vec_len (tap_name) > 63)
+  if (vec_len (host_if_name) > 63)
     {
       errmsg ("tap name too long. ");
       return -99;
     }
-  if (vec_len (host_namespace) > 63)
+  if (vec_len (host_ns) > 63)
     {
       errmsg ("host name space too long. ");
       return -99;
@@ -7900,23 +7903,27 @@
       return -99;
     }
 
-  vec_add1 (tap_name, 0);
-
   /* Construct the API message */
   M (TAP_CREATE_V2, mp);
 
   mp->use_random_mac = random_mac;
-  clib_memcpy (mp->mac_address, mac_address, 6);
-  clib_memcpy (mp->tap_name, tap_name, vec_len (tap_name));
-  mp->host_namespace_set = host_namespace != 0;
+
+  mp->id = id;
+  mp->host_namespace_set = host_ns != 0;
   mp->host_bridge_set = host_bridge != 0;
   mp->host_ip4_addr_set = host_ip4_prefix_len != 0;
   mp->host_ip6_addr_set = host_ip6_prefix_len != 0;
   mp->rx_ring_sz = rx_ring_sz;
   mp->tx_ring_sz = tx_ring_sz;
-  if (host_namespace)
-    clib_memcpy (mp->host_namespace, host_namespace,
-		 vec_len (host_namespace));
+
+  if (random_mac)
+    clib_memcpy (mp->mac_address, mac_address, 6);
+  if (host_mac_addr_set)
+    clib_memcpy (mp->host_mac_addr, host_mac_addr, 6);
+  if (host_if_name)
+    clib_memcpy (mp->host_if_name, host_if_name, vec_len (host_if_name));
+  if (host_ns)
+    clib_memcpy (mp->host_namespace, host_ns, vec_len (host_ns));
   if (host_bridge)
     clib_memcpy (mp->host_bridge, host_bridge, vec_len (host_bridge));
   if (host_ip4_prefix_len)
@@ -7925,7 +7932,9 @@
     clib_memcpy (mp->host_ip6_addr, &host_ip6_addr, 16);
 
 
-  vec_free (tap_name);
+  vec_free (host_ns);
+  vec_free (host_if_name);
+  vec_free (host_bridge);
 
   /* send it... */
   S (mp);
diff --git a/src/vnet/devices/netlink.c b/src/vnet/devices/netlink.c
index b3330dd..5994366 100644
--- a/src/vnet/devices/netlink.c
+++ b/src/vnet/devices/netlink.c
@@ -19,36 +19,31 @@
 #include <sys/stat.h>
 #include <fcntl.h>
 #include <net/if.h>
-#include <linux/if_tun.h>
-#include <sys/ioctl.h>
-#include <linux/virtio_net.h>
-#include <linux/vhost.h>
-#include <sys/eventfd.h>
 
 #include <linux/netlink.h>
 #include <linux/rtnetlink.h>
 
 #include <vlib/vlib.h>
 #include <vlib/unix/unix.h>
+#include <vnet/devices/netlink.h>
 
 typedef struct
 {
   u8 *data;
 } vnet_netlink_msg_t;
 
-void
+static void
 vnet_netlink_msg_init (vnet_netlink_msg_t * m, u16 type, u16 flags,
 		       void *msg_data, int msg_len)
 {
   struct nlmsghdr *nh;
   u8 *p;
-  int len = NLMSG_LENGTH (msg_len);
   memset (m, 0, sizeof (vnet_netlink_msg_t));
-  vec_add2 (m->data, p, len);
+  vec_add2 (m->data, p, NLMSG_SPACE (msg_len));
   ASSERT (m->data == p);
 
   nh = (struct nlmsghdr *) p;
-  nh->nlmsg_flags = flags;
+  nh->nlmsg_flags = flags | NLM_F_ACK;
   nh->nlmsg_type = type;
   clib_memcpy (m->data + sizeof (struct nlmsghdr), msg_data, msg_len);
 }
@@ -60,7 +55,7 @@
   struct rtattr *rta;
   u8 *p;
 
-  vec_add2 (m->data, p, RTA_LENGTH (rta_data_len));
+  vec_add2 (m->data, p, RTA_SPACE (rta_data_len));
   rta = (struct rtattr *) p;
   rta->rta_type = rta_type;
   rta->rta_len = RTA_LENGTH (rta_data_len);
@@ -72,9 +67,10 @@
 {
   clib_error_t *err = 0;
   struct sockaddr_nl ra = { 0 };
-  int sock;
+  int len, sock;
   struct nlmsghdr *nh = (struct nlmsghdr *) m->data;
   nh->nlmsg_len = vec_len (m->data);
+  char buf[4096];
 
   if ((sock = socket (AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) == -1)
     return clib_error_return_unix (0, "socket(AF_NETLINK)");
@@ -85,87 +81,126 @@
   if ((bind (sock, (struct sockaddr *) &ra, sizeof (ra))) == -1)
     {
       err = clib_error_return_unix (0, "bind");
-      goto error;
+      goto done;
     }
 
   if ((send (sock, m->data, vec_len (m->data), 0)) == -1)
     err = clib_error_return_unix (0, "send");
 
-error:
+  if ((len = recv (sock, buf, sizeof (buf), 0)) == -1)
+    err = clib_error_return_unix (0, "recv");
+
+  for (nh = (struct nlmsghdr *) buf; NLMSG_OK (nh, len);
+       nh = NLMSG_NEXT (nh, len))
+    {
+      if (nh->nlmsg_type == NLMSG_DONE)
+	goto done;
+
+      if (nh->nlmsg_type == NLMSG_ERROR)
+	{
+	  struct nlmsgerr *e = (struct nlmsgerr *) NLMSG_DATA (nh);
+	  if (e->error)
+	    err = clib_error_return (0, "netlink error %d", e->error);
+	  goto done;
+	}
+    }
+
+done:
   close (sock);
   vec_free (m->data);
   return err;
 }
 
 clib_error_t *
-vnet_netlink_set_if_namespace (int ifindex, char *net_ns)
+vnet_netlink_set_link_name (int ifindex, char *new_ifname)
 {
   vnet_netlink_msg_t m;
   struct ifinfomsg ifmsg = { 0 };
 
-  clib_error_t *err;
-  int data;
-  u16 type;
-  u8 *s;
-
-  if (strncmp (net_ns, "pid:", 4) == 0)
-    {
-      data = atoi (net_ns + 4);
-      type = IFLA_NET_NS_PID;
-    }
-  else
-    {
-      if (net_ns[0] == '/')
-	s = format (0, "%s%c", net_ns, 0);
-      else
-	s = format (0, "/var/run/netns/%s%c", net_ns, 0);
-
-      data = open ((char *) s, O_RDONLY);
-      type = IFLA_NET_NS_FD;
-      vec_free (s);
-      if (data == -1)
-	return clib_error_return (0, "namespace '%s' doesn't exist", net_ns);
-    }
-
-  ifmsg.ifi_family = AF_UNSPEC;
   ifmsg.ifi_index = ifindex;
-  ifmsg.ifi_change = 0xffffffff;
   vnet_netlink_msg_init (&m, RTM_SETLINK, NLM_F_REQUEST,
 			 &ifmsg, sizeof (struct ifinfomsg));
 
-  vnet_netlink_msg_add_rtattr (&m, type, &data, sizeof (int));
-  err = vnet_netlink_msg_send (&m);
+  vnet_netlink_msg_add_rtattr (&m, IFLA_IFNAME, new_ifname,
+			       strlen (new_ifname) + 1);
 
-  if (type == IFLA_NET_NS_FD)
-    close (data);
-  return err;
-}
-
-clib_error_t *
-vnet_netlink_set_if_master (int ifindex, int master_ifindex)
-{
-  vnet_netlink_msg_t m;
-  struct ifinfomsg ifmsg = { 0 };
-
-  ifmsg.ifi_family = AF_UNSPEC;
-  ifmsg.ifi_index = ifindex;
-  ifmsg.ifi_change = 0xffffffff;
-  vnet_netlink_msg_init (&m, RTM_SETLINK, NLM_F_REQUEST,
-			 &ifmsg, sizeof (struct ifinfomsg));
-  vnet_netlink_msg_add_rtattr (&m, IFLA_MASTER, &master_ifindex,
-			       sizeof (int));
   return vnet_netlink_msg_send (&m);
 }
 
 clib_error_t *
-vnet_netlink_set_if_mtu (int ifindex, int mtu)
+vnet_netlink_set_link_netns (int ifindex, int netns_fd, char *new_ifname)
 {
   vnet_netlink_msg_t m;
   struct ifinfomsg ifmsg = { 0 };
 
-  ifmsg.ifi_family = AF_UNSPEC;
   ifmsg.ifi_index = ifindex;
-  ifmsg.ifi_change = 0xffffffff;
+  vnet_netlink_msg_init (&m, RTM_SETLINK, NLM_F_REQUEST,
+			 &ifmsg, sizeof (struct ifinfomsg));
+
+  vnet_netlink_msg_add_rtattr (&m, IFLA_NET_NS_FD, &netns_fd, sizeof (int));
+  if (new_ifname)
+    vnet_netlink_msg_add_rtattr (&m, IFLA_IFNAME, new_ifname,
+				 strlen (new_ifname) + 1);
+
+  return vnet_netlink_msg_send (&m);
+}
+
+clib_error_t *
+vnet_netlink_set_link_master (int ifindex, char *master_ifname)
+{
+  vnet_netlink_msg_t m;
+  struct ifinfomsg ifmsg = { 0 };
+  int i;
+
+  ifmsg.ifi_index = ifindex;
+
+  if ((i = if_nametoindex (master_ifname)) == 0)
+    clib_error_return_unix (0, "unknown master interface '%s'",
+			    master_ifname);
+
+  vnet_netlink_msg_init (&m, RTM_SETLINK, NLM_F_REQUEST,
+			 &ifmsg, sizeof (struct ifinfomsg));
+  vnet_netlink_msg_add_rtattr (&m, IFLA_MASTER, &i, sizeof (int));
+  return vnet_netlink_msg_send (&m);
+}
+
+clib_error_t *
+vnet_netlink_set_link_addr (int ifindex, u8 * mac)
+{
+  vnet_netlink_msg_t m;
+  struct ifinfomsg ifmsg = { 0 };
+
+  ifmsg.ifi_index = ifindex;
+
+  vnet_netlink_msg_init (&m, RTM_SETLINK, NLM_F_REQUEST,
+			 &ifmsg, sizeof (struct ifinfomsg));
+  vnet_netlink_msg_add_rtattr (&m, IFLA_ADDRESS, mac, 6);
+  return vnet_netlink_msg_send (&m);
+}
+
+clib_error_t *
+vnet_netlink_set_link_state (int ifindex, int up)
+{
+  vnet_netlink_msg_t m;
+  struct ifinfomsg ifmsg = { 0 };
+
+  ifmsg.ifi_flags = IFF_UP;
+  ifmsg.ifi_change = IFF_UP;
+  ifmsg.ifi_index = ifindex;
+
+  vnet_netlink_msg_init (&m, RTM_SETLINK, NLM_F_REQUEST,
+			 &ifmsg, sizeof (struct ifinfomsg));
+  return vnet_netlink_msg_send (&m);
+}
+
+clib_error_t *
+vnet_netlink_set_link_mtu (int ifindex, int mtu)
+{
+  vnet_netlink_msg_t m;
+  struct ifinfomsg ifmsg = { 0 };
+
+  ifmsg.ifi_index = ifindex;
+
   vnet_netlink_msg_init (&m, RTM_SETLINK, NLM_F_REQUEST,
 			 &ifmsg, sizeof (struct ifinfomsg));
   vnet_netlink_msg_add_rtattr (&m, IFLA_MTU, &mtu, sizeof (int));
diff --git a/src/vnet/devices/netlink.h b/src/vnet/devices/netlink.h
index e61b827..e850196 100644
--- a/src/vnet/devices/netlink.h
+++ b/src/vnet/devices/netlink.h
@@ -16,9 +16,12 @@
 #ifndef included_vnet_device_netlink_h
 #define included_vnet_device_netlink_h
 
-clib_error_t *vnet_netlink_set_if_mtu (int ifindex, int mtu);
-clib_error_t *vnet_netlink_set_if_namespace (int ifindex, char *net_ns);
-clib_error_t *vnet_netlink_set_if_master (int ifindex, int master_ifindex);
+clib_error_t *vnet_netlink_set_link_name (int ifindex, char *new_ifname);
+clib_error_t *vnet_netlink_set_link_netns (int ifindex, int netns_fd,
+					   char *new_ifname);
+clib_error_t *vnet_netlink_set_link_master (int ifindex, char *master_ifname);
+clib_error_t *vnet_netlink_set_link_addr (int ifindex, u8 * addr);
+clib_error_t *vnet_netlink_set_link_state (int ifindex, int up);
 clib_error_t *vnet_netlink_add_ip4_addr (int ifindex, void *addr,
 					 int pfx_len);
 clib_error_t *vnet_netlink_add_ip6_addr (int ifindex, void *addr,
diff --git a/src/vnet/devices/tap/cli.c b/src/vnet/devices/tap/cli.c
index f7fc1e6..c86995c 100644
--- a/src/vnet/devices/tap/cli.c
+++ b/src/vnet/devices/tap/cli.c
@@ -38,38 +38,47 @@
   tap_create_if_args_t args = { 0 };
   int ip_addr_set = 0;
 
-  /* Get a line of input. */
-  if (!unformat_user (input, unformat_line_input, line_input))
-    return clib_error_return (0, "Missing name <interface>");
+  args.id = ~0;
 
-  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
+  /* Get a line of input. */
+  if (unformat_user (input, unformat_line_input, line_input))
     {
-      if (unformat (line_input, "name %s", &args.name))
-	;
-      else if (unformat (line_input, "host-ns %s", &args.host_namespace))
-	;
-      else if (unformat (line_input, "host-bridge %s", &args.host_bridge))
-	;
-      else if (unformat (line_input, "host-ip4-addr %U/%d",
-			 unformat_ip4_address, &args.host_ip4_addr,
-			 &args.host_ip4_prefix_len))
-	ip_addr_set = 1;
-      else if (unformat (line_input, "host-ip6-addr %U/%d",
-			 unformat_ip6_address, &args.host_ip6_addr,
-			 &args.host_ip6_prefix_len))
-	ip_addr_set = 1;
-      else if (unformat (line_input, "rx-ring-size %d", &args.rx_ring_sz))
-	;
-      else if (unformat (line_input, "tx-ring-size %d", &args.tx_ring_sz))
-	;
-      else if (unformat (line_input, "hw-addr %U",
-			 unformat_ethernet_address, args.hw_addr))
-	args.hw_addr_set = 1;
-      else
-	return clib_error_return (0, "unknown input `%U'",
-				  format_unformat_error, input);
+
+      while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
+	{
+	  if (unformat (line_input, "id %u", &args.id))
+	    ;
+	  else
+	    if (unformat (line_input, "host-if-name %s", &args.host_if_name))
+	    ;
+	  else if (unformat (line_input, "host-ns %s", &args.host_namespace))
+	    ;
+	  else if (unformat (line_input, "host-mac-addr %U",
+			     unformat_ethernet_address, args.host_mac_addr))
+	    ;
+	  else if (unformat (line_input, "host-bridge %s", &args.host_bridge))
+	    ;
+	  else if (unformat (line_input, "host-ip4-addr %U/%d",
+			     unformat_ip4_address, &args.host_ip4_addr,
+			     &args.host_ip4_prefix_len))
+	    ip_addr_set = 1;
+	  else if (unformat (line_input, "host-ip6-addr %U/%d",
+			     unformat_ip6_address, &args.host_ip6_addr,
+			     &args.host_ip6_prefix_len))
+	    ip_addr_set = 1;
+	  else if (unformat (line_input, "rx-ring-size %d", &args.rx_ring_sz))
+	    ;
+	  else if (unformat (line_input, "tx-ring-size %d", &args.tx_ring_sz))
+	    ;
+	  else if (unformat (line_input, "hw-addr %U",
+			     unformat_ethernet_address, args.mac_addr))
+	    args.mac_addr_set = 1;
+	  else
+	    return clib_error_return (0, "unknown input `%U'",
+				      format_unformat_error, input);
+	}
+      unformat_free (line_input);
     }
-  unformat_free (line_input);
 
   if (ip_addr_set && args.host_bridge)
     return clib_error_return (0, "Please specify either host ip address or "
@@ -77,7 +86,7 @@
 
   tap_create_if (vm, &args);
 
-  vec_free (args.name);
+  vec_free (args.host_if_name);
   vec_free (args.host_namespace);
   vec_free (args.host_bridge);
 
@@ -88,10 +97,10 @@
 /* *INDENT-OFF* */
 VLIB_CLI_COMMAND (tap_create_command, static) = {
   .path = "create tap",
-  .short_help = "create tap {name <if-name>} [hw-addr <mac-address>] "
+  .short_help = "create tap {id <if-id>} [hw-addr <mac-address>] "
     "[rx-ring-size <size>] [tx-ring-size <size>] [host-ns <netns>] "
     "[host-bridge <bridge-name>] [host-ip4-addr <ip4addr/mask>] "
-    "[host-ip6-addr <ip6-addr]",
+    "[host-ip6-addr <ip6-addr] [host-if-name <name>]",
   .function = tap_create_command_fn,
 };
 /* *INDENT-ON* */
@@ -209,8 +218,8 @@
       vif = pool_elt_at_index (mm->interfaces, hi->dev_instance);
       vlib_cli_output (vm, "interface %U", format_vnet_sw_if_index_name,
 		       vnm, vif->sw_if_index);
-      if (vif->name)
-	vlib_cli_output (vm, "  name \"%s\"", vif->name);
+      if (vif->host_if_name)
+	vlib_cli_output (vm, "  name \"%s\"", vif->host_if_name);
       if (vif->net_ns)
 	vlib_cli_output (vm, "  host-ns \"%s\"", vif->net_ns);
       vlib_cli_output (vm, "  flags 0x%x", vif->flags);
diff --git a/src/vnet/devices/tap/tap.c b/src/vnet/devices/tap/tap.c
index b4004f7..f31548c 100644
--- a/src/vnet/devices/tap/tap.c
+++ b/src/vnet/devices/tap/tap.c
@@ -15,6 +15,7 @@
  *------------------------------------------------------------------
  */
 
+#define _GNU_SOURCE
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
@@ -24,6 +25,7 @@
 #include <linux/virtio_net.h>
 #include <linux/vhost.h>
 #include <sys/eventfd.h>
+#include <sched.h>
 
 #include <linux/netlink.h>
 #include <linux/rtnetlink.h>
@@ -37,6 +39,8 @@
 #include <vnet/devices/virtio/virtio.h>
 #include <vnet/devices/tap/tap.h>
 
+tap_main_t tap_main;
+
 #define _IOCTL(fd,a,...) \
   if (ioctl (fd, a, __VA_ARGS__) < 0) \
     { \
@@ -53,24 +57,79 @@
   return 0;
 }
 
+static int
+open_netns_fd (char *netns)
+{
+  u8 *s = 0;
+  int fd;
+
+  if (strncmp (netns, "pid:", 4) == 0)
+    s = format (0, "/proc/%u/ns/net%c", atoi (netns + 4), 0);
+  else if (netns[0] == '/')
+    s = format (0, "%s%c", netns, 0);
+  else
+    s = format (0, "/var/run/netns/%s%c", netns, 0);
+
+  fd = open ((char *) s, O_RDONLY);
+  vec_free (s);
+  return fd;
+}
+
+
 void
 tap_create_if (vlib_main_t * vm, tap_create_if_args_t * args)
 {
   vnet_main_t *vnm = vnet_get_main ();
   virtio_main_t *vim = &virtio_main;
+  tap_main_t *tm = &tap_main;
   vnet_sw_interface_t *sw;
   vnet_hw_interface_t *hw;
   int i, fd = -1;
+  int old_netns_fd = -1;
   struct ifreq ifr;
   size_t hdrsz;
   struct vhost_memory *vhost_mem = 0;
   virtio_if_t *vif = 0;
   clib_error_t *err = 0;
+  uword *p;
+
+  if (args->id != ~0)
+    {
+      p = hash_get (tm->dev_instance_by_interface_id, args->id);
+      if (p)
+	{
+	  args->rv = VNET_API_ERROR_INVALID_INTERFACE;
+	  args->error = clib_error_return (0, "interface already exists");
+	  return;
+	}
+    }
+  else
+    {
+      int tries = 1000;
+      while (--tries)
+	{
+	  args->id = tm->last_used_interface_id++;
+	  p = hash_get (tm->dev_instance_by_interface_id, args->id);
+	  if (!p)
+	    break;
+	}
+
+      if (!tries)
+	{
+	  args->rv = VNET_API_ERROR_UNSPECIFIED;
+	  args->error =
+	    clib_error_return (0, "cannot find free interface id");
+	  return;
+	}
+    }
 
   memset (&ifr, 0, sizeof (ifr));
   pool_get (vim->interfaces, vif);
   vif->dev_instance = vif - vim->interfaces;
   vif->tap_fd = -1;
+  vif->id = args->id;
+
+  hash_set (tm->dev_instance_by_interface_id, vif->id, vif->dev_instance);
 
   if ((vif->fd = open ("/dev/vhost-net", O_RDWR | O_NONBLOCK)) < 0)
     {
@@ -119,10 +178,8 @@
     }
 
   ifr.ifr_flags = IFF_TAP | IFF_NO_PI | IFF_ONE_QUEUE | IFF_VNET_HDR;
-  strncpy (ifr.ifr_ifrn.ifrn_name, (char *) args->name, IF_NAMESIZE - 1);
   _IOCTL (vif->tap_fd, TUNSETIFF, (void *) &ifr);
-
-  vif->ifindex = if_nametoindex ((char *) args->name);
+  vif->ifindex = if_nametoindex (ifr.ifr_ifrn.ifrn_name);
 
   unsigned int offload = 0;
   hdrsz = sizeof (struct virtio_net_hdr_v1);
@@ -130,10 +187,61 @@
   _IOCTL (vif->tap_fd, TUNSETVNETHDRSZ, &hdrsz);
   _IOCTL (vif->fd, VHOST_SET_OWNER, 0);
 
-  if (args->host_bridge)
+  /* if namespace is specified, all further netlink messages should be excuted
+     after we change our net namespace */
+  if (args->host_namespace)
     {
-      int master_ifindex = if_nametoindex ((char *) args->host_bridge);
-      args->error = vnet_netlink_set_if_master (vif->ifindex, master_ifindex);
+      int fd;
+      old_netns_fd = open ("/proc/self/ns/net", O_RDONLY);
+      if ((fd = open_netns_fd ((char *) args->host_namespace)) == -1)
+	{
+	  args->rv = VNET_API_ERROR_SYSCALL_ERROR_2;
+	  args->error = clib_error_return_unix (0, "open_netns_fd '%s'",
+						args->host_namespace);
+	  goto error;
+	}
+      args->error = vnet_netlink_set_link_netns (vif->ifindex, fd,
+						 (char *) args->host_if_name);
+      if (args->error)
+	{
+	  args->rv = VNET_API_ERROR_NETLINK_ERROR;
+	  goto error;
+	}
+      if (setns (fd, CLONE_NEWNET) == -1)
+	{
+	  args->rv = VNET_API_ERROR_SYSCALL_ERROR_3;
+	  args->error = clib_error_return_unix (0, "setns '%s'",
+						args->host_namespace);
+	  goto error;
+	}
+      close (fd);
+      if ((vif->ifindex = if_nametoindex ((char *) args->host_if_name)) == 0)
+	{
+	  args->rv = VNET_API_ERROR_SYSCALL_ERROR_3;
+	  args->error = clib_error_return_unix (0, "if_nametoindex '%s'",
+						args->host_if_name);
+	  goto error;
+	}
+    }
+  else
+    {
+      if (args->host_if_name)
+	{
+	  args->error = vnet_netlink_set_link_name (vif->ifindex,
+						    (char *)
+						    args->host_if_name);
+	  if (args->error)
+	    {
+	      args->rv = VNET_API_ERROR_NETLINK_ERROR;
+	      goto error;
+	    }
+	}
+    }
+
+  if (!ethernet_mac_address_is_zero (args->host_mac_addr))
+    {
+      args->error = vnet_netlink_set_link_addr (vif->ifindex,
+						args->host_mac_addr);
       if (args->error)
 	{
 	  args->rv = VNET_API_ERROR_NETLINK_ERROR;
@@ -141,11 +249,10 @@
 	}
     }
 
-  if (args->host_namespace)
+  if (args->host_bridge)
     {
-      args->error = vnet_netlink_set_if_namespace (vif->ifindex,
-						   (char *)
-						   args->host_namespace);
+      args->error = vnet_netlink_set_link_master (vif->ifindex,
+						  (char *) args->host_bridge);
       if (args->error)
 	{
 	  args->rv = VNET_API_ERROR_NETLINK_ERROR;
@@ -153,6 +260,7 @@
 	}
     }
 
+
   if (args->host_ip4_prefix_len)
     {
       args->error = vnet_netlink_add_ip4_addr (vif->ifindex,
@@ -177,6 +285,25 @@
 	}
     }
 
+  args->error = vnet_netlink_set_link_state (vif->ifindex, 1 /* UP */ );
+  if (args->error)
+    {
+      args->rv = VNET_API_ERROR_NETLINK_ERROR;
+      goto error;
+    }
+
+  /* switch back to old net namespace */
+  if (args->host_namespace)
+    {
+      if (setns (old_netns_fd, CLONE_NEWNET) == -1)
+	{
+	  args->rv = VNET_API_ERROR_SYSCALL_ERROR_2;
+	  args->error = clib_error_return_unix (0, "setns '%s'",
+						args->host_namespace);
+	  goto error;
+	}
+    }
+
   /* Set vhost memory table */
   i = sizeof (struct vhost_memory) + sizeof (struct vhost_memory_region);
   vhost_mem = clib_mem_alloc (i);
@@ -197,33 +324,24 @@
       goto error;
     }
 
-  /* set host side up */
-  if ((fd = socket (AF_INET, SOCK_STREAM, 0)) > 0)
-    {
-      memset (&ifr, 0, sizeof (struct ifreq));
-      strncpy (ifr.ifr_name, (char *) args->name, sizeof (ifr.ifr_name) - 1);
-      _IOCTL (fd, SIOCGIFFLAGS, (void *) &ifr);
-      ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
-      _IOCTL (fd, SIOCSIFFLAGS, (void *) &ifr);
-    }
-
-  if (!args->hw_addr_set)
+  if (!args->mac_addr_set)
     {
       f64 now = vlib_time_now (vm);
       u32 rnd;
       rnd = (u32) (now * 1e6);
       rnd = random_u32 (&rnd);
 
-      memcpy (args->hw_addr + 2, &rnd, sizeof (rnd));
-      args->hw_addr[0] = 2;
-      args->hw_addr[1] = 0xfe;
+      memcpy (args->mac_addr + 2, &rnd, sizeof (rnd));
+      args->mac_addr[0] = 2;
+      args->mac_addr[1] = 0xfe;
     }
-  vif->name = args->name;
-  args->name = 0;
+  vif->host_if_name = args->host_if_name;
+  args->host_if_name = 0;
   vif->net_ns = args->host_namespace;
   args->host_namespace = 0;
   args->error = ethernet_register_interface (vnm, virtio_device_class.index,
-					     vif->dev_instance, args->hw_addr,
+					     vif->dev_instance,
+					     args->mac_addr,
 					     &vif->hw_if_index,
 					     virtio_eth_flag_change);
   if (args->error)
@@ -276,6 +394,7 @@
 {
   vnet_main_t *vnm = vnet_get_main ();
   virtio_main_t *mm = &virtio_main;
+  tap_main_t *tm = &tap_main;
   int i;
   virtio_if_t *vif;
   vnet_hw_interface_t *hw;
@@ -301,6 +420,7 @@
   vec_foreach_index (i, vif->vrings) virtio_vring_free (vif, i);
   vec_free (vif->vrings);
 
+  hash_unset (tm->dev_instance_by_interface_id, vif->id);
   memset (vif, 0, sizeof (*vif));
   pool_put (mm->interfaces, vif);
 
@@ -337,7 +457,8 @@
 static clib_error_t *
 tap_init (vlib_main_t * vm)
 {
-
+  tap_main_t *tm = &tap_main;
+  tm->dev_instance_by_interface_id = hash_create (0, sizeof (uword));
   return 0;
 }
 
diff --git a/src/vnet/devices/tap/tap.h b/src/vnet/devices/tap/tap.h
index 0e0f8cb..7d07ffb 100644
--- a/src/vnet/devices/tap/tap.h
+++ b/src/vnet/devices/tap/tap.h
@@ -24,12 +24,14 @@
 
 typedef struct
 {
-  u8 *name;
-  u8 hw_addr_set;
-  u8 hw_addr[6];
+  u32 id;
+  u8 mac_addr_set;
+  u8 mac_addr[6];
   u16 rx_ring_sz;
   u16 tx_ring_sz;
   u8 *host_namespace;
+  u8 *host_if_name;
+  u8 host_mac_addr[6];
   u8 *host_bridge;
   ip4_address_t host_ip4_addr;
   u32 host_ip4_prefix_len;
@@ -48,6 +50,12 @@
   u8 dev_name[64];
 } tap_interface_details_t;
 
+typedef struct
+{
+  u32 last_used_interface_id;
+  uword *dev_instance_by_interface_id;
+} tap_main_t;
+
 void tap_create_if (vlib_main_t * vm, tap_create_if_args_t * args);
 int tap_delete_if (vlib_main_t * vm, u32 sw_if_index);
 int tap_dump_ifs (tap_interface_details_t ** out_tapids);
diff --git a/src/vnet/devices/tap/tapv2.api b/src/vnet/devices/tap/tapv2.api
index 0378860..a206269 100644
--- a/src/vnet/devices/tap/tapv2.api
+++ b/src/vnet/devices/tap/tapv2.api
@@ -24,11 +24,15 @@
 /** \brief Initialize a new tap interface with the given paramters
     @param client_index - opaque cookie to identify the sender
     @param context - sender context, to match reply w/ request
+    @param id - interface id, 0xffff means auto
     @param use_random_mac - let the system generate a unique mac address
-    @param tap_name - name to associate with the new interface
     @param mac_address - mac addr to assign to the interface if use_radom not set
     @param tx_ring_sz - the number of entries of TX ring
     @param rx_ring_sz - the number of entries of RX ring
+    @param host_mac_addr_set - host side interface mac address should be set
+    @param host_mac_addr - host side interface mac address
+    @param host_if_name_set - host side interface name should be set
+    @param host_if_name - host side interface name
     @param host_namespace_set - host namespece should be set
     @param host_namespace - host namespace to attach interface to
     @param host_bridge_set - host bridge should be set
@@ -44,13 +48,17 @@
 {
   u32 client_index;
   u32 context;
+  u32 id;
   u8 use_random_mac;
-  u8 tap_name[64];
   u8 mac_address[6];
   u16 tx_ring_sz; /* optional, default is 256 entries, must be power of 2 */
   u16 rx_ring_sz; /* optional, default is 256 entries, must be power of 2 */
   u8 host_namespace_set;
   u8 host_namespace[64];
+  u8 host_mac_addr_set;
+  u8 host_mac_addr[6];
+  u8 host_if_name_set;
+  u8 host_if_name[64];
   u8 host_bridge_set;
   u8 host_bridge[64];
   u8 host_ip4_addr_set;
diff --git a/src/vnet/devices/tap/tapv2_api.c b/src/vnet/devices/tap/tapv2_api.c
index 2b324d6..3cededb 100644
--- a/src/vnet/devices/tap/tapv2_api.c
+++ b/src/vnet/devices/tap/tapv2_api.c
@@ -59,16 +59,25 @@
 
   memset (ap, 0, sizeof (*ap));
 
-  ap->name = mp->tap_name;
+  ap->id = mp->id;
   if (!mp->use_random_mac)
     {
-      clib_memcpy (ap->hw_addr, mp->mac_address, 6);
-      ap->hw_addr_set = 1;
+      clib_memcpy (ap->mac_addr, mp->mac_address, 6);
+      ap->mac_addr_set = 1;
     }
   ap->rx_ring_sz = ntohs (mp->rx_ring_sz);
   ap->tx_ring_sz = ntohs (mp->tx_ring_sz);
   ap->sw_if_index = (u32) ~ 0;
 
+  if (mp->host_if_name_set)
+    ap->host_if_name = mp->host_if_name;
+
+  if (mp->host_mac_addr_set)
+    {
+      clib_memcpy (ap->host_mac_addr, mp->host_mac_addr, 6);
+      ap->mac_addr_set = 1;
+    }
+
   if (mp->host_namespace_set)
     ap->host_namespace = mp->host_namespace;
 
diff --git a/src/vnet/devices/virtio/device.c b/src/vnet/devices/virtio/device.c
index 275a3c7..d4ef6d8 100644
--- a/src/vnet/devices/virtio/device.c
+++ b/src/vnet/devices/virtio/device.c
@@ -55,7 +55,7 @@
 
   if (vif->type == VIRTIO_IF_TYPE_TAP)
     {
-      s = format (s, "tap-%s", vif->name);
+      s = format (s, "tap%u", vif->id);
     }
   else
     s = format (s, "virtio%lu", vif->dev_instance);
diff --git a/src/vnet/devices/virtio/virtio.h b/src/vnet/devices/virtio/virtio.h
index 7dcd90a..cb97df8 100644
--- a/src/vnet/devices/virtio/virtio.h
+++ b/src/vnet/devices/virtio/virtio.h
@@ -91,6 +91,7 @@
 typedef struct
 {
   u32 flags;
+  u32 id;
   u32 dev_instance;
   u32 hw_if_index;
   u32 sw_if_index;
@@ -102,7 +103,7 @@
   u64 features, remote_features;
 
   virtio_if_type_t type;
-  u8 *name;
+  u8 *host_if_name;
   u8 *net_ns;
   int ifindex;
 } virtio_if_t;
diff --git a/src/vnet/ethernet/ethernet.h b/src/vnet/ethernet/ethernet.h
index 2a3383a..9a97817 100644
--- a/src/vnet/ethernet/ethernet.h
+++ b/src/vnet/ethernet/ethernet.h
@@ -61,6 +61,12 @@
   return (a & (1ULL << (5 * 8))) != 0;
 }
 
+static inline int
+ethernet_mac_address_is_zero (u8 * mac)
+{
+  return ((*((u32 *) mac) == 0) && (*((u16 *) (mac + 4)) == 0));
+}
+
 static_always_inline int
 ethernet_frame_is_tagged (u16 type)
 {
diff --git a/src/vpp/api/custom_dump.c b/src/vpp/api/custom_dump.c
index a4d5870..c26d65a 100644
--- a/src/vpp/api/custom_dump.c
+++ b/src/vpp/api/custom_dump.c
@@ -556,9 +556,15 @@
   memset (null_mac, 0, sizeof (null_mac));
 
   s = format (0, "SCRIPT: tap_create_v2 ");
-  s = format (s, "name %s ", mp->tap_name);
+  s = format (s, "id %s ", mp->id);
   if (memcmp (mp->mac_address, null_mac, 6))
-    s = format (s, "hw-addr %U ", format_ethernet_address, mp->mac_address);
+    s = format (s, "mac-address %U ",
+		format_ethernet_address, mp->mac_address);
+  if (memcmp (mp->host_mac_addr, null_mac, 6))
+    s = format (s, "host-mac-addr %U ",
+		format_ethernet_address, mp->host_mac_addr);
+  if (mp->host_if_name_set)
+    s = format (s, "host-if-name %s ", mp->host_if_name);
   if (mp->host_namespace_set)
     s = format (s, "host-ns %s ", mp->host_namespace);
   if (mp->host_bridge_set)