Hi, I preparation for my TSO in software diff, I would like to cleanup the fragment code. Both are very simmilar and I like consistency.
- Use if_output_ml() to send mbuf lists to interfaces. This can be used for TSO, fragments, ARP and ND6. - Rename variable fml to ml. It will soon be used for TCP segments, no need to have the f for fragment in the name. - In pf_route6() split the if else block, then tcp_chopper() can be easily put in there in the next diff. - In ip_fragment() the if (hlen + firstlen < tlen) is a new safety check. It makes the code correct for the case where the packet was to short to be fragmented. This should not happen, but the other functions also have this logic. No functional change intended. ok? bluhm Index: net/if.c =================================================================== RCS file: /data/mirror/openbsd/cvs/src/sys/net/if.c,v retrieving revision 1.694 diff -u -p -r1.694 if.c --- net/if.c 26 Apr 2023 19:54:35 -0000 1.694 +++ net/if.c 5 May 2023 20:27:06 -0000 @@ -762,27 +762,6 @@ if_enqueue_ifq(struct ifnet *ifp, struct } void -if_mqoutput(struct ifnet *ifp, struct mbuf_queue *mq, unsigned int *total, - struct sockaddr *dst, struct rtentry *rt) -{ - struct mbuf_list ml; - struct mbuf *m; - unsigned int len; - - mq_delist(mq, &ml); - len = ml_len(&ml); - while ((m = ml_dequeue(&ml)) != NULL) - ifp->if_output(ifp, m, rt_key(rt), rt); - - /* XXXSMP we also discard if other CPU enqueues */ - if (mq_len(mq) > 0) { - /* mbuf is back in queue. Discard. */ - atomic_sub_int(total, len + mq_purge(mq)); - } else - atomic_sub_int(total, len); -} - -void if_input(struct ifnet *ifp, struct mbuf_list *ml) { ifiq_input(&ifp->if_rcv, ml); @@ -841,6 +820,46 @@ if_input_local(struct ifnet *ifp, struct } return (0); +} + +int +if_output_ml(struct ifnet *ifp, struct mbuf_list *ml, + struct sockaddr *dst, struct rtentry *rt) +{ + struct mbuf *m; + int error = 0; + + while ((m = ml_dequeue(ml)) != NULL) { + error = ifp->if_output(ifp, m, dst, rt); + if (error) + break; + } + if (error) + ml_purge(ml); + + return error; +} + +int +if_output_mq(struct ifnet *ifp, struct mbuf_queue *mq, unsigned int *total, + struct sockaddr *dst, struct rtentry *rt) +{ + struct mbuf_list ml; + unsigned int len; + int error; + + mq_delist(mq, &ml); + len = ml_len(&ml); + error = if_output_ml(ifp, &ml, dst, rt); + + /* XXXSMP we also discard if other CPU enqueues */ + if (mq_len(mq) > 0) { + /* mbuf is back in queue. Discard. */ + atomic_sub_int(total, len + mq_purge(mq)); + } else + atomic_sub_int(total, len); + + return error; } int Index: net/if_bridge.c =================================================================== RCS file: /data/mirror/openbsd/cvs/src/sys/net/if_bridge.c,v retrieving revision 1.365 diff -u -p -r1.365 if_bridge.c --- net/if_bridge.c 27 Feb 2023 09:35:32 -0000 1.365 +++ net/if_bridge.c 5 May 2023 20:38:22 -0000 @@ -1826,7 +1826,7 @@ bridge_fragment(struct ifnet *brifp, str struct mbuf *m) { struct llc llc; - struct mbuf_list fml; + struct mbuf_list ml; int error = 0; int hassnap = 0; u_int16_t etype; @@ -1884,11 +1884,11 @@ bridge_fragment(struct ifnet *brifp, str return; } - error = ip_fragment(m, &fml, ifp, ifp->if_mtu); + error = ip_fragment(m, &ml, ifp, ifp->if_mtu); if (error) return; - while ((m = ml_dequeue(&fml)) != NULL) { + while ((m = ml_dequeue(&ml)) != NULL) { if (hassnap) { M_PREPEND(m, LLC_SNAPFRAMELEN, M_DONTWAIT); if (m == NULL) { @@ -1908,7 +1908,7 @@ bridge_fragment(struct ifnet *brifp, str break; } if (error) - ml_purge(&fml); + ml_purge(&ml); else ipstat_inc(ips_fragmented); Index: net/if_var.h =================================================================== RCS file: /data/mirror/openbsd/cvs/src/sys/net/if_var.h,v retrieving revision 1.125 diff -u -p -r1.125 if_var.h --- net/if_var.h 18 Apr 2023 22:01:24 -0000 1.125 +++ net/if_var.h 5 May 2023 21:07:16 -0000 @@ -321,12 +321,14 @@ extern struct ifnet_head ifnetlist; void if_start(struct ifnet *); int if_enqueue(struct ifnet *, struct mbuf *); int if_enqueue_ifq(struct ifnet *, struct mbuf *); -void if_mqoutput(struct ifnet *, struct mbuf_queue *, unsigned int *, - struct sockaddr *, struct rtentry *); void if_input(struct ifnet *, struct mbuf_list *); void if_vinput(struct ifnet *, struct mbuf *); void if_input_process(struct ifnet *, struct mbuf_list *); int if_input_local(struct ifnet *, struct mbuf *, sa_family_t); +int if_output_ml(struct ifnet *, struct mbuf_list *, + struct sockaddr *, struct rtentry *); +int if_output_mq(struct ifnet *, struct mbuf_queue *, unsigned int *, + struct sockaddr *, struct rtentry *); int if_output_local(struct ifnet *, struct mbuf *, sa_family_t); void if_rtrequest_dummy(struct ifnet *, int, struct rtentry *); void p2p_rtrequest(struct ifnet *, int, struct rtentry *); Index: net/pf.c =================================================================== RCS file: /data/mirror/openbsd/cvs/src/sys/net/pf.c,v retrieving revision 1.1175 diff -u -p -r1.1175 pf.c --- net/pf.c 3 May 2023 10:32:47 -0000 1.1175 +++ net/pf.c 5 May 2023 20:38:22 -0000 @@ -6466,12 +6466,11 @@ void pf_route(struct pf_pdesc *pd, struct pf_state *st) { struct mbuf *m0; - struct mbuf_list fml; + struct mbuf_list ml; struct sockaddr_in *dst, sin; struct rtentry *rt = NULL; struct ip *ip; struct ifnet *ifp = NULL; - int error = 0; unsigned int rtableid; if (pd->m->m_pkthdr.pf.routed++ > 3) { @@ -6559,7 +6558,7 @@ pf_route(struct pf_pdesc *pd, struct pf_ ipstat_inc(ips_outswcsum); ip->ip_sum = in_cksum(m0, ip->ip_hl << 2); } - error = ifp->if_output(ifp, m0, sintosa(dst), rt); + ifp->if_output(ifp, m0, sintosa(dst), rt); goto done; } @@ -6575,19 +6574,10 @@ pf_route(struct pf_pdesc *pd, struct pf_ goto bad; } - error = ip_fragment(m0, &fml, ifp, ifp->if_mtu); - if (error) + if (ip_fragment(m0, &ml, ifp, ifp->if_mtu) || + if_output_ml(ifp, &ml, sintosa(dst), rt)) goto done; - - while ((m0 = ml_dequeue(&fml)) != NULL) { - error = ifp->if_output(ifp, m0, sintosa(dst), rt); - if (error) - break; - } - if (error) - ml_purge(&fml); - else - ipstat_inc(ips_fragmented); + ipstat_inc(ips_fragmented); done: if_put(ifp); @@ -6695,15 +6685,19 @@ pf_route6(struct pf_pdesc *pd, struct pf */ if ((mtag = m_tag_find(m0, PACKET_TAG_PF_REASSEMBLED, NULL))) { (void) pf_refragment6(&m0, mtag, dst, ifp, rt); - } else if ((u_long)m0->m_pkthdr.len <= ifp->if_mtu) { + goto done; + } + + if ((u_long)m0->m_pkthdr.len <= ifp->if_mtu) { ifp->if_output(ifp, m0, sin6tosa(dst), rt); - } else { - ip6stat_inc(ip6s_cantfrag); - if (st->rt != PF_DUPTO) - pf_send_icmp(m0, ICMP6_PACKET_TOO_BIG, 0, - ifp->if_mtu, pd->af, st->rule.ptr, pd->rdomain); - goto bad; + goto done; } + + ip6stat_inc(ip6s_cantfrag); + if (st->rt != PF_DUPTO) + pf_send_icmp(m0, ICMP6_PACKET_TOO_BIG, 0, + ifp->if_mtu, pd->af, st->rule.ptr, pd->rdomain); + goto bad; done: if_put(ifp); Index: net/pf_norm.c =================================================================== RCS file: /data/mirror/openbsd/cvs/src/sys/net/pf_norm.c,v retrieving revision 1.226 diff -u -p -r1.226 pf_norm.c --- net/pf_norm.c 6 Nov 2022 18:05:05 -0000 1.226 +++ net/pf_norm.c 5 May 2023 20:38:22 -0000 @@ -954,7 +954,7 @@ pf_refragment6(struct mbuf **m0, struct struct ifnet *ifp, struct rtentry *rt) { struct mbuf *m = *m0; - struct mbuf_list fml; + struct mbuf_list ml; struct pf_fragment_tag *ftag = (struct pf_fragment_tag *)(mtag + 1); u_int32_t mtu; u_int16_t hdrlen, extoff, maxlen; @@ -997,14 +997,14 @@ pf_refragment6(struct mbuf **m0, struct * we drop the packet. */ mtu = hdrlen + sizeof(struct ip6_frag) + maxlen; - error = ip6_fragment(m, &fml, hdrlen, proto, mtu); + error = ip6_fragment(m, &ml, hdrlen, proto, mtu); *m0 = NULL; /* ip6_fragment() has consumed original packet. */ if (error) { DPFPRINTF(LOG_NOTICE, "refragment error %d", error); return (PF_DROP); } - while ((m = ml_dequeue(&fml)) != NULL) { + while ((m = ml_dequeue(&ml)) != NULL) { m->m_pkthdr.pf.flags |= PF_TAG_REFRAGMENTED; if (ifp == NULL) { ip6_forward(m, NULL, 0); Index: netinet/if_ether.c =================================================================== RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/if_ether.c,v retrieving revision 1.263 diff -u -p -r1.263 if_ether.c --- netinet/if_ether.c 25 Apr 2023 16:24:25 -0000 1.263 +++ netinet/if_ether.c 5 May 2023 20:27:06 -0000 @@ -723,7 +723,7 @@ arpcache(struct ifnet *ifp, struct ether la->la_asked = 0; la->la_refreshed = 0; - if_mqoutput(ifp, &la->la_mq, &la_hold_total, rt_key(rt), rt); + if_output_mq(ifp, &la->la_mq, &la_hold_total, rt_key(rt), rt); return (0); } Index: netinet/ip_output.c =================================================================== RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ip_output.c,v retrieving revision 1.382 diff -u -p -r1.382 ip_output.c --- netinet/ip_output.c 12 Aug 2022 17:04:16 -0000 1.382 +++ netinet/ip_output.c 5 May 2023 20:44:45 -0000 @@ -104,7 +104,7 @@ ip_output(struct mbuf *m, struct mbuf *o { struct ip *ip; struct ifnet *ifp = NULL; - struct mbuf_list fml; + struct mbuf_list ml; int hlen = sizeof (struct ip); int error = 0; struct route iproute; @@ -505,19 +505,10 @@ sendit: goto bad; } - error = ip_fragment(m, &fml, ifp, mtu); - if (error) + if ((error = ip_fragment(m, &ml, ifp, mtu)) || + (error = if_output_ml(ifp, &ml, sintosa(dst), ro->ro_rt))) goto done; - - while ((m = ml_dequeue(&fml)) != NULL) { - error = ifp->if_output(ifp, m, sintosa(dst), ro->ro_rt); - if (error) - break; - } - if (error) - ml_purge(&fml); - else - ipstat_inc(ips_fragmented); + ipstat_inc(ips_fragmented); done: if (ro == &iproute && ro->ro_rt) @@ -677,16 +668,15 @@ ip_output_ipsec_send(struct tdb *tdb, st #endif /* IPSEC */ int -ip_fragment(struct mbuf *m0, struct mbuf_list *fml, struct ifnet *ifp, +ip_fragment(struct mbuf *m0, struct mbuf_list *ml, struct ifnet *ifp, u_long mtu) { - struct mbuf *m; struct ip *ip; int firstlen, hlen, tlen, len, off; int error; - ml_init(fml); - ml_enqueue(fml, m0); + ml_init(ml); + ml_enqueue(ml, m0); ip = mtod(m0, struct ip *); hlen = ip->ip_hl << 2; @@ -705,10 +695,11 @@ ip_fragment(struct mbuf *m0, struct mbuf in_proto_cksum_out(m0, NULL); /* - * Loop through length of segment after first fragment, + * Loop through length of payload after first fragment, * make new header and copy data of each part and link onto chain. */ for (off = hlen + firstlen; off < tlen; off += len) { + struct mbuf *m; struct ip *mhip; int mhlen; @@ -717,8 +708,7 @@ ip_fragment(struct mbuf *m0, struct mbuf error = ENOBUFS; goto bad; } - ml_enqueue(fml, m); - + ml_enqueue(ml, m); if ((error = m_dup_pkthdr(m, m0, M_DONTWAIT)) != 0) goto bad; m->m_data += max_linkhdr; @@ -762,25 +752,26 @@ ip_fragment(struct mbuf *m0, struct mbuf * Update first fragment by trimming what's been copied out * and updating header, then send each fragment (in order). */ - m = m0; - m_adj(m, hlen + firstlen - tlen); - ip->ip_off |= htons(IP_MF); - ip->ip_len = htons(m->m_pkthdr.len); + if (hlen + firstlen < tlen) { + m_adj(m0, hlen + firstlen - tlen); + ip->ip_off |= htons(IP_MF); + } + ip->ip_len = htons(m0->m_pkthdr.len); ip->ip_sum = 0; - if (in_ifcap_cksum(m, ifp, IFCAP_CSUM_IPv4)) - m->m_pkthdr.csum_flags |= M_IPV4_CSUM_OUT; + if (in_ifcap_cksum(m0, ifp, IFCAP_CSUM_IPv4)) + m0->m_pkthdr.csum_flags |= M_IPV4_CSUM_OUT; else { ipstat_inc(ips_outswcsum); - ip->ip_sum = in_cksum(m, hlen); + ip->ip_sum = in_cksum(m0, hlen); } - ipstat_add(ips_ofragments, ml_len(fml)); + ipstat_add(ips_ofragments, ml_len(ml)); return (0); bad: ipstat_inc(ips_odropped); - ml_purge(fml); + ml_purge(ml); return (error); } Index: netinet6/ip6_output.c =================================================================== RCS file: /data/mirror/openbsd/cvs/src/sys/netinet6/ip6_output.c,v retrieving revision 1.272 diff -u -p -r1.272 ip6_output.c --- netinet6/ip6_output.c 12 Nov 2022 02:50:59 -0000 1.272 +++ netinet6/ip6_output.c 5 May 2023 20:41:23 -0000 @@ -165,7 +165,7 @@ ip6_output(struct mbuf *m, struct ip6_pk { struct ip6_hdr *ip6; struct ifnet *ifp = NULL; - struct mbuf_list fml; + struct mbuf_list ml; int hlen, tlen; struct route_in6 ip6route; struct rtentry *rt = NULL; @@ -751,19 +751,10 @@ reroute: ip6->ip6_nxt = IPPROTO_FRAGMENT; } - error = ip6_fragment(m, &fml, hlen, nextproto, mtu); - if (error) + if ((error = ip6_fragment(m, &ml, hlen, nextproto, mtu)) || + (error = if_output_ml(ifp, &ml, sin6tosa(dst), ro->ro_rt))) goto done; - - while ((m = ml_dequeue(&fml)) != NULL) { - error = ifp->if_output(ifp, m, sin6tosa(dst), ro->ro_rt); - if (error) - break; - } - if (error) - ml_purge(&fml); - else - ip6stat_inc(ip6s_fragmented); + ip6stat_inc(ip6s_fragmented); done: if (ro == &ip6route && ro->ro_rt) { @@ -789,16 +780,15 @@ bad: } int -ip6_fragment(struct mbuf *m0, struct mbuf_list *fml, int hlen, - u_char nextproto, u_long mtu) +ip6_fragment(struct mbuf *m0, struct mbuf_list *ml, int hlen, u_char nextproto, + u_long mtu) { - struct mbuf *m; struct ip6_hdr *ip6; u_int32_t id; int tlen, len, off; int error; - ml_init(fml); + ml_init(ml); ip6 = mtod(m0, struct ip6_hdr *); tlen = m0->m_pkthdr.len; @@ -810,10 +800,11 @@ ip6_fragment(struct mbuf *m0, struct mbu id = htonl(ip6_randomid()); /* - * Loop through length of segment, + * Loop through length of payload, * make new header and copy data of each part and link onto chain. */ for (off = hlen; off < tlen; off += len) { + struct mbuf *m; struct mbuf *mlast; struct ip6_hdr *mhip6; struct ip6_frag *ip6f; @@ -823,8 +814,7 @@ ip6_fragment(struct mbuf *m0, struct mbu error = ENOBUFS; goto bad; } - ml_enqueue(fml, m); - + ml_enqueue(ml, m); if ((error = m_dup_pkthdr(m, m0, M_DONTWAIT)) != 0) goto bad; m->m_data += max_linkhdr; @@ -856,13 +846,13 @@ ip6_fragment(struct mbuf *m0, struct mbu ip6f->ip6f_nxt = nextproto; } - ip6stat_add(ip6s_ofragments, ml_len(fml)); + ip6stat_add(ip6s_ofragments, ml_len(ml)); m_freem(m0); return (0); bad: ip6stat_inc(ip6s_odropped); - ml_purge(fml); + ml_purge(ml); m_freem(m0); return (error); } Index: netinet6/nd6.c =================================================================== RCS file: /data/mirror/openbsd/cvs/src/sys/netinet6/nd6.c,v retrieving revision 1.275 diff -u -p -r1.275 nd6.c --- netinet6/nd6.c 4 May 2023 06:56:56 -0000 1.275 +++ netinet6/nd6.c 5 May 2023 20:27:06 -0000 @@ -1181,7 +1181,7 @@ fail: * meaningless. */ nd6_llinfo_settimer(ln, nd6_gctimer); - if_mqoutput(ifp, &ln->ln_mq, &ln_hold_total, + if_output_mq(ifp, &ln->ln_mq, &ln_hold_total, rt_key(rt), rt); } else if (ln->ln_state == ND6_LLINFO_INCOMPLETE) { /* probe right away */ Index: netinet6/nd6_nbr.c =================================================================== RCS file: /data/mirror/openbsd/cvs/src/sys/netinet6/nd6_nbr.c,v retrieving revision 1.148 diff -u -p -r1.148 nd6_nbr.c --- netinet6/nd6_nbr.c 4 May 2023 06:56:56 -0000 1.148 +++ netinet6/nd6_nbr.c 5 May 2023 20:27:06 -0000 @@ -851,7 +851,7 @@ nd6_na_input(struct mbuf *m, int off, in } rt->rt_flags &= ~RTF_REJECT; ln->ln_asked = 0; - if_mqoutput(ifp, &ln->ln_mq, &ln_hold_total, rt_key(rt), rt); + if_output_mq(ifp, &ln->ln_mq, &ln_hold_total, rt_key(rt), rt); freeit: rtfree(rt);