2009-12-15 16:15:14 +00:00
|
|
|
/*-
|
|
|
|
* 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
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
|
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
|
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
|
|
* SUCH DAMAGE.
|
|
|
|
*
|
|
|
|
* $FreeBSD$
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef _IPFW2_PRIVATE_H
|
|
|
|
#define _IPFW2_PRIVATE_H
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Internal constants and data structures used by ipfw components
|
|
|
|
* and not meant to be exported outside the kernel.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef _KERNEL
|
|
|
|
|
|
|
|
#define MTAG_IPFW 1148380143 /* IPFW-tagged cookie */
|
|
|
|
|
|
|
|
/* Return values from ipfw_chk() */
|
|
|
|
enum {
|
|
|
|
IP_FW_PASS = 0,
|
|
|
|
IP_FW_DENY,
|
|
|
|
IP_FW_DIVERT,
|
|
|
|
IP_FW_TEE,
|
|
|
|
IP_FW_DUMMYNET,
|
|
|
|
IP_FW_NETGRAPH,
|
|
|
|
IP_FW_NGTEE,
|
|
|
|
IP_FW_NAT,
|
|
|
|
IP_FW_REASS,
|
|
|
|
};
|
|
|
|
|
|
|
|
/* flags for divert mtag */
|
|
|
|
#define IP_FW_DIVERT_LOOPBACK_FLAG 0x00080000
|
|
|
|
#define IP_FW_DIVERT_OUTPUT_FLAG 0x00100000
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Structure for collecting parameters to dummynet for ip6_output forwarding
|
|
|
|
*/
|
|
|
|
struct _ip6dn_args {
|
|
|
|
struct ip6_pktopts *opt_or;
|
|
|
|
struct route_in6 ro_or;
|
|
|
|
int flags_or;
|
|
|
|
struct ip6_moptions *im6o_or;
|
|
|
|
struct ifnet *origifp_or;
|
|
|
|
struct ifnet *ifp_or;
|
|
|
|
struct sockaddr_in6 dst_or;
|
|
|
|
u_long mtu_or;
|
|
|
|
struct route_in6 ro_pmtu_or;
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Arguments for calling ipfw_chk() and dummynet_io(). We put them
|
|
|
|
* all into a structure because this way it is easier and more
|
|
|
|
* efficient to pass variables around and extend the interface.
|
|
|
|
*/
|
|
|
|
struct ip_fw_args {
|
|
|
|
struct mbuf *m; /* the mbuf chain */
|
|
|
|
struct ifnet *oif; /* output interface */
|
|
|
|
struct sockaddr_in *next_hop; /* forward address */
|
2009-12-22 13:53:34 +00:00
|
|
|
|
merge code from ipfw3-head to reduce contention on the ipfw lock
and remove all O(N) sequences from kernel critical sections in ipfw.
In detail:
1. introduce a IPFW_UH_LOCK to arbitrate requests from
the upper half of the kernel. Some things, such as 'ipfw show',
can be done holding this lock in read mode, whereas insert and
delete require IPFW_UH_WLOCK.
2. introduce a mapping structure to keep rules together. This replaces
the 'next' chain currently used in ipfw rules. At the moment
the map is a simple array (sorted by rule number and then rule_id),
so we can find a rule quickly instead of having to scan the list.
This reduces many expensive lookups from O(N) to O(log N).
3. when an expensive operation (such as insert or delete) is done
by userland, we grab IPFW_UH_WLOCK, create a new copy of the map
without blocking the bottom half of the kernel, then acquire
IPFW_WLOCK and quickly update pointers to the map and related info.
After dropping IPFW_LOCK we can then continue the cleanup protected
by IPFW_UH_LOCK. So userland still costs O(N) but the kernel side
is only blocked for O(1).
4. do not pass pointers to rules through dummynet, netgraph, divert etc,
but rather pass a <slot, chain_id, rulenum, rule_id> tuple.
We validate the slot index (in the array of #2) with chain_id,
and if successful do a O(1) dereference; otherwise, we can find
the rule in O(log N) through <rulenum, rule_id>
All the above does not change the userland/kernel ABI, though there
are some disgusting casts between pointers and uint32_t
Operation costs now are as follows:
Function Old Now Planned
-------------------------------------------------------------------
+ skipto X, non cached O(N) O(log N)
+ skipto X, cached O(1) O(1)
XXX dynamic rule lookup O(1) O(log N) O(1)
+ skipto tablearg O(N) O(1)
+ reinject, non cached O(N) O(log N)
+ reinject, cached O(1) O(1)
+ kernel blocked during setsockopt() O(N) O(1)
-------------------------------------------------------------------
The only (very small) regression is on dynamic rule lookup and this will
be fixed in a day or two, without changing the userland/kernel ABI
Supported by: Valeria Paoli
MFC after: 1 month
2009-12-22 19:01:47 +00:00
|
|
|
/* chain_id validates 'slot', the location of the pointer to
|
|
|
|
* a matching rule.
|
|
|
|
* If invalid, we can lookup the rule using rule_id and rulenum
|
|
|
|
*/
|
|
|
|
uint32_t slot; /* slot for matching rule */
|
|
|
|
uint32_t rulenum; /* matching rule number */
|
2009-12-22 13:53:34 +00:00
|
|
|
uint32_t rule_id; /* matching rule id */
|
|
|
|
uint32_t chain_id; /* ruleset id */
|
|
|
|
|
2009-12-15 16:15:14 +00:00
|
|
|
struct ether_header *eh; /* for bridged packets */
|
|
|
|
|
|
|
|
struct ipfw_flow_id f_id; /* grabbed from IP header */
|
|
|
|
uint32_t cookie; /* a cookie depending on rule action */
|
|
|
|
struct inpcb *inp;
|
|
|
|
|
|
|
|
struct _ip6dn_args dummypar; /* dummynet->ip6_output */
|
|
|
|
struct sockaddr_in hopstore; /* store here if cannot use a pointer */
|
|
|
|
};
|
|
|
|
|
|
|
|
MALLOC_DECLARE(M_IPFW);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Function definitions.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* Firewall hooks */
|
|
|
|
|
2009-12-16 10:48:40 +00:00
|
|
|
int ipfw_check_in(void *, struct mbuf **, struct ifnet *,
|
|
|
|
int, struct inpcb *inp);
|
|
|
|
int ipfw_check_out(void *, struct mbuf **, struct ifnet *,
|
|
|
|
int, struct inpcb *inp);
|
2009-12-15 16:15:14 +00:00
|
|
|
|
2009-12-16 10:48:40 +00:00
|
|
|
int ipfw_attach_hooks(void);
|
2009-12-15 16:15:14 +00:00
|
|
|
int ipfw_unhook(void);
|
|
|
|
int ipfw6_unhook(void);
|
|
|
|
#ifdef NOTYET
|
|
|
|
void ipfw_nat_destroy(void);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* In ip_fw_log.c */
|
|
|
|
struct ip;
|
2009-12-17 23:11:16 +00:00
|
|
|
void ipfw_log_bpf(int);
|
2009-12-15 16:15:14 +00:00
|
|
|
void ipfw_log(struct ip_fw *f, u_int hlen, struct ip_fw_args *args,
|
|
|
|
struct mbuf *m, struct ifnet *oif, u_short offset, uint32_t tablearg,
|
|
|
|
struct ip *ip);
|
|
|
|
VNET_DECLARE(u_int64_t, norule_counter);
|
|
|
|
#define V_norule_counter VNET(norule_counter)
|
|
|
|
VNET_DECLARE(int, verbose_limit);
|
|
|
|
#define V_verbose_limit VNET(verbose_limit)
|
|
|
|
|
|
|
|
/* In ip_fw_dynamic.c */
|
|
|
|
|
|
|
|
enum { /* result for matching dynamic rules */
|
|
|
|
MATCH_REVERSE = 0,
|
|
|
|
MATCH_FORWARD,
|
|
|
|
MATCH_NONE,
|
|
|
|
MATCH_UNKNOWN,
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The lock for dynamic rules is only used once outside the file,
|
|
|
|
* and only to release the result of lookup_dyn_rule().
|
|
|
|
* Eventually we may implement it with a callback on the function.
|
|
|
|
*/
|
|
|
|
void ipfw_dyn_unlock(void);
|
|
|
|
|
|
|
|
struct tcphdr;
|
2009-12-16 10:48:40 +00:00
|
|
|
struct mbuf *ipfw_send_pkt(struct mbuf *, struct ipfw_flow_id *,
|
2009-12-15 16:15:14 +00:00
|
|
|
u_int32_t, u_int32_t, int);
|
2009-12-16 10:48:40 +00:00
|
|
|
int ipfw_install_state(struct ip_fw *rule, ipfw_insn_limit *cmd,
|
2009-12-15 16:15:14 +00:00
|
|
|
struct ip_fw_args *args, uint32_t tablearg);
|
2009-12-16 10:48:40 +00:00
|
|
|
ipfw_dyn_rule *ipfw_lookup_dyn_rule(struct ipfw_flow_id *pkt,
|
|
|
|
int *match_direction, struct tcphdr *tcp);
|
|
|
|
void ipfw_remove_dyn_children(struct ip_fw *rule);
|
2009-12-15 16:15:14 +00:00
|
|
|
void ipfw_get_dynamic(char **bp, const char *ep);
|
|
|
|
|
|
|
|
void ipfw_dyn_attach(void); /* uma_zcreate .... */
|
|
|
|
void ipfw_dyn_detach(void); /* uma_zdestroy ... */
|
|
|
|
void ipfw_dyn_init(void); /* per-vnet initialization */
|
|
|
|
void ipfw_dyn_uninit(int); /* per-vnet deinitialization */
|
|
|
|
int ipfw_dyn_len(void);
|
|
|
|
|
|
|
|
/* common variables */
|
|
|
|
VNET_DECLARE(int, fw_one_pass);
|
2009-12-16 10:48:40 +00:00
|
|
|
#define V_fw_one_pass VNET(fw_one_pass)
|
|
|
|
|
2009-12-15 16:15:14 +00:00
|
|
|
VNET_DECLARE(int, fw_verbose);
|
2009-12-16 10:48:40 +00:00
|
|
|
#define V_fw_verbose VNET(fw_verbose)
|
2009-12-15 16:15:14 +00:00
|
|
|
|
2009-12-16 10:48:40 +00:00
|
|
|
VNET_DECLARE(struct ip_fw_chain, layer3_chain);
|
2009-12-15 16:15:14 +00:00
|
|
|
#define V_layer3_chain VNET(layer3_chain)
|
2009-12-16 10:48:40 +00:00
|
|
|
|
|
|
|
VNET_DECLARE(u_int32_t, set_disable);
|
2009-12-15 21:24:12 +00:00
|
|
|
#define V_set_disable VNET(set_disable)
|
2009-12-15 16:15:14 +00:00
|
|
|
|
2009-12-16 10:48:40 +00:00
|
|
|
VNET_DECLARE(int, autoinc_step);
|
|
|
|
#define V_autoinc_step VNET(autoinc_step)
|
2009-12-15 16:15:14 +00:00
|
|
|
|
|
|
|
struct ip_fw_chain {
|
|
|
|
struct ip_fw *rules; /* list of rules */
|
|
|
|
struct ip_fw *reap; /* list of rules to reap */
|
2009-12-16 10:48:40 +00:00
|
|
|
struct ip_fw *default_rule;
|
2009-12-22 13:53:34 +00:00
|
|
|
int n_rules; /* number of static rules */
|
|
|
|
int static_len; /* total len of static rules */
|
merge code from ipfw3-head to reduce contention on the ipfw lock
and remove all O(N) sequences from kernel critical sections in ipfw.
In detail:
1. introduce a IPFW_UH_LOCK to arbitrate requests from
the upper half of the kernel. Some things, such as 'ipfw show',
can be done holding this lock in read mode, whereas insert and
delete require IPFW_UH_WLOCK.
2. introduce a mapping structure to keep rules together. This replaces
the 'next' chain currently used in ipfw rules. At the moment
the map is a simple array (sorted by rule number and then rule_id),
so we can find a rule quickly instead of having to scan the list.
This reduces many expensive lookups from O(N) to O(log N).
3. when an expensive operation (such as insert or delete) is done
by userland, we grab IPFW_UH_WLOCK, create a new copy of the map
without blocking the bottom half of the kernel, then acquire
IPFW_WLOCK and quickly update pointers to the map and related info.
After dropping IPFW_LOCK we can then continue the cleanup protected
by IPFW_UH_LOCK. So userland still costs O(N) but the kernel side
is only blocked for O(1).
4. do not pass pointers to rules through dummynet, netgraph, divert etc,
but rather pass a <slot, chain_id, rulenum, rule_id> tuple.
We validate the slot index (in the array of #2) with chain_id,
and if successful do a O(1) dereference; otherwise, we can find
the rule in O(log N) through <rulenum, rule_id>
All the above does not change the userland/kernel ABI, though there
are some disgusting casts between pointers and uint32_t
Operation costs now are as follows:
Function Old Now Planned
-------------------------------------------------------------------
+ skipto X, non cached O(N) O(log N)
+ skipto X, cached O(1) O(1)
XXX dynamic rule lookup O(1) O(log N) O(1)
+ skipto tablearg O(N) O(1)
+ reinject, non cached O(N) O(log N)
+ reinject, cached O(1) O(1)
+ kernel blocked during setsockopt() O(N) O(1)
-------------------------------------------------------------------
The only (very small) regression is on dynamic rule lookup and this will
be fixed in a day or two, without changing the userland/kernel ABI
Supported by: Valeria Paoli
MFC after: 1 month
2009-12-22 19:01:47 +00:00
|
|
|
struct ip_fw **map; /* array of rule ptrs to ease lookup */
|
2009-12-15 16:15:14 +00:00
|
|
|
LIST_HEAD(nat_list, cfg_nat) nat; /* list of nat entries */
|
|
|
|
struct radix_node_head *tables[IPFW_TABLES_MAX];
|
|
|
|
struct rwlock rwmtx;
|
merge code from ipfw3-head to reduce contention on the ipfw lock
and remove all O(N) sequences from kernel critical sections in ipfw.
In detail:
1. introduce a IPFW_UH_LOCK to arbitrate requests from
the upper half of the kernel. Some things, such as 'ipfw show',
can be done holding this lock in read mode, whereas insert and
delete require IPFW_UH_WLOCK.
2. introduce a mapping structure to keep rules together. This replaces
the 'next' chain currently used in ipfw rules. At the moment
the map is a simple array (sorted by rule number and then rule_id),
so we can find a rule quickly instead of having to scan the list.
This reduces many expensive lookups from O(N) to O(log N).
3. when an expensive operation (such as insert or delete) is done
by userland, we grab IPFW_UH_WLOCK, create a new copy of the map
without blocking the bottom half of the kernel, then acquire
IPFW_WLOCK and quickly update pointers to the map and related info.
After dropping IPFW_LOCK we can then continue the cleanup protected
by IPFW_UH_LOCK. So userland still costs O(N) but the kernel side
is only blocked for O(1).
4. do not pass pointers to rules through dummynet, netgraph, divert etc,
but rather pass a <slot, chain_id, rulenum, rule_id> tuple.
We validate the slot index (in the array of #2) with chain_id,
and if successful do a O(1) dereference; otherwise, we can find
the rule in O(log N) through <rulenum, rule_id>
All the above does not change the userland/kernel ABI, though there
are some disgusting casts between pointers and uint32_t
Operation costs now are as follows:
Function Old Now Planned
-------------------------------------------------------------------
+ skipto X, non cached O(N) O(log N)
+ skipto X, cached O(1) O(1)
XXX dynamic rule lookup O(1) O(log N) O(1)
+ skipto tablearg O(N) O(1)
+ reinject, non cached O(N) O(log N)
+ reinject, cached O(1) O(1)
+ kernel blocked during setsockopt() O(N) O(1)
-------------------------------------------------------------------
The only (very small) regression is on dynamic rule lookup and this will
be fixed in a day or two, without changing the userland/kernel ABI
Supported by: Valeria Paoli
MFC after: 1 month
2009-12-22 19:01:47 +00:00
|
|
|
struct rwlock uh_lock; /* lock for upper half */
|
2009-12-15 16:15:14 +00:00
|
|
|
uint32_t id; /* ruleset id */
|
|
|
|
};
|
|
|
|
|
|
|
|
struct sockopt; /* used by tcp_var.h */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The lock is heavily used by ip_fw2.c (the main file) and ip_fw_nat.c
|
|
|
|
* so the variable and the macros must be here.
|
|
|
|
*/
|
|
|
|
|
merge code from ipfw3-head to reduce contention on the ipfw lock
and remove all O(N) sequences from kernel critical sections in ipfw.
In detail:
1. introduce a IPFW_UH_LOCK to arbitrate requests from
the upper half of the kernel. Some things, such as 'ipfw show',
can be done holding this lock in read mode, whereas insert and
delete require IPFW_UH_WLOCK.
2. introduce a mapping structure to keep rules together. This replaces
the 'next' chain currently used in ipfw rules. At the moment
the map is a simple array (sorted by rule number and then rule_id),
so we can find a rule quickly instead of having to scan the list.
This reduces many expensive lookups from O(N) to O(log N).
3. when an expensive operation (such as insert or delete) is done
by userland, we grab IPFW_UH_WLOCK, create a new copy of the map
without blocking the bottom half of the kernel, then acquire
IPFW_WLOCK and quickly update pointers to the map and related info.
After dropping IPFW_LOCK we can then continue the cleanup protected
by IPFW_UH_LOCK. So userland still costs O(N) but the kernel side
is only blocked for O(1).
4. do not pass pointers to rules through dummynet, netgraph, divert etc,
but rather pass a <slot, chain_id, rulenum, rule_id> tuple.
We validate the slot index (in the array of #2) with chain_id,
and if successful do a O(1) dereference; otherwise, we can find
the rule in O(log N) through <rulenum, rule_id>
All the above does not change the userland/kernel ABI, though there
are some disgusting casts between pointers and uint32_t
Operation costs now are as follows:
Function Old Now Planned
-------------------------------------------------------------------
+ skipto X, non cached O(N) O(log N)
+ skipto X, cached O(1) O(1)
XXX dynamic rule lookup O(1) O(log N) O(1)
+ skipto tablearg O(N) O(1)
+ reinject, non cached O(N) O(log N)
+ reinject, cached O(1) O(1)
+ kernel blocked during setsockopt() O(N) O(1)
-------------------------------------------------------------------
The only (very small) regression is on dynamic rule lookup and this will
be fixed in a day or two, without changing the userland/kernel ABI
Supported by: Valeria Paoli
MFC after: 1 month
2009-12-22 19:01:47 +00:00
|
|
|
#define IPFW_LOCK_INIT(_chain) do { \
|
|
|
|
rw_init(&(_chain)->rwmtx, "IPFW static rules"); \
|
|
|
|
rw_init(&(_chain)->uh_lock, "IPFW UH lock"); \
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
#define IPFW_LOCK_DESTROY(_chain) do { \
|
|
|
|
rw_destroy(&(_chain)->rwmtx); \
|
|
|
|
rw_destroy(&(_chain)->uh_lock); \
|
|
|
|
} while (0)
|
|
|
|
|
2009-12-15 16:15:14 +00:00
|
|
|
#define IPFW_WLOCK_ASSERT(_chain) rw_assert(&(_chain)->rwmtx, RA_WLOCKED)
|
|
|
|
|
|
|
|
#define IPFW_RLOCK(p) rw_rlock(&(p)->rwmtx)
|
|
|
|
#define IPFW_RUNLOCK(p) rw_runlock(&(p)->rwmtx)
|
|
|
|
#define IPFW_WLOCK(p) rw_wlock(&(p)->rwmtx)
|
|
|
|
#define IPFW_WUNLOCK(p) rw_wunlock(&(p)->rwmtx)
|
|
|
|
|
merge code from ipfw3-head to reduce contention on the ipfw lock
and remove all O(N) sequences from kernel critical sections in ipfw.
In detail:
1. introduce a IPFW_UH_LOCK to arbitrate requests from
the upper half of the kernel. Some things, such as 'ipfw show',
can be done holding this lock in read mode, whereas insert and
delete require IPFW_UH_WLOCK.
2. introduce a mapping structure to keep rules together. This replaces
the 'next' chain currently used in ipfw rules. At the moment
the map is a simple array (sorted by rule number and then rule_id),
so we can find a rule quickly instead of having to scan the list.
This reduces many expensive lookups from O(N) to O(log N).
3. when an expensive operation (such as insert or delete) is done
by userland, we grab IPFW_UH_WLOCK, create a new copy of the map
without blocking the bottom half of the kernel, then acquire
IPFW_WLOCK and quickly update pointers to the map and related info.
After dropping IPFW_LOCK we can then continue the cleanup protected
by IPFW_UH_LOCK. So userland still costs O(N) but the kernel side
is only blocked for O(1).
4. do not pass pointers to rules through dummynet, netgraph, divert etc,
but rather pass a <slot, chain_id, rulenum, rule_id> tuple.
We validate the slot index (in the array of #2) with chain_id,
and if successful do a O(1) dereference; otherwise, we can find
the rule in O(log N) through <rulenum, rule_id>
All the above does not change the userland/kernel ABI, though there
are some disgusting casts between pointers and uint32_t
Operation costs now are as follows:
Function Old Now Planned
-------------------------------------------------------------------
+ skipto X, non cached O(N) O(log N)
+ skipto X, cached O(1) O(1)
XXX dynamic rule lookup O(1) O(log N) O(1)
+ skipto tablearg O(N) O(1)
+ reinject, non cached O(N) O(log N)
+ reinject, cached O(1) O(1)
+ kernel blocked during setsockopt() O(N) O(1)
-------------------------------------------------------------------
The only (very small) regression is on dynamic rule lookup and this will
be fixed in a day or two, without changing the userland/kernel ABI
Supported by: Valeria Paoli
MFC after: 1 month
2009-12-22 19:01:47 +00:00
|
|
|
#define IPFW_UH_RLOCK(p) rw_rlock(&(p)->uh_lock)
|
|
|
|
#define IPFW_UH_RUNLOCK(p) rw_runlock(&(p)->uh_lock)
|
|
|
|
#define IPFW_UH_WLOCK(p) rw_wlock(&(p)->uh_lock)
|
|
|
|
#define IPFW_UH_WUNLOCK(p) rw_wunlock(&(p)->uh_lock)
|
|
|
|
|
2009-12-15 21:24:12 +00:00
|
|
|
/* In ip_fw_sockopt.c */
|
merge code from ipfw3-head to reduce contention on the ipfw lock
and remove all O(N) sequences from kernel critical sections in ipfw.
In detail:
1. introduce a IPFW_UH_LOCK to arbitrate requests from
the upper half of the kernel. Some things, such as 'ipfw show',
can be done holding this lock in read mode, whereas insert and
delete require IPFW_UH_WLOCK.
2. introduce a mapping structure to keep rules together. This replaces
the 'next' chain currently used in ipfw rules. At the moment
the map is a simple array (sorted by rule number and then rule_id),
so we can find a rule quickly instead of having to scan the list.
This reduces many expensive lookups from O(N) to O(log N).
3. when an expensive operation (such as insert or delete) is done
by userland, we grab IPFW_UH_WLOCK, create a new copy of the map
without blocking the bottom half of the kernel, then acquire
IPFW_WLOCK and quickly update pointers to the map and related info.
After dropping IPFW_LOCK we can then continue the cleanup protected
by IPFW_UH_LOCK. So userland still costs O(N) but the kernel side
is only blocked for O(1).
4. do not pass pointers to rules through dummynet, netgraph, divert etc,
but rather pass a <slot, chain_id, rulenum, rule_id> tuple.
We validate the slot index (in the array of #2) with chain_id,
and if successful do a O(1) dereference; otherwise, we can find
the rule in O(log N) through <rulenum, rule_id>
All the above does not change the userland/kernel ABI, though there
are some disgusting casts between pointers and uint32_t
Operation costs now are as follows:
Function Old Now Planned
-------------------------------------------------------------------
+ skipto X, non cached O(N) O(log N)
+ skipto X, cached O(1) O(1)
XXX dynamic rule lookup O(1) O(log N) O(1)
+ skipto tablearg O(N) O(1)
+ reinject, non cached O(N) O(log N)
+ reinject, cached O(1) O(1)
+ kernel blocked during setsockopt() O(N) O(1)
-------------------------------------------------------------------
The only (very small) regression is on dynamic rule lookup and this will
be fixed in a day or two, without changing the userland/kernel ABI
Supported by: Valeria Paoli
MFC after: 1 month
2009-12-22 19:01:47 +00:00
|
|
|
int ipfw_find_rule(struct ip_fw_chain *chain, uint32_t key, uint32_t id);
|
2009-12-15 21:24:12 +00:00
|
|
|
int ipfw_add_rule(struct ip_fw_chain *chain, struct ip_fw *input_rule);
|
|
|
|
int ipfw_ctl(struct sockopt *sopt);
|
|
|
|
int ipfw_chk(struct ip_fw_args *args);
|
|
|
|
void ipfw_reap_rules(struct ip_fw *head);
|
|
|
|
|
|
|
|
/* In ip_fw_table.c */
|
|
|
|
struct radix_node;
|
|
|
|
int ipfw_lookup_table(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr,
|
|
|
|
uint32_t *val);
|
|
|
|
int ipfw_init_tables(struct ip_fw_chain *ch);
|
|
|
|
int ipfw_flush_table(struct ip_fw_chain *ch, uint16_t tbl);
|
|
|
|
void ipfw_flush_tables(struct ip_fw_chain *ch);
|
|
|
|
int ipfw_add_table_entry(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr,
|
|
|
|
uint8_t mlen, uint32_t value);
|
|
|
|
int ipfw_dump_table_entry(struct radix_node *rn, void *arg);
|
|
|
|
int ipfw_del_table_entry(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr,
|
|
|
|
uint8_t mlen);
|
|
|
|
int ipfw_count_table(struct ip_fw_chain *ch, uint32_t tbl, uint32_t *cnt);
|
|
|
|
int ipfw_dump_table(struct ip_fw_chain *ch, ipfw_table *tbl);
|
|
|
|
|
2009-12-15 16:15:14 +00:00
|
|
|
/* In ip_fw_nat.c */
|
2009-12-15 21:24:12 +00:00
|
|
|
|
2009-12-15 16:15:14 +00:00
|
|
|
extern struct cfg_nat *(*lookup_nat_ptr)(struct nat_list *, int);
|
|
|
|
|
|
|
|
typedef int ipfw_nat_t(struct ip_fw_args *, struct cfg_nat *, struct mbuf *);
|
|
|
|
typedef int ipfw_nat_cfg_t(struct sockopt *);
|
|
|
|
|
2009-12-15 21:24:12 +00:00
|
|
|
extern ipfw_nat_t *ipfw_nat_ptr;
|
|
|
|
#define IPFW_NAT_LOADED (ipfw_nat_ptr != NULL)
|
|
|
|
|
|
|
|
extern ipfw_nat_cfg_t *ipfw_nat_cfg_ptr;
|
|
|
|
extern ipfw_nat_cfg_t *ipfw_nat_del_ptr;
|
|
|
|
extern ipfw_nat_cfg_t *ipfw_nat_get_cfg_ptr;
|
|
|
|
extern ipfw_nat_cfg_t *ipfw_nat_get_log_ptr;
|
|
|
|
|
2009-12-15 16:15:14 +00:00
|
|
|
#endif /* _KERNEL */
|
|
|
|
#endif /* _IPFW2_PRIVATE_H */
|