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>
int fd;
};
-static const struct netdev_rx_class netdev_rx_bsd_class;
-
struct netdev_bsd {
struct netdev up;
unsigned int cache_valid;
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);
}
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;
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;
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
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_);
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);
}
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;
}
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);
}
}
}
-
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_);
* 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_);
/* 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_);
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,
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 = {
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,
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
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 *);
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 *
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);
}
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;
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;
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);
}
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;
}
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)) {
}
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);
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 */
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 *
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);
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
}
}
+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
}
}
- *netdevp = &netdev->up;
return 0;
}
* 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;
}
goto error_close;
}
- netdev_init(&netdev->up, name, &netdev_tap_class);
- *netdevp = &netdev->up;
return 0;
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_);
{
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;
};
/* 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;
}
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));
}
/* 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;
}
}
- 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;
}
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) {
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, \
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, \
\
\
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,
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,
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. */
/* 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
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 *);
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.
*
* 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.
* 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.
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
* 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
* 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);
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 *);
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 *
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);
}
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 */ \
\
\
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, \
struct netdev *netdev;
int error;
- *netdevp = NULL;
netdev_initialize();
netdev = shash_find_data(&netdev_shash, name);
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
{
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);
}
}
{
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;
}
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);
}
}
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;
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
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. */
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)
{