pf: Fix vnet purging

pf_purge_thread() breaks up the work of iterating all states (in
pf_purge_expired_states()) and tracks progress in the idx variable.

If multiple vnets exist this results in pf_purge_thread() only calling
pf_purge_expired_states() for part of the states (the first part of the
first vnet, second part of the second vnet and so on).
Combined with the mark-and-sweep approach to cleaning up old rules (in
V_pf_unlinked_rules) that resulted in pf freeing rules that were still
referenced by states. This in turn caused panics when pf_state_expires()
encounters that state and attempts to access the rule.

We need to track the progress per vnet, not globally, so idx is moved
into a per-vnet V_pf_purge_idx.

PR:		219251
Sponsored by:	Hackathon Essen 2017
This commit is contained in:
Kristof Provost 2017-07-09 17:56:39 +00:00
parent 14bcf3e185
commit b7ae43552b
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=320848

View File

@ -132,6 +132,9 @@ VNET_DEFINE(int, pf_tcp_iss_off);
VNET_DECLARE(int, pf_vnet_active);
#define V_pf_vnet_active VNET(pf_vnet_active)
static VNET_DEFINE(uint32_t, pf_purge_idx);
#define V_pf_purge_idx VNET(pf_purge_idx)
/*
* Queue for pf_intr() sends.
*/
@ -1427,7 +1430,6 @@ void
pf_purge_thread(void *unused __unused)
{
VNET_ITERATOR_DECL(vnet_iter);
u_int idx = 0;
sx_xlock(&pf_end_lock);
while (pf_end_threads == 0) {
@ -1448,14 +1450,15 @@ pf_purge_thread(void *unused __unused)
* Process 1/interval fraction of the state
* table every run.
*/
idx = pf_purge_expired_states(idx, pf_hashmask /
V_pf_purge_idx =
pf_purge_expired_states(V_pf_purge_idx, pf_hashmask /
(V_pf_default_rule.timeout[PFTM_INTERVAL] * 10));
/*
* Purge other expired types every
* PFTM_INTERVAL seconds.
*/
if (idx == 0) {
if (V_pf_purge_idx == 0) {
/*
* Order is important:
* - states and src nodes reference rules