Index: sys/net/if.c
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/net/if.c,v
diff -u -p -u -p -r1.726 if.c
--- sys/net/if.c	3 Feb 2025 08:58:52 -0000	1.726
+++ sys/net/if.c	27 Feb 2025 00:34:43 -0000
@@ -177,6 +177,9 @@ void	ifa_print_all(void);
 
 void	if_qstart_compat(struct ifqueue *);
 
+struct softnet *
+	net_sn(unsigned int);
+
 /*
  * interface index map
  *
@@ -241,19 +244,18 @@ struct rwlock if_tmplist_lock = RWLOCK_I
 struct mutex if_hooks_mtx = MUTEX_INITIALIZER(IPL_NONE);
 void	if_hooks_run(struct task_list *);
 
-int	ifq_congestion;
-
-int		 netisr;
+int		ifq_congestion;
+int		netisr;
 
 struct softnet {
 	char		 sn_name[16];
 	struct taskq	*sn_taskq;
-};
-
-#define	NET_TASKQ	4
+	struct netstack	 sn_netstack;
+} __aligned(64);
+#define NET_TASKQ	4
 struct softnet	softnets[NET_TASKQ];
 
-struct task if_input_task_locked = TASK_INITIALIZER(if_netisr, NULL);
+struct task	if_input_task_locked = TASK_INITIALIZER(if_netisr, NULL);
 
 /*
  * Serialize socket operations to ensure no new sleeping points
@@ -778,7 +780,8 @@ if_input(struct ifnet *ifp, struct mbuf_
 }
 
 int
-if_input_local(struct ifnet *ifp, struct mbuf *m, sa_family_t af)
+if_input_local(struct ifnet *ifp, struct mbuf *m, sa_family_t af,
+    struct netstack *ns)
 {
 	int keepflags, keepcksum;
 	uint16_t keepmss;
@@ -848,16 +851,16 @@ if_input_local(struct ifnet *ifp, struct
 	case AF_INET:
 		if (ISSET(keepcksum, M_IPV4_CSUM_OUT))
 			m->m_pkthdr.csum_flags |= M_IPV4_CSUM_IN_OK;
-		ipv4_input(ifp, m);
+		ipv4_input(ifp, m, ns);
 		break;
 #ifdef INET6
 	case AF_INET6:
-		ipv6_input(ifp, m);
+		ipv6_input(ifp, m, ns);
 		break;
 #endif /* INET6 */
 #ifdef MPLS
 	case AF_MPLS:
-		mpls_input(ifp, m);
+		mpls_input(ifp, m, ns);
 		break;
 #endif /* MPLS */
 	default:
@@ -979,9 +982,10 @@ if_output_local(struct ifnet *ifp, struc
 }
 
 void
