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. */
/* Returns the netdev with 'name' or NULL if there is none.
*
- * The caller must not free the returned value. */
+ * The caller must free the returned netdev with netdev_close(). */
struct netdev *
netdev_from_name(const char *name)
{
- return shash_find_data(&netdev_shash, name);
+ struct netdev *netdev;
+
+ netdev = shash_find_data(&netdev_shash, name);
+ if (netdev) {
+ netdev_ref(netdev);
+ }
+
+ return netdev;
}
/* Fills 'device_list' with devices that match 'netdev_class'.
*
- * The caller is responsible for initializing and destroying 'device_list'
- * but the contained netdevs must not be freed. */
+ * The caller is responsible for initializing and destroying 'device_list' and
+ * must close each device on the list. */
void
netdev_get_devices(const struct netdev_class *netdev_class,
struct shash *device_list)
struct netdev *dev = node->data;
if (dev->netdev_class == netdev_class) {
+ dev->ref_cnt++;
shash_add(device_list, node->name, node->data);
}
}
const char *
netdev_get_type_from_name(const char *name)
{
- const struct netdev *dev = netdev_from_name(name);
- return dev ? netdev_get_type(dev) : NULL;
+ struct netdev *dev = netdev_from_name(name);
+ const char *type = dev ? netdev_get_type(dev) : NULL;
+ netdev_close(dev);
+ 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)
{