From e5a3ae0179b807efc2202a47e11d698396dd0780 Mon Sep 17 00:00:00 2001 From: Stanislav Zaikin Date: Tue, 5 Apr 2022 19:23:12 +0200 Subject: policer: output interface policer Type: improvement Change-Id: Ibc1b5059ed51c34334340534e9eb68121f556bce Signed-off-by: Stanislav Zaikin --- src/vnet/policer/node_funcs.c | 70 ++++++++++++++++++++++++++++++++++++------ src/vnet/policer/policer.api | 17 ++++++++++ src/vnet/policer/policer.c | 44 ++++++++++++++++++++------ src/vnet/policer/policer.h | 7 +++-- src/vnet/policer/policer_api.c | 26 +++++++++++++++- test/test_ipsec_tun_if_esp.py | 18 +++++------ test/test_policer_input.py | 43 ++++++++++++++++++++------ test/vpp_policer.py | 16 ++++++++-- 8 files changed, 195 insertions(+), 46 deletions(-) diff --git a/src/vnet/policer/node_funcs.c b/src/vnet/policer/node_funcs.c index 21b9393a222..5fa0c8563be 100644 --- a/src/vnet/policer/node_funcs.c +++ b/src/vnet/policer/node_funcs.c @@ -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; diff --git a/src/vnet/policer/policer.api b/src/vnet/policer/policer.api index a664ab0be76..f4bf9384f10 100644 --- a/src/vnet/policer/policer.api +++ b/src/vnet/policer/policer.api @@ -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 diff --git a/src/vnet/policer/policer.c b/src/vnet/policer/policer.c index 9eb56414561..0513563e1ec 100644 --- a/src/vnet/policer/policer.c +++ b/src/vnet/policer/policer.c @@ -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 ", .function = policer_add_command_fn, }; + VLIB_CLI_COMMAND (policer_add_command, static) = { .path = "policer add", .short_help = "policer name ", .function = policer_add_command_fn, }; + VLIB_CLI_COMMAND (policer_del_command, static) = { .path = "policer del", .short_help = "policer del name ", .function = policer_del_command_fn, }; + VLIB_CLI_COMMAND (policer_bind_command, static) = { .path = "policer bind", .short_help = "policer bind [unbind] name ", .function = policer_bind_command_fn, }; + VLIB_CLI_COMMAND (policer_input_command, static) = { .path = "policer input", .short_help = "policer input [unapply] name ", .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 ", + .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)); diff --git a/src/vnet/policer/policer.h b/src/vnet/policer/policer.h index 2687064bf0d..f5b6c0d3b31 100644 --- a/src/vnet/policer/policer.h +++ b/src/vnet/policer/policer.h @@ -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__ */ diff --git a/src/vnet/policer/policer_api.c b/src/vnet/policer/policer_api.c index 8c958e79676..4f9baa09feb 100644 --- a/src/vnet/policer/policer_api.c +++ b/src/vnet/policer/policer_api.c @@ -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, diff --git a/test/test_ipsec_tun_if_esp.py b/test/test_ipsec_tun_if_esp.py index 8b6f619b47f..14c9b3e3f11 100644 --- a/test/test_ipsec_tun_if_esp.py +++ b/test/test_ipsec_tun_if_esp.py @@ -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 diff --git a/test/test_policer_input.py b/test/test_policer_input.py index c95f6643ff2..9a4266ceb12 100644 --- a/test/test_policer_input.py +++ b/test/test_policer_input.py @@ -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) diff --git a/test/vpp_policer.py b/test/vpp_policer.py index 2c47eed75fd..0f3b073d6e3 100644 --- a/test/vpp_policer.py +++ b/test/vpp_policer.py @@ -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( -- cgit 1.2.3-korg