Summary
On VPP 26.06-release (nat44-ed, on-a-stick — one interface configured as both NAT in and out,
so the classification feature is active), a worker thread reliably SIGSEGVs in
nat44_ed_out2in_slowpath_node_fn under normal CGNAT traffic. For ~39 s before the crash the log
floods with:
nat_6t_flow_icmp_translate:3955: unexpected NAT protocol value 47' nat_6t_flow_icmp_translate:3955: unexpected NAT protocol value 4'
i.e. an ICMP error message whose quoted inner packet is GRE (proto 47) or IPIP (proto 4) —
generated naturally by subscribers running PPTP (GRE) / IP-in-IP tunnels.
Environment
- VPP
26.06-release (x86_64-v4 build), vpp_plugins/nat_plugin.so
- Debian 13 (trixie), kernel 6.12.94, Intel E810 via DPDK/vfio-pci, 16 worker threads
- nat44-ed (endpoint-dependent), on-a-stick: both interfaces
nat44 in out (classification feature)
- CGNAT pool /24 + 375 address-only 1:1 static mappings, ~1.3–1.5M sessions, ~930k pps
Steps to reproduce
- nat44-ed on-a-stick (one interface configured as both
in and out) with a NAT pool / static-mapped
external address.
- From outside, send to that NATed external address an ICMP error (dest-unreachable / TTL-exceeded /
frag-needed) whose quoted inner IPv4 header has protocol = 47 (GRE) or 4 (IPIP).
- Drive volume through the out2in slow path. The log floods with
nat_6t_flow_icmp_translate:3955: unexpected NAT protocol value '47'/'4', then a worker SIGSEGVs in nat44_ed_out2in_slowpath_node_fn.
Crash details
Syslog:
received signal SIGSEGV, PC 0x..b957, faulting address 0x..
#0 nat44_ed_out2in_slowpath_node_fn_x86_64_v4 + 0x9e7 (nat_plugin.so)
Backtrace (gdb on core):
#6 nat44_ed_out2in_slowpath_node_fn_x86_64_v4 () nat_plugin.so
#7 dispatch_node () libvlib
#8 vlib_worker_thread_bootstrap_fn () libvlib
Faulting instruction:
nat44_ed_out2in_slowpath_node_fn_x86_64_v4+2535: mov %ebp,0x4(%rcx,%rbx,4)
followed by lea (%rbp,%rbp,2) (×3) and mov qword [..],-1 — the shape of clib_dlist
manipulation on the per-thread LRU pool (dlist_elt_t = {next,prev,value} = 3×u32, -1 = invalid-index
sentinel).
Source analysis
nat_6t_flow_icmp_translate() (nat44_ed.c) switches on the inner packet's protocol; for anything other
than TCP/UDP/ICMP (GRE 47, IPIP 4) it returns cleanly:
3954 default:
3955 clib_warning ("unexpected NAT protocol value `%d'", inner_proto);
3956 return NAT_ED_TRNSL_ERR_TRANSLATION_FAILED;
The node-fn callers handle that return correctly (next=DROP; b0->error; goto trace0), so this is not
a missing-drop bug.
Suspected mechanism (UNVERIFIED — static analysis + faulting-instruction shape only):
icmp_out2in_ed_slow_path() (nat44_ed_out2in.c) creates a session for the inbound ICMP error and links
it into the per-thread LRU dlist. Back in the node fn (~l.1122-1131) the follow-up
nat_6t_flow_buf_translate_o2i() then fails for the GRE/IPIP inner packet, so the packet is dropped — but
unlike the FLOW_MISMATCH path (~l.936-939, which does nat44_ed_free_session_data + nat_ed_session_delete)
this drop path does not delete the just-created session, leaking it in the LRU dlist. Accumulation
corrupts the dlist → later SIGSEGV in dlist code (consistent with the ~39 s warning flood beforehand).
Candidate fix (unverified): on that drop path, free_session_data + session_delete the just-created
s0 (mirroring l.936-939). Reproducing + verifying on a debug build; will follow up with a PR if confirmed.
Impact
Worker SIGSEGV → VPP restart. Triggered by everyday GRE/IPIP tunnel traffic, so a nat44-ed node cannot
stay up reliably. The crash is in LRU clib_dlist code but the trigger differs from VPP-2117 / CSIT-1947
(not the eviction path — a session leaked into the LRU on an ICMP-error translate failure).
Artifacts
A 12 GB core (VPP 26.06-release, core.vpp_wk_15.*) is available on request.
Question
Does this analysis match a known issue, or is it already fixed on master? Happy to test a patch.
Summary
On VPP 26.06-release (nat44-ed, on-a-stick — one interface configured as both NAT
inandout,so the classification feature is active), a worker thread reliably SIGSEGVs in
nat44_ed_out2in_slowpath_node_fnunder normal CGNAT traffic. For ~39 s before the crash the logfloods with:
nat_6t_flow_icmp_translate:3955: unexpected NAT protocol value 47' nat_6t_flow_icmp_translate:3955: unexpected NAT protocol value 4'
i.e. an ICMP error message whose quoted inner packet is GRE (proto 47) or IPIP (proto 4) —
generated naturally by subscribers running PPTP (GRE) / IP-in-IP tunnels.
Environment
26.06-release(x86_64-v4 build),vpp_plugins/nat_plugin.sonat44 in out(classification feature)Steps to reproduce
inandout) with a NAT pool / static-mappedexternal address.
frag-needed) whose quoted inner IPv4 header has
protocol = 47(GRE) or4(IPIP).nat_6t_flow_icmp_translate:3955: unexpected NAT protocol value '47'/'4', then a worker SIGSEGVs innat44_ed_out2in_slowpath_node_fn.Crash details
Syslog:
received signal SIGSEGV, PC 0x..b957, faulting address 0x..
#0 nat44_ed_out2in_slowpath_node_fn_x86_64_v4 + 0x9e7 (nat_plugin.so)
Backtrace (gdb on core):
#6 nat44_ed_out2in_slowpath_node_fn_x86_64_v4 () nat_plugin.so
#7 dispatch_node () libvlib
#8 vlib_worker_thread_bootstrap_fn () libvlib
Faulting instruction:
nat44_ed_out2in_slowpath_node_fn_x86_64_v4+2535: mov %ebp,0x4(%rcx,%rbx,4)
followed by
lea (%rbp,%rbp,2)(×3) andmov qword [..],-1— the shape ofclib_dlistmanipulation on the per-thread LRU pool (
dlist_elt_t= {next,prev,value} = 3×u32, -1 = invalid-indexsentinel).
Source analysis
nat_6t_flow_icmp_translate()(nat44_ed.c) switches on the inner packet's protocol; for anything otherthan TCP/UDP/ICMP (GRE 47, IPIP 4) it returns cleanly: