this could also be used for 802.1AD right?
On Tue, Jan 7, 2014 at 7:33 AM, Simon Horman <ho...@verge.net.au> wrote: > If VLAN acceleration is used when the kernel receives a packet > then the outer-most VLAN tag will not be present in the packet > when it is received by netdev-linux. Rather, it will be present > in auxdata. > > This patch uses recvmsg() instead of recv() to read auxdata for > each packet and if the vlan_tid is set then it is added to the packet. > > Adding the vlan_tid makes use of headroom available > in the buffer parameter of rx_recv. > > Signed-off-by: Simon Horman <ho...@verge.net.au> > > -- > v4 > * Rebase > * Make aux variable in netdev_linux_rx_recv_sock() const > * Use TP_STATUS_VLAN_VALID to allow vlan 0 to be read from auxdata > * Use TP_STATUS_VLAN_TPID_VALID allow the VLAN tpid to be read > from auxdata > > v3 > * Remove unnecessary cast > * On success return 0 and increment buffer->size > * Limit to reading one VLAN from auxdata > > v2 > * Updated to use eth_push_vlan() to efficiently push the VLAN > if headroom is available. This is possible now there > is a struct ofpbuf * to work with. > * Various cleanups > --- > include/sparse/sys/socket.h | 1 + > lib/netdev-linux.c | 152 > +++++++++++++++++++++++++++++++++++++++----- > 2 files changed, 136 insertions(+), 17 deletions(-) > > diff --git a/include/sparse/sys/socket.h b/include/sparse/sys/socket.h > index 75ee43c..3212bf4 100644 > --- a/include/sparse/sys/socket.h > +++ b/include/sparse/sys/socket.h > @@ -87,6 +87,7 @@ enum { > }; > > enum { > + SOL_PACKET, > SOL_SOCKET > }; > > diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c > index 106c18a..444369e 100644 > --- a/lib/netdev-linux.c > +++ b/lib/netdev-linux.c > @@ -20,11 +20,11 @@ > > #include <errno.h> > #include <fcntl.h> > -#include <arpa/inet.h> > #include <inttypes.h> > #include <linux/filter.h> > #include <linux/gen_stats.h> > #include <linux/if_ether.h> > +#include <linux/if_packet.h> > #include <linux/if_tun.h> > #include <linux/types.h> > #include <linux/ethtool.h> > @@ -37,10 +37,8 @@ > #include <sys/types.h> > #include <sys/ioctl.h> > #include <sys/socket.h> > -#include <netpacket/packet.h> > #include <net/if.h> > #include <net/if_arp.h> > -#include <net/if_packet.h> > #include <net/route.h> > #include <netinet/in.h> > #include <poll.h> > @@ -763,7 +761,7 @@ netdev_linux_rx_construct(struct netdev_rx *rx_) > rx->fd = netdev->tap_fd; > } else { > struct sockaddr_ll sll; > - int ifindex; > + int ifindex, val; > /* Result of tcpdump -dd inbound */ > static const struct sock_filter filt[] = { > { 0x28, 0, 0, 0xfffff004 }, /* ldh [0] */ > @@ -783,6 +781,16 @@ netdev_linux_rx_construct(struct netdev_rx *rx_) > goto error; > } > > + val = 1; > + error = setsockopt(rx->fd, SOL_PACKET, PACKET_AUXDATA, > + &val, sizeof val); > + if (error) { > + error = errno; > + VLOG_ERR("%s: failed to mark socket for auxdata (%s)", > + netdev_get_name(netdev_), ovs_strerror(error)); > + goto error; > + } > + > /* Set non-blocking mode. */ > error = set_nonblocking(rx->fd); > if (error) { > @@ -799,7 +807,7 @@ netdev_linux_rx_construct(struct netdev_rx *rx_) > memset(&sll, 0, sizeof sll); > sll.sll_family = AF_PACKET; > sll.sll_ifindex = ifindex; > - sll.sll_protocol = (OVS_FORCE unsigned short int) > htons(ETH_P_ALL); > + sll.sll_protocol = htons(ETH_P_ALL); > if (bind(rx->fd, (struct sockaddr *) &sll, sizeof sll) < 0) { > error = errno; > VLOG_ERR("%s: failed to bind raw socket (%s)", > @@ -847,31 +855,141 @@ netdev_linux_rx_dealloc(struct netdev_rx *rx_) > free(rx); > } > > +#ifdef TP_STATUS_VLAN_TPID_VALID > +static ovs_be16 > +auxdata_to_vlan_tpid(const struct tpacket_auxdata *aux) > +{ > + if (aux->tp_status & TP_STATUS_VLAN_TPID_VALID) { > + return htons(aux->tp_vlan_tpid); > + } else { > + return htons(ETH_TYPE_VLAN); > + } > +} > +#else > +static ovs_be16 > +auxdata_to_vlan_tpid(const struct tpacket_auxdata *aux OVS_UNUSED) > +{ > + return htons(ETH_TYPE_VLAN); > +} > +#endif > + > +/* TP_STATUS_VLAN_VALID was added to v3.0 of the linux kernel > + * to allow VLAN 0 to be accessed via auxdata. Use it if it > + * is available */ > +#ifdef TP_STATUS_VLAN_VALID > +static bool > +auxdata_has_vlan_tci(const struct tpacket_auxdata *aux) > +{ > + return aux->tp_vlan_tci || (aux->tp_status & TP_STATUS_VLAN_VALID); > +} > +#else > +static bool > +auxdata_has_vlan_tci(const struct tpacket_auxdata *aux) > +{ > + return aux->tp_vlan_tci; > +} > +#endif > + > static int > -netdev_linux_rx_recv(struct netdev_rx *rx_, struct ofpbuf *buffer) > +netdev_linux_rx_recv_sock(int fd, struct ofpbuf *buffer) > { > - struct netdev_rx_linux *rx = netdev_rx_linux_cast(rx_); > + size_t size; > ssize_t retval; > - size_t size = ofpbuf_tailroom(buffer); > + struct iovec iov; > + struct cmsghdr *cmsg; > + union { > + struct cmsghdr cmsg; > + char buffer[CMSG_SPACE(sizeof(struct tpacket_auxdata))]; > + } cmsg_buffer; > + struct msghdr msgh; > + > + /* Reserve headroom for a single VLAN tag */ > + ofpbuf_reserve(buffer, VLAN_HEADER_LEN); > + size = ofpbuf_tailroom(buffer); > + > + iov.iov_base = buffer->data; > + iov.iov_len = size; > + msgh.msg_name = NULL; > + msgh.msg_namelen = 0; > + msgh.msg_iov = &iov; > + msgh.msg_iovlen = 1; > + msgh.msg_control = &cmsg_buffer; > + msgh.msg_controllen = sizeof cmsg_buffer; > + msgh.msg_flags = 0; > > do { > - retval = (rx->is_tap > - ? read(rx->fd, buffer->data, size) > - : recv(rx->fd, buffer->data, size, MSG_TRUNC)); > + retval = recvmsg(fd, &msgh, MSG_TRUNC); > } while (retval < 0 && errno == EINTR); > > if (retval < 0) { > - if (errno != EAGAIN) { > - VLOG_WARN_RL(&rl, "error receiving Ethernet packet on %s: %s", > - ovs_strerror(errno), netdev_rx_get_name(rx_)); > + return errno; > + } else if (retval > size) { > + return EMSGSIZE; > + } > + > + buffer->size += retval; > + > + for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg; cmsg = CMSG_NXTHDR(&msgh, > cmsg)) { > + const struct tpacket_auxdata *aux; > + > + if (cmsg->cmsg_level != SOL_PACKET > + || cmsg->cmsg_type != PACKET_AUXDATA > + || cmsg->cmsg_len < CMSG_LEN(sizeof(struct tpacket_auxdata))) > { > + continue; > } > + > + aux = (struct tpacket_auxdata *)(void *)CMSG_DATA(cmsg); > + if (auxdata_has_vlan_tci(aux)) { > + if (retval < ETH_ADDR_LEN) { > + return EINVAL; > + } > + > + eth_push_vlan(buffer, auxdata_to_vlan_tpid(aux), > + htons(aux->tp_vlan_tci)); > + break; > + } > + } > + > + return 0; > +} > + > +static int > +netdev_linux_rx_recv_tap(int fd, struct ofpbuf *buffer) > +{ > + ssize_t retval; > + size_t size = ofpbuf_tailroom(buffer); > + > + do { > + retval = read(fd, buffer->data, size); > + } while (retval < 0 && errno == EINTR); > + > + if (retval < 0) { > return errno; > } else if (retval > size) { > return EMSGSIZE; > - } else { > - buffer->size += retval; > - return 0; > } > + > + buffer->size += retval; > + return 0; > +} > + > +static int > +netdev_linux_rx_recv(struct netdev_rx *rx_, struct ofpbuf *buffer) > +{ > + struct netdev_rx_linux *rx = netdev_rx_linux_cast(rx_); > + int retval; > + > + retval = (rx->is_tap > + ? netdev_linux_rx_recv_tap(rx->fd, buffer) > + : netdev_linux_rx_recv_sock(rx->fd, buffer)); > + if (retval) { > + if (retval != EAGAIN && retval != EMSGSIZE) { > + VLOG_WARN_RL(&rl, "error receiving Ethernet packet on %s: %s", > + ovs_strerror(errno), netdev_rx_get_name(rx_)); > + } > + } > + > + return retval; > } > > static void > -- > 1.8.4 > > _______________________________________________ > dev mailing list > dev@openvswitch.org > http://openvswitch.org/mailman/listinfo/dev >
_______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev