[BACK]Return to npf_conn.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / net / npf

Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.

Diff for /src/sys/net/npf/npf_conn.c between version 1.21 and 1.22

version 1.21, 2016/12/10 22:09:49 version 1.22, 2016/12/26 23:05:06
Line 98 
Line 98 
  *                      npf_conn_t::c_lock   *                      npf_conn_t::c_lock
  */   */
   
   #ifdef _KERNEL
 #include <sys/cdefs.h>  #include <sys/cdefs.h>
 __KERNEL_RCSID(0, "$NetBSD$");  __KERNEL_RCSID(0, "$NetBSD$");
   
Line 116  __KERNEL_RCSID(0, "$NetBSD$");
Line 117  __KERNEL_RCSID(0, "$NetBSD$");
 #include <sys/pool.h>  #include <sys/pool.h>
 #include <sys/queue.h>  #include <sys/queue.h>
 #include <sys/systm.h>  #include <sys/systm.h>
   #endif
   
 #define __NPF_CONN_PRIVATE  #define __NPF_CONN_PRIVATE
 #include "npf_conn.h"  #include "npf_conn.h"
Line 130  CTASSERT(PFIL_ALL == (0x001 | 0x002));
Line 132  CTASSERT(PFIL_ALL == (0x001 | 0x002));
 #define CONN_EXPIRE     0x010   /* explicitly expire */  #define CONN_EXPIRE     0x010   /* explicitly expire */
 #define CONN_REMOVED    0x020   /* "forw/back" entries removed */  #define CONN_REMOVED    0x020   /* "forw/back" entries removed */
   
 /*  
  * Connection tracking state: disabled (off) or enabled (on).  
  */  
 enum { CONN_TRACKING_OFF, CONN_TRACKING_ON };  enum { CONN_TRACKING_OFF, CONN_TRACKING_ON };
 static volatile int     conn_tracking   __cacheline_aligned;  
   
 /* Connection tracking database, connection cache and the lock. */  static void     npf_conn_destroy(npf_t *, npf_conn_t *);
 static npf_conndb_t *   conn_db         __read_mostly;  
 static pool_cache_t     conn_cache      __read_mostly;  
 static kmutex_t         conn_lock       __cacheline_aligned;  
   
 static void     npf_conn_worker(void);  
 static void     npf_conn_destroy(npf_conn_t *);  
   
 /*  /*
  * npf_conn_sys{init,fini}: initialise/destroy connection tracking.   * npf_conn_sys{init,fini}: initialise/destroy connection tracking.
  */   */
   
 void  void
 npf_conn_sysinit(void)  npf_conn_init(npf_t *npf, int flags)
 {  {
         conn_cache = pool_cache_init(sizeof(npf_conn_t), coherency_unit,          npf->conn_cache = pool_cache_init(sizeof(npf_conn_t), coherency_unit,
             0, 0, "npfconpl", NULL, IPL_NET, NULL, NULL, NULL);              0, 0, "npfconpl", NULL, IPL_NET, NULL, NULL, NULL);
         mutex_init(&conn_lock, MUTEX_DEFAULT, IPL_NONE);          mutex_init(&npf->conn_lock, MUTEX_DEFAULT, IPL_NONE);
         conn_tracking = CONN_TRACKING_OFF;          npf->conn_tracking = CONN_TRACKING_OFF;
         conn_db = npf_conndb_create();          npf->conn_db = npf_conndb_create();
   
         npf_worker_register(npf_conn_worker);          if ((flags & NPF_NO_GC) == 0) {
                   npf_worker_register(npf, npf_conn_worker);
           }
 }  }
   
 void  void
 npf_conn_sysfini(void)  npf_conn_fini(npf_t *npf)
 {  {
         /* Note: the caller should have flushed the connections. */          /* Note: the caller should have flushed the connections. */
         KASSERT(conn_tracking == CONN_TRACKING_OFF);          KASSERT(npf->conn_tracking == CONN_TRACKING_OFF);
         npf_worker_unregister(npf_conn_worker);          npf_worker_unregister(npf, npf_conn_worker);
   
         npf_conndb_destroy(conn_db);          npf_conndb_destroy(npf->conn_db);
         pool_cache_destroy(conn_cache);          pool_cache_destroy(npf->conn_cache);
         mutex_destroy(&conn_lock);          mutex_destroy(&npf->conn_lock);
 }  }
   
 /*  /*
Line 180  npf_conn_sysfini(void)
Line 174  npf_conn_sysfini(void)
  *    there are no connection database lookups or references in-flight.   *    there are no connection database lookups or references in-flight.
  */   */
 void  void
 npf_conn_load(npf_conndb_t *ndb, bool track)  npf_conn_load(npf_t *npf, npf_conndb_t *ndb, bool track)
 {  {
         npf_conndb_t *odb = NULL;          npf_conndb_t *odb = NULL;
   
         KASSERT(npf_config_locked_p());          KASSERT(npf_config_locked_p(npf));
   
         /*          /*
          * The connection database is in the quiescent state.           * The connection database is in the quiescent state.
          * Prevent G/C thread from running and install a new database.           * Prevent G/C thread from running and install a new database.
          */           */
         mutex_enter(&conn_lock);          mutex_enter(&npf->conn_lock);
         if (ndb) {          if (ndb) {
                 KASSERT(conn_tracking == CONN_TRACKING_OFF);                  KASSERT(npf->conn_tracking == CONN_TRACKING_OFF);
                 odb = conn_db;                  odb = npf->conn_db;
                 conn_db = ndb;                  npf->conn_db = ndb;
                 membar_sync();                  membar_sync();
         }          }
         if (track) {          if (track) {
                 /* After this point lookups start flying in. */                  /* After this point lookups start flying in. */
                 conn_tracking = CONN_TRACKING_ON;                  npf->conn_tracking = CONN_TRACKING_ON;
         }          }
         mutex_exit(&conn_lock);          mutex_exit(&npf->conn_lock);
   
         if (odb) {          if (odb) {
                 /*                  /*
                  * Flush all, no sync since the caller did it for us.                   * Flush all, no sync since the caller did it for us.
                  * Also, release the pool cache memory.                   * Also, release the pool cache memory.
                  */                   */
                 npf_conn_gc(odb, true, false);                  npf_conn_gc(npf, odb, true, false);
                 npf_conndb_destroy(odb);                  npf_conndb_destroy(odb);
                 pool_cache_invalidate(conn_cache);                  pool_cache_invalidate(npf->conn_cache);
         }          }
 }  }
   
