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
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
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.
15 Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
18 --- a/include/linux/netfilter.h
19 +++ b/include/linux/netfilter.h
20 @@ -274,8 +274,6 @@ struct nf_queue_entry;
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);
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);
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,
44 +int nf_ip_route(struct net *net, struct dst_entry **dst, struct flowi *fl,
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
53 +static inline int nf_ip_route(struct net *net, struct dst_entry **dst,
54 + struct flowi *fl, bool strict)
58 #endif /* CONFIG_INET */
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,
67 + int (*route)(struct net *net, struct dst_entry **dst, struct flowi *fl,
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
78 -static int nf_br_route(struct net *net, struct dst_entry **dst,
79 - struct flowi *fl, bool strict __always_unused)
84 static const struct nf_afinfo nf_br_afinfo = {
86 - .route = nf_br_route,
87 .reroute = nf_br_reroute,
90 --- a/net/ipv4/netfilter.c
91 +++ b/net/ipv4/netfilter.c
92 @@ -150,8 +150,8 @@ __sum16 nf_ip_checksum_partial(struct sk
94 EXPORT_SYMBOL_GPL(nf_ip_checksum_partial);
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)
101 struct rtable *rt = ip_route_output_key(net, &fl->u.ip4);
103 @@ -159,10 +159,10 @@ static int nf_ip_route(struct net *net,
107 +EXPORT_SYMBOL_GPL(nf_ip_route);
109 static const struct nf_afinfo nf_ip_afinfo = {
111 - .route = nf_ip_route,
112 .reroute = nf_ip_reroute,
113 .route_key_size = sizeof(struct ip_rt_info),
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,
124 static const struct nf_afinfo nf_ip6_afinfo = {
126 - .route = nf_ip6_route,
127 .reroute = nf_ip6_reroute,
128 .route_key_size = sizeof(struct ip6_rt_info),
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
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;
139 struct flowi6 fl6 = {
140 @@ -69,8 +68,8 @@ static u32 __nft_fib6_eval_type(const st
144 - afinfo = nf_get_afinfo(NFPROTO_IPV6);
146 + v6ops = nf_get_ipv6_ops();
148 return RTN_UNREACHABLE;
150 if (priv->flags & NFTA_FIB_F_IIF)
151 @@ -80,12 +79,11 @@ static u32 __nft_fib6_eval_type(const st
153 nft_fib6_flowi_init(&fl6, priv, pkt, dev, iph);
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))
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);
167 --- a/net/netfilter/nf_conntrack_h323_main.c
168 +++ b/net/netfilter/nf_conntrack_h323_main.c
170 #include <linux/skbuff.h>
171 #include <net/route.h>
172 #include <net/ip6_route.h>
173 +#include <linux/netfilter_ipv6.h>
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,
181 - const struct nf_afinfo *afinfo;
184 - /* rcu_read_lock()ed by nf_hook_thresh */
185 - afinfo = nf_get_afinfo(family);
191 struct flowi4 fl1, fl2;
192 @@ -750,10 +745,10 @@ static int callforward_do_filter(struct
194 memset(&fl2, 0, sizeof(fl2));
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
209 #if IS_ENABLED(CONFIG_NF_CONNTRACK_IPV6)
211 - struct flowi6 fl1, fl2;
212 + const struct nf_ipv6_ops *v6ops;
213 struct rt6_info *rt1, *rt2;
214 + struct flowi6 fl1, fl2;
216 + v6ops = nf_get_ipv6_ops();
220 memset(&fl1, 0, sizeof(fl1));
221 fl1.daddr = src->in6;
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
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;
246 memset(&fl, 0, sizeof(fl));
247 @@ -43,15 +43,10 @@ static u16 get_tcpmss(const struct nft_p
251 - ai = nf_get_afinfo(nft_pf(pkt));
253 - struct dst_entry *dst = NULL;
255 - ai->route(nft_net(pkt), &dst, &fl, false);
257 - mtu = min(mtu, dst_mtu(dst));
260 + nf_route(nft_net(pkt), &dst, &fl, false, nft_pf(pkt));
262 + mtu = min(mtu, dst_mtu(dst));
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
272 EXPORT_SYMBOL_GPL(nf_checksum_partial);
274 +int nf_route(struct net *net, struct dst_entry **dst, struct flowi *fl,
275 + bool strict, unsigned short family)
277 + const struct nf_ipv6_ops *v6ops;
282 + ret = nf_ip_route(net, dst, fl, strict);
285 + v6ops = rcu_dereference(nf_ipv6_ops);
287 + ret = v6ops->route(net, dst, fl, strict);
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
300 - const struct nf_afinfo *ai;
301 struct rtable *rt = NULL;
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;
308 - ai = nf_get_afinfo(family);
310 - ai->route(net, (struct dst_entry **)&rt, &fl, false);
312 + nf_route(net, (struct dst_entry **)&rt, &fl, false, family);
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)
322 - const struct nf_afinfo *afinfo;
323 + const struct nf_ipv6_ops *v6ops;
327 @@ -47,17 +47,14 @@ static u32 match_lookup_rt6(struct net *
329 flow.flowi6_oif = dev->ifindex;
331 - afinfo = nf_get_afinfo(NFPROTO_IPV6);
332 - if (afinfo != NULL) {
333 - const struct nf_ipv6_ops *v6ops;
335 + v6ops = nf_get_ipv6_ops();
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;
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);