mirror of
https://github.com/openvswitch/ovs
synced 2025-09-01 06:45:17 +00:00
netdev: Adopt four-step alloc/construct/destruct/dealloc lifecycle.
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>
This commit is contained in:
140
lib/netdev-bsd.c
140
lib/netdev-bsd.c
@@ -74,8 +74,6 @@ struct netdev_rx_bsd {
|
|||||||
int fd;
|
int fd;
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct netdev_rx_class netdev_rx_bsd_class;
|
|
||||||
|
|
||||||
struct netdev_bsd {
|
struct netdev_bsd {
|
||||||
struct netdev up;
|
struct netdev up;
|
||||||
unsigned int cache_valid;
|
unsigned int cache_valid;
|
||||||
@@ -162,7 +160,7 @@ netdev_bsd_cast(const struct netdev *netdev)
|
|||||||
static struct netdev_rx_bsd *
|
static struct netdev_rx_bsd *
|
||||||
netdev_rx_bsd_cast(const struct netdev_rx *rx)
|
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 CONTAINER_OF(rx, struct netdev_rx_bsd, up);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -269,12 +267,17 @@ cache_notifier_unref(void)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Allocate a netdev_bsd structure */
|
static struct netdev *
|
||||||
static int
|
netdev_bsd_alloc(void)
|
||||||
netdev_bsd_create_system(const struct netdev_class *class, const char *name,
|
|
||||||
struct netdev **netdevp)
|
|
||||||
{
|
{
|
||||||
struct netdev_bsd *netdev;
|
struct netdev_bsd *netdev = xzalloc(sizeof *netdev);
|
||||||
|
return &netdev->up;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
netdev_bsd_construct_system(struct netdev *netdev_)
|
||||||
|
{
|
||||||
|
struct netdev_bsd *netdev = netdev_bsd_cast(netdev_);
|
||||||
enum netdev_flags flags;
|
enum netdev_flags flags;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
@@ -283,34 +286,26 @@ netdev_bsd_create_system(const struct netdev_class *class, const char *name,
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
netdev = xzalloc(sizeof *netdev);
|
|
||||||
netdev->change_seq = 1;
|
netdev->change_seq = 1;
|
||||||
netdev_init(&netdev->up, name, class);
|
|
||||||
netdev->tap_fd = -1;
|
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 */
|
/* 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) {
|
if (error == ENXIO) {
|
||||||
free(netdev->kernel_name);
|
free(netdev->kernel_name);
|
||||||
netdev_uninit(&netdev->up, false);
|
|
||||||
free(netdev);
|
|
||||||
cache_notifier_unref();
|
cache_notifier_unref();
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
*netdevp = &netdev->up;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Allocate a netdev_bsd structure with 'tap' class.
|
|
||||||
*/
|
|
||||||
static int
|
static int
|
||||||
netdev_bsd_create_tap(const struct netdev_class *class, const char *name,
|
netdev_bsd_construct_tap(struct netdev *netdev_)
|
||||||
struct netdev **netdevp)
|
|
||||||
{
|
{
|
||||||
struct netdev_bsd *netdev = NULL;
|
struct netdev_bsd *netdev = netdev_bsd_cast(netdev_);
|
||||||
|
const char *name = netdev_->name;
|
||||||
int error = 0;
|
int error = 0;
|
||||||
struct ifreq ifr;
|
struct ifreq ifr;
|
||||||
char *kernel_name = NULL;
|
char *kernel_name = NULL;
|
||||||
@@ -320,9 +315,6 @@ netdev_bsd_create_tap(const struct netdev_class *class, const char *name,
|
|||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* allocate the device structure and set the internal flag */
|
|
||||||
netdev = xzalloc(sizeof *netdev);
|
|
||||||
|
|
||||||
memset(&ifr, 0, sizeof(ifr));
|
memset(&ifr, 0, sizeof(ifr));
|
||||||
|
|
||||||
/* Create a tap device by opening /dev/tap. The TAPGIFNAME ioctl is used
|
/* 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;
|
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;
|
netdev->kernel_name = kernel_name;
|
||||||
*netdevp = &netdev->up;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
error_unref_notifier:
|
error_unref_notifier:
|
||||||
cache_notifier_unref();
|
cache_notifier_unref();
|
||||||
error:
|
error:
|
||||||
free(netdev);
|
|
||||||
free(kernel_name);
|
free(kernel_name);
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
netdev_bsd_destroy(struct netdev *netdev_)
|
netdev_bsd_destruct(struct netdev *netdev_)
|
||||||
{
|
{
|
||||||
struct netdev_bsd *netdev = netdev_bsd_cast(netdev_);
|
struct netdev_bsd *netdev = netdev_bsd_cast(netdev_);
|
||||||
|
|
||||||
@@ -406,6 +393,13 @@ netdev_bsd_destroy(struct netdev *netdev_)
|
|||||||
pcap_close(netdev->pcap);
|
pcap_close(netdev->pcap);
|
||||||
}
|
}
|
||||||
free(netdev->kernel_name);
|
free(netdev->kernel_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
netdev_bsd_dealloc(struct netdev *netdev_)
|
||||||
|
{
|
||||||
|
struct netdev_bsd *netdev = netdev_bsd_cast(netdev_);
|
||||||
|
|
||||||
free(netdev);
|
free(netdev);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -478,21 +472,26 @@ error:
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static struct netdev_rx *
|
||||||
netdev_bsd_rx_open(struct netdev *netdev_, struct netdev_rx **rxp)
|
netdev_bsd_rx_alloc(void)
|
||||||
{
|
{
|
||||||
|
struct netdev_rx_bsd *rx = xzalloc(sizeof *rx);
|
||||||
|
return &rx->up;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
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_bsd *netdev = netdev_bsd_cast(netdev_);
|
||||||
|
|
||||||
struct netdev_rx_bsd *rx;
|
|
||||||
pcap_t *pcap;
|
|
||||||
int fd;
|
|
||||||
|
|
||||||
if (!strcmp(netdev_get_type(netdev_), "tap")) {
|
if (!strcmp(netdev_get_type(netdev_), "tap")) {
|
||||||
pcap = NULL;
|
rx->pcap_handle = NULL;
|
||||||
fd = netdev->tap_fd;
|
rx->fd = netdev->tap_fd;
|
||||||
} else {
|
} else {
|
||||||
int error = netdev_bsd_open_pcap(netdev_get_kernel_name(netdev_),
|
int error = netdev_bsd_open_pcap(netdev_get_kernel_name(netdev_),
|
||||||
&pcap, &fd);
|
&rx->pcap_handle, &rx->fd);
|
||||||
if (error) {
|
if (error) {
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
@@ -500,23 +499,24 @@ netdev_bsd_rx_open(struct netdev *netdev_, struct netdev_rx **rxp)
|
|||||||
netdev_bsd_changed(netdev);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
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_);
|
struct netdev_rx_bsd *rx = netdev_rx_bsd_cast(rx_);
|
||||||
|
|
||||||
if (rx->pcap_handle) {
|
if (rx->pcap_handle) {
|
||||||
pcap_close(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);
|
free(rx);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -615,9 +615,8 @@ netdev_rx_bsd_recv_tap(struct netdev_rx_bsd *rx, void *data, size_t size)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int
|
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_);
|
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'.
|
* when a packet is ready to be received with netdev_rx_recv() on 'rx'.
|
||||||
*/
|
*/
|
||||||
static void
|
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_);
|
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'. */
|
/* Discards all packets waiting to be received from 'rx'. */
|
||||||
static int
|
static int
|
||||||
netdev_rx_bsd_drain(struct netdev_rx *rx_)
|
netdev_bsd_rx_drain(struct netdev_rx *rx_)
|
||||||
{
|
{
|
||||||
struct ifreq ifr;
|
struct ifreq ifr;
|
||||||
struct netdev_rx_bsd *rx = netdev_rx_bsd_cast(rx_);
|
struct netdev_rx_bsd *rx = netdev_rx_bsd_cast(rx_);
|
||||||
@@ -1379,14 +1378,14 @@ const struct netdev_class netdev_bsd_class = {
|
|||||||
NULL, /* init */
|
NULL, /* init */
|
||||||
netdev_bsd_run,
|
netdev_bsd_run,
|
||||||
netdev_bsd_wait,
|
netdev_bsd_wait,
|
||||||
netdev_bsd_create_system,
|
netdev_bsd_alloc,
|
||||||
netdev_bsd_destroy,
|
netdev_bsd_construct_system,
|
||||||
|
netdev_bsd_destruct,
|
||||||
|
netdev_bsd_dealloc,
|
||||||
NULL, /* get_config */
|
NULL, /* get_config */
|
||||||
NULL, /* set_config */
|
NULL, /* set_config */
|
||||||
NULL, /* get_tunnel_config */
|
NULL, /* get_tunnel_config */
|
||||||
|
|
||||||
netdev_bsd_rx_open,
|
|
||||||
|
|
||||||
netdev_bsd_send,
|
netdev_bsd_send,
|
||||||
netdev_bsd_send_wait,
|
netdev_bsd_send_wait,
|
||||||
|
|
||||||
@@ -1425,7 +1424,15 @@ const struct netdev_class netdev_bsd_class = {
|
|||||||
|
|
||||||
netdev_bsd_update_flags,
|
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 = {
|
const struct netdev_class netdev_tap_class = {
|
||||||
@@ -1434,14 +1441,14 @@ const struct netdev_class netdev_tap_class = {
|
|||||||
NULL, /* init */
|
NULL, /* init */
|
||||||
netdev_bsd_run,
|
netdev_bsd_run,
|
||||||
netdev_bsd_wait,
|
netdev_bsd_wait,
|
||||||
netdev_bsd_create_tap,
|
netdev_bsd_alloc,
|
||||||
netdev_bsd_destroy,
|
netdev_bsd_construct_tap,
|
||||||
|
netdev_bsd_destruct,
|
||||||
|
netdev_bsd_dealloc,
|
||||||
NULL, /* get_config */
|
NULL, /* get_config */
|
||||||
NULL, /* set_config */
|
NULL, /* set_config */
|
||||||
NULL, /* get_tunnel_config */
|
NULL, /* get_tunnel_config */
|
||||||
|
|
||||||
netdev_bsd_rx_open,
|
|
||||||
|
|
||||||
netdev_bsd_send,
|
netdev_bsd_send,
|
||||||
netdev_bsd_send_wait,
|
netdev_bsd_send_wait,
|
||||||
|
|
||||||
@@ -1480,14 +1487,15 @@ const struct netdev_class netdev_tap_class = {
|
|||||||
|
|
||||||
netdev_bsd_update_flags,
|
netdev_bsd_update_flags,
|
||||||
|
|
||||||
netdev_bsd_change_seq
|
netdev_bsd_change_seq,
|
||||||
};
|
|
||||||
|
|
||||||
static const struct netdev_rx_class netdev_rx_bsd_class = {
|
netdev_bsd_rx_alloc,
|
||||||
netdev_rx_bsd_destroy,
|
netdev_bsd_rx_construct,
|
||||||
netdev_rx_bsd_recv,
|
netdev_bsd_rx_destruct,
|
||||||
netdev_rx_bsd_wait,
|
netdev_bsd_rx_dealloc,
|
||||||
netdev_rx_bsd_drain,
|
netdev_bsd_rx_recv,
|
||||||
|
netdev_bsd_rx_wait,
|
||||||
|
netdev_bsd_rx_drain,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@@ -73,11 +73,8 @@ struct netdev_rx_dummy {
|
|||||||
bool listening;
|
bool listening;
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct netdev_rx_class netdev_rx_dummy_class;
|
|
||||||
|
|
||||||
static unixctl_cb_func netdev_dummy_set_admin_state;
|
static unixctl_cb_func netdev_dummy_set_admin_state;
|
||||||
static int netdev_dummy_create(const struct netdev_class *, const char *,
|
static int netdev_dummy_construct(struct netdev *);
|
||||||
struct netdev **);
|
|
||||||
static void netdev_dummy_poll_notify(struct netdev_dummy *);
|
static void netdev_dummy_poll_notify(struct netdev_dummy *);
|
||||||
static void netdev_dummy_queue_packet(struct netdev_dummy *, struct ofpbuf *);
|
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
|
static bool
|
||||||
is_dummy_class(const struct netdev_class *class)
|
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_dummy *
|
||||||
@@ -99,7 +96,7 @@ netdev_dummy_cast(const struct netdev *netdev)
|
|||||||
static struct netdev_rx_dummy *
|
static struct netdev_rx_dummy *
|
||||||
netdev_rx_dummy_cast(const struct netdev_rx *rx)
|
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);
|
return CONTAINER_OF(rx, struct netdev_rx_dummy, up);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -248,17 +245,21 @@ netdev_dummy_wait(void)
|
|||||||
shash_destroy(&dummy_netdevs);
|
shash_destroy(&dummy_netdevs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct netdev *
|
||||||
|
netdev_dummy_alloc(void)
|
||||||
|
{
|
||||||
|
struct netdev_dummy *netdev = xzalloc(sizeof *netdev);
|
||||||
|
return &netdev->up;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
netdev_dummy_create(const struct netdev_class *class, const char *name,
|
netdev_dummy_construct(struct netdev *netdev_)
|
||||||
struct netdev **netdevp)
|
|
||||||
{
|
{
|
||||||
static atomic_uint next_n = ATOMIC_VAR_INIT(0xaa550000);
|
static atomic_uint next_n = ATOMIC_VAR_INIT(0xaa550000);
|
||||||
struct netdev_dummy *netdev;
|
struct netdev_dummy *netdev = netdev_dummy_cast(netdev_);
|
||||||
unsigned int n;
|
unsigned int n;
|
||||||
|
|
||||||
atomic_add(&next_n, 1, &n);
|
atomic_add(&next_n, 1, &n);
|
||||||
netdev = xzalloc(sizeof *netdev);
|
|
||||||
netdev_init(&netdev->up, name, class);
|
|
||||||
netdev->hwaddr[0] = 0xaa;
|
netdev->hwaddr[0] = 0xaa;
|
||||||
netdev->hwaddr[1] = 0x55;
|
netdev->hwaddr[1] = 0x55;
|
||||||
netdev->hwaddr[2] = n >> 24;
|
netdev->hwaddr[2] = n >> 24;
|
||||||
@@ -276,13 +277,11 @@ netdev_dummy_create(const struct netdev_class *class, const char *name,
|
|||||||
|
|
||||||
list_init(&netdev->rxes);
|
list_init(&netdev->rxes);
|
||||||
|
|
||||||
*netdevp = &netdev->up;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
netdev_dummy_destroy(struct netdev *netdev_)
|
netdev_dummy_destruct(struct netdev *netdev_)
|
||||||
{
|
{
|
||||||
struct netdev_dummy *netdev = netdev_dummy_cast(netdev_);
|
struct netdev_dummy *netdev = netdev_dummy_cast(netdev_);
|
||||||
size_t i;
|
size_t i;
|
||||||
@@ -292,6 +291,13 @@ netdev_dummy_destroy(struct netdev *netdev_)
|
|||||||
dummy_stream_close(&netdev->streams[i]);
|
dummy_stream_close(&netdev->streams[i]);
|
||||||
}
|
}
|
||||||
free(netdev->streams);
|
free(netdev->streams);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
netdev_dummy_dealloc(struct netdev *netdev_)
|
||||||
|
{
|
||||||
|
struct netdev_dummy *netdev = netdev_dummy_cast(netdev_);
|
||||||
|
|
||||||
free(netdev);
|
free(netdev);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -337,24 +343,45 @@ netdev_dummy_set_config(struct netdev *netdev_, const struct smap *args)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static struct netdev_rx *
|
||||||
netdev_dummy_rx_open(struct netdev *netdev_, struct netdev_rx **rxp)
|
netdev_dummy_rx_alloc(void)
|
||||||
{
|
{
|
||||||
struct netdev_dummy *netdev = netdev_dummy_cast(netdev_);
|
struct netdev_rx_dummy *rx = xzalloc(sizeof *rx);
|
||||||
struct netdev_rx_dummy *rx;
|
return &rx->up;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
netdev_dummy_rx_construct(struct netdev_rx *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_push_back(&netdev->rxes, &rx->node);
|
||||||
list_init(&rx->recv_queue);
|
list_init(&rx->recv_queue);
|
||||||
rx->recv_queue_len = 0;
|
rx->recv_queue_len = 0;
|
||||||
|
|
||||||
*rxp = &rx->up;
|
|
||||||
return 0;
|
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
|
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 netdev_rx_dummy *rx = netdev_rx_dummy_cast(rx_);
|
||||||
struct ofpbuf *packet;
|
struct ofpbuf *packet;
|
||||||
@@ -378,16 +405,7 @@ netdev_rx_dummy_recv(struct netdev_rx *rx_, void *buffer, size_t size)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
netdev_rx_dummy_destroy(struct netdev_rx *rx_)
|
netdev_dummy_rx_wait(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_)
|
|
||||||
{
|
{
|
||||||
struct netdev_rx_dummy *rx = netdev_rx_dummy_cast(rx_);
|
struct netdev_rx_dummy *rx = netdev_rx_dummy_cast(rx_);
|
||||||
if (!list_is_empty(&rx->recv_queue)) {
|
if (!list_is_empty(&rx->recv_queue)) {
|
||||||
@@ -396,7 +414,7 @@ netdev_rx_dummy_wait(struct netdev_rx *rx_)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
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_);
|
struct netdev_rx_dummy *rx = netdev_rx_dummy_cast(rx_);
|
||||||
ofpbuf_list_delete(&rx->recv_queue);
|
ofpbuf_list_delete(&rx->recv_queue);
|
||||||
@@ -554,14 +572,14 @@ static const struct netdev_class dummy_class = {
|
|||||||
netdev_dummy_run,
|
netdev_dummy_run,
|
||||||
netdev_dummy_wait,
|
netdev_dummy_wait,
|
||||||
|
|
||||||
netdev_dummy_create,
|
netdev_dummy_alloc,
|
||||||
netdev_dummy_destroy,
|
netdev_dummy_construct,
|
||||||
|
netdev_dummy_destruct,
|
||||||
|
netdev_dummy_dealloc,
|
||||||
netdev_dummy_get_config,
|
netdev_dummy_get_config,
|
||||||
netdev_dummy_set_config,
|
netdev_dummy_set_config,
|
||||||
NULL, /* get_tunnel_config */
|
NULL, /* get_tunnel_config */
|
||||||
|
|
||||||
netdev_dummy_rx_open,
|
|
||||||
|
|
||||||
netdev_dummy_send, /* send */
|
netdev_dummy_send, /* send */
|
||||||
NULL, /* send_wait */
|
NULL, /* send_wait */
|
||||||
|
|
||||||
@@ -601,14 +619,15 @@ static const struct netdev_class dummy_class = {
|
|||||||
|
|
||||||
netdev_dummy_update_flags,
|
netdev_dummy_update_flags,
|
||||||
|
|
||||||
netdev_dummy_change_seq
|
netdev_dummy_change_seq,
|
||||||
};
|
|
||||||
|
|
||||||
static const struct netdev_rx_class netdev_rx_dummy_class = {
|
netdev_dummy_rx_alloc,
|
||||||
netdev_rx_dummy_destroy,
|
netdev_dummy_rx_construct,
|
||||||
netdev_rx_dummy_recv,
|
netdev_dummy_rx_destruct,
|
||||||
netdev_rx_dummy_wait,
|
netdev_dummy_rx_dealloc,
|
||||||
netdev_rx_dummy_drain,
|
netdev_dummy_rx_recv,
|
||||||
|
netdev_dummy_rx_wait,
|
||||||
|
netdev_dummy_rx_drain,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct ofpbuf *
|
static struct ofpbuf *
|
||||||
|
@@ -398,8 +398,6 @@ struct netdev_rx_linux {
|
|||||||
int fd;
|
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
|
/* This is set pretty low because we probably won't learn anything from the
|
||||||
* additional log messages. */
|
* additional log messages. */
|
||||||
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 20);
|
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 *
|
static struct netdev_rx_linux *
|
||||||
netdev_rx_linux_cast(const struct netdev_rx *rx)
|
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);
|
return CONTAINER_OF(rx, struct netdev_rx_linux, up);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -571,29 +569,38 @@ cache_notifier_unref(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct netdev *
|
||||||
|
netdev_linux_alloc(void)
|
||||||
|
{
|
||||||
|
struct netdev_linux *netdev = xzalloc(sizeof *netdev);
|
||||||
|
return &netdev->up;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
netdev_linux_common_construct(struct netdev_linux *netdev)
|
||||||
|
{
|
||||||
|
netdev->change_seq = 1;
|
||||||
|
|
||||||
|
return cache_notifier_ref();
|
||||||
|
}
|
||||||
|
|
||||||
/* Creates system and internal devices. */
|
/* Creates system and internal devices. */
|
||||||
static int
|
static int
|
||||||
netdev_linux_create(const struct netdev_class *class, const char *name,
|
netdev_linux_construct(struct netdev *netdev_)
|
||||||
struct netdev **netdevp)
|
|
||||||
{
|
{
|
||||||
struct netdev_linux *netdev;
|
struct netdev_linux *netdev = netdev_linux_cast(netdev_);
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
error = cache_notifier_ref();
|
error = netdev_linux_common_construct(netdev);
|
||||||
if (error) {
|
if (error) {
|
||||||
return 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);
|
error = get_flags(&netdev->up, &netdev->ifi_flags);
|
||||||
if (error == ENODEV) {
|
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. */
|
/* The device does not exist, so don't allow it to be opened. */
|
||||||
netdev_uninit(&netdev->up, false);
|
|
||||||
cache_notifier_unref();
|
cache_notifier_unref();
|
||||||
free(netdev);
|
|
||||||
return ENODEV;
|
return ENODEV;
|
||||||
} else {
|
} else {
|
||||||
/* "Internal" netdevs have to be created as netdev objects before
|
/* "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;
|
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
|
* buffers, across all readers. Therefore once data is read it will
|
||||||
* be unavailable to other reads for tap devices. */
|
* be unavailable to other reads for tap devices. */
|
||||||
static int
|
static int
|
||||||
netdev_linux_create_tap(const struct netdev_class *class OVS_UNUSED,
|
netdev_linux_construct_tap(struct netdev *netdev_)
|
||||||
const char *name, struct netdev **netdevp)
|
|
||||||
{
|
{
|
||||||
struct netdev_linux *netdev;
|
struct netdev_linux *netdev = netdev_linux_cast(netdev_);
|
||||||
static const char tap_dev[] = "/dev/net/tun";
|
static const char tap_dev[] = "/dev/net/tun";
|
||||||
|
const char *name = netdev_->name;
|
||||||
struct ifreq ifr;
|
struct ifreq ifr;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
netdev = xzalloc(sizeof *netdev);
|
error = netdev_linux_common_construct(netdev);
|
||||||
netdev->change_seq = 1;
|
|
||||||
|
|
||||||
error = cache_notifier_ref();
|
|
||||||
if (error) {
|
if (error) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
@@ -654,8 +657,6 @@ netdev_linux_create_tap(const struct netdev_class *class OVS_UNUSED,
|
|||||||
goto error_close;
|
goto error_close;
|
||||||
}
|
}
|
||||||
|
|
||||||
netdev_init(&netdev->up, name, &netdev_tap_class);
|
|
||||||
*netdevp = &netdev->up;
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
error_close:
|
error_close:
|
||||||
@@ -663,12 +664,11 @@ error_close:
|
|||||||
error_unref_notifier:
|
error_unref_notifier:
|
||||||
cache_notifier_unref();
|
cache_notifier_unref();
|
||||||
error:
|
error:
|
||||||
free(netdev);
|
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
netdev_linux_destroy(struct netdev *netdev_)
|
netdev_linux_destruct(struct netdev *netdev_)
|
||||||
{
|
{
|
||||||
struct netdev_linux *netdev = netdev_linux_cast(netdev_);
|
struct netdev_linux *netdev = netdev_linux_cast(netdev_);
|
||||||
|
|
||||||
@@ -681,22 +681,35 @@ netdev_linux_destroy(struct netdev *netdev_)
|
|||||||
{
|
{
|
||||||
close(netdev->tap_fd);
|
close(netdev->tap_fd);
|
||||||
}
|
}
|
||||||
free(netdev);
|
|
||||||
|
|
||||||
cache_notifier_unref();
|
cache_notifier_unref();
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static void
|
||||||
netdev_linux_rx_open(struct netdev *netdev_, struct netdev_rx **rxp)
|
netdev_linux_dealloc(struct netdev *netdev_)
|
||||||
{
|
{
|
||||||
struct netdev_linux *netdev = netdev_linux_cast(netdev_);
|
struct netdev_linux *netdev = netdev_linux_cast(netdev_);
|
||||||
bool is_tap = is_tap_netdev(netdev_);
|
free(netdev);
|
||||||
struct netdev_rx_linux *rx;
|
}
|
||||||
int error;
|
|
||||||
int fd;
|
|
||||||
|
|
||||||
if (is_tap) {
|
static struct netdev_rx *
|
||||||
fd = netdev->tap_fd;
|
netdev_linux_rx_alloc(void)
|
||||||
|
{
|
||||||
|
struct netdev_rx_linux *rx = xzalloc(sizeof *rx);
|
||||||
|
return &rx->up;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
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_);
|
||||||
|
int error;
|
||||||
|
|
||||||
|
rx->is_tap = is_tap_netdev(netdev_);
|
||||||
|
if (rx->is_tap) {
|
||||||
|
rx->fd = netdev->tap_fd;
|
||||||
} else {
|
} else {
|
||||||
struct sockaddr_ll sll;
|
struct sockaddr_ll sll;
|
||||||
int ifindex;
|
int ifindex;
|
||||||
@@ -712,15 +725,15 @@ netdev_linux_rx_open(struct netdev *netdev_, struct netdev_rx **rxp)
|
|||||||
};
|
};
|
||||||
|
|
||||||
/* Create file descriptor. */
|
/* Create file descriptor. */
|
||||||
fd = socket(PF_PACKET, SOCK_RAW, 0);
|
rx->fd = socket(PF_PACKET, SOCK_RAW, 0);
|
||||||
if (fd < 0) {
|
if (rx->fd < 0) {
|
||||||
error = errno;
|
error = errno;
|
||||||
VLOG_ERR("failed to create raw socket (%s)", ovs_strerror(error));
|
VLOG_ERR("failed to create raw socket (%s)", ovs_strerror(error));
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set non-blocking mode. */
|
/* Set non-blocking mode. */
|
||||||
error = set_nonblocking(fd);
|
error = set_nonblocking(rx->fd);
|
||||||
if (error) {
|
if (error) {
|
||||||
goto 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_family = AF_PACKET;
|
||||||
sll.sll_ifindex = ifindex;
|
sll.sll_ifindex = ifindex;
|
||||||
sll.sll_protocol = (OVS_FORCE unsigned short int) htons(ETH_P_ALL);
|
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;
|
error = errno;
|
||||||
VLOG_ERR("%s: failed to bind raw socket (%s)",
|
VLOG_ERR("%s: failed to bind raw socket (%s)",
|
||||||
netdev_get_name(netdev_), ovs_strerror(error));
|
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. */
|
/* 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);
|
sizeof fprog);
|
||||||
if (error) {
|
if (error) {
|
||||||
error = errno;
|
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;
|
return 0;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
if (fd >= 0) {
|
if (rx->fd >= 0) {
|
||||||
close(fd);
|
close(rx->fd);
|
||||||
}
|
}
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
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_);
|
struct netdev_rx_linux *rx = netdev_rx_linux_cast(rx_);
|
||||||
|
|
||||||
if (!rx->is_tap) {
|
if (!rx->is_tap) {
|
||||||
close(rx->fd);
|
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);
|
free(rx);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
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_);
|
struct netdev_rx_linux *rx = netdev_rx_linux_cast(rx_);
|
||||||
ssize_t retval;
|
ssize_t retval;
|
||||||
@@ -804,14 +818,14 @@ netdev_rx_linux_recv(struct netdev_rx *rx_, void *data, size_t size)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
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_);
|
struct netdev_rx_linux *rx = netdev_rx_linux_cast(rx_);
|
||||||
poll_fd_wait(rx->fd, POLLIN);
|
poll_fd_wait(rx->fd, POLLIN);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
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_);
|
struct netdev_rx_linux *rx = netdev_rx_linux_cast(rx_);
|
||||||
if (rx->is_tap) {
|
if (rx->is_tap) {
|
||||||
@@ -2379,7 +2393,7 @@ netdev_linux_change_seq(const struct netdev *netdev)
|
|||||||
return netdev_linux_cast(netdev)->change_seq;
|
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) \
|
GET_FEATURES, GET_STATUS) \
|
||||||
{ \
|
{ \
|
||||||
NAME, \
|
NAME, \
|
||||||
@@ -2388,14 +2402,14 @@ netdev_linux_change_seq(const struct netdev *netdev)
|
|||||||
netdev_linux_run, \
|
netdev_linux_run, \
|
||||||
netdev_linux_wait, \
|
netdev_linux_wait, \
|
||||||
\
|
\
|
||||||
CREATE, \
|
netdev_linux_alloc, \
|
||||||
netdev_linux_destroy, \
|
CONSTRUCT, \
|
||||||
|
netdev_linux_destruct, \
|
||||||
|
netdev_linux_dealloc, \
|
||||||
NULL, /* get_config */ \
|
NULL, /* get_config */ \
|
||||||
NULL, /* set_config */ \
|
NULL, /* set_config */ \
|
||||||
NULL, /* get_tunnel_config */ \
|
NULL, /* get_tunnel_config */ \
|
||||||
\
|
\
|
||||||
netdev_linux_rx_open, \
|
|
||||||
\
|
|
||||||
netdev_linux_send, \
|
netdev_linux_send, \
|
||||||
netdev_linux_send_wait, \
|
netdev_linux_send_wait, \
|
||||||
\
|
\
|
||||||
@@ -2435,13 +2449,21 @@ netdev_linux_change_seq(const struct netdev *netdev)
|
|||||||
\
|
\
|
||||||
netdev_linux_update_flags, \
|
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 =
|
const struct netdev_class netdev_linux_class =
|
||||||
NETDEV_LINUX_CLASS(
|
NETDEV_LINUX_CLASS(
|
||||||
"system",
|
"system",
|
||||||
netdev_linux_create,
|
netdev_linux_construct,
|
||||||
netdev_linux_get_stats,
|
netdev_linux_get_stats,
|
||||||
NULL, /* set_stats */
|
NULL, /* set_stats */
|
||||||
netdev_linux_get_features,
|
netdev_linux_get_features,
|
||||||
@@ -2450,7 +2472,7 @@ const struct netdev_class netdev_linux_class =
|
|||||||
const struct netdev_class netdev_tap_class =
|
const struct netdev_class netdev_tap_class =
|
||||||
NETDEV_LINUX_CLASS(
|
NETDEV_LINUX_CLASS(
|
||||||
"tap",
|
"tap",
|
||||||
netdev_linux_create_tap,
|
netdev_linux_construct_tap,
|
||||||
netdev_tap_get_stats,
|
netdev_tap_get_stats,
|
||||||
NULL, /* set_stats */
|
NULL, /* set_stats */
|
||||||
netdev_linux_get_features,
|
netdev_linux_get_features,
|
||||||
@@ -2459,18 +2481,11 @@ const struct netdev_class netdev_tap_class =
|
|||||||
const struct netdev_class netdev_internal_class =
|
const struct netdev_class netdev_internal_class =
|
||||||
NETDEV_LINUX_CLASS(
|
NETDEV_LINUX_CLASS(
|
||||||
"internal",
|
"internal",
|
||||||
netdev_linux_create,
|
netdev_linux_construct,
|
||||||
netdev_internal_get_stats,
|
netdev_internal_get_stats,
|
||||||
netdev_internal_set_stats,
|
netdev_internal_set_stats,
|
||||||
NULL, /* get_features */
|
NULL, /* get_features */
|
||||||
netdev_internal_get_status);
|
netdev_internal_get_status);
|
||||||
|
|
||||||
static const struct netdev_rx_class netdev_rx_linux_class = {
|
|
||||||
netdev_rx_linux_destroy,
|
|
||||||
netdev_rx_linux_recv,
|
|
||||||
netdev_rx_linux_wait,
|
|
||||||
netdev_rx_linux_drain,
|
|
||||||
};
|
|
||||||
|
|
||||||
/* HTB traffic control class. */
|
/* HTB traffic control class. */
|
||||||
|
|
||||||
|
@@ -30,7 +30,8 @@ extern "C" {
|
|||||||
|
|
||||||
/* A network device (e.g. an Ethernet device).
|
/* 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 {
|
struct netdev {
|
||||||
char *name; /* Name of network device. */
|
char *name; /* Name of network device. */
|
||||||
const struct netdev_class *netdev_class; /* Functions to control
|
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". */
|
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 char *netdev_get_type(const struct netdev *);
|
||||||
const struct netdev_class *netdev_get_class(const struct netdev *);
|
const struct netdev_class *netdev_get_class(const struct netdev *);
|
||||||
const char *netdev_get_name(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 *,
|
void netdev_get_devices(const struct netdev_class *,
|
||||||
struct shash *device_list);
|
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 class structure, to be defined by each implementation of a
|
||||||
* network device.
|
* network device.
|
||||||
*
|
*
|
||||||
* These functions return 0 if successful or a positive errno value on failure,
|
* 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 {
|
struct netdev_class {
|
||||||
/* Type of netdevs in this class, e.g. "system", "tap", "gre", etc.
|
/* Type of netdevs in this class, e.g. "system", "tap", "gre", etc.
|
||||||
*
|
*
|
||||||
@@ -64,6 +155,10 @@ struct netdev_class {
|
|||||||
* the system. */
|
* the system. */
|
||||||
const char *type;
|
const char *type;
|
||||||
|
|
||||||
|
/* ## ------------------- ## */
|
||||||
|
/* ## Top-Level Functions ## */
|
||||||
|
/* ## ------------------- ## */
|
||||||
|
|
||||||
/* Called when the netdev provider is registered, typically at program
|
/* Called when the netdev provider is registered, typically at program
|
||||||
* startup. Returning an error from this function will prevent any network
|
* startup. Returning an error from this function will prevent any network
|
||||||
* device in this class from being opened.
|
* device in this class from being opened.
|
||||||
@@ -83,18 +178,16 @@ struct netdev_class {
|
|||||||
* needed here. */
|
* needed here. */
|
||||||
void (*wait)(void);
|
void (*wait)(void);
|
||||||
|
|
||||||
/* Attempts to create a network device named 'name' in 'netdev_class'. On
|
/* ## ---------------- ## */
|
||||||
* success sets 'netdevp' to the newly created device. */
|
/* ## netdev Functions ## */
|
||||||
int (*create)(const struct netdev_class *netdev_class, const char *name,
|
/* ## ---------------- ## */
|
||||||
struct netdev **netdevp);
|
|
||||||
|
|
||||||
/* Destroys 'netdev'.
|
/* Life-cycle functions for a netdev. See the large comment above on
|
||||||
*
|
* struct netdev_class. */
|
||||||
* Netdev devices maintain a reference count that is incremented on
|
struct netdev *(*alloc)(void);
|
||||||
* netdev_open() and decremented on netdev_close(). If 'netdev'
|
int (*construct)(struct netdev *);
|
||||||
* has a non-zero reference count, then this function will not be
|
void (*destruct)(struct netdev *);
|
||||||
* called. */
|
void (*dealloc)(struct netdev *);
|
||||||
void (*destroy)(struct netdev *netdev);
|
|
||||||
|
|
||||||
/* Fetches the device 'netdev''s configuration, storing it in 'args'.
|
/* Fetches the device 'netdev''s configuration, storing it in 'args'.
|
||||||
* The caller owns 'args' and pre-initializes it to an empty smap.
|
* The caller owns 'args' and pre-initializes it to an empty smap.
|
||||||
@@ -116,18 +209,6 @@ struct netdev_class {
|
|||||||
const struct netdev_tunnel_config *
|
const struct netdev_tunnel_config *
|
||||||
(*get_tunnel_config)(const struct netdev *netdev);
|
(*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
|
/* Sends the 'size'-byte packet in 'buffer' on 'netdev'. Returns 0 if
|
||||||
* successful, otherwise a positive errno value. Returns EAGAIN without
|
* successful, otherwise a positive errno value. Returns EAGAIN without
|
||||||
* blocking if the packet cannot be queued immediately. Returns EMSGSIZE
|
* 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
|
* returned sequence number is allowed to change even when 'netdev' doesn't
|
||||||
* change, although implementations should try to avoid this. */
|
* change, although implementations should try to avoid this. */
|
||||||
unsigned int (*change_seq)(const struct netdev *netdev);
|
unsigned int (*change_seq)(const struct netdev *netdev);
|
||||||
};
|
|
||||||
|
|
||||||
/* A data structure for capturing packets received by a network device.
|
|
||||||
*
|
|
||||||
* This structure should be treated as opaque by network device
|
|
||||||
* implementations. */
|
|
||||||
struct netdev_rx {
|
|
||||||
const struct netdev_rx_class *rx_class;
|
|
||||||
struct netdev *netdev;
|
|
||||||
};
|
|
||||||
|
|
||||||
void netdev_rx_init(struct netdev_rx *, struct netdev *,
|
/* ## ------------------- ## */
|
||||||
const struct netdev_rx_class *);
|
/* ## netdev_rx Functions ## */
|
||||||
void netdev_rx_uninit(struct netdev_rx *);
|
/* ## ------------------- ## */
|
||||||
struct netdev *netdev_rx_get_netdev(const struct netdev_rx *);
|
|
||||||
|
|
||||||
struct netdev_rx_class {
|
/* If a particular netdev class does not support receiving packets, all these
|
||||||
/* Destroys 'rx'. */
|
* function pointers must be NULL. */
|
||||||
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
|
/* Attempts to receive a packet from 'rx' into the 'size' bytes in
|
||||||
* 'buffer'. If successful, returns the number of bytes in the received
|
* '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.
|
* if no packet is ready to be received.
|
||||||
*
|
*
|
||||||
* Must return -EMSGSIZE, and discard the packet, if the received packet
|
* Must return -EMSGSIZE, and discard the packet, if the received packet
|
||||||
* is longer than 'size' bytes. */
|
* is longer than 'size' bytes.
|
||||||
int (*recv)(struct netdev_rx *rx, void *buffer, size_t size);
|
*
|
||||||
|
* 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
|
/* 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()
|
* poll_block() when a packet is ready to be received with netdev_rx_recv()
|
||||||
* on 'rx'. */
|
* on 'rx'. */
|
||||||
void (*wait)(struct netdev_rx *rx);
|
void (*rx_wait)(struct netdev_rx *rx);
|
||||||
|
|
||||||
/* Discards all packets waiting to be received from '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_register_provider(const struct netdev_class *);
|
||||||
int netdev_unregister_provider(const char *type);
|
int netdev_unregister_provider(const char *type);
|
||||||
const struct netdev_class *netdev_lookup_provider(const char *type);
|
const struct netdev_class *netdev_lookup_provider(const char *type);
|
||||||
|
@@ -64,8 +64,7 @@ struct vport_class {
|
|||||||
struct netdev_class netdev_class;
|
struct netdev_class netdev_class;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int netdev_vport_create(const struct netdev_class *, const char *,
|
static int netdev_vport_construct(struct netdev *);
|
||||||
struct netdev **);
|
|
||||||
static int get_patch_config(const struct netdev *, struct smap *args);
|
static int get_patch_config(const struct netdev *, struct smap *args);
|
||||||
static int get_tunnel_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 void netdev_vport_poll_notify(struct netdev_vport *);
|
||||||
@@ -73,7 +72,7 @@ static void netdev_vport_poll_notify(struct netdev_vport *);
|
|||||||
static bool
|
static bool
|
||||||
is_vport_class(const struct netdev_class *class)
|
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 *
|
static const struct vport_class *
|
||||||
@@ -155,30 +154,39 @@ netdev_vport_get_dpif_port_strdup(const struct netdev *netdev)
|
|||||||
sizeof namebuf));
|
sizeof namebuf));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static struct netdev *
|
||||||
netdev_vport_create(const struct netdev_class *netdev_class, const char *name,
|
netdev_vport_alloc(void)
|
||||||
struct netdev **netdevp)
|
|
||||||
{
|
{
|
||||||
struct netdev_vport *dev;
|
struct netdev_vport *netdev = xzalloc(sizeof *netdev);
|
||||||
|
return &netdev->up;
|
||||||
|
}
|
||||||
|
|
||||||
dev = xzalloc(sizeof *dev);
|
static int
|
||||||
netdev_init(&dev->up, name, netdev_class);
|
netdev_vport_construct(struct netdev *netdev_)
|
||||||
dev->change_seq = 1;
|
{
|
||||||
eth_addr_random(dev->etheraddr);
|
struct netdev_vport *netdev = netdev_vport_cast(netdev_);
|
||||||
|
|
||||||
|
netdev->change_seq = 1;
|
||||||
|
eth_addr_random(netdev->etheraddr);
|
||||||
|
|
||||||
*netdevp = &dev->up;
|
|
||||||
route_table_register();
|
route_table_register();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
netdev_vport_destroy(struct netdev *netdev_)
|
netdev_vport_destruct(struct netdev *netdev_)
|
||||||
{
|
{
|
||||||
struct netdev_vport *netdev = netdev_vport_cast(netdev_);
|
struct netdev_vport *netdev = netdev_vport_cast(netdev_);
|
||||||
|
|
||||||
route_table_unregister();
|
route_table_unregister();
|
||||||
free(netdev->peer);
|
free(netdev->peer);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
netdev_vport_dealloc(struct netdev *netdev_)
|
||||||
|
{
|
||||||
|
struct netdev_vport *netdev = netdev_vport_cast(netdev_);
|
||||||
free(netdev);
|
free(netdev);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -629,14 +637,14 @@ get_stats(const struct netdev *netdev, struct netdev_stats *stats)
|
|||||||
netdev_vport_run, \
|
netdev_vport_run, \
|
||||||
netdev_vport_wait, \
|
netdev_vport_wait, \
|
||||||
\
|
\
|
||||||
netdev_vport_create, \
|
netdev_vport_alloc, \
|
||||||
netdev_vport_destroy, \
|
netdev_vport_construct, \
|
||||||
|
netdev_vport_destruct, \
|
||||||
|
netdev_vport_dealloc, \
|
||||||
GET_CONFIG, \
|
GET_CONFIG, \
|
||||||
SET_CONFIG, \
|
SET_CONFIG, \
|
||||||
GET_TUNNEL_CONFIG, \
|
GET_TUNNEL_CONFIG, \
|
||||||
\
|
\
|
||||||
NULL, /* rx_open */ \
|
|
||||||
\
|
|
||||||
NULL, /* send */ \
|
NULL, /* send */ \
|
||||||
NULL, /* send_wait */ \
|
NULL, /* send_wait */ \
|
||||||
\
|
\
|
||||||
@@ -676,7 +684,15 @@ get_stats(const struct netdev *netdev, struct netdev_stats *stats)
|
|||||||
\
|
\
|
||||||
netdev_vport_update_flags, \
|
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) \
|
#define TUNNEL_CLASS(NAME, DPIF_PORT) \
|
||||||
{ DPIF_PORT, \
|
{ DPIF_PORT, \
|
||||||
|
143
lib/netdev.c
143
lib/netdev.c
@@ -251,7 +251,6 @@ netdev_open(const char *name, const char *type, struct netdev **netdevp)
|
|||||||
struct netdev *netdev;
|
struct netdev *netdev;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
*netdevp = NULL;
|
|
||||||
netdev_initialize();
|
netdev_initialize();
|
||||||
|
|
||||||
netdev = shash_find_data(&netdev_shash, name);
|
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;
|
const struct netdev_class *class;
|
||||||
|
|
||||||
class = netdev_lookup_provider(type);
|
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",
|
VLOG_WARN("could not create netdev %s of unknown type %s",
|
||||||
name, type);
|
name, type);
|
||||||
return EAFNOSUPPORT;
|
error = EAFNOSUPPORT;
|
||||||
}
|
}
|
||||||
error = class->create(class, name, &netdev);
|
} else {
|
||||||
if (error) {
|
error = 0;
|
||||||
return error;
|
|
||||||
}
|
|
||||||
ovs_assert(netdev->netdev_class == class);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
netdev->ref_cnt++;
|
|
||||||
|
|
||||||
*netdevp = netdev;
|
if (!error) {
|
||||||
return 0;
|
netdev->ref_cnt++;
|
||||||
|
*netdevp = netdev;
|
||||||
|
} else {
|
||||||
|
*netdevp = NULL;
|
||||||
|
}
|
||||||
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Returns a reference to 'netdev_' for the caller to own. Returns null if
|
/* 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);
|
ovs_assert(dev->ref_cnt);
|
||||||
if (!--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;
|
int error;
|
||||||
|
|
||||||
error = (netdev->netdev_class->rx_open
|
if (netdev->netdev_class->rx_alloc) {
|
||||||
? netdev->netdev_class->rx_open(netdev, rxp)
|
struct netdev_rx *rx = netdev->netdev_class->rx_alloc();
|
||||||
: EOPNOTSUPP);
|
if (rx) {
|
||||||
if (!error) {
|
rx->netdev = netdev;
|
||||||
ovs_assert((*rxp)->netdev == netdev);
|
error = netdev->netdev_class->rx_construct(rx);
|
||||||
netdev->ref_cnt++;
|
if (!error) {
|
||||||
|
netdev->ref_cnt++;
|
||||||
|
*rxp = rx;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
netdev->netdev_class->rx_dealloc(rx);
|
||||||
|
} else {
|
||||||
|
error = ENOMEM;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
*rxp = NULL;
|
error = EOPNOTSUPP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*rxp = NULL;
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -401,10 +430,10 @@ void
|
|||||||
netdev_rx_close(struct netdev_rx *rx)
|
netdev_rx_close(struct netdev_rx *rx)
|
||||||
{
|
{
|
||||||
if (rx) {
|
if (rx) {
|
||||||
struct netdev *dev = rx->netdev;
|
struct netdev *netdev = rx->netdev;
|
||||||
|
netdev->netdev_class->rx_destruct(rx);
|
||||||
rx->rx_class->destroy(rx);
|
netdev->netdev_class->rx_dealloc(rx);
|
||||||
netdev_unref(dev);
|
netdev_close(netdev);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -416,7 +445,8 @@ netdev_rx_recv(struct netdev_rx *rx, struct ofpbuf *buffer)
|
|||||||
ovs_assert(buffer->size == 0);
|
ovs_assert(buffer->size == 0);
|
||||||
ovs_assert(ofpbuf_tailroom(buffer) >= ETH_TOTAL_MIN);
|
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) {
|
if (retval >= 0) {
|
||||||
COVERAGE_INC(netdev_received);
|
COVERAGE_INC(netdev_received);
|
||||||
buffer->size += retval;
|
buffer->size += retval;
|
||||||
@@ -432,13 +462,15 @@ netdev_rx_recv(struct netdev_rx *rx, struct ofpbuf *buffer)
|
|||||||
void
|
void
|
||||||
netdev_rx_wait(struct netdev_rx *rx)
|
netdev_rx_wait(struct netdev_rx *rx)
|
||||||
{
|
{
|
||||||
rx->rx_class->wait(rx);
|
rx->netdev->netdev_class->rx_wait(rx);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
netdev_rx_drain(struct netdev_rx *rx)
|
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
|
/* 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);
|
return netdev->netdev_class->change_seq(netdev);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Initializes 'netdev' as a netdev device named 'name' of the specified
|
|
||||||
* 'netdev_class'. This function is ordinarily called from a netdev provider's
|
|
||||||
* 'create' function.
|
|
||||||
*
|
|
||||||
* This function adds 'netdev' to a netdev-owned shash, so it is very important
|
|
||||||
* that 'netdev' only be freed after calling netdev_uninit(). */
|
|
||||||
void
|
|
||||||
netdev_init(struct netdev *netdev, const char *name,
|
|
||||||
const struct netdev_class *netdev_class)
|
|
||||||
{
|
|
||||||
ovs_assert(!shash_find(&netdev_shash, name));
|
|
||||||
|
|
||||||
memset(netdev, 0, sizeof *netdev);
|
|
||||||
netdev->netdev_class = netdev_class;
|
|
||||||
netdev->name = xstrdup(name);
|
|
||||||
netdev->node = shash_add(&netdev_shash, name, netdev);
|
|
||||||
list_init(&netdev->saved_flags_list);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Undoes the results of initialization.
|
|
||||||
*
|
|
||||||
* Normally this function does not need to be called as netdev_close has
|
|
||||||
* the same effect when the refcount drops to zero.
|
|
||||||
* However, it may be called by providers due to an error on creation
|
|
||||||
* that occurs after initialization. It this case netdev_close() would
|
|
||||||
* never be called. */
|
|
||||||
void
|
|
||||||
netdev_uninit(struct netdev *netdev, bool destroy)
|
|
||||||
{
|
|
||||||
char *name = netdev->name;
|
|
||||||
|
|
||||||
ovs_assert(!netdev->ref_cnt);
|
|
||||||
ovs_assert(list_is_empty(&netdev->saved_flags_list));
|
|
||||||
|
|
||||||
shash_delete(&netdev_shash, netdev->node);
|
|
||||||
|
|
||||||
if (destroy) {
|
|
||||||
netdev->netdev_class->destroy(netdev);
|
|
||||||
}
|
|
||||||
free(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Returns the class type of 'netdev'.
|
/* Returns the class type of 'netdev'.
|
||||||
*
|
*
|
||||||
* The caller must not free the returned value. */
|
* The caller must not free the returned value. */
|
||||||
@@ -1428,21 +1418,6 @@ netdev_get_type_from_name(const char *name)
|
|||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
netdev_rx_init(struct netdev_rx *rx, struct netdev *netdev,
|
|
||||||
const struct netdev_rx_class *class)
|
|
||||||
{
|
|
||||||
ovs_assert(netdev->ref_cnt > 0);
|
|
||||||
rx->rx_class = class;
|
|
||||||
rx->netdev = netdev;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
netdev_rx_uninit(struct netdev_rx *rx OVS_UNUSED)
|
|
||||||
{
|
|
||||||
/* Nothing to do. */
|
|
||||||
}
|
|
||||||
|
|
||||||
struct netdev *
|
struct netdev *
|
||||||
netdev_rx_get_netdev(const struct netdev_rx *rx)
|
netdev_rx_get_netdev(const struct netdev_rx *rx)
|
||||||
{
|
{
|
||||||
|
Reference in New Issue
Block a user