On Wed, Jan 26, 2022 at 01:29:42AM +0100, Alexander Bluhm wrote:
> Hi,
> 
> There were some problems with ix(4) and ixl(4) hardware checksumming
> for the output path on strict alignment architectures.
> 
> I have merged jan@'s diffs and added some sanity checks and
> workarounds.
> 
> - If the first mbuf is not aligned or not contigous, use m_copydata()
>   to extract the IP, IPv6, TCP header.
> - If the header is in the first mbuf, use m_data for the fast path.
> - Add netstat counter for invalid header chains.  This makes
>   us aware when hardware checksumming fails.
> - Add netstat counter for header copies.  This indicates that
>   better storage allocation in the network stack is possible.
>   It also allows to recognize alignment problems on non-strict
>   architectures.
> - There is not risk of crashes on sparc64.
> 
> Does this aproach make sense?

I think it is overly complicated and too much data is copied around.
First of all there is no need to extract ipproto.
The code can just use the M_TCP_CSUM_OUT and M_UDP_CSUM_OUT flags (they
are not set for other protos).
Because of this only they ip_hlen needs to be accessed and this can be
done with m_getptr().

In the IP6 case even more can be skipped since ip_hlen is static for IPv6.

In ixl(4) also the tcp header lenght needs to be extracted. Again the code
can be simplified because HW checksumming is only enabled if ip_hlen == 5
and so the offset of the th_off field is static (for both IPv4 and IPv6).
Again m_getptr can be used to just access the byte with th_off.

Longterm in_proto_cksum_out() should probably help provide the th_off
field. I think enforcing ip_hlen == 5 for UDP and TCP is fine, who needs
IP options on UDP and TCP?

