/* * 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 * - 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_ISS_CLIENT 0x10000 // initial sequence number for TCP client #define TCP_ISS_SERVER 0x20000 // initial sequence number for TCP server #define TCP_MAX_WINDOW 0xFFFFF // initial TCP send window #define PAYLOAD_MAX_LEN 1500 // max length for an UDP packet / TCP segment #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 #define NIC_RX_BUF_SIZE 0x100000 // 1 Mbytes #define NIC_R2T_QUEUE_SIZE 0x64 // smallest KCM size #define NIC_CRQ_QUEUE_SIZE 0x8 // actual size is 8 * sizeof(sockaddr_t) #define NIC_KERNEL_BUF_SIZE 0x800 // 2 Kbytes for one ETH/IP/TCP packet /***************************************************************************************** * 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 th, 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 */ uint32_t length; /*! number of bytes in buffer */ 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 / SEND / CLOSE), and the * priority between clients is round-robin. It takes into account the request registered * by the RX server thread in the R2T queue associated to the involved socket. * When a command is completed, it unblocks the client thread. For a SEND command, the * last byte must have been sent for an UDP socket, and it must have been acknowledged * for a TCP socket. * When the TX client threads queue is empty, it blocks on 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: * It execute an infinite loop in which it takes the lock protecting the clients list * to build a "kleenex" list of currently registered clients. * For each client registered in this "kleenex" list, it takes the lock protecting the * socket state, build one packet/segment in a local 2K bytes kernel buffer, calls the * transport layer to add the UDP/TCP header, 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. * Finally, it updates the socket state, and release the socket lock. ****************************************************************************************** * @ 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 function displays all the fields of an ETH/IP/TCP segment or ETH/IP/UDP packet. ****************************************************************************************** * @ is_tx : [in] sent packet if true / received packet if false. * @ pid : [in] process identifier. * @ trdid : [in] thread identifier. * @ cycle : [in] date (number of cycles). * @ buf : [in] local pointer on kernel buffer containing the packet. *****************************************************************************************/ void dev_nic_packet_display( bool_t is_tx, pid_t pid, trdid_t trdid, uint32_t cycle, uint8_t * buf ); #endif /* _DEV_NIC_H */