network: improve throughput by batch processing packets
This commit is contained in:
@@ -56,7 +56,9 @@
|
|||||||
#define NET_TYPE_PCAP 2 /* use the (Win)Pcap API */
|
#define NET_TYPE_PCAP 2 /* use the (Win)Pcap API */
|
||||||
|
|
||||||
#define NET_MAX_FRAME 1518
|
#define NET_MAX_FRAME 1518
|
||||||
#define NET_QUEUE_LEN 8
|
/* Queue size must be a power of 2 */
|
||||||
|
#define NET_QUEUE_LEN 16
|
||||||
|
#define NET_QUEUE_LEN_MASK (NET_QUEUE_LEN - 1)
|
||||||
#define NET_CARD_MAX 4
|
#define NET_CARD_MAX 4
|
||||||
#define NET_HOST_INTF_MAX 64
|
#define NET_HOST_INTF_MAX 64
|
||||||
|
|
||||||
@@ -92,12 +94,10 @@ typedef int (*NETSETLINKSTATE)(void *);
|
|||||||
typedef struct netpkt {
|
typedef struct netpkt {
|
||||||
uint8_t *data;
|
uint8_t *data;
|
||||||
int len;
|
int len;
|
||||||
uint64_t tsc;
|
|
||||||
} netpkt_t;
|
} netpkt_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
netpkt_t packets[NET_QUEUE_LEN];
|
netpkt_t packets[NET_QUEUE_LEN];
|
||||||
int size;
|
|
||||||
int head;
|
int head;
|
||||||
int tail;
|
int tail;
|
||||||
} netqueue_t;
|
} netqueue_t;
|
||||||
@@ -165,7 +165,9 @@ extern int network_card_get_from_internal_name(char *);
|
|||||||
extern const device_t *network_card_getdevice(int);
|
extern const device_t *network_card_getdevice(int);
|
||||||
|
|
||||||
extern int network_tx_pop(netcard_t *card, netpkt_t *out_pkt);
|
extern int network_tx_pop(netcard_t *card, netpkt_t *out_pkt);
|
||||||
|
extern int network_tx_popv(netcard_t *card, netpkt_t *pkt_vec, int vec_size);
|
||||||
extern int network_rx_put(netcard_t *card, uint8_t *bufp, int len);
|
extern int network_rx_put(netcard_t *card, uint8_t *bufp, int len);
|
||||||
|
extern int network_rx_put_pkt(netcard_t *card, netpkt_t *pkt);
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@@ -72,6 +72,8 @@
|
|||||||
#include <86box/network.h>
|
#include <86box/network.h>
|
||||||
#include <86box/net_event.h>
|
#include <86box/net_event.h>
|
||||||
|
|
||||||
|
#define PCAP_PKT_BATCH NET_QUEUE_LEN
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
NET_EVENT_STOP = 0,
|
NET_EVENT_STOP = 0,
|
||||||
NET_EVENT_TX,
|
NET_EVENT_TX,
|
||||||
@@ -120,6 +122,17 @@ struct pcap_if {
|
|||||||
void *addresses;
|
void *addresses;
|
||||||
bpf_u_int32 flags;
|
bpf_u_int32 flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct pcap_send_queue {
|
||||||
|
u_int maxlen; /* Maximum size of the queue, in bytes. This
|
||||||
|
variable contains the size of the buffer field. */
|
||||||
|
u_int len; /* Current size of the queue, in bytes. */
|
||||||
|
char *buffer; /* Buffer containing the packets to be sent. */
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct pcap_send_queue pcap_send_queue;
|
||||||
|
|
||||||
|
typedef void (*pcap_handler)(u_char *user, const struct pcap_pkthdr *h, const u_char *bytes);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -129,7 +142,11 @@ typedef struct {
|
|||||||
net_evt_t tx_event;
|
net_evt_t tx_event;
|
||||||
net_evt_t stop_event;
|
net_evt_t stop_event;
|
||||||
netpkt_t pkt;
|
netpkt_t pkt;
|
||||||
|
netpkt_t pktv[PCAP_PKT_BATCH];
|
||||||
uint8_t mac_addr[6];
|
uint8_t mac_addr[6];
|
||||||
|
#ifdef _WIN32
|
||||||
|
struct pcap_send_queue *pcap_queue;
|
||||||
|
#endif
|
||||||
} net_pcap_t;
|
} net_pcap_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -154,11 +171,16 @@ static int (*f_pcap_setnonblock)(void*, int, char*);
|
|||||||
static int (*f_pcap_set_immediate_mode)(void *, int);
|
static int (*f_pcap_set_immediate_mode)(void *, int);
|
||||||
static int (*f_pcap_set_promisc)(void *, int);
|
static int (*f_pcap_set_promisc)(void *, int);
|
||||||
static int (*f_pcap_set_snaplen)(void *, int);
|
static int (*f_pcap_set_snaplen)(void *, int);
|
||||||
|
static int (*f_pcap_dispatch)(void *, int, pcap_handler callback, u_char *user);
|
||||||
static void *(*f_pcap_create)(const char *, char*);
|
static void *(*f_pcap_create)(const char *, char*);
|
||||||
static int (*f_pcap_activate)(void *);
|
static int (*f_pcap_activate)(void *);
|
||||||
static void *(*f_pcap_geterr)(void *);
|
static void *(*f_pcap_geterr)(void *);
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
static HANDLE (*f_pcap_getevent)(void *);
|
static HANDLE (*f_pcap_getevent)(void *);
|
||||||
|
static int (*f_pcap_sendqueue_queue)(void *, void *, void *);
|
||||||
|
static u_int (*f_pcap_sendqueue_transmit)(void *, void *, int sync);
|
||||||
|
static void *(*f_pcap_sendqueue_alloc)(u_int memsize);
|
||||||
|
static void (*f_pcap_sendqueue_destroy)(void *);
|
||||||
#else
|
#else
|
||||||
static int (*f_pcap_get_selectable_fd)(void *);
|
static int (*f_pcap_get_selectable_fd)(void *);
|
||||||
#endif
|
#endif
|
||||||
@@ -177,13 +199,18 @@ static dllimp_t pcap_imports[] = {
|
|||||||
{ "pcap_set_immediate_mode", &f_pcap_set_immediate_mode},
|
{ "pcap_set_immediate_mode", &f_pcap_set_immediate_mode},
|
||||||
{ "pcap_set_promisc", &f_pcap_set_promisc },
|
{ "pcap_set_promisc", &f_pcap_set_promisc },
|
||||||
{ "pcap_set_snaplen", &f_pcap_set_snaplen },
|
{ "pcap_set_snaplen", &f_pcap_set_snaplen },
|
||||||
|
{ "pcap_dispatch", &f_pcap_dispatch },
|
||||||
{ "pcap_create", &f_pcap_create },
|
{ "pcap_create", &f_pcap_create },
|
||||||
{ "pcap_activate", &f_pcap_activate },
|
{ "pcap_activate", &f_pcap_activate },
|
||||||
{ "pcap_geterr", &f_pcap_geterr },
|
{ "pcap_geterr", &f_pcap_geterr },
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
{ "pcap_getevent", &f_pcap_getevent },
|
{ "pcap_getevent", &f_pcap_getevent },
|
||||||
|
{ "pcap_sendqueue_queue", &f_pcap_sendqueue_queue },
|
||||||
|
{ "pcap_sendqueue_transmit", &f_pcap_sendqueue_transmit},
|
||||||
|
{ "pcap_sendqueue_alloc", &f_pcap_sendqueue_alloc },
|
||||||
|
{ "pcap_sendqueue_destroy", &f_pcap_sendqueue_destroy },
|
||||||
#else
|
#else
|
||||||
{ "pcap_get_selectable_fd", &f_pcap_get_selectable_fd },
|
{ "pcap_get_selectable_fd", &f_pcap_get_selectable_fd },
|
||||||
#endif
|
#endif
|
||||||
{ NULL, NULL },
|
{ NULL, NULL },
|
||||||
};
|
};
|
||||||
@@ -208,15 +235,12 @@ pcap_log(const char *fmt, ...)
|
|||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
net_pcap_read_packet(net_pcap_t *pcap)
|
net_pcap_rx_handler(uint8_t *user, const struct pcap_pkthdr *h, const uint8_t *bytes)
|
||||||
{
|
{
|
||||||
struct pcap_pkthdr h;
|
net_pcap_t *pcap = (net_pcap_t*)user;
|
||||||
|
memcpy(pcap->pkt.data, bytes, h->caplen);
|
||||||
uint8_t *data = (uint8_t *) f_pcap_next((void *) pcap->pcap, &h);
|
pcap->pkt.len = h->caplen;
|
||||||
if (!data)
|
network_rx_put_pkt(pcap->card, &pcap->pkt);
|
||||||
return;
|
|
||||||
|
|
||||||
network_rx_put(pcap->card, data, h.caplen);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Send a packet to the Pcap interface. */
|
/* Send a packet to the Pcap interface. */
|
||||||
@@ -251,6 +275,7 @@ net_pcap_thread(void *priv)
|
|||||||
|
|
||||||
bool run = true;
|
bool run = true;
|
||||||
|
|
||||||
|
struct pcap_pkthdr h;
|
||||||
while (run) {
|
while (run) {
|
||||||
int ret = WaitForMultipleObjects(NET_EVENT_MAX, events, FALSE, INFINITE);
|
int ret = WaitForMultipleObjects(NET_EVENT_MAX, events, FALSE, INFINITE);
|
||||||
|
|
||||||
@@ -262,13 +287,17 @@ net_pcap_thread(void *priv)
|
|||||||
|
|
||||||
case NET_EVENT_TX:
|
case NET_EVENT_TX:
|
||||||
net_event_clear(&pcap->tx_event);
|
net_event_clear(&pcap->tx_event);
|
||||||
while (network_tx_pop(pcap->card, &pcap->pkt)) {
|
int packets = network_tx_popv(pcap->card, pcap->pktv, PCAP_PKT_BATCH);
|
||||||
net_pcap_in(pcap->pcap, pcap->pkt.data, pcap->pkt.len);
|
for (int i = 0; i < packets; i++) {
|
||||||
|
h.caplen = pcap->pktv[i].len;
|
||||||
|
f_pcap_sendqueue_queue(pcap->pcap_queue, &h, pcap->pktv[i].data);
|
||||||
}
|
}
|
||||||
|
f_pcap_sendqueue_transmit(pcap->pcap, pcap->pcap_queue, 0);
|
||||||
|
pcap->pcap_queue->len = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NET_EVENT_RX:
|
case NET_EVENT_RX:
|
||||||
net_pcap_read_packet(pcap);
|
f_pcap_dispatch(pcap->pcap, PCAP_PKT_BATCH, net_pcap_rx_handler, (u_char *)pcap);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -305,13 +334,14 @@ net_pcap_thread(void *priv)
|
|||||||
if (pfd[NET_EVENT_TX].revents & POLLIN) {
|
if (pfd[NET_EVENT_TX].revents & POLLIN) {
|
||||||
net_event_clear(&pcap->tx_event);
|
net_event_clear(&pcap->tx_event);
|
||||||
|
|
||||||
if (network_tx_pop(pcap->card, &pcap->pkt)) {
|
int packets = network_tx_popv(pcap->card, pcap->pktv, PCAP_PKT_BATCH);
|
||||||
net_pcap_in(pcap->pcap, pcap->pkt.data, pcap->pkt.len);
|
for (int i = 0; i < packets; i++) {
|
||||||
|
net_pcap_in(pcap->pcap, pcap->pktv[i].data, pcap->pktv[i].len);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pfd[NET_EVENT_RX].revents & POLLIN) {
|
if (pfd[NET_EVENT_RX].revents & POLLIN) {
|
||||||
net_pcap_read_packet(pcap);
|
f_pcap_dispatch(pcap->pcap, PCAP_PKT_BATCH, net_pcap_rx_handler, (u_char *)pcap);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -470,7 +500,15 @@ net_pcap_init(const netcard_t *card, const uint8_t *mac_addr, void *priv)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
pcap->pcap_queue = f_pcap_sendqueue_alloc(PCAP_PKT_BATCH * NET_MAX_FRAME);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
for (int i = 0; i < PCAP_PKT_BATCH; i++) {
|
||||||
|
pcap->pktv[i].data = calloc(1, NET_MAX_FRAME);
|
||||||
|
}
|
||||||
pcap->pkt.data = calloc(1, NET_MAX_FRAME);
|
pcap->pkt.data = calloc(1, NET_MAX_FRAME);
|
||||||
|
|
||||||
net_event_init(&pcap->tx_event);
|
net_event_init(&pcap->tx_event);
|
||||||
net_event_init(&pcap->stop_event);
|
net_event_init(&pcap->stop_event);
|
||||||
pcap->poll_tid = thread_create(net_pcap_thread, pcap);
|
pcap->poll_tid = thread_create(net_pcap_thread, pcap);
|
||||||
@@ -497,8 +535,14 @@ net_pcap_close(void *priv)
|
|||||||
thread_wait(pcap->poll_tid);
|
thread_wait(pcap->poll_tid);
|
||||||
pcap_log("PCAP: thread ended\n");
|
pcap_log("PCAP: thread ended\n");
|
||||||
|
|
||||||
|
for (int i = 0; i < PCAP_PKT_BATCH; i++) {
|
||||||
|
free(pcap->pktv[i].data);
|
||||||
|
}
|
||||||
free(pcap->pkt.data);
|
free(pcap->pkt.data);
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
f_pcap_sendqueue_destroy((void*)pcap->pcap_queue);
|
||||||
|
#endif
|
||||||
/* OK, now shut down Pcap itself. */
|
/* OK, now shut down Pcap itself. */
|
||||||
f_pcap_close((void*)pcap->pcap);
|
f_pcap_close((void*)pcap->pcap);
|
||||||
|
|
||||||
|
@@ -45,6 +45,8 @@
|
|||||||
#endif
|
#endif
|
||||||
#include <86box/net_event.h>
|
#include <86box/net_event.h>
|
||||||
|
|
||||||
|
#define SLIRP_PKT_BATCH NET_QUEUE_LEN
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
NET_EVENT_STOP = 0,
|
NET_EVENT_STOP = 0,
|
||||||
NET_EVENT_TX,
|
NET_EVENT_TX,
|
||||||
@@ -60,6 +62,7 @@ typedef struct {
|
|||||||
net_evt_t tx_event;
|
net_evt_t tx_event;
|
||||||
net_evt_t stop_event;
|
net_evt_t stop_event;
|
||||||
netpkt_t pkt;
|
netpkt_t pkt;
|
||||||
|
netpkt_t pkt_tx_v[SLIRP_PKT_BATCH];
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
HANDLE sock_event;
|
HANDLE sock_event;
|
||||||
#else
|
#else
|
||||||
@@ -153,22 +156,12 @@ ssize_t
|
|||||||
net_slirp_send_packet(const void *qp, size_t pkt_len, void *opaque)
|
net_slirp_send_packet(const void *qp, size_t pkt_len, void *opaque)
|
||||||
{
|
{
|
||||||
net_slirp_t *slirp = (net_slirp_t *) opaque;
|
net_slirp_t *slirp = (net_slirp_t *) opaque;
|
||||||
uint8_t *mac = slirp->mac_addr;
|
|
||||||
uint32_t mac_cmp32[2];
|
|
||||||
uint16_t mac_cmp16[2];
|
|
||||||
|
|
||||||
slirp_log("SLiRP: received %d-byte packet\n", pkt_len);
|
slirp_log("SLiRP: received %d-byte packet\n", pkt_len);
|
||||||
|
|
||||||
/* Received MAC. */
|
memcpy(slirp->pkt.data, (uint8_t*) qp, pkt_len);
|
||||||
mac_cmp32[0] = *(uint32_t *) (((uint8_t *) qp) + 6);
|
slirp->pkt.len = pkt_len;
|
||||||
mac_cmp16[0] = *(uint16_t *) (((uint8_t *) qp) + 10);
|
network_rx_put_pkt(slirp->card, &slirp->pkt);
|
||||||
|
|
||||||
/* Local MAC. */
|
|
||||||
mac_cmp32[1] = *(uint32_t *) mac;
|
|
||||||
mac_cmp16[1] = *(uint16_t *) (mac + 4);
|
|
||||||
if ((mac_cmp32[0] != mac_cmp32[1]) || (mac_cmp16[0] != mac_cmp16[1])) {
|
|
||||||
network_rx_put(slirp->card, (uint8_t *) qp, pkt_len);
|
|
||||||
}
|
|
||||||
|
|
||||||
return pkt_len;
|
return pkt_len;
|
||||||
}
|
}
|
||||||
@@ -336,8 +329,9 @@ net_slirp_thread(void *priv)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case NET_EVENT_TX:
|
case NET_EVENT_TX:
|
||||||
while (network_tx_pop(slirp->card, &slirp->pkt)) {
|
int packets = network_tx_popv(slirp->card, slirp->pkt_tx_v, SLIRP_PKT_BATCH);
|
||||||
net_slirp_in(slirp, slirp->pkt.data, slirp->pkt.len);
|
for (int i = 0; i < packets; i++) {
|
||||||
|
net_slirp_in(slirp, slirp->pkt_tx_v[i].data, slirp->pkt_tx_v[i].len);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -381,11 +375,11 @@ net_slirp_thread(void *priv)
|
|||||||
if (slirp->pfd[NET_EVENT_TX].revents & POLLIN) {
|
if (slirp->pfd[NET_EVENT_TX].revents & POLLIN) {
|
||||||
net_event_clear(&slirp->tx_event);
|
net_event_clear(&slirp->tx_event);
|
||||||
|
|
||||||
if (network_tx_pop(slirp->card, &slirp->pkt)) {
|
int packets = network_tx_popv(slirp->card, slirp->pkt_tx_v, SLIRP_PKT_BATCH);
|
||||||
net_slirp_in(slirp, slirp->pkt.data, slirp->pkt.len);
|
for (int i = 0; i < packets; i++) {
|
||||||
|
net_slirp_in(slirp, slirp->pkt_tx_v[i].data, slirp->pkt_tx_v[i].len);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
slirp_log("SLiRP: polling stopped.\n");
|
slirp_log("SLiRP: polling stopped.\n");
|
||||||
@@ -453,6 +447,9 @@ net_slirp_init(const netcard_t *card, const uint8_t *mac_addr, void *priv)
|
|||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < SLIRP_PKT_BATCH; i++) {
|
||||||
|
slirp->pkt_tx_v[i].data = calloc(1, NET_MAX_FRAME);
|
||||||
|
}
|
||||||
slirp->pkt.data = calloc(1, NET_MAX_FRAME);
|
slirp->pkt.data = calloc(1, NET_MAX_FRAME);
|
||||||
net_event_init(&slirp->tx_event);
|
net_event_init(&slirp->tx_event);
|
||||||
net_event_init(&slirp->stop_event);
|
net_event_init(&slirp->stop_event);
|
||||||
@@ -485,6 +482,9 @@ net_slirp_close(void *priv)
|
|||||||
net_event_close(&slirp->tx_event);
|
net_event_close(&slirp->tx_event);
|
||||||
net_event_close(&slirp->stop_event);
|
net_event_close(&slirp->stop_event);
|
||||||
slirp_cleanup(slirp->slirp);
|
slirp_cleanup(slirp->slirp);
|
||||||
|
for (int i = 0; i < SLIRP_PKT_BATCH; i++) {
|
||||||
|
free(slirp->pkt_tx_v[i].data);
|
||||||
|
}
|
||||||
free(slirp->pkt.data);
|
free(slirp->pkt.data);
|
||||||
free(slirp);
|
free(slirp);
|
||||||
slirp_card_num--;
|
slirp_card_num--;
|
||||||
|
@@ -240,12 +240,11 @@ network_init(void)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
void
|
||||||
network_queue_init(netqueue_t *queue)
|
network_queue_init(netqueue_t *queue)
|
||||||
{
|
{
|
||||||
queue->size = NET_QUEUE_LEN;
|
|
||||||
queue->head = queue->tail = 0;
|
queue->head = queue->tail = 0;
|
||||||
for (int i=0; i<queue->size; i++) {
|
for (int i=0; i<NET_QUEUE_LEN; i++) {
|
||||||
queue->packets[i].data = calloc(1, NET_MAX_FRAME);
|
queue->packets[i].data = calloc(1, NET_MAX_FRAME);
|
||||||
queue->packets[i].len = 0;
|
queue->packets[i].len = 0;
|
||||||
}
|
}
|
||||||
@@ -255,7 +254,7 @@ network_queue_init(netqueue_t *queue)
|
|||||||
static bool
|
static bool
|
||||||
network_queue_full(netqueue_t *queue)
|
network_queue_full(netqueue_t *queue)
|
||||||
{
|
{
|
||||||
return ((queue->head + 1) % queue->size) == queue->tail;
|
return ((queue->head + 1) & NET_QUEUE_LEN_MASK) == queue->tail;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
@@ -264,30 +263,50 @@ network_queue_empty(netqueue_t *queue)
|
|||||||
return (queue->head == queue->tail);
|
return (queue->head == queue->tail);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
network_swap_packet(netpkt_t *pkt1, netpkt_t *pkt2)
|
||||||
|
{
|
||||||
|
netpkt_t tmp = *pkt2;
|
||||||
|
*pkt2 = *pkt1;
|
||||||
|
*pkt1 = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
network_queue_put(netqueue_t *queue, uint8_t *data, int len)
|
network_queue_put(netqueue_t *queue, uint8_t *data, int len)
|
||||||
{
|
{
|
||||||
if (len > NET_MAX_FRAME || network_queue_full(queue)) {
|
if (len == 0 || len > NET_MAX_FRAME || network_queue_full(queue)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
netpkt_t *pkt = &queue->packets[queue->head];
|
netpkt_t *pkt = &queue->packets[queue->head];
|
||||||
memcpy(pkt->data, data, len);
|
memcpy(pkt->data, data, len);
|
||||||
pkt->len = len;
|
pkt->len = len;
|
||||||
queue->head = (queue->head + 1) % queue->size;
|
queue->head = (queue->head + 1) & NET_QUEUE_LEN_MASK;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
network_queue_put_swap(netqueue_t *queue, netpkt_t *src_pkt)
|
||||||
|
{
|
||||||
|
if (src_pkt->len == 0 || src_pkt->len > NET_MAX_FRAME || network_queue_full(queue)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
netpkt_t *dst_pkt = &queue->packets[queue->head];
|
||||||
|
network_swap_packet(src_pkt, dst_pkt);
|
||||||
|
|
||||||
|
queue->head = (queue->head + 1) & NET_QUEUE_LEN_MASK;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
network_queue_get(netqueue_t *queue, netpkt_t *dst_pkt) {
|
network_queue_get_swap(netqueue_t *queue, netpkt_t *dst_pkt) {
|
||||||
if (network_queue_empty(queue))
|
if (network_queue_empty(queue))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
netpkt_t *pkt = &queue->packets[queue->tail];
|
netpkt_t *src_pkt = &queue->packets[queue->tail];
|
||||||
memcpy(dst_pkt->data, pkt->data, pkt->len);
|
network_swap_packet(src_pkt, dst_pkt);
|
||||||
dst_pkt->len = pkt->len;
|
queue->tail = (queue->tail + 1) & NET_QUEUE_LEN_MASK;
|
||||||
queue->tail = (queue->tail + 1) % queue->size;
|
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -303,23 +322,18 @@ network_queue_move(netqueue_t *dst_q, netqueue_t *src_q)
|
|||||||
|
|
||||||
netpkt_t *src_pkt = &src_q->packets[src_q->tail];
|
netpkt_t *src_pkt = &src_q->packets[src_q->tail];
|
||||||
netpkt_t *dst_pkt = &dst_q->packets[dst_q->head];
|
netpkt_t *dst_pkt = &dst_q->packets[dst_q->head];
|
||||||
uint8_t *tmp_dat = dst_pkt->data;
|
|
||||||
|
|
||||||
dst_pkt->data = src_pkt->data;
|
network_swap_packet(src_pkt, dst_pkt);
|
||||||
dst_pkt->len = src_pkt->len;
|
dst_q->head = (dst_q->head + 1) & NET_QUEUE_LEN_MASK;
|
||||||
dst_q->head = (dst_q->head + 1) % dst_q->size;
|
src_q->tail = (src_q->tail + 1) & NET_QUEUE_LEN_MASK;
|
||||||
|
|
||||||
src_pkt->data = tmp_dat;
|
return dst_pkt->len;
|
||||||
src_pkt->len = 0;
|
|
||||||
src_q->tail = (src_q->tail + 1) % src_q->size;
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
void
|
||||||
network_queue_clear(netqueue_t *queue)
|
network_queue_clear(netqueue_t *queue)
|
||||||
{
|
{
|
||||||
for (int i=0; i<queue->size; i++) {
|
for (int i=0; i<NET_QUEUE_LEN; i++) {
|
||||||
free(queue->packets[i].data);
|
free(queue->packets[i].data);
|
||||||
queue->packets[i].len = 0;
|
queue->packets[i].len = 0;
|
||||||
}
|
}
|
||||||
@@ -331,41 +345,47 @@ static void
|
|||||||
network_rx_queue(void *priv)
|
network_rx_queue(void *priv)
|
||||||
{
|
{
|
||||||
netcard_t *card = (netcard_t *)priv;
|
netcard_t *card = (netcard_t *)priv;
|
||||||
double timer_period;
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
bool activity = false;
|
uint32_t rx_bytes = 0;
|
||||||
|
for (int i = 0; i < NET_QUEUE_LEN; i++) {
|
||||||
|
if (card->queued_pkt.len == 0) {
|
||||||
|
thread_wait_mutex(card->rx_mutex);
|
||||||
|
int res = network_queue_get_swap(&card->queues[NET_QUEUE_RX], &card->queued_pkt);
|
||||||
|
thread_release_mutex(card->rx_mutex);
|
||||||
|
if (!res)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (card->queued_pkt.len == 0) {
|
|
||||||
thread_wait_mutex(card->rx_mutex);
|
|
||||||
network_queue_get(&card->queues[NET_QUEUE_RX], &card->queued_pkt);
|
|
||||||
thread_release_mutex(card->rx_mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (card->queued_pkt.len > 0) {
|
|
||||||
network_dump_packet(&card->queued_pkt);
|
network_dump_packet(&card->queued_pkt);
|
||||||
ret = card->rx(card->card_drv, card->queued_pkt.data, card->queued_pkt.len);
|
int res = card->rx(card->card_drv, card->queued_pkt.data, card->queued_pkt.len);
|
||||||
}
|
if (!res)
|
||||||
|
break;
|
||||||
if (ret) {
|
rx_bytes += card->queued_pkt.len;
|
||||||
activity = true;
|
|
||||||
timer_period = 0.762939453125 * ((card->queued_pkt.len >= 128) ? ((double) card->queued_pkt.len) : 128.0);
|
|
||||||
card->queued_pkt.len = 0;
|
card->queued_pkt.len = 0;
|
||||||
} else {
|
|
||||||
timer_period = 0.762939453125 * 128.0;
|
|
||||||
}
|
}
|
||||||
timer_on_auto(&card->timer, timer_period);
|
|
||||||
|
|
||||||
/* Transmission. */
|
/* Transmission. */
|
||||||
|
uint32_t tx_bytes = 0;
|
||||||
thread_wait_mutex(card->tx_mutex);
|
thread_wait_mutex(card->tx_mutex);
|
||||||
ret = network_queue_move(&card->queues[NET_QUEUE_TX_HOST], &card->queues[NET_QUEUE_TX_VM]);
|
for (int i = 0; i < NET_QUEUE_LEN; i++) {
|
||||||
|
uint32_t bytes = network_queue_move(&card->queues[NET_QUEUE_TX_HOST], &card->queues[NET_QUEUE_TX_VM]);
|
||||||
|
if (!bytes)
|
||||||
|
break;
|
||||||
|
tx_bytes += bytes;
|
||||||
|
}
|
||||||
thread_release_mutex(card->tx_mutex);
|
thread_release_mutex(card->tx_mutex);
|
||||||
if (ret) {
|
if (tx_bytes) {
|
||||||
/* Notify host that a packet is available in the TX queue */
|
/* Notify host that a packet is available in the TX queue */
|
||||||
card->host_drv.notify_in(card->host_drv.priv);
|
card->host_drv.notify_in(card->host_drv.priv);
|
||||||
activity = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double timer_period = 0.762939453125 * (rx_bytes > tx_bytes ? rx_bytes : tx_bytes);
|
||||||
|
if (timer_period < 200)
|
||||||
|
timer_period = 200;
|
||||||
|
|
||||||
|
timer_on_auto(&card->timer, timer_period);
|
||||||
|
|
||||||
|
bool activity = rx_bytes || tx_bytes;
|
||||||
ui_sb_update_icon(SB_NETWORK, activity);
|
ui_sb_update_icon(SB_NETWORK, activity);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -498,12 +518,29 @@ int network_tx_pop(netcard_t *card, netpkt_t *out_pkt)
|
|||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
thread_wait_mutex(card->tx_mutex);
|
thread_wait_mutex(card->tx_mutex);
|
||||||
ret = network_queue_get(&card->queues[NET_QUEUE_TX_HOST], out_pkt);
|
ret = network_queue_get_swap(&card->queues[NET_QUEUE_TX_HOST], out_pkt);
|
||||||
thread_release_mutex(card->tx_mutex);
|
thread_release_mutex(card->tx_mutex);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int network_tx_popv(netcard_t *card, netpkt_t *pkt_vec, int vec_size)
|
||||||
|
{
|
||||||
|
int pkt_count = 0;
|
||||||
|
|
||||||
|
netqueue_t *queue = &card->queues[NET_QUEUE_TX_HOST];
|
||||||
|
thread_wait_mutex(card->tx_mutex);
|
||||||
|
for (int i = 0; i < vec_size; i++) {
|
||||||
|
if (!network_queue_get_swap(queue, pkt_vec))
|
||||||
|
break;
|
||||||
|
pkt_count++;
|
||||||
|
pkt_vec++;
|
||||||
|
}
|
||||||
|
thread_release_mutex(card->tx_mutex);
|
||||||
|
|
||||||
|
return pkt_count;
|
||||||
|
}
|
||||||
|
|
||||||
int network_rx_put(netcard_t *card, uint8_t *bufp, int len)
|
int network_rx_put(netcard_t *card, uint8_t *bufp, int len)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
@@ -515,6 +552,17 @@ int network_rx_put(netcard_t *card, uint8_t *bufp, int len)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int network_rx_put_pkt(netcard_t *card, netpkt_t *pkt)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
thread_wait_mutex(card->rx_mutex);
|
||||||
|
ret = network_queue_put_swap(&card->queues[NET_QUEUE_RX], pkt);
|
||||||
|
thread_release_mutex(card->rx_mutex);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
network_dev_to_id(char *devname)
|
network_dev_to_id(char *devname)
|
||||||
{
|
{
|
||||||
|
Reference in New Issue
Block a user