policer: output interface policer

Type: improvement

Change-Id: Ibc1b5059ed51c34334340534e9eb68121f556bce
Signed-off-by: Stanislav Zaikin <zstaseg@gmail.com>
This commit is contained in:
Stanislav Zaikin
2022-04-05 19:23:12 +02:00
committed by Neale Ranns
parent 0ec1c6dc68
commit e5a3ae0179
8 changed files with 195 additions and 46 deletions

View File

@ -68,7 +68,7 @@ static char *vnet_policer_error_strings[] = {
static inline uword
vnet_policer_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
vlib_frame_t *frame)
vlib_frame_t *frame, vlib_dir_t dir)
{
u32 n_left_from, *from, *to_next;
vnet_policer_next_t next_index;
@ -120,11 +120,11 @@ vnet_policer_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
b0 = vlib_get_buffer (vm, bi0);
b1 = vlib_get_buffer (vm, bi1);
sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
sw_if_index0 = vnet_buffer (b0)->sw_if_index[dir];
sw_if_index1 = vnet_buffer (b1)->sw_if_index[dir];
pi0 = pm->policer_index_by_sw_if_index[sw_if_index0];
pi1 = pm->policer_index_by_sw_if_index[sw_if_index1];
pi0 = pm->policer_index_by_sw_if_index[dir][sw_if_index0];
pi1 = pm->policer_index_by_sw_if_index[dir][sw_if_index1];
act0 = vnet_policer_police (vm, b0, pi0, time_in_policer_periods,
POLICE_CONFORM /* no chaining */, true);
@ -206,9 +206,8 @@ vnet_policer_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
b0 = vlib_get_buffer (vm, bi0);
sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
pi0 = pm->policer_index_by_sw_if_index[sw_if_index0];
sw_if_index0 = vnet_buffer (b0)->sw_if_index[dir];
pi0 = pm->policer_index_by_sw_if_index[dir][sw_if_index0];
act0 = vnet_policer_police (vm, b0, pi0, time_in_policer_periods,
POLICE_CONFORM /* no chaining */, true);
@ -256,7 +255,7 @@ vnet_policer_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
VLIB_NODE_FN (policer_input_node)
(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
{
return vnet_policer_inline (vm, node, frame);
return vnet_policer_inline (vm, node, frame, VLIB_RX);
}
VLIB_REGISTER_NODE (policer_input_node) = {
@ -279,12 +278,43 @@ VNET_FEATURE_INIT (policer_input_node, static) = {
.runs_before = VNET_FEATURES ("ethernet-input"),
};
VLIB_NODE_FN (policer_output_node)
(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
{
return vnet_policer_inline (vm, node, frame, VLIB_TX);
}
VLIB_REGISTER_NODE (policer_output_node) = {
.name = "policer-output",
.vector_size = sizeof (u32),
.format_trace = format_policer_trace,
.type = VLIB_NODE_TYPE_INTERNAL,
.n_errors = ARRAY_LEN(vnet_policer_error_strings),
.error_strings = vnet_policer_error_strings,
.n_next_nodes = VNET_POLICER_N_NEXT,
.next_nodes = {
[VNET_POLICER_NEXT_DROP] = "error-drop",
[VNET_POLICER_NEXT_HANDOFF] = "policer-output-handoff",
},
};
VNET_FEATURE_INIT (policer_output_node, static) = {
.arc_name = "ip4-output",
.node_name = "policer-output",
};
VNET_FEATURE_INIT (policer6_output_node, static) = {
.arc_name = "ip6-output",
.node_name = "policer-output",
};
static char *policer_input_handoff_error_strings[] = { "congestion drop" };
VLIB_NODE_FN (policer_input_handoff_node)
(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
{
return policer_handoff (vm, node, frame, vnet_policer_main.fq_index, ~0);
return policer_handoff (vm, node, frame, vnet_policer_main.fq_index[VLIB_RX],
~0);
}
VLIB_REGISTER_NODE (policer_input_handoff_node) = {
@ -301,6 +331,26 @@ VLIB_REGISTER_NODE (policer_input_handoff_node) = {
},
};
VLIB_NODE_FN (policer_output_handoff_node)
(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
{
return policer_handoff (vm, node, frame, vnet_policer_main.fq_index[VLIB_TX],
~0);
}
VLIB_REGISTER_NODE (policer_output_handoff_node) = {
.name = "policer-output-handoff",
.vector_size = sizeof (u32),
.format_trace = format_policer_handoff_trace,
.type = VLIB_NODE_TYPE_INTERNAL,
.n_errors = ARRAY_LEN(policer_input_handoff_error_strings),
.error_strings = policer_input_handoff_error_strings,
.n_next_nodes = 1,
.next_nodes = {
[0] = "error-drop",
},
};
typedef struct
{
u32 sw_if_index;

View File

@ -52,6 +52,23 @@ autoreply define policer_input
bool apply;
};
/** \brief policer output: Apply policer as an output feature.
@param client_index - opaque cookie to identify the sender
@param context - sender context, to match reply w/ request
@param name - policer name
@param sw_if_index - interface to apply the policer
@param apply - Apply/remove
*/
autoreply define policer_output
{
u32 client_index;
u32 context;
string name[64];
vl_api_interface_index_t sw_if_index;
bool apply;
};
/** \brief Add/del policer
@param client_index - opaque cookie to identify the sender
@param context - sender context, to match reply w/ request

View File

@ -166,7 +166,7 @@ policer_bind_worker (u8 *name, u32 worker, bool bind)
}
int
policer_input (u8 *name, u32 sw_if_index, bool apply)
policer_input (u8 *name, u32 sw_if_index, vlib_dir_t dir, bool apply)
{
vnet_policer_main_t *pm = &vnet_policer_main;
policer_t *policer;
@ -184,16 +184,26 @@ policer_input (u8 *name, u32 sw_if_index, bool apply)
if (apply)
{
vec_validate (pm->policer_index_by_sw_if_index, sw_if_index);
pm->policer_index_by_sw_if_index[sw_if_index] = policer_index;
vec_validate (pm->policer_index_by_sw_if_index[dir], sw_if_index);
pm->policer_index_by_sw_if_index[dir][sw_if_index] = policer_index;
}
else
{
pm->policer_index_by_sw_if_index[sw_if_index] = ~0;
pm->policer_index_by_sw_if_index[dir][sw_if_index] = ~0;
}
vnet_feature_enable_disable ("device-input", "policer-input", sw_if_index,
apply, 0, 0);
if (dir == VLIB_RX)
{
vnet_feature_enable_disable ("device-input", "policer-input",
sw_if_index, apply, 0, 0);
}
else
{
vnet_feature_enable_disable ("ip4-output", "policer-output", sw_if_index,
apply, 0, 0);
vnet_feature_enable_disable ("ip6-output", "policer-output", sw_if_index,
apply, 0, 0);
}
return 0;
}
@ -637,6 +647,7 @@ policer_input_command_fn (vlib_main_t *vm, unformat_input_t *input,
u8 apply, *name = 0;
u32 sw_if_index;
int rv;
vlib_dir_t dir = cmd->function_arg;
apply = 1;
sw_if_index = ~0;
@ -669,7 +680,7 @@ policer_input_command_fn (vlib_main_t *vm, unformat_input_t *input,
}
else
{
rv = policer_input (name, sw_if_index, apply);
rv = policer_input (name, sw_if_index, dir, apply);
if (rv)
error = clib_error_return (0, "failed: `%d'", rv);
@ -681,33 +692,43 @@ done:
return error;
}
/* *INDENT-OFF* */
VLIB_CLI_COMMAND (configure_policer_command, static) = {
.path = "configure policer",
.short_help = "configure policer name <name> <params> ",
.function = policer_add_command_fn,
};
VLIB_CLI_COMMAND (policer_add_command, static) = {
.path = "policer add",
.short_help = "policer name <name> <params> ",
.function = policer_add_command_fn,
};
VLIB_CLI_COMMAND (policer_del_command, static) = {
.path = "policer del",
.short_help = "policer del name <name> ",
.function = policer_del_command_fn,
};
VLIB_CLI_COMMAND (policer_bind_command, static) = {
.path = "policer bind",
.short_help = "policer bind [unbind] name <name> <worker>",
.function = policer_bind_command_fn,
};
VLIB_CLI_COMMAND (policer_input_command, static) = {
.path = "policer input",
.short_help = "policer input [unapply] name <name> <interfac>",
.function = policer_input_command_fn,
.function_arg = VLIB_RX,
};
VLIB_CLI_COMMAND (policer_output_command, static) = {
.path = "policer output",
.short_help = "policer output [unapply] name <name> <interfac>",
.function = policer_input_command_fn,
.function_arg = VLIB_TX,
};
/* *INDENT-ON* */
static clib_error_t *
show_policer_command_fn (vlib_main_t * vm,
@ -792,7 +813,10 @@ policer_init (vlib_main_t * vm)
pm->vlib_main = vm;
pm->vnet_main = vnet_get_main ();
pm->log_class = vlib_log_register_class ("policer", 0);
pm->fq_index = vlib_frame_queue_main_init (policer_input_node.index, 0);
pm->fq_index[VLIB_RX] =
vlib_frame_queue_main_init (policer_input_node.index, 0);
pm->fq_index[VLIB_TX] =
vlib_frame_queue_main_init (policer_output_node.index, 0);
pm->policer_config_by_name = hash_create_string (0, sizeof (uword));
pm->policer_index_by_name = hash_create_string (0, sizeof (uword));

View File

@ -39,7 +39,7 @@ typedef struct
uword *policer_index_by_name;
/* Policer by sw_if_index vector */
u32 *policer_index_by_sw_if_index;
u32 *policer_index_by_sw_if_index[VLIB_N_RX_TX];
/* convenience */
vlib_main_t *vlib_main;
@ -48,7 +48,7 @@ typedef struct
vlib_log_class_t log_class;
/* frame queue for thread handoff */
u32 fq_index;
u32 fq_index[VLIB_N_RX_TX];
u16 msg_id_base;
} vnet_policer_main_t;
@ -58,6 +58,7 @@ extern vnet_policer_main_t vnet_policer_main;
extern vlib_combined_counter_main_t policer_counters[];
extern vlib_node_registration_t policer_input_node;
extern vlib_node_registration_t policer_output_node;
typedef enum
{
@ -71,7 +72,7 @@ clib_error_t *policer_add_del (vlib_main_t *vm, u8 *name,
qos_pol_cfg_params_st *cfg, u32 *policer_index,
u8 is_add);
int policer_bind_worker (u8 *name, u32 worker, bool bind);
int policer_input (u8 *name, u32 sw_if_index, bool apply);
int policer_input (u8 *name, u32 sw_if_index, vlib_dir_t dir, bool apply);
#endif /* __included_policer_h__ */

View File

@ -120,13 +120,37 @@ vl_api_policer_input_t_handler (vl_api_policer_input_t *mp)
sw_if_index = ntohl (mp->sw_if_index);
apply = mp->apply;
rv = policer_input (name, sw_if_index, apply);
rv = policer_input (name, sw_if_index, VLIB_RX, apply);
vec_free (name);
BAD_SW_IF_INDEX_LABEL;
REPLY_MACRO (VL_API_POLICER_INPUT_REPLY);
}
static void
vl_api_policer_output_t_handler (vl_api_policer_input_t *mp)
{
vl_api_policer_bind_reply_t *rmp;
u8 *name;
u32 sw_if_index;
u8 apply;
int rv;
VALIDATE_SW_IF_INDEX (mp);
name = format (0, "%s", mp->name);
vec_terminate_c_string (name);
sw_if_index = ntohl (mp->sw_if_index);
apply = mp->apply;
rv = policer_input (name, sw_if_index, VLIB_TX, apply);
vec_free (name);
BAD_SW_IF_INDEX_LABEL;
REPLY_MACRO (VL_API_POLICER_OUTPUT_REPLY);
}
static void
send_policer_details (u8 *name, qos_pol_cfg_params_st *config,
policer_t *templ, vl_api_registration_t *reg,

View File

@ -25,7 +25,7 @@ from util import ppp
from vpp_papi import VppEnum
from vpp_papi_provider import CliFailedCommandError
from vpp_acl import AclRule, VppAcl, VppAclInterface
from vpp_policer import PolicerAction, VppPolicer
from vpp_policer import PolicerAction, VppPolicer, Dir
def config_tun_params(p, encryption_type, tun_if, src=None, dst=None):
@ -513,7 +513,7 @@ class TestIpsec6TunIfEspHandoff(TemplateIpsec6TunIfEsp,
policer.add_vpp_config()
# Start policing on tun
policer.apply_vpp_config(p.tun_if.sw_if_index, True)
policer.apply_vpp_config(p.tun_if.sw_if_index, Dir.RX, True)
for pol_bind in [1, 0]:
policer.bind_vpp_config(pol_bind, True)
@ -557,7 +557,7 @@ class TestIpsec6TunIfEspHandoff(TemplateIpsec6TunIfEsp,
stats1['conform_packets'] +
stats1['violate_packets'])
policer.apply_vpp_config(p.tun_if.sw_if_index, False)
policer.apply_vpp_config(p.tun_if.sw_if_index, Dir.RX, False)
policer.remove_vpp_config()
@ -585,7 +585,7 @@ class TestIpsec4TunIfEspHandoff(TemplateIpsec4TunIfEsp,
policer.add_vpp_config()
# Start policing on tun
policer.apply_vpp_config(p.tun_if.sw_if_index, True)
policer.apply_vpp_config(p.tun_if.sw_if_index, Dir.RX, True)
for pol_bind in [1, 0]:
policer.bind_vpp_config(pol_bind, True)
@ -629,7 +629,7 @@ class TestIpsec4TunIfEspHandoff(TemplateIpsec4TunIfEsp,
stats1['conform_packets'] +
stats1['violate_packets'])
policer.apply_vpp_config(p.tun_if.sw_if_index, False)
policer.apply_vpp_config(p.tun_if.sw_if_index, Dir.RX, False)
policer.remove_vpp_config()
@ -2726,7 +2726,7 @@ class TestIpsecItf4(TemplateIpsec,
policer.add_vpp_config()
# Start policing on tun
policer.apply_vpp_config(p.tun_if.sw_if_index, True)
policer.apply_vpp_config(p.tun_if.sw_if_index, Dir.RX, True)
self.verify_tun_44(p, count=n_pkts)
self.assertEqual(p.tun_if.get_rx_stats(), n_pkts)
@ -2740,7 +2740,7 @@ class TestIpsecItf4(TemplateIpsec,
self.assertGreater(stats['violate_packets'], 0)
# Stop policing on tun
policer.apply_vpp_config(p.tun_if.sw_if_index, False)
policer.apply_vpp_config(p.tun_if.sw_if_index, Dir.RX, False)
self.verify_tun_44(p, count=n_pkts)
# No new policer stats
@ -3017,7 +3017,7 @@ class TestIpsecItf6(TemplateIpsec,
policer.add_vpp_config()
# Start policing on tun
policer.apply_vpp_config(p.tun_if.sw_if_index, True)
policer.apply_vpp_config(p.tun_if.sw_if_index, Dir.RX, True)
self.verify_tun_66(p, count=n_pkts)
self.assertEqual(p.tun_if.get_rx_stats(), n_pkts)
@ -3031,7 +3031,7 @@ class TestIpsecItf6(TemplateIpsec,
self.assertGreater(stats['violate_packets'], 0)
# Stop policing on tun
policer.apply_vpp_config(p.tun_if.sw_if_index, False)
policer.apply_vpp_config(p.tun_if.sw_if_index, Dir.RX, False)
self.verify_tun_66(p, count=n_pkts)
# No new policer stats

View File

@ -8,13 +8,13 @@ from scapy.layers.l2 import Ether
from scapy.packet import Raw
from framework import VppTestCase, VppTestRunner
from vpp_papi import VppEnum
from vpp_policer import VppPolicer, PolicerAction
from vpp_policer import VppPolicer, PolicerAction, Dir
NUM_PKTS = 67
class TestPolicerInput(VppTestCase):
""" Policer on an input interface """
""" Policer on an interface """
vpp_worker_count = 2
def setUp(self):
@ -38,8 +38,7 @@ class TestPolicerInput(VppTestCase):
i.admin_down()
super(TestPolicerInput, self).tearDown()
def test_policer_input(self):
""" Input Policing """
def policer_interface_test(self, dir: Dir):
pkts = self.pkt * NUM_PKTS
action_tx = PolicerAction(
@ -51,8 +50,12 @@ class TestPolicerInput(VppTestCase):
violate_action=action_tx)
policer.add_vpp_config()
sw_if_index = (self.pg0.sw_if_index
if dir == Dir.RX
else self.pg1.sw_if_index)
# Start policing on pg0
policer.apply_vpp_config(self.pg0.sw_if_index, True)
policer.apply_vpp_config(sw_if_index, dir, True)
rx = self.send_and_expect(self.pg0, pkts, self.pg1, worker=0)
stats = policer.get_stats()
@ -63,7 +66,7 @@ class TestPolicerInput(VppTestCase):
self.assertGreater(stats['violate_packets'], 0)
# Stop policing on pg0
policer.apply_vpp_config(self.pg0.sw_if_index, False)
policer.apply_vpp_config(sw_if_index, dir, False)
rx = self.send_and_expect(self.pg0, pkts, self.pg1, worker=0)
@ -74,8 +77,15 @@ class TestPolicerInput(VppTestCase):
policer.remove_vpp_config()
def test_policer_handoff(self):
""" Worker thread handoff """
def test_policer_input(self):
""" Input Policing """
self.policer_interface_test(Dir.RX)
def test_policer_output(self):
""" Output Policing """
self.policer_interface_test(Dir.TX)
def policer_handoff_test(self, dir: Dir):
pkts = self.pkt * NUM_PKTS
action_tx = PolicerAction(
@ -87,11 +97,15 @@ class TestPolicerInput(VppTestCase):
violate_action=action_tx)
policer.add_vpp_config()
sw_if_index = (self.pg0.sw_if_index
if dir == Dir.RX
else self.pg1.sw_if_index)
# Bind the policer to worker 1
policer.bind_vpp_config(1, True)
# Start policing on pg0
policer.apply_vpp_config(self.pg0.sw_if_index, True)
policer.apply_vpp_config(sw_if_index, dir, True)
for worker in [0, 1]:
self.send_and_expect(self.pg0, pkts, self.pg1, worker=worker)
@ -138,9 +152,18 @@ class TestPolicerInput(VppTestCase):
stats['violate_packets'])
# Stop policing on pg0
policer.apply_vpp_config(self.pg0.sw_if_index, False)
policer.apply_vpp_config(sw_if_index, dir, False)
policer.remove_vpp_config()
def test_policer_handoff_input(self):
""" Worker thread handoff policer input"""
self.policer_handoff_test(Dir.RX)
def test_policer_handoff_output(self):
""" Worker thread handoff policer output"""
self.policer_handoff_test(Dir.TX)
if __name__ == '__main__':
unittest.main(testRunner=VppTestRunner)

View File

@ -1,5 +1,11 @@
from vpp_object import VppObject
from vpp_ip import INVALID_INDEX
from enum import Enum
class Dir(Enum):
RX = 0
TX = 1
class PolicerAction():
@ -61,9 +67,13 @@ class VppPolicer(VppObject):
self._test.vapi.policer_bind(name=self.name, worker_index=worker,
bind_enable=bind)
def apply_vpp_config(self, if_index, apply):
self._test.vapi.policer_input(name=self.name, sw_if_index=if_index,
apply=apply)
def apply_vpp_config(self, if_index, dir: Dir, apply):
if dir == Dir.RX:
self._test.vapi.policer_input(
name=self.name, sw_if_index=if_index, apply=apply)
else:
self._test.vapi.policer_output(
name=self.name, sw_if_index=if_index, apply=apply)
def query_vpp_config(self):
dump = self._test.vapi.policer_dump(