blob: 3b9e863be74129106970e1e44275ff0e0cc218e4 [file] [log] [blame]
developereed1a952023-03-01 14:30:18 +08001diff --git a/include/net/netfilter/nf_flow_table.h b/include/net/netfilter/nf_flow_table.h
2index 8a84de3..1a23c03 100644
3--- a/include/net/netfilter/nf_flow_table.h
4+++ b/include/net/netfilter/nf_flow_table.h
5@@ -276,6 +276,7 @@ int nf_flow_table_init(struct nf_flowtable *flow_table);
6 void nf_flow_table_free(struct nf_flowtable *flow_table);
7
8 void flow_offload_teardown(struct flow_offload *flow);
9+void flow_offload_teardown_by_tuple(struct flow_offload_tuple *tuple);
10
11 int nf_flow_table_iterate(struct nf_flowtable *flow_table,
12 void (*iter)(struct flow_offload *flow, void *data),
13diff --git a/include/uapi/linux/netfilter/nfnetlink.h b/include/uapi/linux/netfilter/nfnetlink.h
14index 5bc960f..603d9c0 100644
15--- a/include/uapi/linux/netfilter/nfnetlink.h
16+++ b/include/uapi/linux/netfilter/nfnetlink.h
17@@ -60,7 +60,8 @@ struct nfgenmsg {
18 #define NFNL_SUBSYS_CTHELPER 9
19 #define NFNL_SUBSYS_NFTABLES 10
20 #define NFNL_SUBSYS_NFT_COMPAT 11
21-#define NFNL_SUBSYS_COUNT 12
22+#define NFNL_SUBSYS_FLOWTABLE 12
23+#define NFNL_SUBSYS_COUNT 13
24
25 /* Reserved control nfnetlink messages */
26 #define NFNL_MSG_BATCH_BEGIN NLMSG_MIN_TYPE
27diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
28index 5d690ab..8ec87aa 100644
29--- a/net/netfilter/Kconfig
30+++ b/net/netfilter/Kconfig
31@@ -708,6 +708,15 @@ config NF_FLOW_TABLE
32
33 To compile it as a module, choose M here.
34
35+config NF_FLOW_TABLE_NETLINK
36+ tristate "Netfilter flow table netlink module"
37+ depends on NETFILTER_INGRESS
38+ depends on NF_CONNTRACK
39+ help
40+ This option adds the flow table core infrastructure.
41+
42+ To compile it as a module, choose M here.
43+
44 config NETFILTER_XTABLES
45 tristate "Netfilter Xtables support (required for ip_tables)"
46 default m if NETFILTER_ADVANCED=n
47diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile
48index d93a121..fa6ffb1 100644
49--- a/net/netfilter/Makefile
50+++ b/net/netfilter/Makefile
51@@ -124,6 +124,7 @@ nf_flow_table-objs := nf_flow_table_core.o nf_flow_table_ip.o \
52 nf_flow_table_offload.o
53
54 obj-$(CONFIG_NF_FLOW_TABLE_INET) += nf_flow_table_inet.o
55+obj-$(CONFIG_NF_FLOW_TABLE_NETLINK) += nf_flow_table_netlink.o
56
57 # generic X tables
58 obj-$(CONFIG_NETFILTER_XTABLES) += x_tables.o xt_tcpudp.o
59diff --git a/net/netfilter/nf_flow_table_core.c b/net/netfilter/nf_flow_table_core.c
60index 1036558..a0f52f6 100644
61--- a/net/netfilter/nf_flow_table_core.c
62+++ b/net/netfilter/nf_flow_table_core.c
63@@ -373,6 +373,29 @@ void flow_offload_teardown(struct flow_offload *flow)
64 }
65 EXPORT_SYMBOL_GPL(flow_offload_teardown);
66
67+void flow_offload_teardown_by_tuple(struct flow_offload_tuple *tuple)
68+{
69+ struct net_device *netdev;
70+ struct nf_flowtable *flowtable;
71+ struct flow_offload_tuple_rhash *tuplehash;
72+ struct flow_offload *flow;
73+ int dir;
74+
75+ list_for_each_entry(flowtable, &flowtables, list) {
76+ for_each_netdev(&init_net, netdev) {
77+ tuple->iifidx = netdev->ifindex;
78+ tuplehash = flow_offload_lookup(flowtable, tuple);
79+ if (!tuplehash)
80+ continue;
81+
82+ dir = tuplehash->tuple.dir;
83+ flow = container_of(tuplehash, struct flow_offload, tuplehash[dir]);
84+ flow_offload_teardown(flow);
85+ }
86+ };
87+}
88+EXPORT_SYMBOL_GPL(flow_offload_teardown_by_tuple);
89+
90 struct flow_offload_tuple_rhash *
91 flow_offload_lookup(struct nf_flowtable *flow_table,
92 struct flow_offload_tuple *tuple)
93diff --git a/net/netfilter/nf_flow_table_netlink.c b/net/netfilter/nf_flow_table_netlink.c
94new file mode 100644
95index 0000000..f05f29e
96--- /dev/null
97+++ b/net/netfilter/nf_flow_table_netlink.c
98@@ -0,0 +1,239 @@
99+#include <linux/types.h>
100+#include <linux/kernel.h>
101+#include <linux/init.h>
102+#include <linux/module.h>
103+#include <linux/netfilter.h>
104+#include <linux/netlink.h>
105+#include <net/netlink.h>
106+#include <net/ip.h>
107+#include <linux/netfilter/nfnetlink.h>
108+#include <net/netfilter/nf_flow_table.h>
109+
110+enum ft_netlink_msg_types {
111+ FT_MSG_DEL,
112+ FT_MSG_ADD,
113+ FT_MSG_FLUSH,
114+ FT_MSG_MAX
115+};
116+
117+enum ftattr_type {
118+ FTA_UNSPEC,
119+ FTA_TUPLE,
120+ __FTA_MAX
121+};
122+#define FTA_MAX (__FTA_MAX - 1)
123+
124+enum ftattr_tuple {
125+ FTA_TUPLE_UNSPEC,
126+ FTA_TUPLE_IP,
127+ FTA_TUPLE_PROTO,
128+ FTA_TUPLE_ZONE,
129+ __FTA_TUPLE_MAX
130+};
131+#define FTA_TUPLE_MAX (__FTA_TUPLE_MAX - 1)
132+
133+enum ftattr_ip {
134+ FTA_IP_UNSPEC,
135+ FTA_IP_V4_SRC,
136+ FTA_IP_V4_DST,
137+ __FTA_IP_MAX
138+};
139+#define FTA_IP_MAX (__FTA_IP_MAX - 1)
140+
141+enum ftattr_l4proto {
142+ FTA_PROTO_UNSPEC,
143+ FTA_PROTO_NUM,
144+ FTA_PROTO_SPORT,
145+ FTA_PROTO_DPORT,
146+ __FTA_PROTO_MAX
147+};
148+#define FTA_PROTO_MAX (__FTA_PROTO_MAX - 1)
149+
150+static const struct nla_policy tuple_nla_policy[FTA_TUPLE_MAX + 1] = {
151+ [FTA_TUPLE_IP] = { .type = NLA_NESTED },
152+ [FTA_TUPLE_PROTO] = { .type = NLA_NESTED },
153+ [FTA_TUPLE_ZONE] = { .type = NLA_U16 },
154+};
155+
156+static const struct nla_policy ip_nla_policy[FTA_IP_MAX + 1] = {
157+ [FTA_IP_V4_SRC] = { .type = NLA_U32 },
158+ [FTA_IP_V4_DST] = { .type = NLA_U32 },
159+};
160+
161+static const struct nla_policy l4proto_nla_policy[FTA_PROTO_MAX + 1] = {
162+ [FTA_PROTO_NUM] = { .type = NLA_U8 },
163+ [FTA_PROTO_SPORT] = {.type = NLA_U16},
164+ [FTA_PROTO_DPORT] = {.type = NLA_U16},
165+};
166+
167+static inline int ftnetlink_parse_tuple_ip(struct nlattr *attr,
168+ struct flow_offload_tuple *tuple)
169+{
170+ struct nlattr *tb[FTA_IP_MAX+1];
171+ int err;
172+
173+ err = nla_parse_nested_deprecated(tb, FTA_IP_MAX, attr, ip_nla_policy, NULL);
174+
175+ if (err < 0)
176+ return err;
177+
178+ switch (tuple->l3proto) {
179+ case NFPROTO_IPV4:
180+ if (!tb[FTA_IP_V4_SRC] || !tb[FTA_IP_V4_DST])
181+ return -EINVAL;
182+
183+ tuple->src_v4.s_addr = nla_get_in_addr(tb[FTA_IP_V4_SRC]);
184+ tuple->dst_v4.s_addr = nla_get_in_addr(tb[FTA_IP_V4_DST]);
185+ }
186+
187+ return err;
188+}
189+
190+static inline int ftnetlink_parse_tuple_proto(struct nlattr *attr,
191+ struct flow_offload_tuple *tuple)
192+{
193+ struct nlattr *tb[FTA_PROTO_MAX+1];
194+ int err;
195+
196+ err = nla_parse_nested_deprecated(tb, FTA_PROTO_MAX, attr, l4proto_nla_policy, NULL);
197+
198+ if(err < 0)
199+ return err;
200+
201+ if (!tb[FTA_PROTO_NUM] || !tb[FTA_PROTO_SPORT] || !tb[FTA_PROTO_DPORT])
202+ return -EINVAL;
203+
204+ tuple->l4proto = nla_get_u8(tb[FTA_PROTO_NUM]);
205+ tuple->src_port = nla_get_u16(tb[FTA_PROTO_SPORT]);
206+ tuple->dst_port = nla_get_u16(tb[FTA_PROTO_DPORT]);
207+
208+ return err;
209+}
210+
211+static int ftnetlink_parse_tuple(const struct nlattr * const cda[],
212+ struct flow_offload_tuple *tuple,
213+ int attrtype, int l3proto)
214+{
215+ struct nlattr *tb[FTA_TUPLE_MAX+1];
216+ int err;
217+
218+ memset(tuple, 0, sizeof(*tuple));
219+
220+ err = nla_parse_nested_deprecated(tb, FTA_TUPLE_MAX, cda[attrtype], tuple_nla_policy, NULL);
221+ if (err < 0)
222+ return err;
223+
224+ if (!tb[FTA_TUPLE_IP])
225+ return -EINVAL;
226+
227+ /* parse IP */
228+ tuple->l3proto = l3proto;
229+ err = ftnetlink_parse_tuple_ip(tb[FTA_TUPLE_IP], tuple);
230+ if (err < 0)
231+ return err;
232+
233+ /* parse proto */
234+ if (!tb[FTA_TUPLE_PROTO])
235+ return -EINVAL;
236+ err = ftnetlink_parse_tuple_proto(tb[FTA_TUPLE_PROTO], tuple);
237+
238+ if (err >= 0)
239+ printk("tuple info:sip=%pI4,dip=%pI4 proto=%d "
240+ "sport=%d dport=%d\n",
241+ &tuple->src_v4, &tuple->dst_v4, tuple->l4proto,
242+ ntohs(tuple->src_port), ntohs(tuple->dst_port));
243+
244+ return err;
245+}
246+
247+static int ftnetlink_del_nf_flow(struct net *net, struct sock *ftnl, struct sk_buff *skb,
248+ const struct nlmsghdr *nlh,
249+ const struct nlattr * const cda[],
250+ struct netlink_ext_ack *extack)
251+{
252+ struct net_device *dev = skb->dev;
253+ struct flow_offload_tuple tuple;
254+ int err = -1;
255+ struct nfgenmsg *nfmsg = nlmsg_data(nlh);
256+ u_int8_t u3 = nfmsg->nfgen_family;
257+
258+ /* parse tuple */
259+ if(!cda[FTA_TUPLE])
260+ return -EINVAL;
261+
262+ err = ftnetlink_parse_tuple(cda, &tuple, FTA_TUPLE, u3);
263+ if (err < 0)
264+ return err;
265+
266+ /* teardown the flow */
267+ flow_offload_teardown_by_tuple(&tuple);
268+
269+ return 0;
270+}
271+
272+static int ftnetlink_add_nf_flow(struct net *net, struct sock *ftnl, struct sk_buff *skb,
273+ const struct nlmsghdr *nlh,
274+ const struct nlattr * const cda[],
275+ struct netlink_ext_ack *extack)
276+{
277+ return 0;
278+}
279+
280+static int ftnetlink_flush_table(struct net *net, struct sock *ftnl, struct sk_buff *skb,
281+ const struct nlmsghdr *nlh,
282+ const struct nlattr * const cda[],
283+ struct netlink_ext_ack *extack)
284+{
285+ struct net_device *dev = skb->dev;
286+
287+ nf_flow_table_cleanup(dev);
288+
289+ return 0;
290+}
291+
292+static const struct nla_policy ft_nla_policy[FTA_MAX + 1] = {
293+ [FTA_TUPLE] = { .type = NLA_NESTED },
294+};
295+
296+static const struct nfnl_callback flow_table_cb[FT_MSG_MAX] = {
297+ [FT_MSG_DEL] = {
298+ .call = ftnetlink_del_nf_flow,
299+ .attr_count = FTA_MAX,
300+ .policy = ft_nla_policy
301+ },
302+ [FT_MSG_ADD] = {
303+ .call = ftnetlink_add_nf_flow,
304+ .attr_count = FTA_MAX,
305+ .policy = ft_nla_policy
306+ },
307+ [FT_MSG_FLUSH] = {
308+ .call = ftnetlink_flush_table,
309+ .attr_count = FTA_MAX,
310+ .policy = ft_nla_policy
311+ },
312+};
313+
314+static const struct nfnetlink_subsystem ftnl_subsys = {
315+ .name = "flowtable",
316+ .subsys_id = NFNL_SUBSYS_FLOWTABLE,
317+ .cb_count = FT_MSG_MAX,
318+ .cb = flow_table_cb,
319+};
320+
321+static int __init ftnetlink_init(void)
322+{
323+ int ret;
324+
325+ ret = nfnetlink_subsys_register(&ftnl_subsys);
326+
327+ return ret;
328+}
329+
330+static void ftnetlink_exit(void)
331+{
332+ nfnetlink_subsys_unregister(&ftnl_subsys);
333+}
334+
335+MODULE_LICENSE("GPL");
336+module_init(ftnetlink_init);
337+module_exit(ftnetlink_exit);