Support zero copy while call `ff_write`, you can enable it by modify ‘FF_ZC_SEND=1' in `lib/Makefile`.

`FF_ZC_SEND` is same as `FF_USE_PAGE_ARRAY`, it will improve performance slightly in some scenarios, need to be tested in combination with real applications.

You can enable both compilation options at the same time or separately.
This commit is contained in:
fengbojiang 2022-04-15 18:00:49 +08:00
parent 93b7ff1c3f
commit e12886c02c
6 changed files with 434 additions and 1 deletions

298
example/main_zc.c Normal file
View File

@ -0,0 +1,298 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <errno.h>
#include <assert.h>
#include "ff_config.h"
#include "ff_api.h"
#define MAX_EVENTS 512
/* kevent set */
struct kevent kevSet;
/* events */
struct kevent events[MAX_EVENTS];
/* kq */
int kq;
int sockfd;
#ifdef INET6
int sockfd6;
#endif
char html[] =
"HTTP/1.1 200 OK\r\n"
"Server: F-Stack\r\n"
"Date: Sat, 25 Feb 2017 09:26:33 GMT\r\n"
"Content-Type: text/html\r\n"
"Content-Length: 438\r\n"
"Last-Modified: Tue, 21 Feb 2017 09:44:03 GMT\r\n"
"Connection: keep-alive\r\n"
"Accept-Ranges: bytes\r\n"
"\r\n"
"<!DOCTYPE html>\r\n"
"<html>\r\n"
"<head>\r\n"
"<title>Welcome to F-Stack!</title>\r\n"
"<style>\r\n"
" body { \r\n"
" width: 35em;\r\n"
" margin: 0 auto; \r\n"
" font-family: Tahoma, Verdana, Arial, sans-serif;\r\n"
" }\r\n"
"</style>\r\n"
"</head>\r\n"
"<body>\r\n"
"<h1>Welcome to F-Stack!</h1>\r\n"
"\r\n"
"<p>For online documentation and support please refer to\r\n"
"<a href=\"http://F-Stack.org/\">F-Stack.org</a>.<br/>\r\n"
"\r\n"
"<p><em>Thank you for using F-Stack.</em></p>\r\n"
"</body>\r\n"
"</html>";
char html1[] =
"HTTP/1.1 200 OK\r\n"
"Server: F-Stack\r\n"
"Date: Sat, 25 Feb 2017 09:26:33 GMT\r\n"
"Content-Type: text/html\r\n"
"Content-Length: 9438\r\n"
"Last-Modified: Tue, 21 Feb 2017 09:44:03 GMT\r\n"
"Connection: keep-alive\r\n"
"Accept-Ranges: bytes\r\n"
"\r\n"
"<!DOCTYPE html>\r\n"
"<html>\r\n"
"<head>\r\n"
"<title>Welcome to F-Stack!</title>\r\n"
"<style>\r\n"
" body { \r\n"
" width: 35em;\r\n"
" margin: 0 auto; \r\n"
" font-family: Tahoma, Verdana, Arial, sans-serif;\r\n"
" }\r\n"
"</style>\r\n"
"</head>\r\n"
"<body>\r\n"
"<h1>Welcome to F-Stack!</h1>\r\n"
"\r\n"
"<p>For online documentation and support please refer to012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234"
"5678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234"
"56789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789\r\n"
"<a href=\"http://F-Stack.org/\">F-Stack.org</a>.<br/>\r\n"
"\r\n"
"<p><em>Thank you for using F-Stack.</em></p>\r\n"
"</body>\r\n"
"</html>";
char html2[] =
"HTTP/1.1 200 OK\r\n"
"Server: F-Stack\r\n"
"Date: Sat, 25 Feb 2017 09:26:33 GMT\r\n"
"Content-Type: text/html\r\n"
"Content-Length: 1228\r\n"
"Last-Modified: Tue, 21 Feb 2017 09:44:03 GMT\r\n"
"Connection: keep-alive\r\n"
"Accept-Ranges: bytes\r\n"
"\r\n"
"<!DOCTYPE html>\r\n"
"<html>\r\n"
"<head>\r\n"
"<title>Welcome to F-Stack!</title>\r\n"
"<style>\r\n"
" body { \r\n"
" width: 35em;\r\n"
" margin: 0 auto; \r\n"
" font-family: Tahoma, Verdana, Arial, sans-serif;\r\n"
" }\r\n"
"</style>\r\n"
"</head>\r\n"
"<body>\r\n"
"<h1>Welcome to F-Stack!</h1>\r\n"
"\r\n"
"<p>For online documentation and support please refer to0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789\r\n"
"<a href=\"http://F-Stack.org/\">F-Stack.org</a>.<br/>\r\n"
"\r\n"
"<p><em>Thank you for using F-Stack.</em></p>\r\n"
"</body>\r\n"
"</html>";
extern int ff_zc_mbuf_get(struct ff_zc_mbuf *m, int len);
extern int ff_zc_mbuf_write(struct ff_zc_mbuf *m, const char *data, int len);
char *buf_tmp;
char html_buf[10240];
size_t buf_len = 0;
struct ff_zc_mbuf zc_buf;
int loop(void *arg)
{
/* Wait for events to happen */
unsigned nevents = ff_kevent(kq, NULL, 0, events, MAX_EVENTS, NULL);
unsigned i;
buf_len = sizeof(html) - 1;
buf_tmp = html;
for (i = 0; i < nevents; ++i) {
struct kevent event = events[i];
int clientfd = (int)event.ident;
/* Handle disconnect */
if (event.flags & EV_EOF) {
/* Simply close socket */
ff_close(clientfd);
#ifdef INET6
} else if (clientfd == sockfd || clientfd == sockfd6) {
#else
} else if (clientfd == sockfd) {
#endif
int available = (int)event.data;
do {
int nclientfd = ff_accept(clientfd, NULL, NULL);
if (nclientfd < 0) {
printf("ff_accept failed:%d, %s\n", errno,
strerror(errno));
break;
}
/* Add to event list */
EV_SET(&kevSet, nclientfd, EVFILT_READ, EV_ADD, 0, 0, NULL);
if(ff_kevent(kq, &kevSet, 1, NULL, 0, NULL) < 0) {
printf("ff_kevent error:%d, %s\n", errno,
strerror(errno));
return -1;
}
available--;
} while (available);
} else if (event.filter == EVFILT_READ) {
char buf[256];
size_t readlen = ff_read(clientfd, buf, sizeof(buf));
#ifdef FSTACK_ZC_SEND
int ret = ff_zc_mbuf_get(&zc_buf, buf_len);
if (ret < 0) {
printf("ff_zc_mbuf_get failed, len:%d, errno:%d, %s\n", buf_len, errno, strerror(errno));
exit(1);
}
/* APP can call ff_zc_mbuf_write multi times */
int len_part = 1440, off, to_write_len;
for (off = 0; off < buf_len;){
to_write_len = (buf_len - off) > len_part ? len_part : (buf_len - off);
ret = ff_zc_mbuf_write(&zc_buf, (const char *)buf_tmp + off, to_write_len);
if (ret != to_write_len) {
printf("ff_zc_mbuf_write failed, len:%d, errno:%d, %s\n", to_write_len, errno, strerror(errno));
exit(1);
}
off += to_write_len;
}
/* Or call ff_zc_mbuf_write one time */
/*
if (ret != buf_len) {
printf("ff_zc_mbuf_write failed, len:%d, errno:%d, %s\n", buf_len, errno, strerror(errno));
exit(1);
}
*/
/* Simulate the application load */
int i, j = 0;
for (i = 0; i < 10000; i++){
j++;
}
ff_write(clientfd, zc_buf.bsd_mbuf, buf_len);
#else
memcpy(html_buf, buf_tmp, buf_len);
/* Simulate the application load */
int i, j = 0;
for (i = 0; i < 10000; i++){
j++;
}
ff_write(clientfd, html_buf, buf_len);
#endif
} else {
printf("unknown event: %8.8X\n", event.flags);
}
}
}
int main(int argc, char * argv[])
{
ff_init(argc, argv);
assert((kq = ff_kqueue()) > 0);
sockfd = ff_socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
printf("ff_socket failed, sockfd:%d, errno:%d, %s\n", sockfd, errno, strerror(errno));
exit(1);
}
struct sockaddr_in my_addr;
bzero(&my_addr, sizeof(my_addr));
my_addr.sin_family = AF_INET;
my_addr.sin_port = htons(80);
my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
int ret = ff_bind(sockfd, (struct linux_sockaddr *)&my_addr, sizeof(my_addr));
if (ret < 0) {
printf("ff_bind failed, sockfd:%d, errno:%d, %s\n", sockfd, errno, strerror(errno));
exit(1);
}
ret = ff_listen(sockfd, MAX_EVENTS);
if (ret < 0) {
printf("ff_listen failed, sockfd:%d, errno:%d, %s\n", sockfd, errno, strerror(errno));
exit(1);
}
EV_SET(&kevSet, sockfd, EVFILT_READ, EV_ADD, 0, MAX_EVENTS, NULL);
/* Update kqueue */
ff_kevent(kq, &kevSet, 1, NULL, 0, NULL);
#ifdef INET6
sockfd6 = ff_socket(AF_INET6, SOCK_STREAM, 0);
if (sockfd6 < 0) {
printf("ff_socket failed, sockfd6:%d, errno:%d, %s\n", sockfd6, errno, strerror(errno));
exit(1);
}
struct sockaddr_in6 my_addr6;
bzero(&my_addr6, sizeof(my_addr6));
my_addr6.sin6_family = AF_INET6;
my_addr6.sin6_port = htons(80);
my_addr6.sin6_addr = in6addr_any;
ret = ff_bind(sockfd6, (struct linux_sockaddr *)&my_addr6, sizeof(my_addr6));
if (ret < 0) {
printf("ff_bind failed, sockfd6:%d, errno:%d, %s\n", sockfd6, errno, strerror(errno));
exit(1);
}
ret = ff_listen(sockfd6, MAX_EVENTS);
if (ret < 0) {
printf("ff_listen failed, sockfd6:%d, errno:%d, %s\n", sockfd6, errno, strerror(errno));
exit(1);
}
EV_SET(&kevSet, sockfd6, EVFILT_READ, EV_ADD, 0, MAX_EVENTS, NULL);
ff_kevent(kq, &kevSet, 1, NULL, 0, NULL);
#endif
ff_run(loop, NULL);
return 0;
}

