From cdaf0d8c884ae0f337ef94b0ceb7449c991a3e6c Mon Sep 17 00:00:00 2001 From: Klement Sekera Date: Mon, 14 Feb 2022 20:20:22 +0000 Subject: bfd: add per session counters Add udp total session counts - as stat segment entries: /bfd/udp4/sessions /bfd/udp6/sessions and per session packet/byte counters: /bfd/rx-session-counters /bfd/rx-session-echo-counters /bfd/tx-session-counters /bfd/tx-session-echo-counters These counters are per-thread and per-session id. Adjust tests to verify proper function. Type: refactor Signed-off-by: Klement Sekera Change-Id: Ie597928022b6ac74c2220019b9e8e1714295f170 --- src/vnet/bfd/bfd_main.c | 44 +++++++++++++--- src/vnet/bfd/bfd_main.h | 12 +++-- src/vnet/bfd/bfd_udp.c | 86 ++++++++++++++++++++++++++++--- src/vnet/bfd/bfd_udp.h | 14 ++--- test/test_bfd.py | 133 ++++++++++++++++++++++++++++++++++++++++++++---- 5 files changed, 251 insertions(+), 38 deletions(-) diff --git a/src/vnet/bfd/bfd_main.c b/src/vnet/bfd/bfd_main.c index 23e3f0f02e9..a9dd60e2b20 100644 --- a/src/vnet/bfd/bfd_main.c +++ b/src/vnet/bfd/bfd_main.c @@ -30,6 +30,17 @@ #include #include +static void +bfd_validate_counters (bfd_main_t *bm) +{ + vlib_validate_combined_counter (&bm->rx_counter, pool_elts (bm->sessions)); + vlib_validate_combined_counter (&bm->rx_echo_counter, + pool_elts (bm->sessions)); + vlib_validate_combined_counter (&bm->tx_counter, pool_elts (bm->sessions)); + vlib_validate_combined_counter (&bm->tx_echo_counter, + pool_elts (bm->sessions)); +} + static u64 bfd_calc_echo_checksum (u32 discriminator, u64 expire_time, u32 secret) { @@ -727,11 +738,11 @@ bfd_transport_control_frame (vlib_main_t * vm, u32 bi, bfd_session_t * bs) { case BFD_TRANSPORT_UDP4: BFD_DBG ("Transport bfd via udp4, bs_idx=%u", bs->bs_idx); - return bfd_transport_udp4 (vm, bi, bs); + return bfd_transport_udp4 (vm, bi, bs, 0 /* is_echo */); break; case BFD_TRANSPORT_UDP6: BFD_DBG ("Transport bfd via udp6, bs_idx=%u", bs->bs_idx); - return bfd_transport_udp6 (vm, bi, bs); + return bfd_transport_udp6 (vm, bi, bs, 0 /* is_echo */); break; } return 0; @@ -761,11 +772,11 @@ bfd_transport_echo (vlib_main_t * vm, u32 bi, bfd_session_t * bs) { case BFD_TRANSPORT_UDP4: BFD_DBG ("Transport bfd echo via udp4, bs_idx=%u", bs->bs_idx); - return bfd_transport_udp4 (vm, bi, bs); + return bfd_transport_udp4 (vm, bi, bs, 1 /* is_echo */); break; case BFD_TRANSPORT_UDP6: BFD_DBG ("Transport bfd echo via udp6, bs_idx=%u", bs->bs_idx); - return bfd_transport_udp6 (vm, bi, bs); + return bfd_transport_udp6 (vm, bi, bs, 1 /* is_echo */); break; } return 0; @@ -1336,6 +1347,14 @@ bfd_main_init (vlib_main_t * vm) bm->owner_thread_index = ~0; if (n_vlib_mains > 1) clib_spinlock_init (&bm->lock); + bm->rx_counter.name = "bfd rx session counters"; + bm->rx_counter.stat_segment_name = "/bfd/rx-session-counters"; + bm->rx_echo_counter.name = "bfd rx session echo counters"; + bm->rx_echo_counter.stat_segment_name = "/bfd/rx-session-echo-counters"; + bm->tx_counter.name = "bfd tx session counters"; + bm->tx_counter.stat_segment_name = "/bfd/tx-session-counters"; + bm->tx_echo_counter.name = "bfd tx session echo counters"; + bm->tx_echo_counter.stat_segment_name = "/bfd/tx-session-echo-counters"; return 0; } @@ -1371,6 +1390,11 @@ bfd_get_session (bfd_main_t * bm, bfd_transport_e t) while (hash_get (bm->session_by_disc, result->local_discr)); bfd_set_defaults (bm, result); hash_set (bm->session_by_disc, result->local_discr, result->bs_idx); + bfd_validate_counters (bm); + vlib_zero_combined_counter (&bm->rx_counter, result->bs_idx); + vlib_zero_combined_counter (&bm->rx_echo_counter, result->bs_idx); + vlib_zero_combined_counter (&bm->tx_counter, result->bs_idx); + vlib_zero_combined_counter (&bm->tx_echo_counter, result->bs_idx); bfd_unlock (bm); return result; } @@ -1392,6 +1416,10 @@ bfd_put_session (bfd_main_t * bm, bfd_session_t * bs) --bs->auth.next_key->use_count; } hash_unset (bm->session_by_disc, bs->local_discr); + vlib_zero_combined_counter (&bm->rx_counter, bs->bs_idx); + vlib_zero_combined_counter (&bm->rx_echo_counter, bs->bs_idx); + vlib_zero_combined_counter (&bm->tx_counter, bs->bs_idx); + vlib_zero_combined_counter (&bm->tx_echo_counter, bs->bs_idx); pool_put (bm->sessions, bs); bfd_unlock (bm); } @@ -1905,8 +1933,8 @@ bfd_consume_pkt (vlib_main_t * vm, bfd_main_t * bm, const bfd_pkt_t * pkt, } } -int -bfd_consume_echo_pkt (vlib_main_t * vm, bfd_main_t * bm, vlib_buffer_t * b) +bfd_session_t * +bfd_consume_echo_pkt (vlib_main_t *vm, bfd_main_t *bm, vlib_buffer_t *b) { bfd_echo_pkt_t *pkt = NULL; if (b->current_length != sizeof (*pkt)) @@ -1926,7 +1954,7 @@ bfd_consume_echo_pkt (vlib_main_t * vm, bfd_main_t * bm, vlib_buffer_t * b) if (checksum != pkt->checksum) { BFD_DBG ("Invalid echo packet, checksum mismatch"); - return 1; + return 0; } u64 now = bfd_time_now_nsec (vm, NULL); if (pkt->expire_time_nsec < now) @@ -1938,7 +1966,7 @@ bfd_consume_echo_pkt (vlib_main_t * vm, bfd_main_t * bm, vlib_buffer_t * b) { bs->echo_last_rx_nsec = now; } - return 1; + return bs; } u8 * diff --git a/src/vnet/bfd/bfd_main.h b/src/vnet/bfd/bfd_main.h index 5e9f025c657..2d91e68c557 100644 --- a/src/vnet/bfd/bfd_main.h +++ b/src/vnet/bfd/bfd_main.h @@ -258,7 +258,7 @@ typedef enum } bfd_listen_event_e; /** - * session nitification call back function type + * session notification call back function type */ typedef void (*bfd_notify_fn_t) (bfd_listen_event_e, const bfd_session_t *); @@ -322,6 +322,11 @@ typedef struct vlib_log_class_t log_class; u16 msg_id_base; + + vlib_combined_counter_main_t rx_counter; + vlib_combined_counter_main_t rx_echo_counter; + vlib_combined_counter_main_t tx_counter; + vlib_combined_counter_main_t tx_echo_counter; } bfd_main_t; extern bfd_main_t bfd_main; @@ -412,10 +417,11 @@ void bfd_put_session (bfd_main_t * bm, bfd_session_t * bs); bfd_session_t *bfd_find_session_by_idx (bfd_main_t * bm, uword bs_idx); bfd_session_t *bfd_find_session_by_disc (bfd_main_t * bm, u32 disc); void bfd_session_start (bfd_main_t * bm, bfd_session_t * bs); +void bfd_session_stop (bfd_main_t *bm, bfd_session_t *bs); void bfd_consume_pkt (vlib_main_t * vm, bfd_main_t * bm, const bfd_pkt_t * bfd, u32 bs_idx); -int bfd_consume_echo_pkt (vlib_main_t * vm, bfd_main_t * bm, - vlib_buffer_t * b); +bfd_session_t *bfd_consume_echo_pkt (vlib_main_t *vm, bfd_main_t *bm, + vlib_buffer_t *b); int bfd_verify_pkt_common (const bfd_pkt_t * pkt); int bfd_verify_pkt_auth (vlib_main_t * vm, const bfd_pkt_t * pkt, u16 pkt_size, bfd_session_t * bs); diff --git a/src/vnet/bfd/bfd_udp.c b/src/vnet/bfd/bfd_udp.c index d8fd4a10529..97b1a737528 100644 --- a/src/vnet/bfd/bfd_udp.c +++ b/src/vnet/bfd/bfd_udp.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -68,8 +69,10 @@ typedef struct vlib_log_class_t log_class; /* number of active udp4 sessions */ u32 udp4_sessions_count; + u32 udp4_sessions_count_stat_seg_entry; /* number of active udp6 sessions */ u32 udp6_sessions_count; + u32 udp6_sessions_count_stat_seg_entry; } bfd_udp_main_t; static vlib_node_registration_t bfd_udp4_input_node; @@ -79,6 +82,14 @@ static vlib_node_registration_t bfd_udp_echo6_input_node; bfd_udp_main_t bfd_udp_main; +void +bfd_udp_update_stat_segment_entry (u32 entry, u64 value) +{ + vlib_stat_segment_lock (); + stat_segment_set_state_counter (entry, value); + vlib_stat_segment_unlock (); +} + vnet_api_error_t bfd_udp_set_echo_source (u32 sw_if_index) { @@ -94,7 +105,7 @@ bfd_udp_set_echo_source (u32 sw_if_index) } vnet_api_error_t -bfd_udp_del_echo_source (u32 sw_if_index) +bfd_udp_del_echo_source () { bfd_udp_main.echo_source_sw_if_index = ~0; bfd_udp_main.echo_source_is_set = 0; @@ -372,13 +383,18 @@ bfd_add_udp6_transport (vlib_main_t * vm, u32 bi, const bfd_session_t * bs, } static void -bfd_create_frame_to_next_node (vlib_main_t * vm, u32 bi, u32 next_node) +bfd_create_frame_to_next_node (vlib_main_t *vm, bfd_main_t *bm, + const bfd_session_t *bs, u32 bi, u32 next_node, + vlib_combined_counter_main_t *tx_counter) { vlib_frame_t *f = vlib_get_frame_to_node (vm, next_node); u32 *to_next = vlib_frame_vector_args (f); to_next[0] = bi; f->n_vectors = 1; vlib_put_frame_to_node (vm, next_node, f); + vlib_buffer_t *b = vlib_get_buffer (vm, bi); + vlib_increment_combined_counter (tx_counter, vm->thread_index, bs->bs_idx, 1, + vlib_buffer_length_in_chain (vm, b)); } int @@ -435,25 +451,33 @@ bfd_udp_calc_next_node (const struct bfd_session_s *bs, u32 * next_node) } int -bfd_transport_udp4 (vlib_main_t * vm, u32 bi, const struct bfd_session_s *bs) +bfd_transport_udp4 (vlib_main_t *vm, u32 bi, const struct bfd_session_s *bs, + int is_echo) { u32 next_node; int rv = bfd_udp_calc_next_node (bs, &next_node); + bfd_main_t *bm = bfd_udp_main.bfd_main; if (rv) { - bfd_create_frame_to_next_node (vm, bi, next_node); + bfd_create_frame_to_next_node (vm, bm, bs, bi, next_node, + is_echo ? &bm->tx_echo_counter : + &bm->tx_counter); } return rv; } int -bfd_transport_udp6 (vlib_main_t * vm, u32 bi, const struct bfd_session_s *bs) +bfd_transport_udp6 (vlib_main_t *vm, u32 bi, const struct bfd_session_s *bs, + int is_echo) { u32 next_node; int rv = bfd_udp_calc_next_node (bs, &next_node); + bfd_main_t *bm = bfd_udp_main.bfd_main; if (rv) { - bfd_create_frame_to_next_node (vm, bi, next_node); + bfd_create_frame_to_next_node ( + vm, bfd_udp_main.bfd_main, bs, bi, next_node, + is_echo ? &bm->tx_echo_counter : &bm->tx_counter); } return 1; } @@ -530,6 +554,8 @@ bfd_udp_add_session_internal (vlib_main_t * vm, bfd_udp_main_t * bum, "returns %d", format_ip46_address, &key->peer_addr, IP46_TYPE_ANY, key->sw_if_index, bus->adj_index); ++bum->udp4_sessions_count; + bfd_udp_update_stat_segment_entry ( + bum->udp4_sessions_count_stat_seg_entry, bum->udp4_sessions_count); if (1 == bum->udp4_sessions_count) { udp_register_dst_port (vm, UDP_DST_PORT_bfd4, @@ -547,6 +573,8 @@ bfd_udp_add_session_internal (vlib_main_t * vm, bfd_udp_main_t * bum, "returns %d", format_ip46_address, &key->peer_addr, IP46_TYPE_ANY, key->sw_if_index, bus->adj_index); ++bum->udp6_sessions_count; + bfd_udp_update_stat_segment_entry ( + bum->udp6_sessions_count_stat_seg_entry, bum->udp6_sessions_count); if (1 == bum->udp6_sessions_count) { udp_register_dst_port (vm, UDP_DST_PORT_bfd6, @@ -719,6 +747,8 @@ bfd_udp_del_session_internal (vlib_main_t * vm, bfd_session_t * bs) { case BFD_TRANSPORT_UDP4: --bum->udp4_sessions_count; + bfd_udp_update_stat_segment_entry ( + bum->udp4_sessions_count_stat_seg_entry, bum->udp4_sessions_count); if (!bum->udp4_sessions_count) { udp_unregister_dst_port (vm, UDP_DST_PORT_bfd4, 1); @@ -727,6 +757,8 @@ bfd_udp_del_session_internal (vlib_main_t * vm, bfd_session_t * bs) break; case BFD_TRANSPORT_UDP6: --bum->udp6_sessions_count; + bfd_udp_update_stat_segment_entry ( + bum->udp6_sessions_count_stat_seg_entry, bum->udp6_sessions_count); if (!bum->udp6_sessions_count) { udp_unregister_dst_port (vm, UDP_DST_PORT_bfd6, 0); @@ -1342,6 +1374,9 @@ bfd_udp_input (vlib_main_t * vm, vlib_node_runtime_t * rt, next0 = BFD_UDP_INPUT_NEXT_NORMAL; if (BFD_UDP_ERROR_NONE == error0) { + vlib_increment_combined_counter ( + &bm->rx_counter, vm->thread_index, bs->bs_idx, 1, + vlib_buffer_length_in_chain (vm, b0)); /* * if everything went fine, check for poll bit, if present, re-use * the buffer and based on (now updated) session parameters, send @@ -1488,8 +1523,9 @@ bfd_udp_echo_input (vlib_main_t * vm, vlib_node_runtime_t * rt, clib_memcpy_fast (t0->data, vlib_buffer_get_current (b0), len); } + bfd_session_t *bs = NULL; bfd_lock (bm); - if (bfd_consume_echo_pkt (vm, bfd_udp_main.bfd_main, b0)) + if ((bs = bfd_consume_echo_pkt (vm, bfd_udp_main.bfd_main, b0))) { b0->error = rt->errors[BFD_UDP_ERROR_NONE]; next0 = BFD_UDP_ECHO_INPUT_NEXT_NORMAL; @@ -1512,6 +1548,14 @@ bfd_udp_echo_input (vlib_main_t * vm, vlib_node_runtime_t * rt, } bfd_unlock (bm); + + if (bs) + { + vlib_increment_combined_counter ( + &bm->rx_echo_counter, vm->thread_index, bs->bs_idx, 1, + vlib_buffer_length_in_chain (vm, b0)); + } + vlib_set_next_frame_buffer (vm, rt, next0, bi0); from += 1; @@ -1640,6 +1684,32 @@ bfd_udp_sw_if_add_del (CLIB_UNUSED (vnet_main_t *vnm), u32 sw_if_index, VNET_SW_INTERFACE_ADD_DEL_FUNCTION (bfd_udp_sw_if_add_del); +clib_error_t * +bfd_udp_stats_init (bfd_udp_main_t *bum) +{ + const char *name4 = "/bfd/udp4/sessions"; + bum->udp4_sessions_count_stat_seg_entry = + stat_segment_new_entry ((u8 *) name4, STAT_DIR_TYPE_SCALAR_INDEX); + + stat_segment_set_state_counter (bum->udp4_sessions_count_stat_seg_entry, 0); + if (~0 == bum->udp4_sessions_count_stat_seg_entry) + { + return clib_error_return ( + 0, "Could not create stat segment entry for %s", name4); + } + const char *name6 = "/bfd/udp6/sessions"; + bum->udp6_sessions_count_stat_seg_entry = + stat_segment_new_entry ((u8 *) name6, STAT_DIR_TYPE_SCALAR_INDEX); + + if (~0 == bum->udp6_sessions_count_stat_seg_entry) + { + return clib_error_return ( + 0, "Could not create stat segment entry for %s", name6); + } + + return 0; +} + /* * setup function */ @@ -1671,6 +1741,8 @@ bfd_udp_init (vlib_main_t * vm) ASSERT (node); bfd_udp_main.ip6_midchain_idx = node->index; + bfd_udp_stats_init (&bfd_udp_main); + bfd_udp_main.log_class = vlib_log_register_class ("bfd", "udp"); vlib_log_debug (bfd_udp_main.log_class, "initialized"); return 0; diff --git a/src/vnet/bfd/bfd_udp.h b/src/vnet/bfd/bfd_udp.h index 87868104f98..866b5868b00 100644 --- a/src/vnet/bfd/bfd_udp.h +++ b/src/vnet/bfd/bfd_udp.h @@ -24,7 +24,6 @@ #include #include -/* *INDENT-OFF* */ /** identifier of BFD session based on UDP transport only */ typedef CLIB_PACKED (struct { union { @@ -38,7 +37,6 @@ typedef CLIB_PACKED (struct { /** peer address */ ip46_address_t peer_addr; }) bfd_udp_key_t; -/* *INDENT-ON* */ /** UDP transport specific data embedded in bfd_session's union */ typedef struct @@ -82,22 +80,18 @@ int bfd_add_udp6_transport (vlib_main_t * vm, u32 bi, /** * @brief transport packet over udpv4 * - * @param is_echo 1 if this is echo packet, 0 if control frame - * * @return 1 on success, 0 on failure */ -int bfd_transport_udp4 (vlib_main_t * vm, u32 bi, - const struct bfd_session_s *bs); +int bfd_transport_udp4 (vlib_main_t *vm, u32 bi, + const struct bfd_session_s *bs, int is_echo); /** * @brief transport packet over udpv6 * - * @param is_echo 1 if this is echo packet, 0 if control frame - * * @return 1 on success, 0 on failure */ -int bfd_transport_udp6 (vlib_main_t * vm, u32 bi, - const struct bfd_session_s *bs); +int bfd_transport_udp6 (vlib_main_t *vm, u32 bi, + const struct bfd_session_s *bs, int is_echo); /** * @brief check if the bfd udp layer is echo-capable at this time diff --git a/test/test_bfd.py b/test/test_bfd.py index 7a444cb3caf..174db3ed54a 100644 --- a/test/test_bfd.py +++ b/test/test_bfd.py @@ -4,6 +4,7 @@ from __future__ import division import binascii +from collections import namedtuple import hashlib import ipaddress import reprlib @@ -373,6 +374,10 @@ class BFDTestSession(object): self.state = BFDState.down self.auth_type = BFDAuthType.no_auth self.tunnel_header = tunnel_header + self.tx_packets = 0 + self.rx_packets = 0 + self.tx_packets_echo = 0 + self.rx_packets_echo = 0 def inc_seq_num(self): """ increment sequence number, wrapping if needed """ @@ -495,6 +500,7 @@ class BFDTestSession(object): interface = self.phy_interface self.test.logger.debug(ppp("Sending packet:", packet)) interface.add_stream(packet) + self.tx_packets += 1 self.test.pg_start() def verify_sha1_auth(self, packet): @@ -685,6 +691,7 @@ def wait_for_bfd_packet(test, timeout=1, pcap_time_min=None, is_tunnel=False): if time_left < 0: raise CaptureTimeoutError("Packet did not arrive within timeout") p = test.pg0.wait_for_packet(timeout=time_left) + test.test_session.rx_packets += 1 test.logger.debug(ppp("BFD: Got packet:", p)) if pcap_time_min is not None and p.time < pcap_time_min: test.logger.debug(ppp("BFD: ignoring packet (pcap time %s < " @@ -707,6 +714,33 @@ def wait_for_bfd_packet(test, timeout=1, pcap_time_min=None, is_tunnel=False): return p +BFDStats = namedtuple("BFDStats", "rx rx_echo tx tx_echo") + + +def bfd_grab_stats_snapshot(test, bs_idx=0, thread_index=None): + s = test.statistics + ti = thread_index + if ti is None: + rx = s['/bfd/rx-session-counters'][:, bs_idx].sum_packets() + rx_echo = s['/bfd/rx-session-echo-counters'][:, bs_idx].sum_packets() + tx = s['/bfd/tx-session-counters'][:, bs_idx].sum_packets() + tx_echo = s['/bfd/tx-session-echo-counters'][:, bs_idx].sum_packets() + else: + rx = s['/bfd/rx-session-counters'][ti, bs_idx].sum_packets() + rx_echo = s['/bfd/rx-session-echo-counters'][ti, bs_idx].sum_packets() + tx = s['/bfd/tx-session-counters'][ti, bs_idx].sum_packets() + tx_echo = s['/bfd/tx-session-echo-counters'][ti, bs_idx].sum_packets() + return BFDStats(rx, rx_echo, tx, tx_echo) + + +def bfd_stats_diff(stats_before, stats_after): + rx = stats_after.rx - stats_before.rx + rx_echo = stats_after.rx_echo - stats_before.rx_echo + tx = stats_after.tx - stats_before.tx + tx_echo = stats_after.tx_echo - stats_before.tx_echo + return BFDStats(rx, rx_echo, tx, tx_echo) + + @tag_run_solo class BFD4TestCase(VppTestCase): """Bidirectional Forwarding Detection (BFD)""" @@ -745,6 +779,8 @@ class BFD4TestCase(VppTestCase): self.vapi.want_bfd_events() self.pg0.enable_capture() try: + self.bfd_udp4_sessions = self.statistics['/bfd/udp4/sessions'] + self.bfd_udp6_sessions = self.statistics['/bfd/udp6/sessions'] self.vpp_session = VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip4) self.vpp_session.add_vpp_config() @@ -763,6 +799,10 @@ class BFD4TestCase(VppTestCase): def test_session_up(self): """ bring BFD session up """ bfd_session_up(self) + bfd_udp4_sessions = self.statistics['/bfd/udp4/sessions'] + bfd_udp6_sessions = self.statistics['/bfd/udp6/sessions'] + self.assert_equal(bfd_udp4_sessions - self.bfd_udp4_sessions, 1) + self.assert_equal(bfd_udp6_sessions, self.bfd_udp6_sessions) def test_session_up_by_ip(self): """ bring BFD session up - first frame looked up by address pair """ @@ -1121,8 +1161,8 @@ class BFD4TestCase(VppTestCase): def test_echo_looped_back(self): """ echo packets looped back """ - # don't need a session in this case.. - self.vpp_session.remove_vpp_config() + bfd_session_up(self) + stats_before = bfd_grab_stats_snapshot(self) self.pg0.enable_capture() echo_packet_count = 10 # random source port low enough to increment a few times.. @@ -1141,7 +1181,10 @@ class BFD4TestCase(VppTestCase): self.logger.debug(ppp("Sending packet:", echo_packet)) self.pg0.add_stream(echo_packet) self.pg_start() - for dummy in range(echo_packet_count): + self.logger.debug(self.vapi.ppcli("show trace")) + counter = 0 + bfd_control_packets_rx = 0 + while counter < echo_packet_count: p = self.pg0.wait_for_packet(1) self.logger.debug(ppp("Got packet:", p)) ether = p[Ether] @@ -1150,8 +1193,11 @@ class BFD4TestCase(VppTestCase): self.assert_equal(self.pg0.local_mac, ether.src, "Source MAC") ip = p[IP] self.assert_equal(self.pg0.remote_ip4, ip.dst, "Destination IP") - self.assert_equal(self.pg0.remote_ip4, ip.src, "Destination IP") udp = p[UDP] + if udp.dport == BFD.udp_dport: + bfd_control_packets_rx += 1 + continue + self.assert_equal(self.pg0.remote_ip4, ip.src, "Source IP") self.assert_equal(udp.dport, BFD.udp_dport_echo, "UDP destination port") self.assert_equal(udp.sport, udp_sport_rx, "UDP source port") @@ -1161,11 +1207,23 @@ class BFD4TestCase(VppTestCase): self.assertEqual(scapy.compat.raw(p[UDP].payload), scapy.compat.raw(echo_packet[UDP].payload), "Received packet is not the echo packet sent") + counter += 1 self.assert_equal(udp_sport_tx, udp_sport_rx, "UDP source port (== " "ECHO packet identifier for test purposes)") + stats_after = bfd_grab_stats_snapshot(self) + diff = bfd_stats_diff(stats_before, stats_after) + self.assertEqual( + 0, diff.rx, "RX counter bumped but no BFD packets sent") + self.assertEqual( + bfd_control_packets_rx, diff.tx, "TX counter incorrect") + self.assertEqual(0, diff.rx_echo, + "RX echo counter bumped but no BFD session exists") + self.assertEqual(0, diff.tx_echo, + "TX echo counter bumped but no BFD session exists") def test_echo(self): """ echo function """ + stats_before = bfd_grab_stats_snapshot(self) bfd_session_up(self) self.test_session.update(required_min_echo_rx=150000) self.test_session.send_packet() @@ -1201,9 +1259,12 @@ class BFD4TestCase(VppTestCase): "ECHO packet destination MAC address") p[Ether].dst = self.pg0.local_mac self.pg0.add_stream(p) + self.test_session.rx_packets_echo += 1 + self.test_session.tx_packets_echo += 1 self.pg_start() echo_seen = True elif p.haslayer(BFD): + self.test_session.rx_packets += 1 if echo_seen: self.assertGreaterEqual( p[BFD].required_min_rx_interval, @@ -1220,6 +1281,20 @@ class BFD4TestCase(VppTestCase): self.test_session.send_packet() self.assertTrue(echo_seen, "No echo packets received") + stats_after = bfd_grab_stats_snapshot(self) + diff = bfd_stats_diff(stats_before, stats_after) + # our rx is vpp tx and vice versa, also tolerate one packet off + self.assert_in_range(self.test_session.tx_packets, + diff.rx - 1, diff.rx + 1, "RX counter") + self.assert_in_range(self.test_session.rx_packets, + diff.tx - 1, diff.tx + 1, "TX counter") + self.assert_in_range(self.test_session.tx_packets_echo, + diff.rx_echo - 1, diff.rx_echo + 1, + "RX echo counter") + self.assert_in_range(self.test_session.rx_packets_echo, + diff.tx_echo - 1, diff.tx_echo + 1, + "TX echo counter") + def test_echo_fail(self): """ session goes down if echo function fails """ bfd_session_up(self) @@ -1555,6 +1630,8 @@ class BFD6TestCase(VppTestCase): self.vapi.want_bfd_events() self.pg0.enable_capture() try: + self.bfd_udp4_sessions = self.statistics['/bfd/udp4/sessions'] + self.bfd_udp6_sessions = self.statistics['/bfd/udp6/sessions'] self.vpp_session = VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip6, af=AF_INET6) @@ -1575,6 +1652,10 @@ class BFD6TestCase(VppTestCase): def test_session_up(self): """ bring BFD session up """ bfd_session_up(self) + bfd_udp4_sessions = self.statistics['/bfd/udp4/sessions'] + bfd_udp6_sessions = self.statistics['/bfd/udp6/sessions'] + self.assert_equal(bfd_udp4_sessions, self.bfd_udp4_sessions) + self.assert_equal(bfd_udp6_sessions - self.bfd_udp6_sessions, 1) def test_session_up_by_ip(self): """ bring BFD session up - first frame looked up by address pair """ @@ -1614,8 +1695,8 @@ class BFD6TestCase(VppTestCase): def test_echo_looped_back(self): """ echo packets looped back """ - # don't need a session in this case.. - self.vpp_session.remove_vpp_config() + bfd_session_up(self) + stats_before = bfd_grab_stats_snapshot(self) self.pg0.enable_capture() echo_packet_count = 10 # random source port low enough to increment a few times.. @@ -1634,7 +1715,9 @@ class BFD6TestCase(VppTestCase): self.logger.debug(ppp("Sending packet:", echo_packet)) self.pg0.add_stream(echo_packet) self.pg_start() - for dummy in range(echo_packet_count): + counter = 0 + bfd_control_packets_rx = 0 + while counter < echo_packet_count: p = self.pg0.wait_for_packet(1) self.logger.debug(ppp("Got packet:", p)) ether = p[Ether] @@ -1643,8 +1726,11 @@ class BFD6TestCase(VppTestCase): self.assert_equal(self.pg0.local_mac, ether.src, "Source MAC") ip = p[IPv6] self.assert_equal(self.pg0.remote_ip6, ip.dst, "Destination IP") - self.assert_equal(self.pg0.remote_ip6, ip.src, "Destination IP") udp = p[UDP] + if udp.dport == BFD.udp_dport: + bfd_control_packets_rx += 1 + continue + self.assert_equal(self.pg0.remote_ip6, ip.src, "Source IP") self.assert_equal(udp.dport, BFD.udp_dport_echo, "UDP destination port") self.assert_equal(udp.sport, udp_sport_rx, "UDP source port") @@ -1654,13 +1740,23 @@ class BFD6TestCase(VppTestCase): self.assertEqual(scapy.compat.raw(p[UDP].payload), scapy.compat.raw(echo_packet[UDP].payload), "Received packet is not the echo packet sent") + counter += 1 self.assert_equal(udp_sport_tx, udp_sport_rx, "UDP source port (== " "ECHO packet identifier for test purposes)") - self.assert_equal(udp_sport_tx, udp_sport_rx, "UDP source port (== " - "ECHO packet identifier for test purposes)") + stats_after = bfd_grab_stats_snapshot(self) + diff = bfd_stats_diff(stats_before, stats_after) + self.assertEqual( + 0, diff.rx, "RX counter bumped but no BFD packets sent") + self.assertEqual(bfd_control_packets_rx, + diff.tx, "TX counter incorrect") + self.assertEqual(0, diff.rx_echo, + "RX echo counter bumped but no BFD session exists") + self.assertEqual(0, diff.tx_echo, + "TX echo counter bumped but no BFD session exists") def test_echo(self): """ echo function """ + stats_before = bfd_grab_stats_snapshot(self) bfd_session_up(self) self.test_session.update(required_min_echo_rx=150000) self.test_session.send_packet() @@ -1694,11 +1790,14 @@ class BFD6TestCase(VppTestCase): self.logger.debug(ppp("Looping back packet:", p)) self.assert_equal(p[Ether].dst, self.pg0.remote_mac, "ECHO packet destination MAC address") + self.test_session.rx_packets_echo += 1 + self.test_session.tx_packets_echo += 1 p[Ether].dst = self.pg0.local_mac self.pg0.add_stream(p) self.pg_start() echo_seen = True elif p.haslayer(BFD): + self.test_session.rx_packets += 1 if echo_seen: self.assertGreaterEqual( p[BFD].required_min_rx_interval, @@ -1715,6 +1814,20 @@ class BFD6TestCase(VppTestCase): self.test_session.send_packet() self.assertTrue(echo_seen, "No echo packets received") + stats_after = bfd_grab_stats_snapshot(self) + diff = bfd_stats_diff(stats_before, stats_after) + # our rx is vpp tx and vice versa, also tolerate one packet off + self.assert_in_range(self.test_session.tx_packets, + diff.rx - 1, diff.rx + 1, "RX counter") + self.assert_in_range(self.test_session.rx_packets, + diff.tx - 1, diff.tx + 1, "TX counter") + self.assert_in_range(self.test_session.tx_packets_echo, + diff.rx_echo - 1, diff.rx_echo + 1, + "RX echo counter") + self.assert_in_range(self.test_session.rx_packets_echo, + diff.tx_echo - 1, diff.tx_echo + 1, + "TX echo counter") + def test_intf_deleted(self): """ interface with bfd session deleted """ intf = VppLoInterface(self) -- cgit 1.2.3-korg