/* * dev_nic.h - NIC (Network Controler) generic device API definition. * * Author Alain Greiner (2016,2017,2018,2019,2020) * * Copyright (c) UPMC Sorbonne Universites * * This file is part of ALMOS-MKH * * ALMOS-MKH is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2.0 of the License. * * ALMOS-MKH is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with ALMOS-kernel; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _DEV_NIC_H #define _DEV_NIC_H #include #include #include #include #include /**** Forward declarations ****/ struct chdev_s; /***************************************************************************************** * Generic Network Interface Controler definition * * This device provides access to a generic Gigabit Ethernet network controler. * It assumes that the NIC hardware peripheral handles two packets queues for sent (TX) * and received (RX) packets. * * The supported protocols stack is : Ethernet / IPV4 / TCP or UDP * * 1) hardware assumptions * * The NIC device is handling two (infinite) streams of packets to or from the network. * It is the driver responsibility to move the RX packets from the NIC to the RX queue, * and the TX packets from the TX queue to the NIC. * * AS the RX and TX queues are independant, there is one NIC_RX device descriptor * to handle RX packets, and another NIC_TX device descriptor to handle TX packets. * * In order to improve throughput, the NIC controller can implement multiple (N) channels. * In this case, the channel index is defined by an hash function computed from the remote * IP address and port. This index is computed by the hardware for an RX packet, and is * computed by the kernel for a TX packet, using a specific driver function. * The 2*N chdevs, and the associated server threads implementing the protocols stack, * are distributed in 2*N different clusters. * * 2) User API * * On the user side, ALMOS-MKH implements the POSIX socket API. * The following kernel functions implement the socket related syscalls : * - socket_build() : create a local socket registered in process fd_array[]. * - socket_bind() : attach a local IP address and port to a local socket. * - socket_listen() : local server makes a passive open. * - socket_connect() : local client makes an active open to a remote server. * - socket_accept() : local server accept a new remote client. * - socket_send() : send data on a connected socket. * - socket_recv() : receive data on a connected socket. * - socket_sendto() : send a packet to a remote (IP address/port). * - socket_recvfrom() : receive a paket from a remote (IP address/port). * * 3) NIC TX and NIC_RX server threads * * The dev_nic_tx_server() & dev_nic_rx_server() functions defined below execute * the user commands stored in the sockets to implement the [ETH / IP / TCP or UDP] * protocols stack, as defined in the and files. * * 4) NIC driver API * * The generic NIC device "driver" API defines the following commands, used by the * NIC_TX and NIC_RX server threads, running in the cluster containing the relevant chdev, * to access the NIC_TX and NIC_RX packets queues: * * - READ : consume one packet from the NIC_RX queue. * - WRITE : produce one packet to the NIC_TX queue. * * All RX or TX paquets are sent or received in standard 2 Kbytes kernel buffers, * that are dynamically allocated by the protocols stack. * The actual TX an RX queues structures depends on the hardware NIC implementation, * and are defined in the HAL specific driver code. * * Moreover, the generic NIC device "driver" API defines the following commands, * used directly by a client thread running in any cluster, to access the NIC device * configuration or status registers: * * - GET_KEY : get channel index from remote IP address and port * - SET_RUN : activate/desactivate one channel (both directions) * - GET_INSTRU : get one instrumentation counter value * - CLEAR_INSTRU : reset all instrumentation counters * * WARNING: the WTI mailboxes used by the driver ro receive events from the hardware * (available RX packet, or available free TX slot, for a given channel), must be * statically allocated during the kernel initialisation phase, and must be * routed to the cluster containing the associated TX/RX chdev and server thread. * *****************************************************************************************/ /**** Forward declarations ****/ struct chdev_s; /***************************************************************************************** * Various constants used by the protocols stack ****************************************************************************************/ #define SRC_MAC_5 0x66 // This is a temporary short-cut for debug #define SRC_MAC_4 0x55 #define SRC_MAC_3 0x44 #define SRC_MAC_2 0x33 #define SRC_MAC_1 0x22 #define SRC_MAC_0 0x11 #define DST_MAC_5 0x66 // This is a temporary short-cut for debug #define DST_MAC_4 0x55 #define DST_MAC_3 0x44 #define DST_MAC_2 0x33 #define DST_MAC_1 0x22 #define DST_MAC_0 0x11 #define TCP_HEAD_LEN 20 #define UDP_HEAD_LEN 8 #define IP_HEAD_LEN 20 #define ETH_HEAD_LEN 14 #define PROTOCOL_UDP 0x11 #define PROTOCOL_TCP 0x06 #define TCP_FLAG_FIN 0x01 #define TCP_FLAG_SYN 0x02 #define TCP_FLAG_RST 0x04 #define TCP_FLAG_PSH 0x08 #define TCP_FLAG_ACK 0x10 #define TCP_FLAG_URG 0x20 /***************************************************************************************** * This structure defines the specific chdev extension for NIC device: * - queue : local pointer on the memory mapped queue of TX or RX packets, used * by the NIC driver to move packets to/from the NIC hardware. The actual descriptor * depends on the NIC implementation. * - root : root of an xlist of sockets that are in the LISTEN state, waiting one or * several TCP connection requests from remote processes. It is only used by the * NIC_RX server thread attached to a NIC_RX chdev. * - lock : lock protecting concurrent access to the litening sockets list. ****************************************************************************************/ typedef struct nic_extend_s { void * queue; /*! pointer on NIC packets queue descriptor (RX or TX) */ xlist_entry_t root; /*! root of listening sockets list (only used in RX[0]) */ remote_busylock_t lock; /*! lock protecting this list (only used in RX[0] */ } nic_extend_t; /***************************************************************************************** * This enum defines the various implementations of the generic NIC peripheral. * This array must be kept consistent with the define in the arch_info.h file. ****************************************************************************************/ typedef enum nic_impl_e { IMPL_NIC_CBF = 0, IMPL_NIC_I86 = 1, } nic_impl_t; /**************************************************************************************** * This defines the (implementation independant) commands to access the NIC hardware. * There is two types of commands * - The first 2 commands are used by the NIC_TX and NIC_RX server threads, and stored * in the server thread descriptor, to access the NIC_RX & NIC_TX packet queues. * The buffer is always a 2K bytes kernel buffer, containing an Ethernet packet. * - The next 4 synchronous commands are used by the client thread, and stored in the * client thread descriptor, to directly access the NIC registers. ****************************************************************************************/ typedef enum nic_cmd_e { NIC_CMD_WRITE = 10, /*! put one (given length) packet to TX queue */ NIC_CMD_READ = 11, /*! get one (any length) packet from RX queue */ NIC_CMD_GET_KEY = 20, /*! return channel index from IP address and port */ NIC_CMD_SET_RUN = 21, /*! enable/disable one NIC channel */ NIC_CMD_GET_INSTRU = 22, /*! return one intrumentation register value */ NIC_CMD_CLEAR_INSTRU = 23, /*! reset all instrumentation registers */ } nic_cmd_t; typedef struct nic_command_s { xptr_t dev_xp; /*! extended pointer on NIC chdev descriptor */ nic_cmd_t type; /*! command type */ uint8_t * buffer; /*! local pointer on kernel buffer (when READ / WRITE) */ uint32_t length; /*! number of bytes in buffer (when READ / WRITE ) */ uint32_t status; /*! return value (depends on command type) */ uint32_t error; /*! return an error from the hardware (0 if no error) */ } nic_command_t; /****************************************************************************************** * This function completes the NIC-RX and NIC-TX chdev descriptors initialisation. * namely the link with the implementation specific driver. * The func, impl, channel, is_rx, base fields have been previously initialised. * It calls the specific driver initialisation function, to initialise the hardware * device and the specific data structures when required. * It creates the associated server thread and allocates a WTI from local ICU. * For a TX_NIC chedv, it allocates and initializes the R2T queue used by the * NIC_RX[channel] server to send direct requests to the NIC_TX[channel] server, * and the CRQ queue used to register connection requests. * It must de executed by a local thread. * For NIC_TX and NIC_RX chdevs, the "wait_root" field is actually a list of sockets. ****************************************************************************************** * @ chdev : local pointer on NIC chdev descriptor. *****************************************************************************************/ void dev_nic_init( struct chdev_s * chdev ); /* Functions directly called by a client thread in any cluster */ /****************************************************************************************** * This function compute a channel index in range [0,nic_channels[ from the remote IP * address and , by calling the relevant driver command. ****************************************************************************************** * @ addr : [in] IP address. * @ port : [in] TCP/UDP port. * @ return the selected channel index *****************************************************************************************/ uint32_t dev_nic_get_key( uint32_t addr, uint16_t port ); /****************************************************************************************** * This function activate / de-activate a NIC channel DMA engine identified by the * argument, as defined by the argument. ****************************************************************************************** * @ channel : [in] NIC channel index. * @ run : [in] activate if non-zero / desactivate if zero. * @ return 0 if success / return -1 if error. *****************************************************************************************/ error_t dev_nic_set_run( uint32_t channel, uint32_t run ); /****************************************************************************************** * This instrumentation function displays on the TXT0 kernel terminal the content * of the instrumentation registers contained in the NIC device. ****************************************************************************************** * @ return 0 if success / return -1 if error. *****************************************************************************************/ error_t dev_nic_get_instru( void ); /****************************************************************************************** * This instrumentation function reset all instrumentation registers contained * in the NIC device. ****************************************************************************************** * @ return 0 if success / return -1 if error. *****************************************************************************************/ error_t dev_nic_clear_instru( void ); /* Functions executed by the TX and RX server threads */ /****************************************************************************************** * This function is executed by the server thread associated to a NIC_TX[channel] chdev. * This TX server thread is created by the dev_nic_init() function. * It build and send UDP packets or TCP segments for all clients threads registered in * the NIC_TX[channel] chdev. The command types are (CONNECT / ACCEPT / CLOSE / SEND). * It takes into account the request registered by the RX server thread in the R2T queues. * The loop on registered sockets implements a round-robin priority between sockets. * When no registered socket is active, it blocks on the THREAD_BLOCKED_CLIENT condition * and deschedules. It is re-activated by a client thread registering a command. * When the NIC_TX packet queue is full, it blocks on the THREAD_BLOCKED_ISR condition * and deschedules. It is reactivated by the NIC_TX DMA engine. ****************************************************************************************** * Implementation note: * At each iteration in the infinite loop, it takes the lock protecting the registered * client sockets queue to find one active socket (tx_valid or r2t_valid flags set). * For each registered socket, it takes the lock protecting the socket state, and * exit the scan when an active socket has been found, without releasing the socket state. * When the scan is completed, it release the lock protecting the queue, before handling * the found active socket. The socket lock is released only when the requested packet * has been build, and the active socket state has been updated. * To handle a socket request, it calls the transport layer to build the UDP packet or * TCP segment in a local 2K bytes kernel buffer, calls the IP layer to add the IP header, * calls the ETH layer to add the ETH header, and moves the packet to the NIC_TX_QUEUE. ****************************************************************************************** * @ chdev : [in] local pointer on one local NIC_TX[channel] chdev descriptor. *****************************************************************************************/ void dev_nic_tx_server( struct chdev_s * chdev ); /****************************************************************************************** * This function is executed by the server thread associated to a NIC_RX[channel] chdev. * This RX server thread is created by the dev_nic_init() function. * It handles all UDP packets or TCP segments received by the sockets attached to * the NIC_RX[channel] chdev. It writes the received data in the socket rcv_buf, and * unblocks the client thread waiting on a RECV command. * To implement the three steps handshahke required by a TCP connection, it posts direct * requests to the TX server, using the R2T queue attached to the involved socket. * It blocks on the THREAD_BLOCKED_ISR condition and deschedules when the NIC_RX_QUEUE * is empty, and is re-activated by the NIC_RX_ISR, when the queue becomes non empty. ****************************************************************************************** * Implementation note: * It executes an infinite loop in which it extracts one packet from the NIC_RX_QUEUE * of received packets, copies this packet in a local 2 kbytes kernel buffer, checks * the Ethernet header, checks the IP header, calls the relevant (TCP or UDP) transport * protocol that search a matching socket for the received packet. It copies the payload * to the relevant socket rcv_buf when the packet is acceptable, and unblocks the client * thread. It discard the packet if no socket found. ****************************************************************************************** * @ chdev : [in] local pointer on one local NIC_RX[channel] chdev descriptor. *****************************************************************************************/ void dev_nic_rx_server( struct chdev_s * chdev ); /****************************************************************************************** * This debug function can be called by the dev_nic_tx_server() function to display * on TXT0 the header of a TX [ETH/IP/TCP] segment or [ETH/IP/UDP] packet. ****************************************************************************************** * @ pid : [in] process identifier. * @ fdid : [in] socket identifier. * @ cycle : [in] date (number of cycles). * @ buf : [in] local pointer on kernel buffer containing the packet. *****************************************************************************************/ void dev_nic_packet_display( pid_t pid, uint32_t fdid, uint32_t cycle, uint8_t * buf ); #endif /* _DEV_NIC_H */