Hi All,

Just wondering if anyone has had time to review this?
Any feedback would be much appreciated.

Thanks
Ian

> -----Original Message-----
> From: Stokes, Ian
> Sent: Wednesday, September 30, 2015 1:45 PM
> To: dev@openvswitch.org
> Cc: Stokes, Ian
> Subject: [PATCH] netdev_dpdk.c: Add QoS functionality.
> 
> This patch provides the modifications required in netdev-dpdk.c and
> vswitch.xml to allow for a DPDK user space QoS algorithm.
> 
> This patch adds a QoS configuration structure for netdev-dpdk and
> expected QoS operations 'dpdk_qos_ops'. Various helper functions
> are also supplied.
> 
> Also included are the modifications required for vswitch.xml to allow a
> new QoS implementation for netdev-dpdk devices. This includes a new QoS
> type
> `us-policer` as well as its expected QoS table entries.
> 
> The QoS functionality implemented for DPDK devices is `us-policer`.
> This is an egress policer used to drop packets at configurable rate.
> 
> The INSTALL.DPDK.md guide has also been modified to provide an example
> configuration of `us-policer` QoS.
> 
> Signed-off-by: Ian Stokes <ian.sto...@intel.com>
> ---
>  INSTALL.DPDK.md      |   52 +++++++
>  lib/netdev-dpdk.c    |  414
> +++++++++++++++++++++++++++++++++++++++++++++++++-
>  vswitchd/vswitch.xml |   40 +++++
>  3 files changed, 500 insertions(+), 6 deletions(-)
> 
> diff --git a/INSTALL.DPDK.md b/INSTALL.DPDK.md
> index 7bf110c..61bca31 100644
> --- a/INSTALL.DPDK.md
> +++ b/INSTALL.DPDK.md
> @@ -207,6 +207,58 @@ Using the DPDK with ovs-vswitchd:
>     ./ovs-ofctl add-flow br0 in_port=2,action=output:1
>     ```
> 
> +8. QoS usage example
> +
> +   OVS supports egress QoS for physical and virtual DPDK port types.
> Currently
> +   there is only one supported QoS type 'us-policer'.
> +
> +   Assuming you have a vhost-user port transmitting traffic consisting
> of
> +   packets of size 64 bytes, the following command would limit the
> egress
> +   transmission rate of the port to ~1,000,000 packets per second:
> +
> +   `ovs-vsctl set port vhost-user0 qos=@newqos -- --id=@newqos create
> qos
> +   type=us-policer other-config:cir=46000000 other-config:cbs=2048
> +   other-config:ebs=2048`
> +
> +   An explanation of the us-policer specific parameters are detailed
> below.
> +
> +   `type=us-policer`: Sets the QoS type to userspace-policer. This is
> required
> +   so that the dpdk-netdev can be configured with the correct QoS type.
> +   The specifics of us-policer can be found in the vswitch.xml file.
> +
> +   `other-config:cir=46000000`: The Committed Information Rate (cir)
> +   represents the bytes per second rate at which the token buckets will
> be
> +   updated. See RFC2697 for specific details. The cir value is
> calculated by
> +   (pps x packet data size). For example the value 46000000 can be
> broken
> +   into '1,000,000 x 46'. Where 1,000,000 is the policing rate for the
> number
> +   of packets per second and 46 represents the size of the packet data
> for a 64
> +   byte ip packet.
> +
> +   `other-config:cbs=2048`: This represents the value of the Commited
> Burst Size
> +   (cbs) token bucket. At a minimum this value should be be set to the
> expected
> +   largest size packet in the traffic stream. In practice larger values
> may be
> +   used to increase the size of the token bucket. If a packet can be
> +   transmitted then the cbs will be decremented by the number of
> bytes/tokens of
> +   the packet. If there are not enough tokens in the cbs bucket then
> the Excess
> +   Burst Size (ebs) token bucket will be used too and excess bytes
> decremented
> +   in the ebs.
> +
> +   `other-config:ebs=2048`: This represents the value of the Excess
> Burst Size
> +   (ebs). At a minimum this value should be set to the expected largest
> size
> +   packet in the traffic stream. In practice larger values may be used
> to
> +   increase the size of the token bucket. In the us-policer
> implementation any
> +   packet that requires tokens from the ebs token bucket will be marked
> to be
> +   dropped. Any packet that has exhausted the ebs bucket will also be
> dropped.
> +
> +   To examine the QoS configuration of the port:
> +
> +   `ovs-appctl -t ovs-vswitchd qos/show vhost-user0`
> +
> +   To clear the QoS configuration from the port and ovsdb use the
> following:
> +
> +   `ovs-vsctl -- destroy QoS vhost-user0 -- clear Port vhost-user0 qos`
> +
> +
>  Performance Tuning:
>  -------------------
> 
> diff --git a/lib/netdev-dpdk.c b/lib/netdev-dpdk.c
> index b72a33b..7e7fca1 100644
> --- a/lib/netdev-dpdk.c
> +++ b/lib/netdev-dpdk.c
> @@ -44,6 +44,7 @@
>  #include "ovs-rcu.h"
>  #include "packets.h"
>  #include "shash.h"
> +#include "smap.h"
>  #include "sset.h"
>  #include "unaligned.h"
>  #include "timeval.h"
> @@ -52,12 +53,14 @@
> 
>  #include "rte_config.h"
>  #include "rte_mbuf.h"
> +#include "rte_meter.h"
>  #include "rte_virtio_net.h"
> 
>  VLOG_DEFINE_THIS_MODULE(dpdk);
>  static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 20);
> 
>  #define DPDK_PORT_WATCHDOG_INTERVAL 5
> +#define DPDK_MAX_QOS_NAME_SIZE 10
> 
>  #define OVS_CACHE_LINE_SIZE CACHE_LINE_SIZE
>  #define OVS_VPORT_DPDK "ovs_dpdk"
> @@ -142,6 +145,122 @@ static int rte_eal_init_ret = ENODEV;
> 
>  static struct ovs_mutex dpdk_mutex = OVS_MUTEX_INITIALIZER;
> 
> +/* 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;
> +};
> +
> +/* 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 the QoS implementation on 'netdev'. The
> +     * implementation should make the appropriate calls to configure
> QoS
> +     * according to 'details'. The implementation may assume that any
> current
> +     * QoS configuration already installed should be destroyed before
> +     * constructing the new configuration.
> +     *
> +     * 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 'netdev-
> >qos_conf'
> +     * to an initialized 'struct qos_conf'.
> +     *
> +     * For all QoS implementations it should always be non-null.
> +     */
> +    int (*qos_construct)(struct netdev *netdev, const struct smap
> *details);
> +
> +    /* 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 netdev *netdev, struct qos_conf *conf);
> +
> +    /* Retrieves details of 'netdev->qos_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 netdev *netdev, struct smap *details);
> +
> +    /* Reconfigures 'netdev->qos_conf' according to 'details',
> performing any
> +     * required calls to complete the reconfiguration.
> +     *
> +     * 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 may be null if 'qos_conf' is not configurable.
> +     */
> +    int (*qos_set)(struct netdev *netdev, 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_alg_process)(struct netdev *netdev, struct rte_mbuf
> **pkts,
> +                           int pkt_cnt);
> +};
> +
> +/* dpdk_qos_ops for each type of user space QoS implementation */
> +static const struct dpdk_qos_ops us_policer_ops;
> +
> +/*
> + * Array of dpdk_qos_ops, contains pointer to all supported QoS
> + * operations.
> + */
> +static const struct dpdk_qos_ops *const qos_confs[] = {
> +    &us_policer_ops,               /*User Space Strict Priority
> Queuing*/
> +    NULL
> +};
> +
> +/* Action that can be set for a packet for rte_meter */
> +enum us_policer_action {
> +        GREEN = e_RTE_METER_GREEN,
> +        YELLOW = e_RTE_METER_YELLOW,
> +        RED = e_RTE_METER_RED,
> +        DROP = 3,
> +};
> +
> +/*
> + * Table representing the policing policy. Rows indicate the input
> color,
> + * columns indicate the output color, and the value that is stored in
> + * the table indicates the action to be taken for that particular case.
> + */
> +enum us_policer_action us_policer_table[e_RTE_METER_COLORS]
> +                                       [e_RTE_METER_COLORS] =
> +{
> +     { GREEN, DROP, DROP},
> +     { DROP, DROP, DROP},
> +     { DROP, DROP, DROP}
> +};
> +
>  /* Contains all 'struct dpdk_dev's. */
>  static struct ovs_list dpdk_list OVS_GUARDED_BY(dpdk_mutex)
>      = OVS_LIST_INITIALIZER(&dpdk_list);
> @@ -235,6 +354,11 @@ struct netdev_dpdk {
> 
>      /* In dpdk_list. */
>      struct ovs_list list_node OVS_GUARDED_BY(dpdk_mutex);
> +
> +    /* QoS configuration and lock for the device */
> +    struct qos_conf *qos_conf;
> +    rte_spinlock_t qos_lock;
> +
>  };
> 
>  struct netdev_rxq_dpdk {
> @@ -614,6 +738,10 @@ netdev_dpdk_init(struct netdev *netdev_, unsigned
> int port_no,
>          goto unlock;
>      }
> 
> +    /* Initialise QoS configuration to NULL and qos lock to unlocked */
> +    netdev->qos_conf = NULL;
> +    rte_spinlock_init(&netdev->qos_lock);
> +
>      netdev_->n_txq = NR_QUEUE;
>      netdev_->n_rxq = NR_QUEUE;
>      netdev->real_n_txq = NR_QUEUE;
> @@ -1072,6 +1200,13 @@ __netdev_dpdk_vhost_send(struct netdev *netdev,
> struct dp_packet **pkts,
>          goto out;
>      }
> 
> +    /* Check has QoS has been configured for the netdev */
> +    rte_spinlock_lock(&vhost_dev->qos_lock);
> +    if (vhost_dev->qos_conf != NULL) {
> +        cnt = vhost_dev->qos_conf->ops->qos_alg_process(netdev,
> cur_pkts, cnt);
> +    }
> +    rte_spinlock_unlock(&vhost_dev->qos_lock);
> +
>      /* There is vHost TX single queue, So we need to lock it for TX. */
>      rte_spinlock_lock(&vhost_dev->vhost_tx_lock);
> 
> @@ -1216,6 +1351,14 @@ dpdk_do_tx_copy(struct netdev *netdev, int qid,
> struct dp_packet **pkts,
>      if (dev->type == DPDK_DEV_VHOST) {
>          __netdev_dpdk_vhost_send(netdev, (struct dp_packet **) mbufs,
> newcnt, true);
>      } else {
> +
> +        /* Check if QoS has been configured for this netdev. */
> +        rte_spinlock_lock(&dev->qos_lock);
> +        if (dev->qos_conf != NULL) {
> +            newcnt = dev->qos_conf->ops->qos_alg_process(netdev, mbufs,
> newcnt);
> +        }
> +        rte_spinlock_unlock(&dev->qos_lock);
> +
>          dpdk_queue_pkts(dev, qid, mbufs, newcnt);
>          dpdk_queue_flush(dev, qid);
>      }
> @@ -1289,9 +1432,18 @@ netdev_dpdk_send__(struct netdev_dpdk *dev, int
> qid,
>              }
>          }
>          if (next_tx_idx != cnt) {
> -           dpdk_queue_pkts(dev, qid,
> -                            (struct rte_mbuf **)&pkts[next_tx_idx],
> -                            cnt-next_tx_idx);
> +            cnt -= next_tx_idx;
> +
> +            /* Check if QoS has been configured for this netdev. */
> +            rte_spinlock_lock(&dev->qos_lock);
> +            if (dev->qos_conf != NULL) {
> +                struct netdev *netdev = &dev->up;
> +                cnt = dev->qos_conf->ops->qos_alg_process(netdev,
> +                        (struct rte_mbuf**)pkts, cnt);
> +            }
> +            rte_spinlock_unlock(&dev->qos_lock);
> +
> +            dpdk_queue_pkts(dev, qid, (struct rte_mbuf
> **)&pkts[next_tx_idx], cnt);
>          }
> 
>          if (OVS_UNLIKELY(dropped)) {
> @@ -2032,6 +2184,256 @@ unlock_dpdk:
>      return err;
>  }
> 
> +/* QoS Functions */
> +
> +/*
> + * Initialize QoS configuration operations.
> + */
> +static void
> +qos_conf_init(struct qos_conf *conf, const struct dpdk_qos_ops *ops)
> +{
> +    conf->ops = ops;
> +}
> +
> +/*
> + * 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 (!strncmp(name, ops->qos_name,DPDK_MAX_QOS_NAME_SIZE)) {
> +            return ops;
> +        }
> +    }
> +    return NULL;
> +}
> +
> +/*
> + * Call qos_destruct to clean up items associated with the netdevs
> + * qos_conf. Set netdevs qos_conf to NULL.
> + */
> +static void
> +qos_delete_conf(struct netdev *netdev_)
> +{
> +    struct netdev_dpdk *netdev = netdev_dpdk_cast(netdev_);
> +
> +    rte_spinlock_lock(&netdev->qos_lock);
> +    if (netdev->qos_conf) {
> +        if (netdev->qos_conf->ops->qos_destruct) {
> +            netdev->qos_conf->ops->qos_destruct(netdev_, netdev-
> >qos_conf);
> +        }
> +        netdev->qos_conf = NULL;
> +    }
> +    rte_spinlock_unlock(&netdev->qos_lock);
> +}
> +
> +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)
> +{
> +    struct netdev_dpdk *netdev = netdev_dpdk_cast(netdev_);
> +    int error = 0;
> +
> +    ovs_mutex_lock(&netdev->mutex);
> +    if(netdev->qos_conf){
> +        *typep = netdev->qos_conf->ops->qos_name;
> +        error = (netdev->qos_conf->ops->qos_get
> +                 ? netdev->qos_conf->ops->qos_get(netdev_, details):
> 0);
> +    }
> +    ovs_mutex_unlock(&netdev->mutex);
> +
> +    return error;
> +}
> +
> +static int
> +netdev_dpdk_set_qos(struct netdev *netdev_,
> +                    const char *type, const struct smap *details)
> +{
> +    struct netdev_dpdk *netdev = netdev_dpdk_cast(netdev_);
> +    const struct dpdk_qos_ops *new_ops = NULL;
> +    int error = 0;
> +
> +    /* If type is empty the current QoS configuration
> +        for the dpdk-netdev can be destroyed */
> +    if(type[0] == '\0') {
> +        qos_delete_conf(netdev_);
> +    }
> +
> +    new_ops = qos_lookup_name(type);
> +    if (!new_ops || !new_ops->qos_construct) {
> +        return EOPNOTSUPP;
> +    }
> +
> +    ovs_mutex_lock(&netdev->mutex);
> +    if (netdev->qos_conf) {
> +        if (new_ops == netdev->qos_conf->ops) {
> +            error = new_ops->qos_set ? new_ops->qos_set(netdev_,
> details) : 0;
> +        }
> +        else {
> +            /* Delete existing QoS configuration. */
> +            qos_delete_conf(netdev_);
> +            ovs_assert(netdev->qos_conf == NULL);
> +
> +            /* Install new QoS configuration. */
> +            error = new_ops->qos_construct(netdev_, details);
> +            ovs_assert((error == 0) == (netdev->qos_conf != NULL));
> +        }
> +    } else {
> +        error = new_ops->qos_construct(netdev_, details);
> +        ovs_assert((error == 0) == (netdev->qos_conf != NULL));
> +    }
> +
> +    ovs_mutex_unlock(&netdev->mutex);
> +    return error;
> +}
> +
> +/* us-policer details */
> +
> +struct us_policer {
> +    struct qos_conf qos_conf;
> +    struct rte_meter_srtcm_params app_srtcm_params;
> +    struct rte_meter_srtcm test_meter;
> +};
> +
> +static struct us_policer *
> +us_policer_get__(const struct netdev *netdev_)
> +{
> +    struct netdev_dpdk *netdev = netdev_dpdk_cast(netdev_);
> +    return CONTAINER_OF(netdev->qos_conf, struct us_policer, qos_conf);
> +}
> +
> +static int
> +us_policer_qos_construct(struct netdev *netdev_, const struct smap
> *details)
> +{
> +    struct netdev_dpdk *netdev = netdev_dpdk_cast(netdev_);
> +    struct us_policer *policer;
> +    const char *cir_s;
> +    const char *cbs_s;
> +    const char *ebs_s;
> +    int err = 0;
> +
> +    rte_spinlock_lock(&netdev->qos_lock);
> +    policer = xmalloc(sizeof *policer);
> +    qos_conf_init(&policer->qos_conf, &us_policer_ops);
> +    netdev->qos_conf = &policer->qos_conf;
> +    cir_s = smap_get(details, "cir");
> +    cbs_s = smap_get(details, "cbs");
> +    ebs_s = smap_get(details, "ebs");
> +    policer->app_srtcm_params.cir = cir_s ? strtoull(cir_s, NULL, 10) :
> 0;
> +    policer->app_srtcm_params.cbs = cbs_s ? strtoull(cbs_s, NULL, 10) :
> 0;
> +    policer->app_srtcm_params.ebs = ebs_s ? strtoull(ebs_s, NULL, 10) :
> 0;
> +    err = rte_meter_srtcm_config(&policer->test_meter, &policer-
> >app_srtcm_params);
> +    rte_spinlock_unlock(&netdev->qos_lock);
> +
> +    return err;
> +}
> +
> +static void
> +us_policer_qos_destruct(struct netdev *netdev_ OVS_UNUSED, struct
> qos_conf *conf)
> +{
> +    struct us_policer *policer = CONTAINER_OF(conf, struct us_policer,
> qos_conf);
> +    free(policer);
> +}
> +
> +static int
> +us_policer_qos_get(const struct netdev *netdev, struct smap *details)
> +{
> +    struct us_policer *policer = us_policer_get__(netdev);
> +    smap_add_format(details, "cir", "%llu", 1ULL * policer-
> >app_srtcm_params.cir);
> +    smap_add_format(details, "cbs", "%llu", 1ULL * policer-
> >app_srtcm_params.cbs);
> +    smap_add_format(details, "ebs", "%llu", 1ULL * policer-
> >app_srtcm_params.ebs);
> +    return 0;
> +}
> +
> +static int
> +us_policer_qos_set(struct netdev *netdev_, const struct smap *details)
> +{
> +    struct us_policer *policer;
> +    const char *cir_s;
> +    const char *cbs_s;
> +    const char *ebs_s;
> +    int err = 0;
> +
> +    policer = us_policer_get__(netdev_);
> +    cir_s = smap_get(details, "cir");
> +    cbs_s = smap_get(details, "cbs");
> +    ebs_s = smap_get(details, "ebs");
> +    policer->app_srtcm_params.cir = cir_s ? strtoull(cir_s, NULL, 10) :
> 0;
> +    policer->app_srtcm_params.cbs = cbs_s ? strtoull(cbs_s, NULL, 10) :
> 0;
> +    policer->app_srtcm_params.ebs = ebs_s ? strtoull(ebs_s, NULL, 10) :
> 0;
> +    err = rte_meter_srtcm_config(&policer->test_meter, &policer-
> >app_srtcm_params);
> +
> +    return err;
> +}
> +
> +static inline int
> +__us_policer_pkt_handle(struct rte_meter_srtcm *meter, struct rte_mbuf
> *pkt, uint64_t time)
> +{
> +     uint8_t input_color, output_color;
> +     uint32_t pkt_len = rte_pktmbuf_pkt_len(pkt) - sizeof(struct
> ether_hdr);
> +     input_color = 0;
> +     enum us_policer_action action;
> +
> +     /* color input is not used for blind modes */
> +     output_color = (uint8_t) rte_meter_srtcm_color_blind_check(meter,
> time, pkt_len);
> +
> +     /* Apply policing and set the output color */
> +     action = us_policer_table[input_color][output_color];
> +
> +     return action;
> +}
> +
> +static int
> +us_policer_alg_process(struct netdev *netdev_, struct rte_mbuf **pkts,
> int pkt_cnt)
> +{
> +     int i = 0;
> +    int cnt = pkt_cnt;
> +    struct us_policer *policer = us_policer_get__(netdev_);
> +    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 (__us_policer_pkt_handle(&policer->test_meter, pkt,
> current_time) == DROP) {
> +            rte_pktmbuf_free(pkt);
> +            cnt = cnt - 1;
> +        }
> +    }
> +
> +    return cnt;
> +}
> +
> +static const struct dpdk_qos_ops us_policer_ops = {
> +    "us-policer",    /* qos_name */
> +    us_policer_qos_construct,
> +     us_policer_qos_destruct,
> +    us_policer_qos_get,
> +    us_policer_qos_set,
> +     us_policer_alg_process
> +};
> +
>  #define NETDEV_DPDK_CLASS(NAME, INIT, CONSTRUCT, DESTRUCT, MULTIQ,
> SEND, \
>      GET_CARRIER, GET_STATS, GET_FEATURES, GET_STATUS, RXQ_RECV)
> \
>  {                                                             \
> @@ -2069,10 +2471,10 @@ unlock_dpdk:
>      NULL,                       /* set_advertisements */      \
>                                                                \
>      NULL,                       /* set_policing */            \
> -    NULL,                       /* get_qos_types */           \
> +    netdev_dpdk_get_qos_types,                                \
>      NULL,                       /* get_qos_capabilities */    \
> -    NULL,                       /* get_qos */                 \
> -    NULL,                       /* set_qos */                 \
> +    netdev_dpdk_get_qos,                                      \
> +    netdev_dpdk_set_qos,                                      \
>      NULL,                       /* get_queue */               \
>      NULL,                       /* set_queue */               \
>      NULL,                       /* delete_queue */            \
> diff --git a/vswitchd/vswitch.xml b/vswitchd/vswitch.xml
> index 0ab4a9a..77f70a4 100644
> --- a/vswitchd/vswitch.xml
> +++ b/vswitchd/vswitch.xml
> @@ -3283,6 +3283,18 @@
>            for information on how this classifier works.
>          </dd>
>        </dl>
> +      <dl>
> +        <dt><code>us-policer</code></dt>
> +        <dd>
> +          Userspace egress policer algorithm. This implementation uses
> the DPDK
> +          rte_meter library. The rte_meter library provides an
> implementation of
> +          srTCM (RFC2697) which allows the metering and policing of
> traffic.
> +          For more information regarding the usage of the DPDK
> rte_meter see
> +
> <code>http://dpdk.org/doc/guides/sample_app_ug/qos_metering.html</code>
> +          For more information regarding srTCM see
> +          <code>https://tools.ietf.org/html/rfc2697</code>
> +        </dd>
> +      </dl>
>      </column>
> 
>      <column name="queues">
> @@ -3319,6 +3331,34 @@
>        </column>
>      </group>
> 
> +    <group title="Configuration for us-policer QoS">
> +      <p>
> +        <ref table="QoS"/> <ref table="QoS" column="type"/>
> +        <code>us-policer</code> provides egress policing for userspace
> port
> +        types with DPDK.
> +
> +        It has the following key-value pairs defined.
> +      </p>
> +
> +      <column name="other_config" key="cir" type='{"type": "integer"}'>
> +        The Committed Information Rate (CIR) is measured in bytes of IP
> packets
> +        per second, i.e., it includes the IP header, but not link
> specific
> +        (e.g. Ethernet) headers. See RFC2697 for more details.
> +      </column>
> +      <column name="other_config" key="cbs" type='{"type": "integer"}'>
> +        The Committed Burst Size (CBS) is measured in bytes. It must be
> set to a
> +        value greater than 0. It is recommended that the minimum value
> for CBS
> +        be the size of the largest possible IP packet in the stream.
> +        See RFC2697 for more details.
> +      </column>
> +      <column name="other_config" key="ebs" type='{"type": "integer"}'>
> +        The Excess Burst Size (EBS) is measured in bytes. It must be
> set to a
> +        value greater than 0. It is recommended that the minimum value
> for EBS
> +        be the size of the largest possible IP packet in the stream.
> +        See RFC2697 for more details.
> +      </column>
> +    </group>
> +
>      <group title="Common Columns">
>        The overall purpose of these columns is described under
> <code>Common
>        Columns</code> at the beginning of this document.
> --
> 1.7.4.1

_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to