@@ -23,6 +23,13 @@ Post-v3.1.0
process extra privileges when mapping physical interconnect memory.
- SRv6 Tunnel Protocol
* Added support for userspace datapath (only).
+ - Userspace datapath:
+ * Added new configuration options 'kpkts_rate' and 'kpkts_burst' for
+ 'egress-policer' to support packet-per-second policing.
+ Examples:
+ ovs-vsctl set port vhost-user0 qos=@newqos -- \
+ --id=@newqos create qos type=egress-policer \
+ other-config:kpkts_rate=123 other-config:kpkts_burst=123
v3.1.0 - 16 Feb 2023
@@ -19,6 +19,7 @@
#include <errno.h>
#include <signal.h>
+#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
@@ -59,6 +60,7 @@
#include "openvswitch/ofp-parse.h"
#include "openvswitch/ofp-print.h"
#include "openvswitch/shash.h"
+#include "openvswitch/token-bucket.h"
#include "openvswitch/vlog.h"
#include "ovs-numa.h"
#include "ovs-rcu.h"
@@ -400,6 +402,11 @@ struct dpdk_tx_queue {
);
};
+enum policer_type {
+ POLICER_BPS = 1 << 0, /* Rate value in bytes/sec. */
+ POLICER_PKTPS = 1 << 1, /* Rate value in packet/sec. */
+};
+
struct ingress_policer {
struct rte_meter_srtcm_params app_srtcm_params;
struct rte_meter_srtcm in_policer;
@@ -2335,6 +2342,29 @@ srtcm_policer_run_single_packet(struct rte_meter_srtcm *meter,
return cnt;
}
+static int
+pkts_policer_run_single_packet(struct token_bucket *tb, struct rte_mbuf **pkts,
+ int pkt_cnt, bool should_steal)
+{
+ struct rte_mbuf *pkt;
+ int cnt = 0;
+
+ for (int i = 0; i < pkt_cnt; i++) {
+ pkt = pkts[i];
+ /* Handle current packet. */
+ if (token_bucket_withdraw(tb, 1)) {
+ 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)
@@ -4757,6 +4787,10 @@ netdev_dpdk_queue_dump_done(const struct netdev *netdev OVS_UNUSED,
struct egress_policer {
struct qos_conf qos_conf;
+ enum policer_type type;
+ uint32_t kpkts_rate;
+ uint32_t kpkts_burst;
+ struct token_bucket egress_tb;
struct rte_meter_srtcm_params app_srtcm_params;
struct rte_meter_srtcm egress_meter;
struct rte_meter_srtcm_profile egress_prof;
@@ -4776,10 +4810,11 @@ static int
egress_policer_qos_construct(const struct smap *details,
struct qos_conf **conf)
{
+ uint32_t kpkts_burst, kpkts_rate;
struct egress_policer *policer;
int err = 0;
- policer = xmalloc(sizeof *policer);
+ policer = xcalloc(1, 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,
@@ -4787,15 +4822,32 @@ egress_policer_qos_construct(const struct smap *details,
if (!err) {
err = rte_meter_srtcm_config(&policer->egress_meter,
&policer->egress_prof);
+ if (!err) {
+ policer->type |= POLICER_BPS;
+ } else {
+ VLOG_ERR("Could not create rte meter for egress policer");
+ }
}
- if (!err) {
- *conf = &policer->qos_conf;
- } else {
- VLOG_ERR("Could not create rte meter for egress policer");
+ kpkts_rate = smap_get_uint(details, "kpkts_rate", 0);
+ kpkts_burst = smap_get_uint(details, "kpkts_burst", 0);
+ if (kpkts_rate && kpkts_burst) {
+ /* Rate in kilo-packets/second, bucket 1000 packets. */
+ /* msec * kilo-packets/sec = 1 packets. */
+ token_bucket_set(&policer->egress_tb, kpkts_rate, kpkts_burst * 1000);
+ policer->kpkts_burst = kpkts_burst;
+ policer->kpkts_rate = kpkts_rate;
+ policer->type |= POLICER_PKTPS;
+ }
+
+ if (!policer->type) {
+ /* both bps and kpkts contrsruct failed.*/
free(policer);
*conf = NULL;
- err = -err;
+ err = EINVAL;
+ } else {
+ err = 0;
+ *conf = &policer->qos_conf;
}
return err;
@@ -4817,6 +4869,8 @@ egress_policer_qos_get(const struct qos_conf *conf, struct smap *details)
smap_add_format(details, "cir", "%"PRIu64, policer->app_srtcm_params.cir);
smap_add_format(details, "cbs", "%"PRIu64, policer->app_srtcm_params.cbs);
+ smap_add_format(details, "kpkts_rate", "%"PRIu32, policer->kpkts_rate);
+ smap_add_format(details, "kpkts_burst", "%"PRIu32, policer->kpkts_burst);
return 0;
}
@@ -4828,25 +4882,37 @@ egress_policer_qos_is_equal(const struct qos_conf *conf,
struct egress_policer *policer =
CONTAINER_OF(conf, struct egress_policer, qos_conf);
struct rte_meter_srtcm_params params;
+ uint32_t kpkts_burst, kpkts_rate;
egress_policer_details_to_param(details, ¶ms);
- return !memcmp(¶ms, &policer->app_srtcm_params, sizeof params);
+ kpkts_rate = smap_get_uint(details, "kpkts_rate", 0);
+ kpkts_burst = smap_get_uint(details, "kpkts_burst", 0);
+
+ return (!memcmp(¶ms, &policer->app_srtcm_params, sizeof params))
+ && (policer->kpkts_rate == kpkts_rate
+ && policer->kpkts_burst == kpkts_burst);
}
static int
egress_policer_run(struct 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);
+ if (policer->type & POLICER_BPS) {
+ pkt_cnt = srtcm_policer_run_single_packet(&policer->egress_meter,
+ &policer->egress_prof, pkts,
+ pkt_cnt, should_steal);
+ }
- return cnt;
+ if (policer->type & POLICER_PKTPS) {
+ pkt_cnt = pkts_policer_run_single_packet(&policer->egress_tb, pkts,
+ pkt_cnt, should_steal);
+ }
+
+ return pkt_cnt;
}
static const struct dpdk_qos_ops egress_policer_ops = {
@@ -570,6 +570,140 @@ dnl --------------------------------------------------------------------------
+dnl --------------------------------------------------------------------------
+dnl QoS (kpkts) create delete phy port
+AT_SETUP([OVS-DPDK - QoS (kpkts) create delete phy port])
+AT_KEYWORDS([dpdk])
+
+OVS_DPDK_PRE_PHY_SKIP()
+OVS_DPDK_START()
+
+dnl Add userspace bridge and attach it to OVS and add egress policer
+AT_CHECK([ovs-vsctl add-br br10 -- set bridge br10 datapath_type=netdev])
+AT_CHECK([ovs-vsctl add-port br10 phy0 -- set Interface phy0 type=dpdk options:dpdk-devargs=$(cat PCI_ADDR)], [], [stdout], [stderr])
+OVS_WAIT_UNTIL([ovs-vsctl set port phy0 qos=@newqos -- --id=@newqos create qos type=egress-policer other-config:kpkts_rate=123 other-config:kpkts_burst=246])
+AT_CHECK([ovs-appctl -t ovs-vswitchd qos/show phy0], [], [stdout])
+sleep 2
+
+dnl Remove egress policer
+AT_CHECK([ovs-vsctl destroy QoS phy0 -- clear Port phy0 qos])
+
+dnl Check egress policer was removed correctly
+AT_CHECK([ovs-appctl -t ovs-vswitchd qos/show phy0], [], [stdout])
+AT_CHECK([grep -E 'QoS not configured on phy0' stdout], [], [stdout])
+
+dnl Clean up
+AT_CHECK([ovs-vsctl del-port br10 phy0], [], [stdout], [stderr])
+OVS_VSWITCHD_STOP("[SYSTEM_DPDK_ALLOWED_LOGS]")
+AT_CLEANUP
+dnl --------------------------------------------------------------------------
+
+
+
+dnl --------------------------------------------------------------------------
+dnl QoS (kpkts) create delete vport port
+AT_SETUP([OVS-DPDK - QoS (kpkts) create delete vport port])
+AT_KEYWORDS([dpdk])
+
+OVS_DPDK_PRE_CHECK()
+OVS_DPDK_START()
+
+dnl Add userspace bridge and attach it to OVS and add egress policer
+AT_CHECK([ovs-vsctl add-br br10 -- set bridge br10 datapath_type=netdev])
+AT_CHECK([ovs-vsctl add-port br10 dpdkvhostuserclient0 -- set Interface dpdkvhostuserclient0 type=dpdkvhostuserclient options:vhost-server-path=$OVS_RUNDIR/dpdkvhostclient0], [], [stdout], [stderr])
+OVS_WAIT_UNTIL([ovs-vsctl set port dpdkvhostuserclient0 qos=@newqos -- --id=@newqos create qos type=egress-policer other-config:kpkts_rate=123 \
+ other-config:kpkts_burst=456])
+AT_CHECK([ovs-appctl -t ovs-vswitchd qos/show dpdkvhostuserclient0], [], [stdout])
+sleep 2
+
+dnl Parse log file
+AT_CHECK([grep "VHOST_CONFIG: ($OVS_RUNDIR/dpdkvhostclient0) vhost-user client: socket created" ovs-vswitchd.log], [], [stdout])
+AT_CHECK([grep "vHost User device 'dpdkvhostuserclient0' created in 'client' mode, using client socket" ovs-vswitchd.log], [], [stdout])
+AT_CHECK([grep "VHOST_CONFIG: ($OVS_RUNDIR/dpdkvhostclient0) reconnecting..." ovs-vswitchd.log], [], [stdout])
+
+dnl Remove egress policer
+AT_CHECK([ovs-vsctl destroy QoS dpdkvhostuserclient0 -- clear Port dpdkvhostuserclient0 qos])
+
+dnl Check egress policer was removed correctly
+AT_CHECK([ovs-appctl -t ovs-vswitchd qos/show dpdkvhostuserclient0], [], [stdout])
+AT_CHECK([grep -E 'QoS not configured on dpdkvhostuserclient0' stdout], [], [stdout])
+
+dnl Clean up
+AT_CHECK([ovs-vsctl del-port br10 dpdkvhostuserclient0], [], [stdout], [stderr])
+OVS_VSWITCHD_STOP("m4_join([], [SYSTEM_DPDK_ALLOWED_LOGS], [
+\@VHOST_CONFIG: ($OVS_RUNDIR/dpdkvhostclient0) failed to connect: No such file or directory@d
+\@Failed to set QoS type egress-policer on port dpdkvhostuserclient0@d
+])")
+AT_CLEANUP
+dnl --------------------------------------------------------------------------
+
+
+
+dnl --------------------------------------------------------------------------
+dnl QoS (kpkts) no rate
+AT_SETUP([OVS-DPDK - QoS (kpkts) no rate])
+AT_KEYWORDS([dpdk])
+
+OVS_DPDK_PRE_CHECK()
+OVS_DPDK_START()
+
+dnl Add userspace bridge and attach it to OVS and add egress policer
+AT_CHECK([ovs-vsctl add-br br10 -- set bridge br10 datapath_type=netdev])
+AT_CHECK([ovs-vsctl add-port br10 dpdkvhostuserclient0 -- set Interface dpdkvhostuserclient0 type=dpdkvhostuserclient options:vhost-server-path=$OVS_RUNDIR/dpdkvhostclient0], [], [stdout], [stderr])
+OVS_WAIT_UNTIL([ovs-vsctl set port dpdkvhostuserclient0 qos=@newqos -- --id=@newqos create qos type=egress-policer other-config:kpkts_burst=123])
+sleep 2
+
+dnl Parse log file
+AT_CHECK([grep "VHOST_CONFIG: ($OVS_RUNDIR/dpdkvhostclient0) vhost-user client: socket created" ovs-vswitchd.log], [], [stdout])
+AT_CHECK([grep "vHost User device 'dpdkvhostuserclient0' created in 'client' mode, using client socket" ovs-vswitchd.log], [], [stdout])
+AT_CHECK([grep "VHOST_CONFIG: ($OVS_RUNDIR/dpdkvhostclient0) reconnecting..." ovs-vswitchd.log], [], [stdout])
+
+dnl Check egress policer was not created
+AT_CHECK([ovs-appctl -t ovs-vswitchd qos/show dpdkvhostuserclient0], [], [stdout])
+AT_CHECK([grep -E 'QoS not configured on dpdkvhostuserclient0' stdout], [], [stdout])
+
+dnl Clean up
+AT_CHECK([ovs-vsctl del-port br10 dpdkvhostuserclient0], [], [stdout], [stderr])
+OVS_VSWITCHD_STOP("m4_join([], [SYSTEM_DPDK_ALLOWED_LOGS], [
+\@VHOST_CONFIG: ($OVS_RUNDIR/dpdkvhostclient0) failed to connect: No such file or directory@d
+\@Could not create rte meter for egress policer@d
+\@Failed to set QoS type egress-policer on port dpdkvhostuserclient0@d
+])")
+AT_CLEANUP
+dnl --------------------------------------------------------------------------
+
+
+
+dnl --------------------------------------------------------------------------
+dnl QoS (kpkts) no burst
+AT_SETUP([OVS-DPDK - QoS (kpkts) no burst])
+AT_KEYWORDS([dpdk])
+
+OVS_DPDK_PRE_CHECK()
+OVS_DPDK_START()
+
+dnl Add userspace bridge and attach it to OVS and add egress policer
+AT_CHECK([ovs-vsctl add-br br10 -- set bridge br10 datapath_type=netdev])
+AT_CHECK([ovs-vsctl add-port br10 dpdkvhostuserclient0 -- set Interface dpdkvhostuserclient0 type=dpdkvhostuserclient options:vhost-server-path=$OVS_RUNDIR/dpdkvhostclient0], [], [stdout], [stderr])
+OVS_WAIT_UNTIL([ovs-vsctl set port dpdkvhostuserclient0 qos=@newqos -- --id=@newqos create qos type=egress-policer other-config:kpkts_rate=123])
+sleep 2
+
+dnl Parse log file
+AT_CHECK([grep "VHOST_CONFIG: ($OVS_RUNDIR/dpdkvhostclient0) vhost-user client: socket created" ovs-vswitchd.log], [], [stdout])
+AT_CHECK([grep "vHost User device 'dpdkvhostuserclient0' created in 'client' mode, using client socket" ovs-vswitchd.log], [], [stdout])
+AT_CHECK([grep "VHOST_CONFIG: ($OVS_RUNDIR/dpdkvhostclient0) reconnecting..." ovs-vswitchd.log], [], [stdout])
+
+dnl Clean up
+AT_CHECK([ovs-vsctl del-port br10 dpdkvhostuserclient0], [], [stdout], [stderr])
+OVS_VSWITCHD_STOP("m4_join([], [SYSTEM_DPDK_ALLOWED_LOGS], [
+\@VHOST_CONFIG: ($OVS_RUNDIR/dpdkvhostclient0) failed to connect: No such file or directory@d
+\@Could not create rte meter for egress policer@d
+\@Failed to set QoS type egress-policer on port dpdkvhostuserclient0@d
+])")
+AT_CLEANUP
+dnl --------------------------------------------------------------------------
+
+
dnl --------------------------------------------------------------------------
dnl MTU increase phy port
@@ -4894,6 +4894,16 @@ ovs-vsctl add-port br0 p0 -- set Interface p0 type=patch options:peer=p1 \
bytes/tokens of the packet. If there are not enough tokens in the cbs
bucket the packet might be dropped.
</column>
+ <column name="other_config" key="kpkts_rate"
+ type='{"type": "integer", "minInteger": 0, "maxInteger": 4294967}'>
+ The Packets Per Second (pps) represents the packet per second rate at
+ which the token bucket will be updated.
+ </column>
+ <column name="other_config" key="kpkts_burst"
+ type='{"type": "integer", "minInteger": 0, "maxInteger": 4294967}'>
+ The Packets Per Second Burst Size is measured in count and represents a
+ token bucket.
+ </column>
</group>
<group title="Configuration for linux-sfq">