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 * 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 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 * 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 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 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 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_test_modlmisc = { 191 .misc_modops = &mod_miscops, 192 .misc_linkinfo = "stream ktest module" 193 }; 194 195 static struct modlinkage stream_test_modlinkage = { 196 .ml_rev = MODREV_1, 197 .ml_linkage = { &stream_test_modlmisc, NULL } 198 }; 199 200 int 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_test_modlinkage)) != 0) { 221 ktest_unregister_module("stream"); 222 return (ret); 223 } 224 225 return (0); 226 } 227 228 int 229 _fini() 230 { 231 ktest_unregister_module("stream"); 232 return (mod_remove(&stream_test_modlinkage)); 233 } 234 235 int 236 _info(struct modinfo *modinfop) 237 { 238 return (mod_info(&stream_test_modlinkage, modinfop)); 239 } 240