Commit c0cfa6df authored by Antoine Kaufmann's avatar Antoine Kaufmann
Browse files

add ethernet protocol

parent 48328bbb
......@@ -610,7 +610,7 @@ int main(int argc, char *argv[])
di.pci_revision = 0x00;
di.pci_msi_nvecs = 32;
if (nicsim_init(&di, "/tmp/cosim-pci", "/dev/shm/dummy_nic_shm")) {
if (nicsim_init(&di, "/tmp/cosim-pci", NULL, "/dev/shm/dummy_nic_shm")) {
return EXIT_FAILURE;
}
......
......@@ -126,7 +126,7 @@ int main(int argc, char *argv[])
di.pci_revision = 0x00;
di.pci_msi_nvecs = 0x00;
if (nicsim_init(&di, "/tmp/cosim-pci", "/dev/shm/dummy_nic_shm")) {
if (nicsim_init(&di, "/tmp/cosim-pci", NULL, "/dev/shm/dummy_nic_shm")) {
return EXIT_FAILURE;
}
......
......@@ -25,15 +25,25 @@
#define COSIM_NICSIM_H_
#include <cosim_pcie_proto.h>
#include <cosim_eth_proto.h>
int nicsim_init(struct cosim_pcie_proto_dev_intro *di,
const char *uxsocket_path, const char *shm_path);
const char *pci_socket_path, const char *eth_socket_path,
const char *shm_path);
void nicsim_cleanup(void);
volatile union cosim_pcie_proto_h2d *nicif_h2d_poll(void);
void nicif_h2d_done(volatile union cosim_pcie_proto_h2d *msg);
void nicif_h2d_next(void);
volatile union cosim_pcie_proto_d2h *nicsim_d2h_alloc(void);
volatile union cosim_eth_proto_n2d *nicif_n2d_poll(void);
void nicif_n2d_done(volatile union cosim_eth_proto_n2d *msg);
void nicif_n2d_next(void);
volatile union cosim_eth_proto_d2n *nicsim_d2n_alloc(void);
#endif /* ndef COSIM_NICSIM_H_ */
......@@ -25,6 +25,7 @@
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <poll.h>
#include <unistd.h>
#include <nicsim.h>
......@@ -37,63 +38,189 @@
#define H2D_ELEN (4096 + 64)
#define H2D_ENUM 1024
#define D2N_ELEN (2048 + 64)
#define D2N_ENUM 1024
#define N2D_ELEN (2048 + 64)
#define N2D_ENUM 1024
static uint8_t *d2h_queue;
static size_t d2h_pos;
static size_t d2h_off; /* offset in shm region */
static uint8_t *h2d_queue;
static size_t h2d_pos;
static size_t h2d_off; /* offset in shm region */
static uint8_t *d2n_queue;
static size_t d2n_pos;
static size_t d2n_off; /* offset in shm region */
static uint8_t *n2d_queue;
static size_t n2d_pos;
static size_t n2d_off; /* offset in shm region */
static int shm_fd = -1;
static int pci_cfd = -1;
static int eth_cfd = -1;
int nicsim_init(struct cosim_pcie_proto_dev_intro *di,
const char *uxsocket_path, const char *shm_path)
static int accept_pci(struct cosim_pcie_proto_dev_intro *di, int pci_lfd)
{
int shm_fd, pci_lfd;
size_t d2h_off, h2d_off;
void *shmptr;
if ((pci_cfd = accept(pci_lfd, NULL, NULL)) < 0) {
return -1;
}
close(pci_lfd);
printf("pci connection accepted\n");
if ((shm_fd = shm_create(shm_path, 32 * 1024 * 1024, &shmptr)) < 0) {
di->d2h_offset = d2h_off;
di->d2h_elen = D2H_ELEN;
di->d2h_nentries = D2H_ENUM;
di->h2d_offset = h2d_off;
di->h2d_elen = H2D_ELEN;
di->h2d_nentries = H2D_ENUM;
if (uxsocket_send(pci_cfd, di, sizeof(*di), shm_fd)) {
return -1;
}
printf("pci intro sent\n");
return 0;
}
static int accept_eth(int eth_lfd)
{
struct cosim_eth_proto_dev_intro di;
if ((pci_lfd = uxsocket_init(uxsocket_path)) < 0) {
if ((eth_cfd = accept(eth_lfd, NULL, NULL)) < 0) {
return -1;
}
close(eth_lfd);
printf("eth connection accepted\n");
memset(&di, 0, sizeof(di));
di.flags = 0;
di.d2n_offset = d2n_off;
di.d2n_elen = D2N_ELEN;
di.d2n_nentries = D2N_ENUM;
if ((pci_cfd = accept(pci_lfd, NULL, NULL)) < 0) {
di.n2d_offset = n2d_off;
di.n2d_elen = N2D_ELEN;
di.n2d_nentries = N2D_ENUM;
if (uxsocket_send(eth_cfd, &di, sizeof(di), shm_fd)) {
return -1;
}
printf("eth intro sent\n");
return 0;
}
static int accept_conns(struct cosim_pcie_proto_dev_intro *di,
int pci_lfd, int eth_lfd)
{
struct pollfd pfds[2];
int await_pci = pci_lfd != -1;
int await_eth = eth_lfd != -1;
int ret;
while (await_pci || await_eth) {
if (await_pci && await_eth) {
/* we're waiting on both fds */
pfds[0].fd = pci_lfd;
pfds[1].fd = eth_lfd;
pfds[0].events = pfds[1].events = POLLIN;
pfds[0].revents = pfds[1].revents = 0;
ret = poll(pfds, 2, -1);
if (ret < 0) {
perror("poll failed");
return -1;
}
if (pfds[0].revents) {
if (accept_pci(di, pci_lfd) != 0)
return -1;
await_pci = 0;
}
if (pfds[1].revents) {
if (accept_eth(pci_lfd) != 0)
return -1;
await_eth = 0;
}
} else if (await_pci) {
/* waiting just on pci */
if (accept_pci(di, pci_lfd) != 0)
return -1;
await_pci = 0;
} else {
/* waiting just on ethernet */
if (accept_eth(eth_lfd) != 0)
return -1;
await_eth = 0;
}
}
return 0;
}
int nicsim_init(struct cosim_pcie_proto_dev_intro *di,
const char *pci_socket_path, const char *eth_socket_path,
const char *shm_path)
{
int pci_lfd = -1, eth_lfd = -1;
void *shmptr;
/* ready in memory queues */
if ((shm_fd = shm_create(shm_path, 32 * 1024 * 1024, &shmptr)) < 0) {
return -1;
}
close(pci_lfd);
printf("connection accepted\n");
d2h_off = 0;
h2d_off = (uint64_t) D2H_ELEN * D2H_ENUM;
h2d_off = d2h_off + (uint64_t) D2H_ELEN * D2H_ENUM;
d2n_off = h2d_off + (uint64_t) H2D_ELEN * H2D_ENUM;
n2d_off = d2n_off + (uint64_t) D2N_ELEN * D2N_ENUM;
d2h_queue = (uint8_t *) shmptr + d2h_off;
h2d_queue = (uint8_t *) shmptr + h2d_off;
d2n_queue = (uint8_t *) shmptr + d2n_off;
n2d_queue = (uint8_t *) shmptr + n2d_off;
d2h_pos = h2d_pos = 0;
di->d2h_offset = d2h_off;
di->d2h_elen = D2H_ELEN;
di->d2h_nentries = D2H_ENUM;
d2h_pos = h2d_pos = d2n_pos = n2d_pos = 0;
di->h2d_offset = h2d_off;
di->h2d_elen = H2D_ELEN;
di->h2d_nentries = H2D_ENUM;
/* get listening sockets ready */
if (pci_socket_path != NULL) {
if ((pci_lfd = uxsocket_init(pci_socket_path)) < 0) {
return -1;
}
}
if (eth_socket_path != NULL) {
if ((eth_lfd = uxsocket_init(eth_socket_path)) < 0) {
return -1;
}
}
if (uxsocket_send(pci_cfd, di, sizeof(*di), shm_fd)) {
/* accept connection fds */
if (accept_conns(di, pci_lfd, eth_lfd) != 0) {
return -1;
}
printf("connection sent\n");
struct cosim_pcie_proto_host_intro hi;
if (recv(pci_cfd, &hi, sizeof(hi), 0) != sizeof(hi)) {
return -1;
/* receive introductions from other end */
if (pci_socket_path != NULL) {
struct cosim_pcie_proto_host_intro hi;
if (recv(pci_cfd, &hi, sizeof(hi), 0) != sizeof(hi)) {
return -1;
}
printf("pci host info received\n");
}
if (eth_socket_path != NULL) {
struct cosim_eth_proto_net_intro ni;
if (recv(eth_cfd, &ni, sizeof(ni), 0) != sizeof(ni)) {
return -1;
}
printf("eth net info received\n");
}
printf("host info received\n");
return 0;
}
......@@ -101,8 +228,12 @@ int nicsim_init(struct cosim_pcie_proto_dev_intro *di,
void nicsim_cleanup(void)
{
close(pci_cfd);
close(eth_cfd);
}
/******************************************************************************/
/* PCI */
volatile union cosim_pcie_proto_h2d *nicif_h2d_poll(void)
{
volatile union cosim_pcie_proto_h2d *msg =
......@@ -144,3 +275,46 @@ volatile union cosim_pcie_proto_d2h *nicsim_d2h_alloc(void)
return msg;
}
/******************************************************************************/
/* Ethernet */
volatile union cosim_eth_proto_n2d *nicif_n2d_poll(void)
{
volatile union cosim_eth_proto_n2d *msg =
(volatile union cosim_eth_proto_n2d *)
(n2d_queue + n2d_pos * N2D_ELEN);
/* message not ready */
if ((msg->dummy.own_type & COSIM_ETH_PROTO_N2D_OWN_MASK) !=
COSIM_ETH_PROTO_N2D_OWN_DEV)
return NULL;
return msg;
}
void nicif_n2d_done(volatile union cosim_eth_proto_n2d *msg)
{
msg->dummy.own_type = (msg->dummy.own_type & COSIM_ETH_PROTO_N2D_MSG_MASK)
| COSIM_ETH_PROTO_N2D_OWN_NET;
}
void nicif_n2d_next(void)
{
n2d_pos = (n2d_pos + 1) % N2D_ENUM;
}
volatile union cosim_eth_proto_d2n *nicsim_d2n_alloc(void)
{
volatile union cosim_eth_proto_d2n *msg =
(volatile union cosim_eth_proto_d2n *)
(d2n_queue + d2n_pos * D2N_ELEN);
if ((msg->dummy.own_type & COSIM_ETH_PROTO_D2N_OWN_MASK) !=
COSIM_ETH_PROTO_D2N_OWN_DEV)
{
return NULL;
}
d2n_pos = (d2n_pos + 1) % D2N_ENUM;
return msg;
}
#ifndef COSIM_ETH_PROTO_H_
#define COSIM_ETH_PROTO_H_
#include <stdint.h>
/******************************************************************************/
/* Initialization messages on Unix socket */
/** in dev_intro.flags to indicate that sender supports issuing syncs. */
#define COSIM_ETH_PROTO_FLAGS_DI_SYNC (1 << 0)
/**
* welcome message sent by device to network. This message comes with the shared
* memory file descriptor attached.
*/
struct cosim_eth_proto_dev_intro {
/** flags: see COSIM_ETH_PROTO_FLAGS_DI_* */
uint64_t flags;
/** offset of the device-to-network queue in shared memory region */
uint64_t d2n_offset;
/** size of an entry in the device-to-network queue in bytes */
uint64_t d2n_elen;
/** total device-to-network queue length in #entries */
uint64_t d2n_nentries;
/** offset of the net-to-device queue in shared memory region */
uint64_t n2d_offset;
/** size of an entry in the net-to-device queue in bytes */
uint64_t n2d_elen;
/** total net-to-device queue length in #entries */
uint64_t n2d_nentries;
} __attribute__((packed));
#define COSIM_ETH_PROTO_FLAGS_IN_SYNC (1 << 0)
/** welcome message sent by network to device */
struct cosim_eth_proto_net_intro {
/** flags: see COSIM_ETH_PROTO_FLAGS_IN_* */
uint64_t flags;
} __attribute__((packed));
/******************************************************************************/
/* Messages on in-memory device to network channel */
/** Mask for ownership bit in own_type field */
#define COSIM_ETH_PROTO_D2N_OWN_MASK 0x80
/** Message is owned by device */
#define COSIM_ETH_PROTO_D2N_OWN_DEV 0x00
/** Message is owned by network */
#define COSIM_ETH_PROTO_D2N_OWN_NET 0x80
/** Mask for type value in own_type field */
#define COSIM_ETH_PROTO_D2N_MSG_MASK 0x7f
#define COSIM_ETH_PROTO_D2N_MSG_SYNC 0x1
#define COSIM_ETH_PROTO_D2N_MSG_SEND 0x2
struct cosim_eth_proto_d2n_dummy {
uint8_t pad[63];
uint8_t own_type;
} __attribute__((packed));
struct cosim_eth_proto_d2n_sync {
uint64_t timestamp;
uint8_t pad[55];
uint8_t own_type;
} __attribute__((packed));
struct cosim_eth_proto_d2n_send {
uint16_t len;
uint8_t port;
uint8_t pad[60];
uint8_t own_type;
uint8_t data[];
} __attribute__((packed));
union cosim_eth_proto_d2n {
struct cosim_eth_proto_d2n_dummy dummy;
struct cosim_eth_proto_d2n_sync sync;
struct cosim_eth_proto_d2n_send send;
};
/******************************************************************************/
/* Messages on in-memory network to device channel */
#define COSIM_ETH_PROTO_N2D_OWN_MASK 0x80
/** Message is owned by host */
#define COSIM_ETH_PROTO_N2D_OWN_NET 0x00
/** Message is owned by device */
#define COSIM_ETH_PROTO_N2D_OWN_DEV 0x80
#define COSIM_ETH_PROTO_N2D_MSG_MASK 0x7f
#define COSIM_ETH_PROTO_N2D_MSG_SYNC 0x1
#define COSIM_ETH_PROTO_N2D_MSG_RECV 0x2
struct cosim_eth_proto_n2d_dummy {
uint8_t pad[63];
uint8_t own_type;
} __attribute__((packed));
struct cosim_eth_proto_n2d_sync {
uint64_t timestamp;
uint8_t pad[55];
uint8_t own_type;
} __attribute__((packed));
struct cosim_eth_proto_n2d_recv {
uint16_t len;
uint8_t port;
uint8_t pad[60];
uint8_t own_type;
uint8_t data[];
};
union cosim_eth_proto_n2d {
struct cosim_eth_proto_n2d_dummy dummy;
struct cosim_eth_proto_n2d_sync sync;
struct cosim_eth_proto_n2d_recv recv;
};
#endif /* ndef COSIM_ETH_PROTO_H_ */
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