> ix(4) works quite well, but finds some UDP packets that need copy.
> ixl(4) has not been tested yet.  I would like to have some feedback
> for the idea first.
> 
> bluhm
> 
> Index: sys/dev/pci/if_ix.c
> ===================================================================
> RCS file: /data/mirror/openbsd/cvs/src/sys/dev/pci/if_ix.c,v
> retrieving revision 1.180
> diff -u -p -r1.180 if_ix.c
> --- sys/dev/pci/if_ix.c       27 Jul 2021 01:44:55 -0000      1.180
> +++ sys/dev/pci/if_ix.c       25 Jan 2022 23:48:53 -0000
> @@ -1878,8 +1878,8 @@ ixgbe_setup_interface(struct ix_softc *s
>  #if NVLAN > 0
>       ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING;
>  #endif
> -
>       ifp->if_capabilities |= IFCAP_CSUM_TCPv4 | IFCAP_CSUM_UDPv4;
> +     ifp->if_capabilities |= IFCAP_CSUM_TCPv6 | IFCAP_CSUM_UDPv6;
>  
>       /*
>        * Specify the media types supported by this sc and register
> @@ -2437,12 +2437,6 @@ ixgbe_tx_ctx_setup(struct tx_ring *txr, 
>  #else
>       struct ether_header *eh;
>  #endif
> -     struct ip *ip;
> -#ifdef notyet
> -     struct ip6_hdr *ip6;
> -#endif
> -     struct mbuf *m;
> -     int     ipoff;
>       uint32_t vlan_macip_lens = 0, type_tucmd_mlhl = 0;
>       int     ehdrlen, ip_hlen = 0;
>       uint16_t etype;
> @@ -2511,29 +2505,46 @@ ixgbe_tx_ctx_setup(struct tx_ring *txr, 
>       vlan_macip_lens |= ehdrlen << IXGBE_ADVTXD_MACLEN_SHIFT;
>  
>       switch (etype) {
> -     case ETHERTYPE_IP:
> -             if (mp->m_pkthdr.len < ehdrlen + sizeof(*ip))
> +     case ETHERTYPE_IP: {
> +             struct ip *ip, ipdata;
> +
> +             if (mp->m_pkthdr.len < ehdrlen + sizeof(*ip)) {
> +                     ipstat_inc(ips_outbadcsum);
>                       return (-1);
> -             m = m_getptr(mp, ehdrlen, &ipoff);
> -             KASSERT(m != NULL && m->m_len - ipoff >= sizeof(*ip));
> -             ip = (struct ip *)(m->m_data + ipoff);
> +             }
> +             if (((mtod(mp, unsigned long) + ehdrlen) & ALIGNBYTES) == 0 &&
> +                 mp->m_len >= ehdrlen + sizeof(*ip)) {
> +                     ip = (struct ip *)(mp->m_data + ehdrlen);
> +             } else {
> +                     ipstat_inc(ips_outcpycsum);
> +                     m_copydata(mp, ehdrlen, sizeof(ipdata), &ipdata);
> +                     ip = &ipdata;
> +             }
>               ip_hlen = ip->ip_hl << 2;
>               ipproto = ip->ip_p;
>               type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_IPV4;
>               break;
> -#ifdef notyet
> -     case ETHERTYPE_IPV6:
> -             if (mp->m_pkthdr.len < ehdrlen + sizeof(*ip6))
> +     }
> +     case ETHERTYPE_IPV6: {
> +             struct ip6_hdr *ip6, ip6data;
> +
> +             if (mp->m_pkthdr.len < ehdrlen + sizeof(*ip6)) {
> +                     ip6stat_inc(ip6s_outbadcsum);
>                       return (-1);
> -             m = m_getptr(mp, ehdrlen, &ipoff);
> -             KASSERT(m != NULL && m->m_len - ipoff >= sizeof(*ip6));
> -             ip6 = (struct ip6 *)(m->m_data + ipoff);
> +             }
> +             if (((mtod(mp, unsigned long) + ehdrlen) & ALIGNBYTES) == 0 &&
> +                 mp->m_len >= ehdrlen + sizeof(*ip6)) {
> +                     ip6 = (struct ip6_hdr *)(mp->m_data + ehdrlen);
> +             } else {
> +                     ip6stat_inc(ip6s_outcpycsum);
> +                     m_copydata(mp, ehdrlen, sizeof(ip6data), &ip6data);
> +                     ip6 = &ip6data;
> +             }
>               ip_hlen = sizeof(*ip6);
> -             /* XXX-BZ this will go badly in case of ext hdrs. */
>               ipproto = ip6->ip6_nxt;
>               type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_IPV6;
>               break;
> -#endif
> +     }
>       default:
>               offload = FALSE;
>               break;
> @@ -2552,6 +2563,10 @@ ixgbe_tx_ctx_setup(struct tx_ring *txr, 
>                       type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_L4T_UDP;
>               break;
>       default:
> +             if (mp->m_pkthdr.csum_flags & M_TCP_CSUM_OUT)
> +                     tcpstat_inc(tcps_outbadcsum);
> +             if (mp->m_pkthdr.csum_flags & M_UDP_CSUM_OUT)
> +                     udpstat_inc(udps_outbadcsum);
>               offload = FALSE;
>               break;
>       }
> Index: sys/dev/pci/if_ixl.c
> ===================================================================
> RCS file: /data/mirror/openbsd/cvs/src/sys/dev/pci/if_ixl.c,v
> retrieving revision 1.78
> diff -u -p -r1.78 if_ixl.c
> --- sys/dev/pci/if_ixl.c      9 Jan 2022 05:42:54 -0000       1.78
> +++ sys/dev/pci/if_ixl.c      25 Jan 2022 23:50:01 -0000
> @@ -71,6 +71,7 @@
>  #include <net/if.h>
>  #include <net/if_dl.h>
>  #include <net/if_media.h>
> +#include <net/route.h>
>  #include <net/toeplitz.h>
>  
>  #if NBPFILTER > 0
> @@ -82,6 +83,15 @@
>  #endif
>  
>  #include <netinet/in.h>
> +#include <netinet/ip.h>
> +#include <netinet/ip_var.h>
> +#include <netinet/ip6.h>
> +#include <netinet6/ip6_var.h>
> +#include <netinet/tcp.h>
> +#include <netinet/tcp_timer.h>
> +#include <netinet/tcp_var.h>
> +#include <netinet/udp.h>
> +#include <netinet/udp_var.h>
>  #include <netinet/if_ether.h>
>  
>  #include <dev/pci/pcireg.h>
> @@ -1388,6 +1398,7 @@ static int      ixl_rxeof(struct ixl_softc *,
>  static void  ixl_rxfill(struct ixl_softc *, struct ixl_rx_ring *);
>  static void  ixl_rxrefill(void *);
>  static int   ixl_rxrinfo(struct ixl_softc *, struct if_rxrinfo *);
> +static void  ixl_rx_checksum(struct mbuf *, uint64_t);
>  
>  #if NKSTAT > 0
>  static void  ixl_kstat_attach(struct ixl_softc *);
> @@ -1942,9 +1953,10 @@ ixl_attach(struct device *parent, struct
>       ifp->if_capabilities = IFCAP_VLAN_MTU;
>  #if 0
>       ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING;
> -     ifp->if_capabilities |= IFCAP_CSUM_IPv4 | IFCAP_CSUM_TCPv4 |
> -         IFCAP_CSUM_UDPv4;
>  #endif
> +     ifp->if_capabilities |= IFCAP_CSUM_IPv4;
> +     ifp->if_capabilities |= IFCAP_CSUM_TCPv4 | IFCAP_CSUM_UDPv4;
> +     ifp->if_capabilities |= IFCAP_CSUM_TCPv6 | IFCAP_CSUM_UDPv6;
>  
>       ifmedia_init(&sc->sc_media, 0, ixl_media_change, ixl_media_status);
>  
> @@ -2771,6 +2783,119 @@ ixl_load_mbuf(bus_dma_tag_t dmat, bus_dm
>           BUS_DMA_STREAMING | BUS_DMA_NOWAIT));
>  }
>  
> +static int
> +ixl_tx_setup_offload(struct mbuf *mp, uint64_t *cmd)
> +{
> +     uint64_t         ip_hdr_len;
> +     uint8_t          ipproto;
> +
> +     switch (ntohs(mtod(mp, struct ether_header *)->ether_type)) {
> +     case ETHERTYPE_IP: {
> +             struct ip *ip, ipdata;
> +
> +             if (mp->m_pkthdr.len < ETHER_HDR_LEN + sizeof(*ip)) {
> +                     ipstat_inc(ips_outbadcsum);
> +                     return (-1);
> +             }
> +             if (((mtod(mp, unsigned long) + ETHER_HDR_LEN) & ALIGNBYTES)
> +                 == 0 && mp->m_len >= ETHER_HDR_LEN + sizeof(*ip)) {
> +                     ip = (struct ip *)(mp->m_data + ETHER_HDR_LEN);
> +             } else {
> +                     ipstat_inc(ips_outcpycsum);
> +                     m_copydata(mp, ETHER_HDR_LEN, sizeof(ipdata), &ipdata);
> +                     ip = &ipdata;
> +             }
> +             if (mp->m_pkthdr.csum_flags & M_IPV4_CSUM_OUT)
> +                     *cmd |= IXL_TX_DESC_CMD_IIPT_IPV4_CSUM;
> +             else
> +                     *cmd |= IXL_TX_DESC_CMD_IIPT_IPV4;
> +
> +             ip_hdr_len = ip->ip_hl << 2;
> +             ipproto = ip->ip_p;
> +             break;
> +     }
> +#ifdef INET6
> +     case ETHERTYPE_IPV6: {
> +             struct ip6_hdr *ip6, ip6data;
> +
> +             if (mp->m_pkthdr.len < ETHER_HDR_LEN + sizeof(*ip6)) {
> +                     ip6stat_inc(ip6s_outbadcsum);
> +                     return (-1);
> +             }
> +             if (((mtod(mp, unsigned long) + ETHER_HDR_LEN) & ALIGNBYTES)
> +                 == 0 && mp->m_len >= ETHER_HDR_LEN + sizeof(*ip6)) {
> +                     ip6 = (struct ip6_hdr *)(mp->m_data + ETHER_HDR_LEN);
> +             } else {
> +                     ip6stat_inc(ip6s_outcpycsum);
> +                     m_copydata(mp, ETHER_HDR_LEN, sizeof(ip6data),
> +                         &ip6data);
> +                     ip6 = &ip6data;
> +             }
> +
> +             *cmd |= IXL_TX_DESC_CMD_IIPT_IPV6;
> +
> +             ip_hdr_len = sizeof(*ip6);
> +             ipproto = ip6->ip6_nxt;
> +             break;
> +     }
> +#endif
> +     default:
> +             return (-1);
> +     }
> +
> +     *cmd |= (ETHER_HDR_LEN >> 1) << IXL_TX_DESC_MACLEN_SHIFT;
> +     *cmd |= (ip_hdr_len >> 2) << IXL_TX_DESC_IPLEN_SHIFT;
> +
> +     switch (ipproto) {
> +     case IPPROTO_TCP:
> +             if (mp->m_pkthdr.csum_flags & M_TCP_CSUM_OUT) {
> +                     struct tcphdr *th, thdata;
> +
> +                     if (mp->m_pkthdr.len < ETHER_HDR_LEN + ip_hdr_len +
> +                         sizeof(*th)) {
> +                             tcpstat_inc(tcps_outbadcsum);
> +                             return (-1);
> +                     }
> +                     if (((mtod(mp, unsigned long) + ETHER_HDR_LEN +
> +                         ip_hdr_len) & ALIGNBYTES) == 0 &&
> +                         mp->m_len >= ETHER_HDR_LEN + ip_hdr_len +
> +                         sizeof(*th)) {
> +                             th = (struct tcphdr *)(mp->m_data +
> +                                 ETHER_HDR_LEN + ip_hdr_len);
> +                     } else {
> +                             tcpstat_inc(tcps_outcpycsum);
> +                             m_copydata(mp, ETHER_HDR_LEN + ip_hdr_len,
> +                                 sizeof(thdata), &thdata);
> +                             th = &thdata;
> +                     }
> +                     *cmd |= IXL_TX_DESC_CMD_L4T_EOFT_TCP;
> +                     *cmd |= (uint64_t)th->th_off <<
> +                         IXL_TX_DESC_L4LEN_SHIFT;
> +             }
> +             break;
> +     case IPPROTO_UDP:
> +             if (mp->m_pkthdr.csum_flags & M_UDP_CSUM_OUT) {
> +                     if (mp->m_pkthdr.len < ETHER_HDR_LEN + ip_hdr_len +
> +                         sizeof(struct udphdr)) {
> +                             udpstat_inc(udps_outbadcsum);
> +                             return (-1);
> +                     }
> +                     *cmd |= IXL_TX_DESC_CMD_L4T_EOFT_UDP;
> +                     *cmd |= (sizeof(struct udphdr) >> 2) <<
> +                         IXL_TX_DESC_L4LEN_SHIFT;
> +             }
> +             break;
> +     default:
> +             if (mp->m_pkthdr.csum_flags & M_TCP_CSUM_OUT)
> +                     tcpstat_inc(tcps_outbadcsum);
> +             if (mp->m_pkthdr.csum_flags & M_UDP_CSUM_OUT)
> +                     udpstat_inc(udps_outbadcsum);
> +             return (-1);
> +     }
> +
> +     return (0);
> +}
> +
>  static void
>  ixl_start(struct ifqueue *ifq)
>  {
> @@ -2781,7 +2906,7 @@ ixl_start(struct ifqueue *ifq)
>       struct ixl_tx_map *txm;
>       bus_dmamap_t map;
>       struct mbuf *m;
> -     uint64_t cmd;
> +     uint64_t cmd, off = 0;
>       unsigned int prod, free, last, i;
>       unsigned int mask;
>       int post = 0;
> @@ -2828,12 +2953,15 @@ ixl_start(struct ifqueue *ifq)
>               bus_dmamap_sync(sc->sc_dmat, map, 0,
>                   map->dm_mapsize, BUS_DMASYNC_PREWRITE);
>  
> +             ixl_tx_setup_offload(m, &off);
> +
>               for (i = 0; i < map->dm_nsegs; i++) {
>                       txd = &ring[prod];
>  
>                       cmd = (uint64_t)map->dm_segs[i].ds_len <<
>                           IXL_TX_DESC_BSIZE_SHIFT;
>                       cmd |= IXL_TX_DESC_DTYPE_DATA | IXL_TX_DESC_CMD_ICRC;
> +                     cmd |= off;
>  
>                       htolem64(&txd->addr, map->dm_segs[i].ds_addr);
>                       htolem64(&txd->cmd, cmd);
> @@ -3190,6 +3318,7 @@ ixl_rxeof(struct ixl_softc *sc, struct i
>                                       m->m_pkthdr.csum_flags |= M_FLOWID;
>                               }
>  
> +                             ixl_rx_checksum(m, word);
>                               ml_enqueue(&ml, m);
>                       } else {
>                               ifp->if_ierrors++; /* XXX */
> @@ -3320,6 +3449,23 @@ ixl_rxrinfo(struct ixl_softc *sc, struct
>       free(ifr, M_TEMP, ixl_nqueues(sc) * sizeof(*ifr));
>  
>       return (rv);
> +}
> +
> +static void
> +ixl_rx_checksum(struct mbuf *m, uint64_t word)
> +{
> +     if (!ISSET(word, IXL_RX_DESC_L3L4P))
> +             return;
> +
> +     if (ISSET(word, IXL_RX_DESC_IPE))
> +             return;
> +
> +     m->m_pkthdr.csum_flags |= M_IPV4_CSUM_IN_OK;
> +
> +     if (ISSET(word, IXL_RX_DESC_L4E))
> +             return;
> +
> +     m->m_pkthdr.csum_flags |= M_TCP_CSUM_IN_OK | M_UDP_CSUM_IN_OK;
>  }
>  
>  static int
> Index: sys/dev/pci/ixgbe.h
> ===================================================================
> RCS file: /data/mirror/openbsd/cvs/src/sys/dev/pci/ixgbe.h,v
> retrieving revision 1.32
> diff -u -p -r1.32 ixgbe.h
> --- sys/dev/pci/ixgbe.h       18 Jul 2020 07:18:22 -0000      1.32
> +++ sys/dev/pci/ixgbe.h       25 Jan 2022 22:25:56 -0000
> @@ -60,11 +60,20 @@
>  
>  #include <net/if.h>
>  #include <net/if_media.h>
> +#include <net/route.h>
>  #include <net/toeplitz.h>
>  
>  #include <netinet/in.h>
>  #include <netinet/if_ether.h>
>  #include <netinet/ip.h>
> +#include <netinet/ip6.h>
> +#include <netinet/ip_var.h>
> +#include <netinet6/ip6_var.h>
> +#include <netinet/tcp.h>
> +#include <netinet/tcp_timer.h>
> +#include <netinet/tcp_var.h>
> +#include <netinet/udp.h>
> +#include <netinet/udp_var.h>
>  
>  #if NBPFILTER > 0
>  #include <net/bpf.h>
> Index: sys/netinet/ip_var.h
> ===================================================================
> RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ip_var.h,v
> retrieving revision 1.88
> diff -u -p -r1.88 ip_var.h
> --- sys/netinet/ip_var.h      30 Mar 2021 08:37:11 -0000      1.88
> +++ sys/netinet/ip_var.h      25 Jan 2022 18:07:02 -0000
> @@ -88,6 +88,8 @@ struct      ipstat {
>       u_long  ips_outswcsum;          /* software checksummed on output */
>       u_long  ips_notmember;          /* multicasts for unregistered groups */
>       u_long  ips_wrongif;            /* packet received on wrong interface */
> +     u_long  ips_outbadcsum;         /* output hardware checksum failed */
> +     u_long  ips_outcpycsum;         /* output checksum needs copy */
>  };
>  
>  struct ipoption {
> @@ -133,6 +135,8 @@ enum ipstat_counters {
>       ips_outswcsum,          /* software checksummed on output */
>       ips_notmember,          /* multicasts for unregistered groups */
>       ips_wrongif,            /* packet received on wrong interface */
> +     ips_outbadcsum,         /* output hardware checksum failed */
> +     ips_outcpycsum,         /* output checksum needs copy */
>  
>       ips_ncounters
>  };
> Index: sys/netinet/tcp_var.h
> ===================================================================
> RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/tcp_var.h,v
> retrieving revision 1.137
> diff -u -p -r1.137 tcp_var.h
> --- sys/netinet/tcp_var.h     23 Jan 2022 21:44:31 -0000      1.137
> +++ sys/netinet/tcp_var.h     25 Jan 2022 22:19:42 -0000
> @@ -434,6 +434,9 @@ struct    tcpstat {
>       u_int64_t tcps_sack_rcv_opts;           /* SACK options received */
>       u_int64_t tcps_sack_snd_opts;           /* SACK options sent */
>       u_int64_t tcps_sack_drop_opts;          /* SACK options dropped */
> +
> +     u_int64_t tcps_outbadcsum;      /* output hardware checksum failed */
> +     u_int64_t tcps_outcpycsum;      /* output checksum needs copy */
>  };
>  
>  /*
> @@ -605,6 +608,9 @@ enum tcpstat_counters {
>       tcps_sack_rcv_opts,
>       tcps_sack_snd_opts,
>       tcps_sack_drop_opts,
> +     tcps_outbadcsum,
> +     tcps_outcpycsum,
> +
>       tcps_ncounters,
>  };
>  
> Index: sys/netinet/udp_var.h
> ===================================================================
> RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/udp_var.h,v
> retrieving revision 1.35
> diff -u -p -r1.35 udp_var.h
> --- sys/netinet/udp_var.h     22 Aug 2020 17:54:57 -0000      1.35
> +++ sys/netinet/udp_var.h     25 Jan 2022 22:22:08 -0000
> @@ -68,6 +68,8 @@ struct      udpstat {
>                               /* output statistics: */
>       u_long  udps_opackets;          /* total output packets */
>       u_long  udps_outswcsum;         /* output software-csummed packets */
> +     u_long  udps_outbadcsum;        /* output hardware checksum failed */
> +     u_long  udps_outcpycsum;        /* output checksum needs copy */
>  };
>  
>  /*
> @@ -111,6 +113,8 @@ enum udpstat_counters {
>                       /* output statistics: */
>       udps_opackets,          /* total output packets */
>       udps_outswcsum,         /* output software-csummed packets */
> +     udps_outbadcsum,        /* output hardware checksum failed */
> +     udps_outcpycsum,        /* output checksum needs copy */
>  
>       udps_ncounters
>  };
> Index: sys/netinet6/ip6_var.h
> ===================================================================
> RCS file: /data/mirror/openbsd/cvs/src/sys/netinet6/ip6_var.h,v
> retrieving revision 1.89
> diff -u -p -r1.89 ip6_var.h
> --- sys/netinet6/ip6_var.h    1 Dec 2021 12:51:09 -0000       1.89
> +++ sys/netinet6/ip6_var.h    25 Jan 2022 22:12:22 -0000
> @@ -199,6 +199,8 @@ struct    ip6stat {
>       u_int64_t ip6s_forward_cachehit;
>       u_int64_t ip6s_forward_cachemiss;
>       u_int64_t ip6s_wrongif;
> +     u_int64_t ip6s_outbadcsum;
> +     u_int64_t ip6s_outcpycsum;
>  };
>  
>  #ifdef _KERNEL
> @@ -245,6 +247,9 @@ enum ip6stat_counters {
>       ip6s_forward_cachehit = ip6s_sources_deprecated + 16,
>       ip6s_forward_cachemiss,
>       ip6s_wrongif,
> +     ip6s_outbadcsum,
> +     ip6s_outcpycsum,
> +
>       ip6s_ncounters,
>  };
>  
> Index: usr.bin/netstat/inet.c
> ===================================================================
> RCS file: /data/mirror/openbsd/cvs/src/usr.bin/netstat/inet.c,v
> retrieving revision 1.173
> diff -u -p -r1.173 inet.c
> --- usr.bin/netstat/inet.c    5 Dec 2021 22:36:19 -0000       1.173
> +++ usr.bin/netstat/inet.c    25 Jan 2022 23:11:34 -0000
> @@ -408,6 +408,8 @@ tcp_stats(char *name)
>       p(tcps_sndwinup, "\t\t%u window update packet%s\n");
>       p(tcps_sndctrl, "\t\t%u control packet%s\n");
>       p(tcps_outswcsum, "\t\t%u packet%s software-checksummed\n");
> +     p(tcps_outbadcsum, "\t%llu packet%s output hardware checksum failed\n");
> +     p(tcps_outcpycsum, "\t%llu packet%s output checksum needs copy\n");
>       p(tcps_rcvtotal, "\t%u packet%s received\n");
>       p2(tcps_rcvackpack, tcps_rcvackbyte, "\t\t%u ack%s (for %llu 
> byte%s)\n");
>       p(tcps_rcvdupack, "\t\t%u duplicate ack%s\n");
> @@ -540,6 +542,8 @@ udp_stats(char *name)
>       p1(udps_nosum, "\t%lu with no checksum\n");
>       p(udps_inswcsum, "\t%lu input packet%s software-checksummed\n");
>       p(udps_outswcsum, "\t%lu output packet%s software-checksummed\n");
> +     p(udps_outbadcsum, "\t%lu packet%s output hardware checksum failed\n");
> +     p(udps_outcpycsum, "\t%lu packet%s output checksum needs copy\n");
>       p1(udps_noport, "\t%lu dropped due to no socket\n");
>       p(udps_noportbcast, "\t%lu broadcast/multicast datagram%s dropped due 
> to no socket\n");
>       p1(udps_nosec, "\t%lu dropped due to missing IPsec protection\n");
> @@ -610,6 +614,8 @@ ip_stats(char *name)
>       p(ips_badaddr, "\t%lu datagram%s with bad address in header\n");
>       p(ips_inswcsum, "\t%lu input datagram%s software-checksummed\n");
>       p(ips_outswcsum, "\t%lu output datagram%s software-checksummed\n");
> +     p(ips_outbadcsum, "\t%lu packet%s output hardware checksum failed\n");
> +     p(ips_outcpycsum, "\t%lu packet%s output checksum needs copy\n");
>       p(ips_notmember, "\t%lu multicast packet%s which we don't join\n");
>       p(ips_wrongif, "\t%lu packet%s received on wrong interface\n");
>  #undef p
> Index: usr.bin/netstat/inet6.c
> ===================================================================
> RCS file: /data/mirror/openbsd/cvs/src/usr.bin/netstat/inet6.c,v
> retrieving revision 1.55
> diff -u -p -r1.55 inet6.c
> --- usr.bin/netstat/inet6.c   26 Jan 2021 18:22:35 -0000      1.55
> +++ usr.bin/netstat/inet6.c   25 Jan 2022 23:11:34 -0000
> @@ -372,6 +372,8 @@ ip6_stats(char *name)
>       p(ip6s_badscope, "\t%llu packet%s that violated scope rules\n");
>       p(ip6s_notmember, "\t%llu multicast packet%s which we don't join\n");
>       p(ip6s_wrongif, "\t%llu packet%s received on wrong interface\n");
> +     p(ip6s_outbadcsum, "\t%llu packet%s output hardware checksum failed\n");
> +     p(ip6s_outcpycsum, "\t%llu packet%s output checksum needs copy\n");
>       for (first = 1, i = 0; i < 256; i++)
>               if (ip6stat.ip6s_nxthist[i] != 0) {
>                       if (first) {
> 

-- 
:wq Claudio

Reply via email to