Commit d2675fe9 authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files

Merge branch 'net-flow-dissector-allow-explicit-passing-of-netns'

Florian Westphal says:

====================
net: flow dissector: allow explicit passing of netns

Change since last version:
 fix kdoc comment warning reported by kbuild robot, no other changes,
 thus retaining RvB tags from Eric and Willem.
 v1: https://lore.kernel.org/netdev/20240607083205.3000-1-fw@strlen.de/

Years ago flow dissector gained ability to delegate flow dissection
to a bpf program, scoped per netns.

The netns is derived from skb->dev, and if that is not available, from
skb->sk.  If neither is set, we hit a (benign) WARN_ON_ONCE().

This WARN_ON_ONCE can be triggered from netfilter.
Known skb origins are nf_send_reset and ipv4 stack generated IGMP
messages.

Lets allow callers to pass the current netns explicitly and make
nf_tables use those instead.

This targets net-next instead of net because the WARN is benign and this
is not a regression.
====================

Link: https://lore.kernel.org/r/20240608221057.16070-1-fw@strlen.de


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 91579c93 d1dab4f7
Loading
Loading
Loading
Loading
+17 −3
Original line number Diff line number Diff line
@@ -1498,8 +1498,14 @@ __skb_set_sw_hash(struct sk_buff *skb, __u32 hash, bool is_l4)
	__skb_set_hash(skb, hash, true, is_l4);
}

void __skb_get_hash(struct sk_buff *skb);
u32 __skb_get_hash_symmetric(const struct sk_buff *skb);
u32 __skb_get_hash_symmetric_net(const struct net *net, const struct sk_buff *skb);

static inline u32 __skb_get_hash_symmetric(const struct sk_buff *skb)
{
	return __skb_get_hash_symmetric_net(NULL, skb);
}

void __skb_get_hash_net(const struct net *net, struct sk_buff *skb);
u32 skb_get_poff(const struct sk_buff *skb);
u32 __skb_get_poff(const struct sk_buff *skb, const void *data,
		   const struct flow_keys_basic *keys, int hlen);
@@ -1578,10 +1584,18 @@ void skb_flow_dissect_hash(const struct sk_buff *skb,
			   struct flow_dissector *flow_dissector,
			   void *target_container);

static inline __u32 skb_get_hash_net(const struct net *net, struct sk_buff *skb)
{
	if (!skb->l4_hash && !skb->sw_hash)
		__skb_get_hash_net(net, skb);

	return skb->hash;
}

static inline __u32 skb_get_hash(struct sk_buff *skb)
{
	if (!skb->l4_hash && !skb->sw_hash)
		__skb_get_hash(skb);
		__skb_get_hash_net(NULL, skb);

	return skb->hash;
}
+14 −7
Original line number Diff line number Diff line
@@ -1845,22 +1845,23 @@ EXPORT_SYMBOL(make_flow_keys_digest);

static struct flow_dissector flow_keys_dissector_symmetric __read_mostly;

u32 __skb_get_hash_symmetric(const struct sk_buff *skb)
u32 __skb_get_hash_symmetric_net(const struct net *net, const struct sk_buff *skb)
{
	struct flow_keys keys;

	__flow_hash_secret_init();

	memset(&keys, 0, sizeof(keys));
	__skb_flow_dissect(NULL, skb, &flow_keys_dissector_symmetric,
	__skb_flow_dissect(net, skb, &flow_keys_dissector_symmetric,
			   &keys, NULL, 0, 0, 0, 0);

	return __flow_hash_from_keys(&keys, &hashrnd);
}
EXPORT_SYMBOL_GPL(__skb_get_hash_symmetric);
EXPORT_SYMBOL_GPL(__skb_get_hash_symmetric_net);

/**
 * __skb_get_hash: calculate a flow hash
 * __skb_get_hash_net: calculate a flow hash
 * @net: associated network namespace, derived from @skb if NULL
 * @skb: sk_buff to calculate flow hash from
 *
 * This function calculates a flow hash based on src/dst addresses
@@ -1868,18 +1869,24 @@ EXPORT_SYMBOL_GPL(__skb_get_hash_symmetric);
 * on success, zero indicates no valid hash.  Also, sets l4_hash in skb
 * if hash is a canonical 4-tuple hash over transport ports.
 */
void __skb_get_hash(struct sk_buff *skb)
void __skb_get_hash_net(const struct net *net, struct sk_buff *skb)
{
	struct flow_keys keys;
	u32 hash;

	memset(&keys, 0, sizeof(keys));

	__skb_flow_dissect(net, skb, &flow_keys_dissector,
			   &keys, NULL, 0, 0, 0,
			   FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL);

	__flow_hash_secret_init();

	hash = ___skb_get_hash(skb, &keys, &hashrnd);
	hash = __flow_hash_from_keys(&keys, &hashrnd);

	__skb_set_sw_hash(skb, hash, flow_keys_have_l4(&keys));
}
EXPORT_SYMBOL(__skb_get_hash);
EXPORT_SYMBOL(__skb_get_hash_net);

__u32 skb_get_hash_perturb(const struct sk_buff *skb,
			   const siphash_key_t *perturb)
+1 −1
Original line number Diff line number Diff line
@@ -317,7 +317,7 @@ void nft_trace_init(struct nft_traceinfo *info, const struct nft_pktinfo *pkt,
	net_get_random_once(&trace_key, sizeof(trace_key));

	info->skbid = (u32)siphash_3u32(hash32_ptr(skb),
					skb_get_hash(skb),
					skb_get_hash_net(nft_net(pkt), skb),
					skb->skb_iif,
					&trace_key);
}
+2 −1
Original line number Diff line number Diff line
@@ -51,7 +51,8 @@ static void nft_symhash_eval(const struct nft_expr *expr,
	struct sk_buff *skb = pkt->skb;
	u32 h;

	h = reciprocal_scale(__skb_get_hash_symmetric(skb), priv->modulus);
	h = reciprocal_scale(__skb_get_hash_symmetric_net(nft_net(pkt), skb),
			     priv->modulus);

	regs->data[priv->dreg] = h + priv->offset;
}