aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKlement Sekera <klement.sekera@gmail.com>2024-04-13 11:04:23 +0200
committerOle Tr�an <otroan@employees.org>2024-10-07 12:29:02 +0000
commit6f3d9e2cb859375cdc1df1a5f8a4d78a1db74cfb (patch)
tree49f862d65b395ad70b52429ad69409b02183fd2e
parent22c7420dfbc0528a8b06138beb8f3b760f316d6e (diff)
ip: add ip6 shallow reassembly output feature
Type: improvement Change-Id: I0cb4014f03abdd0e55d4bb7ff40ae293a6ed3562 Signed-off-by: Klement Sekera <klement.sekera@gmail.com>
-rw-r--r--src/vnet/ip/reass/ip6_sv_reass.c211
-rw-r--r--src/vnet/ip/reass/ip6_sv_reass.h3
2 files changed, 172 insertions, 42 deletions
diff --git a/src/vnet/ip/reass/ip6_sv_reass.c b/src/vnet/ip/reass/ip6_sv_reass.c
index fe2ed05555c..aa5af1c568c 100644
--- a/src/vnet/ip/reass/ip6_sv_reass.c
+++ b/src/vnet/ip/reass/ip6_sv_reass.c
@@ -150,10 +150,13 @@ typedef struct
/** Worker handoff */
u32 fq_index;
u32 fq_feature_index;
+ u32 fq_output_feature_index;
u32 fq_custom_context_index;
// reference count for enabling/disabling feature - per interface
u32 *feature_use_refcount_per_intf;
+ // reference count for enabling/disabling output feature - per interface
+ u32 *output_feature_use_refcount_per_intf;
} ip6_sv_reass_main_t;
extern ip6_sv_reass_main_t ip6_sv_reass_main;
@@ -513,17 +516,24 @@ ip6_sv_reass_verify_packet_size_lt_64k (vlib_main_t * vm,
return true;
}
+struct ip6_sv_reass_args
+{
+ bool is_feature;
+ bool is_output_feature;
+ bool custom_next;
+ bool custom_context;
+};
+
always_inline uword
ip6_sv_reassembly_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
- vlib_frame_t *frame, bool is_feature,
- bool custom_next, bool custom_context)
+ vlib_frame_t *frame, struct ip6_sv_reass_args a)
{
u32 *from = vlib_frame_vector_args (frame);
u32 n_left_from, n_left_to_next, *to_next, *to_next_aux, next_index;
ip6_sv_reass_main_t *rm = &ip6_sv_reass_main;
ip6_sv_reass_per_thread_t *rt = &rm->per_thread_data[vm->thread_index];
u32 *context;
- if (custom_context)
+ if (a.custom_context)
context = vlib_frame_aux_args (frame);
clib_spinlock_lock (&rt->lock);
@@ -533,7 +543,7 @@ ip6_sv_reassembly_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
while (n_left_from > 0)
{
- if (custom_context)
+ if (a.custom_context)
vlib_get_next_frame_with_aux_safe (vm, node, next_index, to_next,
to_next_aux, n_left_to_next);
else
@@ -549,7 +559,11 @@ ip6_sv_reassembly_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
bi0 = from[0];
b0 = vlib_get_buffer (vm, bi0);
- ip6_header_t *ip0 = vlib_buffer_get_current (b0);
+ ip6_header_t *ip0 = (ip6_header_t *) u8_ptr_add (
+ vlib_buffer_get_current (b0),
+ (ptrdiff_t) (a.is_output_feature ? 1 : 0) *
+ vnet_buffer (b0)->ip.save_rewrite_length);
+
ip6_frag_hdr_t *frag_hdr;
ip6_ext_hdr_chain_t hdr_chain;
bool is_atomic_fragment = false;
@@ -585,8 +599,8 @@ ip6_sv_reassembly_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
goto packet_enqueue;
}
vnet_buffer (b0)->ip.reass.is_non_first_fragment = 0;
- next0 = custom_next ? vnet_buffer (b0)->ip.reass.next_index :
- IP6_SV_REASSEMBLY_NEXT_INPUT;
+ next0 = a.custom_next ? vnet_buffer (b0)->ip.reass.next_index :
+ IP6_SV_REASSEMBLY_NEXT_INPUT;
if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
{
ip6_sv_reass_add_trace (
@@ -625,7 +639,7 @@ ip6_sv_reassembly_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
kv.k.as_u64[1] = ip0->src_address.as_u64[1];
kv.k.as_u64[2] = ip0->dst_address.as_u64[0];
kv.k.as_u64[3] = ip0->dst_address.as_u64[1];
- if (custom_context)
+ if (a.custom_context)
kv.k.as_u64[4] =
(u64) *context << 32 | (u64) frag_hdr->identification;
else
@@ -644,7 +658,7 @@ ip6_sv_reassembly_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
next0 = IP6_SV_REASSEMBLY_NEXT_HANDOFF;
vnet_buffer (b0)->ip.reass.owner_thread_index =
kv.v.thread_index;
- if (custom_context)
+ if (a.custom_context)
forward_context = 1;
goto packet_enqueue;
}
@@ -670,8 +684,8 @@ ip6_sv_reassembly_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
reass->tcp_seq_number;
vnet_buffer (b0)->ip.reass.l4_src_port = reass->l4_src_port;
vnet_buffer (b0)->ip.reass.l4_dst_port = reass->l4_dst_port;
- next0 = custom_next ? vnet_buffer (b0)->ip.reass.next_index :
- IP6_SV_REASSEMBLY_NEXT_INPUT;
+ next0 = a.custom_next ? vnet_buffer (b0)->ip.reass.next_index :
+ IP6_SV_REASSEMBLY_NEXT_INPUT;
if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
{
ip6_sv_reass_add_trace (
@@ -724,7 +738,7 @@ ip6_sv_reassembly_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
to_next += 1;
n_left_to_next -= 1;
b0 = vlib_get_buffer (vm, bi0);
- if (is_feature)
+ if (a.is_feature || a.is_output_feature)
{
vnet_feature_next (&next0, b0);
}
@@ -761,12 +775,13 @@ ip6_sv_reassembly_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
to_next[0] = bi0;
to_next += 1;
n_left_to_next -= 1;
- if (is_feature && IP6_ERROR_NONE == error0)
+ if ((a.is_feature || a.is_output_feature) &&
+ IP6_ERROR_NONE == error0)
{
b0 = vlib_get_buffer (vm, bi0);
vnet_feature_next (&next0, b0);
}
- if (custom_context && forward_context)
+ if (a.custom_context && forward_context)
{
if (to_next_aux)
{
@@ -783,7 +798,7 @@ ip6_sv_reassembly_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
next_packet:
from += 1;
- if (custom_context)
+ if (a.custom_context)
context += 1;
n_left_from -= 1;
}
@@ -795,13 +810,16 @@ ip6_sv_reassembly_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
return frame->n_vectors;
}
-VLIB_NODE_FN (ip6_sv_reass_node) (vlib_main_t * vm,
- vlib_node_runtime_t * node,
- vlib_frame_t * frame)
+VLIB_NODE_FN (ip6_sv_reass_node)
+(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
{
- return ip6_sv_reassembly_inline (vm, node, frame, false /* is_feature */,
- false /* custom next */,
- false /* custom context */);
+ return ip6_sv_reassembly_inline (vm, node, frame,
+ (struct ip6_sv_reass_args){
+ .is_feature = false,
+ .is_output_feature = false,
+ .custom_context = false,
+ .custom_next = false,
+ });
}
VLIB_REGISTER_NODE (ip6_sv_reass_node) = {
@@ -824,9 +842,13 @@ VLIB_NODE_FN (ip6_sv_reass_node_feature) (vlib_main_t * vm,
vlib_node_runtime_t * node,
vlib_frame_t * frame)
{
- return ip6_sv_reassembly_inline (vm, node, frame, true /* is_feature */,
- false /* custom next */,
- false /* custom context */);
+ return ip6_sv_reassembly_inline (vm, node, frame,
+ (struct ip6_sv_reass_args){
+ .is_feature = true,
+ .is_output_feature = false,
+ .custom_context = false,
+ .custom_next = false,
+ });
}
VLIB_REGISTER_NODE (ip6_sv_reass_node_feature) = {
@@ -852,12 +874,50 @@ VNET_FEATURE_INIT (ip6_sv_reassembly_feature) = {
.runs_after = 0,
};
+VLIB_NODE_FN (ip6_sv_reass_node_output_feature)
+(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
+{
+ return ip6_sv_reassembly_inline (vm, node, frame,
+ (struct ip6_sv_reass_args){
+ .is_feature = false,
+ .is_output_feature = true,
+ .custom_context = false,
+ .custom_next = false,
+ });
+}
+
+VLIB_REGISTER_NODE (ip6_sv_reass_node_output_feature) = {
+ .name = "ip6-sv-reassembly-output-feature",
+ .vector_size = sizeof (u32),
+ .format_trace = format_ip6_sv_reass_trace,
+ .n_errors = IP6_N_ERROR,
+ .error_counters = ip6_error_counters,
+ .n_next_nodes = IP6_SV_REASSEMBLY_N_NEXT,
+ .next_nodes =
+ {
+ [IP6_SV_REASSEMBLY_NEXT_INPUT] = "ip6-input",
+ [IP6_SV_REASSEMBLY_NEXT_DROP] = "ip6-drop",
+ [IP6_SV_REASSEMBLY_NEXT_ICMP_ERROR] = "ip6-icmp-error",
+ [IP6_SV_REASSEMBLY_NEXT_HANDOFF] = "ip6-sv-reass-output-feature-hoff",
+ },
+};
+
+VNET_FEATURE_INIT (ip6_sv_reassembly_output_feature) = {
+ .arc_name = "ip6-output",
+ .node_name = "ip6-sv-reassembly-output-feature",
+ .runs_after = 0,
+};
+
VLIB_NODE_FN (ip6_sv_reass_custom_context_node)
(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
{
- return ip6_sv_reassembly_inline (vm, node, frame, false /* is_feature */,
- true /* custom next */,
- true /* custom context */);
+ return ip6_sv_reassembly_inline (vm, node, frame,
+ (struct ip6_sv_reass_args){
+ .is_feature = false,
+ .is_output_feature = false,
+ .custom_context = true,
+ .custom_next = true,
+ });
}
VLIB_REGISTER_NODE (ip6_sv_reass_custom_context_node) = {
@@ -950,7 +1010,7 @@ ip6_sv_reass_set (u32 timeout_ms, u32 max_reassemblies,
ctx.failure = 0;
ctx.new_hash = &new_hash;
clib_bihash_init_48_8 (&new_hash, "ip6-sv-reass", new_nbuckets,
- new_nbuckets * 1024);
+ (uword) new_nbuckets * 1024);
clib_bihash_foreach_key_value_pair_48_8 (&ip6_sv_reass_main.hash,
ip6_rehash_cb, &ctx);
if (ctx.failure)
@@ -1011,7 +1071,7 @@ ip6_sv_reass_init_function (vlib_main_t * vm)
nbuckets = ip6_sv_reass_get_nbuckets ();
clib_bihash_init_48_8 (&rm->hash, "ip6-sv-reass", nbuckets,
- nbuckets * 1024);
+ (uword) nbuckets * 1024);
node = vlib_get_node_by_name (vm, (u8 *) "ip6-drop");
ASSERT (node);
@@ -1026,6 +1086,8 @@ ip6_sv_reass_init_function (vlib_main_t * vm)
rm->fq_index = vlib_frame_queue_main_init (ip6_sv_reass_node.index, 0);
rm->fq_feature_index =
vlib_frame_queue_main_init (ip6_sv_reass_node_feature.index, 0);
+ rm->fq_output_feature_index =
+ vlib_frame_queue_main_init (ip6_sv_reass_node_output_feature.index, 0);
rm->fq_custom_context_index =
vlib_frame_queue_main_init (ip6_sv_reass_custom_context_node.index, 0);
@@ -1260,20 +1322,26 @@ format_ip6_sv_reassembly_handoff_trace (u8 * s, va_list * args)
return s;
}
+struct ip6_sv_reass_hoff_args
+{
+ bool is_feature;
+ bool is_output_feature;
+ bool custom_context;
+};
+
always_inline uword
ip6_sv_reassembly_handoff_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
- vlib_frame_t *frame, bool is_feature,
- bool custom_context)
+ vlib_frame_t *frame,
+ struct ip6_sv_reass_hoff_args a)
{
ip6_sv_reass_main_t *rm = &ip6_sv_reass_main;
vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
u32 n_enq, n_left_from, *from, *context;
u16 thread_indices[VLIB_FRAME_SIZE], *ti;
- u32 fq_index;
from = vlib_frame_vector_args (frame);
- if (custom_context)
+ if (a.custom_context)
context = vlib_frame_aux_args (frame);
n_left_from = frame->n_vectors;
vlib_get_buffers (vm, from, bufs, n_left_from);
@@ -1281,9 +1349,10 @@ ip6_sv_reassembly_handoff_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
b = bufs;
ti = thread_indices;
- fq_index = (is_feature) ?
- rm->fq_feature_index :
- (custom_context ? rm->fq_custom_context_index : rm->fq_index);
+ const u32 fq_index = a.is_output_feature ? rm->fq_output_feature_index :
+ a.is_feature ? rm->fq_feature_index :
+ a.custom_context ? rm->fq_custom_context_index :
+ rm->fq_index;
while (n_left_from > 0)
{
@@ -1302,7 +1371,7 @@ ip6_sv_reassembly_handoff_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
ti += 1;
b += 1;
}
- if (custom_context)
+ if (a.custom_context)
n_enq = vlib_buffer_enqueue_to_thread_with_aux (
vm, node, fq_index, from, context, thread_indices, frame->n_vectors, 1);
else
@@ -1321,7 +1390,10 @@ VLIB_NODE_FN (ip6_sv_reassembly_handoff_node) (vlib_main_t * vm,
vlib_frame_t * frame)
{
return ip6_sv_reassembly_handoff_inline (
- vm, node, frame, false /* is_feature */, false /* custom_context */);
+ vm, node, frame,
+ (struct ip6_sv_reass_hoff_args){ .is_feature = false,
+ .is_output_feature = false,
+ .custom_context = false });
}
VLIB_REGISTER_NODE (ip6_sv_reassembly_handoff_node) = {
@@ -1338,15 +1410,16 @@ VLIB_REGISTER_NODE (ip6_sv_reassembly_handoff_node) = {
},
};
-
VLIB_NODE_FN (ip6_sv_reassembly_feature_handoff_node) (vlib_main_t * vm,
vlib_node_runtime_t * node, vlib_frame_t * frame)
{
return ip6_sv_reassembly_handoff_inline (
- vm, node, frame, true /* is_feature */, false /* custom_context */);
+ vm, node, frame,
+ (struct ip6_sv_reass_hoff_args){ .is_feature = true,
+ .is_output_feature = false,
+ .custom_context = false });
}
-
VLIB_REGISTER_NODE (ip6_sv_reassembly_feature_handoff_node) = {
.name = "ip6-sv-reass-feature-hoff",
.vector_size = sizeof (u32),
@@ -1361,11 +1434,38 @@ VLIB_REGISTER_NODE (ip6_sv_reassembly_feature_handoff_node) = {
},
};
+VLIB_NODE_FN (ip6_sv_reassembly_output_feature_handoff_node)
+(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
+{
+ return ip6_sv_reassembly_handoff_inline (
+ vm, node, frame,
+ (struct ip6_sv_reass_hoff_args){ .is_feature = false,
+ .is_output_feature = true,
+ .custom_context = false });
+}
+
+VLIB_REGISTER_NODE (ip6_sv_reassembly_output_feature_handoff_node) = {
+ .name = "ip6-sv-reass-output-feature-hoff",
+ .vector_size = sizeof (u32),
+ .n_errors = ARRAY_LEN(ip6_sv_reassembly_handoff_error_strings),
+ .error_strings = ip6_sv_reassembly_handoff_error_strings,
+ .format_trace = format_ip6_sv_reassembly_handoff_trace,
+
+ .n_next_nodes = 1,
+
+ .next_nodes = {
+ [0] = "error-drop",
+ },
+};
+
VLIB_NODE_FN (ip6_sv_reassembly_custom_context_handoff_node)
(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
{
return ip6_sv_reassembly_handoff_inline (
- vm, node, frame, false /* is_feature */, true /* custom_context */);
+ vm, node, frame,
+ (struct ip6_sv_reass_hoff_args){ .is_feature = false,
+ .is_output_feature = false,
+ .custom_context = true });
}
VLIB_REGISTER_NODE (ip6_sv_reassembly_custom_context_handoff_node) = {
@@ -1411,6 +1511,33 @@ ip6_sv_reass_enable_disable_with_refcnt (u32 sw_if_index, int is_enable)
return 0;
}
+vnet_api_error_t
+ip6_sv_reass_output_enable_disable_with_refcnt (u32 sw_if_index, int is_enable)
+{
+ ip6_sv_reass_main_t *rm = &ip6_sv_reass_main;
+ vec_validate (rm->output_feature_use_refcount_per_intf, sw_if_index);
+ if (is_enable)
+ {
+ if (!rm->output_feature_use_refcount_per_intf[sw_if_index])
+ {
+ ++rm->output_feature_use_refcount_per_intf[sw_if_index];
+ return vnet_feature_enable_disable (
+ "ip6-output", "ip6-sv-reassembly-output-feature", sw_if_index, 1,
+ 0, 0);
+ }
+ ++rm->output_feature_use_refcount_per_intf[sw_if_index];
+ }
+ else
+ {
+ --rm->output_feature_use_refcount_per_intf[sw_if_index];
+ if (!rm->output_feature_use_refcount_per_intf[sw_if_index])
+ return vnet_feature_enable_disable ("ip6-output",
+ "ip6-sv-reassembly-output-feature",
+ sw_if_index, 0, 0, 0);
+ }
+ return 0;
+}
+
uword
ip6_sv_reass_custom_context_register_next_node (uword node_index)
{
diff --git a/src/vnet/ip/reass/ip6_sv_reass.h b/src/vnet/ip/reass/ip6_sv_reass.h
index 7dc9df132dd..b236e53f9e0 100644
--- a/src/vnet/ip/reass/ip6_sv_reass.h
+++ b/src/vnet/ip/reass/ip6_sv_reass.h
@@ -42,6 +42,9 @@ vnet_api_error_t ip6_sv_reass_get (u32 * timeout_ms, u32 * max_reassemblies,
vnet_api_error_t ip6_sv_reass_enable_disable (u32 sw_if_index,
u8 enable_disable);
+vnet_api_error_t
+ip6_sv_reass_output_enable_disable_with_refcnt (u32 sw_if_index,
+ int is_enable);
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);