Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F147448112
D23586.id68170.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
13 KB
Referenced Files
None
Subscribers
None
D23586.id68170.diff
View Options
Index: sbin/ipfw/ipfw.8
===================================================================
--- sbin/ipfw/ipfw.8
+++ sbin/ipfw/ipfw.8
@@ -3644,6 +3644,10 @@
.It Va net.inet.ip.fw.tables_max: No 128
Defines number of tables available in ipfw.
Number cannot exceed 65534.
+.It Va net.inet.ip.fw.nat_hash: No 1
+Defines size of the hash table for accessing ipfw NAT instances.
+The number should be set to half of the number of expected instances.
+It works best with sequentially numbered instances.
.El
.Sh SYSCTL VARIABLES
A set of
Index: sys/netpfil/ipfw/ip_fw2.c
===================================================================
--- sys/netpfil/ipfw/ip_fw2.c
+++ sys/netpfil/ipfw/ip_fw2.c
@@ -130,6 +130,9 @@
/* Use 128 tables by default */
static unsigned int default_fw_tables = IPFW_TABLES_DEFAULT;
+/* Keep hash as small as possible */
+int fw_nat_hash = 1;
+
#ifndef LINEAR_SKIPTO
static int jump_fast(struct ip_fw_chain *chain, struct ip_fw *f, int num,
int tablearg, int jump_backwards);
@@ -166,7 +169,7 @@
VNET_DEFINE(int, ipfw_nat_ready) = 0;
ipfw_nat_t *ipfw_nat_ptr = NULL;
-struct cfg_nat *(*lookup_nat_ptr)(struct nat_list *, int);
+struct cfg_nat *(*lookup_nat_ptr)(struct nat_lists *, int);
ipfw_nat_cfg_t *ipfw_nat_cfg_ptr;
ipfw_nat_cfg_t *ipfw_nat_del_ptr;
ipfw_nat_cfg_t *ipfw_nat_get_cfg_ptr;
@@ -209,6 +212,9 @@
SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, static_count,
CTLFLAG_VNET | CTLFLAG_RD, &VNET_NAME(layer3_chain.n_rules), 0,
"Number of static rules");
+SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, nat_hash, CTLFLAG_RDTUN,
+ &fw_nat_hash, 0,
+ "Size of hash table for NAT instances.");
#ifdef INET6
SYSCTL_DECL(_net_inet6_ip6);
@@ -3327,6 +3333,9 @@
if (default_fw_tables > IPFW_TABLES_MAX)
default_fw_tables = IPFW_TABLES_MAX;
+ if (fw_nat_hash < 1)
+ fw_nat_hash = 1;
+
ipfw_init_sopt_handler();
ipfw_init_obj_rewriter();
ipfw_iface_init();
@@ -3369,9 +3378,6 @@
#endif
#ifdef IPFIREWALL_VERBOSE_LIMIT
V_verbose_limit = IPFIREWALL_VERBOSE_LIMIT;
-#endif
-#ifdef IPFIREWALL_NAT
- LIST_INIT(&chain->nat);
#endif
/* Init shared services hash table */
Index: sys/netpfil/ipfw/ip_fw_nat.c
===================================================================
--- sys/netpfil/ipfw/ip_fw_nat.c
+++ sys/netpfil/ipfw/ip_fw_nat.c
@@ -103,6 +103,7 @@
struct cfg_nat *ptr;
struct ifaddr *ifa;
struct ip_fw_chain *chain;
+ int i;
KASSERT(curvnet == ifp->if_vnet,
("curvnet(%p) differs from iface vnet(%p)", curvnet, ifp->if_vnet));
@@ -113,26 +114,27 @@
chain = &V_layer3_chain;
IPFW_UH_WLOCK(chain);
/* Check every nat entry... */
- LIST_FOREACH(ptr, &chain->nat, _next) {
- struct epoch_tracker et;
+ for(i = 0; i < chain->nat.len; i++)
+ LIST_FOREACH(ptr, &chain->nat.tbl[i], _next) {
+ struct epoch_tracker et;
- /* ...using nic 'ifp->if_xname' as dynamic alias address. */
- if (strncmp(ptr->if_name, ifp->if_xname, IF_NAMESIZE) != 0)
- continue;
- NET_EPOCH_ENTER(et);
- CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
- if (ifa->ifa_addr == NULL)
+ /* ...using nic 'ifp->if_xname' as dynamic alias address. */
+ if (strncmp(ptr->if_name, ifp->if_xname, IF_NAMESIZE) != 0)
continue;
- if (ifa->ifa_addr->sa_family != AF_INET)
- continue;
- IPFW_WLOCK(chain);
- ptr->ip = ((struct sockaddr_in *)
- (ifa->ifa_addr))->sin_addr;
- LibAliasSetAddress(ptr->lib, ptr->ip);
- IPFW_WUNLOCK(chain);
+ NET_EPOCH_ENTER(et);
+ CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
+ if (ifa->ifa_addr == NULL)
+ continue;
+ if (ifa->ifa_addr->sa_family != AF_INET)
+ continue;
+ IPFW_WLOCK(chain);
+ ptr->ip = ((struct sockaddr_in *)
+ (ifa->ifa_addr))->sin_addr;
+ LibAliasSetAddress(ptr->lib, ptr->ip);
+ IPFW_WUNLOCK(chain);
+ }
+ NET_EPOCH_EXIT(et);
}
- NET_EPOCH_EXIT(et);
- }
IPFW_UH_WUNLOCK(chain);
}
@@ -348,6 +350,8 @@
/* Check if this is 'global' instance */
if (t == NULL) {
+ int i;
+
if (args->flags & IPFW_ARGS_IN) {
/* Wrong direction, skip processing */
args->m = mcl;
@@ -358,17 +362,18 @@
chain = &V_layer3_chain;
IPFW_RLOCK_ASSERT(chain);
/* Check every nat entry... */
- LIST_FOREACH(t, &chain->nat, _next) {
- if ((t->mode & PKT_ALIAS_SKIP_GLOBAL) != 0)
- continue;
- retval = LibAliasOutTry(t->lib, c,
- mcl->m_len + M_TRAILINGSPACE(mcl), 0);
- if (retval == PKT_ALIAS_OK) {
- /* Nat instance recognises state */
- found = 1;
- break;
+ for(i = 0; i < chain->nat.len; i++)
+ LIST_FOREACH(t, &chain->nat.tbl[i], _next) {
+ if ((t->mode & PKT_ALIAS_SKIP_GLOBAL) != 0)
+ continue;
+ retval = LibAliasOutTry(t->lib, c,
+ mcl->m_len + M_TRAILINGSPACE(mcl), 0);
+ if (retval == PKT_ALIAS_OK) {
+ /* Nat instance recognises state */
+ found = 1;
+ break;
+ }
}
- }
if (found != 1) {
/* No instance found, return ignore */
args->m = mcl;
@@ -459,10 +464,14 @@
}
static struct cfg_nat *
-lookup_nat(struct nat_list *l, int nat_id)
+lookup_nat(struct nat_lists *ls, int nat_id)
{
struct cfg_nat *res;
+ struct nat_list * l;
+ KASSERT(ls->len > 0 && ls->tbl != NULL, "Query an uninitialzed nat chain.");
+ l = NAT_TABLE_LIST(*ls, nat_id);
+
LIST_FOREACH(res, l, _next) {
if (res->id == nat_id)
break;
@@ -471,9 +480,8 @@
}
static struct cfg_nat *
-lookup_nat_name(struct nat_list *l, char *name)
+lookup_nat_name(struct nat_lists *ls, char *name)
{
- struct cfg_nat *res;
int id;
char *errptr;
@@ -481,11 +489,7 @@
if (id == 0 || *errptr != '\0')
return (NULL);
- LIST_FOREACH(res, l, _next) {
- if (res->id == id)
- break;
- }
- return (res);
+ return lookup_nat(ls, id);
}
/* IP_FW3 configuration routines */
@@ -549,7 +553,7 @@
IPFW_WLOCK(chain);
if (tcfg != NULL)
LIST_REMOVE(tcfg, _next);
- LIST_INSERT_HEAD(&chain->nat, ptr, _next);
+ LIST_INSERT_HEAD(NAT_TABLE_LIST(chain->nat, ptr->id), ptr, _next);
IPFW_WUNLOCK(chain);
chain->gencnt++;
@@ -774,7 +778,7 @@
ipfw_obj_lheader *olh;
struct nat44_cfg_nat *ucfg;
struct cfg_nat *ptr;
- int nat_count;
+ int nat_count, i;
/* Check minimum header size */
if (sd->valsize < sizeof(ipfw_obj_lheader))
@@ -783,8 +787,9 @@
olh = (ipfw_obj_lheader *)ipfw_get_sopt_header(sd, sizeof(*olh));
IPFW_UH_RLOCK(chain);
nat_count = 0;
- LIST_FOREACH(ptr, &chain->nat, _next)
- nat_count++;
+ for(i = 0; i < chain->nat.len; i++)
+ LIST_FOREACH(ptr, &chain->nat.tbl[i], _next)
+ nat_count++;
olh->count = nat_count;
olh->objsize = sizeof(struct nat44_cfg_nat);
@@ -795,11 +800,12 @@
return (ENOMEM);
}
- LIST_FOREACH(ptr, &chain->nat, _next) {
- ucfg = (struct nat44_cfg_nat *)ipfw_get_sopt_space(sd,
- sizeof(*ucfg));
- export_nat_cfg(ptr, ucfg);
- }
+ for(i = 0; i < chain->nat.len; i++)
+ LIST_FOREACH(ptr, &chain->nat.tbl[i], _next) {
+ ucfg = (struct nat44_cfg_nat *)ipfw_get_sopt_space(sd,
+ sizeof(*ucfg));
+ export_nat_cfg(ptr, ucfg);
+ }
IPFW_UH_RUNLOCK(chain);
@@ -1027,7 +1033,7 @@
struct cfg_redir_legacy *ser_r;
struct cfg_spool_legacy *ser_s;
char *data;
- int gencnt, nat_cnt, len, error;
+ int gencnt, nat_cnt, len, error, i;
nat_cnt = 0;
len = sizeof(nat_cnt);
@@ -1036,15 +1042,16 @@
retry:
gencnt = chain->gencnt;
/* Estimate memory amount */
- LIST_FOREACH(n, &chain->nat, _next) {
- nat_cnt++;
- len += sizeof(struct cfg_nat_legacy);
- LIST_FOREACH(r, &n->redir_chain, _next) {
- len += sizeof(struct cfg_redir_legacy);
- LIST_FOREACH(s, &r->spool_chain, _next)
- len += sizeof(struct cfg_spool_legacy);
+ for(i = 0; i < chain->nat.len; i++)
+ LIST_FOREACH(n, &chain->nat.tbl[i], _next) {
+ nat_cnt++;
+ len += sizeof(struct cfg_nat_legacy);
+ LIST_FOREACH(r, &n->redir_chain, _next) {
+ len += sizeof(struct cfg_redir_legacy);
+ LIST_FOREACH(s, &r->spool_chain, _next)
+ len += sizeof(struct cfg_spool_legacy);
+ }
}
- }
IPFW_UH_RUNLOCK(chain);
data = malloc(len, M_TEMP, M_WAITOK | M_ZERO);
@@ -1059,36 +1066,37 @@
goto retry;
}
/* Serialize all the data. */
- LIST_FOREACH(n, &chain->nat, _next) {
- ucfg = (struct cfg_nat_legacy *)&data[len];
- ucfg->id = n->id;
- ucfg->ip = n->ip;
- ucfg->redir_cnt = n->redir_cnt;
- ucfg->mode = n->mode;
- strlcpy(ucfg->if_name, n->if_name, sizeof(ucfg->if_name));
- len += sizeof(struct cfg_nat_legacy);
- LIST_FOREACH(r, &n->redir_chain, _next) {
- ser_r = (struct cfg_redir_legacy *)&data[len];
- ser_r->mode = r->mode;
- ser_r->laddr = r->laddr;
- ser_r->paddr = r->paddr;
- ser_r->raddr = r->raddr;
- ser_r->lport = r->lport;
- ser_r->pport = r->pport;
- ser_r->rport = r->rport;
- ser_r->pport_cnt = r->pport_cnt;
- ser_r->rport_cnt = r->rport_cnt;
- ser_r->proto = r->proto;
- ser_r->spool_cnt = r->spool_cnt;
- len += sizeof(struct cfg_redir_legacy);
- LIST_FOREACH(s, &r->spool_chain, _next) {
- ser_s = (struct cfg_spool_legacy *)&data[len];
- ser_s->addr = s->addr;
- ser_s->port = s->port;
- len += sizeof(struct cfg_spool_legacy);
+ for(i = 0; i < chain->nat.len; i++)
+ LIST_FOREACH(n, &chain->nat.tbl[i], _next) {
+ ucfg = (struct cfg_nat_legacy *)&data[len];
+ ucfg->id = n->id;
+ ucfg->ip = n->ip;
+ ucfg->redir_cnt = n->redir_cnt;
+ ucfg->mode = n->mode;
+ strlcpy(ucfg->if_name, n->if_name, sizeof(ucfg->if_name));
+ len += sizeof(struct cfg_nat_legacy);
+ LIST_FOREACH(r, &n->redir_chain, _next) {
+ ser_r = (struct cfg_redir_legacy *)&data[len];
+ ser_r->mode = r->mode;
+ ser_r->laddr = r->laddr;
+ ser_r->paddr = r->paddr;
+ ser_r->raddr = r->raddr;
+ ser_r->lport = r->lport;
+ ser_r->pport = r->pport;
+ ser_r->rport = r->rport;
+ ser_r->pport_cnt = r->pport_cnt;
+ ser_r->rport_cnt = r->rport_cnt;
+ ser_r->proto = r->proto;
+ ser_r->spool_cnt = r->spool_cnt;
+ len += sizeof(struct cfg_redir_legacy);
+ LIST_FOREACH(s, &r->spool_chain, _next) {
+ ser_s = (struct cfg_spool_legacy *)&data[len];
+ ser_s->addr = s->addr;
+ ser_s->port = s->port;
+ len += sizeof(struct cfg_spool_legacy);
+ }
}
}
- }
IPFW_UH_RUNLOCK(chain);
error = sooptcopyout(sopt, data, len);
@@ -1102,7 +1110,7 @@
{
uint8_t *data;
struct cfg_nat *ptr;
- int i, size;
+ int i, k, size;
struct ip_fw_chain *chain;
IPFW_RLOCK_TRACKER;
@@ -1111,11 +1119,12 @@
IPFW_RLOCK(chain);
/* one pass to count, one to copy the data */
i = 0;
- LIST_FOREACH(ptr, &chain->nat, _next) {
- if (ptr->lib->logDesc == NULL)
- continue;
- i++;
- }
+ for(k = 0; k < chain->nat.len; k++)
+ LIST_FOREACH(ptr, &chain->nat.tbl[k], _next) {
+ if (ptr->lib->logDesc == NULL)
+ continue;
+ i++;
+ }
size = i * (LIBALIAS_BUF_SIZE + sizeof(int));
data = malloc(size, M_IPFW, M_NOWAIT | M_ZERO);
if (data == NULL) {
@@ -1123,14 +1132,15 @@
return (ENOSPC);
}
i = 0;
- LIST_FOREACH(ptr, &chain->nat, _next) {
- if (ptr->lib->logDesc == NULL)
- continue;
- bcopy(&ptr->id, &data[i], sizeof(int));
- i += sizeof(int);
- bcopy(ptr->lib->logDesc, &data[i], LIBALIAS_BUF_SIZE);
- i += LIBALIAS_BUF_SIZE;
- }
+ for(k = 0; k < chain->nat.len; k++)
+ LIST_FOREACH(ptr, &chain->nat.tbl[k], _next) {
+ if (ptr->lib->logDesc == NULL)
+ continue;
+ bcopy(&ptr->id, &data[i], sizeof(int));
+ i += sizeof(int);
+ bcopy(ptr->lib->logDesc, &data[i], LIBALIAS_BUF_SIZE);
+ i += LIBALIAS_BUF_SIZE;
+ }
IPFW_RUNLOCK(chain);
sooptcopyout(sopt, data, size);
free(data, M_IPFW);
@@ -1140,8 +1150,19 @@
static int
vnet_ipfw_nat_init(const void *arg __unused)
{
+ struct ip_fw_chain *chain;
+ int i;
+ chain = &V_layer3_chain;
+ IPFW_WLOCK(chain);
+ chain->nat.len = fw_nat_hash;
+ chain->nat.tbl = malloc(chain->nat.len * sizeof(*chain->nat.tbl),
+ M_IPFW, M_NOWAIT | M_ZERO);
+ for(i = 0; i < chain->nat.len; i++)
+ LIST_INIT(&chain->nat.tbl[i]);
+
V_ipfw_nat_ready = 1;
+ IPFW_WUNLOCK(chain);
return (0);
}
@@ -1150,15 +1171,19 @@
{
struct cfg_nat *ptr, *ptr_temp;
struct ip_fw_chain *chain;
+ int i;
chain = &V_layer3_chain;
IPFW_WLOCK(chain);
V_ipfw_nat_ready = 0;
- LIST_FOREACH_SAFE(ptr, &chain->nat, _next, ptr_temp) {
- LIST_REMOVE(ptr, _next);
- free_nat_instance(ptr);
- }
+ for(i = 0; i < chain->nat.len; i++)
+ LIST_FOREACH_SAFE(ptr, &chain->nat.tbl[i], _next, ptr_temp) {
+ LIST_REMOVE(ptr, _next);
+ free_nat_instance(ptr);
+ }
flush_nat_ptrs(chain, -1 /* flush all */);
+ chain->nat.len = 0;
+ free(chain->nat.tbl, M_IPFW);
IPFW_WUNLOCK(chain);
return (0);
}
Index: sys/netpfil/ipfw/ip_fw_private.h
===================================================================
--- sys/netpfil/ipfw/ip_fw_private.h
+++ sys/netpfil/ipfw/ip_fw_private.h
@@ -250,6 +250,8 @@
VNET_DECLARE(unsigned int, fw_tables_sets);
#define V_fw_tables_sets VNET(fw_tables_sets)
+extern int fw_nat_hash;
+
struct tables_config;
#ifdef _KERNEL
@@ -288,6 +290,12 @@
#endif
+struct nat_lists {
+ LIST_HEAD(nat_list, cfg_nat) *tbl; /* table of lists of nat entries */
+ int len; /* size of of nat lookup table */
+};
+#define NAT_TABLE_LIST(n,i) (&((n).tbl[(i)%(n).len]))
+
struct ip_fw_chain {
struct ip_fw **map; /* array of rule ptrs to ease lookup */
uint32_t id; /* ruleset id */
@@ -303,7 +311,7 @@
#endif
int static_len; /* total len of static rules (v0) */
uint32_t gencnt; /* NAT generation count */
- LIST_HEAD(nat_list, cfg_nat) nat; /* list of nat entries */
+ struct nat_lists nat; /* nat entries */
struct ip_fw *default_rule;
struct tables_config *tblcfg; /* tables module data */
void *ifcfg; /* interface module data */
@@ -788,7 +796,7 @@
/* In ip_fw_nat.c -- XXX to be moved to ip_var.h */
-extern struct cfg_nat *(*lookup_nat_ptr)(struct nat_list *, int);
+extern struct cfg_nat *(*lookup_nat_ptr)(struct nat_lists *, int);
typedef int ipfw_nat_t(struct ip_fw_args *, struct cfg_nat *, struct mbuf *);
typedef int ipfw_nat_cfg_t(struct sockopt *);
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Thu, Mar 12, 2:45 AM (13 h, 47 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
29558405
Default Alt Text
D23586.id68170.diff (13 KB)
Attached To
Mode
D23586: ipfw_nat: Perfomance of accessing multiple nat tables
Attached
Detach File
Event Timeline
Log In to Comment