kernel: add linux 5.10 support
[openwrt/staging/dedeckeh.git] / target / linux / generic / pending-5.10 / 640-01-netfilter-flowtable-add-xmit-path-types.patch
1 From: Pablo Neira Ayuso <pablo@netfilter.org>
2 Date: Fri, 20 Nov 2020 13:49:14 +0100
3 Subject: [PATCH] netfilter: flowtable: add xmit path types
4
5 Add the xmit_type field that defines the two supported xmit paths in the
6 flowtable data plane, which are the neighbour and the xfrm xmit paths.
7 This patch prepares for new flowtable xmit path types to come.
8
9 Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
10 ---
11
12 --- a/include/net/netfilter/nf_flow_table.h
13 +++ b/include/net/netfilter/nf_flow_table.h
14 @@ -89,6 +89,11 @@ enum flow_offload_tuple_dir {
15 FLOW_OFFLOAD_DIR_MAX = IP_CT_DIR_MAX
16 };
17
18 +enum flow_offload_xmit_type {
19 + FLOW_OFFLOAD_XMIT_NEIGH = 0,
20 + FLOW_OFFLOAD_XMIT_XFRM,
21 +};
22 +
23 struct flow_offload_tuple {
24 union {
25 struct in_addr src_v4;
26 @@ -111,7 +116,8 @@ struct flow_offload_tuple {
27 /* All members above are keys for lookups, see flow_offload_hash(). */
28 struct { } __hash;
29
30 - u8 dir;
31 + u8 dir:6,
32 + xmit_type:2;
33
34 u16 mtu;
35
36 @@ -158,7 +164,8 @@ static inline __s32 nf_flow_timeout_delt
37
38 struct nf_flow_route {
39 struct {
40 - struct dst_entry *dst;
41 + struct dst_entry *dst;
42 + enum flow_offload_xmit_type xmit_type;
43 } tuple[FLOW_OFFLOAD_DIR_MAX];
44 };
45
46 --- a/net/netfilter/nf_flow_table_core.c
47 +++ b/net/netfilter/nf_flow_table_core.c
48 @@ -95,6 +95,7 @@ static int flow_offload_fill_route(struc
49 }
50
51 flow_tuple->iifidx = other_dst->dev->ifindex;
52 + flow_tuple->xmit_type = route->tuple[dir].xmit_type;
53 flow_tuple->dst_cache = dst;
54
55 return 0;
56 --- a/net/netfilter/nf_flow_table_ip.c
57 +++ b/net/netfilter/nf_flow_table_ip.c
58 @@ -220,10 +220,20 @@ static bool nf_flow_exceeds_mtu(const st
59 return true;
60 }
61
62 -static int nf_flow_offload_dst_check(struct dst_entry *dst)
63 +static inline struct dst_entry *
64 +nft_flow_dst(struct flow_offload_tuple_rhash *tuplehash)
65 {
66 - if (unlikely(dst_xfrm(dst)))
67 + return tuplehash->tuple.dst_cache;
68 +}
69 +
70 +static int nf_flow_offload_dst_check(struct flow_offload_tuple_rhash *tuplehash)
71 +{
72 + struct dst_entry *dst;
73 +
74 + if (unlikely(tuplehash->tuple.xmit_type == FLOW_OFFLOAD_XMIT_XFRM)) {
75 + dst = nft_flow_dst(tuplehash);
76 return dst_check(dst, 0) ? 0 : -1;
77 + }
78
79 return 0;
80 }
81 @@ -265,8 +275,6 @@ nf_flow_offload_ip_hook(void *priv, stru
82
83 dir = tuplehash->tuple.dir;
84 flow = container_of(tuplehash, struct flow_offload, tuplehash[dir]);
85 - rt = (struct rtable *)flow->tuplehash[dir].tuple.dst_cache;
86 - outdev = rt->dst.dev;
87
88 if (unlikely(nf_flow_exceeds_mtu(skb, flow->tuplehash[dir].tuple.mtu)))
89 return NF_ACCEPT;
90 @@ -280,7 +288,7 @@ nf_flow_offload_ip_hook(void *priv, stru
91
92 flow_offload_refresh(flow_table, flow);
93
94 - if (nf_flow_offload_dst_check(&rt->dst)) {
95 + if (nf_flow_offload_dst_check(tuplehash)) {
96 flow_offload_teardown(flow);
97 return NF_ACCEPT;
98 }
99 @@ -295,13 +303,16 @@ nf_flow_offload_ip_hook(void *priv, stru
100 if (flow_table->flags & NF_FLOWTABLE_COUNTER)
101 nf_ct_acct_update(flow->ct, tuplehash->tuple.dir, skb->len);
102
103 - if (unlikely(dst_xfrm(&rt->dst))) {
104 + rt = (struct rtable *)tuplehash->tuple.dst_cache;
105 +
106 + if (unlikely(tuplehash->tuple.xmit_type == FLOW_OFFLOAD_XMIT_XFRM)) {
107 memset(skb->cb, 0, sizeof(struct inet_skb_parm));
108 IPCB(skb)->iif = skb->dev->ifindex;
109 IPCB(skb)->flags = IPSKB_FORWARDED;
110 return nf_flow_xmit_xfrm(skb, state, &rt->dst);
111 }
112
113 + outdev = rt->dst.dev;
114 skb->dev = outdev;
115 nexthop = rt_nexthop(rt, flow->tuplehash[!dir].tuple.src_v4.s_addr);
116 skb_dst_set_noref(skb, &rt->dst);
117 @@ -506,8 +517,6 @@ nf_flow_offload_ipv6_hook(void *priv, st
118
119 dir = tuplehash->tuple.dir;
120 flow = container_of(tuplehash, struct flow_offload, tuplehash[dir]);
121 - rt = (struct rt6_info *)flow->tuplehash[dir].tuple.dst_cache;
122 - outdev = rt->dst.dev;
123
124 if (unlikely(nf_flow_exceeds_mtu(skb, flow->tuplehash[dir].tuple.mtu)))
125 return NF_ACCEPT;
126 @@ -518,7 +527,7 @@ nf_flow_offload_ipv6_hook(void *priv, st
127
128 flow_offload_refresh(flow_table, flow);
129
130 - if (nf_flow_offload_dst_check(&rt->dst)) {
131 + if (nf_flow_offload_dst_check(tuplehash)) {
132 flow_offload_teardown(flow);
133 return NF_ACCEPT;
134 }
135 @@ -536,13 +545,16 @@ nf_flow_offload_ipv6_hook(void *priv, st
136 if (flow_table->flags & NF_FLOWTABLE_COUNTER)
137 nf_ct_acct_update(flow->ct, tuplehash->tuple.dir, skb->len);
138
139 - if (unlikely(dst_xfrm(&rt->dst))) {
140 + rt = (struct rt6_info *)tuplehash->tuple.dst_cache;
141 +
142 + if (unlikely(tuplehash->tuple.xmit_type == FLOW_OFFLOAD_XMIT_XFRM)) {
143 memset(skb->cb, 0, sizeof(struct inet6_skb_parm));
144 IP6CB(skb)->iif = skb->dev->ifindex;
145 IP6CB(skb)->flags = IP6SKB_FORWARDED;
146 return nf_flow_xmit_xfrm(skb, state, &rt->dst);
147 }
148
149 + outdev = rt->dst.dev;
150 skb->dev = outdev;
151 nexthop = rt6_nexthop(rt, &flow->tuplehash[!dir].tuple.src_v6);
152 skb_dst_set_noref(skb, &rt->dst);
153 --- a/net/netfilter/nft_flow_offload.c
154 +++ b/net/netfilter/nft_flow_offload.c
155 @@ -19,6 +19,22 @@ struct nft_flow_offload {
156 struct nft_flowtable *flowtable;
157 };
158
159 +static enum flow_offload_xmit_type nft_xmit_type(struct dst_entry *dst)
160 +{
161 + if (dst_xfrm(dst))
162 + return FLOW_OFFLOAD_XMIT_XFRM;
163 +
164 + return FLOW_OFFLOAD_XMIT_NEIGH;
165 +}
166 +
167 +static void nft_default_forward_path(struct nf_flow_route *route,
168 + struct dst_entry *dst_cache,
169 + enum ip_conntrack_dir dir)
170 +{
171 + route->tuple[dir].dst = dst_cache;
172 + route->tuple[dir].xmit_type = nft_xmit_type(dst_cache);
173 +}
174 +
175 static int nft_flow_route(const struct nft_pktinfo *pkt,
176 const struct nf_conn *ct,
177 struct nf_flow_route *route,
178 @@ -44,8 +60,8 @@ static int nft_flow_route(const struct n
179 if (!other_dst)
180 return -ENOENT;
181
182 - route->tuple[dir].dst = this_dst;
183 - route->tuple[!dir].dst = other_dst;
184 + nft_default_forward_path(route, this_dst, dir);
185 + nft_default_forward_path(route, other_dst, !dir);
186
187 return 0;
188 }