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