net/netfilter/nf_conntrack_ecache.c

Source file repositories/reference/linux-study-clean/net/netfilter/nf_conntrack_ecache.c

File Facts

System
Linux kernel
Corpus path
net/netfilter/nf_conntrack_ecache.c
Extension
.c
Size
9346 bytes
Lines
384
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

if (nf_conntrack_event(IPCT_DESTROY, ct)) {
			ret = STATE_CONGESTED;
			break;
		}

		hlist_nulls_del_rcu(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode);
		hlist_nulls_add_head(&ct->tuplehash[IP_CT_DIR_REPLY].hnnode, &evicted_list);

		if (time_after(stop, jiffies)) {
			ret = STATE_RESTART;
			break;
		}

		if (sent++ > 16) {
			spin_unlock_bh(&cnet->ecache.dying_lock);
			cond_resched();
			goto next;
		}
	}

	spin_unlock_bh(&cnet->ecache.dying_lock);

	hlist_nulls_for_each_entry_safe(h, n, &evicted_list, hnnode) {
		struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(h);

		hlist_nulls_del_rcu(&ct->tuplehash[IP_CT_DIR_REPLY].hnnode);
		nf_ct_put(ct);

		cond_resched();
	}

	return ret;
}

static void ecache_work(struct work_struct *work)
{
	struct nf_conntrack_net *cnet = container_of(work, struct nf_conntrack_net, ecache.dwork.work);
	int ret, delay = -1;

	ret = ecache_work_evict_list(cnet);
	switch (ret) {
	case STATE_CONGESTED:
		delay = ECACHE_RETRY_JIFFIES;
		break;
	case STATE_RESTART:
		delay = 0;
		break;
	case STATE_DONE:
		break;
	}

	if (delay >= 0)
		schedule_delayed_work(&cnet->ecache.dwork, delay);
}

static int __nf_conntrack_eventmask_report(struct nf_conntrack_ecache *e,
					   const u32 events,
					   const u32 missed,
					   const struct nf_ct_event *item)
{
	struct net *net = nf_ct_net(item->ct);
	struct nf_ct_event_notifier *notify;
	u32 old, want;
	int ret;

	if (!((events | missed) & e->ctmask))
		return 0;

	rcu_read_lock();

	notify = rcu_dereference(net->ct.nf_conntrack_event_cb);
	if (!notify) {
		rcu_read_unlock();
		return 0;
	}

	ret = notify->ct_event(events | missed, item);
	rcu_read_unlock();

	if (likely(ret >= 0 && missed == 0))
		return 0;

	do {
		old = READ_ONCE(e->missed);
		if (ret < 0)
			want = old | events;
		else
			want = old & ~missed;
	} while (cmpxchg(&e->missed, old, want) != old);

Annotation

Implementation Notes