1 // SPDX-License-Identifier: BSD-3-Clause 2 /* Copyright (C) 2022 Microchip Technology Inc. and its subsidiaries. 3 * Microchip VCAP API kunit test suite 4 */ 5 6 #include <kunit/test.h> 7 #include "vcap_api.h" 8 #include "vcap_api_client.h" 9 #include "vcap_api_debugfs.h" 10 #include "vcap_model_kunit.h" 11 12 /* First we have the test infrastructure that emulates the platform 13 * implementation 14 */ 15 #define TEST_BUF_CNT 100 16 #define TEST_BUF_SZ 350 17 #define STREAMWSIZE 64 18 19 static u32 test_updateaddr[STREAMWSIZE] = {}; 20 static int test_updateaddridx; 21 static int test_cache_erase_count; 22 static u32 test_init_start; 23 static u32 test_init_count; 24 static u32 test_hw_counter_id; 25 static struct vcap_cache_data test_hw_cache; 26 static struct net_device test_netdev = {}; 27 static int test_move_addr; 28 static int test_move_offset; 29 static int test_move_count; 30 static char test_pr_buffer[TEST_BUF_CNT][TEST_BUF_SZ]; 31 static int test_pr_bufferidx; 32 static int test_pr_idx; 33 34 /* Callback used by the VCAP API */ 35 static enum vcap_keyfield_set test_val_keyset(struct net_device *ndev, 36 struct vcap_admin *admin, 37 struct vcap_rule *rule, 38 struct vcap_keyset_list *kslist, 39 u16 l3_proto) 40 { 41 int idx; 42 43 if (kslist->cnt > 0) { 44 switch (admin->vtype) { 45 case VCAP_TYPE_IS0: 46 for (idx = 0; idx < kslist->cnt; idx++) { 47 if (kslist->keysets[idx] == VCAP_KFS_ETAG) 48 return kslist->keysets[idx]; 49 if (kslist->keysets[idx] == 50 VCAP_KFS_PURE_5TUPLE_IP4) 51 return kslist->keysets[idx]; 52 if (kslist->keysets[idx] == 53 VCAP_KFS_NORMAL_5TUPLE_IP4) 54 return kslist->keysets[idx]; 55 if (kslist->keysets[idx] == 56 VCAP_KFS_NORMAL_7TUPLE) 57 return kslist->keysets[idx]; 58 } 59 break; 60 case VCAP_TYPE_IS2: 61 for (idx = 0; idx < kslist->cnt; idx++) { 62 if (kslist->keysets[idx] == VCAP_KFS_MAC_ETYPE) 63 return kslist->keysets[idx]; 64 if (kslist->keysets[idx] == VCAP_KFS_ARP) 65 return kslist->keysets[idx]; 66 if (kslist->keysets[idx] == VCAP_KFS_IP_7TUPLE) 67 return kslist->keysets[idx]; 68 } 69 break; 70 default: 71 pr_info("%s:%d: no validation for VCAP %d\n", 72 __func__, __LINE__, admin->vtype); 73 break; 74 } 75 } 76 return -EINVAL; 77 } 78 79 /* Callback used by the VCAP API */ 80 static void test_add_def_fields(struct net_device *ndev, 81 struct vcap_admin *admin, 82 struct vcap_rule *rule) 83 { 84 if (admin->vinst == 0 || admin->vinst == 2) 85 vcap_rule_add_key_bit(rule, VCAP_KF_LOOKUP_FIRST_IS, 86 VCAP_BIT_1); 87 else 88 vcap_rule_add_key_bit(rule, VCAP_KF_LOOKUP_FIRST_IS, 89 VCAP_BIT_0); 90 } 91 92 /* Callback used by the VCAP API */ 93 static void test_cache_erase(struct vcap_admin *admin) 94 { 95 if (test_cache_erase_count) { 96 memset(admin->cache.keystream, 0, test_cache_erase_count); 97 memset(admin->cache.maskstream, 0, test_cache_erase_count); 98 memset(admin->cache.actionstream, 0, test_cache_erase_count); 99 test_cache_erase_count = 0; 100 } 101 } 102 103 /* Callback used by the VCAP API */ 104 static void test_cache_init(struct net_device *ndev, struct vcap_admin *admin, 105 u32 start, u32 count) 106 { 107 test_init_start = start; 108 test_init_count = count; 109 } 110 111 /* Callback used by the VCAP API */ 112 static void test_cache_read(struct net_device *ndev, struct vcap_admin *admin, 113 enum vcap_selection sel, u32 start, u32 count) 114 { 115 u32 *keystr, *mskstr, *actstr; 116 int idx; 117 118 pr_debug("%s:%d: %d %d\n", __func__, __LINE__, start, count); 119 switch (sel) { 120 case VCAP_SEL_ENTRY: 121 keystr = &admin->cache.keystream[start]; 122 mskstr = &admin->cache.maskstream[start]; 123 for (idx = 0; idx < count; ++idx) { 124 pr_debug("%s:%d: keydata[%02d]: 0x%08x\n", __func__, 125 __LINE__, start + idx, keystr[idx]); 126 } 127 for (idx = 0; idx < count; ++idx) { 128 /* Invert the mask before decoding starts */ 129 mskstr[idx] = ~mskstr[idx]; 130 pr_debug("%s:%d: mskdata[%02d]: 0x%08x\n", __func__, 131 __LINE__, start + idx, mskstr[idx]); 132 } 133 break; 134 case VCAP_SEL_ACTION: 135 actstr = &admin->cache.actionstream[start]; 136 for (idx = 0; idx < count; ++idx) { 137 pr_debug("%s:%d: actdata[%02d]: 0x%08x\n", __func__, 138 __LINE__, start + idx, actstr[idx]); 139 } 140 break; 141 case VCAP_SEL_COUNTER: 142 pr_debug("%s:%d\n", __func__, __LINE__); 143 test_hw_counter_id = start; 144 admin->cache.counter = test_hw_cache.counter; 145 admin->cache.sticky = test_hw_cache.sticky; 146 break; 147 case VCAP_SEL_ALL: 148 pr_debug("%s:%d\n", __func__, __LINE__); 149 break; 150 } 151 } 152 153 /* Callback used by the VCAP API */ 154 static void test_cache_write(struct net_device *ndev, struct vcap_admin *admin, 155 enum vcap_selection sel, u32 start, u32 count) 156 { 157 u32 *keystr, *mskstr, *actstr; 158 int idx; 159 160 switch (sel) { 161 case VCAP_SEL_ENTRY: 162 keystr = &admin->cache.keystream[start]; 163 mskstr = &admin->cache.maskstream[start]; 164 for (idx = 0; idx < count; ++idx) { 165 pr_debug("%s:%d: keydata[%02d]: 0x%08x\n", __func__, 166 __LINE__, start + idx, keystr[idx]); 167 } 168 for (idx = 0; idx < count; ++idx) { 169 /* Invert the mask before encoding starts */ 170 mskstr[idx] = ~mskstr[idx]; 171 pr_debug("%s:%d: mskdata[%02d]: 0x%08x\n", __func__, 172 __LINE__, start + idx, mskstr[idx]); 173 } 174 break; 175 case VCAP_SEL_ACTION: 176 actstr = &admin->cache.actionstream[start]; 177 for (idx = 0; idx < count; ++idx) { 178 pr_debug("%s:%d: actdata[%02d]: 0x%08x\n", __func__, 179 __LINE__, start + idx, actstr[idx]); 180 } 181 break; 182 case VCAP_SEL_COUNTER: 183 pr_debug("%s:%d\n", __func__, __LINE__); 184 test_hw_counter_id = start; 185 test_hw_cache.counter = admin->cache.counter; 186 test_hw_cache.sticky = admin->cache.sticky; 187 break; 188 case VCAP_SEL_ALL: 189 pr_err("%s:%d: cannot write all streams at once\n", 190 __func__, __LINE__); 191 break; 192 } 193 } 194 195 /* Callback used by the VCAP API */ 196 static void test_cache_update(struct net_device *ndev, struct vcap_admin *admin, 197 enum vcap_command cmd, 198 enum vcap_selection sel, u32 addr) 199 { 200 if (test_updateaddridx < ARRAY_SIZE(test_updateaddr)) 201 test_updateaddr[test_updateaddridx] = addr; 202 else 203 pr_err("%s:%d: overflow: %d\n", __func__, __LINE__, 204 test_updateaddridx); 205 test_updateaddridx++; 206 } 207 208 static void test_cache_move(struct net_device *ndev, struct vcap_admin *admin, 209 u32 addr, int offset, int count) 210 { 211 test_move_addr = addr; 212 test_move_offset = offset; 213 test_move_count = count; 214 } 215 216 /* Provide port information via a callback interface */ 217 static int vcap_test_port_info(struct net_device *ndev, 218 struct vcap_admin *admin, 219 struct vcap_output_print *out) 220 { 221 return 0; 222 } 223 224 static int vcap_test_enable(struct net_device *ndev, 225 struct vcap_admin *admin, 226 bool enable) 227 { 228 return 0; 229 } 230 231 static struct vcap_operations test_callbacks = { 232 .validate_keyset = test_val_keyset, 233 .add_default_fields = test_add_def_fields, 234 .cache_erase = test_cache_erase, 235 .cache_write = test_cache_write, 236 .cache_read = test_cache_read, 237 .init = test_cache_init, 238 .update = test_cache_update, 239 .move = test_cache_move, 240 .port_info = vcap_test_port_info, 241 .enable = vcap_test_enable, 242 }; 243 244 static struct vcap_control test_vctrl = { 245 .vcaps = kunit_test_vcaps, 246 .stats = &kunit_test_vcap_stats, 247 .ops = &test_callbacks, 248 }; 249 250 static void vcap_test_api_init(struct vcap_admin *admin) 251 { 252 /* Initialize the shared objects */ 253 INIT_LIST_HEAD(&test_vctrl.list); 254 INIT_LIST_HEAD(&admin->list); 255 INIT_LIST_HEAD(&admin->rules); 256 list_add_tail(&admin->list, &test_vctrl.list); 257 memset(test_updateaddr, 0, sizeof(test_updateaddr)); 258 test_updateaddridx = 0; 259 test_pr_bufferidx = 0; 260 test_pr_idx = 0; 261 } 262 263 /* callback used by the show_admin function */ 264 static __printf(2, 3) 265 int test_prf(void *out, const char *fmt, ...) 266 { 267 static char test_buffer[TEST_BUF_SZ]; 268 va_list args; 269 int idx, cnt; 270 271 if (test_pr_bufferidx >= TEST_BUF_CNT) { 272 pr_err("%s:%d: overflow: %d\n", __func__, __LINE__, 273 test_pr_bufferidx); 274 return 0; 275 } 276 277 va_start(args, fmt); 278 cnt = vscnprintf(test_buffer, TEST_BUF_SZ, fmt, args); 279 va_end(args); 280 281 for (idx = 0; idx < cnt; ++idx) { 282 test_pr_buffer[test_pr_bufferidx][test_pr_idx] = 283 test_buffer[idx]; 284 if (test_buffer[idx] == '\n') { 285 test_pr_buffer[test_pr_bufferidx][++test_pr_idx] = 0; 286 test_pr_idx = 0; 287 test_pr_bufferidx++; 288 } else { 289 ++test_pr_idx; 290 } 291 } 292 293 return cnt; 294 } 295 296 /* Define the test cases. */ 297 298 static void vcap_api_addr_keyset_test(struct kunit *test) 299 { 300 u32 keydata[12] = { 301 0x40450042, 0x000feaf3, 0x00000003, 0x00050600, 302 0x10203040, 0x00075880, 0x633c6864, 0x00040003, 303 0x00000020, 0x00000008, 0x00000240, 0x00000000, 304 }; 305 u32 mskdata[12] = { 306 0x0030ff80, 0xfff00000, 0xfffffffc, 0xfff000ff, 307 0x00000000, 0xfff00000, 0x00000000, 0xfff3fffc, 308 0xffffffc0, 0xffffffff, 0xfffffc03, 0xffffffff, 309 }; 310 u32 actdata[12] = {}; 311 struct vcap_admin admin = { 312 .vtype = VCAP_TYPE_IS2, 313 .cache = { 314 .keystream = keydata, 315 .maskstream = mskdata, 316 .actionstream = actdata, 317 }, 318 }; 319 int ret, idx, addr; 320 321 vcap_test_api_init(&admin); 322 323 /* Go from higher to lower addresses searching for a keyset */ 324 for (idx = ARRAY_SIZE(keydata) - 1, addr = 799; idx > 0; 325 --idx, --addr) { 326 admin.cache.keystream = &keydata[idx]; 327 admin.cache.maskstream = &mskdata[idx]; 328 ret = vcap_addr_keyset(&test_vctrl, &test_netdev, &admin, addr); 329 KUNIT_EXPECT_EQ(test, -EINVAL, ret); 330 } 331 332 /* Finally we hit the start of the rule */ 333 admin.cache.keystream = &keydata[idx]; 334 admin.cache.maskstream = &mskdata[idx]; 335 ret = vcap_addr_keyset(&test_vctrl, &test_netdev, &admin, addr); 336 KUNIT_EXPECT_EQ(test, VCAP_KFS_MAC_ETYPE, ret); 337 } 338 339 static void vcap_api_show_admin_raw_test(struct kunit *test) 340 { 341 u32 keydata[4] = { 342 0x40450042, 0x000feaf3, 0x00000003, 0x00050600, 343 }; 344 u32 mskdata[4] = { 345 0x0030ff80, 0xfff00000, 0xfffffffc, 0xfff000ff, 346 }; 347 u32 actdata[12] = {}; 348 struct vcap_admin admin = { 349 .vtype = VCAP_TYPE_IS2, 350 .cache = { 351 .keystream = keydata, 352 .maskstream = mskdata, 353 .actionstream = actdata, 354 }, 355 .first_valid_addr = 786, 356 .last_valid_addr = 788, 357 }; 358 struct vcap_rule_internal ri = { 359 .ndev = &test_netdev, 360 }; 361 struct vcap_output_print out = { 362 .prf = (void *)test_prf, 363 }; 364 const char *test_expected = 365 " addr: 786, X6 rule, keyset: VCAP_KFS_MAC_ETYPE\n"; 366 int ret; 367 368 vcap_test_api_init(&admin); 369 list_add_tail(&ri.list, &admin.rules); 370 371 ret = vcap_show_admin_raw(&test_vctrl, &admin, &out); 372 KUNIT_EXPECT_EQ(test, 0, ret); 373 KUNIT_EXPECT_STREQ(test, test_expected, test_pr_buffer[0]); 374 } 375 376 static const char * const test_admin_info_expect[] = { 377 "name: is2\n", 378 "rows: 256\n", 379 "sw_count: 12\n", 380 "sw_width: 52\n", 381 "sticky_width: 1\n", 382 "act_width: 110\n", 383 "default_cnt: 73\n", 384 "require_cnt_dis: 0\n", 385 "version: 1\n", 386 "vtype: 2\n", 387 "vinst: 0\n", 388 "first_cid: 10000\n", 389 "last_cid: 19999\n", 390 "lookups: 4\n", 391 "first_valid_addr: 0\n", 392 "last_valid_addr: 3071\n", 393 "last_used_addr: 794\n", 394 }; 395 396 static void vcap_api_show_admin_test(struct kunit *test) 397 { 398 struct vcap_admin admin = { 399 .vtype = VCAP_TYPE_IS2, 400 .first_cid = 10000, 401 .last_cid = 19999, 402 .lookups = 4, 403 .last_valid_addr = 3071, 404 .first_valid_addr = 0, 405 .last_used_addr = 794, 406 }; 407 struct vcap_output_print out = { 408 .prf = (void *)test_prf, 409 }; 410 int idx; 411 412 vcap_test_api_init(&admin); 413 414 vcap_show_admin_info(&test_vctrl, &admin, &out); 415 for (idx = 0; idx < test_pr_bufferidx; ++idx) { 416 /* pr_info("log[%02d]: %s", idx, test_pr_buffer[idx]); */ 417 KUNIT_EXPECT_STREQ(test, test_admin_info_expect[idx], 418 test_pr_buffer[idx]); 419 } 420 } 421 422 static const char * const test_admin_expect[] = { 423 "name: is2\n", 424 "rows: 256\n", 425 "sw_count: 12\n", 426 "sw_width: 52\n", 427 "sticky_width: 1\n", 428 "act_width: 110\n", 429 "default_cnt: 73\n", 430 "require_cnt_dis: 0\n", 431 "version: 1\n", 432 "vtype: 2\n", 433 "vinst: 0\n", 434 "first_cid: 8000000\n", 435 "last_cid: 8199999\n", 436 "lookups: 4\n", 437 "first_valid_addr: 0\n", 438 "last_valid_addr: 3071\n", 439 "last_used_addr: 794\n", 440 "\n", 441 "rule: 100, addr: [794,799], X6, ctr[0]: 0, hit: 0\n", 442 " chain_id: 0\n", 443 " user: 0\n", 444 " priority: 0\n", 445 " keyset: VCAP_KFS_MAC_ETYPE\n", 446 " keyset_sw: 6\n", 447 " keyset_sw_regs: 2\n", 448 " ETYPE_LEN_IS: W1: 1/1\n", 449 " IF_IGR_PORT_MASK: W32: 0xffabcd01/0xffffffff\n", 450 " IF_IGR_PORT_MASK_RNG: W4: 5/15\n", 451 " L2_DMAC: W48: 01:02:03:04:05:06/ff:ff:ff:ff:ff:ff\n", 452 " L2_PAYLOAD_ETYPE: W64: 0x9000002000000081/0xff000000000000ff\n", 453 " L2_SMAC: W48: b1:9e:34:32:75:88/ff:ff:ff:ff:ff:ff\n", 454 " LOOKUP_FIRST_IS: W1: 1/1\n", 455 " TYPE: W4: 0/15\n", 456 " actionset: VCAP_AFS_BASE_TYPE\n", 457 " actionset_sw: 3\n", 458 " actionset_sw_regs: 4\n", 459 " CNT_ID: W12: 100\n", 460 " MATCH_ID: W16: 1\n", 461 " MATCH_ID_MASK: W16: 1\n", 462 " POLICE_ENA: W1: 1\n", 463 " PORT_MASK: W68: 0x0514670115f3324589\n", 464 }; 465 466 static void vcap_api_show_admin_rule_test(struct kunit *test) 467 { 468 u32 keydata[] = { 469 0x40450042, 0x000feaf3, 0x00000003, 0x00050600, 470 0x10203040, 0x00075880, 0x633c6864, 0x00040003, 471 0x00000020, 0x00000008, 0x00000240, 0x00000000, 472 }; 473 u32 mskdata[] = { 474 0x0030ff80, 0xfff00000, 0xfffffffc, 0xfff000ff, 475 0x00000000, 0xfff00000, 0x00000000, 0xfff3fffc, 476 0xffffffc0, 0xffffffff, 0xfffffc03, 0xffffffff, 477 }; 478 u32 actdata[] = { 479 0x00040002, 0xf3324589, 0x14670115, 0x00000005, 480 0x00000000, 0x00100000, 0x06400010, 0x00000000, 481 0x00000000, 0x00000000, 0x00000000, 0x00000000, 482 0x00000000, 0x00000000, 0x00000000, 0x00000000, 483 0x00000000, 0x00000000, 0x00000000, 0x00000000, 484 0x00000000, 0x00000000, 0x00000000, 0x00000000, 485 }; 486 struct vcap_admin admin = { 487 .vtype = VCAP_TYPE_IS2, 488 .first_cid = 8000000, 489 .last_cid = 8199999, 490 .lookups = 4, 491 .last_valid_addr = 3071, 492 .first_valid_addr = 0, 493 .last_used_addr = 794, 494 .cache = { 495 .keystream = keydata, 496 .maskstream = mskdata, 497 .actionstream = actdata, 498 }, 499 }; 500 struct vcap_rule_internal ri = { 501 .admin = &admin, 502 .data = { 503 .id = 100, 504 .keyset = VCAP_KFS_MAC_ETYPE, 505 .actionset = VCAP_AFS_BASE_TYPE, 506 }, 507 .size = 6, 508 .keyset_sw = 6, 509 .keyset_sw_regs = 2, 510 .actionset_sw = 3, 511 .actionset_sw_regs = 4, 512 .addr = 794, 513 .vctrl = &test_vctrl, 514 }; 515 struct vcap_output_print out = { 516 .prf = (void *)test_prf, 517 }; 518 int ret, idx; 519 520 vcap_test_api_init(&admin); 521 list_add_tail(&ri.list, &admin.rules); 522 523 ret = vcap_show_admin(&test_vctrl, &admin, &out); 524 KUNIT_EXPECT_EQ(test, 0, ret); 525 for (idx = 0; idx < test_pr_bufferidx; ++idx) { 526 /* pr_info("log[%02d]: %s", idx, test_pr_buffer[idx]); */ 527 KUNIT_EXPECT_STREQ(test, test_admin_expect[idx], 528 test_pr_buffer[idx]); 529 } 530 } 531 532 static struct kunit_case vcap_api_debugfs_test_cases[] = { 533 KUNIT_CASE(vcap_api_addr_keyset_test), 534 KUNIT_CASE(vcap_api_show_admin_raw_test), 535 KUNIT_CASE(vcap_api_show_admin_test), 536 KUNIT_CASE(vcap_api_show_admin_rule_test), 537 {} 538 }; 539 540 static struct kunit_suite vcap_api_debugfs_test_suite = { 541 .name = "VCAP_API_DebugFS_Testsuite", 542 .test_cases = vcap_api_debugfs_test_cases, 543 }; 544 545 kunit_test_suite(vcap_api_debugfs_test_suite); 546