tap: add support to configure tap interface host MTU size

This patch adds support to configure host mtu size using
api, cli or startup.conf.

Type: feature

Change-Id: I8ab087d82dbe7dedc498825c1a3ea3fcb2cce030
Signed-off-by: Mohsin Kazmi <sykazmi@cisco.com>
diff --git a/src/vnet/devices/netlink.h b/src/vnet/devices/netlink.h
index 0d3e0d2..4c76568 100644
--- a/src/vnet/devices/netlink.h
+++ b/src/vnet/devices/netlink.h
@@ -22,6 +22,7 @@
 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_set_link_mtu (int ifindex, int mtu);
 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 084fb90..c74d24a 100644
--- a/src/vnet/devices/tap/cli.c
+++ b/src/vnet/devices/tap/cli.c
@@ -76,6 +76,10 @@
 	    ;
 	  else if (unformat (line_input, "tx-ring-size %d", &args.tx_ring_sz))
 	    ;
+	  else
+	    if (unformat
+		(line_input, "host-mtu-size %d", &args.host_mtu_size))
+	    args.host_mtu_set = 1;
 	  else if (unformat (line_input, "no-gso"))
 	    args.tap_flags &= ~TAP_FLAG_GSO;
 	  else if (unformat (line_input, "gso"))
@@ -114,7 +118,8 @@
     "[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-ip4-gw <ip4-addr>] "
-    "[host-ip6-gw <ip6-addr>] [host-if-name <name>] [no-gso|gso]",
+    "[host-ip6-gw <ip6-addr>] [host-mac-addr <host-mac-address>] "
+    "[host-if-name <name>] [host-mtu-size <size>] [no-gso|gso]",
   .function = tap_create_command_fn,
 };
 /* *INDENT-ON* */
diff --git a/src/vnet/devices/tap/tap.c b/src/vnet/devices/tap/tap.c
index 35f1f2a..8dc798a 100644
--- a/src/vnet/devices/tap/tap.c
+++ b/src/vnet/devices/tap/tap.c
@@ -361,6 +361,29 @@
 	}
     }
 
+  if (args->host_mtu_set)
+    {
+      args->error =
+	vnet_netlink_set_link_mtu (vif->ifindex, args->host_mtu_size);
+      if (args->error)
+	{
+	  args->rv = VNET_API_ERROR_NETLINK_ERROR;
+	  goto error;
+	}
+    }
+  else if (tm->host_mtu_size != 0)
+    {
+      args->error =
+	vnet_netlink_set_link_mtu (vif->ifindex, tm->host_mtu_size);
+      if (args->error)
+	{
+	  args->rv = VNET_API_ERROR_NETLINK_ERROR;
+	  goto error;
+	}
+      args->host_mtu_set = 1;
+      args->host_mtu_size = tm->host_mtu_size;
+    }
+
   /* Set vhost memory table */
   i = sizeof (struct vhost_memory) + sizeof (struct vhost_memory_region);
   vhost_mem = clib_mem_alloc (i);
@@ -396,6 +419,7 @@
   args->host_namespace = 0;
   vif->host_bridge = args->host_bridge;
   args->host_bridge = 0;
+  vif->host_mtu_size = args->host_mtu_size;
   clib_memcpy (vif->host_mac_addr, args->host_mac_addr, 6);
   vif->host_ip4_prefix_len = args->host_ip4_prefix_len;
   vif->host_ip6_prefix_len = args->host_ip6_prefix_len;
@@ -627,6 +651,7 @@
     if (vif->host_ip6_prefix_len)
       clib_memcpy(tapid->host_ip6_addr, &vif->host_ip6_addr, 16);
     tapid->host_ip6_prefix_len = vif->host_ip6_prefix_len;
+    tapid->host_mtu_size = vif->host_mtu_size;
   );
   /* *INDENT-ON* */
 
@@ -636,6 +661,26 @@
 }
 
 static clib_error_t *
+tap_mtu_config (vlib_main_t * vm, unformat_input_t * input)
+{
+  tap_main_t *tm = &tap_main;
+
+  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (input, "host-mtu %d", &tm->host_mtu_size))
+	;
+      else
+	return clib_error_return (0, "unknown input `%U'",
+				  format_unformat_error, input);
+    }
+
+  return 0;
+}
+
+/* tap { host-mtu <size> } configuration. */
+VLIB_CONFIG_FUNCTION (tap_mtu_config, "tap");
+
+static clib_error_t *
 tap_init (vlib_main_t * vm)
 {
   tap_main_t *tm = &tap_main;
@@ -644,6 +689,8 @@
   tm->log_default = vlib_log_register_class ("tap", 0);
   vlib_log_debug (tm->log_default, "initialized");
 
+  tm->host_mtu_size = 0;
+
   return error;
 }
 
diff --git a/src/vnet/devices/tap/tap.h b/src/vnet/devices/tap/tap.h
index 745f9fc..45ff1d9 100644
--- a/src/vnet/devices/tap/tap.h
+++ b/src/vnet/devices/tap/tap.h
@@ -43,6 +43,8 @@
   u8 host_ip6_prefix_len;
   ip6_address_t host_ip6_gw;
   u8 host_ip6_gw_set;
