Sun Feb 13 19:20:23 2022 UTC ()
npf(4): Use atomic_store_release and atomic_load_consume for conn_db.

...or atomic_load_relaxed, when npf->conn_lock is held, for the sake
of C11.

No need for store-before-load implied by membar_sync.


(riastradh)
diff -r1.33 -r1.34 src/sys/net/npf/npf_conn.c

cvs diff -r1.33 -r1.34 src/sys/net/npf/npf_conn.c (expand / switch to unified diff)

--- src/sys/net/npf/npf_conn.c 2021/01/25 17:18:55 1.33
+++ src/sys/net/npf/npf_conn.c 2022/02/13 19:20:23 1.34
@@ -94,27 +94,27 @@ @@ -94,27 +94,27 @@
94 * performing their own lookup using different key. Recursive call 94 * performing their own lookup using different key. Recursive call
95 * to npf_conn_inspect() is not allowed. The ALGs ought to use the 95 * to npf_conn_inspect() is not allowed. The ALGs ought to use the
96 * npf_conn_lookup() function for this purpose. 96 * npf_conn_lookup() function for this purpose.
97 * 97 *
98 * Lock order 98 * Lock order
99 * 99 *
100 * npf->config_lock -> 100 * npf->config_lock ->
101 * conn_lock -> 101 * conn_lock ->
102 * npf_conn_t::c_lock 102 * npf_conn_t::c_lock
103 */ 103 */
104 104
105#ifdef _KERNEL 105#ifdef _KERNEL
106#include <sys/cdefs.h> 106#include <sys/cdefs.h>
107__KERNEL_RCSID(0, "$NetBSD: npf_conn.c,v 1.33 2021/01/25 17:18:55 christos Exp $"); 107__KERNEL_RCSID(0, "$NetBSD: npf_conn.c,v 1.34 2022/02/13 19:20:23 riastradh Exp $");
108 108
109#include <sys/param.h> 109#include <sys/param.h>
110#include <sys/types.h> 110#include <sys/types.h>
111 111
112#include <netinet/in.h> 112#include <netinet/in.h>
113#include <netinet/tcp.h> 113#include <netinet/tcp.h>
114 114
115#include <sys/atomic.h> 115#include <sys/atomic.h>
116#include <sys/kmem.h> 116#include <sys/kmem.h>
117#include <sys/mutex.h> 117#include <sys/mutex.h>
118#include <net/pfil.h> 118#include <net/pfil.h>
119#include <sys/pool.h> 119#include <sys/pool.h>
120#include <sys/queue.h> 120#include <sys/queue.h>
@@ -211,28 +211,27 @@ npf_conn_load(npf_t *npf, npf_conndb_t * @@ -211,28 +211,27 @@ npf_conn_load(npf_t *npf, npf_conndb_t *
211 npf_conndb_t *odb = NULL; 211 npf_conndb_t *odb = NULL;
212 212
213 KASSERT(npf_config_locked_p(npf)); 213 KASSERT(npf_config_locked_p(npf));
214 214
215 /* 215 /*
216 * The connection database is in the quiescent state. 216 * The connection database is in the quiescent state.
217 * Prevent G/C thread from running and install a new database. 217 * Prevent G/C thread from running and install a new database.
218 */ 218 */
219 mutex_enter(&npf->conn_lock); 219 mutex_enter(&npf->conn_lock);
220 if (ndb) { 220 if (ndb) {
221 KASSERT(atomic_load_relaxed(&npf->conn_tracking) 221 KASSERT(atomic_load_relaxed(&npf->conn_tracking)
222 == CONN_TRACKING_OFF); 222 == CONN_TRACKING_OFF);
223 odb = atomic_load_relaxed(&npf->conn_db); 223 odb = atomic_load_relaxed(&npf->conn_db);
224 membar_sync(); 224 atomic_store_release(&npf->conn_db, ndb);
225 atomic_store_relaxed(&npf->conn_db, ndb); 
226 } 225 }
227 if (track) { 226 if (track) {
228 /* After this point lookups start flying in. */ 227 /* After this point lookups start flying in. */
229 membar_producer(); 228 membar_producer();
230 atomic_store_relaxed(&npf->conn_tracking, CONN_TRACKING_ON); 229 atomic_store_relaxed(&npf->conn_tracking, CONN_TRACKING_ON);
231 } 230 }
232 mutex_exit(&npf->conn_lock); 231 mutex_exit(&npf->conn_lock);
233 232
234 if (odb) { 233 if (odb) {
235 /* 234 /*
236 * Flush all, no sync since the caller did it for us. 235 * Flush all, no sync since the caller did it for us.
237 * Also, release the pool cache memory. 236 * Also, release the pool cache memory.
238 */ 237 */
@@ -482,27 +481,27 @@ npf_conn_establish(npf_cache_t *npc, con @@ -482,27 +481,27 @@ npf_conn_establish(npf_cache_t *npc, con
482 /* 481 /*
483 * Set last activity time for a new connection and acquire 482 * Set last activity time for a new connection and acquire
484 * a reference for the caller before we make it visible. 483 * a reference for the caller before we make it visible.
485 */ 484 */
486 conn_update_atime(con); 485 conn_update_atime(con);
487 atomic_store_relaxed(&con->c_refcnt, 1); 486 atomic_store_relaxed(&con->c_refcnt, 1);
488 487
489 /* 488 /*
490 * Insert both keys (entries representing directions) of the 489 * Insert both keys (entries representing directions) of the
491 * connection. At this point it becomes visible, but we activate 490 * connection. At this point it becomes visible, but we activate
492 * the connection later. 491 * the connection later.
493 */ 492 */
494 mutex_enter(&con->c_lock); 493 mutex_enter(&con->c_lock);
495 conn_db = atomic_load_relaxed(&npf->conn_db); 494 conn_db = atomic_load_consume(&npf->conn_db);
496 if (!npf_conndb_insert(conn_db, fw, con, NPF_FLOW_FORW)) { 495 if (!npf_conndb_insert(conn_db, fw, con, NPF_FLOW_FORW)) {
497 error = EISCONN; 496 error = EISCONN;
498 goto err; 497 goto err;
499 } 498 }
500 if (!npf_conndb_insert(conn_db, bk, con, NPF_FLOW_BACK)) { 499 if (!npf_conndb_insert(conn_db, bk, con, NPF_FLOW_BACK)) {
501 npf_conn_t *ret __diagused; 500 npf_conn_t *ret __diagused;
502 ret = npf_conndb_remove(conn_db, fw); 501 ret = npf_conndb_remove(conn_db, fw);
503 KASSERT(ret == con); 502 KASSERT(ret == con);
504 error = EISCONN; 503 error = EISCONN;
505 goto err; 504 goto err;
506 } 505 }
507err: 506err:
508 /* 507 /*
@@ -587,27 +586,27 @@ npf_conn_setnat(const npf_cache_t *npc,  @@ -587,27 +586,27 @@ npf_conn_setnat(const npf_cache_t *npc,
587 mutex_exit(&con->c_lock); 586 mutex_exit(&con->c_lock);
588 return EINVAL; 587 return EINVAL;
589 } 588 }
590 KASSERT((flags & CONN_REMOVED) == 0); 589 KASSERT((flags & CONN_REMOVED) == 0);
591 590
592 if (__predict_false(con->c_nat != NULL)) { 591 if (__predict_false(con->c_nat != NULL)) {
593 /* Race with a duplicate packet. */ 592 /* Race with a duplicate packet. */
594 mutex_exit(&con->c_lock); 593 mutex_exit(&con->c_lock);
595 npf_stats_inc(npc->npc_ctx, NPF_STAT_RACE_NAT); 594 npf_stats_inc(npc->npc_ctx, NPF_STAT_RACE_NAT);
596 return EISCONN; 595 return EISCONN;
597 } 596 }
598 597
599 /* Remove the "backwards" key. */ 598 /* Remove the "backwards" key. */
600 conn_db = atomic_load_relaxed(&npf->conn_db); 599 conn_db = atomic_load_consume(&npf->conn_db);
601 bk = npf_conn_getbackkey(con, con->c_alen); 600 bk = npf_conn_getbackkey(con, con->c_alen);
602 ret = npf_conndb_remove(conn_db, bk); 601 ret = npf_conndb_remove(conn_db, bk);
603 KASSERT(ret == con); 602 KASSERT(ret == con);
604 603
605 /* Set the source/destination IDs to the translation values. */ 604 /* Set the source/destination IDs to the translation values. */
606 npf_conn_adjkey(bk, taddr, tport, nat_type_which[ntype]); 605 npf_conn_adjkey(bk, taddr, tport, nat_type_which[ntype]);
607 606
608 /* Finally, re-insert the "backwards" key. */ 607 /* Finally, re-insert the "backwards" key. */
609 if (!npf_conndb_insert(conn_db, bk, con, NPF_FLOW_BACK)) { 608 if (!npf_conndb_insert(conn_db, bk, con, NPF_FLOW_BACK)) {
610 /* 609 /*
611 * Race: we have hit the duplicate, remove the "forwards" 610 * Race: we have hit the duplicate, remove the "forwards"
612 * key and expire our connection; it is no longer valid. 611 * key and expire our connection; it is no longer valid.
613 */ 612 */
@@ -752,27 +751,27 @@ npf_conn_remove(npf_conndb_t *cd, npf_co @@ -752,27 +751,27 @@ npf_conn_remove(npf_conndb_t *cd, npf_co
752 } 751 }
753 752
754 /* Flag the removal and expiration. */ 753 /* Flag the removal and expiration. */
755 atomic_or_uint(&con->c_flags, CONN_REMOVED | CONN_EXPIRE); 754 atomic_or_uint(&con->c_flags, CONN_REMOVED | CONN_EXPIRE);
756 mutex_exit(&con->c_lock); 755 mutex_exit(&con->c_lock);
757} 756}
758 757
759/* 758/*
760 * npf_conn_worker: G/C to run from a worker thread or via npfk_gc(). 759 * npf_conn_worker: G/C to run from a worker thread or via npfk_gc().
761 */ 760 */
762void 761void
763npf_conn_worker(npf_t *npf) 762npf_conn_worker(npf_t *npf)
764{ 763{
765 npf_conndb_t *conn_db = atomic_load_relaxed(&npf->conn_db); 764 npf_conndb_t *conn_db = atomic_load_consume(&npf->conn_db);
766 npf_conndb_gc(npf, conn_db, false, true); 765 npf_conndb_gc(npf, conn_db, false, true);
767} 766}
768 767
769/* 768/*
770 * npf_conndb_export: construct a list of connections prepared for saving. 769 * npf_conndb_export: construct a list of connections prepared for saving.
771 * Note: this is expected to be an expensive operation. 770 * Note: this is expected to be an expensive operation.
772 */ 771 */
773int 772int
774npf_conndb_export(npf_t *npf, nvlist_t *nvl) 773npf_conndb_export(npf_t *npf, nvlist_t *nvl)
775{ 774{
776 npf_conn_t *head, *con; 775 npf_conn_t *head, *con;
777 npf_conndb_t *conn_db; 776 npf_conndb_t *conn_db;
778 777