1 1.4 christos /* $NetBSD: t_cop.c,v 1.4 2017/01/13 21:30:42 christos Exp $ */ 2 1.1 alnsn 3 1.1 alnsn /*- 4 1.1 alnsn * Copyright (c) 2014 Alexander Nasonov. 5 1.1 alnsn * All rights reserved. 6 1.1 alnsn * 7 1.1 alnsn * Redistribution and use in source and binary forms, with or without 8 1.1 alnsn * modification, are permitted provided that the following conditions 9 1.1 alnsn * are met: 10 1.1 alnsn * 11 1.1 alnsn * 1. Redistributions of source code must retain the above copyright 12 1.1 alnsn * notice, this list of conditions and the following disclaimer. 13 1.1 alnsn * 2. Redistributions in binary form must reproduce the above copyright 14 1.1 alnsn * notice, this list of conditions and the following disclaimer in 15 1.1 alnsn * the documentation and/or other materials provided with the 16 1.1 alnsn * distribution. 17 1.1 alnsn * 18 1.1 alnsn * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 1.1 alnsn * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 1.1 alnsn * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 21 1.1 alnsn * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 22 1.1 alnsn * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 23 1.1 alnsn * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 24 1.1 alnsn * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 1.1 alnsn * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 26 1.1 alnsn * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 1.1 alnsn * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 28 1.1 alnsn * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 1.1 alnsn * SUCH DAMAGE. 30 1.1 alnsn */ 31 1.1 alnsn 32 1.1 alnsn #include <sys/cdefs.h> 33 1.4 christos __RCSID("$NetBSD: t_cop.c,v 1.4 2017/01/13 21:30:42 christos Exp $"); 34 1.1 alnsn 35 1.1 alnsn #include <stdint.h> 36 1.1 alnsn #include <string.h> 37 1.1 alnsn 38 1.1 alnsn #define __BPF_PRIVATE 39 1.1 alnsn #include <net/bpf.h> 40 1.1 alnsn #include <net/bpfjit.h> 41 1.1 alnsn 42 1.1 alnsn #include "../../net/bpf/h_bpf.h" 43 1.1 alnsn 44 1.1 alnsn /* XXX: atf-c.h has collisions with mbuf */ 45 1.1 alnsn #undef m_type 46 1.1 alnsn #undef m_data 47 1.1 alnsn #include <atf-c.h> 48 1.1 alnsn 49 1.4 christos #include "h_macros.h" 50 1.1 alnsn 51 1.1 alnsn static uint32_t retA(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A); 52 1.1 alnsn static uint32_t retBL(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A); 53 1.1 alnsn static uint32_t retWL(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A); 54 1.1 alnsn static uint32_t retNF(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A); 55 1.1 alnsn static uint32_t setARG(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A); 56 1.1 alnsn 57 1.1 alnsn static const bpf_copfunc_t copfuncs[] = { 58 1.1 alnsn &retA, 59 1.1 alnsn &retBL, 60 1.1 alnsn &retWL, 61 1.1 alnsn &retNF, 62 1.1 alnsn &setARG 63 1.1 alnsn }; 64 1.1 alnsn 65 1.1 alnsn static const bpf_ctx_t ctx = { 66 1.1 alnsn .copfuncs = copfuncs, 67 1.1 alnsn .nfuncs = sizeof(copfuncs) / sizeof(copfuncs[0]), 68 1.1 alnsn .extwords = 0 69 1.1 alnsn }; 70 1.1 alnsn 71 1.1 alnsn static uint32_t 72 1.1 alnsn retA(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A) 73 1.1 alnsn { 74 1.1 alnsn 75 1.1 alnsn return A; 76 1.1 alnsn } 77 1.1 alnsn 78 1.1 alnsn static uint32_t 79 1.1 alnsn retBL(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A) 80 1.1 alnsn { 81 1.1 alnsn 82 1.1 alnsn return args->buflen; 83 1.1 alnsn } 84 1.1 alnsn 85 1.1 alnsn static uint32_t 86 1.1 alnsn retWL(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A) 87 1.1 alnsn { 88 1.1 alnsn 89 1.1 alnsn return args->wirelen; 90 1.1 alnsn } 91 1.1 alnsn 92 1.1 alnsn static uint32_t 93 1.1 alnsn retNF(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A) 94 1.1 alnsn { 95 1.1 alnsn 96 1.1 alnsn return bc->nfuncs; 97 1.1 alnsn } 98 1.1 alnsn 99 1.1 alnsn /* 100 1.1 alnsn * COP function with a side effect. 101 1.1 alnsn */ 102 1.1 alnsn static uint32_t 103 1.1 alnsn setARG(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A) 104 1.1 alnsn { 105 1.1 alnsn bool *arg = (bool *)args->arg; 106 1.1 alnsn bool old = *arg; 107 1.1 alnsn 108 1.1 alnsn *arg = true; 109 1.1 alnsn return old; 110 1.1 alnsn } 111 1.1 alnsn 112 1.1 alnsn ATF_TC(bpfjit_cop_no_ctx); 113 1.1 alnsn ATF_TC_HEAD(bpfjit_cop_no_ctx, tc) 114 1.1 alnsn { 115 1.1 alnsn atf_tc_set_md_var(tc, "descr", "Test that bpf program with BPF_COP " 116 1.1 alnsn "instruction isn't valid without a context"); 117 1.1 alnsn } 118 1.1 alnsn 119 1.1 alnsn ATF_TC_BODY(bpfjit_cop_no_ctx, tc) 120 1.1 alnsn { 121 1.1 alnsn static struct bpf_insn insns[] = { 122 1.1 alnsn BPF_STMT(BPF_MISC+BPF_COP, 0), 123 1.1 alnsn BPF_STMT(BPF_RET+BPF_K, 7) 124 1.1 alnsn }; 125 1.1 alnsn 126 1.1 alnsn bpfjit_func_t code; 127 1.1 alnsn 128 1.1 alnsn size_t insn_count = sizeof(insns) / sizeof(insns[0]); 129 1.1 alnsn 130 1.1 alnsn RZ(rump_init()); 131 1.1 alnsn 132 1.1 alnsn ATF_CHECK(!prog_validate(insns, insn_count)); 133 1.1 alnsn 134 1.1 alnsn rump_schedule(); 135 1.1 alnsn code = rumpns_bpfjit_generate_code(NULL, insns, insn_count); 136 1.1 alnsn rump_unschedule(); 137 1.1 alnsn ATF_CHECK(code == NULL); 138 1.1 alnsn } 139 1.1 alnsn 140 1.1 alnsn ATF_TC(bpfjit_cop_ret_A); 141 1.1 alnsn ATF_TC_HEAD(bpfjit_cop_ret_A, tc) 142 1.1 alnsn { 143 1.1 alnsn atf_tc_set_md_var(tc, "descr", "Test coprocessor function " 144 1.1 alnsn "that returns a content of the A register"); 145 1.1 alnsn } 146 1.1 alnsn 147 1.1 alnsn ATF_TC_BODY(bpfjit_cop_ret_A, tc) 148 1.1 alnsn { 149 1.1 alnsn static struct bpf_insn insns[] = { 150 1.1 alnsn BPF_STMT(BPF_LD+BPF_IMM, 13), 151 1.1 alnsn BPF_STMT(BPF_MISC+BPF_COP, 0), // retA 152 1.1 alnsn BPF_STMT(BPF_RET+BPF_A, 0) 153 1.1 alnsn }; 154 1.1 alnsn 155 1.1 alnsn bpfjit_func_t code; 156 1.1 alnsn uint8_t pkt[1] = { 0 }; 157 1.1 alnsn bpf_args_t args = { 158 1.1 alnsn .pkt = pkt, 159 1.1 alnsn .buflen = sizeof(pkt), 160 1.1 alnsn .wirelen = sizeof(pkt), 161 1.1 alnsn }; 162 1.1 alnsn 163 1.1 alnsn size_t insn_count = sizeof(insns) / sizeof(insns[0]); 164 1.1 alnsn 165 1.1 alnsn RZ(rump_init()); 166 1.1 alnsn 167 1.1 alnsn rump_schedule(); 168 1.1 alnsn code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count); 169 1.1 alnsn rump_unschedule(); 170 1.1 alnsn ATF_REQUIRE(code != NULL); 171 1.1 alnsn 172 1.1 alnsn ATF_CHECK(code(&ctx, &args) == 13); 173 1.1 alnsn 174 1.1 alnsn rump_schedule(); 175 1.1 alnsn rumpns_bpfjit_free_code(code); 176 1.1 alnsn rump_unschedule(); 177 1.1 alnsn } 178 1.1 alnsn 179 1.1 alnsn ATF_TC(bpfjit_cop_ret_buflen); 180 1.1 alnsn ATF_TC_HEAD(bpfjit_cop_ret_buflen, tc) 181 1.1 alnsn { 182 1.1 alnsn atf_tc_set_md_var(tc, "descr", "Test coprocessor function " 183 1.1 alnsn "that returns the buflen argument"); 184 1.1 alnsn } 185 1.1 alnsn 186 1.1 alnsn ATF_TC_BODY(bpfjit_cop_ret_buflen, tc) 187 1.1 alnsn { 188 1.1 alnsn static struct bpf_insn insns[] = { 189 1.1 alnsn BPF_STMT(BPF_LD+BPF_IMM, 13), 190 1.1 alnsn BPF_STMT(BPF_MISC+BPF_COP, 1), // retBL 191 1.1 alnsn BPF_STMT(BPF_RET+BPF_A, 0) 192 1.1 alnsn }; 193 1.1 alnsn 194 1.1 alnsn bpfjit_func_t code; 195 1.1 alnsn uint8_t pkt[1] = { 0 }; 196 1.1 alnsn bpf_args_t args = { 197 1.1 alnsn .pkt = pkt, 198 1.1 alnsn .buflen = sizeof(pkt), 199 1.1 alnsn .wirelen = sizeof(pkt) 200 1.1 alnsn }; 201 1.1 alnsn 202 1.1 alnsn size_t insn_count = sizeof(insns) / sizeof(insns[0]); 203 1.1 alnsn 204 1.1 alnsn RZ(rump_init()); 205 1.1 alnsn 206 1.1 alnsn rump_schedule(); 207 1.1 alnsn code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count); 208 1.1 alnsn rump_unschedule(); 209 1.1 alnsn ATF_REQUIRE(code != NULL); 210 1.1 alnsn 211 1.1 alnsn ATF_CHECK(code(&ctx, &args) == sizeof(pkt)); 212 1.1 alnsn 213 1.1 alnsn rump_schedule(); 214 1.1 alnsn rumpns_bpfjit_free_code(code); 215 1.1 alnsn rump_unschedule(); 216 1.1 alnsn } 217 1.1 alnsn 218 1.1 alnsn ATF_TC(bpfjit_cop_ret_wirelen); 219 1.1 alnsn ATF_TC_HEAD(bpfjit_cop_ret_wirelen, tc) 220 1.1 alnsn { 221 1.1 alnsn atf_tc_set_md_var(tc, "descr", "Test coprocessor function " 222 1.1 alnsn "that returns the wirelen argument"); 223 1.1 alnsn } 224 1.1 alnsn 225 1.1 alnsn ATF_TC_BODY(bpfjit_cop_ret_wirelen, tc) 226 1.1 alnsn { 227 1.1 alnsn static struct bpf_insn insns[] = { 228 1.1 alnsn BPF_STMT(BPF_LD+BPF_IMM, 13), 229 1.1 alnsn BPF_STMT(BPF_MISC+BPF_COP, 2), // retWL 230 1.1 alnsn BPF_STMT(BPF_RET+BPF_A, 0) 231 1.1 alnsn }; 232 1.1 alnsn 233 1.1 alnsn bpfjit_func_t code; 234 1.1 alnsn uint8_t pkt[1] = { 0 }; 235 1.1 alnsn bpf_args_t args = { 236 1.1 alnsn .pkt = pkt, 237 1.1 alnsn .buflen = sizeof(pkt), 238 1.1 alnsn .wirelen = sizeof(pkt) 239 1.1 alnsn }; 240 1.1 alnsn 241 1.1 alnsn size_t insn_count = sizeof(insns) / sizeof(insns[0]); 242 1.1 alnsn 243 1.1 alnsn RZ(rump_init()); 244 1.1 alnsn 245 1.1 alnsn rump_schedule(); 246 1.1 alnsn code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count); 247 1.1 alnsn rump_unschedule(); 248 1.1 alnsn ATF_REQUIRE(code != NULL); 249 1.1 alnsn 250 1.1 alnsn ATF_CHECK(code(&ctx, &args) == sizeof(pkt)); 251 1.1 alnsn 252 1.1 alnsn rump_schedule(); 253 1.1 alnsn rumpns_bpfjit_free_code(code); 254 1.1 alnsn rump_unschedule(); 255 1.1 alnsn } 256 1.1 alnsn 257 1.1 alnsn ATF_TC(bpfjit_cop_ret_nfuncs); 258 1.1 alnsn ATF_TC_HEAD(bpfjit_cop_ret_nfuncs, tc) 259 1.1 alnsn { 260 1.1 alnsn atf_tc_set_md_var(tc, "descr", "Test coprocessor function " 261 1.1 alnsn "that returns nfuncs member of the context argument"); 262 1.1 alnsn } 263 1.1 alnsn 264 1.1 alnsn ATF_TC_BODY(bpfjit_cop_ret_nfuncs, tc) 265 1.1 alnsn { 266 1.1 alnsn static struct bpf_insn insns[] = { 267 1.1 alnsn BPF_STMT(BPF_LD+BPF_IMM, 13), 268 1.1 alnsn BPF_STMT(BPF_MISC+BPF_COP, 3), // retNF 269 1.1 alnsn BPF_STMT(BPF_RET+BPF_A, 0) 270 1.1 alnsn }; 271 1.1 alnsn 272 1.1 alnsn bpfjit_func_t code; 273 1.1 alnsn uint8_t pkt[1] = { 0 }; 274 1.1 alnsn bpf_args_t args = { 275 1.1 alnsn .pkt = pkt, 276 1.1 alnsn .buflen = sizeof(pkt), 277 1.1 alnsn .wirelen = sizeof(pkt) 278 1.1 alnsn }; 279 1.1 alnsn 280 1.1 alnsn size_t insn_count = sizeof(insns) / sizeof(insns[0]); 281 1.1 alnsn 282 1.1 alnsn RZ(rump_init()); 283 1.1 alnsn 284 1.1 alnsn rump_schedule(); 285 1.1 alnsn code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count); 286 1.1 alnsn rump_unschedule(); 287 1.1 alnsn ATF_REQUIRE(code != NULL); 288 1.1 alnsn 289 1.1 alnsn ATF_CHECK(code(&ctx, &args) == ctx.nfuncs); 290 1.1 alnsn 291 1.1 alnsn rump_schedule(); 292 1.1 alnsn rumpns_bpfjit_free_code(code); 293 1.1 alnsn rump_unschedule(); 294 1.1 alnsn } 295 1.1 alnsn 296 1.1 alnsn ATF_TC(bpfjit_cop_side_effect); 297 1.1 alnsn ATF_TC_HEAD(bpfjit_cop_side_effect, tc) 298 1.1 alnsn { 299 1.1 alnsn atf_tc_set_md_var(tc, "descr", 300 1.1 alnsn "Test that ABC optimization doesn't skip BPF_COP call"); 301 1.1 alnsn } 302 1.1 alnsn 303 1.1 alnsn ATF_TC_BODY(bpfjit_cop_side_effect, tc) 304 1.1 alnsn { 305 1.1 alnsn static struct bpf_insn insns[] = { 306 1.1 alnsn BPF_STMT(BPF_LD+BPF_IMM, 13), 307 1.1 alnsn BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 0), 308 1.1 alnsn BPF_STMT(BPF_MISC+BPF_COP, 4), // setARG 309 1.1 alnsn BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 99999), 310 1.1 alnsn BPF_STMT(BPF_RET+BPF_A, 0) 311 1.1 alnsn }; 312 1.1 alnsn 313 1.1 alnsn bpfjit_func_t code; 314 1.1 alnsn bool arg = false; 315 1.1 alnsn uint8_t pkt[1] = { 0 }; 316 1.1 alnsn bpf_args_t args = { 317 1.1 alnsn .pkt = pkt, 318 1.1 alnsn .buflen = sizeof(pkt), 319 1.1 alnsn .wirelen = sizeof(pkt), 320 1.1 alnsn .mem = NULL, 321 1.1 alnsn .arg = &arg 322 1.1 alnsn }; 323 1.1 alnsn 324 1.1 alnsn size_t insn_count = sizeof(insns) / sizeof(insns[0]); 325 1.1 alnsn 326 1.1 alnsn RZ(rump_init()); 327 1.1 alnsn 328 1.1 alnsn rump_schedule(); 329 1.1 alnsn code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count); 330 1.1 alnsn rump_unschedule(); 331 1.1 alnsn ATF_REQUIRE(code != NULL); 332 1.1 alnsn 333 1.1 alnsn ATF_CHECK(code(&ctx, &args) == 0); 334 1.1 alnsn ATF_CHECK(arg == true); 335 1.1 alnsn 336 1.1 alnsn rump_schedule(); 337 1.1 alnsn rumpns_bpfjit_free_code(code); 338 1.1 alnsn rump_unschedule(); 339 1.1 alnsn } 340 1.1 alnsn 341 1.3 alnsn ATF_TC(bpfjit_cop_copx); 342 1.3 alnsn ATF_TC_HEAD(bpfjit_cop_copx, tc) 343 1.3 alnsn { 344 1.3 alnsn atf_tc_set_md_var(tc, "descr", 345 1.3 alnsn "Test BPF_COP call followed by BPF_COPX call"); 346 1.3 alnsn } 347 1.3 alnsn 348 1.3 alnsn ATF_TC_BODY(bpfjit_cop_copx, tc) 349 1.3 alnsn { 350 1.3 alnsn static struct bpf_insn insns[] = { 351 1.3 alnsn BPF_STMT(BPF_LD+BPF_IMM, 1), /* A <- 1 */ 352 1.3 alnsn BPF_STMT(BPF_MISC+BPF_COP, 0), /* retA */ 353 1.3 alnsn BPF_STMT(BPF_MISC+BPF_TAX, 0), /* X <- A */ 354 1.3 alnsn BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 0), /* A = P[0] */ 355 1.3 alnsn BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 1), /* A = A + X */ 356 1.3 alnsn BPF_STMT(BPF_MISC+BPF_TAX, 0), /* X <- A */ 357 1.3 alnsn BPF_STMT(BPF_MISC+BPF_COPX, 0), /* retNF */ 358 1.3 alnsn BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 1), /* A = A + X */ 359 1.3 alnsn BPF_STMT(BPF_RET+BPF_A, 0) 360 1.3 alnsn }; 361 1.3 alnsn 362 1.3 alnsn bpfjit_func_t code; 363 1.3 alnsn uint8_t pkt[1] = { 2 }; 364 1.3 alnsn bpf_args_t args = { 365 1.3 alnsn .pkt = pkt, 366 1.3 alnsn .buflen = sizeof(pkt), 367 1.3 alnsn .wirelen = sizeof(pkt), 368 1.3 alnsn }; 369 1.3 alnsn 370 1.3 alnsn size_t insn_count = sizeof(insns) / sizeof(insns[0]); 371 1.3 alnsn 372 1.3 alnsn RZ(rump_init()); 373 1.3 alnsn 374 1.3 alnsn rump_schedule(); 375 1.3 alnsn code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count); 376 1.3 alnsn rump_unschedule(); 377 1.3 alnsn ATF_REQUIRE(code != NULL); 378 1.3 alnsn 379 1.3 alnsn ATF_CHECK(code(&ctx, &args) == 3 + ctx.nfuncs); 380 1.3 alnsn 381 1.3 alnsn rump_schedule(); 382 1.3 alnsn rumpns_bpfjit_free_code(code); 383 1.3 alnsn rump_unschedule(); 384 1.3 alnsn } 385 1.3 alnsn 386 1.1 alnsn ATF_TC(bpfjit_cop_invalid_index); 387 1.1 alnsn ATF_TC_HEAD(bpfjit_cop_invalid_index, tc) 388 1.1 alnsn { 389 1.1 alnsn atf_tc_set_md_var(tc, "descr", 390 1.1 alnsn "Test that out-of-range coprocessor function fails validation"); 391 1.1 alnsn } 392 1.1 alnsn 393 1.1 alnsn ATF_TC_BODY(bpfjit_cop_invalid_index, tc) 394 1.1 alnsn { 395 1.1 alnsn static struct bpf_insn insns[] = { 396 1.1 alnsn BPF_STMT(BPF_LD+BPF_IMM, 13), 397 1.1 alnsn BPF_STMT(BPF_MISC+BPF_COP, 6), // invalid index 398 1.1 alnsn BPF_STMT(BPF_RET+BPF_K, 27) 399 1.1 alnsn }; 400 1.1 alnsn 401 1.1 alnsn bpfjit_func_t code; 402 1.1 alnsn size_t insn_count = sizeof(insns) / sizeof(insns[0]); 403 1.1 alnsn 404 1.1 alnsn RZ(rump_init()); 405 1.1 alnsn 406 1.1 alnsn rump_schedule(); 407 1.1 alnsn code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count); 408 1.1 alnsn rump_unschedule(); 409 1.1 alnsn ATF_CHECK(code == NULL); 410 1.1 alnsn } 411 1.1 alnsn 412 1.1 alnsn ATF_TC(bpfjit_copx_no_ctx); 413 1.1 alnsn ATF_TC_HEAD(bpfjit_copx_no_ctx, tc) 414 1.1 alnsn { 415 1.1 alnsn atf_tc_set_md_var(tc, "descr", "Test that bpf program with BPF_COPX " 416 1.1 alnsn "instruction isn't valid without a context"); 417 1.1 alnsn } 418 1.1 alnsn 419 1.1 alnsn ATF_TC_BODY(bpfjit_copx_no_ctx, tc) 420 1.1 alnsn { 421 1.1 alnsn static struct bpf_insn insns[] = { 422 1.1 alnsn BPF_STMT(BPF_MISC+BPF_COP, 0), 423 1.1 alnsn BPF_STMT(BPF_RET+BPF_K, 7) 424 1.1 alnsn }; 425 1.1 alnsn 426 1.1 alnsn bpfjit_func_t code; 427 1.1 alnsn 428 1.1 alnsn size_t insn_count = sizeof(insns) / sizeof(insns[0]); 429 1.1 alnsn 430 1.1 alnsn RZ(rump_init()); 431 1.1 alnsn 432 1.1 alnsn ATF_CHECK(!prog_validate(insns, insn_count)); 433 1.1 alnsn 434 1.1 alnsn rump_schedule(); 435 1.1 alnsn code = rumpns_bpfjit_generate_code(NULL, insns, insn_count); 436 1.1 alnsn rump_unschedule(); 437 1.1 alnsn ATF_CHECK(code == NULL); 438 1.1 alnsn } 439 1.1 alnsn 440 1.1 alnsn ATF_TC(bpfjit_copx_ret_A); 441 1.1 alnsn ATF_TC_HEAD(bpfjit_copx_ret_A, tc) 442 1.1 alnsn { 443 1.1 alnsn atf_tc_set_md_var(tc, "descr", "Test coprocessor function " 444 1.1 alnsn "that returns a content of the A register"); 445 1.1 alnsn } 446 1.1 alnsn 447 1.1 alnsn ATF_TC_BODY(bpfjit_copx_ret_A, tc) 448 1.1 alnsn { 449 1.1 alnsn static struct bpf_insn insns[] = { 450 1.1 alnsn BPF_STMT(BPF_LD+BPF_IMM, 13), 451 1.1 alnsn BPF_STMT(BPF_LDX+BPF_IMM, 0), // retA 452 1.1 alnsn BPF_STMT(BPF_MISC+BPF_COPX, 0), 453 1.1 alnsn BPF_STMT(BPF_RET+BPF_A, 0) 454 1.1 alnsn }; 455 1.1 alnsn 456 1.1 alnsn bpfjit_func_t code; 457 1.1 alnsn uint8_t pkt[1] = { 0 }; 458 1.1 alnsn bpf_args_t args = { 459 1.1 alnsn .pkt = pkt, 460 1.1 alnsn .buflen = sizeof(pkt), 461 1.1 alnsn .wirelen = sizeof(pkt), 462 1.1 alnsn }; 463 1.1 alnsn 464 1.1 alnsn size_t insn_count = sizeof(insns) / sizeof(insns[0]); 465 1.1 alnsn 466 1.1 alnsn RZ(rump_init()); 467 1.1 alnsn 468 1.1 alnsn rump_schedule(); 469 1.1 alnsn code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count); 470 1.1 alnsn rump_unschedule(); 471 1.1 alnsn ATF_REQUIRE(code != NULL); 472 1.1 alnsn 473 1.1 alnsn ATF_CHECK(code(&ctx, &args) == 13); 474 1.1 alnsn 475 1.1 alnsn rump_schedule(); 476 1.1 alnsn rumpns_bpfjit_free_code(code); 477 1.1 alnsn rump_unschedule(); 478 1.1 alnsn } 479 1.1 alnsn 480 1.1 alnsn ATF_TC(bpfjit_copx_ret_buflen); 481 1.1 alnsn ATF_TC_HEAD(bpfjit_copx_ret_buflen, tc) 482 1.1 alnsn { 483 1.1 alnsn atf_tc_set_md_var(tc, "descr", "Test coprocessor function " 484 1.1 alnsn "that returns the buflen argument"); 485 1.1 alnsn } 486 1.1 alnsn 487 1.1 alnsn ATF_TC_BODY(bpfjit_copx_ret_buflen, tc) 488 1.1 alnsn { 489 1.1 alnsn static struct bpf_insn insns[] = { 490 1.1 alnsn BPF_STMT(BPF_LD+BPF_IMM, 13), 491 1.1 alnsn BPF_STMT(BPF_LDX+BPF_IMM, 1), // retBL 492 1.1 alnsn BPF_STMT(BPF_MISC+BPF_COPX, 0), 493 1.1 alnsn BPF_STMT(BPF_RET+BPF_A, 0) 494 1.1 alnsn }; 495 1.1 alnsn 496 1.1 alnsn bpfjit_func_t code; 497 1.1 alnsn uint8_t pkt[1] = { 0 }; 498 1.1 alnsn bpf_args_t args = { 499 1.1 alnsn .pkt = pkt, 500 1.1 alnsn .buflen = sizeof(pkt), 501 1.1 alnsn .wirelen = sizeof(pkt) 502 1.1 alnsn }; 503 1.1 alnsn 504 1.1 alnsn size_t insn_count = sizeof(insns) / sizeof(insns[0]); 505 1.1 alnsn 506 1.1 alnsn RZ(rump_init()); 507 1.1 alnsn 508 1.1 alnsn rump_schedule(); 509 1.1 alnsn code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count); 510 1.1 alnsn rump_unschedule(); 511 1.1 alnsn ATF_REQUIRE(code != NULL); 512 1.1 alnsn 513 1.1 alnsn ATF_CHECK(code(&ctx, &args) == sizeof(pkt)); 514 1.1 alnsn 515 1.2 alnsn rump_schedule(); 516 1.1 alnsn rumpns_bpfjit_free_code(code); 517 1.1 alnsn rump_unschedule(); 518 1.1 alnsn } 519 1.1 alnsn 520 1.1 alnsn ATF_TC(bpfjit_copx_ret_wirelen); 521 1.1 alnsn ATF_TC_HEAD(bpfjit_copx_ret_wirelen, tc) 522 1.1 alnsn { 523 1.1 alnsn atf_tc_set_md_var(tc, "descr", "Test coprocessor function " 524 1.1 alnsn "that returns the wirelen argument"); 525 1.1 alnsn } 526 1.1 alnsn 527 1.1 alnsn ATF_TC_BODY(bpfjit_copx_ret_wirelen, tc) 528 1.1 alnsn { 529 1.1 alnsn static struct bpf_insn insns[] = { 530 1.1 alnsn BPF_STMT(BPF_LDX+BPF_IMM, 2), // retWL 531 1.1 alnsn BPF_STMT(BPF_LD+BPF_IMM, 13), 532 1.1 alnsn BPF_STMT(BPF_MISC+BPF_COPX, 0), 533 1.1 alnsn BPF_STMT(BPF_RET+BPF_A, 0) 534 1.1 alnsn }; 535 1.1 alnsn 536 1.1 alnsn bpfjit_func_t code; 537 1.1 alnsn uint8_t pkt[1] = { 0 }; 538 1.1 alnsn bpf_args_t args = { 539 1.1 alnsn .pkt = pkt, 540 1.1 alnsn .buflen = sizeof(pkt), 541 1.1 alnsn .wirelen = sizeof(pkt) 542 1.1 alnsn }; 543 1.1 alnsn 544 1.1 alnsn size_t insn_count = sizeof(insns) / sizeof(insns[0]); 545 1.1 alnsn 546 1.1 alnsn RZ(rump_init()); 547 1.1 alnsn 548 1.1 alnsn rump_schedule(); 549 1.1 alnsn code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count); 550 1.1 alnsn rump_unschedule(); 551 1.1 alnsn ATF_REQUIRE(code != NULL); 552 1.1 alnsn 553 1.1 alnsn ATF_CHECK(code(&ctx, &args) == sizeof(pkt)); 554 1.1 alnsn 555 1.1 alnsn rump_schedule(); 556 1.1 alnsn rumpns_bpfjit_free_code(code); 557 1.1 alnsn rump_unschedule(); 558 1.1 alnsn } 559 1.1 alnsn 560 1.1 alnsn ATF_TC(bpfjit_copx_ret_nfuncs); 561 1.1 alnsn ATF_TC_HEAD(bpfjit_copx_ret_nfuncs, tc) 562 1.1 alnsn { 563 1.1 alnsn atf_tc_set_md_var(tc, "descr", "Test coprocessor function " 564 1.1 alnsn "that returns nfuncs member of the context argument"); 565 1.1 alnsn } 566 1.1 alnsn 567 1.1 alnsn ATF_TC_BODY(bpfjit_copx_ret_nfuncs, tc) 568 1.1 alnsn { 569 1.1 alnsn static struct bpf_insn insns[] = { 570 1.1 alnsn BPF_STMT(BPF_LD+BPF_IMM, 13), 571 1.1 alnsn BPF_STMT(BPF_LDX+BPF_IMM, 3), // retNF 572 1.1 alnsn BPF_STMT(BPF_MISC+BPF_COPX, 0), 573 1.1 alnsn BPF_STMT(BPF_RET+BPF_A, 0) 574 1.1 alnsn }; 575 1.1 alnsn 576 1.1 alnsn bpfjit_func_t code; 577 1.1 alnsn uint8_t pkt[1] = { 0 }; 578 1.1 alnsn bpf_args_t args = { 579 1.1 alnsn .pkt = pkt, 580 1.1 alnsn .buflen = sizeof(pkt), 581 1.1 alnsn .wirelen = sizeof(pkt) 582 1.1 alnsn }; 583 1.1 alnsn 584 1.1 alnsn size_t insn_count = sizeof(insns) / sizeof(insns[0]); 585 1.1 alnsn 586 1.1 alnsn RZ(rump_init()); 587 1.1 alnsn 588 1.1 alnsn rump_schedule(); 589 1.1 alnsn code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count); 590 1.1 alnsn rump_unschedule(); 591 1.1 alnsn ATF_REQUIRE(code != NULL); 592 1.1 alnsn 593 1.1 alnsn ATF_CHECK(code(&ctx, &args) == ctx.nfuncs); 594 1.1 alnsn 595 1.1 alnsn rump_schedule(); 596 1.1 alnsn rumpns_bpfjit_free_code(code); 597 1.1 alnsn rump_unschedule(); 598 1.1 alnsn } 599 1.1 alnsn 600 1.1 alnsn ATF_TC(bpfjit_copx_side_effect); 601 1.1 alnsn ATF_TC_HEAD(bpfjit_copx_side_effect, tc) 602 1.1 alnsn { 603 1.1 alnsn atf_tc_set_md_var(tc, "descr", 604 1.1 alnsn "Test that ABC optimization doesn't skip BPF_COPX call"); 605 1.1 alnsn } 606 1.1 alnsn 607 1.1 alnsn ATF_TC_BODY(bpfjit_copx_side_effect, tc) 608 1.1 alnsn { 609 1.1 alnsn static struct bpf_insn insns[] = { 610 1.1 alnsn BPF_STMT(BPF_LD+BPF_IMM, 13), 611 1.1 alnsn BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 0), 612 1.1 alnsn BPF_STMT(BPF_LDX+BPF_IMM, 4), // setARG 613 1.1 alnsn BPF_STMT(BPF_MISC+BPF_COPX, 0), 614 1.1 alnsn BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 99999), 615 1.1 alnsn BPF_STMT(BPF_RET+BPF_A, 0) 616 1.1 alnsn }; 617 1.1 alnsn 618 1.1 alnsn bpfjit_func_t code; 619 1.1 alnsn bool arg = false; 620 1.1 alnsn uint8_t pkt[1] = { 0 }; 621 1.1 alnsn bpf_args_t args = { 622 1.1 alnsn .pkt = pkt, 623 1.1 alnsn .buflen = sizeof(pkt), 624 1.1 alnsn .wirelen = sizeof(pkt), 625 1.1 alnsn .mem = NULL, 626 1.1 alnsn .arg = &arg 627 1.1 alnsn }; 628 1.1 alnsn 629 1.1 alnsn size_t insn_count = sizeof(insns) / sizeof(insns[0]); 630 1.1 alnsn 631 1.1 alnsn RZ(rump_init()); 632 1.1 alnsn 633 1.1 alnsn rump_schedule(); 634 1.1 alnsn code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count); 635 1.1 alnsn rump_unschedule(); 636 1.1 alnsn ATF_REQUIRE(code != NULL); 637 1.1 alnsn 638 1.1 alnsn ATF_CHECK(code(&ctx, &args) == 0); 639 1.1 alnsn ATF_CHECK(arg == true); 640 1.1 alnsn 641 1.1 alnsn rump_schedule(); 642 1.1 alnsn rumpns_bpfjit_free_code(code); 643 1.1 alnsn rump_unschedule(); 644 1.1 alnsn } 645 1.1 alnsn 646 1.3 alnsn ATF_TC(bpfjit_copx_cop); 647 1.3 alnsn ATF_TC_HEAD(bpfjit_copx_cop, tc) 648 1.3 alnsn { 649 1.3 alnsn atf_tc_set_md_var(tc, "descr", 650 1.3 alnsn "Test BPF_COPX call followed by BPF_COP call"); 651 1.3 alnsn } 652 1.3 alnsn 653 1.3 alnsn ATF_TC_BODY(bpfjit_copx_cop, tc) 654 1.3 alnsn { 655 1.3 alnsn static struct bpf_insn insns[] = { 656 1.3 alnsn BPF_STMT(BPF_LDX+BPF_IMM, 2), /* X <- 2 */ 657 1.3 alnsn BPF_STMT(BPF_MISC+BPF_COPX, 0), /* retWL */ 658 1.3 alnsn BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 1), /* A = A + X */ 659 1.3 alnsn BPF_STMT(BPF_MISC+BPF_TAX, 0), /* X <- A */ 660 1.3 alnsn BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 0), /* A = P[0] */ 661 1.3 alnsn BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 1), /* A = A + X */ 662 1.3 alnsn BPF_STMT(BPF_MISC+BPF_TAX, 0), /* X <- A */ 663 1.3 alnsn BPF_STMT(BPF_MISC+BPF_COP, 3), /* retNF */ 664 1.3 alnsn BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 1), /* A = A + X */ 665 1.3 alnsn BPF_STMT(BPF_RET+BPF_A, 0) 666 1.3 alnsn }; 667 1.3 alnsn 668 1.3 alnsn bpfjit_func_t code; 669 1.3 alnsn uint8_t pkt[1] = { 2 }; 670 1.3 alnsn bpf_args_t args = { 671 1.3 alnsn .pkt = pkt, 672 1.3 alnsn .buflen = sizeof(pkt), 673 1.3 alnsn .wirelen = sizeof(pkt), 674 1.3 alnsn }; 675 1.3 alnsn 676 1.3 alnsn size_t insn_count = sizeof(insns) / sizeof(insns[0]); 677 1.3 alnsn 678 1.3 alnsn RZ(rump_init()); 679 1.3 alnsn 680 1.3 alnsn rump_schedule(); 681 1.3 alnsn code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count); 682 1.3 alnsn rump_unschedule(); 683 1.3 alnsn ATF_REQUIRE(code != NULL); 684 1.3 alnsn 685 1.3 alnsn ATF_CHECK(code(&ctx, &args) == 5 + ctx.nfuncs); 686 1.3 alnsn 687 1.3 alnsn rump_schedule(); 688 1.3 alnsn rumpns_bpfjit_free_code(code); 689 1.3 alnsn rump_unschedule(); 690 1.3 alnsn } 691 1.3 alnsn 692 1.1 alnsn ATF_TC(bpfjit_copx_invalid_index); 693 1.1 alnsn ATF_TC_HEAD(bpfjit_copx_invalid_index, tc) 694 1.1 alnsn { 695 1.1 alnsn atf_tc_set_md_var(tc, "descr", 696 1.1 alnsn "Test that out-of-range BPF_COPX call fails at runtime"); 697 1.1 alnsn } 698 1.1 alnsn 699 1.1 alnsn ATF_TC_BODY(bpfjit_copx_invalid_index, tc) 700 1.1 alnsn { 701 1.1 alnsn static struct bpf_insn insns[] = { 702 1.1 alnsn BPF_STMT(BPF_LDX+BPF_IMM, 5), // invalid index 703 1.1 alnsn BPF_STMT(BPF_MISC+BPF_COPX, 0), 704 1.1 alnsn BPF_STMT(BPF_RET+BPF_K, 27) 705 1.1 alnsn }; 706 1.1 alnsn 707 1.1 alnsn bpfjit_func_t code; 708 1.1 alnsn uint8_t pkt[1] = { 0 }; 709 1.1 alnsn bpf_args_t args = { 710 1.1 alnsn .pkt = pkt, 711 1.1 alnsn .buflen = sizeof(pkt), 712 1.1 alnsn .wirelen = sizeof(pkt) 713 1.1 alnsn }; 714 1.1 alnsn 715 1.1 alnsn size_t insn_count = sizeof(insns) / sizeof(insns[0]); 716 1.1 alnsn 717 1.1 alnsn RZ(rump_init()); 718 1.1 alnsn 719 1.1 alnsn rump_schedule(); 720 1.1 alnsn code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count); 721 1.1 alnsn rump_unschedule(); 722 1.1 alnsn ATF_REQUIRE(code != NULL); 723 1.1 alnsn 724 1.1 alnsn ATF_CHECK(code(&ctx, &args) == 0); 725 1.1 alnsn 726 1.1 alnsn rump_schedule(); 727 1.1 alnsn rumpns_bpfjit_free_code(code); 728 1.1 alnsn rump_unschedule(); 729 1.1 alnsn } 730 1.1 alnsn 731 1.1 alnsn ATF_TP_ADD_TCS(tp) 732 1.1 alnsn { 733 1.1 alnsn 734 1.1 alnsn /* 735 1.1 alnsn * For every new test please also add a similar test 736 1.1 alnsn * to ../../lib/libbpfjit/t_cop.c 737 1.1 alnsn */ 738 1.1 alnsn ATF_TP_ADD_TC(tp, bpfjit_cop_no_ctx); 739 1.1 alnsn ATF_TP_ADD_TC(tp, bpfjit_cop_ret_A); 740 1.1 alnsn ATF_TP_ADD_TC(tp, bpfjit_cop_ret_buflen); 741 1.1 alnsn ATF_TP_ADD_TC(tp, bpfjit_cop_ret_wirelen); 742 1.1 alnsn ATF_TP_ADD_TC(tp, bpfjit_cop_ret_nfuncs); 743 1.1 alnsn ATF_TP_ADD_TC(tp, bpfjit_cop_side_effect); 744 1.3 alnsn ATF_TP_ADD_TC(tp, bpfjit_cop_copx); 745 1.1 alnsn ATF_TP_ADD_TC(tp, bpfjit_cop_invalid_index); 746 1.1 alnsn 747 1.1 alnsn ATF_TP_ADD_TC(tp, bpfjit_copx_no_ctx); 748 1.1 alnsn ATF_TP_ADD_TC(tp, bpfjit_copx_ret_A); 749 1.1 alnsn ATF_TP_ADD_TC(tp, bpfjit_copx_ret_buflen); 750 1.1 alnsn ATF_TP_ADD_TC(tp, bpfjit_copx_ret_wirelen); 751 1.1 alnsn ATF_TP_ADD_TC(tp, bpfjit_copx_ret_nfuncs); 752 1.1 alnsn ATF_TP_ADD_TC(tp, bpfjit_copx_side_effect); 753 1.3 alnsn ATF_TP_ADD_TC(tp, bpfjit_copx_cop); 754 1.1 alnsn ATF_TP_ADD_TC(tp, bpfjit_copx_invalid_index); 755 1.1 alnsn 756 1.1 alnsn return atf_no_error(); 757 1.1 alnsn } 758