From: Ralf Lici <ralf@mandelbit.com>
To: netdev@vger.kernel.org
Cc: "Daniel Gröber" <dxld@darkboxed.org>,
"Ralf Lici" <ralf@mandelbit.com>,
"Antonio Quartulli" <antonio@mandelbit.com>,
"Andrew Lunn" <andrew+netdev@lunn.ch>,
"David S. Miller" <davem@davemloft.net>,
"Eric Dumazet" <edumazet@google.com>,
"Jakub Kicinski" <kuba@kernel.org>,
"Paolo Abeni" <pabeni@redhat.com>,
linux-kernel@vger.kernel.org
Subject: [RFC net-next 09/15] ipxlat: emit translator-generated ICMP errors on drop
Date: Thu, 19 Mar 2026 16:12:18 +0100 [thread overview]
Message-ID: <20260319151230.655687-10-ralf@mandelbit.com> (raw)
In-Reply-To: <20260319151230.655687-1-ralf@mandelbit.com>
When validation or policy requires dropping a packet and generating an
ICMP error, route that failure through explicit ICMP emission paths so
the sender can be notified where appropriate. This commit adds
translator-originated error generation for both directions and
integrates it into dispatch action handling without changing normal
forwarding behavior.
Signed-off-by: Ralf Lici <ralf@mandelbit.com>
---
drivers/net/ipxlat/dispatch.c | 66 ++++++++++++++++++++++++++++++++++-
drivers/net/ipxlat/dispatch.h | 7 ++++
drivers/net/ipxlat/packet.c | 25 ++++++++++---
3 files changed, 92 insertions(+), 6 deletions(-)
diff --git a/drivers/net/ipxlat/dispatch.c b/drivers/net/ipxlat/dispatch.c
index 133d30859f49..b8b9b930b04c 100644
--- a/drivers/net/ipxlat/dispatch.c
+++ b/drivers/net/ipxlat/dispatch.c
@@ -11,7 +11,12 @@
* Ralf Lici <ralf@mandelbit.com>
*/
+#include <linux/icmp.h>
+#include <linux/icmpv6.h>
+#include <net/icmp.h>
#include <net/ip.h>
+#include <net/route.h>
+#include <net/ipv6.h>
#include "dispatch.h"
#include "packet.h"
@@ -21,7 +26,8 @@
static enum ipxlat_action
ipxlat_resolve_failed_action(const struct sk_buff *skb)
{
- return IPXLAT_ACT_DROP;
+ return ipxlat_skb_cb(skb)->emit_icmp_err ? IPXLAT_ACT_ICMP_ERR :
+ IPXLAT_ACT_DROP;
}
enum ipxlat_action ipxlat_translate(struct ipxlat_priv *ipxlat,
@@ -61,6 +67,59 @@ void ipxlat_mark_icmp_drop(struct sk_buff *skb, u8 type, u8 code, u32 info)
cb->icmp_err.info = info;
}
+static void ipxlat_46_emit_icmp_err(struct ipxlat_priv *ipxlat,
+ struct sk_buff *inner)
+{
+ struct ipxlat_cb *cb = ipxlat_skb_cb(inner);
+ const struct iphdr *iph = ip_hdr(inner);
+ struct inet_skb_parm param = {};
+
+ /* build route metadata on demand when the packet has no dst */
+ if (unlikely(!skb_dst(inner))) {
+ const int reason = ip_route_input_noref(inner, iph->daddr,
+ iph->saddr,
+ ip4h_dscp(iph),
+ inner->dev);
+
+ if (unlikely(reason)) {
+ netdev_dbg(ipxlat->dev,
+ "icmp4 emit: route build failed reason=%d\n",
+ reason);
+ return;
+ }
+ }
+
+ /* emit the ICMPv4 error */
+ __icmp_send(inner, cb->icmp_err.type, cb->icmp_err.code,
+ htonl(cb->icmp_err.info), ¶m);
+}
+
+static void ipxlat_64_emit_icmp_err(struct sk_buff *inner)
+{
+ struct ipxlat_cb *cb = ipxlat_skb_cb(inner);
+ struct inet6_skb_parm param = {};
+
+ /* emit the ICMPv6 error */
+ icmp6_send(inner, cb->icmp_err.type, cb->icmp_err.code,
+ cb->icmp_err.info, NULL, ¶m);
+}
+
+/* emit translator-generated ICMP errors for packets rejected by RFC rules */
+void ipxlat_emit_icmp_error(struct ipxlat_priv *ipxlat, struct sk_buff *inner)
+{
+ switch (ntohs(inner->protocol)) {
+ case ETH_P_IPV6:
+ ipxlat_64_emit_icmp_err(inner);
+ return;
+ case ETH_P_IP:
+ ipxlat_46_emit_icmp_err(ipxlat, inner);
+ return;
+ default:
+ DEBUG_NET_WARN_ON_ONCE(1);
+ return;
+ }
+}
+
static void ipxlat_forward_pkt(struct ipxlat_priv *ipxlat, struct sk_buff *skb)
{
const unsigned int len = skb->len;
@@ -90,6 +149,11 @@ int ipxlat_process_skb(struct ipxlat_priv *ipxlat, struct sk_buff *skb,
dev_dstats_tx_add(ipxlat->dev, skb->len);
ipxlat_forward_pkt(ipxlat, skb);
return 0;
+ case IPXLAT_ACT_ICMP_ERR:
+ dev_dstats_tx_dropped(ipxlat->dev);
+ ipxlat_emit_icmp_error(ipxlat, skb);
+ consume_skb(skb);
+ return 0;
case IPXLAT_ACT_DROP:
goto drop_free;
default:
diff --git a/drivers/net/ipxlat/dispatch.h b/drivers/net/ipxlat/dispatch.h
index fa6fafea656b..73acd831b6cf 100644
--- a/drivers/net/ipxlat/dispatch.h
+++ b/drivers/net/ipxlat/dispatch.h
@@ -44,6 +44,13 @@ enum ipxlat_action {
*/
void ipxlat_mark_icmp_drop(struct sk_buff *skb, u8 type, u8 code, u32 info);
+/**
+ * ipxlat_emit_icmp_error - emit cached translator-generated ICMP error
+ * @ipxlat: translator private context
+ * @inner: offending packet used as quoted payload
+ */
+void ipxlat_emit_icmp_error(struct ipxlat_priv *ipxlat, struct sk_buff *inner);
+
/**
* ipxlat_translate - validate/translate one packet and return next action
* @ipxlat: translator private context
diff --git a/drivers/net/ipxlat/packet.c b/drivers/net/ipxlat/packet.c
index b37a3e55aff8..758b72bdc6f1 100644
--- a/drivers/net/ipxlat/packet.c
+++ b/drivers/net/ipxlat/packet.c
@@ -142,6 +142,8 @@ static int ipxlat_v4_srr_check(struct sk_buff *skb, const struct iphdr *hdr)
if (unlikely(ptr > len - 3))
return -EINVAL;
+ ipxlat_mark_icmp_drop(skb, ICMP_DEST_UNREACH,
+ ICMP_SR_FAILED, 0);
return -EINVAL;
}
@@ -272,8 +274,10 @@ static int ipxlat_v4_pull_hdrs(struct sk_buff *skb)
/* RFC 7915 Section 4.1 */
if (unlikely(ipxlat_v4_srr_check(skb, l3_hdr)))
return -EINVAL;
- if (unlikely(l3_hdr->ttl <= 1))
+ if (unlikely(l3_hdr->ttl <= 1)) {
+ ipxlat_mark_icmp_drop(skb, ICMP_TIME_EXCEEDED, ICMP_EXC_TTL, 0);
return -EINVAL;
+ }
/* RFC 7915 Section 1.2:
* Fragmented ICMP/ICMPv6 packets will not be translated by IP/ICMP
@@ -390,8 +394,11 @@ int ipxlat_v4_validate_skb(struct ipxlat_priv *ipxlat, struct sk_buff *skb)
* Fragmented checksum-less IPv4 UDP is rejected because 4->6 cannot
* reliably translate it.
*/
- if (unlikely(ip_is_fragment(l3_hdr)))
+ if (unlikely(ip_is_fragment(l3_hdr))) {
+ ipxlat_mark_icmp_drop(skb, ICMP_DEST_UNREACH, ICMP_PKT_FILTERED,
+ 0);
return -EINVAL;
+ }
/* udph->len bounds the span used to compute replacement checksum */
if (unlikely(ntohs(udph->len) > skb->len - cb->l4_off))
@@ -520,7 +527,7 @@ static int ipxlat_v6_walk_hdrs(struct sk_buff *skb, unsigned int l3_offset,
*/
static int ipxlat_v6_check_rh(struct sk_buff *skb)
{
- unsigned int rh_off;
+ unsigned int rh_off, pointer;
int flags, nexthdr;
rh_off = 0;
@@ -531,6 +538,8 @@ static int ipxlat_v6_check_rh(struct sk_buff *skb)
if (likely(nexthdr != NEXTHDR_ROUTING))
return 0;
+ pointer = rh_off + offsetof(struct ipv6_rt_hdr, segments_left);
+ ipxlat_mark_icmp_drop(skb, ICMPV6_PARAMPROB, ICMPV6_HDR_FIELD, pointer);
return -EINVAL;
}
@@ -550,8 +559,11 @@ static int ipxlat_v6_pull_outer_l3(struct sk_buff *skb)
!ipxlat_v6_validate_saddr(&l3_hdr->saddr)))
return -EINVAL;
- if (unlikely(l3_hdr->hop_limit <= 1))
+ if (unlikely(l3_hdr->hop_limit <= 1)) {
+ ipxlat_mark_icmp_drop(skb, ICMPV6_TIME_EXCEED,
+ ICMPV6_EXC_HOPLIMIT, 0);
return -EINVAL;
+ }
return 0;
}
@@ -617,8 +629,11 @@ static int ipxlat_v6_pull_hdrs(struct sk_buff *skb)
/* -EPROTONOSUPPORT means packet layout is syntactically valid but
* unsupported by our RFC 7915 path
*/
- if (unlikely(err == -EPROTONOSUPPORT))
+ if (unlikely(err == -EPROTONOSUPPORT)) {
+ ipxlat_mark_icmp_drop(skb, ICMPV6_DEST_UNREACH,
+ ICMPV6_ADM_PROHIBITED, 0);
return -EINVAL;
+ }
if (unlikely(err))
return err;
--
2.53.0
next prev parent reply other threads:[~2026-03-19 15:20 UTC|newest]
Thread overview: 18+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-03-19 15:12 [RFC net-next 00/15] Introducing ipxlat: a stateless IPv4/IPv6 translation device Ralf Lici
2026-03-19 15:12 ` [RFC net-next 01/15] drivers/net: add ipxlat netdevice skeleton and build plumbing Ralf Lici
2026-03-19 15:12 ` [RFC net-next 02/15] ipxlat: add RFC 6052 address conversion helpers Ralf Lici
2026-03-19 15:12 ` [RFC net-next 03/15] ipxlat: add packet metadata control block helpers Ralf Lici
2026-03-19 15:12 ` [RFC net-next 04/15] ipxlat: add IPv4 packet validation path Ralf Lici
2026-03-19 15:12 ` [RFC net-next 05/15] ipxlat: add IPv6 " Ralf Lici
2026-03-19 15:12 ` [RFC net-next 06/15] ipxlat: add transport checksum and offload helpers Ralf Lici
2026-03-19 15:12 ` [RFC net-next 07/15] ipxlat: add 4to6 and 6to4 TCP/UDP translation helpers Ralf Lici
2026-03-19 15:12 ` [RFC net-next 08/15] ipxlat: add translation engine and dispatch core Ralf Lici
2026-03-19 15:12 ` Ralf Lici [this message]
2026-03-19 15:12 ` [RFC net-next 10/15] ipxlat: add 4to6 pre-fragmentation path Ralf Lici
2026-03-19 15:12 ` [RFC net-next 11/15] ipxlat: add ICMP informational translation paths Ralf Lici
2026-03-19 15:12 ` [RFC net-next 12/15] ipxlat: add ICMP error translation and quoted-inner handling Ralf Lici
2026-03-19 15:12 ` [RFC net-next 13/15] ipxlat: add netlink control plane and uapi Ralf Lici
2026-03-19 15:12 ` [RFC net-next 14/15] selftests: net: add ipxlat coverage Ralf Lici
2026-03-19 15:12 ` [RFC net-next 15/15] Documentation: networking: add ipxlat translator guide Ralf Lici
2026-03-19 22:11 ` Jonathan Corbet
2026-03-24 9:55 ` Ralf Lici
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260319151230.655687-10-ralf@mandelbit.com \
--to=ralf@mandelbit.com \
--cc=andrew+netdev@lunn.ch \
--cc=antonio@mandelbit.com \
--cc=davem@davemloft.net \
--cc=dxld@darkboxed.org \
--cc=edumazet@google.com \
--cc=kuba@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox