Commit fa41ef71 authored by Leonardo Lai's avatar Leonardo Lai

reworked bindings table

parent 841b83bc
......@@ -35,3 +35,5 @@ This software uses code from:
License: BSD 3-Clause
- inih: https://github.com/benhoyt/inih
License: BSD 3-Clause
- list: https://github.com/clibs/list
License: MIT
......@@ -33,12 +33,14 @@ CFLAGS+= --param large-function-growth=1000
DPDK_CFLAGS= -DRTE_MACHINE_CPUFLAG_SSE -DRTE_MACHINE_CPUFLAG_SSE2 -DRTE_MACHINE_CPUFLAG_SSE3
DPDK_CFLAGS+= -DRTE_MACHINE_CPUFLAG_SSSE3 -DRTE_MACHINE_CPUFLAG_SSE4_1 -DRTE_MACHINE_CPUFLAG_SSE4_2
DPDK_CFLAGS+= -DRTE_COMPILE_TIME_CPUFLAGS=RTE_CPUFLAG_SSE,RTE_CPUFLAG_SSE2,RTE_CPUFLAG_SSE3,RTE_CPUFLAG_SSSE3,RTE_CPUFLAG_SSE4_1,RTE_CPUFLAG_SSE4_2
DPDK_CFLAGS+= -I${UDPDK_DPDK}/include
DPDK_CFLAGS+= -I${INIH}
UDPDK_C= ${CC} -c $(DPDK_CFLAGS) ${CFLAGS} ${WERROR} $<
UDPDK_CFLAGS+= -I${UDPDK_DPDK}/include
UDPDK_CFLAGS+= -I${INIH}
UDPDK_CFLAGS+= -Ilist -Ishmalloc
UDPDK_SRCS+= \
UDPDK_C= ${CC} -c $(DPDK_CFLAGS) $(UDPDK_CFLAGS) ${CFLAGS} ${WERROR} $<
UDPDK_CORE_SRCS+= \
udpdk_args.c \
udpdk_globals.c \
udpdk_init.c \
......@@ -46,8 +48,19 @@ UDPDK_SRCS+= \
udpdk_poller.c \
udpdk_syscall.c \
UDPDK_LIST_SRCS+= \
list/list.c \
list/list_node.c \
list/list_iterator.c \
list/list_globals.c \
list/list_init.c
UDPDK_SHM_SRCS+=
shmalloc/udpdk_shmalloc.c \
SRCS= ${UDPDK_SRCS}
SRCS+= ${UDPDK_CORE_SRCS}
SRCS+= ${UDPDK_LIST_SRCS}
SRCS+= ${UDPDK_SHM_SRCS}
OBJS+= $(patsubst %.c,%.o,${SRCS})
......@@ -67,7 +80,7 @@ libudpdk.a: ${OBJS}
rm -f $*.ro
${OBJS}: %.o: %.c
${UDPDK_C}
${UDPDK_C} -o $@
.PHONY: clean
clean:
......
//
// Created by leoll2 on 11/01/20.
// Copyright (c) 2020 Leonardo Lai. All rights reserved.
//
#include <string.h>
#include "udpdk_shmalloc.h"
#define SetBit(A,k) (A[(k / 32)] |= (1 << (k % 32)))
#define ClearBit(A,k) (A[(k / 32)] &= ~(1 << (k % 32)))
#define TestBit(A,k) (A[(k / 32)] & (1 << (k % 32)))
struct allocator {
unsigned size;
unsigned elem_size; // size (byte) of each element
unsigned n_free;
unsigned next_free; // index of next free
unsigned pool_offset; // offset (bytes) from the begin of memzone
};
const struct rte_memzone *udpdk_init_allocator(const char *name, unsigned size, unsigned elem_size)
{
unsigned mem_needed;
unsigned p_off;
const struct rte_memzone *mz;
struct allocator *all;
const int *free_bitfield;
//Round-up elem_size to cache line multiple (64 byte)
elem_size = (elem_size + 64 - 1) / 64;
// Determine how much memory is needed (pool size + bitfield of free elems + variables)
mem_needed = sizeof(struct allocator) + (size / 8 + 1);
mem_needed = (mem_needed + elem_size - 1) / elem_size; // align
p_off = mem_needed;
mem_needed += (size * elem_size);
// Allocate the memory for the allocator and its pool
mz = rte_memzone_reserve(name, mem_needed, rte_socket_id(), 0);
if (mz == NULL) {
return NULL;
}
// Initialize the allocator internal variables
all = (struct allocator *)(void *)mz->addr;
all->size = size;
all->elem_size = elem_size;
all->n_free = size;
all->next_free = 0;
all->pool_offset = p_off;
// Mark all the elements as free
free_bitfield = (int *)(all + 1);
memset((void *)free_bitfield, 0, (size / 8 + 1));
return mz;
}
void *udpdk_shmalloc(const struct rte_memzone *mz)
{
struct allocator *all;
int *free_bitfield;
unsigned size;
unsigned p_off;
unsigned i, j;
void *ret;
all = (struct allocator *)(void *)mz->addr;
free_bitfield = (int *)(all + 1);
if (all->n_free == 0) {
RTE_LOG(WARNING, SHM, "shmalloc failed: out of memory\n");
return NULL;
}
size = all->size;
p_off = all->pool_offset;
// Compute and store the pointer to return
ret = ((void *)mz->addr + p_off + (all->next_free * all->elem_size));
--all->n_free;
// Update the free bitfield
SetBit(free_bitfield, all->next_free);
// Find the next free slot
if (all->n_free != 0) {
j = all->next_free + 1;
for (int i = 0; i < size; i++) {
if (j >= size) {
j = 0;
}
if (!TestBit(free_bitfield, j)) {
all->next_free = j;
break;
}
++j;
}
}
return ret;
}
// NOTE: the memzone is only needed to check memory boundaries
void udpdk_shfree(const struct rte_memzone *mz, void *addr)
{
struct allocator *all;
int *free_bitfield;
unsigned p_off;
unsigned i;
void *pool_start;
void *pool_end;
all = (struct allocator *)(void *)mz->addr;
free_bitfield = (int *)(all + 1);
p_off = all->pool_offset;
// Validate the address
pool_start = (void *)mz->addr + p_off;
pool_end = ((void *)mz->addr + p_off + (all->size * all->elem_size));
if ((addr < pool_start) || (addr >= pool_end)) {
RTE_LOG(WARNING, SHM, "Double free\n");
return;
}
// Check if the memory was really allocated
i = (addr - pool_start) / all->elem_size;
if (!TestBit(free_bitfield, i)) {
RTE_LOG(WARNING, SHM, "Double free\n");
return;
}
// Free
ClearBit(free_bitfield, i);
++all->n_free;
// If prevoiusly full, recompute next_free
if (all->n_free == 1) {
all->next_free = i;
}
}
void udpdk_destroy_allocator(const struct rte_memzone *mz)
{
const struct allocator *all;
all = (struct allocator *)(void *)mz->addr;
if (all->n_free != all->size) {
RTE_LOG(WARNING, SHM, "Destroying shm allocator before all the elements were freed!\n");
}
rte_memzone_free(mz);
}
//
// Created by leoll2 on 11/01/20.
// Copyright (c) 2020 Leonardo Lai. All rights reserved.
//
#ifndef UDPDK_SHMALLOC_H
#define UDPDK_SHMALLOC_H
#include <rte_compat.h>
#include <rte_memory.h>
#include <rte_common.h>
const struct rte_memzone *udpdk_init_allocator(const char *name, unsigned size, unsigned elem_size);
void *udpdk_shmalloc(const struct rte_memzone *mz);
void udpdk_shfree(const struct rte_memzone *mz, void *addr);
void udpdk_destroy_allocator(const struct rte_memzone *mz);
#endif // UDPDK_SHMALLOC_H
//
// Created by leoll2 on 9/27/20.
// Copyright (c) 2020 Leonardo Lai. All rights reserved.
//
// Data structure to hold (ip, port) pairs of bound sockets
// It is an array of size MAX_PORTS of lists; each list contains all
// the IPs bound to that port (typically one, but can be many)
//
#include "udpdk_bind_table.h"
void *bind_info_alloc = NULL;
list_t *sock_bind_table[UDP_MAX_PORT];
/* Initialize the bindings table */
inline void btable_init(void)
{
// Create the allocator for bind_info elements
bind_info_alloc = udpdk_init_allocator("list_t_alloc", NUM_SOCKETS_MAX, sizeof(struct bind_info));
// All ports are initially free
for (unsigned i = 0; i < UDP_MAX_PORT; i++) {
sock_bind_table[i] = NULL;
}
}
/* Get the index of a free port (-1 if none available) */
inline int btable_get_free_port(void)
{
for (unsigned i = 0; i < UDP_MAX_PORT; i++) {
if (sock_bind_table[i] == NULL) {
return i;
}
}
return -1;
}
/* Verify if binding the pair (ip, port) is possible, provided the
* options and the previous bindings.
*/
static inline int btable_can_bind(struct in_addr ip, int port, int opts)
{
bool reuse_addr = opts & SO_REUSEADDR;
bool reuse_port = opts & SO_REUSEPORT;
bool can_bind = true;
list_iterator_t *it;
list_node_t *node;
unsigned long ip_oth, ip_new;
int opts_oth;
if (sock_bind_table[port] == NULL) {
return 0;
}
ip_new = ip.s_addr;
it = list_iterator_new(sock_bind_table[port], LIST_HEAD);
while ((node = list_iterator_next(it))) {
ip_oth = node->val.ip_addr.s_addr;
opts_oth = node->val.opts;
// If different, and none is INADDR_ANY, continue
if ((ip_oth != ip_new) && (ip_oth != INADDR_ANY) && (ip_new != INADDRY_ANY)) {
continue;
}
// If different, one is INADDR_ANY, and the new has SO_REUSEADDR or SO_REUSEPORT, continue
if ((ip_oth != ip_new) && ((ip_oth == INADDR_ANY) || (ip_new != INADDRY_ANY))
&& ((opts & SO_REUSEADDR) || (opts & SO_REUSEPORT))) {
continue;
}
// If same, not INADDR_ANY and both have SO_REUSEPORT, continue
if ((ip_oth == ip_new) && (ip_new != INADDR_ANY)
&& (opts & SO_REUSEPORT) && (ops_oth & SO_REUSEPORT)) {
continue;
}
can_bind = false;
break;
}
list_iterator_destroy(it);
if (can_bind) {
return 0;
} else {
return -1;
}
}
inline int btable_add_binding(int s, struct in_addr ip, int port, int opts)
{
struct bind_info *b;
list_node_t *ln;
// Check if binding this pair is allowed
if (!btable_can_bind(ip, port, opts)) {
return -1;
}
// Allocate the list if missing
if (sock_bind_table[port] == NULL) {
sock_bind_table[port] = list_new();
}
// Allocate and setup a new bind_info element
b = (struct bind_info)udpdk_shmalloc(bind_info_alloc);
b->sockfd = s;
b->ip_addr = ip;
b->reuse_addr = opts & SO_REUSEADDR;
b->reuse_port = opts & SO_REUSEPORT;
b->closed = false;
// Insert the bind_info in the list
ln = list_node_new(b);
if (ip.s_addr == INADDR_ANY) {
list_lpush(sock_bind_table[port], ln);
} else {
list_rpush(sock_bind_table[port], ln);
}
}
/* Remove a binding from the port */
void btable_del_binding(int s, int port) {
// TODO rimuovi dalla lista
// TODO free bind_info memory
// TODO se la lista è vuota, dealloca la lista -> porta torna libera
}
/* Get all the bind_info descriptors of the sockets bound to the given port */
list_t *btable_get_bindings(int port) {
return sock_bind_table[port];
}
......@@ -3,16 +3,13 @@
// Copyright (c) 2020 Leonardo Lai. All rights reserved.
//
#ifndef UDPDK_LOOKUP_TABLE_H
#define UDPDK_LOOKUP_TABLE_H
#ifndef UDPDK_BIND_TABLE_H
#define UDPDK_BIND_TABLE_H
#include "udpdk_constants.h"
#include "udpdk_types.h"
typedef struct htable_item {
int key;
int val;
} htable_item;
/*
void htable_init(htable_item *table);
int htable_insert(htable_item *table, int key, int val);
......@@ -20,5 +17,16 @@ int htable_insert(htable_item *table, int key, int val);
int htable_lookup(htable_item *table, int key);
int htable_delete(htable_item *table, int key);
*/
void btable_init(void);
int btable_get_free_port(void);
int btable_add_binding(int s, struct in_addr ip, int port, int opts);
void btable_del_binding(int s, int port);
list_t *btable_get_bindings(int port);
#endif //UDPDK_LOOKUP_TABLE_H
#endif //UDPDK_BIND_TABLE_H
......@@ -10,6 +10,7 @@
#define MIN(a,b) ((a) < (b) ? a : b)
#define NUM_SOCKETS_MAX 1024
#define UDP_MAX_PORT 65536
/* DPDK ports */
#define PORT_RX 0
......
......@@ -27,8 +27,6 @@ struct rte_mempool *tx_pktmbuf_direct_pool = NULL;
struct rte_mempool *tx_pktmbuf_indirect_pool = NULL;
htable_item *udp_port_table = NULL;
struct exch_zone_info *exch_zone_desc = NULL;
struct exch_slot *exch_slots = NULL;
\ No newline at end of file
struct exch_slot *exch_slots = NULL;
......@@ -20,6 +20,7 @@
#include <rte_memory.h>
#include <rte_memzone.h>
#include "list.h"
#include "udpdk_api.h"
#include "udpdk_args.h"
#include "udpdk_constants.h"
......@@ -34,7 +35,6 @@
extern int interrupted;
extern struct exch_zone_info *exch_zone_desc;
extern struct exch_slot *exch_slots;
extern htable_item *udp_port_table;
extern struct rte_mempool *rx_pktmbuf_pool;
extern struct rte_mempool *tx_pktmbuf_pool;
extern struct rte_mempool *tx_pktmbuf_direct_pool;
......@@ -303,6 +303,9 @@ int udpdk_init(int argc, char *argv[])
return -1;
}
// Initialize the list allocators
udpdk_list_init();
// Initialize pools of mbuf
retval = init_mbuf_pools();
if (retval < 0) {
......@@ -385,4 +388,6 @@ void udpdk_cleanup(void)
rte_eth_dev_stop(port_id);
rte_eth_dev_close(port_id);
}
}
\ No newline at end of file
udpdk_list_deinit();
}
//
// Created by leoll2 on 9/27/20.
// Copyright (c) 2020 Leonardo Lai. All rights reserved.
//
// Simple hashmap with fixed size, useful to implement L4 port switching.
// Keys and values must be non-negative integers (-1 is reserved for 'empty')
//
#include "udpdk_lookup_table.h"
#define h(x) (9649 * x % NUM_SOCKETS_MAX)
void htable_init(htable_item *table)
{
for (int i = 0; i < NUM_SOCKETS_MAX; i++) {
table[i].key = -1;
}
}
static inline int htable_get_idx(htable_item *table, int key)
{
int i = h(key);
int free_idx = -1;
int scanned = 0;
// find a free slot (linear probing starting from hashed index)
while ((table[i].key != key) && (++scanned < NUM_SOCKETS_MAX)) {
if (free_idx == -1 && table[i].key == -1) {
// store the first free index
free_idx = i;
}
i++;
if (i == NUM_SOCKETS_MAX) {
i = 0;
}
}
// table is full
if (scanned == NUM_SOCKETS_MAX) {
return free_idx;
}
return i;
}
inline int htable_insert(htable_item *table, int key, int val)
{
int i = htable_get_idx(table, key);
if (i == -1) {
// full
return -1;
}
table[i].key = key;
table[i].val = val;
return 0;
}
inline int htable_delete(htable_item *table, int key)
{
int i = htable_get_idx(table, key);
if (i == -1) {
// not found (table full)
return -1;
} else if (table[i].key == -1) {
// not found (table not full)
return -1;
} else {
// remove
table[i].key = -1;
return 0;
}
}
inline int htable_lookup(htable_item *table, int key)
{
int i = htable_get_idx(table, key);
if (i == -1) {
// not found (table full)
return -1;
} else if (table[i].key == -1) {
// not found (table not full)
return -1;
} else {
return table[i].val;
}
}
......@@ -22,9 +22,18 @@
#include <unistd.h>
#include "udpdk_constants.h"
#include "list.h"
enum exch_ring_func {EXCH_RING_RX, EXCH_RING_TX};
struct bind_info {
int sockfd; // socket fd of the (addr, port) pair
struct in_addr ip_addr; // IPv4 address associated to the socket
bool reuse_addr; // SO_REUSEADDR
bool reuse_port; // SO_REUSEPORT
bool closed; // mark this binding as closed
};
struct exch_slot_info {
int used; // used by an open socket
int bound; // used by a socket that did 'bind'
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment