MFp4 bz_ipv6_fast:
Add code to handle pre-checked TCP checksums as indicated by mbuf flags to save the entire computation for validation if not needed. In the IPv6 TCP output path only compute the pseudo-header checksum, set the checksum offset in the mbuf field along the appropriate flag as done in IPv4. In tcp_respond() just initialize the IPv6 payload length to 0 as ip6_output() will properly set it. Sponsored by: The FreeBSD Foundation Sponsored by: iXsystems Reviewed by: gnn (as part of the whole) MFC After: 3 days
This commit is contained in:
parent
d4b93a67d9
commit
45747ba53c
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=235961
@ -577,13 +577,31 @@ tcp_input(struct mbuf *m, int off0)
|
||||
#ifdef INET6
|
||||
if (isipv6) {
|
||||
/* IP6_EXTHDR_CHECK() is already done at tcp6_input(). */
|
||||
|
||||
if (m->m_len < (sizeof(*ip6) + sizeof(*th))) {
|
||||
m = m_pullup(m, sizeof(*ip6) + sizeof(*th));
|
||||
if (m == NULL) {
|
||||
TCPSTAT_INC(tcps_rcvshort);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ip6 = mtod(m, struct ip6_hdr *);
|
||||
th = (struct tcphdr *)((caddr_t)ip6 + off0);
|
||||
tlen = sizeof(*ip6) + ntohs(ip6->ip6_plen) - off0;
|
||||
if (in6_cksum(m, IPPROTO_TCP, off0, tlen)) {
|
||||
if (m->m_pkthdr.csum_flags & CSUM_DATA_VALID) {
|
||||
if (m->m_pkthdr.csum_flags & CSUM_PSEUDO_HDR)
|
||||
th->th_sum = m->m_pkthdr.csum_data;
|
||||
else
|
||||
th->th_sum = in6_cksum_pseudo(ip6, tlen,
|
||||
IPPROTO_TCP, m->m_pkthdr.csum_data);
|
||||
th->th_sum ^= 0xffff;
|
||||
} else
|
||||
th->th_sum = in6_cksum(m, IPPROTO_TCP, off0, tlen);
|
||||
if (th->th_sum) {
|
||||
TCPSTAT_INC(tcps_rcvbadsum);
|
||||
goto drop;
|
||||
}
|
||||
th = (struct tcphdr *)((caddr_t)ip6 + off0);
|
||||
|
||||
/*
|
||||
* Be proactive about unspecified IPv6 address in source.
|
||||
|
@ -1047,19 +1047,23 @@ tcp_output(struct tcpcb *tp)
|
||||
* checksum extended header and data.
|
||||
*/
|
||||
m->m_pkthdr.len = hdrlen + len; /* in6_cksum() need this */
|
||||
m->m_pkthdr.csum_flags = CSUM_TCP;
|
||||
m->m_pkthdr.csum_data = offsetof(struct tcphdr, th_sum);
|
||||
#ifdef INET6
|
||||
if (isipv6)
|
||||
if (isipv6) {
|
||||
/*
|
||||
* ip6_plen is not need to be filled now, and will be filled
|
||||
* in ip6_output.
|
||||
*/
|
||||
th->th_sum = in6_cksum(m, IPPROTO_TCP, sizeof(struct ip6_hdr),
|
||||
sizeof(struct tcphdr) + optlen + len);
|
||||
th->th_sum = in6_cksum_pseudo(ip6, sizeof(struct tcphdr) +
|
||||
optlen + len, IPPROTO_TCP, 0);
|
||||
}
|
||||
#endif
|
||||
#if defined(INET6) && defined(INET)
|
||||
else
|
||||
#endif /* INET6 */
|
||||
#endif
|
||||
#ifdef INET
|
||||
{
|
||||
m->m_pkthdr.csum_flags = CSUM_TCP;
|
||||
m->m_pkthdr.csum_data = offsetof(struct tcphdr, th_sum);
|
||||
th->th_sum = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr,
|
||||
htons(sizeof(struct tcphdr) + IPPROTO_TCP + len + optlen));
|
||||
|
||||
@ -1067,6 +1071,7 @@ tcp_output(struct tcpcb *tp)
|
||||
KASSERT(ip->ip_v == IPVERSION,
|
||||
("%s: IP version incorrect: %d", __func__, ip->ip_v));
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Enable TSO and specify the size of the segments.
|
||||
|
@ -573,8 +573,7 @@ tcp_respond(struct tcpcb *tp, void *ipgen, struct tcphdr *th, struct mbuf *m,
|
||||
ip6->ip6_flow = 0;
|
||||
ip6->ip6_vfc = IPV6_VERSION;
|
||||
ip6->ip6_nxt = IPPROTO_TCP;
|
||||
ip6->ip6_plen = htons((u_short)(sizeof (struct tcphdr) +
|
||||
tlen));
|
||||
ip6->ip6_plen = 0; /* Set in ip6_output(). */
|
||||
tlen += sizeof (struct ip6_hdr) + sizeof (struct tcphdr);
|
||||
}
|
||||
#endif
|
||||
@ -619,12 +618,13 @@ tcp_respond(struct tcpcb *tp, void *ipgen, struct tcphdr *th, struct mbuf *m,
|
||||
else
|
||||
nth->th_win = htons((u_short)win);
|
||||
nth->th_urp = 0;
|
||||
|
||||
m->m_pkthdr.csum_flags = CSUM_TCP;
|
||||
m->m_pkthdr.csum_data = offsetof(struct tcphdr, th_sum);
|
||||
#ifdef INET6
|
||||
if (isipv6) {
|
||||
nth->th_sum = 0;
|
||||
nth->th_sum = in6_cksum(m, IPPROTO_TCP,
|
||||
sizeof(struct ip6_hdr),
|
||||
tlen - sizeof(struct ip6_hdr));
|
||||
nth->th_sum = in6_cksum_pseudo(ip6,
|
||||
tlen - sizeof(struct ip6_hdr), IPPROTO_TCP, 0);
|
||||
ip6->ip6_hlim = in6_selecthlim(tp != NULL ? tp->t_inpcb :
|
||||
NULL, NULL);
|
||||
}
|
||||
@ -636,8 +636,6 @@ tcp_respond(struct tcpcb *tp, void *ipgen, struct tcphdr *th, struct mbuf *m,
|
||||
{
|
||||
nth->th_sum = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr,
|
||||
htons((u_short)(tlen - sizeof(struct ip) + ip->ip_p)));
|
||||
m->m_pkthdr.csum_flags = CSUM_TCP;
|
||||
m->m_pkthdr.csum_data = offsetof(struct tcphdr, th_sum);
|
||||
}
|
||||
#endif /* INET */
|
||||
#ifdef TCPDEBUG
|
||||
|
@ -1473,11 +1473,12 @@ syncache_respond(struct syncache *sc)
|
||||
optlen = 0;
|
||||
|
||||
M_SETFIB(m, sc->sc_inc.inc_fibnum);
|
||||
m->m_pkthdr.csum_flags = CSUM_TCP;
|
||||
m->m_pkthdr.csum_data = offsetof(struct tcphdr, th_sum);
|
||||
#ifdef INET6
|
||||
if (sc->sc_inc.inc_flags & INC_ISIPV6) {
|
||||
th->th_sum = 0;
|
||||
th->th_sum = in6_cksum(m, IPPROTO_TCP, hlen,
|
||||
tlen + optlen - hlen);
|
||||
th->th_sum = in6_cksum_pseudo(ip6, tlen + optlen - hlen,
|
||||
IPPROTO_TCP, 0);
|
||||
ip6->ip6_hlim = in6_selecthlim(NULL, NULL);
|
||||
error = ip6_output(m, NULL, NULL, 0, NULL, NULL, NULL);
|
||||
}
|
||||
@ -1489,8 +1490,6 @@ syncache_respond(struct syncache *sc)
|
||||
{
|
||||
th->th_sum = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr,
|
||||
htons(tlen + optlen - hlen + IPPROTO_TCP));
|
||||
m->m_pkthdr.csum_flags = CSUM_TCP;
|
||||
m->m_pkthdr.csum_data = offsetof(struct tcphdr, th_sum);
|
||||
error = ip_output(m, sc->sc_ipopts, NULL, 0, NULL, NULL);
|
||||
}
|
||||
#endif
|
||||
|
@ -574,10 +574,12 @@ tcp_twrespond(struct tcptw *tw, int flags)
|
||||
th->th_flags = flags;
|
||||
th->th_win = htons(tw->last_win);
|
||||
|
||||
m->m_pkthdr.csum_flags = CSUM_TCP;
|
||||
m->m_pkthdr.csum_data = offsetof(struct tcphdr, th_sum);
|
||||
#ifdef INET6
|
||||
if (isipv6) {
|
||||
th->th_sum = in6_cksum(m, IPPROTO_TCP, sizeof(struct ip6_hdr),
|
||||
sizeof(struct tcphdr) + optlen);
|
||||
th->th_sum = in6_cksum_pseudo(ip6,
|
||||
sizeof(struct tcphdr) + optlen, IPPROTO_TCP, 0);
|
||||
ip6->ip6_hlim = in6_selecthlim(inp, NULL);
|
||||
error = ip6_output(m, inp->in6p_outputopts, NULL,
|
||||
(tw->tw_so_options & SO_DONTROUTE), NULL, NULL, inp);
|
||||
@ -590,8 +592,6 @@ tcp_twrespond(struct tcptw *tw, int flags)
|
||||
{
|
||||
th->th_sum = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr,
|
||||
htons(sizeof(struct tcphdr) + optlen + IPPROTO_TCP));
|
||||
m->m_pkthdr.csum_flags = CSUM_TCP;
|
||||
m->m_pkthdr.csum_data = offsetof(struct tcphdr, th_sum);
|
||||
ip->ip_len = m->m_pkthdr.len;
|
||||
if (V_path_mtu_discovery)
|
||||
ip->ip_off |= IP_DF;
|
||||
|
Loading…
Reference in New Issue
Block a user