From 0729fd4b361172de510a989e94542e39f365ed7a Mon Sep 17 00:00:00 2001 From: James Archer Date: Wed, 15 Jan 2025 17:06:32 +1100 Subject: [PATCH 1/3] net: fix inconsistencies with network_components.mk snippet Co-authored-by: Courtney Darville Signed-off-by: James Archer --- network/components/network_components.mk | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/network/components/network_components.mk b/network/components/network_components.mk index 904a728c5..6b0d82f60 100644 --- a/network/components/network_components.mk +++ b/network/components/network_components.mk @@ -46,10 +46,11 @@ network/components/network_arp.o: ${SDDF}/network/components/arp.c ${LD} ${LDFLAGS} -o $@ $< ${LIBS} clean:: - rm -f network_virt_[rt]x.[od] network_copy.[od] network_arp.[od] + ${RM} -f network_virt_[rt]x.[od] network_copy.[od] network_arp.[od] clobber:: - rm -f ${IMAGES} + ${RM} -f ${NETWORK_IMAGES} + rmdir network/components network/components: mkdir -p $@ From 0a0d42717764c724c2a3e1d5f618e773d37341b5 Mon Sep 17 00:00:00 2001 From: James Archer Date: Thu, 30 Jan 2025 15:57:40 +1100 Subject: [PATCH 2/3] net: create lib_sddf_lwip helper library for clients using lwip Co-authored-by: Courtney Darville Co-authored-by: James Archer Signed-off-by: James Archer --- include/sddf/network/lib_sddf_lwip.h | 114 +++++++ network/lib_sddf_lwip/lib_sddf_lwip.c | 428 +++++++++++++++++++++++++ network/lib_sddf_lwip/lib_sddf_lwip.mk | 115 +++++++ 3 files changed, 657 insertions(+) create mode 100644 include/sddf/network/lib_sddf_lwip.h create mode 100644 network/lib_sddf_lwip/lib_sddf_lwip.c create mode 100644 network/lib_sddf_lwip/lib_sddf_lwip.mk diff --git a/include/sddf/network/lib_sddf_lwip.h b/include/sddf/network/lib_sddf_lwip.h new file mode 100644 index 000000000..2e5cf3ca4 --- /dev/null +++ b/include/sddf/network/lib_sddf_lwip.h @@ -0,0 +1,114 @@ +/* + * Copyright 2022, UNSW + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include +#include +#include +#include +#include "lwip/pbuf.h" + +#define SDDF_LIB_SDDF_LWIP_MAGIC_LEN 5 +static char SDDF_LIB_SDDF_LWIP_MAGIC[SDDF_NET_MAGIC_LEN] = { 's', 'D', 'D', 'F', 0x8 }; + +/* Default ethernet MTU. */ +#define SDDF_LWIP_ETHER_MTU 1500 + +/* Definitions for sDDF error constants. */ +typedef enum { + /* No error, everything OK. */ + SDDF_LWIP_ERR_OK = 0, + /* Pbuf too large for sDDF buffer. */ + SDDF_LWIP_ERR_PBUF = -1, + /* No buffers available. */ + SDDF_LWIP_ERR_NO_BUF = -2, + /* Pbuf successfully enqueued to be sent later. */ + SDDF_LWIP_ERR_ENQUEUED = -3, + /* Could not resolve error. */ + SDDF_LWIP_ERR_UNHANDLED = -4 +} net_sddf_err_t; + +typedef struct lib_sddf_lwip_config { + char magic[SDDF_LIB_SDDF_LWIP_MAGIC_LEN]; + region_resource_t pbuf_pool; + uint64_t num_pbufs; +} lib_sddf_lwip_config_t; + +/** + * Function type for output of sDDF LWIP errors. + */ +typedef int (*sddf_lwip_err_output_fn)(const char *format, ...) __attribute__((format(__printf__, 1, 2))); + +/** + * Function type for netif status callback. Invoked by LWIP upon + * successfully obtaining an IP address for the network interface. + */ +typedef void (*sddf_lwip_netif_status_callback_fn)(char *ip_addr); + +/** + * Function type for handling function which is optionally invoked + * when a pbuf is unable to be sent due to no available sDDF tx buffers. + * Can be used to store pbuf until more buffers are available. + */ +typedef net_sddf_err_t (*sddf_lwip_handle_empty_tx_free_fn)(struct pbuf *p); + +/** + * Checks LWIP system timeouts. Should be invoked after every LWIP tick. + */ +void sddf_lwip_process_timeout(void); + +/** + * Transmits the provided pbuf through the sddf network system. + * + * @param p pbuf to be transmitted. + * + * @return If the pbuf is sent successfully, SDDF_LWIP_ERR_OK is returned and the + * pbuf can safely be freed. If the pbuf is too large, SDDF_LWIP_ERR_PBUF is + * returned. If there are no free sDDF buffers available, + * handle_empty_tx_free will be called with the pbuf, and the return value + * will be returned. + */ +net_sddf_err_t sddf_lwip_transmit_pbuf(struct pbuf *p); + +/** + * Handles the passing of incoming packets in sDDF buffers to LWIP. Must be + * called to process the sDDF RX queue each time a notification is received + * from the network virtualiser. + */ +void sddf_lwip_process_rx(void); + +/** + * Handles the sending of notifications to the network RX and TX virtualisers. + * Must be invoked at the end of each event handling loop and initialisation + * to ensure outgoing buffers are processed by the virtualisers. + */ +void sddf_lwip_maybe_notify(void); + +/** + * Initialisation function for the sDDF LWIP library. Must be called prior + * to using any other library functions. + * + * @param lib_sddf_lwip_config config structure for this library + * @param net_config sDDF-Net config resource structure + * @param timer_config sDDF-Timer config resource structure + * @param rx_queue RX net queue handle data structure. Must be initialised + * prior to being passed to this function. + * @param tx_queue TX net queue handle data structure. Must be initialised + * prior to being passed to this function. + * @param err_output function pointer to optional user provided error + * output function. Provide NULL to use default sddf_printf_. + * @param netif_callback function pointer to optional user provided netif + * status callback function. Provide NULL to use err_output to print client + * MAC address and obtained IP address. + * @param handle_empty_tx_free function pointer to optional user provided + * handling function for no available sDDF TX buffers during sending of LWIP + * pbuf. Provide NULL to leave unhandled. + */ +void sddf_lwip_init(lib_sddf_lwip_config_t *lib_sddf_lwip_config, net_client_config_t *net_config, + timer_client_config_t *timer_config, net_queue_handle_t rx_queue, net_queue_handle_t tx_queue, + sddf_lwip_err_output_fn err_output, sddf_lwip_netif_status_callback_fn netif_callback, + sddf_lwip_handle_empty_tx_free_fn handle_empty_tx_free); diff --git a/network/lib_sddf_lwip/lib_sddf_lwip.c b/network/lib_sddf_lwip/lib_sddf_lwip.c new file mode 100644 index 000000000..7d4e40534 --- /dev/null +++ b/network/lib_sddf_lwip/lib_sddf_lwip.c @@ -0,0 +1,428 @@ +/* + * Copyright 2022, UNSW + * SPDX-License-Identifier: BSD-2-Clause + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "lwip/err.h" +#include "lwip/init.h" +#include "lwip/ip4_addr.h" +#include "netif/etharp.h" +#include "lwip/pbuf.h" +#include "lwip/netif.h" +#include "lwip/snmp.h" +#include "lwip/sys.h" +#include "lwip/timeouts.h" +#include "lwip/dhcp.h" + +typedef struct lwip_state { + /* LWIP network interface struct. */ + struct netif netif; + /* MAC address of client. */ + uint8_t mac[6]; + /* Output function used to print error messages. */ + sddf_lwip_err_output_fn err_output; + /* Callback function to be invoked when ip address is obtained. */ + sddf_lwip_netif_status_callback_fn netif_callback; + /* Function that optionally handles when no free tx buffers available. */ + sddf_lwip_handle_empty_tx_free_fn handle_empty_tx_free; +} lwip_state_t; + +typedef struct sddf_state { + /* sddf net rx queue handle. */ + net_queue_handle_t rx_queue; + /* sddf net tx queue handle. */ + net_queue_handle_t tx_queue; + /* sddf channel for net rx virt. */ + microkit_channel rx_ch; + /* sddf channel for net tx virt. */ + microkit_channel tx_ch; + /* Base address of data region containing rx buffers. */ + uintptr_t rx_buffer_data_region; + /* Base address of data region containing tx buffers. */ + uintptr_t tx_buffer_data_region; + /* Boolean indicating whether buffers have been given to rx virt. */ + bool notify_rx; + /* Boolean indicating whether buffers have been given to tx virt. */ + bool notify_tx; + /* sddf channel for timer. */ + microkit_channel timer_ch; +} sddf_state_t; + +/* Wrapper over custom_pbuf structure to keep track of buffer's offset into data region. */ +typedef struct pbuf_custom_offset { + struct pbuf_custom custom; + uint64_t offset; +} pbuf_custom_offset_t; + +typedef struct pbuf_pool { + union { + pbuf_custom_offset_t pbuf; + size_t next_free; + } *pbufs; + size_t capacity; + size_t first_free; +} pbuf_pool_t; + +lib_sddf_lwip_config_t lib_config; +lwip_state_t lwip_state; +sddf_state_t sddf_state; +pbuf_pool_t pbuf_pool; + +pbuf_pool_t pbuf_pool_init(void *mem, size_t mem_size, size_t pbuf_count) +{ + assert(mem != NULL); + assert(pbuf_count != 0); + assert(pbuf_count == mem_size / sizeof(pbuf_custom_offset_t)); + + pbuf_pool_t pool = { + .pbufs = mem, + .first_free = 0, + .capacity = pbuf_count, + }; + + for (size_t i = 0; i < pbuf_count - 1; i++) { + pool.pbufs[i].next_free = i + 1; + } + pool.pbufs[pbuf_count - 1].next_free = SIZE_MAX; + + return pool; +} + +pbuf_custom_offset_t *pbuf_pool_alloc(pbuf_pool_t *pool) +{ + assert(pool != NULL); + + if (pool->first_free == SIZE_MAX) { + return NULL; + } + + size_t first_free = pool->first_free; + pool->first_free = pool->pbufs[first_free].next_free; + return &pool->pbufs[first_free].pbuf; +} + +void pbuf_pool_free(pbuf_pool_t *pool, pbuf_custom_offset_t *pbuf) +{ + assert(pool != NULL); + assert(pbuf != NULL); + assert((pbuf_custom_offset_t *)pool->pbufs <= pbuf); + assert(pbuf < (pbuf_custom_offset_t *)&pool->pbufs[pool->capacity]); + + size_t idx = pbuf - (pbuf_custom_offset_t *)pool->pbufs; + pool->pbufs[idx].next_free = pool->first_free; + pool->first_free = idx; +} + +/** + * Helper function to convert sddf errors to lwip errors. + * + * @param sddf_err sddf error. + * + * @return Equivalent lwip error. + */ +static err_t sddf_err_to_lwip_err(net_sddf_err_t sddf_err) +{ + switch (sddf_err) { + case SDDF_LWIP_ERR_OK: + return ERR_OK; + case SDDF_LWIP_ERR_PBUF: + return ERR_BUF; + case SDDF_LWIP_ERR_NO_BUF: + return ERR_MEM; + case SDDF_LWIP_ERR_ENQUEUED: + return ERR_OK; + case SDDF_LWIP_ERR_UNHANDLED: + return ERR_MEM; + } + return ERR_ARG; +} + +/** + * Default netif status callback function. Prints client MAC address and + * obtained ip address. + * + * @param ip_addr Obtained ip address as a string. + */ +static void netif_status_callback_default(char *ip_addr) +{ + uint8_t *mac = lwip_state.netif.hwaddr; + lwip_state.err_output("LWIP|NOTICE: DHCP request for mac " + "%02x:%02x:%02x:%02x:%02x:%02x " + "returned ip address: %s\n", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], ip_addr); +} + +/** + * Default handling function to be called during transmission if tx free + * queue is empty. + * + * @param p pbuf that could not be sent due to queue being empty. + * + * @return Simply returns the sddf error indicating nothing was done. + */ +static net_sddf_err_t handle_empty_tx_free_default(struct pbuf *p) +{ + return SDDF_LWIP_ERR_UNHANDLED; +} + +/** + * Returns current time from the timer. + */ +uint32_t sys_now(void) +{ + return sddf_timer_time_now(sddf_state.timer_ch) / NS_IN_MS; +} + +void sddf_lwip_process_timeout() +{ + sys_check_timeouts(); +} + +/** + * Free a pbuf. This also returns the underlying sddf buffer to the receive free ring. + * + * @param p pbuf to free. + */ +static void interface_free_buffer(struct pbuf *p) +{ + SYS_ARCH_DECL_PROTECT(old_level); + pbuf_custom_offset_t *custom_pbuf_offset = (pbuf_custom_offset_t *)p; + SYS_ARCH_PROTECT(old_level); + net_buff_desc_t buffer = { custom_pbuf_offset->offset, 0 }; + int err = net_enqueue_free(&(sddf_state.rx_queue), buffer); + assert(!err); + sddf_state.notify_rx = true; + pbuf_pool_free(&pbuf_pool, custom_pbuf_offset); + SYS_ARCH_UNPROTECT(old_level); +} + +/** + * Create a pbuf structure to pass to the network interface. + * + * @param offset offset into the data region of the buffer to be passed. + * @param length length of data. + * + * @return the newly created pbuf. Can be cast to pbuf_custom. + */ +static struct pbuf *create_interface_buffer(uint64_t offset, size_t length) +{ + pbuf_custom_offset_t *custom_pbuf_offset = (pbuf_custom_offset_t *)pbuf_pool_alloc(&pbuf_pool); + custom_pbuf_offset->offset = offset; + custom_pbuf_offset->custom.custom_free_function = interface_free_buffer; + + return pbuf_alloced_custom(PBUF_RAW, length, PBUF_REF, &custom_pbuf_offset->custom, + (void *)(offset + sddf_state.rx_buffer_data_region), NET_BUFFER_SIZE); +} + +/** + * Copy a pbuf into an sddf buffer and insert it into the transmit active queue. + * + * @param netif lwip network interface state. + * @param p pbuf to be transmitted. + * + * @return If the pbuf is sent, ERR_OK is returned and the pbuf can safely be + * freed. If the pbuf is too large ERR_MEM is returned. If there are no free + * sddf buffers available, handle_empty_tx_free will be called with the pbuf, + * and the equivalent lwip error will be returned. + */ +static err_t lwip_eth_send(struct netif *netif, struct pbuf *p) +{ + if (p->tot_len > NET_BUFFER_SIZE) { + lwip_state.err_output("LWIP|ERROR: attempted to send a packet of size %u > BUFFER SIZE %u\n", p->tot_len, + NET_BUFFER_SIZE); + return ERR_MEM; + } + + if (net_queue_empty_free(&sddf_state.tx_queue)) { + return sddf_err_to_lwip_err(lwip_state.handle_empty_tx_free(p)); + } + + net_buff_desc_t buffer; + int err = net_dequeue_free(&sddf_state.tx_queue, &buffer); + assert(!err); + + uintptr_t frame = buffer.io_or_offset + sddf_state.tx_buffer_data_region; + uint16_t copied = 0; + for (struct pbuf *curr = p; curr != NULL; curr = curr->next) { + memcpy((void *)(frame + copied), curr->payload, curr->len); + copied += curr->len; + } + + buffer.len = copied; + err = net_enqueue_active(&sddf_state.tx_queue, buffer); + assert(!err); + + sddf_state.notify_tx = true; + + return ERR_OK; +} + +net_sddf_err_t sddf_lwip_transmit_pbuf(struct pbuf *p) +{ + if (p->tot_len > NET_BUFFER_SIZE) { + lwip_state.err_output("LWIP|ERROR: attempted to send a packet of size %u > BUFFER SIZE %u\n", p->tot_len, + NET_BUFFER_SIZE); + return SDDF_LWIP_ERR_PBUF; + } + + if (net_queue_empty_free(&sddf_state.tx_queue)) { + return lwip_state.handle_empty_tx_free(p); + } + + err_t err = lwip_eth_send(&lwip_state.netif, p); + assert(!err); + + return SDDF_LWIP_ERR_OK; +} + +void sddf_lwip_process_rx(void) +{ + bool reprocess = true; + while (reprocess) { + while (!net_queue_empty_active(&sddf_state.rx_queue)) { + net_buff_desc_t buffer; + int err = net_dequeue_active(&sddf_state.rx_queue, &buffer); + assert(!err); + + struct pbuf *p = create_interface_buffer(buffer.io_or_offset, buffer.len); + assert(p != NULL); + if (lwip_state.netif.input(p, &lwip_state.netif) != ERR_OK) { + lwip_state.err_output("LWIP|ERROR: unknown error inputting pbuf into network stack\n"); + pbuf_free(p); + } + } + + net_request_signal_active(&sddf_state.rx_queue); + reprocess = false; + + if (!net_queue_empty_active(&sddf_state.rx_queue)) { + net_cancel_signal_active(&sddf_state.rx_queue); + reprocess = true; + } + } +} + +/** + * Initialise the network interface data structure. + * + * @param netif network interface data structure. + */ +static err_t ethernet_init(struct netif *netif) +{ + if (netif->state == NULL) { + return ERR_ARG; + } + + memcpy(netif->hwaddr, lwip_state.mac, 6); + netif->mtu = SDDF_LWIP_ETHER_MTU; + netif->hwaddr_len = ETHARP_HWADDR_LEN; + netif->output = etharp_output; + netif->linkoutput = lwip_eth_send; + netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP | NETIF_FLAG_IGMP; + + return ERR_OK; +} + +/** + * Network interface callback function invoked when DHCP packets are received. + * If an ip address is successfully obtained, the provided netif_callback + * function will be invoked with the ip address as a string. + * + * @param netif network interface data structure. + */ +static void netif_status_callback(struct netif *netif) +{ + if (dhcp_supplied_address(netif)) { + char ip4_str[IP4ADDR_STRLEN_MAX]; + lwip_state.netif_callback(ip4addr_ntoa_r(netif_ip4_addr(netif), ip4_str, IP4ADDR_STRLEN_MAX)); + } +} + +void sddf_lwip_init(lib_sddf_lwip_config_t *lib_sddf_lwip_config, net_client_config_t *net_config, + timer_client_config_t *timer_config, net_queue_handle_t rx_queue, net_queue_handle_t tx_queue, + sddf_lwip_err_output_fn err_output, sddf_lwip_netif_status_callback_fn netif_callback, + sddf_lwip_handle_empty_tx_free_fn handle_empty_tx_free) +{ + char *magic = (char *)lib_sddf_lwip_config; + for (int i = 0; i < SDDF_LIB_SDDF_LWIP_MAGIC_LEN; i++) { + if (magic[i] != SDDF_LIB_SDDF_LWIP_MAGIC[i]) { + assert(false); + } + } + lib_config = *lib_sddf_lwip_config; + + /* Initialise sddf state */ + sddf_state.rx_queue = rx_queue; + sddf_state.tx_queue = tx_queue; + sddf_state.rx_ch = net_config->rx.id; + sddf_state.tx_ch = net_config->tx.id; + sddf_state.rx_buffer_data_region = net_config->rx_data.vaddr; + sddf_state.tx_buffer_data_region = net_config->tx_data.vaddr; + sddf_state.timer_ch = timer_config->driver_id; + + /* Initialise lwip state */ + sddf_memcpy(lwip_state.mac, net_config->mac_addr, 6); + lwip_state.err_output = (err_output == NULL) ? sddf_printf_ : err_output; + lwip_state.netif_callback = (netif_callback == NULL) ? netif_status_callback_default : netif_callback; + lwip_state.handle_empty_tx_free = (handle_empty_tx_free == NULL) ? handle_empty_tx_free_default + : handle_empty_tx_free; + + lwip_init(); + + pbuf_pool = pbuf_pool_init(lib_config.pbuf_pool.vaddr, lib_config.pbuf_pool.size, lib_config.num_pbufs); + + /* Set dummy IP configuration values to get lwIP bootstrapped */ + struct ip4_addr netmask, ipaddr, gw, multicast; + ipaddr_aton("0.0.0.0", &gw); + ipaddr_aton("0.0.0.0", &ipaddr); + ipaddr_aton("0.0.0.0", &multicast); + ipaddr_aton("255.255.255.0", &netmask); + + lwip_state.netif.name[0] = 'e'; + lwip_state.netif.name[1] = '0'; + + if (!netif_add(&(lwip_state.netif), &ipaddr, &netmask, &gw, (void *)&lwip_state, ethernet_init, ethernet_input)) { + lwip_state.err_output("LWIP|ERROR: Netif add returned NULL\n"); + } + + netif_set_default(&(lwip_state.netif)); + netif_set_status_callback(&(lwip_state.netif), netif_status_callback); + netif_set_up(&(lwip_state.netif)); + + if (dhcp_start(&(lwip_state.netif))) { + lwip_state.err_output("LWIP|ERROR: failed to start DHCP negotiation\n"); + } +} + +void sddf_lwip_maybe_notify() +{ + if (sddf_state.notify_rx && net_require_signal_free(&sddf_state.rx_queue)) { + net_cancel_signal_free(&sddf_state.rx_queue); + sddf_state.notify_rx = false; + if (!microkit_have_signal) { + microkit_deferred_notify(sddf_state.rx_ch); + } else if (microkit_signal_cap != BASE_OUTPUT_NOTIFICATION_CAP + sddf_state.rx_ch) { + microkit_notify(sddf_state.rx_ch); + } + } + + if (sddf_state.notify_tx && net_require_signal_active(&sddf_state.tx_queue)) { + net_cancel_signal_active(&sddf_state.tx_queue); + sddf_state.notify_tx = false; + if (!microkit_have_signal) { + microkit_deferred_notify(sddf_state.tx_ch); + } else if (microkit_signal_cap != BASE_OUTPUT_NOTIFICATION_CAP + sddf_state.tx_ch) { + microkit_notify(sddf_state.tx_ch); + } + } +} diff --git a/network/lib_sddf_lwip/lib_sddf_lwip.mk b/network/lib_sddf_lwip/lib_sddf_lwip.mk new file mode 100644 index 000000000..704d3e711 --- /dev/null +++ b/network/lib_sddf_lwip/lib_sddf_lwip.mk @@ -0,0 +1,115 @@ +# +# Copyright 2025, UNSW +# +# SPDX-License-Identifier: BSD-2-Clause +# +# This Makefile snippet builds the lib_sddf_lwip library +# The library provides a helper interface for using lwIP +# in an sDDF-net client. It also includes the necessary +# lwIP objects. +# +# NOTES: +# Generates lib_sddf_lwip.a or lib_sddf_lwip%.a. That is, +# it can generate different versions of the library with +# the same filename stem. This is useful if you want to +# build multiple different versions with different build- +# time configurations. CFLAGS can be configured using the +# SDDF_LWIP_CFLAGS variable, as well as its suffixed +# variant. +# +# For example, if you only need to generate one version +# of the library, usage is simple: +# +# LIB_SDDF_LWIP_CFLAGS := -O2 +# include lib_sddf_lwip.mk +# my_program.elf: lib_sddf_lwip.a +# +# However, if you have two different programs requiring +# two differently configured versions of the library, you +# can do this instead: +# +# LIB_SDDF_LWIP_CFLAGS_0 := -O0 -g +# LIB_SDDF_LWIP_CFLAGS_1 := -O3 +# include lib_sddf_lwip.mk +# program_0.elf: lib_sddf_lwip_0.a +# program_1.elf: lib_sddf_lwip_1.a +# + + +LIB_SDDF_LWIP_DIR := $(dir $(lastword $(MAKEFILE_LIST))) +LIB_SDDF_LWIP_LWIP_FILES := \ + core/init.c \ + api/err.c \ + core/def.c \ + core/dns.c \ + core/inet_chksum.c \ + core/ip.c \ + core/mem.c \ + core/memp.c \ + core/netif.c \ + core/pbuf.c \ + core/raw.c \ + core/stats.c \ + core/sys.c \ + core/altcp.c \ + core/altcp_alloc.c \ + core/altcp_tcp.c \ + core/tcp.c \ + core/tcp_in.c \ + core/tcp_out.c \ + core/timeouts.c \ + core/udp.c \ + core/ipv4/autoip.c \ + core/ipv4/dhcp.c \ + core/ipv4/etharp.c \ + core/ipv4/icmp.c \ + core/ipv4/igmp.c \ + core/ipv4/ip4_frag.c \ + core/ipv4/ip4.c \ + core/ipv4/ip4_addr.c \ + netif/ethernet.c + +lib_sddf_lwip.a: lib_sddf_lwip_out/lib_sddf_lwip.o $(addprefix lib_sddf_lwip_out/, $(LIB_SDDF_LWIP_LWIP_FILES:.c=.o)) + $(AR) rv $@ $^ + $(RANLIB) $@ + +lib_sddf_lwip%.a: lib_sddf_lwip_out%/lib_sddf_lwip.o $(addprefix lib_sddf_lwip_out%/, $(LIB_SDDF_LWIP_LWIP_FILES:.c=.o)) + $(AR) rv $@ $^ + $(RANLIB) $@ + +lib_sddf_lwip_out/lib_sddf_lwip.o: CFLAGS += $(LIB_SDDF_LWIP_CFLAGS) +lib_sddf_lwip_out/lib_sddf_lwip.o: $(CHECK_FLAGS_BOARD_MD5) +lib_sddf_lwip_out/lib_sddf_lwip.o: $(LIB_SDDF_LWIP_DIR)/lib_sddf_lwip.c + mkdir -p $(dir $@) + $(CC) $(CFLAGS) -c -o $@ $< + +lib_sddf_lwip_out%/lib_sddf_lwip.o: CFLAGS += $(LIB_SDDF_LWIP_CFLAGS$*) +lib_sddf_lwip_out%/lib_sddf_lwip.o: $(CHECK_FLAGS_BOARD_MD5) +lib_sddf_lwip_out%/lib_sddf_lwip.o: $(LIB_SDDF_LWIP_DIR)/lib_sddf_lwip.c + mkdir -p $(dir $@) + $(CC) $(CFLAGS) -c -o $@ $< + +$(foreach f,$(LIB_SDDF_LWIP_LWIP_FILES), \ + $(eval \ + lib_sddf_lwip_out/$(f:.c=.o): $(SDDF)/network/ipstacks/lwip/src/$(f) ; \ + mkdir -p $$(dir $$@); \ + $$(CC) $$(CFLAGS) $$(LIB_SDDF_LWIP_CFLAGS) -c -o $$@ $$< \ + ) \ + $(eval \ + lib_sddf_lwip_out%/$(f:.c=.o): $(SDDF)/network/ipstacks/lwip/src/$(f) ; \ + mkdir -p $$(dir $$@); \ + $$(CC) $$(CFLAGS) $$(LIB_SDDF_LWIP_CFLAGS$*) -c -o $$@ $$< \ + ) \ +) + +clean:: + $(RM) -f lib_sddf_lwip_out* + +clobber:: clean + $(RM) -f lib_sddf_lwip*.a + +-include $(wildcard lib_sddf_lwip_out*/*.d) +-include $(wildcard lib_sddf_lwip_out*/core/*.d) +-include $(wildcard lib_sddf_lwip_out*/core/ipv4/*.d) +-include $(wildcard lib_sddf_lwip_out*/api/*.d) +-include $(wildcard lib_sddf_lwip_out*/netif/*.d) From 962766ddf24db93b2c120c3dad058967fd24a2fc Mon Sep 17 00:00:00 2001 From: James Archer Date: Thu, 30 Jan 2025 15:58:27 +1100 Subject: [PATCH 3/3] echo_server: use lib_sddf_lwip Co-authored-by: Courtney Darville Co-authored-by: James Archer Signed-off-by: James Archer --- examples/echo_server/echo.c | 161 +++++++++++++++ examples/echo_server/echo.h | 3 - examples/echo_server/echo.mk | 49 ++--- examples/echo_server/lwip.c | 379 ----------------------------------- examples/echo_server/meta.py | 11 +- 5 files changed, 190 insertions(+), 413 deletions(-) create mode 100644 examples/echo_server/echo.c delete mode 100644 examples/echo_server/lwip.c diff --git a/examples/echo_server/echo.c b/examples/echo_server/echo.c new file mode 100644 index 000000000..b10da4b58 --- /dev/null +++ b/examples/echo_server/echo.c @@ -0,0 +1,161 @@ +/* + * Copyright 2022, UNSW + * SPDX-License-Identifier: BSD-2-Clause + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "lwip/pbuf.h" + +#include "echo.h" + +__attribute__((__section__(".serial_client_config"))) serial_client_config_t serial_config; + +__attribute__((__section__(".timer_client_config"))) timer_client_config_t timer_config; + +__attribute__((__section__(".net_client_config"))) net_client_config_t net_config; + +__attribute__((__section__(".benchmark_client_config"))) benchmark_client_config_t benchmark_config; + +__attribute__((__section__(".lib_sddf_lwip_config"))) lib_sddf_lwip_config_t lib_sddf_lwip_config; + +serial_queue_handle_t serial_tx_queue_handle; + +net_queue_handle_t net_rx_handle; +net_queue_handle_t net_tx_handle; + +#define LWIP_TICK_MS 100 + +struct pbuf *head; +struct pbuf *tail; + +/** + * Netif status callback function that output's client's Microkit name and + * obtained IP address. + * + * @param ip_addr ip address of the client. + */ +void netif_status_callback(char *ip_addr) +{ + sddf_printf("DHCP request finished, IP address for netif %s is: %s\n", microkit_name, ip_addr); +} + +/** + * Sets a timeout for the next lwip tick. + */ +void set_timeout(void) +{ + sddf_timer_set_timeout(timer_config.driver_id, LWIP_TICK_MS * NS_IN_MS); +} + +/** + * Stores a pbuf to be transmitted upon available transmit buffers. + * + * @param p pbuf to be stored. + */ +net_sddf_err_t enqueue_pbufs(struct pbuf *p) +{ + /* Indicate to the tx virt that we wish to be notified about free tx buffers */ + net_request_signal_free(&net_tx_handle); + + if (head == NULL) { + head = p; + } else { + tail->next_chain = p; + } + tail = p; + + /* Increment reference count to ensure this pbuf is not freed by lwip */ + pbuf_ref(p); + + return SDDF_LWIP_ERR_OK; +} + +void transmit(void) +{ + bool reprocess = true; + while (reprocess) { + while (head != NULL && !net_queue_empty_free(&net_tx_handle)) { + net_sddf_err_t err = sddf_lwip_transmit_pbuf(head); + if (err == SDDF_LWIP_ERR_PBUF) { + sddf_dprintf("LWIP|ERROR: attempted to send a packet of size %u > BUFFER SIZE %u\n", head->tot_len, + NET_BUFFER_SIZE); + } else if (err != SDDF_LWIP_ERR_OK) { + sddf_dprintf("LWIP|ERROR: unkown error when trying to send pbuf %p\n", head); + } + + struct pbuf *temp = head; + head = temp->next_chain; + if (head == NULL) { + tail = NULL; + } + pbuf_free(temp); + } + + /* Only request a signal if there are more pending pbufs to send */ + if (head == NULL || !net_queue_empty_free(&net_tx_handle)) { + net_cancel_signal_free(&net_tx_handle); + } else { + net_request_signal_free(&net_tx_handle); + } + reprocess = false; + + if (head != NULL && !net_queue_empty_free(&net_tx_handle)) { + net_cancel_signal_free(&net_tx_handle); + reprocess = true; + } + } +} + +void init(void) +{ + serial_queue_init(&serial_tx_queue_handle, serial_config.tx.queue.vaddr, serial_config.tx.data.size, + serial_config.tx.data.vaddr); + serial_putchar_init(serial_config.tx.id, &serial_tx_queue_handle); + + net_queue_init(&net_rx_handle, net_config.rx.free_queue.vaddr, net_config.rx.active_queue.vaddr, + net_config.rx.num_buffers); + net_queue_init(&net_tx_handle, net_config.tx.free_queue.vaddr, net_config.tx.active_queue.vaddr, + net_config.tx.num_buffers); + net_buffers_init(&net_tx_handle, 0); + + sddf_lwip_init(&lib_sddf_lwip_config, &net_config, &timer_config, net_rx_handle, net_tx_handle, NULL, + netif_status_callback, enqueue_pbufs); + set_timeout(); + + setup_udp_socket(); + setup_utilization_socket(benchmark_config.cycle_counters, benchmark_config.start_ch, benchmark_config.stop_ch); + setup_tcp_socket(); + + sddf_lwip_maybe_notify(); +} + +void notified(microkit_channel ch) +{ + if (ch == net_config.rx.id) { + sddf_lwip_process_rx(); + } else if (ch == net_config.tx.id) { + transmit(); + } else if (ch == timer_config.driver_id) { + sddf_lwip_process_timeout(); + set_timeout(); + } else if (ch == serial_config.tx.id) { + // Nothing to do + } else { + sddf_dprintf("LWIP|LOG: received notification on unexpected channel: %u\n", ch); + } + + sddf_lwip_maybe_notify(); +} diff --git a/examples/echo_server/echo.h b/examples/echo_server/echo.h index 787ec18fe..9f2df2960 100644 --- a/examples/echo_server/echo.h +++ b/examples/echo_server/echo.h @@ -9,9 +9,6 @@ #define UTILIZATION_PORT 1236 #define TCP_ECHO_PORT 1237 -#define LINK_SPEED 1000000000 // Gigabit -#define ETHER_MTU 1500 - int setup_udp_socket(void); int setup_utilization_socket(void *cycle_counters, microkit_channel start_ch, microkit_channel stop_ch); int setup_tcp_socket(void); diff --git a/examples/echo_server/echo.mk b/examples/echo_server/echo.mk index 69f3ee23a..f72c0aef6 100644 --- a/examples/echo_server/echo.mk +++ b/examples/echo_server/echo.mk @@ -31,8 +31,9 @@ METAPROGRAM := $(TOP)/meta.py vpath %.c ${SDDF} ${ECHO_SERVER} -IMAGES := eth_driver.elf lwip0.elf lwip1.elf benchmark.elf idle.elf network_virt_rx.elf\ - network_virt_tx.elf network_copy.elf timer_driver.elf uart_driver.elf serial_virt_tx.elf +IMAGES := eth_driver.elf echo0.elf echo1.elf benchmark.elf idle.elf network_virt_rx.elf\ + network_virt_tx.elf network_copy0.elf network_copy1.elf timer_driver.elf\ + uart_driver.elf serial_virt_tx.elf CFLAGS := -mcpu=$(CPU) \ -mstrict-align \ @@ -51,7 +52,7 @@ CFLAGS := -mcpu=$(CPU) \ LDFLAGS := -L$(BOARD_DIR)/lib -L${LIBC} LIBS := --start-group -lmicrokit -Tmicrokit.ld -lc libsddf_util_debug.a --end-group -CHECK_FLAGS_BOARD_MD5:=.board_cflags-$(shell echo -- ${CFLAGS} ${BOARD} ${MICROKIT_CONFIG} | shasum | sed 's/ *-//') +CHECK_FLAGS_BOARD_MD5 := .board_cflags-$(shell echo -- ${CFLAGS} ${BOARD} ${MICROKIT_CONFIG} | shasum | sed 's/ *-//') ${CHECK_FLAGS_BOARD_MD5}: -rm -f .board_cflags-* @@ -60,32 +61,19 @@ ${CHECK_FLAGS_BOARD_MD5}: %.elf: %.o $(LD) $(LDFLAGS) $< $(LIBS) -o $@ -include ${SDDF}/${LWIPDIR}/Filelists.mk - -# NETIFFILES: Files implementing various generic network interface functions -# Override version in Filelists.mk -NETIFFILES:=$(LWIPDIR)/netif/ethernet.c - -# LWIPFILES: All the above. -LWIPFILES=lwip.c $(COREFILES) $(CORE4FILES) $(NETIFFILES) -LWIP_OBJS := $(LWIPFILES:.c=.o) lwip.o utilization_socket.o \ +ECHO_OBJS := echo.o utilization_socket.o \ udp_echo_socket.o tcp_echo_socket.o -OBJS := $(LWIP_OBJS) -DEPS := $(filter %.d,$(OBJS:.o=.d)) +DEPS := $(ECHO_OBJS:.o=.d) all: loader.img -${LWIP_OBJS}: ${CHECK_FLAGS_BOARD_MD5} -lwip0.elf: $(LWIP_OBJS) libsddf_util.a - $(LD) $(LDFLAGS) $^ $(LIBS) -o $@ -lwip1.elf: $(LWIP_OBJS) libsddf_util.a +${ECHO_OBJS}: ${CHECK_FLAGS_BOARD_MD5} +echo0.elf echo1.elf: $(ECHO_OBJS) libsddf_util.a lib_sddf_lwip_echo.a $(LD) $(LDFLAGS) $^ $(LIBS) -o $@ -LWIPDIRS := $(addprefix ${LWIPDIR}/, core/ipv4 netif api) -${LWIP_OBJS}: |${BUILD_DIR}/${LWIPDIRS} -${BUILD_DIR}/${LWIPDIRS}: - mkdir -p $@ +network_copy0.elf network_copy1.elf: network_copy.elf + cp $< $@ # Need to build libsddf_util_debug.a because it's included in LIBS # for the unimplemented libc dependencies @@ -106,16 +94,18 @@ $(SYSTEM_FILE): $(METAPROGRAM) $(IMAGES) $(DTB) $(OBJCOPY) --update-section .net_copy_config=net_copy_client0_net_copier.data network_copy.elf network_copy0.elf $(OBJCOPY) --update-section .net_copy_config=net_copy_client1_net_copier.data network_copy.elf network_copy1.elf $(OBJCOPY) --update-section .device_resources=timer_driver_device_resources.data timer_driver.elf - $(OBJCOPY) --update-section .timer_client_config=timer_client_client0.data lwip0.elf - $(OBJCOPY) --update-section .net_client_config=net_client_client0.data lwip0.elf - $(OBJCOPY) --update-section .serial_client_config=serial_client_client0.data lwip0.elf - $(OBJCOPY) --update-section .timer_client_config=timer_client_client1.data lwip1.elf - $(OBJCOPY) --update-section .net_client_config=net_client_client1.data lwip1.elf - $(OBJCOPY) --update-section .serial_client_config=serial_client_client1.data lwip1.elf + $(OBJCOPY) --update-section .timer_client_config=timer_client_client0.data echo0.elf + $(OBJCOPY) --update-section .net_client_config=net_client_client0.data echo0.elf + $(OBJCOPY) --update-section .serial_client_config=serial_client_client0.data echo0.elf + $(OBJCOPY) --update-section .timer_client_config=timer_client_client1.data echo1.elf + $(OBJCOPY) --update-section .net_client_config=net_client_client1.data echo1.elf + $(OBJCOPY) --update-section .serial_client_config=serial_client_client1.data echo1.elf $(OBJCOPY) --update-section .serial_client_config=serial_client_bench.data benchmark.elf $(OBJCOPY) --update-section .benchmark_config=benchmark_config.data benchmark.elf - $(OBJCOPY) --update-section .benchmark_client_config=benchmark_client_config.data lwip0.elf + $(OBJCOPY) --update-section .benchmark_client_config=benchmark_client_config.data echo0.elf $(OBJCOPY) --update-section .benchmark_config=benchmark_idle_config.data idle.elf + $(OBJCOPY) --update-section .lib_sddf_lwip_config=lib_sddf_lwip_config_client0.data echo0.elf + $(OBJCOPY) --update-section .lib_sddf_lwip_config=lib_sddf_lwip_config_client1.data echo1.elf ${IMAGE_FILE} $(REPORT_FILE): $(IMAGES) $(SYSTEM_FILE) $(MICROKIT_TOOL) $(SYSTEM_FILE) --search-path $(BUILD_DIR) --board $(MICROKIT_BOARD) --config $(MICROKIT_CONFIG) -o $(IMAGE_FILE) -r $(REPORT_FILE) @@ -123,6 +113,7 @@ ${IMAGE_FILE} $(REPORT_FILE): $(IMAGES) $(SYSTEM_FILE) include ${SDDF}/util/util.mk include ${SDDF}/network/components/network_components.mk +include ${SDDF}/network/lib_sddf_lwip/lib_sddf_lwip.mk include ${ETHERNET_DRIVER}/eth_driver.mk include ${BENCHMARK}/benchmark.mk include ${TIMER_DRIVER}/timer_driver.mk diff --git a/examples/echo_server/lwip.c b/examples/echo_server/lwip.c deleted file mode 100644 index 540ef4976..000000000 --- a/examples/echo_server/lwip.c +++ /dev/null @@ -1,379 +0,0 @@ -/* - * Copyright 2022, UNSW - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "lwip/init.h" -#include "netif/etharp.h" -#include "lwip/pbuf.h" -#include "lwip/netif.h" -#include "lwip/stats.h" -#include "lwip/snmp.h" -#include "lwip/sys.h" -#include "lwip/timeouts.h" -#include "lwip/dhcp.h" - -#include "echo.h" - -__attribute__((__section__(".serial_client_config"))) serial_client_config_t serial_config; - -__attribute__((__section__(".timer_client_config"))) timer_client_config_t timer_config; - -__attribute__((__section__(".net_client_config"))) net_client_config_t net_config; - -__attribute__((__section__(".benchmark_client_config"))) benchmark_client_config_t benchmark_config; - -serial_queue_handle_t serial_tx_queue_handle; - -#define LWIP_TICK_MS 100 -#define NUM_PBUFFS 512 // TODO: make dynamic - -/* Booleans to indicate whether packets have been enqueued during notification handling */ -static bool notify_tx; -static bool notify_rx; - -/* Wrapper over custom_pbuf structure to keep track of buffer offset */ -typedef struct pbuf_custom_offset { - struct pbuf_custom custom; - uint64_t offset; -} pbuf_custom_offset_t; - -LWIP_MEMPOOL_DECLARE( - RX_POOL, - NUM_PBUFFS * 2, - sizeof(struct pbuf_custom_offset), - "Zero-copy RX pool" -); - -typedef struct state { - struct netif netif; - uint8_t mac[ETH_HWADDR_LEN]; - net_queue_handle_t rx_queue; - net_queue_handle_t tx_queue; - struct pbuf *head; - struct pbuf *tail; -} state_t; - -state_t state; - -void set_timeout(void) -{ - sddf_timer_set_timeout(timer_config.driver_id, LWIP_TICK_MS * NS_IN_MS); -} - -uint32_t sys_now(void) -{ - return sddf_timer_time_now(timer_config.driver_id) / NS_IN_MS; -} - -/** - * Free a pbuf. This also returns the underlying buffer to the receive free ring. - * - * @param p pbuf to free. - */ -static void interface_free_buffer(struct pbuf *p) -{ - SYS_ARCH_DECL_PROTECT(old_level); - pbuf_custom_offset_t *custom_pbuf_offset = (pbuf_custom_offset_t *)p; - SYS_ARCH_PROTECT(old_level); - net_buff_desc_t buffer = {custom_pbuf_offset->offset, 0}; - int err = net_enqueue_free(&(state.rx_queue), buffer); - assert(!err); - notify_rx = true; - LWIP_MEMPOOL_FREE(RX_POOL, custom_pbuf_offset); - SYS_ARCH_UNPROTECT(old_level); -} - -/** - * Create a pbuf structure to pass to the network interface. - * - * @param state client state data. - * @param buffer shared buffer containing the data. - * @param length length of data. - * - * @return the newly created pbuf. Can be cast to pbuf_custom. - */ -static struct pbuf *create_interface_buffer(uint64_t offset, size_t length) -{ - pbuf_custom_offset_t *custom_pbuf_offset = (pbuf_custom_offset_t *) LWIP_MEMPOOL_ALLOC(RX_POOL); - custom_pbuf_offset->offset = offset; - custom_pbuf_offset->custom.custom_free_function = interface_free_buffer; - - return pbuf_alloced_custom(PBUF_RAW, length, PBUF_REF, &custom_pbuf_offset->custom, - (void *)(offset + net_config.rx_data.vaddr), NET_BUFFER_SIZE); -} - -/** - * Stores a pbuf to be transmitted upon available transmit buffers. - * - * @param p pbuf to be stored. - */ -void enqueue_pbufs(struct pbuf *p) -{ - /* Indicate to the multiplexer that we require transmit free buffers */ - net_request_signal_free(&state.tx_queue); - - if (state.head == NULL) { - state.head = p; - } else { - state.tail->next_chain = p; - } - state.tail = p; - - /* Increment refernce count to ensure this pbuf is not freed by lwip */ - pbuf_ref(p); -} - -/** - * Insert pbuf into transmit active queue. If no free buffers available or transmit active queue is full, - * stores pbuf to be sent upon buffers becoming available. - * */ -static err_t lwip_eth_send(struct netif *netif, struct pbuf *p) -{ - if (p->tot_len > NET_BUFFER_SIZE) { - sddf_dprintf("LWIP|ERROR: attempted to send a packet of size %u > BUFFER SIZE %u\n", p->tot_len, NET_BUFFER_SIZE); - return ERR_MEM; - } - - if (net_queue_empty_free(&state.tx_queue)) { - enqueue_pbufs(p); - return ERR_OK; - } - - net_buff_desc_t buffer; - int err = net_dequeue_free(&state.tx_queue, &buffer); - assert(!err); - - void *frame = buffer.io_or_offset + net_config.tx_data.vaddr; - uint16_t copied = 0; - for (struct pbuf *curr = p; curr != NULL; curr = curr->next) { - memcpy(frame + copied, curr->payload, curr->len); - copied += curr->len; - } - - buffer.len = copied; - err = net_enqueue_active(&state.tx_queue, buffer); - assert(!err); - - notify_tx = true; - - return ERR_OK; -} - -void transmit(void) -{ - bool reprocess = true; - while (reprocess) { - while (state.head != NULL && !net_queue_empty_free(&state.tx_queue)) { - err_t err = lwip_eth_send(&state.netif, state.head); - if (err == ERR_MEM) { - sddf_dprintf("LWIP|ERROR: attempted to send a packet of size %u > BUFFER SIZE %u\n", state.head->tot_len, - NET_BUFFER_SIZE); - } else if (err != ERR_OK) { - sddf_dprintf("LWIP|ERROR: unkown error when trying to send pbuf %p\n", state.head); - } - - struct pbuf *temp = state.head; - state.head = temp->next_chain; - if (state.head == NULL) { - state.tail = NULL; - } - pbuf_free(temp); - } - - /* Only request a signal if no more pbufs enqueud to send */ - if (state.head == NULL || !net_queue_empty_free(&state.tx_queue)) { - net_cancel_signal_free(&state.tx_queue); - } else { - net_request_signal_free(&state.tx_queue); - } - reprocess = false; - - if (state.head != NULL && !net_queue_empty_free(&state.tx_queue)) { - net_cancel_signal_free(&state.tx_queue); - reprocess = true; - } - } -} - -void receive(void) -{ - bool reprocess = true; - while (reprocess) { - while (!net_queue_empty_active(&state.rx_queue)) { - net_buff_desc_t buffer; - int err = net_dequeue_active(&state.rx_queue, &buffer); - assert(!err); - - struct pbuf *p = create_interface_buffer(buffer.io_or_offset, buffer.len); - assert(p != NULL); - if (state.netif.input(p, &state.netif) != ERR_OK) { - sddf_dprintf("LWIP|ERROR: unkown error inputting pbuf into network stack\n"); - pbuf_free(p); - } - } - - net_request_signal_active(&state.rx_queue); - reprocess = false; - - if (!net_queue_empty_active(&state.rx_queue)) { - net_cancel_signal_active(&state.rx_queue); - reprocess = true; - } - } -} - -/** - * Initialise the network interface data structure. - * - * @param netif network interface data structuer. - */ -static err_t ethernet_init(struct netif *netif) -{ - if (netif->state == NULL) { - return ERR_ARG; - } - state_t *data = netif->state; - - netif->hwaddr[0] = data->mac[0]; - netif->hwaddr[1] = data->mac[1]; - netif->hwaddr[2] = data->mac[2]; - netif->hwaddr[3] = data->mac[3]; - netif->hwaddr[4] = data->mac[4]; - netif->hwaddr[5] = data->mac[5]; - netif->mtu = ETHER_MTU; - netif->hwaddr_len = ETHARP_HWADDR_LEN; - netif->output = etharp_output; - netif->linkoutput = lwip_eth_send; - NETIF_INIT_SNMP(netif, snmp_ifType_ethernet_csmacd, LINK_SPEED); - netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP | NETIF_FLAG_IGMP; - return ERR_OK; -} - -/* Callback function that prints DHCP supplied IP address. */ -static void netif_status_callback(struct netif *netif) -{ - if (dhcp_supplied_address(netif)) { - sddf_printf("LWIP|NOTICE: DHCP request for %s returned IP address: %s\n", microkit_name, - ip4addr_ntoa(netif_ip4_addr(netif))); - } -} - -void init(void) -{ - serial_queue_init(&serial_tx_queue_handle, serial_config.tx.queue.vaddr, serial_config.tx.data.size, - serial_config.tx.data.vaddr); - serial_putchar_init(serial_config.tx.id, &serial_tx_queue_handle); - - net_queue_init(&state.rx_queue, net_config.rx.free_queue.vaddr, net_config.rx.active_queue.vaddr, - net_config.rx.num_buffers); - net_queue_init(&state.tx_queue, net_config.tx.free_queue.vaddr, net_config.tx.active_queue.vaddr, - net_config.tx.num_buffers); - net_buffers_init(&state.tx_queue, 0); - - lwip_init(); - set_timeout(); - - LWIP_MEMPOOL_INIT(RX_POOL); - - sddf_memcpy(state.mac, net_config.mac_addr, 6); - - /* Set dummy IP configuration values to get lwIP bootstrapped */ - struct ip4_addr netmask, ipaddr, gw, multicast; - ipaddr_aton("0.0.0.0", &gw); - ipaddr_aton("0.0.0.0", &ipaddr); - ipaddr_aton("0.0.0.0", &multicast); - ipaddr_aton("255.255.255.0", &netmask); - - state.netif.name[0] = 'e'; - state.netif.name[1] = '0'; - - if (!netif_add(&(state.netif), &ipaddr, &netmask, &gw, (void *)&state, - ethernet_init, ethernet_input)) { - sddf_dprintf("LWIP|ERROR: Netif add returned NULL\n"); - } - - netif_set_default(&(state.netif)); - netif_set_status_callback(&(state.netif), netif_status_callback); - netif_set_up(&(state.netif)); - - if (dhcp_start(&(state.netif))) { - sddf_dprintf("LWIP|ERROR: failed to start DHCP negotiation\n"); - } - - setup_udp_socket(); - setup_utilization_socket(benchmark_config.cycle_counters, benchmark_config.start_ch, benchmark_config.stop_ch); - setup_tcp_socket(); - - if (notify_rx && net_require_signal_free(&state.rx_queue)) { - net_cancel_signal_free(&state.rx_queue); - notify_rx = false; - if (!microkit_have_signal) { - microkit_deferred_notify(net_config.rx.id); - } else if (microkit_signal_cap != BASE_OUTPUT_NOTIFICATION_CAP + net_config.rx.id) { - microkit_notify(net_config.rx.id); - } - } - - if (notify_tx && net_require_signal_active(&state.tx_queue)) { - net_cancel_signal_active(&state.tx_queue); - notify_tx = false; - if (!microkit_have_signal) { - microkit_deferred_notify(net_config.tx.id); - } else if (microkit_signal_cap != BASE_OUTPUT_NOTIFICATION_CAP + net_config.tx.id) { - microkit_notify(net_config.tx.id); - } - } -} - -void notified(microkit_channel ch) -{ - if (ch == net_config.rx.id) { - receive(); - } else if (ch == net_config.tx.id) { - transmit(); - receive(); - } else if (ch == timer_config.driver_id) { - sys_check_timeouts(); - set_timeout(); - } else if (ch == serial_config.tx.id) { - // Nothing to do - } else { - sddf_dprintf("LWIP|LOG: received notification on unexpected channel: %u\n", ch); - } - - if (notify_rx && net_require_signal_free(&state.rx_queue)) { - net_cancel_signal_free(&state.rx_queue); - notify_rx = false; - if (!microkit_have_signal) { - microkit_deferred_notify(net_config.rx.id); - } else if (microkit_signal_cap != BASE_OUTPUT_NOTIFICATION_CAP + net_config.rx.id) { - microkit_notify(net_config.rx.id); - } - } - - if (notify_tx && net_require_signal_active(&state.tx_queue)) { - net_cancel_signal_active(&state.tx_queue); - notify_tx = false; - if (!microkit_have_signal) { - microkit_deferred_notify(net_config.tx.id); - } else if (microkit_signal_cap != BASE_OUTPUT_NOTIFICATION_CAP + net_config.tx.id) { - microkit_notify(net_config.tx.id); - } - } -} diff --git a/examples/echo_server/meta.py b/examples/echo_server/meta.py index e5be24230..28b0c9b58 100644 --- a/examples/echo_server/meta.py +++ b/examples/echo_server/meta.py @@ -172,11 +172,11 @@ def generate(sdf_file: str, output_dir: str, dtb: DeviceTree): net_virt_rx = ProtectionDomain("net_virt_rx", "network_virt_rx.elf", priority=99) net_system = Sddf.Net(sdf, ethernet_node, ethernet_driver, net_virt_tx, net_virt_rx) - client0 = ProtectionDomain("client0", "lwip0.elf", priority=97, budget=20000) + client0 = ProtectionDomain("client0", "echo0.elf", priority=97, budget=20000) client0_net_copier = ProtectionDomain( "client0_net_copier", "network_copy0.elf", priority=98, budget=20000 ) - client1 = ProtectionDomain("client1", "lwip1.elf", priority=97, budget=20000) + client1 = ProtectionDomain("client1", "echo1.elf", priority=97, budget=20000) client1_net_copier = ProtectionDomain( "client1_net_copier", "network_copy1.elf", priority=98, budget=20000 ) @@ -193,6 +193,9 @@ def generate(sdf_file: str, output_dir: str, dtb: DeviceTree): net_system.add_client_with_copier(client0, client0_net_copier, mac_addr=client0_mac_addr) net_system.add_client_with_copier(client1, client1_net_copier, mac_addr=client1_mac_addr) + client0_lib_sddf_lwip = Sddf.Lwip(sdf, net_system, client0) + client1_lib_sddf_lwip = Sddf.Lwip(sdf, net_system, client1) + # Benchmark specific resources bench_idle = ProtectionDomain("bench_idle", "idle.elf", priority=1) @@ -259,6 +262,10 @@ def generate(sdf_file: str, output_dir: str, dtb: DeviceTree): assert net_system.serialise_config(output_dir) assert timer_system.connect() assert timer_system.serialise_config(output_dir) + assert client0_lib_sddf_lwip.connect() + assert client0_lib_sddf_lwip.serialise_config(output_dir) + assert client1_lib_sddf_lwip.connect() + assert client1_lib_sddf_lwip.serialise_config(output_dir) with open(f"{output_dir}/benchmark_config.data", "wb+") as f: f.write(benchmark_config.serialise())