| @@ -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 | } |
507 | err: | | 506 | err: |
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 | */ |
762 | void | | 761 | void |
763 | npf_conn_worker(npf_t *npf) | | 762 | npf_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 | */ |
773 | int | | 772 | int |
774 | npf_conndb_export(npf_t *npf, nvlist_t *nvl) | | 773 | npf_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 | |