-if_input_process(struct ifnet *ifp, struct mbuf_list *ml)
+if_input_process(struct ifnet *ifp, struct mbuf_list *ml, unsigned int idx)
 {
 	struct mbuf *m;
+	struct softnet *sn;
 
 	if (ml_empty(ml))
 		return;
@@ -996,14 +1000,16 @@ if_input_process(struct ifnet *ifp, stru
 	 * read only or MP safe.  Usually they hold the exclusive net lock.
 	 */
 
+	sn = net_sn(idx);
+
 	NET_LOCK_SHARED();
 	while ((m = ml_dequeue(ml)) != NULL)
-		(*ifp->if_input)(ifp, m);
+		(*ifp->if_input)(ifp, m, &sn->sn_netstack);
 	NET_UNLOCK_SHARED();
 }
 
 void
-if_vinput(struct ifnet *ifp, struct mbuf *m)
+if_vinput(struct ifnet *ifp, struct mbuf *m, struct netstack *ns)
 {
 #if NBPFILTER > 0
 	caddr_t if_bpf;
@@ -1030,7 +1036,7 @@ if_vinput(struct ifnet *ifp, struct mbuf
 #endif
 
 	if (__predict_true(!ISSET(ifp->if_xflags, IFXF_MONITOR)))
-		(*ifp->if_input)(ifp, m);
+		(*ifp->if_input)(ifp, m, ns);
 	else
 		m_freem(m);
 }
@@ -1677,9 +1683,9 @@ p2p_bpf_mtap(caddr_t if_bpf, const struc
 }
 
 void
-p2p_input(struct ifnet *ifp, struct mbuf *m)
+p2p_input(struct ifnet *ifp, struct mbuf *m, struct netstack *ns)
 {
-	void (*input)(struct ifnet *, struct mbuf *);
+	void (*input)(struct ifnet *, struct mbuf *, struct netstack *);
 
 	switch (m->m_pkthdr.ph_family) {
 	case AF_INET:
@@ -1700,7 +1706,7 @@ p2p_input(struct ifnet *ifp, struct mbuf
 		return;
 	}
 
-	(*input)(ifp, m);
+	(*input)(ifp, m, ns);
 }
 
 /*
@@ -3672,18 +3678,21 @@ unhandled_af(int af)
 	panic("unhandled af %d", af);
 }
 
-struct taskq *
-net_tq(unsigned int ifindex)
+struct softnet *
+net_sn(unsigned int ifindex)
 {
-	struct softnet *sn;
 	static int nettaskqs;
 
 	if (nettaskqs == 0)
 		nettaskqs = min(NET_TASKQ, ncpus);
 
-	sn = &softnets[ifindex % nettaskqs];
+	return (&softnets[ifindex % nettaskqs]);
+}
 
-	return (sn->sn_taskq);
+struct taskq *
+net_tq(unsigned int ifindex)
+{
+	return (net_sn(ifindex)->sn_taskq);
 }
 
 void
Index: sys/net/if.h
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/net/if.h,v
diff -u -p -u -p -r1.217 if.h
--- sys/net/if.h	9 Jun 2024 16:25:28 -0000	1.217
+++ sys/net/if.h	27 Feb 2025 00:34:43 -0000
@@ -560,7 +560,8 @@ void	if_congestion(void);
 int	if_congested(void);
 __dead void	unhandled_af(int);
 int	if_setlladdr(struct ifnet *, const uint8_t *);
-struct taskq * net_tq(unsigned int);
+struct taskq *
+	net_tq(unsigned int);
 void	net_tq_barriers(const char *);
 
 #endif /* _KERNEL */
Index: sys/net/if_aggr.c
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/net/if_aggr.c,v
diff -u -p -u -p -r1.47 if_aggr.c
--- sys/net/if_aggr.c	18 Dec 2024 01:56:05 -0000	1.47
+++ sys/net/if_aggr.c	27 Feb 2025 00:34:43 -0000
@@ -352,7 +352,7 @@ struct aggr_port {
 	uint32_t		 p_mtu;
 
 	int (*p_ioctl)(struct ifnet *, u_long, caddr_t);
-	void (*p_input)(struct ifnet *, struct mbuf *);
+	void (*p_input)(struct ifnet *, struct mbuf *, struct netstack *);
 	int (*p_output)(struct ifnet *, struct mbuf *, struct sockaddr *,
 	    struct rtentry *);
 
@@ -745,7 +745,7 @@ aggr_start(struct ifqueue *ifq)
 }
 
 static inline struct mbuf *
-aggr_input_control(struct aggr_port *p, struct mbuf *m)
+aggr_input_control(struct aggr_port *p, struct mbuf *m, struct netstack *ns)
 {
 	struct ether_header *eh;
 	int hlen = sizeof(*eh);
@@ -808,7 +808,7 @@ aggr_input_control(struct aggr_port *p, 
 		case 0x0: /* Nearest Customer Bridge */
 		case 0x3: /* Non-TPMR Bridge */
 		case 0xe: /* Nearest Bridge */
-			p->p_input(p->p_ifp0, m);
+			p->p_input(p->p_ifp0, m, ns);
 			return (NULL);
 		default:
 			break;
@@ -823,7 +823,7 @@ drop:
 }
 
 static void
-aggr_input(struct ifnet *ifp0, struct mbuf *m)
+aggr_input(struct ifnet *ifp0, struct mbuf *m, struct netstack *ns)
 {
 	struct arpcom *ac0 = (struct arpcom *)ifp0;
 	struct aggr_port *p = ac0->ac_trunkport;
@@ -833,7 +833,7 @@ aggr_input(struct ifnet *ifp0, struct mb
 	if (!ISSET(ifp->if_flags, IFF_RUNNING))
 		goto drop;
 
-	m = aggr_input_control(p, m);
+	m = aggr_input_control(p, m, ns);
 	if (m == NULL)
 		return;
 
@@ -843,7 +843,7 @@ aggr_input(struct ifnet *ifp0, struct mb
 	if (!ISSET(m->m_pkthdr.csum_flags, M_FLOWID))
 		m->m_pkthdr.ph_flowid = ifp0->if_index ^ sc->sc_mix;
 
-	if_vinput(ifp, m);
+	if_vinput(ifp, m, ns);
 
 	return;
 
Index: sys/net/if_bpe.c
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/net/if_bpe.c,v
diff -u -p -u -p -r1.22 if_bpe.c
--- sys/net/if_bpe.c	23 Dec 2023 10:52:54 -0000	1.22
+++ sys/net/if_bpe.c	27 Feb 2025 00:34:43 -0000
@@ -729,7 +729,7 @@ bpe_find(struct ifnet *ifp0, uint32_t is
 }
 
 void
-bpe_input(struct ifnet *ifp0, struct mbuf *m)
+bpe_input(struct ifnet *ifp0, struct mbuf *m, struct netstack *ns)
 {
 	struct bpe_softc *sc;
 	struct ifnet *ifp;
@@ -809,7 +809,7 @@ bpe_input(struct ifnet *ifp0, struct mbu
 	pf_pkt_addr_changed(m);
 #endif
 
-	if_vinput(ifp, m);
+	if_vinput(ifp, m, ns);
 	return;
 
 drop:
Index: sys/net/if_bpe.h
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/net/if_bpe.h,v
diff -u -p -u -p -r1.1 if_bpe.h
--- sys/net/if_bpe.h	20 Dec 2018 23:00:55 -0000	1.1
+++ sys/net/if_bpe.h	27 Feb 2025 00:34:43 -0000
@@ -20,7 +20,7 @@
 #define _NET_IF_BPE_H
 
 #ifdef _KERNEL
-void	bpe_input(struct ifnet *, struct mbuf *);
+void	bpe_input(struct ifnet *, struct mbuf *, struct netstack *);
 #endif
 
 #endif /* _NET_IF_GRE_H_ */
Index: sys/net/if_bridge.c
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/net/if_bridge.c,v
diff -u -p -u -p -r1.373 if_bridge.c
--- sys/net/if_bridge.c	14 Feb 2025 13:14:13 -0000	1.373
+++ sys/net/if_bridge.c	27 Feb 2025 00:34:43 -0000
@@ -111,7 +111,8 @@ void	bridge_spandetach(void *);
 int	bridge_ifremove(struct bridge_iflist *);
 void	bridge_spanremove(struct bridge_iflist *);
 struct mbuf *
-	bridge_input(struct ifnet *, struct mbuf *, uint64_t, void *);
+	bridge_input(struct ifnet *, struct mbuf *, uint64_t, void *,
+	    struct netstack *);
 void	bridge_process(struct ifnet *, struct mbuf *);
 void	bridgeintr_frame(struct ifnet *, struct ifnet *, struct mbuf *);
 void	bridge_bifgetstp(struct bridge_softc *, struct bridge_iflist *,
@@ -1138,7 +1139,8 @@ bridge_ourether(struct ifnet *ifp, uint8
  * not for us, and schedule an interrupt.
  */
 struct mbuf *
-bridge_input(struct ifnet *ifp, struct mbuf *m, uint64_t dst, void *null)
+bridge_input(struct ifnet *ifp, struct mbuf *m, uint64_t dst, void *null,
+    struct netstack *ns)
 {
 	KASSERT(m->m_flags & M_PKTHDR);
 
@@ -1597,10 +1599,10 @@ bridge_ipsec(struct ifnet *ifp, struct e
 			}
 
 			prot = (*(tdb->tdb_xform->xf_input))(&m, tdb, hlen,
-			    off);
+			    off, NULL);
 			tdb_unref(tdb);
 			if (prot != IPPROTO_DONE)
-				ip_deliver(&m, &hlen, prot, af, 0);
+				ip_deliver(&m, &hlen, prot, af, 0, NULL);
 			return (1);
 		} else {
 			tdb_unref(tdb);
@@ -1746,7 +1748,7 @@ bridge_ip(struct ifnet *brifp, int dir, 
 			m_resethdr(m);
 			m->m_pkthdr.ph_ifidx = ifp->if_index;
 			m->m_pkthdr.ph_rtableid = ifp->if_rdomain;
-			ipv4_input(ifp, m);
+			ipv4_input(ifp, m, NULL);
 			return (NULL);
 		}
 #endif /* NPF > 0 */
@@ -1782,7 +1784,7 @@ bridge_ip(struct ifnet *brifp, int dir, 
 			m_resethdr(m);
 			m->m_pkthdr.ph_ifidx = ifp->if_index;
 			m->m_pkthdr.ph_rtableid = ifp->if_rdomain;
-			ipv6_input(ifp, m);
+			ipv6_input(ifp, m, NULL);
 			return (NULL);
 		}
 #endif /* NPF > 0 */
Index: sys/net/if_etherip.c
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/net/if_etherip.c,v
diff -u -p -u -p -r1.56 if_etherip.c
--- sys/net/if_etherip.c	20 Aug 2024 07:47:25 -0000	1.56
+++ sys/net/if_etherip.c	27 Feb 2025 00:34:43 -0000
@@ -121,7 +121,8 @@ int etherip_del_tunnel(struct etherip_so
 int etherip_up(struct etherip_softc *);
 int etherip_down(struct etherip_softc *);
 struct etherip_softc *etherip_find(const struct etherip_tunnel *);
-int etherip_input(struct etherip_tunnel *, struct mbuf *, uint8_t, int);
+int etherip_input(struct etherip_tunnel *, struct mbuf *, uint8_t, int,
+    struct netstack *);
 
 struct if_clone	etherip_cloner = IF_CLONE_INITIALIZER("etherip",
     etherip_clone_create, etherip_clone_destroy);
@@ -589,7 +590,8 @@ ip_etherip_output(struct ifnet *ifp, str
 }
 
 int
-ip_etherip_input(struct mbuf **mp, int *offp, int type, int af)
+ip_etherip_input(struct mbuf **mp, int *offp, int type, int af,
+    struct netstack *ns)
 {
 	struct mbuf *m = *mp;
 	struct etherip_tunnel key;
@@ -601,7 +603,7 @@ ip_etherip_input(struct mbuf **mp, int *
 	key.t_src4 = ip->ip_dst;
 	key.t_dst4 = ip->ip_src;
 
-	return (etherip_input(&key, m, ip->ip_tos, *offp));
+	return (etherip_input(&key, m, ip->ip_tos, *offp, ns));
 }
 
 struct etherip_softc *
@@ -626,7 +628,7 @@ etherip_find(const struct etherip_tunnel
 
 int
 etherip_input(struct etherip_tunnel *key, struct mbuf *m, uint8_t tos,
-    int hlen)
+    int hlen, struct netstack *ns)
 {
 	struct etherip_softc *sc;
 	struct ifnet *ifp;
@@ -693,7 +695,7 @@ etherip_input(struct etherip_tunnel *key
 	pf_pkt_addr_changed(m);
 #endif
 
-	if_vinput(ifp, m);
+	if_vinput(ifp, m, ns);
 	return IPPROTO_DONE;
 
 drop:
@@ -768,7 +770,8 @@ ip6_etherip_output(struct ifnet *ifp, st
 }
 
 int
-ip6_etherip_input(struct mbuf **mp, int *offp, int proto, int af)
+ip6_etherip_input(struct mbuf **mp, int *offp, int proto, int af,
+    struct netstack *ns)
 {
 	struct mbuf *m = *mp;
 	struct etherip_tunnel key;
@@ -783,7 +786,7 @@ ip6_etherip_input(struct mbuf **mp, int 
 
 	flow = bemtoh32(&ip6->ip6_flow);
 
-	return (etherip_input(&key, m, flow >> 20, *offp));
+	return (etherip_input(&key, m, flow >> 20, *offp, ns));
 }
 #endif /* INET6 */
 
Index: sys/net/if_etherip.h
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/net/if_etherip.h,v
diff -u -p -u -p -r1.10 if_etherip.h
--- sys/net/if_etherip.h	20 Nov 2017 14:21:28 -0000	1.10
+++ sys/net/if_etherip.h	27 Feb 2025 00:34:43 -0000
@@ -19,11 +19,11 @@
 
 int etherip_sysctl(int *, uint, void *, size_t *, void *, size_t);
 int ip_etherip_output(struct ifnet *, struct mbuf *);
-int ip_etherip_input(struct mbuf **, int *, int, int);
+int ip_etherip_input(struct mbuf **, int *, int, int, struct netstack *);
 
 #ifdef INET6
 int ip6_etherip_output(struct ifnet *, struct mbuf *);
-int ip6_etherip_input(struct mbuf **, int *, int, int);
+int ip6_etherip_input(struct mbuf **, int *, int, int, struct netstack *);
 #endif /* INET6 */
 
 #endif /* _NET_IF_ETHERIP_H_ */
Index: sys/net/if_ethersubr.c
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/net/if_ethersubr.c,v
diff -u -p -u -p -r1.296 if_ethersubr.c
--- sys/net/if_ethersubr.c	15 Jan 2025 06:15:44 -0000	1.296
+++ sys/net/if_ethersubr.c	27 Feb 2025 00:34:43 -0000
@@ -265,7 +265,7 @@ ether_resolve(struct ifnet *ifp, struct 
 			/* XXX Should we input an unencrypted IPsec packet? */
 			mcopy = m_copym(m, 0, M_COPYALL, M_NOWAIT);
 			if (mcopy != NULL)
-				if_input_local(ifp, mcopy, af);
+				if_input_local(ifp, mcopy, af, NULL);
 		}
 		break;
 #ifdef INET6
@@ -399,10 +399,10 @@ ether_output(struct ifnet *ifp, struct m
  * to ether_input().
  */
 void
-ether_input(struct ifnet *ifp, struct mbuf *m)
+ether_input(struct ifnet *ifp, struct mbuf *m, struct netstack *ns)
 {
 	struct ether_header *eh;
-	void (*input)(struct ifnet *, struct mbuf *);
+	void (*input)(struct ifnet *, struct mbuf *, struct netstack *);
 	u_int16_t etype;
 	struct arpcom *ac;
 	const struct ether_brport *eb;
@@ -429,7 +429,7 @@ ether_input(struct ifnet *ifp, struct mb
 	if (ISSET(m->m_flags, M_VLANTAG) ||
 	    etype == ETHERTYPE_VLAN || etype == ETHERTYPE_QINQ) {
 #if NVLAN > 0
-		m = vlan_input(ifp, m, &sdelim);
+		m = vlan_input(ifp, m, &sdelim, ns);
 		if (m == NULL)
 			return;
 #else
@@ -455,7 +455,7 @@ ether_input(struct ifnet *ifp, struct mb
 		eb->eb_port_take(eb->eb_port);
 	smr_read_leave();
 	if (eb != NULL) {
-		m = (*eb->eb_input)(ifp, m, dst, eb->eb_port);
+		m = (*eb->eb_input)(ifp, m, dst, eb->eb_port, ns);
 		eb->eb_port_rele(eb->eb_port);
 		if (m == NULL) {
 			return;
@@ -487,7 +487,7 @@ ether_input(struct ifnet *ifp, struct mb
 		 */
 		if (ifp->if_type != IFT_CARP &&
 		    !SRPL_EMPTY_LOCKED(&ifp->if_carp)) {
-			m = carp_input(ifp, m, dst);
+			m = carp_input(ifp, m, dst, ns);
 			if (m == NULL)
 				return;
 
@@ -559,7 +559,7 @@ ether_input(struct ifnet *ifp, struct mb
 			struct pipex_session *session;
 
 			if ((session = pipex_pppoe_lookup_session(m)) != NULL) {
-				pipex_pppoe_input(m, session);
+				pipex_pppoe_input(m, session, ns);
 				pipex_rele_session(session);
 				return;
 			}
@@ -569,7 +569,7 @@ ether_input(struct ifnet *ifp, struct mb
 			if (mq_enqueue(&pppoediscinq, m) == 0)
 				schednetisr(NETISR_PPPOE);
 		} else {
-			m = pppoe_vinput(ifp, m);
+			m = pppoe_vinput(ifp, m, ns);
 			if (m != NULL && mq_enqueue(&pppoeinq, m) == 0)
 				schednetisr(NETISR_PPPOE);
 		}
@@ -583,7 +583,7 @@ ether_input(struct ifnet *ifp, struct mb
 #endif
 #if NBPE > 0
 	case ETHERTYPE_PBB:
-		bpe_input(ifp, m);
+		bpe_input(ifp, m, ns);
 		return;
 #endif
 	default:
@@ -594,7 +594,7 @@ ether_input(struct ifnet *ifp, struct mb
 	}
 
 	m_adj(m, sizeof(*eh));
-	(*input)(ifp, m);
+	(*input)(ifp, m, ns);
 	return;
 dropanyway:
 	m_freem(m);
Index: sys/net/if_gif.c
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/net/if_gif.c,v
diff -u -p -u -p -r1.138 if_gif.c
--- sys/net/if_gif.c	13 May 2024 01:15:53 -0000	1.138
+++ sys/net/if_gif.c	27 Feb 2025 00:34:43 -0000
@@ -128,7 +128,7 @@ int	gif_set_tunnel(struct gif_softc *, s
 int	gif_get_tunnel(struct gif_softc *, struct if_laddrreq *);
 int	gif_del_tunnel(struct gif_softc *);
 int	gif_input(struct gif_tunnel *, struct mbuf **, int *, int, int,
-	    uint8_t);
+	    uint8_t, struct netstack *);
 
 /*
  * gif global variable definitions
@@ -715,7 +715,8 @@ gif_del_tunnel(struct gif_softc *sc)
 }
 
 int
-in_gif_input(struct mbuf **mp, int *offp, int proto, int af)
+in_gif_input(struct mbuf **mp, int *offp, int proto, int af,
+    struct netstack *ns)
 {
 	struct mbuf *m = *mp;
 	struct gif_tunnel key;
@@ -728,16 +729,17 @@ in_gif_input(struct mbuf **mp, int *offp
 	key.t_src4 = ip->ip_dst;
 	key.t_dst4 = ip->ip_src;
 
-	rv = gif_input(&key, mp, offp, proto, af, ip->ip_tos);
+	rv = gif_input(&key, mp, offp, proto, af, ip->ip_tos, ns);
 	if (rv == -1)
-		rv = ipip_input(mp, offp, proto, af);
+		rv = ipip_input(mp, offp, proto, af, ns);
 
 	return (rv);
 }
 
 #ifdef INET6
 int
-in6_gif_input(struct mbuf **mp, int *offp, int proto, int af)
+in6_gif_input(struct mbuf **mp, int *offp, int proto, int af,
+    struct netstack *ns)
 {
 	struct mbuf *m = *mp;
 	struct gif_tunnel key;
@@ -753,9 +755,9 @@ in6_gif_input(struct mbuf **mp, int *off
 
 	flow = ntohl(ip6->ip6_flow);
 
-	rv = gif_input(&key, mp, offp, proto, af, flow >> 20);
+	rv = gif_input(&key, mp, offp, proto, af, flow >> 20, ns);
 	if (rv == -1)
-		rv = ipip_input(mp, offp, proto, af);
+		rv = ipip_input(mp, offp, proto, af, ns);
 
 	return (rv);
 }
@@ -783,7 +785,7 @@ gif_find(const struct gif_tunnel *key)
 
 int
 gif_input(struct gif_tunnel *key, struct mbuf **mp, int *offp, int proto,
-    int af, uint8_t otos)
+    int af, uint8_t otos, struct netstack *ns)
 {
 	struct mbuf *m = *mp;
 	struct gif_softc *sc;
@@ -889,7 +891,7 @@ gif_input(struct gif_tunnel *key, struct
 	}
 
 	*mp = NULL;
-	if_vinput(ifp, m);
+	if_vinput(ifp, m, ns);
 	return (IPPROTO_DONE);
 
  drop:
Index: sys/net/if_gif.h
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/net/if_gif.h,v
diff -u -p -u -p -r1.18 if_gif.h
--- sys/net/if_gif.h	10 Feb 2018 08:12:01 -0000	1.18
+++ sys/net/if_gif.h	27 Feb 2025 00:34:43 -0000
@@ -37,7 +37,7 @@
 #ifndef _NET_IF_GIF_H_
 #define _NET_IF_GIF_H_
 
-int in_gif_input(struct mbuf **, int *, int, int);
-int in6_gif_input(struct mbuf **, int *, int, int);
+int in_gif_input(struct mbuf **, int *, int, int, struct netstack *);
+int in6_gif_input(struct mbuf **, int *, int, int, struct netstack *);
 
 #endif /* _NET_IF_GIF_H_ */
Index: sys/net/if_gre.c
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/net/if_gre.c,v
diff -u -p -u -p -r1.183 if_gre.c
--- sys/net/if_gre.c	21 Feb 2025 06:20:12 -0000	1.183
+++ sys/net/if_gre.c	27 Feb 2025 00:34:43 -0000
@@ -295,7 +295,7 @@ static int	gre_down(struct gre_softc *);
 static void	gre_link_state(struct ifnet *, unsigned int);
 
 static int	gre_input_key(struct mbuf **, int *, int, int, uint8_t,
-		    struct gre_tunnel *);
+		    struct gre_tunnel *, struct netstack *);
 
 static struct mbuf *
 		gre_ipv4_patch(const struct gre_tunnel *, struct mbuf *,
@@ -389,7 +389,7 @@ static int	egre_up(struct egre_softc *);
 static int	egre_down(struct egre_softc *);
 
 static int	egre_input(const struct gre_tunnel *, struct mbuf *, int,
-		    uint8_t);
+		    uint8_t, struct netstack *);
 struct if_clone egre_cloner =
     IF_CLONE_INITIALIZER("egre", egre_clone_create, egre_clone_destroy);
 
@@ -450,7 +450,7 @@ static void	nvgre_link_change(void *);
 static void	nvgre_detach(void *);
 
 static int	nvgre_input(const struct gre_tunnel *, struct mbuf *, int,
-		    uint8_t);
+		    uint8_t, struct netstack *);
 static void	nvgre_send(void *);
 
 static int	nvgre_add_addr(struct nvgre_softc *, const struct ifbareq *);
@@ -527,7 +527,7 @@ static struct mbuf *
 
 static struct mbuf *
 		eoip_input(struct gre_tunnel *, struct mbuf *,
-		    const struct gre_header *, uint8_t, int);
+		    const struct gre_header *, uint8_t, int, struct netstack *);
 struct if_clone eoip_cloner =
     IF_CLONE_INITIALIZER("eoip", eoip_clone_create, eoip_clone_destroy);
 
@@ -890,7 +890,7 @@ eoip_clone_destroy(struct ifnet *ifp)
 }
 
 int
-gre_input(struct mbuf **mp, int *offp, int type, int af)
+gre_input(struct mbuf **mp, int *offp, int type, int af, struct netstack *ns)
 {
 	struct mbuf *m = *mp;
 	struct gre_tunnel key;
@@ -904,15 +904,15 @@ gre_input(struct mbuf **mp, int *offp, i
 	key.t_src4 = ip->ip_dst;
 	key.t_dst4 = ip->ip_src;
 
-	if (gre_input_key(mp, offp, type, af, ip->ip_tos, &key) == -1)
-		return (rip_input(mp, offp, type, af));
+	if (gre_input_key(mp, offp, type, af, ip->ip_tos, &key, ns) == -1)
+		return (rip_input(mp, offp, type, af, ns));
 
 	return (IPPROTO_DONE);
 }
 
 #ifdef INET6
 int
-gre_input6(struct mbuf **mp, int *offp, int type, int af)
+gre_input6(struct mbuf **mp, int *offp, int type, int af, struct netstack *ns)
 {
 	struct mbuf *m = *mp;
 	struct gre_tunnel key;
@@ -929,8 +929,8 @@ gre_input6(struct mbuf **mp, int *offp, 
 
 	flow = bemtoh32(&ip6->ip6_flow);
 
-	if (gre_input_key(mp, offp, type, af, flow >> 20, &key) == -1)
-		return (rip6_input(mp, offp, type, af));
+	if (gre_input_key(mp, offp, type, af, flow >> 20, &key, ns) == -1)
+		return (rip6_input(mp, offp, type, af, ns));
 
 	return (IPPROTO_DONE);
 }
@@ -969,7 +969,7 @@ mgre_find(const struct gre_tunnel *key)
 
 static struct mbuf *
 gre_input_1(struct gre_tunnel *key, struct mbuf *m,
-    const struct gre_header *gh, uint8_t otos, int iphlen)
+    const struct gre_header *gh, uint8_t otos, int iphlen, struct netstack *ns)
 {
 	switch (gh->gre_proto) {
 	case htons(ETHERTYPE_PPP):
@@ -981,7 +981,7 @@ gre_input_1(struct gre_tunnel *key, stru
 			if (session != NULL) {
 				struct mbuf *m0;
 
-				m0 = pipex_pptp_input(m, session);
+				m0 = pipex_pptp_input(m, session, ns);
 				pipex_rele_session(session);
 
 				if (m0 == NULL)
@@ -991,7 +991,7 @@ gre_input_1(struct gre_tunnel *key, stru
 #endif
 		break;
 	case htons(GRE_EOIP):
-		return (eoip_input(key, m, gh, otos, iphlen));
+		return (eoip_input(key, m, gh, otos, iphlen, ns));
 		break;
 	}
 
@@ -1000,7 +1000,7 @@ gre_input_1(struct gre_tunnel *key, stru
 
 static int
 gre_input_key(struct mbuf **mp, int *offp, int type, int af, uint8_t otos,
-    struct gre_tunnel *key)
+    struct gre_tunnel *key, struct netstack *ns)
 {
 	struct mbuf *m = *mp;
 	int iphlen = *offp, hlen, rxprio;
@@ -1036,7 +1036,7 @@ gre_input_key(struct mbuf **mp, int *off
 		break;
 
 	case htons(GRE_VERS_1):
-		m = gre_input_1(key, m, gh, otos, iphlen);
+		m = gre_input_1(key, m, gh, otos, iphlen, ns);
 		if (m == NULL)
 			return (IPPROTO_DONE);
 		/* FALLTHROUGH */
@@ -1067,8 +1067,8 @@ gre_input_key(struct mbuf **mp, int *off
 		key->t_key_mask = GRE_KEY_NONE;
 
 	if (gh->gre_proto == htons(ETHERTYPE_TRANSETHER)) {
-		if (egre_input(key, m, hlen, otos) == -1 &&
-		    nvgre_input(key, m, hlen, otos) == -1)
+		if (egre_input(key, m, hlen, otos, ns) == -1 &&
+		    nvgre_input(key, m, hlen, otos, ns) == -1)
 			goto decline;
 
 		return (IPPROTO_DONE);
@@ -1181,7 +1181,7 @@ gre_input_key(struct mbuf **mp, int *off
 	m->m_flags &= ~(M_MCAST|M_BCAST);
 	m->m_flags |= mcast;
 
-	if_vinput(ifp, m);
+	if_vinput(ifp, m, ns);
 	return (IPPROTO_DONE);
 decline:
 	*mp = m;
@@ -1288,7 +1288,8 @@ gre_mpls_patch(const struct gre_tunnel *
 } while (0)
 
 static int
-egre_input(const struct gre_tunnel *key, struct mbuf *m, int hlen, uint8_t otos)
+egre_input(const struct gre_tunnel *key, struct mbuf *m, int hlen,
+    uint8_t otos, struct netstack *ns)
 {
 	struct egre_softc *sc;
 
@@ -1312,7 +1313,7 @@ egre_input(const struct gre_tunnel *key,
 
 	gre_l2_prio(&sc->sc_tunnel, m, otos);
 
-	if_vinput(&sc->sc_ac.ac_if, m);
+	if_vinput(&sc->sc_ac.ac_if, m, ns);
 
 	return (0);
 }
@@ -1355,7 +1356,7 @@ nvgre_ucast_find(const struct gre_tunnel
 
 static int
 nvgre_input(const struct gre_tunnel *key, struct mbuf *m, int hlen,
-    uint8_t otos)
+    uint8_t otos, struct netstack *ns)
 {
 	struct nvgre_softc *sc;
 	struct ether_header *eh;
@@ -1384,7 +1385,7 @@ nvgre_input(const struct gre_tunnel *key
 
 	gre_l2_prio(&sc->sc_tunnel, m, otos);
 
-	if_vinput(&sc->sc_ac.ac_if, m);
+	if_vinput(&sc->sc_ac.ac_if, m, ns);
 
 	return (0);
 }
@@ -3983,7 +3984,7 @@ eoip_keepalive_recv(struct eoip_softc *s
 
 static struct mbuf *
 eoip_input(struct gre_tunnel *key, struct mbuf *m,
-    const struct gre_header *gh, uint8_t otos, int iphlen)
+    const struct gre_header *gh, uint8_t otos, int iphlen, struct netstack *ns)
 {
 	struct eoip_softc *sc;
 	struct gre_h_key_eoip *eoiph;
@@ -4032,7 +4033,7 @@ eoip_input(struct gre_tunnel *key, struc
 
 	gre_l2_prio(&sc->sc_tunnel, m, otos);
 
-	if_vinput(&sc->sc_ac.ac_if, m);
+	if_vinput(&sc->sc_ac.ac_if, m, ns);
 
 	return (NULL);
 
Index: sys/net/if_gre.h
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/net/if_gre.h,v
diff -u -p -u -p -r1.16 if_gre.h
--- sys/net/if_gre.h	10 Mar 2021 10:21:48 -0000	1.16
+++ sys/net/if_gre.h	27 Feb 2025 00:34:43 -0000
@@ -115,7 +115,7 @@ struct mobip_h {
 
 #ifdef _KERNEL
 int	gre_sysctl(int *, u_int, void *, size_t *, void *, size_t);
-int	gre_input(struct mbuf **, int *, int, int);
-int	gre_input6(struct mbuf **, int *, int, int);
+int	gre_input(struct mbuf **, int *, int, int, struct netstack *);
+int	gre_input6(struct mbuf **, int *, int, int, struct netstack *);
 #endif
 #endif /* _NET_IF_GRE_H_ */
Index: sys/net/if_loop.c
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/net/if_loop.c,v
diff -u -p -u -p -r1.99 if_loop.c
--- sys/net/if_loop.c	3 Jan 2025 21:27:40 -0000	1.99
+++ sys/net/if_loop.c	27 Feb 2025 00:34:43 -0000
@@ -143,7 +143,7 @@
 int	loioctl(struct ifnet *, u_long, caddr_t);
 void	loopattach(int);
 void	lortrequest(struct ifnet *, int, struct rtentry *);
-void	loinput(struct ifnet *, struct mbuf *);
+void	loinput(struct ifnet *, struct mbuf *, struct netstack *);
 int	looutput(struct ifnet *,
 	    struct mbuf *, struct sockaddr *, struct rtentry *);
 int	lo_bpf_mtap(caddr_t, const struct mbuf *, u_int);
@@ -242,14 +242,14 @@ lo_bpf_mtap(caddr_t if_bpf, const struct
 }
 
 void
-loinput(struct ifnet *ifp, struct mbuf *m)
+loinput(struct ifnet *ifp, struct mbuf *m, struct netstack *ns)
 {
 	int error;
 
 	if ((m->m_flags & M_PKTHDR) == 0)
 		panic("%s: no header mbuf", __func__);
 
-	error = if_input_local(ifp, m, m->m_pkthdr.ph_family);
+	error = if_input_local(ifp, m, m->m_pkthdr.ph_family, ns);
 	if (error)
 		counters_inc(ifp->if_counters, ifc_ierrors);
 }
Index: sys/net/if_mpe.c
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/net/if_mpe.c,v
diff -u -p -u -p -r1.105 if_mpe.c
--- sys/net/if_mpe.c	1 Jan 2024 18:47:02 -0000	1.105
+++ sys/net/if_mpe.c	27 Feb 2025 00:34:43 -0000
@@ -545,7 +545,7 @@ mpe_input(struct ifnet *ifp, struct mbuf
 		break;
 	}
 
-	if_vinput(ifp, m);
+	if_vinput(ifp, m, NULL);
 	return;
 drop:
 	m_freem(m);
Index: sys/net/if_mpip.c
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/net/if_mpip.c,v
diff -u -p -u -p -r1.19 if_mpip.c
--- sys/net/if_mpip.c	1 Jan 2024 18:47:02 -0000	1.19
+++ sys/net/if_mpip.c	27 Feb 2025 00:34:43 -0000
@@ -608,7 +608,7 @@ mpip_input(struct mpip_softc *sc, struct
 		break;
 	}
 
-	if_vinput(ifp, m);
+	if_vinput(ifp, m, NULL);
 	return;
 drop:
 	m_freem(m);
Index: sys/net/if_mpw.c
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/net/if_mpw.c,v
diff -u -p -u -p -r1.66 if_mpw.c
--- sys/net/if_mpw.c	13 May 2024 01:15:53 -0000	1.66
+++ sys/net/if_mpw.c	27 Feb 2025 00:34:43 -0000
@@ -614,7 +614,7 @@ mpw_input(struct mpw_softc *sc, struct m
 	/* packet has not been processed by PF yet. */
 	KASSERT(m->m_pkthdr.pf.statekey == NULL);
 
-	if_vinput(ifp, m);
+	if_vinput(ifp, m, NULL);
 	return;
 drop:
 	m_freem(m);
Index: sys/net/if_pfsync.c
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/net/if_pfsync.c,v
diff -u -p -u -p -r1.330 if_pfsync.c
--- sys/net/if_pfsync.c	18 Dec 2024 02:25:30 -0000	1.330
+++ sys/net/if_pfsync.c	27 Feb 2025 00:34:43 -0000
@@ -3318,7 +3318,8 @@ pfsync_in_tdb(struct pfsync_softc *sc,
 }
 
 int
-pfsync_input4(struct mbuf **mp, int *offp, int proto, int af)
+pfsync_input4(struct mbuf **mp, int *offp, int proto, int af,
+    struct netstack *ns)
 {
 	struct mbuf *m = *mp;
 	struct ip *ip;
Index: sys/net/if_pfsync.h
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/net/if_pfsync.h,v
diff -u -p -u -p -r1.63 if_pfsync.h
--- sys/net/if_pfsync.h	12 Oct 2024 23:10:07 -0000	1.63
+++ sys/net/if_pfsync.h	27 Feb 2025 00:34:43 -0000
@@ -308,7 +308,8 @@ enum pfsync_counters {
 #define PFSYNC_S_PFSYNC	0xd2
 #define PFSYNC_S_DEAD	0xde
 
-int			pfsync_input4(struct mbuf **, int *, int, int);
+int			pfsync_input4(struct mbuf **, int *, int, int,
+			    struct netstack *);
 int			pfsync_sysctl(int *, u_int,  void *, size_t *,
 			    void *, size_t);
 
Index: sys/net/if_ppp.c
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/net/if_ppp.c,v
diff -u -p -u -p -r1.118 if_ppp.c
--- sys/net/if_ppp.c	28 Feb 2024 16:08:34 -0000	1.118
+++ sys/net/if_ppp.c	27 Feb 2025 00:34:43 -0000
@@ -1410,7 +1410,7 @@ ppp_inproc(struct ppp_softc *sc, struct 
 		m->m_data += PPP_HDRLEN;
 		m->m_len -= PPP_HDRLEN;
 
-		ipv4_input(ifp, m);
+		ipv4_input(ifp, m, NULL);
 		rv = 1;
 		break;
 #ifdef INET6
@@ -1428,7 +1428,7 @@ ppp_inproc(struct ppp_softc *sc, struct 
 		m->m_data += PPP_HDRLEN;
 		m->m_len -= PPP_HDRLEN;
 
-		ipv6_input(ifp, m);
+		ipv6_input(ifp, m, NULL);
 		rv = 1;
 		break;
 #endif
Index: sys/net/if_pppoe.c
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/net/if_pppoe.c,v
diff -u -p -u -p -r1.85 if_pppoe.c
--- sys/net/if_pppoe.c	15 Jan 2025 06:15:44 -0000	1.85
+++ sys/net/if_pppoe.c	27 Feb 2025 00:34:43 -0000
@@ -727,7 +727,7 @@ pppoe_disc_input(struct mbuf *m)
 }
 
 struct mbuf *
-pppoe_vinput(struct ifnet *ifp0, struct mbuf *m)
+pppoe_vinput(struct ifnet *ifp0, struct mbuf *m, struct netstack *ns)
 {
 	struct pppoe_softc *sc;
 	struct ifnet *ifp;
@@ -816,7 +816,7 @@ pppoe_vinput(struct ifnet *ifp0, struct 
 		sc->sc_sppp.pp_last_activity = now;
 
 	m->m_pkthdr.ph_family = af;
-	if_vinput(ifp, m);
+	if_vinput(ifp, m, ns);
 done:
 	m = NULL;
 put:
Index: sys/net/if_pppoe.h
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/net/if_pppoe.h,v
diff -u -p -u -p -r1.9 if_pppoe.h
--- sys/net/if_pppoe.h	15 Jan 2025 06:15:44 -0000	1.9
+++ sys/net/if_pppoe.h	27 Feb 2025 00:34:43 -0000
@@ -70,7 +70,7 @@ extern struct mbuf_queue pppoediscinq;
 extern struct mbuf_queue pppoeinq;
 
 int		 pppoe_if_exists(void);
-struct mbuf	*pppoe_vinput(struct ifnet *, struct mbuf *);
+struct mbuf	*pppoe_vinput(struct ifnet *, struct mbuf *, struct netstack *);
 
 #endif /* _KERNEL */
 #endif /* _NET_IF_PPPOE_H_ */
Index: sys/net/if_pppx.c
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/net/if_pppx.c,v
diff -u -p -u -p -r1.133 if_pppx.c
--- sys/net/if_pppx.c	30 Dec 2024 02:46:00 -0000	1.133
+++ sys/net/if_pppx.c	27 Feb 2025 00:34:43 -0000
@@ -401,11 +401,11 @@ pppxwrite(dev_t dev, struct uio *uio, in
 
 	switch (proto) {
 	case AF_INET:
-		ipv4_input(&pxi->pxi_if, top);
+		ipv4_input(&pxi->pxi_if, top, NULL);
 		break;
 #ifdef INET6
 	case AF_INET6:
-		ipv6_input(&pxi->pxi_if, top);
+		ipv6_input(&pxi->pxi_if, top, NULL);
 		break;
 #endif
 	default:
@@ -1193,11 +1193,11 @@ pppacwrite(dev_t dev, struct uio *uio, i
 
 	switch (proto) {
 	case AF_INET:
-		ipv4_input(ifp, m);
+		ipv4_input(ifp, m, NULL);
 		break;
 #ifdef INET6
 	case AF_INET6:
-		ipv6_input(ifp, m);
+		ipv6_input(ifp, m, NULL);
 		break;
 #endif
 	default:
Index: sys/net/if_rport.c
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/net/if_rport.c,v
diff -u -p -u -p -r1.1 if_rport.c
--- sys/net/if_rport.c	31 Aug 2024 04:17:14 -0000	1.1
+++ sys/net/if_rport.c	27 Feb 2025 00:34:43 -0000
@@ -74,7 +74,7 @@ static int	rport_output(struct ifnet *, 
 		    struct rtentry *);
 static int	rport_enqueue(struct ifnet *, struct mbuf *);
 static void	rport_start(struct ifqueue *);
-static void	rport_input(struct ifnet *, struct mbuf *);
+static void	rport_input(struct ifnet *, struct mbuf *, struct netstack *);
 
 static int	rport_up(struct rport_softc *);
 static int	rport_down(struct rport_softc *);
@@ -255,7 +255,7 @@ rport_start(struct ifqueue *ifq)
 		}
 #endif
 
-		if_vinput(ifp0, m);
+		if_vinput(ifp0, m, NULL);
 	}
 	NET_UNLOCK_SHARED();
 
@@ -263,20 +263,20 @@ rport_start(struct ifqueue *ifq)
 }
 
 static void
-rport_input(struct ifnet *ifp, struct mbuf *m)
+rport_input(struct ifnet *ifp, struct mbuf *m, struct netstack *ns)
 {
         switch (m->m_pkthdr.ph_family) {
         case AF_INET:
-                ipv4_input(ifp, m);
+                ipv4_input(ifp, m, ns);
                 break;
 #ifdef INET6
         case AF_INET6:
-                ipv6_input(ifp, m);
+                ipv6_input(ifp, m, ns);
                 break;
 #endif
 #ifdef MPLS
         case AF_MPLS:
-                mpls_input(ifp, m);
+                mpls_input(ifp, m, ns);
                 break;
 #endif
         default:
Index: sys/net/if_sec.c
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/net/if_sec.c,v
diff -u -p -u -p -r1.12 if_sec.c
--- sys/net/if_sec.c	14 Feb 2025 13:14:13 -0000	1.12
+++ sys/net/if_sec.c	27 Feb 2025 00:34:43 -0000
@@ -448,7 +448,8 @@ sec_get(unsigned int unit)
 }
 
 void
-sec_input(struct sec_softc *sc, int af, int proto, struct mbuf *m)
+sec_input(struct sec_softc *sc, int af, int proto, struct mbuf *m,
+    struct netstack *ns)
 {
 	struct ip *iph;
 	int hlen;
@@ -486,7 +487,7 @@ sec_input(struct sec_softc *sc, int af, 
 
 	m->m_pkthdr.ph_family = af;
 
-	if_vinput(&sc->sc_if, m);
+	if_vinput(&sc->sc_if, m, ns);
 }
 
 void
Index: sys/net/if_spppsubr.c
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/net/if_spppsubr.c,v
diff -u -p -u -p -r1.195 if_spppsubr.c
--- sys/net/if_spppsubr.c	15 Jan 2025 06:15:44 -0000	1.195
+++ sys/net/if_spppsubr.c	27 Feb 2025 00:34:43 -0000
@@ -533,7 +533,7 @@ sppp_input(struct ifnet *ifp, struct mbu
 			if (sp->state[IDX_IPCP] == STATE_OPENED) {
 				sp->pp_last_activity = tv.tv_sec;
 				if (ifp->if_flags & IFF_UP) {
-					ipv4_input(ifp, m);
+					ipv4_input(ifp, m, NULL);
 					return;
 				}
 			}
@@ -548,7 +548,7 @@ sppp_input(struct ifnet *ifp, struct mbu
 			if (sp->state[IDX_IPV6CP] == STATE_OPENED) {
 				sp->pp_last_activity = tv.tv_sec;
 				if (ifp->if_flags & IFF_UP) {
-					ipv6_input(ifp, m);
+					ipv6_input(ifp, m, NULL);
 					return;
 				}
 			}
Index: sys/net/if_tpmr.c
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/net/if_tpmr.c,v
diff -u -p -u -p -r1.35 if_tpmr.c
--- sys/net/if_tpmr.c	23 Dec 2023 10:52:54 -0000	1.35
+++ sys/net/if_tpmr.c	27 Feb 2025 00:34:43 -0000
@@ -249,7 +249,8 @@ tpmr_8021q_filter(const struct mbuf *m, 
 struct tpmr_pf_ip_family {
 	sa_family_t	   af;
 	struct mbuf	*(*ip_check)(struct ifnet *, struct mbuf *);
-	void		 (*ip_input)(struct ifnet *, struct mbuf *);
+	void		 (*ip_input)(struct ifnet *, struct mbuf *,
+			    struct netstack *);
 };
 
 static const struct tpmr_pf_ip_family tpmr_pf_ipv4 = {
@@ -267,7 +268,7 @@ static const struct tpmr_pf_ip_family tp
 #endif
 
 static struct mbuf *
-tpmr_pf(struct ifnet *ifp0, int dir, struct mbuf *m)
+tpmr_pf(struct ifnet *ifp0, int dir, struct mbuf *m, struct netstack *ns)
 {
 	struct ether_header *eh, copy;
 	const struct tpmr_pf_ip_family *fam;
@@ -305,7 +306,7 @@ tpmr_pf(struct ifnet *ifp0, int dir, str
 	if (dir == PF_IN && ISSET(m->m_pkthdr.pf.flags, PF_TAG_DIVERTED)) {
 		pf_mbuf_unlink_state_key(m);
 		pf_mbuf_unlink_inpcb(m);
-		(*fam->ip_input)(ifp0, m);
+		(*fam->ip_input)(ifp0, m, ns);
 		return (NULL);
 	}
 
@@ -323,7 +324,8 @@ tpmr_pf(struct ifnet *ifp0, int dir, str
 #endif /* NPF > 0 */
 
 static struct mbuf *
-tpmr_input(struct ifnet *ifp0, struct mbuf *m, uint64_t dst, void *brport)
+tpmr_input(struct ifnet *ifp0, struct mbuf *m, uint64_t dst, void *brport,
+ struct netstack *ns)
 {
 	struct tpmr_port *p = brport;
 	struct tpmr_softc *sc = p->p_tpmr;
@@ -364,7 +366,7 @@ tpmr_input(struct ifnet *ifp0, struct mb
 
 #if NPF > 0
 	if (!ISSET(iff, IFF_LINK1) &&
-	    (m = tpmr_pf(ifp0, PF_IN, m)) == NULL)
+	    (m = tpmr_pf(ifp0, PF_IN, m, ns)) == NULL)
 		return (NULL);
 #endif
 
@@ -390,7 +392,7 @@ tpmr_input(struct ifnet *ifp0, struct mb
 	ifpn = pn->p_ifp0;
 #if NPF > 0
 	if (!ISSET(iff, IFF_LINK1) &&
-	    (m = tpmr_pf(ifpn, PF_OUT, m)) == NULL) {
+	    (m = tpmr_pf(ifpn, PF_OUT, m, ns)) == NULL) {
 		tpmr_p_rele(pn);
 		return (NULL);
 	}
Index: sys/net/if_trunk.c
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/net/if_trunk.c,v
diff -u -p -u -p -r1.154 if_trunk.c
--- sys/net/if_trunk.c	23 Dec 2023 10:52:54 -0000	1.154
+++ sys/net/if_trunk.c	27 Feb 2025 00:34:43 -0000
@@ -76,7 +76,7 @@ int	 trunk_ether_delmulti(struct trunk_s
 void	 trunk_ether_purgemulti(struct trunk_softc *);
 int	 trunk_ether_cmdmulti(struct trunk_port *, u_long);
 int	 trunk_ioctl_allports(struct trunk_softc *, u_long, caddr_t);
-void	 trunk_input(struct ifnet *, struct mbuf *);
+void	 trunk_input(struct ifnet *, struct mbuf *, struct netstack *);
 void	 trunk_start(struct ifnet *);
 void	 trunk_init(struct ifnet *);
 void	 trunk_stop(struct ifnet *);
@@ -1142,7 +1142,7 @@ trunk_stop(struct ifnet *ifp)
 }
 
 void
-trunk_input(struct ifnet *ifp, struct mbuf *m)
+trunk_input(struct ifnet *ifp, struct mbuf *m, struct netstack *ns)
 {
 	struct arpcom *ac0 = (struct arpcom *)ifp;
 	struct trunk_port *tp;
@@ -1195,7 +1195,7 @@ trunk_input(struct ifnet *ifp, struct mb
 	}
 
 
-	if_vinput(trifp, m);
+	if_vinput(trifp, m, ns);
 	return;
 
  bad:
Index: sys/net/if_trunk.h
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/net/if_trunk.h,v
diff -u -p -u -p -r1.31 if_trunk.h
--- sys/net/if_trunk.h	13 May 2024 01:15:53 -0000	1.31
+++ sys/net/if_trunk.h	27 Feb 2025 00:34:43 -0000
@@ -172,7 +172,7 @@ struct trunk_port {
 	int	(*tp_ioctl)(struct ifnet *, u_long, caddr_t);
 	int	(*tp_output)(struct ifnet *, struct mbuf *, struct sockaddr *,
 		    struct rtentry *);
-	void	(*tp_input)(struct ifnet *, struct mbuf *);
+	void	(*tp_input)(struct ifnet *, struct mbuf *, struct netstack *);
 
 	SLIST_ENTRY(trunk_port)		tp_entries;
 };
Index: sys/net/if_tun.c
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/net/if_tun.c,v
diff -u -p -u -p -r1.250 if_tun.c
--- sys/net/if_tun.c	30 Dec 2024 02:46:00 -0000	1.250
+++ sys/net/if_tun.c	27 Feb 2025 00:34:43 -0000
@@ -122,7 +122,7 @@ int	tun_dev_write(dev_t, struct uio *, i
 int	tun_dev_kqfilter(dev_t, struct knote *);
 
 int	tun_ioctl(struct ifnet *, u_long, caddr_t);
-void	tun_input(struct ifnet *, struct mbuf *);
+void	tun_input(struct ifnet *, struct mbuf *, struct netstack *);
 int	tun_output(struct ifnet *, struct mbuf *, struct sockaddr *,
 	    struct rtentry *);
 int	tun_enqueue(struct ifnet *, struct mbuf *);
@@ -1041,7 +1041,7 @@ tun_dev_write(dev_t dev, struct uio *uio
 	}
 
 	NET_LOCK();
-	if_vinput(ifp, m0);
+	if_vinput(ifp, m0, NULL);
 	NET_UNLOCK();
 
 	tun_put(sc);
@@ -1055,7 +1055,7 @@ put:
 }
 
 void
-tun_input(struct ifnet *ifp, struct mbuf *m0)
+tun_input(struct ifnet *ifp, struct mbuf *m0, struct netstack *ns)
 {
 	uint32_t		af;
 
@@ -1067,16 +1067,16 @@ tun_input(struct ifnet *ifp, struct mbuf
 
 	switch (ntohl(af)) {
 	case AF_INET:
-		ipv4_input(ifp, m0);
+		ipv4_input(ifp, m0, ns);
 		break;
 #ifdef INET6
 	case AF_INET6:
-		ipv6_input(ifp, m0);
+		ipv6_input(ifp, m0, ns);
 		break;
 #endif
 #ifdef MPLS
 	case AF_MPLS:
-		mpls_input(ifp, m0);
+		mpls_input(ifp, m0, ns);
 		break;
 #endif
 	default:
Index: sys/net/if_var.h
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/net/if_var.h,v
diff -u -p -u -p -r1.135 if_var.h
--- sys/net/if_var.h	24 Jan 2025 09:19:07 -0000	1.135
+++ sys/net/if_var.h	27 Feb 2025 00:34:43 -0000
@@ -46,6 +46,7 @@
 #include <sys/timeout.h>
 
 #include <net/ifq.h>
+#include <net/route.h>
 
 /*
  * Structures defining a network interface, providing a packet
@@ -90,6 +91,10 @@ struct ifnet;
 struct task;
 struct cpumem;
 
+struct netstack {
+	struct route	ns_route;
+};
+
 /*
  * Structure describing a `cloning' interface.
  */
@@ -191,7 +196,7 @@ struct ifnet {				/* and the entries */
 	struct	task if_linkstatetask;	/* [I] task to do route updates */
 
 	/* procedure handles */
-	void	(*if_input)(struct ifnet *, struct mbuf *);
+	void	(*if_input)(struct ifnet *, struct mbuf *, struct netstack *);
 	int	(*if_bpf_mtap)(caddr_t, const struct mbuf *, u_int);
 	int	(*if_output)(struct ifnet *, struct mbuf *, struct sockaddr *,
 		     struct rtentry *);	/* output routine (enqueue) */
@@ -330,9 +335,10 @@ void	if_start(struct ifnet *);
 int	if_enqueue(struct ifnet *, struct mbuf *);
 int	if_enqueue_ifq(struct ifnet *, struct mbuf *);
 void	if_input(struct ifnet *, struct mbuf_list *);
-void	if_vinput(struct ifnet *, struct mbuf *);
-void	if_input_process(struct ifnet *, struct mbuf_list *);
-int	if_input_local(struct ifnet *, struct mbuf *, sa_family_t);
+void	if_vinput(struct ifnet *, struct mbuf *, struct netstack *);
+void	if_input_process(struct ifnet *, struct mbuf_list *, unsigned int);
+int	if_input_local(struct ifnet *, struct mbuf *, sa_family_t,
+	    struct netstack *);
 int	if_output_ml(struct ifnet *, struct mbuf_list *,
 	    struct sockaddr *, struct rtentry *);
 int	if_output_mq(struct ifnet *, struct mbuf_queue *, unsigned int *,
@@ -342,7 +348,7 @@ int	if_output_tso(struct ifnet *, struct
 int	if_output_local(struct ifnet *, struct mbuf *, sa_family_t);
 void	if_rtrequest_dummy(struct ifnet *, int, struct rtentry *);
 void	p2p_rtrequest(struct ifnet *, int, struct rtentry *);
-void	p2p_input(struct ifnet *, struct mbuf *);
+void	p2p_input(struct ifnet *, struct mbuf *, struct netstack *);
 int	p2p_bpf_mtap(caddr_t, const struct mbuf *, u_int);
 
 struct	ifaddr *ifa_ifwithaddr(const struct sockaddr *, u_int);
Index: sys/net/if_veb.c
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/net/if_veb.c,v
diff -u -p -u -p -r1.36 if_veb.c
--- sys/net/if_veb.c	5 Aug 2024 17:47:29 -0000	1.36
+++ sys/net/if_veb.c	27 Feb 2025 00:34:43 -0000
@@ -167,7 +167,7 @@ static int	veb_clone_create(struct if_cl
 static int	veb_clone_destroy(struct ifnet *);
 
 static int	veb_ioctl(struct ifnet *, u_long, caddr_t);
-static void	veb_input(struct ifnet *, struct mbuf *);
+static void	veb_input(struct ifnet *, struct mbuf *, struct netstack *);
 static int	veb_enqueue(struct ifnet *, struct mbuf *);
 static int	veb_output(struct ifnet *, struct mbuf *, struct sockaddr *,
 		    struct rtentry *);
@@ -409,7 +409,8 @@ veb_clone_destroy(struct ifnet *ifp)
 }
 
 static struct mbuf *
-veb_span_input(struct ifnet *ifp0, struct mbuf *m, uint64_t dst, void *brport)
+veb_span_input(struct ifnet *ifp0, struct mbuf *m, uint64_t dst, void *brport,
+    struct netstack *ns)
 {
 	m_freem(m);
 	return (NULL);
@@ -589,7 +590,8 @@ veb_rule_filter(struct veb_port *p, int 
 struct veb_pf_ip_family {
 	sa_family_t	   af;
 	struct mbuf	*(*ip_check)(struct ifnet *, struct mbuf *);
-	void		 (*ip_input)(struct ifnet *, struct mbuf *);
+	void		 (*ip_input)(struct ifnet *, struct mbuf *,
+			    struct netstack *);
 };
 
 static const struct veb_pf_ip_family veb_pf_ipv4 = {
@@ -607,7 +609,7 @@ static const struct veb_pf_ip_family veb
 #endif
 
 static struct mbuf *
-veb_pf(struct ifnet *ifp0, int dir, struct mbuf *m)
+veb_pf(struct ifnet *ifp0, int dir, struct mbuf *m, struct netstack *ns)
 {
 	struct ether_header *eh, copy;
 	const struct veb_pf_ip_family *fam;
@@ -654,7 +656,7 @@ veb_pf(struct ifnet *ifp0, int dir, stru
 	if (dir == PF_IN && ISSET(m->m_pkthdr.pf.flags, PF_TAG_DIVERTED)) {
 		pf_mbuf_unlink_state_key(m);
 		pf_mbuf_unlink_inpcb(m);
-		(*fam->ip_input)(ifp0, m);
+		(*fam->ip_input)(ifp0, m, ns);
 		return (NULL);
 	}
 
@@ -719,7 +721,7 @@ veb_ipsec_proto_in(struct ifnet *ifp0, s
 			}
 		}
 
-		(*(tdb->tdb_xform->xf_input))(m, tdb, iphlen, poff);
+		(*(tdb->tdb_xform->xf_input))(m, tdb, iphlen, poff, NULL);
 		return (NULL);
 	}
 
@@ -927,7 +929,7 @@ veb_ipsec_out(struct ifnet *ifp0, struct
 
 static void
 veb_broadcast(struct veb_softc *sc, struct veb_port *rp, struct mbuf *m0,
-    uint64_t src, uint64_t dst)
+    uint64_t src, uint64_t dst, struct netstack *ns)
 {
 	struct ifnet *ifp = &sc->sc_if;
 	struct veb_ports *pm;
@@ -944,7 +946,7 @@ veb_broadcast(struct veb_softc *sc, stru
 	 * let pf look at it, but use the veb interface as a proxy.
 	 */
 	if (ISSET(ifp->if_flags, IFF_LINK1) &&
-	    (m0 = veb_pf(ifp, PF_FWD, m0)) == NULL)
+	    (m0 = veb_pf(ifp, PF_FWD, m0, ns)) == NULL)
 		return;
 #endif
 
@@ -1010,7 +1012,7 @@ done:
 
 static struct mbuf *
 veb_transmit(struct veb_softc *sc, struct veb_port *rp, struct veb_port *tp,
-    struct mbuf *m, uint64_t src, uint64_t dst)
+    struct mbuf *m, uint64_t src, uint64_t dst, struct netstack *ns)
 {
 	struct ifnet *ifp = &sc->sc_if;
 	struct ifnet *ifp0;
@@ -1039,7 +1041,7 @@ veb_transmit(struct veb_softc *sc, struc
 
 #if NPF > 0
 	if (ISSET(ifp->if_flags, IFF_LINK1) &&
-	    (m = veb_pf(ifp0, PF_FWD, m)) == NULL)
+	    (m = veb_pf(ifp0, PF_FWD, m, ns)) == NULL)
 		return (NULL);
 #endif
 
@@ -1055,13 +1057,15 @@ drop:
 }
 
 static struct mbuf *
-veb_vport_input(struct ifnet *ifp0, struct mbuf *m, uint64_t dst, void *brport)
+veb_vport_input(struct ifnet *ifp0, struct mbuf *m, uint64_t dst, void *brport,
+    struct netstack *ns)
 {
 	return (m);
 }
 
 static struct mbuf *
-veb_port_input(struct ifnet *ifp0, struct mbuf *m, uint64_t dst, void *brport)
+veb_port_input(struct ifnet *ifp0, struct mbuf *m, uint64_t dst, void *brport,
+    struct netstack *ns)
 {
 	struct veb_port *p = brport;
 	struct veb_softc *sc = p->p_veb;
@@ -1144,7 +1148,7 @@ veb_port_input(struct ifnet *ifp0, struc
 
 #if NPF > 0
 	if (ISSET(ifp->if_flags, IFF_LINK1) &&
-	    (m = veb_pf(ifp0, PF_IN, m)) == NULL)
+	    (m = veb_pf(ifp0, PF_IN, m, ns)) == NULL)
 		return (NULL);
 #endif
 
@@ -1170,7 +1174,7 @@ veb_port_input(struct ifnet *ifp0, struc
 			veb_eb_port_take(NULL, tp);
 		smr_read_leave();
 		if (tp != NULL) {
-			m = veb_transmit(sc, p, tp, m, src, dst);
+			m = veb_transmit(sc, p, tp, m, src, dst, ns);
 			veb_eb_port_rele(NULL, tp);
 		}
 
@@ -1182,7 +1186,7 @@ veb_port_input(struct ifnet *ifp0, struc
 		SET(m->m_flags, ETH64_IS_BROADCAST(dst) ? M_BCAST : M_MCAST);
 	}
 
-	veb_broadcast(sc, p, m, src, dst);
+	veb_broadcast(sc, p, m, src, dst, ns);
 	return (NULL);
 
 drop:
@@ -1191,7 +1195,7 @@ drop:
 }
 
 static void
-veb_input(struct ifnet *ifp, struct mbuf *m)
+veb_input(struct ifnet *ifp, struct mbuf *m, struct netstack *ns)
 {
 	m_freem(m);
 }
@@ -2446,7 +2450,7 @@ vport_if_enqueue(struct ifnet *ifp, stru
 	 * if_vinput compat with veb calling if_enqueue.
 	 */
 
-	if_vinput(ifp, m);
+	if_vinput(ifp, m, NULL);
 
 	return (0);
 }
@@ -2483,7 +2487,7 @@ vport_enqueue(struct ifnet *ifp, struct 
 	smr_read_leave();
 	if (eb != NULL) {
 		struct mbuf *(*input)(struct ifnet *, struct mbuf *,
-		    uint64_t, void *) = eb->eb_input;
+		    uint64_t, void *, struct netstack *) = eb->eb_input;
 		struct ether_header *eh;
 		uint64_t dst;
 
@@ -2501,7 +2505,7 @@ vport_enqueue(struct ifnet *ifp, struct 
 
 		if (input == veb_vport_input)
 			input = veb_port_input;
-		m = (*input)(ifp, m, dst, eb->eb_port);
+		m = (*input)(ifp, m, dst, eb->eb_port, NULL);
 
 		error = 0;
 
Index: sys/net/if_vlan.c
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/net/if_vlan.c,v
diff -u -p -u -p -r1.219 if_vlan.c
--- sys/net/if_vlan.c	9 Jun 2024 16:25:28 -0000	1.219
+++ sys/net/if_vlan.c	27 Feb 2025 00:34:43 -0000
@@ -374,7 +374,8 @@ vlan_inject(struct mbuf *m, uint16_t typ
 }
 
 struct mbuf *
-vlan_input(struct ifnet *ifp0, struct mbuf *m, unsigned int *sdelim)
+vlan_input(struct ifnet *ifp0, struct mbuf *m, unsigned int *sdelim,
+    struct netstack *ns)
 {
 	struct vlan_softc *sc;
 	struct ifnet *ifp;
@@ -471,7 +472,7 @@ vlan_input(struct ifnet *ifp0, struct mb
 		break;
 	}
 
-	if_vinput(ifp, m);
+	if_vinput(ifp, m, ns);
 leave:
 	refcnt_rele_wake(&sc->sc_refcnt);
 	return (NULL);
Index: sys/net/if_vlan_var.h
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/net/if_vlan_var.h,v
diff -u -p -u -p -r1.47 if_vlan_var.h
--- sys/net/if_vlan_var.h	13 May 2024 01:15:53 -0000	1.47
+++ sys/net/if_vlan_var.h	27 Feb 2025 00:34:43 -0000
@@ -47,7 +47,8 @@ struct	vlanreq {
 };
 
 #ifdef _KERNEL
-struct mbuf	*vlan_input(struct ifnet *, struct mbuf *, unsigned int *);
+struct mbuf	*vlan_input(struct ifnet *, struct mbuf *, unsigned int *,
+		    struct netstack *);
 struct mbuf	*vlan_inject(struct mbuf *, uint16_t, uint16_t);
 #endif /* _KERNEL */
 
Index: sys/net/if_vxlan.c
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/net/if_vxlan.c,v
diff -u -p -u -p -r1.100 if_vxlan.c
--- sys/net/if_vxlan.c	31 Oct 2024 11:41:31 -0000	1.100
+++ sys/net/if_vxlan.c	27 Feb 2025 00:34:43 -0000
@@ -173,8 +173,8 @@ static int	vxlan_addmulti(struct vxlan_s
 static void	vxlan_delmulti(struct vxlan_softc *);
 
 static struct mbuf *
-		vxlan_input(void *, struct mbuf *,
-		    struct ip *, struct ip6_hdr *, void *, int);
+		vxlan_input(void *, struct mbuf *, struct ip *,
+		    struct ip6_hdr *, void *, int, struct netstack *);
 
 static int	vxlan_set_rdomain(struct vxlan_softc *, const struct ifreq *);
 static int	vxlan_get_rdomain(struct vxlan_softc *, struct ifreq *);
@@ -602,7 +602,7 @@ vxlan_send(void *arg)
 
 static struct mbuf *
 vxlan_input(void *arg, struct mbuf *m, struct ip *ip, struct ip6_hdr *ip6,
-    void *uhp, int hlen)
+    void *uhp, int hlen, struct netstack *ns)
 {
 	struct vxlan_tep *vt = arg;
 	union vxlan_addr addr;
@@ -711,7 +711,7 @@ vxlan_input(void *arg, struct mbuf *m, s
 		break;
         }
 
-	if_vinput(ifp, m);
+	if_vinput(ifp, m, ns);
 rele:
 	vxlan_rele(sc);
 	return (NULL);
Index: sys/net/if_wg.c
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/net/if_wg.c,v
diff -u -p -u -p -r1.40 if_wg.c
--- sys/net/if_wg.c	25 Jan 2025 14:51:34 -0000	1.40
+++ sys/net/if_wg.c	27 Feb 2025 00:34:43 -0000
@@ -368,7 +368,7 @@ void	wg_index_drop(void *, uint32_t);
 
 struct mbuf *
 	wg_input(void *, struct mbuf *, struct ip *, struct ip6_hdr *, void *,
-	    int);
+	    int, struct netstack *);
 int	wg_output(struct ifnet *, struct mbuf *, struct sockaddr *,
 	    struct rtentry *);
 int	wg_ioctl_set(struct wg_softc *, struct wg_data_io *);
@@ -1867,10 +1867,10 @@ wg_deliver_in(void *_peer)
 
 		NET_LOCK();
 		if (m->m_pkthdr.ph_family == AF_INET)
-			ipv4_input(&sc->sc_if, m);
+			ipv4_input(&sc->sc_if, m, NULL);
 #ifdef INET6
 		else if (m->m_pkthdr.ph_family == AF_INET6)
-			ipv6_input(&sc->sc_if, m);
+			ipv6_input(&sc->sc_if, m, NULL);
 #endif
 		else
 			panic("invalid ph_family");
@@ -2080,7 +2080,7 @@ wg_index_drop(void *_sc, uint32_t key0)
 
 struct mbuf *
 wg_input(void *_sc, struct mbuf *m, struct ip *ip, struct ip6_hdr *ip6,
-    void *_uh, int hlen)
+    void *_uh, int hlen, struct netstack *ns)
 {
 	struct wg_pkt_data	*data;
 	struct noise_remote	*remote;
Index: sys/net/ifq.c
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/net/ifq.c,v
diff -u -p -u -p -r1.57 ifq.c
--- sys/net/ifq.c	21 Feb 2025 06:20:12 -0000	1.57
+++ sys/net/ifq.c	27 Feb 2025 00:34:43 -0000
@@ -860,7 +860,7 @@ ifiq_process(void *arg)
 	ml_init(&ifiq->ifiq_ml);
 	mtx_leave(&ifiq->ifiq_mtx);
 
-	if_input_process(ifiq->ifiq_if, &ml);
+	if_input_process(ifiq->ifiq_if, &ml, ifiq->ifiq_idx);
 }
 
 int
Index: sys/net/pipex.c
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/net/pipex.c,v
diff -u -p -u -p -r1.158 pipex.c
--- sys/net/pipex.c	3 Feb 2025 09:44:30 -0000	1.158
+++ sys/net/pipex.c	27 Feb 2025 00:34:43 -0000
@@ -935,7 +935,8 @@ drop:
 }
 
 void
-pipex_ppp_input(struct mbuf *m0, struct pipex_session *session, int decrypted)
+pipex_ppp_input(struct mbuf *m0, struct pipex_session *session, int decrypted,
+    struct netstack *ns)
 {
 	int proto, hlen = 0;
 	struct mbuf *n;
@@ -999,7 +1000,7 @@ again:
 			 * is required, discard it.
 			 */
 			goto drop;
-		pipex_ip_input(m0, session);
+		pipex_ip_input(m0, session, ns);
 		return;
 #ifdef INET6
 	case PPP_IPV6:
@@ -1009,7 +1010,7 @@ again:
 			 * is required, discard it.
 			 */
 			goto drop;
-		pipex_ip6_input(m0, session);
+		pipex_ip6_input(m0, session, ns);
 		return;
 #endif
 	default:
@@ -1028,7 +1029,8 @@ drop:
 }
 
 void
-pipex_ip_input(struct mbuf *m0, struct pipex_session *session)
+pipex_ip_input(struct mbuf *m0, struct pipex_session *session,
+    struct netstack *ns)
 {
 	struct ifnet *ifp;
 	struct ip *ip;
@@ -1093,7 +1095,7 @@ pipex_ip_input(struct mbuf *m0, struct p
 
 	counters_pkt(ifp->if_counters, ifc_ipackets, ifc_ibytes, len);
 	counters_pkt(session->stat_counters, pxc_ipackets, pxc_ibytes, len);
-	ipv4_input(ifp, m0);
+	ipv4_input(ifp, m0, ns);
 
 	if_put(ifp);
 
@@ -1105,7 +1107,8 @@ drop:
 
 #ifdef INET6
 void
-pipex_ip6_input(struct mbuf *m0, struct pipex_session *session)
+pipex_ip6_input(struct mbuf *m0, struct pipex_session *session,
+    struct netstack *ns)
 {
 	struct ifnet *ifp;
 	int len;
@@ -1141,7 +1144,7 @@ pipex_ip6_input(struct mbuf *m0, struct 
 
 	counters_pkt(ifp->if_counters, ifc_ipackets, ifc_ibytes, len);
 	counters_pkt(session->stat_counters, pxc_ipackets, pxc_ibytes, len);
-	ipv6_input(ifp, m0);
+	ipv6_input(ifp, m0, ns);
 
 	if_put(ifp);
 
@@ -1154,7 +1157,7 @@ drop:
 
 struct mbuf *
 pipex_common_input(struct pipex_session *session, struct mbuf *m0, int hlen,
-    int plen, int locked)
+    int plen, int locked, struct netstack *ns)
 {
 	int proto, ppphlen;
 	u_char code;
@@ -1208,7 +1211,7 @@ pipex_common_input(struct pipex_session 
 			m_adj(m0, plen - m0->m_pkthdr.len);
 	}
 
-	pipex_ppp_input(m0, session, 0);
+	pipex_ppp_input(m0, session, 0, ns);
 
 	return (NULL);
 
@@ -1306,7 +1309,8 @@ pipex_pppoe_lookup_session(struct mbuf *
 }
 
 struct mbuf *
-pipex_pppoe_input(struct mbuf *m0, struct pipex_session *session)
+pipex_pppoe_input(struct mbuf *m0, struct pipex_session *session,
+    struct netstack *ns)
 {
 	int hlen;
 	struct pipex_pppoe_header pppoe;
@@ -1319,7 +1323,7 @@ pipex_pppoe_input(struct mbuf *m0, struc
 	    sizeof(struct pipex_pppoe_header), &pppoe);
 
 	hlen = sizeof(struct ether_header) + sizeof(struct pipex_pppoe_header);
-	m0 = pipex_common_input(session, m0, hlen, ntohs(pppoe.length), 0);
+	m0 = pipex_common_input(session, m0, hlen, ntohs(pppoe.length), 0, ns);
 	if (m0 == NULL)
 		return (NULL);
 	m_freem(m0);
@@ -1536,7 +1540,8 @@ not_ours:
 }
 
 struct mbuf *
-pipex_pptp_input(struct mbuf *m0, struct pipex_session *session)
+pipex_pptp_input(struct mbuf *m0, struct pipex_session *session,
+    struct netstack *ns)
 {
 	int hlen, has_seq, has_ack, nseq;
 	const char *reason = "";
@@ -1631,7 +1636,7 @@ pipex_pptp_input(struct mbuf *m0, struct
 	 */
 	if (!rewind)
 		session->proto.pptp.rcv_gap += nseq;
-	m0 = pipex_common_input(session, m0, hlen, ntohs(gre->len), 1);
+	m0 = pipex_common_input(session, m0, hlen, ntohs(gre->len), 1, ns);
 	if (m0 == NULL) {
 		/*
 		 * pipex_common_input() releases lock if the
@@ -2056,7 +2061,7 @@ not_ours:
 
 struct mbuf *
 pipex_l2tp_input(struct mbuf *m0, int off0, struct pipex_session *session,
-    uint32_t ipsecflowinfo)
+    uint32_t ipsecflowinfo, struct netstack *nst)
 {
 	struct pipex_l2tp_session *l2tp_session;
 	int length = 0, offset = 0, hlen, nseq;
@@ -2142,7 +2147,7 @@ pipex_l2tp_input(struct mbuf *m0, int of
 	 */
 	if (!rewind)
 		session->proto.l2tp.nr_gap += nseq;
-	m0 = pipex_common_input(session, m0, hlen, length, 1);
+	m0 = pipex_common_input(session, m0, hlen, length, 1, nst);
 	if (m0 == NULL) {
 		/*
 		 * pipex_common_input() releases lock if the
Index: sys/net/pipex.h
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/net/pipex.h,v
diff -u -p -u -p -r1.34 pipex.h
--- sys/net/pipex.h	25 Jan 2025 02:06:40 -0000	1.34
+++ sys/net/pipex.h	27 Feb 2025 00:34:43 -0000
@@ -175,10 +175,10 @@ void			 pipex_init(void);
 
 struct pipex_session	*pipex_pppoe_lookup_session(struct mbuf *);
 struct mbuf		*pipex_pppoe_input(struct mbuf *,
-			    struct pipex_session *);
+			    struct pipex_session *, struct netstack *);
 struct pipex_session	*pipex_pptp_lookup_session(struct mbuf *);
 struct mbuf		*pipex_pptp_input(struct mbuf *,
-			    struct pipex_session *);
+			    struct pipex_session *, struct netstack *);
 struct pipex_session	*pipex_pptp_userland_lookup_session_ipv4(struct mbuf *,
 			    struct in_addr);
 struct pipex_session	*pipex_pptp_userland_lookup_session_ipv6(struct mbuf *,
@@ -190,7 +190,8 @@ struct mbuf		*pipex_pptp_userland_output
 struct pipex_session	*pipex_l2tp_lookup_session(struct mbuf *, int,
 			    struct sockaddr *);
 struct mbuf		*pipex_l2tp_input(struct mbuf *, int off,
-			    struct pipex_session *, uint32_t);
+			    struct pipex_session *, uint32_t,
+			    struct netstack *);
 struct pipex_session	*pipex_l2tp_userland_lookup_session_ipv4(struct mbuf *,
 			    struct in_addr);
 struct pipex_session	*pipex_l2tp_userland_lookup_session_ipv6(struct mbuf *,
Index: sys/net/pipex_local.h
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/net/pipex_local.h,v
diff -u -p -u -p -r1.53 pipex_local.h
--- sys/net/pipex_local.h	26 Jul 2024 15:51:09 -0000	1.53
+++ sys/net/pipex_local.h	27 Feb 2025 00:34:43 -0000
@@ -426,16 +426,19 @@ struct pipex_session  *pipex_lookup_by_i
 struct pipex_session  *pipex_lookup_by_ip_address (struct in_addr);
 struct pipex_session  *pipex_lookup_by_session_id_locked (int, int);
 struct pipex_session  *pipex_lookup_by_session_id (int, int);
-void                  pipex_ip_output (struct mbuf *, struct pipex_session *);
-void                  pipex_ppp_output (struct mbuf *, struct pipex_session *, int);
-int                   pipex_ppp_proto (struct mbuf *, struct pipex_session *, int, int *);
-void                  pipex_ppp_input (struct mbuf *, struct pipex_session *, int);
-void                  pipex_ip_input (struct mbuf *, struct pipex_session *);
-#ifdef INET6
-void                  pipex_ip6_input (struct mbuf *, struct pipex_session *);
-#endif
+void                  pipex_ip_output(struct mbuf *, struct pipex_session *);
+void                  pipex_ppp_output(struct mbuf *, struct pipex_session *,
+			int);
+int                   pipex_ppp_proto(struct mbuf *, struct pipex_session *,
+			int, int *);
+void                  pipex_ppp_input(struct mbuf *, struct pipex_session *,
+			int, struct netstack *);
+void                  pipex_ip_input(struct mbuf *, struct pipex_session *,
+			struct netstack *);
+void                  pipex_ip6_input(struct mbuf *, struct pipex_session *,
+			struct netstack *);
 struct mbuf           *pipex_common_input(struct pipex_session *,
-                          struct mbuf *, int, int, int);
+                          struct mbuf *, int, int, int, struct netstack *);
 
 #ifdef PIPEX_PPPOE
 void                  pipex_pppoe_output (struct mbuf *, struct pipex_session *);
Index: sys/netinet/icmp6.h
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/netinet/icmp6.h,v
diff -u -p -u -p -r1.54 icmp6.h
--- sys/netinet/icmp6.h	1 Jan 2025 13:44:22 -0000	1.54
+++ sys/netinet/icmp6.h	27 Feb 2025 00:34:43 -0000
@@ -592,7 +592,8 @@ struct	in6_multi;
 void		 icmp6_init(void);
 struct mbuf	*icmp6_do_error(struct mbuf *, int, int, int);
 void		 icmp6_error(struct mbuf *, int, int, int);
-int		 icmp6_input(struct mbuf **, int *, int, int);
+int		 icmp6_input(struct mbuf **, int *, int, int,
+		    struct netstack *);
 void		 icmp6_fasttimo(void);
 int		 icmp6_reflect(struct mbuf **, size_t, struct sockaddr *);
 void		 icmp6_redirect_input(struct mbuf *, int);
Index: sys/netinet/if_ether.c
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/netinet/if_ether.c,v
diff -u -p -u -p -r1.271 if_ether.c
--- sys/netinet/if_ether.c	17 Feb 2025 20:31:25 -0000	1.271
+++ sys/netinet/if_ether.c	27 Feb 2025 00:34:43 -0000
@@ -515,7 +515,7 @@ arppullup(struct mbuf *m)
  * then the protocol-specific routine is called.
  */
 void
-arpinput(struct ifnet *ifp, struct mbuf *m)
+arpinput(struct ifnet *ifp, struct mbuf *m, struct netstack *ns)
 {
 	if ((m = arppullup(m)) == NULL)
 		return;
@@ -844,7 +844,7 @@ arpproxy(struct in_addr in, unsigned int
  * then the protocol-specific routine is called.
  */
 void
-revarpinput(struct ifnet *ifp, struct mbuf *m)
+revarpinput(struct ifnet *ifp, struct mbuf *m, struct netstack *ns)
 {
 	if ((m = arppullup(m)) == NULL)
 		return;
Index: sys/netinet/if_ether.h
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/netinet/if_ether.h,v
diff -u -p -u -p -r1.93 if_ether.h
--- sys/netinet/if_ether.h	1 Jan 2025 13:44:22 -0000	1.93
+++ sys/netinet/if_ether.h	27 Feb 2025 00:34:43 -0000
@@ -222,7 +222,7 @@ do {									\
 
 struct ether_brport {
 	struct mbuf	*(*eb_input)(struct ifnet *, struct mbuf *,
-			   uint64_t, void *);
+			   uint64_t, void *, struct netstack *);
 	void		(*eb_port_take)(void *);
 	void		(*eb_port_rele)(void *);
 	void		  *eb_port;
@@ -257,13 +257,13 @@ extern u_int8_t ether_ipmulticast_max[ET
 extern unsigned int revarp_ifidx;
 #endif /* NFSCLIENT */
 
-void	revarpinput(struct ifnet *, struct mbuf *);
+void	revarpinput(struct ifnet *, struct mbuf *, struct netstack *);
 void	revarprequest(struct ifnet *);
 int	revarpwhoarewe(struct ifnet *, struct in_addr *, struct in_addr *);
 int	revarpwhoami(struct in_addr *, struct ifnet *);
 
 void	arpinit(void);
-void	arpinput(struct ifnet *, struct mbuf *);
+void	arpinput(struct ifnet *, struct mbuf *, struct netstack *);
 void	arprequest(struct ifnet *, u_int32_t *, u_int32_t *, u_int8_t *);
 void	arpwhohas(struct arpcom *, struct in_addr *);
 int	arpproxy(struct in_addr, unsigned int);
@@ -278,7 +278,7 @@ int	ether_multiaddr(struct sockaddr *, u
 void	ether_ifattach(struct ifnet *);
 void	ether_ifdetach(struct ifnet *);
 int	ether_ioctl(struct ifnet *, struct arpcom *, u_long, caddr_t);
-void	ether_input(struct ifnet *, struct mbuf *);
+void	ether_input(struct ifnet *, struct mbuf *, struct netstack *);
 int	ether_resolve(struct ifnet *, struct mbuf *, struct sockaddr *,
 	    struct rtentry *, struct ether_header *);
 struct mbuf *
Index: sys/netinet/igmp.c
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/netinet/igmp.c,v
diff -u -p -u -p -r1.85 igmp.c
--- sys/netinet/igmp.c	20 Aug 2024 07:46:27 -0000	1.85
+++ sys/netinet/igmp.c	27 Feb 2025 00:34:43 -0000
@@ -105,7 +105,8 @@ int igmp_checktimer(struct ifnet *);
 void igmp_sendpkt(struct ifnet *, struct in_multi *, int, in_addr_t);
 int rti_fill(struct in_multi *);
 struct router_info * rti_find(struct ifnet *);
-int igmp_input_if(struct ifnet *, struct mbuf **, int *, int, int);
+int igmp_input_if(struct ifnet *, struct mbuf **, int *, int, int,
+    struct netstack *);
 int igmp_sysctl_igmpstat(void *, size_t *, void *);
 
 void
@@ -196,7 +197,7 @@ rti_delete(struct ifnet *ifp)
 }
 
 int
-igmp_input(struct mbuf **mp, int *offp, int proto, int af)
+igmp_input(struct mbuf **mp, int *offp, int proto, int af, struct netstack *ns)
 {
 	struct ifnet *ifp;
 
@@ -209,14 +210,15 @@ igmp_input(struct mbuf **mp, int *offp, 
 	}
 
 	KERNEL_LOCK();
-	proto = igmp_input_if(ifp, mp, offp, proto, af);
+	proto = igmp_input_if(ifp, mp, offp, proto, af, ns);
 	KERNEL_UNLOCK();
 	if_put(ifp);
 	return proto;
 }
 
 int
-igmp_input_if(struct ifnet *ifp, struct mbuf **mp, int *offp, int proto, int af)
+igmp_input_if(struct ifnet *ifp, struct mbuf **mp, int *offp, int proto,
+    int af, struct netstack *ns)
 {
 	struct mbuf *m = *mp;
 	int iphlen = *offp;
@@ -484,7 +486,7 @@ igmp_input_if(struct ifnet *ifp, struct 
 	 * Pass all valid IGMP packets up to any process(es) listening
 	 * on a raw IGMP socket.
 	 */
-	return rip_input(mp, offp, proto, af);
+	return rip_input(mp, offp, proto, af, ns);
 }
 
 void
Index: sys/netinet/igmp_var.h
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/netinet/igmp_var.h,v
diff -u -p -u -p -r1.15 igmp_var.h
--- sys/netinet/igmp_var.h	28 Mar 2022 16:31:26 -0000	1.15
+++ sys/netinet/igmp_var.h	27 Feb 2025 00:34:43 -0000
@@ -106,7 +106,7 @@ igmpstat_inc(enum igmpstat_counters c)
 #define	IGMP_RANDOM_DELAY(X)	(arc4random_uniform(X) + 1)
 
 void	igmp_init(void);
-int	igmp_input(struct mbuf **, int *, int, int);
+int	igmp_input(struct mbuf **, int *, int, int, struct netstack *);
 void	igmp_joingroup(struct in_multi *, struct ifnet *);
 void	igmp_leavegroup(struct in_multi *, struct ifnet *);
 void	igmp_fasttimo(void);
Index: sys/netinet/in.h
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/netinet/in.h,v
diff -u -p -u -p -r1.148 in.h
--- sys/netinet/in.h	13 Feb 2024 12:22:09 -0000	1.148
+++ sys/netinet/in.h	27 Feb 2025 00:34:43 -0000
@@ -771,8 +771,9 @@ struct sockaddr_in;
 struct ifaddr;
 struct in_ifaddr;
 struct route;
+struct netstack;
 
-void	   ipv4_input(struct ifnet *, struct mbuf *);
+void	   ipv4_input(struct ifnet *, struct mbuf *, struct netstack *);
 struct mbuf *
 	   ipv4_check(struct ifnet *, struct mbuf *);
 
Index: sys/netinet/in_pcb.h
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/netinet/in_pcb.h,v
diff -u -p -u -p -r1.165 in_pcb.h
--- sys/netinet/in_pcb.h	12 Feb 2025 21:28:11 -0000	1.165
+++ sys/netinet/in_pcb.h	27 Feb 2025 00:34:43 -0000
@@ -170,7 +170,7 @@ struct inpcb {
 	struct	icmp6_filter *inp_icmp6filt;
 	struct	pf_state_key *inp_pf_sk; /* [L] */
 	struct	mbuf *(*inp_upcall)(void *, struct mbuf *,
-		    struct ip *, struct ip6_hdr *, void *, int);
+	    struct ip *, struct ip6_hdr *, void *, int, struct netstack *);
 	void	*inp_upcall_arg;
 	u_int	inp_rtableid;		/* [t] */
 	int	inp_pipex;		/* pipex indication */
Index: sys/netinet/ip_ah.c
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/netinet/ip_ah.c,v
diff -u -p -u -p -r1.174 ip_ah.c
--- sys/netinet/ip_ah.c	3 May 2022 09:18:11 -0000	1.174
+++ sys/netinet/ip_ah.c	27 Feb 2025 00:34:43 -0000
@@ -527,7 +527,8 @@ error6:
  * passes authentication.
  */
 int
-ah_input(struct mbuf **mp, struct tdb *tdb, int skip, int protoff)
+ah_input(struct mbuf **mp, struct tdb *tdb, int skip, int protoff,
+    struct netstack *ns)
 {
 	const struct auth_hash *ahx = tdb->tdb_authalgxform;
 	struct mbuf *m = *mp, *m1, *m0;
@@ -842,7 +843,7 @@ ah_input(struct mbuf **mp, struct tdb *t
 			m->m_pkthdr.len -= rplen + ahx->authsize;
 		}
 
-	return ipsec_common_input_cb(mp, tdb, skip, protoff);
+	return ipsec_common_input_cb(mp, tdb, skip, protoff, ns);
 
  drop:
 	free(ptr, M_XDATA, 0);
Index: sys/netinet/ip_carp.c
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/netinet/ip_carp.c,v
diff -u -p -u -p -r1.365 ip_carp.c
--- sys/netinet/ip_carp.c	19 Dec 2024 22:10:35 -0000	1.365
+++ sys/netinet/ip_carp.c	27 Feb 2025 00:34:43 -0000
@@ -434,7 +434,8 @@ carp_hmac_verify(struct carp_vhost_entry
 }
 
 int
-carp_proto_input(struct mbuf **mp, int *offp, int proto, int af)
+carp_proto_input(struct mbuf **mp, int *offp, int proto, int af,
+    struct netstack *ns)
 {
 	struct ifnet *ifp;
 
@@ -538,7 +539,8 @@ carp_proto_input_if(struct ifnet *ifp, s
 
 #ifdef INET6
 int
-carp6_proto_input(struct mbuf **mp, int *offp, int proto, int af)
+carp6_proto_input(struct mbuf **mp, int *offp, int proto, int af,
+    struct netstack *ns)
 {
 	struct ifnet *ifp;
 
@@ -1404,7 +1406,8 @@ carp_vhe_match(struct carp_softc *sc, ui
 }
 
 struct mbuf *
-carp_input(struct ifnet *ifp0, struct mbuf *m, uint64_t dst)
+carp_input(struct ifnet *ifp0, struct mbuf *m, uint64_t dst,
+    struct netstack *ns)
 {
 	struct srpl *cif;
 	struct carp_softc *sc;
@@ -1458,14 +1461,14 @@ carp_input(struct ifnet *ifp0, struct mb
 			if (m0 == NULL)
 				continue;
 
-			if_vinput(&sc->sc_if, m0);
+			if_vinput(&sc->sc_if, m0, ns);
 		}
 		SRPL_LEAVE(&sr);
 
 		return (m);
 	}
 
-	if_vinput(&sc->sc_if, m);
+	if_vinput(&sc->sc_if, m, ns);
 out:
 	SRPL_LEAVE(&sr);
 
Index: sys/netinet/ip_carp.h
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/netinet/ip_carp.h,v
diff -u -p -u -p -r1.51 ip_carp.h
--- sys/netinet/ip_carp.h	7 Mar 2021 06:02:32 -0000	1.51
+++ sys/netinet/ip_carp.h	27 Feb 2025 00:34:43 -0000
@@ -209,12 +209,14 @@ carp_strict_addr_chk(struct ifnet *ifp_a
 	    ifp_a->if_carpdevidx == ifp_b->if_carpdevidx));
 }
 
-struct mbuf	*carp_input(struct ifnet *, struct mbuf *, uint64_t);
-
-int		 carp_proto_input(struct mbuf **, int *, int, int);
+struct mbuf	*carp_input(struct ifnet *, struct mbuf *, uint64_t,
+		    struct netstack *);
+int		 carp_proto_input(struct mbuf **, int *, int, int,
+		    struct netstack *);
 void		 carp_carpdev_state(void *);
 void		 carp_group_demote_adj(struct ifnet *, int, char *);
-int		 carp6_proto_input(struct mbuf **, int *, int, int);
+int		 carp6_proto_input(struct mbuf **, int *, int, int,
+		    struct netstack *);
 int		 carp_iamatch(struct ifnet *);
 int		 carp_ourether(struct ifnet *, u_int8_t *);
 int		 carp_output(struct ifnet *, struct mbuf *, struct sockaddr *,
Index: sys/netinet/ip_divert.c
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/netinet/ip_divert.c,v
diff -u -p -u -p -r1.99 ip_divert.c
--- sys/netinet/ip_divert.c	23 Jan 2025 12:51:51 -0000	1.99
+++ sys/netinet/ip_divert.c	27 Feb 2025 00:34:43 -0000
@@ -168,7 +168,7 @@ divert_output(struct inpcb *inp, struct 
 			error = ENETDOWN;
 			goto fail;
 		}
-		ipv4_input(ifp, m);
+		ipv4_input(ifp, m, NULL);
 		if_put(ifp);
 	} else {
 		m->m_pkthdr.ph_rtableid = inp->inp_rtableid;
Index: sys/netinet/ip_esp.c
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/netinet/ip_esp.c,v
diff -u -p -u -p -r1.196 ip_esp.c
--- sys/netinet/ip_esp.c	7 Jun 2024 13:15:25 -0000	1.196
+++ sys/netinet/ip_esp.c	27 Feb 2025 00:34:43 -0000
@@ -338,7 +338,8 @@ esp_zeroize(struct tdb *tdbp)
  * ESP input processing, called (eventually) through the protocol switch.
  */
 int
-esp_input(struct mbuf **mp, struct tdb *tdb, int skip, int protoff)
+esp_input(struct mbuf **mp, struct tdb *tdb, int skip, int protoff,
+    struct netstack *ns)
 {
 	const struct auth_hash *esph = tdb->tdb_authalgxform;
 	const struct enc_xform *espx = tdb->tdb_encalgxform;
@@ -672,7 +673,7 @@ esp_input(struct mbuf **mp, struct tdb *
 	m_copyback(m, protoff, sizeof(u_int8_t), lastthree + 2, M_NOWAIT);
 
 	/* Back to generic IPsec input processing */
-	return ipsec_common_input_cb(mp, tdb, skip, protoff);
+	return ipsec_common_input_cb(mp, tdb, skip, protoff, ns);
 
  drop:
 	m_freemp(mp);
Index: sys/netinet/ip_icmp.c
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/netinet/ip_icmp.c,v
diff -u -p -u -p -r1.198 ip_icmp.c
--- sys/netinet/ip_icmp.c	3 Jan 2025 21:27:40 -0000	1.198
+++ sys/netinet/ip_icmp.c	27 Feb 2025 00:34:43 -0000
@@ -140,7 +140,8 @@ const struct sysctl_bounded_args icmpctl
 
 void icmp_mtudisc_timeout(struct rtentry *, u_int);
 int icmp_ratelimit(const struct in_addr *, const int, const int);
-int icmp_input_if(struct ifnet *, struct mbuf **, int *, int, int);
+int icmp_input_if(struct ifnet *, struct mbuf **, int *, int, int,
+    struct netstack *);
 int icmp_sysctl_icmpstat(void *, size_t *, void *);
 
 void
@@ -310,7 +311,7 @@ icmp_error(struct mbuf *n, int type, int
  * Process a received ICMP message.
  */
 int
-icmp_input(struct mbuf **mp, int *offp, int proto, int af)
+icmp_input(struct mbuf **mp, int *offp, int proto, int af, struct netstack *ns)
 {
 	struct ifnet *ifp;
 
@@ -320,13 +321,14 @@ icmp_input(struct mbuf **mp, int *offp, 
 		return IPPROTO_DONE;
 	}
 
-	proto = icmp_input_if(ifp, mp, offp, proto, af);
+	proto = icmp_input_if(ifp, mp, offp, proto, af, ns);
 	if_put(ifp);
 	return proto;
 }
 
 int
-icmp_input_if(struct ifnet *ifp, struct mbuf **mp, int *offp, int proto, int af)
+icmp_input_if(struct ifnet *ifp, struct mbuf **mp, int *offp, int proto,
+    int af, struct netstack *ns)
 {
 	struct mbuf *m = *mp;
 	int hlen = *offp;
@@ -673,7 +675,7 @@ reflect:
 	}
 
 raw:
-	return rip_input(mp, offp, proto, af);
+	return rip_input(mp, offp, proto, af, ns);
 
 freeit:
 	m_freem(m);
Index: sys/netinet/ip_icmp.h
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/netinet/ip_icmp.h,v
diff -u -p -u -p -r1.32 ip_icmp.h
--- sys/netinet/ip_icmp.h	20 Dec 2020 21:15:47 -0000	1.32
+++ sys/netinet/ip_icmp.h	27 Feb 2025 00:34:43 -0000
@@ -233,7 +233,7 @@ struct icmp_ext_obj_hdr {
 struct mbuf *
 	icmp_do_error(struct mbuf *, int, int, u_int32_t, int);
 void	icmp_error(struct mbuf *, int, int, u_int32_t, int);
-int	icmp_input(struct mbuf **, int *, int, int);
+int	icmp_input(struct mbuf **, int *, int, int, struct netstack *);
 void	icmp_init(void);
 int	icmp_reflect(struct mbuf *, struct mbuf **, struct in_ifaddr *);
 void	icmp_send(struct mbuf *, struct mbuf *);
Index: sys/netinet/ip_input.c
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/netinet/ip_input.c,v
diff -u -p -u -p -r1.403 ip_input.c
--- sys/netinet/ip_input.c	3 Jan 2025 21:27:40 -0000	1.403
+++ sys/netinet/ip_input.c	27 Feb 2025 00:34:43 -0000
@@ -146,7 +146,7 @@ static struct mbuf_queue	ipsendraw_mq;
 
 extern struct niqueue		arpinq;
 
-int	ip_ours(struct mbuf **, int *, int, int);
+int	ip_ours(struct mbuf **, int *, int, int, struct netstack *);
 int	ip_ours_enqueue(struct mbuf **mp, int *offp, int nxt);
 int	ip_dooptions(struct mbuf *, struct ifnet *, int);
 int	in_ouraddr(struct mbuf *, struct ifnet *, struct route *, int);
@@ -246,7 +246,7 @@ ip_init(void)
  * NET_LOCK_SHARED() and the transport layer needing it exclusively.
  */
 int
-ip_ours(struct mbuf **mp, int *offp, int nxt, int af)
+ip_ours(struct mbuf **mp, int *offp, int nxt, int af, struct netstack *ns)
 {
 	nxt = ip_fragcheck(mp, offp);
 	if (nxt == IPPROTO_DONE)
@@ -256,7 +256,7 @@ ip_ours(struct mbuf **mp, int *offp, int
 	if (af != AF_UNSPEC)
 		return nxt;
 
-	nxt = ip_deliver(mp, offp, nxt, AF_INET, 1);
+	nxt = ip_deliver(mp, offp, nxt, AF_INET, 1, ns);
 	if (nxt == IPPROTO_DONE)
 		return IPPROTO_DONE;
 
@@ -325,7 +325,7 @@ ipintr(void)
 			nxt = ip->ip_p;
 		}
 
-		nxt = ip_deliver(&m, &off, nxt, AF_INET, 0);
+		nxt = ip_deliver(&m, &off, nxt, AF_INET, 0, NULL);
 		KASSERT(nxt == IPPROTO_DONE);
 	}
 }
@@ -336,12 +336,12 @@ ipintr(void)
  * Checksum and byte swap header.  Process options. Forward or deliver.
  */
 void
-ipv4_input(struct ifnet *ifp, struct mbuf *m)
+ipv4_input(struct ifnet *ifp, struct mbuf *m, struct netstack *ns)
 {
 	int off, nxt;
 
 	off = 0;
-	nxt = ip_input_if(&m, &off, IPPROTO_IPV4, AF_UNSPEC, ifp);
+	nxt = ip_input_if(&m, &off, IPPROTO_IPV4, AF_UNSPEC, ifp, ns);
 	KASSERT(nxt == IPPROTO_DONE);
 }
 
@@ -439,9 +439,10 @@ bad:
 }
 
 int
-ip_input_if(struct mbuf **mp, int *offp, int nxt, int af, struct ifnet *ifp)
+ip_input_if(struct mbuf **mp, int *offp, int nxt, int af, struct ifnet *ifp,
+    struct netstack *ns)
 {
-	struct route ro;
+	struct route iproute, *ro = NULL;
 	struct mbuf *m;
 	struct ip *ip;
 	int hlen;
@@ -452,7 +453,6 @@ ip_input_if(struct mbuf **mp, int *offp,
 
 	KASSERT(*offp == 0);
 
-	ro.ro_rt = NULL;
 	ipstat_inc(ips_total);
 	m = *mp = ipv4_check(ifp, *mp);
 	if (m == NULL)
@@ -508,15 +508,21 @@ ip_input_if(struct mbuf **mp, int *offp,
 
 	if (ip->ip_dst.s_addr == INADDR_BROADCAST ||
 	    ip->ip_dst.s_addr == INADDR_ANY) {
-		nxt = ip_ours(mp, offp, nxt, af);
+		nxt = ip_ours(mp, offp, nxt, af, ns);
 		goto out;
 	}
 
-	switch(in_ouraddr(m, ifp, &ro, flags)) {
+	if (ns == NULL) {
+		ro = &iproute;
+		ro->ro_rt = NULL;
+	} else {
+		ro = &ns->ns_route;
+	}
+	switch(in_ouraddr(m, ifp, ro, flags)) {
 	case 2:
 		goto bad;
 	case 1:
-		nxt = ip_ours(mp, offp, nxt, af);
+		nxt = ip_ours(mp, offp, nxt, af, ns);
 		goto out;
 	}
 
@@ -565,7 +571,7 @@ ip_input_if(struct mbuf **mp, int *offp,
 			 * host belongs to their destination groups.
 			 */
 			if (ip->ip_p == IPPROTO_IGMP) {
-				nxt = ip_ours(mp, offp, nxt, af);
+				nxt = ip_ours(mp, offp, nxt, af, ns);
 				goto out;
 			}
 			ipstat_inc(ips_forward);
@@ -581,7 +587,7 @@ ip_input_if(struct mbuf **mp, int *offp,
 				ipstat_inc(ips_cantforward);
 			goto bad;
 		}
-		nxt = ip_ours(mp, offp, nxt, af);
+		nxt = ip_ours(mp, offp, nxt, af, ns);
 		goto out;
 	}
 
@@ -614,15 +620,17 @@ ip_input_if(struct mbuf **mp, int *offp,
 	}
 #endif /* IPSEC */
 
-	ip_forward(m, ifp, &ro, flags);
+	ip_forward(m, ifp, ro, flags);
 	*mp = NULL;
-	rtfree(ro.ro_rt);
+	if (ro == &iproute)
+		rtfree(ro->ro_rt);
 	return IPPROTO_DONE;
  bad:
 	nxt = IPPROTO_DONE;
 	m_freemp(mp);
  out:
-	rtfree(ro.ro_rt);
+	if (ro == &iproute)
+		rtfree(ro->ro_rt);
 	return nxt;
 }
 
@@ -743,7 +751,8 @@ ip_fragcheck(struct mbuf **mp, int *offp
 #endif
 
 int
-ip_deliver(struct mbuf **mp, int *offp, int nxt, int af, int shared)
+ip_deliver(struct mbuf **mp, int *offp, int nxt, int af, int shared,
+    struct netstack *ns)
 {
 #ifdef INET6
 	int nest = 0;
@@ -825,7 +834,7 @@ ip_deliver(struct mbuf **mp, int *offp, 
 			naf = af;
 			break;
 		}
-		nxt = (*psw->pr_input)(mp, offp, nxt, af);
+		nxt = (*psw->pr_input)(mp, offp, nxt, af, ns);
 		af = naf;
 	}
 	return nxt;
Index: sys/netinet/ip_ipcomp.c
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/netinet/ip_ipcomp.c,v
diff -u -p -u -p -r1.92 ip_ipcomp.c
--- sys/netinet/ip_ipcomp.c	3 May 2022 09:18:11 -0000	1.92
+++ sys/netinet/ip_ipcomp.c	27 Feb 2025 00:34:43 -0000
@@ -131,7 +131,8 @@ ipcomp_zeroize(struct tdb *tdbp)
  * ipcomp_input() gets called to uncompress an input packet
  */
 int
-ipcomp_input(struct mbuf **mp, struct tdb *tdb, int skip, int protoff)
+ipcomp_input(struct mbuf **mp, struct tdb *tdb, int skip, int protoff,
+    struct netstack *ns)
 {
 	const struct comp_algo *ipcompx = tdb->tdb_compalgxform;
 	struct mbuf *m = *mp;
@@ -289,7 +290,7 @@ ipcomp_input(struct mbuf **mp, struct td
 	m_copyback(m, protoff, sizeof(u_int8_t), &nproto, M_NOWAIT);
 
 	/* Back to generic IPsec input processing */
-	return ipsec_common_input_cb(mp, tdb, skip, protoff);
+	return ipsec_common_input_cb(mp, tdb, skip, protoff, ns);
 
  drop:
 	m_freemp(mp);
Index: sys/netinet/ip_ipip.c
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/netinet/ip_ipip.c,v
diff -u -p -u -p -r1.105 ip_ipip.c
--- sys/netinet/ip_ipip.c	22 Aug 2024 10:58:31 -0000	1.105
+++ sys/netinet/ip_ipip.c	27 Feb 2025 00:34:43 -0000
@@ -106,7 +106,7 @@ ipip_init(void)
  * Really only a wrapper for ipip_input_if(), for use with pr_input.
  */
 int
-ipip_input(struct mbuf **mp, int *offp, int nxt, int af)
+ipip_input(struct mbuf **mp, int *offp, int nxt, int af, struct netstack *ns)
 {
 	struct ifnet *ifp;
 	int ipip_allow_local = atomic_load_int(&ipip_allow);
@@ -124,7 +124,7 @@ ipip_input(struct mbuf **mp, int *offp, 
 		m_freemp(mp);
 		return IPPROTO_DONE;
 	}
-	nxt = ipip_input_if(mp, offp, nxt, af, ipip_allow_local, ifp);
+	nxt = ipip_input_if(mp, offp, nxt, af, ipip_allow_local, ifp, ns);
 	if_put(ifp);
 
 	return nxt;
@@ -140,7 +140,7 @@ ipip_input(struct mbuf **mp, int *offp, 
 
 int
 ipip_input_if(struct mbuf **mp, int *offp, int proto, int oaf, int allow,
-    struct ifnet *ifp)
+    struct ifnet *ifp, struct netstack *ns)
 {
 	struct mbuf *m = *mp;
 	struct sockaddr_in *sin;
@@ -326,10 +326,10 @@ ipip_input_if(struct mbuf **mp, int *off
 
 	switch (proto) {
 	case IPPROTO_IPV4:
-		return ip_input_if(mp, offp, proto, oaf, ifp);
+		return ip_input_if(mp, offp, proto, oaf, ifp, ns);
 #ifdef INET6
 	case IPPROTO_IPV6:
-		return ip6_input_if(mp, offp, proto, oaf, ifp);
+		return ip6_input_if(mp, offp, proto, oaf, ifp, ns);
 #endif
 	}
  bad:
@@ -564,7 +564,8 @@ ipe4_zeroize(struct tdb *tdbp)
 }
 
 int
-ipe4_input(struct mbuf **mp, struct tdb *tdb, int hlen, int proto)
+ipe4_input(struct mbuf **mp, struct tdb *tdb, int hlen, int proto,
+    struct netstack *ns)
 {
 	/* This is a rather serious mistake, so no conditional printing. */
 	printf("%s: should never be called\n", __func__);
Index: sys/netinet/ip_ipip.h
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/netinet/ip_ipip.h,v
diff -u -p -u -p -r1.14 ip_ipip.h
--- sys/netinet/ip_ipip.h	22 Aug 2024 10:58:31 -0000	1.14
+++ sys/netinet/ip_ipip.h	27 Feb 2025 00:34:43 -0000
@@ -113,8 +113,9 @@ ipipstat_pkt(enum ipipstat_counters p, e
 struct tdb;
 
 void	ipip_init(void);
-int	ipip_input(struct mbuf **, int *, int, int);
-int	ipip_input_if(struct mbuf **, int *, int, int, int, struct ifnet *);
+int	ipip_input(struct mbuf **, int *, int, int, struct netstack *);
+int	ipip_input_if(struct mbuf **, int *, int, int, int, struct ifnet *,
+	    struct netstack *);
 int	ipip_output(struct mbuf **, struct tdb *);
 int	ipip_sysctl(int *, u_int, void *, size_t *, void *, size_t);
 
Index: sys/netinet/ip_ipsp.h
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/netinet/ip_ipsp.h,v
diff -u -p -u -p -r1.247 ip_ipsp.h
--- sys/netinet/ip_ipsp.h	14 Feb 2025 13:14:13 -0000	1.247
+++ sys/netinet/ip_ipsp.h	27 Feb 2025 00:34:43 -0000
@@ -533,7 +533,8 @@ struct xformsw {
 	int	(*xf_init)(struct tdb *, const struct xformsw *,
 		    struct ipsecinit *);
 	int	(*xf_zeroize)(struct tdb *); /* termination */
-	int	(*xf_input)(struct mbuf **, struct tdb *, int, int);
+	int	(*xf_input)(struct mbuf **, struct tdb *, int, int,
+		    struct netstack *);
 	int	(*xf_output)(struct mbuf *, struct tdb *, int, int);
 };
 
@@ -629,17 +630,17 @@ void	tdb_printit(void *, int, int (*)(co
 int	ipe4_attach(void);
 int	ipe4_init(struct tdb *, const struct xformsw *, struct ipsecinit *);
 int	ipe4_zeroize(struct tdb *);
-int	ipe4_input(struct mbuf **, struct tdb *, int, int);
+int	ipe4_input(struct mbuf **, struct tdb *, int, int, struct netstack *);
 
 /* XF_AH */
 int	ah_attach(void);
 int	ah_init(struct tdb *, const struct xformsw *, struct ipsecinit *);
 int	ah_zeroize(struct tdb *);
-int	ah_input(struct mbuf **, struct tdb *, int, int);
+int	ah_input(struct mbuf **, struct tdb *, int, int, struct netstack *);
 int	ah_output(struct mbuf *, struct tdb *, int, int);
 int	ah_sysctl(int *, u_int, void *, size_t *, void *, size_t);
 
-int	ah46_input(struct mbuf **, int *, int, int);
+int	ah46_input(struct mbuf **, int *, int, int, struct netstack *);
 void	ah4_ctlinput(int, struct sockaddr *, u_int, void *);
 void	udpencap_ctlinput(int, struct sockaddr *, u_int, void *);
 
@@ -647,28 +648,29 @@ void	udpencap_ctlinput(int, struct socka
 int	esp_attach(void);
 int	esp_init(struct tdb *, const struct xformsw *, struct ipsecinit *);
 int	esp_zeroize(struct tdb *);
-int	esp_input(struct mbuf **, struct tdb *, int, int);
+int	esp_input(struct mbuf **, struct tdb *, int, int, struct netstack *);
 int	esp_output(struct mbuf *, struct tdb *, int, int);
 int	esp_sysctl(int *, u_int, void *, size_t *, void *, size_t);
 
-int	esp46_input(struct mbuf **, int *, int, int);
+int	esp46_input(struct mbuf **, int *, int, int, struct netstack *);
 void	esp4_ctlinput(int, struct sockaddr *, u_int, void *);
 
 /* XF_IPCOMP */
 int	ipcomp_attach(void);
 int	ipcomp_init(struct tdb *, const struct xformsw *, struct ipsecinit *);
 int	ipcomp_zeroize(struct tdb *);
-int	ipcomp_input(struct mbuf **, struct tdb *, int, int);
+int	ipcomp_input(struct mbuf **, struct tdb *, int, int, struct netstack *);
 int	ipcomp_output(struct mbuf *, struct tdb *, int, int);
 int	ipcomp_sysctl(int *, u_int, void *, size_t *, void *, size_t);
-int	ipcomp46_input(struct mbuf **, int *, int, int);
+int	ipcomp46_input(struct mbuf **, int *, int, int, struct netstack *);
 
 /* XF_TCPSIGNATURE */
 int	tcp_signature_tdb_attach(void);
 int	tcp_signature_tdb_init(struct tdb *, const struct xformsw *,
 	    struct ipsecinit *);
 int	tcp_signature_tdb_zeroize(struct tdb *);
-int	tcp_signature_tdb_input(struct mbuf **, struct tdb *, int, int);
+int	tcp_signature_tdb_input(struct mbuf **, struct tdb *, int, int,
+	    struct netstack *);
 int	tcp_signature_tdb_output(struct mbuf *, struct tdb *, int, int);
 
 /* Replay window */
@@ -694,9 +696,12 @@ void	ipsp_ids_free(struct ipsec_ids *);
 void	ipsp_init(void);
 void	ipsec_init(void);
 int	ipsec_sysctl(int *, u_int, void *, size_t *, void *, size_t);
-int	ipsec_common_input(struct mbuf **, int, int, int, int, int);
-int	ipsec_common_input_cb(struct mbuf **, struct tdb *, int, int);
-int	ipsec_input_disabled(struct mbuf **, int *, int, int);
+int	ipsec_common_input(struct mbuf **, int, int, int, int, int,
+	    struct netstack *);
+int	ipsec_common_input_cb(struct mbuf **, struct tdb *, int, int,
+	    struct netstack *);
+int	ipsec_input_disabled(struct mbuf **, int *, int, int,
+	    struct netstack *);
 int	ipsec_protoff(struct mbuf *, int, int);
 int	ipsec_delete_policy(struct ipsec_policy *);
 ssize_t	ipsec_hdrsz(struct tdb *);
Index: sys/netinet/ip_output.c
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/netinet/ip_output.c,v
diff -u -p -u -p -r1.404 ip_output.c
--- sys/netinet/ip_output.c	14 Feb 2025 13:14:13 -0000	1.404
+++ sys/netinet/ip_output.c	27 Feb 2025 00:34:43 -0000
@@ -1763,7 +1763,7 @@ ip_mloopback(struct ifnet *ifp, struct m
 		 * than the interface's MTU.  Can this possibly matter?
 		 */
 		in_hdr_cksum_out(copym, NULL);
-		if_input_local(ifp, copym, dst->sin_family);
+		if_input_local(ifp, copym, dst->sin_family, NULL);
 	}
 }
 
Index: sys/netinet/ip_var.h
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/netinet/ip_var.h,v
diff -u -p -u -p -r1.120 ip_var.h
--- sys/netinet/ip_var.h	12 Jul 2024 19:50:35 -0000	1.120
+++ sys/netinet/ip_var.h	27 Feb 2025 00:34:43 -0000
@@ -262,12 +262,13 @@ void	 ip_stripoptions(struct mbuf *);
 int	 ip_sysctl(int *, u_int, void *, size_t *, void *, size_t);
 void	 ip_savecontrol(struct inpcb *, struct mbuf **, struct ip *,
 	    struct mbuf *);
-int	 ip_input_if(struct mbuf **, int *, int, int, struct ifnet *);
-int	 ip_deliver(struct mbuf **, int *, int, int, int);
+int	 ip_input_if(struct mbuf **, int *, int, int, struct ifnet *,
+	    struct netstack *);
+int	 ip_deliver(struct mbuf **, int *, int, int, int, struct netstack *);
 void	 ip_forward(struct mbuf *, struct ifnet *, struct route *, int);
 int	 rip_ctloutput(int, struct socket *, int, int, struct mbuf *);
 void	 rip_init(void);
-int	 rip_input(struct mbuf **, int *, int, int);
+int	 rip_input(struct mbuf **, int *, int, int, struct netstack *);
 int	 rip_output(struct mbuf *, struct socket *, struct sockaddr *,
 	    struct mbuf *);
 struct mbuf *
Index: sys/netinet/ipsec_input.c
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/netinet/ipsec_input.c,v
diff -u -p -u -p -r1.207 ipsec_input.c
--- sys/netinet/ipsec_input.c	27 Dec 2024 10:15:09 -0000	1.207
+++ sys/netinet/ipsec_input.c	27 Feb 2025 00:34:43 -0000
@@ -186,7 +186,7 @@ ipsec_init(void)
  */
 int
 ipsec_common_input(struct mbuf **mp, int skip, int protoff, int af, int sproto,
-    int udpencap)
+    int udpencap, struct netstack *ns)
 {
 #define IPSEC_ISTAT(x,y,z) do {			\
 	if (sproto == IPPROTO_ESP)		\
@@ -340,7 +340,7 @@ ipsec_common_input(struct mbuf **mp, int
 	 * Call appropriate transform and return -- callback takes care of
 	 * everything else.
 	 */
-	prot = (*(tdbp->tdb_xform->xf_input))(mp, tdbp, skip, protoff);
+	prot = (*(tdbp->tdb_xform->xf_input))(mp, tdbp, skip, protoff, ns);
 	if (prot == IPPROTO_DONE) {
 		ipsecstat_inc(ipsec_idrops);
 		tdbstat_inc(tdbp, tdb_idrops);
@@ -363,7 +363,8 @@ ipsec_common_input(struct mbuf **mp, int
  * filtering and other sanity checks on the processed packet.
  */
 int
-ipsec_common_input_cb(struct mbuf **mp, struct tdb *tdbp, int skip, int protoff)
+ipsec_common_input_cb(struct mbuf **mp, struct tdb *tdbp, int skip,
+    int protoff, struct netstack *ns)
 {
 	struct mbuf *m = *mp;
 	int af, sproto;
@@ -747,14 +748,15 @@ ipsec_sysctl_ipsecstat(void *oldp, size_
 }
 
 int
-ipsec_input_disabled(struct mbuf **mp, int *offp, int proto, int af)
+ipsec_input_disabled(struct mbuf **mp, int *offp, int proto, int af,
+    struct netstack *ns)
 {
 	switch (af) {
 	case AF_INET:
-		return rip_input(mp, offp, proto, af);
+		return rip_input(mp, offp, proto, af, ns);
 #ifdef INET6
 	case AF_INET6:
-		return rip6_input(mp, offp, proto, af);
+		return rip6_input(mp, offp, proto, af, ns);
 #endif
 	default:
 		unhandled_af(af);
@@ -762,7 +764,7 @@ ipsec_input_disabled(struct mbuf **mp, i
 }
 
 int
-ah46_input(struct mbuf **mp, int *offp, int proto, int af)
+ah46_input(struct mbuf **mp, int *offp, int proto, int af, struct netstack *ns)
 {
 	int protoff;
 
@@ -771,7 +773,7 @@ ah46_input(struct mbuf **mp, int *offp, 
 	    ((*mp)->m_pkthdr.pf.flags & PF_TAG_DIVERTED) ||
 #endif
 	    !atomic_load_int(&ah_enable))
-		return ipsec_input_disabled(mp, offp, proto, af);
+		return ipsec_input_disabled(mp, offp, proto, af, ns);
 
 	protoff = ipsec_protoff(*mp, *offp, af);
 	if (protoff < 0) {
@@ -781,7 +783,7 @@ ah46_input(struct mbuf **mp, int *offp, 
 		return IPPROTO_DONE;
 	}
 
-	return ipsec_common_input(mp, *offp, protoff, af, proto, 0);
+	return ipsec_common_input(mp, *offp, protoff, af, proto, 0, ns);
 }
 
 void
@@ -795,7 +797,8 @@ ah4_ctlinput(int cmd, struct sockaddr *s
 }
 
 int
-esp46_input(struct mbuf **mp, int *offp, int proto, int af)
+esp46_input(struct mbuf **mp, int *offp, int proto, int af,
+    struct netstack *ns)
 {
 	int protoff;
 
@@ -804,7 +807,7 @@ esp46_input(struct mbuf **mp, int *offp,
 	    ((*mp)->m_pkthdr.pf.flags & PF_TAG_DIVERTED) ||
 #endif
 	    !esp_enable)
-		return ipsec_input_disabled(mp, offp, proto, af);
+		return ipsec_input_disabled(mp, offp, proto, af, ns);
 
 	protoff = ipsec_protoff(*mp, *offp, af);
 	if (protoff < 0) {
@@ -814,12 +817,13 @@ esp46_input(struct mbuf **mp, int *offp,
 		return IPPROTO_DONE;
 	}
 
-	return ipsec_common_input(mp, *offp, protoff, af, proto, 0);
+	return ipsec_common_input(mp, *offp, protoff, af, proto, 0, ns);
 }
 
 /* IPv4 IPCOMP wrapper */
 int
-ipcomp46_input(struct mbuf **mp, int *offp, int proto, int af)
+ipcomp46_input(struct mbuf **mp, int *offp, int proto, int af,
+    struct netstack *ns)
 {
 	int protoff;
 
@@ -828,7 +832,7 @@ ipcomp46_input(struct mbuf **mp, int *of
 	    ((*mp)->m_pkthdr.pf.flags & PF_TAG_DIVERTED) ||
 #endif
 	    !atomic_load_int(&ipcomp_enable))
-		return ipsec_input_disabled(mp, offp, proto, af);
+		return ipsec_input_disabled(mp, offp, proto, af, ns);
 
 	protoff = ipsec_protoff(*mp, *offp, af);
 	if (protoff < 0) {
@@ -838,7 +842,7 @@ ipcomp46_input(struct mbuf **mp, int *of
 		return IPPROTO_DONE;
 	}
 
-	return ipsec_common_input(mp, *offp, protoff, af, proto, 0);
+	return ipsec_common_input(mp, *offp, protoff, af, proto, 0, ns);
 }
 
 void
Index: sys/netinet/raw_ip.c
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/netinet/raw_ip.c,v
diff -u -p -u -p -r1.164 raw_ip.c
--- sys/netinet/raw_ip.c	6 Feb 2025 13:40:58 -0000	1.164
+++ sys/netinet/raw_ip.c	27 Feb 2025 00:34:43 -0000
@@ -129,7 +129,7 @@ rip_init(void)
 }
 
 int
-rip_input(struct mbuf **mp, int *offp, int proto, int af)
+rip_input(struct mbuf **mp, int *offp, int proto, int af, struct netstack *ns)
 {
 	struct mbuf *m = *mp;
 	struct ip *ip = mtod(m, struct ip *);
Index: sys/netinet/tcp_input.c
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/netinet/tcp_input.c,v
diff -u -p -u -p -r1.431 tcp_input.c
--- sys/netinet/tcp_input.c	17 Feb 2025 08:56:33 -0000	1.431
+++ sys/netinet/tcp_input.c	27 Feb 2025 00:34:43 -0000
@@ -352,7 +352,7 @@ tcp_flush_queue(struct tcpcb *tp)
  * protocol specification dated September, 1981 very closely.
  */
 int
-tcp_input(struct mbuf **mp, int *offp, int proto, int af)
+tcp_input(struct mbuf **mp, int *offp, int proto, int af, struct netstack *ns)
 {
 	struct mbuf *m = *mp;
 	int iphlen = *offp;
Index: sys/netinet/tcp_subr.c
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/netinet/tcp_subr.c,v
diff -u -p -u -p -r1.208 tcp_subr.c
--- sys/netinet/tcp_subr.c	12 Feb 2025 21:28:11 -0000	1.208
+++ sys/netinet/tcp_subr.c	27 Feb 2025 00:34:43 -0000
@@ -1021,7 +1021,7 @@ tcp_signature_tdb_zeroize(struct tdb *td
 
 int
 tcp_signature_tdb_input(struct mbuf **mp, struct tdb *tdbp, int skip,
-    int protoff)
+    int protoff, struct netstack *sn)
 {
 	m_freemp(mp);
 	return (IPPROTO_DONE);
Index: sys/netinet/tcp_var.h
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/netinet/tcp_var.h,v
diff -u -p -u -p -r1.185 tcp_var.h
--- sys/netinet/tcp_var.h	16 Jan 2025 11:59:20 -0000	1.185
+++ sys/netinet/tcp_var.h	27 Feb 2025 00:34:43 -0000
@@ -717,7 +717,7 @@ struct tcpcb *
 int	 tcp_dooptions(struct tcpcb *, u_char *, int, struct tcphdr *,
 		struct mbuf *, int, struct tcp_opt_info *, u_int, uint64_t);
 void	 tcp_init(void);
-int	 tcp_input(struct mbuf **, int *, int, int);
+int	 tcp_input(struct mbuf **, int *, int, int, struct netstack *);
 int	 tcp_mss(struct tcpcb *, int);
 void	 tcp_mss_update(struct tcpcb *);
 u_int	 tcp_hdrsz(struct tcpcb *);
Index: sys/netinet/udp_usrreq.c
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/netinet/udp_usrreq.c,v
diff -u -p -u -p -r1.333 udp_usrreq.c
--- sys/netinet/udp_usrreq.c	17 Feb 2025 12:46:02 -0000	1.333
+++ sys/netinet/udp_usrreq.c	27 Feb 2025 00:34:43 -0000
@@ -171,7 +171,7 @@ struct	cpumem *udpcounters;
 
 void	udp_sbappend(struct inpcb *, struct mbuf *, struct ip *,
 	    struct ip6_hdr *, int, struct udphdr *, struct sockaddr *,
-	    u_int32_t);
+	    u_int32_t, struct netstack *);
 int	udp_output(struct inpcb *, struct mbuf *, struct mbuf *, struct mbuf *);
 void	udp_notify(struct inpcb *, int);
 int	udp_sysctl_locked(int *, u_int, void *, size_t *, void *, size_t);
@@ -192,7 +192,7 @@ udp_init(void)
 }
 
 int
-udp_input(struct mbuf **mp, int *offp, int proto, int af)
+udp_input(struct mbuf **mp, int *offp, int proto, int af, struct netstack *ns)
 {
 	struct mbuf *m = *mp;
 	int iphlen = *offp;
@@ -340,7 +340,7 @@ udp_input(struct mbuf **mp, int *offp, i
 			protoff = af == AF_INET ? offsetof(struct ip, ip_p) :
 			    offsetof(struct ip6_hdr, ip6_nxt);
 			return ipsec_common_input(mp, skip, protoff,
-			    af, IPPROTO_ESP, 1);
+			    af, IPPROTO_ESP, 1, ns);
 		}
 	}
 #endif /* IPSEC */
@@ -473,7 +473,7 @@ udp_input(struct mbuf **mp, int *offp, i
 				n = m_copym(m, 0, M_COPYALL, M_NOWAIT);
 				if (n != NULL) {
 					udp_sbappend(last, n, ip, ip6, iphlen,
-					    uh, &srcsa.sa, 0);
+					    uh, &srcsa.sa, 0, ns);
 				}
 				in_pcbunref(last);
 
@@ -508,7 +508,7 @@ udp_input(struct mbuf **mp, int *offp, i
 			return IPPROTO_DONE;
 		}
 
-		udp_sbappend(last, m, ip, ip6, iphlen, uh, &srcsa.sa, 0);
+		udp_sbappend(last, m, ip, ip6, iphlen, uh, &srcsa.sa, 0, ns);
 		in_pcbunref(last);
 
 		return IPPROTO_DONE;
@@ -624,7 +624,7 @@ udp_input(struct mbuf **mp, int *offp, i
 		if ((session = pipex_l2tp_lookup_session(m, off, &srcsa.sa))
 		    != NULL) {
 			m = *mp = pipex_l2tp_input(m, off, session,
-			    ipsecflowinfo);
+			    ipsecflowinfo, ns);
 			pipex_rele_session(session);
 			if (m == NULL) {
 				in_pcbunref(inp);
@@ -634,7 +634,7 @@ udp_input(struct mbuf **mp, int *offp, i
 	}
 #endif
 
-	udp_sbappend(inp, m, ip, ip6, iphlen, uh, &srcsa.sa, ipsecflowinfo);
+	udp_sbappend(inp, m, ip, ip6, iphlen, uh, &srcsa.sa, ipsecflowinfo, ns);
 	in_pcbunref(inp);
 	return IPPROTO_DONE;
 bad:
@@ -646,7 +646,8 @@ bad:
 void
 udp_sbappend(struct inpcb *inp, struct mbuf *m, struct ip *ip,
     struct ip6_hdr *ip6, int hlen, struct udphdr *uh,
-    struct sockaddr *srcaddr, u_int32_t ipsecflowinfo)
+    struct sockaddr *srcaddr, u_int32_t ipsecflowinfo,
+    struct netstack *ns)
 {
 	struct socket *so = inp->inp_socket;
 	struct mbuf *opts = NULL;
@@ -655,7 +656,7 @@ udp_sbappend(struct inpcb *inp, struct m
 
 	if (inp->inp_upcall != NULL) {
 		m = (*inp->inp_upcall)(inp->inp_upcall_arg, m,
-		    ip, ip6, uh, hlen);
+		    ip, ip6, uh, hlen, ns);
 		if (m == NULL)
 			return;
 	}
Index: sys/netinet/udp_var.h
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/netinet/udp_var.h,v
diff -u -p -u -p -r1.52 udp_var.h
--- sys/netinet/udp_var.h	12 Jul 2024 19:50:35 -0000	1.52
+++ sys/netinet/udp_var.h	27 Feb 2025 00:34:43 -0000
@@ -137,7 +137,7 @@ void	udp6_ctlinput(int, struct sockaddr 
 #endif /* INET6 */
 void	 udp_ctlinput(int, struct sockaddr *, u_int, void *);
 void	 udp_init(void);
-int	 udp_input(struct mbuf **, int *, int, int);
+int	 udp_input(struct mbuf **, int *, int, int, struct netstack *);
 #ifdef INET6
 int	 udp6_output(struct inpcb *, struct mbuf *, struct mbuf *,
 	struct mbuf *);
Index: sys/netinet6/dest6.c
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/netinet6/dest6.c,v
diff -u -p -u -p -r1.20 dest6.c
--- sys/netinet6/dest6.c	13 Feb 2024 12:22:09 -0000	1.20
+++ sys/netinet6/dest6.c	27 Feb 2025 00:34:43 -0000
@@ -49,7 +49,8 @@
  * Destination options header processing.
  */
 int
-dest6_input(struct mbuf **mp, int *offp, int proto, int af)
+dest6_input(struct mbuf **mp, int *offp, int proto, int af,
+    struct netstack *ns)
 {
 	int off = *offp, dstoptlen, optlen;
 	struct ip6_dest *dstopts;
Index: sys/netinet6/frag6.c
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/netinet6/frag6.c,v
diff -u -p -u -p -r1.89 frag6.c
--- sys/netinet6/frag6.c	29 Jul 2024 12:41:30 -0000	1.89
+++ sys/netinet6/frag6.c	27 Feb 2025 00:34:43 -0000
@@ -111,7 +111,8 @@ frag6_init(void)
  * Fragment input
  */
 int
-frag6_input(struct mbuf **mp, int *offp, int proto, int af)
+frag6_input(struct mbuf **mp, int *offp, int proto, int af,
+    struct netstack *ns)
 {
 	struct mbuf *m = *mp, *t;
 	struct ip6_hdr *ip6;
Index: sys/netinet6/icmp6.c
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/netinet6/icmp6.c,v
diff -u -p -u -p -r1.256 icmp6.c
--- sys/netinet6/icmp6.c	3 Jan 2025 21:27:40 -0000	1.256
+++ sys/netinet6/icmp6.c	27 Feb 2025 00:34:43 -0000
@@ -384,7 +384,8 @@ icmp6_error(struct mbuf *m, int type, in
  * Process a received ICMP6 message.
  */
 int
-icmp6_input(struct mbuf **mp, int *offp, int proto, int af)
+icmp6_input(struct mbuf **mp, int *offp, int proto, int af,
+    struct netstack *ns)
 {
 #if NCARP > 0
 	struct ifnet *ifp;
@@ -757,7 +758,7 @@ badlen:
 raw:
 #endif
 	/* deliver the packet to appropriate sockets */
-	return rip6_input(mp, offp, proto, af);
+	return rip6_input(mp, offp, proto, af, ns);
 
  freeit:
 	m_freem(m);
Index: sys/netinet6/in6.h
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/netinet6/in6.h,v
diff -u -p -u -p -r1.119 in6.h
--- sys/netinet6/in6.h	1 Sep 2024 03:09:00 -0000	1.119
+++ sys/netinet6/in6.h	27 Feb 2025 00:34:43 -0000
@@ -405,8 +405,9 @@ struct ifaddr;
 struct in6_ifaddr;
 struct ifnet;
 struct rtentry;
+struct netstack;
 
-void	ipv6_input(struct ifnet *, struct mbuf *);
+void	ipv6_input(struct ifnet *, struct mbuf *, struct netstack *);
 struct mbuf *
 	ipv6_check(struct ifnet *, struct mbuf *);
 
Index: sys/netinet6/ip6_divert.c
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/netinet6/ip6_divert.c,v
diff -u -p -u -p -r1.98 ip6_divert.c
--- sys/netinet6/ip6_divert.c	23 Jan 2025 12:51:51 -0000	1.98
+++ sys/netinet6/ip6_divert.c	27 Feb 2025 00:34:43 -0000
@@ -177,7 +177,7 @@ divert6_output(struct inpcb *inp, struct
 			error = ENETDOWN;
 			goto fail;
 		}
-		ipv6_input(ifp, m);
+		ipv6_input(ifp, m, NULL);
 		if_put(ifp);
 	} else {
 		m->m_pkthdr.ph_rtableid = inp->inp_rtableid;
Index: sys/netinet6/ip6_input.c
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/netinet6/ip6_input.c,v
diff -u -p -u -p -r1.267 ip6_input.c
--- sys/netinet6/ip6_input.c	21 Nov 2024 20:15:44 -0000	1.267
+++ sys/netinet6/ip6_input.c	27 Feb 2025 00:34:43 -0000
@@ -119,7 +119,7 @@ struct cpumem *ip6counters;
 
 uint8_t ip6_soiikey[IP6_SOIIKEY_LEN];
 
-int ip6_ours(struct mbuf **, int *, int, int, int);
+int ip6_ours(struct mbuf **, int *, int, int, int, struct netstack *);
 int ip6_check_rh0hdr(struct mbuf *, int *);
 int ip6_hbhchcheck(struct mbuf **, int *, int *, int);
 int ip6_hopopts_input(struct mbuf **, int *, u_int32_t *, u_int32_t *);
@@ -172,7 +172,8 @@ ip6_init(void)
  * NET_LOCK_SHARED() and the transport layer needing it exclusively.
  */
 int
-ip6_ours(struct mbuf **mp, int *offp, int nxt, int af, int flags)
+ip6_ours(struct mbuf **mp, int *offp, int nxt, int af, int flags,
+    struct netstack *ns)
 {
 	/* ip6_hbhchcheck() may be run before, then off and nxt are set */
 	if (*offp == 0) {
@@ -185,7 +186,7 @@ ip6_ours(struct mbuf **mp, int *offp, in
 	if (af != AF_UNSPEC)
 		return nxt;
 
-	nxt = ip_deliver(mp, offp, nxt, AF_INET6, 1);
+	nxt = ip_deliver(mp, offp, nxt, AF_INET6, 1, ns);
 	if (nxt == IPPROTO_DONE)
 		return IPPROTO_DONE;
 
@@ -253,18 +254,18 @@ ip6intr(void)
 			off = sizeof(struct ip6_hdr);
 			nxt = ip6->ip6_nxt;
 		}
-		nxt = ip_deliver(&m, &off, nxt, AF_INET6, 0);
+		nxt = ip_deliver(&m, &off, nxt, AF_INET6, 0, NULL);
 		KASSERT(nxt == IPPROTO_DONE);
 	}
 }
 
 void
-ipv6_input(struct ifnet *ifp, struct mbuf *m)
+ipv6_input(struct ifnet *ifp, struct mbuf *m, struct netstack *ns)
 {
 	int off, nxt;
 
 	off = 0;
-	nxt = ip6_input_if(&m, &off, IPPROTO_IPV6, AF_UNSPEC, ifp);
+	nxt = ip6_input_if(&m, &off, IPPROTO_IPV6, AF_UNSPEC, ifp, ns);
 	KASSERT(nxt == IPPROTO_DONE);
 }
 
@@ -360,9 +361,10 @@ bad:
 }
 
 int
-ip6_input_if(struct mbuf **mp, int *offp, int nxt, int af, struct ifnet *ifp)
+ip6_input_if(struct mbuf **mp, int *offp, int nxt, int af, struct ifnet *ifp,
+    struct netstack *ns)
 {
-	struct route ro;
+	struct route iproute, *ro = NULL;
 	struct mbuf *m;
 	struct ip6_hdr *ip6;
 	struct rtentry *rt;
@@ -375,7 +377,6 @@ ip6_input_if(struct mbuf **mp, int *offp
 
 	KASSERT(*offp == 0);
 
-	ro.ro_rt = NULL;
 	ip6stat_inc(ip6s_total);
 	m = *mp = ipv6_check(ifp, *mp);
 	if (m == NULL)
@@ -461,7 +462,7 @@ ip6_input_if(struct mbuf **mp, int *offp
 
 #if NPF > 0
 	if (pf_ouraddr(m) == 1) {
-		nxt = ip6_ours(mp, offp, nxt, af, flags);
+		nxt = ip6_ours(mp, offp, nxt, af, flags, ns);
 		goto out;
 	}
 #endif
@@ -513,7 +514,7 @@ ip6_input_if(struct mbuf **mp, int *offp
 			if (ours) {
 				if (af == AF_UNSPEC)
 					nxt = ip6_ours(mp, offp, nxt, af,
-					    flags);
+					    flags, ns);
 				goto out;
 			}
 			goto bad;
@@ -525,7 +526,7 @@ ip6_input_if(struct mbuf **mp, int *offp
 				ip6stat_inc(ip6s_cantforward);
 			goto bad;
 		}
-		nxt = ip6_ours(mp, offp, nxt, af, flags);
+		nxt = ip6_ours(mp, offp, nxt, af, flags, ns);
 		goto out;
 	}
 
@@ -533,7 +534,13 @@ ip6_input_if(struct mbuf **mp, int *offp
 	/*
 	 *  Unicast check
 	 */
-	rt = route6_mpath(&ro, &ip6->ip6_dst, &ip6->ip6_src,
+	if (ns == NULL) {
+		ro = &iproute;
+		ro->ro_rt = NULL;
+	} else {
+		ro = &ns->ns_route;
+	}
+	rt = route6_mpath(ro, &ip6->ip6_dst, &ip6->ip6_src,
 	    m->m_pkthdr.ph_rtableid);
 
 	/*
@@ -585,7 +592,7 @@ ip6_input_if(struct mbuf **mp, int *offp
 
 			goto bad;
 		} else {
-			nxt = ip6_ours(mp, offp, nxt, af, flags);
+			nxt = ip6_ours(mp, offp, nxt, af, flags, ns);
 			goto out;
 		}
 	}
@@ -611,7 +618,7 @@ ip6_input_if(struct mbuf **mp, int *offp
 
 	if (ours) {
 		if (af == AF_UNSPEC)
-			nxt = ip6_ours(mp, offp, nxt, af, flags);
+			nxt = ip6_ours(mp, offp, nxt, af, flags, ns);
 		goto out;
 	}
 
@@ -631,15 +638,17 @@ ip6_input_if(struct mbuf **mp, int *offp
 	}
 #endif /* IPSEC */
 
-	ip6_forward(m, &ro, flags);
+	ip6_forward(m, ro, flags);
 	*mp = NULL;
-	rtfree(ro.ro_rt);
+	if (ro == &iproute)
+		rtfree(ro->ro_rt);
 	return IPPROTO_DONE;
  bad:
 	nxt = IPPROTO_DONE;
 	m_freemp(mp);
  out:
-	rtfree(ro.ro_rt);
+	if (ro == &iproute)
+		rtfree(ro->ro_rt);
 	return nxt;
 }
 
Index: sys/netinet6/ip6_output.c
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/netinet6/ip6_output.c,v
diff -u -p -u -p -r1.295 ip6_output.c
--- sys/netinet6/ip6_output.c	14 Feb 2025 13:14:13 -0000	1.295
+++ sys/netinet6/ip6_output.c	27 Feb 2025 00:34:44 -0000
@@ -2565,7 +2565,7 @@ ip6_mloopback(struct ifnet *ifp, struct 
 	if (IN6_IS_SCOPE_EMBED(&ip6->ip6_dst))
 		ip6->ip6_dst.s6_addr16[1] = 0;
 
-	if_input_local(ifp, copym, dst->sin6_family);
+	if_input_local(ifp, copym, dst->sin6_family, NULL);
 }
 
 /*
Index: sys/netinet6/ip6_var.h
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/netinet6/ip6_var.h,v
diff -u -p -u -p -r1.121 ip6_var.h
--- sys/netinet6/ip6_var.h	21 Nov 2024 20:15:44 -0000	1.121
+++ sys/netinet6/ip6_var.h	27 Feb 2025 00:34:44 -0000
@@ -310,7 +310,8 @@ int	icmp6_ctloutput(int, struct socket *
 
 void	ip6_init(void);
 void	ip6intr(void);
-int	ip6_input_if(struct mbuf **, int *, int, int, struct ifnet *);
+int	ip6_input_if(struct mbuf **, int *, int, int, struct ifnet *,
+	    struct netstack *);
 int	ip6_ours_enqueue(struct mbuf **, int *, int);
 void	ip6_freepcbopts(struct ip6_pktopts *);
 void	ip6_freemoptions(struct ip6_moptions *);
@@ -340,15 +341,15 @@ void	ip6_randomid_init(void);
 u_int32_t ip6_randomid(void);
 void	ip6_send(struct mbuf *);
 
-int	route6_input(struct mbuf **, int *, int, int);
+int	route6_input(struct mbuf **, int *, int, int, struct netstack *);
 
 void	frag6_init(void);
-int	frag6_input(struct mbuf **, int *, int, int);
+int	frag6_input(struct mbuf **, int *, int, int, struct netstack *);
 int	frag6_deletefraghdr(struct mbuf *, int);
 void	frag6_slowtimo(void);
 
 void	rip6_init(void);
-int	rip6_input(struct mbuf **, int *, int, int);
+int	rip6_input(struct mbuf **, int *, int, int, struct netstack *);
 void	rip6_ctlinput(int, struct sockaddr *, u_int, void *);
 int	rip6_ctloutput(int, struct socket *, int, int, struct mbuf *);
 int	rip6_output(struct mbuf *, struct socket *, struct sockaddr *,
@@ -363,7 +364,7 @@ int	rip6_send(struct socket *, struct mb
 	    struct mbuf *);
 int	rip6_sysctl(int *, u_int, void *, size_t *, void *, size_t);
 
-int	dest6_input(struct mbuf **, int *, int, int);
+int	dest6_input(struct mbuf **, int *, int, int, struct netstack *);
 
 int	in6_pcbselsrc(const struct in6_addr **, struct sockaddr_in6 *,
 	    struct inpcb *, struct ip6_pktopts *);
Index: sys/netinet6/mld6.c
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/netinet6/mld6.c,v
diff -u -p -u -p -r1.64 mld6.c
--- sys/netinet6/mld6.c	19 Aug 2024 08:07:16 -0000	1.64
+++ sys/netinet6/mld6.c	27 Feb 2025 00:34:44 -0000
@@ -489,6 +489,5 @@ mld6_sendpkt(struct in6_multi *in6m, int
 	if_put(ifp);
 
 	icmp6stat_inc(icp6s_outhist + type);
-	ip6_output(mh, &ip6_opts, NULL, ia6 ? 0 : IPV6_UNSPECSRC, &im6o,
-	    NULL);
+	ip6_output(mh, &ip6_opts, NULL, ia6 ? 0 : IPV6_UNSPECSRC, &im6o, NULL);
 }
Index: sys/netinet6/raw_ip6.c
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/netinet6/raw_ip6.c,v
diff -u -p -u -p -r1.188 raw_ip6.c
--- sys/netinet6/raw_ip6.c	12 Feb 2025 21:28:11 -0000	1.188
+++ sys/netinet6/raw_ip6.c	27 Feb 2025 00:34:44 -0000
@@ -132,7 +132,7 @@ rip6_init(void)
 }
 
 int
-rip6_input(struct mbuf **mp, int *offp, int proto, int af)
+rip6_input(struct mbuf **mp, int *offp, int proto, int af, struct netstack *ns)
 {
 	struct mbuf *m = *mp;
 	struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
Index: sys/netinet6/route6.c
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/netinet6/route6.c,v
diff -u -p -u -p -r1.22 route6.c
--- sys/netinet6/route6.c	13 Feb 2024 12:22:09 -0000	1.22
+++ sys/netinet6/route6.c	27 Feb 2025 00:34:44 -0000
@@ -51,7 +51,8 @@
  */
 
 int
-route6_input(struct mbuf **mp, int *offp, int proto, int af)
+route6_input(struct mbuf **mp, int *offp, int proto, int af,
+    struct netstack *ns)
 {
 	struct ip6_hdr *ip6;
 	struct mbuf *m = *mp;
Index: sys/netmpls/mpls.h
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/netmpls/mpls.h,v
diff -u -p -u -p -r1.46 mpls.h
--- sys/netmpls/mpls.h	25 May 2021 22:45:10 -0000	1.46
+++ sys/netmpls/mpls.h	27 Feb 2025 00:34:44 -0000
@@ -161,6 +161,6 @@ struct mbuf	*mpls_ip6_adjttl(struct mbuf
 
 int		 mpls_output(struct ifnet *, struct mbuf *, struct sockaddr *,
 		    struct rtentry *);
-void		 mpls_input(struct ifnet *, struct mbuf *);
+void		 mpls_input(struct ifnet *, struct mbuf *, struct netstack *);
 
 #endif /* _KERNEL */
Index: sys/netmpls/mpls_input.c
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/netmpls/mpls_input.c,v
diff -u -p -u -p -r1.79 mpls_input.c
--- sys/netmpls/mpls_input.c	13 May 2023 13:35:18 -0000	1.79
+++ sys/netmpls/mpls_input.c	27 Feb 2025 00:34:44 -0000
@@ -47,7 +47,7 @@ struct mbuf	*mpls_do_error(struct mbuf *
 void		 mpls_input_local(struct rtentry *, struct mbuf *);
 
 void
-mpls_input(struct ifnet *ifp, struct mbuf *m)
+mpls_input(struct ifnet *ifp, struct mbuf *m, struct netstack *ns)
 {
 	struct sockaddr_mpls *smpls;
 	struct sockaddr_mpls sa_mpls;
@@ -126,7 +126,7 @@ do_v4:
 					if (m == NULL)
 						return;
 				}
-				ipv4_input(ifp, m);
+				ipv4_input(ifp, m, ns);
 				return;
 #ifdef INET6
 			case MPLS_LABEL_IPV6NULL:
@@ -136,7 +136,7 @@ do_v6:
 					if (m == NULL)
 						return;
 				}
-				ipv6_input(ifp, m);
+				ipv6_input(ifp, m, ns);
 				return;
 #endif	/* INET6 */
 			case MPLS_LABEL_IMPLNULL:
Index: sys/sys/protosw.h
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/sys/protosw.h,v
diff -u -p -u -p -r1.71 protosw.h
--- sys/sys/protosw.h	5 Jan 2025 12:36:48 -0000	1.71
+++ sys/sys/protosw.h	27 Feb 2025 00:34:44 -0000
@@ -63,6 +63,7 @@ struct domain;
 struct proc;
 struct stat;
 struct ifnet;
+struct netstack;
 
 struct pr_usrreqs {
 	int	(*pru_attach)(struct socket *, int, int);
@@ -96,7 +97,7 @@ struct protosw {
 
 /* protocol-protocol hooks */
 					/* input to protocol (from below) */
-	int	(*pr_input)(struct mbuf **, int *, int, int);
+	int	(*pr_input)(struct mbuf **, int *, int, int, struct netstack *);
 					/* control input (from below) */
 	void	(*pr_ctlinput)(int, struct sockaddr *, u_int, void *);
 					/* control output (from above) */