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 */
test_val_keyset(struct net_device * ndev,struct vcap_admin * admin,struct vcap_rule * rule,struct vcap_keyset_list * kslist,u16 l3_proto)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 */
test_add_def_fields(struct net_device * ndev,struct vcap_admin * admin,struct vcap_rule * rule)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 */
test_cache_erase(struct vcap_admin * admin)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 */
test_cache_init(struct net_device * ndev,struct vcap_admin * admin,u32 start,u32 count)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 */
test_cache_read(struct net_device * ndev,struct vcap_admin * admin,enum vcap_selection sel,u32 start,u32 count)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 */
test_cache_write(struct net_device * ndev,struct vcap_admin * admin,enum vcap_selection sel,u32 start,u32 count)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 */
test_cache_update(struct net_device * ndev,struct vcap_admin * admin,enum vcap_command cmd,enum vcap_selection sel,u32 addr)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
test_cache_move(struct net_device * ndev,struct vcap_admin * admin,u32 addr,int offset,int count)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 */
vcap_test_port_info(struct net_device * ndev,struct vcap_admin * admin,struct vcap_output_print * out)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 const struct vcap_operations test_callbacks = {
225 .validate_keyset = test_val_keyset,
226 .add_default_fields = test_add_def_fields,
227 .cache_erase = test_cache_erase,
228 .cache_write = test_cache_write,
229 .cache_read = test_cache_read,
230 .init = test_cache_init,
231 .update = test_cache_update,
232 .move = test_cache_move,
233 .port_info = vcap_test_port_info,
234 };
235
236 static struct vcap_control test_vctrl = {
237 .vcaps = kunit_test_vcaps,
238 .stats = &kunit_test_vcap_stats,
239 .ops = &test_callbacks,
240 };
241
vcap_test_api_init(struct vcap_admin * admin)242 static void vcap_test_api_init(struct vcap_admin *admin)
243 {
244 /* Initialize the shared objects */
245 INIT_LIST_HEAD(&test_vctrl.list);
246 mutex_init(&test_vctrl.lock);
247 INIT_LIST_HEAD(&admin->list);
248 INIT_LIST_HEAD(&admin->rules);
249 INIT_LIST_HEAD(&admin->enabled);
250 admin->vctrl = &test_vctrl;
251 list_add_tail(&admin->list, &test_vctrl.list);
252 memset(test_updateaddr, 0, sizeof(test_updateaddr));
253 test_updateaddridx = 0;
254 test_pr_bufferidx = 0;
255 test_pr_idx = 0;
256 }
257
258 /* callback used by the show_admin function */
259 static __printf(2, 3)
test_prf(void * out,const char * fmt,...)260 int test_prf(void *out, const char *fmt, ...)
261 {
262 static char test_buffer[TEST_BUF_SZ];
263 va_list args;
264 int idx, cnt;
265
266 if (test_pr_bufferidx >= TEST_BUF_CNT) {
267 pr_err("%s:%d: overflow: %d\n", __func__, __LINE__,
268 test_pr_bufferidx);
269 return 0;
270 }
271
272 va_start(args, fmt);
273 cnt = vscnprintf(test_buffer, TEST_BUF_SZ, fmt, args);
274 va_end(args);
275
276 for (idx = 0; idx < cnt; ++idx) {
277 test_pr_buffer[test_pr_bufferidx][test_pr_idx] =
278 test_buffer[idx];
279 if (test_buffer[idx] == '\n') {
280 test_pr_buffer[test_pr_bufferidx][++test_pr_idx] = 0;
281 test_pr_idx = 0;
282 test_pr_bufferidx++;
283 } else {
284 ++test_pr_idx;
285 }
286 }
287
288 return cnt;
289 }
290
291 /* Define the test cases. */
292
vcap_api_addr_keyset_test(struct kunit * test)293 static void vcap_api_addr_keyset_test(struct kunit *test)
294 {
295 u32 keydata[12] = {
296 0x40450042, 0x000feaf3, 0x00000003, 0x00050600,
297 0x10203040, 0x00075880, 0x633c6864, 0x00040003,
298 0x00000020, 0x00000008, 0x00000240, 0x00000000,
299 };
300 u32 mskdata[12] = {
301 0x0030ff80, 0xfff00000, 0xfffffffc, 0xfff000ff,
302 0x00000000, 0xfff00000, 0x00000000, 0xfff3fffc,
303 0xffffffc0, 0xffffffff, 0xfffffc03, 0xffffffff,
304 };
305 u32 actdata[12] = {};
306 struct vcap_admin admin = {
307 .vtype = VCAP_TYPE_IS2,
308 .cache = {
309 .keystream = keydata,
310 .maskstream = mskdata,
311 .actionstream = actdata,
312 },
313 };
314 enum vcap_keyfield_set keysets[10];
315 struct vcap_keyset_list matches;
316 int ret, idx, addr;
317
318 vcap_test_api_init(&admin);
319
320 /* Go from higher to lower addresses searching for a keyset */
321 matches.keysets = keysets;
322 matches.cnt = 0;
323 matches.max = ARRAY_SIZE(keysets);
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_keysets(&test_vctrl, &test_netdev, &admin,
329 addr, &matches);
330 KUNIT_EXPECT_EQ(test, -EINVAL, ret);
331 }
332
333 /* Finally we hit the start of the rule */
334 admin.cache.keystream = &keydata[idx];
335 admin.cache.maskstream = &mskdata[idx];
336 matches.cnt = 0;
337 ret = vcap_addr_keysets(&test_vctrl, &test_netdev, &admin,
338 addr, &matches);
339 KUNIT_EXPECT_EQ(test, 0, ret);
340 KUNIT_EXPECT_EQ(test, matches.cnt, 1);
341 KUNIT_EXPECT_EQ(test, matches.keysets[0], VCAP_KFS_MAC_ETYPE);
342 }
343
vcap_api_show_admin_raw_test(struct kunit * test)344 static void vcap_api_show_admin_raw_test(struct kunit *test)
345 {
346 u32 keydata[4] = {
347 0x40450042, 0x000feaf3, 0x00000003, 0x00050600,
348 };
349 u32 mskdata[4] = {
350 0x0030ff80, 0xfff00000, 0xfffffffc, 0xfff000ff,
351 };
352 u32 actdata[12] = {};
353 struct vcap_admin admin = {
354 .vtype = VCAP_TYPE_IS2,
355 .cache = {
356 .keystream = keydata,
357 .maskstream = mskdata,
358 .actionstream = actdata,
359 },
360 .first_valid_addr = 786,
361 .last_valid_addr = 788,
362 };
363 struct vcap_rule_internal ri = {
364 .ndev = &test_netdev,
365 };
366 struct vcap_output_print out = {
367 .prf = (void *)test_prf,
368 };
369 const char *test_expected =
370 " addr: 786, X6 rule, keysets: VCAP_KFS_MAC_ETYPE\n";
371 int ret;
372
373 vcap_test_api_init(&admin);
374 list_add_tail(&ri.list, &admin.rules);
375
376 ret = vcap_show_admin_raw(&test_vctrl, &admin, &out);
377 KUNIT_EXPECT_EQ(test, 0, ret);
378 KUNIT_EXPECT_STREQ(test, test_expected, test_pr_buffer[0]);
379 }
380
381 static const char * const test_admin_info_expect[] = {
382 "name: is2\n",
383 "rows: 256\n",
384 "sw_count: 12\n",
385 "sw_width: 52\n",
386 "sticky_width: 1\n",
387 "act_width: 110\n",
388 "default_cnt: 73\n",
389 "require_cnt_dis: 0\n",
390 "version: 1\n",
391 "vtype: 4\n",
392 "vinst: 0\n",
393 "ingress: 1\n",
394 "first_cid: 10000\n",
395 "last_cid: 19999\n",
396 "lookups: 4\n",
397 "first_valid_addr: 0\n",
398 "last_valid_addr: 3071\n",
399 "last_used_addr: 794\n",
400 };
401
vcap_api_show_admin_test(struct kunit * test)402 static void vcap_api_show_admin_test(struct kunit *test)
403 {
404 struct vcap_admin admin = {
405 .vtype = VCAP_TYPE_IS2,
406 .first_cid = 10000,
407 .last_cid = 19999,
408 .lookups = 4,
409 .last_valid_addr = 3071,
410 .first_valid_addr = 0,
411 .last_used_addr = 794,
412 .ingress = true,
413 };
414 struct vcap_output_print out = {
415 .prf = (void *)test_prf,
416 };
417 int idx;
418
419 vcap_test_api_init(&admin);
420
421 vcap_show_admin_info(&test_vctrl, &admin, &out);
422 for (idx = 0; idx < test_pr_bufferidx; ++idx) {
423 /* pr_info("log[%02d]: %s", idx, test_pr_buffer[idx]); */
424 KUNIT_EXPECT_STREQ(test, test_admin_info_expect[idx],
425 test_pr_buffer[idx]);
426 }
427 }
428
429 static const char * const test_admin_expect[] = {
430 "name: is2\n",
431 "rows: 256\n",
432 "sw_count: 12\n",
433 "sw_width: 52\n",
434 "sticky_width: 1\n",
435 "act_width: 110\n",
436 "default_cnt: 73\n",
437 "require_cnt_dis: 0\n",
438 "version: 1\n",
439 "vtype: 4\n",
440 "vinst: 0\n",
441 "ingress: 1\n",
442 "first_cid: 8000000\n",
443 "last_cid: 8199999\n",
444 "lookups: 4\n",
445 "first_valid_addr: 0\n",
446 "last_valid_addr: 3071\n",
447 "last_used_addr: 794\n",
448 "\n",
449 "rule: 100, addr: [794,799], X6, ctr[0]: 0, hit: 0\n",
450 " chain_id: 0\n",
451 " user: 0\n",
452 " priority: 0\n",
453 " state: permanent\n",
454 " keysets: VCAP_KFS_MAC_ETYPE\n",
455 " keyset_sw: 6\n",
456 " keyset_sw_regs: 2\n",
457 " ETYPE_LEN_IS: W1: 1/1\n",
458 " IF_IGR_PORT_MASK: W32: 0xffabcd01/0xffffffff\n",
459 " IF_IGR_PORT_MASK_RNG: W4: 5/15\n",
460 " L2_DMAC: W48: 01:02:03:04:05:06/ff:ff:ff:ff:ff:ff\n",
461 " L2_PAYLOAD_ETYPE: W64: 0x9000002000000081/0xff000000000000ff\n",
462 " L2_SMAC: W48: b1:9e:34:32:75:88/ff:ff:ff:ff:ff:ff\n",
463 " LOOKUP_FIRST_IS: W1: 1/1\n",
464 " TYPE: W4: 0/15\n",
465 " actionset: VCAP_AFS_BASE_TYPE\n",
466 " actionset_sw: 3\n",
467 " actionset_sw_regs: 4\n",
468 " CNT_ID: W12: 100\n",
469 " MATCH_ID: W16: 1\n",
470 " MATCH_ID_MASK: W16: 1\n",
471 " POLICE_ENA: W1: 1\n",
472 " PORT_MASK: W68: 0x0514670115f3324589\n",
473 };
474
vcap_api_show_admin_rule_test(struct kunit * test)475 static void vcap_api_show_admin_rule_test(struct kunit *test)
476 {
477 u32 keydata[] = {
478 0x40450042, 0x000feaf3, 0x00000003, 0x00050600,
479 0x10203040, 0x00075880, 0x633c6864, 0x00040003,
480 0x00000020, 0x00000008, 0x00000240, 0x00000000,
481 };
482 u32 mskdata[] = {
483 0x0030ff80, 0xfff00000, 0xfffffffc, 0xfff000ff,
484 0x00000000, 0xfff00000, 0x00000000, 0xfff3fffc,
485 0xffffffc0, 0xffffffff, 0xfffffc03, 0xffffffff,
486 };
487 u32 actdata[] = {
488 0x00040002, 0xf3324589, 0x14670115, 0x00000005,
489 0x00000000, 0x00100000, 0x06400010, 0x00000000,
490 0x00000000, 0x00000000, 0x00000000, 0x00000000,
491 0x00000000, 0x00000000, 0x00000000, 0x00000000,
492 0x00000000, 0x00000000, 0x00000000, 0x00000000,
493 0x00000000, 0x00000000, 0x00000000, 0x00000000,
494 };
495 struct vcap_admin admin = {
496 .vtype = VCAP_TYPE_IS2,
497 .first_cid = 8000000,
498 .last_cid = 8199999,
499 .lookups = 4,
500 .last_valid_addr = 3071,
501 .first_valid_addr = 0,
502 .last_used_addr = 794,
503 .ingress = true,
504 .cache = {
505 .keystream = keydata,
506 .maskstream = mskdata,
507 .actionstream = actdata,
508 },
509 };
510 struct vcap_rule_internal ri = {
511 .admin = &admin,
512 .data = {
513 .id = 100,
514 .keyset = VCAP_KFS_MAC_ETYPE,
515 .actionset = VCAP_AFS_BASE_TYPE,
516 },
517 .size = 6,
518 .keyset_sw = 6,
519 .keyset_sw_regs = 2,
520 .actionset_sw = 3,
521 .actionset_sw_regs = 4,
522 .addr = 794,
523 .vctrl = &test_vctrl,
524 };
525 struct vcap_output_print out = {
526 .prf = (void *)test_prf,
527 };
528 int ret, idx;
529
530 vcap_test_api_init(&admin);
531 list_add_tail(&ri.list, &admin.rules);
532
533 ret = vcap_show_admin(&test_vctrl, &admin, &out);
534 KUNIT_EXPECT_EQ(test, 0, ret);
535 for (idx = 0; idx < test_pr_bufferidx; ++idx) {
536 /* pr_info("log[%02d]: %s", idx, test_pr_buffer[idx]); */
537 KUNIT_EXPECT_STREQ(test, test_admin_expect[idx],
538 test_pr_buffer[idx]);
539 }
540 }
541
542 static struct kunit_case vcap_api_debugfs_test_cases[] = {
543 KUNIT_CASE(vcap_api_addr_keyset_test),
544 KUNIT_CASE(vcap_api_show_admin_raw_test),
545 KUNIT_CASE(vcap_api_show_admin_test),
546 KUNIT_CASE(vcap_api_show_admin_rule_test),
547 {}
548 };
549
550 static struct kunit_suite vcap_api_debugfs_test_suite = {
551 .name = "VCAP_API_DebugFS_Testsuite",
552 .test_cases = vcap_api_debugfs_test_cases,
553 };
554
555 kunit_test_suite(vcap_api_debugfs_test_suite);
556