so stop that pseudo-header wankery. v6 doesn't have it at all. instead of incrementally pre-computing a tiny part of the proto cksum, just do it in in_proto_cksum_out when needed. makes everything else in the stack super easy: need cksum? set flag, done.
stack and pf cases tested with all 3 offloading variants (none / needs-phdr / full). and if sk(4) wouldn't be such a weird beast with it's more-in-software-than-hw RX offloading in_cksum_addword could be deleted too. ok? Index: net/if_pflow.c =================================================================== RCS file: /cvs/src/sys/net/if_pflow.c,v retrieving revision 1.36 diff -u -p -r1.36 if_pflow.c --- net/if_pflow.c 17 Oct 2013 16:27:41 -0000 1.36 +++ net/if_pflow.c 18 Oct 2013 13:35:38 -0000 @@ -126,9 +126,6 @@ struct if_clone pflow_cloner = IF_CLONE_INITIALIZER("pflow", pflow_clone_create, pflow_clone_destroy); -/* from udp_usrreq.c */ -extern int udpcksum; - void pflowattach(int npflow) { @@ -1535,6 +1532,8 @@ pflow_sendout_mbuf(struct pflow_softc *s ui->ui_dst = sc->sc_receiver_ip; ui->ui_dport = sc->sc_receiver_port; ui->ui_ulen = htons(sizeof(struct udphdr) + len); + ui->ui_sum = 0; + m->m_pkthdr.csum_flags |= M_UDP_CSUM_OUT; ip = (struct ip *)ui; ip->ip_v = IPVERSION; @@ -1544,18 +1543,6 @@ pflow_sendout_mbuf(struct pflow_softc *s ip->ip_tos = IPTOS_LOWDELAY; ip->ip_ttl = IPDEFTTL; ip->ip_len = htons(sizeof(struct udpiphdr) + len); - - /* - * Compute the pseudo-header checksum; defer further checksumming - * until ip_output() or hardware (if it exists). - */ - if (udpcksum) { - m->m_pkthdr.csum_flags |= M_UDP_CSUM_OUT; - ui->ui_sum = in_cksum_phdr(ui->ui_src.s_addr, - ui->ui_dst.s_addr, htons(len + sizeof(struct udphdr) + - IPPROTO_UDP)); - } else - ui->ui_sum = 0; #if NBPFILTER > 0 if (ifp->if_bpf) { Index: net/pf.c =================================================================== RCS file: /cvs/src/sys/net/pf.c,v retrieving revision 1.844 diff -u -p -r1.844 pf.c --- net/pf.c 17 Oct 2013 16:27:41 -0000 1.844 +++ net/pf.c 18 Oct 2013 13:15:04 -0000 @@ -6742,20 +6742,10 @@ pf_cksum(struct pf_pdesc *pd, struct mbu switch (pd->proto) { case IPPROTO_TCP: pd->hdr.tcp->th_sum = 0; - if (pd->af == AF_INET) { - pd->hdr.tcp->th_sum = in_cksum_phdr(pd->src->v4.s_addr, - pd->dst->v4.s_addr, htons(pd->tot_len - - pd->off + IPPROTO_TCP)); - } m->m_pkthdr.csum_flags |= M_TCP_CSUM_OUT; break; case IPPROTO_UDP: pd->hdr.udp->uh_sum = 0; - if (pd->af == AF_INET) { - pd->hdr.udp->uh_sum = in_cksum_phdr(pd->src->v4.s_addr, - pd->dst->v4.s_addr, htons(pd->tot_len - - pd->off + IPPROTO_UDP)); - } m->m_pkthdr.csum_flags |= M_UDP_CSUM_OUT; break; case IPPROTO_ICMP: Index: net/pipex.c =================================================================== RCS file: /cvs/src/sys/net/pipex.c,v retrieving revision 1.44 diff -u -p -r1.44 pipex.c --- net/pipex.c 17 Oct 2013 16:27:43 -0000 1.44 +++ net/pipex.c 18 Oct 2013 13:34:13 -0000 @@ -1976,7 +1976,9 @@ pipex_l2tp_output(struct mbuf *m0, struc udp->uh_sport = session->local.sin6.sin6_port; udp->uh_dport = session->peer.sin6.sin6_port; udp->uh_ulen = htons(plen); + udp->uh_sum = 0; + m0->m_pkthdr.csum_flags |= M_UDP_CSUM_OUT; m0->m_pkthdr.rcvif = session->pipex_iface->ifnet_this; #if NPF > 0 pf_pkt_addr_changed(m0); @@ -1991,13 +1993,6 @@ pipex_l2tp_output(struct mbuf *m0, struc ip->ip_ttl = MAXTTL; ip->ip_tos = 0; - if (udpcksum) { - udp->uh_sum = in_cksum_phdr(ip->ip_src.s_addr, - ip->ip_dst.s_addr, htons(plen + IPPROTO_UDP)); - m0->m_pkthdr.csum_flags |= M_UDP_CSUM_OUT; - } else - udp->uh_sum = 0; - if (ip_output(m0, NULL, NULL, IP_IPSECFLOW, NULL, NULL, session->proto.l2tp.ipsecflowinfo) != 0) { PIPEX_DBG((session, LOG_DEBUG, "ip_output failed.")); @@ -2017,10 +2012,6 @@ pipex_l2tp_output(struct mbuf *m0, struc &session->peer.sin6, NULL, NULL); /* ip6->ip6_plen will be filled in ip6_output. */ - udp->uh_sum = 0; - if ((udp->uh_sum = in6_cksum(m0, IPPROTO_UDP, - sizeof(struct ip6_hdr), plen)) == 0) - udp->uh_sum = 0xffff; if (ip6_output(m0, NULL, NULL, 0, NULL, NULL, NULL) != 0) { PIPEX_DBG((session, LOG_DEBUG, "ip6_output failed.")); goto drop; Index: netinet/ip_output.c =================================================================== RCS file: /cvs/src/sys/netinet/ip_output.c,v retrieving revision 1.247 diff -u -p -r1.247 ip_output.c --- netinet/ip_output.c 18 Oct 2013 09:04:03 -0000 1.247 +++ netinet/ip_output.c 18 Oct 2013 14:24:12 -0000 @@ -2083,6 +2083,25 @@ in_delayed_cksum(struct mbuf *m) void in_proto_cksum_out(struct mbuf *m, struct ifnet *ifp) { + /* some hw and in_delayed_cksum need the pseudo header cksum */ + if (m->m_pkthdr.csum_flags & (M_TCP_CSUM_OUT|M_UDP_CSUM_OUT)) { + struct ip *ip; + u_int16_t csum, offset; + + ip = mtod(m, struct ip *); + offset = ip->ip_hl << 2; + csum = in_cksum_phdr(ip->ip_src.s_addr, ip->ip_dst.s_addr, + htonl(ntohs(ip->ip_len) - offset + ip->ip_p)); + if (ip->ip_p == IPPROTO_TCP) + offset += offsetof(struct tcphdr, th_sum); + else if (ip->ip_p == IPPROTO_UDP) + offset += offsetof(struct udphdr, uh_sum); + if ((offset + sizeof(u_int16_t)) > m->m_len) + m_copyback(m, offset, sizeof(csum), &csum, M_NOWAIT); + else + *(u_int16_t *)(mtod(m, caddr_t) + offset) = csum; + } + if (m->m_pkthdr.csum_flags & M_TCP_CSUM_OUT) { if (!ifp || !(ifp->if_capabilities & IFCAP_CSUM_TCPv4) || ifp->if_bridgeport != NULL) { Index: netinet/tcp_output.c =================================================================== RCS file: /cvs/src/sys/netinet/tcp_output.c,v retrieving revision 1.99 diff -u -p -r1.99 tcp_output.c --- netinet/tcp_output.c 12 Aug 2013 21:57:16 -0000 1.99 +++ netinet/tcp_output.c 18 Oct 2013 13:22:08 -0000 @@ -947,28 +947,8 @@ send: } #endif /* TCP_SIGNATURE */ - /* - * Put TCP length in extended header, and then - * checksum extended header and data. - */ - switch (tp->pf) { - case 0: /*default to PF_INET*/ -#ifdef INET - case AF_INET: - /* Defer checksumming until later (ip_output() or hardware) */ - m->m_pkthdr.csum_flags |= M_TCP_CSUM_OUT; - if (len + optlen) - th->th_sum = in_cksum_addword(th->th_sum, - htons((u_int16_t)(len + optlen))); - break; -#endif /* INET */ -#ifdef INET6 - case AF_INET6: - th->th_sum = in6_cksum(m, IPPROTO_TCP, sizeof(struct ip6_hdr), - hdrlen - sizeof(struct ip6_hdr) + len); - break; -#endif /* INET6 */ - } + /* Defer checksumming until later (ip_output() or hardware) */ + m->m_pkthdr.csum_flags |= M_TCP_CSUM_OUT; /* * In transmit state, time the transmission and arrange for Index: netinet/tcp_subr.c =================================================================== RCS file: /cvs/src/sys/netinet/tcp_subr.c,v retrieving revision 1.120 diff -u -p -r1.120 tcp_subr.c --- netinet/tcp_subr.c 1 Jun 2013 16:22:05 -0000 1.120 +++ netinet/tcp_subr.c 18 Oct 2013 14:45:09 -0000 @@ -257,9 +257,6 @@ tcp_template(tp) th = (struct tcphdr *)(mtod(m, caddr_t) + sizeof(struct ip)); - th->th_sum = in_cksum_phdr(ipovly->ih_src.s_addr, - ipovly->ih_dst.s_addr, - htons(sizeof (struct tcphdr) + IPPROTO_TCP)); } break; #endif /* INET */ @@ -281,7 +278,6 @@ tcp_template(tp) th = (struct tcphdr *)(mtod(m, caddr_t) + sizeof(struct ip6_hdr)); - th->th_sum = 0; } break; #endif /* INET6 */ @@ -296,6 +292,7 @@ tcp_template(tp) th->th_flags = 0; th->th_win = 0; th->th_urp = 0; + th->th_sum = 0; return (m); } Index: netinet/udp_usrreq.c =================================================================== RCS file: /cvs/src/sys/netinet/udp_usrreq.c,v retrieving revision 1.168 diff -u -p -r1.168 udp_usrreq.c --- netinet/udp_usrreq.c 17 Oct 2013 16:27:44 -0000 1.168 +++ netinet/udp_usrreq.c 18 Oct 2013 13:31:29 -0000 @@ -1077,21 +1077,11 @@ udp_output(struct mbuf *m, ...) ui->ui_sport = inp->inp_lport; ui->ui_dport = inp->inp_fport; ui->ui_ulen = ui->ui_len; - - /* - * Compute the pseudo-header checksum; defer further checksumming - * until ip_output() or hardware (if it exists). - */ - if (udpcksum) { - m->m_pkthdr.csum_flags |= M_UDP_CSUM_OUT; - ui->ui_sum = in_cksum_phdr(ui->ui_src.s_addr, - ui->ui_dst.s_addr, htons((u_int16_t)len + - sizeof (struct udphdr) + IPPROTO_UDP)); - } else - ui->ui_sum = 0; ((struct ip *)ui)->ip_len = htons(sizeof (struct udpiphdr) + len); ((struct ip *)ui)->ip_ttl = inp->inp_ip.ip_ttl; ((struct ip *)ui)->ip_tos = inp->inp_ip.ip_tos; + if (udpcksum) + m->m_pkthdr.csum_flags |= M_UDP_CSUM_OUT; udpstat.udps_opackets++;