+const struct netdev_tunnel_config *
+netdev_get_tunnel_config(const struct netdev *netdev)
+ OVS_EXCLUDED(netdev_mutex)
+{
+ if (netdev->netdev_class->get_tunnel_config) {
+ return netdev->netdev_class->get_tunnel_config(netdev);
+ } else {
+ return NULL;
+ }
+}
+
+static void
+netdev_unref(struct netdev *dev)
+ OVS_RELEASES(netdev_mutex)
+{
+ ovs_assert(dev->ref_cnt);
+ if (!--dev->ref_cnt) {
+ const struct netdev_class *class = dev->netdev_class;
+ struct netdev_registered_class *rc;
+ int old_ref_cnt;
+
+ dev->netdev_class->destruct(dev);
+
+ shash_delete(&netdev_shash, dev->node);
+ free(dev->name);
+ dev->netdev_class->dealloc(dev);
+ ovs_mutex_unlock(&netdev_mutex);
+
+ ovs_mutex_lock(&netdev_class_mutex);
+ rc = netdev_lookup_class(class->type);
+ atomic_sub(&rc->ref_cnt, 1, &old_ref_cnt);
+ ovs_assert(old_ref_cnt > 0);
+ ovs_mutex_unlock(&netdev_class_mutex);
+ } else {
+ ovs_mutex_unlock(&netdev_mutex);
+ }
+}
+
+/* Closes and destroys 'netdev'. */
+void
+netdev_close(struct netdev *netdev)
+ OVS_EXCLUDED(netdev_mutex)
+{
+ if (netdev) {
+ ovs_mutex_lock(&netdev_mutex);
+ netdev_unref(netdev);
+ }
+}
+
+/* Parses 'netdev_name_', which is of the form [type@]name into its component
+ * pieces. 'name' and 'type' must be freed by the caller. */
+void
+netdev_parse_name(const char *netdev_name_, char **name, char **type)
+{
+ char *netdev_name = xstrdup(netdev_name_);
+ char *separator;
+
+ separator = strchr(netdev_name, '@');
+ if (separator) {
+ *separator = '\0';
+ *type = netdev_name;
+ *name = xstrdup(separator + 1);
+ } else {
+ *name = netdev_name;
+ *type = xstrdup("system");
+ }
+}
+
+/* Attempts to open a netdev_rxq handle for obtaining packets received on
+ * 'netdev'. On success, returns 0 and stores a nonnull 'netdev_rxq *' into
+ * '*rxp'. On failure, returns a positive errno value and stores NULL into
+ * '*rxp'.
+ *
+ * Some kinds of network devices might not support receiving packets. This
+ * function returns EOPNOTSUPP in that case.*/
+int
+netdev_rxq_open(struct netdev *netdev, struct netdev_rxq **rxp, int id)
+ OVS_EXCLUDED(netdev_mutex)
+{
+ int error;
+
+ if (netdev->netdev_class->rxq_alloc && id < netdev->n_rxq) {
+ struct netdev_rxq *rx = netdev->netdev_class->rxq_alloc();
+ if (rx) {
+ rx->netdev = netdev;
+ rx->queue_id = id;
+ error = netdev->netdev_class->rxq_construct(rx);
+ if (!error) {
+ ovs_mutex_lock(&netdev_mutex);
+ netdev->ref_cnt++;
+ ovs_mutex_unlock(&netdev_mutex);
+
+ *rxp = rx;
+ return 0;