Changeset View
Standalone View
sys/net/iflib.c
Show First 20 Lines • Show All 2,816 Lines • ▼ Show 20 Lines | print_pkt(if_pkt_info_t pi) | ||||
printf("pi new_pidx: %d csum_flags: %lx tso_segsz: %d mflags: %x vtag: %d\n", | printf("pi new_pidx: %d csum_flags: %lx tso_segsz: %d mflags: %x vtag: %d\n", | ||||
pi->ipi_new_pidx, pi->ipi_csum_flags, pi->ipi_tso_segsz, pi->ipi_mflags, pi->ipi_vtag); | pi->ipi_new_pidx, pi->ipi_csum_flags, pi->ipi_tso_segsz, pi->ipi_mflags, pi->ipi_vtag); | ||||
printf("pi etype: %d ehdrlen: %d ip_hlen: %d ipproto: %d\n", | printf("pi etype: %d ehdrlen: %d ip_hlen: %d ipproto: %d\n", | ||||
pi->ipi_etype, pi->ipi_ehdrlen, pi->ipi_ip_hlen, pi->ipi_ipproto); | pi->ipi_etype, pi->ipi_ehdrlen, pi->ipi_ip_hlen, pi->ipi_ipproto); | ||||
} | } | ||||
#endif | #endif | ||||
#define IS_TSO4(pi) ((pi)->ipi_csum_flags & CSUM_IP_TSO) | #define IS_TSO4(pi) ((pi)->ipi_csum_flags & CSUM_IP_TSO) | ||||
#define IS_TX_OFFLOAD4(pi) ((pi)->ipi_csum_flags & (CSUM_IP_TCP | CSUM_IP_TSO)) | |||||
#define IS_TSO6(pi) ((pi)->ipi_csum_flags & CSUM_IP6_TSO) | #define IS_TSO6(pi) ((pi)->ipi_csum_flags & CSUM_IP6_TSO) | ||||
#define IS_TX_OFFLOAD6(pi) ((pi)->ipi_csum_flags & (CSUM_IP6_TCP | CSUM_IP6_TSO)) | |||||
static int | static int | ||||
iflib_parse_header(iflib_txq_t txq, if_pkt_info_t pi, struct mbuf **mp) | iflib_parse_header(iflib_txq_t txq, if_pkt_info_t pi, struct mbuf **mp) | ||||
{ | { | ||||
if_shared_ctx_t sctx = txq->ift_ctx->ifc_sctx; | if_shared_ctx_t sctx = txq->ift_ctx->ifc_sctx; | ||||
struct ether_vlan_header *eh; | struct ether_vlan_header *eh; | ||||
struct mbuf *m, *n; | struct mbuf *m, *n; | ||||
▲ Show 20 Lines • Show All 69 Lines • ▼ Show 20 Lines | case ETHERTYPE_IP: | ||||
} | } | ||||
pi->ipi_ip_hlen = ip->ip_hl << 2; | pi->ipi_ip_hlen = ip->ip_hl << 2; | ||||
pi->ipi_ipproto = ip->ip_p; | pi->ipi_ipproto = ip->ip_p; | ||||
pi->ipi_flags |= IPI_TX_IPV4; | pi->ipi_flags |= IPI_TX_IPV4; | ||||
if ((sctx->isc_flags & IFLIB_NEED_ZERO_CSUM) && (pi->ipi_csum_flags & CSUM_IP)) | if ((sctx->isc_flags & IFLIB_NEED_ZERO_CSUM) && (pi->ipi_csum_flags & CSUM_IP)) | ||||
ip->ip_sum = 0; | ip->ip_sum = 0; | ||||
if (IS_TSO4(pi)) { | /* TCP checksum offload may require TCP header length */ | ||||
if (pi->ipi_ipproto == IPPROTO_TCP) { | if (IS_TX_OFFLOAD4(pi)) { | ||||
if (__predict_true(pi->ipi_ipproto == IPPROTO_TCP)) { | |||||
shurd: Non-TCP TSO won't need the tcp header and sequence number information though. The IS_TSO4()… | |||||
Not Done Inline ActionsI think my comment there was really asking if iflib is supposed to support non-TCP TSO. Does FreeBSD mean TSO to be "TCP segmentation offload" like in the ifconfig(8) man page, or "Transmit segmentation offload" like in the Intel datasheets? erj: I think my comment there was really asking if iflib is supposed to support non-TCP TSO.
Does… | |||||
Not Done Inline ActionsFreeBSD does not support anything but TCP TSO. So checking for IPPROTO_TCP is redundant, and can be skipped. gallatin: FreeBSD does not support anything but TCP TSO. So checking for IPPROTO_TCP is redundant, and… | |||||
Not Done Inline ActionsI don't want to remove it in this patch because I think it's outside the scope I wanted for it. Maybe the entire function needs a revisit / documenting. erj: I don't want to remove it in this patch because I think it's outside the scope I wanted for it. | |||||
if (__predict_false(th == NULL)) { | if (__predict_false(th == NULL)) { | ||||
txq->ift_pullups++; | txq->ift_pullups++; | ||||
if (__predict_false((m = m_pullup(m, (ip->ip_hl << 2) + sizeof(*th))) == NULL)) | if (__predict_false((m = m_pullup(m, (ip->ip_hl << 2) + sizeof(*th))) == NULL)) | ||||
return (ENOMEM); | return (ENOMEM); | ||||
th = (struct tcphdr *)((caddr_t)ip + pi->ipi_ip_hlen); | th = (struct tcphdr *)((caddr_t)ip + pi->ipi_ip_hlen); | ||||
} | } | ||||
pi->ipi_tcp_hflags = th->th_flags; | pi->ipi_tcp_hflags = th->th_flags; | ||||
pi->ipi_tcp_hlen = th->th_off << 2; | pi->ipi_tcp_hlen = th->th_off << 2; | ||||
pi->ipi_tcp_seq = th->th_seq; | pi->ipi_tcp_seq = th->th_seq; | ||||
} | } | ||||
if (IS_TSO4(pi)) { | |||||
if (__predict_false(ip->ip_p != IPPROTO_TCP)) | if (__predict_false(ip->ip_p != IPPROTO_TCP)) | ||||
return (ENXIO); | return (ENXIO); | ||||
th->th_sum = in_pseudo(ip->ip_src.s_addr, | th->th_sum = in_pseudo(ip->ip_src.s_addr, | ||||
ip->ip_dst.s_addr, htons(IPPROTO_TCP)); | ip->ip_dst.s_addr, htons(IPPROTO_TCP)); | ||||
pi->ipi_tso_segsz = m->m_pkthdr.tso_segsz; | pi->ipi_tso_segsz = m->m_pkthdr.tso_segsz; | ||||
if (sctx->isc_flags & IFLIB_TSO_INIT_IP) { | if (sctx->isc_flags & IFLIB_TSO_INIT_IP) { | ||||
ip->ip_sum = 0; | ip->ip_sum = 0; | ||||
ip->ip_len = htons(pi->ipi_ip_hlen + pi->ipi_tcp_hlen + pi->ipi_tso_segsz); | ip->ip_len = htons(pi->ipi_ip_hlen + pi->ipi_tcp_hlen + pi->ipi_tso_segsz); | ||||
} | } | ||||
} | } | ||||
} | |||||
break; | break; | ||||
} | } | ||||
#endif | #endif | ||||
#ifdef INET6 | #ifdef INET6 | ||||
case ETHERTYPE_IPV6: | case ETHERTYPE_IPV6: | ||||
{ | { | ||||
struct ip6_hdr *ip6 = (struct ip6_hdr *)(m->m_data + pi->ipi_ehdrlen); | struct ip6_hdr *ip6 = (struct ip6_hdr *)(m->m_data + pi->ipi_ehdrlen); | ||||
struct tcphdr *th; | struct tcphdr *th; | ||||
pi->ipi_ip_hlen = sizeof(struct ip6_hdr); | pi->ipi_ip_hlen = sizeof(struct ip6_hdr); | ||||
if (__predict_false(m->m_len < pi->ipi_ehdrlen + sizeof(struct ip6_hdr))) { | if (__predict_false(m->m_len < pi->ipi_ehdrlen + sizeof(struct ip6_hdr))) { | ||||
if (__predict_false((m = m_pullup(m, pi->ipi_ehdrlen + sizeof(struct ip6_hdr))) == NULL)) | if (__predict_false((m = m_pullup(m, pi->ipi_ehdrlen + sizeof(struct ip6_hdr))) == NULL)) | ||||
return (ENOMEM); | return (ENOMEM); | ||||
} | } | ||||
th = (struct tcphdr *)((caddr_t)ip6 + pi->ipi_ip_hlen); | th = (struct tcphdr *)((caddr_t)ip6 + pi->ipi_ip_hlen); | ||||
/* XXX-BZ this will go badly in case of ext hdrs. */ | /* XXX-BZ this will go badly in case of ext hdrs. */ | ||||
pi->ipi_ipproto = ip6->ip6_nxt; | pi->ipi_ipproto = ip6->ip6_nxt; | ||||
pi->ipi_flags |= IPI_TX_IPV6; | pi->ipi_flags |= IPI_TX_IPV6; | ||||
if (IS_TSO6(pi)) { | /* TCP checksum offload may require TCP header length */ | ||||
if (IS_TX_OFFLOAD6(pi)) { | |||||
if (pi->ipi_ipproto == IPPROTO_TCP) { | if (pi->ipi_ipproto == IPPROTO_TCP) { | ||||
if (__predict_false(m->m_len < pi->ipi_ehdrlen + sizeof(struct ip6_hdr) + sizeof(struct tcphdr))) { | if (__predict_false(m->m_len < pi->ipi_ehdrlen + sizeof(struct ip6_hdr) + sizeof(struct tcphdr))) { | ||||
txq->ift_pullups++; | |||||
if (__predict_false((m = m_pullup(m, pi->ipi_ehdrlen + sizeof(struct ip6_hdr) + sizeof(struct tcphdr))) == NULL)) | if (__predict_false((m = m_pullup(m, pi->ipi_ehdrlen + sizeof(struct ip6_hdr) + sizeof(struct tcphdr))) == NULL)) | ||||
return (ENOMEM); | return (ENOMEM); | ||||
} | } | ||||
pi->ipi_tcp_hflags = th->th_flags; | pi->ipi_tcp_hflags = th->th_flags; | ||||
pi->ipi_tcp_hlen = th->th_off << 2; | pi->ipi_tcp_hlen = th->th_off << 2; | ||||
pi->ipi_tcp_seq = th->th_seq; | |||||
} | } | ||||
if (IS_TSO6(pi)) { | |||||
if (__predict_false(ip6->ip6_nxt != IPPROTO_TCP)) | if (__predict_false(ip6->ip6_nxt != IPPROTO_TCP)) | ||||
return (ENXIO); | return (ENXIO); | ||||
/* | /* | ||||
* The corresponding flag is set by the stack in the IPv4 | * The corresponding flag is set by the stack in the IPv4 | ||||
* TSO case, but not in IPv6 (at least in FreeBSD 10.2). | * TSO case, but not in IPv6 (at least in FreeBSD 10.2). | ||||
* So, set it here because the rest of the flow requires it. | * So, set it here because the rest of the flow requires it. | ||||
*/ | */ | ||||
pi->ipi_csum_flags |= CSUM_TCP_IPV6; | pi->ipi_csum_flags |= CSUM_IP6_TCP; | ||||
th->th_sum = in6_cksum_pseudo(ip6, 0, IPPROTO_TCP, 0); | th->th_sum = in6_cksum_pseudo(ip6, 0, IPPROTO_TCP, 0); | ||||
pi->ipi_tso_segsz = m->m_pkthdr.tso_segsz; | pi->ipi_tso_segsz = m->m_pkthdr.tso_segsz; | ||||
} | |||||
} | } | ||||
Done Inline ActionsDid you confirm that the CSUM_TCP_IPV6 csum flag *is* set on -current? Not forcing CSUM_TCP_IPV6 seems like a significant change here. I'll take a look at what "the rest of the flow requires it" means in this context. shurd: Did you confirm that the CSUM_TCP_IPV6 csum flag *is* set on -current? Not forcing… | |||||
Not Done Inline ActionsErr, looking at this again, I shouldn't have reverted it. I think yesterday I read the flag as being TSO instead of TCP and agreed that it was redundant. erj: Err, looking at this again, I shouldn't have reverted it. I think yesterday I read the flag as… | |||||
Not Done Inline ActionsAnd setting it is safe, because you've already nuked the checksum that would have been there if it had not been set. Speaking of that.. It would be nice if FreeBSD handled TSO pseudo hdr checksums based on a length of 0 like windows, since that's what most ASICs want. At Myricom, we had a special mode in the NIC to handle linux/freebsd TSO where we subtracted out the len from the csum we were passed, but most NICs don't have that. I suppose a change like that might be too disruptive, but it would allow cleaning up a ton of places where drivers call in*_cksum_pseudo() to get the checksum in the form they want. gallatin: And setting it is safe, because you've already nuked the checksum that would have been there if… | |||||
break; | break; | ||||
} | } | ||||
#endif | #endif | ||||
default: | default: | ||||
pi->ipi_csum_flags &= ~CSUM_OFFLOAD; | pi->ipi_csum_flags &= ~CSUM_OFFLOAD; | ||||
pi->ipi_ip_hlen = 0; | pi->ipi_ip_hlen = 0; | ||||
break; | break; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 3,440 Lines • Show Last 20 Lines |
Non-TCP TSO won't need the tcp header and sequence number information though. The IS_TSO4() block below fills in the generic information.