From: Pablo Neira Ayuso Date: Wed, 20 Dec 2017 16:04:18 +0100 Subject: [PATCH] netfilter: move checksum_partial indirection to struct nf_ipv6_ops We cannot make a direct call to nf_ip6_checksum_partial() because that would result in autoloading the 'ipv6' module because of symbol dependencies. Therefore, define checksum_partial indirection in nf_ipv6_ops where this really belongs to. For IPv4, we can indeed make a direct function call, which is faster, given IPv4 is built-in in the networking code by default. Still, CONFIG_INET=n and CONFIG_NETFILTER=y is possible, so define empty inline stub for IPv4 in such case. Signed-off-by: Pablo Neira Ayuso --- --- a/include/linux/netfilter.h +++ b/include/linux/netfilter.h @@ -311,11 +311,6 @@ struct nf_queue_entry; struct nf_afinfo { unsigned short family; - __sum16 (*checksum_partial)(struct sk_buff *skb, - unsigned int hook, - unsigned int dataoff, - unsigned int len, - u_int8_t protocol); int (*route)(struct net *net, struct dst_entry **dst, struct flowi *fl, bool strict); void (*saveroute)(const struct sk_buff *skb, @@ -335,22 +330,9 @@ __sum16 nf_checksum(struct sk_buff *skb, unsigned int dataoff, u_int8_t protocol, unsigned short family); -static inline __sum16 -nf_checksum_partial(struct sk_buff *skb, unsigned int hook, - unsigned int dataoff, unsigned int len, - u_int8_t protocol, unsigned short family) -{ - const struct nf_afinfo *afinfo; - __sum16 csum = 0; - - rcu_read_lock(); - afinfo = nf_get_afinfo(family); - if (afinfo) - csum = afinfo->checksum_partial(skb, hook, dataoff, len, - protocol); - rcu_read_unlock(); - return csum; -} +__sum16 nf_checksum_partial(struct sk_buff *skb, unsigned int hook, + unsigned int dataoff, unsigned int len, + u_int8_t protocol, unsigned short family); int nf_register_afinfo(const struct nf_afinfo *afinfo); void nf_unregister_afinfo(const struct nf_afinfo *afinfo); --- a/include/linux/netfilter_ipv4.h +++ b/include/linux/netfilter_ipv4.h @@ -11,12 +11,23 @@ int ip_route_me_harder(struct net *net, #ifdef CONFIG_INET __sum16 nf_ip_checksum(struct sk_buff *skb, unsigned int hook, unsigned int dataoff, u_int8_t protocol); +__sum16 nf_ip_checksum_partial(struct sk_buff *skb, unsigned int hook, + unsigned int dataoff, unsigned int len, + u_int8_t protocol); #else static inline __sum16 nf_ip_checksum(struct sk_buff *skb, unsigned int hook, unsigned int dataoff, u_int8_t protocol) { return 0; } +static inline __sum16 nf_ip_checksum_partial(struct sk_buff *skb, + unsigned int hook, + unsigned int dataoff, + unsigned int len, + u_int8_t protocol) +{ + return 0; +} #endif /* CONFIG_INET */ #endif /*__LINUX_IP_NETFILTER_H*/ --- a/include/linux/netfilter_ipv6.h +++ b/include/linux/netfilter_ipv6.h @@ -21,6 +21,9 @@ struct nf_ipv6_ops { int (*output)(struct net *, struct sock *, struct sk_buff *)); __sum16 (*checksum)(struct sk_buff *skb, unsigned int hook, unsigned int dataoff, u_int8_t protocol); + __sum16 (*checksum_partial)(struct sk_buff *skb, unsigned int hook, + unsigned int dataoff, unsigned int len, + u_int8_t protocol); }; #ifdef CONFIG_NETFILTER --- a/net/bridge/netfilter/nf_tables_bridge.c +++ b/net/bridge/netfilter/nf_tables_bridge.c @@ -106,13 +106,6 @@ static int nf_br_reroute(struct net *net return 0; } -static __sum16 nf_br_checksum_partial(struct sk_buff *skb, unsigned int hook, - unsigned int dataoff, unsigned int len, - u_int8_t protocol) -{ - return 0; -} - static int nf_br_route(struct net *net, struct dst_entry **dst, struct flowi *fl, bool strict __always_unused) { @@ -121,7 +114,6 @@ static int nf_br_route(struct net *net, static const struct nf_afinfo nf_br_afinfo = { .family = AF_BRIDGE, - .checksum_partial = nf_br_checksum_partial, .route = nf_br_route, .saveroute = nf_br_saveroute, .reroute = nf_br_reroute, --- a/net/ipv4/netfilter.c +++ b/net/ipv4/netfilter.c @@ -155,9 +155,9 @@ __sum16 nf_ip_checksum(struct sk_buff *s } EXPORT_SYMBOL(nf_ip_checksum); -static __sum16 nf_ip_checksum_partial(struct sk_buff *skb, unsigned int hook, - unsigned int dataoff, unsigned int len, - u_int8_t protocol) +__sum16 nf_ip_checksum_partial(struct sk_buff *skb, unsigned int hook, + unsigned int dataoff, unsigned int len, + u_int8_t protocol) { const struct iphdr *iph = ip_hdr(skb); __sum16 csum = 0; @@ -175,6 +175,7 @@ static __sum16 nf_ip_checksum_partial(st } return csum; } +EXPORT_SYMBOL_GPL(nf_ip_checksum_partial); static int nf_ip_route(struct net *net, struct dst_entry **dst, struct flowi *fl, bool strict __always_unused) @@ -188,7 +189,6 @@ static int nf_ip_route(struct net *net, static const struct nf_afinfo nf_ip_afinfo = { .family = AF_INET, - .checksum_partial = nf_ip_checksum_partial, .route = nf_ip_route, .saveroute = nf_ip_saveroute, .reroute = nf_ip_reroute, --- a/net/ipv6/netfilter.c +++ b/net/ipv6/netfilter.c @@ -194,15 +194,15 @@ static __sum16 nf_ip6_checksum_partial(s }; static const struct nf_ipv6_ops ipv6ops = { - .chk_addr = ipv6_chk_addr, - .route_input = ip6_route_input, - .fragment = ip6_fragment, - .checksum = nf_ip6_checksum, + .chk_addr = ipv6_chk_addr, + .route_input = ip6_route_input, + .fragment = ip6_fragment, + .checksum = nf_ip6_checksum, + .checksum_partial = nf_ip6_checksum_partial, }; static const struct nf_afinfo nf_ip6_afinfo = { .family = AF_INET6, - .checksum_partial = nf_ip6_checksum_partial, .route = nf_ip6_route, .saveroute = nf_ip6_saveroute, .reroute = nf_ip6_reroute, --- a/net/netfilter/utils.c +++ b/net/netfilter/utils.c @@ -24,3 +24,27 @@ __sum16 nf_checksum(struct sk_buff *skb, return csum; } EXPORT_SYMBOL_GPL(nf_checksum); + +__sum16 nf_checksum_partial(struct sk_buff *skb, unsigned int hook, + unsigned int dataoff, unsigned int len, + u_int8_t protocol, unsigned short family) +{ + const struct nf_ipv6_ops *v6ops; + __sum16 csum = 0; + + switch (family) { + case AF_INET: + csum = nf_ip_checksum_partial(skb, hook, dataoff, len, + protocol); + break; + case AF_INET6: + v6ops = rcu_dereference(nf_ipv6_ops); + if (v6ops) + csum = v6ops->checksum_partial(skb, hook, dataoff, len, + protocol); + break; + } + + return csum; +} +EXPORT_SYMBOL_GPL(nf_checksum_partial);