Commit graph

185 commits

Author SHA1 Message Date
Stefano Brivio
b15e97cb9d conf: Introduce PASST_LEGACY_NO_OPTIONS ifdef for legacy
Before introducing options, the default behaviour in passt mode was
to forward all ports, to run in foreground and to log to stderr.
Make it a bit more convenient to restore that at build time.

Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
2021-09-09 15:40:04 +02:00
Stefano Brivio
647a413794 tcp, udp: Restore usage of gateway for guest to connect to local host
This went lost in a recent rework: if the guest wants to connect
directly to the host, it can use the address of the default gateway.

Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
2021-09-01 17:00:27 +02:00
Stefano Brivio
f29c48db6b Makefile: Make sure destination directories exist on install
Mostly theoretical, but convenient for testing.

Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
2021-09-01 17:00:27 +02:00
Stefano Brivio
77d4efa236 udp: Handle partial failure in sendmmsg() to UNIX domain socket
Similarly to the handling introduced by commit "tcp: Proper error
handling for sendmmsg() to UNIX domain socket" for TCP, we need to
deal with partial sendmmsg() failures for UDP as well.

Here, we can lose messages, but we need to make sure that the last
message is delivered completely, otherwise qemu will fail to
reassemble further packets. For UDP, this is somewhat complicated
by the fact that one message might include multiple datagrams, and
we need to respect message boundaries: go through headers, and
calculate what we need to re-send, if anything.

Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
2021-09-01 17:00:27 +02:00
Stefano Brivio
cd04d238b2 doc/demo: Also forward all UDP ports from namespace
Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
2021-09-01 17:00:27 +02:00
Stefano Brivio
564fbca39a doc/demo: Explicitly run in foreground, drop pipe to cat
Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
2021-09-01 17:00:27 +02:00
Stefano Brivio
e1c94637ad dhcp: Send option 121 if the default gateway is not on the assigned subnet
This enables CirrOS with udhcpc to set up a route to a gateway
that's not on the assigned subnet, together with:
	https://bugs.launchpad.net/cirros/+bug/1190372

Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
2021-09-01 17:00:27 +02:00
Stefano Brivio
7eb155ab8f conf: Fix check for IPv6 DNS address being already set
Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
2021-09-01 17:00:27 +02:00
Stefano Brivio
64c0f20ab3 arp: Don't resolve own, configured IPv4 address
DHCP clients might try to resolve the assigned address to check if it's
already in use: don't resolve the configured IPv4 address.

Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
2021-09-01 17:00:27 +02:00
Stefano Brivio
77c72b31ed Makefile: Quick hack to build convenience Debian and RPM packages
Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
2021-09-01 17:00:27 +02:00
Stefano Brivio
b9c6fca469 Makefile: Add install, uninstall targets
Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
2021-09-01 17:00:27 +02:00
Stefano Brivio
da20f57f19 passt, qrap: Add man pages
Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
2021-09-01 17:00:27 +02:00
Stefano Brivio
05432945bb qrap: Minor fixes in comments and usage message
Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
2021-09-01 17:00:27 +02:00
Stefano Brivio
d5b3467056 pasta: If a new namespace is created, wait for it to be ready before proceeding
Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
2021-09-01 17:00:27 +02:00
Stefano Brivio
088d19fbb8 conf: Minor fixes for usage message
Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
2021-09-01 17:00:27 +02:00
Stefano Brivio
2166c5872e arp: Don't answer announcements from guest or namespace
Depending on the configuration, the host might have the same address.
Don't answer them to avoid a duplicate IP address detection.

Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
2021-09-01 17:00:27 +02:00
Stefano Brivio
1e49d194d0 passt, pasta: Introduce command-line options and port re-mapping
Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
2021-09-01 17:00:27 +02:00
Stefano Brivio
1b1b27c06a tcp: Fixes for early data in SOCK_SYN_SENT, closing states, clamping window
More details here after rebase.

Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
2021-09-01 16:49:21 +02:00
Stefano Brivio
75a7239e5b tap: Make sure we don't receive frames bigger than ETH_MAX_MTU from qemu
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>
2021-09-01 16:49:21 +02:00
Stefano Brivio
353185cd36 dhcpv6: Fix parsing for IA_ADDR suboptions of IA_NA/IA_TA
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>
2021-09-01 16:49:21 +02:00
Stefano Brivio
d2272f74f7 tcp: Proper error handling for sendmmsg() to UNIX domain socket
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>
2021-08-26 23:30:22 +02:00
Stefano Brivio
cc2ebfd5f2 tcp: Never send ACK because of pending unacknowleged data when sending SYN
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>
2021-08-24 18:27:24 +02:00
Stefano Brivio
f2e3b9defd tcp: Drop EPOLLET for non-spliced connections
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>
2021-08-24 18:24:11 +02:00
Stefano Brivio
ce24fe0b3f util: Don't close ping sockets if bind() fails
...they're still usable, thanks to the workaround implemented in
icmp_tap_handler().

Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
2021-08-04 01:44:58 +02:00
Stefano Brivio
a340e5336d util: Fix millisecond logging timestamp calculation
Four sub-second digits means 0.1ms units: divide nanoseconds by
10^5, not 10^6.

Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
2021-08-04 01:39:00 +02:00
Stefano Brivio
539dcf5add tcp: Fast re-transmit, more fixes for closing states and no_snd_wnd
...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>
2021-08-04 01:35:45 +02:00
Stefano Brivio
0017bc3c3e tcp: Always allow ACKs when pending, fixes for no_snd_wnd and closing states
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>
2021-08-04 01:29:59 +02:00
Stefano Brivio
c62490ffa8 tcp: Lower TCP_TAP_FRAMES to 32
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>
2021-08-04 01:28:21 +02:00
Stefano Brivio
f57c2a72e4 doc/demo.sh: Pick IPv6 interface only if it has a nexthop route
Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
2021-08-04 01:22:27 +02:00
Stefano Brivio
dc169643a4 tcp: Full batched processing for tap messages
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>
2021-07-27 01:35:58 +02:00
Stefano Brivio
fd5050ccba tcp: Limit TCP_INFO getsockopt() syscalls
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>
2021-07-27 00:50:53 +02:00
Stefano Brivio
d372c42460 tap: Increase amount of tap receive buffers to 128
...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>
2021-07-27 00:48:06 +02:00
Stefano Brivio
8af961b85b tcp, udp: Map source address to gateway for any traffic from 127.0.0.0/8
...instead of just 127.0.0.1.

Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
2021-07-26 18:20:01 +02:00
Stefano Brivio
9663378d6d icmp: Work around possible failure on bind() due to e.g. broken SELinux policy
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>
2021-07-26 17:43:10 +02:00
Stefano Brivio
0279ec8eae tcp: Fix re-send mechanism to tap on ACK timeout
Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
2021-07-26 14:25:16 +02:00
Stefano Brivio
74677bddb2 tcp: Simplify ACK accounting, skip some useless operations on tap handling
Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
2021-07-26 14:23:34 +02:00
Stefano Brivio
39ad062100 tcp: Introduce scatter-gather IO path from socket to tap
...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>
2021-07-26 14:20:36 +02:00
Stefano Brivio
85a820a66f tap: Don't override address observed from guest with our own notion of it
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>
2021-07-26 14:13:21 +02:00
Stefano Brivio
86b273150a tcp, udp: Allow binding ports in init namespace to both tap and loopback
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>
2021-07-26 14:10:29 +02:00
Stefano Brivio
f4aaa471a1 doc/demo.sh: Increase tcp_rmem and tcp_wmem before running passt
...this is convenient for performance testing.

Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
2021-07-26 11:26:16 +02:00
Stefano Brivio
16b08367a5 tap: Fill the IPv6 flow label field to represent flow association
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>
2021-07-26 07:30:57 +02:00
Stefano Brivio
17765f8de0 checksum: Introduce AVX2 implementation, unify helpers
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>
2021-07-26 07:18:50 +02:00
Stefano Brivio
0be49ccd93 dhcpv6: Drop bogus option length test while checking for not-on-link IA_NA
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>
2021-07-26 07:11:33 +02:00
Stefano Brivio
60dee2705b tcp: Don't open a new connection from tap if both SYN and ACK are set
Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
2021-07-21 17:48:33 +02:00
Stefano Brivio
330ea9e681 tap: Fix comment for tap_handler_pasta()
Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
2021-07-21 17:48:12 +02:00
Stefano Brivio
49631a38a6 tcp, udp: Split IPv4 and IPv6 bound port sets
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>
2021-07-21 17:44:39 +02:00
Stefano Brivio
b508079c4c tcp: Replace source address also if it's the same as the guest address
...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>
2021-07-21 12:05:58 +02:00
Stefano Brivio
1642a04f48 tcp: Increase maximum window scaling factor from 8 to 9
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>
2021-07-21 12:05:03 +02:00
Stefano Brivio
64a0ba3b27 udp: Introduce recvmmsg()/sendmmsg(), zero-copy path from socket
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>
2021-07-21 12:01:04 +02:00
Stefano Brivio
7fa3e90290 ndp: Store link-local or global address on any NDP message received
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>
2021-07-21 10:04:17 +02:00