diff --git a/.gitignore b/.gitignore index e5fe2fd..1de6f6c 100644 --- a/.gitignore +++ b/.gitignore @@ -17,6 +17,8 @@ mand/p_table_stubs.c # libdmconfig build files libdmconfig/codes.h libdmconfig/extensivedump.out +libdmconfig/tests/event_client_sample +libdmconfig/tests/event_notify_sample # lua build files lua/fncAdminPasswd.out @@ -50,7 +52,8 @@ stamp-h1 /build* # pyang plugin -OpenCPE.pyc +__pycache__ +*.pyc p_table* dm_action_* 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/README.md b/README.md index c9318c0..f40b4d0 100644 --- a/README.md +++ b/README.md @@ -39,10 +39,12 @@ aware and depend on particular entries in those models. - expat - libev - libtalloc -- lua 5.1 or 5.2 +- libnl and libnl-route +- lua 5.1 - 5.3 - xsltproc -- python -- pyang +- python3 +- pyang v1.7 +- python3-six ## Optional tools and libraries @@ -75,6 +77,10 @@ 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) +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 YANG is specified in [RFC 6020][1]. mand already contains several IETF YANG modules diff --git a/configure.ac b/configure.ac index 5afbcf1..c3cfac2 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) @@ -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 @@ -101,9 +100,14 @@ 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. +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) ) @@ -117,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/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 744d639..71ee770 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; @@ -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/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/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/libdmconfig/dmcontext.c b/libdmconfig/dmcontext.c index 791f378..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) { @@ -181,6 +183,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; @@ -211,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; } diff --git a/libdmconfig/tests/Makefile.am b/libdmconfig/tests/Makefile.am index d8d5e12..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 = client_sample polling_sample dm_sample \ - event_client_sample event_notify_sample - -LDADD = ../libdmconfig.la +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_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; } 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; } - 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 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_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); diff --git a/mand/dm_deserialize.c b/mand/dm_deserialize.c index 88a8bda..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; }; @@ -71,7 +76,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 +114,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; @@ -182,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; - 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++; @@ -227,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); } @@ -250,7 +256,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 +265,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 69fab5d..ab28b22 100644 --- a/mand/dm_dmconfig.c +++ b/mand/dm_dmconfig.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -36,6 +37,15 @@ #include #include + +#include +#include + +#include +#include +#include +#include + #include #include @@ -128,7 +138,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; @@ -167,7 +177,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 +191,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 @@ -403,7 +424,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 +691,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 +725,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 +754,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 +774,7 @@ dmconfig_set_array_cb(SOCKCONTEXT *ctx __attribute__((unused)), } } - return RC_OK; + return DM_OK; } static DM_RESULT @@ -791,15 +812,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 @@ -1547,42 +1567,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; @@ -1593,13 +1676,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; @@ -1610,10 +1728,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) @@ -1629,54 +1751,323 @@ 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; +} - if (!(ctx = find_role("-state"))) +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; - name = dm_get_string_by_id(tbl, field_ocpe__interfaces_state__interface_name); - printf("get_ocpe__interfaces_state__interface: %s\n", name); + 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; - 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); + 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 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; - } - /* apply values to table */ - int32_t if_index; - uint32_t if_flags; - struct dm_bin hwaddr; - uint8_t *mac; + 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) +{ + /* + * 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); + + 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); + char macstr[20]; - uint32_t if_speed; - DM2_AVPGRP grp; + ticks_t rt_now = ticks(); + + 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) { + 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) { + close(fd); + return rc; + } + uint32_t if_flags = ifr.ifr_flags; + + if ((rc = if_ioctl(fd, SIOCGIFHWADDR, &ifr)) != RC_OK) { + close(fd); + return rc; + } + uint8_t mac[6]; + memcpy(mac, ifr.ifr_hwaddr.sa_data, 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); + + close(fd); + + 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"); + 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); @@ -1687,11 +2078,10 @@ 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); - 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,28 +2090,65 @@ 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); + /* read IP's from NL */ + + int ifindex; + struct nl_sock *socket = nl_socket_alloc(); + 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) { + 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) { + rc = RC_ERR_ALLOC; + goto cleanup; + } + + 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); + + 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 */ @@ -1730,16 +2157,12 @@ static void update_interface_state(struct dm_value_table *tbl) sel[4] = 0; dm_sel2name(sel, buffer, sizeof(buffer)); - printf("interface: %s\n", 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; + logx(LOG_DEBUG, "interface: %s", buffer); + 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); @@ -1749,49 +2172,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"); + rtnl_addr_set_family(addr_filter, AF_INET); - 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); - - 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 */ @@ -1799,53 +2187,41 @@ 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; + neigh_filter = rtnl_neigh_alloc(); + rtnl_neigh_set_ifindex(neigh_filter, ifindex); - 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; + rtnl_neigh_set_family(neigh_filter, AF_INET); - printf("IPV4 Neighbor #1\n"); + nl_cache_foreach_filter(neigh_cache, (struct nl_object *) neigh_filter, update_neigh_state_ip4, sel); - if (!(ipn = dm_add_instance_by_selector(sel, &if_id))) - return; + /* IPv4 Routes/Gateway */ - 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); + sel[4] = field_ocpe__interfaces_state__interface__ipv4_gatewayip; + sel[5] = 0; - update_instance_node_index(ipn); + route_filter = rtnl_route_alloc(); - printf("IPV4 Neighbor %d\n", if_id); + 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); - if_id++; + 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); - if (dm_expect_group_end(&ipiface) != RC_OK) - return; + 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 */ @@ -1854,15 +2230,16 @@ 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 (!(iftbl = dm_get_table_by_selector(sel))) { + rc = RC_ERR_MISC; + goto cleanup; + } - 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); @@ -1873,50 +2250,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); + rtnl_addr_set_family(addr_filter, AF_INET6); - update_instance_node_index(ipn); - - if_id++; - } + nl_cache_foreach_filter(addr_cache, (struct nl_object *) addr_filter, update_addr_state_ip6, sel); /* IPv6 Neighbor */ @@ -1924,54 +2265,48 @@ 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"); + rtnl_neigh_set_family(neigh_filter, AF_INET6); - if (!(ipn = dm_add_instance_by_selector(sel, &if_id))) - return; + nl_cache_foreach_filter(neigh_cache, (struct nl_object *) neigh_filter, update_neigh_state_ip6, sel); - 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); + /* IPv6 Routes/Gateway */ - update_instance_node_index(ipn); + sel[4] = field_ocpe__interfaces_state__interface__ipv6_gatewayip; + sel[5] = 0; - printf("IPV6 Neighbor %d\n", if_id); + nl_addr_set_family(route_dst, AF_INET6); + rtnl_route_set_family(route_filter, AF_INET6); - if_id++; - } + dm_del_table_by_selector(sel); + nl_cache_foreach_filter(route_cache, (struct nl_object *)route_filter, update_route_state_ip6, sel); + + rc = RC_OK; + +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); - 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)), @@ -2027,11 +2362,26 @@ 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; + + /* + * 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); 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_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 b714c03..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; } @@ -649,6 +648,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 +673,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 +689,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 +705,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 +721,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 +741,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 +761,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 +778,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 +799,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 +819,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 +837,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 +854,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 +895,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; @@ -1043,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; @@ -1073,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; @@ -1097,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) { @@ -1155,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; } @@ -1341,7 +1347,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 +1364,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); diff --git a/mand/dm_notify.c b/mand/dm_notify.c index 7111540..ea4b2f7 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 @@ -59,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) { @@ -182,6 +181,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); @@ -308,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) { @@ -367,7 +366,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 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_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/dm_store.c b/mand/dm_store.c index ad87904..1095a75 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; @@ -1360,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); @@ -1589,10 +1583,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) 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; } 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; diff --git a/mand/mand.c b/mand/mand.c index 3a44cce..f54d0cd 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 { @@ -145,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 @@ -195,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) { @@ -209,19 +212,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(); 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: 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"; } 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."; + } + } }