netdev: Adopt four-step alloc/construct/destruct/dealloc lifecycle.
authorBen Pfaff <blp@nicira.com>
Sat, 10 Aug 2013 04:21:38 +0000 (21:21 -0700)
committerBen Pfaff <blp@nicira.com>
Sat, 10 Aug 2013 04:21:38 +0000 (21:21 -0700)
This is the same lifecycle used in the ofproto provider interface.
Compared to the previous netdev provider interface, it has the
advantage that the netdev top layer can control when any given
netdev becomes visible to the outside world.

Signed-off-by: Ben Pfaff <blp@nicira.com>
lib/netdev-bsd.c
lib/netdev-dummy.c
lib/netdev-linux.c
lib/netdev-provider.h
lib/netdev-vport.c
lib/netdev.c

index 67c0c18..0f625af 100644 (file)
@@ -74,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;
@@ -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);
 }
 
@@ -269,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;
 
@@ -283,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;
@@ -320,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
@@ -376,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_);
 
@@ -406,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);
 }
 
@@ -478,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;
         }
@@ -500,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);
 }
 
@@ -615,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_);
 
@@ -631,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_);
 
@@ -640,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_);
@@ -1379,14 +1378,14 @@ const struct netdev_class netdev_bsd_class = {
     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,
 
@@ -1425,7 +1424,15 @@ 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 = {
@@ -1434,14 +1441,14 @@ const struct netdev_class netdev_tap_class = {
     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,
 
@@ -1480,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,
 };
 \f
 
index dc3ddf8..0560ade 100644 (file)
@@ -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 *
index 9306100..cf45905 100644 (file)
@@ -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);
 }
 \f
@@ -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,
-};
 \f
 /* HTB traffic control class. */
 
index 19230a1..05cf24f 100644 (file)
@@ -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);
-};
-\f
-/* 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);
index 14b3347..ac3da63 100644 (file)
@@ -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,                                            \
index 30c44a2..9cb4a88 100644 (file)
@@ -251,7 +251,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);
@@ -259,22 +258,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
@@ -348,7 +363,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);
     }
 }
 
@@ -385,15 +404,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;
 }
 
@@ -401,10 +430,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);
     }
 }
 
@@ -416,7 +445,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;
@@ -432,13 +462,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
@@ -1326,48 +1358,6 @@ netdev_change_seq(const struct netdev *netdev)
     return netdev->netdev_class->change_seq(netdev);
 }
 \f
-/* 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. */
@@ -1428,21 +1418,6 @@ netdev_get_type_from_name(const char *name)
     return type;
 }
 \f
-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)
 {