From 268fcf284093b951528759389de38afe020c731d Mon Sep 17 00:00:00 2001 From: Robin Haberkorn Date: Fri, 1 Jun 2018 22:28:58 +0200 Subject: [PATCH 01/35] avoid some compiler warnings (we build with -Werror...) * the check in dm_walk_table_cb() is unnecessary since the arguments are declared as non-null. * the signature of +sessionTimeoutEvent() was wrong --- mand/dm_dmconfig.c | 2 +- mand/dm_store.c | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/mand/dm_dmconfig.c b/mand/dm_dmconfig.c index 69fab5d..f88f8b4 100644 --- a/mand/dm_dmconfig.c +++ b/mand/dm_dmconfig.c @@ -128,7 +128,7 @@ shutdown_session(SOCKCONTEXT *ctx) } static void -sessionTimeoutEvent(struct ev_loop *loop __attribute__((unused)), ev_io *w, int revents __attribute__((unused))) +sessionTimeoutEvent(struct ev_loop *loop __attribute__((unused)), ev_timer *w, int revents __attribute__((unused))) { SOCKCONTEXT *ctx = w->data; diff --git a/mand/dm_store.c b/mand/dm_store.c index ad87904..9162647 100644 --- a/mand/dm_store.c +++ b/mand/dm_store.c @@ -1243,9 +1243,6 @@ int dm_walk_table_cb(int level, void *userData, walk_cb *cb, debug("(%p, %p)\n", kw_base, st_base); - if (!kw_base || !st_base) - return 0; - ref.kw_base = kw_base; ref.kw_elem = kw_base->table; ref.st_base = st_base; From 3bd96392691e02dfb4d7cb609caab2b78c223120 Mon Sep 17 00:00:00 2001 From: Robin Haberkorn Date: Fri, 1 Jun 2018 22:31:13 +0200 Subject: [PATCH 02/35] Lua 5.3 compatibility: use luaL_optinteger() instead of luaL_optint() * the former is available on both 5.2, as well as 5.3 --- README.md | 2 +- mand/dm_luaif.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index c9318c0..46d57d7 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ aware and depend on particular entries in those models. - expat - libev - libtalloc -- lua 5.1 or 5.2 +- lua 5.1 - 5.3 - xsltproc - python - pyang diff --git a/mand/dm_luaif.c b/mand/dm_luaif.c index b714c03..690cc61 100644 --- a/mand/dm_luaif.c +++ b/mand/dm_luaif.c @@ -1341,7 +1341,7 @@ LUA_SIG(deserialize_file) luaL_argcheck(L, top && top <= 2, top, L_NUMBER); file = luaL_checkstring(L, 1); - flags = luaL_optint(L, 2, DS_USERCONFIG); + flags = (int)luaL_optinteger(L, 2, DS_USERCONFIG); debug(": LUAIF: deserialize_file %s, %d\n", file, flags); @@ -1358,7 +1358,7 @@ LUA_SIG(deserialize_directory) luaL_argcheck(L, top && top <= 2, top, L_NUMBER); dir = luaL_checkstring(L, 1); - flags = luaL_optint(L, 2, DS_USERCONFIG); + flags = (int)luaL_optinteger(L, 2, DS_USERCONFIG); debug(": LUAIF: deserialize_directory %s, %d\n", dir, flags); From 23ba579637545b4e894a324b98f954a157246e3a Mon Sep 17 00:00:00 2001 From: Robin Haberkorn Date: Fri, 1 Jun 2018 23:04:11 +0200 Subject: [PATCH 03/35] removed dependency on the rename-tool * there are actually two incompatible versions around: the Perl-based one we we're assuming and an implementation from util-linux. * instead of trying to check for the correct behaviour, we simply rename files using a POSIX shell loop now. * The Perl rename is also apparently not available on Yocto --- configure.ac | 1 - lua/Makefile.am | 5 +++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/configure.ac b/configure.ac index 5afbcf1..adada60 100644 --- a/configure.ac +++ b/configure.ac @@ -40,7 +40,6 @@ AM_PROG_CC_C_O AC_CHECK_PROG(LUAC, luac, luac) AC_CHECK_PROG(LUAC, luac5.1, luac5.1) AC_CHECK_HEADER(lua.h, , AC_MSG_ERROR(You need the lua headers) ) -AC_CHECK_PROG(RENAME, rename, rename) AC_PROG_INSTALL AC_SET_MAKE AC_CHECK_DEBUGGING diff --git a/lua/Makefile.am b/lua/Makefile.am index 1d27d9c..9918267 100644 --- a/lua/Makefile.am +++ b/lua/Makefile.am @@ -15,5 +15,6 @@ CLEANFILES = $(targets) @LUAC@ @LUACFLAGS@ -o $@ $^ install-data-hook: - @RENAME@ 's/\.out/.lua/' $(DESTDIR)$(luafunctionsdir)/*.out - + for f in $(DESTDIR)$(luafunctionsdir)/*.out; do \ + mv $$f `dirname $$f`/`basename $$f .out`.lua; \ + done From 228895baaa49e10320bd05b4d3856efde9cc5da6 Mon Sep 17 00:00:00 2001 From: Robin Haberkorn Date: Mon, 18 Jun 2018 15:05:48 +0200 Subject: [PATCH 04/35] daemonize after dmconfig server has been initialized * one purpose of daemonizing is to "signal" a startup system like systemd that the service has initialized all of its resources. (If you don't want to add dependencies on DBUS or Systemd libs) * e.g. a system service of mand should not become active before the dmconfig socket has been initialized, since otherwise systemd services depending on mand (usually dmconfig clients) might fail to open a dmconfig connection, resulting in unnecessary restarts. * NOTE: When daemonizing, mand returns exit code 2 as it uses daemon() A systemd job for mand could/should thus contain the following service-statements: Type=forking GuessMainPID=yes ExecStart=/sbin/mand -d SuccessExitStatus=2 --- mand/mand.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/mand/mand.c b/mand/mand.c index 3a44cce..26636f0 100644 --- a/mand/mand.c +++ b/mand/mand.c @@ -209,19 +209,18 @@ int main(int argc, char *argv[]) dm_load_default_config(); } - if (run_daemon) - if (daemon(1, 0) != 0) { - fprintf(stderr, "daemon failed: %s\n", strerror(errno)); - exit(1); - - } - dm_notify_init(EV_DEFAULT_UC); libdmconfigSocketType = AF_INET; if (init_libdmconfig_server(EV_DEFAULT_UC)) debug("Cannot initiate libdmconfig server\n"); + if (run_daemon) + if (daemon(1, 0) != 0) { + fprintf(stderr, "daemon failed: %s\n", strerror(errno)); + exit(1); + } + ev_loop(EV_DEFAULT_UC_ 0); dm_shutdown(); From 0ed7b27d66a4a7ce8d863fba55cea76245b59c5f Mon Sep 17 00:00:00 2001 From: Robin Haberkorn Date: Wed, 20 May 2020 20:51:56 +0200 Subject: [PATCH 05/35] do fsync() before rename(): avoids possible data loss when power cycling after dm_save() (and dmconfig's save request) see also https://stackoverflow.com/questions/7433057/is-rename-without-fsync-safe --- mand/mand.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mand/mand.c b/mand/mand.c index 26636f0..2d08479 100644 --- a/mand/mand.c +++ b/mand/mand.c @@ -68,6 +68,8 @@ void dm_save(void) fout = fdopen(fd, "w"); if (fout) { dm_serialize_store(fout, S_CFG); + fflush(fout); + fsync(fd); fclose(fout); rename(fname, DM_CONFIG); } else { From c32e6814d7acbf619ba635c75f990973c59f368c Mon Sep 17 00:00:00 2001 From: Robin Haberkorn Date: Tue, 27 Oct 2020 01:14:58 +0100 Subject: [PATCH 06/35] fixed compiler warnings/errors with GCC 7 * duplicate `const` identifiers are avoided (they are pointless anyway) * every case-statement without a `break` needs a `/* fallthrough */` comment because of -Wimplicit-fallthrough. --- libdmconfig/dm_dmconfig_rpc_stub.c | 4 ++-- libdmconfig/dm_dmconfig_rpc_stub.h | 4 ++-- libdmconfig/dmcontext.c | 1 + mand/dm_luaif.c | 13 +++++++++++++ 4 files changed, 18 insertions(+), 4 deletions(-) diff --git a/libdmconfig/dm_dmconfig_rpc_stub.c b/libdmconfig/dm_dmconfig_rpc_stub.c index 0a9de7e..05364e1 100644 --- a/libdmconfig/dm_dmconfig_rpc_stub.c +++ b/libdmconfig/dm_dmconfig_rpc_stub.c @@ -363,7 +363,7 @@ uint32_t rpc_db_cancel_async(DMCONTEXT *ctx, DMRESULT_CB cb, void *data) return dm_enqueue_request(ctx, req, cb, data); } -uint32_t rpc_db_findinstance_async(DMCONTEXT *ctx, const const char *path, const char *name, const struct dm2_avp *search, DMRESULT_CB cb, void *data) +uint32_t rpc_db_findinstance_async(DMCONTEXT *ctx, const char *path, const char *name, const struct dm2_avp *search, DMRESULT_CB cb, void *data) { uint32_t rc; DM2_REQUEST *req; @@ -684,7 +684,7 @@ uint32_t rpc_db_cancel(DMCONTEXT *ctx, DM2_AVPGRP *answer) return reply.rc; } -uint32_t rpc_db_findinstance(DMCONTEXT *ctx, const const char *path, const char *name, const struct dm2_avp *search, DM2_AVPGRP *answer) +uint32_t rpc_db_findinstance(DMCONTEXT *ctx, const char *path, const char *name, const struct dm2_avp *search, DM2_AVPGRP *answer) { struct async_reply reply = {.rc = RC_OK, .answer = answer }; diff --git a/libdmconfig/dm_dmconfig_rpc_stub.h b/libdmconfig/dm_dmconfig_rpc_stub.h index 7a46192..1acaa3a 100644 --- a/libdmconfig/dm_dmconfig_rpc_stub.h +++ b/libdmconfig/dm_dmconfig_rpc_stub.h @@ -38,7 +38,7 @@ uint32_t rpc_db_dump_async(DMCONTEXT *ctx, const char *path, DMRESULT_CB cb, voi uint32_t rpc_db_save_async(DMCONTEXT *ctx, DMRESULT_CB cb, void *data); uint32_t rpc_db_commit_async(DMCONTEXT *ctx, DMRESULT_CB cb, void *data); uint32_t rpc_db_cancel_async(DMCONTEXT *ctx, DMRESULT_CB cb, void *data); -uint32_t rpc_db_findinstance_async(DMCONTEXT *ctx, const const char *path, const char *name, const struct dm2_avp *search, DMRESULT_CB cb, void *data); +uint32_t rpc_db_findinstance_async(DMCONTEXT *ctx, const char *path, const char *name, const struct dm2_avp *search, DMRESULT_CB cb, void *data); uint32_t rpc_register_role_async(DMCONTEXT *ctx, const char *role, DMRESULT_CB cb, void *data); uint32_t rpc_system_restart_async(DMCONTEXT *ctx); uint32_t rpc_system_shutdown_async(DMCONTEXT *ctx); @@ -71,7 +71,7 @@ uint32_t rpc_db_dump(DMCONTEXT *ctx, const char *path, DM2_AVPGRP *grp); uint32_t rpc_db_save(DMCONTEXT *ctx, DM2_AVPGRP *grp); uint32_t rpc_db_commit(DMCONTEXT *ctx, DM2_AVPGRP *grp); uint32_t rpc_db_cancel(DMCONTEXT *ctx, DM2_AVPGRP *grp); -uint32_t rpc_db_findinstance(DMCONTEXT *ctx, const const char *path, const char *name, const struct dm2_avp *search, DM2_AVPGRP *grp); +uint32_t rpc_db_findinstance(DMCONTEXT *ctx, const char *path, const char *name, const struct dm2_avp *search, DM2_AVPGRP *grp); uint32_t rpc_register_role(DMCONTEXT *ctx, const char *role); uint32_t rpc_system_restart(DMCONTEXT *ctx); uint32_t rpc_system_shutdown(DMCONTEXT *ctx); diff --git a/libdmconfig/dmcontext.c b/libdmconfig/dmcontext.c index 791f378..ecc3fb2 100644 --- a/libdmconfig/dmcontext.c +++ b/libdmconfig/dmcontext.c @@ -181,6 +181,7 @@ uint32_t dm_enqueue(DMCONTEXT *socket, DM2_REQUEST *req, int flags, DMRESULT_CB /* initialize static hopid */ switch (hopid) { /* one never knows... */ case 0: srand((unsigned int)time(NULL)); + /* fallthrough */ case MAX_INT: hopid = endid = (float)rand()/RAND_MAX * (MAX_INT-1) + 1; break; default: hopid = ++endid; diff --git a/mand/dm_luaif.c b/mand/dm_luaif.c index 690cc61..ca8d06d 100644 --- a/mand/dm_luaif.c +++ b/mand/dm_luaif.c @@ -649,6 +649,7 @@ luaif_get_cb(void *data, const dm_selector sb __attribute__((unused)), switch (type) { case AVP_UNKNOWN: type = AVP_ENUM; + /* fallthrough */ case AVP_ENUM: lua_pushstring(L, dm_int2enum(&elem->u.e, DM_ENUM(val))); @@ -673,6 +674,7 @@ luaif_get_cb(void *data, const dm_selector sb __attribute__((unused)), switch (type) { case AVP_UNKNOWN: type = AVP_COUNTER; + /* fallthrough */ case AVP_COUNTER: lua_pushinteger(L, DM_UINT(val)); @@ -688,6 +690,7 @@ luaif_get_cb(void *data, const dm_selector sb __attribute__((unused)), switch (type) { case AVP_UNKNOWN: type = AVP_INT32; + /* fallthrough */ case AVP_INT32: lua_pushinteger(L, DM_INT(val)); @@ -703,6 +706,7 @@ luaif_get_cb(void *data, const dm_selector sb __attribute__((unused)), switch (type) { case AVP_UNKNOWN: type = AVP_UINT32; + /* fallthrough */ case AVP_UINT32: lua_pushinteger(L, DM_UINT(val)); @@ -718,6 +722,7 @@ luaif_get_cb(void *data, const dm_selector sb __attribute__((unused)), switch (type) { case AVP_UNKNOWN: type = AVP_INT64; + /* fallthrough */ case AVP_INT64: { char buf[INT64_DIGITS]; @@ -737,6 +742,7 @@ luaif_get_cb(void *data, const dm_selector sb __attribute__((unused)), switch (type) { case AVP_UNKNOWN: type = AVP_UINT64; + /* fallthrough */ case AVP_UINT64: { char buf[UINT64_DIGITS]; @@ -756,6 +762,7 @@ luaif_get_cb(void *data, const dm_selector sb __attribute__((unused)), switch (type) { case AVP_UNKNOWN: type = AVP_STRING; + /* fallthrough */ case AVP_STRING: lua_pushstring(L, DM_STRING(val) ? : ""); @@ -772,6 +779,7 @@ luaif_get_cb(void *data, const dm_selector sb __attribute__((unused)), switch (type) { case AVP_UNKNOWN: type = AVP_BINARY; + /* fallthrough */ case AVP_BINARY: if (DM_BINARY(val)) lua_pushlstring(L, (const char *)DM_BINARY(val)->data, DM_BINARY(val)->len); @@ -792,6 +800,7 @@ luaif_get_cb(void *data, const dm_selector sb __attribute__((unused)), switch (type) { case AVP_UNKNOWN: type = AVP_ADDRESS; + /* fallthrough */ case AVP_ADDRESS: inet_ntop(AF_INET, DM_IP4_REF(val), buf, sizeof(buf)); lua_pushstring(L, buf); @@ -811,6 +820,7 @@ luaif_get_cb(void *data, const dm_selector sb __attribute__((unused)), switch (type) { case AVP_UNKNOWN: type = AVP_ADDRESS; + /* fallthrough */ case AVP_ADDRESS: inet_ntop(AF_INET6, DM_IP6_REF(val), buf, sizeof(buf)); lua_pushstring(L, buf); @@ -828,6 +838,7 @@ luaif_get_cb(void *data, const dm_selector sb __attribute__((unused)), switch (type) { case AVP_UNKNOWN: type = AVP_BOOL; + /* fallthrough */ case AVP_BOOL: lua_pushboolean(L, DM_BOOL(val)); @@ -844,6 +855,7 @@ luaif_get_cb(void *data, const dm_selector sb __attribute__((unused)), switch (type) { case AVP_UNKNOWN: type = AVP_DATE; + /* fallthrough */ case AVP_DATE: lua_pushinteger(L, DM_TIME(val)); @@ -884,6 +896,7 @@ luaif_get_cb(void *data, const dm_selector sb __attribute__((unused)), switch (type) { case AVP_UNKNOWN: type = AVP_PATH; + /* fallthrough */ case AVP_PATH: { char buffer[MAX_PARAM_NAME_LEN]; char *name; From b7a0c0cd36c6508c8549e1eb662e80e23b68a1b4 Mon Sep 17 00:00:00 2001 From: Robin Haberkorn Date: Thu, 28 Jan 2021 15:25:15 +0100 Subject: [PATCH 07/35] fixed recursive notifications on the root (ie. entire database tree) This adds support for empty selectors in dm_set_notify_by_selector_recursive(). It may actually be better to extend dm_get_element_ref(). --- mand/dm_notify.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/mand/dm_notify.c b/mand/dm_notify.c index 7111540..51de56c 100644 --- a/mand/dm_notify.c +++ b/mand/dm_notify.c @@ -367,7 +367,12 @@ DM_RESULT dm_set_notify_by_selector_recursive(const dm_selector sel, int slot, i ENTER(); - if (dm_get_element_ref(sel, &ref)) { + if (!sel[0]) { + debug("(): notify on root\n"); + set_notify_slot_table(&dm_root, dm_value_store, slot, value); + EXIT(); + return DM_OK; + } else if (dm_get_element_ref(sel, &ref)) { #if DEBUG debug("(): %s\n", ref.kw_base->name); #endif From e026ba4438a9505b8862cee11f39baf9bb5887e3 Mon Sep 17 00:00:00 2001 From: Robin Haberkorn Date: Fri, 19 Feb 2021 05:34:54 +0100 Subject: [PATCH 08/35] rewrote event_client_sample.c: it now represents the current state of the API --- .gitignore | 1 + README.md | 3 + libdmconfig/tests/Makefile.am | 8 +- libdmconfig/tests/event_client_sample.c | 398 +++++++++++++----------- 4 files changed, 219 insertions(+), 191 deletions(-) diff --git a/.gitignore b/.gitignore index e5fe2fd..1e87ecd 100644 --- a/.gitignore +++ b/.gitignore @@ -17,6 +17,7 @@ mand/p_table_stubs.c # libdmconfig build files libdmconfig/codes.h libdmconfig/extensivedump.out +libdmconfig/tests/event_client_sample # lua build files lua/fncAdminPasswd.out diff --git a/README.md b/README.md index 46d57d7..1ba8425 100644 --- a/README.md +++ b/README.md @@ -75,6 +75,9 @@ libdmconfig API documentation can be build with doxygen: For how to use this API, refer to the C and Lua samples in libdmconfig/tests. +**NOTE:** Currently only the [event_client_sample.c](libdmconfig/tests/event_client_sample.c) +example builds and reflects the current state of the API. + # Adding new YANG modules YANG is specified in [RFC 6020][1]. mand already contains several IETF YANG modules diff --git a/libdmconfig/tests/Makefile.am b/libdmconfig/tests/Makefile.am index d8d5e12..5a18e1a 100644 --- a/libdmconfig/tests/Makefile.am +++ b/libdmconfig/tests/Makefile.am @@ -8,8 +8,8 @@ AM_CFLAGS = -g -std=gnu99 \ -I$(top_srcdir) -check_PROGRAMS = client_sample polling_sample dm_sample \ - event_client_sample event_notify_sample - -LDADD = ../libdmconfig.la +check_PROGRAMS = event_client_sample +#check_PROGRAMS = client_sample polling_sample dm_sample \ +# event_client_sample event_notify_sample +LDADD = ../libdmconfig.la ../libdm_dmclient.la diff --git a/libdmconfig/tests/event_client_sample.c b/libdmconfig/tests/event_client_sample.c index 3cb7399..cd39a84 100644 --- a/libdmconfig/tests/event_client_sample.c +++ b/libdmconfig/tests/event_client_sample.c @@ -3,138 +3,133 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /* - libdmconfig client lib sample: uses the nonblocking libevent-based API + * libdmconfig client lib sample: uses the nonblocking libev-based API */ #define _GNU_SOURCE #include #include +#include #include +#include -#include -#include +#include +#include #include +#include -#define CB_ERR(...) { \ +#define CB_ERR(...) do { \ fprintf(stderr, __VA_ARGS__); \ return; \ -} +} while (0) -void registerEndSession(DMCONTEXT *dmCtx); -void sessionTerminated(DMCONFIG_EVENT event, DMCONTEXT *dmCtx __attribute__((unused)), - void *user_data __attribute__((unused)), uint32_t answer_rc, - DM_AVPGRP *answer_grp __attribute__((unused))); -void listReceived(DMCONFIG_EVENT event, DMCONTEXT *dmCtx, - void *user_data __attribute__((unused)), uint32_t answer_rc, - DM_AVPGRP *answer_grp); -void dumpReceived(DMCONFIG_EVENT event, DMCONTEXT *dmCtx, - void *user_data __attribute__((unused)), uint32_t answer_rc, - DM_AVPGRP *answer_grp); -void instanceDeleted(DMCONFIG_EVENT event, DMCONTEXT *dmCtx, - void *user_data __attribute__((unused)), uint32_t answer_rc, - DM_AVPGRP *answer_grp __attribute__((unused))); -void instanceAdded(DMCONFIG_EVENT event, DMCONTEXT *dmCtx, - void *user_data __attribute__((unused)), uint32_t answer_rc, - DM_AVPGRP *answer_grp); -void parametersReceived(DMCONFIG_EVENT event, DMCONTEXT *dmCtx, - void *user_data __attribute__((unused)), uint32_t answer_rc, - DM_AVPGRP *answer_grp); -void committedChanges(DMCONFIG_EVENT event, DMCONTEXT *dmCtx, - void *user_data __attribute__((unused)), uint32_t answer_rc, - DM_AVPGRP *answer_grp __attribute__((unused))); -void parametersSet(DMCONFIG_EVENT event, DMCONTEXT *dmCtx, - void *user_data __attribute__((unused)), uint32_t answer_rc, - DM_AVPGRP *answer_grp __attribute__((unused))); -void sessionStarted(DMCONFIG_EVENT event, DMCONTEXT *dmCtx, - void *user_data __attribute__((unused)), - uint32_t answer_rc, DM_AVPGRP *answer_grp); -void socketConnected(DMCONFIG_EVENT event, DMCONTEXT *dmCtx, - void *userdata __attribute__((unused))); -int main(int argc __attribute__((unused)), char **argv __attribute__((unused))); - -int counter = 0; - - /* registers END SESSION when it is called the 7. time */ -void +/* registers END SESSION when it is called the 7. time */ +static void registerEndSession(DMCONTEXT *dmCtx) { + static int counter = 0; + if (++counter == 7) { - if (dm_register_end_session(dmCtx, sessionTerminated, NULL)) + if (rpc_endsession_async(dmCtx)) CB_ERR("Couldn't register END SESSION request.\n"); printf("END SESSION registered.\n"); } } -void -sessionTerminated(DMCONFIG_EVENT event, DMCONTEXT *dmCtx __attribute__((unused)), - void *user_data __attribute__((unused)), uint32_t answer_rc, - DM_AVPGRP *answer_grp __attribute__((unused))) +static void +listReceived(DMCONTEXT *dmCtx, DMCONFIG_EVENT event, DM2_AVPGRP *answer_grp, void *user_data __attribute__((unused))) { - if (event != DMCONFIG_ANSWER_READY || answer_rc) - CB_ERR("Couldn't terminate session.\n"); - - printf("Session terminated.\n" - "Returning...\n"); -} + uint32_t rc; -void -listReceived(DMCONFIG_EVENT event, DMCONTEXT *dmCtx, void *user_data __attribute__((unused)), uint32_t answer_rc, DM_AVPGRP *answer_grp) -{ - uint32_t uintval, uintval2, uintval3; - char *charval; + if (event != DMCONFIG_ANSWER_READY) + CB_ERR("Couldn't list object.\n"); - if (event != DMCONFIG_ANSWER_READY || answer_rc) + uint32_t answer_rc; + rc = dm_expect_uint32_type(answer_grp, AVP_RC, VP_TRAVELPING, &answer_rc); + if (rc != RC_OK || answer_rc != RC_OK) CB_ERR("Couldn't list object.\n"); printf("Object listed.\n" - "Retrieved nodes (in \"InternetGatewayDevice\"):\n"); + "Retrieved nodes:\n"); - while (!dm_decode_node_list(answer_grp, &charval, &uintval, &uintval2, &uintval3)) { - switch (uintval) { /* type */ - case NODE_OBJECT: - printf("Object(%d): ", uintval2); - break; - case NODE_PARAMETER: - printf("Parameter(type:%d): ", uintval3); + uint32_t code, vendor_id; + void *data; + size_t size; + + while (dm_expect_avp(answer_grp, &code, &vendor_id, &data, &size) == RC_OK) { + assert(vendor_id == VP_TRAVELPING); + + DM2_AVPGRP container; + dm_init_avpgrp(answer_grp->ctx, data, size, &container); + + char *name; + uint32_t type; + + switch (code) { /* type */ + case AVP_OBJECT: + case AVP_TABLE: + rc = dm_expect_string_type(&container, AVP_NAME, VP_TRAVELPING, &name); + if (rc != RC_OK) + CB_ERR("Couldn't decode AVP_OBJECT.\n"); + printf("Object: %s\n", name); + talloc_free(name); break; - case NODE_TABLE: - printf("Table: "); + case AVP_ELEMENT: + rc = dm_expect_string_type(&container, AVP_NAME, VP_TRAVELPING, &name); + if (rc != RC_OK) + CB_ERR("Couldn't decode AVP_ELEMENT.\n"); + rc = dm_expect_uint32_type(&container, AVP_TYPE, VP_TRAVELPING, &type); + if (rc != RC_OK) + CB_ERR("Couldn't decode AVP_ELEMENT.\n"); + printf("Parameter(type:%" PRIu32 "): %s\n", type, name); + talloc_free(name); break; default: - free(charval); CB_ERR("Invalid element type retrieved.\n"); } - printf("%s\n", charval); - free(charval); } registerEndSession(dmCtx); } -void -dumpReceived(DMCONFIG_EVENT event, DMCONTEXT *dmCtx, void *user_data __attribute__((unused)), uint32_t answer_rc, DM_AVPGRP *answer_grp) +static void +dumpReceived(DMCONTEXT *dmCtx, DMCONFIG_EVENT event, DM2_AVPGRP *answer_grp, void *user_data __attribute__((unused))) { - char *data; + uint32_t rc; - if (event != DMCONFIG_ANSWER_READY || answer_rc) + if (event != DMCONFIG_ANSWER_READY) + CB_ERR("Couldn't dump database.\n"); + + uint32_t answer_rc; + rc = dm_expect_uint32_type(answer_grp, AVP_RC, VP_TRAVELPING, &answer_rc); + if (rc != RC_OK || answer_rc != RC_OK) CB_ERR("Couldn't dump database.\n"); printf("Data base dumped.\n"); - if (dm_decode_cmd_dump(answer_grp, &data)) + char *data; + rc = dm_expect_string_type(answer_grp, AVP_STRING, VP_TRAVELPING, &data); + if (rc != RC_OK) CB_ERR("Allocation error.\n"); printf("Received data:\n%s", data); - free(data); + talloc_free(data); registerEndSession(dmCtx); } -void -instanceDeleted(DMCONFIG_EVENT event, DMCONTEXT *dmCtx, void *user_data __attribute__((unused)), uint32_t answer_rc, DM_AVPGRP *answer_grp __attribute__((unused))) +static void +instanceDeleted(DMCONTEXT *dmCtx, DMCONFIG_EVENT event, DM2_AVPGRP *answer_grp, void *user_data __attribute__((unused))) { - if (event != DMCONFIG_ANSWER_READY || answer_rc) + uint32_t rc; + + if (event != DMCONFIG_ANSWER_READY) + CB_ERR("Couldn't delete instance.\n"); + + uint32_t answer_rc; + rc = dm_expect_uint32_type(answer_grp, AVP_RC, VP_TRAVELPING, &answer_rc); + if (rc != RC_OK || answer_rc != RC_OK) CB_ERR("Couldn't delete instance.\n"); printf("Instance deleted.\n"); @@ -142,204 +137,233 @@ instanceDeleted(DMCONFIG_EVENT event, DMCONTEXT *dmCtx, void *user_data __attrib registerEndSession(dmCtx); } -void -instanceAdded(DMCONFIG_EVENT event, DMCONTEXT *dmCtx, void *user_data __attribute__((unused)), uint32_t answer_rc, DM_AVPGRP *answer_grp) +static void +instanceAdded(DMCONTEXT *dmCtx, DMCONFIG_EVENT event, DM2_AVPGRP *answer_grp, void *user_data __attribute__((unused))) { - uint16_t instance; - char *charval; + uint32_t rc; + + if (event != DMCONFIG_ANSWER_READY) + CB_ERR("Couldn't add instance.\n"); - if (event != DMCONFIG_ANSWER_READY || answer_rc) + uint32_t answer_rc; + rc = dm_expect_uint32_type(answer_grp, AVP_RC, VP_TRAVELPING, &answer_rc); + if (rc != RC_OK || answer_rc != RC_OK) CB_ERR("Couldn't add instance.\n"); + printf("Instance added.\n"); - if (dm_decode_add_instance(answer_grp, &instance)) - CB_ERR("Misc error.\n"); + uint16_t instance; + rc = dm_expect_uint16_type(answer_grp, AVP_UINT16, VP_TRAVELPING, &instance); + if (rc != RC_OK) + CB_ERR("Cannot decode instance id.\n"); - if (asprintf(&charval, "InternetGatewayDevice.X_TPOSS_InterfaceMap.InterfaceType.%u", instance) == -1) + char *charval; + if (asprintf(&charval, "dhcp.client.interfaces.%u", instance) == -1) CB_ERR("Allocation error.\n"); printf("New instance: %s\n", charval); - if (dm_register_del_instance(dmCtx, charval, instanceDeleted, NULL)) { - free(charval); + rc = rpc_db_delinstance_async(dmCtx, charval, instanceDeleted, NULL); + free(charval); + if (rc != RC_OK) CB_ERR("Couldn't register DELETE INSTANCE request.\n"); - } printf("DELETE INSTANCE request registered.\n"); - free(charval); registerEndSession(dmCtx); } -void -parametersReceived(DMCONFIG_EVENT event, DMCONTEXT *dmCtx, void *user_data __attribute__((unused)), uint32_t answer_rc, DM_AVPGRP *answer_grp) +static void +parametersReceived(DMCONTEXT *dmCtx, DMCONFIG_EVENT event, DM2_AVPGRP *answer_grp, void *user_data __attribute__((unused))) { - int32_t intval; - char *charval; - char *address; - - uint32_t unknown_type, vendor_id; - uint8_t flags; - void *data; - size_t len; + uint32_t rc; - void *unknown_data; - size_t unknown_size; + if (event != DMCONFIG_ANSWER_READY) + CB_ERR("Couldn't get parameters.\n"); - if (event != DMCONFIG_ANSWER_READY || answer_rc) + uint32_t answer_rc; + rc = dm_expect_uint32_type(answer_grp, AVP_RC, VP_TRAVELPING, &answer_rc); + if (rc != RC_OK || answer_rc != RC_OK) CB_ERR("Couldn't get parameters.\n"); + printf("Retrieved parameters:\n"); - if (dm_decode_int32(answer_grp, &intval) || - dm_decode_string(answer_grp, &charval) || - dm_avpgrp_get_avp(answer_grp, &unknown_type, &flags, &vendor_id, &data, &len) || - dm_decode_unknown_as_string(unknown_type, data, len, &address) || - dm_decode_unknown(answer_grp, &unknown_type, &unknown_data, &unknown_size)) - CB_ERR("Allocation error.\n"); + uint32_t intval; + char *charval, *address; + + uint32_t code, vendor_id; + void *data; + size_t len; + + if (dm_expect_uint32_type(answer_grp, AVP_UINT32, VP_TRAVELPING, &intval) != RC_OK || + dm_expect_string_type(answer_grp, AVP_STRING, VP_TRAVELPING, &charval) != RC_OK || + dm_expect_avp(answer_grp, &code, &vendor_id, &data, &len) != RC_OK || + dm_decode_unknown_as_string(code, data, len, &address) != RC_OK || + dm_expect_avp(answer_grp, &code, &vendor_id, &data, &len) != RC_OK) + CB_ERR("Couldn't decode GET response.\n"); - printf("Received integer: %d\n" + printf("Received integer: %" PRIu32 "\n" "Received string: \"%s\"\n" "Received address: %s\n" - "Received unknown data: %d, %p\n", - intval, charval, address, unknown_size, unknown_data); - free(charval); + "Received unknown data: %lu, %p\n", + intval, charval, address, len, data); + free(address); - free(unknown_data); registerEndSession(dmCtx); } -void -committedChanges(DMCONFIG_EVENT event, DMCONTEXT *dmCtx, void *user_data __attribute__((unused)), uint32_t answer_rc, DM_AVPGRP *answer_grp __attribute__((unused))) +static void +committedChanges(DMCONTEXT *dmCtx, DMCONFIG_EVENT event, DM2_AVPGRP *answer_grp, void *user_data __attribute__((unused))) { - if (event != DMCONFIG_ANSWER_READY || answer_rc) + uint32_t rc; + + if (event != DMCONFIG_ANSWER_READY) + CB_ERR("Couldn't commit changes.\n"); + + uint32_t answer_rc; + rc = dm_expect_uint32_type(answer_grp, AVP_RC, VP_TRAVELPING, &answer_rc); + if (rc != RC_OK || answer_rc != RC_OK) CB_ERR("Couldn't commit changes.\n"); + printf("Changes committed.\n"); registerEndSession(dmCtx); } -void -parametersSet(DMCONFIG_EVENT event, DMCONTEXT *dmCtx, void *user_data __attribute__((unused)), uint32_t answer_rc, DM_AVPGRP *answer_grp __attribute__((unused))) +static void +parametersSet(DMCONTEXT *dmCtx, DMCONFIG_EVENT event, DM2_AVPGRP *answer_grp, void *user_data __attribute__((unused))) { - if (event != DMCONFIG_ANSWER_READY || answer_rc) + uint32_t rc; + + if (event != DMCONFIG_ANSWER_READY) CB_ERR("Couldn't set parameters.\n"); + + uint32_t answer_rc; + rc = dm_expect_uint32_type(answer_grp, AVP_RC, VP_TRAVELPING, &answer_rc); + if (rc != RC_OK || answer_rc != RC_OK) + CB_ERR("Couldn't set parameters.\n"); + printf("Parameters set.\n"); - if (dm_register_commit(dmCtx, committedChanges, NULL)) + rc = rpc_db_commit_async(dmCtx, committedChanges, NULL); + if (rc != RC_OK) CB_ERR("Couldn't register COMMIT request.\n"); printf("COMMIT request registered.\n"); registerEndSession(dmCtx); } -void -sessionStarted(DMCONFIG_EVENT event, DMCONTEXT *dmCtx, void *user_data __attribute__((unused)), uint32_t answer_rc, DM_AVPGRP *answer_grp) +static void +sessionStarted(DMCONTEXT *dmCtx, DMCONFIG_EVENT event, DM2_AVPGRP *answer_grp, void *user_data __attribute__((unused))) { - DM_AVPGRP *grp; + uint32_t rc; - if (event != DMCONFIG_ANSWER_READY || answer_rc) + if (event != DMCONFIG_ANSWER_READY) CB_ERR("Couldn't start session.\n"); - printf("Session started.\n"); - if (dm_decode_start_session(dmCtx, answer_grp)) - CB_ERR("Couldn't decode sessionid.\n"); - - if (!(grp = dm_grp_new())) - CB_ERR("Allocation error.\n"); + uint32_t answer_rc; + rc = dm_expect_uint32_type(answer_grp, AVP_RC, VP_TRAVELPING, &answer_rc); + if (rc != RC_OK || answer_rc != RC_OK) + CB_ERR("Couldn't start session.\n"); - if (dm_grp_set_unknown(&grp, "InternetGatewayDevice.ManagementServer.PeriodicInformInterval", "42") || - dm_grp_set_string(&grp, "InternetGatewayDevice.DeviceInfo.ModelName", "TEST")) { - dm_grp_free(grp); - CB_ERR("Allocation error.\n"); - } + printf("Session started. Session Id: %" PRIu32 "\n", dmCtx->sessionid); + + struct rpc_db_set_path_value set_values[] = { + { + .path = "system.dns-resolver.options.timeout", + .value.code = AVP_UNKNOWN, + .value.vendor_id = VP_TRAVELPING, + .value.data = "42", + .value.size = 2 + }, + { + .path = "system.location", + .value.code = AVP_STRING, + .value.vendor_id = VP_TRAVELPING, + .value.data = "TEST", + .value.size = 4 + } + }; - if (dm_register_packet_set(dmCtx, grp, parametersSet, NULL)) { - dm_grp_free(grp); + rc = rpc_db_set_async(dmCtx, sizeof(set_values)/sizeof(set_values[0]), set_values, parametersSet, NULL); + if (rc != RC_OK) CB_ERR("Couldn't register SET request.\n"); - } - dm_grp_free(grp); printf("SET request registered.\n"); - if (!(grp = dm_grp_new())) - CB_ERR("Allocation error.\n"); - - if (dm_grp_get_int32(&grp, "InternetGatewayDevice.LANDevice.1.LANHostConfigManagement.DHCPLeaseTime") || - dm_grp_get_string(&grp, "InternetGatewayDevice.DeviceInfo.ManufacturerOUI") || - dm_grp_get_addr(&grp, "InternetGatewayDevice.DeviceInfo.SyslogServer") || - dm_grp_get_unknown(&grp, "InternetGatewayDevice.DeviceInfo.Manufacturer")) { - dm_grp_free(grp); - CB_ERR("Allocation error.\n"); - } + static const char *get_values[] = { + "dhcp.server.lease-time", + "system-state.platform.machine", + "interfaces.interface.1.ipv4.address.1.ip", + "system-state.platform.serial-number" + }; - if (dm_register_packet_get(dmCtx, grp, parametersReceived, NULL)) { - dm_grp_free(grp); + rc = rpc_db_get_async(dmCtx, sizeof(get_values)/sizeof(get_values[0]), get_values, parametersReceived, NULL); + if (rc != RC_OK) CB_ERR("Couldn't register GET request.\n"); - } - dm_grp_free(grp); printf("GET request registered.\n"); - if (dm_register_add_instance(dmCtx, "InternetGatewayDevice.X_TPOSS_InterfaceMap.InterfaceType", - DM_ADD_INSTANCE_AUTO, instanceAdded, NULL)) + rc = rpc_db_addinstance_async(dmCtx, "dhcp.client.interfaces", + DM_ADD_INSTANCE_AUTO, instanceAdded, NULL); + if (rc != RC_OK) CB_ERR("Couldn't register ADD INSTANCE request.\n"); printf("ADD INSTANCE request registered.\n"); - if (dm_register_cmd_dump(dmCtx, "", dumpReceived, NULL)) + rc = rpc_db_dump_async(dmCtx, "", dumpReceived, NULL); + if (rc != RC_OK) CB_ERR("Couldn't register DUMP request.\n"); printf("DUMP request registered.\n"); - if (dm_register_list(dmCtx, "InternetGatewayDevice", 1, listReceived, NULL)) + rc = rpc_db_list_async(dmCtx, 1, "", listReceived, NULL); + if (rc != RC_OK) CB_ERR("Couldn't register LIST request.\n"); printf("LIST request registered.\n"); } -void +static uint32_t socketConnected(DMCONFIG_EVENT event, DMCONTEXT *dmCtx, void *userdata __attribute__((unused))) { - struct timeval timeout = {.tv_sec = 20, .tv_usec = 0}; - - if (event != DMCONFIG_CONNECTED) - CB_ERR("Connecting socket unsuccessful.\n"); + if (event != DMCONFIG_CONNECTED) { + fprintf(stderr, "Connecting socket unsuccessful.\n"); + return RC_ERR_MISC; + } printf("Socket connected.\n"); - if (dm_register_start_session(dmCtx, CMD_FLAG_CONFIGURE, NULL, &timeout, sessionStarted, NULL)) - CB_ERR("Couldn't register start session request.\n"); + if (rpc_startsession_async(dmCtx, CMD_FLAG_CONFIGURE, 20, sessionStarted, NULL)) { + fprintf(stderr, "Couldn't register start session request.\n"); + return RC_ERR_MISC; + } printf("Start session request registered.\n"); + + return RC_OK; } int main(int argc __attribute__((unused)), char **argv __attribute__((unused))) { - DMCONTEXT dmCtx; - struct event_base *base; + struct ev_loop *loop = EV_DEFAULT; - if (!(base = event_init())) { - fprintf(stderr, "Couldn't initialize event base.\n"); - return 0; - } - printf("Event base initialized.\n"); - - dm_context_init(&dmCtx, base); + DMCONTEXT *dmCtx; + uint32_t rc; - if (dm_create_socket(&dmCtx, AF_INET)) { - fprintf(stderr, "Couldn't create socket.\n"); - event_base_free(base); + dmCtx = dm_context_new(); + if (!dmCtx) { + fprintf(stderr, "Couldn't create dmconfig context.\n"); return 0; } - printf("Socket created.\n"); - if (dm_register_connect_callback(&dmCtx, AF_INET, socketConnected, NULL)) { + dm_context_init(dmCtx, EV_A, AF_INET, NULL, socketConnected, NULL); + + rc = dm_connect_async(dmCtx); + if (rc != RC_OK) { fprintf(stderr, "Couldn't register connect callback or connecting unsuccessful.\n"); - dm_shutdown_socket(&dmCtx); - event_base_free(base); + dm_context_shutdown(dmCtx, DMCONFIG_OK); return 0; } printf("Connect callback registered.\n"); - event_base_dispatch(dm_context_get_event_base(&dmCtx)); + ev_run(EV_A_ 0); - dm_shutdown_socket(&dmCtx); + dm_context_shutdown(dmCtx, DMCONFIG_OK); printf("Socket shut down.\n"); - event_base_free(base); - printf("Event base freed.\n"); return 0; } From 7109fc6564d6c2fced64def19294fd744bafcfcb Mon Sep 17 00:00:00 2001 From: Robin Haberkorn Date: Thu, 6 May 2021 02:58:22 +0200 Subject: [PATCH 09/35] dmctrl: fixed crashes when omitting parameters to subcommands * For instance, "dmctrl set", "dmctrl get" etc. all crashed. * This was not critical since these commands are not supposed to do anything but fail without arguments. They will now fail more gracefully. * Perhaps, there should be dedicated error messages when detecting missing parameters (TODO). --- mand/dmctrl.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/mand/dmctrl.c b/mand/dmctrl.c index efd1110..8c3a8e8 100644 --- a/mand/dmctrl.c +++ b/mand/dmctrl.c @@ -213,23 +213,23 @@ void parse_commandline(int argc, char **argv) command = DMCTRL_COMMIT; } else if (strcasecmp(*(argv + optind), "list") == 0) { command = DMCTRL_LIST; - what = *(argv + optind + 1); + what = optind+1 == argc ? "" : *(argv + optind + 1); } else if (strcasecmp(*(argv + optind), "get") == 0) { command = DMCTRL_GET; - what = *(argv + optind + 1); + what = optind+1 == argc ? "" : *(argv + optind + 1); } else if (strcasecmp(*(argv + optind), "set") == 0) { command = DMCTRL_SET; - what = *(argv + optind + 1); + what = optind+1 == argc ? "" : *(argv + optind + 1); } else if (strcasecmp(*(argv + optind), "add") == 0) { command = DMCTRL_ADD; - what = *(argv + optind + 1); + what = optind+1 == argc ? "" : *(argv + optind + 1); } else if (strcasecmp(*(argv + optind), "del") == 0) { command = DMCTRL_DEL; - what = *(argv + optind + 1); + what = optind+1 == argc ? "" : *(argv + optind + 1); } else if (strcasecmp(*(argv + optind), "find") == 0) { command = DMCTRL_FIND; - base = *(argv + optind + 1); - what = *(argv + optind + 2); + base = optind+1 == argc ? "" : *(argv + optind + 1); + what = optind+1 == argc ? "" : *(argv + optind + 2); } else if (strcasecmp(*(argv + optind), "dump") == 0) { command = DMCTRL_DUMP; what = optind+1 == argc ? "" : *(argv + optind + 1); @@ -283,9 +283,7 @@ uint32_t dmctrl_connect_cb(DMCONFIG_EVENT event, DMCONTEXT *socket, void *userda break; } case DMCTRL_LIST: { - char *path = what ? what : ""; - - if ((rc = rpc_db_list(socket, 0, path, answer)) != RC_OK) { + if ((rc = rpc_db_list(socket, 0, what, answer)) != RC_OK) { printf("failed with rc=%d (0x%08x)\n", rc, rc); break; } From ed6bbfee1a000df6135a4bda563ffaf26572b017 Mon Sep 17 00:00:00 2001 From: Robin Haberkorn Date: Mon, 31 May 2021 03:21:12 +0200 Subject: [PATCH 10/35] fixed processing of the interface state callback * some parameters were set as T_UINT while they are in reality T_UINT64 * Has been broken in 5ff31d9ff3745afbe93f87c5058d6e4558aa75dd when I added support for 64-bit integers in Yang schemes. --- mand/dm_dmconfig.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/mand/dm_dmconfig.c b/mand/dm_dmconfig.c index f88f8b4..c676afe 100644 --- a/mand/dm_dmconfig.c +++ b/mand/dm_dmconfig.c @@ -1691,7 +1691,7 @@ static void update_interface_state(struct dm_value_table *tbl) snprintf(macstr, sizeof(macstr), "%02x:%02x:%02x:%02x:%02x:%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); dm_set_string_by_id(tbl, field_ocpe__interfaces_state__interface_physaddress , macstr); - dm_set_uint_by_id(tbl, field_ocpe__interfaces_state__interface_speed , if_speed); + dm_set_uint64_by_id(tbl, field_ocpe__interfaces_state__interface_speed, if_speed); struct dm_value_table *stats; @@ -1700,17 +1700,17 @@ static void update_interface_state(struct dm_value_table *tbl) if (dm_get_ticks_by_id(stats, field_ocpe__interfaces_state__interface__statistics_discontinuitytime) == 0) dm_set_ticks_by_id(stats, field_ocpe__interfaces_state__interface__statistics_discontinuitytime, rt_now); - dm_set_uint_by_id(stats, field_ocpe__interfaces_state__interface__statistics_inoctets, rec_oct); - dm_set_uint_by_id(stats, field_ocpe__interfaces_state__interface__statistics_inunicastpkts, rec_pkt); -// dm_set_uint_by_id(stats, field_ocpe__interfaces_state__interface__statistics_inbroadcastpkts, ); -// dm_set_uint_by_id(stats, field_ocpe__interfaces_state__interface__statistics_inmulticastpkts, ); + dm_set_uint64_by_id(stats, field_ocpe__interfaces_state__interface__statistics_inoctets, rec_oct); + dm_set_uint64_by_id(stats, field_ocpe__interfaces_state__interface__statistics_inunicastpkts, rec_pkt); +// dm_set_uint64_by_id(stats, field_ocpe__interfaces_state__interface__statistics_inbroadcastpkts, ); +// dm_set_uint64_by_id(stats, field_ocpe__interfaces_state__interface__statistics_inmulticastpkts, ); dm_set_uint_by_id(stats, field_ocpe__interfaces_state__interface__statistics_indiscards, rec_drop); dm_set_uint_by_id(stats, field_ocpe__interfaces_state__interface__statistics_inerrors, rec_err); // dm_set_uint_by_id(stats, field_ocpe__interfaces_state__interface__statistics_inunknownprotos, ); - dm_set_uint_by_id(stats, field_ocpe__interfaces_state__interface__statistics_outoctets, snd_oct); - dm_set_uint_by_id(stats, field_ocpe__interfaces_state__interface__statistics_outunicastpkts, snd_pkt); -// dm_set_uint_by_id(stats, field_ocpe__interfaces_state__interface__statistics_outbroadcastpkts, ); -// dm_set_uint_by_id(stats, field_ocpe__interfaces_state__interface__statistics_outmulticastpkts, ); + dm_set_uint64_by_id(stats, field_ocpe__interfaces_state__interface__statistics_outoctets, snd_oct); + dm_set_uint64_by_id(stats, field_ocpe__interfaces_state__interface__statistics_outunicastpkts, snd_pkt); +// dm_set_uint64_by_id(stats, field_ocpe__interfaces_state__interface__statistics_outbroadcastpkts, ); +// dm_set_uint64_by_id(stats, field_ocpe__interfaces_state__interface__statistics_outmulticastpkts, ); dm_set_uint_by_id(stats, field_ocpe__interfaces_state__interface__statistics_outdiscards, snd_drop); dm_set_uint_by_id(stats, field_ocpe__interfaces_state__interface__statistics_outerrors, snd_err); From a879fbcaf465895052b7f290111ea088000d7c33 Mon Sep 17 00:00:00 2001 From: Robin Haberkorn Date: Tue, 1 Jun 2021 16:24:12 +0200 Subject: [PATCH 11/35] update_interface_state(): make sure that missing interfaces are reported as "down" --- mand/dm_dmconfig.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/mand/dm_dmconfig.c b/mand/dm_dmconfig.c index c676afe..2f82a83 100644 --- a/mand/dm_dmconfig.c +++ b/mand/dm_dmconfig.c @@ -1639,6 +1639,15 @@ static void update_interface_state(struct dm_value_table *tbl) if (!(ctx = find_role("-state"))) return; + /* + * Make sure the interface is reported as "down" in case of any errors. + * This will also include missing interfaces. + */ + dm_set_enum_by_id(tbl, field_ocpe__interfaces_state__interface_adminstatus , + field_ocpe__interfaces_state__interface_adminstatus_down); + dm_set_enum_by_id(tbl, field_ocpe__interfaces_state__interface_operstatus , + field_ocpe__interfaces_state__interface_operstatus_down); + name = dm_get_string_by_id(tbl, field_ocpe__interfaces_state__interface_name); printf("get_ocpe__interfaces_state__interface: %s\n", name); From f478a5b0c20fd77e2469571b4fe1a6c82b2251d7 Mon Sep 17 00:00:00 2001 From: Robin Haberkorn Date: Tue, 1 Jun 2021 16:08:13 +0200 Subject: [PATCH 12/35] disabled notifications on all dm_set_*_by_id() * It does not make sense IMHO to notify everybody. These functions are only used in callbacks/actions (see dm_dmconfig.c). * When a dmconfig client lists/gets a parameter with a callback, it would also be notified - this is unnecessary since it gets all the information in the LIST or GET. * Other dmconfig clients would spuriously receive notifications only because somebody else listed these parameters. On the other hand, they cannot count on timely notifications. So disabling all notifications does not bring any disadvantages. If you want to be informed about changes in passively-updated parameters like in interfaces-state, you have to poll them regularily. --- mand/dm_store.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/mand/dm_store.c b/mand/dm_store.c index 9162647..800e12a 100644 --- a/mand/dm_store.c +++ b/mand/dm_store.c @@ -1591,28 +1591,28 @@ void dm_set_bool_by_id(struct dm_value_table *ift, dm_id id, char bool) DM_parity_assert(ift->values[id - 1]); set_DM_BOOL(ift->values[id - 1], bool); DM_parity_update(ift->values[id - 1]); - __DM_NOTIFY_BY_ID(ift, id); +// __DM_NOTIFY_BY_ID(ift, id); } void dm_set_string_by_id(struct dm_value_table *ift, dm_id id, const char *val) { DM_parity_assert(ift->values[id - 1]); dm_set_string_value(&ift->values[id - 1], val); - __DM_NOTIFY_BY_ID(ift, id); +// __DM_NOTIFY_BY_ID(ift, id); } void dm_set_binary_by_id(struct dm_value_table *ift, dm_id id, const binary_t *val) { DM_parity_assert(ift->values[id - 1]); dm_set_binary_value(&ift->values[id - 1], val); - __DM_NOTIFY_BY_ID(ift, id); +// __DM_NOTIFY_BY_ID(ift, id); } void dm_set_binary_data_by_id(struct dm_value_table *ift, dm_id id, unsigned int len, const uint8_t *data) { DM_parity_assert(ift->values[id - 1]); dm_set_binary_data(&ift->values[id - 1], len, data); - __DM_NOTIFY_BY_ID(ift, id); +// __DM_NOTIFY_BY_ID(ift, id); } int dm_set_binary_data_by_selector(const dm_selector sel, unsigned int len, uint8_t * const data, int flags) @@ -1641,7 +1641,7 @@ void dm_set_enum_by_id(struct dm_value_table *ift, dm_id id, int val) DM_parity_assert(ift->values[id - 1]); set_DM_ENUM(ift->values[id - 1], val); DM_parity_update(ift->values[id - 1]); - __DM_NOTIFY_BY_ID(ift, id); +// __DM_NOTIFY_BY_ID(ift, id); } void dm_set_counter_by_id(struct dm_value_table *ift, dm_id id, unsigned int val) @@ -1649,7 +1649,7 @@ void dm_set_counter_by_id(struct dm_value_table *ift, dm_id id, unsigned int val DM_parity_assert(ift->values[id - 1]); set_DM_UINT(ift->values[id - 1], val); DM_parity_update(ift->values[id - 1]); - __DM_NOTIFY_BY_ID(ift, id); +// __DM_NOTIFY_BY_ID(ift, id); } void dm_set_int_by_id(struct dm_value_table *ift, dm_id id, int val) @@ -1657,7 +1657,7 @@ void dm_set_int_by_id(struct dm_value_table *ift, dm_id id, int val) DM_parity_assert(ift->values[id - 1]); set_DM_INT(ift->values[id - 1], val); DM_parity_update(ift->values[id - 1]); - __DM_NOTIFY_BY_ID(ift, id); +// __DM_NOTIFY_BY_ID(ift, id); } void dm_set_uint_by_id(struct dm_value_table *ift, dm_id id, unsigned int val) @@ -1665,7 +1665,7 @@ void dm_set_uint_by_id(struct dm_value_table *ift, dm_id id, unsigned int val) DM_parity_assert(ift->values[id - 1]); set_DM_UINT(ift->values[id - 1], val); DM_parity_update(ift->values[id - 1]); - __DM_NOTIFY_BY_ID(ift, id); +// __DM_NOTIFY_BY_ID(ift, id); } void dm_set_int64_by_id(struct dm_value_table *ift, dm_id id, int64_t val) @@ -1673,7 +1673,7 @@ void dm_set_int64_by_id(struct dm_value_table *ift, dm_id id, int64_t val) DM_parity_assert(ift->values[id - 1]); set_DM_INT64(ift->values[id - 1], val); DM_parity_update(ift->values[id - 1]); - __DM_NOTIFY_BY_ID(ift, id); +// __DM_NOTIFY_BY_ID(ift, id); } void dm_set_uint64_by_id(struct dm_value_table *ift, dm_id id, uint64_t val) @@ -1681,7 +1681,7 @@ void dm_set_uint64_by_id(struct dm_value_table *ift, dm_id id, uint64_t val) DM_parity_assert(ift->values[id - 1]); set_DM_UINT64(ift->values[id - 1], val); DM_parity_update(ift->values[id - 1]); - __DM_NOTIFY_BY_ID(ift, id); +// __DM_NOTIFY_BY_ID(ift, id); } void dm_set_time_by_id(struct dm_value_table *ift, dm_id id, time_t t) @@ -1689,7 +1689,7 @@ void dm_set_time_by_id(struct dm_value_table *ift, dm_id id, time_t t) DM_parity_assert(ift->values[id - 1]); set_DM_TIME(ift->values[id - 1], t); DM_parity_update(ift->values[id - 1]); - __DM_NOTIFY_BY_ID(ift, id); +// __DM_NOTIFY_BY_ID(ift, id); } void dm_set_ticks_by_id(struct dm_value_table *ift, dm_id id, ticks_t val) @@ -1697,14 +1697,14 @@ void dm_set_ticks_by_id(struct dm_value_table *ift, dm_id id, ticks_t val) DM_parity_assert(ift->values[id - 1]); set_DM_TICKS(ift->values[id - 1], val); DM_parity_update(ift->values[id - 1]); - __DM_NOTIFY_BY_ID(ift, id); +// __DM_NOTIFY_BY_ID(ift, id); } void dm_set_selector_by_id(struct dm_value_table *ift, dm_id id, const dm_selector sel) { DM_parity_assert(ift->values[id - 1]); dm_set_selector_value(&ift->values[id - 1], sel); - __DM_NOTIFY_BY_ID(ift, id); +// __DM_NOTIFY_BY_ID(ift, id); } void dm_set_ipv4_by_id(struct dm_value_table *ift, dm_id id, struct in_addr val) @@ -1712,7 +1712,7 @@ void dm_set_ipv4_by_id(struct dm_value_table *ift, dm_id id, struct in_addr val) DM_parity_assert(ift->values[id - 1]); set_DM_IP4(ift->values[id - 1], val); DM_parity_update(ift->values[id - 1]); - __DM_NOTIFY_BY_ID(ift, id); +// __DM_NOTIFY_BY_ID(ift, id); } void dm_set_ipv6_by_id(struct dm_value_table *ift, dm_id id, struct in6_addr val) @@ -1720,5 +1720,5 @@ void dm_set_ipv6_by_id(struct dm_value_table *ift, dm_id id, struct in6_addr val DM_parity_assert(ift->values[id - 1]); set_DM_IP6(ift->values[id - 1], val); DM_parity_update(ift->values[id - 1]); - __DM_NOTIFY_BY_ID(ift, id); +// __DM_NOTIFY_BY_ID(ift, id); } From 3354f3489dd4a2dd90f932689d4a344f74f29540 Mon Sep 17 00:00:00 2001 From: Robin Haberkorn Date: Wed, 9 Jun 2021 03:37:04 +0200 Subject: [PATCH 13/35] fixup f478a5b0c20fd77e2469571b4fe1a6c82b2251d7: some notifications were still not disabled - introduced `notify_enabled` as a workaround --- mand/dm_dmconfig.c | 12 ++++++++++++ mand/dm_notify.c | 5 +++++ mand/dm_notify.h | 2 ++ mand/dm_store.c | 30 +++++++++++++++--------------- 4 files changed, 34 insertions(+), 15 deletions(-) diff --git a/mand/dm_dmconfig.c b/mand/dm_dmconfig.c index 2f82a83..e81edb4 100644 --- a/mand/dm_dmconfig.c +++ b/mand/dm_dmconfig.c @@ -2036,11 +2036,23 @@ DM_VALUE __get_ocpe__interfaces_state__interface(struct dm_value_table *tbl, dm_ ticks2str(buf1, sizeof(buf1), ticks2realtime(last)); ticks2str(buf2, sizeof(buf2), ticks2realtime(rt_now)); + /* + * FIXME: Disables all notifications. + * The dmconfig client querying this information does not need them + * and the others cannot rely on notifications anyway. + * This should be solved more elegantly, though. + */ + int notify_enabled_old = notify_enabled; + notify_enabled = 0; + printf("get_ocpe__interfaces_state__interface: %s: %s, %s, %" PRItick "\n", e->key, buf1, buf2, rt_now - last); if (rt_now - last > 10) update_interface_state(tbl); dm_set_ticks_by_id(tbl, field_ocpe__interfaces_state__interface_lastread, rt_now); + + notify_enabled = notify_enabled_old; + return *dm_get_value_ref_by_id(tbl, id); } diff --git a/mand/dm_notify.c b/mand/dm_notify.c index 51de56c..fa2ee41 100644 --- a/mand/dm_notify.c +++ b/mand/dm_notify.c @@ -25,6 +25,8 @@ //#define SDEBUG #include "debug.h" +int notify_enabled = 1; + static int notify_pending = 0; static int @@ -182,6 +184,9 @@ void notify_sel(int slot, const dm_selector sel, /* not notify's at all */ return; + if (!notify_enabled) + return; + debug("(): %s, %08x ... %d", dm_sel2name(sel, b1, sizeof(b1)), ntfy, slot); dm_selcpy(si.sb, sel); diff --git a/mand/dm_notify.h b/mand/dm_notify.h index bf4efa0..348033c 100644 --- a/mand/dm_notify.h +++ b/mand/dm_notify.h @@ -39,6 +39,8 @@ struct slot { RB_PROTOTYPE(notify_queue, notify_item, node, notify_compare); +extern int notify_enabled; + int alloc_slot(notify_cb *cb, void *data); void free_slot(int slot); diff --git a/mand/dm_store.c b/mand/dm_store.c index 800e12a..9162647 100644 --- a/mand/dm_store.c +++ b/mand/dm_store.c @@ -1591,28 +1591,28 @@ void dm_set_bool_by_id(struct dm_value_table *ift, dm_id id, char bool) DM_parity_assert(ift->values[id - 1]); set_DM_BOOL(ift->values[id - 1], bool); DM_parity_update(ift->values[id - 1]); -// __DM_NOTIFY_BY_ID(ift, id); + __DM_NOTIFY_BY_ID(ift, id); } void dm_set_string_by_id(struct dm_value_table *ift, dm_id id, const char *val) { DM_parity_assert(ift->values[id - 1]); dm_set_string_value(&ift->values[id - 1], val); -// __DM_NOTIFY_BY_ID(ift, id); + __DM_NOTIFY_BY_ID(ift, id); } void dm_set_binary_by_id(struct dm_value_table *ift, dm_id id, const binary_t *val) { DM_parity_assert(ift->values[id - 1]); dm_set_binary_value(&ift->values[id - 1], val); -// __DM_NOTIFY_BY_ID(ift, id); + __DM_NOTIFY_BY_ID(ift, id); } void dm_set_binary_data_by_id(struct dm_value_table *ift, dm_id id, unsigned int len, const uint8_t *data) { DM_parity_assert(ift->values[id - 1]); dm_set_binary_data(&ift->values[id - 1], len, data); -// __DM_NOTIFY_BY_ID(ift, id); + __DM_NOTIFY_BY_ID(ift, id); } int dm_set_binary_data_by_selector(const dm_selector sel, unsigned int len, uint8_t * const data, int flags) @@ -1641,7 +1641,7 @@ void dm_set_enum_by_id(struct dm_value_table *ift, dm_id id, int val) DM_parity_assert(ift->values[id - 1]); set_DM_ENUM(ift->values[id - 1], val); DM_parity_update(ift->values[id - 1]); -// __DM_NOTIFY_BY_ID(ift, id); + __DM_NOTIFY_BY_ID(ift, id); } void dm_set_counter_by_id(struct dm_value_table *ift, dm_id id, unsigned int val) @@ -1649,7 +1649,7 @@ void dm_set_counter_by_id(struct dm_value_table *ift, dm_id id, unsigned int val DM_parity_assert(ift->values[id - 1]); set_DM_UINT(ift->values[id - 1], val); DM_parity_update(ift->values[id - 1]); -// __DM_NOTIFY_BY_ID(ift, id); + __DM_NOTIFY_BY_ID(ift, id); } void dm_set_int_by_id(struct dm_value_table *ift, dm_id id, int val) @@ -1657,7 +1657,7 @@ void dm_set_int_by_id(struct dm_value_table *ift, dm_id id, int val) DM_parity_assert(ift->values[id - 1]); set_DM_INT(ift->values[id - 1], val); DM_parity_update(ift->values[id - 1]); -// __DM_NOTIFY_BY_ID(ift, id); + __DM_NOTIFY_BY_ID(ift, id); } void dm_set_uint_by_id(struct dm_value_table *ift, dm_id id, unsigned int val) @@ -1665,7 +1665,7 @@ void dm_set_uint_by_id(struct dm_value_table *ift, dm_id id, unsigned int val) DM_parity_assert(ift->values[id - 1]); set_DM_UINT(ift->values[id - 1], val); DM_parity_update(ift->values[id - 1]); -// __DM_NOTIFY_BY_ID(ift, id); + __DM_NOTIFY_BY_ID(ift, id); } void dm_set_int64_by_id(struct dm_value_table *ift, dm_id id, int64_t val) @@ -1673,7 +1673,7 @@ void dm_set_int64_by_id(struct dm_value_table *ift, dm_id id, int64_t val) DM_parity_assert(ift->values[id - 1]); set_DM_INT64(ift->values[id - 1], val); DM_parity_update(ift->values[id - 1]); -// __DM_NOTIFY_BY_ID(ift, id); + __DM_NOTIFY_BY_ID(ift, id); } void dm_set_uint64_by_id(struct dm_value_table *ift, dm_id id, uint64_t val) @@ -1681,7 +1681,7 @@ void dm_set_uint64_by_id(struct dm_value_table *ift, dm_id id, uint64_t val) DM_parity_assert(ift->values[id - 1]); set_DM_UINT64(ift->values[id - 1], val); DM_parity_update(ift->values[id - 1]); -// __DM_NOTIFY_BY_ID(ift, id); + __DM_NOTIFY_BY_ID(ift, id); } void dm_set_time_by_id(struct dm_value_table *ift, dm_id id, time_t t) @@ -1689,7 +1689,7 @@ void dm_set_time_by_id(struct dm_value_table *ift, dm_id id, time_t t) DM_parity_assert(ift->values[id - 1]); set_DM_TIME(ift->values[id - 1], t); DM_parity_update(ift->values[id - 1]); -// __DM_NOTIFY_BY_ID(ift, id); + __DM_NOTIFY_BY_ID(ift, id); } void dm_set_ticks_by_id(struct dm_value_table *ift, dm_id id, ticks_t val) @@ -1697,14 +1697,14 @@ void dm_set_ticks_by_id(struct dm_value_table *ift, dm_id id, ticks_t val) DM_parity_assert(ift->values[id - 1]); set_DM_TICKS(ift->values[id - 1], val); DM_parity_update(ift->values[id - 1]); -// __DM_NOTIFY_BY_ID(ift, id); + __DM_NOTIFY_BY_ID(ift, id); } void dm_set_selector_by_id(struct dm_value_table *ift, dm_id id, const dm_selector sel) { DM_parity_assert(ift->values[id - 1]); dm_set_selector_value(&ift->values[id - 1], sel); -// __DM_NOTIFY_BY_ID(ift, id); + __DM_NOTIFY_BY_ID(ift, id); } void dm_set_ipv4_by_id(struct dm_value_table *ift, dm_id id, struct in_addr val) @@ -1712,7 +1712,7 @@ void dm_set_ipv4_by_id(struct dm_value_table *ift, dm_id id, struct in_addr val) DM_parity_assert(ift->values[id - 1]); set_DM_IP4(ift->values[id - 1], val); DM_parity_update(ift->values[id - 1]); -// __DM_NOTIFY_BY_ID(ift, id); + __DM_NOTIFY_BY_ID(ift, id); } void dm_set_ipv6_by_id(struct dm_value_table *ift, dm_id id, struct in6_addr val) @@ -1720,5 +1720,5 @@ void dm_set_ipv6_by_id(struct dm_value_table *ift, dm_id id, struct in6_addr val DM_parity_assert(ift->values[id - 1]); set_DM_IP6(ift->values[id - 1], val); DM_parity_update(ift->values[id - 1]); -// __DM_NOTIFY_BY_ID(ift, id); + __DM_NOTIFY_BY_ID(ift, id); } From 00ba9364fa4b2d36ece153b1d679d42bd0573fb9 Mon Sep 17 00:00:00 2001 From: Robin Haberkorn Date: Wed, 23 Jun 2021 02:01:34 +0200 Subject: [PATCH 14/35] ported from Python 2 to 3 * Python 2 is deprecated and no longer (easily) supported in Yocto hardknott. There is little sense in supporting both Python 2 and 3. * OpenCPE.py was ported using the `modernize` package. --- .gitignore | 3 ++- README.md | 5 +++-- configure.ac | 2 +- yang/pyang_plugin/OpenCPE.py | 13 +++++++------ 4 files changed, 13 insertions(+), 10 deletions(-) diff --git a/.gitignore b/.gitignore index 1e87ecd..78785fb 100644 --- a/.gitignore +++ b/.gitignore @@ -51,7 +51,8 @@ stamp-h1 /build* # pyang plugin -OpenCPE.pyc +__pycache__ +*.pyc p_table* dm_action_* diff --git a/README.md b/README.md index 1ba8425..b866f18 100644 --- a/README.md +++ b/README.md @@ -41,8 +41,9 @@ aware and depend on particular entries in those models. - libtalloc - lua 5.1 - 5.3 - xsltproc -- python -- pyang +- python3 +- pyang v1.7 +- python3-six ## Optional tools and libraries diff --git a/configure.ac b/configure.ac index adada60..369a09b 100644 --- a/configure.ac +++ b/configure.ac @@ -27,7 +27,7 @@ dnl ## AC_MSG_PART(Build Tools) -AM_PATH_PYTHON +AM_PATH_PYTHON([3.0]) AX_PYTHON_MODULE([pyang], [true]) AC_CHECK_PROG(PYANG, pyang, pyang) diff --git a/yang/pyang_plugin/OpenCPE.py b/yang/pyang_plugin/OpenCPE.py index b5a7ac8..d5b8c69 100644 --- a/yang/pyang_plugin/OpenCPE.py +++ b/yang/pyang_plugin/OpenCPE.py @@ -9,6 +9,7 @@ from pyang import statements from copy import deepcopy +from six.moves import range def pyang_plugin_init(): plugin.register_plugin(TreePlugin()) @@ -90,7 +91,7 @@ def emit_tree(modules, fd): for module in modules: module_augments = module.search('augment') for augment in module_augments: - if augment.arg not in augments.keys(): + if augment.arg not in list(augments.keys()): augments[augment.arg] = [augment] else: augments[augment.arg] += [augment] @@ -191,7 +192,7 @@ def print_children(i_children, module, typedefs, groupings, augments, deviations ch.parent.search_one(ch.arg) is None): pass #exclude the deviations with 'not supported' - elif get_xpath(ch) not in deviations.keys(): + elif get_xpath(ch) not in list(deviations.keys()): child_write_access = get_write_access(write_access, ch) print_node(ch, module, typedefs, groupings, augments, deviations, annotations, fd, child_write_access) @@ -207,7 +208,7 @@ def print_node(s, module, typedefs, groupings, augments, deviations, annotations children = s.substmts #include the augments if neccassary - if get_xpath(s) in augments.keys(): + if get_xpath(s) in list(augments.keys()): for augment in augments[get_xpath(s)]: children += augment.i_children @@ -251,7 +252,7 @@ def print_node(s, module, typedefs, groupings, augments, deviations, annotations #the inner part of one struct for child in children: - if child.keyword in ['container', 'list', 'leaf', 'leaf-list'] and get_xpath(child) not in deviations.keys(): + if child.keyword in ['container', 'list', 'leaf', 'leaf-list'] and get_xpath(child) not in list(deviations.keys()): counter += print_field(fd, child, typedefs, annotations, counter, keys, write_access=get_write_access(write_access, child)) elif child.keyword == 'choice': for substmt in child.substmts: @@ -304,7 +305,7 @@ def print_field(fd, child, typedefs, annotations, counter, keys, prefix='', writ getter = False setter = False annotated_type = None - if get_xpath(child) in annotations.keys(): + if get_xpath(child) in list(annotations.keys()): action = annotations[get_xpath(child)].search_one(('opencpe-annotations', 'action')) annotated_flags = annotations[get_xpath(child)].search_one(('opencpe-annotations', 'flags')) getter = annotations[get_xpath(child)].search_one(('opencpe-annotations', 'getter')) @@ -752,7 +753,7 @@ def zero(n): # the code regarding the transitive reduction is now used here def make_chains(chains): - keys = chains.keys() + keys = list(chains.keys()) n = len(keys) for action in keys: From 04d9843a31a9a9b632bec176ebbe88eafe378635 Mon Sep 17 00:00:00 2001 From: Robin Haberkorn Date: Thu, 1 Jul 2021 14:13:25 +0200 Subject: [PATCH 15/35] fixed compiler warnings/errors with GCC 10 * fixed some return type mismatches * chdir() and asprintf() return values should be checked * avoid multiple definitions of notify_attr * one pointless if-statement in dm_deserialize.c has been commented out since I am not sure about its purpose --- mand/dm_deserialize.c | 19 +++++++++++-------- mand/dm_dmconfig.c | 29 ++++++++++++++--------------- mand/dm_serialize.c | 1 + mand/dm_serialize.h | 2 -- mand/mand.c | 3 ++- 5 files changed, 28 insertions(+), 26 deletions(-) diff --git a/mand/dm_deserialize.c b/mand/dm_deserialize.c index 88a8bda..7d1f75f 100644 --- a/mand/dm_deserialize.c +++ b/mand/dm_deserialize.c @@ -71,7 +71,7 @@ startElement(void *userData, const char *name, const char **atts) int xid = 0; int ntfy = 0; - dm_id id; + dm_id id = DM_ERR; (*state)++; if (!is_root) @@ -109,10 +109,13 @@ startElement(void *userData, const char *name, const char **atts) debug("(): Error during Lua function execution"); } } else { - if (xid != 0) - asprintf(&(*state)->base, "%s.%s.%d", base, name, xid); - else - asprintf(&(*state)->base, "%s.%s", base, name); + int rc = xid != 0 + ? asprintf(&(*state)->base, "%s.%s.%d", base, name, xid) + : asprintf(&(*state)->base, "%s.%s", base, name); + if (rc < 0) { + debug("memory allocation failed"); + return; + } if (valid) { const struct dm_table *table = element->u.t.table; @@ -185,7 +188,7 @@ startElement(void *userData, const char *name, const char **atts) static void string_unescape(char *text, const char *s, int len) { int in_c = 0; - char c; + char c = 0; char *d = text + strlen(text); while (len) { @@ -250,7 +253,7 @@ endElement(void *userData, const char *name __attribute__ ((unused))) { struct XMLstate **state = userData; - if (((*state)->flags & XML_ROOT) != XML_VALID) { +// if (((*state)->flags & XML_ROOT) != XML_VALID) { if (((*state)->flags & XML_VALID) == XML_VALID) { handleElement(*state); @@ -259,7 +262,7 @@ endElement(void *userData, const char *name __attribute__ ((unused))) } else { debug("handle invalid: %s = '%s'\n", (*state)->base, (*state)->text ? : "NOTHING"); } - } +// } if (((*state)->flags & XML_UPGRADE) == XML_UPGRADE) { lua_pushinteger(lua_environment, CFG_VERSION); diff --git a/mand/dm_dmconfig.c b/mand/dm_dmconfig.c index e81edb4..0398665 100644 --- a/mand/dm_dmconfig.c +++ b/mand/dm_dmconfig.c @@ -403,7 +403,7 @@ dmconfig_string2value(char *s, size_t size, const struct dm_element *elem, DM_VA debug(": %s: %*s", elem->key, ilen, s); if (!(dum = strndup(s, size))) - return RC_ERR_ALLOC; + return DM_OOM; switch (elem->type) { case T_BASE64: @@ -670,22 +670,22 @@ dmconfig_set_array_cb(SOCKCONTEXT *ctx __attribute__((unused)), DM_VALUE *st) { int len = avp->size; - uint32_t rc; + DM_RESULT rc; char buffer[MAX_PARAM_NAME_LEN]; char *path; if (elem->type != T_OBJECT || st->type != T_OBJECT || (avp->code != AVP_UNKNOWN && avp->code != AVP_ARRAY)) - return RC_ERR_INVALID_AVP_TYPE; + return DM_INVALID_TYPE; if (!(path = dm_sel2name(sel, buffer, sizeof(buffer)))) - return RC_ERR_ALLOC; + return DM_OOM; debug(": %08x:%08x, %d, %d, %s (%s): %*s", avp->vendor_id, avp->code, elem->type, st->type, elem->key, path, len, (char *)avp->data); if (!dm_del_table_by_selector(sel)) - return RC_ERR_MISC; + return DM_ERROR; if (avp->code == AVP_UNKNOWN) { debug(": string2array"); @@ -704,7 +704,7 @@ dmconfig_set_array_cb(SOCKCONTEXT *ctx __attribute__((unused)), s_len = (p != NULL) ? (size_t)(p - s) : rem; if (!(node = dm_add_instance_by_selector(sel, &id))) - return RC_ERR_ALLOC; + return DM_OOM; value = dm_get_value_ref_by_index(DM_TABLE(node->table), 0); @@ -733,11 +733,11 @@ dmconfig_set_array_cb(SOCKCONTEXT *ctx __attribute__((unused)), struct dm_instance_node *node; DM_VALUE *value; - if ((rc = dm_expect_value(&container, &a)) != RC_OK) - return rc; + if (dm_expect_value(&container, &a) != RC_OK) + return DM_ERROR; if (!(node = dm_add_instance_by_selector(sel, &id))) - return RC_ERR_ALLOC; + return DM_OOM; value = dm_get_value_ref_by_index(DM_TABLE(node->table), 0); @@ -753,7 +753,7 @@ dmconfig_set_array_cb(SOCKCONTEXT *ctx __attribute__((unused)), } } - return RC_OK; + return DM_OK; } static DM_RESULT @@ -791,15 +791,14 @@ dmconfig_get_cb(void *data, const dm_selector sb __attribute__((unused)), const struct dm_element *elem, int st_type, const DM_VALUE val) { DM2_REQUEST *req = data; - uint32_t rc; if (!elem) - return RC_ERR_VALUE_NOT_FOUND; + return DM_VALUE_NOT_FOUND; - if ((rc = dm_add_avp(req, elem, st_type, val)) != RC_OK) - return rc; + if (dm_add_avp(req, elem, st_type, val) != RC_OK) + return DM_ERROR; - return RC_OK; + return DM_OK; } static int diff --git a/mand/dm_serialize.c b/mand/dm_serialize.c index a8cf84f..88c1a03 100644 --- a/mand/dm_serialize.c +++ b/mand/dm_serialize.c @@ -14,6 +14,7 @@ #include "dm.h" #include "dm_token.h" #include "dm_store.h" +#include "dm_deserialize.h" #include "dm_serialize.h" #include "dm_strings.h" #include "dm_cfgversion.h" diff --git a/mand/dm_serialize.h b/mand/dm_serialize.h index d2c3fae..720ee9e 100644 --- a/mand/dm_serialize.h +++ b/mand/dm_serialize.h @@ -15,8 +15,6 @@ #define S_SYS (1 << 2) #define S_ALL (S_CFG | S_ACS | S_SYS) -struct dm_enum notify_attr; - void dm_serialize_store(FILE *stream, int flags); void dm_serialize_element(FILE *stream, const char *element, int flags); diff --git a/mand/mand.c b/mand/mand.c index 2d08479..6eb9f5a 100644 --- a/mand/mand.c +++ b/mand/mand.c @@ -147,7 +147,8 @@ int main(int argc, char *argv[]) FILE *fin; /* switch working dir to /tmp so that logfiles can be written */ - chdir("/tmp"); + if (chdir("/tmp") < 0) + perror("chdir"); /* * prevent any spawned processes from inheriting LD_PRELOAD From e93a708145ac4139dae1fd4717d07a7cc28a8f59 Mon Sep 17 00:00:00 2001 From: Robin Haberkorn Date: Thu, 15 Jul 2021 02:15:18 +0300 Subject: [PATCH 16/35] fixed strncpy() problems that could theoretically result in unterminated strings * this only resulted in warnings (and therefore build errors) when building with optimizations (ie. when functions are inlined). --- mand/inet_helper.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/mand/inet_helper.c b/mand/inet_helper.c index 33bbb58..47b91ca 100644 --- a/mand/inet_helper.c +++ b/mand/inet_helper.c @@ -45,7 +45,8 @@ int do_ethflags(const char *iface, uint32_t flags, uint32_t mask) return -1; memset(&ifr, 0, sizeof(ifr)); - strncpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name)); + strncpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name)-1); + ifr.ifr_name[sizeof(ifr.ifr_name)-1] = '\0'; err = ioctl(s, SIOCGIFFLAGS, &ifr); if (err) { debug("(): SIOCGIFFLAGS: %m"); @@ -74,7 +75,8 @@ struct in_addr getifip(const char *iface) return ret; memset(&ifr, 0, sizeof(ifr)); - strncpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name)); + strncpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name)-1); + ifr.ifr_name[sizeof(ifr.ifr_name)-1] = '\0'; ifr.ifr_addr.sa_family = AF_INET; if (ioctl(s, SIOCGIFADDR, &ifr) == 0) ret = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr; @@ -95,7 +97,8 @@ struct in_addr getifdstip(const char *iface) return ret; memset(&ifr, 0, sizeof(ifr)); - strncpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name)); + strncpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name)-1); + ifr.ifr_name[sizeof(ifr.ifr_name)-1] = '\0'; ifr.ifr_addr.sa_family = AF_INET; if (ioctl(s, SIOCGIFDSTADDR, &ifr) == 0) ret = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr; From fca2a6f5cb1ee56ad45b614ee4c75057cf05fedb Mon Sep 17 00:00:00 2001 From: Robin Haberkorn Date: Sun, 10 Oct 2021 23:49:31 +0300 Subject: [PATCH 17/35] added dm_authentication action and added missing action for system.ntp.enabled --- yang/specs/opencpe-actiontable.yang | 10 ++++++++++ yang/specs/opencpe-annotations.yang | 12 ++++++++++++ 2 files changed, 22 insertions(+) diff --git a/yang/specs/opencpe-actiontable.yang b/yang/specs/opencpe-actiontable.yang index 83a93c5..e7aa4f7 100644 --- a/yang/specs/opencpe-actiontable.yang +++ b/yang/specs/opencpe-actiontable.yang @@ -25,6 +25,16 @@ module opencpe-actiontable { ocpe-actiontable:chain "NULL"; } + ocpe-actiontable:action-field authentication { + ocpe-actiontable:include "NULL"; + ocpe-actiontable:comment "a first try on the new action table"; + ocpe-actiontable:sel 2; + ocpe-actiontable:pre "NULL"; + ocpe-actiontable:action "NULL"; + ocpe-actiontable:post "NULL"; + ocpe-actiontable:chain "NULL"; + } + ocpe-actiontable:action-field if_ip { ocpe-actiontable:include "NULL"; ocpe-actiontable:comment "a first try on the new action table"; diff --git a/yang/specs/opencpe-annotations.yang b/yang/specs/opencpe-annotations.yang index fc90a2e..26ee4a7 100644 --- a/yang/specs/opencpe-annotations.yang +++ b/yang/specs/opencpe-annotations.yang @@ -16,6 +16,10 @@ module opencpe-annotations { ocpe-annotation:setter true; } + ocpe-annotation:annotate "/sys:system/sys:ntp/sys:enabled" { + ocpe-annotation:action "dm_ntp"; + } + ocpe-annotation:annotate "/sys:system/sys:ntp/sys:server/sys:udp/sys:address" { ocpe-annotation:action "dm_ntp"; } @@ -36,6 +40,14 @@ module opencpe-annotations { ocpe-annotation:action "dm_dns"; } + ocpe-annotation:annotate "/sys:system/sys:authentication/sys:user/sys:name" { + ocpe-annotation:action "dm_authentication"; + } + + ocpe-annotation:annotate "/sys:system/sys:authentication/sys:user/sys:password" { + ocpe-annotation:action "dm_authentication"; + } + ocpe-annotation:annotate "/if:interfaces/if:interface/ip:ipv4/ip:address/ip:ip" { ocpe-annotation:action "dm_if_ip"; } From ad906e1f77dfa30d71404c8236043c08ce9468e6 Mon Sep 17 00:00:00 2001 From: Robin Haberkorn Date: Thu, 6 Jan 2022 22:00:00 +0100 Subject: [PATCH 18/35] invalid AVP_PATHs will now return RC_ERR_VALUE_NOT_FOUND * This affects e.g. libdmconfig set/get requests (or dmctrl set/get) with invalid paths. It's useful to detect mistakes in selector paths. --- libdmconfig/dm_dmconfig_rpc_skel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libdmconfig/dm_dmconfig_rpc_skel.c b/libdmconfig/dm_dmconfig_rpc_skel.c index 744d639..3f5518f 100644 --- a/libdmconfig/dm_dmconfig_rpc_skel.c +++ b/libdmconfig/dm_dmconfig_rpc_skel.c @@ -45,7 +45,7 @@ dm_expect_path_type(DM2_AVPGRP *grp, uint32_t exp_code, uint32_t exp_vendor_id, return r; if (!dm_name2sel(s, value)) - r = RC_ERR_MISC; + r = RC_ERR_VALUE_NOT_FOUND; talloc_free(s); return r; From 69b4dc6498373b7e85dbf1bb38a2c1c6dacb1603 Mon Sep 17 00:00:00 2001 From: Robin Haberkorn Date: Tue, 11 Jan 2022 18:49:01 +0100 Subject: [PATCH 19/35] minor fix in update_interface_state(): report interface as down also when a "-state" role (config agent implementing the rpc_interface_state) is missing --- mand/dm_dmconfig.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/mand/dm_dmconfig.c b/mand/dm_dmconfig.c index 0398665..18323a3 100644 --- a/mand/dm_dmconfig.c +++ b/mand/dm_dmconfig.c @@ -1635,9 +1635,6 @@ static void update_interface_state(struct dm_value_table *tbl) const char *name; DM2_AVPGRP answer; - if (!(ctx = find_role("-state"))) - return; - /* * Make sure the interface is reported as "down" in case of any errors. * This will also include missing interfaces. @@ -1647,6 +1644,10 @@ static void update_interface_state(struct dm_value_table *tbl) dm_set_enum_by_id(tbl, field_ocpe__interfaces_state__interface_operstatus , field_ocpe__interfaces_state__interface_operstatus_down); + if (!(ctx = find_role("-state"))) + /* there is no agent implementing the RPC */ + return; + name = dm_get_string_by_id(tbl, field_ocpe__interfaces_state__interface_name); printf("get_ocpe__interfaces_state__interface: %s\n", name); From 08714a06450c281096d9606a36a10ffe147d903d Mon Sep 17 00:00:00 2001 From: Robin Haberkorn Date: Tue, 11 Jan 2022 19:04:29 +0100 Subject: [PATCH 20/35] avoid dm_save() recursions (FIXME FIXME FIXME) * The sync wrappers around server-to-client requests recurse the event loop. Since the SAVE request will include fetching the interfaces state (calls rpc_get_interface_state()), the SAVE request could be in certain corner cases executed again, resulting in a deadlock because of the non-recursive mutex lock. * This is only a temporary workaround. The event loop recursion itself is broken by design. For most server-to-client requests, it could be easily avoided. Avoiding event loop recusion in rpc_get_interface_state() would require significant refactoring, though. It will be easier to reintegrate the RPC implementation (e.g. from mand-metropolisd) back into mand - the implementation is OS agnostic, so there is no real reason to have this as a RPC. --- mand/mand.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/mand/mand.c b/mand/mand.c index 6eb9f5a..22babe0 100644 --- a/mand/mand.c +++ b/mand/mand.c @@ -55,13 +55,22 @@ extern int libdmconfigSocketType; void dm_save(void) { - static pthread_mutex_t save_mutex = PTHREAD_MUTEX_INITIALIZER; - char *fname; int fd; FILE *fout; - pthread_mutex_lock(&save_mutex); + /* + * FIXME: Temporary workaround to possible deadlocks. + * Instead the event loop recursion in dm_dmclient_rpc_stub.c should + * be avoided. + */ + static sig_atomic_t running = 0; + if (running) + return; + running = 1; + +// static pthread_mutex_t save_mutex = PTHREAD_MUTEX_INITIALIZER; +// pthread_mutex_lock(&save_mutex); fname = strdup(DM_CONFIG ".XXXXXX"); if (fname && (fd = mkstemp(fname)) != -1) { @@ -78,7 +87,9 @@ void dm_save(void) } free(fname); - pthread_mutex_unlock(&save_mutex); +// pthread_mutex_unlock(&save_mutex); + + running = 0; } void dm_dump(int fd, const char *element) From 3fe2420f7f822700e76a112fb56dfc8d0941e935 Mon Sep 17 00:00:00 2001 From: Robin Haberkorn Date: Sun, 6 Feb 2022 19:13:25 +0100 Subject: [PATCH 21/35] Revert "avoid dm_save() recursions (FIXME FIXME FIXME)" This reverts commit 08714a06450c281096d9606a36a10ffe147d903d. --- mand/mand.c | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/mand/mand.c b/mand/mand.c index 22babe0..6eb9f5a 100644 --- a/mand/mand.c +++ b/mand/mand.c @@ -55,22 +55,13 @@ extern int libdmconfigSocketType; void dm_save(void) { + static pthread_mutex_t save_mutex = PTHREAD_MUTEX_INITIALIZER; + char *fname; int fd; FILE *fout; - /* - * FIXME: Temporary workaround to possible deadlocks. - * Instead the event loop recursion in dm_dmclient_rpc_stub.c should - * be avoided. - */ - static sig_atomic_t running = 0; - if (running) - return; - running = 1; - -// static pthread_mutex_t save_mutex = PTHREAD_MUTEX_INITIALIZER; -// pthread_mutex_lock(&save_mutex); + pthread_mutex_lock(&save_mutex); fname = strdup(DM_CONFIG ".XXXXXX"); if (fname && (fd = mkstemp(fname)) != -1) { @@ -87,9 +78,7 @@ void dm_save(void) } free(fname); -// pthread_mutex_unlock(&save_mutex); - - running = 0; + pthread_mutex_unlock(&save_mutex); } void dm_dump(int fd, const char *element) From 3a7e48c955b40ae35d349f6e13cc1449555b7ef6 Mon Sep 17 00:00:00 2001 From: Robin Haberkorn Date: Thu, 10 Feb 2022 00:31:43 +0100 Subject: [PATCH 22/35] avoid ev_loop recursion: some of the server-to-client requests have been refactored while update_interface_state() directly uses libnl now * ev_loop recursion is unsafe and caused crashes * the firmware_download, firmware_commit and set_boot_order requests will now use the main ev_run() * Unfortunately, it would have been a lot of refactoring to keep the CMD_CLIENT_GET_INTERFACE_STATE while avoiding ev_loop recursion. update_interface_state() therefore no longer calls a server-to-client request but uses libnl directly to retrieve all necessary data. It is assumed that there is no need to actually customize the interface-state retrieval. CMD_CLIENT_GET_INTERFACE_STATE has been removed. --- README.md | 1 + configure.ac | 5 + libdmconfig/dm_dmclient_rpc_impl.c | 6 - libdmconfig/dm_dmclient_rpc_impl.h | 1 - libdmconfig/dm_dmclient_rpc_skel.c | 17 - libdmconfig/dm_dmclient_rpc_stub.c | 64 --- libdmconfig/dm_dmclient_rpc_stub.h | 9 - libdmconfig/dm_dmconfig_rpc_impl.h | 8 +- libdmconfig/dm_dmconfig_rpc_skel.c | 84 ++-- libdmconfig/dm_dmconfig_rpc_skel.h | 16 +- libdmconfig/dmconfig.xml | 3 - mand/Makefile.am | 6 +- mand/dm_dmconfig.c | 709 +++++++++++++++++++---------- 13 files changed, 535 insertions(+), 394 deletions(-) diff --git a/README.md b/README.md index b866f18..2a52b07 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,7 @@ aware and depend on particular entries in those models. - expat - libev - libtalloc +- libnl and libnl-route - lua 5.1 - 5.3 - xsltproc - python3 diff --git a/configure.ac b/configure.ac index 369a09b..04deee0 100644 --- a/configure.ac +++ b/configure.ac @@ -103,6 +103,11 @@ fi AC_CHECK_LIB(talloc, talloc_named_const, , AC_MSG_ERROR(Required libtalloc missing) ) AC_CHECK_HEADERS([talloc.h talloc/talloc.h]) +# Necessary to rertrieving the interface-state. +PKG_CHECK_MODULES([LIBNL3], [libnl-3.0 >= 3.2.8 libnl-route-3.0 >= 3.2.8]) +AC_SUBST([LIBNL3_LIBS]) +AC_SUBST([LIBNL3_CFLAGS]) + save_LIBS=$LIBS AC_CHECK_HEADER(pthread.h, , AC_MSG_ERROR(You need the pthread headers) ) diff --git a/libdmconfig/dm_dmclient_rpc_impl.c b/libdmconfig/dm_dmclient_rpc_impl.c index 708b0d9..3eb6dcb 100644 --- a/libdmconfig/dm_dmclient_rpc_impl.c +++ b/libdmconfig/dm_dmclient_rpc_impl.c @@ -10,7 +10,6 @@ uint32_t rpc_client_active_notify(void *ctx, DM2_AVPGRP *obj) __attribute__ ((weak, alias ("__rpc_client_active_notify"))); uint32_t rpc_client_event_broadcast(void *ctx, const char *path, uint32_t type) __attribute__ ((weak, alias ("__rpc_client_event_broadcast"))); -uint32_t rpc_client_get_interface_state(void *ctx, const char *if_name, DM2_REQUEST *answer) __attribute__ ((weak, alias ("__rpc_client_get_interface_state"))); uint32_t rpc_agent_firmware_download(void *ctx, char *address, uint8_t credentialstype, char *credential, char *install_target, uint32_t timeframe, uint8_t retry_count, uint32_t retry_interval, uint32_t retry_interval_increment, @@ -28,11 +27,6 @@ uint32_t __rpc_client_event_broadcast(void *ctx __attribute__((unused)), const c return RC_OK; } -uint32_t __rpc_client_get_interface_state(void *ctx __attribute__((unused)), const char *if_name __attribute__((unused)), DM2_REQUEST *answer __attribute__((unused))) -{ - return RC_OK; -} - uint32_t __rpc_agent_firmware_download(void *ctx __attribute__((unused)), char *address __attribute__((unused)), uint8_t credentialstype __attribute__((unused)), diff --git a/libdmconfig/dm_dmclient_rpc_impl.h b/libdmconfig/dm_dmclient_rpc_impl.h index ba171c8..24e3f68 100644 --- a/libdmconfig/dm_dmclient_rpc_impl.h +++ b/libdmconfig/dm_dmclient_rpc_impl.h @@ -16,7 +16,6 @@ uint32_t rpc_client_active_notify(void *ctx, DM2_AVPGRP *obj); uint32_t rpc_client_event_broadcast(void *ctx, const char *path, uint32_t type); -uint32_t rpc_client_get_interface_state(void *ctx, const char *if_name, DM2_REQUEST *answer); uint32_t rpc_agent_firmware_download(void *ctx, char *address, uint8_t credentialstype, char *credential, char *install_target, uint32_t timeframe, uint8_t retry_count, uint32_t retry_interval, uint32_t retry_interval_increment, diff --git a/libdmconfig/dm_dmclient_rpc_skel.c b/libdmconfig/dm_dmclient_rpc_skel.c index 4088c1e..866120f 100644 --- a/libdmconfig/dm_dmclient_rpc_skel.c +++ b/libdmconfig/dm_dmclient_rpc_skel.c @@ -52,19 +52,6 @@ rpc_client_event_broadcast_skel(void *ctx, DM2_AVPGRP *obj) return rpc_client_event_broadcast(ctx, path, type); } -static inline uint32_t -rpc_client_get_interface_state_skel(void *ctx, DM2_AVPGRP *obj, DM2_REQUEST *answer) -{ - uint32_t rc; - char *if_name; - - if ((rc = dm_expect_string_type(obj, AVP_STRING, VP_TRAVELPING, &if_name)) != RC_OK - || (rc = dm_expect_end(obj)) != RC_OK) - return rc; - - return rpc_client_get_interface_state(ctx, if_name, answer); -} - static inline uint32_t rpc_agent_firmware_download_skel(void *ctx, DM2_AVPGRP *obj, DM2_REQUEST *answer) { @@ -154,10 +141,6 @@ rpc_dmclient_switch(void *ctx, const DMC_REQUEST *req, DM2_AVPGRP *obj __attribu return rc; switch (req->code) { - case CMD_CLIENT_GET_INTERFACE_STATE: - rc = rpc_client_get_interface_state_skel(ctx, obj, *answer); - break; - case CMD_FIRMWARE_DOWNLOAD: rpc_agent_firmware_download_skel(ctx, obj, *answer); break; diff --git a/libdmconfig/dm_dmclient_rpc_stub.c b/libdmconfig/dm_dmclient_rpc_stub.c index 0b45c99..a01cb26 100644 --- a/libdmconfig/dm_dmclient_rpc_stub.c +++ b/libdmconfig/dm_dmclient_rpc_stub.c @@ -51,21 +51,6 @@ uint32_t rpc_event_broadcast(DMCONTEXT *ctx, const char *path, uint32_t type) } -uint32_t rpc_get_interface_state_async(DMCONTEXT *ctx, const char *if_name, DMRESULT_CB cb, void *data) -{ - uint32_t rc; - DM2_REQUEST *req; - - if (!(req = dm_new_request(ctx, CMD_CLIENT_GET_INTERFACE_STATE, CMD_FLAG_REQUEST, 0, 0))) - return RC_ERR_ALLOC; - - if ((rc = dm_add_string(req, AVP_STRING, VP_TRAVELPING, if_name)) != RC_OK - || (rc = dm_finalize_packet(req)) != RC_OK) - return rc; - - return dm_enqueue_request(ctx, req, cb, data); -} - uint32_t rpc_agent_firmware_download_async(DMCONTEXT *ctx, const char *address, uint8_t credentialstype, const char *credential, const char *install_target, uint32_t timeframe, uint8_t retry_count, uint32_t retry_interval, uint32_t retry_interval_increment, @@ -124,52 +109,3 @@ uint32_t rpc_agent_set_boot_order_async(DMCONTEXT *ctx, int pcnt, const char **b return dm_enqueue_request(ctx, req, cb, data); } - -/* - * sync call wrapper's - */ - -uint32_t rpc_get_interface_state(DMCONTEXT *ctx, const char *if_name, DM2_AVPGRP *answer) -{ - struct async_reply reply = {.rc = RC_OK, .answer = answer }; - - rpc_get_interface_state_async(ctx, if_name, dm_async_cb, &reply); - ev_run(ctx->ev, 0); - - return reply.rc; -} - -uint32_t rpc_agent_firmware_download(DMCONTEXT *ctx, const char *address, uint8_t credentialstype, const char *credential, - const char *install_target, uint32_t timeframe, uint8_t retry_count, - uint32_t retry_interval, uint32_t retry_interval_increment, - DM2_AVPGRP *answer) -{ - struct async_reply reply = {.rc = RC_OK, .answer = answer }; - - rpc_agent_firmware_download_async(ctx, address, credentialstype, credential, install_target, - timeframe, retry_count, retry_interval, retry_interval_increment, - dm_async_cb, &reply); - ev_run(ctx->ev, 0); - - return reply.rc; -} - -uint32_t rpc_agent_firmware_commit(DMCONTEXT *ctx, int32_t job_id) -{ - struct async_reply reply = {.rc = RC_OK, .answer = NULL }; - - rpc_agent_firmware_commit_async(ctx, job_id, dm_async_cb, &reply); - ev_run(ctx->ev, 0); - - return reply.rc; -} - -uint32_t rpc_agent_set_boot_order(DMCONTEXT *ctx, int pcnt, const char **boot_order) -{ - struct async_reply reply = {.rc = RC_OK, .answer = NULL }; - - rpc_agent_set_boot_order_async(ctx, pcnt, boot_order, dm_async_cb, &reply); - ev_run(ctx->ev, 0); - - return reply.rc; -} diff --git a/libdmconfig/dm_dmclient_rpc_stub.h b/libdmconfig/dm_dmclient_rpc_stub.h index 1437c31..12f4a1e 100644 --- a/libdmconfig/dm_dmclient_rpc_stub.h +++ b/libdmconfig/dm_dmclient_rpc_stub.h @@ -16,7 +16,6 @@ #include "mand/dm_notify.h" uint32_t rpc_event_broadcast(DMCONTEXT *ctx, const char *path, uint32_t type); -uint32_t rpc_get_interface_state_async(DMCONTEXT *ctx, const char *if_name, DMRESULT_CB cb, void *data); uint32_t rpc_agent_firmware_download_async(DMCONTEXT *ctx, const char *address, uint8_t credentialstype, const char *credential, const char *install_target, uint32_t timeframe, uint8_t retry_count, uint32_t retry_interval, uint32_t retry_interval_increment, @@ -24,12 +23,4 @@ uint32_t rpc_agent_firmware_download_async(DMCONTEXT *ctx, const char *address, uint32_t rpc_agent_firmware_commit_async(DMCONTEXT *ctx, int32_t job_id, DMRESULT_CB cb, void *data); uint32_t rpc_agent_set_boot_order_async(DMCONTEXT *ctx, int pcnt, const char **boot_order, DMRESULT_CB cb, void *data); -uint32_t rpc_get_interface_state(DMCONTEXT *ctx, const char *if_name, DM2_AVPGRP *answer); -uint32_t rpc_agent_firmware_download(DMCONTEXT *ctx, const char *address, uint8_t credentialstype, const char *credential, - const char *install_target, uint32_t timeframe, uint8_t retry_count, - uint32_t retry_interval, uint32_t retry_interval_increment, - DM2_AVPGRP *grp); -uint32_t rpc_agent_firmware_commit(DMCONTEXT *ctx, int32_t job_id); -uint32_t rpc_agent_set_boot_order(DMCONTEXT *ctx, int pcnt, const char **boot_order); - #endif diff --git a/libdmconfig/dm_dmconfig_rpc_impl.h b/libdmconfig/dm_dmconfig_rpc_impl.h index c8e487e..71ed092 100644 --- a/libdmconfig/dm_dmconfig_rpc_impl.h +++ b/libdmconfig/dm_dmconfig_rpc_impl.h @@ -48,8 +48,10 @@ uint32_t rpc_system_shutdown(void *ctx); uint32_t rpc_firmware_download(void *ctx, char *address, uint8_t credentialstype, char *credential, char *install_target, uint32_t timeframe, uint8_t retry_count, uint32_t retry_interval, uint32_t retry_interval_increment, - DM2_REQUEST *answer); -uint32_t rpc_firmware_commit(void *ctx, int32_t job_id); -uint32_t rpc_set_boot_order(void *ctx, int pcnt, const char **boot_order); + struct dm_request_info *request_info); +uint32_t rpc_firmware_commit(void *ctx, int32_t job_id, + struct dm_request_info *request_info); +uint32_t rpc_set_boot_order(void *ctx, int pcnt, const char **boot_order, + struct dm_request_info *request_info); #endif diff --git a/libdmconfig/dm_dmconfig_rpc_skel.c b/libdmconfig/dm_dmconfig_rpc_skel.c index 3f5518f..71ee770 100644 --- a/libdmconfig/dm_dmconfig_rpc_skel.c +++ b/libdmconfig/dm_dmconfig_rpc_skel.c @@ -404,7 +404,7 @@ rpc_system_shutdown_skel(void *ctx, DM2_AVPGRP *obj) } static inline uint32_t -rpc_firmware_download_skel(void *ctx, DM2_AVPGRP *obj, DM2_REQUEST *answer) +rpc_firmware_download_skel(void *ctx, DM2_AVPGRP *obj, struct dm_request_info *request_info) { uint32_t rc; char *address; @@ -429,11 +429,12 @@ rpc_firmware_download_skel(void *ctx, DM2_AVPGRP *obj, DM2_REQUEST *answer) return rpc_firmware_download(ctx, address, credentialstype, credential, install_target, timeframe, retry_count, - retry_interval, retry_interval_increment, answer); + retry_interval, retry_interval_increment, + request_info); } static inline uint32_t -rpc_firmware_commit_skel(void *ctx, DM2_AVPGRP *obj) +rpc_firmware_commit_skel(void *ctx, DM2_AVPGRP *obj, struct dm_request_info *request_info) { uint32_t rc; int32_t job_id; @@ -442,11 +443,11 @@ rpc_firmware_commit_skel(void *ctx, DM2_AVPGRP *obj) || (rc = dm_expect_end(obj)) != RC_OK) return rc; - return rpc_firmware_commit(ctx, job_id); + return rpc_firmware_commit(ctx, job_id, request_info); } static inline uint32_t -rpc_set_boot_order_skel(void *ctx, DM2_AVPGRP *obj) +rpc_set_boot_order_skel(void *ctx, DM2_AVPGRP *obj, struct dm_request_info *request_info) { uint32_t rc; int pcnt; @@ -464,17 +465,16 @@ rpc_set_boot_order_skel(void *ctx, DM2_AVPGRP *obj) } while (dm_expect_end(obj) != RC_OK); if (rc == RC_OK) - rc = rpc_set_boot_order(ctx, pcnt, (const char **)boot_order); + rc = rpc_set_boot_order(ctx, pcnt, (const char **)boot_order, request_info); talloc_free(boot_order); return rc; } uint32_t -rpc_dmconfig_switch(void *ctx, const DMC_REQUEST *req, DM2_AVPGRP *obj, DM2_REQUEST **answer) +rpc_dmconfig_switch(void *ctx, const DMC_REQUEST *req, DM2_AVPGRP *obj, struct dm_request_info *request_info) { uint32_t rc; - size_t pos; /* one way requests */ switch (req->code) { @@ -482,92 +482,93 @@ rpc_dmconfig_switch(void *ctx, const DMC_REQUEST *req, DM2_AVPGRP *obj, DM2_REQU return rpc_endsession_skel(ctx, obj); } - if (!(*answer = dm_new_request(ctx, req->code, 0, req->hop2hop, req->end2end))) + if (!(request_info->answer = dm_new_request(ctx, req->code, 0, req->hop2hop, req->end2end))) return RC_ERR_ALLOC; /* make the RC the first AVP and remember it's position */ - if ((rc = dm_add_uint32_get_pos(*answer, AVP_RC, VP_TRAVELPING, RC_OK, &pos)) != RC_OK) + if ((rc = dm_add_uint32_get_pos(request_info->answer, AVP_RC, VP_TRAVELPING, RC_OK, + &request_info->rc_pos)) != RC_OK) return rc; switch (req->code) { case CMD_STARTSESSION: - rc = rpc_startsession_skel(ctx, obj, *answer); + rc = rpc_startsession_skel(ctx, obj, request_info->answer); break; case CMD_SWITCHSESSION: - rc = rpc_switchsession_skel(ctx, obj, *answer); + rc = rpc_switchsession_skel(ctx, obj, request_info->answer); break; case CMD_SESSIONINFO: - rc = rpc_sessioninfo_skel(ctx, obj, *answer); + rc = rpc_sessioninfo_skel(ctx, obj, request_info->answer); break; case CMD_CFGSESSIONINFO: - rc = rpc_cfgsessioninfo_skel(ctx, obj, *answer); + rc = rpc_cfgsessioninfo_skel(ctx, obj, request_info->answer); break; case CMD_SUBSCRIBE_NOTIFY: - rc = rpc_subscribe_notify_skel(ctx, obj, *answer); + rc = rpc_subscribe_notify_skel(ctx, obj, request_info->answer); break; case CMD_UNSUBSCRIBE_NOTIFY: - rc = rpc_unsubscribe_notify_skel(ctx, obj, *answer); + rc = rpc_unsubscribe_notify_skel(ctx, obj, request_info->answer); break; case CMD_PARAM_NOTIFY: - rc = rpc_param_notify_skel(ctx, obj, *answer); + rc = rpc_param_notify_skel(ctx, obj, request_info->answer); break; case CMD_RECURSIVE_PARAM_NOTIFY: - rc = rpc_recursive_param_notify_skel(ctx, obj, *answer); + rc = rpc_recursive_param_notify_skel(ctx, obj, request_info->answer); break; case CMD_GET_PASSIVE_NOTIFICATIONS: - rc = rpc_get_passive_notifications_skel(ctx, obj, *answer); + rc = rpc_get_passive_notifications_skel(ctx, obj, request_info->answer); break; case CMD_DB_ADDINSTANCE: - rc = rpc_db_addinstance_skel(ctx, obj, *answer); + rc = rpc_db_addinstance_skel(ctx, obj, request_info->answer); break; case CMD_DB_DELINSTANCE: - rc = rpc_db_delinstance_skel(ctx, obj, *answer); + rc = rpc_db_delinstance_skel(ctx, obj, request_info->answer); break; case CMD_DB_SET: - rc = rpc_db_set_skel(ctx, obj, *answer); + rc = rpc_db_set_skel(ctx, obj, request_info->answer); break; case CMD_DB_GET: - rc = rpc_db_get_skel(ctx, obj, *answer); + rc = rpc_db_get_skel(ctx, obj, request_info->answer); break; case CMD_DB_LIST: - rc = rpc_db_list_skel(ctx, obj, *answer); + rc = rpc_db_list_skel(ctx, obj, request_info->answer); break; case CMD_DB_RETRIEVE_ENUMS: - rc = rpc_db_retrieve_enum_skel(ctx, obj, *answer); + rc = rpc_db_retrieve_enum_skel(ctx, obj, request_info->answer); break; case CMD_DB_DUMP: - rc = rpc_db_dump_skel(ctx, obj, *answer); + rc = rpc_db_dump_skel(ctx, obj, request_info->answer); break; case CMD_DB_SAVE: - rc = rpc_db_save_skel(ctx, obj, *answer); + rc = rpc_db_save_skel(ctx, obj, request_info->answer); break; case CMD_DB_COMMIT: - rc = rpc_db_commit_skel(ctx, obj, *answer); + rc = rpc_db_commit_skel(ctx, obj, request_info->answer); break; case CMD_DB_CANCEL: - rc = rpc_db_cancel_skel(ctx, obj, *answer); + rc = rpc_db_cancel_skel(ctx, obj, request_info->answer); break; case CMD_DB_FINDINSTANCE: - rc = rpc_db_findinstance_skel(ctx, obj, *answer); + rc = rpc_db_findinstance_skel(ctx, obj, request_info->answer); break; case CMD_REGISTER_ROLE: @@ -582,17 +583,24 @@ rpc_dmconfig_switch(void *ctx, const DMC_REQUEST *req, DM2_AVPGRP *obj, DM2_REQU rc = rpc_system_shutdown_skel(ctx, obj); break; + /* + * Ownership of request_info is passed to these functions + * because the answers will be sent from libev watchers. + */ case CMD_FIRMWARE_DOWNLOAD: - rpc_firmware_download_skel(ctx, obj, *answer); - break; + talloc_increase_ref_count(request_info); + rpc_firmware_download_skel(ctx, obj, request_info); + return RC_OK; case CMD_FIRMWARE_COMMIT: - rpc_firmware_commit_skel(ctx, obj); - break; + talloc_increase_ref_count(request_info); + rpc_firmware_commit_skel(ctx, obj, request_info); + return RC_OK; case CMD_SET_BOOT_ORDER: - rpc_set_boot_order_skel(ctx, obj); - break; + talloc_increase_ref_count(request_info); + rpc_set_boot_order_skel(ctx, obj, request_info); + return RC_OK; default: rc = RC_ERR_CONNECTION; @@ -601,8 +609,8 @@ rpc_dmconfig_switch(void *ctx, const DMC_REQUEST *req, DM2_AVPGRP *obj, DM2_REQU if (rc != RC_ERR_ALLOC) { /* fill in the RC */ - dm_put_uint32_at_pos(*answer, pos, rc); - return dm_finalize_packet(*answer); + dm_put_uint32_at_pos(request_info->answer, request_info->rc_pos, rc); + return dm_finalize_packet(request_info->answer); } return rc; diff --git a/libdmconfig/dm_dmconfig_rpc_skel.h b/libdmconfig/dm_dmconfig_rpc_skel.h index aa7a07f..649d704 100644 --- a/libdmconfig/dm_dmconfig_rpc_skel.h +++ b/libdmconfig/dm_dmconfig_rpc_skel.h @@ -10,9 +10,23 @@ #ifndef DM_DMCONFIG_RPC_SKEL_H #define DM_DMCONFIG_RPC_SKEL_H +#include + +//#include "mand/dm_dmconfig.h" + #include "libdmconfig/dmmsg.h" #include "libdmconfig/dmconfig.h" -uint32_t rpc_dmconfig_switch(void *ctx, const DMC_REQUEST *req, DM2_AVPGRP *obj, DM2_REQUEST **answer); +struct dm_request_info { + /** SOCKCONTEXT on which the request was received */ + void *ctx; + /** partially prepared answer */ + DM2_REQUEST *answer; + /** position of return code in answer */ + size_t rc_pos; +}; + +uint32_t rpc_dmconfig_switch(void *ctx, const DMC_REQUEST *req, DM2_AVPGRP *obj, + struct dm_request_info *request_info); #endif diff --git a/libdmconfig/dmconfig.xml b/libdmconfig/dmconfig.xml index 474bfaa..4c7f376 100644 --- a/libdmconfig/dmconfig.xml +++ b/libdmconfig/dmconfig.xml @@ -108,9 +108,6 @@ - - - diff --git a/mand/Makefile.am b/mand/Makefile.am index a575725..87402c1 100644 --- a/mand/Makefile.am +++ b/mand/Makefile.am @@ -5,7 +5,8 @@ AM_CFLAGS = -g -Werror -funit-at-a-time \ -I$(top_srcdir) \ -I$(top_srcdir)/include/compat \ - -I$(top_builddir) + -I$(top_builddir) \ + $(LIBNL3_CFLAGS) SUBDIRS = snmp tests @@ -54,7 +55,8 @@ if NET_SNMP mand_SOURCES += net-snmpd.c endif -mand_LDADD = libdm.la $(top_builddir)/libdmconfig/libdm_dmconfig.la +mand_LDADD = libdm.la $(top_builddir)/libdmconfig/libdm_dmconfig.la \ + $(LIBNL3_LIBS) p_table.c p_table.h dm_action_table.c dm_action_table.h: $(top_srcdir)/yang/specs/*yang $(PYANG) --plugindir $(top_srcdir)/yang/pyang_plugin/ -p $(top_srcdir)/yang/specs -f OpenCPE $(top_srcdir)/yang/specs/*.yang diff --git a/mand/dm_dmconfig.c b/mand/dm_dmconfig.c index 18323a3..15c05d4 100644 --- a/mand/dm_dmconfig.c +++ b/mand/dm_dmconfig.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -36,6 +37,14 @@ #include #include + +#include +#include + +#include +#include +#include + #include #include @@ -167,7 +176,6 @@ request_cb(DMCONTEXT *socket, DM_PACKET *pkt, DM2_AVPGRP *grp, void *userdata) { SOCKCONTEXT *ctx = userdata; DMC_REQUEST req; - DM2_REQUEST *answer = NULL; req.hop2hop = dm_hop2hop_id(pkt); req.end2end = dm_end2end_id(pkt); @@ -182,13 +190,25 @@ request_cb(DMCONTEXT *socket, DM_PACKET *pkt, DM2_AVPGRP *grp, void *userdata) if (ev_is_active(&ctx->session_timer_ev)) ev_timer_again(socket->ev, &ctx->session_timer_ev); - if ((rpc_dmconfig_switch(ctx, &req, grp, &answer)) == RC_ERR_ALLOC) { + struct dm_request_info *request_info = talloc_zero(NULL, struct dm_request_info); + if (!request_info) + return; + request_info->ctx = ctx; + + if ((rpc_dmconfig_switch(ctx, &req, grp, request_info)) == RC_ERR_ALLOC) { shutdown_session(ctx); + talloc_free(request_info); return; } - if (answer) - dm_enqueue(socket, answer, REPLY, NULL, NULL); + /* + * FIXME: Perhaps we should move this into rpc_dmconfig_switch(). + * However, we don't have the DMCONTEXT type there. + * It could be added to struct dm_request_info, though. + */ + if (request_info->answer && !talloc_reference_count(request_info)) + dm_enqueue(socket, request_info->answer, REPLY, NULL, NULL); + talloc_unlink(NULL, request_info); } uint32_t @@ -1546,42 +1566,105 @@ uint32_t rpc_system_shutdown(void *data __attribute__((unused))) return RC_OK; } +static void +rpc_firmware_download_cb(DMCONTEXT *socket __attribute__((unused)), DMCONFIG_EVENT event, DM2_AVPGRP *grp, void *userdata) +{ + uint32_t rc = RC_OK; + struct dm_request_info *request_info = userdata; + SOCKCONTEXT *ctx = request_info->ctx; + + if (event != DMCONFIG_ANSWER_READY) { + rc = RC_ERR_MISC; + goto response; + } + + if (dm_expect_uint32_type(grp, AVP_RC, VP_TRAVELPING, &rc) != RC_OK) { + rc = RC_ERR_MISC; + goto response; + } + + int32_t job_id; + if ((rc = dm_expect_int32_type(grp, AVP_INT32, VP_TRAVELPING, &job_id)) != RC_OK + || (rc = dm_expect_group_end(grp)) != RC_OK) + goto response; + + dm_debug(ctx->id, "CMD: %s: answer: %u", "FIRMWARE DOWNLOAD", job_id); + +response: + if (rc == RC_OK) { + if (dm_add_int32(request_info->answer, AVP_INT32, VP_TRAVELPING, job_id) != RC_OK) + return; + } else { + /* fill in the RC */ + dm_put_uint32_at_pos(request_info->answer, request_info->rc_pos, rc); + } + if (dm_finalize_packet(request_info->answer) != RC_OK) + return; + + dm_enqueue(ctx->socket, request_info->answer, REPLY, NULL, NULL); + talloc_free(request_info); +} + uint32_t rpc_firmware_download(void *data, char *address, uint8_t credentialstype, char *credential, - char *install_target, uint32_t timeframe, uint8_t retry_count, - uint32_t retry_interval, uint32_t retry_interval_increment, - DM2_REQUEST *answer) + char *install_target, uint32_t timeframe, uint8_t retry_count, + uint32_t retry_interval, uint32_t retry_interval_increment, + struct dm_request_info *request_info) { - SOCKCONTEXT *ctx __attribute__((unused)) = data; + SOCKCONTEXT *ctx = data; SOCKCONTEXT *clnt; - DM2_AVPGRP clnt_answer; uint32_t rc; - int32_t job_id; dm_debug(ctx->id, "CMD: %s", "FIRMWARE DOWNLOAD"); - if ((clnt = find_role("-firmware")) == NULL) + if ((clnt = find_role("-firmware")) == NULL) { + talloc_free(request_info); return RC_ERR_MISC; + } - memset(&clnt_answer, 0, sizeof(clnt_answer)); - if ((rc = rpc_agent_firmware_download(clnt->socket, address, credentialstype, credential, - install_target, timeframe, retry_count, - retry_interval, retry_interval_increment, &clnt_answer)) != RC_OK) { - printf("rpc_agent_firmware_download rc=%d\n", rc); + rc = rpc_agent_firmware_download_async(clnt->socket, address, credentialstype, credential, + install_target, timeframe, retry_count, + retry_interval, retry_interval_increment, + rpc_firmware_download_cb, request_info); + if (rc != RC_OK) { + logx(LOG_ERR, "rpc_agent_firmware_download_async rc=%d\n", rc); return rc; } - if ((rc = dm_expect_int32_type(&clnt_answer, AVP_INT32, VP_TRAVELPING, &job_id)) != RC_OK - || (rc = dm_expect_group_end(&clnt_answer)) != RC_OK) - return rc; - dm_debug(ctx->id, "CMD: %s: answer: %u", "FIRMWARE DOWNLOAD", job_id); + return RC_OK; +} - if (dm_add_int32(answer, AVP_INT32, VP_TRAVELPING, job_id)) - return RC_ERR_ALLOC; +static void +rpc_firmware_commit_cb(DMCONTEXT *socket __attribute__((unused)), DMCONFIG_EVENT event, DM2_AVPGRP *grp, void *userdata) +{ + uint32_t rc = RC_OK; + struct dm_request_info *request_info = userdata; + SOCKCONTEXT *ctx = request_info->ctx; - return RC_OK; + if (event != DMCONFIG_ANSWER_READY) { + rc = RC_ERR_MISC; + goto response; + } + + if (dm_expect_uint32_type(grp, AVP_RC, VP_TRAVELPING, &rc) != RC_OK) { + rc = RC_ERR_MISC; + goto response; + } + + dm_debug(ctx->id, "CMD: %s: answer: %u", "FIRMWARE COMMIT", rc); + +response: + if (rc != RC_OK) + /* fill in the RC */ + dm_put_uint32_at_pos(request_info->answer, request_info->rc_pos, rc); + if (dm_finalize_packet(request_info->answer) != RC_OK) + return; + + dm_enqueue(ctx->socket, request_info->answer, REPLY, NULL, NULL); + talloc_free(request_info); } -uint32_t rpc_firmware_commit(void *data, int32_t job_id) +uint32_t rpc_firmware_commit(void *data, int32_t job_id, + struct dm_request_info *request_info) { SOCKCONTEXT *ctx __attribute__((unused)) = data; SOCKCONTEXT *clnt; @@ -1592,13 +1675,48 @@ uint32_t rpc_firmware_commit(void *data, int32_t job_id) if ((clnt = find_role("-firmware")) == NULL) return RC_ERR_MISC; - rc = rpc_agent_firmware_commit(clnt->socket, job_id); + rc = rpc_agent_firmware_commit_async(clnt->socket, job_id, + rpc_firmware_commit_cb, request_info); + if (rc != RC_OK) { + logx(LOG_ERR, "rpc_agent_firmware_commit_async rc=%d\n", rc); + return rc; + } - dm_debug(ctx->id, "CMD: %s: answer: %u", "FIRMWARE COMMIT", rc); - return rc; + return RC_OK; +} + +static void +rpc_set_boot_order_cb(DMCONTEXT *socket __attribute__((unused)), DMCONFIG_EVENT event, DM2_AVPGRP *grp, void *userdata) +{ + uint32_t rc = RC_OK; + struct dm_request_info *request_info = userdata; + SOCKCONTEXT *ctx = request_info->ctx; + + if (event != DMCONFIG_ANSWER_READY) { + rc = RC_ERR_MISC; + goto response; + } + + if (dm_expect_uint32_type(grp, AVP_RC, VP_TRAVELPING, &rc) != RC_OK) { + rc = RC_ERR_MISC; + goto response; + } + + dm_debug(ctx->id, "CMD: %s: answer: %u", "SET BOOT ORDER", rc); + +response: + if (rc != RC_OK) + /* fill in the RC */ + dm_put_uint32_at_pos(request_info->answer, request_info->rc_pos, rc); + if (dm_finalize_packet(request_info->answer) != RC_OK) + return; + + dm_enqueue(ctx->socket, request_info->answer, REPLY, NULL, NULL); + talloc_free(request_info); } -uint32_t rpc_set_boot_order(void *data, int pcnt, const char **boot_order) +uint32_t rpc_set_boot_order(void *data, int pcnt, const char **boot_order, + struct dm_request_info *request_info) { SOCKCONTEXT *ctx __attribute__((unused)) = data; SOCKCONTEXT *clnt; @@ -1609,10 +1727,14 @@ uint32_t rpc_set_boot_order(void *data, int pcnt, const char **boot_order) if ((clnt = find_role("-firmware")) == NULL) return RC_ERR_MISC; - rc = rpc_agent_set_boot_order(clnt->socket, pcnt, boot_order); + rc = rpc_agent_set_boot_order_async(clnt->socket, pcnt, boot_order, + rpc_set_boot_order_cb, request_info); + if (rc != RC_OK) { + logx(LOG_ERR, "rpc_agent_set_boot_order_async rc=%d\n", rc); + return rc; + } - dm_debug(ctx->id, "CMD: %s: answer: %u", "SET BOOT ORDER", rc); - return rc; + return RC_OK; } void dm_event_broadcast(const dm_selector sel, enum dm_action_type type) @@ -1628,13 +1750,183 @@ void dm_event_broadcast(const dm_selector sel, enum dm_action_type type) rpc_event_broadcast(ctx->socket, path, type); } -static void update_interface_state(struct dm_value_table *tbl) +static int sys_scan(const char *file, const char *fmt, ...) { - uint32_t rc; - SOCKCONTEXT *ctx; - const char *name; - DM2_AVPGRP answer; + FILE *fin; + int rc, _errno; + va_list vlist; + + fin = fopen(file, "r"); + if (!fin) { + errno = 0; + return EOF; + } + + va_start(vlist, fmt); + errno = 0; + rc = vfscanf(fin, fmt, vlist); + _errno = errno; + va_end(vlist); + + fclose(fin); + + errno = _errno; + return rc; +} + +static uint32_t if_ioctl(int d, int request, void *data) +{ + int result; + + if (ioctl(d, request, data) == -1) { + do { + result = close(d); + } while (result == -1 && errno == EINTR); + return RC_ERR_MISC; + } + return RC_OK; +} + +static void +update_neigh_state_ip4(struct nl_object *obj, void *data) +{ + dm_selector *sel = data; + + char buf[32]; + struct rtnl_neigh *neigh = (struct rtnl_neigh *)obj; + + struct in_addr dst; + memcpy(&dst.s_addr, nl_addr_get_binary_addr(rtnl_neigh_get_dst(neigh)), sizeof(dst.s_addr)); + struct nl_addr *lladdr = rtnl_neigh_get_lladdr(neigh); + uint32_t state = rtnl_neigh_get_state(neigh); + nl_addr2str(lladdr, buf, sizeof(buf)); + uint8_t origin = (state == NUD_PERMANENT) ? 1 : 2; + + dm_id if_id = 0; + + struct dm_instance_node *ipn; + if (!(ipn = dm_add_instance_by_selector(*sel, &if_id))) + return; + + dm_set_ipv4_by_id(DM_TABLE(ipn->table), field_ocpe__interfaces_state__interface__ipv4__neighbor_ip, dst); + dm_set_string_by_id(DM_TABLE(ipn->table), field_ocpe__interfaces_state__interface__ipv4__neighbor_linklayeraddress, buf); + dm_set_enum_by_id(DM_TABLE(ipn->table), field_ocpe__interfaces_state__interface__ipv4__neighbor_origin, origin); + + update_instance_node_index(ipn); + + logx(LOG_DEBUG, "IPV4 Neighbor %d", if_id); +} + +static void +update_neigh_state_ip6(struct nl_object *obj, void *data) +{ + dm_selector *sel = data; + + char buf[32]; + struct rtnl_neigh *neigh = (struct rtnl_neigh *)obj; + + struct in6_addr dst; + memcpy(dst.s6_addr, nl_addr_get_binary_addr(rtnl_neigh_get_dst(neigh)), sizeof(dst.s6_addr)); + struct nl_addr *lladdr = rtnl_neigh_get_lladdr(neigh); + uint32_t state = rtnl_neigh_get_state(neigh); + uint32_t flags = rtnl_neigh_get_flags(neigh); + nl_addr2str(lladdr, buf, sizeof(buf)); + uint8_t origin = (state == NUD_PERMANENT) ? 1 : 2; + uint8_t is_router = ((flags & NTF_ROUTER) != 0); + + dm_id if_id = 0; + + struct dm_instance_node *ipn; + if (!(ipn = dm_add_instance_by_selector(*sel, &if_id))) + return; + + dm_set_ipv6_by_id(DM_TABLE(ipn->table), field_ocpe__interfaces_state__interface__ipv6__neighbor_ip, dst); + dm_set_string_by_id(DM_TABLE(ipn->table), field_ocpe__interfaces_state__interface__ipv6__neighbor_linklayeraddress, buf); + dm_set_enum_by_id(DM_TABLE(ipn->table), field_ocpe__interfaces_state__interface__ipv6__neighbor_origin, origin); + dm_set_bool_by_id(DM_TABLE(ipn->table), field_ocpe__interfaces_state__interface__ipv6__neighbor_isrouter, is_router); + + update_instance_node_index(ipn); + + logx(LOG_DEBUG, "IPV6 Neighbor %d", if_id); +} + +static void +update_addr_state_ip4(struct nl_object *obj, void *data) +{ + dm_selector *sel = data; + + char buf[32]; + struct nl_addr *naddr = rtnl_addr_get_local((struct rtnl_addr *) obj); + struct in_addr addr; + memcpy(&addr.s_addr, nl_addr_get_binary_addr(naddr), sizeof(addr.s_addr)); + unsigned int flags = rtnl_addr_get_flags((struct rtnl_addr *) obj); + uint8_t origin = 0; + logx(LOG_DEBUG, "IP: %s", nl_addr2str(naddr, buf, sizeof(buf))); + + if (flags & IFA_F_PERMANENT) + origin = 1; + + dm_id if_id = 0; + + struct dm_instance_node *ipn; + if (!(ipn = dm_add_instance_by_selector(*sel, &if_id))) + return; + logx(LOG_DEBUG, "IPV4 Addr %d", if_id); + + dm_set_ipv4_by_id(DM_TABLE(ipn->table), field_ocpe__interfaces_state__interface__ipv4__address_ip, addr); + dm_set_uint_by_id(DM_TABLE(ipn->table), field_ocpe__interfaces_state__interface__ipv4__address_prefixlength, + nl_addr_get_prefixlen(naddr)); + dm_set_enum_by_id(DM_TABLE(ipn->table), field_ocpe__interfaces_state__interface__ipv4__address_origin, origin); + + update_instance_node_index(ipn); +} + +static void +update_addr_state_ip6(struct nl_object *obj, void *data) +{ + dm_selector *sel = data; + + char buf[32]; + struct nl_addr *naddr = rtnl_addr_get_local((struct rtnl_addr *) obj); + struct in6_addr addr; + memcpy(addr.s6_addr, nl_addr_get_binary_addr(naddr), sizeof(addr.s6_addr)); + unsigned int flags = rtnl_addr_get_flags((struct rtnl_addr *) obj); + uint8_t origin = 0; + uint8_t status = 4; + + logx(LOG_DEBUG, "IP: %s", nl_addr2str(naddr, buf, sizeof(buf))); + + if (flags & IFA_F_OPTIMISTIC) + status = 7; + else if (flags & IFA_F_TENTATIVE) + status = 5; + else if (flags & IFA_F_HOMEADDRESS) + status = 0; + else if (flags & IFA_F_DEPRECATED) + status = 1; + + if (flags & IFA_F_PERMANENT) + origin = 1; + + dm_id if_id = 0; + + struct dm_instance_node *ipn; + if (!(ipn = dm_add_instance_by_selector(*sel, &if_id))) + return; + logx(LOG_DEBUG, "IPV6 Addr %d", if_id); + + dm_set_ipv6_by_id(DM_TABLE(ipn->table), field_ocpe__interfaces_state__interface__ipv6__address_ip, addr); + dm_set_uint_by_id(DM_TABLE(ipn->table), field_ocpe__interfaces_state__interface__ipv6__address_prefixlength, + nl_addr_get_prefixlen(naddr)); + dm_set_enum_by_id(DM_TABLE(ipn->table), field_ocpe__interfaces_state__interface__ipv6__address_origin, origin); + dm_set_enum_by_id(DM_TABLE(ipn->table), field_ocpe__interfaces_state__interface__ipv6__address_status, status); + + update_instance_node_index(ipn); +} + +static uint32_t update_interface_state(struct dm_value_table *tbl) +{ /* * Make sure the interface is reported as "down" in case of any errors. * This will also include missing interfaces. @@ -1644,48 +1936,75 @@ static void update_interface_state(struct dm_value_table *tbl) dm_set_enum_by_id(tbl, field_ocpe__interfaces_state__interface_operstatus , field_ocpe__interfaces_state__interface_operstatus_down); - if (!(ctx = find_role("-state"))) - /* there is no agent implementing the RPC */ - return; + const char *if_name = dm_get_string_by_id(tbl, field_ocpe__interfaces_state__interface_name); + logx(LOG_DEBUG, "get_ocpe__interfaces_state__interface: %s", if_name); - name = dm_get_string_by_id(tbl, field_ocpe__interfaces_state__interface_name); - printf("get_ocpe__interfaces_state__interface: %s\n", name); + char macstr[20]; + ticks_t rt_now = ticks(); - memset(&answer, 0, sizeof(answer)); - if ((rc = rpc_get_interface_state(ctx->socket, name, &answer)) != RC_OK) { - printf("get_ocpe__interfaces_state__interface rc=%d\n", rc); - return; - } + int fd; + FILE *fp; + char line[1024]; + struct ifreq ifr; + uint32_t rc; + + int scan_count; + + logx(LOG_DEBUG, "if_name: %s", if_name); + + const char *dev = if_name; + + fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); + if (fd == -1) + return RC_ERR_MISC; + + strncpy(ifr.ifr_name, dev, IFNAMSIZ-1); + ifr.ifr_name[IFNAMSIZ-1] = '\0'; + + if ((rc = if_ioctl(fd, SIOCGIFINDEX, &ifr)) != RC_OK) + return rc; + if (ifr.ifr_ifindex == 0) + ifr.ifr_ifindex = 2147483647; + int32_t if_index = ifr.ifr_ifindex; + + if ((rc = if_ioctl(fd, SIOCGIFFLAGS, &ifr)) != RC_OK) + return rc; + uint32_t if_flags = ifr.ifr_flags; + + if ((rc = if_ioctl(fd, SIOCGIFHWADDR, &ifr)) != RC_OK) + return rc; + uint8_t mac[6]; + memcpy(mac, &ifr.ifr_hwaddr, sizeof(mac)); + + struct ethtool_cmd cmd; + ifr.ifr_data = (void *)&cmd; + cmd.cmd = ETHTOOL_GSET; /* "Get settings" */ + uint32_t if_speed = 0; + if ((rc = if_ioctl(fd, SIOCETHTOOL, &ifr)) == RC_OK) + if_speed = ethtool_cmd_speed(&cmd); + + if (!(fp = fopen("/proc/net/dev", "r"))) + return RC_ERR_MISC; + + if (!fgets(line, sizeof(line), fp)) /* ignore first line */ + logx(LOG_ERR, "Cannot parse /proc/net/dev"); + if (!fgets(line, sizeof(line), fp)) + logx(LOG_ERR, "Cannot parse /proc/net/dev"); - /* apply values to table */ - int32_t if_index; - uint32_t if_flags; - struct dm_bin hwaddr; - uint8_t *mac; - char macstr[20]; - uint32_t if_speed; - DM2_AVPGRP grp; uint64_t rec_pkt = 0, rec_oct = 0, rec_err = 0, rec_drop = 0; uint64_t snd_pkt = 0, snd_oct = 0, snd_err = 0, snd_drop = 0; - ticks_t rt_now = ticks(); - if (dm_expect_int32_type(&answer, AVP_INT32, VP_TRAVELPING, &if_index) != RC_OK - || dm_expect_uint32_type(&answer, AVP_UINT32, VP_TRAVELPING, &if_flags) != RC_OK - || dm_expect_bin(&answer, AVP_BINARY, VP_TRAVELPING, &hwaddr) != RC_OK - || dm_expect_uint32_type(&answer, AVP_UINT32, VP_TRAVELPING, &if_speed) != RC_OK - || dm_expect_object(&answer, &grp) != RC_OK - || dm_expect_uint64_type(&grp, AVP_UINT64, VP_TRAVELPING, &rec_oct) != RC_OK - || dm_expect_uint64_type(&grp, AVP_UINT64, VP_TRAVELPING, &rec_pkt) != RC_OK - || dm_expect_uint64_type(&grp, AVP_UINT64, VP_TRAVELPING, &rec_err) != RC_OK - || dm_expect_uint64_type(&grp, AVP_UINT64, VP_TRAVELPING, &rec_drop) != RC_OK - || dm_expect_uint64_type(&grp, AVP_UINT64, VP_TRAVELPING, &snd_oct) != RC_OK - || dm_expect_uint64_type(&grp, AVP_UINT64, VP_TRAVELPING, &snd_pkt) != RC_OK - || dm_expect_uint64_type(&grp, AVP_UINT64, VP_TRAVELPING, &snd_err) != RC_OK - || dm_expect_uint64_type(&grp, AVP_UINT64, VP_TRAVELPING, &snd_drop) != RC_OK - || dm_expect_group_end(&grp) != RC_OK) - return; + while (!feof(fp)) { + char device[32]; - printf("if_flags: %08x\n", if_flags); + scan_count = fscanf(fp, " %32[^:]:%"PRIu64" %"PRIu64" %"PRIu64" %"PRIu64" %*u %*u %*u %*u %"PRIu64" %"PRIu64" %"PRIu64" %"PRIu64" %*u %*u %*s", + device, + &rec_oct, &rec_pkt, &rec_err, &rec_drop, + &snd_oct, &snd_pkt, &snd_err, &snd_drop); + if (scan_count == 9 && strcmp(dev, device) == 0) + break; + } + fclose(fp); if (dm_get_ticks_by_id(tbl, field_ocpe__interfaces_state__interface_lastchange) == 0) dm_set_ticks_by_id(tbl, field_ocpe__interfaces_state__interface_lastchange , rt_now); @@ -1696,7 +2015,6 @@ static void update_interface_state(struct dm_value_table *tbl) dm_set_enum_by_id(tbl, field_ocpe__interfaces_state__interface_operstatus , (if_flags & IFF_UP) ? field_ocpe__interfaces_state__interface_operstatus_up : field_ocpe__interfaces_state__interface_operstatus_down); - mac = hwaddr.data; snprintf(macstr, sizeof(macstr), "%02x:%02x:%02x:%02x:%02x:%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); dm_set_string_by_id(tbl, field_ocpe__interfaces_state__interface_physaddress , macstr); @@ -1723,14 +2041,47 @@ static void update_interface_state(struct dm_value_table *tbl) dm_set_uint_by_id(stats, field_ocpe__interfaces_state__interface__statistics_outdiscards, snd_drop); dm_set_uint_by_id(stats, field_ocpe__interfaces_state__interface__statistics_outerrors, snd_err); + /* read IP's from NL */ + + int ifindex; + struct nl_sock *socket = nl_socket_alloc(); + struct nl_cache *link_cache; + struct nl_cache *addr_cache; + struct nl_cache *neigh_cache; + struct rtnl_link *link; + struct rtnl_addr *addr_filter = NULL; + struct rtnl_neigh *neigh_filter = NULL; + int forward; + uint32_t mtu; + + if (nl_connect(socket, NETLINK_ROUTE) < 0) + return RC_ERR_MISC; + + if (rtnl_link_alloc_cache(socket, AF_UNSPEC, &link_cache) < 0 + || rtnl_addr_alloc_cache(socket, &addr_cache) < 0 + || rtnl_neigh_alloc_cache(socket, &neigh_cache) < 0) { + nl_socket_free(socket); + return RC_ERR_ALLOC; + } + + rc = RC_OK; + + link = rtnl_link_get_by_name(link_cache, dev); + ifindex = rtnl_link_get_ifindex(link); + mtu = rtnl_link_get_mtu(link); + if (mtu == 0 || mtu > 65535) + mtu = 65535; + + addr_filter = rtnl_addr_alloc(); + rtnl_addr_set_ifindex(addr_filter, ifindex); + + snprintf(line, sizeof(line), "/proc/sys/net/ipv4/conf/%s/forwarding", dev); + sys_scan(line, "%u", &forward); + logx(LOG_DEBUG, "IPv4 Forward: %d", forward); + char buffer[MAX_PARAM_NAME_LEN]; dm_selector sel; - dm_id if_id; - struct dm_instance_node *ipn; struct dm_value_table *iftbl; - DM2_AVPGRP ipiface; - uint8_t forward; - uint32_t mtu; /* IPv4 Interface */ @@ -1739,16 +2090,10 @@ static void update_interface_state(struct dm_value_table *tbl) sel[4] = 0; dm_sel2name(sel, buffer, sizeof(buffer)); - printf("interface: %s\n", buffer); + logx(LOG_DEBUG, "interface: %s", buffer); if (!(iftbl = dm_get_table_by_selector(sel))) - return; - - if (dm_expect_object(&answer, &ipiface) != RC_OK - || dm_expect_uint8_type(&ipiface, AVP_BOOL, VP_TRAVELPING, &forward) != RC_OK - || dm_expect_uint32_type(&ipiface, AVP_UINT32, VP_TRAVELPING, &mtu) != RC_OK) - return; - + return RC_ERR_MISC; dm_set_bool_by_id(iftbl, field_ocpe__interfaces_state__interface__ipv4_forwarding, forward); dm_set_uint_by_id(iftbl, field_ocpe__interfaces_state__interface__ipv4_mtu, mtu); @@ -1758,49 +2103,14 @@ static void update_interface_state(struct dm_value_table *tbl) sel[5] = 0; dm_sel2name(sel, buffer, sizeof(buffer)); - printf("interface: %s\n", buffer); + logx(LOG_DEBUG, "interface: %s", buffer); dm_del_table_by_selector(sel); dm_add_table_by_selector(sel); - if (dm_expect_object(&ipiface, &grp) != RC_OK) - return; - - printf("IPV4 Group\n"); - - if_id = 1; - while (dm_expect_group_end(&grp) != RC_OK) { - DM2_AVPGRP addr; - int family; - struct in_addr iaddr; - uint8_t prefix_len; - uint8_t origin; - uint8_t status; - - printf("IPV4 Addr\n"); - - if (dm_expect_object(&grp, &addr) != RC_OK - || dm_expect_address_type(&addr, AVP_ADDRESS, VP_TRAVELPING, &family, &iaddr, sizeof(iaddr)) != RC_OK - || dm_expect_uint8_type(&addr, AVP_UINT8, VP_TRAVELPING, &prefix_len) != RC_OK - || dm_expect_uint8_type(&addr, AVP_ENUM, VP_TRAVELPING, &origin) != RC_OK - || dm_expect_uint8_type(&addr, AVP_ENUM, VP_TRAVELPING, &status) != RC_OK - || dm_expect_group_end(&addr) != RC_OK) - return; - - printf("IPV4 Addr #1\n"); - - if (!(ipn = dm_add_instance_by_selector(sel, &if_id))) - return; - printf("IPV4 Addr %d\n", if_id); - - dm_set_ipv4_by_id(DM_TABLE(ipn->table), field_ocpe__interfaces_state__interface__ipv4__address_ip, iaddr); - dm_set_uint_by_id(DM_TABLE(ipn->table), field_ocpe__interfaces_state__interface__ipv4__address_prefixlength, prefix_len); - dm_set_enum_by_id(DM_TABLE(ipn->table), field_ocpe__interfaces_state__interface__ipv4__address_origin, origin); + rtnl_addr_set_family(addr_filter, AF_INET); - update_instance_node_index(ipn); - - if_id++; - } + nl_cache_foreach_filter(addr_cache, (struct nl_object *) addr_filter, update_addr_state_ip4, sel); /* IPv4 Neighbor */ @@ -1808,53 +2118,17 @@ static void update_interface_state(struct dm_value_table *tbl) sel[5] = 0; dm_sel2name(sel, buffer, sizeof(buffer)); - printf("interface: %s\n", buffer); + logx(LOG_DEBUG, "interface: %s", buffer); dm_del_table_by_selector(sel); dm_add_table_by_selector(sel); - if (dm_expect_object(&ipiface, &grp) != RC_OK) - return; - - printf("IPV4 Neighbor Group\n"); - - if_id = 1; - while (dm_expect_group_end(&grp) != RC_OK) { - DM2_AVPGRP addr; - int family; - struct in_addr dst; - char *lladdr; - uint8_t origin; - uint8_t is_router; - - printf("IPV4 Neighbor\n"); - - if (dm_expect_object(&grp, &addr) != RC_OK - || dm_expect_address_type(&addr, AVP_ADDRESS, VP_TRAVELPING, &family, &dst, sizeof(dst)) != RC_OK - || dm_expect_string_type(&addr, AVP_STRING, VP_TRAVELPING, &lladdr) != RC_OK - || dm_expect_uint8_type(&addr, AVP_ENUM, VP_TRAVELPING, &origin) != RC_OK - || dm_expect_uint8_type(&addr, AVP_BOOL, VP_TRAVELPING, &is_router) != RC_OK - || dm_expect_group_end(&addr) != RC_OK) - return; - - printf("IPV4 Neighbor #1\n"); - - if (!(ipn = dm_add_instance_by_selector(sel, &if_id))) - return; - - dm_set_ipv4_by_id(DM_TABLE(ipn->table), field_ocpe__interfaces_state__interface__ipv4__neighbor_ip, dst); - dm_set_string_by_id(DM_TABLE(ipn->table), field_ocpe__interfaces_state__interface__ipv4__neighbor_linklayeraddress, lladdr); - dm_set_enum_by_id(DM_TABLE(ipn->table), field_ocpe__interfaces_state__interface__ipv4__neighbor_origin, origin); - - update_instance_node_index(ipn); + neigh_filter = rtnl_neigh_alloc(); + rtnl_neigh_set_ifindex(neigh_filter, ifindex); - printf("IPV4 Neighbor %d\n", if_id); + rtnl_neigh_set_family(neigh_filter, AF_INET); - if_id++; - } - - if (dm_expect_group_end(&ipiface) != RC_OK) - return; + nl_cache_foreach_filter(neigh_cache, (struct nl_object *) neigh_filter, update_neigh_state_ip4, sel); /* IPv6 Interface */ @@ -1863,15 +2137,14 @@ static void update_interface_state(struct dm_value_table *tbl) sel[4] = 0; dm_sel2name(sel, buffer, sizeof(buffer)); - printf("interface: %s\n", buffer); + logx(LOG_DEBUG, "interface: %s", buffer); if (!(iftbl = dm_get_table_by_selector(sel))) - return; + return RC_ERR_MISC; - if (dm_expect_object(&answer, &ipiface) != RC_OK - || dm_expect_uint8_type(&ipiface, AVP_BOOL, VP_TRAVELPING, &forward) != RC_OK - || dm_expect_uint32_type(&ipiface, AVP_UINT32, VP_TRAVELPING, &mtu) != RC_OK) - return; + snprintf(line, sizeof(line), "/proc/sys/net/ipv6/conf/%s/forwarding", dev); + sys_scan(line, "%u", &forward); + logx(LOG_DEBUG, "IPv6 Forward: %d", forward); dm_set_bool_by_id(iftbl, field_ocpe__interfaces_state__interface__ipv6_forwarding, forward); dm_set_uint_by_id(iftbl, field_ocpe__interfaces_state__interface__ipv6_mtu, mtu); @@ -1882,50 +2155,14 @@ static void update_interface_state(struct dm_value_table *tbl) sel[5] = 0; dm_sel2name(sel, buffer, sizeof(buffer)); - printf("interface: %s\n", buffer); + logx(LOG_DEBUG, "interface: %s", buffer); dm_del_table_by_selector(sel); dm_add_table_by_selector(sel); - if (dm_expect_object(&ipiface, &grp) != RC_OK) - return; - - printf("IPV6 Group\n"); - - if_id = 1; - while (dm_expect_group_end(&grp) != RC_OK) { - DM2_AVPGRP addr; - int family; - struct in6_addr iaddr; - uint8_t prefix_len; - uint8_t origin; - uint8_t status; - - printf("IPV6 Addr\n"); - - if (dm_expect_object(&grp, &addr) != RC_OK - || dm_expect_address_type(&addr, AVP_ADDRESS, VP_TRAVELPING, &family, (struct in_addr *)&iaddr, sizeof(iaddr)) != RC_OK - || dm_expect_uint8_type(&addr, AVP_UINT8, VP_TRAVELPING, &prefix_len) != RC_OK - || dm_expect_uint8_type(&addr, AVP_ENUM, VP_TRAVELPING, &origin) != RC_OK - || dm_expect_uint8_type(&addr, AVP_ENUM, VP_TRAVELPING, &status) != RC_OK - || dm_expect_group_end(&addr) != RC_OK) - return; - - printf("IPV6 Addr #1\n"); - - if (!(ipn = dm_add_instance_by_selector(sel, &if_id))) - return; - printf("IPV6 Addr %d\n", if_id); - - dm_set_ipv6_by_id(DM_TABLE(ipn->table), field_ocpe__interfaces_state__interface__ipv6__address_ip, iaddr); - dm_set_uint_by_id(DM_TABLE(ipn->table), field_ocpe__interfaces_state__interface__ipv6__address_prefixlength, prefix_len); - dm_set_enum_by_id(DM_TABLE(ipn->table), field_ocpe__interfaces_state__interface__ipv6__address_origin, origin); - dm_set_enum_by_id(DM_TABLE(ipn->table), field_ocpe__interfaces_state__interface__ipv6__address_status, status); - - update_instance_node_index(ipn); + rtnl_addr_set_family(addr_filter, AF_INET6); - if_id++; - } + nl_cache_foreach_filter(addr_cache, (struct nl_object *) addr_filter, update_addr_state_ip6, sel); /* IPv6 Neighbor */ @@ -1933,54 +2170,23 @@ static void update_interface_state(struct dm_value_table *tbl) sel[5] = 0; dm_sel2name(sel, buffer, sizeof(buffer)); - printf("interface: %s\n", buffer); + logx(LOG_DEBUG, "interface: %s", buffer); dm_del_table_by_selector(sel); dm_add_table_by_selector(sel); - if (dm_expect_object(&ipiface, &grp) != RC_OK) - return; - - printf("IPV6 Neighbor Group\n"); - - if_id = 1; - while (dm_expect_group_end(&grp) != RC_OK) { - DM2_AVPGRP addr; - int family; - struct in6_addr dst; - char *lladdr; - uint8_t origin; - uint8_t is_router; - - printf("IPV6 Neighbor\n"); - - if (dm_expect_object(&grp, &addr) != RC_OK - || dm_expect_address_type(&addr, AVP_ADDRESS, VP_TRAVELPING, &family, (struct in_addr *)&dst, sizeof(dst)) != RC_OK - || dm_expect_string_type(&addr, AVP_STRING, VP_TRAVELPING, &lladdr) != RC_OK - || dm_expect_uint8_type(&addr, AVP_ENUM, VP_TRAVELPING, &origin) != RC_OK - || dm_expect_uint8_type(&addr, AVP_BOOL, VP_TRAVELPING, &is_router) != RC_OK - || dm_expect_group_end(&addr) != RC_OK) - return; - - printf("IPV6 Neighbor #1\n"); - - if (!(ipn = dm_add_instance_by_selector(sel, &if_id))) - return; - - dm_set_ipv6_by_id(DM_TABLE(ipn->table), field_ocpe__interfaces_state__interface__ipv6__neighbor_ip, dst); - dm_set_string_by_id(DM_TABLE(ipn->table), field_ocpe__interfaces_state__interface__ipv6__neighbor_linklayeraddress, lladdr); - dm_set_enum_by_id(DM_TABLE(ipn->table), field_ocpe__interfaces_state__interface__ipv6__neighbor_origin, origin); - dm_set_bool_by_id(DM_TABLE(ipn->table), field_ocpe__interfaces_state__interface__ipv6__neighbor_isrouter, is_router); - - update_instance_node_index(ipn); + rtnl_neigh_set_family(neigh_filter, AF_INET6); - printf("IPV6 Neighbor %d\n", if_id); + nl_cache_foreach_filter(neigh_cache, (struct nl_object *) neigh_filter, update_neigh_state_ip6, sel); - if_id++; - } + nl_cache_free(neigh_cache); + nl_cache_free(addr_cache); + nl_cache_free(link_cache); + if (addr_filter) rtnl_addr_put(addr_filter); + if (neigh_filter) rtnl_neigh_put(neigh_filter); + nl_socket_free(socket); - if (dm_expect_group_end(&ipiface) != RC_OK) - return; + return rc; } int set_ocpe__system_state__clock_currentdatetime(struct dm_value_table *tbl __attribute__((unused)), @@ -2045,6 +2251,9 @@ DM_VALUE __get_ocpe__interfaces_state__interface(struct dm_value_table *tbl, dm_ int notify_enabled_old = notify_enabled; notify_enabled = 0; + /* + * FIXME: Perhaps we no longer need to restrict the frequency of update_interface_state()- + */ printf("get_ocpe__interfaces_state__interface: %s: %s, %s, %" PRItick "\n", e->key, buf1, buf2, rt_now - last); if (rt_now - last > 10) update_interface_state(tbl); From 0b764a8cf85df8a2a67dc357e8f82b55ce4dac0d Mon Sep 17 00:00:00 2001 From: Robin Haberkorn Date: Fri, 20 May 2022 15:09:03 +0500 Subject: [PATCH 23/35] added --with-config-version to specify the version that configs are serialized with * This used to be the SVN revision or was a manually managed constant tied to the mand sources. * This is actually a necessity for using Lua upgrade scripts as the CFG_VERSION was hardcoded to 1. This no longer made any sense since the data models are managed outside of the mand source tree. * Theoretically, every Yang scheme could have its own version, but that would have to be stored somewhere. A single revision is still practically sufficient since while it cannot have a globally significant meaning, it can be managed across all firmware variants/products of a given Linux distribution. * The Lua scripts from lua/ are no longer installed since they still refer to the old TR069 data model and Travelping-specific products. The files are kept for reference (for the time being). * Useful improvments to the Lua function hooks (TODO): * The current/new versions could be stored into global variables instead of passing "arguments" to the script. * There should be an arbitrary number of scripts for "event", so you can install scripts on a per-feature basis instead of matching against firmware names and the like. This cannot easily be emulated in Lua since we would need a way of listing directories (not part of the C or Lua runtimes). --- Makefile.am | 2 +- configure.ac | 6 ++++++ mand/dm_cfgversion.h | 2 -- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Makefile.am b/Makefile.am index 977760d..34962bc 100644 --- a/Makefile.am +++ b/Makefile.am @@ -8,7 +8,7 @@ AM_CFLAGS = -DWITH_SOAPDEFS_H EXTRA_DIST = doxygen.cfg -SUBDIRS = utils libdmconfig libdmconfig/tests mand lua +SUBDIRS = utils libdmconfig libdmconfig/tests mand LIBTOOL_DEPS = @LIBTOOL_DEPS@ libtool: $(LIBTOOL_DEPS) diff --git a/configure.ac b/configure.ac index 04deee0..6dc568e 100644 --- a/configure.ac +++ b/configure.ac @@ -121,6 +121,12 @@ dnl AC_MSG_PART(Options) +AC_ARG_WITH(config-version, + [AC_HELP_STRING([--with-config-version=], + [Version of serialized configs])], + [cfg_version=$withval], [cfg_version=1]) +AC_DEFINE_UNQUOTED(CFG_VERSION, $cfg_version, [Version of serialized configs]) + dnl libdmconfig related options AC_ARG_ENABLE(libdmconfig-debug, diff --git a/mand/dm_cfgversion.h b/mand/dm_cfgversion.h index 4e4eded..740fa39 100644 --- a/mand/dm_cfgversion.h +++ b/mand/dm_cfgversion.h @@ -5,8 +5,6 @@ #ifndef __HAVE_DM_CFGVERSION_H #define __HAVE_DM_CFGVERSION_H -#define CFG_VERSION 1 - int dm_get_cfg_version(void); void dm_set_cfg_version(int v); From 324e06ed3039bf1fe9b3ae60d8263047eb75e340 Mon Sep 17 00:00:00 2001 From: Robin Haberkorn Date: Wed, 15 Jun 2022 18:41:50 +0200 Subject: [PATCH 24/35] fixed the dm.list() and dm.set() commands of the Lua interface * dm.list() still only supports the old-school non-recursive API. This may have to be changed but for the time being, it's sufficient for what we do in fncPostVersionCheck.lua. * There are some remnants of "configure" sessions in the Lua interface. I don't know what their initial motivation was but they can probably be removed altogether. --- mand/dm_lua.h | 9 ++++----- mand/dm_luaif.c | 31 ++++++++++++------------------- 2 files changed, 16 insertions(+), 24 deletions(-) diff --git a/mand/dm_lua.h b/mand/dm_lua.h index 60c7143..e484fb1 100644 --- a/mand/dm_lua.h +++ b/mand/dm_lua.h @@ -74,11 +74,10 @@ lua_register_type_constants(lua_State *L) {"t_binary", AVP_BINARY}, {"t_unknown", AVP_UNKNOWN}, -#if 0 - {"n_object", NODE_OBJECT}, /* list result node types */ - {"n_table", NODE_TABLE}, - {"n_parameter", NODE_PARAMETER}, -#endif + {"t_object", AVP_OBJECT}, /* list result node types */ + {"t_table", AVP_TABLE}, + {"t_element", AVP_ELEMENT}, + {NULL, 0} }; diff --git a/mand/dm_luaif.c b/mand/dm_luaif.c index ca8d06d..2d30ad8 100644 --- a/mand/dm_luaif.c +++ b/mand/dm_luaif.c @@ -573,12 +573,11 @@ luaif_set_cb(void *data, const dm_selector sel __attribute__((unused)), DM_parity_update(*st); cache_add(sel, "", elem, base, st, new_value, 0, NULL); } else { - new_value.flags |= DV_UPDATED; - DM_parity_update(new_value); - r = dm_overwrite_any_value_by_selector(sel, elem->type, - new_value, -1); - } #endif + new_value.flags |= DV_UPDATED; + DM_parity_update(new_value); + r = dm_overwrite_any_value_by_selector(sel, elem->type, + new_value, -1); return r; } @@ -1056,15 +1055,10 @@ LUA_SIG(retrieve_enums) return 2; } -/* - * FIXME: update so it is API-compatible with dmconfig's new recursive list - */ static int -luaif_list_cb(void *data __attribute__((unused)), CB_type type __attribute__((unused)), dm_id id __attribute__((unused)), - const struct dm_element *elem __attribute__((unused)), - const DM_VALUE value __attribute__((unused))) +luaif_list_cb(void *data, CB_type type, dm_id id, + const struct dm_element *elem, const DM_VALUE value __attribute__((unused))) { -#if 0 lua_State *L = data; int cnt; @@ -1086,16 +1080,17 @@ luaif_list_cb(void *data __attribute__((unused)), CB_type type __attribute__((un case CB_object_instance_end: return 1; case CB_object_start: - node_type = NODE_TABLE; + node_type = AVP_TABLE; break; case CB_object_instance_start: snprintf(numbuf, sizeof(numbuf), "%hu", id); node_name = numbuf; + /* fall through */ case CB_table_start: - node_type = NODE_OBJECT; + node_type = AVP_OBJECT; break; case CB_element: - node_type = NODE_PARAMETER; + node_type = AVP_ELEMENT; break; default: return 0; @@ -1110,7 +1105,7 @@ luaif_list_cb(void *data __attribute__((unused)), CB_type type __attribute__((un lua_setfield(L, -2, "type"); switch (node_type) { - case NODE_PARAMETER: { + case AVP_ELEMENT: { uint32_t type; switch (elem->type) { @@ -1168,15 +1163,13 @@ luaif_list_cb(void *data __attribute__((unused)), CB_type type __attribute__((un break; } - case NODE_OBJECT: + case AVP_OBJECT: lua_pushinteger(L, elem->u.t.table->size); lua_setfield(L, -2, "size"); } lua_settable(L, -3); lua_pushinteger(L, cnt + 1); /* update array index counter */ - -#endif return 1; } From 4e565241ad79954b9c851c2370afc6530be48b56 Mon Sep 17 00:00:00 2001 From: Robin Haberkorn Date: Wed, 22 Jun 2022 23:03:46 +0200 Subject: [PATCH 25/35] fixed serious memory leaks of DM2_REQUEST stubs * Objects were passed into dm_enqueue(), apparently with the intention that it takes ownership of the object. dm_enqueue() only reparented DM2_REQUEST::packet though. * Effectively, we leaked a few bytes for every dmconfig request sent. --- libdmconfig/dmcontext.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libdmconfig/dmcontext.c b/libdmconfig/dmcontext.c index ecc3fb2..89a8afb 100644 --- a/libdmconfig/dmcontext.c +++ b/libdmconfig/dmcontext.c @@ -163,7 +163,9 @@ dm_context_shutdown(DMCONTEXT *sock, DMCONFIG_EVENT event) } -/** @private put a packet into the send queue +/** @private put a packet into the send queue + * + * @param req The request to enqueue. The ownership of the request is passed to the function. */ uint32_t dm_enqueue(DMCONTEXT *socket, DM2_REQUEST *req, int flags, DMRESULT_CB cb, void *data) { @@ -212,6 +214,7 @@ uint32_t dm_enqueue(DMCONTEXT *socket, DM2_REQUEST *req, int flags, DMRESULT_CB ev_timer_again(socket->ev, &socket->writeCtx.timer_ev); } + talloc_free(req); return RC_OK; } From a0a423814e5e317dcd802527fae8a671458c2a4a Mon Sep 17 00:00:00 2001 From: Robin Haberkorn Date: Sun, 2 Oct 2022 05:16:24 +0300 Subject: [PATCH 26/35] added interfaces-state.interface.ipv[46].gateway-ip array for querying the currently active gateways * especially useful when DHCP-assigned * this analyzes all default routes * In the future, we might want to support the configuration and querying of all routes. There probably is an existing IETF model for that. --- mand/dm_dmconfig.c | 97 +++++++++++++++++++++++++++++++++++- yang/specs/opencpe-mand.yang | 25 ++++++++++ 2 files changed, 121 insertions(+), 1 deletion(-) diff --git a/mand/dm_dmconfig.c b/mand/dm_dmconfig.c index 15c05d4..04a88be 100644 --- a/mand/dm_dmconfig.c +++ b/mand/dm_dmconfig.c @@ -42,6 +42,7 @@ #include #include +#include #include #include @@ -1925,6 +1926,60 @@ update_addr_state_ip6(struct nl_object *obj, void *data) update_instance_node_index(ipn); } +static void +update_route_state_nh_ipv4(struct rtnl_nexthop *nh, void *data) +{ + dm_selector *sel = data; + + struct nl_addr *addr = rtnl_route_nh_get_gateway(nh); + if (!addr) + return; + + dm_id id = 0; + struct dm_instance_node *ipn = dm_add_instance_by_selector(*sel, &id); + if (!ipn) + return; + + struct in_addr dst; + memcpy(&dst.s_addr, nl_addr_get_binary_addr(addr), sizeof(dst.s_addr)); + /* interfaces.interface.ipv4.gateway-ip[id] */ + dm_set_ipv4_by_id(DM_TABLE(ipn->table), 1, dst); +} + +static void +update_route_state_ip4(struct nl_object *obj, void *data) +{ + struct rtnl_route *route = (struct rtnl_route *)obj; + rtnl_route_foreach_nexthop(route, update_route_state_nh_ipv4, data); +} + +static void +update_route_state_nh_ip6(struct rtnl_nexthop *nh, void *data) +{ + dm_selector *sel = data; + + struct nl_addr *addr = rtnl_route_nh_get_gateway(nh); + if (!addr) + return; + + dm_id id = 0; + struct dm_instance_node *ipn = dm_add_instance_by_selector(*sel, &id); + if (!ipn) + return; + + struct in6_addr dst; + memcpy(dst.s6_addr, nl_addr_get_binary_addr(addr), sizeof(dst.s6_addr)); + /* interfaces.interface.ipv6.gateway-ip[id] */ + dm_set_ipv6_by_id(DM_TABLE(ipn->table), 1, dst); +} + +static void +update_route_state_ip6(struct nl_object *obj, void *data) +{ + struct rtnl_route *route = (struct rtnl_route *)obj; + rtnl_route_foreach_nexthop(route, update_route_state_nh_ip6, data); +} + static uint32_t update_interface_state(struct dm_value_table *tbl) { /* @@ -2048,9 +2103,11 @@ static uint32_t update_interface_state(struct dm_value_table *tbl) struct nl_cache *link_cache; struct nl_cache *addr_cache; struct nl_cache *neigh_cache; + struct nl_cache *route_cache; struct rtnl_link *link; struct rtnl_addr *addr_filter = NULL; struct rtnl_neigh *neigh_filter = NULL; + struct rtnl_route *route_filter = NULL; int forward; uint32_t mtu; @@ -2059,7 +2116,8 @@ static uint32_t update_interface_state(struct dm_value_table *tbl) if (rtnl_link_alloc_cache(socket, AF_UNSPEC, &link_cache) < 0 || rtnl_addr_alloc_cache(socket, &addr_cache) < 0 - || rtnl_neigh_alloc_cache(socket, &neigh_cache) < 0) { + || rtnl_neigh_alloc_cache(socket, &neigh_cache) < 0 + || rtnl_route_alloc_cache(socket, AF_UNSPEC, 0, &route_cache) < 0) { nl_socket_free(socket); return RC_ERR_ALLOC; } @@ -2130,6 +2188,28 @@ static uint32_t update_interface_state(struct dm_value_table *tbl) nl_cache_foreach_filter(neigh_cache, (struct nl_object *) neigh_filter, update_neigh_state_ip4, sel); + /* IPv4 Routes/Gateway */ + + sel[4] = field_ocpe__interfaces_state__interface__ipv4_gatewayip; + sel[5] = 0; + + route_filter = rtnl_route_alloc(); + + struct rtnl_nexthop *nh = rtnl_route_nh_alloc(); + rtnl_route_nh_set_ifindex(nh, ifindex); + /* This apparently passes ownership of nh */ + rtnl_route_add_nexthop(route_filter, nh); + + struct nl_addr *route_dst = nl_addr_build(AF_INET, NULL, 0); + if (!route_dst) + return RC_ERR_MISC; + rtnl_route_set_dst(route_filter, route_dst); + + rtnl_route_set_family(route_filter, AF_INET); + + dm_del_table_by_selector(sel); + nl_cache_foreach_filter(route_cache, (struct nl_object *)route_filter, update_route_state_ip4, sel); + /* IPv6 Interface */ dm_selcpy(sel, tbl->id); @@ -2179,11 +2259,26 @@ static uint32_t update_interface_state(struct dm_value_table *tbl) nl_cache_foreach_filter(neigh_cache, (struct nl_object *) neigh_filter, update_neigh_state_ip6, sel); + /* IPv6 Routes/Gateway */ + + sel[4] = field_ocpe__interfaces_state__interface__ipv6_gatewayip; + sel[5] = 0; + + nl_addr_set_family(route_dst, AF_INET6); + rtnl_route_set_family(route_filter, AF_INET6); + + dm_del_table_by_selector(sel); + nl_cache_foreach_filter(route_cache, (struct nl_object *)route_filter, update_route_state_ip6, sel); + + nl_addr_put(route_dst); + + nl_cache_free(route_cache); nl_cache_free(neigh_cache); nl_cache_free(addr_cache); nl_cache_free(link_cache); if (addr_filter) rtnl_addr_put(addr_filter); if (neigh_filter) rtnl_neigh_put(neigh_filter); + if (route_filter) rtnl_route_put(route_filter); nl_socket_free(socket); return rc; diff --git a/yang/specs/opencpe-mand.yang b/yang/specs/opencpe-mand.yang index b559260..66908dc 100644 --- a/yang/specs/opencpe-mand.yang +++ b/yang/specs/opencpe-mand.yang @@ -8,6 +8,12 @@ module opencpe-mand { prefix "if"; revision-date 2013-07-04; } + import ietf-ip { + prefix ip; + } + import ietf-inet-types { + prefix inet; + } organization "Travelping GmbH"; @@ -26,4 +32,23 @@ module opencpe-mand { } } + /* + * FIXME: We could map all routes into the data model instead + * of only the default gateways. + */ + augment "/if:interfaces-state/if:interface/ip:ipv4" { + leaf-list gateway-ip { + type inet:ipv4-address-no-zone; + description + "A list of gateway addresses."; + } + } + + augment "/if:interfaces-state/if:interface/ip:ipv6" { + leaf-list gateway-ip { + type inet:ipv6-address-no-zone; + description + "A list of gateway addresses."; + } + } } From 2d357cef42e7c9acfbd5861ed9fff292b84d1150 Mon Sep 17 00:00:00 2001 From: Robin Haberkorn Date: Sat, 10 Dec 2022 20:54:08 +0300 Subject: [PATCH 27/35] fixed memory leak in update_interface_state() --- mand/dm_dmconfig.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/mand/dm_dmconfig.c b/mand/dm_dmconfig.c index 04a88be..51e40b4 100644 --- a/mand/dm_dmconfig.c +++ b/mand/dm_dmconfig.c @@ -2276,9 +2276,10 @@ static uint32_t update_interface_state(struct dm_value_table *tbl) nl_cache_free(neigh_cache); nl_cache_free(addr_cache); nl_cache_free(link_cache); - if (addr_filter) rtnl_addr_put(addr_filter); - if (neigh_filter) rtnl_neigh_put(neigh_filter); - if (route_filter) rtnl_route_put(route_filter); + rtnl_link_put(link); + rtnl_addr_put(addr_filter); + rtnl_neigh_put(neigh_filter); + rtnl_route_put(route_filter); nl_socket_free(socket); return rc; From 8641bd1e0986768a6fa041364680099b17b10b14 Mon Sep 17 00:00:00 2001 From: Robin Haberkorn Date: Sun, 11 Dec 2022 01:41:45 +0300 Subject: [PATCH 28/35] fixed file descriptor leak and error handling in update_interface_state() --- mand/dm_dmconfig.c | 90 +++++++++++++++++++++++++++++----------------- 1 file changed, 57 insertions(+), 33 deletions(-) diff --git a/mand/dm_dmconfig.c b/mand/dm_dmconfig.c index 51e40b4..7a1f3e4 100644 --- a/mand/dm_dmconfig.c +++ b/mand/dm_dmconfig.c @@ -2016,18 +2016,24 @@ static uint32_t update_interface_state(struct dm_value_table *tbl) strncpy(ifr.ifr_name, dev, IFNAMSIZ-1); ifr.ifr_name[IFNAMSIZ-1] = '\0'; - if ((rc = if_ioctl(fd, SIOCGIFINDEX, &ifr)) != RC_OK) + if ((rc = if_ioctl(fd, SIOCGIFINDEX, &ifr)) != RC_OK) { + close(fd); return rc; + } if (ifr.ifr_ifindex == 0) ifr.ifr_ifindex = 2147483647; int32_t if_index = ifr.ifr_ifindex; - if ((rc = if_ioctl(fd, SIOCGIFFLAGS, &ifr)) != RC_OK) + if ((rc = if_ioctl(fd, SIOCGIFFLAGS, &ifr)) != RC_OK) { + close(fd); return rc; + } uint32_t if_flags = ifr.ifr_flags; - if ((rc = if_ioctl(fd, SIOCGIFHWADDR, &ifr)) != RC_OK) - return rc; + if ((rc = if_ioctl(fd, SIOCGIFHWADDR, &ifr)) != RC_OK) { + close(fd); + return rc; + } uint8_t mac[6]; memcpy(mac, &ifr.ifr_hwaddr, sizeof(mac)); @@ -2038,6 +2044,8 @@ static uint32_t update_interface_state(struct dm_value_table *tbl) if ((rc = if_ioctl(fd, SIOCETHTOOL, &ifr)) == RC_OK) if_speed = ethtool_cmd_speed(&cmd); + close(fd); + if (!(fp = fopen("/proc/net/dev", "r"))) return RC_ERR_MISC; @@ -2100,35 +2108,36 @@ static uint32_t update_interface_state(struct dm_value_table *tbl) int ifindex; struct nl_sock *socket = nl_socket_alloc(); - struct nl_cache *link_cache; - struct nl_cache *addr_cache; - struct nl_cache *neigh_cache; - struct nl_cache *route_cache; - struct rtnl_link *link; - struct rtnl_addr *addr_filter = NULL; + struct nl_cache *link_cache = NULL; + struct nl_cache *addr_cache = NULL; + struct nl_cache *neigh_cache = NULL; + struct nl_cache *route_cache = NULL; struct rtnl_neigh *neigh_filter = NULL; struct rtnl_route *route_filter = NULL; + struct rtnl_addr *addr_filter = NULL; + struct nl_addr *route_dst = NULL; int forward; uint32_t mtu; - if (nl_connect(socket, NETLINK_ROUTE) < 0) - return RC_ERR_MISC; + if (nl_connect(socket, NETLINK_ROUTE) < 0) { + rc = RC_ERR_MISC; + goto cleanup; + } if (rtnl_link_alloc_cache(socket, AF_UNSPEC, &link_cache) < 0 || rtnl_addr_alloc_cache(socket, &addr_cache) < 0 || rtnl_neigh_alloc_cache(socket, &neigh_cache) < 0 || rtnl_route_alloc_cache(socket, AF_UNSPEC, 0, &route_cache) < 0) { - nl_socket_free(socket); - return RC_ERR_ALLOC; + rc = RC_ERR_ALLOC; + goto cleanup; } - rc = RC_OK; - - link = rtnl_link_get_by_name(link_cache, dev); + struct rtnl_link *link = rtnl_link_get_by_name(link_cache, dev); ifindex = rtnl_link_get_ifindex(link); mtu = rtnl_link_get_mtu(link); if (mtu == 0 || mtu > 65535) mtu = 65535; + rtnl_link_put(link); addr_filter = rtnl_addr_alloc(); rtnl_addr_set_ifindex(addr_filter, ifindex); @@ -2150,8 +2159,10 @@ static uint32_t update_interface_state(struct dm_value_table *tbl) dm_sel2name(sel, buffer, sizeof(buffer)); logx(LOG_DEBUG, "interface: %s", buffer); - if (!(iftbl = dm_get_table_by_selector(sel))) - return RC_ERR_MISC; + if (!(iftbl = dm_get_table_by_selector(sel))) { + rc = RC_ERR_MISC; + goto cleanup; + } dm_set_bool_by_id(iftbl, field_ocpe__interfaces_state__interface__ipv4_forwarding, forward); dm_set_uint_by_id(iftbl, field_ocpe__interfaces_state__interface__ipv4_mtu, mtu); @@ -2200,9 +2211,11 @@ static uint32_t update_interface_state(struct dm_value_table *tbl) /* This apparently passes ownership of nh */ rtnl_route_add_nexthop(route_filter, nh); - struct nl_addr *route_dst = nl_addr_build(AF_INET, NULL, 0); - if (!route_dst) - return RC_ERR_MISC; + route_dst = nl_addr_build(AF_INET, NULL, 0); + if (!route_dst) { + rc = RC_ERR_MISC; + goto cleanup; + } rtnl_route_set_dst(route_filter, route_dst); rtnl_route_set_family(route_filter, AF_INET); @@ -2219,8 +2232,10 @@ static uint32_t update_interface_state(struct dm_value_table *tbl) dm_sel2name(sel, buffer, sizeof(buffer)); logx(LOG_DEBUG, "interface: %s", buffer); - if (!(iftbl = dm_get_table_by_selector(sel))) - return RC_ERR_MISC; + if (!(iftbl = dm_get_table_by_selector(sel))) { + rc = RC_ERR_MISC; + goto cleanup; + } snprintf(line, sizeof(line), "/proc/sys/net/ipv6/conf/%s/forwarding", dev); sys_scan(line, "%u", &forward); @@ -2270,16 +2285,25 @@ static uint32_t update_interface_state(struct dm_value_table *tbl) dm_del_table_by_selector(sel); nl_cache_foreach_filter(route_cache, (struct nl_object *)route_filter, update_route_state_ip6, sel); - nl_addr_put(route_dst); + rc = RC_OK; - nl_cache_free(route_cache); - nl_cache_free(neigh_cache); - nl_cache_free(addr_cache); - nl_cache_free(link_cache); - rtnl_link_put(link); - rtnl_addr_put(addr_filter); - rtnl_neigh_put(neigh_filter); - rtnl_route_put(route_filter); +cleanup: + if (route_dst) + nl_addr_put(route_dst); + if (link_cache) + nl_cache_free(link_cache); + if (route_cache) + nl_cache_free(route_cache); + if (neigh_cache) + nl_cache_free(neigh_cache); + if (addr_cache) + nl_cache_free(addr_cache); + if (addr_filter) + rtnl_addr_put(addr_filter); + if (neigh_filter) + rtnl_neigh_put(neigh_filter); + if (route_filter) + rtnl_route_put(route_filter); nl_socket_free(socket); return rc; From 61c79ace778e3d05202df66c3b1b639040fa931c Mon Sep 17 00:00:00 2001 From: Robin Haberkorn Date: Sun, 11 Dec 2022 23:22:41 +0300 Subject: [PATCH 29/35] ported the event_notify_sample.c to the new libdmconfig API --- .gitignore | 1 + README.md | 3 +- libdmconfig/tests/Makefile.am | 5 +- libdmconfig/tests/event_notify_sample.c | 264 ++++++++++++++---------- 4 files changed, 164 insertions(+), 109 deletions(-) diff --git a/.gitignore b/.gitignore index 78785fb..1de6f6c 100644 --- a/.gitignore +++ b/.gitignore @@ -18,6 +18,7 @@ mand/p_table_stubs.c libdmconfig/codes.h libdmconfig/extensivedump.out libdmconfig/tests/event_client_sample +libdmconfig/tests/event_notify_sample # lua build files lua/fncAdminPasswd.out diff --git a/README.md b/README.md index 2a52b07..f40b4d0 100644 --- a/README.md +++ b/README.md @@ -78,7 +78,8 @@ libdmconfig API documentation can be build with doxygen: For how to use this API, refer to the C and Lua samples in libdmconfig/tests. **NOTE:** Currently only the [event_client_sample.c](libdmconfig/tests/event_client_sample.c) -example builds and reflects the current state of the API. +and [event_notify_sample.c](libdmconfig/tests/event_notify_sample.c) +examples build and reflect the current state of the API. # Adding new YANG modules diff --git a/libdmconfig/tests/Makefile.am b/libdmconfig/tests/Makefile.am index 5a18e1a..2e02674 100644 --- a/libdmconfig/tests/Makefile.am +++ b/libdmconfig/tests/Makefile.am @@ -8,8 +8,7 @@ AM_CFLAGS = -g -std=gnu99 \ -I$(top_srcdir) -check_PROGRAMS = event_client_sample -#check_PROGRAMS = client_sample polling_sample dm_sample \ -# event_client_sample event_notify_sample +check_PROGRAMS = event_client_sample event_notify_sample +#check_PROGRAMS = client_sample polling_sample dm_sample LDADD = ../libdmconfig.la ../libdm_dmclient.la diff --git a/libdmconfig/tests/event_notify_sample.c b/libdmconfig/tests/event_notify_sample.c index 72a48b1..48380c1 100644 --- a/libdmconfig/tests/event_notify_sample.c +++ b/libdmconfig/tests/event_notify_sample.c @@ -2,194 +2,248 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * libdmconfig client lib sample: uses the nonblocking libev-based API + * for notifications + */ + #define _GNU_SOURCE #include #include +#include #include +#include -#include -#include +#include +#include #include +#include +#include -#define CB_ERR(...) { \ +#define CB_ERR(...) do { \ fprintf(stderr, __VA_ARGS__); \ return; \ -} - -void activeNotification(DMCONFIG_EVENT event, DMCONTEXT *dmCtx, void *user_data __attribute__((unused)), DM_AVPGRP *grp); +} while (0) -void terminatedSession(DMCONFIG_EVENT event, DMCONTEXT *dmCtx __attribute__((unused)), void *user_data __attribute__((unused)), uint32_t answer_rc, DM_AVPGRP *answer_grp __attribute__((unused))); -void unsubscribedNotify(DMCONFIG_EVENT event, DMCONTEXT *dmCtx, void *user_data __attribute__((unused)), uint32_t answer_rc, DM_AVPGRP *answer_grp __attribute__((unused))); -void registeredNotify(DMCONFIG_EVENT event, DMCONTEXT *dmCtx __attribute__((unused)), void *user_data __attribute__((unused)), uint32_t answer_rc, DM_AVPGRP *answer_grp __attribute__((unused))); -void subscribedNotify(DMCONFIG_EVENT event, DMCONTEXT *dmCtx, void *user_data __attribute__((unused)), uint32_t answer_rc, DM_AVPGRP *answer_grp __attribute__((unused))); -void sessionStarted(DMCONFIG_EVENT event, DMCONTEXT *dmCtx, void *user_data __attribute__((unused)), uint32_t answer_rc, DM_AVPGRP *answer_grp); -void socketConnected(DMCONFIG_EVENT event, DMCONTEXT *dmCtx, void *userdata __attribute__((unused))); -int main(int argc __attribute__((unused)), char **argv __attribute__((unused))); +/** changing this parameter triggers the shutdown process */ +#define SHUTDOWN_PARAMETER "system-state.platform.machine" - /* changing this parameter triggers the shutdown process */ -#define SHUTDOWN_PARAMETER "InternetGatewayDevice.DeviceInfo.ModelName" - -void -terminatedSession(DMCONFIG_EVENT event, DMCONTEXT *dmCtx __attribute__((unused)), void *user_data __attribute__((unused)), uint32_t answer_rc, DM_AVPGRP *answer_grp __attribute__((unused))) +static void +request_cb(DMCONTEXT *socket, DM_PACKET *pkt, DM2_AVPGRP *grp, void *userdata __attribute__((unused))) { - if (event != DMCONFIG_ANSWER_READY || answer_rc) - CB_ERR("Couldn't terminate session.\n"); + DMC_REQUEST req; + DM2_REQUEST *answer = NULL; + + req.hop2hop = dm_hop2hop_id(pkt); + req.end2end = dm_end2end_id(pkt); + req.code = dm_packet_code(pkt); + + printf("request_cb: received %s", + dm_packet_flags(pkt) & CMD_FLAG_REQUEST ? "request" : "answer"); +#ifdef LIBDMCONFIG_DEBUG + dump_dm_packet(pkt); +#endif + + if ((rpc_dmclient_switch(socket, &req, grp, &answer)) == RC_ERR_ALLOC) { + dm_context_shutdown(socket, DMCONFIG_OK); + dm_context_release(socket); + ev_break(socket->ev, EVBREAK_ALL); + return; + } - printf("Session terminated.\n" - "Returning...\n"); + if (answer) + dm_enqueue(socket, answer, REPLY, NULL, NULL); } void -unsubscribedNotify(DMCONFIG_EVENT event, DMCONTEXT *dmCtx, void *user_data __attribute__((unused)), uint32_t answer_rc, DM_AVPGRP *answer_grp __attribute__((unused))) +unsubscribedNotify(DMCONTEXT *dmCtx, DMCONFIG_EVENT event, DM2_AVPGRP *answer_grp, void *user_data __attribute__((unused))) { - if (event != DMCONFIG_ANSWER_READY || answer_rc) + uint32_t rc; + + if (event != DMCONFIG_ANSWER_READY) + CB_ERR("Couldn't unsubscribe notifications.\n"); + + uint32_t answer_rc; + rc = dm_expect_uint32_type(answer_grp, AVP_RC, VP_TRAVELPING, &answer_rc); + if (rc != RC_OK || answer_rc != RC_OK) CB_ERR("Couldn't unsubscribe notifications.\n"); printf("Unsubscribed notifications.\n"); - if (dm_register_end_session(dmCtx, terminatedSession, NULL)) + rc = rpc_endsession_async(dmCtx); + if (rc != RC_OK) CB_ERR("Couldn't register END SESSION request.\n"); printf("END SESSION request registered.\n"); } -void -activeNotification(DMCONFIG_EVENT event, DMCONTEXT *dmCtx, void *user_data __attribute__((unused)), DM_AVPGRP *grp) +uint32_t +rpc_client_active_notify(void *ctx, DM2_AVPGRP *obj) { - uint32_t type; - - if (event != DMCONFIG_ANSWER_READY) - CB_ERR("Error while retrieving an active notification.\n"); + DMCONTEXT *dmCtx = ctx; + uint32_t rc; do { - DM_AVPGRP *notify; - - if (dm_decode_notifications(grp, &type, ¬ify)) - CB_ERR("Couldn't decode active notifications\n") - - if (type == NOTIFY_PARAMETER_CHANGED) { - char *path, *str; - - uint32_t data_type, vendor_id; - uint8_t flags; - void *data; - size_t len; - - if (dm_decode_parameter_changed(notify, &path, &data_type)) - CB_ERR("Couldn't decode active notifications\n"); - - if (dm_avpgrp_get_avp(notify, &data_type, &flags, &vendor_id, &data, &len) || - dm_decode_unknown_as_string(data_type, data, len, &str)) { - free(path); - CB_ERR("Couldn't decode active notifications\n"); + DM2_AVPGRP grp; + uint32_t type; + char *path; + + if ((rc = dm_expect_object(obj, &grp)) != RC_OK + || (rc = dm_expect_uint32_type(&grp, AVP_NOTIFY_TYPE, VP_TRAVELPING, &type)) != RC_OK + || (rc = dm_expect_string_type(&grp, AVP_PATH, VP_TRAVELPING, &path)) != RC_OK) { + fprintf(stderr, "Couldn't decode active notifications, rc=%d\n", rc); + return rc; + } + + switch (type) { + case NOTIFY_INSTANCE_CREATED: + printf("Notification: Instance \"%s\" created\n", path); + break; + + case NOTIFY_INSTANCE_DELETED: + printf("Notification: Instance \"%s\" deleted\n", path); + break; + + case NOTIFY_PARAMETER_CHANGED: { + struct dm2_avp avp; + char *str; + + if ((rc = dm_expect_uint32_type(&grp, AVP_TYPE, VP_TRAVELPING, &type)) != RC_OK + || (rc = dm_expect_value(&grp, &avp)) != RC_OK + || (rc = dm_decode_unknown_as_string(type, avp.data, avp.size, &str)) != RC_OK) { + fprintf(stderr, "Couldn't decode parameter changed notifications, rc=%d\n", rc); + return rc; } - printf("\nNotification: Parameter \"%s\" changed to \"%s\"\n", path, str); + printf("Notification: Parameter \"%s\" changed to \"%s\"\n", path, str); if (!strcmp(path, SHUTDOWN_PARAMETER)) { - if (dm_register_unsubscribe_notify(dmCtx, unsubscribedNotify, NULL)) - CB_ERR("Couldn't register UNSUBSCRIBE NOTIFY request.\n"); - printf("UNSUBSCRIBE NOTIFY request registered.\n"); + /* + * NOTE: You don't strictly need an unsubscribe before terminating the session! + */ + rc = rpc_unsubscribe_notify_async(dmCtx, unsubscribedNotify, NULL); + if (rc != RC_OK) { + fprintf(stderr, "Couldn't register UNSUBSCRIBE NOTIFY request.\n"); + return rc; + } + printf("Notification unsubscription request registered.\n"); } - free(path); - free(str); - } else if (type != NOTIFY_NOTHING) - printf("\nNotification: Warning, unknown type\n"); + break; + } + default: + printf("Notification: Warning, unknown type: %d\n", type); + break; + } + } while ((rc = dm_expect_end(obj)) != RC_OK); - dm_grp_free(notify); - } while (type != NOTIFY_NOTHING); + return dm_expect_end(obj); } void -registeredNotify(DMCONFIG_EVENT event, DMCONTEXT *dmCtx __attribute__((unused)), void *user_data __attribute__((unused)), uint32_t answer_rc, DM_AVPGRP *answer_grp __attribute__((unused))) +registeredNotify(DMCONTEXT *dmCtx __attribute__((unused)), DMCONFIG_EVENT event, DM2_AVPGRP *answer_grp, void *user_data __attribute__((unused))) { - if (event != DMCONFIG_ANSWER_READY || answer_rc) + uint32_t rc; + + if (event != DMCONFIG_ANSWER_READY) + CB_ERR("Couldn't register parameter notifications.\n"); + + uint32_t answer_rc; + rc = dm_expect_uint32_type(answer_grp, AVP_RC, VP_TRAVELPING, &answer_rc); + if (rc != RC_OK || answer_rc != RC_OK) CB_ERR("Couldn't register parameter notifications.\n"); printf("Parameter notifications registered.\n"); - printf("\nThe sample program shuts down when the following parameter is modified: " - SHUTDOWN_PARAMETER "\n\n"); + printf("\nThe sample program shuts down when the following parameter is modified: %s\n\n", + SHUTDOWN_PARAMETER); } void -subscribedNotify(DMCONFIG_EVENT event, DMCONTEXT *dmCtx, void *user_data __attribute__((unused)), uint32_t answer_rc, DM_AVPGRP *answer_grp __attribute__((unused))) +subscribedNotify(DMCONTEXT *dmCtx, DMCONFIG_EVENT event, DM2_AVPGRP *answer_grp, void *user_data __attribute__((unused))) { - if (event != DMCONFIG_ANSWER_READY || answer_rc) + uint32_t rc; + + if (event != DMCONFIG_ANSWER_READY) + CB_ERR("Couldn't subscribe notifications.\n"); + + uint32_t answer_rc; + rc = dm_expect_uint32_type(answer_grp, AVP_RC, VP_TRAVELPING, &answer_rc); + if (rc != RC_OK || answer_rc != RC_OK) CB_ERR("Couldn't subscribe notifications.\n"); printf("Subscribed notifications.\n"); - if (dm_register_recursive_param_notify(dmCtx, 1 /* active notification */, "", registeredNotify, NULL)) + rc = rpc_recursive_param_notify_async(dmCtx, NOTIFY_ACTIVE, "", registeredNotify, NULL); + if (rc != RC_OK) CB_ERR("Couldn't register RECURSIVE PARAM NOTIFY request.\n"); printf("RECURSIVE PARAM NOTIFY request registered.\n"); } -void -sessionStarted(DMCONFIG_EVENT event, DMCONTEXT *dmCtx, void *user_data __attribute__((unused)), uint32_t answer_rc, DM_AVPGRP *answer_grp) +static void +sessionStarted(DMCONTEXT *dmCtx, DMCONFIG_EVENT event, DM2_AVPGRP *answer_grp, void *user_data __attribute__((unused))) { - if (event != DMCONFIG_ANSWER_READY || answer_rc) + uint32_t rc; + + if (event != DMCONFIG_ANSWER_READY) CB_ERR("Couldn't start session.\n"); - printf("Session started.\n"); - if (dm_decode_start_session(dmCtx, answer_grp)) - CB_ERR("Couldn't decode sessionid.\n"); + uint32_t answer_rc; + rc = dm_expect_uint32_type(answer_grp, AVP_RC, VP_TRAVELPING, &answer_rc); + if (rc != RC_OK || answer_rc != RC_OK) + CB_ERR("Couldn't start session.\n"); - if (dm_register_subscribe_notify(dmCtx, activeNotification, NULL, subscribedNotify, NULL)) + printf("Session started. Session Id: %" PRIu32 "\n", dmCtx->sessionid); + + rc = rpc_subscribe_notify_async(dmCtx, subscribedNotify, NULL); + if (rc != RC_OK) CB_ERR("Couldn't register SUBSCRIBE NOTIFY request.\n"); printf("Notification subscription request registered.\n"); } -void +static uint32_t socketConnected(DMCONFIG_EVENT event, DMCONTEXT *dmCtx, void *userdata __attribute__((unused))) { - struct timeval timeout; - - if (event != DMCONFIG_CONNECTED) - CB_ERR("Connecting socket unsuccessful.\n"); + if (event != DMCONFIG_CONNECTED) { + fprintf(stderr, "Connecting socket unsuccessful.\n"); + return RC_ERR_MISC; + } printf("Socket connected.\n"); - memset(&timeout, 0, sizeof(struct timeval)); - - if (dm_register_start_session(dmCtx, CMD_FLAG_READWRITE, &timeout, NULL, sessionStarted, NULL)) - CB_ERR("Couldn't register start session request.\n"); + if (rpc_startsession_async(dmCtx, CMD_FLAG_READWRITE, 0, sessionStarted, NULL)) { + fprintf(stderr, "Couldn't register start session request.\n"); + return RC_ERR_MISC; + } printf("Start session request registered.\n"); + + return RC_OK; } int main(int argc __attribute__((unused)), char **argv __attribute__((unused))) { - DMCONTEXT dmCtx; - struct event_base *base; + struct ev_loop *loop = EV_DEFAULT; - if (!(base = event_init())) { - fprintf(stderr, "Couldn't initialize event base.\n"); - return 0; - } - printf("Event base initialized.\n"); - - dm_context_init(&dmCtx, base); + DMCONTEXT *dmCtx; + uint32_t rc; - if (dm_create_socket(&dmCtx, AF_INET)) { - fprintf(stderr, "Couldn't create socket.\n"); - event_base_free(base); + dmCtx = dm_context_new(); + if (!dmCtx) { + fprintf(stderr, "Couldn't create dmconfig context.\n"); return 0; } - printf("Socket created.\n"); - if (dm_register_connect_callback(&dmCtx, AF_INET, socketConnected, NULL)) { + dm_context_init(dmCtx, EV_A, AF_INET, NULL, socketConnected, request_cb); + + rc = dm_connect_async(dmCtx); + if (rc != RC_OK) { fprintf(stderr, "Couldn't register connect callback or connecting unsuccessful.\n"); - dm_shutdown_socket(&dmCtx); - event_base_free(base); + dm_context_shutdown(dmCtx, DMCONFIG_OK); return 0; } printf("Connect callback registered.\n"); - event_base_dispatch(dm_context_get_event_base(&dmCtx)); + ev_run(EV_A_ 0); - dm_shutdown_socket(&dmCtx); + dm_context_shutdown(dmCtx, DMCONFIG_OK); printf("Socket shut down.\n"); - event_base_free(base); - printf("Event base freed.\n"); return 0; } - From 63254ba31c77be4f2e9ff5b95f6257cc879043a3 Mon Sep 17 00:00:00 2001 From: Robin Haberkorn Date: Sun, 14 May 2023 20:45:28 +0300 Subject: [PATCH 30/35] deserialize the base config before running fncStartup.lua * This allows fncStartup.lua to access the database (eg. to generate parts of the base config) and also makes sure it can make use of already loaded base config. --- mand/mand.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mand/mand.c b/mand/mand.c index 6eb9f5a..f54d0cd 100644 --- a/mand/mand.c +++ b/mand/mand.c @@ -198,11 +198,11 @@ int main(int argc, char *argv[]) if (init_Lua_environment()) debug("(): Couldn't initialize Lua environment"); + dm_load_base_config(); + if (fp_Lua_function("fncStartup", 0)) debug("(): Error during Lua function execution"); - dm_load_base_config(); - printf("deserialize "DM_CONFIG"\n"); fin = fopen(DM_CONFIG, "r"); if (fin) { From ce0a9c557acd25b19f3c6652362f6b947ecee083 Mon Sep 17 00:00:00 2001 From: Robin Haberkorn Date: Fri, 12 Jan 2024 23:52:11 +0300 Subject: [PATCH 31/35] use talloc_total_size() for testing for libtalloc: will work with libusual as well --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 6dc568e..c3cfac2 100644 --- a/configure.ac +++ b/configure.ac @@ -100,7 +100,7 @@ AC_CHECK_LIB([lua], lua_callk, , [have_liblua=no], [-ldl -lm]) if test x$have_liblua = xno; then AC_CHECK_LIB([lua5.1], lua_call, , AC_MSG_ERROR(Required liblua missing), [-ldl -lm]) fi -AC_CHECK_LIB(talloc, talloc_named_const, , AC_MSG_ERROR(Required libtalloc missing) ) +AC_CHECK_LIB(talloc, talloc_total_size, , AC_MSG_ERROR(Required libtalloc missing) ) AC_CHECK_HEADERS([talloc.h talloc/talloc.h]) # Necessary to rertrieving the interface-state. From 25a16bde1d2ffd9c6c10c063c73af6cd75e8259a Mon Sep 17 00:00:00 2001 From: Robin Haberkorn Date: Sat, 13 Jan 2024 00:15:41 +0300 Subject: [PATCH 32/35] avoid `bool` as variable names, so that stdbool.h can be included * important for libusual-compatibility --- mand/dm_store.c | 4 ++-- mand/dm_store.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/mand/dm_store.c b/mand/dm_store.c index 9162647..dcf218f 100644 --- a/mand/dm_store.c +++ b/mand/dm_store.c @@ -1586,10 +1586,10 @@ int dm_compare_values(int type, DM_VALUE *a, DM_VALUE *b) * set methods */ -void dm_set_bool_by_id(struct dm_value_table *ift, dm_id id, char bool) +void dm_set_bool_by_id(struct dm_value_table *ift, dm_id id, char bool_val) { DM_parity_assert(ift->values[id - 1]); - set_DM_BOOL(ift->values[id - 1], bool); + set_DM_BOOL(ift->values[id - 1], bool_val); DM_parity_update(ift->values[id - 1]); __DM_NOTIFY_BY_ID(ift, id); } diff --git a/mand/dm_store.h b/mand/dm_store.h index 5843273..273ae23 100644 --- a/mand/dm_store.h +++ b/mand/dm_store.h @@ -431,9 +431,9 @@ char dm_get_bool_by_selector(const dm_selector sel) return DM_BOOL(dm_get_any_value_by_selector(sel, T_BOOL)); } -int dm_set_bool_by_selector(const dm_selector sel, char bool, int flags) +int dm_set_bool_by_selector(const dm_selector sel, char bool_val, int flags) { - return dm_set_any_value_by_selector(sel, T_BOOL, init_DM_BOOL(bool, flags)); + return dm_set_any_value_by_selector(sel, T_BOOL, init_DM_BOOL(bool_val, flags)); } char dm_get_bool_by_id(struct dm_value_table *ift, dm_id id) From 0e97a9d92ea97fe0559d58418d49347a521e55da Mon Sep 17 00:00:00 2001 From: Robin Haberkorn Date: Tue, 24 Sep 2024 01:08:37 +0200 Subject: [PATCH 33/35] removed unnecessary checks - they are treated as errors by modern versions of GCC --- mand/dm_notify.c | 6 ------ mand/dm_store.c | 3 --- 2 files changed, 9 deletions(-) diff --git a/mand/dm_notify.c b/mand/dm_notify.c index fa2ee41..ea4b2f7 100644 --- a/mand/dm_notify.c +++ b/mand/dm_notify.c @@ -61,9 +61,6 @@ static void reset_notify_element(const struct dm_table *kw, struct dm_value_tabl { const struct dm_element *elem; - if (!kw->table) - return; - elem = &kw->table[index]; switch(elem->type) { @@ -313,9 +310,6 @@ static void set_notify_slot_element(const struct dm_table *kw, struct dm_value_t { const struct dm_element *elem; - if (!kw->table) - return; - elem = &kw->table[index]; switch(elem->type) { diff --git a/mand/dm_store.c b/mand/dm_store.c index dcf218f..1095a75 100644 --- a/mand/dm_store.c +++ b/mand/dm_store.c @@ -1357,9 +1357,6 @@ static int update_flags_element(const struct dm_table *kw, struct dm_value_table const struct dm_element *elem; - if (!kw->table) - return 0; - elem = &kw->table[index]; ret = st->values[index].flags & (DV_UPDATED | DV_NOTIFY); From 29520c556eff8c5705595bd1951af90437eca5eb Mon Sep 17 00:00:00 2001 From: Robin Haberkorn Date: Wed, 16 Jul 2025 13:39:40 +0300 Subject: [PATCH 34/35] dm_deserialize: fixed deserialization of octal escapes (for `encoding="escaped"`) across block boundaries * string_unescape() assumed that all octal escapes are fully contained in the data it gets passed in. This however is not guaranteed since the character data handler (charElement()) could be invoked with any number of bytes by the SAX parser. If it gets passed in e.g. a single slash at the end of the string and the remainig 3 bytes only in the next invocation, the slash would be lost and the 3 octal digits would be deserialized verbatim. * Caused real-life data corruptions during repeated serializations and reboots. * The state necessary by string_unescape() is now part of struct XMLstate. --- mand/dm_deserialize.c | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/mand/dm_deserialize.c b/mand/dm_deserialize.c index 7d1f75f..f22dd5f 100644 --- a/mand/dm_deserialize.c +++ b/mand/dm_deserialize.c @@ -51,6 +51,11 @@ struct XMLstate { DM_VALUE *value; int flags; char *text; + /** state of string_unescape() */ + struct { + int in_c; + char c; + } unescape; struct dm_instance *inst; struct dm_instance_node *node; }; @@ -185,29 +190,27 @@ startElement(void *userData, const char *name, const char **atts) } } -static void string_unescape(char *text, const char *s, int len) +static void string_unescape(struct XMLstate *state, const char *s, int len) { - int in_c = 0; - char c = 0; - char *d = text + strlen(text); + char *d = state->text + strlen(state->text); while (len) { - if (!in_c) { + if (!state->unescape.in_c) { if (*s == '\\') { - in_c++; - c = '\0'; + state->unescape.in_c++; + state->unescape.c = '\0'; } else *d++ = *s; } else { if (*s >= '0' && *s <= '7') { - c = (c << 3) | (*s - '0'); - in_c++; + state->unescape.c = (state->unescape.c << 3) | (*s - '0'); + state->unescape.in_c++; } else /* abort decoding on error */ break; - if (in_c == 4) { - *d++ = c; - in_c = 0; + if (state->unescape.in_c == 4) { + *d++ = state->unescape.c; + state->unescape.in_c = 0; } } s++; @@ -230,7 +233,7 @@ charElement(void *userData, const XML_Char *s, int len) return; if (((*state)->flags & XML_ESCAPED) == XML_ESCAPED) - string_unescape((*state)->text, s, len); + string_unescape(*state, s, len); else strncat((*state)->text, s, len); } From 8cb1d9b6c80c0b8706ffbf8145cfa6ad7bfe27ce Mon Sep 17 00:00:00 2001 From: Robin Haberkorn Date: Mon, 29 Sep 2025 21:25:24 +0300 Subject: [PATCH 35/35] fixed reporting of interfaces-state.interface.X.phys-address It was reading two unrelated bytes from the beginning of struct sockaddr and in turn was cutting off the last two bytes of the actual MAC address. --- mand/dm_dmconfig.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mand/dm_dmconfig.c b/mand/dm_dmconfig.c index 7a1f3e4..ab28b22 100644 --- a/mand/dm_dmconfig.c +++ b/mand/dm_dmconfig.c @@ -2035,7 +2035,7 @@ static uint32_t update_interface_state(struct dm_value_table *tbl) return rc; } uint8_t mac[6]; - memcpy(mac, &ifr.ifr_hwaddr, sizeof(mac)); + memcpy(mac, ifr.ifr_hwaddr.sa_data, sizeof(mac)); struct ethtool_cmd cmd; ifr.ifr_data = (void *)&cmd;