View File

@ -1536,6 +1536,16 @@ m_uiotombuf(struct uio *uio, int how, int len, int align, int flags)
* Give us the full allocation or nothing.
* If len is zero return the smallest empty mbuf.
*/
#ifdef FSTACK_ZC_SEND
if (uio->uio_segflg == UIO_SYSSPACE && uio->uio_rw == UIO_WRITE) {
m = (struct mbuf *)uio->uio_iov->iov_base;
uio->uio_iov->iov_base = (char *)(uio->uio_iov->iov_base) + total;
uio->uio_iov->iov_len = 0;
uio->uio_resid = 0;
uio->uio_offset = total;
progress = total;
} else {
#endif
m = m_getm2(NULL, max(total + align, 1), how, MT_DATA, flags);
if (m == NULL)
return (NULL);
@ -1556,6 +1566,9 @@ m_uiotombuf(struct uio *uio, int how, int len, int align, int flags)
if (flags & M_PKTHDR)
m->m_pkthdr.len += length;
}
#ifdef FSTACK_ZC_SEND
}
#endif
KASSERT(progress == total, ("%s: progress != total", __func__));
return (m);

View File

@ -30,6 +30,7 @@ FF_KNI=1
#FF_NETGRAPH=1
#FF_IPFW=1
#FF_USE_PAGE_ARRAY=1
#FF_ZC_SEND=1
FF_INET6=1
@ -138,7 +139,6 @@ ifeq (${MACHINE_CPUARCH},i386)
MACHINE=i386
endif
#
# Distilled from FreeBSD src/sys/conf/Makefile.mips
#
@ -156,6 +156,10 @@ endif
CFLAGS+= -DFSTACK
ifdef FF_ZC_SEND
CFLAGS+= -DFSTACK_ZC_SEND
endif
# add for LVS tcp option toa, disabled by default
# CFLAGS+= -DLVS_TCPOPT_TOA

