|
Udipe 1.0
Solving the riddle of high-throughput UDP
|
#include <connect.h>
Data Fields | |
| udipe_duration_ns_t | send_timeout |
| udipe_duration_ns_t | recv_timeout |
| const char * | local_interface |
| ip_address_t | local_address |
| ip_address_t | remote_address |
| unsigned | send_buffer: 31 |
| unsigned | recv_buffer: 31 |
| udipe_direction_t | direction |
| udipe_bool_with_default_t | enable_gso |
| udipe_bool_with_default_t | enable_gro |
| uint16_t | gso_segment_size |
| uint8_t | priority |
| bool | allow_multithreading |
| bool | enable_timestamps |
udipe_connect() parameters
This struct controls the parameters that can be tuned when establishing a UDP connection. Like most configuration structs, it is designed such that zero-initializing results in sane defaults, except for sending traffic where you will need to set at least a remote_address.
| bool udipe_connect_options_s::allow_multithreading |
Allow datagrams to be handled by multiple worker threads
This is only appropriate for higher-level protocols where UDP datagrams are independent from each other and the order in which they are sent and processed doesn't matter. But when that is the case, it can significantly improve performance in situations where the number of live network connections is small with respect to the amount of CPU cores.
When this option is set, the callbacks that are passed to streaming commands like udipe_stream_send() must be thread-safe.
By default, each connection is assigned to a single worker thread. This means that as long as commands associated with the connection only originate from a single client thread, packets will be sent and processed in a strict FIFO manner with respect to the order in which the network provided them. But do remember that UDP as a protocol does not provide ordering guarantees to allow e.g. switching between IP routes...
| udipe_direction_t udipe_connect_options_s::direction |
Communication direction(s)
You can use this field to specify that you only intend to send or receive data. See udipe_direction_t for more information.
By default, the connection is configured to receive traffic only, as sending traffic requires a remote address and there is no good default for a remote address.
| udipe_bool_with_default_t udipe_connect_options_s::enable_gro |
Enable Generic Receive Offload (GRO)
This is a Linux UDP performance optimization that lets you receive multiple UDP datagrams with a single receive command. It roughly works by modifying the semantics of oversized receive commands whose output buffer goes above the MTU, so that instead of receiving a single datagram they may receive multiple ones and concatenate their payloads.
You cannot control the granularity of GRO, as it is given by the size of incoming datagrams (which must be of identical size), but you will be able to tell the datagram size at the end of the receive operation.
By default, GRO if enabled if the host operating system supports it and left disabled otherwise. This differs from the behavior of intentionally setting this to UDIPE_TRUE, which makes connection setup fail if GRO is not supported.
| udipe_bool_with_default_t udipe_connect_options_s::enable_gso |
Enable Generic Segmentation Offload (GSO)
This is a Linux UDP performance optimization that lets you send multiple UDP datagrams with a single send command. It roughly works by modifying the semantics of oversized send commands whose input buffer goes above the MTU, so that instead of failing they split the input buffer into multiple datagrams.
The granularity at which a send operation is split into datagrams is controlled by the gso_segment_size option.
By default, GSO if enabled if the host operating system supports it and disabled otherwise. This differs from the behavior of setting this to UDIPE_TRUE, which makes connection setup fail if GSO is not supported.
| bool udipe_connect_options_s::enable_timestamps |
Request packet timestamps
If enabled, each packet will come with a timestamp that indicates when the network interface processed it. This can be combined with application-side timestamps to estimate the kernel and application processing delay on the receive path.
By default, timestamps are not requested.
| uint16_t udipe_connect_options_s::gso_segment_size |
GSO segment size
This is the granularity at which the payload of a send command is split into separate UDP datagrams when the Generic Segmentation Offload feature is enabled.
You must set it such that the resulting packets after adding UDP, IPv4/v6 and Ethernet headers remain below the network's path MTU.
Linux additionally enforces that no more than 64 datagrams may be sent with a single send operation when GSO is enabled.
This option can only be set when enable_gso is set to UDIPE_TRUE, as it makes little sense otherwise and can lead to dangerous judgment errors where you will think that your datagrams will have one size when they will actually have another payload size.
By default, the GSO segment size is auto-tuned to the network path MTU that is estimated by the Linux kernel.
| ip_address_t udipe_connect_options_s::local_address |
Local address
If set to a non-default value, this indicates that you only want to send and receive traffic via the specified local IP address and port.
This address must be of the same type as remote_address i.e. if one is an IPv4 address, then the other must be an IPv6 address, and vice versa.
The default configuration sets this to IPv4 address 0.0.0.0 with port 0 aka a randomly assigned port, unless remote_address is an IPv6 address in which case the default is IPv6 address :: with port 0. This is appropriate if you want to send traffic and do not care which network interface and UDP port it goes through, or if you want to receive traffic and are ready to communicate the port number to your peer (as is common for e.g. local server testing).
| const char* udipe_connect_options_s::local_interface |
Local interface
If set to a non-NULL string, this indicates that you only want to send and receive traffic via the specified network interface.
This parameter must be consistent with local_address (i.e. local_interface should be able to emit from the address specified in local_address if it is not a catch-all address) and remote_address (i.e. remote_address should be reachable from local_interface), otherwise you will not be able to send and receive datagrams.
If you use the udipe_start_connect() asynchronous version of udipe_connect(), then the string targeted by this pointer must not be modified or liberated until the future associated with udipe_start_connect() had been awaited via udipe_finish().
By default, the connection is not bound to any network interface.
| uint8_t udipe_connect_options_s::priority |
Desired traffic priority
Setting a priority higher than zero indicates that the operating system should attempt to process datagrams associated with this connection before those associated with other connections.
On Linux, setting a priority of 7 and above requires CAP_NET_ADMIN privileges.
By default, the priority is 0 i.e. lowest priority.
| unsigned udipe_connect_options_s::recv_buffer |
Receive buffer size
This parameter must not be set if direction is UDIPE_OUT.
This cannot be smaller than 128 or larger than INT_MAX. In addition, on Linux, non-privileged processes cannot go above the limit configured in pseudo file /proc/sys/net/core/rmem_max.
By default, the receive buffer is configured at the OS' default size, which on Linux is itself configured through pseudo-file /proc/sys/net/core/rmem_default or the equivalent sysctl.
| udipe_duration_ns_t udipe_connect_options_s::recv_timeout |
Default receive timeout in nanoseconds or 0 = no timeout / wait forever
This parameter must not be set if direction is UDIPE_OUT.
The default is to wait indefinitely for datagrams to be received. See udipe_duration_ns_t for more info on timeout semantics.
| ip_address_t udipe_connect_options_s::remote_address |
Remote address
This is used to configure which remote IP address and port you want to exchange traffic with.
This address must be of the same type as local_address i.e. if one is an IPv4 address, then the other must be an IPv6 address, and vice versa.
The default configuration sets this to IPv4 address 0.0.0.0 with port 0 aka any port, unless local_address is an IPv6 address in which case the default is IPv6 address :: with port 0.
This is always incorrect for sending traffic and must be changed to the address of the intended peer. When receiving traffic, it simply means that you are accepting traffic from any source address and port.
| unsigned udipe_connect_options_s::send_buffer |
Send buffer size
This parameter must not be set if direction is UDIPE_IN.
It cannot be smaller than 1024 or larger than INT_MAX. In addition, on Linux, non-privileged processes cannot go above the limit configured in pseudo file /proc/sys/net/core/wmem_max.
By default, the send buffer is configured at the OS' default size, which on Linux is itself configured through pseudo-file /proc/sys/net/core/wmem_default or the equivalent sysctl.
| udipe_duration_ns_t udipe_connect_options_s::send_timeout |
Default send timeout in nanoseconds or 0 = no timeout / wait forever
This parameter must not be set if direction is UDIPE_IN.
The default is to wait indefinitely for datagrams to be sent. See udipe_duration_ns_t for more info on timeout semantics.