1 /*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
5 * 1.0 of the CDDL.
6 *
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
10 */
11
12 /*
13 * Copyright 2024 Oxide Computer Company
14 * Copyright 2024 Ryan Zezeski
15 */
16 #include <sys/modctl.h>
17 #include <sys/strsun.h>
18 #include <sys/ktest.h>
19
20 static mblk_t *
allocb_zeroed(size_t len,uint_t pri)21 allocb_zeroed(size_t len, uint_t pri)
22 {
23 mblk_t *mp = allocb(len, pri);
24
25 if (mp != NULL) {
26 bzero(mp->b_wptr, len);
27 mp->b_wptr += len;
28 }
29 return (mp);
30 }
31
32 static size_t
msgsegs(const mblk_t * mp)33 msgsegs(const mblk_t *mp)
34 {
35 size_t out = 0;
36
37 while (mp != NULL) {
38 out++;
39 mp = mp->b_cont;
40 }
41
42 return (out);
43 }
44
45 /*
46 * Initialises a chain of n_mps zeroed mblks, each containing
47 * mplen[i] bytes.
48 */
49 static mblk_t *
init_chain(const size_t * mp_len,const size_t n_mps)50 init_chain(const size_t *mp_len, const size_t n_mps)
51 {
52 mblk_t *out = NULL;
53 mblk_t **cont = &out;
54
55 for (int i = 0; i < n_mps; ++i) {
56 mblk_t *new = allocb_zeroed(mp_len[i], BPRI_LO);
57 if (new == NULL)
58 goto bail;
59 *cont = new;
60 cont = &new->b_cont;
61 }
62
63 return (out);
64
65 bail:
66 if (out != NULL)
67 freemsg(out);
68 return (NULL);
69 }
70
71 /*
72 * Test the MBLKL macro.
73 */
74 void
mblkl_test(ktest_ctx_hdl_t * ctx)75 mblkl_test(ktest_ctx_hdl_t *ctx)
76 {
77 mblk_t *mp1 = allocb(64, 0);
78
79 KT_EASSERT3P(mp1, !=, NULL, ctx);
80 KT_ASSERT3UG(MBLKL(mp1), ==, 0, ctx, cleanup);
81 mp1->b_wptr += 14;
82 KT_ASSERT3UG(MBLKL(mp1), ==, 14, ctx, cleanup);
83 KT_PASS(ctx);
84
85 cleanup:
86 freeb(mp1);
87 }
88
89 void
msgsize_test(ktest_ctx_hdl_t * ctx)90 msgsize_test(ktest_ctx_hdl_t *ctx)
91 {
92 mblk_t *mp1 = allocb(14, 0);
93 mblk_t *mp2 = allocb(20, 0);
94
95 KT_EASSERT3P(mp1, !=, NULL, ctx);
96 KT_EASSERT3PG(mp2, !=, NULL, ctx, cleanup);
97 KT_ASSERT3UG(msgsize(mp1), ==, 0, ctx, cleanup);
98 KT_ASSERT3UG(msgsize(mp2), ==, 0, ctx, cleanup);
99 mp1->b_wptr += 14;
100 mp2->b_wptr += 20;
101 KT_ASSERT3UG(msgsize(mp1), ==, 14, ctx, cleanup);
102 KT_ASSERT3UG(msgsize(mp2), ==, 20, ctx, cleanup);
103 mp1->b_cont = mp2;
104 KT_ASSERT3UG(msgsize(mp1), ==, 34, ctx, cleanup);
105 KT_ASSERT3UG(msgsize(mp2), ==, 20, ctx, cleanup);
106 KT_PASS(ctx);
107
108 cleanup:
109 freeb(mp1);
110
111 if (mp2 != NULL) {
112 freeb(mp2);
113 }
114 }
115
116 void
msgpullup_test(ktest_ctx_hdl_t * ctx)117 msgpullup_test(ktest_ctx_hdl_t *ctx)
118 {
119 const size_t test_1[] = {8, 8};
120 const size_t test_2[] = {4, 8};
121 const size_t test_3[] = {4, 4, 8};
122 mblk_t *mp = NULL;
123 mblk_t *pullmp = NULL;
124
125 /*
126 * Test 1 -> 8 + 8, pullup 4.
127 * Should copy first 4 bytes, then link into the existing mp.
128 */
129 mp = init_chain(test_1, 2);
130 KT_EASSERT3P(mp, !=, NULL, ctx);
131 KT_ASSERT3UG(msgsegs(mp), ==, 2, ctx, cleanup);
132 pullmp = msgpullup(mp, 4);
133 KT_EASSERT3PG(pullmp, !=, NULL, ctx, cleanup);
134
135 KT_ASSERT3UG(MBLKL(pullmp), ==, 4, ctx, cleanup);
136 KT_ASSERT3UG(msgsize(pullmp), ==, 16, ctx, cleanup);
137 KT_ASSERT3UG(msgsegs(pullmp), ==, 3, ctx, cleanup);
138 KT_ASSERT3PG(pullmp->b_cont, !=, NULL, ctx, cleanup);
139 KT_ASSERT3PG(pullmp->b_cont->b_datap, ==, mp->b_datap, ctx, cleanup);
140
141 freemsg(mp);
142 freemsg(pullmp);
143
144 /*
145 * Test 2 -> 4 + 8, pullup 5.
146 * Should be 5(copy) + 7(referencing the original tail).
147 */
148 mp = init_chain(test_2, 2);
149 KT_EASSERT3P(mp, !=, NULL, ctx);
150 KT_ASSERT3UG(msgsegs(mp), ==, 2, ctx, cleanup);
151 pullmp = msgpullup(mp, 5);
152 KT_EASSERT3PG(pullmp, !=, NULL, ctx, cleanup);
153
154 KT_ASSERT3UG(MBLKL(pullmp), ==, 5, ctx, cleanup);
155 KT_ASSERT3UG(msgsize(pullmp), ==, 12, ctx, cleanup);
156 KT_ASSERT3UG(msgsegs(pullmp), ==, 2, ctx, cleanup);
157 KT_ASSERT3PG(pullmp->b_cont, !=, NULL, ctx, cleanup);
158 KT_ASSERT3PG(pullmp->b_cont->b_datap, ==, mp->b_cont->b_datap, ctx,
159 cleanup);
160
161 freemsg(mp);
162 freemsg(pullmp);
163
164 /*
165 * Test 3 -> 4 + 4 + 8, pullup 12.
166 * Should be 12(copy) + 4(original tail).
167 */
168 mp = init_chain(test_3, 3);
169 KT_EASSERT3P(mp, !=, NULL, ctx);
170 KT_ASSERT3UG(msgsegs(mp), ==, 3, ctx, cleanup);
171 pullmp = msgpullup(mp, 12);
172 KT_EASSERT3PG(pullmp, !=, NULL, ctx, cleanup);
173
174 KT_ASSERT3UG(MBLKL(pullmp), ==, 12, ctx, cleanup);
175 KT_ASSERT3UG(msgsize(pullmp), ==, 16, ctx, cleanup);
176 KT_ASSERT3UG(msgsegs(pullmp), ==, 2, ctx, cleanup);
177 KT_ASSERT3PG(pullmp->b_cont, !=, NULL, ctx, cleanup);
178 KT_ASSERT3PG(pullmp->b_cont->b_datap, ==, mp->b_cont->b_cont->b_datap,
179 ctx, cleanup);
180
181 KT_PASS(ctx);
182
183 cleanup:
184 if (mp != NULL)
185 freemsg(mp);
186 if (pullmp != NULL)
187 freemsg(pullmp);
188 }
189
190 static struct modlmisc stream_ktest_modlmisc = {
191 .misc_modops = &mod_miscops,
192 .misc_linkinfo = "stream ktest module"
193 };
194
195 static struct modlinkage stream_ktest_modlinkage = {
196 .ml_rev = MODREV_1,
197 .ml_linkage = { &stream_ktest_modlmisc, NULL }
198 };
199
200 int
_init()201 _init()
202 {
203 int ret;
204 ktest_module_hdl_t *km = NULL;
205 ktest_suite_hdl_t *ks = NULL;
206
207 VERIFY0(ktest_create_module("stream", &km));
208 VERIFY0(ktest_add_suite(km, "mblk", &ks));
209 VERIFY0(ktest_add_test(ks, "mblkl_test", mblkl_test, KTEST_FLAG_NONE));
210 VERIFY0(ktest_add_test(ks, "msgsize_test", msgsize_test,
211 KTEST_FLAG_NONE));
212 VERIFY0(ktest_add_test(ks, "msgpullup_test", msgpullup_test,
213 KTEST_FLAG_NONE));
214
215 if ((ret = ktest_register_module(km)) != 0) {
216 ktest_free_module(km);
217 return (ret);
218 }
219
220 if ((ret = mod_install(&stream_ktest_modlinkage)) != 0) {
221 ktest_unregister_module("stream");
222 return (ret);
223 }
224
225 return (0);
226 }
227
228 int
_fini()229 _fini()
230 {
231 ktest_unregister_module("stream");
232 return (mod_remove(&stream_ktest_modlinkage));
233 }
234
235 int
_info(struct modinfo * modinfop)236 _info(struct modinfo *modinfop)
237 {
238 return (mod_info(&stream_ktest_modlinkage, modinfop));
239 }
240