net/netfilter/ipvs/ip_vs_conn.c

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

File Facts

System
Linux kernel
Corpus path
net/netfilter/ipvs/ip_vs_conn.c
Extension
.c
Size
54006 bytes
Lines
2057
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 ip_vs_iter_state {
	struct seq_net_private	p;
	struct ip_vs_rht	*t;
	int			gen;
	u32			bucket;
	unsigned int		skip_elems;
};

static void *ip_vs_conn_array(struct seq_file *seq)
{
	struct ip_vs_iter_state *iter = seq->private;
	struct net *net = seq_file_net(seq);
	struct netns_ipvs *ipvs = net_ipvs(net);
	struct ip_vs_rht *t = iter->t;
	struct ip_vs_conn_hnode *hn;
	struct hlist_bl_node *e;
	int idx;

	if (!t)
		return NULL;
	for (idx = iter->bucket; idx < t->size; idx++) {
		unsigned int skip = 0;

		hlist_bl_for_each_entry_rcu(hn, e, &t->buckets[idx], node) {
			/* __ip_vs_conn_get() is not needed by
			 * ip_vs_conn_seq_show and ip_vs_conn_sync_seq_show
			 */
			if (!ip_vs_rht_same_table(t, READ_ONCE(hn->hash_key)))
				break;
			if (hn->dir != 0)
				continue;
			if (skip >= iter->skip_elems) {
				iter->bucket = idx;
				return hn;
			}

			++skip;
		}

		if (!(idx & 31)) {
			cond_resched_rcu();
			/* New table installed ? */
			if (iter->gen != atomic_read(&ipvs->conn_tab_changes))
				break;
		}
		iter->skip_elems = 0;
	}

	iter->bucket = idx;
	return NULL;
}

static void *ip_vs_conn_seq_start(struct seq_file *seq, loff_t *pos)
	__acquires(RCU)
{
	struct ip_vs_iter_state *iter = seq->private;
	struct net *net = seq_file_net(seq);
	struct netns_ipvs *ipvs = net_ipvs(net);

	rcu_read_lock();
	iter->gen = atomic_read(&ipvs->conn_tab_changes);
	smp_rmb(); /* ipvs->conn_tab and conn_tab_changes */
	iter->t = rcu_dereference(ipvs->conn_tab);
	if (*pos == 0) {
		iter->skip_elems = 0;
		iter->bucket = 0;
		return SEQ_START_TOKEN;
	}

	return ip_vs_conn_array(seq);
}

static void *ip_vs_conn_seq_next(struct seq_file *seq, void *v, loff_t *pos)
{
	struct ip_vs_iter_state *iter = seq->private;
	struct ip_vs_conn_hnode *hn = v;
	struct hlist_bl_node *e;
	struct ip_vs_rht *t;

	++*pos;
	if (v == SEQ_START_TOKEN)
		return ip_vs_conn_array(seq);

	t = iter->t;
	if (!t)
		return NULL;

	/* more on same hash chain? */
	hlist_bl_for_each_entry_continue_rcu(hn, e, node) {
		/* Our cursor was moved to new table ? */

Annotation

Implementation Notes