diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/vnet/devices/af_packet/af_packet.c | 50 | ||||
-rw-r--r-- | src/vnet/devices/af_packet/af_packet.h | 1 | ||||
-rw-r--r-- | src/vnet/devices/af_packet/device.c | 42 |
3 files changed, 78 insertions, 15 deletions
diff --git a/src/vnet/devices/af_packet/af_packet.c b/src/vnet/devices/af_packet/af_packet.c index 7464d4e629d..92bd109296c 100644 --- a/src/vnet/devices/af_packet/af_packet.c +++ b/src/vnet/devices/af_packet/af_packet.c @@ -19,6 +19,7 @@ #include <linux/if_ether.h> #include <linux/if_packet.h> +#include <dirent.h> #include <vlib/vlib.h> #include <vlib/unix/unix.h> @@ -82,26 +83,35 @@ af_packet_fd_read_ready (unix_file_t * uf) } static int -create_packet_v2_sock (u8 * name, tpacket_req_t * rx_req, +is_bridge (const u8 * host_if_name) +{ + u8 *s; + DIR *dir = NULL; + + s = format (0, "/sys/class/net/%s/bridge%c", host_if_name, 0); + dir = opendir ((char *) s); + vec_free (s); + + if (dir) + { + closedir (dir); + return 0; + } + + return -1; +} + +static int +create_packet_v2_sock (int host_if_index, tpacket_req_t * rx_req, tpacket_req_t * tx_req, int *fd, u8 ** ring) { int ret, err; struct sockaddr_ll sll; - uint host_if_index; int ver = TPACKET_V2; socklen_t req_sz = sizeof (struct tpacket_req); u32 ring_sz = rx_req->tp_block_size * rx_req->tp_block_nr + tx_req->tp_block_size * tx_req->tp_block_nr; - host_if_index = if_nametoindex ((const char *) name); - - if (!host_if_index) - { - DBG_SOCK ("Wrong host interface name"); - ret = VNET_API_ERROR_INVALID_INTERFACE; - goto error; - } - if ((*fd = socket (AF_PACKET, SOCK_RAW, htons (ETH_P_ALL))) < 0) { DBG_SOCK ("Failed to create socket"); @@ -190,6 +200,7 @@ af_packet_create_if (vlib_main_t * vm, u8 * host_if_name, u8 * hw_addr_set, uword *p; uword if_index; u8 *host_if_name_dup = vec_dup (host_if_name); + int host_if_index = -1; p = mhash_get (&apm->if_index_by_host_if_name, host_if_name); if (p) @@ -209,15 +220,29 @@ af_packet_create_if (vlib_main_t * vm, u8 * host_if_name, u8 * hw_addr_set, tx_req->tp_block_nr = AF_PACKET_TX_BLOCK_NR; tx_req->tp_frame_nr = AF_PACKET_TX_FRAME_NR; - ret = create_packet_v2_sock (host_if_name, rx_req, tx_req, &fd, &ring); + host_if_index = if_nametoindex ((const char *) host_if_name); + + if (!host_if_index) + { + DBG_SOCK ("Wrong host interface name"); + return VNET_API_ERROR_INVALID_INTERFACE; + } + + ret = create_packet_v2_sock (host_if_index, rx_req, tx_req, &fd, &ring); if (ret != 0) goto error; + ret = is_bridge (host_if_name); + + if (ret == 0) /* is a bridge, ignore state */ + host_if_index = -1; + /* So far everything looks good, let's create interface */ pool_get (apm->interfaces, apif); if_index = apif - apm->interfaces; + apif->host_if_index = host_if_index; apif->fd = fd; apif->rx_ring = ring; apif->tx_ring = ring + rx_req->tp_block_size * rx_req->tp_block_nr; @@ -341,6 +366,7 @@ af_packet_delete_if (vlib_main_t * vm, u8 * host_if_name) vec_free (apif->host_if_name); apif->host_if_name = NULL; + apif->host_if_index = -1; mhash_unset (&apm->if_index_by_host_if_name, host_if_name, &if_index); diff --git a/src/vnet/devices/af_packet/af_packet.h b/src/vnet/devices/af_packet/af_packet.h index 77a2c7a3753..194977f03c1 100644 --- a/src/vnet/devices/af_packet/af_packet.h +++ b/src/vnet/devices/af_packet/af_packet.h @@ -24,6 +24,7 @@ typedef struct CLIB_CACHE_LINE_ALIGN_MARK (cacheline0); clib_spinlock_t lockp; u8 *host_if_name; + int host_if_index; int fd; struct tpacket_req *rx_req; struct tpacket_req *tx_req; diff --git a/src/vnet/devices/af_packet/device.c b/src/vnet/devices/af_packet/device.c index 2ba3f579c00..2a17e6b3456 100644 --- a/src/vnet/devices/af_packet/device.c +++ b/src/vnet/devices/af_packet/device.c @@ -18,6 +18,8 @@ */ #include <linux/if_packet.h> +#include <sys/ioctl.h> +#include <net/if.h> #include <vlib/vlib.h> #include <vlib/unix/unix.h> @@ -205,17 +207,51 @@ af_packet_interface_admin_up_down (vnet_main_t * vnm, u32 hw_if_index, af_packet_if_t *apif = pool_elt_at_index (apm->interfaces, hw->dev_instance); u32 hw_flags; + int rv, fd = socket (AF_UNIX, SOCK_DGRAM, 0); + struct ifreq ifr; + + /* if interface is a bridge ignore */ + if (apif->host_if_index < 0) + return 0; /* no error */ + + /* use host_if_index in case host name has changed */ + ifr.ifr_ifindex = apif->host_if_index; + if ((rv = ioctl (fd, SIOCGIFNAME, &ifr)) < 0) + { + clib_unix_warning ("af_packet_%s ioctl could not retrieve eth name", + apif->host_if_name); + } apif->is_admin_up = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) != 0; + if ((rv = ioctl (fd, SIOCGIFFLAGS, &ifr)) < 0) + { + clib_unix_warning ("af_packet_%s error: %d", + apif->is_admin_up ? "up" : "down", rv); + } + if (apif->is_admin_up) - hw_flags = VNET_HW_INTERFACE_FLAG_LINK_UP; + { + hw_flags = VNET_HW_INTERFACE_FLAG_LINK_UP; + ifr.ifr_flags |= IFF_UP; + } else - hw_flags = 0; + { + hw_flags = 0; + ifr.ifr_flags &= ~IFF_UP; + } + + if ((rv = ioctl (fd, SIOCSIFFLAGS, &ifr)) < 0) + { + clib_unix_warning ("af_packet_%s error: %d", + apif->is_admin_up ? "up" : "down", rv); + } vnet_hw_interface_set_flags (vnm, hw_if_index, hw_flags); - return 0; + close (fd); + + return 0; /* no error */ } static clib_error_t * |