<commit_before>/*
 * Copyright (C) 2012 <NAME>, <NAME>. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *   1. Redistributions of source code must retain the above copyright
 *      notice, this list of conditions and the following disclaimer.
 *   2. Redistributions in binary form must reproduce the above copyright
 *      notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

/*
 * $FreeBSD$
 * $Id: netmap_mem2.c 10830 2012-03-22 18:06:01Z luigi $
 *
 * New memory allocator for netmap
 */

/*
 * The new version allocates three regions:
 *	nm_if_pool      for the struct netmap_if
 *	nm_ring_pool    for the struct netmap_ring
 *	nm_buf_pool    for the packet buffers.
 *
 * All regions need to be page-sized as we export them to
 * userspace through mmap. Only the latter need to be dma-able,
 * but for convenience use the same type of allocator for all.
 *
 * Once mapped, the three regions are exported to userspace
 * as a contiguous block, starting from nm_if_pool. Each
 * cluster (and pool) is an integral number of pages.
 *   [ . . . ][ . . . . . .][ . . . . . . . . . .]
 *    nm_if     nm_ring            nm_buf
 *
 * The userspace areas contain offsets of the objects in userspace.
 * When (at init time) we write these offsets, we find out the index
 * of the object, and from there locate the offset from the beginning
 * of the region.
 *
 * Allocator for a pool of memory objects of the same size.
 * The pool is split into smaller clusters, whose size is a
 * multiple of the page size. The cluster size is chosen
 * to minimize the waste for a given max cluster size
 * (we do it by brute force, as we have relatively few object
 * per cluster).
 *
 * To be polite with the cache, objects are aligned to
 * the cache line, or 64 bytes. Sizes are rounded to multiple of 64.
 * For each object we have
 * one entry in the bitmap to signal the state. Allocation scans
 * the bitmap, but since this is done only on attach, we are not
 * too worried about performance
 */

/*
 *	MEMORY SIZES:
 *
 * (all the parameters below will become tunables)
 *
 * struct netmap_if is variable size but small.
 * Assuming each NIC has 8+2 rings, (4+1 tx, 4+1 rx) the netmap_if
 * uses 120 bytes on a 64-bit machine.
 * We allocate NETMAP_IF_MAX_SIZE  (1024) which should work even for
 * cards with 48 ring pairs.
 * The total number of 'struct netmap_if' could be slightly larger
 * that the total number of rings on all interfaces on the system.
 */
#define NETMAP_IF_MAX_SIZE      1024
#define NETMAP_IF_MAX_NUM       512

/*
 * netmap rings are up to 2..4k descriptors, 8 bytes each,
 * plus some glue at the beginning (32 bytes).
 * We set the default ring size to 9 pages (36K) and enable
 * a few hundreds of them.
 */
#define NETMAP_RING_MAX_SIZE    (9*PAGE_SIZE)
#define NETMAP_RING_MAX_NUM     200	/* approx 8MB */

/*
 * Buffers: the more the better. Buffer size is NETMAP_BUF_SIZE,
 * 2k or slightly less, aligned to 64 bytes.
 * A large 10G interface can have 2k*18 = 36k buffers per interface,
 * or about 72MB of memory. Up to us to use more.
 */
#ifndef CONSERVATIVE
#define NETMAP_BUF_MAX_NUM      100000  /* 200MB */
#else /* CONSERVATIVE */
#define NETMAP_BUF_MAX_NUM      20000   /* 40MB */
#endif


struct netmap_obj_pool {
	char name[16];		/* name of the allocator */
	u_int objtotal;         /* actual total number of objects. */
	u_int objfree;          /* number of free objects. */
	u_int clustentries;	/* actual objects per cluster */

	/* the total memory space is _numclusters*_clustsize */
	u_int _numclusters;	/* how many clusters */
	u_int _clustsize;        /* cluster size */
	u_int _objsize;		/* actual object size */

	u_int _memtotal;	/* _numclusters*_clustsize */
	struct lut_entry *lut;  /* virt,phys addresses, objtotal entries */
	uint32_t *bitmap;       /* one bit per buffer, 1 means free */
};

struct netmap_mem_d {
	NM_LOCK_T nm_mtx; /* protect the allocator ? */
	u_int nm_totalsize; /* shorthand */

