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:
@@ -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
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
+591
-342
File diff suppressed because it is too large
Load Diff
@@ -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);
|
||||
|
||||
|
||||
+376
-236
File diff suppressed because it is too large
Load Diff
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user