pf: Split pf_src_node into a kernel and userspace struct

Introduce a kernel version of struct pf_src_node (pf_ksrc_node).

This will allow us to improve the in-kernel data structure without
breaking userspace compatibility.

Reviewed by:	philip
MFC after:	2 weeks
Sponsored by:	Orange Business Services
Differential Revision:	https://reviews.freebsd.org/D27707
This commit is contained in:
Kristof Provost 2020-12-23 14:51:52 +01:00
parent 4d86ab429e
commit 17ad7334ca
5 changed files with 129 additions and 85 deletions

View File

@ -54,21 +54,6 @@
#include <netpfil/pf/pf_altq.h>
#include <netpfil/pf/pf_mtag.h>
struct pf_addr {
union {
struct in_addr v4;
struct in6_addr v6;
u_int8_t addr8[16];
u_int16_t addr16[8];
u_int32_t addr32[4];
} pfa; /* 128-bit address */
#define v4 pfa.v4
#define v6 pfa.v6
#define addr8 pfa.addr8
#define addr16 pfa.addr16
#define addr32 pfa.addr32
};
#define PFI_AFLAG_NETWORK 0x01
#define PFI_AFLAG_BROADCAST 0x02
#define PFI_AFLAG_PEER 0x04
@ -480,11 +465,6 @@ struct pf_osfp_ioctl {
int fp_getnum; /* DIOCOSFPGET number */
};
union pf_rule_ptr {
struct pf_rule *ptr;
u_int32_t nr;
};
#define PF_ANCHOR_NAME_SIZE 64
struct pf_rule {
@ -628,17 +608,9 @@ struct pf_rule {
#define PFSTATE_ADAPT_START 60000 /* default adaptive timeout start */
#define PFSTATE_ADAPT_END 120000 /* default adaptive timeout end */
struct pf_threshold {
u_int32_t limit;
#define PF_THRESHOLD_MULT 1000
#define PF_THRESHOLD_MAX 0xffffffff / PF_THRESHOLD_MULT
u_int32_t seconds;
u_int32_t count;
u_int32_t last;
};
struct pf_src_node {
LIST_ENTRY(pf_src_node) entry;
#ifdef _KERNEL
struct pf_ksrc_node {
LIST_ENTRY(pf_ksrc_node) entry;
struct pf_addr addr;
struct pf_addr raddr;
union pf_rule_ptr rule;
@ -653,8 +625,7 @@ struct pf_src_node {
sa_family_t af;
u_int8_t ruletype;
};
#define PFSNODE_HIWAT 10000 /* default source node table size */
#endif
struct pf_state_scrub {
struct timeval pfss_last; /* time received last packet */
@ -738,8 +709,8 @@ struct pf_state {
struct pf_state_key *key[2]; /* addresses stack and wire */
struct pfi_kif *kif;
struct pfi_kif *rt_kif;
struct pf_src_node *src_node;
struct pf_src_node *nat_src_node;
struct pf_ksrc_node *src_node;
struct pf_ksrc_node *nat_src_node;
counter_u64_t packets[2];
counter_u64_t bytes[2];
u_int32_t creation;
@ -1581,9 +1552,9 @@ struct pf_ifspeed_v1 {
#endif /* _KERNEL */
#ifdef _KERNEL
LIST_HEAD(pf_src_node_list, pf_src_node);
LIST_HEAD(pf_ksrc_node_list, pf_ksrc_node);
struct pf_srchash {
struct pf_src_node_list nodes;
struct pf_ksrc_node_list nodes;
struct mtx lock;
};
@ -1695,10 +1666,10 @@ pf_release_state(struct pf_state *s)
extern struct pf_state *pf_find_state_byid(uint64_t, uint32_t);
extern struct pf_state *pf_find_state_all(struct pf_state_key_cmp *,
u_int, int *);
extern struct pf_src_node *pf_find_src_node(struct pf_addr *,
extern struct pf_ksrc_node *pf_find_src_node(struct pf_addr *,
struct pf_rule *, sa_family_t, int);
extern void pf_unlink_src_node(struct pf_src_node *);
extern u_int pf_free_src_nodes(struct pf_src_node_list *);
extern void pf_unlink_src_node(struct pf_ksrc_node *);
extern u_int pf_free_src_nodes(struct pf_ksrc_node_list *);
extern void pf_print_state(struct pf_state *);
extern void pf_print_flags(u_int8_t);
extern u_int16_t pf_cksum_fixup(u_int16_t, u_int16_t, u_int16_t,
@ -1890,9 +1861,9 @@ int pf_step_out_of_anchor(struct pf_anchor_stackframe *, int *,
int pf_map_addr(u_int8_t, struct pf_rule *,
struct pf_addr *, struct pf_addr *,
struct pf_addr *, struct pf_src_node **);
struct pf_addr *, struct pf_ksrc_node **);
struct pf_rule *pf_get_translation(struct pf_pdesc *, struct mbuf *,
int, int, struct pfi_kif *, struct pf_src_node **,
int, int, struct pfi_kif *, struct pf_ksrc_node **,
struct pf_state_key **, struct pf_state_key **,
struct pf_addr *, struct pf_addr *,
uint16_t, uint16_t, struct pf_anchor_stackframe *);

View File

@ -249,7 +249,7 @@ static int pf_test_rule(struct pf_rule **, struct pf_state **,
struct pf_ruleset **, struct inpcb *);
static int pf_create_state(struct pf_rule *, struct pf_rule *,
struct pf_rule *, struct pf_pdesc *,
struct pf_src_node *, struct pf_state_key *,
struct pf_ksrc_node *, struct pf_state_key *,
struct pf_state_key *, struct mbuf *, int,
u_int16_t, u_int16_t, int *, struct pfi_kif *,
struct pf_state **, int, u_int16_t, u_int16_t,
@ -294,7 +294,7 @@ static struct pf_state *pf_find_state(struct pfi_kif *,
struct pf_state_key_cmp *, u_int);
static int pf_src_connlimit(struct pf_state **);
static void pf_overload_task(void *v, int pending);
static int pf_insert_src_node(struct pf_src_node **,
static int pf_insert_src_node(struct pf_ksrc_node **,
struct pf_rule *, struct pf_addr *, sa_family_t);
static u_int pf_purge_expired_states(u_int, int);
static void pf_purge_unlinked_rules(void);
@ -677,12 +677,12 @@ pf_overload_task(void *v, int pending)
* Can return locked on failure, so that we can consistently
* allocate and insert a new one.
*/
struct pf_src_node *
struct pf_ksrc_node *
pf_find_src_node(struct pf_addr *src, struct pf_rule *rule, sa_family_t af,
int returnlocked)
{
struct pf_srchash *sh;
struct pf_src_node *n;
struct pf_ksrc_node *n;
counter_u64_add(V_pf_status.scounters[SCNT_SRC_NODE_SEARCH], 1);
@ -703,7 +703,7 @@ pf_find_src_node(struct pf_addr *src, struct pf_rule *rule, sa_family_t af,
}
static int
pf_insert_src_node(struct pf_src_node **sn, struct pf_rule *rule,
pf_insert_src_node(struct pf_ksrc_node **sn, struct pf_rule *rule,
struct pf_addr *src, sa_family_t af)
{
@ -757,7 +757,7 @@ pf_insert_src_node(struct pf_src_node **sn, struct pf_rule *rule,
}
void
pf_unlink_src_node(struct pf_src_node *src)
pf_unlink_src_node(struct pf_ksrc_node *src)
{
PF_HASHROW_ASSERT(&V_pf_srchash[pf_hashsrc(&src->addr, src->af)]);
@ -767,9 +767,9 @@ pf_unlink_src_node(struct pf_src_node *src)
}
u_int
pf_free_src_nodes(struct pf_src_node_list *head)
pf_free_src_nodes(struct pf_ksrc_node_list *head)
{
struct pf_src_node *sn, *tmp;
struct pf_ksrc_node *sn, *tmp;
u_int count = 0;
LIST_FOREACH_SAFE(sn, head, entry, tmp) {
@ -845,7 +845,7 @@ pf_initialize()
/* Source nodes. */
V_pf_sources_z = uma_zcreate("pf source nodes",
sizeof(struct pf_src_node), NULL, NULL, NULL, NULL, UMA_ALIGN_PTR,
sizeof(struct pf_ksrc_node), NULL, NULL, NULL, NULL, UMA_ALIGN_PTR,
0);
V_pf_limits[PF_LIMIT_SRC_NODES].zone = V_pf_sources_z;
uma_zone_set_max(V_pf_sources_z, PFSNODE_HIWAT);
@ -1596,9 +1596,9 @@ pf_state_expires(const struct pf_state *state)
void
pf_purge_expired_src_nodes()
{
struct pf_src_node_list freelist;
struct pf_ksrc_node_list freelist;
struct pf_srchash *sh;
struct pf_src_node *cur, *next;
struct pf_ksrc_node *cur, *next;
int i;
LIST_INIT(&freelist);
@ -1621,7 +1621,7 @@ pf_purge_expired_src_nodes()
static void
pf_src_tree_remove_state(struct pf_state *s)
{
struct pf_src_node *sn;
struct pf_ksrc_node *sn;
struct pf_srchash *sh;
uint32_t timeout;
@ -3310,7 +3310,7 @@ pf_test_rule(struct pf_rule **rm, struct pf_state **sm, int direction,
sa_family_t af = pd->af;
struct pf_rule *r, *a = NULL;
struct pf_ruleset *ruleset = NULL;
struct pf_src_node *nsn = NULL;
struct pf_ksrc_node *nsn = NULL;
struct tcphdr *th = pd->hdr.tcp;
struct pf_state_key *sk = NULL, *nk = NULL;
u_short reason;
@ -3675,13 +3675,13 @@ pf_test_rule(struct pf_rule **rm, struct pf_state **sm, int direction,
static int
pf_create_state(struct pf_rule *r, struct pf_rule *nr, struct pf_rule *a,
struct pf_pdesc *pd, struct pf_src_node *nsn, struct pf_state_key *nk,
struct pf_pdesc *pd, struct pf_ksrc_node *nsn, struct pf_state_key *nk,
struct pf_state_key *sk, struct mbuf *m, int off, u_int16_t sport,
u_int16_t dport, int *rewrite, struct pfi_kif *kif, struct pf_state **sm,
int tag, u_int16_t bproto_sum, u_int16_t bip_sum, int hdrlen)
{
struct pf_state *s = NULL;
struct pf_src_node *sn = NULL;
struct pf_ksrc_node *sn = NULL;
struct tcphdr *th = pd->hdr.tcp;
u_int16_t mss = V_tcp_mssdflt;
u_short reason;
@ -5447,7 +5447,7 @@ pf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
struct ip *ip;
struct ifnet *ifp = NULL;
struct pf_addr naddr;
struct pf_src_node *sn = NULL;
struct pf_ksrc_node *sn = NULL;
int error = 0;
uint16_t ip_len, ip_off;
@ -5610,7 +5610,7 @@ pf_route6(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
struct ip6_hdr *ip6;
struct ifnet *ifp = NULL;
struct pf_addr naddr;
struct pf_src_node *sn = NULL;
struct pf_ksrc_node *sn = NULL;
KASSERT(m && *m && r && oifp, ("%s: invalid parameters", __func__));
KASSERT(dir == PF_IN || dir == PF_OUT, ("%s: invalid direction",

View File

@ -185,6 +185,8 @@ enum { PF_ADDR_ADDRMASK, PF_ADDR_NOROUTE, PF_ADDR_DYNIFTL,
#define PF_TABLE_NAME_SIZE 32
#define PF_QNAME_SIZE 64
struct pf_rule;
struct pf_status {
uint64_t counters[PFRES_MAX];
uint64_t lcounters[LCNT_MAX];
@ -202,4 +204,52 @@ struct pf_status {
uint8_t pf_chksum[PF_MD5_DIGEST_LENGTH];
};
struct pf_addr {
union {
struct in_addr v4;
struct in6_addr v6;
u_int8_t addr8[16];
u_int16_t addr16[8];
u_int32_t addr32[4];
} pfa; /* 128-bit address */
#define v4 pfa.v4
#define v6 pfa.v6
#define addr8 pfa.addr8
#define addr16 pfa.addr16
#define addr32 pfa.addr32
};
union pf_rule_ptr {
struct pf_rule *ptr;
u_int32_t nr;
};
struct pf_threshold {
u_int32_t limit;
#define PF_THRESHOLD_MULT 1000
#define PF_THRESHOLD_MAX 0xffffffff / PF_THRESHOLD_MULT
u_int32_t seconds;
u_int32_t count;
u_int32_t last;
};
struct pf_src_node {
LIST_ENTRY(pf_src_node) entry;
struct pf_addr addr;
struct pf_addr raddr;
union pf_rule_ptr rule;
struct pfi_kif *kif;
u_int64_t bytes[2];
u_int64_t packets[2];
u_int32_t states;
u_int32_t conn;
struct pf_threshold conn_rate;
u_int32_t creation;
u_int32_t expire;
sa_family_t af;
u_int8_t ruletype;
};
#define PFSNODE_HIWAT 10000 /* default source node table size */
#endif /* _NET_PF_H_ */

View File

@ -116,6 +116,8 @@ static int pf_commit_rules(u_int32_t, int, char *);
static int pf_addr_setup(struct pf_ruleset *,
struct pf_addr_wrap *, sa_family_t);
static void pf_addr_copyout(struct pf_addr_wrap *);
static void pf_src_node_copy(const struct pf_ksrc_node *,
struct pf_src_node *);
#ifdef ALTQ
static int pf_export_kaltq(struct pf_altq *,
struct pfioc_altq_v1 *, size_t);
@ -191,7 +193,7 @@ struct cdev *pf_dev;
*/
static void pf_clear_states(void);
static int pf_clear_tables(void);
static void pf_clear_srcnodes(struct pf_src_node *);
static void pf_clear_srcnodes(struct pf_ksrc_node *);
static void pf_kill_srcnodes(struct pfioc_src_node_kill *);
static void pf_tbladdr_copyout(struct pf_addr_wrap *);
@ -1146,6 +1148,42 @@ pf_addr_copyout(struct pf_addr_wrap *addr)
}
}
static void
pf_src_node_copy(const struct pf_ksrc_node *in, struct pf_src_node *out)
{
int secs = time_uptime, diff;
bzero(out, sizeof(struct pf_src_node));
bcopy(&in->addr, &out->addr, sizeof(struct pf_addr));
bcopy(&in->raddr, &out->raddr, sizeof(struct pf_addr));
if (in->rule.ptr != NULL)
out->rule.nr = in->rule.ptr->nr;
bcopy(&in->bytes, &out->bytes, sizeof(u_int64_t) * 2);
bcopy(&in->packets, &out->packets, sizeof(u_int64_t) * 2);
out->states = in->states;
out->conn = in->conn;
out->af = in->af;
out->ruletype = in->ruletype;
out->creation = secs - in->creation;
if (out->expire > secs)
out->expire -= secs;
else
out->expire = 0;
/* Adjust the connection rate estimate. */
diff = secs - in->conn_rate.last;
if (diff >= in->conn_rate.seconds)
out->conn_rate.count = 0;
else
out->conn_rate.count -=
in->conn_rate.count * diff /
in->conn_rate.seconds;
}
#ifdef ALTQ
/*
* Handle export of struct pf_kaltq to user binaries that may be using any
@ -3765,7 +3803,8 @@ pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td
case DIOCGETSRCNODES: {
struct pfioc_src_nodes *psn = (struct pfioc_src_nodes *)addr;
struct pf_srchash *sh;
struct pf_src_node *n, *p, *pstore;
struct pf_ksrc_node *n;
struct pf_src_node *p, *pstore;
uint32_t i, nr = 0;
for (i = 0, sh = V_pf_srchash; i <= pf_srchashmask;
@ -3791,28 +3830,12 @@ pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td
i++, sh++) {
PF_HASHROW_LOCK(sh);
LIST_FOREACH(n, &sh->nodes, entry) {
int secs = time_uptime, diff;
if ((nr + 1) * sizeof(*p) > (unsigned)psn->psn_len)
break;
bcopy(n, p, sizeof(struct pf_src_node));
if (n->rule.ptr != NULL)
p->rule.nr = n->rule.ptr->nr;
p->creation = secs - p->creation;
if (p->expire > secs)
p->expire -= secs;
else
p->expire = 0;
pf_src_node_copy(n, p);
/* Adjust the connection rate estimate. */
diff = secs - n->conn_rate.last;
if (diff >= n->conn_rate.seconds)
p->conn_rate.count = 0;
else
p->conn_rate.count -=
n->conn_rate.count * diff /
n->conn_rate.seconds;
p++;
nr++;
}
@ -4037,7 +4060,7 @@ pf_clear_tables(void)
}
static void
pf_clear_srcnodes(struct pf_src_node *n)
pf_clear_srcnodes(struct pf_ksrc_node *n)
{
struct pf_state *s;
int i;
@ -4077,12 +4100,12 @@ pf_clear_srcnodes(struct pf_src_node *n)
static void
pf_kill_srcnodes(struct pfioc_src_node_kill *psnk)
{
struct pf_src_node_list kill;
struct pf_ksrc_node_list kill;
LIST_INIT(&kill);
for (int i = 0; i <= pf_srchashmask; i++) {
struct pf_srchash *sh = &V_pf_srchash[i];
struct pf_src_node *sn, *tmp;
struct pf_ksrc_node *sn, *tmp;
PF_HASHROW_LOCK(sh);
LIST_FOREACH_SAFE(sn, &sh->nodes, entry, tmp)

View File

@ -64,7 +64,7 @@ static struct pf_rule *pf_match_translation(struct pf_pdesc *, struct mbuf *,
uint16_t, int, struct pf_anchor_stackframe *);
static int pf_get_sport(sa_family_t, uint8_t, struct pf_rule *,
struct pf_addr *, uint16_t, struct pf_addr *, uint16_t, struct pf_addr *,
uint16_t *, uint16_t, uint16_t, struct pf_src_node **);
uint16_t *, uint16_t, uint16_t, struct pf_ksrc_node **);
#define mix(a,b,c) \
do { \
@ -215,7 +215,7 @@ static int
pf_get_sport(sa_family_t af, u_int8_t proto, struct pf_rule *r,
struct pf_addr *saddr, uint16_t sport, struct pf_addr *daddr,
uint16_t dport, struct pf_addr *naddr, uint16_t *nport, uint16_t low,
uint16_t high, struct pf_src_node **sn)
uint16_t high, struct pf_ksrc_node **sn)
{
struct pf_state_key_cmp key;
struct pf_addr init_addr;
@ -312,7 +312,7 @@ pf_get_sport(sa_family_t af, u_int8_t proto, struct pf_rule *r,
int
pf_map_addr(sa_family_t af, struct pf_rule *r, struct pf_addr *saddr,
struct pf_addr *naddr, struct pf_addr *init_addr, struct pf_src_node **sn)
struct pf_addr *naddr, struct pf_addr *init_addr, struct pf_ksrc_node **sn)
{
struct pf_pool *rpool = &r->rpool;
struct pf_addr *raddr = NULL, *rmask = NULL;
@ -522,7 +522,7 @@ pf_map_addr(sa_family_t af, struct pf_rule *r, struct pf_addr *saddr,
struct pf_rule *
pf_get_translation(struct pf_pdesc *pd, struct mbuf *m, int off, int direction,
struct pfi_kif *kif, struct pf_src_node **sn,
struct pfi_kif *kif, struct pf_ksrc_node **sn,
struct pf_state_key **skp, struct pf_state_key **nkp,
struct pf_addr *saddr, struct pf_addr *daddr,
uint16_t sport, uint16_t dport, struct pf_anchor_stackframe *anchor_stack)