aboutsummaryrefslogtreecommitdiff
path: root/example
diff options
context:
space:
mode:
authorBill Fischofer <bill.fischofer@linaro.org>2015-11-17 18:16:39 -0600
committerMaxim Uvarov <maxim.uvarov@linaro.org>2016-03-04 13:24:49 +0300
commitecb0ab65b6b4e8772405d7bc2c095ef229c18c26 (patch)
treedf915bc1abcbc8d404cf96df6432739dc8002180 /example
parent2f3f19e0069fc85fbeef7164e5dcb1b0e5c61c29 (diff)
example: tm: traffic manager example
This commit includes all of the changes to build the traffic_mgr example application. Signed-off-by: Barry Spinney <spinney@ezchip.com> Signed-off-by: Bill Fischofer <bill.fischofer@linaro.org> Signed-off-by: Maxim Uvarov <maxim.uvarov@linaro.org>
Diffstat (limited to 'example')
-rw-r--r--example/Makefile.am2
-rw-r--r--example/m4/configure.m41
-rw-r--r--example/traffic_mgmt/.gitignore1
-rw-r--r--example/traffic_mgmt/Makefile.am9
-rw-r--r--example/traffic_mgmt/odp_traffic_mgmt.c781
5 files changed, 793 insertions, 1 deletions
diff --git a/example/Makefile.am b/example/Makefile.am
index 5c97fbb64..2d425c6c1 100644
--- a/example/Makefile.am
+++ b/example/Makefile.am
@@ -1 +1 @@
-SUBDIRS = classifier generator ipsec packet time timer l2fwd_simple
+SUBDIRS = classifier generator ipsec packet time timer traffic_mgmt l2fwd_simple
diff --git a/example/m4/configure.m4 b/example/m4/configure.m4
index 1710a31b8..74869ffa7 100644
--- a/example/m4/configure.m4
+++ b/example/m4/configure.m4
@@ -5,4 +5,5 @@ AC_CONFIG_FILES([example/classifier/Makefile
example/packet/Makefile
example/time/Makefile
example/timer/Makefile
+ example/traffic_mgmt/Makefile
example/l2fwd_simple/Makefile])
diff --git a/example/traffic_mgmt/.gitignore b/example/traffic_mgmt/.gitignore
new file mode 100644
index 000000000..9e742f0d8
--- /dev/null
+++ b/example/traffic_mgmt/.gitignore
@@ -0,0 +1 @@
+odp_traffic_mgmt \ No newline at end of file
diff --git a/example/traffic_mgmt/Makefile.am b/example/traffic_mgmt/Makefile.am
new file mode 100644
index 000000000..c8ff79755
--- /dev/null
+++ b/example/traffic_mgmt/Makefile.am
@@ -0,0 +1,9 @@
+include $(top_srcdir)/example/Makefile.inc
+
+bin_PROGRAMS = odp_traffic_mgmt$(EXEEXT)
+odp_traffic_mgmt_LDFLAGS = $(AM_LDFLAGS) -static
+odp_traffic_mgmt_CFLAGS = $(AM_CFLAGS) -I${top_srcdir}/example
+
+noinst_HEADERS = $(top_srcdir)/example/example_debug.h
+
+dist_odp_traffic_mgmt_SOURCES = odp_traffic_mgmt.c
diff --git a/example/traffic_mgmt/odp_traffic_mgmt.c b/example/traffic_mgmt/odp_traffic_mgmt.c
new file mode 100644
index 000000000..b4f010152
--- /dev/null
+++ b/example/traffic_mgmt/odp_traffic_mgmt.c
@@ -0,0 +1,781 @@
+/* Copyright 2015 EZchip Semiconductor Ltd. All Rights Reserved.
+ *
+ * Copyright (c) 2015, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#define _GNU_SOURCE
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <sys/resource.h>
+#include <execinfo.h>
+#include <odp.h>
+#include <odp/api/plat/packet_types.h>
+#include <example_debug.h>
+
+#define NUM_SVC_CLASSES 4
+#define USERS_PER_SVC_CLASS 2
+#define APPS_PER_USER 2
+#define TM_QUEUES_PER_APP 2
+#define NUM_USERS (USERS_PER_SVC_CLASS * NUM_SVC_CLASSES)
+#define NUM_TM_QUEUES (NUM_USERS * APPS_PER_USER * TM_QUEUES_PER_APP)
+#define TM_QUEUES_PER_USER (TM_QUEUES_PER_APP * APPS_PER_USER)
+#define TM_QUEUES_PER_CLASS (USERS_PER_SVC_CLASS * TM_QUEUES_PER_USER)
+
+#define Kbps 1000
+#define Mbps 1000000
+#define PERCENT(percent) (100 * percent)
+
+#define FALSE 0
+#define TRUE 1
+
+#define MAX(a, b) (((a) > (b)) ? (a) : (b))
+#define MIN(a, b) (((a) < (b)) ? (a) : (b))
+
+#define RANDOM_BUF_LEN 1024
+
+typedef struct {
+ odp_tm_shaper_params_t shaper_params;
+ odp_tm_threshold_params_t threshold_params;
+ odp_tm_wred_params_t wred_params[ODP_NUM_PACKET_COLORS];
+} profile_params_set_t;
+
+typedef struct {
+ odp_tm_shaper_t shaper_profile;
+ odp_tm_threshold_t threshold_profile;
+ odp_tm_wred_t wred_profiles[ODP_NUM_PACKET_COLORS];
+} profile_set_t;
+
+static const odp_init_t ODP_INIT_PARAMS = {
+ .log_fn = odp_override_log,
+ .abort_fn = odp_override_abort
+};
+
+static const odp_platform_init_t PLATFORM_PARAMS = {
+};
+
+static profile_params_set_t COMPANY_PROFILE_PARAMS = {
+ .shaper_params = {
+ .commit_bps = 50 * Mbps, .commit_burst = 1000000,
+ .peak_bps = 0, .peak_burst = 0,
+ .dual_rate = FALSE, .shaper_len_adjust = 20
+ },
+
+ .threshold_params = {
+ .max_pkts = 100000, .enable_max_pkts = TRUE,
+ .max_bytes = 10000000, .enable_max_bytes = TRUE
+ },
+
+ .wred_params = {
+ [ODP_PACKET_GREEN ... ODP_PACKET_YELLOW] = {
+ .min_threshold = PERCENT(70),
+ .med_threshold = PERCENT(90),
+ .med_drop_prob = PERCENT(80),
+ .max_drop_prob = PERCENT(100),
+ .enable_wred = TRUE,
+ .use_byte_fullness = FALSE,
+ },
+
+ [ODP_PACKET_RED] = {
+ .min_threshold = PERCENT(40),
+ .med_threshold = PERCENT(70),
+ .med_drop_prob = PERCENT(70),
+ .max_drop_prob = PERCENT(100),
+ .enable_wred = TRUE,
+ .use_byte_fullness = FALSE,
+ },
+ }
+};
+
+static profile_params_set_t COS0_PROFILE_PARAMS = {
+ .shaper_params = {
+ .commit_bps = 1 * Mbps, .commit_burst = 100000,
+ .peak_bps = 4 * Mbps, .peak_burst = 200000,
+ .dual_rate = FALSE, .shaper_len_adjust = 20
+ },
+
+ .threshold_params = {
+ .max_pkts = 10000, .enable_max_pkts = TRUE,
+ .max_bytes = 1000000, .enable_max_bytes = TRUE
+ },
+
+ .wred_params = {
+ [ODP_PACKET_GREEN ... ODP_PACKET_YELLOW] = {
+ .min_threshold = PERCENT(80),
+ .med_threshold = PERCENT(90),
+ .med_drop_prob = PERCENT(50),
+ .max_drop_prob = PERCENT(100),
+ .enable_wred = TRUE,
+ .use_byte_fullness = FALSE,
+ },
+
+ [ODP_PACKET_RED] = {
+ .min_threshold = PERCENT(60),
+ .med_threshold = PERCENT(80),
+ .med_drop_prob = PERCENT(70),
+ .max_drop_prob = PERCENT(100),
+ .enable_wred = TRUE,
+ .use_byte_fullness = FALSE,
+ },
+ }
+};
+
+static profile_params_set_t COS1_PROFILE_PARAMS = {
+ .shaper_params = {
+ .commit_bps = 500 * Kbps, .commit_burst = 50000,
+ .peak_bps = 1500 * Kbps, .peak_burst = 150000,
+ .dual_rate = FALSE, .shaper_len_adjust = 20
+ },
+
+ .threshold_params = {
+ .max_pkts = 5000, .enable_max_pkts = TRUE,
+ .max_bytes = 500000, .enable_max_bytes = TRUE
+ },
+
+ .wred_params = {
+ [ODP_PACKET_GREEN ... ODP_PACKET_YELLOW] = {
+ .min_threshold = PERCENT(40),
+ .med_threshold = PERCENT(90),
+ .med_drop_prob = PERCENT(70),
+ .max_drop_prob = PERCENT(100),
+ .enable_wred = TRUE,
+ .use_byte_fullness = FALSE,
+ },
+
+ [ODP_PACKET_RED] = {
+ .min_threshold = PERCENT(50),
+ .med_threshold = PERCENT(80),
+ .med_drop_prob = PERCENT(80),
+ .max_drop_prob = PERCENT(100),
+ .enable_wred = TRUE,
+ .use_byte_fullness = FALSE,
+ },
+ }
+};
+
+static profile_params_set_t COS2_PROFILE_PARAMS = {
+ .shaper_params = {
+ .commit_bps = 200 * Kbps, .commit_burst = 20000,
+ .peak_bps = 400 * Kbps, .peak_burst = 40000,
+ .dual_rate = FALSE, .shaper_len_adjust = 20
+ },
+
+ .threshold_params = {
+ .max_pkts = 1000, .enable_max_pkts = TRUE,
+ .max_bytes = 100000, .enable_max_bytes = TRUE
+ },
+
+ .wred_params = {
+ [ODP_PACKET_GREEN ... ODP_PACKET_YELLOW] = {
+ .min_threshold = PERCENT(50),
+ .med_threshold = PERCENT(80),
+ .med_drop_prob = PERCENT(70),
+ .max_drop_prob = PERCENT(100),
+ .enable_wred = TRUE,
+ .use_byte_fullness = FALSE,
+ },
+
+ [ODP_PACKET_RED] = {
+ .min_threshold = PERCENT(40),
+ .med_threshold = PERCENT(70),
+ .med_drop_prob = PERCENT(80),
+ .max_drop_prob = PERCENT(100),
+ .enable_wred = TRUE,
+ .use_byte_fullness = FALSE,
+ },
+ }
+};
+
+static profile_params_set_t COS3_PROFILE_PARAMS = {
+ .shaper_params = {
+ .commit_bps = 100 * Kbps, .commit_burst = 5000,
+ .peak_bps = 0, .peak_burst = 0,
+ .dual_rate = FALSE, .shaper_len_adjust = 20
+ },
+
+ .threshold_params = {
+ .max_pkts = 400, .enable_max_pkts = TRUE,
+ .max_bytes = 60000, .enable_max_bytes = TRUE
+ },
+
+ .wred_params = {
+ [ODP_PACKET_GREEN ... ODP_PACKET_YELLOW] = {
+ .min_threshold = PERCENT(40),
+ .med_threshold = PERCENT(70),
+ .med_drop_prob = PERCENT(80),
+ .max_drop_prob = PERCENT(100),
+ .enable_wred = TRUE,
+ .use_byte_fullness = FALSE,
+ },
+
+ [ODP_PACKET_RED] = {
+ .min_threshold = PERCENT(30),
+ .med_threshold = PERCENT(60),
+ .med_drop_prob = PERCENT(80),
+ .max_drop_prob = PERCENT(100),
+ .enable_wred = TRUE,
+ .use_byte_fullness = FALSE,
+ },
+ }
+};
+
+static profile_set_t COMPANY_PROFILE_SET;
+static profile_set_t COS_PROFILE_SETS[NUM_SVC_CLASSES];
+static profile_set_t USER_PROFILE_SETS[NUM_SVC_CLASSES];
+static profile_set_t APP_PROFILE_SETS[NUM_SVC_CLASSES][APPS_PER_USER];
+
+static odp_tm_t odp_tm_test;
+
+static odp_pool_t odp_pool;
+
+static odp_tm_queue_t queue_num_tbls[NUM_SVC_CLASSES][TM_QUEUES_PER_CLASS + 1];
+static uint32_t next_queue_nums[NUM_SVC_CLASSES];
+
+static uint8_t random_buf[RANDOM_BUF_LEN];
+static uint32_t next_rand_byte;
+
+static odp_atomic_u32_t atomic_pkts_into_tm;
+static odp_atomic_u32_t atomic_pkts_from_tm;
+
+static uint32_t g_num_pkts_to_send = 1000;
+static uint8_t g_print_tm_stats = TRUE;
+
+static void tester_egress_fcn(odp_packet_t odp_pkt);
+
+/** @TODO can't call hidden apis in the implementation */
+void _odp_int_name_tbl_init(void);
+
+/* Returns the number of errors encountered. */
+
+static uint32_t create_profile_set(profile_params_set_t *profile_params_set,
+ profile_set_t *profile_set,
+ const char *base_name,
+ uint32_t name_idx,
+ uint32_t shaper_scale,
+ uint32_t threshold_scale)
+{
+ odp_tm_threshold_params_t threshold_params, *thresholds;
+ odp_tm_shaper_params_t shaper_params, *shaper;
+ odp_tm_wred_params_t wred_params, *wred;
+ uint32_t err_cnt, color;
+ char name[64], wred_name[64];
+
+ err_cnt = 0;
+ if (name_idx == 0)
+ snprintf(name, sizeof(name), "%s", base_name);
+ else
+ snprintf(name, sizeof(name), "%s-%u", base_name, name_idx);
+
+ odp_tm_shaper_params_init(&shaper_params);
+ shaper = &profile_params_set->shaper_params;
+ shaper_params.commit_bps = shaper->commit_bps * shaper_scale;
+ shaper_params.peak_bps = shaper->peak_bps * shaper_scale;
+ shaper_params.commit_burst = shaper->commit_burst * shaper_scale;
+ shaper_params.peak_burst = shaper->peak_burst * shaper_scale;
+ shaper_params.dual_rate = shaper->dual_rate;
+ shaper_params.shaper_len_adjust = shaper->shaper_len_adjust;
+ profile_set->shaper_profile = odp_tm_shaper_create(name,
+ &shaper_params);
+ if (profile_set->shaper_profile == ODP_TM_INVALID)
+ err_cnt++;
+
+ odp_tm_threshold_params_init(&threshold_params);
+ thresholds = &profile_params_set->threshold_params;
+ threshold_params.max_pkts = thresholds->max_pkts * threshold_scale;
+ threshold_params.max_bytes = thresholds->max_bytes * threshold_scale;
+ threshold_params.enable_max_pkts = thresholds->enable_max_pkts;
+ threshold_params.enable_max_bytes = thresholds->enable_max_bytes;
+ profile_set->threshold_profile =
+ odp_tm_threshold_create(name, &threshold_params);
+
+ if (profile_set->threshold_profile == ODP_TM_INVALID)
+ err_cnt++;
+
+ for (color = 0; color < ODP_NUM_PACKET_COLORS; color++) {
+ snprintf(wred_name, sizeof(wred_name), "%s-%u", name, color);
+
+ odp_tm_wred_params_init(&wred_params);
+ wred = &profile_params_set->wred_params[color];
+ wred_params.min_threshold = wred->min_threshold;
+ wred_params.med_threshold = wred->med_threshold;
+ wred_params.med_drop_prob = wred->med_drop_prob;
+ wred_params.max_drop_prob = wred->max_drop_prob;
+ wred_params.enable_wred = wred->enable_wred;
+ wred_params.use_byte_fullness = wred->use_byte_fullness;
+ profile_set->wred_profiles[color] =
+ odp_tm_wred_create(wred_name, &wred_params);
+ if (profile_set->wred_profiles[color] == ODP_TM_INVALID)
+ err_cnt++;
+ }
+
+ return err_cnt;
+}
+
+/* Returns the number of errors encountered. */
+
+static uint32_t init_profile_sets(void)
+{
+ uint32_t class_shaper_scale, class_threshold_scale, user_shaper_scale;
+ uint32_t user_threshold_scale, err_cnt, app_idx;
+
+ class_shaper_scale = TM_QUEUES_PER_CLASS / 2;
+ class_threshold_scale = TM_QUEUES_PER_CLASS;
+ user_shaper_scale = TM_QUEUES_PER_USER / 2;
+ user_threshold_scale = TM_QUEUES_PER_USER;
+ err_cnt = 0;
+
+ err_cnt += create_profile_set(&COMPANY_PROFILE_PARAMS,
+ &COMPANY_PROFILE_SET,
+ "CompanyProfiles", 0, 1, 1);
+
+ err_cnt += create_profile_set(&COS0_PROFILE_PARAMS,
+ &COS_PROFILE_SETS[0], "ServiceClass0", 0,
+ class_shaper_scale,
+ class_threshold_scale);
+ err_cnt += create_profile_set(&COS1_PROFILE_PARAMS,
+ &COS_PROFILE_SETS[1], "ServiceClass1", 0,
+ class_shaper_scale,
+ class_threshold_scale);
+ err_cnt += create_profile_set(&COS2_PROFILE_PARAMS,
+ &COS_PROFILE_SETS[2], "ServiceClass2", 0,
+ class_shaper_scale,
+ class_threshold_scale);
+ err_cnt += create_profile_set(&COS3_PROFILE_PARAMS,
+ &COS_PROFILE_SETS[3], "ServiceClass3", 0,
+ class_shaper_scale,
+ class_threshold_scale);
+
+ err_cnt += create_profile_set(&COS0_PROFILE_PARAMS,
+ &USER_PROFILE_SETS[0], "UserSvc0", 0,
+ user_shaper_scale, user_threshold_scale);
+ err_cnt += create_profile_set(&COS1_PROFILE_PARAMS,
+ &USER_PROFILE_SETS[1], "UserSvc1", 0,
+ user_shaper_scale, user_threshold_scale);
+ err_cnt += create_profile_set(&COS2_PROFILE_PARAMS,
+ &USER_PROFILE_SETS[2], "UserSvc2", 0,
+ user_shaper_scale, user_threshold_scale);
+ err_cnt += create_profile_set(&COS3_PROFILE_PARAMS,
+ &USER_PROFILE_SETS[3], "UserSvc3", 0,
+ user_shaper_scale, user_threshold_scale);
+
+ for (app_idx = 0; app_idx < APPS_PER_USER; app_idx++) {
+ err_cnt += create_profile_set(&COS0_PROFILE_PARAMS,
+ &APP_PROFILE_SETS[0][app_idx],
+ "AppSvc0", app_idx + 1, 1, 1);
+ err_cnt += create_profile_set(&COS1_PROFILE_PARAMS,
+ &APP_PROFILE_SETS[1][app_idx],
+ "AppSvc1", app_idx + 1, 1, 1);
+ err_cnt += create_profile_set(&COS2_PROFILE_PARAMS,
+ &APP_PROFILE_SETS[2][app_idx],
+ "AppSvc2", app_idx + 1, 1, 1);
+ err_cnt += create_profile_set(&COS3_PROFILE_PARAMS,
+ &APP_PROFILE_SETS[3][app_idx],
+ "AppSvc3", app_idx + 1, 1, 1);
+ }
+
+ return err_cnt;
+}
+
+static int config_example_user(odp_tm_node_t cos_tm_node,
+ uint8_t svc_class,
+ uint32_t user_num)
+{
+ odp_tm_queue_params_t tm_queue_params;
+ odp_tm_node_params_t tm_node_params;
+ odp_tm_queue_t tm_queue;
+ odp_tm_node_t user_tm_node;
+ profile_set_t *profile_set;
+ uint32_t app_idx, queue_idx, svc_class_queue_num;
+ char user_name[64];
+ int rc;
+
+ profile_set = &USER_PROFILE_SETS[svc_class];
+
+ odp_tm_node_params_init(&tm_node_params);
+ tm_node_params.max_fanin = 64;
+ tm_node_params.shaper_profile = profile_set->shaper_profile;
+ tm_node_params.threshold_profile = profile_set->threshold_profile;
+ tm_node_params.wred_profile[ODP_PACKET_GREEN] =
+ profile_set->wred_profiles[0];
+ tm_node_params.wred_profile[ODP_PACKET_YELLOW] =
+ profile_set->wred_profiles[1];
+ tm_node_params.wred_profile[ODP_PACKET_RED] =
+ profile_set->wred_profiles[2];
+ tm_node_params.level = 2;
+
+ snprintf(user_name, sizeof(user_name), "Subscriber-%u", user_num);
+ user_tm_node = odp_tm_node_create(odp_tm_test, user_name,
+ &tm_node_params);
+ odp_tm_node_connect(user_tm_node, cos_tm_node);
+
+ for (app_idx = 0; app_idx < APPS_PER_USER; app_idx++) {
+ profile_set = &APP_PROFILE_SETS[svc_class][app_idx];
+ for (queue_idx = 0; queue_idx < TM_QUEUES_PER_APP;
+ queue_idx++) {
+ odp_tm_queue_params_init(&tm_queue_params);
+ tm_queue_params.shaper_profile =
+ profile_set->shaper_profile;
+ tm_queue_params.threshold_profile =
+ profile_set->threshold_profile;
+ tm_queue_params.priority = svc_class;
+
+ tm_queue_params.wred_profile[ODP_PACKET_GREEN] =
+ profile_set->wred_profiles[ODP_PACKET_GREEN];
+ tm_queue_params.wred_profile[ODP_PACKET_YELLOW] =
+ profile_set->wred_profiles[ODP_PACKET_YELLOW];
+ tm_queue_params.wred_profile[ODP_PACKET_RED] =
+ profile_set->wred_profiles[ODP_PACKET_RED];
+
+ tm_queue = odp_tm_queue_create(odp_tm_test,
+ &tm_queue_params);
+ rc = odp_tm_queue_connect(tm_queue, user_tm_node);
+ if (rc < 0)
+ return rc;
+
+ svc_class_queue_num = next_queue_nums[svc_class]++;
+ queue_num_tbls[svc_class][svc_class_queue_num + 1] =
+ tm_queue;
+ }
+ }
+
+ return 0;
+}
+
+static int config_company_node(const char *company_name)
+{
+ odp_tm_node_params_t tm_node_params;
+ profile_set_t *profile_set;
+ odp_tm_node_t company_tm_node, cos_tm_node;
+ uint32_t cos_idx, user_idx;
+ char cos_node_name[64];
+
+ profile_set = &COMPANY_PROFILE_SET;
+ odp_tm_node_params_init(&tm_node_params);
+ tm_node_params.max_fanin = 64;
+ tm_node_params.shaper_profile = profile_set->shaper_profile;
+ tm_node_params.threshold_profile = profile_set->threshold_profile;
+ tm_node_params.wred_profile[ODP_PACKET_GREEN] =
+ profile_set->wred_profiles[0];
+ tm_node_params.wred_profile[ODP_PACKET_YELLOW] =
+ profile_set->wred_profiles[1];
+ tm_node_params.wred_profile[ODP_PACKET_RED] =
+ profile_set->wred_profiles[2];
+ tm_node_params.level = 0;
+
+ company_tm_node = odp_tm_node_create(odp_tm_test, company_name,
+ &tm_node_params);
+
+ for (cos_idx = 0; cos_idx < NUM_SVC_CLASSES; cos_idx++) {
+ odp_tm_node_params_init(&tm_node_params);
+ profile_set = &COS_PROFILE_SETS[cos_idx];
+ tm_node_params.max_fanin = 64;
+ tm_node_params.shaper_profile = profile_set->shaper_profile;
+ tm_node_params.threshold_profile =
+ profile_set->threshold_profile;
+ tm_node_params.level = 1;
+
+ tm_node_params.wred_profile[ODP_PACKET_GREEN] =
+ profile_set->wred_profiles[ODP_PACKET_GREEN];
+ tm_node_params.wred_profile[ODP_PACKET_YELLOW] =
+ profile_set->wred_profiles[ODP_PACKET_YELLOW];
+ tm_node_params.wred_profile[ODP_PACKET_RED] =
+ profile_set->wred_profiles[ODP_PACKET_RED];
+
+ snprintf(cos_node_name, sizeof(cos_node_name), "%s-Class-%u",
+ company_name, cos_idx);
+ cos_tm_node = odp_tm_node_create(odp_tm_test, cos_node_name,
+ &tm_node_params);
+ odp_tm_node_connect(cos_tm_node, company_tm_node);
+
+ for (user_idx = 0; user_idx < USERS_PER_SVC_CLASS; user_idx++)
+ config_example_user(cos_tm_node, cos_idx,
+ cos_idx * 256 + user_idx);
+ }
+
+ odp_tm_node_connect(company_tm_node, ODP_TM_ROOT);
+ return 0;
+}
+
+static int create_and_config_tm(void)
+{
+ odp_tm_params_t params;
+ uint32_t err_cnt;
+
+ odp_tm_params_init(&params);
+ params.capability.max_tm_queues = 10 * NUM_TM_QUEUES;
+ params.capability.max_priority = 3;
+ params.capability.max_levels = 3;
+ params.capability.tm_queue_shaper_supported = TRUE;
+ params.capability.tm_node_shaper_supported = TRUE;
+ params.capability.red_supported = TRUE;
+ params.capability.hierarchical_red_supported = TRUE;
+ params.capability.weights_supported = TRUE;
+ params.capability.fair_queuing_supported = TRUE;
+ params.egress.egress_kind = ODP_TM_EGRESS_FN;
+ params.egress.egress_fcn = tester_egress_fcn;
+
+ odp_tm_test = odp_tm_create("TM test", &params);
+ err_cnt = init_profile_sets();
+ if (err_cnt != 0)
+ printf("%s init_profile_sets encountered %u errors\n",
+ __func__, err_cnt);
+
+ config_company_node("TestCompany");
+ return err_cnt;
+}
+
+static uint32_t random_8(void)
+{
+ uint32_t rand8;
+
+ if (RANDOM_BUF_LEN <= next_rand_byte) {
+ odp_random_data(random_buf, RANDOM_BUF_LEN, 1);
+ next_rand_byte = 0;
+ }
+
+ rand8 = random_buf[next_rand_byte++];
+ return rand8;
+}
+
+static uint32_t random_16(void)
+{
+ uint8_t byte1, byte2;
+
+ if ((RANDOM_BUF_LEN - 1) <= next_rand_byte) {
+ odp_random_data(random_buf, RANDOM_BUF_LEN, 1);
+ next_rand_byte = 0;
+ }
+
+ byte1 = random_buf[next_rand_byte++];
+ byte2 = random_buf[next_rand_byte++];
+ return (((uint16_t)byte1) << 8) | ((uint16_t)byte2);
+}
+
+static uint32_t pkt_service_class(void)
+{
+ uint32_t rand8;
+
+ /* Make most of the traffic use service class 3 to increase the amount
+ * of delayed traffic so as to stimulate more interesting behaviors.
+ */
+ rand8 = random_8();
+ switch (rand8) {
+ case 0 ... 24: return 0;
+ case 25 ... 49: return 1;
+ case 50 ... 150: return 2;
+ case 151 ... 255: return 3;
+ default: return 3;
+ }
+}
+
+static odp_packet_t make_odp_packet(uint16_t pkt_len)
+{
+ odp_packet_t odp_pkt;
+ uint8_t rand8a, rand8b, pkt_color, drop_eligible;
+
+ rand8a = random_8();
+ rand8b = random_8();
+ pkt_color = (rand8a < 224) ? 0 : ((rand8a < 248) ? 1 : 2);
+ drop_eligible = (rand8b < 240) ? 1 : 0;
+ odp_pkt = odp_packet_alloc(odp_pool, pkt_len);
+ if (odp_pkt == ODP_PACKET_INVALID) {
+ printf("%s odp_packet_alloc failure *******\n", __func__);
+ return 0;
+ }
+
+ odp_packet_color_set(odp_pkt, pkt_color);
+ odp_packet_drop_eligible_set(odp_pkt, drop_eligible);
+ odp_packet_shaper_len_adjust_set(odp_pkt, 24);
+ return odp_pkt;
+}
+
+void tester_egress_fcn(odp_packet_t odp_pkt ODP_UNUSED)
+{
+ odp_atomic_inc_u32(&atomic_pkts_from_tm);
+}
+
+static int traffic_generator(uint32_t pkts_to_send)
+{
+ odp_pool_param_t pool_params;
+ odp_tm_queue_t tm_queue;
+ odp_packet_t pkt;
+ odp_bool_t tm_is_idle;
+ uint32_t svc_class, queue_num, pkt_len, pkts_into_tm;
+ uint32_t pkts_from_tm, pkt_cnt, millisecs, odp_tm_enq_errs;
+ int rc;
+
+ memset(&pool_params, 0, sizeof(odp_pool_param_t));
+ pool_params.type = ODP_POOL_PACKET;
+ pool_params.pkt.num = pkts_to_send + 10;
+ pool_params.pkt.len = 1600;
+ pool_params.pkt.seg_len = 0;
+ pool_params.pkt.uarea_size = 0;
+
+ odp_pool = odp_pool_create("MyPktPool", &pool_params);
+ odp_tm_enq_errs = 0;
+
+ pkt_cnt = 0;
+ while (pkt_cnt < pkts_to_send) {
+ svc_class = pkt_service_class();
+ queue_num = random_16() & (TM_QUEUES_PER_CLASS - 1);
+ tm_queue = queue_num_tbls[svc_class][queue_num + 1];
+ pkt_len = ((uint32_t)((random_8() & 0x7F) + 2)) * 32;
+ pkt_len = MIN(pkt_len, 1500);
+ pkt = make_odp_packet(pkt_len);
+
+ pkt_cnt++;
+ rc = odp_tm_enq(tm_queue, pkt);
+ if (rc < 0) {
+ odp_tm_enq_errs++;
+ continue;
+ }
+
+ odp_atomic_inc_u32(&atomic_pkts_into_tm);
+ pkts_into_tm = odp_atomic_load_u32(&atomic_pkts_into_tm);
+ pkts_from_tm = odp_atomic_load_u32(&atomic_pkts_from_tm);
+ }
+
+ printf("%s odp_tm_enq_errs=%u\n", __func__, odp_tm_enq_errs);
+
+ /* Wait until the main traffic mgmt worker thread is idle and has no
+ * outstanding events (i.e. no timers, empty work queue, etc), but
+ * not longer than 60 seconds.
+ */
+ for (millisecs = 0; millisecs < 600000; millisecs++) {
+ usleep(100);
+ tm_is_idle = odp_tm_is_idle(odp_tm_test);
+ if (tm_is_idle)
+ break;
+ }
+
+ if (!tm_is_idle)
+ printf("%s WARNING stopped waiting for the TM system "
+ "to be IDLE!\n", __func__);
+
+ /* Wait for up to 2 seconds for pkts_from_tm to match pkts_into_tm. */
+ for (millisecs = 0; millisecs < 2000; millisecs++) {
+ usleep(1000);
+ pkts_into_tm = odp_atomic_load_u32(&atomic_pkts_into_tm);
+ pkts_from_tm = odp_atomic_load_u32(&atomic_pkts_from_tm);
+ if (pkts_into_tm <= pkts_from_tm)
+ break;
+ }
+
+ return 0;
+}
+
+static int process_cmd_line_options(uint32_t argc, char *argv[])
+{
+ uint32_t arg_idx;
+ char *arg;
+
+ arg_idx = 1;
+ while (arg_idx < argc) {
+ arg = argv[arg_idx++];
+ if (!arg) {
+ return -1;
+ } else if (arg[0] == '-') {
+ switch (arg[1]) {
+ case 'n':
+ if (argc <= arg_idx)
+ return -1;
+ g_num_pkts_to_send =
+ atoi(argv[arg_idx++]);
+ break;
+
+ case 'q':
+ g_print_tm_stats = FALSE;
+ break;
+
+ default:
+ printf("Unrecognized cmd line option '%s'\n",
+ arg);
+ return -1;
+ }
+ } else {
+ /* Currently all cmd line options are '-' flag based. */
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static void signal_handler(int signal)
+{
+ size_t num_stack_frames;
+ const char *signal_name;
+ void *bt_array[128];
+
+ switch (signal) {
+ case SIGILL:
+ signal_name = "SIGILL"; break;
+ case SIGFPE:
+ signal_name = "SIGFPE"; break;
+ case SIGSEGV:
+ signal_name = "SIGSEGV"; break;
+ case SIGTERM:
+ signal_name = "SIGTERM"; break;
+ case SIGBUS:
+ signal_name = "SIGBUS"; break;
+ default:
+ signal_name = "UNKNOWN"; break;
+ }
+
+ num_stack_frames = backtrace(bt_array, 100);
+ printf("Received signal=%u (%s) exiting.", signal, signal_name);
+ backtrace_symbols_fd(bt_array, num_stack_frames, fileno(stderr));
+ fflush(NULL);
+ sync();
+ abort();
+}
+
+int main(int argc, char *argv[])
+{
+ struct sigaction signal_action;
+ struct rlimit rlimit;
+ uint32_t pkts_into_tm, pkts_from_tm;
+
+ memset(&signal_action, 0, sizeof(signal_action));
+ signal_action.sa_handler = signal_handler;
+ sigfillset(&signal_action.sa_mask);
+ sigaction(SIGILL, &signal_action, NULL);
+ sigaction(SIGFPE, &signal_action, NULL);
+ sigaction(SIGSEGV, &signal_action, NULL);
+ sigaction(SIGTERM, &signal_action, NULL);
+ sigaction(SIGBUS, &signal_action, NULL);
+
+ getrlimit(RLIMIT_CORE, &rlimit);
+ rlimit.rlim_cur = rlimit.rlim_max;
+ setrlimit(RLIMIT_CORE, &rlimit);
+
+ odp_init_global(&ODP_INIT_PARAMS, &PLATFORM_PARAMS);
+ odp_init_local(ODP_THREAD_CONTROL);
+ _odp_int_name_tbl_init();
+
+ if (process_cmd_line_options(argc, argv) < 0)
+ return -1;
+
+ create_and_config_tm();
+
+ odp_random_data(random_buf, RANDOM_BUF_LEN, 1);
+ next_rand_byte = 0;
+
+ odp_atomic_init_u32(&atomic_pkts_into_tm, 0);
+ odp_atomic_init_u32(&atomic_pkts_from_tm, 0);
+
+ traffic_generator(g_num_pkts_to_send);
+
+ pkts_into_tm = odp_atomic_load_u32(&atomic_pkts_into_tm);
+ pkts_from_tm = odp_atomic_load_u32(&atomic_pkts_from_tm);
+ printf("pkts_into_tm=%u pkts_from_tm=%u\n", pkts_into_tm, pkts_from_tm);
+
+ odp_tm_stats_print(odp_tm_test);
+ return 0;
+}