From fab5e7f3999cf35f787e08e5a0161e5f6b932b0f Mon Sep 17 00:00:00 2001 From: Filip Tehlar Date: Thu, 14 Jan 2021 13:32:01 +0000 Subject: [PATCH] ikev2: use new counters data model & add more counters Type: feature Ticket: VPP-1916 Change-Id: Ibe612d21f748a532d88b73b286dc4a1dd15d7420 Signed-off-by: Filip Tehlar --- src/plugins/ikev2/ikev2.api | 86 +++++++++++++++++++++++++++++ src/plugins/ikev2/ikev2.c | 103 ++++++++++++++++++++--------------- src/plugins/ikev2/test/test_ikev2.py | 30 ++++++++-- 3 files changed, 169 insertions(+), 50 deletions(-) diff --git a/src/plugins/ikev2/ikev2.api b/src/plugins/ikev2/ikev2.api index 9f44cba1661..f936e525e4b 100644 --- a/src/plugins/ikev2/ikev2.api +++ b/src/plugins/ikev2/ikev2.api @@ -496,6 +496,92 @@ autoreply define ikev2_profile_set_liveness option status="in_progress"; }; +counters ikev2 { + processed { + severity info; + type counter64; + units "packets"; + description "packets processed"; + }; + ike_sa_init_retransmit { + severity info; + type counter64; + units "packets"; + description "IKE SA INIT retransmit"; + }; + ike_sa_init_ignore { + severity error; + type counter64; + units "packets"; + description "IKE_SA_INIT ignore (IKE SA already auth)"; + }; + ike_req_retransmit { + severity error; + type counter64; + units "packets"; + description "IKE request retransmit"; + }; + ike_req_ignore { + severity error; + type counter64; + units "packets"; + description "IKE request ignore (old msgid)"; + }; + not_ikev2 { + severity error; + type counter64; + units "packets"; + description "Non IKEv2 packets received"; + }; + bad_length { + severity error; + type counter64; + units "packets"; + description "Bad packet length"; + }; + malformed_packet { + severity error; + type counter64; + units "packets"; + description "Malformed packet"; + }; + no_buff_space { + severity error; + type counter64; + units "packets"; + description "No buffer space"; + }; + keepalive { + severity info; + type counter64; + units "packets"; + description "IKE keepalive messages received"; + }; + rekey_req { + severity info; + type counter64; + units "packets"; + description "IKE rekey requests received"; + }; + exchange_sa_req { + severity info; + type counter64; + units "packets"; + description "IKE EXCHANGE SA requests received"; + }; + ike_auth_req { + severity info; + type counter64; + units "packets"; + description "IKE AUTH SA requests received"; + }; +}; +paths { + "/err/ikev2-ip4" "ike"; + "/err/ikev2-ip6" "ike"; + "/err/ikev2-ip4-natt" "ike"; +}; + /* * Local Variables: * eval: (c-set-style "gnu") diff --git a/src/plugins/ikev2/ikev2.c b/src/plugins/ikev2/ikev2.c index cfc3d9f9940..c9a86475ac6 100644 --- a/src/plugins/ikev2/ikev2.c +++ b/src/plugins/ikev2/ikev2.c @@ -28,6 +28,7 @@ #include #include #include +#include #define IKEV2_LIVENESS_RETRIES 3 #define IKEV2_LIVENESS_PERIOD_CHECK 30 @@ -49,6 +50,14 @@ typedef struct u32 sw_if_index; } ikev2_trace_t; +typedef struct +{ + u16 n_keepalives; + u16 n_rekey_req; + u16 n_exchange_sa_req; + u16 n_ike_auth_req; +} ikev2_stats_t; + static u8 * format_ikev2_trace (u8 * s, va_list * args) { @@ -92,31 +101,6 @@ format_ikev2_gen_sa_error (u8 * s, va_list * args) return s; } -#define foreach_ikev2_error \ -_(PROCESSED, "IKEv2 packets processed") \ -_(IKE_SA_INIT_RETRANSMIT, "IKE_SA_INIT retransmit ") \ -_(IKE_SA_INIT_IGNORE, "IKE_SA_INIT ignore (IKE SA already auth)") \ -_(IKE_REQ_RETRANSMIT, "IKE request retransmit") \ -_(IKE_REQ_IGNORE, "IKE request ignore (old msgid)") \ -_(NOT_IKEV2, "Non IKEv2 packets received") \ -_(BAD_LENGTH, "Bad packet length") \ -_(MALFORMED_PACKET, "Malformed packet") \ -_(NO_BUFF_SPACE, "No buffer space") - -typedef enum -{ -#define _(sym,str) IKEV2_ERROR_##sym, - foreach_ikev2_error -#undef _ - IKEV2_N_ERROR, -} ikev2_error_t; - -static char *ikev2_error_strings[] = { -#define _(sym,string) string, - foreach_ikev2_error -#undef _ -}; - typedef enum { IKEV2_NEXT_IP4_LOOKUP, @@ -2264,8 +2248,8 @@ ikev2_delete_tunnel_interface (vnet_main_t * vnm, ikev2_sa_t * sa, } static u32 -ikev2_generate_message (vlib_buffer_t * b, ikev2_sa_t * sa, - ike_header_t * ike, void *user, udp_header_t * udp) +ikev2_generate_message (vlib_buffer_t *b, ikev2_sa_t *sa, ike_header_t *ike, + void *user, udp_header_t *udp, ikev2_stats_t *stats) { ikev2_main_t *km = &ikev2_main; u16 buffer_data_size = vlib_buffer_get_default_data_size (km->vlib_main); @@ -2448,7 +2432,15 @@ ikev2_generate_message (vlib_buffer_t * b, ikev2_sa_t * sa, vec_free (data); sa->unsupported_cp = 0; } - /* else send empty response */ + else + /* else send empty response */ + { + if (ike_hdr_is_response (ike)) + { + ASSERT (stats != 0); + stats->n_keepalives++; + } + } } else if (ike->exchange == IKEV2_EXCHANGE_CREATE_CHILD_SA) { @@ -2833,6 +2825,19 @@ ikev2_generate_sa_init_data_and_log (ikev2_sa_t * sa) ikev2_elog_error (IKEV2_GENERATE_SA_INIT_OK_ERR_UNSUPP_STR); } +static void +ikev2_update_stats (vlib_main_t *vm, u32 node_index, ikev2_stats_t *s) +{ + vlib_node_increment_counter (vm, node_index, IKEV2_ERROR_KEEPALIVE, + s->n_keepalives); + vlib_node_increment_counter (vm, node_index, IKEV2_ERROR_REKEY_REQ, + s->n_rekey_req); + vlib_node_increment_counter (vm, node_index, IKEV2_ERROR_EXCHANGE_SA_REQ, + s->n_exchange_sa_req); + vlib_node_increment_counter (vm, node_index, IKEV2_ERROR_IKE_AUTH_REQ, + s->n_ike_auth_req); +} + static_always_inline uword ikev2_node_internal (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame, u8 is_ip4, u8 natt) @@ -2842,8 +2847,10 @@ ikev2_node_internal (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b; u16 nexts[VLIB_FRAME_SIZE], *next = nexts; ikev2_main_per_thread_data_t *ptd = ikev2_get_per_thread_data (); + ikev2_stats_t _stats, *stats = &_stats; int res; + clib_memset_u16 (stats, 0, sizeof (stats[0]) / sizeof (u16)); from = vlib_frame_vector_args (frame); vlib_get_buffers (vm, from, bufs, n_left); b = bufs; @@ -2925,6 +2932,7 @@ ikev2_node_internal (vlib_main_t *vm, vlib_node_runtime_t *node, if (ike_hdr_is_initiator (ike0)) { + stats->n_exchange_sa_req++; if (ike0->rspi == 0) { if (is_ip4) @@ -2972,7 +2980,8 @@ ikev2_node_internal (vlib_main_t *vm, vlib_node_runtime_t *node, || sa0->state == IKEV2_STATE_NOTIFY_AND_DELETE) { ike0->flags = IKEV2_HDR_FLAG_RESPONSE; - slen = ikev2_generate_message (b0, sa0, ike0, 0, udp0); + slen = + ikev2_generate_message (b0, sa0, ike0, 0, udp0, stats); if (~0 == slen) vlib_node_increment_counter (vm, node->node_index, IKEV2_ERROR_NO_BUFF_SPACE, @@ -3023,8 +3032,8 @@ ikev2_node_internal (vlib_main_t *vm, vlib_node_runtime_t *node, ike0->msgid = clib_net_to_host_u32 (sai->last_init_msg_id); sa0->last_init_msg_id = sai->last_init_msg_id + 1; - slen = - ikev2_generate_message (b0, sa0, ike0, 0, udp0); + slen = ikev2_generate_message (b0, sa0, ike0, 0, + udp0, stats); if (~0 == slen) vlib_node_increment_counter (vm, node->node_index, @@ -3095,8 +3104,10 @@ ikev2_node_internal (vlib_main_t *vm, vlib_node_runtime_t *node, } else { + stats->n_ike_auth_req++; ike0->flags = IKEV2_HDR_FLAG_RESPONSE; - slen = ikev2_generate_message (b0, sa0, ike0, 0, udp0); + slen = + ikev2_generate_message (b0, sa0, ike0, 0, udp0, stats); if (~0 == slen) vlib_node_increment_counter (vm, node->node_index, IKEV2_ERROR_NO_BUFF_SPACE, @@ -3168,7 +3179,8 @@ ikev2_node_internal (vlib_main_t *vm, vlib_node_runtime_t *node, if (ike_hdr_is_request (ike0)) { ike0->flags = IKEV2_HDR_FLAG_RESPONSE; - slen = ikev2_generate_message (b0, sa0, ike0, 0, udp0); + slen = + ikev2_generate_message (b0, sa0, ike0, 0, udp0, stats); if (~0 == slen) vlib_node_increment_counter (vm, node->node_index, IKEV2_ERROR_NO_BUFF_SPACE, @@ -3228,8 +3240,10 @@ ikev2_node_internal (vlib_main_t *vm, vlib_node_runtime_t *node, } else { + stats->n_rekey_req++; ike0->flags = IKEV2_HDR_FLAG_RESPONSE; - slen = ikev2_generate_message (b0, sa0, ike0, 0, udp0); + slen = + ikev2_generate_message (b0, sa0, ike0, 0, udp0, stats); if (~0 == slen) vlib_node_increment_counter (vm, node->node_index, IKEV2_ERROR_NO_BUFF_SPACE, @@ -3318,6 +3332,7 @@ ikev2_node_internal (vlib_main_t *vm, vlib_node_runtime_t *node, b += 1; } + ikev2_update_stats (vm, node->node_index, stats); vlib_node_increment_counter (vm, node->node_index, IKEV2_ERROR_PROCESSED, frame->n_vectors); vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors); @@ -3351,8 +3366,8 @@ VLIB_REGISTER_NODE (ikev2_node_ip4,static) = { .format_trace = format_ikev2_trace, .type = VLIB_NODE_TYPE_INTERNAL, - .n_errors = ARRAY_LEN(ikev2_error_strings), - .error_strings = ikev2_error_strings, + .n_errors = IKEV2_N_ERROR, + .error_counters = ikev2_error_counters, .n_next_nodes = IKEV2_IP4_N_NEXT, .next_nodes = { @@ -3368,8 +3383,8 @@ VLIB_REGISTER_NODE (ikev2_node_ip4_natt,static) = { .format_trace = format_ikev2_trace, .type = VLIB_NODE_TYPE_INTERNAL, - .n_errors = ARRAY_LEN(ikev2_error_strings), - .error_strings = ikev2_error_strings, + .n_errors = IKEV2_N_ERROR, + .error_counters = ikev2_error_counters, .n_next_nodes = IKEV2_IP4_N_NEXT, .next_nodes = { @@ -3385,8 +3400,8 @@ VLIB_REGISTER_NODE (ikev2_node_ip6,static) = { .format_trace = format_ikev2_trace, .type = VLIB_NODE_TYPE_INTERNAL, - .n_errors = ARRAY_LEN(ikev2_error_strings), - .error_strings = ikev2_error_strings, + .n_errors = IKEV2_N_ERROR, + .error_counters = ikev2_error_counters, .n_next_nodes = IKEV2_IP6_N_NEXT, .next_nodes = { @@ -3722,7 +3737,7 @@ ikev2_initiate_delete_ike_sa_internal (vlib_main_t * vm, ike0->flags = 0; ike0->msgid = clib_host_to_net_u32 (sa->last_init_msg_id); sa->last_init_msg_id += 1; - len = ikev2_generate_message (b0, sa, ike0, 0, 0); + len = ikev2_generate_message (b0, sa, ike0, 0, 0, 0); if (~0 == len) return; @@ -4392,7 +4407,7 @@ ikev2_delete_child_sa_internal (vlib_main_t * vm, ikev2_sa_t * sa, sa->del->spi = csa->i_proposals->spi; ike0->msgid = clib_host_to_net_u32 (sa->last_init_msg_id); sa->last_init_msg_id += 1; - len = ikev2_generate_message (b0, sa, ike0, 0, 0); + len = ikev2_generate_message (b0, sa, ike0, 0, 0, 0); if (~0 == len) return; @@ -4518,7 +4533,7 @@ ikev2_rekey_child_sa_internal (vlib_main_t * vm, ikev2_sa_t * sa, RAND_bytes ((u8 *) & proposals[0].spi, sizeof (proposals[0].spi)); rekey->spi = proposals[0].spi; rekey->ispi = csa->i_proposals->spi; - len = ikev2_generate_message (b0, sa, ike0, proposals, 0); + len = ikev2_generate_message (b0, sa, ike0, proposals, 0, 0); if (~0 == len) return; @@ -4972,7 +4987,7 @@ ikev2_send_informational_request (ikev2_sa_t * sa) ike0->msgid = clib_host_to_net_u32 (sa->last_init_msg_id); ike0->flags = 0; sa->last_init_msg_id += 1; - len = ikev2_generate_message (b0, sa, ike0, 0, 0); + len = ikev2_generate_message (b0, sa, ike0, 0, 0, 0); if (~0 == len) return; diff --git a/src/plugins/ikev2/test/test_ikev2.py b/src/plugins/ikev2/test/test_ikev2.py index 3db3a05a1c3..e6ccef7786a 100644 --- a/src/plugins/ikev2/test/test_ikev2.py +++ b/src/plugins/ikev2/test/test_ikev2.py @@ -592,6 +592,10 @@ class IkePeer(VppTestCase): self.vapi.cli('ikev2 set logging level 4') self.vapi.cli('event-lo clear') + def assert_counter(self, count, name, version='ip4'): + node_name = '/err/ikev2-%s/' % version + name + self.assertEqual(count, self.statistics.get_err_counter(node_name)) + def create_rekey_request(self): sa, first_payload = self.generate_auth_payload(is_rekey=True) header = ikev2.IKEv2( @@ -1317,11 +1321,19 @@ class TemplateResponder(IkePeer): self.sa.child_sas[0].rspi = prop.SPI self.sa.calc_child_keys() + IKE_NODE_SUFFIX = 'ip4' + + def verify_counters(self): + self.assert_counter(2, 'processed', self.IKE_NODE_SUFFIX) + self.assert_counter(1, 'exchange_sa_req', self.IKE_NODE_SUFFIX) + self.assert_counter(1, 'ike_auth_req', self.IKE_NODE_SUFFIX) + def test_responder(self): self.send_sa_init_req() self.send_sa_auth() self.verify_ipsec_sas() self.verify_ike_sas() + self.verify_counters() class Ikev2Params(object): @@ -1624,6 +1636,8 @@ class TestApi(VppTestCase): class TestResponderBehindNAT(TemplateResponder, Ikev2Params): """ test responder - responder behind NAT """ + IKE_NODE_SUFFIX = 'ip4-natt' + def config_tc(self): self.config_params({'r_natt': True}) @@ -1782,6 +1796,9 @@ class TestInitiatorDelSAFromResponder(TemplateInitiator, Ikev2Params): class TestResponderInitBehindNATT(TemplateResponder, Ikev2Params): """ test ikev2 responder - initiator behind NAT """ + + IKE_NODE_SUFFIX = 'ip4-natt' + def config_tc(self): self.config_params( {'i_natt': True}) @@ -1875,6 +1892,7 @@ class Test_IKE_AES_CBC_128_SHA256_128_MODP2048_ESP_AES_CBC_192_SHA_384_192\ class TestAES_CBC_128_SHA256_128_MODP3072_ESP_AES_GCM_16\ (TemplateResponder, Ikev2Params): + """ IKE:AES_CBC_128_SHA256_128,DH=modp3072 ESP:AES_GCM_16 """ @@ -1891,6 +1909,9 @@ class Test_IKE_AES_GCM_16_256(TemplateResponder, Ikev2Params): """ IKE:AES_GCM_16_256 """ + + IKE_NODE_SUFFIX = 'ip6' + def config_tc(self): self.config_params({ 'del_sa_from_responder': True, @@ -1920,6 +1941,7 @@ class TestInitiatorKeepaliveMsg(TestInitiatorPsk): self.assertEqual(ih.id, self.sa.msg_id) plain = self.sa.hmac_and_decrypt(ih) self.assertEqual(plain, b'') + self.assert_counter(1, 'keepalive', 'ip4') def test_initiator(self): super(TestInitiatorKeepaliveMsg, self).test_initiator() @@ -1935,10 +1957,6 @@ class TestMalformedMessages(TemplateResponder, Ikev2Params): def config_tc(self): self.config_params() - def assert_counter(self, count, name, version='ip4'): - node_name = '/err/ikev2-%s/' % version + name - self.assertEqual(count, self.statistics.get_err_counter(node_name)) - def create_ike_init_msg(self, length=None, payload=None): msg = ikev2.IKEv2(length=length, init_SPI='\x11' * 8, flags='Initiator', exch_type='IKE_SA_INIT') @@ -1950,13 +1968,13 @@ class TestMalformedMessages(TemplateResponder, Ikev2Params): def verify_bad_packet_length(self): ike_msg = self.create_ike_init_msg(length=0xdead) self.send_and_assert_no_replies(self.pg0, ike_msg * self.pkt_count) - self.assert_counter(self.pkt_count, 'Bad packet length') + self.assert_counter(self.pkt_count, 'bad_length') def verify_bad_sa_payload_length(self): p = ikev2.IKEv2_payload_SA(length=0xdead) ike_msg = self.create_ike_init_msg(payload=p) self.send_and_assert_no_replies(self.pg0, ike_msg * self.pkt_count) - self.assert_counter(self.pkt_count, 'Malformed packet') + self.assert_counter(self.pkt_count, 'malformed_packet') def test_responder(self): self.pkt_count = 254 -- 2.16.6