aboutsummaryrefslogtreecommitdiffstats
path: root/src/vnet/devices/af_packet
diff options
context:
space:
mode:
authorRay Kinsella <ray.kinsella@intel.com>2017-04-21 12:24:43 +0100
committerDamjan Marion <dmarion.lists@gmail.com>2017-04-28 08:01:12 +0000
commitc855b73f785b3c4c1756927ad542de13ba193b6f (patch)
tree282b4c2ee5b34f20bb9a71b130f20181c55179e5 /src/vnet/devices/af_packet
parentd77630adaf48f05766c33ec60ef19ed50acae161 (diff)
af_packet: reflect admin device state on host
Setting the interface state in VPP on an af_packet device, was not being reflected on the host. This implied the user had to set the device state in VPP and then on the host, in order to put the interface into an 'up' state. This changes makes the device state consisent in VPP and the host. Change-Id: I6dc6aee79503e04576683db937b861337a2b375b Signed-off-by: Ray Kinsella <ray.kinsella@intel.com>
Diffstat (limited to 'src/vnet/devices/af_packet')
-rw-r--r--src/vnet/devices/af_packet/af_packet.c50
-rw-r--r--src/vnet/devices/af_packet/af_packet.h1
-rw-r--r--src/vnet/devices/af_packet/device.c42
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 7464d4e6..92bd1092 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 77a2c7a3..194977f0 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 2ba3f579..2a17e6b3 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 *