Message ID | 20220516191032.340243-4-vladbu@nvidia.com |
---|---|
State | Changes Requested |
Delegated to: | Pablo Neira |
Headers | show |
Series | Conntrack offload debuggability improvements | expand |
On Tue 17 May 2022 at 13:20, Pablo Neira Ayuso <pablo@netfilter.org> wrote: > On Mon, May 16, 2022 at 10:10:32PM +0300, Vlad Buslov wrote: > [...] >> diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig >> index ddc54b6d18ee..c8fc5c7ef04a 100644 >> --- a/net/netfilter/Kconfig >> +++ b/net/netfilter/Kconfig >> @@ -734,6 +734,14 @@ config NF_FLOW_TABLE >> >> To compile it as a module, choose M here. >> >> +config NF_FLOW_TABLE_PROCFS >> + bool "Supply flow table statistics in procfs" >> + default y >> + depends on PROC_FS >> + help >> + This option enables for the flow table offload statistics >> + to be shown in procfs under net/netfilter/nf_flowtable. > > This belongs to patch 2/3. > > Then, use NF_FLOW_TABLE_PROCFS to conditionally add it to > nf_flow_table if this is enabled in .config? To honor this new Kconfig > toggle. > > I mean instead of: > > obj-$(CONFIG_NF_FLOW_TABLE) += nf_flow_table.o > nf_flow_table-objs := nf_flow_table_core.o nf_flow_table_ip.o \ > - nf_flow_table_offload.o > + nf_flow_table_offload.o \ > + nf_flow_table_sysctl.o > > this? > > nf_flow_table-$(CONFIG_NF_FLOW_TABLE_SYSCTL) += nf_flow_table_sysctl.o In V2 I have both sysctl and procfs implementations in single file. As I replied for previous patch in series: Should I split those in two separate files (nf_flow_table_sysctl.c and nf_flow_table_procfs.c) that both could be conditionally compiled depending on their respective configs? > >> config NETFILTER_XTABLES >> tristate "Netfilter Xtables support (required for ip_tables)" >> default m if NETFILTER_ADVANCED=n >> diff --git a/net/netfilter/nf_flow_table_core.c b/net/netfilter/nf_flow_table_core.c >> index e2598f98017c..c86dd627ef42 100644 >> --- a/net/netfilter/nf_flow_table_core.c >> +++ b/net/netfilter/nf_flow_table_core.c >> @@ -662,17 +662,51 @@ void nf_flow_table_free(struct nf_flowtable *flow_table) >> } >> EXPORT_SYMBOL_GPL(nf_flow_table_free); >> >> +static int nf_flow_table_init_net(struct net *net) >> +{ >> + net->ft.stat = alloc_percpu(struct nf_flow_table_stat); > > Missing check for NULL in case alloc_percpu() fails? > I might be missing something, but why isn't NULL check in following line sufficient? >> + return net->ft.stat ? 0 : -ENOMEM; >> +}
On Mon, May 16, 2022 at 10:10:32PM +0300, Vlad Buslov wrote: [...] > diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig > index ddc54b6d18ee..c8fc5c7ef04a 100644 > --- a/net/netfilter/Kconfig > +++ b/net/netfilter/Kconfig > @@ -734,6 +734,14 @@ config NF_FLOW_TABLE > > To compile it as a module, choose M here. > > +config NF_FLOW_TABLE_PROCFS > + bool "Supply flow table statistics in procfs" > + default y > + depends on PROC_FS > + help > + This option enables for the flow table offload statistics > + to be shown in procfs under net/netfilter/nf_flowtable. This belongs to patch 2/3. Then, use NF_FLOW_TABLE_PROCFS to conditionally add it to nf_flow_table if this is enabled in .config? To honor this new Kconfig toggle. I mean instead of: obj-$(CONFIG_NF_FLOW_TABLE) += nf_flow_table.o nf_flow_table-objs := nf_flow_table_core.o nf_flow_table_ip.o \ - nf_flow_table_offload.o + nf_flow_table_offload.o \ + nf_flow_table_sysctl.o this? nf_flow_table-$(CONFIG_NF_FLOW_TABLE_SYSCTL) += nf_flow_table_sysctl.o > config NETFILTER_XTABLES > tristate "Netfilter Xtables support (required for ip_tables)" > default m if NETFILTER_ADVANCED=n > diff --git a/net/netfilter/nf_flow_table_core.c b/net/netfilter/nf_flow_table_core.c > index e2598f98017c..c86dd627ef42 100644 > --- a/net/netfilter/nf_flow_table_core.c > +++ b/net/netfilter/nf_flow_table_core.c > @@ -662,17 +662,51 @@ void nf_flow_table_free(struct nf_flowtable *flow_table) > } > EXPORT_SYMBOL_GPL(nf_flow_table_free); > > +static int nf_flow_table_init_net(struct net *net) > +{ > + net->ft.stat = alloc_percpu(struct nf_flow_table_stat); Missing check for NULL in case alloc_percpu() fails? > + return net->ft.stat ? 0 : -ENOMEM; > +}
On Tue, May 17, 2022 at 02:16:04PM +0300, Vlad Buslov wrote: > > On Tue 17 May 2022 at 13:20, Pablo Neira Ayuso <pablo@netfilter.org> wrote: > > On Mon, May 16, 2022 at 10:10:32PM +0300, Vlad Buslov wrote: > > [...] > >> diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig > >> index ddc54b6d18ee..c8fc5c7ef04a 100644 > >> --- a/net/netfilter/Kconfig > >> +++ b/net/netfilter/Kconfig > >> @@ -734,6 +734,14 @@ config NF_FLOW_TABLE > >> > >> To compile it as a module, choose M here. > >> > >> +config NF_FLOW_TABLE_PROCFS > >> + bool "Supply flow table statistics in procfs" > >> + default y > >> + depends on PROC_FS > >> + help > >> + This option enables for the flow table offload statistics > >> + to be shown in procfs under net/netfilter/nf_flowtable. > > > > This belongs to patch 2/3. > > > > Then, use NF_FLOW_TABLE_PROCFS to conditionally add it to > > nf_flow_table if this is enabled in .config? To honor this new Kconfig > > toggle. > > > > I mean instead of: > > > > obj-$(CONFIG_NF_FLOW_TABLE) += nf_flow_table.o > > nf_flow_table-objs := nf_flow_table_core.o nf_flow_table_ip.o \ > > - nf_flow_table_offload.o > > + nf_flow_table_offload.o \ > > + nf_flow_table_sysctl.o > > > > this? > > > > nf_flow_table-$(CONFIG_NF_FLOW_TABLE_SYSCTL) += nf_flow_table_sysctl.o > > In V2 I have both sysctl and procfs implementations in single file. > As I replied for previous patch in series: Should I split those in two > separate files (nf_flow_table_sysctl.c and nf_flow_table_procfs.c) that > both could be conditionally compiled depending on their respective > configs? Same file is fine. Probably instead ? nf_flow_table-$(CONFIG_SYSCTL) += nf_flow_table_sysctl.o so the #ifdef CONFIG_SYSCTL in nf_flow_table_sysctl.c can go away. you would need to move: unsigned int nf_ft_hw_max __read_mostly; to nf_flow_table_offload.c Make sense? > >> config NETFILTER_XTABLES > >> tristate "Netfilter Xtables support (required for ip_tables)" > >> default m if NETFILTER_ADVANCED=n > >> diff --git a/net/netfilter/nf_flow_table_core.c b/net/netfilter/nf_flow_table_core.c > >> index e2598f98017c..c86dd627ef42 100644 > >> --- a/net/netfilter/nf_flow_table_core.c > >> +++ b/net/netfilter/nf_flow_table_core.c > >> @@ -662,17 +662,51 @@ void nf_flow_table_free(struct nf_flowtable *flow_table) > >> } > >> EXPORT_SYMBOL_GPL(nf_flow_table_free); > >> > >> +static int nf_flow_table_init_net(struct net *net) > >> +{ > >> + net->ft.stat = alloc_percpu(struct nf_flow_table_stat); > > > > Missing check for NULL in case alloc_percpu() fails? > > > > I might be missing something, but why isn't NULL check in following line > sufficient? I overlook the return is check for NULL, sorry for the noise. > >> + return net->ft.stat ? 0 : -ENOMEM; > >> +} >
On Tue 17 May 2022 at 14:26, Pablo Neira Ayuso <pablo@netfilter.org> wrote: > On Tue, May 17, 2022 at 02:16:04PM +0300, Vlad Buslov wrote: >> >> On Tue 17 May 2022 at 13:20, Pablo Neira Ayuso <pablo@netfilter.org> wrote: >> > On Mon, May 16, 2022 at 10:10:32PM +0300, Vlad Buslov wrote: >> > [...] >> >> diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig >> >> index ddc54b6d18ee..c8fc5c7ef04a 100644 >> >> --- a/net/netfilter/Kconfig >> >> +++ b/net/netfilter/Kconfig >> >> @@ -734,6 +734,14 @@ config NF_FLOW_TABLE >> >> >> >> To compile it as a module, choose M here. >> >> >> >> +config NF_FLOW_TABLE_PROCFS >> >> + bool "Supply flow table statistics in procfs" >> >> + default y >> >> + depends on PROC_FS >> >> + help >> >> + This option enables for the flow table offload statistics >> >> + to be shown in procfs under net/netfilter/nf_flowtable. >> > >> > This belongs to patch 2/3. >> > >> > Then, use NF_FLOW_TABLE_PROCFS to conditionally add it to >> > nf_flow_table if this is enabled in .config? To honor this new Kconfig >> > toggle. >> > >> > I mean instead of: >> > >> > obj-$(CONFIG_NF_FLOW_TABLE) += nf_flow_table.o >> > nf_flow_table-objs := nf_flow_table_core.o nf_flow_table_ip.o \ >> > - nf_flow_table_offload.o >> > + nf_flow_table_offload.o \ >> > + nf_flow_table_sysctl.o >> > >> > this? >> > >> > nf_flow_table-$(CONFIG_NF_FLOW_TABLE_SYSCTL) += nf_flow_table_sysctl.o >> >> In V2 I have both sysctl and procfs implementations in single file. >> As I replied for previous patch in series: Should I split those in two >> separate files (nf_flow_table_sysctl.c and nf_flow_table_procfs.c) that >> both could be conditionally compiled depending on their respective >> configs? > > Same file is fine. > > Probably instead ? > > nf_flow_table-$(CONFIG_SYSCTL) += nf_flow_table_sysctl.o > > so the #ifdef CONFIG_SYSCTL in nf_flow_table_sysctl.c can go away. > > you would need to move: > > unsigned int nf_ft_hw_max __read_mostly; > > to nf_flow_table_offload.c > > Make sense? Yep. Will send the V3 soon. Thanks, Vlad [...]
diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h index c4f5601f6e32..bf770c13e19b 100644 --- a/include/net/net_namespace.h +++ b/include/net/net_namespace.h @@ -26,6 +26,9 @@ #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) #include <net/netns/conntrack.h> #endif +#if IS_ENABLED(CONFIG_NF_FLOW_TABLE) +#include <net/netns/flow_table.h> +#endif #include <net/netns/nftables.h> #include <net/netns/xfrm.h> #include <net/netns/mpls.h> @@ -140,6 +143,9 @@ struct net { #if defined(CONFIG_NF_TABLES) || defined(CONFIG_NF_TABLES_MODULE) struct netns_nftables nft; #endif +#if IS_ENABLED(CONFIG_NF_FLOW_TABLE) + struct netns_ft ft; +#endif #endif #ifdef CONFIG_WEXT_CORE struct sk_buff_head wext_nlevents; diff --git a/include/net/netfilter/nf_flow_table.h b/include/net/netfilter/nf_flow_table.h index e09c29fa034e..94606c04b6fe 100644 --- a/include/net/netfilter/nf_flow_table.h +++ b/include/net/netfilter/nf_flow_table.h @@ -360,4 +360,14 @@ static inline struct nf_ft_net *nf_ft_pernet_get(struct nf_flowtable *flow_table int nf_flow_table_init_sysctl(struct net *net); void nf_flow_table_fini_sysctl(struct net *net); +#define NF_FLOW_TABLE_STAT_INC(net, count) __this_cpu_inc((net)->ft.stat->count) +#define NF_FLOW_TABLE_STAT_DEC(net, count) __this_cpu_dec((net)->ft.stat->count) +#define NF_FLOW_TABLE_STAT_INC_ATOMIC(net, count) \ + this_cpu_inc((net)->ft.stat->count) +#define NF_FLOW_TABLE_STAT_DEC_ATOMIC(net, count) \ + this_cpu_dec((net)->ft.stat->count) + +int nf_flow_table_init_proc(struct net *net); +void nf_flow_table_fini_proc(struct net *net); + #endif /* _NF_FLOW_TABLE_H */ diff --git a/include/net/netns/flow_table.h b/include/net/netns/flow_table.h new file mode 100644 index 000000000000..1c5fc657e267 --- /dev/null +++ b/include/net/netns/flow_table.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __NETNS_FLOW_TABLE_H +#define __NETNS_FLOW_TABLE_H + +struct nf_flow_table_stat { + unsigned int count_wq_add; + unsigned int count_wq_del; + unsigned int count_wq_stats; +}; + +struct netns_ft { + struct nf_flow_table_stat __percpu *stat; +}; +#endif diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index ddc54b6d18ee..c8fc5c7ef04a 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig @@ -734,6 +734,14 @@ config NF_FLOW_TABLE To compile it as a module, choose M here. +config NF_FLOW_TABLE_PROCFS + bool "Supply flow table statistics in procfs" + default y + depends on PROC_FS + help + This option enables for the flow table offload statistics + to be shown in procfs under net/netfilter/nf_flowtable. + config NETFILTER_XTABLES tristate "Netfilter Xtables support (required for ip_tables)" default m if NETFILTER_ADVANCED=n diff --git a/net/netfilter/nf_flow_table_core.c b/net/netfilter/nf_flow_table_core.c index e2598f98017c..c86dd627ef42 100644 --- a/net/netfilter/nf_flow_table_core.c +++ b/net/netfilter/nf_flow_table_core.c @@ -662,17 +662,51 @@ void nf_flow_table_free(struct nf_flowtable *flow_table) } EXPORT_SYMBOL_GPL(nf_flow_table_free); +static int nf_flow_table_init_net(struct net *net) +{ + net->ft.stat = alloc_percpu(struct nf_flow_table_stat); + return net->ft.stat ? 0 : -ENOMEM; +} + +static void nf_flow_table_fini_net(struct net *net) +{ + free_percpu(net->ft.stat); +} + static int nf_flow_table_pernet_init(struct net *net) { - return nf_flow_table_init_sysctl(net); + int ret; + + ret = nf_flow_table_init_net(net); + if (ret < 0) + return ret; + + ret = nf_flow_table_init_sysctl(net); + if (ret < 0) + goto out_sysctl; + + ret = nf_flow_table_init_proc(net); + if (ret < 0) + goto out_proc; + + return 0; + +out_proc: + nf_flow_table_fini_sysctl(net); +out_sysctl: + nf_flow_table_fini_net(net); + return ret; } static void nf_flow_table_pernet_exit(struct list_head *net_exit_list) { struct net *net; - list_for_each_entry(net, net_exit_list, exit_list) + list_for_each_entry(net, net_exit_list, exit_list) { + nf_flow_table_fini_proc(net); nf_flow_table_fini_sysctl(net); + nf_flow_table_fini_net(net); + } } unsigned int nf_ft_net_id __read_mostly; diff --git a/net/netfilter/nf_flow_table_offload.c b/net/netfilter/nf_flow_table_offload.c index a6e763901eb9..381bd598a16f 100644 --- a/net/netfilter/nf_flow_table_offload.c +++ b/net/netfilter/nf_flow_table_offload.c @@ -993,17 +993,22 @@ static void flow_offload_work_stats(struct flow_offload_work *offload) static void flow_offload_work_handler(struct work_struct *work) { struct flow_offload_work *offload; + struct net *net; offload = container_of(work, struct flow_offload_work, work); + net = read_pnet(&offload->flowtable->net); switch (offload->cmd) { case FLOW_CLS_REPLACE: flow_offload_work_add(offload); + NF_FLOW_TABLE_STAT_DEC_ATOMIC(net, count_wq_add); break; case FLOW_CLS_DESTROY: flow_offload_work_del(offload); + NF_FLOW_TABLE_STAT_DEC_ATOMIC(net, count_wq_del); break; case FLOW_CLS_STATS: flow_offload_work_stats(offload); + NF_FLOW_TABLE_STAT_DEC_ATOMIC(net, count_wq_stats); break; default: WARN_ON_ONCE(1); @@ -1015,12 +1020,18 @@ static void flow_offload_work_handler(struct work_struct *work) static void flow_offload_queue_work(struct flow_offload_work *offload) { - if (offload->cmd == FLOW_CLS_REPLACE) + struct net *net = read_pnet(&offload->flowtable->net); + + if (offload->cmd == FLOW_CLS_REPLACE) { + NF_FLOW_TABLE_STAT_INC(net, count_wq_add); queue_work(nf_flow_offload_add_wq, &offload->work); - else if (offload->cmd == FLOW_CLS_DESTROY) + } else if (offload->cmd == FLOW_CLS_DESTROY) { + NF_FLOW_TABLE_STAT_INC(net, count_wq_del); queue_work(nf_flow_offload_del_wq, &offload->work); - else + } else { + NF_FLOW_TABLE_STAT_INC(net, count_wq_stats); queue_work(nf_flow_offload_stats_wq, &offload->work); + } } static struct flow_offload_work * diff --git a/net/netfilter/nf_flow_table_sysctl.c b/net/netfilter/nf_flow_table_sysctl.c index ce8c0a2c4bdb..2aefd7542527 100644 --- a/net/netfilter/nf_flow_table_sysctl.c +++ b/net/netfilter/nf_flow_table_sysctl.c @@ -1,7 +1,95 @@ // SPDX-License-Identifier: GPL-2.0-only #include <linux/kernel.h> +#include <linux/proc_fs.h> #include <net/netfilter/nf_flow_table.h> +#ifdef CONFIG_NF_FLOW_TABLE_PROCFS +static void *nf_flow_table_cpu_seq_start(struct seq_file *seq, loff_t *pos) +{ + struct net *net = seq_file_net(seq); + int cpu; + + if (*pos == 0) + return SEQ_START_TOKEN; + + for (cpu = *pos - 1; cpu < nr_cpu_ids; ++cpu) { + if (!cpu_possible(cpu)) + continue; + *pos = cpu + 1; + return per_cpu_ptr(net->ft.stat, cpu); + } + + return NULL; +} + +static void *nf_flow_table_cpu_seq_next(struct seq_file *seq, void *v, loff_t *pos) +{ + struct net *net = seq_file_net(seq); + int cpu; + + for (cpu = *pos; cpu < nr_cpu_ids; ++cpu) { + if (!cpu_possible(cpu)) + continue; + *pos = cpu + 1; + return per_cpu_ptr(net->ft.stat, cpu); + } + (*pos)++; + return NULL; +} + +static void nf_flow_table_cpu_seq_stop(struct seq_file *seq, void *v) +{ +} + +static int nf_flow_table_cpu_seq_show(struct seq_file *seq, void *v) +{ + const struct nf_flow_table_stat *st = v; + + if (v == SEQ_START_TOKEN) { + seq_puts(seq, "wq_add wq_del wq_stats\n"); + return 0; + } + + seq_printf(seq, "%8d %8d %8d\n", + st->count_wq_add, + st->count_wq_del, + st->count_wq_stats + ); + return 0; +} + +static const struct seq_operations nf_flow_table_cpu_seq_ops = { + .start = nf_flow_table_cpu_seq_start, + .next = nf_flow_table_cpu_seq_next, + .stop = nf_flow_table_cpu_seq_stop, + .show = nf_flow_table_cpu_seq_show, +}; + +int nf_flow_table_init_proc(struct net *net) +{ + struct proc_dir_entry *pde; + + pde = proc_create_net("nf_flowtable", 0444, net->proc_net_stat, + &nf_flow_table_cpu_seq_ops, + sizeof(struct seq_net_private)); + return pde ? 0 : -ENOMEM; +} + +void nf_flow_table_fini_proc(struct net *net) +{ + remove_proc_entry("nf_flowtable", net->proc_net_stat); +} +#else +int nf_flow_table_init_proc(struct net *net) +{ + return 0; +} + +void nf_flow_table_fini_proc(struct net *net) +{ +} +#endif /* CONFIG_NF_FLOW_TABLE_PROCFS */ + unsigned int nf_ft_hw_max __read_mostly; #ifdef CONFIG_SYSCTL