View File

@ -241,6 +241,62 @@ int ff_ngctl(int cmd, void *data);
/* internal api end */
/* zero ccopy API begin */
struct ff_zc_mbuf {
void *bsd_mbuf; /* point to the head mbuf */
void *bsd_mbuf_off; /* ponit to the current mbuf in the mbuf chain with offset */
int off; /* the offset of total mbuf, APP shouldn't modify it */
int len; /* the total len of the mbuf chain */
};
/*
* Get the ff zero copy mbuf.
*
* @param m
* The ponitor of 'sturct ff_zc_mbuf', and can't be NULL.
* Can used by 'ff_zc_mbuf_write' and 'ff_zc_mbuf_read'.
* @param len
* The total buf len of mbuf chain that you want to alloc.
*
* @return error_no
* 0 means success.
* -1 means error.
*/
int ff_zc_mbuf_get(struct ff_zc_mbuf *m, int len);
/*
* Write data to the mbuf chain in 'sturct ff_zc_mbuf'.
* APP can call this function multiple times, need pay attion to the offset of data.
* but the total len can't be larger than m->len.
* After this fuction return success,
* the struct 'ff_zc_mbuf *m' can be reused in `ff_zc_mbuf_get`.
*
* APP nedd call 'ff_write' to send data actually after finish write data to mbuf,
* And use 'bsd_mbuf' of 'struct ff_zc_mbuf' as the 'buf' argument.
*
* See 'example/main_zc.c'
*
* @param m
* The ponitor of 'sturct ff_zc_mbuf', must be call 'ff_zc_mbuf_get' first.
* @param data
* The pointer of data that want to write to socket, need pay attion to the offset.
* @param len
* The len that APP want to write to mbuf chain this time.
*
* @return error_no
* 0 means success.
* -1 means error.
*/
int ff_zc_mbuf_write(struct ff_zc_mbuf *m, const char *data, int len);
/*
* Read data to the mbuf chain in 'sturct ff_zc_mbuf'.
* not implemented now.
*/
int ff_zc_mbuf_read(struct ff_zc_mbuf *m, const char *data, int len);
/* ZERO COPY API end */
#ifdef __cplusplus
}
#endif

