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