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>
This commit is contained in:
parent
a4c4009f4f
commit
5f5624cf15
@ -11,9 +11,21 @@ static inline struct icmp6hdr *icmp6_hdr(const struct sk_buff *skb)
|
||||
|
||||
#include <linux/netdevice.h>
|
||||
|
||||
extern void icmpv6_send(struct sk_buff *skb,
|
||||
u8 type, u8 code,
|
||||
__u32 info);
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
extern void icmpv6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info);
|
||||
|
||||
typedef void ip6_icmp_send_t(struct sk_buff *skb, u8 type, u8 code, __u32 info);
|
||||
extern int inet6_register_icmp_sender(ip6_icmp_send_t *fn);
|
||||
extern int inet6_unregister_icmp_sender(ip6_icmp_send_t *fn);
|
||||
|
||||
#else
|
||||
|
||||
static inline void icmpv6_send(struct sk_buff *skb,
|
||||
u8 type, u8 code, __u32 info)
|
||||
{
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
extern int icmpv6_init(void);
|
||||
extern int icmpv6_err_convert(u8 type, u8 code,
|
||||
|
@ -40,7 +40,7 @@ obj-$(CONFIG_IPV6_SIT) += sit.o
|
||||
obj-$(CONFIG_IPV6_TUNNEL) += ip6_tunnel.o
|
||||
obj-$(CONFIG_IPV6_GRE) += ip6_gre.o
|
||||
|
||||
obj-y += addrconf_core.o exthdrs_core.o ip6_checksum.o
|
||||
obj-y += addrconf_core.o exthdrs_core.o ip6_checksum.o ip6_icmp.o
|
||||
obj-$(CONFIG_INET) += output_core.o protocol.o $(ipv6-offload)
|
||||
|
||||
obj-$(subst m,y,$(CONFIG_IPV6)) += inet6_hashtables.o
|
||||
|
@ -123,15 +123,6 @@ static __inline__ void icmpv6_xmit_unlock(struct sock *sk)
|
||||
spin_unlock_bh(&sk->sk_lock.slock);
|
||||
}
|
||||
|
||||
/*
|
||||
* Slightly more convenient version of icmpv6_send.
|
||||
*/
|
||||
void icmpv6_param_prob(struct sk_buff *skb, u8 code, int pos)
|
||||
{
|
||||
icmpv6_send(skb, ICMPV6_PARAMPROB, code, pos);
|
||||
kfree_skb(skb);
|
||||
}
|
||||
|
||||
/*
|
||||
* Figure out, may we reply to this packet with icmp error.
|
||||
*
|
||||
@ -332,7 +323,7 @@ static struct dst_entry *icmpv6_route_lookup(struct net *net, struct sk_buff *sk
|
||||
* anycast.
|
||||
*/
|
||||
if (((struct rt6_info *)dst)->rt6i_flags & RTF_ANYCAST) {
|
||||
LIMIT_NETDEBUG(KERN_DEBUG "icmpv6_send: acast source\n");
|
||||
LIMIT_NETDEBUG(KERN_DEBUG "icmp6_send: acast source\n");
|
||||
dst_release(dst);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
@ -381,7 +372,7 @@ relookup_failed:
|
||||
/*
|
||||
* Send an ICMP message in response to a packet in error
|
||||
*/
|
||||
void icmpv6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info)
|
||||
static void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info)
|
||||
{
|
||||
struct net *net = dev_net(skb->dev);
|
||||
struct inet6_dev *idev = NULL;
|
||||
@ -406,7 +397,7 @@ void icmpv6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info)
|
||||
/*
|
||||
* Make sure we respect the rules
|
||||
* i.e. RFC 1885 2.4(e)
|
||||
* Rule (e.1) is enforced by not using icmpv6_send
|
||||
* Rule (e.1) is enforced by not using icmp6_send
|
||||
* in any code that processes icmp errors.
|
||||
*/
|
||||
addr_type = ipv6_addr_type(&hdr->daddr);
|
||||
@ -444,7 +435,7 @@ void icmpv6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info)
|
||||
* and anycast addresses will be checked later.
|
||||
*/
|
||||
if ((addr_type == IPV6_ADDR_ANY) || (addr_type & IPV6_ADDR_MULTICAST)) {
|
||||
LIMIT_NETDEBUG(KERN_DEBUG "icmpv6_send: addr_any/mcast source\n");
|
||||
LIMIT_NETDEBUG(KERN_DEBUG "icmp6_send: addr_any/mcast source\n");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -452,7 +443,7 @@ void icmpv6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info)
|
||||
* Never answer to a ICMP packet.
|
||||
*/
|
||||
if (is_ineligible(skb)) {
|
||||
LIMIT_NETDEBUG(KERN_DEBUG "icmpv6_send: no reply to icmp error\n");
|
||||
LIMIT_NETDEBUG(KERN_DEBUG "icmp6_send: no reply to icmp error\n");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -529,7 +520,14 @@ out_dst_release:
|
||||
out:
|
||||
icmpv6_xmit_unlock(sk);
|
||||
}
|
||||
EXPORT_SYMBOL(icmpv6_send);
|
||||
|
||||
/* Slightly more convenient version of icmp6_send.
|
||||
*/
|
||||
void icmpv6_param_prob(struct sk_buff *skb, u8 code, int pos)
|
||||
{
|
||||
icmp6_send(skb, ICMPV6_PARAMPROB, code, pos);
|
||||
kfree_skb(skb);
|
||||
}
|
||||
|
||||
static void icmpv6_echo_reply(struct sk_buff *skb)
|
||||
{
|
||||
@ -885,8 +883,14 @@ int __init icmpv6_init(void)
|
||||
err = -EAGAIN;
|
||||
if (inet6_add_protocol(&icmpv6_protocol, IPPROTO_ICMPV6) < 0)
|
||||
goto fail;
|
||||
|
||||
err = inet6_register_icmp_sender(icmp6_send);
|
||||
if (err)
|
||||
goto sender_reg_err;
|
||||
return 0;
|
||||
|
||||
sender_reg_err:
|
||||
inet6_del_protocol(&icmpv6_protocol, IPPROTO_ICMPV6);
|
||||
fail:
|
||||
pr_err("Failed to register ICMP6 protocol\n");
|
||||
unregister_pernet_subsys(&icmpv6_sk_ops);
|
||||
@ -895,6 +899,7 @@ fail:
|
||||
|
||||
void icmpv6_cleanup(void)
|
||||
{
|
||||
inet6_unregister_icmp_sender(icmp6_send);
|
||||
unregister_pernet_subsys(&icmpv6_sk_ops);
|
||||
inet6_del_protocol(&icmpv6_protocol, IPPROTO_ICMPV6);
|
||||
}
|
||||
|
47
net/ipv6/ip6_icmp.c
Normal file
47
net/ipv6/ip6_icmp.c
Normal file
@ -0,0 +1,47 @@
|
||||
#include <linux/export.h>
|
||||
#include <linux/icmpv6.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
#include <net/ipv6.h>
|
||||
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
|
||||
static ip6_icmp_send_t __rcu *ip6_icmp_send;
|
||||
|
||||
int inet6_register_icmp_sender(ip6_icmp_send_t *fn)
|
||||
{
|
||||
return (cmpxchg((ip6_icmp_send_t **)&ip6_icmp_send, NULL, fn) == NULL) ?
|
||||
0 : -EBUSY;
|
||||
}
|
||||
EXPORT_SYMBOL(inet6_register_icmp_sender);
|
||||
|
||||
int inet6_unregister_icmp_sender(ip6_icmp_send_t *fn)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = (cmpxchg((ip6_icmp_send_t **)&ip6_icmp_send, fn, NULL) == fn) ?
|
||||
0 : -EINVAL;
|
||||
|
||||
synchronize_net();
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(inet6_unregister_icmp_sender);
|
||||
|
||||
void icmpv6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info)
|
||||
{
|
||||
ip6_icmp_send_t *send;
|
||||
|
||||
rcu_read_lock();
|
||||
send = rcu_dereference(ip6_icmp_send);
|
||||
|
||||
if (!send)
|
||||
goto out;
|
||||
send(skb, type, code, info);
|
||||
out:
|
||||
rcu_read_unlock();
|
||||
}
|
||||
EXPORT_SYMBOL(icmpv6_send);
|
||||
#endif
|
Loading…
x
Reference in New Issue
Block a user