All of lore.kernel.org
 help / color / mirror / Atom feed
From: Ralf Lici <ralf@mandelbit.com>
To: netdev@vger.kernel.org
Cc: "David S. Miller" <davem@davemloft.net>,
	"Eric Dumazet" <edumazet@kernel.org>,
	"Jakub Kicinski" <kuba@kernel.org>,
	"Paolo Abeni" <pabeni@redhat.com>,
	"Simon Horman" <horms@kernel.org>,
	"Daniel Gröber" <dxld@darkboxed.org>,
	"Antonio Quartulli" <antonio@mandelbit.com>,
	linux-kernel@vger.kernel.org
Subject: [RFC net-next v2 07/18] net: ipxlat: add packet metadata and header helpers
Date: Sat, 24 Oct 2026 11:25:17 +0200	[thread overview]
Message-ID: <20261024092532.172005-8-ralf@mandelbit.com> (raw)
In-Reply-To: <20261024092532.172005-1-ralf@mandelbit.com>

Define the skb control block used while a packet is prepared, together
with offset, length, fragment and pending-error helpers shared by
the two protocol families.

Signed-off-by: Ralf Lici <ralf@mandelbit.com>
---
Changes since RFC v1 https://lore.kernel.org/netdev/20260319151230.655687-4-ralf@mandelbit.com/
- Reshape the v1 control block for the prepare-translate engine contract,
  remove netdevice actions and continuation policy from its metadata,
  and split family-specific parsing into packet4.c and packet6.c.
- Make headers which expose IPv6 packet and Fragment Header types
  include the declarations they use. (Sashiko)

 net/ipxlat/packet.h | 243 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 243 insertions(+)
 create mode 100644 net/ipxlat/packet.h

