From 56b8abc07fcf9b339d54d659797715df7f0328f1 Mon Sep 17 00:00:00 2001 From: Ole Troan Date: Tue, 5 Sep 2023 08:27:53 +0200 Subject: [PATCH] ip: punt add punt socket support for icmp6 Punt support for ICMP6 messages allows for an external IPv6 RA advertisement agent. Type: feature Change-Id: I0cc928b747ac1f8335ee9f7c42a3231424825dbc Signed-off-by: Ole Troan --- src/vnet/ip/punt.c | 37 +++++++++++++++++--------- src/vnet/ip/punt.h | 1 + src/vnet/ip/punt_node.c | 70 ++++++++++++++++++++++++++++++++++++------------- 3 files changed, 77 insertions(+), 31 deletions(-) diff --git a/src/vnet/ip/punt.c b/src/vnet/ip/punt.c index 10deb2e8849..aedfcad855e 100644 --- a/src/vnet/ip/punt.c +++ b/src/vnet/ip/punt.c @@ -148,14 +148,31 @@ punt_socket_register_l4 (vlib_main_t * vm, punt_main_t *pm = &punt_main; punt_client_t *c; - /* For now we only support UDP punt */ - if (protocol != IP_PROTOCOL_UDP) - return clib_error_return (0, - "only UDP protocol (%d) is supported, got %d", - IP_PROTOCOL_UDP, protocol); - if (port == (u16) ~ 0) - return clib_error_return (0, "UDP port number required"); + return clib_error_return (0, "Port number required"); + + u32 node_index; + switch (protocol) + { + case IP_PROTOCOL_UDP: + node_index = (af == AF_IP4 ? udp4_punt_socket_node.index : + udp6_punt_socket_node.index); + udp_register_dst_port (vm, port, node_index, af == AF_IP4); + break; + case IP_PROTOCOL_ICMP6: + if (af != AF_IP6) + return clib_error_return ( + 0, "only UDP or ICMP6 protocol (%d, %d) is supported, got %d", + IP_PROTOCOL_UDP, IP_PROTOCOL_ICMP6, protocol); + + node_index = icmp6_punt_socket_node.index; + icmp6_register_type (vm, port, node_index); + break; + default: + return clib_error_return ( + 0, "only UDP or ICMP6 protocol (%d) is supported, got %d", + IP_PROTOCOL_UDP, protocol); + } c = punt_client_l4_get (af, port); @@ -173,12 +190,6 @@ punt_socket_register_l4 (vlib_main_t * vm, c->reg.punt.l4.protocol = protocol; c->reg.punt.l4.af = af; - u32 node_index = (af == AF_IP4 ? - udp4_punt_socket_node.index : - udp6_punt_socket_node.index); - - udp_register_dst_port (vm, port, node_index, af == AF_IP4); - return (NULL); } diff --git a/src/vnet/ip/punt.h b/src/vnet/ip/punt.h index a2612d60f07..09e6e7393d6 100644 --- a/src/vnet/ip/punt.h +++ b/src/vnet/ip/punt.h @@ -239,6 +239,7 @@ extern vlib_node_registration_t udp4_punt_node; extern vlib_node_registration_t udp6_punt_node; extern vlib_node_registration_t udp4_punt_socket_node; extern vlib_node_registration_t udp6_punt_socket_node; +extern vlib_node_registration_t icmp6_punt_socket_node; extern vlib_node_registration_t ip4_proto_punt_socket_node; extern vlib_node_registration_t ip6_proto_punt_socket_node; extern vlib_node_registration_t punt_socket_rx_node; diff --git a/src/vnet/ip/punt_node.c b/src/vnet/ip/punt_node.c index 5d822c73759..8a2057be509 100644 --- a/src/vnet/ip/punt_node.c +++ b/src/vnet/ip/punt_node.c @@ -244,10 +244,9 @@ format_udp_punt_trace (u8 * s, va_list * args) } always_inline uword -punt_socket_inline (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * frame, - punt_type_t pt, ip_address_family_t af) +punt_socket_inline2 (vlib_main_t *vm, vlib_node_runtime_t *node, + vlib_frame_t *frame, punt_type_t pt, + ip_address_family_t af, ip_protocol_t protocol) { u32 *buffers = vlib_frame_vector_args (frame); u32 thread_index = vm->thread_index; @@ -267,33 +266,42 @@ punt_socket_inline (vlib_main_t * vm, uword l; punt_packetdesc_t packetdesc; punt_client_t *c; - + u16 port = 0; b = vlib_get_buffer (vm, buffers[i]); if (PUNT_TYPE_L4 == pt) { - /* Reverse UDP Punt advance */ - udp_header_t *udp; - if (AF_IP4 == af) + if (protocol == IP_PROTOCOL_UDP) { - vlib_buffer_advance (b, -(sizeof (ip4_header_t) + - sizeof (udp_header_t))); - ip4_header_t *ip = vlib_buffer_get_current (b); - udp = (udp_header_t *) (ip + 1); + /* Reverse UDP Punt advance */ + udp_header_t *udp; + if (AF_IP4 == af) + { + vlib_buffer_advance ( + b, -(sizeof (ip4_header_t) + sizeof (udp_header_t))); + ip4_header_t *ip = vlib_buffer_get_current (b); + udp = (udp_header_t *) (ip + 1); + } + else + { + vlib_buffer_advance ( + b, -(sizeof (ip6_header_t) + sizeof (udp_header_t))); + ip6_header_t *ip = vlib_buffer_get_current (b); + udp = (udp_header_t *) (ip + 1); + } + port = clib_net_to_host_u16 (udp->dst_port); } - else + else if (protocol == IP_PROTOCOL_ICMP6) { - vlib_buffer_advance (b, -(sizeof (ip6_header_t) + - sizeof (udp_header_t))); ip6_header_t *ip = vlib_buffer_get_current (b); - udp = (udp_header_t *) (ip + 1); + icmp46_header_t *icmp = ip6_next_header (ip); + port = icmp->type; } - /* * Find registerered client * If no registered client, drop packet and count */ - c = punt_client_l4_get (af, clib_net_to_host_u16 (udp->dst_port)); + c = punt_client_l4_get (af, port); } else if (PUNT_TYPE_IP_PROTO == pt) { @@ -397,6 +405,14 @@ error: return n_packets; } +always_inline uword +punt_socket_inline (vlib_main_t *vm, vlib_node_runtime_t *node, + vlib_frame_t *frame, punt_type_t pt, + ip_address_family_t af) +{ + return punt_socket_inline2 (vm, node, frame, pt, af, IP_PROTOCOL_UDP); +} + static uword udp4_punt_socket (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * from_frame) @@ -427,6 +443,14 @@ ip6_proto_punt_socket (vlib_main_t * vm, PUNT_TYPE_IP_PROTO, AF_IP6); } +static uword +icmp6_punt_socket (vlib_main_t *vm, vlib_node_runtime_t *node, + vlib_frame_t *from_frame) +{ + return punt_socket_inline2 (vm, node, from_frame, PUNT_TYPE_L4, AF_IP6, + IP_PROTOCOL_ICMP6); +} + static uword exception_punt_socket (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * from_frame) @@ -484,6 +508,16 @@ VLIB_REGISTER_NODE (exception_punt_socket_node) = { .n_errors = PUNT_N_ERROR, .error_strings = punt_error_strings, }; +VLIB_REGISTER_NODE (icmp6_punt_socket_node) = { + .function = icmp6_punt_socket, + .name = "ip6-icmp-punt-socket", + .format_trace = format_udp_punt_trace, + .flags = VLIB_NODE_FLAG_IS_DROP, + .vector_size = sizeof (u32), + .n_errors = PUNT_N_ERROR, + .error_strings = punt_error_strings, +}; + /* *INDENT-ON* */ typedef struct -- 2.16.6