@@ -29,6 +29,7 @@
#include "openvswitch/vlog.h"
#include "ovs-thread.h"
#include "smap.h"
+#include "sset.h"
#include "util.h"
VLOG_DEFINE_THIS_MODULE(netdev_dpdk_common);
@@ -402,6 +403,706 @@ dpdk_mp_dump(FILE *stream, struct dpdk_mp *dmp)
ovs_mutex_unlock(&dpdk_mp_mutex);
}
+/* Quality of Service */
+
+struct dpdk_qos_conf {
+ const struct dpdk_qos_ops *ops;
+ rte_spinlock_t lock;
+};
+
+/* QoS queue information used by the netdev queue dump functions. */
+struct dpdk_qos_queue_state {
+ uint32_t *queues;
+ size_t cur_queue;
+ size_t n_queues;
+};
+
+struct dpdk_qos_ingress_policer {
+ struct rte_meter_srtcm_params app_srtcm_params;
+ struct rte_meter_srtcm in_policer;
+ struct rte_meter_srtcm_profile in_prof;
+ rte_spinlock_t policer_lock;
+};
+
+/* A particular implementation of dpdk QoS operations.
+ *
+ * The functions below return 0 if successful or a positive errno value on
+ * failure, except where otherwise noted. All of them must be provided, except
+ * where otherwise noted.
+ */
+struct dpdk_qos_ops {
+
+ /* Name of the QoS type */
+ const char *qos_name;
+
+ /* Called to construct a qos_conf object. The implementation should make
+ * the appropriate calls to configure QoS according to 'details'.
+ *
+ * The contents of 'details' should be documented as valid for 'ovs_name'
+ * in the "other_config" column in the "QoS" table in vswitchd/vswitch.xml
+ * (which is built as ovs-vswitchd.conf.db(8)).
+ *
+ * This function must return 0 if and only if it sets '*conf' to an
+ * initialized 'struct dpdk_qos_conf'.
+ *
+ * For all QoS implementations it should always be non-null.
+ */
+ int (*qos_construct)(const struct smap *details,
+ struct dpdk_qos_conf **conf);
+
+ /* Destroys the data structures allocated by the implementation as part of
+ * 'qos_conf'.
+ *
+ * For all QoS implementations it should always be non-null.
+ */
+ void (*qos_destruct)(struct dpdk_qos_conf *conf);
+
+ /* Retrieves details of 'conf' configuration into 'details'.
+ *
+ * The contents of 'details' should be documented as valid for 'ovs_name'
+ * in the "other_config" column in the "QoS" table in vswitchd/vswitch.xml
+ * (which is built as ovs-vswitchd.conf.db(8)).
+ */
+ int (*qos_get)(const struct dpdk_qos_conf *conf, struct smap *details);
+
+ /* Returns true if 'conf' is already configured according to 'details'.
+ *
+ * The contents of 'details' should be documented as valid for 'ovs_name'
+ * in the "other_config" column in the "QoS" table in vswitchd/vswitch.xml
+ * (which is built as ovs-vswitchd.conf.db(8)).
+ *
+ * For all QoS implementations it should always be non-null.
+ */
+ bool (*qos_is_equal)(const struct dpdk_qos_conf *conf,
+ const struct smap *details);
+
+ /* Modify an array of rte_mbufs. The modification is specific to
+ * each qos implementation.
+ *
+ * The function should take and array of mbufs and an int representing
+ * the current number of mbufs present in the array.
+ *
+ * After the function has performed a qos modification to the array of
+ * mbufs it returns an int representing the number of mbufs now present in
+ * the array. This value is can then be passed to the port send function
+ * along with the modified array for transmission.
+ *
+ * For all QoS implementations it should always be non-null.
+ */
+ int (*qos_run)(struct dpdk_qos_conf *qos_conf, struct rte_mbuf **pkts,
+ int pkt_cnt, bool should_steal);
+
+ /* Called to construct a QoS Queue. The implementation should make
+ * the appropriate calls to configure QoS Queue according to 'details'.
+ *
+ * The contents of 'details' should be documented as valid for 'ovs_name'
+ * in the "other_config" column in the "QoS" table in vswitchd/vswitch.xml
+ * (which is built as ovs-vswitchd.conf.db(8)).
+ *
+ * This function must return 0 if and only if it constructs
+ * QoS queue successfully.
+ */
+ int (*qos_queue_construct)(const struct smap *details,
+ uint32_t queue_id,
+ struct dpdk_qos_conf *conf);
+
+ /* Destroys the QoS Queue. */
+ void (*qos_queue_destruct)(struct dpdk_qos_conf *conf, uint32_t queue_id);
+
+ /* Retrieves details of QoS Queue configuration into 'details'.
+ *
+ * The contents of 'details' should be documented as valid for 'ovs_name'
+ * in the "other_config" column in the "QoS" table in vswitchd/vswitch.xml
+ * (which is built as ovs-vswitchd.conf.db(8)).
+ */
+ int (*qos_queue_get)(struct smap *details, uint32_t queue_id,
+ const struct dpdk_qos_conf *conf);
+
+ /* Retrieves statistics of QoS Queue configuration into 'stats'. */
+ int (*qos_queue_get_stats)(const struct dpdk_qos_conf *conf,
+ uint32_t queue_id,
+ struct netdev_queue_stats *stats);
+
+ /* Setup the 'dpdk_qos_queue_state' structure used by the dpdk queue
+ * dump functions.
+ */
+ int (*qos_queue_dump_state_init)(const struct dpdk_qos_conf *conf,
+ struct dpdk_qos_queue_state *state);
+};
+
+/* dpdk_qos_ops for each type of user space QoS implementation. */
+static const struct dpdk_qos_ops egress_policer_ops;
+static const struct dpdk_qos_ops trtcm_policer_ops;
+
+/*
+ * Array of dpdk_qos_ops, contains pointer to all supported QoS
+ * operations.
+ */
+static const struct dpdk_qos_ops *const qos_confs[] = {
+ &egress_policer_ops,
+ &trtcm_policer_ops,
+ NULL
+};
+
+static bool
+srtcm_policer_pkt_handle(struct rte_meter_srtcm *meter,
+ struct rte_meter_srtcm_profile *profile,
+ struct rte_mbuf *pkt, uint64_t time)
+{
+ uint32_t pkt_len = rte_pktmbuf_pkt_len(pkt) - sizeof(struct rte_ether_hdr);
+
+ return rte_meter_srtcm_color_blind_check(meter, profile, time, pkt_len) ==
+ RTE_COLOR_GREEN;
+}
+
+static int
+srtcm_policer_run_single_packet(struct rte_meter_srtcm *meter,
+ struct rte_meter_srtcm_profile *profile,
+ struct rte_mbuf **pkts, int pkt_cnt,
+ bool should_steal)
+{
+ int i = 0;
+ int cnt = 0;
+ struct rte_mbuf *pkt = NULL;
+ uint64_t current_time = rte_rdtsc();
+
+ for (i = 0; i < pkt_cnt; i++) {
+ pkt = pkts[i];
+ /* Handle current packet */
+ if (srtcm_policer_pkt_handle(meter, profile,
+ pkt, current_time)) {
+ if (cnt != i) {
+ pkts[cnt] = pkt;
+ }
+ cnt++;
+ } else {
+ if (should_steal) {
+ rte_pktmbuf_free(pkt);
+ }
+ }
+ }
+
+ return cnt;
+}
+
+int
+dpdk_qos_ingress_policer_run(struct dpdk_qos_ingress_policer *policer,
+ struct rte_mbuf **pkts, int pkt_cnt,
+ bool should_steal)
+{
+ int cnt = 0;
+
+ rte_spinlock_lock(&policer->policer_lock);
+ cnt = srtcm_policer_run_single_packet(&policer->in_policer,
+ &policer->in_prof,
+ pkts, pkt_cnt, should_steal);
+ rte_spinlock_unlock(&policer->policer_lock);
+
+ return cnt;
+}
+
+struct dpdk_qos_ingress_policer *
+dpdk_qos_ingress_policer_construct(uint32_t rate, uint32_t burst)
+{
+ struct dpdk_qos_ingress_policer *policer = NULL;
+ uint64_t rate_bytes;
+ uint64_t burst_bytes;
+ int err = 0;
+
+ policer = xmalloc(sizeof *policer);
+ rte_spinlock_init(&policer->policer_lock);
+
+ /* rte_meter requires bytes so convert kbits rate and burst to bytes. */
+ rate_bytes = rate * 1000ULL / 8;
+ burst_bytes = burst * 1000ULL / 8;
+
+ policer->app_srtcm_params.cir = rate_bytes;
+ policer->app_srtcm_params.cbs = burst_bytes;
+ policer->app_srtcm_params.ebs = 0;
+ err = rte_meter_srtcm_profile_config(&policer->in_prof,
+ &policer->app_srtcm_params);
+ if (!err) {
+ err = rte_meter_srtcm_config(&policer->in_policer,
+ &policer->in_prof);
+ }
+ if (err) {
+ VLOG_ERR("Could not create rte meter for ingress policer");
+ free(policer);
+ return NULL;
+ }
+
+ return policer;
+}
+
+void
+dpdk_qos_ingress_policer_destruct(struct dpdk_qos_ingress_policer *policer)
+{
+ free(policer);
+}
+
+/*
+ * Initialize QoS configuration operations.
+ */
+static void
+qos_conf_init(struct dpdk_qos_conf *conf, const struct dpdk_qos_ops *ops)
+{
+ conf->ops = ops;
+ rte_spinlock_init(&conf->lock);
+}
+
+static const struct dpdk_qos_ops *
+qos_lookup_name(const char *name)
+{
+ const struct dpdk_qos_ops *const *opsp;
+
+ for (opsp = qos_confs; *opsp != NULL; opsp++) {
+ const struct dpdk_qos_ops *ops = *opsp;
+ if (!strcmp(name, ops->qos_name)) {
+ return ops;
+ }
+ }
+ return NULL;
+}
+
+int
+dpdk_qos_run(struct dpdk_qos_conf *qos_conf, struct rte_mbuf **pkts,
+ int pkt_cnt, bool should_steal)
+{
+ int cnt;
+
+ rte_spinlock_lock(&qos_conf->lock);
+ cnt = qos_conf->ops->qos_run(qos_conf, pkts, pkt_cnt, should_steal);
+ rte_spinlock_unlock(&qos_conf->lock);
+
+ return cnt;
+}
+
+/* egress-policer details */
+
+struct egress_policer {
+ struct dpdk_qos_conf qos_conf;
+ struct rte_meter_srtcm_params app_srtcm_params;
+ struct rte_meter_srtcm egress_meter;
+ struct rte_meter_srtcm_profile egress_prof;
+};
+
+static void
+egress_policer_details_to_param(const struct smap *details,
+ struct rte_meter_srtcm_params *params)
+{
+ memset(params, 0, sizeof *params);
+ params->cir = smap_get_ullong(details, "cir", 0);
+ params->cbs = smap_get_ullong(details, "cbs", 0);
+ params->ebs = 0;
+}
+
+static int
+egress_policer_qos_construct(const struct smap *details,
+ struct dpdk_qos_conf **conf)
+{
+ struct egress_policer *policer;
+ int err = 0;
+
+ policer = xmalloc(sizeof *policer);
+ qos_conf_init(&policer->qos_conf, &egress_policer_ops);
+ egress_policer_details_to_param(details, &policer->app_srtcm_params);
+ err = rte_meter_srtcm_profile_config(&policer->egress_prof,
+ &policer->app_srtcm_params);
+ if (!err) {
+ err = rte_meter_srtcm_config(&policer->egress_meter,
+ &policer->egress_prof);
+ }
+
+ if (!err) {
+ *conf = &policer->qos_conf;
+ } else {
+ VLOG_ERR("Could not create rte meter for egress policer");
+ free(policer);
+ *conf = NULL;
+ err = -err;
+ }
+
+ return err;
+}
+
+static void
+egress_policer_qos_destruct(struct dpdk_qos_conf *conf)
+{
+ struct egress_policer *policer = CONTAINER_OF(conf, struct egress_policer,
+ qos_conf);
+ free(policer);
+}
+
+static int
+egress_policer_qos_get(const struct dpdk_qos_conf *conf, struct smap *details)
+{
+ struct egress_policer *policer =
+ CONTAINER_OF(conf, struct egress_policer, qos_conf);
+
+ smap_add_format(details, "cir", "%"PRIu64, policer->app_srtcm_params.cir);
+ smap_add_format(details, "cbs", "%"PRIu64, policer->app_srtcm_params.cbs);
+
+ return 0;
+}
+
+static bool
+egress_policer_qos_is_equal(const struct dpdk_qos_conf *conf,
+ const struct smap *details)
+{
+ struct egress_policer *policer =
+ CONTAINER_OF(conf, struct egress_policer, qos_conf);
+ struct rte_meter_srtcm_params params;
+
+ egress_policer_details_to_param(details, ¶ms);
+
+ return !memcmp(¶ms, &policer->app_srtcm_params, sizeof params);
+}
+
+static int
+egress_policer_run(struct dpdk_qos_conf *conf, struct rte_mbuf **pkts,
+ int pkt_cnt, bool should_steal)
+{
+ int cnt = 0;
+ struct egress_policer *policer =
+ CONTAINER_OF(conf, struct egress_policer, qos_conf);
+
+ cnt = srtcm_policer_run_single_packet(&policer->egress_meter,
+ &policer->egress_prof, pkts,
+ pkt_cnt, should_steal);
+
+ return cnt;
+}
+
+static const struct dpdk_qos_ops egress_policer_ops = {
+ .qos_name = "egress-policer", /* qos_name */
+ .qos_construct = egress_policer_qos_construct,
+ .qos_destruct = egress_policer_qos_destruct,
+ .qos_get = egress_policer_qos_get,
+ .qos_is_equal = egress_policer_qos_is_equal,
+ .qos_run = egress_policer_run
+};
+
+/* trtcm-policer details */
+
+struct trtcm_policer {
+ struct dpdk_qos_conf qos_conf;
+ struct rte_meter_trtcm_rfc4115_params meter_params;
+ struct rte_meter_trtcm_rfc4115_profile meter_profile;
+ struct rte_meter_trtcm_rfc4115 meter;
+ struct netdev_queue_stats stats;
+ struct hmap queues;
+};
+
+struct trtcm_policer_queue {
+ struct hmap_node hmap_node;
+ uint32_t queue_id;
+ struct rte_meter_trtcm_rfc4115_params meter_params;
+ struct rte_meter_trtcm_rfc4115_profile meter_profile;
+ struct rte_meter_trtcm_rfc4115 meter;
+ struct netdev_queue_stats stats;
+};
+
+static void
+trtcm_policer_details_to_param(const struct smap *details,
+ struct rte_meter_trtcm_rfc4115_params *params)
+{
+ memset(params, 0, sizeof *params);
+ params->cir = smap_get_ullong(details, "cir", 0);
+ params->eir = smap_get_ullong(details, "eir", 0);
+ params->cbs = smap_get_ullong(details, "cbs", 0);
+ params->ebs = smap_get_ullong(details, "ebs", 0);
+}
+
+static void
+trtcm_policer_param_to_detail(
+ const struct rte_meter_trtcm_rfc4115_params *params,
+ struct smap *details)
+{
+ smap_add_format(details, "cir", "%"PRIu64, params->cir);
+ smap_add_format(details, "eir", "%"PRIu64, params->eir);
+ smap_add_format(details, "cbs", "%"PRIu64, params->cbs);
+ smap_add_format(details, "ebs", "%"PRIu64, params->ebs);
+}
+
+
+static int
+trtcm_policer_qos_construct(const struct smap *details,
+ struct dpdk_qos_conf **conf)
+{
+ struct trtcm_policer *policer;
+ int err = 0;
+
+ policer = xmalloc(sizeof *policer);
+ qos_conf_init(&policer->qos_conf, &trtcm_policer_ops);
+ trtcm_policer_details_to_param(details, &policer->meter_params);
+ err = rte_meter_trtcm_rfc4115_profile_config(&policer->meter_profile,
+ &policer->meter_params);
+ if (!err) {
+ err = rte_meter_trtcm_rfc4115_config(&policer->meter,
+ &policer->meter_profile);
+ }
+
+ if (!err) {
+ *conf = &policer->qos_conf;
+ memset(&policer->stats, 0, sizeof policer->stats);
+ hmap_init(&policer->queues);
+ } else {
+ free(policer);
+ *conf = NULL;
+ err = -err;
+ }
+
+ return err;
+}
+
+static void
+trtcm_policer_qos_destruct(struct dpdk_qos_conf *conf)
+{
+ struct trtcm_policer_queue *queue;
+ struct trtcm_policer *policer = CONTAINER_OF(conf, struct trtcm_policer,
+ qos_conf);
+
+ HMAP_FOR_EACH_SAFE (queue, hmap_node, &policer->queues) {
+ hmap_remove(&policer->queues, &queue->hmap_node);
+ free(queue);
+ }
+ hmap_destroy(&policer->queues);
+ free(policer);
+}
+
+static int
+trtcm_policer_qos_get(const struct dpdk_qos_conf *conf, struct smap *details)
+{
+ struct trtcm_policer *policer = CONTAINER_OF(conf, struct trtcm_policer,
+ qos_conf);
+
+ trtcm_policer_param_to_detail(&policer->meter_params, details);
+ return 0;
+}
+
+static bool
+trtcm_policer_qos_is_equal(const struct dpdk_qos_conf *conf,
+ const struct smap *details)
+{
+ struct trtcm_policer *policer = CONTAINER_OF(conf, struct trtcm_policer,
+ qos_conf);
+ struct rte_meter_trtcm_rfc4115_params params;
+
+ trtcm_policer_details_to_param(details, ¶ms);
+
+ return !memcmp(¶ms, &policer->meter_params, sizeof params);
+}
+
+static struct trtcm_policer_queue *
+trtcm_policer_qos_find_queue(struct trtcm_policer *policer, uint32_t queue_id)
+{
+ struct trtcm_policer_queue *queue;
+ HMAP_FOR_EACH_WITH_HASH (queue, hmap_node, hash_2words(queue_id, 0),
+ &policer->queues) {
+ if (queue->queue_id == queue_id) {
+ return queue;
+ }
+ }
+ return NULL;
+}
+
+static bool
+trtcm_policer_run_single_packet(struct trtcm_policer *policer,
+ struct rte_mbuf *pkt, uint64_t time)
+{
+ enum rte_color pkt_color;
+ struct trtcm_policer_queue *queue;
+ uint32_t pkt_len = rte_pktmbuf_pkt_len(pkt) - sizeof(struct rte_ether_hdr);
+ struct dp_packet *dpkt = CONTAINER_OF(pkt, struct dp_packet, mbuf);
+
+ queue = trtcm_policer_qos_find_queue(policer, dpkt->md.skb_priority);
+ if (!queue) {
+ /* If no queue is found, use the default queue, which MUST exist. */
+ queue = trtcm_policer_qos_find_queue(policer, 0);
+ if (!queue) {
+ return false;
+ }
+ }
+
+ pkt_color =
+ rte_meter_trtcm_rfc4115_color_blind_check(&queue->meter,
+ &queue->meter_profile,
+ time, pkt_len);
+
+ if (pkt_color == RTE_COLOR_RED) {
+ queue->stats.tx_errors++;
+ } else {
+ queue->stats.tx_bytes += pkt_len;
+ queue->stats.tx_packets++;
+ }
+
+ pkt_color =
+ rte_meter_trtcm_rfc4115_color_aware_check(&policer->meter,
+ &policer->meter_profile,
+ time, pkt_len, pkt_color);
+
+ if (pkt_color == RTE_COLOR_RED) {
+ policer->stats.tx_errors++;
+ return false;
+ }
+
+ policer->stats.tx_bytes += pkt_len;
+ policer->stats.tx_packets++;
+ return true;
+}
+
+static int
+trtcm_policer_run(struct dpdk_qos_conf *conf, struct rte_mbuf **pkts,
+ int pkt_cnt, bool should_steal)
+{
+ int i = 0;
+ int cnt = 0;
+ struct rte_mbuf *pkt = NULL;
+ uint64_t current_time = rte_rdtsc();
+
+ struct trtcm_policer *policer = CONTAINER_OF(conf, struct trtcm_policer,
+ qos_conf);
+
+ for (i = 0; i < pkt_cnt; i++) {
+ pkt = pkts[i];
+
+ if (trtcm_policer_run_single_packet(policer, pkt, current_time)) {
+ if (cnt != i) {
+ pkts[cnt] = pkt;
+ }
+ cnt++;
+ } else {
+ if (should_steal) {
+ rte_pktmbuf_free(pkt);
+ }
+ }
+ }
+ return cnt;
+}
+
+static int
+trtcm_policer_qos_queue_construct(const struct smap *details,
+ uint32_t queue_id,
+ struct dpdk_qos_conf *conf)
+{
+ int err = 0;
+ struct trtcm_policer_queue *queue;
+ struct trtcm_policer *policer = CONTAINER_OF(conf, struct trtcm_policer,
+ qos_conf);
+
+ queue = trtcm_policer_qos_find_queue(policer, queue_id);
+ if (!queue) {
+ queue = xmalloc(sizeof *queue);
+ queue->queue_id = queue_id;
+ memset(&queue->stats, 0, sizeof queue->stats);
+ queue->stats.created = time_msec();
+ hmap_insert(&policer->queues, &queue->hmap_node,
+ hash_2words(queue_id, 0));
+ }
+ if (queue_id == 0 && smap_is_empty(details)) {
+ /* No default queue configured, use port values */
+ memcpy(&queue->meter_params, &policer->meter_params,
+ sizeof queue->meter_params);
+ } else {
+ trtcm_policer_details_to_param(details, &queue->meter_params);
+ }
+
+ err = rte_meter_trtcm_rfc4115_profile_config(&queue->meter_profile,
+ &queue->meter_params);
+
+ if (!err) {
+ err = rte_meter_trtcm_rfc4115_config(&queue->meter,
+ &queue->meter_profile);
+ }
+ if (err) {
+ hmap_remove(&policer->queues, &queue->hmap_node);
+ free(queue);
+ err = -err;
+ }
+ return err;
+}
+
+static void
+trtcm_policer_qos_queue_destruct(struct dpdk_qos_conf *conf, uint32_t queue_id)
+{
+ struct trtcm_policer_queue *queue;
+ struct trtcm_policer *policer = CONTAINER_OF(conf, struct trtcm_policer,
+ qos_conf);
+
+ queue = trtcm_policer_qos_find_queue(policer, queue_id);
+ if (queue) {
+ hmap_remove(&policer->queues, &queue->hmap_node);
+ free(queue);
+ }
+}
+
+static int
+trtcm_policer_qos_queue_get(struct smap *details, uint32_t queue_id,
+ const struct dpdk_qos_conf *conf)
+{
+ struct trtcm_policer_queue *queue;
+ struct trtcm_policer *policer = CONTAINER_OF(conf, struct trtcm_policer,
+ qos_conf);
+
+ queue = trtcm_policer_qos_find_queue(policer, queue_id);
+ if (!queue) {
+ return EINVAL;
+ }
+
+ trtcm_policer_param_to_detail(&queue->meter_params, details);
+ return 0;
+}
+
+static int
+trtcm_policer_qos_queue_get_stats(const struct dpdk_qos_conf *conf,
+ uint32_t queue_id,
+ struct netdev_queue_stats *stats)
+{
+ struct trtcm_policer_queue *queue;
+ struct trtcm_policer *policer = CONTAINER_OF(conf, struct trtcm_policer,
+ qos_conf);
+
+ queue = trtcm_policer_qos_find_queue(policer, queue_id);
+ if (!queue) {
+ return EINVAL;
+ }
+ memcpy(stats, &queue->stats, sizeof *stats);
+ return 0;
+}
+
+static int
+trtcm_policer_qos_queue_dump_state_init(const struct dpdk_qos_conf *conf,
+ struct dpdk_qos_queue_state *state)
+{
+ uint32_t i = 0;
+ struct trtcm_policer_queue *queue;
+ struct trtcm_policer *policer = CONTAINER_OF(conf, struct trtcm_policer,
+ qos_conf);
+
+ state->n_queues = hmap_count(&policer->queues);
+ state->cur_queue = 0;
+ state->queues = xmalloc(state->n_queues * sizeof *state->queues);
+
+ HMAP_FOR_EACH (queue, hmap_node, &policer->queues) {
+ state->queues[i++] = queue->queue_id;
+ }
+ return 0;
+}
+
+static const struct dpdk_qos_ops trtcm_policer_ops = {
+ .qos_name = "trtcm-policer",
+ .qos_construct = trtcm_policer_qos_construct,
+ .qos_destruct = trtcm_policer_qos_destruct,
+ .qos_get = trtcm_policer_qos_get,
+ .qos_is_equal = trtcm_policer_qos_is_equal,
+ .qos_run = trtcm_policer_run,
+ .qos_queue_construct = trtcm_policer_qos_queue_construct,
+ .qos_queue_destruct = trtcm_policer_qos_queue_destruct,
+ .qos_queue_get = trtcm_policer_qos_queue_get,
+ .qos_queue_get_stats = trtcm_policer_qos_queue_get_stats,
+ .qos_queue_dump_state_init = trtcm_policer_qos_queue_dump_state_init
+};
+
static void
parse_mempool_config(const struct smap *ovs_other_config)
{
@@ -462,6 +1163,259 @@ parse_user_mempools_list(const struct smap *ovs_other_config)
free(copy);
}
+int
+netdev_dpdk_common_set_policing(struct netdev_dpdk_common *common,
+ uint32_t policer_rate, uint32_t policer_burst)
+{
+ struct dpdk_qos_ingress_policer *policer;
+
+ /* Force to 0 if no rate specified,
+ * default to 8000 kbits if burst is 0,
+ * else stick with user-specified value.
+ */
+ policer_burst = (!policer_rate ? 0
+ : !policer_burst ? 8000
+ : policer_burst);
+
+ policer = ovsrcu_get_protected(struct dpdk_qos_ingress_policer *,
+ &common->ingress_policer);
+
+ if (common->policer_rate == policer_rate &&
+ common->policer_burst == policer_burst) {
+ /* Assume that settings haven't changed since we last set them. */
+ return 0;
+ }
+
+ /* Destroy any existing ingress policer for the device if one exists */
+ if (policer) {
+ ovsrcu_postpone__((void (*)(void *)) dpdk_qos_ingress_policer_destruct,
+ policer);
+ }
+
+ if (policer_rate != 0) {
+ policer = dpdk_qos_ingress_policer_construct(policer_rate,
+ policer_burst);
+ } else {
+ policer = NULL;
+ }
+ ovsrcu_set(&common->ingress_policer, policer);
+ common->policer_rate = policer_rate;
+ common->policer_burst = policer_burst;
+
+ return 0;
+}
+
+/* QoS Functions */
+
+int
+netdev_dpdk_common_get_qos_types(const struct netdev *netdev OVS_UNUSED,
+ struct sset *types)
+{
+ const struct dpdk_qos_ops *const *opsp;
+
+ for (opsp = qos_confs; *opsp != NULL; opsp++) {
+ const struct dpdk_qos_ops *ops = *opsp;
+ if (ops->qos_construct && ops->qos_name[0] != '\0') {
+ sset_add(types, ops->qos_name);
+ }
+ }
+ return 0;
+}
+
+int
+netdev_dpdk_common_get_qos(const struct netdev_dpdk_common *common,
+ const char **typep, struct smap *details)
+{
+ struct dpdk_qos_conf *qos_conf;
+ int error = 0;
+
+ qos_conf = ovsrcu_get_protected(struct dpdk_qos_conf *, &common->qos_conf);
+ if (qos_conf) {
+ *typep = qos_conf->ops->qos_name;
+ error = (qos_conf->ops->qos_get
+ ? qos_conf->ops->qos_get(qos_conf, details) : 0);
+ } else {
+ /* No QoS configuration set, return an empty string */
+ *typep = "";
+ }
+
+ return error;
+}
+
+int
+netdev_dpdk_common_set_qos(struct netdev_dpdk_common *common,
+ const char *type, const struct smap *details)
+{
+ struct netdev *netdev = &common->up;
+ const struct dpdk_qos_ops *new_ops = NULL;
+ struct dpdk_qos_conf *qos_conf, *new_qos_conf = NULL;
+ int error = 0;
+
+ qos_conf = ovsrcu_get_protected(struct dpdk_qos_conf *, &common->qos_conf);
+
+ new_ops = qos_lookup_name(type);
+
+ if (!new_ops || !new_ops->qos_construct) {
+ new_qos_conf = NULL;
+ if (type && type[0]) {
+ error = EOPNOTSUPP;
+ }
+ } else if (qos_conf && qos_conf->ops == new_ops
+ && qos_conf->ops->qos_is_equal(qos_conf, details)) {
+ new_qos_conf = qos_conf;
+ } else {
+ error = new_ops->qos_construct(details, &new_qos_conf);
+ }
+
+ if (error) {
+ VLOG_ERR("Failed to set QoS type %s on port %s: %s",
+ type, netdev->name, rte_strerror(error));
+ }
+
+ if (new_qos_conf != qos_conf) {
+ ovsrcu_set(&common->qos_conf, new_qos_conf);
+ if (qos_conf) {
+ ovsrcu_postpone(qos_conf->ops->qos_destruct, qos_conf);
+ }
+ }
+
+ return error;
+}
+
+int
+netdev_dpdk_common_get_queue(const struct netdev_dpdk_common *common,
+ uint32_t queue_id, struct smap *details)
+{
+ struct dpdk_qos_conf *qos_conf;
+ int error = 0;
+
+ qos_conf = ovsrcu_get_protected(struct dpdk_qos_conf *, &common->qos_conf);
+ if (!qos_conf || !qos_conf->ops || !qos_conf->ops->qos_queue_get) {
+ error = EOPNOTSUPP;
+ } else {
+ error = qos_conf->ops->qos_queue_get(details, queue_id, qos_conf);
+ }
+
+ return error;
+}
+
+int
+netdev_dpdk_common_set_queue(struct netdev_dpdk_common *common,
+ uint32_t queue_id, const struct smap *details)
+{
+ struct netdev *netdev = &common->up;
+ struct dpdk_qos_conf *qos_conf;
+ int error = 0;
+
+ qos_conf = ovsrcu_get_protected(struct dpdk_qos_conf *, &common->qos_conf);
+ if (!qos_conf || !qos_conf->ops || !qos_conf->ops->qos_queue_construct) {
+ error = EOPNOTSUPP;
+ } else {
+ error = qos_conf->ops->qos_queue_construct(details, queue_id,
+ qos_conf);
+ }
+
+ if (error && error != EOPNOTSUPP) {
+ VLOG_ERR("Failed to set QoS queue %d on port %s: %s",
+ queue_id, netdev->name, rte_strerror(error));
+ }
+
+ return error;
+}
+
+int
+netdev_dpdk_common_delete_queue(struct netdev_dpdk_common *common,
+ uint32_t queue_id)
+{
+ struct dpdk_qos_conf *qos_conf;
+ int error = 0;
+
+ qos_conf = ovsrcu_get_protected(struct dpdk_qos_conf *, &common->qos_conf);
+ if (qos_conf && qos_conf->ops && qos_conf->ops->qos_queue_destruct) {
+ qos_conf->ops->qos_queue_destruct(qos_conf, queue_id);
+ } else {
+ error = EOPNOTSUPP;
+ }
+
+ return error;
+}
+
+int
+netdev_dpdk_common_get_queue_stats(const struct netdev_dpdk_common *common,
+ uint32_t queue_id,
+ struct netdev_queue_stats *stats)
+{
+ struct dpdk_qos_conf *qos_conf;
+ int error = 0;
+
+ qos_conf = ovsrcu_get_protected(struct dpdk_qos_conf *, &common->qos_conf);
+ if (qos_conf && qos_conf->ops && qos_conf->ops->qos_queue_get_stats) {
+ qos_conf->ops->qos_queue_get_stats(qos_conf, queue_id, stats);
+ } else {
+ error = EOPNOTSUPP;
+ }
+
+ return error;
+}
+
+int
+netdev_dpdk_common_queue_dump_start(const struct netdev_dpdk_common *common,
+ void **statep)
+{
+ struct dpdk_qos_conf *qos_conf;
+ int error = 0;
+
+ qos_conf = ovsrcu_get_protected(struct dpdk_qos_conf *, &common->qos_conf);
+ if (qos_conf && qos_conf->ops
+ && qos_conf->ops->qos_queue_dump_state_init) {
+ struct dpdk_qos_queue_state *state;
+
+ *statep = state = xmalloc(sizeof *state);
+ error = qos_conf->ops->qos_queue_dump_state_init(qos_conf, state);
+ } else {
+ error = EOPNOTSUPP;
+ }
+
+ return error;
+}
+
+int
+netdev_dpdk_common_queue_dump_next(const struct netdev_dpdk_common *common,
+ void *state_, uint32_t *queue_idp,
+ struct smap *details)
+{
+ struct dpdk_qos_conf *qos_conf;
+ struct dpdk_qos_queue_state *state = state_;
+ int error = EOF;
+
+ qos_conf = ovsrcu_get_protected(struct dpdk_qos_conf *, &common->qos_conf);
+ if (qos_conf) {
+ while (state->cur_queue < state->n_queues) {
+ uint32_t queue_id = state->queues[state->cur_queue++];
+
+ if (qos_conf->ops && qos_conf->ops->qos_queue_get) {
+ *queue_idp = queue_id;
+ error = qos_conf->ops->qos_queue_get(details, queue_id,
+ qos_conf);
+ break;
+ }
+ }
+ }
+
+ return error;
+}
+
+int
+netdev_dpdk_common_queue_dump_done(const struct netdev *netdev OVS_UNUSED,
+ void *state_)
+{
+ struct dpdk_qos_queue_state *state = state_;
+
+ free(state->queues);
+ free(state);
+ return 0;
+}
+
void
dpdk_mp_init(const struct smap *ovs_other_config)
{
@@ -33,8 +33,8 @@
#include "packets.h"
struct dpdk_tx_queue;
-struct ingress_policer;
-struct qos_conf;
+struct dpdk_qos_ingress_policer;
+struct dpdk_qos_conf;
struct smap;
extern struct ovs_mutex dpdk_mutex;
@@ -141,10 +141,10 @@ struct netdev_dpdk_common {
struct ovs_list list_node;
/* QoS configuration and lock for the device */
- OVSRCU_TYPE(struct qos_conf *) qos_conf;
+ OVSRCU_TYPE(struct dpdk_qos_conf *) qos_conf;
/* Ingress Policer */
- OVSRCU_TYPE(struct ingress_policer *) ingress_policer;
+ OVSRCU_TYPE(struct dpdk_qos_ingress_policer *) ingress_policer;
uint32_t policer_rate;
uint32_t policer_burst;
@@ -285,4 +285,46 @@ struct dpdk_mp * dpdk_mp_get(struct dpdk_mp_config *cfg);
void dpdk_mp_put(struct dpdk_mp *dmp);
void dpdk_mp_dump(FILE *stream, struct dpdk_mp *dmp);
+/* Quality of Service */
+
+int dpdk_qos_run(struct dpdk_qos_conf *qos_conf, struct rte_mbuf **pkts,
+ int pkt_cnt, bool should_steal);
+
+/* Ingress policer */
+struct dpdk_qos_ingress_policer *
+ dpdk_qos_ingress_policer_construct(uint32_t rate, uint32_t burst);
+void dpdk_qos_ingress_policer_destruct(struct dpdk_qos_ingress_policer *);
+int dpdk_qos_ingress_policer_run(struct dpdk_qos_ingress_policer *policer,
+ struct rte_mbuf **pkts, int pkt_cnt,
+ bool should_steal);
+
+int netdev_dpdk_common_set_policing(struct netdev_dpdk_common *common,
+ uint32_t policer_rate,
+ uint32_t policer_burst);
+
+int netdev_dpdk_common_get_qos_types(const struct netdev *netdev,
+ struct sset *types);
+int netdev_dpdk_common_get_qos(const struct netdev_dpdk_common *common,
+ const char **typep, struct smap *details);
+int netdev_dpdk_common_set_qos(struct netdev_dpdk_common *common,
+ const char *type, const struct smap *details);
+int netdev_dpdk_common_get_queue(const struct netdev_dpdk_common *common,
+ uint32_t queue_id, struct smap *details);
+int netdev_dpdk_common_set_queue(struct netdev_dpdk_common *common,
+ uint32_t queue_id,
+ const struct smap *details);
+int netdev_dpdk_common_delete_queue(struct netdev_dpdk_common *common,
+ uint32_t queue_id);
+int netdev_dpdk_common_get_queue_stats(const struct netdev_dpdk_common *common,
+ uint32_t queue_id,
+ struct netdev_queue_stats *stats);
+int
+netdev_dpdk_common_queue_dump_start(const struct netdev_dpdk_common *common,
+ void **statep);
+int netdev_dpdk_common_queue_dump_next(const struct netdev_dpdk_common *common,
+ void *state_, uint32_t *queue_idp,
+ struct smap *details);
+int netdev_dpdk_common_queue_dump_done(const struct netdev *netdev,
+ void *state_);
+
#endif /* NETDEV_DPDK_COMMON_H */
@@ -157,143 +157,6 @@ static const struct rte_vhost_device_ops virtio_net_device_ops =
.destroy_connection = destroy_connection,
};
-/* Quality of Service */
-
-/* An instance of a QoS configuration. Always associated with a particular
- * network device.
- *
- * Each QoS implementation subclasses this with whatever additional data it
- * needs.
- */
-struct qos_conf {
- const struct dpdk_qos_ops *ops;
- rte_spinlock_t lock;
-};
-
-/* QoS queue information used by the netdev queue dump functions. */
-struct netdev_dpdk_queue_state {
- uint32_t *queues;
- size_t cur_queue;
- size_t n_queues;
-};
-
-/* A particular implementation of dpdk QoS operations.
- *
- * The functions below return 0 if successful or a positive errno value on
- * failure, except where otherwise noted. All of them must be provided, except
- * where otherwise noted.
- */
-struct dpdk_qos_ops {
-
- /* Name of the QoS type */
- const char *qos_name;
-
- /* Called to construct a qos_conf object. The implementation should make
- * the appropriate calls to configure QoS according to 'details'.
- *
- * The contents of 'details' should be documented as valid for 'ovs_name'
- * in the "other_config" column in the "QoS" table in vswitchd/vswitch.xml
- * (which is built as ovs-vswitchd.conf.db(8)).
- *
- * This function must return 0 if and only if it sets '*conf' to an
- * initialized 'struct qos_conf'.
- *
- * For all QoS implementations it should always be non-null.
- */
- int (*qos_construct)(const struct smap *details, struct qos_conf **conf);
-
- /* Destroys the data structures allocated by the implementation as part of
- * 'qos_conf'.
- *
- * For all QoS implementations it should always be non-null.
- */
- void (*qos_destruct)(struct qos_conf *conf);
-
- /* Retrieves details of 'conf' configuration into 'details'.
- *
- * The contents of 'details' should be documented as valid for 'ovs_name'
- * in the "other_config" column in the "QoS" table in vswitchd/vswitch.xml
- * (which is built as ovs-vswitchd.conf.db(8)).
- */
- int (*qos_get)(const struct qos_conf *conf, struct smap *details);
-
- /* Returns true if 'conf' is already configured according to 'details'.
- *
- * The contents of 'details' should be documented as valid for 'ovs_name'
- * in the "other_config" column in the "QoS" table in vswitchd/vswitch.xml
- * (which is built as ovs-vswitchd.conf.db(8)).
- *
- * For all QoS implementations it should always be non-null.
- */
- bool (*qos_is_equal)(const struct qos_conf *conf,
- const struct smap *details);
-
- /* Modify an array of rte_mbufs. The modification is specific to
- * each qos implementation.
- *
- * The function should take and array of mbufs and an int representing
- * the current number of mbufs present in the array.
- *
- * After the function has performed a qos modification to the array of
- * mbufs it returns an int representing the number of mbufs now present in
- * the array. This value is can then be passed to the port send function
- * along with the modified array for transmission.
- *
- * For all QoS implementations it should always be non-null.
- */
- int (*qos_run)(struct qos_conf *qos_conf, struct rte_mbuf **pkts,
- int pkt_cnt, bool should_steal);
-
- /* Called to construct a QoS Queue. The implementation should make
- * the appropriate calls to configure QoS Queue according to 'details'.
- *
- * The contents of 'details' should be documented as valid for 'ovs_name'
- * in the "other_config" column in the "QoS" table in vswitchd/vswitch.xml
- * (which is built as ovs-vswitchd.conf.db(8)).
- *
- * This function must return 0 if and only if it constructs
- * QoS queue successfully.
- */
- int (*qos_queue_construct)(const struct smap *details,
- uint32_t queue_id, struct qos_conf *conf);
-
- /* Destroys the QoS Queue. */
- void (*qos_queue_destruct)(struct qos_conf *conf, uint32_t queue_id);
-
- /* Retrieves details of QoS Queue configuration into 'details'.
- *
- * The contents of 'details' should be documented as valid for 'ovs_name'
- * in the "other_config" column in the "QoS" table in vswitchd/vswitch.xml
- * (which is built as ovs-vswitchd.conf.db(8)).
- */
- int (*qos_queue_get)(struct smap *details, uint32_t queue_id,
- const struct qos_conf *conf);
-
- /* Retrieves statistics of QoS Queue configuration into 'stats'. */
- int (*qos_queue_get_stats)(const struct qos_conf *conf, uint32_t queue_id,
- struct netdev_queue_stats *stats);
-
- /* Setup the 'netdev_dpdk_queue_state' structure used by the dpdk queue
- * dump functions.
- */
- int (*qos_queue_dump_state_init)(const struct qos_conf *conf,
- struct netdev_dpdk_queue_state *state);
-};
-
-/* dpdk_qos_ops for each type of user space QoS implementation. */
-static const struct dpdk_qos_ops egress_policer_ops;
-static const struct dpdk_qos_ops trtcm_policer_ops;
-
-/*
- * Array of dpdk_qos_ops, contains pointer to all supported QoS
- * operations.
- */
-static const struct dpdk_qos_ops *const qos_confs[] = {
- &egress_policer_ops,
- &trtcm_policer_ops,
- NULL
-};
-
struct ovs_mutex dpdk_mutex = OVS_MUTEX_INITIALIZER;
/* Contains all 'struct dpdk_dev's. */
@@ -314,13 +177,6 @@ struct dpdk_tx_queue {
);
};
-struct ingress_policer {
- struct rte_meter_srtcm_params app_srtcm_params;
- struct rte_meter_srtcm in_policer;
- struct rte_meter_srtcm_profile in_prof;
- rte_spinlock_t policer_lock;
-};
-
enum dpdk_rx_steer_flags {
DPDK_RX_STEER_LACP = 1 << 0,
};
@@ -408,10 +264,10 @@ struct netdev_dpdk {
struct ovs_list list_node OVS_GUARDED_BY(dpdk_mutex);
/* QoS configuration and lock for the device */
- OVSRCU_TYPE(struct qos_conf *) qos_conf;
+ OVSRCU_TYPE(struct dpdk_qos_conf *) qos_conf;
/* Ingress Policer */
- OVSRCU_TYPE(struct ingress_policer *) ingress_policer;
+ OVSRCU_TYPE(struct dpdk_qos_ingress_policer *) ingress_policer;
uint32_t policer_rate;
uint32_t policer_burst;
@@ -506,9 +362,6 @@ static void netdev_dpdk_clear_xstats(struct netdev_dpdk *dev);
int netdev_dpdk_get_vid(const struct netdev_dpdk *dev);
-struct ingress_policer *
-netdev_dpdk_get_ingress_policer(const struct netdev_dpdk *dev);
-
static void netdev_dpdk_mbuf_dump(const char *prefix, const char *message,
const struct rte_mbuf *);
@@ -1265,7 +1118,7 @@ common_destruct(struct netdev_dpdk_common *common)
dpdk_mp_put(common->dpdk_mp);
ovs_list_remove(&common->list_node);
- free(ovsrcu_get_protected(struct ingress_policer *,
+ free(ovsrcu_get_protected(struct dpdk_qos_ingress_policer *,
&common->ingress_policer));
free(common->sw_stats);
ovs_mutex_destroy(&common->mutex);
@@ -2429,62 +2282,6 @@ netdev_dpdk_eth_tx_burst(struct netdev_dpdk *dev, int qid,
return cnt - nb_tx;
}
-static inline bool
-netdev_dpdk_srtcm_policer_pkt_handle(struct rte_meter_srtcm *meter,
- struct rte_meter_srtcm_profile *profile,
- struct rte_mbuf *pkt, uint64_t time)
-{
- uint32_t pkt_len = rte_pktmbuf_pkt_len(pkt) - sizeof(struct rte_ether_hdr);
-
- return rte_meter_srtcm_color_blind_check(meter, profile, time, pkt_len) ==
- RTE_COLOR_GREEN;
-}
-
-static int
-srtcm_policer_run_single_packet(struct rte_meter_srtcm *meter,
- struct rte_meter_srtcm_profile *profile,
- struct rte_mbuf **pkts, int pkt_cnt,
- bool should_steal)
-{
- int i = 0;
- int cnt = 0;
- struct rte_mbuf *pkt = NULL;
- uint64_t current_time = rte_rdtsc();
-
- for (i = 0; i < pkt_cnt; i++) {
- pkt = pkts[i];
- /* Handle current packet */
- if (netdev_dpdk_srtcm_policer_pkt_handle(meter, profile,
- pkt, current_time)) {
- if (cnt != i) {
- pkts[cnt] = pkt;
- }
- cnt++;
- } else {
- if (should_steal) {
- rte_pktmbuf_free(pkt);
- }
- }
- }
-
- return cnt;
-}
-
-static int
-ingress_policer_run(struct ingress_policer *policer, struct rte_mbuf **pkts,
- int pkt_cnt, bool should_steal)
-{
- int cnt = 0;
-
- rte_spinlock_lock(&policer->policer_lock);
- cnt = srtcm_policer_run_single_packet(&policer->in_policer,
- &policer->in_prof,
- pkts, pkt_cnt, should_steal);
- rte_spinlock_unlock(&policer->policer_lock);
-
- return cnt;
-}
-
static bool
is_vhost_running(struct netdev_dpdk *dev)
{
@@ -2500,7 +2297,7 @@ netdev_dpdk_vhost_rxq_recv(struct netdev_rxq *rxq,
{
struct netdev_dpdk_common *common = netdev_dpdk_common_cast(rxq->netdev);
struct netdev_dpdk *dev = netdev_dpdk_cast(rxq->netdev);
- struct ingress_policer *policer = netdev_dpdk_get_ingress_policer(dev);
+ struct dpdk_qos_ingress_policer *policer;
uint16_t nb_rx = 0;
uint16_t qos_drops = 0;
int qid = rxq->queue_id * VIRTIO_QNUM + VIRTIO_TXQ;
@@ -2528,9 +2325,11 @@ netdev_dpdk_vhost_rxq_recv(struct netdev_rxq *rxq,
}
}
+ policer = ovsrcu_get(struct dpdk_qos_ingress_policer *,
+ &common->ingress_policer);
if (policer) {
qos_drops = nb_rx;
- nb_rx = ingress_policer_run(policer,
+ nb_rx = dpdk_qos_ingress_policer_run(policer,
(struct rte_mbuf **) batch->packets,
nb_rx, true);
qos_drops -= nb_rx;
@@ -2563,8 +2362,7 @@ netdev_dpdk_eth_rxq_recv(struct netdev_rxq *rxq, struct dp_packet_batch *batch,
{
struct netdev_dpdk_common *common = netdev_dpdk_common_cast(rxq->netdev);
struct netdev_rxq_dpdk *rx = netdev_rxq_dpdk_cast(rxq);
- struct netdev_dpdk *dev = netdev_dpdk_cast(rxq->netdev);
- struct ingress_policer *policer = netdev_dpdk_get_ingress_policer(dev);
+ struct dpdk_qos_ingress_policer *policer;
int nb_rx;
int dropped = 0;
@@ -2587,9 +2385,11 @@ netdev_dpdk_eth_rxq_recv(struct netdev_rxq *rxq, struct dp_packet_batch *batch,
}
}
+ policer = ovsrcu_get(struct dpdk_qos_ingress_policer *,
+ &common->ingress_policer);
if (policer) {
dropped = nb_rx;
- nb_rx = ingress_policer_run(policer,
+ nb_rx = dpdk_qos_ingress_policer_run(policer,
(struct rte_mbuf **) batch->packets,
nb_rx, true);
dropped -= nb_rx;
@@ -2609,22 +2409,6 @@ netdev_dpdk_eth_rxq_recv(struct netdev_rxq *rxq, struct dp_packet_batch *batch,
return 0;
}
-static inline int
-netdev_dpdk_qos_run(struct netdev_dpdk_common *common, struct rte_mbuf **pkts,
- int cnt, bool should_steal)
-{
- struct qos_conf *qos_conf;
-
- qos_conf = ovsrcu_get(struct qos_conf *, &common->qos_conf);
- if (qos_conf) {
- rte_spinlock_lock(&qos_conf->lock);
- cnt = qos_conf->ops->qos_run(qos_conf, pkts, cnt, should_steal);
- rte_spinlock_unlock(&qos_conf->lock);
- }
-
- return cnt;
-}
-
static int
netdev_dpdk_filter_packet_len(struct netdev_dpdk_common *common,
struct rte_mbuf **pkts, int pkt_cnt)
@@ -2842,6 +2626,7 @@ netdev_dpdk_common_send(struct netdev_dpdk_common *common,
struct rte_mbuf **pkts = (struct rte_mbuf **) batch->packets;
size_t cnt, pkt_cnt = dp_packet_batch_size(batch);
struct netdev *netdev = &common->up;
+ struct dpdk_qos_conf *qos_conf;
struct dp_packet *packet;
bool need_copy = false;
@@ -2874,8 +2659,11 @@ netdev_dpdk_common_send(struct netdev_dpdk_common *common,
}
/* Apply Quality of Service policy. */
- cnt = netdev_dpdk_qos_run(common, pkts, pkt_cnt, true);
- stats->tx_qos_drops += pkt_cnt - cnt;
+ qos_conf = ovsrcu_get(struct dpdk_qos_conf *, &common->qos_conf);
+ if (qos_conf) {
+ cnt = dpdk_qos_run(qos_conf, pkts, pkt_cnt, true);
+ stats->tx_qos_drops += pkt_cnt - cnt;
+ }
return cnt;
}
@@ -3779,84 +3567,38 @@ netdev_dpdk_eth_get_duplex(const struct netdev *netdev, bool *full_duplex)
return err;
}
-static struct ingress_policer *
-netdev_dpdk_policer_construct(uint32_t rate, uint32_t burst)
+static int
+netdev_dpdk_eth_set_policing(struct netdev *netdev, uint32_t policer_rate,
+ uint32_t policer_burst,
+ uint32_t policer_kpkts_rate OVS_UNUSED,
+ uint32_t policer_kpkts_burst OVS_UNUSED)
{
- struct ingress_policer *policer = NULL;
- uint64_t rate_bytes;
- uint64_t burst_bytes;
- int err = 0;
-
- policer = xmalloc(sizeof *policer);
- rte_spinlock_init(&policer->policer_lock);
-
- /* rte_meter requires bytes so convert kbits rate and burst to bytes. */
- rate_bytes = rate * 1000ULL / 8;
- burst_bytes = burst * 1000ULL / 8;
+ struct netdev_dpdk_common *common = netdev_dpdk_common_cast(netdev);
+ struct netdev_dpdk *dev = netdev_dpdk_cast(netdev);
+ int ret;
- policer->app_srtcm_params.cir = rate_bytes;
- policer->app_srtcm_params.cbs = burst_bytes;
- policer->app_srtcm_params.ebs = 0;
- err = rte_meter_srtcm_profile_config(&policer->in_prof,
- &policer->app_srtcm_params);
- if (!err) {
- err = rte_meter_srtcm_config(&policer->in_policer,
- &policer->in_prof);
- }
- if (err) {
- VLOG_ERR("Could not create rte meter for ingress policer");
- free(policer);
- return NULL;
- }
+ ovs_mutex_lock(&dev->mutex);
+ ret = netdev_dpdk_common_set_policing(common, policer_rate, policer_burst);
+ ovs_mutex_unlock(&dev->mutex);
- return policer;
+ return ret;
}
static int
-netdev_dpdk_set_policing(struct netdev* netdev, uint32_t policer_rate,
- uint32_t policer_burst,
- uint32_t policer_kpkts_rate OVS_UNUSED,
- uint32_t policer_kpkts_burst OVS_UNUSED)
+netdev_dpdk_vhost_set_policing(struct netdev *netdev, uint32_t policer_rate,
+ uint32_t policer_burst,
+ uint32_t policer_kpkts_rate OVS_UNUSED,
+ uint32_t policer_kpkts_burst OVS_UNUSED)
{
+ struct netdev_dpdk_common *common = netdev_dpdk_common_cast(netdev);
struct netdev_dpdk *dev = netdev_dpdk_cast(netdev);
- struct ingress_policer *policer;
-
- /* Force to 0 if no rate specified,
- * default to 8000 kbits if burst is 0,
- * else stick with user-specified value.
- */
- policer_burst = (!policer_rate ? 0
- : !policer_burst ? 8000
- : policer_burst);
+ int ret;
ovs_mutex_lock(&dev->mutex);
-
- policer = ovsrcu_get_protected(struct ingress_policer *,
- &dev->ingress_policer);
-
- if (dev->policer_rate == policer_rate &&
- dev->policer_burst == policer_burst) {
- /* Assume that settings haven't changed since we last set them. */
- ovs_mutex_unlock(&dev->mutex);
- return 0;
- }
-
- /* Destroy any existing ingress policer for the device if one exists */
- if (policer) {
- ovsrcu_postpone(free, policer);
- }
-
- if (policer_rate != 0) {
- policer = netdev_dpdk_policer_construct(policer_rate, policer_burst);
- } else {
- policer = NULL;
- }
- ovsrcu_set(&dev->ingress_policer, policer);
- dev->policer_rate = policer_rate;
- dev->policer_burst = policer_burst;
+ ret = netdev_dpdk_common_set_policing(common, policer_rate, policer_burst);
ovs_mutex_unlock(&dev->mutex);
- return 0;
+ return ret;
}
static int
@@ -4975,706 +4717,245 @@ netdev_dpdk_vhost_class_init(void)
/* QoS Functions */
-struct ingress_policer *
-netdev_dpdk_get_ingress_policer(const struct netdev_dpdk *dev)
-{
- return ovsrcu_get(struct ingress_policer *, &dev->ingress_policer);
-}
-
-/*
- * Initialize QoS configuration operations.
- */
-static void
-qos_conf_init(struct qos_conf *conf, const struct dpdk_qos_ops *ops)
-{
- conf->ops = ops;
- rte_spinlock_init(&conf->lock);
-}
-
-/*
- * Search existing QoS operations in qos_ops and compare each set of
- * operations qos_name to name. Return a dpdk_qos_ops pointer to a match,
- * else return NULL
- */
-static const struct dpdk_qos_ops *
-qos_lookup_name(const char *name)
-{
- const struct dpdk_qos_ops *const *opsp;
-
- for (opsp = qos_confs; *opsp != NULL; opsp++) {
- const struct dpdk_qos_ops *ops = *opsp;
- if (!strcmp(name, ops->qos_name)) {
- return ops;
- }
- }
- return NULL;
-}
-
-static int
-netdev_dpdk_get_qos_types(const struct netdev *netdev OVS_UNUSED,
- struct sset *types)
-{
- const struct dpdk_qos_ops *const *opsp;
-
- for (opsp = qos_confs; *opsp != NULL; opsp++) {
- const struct dpdk_qos_ops *ops = *opsp;
- if (ops->qos_construct && ops->qos_name[0] != '\0') {
- sset_add(types, ops->qos_name);
- }
- }
- return 0;
-}
-
static int
-netdev_dpdk_get_qos(const struct netdev *netdev,
- const char **typep, struct smap *details)
+netdev_dpdk_eth_get_qos(const struct netdev *netdev,
+ const char **typep, struct smap *details)
{
+ const struct netdev_dpdk_common *common = netdev_dpdk_common_cast(netdev);
struct netdev_dpdk *dev = netdev_dpdk_cast(netdev);
- struct qos_conf *qos_conf;
int error = 0;
ovs_mutex_lock(&dev->mutex);
- qos_conf = ovsrcu_get_protected(struct qos_conf *, &dev->qos_conf);
- if (qos_conf) {
- *typep = qos_conf->ops->qos_name;
- error = (qos_conf->ops->qos_get
- ? qos_conf->ops->qos_get(qos_conf, details): 0);
- } else {
- /* No QoS configuration set, return an empty string */
- *typep = "";
- }
+ error = netdev_dpdk_common_get_qos(common, typep, details);
ovs_mutex_unlock(&dev->mutex);
return error;
}
static int
-netdev_dpdk_set_qos(struct netdev *netdev, const char *type,
- const struct smap *details)
+netdev_dpdk_vhost_get_qos(const struct netdev *netdev,
+ const char **typep, struct smap *details)
{
+ const struct netdev_dpdk_common *common = netdev_dpdk_common_cast(netdev);
struct netdev_dpdk *dev = netdev_dpdk_cast(netdev);
- const struct dpdk_qos_ops *new_ops = NULL;
- struct qos_conf *qos_conf, *new_qos_conf = NULL;
int error = 0;
ovs_mutex_lock(&dev->mutex);
-
- qos_conf = ovsrcu_get_protected(struct qos_conf *, &dev->qos_conf);
-
- new_ops = qos_lookup_name(type);
-
- if (!new_ops || !new_ops->qos_construct) {
- new_qos_conf = NULL;
- if (type && type[0]) {
- error = EOPNOTSUPP;
- }
- } else if (qos_conf && qos_conf->ops == new_ops
- && qos_conf->ops->qos_is_equal(qos_conf, details)) {
- new_qos_conf = qos_conf;
- } else {
- error = new_ops->qos_construct(details, &new_qos_conf);
- }
-
- if (error) {
- VLOG_ERR("Failed to set QoS type %s on port %s: %s",
- type, netdev->name, rte_strerror(error));
- }
-
- if (new_qos_conf != qos_conf) {
- ovsrcu_set(&dev->qos_conf, new_qos_conf);
- if (qos_conf) {
- ovsrcu_postpone(qos_conf->ops->qos_destruct, qos_conf);
- }
- }
-
+ error = netdev_dpdk_common_get_qos(common, typep, details);
ovs_mutex_unlock(&dev->mutex);
return error;
}
static int
-netdev_dpdk_get_queue(const struct netdev *netdev, uint32_t queue_id,
- struct smap *details)
+netdev_dpdk_eth_set_qos(struct netdev *netdev, const char *type,
+ const struct smap *details)
{
+ struct netdev_dpdk_common *common = netdev_dpdk_common_cast(netdev);
struct netdev_dpdk *dev = netdev_dpdk_cast(netdev);
- struct qos_conf *qos_conf;
int error = 0;
ovs_mutex_lock(&dev->mutex);
-
- qos_conf = ovsrcu_get_protected(struct qos_conf *, &dev->qos_conf);
- if (!qos_conf || !qos_conf->ops || !qos_conf->ops->qos_queue_get) {
- error = EOPNOTSUPP;
- } else {
- error = qos_conf->ops->qos_queue_get(details, queue_id, qos_conf);
- }
-
+ error = netdev_dpdk_common_set_qos(common, type, details);
ovs_mutex_unlock(&dev->mutex);
return error;
}
static int
-netdev_dpdk_set_queue(struct netdev *netdev, uint32_t queue_id,
- const struct smap *details)
+netdev_dpdk_vhost_set_qos(struct netdev *netdev, const char *type,
+ const struct smap *details)
{
+ struct netdev_dpdk_common *common = netdev_dpdk_common_cast(netdev);
struct netdev_dpdk *dev = netdev_dpdk_cast(netdev);
- struct qos_conf *qos_conf;
int error = 0;
ovs_mutex_lock(&dev->mutex);
-
- qos_conf = ovsrcu_get_protected(struct qos_conf *, &dev->qos_conf);
- if (!qos_conf || !qos_conf->ops || !qos_conf->ops->qos_queue_construct) {
- error = EOPNOTSUPP;
- } else {
- error = qos_conf->ops->qos_queue_construct(details, queue_id,
- qos_conf);
- }
-
- if (error && error != EOPNOTSUPP) {
- VLOG_ERR("Failed to set QoS queue %d on port %s: %s",
- queue_id, netdev_get_name(netdev), rte_strerror(error));
- }
-
+ error = netdev_dpdk_common_set_qos(common, type, details);
ovs_mutex_unlock(&dev->mutex);
return error;
}
static int
-netdev_dpdk_delete_queue(struct netdev *netdev, uint32_t queue_id)
+netdev_dpdk_eth_get_queue(const struct netdev *netdev, uint32_t queue_id,
+ struct smap *details)
{
+ const struct netdev_dpdk_common *common = netdev_dpdk_common_cast(netdev);
struct netdev_dpdk *dev = netdev_dpdk_cast(netdev);
- struct qos_conf *qos_conf;
int error = 0;
ovs_mutex_lock(&dev->mutex);
-
- qos_conf = ovsrcu_get_protected(struct qos_conf *, &dev->qos_conf);
- if (qos_conf && qos_conf->ops && qos_conf->ops->qos_queue_destruct) {
- qos_conf->ops->qos_queue_destruct(qos_conf, queue_id);
- } else {
- error = EOPNOTSUPP;
- }
-
+ error = netdev_dpdk_common_get_queue(common, queue_id, details);
ovs_mutex_unlock(&dev->mutex);
return error;
}
static int
-netdev_dpdk_get_queue_stats(const struct netdev *netdev, uint32_t queue_id,
- struct netdev_queue_stats *stats)
+netdev_dpdk_vhost_get_queue(const struct netdev *netdev, uint32_t queue_id,
+ struct smap *details)
{
+ const struct netdev_dpdk_common *common = netdev_dpdk_common_cast(netdev);
struct netdev_dpdk *dev = netdev_dpdk_cast(netdev);
- struct qos_conf *qos_conf;
int error = 0;
ovs_mutex_lock(&dev->mutex);
-
- qos_conf = ovsrcu_get_protected(struct qos_conf *, &dev->qos_conf);
- if (qos_conf && qos_conf->ops && qos_conf->ops->qos_queue_get_stats) {
- qos_conf->ops->qos_queue_get_stats(qos_conf, queue_id, stats);
- } else {
- error = EOPNOTSUPP;
- }
-
+ error = netdev_dpdk_common_get_queue(common, queue_id, details);
ovs_mutex_unlock(&dev->mutex);
return error;
}
static int
-netdev_dpdk_queue_dump_start(const struct netdev *netdev, void **statep)
+netdev_dpdk_eth_set_queue(struct netdev *netdev, uint32_t queue_id,
+ const struct smap *details)
{
- int error = 0;
- struct qos_conf *qos_conf;
+ struct netdev_dpdk_common *common = netdev_dpdk_common_cast(netdev);
struct netdev_dpdk *dev = netdev_dpdk_cast(netdev);
+ int error = 0;
ovs_mutex_lock(&dev->mutex);
-
- qos_conf = ovsrcu_get_protected(struct qos_conf *, &dev->qos_conf);
- if (qos_conf && qos_conf->ops
- && qos_conf->ops->qos_queue_dump_state_init) {
- struct netdev_dpdk_queue_state *state;
-
- *statep = state = xmalloc(sizeof *state);
- error = qos_conf->ops->qos_queue_dump_state_init(qos_conf, state);
- } else {
- error = EOPNOTSUPP;
- }
-
+ error = netdev_dpdk_common_set_queue(common, queue_id, details);
ovs_mutex_unlock(&dev->mutex);
return error;
}
static int
-netdev_dpdk_queue_dump_next(const struct netdev *netdev, void *state_,
- uint32_t *queue_idp, struct smap *details)
+netdev_dpdk_vhost_set_queue(struct netdev *netdev, uint32_t queue_id,
+ const struct smap *details)
{
+ struct netdev_dpdk_common *common = netdev_dpdk_common_cast(netdev);
struct netdev_dpdk *dev = netdev_dpdk_cast(netdev);
- struct netdev_dpdk_queue_state *state = state_;
- struct qos_conf *qos_conf;
- int error = EOF;
+ int error = 0;
ovs_mutex_lock(&dev->mutex);
-
- while (state->cur_queue < state->n_queues) {
- uint32_t queue_id = state->queues[state->cur_queue++];
-
- qos_conf = ovsrcu_get_protected(struct qos_conf *, &dev->qos_conf);
- if (qos_conf && qos_conf->ops && qos_conf->ops->qos_queue_get) {
- *queue_idp = queue_id;
- error = qos_conf->ops->qos_queue_get(details, queue_id, qos_conf);
- break;
- }
- }
-
+ error = netdev_dpdk_common_set_queue(common, queue_id, details);
ovs_mutex_unlock(&dev->mutex);
return error;
}
static int
-netdev_dpdk_queue_dump_done(const struct netdev *netdev OVS_UNUSED,
- void *state_)
-{
- struct netdev_dpdk_queue_state *state = state_;
-
- free(state->queues);
- free(state);
- return 0;
-}
-
-
-
-/* egress-policer details */
-
-struct egress_policer {
- struct qos_conf qos_conf;
- struct rte_meter_srtcm_params app_srtcm_params;
- struct rte_meter_srtcm egress_meter;
- struct rte_meter_srtcm_profile egress_prof;
-};
-
-static void
-egress_policer_details_to_param(const struct smap *details,
- struct rte_meter_srtcm_params *params)
-{
- memset(params, 0, sizeof *params);
- params->cir = smap_get_ullong(details, "cir", 0);
- params->cbs = smap_get_ullong(details, "cbs", 0);
- params->ebs = 0;
-}
-
-static int
-egress_policer_qos_construct(const struct smap *details,
- struct qos_conf **conf)
-{
- struct egress_policer *policer;
- int err = 0;
-
- policer = xmalloc(sizeof *policer);
- qos_conf_init(&policer->qos_conf, &egress_policer_ops);
- egress_policer_details_to_param(details, &policer->app_srtcm_params);
- err = rte_meter_srtcm_profile_config(&policer->egress_prof,
- &policer->app_srtcm_params);
- if (!err) {
- err = rte_meter_srtcm_config(&policer->egress_meter,
- &policer->egress_prof);
- }
-
- if (!err) {
- *conf = &policer->qos_conf;
- } else {
- VLOG_ERR("Could not create rte meter for egress policer");
- free(policer);
- *conf = NULL;
- err = -err;
- }
-
- return err;
-}
-
-static void
-egress_policer_qos_destruct(struct qos_conf *conf)
-{
- struct egress_policer *policer = CONTAINER_OF(conf, struct egress_policer,
- qos_conf);
- free(policer);
-}
-
-static int
-egress_policer_qos_get(const struct qos_conf *conf, struct smap *details)
-{
- struct egress_policer *policer =
- CONTAINER_OF(conf, struct egress_policer, qos_conf);
-
- smap_add_format(details, "cir", "%"PRIu64, policer->app_srtcm_params.cir);
- smap_add_format(details, "cbs", "%"PRIu64, policer->app_srtcm_params.cbs);
-
- return 0;
-}
-
-static bool
-egress_policer_qos_is_equal(const struct qos_conf *conf,
- const struct smap *details)
+netdev_dpdk_eth_delete_queue(struct netdev *netdev, uint32_t queue_id)
{
- struct egress_policer *policer =
- CONTAINER_OF(conf, struct egress_policer, qos_conf);
- struct rte_meter_srtcm_params params;
+ struct netdev_dpdk_common *common = netdev_dpdk_common_cast(netdev);
+ struct netdev_dpdk *dev = netdev_dpdk_cast(netdev);
+ int error = 0;
- egress_policer_details_to_param(details, ¶ms);
+ ovs_mutex_lock(&dev->mutex);
+ error = netdev_dpdk_common_delete_queue(common, queue_id);
+ ovs_mutex_unlock(&dev->mutex);
- return !memcmp(¶ms, &policer->app_srtcm_params, sizeof params);
+ return error;
}
static int
-egress_policer_run(struct qos_conf *conf, struct rte_mbuf **pkts, int pkt_cnt,
- bool should_steal)
+netdev_dpdk_vhost_delete_queue(struct netdev *netdev, uint32_t queue_id)
{
- int cnt = 0;
- struct egress_policer *policer =
- CONTAINER_OF(conf, struct egress_policer, qos_conf);
-
- cnt = srtcm_policer_run_single_packet(&policer->egress_meter,
- &policer->egress_prof, pkts,
- pkt_cnt, should_steal);
-
- return cnt;
-}
-
-static const struct dpdk_qos_ops egress_policer_ops = {
- .qos_name = "egress-policer", /* qos_name */
- .qos_construct = egress_policer_qos_construct,
- .qos_destruct = egress_policer_qos_destruct,
- .qos_get = egress_policer_qos_get,
- .qos_is_equal = egress_policer_qos_is_equal,
- .qos_run = egress_policer_run
-};
-
-/* trtcm-policer details */
-
-struct trtcm_policer {
- struct qos_conf qos_conf;
- struct rte_meter_trtcm_rfc4115_params meter_params;
- struct rte_meter_trtcm_rfc4115_profile meter_profile;
- struct rte_meter_trtcm_rfc4115 meter;
- struct netdev_queue_stats stats;
- struct hmap queues;
-};
-
-struct trtcm_policer_queue {
- struct hmap_node hmap_node;
- uint32_t queue_id;
- struct rte_meter_trtcm_rfc4115_params meter_params;
- struct rte_meter_trtcm_rfc4115_profile meter_profile;
- struct rte_meter_trtcm_rfc4115 meter;
- struct netdev_queue_stats stats;
-};
+ struct netdev_dpdk_common *common = netdev_dpdk_common_cast(netdev);
+ struct netdev_dpdk *dev = netdev_dpdk_cast(netdev);
+ int error = 0;
-static void
-trtcm_policer_details_to_param(const struct smap *details,
- struct rte_meter_trtcm_rfc4115_params *params)
-{
- memset(params, 0, sizeof *params);
- params->cir = smap_get_ullong(details, "cir", 0);
- params->eir = smap_get_ullong(details, "eir", 0);
- params->cbs = smap_get_ullong(details, "cbs", 0);
- params->ebs = smap_get_ullong(details, "ebs", 0);
-}
+ ovs_mutex_lock(&dev->mutex);
+ error = netdev_dpdk_common_delete_queue(common, queue_id);
+ ovs_mutex_unlock(&dev->mutex);
-static void
-trtcm_policer_param_to_detail(
- const struct rte_meter_trtcm_rfc4115_params *params,
- struct smap *details)
-{
- smap_add_format(details, "cir", "%"PRIu64, params->cir);
- smap_add_format(details, "eir", "%"PRIu64, params->eir);
- smap_add_format(details, "cbs", "%"PRIu64, params->cbs);
- smap_add_format(details, "ebs", "%"PRIu64, params->ebs);
+ return error;
}
-
static int
-trtcm_policer_qos_construct(const struct smap *details,
- struct qos_conf **conf)
+netdev_dpdk_eth_get_queue_stats(const struct netdev *netdev, uint32_t queue_id,
+ struct netdev_queue_stats *stats)
{
- struct trtcm_policer *policer;
- int err = 0;
-
- policer = xmalloc(sizeof *policer);
- qos_conf_init(&policer->qos_conf, &trtcm_policer_ops);
- trtcm_policer_details_to_param(details, &policer->meter_params);
- err = rte_meter_trtcm_rfc4115_profile_config(&policer->meter_profile,
- &policer->meter_params);
- if (!err) {
- err = rte_meter_trtcm_rfc4115_config(&policer->meter,
- &policer->meter_profile);
- }
-
- if (!err) {
- *conf = &policer->qos_conf;
- memset(&policer->stats, 0, sizeof policer->stats);
- hmap_init(&policer->queues);
- } else {
- free(policer);
- *conf = NULL;
- err = -err;
- }
-
- return err;
-}
+ const struct netdev_dpdk_common *common = netdev_dpdk_common_cast(netdev);
+ struct netdev_dpdk *dev = netdev_dpdk_cast(netdev);
+ int error = 0;
-static void
-trtcm_policer_qos_destruct(struct qos_conf *conf)
-{
- struct trtcm_policer_queue *queue;
- struct trtcm_policer *policer = CONTAINER_OF(conf, struct trtcm_policer,
- qos_conf);
+ ovs_mutex_lock(&dev->mutex);
+ error = netdev_dpdk_common_get_queue_stats(common, queue_id, stats);
+ ovs_mutex_unlock(&dev->mutex);
- HMAP_FOR_EACH_SAFE (queue, hmap_node, &policer->queues) {
- hmap_remove(&policer->queues, &queue->hmap_node);
- free(queue);
- }
- hmap_destroy(&policer->queues);
- free(policer);
+ return error;
}
static int
-trtcm_policer_qos_get(const struct qos_conf *conf, struct smap *details)
-{
- struct trtcm_policer *policer = CONTAINER_OF(conf, struct trtcm_policer,
- qos_conf);
-
- trtcm_policer_param_to_detail(&policer->meter_params, details);
- return 0;
-}
-
-static bool
-trtcm_policer_qos_is_equal(const struct qos_conf *conf,
- const struct smap *details)
-{
- struct trtcm_policer *policer = CONTAINER_OF(conf, struct trtcm_policer,
- qos_conf);
- struct rte_meter_trtcm_rfc4115_params params;
-
- trtcm_policer_details_to_param(details, ¶ms);
-
- return !memcmp(¶ms, &policer->meter_params, sizeof params);
-}
-
-static struct trtcm_policer_queue *
-trtcm_policer_qos_find_queue(struct trtcm_policer *policer, uint32_t queue_id)
-{
- struct trtcm_policer_queue *queue;
- HMAP_FOR_EACH_WITH_HASH (queue, hmap_node, hash_2words(queue_id, 0),
- &policer->queues) {
- if (queue->queue_id == queue_id) {
- return queue;
- }
- }
- return NULL;
-}
-
-static inline bool
-trtcm_policer_run_single_packet(struct trtcm_policer *policer,
- struct rte_mbuf *pkt, uint64_t time)
+netdev_dpdk_vhost_get_queue_stats(const struct netdev *netdev,
+ uint32_t queue_id,
+ struct netdev_queue_stats *stats)
{
- enum rte_color pkt_color;
- struct trtcm_policer_queue *queue;
- uint32_t pkt_len = rte_pktmbuf_pkt_len(pkt) - sizeof(struct rte_ether_hdr);
- struct dp_packet *dpkt = CONTAINER_OF(pkt, struct dp_packet, mbuf);
-
- queue = trtcm_policer_qos_find_queue(policer, dpkt->md.skb_priority);
- if (!queue) {
- /* If no queue is found, use the default queue, which MUST exist. */
- queue = trtcm_policer_qos_find_queue(policer, 0);
- if (!queue) {
- return false;
- }
- }
-
- pkt_color = rte_meter_trtcm_rfc4115_color_blind_check(&queue->meter,
- &queue->meter_profile,
- time,
- pkt_len);
-
- if (pkt_color == RTE_COLOR_RED) {
- queue->stats.tx_errors++;
- } else {
- queue->stats.tx_bytes += pkt_len;
- queue->stats.tx_packets++;
- }
-
- pkt_color = rte_meter_trtcm_rfc4115_color_aware_check(&policer->meter,
- &policer->meter_profile,
- time, pkt_len,
- pkt_color);
+ const struct netdev_dpdk_common *common = netdev_dpdk_common_cast(netdev);
+ struct netdev_dpdk *dev = netdev_dpdk_cast(netdev);
+ int error = 0;
- if (pkt_color == RTE_COLOR_RED) {
- policer->stats.tx_errors++;
- return false;
- }
+ ovs_mutex_lock(&dev->mutex);
+ error = netdev_dpdk_common_get_queue_stats(common, queue_id, stats);
+ ovs_mutex_unlock(&dev->mutex);
- policer->stats.tx_bytes += pkt_len;
- policer->stats.tx_packets++;
- return true;
+ return error;
}
static int
-trtcm_policer_run(struct qos_conf *conf, struct rte_mbuf **pkts, int pkt_cnt,
- bool should_steal)
+netdev_dpdk_eth_queue_dump_start(const struct netdev *netdev, void **statep)
{
- int i = 0;
- int cnt = 0;
- struct rte_mbuf *pkt = NULL;
- uint64_t current_time = rte_rdtsc();
-
- struct trtcm_policer *policer = CONTAINER_OF(conf, struct trtcm_policer,
- qos_conf);
+ const struct netdev_dpdk_common *common = netdev_dpdk_common_cast(netdev);
+ struct netdev_dpdk *dev = netdev_dpdk_cast(netdev);
+ int error = 0;
- for (i = 0; i < pkt_cnt; i++) {
- pkt = pkts[i];
+ ovs_mutex_lock(&dev->mutex);
+ error = netdev_dpdk_common_queue_dump_start(common, statep);
+ ovs_mutex_unlock(&dev->mutex);
- if (trtcm_policer_run_single_packet(policer, pkt, current_time)) {
- if (cnt != i) {
- pkts[cnt] = pkt;
- }
- cnt++;
- } else {
- if (should_steal) {
- rte_pktmbuf_free(pkt);
- }
- }
- }
- return cnt;
+ return error;
}
static int
-trtcm_policer_qos_queue_construct(const struct smap *details,
- uint32_t queue_id, struct qos_conf *conf)
+netdev_dpdk_vhost_queue_dump_start(const struct netdev *netdev, void **statep)
{
- int err = 0;
- struct trtcm_policer_queue *queue;
- struct trtcm_policer *policer = CONTAINER_OF(conf, struct trtcm_policer,
- qos_conf);
-
- queue = trtcm_policer_qos_find_queue(policer, queue_id);
- if (!queue) {
- queue = xmalloc(sizeof *queue);
- queue->queue_id = queue_id;
- memset(&queue->stats, 0, sizeof queue->stats);
- queue->stats.created = time_msec();
- hmap_insert(&policer->queues, &queue->hmap_node,
- hash_2words(queue_id, 0));
- }
- if (queue_id == 0 && smap_is_empty(details)) {
- /* No default queue configured, use port values */
- memcpy(&queue->meter_params, &policer->meter_params,
- sizeof queue->meter_params);
- } else {
- trtcm_policer_details_to_param(details, &queue->meter_params);
- }
-
- err = rte_meter_trtcm_rfc4115_profile_config(&queue->meter_profile,
- &queue->meter_params);
-
- if (!err) {
- err = rte_meter_trtcm_rfc4115_config(&queue->meter,
- &queue->meter_profile);
- }
- if (err) {
- hmap_remove(&policer->queues, &queue->hmap_node);
- free(queue);
- err = -err;
- }
- return err;
-}
+ const struct netdev_dpdk_common *common = netdev_dpdk_common_cast(netdev);
+ struct netdev_dpdk *dev = netdev_dpdk_cast(netdev);
+ int error = 0;
-static void
-trtcm_policer_qos_queue_destruct(struct qos_conf *conf, uint32_t queue_id)
-{
- struct trtcm_policer_queue *queue;
- struct trtcm_policer *policer = CONTAINER_OF(conf, struct trtcm_policer,
- qos_conf);
+ ovs_mutex_lock(&dev->mutex);
+ error = netdev_dpdk_common_queue_dump_start(common, statep);
+ ovs_mutex_unlock(&dev->mutex);
- queue = trtcm_policer_qos_find_queue(policer, queue_id);
- if (queue) {
- hmap_remove(&policer->queues, &queue->hmap_node);
- free(queue);
- }
+ return error;
}
static int
-trtcm_policer_qos_queue_get(struct smap *details, uint32_t queue_id,
- const struct qos_conf *conf)
+netdev_dpdk_eth_queue_dump_next(const struct netdev *netdev, void *state_,
+ uint32_t *queue_idp, struct smap *details)
{
- struct trtcm_policer_queue *queue;
- struct trtcm_policer *policer = CONTAINER_OF(conf, struct trtcm_policer,
- qos_conf);
-
- queue = trtcm_policer_qos_find_queue(policer, queue_id);
- if (!queue) {
- return EINVAL;
- }
-
- trtcm_policer_param_to_detail(&queue->meter_params, details);
- return 0;
-}
+ const struct netdev_dpdk_common *common = netdev_dpdk_common_cast(netdev);
+ struct netdev_dpdk *dev = netdev_dpdk_cast(netdev);
+ int ret;
-static int
-trtcm_policer_qos_queue_get_stats(const struct qos_conf *conf,
- uint32_t queue_id,
- struct netdev_queue_stats *stats)
-{
- struct trtcm_policer_queue *queue;
- struct trtcm_policer *policer = CONTAINER_OF(conf, struct trtcm_policer,
- qos_conf);
+ ovs_mutex_lock(&dev->mutex);
+ ret = netdev_dpdk_common_queue_dump_next(common, state_, queue_idp,
+ details);
+ ovs_mutex_unlock(&dev->mutex);
- queue = trtcm_policer_qos_find_queue(policer, queue_id);
- if (!queue) {
- return EINVAL;
- }
- memcpy(stats, &queue->stats, sizeof *stats);
- return 0;
+ return ret;
}
static int
-trtcm_policer_qos_queue_dump_state_init(const struct qos_conf *conf,
- struct netdev_dpdk_queue_state *state)
+netdev_dpdk_vhost_queue_dump_next(const struct netdev *netdev, void *state_,
+ uint32_t *queue_idp, struct smap *details)
{
- uint32_t i = 0;
- struct trtcm_policer_queue *queue;
- struct trtcm_policer *policer = CONTAINER_OF(conf, struct trtcm_policer,
- qos_conf);
+ const struct netdev_dpdk_common *common = netdev_dpdk_common_cast(netdev);
+ struct netdev_dpdk *dev = netdev_dpdk_cast(netdev);
+ int ret;
- state->n_queues = hmap_count(&policer->queues);
- state->cur_queue = 0;
- state->queues = xmalloc(state->n_queues * sizeof *state->queues);
+ ovs_mutex_lock(&dev->mutex);
+ ret = netdev_dpdk_common_queue_dump_next(common, state_, queue_idp,
+ details);
+ ovs_mutex_unlock(&dev->mutex);
- HMAP_FOR_EACH (queue, hmap_node, &policer->queues) {
- state->queues[i++] = queue->queue_id;
- }
- return 0;
+ return ret;
}
-static const struct dpdk_qos_ops trtcm_policer_ops = {
- .qos_name = "trtcm-policer",
- .qos_construct = trtcm_policer_qos_construct,
- .qos_destruct = trtcm_policer_qos_destruct,
- .qos_get = trtcm_policer_qos_get,
- .qos_is_equal = trtcm_policer_qos_is_equal,
- .qos_run = trtcm_policer_run,
- .qos_queue_construct = trtcm_policer_qos_queue_construct,
- .qos_queue_destruct = trtcm_policer_qos_queue_destruct,
- .qos_queue_get = trtcm_policer_qos_queue_get,
- .qos_queue_get_stats = trtcm_policer_qos_queue_get_stats,
- .qos_queue_dump_state_init = trtcm_policer_qos_queue_dump_state_init
-};
-
static void
set_error(struct rte_flow_error *error, enum rte_flow_error_type type)
{
@@ -6423,17 +5704,17 @@ static const struct netdev_class netdev_dpdk_class = {
.get_features = netdev_dpdk_eth_get_features,
.get_speed = netdev_dpdk_eth_get_speed,
.get_duplex = netdev_dpdk_eth_get_duplex,
- .set_policing = netdev_dpdk_set_policing,
- .get_qos_types = netdev_dpdk_get_qos_types,
- .get_qos = netdev_dpdk_get_qos,
- .set_qos = netdev_dpdk_set_qos,
- .get_queue = netdev_dpdk_get_queue,
- .set_queue = netdev_dpdk_set_queue,
- .delete_queue = netdev_dpdk_delete_queue,
- .get_queue_stats = netdev_dpdk_get_queue_stats,
- .queue_dump_start = netdev_dpdk_queue_dump_start,
- .queue_dump_next = netdev_dpdk_queue_dump_next,
- .queue_dump_done = netdev_dpdk_queue_dump_done,
+ .set_policing = netdev_dpdk_eth_set_policing,
+ .get_qos_types = netdev_dpdk_common_get_qos_types,
+ .get_qos = netdev_dpdk_eth_get_qos,
+ .set_qos = netdev_dpdk_eth_set_qos,
+ .get_queue = netdev_dpdk_eth_get_queue,
+ .set_queue = netdev_dpdk_eth_set_queue,
+ .delete_queue = netdev_dpdk_eth_delete_queue,
+ .get_queue_stats = netdev_dpdk_eth_get_queue_stats,
+ .queue_dump_start = netdev_dpdk_eth_queue_dump_start,
+ .queue_dump_next = netdev_dpdk_eth_queue_dump_next,
+ .queue_dump_done = netdev_dpdk_common_queue_dump_done,
.get_status = netdev_dpdk_eth_get_status,
.update_flags = netdev_dpdk_eth_update_flags,
.reconfigure = netdev_dpdk_eth_reconfigure,
@@ -6462,17 +5743,17 @@ static const struct netdev_class netdev_dpdk_vhost_class = {
.get_carrier = netdev_dpdk_vhost_get_carrier,
.get_stats = netdev_dpdk_vhost_get_stats,
.get_custom_stats = netdev_dpdk_vhost_get_custom_stats,
- .set_policing = netdev_dpdk_set_policing,
- .get_qos_types = netdev_dpdk_get_qos_types,
- .get_qos = netdev_dpdk_get_qos,
- .set_qos = netdev_dpdk_set_qos,
- .get_queue = netdev_dpdk_get_queue,
- .set_queue = netdev_dpdk_set_queue,
- .delete_queue = netdev_dpdk_delete_queue,
- .get_queue_stats = netdev_dpdk_get_queue_stats,
- .queue_dump_start = netdev_dpdk_queue_dump_start,
- .queue_dump_next = netdev_dpdk_queue_dump_next,
- .queue_dump_done = netdev_dpdk_queue_dump_done,
+ .set_policing = netdev_dpdk_vhost_set_policing,
+ .get_qos_types = netdev_dpdk_common_get_qos_types,
+ .get_qos = netdev_dpdk_vhost_get_qos,
+ .set_qos = netdev_dpdk_vhost_set_qos,
+ .get_queue = netdev_dpdk_vhost_get_queue,
+ .set_queue = netdev_dpdk_vhost_set_queue,
+ .delete_queue = netdev_dpdk_vhost_delete_queue,
+ .get_queue_stats = netdev_dpdk_vhost_get_queue_stats,
+ .queue_dump_start = netdev_dpdk_vhost_queue_dump_start,
+ .queue_dump_next = netdev_dpdk_vhost_queue_dump_next,
+ .queue_dump_done = netdev_dpdk_common_queue_dump_done,
.get_status = netdev_dpdk_vhost_user_get_status,
.update_flags = netdev_dpdk_vhost_update_flags,
.reconfigure = netdev_dpdk_vhost_reconfigure,
@@ -6504,17 +5785,17 @@ static const struct netdev_class netdev_dpdk_vhost_client_class = {
.get_carrier = netdev_dpdk_vhost_get_carrier,
.get_stats = netdev_dpdk_vhost_get_stats,
.get_custom_stats = netdev_dpdk_vhost_get_custom_stats,
- .set_policing = netdev_dpdk_set_policing,
- .get_qos_types = netdev_dpdk_get_qos_types,
- .get_qos = netdev_dpdk_get_qos,
- .set_qos = netdev_dpdk_set_qos,
- .get_queue = netdev_dpdk_get_queue,
- .set_queue = netdev_dpdk_set_queue,
- .delete_queue = netdev_dpdk_delete_queue,
- .get_queue_stats = netdev_dpdk_get_queue_stats,
- .queue_dump_start = netdev_dpdk_queue_dump_start,
- .queue_dump_next = netdev_dpdk_queue_dump_next,
- .queue_dump_done = netdev_dpdk_queue_dump_done,
+ .set_policing = netdev_dpdk_vhost_set_policing,
+ .get_qos_types = netdev_dpdk_common_get_qos_types,
+ .get_qos = netdev_dpdk_vhost_get_qos,
+ .set_qos = netdev_dpdk_vhost_set_qos,
+ .get_queue = netdev_dpdk_vhost_get_queue,
+ .set_queue = netdev_dpdk_vhost_set_queue,
+ .delete_queue = netdev_dpdk_vhost_delete_queue,
+ .get_queue_stats = netdev_dpdk_vhost_get_queue_stats,
+ .queue_dump_start = netdev_dpdk_vhost_queue_dump_start,
+ .queue_dump_next = netdev_dpdk_vhost_queue_dump_next,
+ .queue_dump_done = netdev_dpdk_common_queue_dump_done,
.get_status = netdev_dpdk_vhost_user_get_status,
.update_flags = netdev_dpdk_vhost_update_flags,
.reconfigure = netdev_dpdk_vhost_client_reconfigure,
Move this code to a new netdev-dpdk-common.c file for reuse. Add separate wrappers for eth and vhost netdevs (in preparation of the separation later). Signed-off-by: David Marchand <david.marchand@redhat.com> --- lib/netdev-dpdk-common.c | 954 ++++++++++++++++++++++++++++++++++ lib/netdev-dpdk-common.h | 50 +- lib/netdev-dpdk.c | 1069 +++++++------------------------------- 3 files changed, 1175 insertions(+), 898 deletions(-)