Line 218  npf_conn_load(npf_conndb_t *ndb, bool tr
Line 212  npf_conn_load(npf_conndb_t *ndb, bool tr
  * npf_conn_tracking: enable/disable connection tracking.   * npf_conn_tracking: enable/disable connection tracking.
  */   */
 void  void
 npf_conn_tracking(bool track)  npf_conn_tracking(npf_t *npf, bool track)
 {  {
         KASSERT(npf_config_locked_p());          KASSERT(npf_config_locked_p(npf));
         conn_tracking = track ? CONN_TRACKING_ON : CONN_TRACKING_OFF;          npf->conn_tracking = track ? CONN_TRACKING_ON : CONN_TRACKING_OFF;
 }  }
   
 static inline bool  static inline bool
 npf_conn_trackable_p(const npf_cache_t *npc)  npf_conn_trackable_p(const npf_cache_t *npc)
 {  {
           const npf_t *npf = npc->npc_ctx;
   
         /*          /*
          * Check if connection tracking is on.  Also, if layer 3 and 4 are           * Check if connection tracking is on.  Also, if layer 3 and 4 are
          * not cached - protocol is not supported or packet is invalid.           * not cached - protocol is not supported or packet is invalid.
          */           */
         if (conn_tracking != CONN_TRACKING_ON) {          if (npf->conn_tracking != CONN_TRACKING_ON) {
                 return false;                  return false;
         }          }
         if (!npf_iscached(npc, NPC_IP46) || !npf_iscached(npc, NPC_LAYER4)) {          if (!npf_iscached(npc, NPC_IP46) || !npf_iscached(npc, NPC_LAYER4)) {
Line 242  npf_conn_trackable_p(const npf_cache_t *
Line 238  npf_conn_trackable_p(const npf_cache_t *
   
 static uint32_t  static uint32_t
 connkey_setkey(npf_connkey_t *key, uint16_t proto, const void *ipv,  connkey_setkey(npf_connkey_t *key, uint16_t proto, const void *ipv,
     const uint16_t *id, uint16_t alen, bool forw)      const uint16_t *id, unsigned alen, bool forw)
 {  {
         uint32_t isrc, idst, *k = key->ck_key;          uint32_t isrc, idst, *k = key->ck_key;
         const npf_addr_t * const *ips = ipv;          const npf_addr_t * const *ips = ipv;
   
         if (__predict_true(forw)) {          if (__predict_true(forw)) {
                 isrc = NPF_SRC, idst = NPF_DST;                  isrc = NPF_SRC, idst = NPF_DST;
         } else {          } else {
Line 268  connkey_setkey(npf_connkey_t *key, uint1
Line 265  connkey_setkey(npf_connkey_t *key, uint1
         k[1] = ((uint32_t)id[isrc] << 16) | id[idst];          k[1] = ((uint32_t)id[isrc] << 16) | id[idst];
   
         if (__predict_true(alen == sizeof(in_addr_t))) {          if (__predict_true(alen == sizeof(in_addr_t))) {
                 k[2] = ips[isrc]->s6_addr32[0];                  k[2] = ips[isrc]->word32[0];
                 k[3] = ips[idst]->s6_addr32[0];                  k[3] = ips[idst]->word32[0];
                 return 4 * sizeof(uint32_t);                  return 4 * sizeof(uint32_t);
         } else {          } else {
                 const u_int nwords = alen >> 2;                  const u_int nwords = alen >> 2;
Line 309  connkey_getkey(const npf_connkey_t *key,
Line 306  connkey_getkey(const npf_connkey_t *key,
 unsigned  unsigned
 npf_conn_conkey(const npf_cache_t *npc, npf_connkey_t *key, const bool forw)  npf_conn_conkey(const npf_cache_t *npc, npf_connkey_t *key, const bool forw)
 {  {
         const uint16_t alen = npc->npc_alen;          const u_int proto = npc->npc_proto;
           const u_int alen = npc->npc_alen;
         const struct tcphdr *th;          const struct tcphdr *th;
         const struct udphdr *uh;          const struct udphdr *uh;
         uint16_t id[2];          uint16_t id[2];
   
         switch (npc->npc_proto) {          switch (proto) {
         case IPPROTO_TCP:          case IPPROTO_TCP:
                 KASSERT(npf_iscached(npc, NPC_TCP));                  KASSERT(npf_iscached(npc, NPC_TCP));
                 th = npc->npc_l4.tcp;                  th = npc->npc_l4.tcp;
Line 347  npf_conn_conkey(const npf_cache_t *npc, 
Line 345  npf_conn_conkey(const npf_cache_t *npc, 
                 /* Unsupported protocol. */                  /* Unsupported protocol. */
                 return 0;                  return 0;
         }          }
           return connkey_setkey(key, proto, npc->npc_ips, id, alen, forw);
         return connkey_setkey(key, npc->npc_proto, npc->npc_ips, id, alen,  
             forw);  
 }  }
   
 static __inline void  static __inline void
Line 372  connkey_set_id(npf_connkey_t *key, const
Line 368  connkey_set_id(npf_connkey_t *key, const
         key->ck_key[1] = ((uint32_t)id << shift) | (oid & mask);          key->ck_key[1] = ((uint32_t)id << shift) | (oid & mask);
 }  }
   
   static inline void
   conn_update_atime(npf_conn_t *con)
   {
           struct timespec tsnow;
   
           getnanouptime(&tsnow);
           con->c_atime = tsnow.tv_sec;
   }
   
 /*  /*
  * npf_conn_ok: check if the connection is active, and has the right direction.   * npf_conn_ok: check if the connection is active, and has the right direction.
  */   */
 static bool  static bool
 npf_conn_ok(npf_conn_t *con, const int di, bool forw)  npf_conn_ok(const npf_conn_t *con, const int di, bool forw)
 {  {
         uint32_t flags = con->c_flags;          const uint32_t flags = con->c_flags;
   
         /* Check if connection is active and not expired. */          /* Check if connection is active and not expired. */
         bool ok = (flags & (CONN_ACTIVE | CONN_EXPIRE)) == CONN_ACTIVE;          bool ok = (flags & (CONN_ACTIVE | CONN_EXPIRE)) == CONN_ACTIVE;
Line 387  npf_conn_ok(npf_conn_t *con, const int d
Line 392  npf_conn_ok(npf_conn_t *con, const int d
         }          }
   
         /* Check if the direction is consistent */          /* Check if the direction is consistent */
         bool pforw = (flags & PFIL_ALL) == di;          bool pforw = (flags & PFIL_ALL) == (unsigned)di;
         if (__predict_false(forw != pforw)) {          if (__predict_false(forw != pforw)) {
                 return false;                  return false;
         }          }
Line 402  npf_conn_ok(npf_conn_t *con, const int d
Line 407  npf_conn_ok(npf_conn_t *con, const int d
 npf_conn_t *  npf_conn_t *
 npf_conn_lookup(const npf_cache_t *npc, const int di, bool *forw)  npf_conn_lookup(const npf_cache_t *npc, const int di, bool *forw)
 {  {
           npf_t *npf = npc->npc_ctx;
         const nbuf_t *nbuf = npc->npc_nbuf;          const nbuf_t *nbuf = npc->npc_nbuf;
         npf_conn_t *con;          npf_conn_t *con;
         npf_connkey_t key;          npf_connkey_t key;
Line 411  npf_conn_lookup(const npf_cache_t *npc, 
Line 417  npf_conn_lookup(const npf_cache_t *npc, 
         if (!npf_conn_conkey(npc, &key, true)) {          if (!npf_conn_conkey(npc, &key, true)) {
                 return NULL;                  return NULL;
         }          }
         con = npf_conndb_lookup(conn_db, &key, forw);          con = npf_conndb_lookup(npf->conn_db, &key, forw);
         if (con == NULL) {          if (con == NULL) {
                 return NULL;                  return NULL;
         }          }
Line 434  npf_conn_lookup(const npf_cache_t *npc, 
Line 440  npf_conn_lookup(const npf_cache_t *npc, 
         }          }
   
         /* Update the last activity time. */          /* Update the last activity time. */
         getnanouptime(&con->c_atime);          conn_update_atime(con);
         return con;          return con;
 }  }
   
Line 479  npf_conn_inspect(npf_cache_t *npc, const
Line 485  npf_conn_inspect(npf_cache_t *npc, const
         /* If invalid state: let the rules deal with it. */          /* If invalid state: let the rules deal with it. */
         if (__predict_false(!ok)) {          if (__predict_false(!ok)) {
                 npf_conn_release(con);                  npf_conn_release(con);
                 npf_stats_inc(NPF_STAT_INVALID_STATE);                  npf_stats_inc(npc->npc_ctx, NPF_STAT_INVALID_STATE);
                 return NULL;                  return NULL;
         }          }
   
Line 504  npf_conn_inspect(npf_cache_t *npc, const
Line 510  npf_conn_inspect(npf_cache_t *npc, const
 npf_conn_t *  npf_conn_t *
 npf_conn_establish(npf_cache_t *npc, int di, bool per_if)  npf_conn_establish(npf_cache_t *npc, int di, bool per_if)
 {  {
           npf_t *npf = npc->npc_ctx;
         const nbuf_t *nbuf = npc->npc_nbuf;          const nbuf_t *nbuf = npc->npc_nbuf;
         npf_conn_t *con;          npf_conn_t *con;
         int error = 0;          int error = 0;
Line 515  npf_conn_establish(npf_cache_t *npc, int
Line 522  npf_conn_establish(npf_cache_t *npc, int
         }          }
   
         /* Allocate and initialise the new connection. */          /* Allocate and initialise the new connection. */
         con = pool_cache_get(conn_cache, PR_NOWAIT);          con = pool_cache_get(npf->conn_cache, PR_NOWAIT);
         if (__predict_false(!con)) {          if (__predict_false(!con)) {
                   npf_worker_signal(npf);
                 return NULL;                  return NULL;
         }          }
         NPF_PRINTF(("NPF: create conn %p\n", con));          NPF_PRINTF(("NPF: create conn %p\n", con));
         npf_stats_inc(NPF_STAT_CONN_CREATE);          npf_stats_inc(npf, NPF_STAT_CONN_CREATE);
   
         mutex_init(&con->c_lock, MUTEX_DEFAULT, IPL_SOFTNET);          mutex_init(&con->c_lock, MUTEX_DEFAULT, IPL_SOFTNET);
         con->c_flags = (di & PFIL_ALL);          con->c_flags = (di & PFIL_ALL);
Line 530  npf_conn_establish(npf_cache_t *npc, int
Line 538  npf_conn_establish(npf_cache_t *npc, int
   
         /* Initialize the protocol state. */          /* Initialize the protocol state. */
         if (!npf_state_init(npc, &con->c_state)) {          if (!npf_state_init(npc, &con->c_state)) {
                 npf_conn_destroy(con);                  npf_conn_destroy(npf, con);
                 return NULL;                  return NULL;
         }          }
   
Line 544  npf_conn_establish(npf_cache_t *npc, int
Line 552  npf_conn_establish(npf_cache_t *npc, int
          */           */
         if (!npf_conn_conkey(npc, fw, true) ||          if (!npf_conn_conkey(npc, fw, true) ||
             !npf_conn_conkey(npc, bk, false)) {              !npf_conn_conkey(npc, bk, false)) {
                 npf_conn_destroy(con);                  npf_conn_destroy(npf, con);
                 return NULL;                  return NULL;
         }          }
         fw->ck_backptr = bk->ck_backptr = con;          fw->ck_backptr = bk->ck_backptr = con;
Line 555  npf_conn_establish(npf_cache_t *npc, int
Line 563  npf_conn_establish(npf_cache_t *npc, int
          * Set last activity time for a new connection and acquire           * Set last activity time for a new connection and acquire
          * a reference for the caller before we make it visible.           * a reference for the caller before we make it visible.
          */           */
         getnanouptime(&con->c_atime);          conn_update_atime(con);
         con->c_refcnt = 1;          con->c_refcnt = 1;
   
         /*          /*
Line 564  npf_conn_establish(npf_cache_t *npc, int
Line 572  npf_conn_establish(npf_cache_t *npc, int
          * the connection later.           * the connection later.
          */           */
         mutex_enter(&con->c_lock);          mutex_enter(&con->c_lock);
         if (!npf_conndb_insert(conn_db, fw, con)) {          if (!npf_conndb_insert(npf->conn_db, fw, con)) {
                 error = EISCONN;                  error = EISCONN;
                 goto err;                  goto err;
         }          }
         if (!npf_conndb_insert(conn_db, bk, con)) {          if (!npf_conndb_insert(npf->conn_db, bk, con)) {
                 npf_conn_t *ret __diagused;                  npf_conn_t *ret __diagused;
                 ret = npf_conndb_remove(conn_db, fw);                  ret = npf_conndb_remove(npf->conn_db, fw);
                 KASSERT(ret == con);                  KASSERT(ret == con);
                 error = EISCONN;                  error = EISCONN;
                 goto err;                  goto err;
Line 584  err:
Line 592  err:
         if (error) {          if (error) {
                 atomic_or_uint(&con->c_flags, CONN_REMOVED | CONN_EXPIRE);                  atomic_or_uint(&con->c_flags, CONN_REMOVED | CONN_EXPIRE);
                 atomic_dec_uint(&con->c_refcnt);                  atomic_dec_uint(&con->c_refcnt);
                 npf_stats_inc(NPF_STAT_RACE_CONN);                  npf_stats_inc(npf, NPF_STAT_RACE_CONN);
         } else {          } else {
                 NPF_PRINTF(("NPF: establish conn %p\n", con));                  NPF_PRINTF(("NPF: establish conn %p\n", con));
         }          }
   
         /* Finally, insert into the connection list. */          /* Finally, insert into the connection list. */
         npf_conndb_enqueue(conn_db, con);          npf_conndb_enqueue(npf->conn_db, con);
         mutex_exit(&con->c_lock);          mutex_exit(&con->c_lock);
   
         return error ? NULL : con;          return error ? NULL : con;
 }  }
   
 static void  static void
 npf_conn_destroy(npf_conn_t *con)  npf_conn_destroy(npf_t *npf, npf_conn_t *con)
 {  {
         KASSERT(con->c_refcnt == 0);          KASSERT(con->c_refcnt == 0);
   
Line 615  npf_conn_destroy(npf_conn_t *con)
Line 623  npf_conn_destroy(npf_conn_t *con)
         mutex_destroy(&con->c_lock);          mutex_destroy(&con->c_lock);
   
         /* Free the structure, increase the counter. */          /* Free the structure, increase the counter. */
         pool_cache_put(conn_cache, con);          pool_cache_put(npf->conn_cache, con);
         npf_stats_inc(NPF_STAT_CONN_DESTROY);          npf_stats_inc(npf, NPF_STAT_CONN_DESTROY);
         NPF_PRINTF(("NPF: conn %p destroyed\n", con));          NPF_PRINTF(("NPF: conn %p destroyed\n", con));
 }  }
   
Line 634  npf_conn_setnat(const npf_cache_t *npc, 
Line 642  npf_conn_setnat(const npf_cache_t *npc, 
                 [NPF_NATOUT] = NPF_DST,                  [NPF_NATOUT] = NPF_DST,
                 [NPF_NATIN] = NPF_SRC,                  [NPF_NATIN] = NPF_SRC,
         };          };
           npf_t *npf = npc->npc_ctx;
         npf_connkey_t key, *bk;          npf_connkey_t key, *bk;
         npf_conn_t *ret __diagused;          npf_conn_t *ret __diagused;
         npf_addr_t *taddr;          npf_addr_t *taddr;
Line 663  npf_conn_setnat(const npf_cache_t *npc, 
Line 672  npf_conn_setnat(const npf_cache_t *npc, 
         if (__predict_false(con->c_nat != NULL)) {          if (__predict_false(con->c_nat != NULL)) {
                 /* Race with a duplicate packet. */                  /* Race with a duplicate packet. */
                 mutex_exit(&con->c_lock);                  mutex_exit(&con->c_lock);
                 npf_stats_inc(NPF_STAT_RACE_NAT);                  npf_stats_inc(npc->npc_ctx, NPF_STAT_RACE_NAT);
                 return EISCONN;                  return EISCONN;
         }          }
   
         /* Remove the "backwards" entry. */          /* Remove the "backwards" entry. */
         ret = npf_conndb_remove(conn_db, &con->c_back_entry);          ret = npf_conndb_remove(npf->conn_db, &con->c_back_entry);
         KASSERT(ret == con);          KASSERT(ret == con);
   
         /* Set the source/destination IDs to the translation values. */          /* Set the source/destination IDs to the translation values. */
Line 679  npf_conn_setnat(const npf_cache_t *npc, 
Line 688  npf_conn_setnat(const npf_cache_t *npc, 
         }          }
   
         /* Finally, re-insert the "backwards" entry. */          /* Finally, re-insert the "backwards" entry. */
         if (!npf_conndb_insert(conn_db, bk, con)) {          if (!npf_conndb_insert(npf->conn_db, bk, con)) {
                 /*                  /*
                  * Race: we have hit the duplicate, remove the "forwards"                   * Race: we have hit the duplicate, remove the "forwards"
                  * entry and expire our connection; it is no longer valid.                   * entry and expire our connection; it is no longer valid.
                  */                   */
                 ret = npf_conndb_remove(conn_db, &con->c_forw_entry);                  ret = npf_conndb_remove(npf->conn_db, &con->c_forw_entry);
                 KASSERT(ret == con);                  KASSERT(ret == con);
   
                 atomic_or_uint(&con->c_flags, CONN_REMOVED | CONN_EXPIRE);                  atomic_or_uint(&con->c_flags, CONN_REMOVED | CONN_EXPIRE);
                 mutex_exit(&con->c_lock);                  mutex_exit(&con->c_lock);
   
                 npf_stats_inc(NPF_STAT_RACE_NAT);                  npf_stats_inc(npc->npc_ctx, NPF_STAT_RACE_NAT);
                 return EISCONN;                  return EISCONN;
         }          }
   
Line 767  npf_nat_t *
Line 776  npf_nat_t *
 npf_conn_getnat(npf_conn_t *con, const int di, bool *forw)  npf_conn_getnat(npf_conn_t *con, const int di, bool *forw)
 {  {
         KASSERT(con->c_refcnt > 0);          KASSERT(con->c_refcnt > 0);
         *forw = (con->c_flags & PFIL_ALL) == di;          *forw = (con->c_flags & PFIL_ALL) == (u_int)di;
         return con->c_nat;          return con->c_nat;
 }  }
   
Line 775  npf_conn_getnat(npf_conn_t *con, const i
Line 784  npf_conn_getnat(npf_conn_t *con, const i
  * npf_conn_expired: criterion to check if connection is expired.   * npf_conn_expired: criterion to check if connection is expired.
  */   */
 static inline bool  static inline bool
 npf_conn_expired(const npf_conn_t *con, const struct timespec *tsnow)  npf_conn_expired(const npf_conn_t *con, uint64_t tsnow)
 {  {
         const int etime = npf_state_etime(&con->c_state, con->c_proto);          const int etime = npf_state_etime(&con->c_state, con->c_proto);
         struct timespec tsdiff;          int elapsed;
   
         if (__predict_false(con->c_flags & CONN_EXPIRE)) {          if (__predict_false(con->c_flags & CONN_EXPIRE)) {
                 /* Explicitly marked to be expired. */                  /* Explicitly marked to be expired. */
                 return true;                  return true;
         }          }
         timespecsub(tsnow, &con->c_atime, &tsdiff);  
         return tsdiff.tv_sec > etime;          /*
            * Note: another thread may update 'atime' and it might
            * become greater than 'now'.
            */
           elapsed = (int64_t)tsnow - con->c_atime;
           return elapsed > etime;
 }  }
   
 /*  /*
Line 796  npf_conn_expired(const npf_conn_t *con, 
Line 810  npf_conn_expired(const npf_conn_t *con, 
  * => If 'sync' is true, then perform passive serialisation.   * => If 'sync' is true, then perform passive serialisation.
  */   */
 void  void
 npf_conn_gc(npf_conndb_t *cd, bool flush, bool sync)  npf_conn_gc(npf_t *npf, npf_conndb_t *cd, bool flush, bool sync)
 {  {
         npf_conn_t *con, *prev, *gclist = NULL;          npf_conn_t *con, *prev, *gclist = NULL;
         struct timespec tsnow;          struct timespec tsnow;
Line 812  npf_conn_gc(npf_conndb_t *cd, bool flush
Line 826  npf_conn_gc(npf_conndb_t *cd, bool flush
                 npf_conn_t *next = con->c_next;                  npf_conn_t *next = con->c_next;
   
                 /* Expired?  Flushing all? */                  /* Expired?  Flushing all? */
                 if (!npf_conn_expired(con, &tsnow) && !flush) {                  if (!npf_conn_expired(con, tsnow.tv_sec) && !flush) {
                         prev = con;                          prev = con;
                         con = next;                          con = next;
                         continue;                          continue;
Line 848  npf_conn_gc(npf_conndb_t *cd, bool flush
Line 862  npf_conn_gc(npf_conndb_t *cd, bool flush
          * Note: drop the conn_lock (see the lock order).           * Note: drop the conn_lock (see the lock order).
          */           */
         if (sync) {          if (sync) {
                 mutex_exit(&conn_lock);                  mutex_exit(&npf->conn_lock);
                 if (gclist) {                  if (gclist) {
                         npf_config_enter();                          npf_config_enter(npf);
                         npf_config_sync();                          npf_config_sync(npf);
                         npf_config_exit();                          npf_config_exit(npf);
                 }                  }
         }          }
   
Line 872  npf_conn_gc(npf_conndb_t *cd, bool flush
Line 886  npf_conn_gc(npf_conndb_t *cd, bool flush
                         kpause("npfcongc", false, 1, NULL);                          kpause("npfcongc", false, 1, NULL);
                         continue;                          continue;
                 }                  }
                 npf_conn_destroy(con);                  npf_conn_destroy(npf, con);
                 con = next;                  con = next;
         }          }
 }  }
Line 880  npf_conn_gc(npf_conndb_t *cd, bool flush
Line 894  npf_conn_gc(npf_conndb_t *cd, bool flush
 /*  /*
  * npf_conn_worker: G/C to run from a worker thread.   * npf_conn_worker: G/C to run from a worker thread.
  */   */
 static void  void
 npf_conn_worker(void)  npf_conn_worker(npf_t *npf)
 {  {
         mutex_enter(&conn_lock);          mutex_enter(&npf->conn_lock);
         /* Note: the conn_lock will be released (sync == true). */          /* Note: the conn_lock will be released (sync == true). */
         npf_conn_gc(conn_db, false, true);          npf_conn_gc(npf, npf->conn_db, false, true);
 }  }
   
 /*  /*
Line 893  npf_conn_worker(void)
Line 907  npf_conn_worker(void)
  * Note: this is expected to be an expensive operation.   * Note: this is expected to be an expensive operation.
  */   */
 int  int
 npf_conndb_export(prop_array_t conlist)  npf_conndb_export(npf_t *npf, prop_array_t conlist)
 {  {
         npf_conn_t *con, *prev;          npf_conn_t *con, *prev;
   
Line 901  npf_conndb_export(prop_array_t conlist)
Line 915  npf_conndb_export(prop_array_t conlist)
          * Note: acquire conn_lock to prevent from the database           * Note: acquire conn_lock to prevent from the database
          * destruction and G/C thread.           * destruction and G/C thread.
          */           */
         mutex_enter(&conn_lock);          mutex_enter(&npf->conn_lock);
         if (conn_tracking != CONN_TRACKING_ON) {          if (npf->conn_tracking != CONN_TRACKING_ON) {
                 mutex_exit(&conn_lock);                  mutex_exit(&npf->conn_lock);
                 return 0;                  return 0;
         }          }
         prev = NULL;          prev = NULL;
         con = npf_conndb_getlist(conn_db);          con = npf_conndb_getlist(npf->conn_db);
         while (con) {          while (con) {
                 npf_conn_t *next = con->c_next;                  npf_conn_t *next = con->c_next;
                 prop_dictionary_t cdict;                  prop_dictionary_t cdict;
   
                 if ((cdict = npf_conn_export(con)) != NULL) {                  if ((cdict = npf_conn_export(npf, con)) != NULL) {
                         prop_array_add(conlist, cdict);                          prop_array_add(conlist, cdict);
                         prop_object_release(cdict);                          prop_object_release(cdict);
                 }                  }
                 prev = con;                  prev = con;
                 con = next;                  con = next;
         }          }
         npf_conndb_settail(conn_db, prev);          npf_conndb_settail(npf->conn_db, prev);
         mutex_exit(&conn_lock);          mutex_exit(&npf->conn_lock);
         return 0;          return 0;
 }  }
   
Line 928  static prop_dictionary_t
Line 942  static prop_dictionary_t
 npf_connkey_export(const npf_connkey_t *key)  npf_connkey_export(const npf_connkey_t *key)
 {  {
         uint16_t id[2], alen, proto;          uint16_t id[2], alen, proto;
           prop_dictionary_t kdict;
         npf_addr_t ips[2];          npf_addr_t ips[2];
         prop_data_t d;          prop_data_t d;
         prop_dictionary_t kdict = prop_dictionary_create();  
   
           kdict = prop_dictionary_create();
         connkey_getkey(key, &proto, ips, id, &alen);          connkey_getkey(key, &proto, ips, id, &alen);
   
         prop_dictionary_set_uint16(kdict, "proto", proto);          prop_dictionary_set_uint16(kdict, "proto", proto);
Line 952  npf_connkey_export(const npf_connkey_t *
Line 967  npf_connkey_export(const npf_connkey_t *
  * npf_conn_export: serialise a single connection.   * npf_conn_export: serialise a single connection.
  */   */
 prop_dictionary_t  prop_dictionary_t
 npf_conn_export(const npf_conn_t *con)  npf_conn_export(npf_t *npf, const npf_conn_t *con)
 {  {
         prop_dictionary_t cdict, kdict;          prop_dictionary_t cdict, kdict;
         prop_data_t d;          prop_data_t d;
Line 964  npf_conn_export(const npf_conn_t *con)
Line 979  npf_conn_export(const npf_conn_t *con)
         prop_dictionary_set_uint32(cdict, "flags", con->c_flags);          prop_dictionary_set_uint32(cdict, "flags", con->c_flags);
         prop_dictionary_set_uint32(cdict, "proto", con->c_proto);          prop_dictionary_set_uint32(cdict, "proto", con->c_proto);
         if (con->c_ifid) {          if (con->c_ifid) {
                 const char *ifname = npf_ifmap_getname(con->c_ifid);                  const char *ifname = npf_ifmap_getname(npf, con->c_ifid);
                 prop_dictionary_set_cstring(cdict, "ifname", ifname);                  prop_dictionary_set_cstring(cdict, "ifname", ifname);
         }          }
   
Line 986  npf_conn_export(const npf_conn_t *con)
Line 1001  npf_conn_export(const npf_conn_t *con)
 static uint32_t  static uint32_t
 npf_connkey_import(prop_dictionary_t kdict, npf_connkey_t *key)  npf_connkey_import(prop_dictionary_t kdict, npf_connkey_t *key)
 {  {
         uint16_t proto;  
         prop_object_t sobj, dobj;          prop_object_t sobj, dobj;
         uint16_t id[2];  
         npf_addr_t const * ips[2];          npf_addr_t const * ips[2];
           uint16_t alen, proto, id[2];
   
         if (!prop_dictionary_get_uint16(kdict, "proto", &proto))          if (!prop_dictionary_get_uint16(kdict, "proto", &proto))
                 return 0;                  return 0;
Line 1008  npf_connkey_import(prop_dictionary_t kdi
Line 1022  npf_connkey_import(prop_dictionary_t kdi
         if ((ips[NPF_DST] = prop_data_data_nocopy(dobj)) == NULL)          if ((ips[NPF_DST] = prop_data_data_nocopy(dobj)) == NULL)
                 return 0;                  return 0;
   
         uint16_t alen = prop_data_size(sobj);          alen = prop_data_size(sobj);
         if (alen != prop_data_size(dobj))          if (alen != prop_data_size(dobj))
                 return 0;                  return 0;
   
Line 1020  npf_connkey_import(prop_dictionary_t kdi
Line 1034  npf_connkey_import(prop_dictionary_t kdi
  * directory and insert into the given database.   * directory and insert into the given database.
  */   */
 int  int
 npf_conn_import(npf_conndb_t *cd, prop_dictionary_t cdict,  npf_conn_import(npf_t *npf, npf_conndb_t *cd, prop_dictionary_t cdict,
     npf_ruleset_t *natlist)      npf_ruleset_t *natlist)
 {  {
         npf_conn_t *con;          npf_conn_t *con;
Line 1030  npf_conn_import(npf_conndb_t *cd, prop_d
Line 1044  npf_conn_import(npf_conndb_t *cd, prop_d
         const void *d;          const void *d;
   
         /* Allocate a connection and initialise it (clear first). */          /* Allocate a connection and initialise it (clear first). */
         con = pool_cache_get(conn_cache, PR_WAITOK);          con = pool_cache_get(npf->conn_cache, PR_WAITOK);
         memset(con, 0, sizeof(npf_conn_t));          memset(con, 0, sizeof(npf_conn_t));
         mutex_init(&con->c_lock, MUTEX_DEFAULT, IPL_SOFTNET);          mutex_init(&con->c_lock, MUTEX_DEFAULT, IPL_SOFTNET);
         npf_stats_inc(NPF_STAT_CONN_CREATE);          npf_stats_inc(npf, NPF_STAT_CONN_CREATE);
   
         prop_dictionary_get_uint32(cdict, "proto", &con->c_proto);          prop_dictionary_get_uint32(cdict, "proto", &con->c_proto);
         prop_dictionary_get_uint32(cdict, "flags", &con->c_flags);          prop_dictionary_get_uint32(cdict, "flags", &con->c_flags);
         con->c_flags &= PFIL_ALL | CONN_ACTIVE | CONN_PASS;          con->c_flags &= PFIL_ALL | CONN_ACTIVE | CONN_PASS;
         getnanouptime(&con->c_atime);          conn_update_atime(con);
   
         if (prop_dictionary_get_cstring_nocopy(cdict, "ifname", &ifname) &&          if (prop_dictionary_get_cstring_nocopy(cdict, "ifname", &ifname) &&
             (con->c_ifid = npf_ifmap_register(ifname)) == 0) {              (con->c_ifid = npf_ifmap_register(npf, ifname)) == 0) {
                 goto err;                  goto err;
         }          }
   
Line 1054  npf_conn_import(npf_conndb_t *cd, prop_d
Line 1068  npf_conn_import(npf_conndb_t *cd, prop_d
   
         /* Reconstruct NAT association, if any. */          /* Reconstruct NAT association, if any. */
         if ((obj = prop_dictionary_get(cdict, "nat")) != NULL &&          if ((obj = prop_dictionary_get(cdict, "nat")) != NULL &&
             (con->c_nat = npf_nat_import(obj, natlist, con)) == NULL) {              (con->c_nat = npf_nat_import(npf, obj, natlist, con)) == NULL) {
                 goto err;                  goto err;
         }          }
   
Line 1088  npf_conn_import(npf_conndb_t *cd, prop_d
Line 1102  npf_conn_import(npf_conndb_t *cd, prop_d
         npf_conndb_enqueue(cd, con);          npf_conndb_enqueue(cd, con);
         return 0;          return 0;
 err:  err:
         npf_conn_destroy(con);          npf_conn_destroy(npf, con);
         return EINVAL;          return EINVAL;
 }  }
   
 int  int
 npf_conn_find(prop_dictionary_t idict, prop_dictionary_t *odict)  npf_conn_find(npf_t *npf, prop_dictionary_t idict, prop_dictionary_t *odict)
 {  {
           prop_dictionary_t kdict;
         npf_connkey_t key;          npf_connkey_t key;
         npf_conn_t *con;          npf_conn_t *con;
         uint16_t dir;          uint16_t dir;
         bool forw;          bool forw;
         prop_dictionary_t kdict;  
   
         if ((kdict = prop_dictionary_get(idict, "key")) == NULL)          if ((kdict = prop_dictionary_get(idict, "key")) == NULL)
                 return EINVAL;                  return EINVAL;
Line 1110  npf_conn_find(prop_dictionary_t idict, p
Line 1124  npf_conn_find(prop_dictionary_t idict, p
         if (!prop_dictionary_get_uint16(idict, "direction", &dir))          if (!prop_dictionary_get_uint16(idict, "direction", &dir))
                 return EINVAL;                  return EINVAL;
   
         con = npf_conndb_lookup(conn_db, &key, &forw);          con = npf_conndb_lookup(npf->conn_db, &key, &forw);
         if (con == NULL) {          if (con == NULL) {
                 return ESRCH;                  return ESRCH;
         }          }
Line 1120  npf_conn_find(prop_dictionary_t idict, p
Line 1134  npf_conn_find(prop_dictionary_t idict, p
                 return ESRCH;                  return ESRCH;
         }          }
   
         *odict = npf_conn_export(con);          *odict = npf_conn_export(npf, con);
         if (*odict == NULL) {          if (*odict == NULL) {
                 atomic_dec_uint(&con->c_refcnt);                  atomic_dec_uint(&con->c_refcnt);
                 return ENOSPC;                  return ENOSPC;
Line 1139  npf_conn_print(const npf_conn_t *con)
Line 1153  npf_conn_print(const npf_conn_t *con)
         const uint32_t *fkey = con->c_forw_entry.ck_key;          const uint32_t *fkey = con->c_forw_entry.ck_key;
         const uint32_t *bkey = con->c_back_entry.ck_key;          const uint32_t *bkey = con->c_back_entry.ck_key;
         const u_int proto = con->c_proto;          const u_int proto = con->c_proto;
         struct timespec tsnow, tsdiff;          struct timespec tspnow;
         const void *src, *dst;          const void *src, *dst;
         int etime;          int etime;
   
         getnanouptime(&tsnow);          getnanouptime(&tspnow);
         timespecsub(&tsnow, &con->c_atime, &tsdiff);  
         etime = npf_state_etime(&con->c_state, proto);          etime = npf_state_etime(&con->c_state, proto);
   
         printf("%p:\n\tproto %d flags 0x%x tsdiff %d etime %d\n",          printf("%p:\n\tproto %d flags 0x%x tsdiff %ld etime %d\n", con,
             con, proto, con->c_flags, (int)tsdiff.tv_sec, etime);              proto, con->c_flags, (long)(tspnow.tv_sec - con->c_atime), etime);
   
         src = &fkey[2], dst = &fkey[2 + (alen >> 2)];          src = &fkey[2], dst = &fkey[2 + (alen >> 2)];
         printf("\tforw %s:%d", npf_addr_dump(src, alen), ntohs(fkey[1] >> 16));          printf("\tforw %s:%d", npf_addr_dump(src, alen), ntohs(fkey[1] >> 16));

Legend:
Removed from v.1.21  
changed lines
  Added in v.1.22

CVSweb <webmaster@jp.NetBSD.org>