On Mon, Jul 03, 2023 at 08:04:11PM +0300, Alexander Bluhm wrote:
> As final step before making LRO (Large Receive Offload) the default,
> we have to fix path MTU discovery when forwarding.
>
> The drivers, currently ix(4) and lo(4) only, record an upper bound
> of the size of the original packets in ph_mss. When sending we
> must chop the packets with TSO (TCP Segmentation Offload) to that
> size. That means we have to call tcp_if_output_tso() before
> ifp->if_output(). I have put that logic into if_output_tso() to
> avoid code duplication.
>
> ok?
I like the idea of this commit. Some comments below.
Thanks,
Jan
> Index: net/if.c
> ===================================================================
> RCS file: /data/mirror/openbsd/cvs/src/sys/net/if.c,v
> retrieving revision 1.702
> diff -u -p -r1.702 if.c
> --- net/if.c 2 Jul 2023 19:59:15 -0000 1.702
> +++ net/if.c 3 Jul 2023 10:28:30 -0000
> @@ -109,6 +109,9 @@
> #include <netinet/tcp.h>
> #include <netinet/tcp_timer.h>
> #include <netinet/tcp_var.h>
I think is a merge bug, isn't it?
> +#include <netinet/tcp.h>
> +#include <netinet/tcp_timer.h>
> +#include <netinet/tcp_var.h>
> @@ -883,6 +886,57 @@ if_output_ml(struct ifnet *ifp, struct m
> ml_purge(ml);
>
> return error;
> +}
> +
> +int
> +if_output_tso(struct ifnet *ifp, struct mbuf **mp, struct sockaddr *dst,
> + struct rtentry *rt, u_int mtu)
> +{
> + uint32_t ifcap;
> + int error;
> +
> + switch (dst->sa_family) {
> + case AF_INET:
> + ifcap = IFCAP_TSOv4;
> + break;
> +#ifdef INET6
> + case AF_INET6:
> + ifcap = IFCAP_TSOv6;
> + break;
> +#endif
> + default:
> + unhandled_af(dst->sa_family);
> + }
> +
> + /*
> + * Try to send with TSO first. When forwarding LRO may set
> + * maximium segment size in mbuf header. Chop TCP segment
> + * even if it would fit interface MTU to preserve maximum
> + * path MTU.
> + */
> + error = tcp_if_output_tso(ifp, mp, dst, rt, ifcap, mtu);
> + if (error || *mp == NULL)
> + return error;
> +
> + if ((*mp)->m_pkthdr.len <= mtu) {
I may miss something but...
Couldn't you move the *_cksum_out() calls above the upper
tcp_if_output_tso() call? And than remove the *_cksum_out() calls
inside of tcp_if_output_tso()?
Thus, there is just one place where we call them.
> + switch (dst->sa_family) {
> + case AF_INET:
> + in_hdr_cksum_out(*mp, ifp);
> + in_proto_cksum_out(*mp, ifp);
> + break;
> +#ifdef INET6
> + case AF_INET6:
> + in6_proto_cksum_out(*mp, ifp);
> + break;
> +#endif
> + }
> + error = ifp->if_output(ifp, *mp, dst, rt);
> + *mp = NULL;
> + return error;
> + }
> +
> + /* mp still contains mbuf that has to be fragmented or dropped. */
> + return 0;
> }