Commit b72920f6 authored by Pablo Neira Ayuso's avatar Pablo Neira Ayuso

netfilter: nftables: counter hardware offload support

This patch adds the .offload_stats operation to synchronize hardware
stats with the expression data. Update the counter expression to use
this new interface. The hardware stats are retrieved from the netlink
dump path via FLOW_CLS_STATS command to the driver.
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parent 88262182
...@@ -867,6 +867,8 @@ struct nft_expr_ops { ...@@ -867,6 +867,8 @@ struct nft_expr_ops {
int (*offload)(struct nft_offload_ctx *ctx, int (*offload)(struct nft_offload_ctx *ctx,
struct nft_flow_rule *flow, struct nft_flow_rule *flow,
const struct nft_expr *expr); const struct nft_expr *expr);
void (*offload_stats)(struct nft_expr *expr,
const struct flow_stats *stats);
u32 offload_flags; u32 offload_flags;
const struct nft_expr_type *type; const struct nft_expr_type *type;
void *data; void *data;
......
...@@ -74,6 +74,7 @@ void nft_flow_rule_set_addr_type(struct nft_flow_rule *flow, ...@@ -74,6 +74,7 @@ void nft_flow_rule_set_addr_type(struct nft_flow_rule *flow,
struct nft_rule; struct nft_rule;
struct nft_flow_rule *nft_flow_rule_create(struct net *net, const struct nft_rule *rule); struct nft_flow_rule *nft_flow_rule_create(struct net *net, const struct nft_rule *rule);
int nft_flow_rule_stats(const struct nft_chain *chain, const struct nft_rule *rule);
void nft_flow_rule_destroy(struct nft_flow_rule *flow); void nft_flow_rule_destroy(struct nft_flow_rule *flow);
int nft_flow_rule_offload_commit(struct net *net); int nft_flow_rule_offload_commit(struct net *net);
......
...@@ -2878,6 +2878,9 @@ static int nf_tables_fill_rule_info(struct sk_buff *skb, struct net *net, ...@@ -2878,6 +2878,9 @@ static int nf_tables_fill_rule_info(struct sk_buff *skb, struct net *net,
goto nla_put_failure; goto nla_put_failure;
} }
if (chain->flags & NFT_CHAIN_HW_OFFLOAD)
nft_flow_rule_stats(chain, rule);
list = nla_nest_start_noflag(skb, NFTA_RULE_EXPRESSIONS); list = nla_nest_start_noflag(skb, NFTA_RULE_EXPRESSIONS);
if (list == NULL) if (list == NULL)
goto nla_put_failure; goto nla_put_failure;
......
...@@ -243,26 +243,56 @@ static void nft_flow_cls_offload_setup(struct flow_cls_offload *cls_flow, ...@@ -243,26 +243,56 @@ static void nft_flow_cls_offload_setup(struct flow_cls_offload *cls_flow,
cls_flow->rule = flow->rule; cls_flow->rule = flow->rule;
} }
static int nft_flow_offload_rule(struct nft_chain *chain, static int nft_flow_offload_cmd(const struct nft_chain *chain,
struct nft_rule *rule, const struct nft_rule *rule,
struct nft_flow_rule *flow, struct nft_flow_rule *flow,
enum flow_cls_command command) enum flow_cls_command command,
struct flow_cls_offload *cls_flow)
{ {
struct netlink_ext_ack extack = {}; struct netlink_ext_ack extack = {};
struct flow_cls_offload cls_flow;
struct nft_base_chain *basechain; struct nft_base_chain *basechain;
if (!nft_is_base_chain(chain)) if (!nft_is_base_chain(chain))
return -EOPNOTSUPP; return -EOPNOTSUPP;
basechain = nft_base_chain(chain); basechain = nft_base_chain(chain);
nft_flow_cls_offload_setup(&cls_flow, basechain, rule, flow, &extack, nft_flow_cls_offload_setup(cls_flow, basechain, rule, flow, &extack,
command); command);
return nft_setup_cb_call(TC_SETUP_CLSFLOWER, &cls_flow, return nft_setup_cb_call(TC_SETUP_CLSFLOWER, cls_flow,
&basechain->flow_block.cb_list); &basechain->flow_block.cb_list);
} }
static int nft_flow_offload_rule(const struct nft_chain *chain,
struct nft_rule *rule,
struct nft_flow_rule *flow,
enum flow_cls_command command)
{
struct flow_cls_offload cls_flow;
return nft_flow_offload_cmd(chain, rule, flow, command, &cls_flow);
}
int nft_flow_rule_stats(const struct nft_chain *chain,
const struct nft_rule *rule)
{
struct flow_cls_offload cls_flow = {};
struct nft_expr *expr, *next;
int err;
err = nft_flow_offload_cmd(chain, rule, NULL, FLOW_CLS_STATS,
&cls_flow);
if (err < 0)
return err;
nft_rule_for_each_expr(expr, next, rule) {
if (expr->ops->offload_stats)
expr->ops->offload_stats(expr, &cls_flow.stats);
}
return 0;
}
static int nft_flow_offload_bind(struct flow_block_offload *bo, static int nft_flow_offload_bind(struct flow_block_offload *bo,
struct nft_base_chain *basechain) struct nft_base_chain *basechain)
{ {
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include <linux/netfilter.h> #include <linux/netfilter.h>
#include <linux/netfilter/nf_tables.h> #include <linux/netfilter/nf_tables.h>
#include <net/netfilter/nf_tables.h> #include <net/netfilter/nf_tables.h>
#include <net/netfilter/nf_tables_offload.h>
struct nft_counter { struct nft_counter {
s64 bytes; s64 bytes;
...@@ -248,6 +249,32 @@ static int nft_counter_clone(struct nft_expr *dst, const struct nft_expr *src) ...@@ -248,6 +249,32 @@ static int nft_counter_clone(struct nft_expr *dst, const struct nft_expr *src)
return 0; return 0;
} }
static int nft_counter_offload(struct nft_offload_ctx *ctx,
struct nft_flow_rule *flow,
const struct nft_expr *expr)
{
/* No specific offload action is needed, but report success. */
return 0;
}
static void nft_counter_offload_stats(struct nft_expr *expr,
const struct flow_stats *stats)
{
struct nft_counter_percpu_priv *priv = nft_expr_priv(expr);
struct nft_counter *this_cpu;
seqcount_t *myseq;
preempt_disable();
this_cpu = this_cpu_ptr(priv->counter);
myseq = this_cpu_ptr(&nft_counter_seq);
write_seqcount_begin(myseq);
this_cpu->packets += stats->pkts;
this_cpu->bytes += stats->bytes;
write_seqcount_end(myseq);
preempt_enable();
}
static struct nft_expr_type nft_counter_type; static struct nft_expr_type nft_counter_type;
static const struct nft_expr_ops nft_counter_ops = { static const struct nft_expr_ops nft_counter_ops = {
.type = &nft_counter_type, .type = &nft_counter_type,
...@@ -258,6 +285,8 @@ static const struct nft_expr_ops nft_counter_ops = { ...@@ -258,6 +285,8 @@ static const struct nft_expr_ops nft_counter_ops = {
.destroy_clone = nft_counter_destroy, .destroy_clone = nft_counter_destroy,
.dump = nft_counter_dump, .dump = nft_counter_dump,
.clone = nft_counter_clone, .clone = nft_counter_clone,
.offload = nft_counter_offload,
.offload_stats = nft_counter_offload_stats,
}; };
static struct nft_expr_type nft_counter_type __read_mostly = { static struct nft_expr_type nft_counter_type __read_mostly = {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment