From 5c0aa976d3d47f17471b609d19b749557716f2a0 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Thu, 12 Feb 2015 13:34:09 +0100 Subject: Add zerocopy sendto --- Makefile | 12 ++ freebsd-to-rtems.py | 2 + freebsd/sys/kern/uipc_syscalls.c | 25 ++++ rtemsbsd/include/rtems/bsd/zerocopy.h | 68 ++++++++++ rtemsbsd/rtems/rtems-bsd-mbuf.c | 68 ++++++++++ testsuite/zerocopy01/test_main.c | 243 ++++++++++++++++++++++++++++++++++ 6 files changed, 418 insertions(+) create mode 100644 rtemsbsd/include/rtems/bsd/zerocopy.h create mode 100644 rtemsbsd/rtems/rtems-bsd-mbuf.c create mode 100644 testsuite/zerocopy01/test_main.c diff --git a/Makefile b/Makefile index 6d26776c..5622849f 100644 --- a/Makefile +++ b/Makefile @@ -80,6 +80,7 @@ LIB_C_FILES += rtemsbsd/rtems/rtems-bsd-jail.c LIB_C_FILES += rtemsbsd/rtems/rtems-bsd-kern_synch.c LIB_C_FILES += rtemsbsd/rtems/rtems-bsd-log.c LIB_C_FILES += rtemsbsd/rtems/rtems-bsd-malloc.c +LIB_C_FILES += rtemsbsd/rtems/rtems-bsd-mbuf.c LIB_C_FILES += rtemsbsd/rtems/rtems-bsd-mutex.c LIB_C_FILES += rtemsbsd/rtems/rtems-bsd-muteximpl.c LIB_C_FILES += rtemsbsd/rtems/rtems-bsd-newproc.c @@ -1385,6 +1386,17 @@ $(TEST_PPP01): $(TEST_PPP01_O_FILES) $(LIB) TESTS += $(TEST_PPP01) O_FILES += $(TEST_PPP01_O_FILES) D_FILES += $(TEST_PPP01_D_FILES) + +TEST_ZEROCOPY01 = testsuite/zerocopy01/zerocopy01.exe +TEST_ZEROCOPY01_O_FILES = +TEST_ZEROCOPY01_D_FILES = +TEST_ZEROCOPY01_O_FILES += testsuite/zerocopy01/test_main.o +TEST_ZEROCOPY01_D_FILES += testsuite/zerocopy01/test_main.d +$(TEST_ZEROCOPY01): $(TEST_ZEROCOPY01_O_FILES) $(LIB) + $(LINK.c) -Wl,-Map,testsuite/zerocopy01/zerocopy01.map $^ -lm -lz -o $@ +NET_TESTS += $(TEST_ZEROCOPY01) +O_FILES += $(TEST_ZEROCOPY01_O_FILES) +D_FILES += $(TEST_ZEROCOPY01_D_FILES) LIB_C_FILES += dhcpcd/arp.c dhcpcd/arp.o: dhcpcd/arp.c $(CC) $(CPPFLAGS) $(CFLAGS) -D__FreeBSD__ -DTHERE_IS_NO_FORK -DMASTER_ONLY -DINET -DINET6 -c $< -o $@ diff --git a/freebsd-to-rtems.py b/freebsd-to-rtems.py index 764b7550..c90c1d17 100755 --- a/freebsd-to-rtems.py +++ b/freebsd-to-rtems.py @@ -680,6 +680,7 @@ rtems.addRTEMSSourceFiles( 'rtems/rtems-bsd-kern_synch.c', 'rtems/rtems-bsd-log.c', 'rtems/rtems-bsd-malloc.c', + 'rtems/rtems-bsd-mbuf.c', 'rtems/rtems-bsd-mutex.c', 'rtems/rtems-bsd-muteximpl.c', 'rtems/rtems-bsd-newproc.c', @@ -2511,6 +2512,7 @@ tests.addTest('thread01', ['test_main']) tests.addTest('mutex01', ['test_main']) tests.addTest('condvar01', ['test_main']) tests.addTest('ppp01', ['test_main'], runTest = False) +tests.addTest('zerocopy01', ['test_main'], runTest = False, netTest = True) dhcpcd = Module('dhcpcd') dhcpcd.addSourceFiles( diff --git a/freebsd/sys/kern/uipc_syscalls.c b/freebsd/sys/kern/uipc_syscalls.c index b0c83e60..44804b38 100644 --- a/freebsd/sys/kern/uipc_syscalls.c +++ b/freebsd/sys/kern/uipc_syscalls.c @@ -99,6 +99,7 @@ __FBSDID("$FreeBSD$"); #endif /* INET || INET6 */ #ifdef __rtems__ #include +#include static int kern_bind(struct thread *, int, struct sockaddr *); @@ -1137,6 +1138,30 @@ sendto(int socket, const void *message, size_t length, int flags, rtems_set_errno_and_return_minus_one(error); } } + +int +rtems_bsd_sendto(int socket, struct mbuf *m, int flags, + const struct sockaddr *dest_addr) +{ + struct thread *td = rtems_bsd_get_curthread_or_null(); + struct file *fp; + struct socket *so; + int error; + + error = getsock_cap(td->td_proc->p_fd, socket, CAP_WRITE, &fp, NULL); + if (error) + return (error); + so = (struct socket *)fp->f_data; + + if (td != NULL) { + error = sosend(so, __DECONST(struct sockaddr *, dest_addr), + NULL, m, NULL, flags, td); + } else { + error = ENOMEM; + } + + return (error); +} #endif /* __rtems__ */ #ifndef __rtems__ diff --git a/rtemsbsd/include/rtems/bsd/zerocopy.h b/rtemsbsd/include/rtems/bsd/zerocopy.h new file mode 100644 index 00000000..2916c5ba --- /dev/null +++ b/rtemsbsd/include/rtems/bsd/zerocopy.h @@ -0,0 +1,68 @@ +/** + * @file + * + * @ingroup rtems_bsd + * + * @brief TODO. + */ + +/* + * Copyright (c) 2015 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _RTEMS_BSD_ZEROCOPY_H_ +#define _RTEMS_BSD_ZEROCOPY_H_ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +struct mbuf *rtems_bsd_m_get(int how, short type); + +struct mbuf *rtems_bsd_m_gethdr(int how, short type); + +void rtems_bsd_m_extaddref(struct mbuf *m, void *buf, size_t size, + u_int *ref_cnt, void (*freef)(void *, void *), void *arg1, + void *arg2); + +void rtems_bsd_m_free(struct mbuf *m); + +int rtems_bsd_sendto(int socket, struct mbuf *m, int flags, + const struct sockaddr *dest_addr); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _RTEMS_BSD_ZEROCOPY_H_ */ diff --git a/rtemsbsd/rtems/rtems-bsd-mbuf.c b/rtemsbsd/rtems/rtems-bsd-mbuf.c new file mode 100644 index 00000000..a1429d86 --- /dev/null +++ b/rtemsbsd/rtems/rtems-bsd-mbuf.c @@ -0,0 +1,68 @@ +/** + * @file + * + * @ingroup rtems_bsd_rtems + * + * @brief TODO. + */ + +/* + * Copyright (c) 2015 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include + +struct mbuf * +rtems_bsd_m_get(int how, short type) +{ + return (m_get(how, type)); +} + +struct mbuf * +rtems_bsd_m_gethdr(int how, short type) +{ + return (m_gethdr(how, type)); +} + +void +rtems_bsd_m_extaddref(struct mbuf *m, void *buf, size_t size, + u_int *ref_cnt, void (*freef)(void *, void *), void *arg1, + void *arg2) +{ + m_extaddref(m, buf, size, ref_cnt, freef, arg1, arg2); +} + +void +rtems_bsd_m_free(struct mbuf *m) +{ + m_free(m); +} diff --git a/testsuite/zerocopy01/test_main.c b/testsuite/zerocopy01/test_main.c new file mode 100644 index 00000000..d23c746f --- /dev/null +++ b/testsuite/zerocopy01/test_main.c @@ -0,0 +1,243 @@ +/* + * Copyright (c) 2015 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define TEST_NAME "LIBBSD ZEROCOPY 1" + +#define BUFFER_COUNT 128 + +#define NOTIFY_THRESHOLD 64 + +#define DATA_SIZE (ETHERMTU - sizeof(struct ip) - sizeof(struct udphdr)) + +struct buffer { + SLIST_ENTRY(buffer) link; + u_int ref_cnt; + char *data; +}; + +struct buffer_control { + SLIST_HEAD(buffer_list, buffer) free_list; + rtems_interrupt_lock lock; + size_t free_buffers; + rtems_id waiting_task; + struct buffer buffers[BUFFER_COUNT]; + char data[DATA_SIZE][BUFFER_COUNT]; +}; + +static struct buffer_control buffer_control; + +static void +buffer_free(void *arg1, void *arg2) +{ + struct buffer_control *bc = arg1; + struct buffer *buf = arg2; + rtems_status_code sc; + rtems_interrupt_lock_context lock_context; + rtems_id waiting_task; + + buf->ref_cnt = 0; + + rtems_interrupt_lock_acquire(&bc->lock, &lock_context); + SLIST_INSERT_HEAD(&bc->free_list, buf, link); + waiting_task = bc->waiting_task; + ++bc->free_buffers; + if (bc->free_buffers < NOTIFY_THRESHOLD) { + waiting_task = 0; + } + rtems_interrupt_lock_release(&bc->lock, &lock_context); + + if (waiting_task != 0) { + sc = rtems_event_transient_send(waiting_task); + assert(sc == RTEMS_SUCCESSFUL); + } +} + +static struct mbuf * +buffer_get(struct buffer_control *bc) +{ + struct mbuf *m = rtems_bsd_m_gethdr(M_WAITOK, MT_DATA); + struct buffer *buf; + rtems_status_code sc; + rtems_interrupt_lock_context lock_context; + + do { + rtems_interrupt_lock_acquire(&bc->lock, &lock_context); + if (SLIST_EMPTY(&bc->free_list)) { + bc->waiting_task = rtems_task_self(); + rtems_interrupt_lock_release(&bc->lock, &lock_context); + + sc = rtems_event_transient_receive(RTEMS_WAIT, + RTEMS_NO_TIMEOUT); + assert(sc == RTEMS_SUCCESSFUL); + + buf = NULL; + } else { + buf = SLIST_FIRST(&bc->free_list); + SLIST_REMOVE_HEAD(&bc->free_list, link); + --bc->free_buffers; + rtems_interrupt_lock_release(&bc->lock, &lock_context); + } + } while (buf == NULL); + + m->m_len = DATA_SIZE; + m->m_pkthdr.len = DATA_SIZE; + rtems_bsd_m_extaddref(m, buf, DATA_SIZE, &buf->ref_cnt, buffer_free, + bc, buf); + + return (m); +} + +static void +network_flood_task(rtems_task_argument arg) +{ + int fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + struct sockaddr_in addr = { + .sin_len = sizeof(addr), + .sin_family = AF_INET, + .sin_port = htons(13161), + .sin_addr = { + .s_addr = INADDR_ANY + } + }; + int rv = inet_aton(NET_CFG_PEER_IP, &addr.sin_addr); + struct buffer_control *bc = (struct buffer_control *)arg; + + assert(fd >= 0); + assert(rv != 0); + + while (true) { + struct mbuf *m = buffer_get(bc); + int error = rtems_bsd_sendto( + fd, + m, + 0, + (const struct sockaddr *) &addr + ); + + if (error != 0) { + printf("zerocopy sendto error: %s\n", strerror(error)); + sleep(1); + } + } +} + +static void +telnet_shell(char *name, void *arg) +{ + rtems_shell_env_t env; + + memset(&env, 0, sizeof(env)); + + env.devname = name; + env.taskname = "TLNT"; + env.login_check = NULL; + env.forever = false; + + rtems_shell_main_loop(&env); +} + +rtems_telnetd_config_table rtems_telnetd_config = { + .command = telnet_shell, + .arg = NULL, + .priority = 2, + .stack_size = 0, + .login_check = NULL, + .keep_stdio = false +}; + +static void +test_main(void) +{ + struct buffer_control *bc = &buffer_control; + rtems_status_code sc; + rtems_id id; + size_t i; + + sc = rtems_telnetd_initialize(); + assert(sc == RTEMS_SUCCESSFUL); + + SLIST_INIT(&bc->free_list); + + for (i = 0; i < BUFFER_COUNT; ++i) { + SLIST_INSERT_HEAD(&bc->free_list, &bc->buffers[i], link); + bc->buffers[i].data = &bc->data[i][0]; + } + + sc = rtems_task_create( + rtems_build_name('F', 'L', 'O', 'D'), + 3, + RTEMS_MINIMUM_STACK_SIZE, + RTEMS_DEFAULT_MODES, + RTEMS_DEFAULT_ATTRIBUTES, + &id + ); + assert(sc == RTEMS_SUCCESSFUL); + + sc = rtems_task_start(id, network_flood_task, (rtems_task_argument) bc); + assert(sc == RTEMS_SUCCESSFUL); + + rtems_task_delete(RTEMS_SELF); + assert(0); +} + +#define DEFAULT_NETWORK_DHCPCD_ENABLE +#define DEFAULT_NETWORK_SHELL + +#define CONFIGURE_MAXIMUM_DRIVERS 32 + +#include -- cgit v1.2.3