#include "netdev-provider.h"
#include "netdev-vport.h"
#include "netlink.h"
+#include "netlink-socket.h"
#include "ofpbuf.h"
#include "openflow/openflow.h"
#include "packets.h"
#include "poll-loop.h"
#include "rtnetlink.h"
+#include "rtnetlink-link.h"
#include "socket-util.h"
#include "shash.h"
#include "svec.h"
static void
netdev_linux_run(void)
{
- rtnetlink_notifier_run();
+ rtnetlink_link_notifier_run();
}
static void
netdev_linux_wait(void)
{
- rtnetlink_notifier_wait();
+ rtnetlink_link_notifier_wait();
}
static void
-netdev_linux_cache_cb(const struct rtnetlink_change *change,
+netdev_linux_cache_cb(const struct rtnetlink_link_change *change,
void *aux OVS_UNUSED)
{
struct netdev_dev_linux *dev;
}
}
-/* Creates the netdev device of 'type' with 'name'. */
+/* Creates system and internal devices. */
static int
-netdev_linux_create_system(const struct netdev_class *class OVS_UNUSED,
+netdev_linux_create(const struct netdev_class *class,
const char *name, const struct shash *args,
struct netdev_dev **netdev_devp)
{
int error;
if (!shash_is_empty(args)) {
- VLOG_WARN("%s: arguments for system devices should be empty", name);
+ VLOG_WARN("%s: arguments for %s devices should be empty",
+ name, class->type);
}
if (!cache_notifier_refcount) {
- error = rtnetlink_notifier_register(&netdev_linux_cache_notifier,
- netdev_linux_cache_cb, NULL);
+ error = rtnetlink_link_notifier_register(&netdev_linux_cache_notifier,
+ netdev_linux_cache_cb, NULL);
if (error) {
return error;
}
cache_notifier_refcount++;
netdev_dev = xzalloc(sizeof *netdev_dev);
- netdev_dev_init(&netdev_dev->netdev_dev, name, &netdev_linux_class);
+ netdev_dev_init(&netdev_dev->netdev_dev, name, class);
*netdev_devp = &netdev_dev->netdev_dev;
return 0;
netdev_linux_destroy(struct netdev_dev *netdev_dev_)
{
struct netdev_dev_linux *netdev_dev = netdev_dev_linux_cast(netdev_dev_);
- const char *type = netdev_dev_get_type(netdev_dev_);
+ const struct netdev_class *class = netdev_dev_get_class(netdev_dev_);
if (netdev_dev->tc && netdev_dev->tc->ops->tc_destroy) {
netdev_dev->tc->ops->tc_destroy(netdev_dev->tc);
}
- if (!strcmp(type, "system")) {
+ if (class == &netdev_linux_class || class == &netdev_internal_class) {
cache_notifier_refcount--;
if (!cache_notifier_refcount) {
- rtnetlink_notifier_unregister(&netdev_linux_cache_notifier);
+ rtnetlink_link_notifier_unregister(&netdev_linux_cache_notifier);
}
- } else if (!strcmp(type, "tap")) {
+ } else if (class == &netdev_tap_class) {
destroy_tap(netdev_dev);
+ } else {
+ NOT_REACHED();
}
free(netdev_dev);
netdev->fd = -1;
netdev_init(&netdev->netdev, netdev_dev_);
- error = netdev_get_flags(&netdev->netdev, &flags);
- if (error == ENODEV) {
- goto error;
+ /* Verify that the device really exists, by attempting to read its flags.
+ * (The flags might be cached, in which case this won't actually do an
+ * ioctl.)
+ *
+ * Don't do this for "internal" netdevs, though, because those have to be
+ * created as netdev objects before they exist in the kernel, because
+ * creating them in the kernel happens by passing a netdev object to
+ * dpif_port_add(). */
+ if (netdev_dev_get_class(netdev_dev_) != &netdev_internal_class) {
+ error = netdev_get_flags(&netdev->netdev, &flags);
+ if (error == ENODEV) {
+ goto error;
+ }
}
if (!strcmp(netdev_dev_get_type(netdev_dev_), "tap") &&
}
static void
-netdev_linux_poll_cb(const struct rtnetlink_change *change,
+netdev_linux_poll_cb(const struct rtnetlink_link_change *change,
void *aux OVS_UNUSED)
{
if (change) {
struct list *list;
if (shash_is_empty(&netdev_linux_notifiers)) {
- int error = rtnetlink_notifier_register(&netdev_linux_poll_notifier,
- netdev_linux_poll_cb, NULL);
+ int error;
+ error = rtnetlink_link_notifier_register(&netdev_linux_poll_notifier,
+ netdev_linux_poll_cb, NULL);
if (error) {
return error;
}
/* If that was the last notifier, unregister. */
if (shash_is_empty(&netdev_linux_notifiers)) {
- rtnetlink_notifier_unregister(&netdev_linux_poll_notifier);
- }
-}
-
-const struct netdev_class netdev_linux_class = {
- "system",
-
- netdev_linux_init,
- netdev_linux_run,
- netdev_linux_wait,
-
- netdev_linux_create_system,
- netdev_linux_destroy,
- NULL, /* reconfigure */
-
- netdev_linux_open,
- netdev_linux_close,
-
- netdev_linux_enumerate,
-
- netdev_linux_recv,
- netdev_linux_recv_wait,
- netdev_linux_drain,
-
- netdev_linux_send,
- netdev_linux_send_wait,
-
- netdev_linux_set_etheraddr,
- netdev_linux_get_etheraddr,
- netdev_linux_get_mtu,
- netdev_linux_get_ifindex,
- netdev_linux_get_carrier,
- netdev_linux_get_stats,
- netdev_vport_set_stats,
-
- netdev_linux_get_features,
- netdev_linux_set_advertisements,
- netdev_linux_get_vlan_vid,
-
- netdev_linux_set_policing,
- netdev_linux_get_qos_types,
- netdev_linux_get_qos_capabilities,
- netdev_linux_get_qos,
- netdev_linux_set_qos,
- netdev_linux_get_queue,
- netdev_linux_set_queue,
- netdev_linux_delete_queue,
- netdev_linux_get_queue_stats,
- netdev_linux_dump_queues,
- netdev_linux_dump_queue_stats,
-
- netdev_linux_get_in4,
- netdev_linux_set_in4,
- netdev_linux_get_in6,
- netdev_linux_add_router,
- netdev_linux_get_next_hop,
- netdev_linux_arp_lookup,
-
- netdev_linux_update_flags,
-
- netdev_linux_poll_add,
- netdev_linux_poll_remove,
-};
-
-const struct netdev_class netdev_tap_class = {
- "tap",
-
- netdev_linux_init,
- netdev_linux_run,
- netdev_linux_wait,
-
- netdev_linux_create_tap,
- netdev_linux_destroy,
- NULL, /* reconfigure */
-
- netdev_linux_open,
- netdev_linux_close,
-
- NULL, /* enumerate */
-
- netdev_linux_recv,
- netdev_linux_recv_wait,
- netdev_linux_drain,
-
- netdev_linux_send,
- netdev_linux_send_wait,
-
- netdev_linux_set_etheraddr,
- netdev_linux_get_etheraddr,
- netdev_linux_get_mtu,
- netdev_linux_get_ifindex,
- netdev_linux_get_carrier,
- netdev_linux_get_stats,
- NULL, /* set_stats */
-
- netdev_linux_get_features,
- netdev_linux_set_advertisements,
- netdev_linux_get_vlan_vid,
-
- netdev_linux_set_policing,
- netdev_linux_get_qos_types,
- netdev_linux_get_qos_capabilities,
- netdev_linux_get_qos,
- netdev_linux_set_qos,
- netdev_linux_get_queue,
- netdev_linux_set_queue,
- netdev_linux_delete_queue,
- netdev_linux_get_queue_stats,
- netdev_linux_dump_queues,
- netdev_linux_dump_queue_stats,
-
- netdev_linux_get_in4,
- netdev_linux_set_in4,
- netdev_linux_get_in6,
- netdev_linux_add_router,
- netdev_linux_get_next_hop,
- netdev_linux_arp_lookup,
-
- netdev_linux_update_flags,
-
- netdev_linux_poll_add,
- netdev_linux_poll_remove,
-};
+ rtnetlink_link_notifier_unregister(&netdev_linux_poll_notifier);
+ }
+}
+
+#define NETDEV_LINUX_CLASS(NAME, CREATE, ENUMERATE, SET_STATS) \
+{ \
+ NAME, \
+ \
+ netdev_linux_init, \
+ netdev_linux_run, \
+ netdev_linux_wait, \
+ \
+ CREATE, \
+ netdev_linux_destroy, \
+ NULL, /* reconfigure */ \
+ \
+ netdev_linux_open, \
+ netdev_linux_close, \
+ \
+ ENUMERATE, \
+ \
+ netdev_linux_recv, \
+ netdev_linux_recv_wait, \
+ netdev_linux_drain, \
+ \
+ netdev_linux_send, \
+ netdev_linux_send_wait, \
+ \
+ netdev_linux_set_etheraddr, \
+ netdev_linux_get_etheraddr, \
+ netdev_linux_get_mtu, \
+ netdev_linux_get_ifindex, \
+ netdev_linux_get_carrier, \
+ netdev_linux_get_stats, \
+ SET_STATS, \
+ \
+ netdev_linux_get_features, \
+ netdev_linux_set_advertisements, \
+ netdev_linux_get_vlan_vid, \
+ \
+ netdev_linux_set_policing, \
+ netdev_linux_get_qos_types, \
+ netdev_linux_get_qos_capabilities, \
+ netdev_linux_get_qos, \
+ netdev_linux_set_qos, \
+ netdev_linux_get_queue, \
+ netdev_linux_set_queue, \
+ netdev_linux_delete_queue, \
+ netdev_linux_get_queue_stats, \
+ netdev_linux_dump_queues, \
+ netdev_linux_dump_queue_stats, \
+ \
+ netdev_linux_get_in4, \
+ netdev_linux_set_in4, \
+ netdev_linux_get_in6, \
+ netdev_linux_add_router, \
+ netdev_linux_get_next_hop, \
+ NULL, /* get_status */ \
+ netdev_linux_arp_lookup, \
+ \
+ netdev_linux_update_flags, \
+ \
+ netdev_linux_poll_add, \
+ netdev_linux_poll_remove \
+}
+
+const struct netdev_class netdev_linux_class =
+ NETDEV_LINUX_CLASS(
+ "system",
+ netdev_linux_create,
+ netdev_linux_enumerate,
+ NULL); /* set_stats */
+
+const struct netdev_class netdev_tap_class =
+ NETDEV_LINUX_CLASS(
+ "tap",
+ netdev_linux_create_tap,
+ NULL, /* enumerate */
+ NULL); /* set_stats */
+
+const struct netdev_class netdev_internal_class =
+ NETDEV_LINUX_CLASS(
+ "internal",
+ netdev_linux_create,
+ NULL, /* enumerate */
+ netdev_vport_set_stats);
\f
/* HTB traffic control class. */