*
* On SMP we have one ICMP socket per-cpu.
*/
-static DEFINE_PER_CPU(struct sock *, __icmp_sk) = NULL;
-#define icmp_sk __get_cpu_var(__icmp_sk)
+static struct sock *icmp_sk(struct net *net)
+{
+ return net->ipv4.icmp_sk[smp_processor_id()];
+}
static inline int icmp_xmit_lock(struct sock *sk)
{
struct sock *sk;
struct sk_buff *skb;
- sk = icmp_sk;
+ sk = icmp_sk(rt->u.dst.dev->nd_net);
if (ip_append_data(sk, icmp_glue_bits, icmp_param,
icmp_param->data_len+icmp_param->head_len,
icmp_param->head_len,
static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb)
{
- struct sock *sk = icmp_sk;
- struct inet_sock *inet = inet_sk(sk);
struct ipcm_cookie ipc;
- struct rtable *rt = (struct rtable *)skb->dst;
+ struct rtable *rt = skb->rtable;
+ struct net *net = rt->u.dst.dev->nd_net;
+ struct sock *sk = icmp_sk(net);
+ struct inet_sock *inet = inet_sk(sk);
__be32 daddr;
if (ip_options_echo(&icmp_param->replyopts, skb))
.tos = RT_TOS(ip_hdr(skb)->tos) } },
.proto = IPPROTO_ICMP };
security_skb_classify_flow(skb, &fl);
- if (ip_route_output_key(rt->u.dst.dev->nd_net, &rt, &fl))
+ if (ip_route_output_key(net, &rt, &fl))
goto out_unlock;
}
if (icmpv4_xrlim_allow(rt, icmp_param->data.icmph.type,
struct iphdr *iph;
int room;
struct icmp_bxm icmp_param;
- struct rtable *rt = (struct rtable *)skb_in->dst;
+ struct rtable *rt = skb_in->rtable;
struct ipcm_cookie ipc;
__be32 saddr;
u8 tos;
struct net *net;
- struct sock *sk = icmp_sk;
+ struct sock *sk;
if (!rt)
goto out;
net = rt->u.dst.dev->nd_net;
+ sk = icmp_sk(net);
/*
* Find the original header. It is expected to be valid, of course.
RT_TOS(tos), rt2->u.dst.dev);
dst_release(&rt2->u.dst);
- rt2 = (struct rtable *)skb_in->dst;
+ rt2 = skb_in->rtable;
skb_in->dst = odst;
}
static void icmp_address_reply(struct sk_buff *skb)
{
- struct rtable *rt = (struct rtable *)skb->dst;
+ struct rtable *rt = skb->rtable;
struct net_device *dev = skb->dev;
struct in_device *in_dev;
struct in_ifaddr *ifa;
int icmp_rcv(struct sk_buff *skb)
{
struct icmphdr *icmph;
- struct rtable *rt = (struct rtable *)skb->dst;
+ struct rtable *rt = skb->rtable;
if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) {
int nh;
},
};
-static void __exit icmp_exit(void)
+static void __net_exit icmp_sk_exit(struct net *net)
{
int i;
- for_each_possible_cpu(i) {
- struct sock *sk;
-
- sk = per_cpu(__icmp_sk, i);
- if (sk == NULL)
- continue;
- per_cpu(__icmp_sk, i) = NULL;
- sock_release(sk->sk_socket);
- }
+ for_each_possible_cpu(i)
+ sk_release_kernel(net->ipv4.icmp_sk[i]);
+ kfree(net->ipv4.icmp_sk);
+ net->ipv4.icmp_sk = NULL;
}
-int __init icmp_init(void)
+int __net_init icmp_sk_init(struct net *net)
{
int i, err;
+ net->ipv4.icmp_sk =
+ kzalloc(nr_cpu_ids * sizeof(struct sock *), GFP_KERNEL);
+ if (net->ipv4.icmp_sk == NULL)
+ return -ENOMEM;
+
for_each_possible_cpu(i) {
struct sock *sk;
struct socket *sock;
if (err < 0)
goto fail;
- per_cpu(__icmp_sk, i) = sk = sock->sk;
+ net->ipv4.icmp_sk[i] = sk = sock->sk;
+ sk_change_net(sk, net);
+
sk->sk_allocation = GFP_ATOMIC;
/* Enough space for 2 64K ICMP packets, including
return 0;
fail:
- icmp_exit();
+ for_each_possible_cpu(i)
+ sk_release_kernel(net->ipv4.icmp_sk[i]);
+ kfree(net->ipv4.icmp_sk);
return err;
}
+static struct pernet_operations __net_initdata icmp_sk_ops = {
+ .init = icmp_sk_init,
+ .exit = icmp_sk_exit,
+};
+
+int __init icmp_init(void)
+{
+ return register_pernet_device(&icmp_sk_ops);
+}
+
EXPORT_SYMBOL(icmp_err_convert);
EXPORT_SYMBOL(icmp_send);
EXPORT_SYMBOL(icmp_statistics);