View File

@ -54,3 +54,6 @@ ff_next_mbuf
ff_mbuf_mtod
ff_rte_frm_extcl
ff_mbuf_set_vlan_info
ff_zc_mbuf_get
ff_zc_mbuf_write
ff_zc_mbuf_read

View File

@ -205,6 +205,65 @@ ff_mbuf_ext_free(struct mbuf *m, void *arg1, void *arg2)
ff_dpdk_pktmbuf_free(arg1);
}
int ff_zc_mbuf_get(struct ff_zc_mbuf *m, int len) {
struct mbuf *mb;
if (m == NULL) {
return -1;
}
mb = m_getm2(NULL, max(len, 1), M_WAITOK, MT_DATA, 0);
if (mb == NULL) {
return -1;
}
m->bsd_mbuf = m->bsd_mbuf_off = mb;
m->off = 0;
m->len = len;
return 0;
}
int
ff_zc_mbuf_write(struct ff_zc_mbuf *zm, const char *data, int len)
{
int ret, length, progress = 0;
struct mbuf *m, *mb;
if (zm == NULL) {
return -1;
}
m = (struct mbuf *)zm->bsd_mbuf_off;
if (zm->off + len > zm->len) {
return -1;
}
for (mb = m; mb != NULL; mb = mb->m_next) {
length = min(M_TRAILINGSPACE(mb), len - progress);
bcopy(data + progress, mtod(mb, char *) + mb->m_len, length);
mb->m_len += length;
progress += length;
if (len == progress) {
break;
}
//if (flags & M_PKTHDR)
// m->m_pkthdr.len += length;
}
zm->off += len;
zm->bsd_mbuf_off = mb;
return len;
}
int
ff_zc_mbuf_read(struct ff_zc_mbuf *m, const char *data, int len)
{
// DOTO: Support read zero copy
return 0;
}
void *
ff_mbuf_gethdr(void *pkt, uint16_t total, void *data,
uint16_t len, uint8_t rx_csum)