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:
Mike Silbersack 2003-09-01 05:55:37 +00:00
parent 6464079f10
commit 3390d47670
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=119644
3 changed files with 87 additions and 18 deletions

View File

@ -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

View File

@ -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);

View File

@ -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);