	/* pointers to the three allocators */
	struct netmap_obj_pool *nm_if_pool;
	struct netmap_obj_pool *nm_ring_pool;
	struct netmap_obj_pool *nm_buf_pool;
};

struct lut_entry *netmap_buffer_lut;	/* exported */


/*
 * Convert a userspace offset to a phisical address.
 * XXX re-do in a simpler way.
 *
 * The idea here is to hide userspace applications the fact that pre-allocated
 * memory is not contiguous, but fragmented across different clusters and
 * smaller memory allocators. Consequently, first of all we need to find which
 * allocator is owning provided offset, then we need to find out the physical
 * address associated to target page (this is done using the look-up table.
 */
static inline vm_paddr_t
netmap_ofstophys(vm_offset_t offset)
{
	const struct netmap_obj_pool *p[] = {
		nm_mem->nm_if_pool,
		nm_mem->nm_ring_pool,
		nm_mem->nm_buf_pool };
	int i;
	vm_offset_t o = offset;


	for (i = 0; i < 3; offset -= p[i]->_memtotal, i++) {
		if (offset >= p[i]->_memtotal)
			continue;
		// XXX now scan the clusters
		return p[i]->lut[offset / p[i]->_objsize].paddr +
			offset % p[i]->_objsize;
	}
	D("invalid ofs 0x%jx out of 0x%jx 0x%jx 0x%jx", (uintmax_t)o,
		(uintmax_t)p[0]->_memtotal,
		(uintmax_t)(p[0]->_memtotal + p[1]->_memtotal),
		(uintmax_t)(p[0]->_memtotal + p[1]->_memtotal +
		    p[2]->_memtotal));
	return 0;	// XXX bad address
}

/*
 * we store objects by kernel address, need to find the offset
 * within the pool to export the value to userspace.
 * Algorithm: scan until we find the cluster, then add the
 * actual offset in the cluster
 */
