summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorAlexander Bluhm <bluhm@cvs.openbsd.org>2023-06-05 11:35:47 +0000
committerAlexander Bluhm <bluhm@cvs.openbsd.org>2023-06-05 11:35:47 +0000
commit040b1d607aa3d4ccdf36290f1c9b555f8fd8910c (patch)
treef5c70992cf5a475f08455c683b34286041852be5 /sys
parentff1505faf2768ec480ff385bc44657c79bac1eba (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.c21
-rw-r--r--sys/net/if_loop.c5
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;