summaryrefslogtreecommitdiffstats
path: root/src/vnet/ip/reass/ip6_sv_reass.c
diff options
context:
space:
mode:
authorKlement Sekera <ksekera@cisco.com>2021-12-07 09:49:53 +0000
committerOle Tr�an <otroan@employees.org>2021-12-10 08:41:00 +0000
commit7c3275e84b64ade4e20d00e4457bd4e437b1894f (patch)
tree1efbac2a6a5cb9ca4917062a37244039c1065e64 /src/vnet/ip/reass/ip6_sv_reass.c
parent514df6f931fb95e801c5033b114967e86113e778 (diff)
ip: reassembly: handle atomic fragments correctly
If a fragment arrives with fragment offset = 0 and M = 0, it means that this is actually a complete packet and per RFC 8200, it should be treated independently from other fragments. This patch does that. Fragmentation header is stripped and fragment is forwarded irregardles of other existing reassemblies in case of full reassembly and treated the same way as regular packet in shallow virtual reassembly. Type: improvement Change-Id: If3322d5e3160cd755b8465a642702a9166d46cc2 Signed-off-by: Klement Sekera <ksekera@cisco.com>
Diffstat (limited to 'src/vnet/ip/reass/ip6_sv_reass.c')
-rw-r--r--src/vnet/ip/reass/ip6_sv_reass.c21
1 files changed, 16 insertions, 5 deletions
diff --git a/src/vnet/ip/reass/ip6_sv_reass.c b/src/vnet/ip/reass/ip6_sv_reass.c
index fb435ba9630..3656c5a8f61 100644
--- a/src/vnet/ip/reass/ip6_sv_reass.c
+++ b/src/vnet/ip/reass/ip6_sv_reass.c
@@ -215,7 +215,7 @@ format_ip6_sv_reass_trace (u8 * s, va_list * args)
clib_net_to_host_u16 (t->l4_dst_port));
break;
case REASS_PASSTHROUGH:
- s = format (s, "[not-fragmented]");
+ s = format (s, "[not fragmented or atomic fragment]");
break;
}
return s;
@@ -532,13 +532,24 @@ ip6_sv_reassembly_inline (vlib_main_t * vm,
ip6_header_t *ip0 = vlib_buffer_get_current (b0);
ip6_frag_hdr_t *frag_hdr;
ip6_ext_hdr_chain_t hdr_chain;
+ bool is_atomic_fragment = false;
int res = ip6_ext_header_walk (
b0, ip0, IP_PROTOCOL_IPV6_FRAGMENTATION, &hdr_chain);
+ if (res >= 0 &&
+ hdr_chain.eh[res].protocol == IP_PROTOCOL_IPV6_FRAGMENTATION)
+ {
+ frag_hdr =
+ ip6_ext_next_header_offset (ip0, hdr_chain.eh[res].offset);
+ is_atomic_fragment = (0 == ip6_frag_hdr_offset (frag_hdr) &&
+ !ip6_frag_hdr_more (frag_hdr));
+ }
+
if (res < 0 ||
- hdr_chain.eh[res].protocol != IP_PROTOCOL_IPV6_FRAGMENTATION)
+ hdr_chain.eh[res].protocol != IP_PROTOCOL_IPV6_FRAGMENTATION ||
+ is_atomic_fragment)
{
- // this is a regular packet - no fragmentation
+ // this is a regular unfragmented packet or an atomic fragment
if (!ip6_get_port
(vm, b0, ip0, b0->current_length,
&(vnet_buffer (b0)->ip.reass.ip_proto),
@@ -565,10 +576,10 @@ ip6_sv_reassembly_inline (vlib_main_t * vm,
}
goto packet_enqueue;
}
- frag_hdr =
- ip6_ext_next_header_offset (ip0, hdr_chain.eh[res].offset);
+
vnet_buffer (b0)->ip.reass.ip6_frag_hdr_offset =
hdr_chain.eh[res].offset;
+
if (0 == ip6_frag_hdr_offset (frag_hdr))
{
// first fragment - verify upper-layer is present