some mostly cosmetic changes in preparation for upcoming work:

+ in many places, replace &V_layer3_chain with a local
  variable chain;
+ bring the counter of rules and static_len within ip_fw_chain
  replacing static variables;
+ remove some spurious comments and extern declaration;
+ document which lock protects certain data structures
This commit is contained in:
Luigi Rizzo 2009-12-22 13:53:34 +00:00
parent feb7a28755
commit 46fdc2bf60
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=200838
4 changed files with 89 additions and 92 deletions

View File

@ -1,5 +1,5 @@
/*-
* Copyright (c) 2002 Luigi Rizzo, Universita` di Pisa
* Copyright (c) 2002-2009 Luigi Rizzo, Universita` di Pisa
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@ -131,12 +131,10 @@ VNET_DEFINE(u_int32_t, set_disable);
#define V_set_disable VNET(set_disable)
VNET_DEFINE(int, fw_verbose);
//#define V_verbose_limit VNET(verbose_limit)
/* counter for ipfw_log(NULL...) */
VNET_DEFINE(u_int64_t, norule_counter);
VNET_DEFINE(int, verbose_limit);
/* layer3_chain contains the list of rules for layer 3 */
VNET_DEFINE(struct ip_fw_chain, layer3_chain);
@ -147,8 +145,6 @@ ipfw_nat_cfg_t *ipfw_nat_del_ptr;
ipfw_nat_cfg_t *ipfw_nat_get_cfg_ptr;
ipfw_nat_cfg_t *ipfw_nat_get_log_ptr;
extern int ipfw_chg_hook(SYSCTL_HANDLER_ARGS);
#ifdef SYSCTL_NODE
SYSCTL_NODE(_net_inet_ip, OID_AUTO, fw, CTLFLAG_RW, 0, "Firewall");
SYSCTL_VNET_INT(_net_inet_ip_fw, OID_AUTO, one_pass,
@ -173,6 +169,9 @@ SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, default_to_accept, CTLFLAG_RDTUN,
&default_to_accept, 0,
"Make the default rule accept all packets.");
TUNABLE_INT("net.inet.ip.fw.default_to_accept", &default_to_accept);
SYSCTL_VNET_INT(_net_inet_ip_fw, OID_AUTO, static_count,
CTLFLAG_RD, &VNET_NAME(layer3_chain.n_rules), 0,
"Number of static rules");
#ifdef INET6
SYSCTL_DECL(_net_inet6_ip6);
@ -738,6 +737,17 @@ check_uidgid(ipfw_insn_u32 *insn, int proto, struct ifnet *oif,
return match;
}
/*
* Helper function to write the matching rule into args
*/
static inline void
set_match(struct ip_fw_args *args, struct ip_fw *f, struct ip_fw_chain *chain)
{
args->rule = f;
args->rule_id = f->id;
args->chain_id = chain->id;
}
/*
* The main check routine for the firewall.
*
@ -1942,13 +1952,9 @@ do { \
case O_PIPE:
case O_QUEUE:
args->rule = f; /* report matching rule */
args->rule_id = f->id;
args->chain_id = chain->id;
if (cmd->arg1 == IP_FW_TABLEARG)
args->cookie = tablearg;
else
args->cookie = cmd->arg1;
set_match(args, f, chain);
args->cookie = (cmd->arg1 == IP_FW_TABLEARG) ?
tablearg : cmd->arg1;
retval = IP_FW_DUMMYNET;
l = 0; /* exit inner loop */
done = 1; /* exit outer loop */
@ -2077,13 +2083,9 @@ do { \
case O_NETGRAPH:
case O_NGTEE:
args->rule = f; /* report matching rule */
args->rule_id = f->id;
args->chain_id = chain->id;
if (cmd->arg1 == IP_FW_TABLEARG)
args->cookie = tablearg;
else
args->cookie = cmd->arg1;
set_match(args, f, chain);
args->cookie = (cmd->arg1 == IP_FW_TABLEARG) ?
tablearg : cmd->arg1;
retval = (cmd->opcode == O_NETGRAPH) ?
IP_FW_NETGRAPH : IP_FW_NGTEE;
l = 0; /* exit inner loop */
@ -2106,14 +2108,12 @@ do { \
struct cfg_nat *t;
int nat_id;
args->rule = f; /* Report matching rule. */
args->rule_id = f->id;
args->chain_id = chain->id;
set_match(args, f, chain);
t = ((ipfw_insn_nat *)cmd)->nat;
if (t == NULL) {
nat_id = (cmd->arg1 == IP_FW_TABLEARG) ?
tablearg : cmd->arg1;
t = (*lookup_nat_ptr)(&V_layer3_chain.nat, nat_id);
t = (*lookup_nat_ptr)(&chain->nat, nat_id);
if (t == NULL) {
retval = IP_FW_DENY;
@ -2175,9 +2175,7 @@ do { \
else
ip->ip_sum = in_cksum(m, hlen);
retval = IP_FW_REASS;
args->rule = f;
args->rule_id = f->id;
args->chain_id = chain->id;
set_match(args, f, chain);
}
done = 1; /* exit outer loop */
break;
@ -2311,8 +2309,13 @@ vnet_ipfw_init(const void *unused)
{
int error;
struct ip_fw default_rule;
struct ip_fw_chain *chain;
chain = &V_layer3_chain;
/* First set up some values that are compile time options */
V_autoinc_step = 100; /* bounded to 1..1000 in add_rule() */
V_fw_deny_unknown_exthdrs = 1;
#ifdef IPFIREWALL_VERBOSE
V_fw_verbose = 1;
#endif
@ -2320,20 +2323,17 @@ vnet_ipfw_init(const void *unused)
V_verbose_limit = IPFIREWALL_VERBOSE_LIMIT;
#endif
error = ipfw_init_tables(&V_layer3_chain);
error = ipfw_init_tables(chain);
if (error) {
panic("init_tables"); /* XXX Marko fix this ! */
}
#ifdef IPFIREWALL_NAT
LIST_INIT(&V_layer3_chain.nat);
LIST_INIT(&chain->nat);
#endif
V_autoinc_step = 100; /* bounded to 1..1000 in add_rule() */
V_fw_deny_unknown_exthdrs = 1;
V_layer3_chain.rules = NULL;
IPFW_LOCK_INIT(&V_layer3_chain);
chain->rules = NULL;
IPFW_LOCK_INIT(chain);
bzero(&default_rule, sizeof default_rule);
default_rule.act_ofs = 0;
@ -2342,17 +2342,17 @@ vnet_ipfw_init(const void *unused)
default_rule.set = RESVD_SET;
default_rule.cmd[0].len = 1;
default_rule.cmd[0].opcode = default_to_accept ? O_ACCEPT : O_DENY;
error = ipfw_add_rule(&V_layer3_chain, &default_rule);
error = ipfw_add_rule(chain, &default_rule);
if (error != 0) {
printf("ipfw2: error %u initializing default rule "
"(support disabled)\n", error);
IPFW_LOCK_DESTROY(&V_layer3_chain);
IPFW_LOCK_DESTROY(chain);
printf("leaving ipfw_iattach (1) with error %d\n", error);
return (error);
}
V_layer3_chain.default_rule = V_layer3_chain.rules;
chain->default_rule = chain->rules;
ipfw_dyn_init();
@ -2386,6 +2386,7 @@ static int
vnet_ipfw_uninit(const void *unused)
{
struct ip_fw *reap;
struct ip_fw_chain *chain = &V_layer3_chain;
V_ipfw_vnet_ready = 0; /* tell new callers to go away */
/*
@ -2400,21 +2401,21 @@ vnet_ipfw_uninit(const void *unused)
V_ip_fw_chk_ptr = NULL;
V_ip_fw_ctl_ptr = NULL;
IPFW_WLOCK(&V_layer3_chain);
IPFW_WLOCK(chain);
/* We wait on the wlock here until the last user leaves */
IPFW_WUNLOCK(&V_layer3_chain);
IPFW_WLOCK(&V_layer3_chain);
IPFW_WUNLOCK(chain);
IPFW_WLOCK(chain);
ipfw_dyn_uninit(0); /* run the callout_drain */
ipfw_flush_tables(&V_layer3_chain);
V_layer3_chain.reap = NULL;
ipfw_free_chain(&V_layer3_chain, 1 /* kill default rule */);
reap = V_layer3_chain.reap;
V_layer3_chain.reap = NULL;
IPFW_WUNLOCK(&V_layer3_chain);
ipfw_flush_tables(chain);
chain->reap = NULL;
ipfw_free_chain(chain, 1 /* kill default rule */);
reap = chain->reap;
chain->reap = NULL;
IPFW_WUNLOCK(chain);
if (reap != NULL)
ipfw_reap_rules(reap);
IPFW_LOCK_DESTROY(&V_layer3_chain);
IPFW_LOCK_DESTROY(chain);
ipfw_dyn_uninit(1); /* free the remaining parts */
return 0;
}

View File

@ -78,9 +78,11 @@ struct ip_fw_args {
struct mbuf *m; /* the mbuf chain */
struct ifnet *oif; /* output interface */
struct sockaddr_in *next_hop; /* forward address */
struct ip_fw *rule; /* matching rule */
uint32_t rule_id; /* matching rule id */
uint32_t chain_id; /* ruleset id */
uint32_t rule_id; /* matching rule id */
uint32_t chain_id; /* ruleset id */
struct ether_header *eh; /* for bridged packets */
struct ipfw_flow_id f_id; /* grabbed from IP header */
@ -174,6 +176,8 @@ struct ip_fw_chain {
struct ip_fw *rules; /* list of rules */
struct ip_fw *reap; /* list of rules to reap */
struct ip_fw *default_rule;
int n_rules; /* number of static rules */
int static_len; /* total len of static rules */
LIST_HEAD(nat_list, cfg_nat) nat; /* list of nat entries */
struct radix_node_head *tables[IPFW_TABLES_MAX];
struct rwlock rwmtx;

View File

@ -77,23 +77,9 @@ __FBSDID("$FreeBSD$");
MALLOC_DEFINE(M_IPFW, "IpFw/IpAcct", "IpFw/IpAcct chain's");
/*
* static variables followed by global ones
* static variables followed by global ones (none in this file)
*/
static VNET_DEFINE(u_int32_t, static_count); /* # of static rules */
#define V_static_count VNET(static_count)
static VNET_DEFINE(u_int32_t, static_len); /* bytes of static rules */
#define V_static_len VNET(static_len)
#ifdef SYSCTL_NODE
SYSCTL_DECL(_net_inet_ip_fw);
SYSCTL_VNET_INT(_net_inet_ip_fw, OID_AUTO, static_count,
CTLFLAG_RD, &VNET_NAME(static_count), 0,
"Number of static rules");
#endif /* SYSCTL_NODE */
/*
* When a rule is added/deleted, clear the next_rule pointers in all rules.
* These will be reconstructed on the fly as packets are matched.
@ -187,11 +173,9 @@ ipfw_add_rule(struct ip_fw_chain *chain, struct ip_fw *input_rule)
/* chain->id incremented inside flush_rule_ptrs() */
rule->id = chain->id;
done:
V_static_count++;
V_static_len += l;
chain->n_rules++;
chain->static_len += l;
IPFW_WUNLOCK(chain);
DEB(printf("ipfw: installed rule %d, static count now %d\n",
rule->rulenum, V_static_count);)
return (0);
}
@ -218,8 +202,8 @@ remove_rule(struct ip_fw_chain *chain, struct ip_fw *rule,
chain->rules = n;
else
prev->next = n;
V_static_count--;
V_static_len -= l;
chain->n_rules--;
chain->static_len -= l;
rule->next = chain->reap;
chain->reap = rule;
@ -839,6 +823,7 @@ ipfw_ctl(struct sockopt *sopt)
int error;
size_t size;
struct ip_fw *buf, *rule;
struct ip_fw_chain *chain;
u_int32_t rulenum[2];
error = priv_check(sopt->sopt_td, PRIV_NETINET_IPFW);
@ -856,6 +841,7 @@ ipfw_ctl(struct sockopt *sopt)
return (error);
}
chain = &V_layer3_chain;
error = 0;
switch (sopt->sopt_name) {
@ -871,7 +857,7 @@ ipfw_ctl(struct sockopt *sopt)
* change between calculating the size and returning the
* data in which case we'll just return what fits.
*/
size = V_static_len; /* size of static rules */
size = chain->static_len; /* size of static rules */
size += ipfw_dyn_len();
if (size >= sopt->sopt_valsize)
@ -883,7 +869,7 @@ ipfw_ctl(struct sockopt *sopt)
*/
buf = malloc(size, M_TEMP, M_WAITOK);
error = sooptcopyout(sopt, buf,
ipfw_getrules(&V_layer3_chain, buf, size));
ipfw_getrules(chain, buf, size));
free(buf, M_TEMP);
break;
@ -901,10 +887,10 @@ ipfw_ctl(struct sockopt *sopt)
* the old list without the need for a lock.
*/
IPFW_WLOCK(&V_layer3_chain);
ipfw_free_chain(&V_layer3_chain, 0 /* keep default rule */);
rule = V_layer3_chain.reap;
IPFW_WUNLOCK(&V_layer3_chain);
IPFW_WLOCK(chain);
ipfw_free_chain(chain, 0 /* keep default rule */);
rule = chain->reap;
IPFW_WUNLOCK(chain);
ipfw_reap_rules(rule);
break;
@ -915,7 +901,7 @@ ipfw_ctl(struct sockopt *sopt)
if (error == 0)
error = check_ipfw_struct(rule, sopt->sopt_valsize);
if (error == 0) {
error = ipfw_add_rule(&V_layer3_chain, rule);
error = ipfw_add_rule(chain, rule);
size = RULESIZE(rule);
if (!error && sopt->sopt_dir == SOPT_GET)
error = sooptcopyout(sopt, rule, size);
@ -941,13 +927,14 @@ ipfw_ctl(struct sockopt *sopt)
if (error)
break;
size = sopt->sopt_valsize;
if (size == sizeof(u_int32_t)) /* delete or reassign */
error = del_entry(&V_layer3_chain, rulenum[0]);
else if (size == 2*sizeof(u_int32_t)) /* set enable/disable */
if (size == sizeof(u_int32_t) && rulenum[0] != 0) {
/* delete or reassign, locking done in del_entry() */
error = del_entry(chain, rulenum[0]);
} else if (size == 2*sizeof(u_int32_t)) { /* set enable/disable */
V_set_disable =
(V_set_disable | rulenum[0]) & ~rulenum[1] &
~(1<<RESVD_SET); /* set RESVD_SET always enabled */
else
} else
error = EINVAL;
break;
@ -960,10 +947,11 @@ ipfw_ctl(struct sockopt *sopt)
if (error)
break;
}
error = zero_entry(&V_layer3_chain, rulenum[0],
error = zero_entry(chain, rulenum[0],
sopt->sopt_name == IP_FW_RESETLOG);
break;
/*--- TABLE manipulations are protected by the IPFW_LOCK ---*/
case IP_FW_TABLE_ADD:
{
ipfw_table_entry ent;
@ -972,7 +960,7 @@ ipfw_ctl(struct sockopt *sopt)
sizeof(ent), sizeof(ent));
if (error)
break;
error = ipfw_add_table_entry(&V_layer3_chain, ent.tbl,
error = ipfw_add_table_entry(chain, ent.tbl,
ent.addr, ent.masklen, ent.value);
}
break;
@ -985,7 +973,7 @@ ipfw_ctl(struct sockopt *sopt)
sizeof(ent), sizeof(ent));
if (error)
break;
error = ipfw_del_table_entry(&V_layer3_chain, ent.tbl,
error = ipfw_del_table_entry(chain, ent.tbl,
ent.addr, ent.masklen);
}
break;
@ -998,9 +986,9 @@ ipfw_ctl(struct sockopt *sopt)
sizeof(tbl), sizeof(tbl));
if (error)
break;
IPFW_WLOCK(&V_layer3_chain);
error = ipfw_flush_table(&V_layer3_chain, tbl);
IPFW_WUNLOCK(&V_layer3_chain);
IPFW_WLOCK(chain);
error = ipfw_flush_table(chain, tbl);
IPFW_WUNLOCK(chain);
}
break;
@ -1011,9 +999,9 @@ ipfw_ctl(struct sockopt *sopt)
if ((error = sooptcopyin(sopt, &tbl, sizeof(tbl),
sizeof(tbl))))
break;
IPFW_RLOCK(&V_layer3_chain);
error = ipfw_count_table(&V_layer3_chain, tbl, &cnt);
IPFW_RUNLOCK(&V_layer3_chain);
IPFW_RLOCK(chain);
error = ipfw_count_table(chain, tbl, &cnt);
IPFW_RUNLOCK(chain);
if (error)
break;
error = sooptcopyout(sopt, &cnt, sizeof(cnt));
@ -1037,9 +1025,9 @@ ipfw_ctl(struct sockopt *sopt)
}
tbl->size = (size - sizeof(*tbl)) /
sizeof(ipfw_table_entry);
IPFW_RLOCK(&V_layer3_chain);
error = ipfw_dump_table(&V_layer3_chain, tbl);
IPFW_RUNLOCK(&V_layer3_chain);
IPFW_RLOCK(chain);
error = ipfw_dump_table(chain, tbl);
IPFW_RUNLOCK(chain);
if (error) {
free(tbl, M_TEMP);
break;
@ -1049,6 +1037,7 @@ ipfw_ctl(struct sockopt *sopt)
}
break;
/*--- NAT operations are protected by the IPFW_LOCK ---*/
case IP_FW_NAT_CFG:
if (IPFW_NAT_LOADED)
error = ipfw_nat_cfg_ptr(sopt);

View File

@ -34,6 +34,9 @@ __FBSDID("$FreeBSD$");
* keys are network prefixes (addr/masklen), and values are integers.
* As a degenerate case we can interpret keys as 32-bit integers
* (with a /32 mask).
*
* The table is protected by the IPFW lock even for manipulation coming
* from userland, because operations are typically fast.
*/
#if !defined(KLD_MODULE)