Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

netfilter: nft_{fwd,dup}_netdev: add offload support

This patch adds support for packet mirroring and redirection. The
nft_fwd_dup_netdev_offload() function configures the flow_action object
for the fwd and the dup actions.

Extend nft_flow_rule_destroy() to release the net_device object when the
flow_rule object is released, since nft_fwd_dup_netdev_offload() bumps
the net_device reference counter.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Acked-by: wenxu <wenxu@ucloud.cn>

+70 -3
+6
include/net/netfilter/nf_dup_netdev.h
··· 7 7 void nf_dup_netdev_egress(const struct nft_pktinfo *pkt, int oif); 8 8 void nf_fwd_netdev_egress(const struct nft_pktinfo *pkt, int oif); 9 9 10 + struct nft_offload_ctx; 11 + struct nft_flow_rule; 12 + 13 + int nft_fwd_dup_netdev_offload(struct nft_offload_ctx *ctx, 14 + struct nft_flow_rule *flow, 15 + enum flow_action_id id, int oif); 10 16 #endif
+2 -1
include/net/netfilter/nf_tables_offload.h
··· 26 26 u8 protonum; 27 27 } dep; 28 28 unsigned int num_actions; 29 + struct net *net; 29 30 struct nft_offload_reg regs[NFT_REG32_15 + 1]; 30 31 }; 31 32 ··· 62 61 #define NFT_OFFLOAD_F_ACTION (1 << 0) 63 62 64 63 struct nft_rule; 65 - struct nft_flow_rule *nft_flow_rule_create(const struct nft_rule *rule); 64 + struct nft_flow_rule *nft_flow_rule_create(struct net *net, const struct nft_rule *rule); 66 65 void nft_flow_rule_destroy(struct nft_flow_rule *flow); 67 66 int nft_flow_rule_offload_commit(struct net *net); 68 67
+21
net/netfilter/nf_dup_netdev.c
··· 10 10 #include <linux/netfilter.h> 11 11 #include <linux/netfilter/nf_tables.h> 12 12 #include <net/netfilter/nf_tables.h> 13 + #include <net/netfilter/nf_tables_offload.h> 13 14 #include <net/netfilter/nf_dup_netdev.h> 14 15 15 16 static void nf_do_netdev_egress(struct sk_buff *skb, struct net_device *dev) ··· 50 49 nf_do_netdev_egress(skb, dev); 51 50 } 52 51 EXPORT_SYMBOL_GPL(nf_dup_netdev_egress); 52 + 53 + int nft_fwd_dup_netdev_offload(struct nft_offload_ctx *ctx, 54 + struct nft_flow_rule *flow, 55 + enum flow_action_id id, int oif) 56 + { 57 + struct flow_action_entry *entry; 58 + struct net_device *dev; 59 + 60 + /* nft_flow_rule_destroy() releases the reference on this device. */ 61 + dev = dev_get_by_index(ctx->net, oif); 62 + if (!dev) 63 + return -EOPNOTSUPP; 64 + 65 + entry = &flow->rule->action.entries[ctx->num_actions++]; 66 + entry->id = id; 67 + entry->dev = dev; 68 + 69 + return 0; 70 + } 71 + EXPORT_SYMBOL_GPL(nft_fwd_dup_netdev_offload); 53 72 54 73 MODULE_LICENSE("GPL"); 55 74 MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>");
+1 -1
net/netfilter/nf_tables_api.c
··· 2853 2853 return nft_table_validate(net, table); 2854 2854 2855 2855 if (chain->flags & NFT_CHAIN_HW_OFFLOAD) { 2856 - flow = nft_flow_rule_create(rule); 2856 + flow = nft_flow_rule_create(net, rule); 2857 2857 if (IS_ERR(flow)) 2858 2858 return PTR_ERR(flow); 2859 2859
+16 -1
net/netfilter/nf_tables_offload.c
··· 28 28 return flow; 29 29 } 30 30 31 - struct nft_flow_rule *nft_flow_rule_create(const struct nft_rule *rule) 31 + struct nft_flow_rule *nft_flow_rule_create(struct net *net, 32 + const struct nft_rule *rule) 32 33 { 33 34 struct nft_offload_ctx *ctx; 34 35 struct nft_flow_rule *flow; ··· 55 54 err = -ENOMEM; 56 55 goto err_out; 57 56 } 57 + ctx->net = net; 58 58 ctx->dep.type = NFT_OFFLOAD_DEP_UNSPEC; 59 59 60 60 while (expr->ops && expr != nft_expr_last(rule)) { ··· 82 80 83 81 void nft_flow_rule_destroy(struct nft_flow_rule *flow) 84 82 { 83 + struct flow_action_entry *entry; 84 + int i; 85 + 86 + flow_action_for_each(i, entry, &flow->rule->action) { 87 + switch (entry->id) { 88 + case FLOW_ACTION_REDIRECT: 89 + case FLOW_ACTION_MIRRED: 90 + dev_put(entry->dev); 91 + break; 92 + default: 93 + break; 94 + } 95 + } 85 96 kfree(flow->rule); 86 97 kfree(flow); 87 98 }
+12
net/netfilter/nft_dup_netdev.c
··· 10 10 #include <linux/netfilter.h> 11 11 #include <linux/netfilter/nf_tables.h> 12 12 #include <net/netfilter/nf_tables.h> 13 + #include <net/netfilter/nf_tables_offload.h> 13 14 #include <net/netfilter/nf_dup_netdev.h> 14 15 15 16 struct nft_dup_netdev { ··· 57 56 return -1; 58 57 } 59 58 59 + static int nft_dup_netdev_offload(struct nft_offload_ctx *ctx, 60 + struct nft_flow_rule *flow, 61 + const struct nft_expr *expr) 62 + { 63 + const struct nft_dup_netdev *priv = nft_expr_priv(expr); 64 + int oif = ctx->regs[priv->sreg_dev].data.data[0]; 65 + 66 + return nft_fwd_dup_netdev_offload(ctx, flow, FLOW_ACTION_MIRRED, oif); 67 + } 68 + 60 69 static struct nft_expr_type nft_dup_netdev_type; 61 70 static const struct nft_expr_ops nft_dup_netdev_ops = { 62 71 .type = &nft_dup_netdev_type, ··· 74 63 .eval = nft_dup_netdev_eval, 75 64 .init = nft_dup_netdev_init, 76 65 .dump = nft_dup_netdev_dump, 66 + .offload = nft_dup_netdev_offload, 77 67 }; 78 68 79 69 static struct nft_expr_type nft_dup_netdev_type __read_mostly = {
+12
net/netfilter/nft_fwd_netdev.c
··· 12 12 #include <linux/ip.h> 13 13 #include <linux/ipv6.h> 14 14 #include <net/netfilter/nf_tables.h> 15 + #include <net/netfilter/nf_tables_offload.h> 15 16 #include <net/netfilter/nf_dup_netdev.h> 16 17 #include <net/neighbour.h> 17 18 #include <net/ip.h> ··· 62 61 63 62 nla_put_failure: 64 63 return -1; 64 + } 65 + 66 + static int nft_fwd_netdev_offload(struct nft_offload_ctx *ctx, 67 + struct nft_flow_rule *flow, 68 + const struct nft_expr *expr) 69 + { 70 + const struct nft_fwd_netdev *priv = nft_expr_priv(expr); 71 + int oif = ctx->regs[priv->sreg_dev].data.data[0]; 72 + 73 + return nft_fwd_dup_netdev_offload(ctx, flow, FLOW_ACTION_REDIRECT, oif); 65 74 } 66 75 67 76 struct nft_fwd_neigh { ··· 205 194 .eval = nft_fwd_netdev_eval, 206 195 .init = nft_fwd_netdev_init, 207 196 .dump = nft_fwd_netdev_dump, 197 + .offload = nft_fwd_netdev_offload, 208 198 }; 209 199 210 200 static const struct nft_expr_ops *