Commit 4688ecb1 authored by Willem de Bruijn's avatar Willem de Bruijn Committed by David S. Miller

net: expand skb_segment unit test with frag_list coverage

Expand the test with these variants that use skb frag_list:

- GSO_TEST_FRAG_LIST:             frag_skb length is gso_size
- GSO_TEST_FRAG_LIST_PURE:        same, data exclusively in frag skbs
- GSO_TEST_FRAG_LIST_NON_UNIFORM: frag_skb length may vary
- GSO_TEST_GSO_BY_FRAGS:          frag_skb length defines gso_size,
                                  i.e., segs may have varying sizes.
Signed-off-by: default avatarWillem de Bruijn <willemb@google.com>
Reviewed-by: default avatarFlorian Westphal <fw@strlen.de>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 1b4fa28a
...@@ -27,6 +27,10 @@ enum gso_test_nr { ...@@ -27,6 +27,10 @@ enum gso_test_nr {
GSO_TEST_FRAGS, GSO_TEST_FRAGS,
GSO_TEST_FRAGS_PURE, GSO_TEST_FRAGS_PURE,
GSO_TEST_GSO_PARTIAL, GSO_TEST_GSO_PARTIAL,
GSO_TEST_FRAG_LIST,
GSO_TEST_FRAG_LIST_PURE,
GSO_TEST_FRAG_LIST_NON_UNIFORM,
GSO_TEST_GSO_BY_FRAGS,
}; };
struct gso_test_case { struct gso_test_case {
...@@ -37,6 +41,8 @@ struct gso_test_case { ...@@ -37,6 +41,8 @@ struct gso_test_case {
unsigned int linear_len; unsigned int linear_len;
unsigned int nr_frags; unsigned int nr_frags;
const unsigned int *frags; const unsigned int *frags;
unsigned int nr_frag_skbs;
const unsigned int *frag_skbs;
/* output as expected */ /* output as expected */
unsigned int nr_segs; unsigned int nr_segs;
...@@ -84,6 +90,48 @@ static struct gso_test_case cases[] = { ...@@ -84,6 +90,48 @@ static struct gso_test_case cases[] = {
.nr_segs = 2, .nr_segs = 2,
.segs = (const unsigned int[]) { 2 * gso_size, 3 }, .segs = (const unsigned int[]) { 2 * gso_size, 3 },
}, },
{
/* commit 89319d3801d1: frag_list on mss boundaries */
.id = GSO_TEST_FRAG_LIST,
.name = "frag_list",
.linear_len = gso_size,
.nr_frag_skbs = 2,
.frag_skbs = (const unsigned int[]) { gso_size, gso_size },
.nr_segs = 3,
.segs = (const unsigned int[]) { gso_size, gso_size, gso_size },
},
{
.id = GSO_TEST_FRAG_LIST_PURE,
.name = "frag_list_pure",
.nr_frag_skbs = 2,
.frag_skbs = (const unsigned int[]) { gso_size, gso_size },
.nr_segs = 2,
.segs = (const unsigned int[]) { gso_size, gso_size },
},
{
/* commit 43170c4e0ba7: GRO of frag_list trains */
.id = GSO_TEST_FRAG_LIST_NON_UNIFORM,
.name = "frag_list_non_uniform",
.linear_len = gso_size,
.nr_frag_skbs = 4,
.frag_skbs = (const unsigned int[]) { gso_size, 1, gso_size, 2 },
.nr_segs = 4,
.segs = (const unsigned int[]) { gso_size, gso_size, gso_size, 3 },
},
{
/* commit 3953c46c3ac7 ("sk_buff: allow segmenting based on frag sizes") and
* commit 90017accff61 ("sctp: Add GSO support")
*
* "there will be a cover skb with protocol headers and
* children ones containing the actual segments"
*/
.id = GSO_TEST_GSO_BY_FRAGS,
.name = "gso_by_frags",
.nr_frag_skbs = 4,
.frag_skbs = (const unsigned int[]) { 100, 200, 300, 400 },
.nr_segs = 4,
.segs = (const unsigned int[]) { 100, 200, 300, 400 },
},
}; };
static void gso_test_case_to_desc(struct gso_test_case *t, char *desc) static void gso_test_case_to_desc(struct gso_test_case *t, char *desc)
...@@ -131,10 +179,54 @@ static void gso_test_func(struct kunit *test) ...@@ -131,10 +179,54 @@ static void gso_test_func(struct kunit *test)
skb->truesize += skb->data_len; skb->truesize += skb->data_len;
} }
if (tcase->frag_skbs) {
unsigned int total_size = 0, total_true_size = 0, alloc_size = 0;
struct sk_buff *frag_skb, *prev = NULL;
page = alloc_page(GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, page);
page_ref_add(page, tcase->nr_frag_skbs - 1);
for (i = 0; i < tcase->nr_frag_skbs; i++) {
unsigned int frag_size;
frag_size = tcase->frag_skbs[i];
frag_skb = build_skb(page_address(page) + alloc_size,
frag_size + shinfo_size);
KUNIT_ASSERT_NOT_NULL(test, frag_skb);
__skb_put(frag_skb, frag_size);
if (prev)
prev->next = frag_skb;
else
skb_shinfo(skb)->frag_list = frag_skb;
prev = frag_skb;
total_size += frag_size;
total_true_size += frag_skb->truesize;
alloc_size += frag_size + shinfo_size;
}
KUNIT_ASSERT_LE(test, alloc_size, PAGE_SIZE);
skb->len += total_size;
skb->data_len += total_size;
skb->truesize += total_true_size;
if (tcase->id == GSO_TEST_GSO_BY_FRAGS)
skb_shinfo(skb)->gso_size = GSO_BY_FRAGS;
}
features = NETIF_F_SG | NETIF_F_HW_CSUM; features = NETIF_F_SG | NETIF_F_HW_CSUM;
if (tcase->id == GSO_TEST_GSO_PARTIAL) if (tcase->id == GSO_TEST_GSO_PARTIAL)
features |= NETIF_F_GSO_PARTIAL; features |= NETIF_F_GSO_PARTIAL;
/* TODO: this should also work with SG,
* rather than hit BUG_ON(i >= nfrags)
*/
if (tcase->id == GSO_TEST_FRAG_LIST_NON_UNIFORM)
features &= ~NETIF_F_SG;
segs = skb_segment(skb, features); segs = skb_segment(skb, features);
if (IS_ERR(segs)) { if (IS_ERR(segs)) {
KUNIT_FAIL(test, "segs error %lld", PTR_ERR(segs)); KUNIT_FAIL(test, "segs error %lld", PTR_ERR(segs));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment