netfilter: nftables: counter hardware offload support
[linux-block.git] / net / netfilter / nf_tables_offload.c
index 1d428792018fe87e59b05f0316d59e6dd1c6b57b..19215e81dd66ebc700bcbd1387ac4c2a8b5cc95f 100644 (file)
@@ -243,26 +243,56 @@ static void nft_flow_cls_offload_setup(struct flow_cls_offload *cls_flow,
                cls_flow->rule = flow->rule;
 }
 
-static int nft_flow_offload_rule(struct nft_chain *chain,
-                                struct nft_rule *rule,
-                                struct nft_flow_rule *flow,
-                                enum flow_cls_command command)
+static int nft_flow_offload_cmd(const struct nft_chain *chain,
+                               const struct nft_rule *rule,
+                               struct nft_flow_rule *flow,
+                               enum flow_cls_command command,
+                               struct flow_cls_offload *cls_flow)
 {
        struct netlink_ext_ack extack = {};
-       struct flow_cls_offload cls_flow;
        struct nft_base_chain *basechain;
 
        if (!nft_is_base_chain(chain))
                return -EOPNOTSUPP;
 
        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);
 
-       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);
 }
 
+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,
                                 struct nft_base_chain *basechain)
 {