From c778c0d73570b51def4f061069af442165eb791e Mon Sep 17 00:00:00 2001 From: bluhm Date: Mon, 5 Jun 2023 11:35:46 +0000 Subject: [PATCH] Do not calculate IP, TCP, UDP checksums on loopback interface. Packets sent over loopback got their checksums calculated twice. In the output path they were filled in and during TCP/IP input all checksums were calculated again to be compared with the previous result. Avoid this by claiming that lo(4) supports hardware checksum offloading. For each packet convert the flag that the checksum should be calculated to the flag that it has been checked successfully. Keep the flag that it should be calculated for the case that it may be bridged or forwarded later. A drawback is that "tcpdump -ni lo0 -v" reports invalid checksum. But that is the same with physical interfaces and hardware offloading. OK dlg@ --- sys/net/if.c | 21 +++++++++++++++++++-- sys/net/if_loop.c | 5 ++++- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/sys/net/if.c b/sys/net/if.c index 36c52330e35..208dd448382 100644 --- a/sys/net/if.c +++ b/sys/net/if.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if.c,v 1.698 2023/05/30 23:55:42 dlg Exp $ */ +/* $OpenBSD: if.c,v 1.699 2023/06/05 11:35:46 bluhm Exp $ */ /* $NetBSD: if.c,v 1.35 1996/05/07 05:26:04 thorpej Exp $ */ /* @@ -778,7 +778,7 @@ if_input(struct ifnet *ifp, struct mbuf_list *ml) int if_input_local(struct ifnet *ifp, struct mbuf *m, sa_family_t af) { - int keepflags; + int keepflags, keepcksum; #if NBPFILTER > 0 /* @@ -796,11 +796,26 @@ if_input_local(struct ifnet *ifp, struct mbuf *m, sa_family_t af) } #endif keepflags = m->m_flags & (M_BCAST|M_MCAST); + /* + * Preserve outgoing checksum flags, in case the packet is + * forwarded to another interface. Then the checksum, which + * is now incorrect, will be calculated before sending. + */ + keepcksum = m->m_pkthdr.csum_flags & (M_IPV4_CSUM_OUT | + M_TCP_CSUM_OUT | M_UDP_CSUM_OUT | M_ICMP_CSUM_OUT); m_resethdr(m); m->m_flags |= M_LOOP | keepflags; + m->m_pkthdr.csum_flags = keepcksum; m->m_pkthdr.ph_ifidx = ifp->if_index; m->m_pkthdr.ph_rtableid = ifp->if_rdomain; + if (ISSET(keepcksum, M_TCP_CSUM_OUT)) + m->m_pkthdr.csum_flags |= M_TCP_CSUM_IN_OK; + if (ISSET(keepcksum, M_UDP_CSUM_OUT)) + m->m_pkthdr.csum_flags |= M_UDP_CSUM_IN_OK; + if (ISSET(keepcksum, M_ICMP_CSUM_OUT)) + m->m_pkthdr.csum_flags |= M_ICMP_CSUM_IN_OK; + ifp->if_opackets++; ifp->if_obytes += m->m_pkthdr.len; @@ -809,6 +824,8 @@ if_input_local(struct ifnet *ifp, struct mbuf *m, sa_family_t af) switch (af) { case AF_INET: + if (ISSET(keepcksum, M_IPV4_CSUM_OUT)) + m->m_pkthdr.csum_flags |= M_IPV4_CSUM_IN_OK; ipv4_input(ifp, m); break; #ifdef INET6 diff --git a/sys/net/if_loop.c b/sys/net/if_loop.c index 4077198b637..d96f5ea753a 100644 --- a/sys/net/if_loop.c +++ b/sys/net/if_loop.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_loop.c,v 1.93 2022/10/21 14:20:03 kn Exp $ */ +/* $OpenBSD: if_loop.c,v 1.94 2023/06/05 11:35:46 bluhm Exp $ */ /* $NetBSD: if_loop.c,v 1.15 1996/05/07 02:40:33 thorpej Exp $ */ /* @@ -173,6 +173,9 @@ loop_clone_create(struct if_clone *ifc, int unit) ifp->if_mtu = LOMTU; ifp->if_flags = IFF_LOOPBACK | IFF_MULTICAST; ifp->if_xflags = IFXF_CLONED; + ifp->if_capabilities = IFCAP_CSUM_IPv4 | + IFCAP_CSUM_TCPv4 | IFCAP_CSUM_UDPv4 | + IFCAP_CSUM_TCPv6 | IFCAP_CSUM_UDPv6; ifp->if_rtrequest = lortrequest; ifp->if_ioctl = loioctl; ifp->if_input = loinput; -- 2.20.1