Merge commit '9dc63482bbeae23dd57b0f885a3fd26b44656844'
authorGiuseppe Lettieri <g.lettieri@iet.unipi.it>
Thu, 15 Aug 2013 17:35:59 +0000 (19:35 +0200)
committerGiuseppe Lettieri <g.lettieri@iet.unipi.it>
Thu, 15 Aug 2013 17:35:59 +0000 (19:35 +0200)
lib/netdev-bsd.c
lib/netdev-dummy.c
lib/netdev-linux.c
lib/netdev-provider.h
lib/netdev-vport.c
lib/netdev.c

index b799cb5..0f625af 100644 (file)
@@ -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,
 };
 \f
 
@@ -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);
+}
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 b705f89..9457c17 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 d5a51fa..5f4345a 100644 (file)
@@ -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);
 }
 \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. */
@@ -1430,21 +1420,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)
 {