API Reference Manual  1.46.0
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 
50 typedef struct {
51  odp_tm_shaper_params_t shaper_params;
52  odp_tm_threshold_params_t threshold_params;
54 } profile_params_set_t;
55 
56 typedef struct {
57  odp_tm_shaper_t shaper_profile;
58  odp_tm_threshold_t threshold_profile;
59  odp_tm_wred_t wred_profiles[ODP_NUM_PACKET_COLORS];
60 } profile_set_t;
61 
62 static const odp_init_t ODP_INIT_PARAMS = {
64  .abort_fn = odp_override_abort
65 };
66 
67 static 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 = {
80  [ODP_PACKET_GREEN] = {
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 
89  [ODP_PACKET_YELLOW] = {
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 
109 static 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 
131  [ODP_PACKET_YELLOW] = {
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 
151 static 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 
173  [ODP_PACKET_YELLOW] = {
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 
193 static 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 
215  [ODP_PACKET_YELLOW] = {
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 
235 static 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 
257  [ODP_PACKET_YELLOW] = {
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 
277 static profile_set_t COMPANY_PROFILE_SET;
278 static profile_set_t COS_PROFILE_SETS[NUM_SVC_CLASSES];
279 static profile_set_t USER_PROFILE_SETS[NUM_SVC_CLASSES];
280 static profile_set_t APP_PROFILE_SETS[NUM_SVC_CLASSES][APPS_PER_USER];
281 
282 static odp_tm_t odp_tm_test;
283 
284 static odp_pool_t odp_pool;
285 
286 static odp_tm_queue_t queue_num_tbls[NUM_SVC_CLASSES][TM_QUEUES_PER_CLASS];
287 static uint32_t next_queue_nums[NUM_SVC_CLASSES];
288 
289 static uint8_t random_buf[RANDOM_BUF_LEN];
290 static uint32_t next_rand_byte;
291 
292 static odp_atomic_u32_t atomic_pkts_into_tm;
293 static odp_atomic_u32_t atomic_pkts_from_tm;
294 
295 static uint32_t g_num_pkts_to_send = 100;
296 static uint8_t g_print_tm_stats = TRUE;
297 
298 static void tester_egress_fcn(odp_packet_t odp_pkt);
299 
300 static uint64_t tm_shaper_min_rate;
301 static uint64_t tm_shaper_max_rate;
302 static uint32_t tm_shaper_min_burst;
303 static uint32_t tm_shaper_max_burst;
304 
305 static uint64_t
306 clamp_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 
319 static uint32_t
320 clamp_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 
335 static 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 
407 static 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 
470 static 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 
535 static 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 
590 static int create_and_config_tm(void)
591 {
592  odp_tm_level_requirements_t *per_level;
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 
670 static 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 
683 static 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 
697 static 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 
718 static 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 
739 void tester_egress_fcn(odp_packet_t odp_pkt ODP_UNUSED)
740 {
741  odp_atomic_inc_u32(&atomic_pkts_from_tm);
742 }
743 
744 static 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 
812 static 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 
849 static 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 
878 static 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;
887  odp_tm_queue_info_t info;
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 
919 int 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.
Pool parameters.
uint32_t uarea_size
Minimum user area size in bytes.
uint32_t num
Number of buffers in the pool.
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...
struct odp_pool_param_t::@126 pkt
Parameters for packet pools.
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.
TM threshold parameters.
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 ...