net/ipv4/inetpeer.c

Source file repositories/reference/linux-study-clean/net/ipv4/inetpeer.c

File Facts

System
Linux kernel
Corpus path
net/ipv4/inetpeer.c
Extension
.c
Size
7944 bytes
Lines
286
Domain
Networking Core
Bucket
Sockets, Protocols, Packet Path, And Network Policy
Inferred role
Networking Core: implementation source
Status
source 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

if (cmp == 0) {
			now = jiffies;
			if (READ_ONCE(p->dtime) != now)
				WRITE_ONCE(p->dtime, now);
			return p;
		}
		if (gc_stack) {
			if (*gc_cnt < PEER_MAX_GC)
				gc_stack[(*gc_cnt)++] = p;
		} else if (unlikely(read_seqretry(&base->lock, seq))) {
			break;
		}
		if (cmp == -1)
			pp = &next->rb_left;
		else
			pp = &next->rb_right;
	}
	*parent_p = parent;
	*pp_p = pp;
	return NULL;
}

/* perform garbage collect on all items stacked during a lookup */
static void inet_peer_gc(struct inet_peer_base *base,
			 struct inet_peer *gc_stack[],
			 unsigned int gc_cnt)
{
	int peer_threshold, peer_maxttl, peer_minttl;
	struct inet_peer *p;
	__u32 delta, ttl;
	int i;

	peer_threshold = READ_ONCE(inet_peer_threshold);
	peer_maxttl = READ_ONCE(inet_peer_maxttl);
	peer_minttl = READ_ONCE(inet_peer_minttl);

	if (base->total >= peer_threshold)
		ttl = 0; /* be aggressive */
	else
		ttl = peer_maxttl - (peer_maxttl - peer_minttl) / HZ *
			base->total / peer_threshold * HZ;
	for (i = 0; i < gc_cnt; i++) {
		p = gc_stack[i];

		delta = (__u32)jiffies - READ_ONCE(p->dtime);

		if (delta < ttl || !refcount_dec_if_one(&p->refcnt))
			gc_stack[i] = NULL;
	}
	for (i = 0; i < gc_cnt; i++) {
		p = gc_stack[i];
		if (p) {
			rb_erase(&p->rb_node, &base->rb_root);
			base->total--;
			kfree_rcu(p, rcu);
		}
	}
}

/* Must be called under RCU : No refcount change is done here. */
struct inet_peer *inet_getpeer(struct inet_peer_base *base,
			       const struct inetpeer_addr *daddr)
{
	struct inet_peer *p, *gc_stack[PEER_MAX_GC];
	struct rb_node **pp, *parent;
	unsigned int gc_cnt, seq;

	/* Attempt a lockless lookup first.
	 * Because of a concurrent writer, we might not find an existing entry.
	 */
	seq = read_seqbegin(&base->lock);
	p = lookup(daddr, base, seq, NULL, &gc_cnt, &parent, &pp);

	/* Make sure tree was not modified during our lookup. */
	if (p && !read_seqretry(&base->lock, seq))
		return p;

	/* retry an exact lookup, taking the lock before.
	 * At least, nodes should be hot in our cache.
	 */
	parent = NULL;
	write_seqlock_bh(&base->lock);

	gc_cnt = 0;
	p = lookup(daddr, base, seq, gc_stack, &gc_cnt, &parent, &pp);
	if (!p) {
		p = kmem_cache_alloc(peer_cachep, GFP_ATOMIC);
		if (p) {
			p->daddr = *daddr;
			p->dtime = (__u32)jiffies;

Annotation

Implementation Notes