diff options
author | Damjan Marion <damarion@cisco.com> | 2017-12-01 13:34:24 +0100 |
---|---|---|
committer | Damjan Marion <dmarion.lists@gmail.com> | 2017-12-02 10:11:25 +0000 |
commit | 91c6ef7cae2d20ca17a69003a44090614412c63f (patch) | |
tree | 28a0ae8030e840a0bc8f65e28f9d5bc2868bf39d /src | |
parent | 9fa1581cc40b656b6e00d77479fc2424cd50a126 (diff) |
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 <damarion@cisco.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/vat/api_format.c | 61 | ||||
-rw-r--r-- | src/vnet/api_errno.h | 6 | ||||
-rw-r--r-- | src/vnet/devices/netlink.c | 186 | ||||
-rw-r--r-- | src/vnet/devices/netlink.h | 5 | ||||
-rw-r--r-- | src/vnet/devices/virtio/cli.c | 48 | ||||
-rw-r--r-- | src/vnet/devices/virtio/tap.c | 120 | ||||
-rw-r--r-- | src/vnet/devices/virtio/tap.h | 11 | ||||
-rw-r--r-- | src/vnet/devices/virtio/tapv2.api | 24 | ||||
-rw-r--r-- | src/vnet/devices/virtio/tapv2_api.c | 25 | ||||
-rw-r--r-- | src/vpp/api/custom_dump.c | 12 |
10 files changed, 380 insertions, 118 deletions
diff --git a/src/vat/api_format.c b/src/vat/api_format.c index c9c62c76e2c..d39a61a813a 100644 --- a/src/vat/api_format.c +++ b/src/vat/api_format.c @@ -7810,10 +7810,13 @@ api_tap_create_v2 (vat_main_t * vam) vl_api_tap_create_v2_t *mp; u8 mac_address[6]; u8 random_mac = 1; - u8 name_set = 0; - u8 *tap_name; - u8 *net_ns = 0; - u8 net_ns_set = 0; + u8 *tap_name = 0; + u8 *host_namespace = 0; + u8 *host_bridge = 0; + ip4_address_t host_ip4_addr; + u32 host_ip4_prefix_len = 0; + ip6_address_t host_ip6_addr; + u32 host_ip6_prefix_len = 0; int ret; int rx_ring_sz = 0, tx_ring_sz = 0; @@ -7827,9 +7830,17 @@ api_tap_create_v2 (vat_main_t * vam) random_mac = 0; } else if (unformat (i, "name %s", &tap_name)) - name_set = 1; - else if (unformat (i, "host-ns %s", &net_ns)) - net_ns_set = 1; + ; + else if (unformat (i, "host-ns %s", &host_namespace)) + ; + else if (unformat (i, "host-bridge %s", &host_bridge)) + ; + else if (unformat (i, "host-ip4-addr %U/%d", unformat_ip4_address, + &host_ip4_addr, &host_ip4_prefix_len)) + ; + else if (unformat (i, "host-ip6-addr %U/%d", unformat_ip6_address, + &host_ip6_addr, &host_ip6_prefix_len)) + ; else if (unformat (i, "rx-ring-size %d", &rx_ring_sz)) ; else if (unformat (i, "tx-ring-size %d", &tx_ring_sz)) @@ -7838,7 +7849,7 @@ api_tap_create_v2 (vat_main_t * vam) break; } - if (name_set == 0) + if (tap_name == 0) { errmsg ("missing tap name. "); return -99; @@ -7848,11 +7859,26 @@ api_tap_create_v2 (vat_main_t * vam) errmsg ("tap name too long. "); return -99; } - if (vec_len (net_ns) > 63) + if (vec_len (host_namespace) > 63) { errmsg ("host name space too long. "); return -99; } + if (vec_len (host_bridge) > 63) + { + errmsg ("host bridge name too long. "); + return -99; + } + if (host_ip4_prefix_len > 32) + { + errmsg ("host ip4 prefix length not valid. "); + return -99; + } + if (host_ip6_prefix_len > 128) + { + errmsg ("host ip6 prefix length not valid. "); + return -99; + } if (!is_pow2 (rx_ring_sz)) { errmsg ("rx ring size must be power of 2. "); @@ -7882,11 +7908,22 @@ api_tap_create_v2 (vat_main_t * vam) 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->net_ns_set = net_ns_set; + mp->host_namespace_set = host_namespace != 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 (net_ns) - clib_memcpy (mp->net_ns, net_ns, vec_len (net_ns)); + if (host_namespace) + clib_memcpy (mp->host_namespace, host_namespace, + vec_len (host_namespace)); + if (host_bridge) + clib_memcpy (mp->host_bridge, host_bridge, vec_len (host_bridge)); + if (host_ip4_prefix_len) + clib_memcpy (mp->host_ip4_addr, &host_ip4_addr, 4); + if (host_ip4_prefix_len) + clib_memcpy (mp->host_ip6_addr, &host_ip6_addr, 16); + vec_free (tap_name); diff --git a/src/vnet/api_errno.h b/src/vnet/api_errno.h index 8c0cc0aba9b..11e5d4f03f1 100644 --- a/src/vnet/api_errno.h +++ b/src/vnet/api_errno.h @@ -132,9 +132,9 @@ _(NAME_SERVER_NO_ADDRESSES, -139, "No addresses available") \ _(NAME_SERVER_NEXT_SERVER, -140, "Retry with new server") \ _(APP_CONNECT_FILTERED, -141, "Connect was filtered") \ _(ACL_IN_USE_INBOUND, -142, "Inbound ACL in use") \ -_(ACL_IN_USE_OUTBOUND, -143, "Outbound ACL in use") \ -_(NAMESPACE_CREATE, -144, "Failed to create netlink namespace") \ -_(VIRTIO_INIT, -145, "Failed to init virtio ring") +_(ACL_IN_USE_OUTBOUND, -143, "Outbound ACL in use") \ +_(INIT_FAILED, -144, "Initialization Failed") \ +_(NETLINK_ERROR, -145, "netlink error") typedef enum { diff --git a/src/vnet/devices/netlink.c b/src/vnet/devices/netlink.c index b05daf2674a..b3330dd89b9 100644 --- a/src/vnet/devices/netlink.c +++ b/src/vnet/devices/netlink.c @@ -31,22 +31,51 @@ #include <vlib/vlib.h> #include <vlib/unix/unix.h> -clib_error_t * -vnet_netlink_set_if_attr (int ifindex, unsigned short rta_type, void *data, - int data_len) +typedef struct +{ + u8 *data; +} vnet_netlink_msg_t; + +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); + ASSERT (m->data == p); + + nh = (struct nlmsghdr *) p; + nh->nlmsg_flags = flags; + nh->nlmsg_type = type; + clib_memcpy (m->data + sizeof (struct nlmsghdr), msg_data, msg_len); +} + +static void +vnet_netlink_msg_add_rtattr (vnet_netlink_msg_t * m, u16 rta_type, + void *rta_data, int rta_data_len) +{ + struct rtattr *rta; + u8 *p; + + vec_add2 (m->data, p, RTA_LENGTH (rta_data_len)); + rta = (struct rtattr *) p; + rta->rta_type = rta_type; + rta->rta_len = RTA_LENGTH (rta_data_len); + clib_memcpy (RTA_DATA (rta), rta_data, rta_data_len); +} + +static clib_error_t * +vnet_netlink_msg_send (vnet_netlink_msg_t * m) { clib_error_t *err = 0; - int sock; struct sockaddr_nl ra = { 0 }; - struct - { - struct nlmsghdr nh; - struct ifinfomsg ifmsg; - char attrbuf[512]; - } req; - struct rtattr *rta; + int sock; + struct nlmsghdr *nh = (struct nlmsghdr *) m->data; + nh->nlmsg_len = vec_len (m->data); - memset (&req, 0, sizeof (req)); if ((sock = socket (AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) == -1) return clib_error_return_unix (0, "socket(AF_NETLINK)"); @@ -59,51 +88,126 @@ vnet_netlink_set_if_attr (int ifindex, unsigned short rta_type, void *data, goto error; } - req.nh.nlmsg_len = NLMSG_LENGTH (sizeof (struct ifinfomsg)); - req.nh.nlmsg_flags = NLM_F_REQUEST; - req.nh.nlmsg_type = RTM_SETLINK; - req.ifmsg.ifi_family = AF_UNSPEC; - req.ifmsg.ifi_index = ifindex; - req.ifmsg.ifi_change = 0xffffffff; - rta = (struct rtattr *) (((char *) &req) + NLMSG_ALIGN (req.nh.nlmsg_len)); - rta->rta_type = rta_type; - rta->rta_len = RTA_LENGTH (data_len); - req.nh.nlmsg_len = NLMSG_ALIGN (req.nh.nlmsg_len) + RTA_LENGTH (data_len); - memcpy (RTA_DATA (rta), data, data_len); - - if ((send (sock, &req, req.nh.nlmsg_len, 0)) == -1) + if ((send (sock, m->data, vec_len (m->data), 0)) == -1) err = clib_error_return_unix (0, "send"); error: close (sock); + vec_free (m->data); return err; } clib_error_t * -vnet_netlink_set_if_mtu (int ifindex, int mtu) +vnet_netlink_set_if_namespace (int ifindex, char *net_ns) { + 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); + } - err = vnet_netlink_set_if_attr (ifindex, IFLA_MTU, &mtu, sizeof (int)); + 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); + + if (type == IFLA_NET_NS_FD) + close (data); return err; } clib_error_t * -vnet_netlink_set_if_namespace (int ifindex, char *net_ns) +vnet_netlink_set_if_master (int ifindex, int master_ifindex) { - clib_error_t *err; - int ns_fd; - u8 *s; - s = format (0, "/var/run/netns/%s%c", net_ns, 0); - ns_fd = open ((char *) s, O_RDONLY); - vec_free (s); - if (ns_fd == -1) - return clib_error_return (0, "namespace '%s' doesn't exist", net_ns); - - err = - vnet_netlink_set_if_attr (ifindex, IFLA_NET_NS_FD, &ns_fd, sizeof (int)); - close (ns_fd); - return err; + 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_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_MTU, &mtu, sizeof (int)); + return vnet_netlink_msg_send (&m); +} + +clib_error_t * +vnet_netlink_add_ip4_addr (int ifindex, void *addr, int pfx_len) +{ + vnet_netlink_msg_t m; + struct ifaddrmsg ifa = { 0 }; + + ifa.ifa_family = AF_INET; + ifa.ifa_prefixlen = pfx_len; + ifa.ifa_index = ifindex; + + vnet_netlink_msg_init (&m, RTM_NEWADDR, + NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL, + &ifa, sizeof (struct ifaddrmsg)); + + vnet_netlink_msg_add_rtattr (&m, IFA_LOCAL, addr, 4); + vnet_netlink_msg_add_rtattr (&m, IFA_ADDRESS, addr, 4); + return vnet_netlink_msg_send (&m); +} + +clib_error_t * +vnet_netlink_add_ip6_addr (int ifindex, void *addr, int pfx_len) +{ + vnet_netlink_msg_t m; + struct ifaddrmsg ifa = { 0 }; + + ifa.ifa_family = AF_INET6; + ifa.ifa_prefixlen = pfx_len; + ifa.ifa_index = ifindex; + + vnet_netlink_msg_init (&m, RTM_NEWADDR, + NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL, + &ifa, sizeof (struct ifaddrmsg)); + + vnet_netlink_msg_add_rtattr (&m, IFA_LOCAL, addr, 16); + vnet_netlink_msg_add_rtattr (&m, IFA_ADDRESS, addr, 16); + return vnet_netlink_msg_send (&m); } /* diff --git a/src/vnet/devices/netlink.h b/src/vnet/devices/netlink.h index 3d5a3660949..e61b82753b7 100644 --- a/src/vnet/devices/netlink.h +++ b/src/vnet/devices/netlink.h @@ -18,6 +18,11 @@ 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_add_ip4_addr (int ifindex, void *addr, + int pfx_len); +clib_error_t *vnet_netlink_add_ip6_addr (int ifindex, void *addr, + int pfx_len); #endif /* included_vnet_device_netlink_h */ 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 <vlib/vlib.h> #include <vlib/unix/unix.h> #include <vnet/ethernet/ethernet.h> +#include <vnet/ip/ip4_packet.h> +#include <vnet/ip/ip6_packet.h> +#include <vnet/ip/format.h> #include <linux/virtio_net.h> #include <linux/vhost.h> #include <vnet/devices/virtio/virtio.h> @@ -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 <if-name>} [hw-addr <mac-address>]" - "[rx-ring-size <size>] [tx-ring-size <size>] [host-ns <netns>]", + .short_help = "create tap {name <if-name>} [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]", .function = tap_create_command_fn, }; /* *INDENT-ON* */ diff --git a/src/vnet/devices/virtio/tap.c b/src/vnet/devices/virtio/tap.c index 34339c95737..cc28df3be7f 100644 --- a/src/vnet/devices/virtio/tap.c +++ b/src/vnet/devices/virtio/tap.c @@ -31,6 +31,8 @@ #include <vlib/vlib.h> #include <vlib/unix/unix.h> #include <vnet/ethernet/ethernet.h> +#include <vnet/ip/ip4_packet.h> +#include <vnet/ip/ip6_packet.h> #include <vnet/devices/netlink.h> #include <vnet/devices/virtio/virtio.h> #include <vnet/devices/virtio/tap.h> @@ -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); diff --git a/src/vpp/api/custom_dump.c b/src/vpp/api/custom_dump.c index 428e1636569..a4d587075b0 100644 --- a/src/vpp/api/custom_dump.c +++ b/src/vpp/api/custom_dump.c @@ -559,8 +559,16 @@ static void *vl_api_tap_create_v2_t_print s = format (s, "name %s ", mp->tap_name); if (memcmp (mp->mac_address, null_mac, 6)) s = format (s, "hw-addr %U ", format_ethernet_address, mp->mac_address); - if (mp->net_ns_set) - s = format (s, "host-ns %s ", mp->net_ns); + if (mp->host_namespace_set) + s = format (s, "host-ns %s ", mp->host_namespace); + if (mp->host_bridge_set) + s = format (s, "host-bridge %s ", mp->host_bridge); + if (mp->host_ip4_addr_set) + s = format (s, "host-ip4-addr %U/%d ", format_ip4_address, + mp->host_ip4_addr, mp->host_ip4_prefix_len); + if (mp->host_ip6_addr_set) + s = format (s, "host-ip6-addr %U/%d ", format_ip6_address, + mp->host_ip6_addr, mp->host_ip6_prefix_len); if (mp->tx_ring_sz) s = format (s, "tx-ring-size %d ", mp->tx_ring_sz); if (mp->rx_ring_sz) |