Hi,
IPsec is not MP safe yet. To allow forwarding in parallel without
dirty hacks, it is better to protect IPsec input and output with
kernel lock. We do not loose much as crypto needs the kernel lock
anyway. From here we can refine the lock later.
Note that there is no kernel lock in the SPD lockup path. I want
to keep that lock free to allow fast forwarding with non IPsec
traffic.
There are still some races in special cases, but in general it works
with parallel IP input.
ok?
bluhm
Index: net/if_bridge.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/net/if_bridge.c,v
retrieving revision 1.361
diff -u -p -r1.361 if_bridge.c
--- net/if_bridge.c 3 Dec 2021 17:18:34 -0000 1.361
+++ net/if_bridge.c 22 Dec 2021 10:49:59 -0000
@@ -1625,12 +1625,15 @@ bridge_ipsec(struct ifnet *ifp, struct e
if ((af == AF_INET) &&
ip_mtudisc && (ip->ip_off & htons(IP_DF)) &&
tdb->tdb_mtu && ntohs(ip->ip_len) > tdb->tdb_mtu &&
- tdb->tdb_mtutimeout > gettime())
+ tdb->tdb_mtutimeout > gettime()) {
bridge_send_icmp_err(ifp, eh, m,
hassnap, llc, tdb->tdb_mtu,
ICMP_UNREACH, ICMP_UNREACH_NEEDFRAG);
- else
+ } else {
+ KERNEL_LOCK();
error = ipsp_process_packet(m, tdb, af, 0);
+ KERNEL_UNLOCK();
+ }
tdb_unref(tdb);
return (1);
} else
Index: netinet/ip_ah.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ip_ah.c,v
retrieving revision 1.171
diff -u -p -r1.171 ip_ah.c
--- netinet/ip_ah.c 20 Dec 2021 17:09:18 -0000 1.171
+++ netinet/ip_ah.c 22 Dec 2021 10:49:59 -0000
@@ -687,13 +687,11 @@ ah_input(struct mbuf **mp, struct tdb *t
crp->crp_buf = (caddr_t)m;
crp->crp_sid = tdb->tdb_cryptoid;
- KERNEL_LOCK();
while ((error = crypto_invoke(crp)) == EAGAIN) {
/* Reset the session ID */
if (tdb->tdb_cryptoid != 0)
tdb->tdb_cryptoid = crp->crp_sid;
}
- KERNEL_UNLOCK();
if (error) {
DPRINTF("crypto error %d", error);
ipsecstat_inc(ipsec_noxform);
@@ -1112,13 +1110,11 @@ ah_output(struct mbuf *m, struct tdb *td
crp->crp_buf = (caddr_t)m;
crp->crp_sid = tdb->tdb_cryptoid;
- KERNEL_LOCK();
while ((error = crypto_invoke(crp)) == EAGAIN) {
/* Reset the session ID */
if (tdb->tdb_cryptoid != 0)
tdb->tdb_cryptoid = crp->crp_sid;
}
- KERNEL_UNLOCK();
if (error) {
DPRINTF("crypto error %d", error);
ipsecstat_inc(ipsec_noxform);
Index: netinet/ip_esp.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ip_esp.c,v
retrieving revision 1.191
diff -u -p -r1.191 ip_esp.c
--- netinet/ip_esp.c 20 Dec 2021 17:09:18 -0000 1.191
+++ netinet/ip_esp.c 22 Dec 2021 10:49:59 -0000
@@ -502,13 +502,11 @@ esp_input(struct mbuf **mp, struct tdb *
crde->crd_len = plen;
}
- KERNEL_LOCK();
while ((error = crypto_invoke(crp)) == EAGAIN) {
/* Reset the session ID */
if (tdb->tdb_cryptoid != 0)
tdb->tdb_cryptoid = crp->crp_sid;
}
- KERNEL_UNLOCK();
if (error) {
DPRINTF("crypto error %d", error);
ipsecstat_inc(ipsec_noxform);
@@ -948,13 +946,11 @@ esp_output(struct mbuf *m, struct tdb *t
crda->crd_len = m->m_pkthdr.len - (skip + alen);
}
- KERNEL_LOCK();
while ((error = crypto_invoke(crp)) == EAGAIN) {
/* Reset the session ID */
if (tdb->tdb_cryptoid != 0)
tdb->tdb_cryptoid = crp->crp_sid;
}
- KERNEL_UNLOCK();
if (error) {
DPRINTF("crypto error %d", error);
ipsecstat_inc(ipsec_noxform);
Index: netinet/ip_ipcomp.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ip_ipcomp.c,v
retrieving revision 1.90
diff -u -p -r1.90 ip_ipcomp.c
--- netinet/ip_ipcomp.c 20 Dec 2021 15:59:09 -0000 1.90
+++ netinet/ip_ipcomp.c 22 Dec 2021 10:49:59 -0000
@@ -171,13 +171,11 @@ ipcomp_input(struct mbuf **mp, struct td
crp->crp_buf = (caddr_t)m;
crp->crp_sid = tdb->tdb_cryptoid;
- KERNEL_LOCK();
while ((error = crypto_invoke(crp)) == EAGAIN) {
/* Reset the session ID */
if (tdb->tdb_cryptoid != 0)
tdb->tdb_cryptoid = crp->crp_sid;
}
- KERNEL_UNLOCK();
if (error) {
DPRINTF("crypto error %d", error);
ipsecstat_inc(ipsec_noxform);
@@ -459,13 +457,11 @@ ipcomp_output(struct mbuf *m, struct tdb
crp->crp_buf = (caddr_t)m;
crp->crp_sid = tdb->tdb_cryptoid;
- KERNEL_LOCK();
while ((error = crypto_invoke(crp)) == EAGAIN) {
/* Reset the session ID */
if (tdb->tdb_cryptoid != 0)
tdb->tdb_cryptoid = crp->crp_sid;
}
- KERNEL_UNLOCK();
if (error) {
DPRINTF("crypto error %d", error);
ipsecstat_inc(ipsec_noxform);
Index: netinet/ip_output.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ip_output.c,v
retrieving revision 1.378
diff -u -p -r1.378 ip_output.c
--- netinet/ip_output.c 20 Dec 2021 15:59:10 -0000 1.378
+++ netinet/ip_output.c 22 Dec 2021 10:49:59 -0000
@@ -659,7 +659,9 @@ ip_output_ipsec_send(struct tdb *tdb, st
m->m_flags &= ~(M_MCAST | M_BCAST);
/* Callee frees mbuf */
+ KERNEL_LOCK();
error = ipsp_process_packet(m, tdb, AF_INET, 0);
+ KERNEL_UNLOCK();
if (error) {
ipsecstat_inc(ipsec_odrops);
tdbstat_inc(tdb, tdb_odrops);
Index: netinet/ipsec_input.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ipsec_input.c,v
retrieving revision 1.199
diff -u -p -r1.199 ipsec_input.c
--- netinet/ipsec_input.c 20 Dec 2021 15:59:10 -0000 1.199
+++ netinet/ipsec_input.c 22 Dec 2021 10:49:59 -0000
@@ -325,6 +325,7 @@ ipsec_common_input(struct mbuf **mp, int
m->m_pkthdr.ph_ifidx = encif->if_index;
}
+ KERNEL_LOCK();
/* Register first use, setup expiration timer. */
if (tdbp->tdb_first_use == 0) {
tdbp->tdb_first_use = gettime();
@@ -352,6 +353,7 @@ ipsec_common_input(struct mbuf **mp, int
tdbstat_inc(tdbp, tdb_idrops);
}
tdb_unref(tdbp);
+ KERNEL_UNLOCK();
return prot;
drop:
Index: netinet/ipsec_output.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ipsec_output.c,v
retrieving revision 1.95
diff -u -p -r1.95 ipsec_output.c
--- netinet/ipsec_output.c 20 Dec 2021 15:59:10 -0000 1.95
+++ netinet/ipsec_output.c 22 Dec 2021 10:49:59 -0000
@@ -512,6 +512,7 @@ ipsp_process_done(struct mbuf *m, struct
/* If there's another (bundled) TDB to apply, do so. */
tdbo = tdb_ref(tdb->tdb_onext);
if (tdbo != NULL) {
+ KERNEL_ASSERT_LOCKED();
error = ipsp_process_packet(m, tdbo,
tdb->tdb_dst.sa.sa_family, 0);
tdb_unref(tdbo);
Index: netinet6/ip6_output.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet6/ip6_output.c,v
retrieving revision 1.264
diff -u -p -r1.264 ip6_output.c
--- netinet6/ip6_output.c 20 Dec 2021 15:59:10 -0000 1.264
+++ netinet6/ip6_output.c 22 Dec 2021 10:49:59 -0000
@@ -2894,7 +2894,9 @@ ip6_output_ipsec_send(struct tdb *tdb, s
m->m_flags &= ~(M_BCAST | M_MCAST);
/* Callee frees mbuf */
+ KERNEL_LOCK();
error = ipsp_process_packet(m, tdb, AF_INET6, tunalready);
+ KERNEL_UNLOCK();
if (error) {
ipsecstat_inc(ipsec_odrops);
tdbstat_inc(tdb, tdb_odrops);