diff options
Diffstat (limited to 'src/vnet/devices/tap')
-rw-r--r-- | src/vnet/devices/tap/cli.c | 77 | ||||
-rw-r--r-- | src/vnet/devices/tap/tap.c | 177 | ||||
-rw-r--r-- | src/vnet/devices/tap/tap.h | 14 | ||||
-rw-r--r-- | src/vnet/devices/tap/tapv2.api | 12 | ||||
-rw-r--r-- | src/vnet/devices/tap/tapv2_api.c | 15 |
5 files changed, 225 insertions, 70 deletions
diff --git a/src/vnet/devices/tap/cli.c b/src/vnet/devices/tap/cli.c index f7fc1e63be7..c86995ce5cc 100644 --- a/src/vnet/devices/tap/cli.c +++ b/src/vnet/devices/tap/cli.c @@ -38,38 +38,47 @@ tap_create_command_fn (vlib_main_t * vm, unformat_input_t * input, 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_command_fn (vlib_main_t * vm, unformat_input_t * input, 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 @@ tap_create_command_fn (vlib_main_t * vm, unformat_input_t * input, /* *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 @@ tap_show_command_fn (vlib_main_t * vm, unformat_input_t * input, 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 b4004f70189..f31548cbbec 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 @@ virtio_eth_flag_change (vnet_main_t * vnm, vnet_hw_interface_t * hi, 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 @@ tap_create_if (vlib_main_t * vm, tap_create_if_args_t * args) } 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,22 +187,61 @@ 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->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 (args->host_namespace) + if (!ethernet_mac_address_is_zero (args->host_mac_addr)) { - args->error = vnet_netlink_set_if_namespace (vif->ifindex, - (char *) - args->host_namespace); + args->error = vnet_netlink_set_link_addr (vif->ifindex, + args->host_mac_addr); if (args->error) { args->rv = VNET_API_ERROR_NETLINK_ERROR; @@ -153,6 +249,18 @@ tap_create_if (vlib_main_t * vm, tap_create_if_args_t * args) } } + if (args->host_bridge) + { + args->error = vnet_netlink_set_link_master (vif->ifindex, + (char *) args->host_bridge); + 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, @@ -177,6 +285,25 @@ tap_create_if (vlib_main_t * vm, tap_create_if_args_t * args) } } + 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 @@ tap_create_if (vlib_main_t * vm, tap_create_if_args_t * args) 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 @@ tap_delete_if (vlib_main_t * vm, u32 sw_if_index) { 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 @@ tap_delete_if (vlib_main_t * vm, u32 sw_if_index) 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 @@ tap_dump_ifs (tap_interface_details_t ** out_tapids) 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 0e0f8cb4056..7d07ffb4e82 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 @@ typedef struct 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 03788607fe5..a2062696709 100644 --- a/src/vnet/devices/tap/tapv2.api +++ b/src/vnet/devices/tap/tapv2.api @@ -24,11 +24,15 @@ vl_api_version 1.0.0 /** \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 @@ define tap_create_v2 { 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 2b324d6b545..3cededbfe82 100644 --- a/src/vnet/devices/tap/tapv2_api.c +++ b/src/vnet/devices/tap/tapv2_api.c @@ -59,16 +59,25 @@ vl_api_tap_create_v2_t_handler (vl_api_tap_create_v2_t * mp) 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; |