X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=lib%2Fnetdev-linux.c;h=97f9a647ffd2d0a37c1dc3e63ec45d7e75da6e26;hb=ea763e0e2828c35660310f8b7791781b17b30cbd;hp=39e21bc6749b27091f764670052cd26bbea179bd;hpb=a339aa8162f4ac29784bc4e35612137f9cb1a025;p=sliver-openvswitch.git diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c index 39e21bc67..97f9a647f 100644 --- a/lib/netdev-linux.c +++ b/lib/netdev-linux.c @@ -53,17 +53,27 @@ #include "netdev-provider.h" #include "netdev-vport.h" #include "netlink.h" +#include "netlink-socket.h" #include "ofpbuf.h" #include "openflow/openflow.h" #include "packets.h" #include "poll-loop.h" #include "rtnetlink.h" +#include "rtnetlink-link.h" #include "socket-util.h" #include "shash.h" #include "svec.h" #include "vlog.h" VLOG_DEFINE_THIS_MODULE(netdev_linux); + +COVERAGE_DEFINE(netdev_get_vlan_vid); +COVERAGE_DEFINE(netdev_set_policing); +COVERAGE_DEFINE(netdev_arp_lookup); +COVERAGE_DEFINE(netdev_get_ifindex); +COVERAGE_DEFINE(netdev_get_hwaddr); +COVERAGE_DEFINE(netdev_set_hwaddr); +COVERAGE_DEFINE(netdev_ethtool); /* These were introduced in Linux 2.6.14, so they might be missing if we have * old headers. */ @@ -448,17 +458,17 @@ netdev_linux_init(void) static void netdev_linux_run(void) { - rtnetlink_notifier_run(); + rtnetlink_link_notifier_run(); } static void netdev_linux_wait(void) { - rtnetlink_notifier_wait(); + rtnetlink_link_notifier_wait(); } static void -netdev_linux_cache_cb(const struct rtnetlink_change *change, +netdev_linux_cache_cb(const struct rtnetlink_link_change *change, void *aux OVS_UNUSED) { struct netdev_dev_linux *dev; @@ -487,9 +497,9 @@ netdev_linux_cache_cb(const struct rtnetlink_change *change, } } -/* Creates the netdev device of 'type' with 'name'. */ +/* Creates system and internal devices. */ static int -netdev_linux_create_system(const struct netdev_class *class OVS_UNUSED, +netdev_linux_create(const struct netdev_class *class, const char *name, const struct shash *args, struct netdev_dev **netdev_devp) { @@ -497,12 +507,13 @@ netdev_linux_create_system(const struct netdev_class *class OVS_UNUSED, int error; if (!shash_is_empty(args)) { - VLOG_WARN("%s: arguments for system devices should be empty", name); + VLOG_WARN("%s: arguments for %s devices should be empty", + name, class->type); } if (!cache_notifier_refcount) { - error = rtnetlink_notifier_register(&netdev_linux_cache_notifier, - netdev_linux_cache_cb, NULL); + error = rtnetlink_link_notifier_register(&netdev_linux_cache_notifier, + netdev_linux_cache_cb, NULL); if (error) { return error; } @@ -510,7 +521,7 @@ netdev_linux_create_system(const struct netdev_class *class OVS_UNUSED, cache_notifier_refcount++; netdev_dev = xzalloc(sizeof *netdev_dev); - netdev_dev_init(&netdev_dev->netdev_dev, name, &netdev_linux_class); + netdev_dev_init(&netdev_dev->netdev_dev, name, class); *netdev_devp = &netdev_dev->netdev_dev; return 0; @@ -588,20 +599,22 @@ static void netdev_linux_destroy(struct netdev_dev *netdev_dev_) { struct netdev_dev_linux *netdev_dev = netdev_dev_linux_cast(netdev_dev_); - const char *type = netdev_dev_get_type(netdev_dev_); + const struct netdev_class *class = netdev_dev_get_class(netdev_dev_); if (netdev_dev->tc && netdev_dev->tc->ops->tc_destroy) { netdev_dev->tc->ops->tc_destroy(netdev_dev->tc); } - if (!strcmp(type, "system")) { + if (class == &netdev_linux_class || class == &netdev_internal_class) { cache_notifier_refcount--; if (!cache_notifier_refcount) { - rtnetlink_notifier_unregister(&netdev_linux_cache_notifier); + rtnetlink_link_notifier_unregister(&netdev_linux_cache_notifier); } - } else if (!strcmp(type, "tap")) { + } else if (class == &netdev_tap_class) { destroy_tap(netdev_dev); + } else { + NOT_REACHED(); } free(netdev_dev); @@ -621,9 +634,19 @@ netdev_linux_open(struct netdev_dev *netdev_dev_, int ethertype, netdev->fd = -1; netdev_init(&netdev->netdev, netdev_dev_); - error = netdev_get_flags(&netdev->netdev, &flags); - if (error == ENODEV) { - goto error; + /* Verify that the device really exists, by attempting to read its flags. + * (The flags might be cached, in which case this won't actually do an + * ioctl.) + * + * Don't do this for "internal" netdevs, though, because those have to be + * created as netdev objects before they exist in the kernel, because + * creating them in the kernel happens by passing a netdev object to + * dpif_port_add(). */ + if (netdev_dev_get_class(netdev_dev_) != &netdev_internal_class) { + error = netdev_get_flags(&netdev->netdev, &flags); + if (error == ENODEV) { + goto error; + } } if (!strcmp(netdev_dev_get_type(netdev_dev_), "tap") && @@ -1059,8 +1082,6 @@ netdev_linux_get_stats(const struct netdev *netdev_, static int use_netlink_stats = -1; int error; - COVERAGE_INC(netdev_get_stats); - if (netdev_dev->have_vport_stats || !(netdev_dev->cache_valid & VALID_HAVE_VPORT_STATS)) { @@ -1875,7 +1896,6 @@ netdev_linux_add_router(struct netdev *netdev OVS_UNUSED, struct in_addr router) make_in4_sockaddr(&rt.rt_gateway, router); make_in4_sockaddr(&rt.rt_genmask, any); rt.rt_flags = RTF_UP | RTF_GATEWAY; - COVERAGE_INC(netdev_add_router); error = ioctl(af_inet_sock, SIOCADDRT, &rt) < 0 ? errno : 0; if (error) { VLOG_WARN("ioctl(SIOCADDRT): %s", strerror(error)); @@ -2030,7 +2050,7 @@ poll_notify(struct list *list) } static void -netdev_linux_poll_cb(const struct rtnetlink_change *change, +netdev_linux_poll_cb(const struct rtnetlink_link_change *change, void *aux OVS_UNUSED) { if (change) { @@ -2057,8 +2077,9 @@ netdev_linux_poll_add(struct netdev *netdev, struct list *list; if (shash_is_empty(&netdev_linux_notifiers)) { - int error = rtnetlink_notifier_register(&netdev_linux_poll_notifier, - netdev_linux_poll_cb, NULL); + int error; + error = rtnetlink_link_notifier_register(&netdev_linux_poll_notifier, + netdev_linux_poll_cb, NULL); if (error) { return error; } @@ -2098,129 +2119,92 @@ netdev_linux_poll_remove(struct netdev_notifier *notifier_) /* If that was the last notifier, unregister. */ if (shash_is_empty(&netdev_linux_notifiers)) { - rtnetlink_notifier_unregister(&netdev_linux_poll_notifier); - } -} - -const struct netdev_class netdev_linux_class = { - "system", - - netdev_linux_init, - netdev_linux_run, - netdev_linux_wait, - - netdev_linux_create_system, - netdev_linux_destroy, - NULL, /* reconfigure */ - - netdev_linux_open, - netdev_linux_close, - - netdev_linux_enumerate, - - netdev_linux_recv, - netdev_linux_recv_wait, - netdev_linux_drain, - - netdev_linux_send, - netdev_linux_send_wait, - - netdev_linux_set_etheraddr, - netdev_linux_get_etheraddr, - netdev_linux_get_mtu, - netdev_linux_get_ifindex, - netdev_linux_get_carrier, - netdev_linux_get_stats, - netdev_vport_set_stats, - - netdev_linux_get_features, - netdev_linux_set_advertisements, - netdev_linux_get_vlan_vid, - - netdev_linux_set_policing, - netdev_linux_get_qos_types, - netdev_linux_get_qos_capabilities, - netdev_linux_get_qos, - netdev_linux_set_qos, - netdev_linux_get_queue, - netdev_linux_set_queue, - netdev_linux_delete_queue, - netdev_linux_get_queue_stats, - netdev_linux_dump_queues, - netdev_linux_dump_queue_stats, - - netdev_linux_get_in4, - netdev_linux_set_in4, - netdev_linux_get_in6, - netdev_linux_add_router, - netdev_linux_get_next_hop, - netdev_linux_arp_lookup, - - netdev_linux_update_flags, - - netdev_linux_poll_add, - netdev_linux_poll_remove, -}; - -const struct netdev_class netdev_tap_class = { - "tap", - - netdev_linux_init, - netdev_linux_run, - netdev_linux_wait, - - netdev_linux_create_tap, - netdev_linux_destroy, - NULL, /* reconfigure */ - - netdev_linux_open, - netdev_linux_close, - - NULL, /* enumerate */ - - netdev_linux_recv, - netdev_linux_recv_wait, - netdev_linux_drain, - - netdev_linux_send, - netdev_linux_send_wait, - - netdev_linux_set_etheraddr, - netdev_linux_get_etheraddr, - netdev_linux_get_mtu, - netdev_linux_get_ifindex, - netdev_linux_get_carrier, - netdev_linux_get_stats, - NULL, /* set_stats */ - - netdev_linux_get_features, - netdev_linux_set_advertisements, - netdev_linux_get_vlan_vid, - - netdev_linux_set_policing, - netdev_linux_get_qos_types, - netdev_linux_get_qos_capabilities, - netdev_linux_get_qos, - netdev_linux_set_qos, - netdev_linux_get_queue, - netdev_linux_set_queue, - netdev_linux_delete_queue, - netdev_linux_get_queue_stats, - netdev_linux_dump_queues, - netdev_linux_dump_queue_stats, - - netdev_linux_get_in4, - netdev_linux_set_in4, - netdev_linux_get_in6, - netdev_linux_add_router, - netdev_linux_get_next_hop, - netdev_linux_arp_lookup, - - netdev_linux_update_flags, - - netdev_linux_poll_add, - netdev_linux_poll_remove, -}; + rtnetlink_link_notifier_unregister(&netdev_linux_poll_notifier); + } +} + +#define NETDEV_LINUX_CLASS(NAME, CREATE, ENUMERATE, SET_STATS) \ +{ \ + NAME, \ + \ + netdev_linux_init, \ + netdev_linux_run, \ + netdev_linux_wait, \ + \ + CREATE, \ + netdev_linux_destroy, \ + NULL, /* reconfigure */ \ + \ + netdev_linux_open, \ + netdev_linux_close, \ + \ + ENUMERATE, \ + \ + netdev_linux_recv, \ + netdev_linux_recv_wait, \ + netdev_linux_drain, \ + \ + netdev_linux_send, \ + netdev_linux_send_wait, \ + \ + netdev_linux_set_etheraddr, \ + netdev_linux_get_etheraddr, \ + netdev_linux_get_mtu, \ + netdev_linux_get_ifindex, \ + netdev_linux_get_carrier, \ + netdev_linux_get_stats, \ + SET_STATS, \ + \ + netdev_linux_get_features, \ + netdev_linux_set_advertisements, \ + netdev_linux_get_vlan_vid, \ + \ + netdev_linux_set_policing, \ + netdev_linux_get_qos_types, \ + netdev_linux_get_qos_capabilities, \ + netdev_linux_get_qos, \ + netdev_linux_set_qos, \ + netdev_linux_get_queue, \ + netdev_linux_set_queue, \ + netdev_linux_delete_queue, \ + netdev_linux_get_queue_stats, \ + netdev_linux_dump_queues, \ + netdev_linux_dump_queue_stats, \ + \ + netdev_linux_get_in4, \ + netdev_linux_set_in4, \ + netdev_linux_get_in6, \ + netdev_linux_add_router, \ + netdev_linux_get_next_hop, \ + NULL, /* get_status */ \ + netdev_linux_arp_lookup, \ + \ + netdev_linux_update_flags, \ + \ + netdev_linux_poll_add, \ + netdev_linux_poll_remove \ +} + +const struct netdev_class netdev_linux_class = + NETDEV_LINUX_CLASS( + "system", + netdev_linux_create, + netdev_linux_enumerate, + NULL); /* set_stats */ + +const struct netdev_class netdev_tap_class = + NETDEV_LINUX_CLASS( + "tap", + netdev_linux_create_tap, + NULL, /* enumerate */ + NULL); /* set_stats */ + +const struct netdev_class netdev_internal_class = + NETDEV_LINUX_CLASS( + "internal", + netdev_linux_create, + NULL, /* enumerate */ + netdev_vport_set_stats); /* HTB traffic control class. */