On Thu, Jul 06, 2023 at 10:19:21PM +0300, Alexander Bluhm wrote:
> On Thu, Jul 06, 2023 at 08:49:03PM +0200, Jan Klemkow wrote:
> > > @@ -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>
>
> Right.
>
> > > + 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
>
> There is the case in tcp_if_output_tso() where we call tcp_chopper().
> Then checksum has to be calcualted after chopping. If I do it
> always before tcp_if_output_tso(), we may caluclate it twice. Once
> for the large packet and once for the small ones.
>
> New diff without duplicate includes.
tested with v4/v6, direct and forwarding.
ok jan@
> Index: net/if.c
> ===================================================================
> RCS file: /data/mirror/openbsd/cvs/src/sys/net/if.c,v
> retrieving revision 1.704
> diff -u -p -r1.704 if.c
> --- net/if.c 6 Jul 2023 04:55:04 -0000 1.704
> +++ net/if.c 6 Jul 2023 19:15:00 -0000
> @@ -886,6 +886,57 @@ if_output_ml(struct ifnet *ifp, struct m
> }
>
> 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) {
> + 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;
> +}
> +
> +int
> if_output_mq(struct ifnet *ifp, struct mbuf_queue *mq, unsigned int *total,
> struct sockaddr *dst, struct rtentry *rt)
> {
> Index: net/if_var.h
> ===================================================================
> RCS file: /data/mirror/openbsd/cvs/src/sys/net/if_var.h,v
> retrieving revision 1.128
> diff -u -p -r1.128 if_var.h
> --- net/if_var.h 28 Jun 2023 11:49:49 -0000 1.128
> +++ net/if_var.h 6 Jul 2023 19:12:39 -0000
> @@ -329,6 +329,8 @@ int if_output_ml(struct ifnet *, struct
> struct sockaddr *, struct rtentry *);
> int if_output_mq(struct ifnet *, struct mbuf_queue *, unsigned int *,
> struct sockaddr *, struct rtentry *);
> +int if_output_tso(struct ifnet *, struct mbuf **, struct sockaddr *,
> + struct rtentry *, u_int);
> int if_output_local(struct ifnet *, struct mbuf *, sa_family_t);
> void if_rtrequest_dummy(struct ifnet *, int, struct rtentry *);
> void p2p_rtrequest(struct ifnet *, int, struct rtentry *);
> Index: net/pf.c
> ===================================================================
> RCS file: /data/mirror/openbsd/cvs/src/sys/net/pf.c,v
> retrieving revision 1.1182
> diff -u -p -r1.1182 pf.c
> --- net/pf.c 6 Jul 2023 04:55:05 -0000 1.1182
> +++ net/pf.c 6 Jul 2023 19:12:39 -0000
> @@ -6610,15 +6610,8 @@ pf_route(struct pf_pdesc *pd, struct pf_
> ip = mtod(m0, struct ip *);
> }
>
> - if (ntohs(ip->ip_len) <= ifp->if_mtu) {
> - in_hdr_cksum_out(m0, ifp);
> - in_proto_cksum_out(m0, ifp);
> - ifp->if_output(ifp, m0, sintosa(dst), rt);
> - goto done;
> - }
> -
> - if (tcp_if_output_tso(ifp, &m0, sintosa(dst), rt,
> - IFCAP_TSOv4, ifp->if_mtu) || m0 == NULL)
> + if (if_output_tso(ifp, &m0, sintosa(dst), rt, ifp->if_mtu) ||
> + m0 == NULL)
> goto done;
>
> /*
> @@ -6745,14 +6738,8 @@ pf_route6(struct pf_pdesc *pd, struct pf
> goto done;
> }
>
> - if (m0->m_pkthdr.len <= ifp->if_mtu) {
> - in6_proto_cksum_out(m0, ifp);
> - ifp->if_output(ifp, m0, sin6tosa(dst), rt);
> - goto done;
> - }
> -
> - if (tcp_if_output_tso(ifp, &m0, sin6tosa(dst), rt,
> - IFCAP_TSOv6, ifp->if_mtu) || m0 == NULL)
> + if (if_output_tso(ifp, &m0, sin6tosa(dst), rt, ifp->if_mtu) ||
> + m0 == NULL)
> goto done;
>
> ip6stat_inc(ip6s_cantfrag);
> Index: netinet/ip_output.c
> ===================================================================
> RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ip_output.c,v
> retrieving revision 1.389
> diff -u -p -r1.389 ip_output.c
> --- netinet/ip_output.c 4 Jul 2023 10:48:19 -0000 1.389
> +++ netinet/ip_output.c 6 Jul 2023 19:12:39 -0000
> @@ -451,17 +451,9 @@ sendit:
> #endif
>
> /*
> - * If small enough for interface, can just send directly.
> + * If TSO or small enough for interface, can just send directly.
> */
> - if (ntohs(ip->ip_len) <= mtu) {
> - in_hdr_cksum_out(m, ifp);
> - in_proto_cksum_out(m, ifp);
> - error = ifp->if_output(ifp, m, sintosa(dst), ro->ro_rt);
> - goto done;
> - }
> -
> - error = tcp_if_output_tso(ifp, &m, sintosa(dst), ro->ro_rt,
> - IFCAP_TSOv4, mtu);
> + error = if_output_tso(ifp, &m, sintosa(dst), ro->ro_rt, mtu);
> if (error || m == NULL)
> goto done;
>
> Index: netinet6/ip6_forward.c
> ===================================================================
> RCS file: /data/mirror/openbsd/cvs/src/sys/netinet6/ip6_forward.c,v
> retrieving revision 1.111
> diff -u -p -r1.111 ip6_forward.c
> --- netinet6/ip6_forward.c 16 Jun 2023 19:18:56 -0000 1.111
> +++ netinet6/ip6_forward.c 6 Jul 2023 19:12:39 -0000
> @@ -319,25 +319,13 @@ reroute:
> }
> #endif
>
> - error = tcp_if_output_tso(ifp, &m, sin6tosa(sin6), rt, IFCAP_TSOv6,
> - ifp->if_mtu);
> + error = if_output_tso(ifp, &m, sin6tosa(sin6), rt, ifp->if_mtu);
> if (error)
> ip6stat_inc(ip6s_cantforward);
> else if (m == NULL)
> ip6stat_inc(ip6s_forward);
> if (error || m == NULL)
> goto senderr;
> -
> - /* Check the size after pf_test to give pf a chance to refragment. */
> - if (m->m_pkthdr.len <= ifp->if_mtu) {
> - in6_proto_cksum_out(m, ifp);
> - error = ifp->if_output(ifp, m, sin6tosa(sin6), rt);
> - if (error)
> - ip6stat_inc(ip6s_cantforward);
> - else
> - ip6stat_inc(ip6s_forward);
> - goto senderr;
> - }
>
> if (mcopy != NULL)
> icmp6_error(mcopy, ICMP6_PACKET_TOO_BIG, 0, ifp->if_mtu);
> Index: netinet6/ip6_output.c
> ===================================================================
> RCS file: /data/mirror/openbsd/cvs/src/sys/netinet6/ip6_output.c,v
> retrieving revision 1.278
> diff -u -p -r1.278 ip6_output.c
> --- netinet6/ip6_output.c 13 Jun 2023 19:34:12 -0000 1.278
> +++ netinet6/ip6_output.c 6 Jul 2023 19:15:00 -0000
> @@ -677,7 +677,8 @@ reroute:
> * 2-a: send as is if tlen <= interface mtu
> * 2-b: error if tlen > interface mtu
> */
> - tlen = m->m_pkthdr.len;
> + tlen = ISSET(m->m_pkthdr.csum_flags, M_TCP_TSO) ?
> + m->m_pkthdr.ph_mss : m->m_pkthdr.len;
>
> if (ISSET(m->m_pkthdr.csum_flags, M_IPV6_DF_OUT)) {
> CLR(m->m_pkthdr.csum_flags, M_IPV6_DF_OUT);
> @@ -686,9 +687,8 @@ reroute:
> dontfrag = 1;
> else
> dontfrag = 0;
> - if (dontfrag && /* case 2-b */
> - (ISSET(m->m_pkthdr.csum_flags, M_TCP_TSO) ?
> - m->m_pkthdr.ph_mss : tlen) > ifp->if_mtu) {
> +
> + if (dontfrag && tlen > ifp->if_mtu) { /* case 2-b */
> #ifdef IPSEC
> if (ip_mtudisc)
> ipsec_adjust_mtu(m, mtu);
> @@ -701,15 +701,12 @@ reroute:
> * transmit packet without fragmentation
> */
> if (dontfrag || tlen <= mtu) { /* case 1-a and 2-a */
> - in6_proto_cksum_out(m, ifp);
> - error = ifp->if_output(ifp, m, sin6tosa(dst), ro->ro_rt);
> - goto done;
> + error = if_output_tso(ifp, &m, sin6tosa(dst), ro->ro_rt,
> + ifp->if_mtu);
> + if (error || m == NULL)
> + goto done;
> + goto bad; /* should not happen */
> }
> -
> - error = tcp_if_output_tso(ifp, &m, sin6tosa(dst), ro->ro_rt,
> - IFCAP_TSOv6, mtu);
> - if (error || m == NULL)
> - goto done;
>
> /*
> * try to fragment the packet. case 1-b
>