aboutgitcodebugslistschat
Commit message (Collapse)AuthorAgeFilesLines
* passt, pasta: Introduce command-line options and port re-mappingStefano Brivio2021-09-0117-691/+1644
| | | | Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
* tcp: Fixes for early data in SOCK_SYN_SENT, closing states, clamping windowStefano Brivio2021-09-011-23/+30
| | | | | | More details here after rebase. Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
* tap: Make sure we don't receive frames bigger than ETH_MAX_MTU from qemuStefano Brivio2021-09-011-5/+4
| | | | | | | And while at it, remove some attributes that are not needed anymore after introducing command line options. Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
* dhcpv6: Fix parsing for IA_ADDR suboptions of IA_NA/IA_TAStefano Brivio2021-09-011-7/+11
| | | | | | | | | | | Once we're past the IA_NA or IA_TA option itself, before we start looking for IA_ADDR suboptions, we need to subtract the length of the option we parsed so far, otherwise we might end up reading past the end of the message, or miss some parts. While at it, streamline calculations in dhcpv6_opt(). Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
* tcp: Proper error handling for sendmmsg() to UNIX domain socketStefano Brivio2021-08-261-37/+64
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | As data from socket is forwarded to the guest, sendmmsg() might send fewer bytes than requested in three different ways: - failing altogether with a negative error code -- ignore that, we'll get an error on the UNIX domain socket later if there's really an issue with it and reset the connection to the guest - sending less than 'vlen' messages -- instead of assuming success in that case and waiting for the guest to send a duplicate ACK indicating missing data, update the sequence number according to what was actually sent and spare some retransmissions - somewhat unexpectedly to me, sending 'vlen' or less than 'vlen' messages, returning up to 'vlen', with the last message being partially sent, and no further indication of errors other than the returned msg_len for the last partially sent message being less than iov_len. In this case, we would assume success and proceed as nothing happened. However, qemu would fail to parse any further message, having received a partial descriptor, and eventually close the connection, logging: serious error: oversized packet received,connection terminated. as the length descriptor for the next message would be sourced from the middle of the next successfully sent message, not from its header. Handle this by checking the msg_len returned for the last (even partially) sent message, and force re-sending the missing bytes, if any, with a blocking sendmsg() -- qemu must not receive anything else than that anyway. While at it, allow to send up to 64KiB for each message, the previous 32KiB limit isn't actually required, and just switch to a new message at each iteration on sending buffers, they are already MSS-sized anyway, so the check in the loop isn't really needed. Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
* tcp: Never send ACK because of pending unacknowleged data when sending SYNStefano Brivio2021-08-241-1/+3
| | | | | | | | | | | | | | With a kernel older than 5.3 (no_snd_wnd set), ack_pending in tcp_send_to_tap() might be true at the beginning of a new connection initiated by a socket. This means we send the first SYN segment to the tap together with ACK set, which is clearly invalid and triggers the receiver to reply with an RST segment right away. Set ack_pending to 0 whenever we're sending a SYN segment. In case of a SYN, ACK segment sent by the caller, the caller passes the ACK flag explicitly. Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
* tcp: Drop EPOLLET for non-spliced connectionsStefano Brivio2021-08-241-4/+4
| | | | | | | Socket-facing functions don't guarantee that all data is handled before they return: stick to level-triggered mode for TCP sockets. Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
* util: Don't close ping sockets if bind() failsStefano Brivio2021-08-041-3/+6
| | | | | | | ...they're still usable, thanks to the workaround implemented in icmp_tap_handler(). Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
* util: Fix millisecond logging timestamp calculationStefano Brivio2021-08-041-1/+1
| | | | | | | Four sub-second digits means 0.1ms units: divide nanoseconds by 10^5, not 10^6. Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
* tcp: Fast re-transmit, more fixes for closing states and no_snd_wndStefano Brivio2021-08-041-45/+73
| | | | | | | | | | | ...and while at it, fix an issue in the calculation of the last IOV buffer size: if we can't receive enough data to fill up the window, the last buffer can be filled completely. Also streamline the code setting iovec lengths if cached values are not matching. Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
* tcp: Always allow ACKs when pending, fixes for no_snd_wnd and closing statesStefano Brivio2021-08-041-10/+23
| | | | | | | | | | | | | | | | We won't necessarily have another choice to ACK in a timely fashion if we skip ACKs from a number of states (including ESTABLISHED) when there's enough window left. Check for ACKed bytes as soon as it makes sense. If the sending window is not reported by the kernel, ACK as soon as we queue onto the socket, given that we're forced to use a rather small window. In FIN_WAIT_1_SOCK_FIN, we also have to account for the FIN flag sent by the peer in the sequence. Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
* tcp: Lower TCP_TAP_FRAMES to 32Stefano Brivio2021-08-041-1/+1
| | | | | | | | Sending 64 frames in a batch looks quite bad when a duplicate ACK comes right at the beginning of it. Lowering this to 32 doesn't affect performance noticeably, with 16 the impact is more apparent. Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
* doc/demo.sh: Pick IPv6 interface only if it has a nexthop routeStefano Brivio2021-08-041-1/+1
| | | | Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
* tcp: Full batched processing for tap messagesStefano Brivio2021-07-271-121/+156
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Similar to UDP, but using a simple sendmsg() on iovec-style buffers from tap instead, as we don't need to preserve message boundaries. A quick test in PASTA mode, from namespace to init via tap: # ip link set dev pasta0 mtu 16384 # iperf3 -c 192.168.1.222 -t 60 [...] [ ID] Interval Transfer Bitrate [ 5] 0.00-60.00 sec 80.4 GBytes 11.5 Gbits/sec receiver # iperf3 -c 2a02:6d40:3cfc:3a01:2b20:4a6a:c25a:3056 -t 60 [...] [ ID] Interval Transfer Bitrate [ 5] 0.00-60.01 sec 39.9 GBytes 5.71 Gbits/sec receiver # ip link set dev pasta0 mtu 65520 # iperf3 -c 192.168.1.222 -t 60 [...] [ ID] Interval Transfer Bitrate [ 5] 0.00-60.01 sec 88.7 GBytes 12.7 Gbits/sec receiver # iperf3 -c 2a02:6d40:3cfc:3a01:2b20:4a6a:c25a:3056 -t 60 [...] [ ID] Interval Transfer Bitrate [ 5] 0.00-60.00 sec 79.5 GBytes 11.4 Gbits/sec receiver Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
* tcp: Limit TCP_INFO getsockopt() syscallsStefano Brivio2021-07-271-1/+2
| | | | | | | | There's no need to constantly query the socket for number of acknowledged bytes if we're far from exhausting the sending window, just do it if we're at least down to 90% of it. Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
* tap: Increase amount of tap receive buffers to 128Stefano Brivio2021-07-272-12/+13
| | | | | | | | ...boom. To make it slightly more reasonable, shrink struct tap_msg down a bit, and move the main message array away from the stack of tap_handler_passt(). Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
* tcp, udp: Map source address to gateway for any traffic from 127.0.0.0/8Stefano Brivio2021-07-262-6/+7
| | | | | | ...instead of just 127.0.0.1. Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
* icmp: Work around possible failure on bind() due to e.g. broken SELinux policyStefano Brivio2021-07-263-5/+22
| | | | | | | | | | | | | | | If we can't bind() ping sockets, the echo identifier sent out from the socket won't be the original one seen from the tap. Binding a ping socket doesn't require any security capability, but it might still fail due to a broken SELinux policy, see for example: https://bugzilla.redhat.com/show_bug.cgi?id=1848929 Track the ICMP echo identifier as part of the epoll reference for the socket and replace it in the reply on mismatch. We won't send out the original identifier as sent from the guest, but still better than missing replies. Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
* tcp: Fix re-send mechanism to tap on ACK timeoutStefano Brivio2021-07-261-2/+3
| | | | Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
* tcp: Simplify ACK accounting, skip some useless operations on tap handlingStefano Brivio2021-07-261-19/+10
| | | | Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
* tcp: Introduce scatter-gather IO path from socket to tapStefano Brivio2021-07-264-45/+514
| | | | | | | | | | | | | | | | | ...similarly to what was done for UDP. Quick performance test with 32KiB buffers, host to VM: $ iperf3 -c 192.0.2.2 -N [ ID] Interval Transfer Bitrate Retr [ 5] 0.00-10.00 sec 8.47 GBytes 7.27 Gbits/sec 0 sender [ 5] 0.00-10.00 sec 8.45 GBytes 7.26 Gbits/sec receiver $ iperf3 -c 2a01:598:88ba:a056:271f:473a:c0d9:abc1 [ ID] Interval Transfer Bitrate Retr [ 5] 0.00-10.00 sec 8.43 GBytes 7.24 Gbits/sec 0 sender [ 5] 0.00-10.00 sec 8.41 GBytes 7.22 Gbits/sec receiver Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
* tap: Don't override address observed from guest with our own notion of itStefano Brivio2021-07-261-15/+22
| | | | | | | | | | | If a tap protocol handler doesn't consume the full batch of packets in one go, we already overrode the destination address in the packet buffer with the address which is configured at start. If we re-enter the tap handler, we shouldn't use the address from the packet buffers anymore to set the observed address of the guest: that's not the address observed from the guest, it's the configured one now. Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
* tcp, udp: Allow binding ports in init namespace to both tap and loopbackStefano Brivio2021-07-266-60/+140
| | | | | | | | Traffic with loopback source address will be forwarded to the direct loopback connection in the namespace, and the tap interface is used for the rest. Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
* doc/demo.sh: Increase tcp_rmem and tcp_wmem before running passtStefano Brivio2021-07-261-0/+2
| | | | | | ...this is convenient for performance testing. Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
* tap: Fill the IPv6 flow label field to represent flow associationStefano Brivio2021-07-265-10/+25
| | | | | | | | | This isn't optional: TCP streams must carry a unique, hard-to-guess, non-zero label for each direction. Linux, probably among others, will otherwise refuse to associate packets in a given stream to the same connection. Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
* checksum: Introduce AVX2 implementation, unify helpersStefano Brivio2021-07-268-92/+332
| | | | | | | | | | | | | | | | | | | Provide an AVX2-based function using compiler intrinsics for TCP/IP-style checksums. The load/unpack/add idea and implementation is largely based on code from BESS (the Berkeley Extensible Software Switch) licensed as 3-Clause BSD, with a number of modifications to further decrease pipeline stalls and to minimise cache pollution. This speeds up considerably data paths from sockets to tap interfaces, decreasing overhead for checksum computation, with 16-64KiB packet buffers, from approximately 11% to 7%. The rest is just syscalls at this point. While at it, provide convenience targets in the Makefile for avx2, avx2_debug, and debug targets -- these simply add target-specific CFLAGS to the build. Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
* dhcpv6: Drop bogus option length test while checking for not-on-link IA_NAStefano Brivio2021-07-261-4/+1
| | | | | | | | | | | dhcpv6_opt() already reflects consumed bytes on the remaining length, and that we're not exceeding the message length. At this point, the remaining length is usually zero. While at it, drop a useless __packed__ attribute that triggers a gcc warning. Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
* tcp: Don't open a new connection from tap if both SYN and ACK are setStefano Brivio2021-07-211-1/+1
| | | | Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
* tap: Fix comment for tap_handler_pasta()Stefano Brivio2021-07-211-1/+1
| | | | Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
* tcp, udp: Split IPv4 and IPv6 bound port setsStefano Brivio2021-07-215-79/+131
| | | | | | | | | | | Allow to bind IPv4 and IPv6 ports to tap, namespace or init separately. Port numbers of TCP ports that are bound in a namespace are also bound for UDP for convenience (e.g. iperf3), and IPv4 ports are always bound if the corresponding IPv6 port is bound (socket might not have the IPV6_V6ONLY option set). This will also be configurable later. Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
* tcp: Replace source address also if it's the same as the guest addressStefano Brivio2021-07-211-2/+4
| | | | | | | | ...not just for loopback addresses, with the address of the default gateway. Otherwise, the guest might receive packets with source and destination set to the same address. Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
* tcp: Increase maximum window scaling factor from 8 to 9Stefano Brivio2021-07-211-1/+1
| | | | | | | This is actually reasonable in terms of memory consumption and allows for better performance with local services. Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
* udp: Introduce recvmmsg()/sendmmsg(), zero-copy path from socketStefano Brivio2021-07-219-61/+537
| | | | | | | | | | Packets are received directly onto pre-cooked, static buffers for IPv4 (with partial checksum pre-calculation) and IPv6 frames, with pre-filled Ethernet addresses and, partially, IP headers, and sent out from the same buffers with sendmmsg(), for both passt and pasta (non-local traffic only) modes. Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
* ndp: Store link-local or global address on any NDP message receivedStefano Brivio2021-07-211-0/+5
| | | | | | | | The guest might not send other types of traffic before we try to communicate to it, so take also this chance to store its configured addresses. Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
* doc/demo.sh: Set MTU to 65535 for both veth interfacesStefano Brivio2021-07-211-0/+2
| | | | | | There's no reason to limit the MTU here to any lower value. Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
* dhcp: Set MTU option (26) to 65520 bytesStefano Brivio2021-07-211-0/+1
| | | | | | | | This value should work for all tap-like interfaces and is rather convenient for performance testing. It will be configurable later on. Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
* ndp: Fix calculation of length for DNS Search List option (31)Stefano Brivio2021-07-171-3/+3
| | | | Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
* tcp: Fix partial (ACK) message coalescing, ACK timeout, MSG_MORE flag settingStefano Brivio2021-07-171-2/+5
| | | | Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
* passt: Add PASTA mode, major reworkStefano Brivio2021-07-1720-1314/+2815
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | PASTA (Pack A Subtle Tap Abstraction) provides quasi-native host connectivity to an otherwise disconnected, unprivileged network and user namespace, similarly to slirp4netns. Given that the implementation is largely overlapping with PASST, no separate binary is built: 'pasta' (and 'passt4netns' for clarity) both link to 'passt', and the mode of operation is selected depending on how the binary is invoked. Usage example: $ unshare -rUn # echo $$ 1871759 $ ./pasta 1871759 # From another terminal # udhcpc -i pasta0 2>/dev/null # ping -c1 pasta.pizza PING pasta.pizza (64.190.62.111) 56(84) bytes of data. 64 bytes from 64.190.62.111 (64.190.62.111): icmp_seq=1 ttl=255 time=34.6 ms --- pasta.pizza ping statistics --- 1 packets transmitted, 1 received, 0% packet loss, time 0ms rtt min/avg/max/mdev = 34.575/34.575/34.575/0.000 ms # ping -c1 spaghetti.pizza PING spaghetti.pizza(2606:4700:3034::6815:147a (2606:4700:3034::6815:147a)) 56 data bytes 64 bytes from 2606:4700:3034::6815:147a (2606:4700:3034::6815:147a): icmp_seq=1 ttl=255 time=29.0 ms --- spaghetti.pizza ping statistics --- 1 packets transmitted, 1 received, 0% packet loss, time 0ms rtt min/avg/max/mdev = 28.967/28.967/28.967/0.000 ms This entails a major rework, especially with regard to the storage of tracked connections and to the semantics of epoll(7) references. Indexing TCP and UDP bindings merely by socket proved to be inflexible and unsuitable to handle different connection flows: pasta also provides Layer-2 to Layer-2 socket mapping between init and a separate namespace for local connections, using a pair of splice() system calls for TCP, and a recvmmsg()/sendmmsg() pair for UDP local bindings. For instance, building on the previous example: # ip link set dev lo up # iperf3 -s $ iperf3 -c ::1 -Z -w 32M -l 1024k -P2 | tail -n4 [SUM] 0.00-10.00 sec 52.3 GBytes 44.9 Gbits/sec 283 sender [SUM] 0.00-10.43 sec 52.3 GBytes 43.1 Gbits/sec receiver iperf Done. epoll(7) references now include a generic part in order to demultiplex data to the relevant protocol handler, using 24 bits for the socket number, and an opaque portion reserved for usage by the single protocol handlers, in order to track sockets back to corresponding connections and bindings. A number of fixes pertaining to TCP state machine and congestion window handling are also included here. Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
* qrap: Skip pci.2 bus for pc-q35, add proper error reporting for probingStefano Brivio2021-07-171-12/+31
| | | | | | | | | | | On pc-q35, pci.2 is usually configured by libvirt as a hotplug bus, so we can't use address 0x0 there. Look for free busses starting from pci.3 instead. While at it, add proper error reporting for passt probing, and add some comments to structs that were previously missing. Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
* doc/demo.sh: Support IPv4-only environments tooStefano Brivio2021-07-171-12/+15
| | | | | | | If no IPv6 global addresses are available, proceed with just IPv4 addresses and routes. Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
* tcp: Add support for kernels not exporting tcpi_snd_wnd via TCP_INFOStefano Brivio2021-06-081-6/+15
| | | | | | | | | | | | | | | | | | | | | Before commit 8f7baad7f035 ("tcp: Add snd_wnd to TCP_INFO"), the kernel didn't export tcpi_snd_wnd via TCP_INFO, which means we don't know what's the window size of the receiver, socket-side. To get TCP connections working in that case, ignore this value if it's zero during handshake, and use the initial window value as suggested by RFC 6928 (14 600 bytes, instead of 4 380 bytes), to keep network performance usable. To make the TCP dynamic responsive enough in this case, also check the socket for available data whenever we get an ACK segment from tap, instead of waiting until all the data from the tap is dequeued. While at it, fix the window scaling value sent for SYN and SYN, ACK segments: we want to increase the data pointer after writing the option, not the value itself. Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
* tcp: Fix window size in initial SYN, ACK segment to guestStefano Brivio2021-06-051-4/+7
| | | | | | | | | | | | During handshake, the initial SYN, ACK segment to the guest, send as a response to the SYN segment, needs to report the unscaled value for the window, given that the handshake hasn't completed yet. While at it, fix the endianness for the window value in case TCP parameters can't be queried via TCP_INFO and we need to use the default value. Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
* passt: When probing for an existing instance, also accept ENOENT on connect()Stefano Brivio2021-05-231-1/+1
| | | | | | | | The most common case is actually that no other instance created a socket with that name -- and that also means there is no other instance. Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
* util: On -DDEBUG, log to stderr with timestampsStefano Brivio2021-05-212-1/+27
| | | | Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
* passt: Also log to stderr, don't fork to background if not interactiveStefano Brivio2021-05-212-3/+3
| | | | Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
* icmp: Implement lazy bind for ping socketsStefano Brivio2021-05-212-3/+13
| | | | | | | | | It turns out that binding ICMP/ICMPv6 echo sockets takes a long time. Instead of binding all of them (one for each possible echo identification number, that is, 2^17) at start-up, bind them as ICMP/ICMPv6 packets are sent by the guest. Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
* ndp: Always answer neighbour solicitations with the requested target addressStefano Brivio2021-05-211-3/+10
| | | | | | | | The guest might try to resolve hosts other than the main host namespace (i.e. the gateway) -- just recycle the target address from the request and resolve it to the MAC address of the gateway. Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
* qrap: Connect to the first available instance of passt, probe via ARP requestStefano Brivio2021-05-213-25/+68
| | | | Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
* passt: Add support for multiple instances in different network namespacesStefano Brivio2021-05-216-44/+114
| | | | | | | | | | | | | ...sharing the same filesystem. Instead of a fixed path for the UNIX domain socket, passt now uses a path with a counter, probing for existing instances, and picking the first free one. The demo script is updated accordingly -- it can now be started several times to create multiple namespaces with an instance of passt each, with addressing reflecting separate subnets, and NDP proxying between them. Signed-off-by: Stefano Brivio <sbrivio@redhat.com>