Commit c29f74e0 authored by Pablo Neira Ayuso's avatar Pablo Neira Ayuso Committed by David S. Miller

netfilter: nf_flow_table: hardware offload support

This patch adds the dataplane hardware offload to the flowtable
infrastructure. Three new flags represent the hardware state of this
flow:

* FLOW_OFFLOAD_HW: This flow entry resides in the hardware.
* FLOW_OFFLOAD_HW_DYING: This flow entry has been scheduled to be remove
  from hardware. This might be triggered by either packet path (via TCP
  RST/FIN packet) or via aging.
* FLOW_OFFLOAD_HW_DEAD: This flow entry has been already removed from
  the hardware, the software garbage collector can remove it from the
  software flowtable.

This patch supports for:

* IPv4 only.
* Aging via FLOW_CLS_STATS, no packet and byte counter synchronization
  at this stage.

This patch also adds the action callback that specifies how to convert
the flow entry into the flow_rule object that is passed to the driver.
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 8bb69f3b
...@@ -848,6 +848,7 @@ enum tc_setup_type { ...@@ -848,6 +848,7 @@ enum tc_setup_type {
TC_SETUP_ROOT_QDISC, TC_SETUP_ROOT_QDISC,
TC_SETUP_QDISC_GRED, TC_SETUP_QDISC_GRED,
TC_SETUP_QDISC_TAPRIO, TC_SETUP_QDISC_TAPRIO,
TC_SETUP_FT,
}; };
/* These structures hold the attributes of bpf state that are being passed /* These structures hold the attributes of bpf state that are being passed
......
...@@ -12,6 +12,9 @@ ...@@ -12,6 +12,9 @@
#include <net/dst.h> #include <net/dst.h>
struct nf_flowtable; struct nf_flowtable;
struct nf_flow_rule;
struct flow_offload;
enum flow_offload_tuple_dir;
struct nf_flowtable_type { struct nf_flowtable_type {
struct list_head list; struct list_head list;
...@@ -20,6 +23,10 @@ struct nf_flowtable_type { ...@@ -20,6 +23,10 @@ struct nf_flowtable_type {
int (*setup)(struct nf_flowtable *ft, int (*setup)(struct nf_flowtable *ft,
struct net_device *dev, struct net_device *dev,
enum flow_block_command cmd); enum flow_block_command cmd);
int (*action)(struct net *net,
const struct flow_offload *flow,
enum flow_offload_tuple_dir dir,
struct nf_flow_rule *flow_rule);
void (*free)(struct nf_flowtable *ft); void (*free)(struct nf_flowtable *ft);
nf_hookfn *hook; nf_hookfn *hook;
struct module *owner; struct module *owner;
...@@ -80,6 +87,9 @@ struct flow_offload_tuple_rhash { ...@@ -80,6 +87,9 @@ struct flow_offload_tuple_rhash {
#define FLOW_OFFLOAD_DNAT 0x2 #define FLOW_OFFLOAD_DNAT 0x2
#define FLOW_OFFLOAD_DYING 0x4 #define FLOW_OFFLOAD_DYING 0x4
#define FLOW_OFFLOAD_TEARDOWN 0x8 #define FLOW_OFFLOAD_TEARDOWN 0x8
#define FLOW_OFFLOAD_HW 0x10
#define FLOW_OFFLOAD_HW_DYING 0x20
#define FLOW_OFFLOAD_HW_DEAD 0x40
enum flow_offload_type { enum flow_offload_type {
NF_FLOW_OFFLOAD_UNSPEC = 0, NF_FLOW_OFFLOAD_UNSPEC = 0,
...@@ -142,11 +152,22 @@ unsigned int nf_flow_offload_ipv6_hook(void *priv, struct sk_buff *skb, ...@@ -142,11 +152,22 @@ unsigned int nf_flow_offload_ipv6_hook(void *priv, struct sk_buff *skb,
#define MODULE_ALIAS_NF_FLOWTABLE(family) \ #define MODULE_ALIAS_NF_FLOWTABLE(family) \
MODULE_ALIAS("nf-flowtable-" __stringify(family)) MODULE_ALIAS("nf-flowtable-" __stringify(family))
static inline int nf_flow_table_offload_setup(struct nf_flowtable *flowtable, void nf_flow_offload_add(struct nf_flowtable *flowtable,
struct net_device *dev, struct flow_offload *flow);
enum flow_block_command cmd) void nf_flow_offload_del(struct nf_flowtable *flowtable,
{ struct flow_offload *flow);
return 0; void nf_flow_offload_stats(struct nf_flowtable *flowtable,
} struct flow_offload *flow);
void nf_flow_table_offload_flush(struct nf_flowtable *flowtable);
int nf_flow_table_offload_setup(struct nf_flowtable *flowtable,
struct net_device *dev,
enum flow_block_command cmd);
int nf_flow_rule_route(struct net *net, const struct flow_offload *flow,
enum flow_offload_tuple_dir dir,
struct nf_flow_rule *flow_rule);
int nf_flow_table_offload_init(void);
void nf_flow_table_offload_exit(void);
#endif /* _NF_FLOW_TABLE_H */ #endif /* _NF_FLOW_TABLE_H */
...@@ -10,6 +10,7 @@ static struct nf_flowtable_type flowtable_ipv4 = { ...@@ -10,6 +10,7 @@ static struct nf_flowtable_type flowtable_ipv4 = {
.family = NFPROTO_IPV4, .family = NFPROTO_IPV4,
.init = nf_flow_table_init, .init = nf_flow_table_init,
.setup = nf_flow_table_offload_setup, .setup = nf_flow_table_offload_setup,
.action = nf_flow_rule_route,
.free = nf_flow_table_free, .free = nf_flow_table_free,
.hook = nf_flow_offload_ip_hook, .hook = nf_flow_offload_ip_hook,
.owner = THIS_MODULE, .owner = THIS_MODULE,
......
...@@ -11,6 +11,7 @@ static struct nf_flowtable_type flowtable_ipv6 = { ...@@ -11,6 +11,7 @@ static struct nf_flowtable_type flowtable_ipv6 = {
.family = NFPROTO_IPV6, .family = NFPROTO_IPV6,
.init = nf_flow_table_init, .init = nf_flow_table_init,
.setup = nf_flow_table_offload_setup, .setup = nf_flow_table_offload_setup,
.action = nf_flow_rule_route,
.free = nf_flow_table_free, .free = nf_flow_table_free,
.hook = nf_flow_offload_ipv6_hook, .hook = nf_flow_offload_ipv6_hook,
.owner = THIS_MODULE, .owner = THIS_MODULE,
......
...@@ -120,7 +120,8 @@ obj-$(CONFIG_NFT_FWD_NETDEV) += nft_fwd_netdev.o ...@@ -120,7 +120,8 @@ obj-$(CONFIG_NFT_FWD_NETDEV) += nft_fwd_netdev.o
# flow table infrastructure # flow table infrastructure
obj-$(CONFIG_NF_FLOW_TABLE) += nf_flow_table.o 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-objs := nf_flow_table_core.o nf_flow_table_ip.o \
nf_flow_table_offload.o
obj-$(CONFIG_NF_FLOW_TABLE_INET) += nf_flow_table_inet.o obj-$(CONFIG_NF_FLOW_TABLE_INET) += nf_flow_table_inet.o
......
...@@ -250,6 +250,9 @@ int flow_offload_add(struct nf_flowtable *flow_table, struct flow_offload *flow) ...@@ -250,6 +250,9 @@ int flow_offload_add(struct nf_flowtable *flow_table, struct flow_offload *flow)
return err; return err;
} }
if (flow_table->flags & NF_FLOWTABLE_HW_OFFLOAD)
nf_flow_offload_add(flow_table, flow);
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(flow_offload_add); EXPORT_SYMBOL_GPL(flow_offload_add);
...@@ -350,9 +353,20 @@ static void nf_flow_offload_gc_step(struct flow_offload *flow, void *data) ...@@ -350,9 +353,20 @@ static void nf_flow_offload_gc_step(struct flow_offload *flow, void *data)
{ {
struct nf_flowtable *flow_table = data; struct nf_flowtable *flow_table = data;
if (flow->flags & FLOW_OFFLOAD_HW)
nf_flow_offload_stats(flow_table, flow);
if (nf_flow_has_expired(flow) || nf_ct_is_dying(flow->ct) || if (nf_flow_has_expired(flow) || nf_ct_is_dying(flow->ct) ||
(flow->flags & (FLOW_OFFLOAD_DYING | FLOW_OFFLOAD_TEARDOWN))) (flow->flags & (FLOW_OFFLOAD_DYING | FLOW_OFFLOAD_TEARDOWN))) {
flow_offload_del(flow_table, flow); if (flow->flags & FLOW_OFFLOAD_HW) {
if (!(flow->flags & FLOW_OFFLOAD_HW_DYING))
nf_flow_offload_del(flow_table, flow);
else if (flow->flags & FLOW_OFFLOAD_HW_DEAD)
flow_offload_del(flow_table, flow);
} else {
flow_offload_del(flow_table, flow);
}
}
} }
static void nf_flow_offload_work_gc(struct work_struct *work) static void nf_flow_offload_work_gc(struct work_struct *work)
...@@ -485,6 +499,7 @@ int nf_flow_table_init(struct nf_flowtable *flowtable) ...@@ -485,6 +499,7 @@ int nf_flow_table_init(struct nf_flowtable *flowtable)
int err; int err;
INIT_DEFERRABLE_WORK(&flowtable->gc_work, nf_flow_offload_work_gc); INIT_DEFERRABLE_WORK(&flowtable->gc_work, nf_flow_offload_work_gc);
flow_block_init(&flowtable->flow_block);
err = rhashtable_init(&flowtable->rhashtable, err = rhashtable_init(&flowtable->rhashtable,
&nf_flow_offload_rhash_params); &nf_flow_offload_rhash_params);
...@@ -520,6 +535,7 @@ static void nf_flow_table_do_cleanup(struct flow_offload *flow, void *data) ...@@ -520,6 +535,7 @@ static void nf_flow_table_do_cleanup(struct flow_offload *flow, void *data)
static void nf_flow_table_iterate_cleanup(struct nf_flowtable *flowtable, static void nf_flow_table_iterate_cleanup(struct nf_flowtable *flowtable,
struct net_device *dev) struct net_device *dev)
{ {
nf_flow_table_offload_flush(flowtable);
nf_flow_table_iterate(flowtable, nf_flow_table_do_cleanup, dev); nf_flow_table_iterate(flowtable, nf_flow_table_do_cleanup, dev);
flush_delayed_work(&flowtable->gc_work); flush_delayed_work(&flowtable->gc_work);
} }
...@@ -547,5 +563,18 @@ void nf_flow_table_free(struct nf_flowtable *flow_table) ...@@ -547,5 +563,18 @@ void nf_flow_table_free(struct nf_flowtable *flow_table)
} }
EXPORT_SYMBOL_GPL(nf_flow_table_free); EXPORT_SYMBOL_GPL(nf_flow_table_free);
static int __init nf_flow_table_module_init(void)
{
return nf_flow_table_offload_init();
}
static void __exit nf_flow_table_module_exit(void)
{
nf_flow_table_offload_exit();
}
module_init(nf_flow_table_module_init);
module_exit(nf_flow_table_module_exit);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>"); MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>");
...@@ -25,6 +25,7 @@ static struct nf_flowtable_type flowtable_inet = { ...@@ -25,6 +25,7 @@ static struct nf_flowtable_type flowtable_inet = {
.family = NFPROTO_INET, .family = NFPROTO_INET,
.init = nf_flow_table_init, .init = nf_flow_table_init,
.setup = nf_flow_table_offload_setup, .setup = nf_flow_table_offload_setup,
.action = nf_flow_rule_route,
.free = nf_flow_table_free, .free = nf_flow_table_free,
.hook = nf_flow_offload_inet_hook, .hook = nf_flow_offload_inet_hook,
.owner = THIS_MODULE, .owner = THIS_MODULE,
......
This diff is collapsed.
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