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>
This commit is contained in:
parent
ee394f96ad
commit
be2861dc36
include/net/netfilter
net/netfilter
@ -7,4 +7,10 @@
|
|||||||
void nf_dup_netdev_egress(const struct nft_pktinfo *pkt, int oif);
|
void nf_dup_netdev_egress(const struct nft_pktinfo *pkt, int oif);
|
||||||
void nf_fwd_netdev_egress(const struct nft_pktinfo *pkt, int oif);
|
void nf_fwd_netdev_egress(const struct nft_pktinfo *pkt, int oif);
|
||||||
|
|
||||||
|
struct nft_offload_ctx;
|
||||||
|
struct nft_flow_rule;
|
||||||
|
|
||||||
|
int nft_fwd_dup_netdev_offload(struct nft_offload_ctx *ctx,
|
||||||
|
struct nft_flow_rule *flow,
|
||||||
|
enum flow_action_id id, int oif);
|
||||||
#endif
|
#endif
|
||||||
|
@ -26,6 +26,7 @@ struct nft_offload_ctx {
|
|||||||
u8 protonum;
|
u8 protonum;
|
||||||
} dep;
|
} dep;
|
||||||
unsigned int num_actions;
|
unsigned int num_actions;
|
||||||
|
struct net *net;
|
||||||
struct nft_offload_reg regs[NFT_REG32_15 + 1];
|
struct nft_offload_reg regs[NFT_REG32_15 + 1];
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -61,7 +62,7 @@ struct nft_flow_rule {
|
|||||||
#define NFT_OFFLOAD_F_ACTION (1 << 0)
|
#define NFT_OFFLOAD_F_ACTION (1 << 0)
|
||||||
|
|
||||||
struct nft_rule;
|
struct nft_rule;
|
||||||
struct nft_flow_rule *nft_flow_rule_create(const struct nft_rule *rule);
|
struct nft_flow_rule *nft_flow_rule_create(struct net *net, 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);
|
||||||
|
|
||||||
|
@ -10,6 +10,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>
|
||||||
#include <net/netfilter/nf_dup_netdev.h>
|
#include <net/netfilter/nf_dup_netdev.h>
|
||||||
|
|
||||||
static void nf_do_netdev_egress(struct sk_buff *skb, struct net_device *dev)
|
static void nf_do_netdev_egress(struct sk_buff *skb, struct net_device *dev)
|
||||||
@ -50,5 +51,25 @@ void nf_dup_netdev_egress(const struct nft_pktinfo *pkt, int oif)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(nf_dup_netdev_egress);
|
EXPORT_SYMBOL_GPL(nf_dup_netdev_egress);
|
||||||
|
|
||||||
|
int nft_fwd_dup_netdev_offload(struct nft_offload_ctx *ctx,
|
||||||
|
struct nft_flow_rule *flow,
|
||||||
|
enum flow_action_id id, int oif)
|
||||||
|
{
|
||||||
|
struct flow_action_entry *entry;
|
||||||
|
struct net_device *dev;
|
||||||
|
|
||||||
|
/* nft_flow_rule_destroy() releases the reference on this device. */
|
||||||
|
dev = dev_get_by_index(ctx->net, oif);
|
||||||
|
if (!dev)
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
|
entry = &flow->rule->action.entries[ctx->num_actions++];
|
||||||
|
entry->id = id;
|
||||||
|
entry->dev = dev;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(nft_fwd_dup_netdev_offload);
|
||||||
|
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>");
|
MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>");
|
||||||
|
@ -2853,7 +2853,7 @@ static int nf_tables_newrule(struct net *net, struct sock *nlsk,
|
|||||||
return nft_table_validate(net, table);
|
return nft_table_validate(net, table);
|
||||||
|
|
||||||
if (chain->flags & NFT_CHAIN_HW_OFFLOAD) {
|
if (chain->flags & NFT_CHAIN_HW_OFFLOAD) {
|
||||||
flow = nft_flow_rule_create(rule);
|
flow = nft_flow_rule_create(net, rule);
|
||||||
if (IS_ERR(flow))
|
if (IS_ERR(flow))
|
||||||
return PTR_ERR(flow);
|
return PTR_ERR(flow);
|
||||||
|
|
||||||
|
@ -28,7 +28,8 @@ static struct nft_flow_rule *nft_flow_rule_alloc(int num_actions)
|
|||||||
return flow;
|
return flow;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct nft_flow_rule *nft_flow_rule_create(const struct nft_rule *rule)
|
struct nft_flow_rule *nft_flow_rule_create(struct net *net,
|
||||||
|
const struct nft_rule *rule)
|
||||||
{
|
{
|
||||||
struct nft_offload_ctx *ctx;
|
struct nft_offload_ctx *ctx;
|
||||||
struct nft_flow_rule *flow;
|
struct nft_flow_rule *flow;
|
||||||
@ -54,6 +55,7 @@ struct nft_flow_rule *nft_flow_rule_create(const struct nft_rule *rule)
|
|||||||
err = -ENOMEM;
|
err = -ENOMEM;
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
|
ctx->net = net;
|
||||||
ctx->dep.type = NFT_OFFLOAD_DEP_UNSPEC;
|
ctx->dep.type = NFT_OFFLOAD_DEP_UNSPEC;
|
||||||
|
|
||||||
while (expr->ops && expr != nft_expr_last(rule)) {
|
while (expr->ops && expr != nft_expr_last(rule)) {
|
||||||
@ -80,6 +82,19 @@ err_out:
|
|||||||
|
|
||||||
void nft_flow_rule_destroy(struct nft_flow_rule *flow)
|
void nft_flow_rule_destroy(struct nft_flow_rule *flow)
|
||||||
{
|
{
|
||||||
|
struct flow_action_entry *entry;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
flow_action_for_each(i, entry, &flow->rule->action) {
|
||||||
|
switch (entry->id) {
|
||||||
|
case FLOW_ACTION_REDIRECT:
|
||||||
|
case FLOW_ACTION_MIRRED:
|
||||||
|
dev_put(entry->dev);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
kfree(flow->rule);
|
kfree(flow->rule);
|
||||||
kfree(flow);
|
kfree(flow);
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,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>
|
||||||
#include <net/netfilter/nf_dup_netdev.h>
|
#include <net/netfilter/nf_dup_netdev.h>
|
||||||
|
|
||||||
struct nft_dup_netdev {
|
struct nft_dup_netdev {
|
||||||
@ -56,6 +57,16 @@ nla_put_failure:
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int nft_dup_netdev_offload(struct nft_offload_ctx *ctx,
|
||||||
|
struct nft_flow_rule *flow,
|
||||||
|
const struct nft_expr *expr)
|
||||||
|
{
|
||||||
|
const struct nft_dup_netdev *priv = nft_expr_priv(expr);
|
||||||
|
int oif = ctx->regs[priv->sreg_dev].data.data[0];
|
||||||
|
|
||||||
|
return nft_fwd_dup_netdev_offload(ctx, flow, FLOW_ACTION_MIRRED, oif);
|
||||||
|
}
|
||||||
|
|
||||||
static struct nft_expr_type nft_dup_netdev_type;
|
static struct nft_expr_type nft_dup_netdev_type;
|
||||||
static const struct nft_expr_ops nft_dup_netdev_ops = {
|
static const struct nft_expr_ops nft_dup_netdev_ops = {
|
||||||
.type = &nft_dup_netdev_type,
|
.type = &nft_dup_netdev_type,
|
||||||
@ -63,6 +74,7 @@ static const struct nft_expr_ops nft_dup_netdev_ops = {
|
|||||||
.eval = nft_dup_netdev_eval,
|
.eval = nft_dup_netdev_eval,
|
||||||
.init = nft_dup_netdev_init,
|
.init = nft_dup_netdev_init,
|
||||||
.dump = nft_dup_netdev_dump,
|
.dump = nft_dup_netdev_dump,
|
||||||
|
.offload = nft_dup_netdev_offload,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct nft_expr_type nft_dup_netdev_type __read_mostly = {
|
static struct nft_expr_type nft_dup_netdev_type __read_mostly = {
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
#include <linux/ip.h>
|
#include <linux/ip.h>
|
||||||
#include <linux/ipv6.h>
|
#include <linux/ipv6.h>
|
||||||
#include <net/netfilter/nf_tables.h>
|
#include <net/netfilter/nf_tables.h>
|
||||||
|
#include <net/netfilter/nf_tables_offload.h>
|
||||||
#include <net/netfilter/nf_dup_netdev.h>
|
#include <net/netfilter/nf_dup_netdev.h>
|
||||||
#include <net/neighbour.h>
|
#include <net/neighbour.h>
|
||||||
#include <net/ip.h>
|
#include <net/ip.h>
|
||||||
@ -63,6 +64,16 @@ nla_put_failure:
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int nft_fwd_netdev_offload(struct nft_offload_ctx *ctx,
|
||||||
|
struct nft_flow_rule *flow,
|
||||||
|
const struct nft_expr *expr)
|
||||||
|
{
|
||||||
|
const struct nft_fwd_netdev *priv = nft_expr_priv(expr);
|
||||||
|
int oif = ctx->regs[priv->sreg_dev].data.data[0];
|
||||||
|
|
||||||
|
return nft_fwd_dup_netdev_offload(ctx, flow, FLOW_ACTION_REDIRECT, oif);
|
||||||
|
}
|
||||||
|
|
||||||
struct nft_fwd_neigh {
|
struct nft_fwd_neigh {
|
||||||
enum nft_registers sreg_dev:8;
|
enum nft_registers sreg_dev:8;
|
||||||
enum nft_registers sreg_addr:8;
|
enum nft_registers sreg_addr:8;
|
||||||
@ -194,6 +205,7 @@ static const struct nft_expr_ops nft_fwd_netdev_ops = {
|
|||||||
.eval = nft_fwd_netdev_eval,
|
.eval = nft_fwd_netdev_eval,
|
||||||
.init = nft_fwd_netdev_init,
|
.init = nft_fwd_netdev_init,
|
||||||
.dump = nft_fwd_netdev_dump,
|
.dump = nft_fwd_netdev_dump,
|
||||||
|
.offload = nft_fwd_netdev_offload,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct nft_expr_ops *
|
static const struct nft_expr_ops *
|
||||||
|
Loading…
Reference in New Issue
Block a user