+  u8 host_mtu_set;
+  u32 host_mtu_size;
   /* return */
   u32 sw_if_index;
   int rv;
@@ -66,6 +68,7 @@
   u8 host_ip4_prefix_len;
   u8 host_ip6_addr[16];
   u8 host_ip6_prefix_len;
+  u32 host_mtu_size;
 } tap_interface_details_t;
 
 typedef struct
@@ -75,6 +78,9 @@
 
   /* bit-map of in-use IDs */
   uword *tap_ids;
+
+  /* host mtu size, configurable through startup.conf */
+  int host_mtu_size;
 } tap_main_t;
 
 void tap_create_if (vlib_main_t * vm, tap_create_if_args_t * args);
diff --git a/src/vnet/devices/tap/tapv2.api b/src/vnet/devices/tap/tapv2.api
index fb90483..2d4d5c3 100644
--- a/src/vnet/devices/tap/tapv2.api
+++ b/src/vnet/devices/tap/tapv2.api
@@ -19,7 +19,7 @@
     the Linux kernel TAP device driver
 */
 
-option version = "2.0.0";
+option version = "2.1.0";
 
 /** \brief Initialize a new tap interface with the given paramters
     @param client_index - opaque cookie to identify the sender
@@ -47,6 +47,8 @@
     @param host_ip4_gw - host IPv4 default gateway
     @param host_ip6_gw_set - host IPv6 default gateway should be set
     @param host_ip6_gw - host IPv6 default gateway
+    @param host_mtu_set - host MTU should be set
+    @param host_mtu_size - host MTU size
     @param tap_flags - flags for the TAP interface creation
 */
 define tap_create_v2
@@ -76,6 +78,8 @@
   u8 host_ip4_gw[4];
   u8 host_ip6_gw_set;
   u8 host_ip6_gw[16];
+  u8 host_mtu_set;
+  u32 host_mtu_size;
   u8 tag[64];
   u32 tap_flags;
 };
@@ -125,6 +129,7 @@
     @param host_ip4_prefix_len - host IPv4 ip address prefix length; 0 if unset
     @param host_ip6_addr - host IPv6 ip address
     @param host_ip6_prefix_len - host IPv6 ip address prefix length; 0 if unset
+    @param host_mtu_size - host mtu size
 */
 define sw_interface_tap_v2_details
 {
@@ -142,6 +147,7 @@
   u8 host_ip4_prefix_len;
   u8 host_ip6_addr[16];
   u8 host_ip6_prefix_len;
+  u32 host_mtu_size;
   u32 tap_flags;
 };
 
diff --git a/src/vnet/devices/tap/tapv2_api.c b/src/vnet/devices/tap/tapv2_api.c
index 40ff22e..2471d00 100644
--- a/src/vnet/devices/tap/tapv2_api.c
+++ b/src/vnet/devices/tap/tapv2_api.c
@@ -109,6 +109,12 @@
       ap->host_ip6_gw_set = 1;
     }
 
+  if (mp->host_mtu_set)
+    {
+      ap->host_mtu_size = ntohl (mp->host_mtu_size);
+      ap->host_mtu_set = 1;
+    }
+
   ap->tap_flags = ntohl (mp->tap_flags);
 
   tap_create_if (vm, ap);
@@ -190,6 +196,7 @@
   clib_memcpy (mp->host_bridge, tap_if->host_bridge,
 	       MIN (ARRAY_LEN (mp->host_bridge) - 1,
 		    strlen ((const char *) tap_if->host_bridge)));
+  mp->host_mtu_size = htonl (tap_if->host_mtu_size);
   if (tap_if->host_ip4_prefix_len)
     clib_memcpy (&mp->host_ip4_addr, &tap_if->host_ip4_addr, 4);
   mp->host_ip4_prefix_len = tap_if->host_ip4_prefix_len;
diff --git a/src/vnet/devices/virtio/virtio.c b/src/vnet/devices/virtio/virtio.c
index a3fd05d..9e2067b 100644
--- a/src/vnet/devices/virtio/virtio.c
+++ b/src/vnet/devices/virtio/virtio.c
@@ -317,6 +317,9 @@
 	    vlib_cli_output (vm, "  name \"%s\"", vif->host_if_name);
 	  if (vif->net_ns)
 	    vlib_cli_output (vm, "  host-ns \"%s\"", vif->net_ns);
+	  if (vif->host_mtu_size)
+	    vlib_cli_output (vm, "  host-mtu-size \"%d\"",
+			     vif->host_mtu_size);
 	  vlib_cli_output (vm, "  fd %d", vif->fd);
 	  vlib_cli_output (vm, "  tap-fd %d", vif->tap_fd);
 	  vlib_cli_output (vm, "  gso-enabled %d", vif->gso_enabled);
diff --git a/src/vnet/devices/virtio/virtio.h b/src/vnet/devices/virtio/virtio.h
index 55b6271..52b57e9 100644
--- a/src/vnet/devices/virtio/virtio.h
+++ b/src/vnet/devices/virtio/virtio.h
@@ -178,6 +178,7 @@
   u8 host_ip4_prefix_len;
   ip6_address_t host_ip6_addr;
   u8 host_ip6_prefix_len;
+  u32 host_mtu_size;
   u32 tap_file_index;
   int gso_enabled;
   int ifindex;