static ssize_t
netmap_obj_offset(struct netmap_obj_pool *p, const void *vaddr)
{<commit_msg>i prefer this fix for the -Wformat warning (just one cast, all the other variables are already correct for %x). My previous attempt put the cast in the wrong place.<commit_after>/*
 * Copyright (C) 2012 <NAME>, <NAME>. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *   1. Redistributions of source code must retain the above copyright
 *      notice, this list of conditions and the following disclaimer.
 *   2. Redistributions in binary form must reproduce the above copyright
 *      notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

/*
 * $FreeBSD$
 * $Id: netmap_mem2.c 10830 2012-03-22 18:06:01Z luigi $
 *
 * New memory allocator for netmap
 */

/*
 * The new version allocates three regions:
 *	nm_if_pool      for the struct netmap_if
 *	nm_ring_pool    for the struct netmap_ring
 *	nm_buf_pool    for the packet buffers.
 *
 * All regions need to be page-sized as we export them to
 * userspace through mmap. Only the latter need to be dma-able,
 * but for convenience use the same type of allocator for all.
 *
 * Once mapped, the three regions are exported to userspace
 * as a contiguous block, starting from nm_if_pool. Each
 * cluster (and pool) is an integral number of pages.
 *   [ . . . ][ . . . . . .][ . . . . . . . . . .]
 *    nm_if     nm_ring            nm_buf
 *
 * The userspace areas contain offsets of the objects in userspace.
 * When (at init time) we write these offsets, we find out the index
 * of the object, and from there locate the offset from the beginning
 * of the region.
 *
 * Allocator for a pool of memory objects of the same size.
 * The pool is split into smaller clusters, whose size is a
 * multiple of the page size. The cluster size is chosen
 * to minimize the waste for a given max cluster size
 * (we do it by brute force, as we have relatively few object
 * per cluster).
 *
 * To be polite with the cache, objects are aligned to
 * the cache line, or 64 bytes. Sizes are rounded to multiple of 64.
 * For each object we have
 * one entry in the bitmap to signal the state. Allocation scans
 * the bitmap, but since this is done only on attach, we are not
 * too worried about performance
 */

/*
 *	MEMORY SIZES:
 *
 * (all the parameters below will become tunables)
 *
 * struct netmap_if is variable size but small.
 * Assuming each NIC has 8+2 rings, (4+1 tx, 4+1 rx) the netmap_if
 * uses 120 bytes on a 64-bit machine.
 * We allocate NETMAP_IF_MAX_SIZE  (1024) which should work even for
 * cards with 48 ring pairs.
 * The total number of 'struct netmap_if' could be slightly larger
 * that the total number of rings on all interfaces on the system.
 */
#define NETMAP_IF_MAX_SIZE      1024
#define NETMAP_IF_MAX_NUM       512

/*
 * netmap rings are up to 2..4k descriptors, 8 bytes each,
 * plus some glue at the beginning (32 bytes).
 * We set the default ring size to 9 pages (36K) and enable
 * a few hundreds of them.
 */
#define NETMAP_RING_MAX_SIZE    (9*PAGE_SIZE)
#define NETMAP_RING_MAX_NUM     200	/* approx 8MB */

/*
 * Buffers: the more the better. Buffer size is NETMAP_BUF_SIZE,
 * 2k or slightly less, aligned to 64 bytes.
 * A large 10G interface can have 2k*18 = 36k buffers per interface,
 * or about 72MB of memory. Up to us to use more.
 */
#ifndef CONSERVATIVE
#define NETMAP_BUF_MAX_NUM      100000  /* 200MB */
#else /* CONSERVATIVE */
#define NETMAP_BUF_MAX_NUM      20000   /* 40MB */
#endif


struct netmap_obj_pool {
	char name[16];		/* name of the allocator */
	u_int objtotal;         /* actual total number of objects. */
	u_int objfree;          /* number of free objects. */
	u_int clustentries;	/* actual objects per cluster */

	/* the total memory space is _numclusters*_clustsize */
	u_int _numclusters;	/* how many clusters */
	u_int _clustsize;        /* cluster size */
	u_int _objsize;		/* actual object size */

	u_int _memtotal;	/* _numclusters*_clustsize */
	struct lut_entry *lut;  /* virt,phys addresses, objtotal entries */
	uint32_t *bitmap;       /* one bit per buffer, 1 means free */
};

struct netmap_mem_d {
	NM_LOCK_T nm_mtx; /* protect the allocator ? */
	u_int nm_totalsize; /* shorthand */

	/* pointers to the three allocators */
	struct netmap_obj_pool *nm_if_pool;
	struct netmap_obj_pool *nm_ring_pool;
	struct netmap_obj_pool *nm_buf_pool;
};

struct lut_entry *netmap_buffer_lut;	/* exported */


/*
 * Convert a userspace offset to a phisical address.
 * XXX re-do in a simpler way.
 *
 * The idea here is to hide userspace applications the fact that pre-allocated
 * memory is not contiguous, but fragmented across different clusters and
 * smaller memory allocators. Consequently, first of all we need to find which
 * allocator is owning provided offset, then we need to find out the physical
 * address associated to target page (this is done using the look-up table.
 */
static inline vm_paddr_t
netmap_ofstophys(vm_offset_t offset)
{
	const struct netmap_obj_pool *p[] = {
		nm_mem->nm_if_pool,
		nm_mem->nm_ring_pool,
		nm_mem->nm_buf_pool };
	int i;
	vm_offset_t o = offset;


	for (i = 0; i < 3; offset -= p[i]->_memtotal, i++) {
		if (offset >= p[i]->_memtotal)
			continue;
		// XXX now scan the clusters
		return p[i]->lut[offset / p[i]->_objsize].paddr +
			offset % p[i]->_objsize;
	}
	D("invalid ofs 0x%x out of 0x%x 0x%x 0x%x", (u_int)o,
		p[0]->_memtotal, p[0]->_memtotal + p[1]->_memtotal,
		p[0]->_memtotal + p[1]->_memtotal + p[2]->_memtotal);
	return 0;	// XXX bad address
}

/*
 * we store objects by kernel address, need to find the offset
 * within the pool to export the value to userspace.
 * Algorithm: scan until we find the cluster, then add the
 * actual offset in the cluster
 */
static ssize_t
netmap_obj_offset(struct netmap_obj_pool *p, const void *vaddr)
{
{'fraction_non_alphanumeric': 0.0821845969433623, 'fraction_numerical': 0.01693137548696434, 'mean_word_length': 3.4275290215588723, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 37, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '96173', 'n_tokens_mistral': 4374, 'n_tokens_neox': 4014, 'n_words': 1783}