aboutsummaryrefslogtreecommitdiffstats
path: root/src/vnet/bfd/bfd_udp.c
diff options
context:
space:
mode:
authorKlement Sekera <ksekera@cisco.com>2017-02-14 07:11:52 +0100
committerDamjan Marion <dmarion.lists@gmail.com>2017-02-15 12:10:23 +0000
commitaeeac3bf4429235c952ce54abad7d3729be6a2f5 (patch)
treecbdd7eb65a86687988557f87f92ecde6ed0f97b8 /src/vnet/bfd/bfd_udp.c
parent12ba252193148c06137a4f811aee71fec0801ea4 (diff)
BFD: loop back echo packets
Change-Id: I772b63ac25ebfccaff9ab9d8d0b1445e85f21df7 Signed-off-by: Klement Sekera <ksekera@cisco.com>
Diffstat (limited to 'src/vnet/bfd/bfd_udp.c')
-rw-r--r--src/vnet/bfd/bfd_udp.c229
1 files changed, 218 insertions, 11 deletions
diff --git a/src/vnet/bfd/bfd_udp.c b/src/vnet/bfd/bfd_udp.c
index 75b35974329..8519009d139 100644
--- a/src/vnet/bfd/bfd_udp.c
+++ b/src/vnet/bfd/bfd_udp.c
@@ -42,6 +42,8 @@ typedef struct
static vlib_node_registration_t bfd_udp4_input_node;
static vlib_node_registration_t bfd_udp6_input_node;
+static vlib_node_registration_t bfd_udp_echo4_input_node;
+static vlib_node_registration_t bfd_udp_echo6_input_node;
bfd_udp_main_t bfd_udp_main;
@@ -594,11 +596,10 @@ typedef enum
BFD_UDP_INPUT_N_NEXT,
} bfd_udp_input_next_t;
-/* Packet counters */
+/* Packet counters - BFD control frames */
#define foreach_bfd_udp_error(F) \
F (NONE, "good bfd packets (processed)") \
- F (BAD, "invalid bfd packets") \
- F (DISABLED, "bfd packets received on disabled interfaces")
+ F (BAD, "invalid bfd packets")
#define F(sym, string) static char BFD_UDP_ERR_##sym##_STR[] = string;
foreach_bfd_udp_error (F);
@@ -618,9 +619,32 @@ typedef enum
BFD_UDP_N_ERROR,
} bfd_udp_error_t;
+/* Packet counters - BFD ECHO packets */
+#define foreach_bfd_udp_echo_error(F) \
+ F (NONE, "good bfd echo packets (processed)") \
+ F (BAD, "invalid bfd echo packets")
+
+#define F(sym, string) static char BFD_UDP_ECHO_ERR_##sym##_STR[] = string;
+foreach_bfd_udp_echo_error (F);
+#undef F
+
+static char *bfd_udp_echo_error_strings[] = {
+#define F(sym, string) BFD_UDP_ECHO_ERR_##sym##_STR,
+ foreach_bfd_udp_echo_error (F)
+#undef F
+};
+
+typedef enum
+{
+#define F(sym, str) BFD_UDP_ECHO_ERROR_##sym,
+ foreach_bfd_udp_echo_error (F)
+#undef F
+ BFD_UDP_ECHO_N_ERROR,
+} bfd_udp_echo_error_t;
+
static void
-bfd_udp4_find_headers (vlib_buffer_t * b, const ip4_header_t ** ip4,
- const udp_header_t ** udp)
+bfd_udp4_find_headers (vlib_buffer_t * b, ip4_header_t ** ip4,
+ udp_header_t ** udp)
{
/* sanity check first */
const i32 start = vnet_buffer (b)->ip.start_of_ip_header;
@@ -714,8 +738,8 @@ bfd_udp4_scan (vlib_main_t * vm, vlib_node_runtime_t * rt,
b->current_length, sizeof (*pkt));
return BFD_UDP_ERROR_BAD;
}
- const ip4_header_t *ip4;
- const udp_header_t *udp;
+ ip4_header_t *ip4;
+ udp_header_t *udp;
bfd_udp4_find_headers (b, &ip4, &udp);
if (!ip4 || !udp)
{
@@ -776,8 +800,8 @@ bfd_udp4_scan (vlib_main_t * vm, vlib_node_runtime_t * rt,
}
static void
-bfd_udp6_find_headers (vlib_buffer_t * b, const ip6_header_t ** ip6,
- const udp_header_t ** udp)
+bfd_udp6_find_headers (vlib_buffer_t * b, ip6_header_t ** ip6,
+ udp_header_t ** udp)
{
/* sanity check first */
const i32 start = vnet_buffer (b)->ip.start_of_ip_header;
@@ -856,8 +880,8 @@ bfd_udp6_scan (vlib_main_t * vm, vlib_node_runtime_t * rt,
b->current_length, sizeof (*pkt));
return BFD_UDP_ERROR_BAD;
}
- const ip6_header_t *ip6;
- const udp_header_t *udp;
+ ip6_header_t *ip6;
+ udp_header_t *udp;
bfd_udp6_find_headers (b, &ip6, &udp);
if (!ip6 || !udp)
{
@@ -1057,6 +1081,185 @@ VLIB_REGISTER_NODE (bfd_udp6_input_node, static) = {
};
/* *INDENT-ON* */
+/**
+ * @brief swap the source and destination IP addresses in the packet
+ */
+static int
+bfd_echo_address_swap (vlib_buffer_t * b, int is_ipv6)
+{
+ udp_header_t *dummy = NULL;
+ if (is_ipv6)
+ {
+ ip6_header_t *ip6 = NULL;
+ bfd_udp6_find_headers (b, &ip6, &dummy);
+ if (!ip6)
+ {
+ return 0;
+ }
+ ip6_address_t tmp = ip6->dst_address;
+ ip6->dst_address = ip6->src_address;
+ ip6->src_address = tmp;
+ vlib_buffer_advance (b,
+ (u8 *) ip6 - (u8 *) vlib_buffer_get_current (b));
+ }
+ else
+ {
+ ip4_header_t *ip4 = NULL;
+ bfd_udp4_find_headers (b, &ip4, &dummy);
+ if (!ip4)
+ {
+ return 0;
+ }
+ ip4_address_t tmp = ip4->dst_address;
+ ip4->dst_address = ip4->src_address;
+ ip4->src_address = tmp;
+ vlib_buffer_advance (b,
+ (u8 *) ip4 - (u8 *) vlib_buffer_get_current (b));
+ }
+ return 1;
+}
+
+/*
+ * Process a frame of bfd echo packets
+ * Expect 1 packet / frame
+ */
+static uword
+bfd_udp_echo_input (vlib_main_t * vm, vlib_node_runtime_t * rt,
+ vlib_frame_t * f, int is_ipv6)
+{
+ u32 n_left_from, *from;
+ bfd_input_trace_t *t0;
+
+ from = vlib_frame_vector_args (f); /* array of buffer indices */
+ n_left_from = f->n_vectors; /* number of buffer indices */
+
+ while (n_left_from > 0)
+ {
+ u32 bi0;
+ vlib_buffer_t *b0;
+ u32 next0;
+
+ bi0 = from[0];
+ b0 = vlib_get_buffer (vm, bi0);
+
+ /* If this pkt is traced, snapshot the data */
+ if (b0->flags & VLIB_BUFFER_IS_TRACED)
+ {
+ int len;
+ t0 = vlib_add_trace (vm, rt, b0, sizeof (*t0));
+ len = (b0->current_length < sizeof (t0->data)) ? b0->current_length
+ : sizeof (t0->data);
+ t0->len = len;
+ clib_memcpy (t0->data, vlib_buffer_get_current (b0), len);
+ }
+
+ if (bfd_echo_address_swap (b0, is_ipv6))
+ {
+ /* loop back the packet */
+ b0->error = rt->errors[BFD_UDP_ERROR_NONE];
+ if (is_ipv6)
+ {
+ vlib_node_increment_counter (vm, bfd_udp_echo6_input_node.index,
+ b0->error, 1);
+ }
+ else
+ {
+ vlib_node_increment_counter (vm, bfd_udp_echo4_input_node.index,
+ b0->error, 1);
+ }
+ next0 = BFD_UDP_INPUT_NEXT_REPLY;
+ }
+ else
+ {
+ b0->error = rt->errors[BFD_UDP_ERROR_BAD];
+ next0 = BFD_UDP_INPUT_NEXT_NORMAL;
+ }
+
+ vlib_set_next_frame_buffer (vm, rt, next0, bi0);
+
+ from += 1;
+ n_left_from -= 1;
+ }
+
+ return f->n_vectors;
+}
+
+static uword
+bfd_udp_echo4_input (vlib_main_t * vm, vlib_node_runtime_t * rt,
+ vlib_frame_t * f)
+{
+ return bfd_udp_echo_input (vm, rt, f, 0);
+}
+
+u8 *
+bfd_echo_input_format_trace (u8 * s, va_list * args)
+{
+ CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
+ CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
+ const bfd_udp_echo_input_trace_t *t =
+ va_arg (*args, bfd_udp_echo_input_trace_t *);
+ if (t->len > STRUCT_SIZE_OF (bfd_pkt_t, head))
+ {
+ s = format (s, "BFD ECHO:\n");
+ s = format (s, " data: %U", format_hexdump, t->data, t->len);
+ }
+
+ return s;
+}
+
+/*
+ * bfd input graph node declaration
+ */
+/* *INDENT-OFF* */
+VLIB_REGISTER_NODE (bfd_udp_echo4_input_node, static) = {
+ .function = bfd_udp_echo4_input,
+ .name = "bfd-udp-echo4-input",
+ .vector_size = sizeof (u32),
+ .type = VLIB_NODE_TYPE_INTERNAL,
+
+ .n_errors = BFD_UDP_ECHO_N_ERROR,
+ .error_strings = bfd_udp_error_strings,
+
+ .format_trace = bfd_echo_input_format_trace,
+
+ .n_next_nodes = BFD_UDP_INPUT_N_NEXT,
+ .next_nodes =
+ {
+ [BFD_UDP_INPUT_NEXT_NORMAL] = "error-drop",
+ [BFD_UDP_INPUT_NEXT_REPLY] = "ip4-lookup",
+ },
+};
+/* *INDENT-ON* */
+
+static uword
+bfd_udp_echo6_input (vlib_main_t * vm, vlib_node_runtime_t * rt,
+ vlib_frame_t * f)
+{
+ return bfd_udp_echo_input (vm, rt, f, 1);
+}
+
+/* *INDENT-OFF* */
+VLIB_REGISTER_NODE (bfd_udp_echo6_input_node, static) = {
+ .function = bfd_udp_echo6_input,
+ .name = "bfd-udp-echo6-input",
+ .vector_size = sizeof (u32),
+ .type = VLIB_NODE_TYPE_INTERNAL,
+
+ .n_errors = BFD_UDP_ECHO_N_ERROR,
+ .error_strings = bfd_udp_echo_error_strings,
+
+ .format_trace = bfd_echo_input_format_trace,
+
+ .n_next_nodes = BFD_UDP_INPUT_N_NEXT,
+ .next_nodes =
+ {
+ [BFD_UDP_INPUT_NEXT_NORMAL] = "error-drop",
+ [BFD_UDP_INPUT_NEXT_REPLY] = "ip6-lookup",
+ },
+};
+
+/* *INDENT-ON* */
+
static clib_error_t *
bfd_sw_interface_up_down (vnet_main_t * vnm, u32 sw_if_index, u32 flags)
{
@@ -1093,6 +1296,10 @@ bfd_udp_init (vlib_main_t * vm)
bfd_udp_main.bfd_main = &bfd_main;
udp_register_dst_port (vm, UDP_DST_PORT_bfd4, bfd_udp4_input_node.index, 1);
udp_register_dst_port (vm, UDP_DST_PORT_bfd6, bfd_udp6_input_node.index, 0);
+ udp_register_dst_port (vm, UDP_DST_PORT_bfd_echo4,
+ bfd_udp_echo4_input_node.index, 1);
+ udp_register_dst_port (vm, UDP_DST_PORT_bfd_echo6,
+ bfd_udp_echo6_input_node.index, 0);
return 0;
}