From 53fadfdcf4c145f77ce6badbc5a8706fe943c543 Mon Sep 17 00:00:00 2001 From: bluhm Date: Sun, 21 Aug 2022 11:44:53 +0000 Subject: [PATCH] Introduce a mutex per inpcb to serialize access to socket receive buffer. Later it may be used to protect more of the PCB or socket. In divert input replace the kernel lock with this mutex. OK mvs@ --- sys/netinet/in_pcb.c | 3 ++- sys/netinet/in_pcb.h | 4 +++- sys/netinet/ip_divert.c | 17 +++++------------ sys/netinet6/ip6_divert.c | 17 +++++------------ 4 files changed, 15 insertions(+), 26 deletions(-) diff --git a/sys/netinet/in_pcb.c b/sys/netinet/in_pcb.c index e5700bb1849..903a03b6d48 100644 --- a/sys/netinet/in_pcb.c +++ b/sys/netinet/in_pcb.c @@ -1,4 +1,4 @@ -/* $OpenBSD: in_pcb.c,v 1.270 2022/08/08 12:06:30 bluhm Exp $ */ +/* $OpenBSD: in_pcb.c,v 1.271 2022/08/21 11:44:53 bluhm Exp $ */ /* $NetBSD: in_pcb.c,v 1.25 1996/02/13 23:41:53 christos Exp $ */ /* @@ -236,6 +236,7 @@ in_pcballoc(struct socket *so, struct inpcbtable *table) inp->inp_table = table; inp->inp_socket = so; refcnt_init_trace(&inp->inp_refcnt, DT_REFCNT_IDX_INPCB); + mtx_init(&inp->inp_mtx, IPL_SOFTNET); inp->inp_seclevel[SL_AUTH] = IPSEC_AUTH_LEVEL_DEFAULT; inp->inp_seclevel[SL_ESP_TRANS] = IPSEC_ESP_TRANS_LEVEL_DEFAULT; inp->inp_seclevel[SL_ESP_NETWORK] = IPSEC_ESP_NETWORK_LEVEL_DEFAULT; diff --git a/sys/netinet/in_pcb.h b/sys/netinet/in_pcb.h index c14aa4b1f0d..9d19225bd50 100644 --- a/sys/netinet/in_pcb.h +++ b/sys/netinet/in_pcb.h @@ -1,4 +1,4 @@ -/* $OpenBSD: in_pcb.h,v 1.129 2022/05/15 09:12:20 dlg Exp $ */ +/* $OpenBSD: in_pcb.h,v 1.130 2022/08/21 11:44:53 bluhm Exp $ */ /* $NetBSD: in_pcb.h,v 1.14 1996/02/13 23:42:00 christos Exp $ */ /* @@ -79,6 +79,7 @@ * I immutable after creation * N net lock * t inpt_mtx pcb table mutex + * p inpcb_mtx pcb mutex */ struct pf_state_key; @@ -121,6 +122,7 @@ struct inpcb { #define inp_route inp_ru.ru_route #define inp_route6 inp_ru.ru_route6 struct refcnt inp_refcnt; /* refcount PCB, delay memory free */ + struct mutex inp_mtx; /* protect PCB and socket members */ int inp_flags; /* generic IP/datagram flags */ union { /* Header prototype. */ struct ip hu_ip; diff --git a/sys/netinet/ip_divert.c b/sys/netinet/ip_divert.c index b843fc96bf4..adf8b091098 100644 --- a/sys/netinet/ip_divert.c +++ b/sys/netinet/ip_divert.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_divert.c,v 1.70 2022/08/20 23:48:58 mvs Exp $ */ +/* $OpenBSD: ip_divert.c,v 1.71 2022/08/21 11:44:54 bluhm Exp $ */ /* * Copyright (c) 2009 Michele Marchetto @@ -228,22 +228,15 @@ divert_packet(struct mbuf *m, int dir, u_int16_t divert_port) if_put(ifp); } + mtx_enter(&inp->inp_mtx); so = inp->inp_socket; - /* - * XXXSMP sbappendaddr() is not MP safe and this function is called - * from pf with shared netlock. To call only one sbappendaddr() from - * divert_packet(), protect it with kernel lock. All other places - * call sbappendaddr() with exclusive net lock. This blocks - * divert_packet() as we have the shared lock. - */ - KERNEL_LOCK(); if (sbappendaddr(so, &so->so_rcv, sintosa(&sin), m, NULL) == 0) { - KERNEL_UNLOCK(); + mtx_leave(&inp->inp_mtx); divstat_inc(divs_fullsock); goto bad; } - sorwakeup(inp->inp_socket); - KERNEL_UNLOCK(); + mtx_leave(&inp->inp_mtx); + sorwakeup(so); in_pcbunref(inp); return; diff --git a/sys/netinet6/ip6_divert.c b/sys/netinet6/ip6_divert.c index bf7d4436bfe..679278ebc99 100644 --- a/sys/netinet6/ip6_divert.c +++ b/sys/netinet6/ip6_divert.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip6_divert.c,v 1.69 2022/08/20 23:48:58 mvs Exp $ */ +/* $OpenBSD: ip6_divert.c,v 1.70 2022/08/21 11:44:54 bluhm Exp $ */ /* * Copyright (c) 2009 Michele Marchetto @@ -234,22 +234,15 @@ divert6_packet(struct mbuf *m, int dir, u_int16_t divert_port) if_put(ifp); } + mtx_enter(&inp->inp_mtx); so = inp->inp_socket; - /* - * XXXSMP sbappendaddr() is not MP safe and this function is called - * from pf with shared netlock. To call only one sbappendaddr() from - * divert_packet(), protect it with kernel lock. All other places - * call sbappendaddr() with exclusive net lock. This blocks - * divert_packet() as we have the shared lock. - */ - KERNEL_LOCK(); if (sbappendaddr(so, &so->so_rcv, sin6tosa(&sin6), m, NULL) == 0) { - KERNEL_UNLOCK(); + mtx_leave(&inp->inp_mtx); div6stat_inc(div6s_fullsock); goto bad; } - sorwakeup(inp->inp_socket); - KERNEL_UNLOCK(); + mtx_leave(&inp->inp_mtx); + sorwakeup(so); in_pcbunref(inp); return; -- 2.20.1