From patchwork Fri Jun 9 11:55:57 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ravi Gunasekaran X-Patchwork-Id: 25328 X-Patchwork-Delegate: reatmon@ti.com Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 937B2C83005 for ; Fri, 9 Jun 2023 11:56:08 +0000 (UTC) Received: from fllv0016.ext.ti.com (fllv0016.ext.ti.com [198.47.19.142]) by mx.groups.io with SMTP id smtpd.web10.11409.1686311766322664167 for ; Fri, 09 Jun 2023 04:56:06 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=@ti.com header.s=ti-com-17q1 header.b=obhHi3kL; spf=pass (domain: ti.com, ip: 198.47.19.142, mailfrom: r-gunasekaran@ti.com) Received: from fllv0035.itg.ti.com ([10.64.41.0]) by fllv0016.ext.ti.com (8.15.2/8.15.2) with ESMTP id 359Bu5No111903 for ; Fri, 9 Jun 2023 06:56:05 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ti.com; s=ti-com-17Q1; t=1686311765; bh=CiBucnEoaYXquMt2dd0a/l8leoxYVFV7Wm0j1LGACC0=; h=From:To:CC:Subject:Date:In-Reply-To:References; b=obhHi3kLZeylmsmQX83AAEKgotdFt3/YpJ1v41KWCJ+3FemtNUT8ujgHt2udnvVb+ JH5YrHHtCEPKxe+ckPP1sg5AH+KLEt68lVRiGr5t0zUQeCLWC2hsmin7hJolayh7FY /9JCM9lRQ4gbNa3dnmgnWCRWzHMtGofTA7sLDmeI= Received: from DLEE104.ent.ti.com (dlee104.ent.ti.com [157.170.170.34]) by fllv0035.itg.ti.com (8.15.2/8.15.2) with ESMTPS id 359Bu4ZF077169 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=FAIL) for ; Fri, 9 Jun 2023 06:56:04 -0500 Received: from DLEE114.ent.ti.com (157.170.170.25) by DLEE104.ent.ti.com (157.170.170.34) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.2507.23; Fri, 9 Jun 2023 06:56:04 -0500 Received: from lelv0326.itg.ti.com (10.180.67.84) by DLEE114.ent.ti.com (157.170.170.25) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.2507.23 via Frontend Transport; Fri, 9 Jun 2023 06:56:04 -0500 Received: from uda0500640.dal.design.ti.com (ileaxei01-snat.itg.ti.com [10.180.69.5]) by lelv0326.itg.ti.com (8.15.2/8.15.2) with ESMTP id 359Btvaa022050; Fri, 9 Jun 2023 06:56:03 -0500 From: Ravi Gunasekaran To: CC: , Subject: [master/kirkstone 3/3] meta-aragos-extras: sysrepo: Introduce nw-configurator app Date: Fri, 9 Jun 2023 17:25:57 +0530 Message-ID: <20230609115557.1685-4-r-gunasekaran@ti.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20230609115557.1685-1-r-gunasekaran@ti.com> References: <20230609115557.1685-1-r-gunasekaran@ti.com> MIME-Version: 1.0 X-EXCLAIMER-MD-CONFIG: e1e8a2fd-e40a-4ac6-ac9b-f7e9cc9ee180 List-Id: X-Webhook-Received: from li982-79.members.linode.com [45.33.32.79] by aws-us-west-2-korg-lkml-1.web.codeaurora.org with HTTPS for ; Fri, 09 Jun 2023 11:56:08 -0000 X-Groupsio-URL: https://lists.yoctoproject.org/g/meta-arago/message/14568 nw-configurator is an app based on netopeer/sysrepo. It parses the syrepo datastores and configures the network parameters. The initial support is added only to parse and configure TSN-EST feature. Signed-off-by: Ravi Gunasekaran --- .../nw-configurator/files/nw-configurator.c | 409 ++++++++++++++++++ .../nw-configurator/nw-configurator.bb | 25 ++ 2 files changed, 434 insertions(+) create mode 100644 meta-arago-extras/recipes-sysrepo/nw-configurator/files/nw-configurator.c create mode 100644 meta-arago-extras/recipes-sysrepo/nw-configurator/nw-configurator.bb diff --git a/meta-arago-extras/recipes-sysrepo/nw-configurator/files/nw-configurator.c b/meta-arago-extras/recipes-sysrepo/nw-configurator/files/nw-configurator.c new file mode 100644 index 00000000..d5b8fd6e --- /dev/null +++ b/meta-arago-extras/recipes-sysrepo/nw-configurator/files/nw-configurator.c @@ -0,0 +1,409 @@ +/* + * Copyright (C) 2023 Texas Instruments Incorporated - http://www.ti.com/ + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Texas Instruments Incorporated nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define INTF_XPATH "/ietf-interfaces:interfaces/interface" +#define QBV_BRIDGE "ieee802-dot1q-bridge" +#define QBV_SCHED_BRIDGE "ieee802-dot1q-sched-bridge" + +#define MAX_CMD_LEN 500 + +#define MAX_SUPPORTED_SOCS 1 +#define MAX_PRIO 16 +#define MAX_TRAFFIC_CLASS 16 +#define NUM_TRAFFIC_CLASS 3 + +struct control_list { + uint32_t timer_interval; + uint8_t gate_state; +}; + +struct basetime { + bool present; + uint64_t sec; + uint32_t nsec; +}; +struct config_est { + bool gate_en; + uint8_t gate_states; + uint32_t gate_list_len; + uint32_t max_list_size; + struct control_list *ctrl_list; + struct basetime base_time; +}; + +static uint8_t exit_app; + +static uint32_t prio_tc_map[MAX_PRIO] = { + 0, 0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* Number of queues associated per class + * 0 means, not applicable + */ +static uint8_t num_class_queues[MAX_TRAFFIC_CLASS] = { + 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +static void sig_handler(int signum) +{ + exit_app = 1; +} + +static void free_resources(struct config_est *config) +{ + if(config->ctrl_list) + free(config->ctrl_list); + + return; +} + +static int +alloc_resources(sr_session_ctx_t *session, sr_val_t *val, + struct config_est *config) +{ + sr_xpath_ctx_t xpath_ctxt = {0}; + char *nodename = NULL; + uint32_t count; + + sr_xpath_recover(&xpath_ctxt); + + nodename = sr_xpath_node_name(val->xpath); + + if (!strcmp(nodename, "supported-list-max")) { + count = val->data.uint32_val; + + config->ctrl_list = malloc(sizeof(struct control_list)*count); + + if (!config->ctrl_list) { + printf("ERROR: Insufficient memory\n"); + return -1; + } + config->max_list_size = count; + + } else if (!strncmp(nodename, "gate-control-entry",18)){ + config->gate_list_len++; + } + + return 0; +} + +static void +parse_est_params(sr_session_ctx_t *session, sr_val_t *val, + struct config_est *config) +{ + sr_xpath_ctx_t xpath_ctxt = {0}; + char *nodename = NULL; + char *index_str = NULL; + uint64_t index; + + sr_xpath_recover(&xpath_ctxt); + + nodename = sr_xpath_node_name(val->xpath); + + if (!nodename) + goto out; + + if (!strcmp(nodename, "gate-enabled")) { + config->gate_en = val->data.bool_val; + } else if (!strcmp(nodename, "admin-gate-states")) { + config->gate_states = val->data.uint8_val; + } else if (!strcmp(nodename, "time-interval-value")) { + sr_xpath_recover(&xpath_ctxt); + index_str = sr_xpath_key_value(val->xpath, + "gate-control-entry", + "index", &xpath_ctxt); + + index = strtoul(index_str, NULL, 0); + (config->ctrl_list + index)->timer_interval = + val->data.uint32_val; + + } else if (!strcmp(nodename, "gate-states-value")) { + sr_xpath_recover(&xpath_ctxt); + index_str = sr_xpath_key_value(val->xpath, + "gate-control-entry", + "index", &xpath_ctxt); + + index = strtoul(index_str, NULL, 0); + (config->ctrl_list + index)->gate_state = val->data.uint8_val; + } else if (!strcmp(nodename, "admin-base-time")) { + config->base_time.present = true; + } else if (!strcmp(nodename, "seconds")) { + config->base_time.sec = val->data.uint64_val; + } else if (!strcmp(nodename, "nanoseconds")) { + config->base_time.nsec = val->data.uint32_val; + } + +out: + return ; +} + +static int prepare_tsn_tc_cmd(char *ifname, struct config_est *config) +{ + char tc_cmd_opts[MAX_CMD_LEN]; + char tc_cmd[MAX_CMD_LEN]; + uint64_t base_time = 0; + uint32_t offset; + int i; + + snprintf(tc_cmd, MAX_CMD_LEN, "tc qdisc replace "); + + snprintf(tc_cmd_opts, MAX_CMD_LEN, "dev %s ", ifname); + strncat(tc_cmd, tc_cmd_opts, MAX_CMD_LEN - 1 - strlen(tc_cmd)); + + snprintf(tc_cmd_opts, MAX_CMD_LEN, "parent root handle 100 taprio "); + strncat(tc_cmd, tc_cmd_opts, MAX_CMD_LEN - 1 - strlen(tc_cmd)); + + snprintf(tc_cmd_opts, MAX_CMD_LEN, "num_tc %d map ", NUM_TRAFFIC_CLASS); + strncat(tc_cmd, tc_cmd_opts, MAX_CMD_LEN - 1 - strlen(tc_cmd)); + + for (i = 0; i < MAX_PRIO; i++) { + snprintf(tc_cmd_opts, MAX_CMD_LEN, "%d ", prio_tc_map[i]); + strncat(tc_cmd, tc_cmd_opts, MAX_CMD_LEN - 1 - strlen(tc_cmd)); + } + + snprintf(tc_cmd_opts, MAX_CMD_LEN, "queues "); + strncat(tc_cmd, tc_cmd_opts, MAX_CMD_LEN - 1 - strlen(tc_cmd)); + + /* First queue-class */ + i = 0; + snprintf(tc_cmd_opts, MAX_CMD_LEN, "%d@%d ",num_class_queues[i] , 0); + strncat(tc_cmd, tc_cmd_opts, MAX_CMD_LEN - 1 - strlen(tc_cmd)); + + offset = num_class_queues[i]; + for (i = 1; i < NUM_TRAFFIC_CLASS; i++) { + snprintf(tc_cmd_opts, MAX_CMD_LEN, "%d@%d ", num_class_queues[i], offset); + strncat(tc_cmd, tc_cmd_opts, MAX_CMD_LEN - 1 - strlen(tc_cmd)); + offset += num_class_queues[i]; + } + + if (config->base_time.present) { + base_time = (config->base_time.sec * 1000000000) + + config->base_time.nsec; + + snprintf(tc_cmd_opts, MAX_CMD_LEN, "base-time %" PRIu64 " ", base_time); + strncat(tc_cmd, tc_cmd_opts, MAX_CMD_LEN - 1 - strlen(tc_cmd)); + } + + for (i = 0; i < config->gate_list_len; i++) { + snprintf(tc_cmd_opts, MAX_CMD_LEN, "sched-entry S %X %d ", + (config->ctrl_list + i)->gate_state, + (config->ctrl_list + i)->timer_interval); + + strncat(tc_cmd, tc_cmd_opts, MAX_CMD_LEN - 1 - strlen(tc_cmd)); + } + + snprintf(tc_cmd_opts, MAX_CMD_LEN, "flags 2"); + strncat(tc_cmd, tc_cmd_opts, MAX_CMD_LEN - 1 - strlen(tc_cmd)); + + printf("Executing command : %s\n", tc_cmd); + + system(tc_cmd); + return 0; +} + +static int +configure_est(sr_session_ctx_t *session, char *xpath, char *ifname, + struct config_est *config) +{ + sr_val_t *values; + size_t count; + int i, ret = -1; + + ret = sr_get_items(session, xpath, 0, 0, &values, &count); + + if (ret != SR_ERR_OK) { + printf("ERROR(%s) : sr_get_items: %s\n", sr_strerror(ret), + __func__); + + return ret; + } + + /* First time scan to allocate neccessary memory */ + for (i = 0; i < count; i++) { + alloc_resources(session, &values[i], config); + } + + if (config->gate_list_len > config->max_list_size) { + printf("Number of gate list entries more than " + "max supported entries. Check xml\n"); + printf("Not applying tc command \n"); + + ret = -1; + goto cleanup; + } + + for (i = 0; i < count; i++) { + parse_est_params(session, &values[i], config); + } + + prepare_tsn_tc_cmd(ifname, config); + +cleanup: + free_resources(config); + sr_free_values(values, count); + + return ret; +} + +static int +module_change_bridge_cb(sr_session_ctx_t *session, uint32_t sub_id, + const char *module_name, const char *xpath, sr_event_t event, + uint32_t request_id, void *private_data) +{ + sr_change_iter_t *iter; + sr_change_oper_t op; + sr_val_t *old_val; + sr_val_t *new_val; + sr_val_t *value; + sr_data_t *data; + sr_xpath_ctx_t xpath_ctx; + char newpath[300]; + char ifname_prev[20]; + struct config_est *config = NULL; + + char *ifname; + int ret = 1; + + ret = 0; + + ret = sr_get_changes_iter(session, xpath, &iter); + if (ret != SR_ERR_OK) { + printf("ERROR(%s): sr_get_changes_iter\n", sr_strerror(ret)); + goto cleanup; + } + + config = malloc(sizeof(struct config_est)); + if (!config) { + printf("ERROR : Insufficient memory\n"); + goto cleanup; + } + + memset(config, 0, sizeof(struct config_est)); + memset(ifname_prev, 0, sizeof(ifname_prev)); + + while (SR_ERR_OK == (ret = sr_get_change_next(session, iter, + &op, &old_val, &new_val))) { + + memset(config, 0, sizeof(struct config_est)); + + value = new_val ? new_val : old_val; + + ifname = sr_xpath_key_value(value->xpath, "interface", + "name", &xpath_ctx); + + if (op == SR_OP_DELETED) + continue; + + snprintf(newpath, 300, + "%s[name='%s']/%s:bridge-port/ieee802-dot1q-sched-bridge:*//*", + INTF_XPATH, ifname, QBV_BRIDGE); + + if (strcmp(ifname, ifname_prev)) { + strcpy(ifname_prev, ifname); + configure_est(session, newpath, ifname, config); + } + } + +cleanup: + if(config) { + free(config); + } + + return ret; + +} + +int main(int argc, char **argv) +{ + int rc; + sr_conn_ctx_t *connection = NULL; + sr_session_ctx_t *session = NULL; + sr_subscription_ctx_t *if_subscription = NULL; + sr_subscr_options_t opts; + + /* connect to sysrepo */ + rc = sr_connect(SR_CONN_DEFAULT, &connection); + if (rc != SR_ERR_OK) { + printf("Connecting to sysrepo failed (%s)\n", sr_strerror(rc)); + goto cleanup; + } + + rc = sr_session_start(connection, SR_DS_RUNNING, &session); + if (rc != SR_ERR_OK) { + printf("Session start failed (%s)\n", sr_strerror(rc)); + goto cleanup; + } + + opts = SR_SUBSCR_DEFAULT | SR_SUBSCR_DONE_ONLY; + + rc = sr_module_change_subscribe(session, + "ietf-interfaces","/ietf-interfaces:interfaces/interface/ieee802-dot1q-bridge:bridge-port/ieee802-dot1q-sched-bridge:*//*", + module_change_bridge_cb, NULL, 0, opts, + &if_subscription); + + if (rc != SR_ERR_OK) { + printf("Could not subscribe to module xpath :" + "//ietf-interfaces:interfaces//interface//ieee802-dot1q-bridge:bridge-port//bridge-name\n"); + } + + signal(SIGINT, sig_handler); + + while(!exit_app) + sleep(1); + +cleanup: + if (session) + sr_session_stop(session); + + if (connection) + sr_disconnect(connection); + + return rc; +} + diff --git a/meta-arago-extras/recipes-sysrepo/nw-configurator/nw-configurator.bb b/meta-arago-extras/recipes-sysrepo/nw-configurator/nw-configurator.bb new file mode 100644 index 00000000..6412c329 --- /dev/null +++ b/meta-arago-extras/recipes-sysrepo/nw-configurator/nw-configurator.bb @@ -0,0 +1,25 @@ +LICENSE="GPLv2" +DESCRIPTION = "Sysrepo based repo to configure EST" +LIC_FILES_CHKSUM = "file://nw-configurator.c;md5=a818a6cf4fbeeb21acc8b4e9956c08a4" + +SRC_URI = "file://nw-configurator.c" + +S = "${WORKDIR}" + +FILES_${PN}-dev = "${includedir}" + +DEPENDS = "sysrepo" + +inherit autotools pkgconfig + +do_compile() { + ${CC} ${CFLAGS} ${LDFLAGS} -I=${STAGING_INCDIR} ${WORKDIR}/nw-configurator.c -o nw-configurator -lsysrepo +} + +BBCLASSEXTEND = "native nativesdk" + +do_install() { + install -d ${D}${bindir} + install -m 0755 nw-configurator ${D}${bindir} +} +