From 060964eaafcacd7191ff218ee5d60d0a1df79efb Mon Sep 17 00:00:00 2001 From: Maxim Menshikov <maxim.menshikov@iopsys.eu> Date: Wed, 20 Jul 2022 15:40:43 +0300 Subject: [PATCH] qosmngr: make queue number assignment independent on interface name --- src/qosmngr.c | 152 ++++++++++++++++++++++++++++---------------------- 1 file changed, 86 insertions(+), 66 deletions(-) diff --git a/src/qosmngr.c b/src/qosmngr.c index 8ff3ee8..ec54beb 100644 --- a/src/qosmngr.c +++ b/src/qosmngr.c @@ -33,10 +33,6 @@ /* Used as an internal value to query all the queues */ #define QOS_QUEUE_ANY -1 -/* Used for getting interface indexes for global q_stat array */ -#define MIN_INDEX 48 -#define MAX_INDEX 57 - /* Used for fetching keys from ubus json reqest */ #define SEPERATOR 44 #define QUOTE 34 @@ -45,8 +41,20 @@ #define PARAM1 "ifname" #define PARAM2 "qid" +/** Container for single interface data (with multiple queues) */ +typedef struct qos_interface_data { + char if_name[IFNAMSIZ]; /**< Cached interface name */ + size_t q_count; /**< Cached number of queues */ + struct qos_stats *q_stat; /**< Cached queue statistics */ +} qos_interface_data; + static int init_flag = 1; -static struct qos_stats **q_stat = {0}; + +/** Number of interfaces currently cached by qosmngr */ +static size_t interface_count = 0; +/** Array of interfaces cached by qosmngr */ +static qos_interface_data *interfaces = NULL; + /** * get_no_queues function for getting number of queues on device by calling uci qos config @@ -93,11 +101,22 @@ done: */ static int get_interface_index(const char *ifname) { - int i; + size_t i; + size_t len = strlen(ifname); + + for (i = 0; i < interface_count; ++i) { + qos_interface_data *cur = &interfaces[i]; + + if (strncmp(cur->if_name, ifname, len) == 0) { + size_t cur_len = strlen(cur->if_name); - for (i = 0; i < strlen(ifname); i++) { - if ((ifname[i] >= MIN_INDEX) && (ifname[i] <= MAX_INDEX)) { - return atoi(ifname + i); + if (cur_len != len) { + if (sscanf(ifname + len, ".%*d") != 1) { + continue; + } + } + + return (int)i; } } @@ -105,84 +124,69 @@ static int get_interface_index(const char *ifname) } /** - * get_no_ports function for getting number of ports on device by calling uci port config + * init_qstat function for initializing global q_stat structure for sustainable stats * @param none * retrun integer value 0 on success and -1 on failure */ -static int get_no_ports() +static int init_qstat() { - int ports = 0; + int ret = 0; + int index = 0; + + syslog(LOG_ERR, "Initializing global stat structure.\n"); struct uci_package *uci_pkg = NULL; struct uci_element *uci_elmnt = NULL; struct uci_context *uci_ctx = uci_alloc_context(); + interface_count = 0; + uci_load(uci_ctx, "ports", &uci_pkg); if (!uci_pkg) { syslog(LOG_ERR, "Failed to load configuration\n"); - ports = -1; + ret = -1; goto done; } + interface_count = 0; + uci_foreach_element(&uci_pkg->sections, uci_elmnt) { struct uci_section *uci_sec = uci_to_section(uci_elmnt); if (uci_sec) - ports++; + interface_count++; } -done: - uci_unload(uci_ctx, uci_pkg); - uci_free_context(uci_ctx); - return ports; -} - -/** - * init_qstat function for initializing global q_stat structure for sustainable stats - * @param none - * retrun integer value 0 on success and -1 on failure - */ -static int init_qstat() -{ - int ret = 0; - int index = 0; - - syslog(LOG_ERR, "Initializing global stat structure.\n"); - - int ports = get_no_ports(); - q_stat = (struct qos_stats **)calloc(ports, sizeof(struct qos_stats *)); - if (q_stat == NULL) { + interfaces = (qos_interface_data *)calloc(interface_count, + sizeof(qos_interface_data)); + if (interfaces == NULL) { syslog(LOG_ERR, "Initialization failed during memory allocation.\n"); ret = -1; - return ret; - } - - struct uci_package *uci_pkg = NULL; - struct uci_element *uci_elmnt = NULL; - struct uci_context *uci_ctx = uci_alloc_context(); - - uci_load(uci_ctx, "ports", &uci_pkg); - if (!uci_pkg) { - syslog(LOG_ERR, "Failed to load configuration\n"); - ret = -1; - goto done; + goto done_unload; } uci_foreach_element(&uci_pkg->sections, uci_elmnt) { struct uci_section *uci_sec = uci_to_section(uci_elmnt); if (uci_sec) { - struct uci_option *uci_opn = uci_lookup_option(uci_ctx, uci_sec, "ifname"); - index = get_interface_index(uci_opn->v.string); - int queues = get_no_queues(uci_opn->v.string); - q_stat[index] = (struct qos_stats *)calloc(queues, sizeof(struct qos_stats)); - if (q_stat[index] == NULL) { + qos_interface_data *data = &interfaces[index]; + struct uci_option *uci_opn = uci_lookup_option(uci_ctx, uci_sec, "ifname"); + int queues; + + queues = get_no_queues(uci_opn->v.string); + strcpy(data->if_name, uci_opn->v.string); + data->q_count = queues; + data->q_stat = (struct qos_stats *)calloc(queues, + sizeof(struct qos_stats)); + if (data->q_stat == NULL) { syslog(LOG_ERR, "Initialization failed during memory allocation.\n"); ret = -1; - uci_unload(uci_ctx, uci_pkg); - goto done; + goto done_unload; } + + index++; } } +done_unload: uci_unload(uci_ctx, uci_pkg); done: uci_free_context(uci_ctx); @@ -204,6 +208,8 @@ static int prepare_stats_blob(struct blob_buf *b, struct qos_stats *stats, void int index; int ret = 0; int is_read_and_reset; + qos_interface_data *iface; + struct qos_stats *q_stat; // Initialize global q_stat global struct if (init_flag) { @@ -222,29 +228,43 @@ static int prepare_stats_blob(struct blob_buf *b, struct qos_stats *stats, void } index = get_interface_index(ifname); + if (index < 0 || index >= interface_count) { + syslog(LOG_ERR, "Invalid interface index %d (out of %zu)", + index, interface_count); + return -1; + } + + iface = &interfaces[index]; + if (qid < 0 || qid >= iface->q_count) { + syslog(LOG_ERR, "Invalid queue index %d (out of %zu)", + qid, iface->q_count); + return -1; + } + + q_stat = &iface->q_stat[qid]; /*BCM968 CHIP, stats read from driver is accunulated stats, while in other its read and reset */ if (!is_read_and_reset) { - q_stat[index][qid].tx_packets = stats->tx_packets; - q_stat[index][qid].tx_bytes = stats->tx_bytes; - q_stat[index][qid].tx_dropped_packets = stats->tx_dropped_packets; - q_stat[index][qid].tx_dropped_bytes = stats->tx_dropped_bytes; + q_stat->tx_packets = stats->tx_packets; + q_stat->tx_bytes = stats->tx_bytes; + q_stat->tx_dropped_packets = stats->tx_dropped_packets; + q_stat->tx_dropped_bytes = stats->tx_dropped_bytes; } else { - q_stat[index][qid].tx_packets += stats->tx_packets; - q_stat[index][qid].tx_bytes += stats->tx_bytes; - q_stat[index][qid].tx_dropped_packets += stats->tx_dropped_packets; - q_stat[index][qid].tx_dropped_bytes += stats->tx_dropped_bytes; + q_stat->tx_packets += stats->tx_packets; + q_stat->tx_bytes += stats->tx_bytes; + q_stat->tx_dropped_packets += stats->tx_dropped_packets; + q_stat->tx_dropped_bytes += stats->tx_dropped_bytes; } dd = blobmsg_open_table(b, ""); blobmsg_add_string(b, "iface", ifname); blobmsg_add_u32(b, "qid", qid); - blobmsg_add_u32(b, "tx_packets", q_stat[index][qid].tx_packets); - blobmsg_add_u32(b, "tx_bytes", q_stat[index][qid].tx_bytes); - blobmsg_add_u32(b, "tx_dropped_packets", q_stat[index][qid].tx_dropped_packets); - blobmsg_add_u32(b, "tx_dropped_bytes", q_stat[index][qid].tx_dropped_bytes); + blobmsg_add_u32(b, "tx_packets", q_stat->tx_packets); + blobmsg_add_u32(b, "tx_bytes", q_stat->tx_bytes); + blobmsg_add_u32(b, "tx_dropped_packets", q_stat->tx_dropped_packets); + blobmsg_add_u32(b, "tx_dropped_bytes", q_stat->tx_dropped_bytes); blobmsg_close_table(b, dd); -- GitLab