Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ipv6: Kill ipv6 dependency of icmpv6_send().

Following patch adds icmp-registration module for ipv6. It allows
ipv6 protocol to register icmp_sender which is used for sending
ipv6 icmp msgs. This extra layer allows us to kill ipv6 dependency
for sending icmp packets.

This patch also fixes ip_tunnel compilation problem when ip_tunnel
is statically compiled in kernel but ipv6 is module

Signed-off-by: Pravin B Shelar <pshelar@nicira.com>
Acked-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Pravin B Shelar and committed by
David S. Miller
5f5624cf a4c4009f

+83 -19
+15 -3
include/linux/icmpv6.h
··· 11 11 12 12 #include <linux/netdevice.h> 13 13 14 - extern void icmpv6_send(struct sk_buff *skb, 15 - u8 type, u8 code, 16 - __u32 info); 14 + #if IS_ENABLED(CONFIG_IPV6) 15 + extern void icmpv6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info); 16 + 17 + typedef void ip6_icmp_send_t(struct sk_buff *skb, u8 type, u8 code, __u32 info); 18 + extern int inet6_register_icmp_sender(ip6_icmp_send_t *fn); 19 + extern int inet6_unregister_icmp_sender(ip6_icmp_send_t *fn); 20 + 21 + #else 22 + 23 + static inline void icmpv6_send(struct sk_buff *skb, 24 + u8 type, u8 code, __u32 info) 25 + { 26 + 27 + } 28 + #endif 17 29 18 30 extern int icmpv6_init(void); 19 31 extern int icmpv6_err_convert(u8 type, u8 code,
+1 -1
net/ipv6/Makefile
··· 40 40 obj-$(CONFIG_IPV6_TUNNEL) += ip6_tunnel.o 41 41 obj-$(CONFIG_IPV6_GRE) += ip6_gre.o 42 42 43 - obj-y += addrconf_core.o exthdrs_core.o ip6_checksum.o 43 + obj-y += addrconf_core.o exthdrs_core.o ip6_checksum.o ip6_icmp.o 44 44 obj-$(CONFIG_INET) += output_core.o protocol.o $(ipv6-offload) 45 45 46 46 obj-$(subst m,y,$(CONFIG_IPV6)) += inet6_hashtables.o
+20 -15
net/ipv6/icmp.c
··· 124 124 } 125 125 126 126 /* 127 - * Slightly more convenient version of icmpv6_send. 128 - */ 129 - void icmpv6_param_prob(struct sk_buff *skb, u8 code, int pos) 130 - { 131 - icmpv6_send(skb, ICMPV6_PARAMPROB, code, pos); 132 - kfree_skb(skb); 133 - } 134 - 135 - /* 136 127 * Figure out, may we reply to this packet with icmp error. 137 128 * 138 129 * We do not reply, if: ··· 323 332 * anycast. 324 333 */ 325 334 if (((struct rt6_info *)dst)->rt6i_flags & RTF_ANYCAST) { 326 - LIMIT_NETDEBUG(KERN_DEBUG "icmpv6_send: acast source\n"); 335 + LIMIT_NETDEBUG(KERN_DEBUG "icmp6_send: acast source\n"); 327 336 dst_release(dst); 328 337 return ERR_PTR(-EINVAL); 329 338 } ··· 372 381 /* 373 382 * Send an ICMP message in response to a packet in error 374 383 */ 375 - void icmpv6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info) 384 + static void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info) 376 385 { 377 386 struct net *net = dev_net(skb->dev); 378 387 struct inet6_dev *idev = NULL; ··· 397 406 /* 398 407 * Make sure we respect the rules 399 408 * i.e. RFC 1885 2.4(e) 400 - * Rule (e.1) is enforced by not using icmpv6_send 409 + * Rule (e.1) is enforced by not using icmp6_send 401 410 * in any code that processes icmp errors. 402 411 */ 403 412 addr_type = ipv6_addr_type(&hdr->daddr); ··· 435 444 * and anycast addresses will be checked later. 436 445 */ 437 446 if ((addr_type == IPV6_ADDR_ANY) || (addr_type & IPV6_ADDR_MULTICAST)) { 438 - LIMIT_NETDEBUG(KERN_DEBUG "icmpv6_send: addr_any/mcast source\n"); 447 + LIMIT_NETDEBUG(KERN_DEBUG "icmp6_send: addr_any/mcast source\n"); 439 448 return; 440 449 } 441 450 ··· 443 452 * Never answer to a ICMP packet. 444 453 */ 445 454 if (is_ineligible(skb)) { 446 - LIMIT_NETDEBUG(KERN_DEBUG "icmpv6_send: no reply to icmp error\n"); 455 + LIMIT_NETDEBUG(KERN_DEBUG "icmp6_send: no reply to icmp error\n"); 447 456 return; 448 457 } 449 458 ··· 520 529 out: 521 530 icmpv6_xmit_unlock(sk); 522 531 } 523 - EXPORT_SYMBOL(icmpv6_send); 532 + 533 + /* Slightly more convenient version of icmp6_send. 534 + */ 535 + void icmpv6_param_prob(struct sk_buff *skb, u8 code, int pos) 536 + { 537 + icmp6_send(skb, ICMPV6_PARAMPROB, code, pos); 538 + kfree_skb(skb); 539 + } 524 540 525 541 static void icmpv6_echo_reply(struct sk_buff *skb) 526 542 { ··· 883 885 err = -EAGAIN; 884 886 if (inet6_add_protocol(&icmpv6_protocol, IPPROTO_ICMPV6) < 0) 885 887 goto fail; 888 + 889 + err = inet6_register_icmp_sender(icmp6_send); 890 + if (err) 891 + goto sender_reg_err; 886 892 return 0; 887 893 894 + sender_reg_err: 895 + inet6_del_protocol(&icmpv6_protocol, IPPROTO_ICMPV6); 888 896 fail: 889 897 pr_err("Failed to register ICMP6 protocol\n"); 890 898 unregister_pernet_subsys(&icmpv6_sk_ops); ··· 899 895 900 896 void icmpv6_cleanup(void) 901 897 { 898 + inet6_unregister_icmp_sender(icmp6_send); 902 899 unregister_pernet_subsys(&icmpv6_sk_ops); 903 900 inet6_del_protocol(&icmpv6_protocol, IPPROTO_ICMPV6); 904 901 }
+47
net/ipv6/ip6_icmp.c
··· 1 + #include <linux/export.h> 2 + #include <linux/icmpv6.h> 3 + #include <linux/mutex.h> 4 + #include <linux/netdevice.h> 5 + #include <linux/spinlock.h> 6 + 7 + #include <net/ipv6.h> 8 + 9 + #if IS_ENABLED(CONFIG_IPV6) 10 + 11 + static ip6_icmp_send_t __rcu *ip6_icmp_send; 12 + 13 + int inet6_register_icmp_sender(ip6_icmp_send_t *fn) 14 + { 15 + return (cmpxchg((ip6_icmp_send_t **)&ip6_icmp_send, NULL, fn) == NULL) ? 16 + 0 : -EBUSY; 17 + } 18 + EXPORT_SYMBOL(inet6_register_icmp_sender); 19 + 20 + int inet6_unregister_icmp_sender(ip6_icmp_send_t *fn) 21 + { 22 + int ret; 23 + 24 + ret = (cmpxchg((ip6_icmp_send_t **)&ip6_icmp_send, fn, NULL) == fn) ? 25 + 0 : -EINVAL; 26 + 27 + synchronize_net(); 28 + 29 + return ret; 30 + } 31 + EXPORT_SYMBOL(inet6_unregister_icmp_sender); 32 + 33 + void icmpv6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info) 34 + { 35 + ip6_icmp_send_t *send; 36 + 37 + rcu_read_lock(); 38 + send = rcu_dereference(ip6_icmp_send); 39 + 40 + if (!send) 41 + goto out; 42 + send(skb, type, code, info); 43 + out: 44 + rcu_read_unlock(); 45 + } 46 + EXPORT_SYMBOL(icmpv6_send); 47 + #endif