From 1a15f1da7a1474d29aad77b8ad3272fcf4b4f6d1 Mon Sep 17 00:00:00 2001 From: Mohd Mehdi <husaam.mehdi@iopsys.eu> Date: Fri, 11 Apr 2025 14:23:36 +0000 Subject: [PATCH] Unified service & datamodel daemon --- .gitlab-ci.yml | 34 +---- Makefile | 70 --------- Makefile.diag.inc | 1 - bbf_plugin/Makefile | 26 ---- bbf_plugin/qos_bbf_vendor.c | 48 ------ bbf_plugin/qos_bbf_vendor.h | 20 --- common.mk | 10 -- gitlab-ci/build.sh | 2 +- gitlab-ci/functional-test.sh | 23 --- src/Makefile | 28 ++++ src/main.c | 132 ++++++++++------ {bbf_plugin => src}/qos_bbf.c | 147 ++++++++++++------ {bbf_plugin => src}/qos_bbf.h | 0 src/qosmngr.c | 161 ++++++++------------ {include => src}/qosmngr.h | 14 +- test/cmocka/Makefile | 26 ---- test/cmocka/functional_test_qos.c | 240 ------------------------------ 17 files changed, 288 insertions(+), 694 deletions(-) delete mode 100644 Makefile delete mode 100644 Makefile.diag.inc delete mode 100644 bbf_plugin/Makefile delete mode 100644 bbf_plugin/qos_bbf_vendor.c delete mode 100644 bbf_plugin/qos_bbf_vendor.h delete mode 100644 common.mk delete mode 100755 gitlab-ci/functional-test.sh create mode 100644 src/Makefile rename {bbf_plugin => src}/qos_bbf.c (96%) rename {bbf_plugin => src}/qos_bbf.h (100%) rename {include => src}/qosmngr.h (87%) delete mode 100644 test/cmocka/Makefile delete mode 100644 test/cmocka/functional_test_qos.c diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 6c92acc..a1b0995 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,24 +1,21 @@ include: - project: 'iopsys/gitlab-ci-pipeline' file: '/static-code-analysis.yml' - ref: '0.31' + ref: '1.2' + +variables: + DEBUG: 'TRUE' + SOURCE_FOLDER: "src" + CPPCHECK_OPTIONS: "--suppress=cert-STR05-C" stages: - static_code_analysis - compile_test - - unit_test - - functional_test - api_test -variables: - COMMON_IMAGE: "dev.iopsys.eu:5050/iopsys/gitlab-ci-pipeline/code-analysis:0.31" - DEBUG: 'TRUE' - SOURCE_FOLDER: "src" - RUN_CPPCHECK: "cppcheck --enable=all --error-exitcode=1 --suppress=missingInclude --suppress=unusedFunction --suppress=unreadVariable --suppress=variableScope --suppress=redundantInitialization --suppress=unusedLabel --suppress=unusedStructMember --suppress=knownConditionTrueFalse --suppress=unmatchedSuppression --force" - run_compile_test: stage: compile_test - image: dev.iopsys.eu:5050/iopsys/gitlab-ci-pipeline/code-analysis:latest + image: ${COMMON_IMAGE} allow_failure: false script: - "./gitlab-ci/install-dependencies.sh" @@ -26,7 +23,7 @@ run_compile_test: run_api_test: stage: api_test - image: dev.iopsys.eu:5050/iopsys/gitlab-ci-pipeline/code-analysis:latest + image: ${COMMON_IMAGE} allow_failure: false script: - "./gitlab-ci/install-dependencies.sh" @@ -41,18 +38,3 @@ run_api_test: - api-test-coverage.xml - api-test-memory-report.xml - timestamp.log - -run_functional_test: - stage: functional_test - image: dev.iopsys.eu:5050/iopsys/gitlab-ci-pipeline/code-analysis:latest - allow_failure: false - script: - - "./gitlab-ci/install-dependencies.sh" - - "./gitlab-ci/setup.sh" - - "./gitlab-ci/functional-test.sh" - - artifacts: - when: always - paths: - - functional-test-coverage.xml - - timestamp.log diff --git a/Makefile b/Makefile deleted file mode 100644 index d6e8359..0000000 --- a/Makefile +++ /dev/null @@ -1,70 +0,0 @@ -# Makefile for qosmngr -include common.mk - --include Makefile.diag.inc - -QOSMNGR_LIB=libqosmngr.so -PLUGIN = bbf_plugin - -GCOV=gcov -SRC_DIR = src - -CODECOVERAGE_SRC = $(addprefix $(SRC_DIR)/, qosmngr.c ) -PROG = $(PROJECT_TOPLEVEL)/qosmngr -SHARED_LIB = $(PROJECT_TOPLEVEL)/libqosmngr.so -OBJS = $(addprefix $(SRC_DIR)/, main.o qosmngr.o ) - -PROG_CFLAGS = $(CFLAGS) -I$(INCLUDE_DIR) $(DIAG_CFLAGS) -Werror -fstrict-aliasing -PROG_LDFLAGS = $(LDFLAGS) -PROG_LIBS = $(COMMON_LDFLAGS) -lgcov - -# MUSL has the following issue in snprintf, so it is ignored: -PROG_CFLAGS += -Wno-format-nonliteral - -.PHONY: all clean - -all: version $(PLUGIN) $(PROG) - -$(PLUGIN): $(OBJS) - $(MAKE) -C ./bbf_plugin - -$(PROG): $(INCLUDE_DIR)/version.h $(OBJS) - $(CC) $(PROG_LDFLAGS) -o $@ $^ $(PROG_LIBS) - -${QOSMNGR_LIB}: - $(CC) $(PROG_LDFLAGS) -shared -o $@ $^ $(PROG_LIBS) - -$(SHARED_LIB): $(INCLUDE_DIR)/version.h $(OBJS) - -version: $(INCLUDE_DIR)/version.h - -$(INCLUDE_DIR)/version.h: $(PROJECT_TOPLEVEL)/VERSION - @(dirty=$(shell (git status --porcelain | grep -q .) && echo -dirty); \ - [ -f $(PROJECT_TOPLEVEL)/VERSION ] && basever=$(shell cat $(PROJECT_TOPLEVEL)/VERSION) || \ - basever=Unknown; \ - xver=$(shell date +'%y%V%u-%H%M'); \ - echo "const char *qosmngr_base_version = \"$$basever\";" > $@; \ - echo "const char *qosmngr_xtra_version = \"$$xver$$dirty\";" >> $@; \ - ) - -test: ${QOSMNGR_LIB} - -coverage: CFLAGS += -g -O0 -fprofile-arcs -ftest-coverage -fPIC -coverage: LDFLAGS += --coverage -coverage: test $(PROG) - $(foreach testprog, $(CODECOVERAGE_SRC), $(GCOV) $(testprog);) - -functional-test: test - $(MAKE) -C test/cmocka functional-test - -%.o: %.c - $(CC) $(PROG_CFLAGS) $(FPIC) -c -o $@ $< - -clean: - rm -f *.o $(SHARED_LIB) $(PROG) $(INCLUDE_DIR)/version.h - rm -f *.xml *.html - find -name '*.gcda' -exec rm {} -fv \; - find -name '*.gcno' -exec rm {} -fv \; - find -name '*.gcov' -exec rm {} -fv \; - make -C test/cmocka clean - diff --git a/Makefile.diag.inc b/Makefile.diag.inc deleted file mode 100644 index 7729cbb..0000000 --- a/Makefile.diag.inc +++ /dev/null @@ -1 +0,0 @@ -DIAG_CFLAGS = -Wall -Wshadow -Wdouble-promotion -Wformat=2 -Wundef -fno-common -Wconversion -Wstrict-prototypes -Wno-declaration-after-statement diff --git a/bbf_plugin/Makefile b/bbf_plugin/Makefile deleted file mode 100644 index e170fd1..0000000 --- a/bbf_plugin/Makefile +++ /dev/null @@ -1,26 +0,0 @@ -LIB_QOS_BBF := libqos_bbf.so -LIB_QOS_BBF_VENDOR := libqos_vendor_bbf.so - -OBJS := qos_bbf.o -OBJS_VENDOR := qos_bbf_vendor.o - -LIB_CFLAGS = $(CFLAGS) -Wall -Werror -LIB_LDFLAGS = $(LDFLAGS) -FPIC := -fPIC - -.PHONY: all - -%.o: %.c - $(CC) $(LIB_CFLAGS) $(FPIC) -c -o $@ $< - -all: $(LIB_QOS_BBF) $(LIB_QOS_BBF_VENDOR) - -$(LIB_QOS_BBF): $(OBJS) - $(CC) $(LIB_CFLAGS) $(LIB_LDFLAGS) -shared -o $@ $^ - -$(LIB_QOS_BBF_VENDOR): $(OBJS_VENDOR) - $(CC) $(LIB_CFLAGS) $(LIB_LDFLAGS) -shared -o $@ $^ - -clean: - rm -f *.o $(LIB_QOS_BBF) $(LIB_QOS_BBF_VENDOR) - diff --git a/bbf_plugin/qos_bbf_vendor.c b/bbf_plugin/qos_bbf_vendor.c deleted file mode 100644 index 07c41e1..0000000 --- a/bbf_plugin/qos_bbf_vendor.c +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) 2024 iopsys Software Solutions AB - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License version 2.1 - * as published by the Free Software Foundation - * - * Author: Rohit Topno <r.topno@gxgroup.eu> - */ - -#include "qos_bbf_vendor.h" - -/************************************************************* - * GET & SET PARAM -*************************************************************/ -static int get_QoSClassification_VLANIDMark(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) -{ - *value = dmuci_get_value_by_section_fallback_def(((struct dm_data *)data)->config_section, "vid_mark", "-1"); - return 0; -} - -static int set_QoSClassification_VLANIDMark(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) -{ - switch (action) { - case VALUECHECK: - if (bbfdm_validate_int(ctx, value, RANGE_ARGS{{"-1",NULL}}, 1)) - return FAULT_9007; - break; - case VALUESET: - dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "vid_mark", value); - break; - } - return 0; -} - -/* ********** DynamicObj ********** */ -DM_MAP_OBJ tDynamicObj[] = { -/* parentobj, nextobject, parameter */ -{"Device.QoS.Classification.{i}.", NULL, tQoSClassificationParams}, -{0} -}; - -/* *** Device.QoS.Classification.{i}. *** */ -DMLEAF tQoSClassificationParams[] = { -/* PARAM, permission, type, getvalue, setvalue, bbfdm_type */ -{BBF_VENDOR_PREFIX"VLANIDMark", &DMWRITE, DMT_UNINT, get_QoSClassification_VLANIDMark, set_QoSClassification_VLANIDMark, BBFDM_BOTH}, -{0} -}; diff --git a/bbf_plugin/qos_bbf_vendor.h b/bbf_plugin/qos_bbf_vendor.h deleted file mode 100644 index b5eecf4..0000000 --- a/bbf_plugin/qos_bbf_vendor.h +++ /dev/null @@ -1,20 +0,0 @@ - -/* - * Copyright (C) 2024 iopsys Software Solutions AB - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License version 2.1 - * as published by the Free Software Foundation - * - * Author: Rohit Topno <r.topno@gxgroup.eu> - * - */ - -#ifndef __IOPSYS_QOS_H -#define __IOPSYS_QOS_H - -#include "libbbfdm-api/dmcommon.h" - -extern DMLEAF tQoSClassificationParams[]; - -#endif //__IOPSYS_QOS_H diff --git a/common.mk b/common.mk deleted file mode 100644 index 2069d99..0000000 --- a/common.mk +++ /dev/null @@ -1,10 +0,0 @@ -# Useful to refer to headers not located in the same directory as the source files being compiled -PROJECT_TOPLEVEL := $(dir $(CURDIR)/$(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST))) -INCLUDE_DIR = $(PROJECT_TOPLEVEL)/include - -# Common compiler options -CC=gcc # gcc || clang - -COMMON_LDFLAGS = -luci -lubus -lubox -ljson-c -lblobmsg_json -lnl-genl-3 -lnl-3 -lqos -QOSMNGR_LIB_DIR ?= $(shell dirname $(PWD)) -QOSMNGR_LDFLAGS = -lqosmngr -L$(QOSMNGR_LIB_DIR) diff --git a/gitlab-ci/build.sh b/gitlab-ci/build.sh index aa28e04..20d23f4 100755 --- a/gitlab-ci/build.sh +++ b/gitlab-ci/build.sh @@ -2,4 +2,4 @@ set -e echo "build stage" pwd -make CFLAGS='-DBBF_VENDOR_PREFIX=\"X_IOPSYS_EU_\"' +make -C ./src CFLAGS='-DBBF_VENDOR_PREFIX=\"X_IOPSYS_EU_\"' diff --git a/gitlab-ci/functional-test.sh b/gitlab-ci/functional-test.sh deleted file mode 100755 index f5231f6..0000000 --- a/gitlab-ci/functional-test.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/bash - -echo "Functional Test" -pwd - -make coverage -C ./ -supervisorctl status all -supervisorctl update -sleep 3 -supervisorctl status all - -make functional-test -C ./ - -supervisorctl stop all -supervisorctl status - -#report part -#GitLab-CI output -gcovr -r . -# Artefact -gcovr -r . --xml -o ./functional-test-coverage.xml -date +%s > timestamp.log - diff --git a/src/Makefile b/src/Makefile new file mode 100644 index 0000000..ef3e7b7 --- /dev/null +++ b/src/Makefile @@ -0,0 +1,28 @@ +PROG = qosmngr +OBJS = main.o qosmngr.o qos_bbf.o + +PROG_CFLAGS = $(CFLAGS) -Wall -Werror +PROG_LDFLAGS = $(LDFLAGS) -lbbfdm-ubus -lbbfdm-api -luci -lubus -lubox -ljson-c +PROG_LDFLAGS += -lblobmsg_json -lnl-genl-3 -lnl-3 -lqos + +ifeq ($(filter -DBBF_VENDOR_PREFIX=%,$(PROG_CFLAGS)),) +PROG_CFLAGS += -DBBF_VENDOR_PREFIX=\"X_IOWRT_EU_\" +endif + +.PHONY: all clean + +all: $(PROG) + +$(PROG): $(OBJS) + $(CC) -o $@ $^ $(PROG_LDFLAGS) + +%.o: %.c + $(CC) $(PROG_CFLAGS) $(FPIC) -c -o $@ $< + +clean: + rm -f *.o $(PROG) + rm -f *.xml *.html + find -name '*.gcda' -exec rm {} -fv \; + find -name '*.gcno' -exec rm {} -fv \; + find -name '*.gcov' -exec rm {} -fv \; + diff --git a/src/main.c b/src/main.c index 68ffc63..625523e 100644 --- a/src/main.c +++ b/src/main.c @@ -2,7 +2,7 @@ /* * main.c - qosmngr's boilerplate and entry point * - * Copyright (C) 2020 iopsys Software Solutions AB. All rights reserved. + * Copyright (C) 2020-2025 iopsys Software Solutions AB. All rights reserved. * * Author: Oskar Viljasaar <oskar.viljasaar@iopsys.eu> * @@ -25,14 +25,18 @@ #include <stdlib.h> #include <libubus.h> +#include <libbbfdm-ubus/bbfdm-ubus.h> #include "qosmngr.h" -#include "version.h" +#include "qos_bbf.h" -const char *ubus_socket; +#define PROTOCOLS_FILE "/etc/protocols" -struct ubus_context *ctx = NULL; +protocol_list_t g_protocol_maps; +extern DM_MAP_OBJ tDynamicObj[]; + +#ifdef UBUS_SUPPORT const struct blobmsg_policy get_status_policy[NUM_QOS_POLICY] = { [QOS_POLICY_IFNAME] = { .name = "ifname", .type = BLOBMSG_TYPE_STRING }, [QOS_POLICY_QID] = { .name = "qid", .type = BLOBMSG_TYPE_INT32}, @@ -52,16 +56,6 @@ static struct ubus_object test_object = { .n_methods = ARRAY_SIZE(qos_methods), }; -/** - * To get the qosmngr version - * @param : none - * return : none - */ -void qosmngr_version(void) -{ - syslog(LOG_ERR, "version : %s.%s\n", qosmngr_base_version, qosmngr_xtra_version); -} - /** * To expose the qosmngr object on ubus i.e., qos with method queue_stats * @param context input parameter pointer to ubus context @@ -72,38 +66,75 @@ static int qosmngr_publish_object(struct ubus_context *context) int ret; ret = ubus_add_object(context, &test_object); if (ret) { - syslog(LOG_ERR, "Failed to add 'qos' ubus object: %s\n", + BBF_ERR("Failed to add 'qos' ubus object: %s\n", ubus_strerror(ret)); } return ret; } +#endif + +static int init_protocol_numbers() +{ + char line[256] = {0}; + protocol_list_t *pentry; + + INIT_LIST_HEAD(&g_protocol_maps.list); + + // cppcheck-suppress cert-MSC24-C + FILE *file = fopen(PROTOCOLS_FILE, "r"); + if (!file) + return -1; + + while (fgets(line, sizeof(line), file)) { + if (line[0] == '#' || line[0] == '\n') + continue; + + char name[32] = {0}; + int number = 0; + if (sscanf(line, "%31s %d", name, &number) == 2) { + pentry = (protocol_list_t *) calloc(1, sizeof(protocol_list_t)); + if (pentry) { + pentry->proto_num = number; + snprintf(pentry->proto_name, sizeof(name), "%s", name); + list_add_tail(&pentry->list, &g_protocol_maps.list); + } + } + } + + fclose(file); + return 0; +} + +int cleanup() +{ + protocol_list_t *entry = NULL, *tmp = NULL; + + list_for_each_entry_safe(entry, tmp, &g_protocol_maps.list, list) { + list_del(&entry->list); + free(entry); + } + return 0; +} -/** - * Main function for qosmngr, everything starts here - * @param argc input number of input arguments - * @param argv input double pointer array of optional command line arguments - * retrun integer value 0 on success and -1 on failure - */ int main(int argc, char **argv) { - int ret; int ch; - int num_of_q = QOS_MIN_Q_NUM_PER_PORT; + int log_level = 7; + struct bbfdm_context bbfdm_ctx = {0}; - /* Logging to syslog */ - openlog("qosmngr", LOG_PID|LOG_CONS, LOG_LOCAL1); - - while ((ch = getopt(argc, argv, "vsq:e:")) != -1) { + while ((ch = getopt(argc, argv, "l:q:")) != -1) { switch (ch) { - case 'v': - qosmngr_version(); - exit(0); - case 's': - ubus_socket = optarg; + case 'l': + if (optarg) { + log_level = (int)strtoul(optarg, NULL, 10); + } + + if (log_level < 0 || log_level > 7) + log_level = 7; break; case 'q': - num_of_q = get_no_of_q_per_port(argv[argc-1]); + int num_of_q = get_no_of_q_per_port(argv[argc-1]); printf("%d", num_of_q); exit(0); default: @@ -111,28 +142,31 @@ int main(int argc, char **argv) } } - argc -= optind; - argv += optind; + memset(&bbfdm_ctx, 0, sizeof(struct bbfdm_context)); + bbfdm_ubus_set_service_name(&bbfdm_ctx, "qosmngr"); + bbfdm_ubus_set_log_level(log_level); + bbfdm_ubus_load_data_model(tDynamicObj); - uloop_init(); - ctx = ubus_connect(ubus_socket); - if (!ctx) { - syslog(LOG_ERR, "Failed to connect to ubus\n"); - return -1; - } + openlog("qosmngr", LOG_PID|LOG_CONS, LOG_LOCAL1); - ubus_add_uloop(ctx); + if (bbfdm_ubus_regiter_init(&bbfdm_ctx)) { + BBF_ERR("Failed to register bbfdm.qosmngr ubus"); + goto out; + } - ret = qosmngr_publish_object(ctx); - if (ret) +#ifdef UBUS_SUPPORT + if (qosmngr_publish_object(&bbfdm_ctx.ubus_ctx)) { + BBF_ERR("Failed to register qos object"); goto out; + } +#endif - /* Main loop of qosmngr */ - uloop_run(); + init_qstat(); + init_protocol_numbers(); + uloop_run(); out: - ubus_free(ctx); - uloop_done(); - + bbfdm_ubus_regiter_free(&bbfdm_ctx); + cleanup(); return 0; } diff --git a/bbf_plugin/qos_bbf.c b/src/qos_bbf.c similarity index 96% rename from bbf_plugin/qos_bbf.c rename to src/qos_bbf.c index 4b4ca12..6e40051 100644 --- a/bbf_plugin/qos_bbf.c +++ b/src/qos_bbf.c @@ -11,7 +11,9 @@ #include "qos_bbf.h" #include "libbbfdm_api.h" -#define PROTOCOLS_FILE "/etc/protocols" +#include "qosmngr.h" + +extern protocol_list_t g_protocol_maps; /************************************************************* * COMMON FUNCTIONS @@ -29,26 +31,13 @@ static int is_numeric(const char *str) static int lookup_protocol_number(const char *protocol) { - FILE *file = fopen(PROTOCOLS_FILE, "r"); - if (!file) - return -1; - - char line[256]; - while (fgets(line, sizeof(line), file)) { - if (line[0] == '#' || line[0] == '\n') - continue; - - char name[32] = {0}; - int number = 0; - if (sscanf(line, "%31s %d", name, &number) == 2) { - if (strcasecmp(name, protocol) == 0) { - fclose(file); - return number; - } + protocol_list_t *entry = NULL; + + list_for_each_entry(entry, &g_protocol_maps.list, list) { + if (strcasecmp(entry->proto_name, protocol) == 0) { + return entry->proto_num; } } - - fclose(file); return -1; } @@ -73,7 +62,7 @@ static unsigned long qos_get_new_order(void) uci_foreach_sections("qos", "classify", s) { dmuci_get_value_by_section_string(s, "order", &order); - unsigned long order_tol = DM_STRTOL(order); + unsigned long order_tol = DM_STRTOUL(order); if (order_tol > max) max = order_tol; } @@ -99,11 +88,11 @@ static void qos_update_order(const char *order, bool is_del) { struct uci_section *classify_s = NULL; char *curr_order = NULL; - unsigned long order_tol = DM_STRTOL(order); + unsigned long order_tol = DM_STRTOUL(order); uci_foreach_sections("qos", "classify", classify_s) { dmuci_get_value_by_section_string(classify_s, "order", &curr_order); - unsigned long curr_order_tol = DM_STRTOL(curr_order); + unsigned long curr_order_tol = DM_STRTOUL(curr_order); if (curr_order_tol >= order_tol) { char new_order[16] = {0}; @@ -115,6 +104,26 @@ static void qos_update_order(const char *order, bool is_del) } } +static int get_QoSQueueStats_value(struct qos_stats *stats, char *intf, char *queue) +{ + char *queue_str = queue; + if (queue && *queue && DM_STRLEN(queue) > 2 && intf && *intf) { + char queue_id[8] = {0}; + + snprintf(queue_id, sizeof(queue_id), "%c", queue_str[2]); + int qid = (int) DM_STRTOL(queue_id); + + // the function name is prepare_stats_blob + // but when the first argument is NULL + // it does not populate the blob + // and only the stats are updated + if (!prepare_stats_blob(NULL, stats, NULL, intf, qid)) { + return 0; + } + } + return 1; +} + /************************************************************* * ENTRY METHOD *************************************************************/ @@ -177,11 +186,28 @@ static int browseQoSQueueInst(struct dmctx *dmctx, DMNODE *parent_node, void *pr static int browseQoSQueueStatsInst(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance) { - struct dm_data curr_data = {0}; struct uci_section *s = NULL; char *inst = NULL; uci_path_foreach_sections(bbfdm, "dmmap_qstats", "queue_stats", s) { + struct dm_data curr_data = {0}; + + char *queue = NULL, *intf = NULL, *enabled = NULL; + struct qos_stats stats = {0}; + + enabled = dmuci_get_value_by_section_fallback_def(s, "enabled", "0"); + + // if enabled is not 0 + if (DM_STRNCMP(enabled, "0", DM_STRLEN("0"))) { + dmuci_get_value_by_section_string(s, "queue", &queue); + dmuci_get_value_by_section_string(s, "interface", &intf); + + if (!get_QoSQueueStats_value(&stats, intf, queue)) { + curr_data.additional_data = (void *)(&stats); + } else { + curr_data.additional_data = NULL; + } + } curr_data.config_section = s; @@ -946,6 +972,13 @@ static int set_QoSClassification_DestMACAddress(char *refparam, struct dmctx *ct static int get_QoSClassification_Ethertype(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { *value = dmuci_get_value_by_section_fallback_def(((struct dm_data *)data)->config_section, "ethertype", "-1"); + // if value is not -1 + if (DM_STRNCMP(*value, "-1", DM_STRLEN("-1"))) { + char *endptr = NULL; + long ethertype = strtol(*value, &endptr, 16); + dmasprintf(value, "%ld", ethertype); + } + return 0; } @@ -957,7 +990,13 @@ static int set_QoSClassification_Ethertype(char *refparam, struct dmctx *ctx, vo return FAULT_9007; break; case VALUESET: - dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "ethertype", value); + char *hex_str = NULL; + char *endptr; + long ethertype = strtol(value, &endptr, 10); + + dmasprintf(&hex_str, "0x%04X", (unsigned int)ethertype); + + dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "ethertype", hex_str); break; } return 0; @@ -1347,6 +1386,26 @@ static int set_QoSClassification_Policer(char *refparam, struct dmctx *ctx, void return 0; } +static int get_QoSClassification_VLANIDMark(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + *value = dmuci_get_value_by_section_fallback_def(((struct dm_data *)data)->config_section, "vid_mark", "-1"); + return 0; +} + +static int set_QoSClassification_VLANIDMark(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + switch (action) { + case VALUECHECK: + if (bbfdm_validate_int(ctx, value, RANGE_ARGS{{"-1",NULL}}, 1)) + return FAULT_9007; + break; + case VALUESET: + dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "vid_mark", value); + break; + } + return 0; +} + static int get_QoSPolicer_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { *value = dmuci_get_value_by_section_fallback_def(((struct dm_data *)data)->config_section, "enable", "1"); @@ -1838,45 +1897,36 @@ static int set_QoSQueueStats_Interface(char *refparam, struct dmctx *ctx, void * return 0; } -static int get_QoSQueueStats_value(void *data, char *option, char **value) +static int get_QoSQueueStats_OutputPackets(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { - char *queue_link = NULL, *intf_link = NULL; - - *value = "0"; - dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "queue", &queue_link); - dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "interface", &intf_link); - - if (queue_link && *queue_link && intf_link && *intf_link) { - json_object *res = NULL; - char queue_id[8] = {0}; - - snprintf(queue_id, sizeof(queue_id), "%c", queue_link[2]); - dmubus_call("qos", "queue_stats", UBUS_ARGS{{"ifname", intf_link, String}, {"qid", queue_id, Integer}}, 2, &res); - DM_ASSERT(res, *value = "0"); - json_object *queue_obj = dmjson_select_obj_in_array_idx(res, 0, 1, "queues"); - *value = dmjson_get_value(queue_obj, 1, option); + if (((struct dm_data *)data)->additional_data) { + dmasprintf(value, "%llu", ((struct qos_stats *)((struct dm_data *)data)->additional_data)->tx_packets); } return 0; } -static int get_QoSQueueStats_OutputPackets(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) -{ - return get_QoSQueueStats_value(data, "tx_packets", value); -} - static int get_QoSQueueStats_OutputBytes(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { - return get_QoSQueueStats_value(data, "tx_bytes", value); + if (((struct dm_data *)data)->additional_data) { + dmasprintf(value, "%llu", ((struct qos_stats *)((struct dm_data *)data)->additional_data)->tx_bytes); + } + return 0; } static int get_QoSQueueStats_DroppedPackets(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { - return get_QoSQueueStats_value(data, "tx_dropped_packets", value); + if (((struct dm_data *)data)->additional_data) { + dmasprintf(value, "%llu", ((struct qos_stats *)((struct dm_data *)data)->additional_data)->tx_dropped_packets); + } + return 0; } static int get_QoSQueueStats_DroppedBytes(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { - return get_QoSQueueStats_value(data, "tx_dropped_bytes", value); + if (((struct dm_data *)data)->additional_data) { + dmasprintf(value, "%llu", ((struct qos_stats *)((struct dm_data *)data)->additional_data)->tx_dropped_bytes); + } + return 0; } static int get_QoSShaper_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) @@ -2108,6 +2158,7 @@ DMLEAF tQoSClassificationParams[] = { {"TrafficClass", &DMWRITE, DMT_INT, get_QoSClassification_TrafficClass, set_QoSClassification_TrafficClass, BBFDM_BOTH}, {"Policer", &DMWRITE, DMT_STRING, get_QoSClassification_Policer, set_QoSClassification_Policer, BBFDM_BOTH}, //{"App", &DMWRITE, DMT_STRING, get_QoSClassification_App, set_QoSClassification_App, BBFDM_BOTH}, +{BBF_VENDOR_PREFIX"VLANIDMark", &DMWRITE, DMT_UNINT, get_QoSClassification_VLANIDMark, set_QoSClassification_VLANIDMark, BBFDM_BOTH}, {0} }; diff --git a/bbf_plugin/qos_bbf.h b/src/qos_bbf.h similarity index 100% rename from bbf_plugin/qos_bbf.h rename to src/qos_bbf.h diff --git a/src/qosmngr.c b/src/qosmngr.c index 4c05a3f..498b1f4 100644 --- a/src/qosmngr.c +++ b/src/qosmngr.c @@ -42,15 +42,15 @@ #define PARAM1 "ifname" #define PARAM2 "qid" +#define BOARD_JSON_FILE "/etc/board.json" + /** 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 */ + char if_name[IFNAMSIZ]; /**< Cached interface name */ } qos_interface_data; -static int init_flag = 1; - /** Number of interfaces currently cached by qosmngr */ static size_t interface_count = 0; /** Array of interfaces cached by qosmngr */ @@ -71,7 +71,7 @@ static int get_no_queues(const char *ifname) uci_load(uci_ctx, "qos", &uci_pkg); if (!uci_pkg) { - syslog(LOG_ERR, "Failed to load configuration\n"); + BBF_ERR("Failed to load configuration\n"); queues = -1; goto done; } @@ -127,21 +127,23 @@ static int get_interface_index(const char *ifname) return -1; } -static int init_interface(const char *ifname, size_t index) +static int init_interface_queues(const char *ifname, qos_interface_data *data) { - qos_interface_data *data = &interfaces[index]; - size_t queues = (size_t)get_no_queues(ifname); + if (data == NULL) { + BBF_ERR("Null interface entry"); + return -1; + } + strncpy(data->if_name, ifname, IFNAMSIZ); data->q_count = queues; - data->q_stat = (struct qos_stats *)calloc(queues, - sizeof(struct qos_stats)); + 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"); - free(interfaces); + BBF_ERR("Initialization failed during memory allocation.\n"); return -1; } + return 0; } @@ -150,61 +152,20 @@ static int init_interface(const char *ifname, size_t index) * @param none * retrun integer value 0 on success and -1 on failure */ -static int init_qstat(void) +int init_qstat(void) { int ret = 0; - syslog(LOG_ERR, "Initializing global stat structure.\n"); - interface_count = 0; - long int size; - FILE *fp = NULL; - char *buffer = NULL; - - fp = fopen("/etc/board.json","r"); - if (fp == NULL) - return -1; - - fseek(fp, 0L, SEEK_END); - size = ftell(fp); - rewind(fp); - - unsigned int buffer_size = 0; - /* Allocate memory for entire content */ - if (size < 0) { - syslog(LOG_ERR, "file read size < 0"); - fclose(fp); - return -1; - } else { - buffer_size = (unsigned int)size; - } - - buffer = calloc(1, buffer_size + 1); - if (buffer == NULL) { - syslog(LOG_ERR, "memory allocation to read buffer failed"); - fclose(fp); - return -1; - } - - /* Copy the file into the buffer */ - if (fread(buffer, buffer_size, 1, fp) != 1) { - syslog(LOG_ERR, "read from board.json file failed"); - free(buffer); - fclose(fp); - return -1; - } - - struct json_object *board_json = json_tokener_parse(buffer); + struct json_object *board_json = json_object_from_file(BOARD_JSON_FILE); if (board_json == NULL) { - syslog(LOG_ERR, "failed to read board.json as json"); - free(buffer); - fclose(fp); + BBF_ERR("failed to read board.json as json"); return -1; } struct json_object *network = NULL; if (!json_object_object_get_ex(board_json, "network", &network)) { - syslog(LOG_ERR, "network object not found in board.json"); + BBF_ERR("network object not found in board.json"); ret = -1; json_object_put(board_json); goto free_and_return; @@ -212,7 +173,7 @@ static int init_qstat(void) struct json_object *lan = NULL; if (!json_object_object_get_ex(network, "lan", &lan)) { - syslog(LOG_ERR, "lan object not found in board.json"); + BBF_ERR("lan object not found in board.json"); json_object_put(board_json); ret = -1; goto free_and_return; @@ -225,7 +186,7 @@ static int init_qstat(void) // its not necessary that board.json has wan section at all if (json_object_object_get_ex(network, "wan", &wan)) { if (!json_object_object_get_ex(wan, "device", &wan_device)) { - syslog(LOG_ERR, "wan device object not found in board.json"); + BBF_ERR("wan device object not found in board.json"); ret = -1; json_object_put(board_json); goto free_and_return; @@ -236,9 +197,9 @@ static int init_qstat(void) struct json_object *lan_ports = NULL; if (!json_object_object_get_ex(lan, "ports", &lan_ports)) { - syslog(LOG_INFO, "lan ports object not found in board.json"); + BBF_INFO("lan ports object not found in board.json"); if (!json_object_object_get_ex(lan, "device", &lan_ports)) { - syslog(LOG_INFO, "lan device object not found in board.json"); + BBF_INFO("lan device object not found in board.json"); ret = -1; json_object_put(board_json); goto free_and_return; @@ -256,7 +217,7 @@ static int init_qstat(void) interfaces = (qos_interface_data *)calloc(interface_count, sizeof(qos_interface_data)); if (interfaces == NULL) { - syslog(LOG_ERR, "Initialization failed during memory allocation."); + BBF_ERR("Initialization failed during memory allocation."); ret = -1; json_object_put(board_json); goto free_and_return; @@ -267,17 +228,16 @@ static int init_qstat(void) for (i = 0; i < json_object_array_length(lan_ports); i++) { struct json_object *l_port_name = json_object_array_get_idx(lan_ports, i); if (!l_port_name) { - syslog(LOG_ERR, "cannot read lan ports array"); + BBF_ERR("cannot read lan ports array"); ret = -1; json_object_put(board_json); free(interfaces); goto free_and_return; } - ret = init_interface(json_object_get_string(l_port_name), i); - + ret = init_interface_queues(json_object_get_string(l_port_name), &interfaces[i]); if (ret < 0) { - syslog(LOG_ERR, "cannot int lan ports qos"); + BBF_ERR("cannot int lan ports qos"); json_object_put(board_json); free(interfaces); goto free_and_return; @@ -285,9 +245,9 @@ static int init_qstat(void) } } else { - ret = init_interface(json_object_get_string(lan_ports), i); + ret = init_interface_queues(json_object_get_string(lan_ports), &interfaces[i]); if (ret < 0) { - syslog(LOG_ERR, "cannot int lan device qos"); + BBF_ERR("cannot int lan device qos"); json_object_put(board_json); free(interfaces); goto free_and_return; @@ -295,14 +255,13 @@ static int init_qstat(void) i++; } - if (wan_device) - ret = init_interface(json_object_get_string(wan_device), i); + if (wan_device) { + ret = init_interface_queues(json_object_get_string(wan_device), &interfaces[i]); + } json_object_put(board_json); free_and_return: - free(buffer); - fclose(fp); return ret; } @@ -313,9 +272,9 @@ free_and_return: * @param dd output parameter pointer to void used for blob buffer array elements * @param ifname input parameter pointer to char for which to get stats * @param qid input parameter integer queue identifier for which to get stats - * retrun integer value 0 on success and -1 on failure + * return integer value 0 on success and -1 on failure */ -static int prepare_stats_blob(struct blob_buf *b, struct qos_stats *stats, void *dd, +int prepare_stats_blob(struct blob_buf *b, struct qos_stats *stats, void *dd, char *ifname, int qid) { int index; @@ -326,20 +285,20 @@ static int prepare_stats_blob(struct blob_buf *b, struct qos_stats *stats, void ret = qos_get_stats(ifname, qid, stats, &is_read_and_reset); if (ret != 0) { - syslog(LOG_ERR, "blob_get_status: ret %d\n", ret); + BBF_ERR("blob_get_status: ret %d\n", ret); return ret; } index = get_interface_index(ifname); if (index < 0 || index >= interface_count) { - syslog(LOG_ERR, "Invalid interface index %d (out of %zu)", - index, interface_count); + BBF_ERR("Invalid interface index %d (out of %zu) for interface %s", + index, interface_count, ifname); return -1; } iface = &interfaces[index]; if (qid < 0 || qid >= iface->q_count) { - syslog(LOG_ERR, "Invalid queue index %d (out of %zu)", + BBF_ERR("Invalid queue index %d (out of %zu)", qid, iface->q_count); return -1; } @@ -352,29 +311,34 @@ static int prepare_stats_blob(struct blob_buf *b, struct qos_stats *stats, void 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 { + } else { 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; + + // update the contents so the caller gets latest data + memcpy(stats, q_stat, sizeof(struct qos_stats)); } - dd = blobmsg_open_table(b, ""); + if (b) { + dd = blobmsg_open_table(b, ""); - blobmsg_add_string(b, "iface", ifname); - blobmsg_add_u32(b, "qid", (uint32_t)qid); - blobmsg_add_u64(b, "tx_packets", (uint64_t)q_stat->tx_packets); - blobmsg_add_u64(b, "tx_bytes", (uint64_t)q_stat->tx_bytes); - blobmsg_add_u64(b, "tx_dropped_packets", (uint64_t)q_stat->tx_dropped_packets); - blobmsg_add_u64(b, "tx_dropped_bytes", (uint64_t)q_stat->tx_dropped_bytes); + blobmsg_add_string(b, "iface", ifname); + blobmsg_add_u32(b, "qid", (uint32_t)qid); + blobmsg_add_u64(b, "tx_packets", (uint64_t)q_stat->tx_packets); + blobmsg_add_u64(b, "tx_bytes", (uint64_t)q_stat->tx_bytes); + blobmsg_add_u64(b, "tx_dropped_packets", (uint64_t)q_stat->tx_dropped_packets); + blobmsg_add_u64(b, "tx_dropped_bytes", (uint64_t)q_stat->tx_dropped_bytes); - blobmsg_close_table(b, dd); + blobmsg_close_table(b, dd); + } return ret; } +#ifdef UBUS_SUPPORT /** * get_stats_by_ifname function for getting specific interface stats * @param b output parameter pointer to blob_buf @@ -427,7 +391,7 @@ static int get_stats_for_all_intf(struct blob_buf *b, struct qos_stats *stats, v cur->if_name, QOS_QUEUE_ANY); if (ret != 0) { - syslog(LOG_ERR, "get_stats_by_ifname failed: ret %d", ret); + BBF_ERR("get_stats_by_ifname failed: ret %d", ret); continue; } } @@ -465,7 +429,7 @@ static int validate_keys(char *req_json) if (!(!strncmp(key, PARAM1, strlen(PARAM1)) || !strncmp(key, PARAM2, strlen(PARAM2)))) { - syslog(LOG_ERR, "ERROR :: unknown parameter : %s\n", key); + BBF_ERR("ERROR :: unknown parameter : %s\n", key); return -1; } } @@ -512,10 +476,11 @@ int qosmngr_get_stats(struct ubus_context *ctx, struct ubus_object *obj, struct blob_buf b = {0}; struct qos_stats stats = {0}; + BBF_WARNING("Warning: qos ubus object has been deprecated, please use bbfdm to fetch the stats!\n"); /* Validate requested parameters, i.e., ifname and qid */ ret = validate_request(msg); if (ret) { - syslog(LOG_ERR, "validate_request failed : ret %d\n", ret); + BBF_ERR("validate_request failed : ret %d\n", ret); return UBUS_STATUS_INVALID_ARGUMENT; } @@ -536,17 +501,6 @@ int qosmngr_get_stats(struct ubus_context *ctx, struct ubus_object *obj, if (tb[QOS_POLICY_QID] && !tb[QOS_POLICY_IFNAME]) return UBUS_STATUS_INVALID_ARGUMENT; - // Initialize global q_stat global struct - if (init_flag) { - ret = init_qstat(); - if (ret) { - syslog(LOG_ERR, "Failed to initialize gobal q_stat"); - return ret; - } - syslog(LOG_INFO, "Initialized gobal q_stat successfully"); - init_flag = 0; - } - blob_buf_init(&b, 0); d = blobmsg_open_array(&b, "queues"); @@ -554,13 +508,13 @@ int qosmngr_get_stats(struct ubus_context *ctx, struct ubus_object *obj, if (tb[QOS_POLICY_IFNAME]) { ret = get_stats_by_ifname(&b, &stats, &dd, ifname, qid); if (ret != 0) { - syslog(LOG_ERR, "get_stats_by_ifname : ret %d\n", ret); + BBF_ERR("get_stats_by_ifname : ret %d\n", ret); goto fail_get_status; } } else { ret = get_stats_for_all_intf(&b, &stats, &dd); if (ret != 0) { - syslog(LOG_ERR, "get_stats_for_all_intf : ret %d\n", ret); + BBF_ERR("get_stats_for_all_intf : ret %d\n", ret); goto fail_get_status; } } @@ -573,3 +527,4 @@ int qosmngr_get_stats(struct ubus_context *ctx, struct ubus_object *obj, blob_buf_free(&b); return ret; } +#endif diff --git a/include/qosmngr.h b/src/qosmngr.h similarity index 87% rename from include/qosmngr.h rename to src/qosmngr.h index d745993..9784af2 100644 --- a/include/qosmngr.h +++ b/src/qosmngr.h @@ -30,7 +30,7 @@ #include <qos.h> /* logging though syslog */ -#include <syslog.h> +#include <libbbfdm-api/dmcommon.h> /* UCI definitions, used to parse the config files at their right location */ #define UCI_CONFIG_QOS "qos" @@ -58,13 +58,21 @@ extern const struct blobmsg_policy get_status_policy[NUM_QOS_POLICY]; /* A QoS queue. */ struct qos_queue { - char name[IFNAMSIZ]; bool enable; struct qos_queue_config config; + char name[IFNAMSIZ]; }; +typedef struct protocol_list { + struct list_head list; + int proto_num; + char proto_name[32]; +} protocol_list_t; + +int init_qstat(void); int qosmngr_get_stats(struct ubus_context *ctx, struct ubus_object *obj, struct ubus_request_data *req, const char *method, struct blob_attr *msg); - +int prepare_stats_blob(struct blob_buf *b, struct qos_stats *stats, void *dd, + char *ifname, int qid); #endif /* QOSMNGR_H */ diff --git a/test/cmocka/Makefile b/test/cmocka/Makefile deleted file mode 100644 index 0051154..0000000 --- a/test/cmocka/Makefile +++ /dev/null @@ -1,26 +0,0 @@ -include ../../common.mk - -QOSMNGR_LIB_DIR = $(PROJECT_TOPLEVEL) -CMOCKA_LIB = -lcmocka -LIBS = $(QOSMNGR_LDFLAGS) $(CMOCKA_LIB) -lpthread $(COMMON_LDFLAGS) -ljson-validator -ljson-schema-validator -ljson-editor -CFLAGS = -g -Wall -O0 -fPIC -I$(INCLUDE_DIR) -LDFLAGS = $(LIBS) -Wl,-rpath=$(QOSMNGR_LIB_DIR) -I$(QOSMNGR_LIB_DIR) --coverage -FUNCTIONAL_TESTS = functional_test_qos - -VALGRIND = valgrind --leak-check=full --show-reachable=no \ - --show-leak-kinds=all --errors-for-leak-kinds=all \ - --error-exitcode=1 --track-origins=yes - -%.o: %.c - $(CC) $(CFLAGS) $(FPIC) -c -o $@ $< - -functional_test_qos: functional_test_qos.o - $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) - -functional-test: $(FUNCTIONAL_TESTS) - $(foreach testprog, $(FUNCTIONAL_TESTS), sudo $(VALGRIND) ./$(testprog);) - -.PHONY: clean - -clean: - rm $(FUNCTIONAL_TESTS) *.o *.gcno *.gcda -fv diff --git a/test/cmocka/functional_test_qos.c b/test/cmocka/functional_test_qos.c deleted file mode 100644 index 2f15f64..0000000 --- a/test/cmocka/functional_test_qos.c +++ /dev/null @@ -1,240 +0,0 @@ -#include <stdio.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <unistd.h> -#include <stdarg.h> -#include <stddef.h> -#include <setjmp.h> -#include <errno.h> -#include <cmocka.h> - -#include <libubus.h> -#include <libubox/blobmsg_json.h> -#include <libubox/blobmsg.h> - -#include <json-validator.h> -#include <json-c/json.h> -#include <json-editor.h> -#include <json-c/json_tokener.h> - -#include "qosmngr.h" - -#define UBUS_OUTPUT_FILE "/tmp/qosmngr_ubus_output.txt" - -struct json_object *json_output = NULL; - -/** - * group_setup function to setup the test modules - * @param state input parameter pointer to a pointer to test state - */ -static int group_setup(void **state) -{ - // Start ubusd if it is not running - system("pidof ubusd || ubusd &"); - - // Restart qosmngr - system("kill $(pidof qosmngr) 2>/dev/null; ../../qosmngr &"); - - return 0; -} - -/** - * group_teardown function to cleanup the test modules - * @param state input parameter pointer to a pointer to test state - */ -static int group_teardown(void **state) -{ - // Stop qosmngr - system("kill $(pidof qosmngr) 2>/dev/null"); - - // Delete test logs - unlink(UBUS_OUTPUT_FILE); - - return 0; -} - -/** - * teardown function to cleanup the test modules - * @param state input parameter pointer to a pointer to test state - */ -static int teardown(void **state) -{ - if (json_output) { - json_object_put(json_output); // Free the output JSON object - json_output = NULL; - } - - return 0; -} - -/** - * validate_queues function to validate all queues received under queues - * @param queues input parameter pointer to json_object containg all queues to - * be validated - */ -static void validate_queues(struct json_object *queues) -{ - int i; - int len; - - assert_non_null(queues); - len = json_object_array_length(queues); - - // Assert on length as well, should be greater than 0 - assert_true(len >= 0); - - for (i = 0; i < len; i++) { - struct json_object *queue = json_object_array_get_idx(queues, i); - json_object_object_foreach(queue, key, val) { - int val_type = json_object_get_type(val); - switch(val_type) { - case json_type_int: - assert_true(json_object_get_int(val) >= 0); - break; - case json_type_string: - assert_true(!strncmp(json_object_get_string(val), - "eth", strlen("eth"))); - break; - } - } - } -} - -/** - * validate_stats function to validate json_object received under json_obj - * @param json_obj input parameter pointer to json_object containg ubus output - */ -static void validate_stats(struct json_object *json_obj) -{ - assert_non_null(json_obj); - - json_object_object_foreach(json_obj, key, val) { - int val_type = json_object_get_type(val); - - if (val_type == json_type_array) { - switch (val_type) { - case json_type_array: - validate_queues(val); - break; - } - } - } -} - -/** - * get_ubus_call_output function to fill global json output variable with ubus call output - * @param ubus_cmd input parameter pointer to char string containg ubus call - * @param negative_case input parameter of type bool to identify negative scenarios - */ -static void get_ubus_call_output(const char *ubus_cmd, bool negative_case) -{ - char cmd[256]; - int fd = -1; - char *str = NULL; - - // Put the output of ubus call into a string - snprintf(cmd, sizeof(cmd), "%s > %s", ubus_cmd, UBUS_OUTPUT_FILE); - int rc = system(cmd); - assert_return_code(rc, errno); - - fd = open(UBUS_OUTPUT_FILE, O_RDONLY); - assert_return_code(fd, errno); - - struct stat st; - rc = fstat(fd, &st); - - if(negative_case) { - assert_false(rc == 0 && st.st_size > 0); - return; - } else - assert_true(rc == 0 && st.st_size > 0); - - str = calloc(1, (size_t)st.st_size + 1); - assert_non_null(str); - - ssize_t read_len = read(fd, str, (size_t)st.st_size); - assert_int_equal((int)read_len, (int)st.st_size); - - // Parse the string to a json_object - //printf("JSON_OBJECT GET : %s\n", str); - json_output = json_tokener_parse(str); - - if (fd >= 0) - close(fd); - if (str) - free(str); -} - -/** - * test_qos_stats_no_param function to test qos_stats without any parameter - * @param state input parameter pointer to a pointer to test state - */ -static void test_qos_stats_no_param(void **state) -{ - get_ubus_call_output("ubus call qos queue_stats", false); - validate_stats(json_output); -} - -/** - * test_qos_stats_one_param function to test qos_stats with just ifname - * @param state input parameter pointer to a pointer to test state - */ -static void test_qos_stats_one_param(void **state) -{ - get_ubus_call_output("ubus call qos queue_stats '{\"ifname\":\"eth0\"}'", false); - validate_stats(json_output); -} - -/** - * test_qos_stats_all_param function to test qos_stats with all valid params - * @param state input parameter pointer to a pointer to test state - */ -static void test_qos_stats_all_param(void **state) -{ - get_ubus_call_output("ubus call qos queue_stats '{\"ifname\":\"eth0\", \"qid\":0}'", false); - validate_stats(json_output); -} - -/** - * test_qos_stats_missing_param_ifname function to test missing parameter i.e., ifname - * @param state input parameter pointer to a pointer to test state - */ -static void test_qos_stats_missing_param_ifname(void **state) -{ - get_ubus_call_output("ubus call qos queue_stats '{\"qid\":0}'", true); -} - -/** - * test_qos_stats_invalid_param_port function to test invalid parameter as port - * @param state input parameter pointer to a pointer to test state - */ -static void test_qos_stats_invalid_param_port(void **state) -{ - get_ubus_call_output("ubus call qos queue_stats '{\"port\":\"eth0\"}'", true); -} - -/** - * test_qos_stats_invalid_param_pid function to test invalid parameter as pid - * @param state input parameter pointer to a pointer to test state - */ -static void test_qos_stats_invalid_param_pid(void **state) -{ - get_ubus_call_output("ubus call qos queue_stats '{\"ifname\":\"eth0\", \"pid\":0}'", true); -} - -int main(void) -{ - const struct CMUnitTest tests[] = { - cmocka_unit_test_teardown(test_qos_stats_no_param, teardown), - cmocka_unit_test_teardown(test_qos_stats_one_param, teardown), - cmocka_unit_test_teardown(test_qos_stats_all_param, teardown), - - // -ve scenarios - cmocka_unit_test_teardown(test_qos_stats_missing_param_ifname, teardown), - cmocka_unit_test_teardown(test_qos_stats_invalid_param_port, teardown), - cmocka_unit_test_teardown(test_qos_stats_invalid_param_pid, teardown), - }; - - return cmocka_run_group_tests(tests, group_setup, group_teardown); -} -- GitLab