+ struct shash_node *node;
+ SHASH_FOR_EACH(node, &netdev_classes) {
+ const struct netdev_class *netdev_class = node->data;
+ if (netdev_class->wait) {
+ netdev_class->wait();
+ }
+ }
+}
+
+/* Initializes and registers a new netdev provider. After successful
+ * registration, new netdevs of that type can be opened using netdev_open(). */
+int
+netdev_register_provider(const struct netdev_class *new_class)
+{
+ struct netdev_class *new_provider;
+
+ if (shash_find(&netdev_classes, new_class->type)) {
+ VLOG_WARN("attempted to register duplicate netdev provider: %s",
+ new_class->type);
+ return EEXIST;
+ }
+
+ if (new_class->init) {
+ int error = new_class->init();
+ if (error) {
+ VLOG_ERR("failed to initialize %s network device class: %s",
+ new_class->type, strerror(error));
+ return error;
+ }
+ }
+
+ new_provider = xmalloc(sizeof *new_provider);
+ memcpy(new_provider, new_class, sizeof *new_provider);
+
+ shash_add(&netdev_classes, new_class->type, new_provider);
+
+ return 0;
+}
+
+/* Unregisters a netdev provider. 'type' must have been previously
+ * registered and not currently be in use by any netdevs. After unregistration
+ * new netdevs of that type cannot be opened using netdev_open(). */
+int
+netdev_unregister_provider(const char *type)
+{
+ struct shash_node *del_node, *netdev_dev_node;
+
+ del_node = shash_find(&netdev_classes, type);
+ if (!del_node) {
+ VLOG_WARN("attempted to unregister a netdev provider that is not "
+ "registered: %s", type);
+ return EAFNOSUPPORT;
+ }
+
+ SHASH_FOR_EACH(netdev_dev_node, &netdev_dev_shash) {
+ struct netdev_dev *netdev_dev = netdev_dev_node->data;
+ if (!strcmp(netdev_dev->netdev_class->type, type)) {
+ VLOG_WARN("attempted to unregister in use netdev provider: %s",
+ type);
+ return EBUSY;