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.
Hrvoje Popovski confirmed this reduces "ifconfig" pauses. He also confirmed states are correctly purged. So, I'd appreciate reviews and oks. > 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 18 Jul 2017 13:28:10 -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,44 @@ pf_purge_expired_rules(void) > } > > void > -pf_purge_thread(void *v) > +pf_purge_timeout(void *unused) > { > - int nloops = 0, s; > - > - for (;;) { > - tsleep(pf_purge_thread, PWAIT, "pftm", 1 * hz); > - > - NET_LOCK(s); > + task_add(softnettq, &pf_purge_task); > +} > > - 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])); > +void > +pf_purge(void *xnloops) > +{ > + int *nloops = xnloops; > + int s; > > - /* 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; > - } > + KERNEL_LOCK(); > + NET_LOCK(s); > > - NET_UNLOCK(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])); > + > + /* 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; > } > + NET_UNLOCK(s); > + KERNEL_UNLOCK(); > + > + if (pf_status.running) > + 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.318 > diff -u -p -r1.318 pf_ioctl.c > --- net/pf_ioctl.c 5 Jul 2017 11:40:17 -0000 1.318 > +++ net/pf_ioctl.c 18 Jul 2017 13:29:39 -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"); > } > @@ -2291,7 +2282,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.460 > diff -u -p -r1.460 pfvar.h > --- net/pfvar.h 28 Jun 2017 19:30:24 -0000 1.460 > +++ net/pfvar.h 18 Jul 2017 13:30:23 -0000 > @@ -1647,7 +1647,8 @@ 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_timeout(void *); > +extern void pf_purge(void *); > extern void pf_purge_expired_src_nodes(); > extern void pf_purge_expired_states(u_int32_t); > extern void pf_purge_expired_rules(); > @@ -1826,6 +1827,8 @@ const struct pfq_ops > *pf_queue_manager(struct pf_queuespec *); > > extern struct pf_status pf_status; > +extern struct task pf_purge_task; > +extern struct timeout pf_purge_to; > extern struct pool pf_frent_pl, pf_frag_pl; > > struct pf_pool_limit { >