1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2023 Alexander V. Chernikov 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 #include "opt_netlink.h" 29 30 #include <sys/param.h> 31 #include <sys/refcount.h> 32 #include <sys/types.h> 33 #include <sys/kernel.h> 34 #include <sys/lock.h> 35 #include <sys/mutex.h> 36 #include <sys/malloc.h> 37 #include <sys/module.h> 38 #include <sys/socket.h> 39 #include <sys/priv.h> 40 41 #include <netlink/netlink.h> 42 #include <netlink/netlink_ctl.h> 43 #include <netlink/netlink_generic.h> 44 #include <netlink/netlink_message_parser.h> 45 46 #include <machine/stdarg.h> 47 #include <tests/ktest.h> 48 49 struct mtx ktest_mtx; 50 #define KTEST_LOCK() mtx_lock(&ktest_mtx) 51 #define KTEST_UNLOCK() mtx_unlock(&ktest_mtx) 52 #define KTEST_LOCK_ASSERT() mtx_assert(&ktest_mtx, MA_OWNED) 53 54 MTX_SYSINIT(ktest_mtx, &ktest_mtx, "ktest mutex", MTX_DEF); 55 56 struct ktest_module { 57 struct ktest_module_info *info; 58 volatile u_int refcount; 59 TAILQ_ENTRY(ktest_module) entries; 60 }; 61 static TAILQ_HEAD(, ktest_module) module_list = TAILQ_HEAD_INITIALIZER(module_list); 62 63 struct nl_ktest_parsed { 64 char *mod_name; 65 char *test_name; 66 struct nlattr *test_meta; 67 }; 68 69 #define _IN(_field) offsetof(struct genlmsghdr, _field) 70 #define _OUT(_field) offsetof(struct nl_ktest_parsed, _field) 71 72 static const struct nlattr_parser nla_p_get[] = { 73 { .type = KTEST_ATTR_MOD_NAME, .off = _OUT(mod_name), .cb = nlattr_get_string }, 74 { .type = KTEST_ATTR_TEST_NAME, .off = _OUT(test_name), .cb = nlattr_get_string }, 75 { .type = KTEST_ATTR_TEST_META, .off = _OUT(test_meta), .cb = nlattr_get_nla }, 76 }; 77 static const struct nlfield_parser nlf_p_get[] = { 78 }; 79 NL_DECLARE_PARSER(ktest_parser, struct genlmsghdr, nlf_p_get, nla_p_get); 80 #undef _IN 81 #undef _OUT 82 83 static bool 84 create_reply(struct nl_writer *nw, struct nlmsghdr *hdr, int cmd) 85 { 86 if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr))) 87 return (false); 88 89 struct genlmsghdr *ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr); 90 ghdr_new->cmd = cmd; 91 ghdr_new->version = 0; 92 ghdr_new->reserved = 0; 93 94 return (true); 95 } 96 97 static int 98 dump_mod_test(struct nlmsghdr *hdr, struct nl_pstate *npt, 99 struct ktest_module *mod, const struct ktest_test_info *test_info) 100 { 101 struct nl_writer *nw = npt->nw; 102 103 if (!create_reply(nw, hdr, KTEST_CMD_NEWTEST)) 104 goto enomem; 105 106 nlattr_add_string(nw, KTEST_ATTR_MOD_NAME, mod->info->name); 107 nlattr_add_string(nw, KTEST_ATTR_TEST_NAME, test_info->name); 108 nlattr_add_string(nw, KTEST_ATTR_TEST_DESCR, test_info->desc); 109 110 if (nlmsg_end(nw)) 111 return (0); 112 enomem: 113 nlmsg_abort(nw); 114 return (ENOMEM); 115 } 116 117 static int 118 dump_mod_tests(struct nlmsghdr *hdr, struct nl_pstate *npt, 119 struct ktest_module *mod, struct nl_ktest_parsed *attrs) 120 { 121 for (int i = 0; i < mod->info->num_tests; i++) { 122 const struct ktest_test_info *test_info = &mod->info->tests[i]; 123 if (attrs->test_name != NULL && strcmp(attrs->test_name, test_info->name)) 124 continue; 125 int error = dump_mod_test(hdr, npt, mod, test_info); 126 if (error != 0) 127 return (error); 128 } 129 130 return (0); 131 } 132 133 static int 134 dump_tests(struct nlmsghdr *hdr, struct nl_pstate *npt) 135 { 136 struct nl_ktest_parsed attrs = { }; 137 struct ktest_module *mod; 138 int error; 139 140 error = nl_parse_nlmsg(hdr, &ktest_parser, npt, &attrs); 141 if (error != 0) 142 return (error); 143 144 hdr->nlmsg_flags |= NLM_F_MULTI; 145 146 KTEST_LOCK(); 147 TAILQ_FOREACH(mod, &module_list, entries) { 148 if (attrs.mod_name && strcmp(attrs.mod_name, mod->info->name)) 149 continue; 150 error = dump_mod_tests(hdr, npt, mod, &attrs); 151 if (error != 0) 152 break; 153 } 154 KTEST_UNLOCK(); 155 156 if (!nlmsg_end_dump(npt->nw, error, hdr)) { 157 //NL_LOG(LOG_DEBUG, "Unable to finalize the dump"); 158 return (ENOMEM); 159 } 160 161 return (error); 162 } 163 164 static int 165 run_test(struct nlmsghdr *hdr, struct nl_pstate *npt) 166 { 167 struct nl_ktest_parsed attrs = { }; 168 struct ktest_module *mod; 169 int error; 170 171 error = nl_parse_nlmsg(hdr, &ktest_parser, npt, &attrs); 172 if (error != 0) 173 return (error); 174 175 if (attrs.mod_name == NULL) { 176 nlmsg_report_err_msg(npt, "KTEST_ATTR_MOD_NAME not set"); 177 return (EINVAL); 178 } 179 180 if (attrs.test_name == NULL) { 181 nlmsg_report_err_msg(npt, "KTEST_ATTR_TEST_NAME not set"); 182 return (EINVAL); 183 } 184 185 const struct ktest_test_info *test = NULL; 186 187 KTEST_LOCK(); 188 TAILQ_FOREACH(mod, &module_list, entries) { 189 if (strcmp(attrs.mod_name, mod->info->name)) 190 continue; 191 192 const struct ktest_module_info *info = mod->info; 193 194 for (int i = 0; i < info->num_tests; i++) { 195 const struct ktest_test_info *test_info = &info->tests[i]; 196 197 if (!strcmp(attrs.test_name, test_info->name)) { 198 test = test_info; 199 break; 200 } 201 } 202 break; 203 } 204 if (test != NULL) 205 refcount_acquire(&mod->refcount); 206 KTEST_UNLOCK(); 207 208 if (test == NULL) 209 return (ESRCH); 210 211 /* Run the test */ 212 struct ktest_test_context ctx = { 213 .npt = npt, 214 .hdr = hdr, 215 .buf = npt_alloc(npt, KTEST_MAX_BUF), 216 .bufsize = KTEST_MAX_BUF, 217 }; 218 219 if (ctx.buf == NULL) { 220 //NL_LOG(LOG_DEBUG, "unable to allocate temporary buffer"); 221 return (ENOMEM); 222 } 223 224 if (test->parse != NULL && attrs.test_meta != NULL) { 225 error = test->parse(&ctx, attrs.test_meta); 226 if (error != 0) 227 return (error); 228 } 229 230 hdr->nlmsg_flags |= NLM_F_MULTI; 231 232 KTEST_LOG_LEVEL(&ctx, LOG_INFO, "start running %s", test->name); 233 error = test->func(&ctx); 234 KTEST_LOG_LEVEL(&ctx, LOG_INFO, "end running %s", test->name); 235 236 refcount_release(&mod->refcount); 237 238 if (!nlmsg_end_dump(npt->nw, error, hdr)) { 239 //NL_LOG(LOG_DEBUG, "Unable to finalize the dump"); 240 return (ENOMEM); 241 } 242 243 return (error); 244 } 245 246 247 /* USER API */ 248 static void 249 register_test_module(struct ktest_module_info *info) 250 { 251 struct ktest_module *mod = malloc(sizeof(*mod), M_TEMP, M_WAITOK | M_ZERO); 252 253 mod->info = info; 254 info->module_ptr = mod; 255 KTEST_LOCK(); 256 TAILQ_INSERT_TAIL(&module_list, mod, entries); 257 KTEST_UNLOCK(); 258 } 259 260 static void 261 unregister_test_module(struct ktest_module_info *info) 262 { 263 struct ktest_module *mod = info->module_ptr; 264 265 info->module_ptr = NULL; 266 267 KTEST_LOCK(); 268 TAILQ_REMOVE(&module_list, mod, entries); 269 KTEST_UNLOCK(); 270 271 free(mod, M_TEMP); 272 } 273 274 static bool 275 can_unregister(struct ktest_module_info *info) 276 { 277 struct ktest_module *mod = info->module_ptr; 278 279 return (refcount_load(&mod->refcount) == 0); 280 } 281 282 int 283 ktest_default_modevent(module_t mod, int type, void *arg) 284 { 285 struct ktest_module_info *info = (struct ktest_module_info *)arg; 286 int error = 0; 287 288 switch (type) { 289 case MOD_LOAD: 290 register_test_module(info); 291 break; 292 case MOD_UNLOAD: 293 if (!can_unregister(info)) 294 return (EBUSY); 295 unregister_test_module(info); 296 break; 297 default: 298 error = EOPNOTSUPP; 299 break; 300 } 301 return (error); 302 } 303 304 bool 305 ktest_start_msg(struct ktest_test_context *ctx) 306 { 307 return (create_reply(ctx->npt->nw, ctx->hdr, KTEST_CMD_NEWMESSAGE)); 308 } 309 310 void 311 ktest_add_msg_meta(struct ktest_test_context *ctx, const char *func, 312 const char *fname, int line) 313 { 314 struct nl_writer *nw = ctx->npt->nw; 315 struct timespec ts; 316 317 nanouptime(&ts); 318 nlattr_add(nw, KTEST_MSG_ATTR_TS, sizeof(ts), &ts); 319 320 nlattr_add_string(nw, KTEST_MSG_ATTR_FUNC, func); 321 nlattr_add_string(nw, KTEST_MSG_ATTR_FILE, fname); 322 nlattr_add_u32(nw, KTEST_MSG_ATTR_LINE, line); 323 } 324 325 void 326 ktest_add_msg_text(struct ktest_test_context *ctx, int msg_level, 327 const char *fmt, ...) 328 { 329 va_list ap; 330 331 va_start(ap, fmt); 332 vsnprintf(ctx->buf, ctx->bufsize, fmt, ap); 333 va_end(ap); 334 335 nlattr_add_u8(ctx->npt->nw, KTEST_MSG_ATTR_LEVEL, msg_level); 336 nlattr_add_string(ctx->npt->nw, KTEST_MSG_ATTR_TEXT, ctx->buf); 337 } 338 339 void 340 ktest_end_msg(struct ktest_test_context *ctx) 341 { 342 nlmsg_end(ctx->npt->nw); 343 } 344 345 /* Module glue */ 346 347 static const struct nlhdr_parser *all_parsers[] = { &ktest_parser }; 348 349 static const struct genl_cmd ktest_cmds[] = { 350 { 351 .cmd_num = KTEST_CMD_LIST, 352 .cmd_name = "KTEST_CMD_LIST", 353 .cmd_cb = dump_tests, 354 .cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL, 355 }, 356 { 357 .cmd_num = KTEST_CMD_RUN, 358 .cmd_name = "KTEST_CMD_RUN", 359 .cmd_cb = run_test, 360 .cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL, 361 .cmd_priv = PRIV_KLD_LOAD, 362 }, 363 }; 364 365 static void 366 ktest_nl_register(void) 367 { 368 bool ret __diagused; 369 int family_id __diagused; 370 371 NL_VERIFY_PARSERS(all_parsers); 372 family_id = genl_register_family(KTEST_FAMILY_NAME, 0, 1, KTEST_CMD_MAX); 373 MPASS(family_id != 0); 374 375 ret = genl_register_cmds(KTEST_FAMILY_NAME, ktest_cmds, NL_ARRAY_LEN(ktest_cmds)); 376 MPASS(ret); 377 } 378 379 static void 380 ktest_nl_unregister(void) 381 { 382 MPASS(TAILQ_EMPTY(&module_list)); 383 384 genl_unregister_family(KTEST_FAMILY_NAME); 385 } 386 387 static int 388 ktest_modevent(module_t mod, int type, void *unused) 389 { 390 int error = 0; 391 392 switch (type) { 393 case MOD_LOAD: 394 ktest_nl_register(); 395 break; 396 case MOD_UNLOAD: 397 ktest_nl_unregister(); 398 break; 399 default: 400 error = EOPNOTSUPP; 401 break; 402 } 403 return (error); 404 } 405 406 static moduledata_t ktestmod = { 407 "ktest", 408 ktest_modevent, 409 0 410 }; 411 412 DECLARE_MODULE(ktestmod, ktestmod, SI_SUB_PSEUDO, SI_ORDER_ANY); 413 MODULE_VERSION(ktestmod, 1); 414 MODULE_DEPEND(ktestmod, netlink, 1, 1, 1); 415 416