Index: sys/net/if.c =================================================================== RCS file: /mount/openbsd/cvs/src/sys/net/if.c,v retrieving revision 1.642 diff -u -p -u -p -r1.642 if.c --- sys/net/if.c 30 Jun 2021 13:23:33 -0000 1.642 +++ sys/net/if.c 16 Jul 2021 16:30:42 -0000 @@ -238,7 +238,7 @@ int ifq_congestion; int netisr; -#define NET_TASKQ 1 +#define NET_TASKQ 4 struct taskq *nettqmp[NET_TASKQ]; struct task if_input_task_locked = TASK_INITIALIZER(if_netisr, NULL); @@ -834,10 +834,10 @@ if_input_process(struct ifnet *ifp, stru * to PF globals, pipex globals, unicast and multicast addresses * lists and the socket layer. */ - NET_LOCK(); + NET_RLOCK_IN_SOFTNET(); while ((m = ml_dequeue(ml)) != NULL) (*ifp->if_input)(ifp, m); - NET_UNLOCK(); + NET_RUNLOCK_IN_SOFTNET(); } void @@ -895,6 +895,12 @@ if_netisr(void *unused) KERNEL_UNLOCK(); } #endif + if (n & (1 << NETISR_IP)) + ipintr(); +#ifdef INET6 + if (n & (1 << NETISR_IPV6)) + ip6intr(); +#endif #if NPPP > 0 if (n & (1 << NETISR_PPP)) { KERNEL_LOCK(); @@ -3316,12 +3322,15 @@ unhandled_af(int af) * globals aren't ready to be accessed by multiple threads in * parallel. */ -int nettaskqs = NET_TASKQ; +int nettaskqs; struct taskq * net_tq(unsigned int ifindex) { struct taskq *t = NULL; + + if (nettaskqs == 0) + nettaskqs = min(NET_TASKQ, ncpus); t = nettqmp[ifindex % nettaskqs]; Index: sys/net/if_ethersubr.c =================================================================== RCS file: /mount/openbsd/cvs/src/sys/net/if_ethersubr.c,v retrieving revision 1.275 diff -u -p -u -p -r1.275 if_ethersubr.c --- sys/net/if_ethersubr.c 7 Jul 2021 20:19:01 -0000 1.275 +++ sys/net/if_ethersubr.c 16 Jul 2021 16:30:42 -0000 @@ -222,7 +222,10 @@ ether_resolve(struct ifnet *ifp, struct switch (af) { case AF_INET: + KERNEL_LOCK(); + /* XXXSMP there is a MP race in arpresolve() */ error = arpresolve(ifp, rt, m, dst, eh->ether_dhost); + KERNEL_UNLOCK(); if (error) return (error); eh->ether_type = htons(ETHERTYPE_IP); @@ -245,7 +248,10 @@ ether_resolve(struct ifnet *ifp, struct break; #ifdef INET6 case AF_INET6: + KERNEL_LOCK(); + /* XXXSMP there is a MP race in nd6_resolve() */ error = nd6_resolve(ifp, rt, m, dst, eh->ether_dhost); + KERNEL_UNLOCK(); if (error) return (error); eh->ether_type = htons(ETHERTYPE_IPV6); Index: sys/net/ifq.c =================================================================== RCS file: /mount/openbsd/cvs/src/sys/net/ifq.c,v retrieving revision 1.44 diff -u -p -u -p -r1.44 ifq.c --- sys/net/ifq.c 9 Jul 2021 01:22:05 -0000 1.44 +++ sys/net/ifq.c 16 Jul 2021 16:30:42 -0000 @@ -243,7 +243,7 @@ void ifq_init(struct ifqueue *ifq, struct ifnet *ifp, unsigned int idx) { ifq->ifq_if = ifp; - ifq->ifq_softnet = net_tq(ifp->if_index); /* + idx */ + ifq->ifq_softnet = net_tq(ifp->if_index + idx); ifq->ifq_softc = NULL; mtx_init(&ifq->ifq_mtx, IPL_NET); @@ -620,7 +620,7 @@ void ifiq_init(struct ifiqueue *ifiq, struct ifnet *ifp, unsigned int idx) { ifiq->ifiq_if = ifp; - ifiq->ifiq_softnet = net_tq(ifp->if_index); /* + idx */ + ifiq->ifiq_softnet = net_tq(ifp->if_index + idx); ifiq->ifiq_softc = NULL; mtx_init(&ifiq->ifiq_mtx, IPL_NET); Index: sys/net/netisr.h =================================================================== RCS file: /mount/openbsd/cvs/src/sys/net/netisr.h,v retrieving revision 1.55 diff -u -p -u -p -r1.55 netisr.h --- sys/net/netisr.h 5 Jan 2021 20:43:36 -0000 1.55 +++ sys/net/netisr.h 16 Jul 2021 16:30:42 -0000 @@ -41,8 +41,10 @@ * interrupt used for scheduling the network code to calls * on the lowest level routine of each protocol. */ +#define NETISR_IP 2 /* same as AF_INET */ #define NETISR_PFSYNC 5 /* for pfsync "immediate" tx */ #define NETISR_ARP 18 /* same as AF_LINK */ +#define NETISR_IPV6 24 /* same as AF_INET6 */ #define NETISR_PPP 28 /* for PPP processing */ #define NETISR_BRIDGE 29 /* for bridge processing */ #define NETISR_SWITCH 31 /* for switch dataplane */ @@ -57,6 +59,8 @@ extern int netisr; /* scheduling bits extern struct task if_input_task_locked; void arpintr(void); +void ipintr(void); +void ip6intr(void); void pppintr(void); void bridgeintr(void); void switchintr(void); Index: sys/netinet/ip_ah.c =================================================================== RCS file: /mount/openbsd/cvs/src/sys/netinet/ip_ah.c,v retrieving revision 1.150 diff -u -p -u -p -r1.150 ip_ah.c --- sys/netinet/ip_ah.c 8 Jul 2021 21:07:19 -0000 1.150 +++ sys/netinet/ip_ah.c 16 Jul 2021 16:30:42 -0000 @@ -550,7 +550,7 @@ ah_input(struct mbuf *m, struct tdb *tdb sizeof(u_int32_t), &btsx); btsx = ntohl(btsx); - switch (checkreplaywindow(tdb, btsx, &esn, 0)) { + switch (checkreplaywindow(tdb, tdb->tdb_rpl, btsx, &esn, 0)) { case 0: /* All's well. */ break; case 1: @@ -697,6 +697,7 @@ ah_input(struct mbuf *m, struct tdb *tdb tc->tc_proto = tdb->tdb_sproto; tc->tc_rdomain = tdb->tdb_rdomain; memcpy(&tc->tc_dst, &tdb->tdb_dst, sizeof(union sockaddr_union)); + tc->tc_rpl = tdb->tdb_rpl; KERNEL_LOCK(); error = crypto_dispatch(crp); @@ -715,6 +716,7 @@ ah_input_cb(struct tdb *tdb, struct tdb_ { const struct auth_hash *ahx = tdb->tdb_authalgxform; int roff, rplen, skip, protoff; + u_int64_t rpl; u_int32_t btsx, esn; caddr_t ptr; unsigned char calc[AH_ALEN_MAX]; @@ -727,6 +729,7 @@ ah_input_cb(struct tdb *tdb, struct tdb_ skip = tc->tc_skip; protoff = tc->tc_protoff; + rpl = tc->tc_rpl; rplen = AH_FLENGTH + sizeof(u_int32_t); @@ -756,7 +759,7 @@ ah_input_cb(struct tdb *tdb, struct tdb_ sizeof(u_int32_t), &btsx); btsx = ntohl(btsx); - switch (checkreplaywindow(tdb, btsx, &esn, 1)) { + switch (checkreplaywindow(tdb, rpl, btsx, &esn, 1)) { case 0: /* All's well. */ #if NPFSYNC > 0 pfsync_update_tdb(tdb,0); Index: sys/netinet/ip_esp.c =================================================================== RCS file: /mount/openbsd/cvs/src/sys/netinet/ip_esp.c,v retrieving revision 1.167 diff -u -p -u -p -r1.167 ip_esp.c --- sys/netinet/ip_esp.c 8 Jul 2021 21:07:19 -0000 1.167 +++ sys/netinet/ip_esp.c 16 Jul 2021 16:30:42 -0000 @@ -388,7 +388,7 @@ esp_input(struct mbuf *m, struct tdb *td &btsx); btsx = ntohl(btsx); - switch (checkreplaywindow(tdb, btsx, &esn, 0)) { + switch (checkreplaywindow(tdb, tdb->tdb_rpl, btsx, &esn, 0)) { case 0: /* All's well */ break; case 1: @@ -511,6 +511,7 @@ esp_input(struct mbuf *m, struct tdb *td tc->tc_proto = tdb->tdb_sproto; tc->tc_rdomain = tdb->tdb_rdomain; tc->tc_dst = tdb->tdb_dst; + tc->tc_rpl = tdb->tdb_rpl; /* Decryption descriptor */ if (espx) { @@ -549,6 +550,7 @@ esp_input_cb(struct tdb *tdb, struct tdb int hlen, roff, skip, protoff; struct mbuf *m1, *mo; const struct auth_hash *esph; + u_int64_t rpl; u_int32_t btsx, esn; caddr_t ptr; #ifdef ENCDEBUG @@ -557,6 +559,7 @@ esp_input_cb(struct tdb *tdb, struct tdb skip = tc->tc_skip; protoff = tc->tc_protoff; + rpl = tc->tc_rpl; NET_ASSERT_LOCKED(); @@ -590,7 +593,7 @@ esp_input_cb(struct tdb *tdb, struct tdb &btsx); btsx = ntohl(btsx); - switch (checkreplaywindow(tdb, btsx, &esn, 1)) { + switch (checkreplaywindow(tdb, rpl, btsx, &esn, 1)) { case 0: /* All's well */ #if NPFSYNC > 0 pfsync_update_tdb(tdb,0); @@ -1049,14 +1052,15 @@ esp_output_cb(struct tdb *tdb, struct td * return 3 for packet within current window but already received */ int -checkreplaywindow(struct tdb *tdb, u_int32_t seq, u_int32_t *seqh, int commit) +checkreplaywindow(struct tdb *tdb, u_int64_t t, u_int32_t seq, u_int32_t *seqh, + int commit) { u_int32_t tl, th, wl; u_int32_t packet, window = TDB_REPLAYMAX - TDB_REPLAYWASTE; int idx, esn = tdb->tdb_flags & TDBF_ESN; - tl = (u_int32_t)tdb->tdb_rpl; - th = (u_int32_t)(tdb->tdb_rpl >> 32); + tl = (u_int32_t)t; + th = (u_int32_t)(t >> 32); /* Zero SN is not allowed */ if ((esn && seq == 0 && tl <= AH_HMAC_INITIAL_RPL && th == 0) || Index: sys/netinet/ip_input.c =================================================================== RCS file: /mount/openbsd/cvs/src/sys/netinet/ip_input.c,v retrieving revision 1.363 diff -u -p -u -p -r1.363 ip_input.c --- sys/netinet/ip_input.c 21 Jun 2021 22:09:14 -0000 1.363 +++ sys/netinet/ip_input.c 16 Jul 2021 16:30:42 -0000 @@ -130,6 +130,8 @@ const struct sysctl_bounded_args ipctl_v { IPCTL_ARPDOWN, &arpt_down, 0, INT_MAX }, }; +struct niqueue ipintrq = NIQUEUE_INITIALIZER(IPQ_MAXLEN, NETISR_IP); + struct pool ipqent_pool; struct pool ipq_pool; @@ -143,6 +145,7 @@ static struct mbuf_queue ipsendraw_mq; extern struct niqueue arpinq; int ip_ours(struct mbuf **, int *, int, int); +int ip_local(struct mbuf **, int *, int, int); int ip_dooptions(struct mbuf *, struct ifnet *); int in_ouraddr(struct mbuf *, struct ifnet *, struct rtentry **); @@ -230,6 +233,43 @@ ip_init(void) } /* + * Enqueue packet for local delivery. Queuing is used as a boundary + * between the network layer (input/forward path) running with shared + * NET_RLOCK_IN_SOFTNET() and the transport layer needing it exclusively. + */ +int +ip_ours(struct mbuf **mp, int *offp, int nxt, int af) +{ + /* We are already in a IPv4/IPv6 local deliver loop. */ + if (af != AF_UNSPEC) + return ip_local(mp, offp, nxt, af); + + niq_enqueue(&ipintrq, *mp); + *mp = NULL; + return IPPROTO_DONE; +} + +/* + * Dequeue and process locally delivered packets. + */ +void +ipintr(void) +{ + struct mbuf *m; + int off, nxt; + + while ((m = niq_dequeue(&ipintrq)) != NULL) { +#ifdef DIAGNOSTIC + if ((m->m_flags & M_PKTHDR) == 0) + panic("ipintr no HDR"); +#endif + off = 0; + nxt = ip_local(&m, &off, IPPROTO_IPV4, AF_UNSPEC); + KASSERT(nxt == IPPROTO_DONE); + } +} + +/* * IPv4 input routine. * * Checksum and byte swap header. Process options. Forward or deliver. @@ -514,7 +554,7 @@ ip_input_if(struct mbuf **mp, int *offp, * If fragmented try to reassemble. Pass to next level. */ int -ip_ours(struct mbuf **mp, int *offp, int nxt, int af) +ip_local(struct mbuf **mp, int *offp, int nxt, int af) { struct mbuf *m = *mp; struct ip *ip = mtod(m, struct ip *); @@ -1665,7 +1705,8 @@ ip_sysctl(int *name, u_int namelen, void newlen)); #endif case IPCTL_IFQUEUE: - return (EOPNOTSUPP); + return (sysctl_niq(name + 1, namelen - 1, + oldp, oldlenp, newp, newlen, &ipintrq)); case IPCTL_ARPQUEUE: return (sysctl_niq(name + 1, namelen - 1, oldp, oldlenp, newp, newlen, &arpinq)); Index: sys/netinet/ip_ipsp.h =================================================================== RCS file: /mount/openbsd/cvs/src/sys/netinet/ip_ipsp.h,v retrieving revision 1.201 diff -u -p -u -p -r1.201 ip_ipsp.h --- sys/netinet/ip_ipsp.h 13 Jul 2021 08:16:17 -0000 1.201 +++ sys/netinet/ip_ipsp.h 16 Jul 2021 16:30:42 -0000 @@ -432,12 +432,13 @@ struct tdb_ident { }; struct tdb_crypto { - u_int32_t tc_spi; union sockaddr_union tc_dst; - u_int8_t tc_proto; + u_int64_t tc_rpl; + u_int32_t tc_spi; int tc_protoff; int tc_skip; u_int tc_rdomain; + u_int8_t tc_proto; }; struct ipsecinit { @@ -622,7 +623,7 @@ int tcp_signature_tdb_output(struct mbuf int, int); /* Replay window */ -int checkreplaywindow(struct tdb *, u_int32_t, u_int32_t *, int); +int checkreplaywindow(struct tdb *, u_int64_t, u_int32_t, u_int32_t *, int); /* Packet processing */ int ipsp_process_packet(struct mbuf *, struct tdb *, int, int); Index: sys/netinet/ip_var.h =================================================================== RCS file: /mount/openbsd/cvs/src/sys/netinet/ip_var.h,v retrieving revision 1.88 diff -u -p -u -p -r1.88 ip_var.h --- sys/netinet/ip_var.h 30 Mar 2021 08:37:11 -0000 1.88 +++ sys/netinet/ip_var.h 16 Jul 2021 16:30:42 -0000 @@ -248,7 +248,6 @@ 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 *); -void ipintr(void); int ip_input_if(struct mbuf **, int *, int, int, struct ifnet *); int ip_deliver(struct mbuf **, int *, int, int); void ip_forward(struct mbuf *, struct ifnet *, struct rtentry *, int); Index: sys/netinet6/ip6_input.c =================================================================== RCS file: /mount/openbsd/cvs/src/sys/netinet6/ip6_input.c,v retrieving revision 1.237 diff -u -p -u -p -r1.237 ip6_input.c --- sys/netinet6/ip6_input.c 3 Jun 2021 04:47:54 -0000 1.237 +++ sys/netinet6/ip6_input.c 16 Jul 2021 16:30:42 -0000 @@ -115,11 +115,14 @@ #include #endif +struct niqueue ip6intrq = NIQUEUE_INITIALIZER(IPQ_MAXLEN, NETISR_IPV6); + struct cpumem *ip6counters; uint8_t ip6_soiikey[IP6_SOIIKEY_LEN]; int ip6_ours(struct mbuf **, int *, int, int); +int ip6_local(struct mbuf **, int *, int, int); int ip6_check_rh0hdr(struct mbuf *, int *); int ip6_hbhchcheck(struct mbuf *, int *, int *, int *); int ip6_hopopts_input(u_int32_t *, u_int32_t *, struct mbuf **, int *); @@ -162,6 +165,43 @@ ip6_init(void) ip6counters = counters_alloc(ip6s_ncounters); } +/* + * Enqueue packet for local delivery. Queuing is used as a boundary + * between the network layer (input/forward path) running with shared + * NET_RLOCK_IN_SOFTNET() and the transport layer needing it exclusively. + */ +int +ip6_ours(struct mbuf **mp, int *offp, int nxt, int af) +{ + /* We are already in a IPv4/IPv6 local deliver loop. */ + if (af != AF_UNSPEC) + return ip6_local(mp, offp, nxt, af); + + niq_enqueue(&ip6intrq, *mp); + *mp = NULL; + return IPPROTO_DONE; +} + +/* + * Dequeue and process locally delivered packets. + */ +void +ip6intr(void) +{ + struct mbuf *m; + int off, nxt; + + while ((m = niq_dequeue(&ip6intrq)) != NULL) { +#ifdef DIAGNOSTIC + if ((m->m_flags & M_PKTHDR) == 0) + panic("ip6intr no HDR"); +#endif + off = 0; + nxt = ip6_local(&m, &off, IPPROTO_IPV6, AF_UNSPEC); + KASSERT(nxt == IPPROTO_DONE); + } +} + void ipv6_input(struct ifnet *ifp, struct mbuf *m) { @@ -544,7 +584,7 @@ ip6_input_if(struct mbuf **mp, int *offp } int -ip6_ours(struct mbuf **mp, int *offp, int nxt, int af) +ip6_local(struct mbuf **mp, int *offp, int nxt, int af) { if (ip6_hbhchcheck(*mp, offp, &nxt, NULL)) return IPPROTO_DONE; @@ -1470,7 +1510,8 @@ ip6_sysctl(int *name, u_int namelen, voi NET_UNLOCK(); return (error); case IPV6CTL_IFQUEUE: - return (EOPNOTSUPP); + return (sysctl_niq(name + 1, namelen - 1, + oldp, oldlenp, newp, newlen, &ip6intrq)); case IPV6CTL_SOIIKEY: return (ip6_sysctl_soiikey(oldp, oldlenp, newp, newlen)); default: