From 8dbbeaa2a927b5a0faca32e9bbc4236746adbb60 Mon Sep 17 00:00:00 2001 From: Giuseppe Lettieri Date: Wed, 26 Sep 2012 19:09:04 +0200 Subject: [PATCH] add/skip packet information on tap send/recv Unless the IFF_NO_PI flag is set when the tap is created, the kernel assumes that each packet sent to or received from a tap fd starts with 4 bytes of packet information. We previously did not care about this 4 extra bytes, but external controllers are confused by them (the internal ovs-switch logic was confused as well, but it defaulted to hub behaviour and the bug was thus hidden). Unfortunately, fd_tuntap does not allow us to set IFF_NO_IP, so we have to manually skip/add the 4 bytes on recv/send. --- lib/netdev-pltap.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/lib/netdev-pltap.c b/lib/netdev-pltap.c index 4e010cf53..c9252e50e 100644 --- a/lib/netdev-pltap.c +++ b/lib/netdev-pltap.c @@ -338,13 +338,16 @@ netdev_pltap_recv(struct netdev *netdev_, void *buffer, size_t size) { struct netdev_dev_pltap *dev = netdev_dev_pltap_cast(netdev_get_dev(netdev_)); + char prefix[4]; + struct iovec iov[2] = { + { .iov_base = prefix, .iov_len = 4 }, + { .iov_base = buffer, .iov_len = size } + }; if (!dev->finalized) return -EAGAIN; for (;;) { ssize_t retval; - retval = read(dev->fd, buffer, size); - VLOG_DBG("%s: read(%"PRIxPTR", %"PRIu64") = %"PRId64, - netdev_get_name(netdev_), (uintptr_t)buffer, size, retval); + retval = readv(dev->fd, iov, 2); if (retval >= 0) { if (retval <= size) { return retval; @@ -376,17 +379,20 @@ netdev_pltap_send(struct netdev *netdev_, const void *buffer, size_t size) { struct netdev_dev_pltap *dev = netdev_dev_pltap_cast(netdev_get_dev(netdev_)); + char prefix[4] = { 0, 0, 8, 6 }; + struct iovec iov[2] = { + { .iov_base = prefix, .iov_len = 4 }, + { .iov_base = buffer, .iov_len = size } + }; if (dev->fd < 0 || !dev->finalized) return EAGAIN; for (;;) { ssize_t retval; - retval = write(dev->fd, buffer, size); - VLOG_DBG("%s: write(%"PRIxPTR", %"PRIu64") = %"PRId64, - netdev_get_name(netdev_), (uintptr_t)buffer, size, retval); + retval = writev(dev->fd, iov, 2); if (retval >= 0) { - if (retval != size) { - VLOG_WARN_RL(&rl, "sent partial Ethernet packet (%"PRId64" bytes of " - "%"PRIu64") on %s", retval, size, netdev_get_name(netdev_)); + if (retval != size + 4) { + VLOG_WARN_RL(&rl, "sent partial Ethernet packet (%zd bytes of %zu) on %s", + retval, size + 4, netdev_get_name(netdev_)); } return 0; } else if (errno != EINTR) { -- 2.43.0