From 4fe6a2aba7e7ddf7ca48e57ef783041e537d6f1f Mon Sep 17 00:00:00 2001 From: Joachim Wiberg Date: Sun, 16 Apr 2023 20:43:41 +0200 Subject: [PATCH] src/confd: initial operational data support for ietf-interfaces Signed-off-by: Joachim Wiberg --- src/confd/src/core.h | 1 + src/confd/src/ietf-interfaces.c | 166 +++++++++++++++++++++++++++++++- src/confd/src/srx_val.c | 37 +++++++ src/confd/src/srx_val.h | 3 + 4 files changed, 206 insertions(+), 1 deletion(-) diff --git a/src/confd/src/core.h b/src/confd/src/core.h index 6f28ac97..7e32fe78 100644 --- a/src/confd/src/core.h +++ b/src/confd/src/core.h @@ -14,6 +14,7 @@ #include #include +#include #include #include #include diff --git a/src/confd/src/ietf-interfaces.c b/src/confd/src/ietf-interfaces.c index f3420b0c..8bbdd13b 100644 --- a/src/confd/src/ietf-interfaces.c +++ b/src/confd/src/ietf-interfaces.c @@ -1,22 +1,44 @@ /* SPDX-License-Identifier: BSD-3-Clause */ +#include + #include "core.h" #include "srx_module.h" #include "srx_val.h" +struct iface { + TAILQ_ENTRY(iface) link; + + int ifindex; + char ifname[IFNAMSIZ]; + char hwaddr[18]; + short flags; + uint64_t speed; + short vid; + short pvid; + char upper[IFNAMSIZ]; +}; + +static const char *iffeat[] = { + "if-mib", + NULL +}; + static const char *ipfeat[] = { "ipv4-non-contiguous-netmasks", NULL }; static const struct srx_module_requirement ietf_if_reqs[] = { - { .dir = YANG_PATH_, .name = "ietf-interfaces", .rev = "2018-02-20" }, + { .dir = YANG_PATH_, .name = "ietf-interfaces", .rev = "2018-02-20", .features = iffeat }, { .dir = YANG_PATH_, .name = "iana-if-type", .rev = "2017-01-19" }, { .dir = YANG_PATH_, .name = "ietf-ip", .rev = "2018-02-22", .features = ipfeat }, { NULL } }; +static TAILQ_HEAD(iflist, iface) iface_list = TAILQ_HEAD_INITIALIZER(iface_list); + static int inet_mask2len(char *netmask) { struct in_addr ina; @@ -33,6 +55,104 @@ static int inet_mask2len(char *netmask) return len; } +static void ifprobe(void) +{ + struct if_nameindex *if_list, *i; + + if_list = if_nameindex(); + if (!if_list) { + ERROR("failed if_nameindex(): %s", strerror(errno)); + return; + } + + for (i = if_list; !(i->if_index == 0 && i->if_name == NULL); i++) { + struct iface *iface; + + if (!i->if_name || i->if_index == 0) + continue; + + iface = calloc(1, sizeof(struct iface)); + if (!iface) { + ERROR("out of memory"); + return; + } + + iface->ifindex = i->if_index; + strlcpy(iface->ifname, i->if_name, sizeof(iface->ifname)); + + /* XXX: add other data */ + TAILQ_INSERT_TAIL(&iface_list, iface, link); + } + + if_freenameindex(if_list); +} + +#define INTERFACE_XPATH "/ietf-interfaces:interfaces/interface[name='%s']" + +static void ifpopul(sr_session_ctx_t *session) +{ + struct iface *iface; + int rc = 0; + + TAILQ_FOREACH(iface, &iface_list, link) { + char xpath[sizeof(INTERFACE_XPATH) + IFNAMSIZ + 42]; + sr_val_t val = { 0 }; + + snprintf(xpath, sizeof(xpath), INTERFACE_XPATH "/if-index", iface->ifname); + val.data.int32_val = iface->ifindex; + val.type = SR_INT32_T; + rc = sr_set_item(session, xpath, &val, 0); + if (rc) + ERROR("failed setting item %s", xpath); + snprintf(xpath, sizeof(xpath), INTERFACE_XPATH "/admin-status", iface->ifname); + val.data.enum_val = "up"; + val.type = SR_ENUM_T; + rc = sr_set_item(session, xpath, &val, 0); + if (rc) + ERROR("failed setting item %s", xpath); + + if (!iface->hwaddr[0]) /* e.g., loopback */ + continue; + + snprintf(xpath, sizeof(xpath), INTERFACE_XPATH "/phys-address", iface->ifname); + rc = sr_set_item_str(session, xpath, iface->hwaddr, 0, 0); + if (rc) + ERROR("failed setting item %s", xpath); + } + + rc = sr_apply_changes(session, 0); + if (rc) + ERROR("faled: %s", sr_strerror(rc)); +} + +static void ifinit(sr_session_ctx_t *session) +{ + struct iface *iface; + int rc = 0; + + TAILQ_FOREACH(iface, &iface_list, link) { + char xpath[sizeof(INTERFACE_XPATH) + IFNAMSIZ + 42]; + sr_val_t val; + + snprintf(xpath, sizeof(xpath), INTERFACE_XPATH "/type", iface->ifname); + if (!strcmp("lo", iface->ifname)) + val.data.string_val = "iana-if-type:softwareLoopback"; + else if (!strncmp("eth", iface->ifname, 3)) + val.data.string_val = "iana-if-type:ethernetCsmacd"; + else + continue; + + val.type = SR_IDENTITYREF_T; + rc = sr_set_item(session, xpath, &val, 0); + if (rc) + ERROR("failed setting item %s", xpath); + } + + rc = sr_apply_changes(session, 0); + if (rc) + ERROR("faled: %s", sr_strerror(rc)); +} + static int ifchange(sr_session_ctx_t *session, uint32_t sub_id, const char *module, const char *xpath, sr_event_t event, unsigned request_id, void *priv) { @@ -133,6 +253,42 @@ fail: return rc; } +static int ifoper(sr_session_ctx_t *session, uint32_t sub_id, const char *module, + const char *path, const char *request_path, uint32_t request_id, + struct lyd_node **parent, void *priv) +{ + char xpath[sizeof(INTERFACE_XPATH) + IFNAMSIZ + 42]; + const struct ly_ctx *ctx; + struct iface *iface; + int first = 1; + int rc = 0; + + ctx = sr_acquire_context(sr_session_get_connection(session)); + + TAILQ_FOREACH(iface, &iface_list, link) { + snprintf(xpath, sizeof(xpath), INTERFACE_XPATH, iface->ifname); + + if ((rc = srx_set_item(ctx, parent, &first, xpath, "if-index", "%d", iface->ifindex))) + goto fail; + + if ((rc = srx_set_item(ctx, parent, &first, xpath, "admin-status", "up"))) + goto fail; + + if ((rc = srx_set_item(ctx, parent, &first, xpath, "oper-status", "up"))) + goto fail; + + if (rc) { + fail: + ERROR("Failed building data tree, libyang error %d", rc); + sr_release_context(sr_session_get_connection(session)); + return SR_ERR_INTERNAL; + } + } + + sr_release_context(sr_session_get_connection(session)); + return SR_ERR_OK; +} + int ietf_interfaces_init(struct confd *confd) { int rc; @@ -141,7 +297,15 @@ int ietf_interfaces_init(struct confd *confd) if (rc) goto err; + ifprobe(); + REGISTER_CHANGE(confd->session, "ietf-interfaces", "/ietf-interfaces:interfaces", 0, ifchange, confd, &confd->sub); + REGISTER_OPER(confd->session, "ietf-interfaces", "/ietf-interfaces:interfaces", ifoper, NULL, 0, &confd->sub); + + sr_session_switch_ds(confd->session, SR_DS_OPERATIONAL); + ifpopul(confd->session); + sr_session_switch_ds(confd->session, SR_DS_RUNNING); + ifinit(confd->session); return SR_ERR_OK; err: diff --git a/src/confd/src/srx_val.c b/src/confd/src/srx_val.c index 705bfd17..a74d494e 100644 --- a/src/confd/src/srx_val.c +++ b/src/confd/src/srx_val.c @@ -3,6 +3,43 @@ #include #include "core.h" +int srx_set_item(const struct ly_ctx *ctx, struct lyd_node **parent, int *first, + char *xpath_base, char *node, const char *fmt, ...) +{ + char xpath[strlen(xpath_base) + strlen(node) + 2]; + va_list ap; + size_t len; + char *val; + int rc; + + va_start(ap, fmt); + len = vsnprintf(NULL, 0, fmt, ap) + 1; + va_end(ap); + + val = alloca(len); + if (!val) + return -1; + + snprintf(xpath, sizeof(xpath), "%s/%s", xpath_base, node); + va_start(ap, fmt); + vsnprintf(val, len, fmt, ap); + va_end(ap); + + DEBUG("Setting first:%d xpath %s to %s", *first, xpath, val); + + if (*first) + rc = lyd_new_path(NULL, ctx, xpath, val, 0, parent); + else + rc = lyd_new_path(*parent, NULL, xpath, val, 0, NULL); + + *first = 0; + if (rc) + ERROR("Failed building data tree, xpath %s, libyang error %d: %s", + xpath, rc, ly_errmsg(ctx)); + + return rc; +} + static int srx_vaget(sr_session_ctx_t *session, const char *fmt, va_list ap, sr_val_type_t type, sr_val_t **val, size_t *cnt) { va_list apdup; diff --git a/src/confd/src/srx_val.h b/src/confd/src/srx_val.h index abefe54d..669644e2 100644 --- a/src/confd/src/srx_val.h +++ b/src/confd/src/srx_val.h @@ -8,6 +8,9 @@ #define SRX_GET_UINT8(s,v,fmt,...) srx_get_int(s, &v, SR_UINT8_T, fmt, ##__VA_ARGS__) #define SRX_GET_UINT32(s,v,fmt,...) srx_get_int(s, &v, SR_UINT32_T, fmt, ##__VA_ARGS__) +int srx_set_item(const struct ly_ctx *ctx, struct lyd_node **parent, int *first, char *xpath_base, + char *node, const char *fmt, ...); + char *srx_get_str (sr_session_ctx_t *session, const char *fmt, ...); int srx_get_int (sr_session_ctx_t *session, int *result, sr_val_type_t type, const char *fmt, ...); int srx_get_bool (sr_session_ctx_t *session, const char *fmt, ...);