Skip to content

Commit

Permalink
netfilter: nf_flow_table: hardware offload support
Browse files Browse the repository at this point in the history
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: Pablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
ummakynes authored and davem330 committed Nov 13, 2019
1 parent 8bb69f3 commit c29f74e
Show file tree
Hide file tree
Showing 8 changed files with 822 additions and 9 deletions.
1 change: 1 addition & 0 deletions include/linux/netdevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -848,6 +848,7 @@ enum tc_setup_type {
TC_SETUP_ROOT_QDISC,
TC_SETUP_QDISC_GRED,
TC_SETUP_QDISC_TAPRIO,
TC_SETUP_FT,
};

/* These structures hold the attributes of bpf state that are being passed
Expand Down
33 changes: 27 additions & 6 deletions include/net/netfilter/nf_flow_table.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
#include <net/dst.h>

struct nf_flowtable;
struct nf_flow_rule;
struct flow_offload;
enum flow_offload_tuple_dir;

struct nf_flowtable_type {
struct list_head list;
Expand All @@ -20,6 +23,10 @@ struct nf_flowtable_type {
int (*setup)(struct nf_flowtable *ft,
struct net_device *dev,
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);
nf_hookfn *hook;
struct module *owner;
Expand Down Expand Up @@ -80,6 +87,9 @@ struct flow_offload_tuple_rhash {
#define FLOW_OFFLOAD_DNAT 0x2
#define FLOW_OFFLOAD_DYING 0x4
#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 {
NF_FLOW_OFFLOAD_UNSPEC = 0,
Expand Down Expand Up @@ -142,11 +152,22 @@ unsigned int nf_flow_offload_ipv6_hook(void *priv, struct sk_buff *skb,
#define MODULE_ALIAS_NF_FLOWTABLE(family) \
MODULE_ALIAS("nf-flowtable-" __stringify(family))

static inline int nf_flow_table_offload_setup(struct nf_flowtable *flowtable,
struct net_device *dev,
enum flow_block_command cmd)
{
return 0;
}
void nf_flow_offload_add(struct nf_flowtable *flowtable,
struct flow_offload *flow);
void nf_flow_offload_del(struct nf_flowtable *flowtable,
struct flow_offload *flow);
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 */
1 change: 1 addition & 0 deletions net/ipv4/netfilter/nf_flow_table_ipv4.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ static struct nf_flowtable_type flowtable_ipv4 = {
.family = NFPROTO_IPV4,
.init = nf_flow_table_init,
.setup = nf_flow_table_offload_setup,
.action = nf_flow_rule_route,
.free = nf_flow_table_free,
.hook = nf_flow_offload_ip_hook,
.owner = THIS_MODULE,
Expand Down
1 change: 1 addition & 0 deletions net/ipv6/netfilter/nf_flow_table_ipv6.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ static struct nf_flowtable_type flowtable_ipv6 = {
.family = NFPROTO_IPV6,
.init = nf_flow_table_init,
.setup = nf_flow_table_offload_setup,
.action = nf_flow_rule_route,
.free = nf_flow_table_free,
.hook = nf_flow_offload_ipv6_hook,
.owner = THIS_MODULE,
Expand Down
3 changes: 2 additions & 1 deletion net/netfilter/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,8 @@ obj-$(CONFIG_NFT_FWD_NETDEV) += nft_fwd_netdev.o

# flow table infrastructure
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

Expand Down
33 changes: 31 additions & 2 deletions net/netfilter/nf_flow_table_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,9 @@ int flow_offload_add(struct nf_flowtable *flow_table, struct flow_offload *flow)
return err;
}

if (flow_table->flags & NF_FLOWTABLE_HW_OFFLOAD)
nf_flow_offload_add(flow_table, flow);

return 0;
}
EXPORT_SYMBOL_GPL(flow_offload_add);
Expand Down Expand Up @@ -350,9 +353,20 @@ static void nf_flow_offload_gc_step(struct flow_offload *flow, void *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) ||
(flow->flags & (FLOW_OFFLOAD_DYING | FLOW_OFFLOAD_TEARDOWN)))
flow_offload_del(flow_table, flow);
(flow->flags & (FLOW_OFFLOAD_DYING | FLOW_OFFLOAD_TEARDOWN))) {
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)
Expand Down Expand Up @@ -485,6 +499,7 @@ int nf_flow_table_init(struct nf_flowtable *flowtable)
int err;

INIT_DEFERRABLE_WORK(&flowtable->gc_work, nf_flow_offload_work_gc);
flow_block_init(&flowtable->flow_block);

err = rhashtable_init(&flowtable->rhashtable,
&nf_flow_offload_rhash_params);
Expand Down Expand Up @@ -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,
struct net_device *dev)
{
nf_flow_table_offload_flush(flowtable);
nf_flow_table_iterate(flowtable, nf_flow_table_do_cleanup, dev);
flush_delayed_work(&flowtable->gc_work);
}
Expand Down Expand Up @@ -547,5 +563,18 @@ void nf_flow_table_free(struct nf_flowtable *flow_table)
}
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_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>");
1 change: 1 addition & 0 deletions net/netfilter/nf_flow_table_inet.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ static struct nf_flowtable_type flowtable_inet = {
.family = NFPROTO_INET,
.init = nf_flow_table_init,
.setup = nf_flow_table_offload_setup,
.action = nf_flow_rule_route,
.free = nf_flow_table_free,
.hook = nf_flow_offload_inet_hook,
.owner = THIS_MODULE,
Expand Down
Loading

0 comments on commit c29f74e

Please sign in to comment.