Implement MBUF_STRESS_TEST mark II.
Changes from the original implementation: - Fragmentation is handled by the function m_fragment, which can be called from whereever fragmentation is needed. Note that this function is wrapped in #ifdef MBUF_STRESS_TEST to discourage non-testing use. - m_fragment works slightly differently from the old fragmentation code in that it allocates a seperate mbuf cluster for each fragment. This defeats dma_map_load_mbuf/buffer's feature of coalescing adjacent fragments. While that is a nice feature in practice, it nerfed the usefulness of mbuf_stress_test. - Add two modes of random fragmentation. Chains with fragments all of the same random length and chains with fragments that are each uniquely random in length may now be requested.
This commit is contained in:
parent
6464079f10
commit
3390d47670
@ -883,3 +883,87 @@ m_defrag(struct mbuf *m0, int how)
|
||||
m_freem(m_final);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
#ifdef MBUF_STRESS_TEST
|
||||
|
||||
/*
|
||||
* Fragment an mbuf chain. There's no reason you'd ever want to do
|
||||
* this in normal usage, but it's great for stress testing various
|
||||
* mbuf consumers.
|
||||
*
|
||||
* If fragmentation is not possible, the original chain will be
|
||||
* returned.
|
||||
*
|
||||
* Possible length values:
|
||||
* 0 no fragmentation will occur
|
||||
* > 0 each fragment will be of the specified length
|
||||
* -1 each fragment will be the same random value in length
|
||||
* -2 each fragment's length will be entirely random
|
||||
* (Random values range from 1 to 256)
|
||||
*/
|
||||
struct mbuf *
|
||||
m_fragment(struct mbuf *m0, int how, int length)
|
||||
{
|
||||
struct mbuf *m_new = NULL, *m_final = NULL;
|
||||
int progress = 0;
|
||||
|
||||
if (!(m0->m_flags & M_PKTHDR))
|
||||
return (m0);
|
||||
|
||||
if ((length == 0) || (length < -2))
|
||||
return (m0);
|
||||
|
||||
m_fixhdr(m0); /* Needed sanity check */
|
||||
|
||||
m_final = m_getcl(how, MT_DATA, M_PKTHDR);
|
||||
|
||||
if (m_final == NULL)
|
||||
goto nospace;
|
||||
|
||||
if (m_dup_pkthdr(m_final, m0, how) == NULL)
|
||||
goto nospace;
|
||||
|
||||
m_new = m_final;
|
||||
|
||||
if (length == -1)
|
||||
length = 1 + (arc4random() & 255);
|
||||
|
||||
while (progress < m0->m_pkthdr.len) {
|
||||
int fraglen;
|
||||
|
||||
if (length > 0)
|
||||
fraglen = length;
|
||||
else
|
||||
fraglen = 1 + (arc4random() & 255);
|
||||
if (fraglen > m0->m_pkthdr.len - progress)
|
||||
fraglen = m0->m_pkthdr.len - progress;
|
||||
|
||||
if (fraglen > MCLBYTES)
|
||||
fraglen = MCLBYTES;
|
||||
|
||||
if (m_new == NULL) {
|
||||
m_new = m_getcl(how, MT_DATA, 0);
|
||||
if (m_new == NULL)
|
||||
goto nospace;
|
||||
}
|
||||
|
||||
m_copydata(m0, progress, fraglen, mtod(m_new, caddr_t));
|
||||
progress += fraglen;
|
||||
m_new->m_len = fraglen;
|
||||
if (m_new != m_final)
|
||||
m_cat(m_final, m_new);
|
||||
m_new = NULL;
|
||||
}
|
||||
m_freem(m0);
|
||||
m0 = m_final;
|
||||
return (m0);
|
||||
nospace:
|
||||
if (m_new)
|
||||
m_free(m_new);
|
||||
if (m_final)
|
||||
m_freem(m_final);
|
||||
/* Return the original chain on failure */
|
||||
return (m0);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -1030,24 +1030,8 @@ ip_output(struct mbuf *m0, struct mbuf *opt, struct route *ro,
|
||||
#endif
|
||||
|
||||
#ifdef MBUF_STRESS_TEST
|
||||
if (mbuf_frag_size && m->m_pkthdr.len > mbuf_frag_size) {
|
||||
struct mbuf *m1, *m2;
|
||||
int length, tmp;
|
||||
|
||||
tmp = length = m->m_pkthdr.len;
|
||||
|
||||
while ((length -= mbuf_frag_size) >= 1) {
|
||||
m1 = m_split(m, length, M_DONTWAIT);
|
||||
if (m1 == NULL)
|
||||
break;
|
||||
m1->m_flags &= ~M_PKTHDR;
|
||||
m2 = m;
|
||||
while (m2->m_next != NULL)
|
||||
m2 = m2->m_next;
|
||||
m2->m_next = m1;
|
||||
m->m_pkthdr.len = tmp;
|
||||
}
|
||||
}
|
||||
if (mbuf_frag_size && m->m_pkthdr.len > mbuf_frag_size)
|
||||
m = m_fragment(m, M_DONTWAIT, mbuf_frag_size);
|
||||
#endif
|
||||
error = (*ifp->if_output)(ifp, m,
|
||||
(struct sockaddr *)dst, ro->ro_rt);
|
||||
|
@ -443,6 +443,7 @@ struct mbuf *m_devget(char *, int, int, struct ifnet *,
|
||||
struct mbuf *m_dup(struct mbuf *, int);
|
||||
int m_dup_pkthdr(struct mbuf *, struct mbuf *, int);
|
||||
u_int m_fixhdr(struct mbuf *);
|
||||
struct mbuf *m_fragment(struct mbuf *, int, int);
|
||||
struct mbuf *m_free(struct mbuf *);
|
||||
void m_freem(struct mbuf *);
|
||||
struct mbuf *m_get(int, short);
|
||||
|
Loading…
Reference in New Issue
Block a user