mirror of
https://github.com/openvswitch/ovs
synced 2025-08-31 06:15:47 +00:00
add port-based ingress policing based packet-per-second rate-limiting
OVS has support for using policing to enforce a rate limit in kilobits per second. This is configured using OVSDB. f.e. $ ovs-vsctl set interface tap0 ingress_policing_rate=1000 $ ovs-vsctl set interface tap0 ingress_policing_burst=100 This patch adds a related feature, allowing policing to enforce a rate limit in kilo-packets per second. This is also configured using OVSDB. $ ovs-vsctl set interface tap0 ingress_policing_kpkts_rate=1000 $ ovs-vsctl set interface tap0 ingress_policing_kpkts_burst=100 The kilo-bit and kilo-packet rate limits may be used separately or in combination. Add separate action for BPS and PPS in netlink message. Revise code and change action result to pipe to allow traffic pipe into second action. This patch implements the feature for: * OVSDB (northbound API) * TC policer when used both with and without TC offload (kernel API) Signed-off-by: Yong Xu <yong.xu@corigine.com> Signed-off-by: Simon Horman <simon.horman@netronome.com>
This commit is contained in:
@@ -485,8 +485,10 @@ static struct tcmsg *netdev_linux_tc_make_request(const struct netdev *,
|
||||
int type,
|
||||
unsigned int flags,
|
||||
struct ofpbuf *);
|
||||
static int tc_add_policer(struct netdev *,
|
||||
uint32_t kbits_rate, uint32_t kbits_burst);
|
||||
|
||||
static int tc_add_policer(struct netdev *, uint32_t kbits_rate,
|
||||
uint32_t kbits_burst, uint32_t kpkts_rate,
|
||||
uint32_t kpkts_burst);
|
||||
|
||||
static int tc_parse_qdisc(const struct ofpbuf *, const char **kind,
|
||||
struct nlattr **options);
|
||||
@@ -2595,24 +2597,62 @@ tc_matchall_fill_police(uint32_t kbits_rate, uint32_t kbits_burst)
|
||||
}
|
||||
|
||||
static void
|
||||
nl_msg_put_act_police(struct ofpbuf *request, struct tc_police police)
|
||||
nl_msg_act_police_start_nest(struct ofpbuf *request, uint32_t prio,
|
||||
size_t *offset, size_t *act_offset)
|
||||
{
|
||||
size_t offset;
|
||||
|
||||
*act_offset = nl_msg_start_nested(request, prio);
|
||||
nl_msg_put_string(request, TCA_ACT_KIND, "police");
|
||||
offset = nl_msg_start_nested(request, TCA_ACT_OPTIONS);
|
||||
nl_msg_put_unspec(request, TCA_POLICE_TBF, &police, sizeof police);
|
||||
tc_put_rtab(request, TCA_POLICE_RATE, &police.rate);
|
||||
nl_msg_put_u32(request, TCA_POLICE_RESULT, TC_ACT_UNSPEC);
|
||||
*offset = nl_msg_start_nested(request, TCA_ACT_OPTIONS);
|
||||
}
|
||||
|
||||
static void
|
||||
nl_msg_act_police_end_nest(struct ofpbuf *request, size_t offset,
|
||||
size_t act_offset)
|
||||
{
|
||||
nl_msg_put_u32(request, TCA_POLICE_RESULT, TC_ACT_PIPE);
|
||||
nl_msg_end_nested(request, offset);
|
||||
nl_msg_end_nested(request, act_offset);
|
||||
}
|
||||
|
||||
static void
|
||||
nl_msg_put_act_police(struct ofpbuf *request, struct tc_police police,
|
||||
uint32_t kpkts_rate, uint32_t kpkts_burst)
|
||||
{
|
||||
size_t offset, act_offset;
|
||||
uint32_t prio = 0;
|
||||
/* used for PPS, set rate as 0 to act as a single action */
|
||||
struct tc_police null_police = {0};
|
||||
|
||||
if (police.rate.rate) {
|
||||
nl_msg_act_police_start_nest(request, ++prio, &offset, &act_offset);
|
||||
tc_put_rtab(request, TCA_POLICE_RATE, &police.rate);
|
||||
nl_msg_put_unspec(request, TCA_POLICE_TBF, &police, sizeof police);
|
||||
nl_msg_act_police_end_nest(request, offset, act_offset);
|
||||
}
|
||||
if (kpkts_rate) {
|
||||
unsigned int pkt_burst_ticks, pps_rate, size;
|
||||
nl_msg_act_police_start_nest(request, ++prio, &offset, &act_offset);
|
||||
pps_rate = kpkts_rate * 1000;
|
||||
size = MIN(UINT32_MAX / 1000, kpkts_burst) * 1000;
|
||||
/* Here tc_bytes_to_ticks is used to convert packets rather than bytes
|
||||
to ticks. */
|
||||
pkt_burst_ticks = tc_bytes_to_ticks(pps_rate, size);
|
||||
nl_msg_put_u64(request, TCA_POLICE_PKTRATE64, (uint64_t) pps_rate);
|
||||
nl_msg_put_u64(request, TCA_POLICE_PKTBURST64,
|
||||
(uint64_t) pkt_burst_ticks);
|
||||
nl_msg_put_unspec(request, TCA_POLICE_TBF, &null_police,
|
||||
sizeof null_police);
|
||||
nl_msg_act_police_end_nest(request, offset, act_offset);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
tc_add_matchall_policer(struct netdev *netdev, uint32_t kbits_rate,
|
||||
uint32_t kbits_burst)
|
||||
uint32_t kbits_burst, uint32_t kpkts_rate,
|
||||
uint32_t kpkts_burst)
|
||||
{
|
||||
uint16_t eth_type = (OVS_FORCE uint16_t) htons(ETH_P_ALL);
|
||||
size_t basic_offset, action_offset, inner_offset;
|
||||
size_t basic_offset, action_offset;
|
||||
uint16_t prio = TC_RESERVED_PRIORITY_POLICE;
|
||||
int ifindex, err = 0;
|
||||
struct tc_police pol_act;
|
||||
@@ -2636,9 +2676,7 @@ tc_add_matchall_policer(struct netdev *netdev, uint32_t kbits_rate,
|
||||
nl_msg_put_string(&request, TCA_KIND, "matchall");
|
||||
basic_offset = nl_msg_start_nested(&request, TCA_OPTIONS);
|
||||
action_offset = nl_msg_start_nested(&request, TCA_MATCHALL_ACT);
|
||||
inner_offset = nl_msg_start_nested(&request, 1);
|
||||
nl_msg_put_act_police(&request, pol_act);
|
||||
nl_msg_end_nested(&request, inner_offset);
|
||||
nl_msg_put_act_police(&request, pol_act, kpkts_rate, kpkts_burst);
|
||||
nl_msg_end_nested(&request, action_offset);
|
||||
nl_msg_end_nested(&request, basic_offset);
|
||||
|
||||
@@ -2678,8 +2716,9 @@ tc_del_matchall_policer(struct netdev *netdev)
|
||||
/* Attempts to set input rate limiting (policing) policy. Returns 0 if
|
||||
* successful, otherwise a positive errno value. */
|
||||
static int
|
||||
netdev_linux_set_policing(struct netdev *netdev_,
|
||||
uint32_t kbits_rate, uint32_t kbits_burst)
|
||||
netdev_linux_set_policing(struct netdev *netdev_, uint32_t kbits_rate,
|
||||
uint32_t kbits_burst, uint32_t kpkts_rate,
|
||||
uint32_t kpkts_burst)
|
||||
{
|
||||
struct netdev_linux *netdev = netdev_linux_cast(netdev_);
|
||||
const char *netdev_name = netdev_get_name(netdev_);
|
||||
@@ -2690,6 +2729,10 @@ netdev_linux_set_policing(struct netdev *netdev_,
|
||||
: !kbits_burst ? 8000 /* Default to 8000 kbits if 0. */
|
||||
: kbits_burst); /* Stick with user-specified value. */
|
||||
|
||||
kpkts_burst = (!kpkts_rate ? 0 /* Force to 0 if no rate specified. */
|
||||
: !kpkts_burst ? 16 /* Default to 16 kpkts if 0. */
|
||||
: kpkts_burst); /* Stick with user-specified value. */
|
||||
|
||||
ovs_mutex_lock(&netdev->mutex);
|
||||
if (netdev_linux_netnsid_is_remote(netdev)) {
|
||||
error = EOPNOTSUPP;
|
||||
@@ -2699,7 +2742,9 @@ netdev_linux_set_policing(struct netdev *netdev_,
|
||||
if (netdev->cache_valid & VALID_POLICING) {
|
||||
error = netdev->netdev_policing_error;
|
||||
if (error || (netdev->kbits_rate == kbits_rate &&
|
||||
netdev->kbits_burst == kbits_burst)) {
|
||||
netdev->kpkts_rate == kpkts_rate &&
|
||||
netdev->kbits_burst == kbits_burst &&
|
||||
netdev->kpkts_burst == kpkts_burst)) {
|
||||
/* Assume that settings haven't changed since we last set them. */
|
||||
goto out;
|
||||
}
|
||||
@@ -2711,8 +2756,9 @@ netdev_linux_set_policing(struct netdev *netdev_,
|
||||
/* Use matchall for policing when offloadling ovs with tc-flower. */
|
||||
if (netdev_is_flow_api_enabled()) {
|
||||
error = tc_del_matchall_policer(netdev_);
|
||||
if (kbits_rate) {
|
||||
error = tc_add_matchall_policer(netdev_, kbits_rate, kbits_burst);
|
||||
if (kbits_rate || kpkts_rate) {
|
||||
error = tc_add_matchall_policer(netdev_, kbits_rate, kbits_burst,
|
||||
kpkts_rate, kpkts_burst);
|
||||
}
|
||||
ovs_mutex_unlock(&netdev->mutex);
|
||||
return error;
|
||||
@@ -2731,7 +2777,7 @@ netdev_linux_set_policing(struct netdev *netdev_,
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (kbits_rate) {
|
||||
if (kbits_rate || kpkts_rate) {
|
||||
error = tc_add_del_qdisc(ifindex, true, 0, TC_INGRESS);
|
||||
if (error) {
|
||||
VLOG_WARN_RL(&rl, "%s: adding policing qdisc failed: %s",
|
||||
@@ -2739,7 +2785,8 @@ netdev_linux_set_policing(struct netdev *netdev_,
|
||||
goto out;
|
||||
}
|
||||
|
||||
error = tc_add_policer(netdev_, kbits_rate, kbits_burst);
|
||||
error = tc_add_policer(netdev_, kbits_rate, kbits_burst,
|
||||
kpkts_rate, kpkts_burst);
|
||||
if (error){
|
||||
VLOG_WARN_RL(&rl, "%s: adding policing action failed: %s",
|
||||
netdev_name, ovs_strerror(error));
|
||||
@@ -2749,6 +2796,8 @@ netdev_linux_set_policing(struct netdev *netdev_,
|
||||
|
||||
netdev->kbits_rate = kbits_rate;
|
||||
netdev->kbits_burst = kbits_burst;
|
||||
netdev->kpkts_rate = kpkts_rate;
|
||||
netdev->kpkts_burst = kpkts_burst;
|
||||
|
||||
out:
|
||||
if (!error || error == ENODEV) {
|
||||
@@ -5525,7 +5574,8 @@ netdev_linux_tc_make_request(const struct netdev *netdev, int type,
|
||||
}
|
||||
|
||||
/* Adds a policer to 'netdev' with a rate of 'kbits_rate' and a burst size
|
||||
* of 'kbits_burst'.
|
||||
* of 'kbits_burst', with a rate of 'kpkts_rate' and a burst size of
|
||||
* 'kpkts_burst'.
|
||||
*
|
||||
* This function is equivalent to running:
|
||||
* /sbin/tc filter add dev <devname> parent ffff: protocol all prio 49
|
||||
@@ -5538,14 +5588,14 @@ netdev_linux_tc_make_request(const struct netdev *netdev, int type,
|
||||
* Returns 0 if successful, otherwise a positive errno value.
|
||||
*/
|
||||
static int
|
||||
tc_add_policer(struct netdev *netdev,
|
||||
uint32_t kbits_rate, uint32_t kbits_burst)
|
||||
tc_add_policer(struct netdev *netdev, uint32_t kbits_rate,
|
||||
uint32_t kbits_burst, uint32_t kpkts_rate,
|
||||
uint32_t kpkts_burst)
|
||||
{
|
||||
size_t basic_offset, police_offset;
|
||||
struct tc_police tc_police;
|
||||
struct ofpbuf request;
|
||||
struct tcmsg *tcmsg;
|
||||
size_t basic_offset;
|
||||
size_t police_offset;
|
||||
int error;
|
||||
int mtu = 65535;
|
||||
|
||||
@@ -5563,7 +5613,6 @@ tc_add_policer(struct netdev *netdev,
|
||||
* tc's point of view. Whatever. */
|
||||
tc_police.burst = tc_bytes_to_ticks(
|
||||
tc_police.rate.rate, MIN(UINT32_MAX / 1024, kbits_burst) * 1024 / 8);
|
||||
|
||||
tcmsg = netdev_linux_tc_make_request(netdev, RTM_NEWTFILTER,
|
||||
NLM_F_EXCL | NLM_F_CREATE, &request);
|
||||
if (!tcmsg) {
|
||||
@@ -5572,12 +5621,10 @@ tc_add_policer(struct netdev *netdev,
|
||||
tcmsg->tcm_parent = tc_make_handle(0xffff, 0);
|
||||
tcmsg->tcm_info = tc_make_handle(49,
|
||||
(OVS_FORCE uint16_t) htons(ETH_P_ALL));
|
||||
|
||||
nl_msg_put_string(&request, TCA_KIND, "basic");
|
||||
basic_offset = nl_msg_start_nested(&request, TCA_OPTIONS);
|
||||
police_offset = nl_msg_start_nested(&request, TCA_BASIC_POLICE);
|
||||
nl_msg_put_unspec(&request, TCA_POLICE_TBF, &tc_police, sizeof tc_police);
|
||||
tc_put_rtab(&request, TCA_POLICE_RATE, &tc_police.rate);
|
||||
police_offset = nl_msg_start_nested(&request, TCA_BASIC_ACT);
|
||||
nl_msg_put_act_police(&request, tc_police, kpkts_rate, kpkts_burst);
|
||||
nl_msg_end_nested(&request, police_offset);
|
||||
nl_msg_end_nested(&request, basic_offset);
|
||||
|
||||
|
Reference in New Issue
Block a user