ip: add extended shallow reassembly

This patch adds some fixes and improvements:

Fixes bug where save_rewrite_length gets overwritten on reassembly
handoff.

Fixes bug where duplicate fragments could cause a reassembly context
to be lost, because the race losing thread would remove bihash entry
created by winning thread.

Improves tracing by adding more events.

Adds extended shallow reassembly. This is a toggleable option, which if
turned on will cause reassembly to wait for both first and last
fragments to calculate total IP payload length. Furthermore it'll store
a local copy of first fragment and necessary data to retrieve it in
vnet_buffer2. This allows downstream features to access full L3/L4
headers when dealing with fragments.

Type: fix
Change-Id: I81695070533410c5815291dbc65ea71c87e3ae05
Signed-off-by: Klement Sekera <klement.sekera@gmail.com>
This commit is contained in:
Klement Sekera
2024-04-19 09:15:01 +02:00
parent db7be85352
commit 860916617d
7 changed files with 1063 additions and 587 deletions
+2 -3
View File
@@ -151,9 +151,8 @@ ip6_map_t_icmp (vlib_main_t * vm,
vnet_buffer (p0)->map_t.map_domain_index);
ctx0.d = d0;
ctx0.sender_port = 0;
if (!ip6_get_port
(vm, p0, ip60, p0->current_length, NULL, &ctx0.sender_port,
NULL, NULL, NULL, NULL))
if (!ip6_get_port (vm, p0, ip60, p0->current_length, NULL,
&ctx0.sender_port, NULL, NULL, NULL, NULL, NULL))
{
// In case of 1:1 mapping, we don't care about the port
if (!(d0->ea_bits_len == 0 && d0->rules))
+18 -2
View File
@@ -241,7 +241,8 @@ typedef struct
u8 ip_proto; /* protocol in ip header */
u8 icmp_type_or_tcp_flags;
u8 is_non_first_fragment : 1;
u8 l4_layer_truncated : 7;
u8 l4_hdr_truncated : 1;
u8 unused : 6;
u32 tcp_seq_number;
};
/* full reassembly output variables */
@@ -492,7 +493,22 @@ typedef struct
};
} nat;
u32 unused[8];
struct
{
/*
* Shallow virtual reassembly output values.
* Only populated if extended reassembly enabled via
* ipX_sv_reass_enable_disable_extended().
*/
struct
{
u32 thread_index;
u32 pool_index;
u32 id;
} reass;
} ip;
u32 unused[5];
} vnet_buffer_opaque2_t;
#define vnet_buffer2(b) ((vnet_buffer_opaque2_t *) (b)->opaque2)
+20 -4
View File
@@ -96,10 +96,10 @@ ip6_parse (vlib_main_t *vm, vlib_buffer_t *b, ip6_header_t *ip6, u32 buff_len,
* @returns 1 on success, 0 otherwise.
*/
always_inline u16
ip6_get_port (vlib_main_t * vm, vlib_buffer_t * b, ip6_header_t * ip6,
u16 buffer_len, u8 * ip_protocol, u16 * src_port,
u16 * dst_port, u8 * icmp_type_or_tcp_flags,
u32 * tcp_ack_number, u32 * tcp_seq_number)
ip6_get_port (vlib_main_t *vm, vlib_buffer_t *b, ip6_header_t *ip6,
u16 buffer_len, u8 *ip_protocol, u16 *src_port, u16 *dst_port,
u8 *icmp_type_or_tcp_flags, u32 *tcp_ack_number,
u32 *tcp_seq_number, void **l4_hdr)
{
u8 l4_protocol;
u16 l4_offset;
@@ -120,8 +120,19 @@ ip6_get_port (vlib_main_t * vm, vlib_buffer_t * b, ip6_header_t * ip6,
*ip_protocol = l4_protocol;
}
l4 = u8_ptr_add (ip6, l4_offset);
if (l4_hdr)
*l4_hdr = l4;
if (l4_protocol == IP_PROTOCOL_TCP || l4_protocol == IP_PROTOCOL_UDP)
{
if ((IP_PROTOCOL_UDP == l4_protocol &&
u8_ptr_add (l4, sizeof (udp_header_t)) >
u8_ptr_add (vlib_buffer_get_current (b), b->current_length)) ||
(IP_PROTOCOL_TCP == l4_protocol &&
u8_ptr_add (l4, sizeof (tcp_header_t)) >
u8_ptr_add (vlib_buffer_get_current (b), b->current_length)))
{
return 0;
}
if (src_port)
*src_port = ((udp_header_t *) (l4))->src_port;
if (dst_port)
@@ -135,6 +146,11 @@ ip6_get_port (vlib_main_t * vm, vlib_buffer_t * b, ip6_header_t * ip6,
}
else if (l4_protocol == IP_PROTOCOL_ICMP6)
{
if (u8_ptr_add (l4, sizeof (icmp46_header_t)) >
u8_ptr_add (vlib_buffer_get_current (b), b->current_length))
{
return 0;
}
icmp46_header_t *icmp = (icmp46_header_t *) (l4);
if (icmp_type_or_tcp_flags)
*icmp_type_or_tcp_flags = ((icmp46_header_t *) (l4))->type;
File diff suppressed because it is too large Load Diff
+28
View File
@@ -23,6 +23,7 @@
#ifndef __included_ip4_sv_reass_h__
#define __included_ip4_sv_reass_h__
#include <stdbool.h>
#include <vnet/api_errno.h>
#include <vnet/vnet.h>
@@ -48,6 +49,33 @@ int ip4_sv_reass_enable_disable_with_refcnt (u32 sw_if_index, int is_enable);
int ip4_sv_reass_output_enable_disable_with_refcnt (u32 sw_if_index,
int is_enable);
/*
* Enable or disable extended reassembly.
*
* Extended reassembly means that fragments are cached until both first and
* last fragments are seen. Furthermore, first fragment buffer will be cloned
* and stored in reassembly context for later retrieval.
*/
void ip4_sv_reass_enable_disable_extended (bool is_enable);
struct ip4_sv_lock_unlock_args
{
u32 *total_ip_payload_length;
u32 *first_fragment_buffer_index;
u32 *first_fragment_total_ip_header_length;
};
/*
* Lock thread-level lock and fetch information from reassembly context.
* Uses vnet_buffer2 data filled by extended reassembly.
*
* Returns 0 on success, -1 otherwise.
*/
int ip4_sv_reass_extended_lock (vlib_buffer_t *b,
struct ip4_sv_lock_unlock_args *a);
void ip4_sv_reass_extended_unlock (vlib_buffer_t *b);
uword ip4_sv_reass_custom_register_next_node (uword node_index);
uword ip4_sv_reass_custom_context_register_next_node (uword node_index);
File diff suppressed because it is too large Load Diff
+28
View File
@@ -23,6 +23,7 @@
#ifndef __included_ip6_sv_reass_h__
#define __included_ip6_sv_reass_h__
#include <stdbool.h>
#include <vnet/api_errno.h>
#include <vnet/vnet.h>
@@ -46,6 +47,33 @@ vnet_api_error_t
ip6_sv_reass_output_enable_disable_with_refcnt (u32 sw_if_index,
int is_enable);
/*
* Enable or disable extended reassembly.
*
* Extended reassembly means that fragments are cached until both first and
* last fragments are seen. Furthermore, first fragment buffer will be cloned
* and stored in reassembly context for later retrieval.
*/
void ip6_sv_reass_enable_disable_extended (bool is_enable);
struct ip6_sv_lock_unlock_args
{
u32 *total_ip_payload_length;
u32 *first_fragment_buffer_index;
u32 *first_fragment_total_ip_header_length;
};
/*
* Lock thread-level lock and fetch information from reassembly context.
* Uses vnet_buffer2 data filled by extended reassembly.
*
* Returns 0 on success, -1 otherwise.
*/
int ip6_sv_reass_extended_lock (vlib_buffer_t *b,
struct ip6_sv_lock_unlock_args *a);
void ip6_sv_reass_extended_unlock (vlib_buffer_t *b);
int ip6_sv_reass_enable_disable_with_refcnt (u32 sw_if_index, int is_enable);
uword ip6_sv_reass_custom_context_register_next_node (uword node_index);