/******************************************************************** * FUNCTION do_show_cli (sub-mode of local RPC) * * show CLI parms * * INPUTS: * server_cb == server control block to use *********************************************************************/ static void do_show_cli (server_cb_t *server_cb) { session_cb_t *session_cb = server_cb->cur_session_cb; val_value_t *mgrset; logfn_t logfn; boolean imode = interactive_mode(); if (imode) { logfn = log_stdout; } else { logfn = log_write; } mgrset = get_mgr_cli_valset(); /* CLI Parameters */ if (mgrset && val_child_cnt(mgrset)) { (*logfn)("\nCLI Variables\n"); val_dump_value_max(mgrset, 0,session_cb->defindent, (imode) ? DUMP_VAL_STDOUT : DUMP_VAL_LOG, session_cb->display_mode, FALSE, FALSE); (*logfn)("\n"); } else { (*logfn)("\nNo CLI variables\n"); } } /* do_show_cli */
/******************************************************************** * FUNCTION yangcli_notification_handler * * matches callback template mgr_not_cbfn_t * * INPUTS: * scb == session receiving RPC reply * msg == notification msg that was parsed * consumed == address of return consumed message flag * * OUTPUTS: * *consumed == TRUE if msg has been consumed so * it will not be freed by mgr_not_dispatch * == FALSE if msg has been not consumed so * it will be freed by mgr_not_dispatch *********************************************************************/ void yangcli_notification_handler (ses_cb_t *scb, mgr_not_msg_t *msg, boolean *consumed) { assert(scb && "scb is NULL!"); assert(msg && "msg is NULL!"); assert(consumed && "consumed is NULL!"); *consumed = FALSE; mgr_scb_t *mgrcb = scb->mgrcb; server_cb_t *server_cb = get_cur_server_cb(); session_cb_t *save_session_cb = server_cb->cur_session_cb; session_cb_t *session_cb = NULL; if (mgrcb) { session_cb = mgrcb->session_cb; } if (session_cb == NULL) { log_error("\nError: session no longer valid; dropping notification"); return; } const xmlChar *sesname = get_session_name(session_cb); if (session_cb != save_session_cb) { set_cur_session_cb(server_cb, session_cb); } /* check the contents of the notification */ if (msg && msg->notification) { /* dispatch this event to any handler registered for * this event; !!! not session-specific !!! */ uint32 retcnt = dispatch_notif_event(session_cb, msg); /* display only unhandled notifications, and only if * the session is configured to show them */ log_debug_t loglevel = log_get_debug_level(); log_debug_t base_loglevel = loglevel + 1; if (loglevel == LOG_DEBUG_INFO) { base_loglevel++; } if (retcnt == 0 && session_cb->echo_notifs && base_loglevel >= session_cb->echo_notif_loglevel) { gl_normal_io(server_cb->cli_gl); if (loglevel >= session_cb->echo_notif_loglevel) { log_write("\n\nIncoming notification for session %u [%s]:", scb->sid, sesname); val_dump_value_max(msg->notification, 0, session_cb->defindent, DUMP_VAL_LOG, session_cb->display_mode, FALSE, FALSE); log_write_append("\n\n"); } else if (msg->eventType) { log_write("\n\nIncoming <%s> notification for session " "%u [%s]\n\n", msg->eventType->name, scb->sid, sesname); } } /* store msg in the session notification log */ dlq_enque(msg, &session_cb->notificationQ); *consumed = TRUE; } if (session_cb != save_session_cb) { set_cur_session_cb(server_cb, save_session_cb); } } /* yangcli_notification_handler */
/******************************************************************** * FUNCTION send_discard_changes_pdu_to_server * * Send a <discard-changes> operation to the server * * INPUTS: * server_cb == server control block to use * * RETURNS: * status *********************************************************************/ status_t send_discard_changes_pdu_to_server (server_cb_t *server_cb) { obj_template_t *rpc; mgr_rpc_req_t *req; val_value_t *reqdata; ses_cb_t *scb; status_t res; xmlns_id_t obj_nsid; req = NULL; reqdata = NULL; res = NO_ERR; if (LOGDEBUG) { log_debug("\nSending <discard-changes> request"); } rpc = ncx_find_object(get_netconf_mod(server_cb), NCX_EL_DISCARD_CHANGES); if (!rpc) { return SET_ERROR(ERR_NCX_DEF_NOT_FOUND); } obj_nsid = obj_get_nsid(rpc); /* construct a method node */ reqdata = xml_val_new_flag(obj_get_name(rpc), obj_nsid); if (!reqdata) { log_error("\nError allocating a new RPC request"); return ERR_INTERNAL_MEM; } scb = mgr_ses_get_scb(server_cb->mysid); if (!scb) { res = SET_ERROR(ERR_INTERNAL_PTR); } else { req = mgr_rpc_new_request(scb); if (!req) { res = ERR_INTERNAL_MEM; log_error("\nError allocating a new RPC request"); } else { req->data = reqdata; req->rpc = rpc; req->timeout = server_cb->timeout; } } /* if all OK, send the RPC request */ if (res == NO_ERR) { if (LOGDEBUG2) { log_debug2("\nabout to send RPC request with reqdata:"); val_dump_value_max(reqdata, 0, server_cb->defindent, DUMP_VAL_LOG, server_cb->display_mode, FALSE, FALSE); } /* the request will be stored if this returns NO_ERR */ res = mgr_rpc_send_request(scb, req, yangcli_reply_handler); if (res == NO_ERR) { server_cb->command_mode = CMD_MODE_AUTODISCARD; } } /* cleanup and set next state */ if (res != NO_ERR) { if (req) { mgr_rpc_free_request(req); } else if (reqdata) { val_free_value(reqdata); } } else { server_cb->state = MGR_IO_ST_CONN_RPYWAIT; } return res; } /* send_discard_changes_pdu_to_server */
/******************************************************************** * FUNCTION send_lock_pdu_to_server * * Send a <lock> or <unlock> operation to the server * * INPUTS: * server_cb == server control block to use * lockcb == lock control block to use within server_cb * islock == TRUE for lock; FALSE for unlock * * RETURNS: * status *********************************************************************/ static status_t send_lock_pdu_to_server (server_cb_t *server_cb, lock_cb_t *lockcb, boolean islock) { obj_template_t *rpc, *input; mgr_rpc_req_t *req; val_value_t *reqdata, *targetval, *parmval; ses_cb_t *scb; status_t res; xmlns_id_t obj_nsid; req = NULL; reqdata = NULL; res = NO_ERR; if (LOGDEBUG) { log_debug("\nSending <%s> request", (islock) ? NCX_EL_LOCK : NCX_EL_UNLOCK); } if (islock) { rpc = ncx_find_object(get_netconf_mod(server_cb), NCX_EL_LOCK); } else { rpc = ncx_find_object(get_netconf_mod(server_cb), NCX_EL_UNLOCK); } if (!rpc) { return SET_ERROR(ERR_NCX_DEF_NOT_FOUND); } obj_nsid = obj_get_nsid(rpc); /* get the 'input' section container */ input = obj_find_child(rpc, NULL, YANG_K_INPUT); if (!input) { return SET_ERROR(ERR_NCX_DEF_NOT_FOUND); } /* construct a method + parameter tree */ reqdata = xml_val_new_struct(obj_get_name(rpc), obj_nsid); if (!reqdata) { log_error("\nError allocating a new RPC request"); return ERR_INTERNAL_MEM; } /* set the [un]lock/input/target node XML namespace */ targetval = xml_val_new_struct(NCX_EL_TARGET, obj_nsid); if (!targetval) { log_error("\nError allocating a new RPC request"); val_free_value(reqdata); return ERR_INTERNAL_MEM; } else { val_add_child(targetval, reqdata); } parmval = xml_val_new_flag(lockcb->config_name, obj_nsid); if (!parmval) { val_free_value(reqdata); return ERR_INTERNAL_MEM; } else { val_add_child(parmval, targetval); } scb = mgr_ses_get_scb(server_cb->mysid); if (!scb) { res = SET_ERROR(ERR_INTERNAL_PTR); } else { req = mgr_rpc_new_request(scb); if (!req) { res = ERR_INTERNAL_MEM; log_error("\nError allocating a new RPC request"); } else { req->data = reqdata; req->rpc = rpc; req->timeout = server_cb->timeout; } } /* if all OK, send the RPC request */ if (res == NO_ERR) { if (LOGDEBUG2) { log_debug2("\nabout to send RPC request with reqdata:"); val_dump_value_max(reqdata, 0, server_cb->defindent, DUMP_VAL_LOG, server_cb->display_mode, FALSE, FALSE); } /* the request will be stored if this returns NO_ERR */ res = mgr_rpc_send_request(scb, req, yangcli_reply_handler); if (res == NO_ERR) { if (islock) { lockcb->lock_state = LOCK_STATE_REQUEST_SENT; } else { lockcb->lock_state = LOCK_STATE_RELEASE_SENT; } (void)uptime(&lockcb->last_msg_time); server_cb->locks_cur_cfg = lockcb->config_id; } } /* cleanup and set next state */ if (res != NO_ERR) { if (req) { mgr_rpc_free_request(req); } else if (reqdata) { val_free_value(reqdata); } } else { server_cb->state = MGR_IO_ST_CONN_RPYWAIT; } return res; } /* send_lock_pdu_to_server */
/******************************************************************** * FUNCTION agt_init2 * * Initialize the Server Library * The agt_profile is set and the object database is * ready to have YANG modules loaded * * RPC and data node callbacks should be installed * after the module is loaded, and before the running config * is loaded. * * RETURNS: * status *********************************************************************/ status_t agt_init2 (void) { val_value_t *clivalset; ncx_module_t *retmod; val_value_t *val; agt_dynlib_cb_t *dynlib; xmlChar *savestr, *revision, savechar; cfg_template_t *cfg; status_t res; uint32 modlen; boolean startup_loaded; log_debug3("\nServer Init-2 Starting..."); startup_loaded = FALSE; /* init user callback support */ agt_cb_init(); agt_commit_complete_init(); agt_commit_validate_init(); agt_not_queue_notification_cb_init(); /* initial signal handler first to allow clean exit */ agt_signal_init(); /* initialize the server timer service */ agt_timer_init(); /* initialize the RPC server callback structures */ res = agt_rpc_init(); if (res != NO_ERR) { log_debug3("\nError in rpc_init"); return res; } /* initialize the NCX connect handler */ res = agt_connect_init(); if (res != NO_ERR) { log_debug3("\nError in agt_connect_init"); return res; } /* initialize the NCX hello handler */ res = agt_hello_init(); if (res != NO_ERR) { log_debug3("\nError in agt_hello_init"); return res; } /* setup an empty <running> config * The config state is still CFG_ST_INIT * so no user access can occur yet (except OP_LOAD by root) */ res = cfg_init_static_db(NCX_CFGID_RUNNING); if (res != NO_ERR) { return res; } /* set the 'ordered-by system' sorted/not-sorted flag */ ncx_set_system_sorted(agt_profile.agt_system_sorted); /* set the 'top-level mandatory objects allowed' flag */ ncx_set_top_mandatory_allowed(!agt_profile.agt_running_error); /*** All Server profile parameters should be set by now ***/ /* must set the server capabilities after the profile is set */ res = agt_cap_set_caps(agt_profile.agt_targ, agt_profile.agt_start, agt_profile.agt_defaultStyle); if (res != NO_ERR) { return res; } /* setup the candidate config if it is used */ if (agt_profile.agt_targ==NCX_AGT_TARG_CANDIDATE) { res = cfg_init_static_db(NCX_CFGID_CANDIDATE); if (res != NO_ERR) { return res; } } /* setup the startup config if it is used */ if (agt_profile.agt_start==NCX_AGT_START_DISTINCT) { res = cfg_init_static_db(NCX_CFGID_STARTUP); if (res != NO_ERR) { return res; } } /* initialize the server access control model */ res = agt_acm_init(); if (res != NO_ERR) { return res; } /* initialize the session handler data structures */ agt_ses_init(); /* load the system module */ res = agt_sys_init(); if (res != NO_ERR) { return res; } /* load the NETCONF state monitoring data model module */ res = agt_state_init(); if (res != NO_ERR) { return res; } /* load the NETCONF Notifications data model module */ res = agt_not_init(); if (res != NO_ERR) { return res; } /* load the NETCONF /proc monitoring data model module */ res = agt_proc_init(); if (res != NO_ERR) { return res; } /* load the partial lock module */ res = y_ietf_netconf_partial_lock_init (y_ietf_netconf_partial_lock_M_ietf_netconf_partial_lock, NULL); if (res != NO_ERR) { return res; } #if 0 // OpenClovis: we do not want this by default /* load the NETCONF interface monitoring data model module */ res = agt_if_init(); if (res != NO_ERR) { return res; } #endif /* initialize the NCX server core callback functions. * the schema (yuma-netconf.yang) for these callbacks was * already loaded in the common ncx_init * */ res = agt_ncx_init(); if (res != NO_ERR) { return res; } /* load the yuma-time-filter module */ res = y_yuma_time_filter_init (y_yuma_time_filter_M_yuma_time_filter, NULL); if (res != NO_ERR) { return res; } /* load the yuma-arp module */ res = y_yuma_arp_init(y_yuma_arp_M_yuma_arp, NULL); if (res != NO_ERR) { return res; } /* check the module parameter set from CLI or conf file * for any modules to pre-load */ res = NO_ERR; clivalset = agt_cli_get_valset(); if (clivalset) { if (LOGDEBUG) { log_debug("\n\nnetconfd final CLI + .conf parameters:\n"); val_dump_value_max(clivalset, 0, NCX_DEF_INDENT, DUMP_VAL_LOG, NCX_DISPLAY_MODE_PLAIN, FALSE, /* withmeta */ TRUE /* config only */); log_debug("\n"); } /* first check if there are any deviations to load */ val = val_find_child(clivalset, NCXMOD_NETCONFD, NCX_EL_DEVIATION); while (val) { res = ncxmod_load_deviation(VAL_STR(val), &agt_profile.agt_savedevQ); if (res != NO_ERR) { return res; } else { val = val_find_next_child(clivalset, NCXMOD_NETCONFD, NCX_EL_DEVIATION, val); } } val = val_find_child(clivalset, NCXMOD_NETCONFD, NCX_EL_MODULE); /* attempt all dynamically loaded modules */ while (val && res == NO_ERR) { /* see if the revision is present in the * module parameter or not */ modlen = 0; revision = NULL; savestr = NULL; savechar = '\0'; if (yang_split_filename(VAL_STR(val), &modlen)) { savestr = &(VAL_STR(val)[modlen]); savechar = *savestr; *savestr = '\0'; revision = savestr + 1; } #ifdef STATIC_SERVER /* load just the module * SIL initialization is assumed to be * handled elsewhere */ res = ncxmod_load_module(VAL_STR(val), revision, &agt_profile.agt_savedevQ, &retmod); } #else /* load the SIL and it will load its own module */ res = agt_load_sil_code(VAL_STR(val), revision, FALSE); if (res == ERR_NCX_SKIPPED) { log_warn("\nWarning: SIL code for module '%s' not found", VAL_STR(val)); res = ncxmod_load_module(VAL_STR(val), revision, &agt_profile.agt_savedevQ, &retmod); } #endif if (savestr != NULL) { *savestr = savechar; } if (res == NO_ERR) { val = val_find_next_child(clivalset, NCXMOD_NETCONFD, NCX_EL_MODULE, val); } } }
/******************************************************************** * FUNCTION show_user_var * * generate the output for a global or local variable * * INPUTS: * server_cb == server control block to use * varname == variable name to show * vartype == type of user variable * val == value associated with this variable * mode == help mode in use * * RETURNS: * status *********************************************************************/ static status_t show_user_var (server_cb_t *server_cb, const xmlChar *varname, var_type_t vartype, val_value_t *val, help_mode_t mode) { session_cb_t *session_cb = server_cb->cur_session_cb; xmlChar *objbuff; logfn_t logfn; boolean imode = interactive_mode(); int32 doubleindent = 1; status_t res = NO_ERR; if (imode) { logfn = log_stdout; } else { logfn = log_write; } switch (vartype) { case VAR_TYP_GLOBAL: case VAR_TYP_LOCAL: case VAR_TYP_SESSION: case VAR_TYP_SYSTEM: case VAR_TYP_CONFIG: if (xml_strcmp(varname, val->name)) { doubleindent = 2; (*logfn)("\n %s ", varname); if (val->obj && obj_is_data_db(val->obj)) { res = obj_gen_object_id(val->obj, &objbuff); if (res != NO_ERR) { (*logfn)("[no object id]\n "); } else { (*logfn)("[%s]\n ", objbuff); m__free(objbuff); } } } else if (session_cb->display_mode == NCX_DISPLAY_MODE_JSON) { (*logfn)("\n %s: ", varname); if (!typ_is_simple(val->btyp)) { (*logfn)("\n"); } } break; default: ; } if (!typ_is_simple(val->btyp) && mode == HELP_MODE_BRIEF) { if (doubleindent == 1) { (*logfn)("\n %s (%s)", varname, tk_get_btype_sym(val->btyp)); } else { (*logfn)("\n (%s)", tk_get_btype_sym(val->btyp)); } } else { val_dump_value_max(val, session_cb->defindent * doubleindent, session_cb->defindent, (imode) ? DUMP_VAL_STDOUT : DUMP_VAL_LOG, session_cb->display_mode, FALSE, FALSE); } return res; } /* show_user_var */