Commit graph

7 commits

Author SHA1 Message Date
Stefano Brivio
38b50dba47 passt: Spare some syscalls, add some optimisations from profiling
Avoid a bunch of syscalls on forwarding paths by:

- storing minimum and maximum file descriptor numbers for each
  protocol, fall back to SO_PROTOCOL query only on overlaps

- allocating a larger receive buffer -- this can result in more
  coalesced packets than sendmmsg() can take (UIO_MAXIOV, i.e. 1024),
  so make sure we don't exceed that within a single call to protocol
  tap handlers

- nesting the handling loop in tap_handler() in the receive loop,
  so that we have better chances of filling our receive buffer in
  fewer calls

- skipping the recvfrom() in the UDP handler on EPOLLERR -- there's
  nothing to be done in that case

and while at it:

- restore the 20ms timer interval for periodic (TCP) events, I
  accidentally changed that to 100ms in an earlier commit

- attempt using SO_ZEROCOPY for UDP -- if it's not available,
  sendmmsg() will succeed anyway

- fix the handling of the status code from sendmmsg(), if it fails,
  we'll try to discard the first message, hence return 1 from the
  UDP handler

Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
2021-04-23 22:22:37 +02:00
Stefano Brivio
6488c3e848 tcp, udp: Replace loopback source address by gateway address
This is symmetric with tap operation and addressing model, and
allows again to reach the guest behind the tap interface by
contacting the local address.

Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
2021-04-22 17:03:43 +02:00
Stefano Brivio
1f7cf04d34 passt: Introduce packet batching mechanism
Receive packets in batches from AF_UNIX, check if they can be sent
with a single syscall, and batch them up with sendmmsg() in case.

A bit rudimentary, currently only implemented for UDP, but it seems
to work.

Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
2021-04-22 13:39:36 +02:00
Stefano Brivio
f435e38927 udp: Fix typo in tcp_tap_handler() documentation
Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
2021-03-17 10:57:42 +01:00
Stefano Brivio
93977868f9 udp: Use size_t for return value of recvfrom()
Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
2021-03-17 10:57:42 +01:00
Stefano Brivio
8bca388e8a passt: Assorted fixes from "fresh eyes" review
A bunch of fixes not worth single commits at this stage, notably:

- make buffer, length parameter ordering consistent in ARP, DHCP,
  NDP handlers

- strict checking of buffer, message and option length in DHCP
  handler (a malicious client could have easily crashed it)

- set up forwarding for IPv4 and IPv6, and masquerading with nft for
  IPv4, from demo script

- get rid of separate slow and fast timers, we don't save any
  overhead that way

- stricter checking of buffer lengths as passed to tap handlers

- proper dequeuing from qemu socket back-end: I accidentally trashed
  messages that were bundled up together in a single tap read
  operation -- the length header tells us what's the size of the next
  frame, but there's no apparent limit to the number of messages we
  get with one single receive

- rework some bits of the TCP state machine, now passive and active
  connection closes appear to be robust -- introduce a new
  FIN_WAIT_1_SOCK_FIN state indicating a FIN_WAIT_1 with a FIN flag
  from socket

- streamline TCP option parsing routine

- track TCP state changes to stderr (this is temporary, proper
  debugging and syslogging support pending)

- observe that multiplying a number by four might very well change
  its value, and this happens to be the case for the data offset
  from the TCP header as we check if it's the same as the total
  length to find out if it's a duplicated ACK segment

- recent estimates suggest that the duration of a millisecond is
  closer to a million nanoseconds than a thousand of them, this
  trend is now reflected into the timespec_diff_ms() convenience
  routine

Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
2021-02-21 11:55:49 +01:00
Stefano Brivio
105b916361 passt: New design and implementation with native Layer 4 sockets
This is a reimplementation, partially building on the earlier draft,
that uses L4 sockets (SOCK_DGRAM, SOCK_STREAM) instead of SOCK_RAW,
providing L4-L2 translation functionality without requiring any
security capability.

Conceptually, this follows the design presented at:
	https://gitlab.com/abologna/kubevirt-and-kvm/-/blob/master/Networking.md

The most significant novelty here comes from TCP and UDP translation
layers. In particular, the TCP state and translation logic follows
the intent of being minimalistic, without reimplementing a full TCP
stack in either direction, and synchronising as much as possible the
TCP dynamic and flows between guest and host kernel.

Another important introduction concerns addressing, port translation
and forwarding. The Layer 4 implementations now attempt to bind on
all unbound ports, in order to forward connections in a transparent
way.

While at it:
- the qemu 'tap' back-end can't be used as-is by qrap anymore,
  because of explicit checks now introduced in qemu to ensure that
  the corresponding file descriptor is actually a tap device. For
  this reason, qrap now operates on a 'socket' back-end type,
  accounting for and building the additional header reporting
  frame length

- provide a demo script that sets up namespaces, addresses and
  routes, and starts the daemon. A virtual machine started in the
  network namespace, wrapped by qrap, will now directly interface
  with passt and communicate using Layer 4 sockets provided by the
  host kernel.

Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
2021-02-16 09:28:55 +01:00