Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F143874525
D51475.id158939.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
6 KB
Referenced Files
None
Subscribers
None
D51475.id158939.diff
View Options
diff --git a/sys/dev/virtio/network/virtio_net.h b/sys/dev/virtio/network/virtio_net.h
--- a/sys/dev/virtio/network/virtio_net.h
+++ b/sys/dev/virtio/network/virtio_net.h
@@ -260,20 +260,23 @@
virtio_net_rx_csum_by_offset(struct mbuf *m, uint16_t eth_type, int ip_start,
struct virtio_net_hdr *hdr)
{
+ int isipv6;
#if defined(INET) || defined(INET6)
int offset = hdr->csum_start + hdr->csum_offset;
#endif
- /* Only do a basic sanity check on the offset. */
+ /* Get IP version and do a basic sanity check on the offset. */
switch (eth_type) {
#if defined(INET)
case ETHERTYPE_IP:
+ isipv6 = 0;
if (__predict_false(offset < ip_start + sizeof(struct ip)))
return (1);
break;
#endif
#if defined(INET6)
case ETHERTYPE_IPV6:
+ isipv6 = 1;
if (__predict_false(offset < ip_start + sizeof(struct ip6_hdr)))
return (1);
break;
@@ -284,6 +287,9 @@
}
/*
+ * Forward the order to calculate the checksum in case this packet
+ * will leave the host over a real interface with checksum offloading.
+ *
* Use the offset to determine the appropriate CSUM_* flags. This is
* a bit dirty, but we can get by with it since the checksum offsets
* happen to be different. We assume the host host does not do IPv4
@@ -291,14 +297,16 @@
*/
switch (hdr->csum_offset) {
case offsetof(struct udphdr, uh_sum):
+ m->m_pkthdr.csum_flags |= (isipv6 ? CSUM_IP6_UDP : CSUM_IP_UDP);
+ break;
case offsetof(struct tcphdr, th_sum):
- m->m_pkthdr.csum_flags |= CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
- m->m_pkthdr.csum_data = 0xFFFF;
+ m->m_pkthdr.csum_flags |= (isipv6 ? CSUM_IP6_TCP : CSUM_IP_TCP);
break;
default:
- /* Here we should increment the rx_csum_bad_offset counter. */
+ /* A packet other than TCP or UDP is unexpected here */
return (1);
}
+ m->m_pkthdr.csum_data = hdr->csum_offset;
return (0);
}
diff --git a/sys/net/if_epair.c b/sys/net/if_epair.c
--- a/sys/net/if_epair.c
+++ b/sys/net/if_epair.c
@@ -549,8 +549,11 @@
ifp->if_dname = epairname;
ifp->if_dunit = unit;
ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
- ifp->if_capabilities = IFCAP_VLAN_MTU;
- ifp->if_capenable = IFCAP_VLAN_MTU;
+ ifp->if_capabilities = IFCAP_VLAN_MTU | IFCAP_TXCSUM |
+ IFCAP_TXCSUM_IPV6;
+ ifp->if_capenable = IFCAP_VLAN_MTU | IFCAP_TXCSUM | IFCAP_TXCSUM_IPV6;
+ ifp->if_hwassist = CSUM_IP_TCP | CSUM_IP_UDP | CSUM_IP6_TCP |
+ CSUM_IP6_UDP;
ifp->if_transmit = epair_transmit;
ifp->if_qflush = epair_qflush;
ifp->if_start = epair_start;
diff --git a/sys/netinet/ip_fastfwd.c b/sys/netinet/ip_fastfwd.c
--- a/sys/netinet/ip_fastfwd.c
+++ b/sys/netinet/ip_fastfwd.c
@@ -460,6 +460,16 @@
} else
gw = (const struct sockaddr *)dst;
+ /*
+ * If TCP/UDP header still needs a valid checksum and interface will not
+ * calculate it for us, do it here.
+ */
+ if (__predict_false(m->m_pkthdr.csum_flags & CSUM_DELAY_DATA &
+ ~nh->nh_ifp->if_hwassist)) {
+ in_delayed_cksum(m);
+ m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA;
+ }
+
/* Handle redirect case. */
redest.s_addr = 0;
if (V_ipsendredirects && osrc.s_addr == ip->ip_src.s_addr &&
diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c
--- a/sys/netinet/tcp_input.c
+++ b/sys/netinet/tcp_input.c
@@ -649,6 +649,12 @@
th->th_sum = in6_cksum_pseudo(ip6, tlen,
IPPROTO_TCP, m->m_pkthdr.csum_data);
th->th_sum ^= 0xffff;
+ } else if (m->m_pkthdr.csum_flags & CSUM_IP6_TCP) {
+ /*
+ * Packet from local host (maybe from a VM).
+ * Checksum not required.
+ */
+ th->th_sum = 0;
} else
th->th_sum = in6_cksum(m, IPPROTO_TCP, off0, tlen);
if (th->th_sum) {
@@ -709,6 +715,12 @@
htonl(m->m_pkthdr.csum_data + tlen +
IPPROTO_TCP));
th->th_sum ^= 0xffff;
+ } else if (m->m_pkthdr.csum_flags & CSUM_IP_TCP) {
+ /*
+ * Packet from local host (maybe from a VM).
+ * Checksum not required.
+ */
+ th->th_sum = 0;
} else {
struct ipovly *ipov = (struct ipovly *)ip;
diff --git a/sys/netinet/udp_usrreq.c b/sys/netinet/udp_usrreq.c
--- a/sys/netinet/udp_usrreq.c
+++ b/sys/netinet/udp_usrreq.c
@@ -555,6 +555,12 @@
ip->ip_dst.s_addr, htonl((u_short)len +
m->m_pkthdr.csum_data + proto));
uh_sum ^= 0xffff;
+ } else if (m->m_pkthdr.csum_flags & CSUM_IP_UDP) {
+ /*
+ * Packet from local host (maybe from a VM).
+ * Checksum not required.
+ */
+ uh_sum = 0;
} else {
char b[offsetof(struct ipovly, ih_src)];
struct ipovly *ipov = (struct ipovly *)ip;
diff --git a/sys/netinet6/ip6_fastfwd.c b/sys/netinet6/ip6_fastfwd.c
--- a/sys/netinet6/ip6_fastfwd.c
+++ b/sys/netinet6/ip6_fastfwd.c
@@ -277,6 +277,19 @@
ip6->ip6_hlim -= IPV6_HLIMDEC;
}
+ /*
+ * If TCP/UDP header still needs a valid checksum and interface will not
+ * calculate it for us, do it here.
+ */
+ if (__predict_false(m->m_pkthdr.csum_flags & CSUM_DELAY_DATA_IPV6 &
+ ~nh->nh_ifp->if_hwassist)) {
+ u_short offset = ip6_lasthdr(m, 0, IPPROTO_IPV6, NULL);
+ if (offset < sizeof(struct ip6_hdr) || offset > m->m_pkthdr.len)
+ goto drop;
+ in6_delayed_cksum(m, m->m_pkthdr.len - offset, offset);
+ m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA_IPV6;
+ }
+
m_clrprotoflags(m); /* Avoid confusing lower layers. */
IP_PROBE(send, NULL, NULL, ip6, nh->nh_ifp, NULL, ip6);
diff --git a/sys/netinet6/ip6_forward.c b/sys/netinet6/ip6_forward.c
--- a/sys/netinet6/ip6_forward.c
+++ b/sys/netinet6/ip6_forward.c
@@ -389,6 +389,19 @@
goto bad;
}
+ /*
+ * If TCP/UDP header still needs a valid checksum and interface will not
+ * calculate it for us, do it here.
+ */
+ if (__predict_false(m->m_pkthdr.csum_flags & CSUM_DELAY_DATA_IPV6 &
+ ~nh->nh_ifp->if_hwassist)) {
+ u_short offset = ip6_lasthdr(m, 0, IPPROTO_IPV6, NULL);
+ if (offset < sizeof(struct ip6_hdr) || offset > m->m_pkthdr.len)
+ goto bad;
+ in6_delayed_cksum(m, m->m_pkthdr.len - offset, offset);
+ m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA_IPV6;
+ }
+
/* Currently LLE layer stores embedded IPv6 addresses */
if (IN6_IS_SCOPE_LINKLOCAL(&dst.sin6_addr)) {
in6_set_unicast_scopeid(&dst.sin6_addr, dst.sin6_scope_id);
diff --git a/sys/netinet6/udp6_usrreq.c b/sys/netinet6/udp6_usrreq.c
--- a/sys/netinet6/udp6_usrreq.c
+++ b/sys/netinet6/udp6_usrreq.c
@@ -429,6 +429,12 @@
uh_sum = in6_cksum_pseudo(ip6, ulen, nxt,
m->m_pkthdr.csum_data);
uh_sum ^= 0xffff;
+ } else if (m->m_pkthdr.csum_flags & CSUM_IP6_UDP) {
+ /*
+ * Packet from local host (maybe from a VM).
+ * Checksum not required.
+ */
+ uh_sum = 0;
} else
uh_sum = in6_cksum_partial(m, nxt, off, plen, ulen);
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Mon, Feb 2, 8:53 AM (2 h, 49 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
28411517
Default Alt Text
D51475.id158939.diff (6 KB)
Attached To
Mode
D51475: sctp, tcp, udp: improve deferred computation of checksums
Attached
Detach File
Event Timeline
Log In to Comment