net/ipv6/route.c

Source file repositories/reference/linux-study-clean/net/ipv6/route.c

File Facts

System
Linux kernel
Corpus path
net/ipv6/route.c
Extension
.c
Size
175181 bytes
Lines
6995
Domain
Networking Core
Bucket
Sockets, Protocols, Packet Path, And Network Policy
Inferred role
Networking Core: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

Networking stack implementation surface: socket APIs, protocol dispatch, packet flow, routing, filtering, and network namespaces.

Dependency Surface

Detected Declarations

Annotated Snippet

struct uncached_list {
	spinlock_t		lock;
	struct list_head	head;
};

static DEFINE_PER_CPU_ALIGNED(struct uncached_list, rt6_uncached_list);

void rt6_uncached_list_add(struct rt6_info *rt)
{
	struct uncached_list *ul = raw_cpu_ptr(&rt6_uncached_list);

	rt->dst.rt_uncached_list = ul;

	spin_lock_bh(&ul->lock);
	list_add_tail(&rt->dst.rt_uncached, &ul->head);
	spin_unlock_bh(&ul->lock);
}

void rt6_uncached_list_del(struct rt6_info *rt)
{
	struct uncached_list *ul = rt->dst.rt_uncached_list;

	if (ul) {
		spin_lock_bh(&ul->lock);
		list_del_init(&rt->dst.rt_uncached);
		spin_unlock_bh(&ul->lock);
	}
}

static void rt6_uncached_list_flush_dev(struct net_device *dev)
{
	int cpu;

	for_each_possible_cpu(cpu) {
		struct uncached_list *ul = per_cpu_ptr(&rt6_uncached_list, cpu);
		struct rt6_info *rt, *safe;

		if (list_empty(&ul->head))
			continue;

		spin_lock_bh(&ul->lock);
		list_for_each_entry_safe(rt, safe, &ul->head, dst.rt_uncached) {
			struct inet6_dev *rt_idev = rt->rt6i_idev;
			struct net_device *rt_dev = rt->dst.dev;
			bool handled = false;

			if (rt_idev && rt_idev->dev == dev) {
				rt->rt6i_idev = in6_dev_get(blackhole_netdev);
				in6_dev_put(rt_idev);
				handled = true;
			}

			if (rt_dev == dev) {
				rt->dst.dev = blackhole_netdev;
				netdev_ref_replace(rt_dev, blackhole_netdev,
						   &rt->dst.dev_tracker,
						   GFP_ATOMIC);
				handled = true;
			}
			if (handled)
				list_del_init(&rt->dst.rt_uncached);
		}
		spin_unlock_bh(&ul->lock);
	}
}

static inline const void *choose_neigh_daddr(const struct in6_addr *p,
					     struct sk_buff *skb,
					     const void *daddr)
{
	if (!ipv6_addr_any(p))
		return (const void *) p;
	else if (skb)
		return &ipv6_hdr(skb)->daddr;
	return daddr;
}

struct neighbour *ip6_neigh_lookup(const struct in6_addr *gw,
				   struct net_device *dev,
				   struct sk_buff *skb,
				   const void *daddr)
{
	struct neighbour *n;

	daddr = choose_neigh_daddr(gw, skb, daddr);
	n = __ipv6_neigh_lookup(dev, daddr);
	if (n)
		return n;

	n = neigh_create(&nd_tbl, daddr, dev);

Annotation

Implementation Notes