Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 887c95cc authored by YOSHIFUJI Hideaki / 吉藤英明's avatar YOSHIFUJI Hideaki / 吉藤英明 Committed by David S. Miller
Browse files

ipv6: Complete neighbour entry removal from dst_entry.



CC: Cong Wang <xiyou.wangcong@gmail.com>
Signed-off-by: default avatarYOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 6fd6ce20
Loading
Loading
Loading
Loading
+0 −2
Original line number Original line Diff line number Diff line
@@ -89,8 +89,6 @@ struct fib6_table;
struct rt6_info {
struct rt6_info {
	struct dst_entry		dst;
	struct dst_entry		dst;


	struct neighbour		*n;

	/*
	/*
	 * Tail elements of dst_entry (__refcnt etc.)
	 * Tail elements of dst_entry (__refcnt etc.)
	 * and these elements (rarely used in hot path) are in
	 * and these elements (rarely used in hot path) are in
+1 −83
Original line number Original line Diff line number Diff line
@@ -151,19 +151,6 @@ static struct neighbour *ip6_neigh_lookup(const struct dst_entry *dst,
	return neigh_create(&nd_tbl, daddr, dst->dev);
	return neigh_create(&nd_tbl, daddr, dst->dev);
}
}


static int rt6_bind_neighbour(struct rt6_info *rt, struct net_device *dev)
{
	struct neighbour *n = __ipv6_neigh_lookup(dev, &rt->rt6i_gateway);
	if (!n) {
		n = neigh_create(&nd_tbl, &rt->rt6i_gateway, dev);
		if (IS_ERR(n))
			return PTR_ERR(n);
	}
	rt->n = n;

	return 0;
}

static struct dst_ops ip6_dst_ops_template = {
static struct dst_ops ip6_dst_ops_template = {
	.family			=	AF_INET6,
	.family			=	AF_INET6,
	.protocol		=	cpu_to_be16(ETH_P_IPV6),
	.protocol		=	cpu_to_be16(ETH_P_IPV6),
@@ -301,9 +288,6 @@ static void ip6_dst_destroy(struct dst_entry *dst)
	struct rt6_info *rt = (struct rt6_info *)dst;
	struct rt6_info *rt = (struct rt6_info *)dst;
	struct inet6_dev *idev = rt->rt6i_idev;
	struct inet6_dev *idev = rt->rt6i_idev;


	if (rt->n)
		neigh_release(rt->n);

	if (!(rt->dst.flags & DST_HOST))
	if (!(rt->dst.flags & DST_HOST))
		dst_destroy_metrics_generic(dst);
		dst_destroy_metrics_generic(dst);


@@ -354,11 +338,6 @@ static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev,
				in6_dev_put(idev);
				in6_dev_put(idev);
			}
			}
		}
		}
		if (rt->n && rt->n->dev == dev) {
			rt->n->dev = loopback_dev;
			dev_hold(loopback_dev);
			dev_put(dev);
		}
	}
	}
}
}


@@ -845,8 +824,6 @@ static struct rt6_info *rt6_alloc_cow(struct rt6_info *ort,
	rt = ip6_rt_copy(ort, daddr);
	rt = ip6_rt_copy(ort, daddr);


	if (rt) {
	if (rt) {
		int attempts = !in_softirq();

		if (!(rt->rt6i_flags & RTF_GATEWAY)) {
		if (!(rt->rt6i_flags & RTF_GATEWAY)) {
			if (ort->rt6i_dst.plen != 128 &&
			if (ort->rt6i_dst.plen != 128 &&
			    ipv6_addr_equal(&ort->rt6i_dst.addr, daddr))
			    ipv6_addr_equal(&ort->rt6i_dst.addr, daddr))
@@ -862,32 +839,6 @@ static struct rt6_info *rt6_alloc_cow(struct rt6_info *ort,
			rt->rt6i_src.plen = 128;
			rt->rt6i_src.plen = 128;
		}
		}
#endif
#endif

	retry:
		if (rt6_bind_neighbour(rt, rt->dst.dev)) {
			struct net *net = dev_net(rt->dst.dev);
			int saved_rt_min_interval =
				net->ipv6.sysctl.ip6_rt_gc_min_interval;
			int saved_rt_elasticity =
				net->ipv6.sysctl.ip6_rt_gc_elasticity;

			if (attempts-- > 0) {
				net->ipv6.sysctl.ip6_rt_gc_elasticity = 1;
				net->ipv6.sysctl.ip6_rt_gc_min_interval = 0;

				ip6_dst_gc(&net->ipv6.ip6_dst_ops);

				net->ipv6.sysctl.ip6_rt_gc_elasticity =
					saved_rt_elasticity;
				net->ipv6.sysctl.ip6_rt_gc_min_interval =
					saved_rt_min_interval;
				goto retry;
			}

			net_warn_ratelimited("Neighbour table overflow\n");
			dst_free(&rt->dst);
			return NULL;
		}
	}
	}


	return rt;
	return rt;
@@ -898,10 +849,8 @@ static struct rt6_info *rt6_alloc_clone(struct rt6_info *ort,
{
{
	struct rt6_info *rt = ip6_rt_copy(ort, daddr);
	struct rt6_info *rt = ip6_rt_copy(ort, daddr);


	if (rt) {
	if (rt)
		rt->rt6i_flags |= RTF_CACHE;
		rt->rt6i_flags |= RTF_CACHE;
		rt->n = neigh_clone(ort->n);
	}
	return rt;
	return rt;
}
}


@@ -1272,20 +1221,8 @@ struct dst_entry *icmp6_dst_alloc(struct net_device *dev,
		goto out;
		goto out;
	}
	}


	if (neigh)
		neigh_hold(neigh);
	else {
		neigh = ip6_neigh_lookup(&rt->dst, NULL, &fl6->daddr);
		if (IS_ERR(neigh)) {
			in6_dev_put(idev);
			dst_free(&rt->dst);
			return ERR_CAST(neigh);
		}
	}

	rt->dst.flags |= DST_HOST;
	rt->dst.flags |= DST_HOST;
	rt->dst.output  = ip6_output;
	rt->dst.output  = ip6_output;
	rt->n = neigh;
	atomic_set(&rt->dst.__refcnt, 1);
	atomic_set(&rt->dst.__refcnt, 1);
	rt->rt6i_dst.addr = fl6->daddr;
	rt->rt6i_dst.addr = fl6->daddr;
	rt->rt6i_dst.plen = 128;
	rt->rt6i_dst.plen = 128;
@@ -1594,12 +1531,6 @@ int ip6_route_add(struct fib6_config *cfg)
	} else
	} else
		rt->rt6i_prefsrc.plen = 0;
		rt->rt6i_prefsrc.plen = 0;


	if (cfg->fc_flags & (RTF_GATEWAY | RTF_NONEXTHOP)) {
		err = rt6_bind_neighbour(rt, dev);
		if (err)
			goto out;
	}

	rt->rt6i_flags = cfg->fc_flags;
	rt->rt6i_flags = cfg->fc_flags;


install_route:
install_route:
@@ -1713,7 +1644,6 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu
	struct netevent_redirect netevent;
	struct netevent_redirect netevent;
	struct rt6_info *rt, *nrt = NULL;
	struct rt6_info *rt, *nrt = NULL;
	struct ndisc_options ndopts;
	struct ndisc_options ndopts;
	struct neighbour *old_neigh;
	struct inet6_dev *in6_dev;
	struct inet6_dev *in6_dev;
	struct neighbour *neigh;
	struct neighbour *neigh;
	struct rd_msg *msg;
	struct rd_msg *msg;
@@ -1786,11 +1716,6 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu
	if (!neigh)
	if (!neigh)
		return;
		return;


	/* Duplicate redirect: silently ignore. */
	old_neigh = rt->n;
	if (neigh == old_neigh)
		goto out;

