From patchwork Wed Sep 30 12:45:15 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Stokes, Ian" X-Patchwork-Id: 524374 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from archives.nicira.com (unknown [IPv6:2600:3c00::f03c:91ff:fe6e:bdf7]) by ozlabs.org (Postfix) with ESMTP id 1366D140D21 for ; Wed, 30 Sep 2015 22:45:31 +1000 (AEST) Received: from archives.nicira.com (localhost [127.0.0.1]) by archives.nicira.com (Postfix) with ESMTP id 8953B10BA2; Wed, 30 Sep 2015 05:45:29 -0700 (PDT) X-Original-To: dev@openvswitch.org Delivered-To: dev@openvswitch.org Received: from mx3v1.cudamail.com (mx3.cudamail.com [64.34.241.5]) by archives.nicira.com (Postfix) with ESMTPS id D831E10BA0 for ; Wed, 30 Sep 2015 05:45:28 -0700 (PDT) Received: from bar4.cudamail.com (bar2 [192.168.15.2]) by mx3v1.cudamail.com (Postfix) with ESMTP id DDDDA6190BC for ; Wed, 30 Sep 2015 06:45:27 -0600 (MDT) X-ASG-Debug-ID: 1443617126-03dc21608001180001-byXFYA Received: from mx3-pf3.cudamail.com ([192.168.14.3]) by bar4.cudamail.com with ESMTP id NfRdBSrF50cve02d (version=TLSv1 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO) for ; Wed, 30 Sep 2015 06:45:26 -0600 (MDT) X-Barracuda-Envelope-From: istokes@ecsmtp.ir.intel.com X-Barracuda-RBL-Trusted-Forwarder: 192.168.14.3 Received: from unknown (HELO mga11.intel.com) (192.55.52.93) by mx3-pf3.cudamail.com with SMTP; 30 Sep 2015 12:45:19 -0000 Received-SPF: none (mx3-pf3.cudamail.com: domain at ecsmtp.ir.intel.com does not designate permitted sender hosts) X-Barracuda-Apparent-Source-IP: 192.55.52.93 X-Barracuda-RBL-IP: 192.55.52.93 Received: from orsmga002.jf.intel.com ([10.7.209.21]) by fmsmga102.fm.intel.com with ESMTP; 30 Sep 2015 05:45:20 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.17,612,1437462000"; d="scan'208";a="816291560" Received: from irvmail001.ir.intel.com ([163.33.26.43]) by orsmga002.jf.intel.com with ESMTP; 30 Sep 2015 05:45:18 -0700 Received: from sivswdev01.ir.intel.com (sivswdev01.ir.intel.com [10.237.217.45]) by irvmail001.ir.intel.com (8.14.3/8.13.6/MailSET/Hub) with ESMTP id t8UCjHpk025389; Wed, 30 Sep 2015 13:45:17 +0100 Received: from sivswdev01.ir.intel.com (localhost [127.0.0.1]) by sivswdev01.ir.intel.com with ESMTP id t8UCjHqP002029; Wed, 30 Sep 2015 13:45:17 +0100 Received: (from istokes@localhost) by sivswdev01.ir.intel.com with id t8UCjHxd002025; Wed, 30 Sep 2015 13:45:17 +0100 X-CudaMail-Envelope-Sender: istokes@ecsmtp.ir.intel.com From: Ian Stokes To: dev@openvswitch.org X-CudaMail-MID: CM-V3-929011062 X-CudaMail-DTE: 093015 X-CudaMail-Originating-IP: 192.55.52.93 Date: Wed, 30 Sep 2015 13:45:15 +0100 X-ASG-Orig-Subj: [##CM-V3-929011062##][PATCH] netdev_dpdk.c: Add QoS functionality. Message-Id: <1443617115-1987-1-git-send-email-ian.stokes@intel.com> X-Mailer: git-send-email 1.7.4.1 X-GBUdb-Analysis: 0, 192.55.52.93, Ugly c=0 p=0 Source New X-MessageSniffer-Rules: 0-0-0-32767-c X-Barracuda-Connect: UNKNOWN[192.168.14.3] X-Barracuda-Start-Time: 1443617126 X-Barracuda-Encrypted: DHE-RSA-AES256-SHA X-Barracuda-URL: https://web.cudamail.com:443/cgi-mod/mark.cgi X-Barracuda-BRTS-Status: 1 X-Virus-Scanned: by bsmtpd at cudamail.com X-ASG-Whitelist: EmailCat (corporate) Subject: [ovs-dev] [PATCH] netdev_dpdk.c: Add QoS functionality. X-BeenThere: dev@openvswitch.org X-Mailman-Version: 2.1.16 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: dev-bounces@openvswitch.org Sender: "dev" 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 --- 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. +
+
us-policer
+
+ 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 + http://dpdk.org/doc/guides/sample_app_ug/qos_metering.html + For more information regarding srTCM see + https://tools.ietf.org/html/rfc2697 +
+
@@ -3319,6 +3331,34 @@ + +

+ + us-policer provides egress policing for userspace port + types with DPDK. + + It has the following key-value pairs defined. +

+ + + 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. + + + 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. + + + 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. + +
+ The overall purpose of these columns is described under Common Columns at the beginning of this document.