From 91c6ef7cae2d20ca17a69003a44090614412c63f Mon Sep 17 00:00:00 2001 From: Damjan Marion Date: Fri, 1 Dec 2017 13:34:24 +0100 Subject: tap_v2: multiple improvements - add support for assigning tap interface to the bridge - add support for assigning tap interface host side ip4 and ip6 address - host namespace can be specified as PID (pid:12345) or full path to file - automatically bring linux interface up Change-Id: I1cf7c3cad9a740e430cc1b9c2bb0aad0ba4cc8d8 Signed-off-by: Damjan Marion --- src/vnet/devices/virtio/cli.c | 48 ++++++++------- src/vnet/devices/virtio/tap.c | 120 +++++++++++++++++++++++++++--------- src/vnet/devices/virtio/tap.h | 11 +++- src/vnet/devices/virtio/tapv2.api | 24 ++++++-- src/vnet/devices/virtio/tapv2_api.c | 25 ++++++-- 5 files changed, 168 insertions(+), 60 deletions(-) (limited to 'src/vnet/devices/virtio') diff --git a/src/vnet/devices/virtio/cli.c b/src/vnet/devices/virtio/cli.c index 0c1b75f8c4e..efd14355627 100644 --- a/src/vnet/devices/virtio/cli.c +++ b/src/vnet/devices/virtio/cli.c @@ -22,6 +22,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -32,8 +35,8 @@ tap_create_command_fn (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) { unformat_input_t _line_input, *line_input = &_line_input; - int rv; 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)) @@ -43,8 +46,18 @@ tap_create_command_fn (vlib_main_t * vm, unformat_input_t * input, { if (unformat (line_input, "name %s", &args.name)) ; - else if (unformat (line_input, "host-ns %s", &args.net_ns)) + 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)) @@ -58,34 +71,27 @@ tap_create_command_fn (vlib_main_t * vm, unformat_input_t * input, } unformat_free (line_input); - rv = tap_create_if (vm, &args); + if (ip_addr_set && args.host_bridge) + return clib_error_return (0, "Please specify either host ip address or " + "host bridge"); + + tap_create_if (vm, &args); vec_free (args.name); + vec_free (args.host_namespace); + vec_free (args.host_bridge); - if (rv == VNET_API_ERROR_SYSCALL_ERROR_1) - return clib_error_return_unix (0, "open '/dev/vhost-net'"); - else if (rv == VNET_API_ERROR_SYSCALL_ERROR_2) - return clib_error_return_unix (0, "open '/dev/net/tun'"); - else if (rv == VNET_API_ERROR_UNSUPPORTED) - return clib_error_return (0, "vhost-net backend doesn't support needed" - " features"); - else if (rv == VNET_API_ERROR_NAMESPACE_CREATE) - return clib_error_return (0, "failed to create netlink namespace"); - else if (rv == VNET_API_ERROR_VIRTIO_INIT) - return clib_error_return (0, "failed to init virtio ring"); - else if (rv == VNET_API_ERROR_INVALID_REGISTRATION) - return clib_error_return (0, "failed to register interface"); - else if (rv != 0) - return clib_error_return (0, "error on creating tap interface"); + return args.error; - return 0; } /* *INDENT-OFF* */ VLIB_CLI_COMMAND (tap_create_command, static) = { .path = "create tap", - .short_help = "create tap {name } [hw-addr ]" - "[rx-ring-size ] [tx-ring-size ] [host-ns ]", + .short_help = "create tap {name } [hw-addr ] " + "[rx-ring-size ] [tx-ring-size ] [host-ns ] " + "[host-bridge ] [host-ip4-addr ] " + "[host-ip6-addr #include #include +#include +#include #include #include #include @@ -47,23 +49,23 @@ virtio_eth_flag_change (vnet_main_t * vnm, vnet_hw_interface_t * hi, u32 flags) { /* nothing for now */ + //TODO On MTU change call vnet_netlink_set_if_mtu return 0; } -int +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; vnet_sw_interface_t *sw; vnet_hw_interface_t *hw; - int i; - clib_error_t *err = 0; + int i, fd; struct ifreq ifr; size_t hdrsz; struct vhost_memory *vhost_mem = 0; virtio_if_t *vif = 0; - int rv = 0; + clib_error_t *err = 0; memset (&ifr, 0, sizeof (ifr)); pool_get (vim->interfaces, vif); @@ -72,7 +74,8 @@ tap_create_if (vlib_main_t * vm, tap_create_if_args_t * args) if ((vif->fd = open ("/dev/vhost-net", O_RDWR | O_NONBLOCK)) < 0) { - rv = VNET_API_ERROR_SYSCALL_ERROR_1; + args->rv = VNET_API_ERROR_SYSCALL_ERROR_1; + args->error = clib_error_return_unix (0, "open '/dev/vhost-net'"); goto error; } @@ -80,19 +83,25 @@ tap_create_if (vlib_main_t * vm, tap_create_if_args_t * args) if ((vif->remote_features & (1ULL << VIRTIO_NET_F_MRG_RXBUF)) == 0) { - rv = VNET_API_ERROR_UNSUPPORTED; + args->rv = VNET_API_ERROR_UNSUPPORTED; + args->error = clib_error_return (0, "vhost-net backend doesn't support " + "VIRTIO_NET_F_MRG_RXBUF feature"); goto error; } if ((vif->remote_features & (1ULL << VIRTIO_RING_F_INDIRECT_DESC)) == 0) { - rv = VNET_API_ERROR_UNSUPPORTED; + args->rv = VNET_API_ERROR_UNSUPPORTED; + args->error = clib_error_return (0, "vhost-net backend doesn't support " + "VIRTIO_RING_F_INDIRECT_DESC feature"); goto error; } if ((vif->remote_features & (1ULL << VIRTIO_F_VERSION_1)) == 0) { - rv = VNET_API_ERROR_UNSUPPORTED; + args->rv = VNET_API_ERROR_UNSUPPORTED; + args->error = clib_error_return (0, "vhost-net backend doesn't support " + "VIRTIO_F_VERSION_1 features"); goto error; } @@ -104,7 +113,8 @@ tap_create_if (vlib_main_t * vm, tap_create_if_args_t * args) if ((vif->tap_fd = open ("/dev/net/tun", O_RDWR | O_NONBLOCK)) < 0) { - rv = VNET_API_ERROR_SYSCALL_ERROR_2; + args->rv = VNET_API_ERROR_SYSCALL_ERROR_2; + args->error = clib_error_return_unix (0, "open '/dev/net/tun'"); goto error; } @@ -120,13 +130,49 @@ tap_create_if (vlib_main_t * vm, tap_create_if_args_t * args) _IOCTL (vif->tap_fd, TUNSETVNETHDRSZ, &hdrsz); _IOCTL (vif->fd, VHOST_SET_OWNER, 0); - if (args->net_ns) + if (args->host_bridge) { - err = vnet_netlink_set_if_namespace (vif->ifindex, - (char *) args->net_ns); - if (err) + int master_ifindex = if_nametoindex ((char *) args->host_bridge); + args->error = vnet_netlink_set_if_master (vif->ifindex, master_ifindex); + if (args->error) { - rv = VNET_API_ERROR_NAMESPACE_CREATE; + args->rv = VNET_API_ERROR_NETLINK_ERROR; + goto error; + } + } + + if (args->host_namespace) + { + args->error = vnet_netlink_set_if_namespace (vif->ifindex, + (char *) + args->host_namespace); + if (args->error) + { + args->rv = VNET_API_ERROR_NETLINK_ERROR; + goto error; + } + } + + if (args->host_ip4_prefix_len) + { + args->error = vnet_netlink_add_ip4_addr (vif->ifindex, + &args->host_ip4_addr, + args->host_ip4_prefix_len); + if (args->error) + { + args->rv = VNET_API_ERROR_NETLINK_ERROR; + goto error; + } + } + + if (args->host_ip6_prefix_len) + { + args->error = vnet_netlink_add_ip6_addr (vif->ifindex, + &args->host_ip6_addr, + args->host_ip6_prefix_len); + if (args->error) + { + args->rv = VNET_API_ERROR_NETLINK_ERROR; goto error; } } @@ -139,18 +185,29 @@ tap_create_if (vlib_main_t * vm, tap_create_if_args_t * args) vhost_mem->regions[0].memory_size = (1ULL << 47) - 4096; _IOCTL (vif->fd, VHOST_SET_MEM_TABLE, vhost_mem); - if ((err = virtio_vring_init (vm, vif, 0, args->rx_ring_sz))) + if ((args->error = virtio_vring_init (vm, vif, 0, args->rx_ring_sz))) { - rv = VNET_API_ERROR_VIRTIO_INIT; + args->rv = VNET_API_ERROR_INIT_FAILED; goto error; } - if ((err = virtio_vring_init (vm, vif, 1, args->tx_ring_sz))) + if ((args->error = virtio_vring_init (vm, vif, 1, args->tx_ring_sz))) { - rv = VNET_API_ERROR_VIRTIO_INIT; + args->rv = VNET_API_ERROR_INIT_FAILED; 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); + close (fd); + } + if (!args->hw_addr_set) { f64 now = vlib_time_now (vm); @@ -164,14 +221,17 @@ tap_create_if (vlib_main_t * vm, tap_create_if_args_t * args) } vif->name = args->name; args->name = 0; - vif->net_ns = args->net_ns; - args->net_ns = 0; - err = ethernet_register_interface (vnm, virtio_device_class.index, - vif->dev_instance, args->hw_addr, - &vif->hw_if_index, - virtio_eth_flag_change); - if (err) - rv = VNET_API_ERROR_INVALID_REGISTRATION; + 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->hw_if_index, + virtio_eth_flag_change); + if (args->error) + { + args->rv = VNET_API_ERROR_INVALID_REGISTRATION; + goto error; + } sw = vnet_get_hw_sw_interface (vnm, vif->hw_if_index); vif->sw_if_index = sw->sw_if_index; @@ -191,6 +251,12 @@ tap_create_if (vlib_main_t * vm, tap_create_if_args_t * args) goto done; error: + if (err) + { + ASSERT (args->error == 0); + args->error = err; + args->rv = VNET_API_ERROR_SYSCALL_ERROR_3; + } if (vif->tap_fd != -1) close (vif->tap_fd); if (vif->fd != -1) @@ -202,8 +268,6 @@ error: done: if (vhost_mem) clib_mem_free (vhost_mem); - - return rv; } int diff --git a/src/vnet/devices/virtio/tap.h b/src/vnet/devices/virtio/tap.h index 58dcb5bda51..0e0f8cb4056 100644 --- a/src/vnet/devices/virtio/tap.h +++ b/src/vnet/devices/virtio/tap.h @@ -25,13 +25,20 @@ typedef struct { u8 *name; - u8 *net_ns; u8 hw_addr_set; u8 hw_addr[6]; u16 rx_ring_sz; u16 tx_ring_sz; + u8 *host_namespace; + u8 *host_bridge; + ip4_address_t host_ip4_addr; + u32 host_ip4_prefix_len; + ip6_address_t host_ip6_addr; + u32 host_ip6_prefix_len; /* return */ u32 sw_if_index; + int rv; + clib_error_t *error; } tap_create_if_args_t; /** TAP interface details struct */ @@ -41,7 +48,7 @@ typedef struct u8 dev_name[64]; } tap_interface_details_t; -int tap_create_if (vlib_main_t * vm, tap_create_if_args_t * args); +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/virtio/tapv2.api b/src/vnet/devices/virtio/tapv2.api index e1592cf7d61..03788607fe5 100644 --- a/src/vnet/devices/virtio/tapv2.api +++ b/src/vnet/devices/virtio/tapv2.api @@ -27,10 +27,18 @@ vl_api_version 1.0.0 @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 net_ns_set - net_ns is entered - @param net_ns - netlink name space @param tx_ring_sz - the number of entries of TX ring @param rx_ring_sz - the number of entries of RX ring + @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 + @param host_bridge - host bridge to attach interface to + @param host_ip4_addr_set - host IPv4 ip address should be set + @param host_ip4_addr - host IPv4 ip address + @param host_ip4_prefix_len - host IPv4 ip address prefix length + @param host_ip6_addr_set - host IPv6 ip address should be set + @param host_ip6_addr - host IPv6 ip address + @param host_ip6_prefix_len - host IPv6 ip address prefix length */ define tap_create_v2 { @@ -39,10 +47,18 @@ define tap_create_v2 u8 use_random_mac; u8 tap_name[64]; u8 mac_address[6]; - u8 net_ns_set; - u8 net_ns[64]; 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_bridge_set; + u8 host_bridge[64]; + u8 host_ip4_addr_set; + u8 host_ip4_addr[4]; + u8 host_ip4_prefix_len; + u8 host_ip6_addr_set; + u8 host_ip6_addr[16]; + u8 host_ip6_prefix_len; }; /** \brief Reply for tap create reply diff --git a/src/vnet/devices/virtio/tapv2_api.c b/src/vnet/devices/virtio/tapv2_api.c index 1c559e6c28e..7a6adca083f 100644 --- a/src/vnet/devices/virtio/tapv2_api.c +++ b/src/vnet/devices/virtio/tapv2_api.c @@ -53,7 +53,6 @@ static void vl_api_tap_create_v2_t_handler (vl_api_tap_create_v2_t * mp) { vlib_main_t *vm = vlib_get_main (); - int rv; vl_api_tap_create_v2_reply_t *rmp; unix_shared_memory_queue_t *q; tap_create_if_args_t _a, *ap = &_a; @@ -69,10 +68,26 @@ vl_api_tap_create_v2_t_handler (vl_api_tap_create_v2_t * mp) ap->rx_ring_sz = mp->rx_ring_sz; ap->tx_ring_sz = mp->tx_ring_sz; ap->sw_if_index = (u32) ~ 0; - if (mp->net_ns_set) - ap->net_ns = mp->net_ns; - rv = tap_create_if (vm, ap); + if (mp->host_namespace_set) + ap->host_namespace = mp->host_namespace; + + if (mp->host_bridge_set) + ap->host_bridge = mp->host_bridge; + + if (mp->host_ip4_addr_set) + { + clib_memcpy (&ap->host_ip4_addr.as_u8, mp->host_ip4_addr, 4); + ap->host_ip4_prefix_len = mp->host_ip4_prefix_len; + } + + if (mp->host_ip6_addr_set) + { + clib_memcpy (&ap->host_ip6_addr, mp->host_ip6_addr, 16); + ap->host_ip6_prefix_len = mp->host_ip6_prefix_len; + } + + tap_create_if (vm, ap); q = vl_api_client_index_to_input_queue (mp->client_index); if (!q) @@ -81,7 +96,7 @@ vl_api_tap_create_v2_t_handler (vl_api_tap_create_v2_t * mp) rmp = vl_msg_api_alloc (sizeof (*rmp)); rmp->_vl_msg_id = ntohs (VL_API_TAP_CREATE_V2_REPLY); rmp->context = mp->context; - rmp->retval = ntohl (rv); + rmp->retval = ntohl (ap->rv); rmp->sw_if_index = ntohl (ap->sw_if_index); vl_msg_api_send_shmem (q, (u8 *) & rmp); -- cgit 1.2.3-korg