diff --git a/net/ipxlat/packet.h b/net/ipxlat/packet.h
new file mode 100644
index 000000000000..463f1ef027d0
--- /dev/null
+++ b/net/ipxlat/packet.h
@@ -0,0 +1,243 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*  IPXLAT - Stateless IP/ICMP Translation (SIIT) engine
+ *
+ *  Copyright (C) 2024- Alberto Leiva Popper <ydahhrk@gmail.com>
+ *  Copyright (C) 2026- Mandelbit SRL
+ *  Copyright (C) 2026- Daniel Gröber <dxld@darkboxed.org>
+ *
+ *  Author:	Alberto Leiva Popper <ydahhrk@gmail.com>
+ *		Antonio Quartulli <antonio@mandelbit.com>
+ *		Daniel Gröber <dxld@darkboxed.org>
+ *		Ralf Lici <ralf@mandelbit.com>
+ */
+
+#ifndef _NET_IPXLAT_PACKET_H_
+#define _NET_IPXLAT_PACKET_H_
+
+#include <net/ip.h>
+#include <net/ipv6.h>
+
+#include <net/ipxlat.h>
+
+/**
+ * struct ipxlat_cb - per-skb parser and control metadata stored in skb->cb
+ * @l4_off: outer L4 header offset
+ * @payload_off: outer payload offset
+ * @fragh_off: outer IPv6 Fragment Header offset, or 0 if absent
+ * @inner_l3_offset: quoted inner L3 offset for ICMP errors
+ * @inner_l4_offset: quoted inner L4 offset for ICMP errors
+ * @inner_fragh_off: quoted inner IPv6 Fragment Header offset, or 0
+ * @l4_proto: outer L4 protocol (or nexthdr for IPv6)
+ * @inner_l4_proto: quoted inner L4 protocol
+ * @l3_hdr_len: outer L3 header length including extension headers
+ * @is_icmp_err: packet is ICMP error and carries quoted inner packet
+ * @emit_icmp_err: datapath must emit translator-generated ICMP on drop
+ * @saddr4: translated outer IPv4 source address for 6->4
+ * @daddr4: translated outer IPv4 destination address for 6->4
+ * @inner_saddr4: translated quoted IPv4 source address for ICMP 6->4
+ * @inner_daddr4: translated quoted IPv4 destination address for ICMP 6->4
+ * @pending_icmp_err: ICMP type/code/info cached for deferred emission
+ * @pending_icmp_err.type: ICMP type to emit
+ * @pending_icmp_err.code: ICMP code to emit
+ * @pending_icmp_err.info: ICMP auxiliary info (e.g. pointer/MTU)
+ */
+struct ipxlat_cb {
+	u16 l4_off;
+	u16 payload_off;
+	u16 fragh_off;
+	u16 inner_l3_offset;
+	u16 inner_l4_offset;
+	u16 inner_fragh_off;
+	u16 l3_hdr_len;
+	u8 l4_proto;
+	u8 inner_l4_proto;
+	bool is_icmp_err;
+	bool emit_icmp_err;
+	__be32 saddr4;
+	__be32 daddr4;
+	__be32 inner_saddr4;
+	__be32 inner_daddr4;
+	struct {
+		u8 type;
+		u8 code;
+		u32 info;
+	} pending_icmp_err;
+};
+
+static inline struct ipxlat_cb *ipxlat_skb_cb(const struct sk_buff *skb)
+{
+	BUILD_BUG_ON(sizeof(struct ipxlat_cb) > sizeof(skb->cb));
+	return (struct ipxlat_cb *)(skb->cb);
+}
+
+static inline unsigned int ipxlat_skb_l4_len(const struct sk_buff *skb)
+{
+	return skb->len - skb_transport_offset(skb);
+}
+
+/* return the L4 length of one eventual segment rather than the GSO aggregate */
+static inline unsigned int ipxlat_skb_l4_seg_len(const struct sk_buff *skb,
+						 const struct ipxlat_cb *cb)
+{
+	const struct skb_shared_info *shinfo;
+
+	if (skb_is_gso(skb)) {
+		shinfo = skb_shinfo(skb);
+		/* legacy UFO's gso_size already includes the UDP header */
+		if (shinfo->gso_type & SKB_GSO_UDP)
+			return shinfo->gso_size;
+
+		/* TCP and UDP-L4 GSO sizes describe payload bytes only */
+		return cb->payload_off - cb->l4_off + shinfo->gso_size;
+	}
+	return skb->len - cb->l4_off;
+}
+
+static inline u8 ipxlat_get_ipv6_tclass(const struct ipv6hdr *hdr)
+{
+	return (hdr->priority << 4) | (hdr->flow_lbl[0] >> 4);
+}
+
+static inline u16 ipxlat_get_frag6_offset(const struct frag_hdr *hdr)
+{
+	return be16_to_cpu(hdr->frag_off) & IP6_OFFSET;
+}
+
+static inline u16 ipxlat_get_frag4_offset(const struct iphdr *hdr)
+{
+	return (be16_to_cpu(hdr->frag_off) & IP_OFFSET) << 3;
+}
+
+static inline bool ipxlat_is_first_frag6(const struct frag_hdr *hdr)
+{
+	return !hdr || ipxlat_get_frag6_offset(hdr) == 0;
+}
+
+static inline bool ipxlat_is_first_frag4(const struct iphdr *hdr)
+{
+	return !(hdr->frag_off & htons(IP_OFFSET));
+}
+
+/**
+ * ipxlat_replace_l3 - replace an outer or quoted L3 header in place
+ * @skb: packet containing the L3 header
+ * @old_l3_end: current offset immediately after the L3 header
+ * @new_l3_end: desired offset immediately after the L3 header
+ * @transport_off: transport header offset after replacement
+ *
+ * The caller must provide valid offsets and enough headroom. Bytes following
+ * @old_l3_end remain unchanged, and the network header is reset to @skb->data.
+ */
+static inline void ipxlat_replace_l3(struct sk_buff *skb,
+				     unsigned int old_l3_end,
+				     unsigned int new_l3_end,
+				     unsigned int transport_off)
+{
+	skb_pull(skb, old_l3_end);
+	skb_push(skb, new_l3_end);
+	skb_reset_network_header(skb);
+	skb_set_transport_header(skb, transport_off);
+}
+
+/**
+ * ipxlat_cb_rebase_offsets - shift cached cb offsets after skb relayout
+ * @cb: parsed packet metadata
+ * @delta: signed byte delta applied to cached offsets
+ *
+ * All cached absolute offsets include the old outer L3 length. Apply the same
+ * delta to keep them pointing at the same logical fields after replacement.
+ */
+static inline void ipxlat_cb_rebase_offsets(struct ipxlat_cb *cb, int delta)
+{
+	cb->l4_off += delta;
+	cb->payload_off += delta;
+
+	if (unlikely(cb->is_icmp_err)) {
+		cb->inner_l3_offset += delta;
+		cb->inner_l4_offset += delta;
+
+		if (cb->inner_fragh_off)
+			cb->inner_fragh_off += delta;
+	}
+}
+
+#ifdef CONFIG_DEBUG_NET
+/**
+ * ipxlat_cb_offsets_valid - validate monotonicity and bounds of cb offsets
+ * @cb: parsed packet metadata
+ *
+ * Checks that L4 precedes payload, quoted L3 follows the outer payload and a
+ * quoted Fragment Header lies inside the quoted L3 area before quoted L4.
+ *
+ * Return: true if cached offsets are internally consistent.
+ */
+static inline bool ipxlat_cb_offsets_valid(const struct ipxlat_cb *cb)
+{
+	if (unlikely(cb->payload_off < cb->l4_off))
+		return false;
+
+	if (cb->is_icmp_err) {
+		if (unlikely(cb->inner_l3_offset < cb->payload_off))
+			return false;
+		if (unlikely(cb->inner_l4_offset < cb->inner_l3_offset))
+			return false;
+		if (unlikely(cb->inner_fragh_off &&
+			     cb->inner_fragh_off < cb->inner_l3_offset))
+			return false;
+		if (unlikely(cb->inner_fragh_off &&
+			     cb->inner_fragh_off >= cb->inner_l4_offset))
+			return false;
+	}
+
+	return true;
+}
+#else
+static inline bool ipxlat_cb_offsets_valid(const struct ipxlat_cb *cb)
+{
+	return true;
+}
+#endif
+
+/**
+ * ipxlat_mark_icmp_drop - record an ICMP error for a dropped packet
+ * @skb: packet carrying the translator metadata
+ * @type: ICMP or ICMPv6 type
+ * @code: ICMP or ICMPv6 code
+ * @info: ICMP or ICMPv6 auxiliary information
+ */
+static inline void ipxlat_mark_icmp_drop(struct sk_buff *skb, u8 type, u8 code,
+					 u32 info)
+{
+	struct ipxlat_cb *cb = ipxlat_skb_cb(skb);
+
+	cb->emit_icmp_err = true;
+	cb->pending_icmp_err.type = type;
+	cb->pending_icmp_err.code = code;
+	cb->pending_icmp_err.info = info;
+}
+
+/**
+ * ipxlat_v4_validate_skb - validate and summarize IPv4 packet into skb->cb
+ * @skb: packet to validate
+ *
+ * Ensures required headers are present and consistent, populates
+ * &struct ipxlat_cb for subsequent 4->6 translation, and may mark a
+ * translator-generated ICMP action on failure paths.
+ *
+ * Return: 0 on success, negative errno on validation failure.
+ */
+int ipxlat_v4_validate_skb(struct sk_buff *skb);
+
+/**
+ * ipxlat_v6_validate_skb - validate and summarize IPv6 packet into skb->cb
+ * @skb: packet to validate
+ *
+ * Ensures required headers are present and consistent, populates
+ * &struct ipxlat_cb for subsequent 6->4 translation, and may mark a
+ * translator-generated ICMP action on failure paths.
+ *
+ * Return: 0 on success, negative errno on validation failure.
+ */
+int ipxlat_v6_validate_skb(struct sk_buff *skb);
+
+#endif /* _NET_IPXLAT_PACKET_H_ */
-- 
2.55.0


  parent reply	other threads:[~2026-10-24  9:26 UTC|newest]

