API Reference Manual 1.51.0
Loading...
Searching...
No Matches
odp_traffic_mgmt.c
1/* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright (c) 2015 EZchip Semiconductor Ltd.
3 * Copyright (c) 2015-2018 Linaro Limited
4 * Copyright (c) 2022 Marvell
5 */
6
15#ifndef _GNU_SOURCE
16#define _GNU_SOURCE
17#endif
18
19#include <execinfo.h>
20#include <inttypes.h>
21#include <signal.h>
22#include <sys/resource.h>
23#include <stdio.h>
24#include <stdlib.h>
25#include <string.h>
26#include <unistd.h>
27
28#include <odp_api.h>
29#include <odp/helper/odph_api.h>
30
31#define NUM_SVC_CLASSES 4
32#define USERS_PER_SVC_CLASS 2
33#define APPS_PER_USER 2
34#define TM_QUEUES_PER_APP 2
35#define NUM_USERS (USERS_PER_SVC_CLASS * NUM_SVC_CLASSES)
36#define NUM_TM_QUEUES (NUM_USERS * APPS_PER_USER * TM_QUEUES_PER_APP)
37#define TM_QUEUES_PER_USER (TM_QUEUES_PER_APP * APPS_PER_USER)
38#define TM_QUEUES_PER_CLASS (USERS_PER_SVC_CLASS * TM_QUEUES_PER_USER)
39#define MAX_NODES_PER_LEVEL (NUM_USERS * APPS_PER_USER)
40
41#define KBPS 1000
42#define MBPS 1000000
43#define PERCENT(percent) (100 * percent)
44
45#define FALSE 0
46#define TRUE 1
47
48#define RANDOM_BUF_LEN 1024
49
50typedef struct {
51 odp_tm_shaper_params_t shaper_params;
52 odp_tm_threshold_params_t threshold_params;
54} profile_params_set_t;
55
56typedef struct {
57 odp_tm_shaper_t shaper_profile;
58 odp_tm_threshold_t threshold_profile;
60} profile_set_t;
61
62static const odp_init_t ODP_INIT_PARAMS = {
64 .abort_fn = odp_override_abort
65};
66
67static profile_params_set_t COMPANY_PROFILE_PARAMS = {
68 .shaper_params = {
69 .commit_rate = 50 * MBPS, .commit_burst = 1000000,
70 .peak_rate = 0, .peak_burst = 0,
71 .dual_rate = FALSE, .shaper_len_adjust = 20
72 },
73
74 .threshold_params = {
75 .max_pkts = 100000, .enable_max_pkts = TRUE,
76 .max_bytes = 10000000, .enable_max_bytes = TRUE
77 },
78
79 .wred_params = {
81 .min_threshold = PERCENT(70),
82 .med_threshold = PERCENT(90),
83 .med_drop_prob = PERCENT(80),
84 .max_drop_prob = PERCENT(100),
85 .enable_wred = TRUE,
86 .use_byte_fullness = FALSE,
87 },
88
90 .min_threshold = PERCENT(70),
91 .med_threshold = PERCENT(90),
92 .med_drop_prob = PERCENT(80),
93 .max_drop_prob = PERCENT(100),
94 .enable_wred = TRUE,
95 .use_byte_fullness = FALSE,
96 },
97
98 [ODP_PACKET_RED] = {
99 .min_threshold = PERCENT(40),
100 .med_threshold = PERCENT(70),
101 .med_drop_prob = PERCENT(70),
102 .max_drop_prob = PERCENT(100),
103 .enable_wred = TRUE,
104 .use_byte_fullness = FALSE,
105 },
106 }
107};
108
109static profile_params_set_t COS0_PROFILE_PARAMS = {
110 .shaper_params = {
111 .commit_rate = 1 * MBPS, .commit_burst = 100000,
112 .peak_rate = 4 * MBPS, .peak_burst = 200000,
113 .dual_rate = TRUE, .shaper_len_adjust = 20
114 },
115
116 .threshold_params = {
117 .max_pkts = 10000, .enable_max_pkts = TRUE,
118 .max_bytes = 1000000, .enable_max_bytes = TRUE
119 },
120
121 .wred_params = {
122 [ODP_PACKET_GREEN] = {
123 .min_threshold = PERCENT(80),
124 .med_threshold = PERCENT(90),
125 .med_drop_prob = PERCENT(50),
126 .max_drop_prob = PERCENT(100),
127 .enable_wred = TRUE,
128 .use_byte_fullness = FALSE,
129 },
130
132 .min_threshold = PERCENT(80),
133 .med_threshold = PERCENT(90),
134 .med_drop_prob = PERCENT(50),
135 .max_drop_prob = PERCENT(100),
136 .enable_wred = TRUE,
137 .use_byte_fullness = FALSE,
138 },
139
140 [ODP_PACKET_RED] = {
141 .min_threshold = PERCENT(60),
142 .med_threshold = PERCENT(80),
143 .med_drop_prob = PERCENT(70),
144 .max_drop_prob = PERCENT(100),
145 .enable_wred = TRUE,
146 .use_byte_fullness = FALSE,
147 },
148 }
149};
150
151static profile_params_set_t COS1_PROFILE_PARAMS = {
152 .shaper_params = {
153 .commit_rate = 500 * KBPS, .commit_burst = 50000,
154 .peak_rate = 1500 * KBPS, .peak_burst = 150000,
155 .dual_rate = TRUE, .shaper_len_adjust = 20
156 },
157
158 .threshold_params = {
159 .max_pkts = 5000, .enable_max_pkts = TRUE,
160 .max_bytes = 500000, .enable_max_bytes = TRUE
161 },
162
163 .wred_params = {
164 [ODP_PACKET_GREEN] = {
165 .min_threshold = PERCENT(40),
166 .med_threshold = PERCENT(90),
167 .med_drop_prob = PERCENT(70),
168 .max_drop_prob = PERCENT(100),
169 .enable_wred = TRUE,
170 .use_byte_fullness = FALSE,
171 },
172
174 .min_threshold = PERCENT(40),
175 .med_threshold = PERCENT(90),
176 .med_drop_prob = PERCENT(70),
177 .max_drop_prob = PERCENT(100),
178 .enable_wred = TRUE,
179 .use_byte_fullness = FALSE,
180 },
181
182 [ODP_PACKET_RED] = {
183 .min_threshold = PERCENT(50),
184 .med_threshold = PERCENT(80),
185 .med_drop_prob = PERCENT(80),
186 .max_drop_prob = PERCENT(100),
187 .enable_wred = TRUE,
188 .use_byte_fullness = FALSE,
189 },
190 }
191};
192
193static profile_params_set_t COS2_PROFILE_PARAMS = {
194 .shaper_params = {
195 .commit_rate = 200 * KBPS, .commit_burst = 20000,
196 .peak_rate = 400 * KBPS, .peak_burst = 40000,
197 .dual_rate = TRUE, .shaper_len_adjust = 20
198 },
199
200 .threshold_params = {
201 .max_pkts = 1000, .enable_max_pkts = TRUE,
202 .max_bytes = 100000, .enable_max_bytes = TRUE
203 },
204
205 .wred_params = {
206 [ODP_PACKET_GREEN] = {
207 .min_threshold = PERCENT(50),
208 .med_threshold = PERCENT(80),
209 .med_drop_prob = PERCENT(70),
210 .max_drop_prob = PERCENT(100),
211 .enable_wred = TRUE,
212 .use_byte_fullness = FALSE,
213 },
214
216 .min_threshold = PERCENT(50),
217 .med_threshold = PERCENT(80),
218 .med_drop_prob = PERCENT(70),
219 .max_drop_prob = PERCENT(100),
220 .enable_wred = TRUE,
221 .use_byte_fullness = FALSE,
222 },
223
224 [ODP_PACKET_RED] = {
225 .min_threshold = PERCENT(40),
226 .med_threshold = PERCENT(70),
227 .med_drop_prob = PERCENT(80),
228 .max_drop_prob = PERCENT(100),
229 .enable_wred = TRUE,
230 .use_byte_fullness = FALSE,
231 },
232 }
233};
234
235static profile_params_set_t COS3_PROFILE_PARAMS = {
236 .shaper_params = {
237 .commit_rate = 100 * KBPS, .commit_burst = 5000,
238 .peak_rate = 0, .peak_burst = 0,
239 .dual_rate = FALSE, .shaper_len_adjust = 20
240 },
241
242 .threshold_params = {
243 .max_pkts = 400, .enable_max_pkts = TRUE,
244 .max_bytes = 60000, .enable_max_bytes = TRUE
245 },
246
247 .wred_params = {
248 [ODP_PACKET_GREEN] = {
249 .min_threshold = PERCENT(40),
250 .med_threshold = PERCENT(70),
251 .med_drop_prob = PERCENT(80),
252 .max_drop_prob = PERCENT(100),
253 .enable_wred = TRUE,
254 .use_byte_fullness = FALSE,
255 },
256
258 .min_threshold = PERCENT(40),
259 .med_threshold = PERCENT(70),
260 .med_drop_prob = PERCENT(80),
261 .max_drop_prob = PERCENT(100),
262 .enable_wred = TRUE,
263 .use_byte_fullness = FALSE,
264 },
265
266 [ODP_PACKET_RED] = {
267 .min_threshold = PERCENT(30),
268 .med_threshold = PERCENT(60),
269 .med_drop_prob = PERCENT(80),
270 .max_drop_prob = PERCENT(100),
271 .enable_wred = TRUE,
272 .use_byte_fullness = FALSE,
273 },
274 }
275};
276
277static profile_set_t COMPANY_PROFILE_SET;
278static profile_set_t COS_PROFILE_SETS[NUM_SVC_CLASSES];
279static profile_set_t USER_PROFILE_SETS[NUM_SVC_CLASSES];
280static profile_set_t APP_PROFILE_SETS[NUM_SVC_CLASSES][APPS_PER_USER];
281
282static odp_tm_t odp_tm_test;
283
284static odp_pool_t odp_pool;
285
286static odp_tm_queue_t queue_num_tbls[NUM_SVC_CLASSES][TM_QUEUES_PER_CLASS];
287static uint32_t next_queue_nums[NUM_SVC_CLASSES];
288
289static uint8_t random_buf[RANDOM_BUF_LEN];
290static uint32_t next_rand_byte;
291
292static odp_atomic_u32_t atomic_pkts_into_tm;
293static odp_atomic_u32_t atomic_pkts_from_tm;
294
295static uint32_t g_num_pkts_to_send = 100;
296static uint8_t g_print_tm_stats = TRUE;
297
298static void tester_egress_fcn(odp_packet_t odp_pkt);
299
300static uint64_t tm_shaper_min_rate;
301static uint64_t tm_shaper_max_rate;
302static uint32_t tm_shaper_min_burst;
303static uint32_t tm_shaper_max_burst;
304
305static uint64_t
306clamp_rate(uint64_t rate)
307{
308 uint64_t val = ODPH_MIN(ODPH_MAX(rate, tm_shaper_min_rate), tm_shaper_max_rate);
309
310 if (!rate)
311 return 0;
312
313 if (val != rate)
314 printf("INFO: Clamped shaper rate from %" PRIu64 " bps"
315 " to %" PRIu64 " bps\n", rate, val);
316 return val;
317}
318
319static uint32_t
320clamp_burst(uint32_t burst)
321{
322 uint32_t val = ODPH_MIN(ODPH_MAX(burst, tm_shaper_min_burst), tm_shaper_max_burst);
323
324 if (!burst)
325 return 0;
326
327 if (val != burst)
328 printf("INFO: Clamped shaper burst from %" PRIu32 "bits to %" PRIu32 "bits\n",
329 burst, val);
330 return val;
331}
332
333/* Returns the number of errors encountered. */
334
335static uint32_t create_profile_set(profile_params_set_t *profile_params_set,
336 profile_set_t *profile_set,
337 const char *base_name,
338 uint32_t name_idx,
339 uint32_t shaper_scale,
340 uint32_t threshold_scale)
341{
342 odp_tm_threshold_params_t threshold_params, *thresholds;
343 odp_tm_shaper_params_t shaper_params, *shaper;
344 odp_tm_wred_params_t wred_params, *wred;
345 uint32_t err_cnt, color;
346 char name[ODP_TM_NAME_LEN], wred_name[ODP_TM_NAME_LEN];
347
348 err_cnt = 0;
349 if (name_idx == 0)
350 snprintf(name, sizeof(name), "%s", base_name);
351 else
352 snprintf(name, sizeof(name), "%s-%" PRIu32,
353 base_name, name_idx);
354
355 odp_tm_shaper_params_init(&shaper_params);
356 shaper = &profile_params_set->shaper_params;
357 shaper_params.commit_rate = clamp_rate(shaper->commit_rate *
358 shaper_scale);
359 shaper_params.peak_rate = clamp_rate(shaper->peak_rate *
360 shaper_scale);
361 shaper_params.commit_burst = clamp_burst(shaper->commit_burst *
362 shaper_scale);
363 shaper_params.peak_burst = clamp_burst(shaper->peak_burst *
364 shaper_scale);
365 shaper_params.dual_rate = shaper->dual_rate;
366 shaper_params.shaper_len_adjust = shaper->shaper_len_adjust;
367 profile_set->shaper_profile = odp_tm_shaper_create(name,
368 &shaper_params);
369 if (profile_set->shaper_profile == ODP_TM_INVALID)
370 err_cnt++;
371
372 odp_tm_threshold_params_init(&threshold_params);
373 thresholds = &profile_params_set->threshold_params;
374 threshold_params.max_pkts = thresholds->max_pkts * threshold_scale;
375 threshold_params.max_bytes = thresholds->max_bytes * threshold_scale;
376 threshold_params.enable_max_pkts = thresholds->enable_max_pkts;
377 threshold_params.enable_max_bytes = thresholds->enable_max_bytes;
378 profile_set->threshold_profile =
379 odp_tm_threshold_create(name, &threshold_params);
380
381 if (profile_set->threshold_profile == ODP_TM_INVALID)
382 err_cnt++;
383
384 for (color = 0; color < ODP_NUM_PACKET_COLORS; color++) {
385 snprintf(wred_name, sizeof(wred_name), "%s-%" PRIu32,
386 name, color);
387
388 odp_tm_wred_params_init(&wred_params);
389 wred = &profile_params_set->wred_params[color];
390 wred_params.min_threshold = wred->min_threshold;
391 wred_params.med_threshold = wred->med_threshold;
392 wred_params.med_drop_prob = wred->med_drop_prob;
393 wred_params.max_drop_prob = wred->max_drop_prob;
394 wred_params.enable_wred = wred->enable_wred;
395 wred_params.use_byte_fullness = wred->use_byte_fullness;
396 profile_set->wred_profiles[color] =
397 odp_tm_wred_create(wred_name, &wred_params);
398 if (profile_set->wred_profiles[color] == ODP_TM_INVALID)
399 err_cnt++;
400 }
401
402 return err_cnt;
403}
404
405/* Returns the number of errors encountered. */
406
407static uint32_t init_profile_sets(void)
408{
409 uint32_t class_shaper_scale, class_threshold_scale, user_shaper_scale;
410 uint32_t user_threshold_scale, err_cnt, app_idx;
411
412 class_shaper_scale = TM_QUEUES_PER_CLASS / 2;
413 class_threshold_scale = TM_QUEUES_PER_CLASS;
414 user_shaper_scale = TM_QUEUES_PER_USER / 2;
415 user_threshold_scale = TM_QUEUES_PER_USER;
416 err_cnt = 0;
417
418 err_cnt += create_profile_set(&COMPANY_PROFILE_PARAMS,
419 &COMPANY_PROFILE_SET,
420 "CompanyProfiles", 0, 1, 1);
421
422 err_cnt += create_profile_set(&COS0_PROFILE_PARAMS,
423 &COS_PROFILE_SETS[0], "ServiceClass0", 0,
424 class_shaper_scale,
425 class_threshold_scale);
426 err_cnt += create_profile_set(&COS1_PROFILE_PARAMS,
427 &COS_PROFILE_SETS[1], "ServiceClass1", 0,
428 class_shaper_scale,
429 class_threshold_scale);
430 err_cnt += create_profile_set(&COS2_PROFILE_PARAMS,
431 &COS_PROFILE_SETS[2], "ServiceClass2", 0,
432 class_shaper_scale,
433 class_threshold_scale);
434 err_cnt += create_profile_set(&COS3_PROFILE_PARAMS,
435 &COS_PROFILE_SETS[3], "ServiceClass3", 0,
436 class_shaper_scale,
437 class_threshold_scale);
438
439 err_cnt += create_profile_set(&COS0_PROFILE_PARAMS,
440 &USER_PROFILE_SETS[0], "UserSvc0", 0,
441 user_shaper_scale, user_threshold_scale);
442 err_cnt += create_profile_set(&COS1_PROFILE_PARAMS,
443 &USER_PROFILE_SETS[1], "UserSvc1", 0,
444 user_shaper_scale, user_threshold_scale);
445 err_cnt += create_profile_set(&COS2_PROFILE_PARAMS,
446 &USER_PROFILE_SETS[2], "UserSvc2", 0,
447 user_shaper_scale, user_threshold_scale);
448 err_cnt += create_profile_set(&COS3_PROFILE_PARAMS,
449 &USER_PROFILE_SETS[3], "UserSvc3", 0,
450 user_shaper_scale, user_threshold_scale);
451
452 for (app_idx = 0; app_idx < APPS_PER_USER; app_idx++) {
453 err_cnt += create_profile_set(&COS0_PROFILE_PARAMS,
454 &APP_PROFILE_SETS[0][app_idx],
455 "AppSvc0", app_idx + 1, 1, 1);
456 err_cnt += create_profile_set(&COS1_PROFILE_PARAMS,
457 &APP_PROFILE_SETS[1][app_idx],
458 "AppSvc1", app_idx + 1, 1, 1);
459 err_cnt += create_profile_set(&COS2_PROFILE_PARAMS,
460 &APP_PROFILE_SETS[2][app_idx],
461 "AppSvc2", app_idx + 1, 1, 1);
462 err_cnt += create_profile_set(&COS3_PROFILE_PARAMS,
463 &APP_PROFILE_SETS[3][app_idx],
464 "AppSvc3", app_idx + 1, 1, 1);
465 }
466
467 return err_cnt;
468}
469
470static int config_example_user(odp_tm_node_t cos_tm_node,
471 uint8_t svc_class,
472 uint32_t user_num)
473{
474 odp_tm_queue_params_t tm_queue_params;
475 odp_tm_node_params_t tm_node_params;
476 odp_tm_queue_t tm_queue;
477 odp_tm_node_t user_tm_node;
478 profile_set_t *profile_set;
479 uint32_t app_idx, queue_idx, svc_class_queue_num;
480 char user_name[ODP_TM_NAME_LEN];
481 int rc;
482
483 profile_set = &USER_PROFILE_SETS[svc_class];
484
485 odp_tm_node_params_init(&tm_node_params);
486 tm_node_params.max_fanin = 64;
487 tm_node_params.shaper_profile = profile_set->shaper_profile;
488 tm_node_params.threshold_profile = profile_set->threshold_profile;
489 tm_node_params.wred_profile[ODP_PACKET_GREEN] =
490 profile_set->wred_profiles[0];
491 tm_node_params.wred_profile[ODP_PACKET_YELLOW] =
492 profile_set->wred_profiles[1];
493 tm_node_params.wred_profile[ODP_PACKET_RED] =
494 profile_set->wred_profiles[2];
495 tm_node_params.level = 2;
496
497 snprintf(user_name, sizeof(user_name), "Subscriber-%" PRIu32, user_num);
498 user_tm_node = odp_tm_node_create(odp_tm_test, user_name,
499 &tm_node_params);
500 odp_tm_node_connect(user_tm_node, cos_tm_node);
501
502 for (app_idx = 0; app_idx < APPS_PER_USER; app_idx++) {
503 profile_set = &APP_PROFILE_SETS[svc_class][app_idx];
504 for (queue_idx = 0; queue_idx < TM_QUEUES_PER_APP;
505 queue_idx++) {
506 odp_tm_queue_params_init(&tm_queue_params);
507 tm_queue_params.shaper_profile =
508 profile_set->shaper_profile;
509 tm_queue_params.threshold_profile =
510 profile_set->threshold_profile;
511 tm_queue_params.priority = svc_class;
512
513 tm_queue_params.wred_profile[ODP_PACKET_GREEN] =
514 profile_set->wred_profiles[ODP_PACKET_GREEN];
515 tm_queue_params.wred_profile[ODP_PACKET_YELLOW] =
516 profile_set->wred_profiles[ODP_PACKET_YELLOW];
517 tm_queue_params.wred_profile[ODP_PACKET_RED] =
518 profile_set->wred_profiles[ODP_PACKET_RED];
519
520 tm_queue = odp_tm_queue_create(odp_tm_test,
521 &tm_queue_params);
522 rc = odp_tm_queue_connect(tm_queue, user_tm_node);
523 if (rc < 0)
524 return rc;
525
526 svc_class_queue_num = next_queue_nums[svc_class]++;
527 queue_num_tbls[svc_class][svc_class_queue_num] =
528 tm_queue;
529 }
530 }
531
532 return 0;
533}
534
535static int config_company_node(const char *company_name)
536{
537 odp_tm_node_params_t tm_node_params;
538 profile_set_t *profile_set;
539 odp_tm_node_t company_tm_node, cos_tm_node;
540 uint32_t cos_idx, user_idx;
541 char cos_node_name[ODP_TM_NAME_LEN];
542
543 profile_set = &COMPANY_PROFILE_SET;
544 odp_tm_node_params_init(&tm_node_params);
545 tm_node_params.max_fanin = 64;
546 tm_node_params.shaper_profile = profile_set->shaper_profile;
547 tm_node_params.threshold_profile = profile_set->threshold_profile;
548 tm_node_params.wred_profile[ODP_PACKET_GREEN] =
549 profile_set->wred_profiles[0];
550 tm_node_params.wred_profile[ODP_PACKET_YELLOW] =
551 profile_set->wred_profiles[1];
552 tm_node_params.wred_profile[ODP_PACKET_RED] =
553 profile_set->wred_profiles[2];
554 tm_node_params.level = 0;
555
556 company_tm_node = odp_tm_node_create(odp_tm_test, company_name,
557 &tm_node_params);
558
559 for (cos_idx = 0; cos_idx < NUM_SVC_CLASSES; cos_idx++) {
560 odp_tm_node_params_init(&tm_node_params);
561 profile_set = &COS_PROFILE_SETS[cos_idx];
562 tm_node_params.max_fanin = 64;
563 tm_node_params.shaper_profile = profile_set->shaper_profile;
564 tm_node_params.threshold_profile =
565 profile_set->threshold_profile;
566 tm_node_params.level = 1;
567
568 tm_node_params.wred_profile[ODP_PACKET_GREEN] =
569 profile_set->wred_profiles[ODP_PACKET_GREEN];
570 tm_node_params.wred_profile[ODP_PACKET_YELLOW] =
571 profile_set->wred_profiles[ODP_PACKET_YELLOW];
572 tm_node_params.wred_profile[ODP_PACKET_RED] =
573 profile_set->wred_profiles[ODP_PACKET_RED];
574
575 snprintf(cos_node_name, sizeof(cos_node_name),
576 "%s-Class-%" PRIu32, company_name, cos_idx);
577 cos_tm_node = odp_tm_node_create(odp_tm_test, cos_node_name,
578 &tm_node_params);
579 odp_tm_node_connect(cos_tm_node, company_tm_node);
580
581 for (user_idx = 0; user_idx < USERS_PER_SVC_CLASS; user_idx++)
582 config_example_user(cos_tm_node, cos_idx,
583 cos_idx * 256 + user_idx);
584 }
585
586 odp_tm_node_connect(company_tm_node, ODP_TM_ROOT);
587 return 0;
588}
589
590static int create_and_config_tm(void)
591{
593 odp_tm_requirements_t requirements;
594 odp_tm_capabilities_t tm_capa;
595 odp_tm_egress_t egress;
596 uint32_t level, err_cnt;
597
598 odp_tm_requirements_init(&requirements);
599 odp_tm_egress_init(&egress);
600
601 requirements.max_tm_queues = 10 * NUM_TM_QUEUES;
602 requirements.num_levels = 3;
603 requirements.tm_queue_shaper_needed = true;
604 requirements.tm_queue_wred_needed = true;
605
606 for (level = 0; level < 3; level++) {
607 per_level = &requirements.per_level[level];
608 per_level->max_num_tm_nodes = MAX_NODES_PER_LEVEL;
609 per_level->max_fanin_per_node = 64;
610 per_level->max_priority = 3;
611 per_level->min_weight = 1;
612 per_level->max_weight = 255;
613 per_level->tm_node_shaper_needed = true;
614 per_level->tm_node_wred_needed = true;
615 per_level->tm_node_dual_slope_needed = true;
616 per_level->fair_queuing_needed = true;
617 per_level->weights_needed = true;
618 }
619
620 egress.egress_kind = ODP_TM_EGRESS_FN;
621 egress.egress_fcn = tester_egress_fcn;
622
623 odp_tm_test = odp_tm_create("TM test", &requirements, &egress);
624 if (odp_tm_test == ODP_TM_INVALID) {
625 printf("Error: failed to create TM\n");
626 return -1;
627 }
628
629 if (odp_tm_capability(odp_tm_test, &tm_capa) != 0) {
630 printf("Error: failed to get tm capability");
631 return -1;
632 }
633
634 tm_shaper_min_rate = tm_capa.per_level[0].min_rate;
635 tm_shaper_max_rate = tm_capa.per_level[0].max_rate;
636 tm_shaper_min_burst = tm_capa.per_level[0].min_burst;
637 tm_shaper_max_burst = tm_capa.per_level[0].max_burst;
638
639 for (level = 1; level < tm_capa.max_levels; level++) {
640 odp_tm_level_capabilities_t *level_capa = &tm_capa.per_level[level];
641
642 if (level_capa->min_rate > tm_shaper_min_rate)
643 tm_shaper_min_rate = level_capa->min_rate;
644
645 if (level_capa->min_burst > tm_shaper_min_burst)
646 tm_shaper_min_burst = level_capa->min_burst;
647
648 if (level_capa->max_rate < tm_shaper_max_rate)
649 tm_shaper_max_rate = level_capa->max_rate;
650
651 if (level_capa->max_burst < tm_shaper_max_burst)
652 tm_shaper_max_burst = level_capa->max_burst;
653 }
654
655 if (tm_shaper_min_rate > tm_shaper_max_rate ||
656 tm_shaper_min_burst > tm_shaper_max_burst) {
657 printf("Error: No shaper rate supported by all TM levels");
658 return -1;
659 }
660
661 err_cnt = init_profile_sets();
662 if (err_cnt != 0)
663 printf("%s init_profile_sets encountered %" PRIu32 " errors\n",
664 __func__, err_cnt);
665
666 config_company_node("TestCompany");
667 return err_cnt;
668}
669
670static uint32_t random_8(void)
671{
672 uint32_t rand8;
673
674 if (RANDOM_BUF_LEN <= next_rand_byte) {
675 odp_random_data(random_buf, RANDOM_BUF_LEN, 1);
676 next_rand_byte = 0;
677 }
678
679 rand8 = random_buf[next_rand_byte++];
680 return rand8;
681}
682
683static uint32_t random_16(void)
684{
685 uint8_t byte1, byte2;
686
687 if ((RANDOM_BUF_LEN - 1) <= next_rand_byte) {
688 odp_random_data(random_buf, RANDOM_BUF_LEN, 1);
689 next_rand_byte = 0;
690 }
691
692 byte1 = random_buf[next_rand_byte++];
693 byte2 = random_buf[next_rand_byte++];
694 return (((uint16_t)byte1) << 8) | ((uint16_t)byte2);
695}
696
697static uint32_t pkt_service_class(void)
698{
699 uint32_t rand8;
700
701 /* Make most of the traffic use service class 3 to increase the amount
702 * of delayed traffic so as to stimulate more interesting behaviors.
703 */
704 rand8 = random_8();
705
706 if (rand8 <= 24)
707 return 0;
708 else if (rand8 >= 25 && rand8 <= 49)
709 return 1;
710 else if (rand8 >= 50 && rand8 <= 150)
711 return 2;
712 else if (rand8 >= 151 && rand8 <= 255)
713 return 3;
714 else
715 return 3;
716}
717
718static odp_packet_t make_odp_packet(uint16_t pkt_len)
719{
720 odp_packet_t odp_pkt;
721 uint8_t rand8a, rand8b, pkt_color, drop_eligible;
722
723 rand8a = random_8();
724 rand8b = random_8();
725 pkt_color = (rand8a < 224) ? 0 : ((rand8a < 248) ? 1 : 2);
726 drop_eligible = (rand8b < 240) ? 1 : 0;
727 odp_pkt = odp_packet_alloc(odp_pool, pkt_len);
728 if (odp_pkt == ODP_PACKET_INVALID) {
729 printf("%s odp_packet_alloc failure *******\n", __func__);
730 return 0;
731 }
732
733 odp_packet_color_set(odp_pkt, pkt_color);
734 odp_packet_drop_eligible_set(odp_pkt, drop_eligible);
736 return odp_pkt;
737}
738
739void tester_egress_fcn(odp_packet_t odp_pkt ODP_UNUSED)
740{
741 odp_atomic_inc_u32(&atomic_pkts_from_tm);
742}
743
744static int traffic_generator(uint32_t pkts_to_send)
745{
746 odp_pool_param_t pool_params;
747 odp_tm_queue_t tm_queue;
748 odp_packet_t pkt;
749 odp_bool_t tm_is_idle;
750 uint32_t svc_class, queue_num, pkt_len, pkts_into_tm;
751 uint32_t pkts_from_tm, pkt_cnt, millisecs, odp_tm_enq_errs;
752 int rc;
753
754 memset(&pool_params, 0, sizeof(odp_pool_param_t));
755 pool_params.type = ODP_POOL_PACKET;
756 pool_params.pkt.num = pkts_to_send + 10;
757 pool_params.pkt.len = 1600;
758 pool_params.pkt.seg_len = 0;
759 pool_params.pkt.uarea_size = 0;
760
761 odp_pool = odp_pool_create("MyPktPool", &pool_params);
762 odp_tm_enq_errs = 0;
763
764 pkt_cnt = 0;
765 while (pkt_cnt < pkts_to_send) {
766 svc_class = pkt_service_class();
767 queue_num = random_16() & (TM_QUEUES_PER_CLASS - 1);
768 tm_queue = queue_num_tbls[svc_class][queue_num];
769 pkt_len = ((uint32_t)((random_8() & 0x7F) + 2)) * 32;
770 pkt_len = ODPH_MIN(pkt_len, 1500u);
771 pkt = make_odp_packet(pkt_len);
772
773 pkt_cnt++;
774 rc = odp_tm_enq(tm_queue, pkt);
775 if (rc < 0) {
776 odp_tm_enq_errs++;
777 continue;
778 }
779
780 odp_atomic_inc_u32(&atomic_pkts_into_tm);
781 }
782
783 printf("%s odp_tm_enq_errs=%" PRIu32 "\n", __func__, odp_tm_enq_errs);
784
785 /* Wait until the main traffic mgmt worker thread is idle and has no
786 * outstanding events (i.e. no timers, empty work queue, etc), but
787 * not longer than 60 seconds.
788 */
789 for (millisecs = 0; millisecs < 600000; millisecs++) {
790 usleep(100);
791 tm_is_idle = odp_tm_is_idle(odp_tm_test);
792 if (tm_is_idle)
793 break;
794 }
795
796 if (!tm_is_idle)
797 printf("%s WARNING stopped waiting for the TM system "
798 "to be IDLE!\n", __func__);
799
800 /* Wait for up to 2 seconds for pkts_from_tm to match pkts_into_tm. */
801 for (millisecs = 0; millisecs < 2000; millisecs++) {
802 usleep(1000);
803 pkts_into_tm = odp_atomic_load_u32(&atomic_pkts_into_tm);
804 pkts_from_tm = odp_atomic_load_u32(&atomic_pkts_from_tm);
805 if (pkts_into_tm <= pkts_from_tm)
806 break;
807 }
808
809 return 0;
810}
811
812static int process_cmd_line_options(uint32_t argc, char *argv[])
813{
814 uint32_t arg_idx;
815 char *arg;
816
817 arg_idx = 1;
818 while (arg_idx < argc) {
819 arg = argv[arg_idx++];
820 if (!arg) {
821 return -1;
822 } else if (arg[0] == '-') {
823 switch (arg[1]) {
824 case 'n':
825 if (argc <= arg_idx)
826 return -1;
827 g_num_pkts_to_send =
828 atoi(argv[arg_idx++]);
829 break;
830
831 case 'q':
832 g_print_tm_stats = FALSE;
833 break;
834
835 default:
836 printf("Unrecognized cmd line option '%s'\n",
837 arg);
838 return -1;
839 }
840 } else {
841 /* Currently all cmd line options are '-' flag based. */
842 return -1;
843 }
844 }
845
846 return 0;
847}
848
849static void signal_handler(int signal)
850{
851 size_t num_stack_frames;
852 const char *signal_name;
853 void *bt_array[128];
854
855 switch (signal) {
856 case SIGILL:
857 signal_name = "SIGILL"; break;
858 case SIGFPE:
859 signal_name = "SIGFPE"; break;
860 case SIGSEGV:
861 signal_name = "SIGSEGV"; break;
862 case SIGTERM:
863 signal_name = "SIGTERM"; break;
864 case SIGBUS:
865 signal_name = "SIGBUS"; break;
866 default:
867 signal_name = "UNKNOWN"; break;
868 }
869
870 num_stack_frames = backtrace(bt_array, 100);
871 printf("Received signal=%u (%s) exiting.", signal, signal_name);
872 backtrace_symbols_fd(bt_array, num_stack_frames, fileno(stderr));
873 fflush(NULL);
874 sync();
875 abort();
876}
877
878static int destroy_tm_queues(void)
879{
880 int i;
881 int class;
882 int ret;
883
884 for (i = 0; i < NUM_SVC_CLASSES; i++)
885 for (class = 0; class < TM_QUEUES_PER_CLASS; class++) {
886 odp_tm_queue_t tm_queue;
888
889 tm_queue = queue_num_tbls[i][class];
890
891 ret = odp_tm_queue_info(tm_queue, &info);
892 if (ret) {
893 printf("Err: odp_tm_queue_info %d\n", ret);
894 return -1;
895 }
896
898 if (ret) {
899 printf("Err: odp_tm_node_disconnect %d\n", ret);
900 return -1;
901 }
902
903 ret = odp_tm_queue_disconnect(tm_queue);
904 if (ret) {
905 printf("odp_tm_queue_disconnect %d\n", ret);
906 return -1;
907 }
908
909 ret = odp_tm_queue_destroy(tm_queue);
910 if (ret) {
911 printf("odp_tm_queue_destroy %d\n", ret);
912 return -1;
913 }
914 }
915
916 return 0;
917}
918
919int main(int argc, char *argv[])
920{
921 struct sigaction signal_action;
922 struct rlimit rlimit;
923 uint32_t pkts_into_tm, pkts_from_tm;
924 odp_instance_t instance;
925 int rc;
926
927 memset(&signal_action, 0, sizeof(signal_action));
928 signal_action.sa_handler = signal_handler;
929 sigfillset(&signal_action.sa_mask);
930 sigaction(SIGILL, &signal_action, NULL);
931 sigaction(SIGFPE, &signal_action, NULL);
932 sigaction(SIGSEGV, &signal_action, NULL);
933 sigaction(SIGTERM, &signal_action, NULL);
934 sigaction(SIGBUS, &signal_action, NULL);
935
936 getrlimit(RLIMIT_CORE, &rlimit);
937 rlimit.rlim_cur = rlimit.rlim_max;
938 setrlimit(RLIMIT_CORE, &rlimit);
939
940 rc = odp_init_global(&instance, &ODP_INIT_PARAMS, NULL);
941 if (rc != 0) {
942 printf("Error: odp_init_global() failed, rc = %d\n", rc);
943 return -1;
944 }
945
946 rc = odp_init_local(instance, ODP_THREAD_CONTROL);
947 if (rc != 0) {
948 printf("Error: odp_init_local() failed, rc = %d\n", rc);
949 return -1;
950 }
951
952 if (process_cmd_line_options(argc, argv) < 0)
953 return -1;
954
955 rc = create_and_config_tm();
956 if (rc != 0)
957 return rc;
958
959 /* Start TM */
960 rc = odp_tm_start(odp_tm_test);
961 if (rc != 0) {
962 printf("Error: odp_tm_start() failed, rc=%d\n", rc);
963 return -1;
964 }
965
966 odp_random_data(random_buf, RANDOM_BUF_LEN, 1);
967 next_rand_byte = 0;
968
969 odp_atomic_init_u32(&atomic_pkts_into_tm, 0);
970 odp_atomic_init_u32(&atomic_pkts_from_tm, 0);
971
972 traffic_generator(g_num_pkts_to_send);
973
974 pkts_into_tm = odp_atomic_load_u32(&atomic_pkts_into_tm);
975 pkts_from_tm = odp_atomic_load_u32(&atomic_pkts_from_tm);
976 printf("pkts_into_tm=%" PRIu32 " pkts_from_tm=%" PRIu32 "\n",
977 pkts_into_tm, pkts_from_tm);
978
979 odp_tm_stats_print(odp_tm_test);
980
981 /* Stop TM */
982 rc = odp_tm_stop(odp_tm_test);
983 if (rc != 0) {
984 printf("Error: odp_tm_stop() failed, rc = %d\n", rc);
985 return -1;
986 }
987
988 rc = destroy_tm_queues();
989 if (rc != 0) {
990 printf("Error: destroy_tm_queues() failed, rc = %d\n", rc);
991 return -1;
992 }
993
994 rc = odp_pool_destroy(odp_pool);
995 if (rc != 0) {
996 printf("Error: odp_pool_destroy() failed, rc = %d\n", rc);
997 return -1;
998 }
999
1000 rc = odp_tm_destroy(odp_tm_test);
1001 if (rc != 0) {
1002 printf("Error: odp_tm_destroy() failed, rc = %d\n", rc);
1003 return -1;
1004 }
1005
1006 rc = odp_term_local();
1007 if (rc != 0) {
1008 printf("Error: odp_term_local() failed, rc = %d\n", rc);
1009 return -1;
1010 }
1011
1012 rc = odp_term_global(instance);
1013 if (rc != 0) {
1014 printf("Error: odp_term_global() failed, rc = %d\n", rc);
1015 return -1;
1016 }
1017
1018 printf("Quit\n");
1019 return 0;
1020}
void odp_atomic_init_u32(odp_atomic_u32_t *atom, uint32_t val)
Initialize atomic uint32 variable.
uint32_t odp_atomic_load_u32(odp_atomic_u32_t *atom)
Load value of atomic uint32 variable.
void odp_atomic_inc_u32(odp_atomic_u32_t *atom)
Increment atomic uint32 variable.
#define ODP_UNUSED
Intentionally unused variables of functions.
Definition spec/hints.h:54
int void odp_override_abort(void) ODP_NORETURN
ODP abort function.
int odp_init_local(odp_instance_t instance, odp_thread_type_t thr_type)
Thread local ODP initialization.
int odp_init_global(odp_instance_t *instance, const odp_init_t *params, const odp_platform_init_t *platform_params)
Global ODP initialization.
int odp_term_local(void)
Thread local ODP termination.
int odp_term_global(odp_instance_t instance)
Global ODP termination.
uint64_t odp_instance_t
ODP instance ID.
int odp_override_log(odp_log_level_t level, const char *fmt,...) ODP_PRINTF_FORMAT(2
ODP log function.
void odp_packet_color_set(odp_packet_t pkt, odp_packet_color_t color)
Set packet color.
#define ODP_NUM_PACKET_COLORS
Maximum number of packet colors which accommodates ODP_PACKET_GREEN, ODP_PACKET_YELLOW and ODP_PACKET...
void odp_packet_drop_eligible_set(odp_packet_t pkt, odp_bool_t status)
Set drop eligible status.
odp_packet_t odp_packet_alloc(odp_pool_t pool, uint32_t len)
Allocate a packet from a packet pool.
void odp_packet_shaper_len_adjust_set(odp_packet_t pkt, int8_t adj)
Set shaper length adjustment.
#define ODP_PACKET_INVALID
Invalid packet.
@ ODP_PACKET_YELLOW
Packet is yellow.
@ ODP_PACKET_RED
Packet is red.
@ ODP_PACKET_GREEN
Packet is green.
odp_pool_t odp_pool_create(const char *name, const odp_pool_param_t *param)
Create a pool.
int odp_pool_destroy(odp_pool_t pool)
Destroy a pool previously created by odp_pool_create()
@ ODP_POOL_PACKET
Packet pool.
int32_t odp_random_data(uint8_t *buf, uint32_t len, odp_random_kind_t kind)
Generate random byte data.
bool odp_bool_t
Boolean type.
@ ODP_THREAD_CONTROL
Control thread.
int odp_tm_destroy(odp_tm_t tm)
Destroy a TM system.
odp_tm_node_t odp_tm_node_create(odp_tm_t tm, const char *name, const odp_tm_node_params_t *params)
Create an tm_node with a specific set of implemented strict priority levels as given by the prioritie...
odp_bool_t odp_tm_is_idle(odp_tm_t tm)
The odp_tm_is_idle function is used to determine if the specified ODP traffic management system still...
odp_tm_threshold_t odp_tm_threshold_create(const char *name, const odp_tm_threshold_params_t *params)
odp_tm_threshold_create() creates a queue threshold profile object, which can subsequently be attache...
odp_tm_wred_t odp_tm_wred_create(const char *name, const odp_tm_wred_params_t *params)
odp_tm_wred_create() creates a WRED (Weighted Random Early Detection) profile object,...
odp_tm_handle_t odp_tm_t
Each odp_tm_t value represents a specific TM system.
odp_tm_t odp_tm_create(const char *name, odp_tm_requirements_t *requirements, odp_tm_egress_t *egress)
Create/instantiate a TM Packet Scheduling system.
odp_tm_handle_t odp_tm_wred_t
Each odp_tm_wred_t value is an opaque ODP handle representing a specific WRED profile usable across a...
void odp_tm_egress_init(odp_tm_egress_t *egress)
Initialize Egress record.
void odp_tm_node_params_init(odp_tm_node_params_t *params)
Initialize TM node parameters.
odp_tm_handle_t odp_tm_node_t
Each odp_tm_node_t value is an opaque ODP handle representing a specific tm_node within a specific TM...
int odp_tm_node_disconnect(odp_tm_node_t src_tm_node)
Disconnect a tm_node to tm_node linkage.
void odp_tm_queue_params_init(odp_tm_queue_params_t *params)
Initialize TM queue parameters.
int odp_tm_enq(odp_tm_queue_t tm_queue, odp_packet_t pkt)
Send packet to TM system.
#define ODP_TM_NAME_LEN
Maximum traffic manager name length, including the null character.
int odp_tm_queue_connect(odp_tm_queue_t tm_queue, odp_tm_node_t dst_tm_node)
The odp_tm_queue_connect() function connects the indicated tm_queue to a parent tm_node or to the egr...
odp_tm_queue_t odp_tm_queue_create(odp_tm_t tm, const odp_tm_queue_params_t *params)
TM queue create.
odp_tm_handle_t odp_tm_queue_t
Each odp_tm_queue_t value is an opaque ODP handle representing a specific tm_queue within a specific ...
void odp_tm_shaper_params_init(odp_tm_shaper_params_t *params)
Initialize TM shaper parameters.
odp_tm_shaper_t odp_tm_shaper_create(const char *name, const odp_tm_shaper_params_t *params)
odp_tm_shaper_create() creates a shaper profile object, which can subsequently be attached to any num...
int odp_tm_start(odp_tm_t tm)
Start a TM system.
int odp_tm_node_connect(odp_tm_node_t src_tm_node, odp_tm_node_t dst_tm_node)
Connects two tm_nodes.
#define ODP_TM_INVALID
The ODP_TM_INVALID constant can be used with any ODP TM handle type and indicates that this value doe...
odp_tm_handle_t odp_tm_threshold_t
Each odp_tm_threshold_t value is an opaque ODP handle representing a specific queue threshold profile...
void odp_tm_threshold_params_init(odp_tm_threshold_params_t *params)
Initialize TM threshold parameters.
int odp_tm_queue_destroy(odp_tm_queue_t tm_queue)
Destroy an tm_queue object.
int odp_tm_capability(odp_tm_t tm, odp_tm_capabilities_t *capabilities)
Query Specific TM Capabilities.
int odp_tm_queue_disconnect(odp_tm_queue_t tm_queue)
Disconnect a tm_queue from a tm_system.
void odp_tm_stats_print(odp_tm_t tm)
The odp_tm_stats_print function is used to write implementation-defined information about the specifi...
void odp_tm_wred_params_init(odp_tm_wred_params_t *params)
Initialize TM WRED parameters.
int odp_tm_queue_info(odp_tm_queue_t tm_queue, odp_tm_queue_info_t *info)
Get tm_queue Info.
int odp_tm_stop(odp_tm_t tm)
Stop a TM system.
#define ODP_TM_ROOT
Constant that is used to refer to the egress/root node of the TM subsystem's tree/hierarchy of nodes.
void odp_tm_requirements_init(odp_tm_requirements_t *requirements)
Initialize Requirements record fields to their default values.
odp_tm_handle_t odp_tm_shaper_t
Each odp_tm_shaper_t value is an opaque ODP handle representing a specific shaper profile usable acro...
The OpenDataPlane API.
Global initialization parameters.
odp_log_func_t log_fn
Replacement for the default log fn.
uint32_t uarea_size
Minimum user area size in bytes.
uint32_t num
Number of buffers in the pool.
struct odp_pool_param_t::@139 pkt
Parameters for packet pools.
odp_pool_type_t type
Pool type.
uint32_t len
Minimum length of 'num' packets.
uint32_t seg_len
Minimum number of packet data bytes that can be stored in the first segment of a newly allocated pack...
TM Capabilities Record.
odp_tm_level_capabilities_t per_level[ODP_TM_MAX_LEVELS]
The per_level array specifies the TM system capabilities that can vary based upon the tm_node level.
uint8_t max_levels
max_levels specifies that maximum number of levels of hierarchical scheduling allowed by this TM Syst...
The odp_tm_egress_t type is used to describe that type of "egress spigot" associated with this TM sys...
odp_tm_egress_kind_t egress_kind
Union discriminator.
odp_tm_egress_fcn_t egress_fcn
Output to user func.
uint64_t max_rate
Maximum allowed value for odp_tm_shaper_params_t::commit_rate and odp_tm_shaper_params_t::peak_rate w...
uint64_t min_rate
Minimum allowed value for odp_tm_shaper_params_t::commit_rate and odp_tm_shaper_params_t::peak_rate w...
uint32_t max_burst
Maximum allowed value for odp_tm_shaper_params_t::commit_burst and odp_tm_shaper_params_t::peak_burst...
uint32_t min_burst
Minimum allowed value for odp_tm_shaper_params_t::commit_burst and odp_tm_shaper_params_t::peak_burst...
odp_bool_t tm_node_dual_slope_needed
tm_node_dual_slope_needed indicates that the tm_nodes at this level are expected to use the dual slop...
odp_bool_t tm_node_wred_needed
tm_node_wred_needed indicates that the tm_nodes at this level are expected to participate in some for...
uint32_t max_num_tm_nodes
max_num_tm_nodes specifies the maximum number of tm_nodes required at this level.
uint32_t max_weight
max_weight only has significance when the weights_supported field below is true, in which case it spe...
odp_bool_t weights_needed
weights_needed indicates that the tm_node schedulers at this level are expected have different weight...
uint32_t max_fanin_per_node
max_fanin_per_level specifies the maximum number of fan_in links to any given scheduler (whether weig...
odp_bool_t tm_node_shaper_needed
tm_node_shaper_needed indicates that the tm_nodes at this level are expected to do TM shaping,
uint8_t max_priority
max_priority specifies the maximum number of strict priority levels that will be used by any tm_node ...
uint32_t min_weight
min_weight only has significance when the weights_supported field below is true, in which case it spe...
odp_bool_t fair_queuing_needed
fair_queuing_needed indicates that the tm_node schedulers at this level are expected to implement WFQ...
odp_tm_shaper_t shaper_profile
The shaper profile to be associated with this tm_node.
uint32_t max_fanin
The max_fanin sets the maximum number of src tm_queues and producer tm_nodes that can be simultaneous...
odp_tm_threshold_t threshold_profile
The threshold profile to be used in setting the max queue fullness for WRED and/or tail drop.
uint8_t level
The level (or tm_node stage) sets the level for this tm_node It must be in range 0....
odp_tm_wred_t wred_profile[ODP_NUM_PACKET_COLORS]
The WRED profile(s) to be associated with this tm_node.
The odp_tm_queue_info_t record type is used to return various bits of information about a given tm_qu...
odp_tm_node_t next_tm_node
The next_tm_node is the "next" node in the tree - i.e.
odp_tm_threshold_t threshold_profile
The threshold profile to be used in setting the max queue fullness for WRED and/or tail drop.
uint8_t priority
The strict priority level assigned to packets in this tm_queue - in other words all packets associate...
odp_tm_wred_t wred_profile[ODP_NUM_PACKET_COLORS]
The WRED profile(s) to be associated with this tm_queue.
odp_tm_shaper_t shaper_profile
The shaper profile to be associated with this tm_queue.
TM Requirements Record.
uint32_t max_tm_queues
max_tm_queues specifies the maximum number of tm_queues that will be used for this TM System.
odp_bool_t tm_queue_wred_needed
tm_queue_wred_needed indicates that the tm_queues are expected to participate in some form of Random ...
uint8_t num_levels
num_levels specifies that number of levels of hierarchical scheduling that will be used.
odp_tm_level_requirements_t per_level[ODP_TM_MAX_LEVELS]
The per_level array specifies the TM system requirements that can vary based upon the tm_node level.
odp_bool_t tm_queue_shaper_needed
tm_queue_shaper_needed indicates that the tm_queues are expected to do TM shaping.
uint32_t commit_burst
The commit burst tolerance for this shaper profile.
odp_bool_t dual_rate
If dual_rate is TRUE it indicates the desire for the implementation to use dual rate shaping for pack...
int8_t shaper_len_adjust
The shaper_len_adjust is a value between -128 and 127 which is directly added to the frame_len of a p...
uint64_t commit_rate
The committed information rate for this shaper profile.
uint32_t peak_burst
The peak burst tolerance for this shaper profile.
uint64_t peak_rate
The peak information rate for this shaper profile.
uint64_t max_bytes
max byte cnt for this threshold profile
odp_bool_t enable_max_bytes
TRUE if max_bytes is valid.
odp_bool_t enable_max_pkts
TRUE if max_pkts is valid.
uint64_t max_pkts
max pkt cnt for this threshold profile
odp_tm_percent_t med_drop_prob
The med_drop_prob is only used when dual-slope WRED is being used, in which case med_drop_prob MUST b...
odp_bool_t use_byte_fullness
When use_byte_fullness is true then WRED will use queue memory usage as the fullness criterion,...
odp_tm_percent_t med_threshold
The meaning of med_threshold depends upon whether single-slope or dual-slope WRED is being used or no...
odp_bool_t enable_wred
When enable_wred is false, all tm_queues and tm_nodes that are attached to this profile will not take...
odp_tm_percent_t max_drop_prob
The max_drop_prob equals the drop probability when the queue fullness almost equals 100%.
odp_tm_percent_t min_threshold
When min_threshold is set to zero then single-slope WRED is enabled, as described in the description ...