• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 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 	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 */
258 static __printf(2, 3)
test_prf(void * out,const char * fmt,...)259 int 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 
vcap_api_addr_keyset_test(struct kunit * test)292 static 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 
vcap_api_show_admin_raw_test(struct kunit * test)343 static 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 
380 static 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 
vcap_api_show_admin_test(struct kunit * test)401 static 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 
428 static 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 
vcap_api_show_admin_rule_test(struct kunit * test)474 static 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 
541 static 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 
549 static struct kunit_suite vcap_api_debugfs_test_suite = {
550 	.name = "VCAP_API_DebugFS_Testsuite",
551 	.test_cases = vcap_api_debugfs_test_cases,
552 };
553 
554 kunit_test_suite(vcap_api_debugfs_test_suite);
555