git: 84f790e5b6cc - main - ip_encap: Recompute flowid for packets received over tunnel
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Tue, 13 Oct 2026 21:01:26 UTC
The branch main has been updated by pouria:
URL: https://cgit.FreeBSD.org/src/commit/?id=84f790e5b6ccca9d7253834b7dcac5f4432b2917
commit 84f790e5b6ccca9d7253834b7dcac5f4432b2917
Author: Pouria Mousavizadeh Tehrani <pouria@FreeBSD.org>
AuthorDate: 2026-10-09 11:08:44 +0000
Commit: Pouria Mousavizadeh Tehrani <pouria@FreeBSD.org>
CommitDate: 2026-10-13 20:59:03 +0000
ip_encap: Recompute flowid for packets received over tunnel
Packets decapsulated by a tunnel interface carry the NIC's flowid
computed over the outer tunnel tuple, which is the same for every
flow a peer carries. Therefore mpath nhop selection places all
traffic on one path.
Add encap_set_flowid() to ip_encap.c, which rehashes a decapsulated
IP packet on its inner addresses.
The feature is off by default and is enabled with the per-vnet
net.route.hash_inbound sysctl.
Reviewed by: gallatin
Differential Revision: https://reviews.freebsd.org/D60552
---
sys/dev/wg/if_wg.c | 3 +++
sys/net/if_geneve.c | 3 +++
sys/net/if_gif.c | 2 ++
sys/net/if_gre.c | 2 ++
sys/net/if_ovpn.c | 3 +++
sys/netinet/ip_encap.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++
sys/netinet/ip_encap.h | 7 +++++++
7 files changed, 72 insertions(+)
diff --git a/sys/dev/wg/if_wg.c b/sys/dev/wg/if_wg.c
index ffae47938e0a..5877c1966512 100644
--- a/sys/dev/wg/if_wg.c
+++ b/sys/dev/wg/if_wg.c
@@ -43,6 +43,7 @@
#include <netinet6/in6_var.h>
#include <netinet/ip.h>
#include <netinet/ip6.h>
+#include <netinet/ip_encap.h>
#include <netinet/ip_icmp.h>
#include <netinet/icmp6.h>
#include <netinet/udp_var.h>
@@ -1833,6 +1834,8 @@ wg_deliver_in(struct wg_peer *peer)
CURVNET_SET(if_getvnet(ifp));
M_SETFIB(m, if_getfib(ifp));
+ if (V_encap_hash_inbound)
+ encap_set_flowid(m, af);
#ifdef DEV_NETMAP
if ((if_getcapenable(ifp) & IFCAP_NETMAP) != 0)
wg_deliver_netmap(ifp, m, af);
diff --git a/sys/net/if_geneve.c b/sys/net/if_geneve.c
index a8947bf4bd52..6413506518ef 100644
--- a/sys/net/if_geneve.c
+++ b/sys/net/if_geneve.c
@@ -68,6 +68,7 @@
#include <netinet/in_var.h>
#include <netinet/in_pcb.h>
#include <netinet/ip.h>
+#include <netinet/ip_encap.h>
#include <netinet/ip_var.h>
#include <netinet/ip6.h>
#include <netinet6/ip6_var.h>
@@ -3063,6 +3064,8 @@ geneve_udp_input(struct mbuf *m, int offset, struct inpcb *inpcb,
if (proto == GENEVE_PROTO_ETHER)
(*ifp->if_input)(ifp, m);
else {
+ if (V_encap_hash_inbound)
+ encap_set_flowid(m, af);
BPF_MTAP2(ifp, &af, sizeof(af), m);
netisr_dispatch_src(info.isr, (uintptr_t)xgnvso, m);
}
diff --git a/sys/net/if_gif.c b/sys/net/if_gif.c
index 3b5a641af0c6..c12c0de98864 100644
--- a/sys/net/if_gif.c
+++ b/sys/net/if_gif.c
@@ -727,6 +727,8 @@ gif_input(struct mbuf *m, struct ifnet *ifp, int proto, uint8_t ecn)
if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
if_inc_counter(ifp, IFCOUNTER_IBYTES, m->m_pkthdr.len);
M_SETFIB(m, ifp->if_fib);
+ if (V_encap_hash_inbound)
+ encap_set_flowid(m, af);
netisr_dispatch(isr, m);
return;
drop:
diff --git a/sys/net/if_gre.c b/sys/net/if_gre.c
index c390e552886a..f29a98c1f365 100644
--- a/sys/net/if_gre.c
+++ b/sys/net/if_gre.c
@@ -825,6 +825,8 @@ gre_input(struct mbuf *m, int off, int proto, void *arg)
m_clrprotoflags(m);
m->m_pkthdr.rcvif = ifp;
M_SETFIB(m, ifp->if_fib);
+ if (V_encap_hash_inbound)
+ encap_set_flowid(m, af);
#ifdef MAC
mac_ifnet_create_mbuf(ifp, m);
#endif
diff --git a/sys/net/if_ovpn.c b/sys/net/if_ovpn.c
index 385037268230..4c100037b8d9 100644
--- a/sys/net/if_ovpn.c
+++ b/sys/net/if_ovpn.c
@@ -67,6 +67,7 @@
#include <netinet/in_fib.h>
#include <netinet/ip.h>
#include <netinet/ip6.h>
+#include <netinet/ip_encap.h>
#include <netinet/ip_var.h>
#include <netinet/udp.h>
#include <netinet/udp_var.h>
@@ -1781,6 +1782,8 @@ skip_float:
*/
af = ovpn_get_af(m);
if (af != 0) {
+ if (V_encap_hash_inbound)
+ encap_set_flowid(m, af);
BPF_MTAP2(sc->ifp, &af, sizeof(af), m);
if (V_async_netisr_queue)
netisr_queue(af == AF_INET ? NETISR_IP : NETISR_IPV6, m);
diff --git a/sys/netinet/ip_encap.c b/sys/netinet/ip_encap.c
index d3ca0b19f2f5..b23813620dd4 100644
--- a/sys/netinet/ip_encap.c
+++ b/sys/netinet/ip_encap.c
@@ -71,21 +71,33 @@
#include <sys/mbuf.h>
#include <sys/errno.h>
#include <sys/socket.h>
+#include <sys/sysctl.h>
#include <net/if.h>
#include <net/if_var.h>
+#include <net/vnet.h>
#include <netinet/in.h>
+#include <netinet/ip.h>
#include <netinet/ip_var.h>
#include <netinet/ip_encap.h>
+#include <netinet/in_rss.h>
#ifdef INET6
+#include <netinet/ip6.h>
#include <netinet6/ip6_var.h>
+#include <netinet6/in6_rss.h>
#endif
static MALLOC_DEFINE(M_NETADDR, "encap_export_host",
"Export host address structure");
+SYSCTL_DECL(_net_route);
+VNET_DEFINE(bool, encap_hash_inbound) = false;
+SYSCTL_BOOL(_net_route, OID_AUTO, hash_inbound, CTLFLAG_RW | CTLFLAG_VNET,
+ &VNET_NAME(encap_hash_inbound), false,
+ "Compute flowid for packets received over tunnel interfaces");
+
struct encaptab {
CK_LIST_ENTRY(encaptab) chain;
int proto;
@@ -410,3 +422,43 @@ encap6_input(struct mbuf **mp, int *offp, int proto)
return (IPPROTO_DONE);
}
#endif /* INET6 */
+
+/*
+ * Set the flowid of a decapsulated IP packet from its inner addresses.
+ *
+ * flowid of an incoming packet computed over the outer tunnel tuple,
+ * which is the same for every flow a peer. Hashing the inner addresses
+ * instead to make the mpath (and RSS, if enabled) work properly.
+ *
+ * Callers must check the V_encap_hash_inbound sysctl before calling.
+ */
+bool
+encap_set_flowid(struct mbuf *m, int af)
+{
+ uint32_t rss_hash, rss_type;
+
+ M_ASSERTPKTHDR(m);
+
+ switch (af) {
+#ifdef INET
+ case AF_INET: {
+ if (rss_mbuf_software_hash_v4(m, 0, &rss_hash, &rss_type) != 0)
+ return (false);
+ break;
+ }
+#endif
+#ifdef INET6
+ case AF_INET6: {
+ if (rss_mbuf_software_hash_v6(m, 0, &rss_hash, &rss_type) != 0)
+ return (false);
+ break;
+ }
+#endif
+ default:
+ return (false);
+ }
+
+ m->m_pkthdr.flowid = rss_hash;
+ M_HASHTYPE_SET(m, rss_type);
+ return (true);
+}
diff --git a/sys/netinet/ip_encap.h b/sys/netinet/ip_encap.h
index 1c2488cbfab7..e174b9ac8299 100644
--- a/sys/netinet/ip_encap.h
+++ b/sys/netinet/ip_encap.h
@@ -37,6 +37,8 @@
#ifdef _KERNEL
+#include <net/vnet.h>
+
int encap4_input(struct mbuf **, int *, int);
int encap6_input(struct mbuf **, int *, int);
@@ -76,6 +78,11 @@ int ip_encap_unregister_srcaddr(const struct srcaddrtab *);
int ip6_encap_unregister_srcaddr(const struct srcaddrtab *);
int ip_encap_detach(const struct encaptab *);
int ip6_encap_detach(const struct encaptab *);
+
+VNET_DECLARE(bool, encap_hash_inbound);
+#define V_encap_hash_inbound VNET(encap_hash_inbound)
+
+bool encap_set_flowid(struct mbuf *, int);
#endif
#endif /*_NETINET_IP_ENCAP_H_*/