From 26fd91ce0ecf723387ff488d6ddb3edfce44186e Mon Sep 17 00:00:00 2001 From: jan Date: Mon, 6 Feb 2023 20:27:44 +0000 Subject: [PATCH] consolidate mbuf header parsing on device driver layer with tweaks from mvs@, mpi@, dlg@, naddy@ and bluhm@ "go for it" deraadt@ ok naddy@, mvs@ --- sys/dev/pci/if_ix.c | 47 +++++++--------------------- sys/dev/pci/if_ixl.c | 62 ++++++++----------------------------- sys/net/if_ethersubr.c | 69 +++++++++++++++++++++++++++++++++++++++++- sys/netinet/if_ether.h | 14 ++++++++- 4 files changed, 104 insertions(+), 88 deletions(-) diff --git a/sys/dev/pci/if_ix.c b/sys/dev/pci/if_ix.c index 32e0c601eb5..ab9edd51023 100644 --- a/sys/dev/pci/if_ix.c +++ b/sys/dev/pci/if_ix.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_ix.c,v 1.191 2023/01/26 07:32:39 deraadt Exp $ */ +/* $OpenBSD: if_ix.c,v 1.192 2023/02/06 20:27:44 jan Exp $ */ /****************************************************************************** @@ -2477,25 +2477,16 @@ static inline int ixgbe_csum_offload(struct mbuf *mp, uint32_t *vlan_macip_lens, uint32_t *type_tucmd_mlhl, uint32_t *olinfo_status) { - struct ether_header *eh = mtod(mp, struct ether_header *); - struct mbuf *m; - int hoff; + struct ether_extracted ext; int offload = 0; uint32_t iphlen; - uint8_t ipproto; - *vlan_macip_lens |= (sizeof(*eh) << IXGBE_ADVTXD_MACLEN_SHIFT); + ether_extract_headers(mp, &ext); - switch (ntohs(eh->ether_type)) { - case ETHERTYPE_IP: { - struct ip *ip; + *vlan_macip_lens |= (sizeof(*ext.eh) << IXGBE_ADVTXD_MACLEN_SHIFT); - m = m_getptr(mp, sizeof(*eh), &hoff); - KASSERT(m != NULL && m->m_len - hoff >= sizeof(*ip)); - ip = (struct ip *)(mtod(m, caddr_t) + hoff); - - iphlen = ip->ip_hl << 2; - ipproto = ip->ip_p; + if (ext.ip4) { + iphlen = ext.ip4->ip_hl << 2; if (ISSET(mp->m_pkthdr.csum_flags, M_IPV4_CSUM_OUT)) { *olinfo_status |= IXGBE_TXD_POPTS_IXSM << 8; @@ -2503,46 +2494,30 @@ ixgbe_csum_offload(struct mbuf *mp, uint32_t *vlan_macip_lens, } *type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_IPV4; - break; - } - #ifdef INET6 - case ETHERTYPE_IPV6: { - struct ip6_hdr *ip6; - - m = m_getptr(mp, sizeof(*eh), &hoff); - KASSERT(m != NULL && m->m_len - hoff >= sizeof(*ip6)); - ip6 = (struct ip6_hdr *)(mtod(m, caddr_t) + hoff); - - iphlen = sizeof(*ip6); - ipproto = ip6->ip6_nxt; + } else if (ext.ip6) { + iphlen = sizeof(*ext.ip6); *type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_IPV6; - break; - } #endif - - default: + } else { return offload; } *vlan_macip_lens |= iphlen; - switch (ipproto) { - case IPPROTO_TCP: + if (ext.tcp) { *type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_L4T_TCP; if (ISSET(mp->m_pkthdr.csum_flags, M_TCP_CSUM_OUT)) { *olinfo_status |= IXGBE_TXD_POPTS_TXSM << 8; offload = 1; } - break; - case IPPROTO_UDP: + } else if (ext.udp) { *type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_L4T_UDP; if (ISSET(mp->m_pkthdr.csum_flags, M_UDP_CSUM_OUT)) { *olinfo_status |= IXGBE_TXD_POPTS_TXSM << 8; offload = 1; } - break; } return offload; diff --git a/sys/dev/pci/if_ixl.c b/sys/dev/pci/if_ixl.c index c565f70e689..3aa9c226c57 100644 --- a/sys/dev/pci/if_ixl.c +++ b/sys/dev/pci/if_ixl.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_ixl.c,v 1.86 2023/01/26 07:32:39 deraadt Exp $ */ +/* $OpenBSD: if_ixl.c,v 1.87 2023/02/06 20:27:45 jan Exp $ */ /* * Copyright (c) 2013-2015, Intel Corporation @@ -2784,10 +2784,8 @@ ixl_load_mbuf(bus_dma_tag_t dmat, bus_dmamap_t map, struct mbuf *m) static uint64_t ixl_tx_setup_offload(struct mbuf *m0) { - struct mbuf *m; - int hoff; + struct ether_extracted ext; uint64_t hlen; - uint8_t ipproto; uint64_t offload = 0; if (ISSET(m0->m_flags, M_VLANTAG)) { @@ -2800,39 +2798,21 @@ ixl_tx_setup_offload(struct mbuf *m0) M_IPV4_CSUM_OUT|M_TCP_CSUM_OUT|M_UDP_CSUM_OUT)) return (offload); - switch (ntohs(mtod(m0, struct ether_header *)->ether_type)) { - case ETHERTYPE_IP: { - struct ip *ip; - - m = m_getptr(m0, ETHER_HDR_LEN, &hoff); - KASSERT(m != NULL && m->m_len - hoff >= sizeof(*ip)); - ip = (struct ip *)(mtod(m, caddr_t) + hoff); + ether_extract_headers(m0, &ext); + if (ext.ip4) { offload |= ISSET(m0->m_pkthdr.csum_flags, M_IPV4_CSUM_OUT) ? IXL_TX_DESC_CMD_IIPT_IPV4_CSUM : IXL_TX_DESC_CMD_IIPT_IPV4; - hlen = ip->ip_hl << 2; - ipproto = ip->ip_p; - break; - } - + hlen = ext.ip4->ip_hl << 2; #ifdef INET6 - case ETHERTYPE_IPV6: { - struct ip6_hdr *ip6; - - m = m_getptr(m0, ETHER_HDR_LEN, &hoff); - KASSERT(m != NULL && m->m_len - hoff >= sizeof(*ip6)); - ip6 = (struct ip6_hdr *)(mtod(m, caddr_t) + hoff); - + } else if (ext.ip6) { offload |= IXL_TX_DESC_CMD_IIPT_IPV6; - hlen = sizeof(*ip6); - ipproto = ip6->ip6_nxt; - break; - } + hlen = sizeof(*ext.ip6); #endif - default: + } else { panic("CSUM_OUT set for non-IP packet"); /* NOTREACHED */ } @@ -2840,30 +2820,12 @@ ixl_tx_setup_offload(struct mbuf *m0) offload |= (ETHER_HDR_LEN >> 1) << IXL_TX_DESC_MACLEN_SHIFT; offload |= (hlen >> 2) << IXL_TX_DESC_IPLEN_SHIFT; - switch (ipproto) { - case IPPROTO_TCP: { - struct tcphdr *th; - - if (!ISSET(m0->m_pkthdr.csum_flags, M_TCP_CSUM_OUT)) - break; - - m = m_getptr(m, hoff + hlen, &hoff); - KASSERT(m != NULL && m->m_len - hoff >= sizeof(*th)); - th = (struct tcphdr *)(mtod(m, caddr_t) + hoff); - + if (ext.tcp && ISSET(m0->m_pkthdr.csum_flags, M_TCP_CSUM_OUT)) { offload |= IXL_TX_DESC_CMD_L4T_EOFT_TCP; - offload |= (uint64_t)th->th_off << IXL_TX_DESC_L4LEN_SHIFT; - break; - } - - case IPPROTO_UDP: - if (!ISSET(m0->m_pkthdr.csum_flags, M_UDP_CSUM_OUT)) - break; - + offload |= (uint64_t)ext.tcp->th_off << IXL_TX_DESC_L4LEN_SHIFT; + } else if (ext.udp && ISSET(m0->m_pkthdr.csum_flags, M_UDP_CSUM_OUT)) { offload |= IXL_TX_DESC_CMD_L4T_EOFT_UDP; - offload |= (sizeof(struct udphdr) >> 2) << - IXL_TX_DESC_L4LEN_SHIFT; - break; + offload |= (sizeof(*ext.udp) >> 2) << IXL_TX_DESC_L4LEN_SHIFT; } return (offload); diff --git a/sys/net/if_ethersubr.c b/sys/net/if_ethersubr.c index c0c2187647b..ec826664177 100644 --- a/sys/net/if_ethersubr.c +++ b/sys/net/if_ethersubr.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_ethersubr.c,v 1.286 2023/01/26 07:32:40 deraadt Exp $ */ +/* $OpenBSD: if_ethersubr.c,v 1.287 2023/02/06 20:27:45 jan Exp $ */ /* $NetBSD: if_ethersubr.c,v 1.19 1996/05/07 02:40:30 thorpej Exp $ */ /* @@ -98,6 +98,10 @@ didn't get a copy, you may request one from . #include #include #include +#include +#include +#include +#include #if NBPFILTER > 0 #include @@ -1034,3 +1038,66 @@ ether_e64_to_addr(struct ether_addr *ea, uint64_t e64) e64 >>= 8; } while (i > 0); } + +/* Parse different TCP/IP protocol headers for a quick view inside an mbuf. */ +void +ether_extract_headers(struct mbuf *mp, struct ether_extracted *ext) +{ + struct mbuf *m; + uint64_t hlen; + int hoff; + uint8_t ipproto; + + /* Return NULL if header was not recognized. */ + memset(ext, 0, sizeof(*ext)); + + if (mp->m_len < sizeof(*ext->eh)) + return; + + ext->eh = mtod(mp, struct ether_header *); + switch (ntohs(ext->eh->ether_type)) { + case ETHERTYPE_IP: + m = m_getptr(mp, sizeof(*ext->eh), &hoff); + if (m == NULL || m->m_len - hoff < sizeof(*ext->ip4)) + return; + ext->ip4 = (struct ip *)(mtod(m, caddr_t) + hoff); + + if (ISSET(ntohs(ext->ip4->ip_off), IP_MF|IP_OFFMASK)) + return; + + hlen = ext->ip4->ip_hl << 2; + ipproto = ext->ip4->ip_p; + + break; +#ifdef INET6 + case ETHERTYPE_IPV6: + m = m_getptr(mp, sizeof(*ext->eh), &hoff); + if (m == NULL || m->m_len - hoff < sizeof(*ext->ip6)) + return; + ext->ip6 = (struct ip6_hdr *)(mtod(m, caddr_t) + hoff); + + hlen = sizeof(*ext->ip6); + ipproto = ext->ip6->ip6_nxt; + + break; +#endif + default: + return; + } + + switch (ipproto) { + case IPPROTO_TCP: + m = m_getptr(m, hoff + hlen, &hoff); + if (m == NULL || m->m_len - hoff < sizeof(*ext->tcp)) + return; + ext->tcp = (struct tcphdr *)(mtod(m, caddr_t) + hoff); + break; + + case IPPROTO_UDP: + m = m_getptr(m, hoff + hlen, &hoff); + if (m == NULL || m->m_len - hoff < sizeof(*ext->udp)) + return; + ext->udp = (struct udphdr *)(mtod(m, caddr_t) + hoff); + break; + } +} diff --git a/sys/netinet/if_ether.h b/sys/netinet/if_ether.h index 4758b38bdc8..5adc39e8967 100644 --- a/sys/netinet/if_ether.h +++ b/sys/netinet/if_ether.h @@ -1,4 +1,4 @@ -/* $OpenBSD: if_ether.h,v 1.86 2023/01/26 07:32:40 deraadt Exp $ */ +/* $OpenBSD: if_ether.h,v 1.87 2023/02/06 20:27:45 jan Exp $ */ /* $NetBSD: if_ether.h,v 1.22 1996/05/11 13:00:00 mycroft Exp $ */ /* @@ -297,6 +297,18 @@ const struct ether_brport * uint64_t ether_addr_to_e64(const struct ether_addr *); void ether_e64_to_addr(struct ether_addr *, uint64_t); +struct ether_extracted { + struct ether_header *eh; + struct ip *ip4; +#ifdef INET6 + struct ip6_hdr *ip6; +#endif + struct tcphdr *tcp; + struct udphdr *udp; +}; + +void ether_extract_headers(struct mbuf *, struct ether_extracted *); + /* * Ethernet multicast address structure. There is one of these for each * multicast address or range of multicast addresses that we are supposed -- 2.20.1