Hi, we have several drivers which have to parse the content of mbufs. This diff suggest a central parsing function for this. Thus, we can reduce redundant code.
I just start with ix(4) and ixl(4) because it was easy to test for me. But, this could also improve em(4), igc(4), ale(4) and oce(4). I'm not sure about the name, the api nor the place of this code. So, if someone has a better idea: i'm open to anything. bye, Jan Index: dev/pci/if_ix.c =================================================================== RCS file: /cvs/src/sys/dev/pci/if_ix.c,v retrieving revision 1.189 diff -u -p -r1.189 if_ix.c --- dev/pci/if_ix.c 2 Sep 2022 14:08:09 -0000 1.189 +++ dev/pci/if_ix.c 17 Jan 2023 16:31:19 -0000 @@ -2477,23 +2477,18 @@ 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_header *eh = NULL; + struct ip *ip = NULL; + struct ip6_hdr *ip6 = NULL; int offload = 0; uint32_t iphlen; uint8_t ipproto; - *vlan_macip_lens |= (sizeof(*eh) << IXGBE_ADVTXD_MACLEN_SHIFT); + if_parse(mp, &eh, &ip, &ip6, NULL, NULL); - switch (ntohs(eh->ether_type)) { - case ETHERTYPE_IP: { - struct ip *ip; - - m = m_getptr(mp, sizeof(*eh), &hoff); - KASSERT(m != NULL && m->m_len - hoff >= sizeof(*ip)); - ip = (struct ip *)(mtod(m, caddr_t) + hoff); + *vlan_macip_lens |= (sizeof(*eh) << IXGBE_ADVTXD_MACLEN_SHIFT); + if (ip) { iphlen = ip->ip_hl << 2; ipproto = ip->ip_p; @@ -2503,26 +2498,14 @@ ixgbe_csum_offload(struct mbuf *mp, uint } *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); - + } else if (ip6) { iphlen = sizeof(*ip6); ipproto = ip6->ip6_nxt; *type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_IPV6; - break; - } #endif - - default: + } else { return offload; } Index: dev/pci/if_ixl.c =================================================================== RCS file: /cvs/src/sys/dev/pci/if_ixl.c,v retrieving revision 1.84 diff -u -p -r1.84 if_ixl.c --- dev/pci/if_ixl.c 5 Aug 2022 13:57:16 -0000 1.84 +++ dev/pci/if_ixl.c 16 Jan 2023 23:58:05 -0000 @@ -2784,12 +2784,15 @@ ixl_load_mbuf(bus_dma_tag_t dmat, bus_dm static uint64_t ixl_tx_setup_offload(struct mbuf *m0) { - struct mbuf *m; - int hoff; + struct ether_header *eh = NULL; + struct ip *ip = NULL; + struct ip6_hdr *ip6 = NULL; + struct tcphdr *th = NULL; uint64_t hlen; uint8_t ipproto; uint64_t offload = 0; + if (ISSET(m0->m_flags, M_VLANTAG)) { uint64_t vtag = m0->m_pkthdr.ether_vtag; offload |= IXL_TX_DESC_CMD_IL2TAG1; @@ -2800,39 +2803,23 @@ 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); + if_parse(m0, &eh, &ip, &ip6, &th, NULL); + if (ip) { 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; - } - #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 (ip6) { offload |= IXL_TX_DESC_CMD_IIPT_IPV6; hlen = sizeof(*ip6); ipproto = ip6->ip6_nxt; - break; - } #endif - default: + } else { panic("CSUM_OUT set for non-IP packet"); /* NOTREACHED */ } @@ -2842,15 +2829,12 @@ ixl_tx_setup_offload(struct mbuf *m0) 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 (th == NULL) + break; + offload |= IXL_TX_DESC_CMD_L4T_EOFT_TCP; offload |= (uint64_t)th->th_off << IXL_TX_DESC_L4LEN_SHIFT; break; Index: net/if.c =================================================================== RCS file: /cvs/src/sys/net/if.c,v retrieving revision 1.683 diff -u -p -r1.683 if.c --- net/if.c 23 Nov 2022 16:57:37 -0000 1.683 +++ net/if.c 16 Jan 2023 23:20:21 -0000 @@ -96,6 +96,10 @@ #include <net/netisr.h> #include <netinet/in.h> +#include <netinet/ip.h> +#include <netinet/ip6.h> +#include <netinet/tcp.h> +#include <netinet/udp.h> #include <netinet/if_ether.h> #include <netinet/igmp.h> #ifdef MROUTING @@ -3352,6 +3356,75 @@ if_rxr_ioctl(struct if_rxrinfo *ifri, co ifr.ifr_info = *rxr; return (if_rxr_info_ioctl(ifri, 1, &ifr)); +} + +void +if_parse(struct mbuf *mp, struct ether_header **eh, struct ip **ip4, + struct ip6_hdr **ip6, struct tcphdr **tcp, struct udphdr **udp) +{ + struct mbuf *m; + int hoff; + uint8_t ipproto; + uint64_t hlen; + + if (eh == NULL) + return; + + *eh = mtod(mp, struct ether_header *); + switch (ntohs((*eh)->ether_type)) { + case ETHERTYPE_IP: + if (ip4 == NULL) + return; + + m = m_getptr(mp, sizeof(**eh), &hoff); + KASSERT(m != NULL && m->m_len - hoff >= sizeof(**ip4)); + *ip4 = (struct ip *)(mtod(m, caddr_t) + hoff); + + hlen = (*ip4)->ip_hl << 2; + ipproto = (*ip4)->ip_p; + + break; + +#ifdef INET6 + case ETHERTYPE_IPV6: + if (ip6 == NULL) + return; + + 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); + + hlen = sizeof(**ip6); + ipproto = (*ip6)->ip6_nxt; + + break; +#endif + + default: + return; + } + + switch (ipproto) { + case IPPROTO_TCP: + if (tcp == NULL) + return; + + m = m_getptr(m, hoff + hlen, &hoff); + KASSERT(m != NULL && m->m_len - hoff >= sizeof(**tcp)); + *tcp = (struct tcphdr *)(mtod(m, caddr_t) + hoff); + break; + + case IPPROTO_UDP: + if (udp == NULL) + return; + + m = m_getptr(m, hoff + hlen, &hoff); + KASSERT(m != NULL && m->m_len - hoff >= sizeof(**udp)); + *udp = (struct udphdr *)(mtod(m, caddr_t) + hoff); + break; + } + + return; } /* Index: net/if_var.h =================================================================== RCS file: /cvs/src/sys/net/if_var.h,v retrieving revision 1.122 diff -u -p -r1.122 if_var.h --- net/if_var.h 23 Nov 2022 14:50:59 -0000 1.122 +++ net/if_var.h 16 Jan 2023 21:50:06 -0000 @@ -317,6 +317,13 @@ int niq_enlist(struct niqueue *, struct extern struct ifnet_head ifnetlist; +#include <netinet/in.h> +#include <netinet/ip.h> +#include <netinet/ip6.h> +#include <netinet/tcp.h> +#include <netinet/udp.h> +#include <netinet/if_ether.h> + void if_start(struct ifnet *); int if_enqueue(struct ifnet *, struct mbuf *); int if_enqueue_ifq(struct ifnet *, struct mbuf *); @@ -371,6 +378,8 @@ u_int if_rxr_get(struct if_rxring *, u_i int if_rxr_info_ioctl(struct if_rxrinfo *, u_int, struct if_rxring_info *); int if_rxr_ioctl(struct if_rxrinfo *, const char *, u_int, struct if_rxring *); +void if_parse(struct mbuf *, struct ether_header **, struct ip **, + struct ip6_hdr **, struct tcphdr **, struct udphdr **); void if_counters_alloc(struct ifnet *); void if_counters_free(struct ifnet *);