+ return *type ? EOPNOTSUPP : 0;
+ }
+}
+
+/* Queries 'netdev' for information about the queue numbered 'queue_id'. If
+ * successful, adds that information as string key-value pairs to 'details'.
+ * Returns 0 if successful, otherwise a positive errno value.
+ *
+ * 'queue_id' must be less than the number of queues supported by 'netdev' for
+ * the current form of QoS (e.g. as returned by netdev_get_n_queues(netdev)).
+ *
+ * The returned contents of 'details' should be documented as valid for the
+ * given 'type' in the "other_config" column in the "Queue" table in
+ * vswitchd/vswitch.xml (which is built as ovs-vswitchd.conf.db(8)).
+ *
+ * The caller must initialize 'details' (e.g. with shash_init()) before calling
+ * this function. The caller must free 'details', including 'data' members,
+ * when it is no longer needed (e.g. with shash_destroy_free_data()). */
+int
+netdev_get_queue(const struct netdev *netdev,
+ unsigned int queue_id, struct shash *details)
+{
+ const struct netdev_class *class = netdev_get_dev(netdev)->netdev_class;
+ int retval;
+
+ retval = (class->get_queue
+ ? class->get_queue(netdev, queue_id, details)
+ : EOPNOTSUPP);
+ if (retval) {
+ shash_clear_free_data(details);
+ }
+ return retval;
+}
+
+/* Configures the queue numbered 'queue_id' on 'netdev' with the key-value
+ * string pairs in 'details'. The contents of 'details' should be documented
+ * as valid for the given 'type' in the "other_config" column in the "Queue"
+ * table in vswitchd/vswitch.xml (which is built as ovs-vswitchd.conf.db(8)).
+ * Returns 0 if successful, otherwise a positive errno value. On failure, the
+ * given queue's configuration should be unmodified.
+ *
+ * 'queue_id' must be less than the number of queues supported by 'netdev' for
+ * the current form of QoS (e.g. as returned by netdev_get_n_queues(netdev)).
+ *
+ * This function does not modify 'details', and the caller retains ownership of
+ * it. */
+int
+netdev_set_queue(struct netdev *netdev,
+ unsigned int queue_id, const struct shash *details)
+{
+ const struct netdev_class *class = netdev_get_dev(netdev)->netdev_class;
+ return (class->set_queue
+ ? class->set_queue(netdev, queue_id, details)
+ : EOPNOTSUPP);
+}
+
+/* Attempts to delete the queue numbered 'queue_id' from 'netdev'. Some kinds
+ * of QoS may have a fixed set of queues, in which case attempts to delete them
+ * will fail with EOPNOTSUPP.
+ *
+ * Returns 0 if successful, otherwise a positive errno value. On failure, the
+ * given queue will be unmodified.
+ *
+ * 'queue_id' must be less than the number of queues supported by 'netdev' for
+ * the current form of QoS (e.g. as returned by
+ * netdev_get_n_queues(netdev)). */
+int
+netdev_delete_queue(struct netdev *netdev, unsigned int queue_id)
+{
+ const struct netdev_class *class = netdev_get_dev(netdev)->netdev_class;
+ return (class->delete_queue
+ ? class->delete_queue(netdev, queue_id)
+ : EOPNOTSUPP);
+}
+
+/* Obtains statistics about 'queue_id' on 'netdev'. On success, returns 0 and
+ * fills 'stats' with the queue's statistics; individual members of 'stats' may
+ * be set to all-1-bits if the statistic is unavailable. On failure, returns a
+ * positive errno value and fills 'stats' with all-1-bits. */
+int
+netdev_get_queue_stats(const struct netdev *netdev, unsigned int queue_id,
+ struct netdev_queue_stats *stats)
+{
+ const struct netdev_class *class = netdev_get_dev(netdev)->netdev_class;
+ int retval;
+
+ retval = (class->get_queue_stats
+ ? class->get_queue_stats(netdev, queue_id, stats)
+ : EOPNOTSUPP);
+ if (retval) {
+ memset(stats, 0xff, sizeof *stats);
+ }
+ return retval;
+}
+
+/* Iterates over all of 'netdev''s queues, calling 'cb' with the queue's ID,
+ * its configuration, and the 'aux' specified by the caller. The order of
+ * iteration is unspecified, but (when successful) each queue is visited
+ * exactly once.
+ *
+ * Calling this function may be more efficient than calling netdev_get_queue()
+ * for every queue.
+ *
+ * 'cb' must not modify or free the 'details' argument passed in.
+ *
+ * Returns 0 if successful, otherwise a positive errno value. On error, some
+ * configured queues may not have been included in the iteration. */
+int
+netdev_dump_queues(const struct netdev *netdev,
+ netdev_dump_queues_cb *cb, void *aux)
+{
+ const struct netdev_class *class = netdev_get_dev(netdev)->netdev_class;
+ return (class->dump_queues
+ ? class->dump_queues(netdev, cb, aux)
+ : EOPNOTSUPP);
+}
+
+/* Iterates over all of 'netdev''s queues, calling 'cb' with the queue's ID,
+ * its statistics, and the 'aux' specified by the caller. The order of
+ * iteration is unspecified, but (when successful) each queue is visited
+ * exactly once.
+ *
+ * Calling this function may be more efficient than calling
+ * netdev_get_queue_stats() for every queue.
+ *
+ * 'cb' must not modify or free the statistics passed in.
+ *
+ * Returns 0 if successful, otherwise a positive errno value. On error, some
+ * configured queues may not have been included in the iteration. */
+int
+netdev_dump_queue_stats(const struct netdev *netdev,
+ netdev_dump_queue_stats_cb *cb, void *aux)
+{
+ const struct netdev_class *class = netdev_get_dev(netdev)->netdev_class;
+ return (class->dump_queue_stats
+ ? class->dump_queue_stats(netdev, cb, aux)
+ : EOPNOTSUPP);
+}
+
+/* If 'netdev' is a VLAN network device (e.g. one created with vconfig(8)),
+ * sets '*vlan_vid' to the VLAN VID associated with that device and returns 0.
+ * Otherwise returns a errno value (specifically ENOENT if 'netdev_name' is the
+ * name of a network device that is not a VLAN device) and sets '*vlan_vid' to
+ * -1. */
+int
+netdev_get_vlan_vid(const struct netdev *netdev, int *vlan_vid)
+{
+ int error = (netdev_get_dev(netdev)->netdev_class->get_vlan_vid
+ ? netdev_get_dev(netdev)->netdev_class->get_vlan_vid(netdev,
+ vlan_vid)
+ : ENOENT);
+ if (error) {
+ *vlan_vid = 0;