On 18/07/17(Tue) 15:55, Martin Pieuchot wrote: > When forwarding a lot of traffic with 10G interfaces contention on the > NET_LOCK() is "visible". Each time you type "ifconfig" you can go grab > a coffee... > > The problem has a name: pf_purge_thread(). This thread is created by > default and run even if you don't have PF enabled. Every `hz' it wakes > up, grab the lock and go to sleep. > > Since the execution of this thread is serialized with the `softnet' task, > it makes more sense to execute it in the same context. This reduce the > NET_LOCK() contention and implicitly preempt the packet processing. > > Diff below improves the situation with PF disabled, I didn't test with > PF enabled.
Updated diff that includes sashan@ suggestions and do not stop the purge task when PF is disabled. Otherwise some states are not purged until PF is re-enabled. This can be optimized later. ok? Index: net/pf.c =================================================================== RCS file: /cvs/src/sys/net/pf.c,v retrieving revision 1.1037 diff -u -p -r1.1037 pf.c --- net/pf.c 4 Jul 2017 14:10:15 -0000 1.1037 +++ net/pf.c 2 Aug 2017 08:08:47 -0000 @@ -121,6 +121,10 @@ u_char pf_tcp_secret[16]; int pf_tcp_secret_init; int pf_tcp_iss_off; +int pf_npurge; +struct task pf_purge_task = TASK_INITIALIZER(pf_purge, &pf_npurge); +struct timeout pf_purge_to = TIMEOUT_INITIALIZER(pf_purge_timeout, NULL); + enum pf_test_status { PF_TEST_FAIL = -1, PF_TEST_OK, @@ -1200,36 +1204,43 @@ pf_purge_expired_rules(void) } void -pf_purge_thread(void *v) +pf_purge_timeout(void *unused) { - int nloops = 0, s; + task_add(softnettq, &pf_purge_task); +} - for (;;) { - tsleep(pf_purge_thread, PWAIT, "pftm", 1 * hz); +void +pf_purge(void *xnloops) +{ + int *nloops = xnloops; + int s; - NET_LOCK(s); + KERNEL_LOCK(); + NET_LOCK(s); - PF_LOCK(); - /* process a fraction of the state table every second */ - pf_purge_expired_states(1 + (pf_status.states - / pf_default_rule.timeout[PFTM_INTERVAL])); + PF_LOCK(); + /* process a fraction of the state table every second */ + pf_purge_expired_states(1 + (pf_status.states + / pf_default_rule.timeout[PFTM_INTERVAL])); - /* purge other expired types every PFTM_INTERVAL seconds */ - if (++nloops >= pf_default_rule.timeout[PFTM_INTERVAL]) { - pf_purge_expired_src_nodes(0); - pf_purge_expired_rules(); - } - PF_UNLOCK(); - /* - * Fragments don't require PF_LOCK(), they use their own lock. - */ - if (nloops >= pf_default_rule.timeout[PFTM_INTERVAL]) { - pf_purge_expired_fragments(); - nloops = 0; - } + /* purge other expired types every PFTM_INTERVAL seconds */ + if (++(*nloops) >= pf_default_rule.timeout[PFTM_INTERVAL]) { + pf_purge_expired_src_nodes(0); + pf_purge_expired_rules(); + } + PF_UNLOCK(); - NET_UNLOCK(s); + /* + * Fragments don't require PF_LOCK(), they use their own lock. + */ + if ((*nloops) >= pf_default_rule.timeout[PFTM_INTERVAL]) { + pf_purge_expired_fragments(); + *nloops = 0; } + NET_UNLOCK(s); + KERNEL_UNLOCK(); + + timeout_add(&pf_purge_to, 1 * hz); } int32_t Index: net/pf_ioctl.c =================================================================== RCS file: /cvs/src/sys/net/pf_ioctl.c,v retrieving revision 1.320 diff -u -p -r1.320 pf_ioctl.c --- net/pf_ioctl.c 27 Jul 2017 12:09:51 -0000 1.320 +++ net/pf_ioctl.c 2 Aug 2017 08:01:53 -0000 @@ -231,16 +231,6 @@ pfattach(int num) /* XXX do our best to avoid a conflict */ pf_status.hostid = arc4random(); - - /* require process context to purge states, so perform in a thread */ - kthread_create_deferred(pf_thread_create, NULL); -} - -void -pf_thread_create(void *v) -{ - if (kthread_create(pf_purge_thread, NULL, NULL, "pfpurge")) - panic("pfpurge thread"); } int @@ -1027,6 +1017,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t a pf_status.stateid = time_second; pf_status.stateid = pf_status.stateid << 32; } + timeout_add(&pf_purge_to, 1 * hz); pf_create_queues(); DPFPRINTF(LOG_NOTICE, "pf: started"); } @@ -2320,7 +2311,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t a pf_default_rule_new.timeout[i]; if (pf_default_rule.timeout[i] == PFTM_INTERVAL && pf_default_rule.timeout[i] < old) - wakeup(pf_purge_thread); + task_add(softnettq, &pf_purge_task); } pfi_xcommit(); pf_trans_set_commit(); Index: net/pfvar.h =================================================================== RCS file: /cvs/src/sys/net/pfvar.h,v retrieving revision 1.461 diff -u -p -r1.461 pfvar.h --- net/pfvar.h 19 Jul 2017 12:51:31 -0000 1.461 +++ net/pfvar.h 2 Aug 2017 08:01:53 -0000 @@ -1648,7 +1648,6 @@ extern int pf_tbladdr_setup(struct pf extern void pf_tbladdr_remove(struct pf_addr_wrap *); extern void pf_tbladdr_copyout(struct pf_addr_wrap *); extern void pf_calc_skip_steps(struct pf_rulequeue *); -extern void pf_purge_thread(void *); extern void pf_purge_expired_src_nodes(); extern void pf_purge_expired_states(u_int32_t); extern void pf_purge_expired_rules(); Index: net/pfvar_priv.h =================================================================== RCS file: /cvs/src/sys/net/pfvar_priv.h,v retrieving revision 1.3 diff -u -p -r1.3 pfvar_priv.h --- net/pfvar_priv.h 5 Jun 2017 22:18:28 -0000 1.3 +++ net/pfvar_priv.h 2 Aug 2017 08:01:53 -0000 @@ -98,6 +98,9 @@ struct pf_pdesc { } hdr; }; +extern struct task pf_purge_task; +extern struct timeout pf_purge_to; + #ifdef WITH_PF_LOCK extern struct rwlock pf_lock; @@ -128,6 +131,8 @@ extern struct rwlock pf_lock; #define PF_ASSERT_UNLOCKED() (void)(0) #endif /* WITH_PF_LOCK */ +extern void pf_purge_timeout(void *); +extern void pf_purge(void *); #endif /* _KERNEL */ #endif /* _NET_PFVAR_PRIV_H_ */