[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20231005134917.2244971-4-willemdebruijn.kernel@gmail.com>
Date: Thu, 5 Oct 2023 09:48:57 -0400
From: Willem de Bruijn <willemdebruijn.kernel@...il.com>
To: netdev@...r.kernel.org
Cc: davem@...emloft.net,
kuba@...nel.org,
edumazet@...gle.com,
pabeni@...hat.com,
alexander.duyck@...il.com,
fw@...len.de,
Willem de Bruijn <willemb@...gle.com>
Subject: [PATCH net-next 3/3] net: expand skb_segment unit test with frag_list coverage
From: Willem de Bruijn <willemb@...gle.com>
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: Willem de Bruijn <willemb@...gle.com>
---
net/core/gso_test.c | 93 +++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 93 insertions(+)
diff --git a/net/core/gso_test.c b/net/core/gso_test.c
index 41d1daa20831e..dc3ca31d11292 100644
--- a/net/core/gso_test.c
+++ b/net/core/gso_test.c
@@ -27,6 +27,10 @@ enum gso_test_nr {
GSO_TEST_FRAGS,
GSO_TEST_FRAGS_PURE,
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 {
@@ -37,6 +41,8 @@ struct gso_test_case {
unsigned int linear_len;
unsigned int nr_frags;
const unsigned int *frags;
+ unsigned int nr_frag_skbs;
+ const unsigned int *frag_skbs;
/* output as expected */
unsigned int nr_segs;
@@ -84,6 +90,48 @@ static struct gso_test_case cases[] = {
.nr_segs = 2,
.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)
@@ -131,10 +179,55 @@ static void gso_test_func(struct kunit *test)
skb->truesize += skb->data_len;
}
+ if (tcase->frag_skbs) {
+ unsigned int total_size = 0, total_true_size = 0;
+ unsigned int 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;
if (tcase->id == GSO_TEST_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);
if (IS_ERR(segs)) {
KUNIT_FAIL(test, "segs error %lld", PTR_ERR(segs));
--
2.42.0.582.g8ccd20d70d-goog
Powered by blists - more mailing lists