diff options
author | Alexander Bluhm <bluhm@cvs.openbsd.org> | 2023-06-05 11:35:47 +0000 |
---|---|---|
committer | Alexander Bluhm <bluhm@cvs.openbsd.org> | 2023-06-05 11:35:47 +0000 |
commit | 040b1d607aa3d4ccdf36290f1c9b555f8fd8910c (patch) | |
tree | f5c70992cf5a475f08455c683b34286041852be5 /sys | |
parent | ff1505faf2768ec480ff385bc44657c79bac1eba (diff) |
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@
Diffstat (limited to 'sys')
-rw-r--r-- | sys/net/if.c | 21 | ||||
-rw-r--r-- | 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; |