net/openvswitch/flow_table.c

Source file repositories/reference/linux-study-clean/net/openvswitch/flow_table.c

File Facts

System
Linux kernel
Corpus path
net/openvswitch/flow_table.c
Extension
.c
Size
29910 bytes
Lines
1218
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

for_each_possible_cpu(cpu) {
			struct mask_array_stats *stats;
			unsigned int start;
			u64 counter;

			stats = per_cpu_ptr(ma->masks_usage_stats, cpu);
			do {
				start = u64_stats_fetch_begin(&stats->syncp);
				counter = stats->usage_cntrs[i];
			} while (u64_stats_fetch_retry(&stats->syncp, start));

			ma->masks_usage_zero_cntr[i] += counter;
		}
	}
}

static struct mask_array *tbl_mask_array_alloc(int size)
{
	struct mask_array *new;

	size = max(MASK_ARRAY_SIZE_MIN, size);
	new = kzalloc(struct_size(new, masks, size) +
		      sizeof(u64) * size, GFP_KERNEL);
	if (!new)
		return NULL;

	new->masks_usage_zero_cntr = (u64 *)((u8 *)new +
					     struct_size(new, masks, size));

	new->masks_usage_stats = __alloc_percpu(sizeof(struct mask_array_stats) +
						sizeof(u64) * size,
						__alignof__(u64));
	if (!new->masks_usage_stats) {
		kfree(new);
		return NULL;
	}

	new->count = 0;
	new->max = size;

	return new;
}

static int tbl_mask_array_realloc(struct flow_table *tbl, int size)
{
	struct mask_array *old;
	struct mask_array *new;

	new = tbl_mask_array_alloc(size);
	if (!new)
		return -ENOMEM;

	old = ovsl_dereference(tbl->mask_array);
	if (old) {
		int i;

		for (i = 0; i < old->max; i++) {
			if (ovsl_dereference(old->masks[i]))
				new->masks[new->count++] = old->masks[i];
		}
		call_rcu(&old->rcu, mask_array_rcu_cb);
	}

	rcu_assign_pointer(tbl->mask_array, new);

	return 0;
}

static int tbl_mask_array_add_mask(struct flow_table *tbl,
				   struct sw_flow_mask *new)
{
	struct mask_array *ma = ovsl_dereference(tbl->mask_array);
	int err, ma_count = READ_ONCE(ma->count);

	if (ma_count >= ma->max) {
		err = tbl_mask_array_realloc(tbl, ma->max +
						  MASK_ARRAY_SIZE_MIN);
		if (err)
			return err;

		ma = ovsl_dereference(tbl->mask_array);
	} else {
		/* On every add or delete we need to reset the counters so
		 * every new mask gets a fair chance of being prioritized.
		 */
		tbl_mask_array_reset_counters(ma);
	}

	BUG_ON(ovsl_dereference(ma->masks[ma_count]));

Annotation

Implementation Notes