summaryrefslogtreecommitdiff
path: root/sys/net
diff options
context:
space:
mode:
authorMartin Pieuchot <mpi@cvs.openbsd.org>2018-05-14 07:34:00 +0000
committerMartin Pieuchot <mpi@cvs.openbsd.org>2018-05-14 07:34:00 +0000
commita50c3525b460dd399538dfb713bf5519518ce4f7 (patch)
tree25e7ba8491a78107e708681599faf034a1768817 /sys/net
parent50dea7aecc6f766e892e6938148dad5c922da2e8 (diff)
Use a SRP list to protect pfkeyv2 sockets, thus removing the need to
grab the KERNEL_LOCK() when delivering messages. This is the same solution already used by routing sockets. ok claudio@, visa@
Diffstat (limited to 'sys/net')
-rw-r--r--sys/net/pfkeyv2.c96
-rw-r--r--sys/net/rtsock.c19
2 files changed, 72 insertions, 43 deletions
diff --git a/sys/net/pfkeyv2.c b/sys/net/pfkeyv2.c
index 50bc080f374..b5f09bba123 100644
--- a/sys/net/pfkeyv2.c
+++ b/sys/net/pfkeyv2.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pfkeyv2.c,v 1.177 2018/05/08 14:10:43 mpi Exp $ */
+/* $OpenBSD: pfkeyv2.c,v 1.178 2018/05/14 07:33:58 mpi Exp $ */
/*
* @(#)COPYRIGHT 1.1 (NRL) 17 January 1995
@@ -133,12 +133,13 @@ struct sockaddr pfkey_addr = { 2, PF_KEY, };
struct domain pfkeydomain;
struct keycb {
- struct rawcb rcb;
- LIST_ENTRY(keycb) kcb_list;
- int flags;
- uint32_t pid;
- uint32_t registration; /* Increase size if SATYPE_MAX > 31 */
- uint rdomain;
+ struct rawcb rcb;
+ SRPL_ENTRY(keycb) kcb_list;
+ struct refcnt refcnt;
+ int flags;
+ uint32_t pid;
+ uint32_t registration; /* Increase if SATYPE_MAX > 31 */
+ unsigned int rdomain;
};
#define sotokeycb(so) ((struct keycb *)(so)->so_pcb)
@@ -148,9 +149,13 @@ struct dump_state {
struct socket *socket;
};
-/* Static globals */
-static LIST_HEAD(, keycb) pfkeyv2_sockets = LIST_HEAD_INITIALIZER(keycb);
+struct pfkey_cb {
+ SRPL_HEAD(, keycb) kcb;
+ struct srpl_rc kcb_rc;
+ struct rwlock kcb_lk;
+};
+struct pfkey_cb pfkey_cb;
struct mutex pfkeyv2_mtx = MUTEX_INITIALIZER(IPL_NONE);
static uint32_t pfkeyv2_seq = 1;
static int nregistered = 0;
@@ -169,6 +174,9 @@ int pfkeyv2_sa_flush(struct tdb *, void *, int);
int pfkeyv2_policy_flush(struct ipsec_policy *, void *, unsigned int);
int pfkeyv2_sysctl_policydumper(struct ipsec_policy *, void *, unsigned int);
+void keycb_ref(void *, void *);
+void keycb_unref(void *, void *);
+
/*
* Wrapper around m_devget(); copy data from contiguous buffer to mbuf
* chain.
@@ -208,9 +216,28 @@ struct domain pfkeydomain = {
};
void
+keycb_ref(void *null, void *v)
+{
+ struct keycb *kp = v;
+
+ refcnt_take(&kp->refcnt);
+}
+
+void
+keycb_unref(void *null, void *v)
+{
+ struct keycb *kp = v;
+
+ refcnt_rele_wake(&kp->refcnt);
+}
+
+void
pfkey_init(void)
{
rn_init(sizeof(struct sockaddr_encap));
+ srpl_rc_init(&pfkey_cb.kcb_rc, keycb_ref, keycb_unref, NULL);
+ rw_init(&pfkey_cb.kcb_lk, "pfkey");
+ SRPL_INIT(&pfkey_cb.kcb);
}
@@ -230,6 +257,7 @@ pfkeyv2_attach(struct socket *so, int proto)
kp = malloc(sizeof(struct keycb), M_PCB, M_WAITOK | M_ZERO);
rp = &kp->rcb;
so->so_pcb = rp;
+ refcnt_init(&kp->refcnt);
error = soreserve(so, RAWSNDQ, RAWRCVQ);
@@ -254,7 +282,9 @@ pfkeyv2_attach(struct socket *so, int proto)
*/
kp->rdomain = rtable_l2(curproc->p_p->ps_rtableid);
- LIST_INSERT_HEAD(&pfkeyv2_sockets, kp, kcb_list);
+ rw_enter(&pfkey_cb.kcb_lk, RW_WRITE);
+ SRPL_INSERT_HEAD_LOCKED(&pfkey_cb.kcb_rc, &pfkey_cb.kcb, kp, kcb_list);
+ rw_exit(&pfkey_cb.kcb_lk);
return (0);
}
@@ -267,12 +297,12 @@ pfkeyv2_detach(struct socket *so)
{
struct keycb *kp;
+ soassertlocked(so);
+
kp = sotokeycb(so);
if (kp == NULL)
return ENOTCONN;
- LIST_REMOVE(kp, kcb_list);
-
if (kp->flags &
(PFKEYV2_SOCKETFLAGS_REGISTERED|PFKEYV2_SOCKETFLAGS_PROMISC)) {
mtx_enter(&pfkeyv2_mtx);
@@ -284,6 +314,14 @@ pfkeyv2_detach(struct socket *so)
mtx_leave(&pfkeyv2_mtx);
}
+ rw_enter(&pfkey_cb.kcb_lk, RW_WRITE);
+ SRPL_REMOVE_LOCKED(&pfkey_cb.kcb_rc, &pfkey_cb.kcb,
+ kp, keycb, kcb_list);
+ rw_exit(&pfkey_cb.kcb_lk);
+
+ /* wait for all references to drop */
+ refcnt_finalize(&kp->refcnt, "pfkeyrefs");
+
so->so_pcb = NULL;
sofree(so);
free(kp, M_PCB, sizeof(struct keycb));
@@ -337,8 +375,6 @@ pfkey_sendup(struct keycb *kp, struct mbuf *m0, int more)
struct socket *so = kp->rcb.rcb_socket;
struct mbuf *m;
- NET_ASSERT_LOCKED();
-
if (more) {
if (!(m = m_dup_pkt(m0, 0, M_DONTWAIT)))
return (ENOMEM);
@@ -368,6 +404,7 @@ pfkeyv2_sendmessage(void **headers, int mode, struct socket *so,
struct mbuf *packet;
struct keycb *s;
struct sadb_msg *smsg;
+ struct srp_ref sr;
/* Find out how much space we'll need... */
j = sizeof(struct sadb_msg);
@@ -430,14 +467,13 @@ pfkeyv2_sendmessage(void **headers, int mode, struct socket *so,
* Search for promiscuous listeners, skipping the
* original destination.
*/
- KERNEL_LOCK();
- LIST_FOREACH(s, &pfkeyv2_sockets, kcb_list) {
+ SRPL_FOREACH(s, &sr, &pfkey_cb.kcb, kcb_list) {
if ((s->flags & PFKEYV2_SOCKETFLAGS_PROMISC) &&
(s->rcb.rcb_socket != so) &&
(s->rdomain == rdomain))
pfkey_sendup(s, packet, 1);
}
- KERNEL_UNLOCK();
+ SRPL_LEAVE(&sr);
m_freem(packet);
break;
@@ -446,8 +482,7 @@ pfkeyv2_sendmessage(void **headers, int mode, struct socket *so,
* Send the message to all registered sockets that match
* the specified satype (e.g., all IPSEC-ESP negotiators)
*/
- KERNEL_LOCK();
- LIST_FOREACH(s, &pfkeyv2_sockets, kcb_list) {
+ SRPL_FOREACH(s, &sr, &pfkey_cb.kcb, kcb_list) {
if ((s->flags & PFKEYV2_SOCKETFLAGS_REGISTERED) &&
(s->rdomain == rdomain)) {
if (!satype) /* Just send to everyone registered */
@@ -459,7 +494,7 @@ pfkeyv2_sendmessage(void **headers, int mode, struct socket *so,
}
}
}
- KERNEL_UNLOCK();
+ SRPL_LEAVE(&sr);
/* Free last/original copy of the packet */
m_freem(packet);
@@ -478,25 +513,23 @@ pfkeyv2_sendmessage(void **headers, int mode, struct socket *so,
goto ret;
/* Send to all registered promiscuous listeners */
- KERNEL_LOCK();
- LIST_FOREACH(s, &pfkeyv2_sockets, kcb_list) {
+ SRPL_FOREACH(s, &sr, &pfkey_cb.kcb, kcb_list) {
if ((s->flags & PFKEYV2_SOCKETFLAGS_PROMISC) &&
!(s->flags & PFKEYV2_SOCKETFLAGS_REGISTERED) &&
(s->rdomain == rdomain))
pfkey_sendup(s, packet, 1);
}
- KERNEL_UNLOCK();
+ SRPL_LEAVE(&sr);
m_freem(packet);
break;
case PFKEYV2_SENDMESSAGE_BROADCAST:
/* Send message to all sockets */
- KERNEL_LOCK();
- LIST_FOREACH(s, &pfkeyv2_sockets, kcb_list) {
+ SRPL_FOREACH(s, &sr, &pfkey_cb.kcb, kcb_list) {
if (s->rdomain == rdomain)
pfkey_sendup(s, packet, 1);
}
- KERNEL_UNLOCK();
+ SRPL_LEAVE(&sr);
m_freem(packet);
break;
}
@@ -973,6 +1006,7 @@ pfkeyv2_send(struct socket *so, void *message, int len)
struct sadb_sa *ssa;
struct sadb_supported *ssup;
struct sadb_ident *sid, *did;
+ struct srp_ref sr;
u_int rdomain;
int promisc;
@@ -1020,13 +1054,12 @@ pfkeyv2_send(struct socket *so, void *message, int len)
goto ret;
/* Send to all promiscuous listeners */
- KERNEL_LOCK();
- LIST_FOREACH(bkp, &pfkeyv2_sockets, kcb_list) {
+ SRPL_FOREACH(bkp, &sr, &pfkey_cb.kcb, kcb_list) {
if ((bkp->flags & PFKEYV2_SOCKETFLAGS_PROMISC) &&
(bkp->rdomain == rdomain))
pfkey_sendup(bkp, packet, 1);
}
- KERNEL_UNLOCK();
+ SRPL_LEAVE(&sr);
m_freem(packet);
@@ -1795,15 +1828,14 @@ pfkeyv2_send(struct socket *so, void *message, int len)
if ((rval = pfdatatopacket(message, len, &packet)) != 0)
goto ret;
- KERNEL_LOCK();
- LIST_FOREACH(bkp, &pfkeyv2_sockets, kcb_list) {
+ SRPL_FOREACH(bkp, &sr, &pfkey_cb.kcb, kcb_list) {
if ((bkp != kp) &&
(bkp->rdomain == rdomain) &&
(!smsg->sadb_msg_seq ||
(smsg->sadb_msg_seq == kp->pid)))
pfkey_sendup(bkp, packet, 1);
}
- KERNEL_UNLOCK();
+ SRPL_LEAVE(&sr);
m_freem(packet);
} else {
diff --git a/sys/net/rtsock.c b/sys/net/rtsock.c
index b1046c7882a..6a91c13c2ed 100644
--- a/sys/net/rtsock.c
+++ b/sys/net/rtsock.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rtsock.c,v 1.264 2018/05/08 14:10:43 mpi Exp $ */
+/* $OpenBSD: rtsock.c,v 1.265 2018/05/14 07:33:59 mpi Exp $ */
/* $NetBSD: rtsock.c,v 1.18 1996/03/29 00:32:10 cgd Exp $ */
/*
@@ -103,8 +103,8 @@ struct walkarg {
};
void route_prinit(void);
-void route_ref(void *, void *);
-void route_unref(void *, void *);
+void rcb_ref(void *, void *);
+void rcb_unref(void *, void *);
int route_output(struct mbuf *, struct socket *, struct sockaddr *,
struct mbuf *);
int route_ctloutput(int, struct socket *, int, int, struct mbuf *);
@@ -169,13 +169,13 @@ struct route_cb route_cb;
void
route_prinit(void)
{
- srpl_rc_init(&route_cb.rcb_rc, route_ref, route_unref, NULL);
+ srpl_rc_init(&route_cb.rcb_rc, rcb_ref, rcb_unref, NULL);
rw_init(&route_cb.rcb_lk, "rtsock");
SRPL_INIT(&route_cb.rcb);
}
void
-route_ref(void *null, void *v)
+rcb_ref(void *null, void *v)
{
struct routecb *rop = v;
@@ -183,7 +183,7 @@ route_ref(void *null, void *v)
}
void
-route_unref(void *null, void *v)
+rcb_unref(void *null, void *v)
{
struct routecb *rop = v;
@@ -265,10 +265,8 @@ route_attach(struct socket *so, int proto)
rp->rcb_faddr = &route_src;
rw_enter(&route_cb.rcb_lk, RW_WRITE);
-
SRPL_INSERT_HEAD_LOCKED(&route_cb.rcb_rc, &route_cb.rcb, rop, rcb_list);
route_cb.any_count++;
-
rw_exit(&route_cb.rcb_lk);
return (0);
@@ -292,8 +290,8 @@ route_detach(struct socket *so)
SRPL_REMOVE_LOCKED(&route_cb.rcb_rc, &route_cb.rcb,
rop, routecb, rcb_list);
-
rw_exit(&route_cb.rcb_lk);
+
/* wait for all references to drop */
refcnt_finalize(&rop->refcnt, "rtsockrefs");
@@ -487,14 +485,13 @@ route_input(struct mbuf *m0, struct socket *so, sa_family_t sa_family)
refcnt_take(&rop->refcnt);
last = rop->rcb.rcb_socket;
}
+ SRPL_LEAVE(&sr);
if (last) {
rtm_sendup(last, m, 0);
refcnt_rele_wake(&sotoroutecb(last)->refcnt);
} else
m_freem(m);
-
- SRPL_LEAVE(&sr);
}
int