X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=lib%2Fnetdev-linux.c;h=e2af6594fcd665c9f91b11e4a55a315a1a5ba426;hb=b0387df4e0ac796af05765834bb6e7750b8b6ae6;hp=baaa1e66343bc32124405d0071ab6167ecd7f758;hpb=c45ab5e9b76adc4097a3243bfc07502e658ccd5c;p=sliver-openvswitch.git diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c index baaa1e663..e2af6594f 100644 --- a/lib/netdev-linux.c +++ b/lib/netdev-linux.c @@ -64,7 +64,7 @@ #include "rtnetlink-link.h" #include "socket-util.h" #include "shash.h" -#include "svec.h" +#include "sset.h" #include "vlog.h" VLOG_DEFINE_THIS_MODULE(netdev_linux); @@ -368,8 +368,9 @@ struct netdev_linux { int fd; }; -/* An AF_INET socket (used for ioctl operations). */ -static int af_inet_sock = -1; +/* Sockets used for ioctl operations. */ +static int af_inet_sock = -1; /* AF_INET, SOCK_DGRAM. */ +static int af_packet_sock = -1; /* AF_PACKET, SOCK_RAW. */ /* A Netlink routing socket that is not subscribed to any multicast groups. */ static struct nl_sock *rtnl_sock; @@ -443,6 +444,15 @@ netdev_linux_init(void) status = af_inet_sock >= 0 ? 0 : errno; if (status) { VLOG_ERR("failed to create inet socket: %s", strerror(status)); + } else { + /* Create AF_PACKET socket. */ + af_packet_sock = socket(AF_PACKET, SOCK_RAW, 0); + status = af_packet_sock >= 0 ? 0 : errno; + if (status) { + VLOG_ERR("failed to create packet socket: %s", + strerror(status)); + } + set_nonblocking(af_packet_sock); } /* Create rtnetlink socket. */ @@ -729,9 +739,9 @@ netdev_linux_close(struct netdev *netdev_) free(netdev); } -/* Initializes 'svec' with a list of the names of all known network devices. */ +/* Initializes 'sset' with a list of the names of all known network devices. */ static int -netdev_linux_enumerate(struct svec *svec) +netdev_linux_enumerate(struct sset *sset) { struct if_nameindex *names; @@ -740,7 +750,7 @@ netdev_linux_enumerate(struct svec *svec) size_t i; for (i = 0; names[i].if_name != NULL; i++) { - svec_add(svec, names[i].if_name); + sset_add(sset, names[i].if_name); } if_freenameindex(names); return 0; @@ -820,15 +830,48 @@ static int netdev_linux_send(struct netdev *netdev_, const void *data, size_t size) { struct netdev_linux *netdev = netdev_linux_cast(netdev_); + for (;;) { + ssize_t retval; - /* XXX should support sending even if 'ethertype' was NETDEV_ETH_TYPE_NONE. - */ - if (netdev->fd < 0) { - return EPIPE; - } + 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; + + error = get_ifindex(netdev_, &ifindex); + if (error) { + return 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; + + 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 = write(netdev->fd, data, size); if (retval < 0) { /* The Linux AF_PACKET implementation never blocks waiting for room * for packets, instead returning ENOBUFS. Translate this into @@ -1115,9 +1158,9 @@ netdev_linux_update_is_pseudo(struct netdev_dev_linux *netdev_dev) static void swap_uint64(uint64_t *a, uint64_t *b) { - *a ^= *b; - *b ^= *a; - *a ^= *b; + uint64_t tmp = *a; + *a = *b; + *b = tmp; } /* Retrieves current device stats for 'netdev'. */ @@ -1510,14 +1553,14 @@ netdev_linux_set_policing(struct netdev *netdev, static int netdev_linux_get_qos_types(const struct netdev *netdev OVS_UNUSED, - struct svec *types) + struct sset *types) { const struct tc_ops **opsp; for (opsp = tcs; *opsp != NULL; opsp++) { const struct tc_ops *ops = *opsp; if (ops->tc_install && ops->ovs_name[0] != '\0') { - svec_add(types, ops->ovs_name); + sset_add(types, ops->ovs_name); } } return 0; @@ -2301,7 +2344,7 @@ htb_get__(const struct netdev *netdev) return CONTAINER_OF(netdev_dev->tc, struct htb, tc); } -static struct htb * +static void htb_install__(struct netdev *netdev, uint64_t max_rate) { struct netdev_dev_linux *netdev_dev = @@ -2313,8 +2356,6 @@ htb_install__(struct netdev *netdev, uint64_t max_rate) htb->max_rate = max_rate; netdev_dev->tc = &htb->tc; - - return htb; } /* Create an HTB qdisc. @@ -2497,8 +2538,10 @@ htb_parse_class_details__(struct netdev *netdev, return EINVAL; } + /* HTB requires at least an mtu sized min-rate to send any traffic even + * on uncongested links. */ hc->min_rate = min_rate_s ? strtoull(min_rate_s, NULL, 10) / 8 : 0; - hc->min_rate = MAX(hc->min_rate, 1500); + hc->min_rate = MAX(hc->min_rate, mtu); hc->min_rate = MIN(hc->min_rate, htb->max_rate); /* max-rate */ @@ -2598,12 +2641,11 @@ htb_tc_load(struct netdev *netdev, struct ofpbuf *nlmsg OVS_UNUSED) struct ofpbuf msg; struct nl_dump dump; struct htb_class hc; - struct htb *htb; /* Get qdisc options. */ hc.max_rate = 0; htb_query_class__(netdev, tc_make_handle(1, 0xfffe), 0, &hc, NULL); - htb = htb_install__(netdev, hc.max_rate); + htb_install__(netdev, hc.max_rate); /* Get queues. */ if (!start_queue_dump(netdev, &dump)) { @@ -2787,7 +2829,7 @@ hfsc_class_cast__(const struct tc_queue *queue) return CONTAINER_OF(queue, struct hfsc_class, tc_queue); } -static struct hfsc * +static void hfsc_install__(struct netdev *netdev, uint32_t max_rate) { struct netdev_dev_linux * netdev_dev; @@ -2798,8 +2840,6 @@ hfsc_install__(struct netdev *netdev, uint32_t max_rate) tc_init(&hfsc->tc, &tc_ops_hfsc); hfsc->max_rate = max_rate; netdev_dev->tc = &hfsc->tc; - - return hfsc; } static void @@ -2973,7 +3013,7 @@ hfsc_parse_class_details__(struct netdev *netdev, max_rate_s = shash_find_data(details, "max-rate"); min_rate = min_rate_s ? strtoull(min_rate_s, NULL, 10) / 8 : 0; - min_rate = MAX(min_rate, 1500); + min_rate = MAX(min_rate, 1); min_rate = MIN(min_rate, hfsc->max_rate); max_rate = (max_rate_s @@ -3098,13 +3138,12 @@ static int hfsc_tc_load(struct netdev *netdev, struct ofpbuf *nlmsg OVS_UNUSED) { struct ofpbuf msg; - struct hfsc *hfsc; struct nl_dump dump; struct hfsc_class hc; hc.max_rate = 0; hfsc_query_class__(netdev, tc_make_handle(1, 0xfffe), 0, &hc, NULL); - hfsc = hfsc_install__(netdev, hc.max_rate); + hfsc_install__(netdev, hc.max_rate); if (!start_queue_dump(netdev, &dump)) { return ENODEV;