From 2df39094d20ae60d2e04316f4ec058f81778cf64 Mon Sep 17 00:00:00 2001 From: Damjan Marion Date: Mon, 4 Dec 2017 20:03:37 +0100 Subject: [PATCH] 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 --- src/vat/api_format.c | 49 ++++++----- src/vnet/devices/netlink.c | 137 +++++++++++++++++++----------- src/vnet/devices/netlink.h | 9 +- src/vnet/devices/tap/cli.c | 77 +++++++++-------- src/vnet/devices/tap/tap.c | 177 ++++++++++++++++++++++++++++++++------- src/vnet/devices/tap/tap.h | 14 +++- src/vnet/devices/tap/tapv2.api | 12 ++- src/vnet/devices/tap/tapv2_api.c | 15 +++- src/vnet/devices/virtio/device.c | 2 +- src/vnet/devices/virtio/virtio.h | 3 +- src/vnet/ethernet/ethernet.h | 6 ++ src/vpp/api/custom_dump.c | 10 ++- 12 files changed, 363 insertions(+), 148 deletions(-) diff --git a/src/vat/api_format.c b/src/vat/api_format.c index d39a61a813a..4b2602d0f3f 100644 --- a/src/vat/api_format.c +++ b/src/vat/api_format.c @@ -7810,8 +7810,11 @@ api_tap_create_v2 (vat_main_t * vam) 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 @@ api_tap_create_v2 (vat_main_t * vam) { random_mac = 0; } - else if (unformat (i, "name %s", &tap_name)) + else if (unformat (i, "id %s", &id)) + ; + else if (unformat (i, "host-if-name %s", &host_if_name)) ; - else if (unformat (i, "host-ns %s", &host_namespace)) + 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 @@ api_tap_create_v2 (vat_main_t * vam) 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 @@ api_tap_create_v2 (vat_main_t * vam) 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 @@ api_tap_create_v2 (vat_main_t * vam) 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 b3330dd89b9..5994366007c 100644 --- a/src/vnet/devices/netlink.c +++ b/src/vnet/devices/netlink.c @@ -19,36 +19,31 @@ #include #include #include -#include -#include -#include -#include -#include #include #include #include #include +#include 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 @@ vnet_netlink_msg_add_rtattr (vnet_netlink_msg_t * m, u16 rta_type, 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 @@ vnet_netlink_msg_send (vnet_netlink_msg_t * m) { 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 @@ vnet_netlink_msg_send (vnet_netlink_msg_t * m) 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; + ifmsg.ifi_index = ifindex; + vnet_netlink_msg_init (&m, RTM_SETLINK, NLM_F_REQUEST, + &ifmsg, sizeof (struct ifinfomsg)); - 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); - } + 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_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, type, &data, sizeof (int)); - err = vnet_netlink_msg_send (&m); + 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); - if (type == IFLA_NET_NS_FD) - close (data); - return err; + return vnet_netlink_msg_send (&m); } clib_error_t * -vnet_netlink_set_if_master (int ifindex, int master_ifindex) +vnet_netlink_set_link_master (int ifindex, char *master_ifname) { vnet_netlink_msg_t m; struct ifinfomsg ifmsg = { 0 }; + int i; - ifmsg.ifi_family = AF_UNSPEC; ifmsg.ifi_index = ifindex; - ifmsg.ifi_change = 0xffffffff; + + 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, &master_ifindex, - sizeof (int)); + vnet_netlink_msg_add_rtattr (&m, IFLA_MASTER, &i, sizeof (int)); return vnet_netlink_msg_send (&m); } clib_error_t * -vnet_netlink_set_if_mtu (int ifindex, int mtu) +vnet_netlink_set_link_addr (int ifindex, u8 * mac) { 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_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 e61b82753b7..e8501961a04 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 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 "); + 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 } [hw-addr ] " + .short_help = "create tap {id } [hw-addr ] " "[rx-ring-size ] [tx-ring-size ] [host-ns ] " "[host-bridge ] [host-ip4-addr ] " - "[host-ip6-addr ]", .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 #include #include @@ -24,6 +25,7 @@ #include #include #include +#include #include #include @@ -37,6 +39,8 @@ #include #include +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; diff --git a/src/vnet/devices/virtio/device.c b/src/vnet/devices/virtio/device.c index 275a3c74990..d4ef6d836c5 100644 --- a/src/vnet/devices/virtio/device.c +++ b/src/vnet/devices/virtio/device.c @@ -55,7 +55,7 @@ format_virtio_device_name (u8 * s, va_list * args) 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 7dcd90ac353..cb97df87121 100644 --- a/src/vnet/devices/virtio/virtio.h +++ b/src/vnet/devices/virtio/virtio.h @@ -91,6 +91,7 @@ typedef struct typedef struct { u32 flags; + u32 id; u32 dev_instance; u32 hw_if_index; u32 sw_if_index; @@ -102,7 +103,7 @@ typedef struct 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 2a3383a9eaa..9a97817262c 100644 --- a/src/vnet/ethernet/ethernet.h +++ b/src/vnet/ethernet/ethernet.h @@ -61,6 +61,12 @@ ethernet_mac_address_is_multicast_u64 (u64 a) 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 a4d587075b0..c26d65adbe0 100644 --- a/src/vpp/api/custom_dump.c +++ b/src/vpp/api/custom_dump.c @@ -556,9 +556,15 @@ static void *vl_api_tap_create_v2_t_print 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) -- 2.16.6