Commit 467cf466 authored by Leonardo Lai's avatar Leonardo Lai

implemented L4 switching table; implemented socket(), bind() and close() primitives

parent 438f2309
......@@ -38,7 +38,10 @@ UDPDK_C= ${CC} -c $(DPDK_CFLAGS) ${CFLAGS} ${WERROR} $<
UDPDK_SRCS+= \
udpdk_syscall.c \
udpdk_init.c \
udpdk_poller.c
udpdk_poller.c \
udpdk_lookup_table.c \
udpdk_globals.c \
SRCS= ${UDPDK_SRCS}
......@@ -70,14 +73,25 @@ install:
rm -rf ${PREFIX_LIB}/libudpdk.a
rm -rf ${PREFIX_INCLUDE}/udpdk_api.h
rm -rf ${PREFIX_INCLUDE}/udpdk_constants.h
rm -rf ${PREFIX_INCLUDE}/udpdk_poller.h
rm -rf ${PREFIX_INCLUDE}/udpdk_types.h
rm -rf ${PREFIX_INCLUDE}/udpdk_lookup_table.h
cp -f libudpdk.a ${PREFIX_LIB}/libudpdk.a.${UDPDK_VERSION}
ln -sf ${PREFIX_LIB}/libudpdk.a.${UDPDK_VERSION} ${PREFIX_LIB}/libudpdk.a
cp -f udpdk_api.h ${PREFIX_INCLUDE}/udpdk_api.h
cp -f udpdk_api.h ${PREFIX_INCLUDE}/udpdk_constants.h
cp -f udpdk_constants.h ${PREFIX_INCLUDE}/udpdk_constants.h
cp -f udpdk_lookup_table.h ${PREFIX_INCLUDE}/udpdk_lookup_table.h
cp -f udpdk_poller.h ${PREFIX_INCLUDE}/udpdk_poller.h
cp -f udpdk_types.h ${PREFIX_INCLUDE}/udpdk_types.h
rm -rf ${PREFIX_INCLUDE}/udpdk_types.h
uninstall:
rm -rf ${PREFIX_LIB}/libudpdk.a.${UDPDK_VERSION}
rm -rf ${PREFIX_LIB}/libudpdk.a
rm -rf ${PREFIX_INCLUDE}/udpdk_api.h
rm -rf ${PREFIX_INCLUDE}/udpdk_constants.h
rm -rf ${PREFIX_INCLUDE}/udpdk_poller.h
rm -rf ${PREFIX_INCLUDE}/udpdk_types.h
rm -rf ${PREFIX_INCLUDE}/udpdk_lookup_table.h
......@@ -8,14 +8,6 @@
#define NUM_SOCKETS_MAX 1024
/* Exchange memzone */
#define EXCH_MEMZONE_NAME "UDPDK_exchange_desc"
#define EXCH_SLOTS_NAME "UDPDK_exchange_slots"
#define EXCH_RING_SIZE 128
#define EXCH_RX_RING_NAME "UDPDK_exchange_ring_%u_RX"
#define EXCH_TX_RING_NAME "UDPDK_exchange_ring_%u_TX"
#define EXCH_BUF_SIZE 32
/* DPDK ports */
#define PORT_RX 0
#define PORT_TX 0
......@@ -34,4 +26,15 @@
#define MAX_FLOW_TTL MS_PER_S
#define IP_FRAG_TBL_BUCKET_ENTRIES 16
/* Exchange memzone */
#define EXCH_MEMZONE_NAME "UDPDK_exchange_desc"
#define EXCH_SLOTS_NAME "UDPDK_exchange_slots"
#define EXCH_RING_SIZE 128
#define EXCH_RX_RING_NAME "UDPDK_exchange_ring_%u_RX"
#define EXCH_TX_RING_NAME "UDPDK_exchange_ring_%u_TX"
#define EXCH_BUF_SIZE 32
/* L4 port switching */
#define UDP_PORT_TABLE_NAME "UDPDK_UDP_port_table"
#endif //UDPDK_CONSTANTS_H
//
// Created by leoll2 on 9/28/20.
// Copyright (c) 2020 Leonardo Lai. All rights reserved.
//
#include "udpdk_lookup_table.h"
#include "udpdk_types.h"
htable_item *udp_port_table = NULL;
struct exch_zone_info *exch_zone_desc = NULL;
......@@ -21,17 +21,16 @@
#include "udpdk_api.h"
#include "udpdk_constants.h"
#include "udpdk_lookup_table.h"
#include "udpdk_poller.h"
#include "udpdk_types.h"
#define RTE_LOGTYPE_INIT RTE_LOGTYPE_USER1
static struct exch_zone_info *exch_zone_desc = NULL;
extern struct exch_zone_info *exch_zone_desc;
struct exch_slot *exch_slots = NULL;
extern htable_item *udp_port_table;
static struct rte_mempool *pktmbuf_pool;
static pid_t poller_pid;
/* Get the name of the rings of exchange slots */
......@@ -181,8 +180,10 @@ static int init_shared_memzone(void)
const struct rte_memzone *mz;
mz = rte_memzone_reserve(EXCH_MEMZONE_NAME, sizeof(*exch_zone_desc), rte_socket_id(), 0);
if (mz == NULL)
if (mz == NULL) {
RTE_LOG(ERR, INIT, "Cannot allocate shared memory for exchange slot descriptors\n");
return -1;
}
memset(mz->addr, 0, sizeof(*exch_zone_desc));
exch_zone_desc = mz->addr;
......@@ -190,6 +191,22 @@ static int init_shared_memzone(void)
return 0;
}
/* Initialize table in shared memory for UDP port switching */
static int init_udp_table(void)
{
const struct rte_memzone *mz;
mz = rte_memzone_reserve(UDP_PORT_TABLE_NAME, NUM_SOCKETS_MAX * sizeof(htable_item), rte_socket_id(), 0);
if (mz == NULL) {
RTE_LOG(ERR, INIT, "Cannot allocate shared memory for UDP port switching table\n");
return -1;
}
udp_port_table = mz->addr;
htable_init(udp_port_table);
return 0;
}
/* Initialize slots to exchange packets between the application and the poller */
static int init_exchange_slots(void)
{
// TODO allocate slots dynamically in udpdk_socket() instead of pre-allocating all them statically
......@@ -270,6 +287,12 @@ int udpdk_init(int argc, char *argv[])
return -1;
}
retval = init_udp_table();
if (retval < 0) {
RTE_LOG(ERR, INIT, "Cannot create table for UDP port switching\n");
return -1;
}
retval = init_exchange_slots();
if (retval < 0) {
RTE_LOG(ERR, INIT, "Cannot initialize exchange slots\n");
......
//
// 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;
}
}
//
// Created by leoll2 on 9/28/20.
// Copyright (c) 2020 Leonardo Lai. All rights reserved.
//
#ifndef UDPDK_LOOKUP_TABLE_H
#define UDPDK_LOOKUP_TABLE_H
#include "udpdk_constants.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);
int htable_lookup(htable_item *table, int key);
int htable_delete(htable_item *table, int key);
#endif //UDPDK_LOOKUP_TABLE_H
......@@ -25,14 +25,16 @@
#include <rte_string_fns.h>
#include "udpdk_constants.h"
#include "udpdk_lookup_table.h"
#include "udpdk_types.h"
#define RTE_LOGTYPE_POLLINIT RTE_LOGTYPE_USER1
static volatile int poller_alive = 1;
static struct exch_zone_info *exch_zone_desc = NULL;
extern struct exch_zone_info *exch_zone_desc;
static struct exch_slot exch_slots[NUM_SOCKETS_MAX];
extern htable_item *udp_port_table;
/* Descriptor of a RX queue */
struct rx_queue {
......@@ -125,6 +127,19 @@ static int setup_exch_zone(void)
return 0;
}
static int setup_udp_table(void)
{
const struct rte_memzone *udp_port_table_mz;
udp_port_table_mz = rte_memzone_lookup(UDP_PORT_TABLE_NAME);
if (udp_port_table_mz == NULL) {
RTE_LOG(ERR, POLLINIT, "Cannot retrieve exchange memzone descriptor\n");
return -1;
}
udp_port_table = udp_port_table_mz->addr;
return 0;
}
/* Initialize UDPDK packet poller (runs in a separate process) */
int poller_init(int argc, char *argv[])
{
......@@ -138,19 +153,26 @@ int poller_init(int argc, char *argv[])
}
// Setup RX/TX queues
setup_queues();
retval = setup_queues();
if (retval < 0) {
RTE_LOG(ERR, POLLINIT, "Cannot setup queues for poller\n");
return -1;
}
// Setup buffers for exchange slots
setup_exch_zone();
retval = setup_exch_zone();
if (retval < 0) {
RTE_LOG(ERR, POLLINIT, "Cannot setup exchange zone for poller\n");
return -1;
}
// Setup table for UDP port switching
retval = setup_udp_table();
if (retval < 0) {
RTE_LOG(ERR, POLLINIT, "Cannot setup table for UDP port switching\n");
return -1;
}
// Setup signals for termination
signal(SIGINT, poller_sighandler);
signal(SIGTERM, poller_sighandler);
......@@ -320,7 +342,7 @@ void poller_body(void)
// Effectively flush the packets to exchange buffers
for (i = 0; i < NUM_SOCKETS_MAX; i++) {
if (exch_zone_desc->slots[i].active) {
if (exch_zone_desc->slots[i].used) {
flush_rx_queue(i);
}
}
......
......@@ -3,18 +3,125 @@
// Copyright (c) 2020 Leonardo Lai. All rights reserved.
//
#include "errno.h"
#include <netinet/in.h>
#include "udpdk_api.h"
#include "udpdk_lookup_table.h"
#define RTE_LOGTYPE_SYSCALL RTE_LOGTYPE_USER1
extern htable_item *udp_port_table;
extern struct exch_zone_info *exch_zone_desc;
static int socket_validate_args(int domain, int type, int protocol)
{
// Domain must be AF_INET (IPv4)
if (domain != AF_INET) {
errno = EAFNOSUPPORT;
RTE_LOG(ERR, SYSCALL, "Attemp to create UDPDK socket of unsupported domain (%d)\n", domain);
return -1;
}
// Type must be DGRAM (UDP)
if (type != SOCK_DGRAM) {
errno = EPROTONOSUPPORT;
RTE_LOG(ERR, SYSCALL, "Attemp to create UDPDK socket of unsupported type (%d)\n", type);
return -1;
}
// Protocol must be 0
if (protocol != 0) {
errno = EINVAL;
RTE_LOG(ERR, SYSCALL, "Attemp to create UDPDK socket of unsupported protocol (%d)\n", protocol);
return -1;
}
return 0;
}
int udpdk_socket(int domain, int type, int protocol)
{
// TODO implement
int sock_id;
// Validate the arguments
if (socket_validate_args(domain, type, protocol) < 0) {
return -1;
}
// Fail if reached the maximum number of open sockets
if (exch_zone_desc->n_zones_active > NUM_SOCKETS_MAX) {
errno = ENOBUFS;
return -1;
}
// Allocate a free sock_id
for (sock_id = 0; sock_id < NUM_SOCKETS_MAX; sock_id++) {
if (!exch_zone_desc->slots[sock_id].used) {
exch_zone_desc->slots[sock_id].used = 1;
exch_zone_desc->slots[sock_id].bound = 0;
exch_zone_desc->slots[sock_id].sockfd = sock_id;
break;
}
}
if (sock_id == NUM_SOCKETS_MAX) {
// Could not find a free slot
errno = ENOBUFS;
RTE_LOG(ERR, SYSCALL, "Failed to allocate a descriptor for socket (%d)\n", sock_id);
return -1;
}
// Increment counter in exch_zone_desc
exch_zone_desc->n_zones_active++;
return sock_id;
}
static int bind_validate_args(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
{
// Check if the sockfd is valid
if (!exch_zone_desc->slots[sockfd].used) {
errno = EBADF;
return -1;
}
// Check if already bound
if (exch_zone_desc->slots[sockfd].bound) {
errno = EINVAL;
return -1;
}
// Validate addr
if (addr->sa_family != AF_INET) {
errno = EINVAL;
return -1;
}
// Validate addr len
if (addrlen != sizeof(struct sockaddr_in)) {
errno = EINVAL;
return -1;
}
return 0;
}
int udpdk_bind(int s, const struct sockaddr *addr, socklen_t addrlen)
int udpdk_bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
{
// TODO implement
int ret;
unsigned short port;
const struct sockaddr_in *addr_in = (struct sockaddr_in *)addr;
// Validate the arguments
if (bind_validate_args(sockfd, addr, addrlen) < 0) {
return -1;
}
port = addr_in->sin_port;
ret = htable_lookup(udp_port_table, port);
if (ret != -1) {
errno = EINVAL;
RTE_LOG(ERR, SYSCALL, "Failed to bind because port %d is already in use\n", port);
return -1;
}
// Mark the slot as bound
exch_zone_desc->slots[sockfd].bound = 1;
// Insert in the hashtable (port, sock_id)
htable_insert(udp_port_table, (int)port, sockfd);
return 0;
}
......@@ -32,8 +139,29 @@ ssize_t udpdk_recvfrom(int s, void *buf, size_t len, int flags,
return 0;
}
static int close_validate_args(int s)
{
// Check if the socket is open
if (!exch_zone_desc->slots[s].used) {
errno = EBADF;
RTE_LOG(ERR, SYSCALL, "Failed to close socket %d because it was not open\n", s);
return -1;
}
return 0;
}
int udpdk_close(int s)
{
// TODO implement
// Validate the arguments
if (close_validate_args(s)) {
return -1;
}
// Reset slot
exch_zone_desc->slots[s].bound = 0;
exch_zone_desc->slots[s].used = 0;
// Decrement counter of active slots
exch_zone_desc->n_zones_active++;
return 0;
}
\ No newline at end of file
}
......@@ -6,7 +6,7 @@
#ifndef UDPDK_TYPES_H
#define UDPDK_TYPES_H
#include <rte_common.h>
//#include <rte_common.h>
#include <rte_eal.h>
#include <rte_ethdev.h>
#include <rte_launch.h>
......@@ -25,8 +25,9 @@
enum exch_ring_func {EXCH_RING_RX, EXCH_RING_TX};
struct exch_slot_info {
int active;
int sockfd;
int used; // used by an open socket
int bound; // used by a socket that did 'bind'
int sockfd; // TODO redundant because it matches the slot index in this implementation
} __rte_cache_aligned;
struct exch_zone_info {
......
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