fe60a7903669908e218e0ae3dfef023023e1fa3d
[openwrt/staging/stintel.git] /
1 From: Pablo Neira Ayuso <pablo@netfilter.org>
2 Date: Mon, 27 Nov 2017 22:29:52 +0100
3 Subject: [PATCH] netfilter: move route indirection to struct nf_ipv6_ops
4
5 We cannot make a direct call to nf_ip6_route() because that would result
6 in autoloading the 'ipv6' module because of symbol dependencies.
7 Therefore, define route indirection in nf_ipv6_ops where this really
8 belongs to.
9
10 For IPv4, we can indeed make a direct function call, which is faster,
11 given IPv4 is built-in in the networking code by default. Still,
12 CONFIG_INET=n and CONFIG_NETFILTER=y is possible, so define empty inline
13 stub for IPv4 in such case.
14
15 Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
16 ---
17
18 --- a/include/linux/netfilter.h
19 +++ b/include/linux/netfilter.h
20 @@ -274,8 +274,6 @@ struct nf_queue_entry;
21
22 struct nf_afinfo {
23 unsigned short family;
24 - int (*route)(struct net *net, struct dst_entry **dst,
25 - struct flowi *fl, bool strict);
26 int (*reroute)(struct net *net, struct sk_buff *skb,
27 const struct nf_queue_entry *entry);
28 int route_key_size;
29 @@ -294,6 +292,8 @@ __sum16 nf_checksum(struct sk_buff *skb,
30 __sum16 nf_checksum_partial(struct sk_buff *skb, unsigned int hook,
31 unsigned int dataoff, unsigned int len,
32 u_int8_t protocol, unsigned short family);
33 +int nf_route(struct net *net, struct dst_entry **dst, struct flowi *fl,
34 + bool strict, unsigned short family);
35
36 int nf_register_afinfo(const struct nf_afinfo *afinfo);
37 void nf_unregister_afinfo(const struct nf_afinfo *afinfo);
38 --- a/include/linux/netfilter_ipv4.h
39 +++ b/include/linux/netfilter_ipv4.h
40 @@ -24,6 +24,8 @@ __sum16 nf_ip_checksum(struct sk_buff *s
41 __sum16 nf_ip_checksum_partial(struct sk_buff *skb, unsigned int hook,
42 unsigned int dataoff, unsigned int len,
43 u_int8_t protocol);
44 +int nf_ip_route(struct net *net, struct dst_entry **dst, struct flowi *fl,
45 + bool strict);
46 #else
47 static inline __sum16 nf_ip_checksum(struct sk_buff *skb, unsigned int hook,
48 unsigned int dataoff, u_int8_t protocol)
49 @@ -38,6 +40,11 @@ static inline __sum16 nf_ip_checksum_par
50 {
51 return 0;
52 }
53 +static inline int nf_ip_route(struct net *net, struct dst_entry **dst,
54 + struct flowi *fl, bool strict)
55 +{
56 + return -EOPNOTSUPP;
57 +}
58 #endif /* CONFIG_INET */
59
60 #endif /*__LINUX_IP_NETFILTER_H*/
61 --- a/include/linux/netfilter_ipv6.h
62 +++ b/include/linux/netfilter_ipv6.h
63 @@ -33,6 +33,8 @@ struct nf_ipv6_ops {
64 __sum16 (*checksum_partial)(struct sk_buff *skb, unsigned int hook,
65 unsigned int dataoff, unsigned int len,
66 u_int8_t protocol);
67 + int (*route)(struct net *net, struct dst_entry **dst, struct flowi *fl,
68 + bool strict);
69 };
70
71 #ifdef CONFIG_NETFILTER
72 --- a/net/bridge/netfilter/nf_tables_bridge.c
73 +++ b/net/bridge/netfilter/nf_tables_bridge.c
74 @@ -101,15 +101,8 @@ static int nf_br_reroute(struct net *net
75 return 0;
76 }
77
78 -static int nf_br_route(struct net *net, struct dst_entry **dst,
79 - struct flowi *fl, bool strict __always_unused)
80 -{
81 - return 0;
82 -}
83 -
84 static const struct nf_afinfo nf_br_afinfo = {
85 .family = AF_BRIDGE,
86 - .route = nf_br_route,
87 .reroute = nf_br_reroute,
88 .route_key_size = 0,
89 };
90 --- a/net/ipv4/netfilter.c
91 +++ b/net/ipv4/netfilter.c
92 @@ -150,8 +150,8 @@ __sum16 nf_ip_checksum_partial(struct sk
93 }
94 EXPORT_SYMBOL_GPL(nf_ip_checksum_partial);
95
96 -static int nf_ip_route(struct net *net, struct dst_entry **dst,
97 - struct flowi *fl, bool strict __always_unused)
98 +int nf_ip_route(struct net *net, struct dst_entry **dst, struct flowi *fl,
99 + bool strict __always_unused)
100 {
101 struct rtable *rt = ip_route_output_key(net, &fl->u.ip4);
102 if (IS_ERR(rt))
103 @@ -159,10 +159,10 @@ static int nf_ip_route(struct net *net,
104 *dst = &rt->dst;
105 return 0;
106 }
107 +EXPORT_SYMBOL_GPL(nf_ip_route);
108
109 static const struct nf_afinfo nf_ip_afinfo = {
110 .family = AF_INET,
111 - .route = nf_ip_route,
112 .reroute = nf_ip_reroute,
113 .route_key_size = sizeof(struct ip_rt_info),
114 };
115 --- a/net/ipv6/netfilter.c
116 +++ b/net/ipv6/netfilter.c
117 @@ -171,11 +171,11 @@ static const struct nf_ipv6_ops ipv6ops
118 .fragment = ip6_fragment,
119 .checksum = nf_ip6_checksum,
120 .checksum_partial = nf_ip6_checksum_partial,
121 + .route = nf_ip6_route,
122 };
123
124 static const struct nf_afinfo nf_ip6_afinfo = {
125 .family = AF_INET6,
126 - .route = nf_ip6_route,
127 .reroute = nf_ip6_reroute,
128 .route_key_size = sizeof(struct ip6_rt_info),
129 };
130 --- a/net/ipv6/netfilter/nft_fib_ipv6.c
131 +++ b/net/ipv6/netfilter/nft_fib_ipv6.c
132 @@ -60,7 +60,6 @@ static u32 __nft_fib6_eval_type(const st
133 {
134 const struct net_device *dev = NULL;
135 const struct nf_ipv6_ops *v6ops;
136 - const struct nf_afinfo *afinfo;
137 int route_err, addrtype;
138 struct rt6_info *rt;
139 struct flowi6 fl6 = {
140 @@ -69,8 +68,8 @@ static u32 __nft_fib6_eval_type(const st
141 };
142 u32 ret = 0;
143
144 - afinfo = nf_get_afinfo(NFPROTO_IPV6);
145 - if (!afinfo)
146 + v6ops = nf_get_ipv6_ops();
147 + if (!v6ops)
148 return RTN_UNREACHABLE;
149
150 if (priv->flags & NFTA_FIB_F_IIF)
151 @@ -80,12 +79,11 @@ static u32 __nft_fib6_eval_type(const st
152
153 nft_fib6_flowi_init(&fl6, priv, pkt, dev, iph);
154
155 - v6ops = nf_get_ipv6_ops();
156 - if (dev && v6ops && v6ops->chk_addr(nft_net(pkt), &fl6.daddr, dev, true))
157 + if (dev && v6ops->chk_addr(nft_net(pkt), &fl6.daddr, dev, true))
158 ret = RTN_LOCAL;
159
160 - route_err = afinfo->route(nft_net(pkt), (struct dst_entry **)&rt,
161 - flowi6_to_flowi(&fl6), false);
162 + route_err = v6ops->route(nft_net(pkt), (struct dst_entry **)&rt,
163 + flowi6_to_flowi(&fl6), false);
164 if (route_err)
165 goto err;
166
167 --- a/net/netfilter/nf_conntrack_h323_main.c
168 +++ b/net/netfilter/nf_conntrack_h323_main.c
169 @@ -24,6 +24,7 @@
170 #include <linux/skbuff.h>
171 #include <net/route.h>
172 #include <net/ip6_route.h>
173 +#include <linux/netfilter_ipv6.h>
174
175 #include <net/netfilter/nf_conntrack.h>
176 #include <net/netfilter/nf_conntrack_core.h>
177 @@ -732,14 +733,8 @@ static int callforward_do_filter(struct
178 const union nf_inet_addr *dst,
179 u_int8_t family)
180 {
181 - const struct nf_afinfo *afinfo;
182 int ret = 0;
183
184 - /* rcu_read_lock()ed by nf_hook_thresh */
185 - afinfo = nf_get_afinfo(family);
186 - if (!afinfo)
187 - return 0;
188 -
189 switch (family) {
190 case AF_INET: {
191 struct flowi4 fl1, fl2;
192 @@ -750,10 +745,10 @@ static int callforward_do_filter(struct
193
194 memset(&fl2, 0, sizeof(fl2));
195 fl2.daddr = dst->ip;
196 - if (!afinfo->route(net, (struct dst_entry **)&rt1,
197 - flowi4_to_flowi(&fl1), false)) {
198 - if (!afinfo->route(net, (struct dst_entry **)&rt2,
199 - flowi4_to_flowi(&fl2), false)) {
200 + if (!nf_ip_route(net, (struct dst_entry **)&rt1,
201 + flowi4_to_flowi(&fl1), false)) {
202 + if (!nf_ip_route(net, (struct dst_entry **)&rt2,
203 + flowi4_to_flowi(&fl2), false)) {
204 if (rt_nexthop(rt1, fl1.daddr) ==
205 rt_nexthop(rt2, fl2.daddr) &&
206 rt1->dst.dev == rt2->dst.dev)
207 @@ -766,18 +761,23 @@ static int callforward_do_filter(struct
208 }
209 #if IS_ENABLED(CONFIG_NF_CONNTRACK_IPV6)
210 case AF_INET6: {
211 - struct flowi6 fl1, fl2;
212 + const struct nf_ipv6_ops *v6ops;
213 struct rt6_info *rt1, *rt2;
214 + struct flowi6 fl1, fl2;
215 +
216 + v6ops = nf_get_ipv6_ops();
217 + if (!v6ops)
218 + return 0;
219
220 memset(&fl1, 0, sizeof(fl1));
221 fl1.daddr = src->in6;
222
223 memset(&fl2, 0, sizeof(fl2));
224 fl2.daddr = dst->in6;
225 - if (!afinfo->route(net, (struct dst_entry **)&rt1,
226 - flowi6_to_flowi(&fl1), false)) {
227 - if (!afinfo->route(net, (struct dst_entry **)&rt2,
228 - flowi6_to_flowi(&fl2), false)) {
229 + if (!v6ops->route(net, (struct dst_entry **)&rt1,
230 + flowi6_to_flowi(&fl1), false)) {
231 + if (!v6ops->route(net, (struct dst_entry **)&rt2,
232 + flowi6_to_flowi(&fl2), false)) {
233 if (ipv6_addr_equal(rt6_nexthop(rt1, &fl1.daddr),
234 rt6_nexthop(rt2, &fl2.daddr)) &&
235 rt1->dst.dev == rt2->dst.dev)
236 --- a/net/netfilter/nft_rt.c
237 +++ b/net/netfilter/nft_rt.c
238 @@ -27,7 +27,7 @@ static u16 get_tcpmss(const struct nft_p
239 {
240 u32 minlen = sizeof(struct ipv6hdr), mtu = dst_mtu(skbdst);
241 const struct sk_buff *skb = pkt->skb;
242 - const struct nf_afinfo *ai;
243 + struct dst_entry *dst = NULL;
244 struct flowi fl;
245
246 memset(&fl, 0, sizeof(fl));
247 @@ -43,15 +43,10 @@ static u16 get_tcpmss(const struct nft_p
248 break;
249 }
250
251 - ai = nf_get_afinfo(nft_pf(pkt));
252 - if (ai) {
253 - struct dst_entry *dst = NULL;
254 -
255 - ai->route(nft_net(pkt), &dst, &fl, false);
256 - if (dst) {
257 - mtu = min(mtu, dst_mtu(dst));
258 - dst_release(dst);
259 - }
260 + nf_route(nft_net(pkt), &dst, &fl, false, nft_pf(pkt));
261 + if (dst) {
262 + mtu = min(mtu, dst_mtu(dst));
263 + dst_release(dst);
264 }
265
266 if (mtu <= minlen || mtu > 0xffff)
267 --- a/net/netfilter/utils.c
268 +++ b/net/netfilter/utils.c
269 @@ -48,3 +48,24 @@ __sum16 nf_checksum_partial(struct sk_bu
270 return csum;
271 }
272 EXPORT_SYMBOL_GPL(nf_checksum_partial);
273 +
274 +int nf_route(struct net *net, struct dst_entry **dst, struct flowi *fl,
275 + bool strict, unsigned short family)
276 +{
277 + const struct nf_ipv6_ops *v6ops;
278 + int ret = 0;
279 +
280 + switch (family) {
281 + case AF_INET:
282 + ret = nf_ip_route(net, dst, fl, strict);
283 + break;
284 + case AF_INET6:
285 + v6ops = rcu_dereference(nf_ipv6_ops);
286 + if (v6ops)
287 + ret = v6ops->route(net, dst, fl, strict);
288 + break;
289 + }
290 +
291 + return ret;
292 +}
293 +EXPORT_SYMBOL_GPL(nf_route);
294 --- a/net/netfilter/xt_TCPMSS.c
295 +++ b/net/netfilter/xt_TCPMSS.c
296 @@ -48,7 +48,6 @@ static u_int32_t tcpmss_reverse_mtu(stru
297 unsigned int family)
298 {
299 struct flowi fl;
300 - const struct nf_afinfo *ai;
301 struct rtable *rt = NULL;
302 u_int32_t mtu = ~0U;
303
304 @@ -62,10 +61,8 @@ static u_int32_t tcpmss_reverse_mtu(stru
305 memset(fl6, 0, sizeof(*fl6));
306 fl6->daddr = ipv6_hdr(skb)->saddr;
307 }
308 - ai = nf_get_afinfo(family);
309 - if (ai != NULL)
310 - ai->route(net, (struct dst_entry **)&rt, &fl, false);
311
312 + nf_route(net, (struct dst_entry **)&rt, &fl, false, family);
313 if (rt != NULL) {
314 mtu = dst_mtu(&rt->dst);
315 dst_release(&rt->dst);
316 --- a/net/netfilter/xt_addrtype.c
317 +++ b/net/netfilter/xt_addrtype.c
318 @@ -36,7 +36,7 @@ MODULE_ALIAS("ip6t_addrtype");
319 static u32 match_lookup_rt6(struct net *net, const struct net_device *dev,
320 const struct in6_addr *addr, u16 mask)
321 {
322 - const struct nf_afinfo *afinfo;
323 + const struct nf_ipv6_ops *v6ops;
324 struct flowi6 flow;
325 struct rt6_info *rt;
326 u32 ret = 0;
327 @@ -47,17 +47,14 @@ static u32 match_lookup_rt6(struct net *
328 if (dev)
329 flow.flowi6_oif = dev->ifindex;
330
331 - afinfo = nf_get_afinfo(NFPROTO_IPV6);
332 - if (afinfo != NULL) {
333 - const struct nf_ipv6_ops *v6ops;
334 -
335 + v6ops = nf_get_ipv6_ops();
336 + if (v6ops) {
337 if (dev && (mask & XT_ADDRTYPE_LOCAL)) {
338 - v6ops = nf_get_ipv6_ops();
339 - if (v6ops && v6ops->chk_addr(net, addr, dev, true))
340 + if (v6ops->chk_addr(net, addr, dev, true))
341 ret = XT_ADDRTYPE_LOCAL;
342 }
343 - route_err = afinfo->route(net, (struct dst_entry **)&rt,
344 - flowi6_to_flowi(&flow), false);
345 + route_err = v6ops->route(net, (struct dst_entry **)&rt,
346 + flowi6_to_flowi(&flow), false);
347 } else {
348 route_err = 1;
349 }