#include <vlib/log.h>
#include <vnet/crypto/crypto.h>
+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)
{
{
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;
{
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;
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;
}
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;
}
--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);
}
}
}
-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))
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)
{
bs->echo_last_rx_nsec = now;
}
- return 1;
+ return bs;
}
u8 *
} 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 *);
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;
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);
#include <vnet/dpo/receive_dpo.h>
#include <vnet/fib/fib_entry.h>
#include <vnet/fib/fib_table.h>
+#include <vpp/stats/stat_segment.h>
#include <vnet/bfd/bfd_debug.h>
#include <vnet/bfd/bfd_udp.h>
#include <vnet/bfd/bfd_main.h>
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;
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)
{
}
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;
}
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
}
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;
}
"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,
"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,
{
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);
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);
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
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;
}
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;
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
*/
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;
#include <vnet/ip/ip6_packet.h>
#include <vnet/bfd/bfd_api.h>
-/* *INDENT-OFF* */
/** identifier of BFD session based on UDP transport only */
typedef CLIB_PACKED (struct {
union {
/** 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
/**
* @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
from __future__ import division
import binascii
+from collections import namedtuple
import hashlib
import ipaddress
import reprlib
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 """
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):
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 < "
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)"""
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()
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 """
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..
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]
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")
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()
"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,
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)
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)
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 """
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..
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]
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")
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()
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,
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)