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 <[email protected]>
---
 .../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 <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <inttypes.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <sysrepo/xpath.h>
+#include <sysrepo.h>
+#include <sysrepo_types.h>
+#include <stdbool.h>
+
+#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}
+}
+
-- 
2.17.1



-=-=-=-=-=-=-=-=-=-=-=-
Links: You receive all messages sent to this group.
View/Reply Online (#14568): 
https://lists.yoctoproject.org/g/meta-arago/message/14568
Mute This Topic: https://lists.yoctoproject.org/mt/99426849/21656
Group Owner: [email protected]
Unsubscribe: https://lists.yoctoproject.org/g/meta-arago/unsub 
[[email protected]]
-=-=-=-=-=-=-=-=-=-=-=-


Reply via email to