diff --git a/apps/lwipserver2/CMakeLists.txt b/apps/lwipserver2/CMakeLists.txt new file mode 100644 index 00000000..1c49139c --- /dev/null +++ b/apps/lwipserver2/CMakeLists.txt @@ -0,0 +1,49 @@ +# +# Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) +# +# SPDX-License-Identifier: BSD-2-Clause +# + +cmake_minimum_required(VERSION 3.8.2) + +project(lwipserver_single C) +includeGlobalComponents() + +find_package(projects_libs REQUIRED) + +set(CAmkESCPP ON CACHE BOOL "" FORCE) +if(KernelArchX86) + set(cpp_define -DKernelArchX86) +elseif(KernelArchARM) + set(cpp_define -DKernelArchArm) +endif() + +include(${LWIP_HELPERS}) +AddLWIPConfiguration(${CMAKE_CURRENT_LIST_DIR}/lwip_include) + +set(libs sel4utils sel4vka sel4allocman sel4vspace sel4simple sel4platsupport lwip) + +set(sources src/tcp_echo_socket.c src/udp_echo_socket.c src/utilization_socket.c) + +DeclareCAmkESComponent( + LWIPServer + SOURCES + ${sources} + INCLUDES + include + LIBS + ${libs} + LD_FLAGS + -Wl,--section-start=.note.gnu.build-id=0x400920 #Ensure reproducible build +) + +CAmkESAddCPPInclude("${CMAKE_CURRENT_LIST_DIR}/include/") + +if(KernelSel4ArchX86_64) + DeclareCAmkESComponent(Ethdriver82574DF SOURCES x86_64_eth_init.c LIBS "${ETHDRIVER_LIBS}") + DeclareCAmkESRootserver(lwipserver2_x86_64.camkes CPP_FLAGS ${cpp_define}) +elseif(KernelPlatformImx8mm-evk) + DeclareCAmkESRootserver(lwipserver2_imx8mm.camkes CPP_FLAGS ${cpp_define}) +else() + message(FATAL_ERROR "Unsupported platform.") +endif() diff --git a/apps/lwipserver2/include/echo/tuning_params.h b/apps/lwipserver2/include/echo/tuning_params.h new file mode 100644 index 00000000..c478832c --- /dev/null +++ b/apps/lwipserver2/include/echo/tuning_params.h @@ -0,0 +1,33 @@ +/* + * Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +/* Number of buffers used for sending and receiving ethernet frames. */ +#define TX_BUFS 510 +#define RX_BUFS 510 + +/* Size used for ethernet buffers. This is the next 2^n for the 1500 byte ethernet MTU */ +#define BUF_SIZE 2048 + +/* Maximum connected TCP clients */ +#define MAX_TCP_CLIENTS 5 + +/* Size of initial TCP socket reads */ +#define TCP_READ_SIZE 1400 + +/* Max size of UDP socket reads */ +#define UDP_READ_SIZE 1500 + +/* DMA memory to use for descriptor rings */ +#define DMA_RING_ALLOC_SIZE 0x4000 + +/* Total DMA memory to allocate = */ +#define DMA_ALLOC_SIZE (DMA_RING_ALLOC_SIZE + BUF_SIZE * (TX_BUFS + RX_BUFS)) + + +/* Heap size */ +#define HEAP_SIZE 0x800000 diff --git a/apps/lwipserver2/lwip_include/lwipopts.h b/apps/lwipserver2/lwip_include/lwipopts.h new file mode 100644 index 00000000..079d4077 --- /dev/null +++ b/apps/lwipserver2/lwip_include/lwipopts.h @@ -0,0 +1,47 @@ +/* + * Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#define NO_SYS 1 +#define NO_SYS_NO_TIMERS 0 +#define LWIP_TIMERS 1 +#define LWIP_NETCONN 0 +#define LWIP_SOCKET 0 +#define LWIP_IGMP 1 +#define LWIP_RAND rand +#define LWIP_DHCP 1 + +#define MEM_ALIGNMENT 4 +#define MEM_SIZE 0x40000 + +#define ETHARP_SUPPORT_STATIC_ENTRIES 1 +#define SYS_LIGHTWEIGHT_PROT 0 +#define LWIP_NETIF_STATUS_CALLBACK 1 + +#define TCP_SND_QUEUELEN 2500 +#define MEMP_NUM_TCP_SEG TCP_SND_QUEUELEN +#define TCP_SND_BUF (100 * TCP_MSS) +#define TCP_WND (100 * TCP_MSS) +#define LWIP_WND_SCALE 1 +#define TCP_RCV_SCALE 10 +#define PBUF_POOL_SIZE 1000 +#define MEMP_NUM_SYS_TIMEOUT 512 + +/* Set this to 0 for performance */ +#define LWIP_STATS 0 + +/* Debugging options */ +#define LWIP_DEBUG +/* Change this to LWIP_DBG_LEVEL_ALL to see a trace */ +#define LWIP_DBG_MIN_LEVEL LWIP_DBG_LEVEL_WARNING + +#define ETHARP_DEBUG LWIP_DBG_ON +#define PBUF_DEBUG LWIP_DBG_ON +#define IP_DEBUG LWIP_DBG_ON +#define TCPIP_DEBUG LWIP_DBG_ON +#define DHCP_DEBUG LWIP_DBG_ON +#define UDP_DEBUG LWIP_DBG_ON diff --git a/apps/lwipserver2/lwipserver2_imx8mm.camkes b/apps/lwipserver2/lwipserver2_imx8mm.camkes new file mode 100644 index 00000000..e4d07c33 --- /dev/null +++ b/apps/lwipserver2/lwipserver2_imx8mm.camkes @@ -0,0 +1,120 @@ +/* + * Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +import ; +import ; +import ; +import ; + +#include +#include +#include +#include +#include +#include + +#include + +component FDT_device { + hardware; + emits FDT resource; +} + +component LWIPServer { + single_threaded_component() + lwip_ethernet_async_client_interfaces(eth0) + lwip_base_interfaces(lwip_base) + SerialServer_putchar_printf_client(putchar) + BenchUtiliz_control_interfaces(idle) +} + +component EthdriverARMPlatDF { + single_threaded_component() + lwip_ethernet_async_server_interfaces(eth0) + SerialServer_putchar_printf_client(putchar) + + attribute int simple = true; + attribute int cnode_size_bits = 12; + attribute int simple_untyped20_pool = 2; + attribute int promiscuous_mode = 1; + attribute int heap_size = 0x10000; + attribute int dma_pool = 0x200000; + + consumes FDT EthDriver; + consumes FDT ocotp; + consumes FDT iomux; + consumes FDT ccm; + consumes FDT analog; + consumes FDT gpio1; + fdt_bind_drivers_interfaces(["/ethernet@30be0000"]); + + composition { + component FDT_device ether_qos; + connection seL4DTBHWThreadless ethdriver_conn(from ether_qos.resource, to EthDriver); + connection seL4DTBHWThreadless ocotp_conn(from ether_qos.resource, to ocotp); + connection seL4DTBHWThreadless iomux_conn(from ether_qos.resource, to iomux); + connection seL4DTBHWThreadless ccm_conn(from ether_qos.resource, to ccm); + connection seL4DTBHWThreadless analog_conn(from ether_qos.resource, to analog); + connection seL4DTBHWThreadless gpio1_conn(from ether_qos.resource, to gpio1); + fdt_bind_driver_connections(); + } + + configuration { + EthDriver.dtb = dtb({ "path" : "/ethernet@30be0000" }); + EthDriver.generate_interrupts = 1; + ocotp.dtb = dtb({ "path" : "/ocotp-ctrl@30350000" }); + iomux.dtb = dtb({ "path" : "/pinctrl@30330000" }); + ccm.dtb = dtb({ "path" : "/clock-controller@30380000" }); + analog.dtb = dtb({ "path" : "/anatop@30360000" }); + gpio1.dtb = dtb({"path" : "/gpio@30200000"}); + } +}; + +assembly { + composition { + component LWIPServer lwipserver; + + component EthdriverARMPlatDF ethdriver; + + component TimeServer time_server; + component SerialServer serial_server; + component BenchUtiliz bench; + + lwip_ethernet_async_connections(eth0, lwipserver, ethdriver) + + lwip_base_connections(lwipserver, lwip_base, time_server.the_timer) + + connection seL4TimeServer serialserver_timer (from serial_server.timeout, to time_server.the_timer); + SerialServer_processed_putchar_printf_connection(putchar, lwipserver, serial_server) + SerialServer_processed_putchar_printf_connection(putchar, ethdriver, serial_server) + + BenchUtiliz_trace_connections(trace, lwipserver, bench) + BenchUtiliz_trace_connections(trace, ethdriver, bench) + BenchUtiliz_control_connections(idle, lwipserver, bench) + } + + configuration { + echo._priority = 100; + lwipserver._priority = 100; + ethdriver._priority = 100; + + /* + * Non-platform specific configurations + */ + time_server.timers_per_client = 8; + + lwip_ethernet_async_configurations(eth0, lwipserver, ethdriver) + lwipserver.heap_size = 0x40000; + + BenchUtiliz_trace_configurations(trace, ethdriver, 103) + BenchUtiliz_trace_configurations(trace, lwipserver, 102) + + ethdriver.enable_tracing = 1; + lwipserver.enable_tracing = 1; + + lwip_base_configuration(lwipserver, lwip_base, "", "0.0.0.0") + } +} diff --git a/apps/lwipserver2/lwipserver2_x86_64.camkes b/apps/lwipserver2/lwipserver2_x86_64.camkes new file mode 100644 index 00000000..e4b09fc0 --- /dev/null +++ b/apps/lwipserver2/lwipserver2_x86_64.camkes @@ -0,0 +1,138 @@ +/* + * Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +import ; +import ; +import ; +import ; + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +component LWIPServer { + single_threaded_component() + lwip_ethernet_async_client_interfaces(eth0) + lwip_base_interfaces(lwip_base) + SerialServer_putchar_printf_client(putchar) + BenchUtiliz_control_interfaces(idle) +} + +/* Example hardware components that contain minimal necessary spec for different ethdrivers */ +component HWEthDriver82574DF { + hardware; + emits IRQ irq; + dataport Buf(0x20000) mmio; +}; + +component Ethdriver82574DF { + single_threaded_component() + dynamic_untyped_allocators_interfaces(init_dynamic) + x86_iospace_dma_interfaces(init_iospaces, "0xc:0x02:0:0") + lwip_ethernet_async_server_interfaces(eth0) + SerialServer_putchar_printf_client(putchar) + /* + * The promiscuous mode is set according to whatever configuration you want, 1 by default. + */ + attribute int promiscuous_mode = 1; + + consumes IRQ irq; + dataport Buf(0x20000) EthDriver; + + /* MMIO and IRQ default values */ + attribute int mmio_paddr = 0xf7cc0000; + attribute int mmio_size = 0x20000; + attribute string irq_irq_type = "pci"; + attribute int irq_irq_ioapic = 0; + attribute int irq_irq_ioapic_pin = 16; + attribute int irq_irq_vector = 16; + + attribute int simple = 1; + attribute int cnode_size_bits = 14; + attribute int simple_untyped20_pool = 2; + attribute int heap_size = 0x40000; + attribute int dma_pool = 0x4000; + attribute int dma_pool_cached = 1; + + + composition { + component HWEthDriver82574DF hwethdriver; + connection seL4HardwareMMIO ethdrivermmio(from EthDriver, to hwethdriver.mmio); + connection seL4GlobalAsynchHardwareInterrupt hwethirq(from hwethdriver.irq, to irq); + dynamic_untyped_allocators_connections(init_dynamic) + x86_iospace_dma_connections(init_iospaces) + } + + configuration { + hwethdriver.mmio_paddr <- mmio_paddr; + hwethdriver.mmio_size <- mmio_size; + hwethdriver.irq_irq_type <- irq_irq_type; + hwethdriver.irq_irq_ioapic <- irq_irq_ioapic; + hwethdriver.irq_irq_ioapic_pin <- irq_irq_ioapic_pin; + hwethdriver.irq_irq_vector <- irq_irq_vector; + dynamic_untyped_allocators_configuration(init_dynamic) + x86_iospace_dma_configuration(init_iospaces) + } +} + +assembly { + composition { + /* LWIPServer component */ + component LWIPServer lwipserver; + + /* Ethdriver component */ + component Ethdriver82574DF ethdriver; + + /* Timer component */ + component TimeServer time_server; + component BenchUtiliz bench; + component SerialServer serial_server; + + /* + * Connections + */ + + lwip_ethernet_async_connections(eth0, lwipserver, ethdriver) + lwip_base_connections(lwipserver, lwip_base, time_server.the_timer) + connection seL4TimeServer serialserver_timer (from serial_server.timeout, to time_server.the_timer); + SerialServer_processed_putchar_printf_connection(putchar, lwipserver, serial_server) + SerialServer_processed_putchar_printf_connection(putchar, ethdriver, serial_server) + + BenchUtiliz_trace_connections(trace, ethdriver, bench) + BenchUtiliz_trace_connections(trace, lwipserver, bench) + BenchUtiliz_control_connections(idle, lwipserver, bench) + } + + configuration { + echo._priority = 100; + lwipserver._priority = 100; + ethdriver._priority = 100; + + lwip_ethernet_async_configurations(eth0, lwipserver, ethdriver) + + BenchUtiliz_trace_configurations(trace, ethdriver, 103) + BenchUtiliz_trace_configurations(trace, lwipserver, 102) + + lwipserver.enable_tracing = 1; + ethdriver.enable_tracing = 1; + + time_server.timers_per_client = 8; + + /* + * LWIPServer config + */ + /* IP and multicast address to assign to the networking device */ + lwip_base_configuration(lwipserver, lwip_base, "", "0.0.0.0") + lwipserver.heap_size = 0x40000; + } +} diff --git a/apps/lwipserver2/settings.cmake b/apps/lwipserver2/settings.cmake new file mode 100644 index 00000000..e3ccd31d --- /dev/null +++ b/apps/lwipserver2/settings.cmake @@ -0,0 +1,26 @@ +# +# Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) +# +# SPDX-License-Identifier: BSD-2-Clause +# + +set(LibLwip ON CACHE BOOL "" FORCE) +set(LibEthdriverNumPreallocatedBuffers 32 CACHE STRING "" FORCE) + +# For x86, we map DMA frames into the IOMMU to use as buffers for the +# Ethernet device. The VKA and VSpace libraries do not like pages that +# are not 4K in size. +set(CAmkESDMALargeFramePromotion OFF CACHE BOOL "" FORCE) + +# This application only works on hardware at the moment, not simulation +# set(SIMULATION OFF CACHE BOOL "" FORCE) +if("${KernelArch}" STREQUAL "x86") + # The IOMMU is required for the Ethdriver component on x86 + set(KernelIOMMU ON CACHE BOOL "" FORCE) +endif() + +set(cpp_define -DKernelArchArm) + +set(LibEthdriverRXDescCount 256 CACHE STRING "" FORCE) +set(LibEthdriverTXDescCount 256 CACHE STRING "" FORCE) +set(CAmkESNoFPUByDefault ON CACHE BOOL "" FORCE) diff --git a/apps/lwipserver2/src/ports.h b/apps/lwipserver2/src/ports.h new file mode 100644 index 00000000..291be05a --- /dev/null +++ b/apps/lwipserver2/src/ports.h @@ -0,0 +1,14 @@ +/* + * Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#define TCP_ECHO_PORT 1234 + +#define UDP_ECHO_PORT 1235 + +/* ipbench utilization client port */ +#define UTILIZATION_PORT 1236 diff --git a/apps/lwipserver2/src/tcp_echo_socket.c b/apps/lwipserver2/src/tcp_echo_socket.c new file mode 100644 index 00000000..607b1ee9 --- /dev/null +++ b/apps/lwipserver2/src/tcp_echo_socket.c @@ -0,0 +1,203 @@ +/* + * Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include + +#include + +#include +#include +#include + +#include "ports.h" +#include + +typedef struct pbuf_chain { + struct pbuf *p; + u16_t packet_pointer; /* 'File' pointer of a pbuf */ + struct pbuf_chain *next; +} pbuf_chain_t; + +typedef struct tcp_client { + pbuf_chain_t *pbufs; + pbuf_chain_t *pbuf_tail; +} tcp_client_t; + +static tcp_client_t tcp_clients[MAX_TCP_CLIENTS]; + +static struct tcp_pcb *tcp_main_socket; + +static struct tcp_pcb *tcp_peer_sockets[MAX_TCP_CLIENTS]; + +static char data_packet[0x1000] ALIGN(0x1000); + +static ps_io_ops_t *ops; + +static int peer_id; + +static int get_free_peer_id(void) +{ + int ret = peer_id; + peer_id = (peer_id + 1) % MAX_TCP_CLIENTS; + return ret; +} + +static void pop_pbuf_from_chain(int client_id) +{ + pbuf_chain_t *head = tcp_clients[client_id].pbufs; + tcp_clients[client_id].pbufs = head->next; + if (head->next == NULL) { + tcp_clients[client_id].pbuf_tail = NULL; + } + pbuf_free(head->p); + ZF_LOGF_IF(ps_free(&ops->malloc_ops, sizeof(*head), head), + "Failed to free a pbuf_chain_t node"); +} + +static err_t lwip_sent_callback(void *arg, struct tcp_pcb *pcb, u16_t len) +{ + int client_id = (int)(uintptr_t) arg; + u16_t can_send = MIN(tcp_sndbuf(pcb), 0x1000); + + if (tcp_clients[client_id].pbufs) { + u16_t num_sent = 0; + pbuf_chain_t *curr_pbuf = tcp_clients[client_id].pbufs; + pbuf_chain_t *prev_pbuf = NULL; + while (num_sent < can_send && curr_pbuf != NULL) { + u16_t to_send = MIN(curr_pbuf->p->tot_len - curr_pbuf->packet_pointer, + can_send - num_sent); + u16_t num_copied = pbuf_copy_partial(curr_pbuf->p, data_packet, to_send, + curr_pbuf->packet_pointer); + err_t error = tcp_write(pcb, data_packet, num_copied, TCP_WRITE_FLAG_COPY); + u16_t sent = num_copied; + if (error != ERR_OK) { + if (error != ERR_MEM) { + ZF_LOGF("Failed to send data through TCP socket, error = %hhd", error); + } + sent = 0; + } + prev_pbuf = curr_pbuf; + curr_pbuf = curr_pbuf->next; + if ((sent + prev_pbuf->packet_pointer) < prev_pbuf->p->tot_len) { + prev_pbuf->packet_pointer += sent; + } else { + ZF_LOGF_IF(prev_pbuf->packet_pointer + sent != prev_pbuf->p->tot_len, + "Didn't sent all the data in the pbuf!"); + pop_pbuf_from_chain(client_id); + } + } + } + + return ERR_OK; +} + +static int add_pbuf_to_chain(int client_id, struct pbuf *p, u16_t packet_pointer) +{ + pbuf_chain_t *new_node = NULL; + int error = ps_calloc(&ops->malloc_ops, 1, sizeof(*new_node), (void **) &new_node); + if (error) { + ZF_LOGE("Failed to allocate memory for the pbuf new_node head"); + return error; + } + + new_node->p = p; + new_node->packet_pointer = packet_pointer; + + if (tcp_clients[client_id].pbuf_tail) { + tcp_clients[client_id].pbuf_tail->next = new_node; + tcp_clients[client_id].pbuf_tail = new_node; + } else { + tcp_clients[client_id].pbuf_tail = new_node; + tcp_clients[client_id].pbufs = new_node; + } + + return 0; +} + +static err_t lwip_tcp_recv_callback(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) +{ + int client_id = (int)(uintptr_t) arg; + err_t error = ERR_OK; + if (p == NULL) { + printf("Connection closed on a TCP socket\n"); + error = tcp_close(pcb); + ZF_LOGF_IF(error, "Failed to close a TCP socket"); + tcp_peer_sockets[client_id] = NULL; + return ERR_OK; + } + + if (err != ERR_OK) { + ZF_LOGE("Encountered error %hhd when trying to receive TCP packet", err); + return ERR_OK; + } + + u16_t bytes_avail = tcp_sndbuf(pcb); + u16_t to_send = MIN(MIN(p->tot_len, bytes_avail), 0x1000); + pbuf_copy_partial(p, data_packet, to_send, 0); + error = tcp_write(pcb, data_packet, to_send, TCP_WRITE_FLAG_COPY); + u16_t sent = to_send; + if (error != ERR_OK) { + if (error != ERR_MEM) { + ZF_LOGF("Failed to send data through TCP socket, error = %hhd", error); + } + sent = 0; + } + + if (sent < p->tot_len) { + /* Store the rest of pbuf in the chain */ + ZF_LOGF_IF(add_pbuf_to_chain(client_id, p, sent), "Failed to add pbuf to chain"); + } else { + pbuf_free(p); + } + + tcp_recved(pcb, p->tot_len); + + return ERR_OK; +} + +static err_t lwip_accept_callback(void *arg, struct tcp_pcb *newpcb, err_t err) +{ + int peer_id = get_free_peer_id(); + if (peer_id == -1) { + ZF_LOGF("not expecting another peer"); + } + + tcp_peer_sockets[peer_id] = newpcb; + + tcp_arg(newpcb, (void *) (uintptr_t) peer_id); + tcp_sent(newpcb, lwip_sent_callback); + tcp_recv(newpcb, lwip_tcp_recv_callback); + + printf("Peer connected\n"); + + return ERR_OK; +} + +int setup_tcp_socket(ps_io_ops_t *io_ops) +{ + ops = io_ops; + tcp_main_socket = tcp_new_ip_type(IPADDR_TYPE_V4); + if (tcp_main_socket == NULL) { + ZF_LOGE("Failed to open a socket for listening for and accepting clients"); + return -1; + } + tcp_sent(tcp_main_socket, lwip_sent_callback); + tcp_recv(tcp_main_socket, lwip_tcp_recv_callback); + err_t error = tcp_bind(tcp_main_socket, IP_ANY_TYPE, TCP_ECHO_PORT); + if (error) { + ZF_LOGE("Failed to bind the TCP socket"); + return -1; + } + tcp_main_socket = tcp_listen_with_backlog_and_err(tcp_main_socket, MAX_TCP_CLIENTS, &error); + if (error != ERR_OK) { + ZF_LOGE("Failed to listen on the TCP socket"); + } + tcp_accept(tcp_main_socket, lwip_accept_callback); + return 0; +} + +CAMKES_POST_INIT_MODULE_DEFINE(setup_tcp_socket_, setup_tcp_socket); diff --git a/apps/lwipserver2/src/udp_echo_socket.c b/apps/lwipserver2/src/udp_echo_socket.c new file mode 100644 index 00000000..5c4024cc --- /dev/null +++ b/apps/lwipserver2/src/udp_echo_socket.c @@ -0,0 +1,47 @@ +/* + * Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include + +#include + +#include +#include +#include + +#include "ports.h" +#include + +static char udp_data_packet[0x1000] ALIGN(0x1000); + +static struct udp_pcb *udp_socket; + +static void lwip_udp_recv_callback(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port) +{ + err_t error = udp_sendto(pcb, p, addr, port); + ZF_LOGF_IF(error, "Failed to send UDP packet through socket"); + pbuf_free(p); +} + +int setup_udp_socket(UNUSED ps_io_ops_t *io_ops) +{ + udp_socket = udp_new_ip_type(IPADDR_TYPE_V4); + if (udp_socket == NULL) { + ZF_LOGE("Failed to open a UDP socket"); + return -1; + } + udp_recv(udp_socket, lwip_udp_recv_callback, udp_socket); + int error = udp_bind(udp_socket, IP_ANY_TYPE, UDP_ECHO_PORT); + if (error) { + ZF_LOGE("Failed to bind the UDP socket"); + return -1; + } + + return 0; +} + +CAMKES_POST_INIT_MODULE_DEFINE(setup_udp_socket_, setup_udp_socket); diff --git a/apps/lwipserver2/src/utilization_socket.c b/apps/lwipserver2/src/utilization_socket.c new file mode 100644 index 00000000..8ad9f7fe --- /dev/null +++ b/apps/lwipserver2/src/utilization_socket.c @@ -0,0 +1,155 @@ +/* + * Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include + +#include + +#include +#include +#include + +#include "ports.h" +#include + +/* This file implements a TCP based utilization measurment process that starts + * and stops utilization measurements based on a client's requests. + * The protocol used to communicate is as follows: + * - Client connects + * - Server sends: 100 IPBENCH V1.0\n + * - Client sends: HELLO\n + * - Server sends: 200 OK (Ready to go)\n + * - Client sends: LOAD cpu_target_lukem\n + * - Server sends: 200 OK\n + * - Client sends: SETUP args::""\n + * - Server sends: 200 OK\n + * - Client sends: START\n + * - Client sends: STOP\n + * - Server sends: 220 VALID DATA (Data to follow)\n + * Content-length: %d\n + * ${content}\n + * - Server closes socket. + * + * It is also possible for client to send QUIT\n during operation. + * + * The server starts recording utilization stats when it receives START and + * finishes recording when it receives STOP. + * + * Only one client can be connected. + */ + +static struct tcp_pcb *utiliz_socket; +static char data_packet[0x1000] ALIGN(0x1000); + +#define WHOAMI "100 IPBENCH V1.0\n" +#define HELLO "HELLO\n" +#define OK_READY "200 OK (Ready to go)\n" +#define LOAD "LOAD cpu_target_lukem\n" +#define OK "200 OK\n" +#define SETUP "SETUP args::\"\"\n" +#define START "START\n" +#define STOP "STOP\n" +#define QUIT "QUIT\n" +#define RESPONSE "220 VALID DATA (Data to follow)\n" \ + "Content-length: %d\n" \ + "%s\n" +#define IDLE_FORMAT ",%ld,%ld" +#define msg_match(msg, match) (strncmp(msg, match, strlen(match))==0) + +static err_t utilization_sent_callback(void *arg, struct tcp_pcb *pcb, u16_t len) +{ + return ERR_OK; +} + +static err_t utilization_recv_callback(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) +{ + if (p == NULL) { + tcp_close(pcb); + return ERR_OK; + } + + pbuf_copy_partial(p, data_packet, p->tot_len, 0); + err_t error; + + if (msg_match(data_packet, HELLO)) { + error = tcp_write(pcb, OK_READY, strlen(OK_READY), TCP_WRITE_FLAG_COPY); + ZF_LOGF_IF(error, "Failed to send OK_READY message through utilization peer"); + } else if (msg_match(data_packet, LOAD)) { + error = tcp_write(pcb, OK, strlen(OK), TCP_WRITE_FLAG_COPY); + ZF_LOGF_IF(error, "Failed to send OK message through utilization peer"); + } else if (msg_match(data_packet, SETUP)) { + error = tcp_write(pcb, OK, strlen(OK), TCP_WRITE_FLAG_COPY); + ZF_LOGF_IF(error, "Failed to send OK message through utilization peer"); + } else if (msg_match(data_packet, START)) { + idle_start(); + } else if (msg_match(data_packet, STOP)) { + uint64_t total, kernel, idle; + idle_stop(&total, &kernel, &idle); + + char *util_msg; + int len = asprintf(&util_msg, IDLE_FORMAT, idle, total); + if (len == -1) { + ZF_LOGE("Failed to format the utilisation message for ipbench"); + } else { + char *response; + len = asprintf(&response, RESPONSE, len + 1, util_msg); + if (len == -1) { + ZF_LOGE("Failed to format the response message for ipbench"); + } else { + error = tcp_write(pcb, response, len, TCP_WRITE_FLAG_COPY); + free(response); + } + free(util_msg); + } + tcp_shutdown(pcb, 0, 1); + } else if (msg_match(data_packet, QUIT)) { + /* Do nothing for now */ + } else { + printf("Received a message that we can't handle %s\n", data_packet); + } + + return ERR_OK; +} + +static err_t utilization_accept_callback(void *arg, struct tcp_pcb *newpcb, err_t err) +{ + printf("Utilization connection established!\n"); + err_t error = tcp_write(newpcb, WHOAMI, strlen(WHOAMI), TCP_WRITE_FLAG_COPY); + ZF_LOGF_IF(error, "Failed to send WHOAMI message through utilization peer"); + tcp_sent(newpcb, utilization_sent_callback); + tcp_recv(newpcb, utilization_recv_callback); + return ERR_OK; +} + +int setup_utilization_socket(UNUSED ps_io_ops_t *io_ops) +{ + utiliz_socket = tcp_new_ip_type(IPADDR_TYPE_V4); + if (utiliz_socket == NULL) { + ZF_LOGE("Failed to open a socket for listening!"); + return -1; + + } + + err_t error = tcp_bind(utiliz_socket, IP_ANY_TYPE, UTILIZATION_PORT); + if (error) { + ZF_LOGE("Failed to bind the TCP socket"); + return -1; + } else { + printf("Utilisation port bound to port %d\n", UTILIZATION_PORT); + } + + utiliz_socket = tcp_listen_with_backlog_and_err(utiliz_socket, 1, &error); + if (error != ERR_OK) { + ZF_LOGE("Failed to listen on the utilization socket"); + } + tcp_accept(utiliz_socket, utilization_accept_callback); + + return 0; +} + +CAMKES_POST_INIT_MODULE_DEFINE(setup_utilization_socket_, setup_utilization_socket); diff --git a/apps/lwipserver2/x86_64_eth_init.c b/apps/lwipserver2/x86_64_eth_init.c new file mode 100644 index 00000000..89ccc62e --- /dev/null +++ b/apps/lwipserver2/x86_64_eth_init.c @@ -0,0 +1,59 @@ +/* + * Copyright 2019, Data61, CSIRO (ABN 41 687 119 230) + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include +#include + + +int ethif_init(struct eth_driver *eth_driver, ps_io_ops_t *io_ops) +{ + ethif_intel_config_t *eth_config = calloc(1, sizeof(ethif_intel_config_t) + sizeof(ps_irq_t)); + *eth_config = (ethif_intel_config_t) { + /* Ethdriver component dataport */ + .bar0 = (void *)EthDriver, + .prom_mode = (uint8_t) promiscuous_mode, + .num_irqs = 1 + }; + + eth_config->irq_info[0] = (ps_irq_t) { + .type = PS_IOAPIC, .ioapic = { .ioapic = 0, .pin = 16, + .level = 1, .polarity = 1, + .vector = 16 + } + }; + + int error = ethif_e82574_init(eth_driver, *io_ops, eth_config); + if (error) { + ZF_LOGF("ERROR init ethernet"); + return error; + } + + return 0; +} + +static int init_device(ps_io_ops_t *io_ops) +{ + + struct eth_driver *eth_driver; + int error = ps_calloc(&io_ops->malloc_ops, 1, sizeof(*eth_driver), (void **)ð_driver); + if (error) { + ZF_LOGE("Failed to allocate struct for ethdriver"); + return error; + } + + error = ethif_init(eth_driver, io_ops); + if (error) { + ZF_LOGE("Failed to initialize ethernet driver"); + return error; + } + return 0; +} + + +CAMKES_PRE_INIT_MODULE_DEFINE(ethdriver_setup, init_device); +