Thread overview: 19+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-24  9:25 [RFC net-next v2 00/18] net: introduce ipxlat stateless IPv4/IPv6 translation Ralf Lici
2026-10-24  9:25 ` [RFC net-next v2 01/18] lwtunnel: track callback dispatch separately from return value Ralf Lici
2026-10-24  9:25 ` [RFC net-next v2 02/18] ipv4/ipv6: add LWT receive helpers Ralf Lici
2026-10-24  9:25 ` [RFC net-next v2 03/18] ipv6: allow output fragmentation to reuse a Fragment Header Ralf Lici
2026-10-24  9:25 ` [RFC net-next v2 04/18] netfilter: preserve IPv6 refragmentation state across reassembly Ralf Lici
2026-10-24  9:25 ` [RFC net-next v2 05/18] net: ipxlat: add engine skeleton and configuration model Ralf Lici
2026-10-24  9:25 ` [RFC net-next v2 06/18] net: ipxlat: add RFC 6052 and EAM address translation Ralf Lici
2026-10-24  9:25 ` Ralf Lici [this message]
2026-10-24  9:25 ` [RFC net-next v2 08/18] net: ipxlat: add IPv4 packet validation Ralf Lici
2026-10-24  9:25 ` [RFC net-next v2 09/18] net: ipxlat: add IPv6 " Ralf Lici
2026-10-24  9:25 ` [RFC net-next v2 10/18] net: ipxlat: add checksum and offload helpers Ralf Lici
2026-10-24  9:25 ` [RFC net-next v2 11/18] net: ipxlat: add IPv4/IPv6 header and transport translation Ralf Lici
2026-10-24  9:25 ` [RFC net-next v2 12/18] net: ipxlat: add translation preparation and dispatch Ralf Lici
2026-10-24  9:25 ` [RFC net-next v2 13/18] net: ipxlat: add translator-generated ICMP errors Ralf Lici
2026-10-24  9:25 ` [RFC net-next v2 14/18] net: ipxlat: add ICMP informational translation Ralf Lici
2026-10-24  9:25 ` [RFC net-next v2 15/18] net: ipxlat: add ICMP error and quoted-packet translation Ralf Lici
2026-10-24  9:25 ` [RFC net-next v2 16/18] net: ipxlat: add lightweight tunnel attachment Ralf Lici
2026-10-24  9:25 ` [RFC net-next v2 17/18] selftests: net: add ipxlat coverage Ralf Lici
2026-10-24  9:25 ` [RFC net-next v2 18/18] docs: networking: add ipxlat guide 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=20261024092532.172005-8-ralf@mandelbit.com \
    --to=ralf@mandelbit.com \
    --cc=antonio@mandelbit.com \
    --cc=davem@davemloft.net \
    --cc=dxld@darkboxed.org \
    --cc=edumazet@kernel.org \
    --cc=horms@kernel.org \
    --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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.