Page MenuHomeFreeBSD

D23586.id68170.diff
No OneTemporary

D23586.id68170.diff

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

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)

Event Timeline