From: Giuseppe Lettieri Date: Thu, 15 Aug 2013 17:35:59 +0000 (+0200) Subject: Merge commit '9dc63482bbeae23dd57b0f885a3fd26b44656844' X-Git-Tag: sliver-openvswitch-2.0.90-1~29 X-Git-Url: http://git.onelab.eu/?a=commitdiff_plain;h=b0fb94a346e52f36aeef238dd5f9bef9a10c14ef;hp=34290dbfe54a930258d4c1d00e82e7c3f51cea5f;p=sliver-openvswitch.git Merge commit '9dc63482bbeae23dd57b0f885a3fd26b44656844' --- diff --git a/lib/netdev-bsd.c b/lib/netdev-bsd.c index b799cb589..0f625afd3 100644 --- a/lib/netdev-bsd.c +++ b/lib/netdev-bsd.c @@ -50,6 +50,7 @@ #include "fatal-signal.h" #include "ofpbuf.h" #include "openflow/openflow.h" +#include "ovs-thread.h" #include "packets.h" #include "poll-loop.h" #include "socket-util.h" @@ -73,8 +74,6 @@ struct netdev_rx_bsd { int fd; }; -static const struct netdev_rx_class netdev_rx_bsd_class; - struct netdev_bsd { struct netdev up; unsigned int cache_valid; @@ -107,11 +106,6 @@ enum { VALID_CARRIER = 1 << 5 }; -#if defined(__NetBSD__) -/* AF_LINK socket used for netdev_bsd_get_stats and set_etheraddr */ -static int af_link_sock = -1; -#endif /* defined(__NetBSD__) */ - #define PCAP_SNAPLEN 2048 @@ -144,12 +138,16 @@ static int get_ifindex(const struct netdev *, int *ifindexp); static int ifr_get_flags(const struct ifreq *); static void ifr_set_flags(struct ifreq *, int flags); -static int netdev_bsd_init(void); +#ifdef __NetBSD__ +static int af_link_ioctl(int command, const void *arg); +#endif + +static void netdev_bsd_run(void); static bool is_netdev_bsd_class(const struct netdev_class *netdev_class) { - return netdev_class->init == netdev_bsd_init; + return netdev_class->run == netdev_bsd_run; } static struct netdev_bsd * @@ -162,7 +160,7 @@ netdev_bsd_cast(const struct netdev *netdev) static struct netdev_rx_bsd * netdev_rx_bsd_cast(const struct netdev_rx *rx) { - netdev_rx_assert_class(rx, &netdev_rx_bsd_class); + ovs_assert(is_netdev_bsd_class(netdev_get_class(rx->netdev))); return CONTAINER_OF(rx, struct netdev_rx_bsd, up); } @@ -172,29 +170,6 @@ netdev_get_kernel_name(const struct netdev *netdev) return netdev_bsd_cast(netdev)->kernel_name; } -/* Initialize the AF_INET socket used for ioctl operations */ -static int -netdev_bsd_init(void) -{ -#if defined(__NetBSD__) - static int status = -1; - - if (status >= 0) { /* already initialized */ - return status; - } - - af_link_sock = socket(AF_LINK, SOCK_DGRAM, 0); - status = af_link_sock >= 0 ? 0 : errno; - if (status) { - VLOG_ERR("failed to create link socket: %s", ovs_strerror(status)); - } - - return status; -#else - return 0; -#endif /* defined(__NetBSD__) */ -} - /* * Perform periodic work needed by netdev. In BSD netdevs it checks for any * interface status changes, and eventually calls all the user callbacks. @@ -292,12 +267,17 @@ cache_notifier_unref(void) return 0; } -/* Allocate a netdev_bsd structure */ +static struct netdev * +netdev_bsd_alloc(void) +{ + struct netdev_bsd *netdev = xzalloc(sizeof *netdev); + return &netdev->up; +} + static int -netdev_bsd_create_system(const struct netdev_class *class, const char *name, - struct netdev **netdevp) +netdev_bsd_construct_system(struct netdev *netdev_) { - struct netdev_bsd *netdev; + struct netdev_bsd *netdev = netdev_bsd_cast(netdev_); enum netdev_flags flags; int error; @@ -306,34 +286,26 @@ netdev_bsd_create_system(const struct netdev_class *class, const char *name, return error; } - netdev = xzalloc(sizeof *netdev); netdev->change_seq = 1; - netdev_init(&netdev->up, name, class); netdev->tap_fd = -1; - netdev->kernel_name = xstrdup(name); + netdev->kernel_name = xstrdup(netdev_->name); /* Verify that the netdev really exists by attempting to read its flags */ - error = netdev_get_flags(&netdev->up, &flags); + error = netdev_get_flags(netdev_, &flags); if (error == ENXIO) { free(netdev->kernel_name); - netdev_uninit(&netdev->up, false); - free(netdev); cache_notifier_unref(); return error; } - *netdevp = &netdev->up; return 0; } -/* - * Allocate a netdev_bsd structure with 'tap' class. - */ static int -netdev_bsd_create_tap(const struct netdev_class *class, const char *name, - struct netdev **netdevp) +netdev_bsd_construct_tap(struct netdev *netdev_) { - struct netdev_bsd *netdev = NULL; + struct netdev_bsd *netdev = netdev_bsd_cast(netdev_); + const char *name = netdev_->name; int error = 0; struct ifreq ifr; char *kernel_name = NULL; @@ -343,9 +315,6 @@ netdev_bsd_create_tap(const struct netdev_class *class, const char *name, goto error; } - /* allocate the device structure and set the internal flag */ - netdev = xzalloc(sizeof *netdev); - memset(&ifr, 0, sizeof(ifr)); /* Create a tap device by opening /dev/tap. The TAPGIFNAME ioctl is used @@ -399,24 +368,19 @@ netdev_bsd_create_tap(const struct netdev_class *class, const char *name, goto error_unref_notifier; } - /* initialize the device structure and - * link the structure to its netdev */ - netdev_init(&netdev->up, name, class); netdev->kernel_name = kernel_name; - *netdevp = &netdev->up; return 0; error_unref_notifier: cache_notifier_unref(); error: - free(netdev); free(kernel_name); return error; } static void -netdev_bsd_destroy(struct netdev *netdev_) +netdev_bsd_destruct(struct netdev *netdev_) { struct netdev_bsd *netdev = netdev_bsd_cast(netdev_); @@ -429,6 +393,13 @@ netdev_bsd_destroy(struct netdev *netdev_) pcap_close(netdev->pcap); } free(netdev->kernel_name); +} + +static void +netdev_bsd_dealloc(struct netdev *netdev_) +{ + struct netdev_bsd *netdev = netdev_bsd_cast(netdev_); + free(netdev); } @@ -501,21 +472,26 @@ error: return error; } +static struct netdev_rx * +netdev_bsd_rx_alloc(void) +{ + struct netdev_rx_bsd *rx = xzalloc(sizeof *rx); + return &rx->up; +} + static int -netdev_bsd_rx_open(struct netdev *netdev_, struct netdev_rx **rxp) +netdev_bsd_rx_construct(struct netdev_rx *rx_) { + struct netdev_rx_bsd *rx = netdev_rx_bsd_cast(rx_); + struct netdev *netdev_ = rx->up.netdev; struct netdev_bsd *netdev = netdev_bsd_cast(netdev_); - struct netdev_rx_bsd *rx; - pcap_t *pcap; - int fd; - if (!strcmp(netdev_get_type(netdev_), "tap")) { - pcap = NULL; - fd = netdev->tap_fd; + rx->pcap_handle = NULL; + rx->fd = netdev->tap_fd; } else { int error = netdev_bsd_open_pcap(netdev_get_kernel_name(netdev_), - &pcap, &fd); + &rx->pcap_handle, &rx->fd); if (error) { return error; } @@ -523,23 +499,24 @@ netdev_bsd_rx_open(struct netdev *netdev_, struct netdev_rx **rxp) netdev_bsd_changed(netdev); } - rx = xmalloc(sizeof *rx); - netdev_rx_init(&rx->up, netdev_, &netdev_rx_bsd_class); - rx->pcap_handle = pcap; - rx->fd = fd; - - *rxp = &rx->up; return 0; } static void -netdev_rx_bsd_destroy(struct netdev_rx *rx_) +netdev_bsd_rx_destruct(struct netdev_rx *rx_) { struct netdev_rx_bsd *rx = netdev_rx_bsd_cast(rx_); if (rx->pcap_handle) { pcap_close(rx->pcap_handle); } +} + +static void +netdev_bsd_rx_dealloc(struct netdev_rx *rx_) +{ + struct netdev_rx_bsd *rx = netdev_rx_bsd_cast(rx_); + free(rx); } @@ -638,9 +615,8 @@ netdev_rx_bsd_recv_tap(struct netdev_rx_bsd *rx, void *data, size_t size) } } - static int -netdev_rx_bsd_recv(struct netdev_rx *rx_, void *data, size_t size) +netdev_bsd_rx_recv(struct netdev_rx *rx_, void *data, size_t size) { struct netdev_rx_bsd *rx = netdev_rx_bsd_cast(rx_); @@ -654,7 +630,7 @@ netdev_rx_bsd_recv(struct netdev_rx *rx_, void *data, size_t size) * when a packet is ready to be received with netdev_rx_recv() on 'rx'. */ static void -netdev_rx_bsd_wait(struct netdev_rx *rx_) +netdev_bsd_rx_wait(struct netdev_rx *rx_) { struct netdev_rx_bsd *rx = netdev_rx_bsd_cast(rx_); @@ -663,7 +639,7 @@ netdev_rx_bsd_wait(struct netdev_rx *rx_) /* Discards all packets waiting to be received from 'rx'. */ static int -netdev_rx_bsd_drain(struct netdev_rx *rx_) +netdev_bsd_rx_drain(struct netdev_rx *rx_) { struct ifreq ifr; struct netdev_rx_bsd *rx = netdev_rx_bsd_cast(rx_); @@ -931,19 +907,16 @@ netdev_bsd_get_stats(const struct netdev *netdev_, struct netdev_stats *stats) return 0; #elif defined(__NetBSD__) struct ifdatareq ifdr; - int saved_errno; - int ret; + int error; memset(&ifdr, 0, sizeof(ifdr)); strncpy(ifdr.ifdr_name, netdev_get_kernel_name(netdev_), sizeof(ifdr.ifdr_name)); - ret = ioctl(af_link_sock, SIOCGIFDATA, &ifdr); - saved_errno = errno; - if (ret == -1) { - return saved_errno; + error = af_link_ioctl(SIOCGIFDATA, &ifdr); + if (!error) { + convert_stats(stats, &ifdr.ifdr_data); } - convert_stats(stats, &ifdr.ifdr_data); - return 0; + return error; #else #error not implemented #endif @@ -1402,17 +1375,17 @@ netdev_bsd_change_seq(const struct netdev *netdev) const struct netdev_class netdev_bsd_class = { "system", - netdev_bsd_init, + NULL, /* init */ netdev_bsd_run, netdev_bsd_wait, - netdev_bsd_create_system, - netdev_bsd_destroy, + netdev_bsd_alloc, + netdev_bsd_construct_system, + netdev_bsd_destruct, + netdev_bsd_dealloc, NULL, /* get_config */ NULL, /* set_config */ NULL, /* get_tunnel_config */ - netdev_bsd_rx_open, - netdev_bsd_send, netdev_bsd_send_wait, @@ -1451,23 +1424,31 @@ const struct netdev_class netdev_bsd_class = { netdev_bsd_update_flags, - netdev_bsd_change_seq + netdev_bsd_change_seq, + + netdev_bsd_rx_alloc, + netdev_bsd_rx_construct, + netdev_bsd_rx_destruct, + netdev_bsd_rx_dealloc, + netdev_bsd_rx_recv, + netdev_bsd_rx_wait, + netdev_bsd_rx_drain, }; const struct netdev_class netdev_tap_class = { "tap", - netdev_bsd_init, + NULL, /* init */ netdev_bsd_run, netdev_bsd_wait, - netdev_bsd_create_tap, - netdev_bsd_destroy, + netdev_bsd_alloc, + netdev_bsd_construct_tap, + netdev_bsd_destruct, + netdev_bsd_dealloc, NULL, /* get_config */ NULL, /* set_config */ NULL, /* get_tunnel_config */ - netdev_bsd_rx_open, - netdev_bsd_send, netdev_bsd_send_wait, @@ -1506,14 +1487,15 @@ const struct netdev_class netdev_tap_class = { netdev_bsd_update_flags, - netdev_bsd_change_seq -}; + netdev_bsd_change_seq, -static const struct netdev_rx_class netdev_rx_bsd_class = { - netdev_rx_bsd_destroy, - netdev_rx_bsd_recv, - netdev_rx_bsd_wait, - netdev_rx_bsd_drain, + netdev_bsd_rx_alloc, + netdev_bsd_rx_construct, + netdev_bsd_rx_destruct, + netdev_bsd_rx_dealloc, + netdev_bsd_rx_recv, + netdev_bsd_rx_wait, + netdev_bsd_rx_drain, }; @@ -1625,7 +1607,7 @@ set_etheraddr(const char *netdev_name OVS_UNUSED, int hwaddr_family OVS_UNUSED, struct if_laddrreq req; struct sockaddr_dl *sdl; struct sockaddr_storage oldaddr; - int ret; + int error; /* * get the old address, add new one, and then remove old one. @@ -1641,9 +1623,10 @@ set_etheraddr(const char *netdev_name OVS_UNUSED, int hwaddr_family OVS_UNUSED, req.addr.ss_family = hwaddr_family; sdl = (struct sockaddr_dl *)&req.addr; sdl->sdl_alen = hwaddr_len; - ret = ioctl(af_link_sock, SIOCGLIFADDR, &req); - if (ret == -1) { - return errno; + + error = af_link_ioctl(SIOCGLIFADDR, &req); + if (error) { + return error; } if (!memcmp(&sdl->sdl_data[sdl->sdl_nlen], mac, hwaddr_len)) { return 0; @@ -1658,19 +1641,15 @@ set_etheraddr(const char *netdev_name OVS_UNUSED, int hwaddr_family OVS_UNUSED, sdl->sdl_alen = hwaddr_len; sdl->sdl_family = hwaddr_family; memcpy(sdl->sdl_data, mac, hwaddr_len); - ret = ioctl(af_link_sock, SIOCALIFADDR, &req); - if (ret == -1) { - return errno; + error = af_link_ioctl(SIOCALIFADDR, &req); + if (error) { + return error; } memset(&req, 0, sizeof(req)); strncpy(req.iflr_name, netdev_name, sizeof(req.iflr_name)); req.addr = oldaddr; - ret = ioctl(af_link_sock, SIOCDLIFADDR, &req); - if (ret == -1) { - return errno; - } - return 0; + return af_link_ioctl(SIOCDLIFADDR, &req); #else #error not implemented #endif @@ -1694,3 +1673,25 @@ ifr_set_flags(struct ifreq *ifr, int flags) ifr->ifr_flagshigh = flags >> 16; #endif } + +/* Calls ioctl() on an AF_LINK sock, passing the specified 'command' and + * 'arg'. Returns 0 if successful, otherwise a positive errno value. */ +int +af_link_ioctl(int command, const void *arg) +{ + static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER; + static int sock; + + if (ovsthread_once_start(&once)) { + sock = socket(AF_LINK, SOCK_DGRAM, 0); + if (sock < 0) { + sock = -errno; + VLOG_ERR("failed to create link socket: %s", ovs_strerror(errno)); + } + ovsthread_once_done(&once); + } + + return (sock < 0 ? -sock + : ioctl(sock, command, arg) == -1 ? errno + : 0); +} diff --git a/lib/netdev-dummy.c b/lib/netdev-dummy.c index dc3ddf80e..0560adecf 100644 --- a/lib/netdev-dummy.c +++ b/lib/netdev-dummy.c @@ -73,11 +73,8 @@ struct netdev_rx_dummy { bool listening; }; -static const struct netdev_rx_class netdev_rx_dummy_class; - static unixctl_cb_func netdev_dummy_set_admin_state; -static int netdev_dummy_create(const struct netdev_class *, const char *, - struct netdev **); +static int netdev_dummy_construct(struct netdev *); static void netdev_dummy_poll_notify(struct netdev_dummy *); static void netdev_dummy_queue_packet(struct netdev_dummy *, struct ofpbuf *); @@ -86,7 +83,7 @@ static void dummy_stream_close(struct dummy_stream *); static bool is_dummy_class(const struct netdev_class *class) { - return class->create == netdev_dummy_create; + return class->construct == netdev_dummy_construct; } static struct netdev_dummy * @@ -99,7 +96,7 @@ netdev_dummy_cast(const struct netdev *netdev) static struct netdev_rx_dummy * netdev_rx_dummy_cast(const struct netdev_rx *rx) { - netdev_rx_assert_class(rx, &netdev_rx_dummy_class); + ovs_assert(is_dummy_class(netdev_get_class(rx->netdev))); return CONTAINER_OF(rx, struct netdev_rx_dummy, up); } @@ -248,17 +245,21 @@ netdev_dummy_wait(void) shash_destroy(&dummy_netdevs); } +static struct netdev * +netdev_dummy_alloc(void) +{ + struct netdev_dummy *netdev = xzalloc(sizeof *netdev); + return &netdev->up; +} + static int -netdev_dummy_create(const struct netdev_class *class, const char *name, - struct netdev **netdevp) +netdev_dummy_construct(struct netdev *netdev_) { static atomic_uint next_n = ATOMIC_VAR_INIT(0xaa550000); - struct netdev_dummy *netdev; + struct netdev_dummy *netdev = netdev_dummy_cast(netdev_); unsigned int n; atomic_add(&next_n, 1, &n); - netdev = xzalloc(sizeof *netdev); - netdev_init(&netdev->up, name, class); netdev->hwaddr[0] = 0xaa; netdev->hwaddr[1] = 0x55; netdev->hwaddr[2] = n >> 24; @@ -276,13 +277,11 @@ netdev_dummy_create(const struct netdev_class *class, const char *name, list_init(&netdev->rxes); - *netdevp = &netdev->up; - return 0; } static void -netdev_dummy_destroy(struct netdev *netdev_) +netdev_dummy_destruct(struct netdev *netdev_) { struct netdev_dummy *netdev = netdev_dummy_cast(netdev_); size_t i; @@ -292,6 +291,13 @@ netdev_dummy_destroy(struct netdev *netdev_) dummy_stream_close(&netdev->streams[i]); } free(netdev->streams); +} + +static void +netdev_dummy_dealloc(struct netdev *netdev_) +{ + struct netdev_dummy *netdev = netdev_dummy_cast(netdev_); + free(netdev); } @@ -337,24 +343,45 @@ netdev_dummy_set_config(struct netdev *netdev_, const struct smap *args) return 0; } +static struct netdev_rx * +netdev_dummy_rx_alloc(void) +{ + struct netdev_rx_dummy *rx = xzalloc(sizeof *rx); + return &rx->up; +} + static int -netdev_dummy_rx_open(struct netdev *netdev_, struct netdev_rx **rxp) +netdev_dummy_rx_construct(struct netdev_rx *rx_) { - struct netdev_dummy *netdev = netdev_dummy_cast(netdev_); - struct netdev_rx_dummy *rx; + struct netdev_rx_dummy *rx = netdev_rx_dummy_cast(rx_); + struct netdev_dummy *netdev = netdev_dummy_cast(rx->up.netdev); - rx = xmalloc(sizeof *rx); - netdev_rx_init(&rx->up, &netdev->up, &netdev_rx_dummy_class); list_push_back(&netdev->rxes, &rx->node); list_init(&rx->recv_queue); rx->recv_queue_len = 0; - *rxp = &rx->up; return 0; } +static void +netdev_dummy_rx_destruct(struct netdev_rx *rx_) +{ + struct netdev_rx_dummy *rx = netdev_rx_dummy_cast(rx_); + + list_remove(&rx->node); + ofpbuf_list_delete(&rx->recv_queue); +} + +static void +netdev_dummy_rx_dealloc(struct netdev_rx *rx_) +{ + struct netdev_rx_dummy *rx = netdev_rx_dummy_cast(rx_); + + free(rx); +} + static int -netdev_rx_dummy_recv(struct netdev_rx *rx_, void *buffer, size_t size) +netdev_dummy_rx_recv(struct netdev_rx *rx_, void *buffer, size_t size) { struct netdev_rx_dummy *rx = netdev_rx_dummy_cast(rx_); struct ofpbuf *packet; @@ -378,16 +405,7 @@ netdev_rx_dummy_recv(struct netdev_rx *rx_, void *buffer, size_t size) } static void -netdev_rx_dummy_destroy(struct netdev_rx *rx_) -{ - struct netdev_rx_dummy *rx = netdev_rx_dummy_cast(rx_); - list_remove(&rx->node); - ofpbuf_list_delete(&rx->recv_queue); - free(rx); -} - -static void -netdev_rx_dummy_wait(struct netdev_rx *rx_) +netdev_dummy_rx_wait(struct netdev_rx *rx_) { struct netdev_rx_dummy *rx = netdev_rx_dummy_cast(rx_); if (!list_is_empty(&rx->recv_queue)) { @@ -396,7 +414,7 @@ netdev_rx_dummy_wait(struct netdev_rx *rx_) } static int -netdev_rx_dummy_drain(struct netdev_rx *rx_) +netdev_dummy_rx_drain(struct netdev_rx *rx_) { struct netdev_rx_dummy *rx = netdev_rx_dummy_cast(rx_); ofpbuf_list_delete(&rx->recv_queue); @@ -554,14 +572,14 @@ static const struct netdev_class dummy_class = { netdev_dummy_run, netdev_dummy_wait, - netdev_dummy_create, - netdev_dummy_destroy, + netdev_dummy_alloc, + netdev_dummy_construct, + netdev_dummy_destruct, + netdev_dummy_dealloc, netdev_dummy_get_config, netdev_dummy_set_config, NULL, /* get_tunnel_config */ - netdev_dummy_rx_open, - netdev_dummy_send, /* send */ NULL, /* send_wait */ @@ -601,14 +619,15 @@ static const struct netdev_class dummy_class = { netdev_dummy_update_flags, - netdev_dummy_change_seq -}; + netdev_dummy_change_seq, -static const struct netdev_rx_class netdev_rx_dummy_class = { - netdev_rx_dummy_destroy, - netdev_rx_dummy_recv, - netdev_rx_dummy_wait, - netdev_rx_dummy_drain, + netdev_dummy_rx_alloc, + netdev_dummy_rx_construct, + netdev_dummy_rx_destruct, + netdev_dummy_rx_dealloc, + netdev_dummy_rx_recv, + netdev_dummy_rx_wait, + netdev_dummy_rx_drain, }; static struct ofpbuf * diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c index 930610067..cf459059b 100644 --- a/lib/netdev-linux.c +++ b/lib/netdev-linux.c @@ -398,8 +398,6 @@ struct netdev_rx_linux { int fd; }; -static const struct netdev_rx_class netdev_rx_linux_class; - /* This is set pretty low because we probably won't learn anything from the * additional log messages. */ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 20); @@ -448,7 +446,7 @@ netdev_linux_cast(const struct netdev *netdev) static struct netdev_rx_linux * netdev_rx_linux_cast(const struct netdev_rx *rx) { - netdev_rx_assert_class(rx, &netdev_rx_linux_class); + ovs_assert(is_netdev_linux_class(netdev_get_class(rx->netdev))); return CONTAINER_OF(rx, struct netdev_rx_linux, up); } @@ -571,29 +569,38 @@ cache_notifier_unref(void) } } +static struct netdev * +netdev_linux_alloc(void) +{ + struct netdev_linux *netdev = xzalloc(sizeof *netdev); + return &netdev->up; +} + +static int +netdev_linux_common_construct(struct netdev_linux *netdev) +{ + netdev->change_seq = 1; + + return cache_notifier_ref(); +} + /* Creates system and internal devices. */ static int -netdev_linux_create(const struct netdev_class *class, const char *name, - struct netdev **netdevp) +netdev_linux_construct(struct netdev *netdev_) { - struct netdev_linux *netdev; + struct netdev_linux *netdev = netdev_linux_cast(netdev_); int error; - error = cache_notifier_ref(); + error = netdev_linux_common_construct(netdev); if (error) { return error; } - netdev = xzalloc(sizeof *netdev); - netdev->change_seq = 1; - netdev_init(&netdev->up, name, class); error = get_flags(&netdev->up, &netdev->ifi_flags); if (error == ENODEV) { - if (class != &netdev_internal_class) { + if (netdev->up.netdev_class != &netdev_internal_class) { /* The device does not exist, so don't allow it to be opened. */ - netdev_uninit(&netdev->up, false); cache_notifier_unref(); - free(netdev); return ENODEV; } else { /* "Internal" netdevs have to be created as netdev objects before @@ -603,7 +610,6 @@ netdev_linux_create(const struct netdev_class *class, const char *name, } } - *netdevp = &netdev->up; return 0; } @@ -614,18 +620,15 @@ netdev_linux_create(const struct netdev_class *class, const char *name, * buffers, across all readers. Therefore once data is read it will * be unavailable to other reads for tap devices. */ static int -netdev_linux_create_tap(const struct netdev_class *class OVS_UNUSED, - const char *name, struct netdev **netdevp) +netdev_linux_construct_tap(struct netdev *netdev_) { - struct netdev_linux *netdev; + struct netdev_linux *netdev = netdev_linux_cast(netdev_); static const char tap_dev[] = "/dev/net/tun"; + const char *name = netdev_->name; struct ifreq ifr; int error; - netdev = xzalloc(sizeof *netdev); - netdev->change_seq = 1; - - error = cache_notifier_ref(); + error = netdev_linux_common_construct(netdev); if (error) { goto error; } @@ -654,8 +657,6 @@ netdev_linux_create_tap(const struct netdev_class *class OVS_UNUSED, goto error_close; } - netdev_init(&netdev->up, name, &netdev_tap_class); - *netdevp = &netdev->up; return 0; error_close: @@ -663,12 +664,11 @@ error_close: error_unref_notifier: cache_notifier_unref(); error: - free(netdev); return error; } static void -netdev_linux_destroy(struct netdev *netdev_) +netdev_linux_destruct(struct netdev *netdev_) { struct netdev_linux *netdev = netdev_linux_cast(netdev_); @@ -681,22 +681,35 @@ netdev_linux_destroy(struct netdev *netdev_) { close(netdev->tap_fd); } - free(netdev); cache_notifier_unref(); } +static void +netdev_linux_dealloc(struct netdev *netdev_) +{ + struct netdev_linux *netdev = netdev_linux_cast(netdev_); + free(netdev); +} + +static struct netdev_rx * +netdev_linux_rx_alloc(void) +{ + struct netdev_rx_linux *rx = xzalloc(sizeof *rx); + return &rx->up; +} + static int -netdev_linux_rx_open(struct netdev *netdev_, struct netdev_rx **rxp) +netdev_linux_rx_construct(struct netdev_rx *rx_) { + struct netdev_rx_linux *rx = netdev_rx_linux_cast(rx_); + struct netdev *netdev_ = rx->up.netdev; struct netdev_linux *netdev = netdev_linux_cast(netdev_); - bool is_tap = is_tap_netdev(netdev_); - struct netdev_rx_linux *rx; int error; - int fd; - if (is_tap) { - fd = netdev->tap_fd; + rx->is_tap = is_tap_netdev(netdev_); + if (rx->is_tap) { + rx->fd = netdev->tap_fd; } else { struct sockaddr_ll sll; int ifindex; @@ -712,15 +725,15 @@ netdev_linux_rx_open(struct netdev *netdev_, struct netdev_rx **rxp) }; /* Create file descriptor. */ - fd = socket(PF_PACKET, SOCK_RAW, 0); - if (fd < 0) { + rx->fd = socket(PF_PACKET, SOCK_RAW, 0); + if (rx->fd < 0) { error = errno; VLOG_ERR("failed to create raw socket (%s)", ovs_strerror(error)); goto error; } /* Set non-blocking mode. */ - error = set_nonblocking(fd); + error = set_nonblocking(rx->fd); if (error) { goto error; } @@ -736,7 +749,7 @@ netdev_linux_rx_open(struct netdev *netdev_, struct netdev_rx **rxp) sll.sll_family = AF_PACKET; sll.sll_ifindex = ifindex; sll.sll_protocol = (OVS_FORCE unsigned short int) htons(ETH_P_ALL); - if (bind(fd, (struct sockaddr *) &sll, sizeof sll) < 0) { + if (bind(rx->fd, (struct sockaddr *) &sll, sizeof sll) < 0) { error = errno; VLOG_ERR("%s: failed to bind raw socket (%s)", netdev_get_name(netdev_), ovs_strerror(error)); @@ -744,7 +757,7 @@ netdev_linux_rx_open(struct netdev *netdev_, struct netdev_rx **rxp) } /* Filter for only inbound packets. */ - error = setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &fprog, + error = setsockopt(rx->fd, SOL_SOCKET, SO_ATTACH_FILTER, &fprog, sizeof fprog); if (error) { error = errno; @@ -754,34 +767,35 @@ netdev_linux_rx_open(struct netdev *netdev_, struct netdev_rx **rxp) } } - rx = xmalloc(sizeof *rx); - netdev_rx_init(&rx->up, netdev_, &netdev_rx_linux_class); - rx->is_tap = is_tap; - rx->fd = fd; - - *rxp = &rx->up; return 0; error: - if (fd >= 0) { - close(fd); + if (rx->fd >= 0) { + close(rx->fd); } return error; } static void -netdev_rx_linux_destroy(struct netdev_rx *rx_) +netdev_linux_rx_destruct(struct netdev_rx *rx_) { struct netdev_rx_linux *rx = netdev_rx_linux_cast(rx_); if (!rx->is_tap) { close(rx->fd); } +} + +static void +netdev_linux_rx_dealloc(struct netdev_rx *rx_) +{ + struct netdev_rx_linux *rx = netdev_rx_linux_cast(rx_); + free(rx); } static int -netdev_rx_linux_recv(struct netdev_rx *rx_, void *data, size_t size) +netdev_linux_rx_recv(struct netdev_rx *rx_, void *data, size_t size) { struct netdev_rx_linux *rx = netdev_rx_linux_cast(rx_); ssize_t retval; @@ -804,14 +818,14 @@ netdev_rx_linux_recv(struct netdev_rx *rx_, void *data, size_t size) } static void -netdev_rx_linux_wait(struct netdev_rx *rx_) +netdev_linux_rx_wait(struct netdev_rx *rx_) { struct netdev_rx_linux *rx = netdev_rx_linux_cast(rx_); poll_fd_wait(rx->fd, POLLIN); } static int -netdev_rx_linux_drain(struct netdev_rx *rx_) +netdev_linux_rx_drain(struct netdev_rx *rx_) { struct netdev_rx_linux *rx = netdev_rx_linux_cast(rx_); if (rx->is_tap) { @@ -2379,7 +2393,7 @@ netdev_linux_change_seq(const struct netdev *netdev) return netdev_linux_cast(netdev)->change_seq; } -#define NETDEV_LINUX_CLASS(NAME, CREATE, GET_STATS, SET_STATS, \ +#define NETDEV_LINUX_CLASS(NAME, CONSTRUCT, GET_STATS, SET_STATS, \ GET_FEATURES, GET_STATUS) \ { \ NAME, \ @@ -2388,14 +2402,14 @@ netdev_linux_change_seq(const struct netdev *netdev) netdev_linux_run, \ netdev_linux_wait, \ \ - CREATE, \ - netdev_linux_destroy, \ + netdev_linux_alloc, \ + CONSTRUCT, \ + netdev_linux_destruct, \ + netdev_linux_dealloc, \ NULL, /* get_config */ \ NULL, /* set_config */ \ NULL, /* get_tunnel_config */ \ \ - netdev_linux_rx_open, \ - \ netdev_linux_send, \ netdev_linux_send_wait, \ \ @@ -2435,13 +2449,21 @@ netdev_linux_change_seq(const struct netdev *netdev) \ netdev_linux_update_flags, \ \ - netdev_linux_change_seq \ + netdev_linux_change_seq, \ + \ + netdev_linux_rx_alloc, \ + netdev_linux_rx_construct, \ + netdev_linux_rx_destruct, \ + netdev_linux_rx_dealloc, \ + netdev_linux_rx_recv, \ + netdev_linux_rx_wait, \ + netdev_linux_rx_drain, \ } const struct netdev_class netdev_linux_class = NETDEV_LINUX_CLASS( "system", - netdev_linux_create, + netdev_linux_construct, netdev_linux_get_stats, NULL, /* set_stats */ netdev_linux_get_features, @@ -2450,7 +2472,7 @@ const struct netdev_class netdev_linux_class = const struct netdev_class netdev_tap_class = NETDEV_LINUX_CLASS( "tap", - netdev_linux_create_tap, + netdev_linux_construct_tap, netdev_tap_get_stats, NULL, /* set_stats */ netdev_linux_get_features, @@ -2459,18 +2481,11 @@ const struct netdev_class netdev_tap_class = const struct netdev_class netdev_internal_class = NETDEV_LINUX_CLASS( "internal", - netdev_linux_create, + netdev_linux_construct, netdev_internal_get_stats, netdev_internal_set_stats, NULL, /* get_features */ netdev_internal_get_status); - -static const struct netdev_rx_class netdev_rx_linux_class = { - netdev_rx_linux_destroy, - netdev_rx_linux_recv, - netdev_rx_linux_wait, - netdev_rx_linux_drain, -}; /* HTB traffic control class. */ diff --git a/lib/netdev-provider.h b/lib/netdev-provider.h index b705f8998..9457c171b 100644 --- a/lib/netdev-provider.h +++ b/lib/netdev-provider.h @@ -30,7 +30,8 @@ extern "C" { /* A network device (e.g. an Ethernet device). * - * Network device implementations should treat this structure as opaque. */ + * Network device implementations may read these members but should not modify + * them. */ struct netdev { char *name; /* Name of network device. */ const struct netdev_class *netdev_class; /* Functions to control @@ -40,9 +41,6 @@ struct netdev { struct list saved_flags_list; /* Contains "struct netdev_saved_flags". */ }; -void netdev_init(struct netdev *, const char *name, - const struct netdev_class *); -void netdev_uninit(struct netdev *, bool destroy); const char *netdev_get_type(const struct netdev *); const struct netdev_class *netdev_get_class(const struct netdev *); const char *netdev_get_name(const struct netdev *); @@ -50,11 +48,104 @@ struct netdev *netdev_from_name(const char *name); void netdev_get_devices(const struct netdev_class *, struct shash *device_list); +/* A data structure for capturing packets received by a network device. + * + * Network device implementations may read these members but should not modify + * them. + * + * None of these members change during the lifetime of a struct netdev_rx. */ +struct netdev_rx { + struct netdev *netdev; /* Owns a reference to the netdev. */ +}; + +struct netdev *netdev_rx_get_netdev(const struct netdev_rx *); + /* Network device class structure, to be defined by each implementation of a * network device. * * These functions return 0 if successful or a positive errno value on failure, - * except where otherwise noted. */ + * except where otherwise noted. + * + * + * Data Structures + * =============== + * + * These functions work primarily with two different kinds of data structures: + * + * - "struct netdev", which represents a network device. + * + * - "struct netdev_rx", which represents a handle for capturing packets + * received on a network device + * + * Each of these data structures contains all of the implementation-independent + * generic state for the respective concept, called the "base" state. None of + * them contains any extra space for implementations to use. Instead, each + * implementation is expected to declare its own data structure that contains + * an instance of the generic data structure plus additional + * implementation-specific members, called the "derived" state. The + * implementation can use casts or (preferably) the CONTAINER_OF macro to + * obtain access to derived state given only a pointer to the embedded generic + * data structure. + * + * + * Life Cycle + * ========== + * + * Four stylized functions accompany each of these data structures: + * + * "alloc" "construct" "destruct" "dealloc" + * ------------ ---------------- --------------- -------------- + * netdev ->alloc ->construct ->destruct ->dealloc + * netdev_rx ->rx_alloc ->rx_construct ->rx_destruct ->rx_dealloc + * + * Any instance of a given data structure goes through the following life + * cycle: + * + * 1. The client calls the "alloc" function to obtain raw memory. If "alloc" + * fails, skip all the other steps. + * + * 2. The client initializes all of the data structure's base state. If this + * fails, skip to step 7. + * + * 3. The client calls the "construct" function. The implementation + * initializes derived state. It may refer to the already-initialized + * base state. If "construct" fails, skip to step 6. + * + * 4. The data structure is now initialized and in use. + * + * 5. When the data structure is no longer needed, the client calls the + * "destruct" function. The implementation uninitializes derived state. + * The base state has not been uninitialized yet, so the implementation + * may still refer to it. + * + * 6. The client uninitializes all of the data structure's base state. + * + * 7. The client calls the "dealloc" to free the raw memory. The + * implementation must not refer to base or derived state in the data + * structure, because it has already been uninitialized. + * + * Each "alloc" function allocates and returns a new instance of the respective + * data structure. The "alloc" function is not given any information about the + * use of the new data structure, so it cannot perform much initialization. + * Its purpose is just to ensure that the new data structure has enough room + * for base and derived state. It may return a null pointer if memory is not + * available, in which case none of the other functions is called. + * + * Each "construct" function initializes derived state in its respective data + * structure. When "construct" is called, all of the base state has already + * been initialized, so the "construct" function may refer to it. The + * "construct" function is allowed to fail, in which case the client calls the + * "dealloc" function (but not the "destruct" function). + * + * Each "destruct" function uninitializes and frees derived state in its + * respective data structure. When "destruct" is called, the base state has + * not yet been uninitialized, so the "destruct" function may refer to it. The + * "destruct" function is not allowed to fail. + * + * Each "dealloc" function frees raw memory that was allocated by the the + * "alloc" function. The memory's base and derived members might not have ever + * been initialized (but if "construct" returned successfully, then it has been + * "destruct"ed already). The "dealloc" function is not allowed to fail. */ struct netdev_class { /* Type of netdevs in this class, e.g. "system", "tap", "gre", etc. * @@ -64,6 +155,10 @@ struct netdev_class { * the system. */ const char *type; +/* ## ------------------- ## */ +/* ## Top-Level Functions ## */ +/* ## ------------------- ## */ + /* Called when the netdev provider is registered, typically at program * startup. Returning an error from this function will prevent any network * device in this class from being opened. @@ -83,18 +178,16 @@ struct netdev_class { * needed here. */ void (*wait)(void); - /* Attempts to create a network device named 'name' in 'netdev_class'. On - * success sets 'netdevp' to the newly created device. */ - int (*create)(const struct netdev_class *netdev_class, const char *name, - struct netdev **netdevp); +/* ## ---------------- ## */ +/* ## netdev Functions ## */ +/* ## ---------------- ## */ - /* Destroys 'netdev'. - * - * Netdev devices maintain a reference count that is incremented on - * netdev_open() and decremented on netdev_close(). If 'netdev' - * has a non-zero reference count, then this function will not be - * called. */ - void (*destroy)(struct netdev *netdev); + /* Life-cycle functions for a netdev. See the large comment above on + * struct netdev_class. */ + struct netdev *(*alloc)(void); + int (*construct)(struct netdev *); + void (*destruct)(struct netdev *); + void (*dealloc)(struct netdev *); /* Fetches the device 'netdev''s configuration, storing it in 'args'. * The caller owns 'args' and pre-initializes it to an empty smap. @@ -116,18 +209,6 @@ struct netdev_class { const struct netdev_tunnel_config * (*get_tunnel_config)(const struct netdev *netdev); - /* Attempts to open a netdev_rx for receiving packets from 'netdev'. - * Returns 0 if successful, otherwise a positive errno value. Returns - * EOPNOTSUPP to indicate that the network device does not implement packet - * reception through this interface. This function may be set to null if - * it would always return EOPNOTSUPP anyhow. (This will prevent the - * network device from being usefully used by the netdev-based "userspace - * datapath".) - * - * On success, the implementation must set '*rxp' to a 'netdev_rx' for - * 'netdev' that it has already initialized (with netdev_rx_init()). */ - int (*rx_open)(struct netdev *netdev, struct netdev_rx **rxp); - /* Sends the 'size'-byte packet in 'buffer' on 'netdev'. Returns 0 if * successful, otherwise a positive errno value. Returns EAGAIN without * blocking if the packet cannot be queued immediately. Returns EMSGSIZE @@ -518,25 +599,20 @@ struct netdev_class { * returned sequence number is allowed to change even when 'netdev' doesn't * change, although implementations should try to avoid this. */ unsigned int (*change_seq)(const struct netdev *netdev); -}; - -/* A data structure for capturing packets received by a network device. - * - * This structure should be treated as opaque by network device - * implementations. */ -struct netdev_rx { - const struct netdev_rx_class *rx_class; - struct netdev *netdev; -}; -void netdev_rx_init(struct netdev_rx *, struct netdev *, - const struct netdev_rx_class *); -void netdev_rx_uninit(struct netdev_rx *); -struct netdev *netdev_rx_get_netdev(const struct netdev_rx *); +/* ## ------------------- ## */ +/* ## netdev_rx Functions ## */ +/* ## ------------------- ## */ + +/* If a particular netdev class does not support receiving packets, all these + * function pointers must be NULL. */ -struct netdev_rx_class { - /* Destroys 'rx'. */ - void (*destroy)(struct netdev_rx *rx); + /* Life-cycle functions for a netdev_rx. See the large comment above on + * struct netdev_class. */ + struct netdev_rx *(*rx_alloc)(void); + int (*rx_construct)(struct netdev_rx *); + void (*rx_destruct)(struct netdev_rx *); + void (*rx_dealloc)(struct netdev_rx *); /* Attempts to receive a packet from 'rx' into the 'size' bytes in * 'buffer'. If successful, returns the number of bytes in the received @@ -544,24 +620,20 @@ struct netdev_rx_class { * if no packet is ready to be received. * * Must return -EMSGSIZE, and discard the packet, if the received packet - * is longer than 'size' bytes. */ - int (*recv)(struct netdev_rx *rx, void *buffer, size_t size); + * is longer than 'size' bytes. + * + * Specify NULL if this */ + int (*rx_recv)(struct netdev_rx *rx, void *buffer, size_t size); /* Registers with the poll loop to wake up from the next call to * poll_block() when a packet is ready to be received with netdev_rx_recv() * on 'rx'. */ - void (*wait)(struct netdev_rx *rx); + void (*rx_wait)(struct netdev_rx *rx); /* Discards all packets waiting to be received from 'rx'. */ - int (*drain)(struct netdev_rx *rx); + int (*rx_drain)(struct netdev_rx *rx); }; -static inline void netdev_rx_assert_class(const struct netdev_rx *rx, - const struct netdev_rx_class *class_) -{ - ovs_assert(rx->rx_class == class_); -} - int netdev_register_provider(const struct netdev_class *); int netdev_unregister_provider(const char *type); const struct netdev_class *netdev_lookup_provider(const char *type); diff --git a/lib/netdev-vport.c b/lib/netdev-vport.c index 14b33475b..ac3da6345 100644 --- a/lib/netdev-vport.c +++ b/lib/netdev-vport.c @@ -64,8 +64,7 @@ struct vport_class { struct netdev_class netdev_class; }; -static int netdev_vport_create(const struct netdev_class *, const char *, - struct netdev **); +static int netdev_vport_construct(struct netdev *); static int get_patch_config(const struct netdev *, struct smap *args); static int get_tunnel_config(const struct netdev *, struct smap *args); static void netdev_vport_poll_notify(struct netdev_vport *); @@ -73,7 +72,7 @@ static void netdev_vport_poll_notify(struct netdev_vport *); static bool is_vport_class(const struct netdev_class *class) { - return class->create == netdev_vport_create; + return class->construct == netdev_vport_construct; } static const struct vport_class * @@ -155,30 +154,39 @@ netdev_vport_get_dpif_port_strdup(const struct netdev *netdev) sizeof namebuf)); } +static struct netdev * +netdev_vport_alloc(void) +{ + struct netdev_vport *netdev = xzalloc(sizeof *netdev); + return &netdev->up; +} + static int -netdev_vport_create(const struct netdev_class *netdev_class, const char *name, - struct netdev **netdevp) +netdev_vport_construct(struct netdev *netdev_) { - struct netdev_vport *dev; + struct netdev_vport *netdev = netdev_vport_cast(netdev_); - dev = xzalloc(sizeof *dev); - netdev_init(&dev->up, name, netdev_class); - dev->change_seq = 1; - eth_addr_random(dev->etheraddr); + netdev->change_seq = 1; + eth_addr_random(netdev->etheraddr); - *netdevp = &dev->up; route_table_register(); return 0; } static void -netdev_vport_destroy(struct netdev *netdev_) +netdev_vport_destruct(struct netdev *netdev_) { struct netdev_vport *netdev = netdev_vport_cast(netdev_); route_table_unregister(); free(netdev->peer); +} + +static void +netdev_vport_dealloc(struct netdev *netdev_) +{ + struct netdev_vport *netdev = netdev_vport_cast(netdev_); free(netdev); } @@ -629,14 +637,14 @@ get_stats(const struct netdev *netdev, struct netdev_stats *stats) netdev_vport_run, \ netdev_vport_wait, \ \ - netdev_vport_create, \ - netdev_vport_destroy, \ + netdev_vport_alloc, \ + netdev_vport_construct, \ + netdev_vport_destruct, \ + netdev_vport_dealloc, \ GET_CONFIG, \ SET_CONFIG, \ GET_TUNNEL_CONFIG, \ \ - NULL, /* rx_open */ \ - \ NULL, /* send */ \ NULL, /* send_wait */ \ \ @@ -676,7 +684,15 @@ get_stats(const struct netdev *netdev, struct netdev_stats *stats) \ netdev_vport_update_flags, \ \ - netdev_vport_change_seq + netdev_vport_change_seq, \ + \ + NULL, /* rx_alloc */ \ + NULL, /* rx_construct */ \ + NULL, /* rx_destruct */ \ + NULL, /* rx_dealloc */ \ + NULL, /* rx_recv */ \ + NULL, /* rx_wait */ \ + NULL, /* rx_drain */ #define TUNNEL_CLASS(NAME, DPIF_PORT) \ { DPIF_PORT, \ diff --git a/lib/netdev.c b/lib/netdev.c index d5a51fa0e..5f4345aff 100644 --- a/lib/netdev.c +++ b/lib/netdev.c @@ -253,7 +253,6 @@ netdev_open(const char *name, const char *type, struct netdev **netdevp) struct netdev *netdev; int error; - *netdevp = NULL; netdev_initialize(); netdev = shash_find_data(&netdev_shash, name); @@ -261,22 +260,38 @@ netdev_open(const char *name, const char *type, struct netdev **netdevp) const struct netdev_class *class; class = netdev_lookup_provider(type); - if (!class) { + if (class) { + netdev = class->alloc(); + if (netdev) { + memset(netdev, 0, sizeof *netdev); + netdev->netdev_class = class; + netdev->name = xstrdup(name); + netdev->node = shash_add(&netdev_shash, name, netdev); + list_init(&netdev->saved_flags_list); + + error = class->construct(netdev); + if (error) { + class->dealloc(netdev); + } + } else { + error = ENOMEM; + } + } else { VLOG_WARN("could not create netdev %s of unknown type %s", name, type); - return EAFNOSUPPORT; - } - error = class->create(class, name, &netdev); - if (error) { - return error; + error = EAFNOSUPPORT; } - ovs_assert(netdev->netdev_class == class); - + } else { + error = 0; } - netdev->ref_cnt++; - *netdevp = netdev; - return 0; + if (!error) { + netdev->ref_cnt++; + *netdevp = netdev; + } else { + *netdevp = NULL; + } + return error; } /* Returns a reference to 'netdev_' for the caller to own. Returns null if @@ -350,7 +365,11 @@ netdev_unref(struct netdev *dev) { ovs_assert(dev->ref_cnt); if (!--dev->ref_cnt) { - netdev_uninit(dev, true); + dev->netdev_class->destruct(dev); + + shash_delete(&netdev_shash, dev->node); + free(dev->name); + dev->netdev_class->dealloc(dev); } } @@ -387,15 +406,25 @@ netdev_rx_open(struct netdev *netdev, struct netdev_rx **rxp) { int error; - error = (netdev->netdev_class->rx_open - ? netdev->netdev_class->rx_open(netdev, rxp) - : EOPNOTSUPP); - if (!error) { - ovs_assert((*rxp)->netdev == netdev); - netdev->ref_cnt++; + if (netdev->netdev_class->rx_alloc) { + struct netdev_rx *rx = netdev->netdev_class->rx_alloc(); + if (rx) { + rx->netdev = netdev; + error = netdev->netdev_class->rx_construct(rx); + if (!error) { + netdev->ref_cnt++; + *rxp = rx; + return 0; + } + netdev->netdev_class->rx_dealloc(rx); + } else { + error = ENOMEM; + } } else { - *rxp = NULL; + error = EOPNOTSUPP; } + + *rxp = NULL; return error; } @@ -403,10 +432,10 @@ void netdev_rx_close(struct netdev_rx *rx) { if (rx) { - struct netdev *dev = rx->netdev; - - rx->rx_class->destroy(rx); - netdev_unref(dev); + struct netdev *netdev = rx->netdev; + netdev->netdev_class->rx_destruct(rx); + netdev->netdev_class->rx_dealloc(rx); + netdev_close(netdev); } } @@ -418,7 +447,8 @@ netdev_rx_recv(struct netdev_rx *rx, struct ofpbuf *buffer) ovs_assert(buffer->size == 0); ovs_assert(ofpbuf_tailroom(buffer) >= ETH_TOTAL_MIN); - retval = rx->rx_class->recv(rx, buffer->data, ofpbuf_tailroom(buffer)); + retval = rx->netdev->netdev_class->rx_recv(rx, buffer->data, + ofpbuf_tailroom(buffer)); if (retval >= 0) { COVERAGE_INC(netdev_received); buffer->size += retval; @@ -434,13 +464,15 @@ netdev_rx_recv(struct netdev_rx *rx, struct ofpbuf *buffer) void netdev_rx_wait(struct netdev_rx *rx) { - rx->rx_class->wait(rx); + rx->netdev->netdev_class->rx_wait(rx); } int netdev_rx_drain(struct netdev_rx *rx) { - return rx->rx_class->drain ? rx->rx_class->drain(rx) : 0; + return (rx->netdev->netdev_class->rx_drain + ? rx->netdev->netdev_class->rx_drain(rx) + : 0); } /* Sends 'buffer' on 'netdev'. Returns 0 if successful, otherwise a positive @@ -1328,48 +1360,6 @@ netdev_change_seq(const struct netdev *netdev) return netdev->netdev_class->change_seq(netdev); } -/* Initializes 'netdev' as a netdev device named 'name' of the specified - * 'netdev_class'. This function is ordinarily called from a netdev provider's - * 'create' function. - * - * This function adds 'netdev' to a netdev-owned shash, so it is very important - * that 'netdev' only be freed after calling netdev_uninit(). */ -void -netdev_init(struct netdev *netdev, const char *name, - const struct netdev_class *netdev_class) -{ - ovs_assert(!shash_find(&netdev_shash, name)); - - memset(netdev, 0, sizeof *netdev); - netdev->netdev_class = netdev_class; - netdev->name = xstrdup(name); - netdev->node = shash_add(&netdev_shash, name, netdev); - list_init(&netdev->saved_flags_list); -} - -/* Undoes the results of initialization. - * - * Normally this function does not need to be called as netdev_close has - * the same effect when the refcount drops to zero. - * However, it may be called by providers due to an error on creation - * that occurs after initialization. It this case netdev_close() would - * never be called. */ -void -netdev_uninit(struct netdev *netdev, bool destroy) -{ - char *name = netdev->name; - - ovs_assert(!netdev->ref_cnt); - ovs_assert(list_is_empty(&netdev->saved_flags_list)); - - shash_delete(&netdev_shash, netdev->node); - - if (destroy) { - netdev->netdev_class->destroy(netdev); - } - free(name); -} - /* Returns the class type of 'netdev'. * * The caller must not free the returned value. */ @@ -1430,21 +1420,6 @@ netdev_get_type_from_name(const char *name) return type; } -void -netdev_rx_init(struct netdev_rx *rx, struct netdev *netdev, - const struct netdev_rx_class *class) -{ - ovs_assert(netdev->ref_cnt > 0); - rx->rx_class = class; - rx->netdev = netdev; -} - -void -netdev_rx_uninit(struct netdev_rx *rx OVS_UNUSED) -{ - /* Nothing to do. */ -} - struct netdev * netdev_rx_get_netdev(const struct netdev_rx *rx) {