-static void
-poll_notify(struct list *list)
-{
- struct netdev_linux_notifier *notifier;
- LIST_FOR_EACH (notifier, node, list) {
- struct netdev_notifier *n = ¬ifier->notifier;
- n->cb(n);
- }
-}
-
-static void
-netdev_linux_poll_cb(const struct rtnetlink_change *change,
- void *aux OVS_UNUSED)
-{
- if (change) {
- struct list *list = shash_find_data(&netdev_linux_notifiers,
- change->ifname);
- if (list) {
- poll_notify(list);
- }
- } else {
- struct shash_node *node;
- SHASH_FOR_EACH (node, &netdev_linux_notifiers) {
- poll_notify(node->data);
- }
- }
-}
-
-static int
-netdev_linux_poll_add(struct netdev *netdev,
- void (*cb)(struct netdev_notifier *), void *aux,
- struct netdev_notifier **notifierp)
-{
- const char *netdev_name = netdev_get_name(netdev);
- struct netdev_linux_notifier *notifier;
- struct list *list;
-
- if (shash_is_empty(&netdev_linux_notifiers)) {
- int error = rtnetlink_notifier_register(&netdev_linux_poll_notifier,
- netdev_linux_poll_cb, NULL);
- if (error) {
- return error;
- }
- }
-
- list = shash_find_data(&netdev_linux_notifiers, netdev_name);
- if (!list) {
- list = xmalloc(sizeof *list);
- list_init(list);
- shash_add(&netdev_linux_notifiers, netdev_name, list);
- }
-
- notifier = xmalloc(sizeof *notifier);
- netdev_notifier_init(¬ifier->notifier, netdev, cb, aux);
- list_push_back(list, ¬ifier->node);
- *notifierp = ¬ifier->notifier;
- return 0;
-}
-
-static void
-netdev_linux_poll_remove(struct netdev_notifier *notifier_)
-{
- struct netdev_linux_notifier *notifier =
- CONTAINER_OF(notifier_, struct netdev_linux_notifier, notifier);
- struct list *list;
-
- /* Remove 'notifier' from its list. */
- list = list_remove(¬ifier->node);
- if (list_is_empty(list)) {
- /* The list is now empty. Remove it from the hash and free it. */
- const char *netdev_name = netdev_get_name(notifier->notifier.netdev);
- shash_delete(&netdev_linux_notifiers,
- shash_find(&netdev_linux_notifiers, netdev_name));
- free(list);
- }
- free(notifier);
-
- /* 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,
-};
+static unsigned int
+netdev_linux_change_seq(const struct netdev *netdev)
+{
+ return netdev_dev_linux_cast(netdev_get_dev(netdev))->change_seq;
+}
+
+#define NETDEV_LINUX_CLASS(NAME, CREATE, ENUMERATE, SET_STATS) \
+{ \
+ NAME, \
+ \
+ netdev_linux_init, \
+ netdev_linux_run, \
+ netdev_linux_wait, \
+ \
+ CREATE, \
+ netdev_linux_destroy, \
+ NULL, /* get_config */ \
+ NULL, /* set_config */ \
+ \
+ netdev_linux_open, \
+ netdev_linux_close, \
+ \
+ ENUMERATE, \
+ \
+ netdev_linux_listen, \
+ 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_set_mtu, \
+ netdev_linux_get_ifindex, \
+ netdev_linux_get_carrier, \
+ netdev_linux_set_miimon_interval, \
+ 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, \
+ netdev_linux_get_status, \
+ netdev_linux_arp_lookup, \
+ \
+ netdev_linux_update_flags, \
+ \
+ netdev_linux_change_seq \
+}
+
+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);