X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=lib%2Fnetdev-linux.c;h=e2af6594fcd665c9f91b11e4a55a315a1a5ba426;hb=b0387df4e0ac796af05765834bb6e7750b8b6ae6;hp=1aa909345f6c241e3865d5ec3e0e84f47580e773;hpb=1de0e8ae5c4a793edc4f033deefb185d933238e4;p=openvswitch diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c index 1aa90934..e2af6594 100644 --- a/lib/netdev-linux.c +++ b/lib/netdev-linux.c @@ -452,6 +452,7 @@ netdev_linux_init(void) VLOG_ERR("failed to create packet socket: %s", strerror(status)); } + set_nonblocking(af_packet_sock); } /* Create rtnetlink socket. */ @@ -828,36 +829,49 @@ netdev_linux_drain(struct netdev *netdev_) static int netdev_linux_send(struct netdev *netdev_, const void *data, size_t size) { - struct sockaddr_ll sll; - struct msghdr msg; - struct iovec iov; - int ifindex; - int error; + struct netdev_linux *netdev = netdev_linux_cast(netdev_); + for (;;) { + ssize_t retval; - error = get_ifindex(netdev_, &ifindex); - if (error) { - return error; - } + if (netdev->fd < 0) { + /* Use our AF_PACKET socket to send to this device. */ + struct sockaddr_ll sll; + struct msghdr msg; + struct iovec iov; + int ifindex; + int error; - /* We don't bother setting most fields in sockaddr_ll because the kernel - * ignores them for SOCK_RAW. */ - memset(&sll, 0, sizeof sll); - sll.sll_family = AF_PACKET; - sll.sll_ifindex = ifindex; + error = get_ifindex(netdev_, &ifindex); + if (error) { + return error; + } - iov.iov_base = (void *) data; - iov.iov_len = size; + /* We don't bother setting most fields in sockaddr_ll because the + * kernel ignores them for SOCK_RAW. */ + memset(&sll, 0, sizeof sll); + sll.sll_family = AF_PACKET; + sll.sll_ifindex = ifindex; - msg.msg_name = &sll; - msg.msg_namelen = sizeof sll; - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - msg.msg_control = NULL; - msg.msg_controllen = 0; - msg.msg_flags = 0; + iov.iov_base = (void *) data; + iov.iov_len = size; + + msg.msg_name = &sll; + msg.msg_namelen = sizeof sll; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = NULL; + msg.msg_controllen = 0; + msg.msg_flags = 0; + + retval = sendmsg(af_packet_sock, &msg, 0); + } else { + /* Use the netdev's own fd to send to this device. This is + * essential for tap devices, because packets sent to a tap device + * with an AF_PACKET socket will loop back to be *received* again + * on the tap device. */ + retval = write(netdev->fd, data, size); + } - for (;;) { - ssize_t retval = sendmsg(af_packet_sock, &msg, 0); if (retval < 0) { /* The Linux AF_PACKET implementation never blocks waiting for room * for packets, instead returning ENOBUFS. Translate this into