/******************************************************************** * FUNCTION check_manager_hello * * Verify that the same NETCONF protocol verion is supported * by the manager and this server * * INPUTS: * scb == session control block * val == value struct for the hello message to check * * RETURNS: * status *********************************************************************/ static status_t check_manager_hello (ses_cb_t *scb, val_value_t *val) { val_value_t *caps, *cap; /* look for the NETCONF base capability string */ caps = val_find_child(val, NC_MODULE, NCX_EL_CAPABILITIES); if (caps && caps->res == NO_ERR) { if (ncx_protocol_enabled(NCX_PROTO_NETCONF11)) { for (cap = val_find_child(caps, NC_MODULE, NCX_EL_CAPABILITY); cap != NULL; cap = val_find_next_child(caps, NC_MODULE, NCX_EL_CAPABILITY, cap)) { if (cap->res == NO_ERR) { if (!xml_strcmp(VAL_STR(cap), CAP_BASE_URN11)) { if (LOGDEBUG3) { log_debug3("\nagt_hello: set " "protocol to base:1.1"); } return ses_set_protocol(scb, NCX_PROTO_NETCONF11); } } } } if (ncx_protocol_enabled(NCX_PROTO_NETCONF10)) { for (cap = val_find_child(caps, NC_MODULE, NCX_EL_CAPABILITY); cap != NULL; cap = val_find_next_child(caps, NC_MODULE, NCX_EL_CAPABILITY, cap)) { if (cap->res == NO_ERR) { if (!xml_strcmp(VAL_STR(cap), CAP_BASE_URN)) { if (LOGDEBUG3) { log_debug3("\nagt_hello: set " "protocol to base:1.0"); } return ses_set_protocol(scb, NCX_PROTO_NETCONF10); } } } } } log_info("\nagt_hello: no NETCONF base:1.0 or base:1.1 URI found"); return ERR_NCX_MISSING_VAL_INST; } /* check_manager_hello */
/******************************************************************** * FUNCTION do_alias (local RPC) * * alias * alias def * alias def=def-value * * Handle the alias command, based on the parameter * * INPUTS: * server_cb == server control block to use * rpc == RPC method for the alias command * line == CLI input in progress * len == offset into line buffer to start parsing * * RETURNS: * status *********************************************************************/ status_t do_alias (server_cb_t *server_cb, obj_template_t *rpc, const xmlChar *line, uint32 len) { val_value_t *valset, *parm; status_t res = NO_ERR; valset = get_valset(server_cb, rpc, &line[len], &res); if (res == NO_ERR && valset) { parm = val_find_child(valset, YANGCLI_MOD, YANGCLI_VAR); if (parm) { const xmlChar *varstr = VAL_STR(parm); res = handle_alias_parm(varstr, FALSE, TRUE); if (res == NO_ERR) { update_yangcli_param_change_flag (ALIASES_FILE, TRUE); } } else { /* no parameter; show all aliases */ show_aliases(); } } if (valset) { val_free_value(valset); } return res; } /* do_alias */
/******************************************************************** * FUNCTION do_unset (local RPC) * * unset def * * Handle the unset command; remove the specified alias * * INPUTS: * server_cb == server control block to use * rpc == RPC method for the unset command * line == CLI input in progress * len == offset into line buffer to start parsing * * RETURNS: * status *********************************************************************/ extern status_t do_unset (server_cb_t *server_cb, obj_template_t *rpc, const xmlChar *line, uint32 len) { val_value_t *valset, *parm; status_t res = NO_ERR; valset = get_valset(server_cb, rpc, &line[len], &res); if (res == NO_ERR && valset) { parm = val_find_child(valset, YANGCLI_MOD, NCX_EL_NAME); if (parm) { const xmlChar *varstr = VAL_STR(parm); alias_cb_t *alias = find_alias(varstr, xml_strlen(varstr)); if (alias) { dlq_remove(alias); free_alias(alias); log_info("\nDeleted alias '%s'\n", varstr); } else { res = ERR_NCX_INVALID_VALUE; log_error("\nError: unknown alias '%s'\n", varstr); } } /* else missing parameter already reported */ } /* else no valset already reported */ if (valset) { val_free_value(valset); } return res; } /* do_unset */
/******************************************************************** * FUNCTION y_starter_starter_kill_vnf_validate * * RPC validation phase * All YANG constraints have passed at this point. * Add description-stmt checks in this function. * * INPUTS: * see agt/agt_rpc.h for details * * RETURNS: * error status ********************************************************************/ static status_t y_starter_starter_kill_vnf_validate ( ses_cb_t *scb, rpc_msg_t *msg, xml_node_t *methnode) { status_t res = NO_ERR; val_value_t *errorval = NULL; val_value_t *vnfID_val; const xmlChar *vnfID; vnfID_val = val_find_child( msg->rpc_input, y_starter_M_starter, y_starter_N_vnfID); if (vnfID_val != NULL && vnfID_val->res == NO_ERR) { vnfID = VAL_STRING(vnfID_val); } if (res != NO_ERR) { agt_record_error( scb, &msg->mhdr, NCX_LAYER_OPERATION, res, methnode, (errorval) ? NCX_NT_VAL : NCX_NT_NONE, errorval, (errorval) ? NCX_NT_VAL : NCX_NT_NONE, errorval); } return res; } /* y_starter_starter_kill_vnf_validate */
/******************************************************************** * FUNCTION y_starter_starter_kill_vnf_invoke * * RPC invocation phase * All constraints have passed at this point. * Call device instrumentation code in this function. * * INPUTS: * see agt/agt_rpc.h for details * * RETURNS: * error status ********************************************************************/ static status_t y_starter_starter_kill_vnf_invoke ( ses_cb_t *scb, rpc_msg_t *msg, xml_node_t *methnode) { status_t res = NO_ERR; val_value_t *vnfID_val; const xmlChar *vnfID; vnfID_val = val_find_child( msg->rpc_input, y_starter_M_starter, y_starter_N_vnfID); if (vnfID_val != NULL && vnfID_val->res == NO_ERR) { vnfID = VAL_STRING(vnfID_val); } /* remove the next line if scb is used */ (void)scb; /* remove the next line if methnode is used */ (void)methnode; /* invoke your device instrumentation code here */ return res; } /* y_starter_starter_kill_vnf_invoke */
/******************************************************************** * FUNCTION y_starter_starter_start_vnf_validate * * RPC validation phase * All YANG constraints have passed at this point. * Add description-stmt checks in this function. * * INPUTS: * see agt/agt_rpc.h for details * * RETURNS: * error status ********************************************************************/ static status_t y_starter_starter_start_vnf_validate ( ses_cb_t *scb, rpc_msg_t *msg, xml_node_t *methnode) { status_t res = NO_ERR; val_value_t *errorval = NULL; val_value_t *port_val; const xmlChar *port; val_value_t *clickDescription_val; const xmlChar *clickDescription; port_val = val_find_child( msg->rpc_input, y_starter_M_starter, y_starter_N_port); if (port_val != NULL && port_val->res == NO_ERR) { port = VAL_STRING(port_val); } clickDescription_val = val_find_child( msg->rpc_input, y_starter_M_starter, y_starter_N_clickDescription); if (clickDescription_val != NULL && clickDescription_val->res == NO_ERR) { clickDescription = VAL_STRING(clickDescription_val); } if (res != NO_ERR) { agt_record_error( scb, &msg->mhdr, NCX_LAYER_OPERATION, res, methnode, (errorval) ? NCX_NT_VAL : NCX_NT_NONE, errorval, (errorval) ? NCX_NT_VAL : NCX_NT_NONE, errorval); } return res; } /* y_starter_starter_start_vnf_validate */
/******************************************************************** * FUNCTION set_my_session_invoke * * set-my-session : invoke params callback * * INPUTS: * see rpc/agt_rpc.h * RETURNS: * status *********************************************************************/ static status_t set_my_session_invoke (ses_cb_t *scb, rpc_msg_t *msg, xml_node_t *methnode) { val_value_t *indentval, *linesizeval, *withdefval; (void)methnode; /* get the indent amount parameter */ indentval = val_find_child(msg->rpc_input, AGT_SES_MODULE, NCX_EL_INDENT); if (indentval && indentval->res == NO_ERR) { scb->indent = VAL_UINT(indentval); } /* get the line sizer parameter */ linesizeval = val_find_child(msg->rpc_input, AGT_SES_MODULE, NCX_EL_LINESIZE); if (linesizeval && linesizeval->res == NO_ERR) { scb->linesize = VAL_UINT(linesizeval); } /* get the with-defaults parameter */ withdefval = val_find_child(msg->rpc_input, AGT_SES_MODULE, NCX_EL_WITH_DEFAULTS); if (withdefval && withdefval->res == NO_ERR) { scb->withdef = ncx_get_withdefaults_enum(VAL_ENUM_NAME(withdefval)); } return NO_ERR; } /* set_my_session_invoke */
/******************************************************************** * FUNCTION y_ietf_netconf_partial_lock_partial_unlock_validate * * RPC validation phase * All YANG constraints have passed at this point. * Add description-stmt checks in this function. * * INPUTS: * see agt/agt_rpc.h for details * * RETURNS: * error status ********************************************************************/ static status_t y_ietf_netconf_partial_lock_partial_unlock_validate ( ses_cb_t *scb, rpc_msg_t *msg, xml_node_t *methnode) { val_value_t *lock_id_val; cfg_template_t *running; plock_cb_t *plcb; uint32 lock_id; status_t res; res = NO_ERR; lock_id_val = val_find_child( msg->rpc_input, y_ietf_netconf_partial_lock_M_ietf_netconf_partial_lock, y_ietf_netconf_partial_lock_N_lock_id); if (lock_id_val == NULL || lock_id_val->res != NO_ERR) { return ERR_NCX_INVALID_VALUE; } lock_id = VAL_UINT(lock_id_val); running = cfg_get_config_id(NCX_CFGID_RUNNING); plcb = cfg_find_partial_lock(running, lock_id); if (plcb == NULL || (plock_get_sid(plcb) != SES_MY_SID(scb))) { res = ERR_NCX_INVALID_VALUE; agt_record_error( scb, &msg->mhdr, NCX_LAYER_OPERATION, res, methnode, NCX_NT_NONE, NULL, NCX_NT_VAL, lock_id_val); } else { msg->rpc_user1 = plcb; } return res; } /* y_ietf_netconf_partial_lock_partial_unlock_validate */
status_t y_ietf_interfaces_init2(void) { status_t res; cfg_template_t* runningcfg; val_value_t* interfaces_state_val; res = NO_ERR; runningcfg = cfg_get_config_id(NCX_CFGID_RUNNING); if (!runningcfg || !runningcfg->root) { return SET_ERROR(ERR_INTERNAL_VAL); } interfaces_state_val = val_find_child(runningcfg->root, "ietf-interfaces", "interfaces-state"); /* Can not coexist with other implementation * of ietf-interfaces. */ if(interfaces_state_val!=NULL) { log_error("\nError: /interfaces-state already present!"); return SET_ERROR(ERR_INTERNAL_VAL); } interfaces_state_val = val_new_value(); if (interfaces_state_val == NULL) { return SET_ERROR(ERR_INTERNAL_VAL); } val_init_from_template(interfaces_state_val, interfaces_state_obj); val_init_virtual(interfaces_state_val, get_interfaces_state, interfaces_state_val->obj); val_add_child(interfaces_state_val, runningcfg->root); return res; }
/******************************************************************** * FUNCTION do_config (local RPC) * * config term * * Enter the configuration mode * * INPUTS: * server_cb == server control block to use * rpc == RPC method for the show command * line == CLI input in progress * len == offset into line buffer to start parsing * * RETURNS: * status *********************************************************************/ status_t do_config (server_cb_t *server_cb, obj_template_t *rpc, const xmlChar *line, uint32 len) { status_t res = NO_ERR; val_value_t *valset = get_valset(server_cb, rpc, &line[len], &res); if (valset && res == NO_ERR) { /* check if the 'brief' flag is set first */ val_value_t *parm = val_find_child(valset, YANGCLI_MOD, YANGCLI_TERM); if (!parm || parm->res != NO_ERR) { log_error("\nError: 'terminal' parameter invalid\n"); if (parm) { res = parm->res; } else { res = ERR_NCX_MISSING_PARM; } } else { session_cb_t *session_cb = server_cb->cur_session_cb; if (session_cb->config_mode) { log_error("\nError: configure mode already active\n"); res = ERR_NCX_IN_USE; } else { res = start_config_mode(server_cb, session_cb); } } } if (valset) { val_free_value(valset); } return res; } /* do_config */
/******************************************************************** * FUNCTION get_session_idval * * Get the session ID number for the virtual * counter entry that was called from a <get> operation * * INPUTS: * virval == virtual value * retsid == address of return session ID number * * OUTPUTS: * *retsid == session ID for this <session> entry * RETURNS: * status *********************************************************************/ static status_t get_session_key (const val_value_t *virval, ses_id_t *retsid) { const val_value_t *parentval, *sidval; parentval = virval->parent; if (parentval == NULL) { return ERR_NCX_DEF_NOT_FOUND; } sidval = val_find_child(parentval, obj_get_mod_name(parentval->obj), (const xmlChar *)"session-id"); if (sidval == NULL) { return ERR_NCX_DEF_NOT_FOUND; } *retsid = VAL_UINT(sidval); return NO_ERR; } /* get_session_key */
/******************************************************************** * FUNCTION y_ietf_netconf_partial_lock_partial_lock_validate * * RPC validation phase * All YANG constraints have passed at this point. * Add description-stmt checks in this function. * * INPUTS: * see agt/agt_rpc.h for details * * RETURNS: * error status ********************************************************************/ static status_t y_ietf_netconf_partial_lock_partial_lock_validate ( ses_cb_t *scb, rpc_msg_t *msg, xml_node_t *methnode) { plock_cb_t *plcb; cfg_template_t *running; val_value_t *select_val, *testval; xpath_result_t *result; xpath_resnode_t *resnode; status_t res, retres; ses_id_t lockowner; res = NO_ERR; retres = NO_ERR; plcb = NULL; result = NULL; running = cfg_get_config_id(NCX_CFGID_RUNNING); /* make sure the running config state is READY */ res = cfg_ok_to_partial_lock(running); if (res != NO_ERR) { agt_record_error(scb, &msg->mhdr, NCX_LAYER_OPERATION, res, methnode, NCX_NT_NONE, NULL, NCX_NT_NONE, NULL); return res; } /* the stack has already made sure at least 1 of these * is present because min-elements=1 */ select_val = val_find_child (msg->rpc_input, y_ietf_netconf_partial_lock_M_ietf_netconf_partial_lock, y_ietf_netconf_partial_lock_N_select); if (select_val == NULL || select_val->res != NO_ERR) { /* should not happen */ return SET_ERROR(ERR_INTERNAL_VAL); } /* allocate a new lock cb * the plcb pointer will be NULL if the result is not NO_ERR */ res = NO_ERR; plcb = plock_cb_new(SES_MY_SID(scb), &res); if (res == ERR_NCX_RESOURCE_DENIED && !plcb && !cfg_is_partial_locked(running)) { /* no partial locks so it is safe to reset the lock index */ plock_cb_reset_id(); res = NO_ERR; plcb = plock_cb_new(SES_MY_SID(scb), &res); } if (res != NO_ERR || !plcb ) { if ( res==NO_ERR && !plcb ) { res = ERR_INTERNAL_MEM; } agt_record_error(scb, &msg->mhdr, NCX_LAYER_OPERATION, res, methnode, NCX_NT_NONE, NULL, NCX_NT_NONE, NULL); if ( plcb ) { plock_cb_free(plcb); } return res; } /* get all the select parm instances and save them * in the partial lock cb */ while (select_val != NULL) { result = xpath1_eval_xmlexpr(scb->reader, select_val->xpathpcb, running->root, running->root, FALSE, /* logerrors */ TRUE, /* config-only */ &res); if (result == NULL || res != NO_ERR) { /* should not get invalid XPath expression * but maybe something was valid in the * object tree but not in the value tree */ agt_record_error(scb, &msg->mhdr, NCX_LAYER_OPERATION, res, methnode, NCX_NT_STRING, VAL_STRING(select_val), NCX_NT_VAL, select_val); retres = res; xpath_free_result(result); } else if (result->restype != XP_RT_NODESET) { res = ERR_NCX_XPATH_NOT_NODESET; agt_record_error(scb, &msg->mhdr, NCX_LAYER_OPERATION, res, methnode, NCX_NT_STRING, VAL_STRING(select_val), NCX_NT_VAL, select_val); retres = res; xpath_free_result(result); } else { /* save these pointers; the result will be * pruned for redundant nodes after all the * select expressions have been processed; * transfer the memory straight across */ plock_add_select(plcb, select_val->xpathpcb, result); select_val->xpathpcb = NULL; result = NULL; } /* set up the next select value even if errors so far */ select_val = val_find_next_child (msg->rpc_input, y_ietf_netconf_partial_lock_M_ietf_netconf_partial_lock, y_ietf_netconf_partial_lock_N_select, select_val); } /* check the result for non-empty only if all * the select stmts were valid */ if (retres == NO_ERR) { res = plock_make_final_result(plcb); if (res != NO_ERR) { agt_record_error(scb, &msg->mhdr, NCX_LAYER_OPERATION, res, methnode, NCX_NT_NONE, NULL, NCX_NT_VAL, select_val); retres = res; } } /* make sure all the nodeptrs identify subtrees in the * running config that can really be locked right now * only if the final result is a non-empty nodeset */ if (retres == NO_ERR) { result = plock_get_final_result(plcb); for (resnode = xpath_get_first_resnode(result); resnode != NULL; resnode = xpath_get_next_resnode(resnode)) { testval = xpath_get_resnode_valptr(resnode); /* !!! Update 2011-09-27 * Just talked to the RFC author; Martin and I * agree RFC 5717 does not specify that write * access be required to create a partial lock * In fact -- a user may want to lock a node * to do a stable read **** deleted agt_acm check ***/ /* make sure there is a plock slot available * and no part of this subtree is already locked * do not check lock conflicts if this subtree * is unauthorized for writing */ lockowner = 0; res = val_ok_to_partial_lock(testval, SES_MY_SID(scb), &lockowner); if (res != NO_ERR) { if (res == ERR_NCX_LOCK_DENIED) { agt_record_error(scb, &msg->mhdr, NCX_LAYER_OPERATION, res, methnode, NCX_NT_UINT32_PTR, &lockowner, NCX_NT_VAL, testval); } else { agt_record_error(scb, &msg->mhdr, NCX_LAYER_OPERATION, res, methnode, NCX_NT_NONE, NULL, NCX_NT_VAL, testval); } retres = res; } } // for loop } // if retres == NO_ERR /* make sure there is no partial commit in progress */ if (agt_ncx_cc_active()) { res = ERR_NCX_IN_USE_COMMIT; agt_record_error(scb, &msg->mhdr, NCX_LAYER_OPERATION, res, methnode, NCX_NT_NONE, NULL, NCX_NT_NONE, NULL); retres = res; } /* save the plock CB only if there were no errors; * otherwise the invoke function will not get called */ if (retres == NO_ERR) { /* the invoke function must free this pointer */ msg->rpc_user1 = plcb; } else { plock_cb_free(plcb); } return retres; } /* y_ietf_netconf_partial_lock_partial_lock_validate */
/******************************************************************** * FUNCTION do_elif (local RPC) * * Handle the if command; start a new ifcb context * * elif expr='xpath-str' [docroot=$foo] * * INPUTS: * server_cb == server control block to use * rpc == RPC method for the show command * line == CLI input in progress * len == offset into line buffer to start parsing * isif == TRUE for if, FALSE for elif * RETURNS: * status *********************************************************************/ static status_t do_if_elif (server_cb_t *server_cb, obj_template_t *rpc, const xmlChar *line, uint32 len, boolean isif) { val_value_t *valset, *docroot, *expr, *dummydoc; xpath_pcb_t *pcb; xpath_result_t *result; status_t res; boolean cond; docroot = NULL; expr = NULL; pcb = NULL; dummydoc = NULL; cond = FALSE; res = NO_ERR; valset = get_valset(server_cb, rpc, &line[len], &res); if (valset == NULL) { return res; } if (res != NO_ERR) { val_free_value(valset); return res; } if (valset->res != NO_ERR) { res = valset->res; val_free_value(valset); return res; } /* get the expr parameter */ expr = val_find_child(valset, YANGCLI_MOD, YANGCLI_EXPR); if (expr == NULL) { res = ERR_NCX_MISSING_PARM; } else if (expr->res != NO_ERR) { res = expr->res; } if (res == NO_ERR) { /* get the optional docroot parameter */ docroot = val_find_child(valset, YANGCLI_MOD, YANGCLI_DOCROOT); if (docroot && docroot->res != NO_ERR) { res = docroot->res; } } if (res == NO_ERR && docroot == NULL) { dummydoc = xml_val_new_struct(NCX_EL_DATA, xmlns_nc_id()); if (dummydoc == NULL) { res = ERR_INTERNAL_MEM; } else { docroot = dummydoc; } } if (res == NO_ERR) { /* got all the parameters, and setup the XPath control block */ pcb = xpath_new_pcb_ex(VAL_STR(expr), xpath_getvar_fn, server_cb->runstack_context); if (pcb == NULL) { res = ERR_INTERNAL_MEM; } else if ((isif && runstack_get_cond_state(server_cb->runstack_context)) || (!isif && !runstack_get_if_used(server_cb->runstack_context))) { /* figure out if this if or elif block is enabled or not */ result = xpath1_eval_expr(pcb, docroot, /* context */ docroot, TRUE, FALSE, &res); if (result != NULL && res == NO_ERR) { /* get new condition state for this loop */ cond = xpath_cvt_boolean(result); } xpath_free_result(result); } if (res == NO_ERR) { if (isif) { res = runstack_handle_if(server_cb->runstack_context, cond); } else { res = runstack_handle_elif(server_cb->runstack_context, cond); } } } /* cleanup and exit */ if (valset) { val_free_value(valset); } if (pcb) { xpath_free_pcb(pcb); } if (dummydoc) { val_free_value(dummydoc); } return res; } /* do_if_elif */
/******************************************************************** * FUNCTION y_starter_starter_start_vnf_invoke * * RPC invocation phase * All constraints have passed at this point. * Call device instrumentation code in this function. * * INPUTS: * see agt/agt_rpc.h for details * * RETURNS: * error status ********************************************************************/ static status_t y_starter_starter_start_vnf_invoke ( ses_cb_t *scb, rpc_msg_t *msg, xml_node_t *methnode) { status_t res = NO_ERR; val_value_t *port_val; const xmlChar *port; val_value_t *clickDescription_val; const xmlChar *clickDescription; port_val = val_find_child( msg->rpc_input, y_starter_M_starter, y_starter_N_port); if (port_val != NULL && port_val->res == NO_ERR) { port = VAL_STRING(port_val); } clickDescription_val = val_find_child( msg->rpc_input, y_starter_M_starter, y_starter_N_clickDescription); if (clickDescription_val != NULL && clickDescription_val->res == NO_ERR) { clickDescription = VAL_STRING(clickDescription_val); } /* remove the next line if scb is used */ (void)scb; /* remove the next line if methnode is used */ (void)methnode; /* invoke your device instrumentation code here */ /*********************** THIS PART IS ADDED MANUALLY BY LEVI *************************/ log_info("\nStart VNF RPC is invoked with the following settings: \n"); log_info("\n%s",clickDescription); int processID; int status; log_info("\nFORKING\n"); /* in order to avoid block main thread otherwise, yangcli also waits for termination of child process */ signal(SIGCHLD, SIG_IGN); if((processID = fork() == 0 )) { /* the child process */ log_info("\nPID of child: %d ",getpid()); /*lastProcess.name = "sleep"; lastProcess.pid = getpid();*/ //dumping data into the processes_array process p; p.uniqueID = uniqueID; p.name = "click"; p.pid = getpid(); process_array[uniqueID]=p; uniqueID++; log_info("\nPID of netconfd: %d ", getppid()); // setting up the default params for starting click char control_socket[3] = "-R"; char port_param[8] = "-p"; strcat(port_param,(char*)port); char p3[3] = "-e"; /* char p4[100] = "FromDevice(eth1)->Discard;";*/ char click_path[100]="/home/unify/click_binaries/bin/click"; int errorCode = execlp(click_path, click_path, control_socket, port_param, p3, clickDescription, NULL); /* if everything went fine, we do not reach this point */ log_info("\nThe result of the execution is %d", errorCode); _exit(127); } else { log_info("\n\n--------------- RPC END ------------------\n\n"); } /********************************** END OF LEVI **************************************/ return res; } /* y_starter_starter_start_vnf_invoke */
/******************************************************************** * FUNCTION do_while (local RPC) * * Handle the while command; start a new loopcb context * * while expr='xpath-str' [docroot=$foo] * * INPUTS: * server_cb == server control block to use * rpc == RPC method for the show command * line == CLI input in progress * len == offset into line buffer to start parsing * * RETURNS: * status *********************************************************************/ status_t do_while (server_cb_t *server_cb, obj_template_t *rpc, const xmlChar *line, uint32 len) { val_value_t *valset, *docroot, *expr, *dummydoc, *maxloops; xpath_pcb_t *pcb; status_t res; uint32 maxloopsval; docroot = NULL; expr = NULL; pcb = NULL; dummydoc = NULL; res = NO_ERR; maxloopsval = YANGCLI_DEF_MAXLOOPS; valset = get_valset(server_cb, rpc, &line[len], &res); if (valset == NULL) { return res; } if (res != NO_ERR) { val_free_value(valset); return res; } if (valset->res != NO_ERR) { res = valset->res; val_free_value(valset); return res; } /* get the expr parameter */ expr = val_find_child(valset, YANGCLI_MOD, YANGCLI_EXPR); if (expr == NULL) { res = ERR_NCX_MISSING_PARM; } else if (expr->res != NO_ERR) { res = expr->res; } if (res == NO_ERR) { /* get the optional docroot parameter */ docroot = val_find_child(valset, YANGCLI_MOD, YANGCLI_DOCROOT); if (docroot != NULL) { if (docroot->res != NO_ERR) { res = docroot->res; } else { val_remove_child(docroot); } } } if (res == NO_ERR && docroot == NULL) { dummydoc = xml_val_new_struct(NCX_EL_DATA, xmlns_nc_id()); if (dummydoc == NULL) { res = ERR_INTERNAL_MEM; } else { docroot = dummydoc; } } if (res == NO_ERR) { /* get the optional maxloops parameter */ maxloops = val_find_child(valset, YANGCLI_MOD, YANGCLI_MAXLOOPS); if (maxloops != NULL) { if (maxloops->res != NO_ERR) { res = maxloops->res; } else { maxloopsval = VAL_UINT(maxloops); } } } if (res == NO_ERR) { /* got all the parameters, and setup the XPath control block */ pcb = xpath_new_pcb_ex(VAL_STR(expr), xpath_getvar_fn, server_cb->runstack_context); if (pcb == NULL) { res = ERR_INTERNAL_MEM; } else { /* save these parameter and start a new while context block */ res = runstack_handle_while(server_cb->runstack_context, maxloopsval, pcb, /* hand off memory here */ docroot); /* hand off memory here */ if (res == NO_ERR) { /* hand off the pcb and docroot memory above */ pcb = NULL; docroot = NULL; } } } /* cleanup and exit */ if (valset) { val_free_value(valset); } if (pcb) { xpath_free_pcb(pcb); } if (docroot) { val_free_value(docroot); } return res; } /* do_while */
/******************************************************************** * FUNCTION do_get_locks (local RPC) * * get all the locks on the server * * INPUTS: * server_cb == server control block to use * rpc == RPC method for the history command * line == CLI input in progress * len == offset into line buffer to start parsing * * RETURNS: * status *********************************************************************/ status_t do_get_locks (server_cb_t *server_cb, obj_template_t *rpc, const xmlChar *line, uint32 len) { ses_cb_t *scb; val_value_t *valset, *parm; uint32 locks_timeout, retry_interval; boolean cleanup, done; status_t res; if (server_cb->locks_active) { log_error("\nError: locks are already active"); return ERR_NCX_OPERATION_FAILED; } if (server_cb->state != MGR_IO_ST_CONN_IDLE) { log_error("\nError: no active session to lock"); return ERR_NCX_OPERATION_FAILED; } scb = mgr_ses_get_scb(server_cb->mysid); if (scb == NULL) { log_error("\nError: active session dropped, cannot lock"); return ERR_NCX_OPERATION_FAILED; } locks_timeout = server_cb->locks_timeout; retry_interval = server_cb->locks_retry_interval; cleanup = TRUE; res = NO_ERR; valset = get_valset(server_cb, rpc, &line[len], &res); if (valset && res == NO_ERR) { /* get the overall lock timeout */ parm = val_find_child(valset, YANGCLI_MOD, YANGCLI_LOCK_TIMEOUT); if (parm && parm->res == NO_ERR) { locks_timeout = VAL_UINT(parm); } /* get the retry interval between failed locks */ parm = val_find_child(valset, YANGCLI_MOD, YANGCLI_RETRY_INTERVAL); if (parm && parm->res == NO_ERR) { retry_interval = VAL_UINT(parm); } /* get the auto-cleanup flag */ parm = val_find_child(valset, YANGCLI_MOD, YANGCLI_CLEANUP); if (parm && parm->res == NO_ERR) { cleanup = VAL_BOOL(parm); } } /* start the auto-lock procedure */ setup_lock_cbs(server_cb); server_cb->locks_timeout = locks_timeout; server_cb->locks_retry_interval = retry_interval; server_cb->locks_cleanup = cleanup; done = FALSE; if (LOGINFO) { log_info("\nSending <lock> operations for get-locks...\n"); } res = handle_get_locks_request_to_server(server_cb, TRUE, &done); if (res != NO_ERR && done) { /* need to undo the whole thing; whatever got done */ } if (valset != NULL) { val_free_value(valset); } return res; } /* do_get_locks */
/******************************************************************** * FUNCTION process_server_hello * * Process the NETCONF server <hello> contents * * 1) Protocol capabilities * 2) Module capabilities * 3) Unrecognized capabilities * * INPUTS: * scb == session control block to set * hello == value struct for the hello message to check * * OUTPUTS: * server caps in the scb->mgrcb is set * * RETURNS: * status *********************************************************************/ static status_t process_server_hello (ses_cb_t *scb, val_value_t *hello) { val_value_t *caps, *sidval, *cap; mgr_scb_t *mscb; boolean c1, c2; status_t res; mscb = mgr_ses_get_mscb(scb); /* make sure the capabilities element is present * This should not fail, since already parsed this far */ caps = val_find_child(hello, NC_MODULE, NCX_EL_CAPABILITIES); if (!caps || caps->res != NO_ERR) { log_error("\nError: no <capabilities> found in server <hello>"); return ERR_NCX_MISSING_VAL_INST; } /* make sure the session-id element is present * This should not fail, since already parsed this far */ sidval = val_find_child(hello, NC_MODULE, NCX_EL_SESSION_ID); if (!sidval || sidval->res != NO_ERR) { log_error("\nError: no <session-id> found in server <hello>"); return ERR_NCX_MISSING_VAL_INST; } else { mscb->agtsid = VAL_UINT(sidval); } /* go through the capability nodes and construct a caplist */ for (cap = val_find_child(caps, NC_MODULE, NCX_EL_CAPABILITY); cap != NULL; cap = val_find_next_child(caps, NC_MODULE, NCX_EL_CAPABILITY, cap)) { if (cap->res != NO_ERR) { continue; } res = cap_add_std_string(&mscb->caplist, VAL_STR(cap)); if (res == ERR_NCX_SKIPPED) { res = cap_add_module_string(&mscb->caplist, VAL_STR(cap)); if (res == ERR_NCX_SKIPPED) { /* * if (ncx_warning_enabled(ERR_NCX_RCV_UNKNOWN_CAP)) { * log_warn("\nWarning: received unknown capability '%s'", * VAL_STR(cap)); * } */ if (LOGDEBUG2) { log_debug2("\nmgr: Got enterprise capability %s", VAL_STR(cap)); } /* hack: check for juniper 1.0 server * change the useprefix mode to TRUE to get * <rpc> operations to work with this server */ if (!xml_strcmp(VAL_STR(cap), CAP_JUNOS)) { if (LOGDEBUG) { log_debug("\nUsing XML prefixes to work " "with Junos 1.0 server\n"); } ncx_set_useprefix(TRUE); } res = cap_add_ent(&mscb->caplist, VAL_STR(cap)); if (res != NO_ERR) { return res; } } } } /* check if the mandatory base protocol capability was set */ res = NO_ERR; c1 = cap_std_set(&mscb->caplist, CAP_STDID_V1); c2 = cap_std_set(&mscb->caplist, CAP_STDID_V11); if (c1 && c2) { if (LOGDEBUG2) { log_debug2("\nmgr_hello: server supports " "base:1.0 and base:1.1"); } if (ses_protocol_requested(scb, NCX_PROTO_NETCONF11)) { if (LOGDEBUG2) { log_debug2("\nmgr_hello: set protocol to base:1.1 " "for session '%d'", scb->sid); } ses_set_protocol(scb, NCX_PROTO_NETCONF11); } else if (ses_protocol_requested(scb, NCX_PROTO_NETCONF10)) { if (LOGDEBUG2) { log_debug2("\nmgr_hello: set protocol to base:1.0 " "for session '%d'", scb->sid); } ses_set_protocol(scb, NCX_PROTO_NETCONF10); } else { log_error("\nError: Internal: no protocols requested, " "dropping session '%d'", scb->sid); res = ERR_NCX_MISSING_VAL_INST; } } else if (c1) { if (LOGDEBUG2) { log_debug2("\nmgr_hello: server supports " "base:1.0 only"); } if (ses_protocol_requested(scb, NCX_PROTO_NETCONF10)) { if (LOGDEBUG2) { log_debug2("\nmgr_hello: set protocol to base:1.0 " "for session '%d'", scb->sid); } ses_set_protocol(scb, NCX_PROTO_NETCONF10); } else { log_error("\nError: Server supports base:1.0 only;" "\n Protocol 'netconf1.0' not enabled, " "dropping session '%d'", scb->sid); res = ERR_NCX_MISSING_VAL_INST; } } else if (c2) { if (LOGDEBUG2) { log_debug2("\nmgr_hello: server supports " "base:1.1 only"); } if (ses_protocol_requested(scb, NCX_PROTO_NETCONF11)) { if (LOGDEBUG2) { log_debug2("\nmgr_hello: set protocol to base:1.1 " "for session '%d'", scb->sid); } ses_set_protocol(scb, NCX_PROTO_NETCONF11); } else { log_error("\nError: Server supports base:1.1 only;" "\n Protocol 'netconf1.1' not enabled, " "dropping session '%d'", scb->sid); res = ERR_NCX_MISSING_VAL_INST; } } else { log_error("\nError: no support for base:1.0 " "or base:1.1 found in server <hello>;" "\n dropping session '%d'", scb->sid); return ERR_NCX_MISSING_VAL_INST; } /* set target type var in the manager session control block */ c1 = cap_std_set(&mscb->caplist, CAP_STDID_WRITE_RUNNING); c2 = cap_std_set(&mscb->caplist, CAP_STDID_CANDIDATE); if (c1 && c2) { mscb->targtyp = NCX_AGT_TARG_CAND_RUNNING; } else if (c1) { mscb->targtyp = NCX_AGT_TARG_RUNNING; } else if (c2) { mscb->targtyp = NCX_AGT_TARG_CANDIDATE; } else { mscb->targtyp = NCX_AGT_TARG_NONE; if (LOGINFO) { log_info("\nmgr_hello: no writable target found for" " session %u (a:%u)", scb->sid, mscb->agtsid); } } /* set the startup type in the mscb */ if (cap_std_set(&mscb->caplist, CAP_STDID_STARTUP)) { mscb->starttyp = NCX_AGT_START_DISTINCT; } else { mscb->starttyp = NCX_AGT_START_MIRROR; } return NO_ERR; } /* process_server_hello */
/******************************************************************** * FUNCTION agt_cli_process_input * * Process the param line parameters against the hardwired * parmset for the netconfd program * * INPUTS: * argc == argument count * argv == array of command line argument strings * agt_profile == agent profile struct to fill in * showver == address of version return quick-exit status * showhelpmode == address of help return quick-exit status * * OUTPUTS: * *agt_profile is filled in, with parms gathered or defaults * *showver == TRUE if user requsted version quick-exit mode * *showhelpmode == requested help mode * (none, breief, normal, full) * * RETURNS: * NO_ERR if all goes well *********************************************************************/ status_t agt_cli_process_input (int argc, char *argv[], agt_profile_t *agt_profile, boolean *showver, help_mode_t *showhelpmode) { ncx_module_t *mod; obj_template_t *obj; val_value_t *valset, *val; FILE *fp; status_t res; boolean test; #ifdef DEBUG if (!argv || !agt_profile || !showver || !showhelpmode) { return SET_ERROR(ERR_INTERNAL_PTR); } #endif *showver = FALSE; *showhelpmode = HELP_MODE_NONE; /* find the parmset definition in the registry */ obj = NULL; mod = ncx_find_module(AGT_CLI_MODULE, NULL); if (mod) { obj = ncx_find_object(mod, AGT_CLI_CONTAINER); } if (!obj) { log_error("\nError: netconfd module with CLI definitions not loaded"); return ERR_NCX_NOT_FOUND; } /* parse the command line against the object template */ res = NO_ERR; valset = NULL; if (argc > 0) { valset = cli_parse(NULL, argc, argv, obj, FULLTEST, PLAINMODE, TRUE, CLI_MODE_PROGRAM, &res); if (res != NO_ERR) { if (valset) { val_free_value(valset); } return res; } } if (valset != NULL) { /* transfer the parmset values */ set_server_profile(valset, agt_profile); /* next get any params from the conf file */ val = val_find_child(valset, AGT_CLI_MODULE, NCX_EL_CONFIG); if (val) { if (val->res == NO_ERR) { /* try the specified config location */ agt_profile->agt_conffile = VAL_STR(val); res = conf_parse_val_from_filespec(VAL_STR(val), valset, TRUE, TRUE); if (res != NO_ERR) { val_free_value(valset); return res; } else { /* transfer the parmset values again */ set_server_profile(valset, agt_profile); } } } else { fp = fopen((const char *)AGT_DEF_CONF_FILE, "r"); if (fp != NULL) { fclose(fp); /* use default config location */ res = conf_parse_val_from_filespec(AGT_DEF_CONF_FILE, valset, TRUE, TRUE); if (res != NO_ERR) { val_free_value(valset); return res; } else { /* transfer the parmset values again */ set_server_profile(valset, agt_profile); } } } /* set the logging control parameters */ val_set_logging_parms(valset); /* audit-log-append param */ val = val_find_child(valset, AGT_CLI_MODULE, NCX_EL_AUDIT_LOG_APPEND); if (val && val->res == NO_ERR) { test = TRUE; } else { test = FALSE; } /* audit-log param */ val = val_find_child(valset, AGT_CLI_MODULE, NCX_EL_AUDIT_LOG); if (val && val->res == NO_ERR) { xmlChar *filespec = ncx_get_source(VAL_STR(val), &res); if (filespec == NULL) { log_error("\nError: get source for audit log failed"); return res; } res = log_audit_open((const char *)filespec, test, TRUE); if (res == NO_ERR) { if (LOGDEBUG) { log_debug("\nAudit log '%s' opened for %s", filespec, (test) ? "append" : "write"); } } else { log_error("\nError: open audit log '%s' failed", filespec); } m__free(filespec); if (res != NO_ERR) { return res; } } /* set the file search path parms */ res = val_set_path_parms(valset); if (res != NO_ERR) { return res; } /* set the warning control parameters */ res = val_set_warning_parms(valset); if (res != NO_ERR) { return res; } /* set the feature code generation parameters */ res = val_set_feature_parms(valset); if (res != NO_ERR) { return res; } /* check the subdirs parameter */ res = val_set_subdirs_parm(valset); if (res != NO_ERR) { return res; } /* check the protocols parameter */ res = val_set_protocols_parm(valset); if (res != NO_ERR) { return res; } /* check the system-sorted param */ val = val_find_child(valset, AGT_CLI_MODULE, NCX_EL_SYSTEM_SORTED); if (val && val->res == NO_ERR) { agt_profile->agt_system_sorted = VAL_BOOL(val); } /* version param handled externally */ /* check if version mode requested */ val = val_find_child(valset, AGT_CLI_MODULE, NCX_EL_VERSION); *showver = (val) ? TRUE : FALSE; /* check if help mode requested */ val = val_find_child(valset, AGT_CLI_MODULE, NCX_EL_HELP); if (val) { *showhelpmode = HELP_MODE_NORMAL; /* help submode parameter (brief/normal/full) */ val = val_find_child(valset, AGT_CLI_MODULE, NCX_EL_BRIEF); if (val) { *showhelpmode = HELP_MODE_BRIEF; } else { /* full parameter */ val = val_find_child(valset, AGT_CLI_MODULE, NCX_EL_FULL); if (val) { *showhelpmode = HELP_MODE_FULL; } } } } /* cleanup and exit * handoff the malloced 'valset' memory here */ cli_val = valset; return res; } /* agt_cli_process_input */
/******************************************************************** * FUNCTION do_aliases (local RPC) * * aliases * aliases clear * aliases show * aliases load[=filespec] * aliases save[=filespec] * * Handle the aliases command, based on the parameter * * INPUTS: * server_cb == server control block to use * rpc == RPC method for the aliases command * line == CLI input in progress * len == offset into line buffer to start parsing * * RETURNS: * status *********************************************************************/ status_t do_aliases (server_cb_t *server_cb, obj_template_t *rpc, const xmlChar *line, uint32 len) { val_value_t *valset; status_t res = NO_ERR; valset = get_valset(server_cb, rpc, &line[len], &res); if (res == NO_ERR && valset) { /* get the 1 of N 'alias-action' choice */ val_value_t *parm; const xmlChar *parmval = NULL; boolean done = FALSE; /* aliases show */ parm = val_find_child(valset, YANGCLI_MOD, YANGCLI_SHOW); if (parm) { show_aliases(); done = TRUE; } /* aliases clear */ if (!done) { parm = val_find_child(valset, YANGCLI_MOD, YANGCLI_CLEAR); if (parm) { dlq_hdr_t *aliasQ = get_aliasQ(); if (!dlq_empty(aliasQ)) { free_aliases(); log_info("\nDeleted all aliases from memory\n"); update_yangcli_param_change_flag (ALIASES_FILE, TRUE); }else { log_info("\nNo aliases found\n"); } done = TRUE; } } /* aliases load */ if (!done) { parm = val_find_child(valset, YANGCLI_MOD, YANGCLI_LOAD); if (parm) { if (xml_strlen(VAL_STR(parm))) { parmval = VAL_STR(parm); } else { parmval = get_aliases_file(); } res = load_aliases(parmval, !val_set_by_default(parm)); if (res == NO_ERR) { log_info("\nLoaded aliases OK from '%s'\n", parmval); } else { log_error("\nLoad aliases from '%s' failed (%s)\n", parmval, get_error_string(res)); } done = TRUE; } } /* aliases save */ if (!done) { parm = val_find_child(valset, YANGCLI_MOD, YANGCLI_SAVE); if (parm) { if (xml_strlen(VAL_STR(parm))) { parmval = VAL_STR(parm); } else { parmval = get_aliases_file(); } res = save_aliases(parmval); if (res == NO_ERR) { log_info("\nSaved aliases OK to '%s'\n", parmval); } else if (res != ERR_NCX_CANCELED) { log_error("\nSave aliases to '%s' failed (%s)\n", parmval, get_error_string(res)); } done = TRUE; } } if (!done) { /* no parameters; show all aliases */ show_aliases(); } } if (valset) { val_free_value(valset); } return res; } /* do_aliases */
/******************************************************************** * FUNCTION set_server_profile * * Get the initial agent profile variables for now * Set the agt_profile data structure * * INPUTS: * valset == value set for CLI parsing or NULL if none * agt_profile == pointer to profile struct to fill in * * OUTPUTS: * *agt_profile is filled in with params of defaults * *********************************************************************/ static void set_server_profile (val_value_t *valset, agt_profile_t *agt_profile) { val_value_t *val; uint32 i; boolean done; /* check if there is any CLI data to read */ if (valset == NULL) { /* assumes agt_profile already has default values */ return; } /* check all the netconfd CLI parameters; * follow the order in netconfd.yang since * no action will be taken until all params are collected * * conf=filespec param checked externally */ /* get access-control param */ val = val_find_child(valset, AGT_CLI_MODULE, NCX_EL_ACCESS_CONTROL); if (val && val->res == NO_ERR) { agt_profile->agt_accesscontrol = VAL_ENUM_NAME(val); } if (agt_profile->agt_accesscontrol) { if (!xml_strcmp(agt_profile->agt_accesscontrol, NCX_EL_ENFORCING)) { agt_profile->agt_accesscontrol_enum = AGT_ACMOD_ENFORCING; } else if (!xml_strcmp(agt_profile->agt_accesscontrol, NCX_EL_PERMISSIVE)) { agt_profile->agt_accesscontrol_enum = AGT_ACMOD_PERMISSIVE; } else if (!xml_strcmp(agt_profile->agt_accesscontrol, NCX_EL_DISABLED)) { agt_profile->agt_accesscontrol_enum = AGT_ACMOD_DISABLED; } else if (!xml_strcmp(agt_profile->agt_accesscontrol, NCX_EL_OFF)) { agt_profile->agt_accesscontrol_enum = AGT_ACMOD_OFF; } else { SET_ERROR(ERR_INTERNAL_VAL); agt_profile->agt_accesscontrol_enum = AGT_ACMOD_ENFORCING; } } else { agt_profile->agt_accesscontrol_enum = AGT_ACMOD_ENFORCING; } /* get default-style param */ val = val_find_child(valset, AGT_CLI_MODULE, NCX_EL_DEFAULT_STYLE); if (val && val->res == NO_ERR) { agt_profile->agt_defaultStyle = VAL_ENUM_NAME(val); agt_profile->agt_defaultStyleEnum = ncx_get_withdefaults_enum(VAL_ENUM_NAME(val)); } /* help parameter checked externally */ /* the logging parameters might have already been * set in the bootstrap CLI (cli_parse_raw) * they may get reset here, if the conf file has * a different value selected */ /* get delete-empty-npcontainters param */ val = val_find_child(valset, AGT_CLI_MODULE, AGT_CLI_DELETE_EMPTY_NPCONTAINERS); if (val && val->res == NO_ERR) { agt_profile->agt_delete_empty_npcontainers = VAL_BOOL(val); } else { agt_profile->agt_delete_empty_npcontainers = AGT_DEF_DELETE_EMPTY_NP; } /* get indent param */ val = val_find_child(valset, AGT_CLI_MODULE, NCX_EL_INDENT); if (val && val->res == NO_ERR) { agt_profile->agt_indent = (int32)VAL_UINT(val); } /* get log param */ val = val_find_child(valset, AGT_CLI_MODULE, NCX_EL_LOG); if (val && val->res == NO_ERR) { agt_profile->agt_logfile = VAL_STR(val); } /* get log-append param */ val = val_find_child(valset, AGT_CLI_MODULE, NCX_EL_LOGAPPEND); if (val && val->res == NO_ERR) { agt_profile->agt_logappend = TRUE; } /* get log-level param */ val = val_find_child(valset, AGT_CLI_MODULE, NCX_EL_LOGLEVEL); if (val && val->res == NO_ERR) { agt_profile->agt_loglevel = log_get_debug_level_enum((const char *)VAL_STR(val)); } /* -------------------- LEVI -------------------------*/ /* port is now a leaf, and not leaf-list /* get leaf-list port parameter */ // val = val_find_child(valset, AGT_CLI_MODULE, NCX_EL_PORT); // if (val && val->res == NO_ERR) { // agt_profile->agt_ports[0] = VAL_UINT16(val); // // val = val_find_next_child(valset, AGT_CLI_MODULE, // NCX_EL_PORT, val); // while (val) { // done = FALSE; // for (i = 0; i < AGT_MAX_PORTS && !done; i++) { // if (agt_profile->agt_ports[i] == VAL_UINT16(val)) { // done = TRUE; // } else if (agt_profile->agt_ports[i] == 0) { // agt_profile->agt_ports[i] = VAL_UINT16(val); // done = TRUE; // } // } // val = val_find_next_child(valset, AGT_CLI_MODULE, // NCX_EL_PORT, val); // } // } /* getting the port params */ val = val_find_child(valset, AGT_CLI_MODULE, NCX_EL_PORT); if (val && val->res == NO_ERR) { agt_profile->agt_port = VAL_UINT(val); } /* ---------------- END LEVI -------------------------*/ /* eventlog-size param */ val = val_find_child(valset, AGT_CLI_MODULE, NCX_EL_EVENTLOG_SIZE); if (val && val->res == NO_ERR) { agt_profile->agt_eventlog_size = VAL_UINT(val); } /* get hello-timeout param */ val = val_find_child(valset, AGT_CLI_MODULE, NCX_EL_HELLO_TIMEOUT); if (val && val->res == NO_ERR) { agt_profile->agt_hello_timeout = VAL_UINT(val); } /* get idle-timeout param */ val = val_find_child(valset, AGT_CLI_MODULE, NCX_EL_IDLE_TIMEOUT); if (val && val->res == NO_ERR) { agt_profile->agt_idle_timeout = VAL_UINT(val); } /* max-burst param */ val = val_find_child(valset, AGT_CLI_MODULE, AGT_CLI_MAX_BURST); if (val && val->res == NO_ERR) { agt_profile->agt_maxburst = VAL_UINT(val); } /* running-error param */ val = val_find_child(valset, AGT_CLI_MODULE, AGT_CLI_RUNNING_ERROR); if (val && val->res == NO_ERR) { if (!xml_strcmp(VAL_ENUM_NAME(val), AGT_CLI_STARTUP_STOP)) { agt_profile->agt_running_error = TRUE; } } /* start choice: * cli module will check that only 1 of the following 3 * parms are actually entered * start choice 1: get no-startup param */ val = val_find_child(valset, AGT_CLI_MODULE, AGT_CLI_NOSTARTUP); if (val && val->res == NO_ERR) { agt_profile->agt_usestartup = FALSE; } /* start choice 2: OR get startup param */ val = val_find_child(valset, AGT_CLI_MODULE, AGT_CLI_STARTUP); if (val && val->res == NO_ERR) { agt_profile->agt_startup = VAL_STR(val); } /* start choice 3: OR get factory-startup param */ val = val_find_child(valset, AGT_CLI_MODULE, AGT_CLI_FACTORY_STARTUP); if (val && val->res == NO_ERR) { agt_profile->agt_factorystartup = TRUE; } /* startup-error param */ val = val_find_child(valset, AGT_CLI_MODULE, AGT_CLI_STARTUP_ERROR); if (val && val->res == NO_ERR) { if (!xml_strcmp(VAL_ENUM_NAME(val), AGT_CLI_STARTUP_STOP)) { agt_profile->agt_startup_error = TRUE; } } /* superuser param */ val = val_find_child(valset, AGT_CLI_MODULE, AGT_CLI_SUPERUSER); if (val && val->res == NO_ERR) { agt_profile->agt_superuser = VAL_STR(val); } /* get target param */ val = val_find_child(valset, AGT_CLI_MODULE, NCX_EL_TARGET); if (val && val->res == NO_ERR) { if (!xml_strcmp(VAL_ENUM_NAME(val), NCX_EL_RUNNING)) { agt_profile->agt_targ = NCX_AGT_TARG_RUNNING; } else if (!xml_strcmp(VAL_ENUM_NAME(val), NCX_EL_CANDIDATE)) { agt_profile->agt_targ = NCX_AGT_TARG_CANDIDATE; } } /* get the :startup capability setting */ val = val_find_child(valset, AGT_CLI_MODULE, NCX_EL_WITH_STARTUP); if (val && val->res == NO_ERR) { if (VAL_BOOL(val)) { agt_profile->agt_start = NCX_AGT_START_DISTINCT; agt_profile->agt_has_startup = TRUE; } else { agt_profile->agt_start = NCX_AGT_START_MIRROR; agt_profile->agt_has_startup = FALSE; } } /* check the subdirs parameter */ val_set_subdirs_parm(valset); /* version param handled externally */ /* get usexmlorder param */ val = val_find_child(valset, AGT_CLI_MODULE, NCX_EL_USEXMLORDER); if (val && val->res == NO_ERR) { agt_profile->agt_xmlorder = TRUE; } /* get the :url capability setting */ val = val_find_child(valset, AGT_CLI_MODULE, NCX_EL_WITH_URL); if (val && val->res == NO_ERR) { agt_profile->agt_useurl = VAL_BOOL(val); } /* get with-validate param */ val = val_find_child(valset, AGT_CLI_MODULE, NCX_EL_WITH_VALIDATE); if (val && val->res == NO_ERR) { agt_profile->agt_usevalidate = VAL_BOOL(val); } } /* set_server_profile */
/******************************************************************** * FUNCTION parse_parm * * Parse, and fill one val_value_t struct during * processing of a parmset * * Error messages are printed by this function!! * Do not duplicate error messages upon error return * * * INPUTS: * tkc == token chain * val == container val to fill in * keepvals == TRUE to save existing parms in 'ps', as needed * FALSE to overwrite old parms in 'ps', as needed * * RETURNS: * status of the operation *********************************************************************/ static status_t parse_parm (tk_chain_t *tkc, val_value_t *val, boolean keepvals) { obj_template_t *obj; const xmlChar *modname; val_value_t *curparm, *newparm; status_t res; ncx_iqual_t iqual; boolean match, usewarning, isdefault; /* get the next token, which must be a TSTRING * representing the parameter name */ if (TK_CUR_TYP(tkc) != TK_TT_TSTRING) { res = ERR_NCX_WRONG_TKTYPE; ncx_conf_exp_err(tkc, res, "parameter name"); return res; } curparm = NULL; usewarning = ncx_warning_enabled(ERR_NCX_CONF_PARM_EXISTS); /* check if this TSTRING is a parameter in this parmset * make sure to always check for prefix:identifier * This is automatically processed in tk.c */ if (TK_CUR_MOD(tkc)) { modname = xmlns_get_module (xmlns_find_ns_by_prefix(TK_CUR_MOD(tkc))); if (modname) { curparm = val_find_child(val, modname, TK_CUR_VAL(tkc)); } } else { curparm = val_find_child(val, val_get_mod_name(val), TK_CUR_VAL(tkc)); } if (curparm) { obj = curparm->obj; } else { obj = obj_find_child(val->obj, TK_CUR_MOD(tkc), TK_CUR_VAL(tkc)); } if (!obj) { res = ERR_NCX_UNKNOWN_PARM; if (TK_CUR_MOD(tkc)) { log_error("\nError: parameter '%s:%s' not found", TK_CUR_MOD(tkc), TK_CUR_VAL(tkc)); } else { log_error("\nError: parameter '%s' not found", TK_CUR_VAL(tkc)); } ncx_conf_exp_err(tkc, res, "parameter name"); return res; } /* got a valid parameter name, now create a new parm * even if it may not be kept. There are corner-cases * that require the new value be parsed before knowing * if a parm value is a duplicate or not */ newparm = val_new_value(); if (!newparm) { res = ERR_INTERNAL_MEM; ncx_print_errormsg(tkc, NULL, res); return res; } val_init_from_template(newparm, obj); /* parse the parameter value */ res = parse_val(tkc, obj, newparm); if (res != NO_ERR) { val_free_value(newparm); return res; } /* check if a potential current value exists, or just * add the newparm to the parmset */ if (curparm) { isdefault = val_set_by_default(curparm); iqual = obj_get_iqualval(obj); if (iqual == NCX_IQUAL_ONE || iqual == NCX_IQUAL_OPT) { /* only one allowed, check really a match */ match = TRUE; if (val_has_index(curparm) && !val_index_match(newparm, curparm)) { match = FALSE; } if (!match) { val_add_child(newparm, val); } else if (isdefault) { dlq_remove(curparm); val_free_value(curparm); val_add_child(newparm, val); } else if (keepvals) { if (usewarning) { /* keep current value and toss new value */ log_warn("\nWarning: Parameter '%s' already exists. " "Not using new value\n", curparm->name); if (LOGDEBUG2) { val_dump_value(newparm, NCX_DEF_INDENT); log_debug2("\n"); } } val_free_value(newparm); } else { if (usewarning) { /* replace current value and warn old value tossed */ log_warn("\nconf: Parameter '%s' already exists. " "Overwriting with new value\n", curparm->name); if (LOGDEBUG2) { val_dump_value(newparm, NCX_DEF_INDENT); log_debug2("\n"); } } dlq_remove(curparm); val_free_value(curparm); val_add_child(newparm, val); } } else { /* mutliple instances allowed */ val_add_child(newparm, val); } } else { val_add_child(newparm, val); } return NO_ERR; } /* parse_parm */
/******************************************************************** * 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 do_show (local RPC) * * show module=mod-name * modules * def=def-nmae * * Get the specified parameter and show the internal info, * based on the parameter * * INPUTS: * server_cb == server control block to use * rpc == RPC method for the show command * line == CLI input in progress * len == offset into line buffer to start parsing * * RETURNS: * status *********************************************************************/ status_t do_show (server_cb_t *server_cb, obj_template_t *rpc, const xmlChar *line, uint32 len) { val_value_t *valset, *parm; ncx_module_t *mod; status_t res; boolean imode, done; help_mode_t mode; xmlChar versionbuffer[NCX_VERSION_BUFFSIZE]; res = NO_ERR; imode = interactive_mode(); valset = get_valset(server_cb, rpc, &line[len], &res); if (valset && res == NO_ERR) { mode = HELP_MODE_NORMAL; /* check if the 'brief' flag is set first */ parm = val_find_child(valset, YANGCLI_MOD, YANGCLI_BRIEF); if (parm && parm->res == NO_ERR) { mode = HELP_MODE_BRIEF; } else { parm = val_find_child(valset, YANGCLI_MOD, YANGCLI_FULL); if (parm && parm->res == NO_ERR) { mode = HELP_MODE_FULL; } } /* get the 1 of N 'showtype' choice */ done = FALSE; /* show cli */ parm = val_find_child(valset, YANGCLI_MOD, YANGCLI_CLI); if (parm) { do_show_cli(server_cb); done = TRUE; } /* show local <foo> */ if (!done) { parm = val_find_child(valset, YANGCLI_MOD, YANGCLI_LOCAL); if (parm) { res = do_show_var(server_cb, VAL_STR(parm), VAR_TYP_LOCAL, FALSE, mode); done = TRUE; } } /* show locals */ if (!done) { parm = val_find_child(valset, YANGCLI_MOD, YANGCLI_LOCALS); if (parm) { res = do_show_vars(server_cb, mode, TRUE, FALSE, FALSE); done = TRUE; } } /* show objects */ if (!done) { parm = val_find_child(valset, YANGCLI_MOD, YANGCLI_OBJECTS); if (parm) { res = do_show_objects(server_cb, mode); done = TRUE; } } /* show global */ if (!done) { parm = val_find_child(valset, YANGCLI_MOD, YANGCLI_GLOBAL); if (parm) { res = do_show_var(server_cb, VAL_STR(parm), VAR_TYP_GLOBAL, FALSE, mode); done = TRUE; } } /* show globals */ if (!done) { parm = val_find_child(valset, YANGCLI_MOD, YANGCLI_GLOBALS); if (parm) { res = do_show_vars(server_cb, mode, TRUE, TRUE, FALSE); done = TRUE; } } /* show session */ parm = val_find_child(valset, YANGCLI_MOD, YANGCLI_SESSION); if (parm) { do_show_session(server_cb, mode); done = TRUE; } /* show system */ parm = val_find_child(valset, YANGCLI_MOD, YANGCLI_SYSTEM); if (parm) { do_show_system(server_cb, mode); done = TRUE; } /* show var <foo> */ if (!done) { parm = val_find_child(valset, YANGCLI_MOD, YANGCLI_VAR); if (parm) { res = do_show_var(server_cb, VAL_STR(parm), VAR_TYP_NONE, TRUE, mode); done = TRUE; } } /* show vars */ if (!done) { parm = val_find_child(valset, YANGCLI_MOD, YANGCLI_VARS); if (parm) { res = do_show_vars(server_cb, mode, FALSE, FALSE, TRUE); done = TRUE; } } /* show module <foo> */ if (!done) { parm = val_find_child(valset, YANGCLI_MOD, YANGCLI_MODULE); if (parm) { mod = find_module(server_cb, VAL_STR(parm)); if (mod) { res = do_show_module(mod, mode); } else { if (imode) { log_stdout("\nyangcli-pro: module (%s) not loaded", VAL_STR(parm)); } else { log_error("\nyangcli-pro: module (%s) not loaded", VAL_STR(parm)); } } done = TRUE; } } /* show modules */ if (!done) { parm = val_find_child(valset, YANGCLI_MOD, YANGCLI_MODULES); if (parm) { res = do_show_modules(server_cb, mode); done = TRUE; } } /* show version */ if (!done) { parm = val_find_child(valset, YANGCLI_MOD, NCX_EL_VERSION); if (parm) { res = ncx_get_version(versionbuffer, NCX_VERSION_BUFFSIZE); if (res == NO_ERR) { if (imode) { log_stdout("\nyangcli version %s\n", versionbuffer); } else { log_write("\nyangcli version %s\n", versionbuffer); } } done = TRUE; } } } if (valset) { val_free_value(valset); } return res; } /* do_show */
/******************************************************************** * FUNCTION y_toaster_make_toast_validate * * RPC validation phase * All YANG constriants have passed at this point. * Add description-stmt checks in this function. * * INPUTS: * see agt/agt_rpc.h for details * * RETURNS: * error status ********************************************************************/ static status_t y_toaster_make_toast_validate ( ses_cb_t *scb, rpc_msg_t *msg, xml_node_t *methnode) { status_t res; val_value_t *errorval; const xmlChar *errorstr; val_value_t *toasterDoneness_val; val_value_t *toasterToastType_val; //uint32 toasterDoneness; //val_idref_t *toasterToastType; res = NO_ERR; errorval = NULL; errorstr = NULL; toasterDoneness_val = val_find_child( msg->rpc_input, y_toaster_M_toaster, y_toaster_N_toasterDoneness); if (toasterDoneness_val != NULL && toasterDoneness_val->res == NO_ERR) { //toasterDoneness = VAL_UINT(toasterDoneness_val); // validate toast doneness within instrumentation if needed } toasterToastType_val = val_find_child( msg->rpc_input, y_toaster_M_toaster, y_toaster_N_toasterToastType); if (toasterToastType_val != NULL && toasterToastType_val->res == NO_ERR) { //toasterToastType = VAL_IDREF(toasterToastType_val); // validate toast-type within instrumentation if needed } /* added code starts here */ if (toaster_enabled) { /* toaster service enabled, check if in use */ if (toaster_toasting) { res = ERR_NCX_IN_USE; } else { /* this is where a check on bread inventory would go */ /* this is where a check on toaster HW ready would go */ } } else { /* toaster service disabled */ res = ERR_NCX_RESOURCE_DENIED; } /* added code ends here */ /* if error: set the res, errorstr, and errorval parms */ if (res != NO_ERR) { agt_record_error( scb, &msg->mhdr, NCX_LAYER_OPERATION, res, methnode, NCX_NT_STRING, errorstr, NCX_NT_VAL, errorval); } return res; } /* y_toaster_make_toast_validate */
/******************************************************************** * FUNCTION y_toaster_make_toast_invoke * * RPC invocation phase * All constraints have passed at this point. * Call device instrumentation code in this function. * * INPUTS: * see agt/agt_rpc.h for details * * RETURNS: * error status ********************************************************************/ static status_t y_toaster_make_toast_invoke ( ses_cb_t *scb, rpc_msg_t *msg, xml_node_t *methnode) { status_t res; val_value_t *toasterDoneness_val; val_value_t *toasterToastType_val; uint32 toasterDoneness; //val_idref_t *toasterToastType; res = NO_ERR; toasterDoneness = 0; toasterDoneness_val = val_find_child( msg->rpc_input, y_toaster_M_toaster, y_toaster_N_toasterDoneness); if (toasterDoneness_val != NULL && toasterDoneness_val->res == NO_ERR) { toasterDoneness = VAL_UINT(toasterDoneness_val); } toasterToastType_val = val_find_child( msg->rpc_input, y_toaster_M_toaster, y_toaster_N_toasterToastType); if (toasterToastType_val != NULL && toasterToastType_val->res == NO_ERR) { //toasterToastType = VAL_IDREF(toasterToastType_val); // invoke instrumentation with this toast type } /* invoke your device instrumentation code here */ /* make sure the toasterDoneness value is set */ if (toasterDoneness_val == NULL) { toasterDoneness = 5; /* set the default */ } /* arbitrary formula to convert toaster doneness to the * number of seconds the toaster should be on */ toaster_duration = toasterDoneness * 12; /* this is where the code would go to adjust the duration * based on the bread type */ if (LOGDEBUG) { log_debug("\ntoaster: starting toaster for %u seconds", toaster_duration); } /* this is where the code would go to start the toaster * heater element */ /* start a timer to toast for the specified time interval */ res = agt_timer_create(toaster_duration, FALSE, toaster_timer_fn, NULL, &toaster_timer_id); if (res == NO_ERR) { toaster_toasting = TRUE; } else { agt_record_error( scb, &msg->mhdr, NCX_LAYER_OPERATION, res, methnode, NCX_NT_NONE, NULL, NCX_NT_NONE, NULL); } /* added code ends here */ return res; } /* y_toaster_make_toast_invoke */