Skip to content

Commit c34b961

Browse files
Paul Blakeydavem330
authored andcommitted
net/sched: act_ct: Create nf flow table per zone
Use the NF flow tables infrastructure for CT offload. Create a nf flow table per zone. Next patches will add FT entries to this table, and do the software offload. Signed-off-by: Paul Blakey <[email protected]> Reviewed-by: Jiri Pirko <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent a7442ec commit c34b961

File tree

3 files changed

+136
-2
lines changed

3 files changed

+136
-2
lines changed

include/net/tc_act/tc_ct.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ struct tcf_ct_params {
2525
u16 ct_action;
2626

2727
struct rcu_head rcu;
28+
29+
struct tcf_ct_flow_table *ct_ft;
2830
};
2931

3032
struct tcf_ct {

net/sched/Kconfig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -972,7 +972,7 @@ config NET_ACT_TUNNEL_KEY
972972

973973
config NET_ACT_CT
974974
tristate "connection tracking tc action"
975-
depends on NET_CLS_ACT && NF_CONNTRACK && NF_NAT
975+
depends on NET_CLS_ACT && NF_CONNTRACK && NF_NAT && NF_FLOW_TABLE
976976
help
977977
Say Y here to allow sending the packets to conntrack module.
978978

net/sched/act_ct.c

Lines changed: 133 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include <linux/pkt_cls.h>
1616
#include <linux/ip.h>
1717
#include <linux/ipv6.h>
18+
#include <linux/rhashtable.h>
1819
#include <net/netlink.h>
1920
#include <net/pkt_sched.h>
2021
#include <net/pkt_cls.h>
@@ -24,13 +25,116 @@
2425
#include <uapi/linux/tc_act/tc_ct.h>
2526
#include <net/tc_act/tc_ct.h>
2627

28+
#include <net/netfilter/nf_flow_table.h>
2729
#include <net/netfilter/nf_conntrack.h>
2830
#include <net/netfilter/nf_conntrack_core.h>
2931
#include <net/netfilter/nf_conntrack_zones.h>
3032
#include <net/netfilter/nf_conntrack_helper.h>
3133
#include <net/netfilter/ipv6/nf_defrag_ipv6.h>
3234
#include <uapi/linux/netfilter/nf_nat.h>
3335

36+
static struct workqueue_struct *act_ct_wq;
37+
static struct rhashtable zones_ht;
38+
static DEFINE_SPINLOCK(zones_lock);
39+
40+
struct tcf_ct_flow_table {
41+
struct rhash_head node; /* In zones tables */
42+
43+
struct rcu_work rwork;
44+
struct nf_flowtable nf_ft;
45+
u16 zone;
46+
u32 ref;
47+
48+
bool dying;
49+
};
50+
51+
static const struct rhashtable_params zones_params = {
52+
.head_offset = offsetof(struct tcf_ct_flow_table, node),
53+
.key_offset = offsetof(struct tcf_ct_flow_table, zone),
54+
.key_len = sizeof_field(struct tcf_ct_flow_table, zone),
55+
.automatic_shrinking = true,
56+
};
57+
58+
static struct nf_flowtable_type flowtable_ct = {
59+
.owner = THIS_MODULE,
60+
};
61+
62+
static int tcf_ct_flow_table_get(struct tcf_ct_params *params)
63+
{
64+
struct tcf_ct_flow_table *ct_ft;
65+
int err = -ENOMEM;
66+
67+
spin_lock_bh(&zones_lock);
68+
ct_ft = rhashtable_lookup_fast(&zones_ht, &params->zone, zones_params);
69+
if (ct_ft)
70+
goto take_ref;
71+
72+
ct_ft = kzalloc(sizeof(*ct_ft), GFP_ATOMIC);
73+
if (!ct_ft)
74+
goto err_alloc;
75+
76+
ct_ft->zone = params->zone;
77+
err = rhashtable_insert_fast(&zones_ht, &ct_ft->node, zones_params);
78+
if (err)
79+
goto err_insert;
80+
81+
ct_ft->nf_ft.type = &flowtable_ct;
82+
err = nf_flow_table_init(&ct_ft->nf_ft);
83+
if (err)
84+
goto err_init;
85+
86+
__module_get(THIS_MODULE);
87+
take_ref:
88+
params->ct_ft = ct_ft;
89+
ct_ft->ref++;
90+
spin_unlock_bh(&zones_lock);
91+
92+
return 0;
93+
94+
err_init:
95+
rhashtable_remove_fast(&zones_ht, &ct_ft->node, zones_params);
96+
err_insert:
97+
kfree(ct_ft);
98+
err_alloc:
99+
spin_unlock_bh(&zones_lock);
100+
return err;
101+
}
102+
103+
static void tcf_ct_flow_table_cleanup_work(struct work_struct *work)
104+
{
105+
struct tcf_ct_flow_table *ct_ft;
106+
107+
ct_ft = container_of(to_rcu_work(work), struct tcf_ct_flow_table,
108+
rwork);
109+
nf_flow_table_free(&ct_ft->nf_ft);
110+
kfree(ct_ft);
111+
112+
module_put(THIS_MODULE);
113+
}
114+
115+
static void tcf_ct_flow_table_put(struct tcf_ct_params *params)
116+
{
117+
struct tcf_ct_flow_table *ct_ft = params->ct_ft;
118+
119+
spin_lock_bh(&zones_lock);
120+
if (--params->ct_ft->ref == 0) {
121+
rhashtable_remove_fast(&zones_ht, &ct_ft->node, zones_params);
122+
INIT_RCU_WORK(&ct_ft->rwork, tcf_ct_flow_table_cleanup_work);
123+
queue_rcu_work(act_ct_wq, &ct_ft->rwork);
124+
}
125+
spin_unlock_bh(&zones_lock);
126+
}
127+
128+
static int tcf_ct_flow_tables_init(void)
129+
{
130+
return rhashtable_init(&zones_ht, &zones_params);
131+
}
132+
133+
static void tcf_ct_flow_tables_uninit(void)
134+
{
135+
rhashtable_destroy(&zones_ht);
136+
}
137+
34138
static struct tc_action_ops act_ct_ops;
35139
static unsigned int ct_net_id;
36140

@@ -207,6 +311,8 @@ static void tcf_ct_params_free(struct rcu_head *head)
207311
struct tcf_ct_params *params = container_of(head,
208312
struct tcf_ct_params, rcu);
209313

314+
tcf_ct_flow_table_put(params);
315+
210316
if (params->tmpl)
211317
nf_conntrack_put(&params->tmpl->ct_general);
212318
kfree(params);
@@ -730,6 +836,10 @@ static int tcf_ct_init(struct net *net, struct nlattr *nla,
730836
if (err)
731837
goto cleanup;
732838

839+
err = tcf_ct_flow_table_get(params);
840+
if (err)
841+
goto cleanup;
842+
733843
spin_lock_bh(&c->tcf_lock);
734844
goto_ch = tcf_action_set_ctrlact(*a, parm->action, goto_ch);
735845
params = rcu_replace_pointer(c->params, params,
@@ -974,12 +1084,34 @@ static struct pernet_operations ct_net_ops = {
9741084

9751085
static int __init ct_init_module(void)
9761086
{
977-
return tcf_register_action(&act_ct_ops, &ct_net_ops);
1087+
int err;
1088+
1089+
act_ct_wq = alloc_ordered_workqueue("act_ct_workqueue", 0);
1090+
if (!act_ct_wq)
1091+
return -ENOMEM;
1092+
1093+
err = tcf_ct_flow_tables_init();
1094+
if (err)
1095+
goto err_tbl_init;
1096+
1097+
err = tcf_register_action(&act_ct_ops, &ct_net_ops);
1098+
if (err)
1099+
goto err_register;
1100+
1101+
return 0;
1102+
1103+
err_tbl_init:
1104+
destroy_workqueue(act_ct_wq);
1105+
err_register:
1106+
tcf_ct_flow_tables_uninit();
1107+
return err;
9781108
}
9791109

9801110
static void __exit ct_cleanup_module(void)
9811111
{
9821112
tcf_unregister_action(&act_ct_ops, &ct_net_ops);
1113+
tcf_ct_flow_tables_uninit();
1114+
destroy_workqueue(act_ct_wq);
9831115
}
9841116

9851117
module_init(ct_init_module);

0 commit comments

Comments
 (0)