	/*
	/*
	 *	We have finally decided to accept it.
	 *	We have finally decided to accept it.
	 */
	 */
@@ -1811,7 +1736,6 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu
		nrt->rt6i_flags &= ~RTF_GATEWAY;
		nrt->rt6i_flags &= ~RTF_GATEWAY;


	nrt->rt6i_gateway = *(struct in6_addr *)neigh->primary_key;
	nrt->rt6i_gateway = *(struct in6_addr *)neigh->primary_key;
	nrt->n = neigh_clone(neigh);


	if (ip6_ins_rt(nrt))
	if (ip6_ins_rt(nrt))
		goto out;
		goto out;
@@ -2125,7 +2049,6 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev,
{
{
	struct net *net = dev_net(idev->dev);
	struct net *net = dev_net(idev->dev);
	struct rt6_info *rt = ip6_dst_alloc(net, net->loopback_dev, 0, NULL);
	struct rt6_info *rt = ip6_dst_alloc(net, net->loopback_dev, 0, NULL);
	int err;


	if (!rt) {
	if (!rt) {
		net_warn_ratelimited("Maximum number of routes reached, consider increasing route/max_size\n");
		net_warn_ratelimited("Maximum number of routes reached, consider increasing route/max_size\n");
@@ -2144,11 +2067,6 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev,
		rt->rt6i_flags |= RTF_ANYCAST;
		rt->rt6i_flags |= RTF_ANYCAST;
	else
	else
		rt->rt6i_flags |= RTF_LOCAL;
		rt->rt6i_flags |= RTF_LOCAL;
	err = rt6_bind_neighbour(rt, rt->dst.dev);
	if (err) {
		dst_free(&rt->dst);
		return ERR_PTR(err);
	}


	rt->rt6i_dst.addr = *addr;
	rt->rt6i_dst.addr = *addr;
	rt->rt6i_dst.plen = 128;
	rt->rt6i_dst.plen = 128;
+0 −1
Original line number Original line Diff line number Diff line
@@ -110,7 +110,6 @@ static int xfrm6_fill_dst(struct xfrm_dst *xdst, struct net_device *dev,


	/* Sheit... I remember I did this right. Apparently,
	/* Sheit... I remember I did this right. Apparently,
	 * it was magically lost, so this code needs audit */
	 * it was magically lost, so this code needs audit */
	xdst->u.rt6.n = neigh_clone(rt->n);
	xdst->u.rt6.rt6i_flags = rt->rt6i_flags & (RTF_ANYCAST |
	xdst->u.rt6.rt6i_flags = rt->rt6i_flags & (RTF_ANYCAST |
						   RTF_LOCAL);
						   RTF_LOCAL);
	xdst->u.rt6.rt6i_metric = rt->rt6i_metric;
	xdst->u.rt6.rt6i_metric = rt->rt6i_metric;