System Callbacks
The callback functions described in this section are invoked as part of normal server operation.
They can be registered from the yp-system library module or a SIL module. Some internal functions are documented as well. These are needed by the system and multiple callbacks are not supported.
Refer to the file
/usr/share/yumapro/src/libsystem/src/example-system.c
for examples
of the callbacks in this section.
Note
System Callback code can be in a SIL library or the yp-system library.
API |
Description |
---|---|
cfg_reload_candidate_cb_t: Invoked each time the candidate datastore is reloaded from the running datastore, such as the <discard-changes> operation. |
|
ncx_load_cbfn_t: Invoked when a module is loaded into the server. |
|
ncx_unload_cbfn_t: Invoked when a module is unloaded from the server. |
|
agt_replay_fn_t: Invoked when a configuration replay procedure is started or finished. |
|
agt_nvload_fn_t: Invoked when the server needs to retrieve the configuration contents from non-volatile storage. |
|
agt_nvsave_fn_t: Invoked when the configuration needs to be saved to Non-Volatile storage. |
|
agt_timer_fn_t: Invoked periodically (1-shot or repeat) to do a short amount of work, and not block the running process. |
|
agt_cb_session_hook_t: Invoked when a session starts and ends. |
|
agt_cb_shutdown_t: Invoked when the server is about to restart or shutdown. |
|
agt_cb_command_complete_t: Invoked when the server has completed an RPC operation and the response has been generated to the client (may not have been sent yet). |
|
agt_acm_group_cbfn_t: Invoked when the server creates a new client session for NETCONF or RESTCONF sessions. It is used to retrieve a list of group names that should be used, as defined in RFC 8341 |
|
Invoked when a data node needs to be processed to process the value as it is being created. |
|
Invoked when there are no other EDIT callbacks set up. |
|
Invoked when there are no other GET callbacks set up. |
|
Invoked when there are no other RPC callbacks set up. |
|
Invoked when there are no other Action callbacks set up. |
Candidate Reload Callback
The Candidate Reload callback is an internal system callback that is used to clear some cached validation data when the running configuration is loaded into the candidate datastore.
Note
This is an internal API and cannot be replaced. Do not use.
There can be one callback registered to be invoked each time the candidate datastore is reloaded from the running datastore, such as the <discard-changes> operation, or anytime the candidate is filled in from <startup>, <running>, or inline configuration.
If the server is run with the :writable-running capability the callback will not be available since the <candidate> datastore is not present when the capability is used. The --target CLI parameter is used to control this behavior.
Module Load Callback
The Module Load callback is a user/system callback that is invoked when a YANG module is loaded into the server. This callback is only invoked for main modules, not submodules.
The following function template definition is used for Module Load callback functions:
-
typedef void (*ncx_load_cbfn_t)(ncx_module_t *mod)
user function callback template when a module is loaded into the system
ncx_load_cbfn_t
Run an instrumentation-defined function for a 'module-loaded' event
- Param mod:
module that was added to the registry
The 'mod' pointer represents a module control block structure that is defined in the
netconf/src/ncx/ncxtypes.h
.This control block is a representation of one module or submodule during and after parsing.
It provides access to the module specific information, such as module name, revision, prefix, and other module specific information.
Note: do not alter any fields in this structure
Module Load Callback Initialization and Cleanup
The 'ncx_set_load_callback' function is used to declare the Module Load callback. The registration can be done during the Initialization Phase 2 after the running configuration has been loaded from the startup file. It can actually be done at any time, as needed.
-
status_t ncx_set_load_callback(ncx_load_cbfn_t cbfn)
Set the callback function for a load-module event.
- Parameters:
cbfn -- callback function to use
- Returns:
status
Example registration function usage:
static status_t interfaces_init2 (void)
{
// ...
/* register load module callback */
res = ncx_set_load_callback(add_module_callback);
if (res != NO_ERR) {
return res;
}
// ...
}
The 'ncx_clear_load_callback' function is used to unload the Module Load callback.
-
void ncx_clear_load_callback(ncx_load_cbfn_t cbfn)
Clear the callback function for a load-module event.
- Parameters:
cbfn -- callback function to use
Example un-register function usage:
void interfaces_cleanup (void)
{
// ...
ncx_clear_load_callback(add_module_callback);
...
}
Module Load Callback Function Example
The 'load_module_callback' function is used to record a backptr for each module or imported module that is encountered during the <load> operation.
static void load_module_callback (ncx_module_t *mod)
{
ncx_backptr_t *backptr = ncx_new_backptr(mod);
if (backptr == NULL) {
log_error("\nError: malloc backptr failed");
return;
}
dlq_enque(backptr, &added_moduleQ);
} /* load_module_callback */
The 'do_load_module' function is located in agt/agt_ncx_load.c
.
It is used to load a module at runtime.
It does the following operations:
registers the callback
saves backptrs during the module load
reads the saved backptrs after the module load
unregisters the callback
cleans up the saved backptrs
static status_t
do_module_load (ses_cb_t *scb,
rpc_msg_t *msg,
const xmlChar *modname,
const xmlChar *revision,
ncx_module_t **retmod)
{
boolean callback_loaded = FALSE;
ncx_module_t *mod = NULL;
boolean already_loaded =
ncx_find_module(modname, revision) ? TRUE : FALSE;
*retmod = NULL;
/* save all the loaded modules including imported modules */
status_t res = ncx_set_load_callback(load_module_callback);
if (res == NO_ERR) {
callback_loaded = TRUE;
} else {
return res;
}
#ifdef STATIC_SERVER
res = ncxmod_load_module(modname,
revision,
agt_get_savedevQ(),
&mod);
#else
res = agt_load_sil_code(modname,
revision,
TRUE,
AGT_SILTYP_MODULE,
FALSE);
if (res == ERR_NCX_SKIPPED) {
log_warn("\nWarning: SIL code for module '%s' not found",
modname);
res = ncxmod_load_module(modname,
revision,
agt_get_savedevQ(),
&mod);
if (res == NO_ERR && mod) {
ncx_set_mod_unloadable(mod);
}
}
#endif // STATIC_SERVER
/* reget the module; it should be found if status == NO_ERR */
if (res == NO_ERR) {
mod = ncx_find_module(modname, revision);
if (mod) {
/* use the list in added_moduleQ not just this 1 module
* this tracks the imports loaded dynamically as well
* as the main module loaded by the <load> operation
*/
res = process_loaded_modules(scb, msg, NULL);
} else {
res = ERR_NCX_OPERATION_FAILED;
}
}
if (callback_loaded) {
ncx_clear_load_callback(load_module_callback);
}
/* done with the added_moduleQ; just used to process modules
* not to save the list of loaded modules (load_moduleQ)
*/
ncx_clean_backptrQ(&added_moduleQ);
if (res == NO_ERR) {
SET_MOD_SIL_LOADED(mod);
*retmod = mod;
if (!already_loaded) {
/* add to the load_moduleQ */
add_loaded_module(modname);
}
}
return res;
} /* do_module_load */
The following functions may be used to obtain required information from the loaded module:
ncx_get_modname() - Get the main module name
ncx_get_mod_nsid() - Get the main module namespace ID
ncx_get_modversion() - Get the module version
ncx_get_modnamespace() - Get the module namespace URI
-
const xmlChar *ncx_get_modname(const ncx_module_t *mod)
Get the main module name.
- Parameters:
mod -- module or submodule to get main module name
- Returns:
main module name or NULL if error
-
xmlns_id_t ncx_get_mod_nsid(const ncx_module_t *mod)
Get the main module namespace ID.
- Parameters:
mod -- module or submodule to get main module namespace ID
- Returns:
namespace id number
-
const xmlChar *ncx_get_modversion(const ncx_module_t *mod)
Get the [sub]module version.
- Parameters:
mod -- module or submodule to get module version
- Returns:
module version or NULL if error
-
const xmlChar *ncx_get_modnamespace(const ncx_module_t *mod)
Get the module namespace URI.
- Parameters:
mod -- module or submodule to get module namespace
- Returns:
module namespace or NULL if error
Module Unload Callback
The Module Unload callback is a user/system callback that is invoked when a YANG module is unloaded from the server. This callback is only invoked for main modules, not submodules.
The following function template definition is used for Module Unload callback functions:
-
typedef void (*ncx_unload_cbfn_t)(ncx_module_t *mod)
user function callback template when a module is unloaded from the system
ncx_unload_cbfn_t
Run an instrumentation-defined function for a 'module-loaded' event
- Param mod:
module that is being removed
The 'mod' pointer represents a module control block structure that is defined in the
netconf/src/ncx/ncxtypes.h
.This control block is a representation of one module or submodule during and after parsing.
It provides access to the module specific information, such as module name, revision, prefix, and other module specific information.
Note: do not alter any fields in this structure
Module Unload Callback Initialization and Cleanup
The 'ncx_set_unload_callback' function is used to declare the Module Unload callback. The registration can be done during the Initialization Phase 2 after the running configuration has been loaded from the startup file. It can actually be done at any time, as needed.
-
status_t ncx_set_unload_callback(ncx_unload_cbfn_t cbfn)
Set the callback function for an unload-module event.
- Parameters:
cbfn -- callback function to use
- Returns:
status
Example Module Unload register usage:
static status_t interfaces_init2 (void)
{
// ...
/* register unload module callback */
res = ncx_set_unload_callback(remove_module_callback);
if (res != NO_ERR) {
return res;
}
// ...
}
The 'ncx_clear_unload_callback' function is used to unload the Module Unload callback.
-
void ncx_clear_unload_callback(ncx_unload_cbfn_t cbfn)
Clear the callback function for an unload-module event.
- Parameters:
cbfn -- callback function to use
Example Module Unload un-register usage:
void interfaces_cleanup (void)
{
// ...
ncx_clear_unload_callback(remove_module_callback);
// ...
}
Module Unload Callback Function Example
In this example, the callback code will find a val_value_t tree, based on the information from 'mod' pointer, and remove it from the static data list.
/********************************************************************
* FUNCTION remove_module
*
* Remove a module entry from the static modules list
*
* INPUTS:
* mod == module to remove
*
********************************************************************/
static void
remove_module (ncx_module_t *mod)
{
xmlns_id_t nsid = val_get_nsid(mymodules_val);
val_value_t *module = val_get_first_child(mymodules_val);
for (; module; module = val_get_next_child(module)) {
val_value_t *checkval =
val_find_child_fast(module, nsid, (const xmlChar *)"name");
/* check the module name, if it match, remove the module from the list */
if (checkval) {
if (xml_strcmp(VAL_STR(checkval), ncx_get_modname(mod))) {
continue;
}
} else {
continue; // error
}
/* check the module revision, if it match, remove the module from the list */
if (ncx_get_modversion(mod)) {
checkval =
val_find_child_fast(module, nsid, (const xmlChar *)"revision");
if (checkval) {
if (xml_strcmp(VAL_STR(checkval), ncx_get_modversion(mod))) {
continue;
}
} else {
continue; // error!
}
}
val_remove_child(module);
val_free_value(module);
return;
}
} /* remove_module */
Config Replay Callback
The Config Replay callback is a user callback that is invoked when the replay configuration procedure is started and finished.
Only one callback function can be registered.
Refer to the Configuration Replay section for complete details on triggering a Configuration Replay procedure.
The following function template definition is used for Config Replay callback functions:
-
typedef void (*agt_replay_fn_t)(boolean is_start)
replay callback (agt_replay_fn_t)
this callback is invoked when a configuration replay is started or finished, which has been triggered by a call to agt_request_replay()
- Param is_start:
TRUE if start; FALSE if finish
Config Replay Callback Initialization and Cleanup
The 'agt_register_replay_callback' function is used to register this callback.
-
void agt_register_replay_callback(agt_replay_fn_t cbfn)
Register a callback function for a replay config event.
- Parameters:
cbfn -- replay function to use (==NULL to clear)
Example Config Replay register usage:
static status_t interfaces_init2 (void)
{
// ...
/* register config replay callback */
res = agt_register_replay_callback(replay_callback);
if (res != NO_ERR) {
return res;
}
// ...
}
There is no unregister function for this callback. The server will cleanup the system automatically during shutdown.
Config Replay Callback Example
static void replay_callback (boolean is_start)
{
if (is_start) {
log_debug("\nConfig Replay is starting");
} else {
log_debug("\nConfig Replay is ending");
}
}
NV-Load Callback
The NV-Load callback function is a user callback that is invoked when the running configuration needs to be read from non-volatile storage.
This callback is used to provide the server with an XML file instead of the default from the --config CLI parameter.
The server will invoke this callback to get the file name and file encoding of the startup configuration file.
Only XML encoding is supported at this time.
Only one callback can be registered.
The
check_load_external_config
function inagt/agt.c
will check this callback during the <load-config> operation.This callback will not be used if the --no-nvstore CLI parameter is used.
Note
If the callback returns NO_ERR
and *filespec is empty then
the server will use the factory configuration.
The following function template definition is used for the NV-Load callback function:
-
typedef status_t (*agt_nvload_fn_t)(ncx_display_mode_t *encoding, xmlChar **filespec)
nvload callback
this callback is invoked when some config needs to be read from non-volatile storage
- Param encoding:
[out]
address of encoding for the config
*encoding set to the enum for the encoding used in the config
- Param filespec:
[out]
address of filespec containing the config that was loaded
*filespec malloced filespec containing the config that was loaded
== NULL if loading the factory default config- Return:
status; error indicates NV-load failed somehow If return NO_ERR and *filespec == NULL then use the factory config
NV-Load Callback Initialization and Cleanup
The 'agt_register_local_nv_handler' function is used to declare the NV-Load callback. The registration can be done during the Initialization Phase 2, after the running configuration has been loaded from the startup file.
-
status_t agt_register_local_nv_handler(agt_nvload_fn_t load_fn, agt_nvsave_fn_t store_fn)
Register a set of nvstore and nvload callback functions to handle the non-volatile storage of the configuration.
- Parameters:
load_fn -- NV-load callback function
store_fn -- NV-save callback function
- Returns:
status
static status_t interfaces_init2 (void)
{
// ...
/* register NV-storage handler to load/save config
* uncomment following to enable
*/
res = agt_register_local_nv_handler(nvload_callback,
nvsave_callback);
if (res != NO_ERR) {
return res;
}
// ...
}
There is no unregister function for this callback. The cleanup will be done automatically by the server.
NV-Load Callback Function Example
/********************************************************************
* FUNCTION nvload_callback
*
* this callback is invoked when some config needs to be read
* from non-volatile storage
*
* INPUTS:
* encoding == address of encoding for the config
* filespec == address of filespec containing the config that was loaded
*
* OUTPUTS:
* *encoding == set to the enum for the encoding used in the config
* *filespec == malloced filespec containing the config that was loaded
*
* RETURNS:
* status; error indicates NV-load failed somehow
* If return NO_ERR and *filespec == NULL then use the factory config
*
*********************************************************************/
static status_t
nvload_callback (ncx_display_mode_t *encoding,
xmlChar **filespec)
{
log_debug("\nEnter nvload_callback ");
*filespec = NULL;
*encoding = NCX_DISPLAY_MODE_XML;
status_t res = NO_ERR;
if (ncxmod_test_filespec(EXAMPLE_CONFIG_SPEC)) {
/* file exists so copy the filespec */
*filespec = xml_strdup(EXAMPLE_CONFIG_SPEC);
if (*filespec == NULL) {
res = ERR_INTERNAL_MEM;
}
}
return res;
} /* nvload_callback */
The following function is used in the example to search for the specified filespec:
-
boolean ncxmod_test_filespec(const xmlChar *filespec)
Check the exact filespec to see if it a file.
- Parameters:
filespec -- file spec to check
- Returns:
TRUE if valid readable file; FALSE otherwise
NV-Save Callback
The NV-Save callback function is a user callback that is invoked when the running configuration needs to be saved to non-volatile storage.
This callback is used to provide the system with an XML file to save, instead of the default from the --config CLI parameter.
The server will invoke this callback to pass the file name and file encoding of the configuration file to save.
Only XML encoding is supported at this time.
Only one callback can be registered.
The
agt_check_save_external_config
function inagt/agt.c
will check this callback during the "save-config" procedure.
The following function template definition is used for NV-Save callback functions:
-
typedef status_t (*agt_nvsave_fn_t)(ncx_display_mode_t encoding, const xmlChar *filespec)
brief nvsave callback
this callback is invoked when some config needs to be saved to non-volatile storage
- Param encoding:
encoding format for the config (xml only allowed value)
- Param filespec:
filespec containing the config to save
- Return:
status; error indicates NV-save failed somehow
NV-Save Callback Initialization and Cleanup
This callback is regered at the same time as the NV Load callback using the 'agt_register_local_nv_handler' function.
There is no cleanup function for this callback. The cleanup will be done automatically by the server.
Refer to the NV-Load Callback Initialization and Cleanup section for details.
NV-Save Callback Function Example
The following example can be found in example-system.c
.
#define EXAMPLE_CONFIG_SPEC (const xmlChar *)"/tmp/example-config.xml"
/********************************************************************
* FUNCTION example_nvsave
*
* Nvsave callback is invoked when some config needs to be saved
* to non-volatile storage
*
* INPUTS:
* encoding == encoding format for the config (xml only allowed value)
* filespec == filespec containing the config to save
*
* RETURNS:
* status; error indicates NV-save failed somehow
*
*********************************************************************/
static status_t
example_nvsave (ncx_display_mode_t encoding,
const xmlChar *filespec)
{
status_t res = NO_ERR;
if (filespec == NULL || *filespec == 0) {
res = ERR_NCX_INVALID_VALUE;
} else if (encoding != NCX_DISPLAY_MODE_XML) {
res = ERR_NCX_INVALID_VALUE;
} else {
res = ncxmod_copy_text_file(filespec, EXAMPLE_CONFIG_SPEC);
}
return res;
} /* example_nvsave */
Periodic Timer Service
Some SIL code may need to be called at periodic intervals to check system status, update counters, and/or perhaps send notifications.
The file agt/agt_timer.h
contains the timer access function
declarations.
This section provides a brief overview of the SIL timer service.
Timer Callback Function
The timer callback function is expected to do a short amount of work, and not block the running process. The function returns zero for a normal exit, and -1 if there was an error and the timer should be destroyed.
The 'agt_timer_fn_t' template in agt/agt_timer.h
is used to define
the SIL timer callback function prototype. This typedef defines the
callback function template expected by the server for use with the timer
service:
-
typedef int (*agt_timer_fn_t)(uint32 timer_id, void *cookie)
timer callback function
Provided the the SIL code registering the timer. It is expected to process the timer expired event.
- Param timer_id:
timer identifier
- Param cookie:
context pointer, such as a session control block, passed to agt_timer_set function (may be NULL)
- Return:
0 normal exit
-1 error exit, delete timer upon return
Timer Access Functions
A SIL timer can be set up as a periodic timer or a one-time event.
The timer interval (in seconds) and the SIL timer callback function are provided when the timer is created. A timer can also be restarted if it is running, and the time interval can be changed as well.
The following table highlights the SIL timer access functions in
agt/agt_timer.h
:
SIL Timer Access Functions
agt_timer_create |
Create a SIL timer. |
agt_timer_restart |
Restart a SIL timer |
agt_timer_delete |
Delete a SIL timer |
-
status_t agt_timer_create(uint32 seconds, boolean is_periodic, agt_timer_fn_t timer_fn, void *cookie, uint32 *ret_timer_id)
Malloc and start a new timer control block.
Main User API - FOr SIL only at this time
- Parameters:
seconds -- number of seconds to wait between polls
is_periodic --
TRUE if periodic timer
FALSE if a 1-event timer
timer_fn -- address of callback function to invoke when the timer poll event occurs
cookie -- address of user cookie to pass to the timer_fn ret_timer_id address of return timer ID
ret_timer_id -- [out]
address of return timer ID
*ret_timer_id timer ID for the allocated timer, if the return value is NO_ERR
- Returns:
NO_ERR if all okay, the minimum spare requests will be malloced
-
status_t agt_timer_restart(uint32 timer_id, uint32 seconds)
Restart a timer with a new timeout value.
If this is a periodic timer, then the interval will be changed to the new value. Otherwise a 1-shot timer will just be reset to the new value
- Parameters:
timer_id -- timer ID to reset
seconds -- new timeout value
- Returns:
status, NO_ERR if all okay,
-
void agt_timer_delete(uint32 timer_id)
Remove and delete a timer control block.
Periodic timers need to be deleted to be stopped 1-shot timers will be deleted automatically after they expire and the callback is invoked
- Parameters:
timer_id -- timer ID to destroy
Example Timer Callback Function
The following example from toaster.c simply completes the toast when the timer expires and calls the auto-generated 'toastDone' send notification function:
/********************************************************************
* FUNCTION toaster_timer_fn
*
* Added timeout function for toaster function
*
* INPUTS:
* see agt/agt_timer.h
*
* RETURNS:
* 0 for OK; -1 to kill periodic timer
********************************************************************/
static int
toaster_timer_fn (uint32 timer_id,
void *cookie)
{
(void)timer_id;
(void)cookie;
/* toast is finished */
toaster_toasting = FALSE;
toaster_timer_id = 0;
if (LOGDEBUG2) {
log_debug2("\ntoast is finished");
}
y_toaster_toastDone_send((const xmlChar *)"done");
return 0;
} /* toaster_timer_fn */
Session Hook Callback
The Session Hook callback function is a user callback that is invoked when a session starts and ends.
This callback is invoked before any data structures and components have been cleaned up and their data destroyed. It can be used to perform session end or start tasks that are not related to a specific YANG module.
Max Callbacks: No limit (except available heap memory)
File:
agt/agt\_cb.h
The following function template definition is used for Session Hook callback functions:
-
typedef void (*agt_cb_session_hook_t)(ncx_ses_event_t ses_event, const ses_cb_t *scb)
Typedef of the agt_cb_session_hook_t callback.
The Session Hook callback is invoked when a session starts and ends. Use ses.h macros like SES_MY_USERNAME(scb) to get data like client username. Max Callbacks: No limit (except available heap memory)
- Param ses_event:
session event type
- Param scb:
session control block for the session event
Session Hook Callback Initialization and Cleanup
The 'agt_cb_session_hook_register' function is used to declare the Session Hook callback. The registration can be done during the Initialization Phase, before or after the running configuration has been loaded from the startup file.
-
status_t agt_cb_session_hook_register(agt_cb_session_hook_t cbfn)
Register a Session Hook callback.
Max Callbacks: No limit (except available heap memory)
- Parameters:
cbfn -- address of callback function to use
- Returns:
the status of the operation.
Initialization function with the Session Hook callback registration may look as follows:
status_t
y_yumaworks_server_init (const xmlChar *modname,
const xmlChar *revision)
{
status_t res = NO_ERR;
// ... load module, etc.
/* Register a Session Hook callback */
res = agt_cb_session_hook_register(session_hook_callback);
return res;
}
The 'agt_cb_session_hook_unregister' function is used to cleanup this callback.
-
void agt_cb_session_hook_unregister(agt_cb_session_hook_t cbfn)
Unregister a Session Hook callback.
This function unregisters a Session Hook callback.
- Parameters:
cbfn -- address of callback function to use
The following example code illustrates how the Session Hook callback can be cleaned up.
void y_yumaworks_server_cleanup (void)
{
// ...
/* Unregister a Session Hook callback. */
agt_cb_session_hook_unregister(session_hook_callback);
// ...
}
Session Hook Callback Function Example
In the following example we are going to register Session Hook callbacks. In the callback function we are going to check if a session that is getting started is a RESTCONF session and the input encoding is XML and then will generate specific logging information for the current session. Refer to the attached YANG module and its SIL code for a complete example.
/********************************************************************
* FUNCTION session_hook_callback
*
* The Session Hook callback is invoked when a session starts
* and ends.
*
* INPUTS:
* ses_event == session event type
* scb == session control block for the session event
*
* RETURNS:
* status
********************************************************************/
static void
session_hook_callback (ncx_ses_event_t ses_event,
const ses_cb_t *scb)
{
if (LOGDEBUG) {
log_debug("\n\nEnter Session Hook callback for %s@%s",
SES_MY_USERNAME(scb) ? SES_MY_USERNAME(scb) : NCX_EL_NOBODY,
SES_PEERADDR(scb) ? SES_PEERADDR(scb) : NCX_EL_LOCALHOST);
}
/* Perform specific tasks when the session is ended or started
* and only if the current session protocol is RESTCONF
* and the session has an input that is encoded in XML
*/
ncx_display_mode_t input_mode = SES_IN_ENCODING(scb);
if (input_mode == NCX_DISPLAY_MODE_XML) {
if (SES_PROTOCOL(scb) == NCX_PROTO_RESTCONF) {
if (ses_event == NCX_SES_EVENT_START) {
if (LOGDEBUG) {
log_debug("\n ++++ Session Start ++++");
}
} else if (ses_event == NCX_SES_EVENT_END) {
if (LOGDEBUG) {
log_debug("\n ---- Session END ----");
}
}
}
}
return;
} /* session_hook_callback */
Shutdown Callback
The Shutdown callback function is a user callback that is invoked when the server is about to restart or shutdown.
This callback is invoked before any data structures and components have been cleaned up and their data destroyed. It can be used to perform on-exit tasks that are not related to a specific YANG module.
Max Callbacks: No limit (except available heap memory)
The following function template definition is used for Shutdown callback functions:
-
typedef void (*agt_cb_shutdown_t)(void)
Typedef of the agt_cb_shutdown_t callback.
The Shutdown callback is the user/system callback that is invoked at the start of a normal agt_cleanup A normal shutdown or restart is in progress. This callback is not invoked if the server crashes.
Max Callbacks: No limit (except available heap memory)
Shutdown Callback Initialization and Cleanup
The 'agt_cb_shutdown_register' function is used to declare the Shutdown callback. The registration can be done during the Initialization Phase 2, before or after the running configuration has been loaded from the startup file.
-
status_t agt_cb_shutdown_register(agt_cb_shutdown_t cbfn)
Register a Shutdown callback.
Max Callbacks: No limit (except available heap memory)
- Parameters:
cbfn -- address of callback function to use
- Returns:
the status of the operation.
Example Initialization function with the Shutdown callback registration:
static status_t server_init (void)
{
// ..
res = agt_cb_shutdown_register(server_shutdown_cb);
// ..
}
There is no cleanup function for this callback. The cleanup will be done automatically by the server.
Shutdown Callback Function Example
The following example code shows a Shutdown callback:
static void server_shutdown_cb (void)
{
// do some platform-specific cleanup
}
Command Complete Callback
The Command Complete callback function is a user callback that is invoked when the server has completed an RPC operation and the response has been generated to the client (may not have been sent yet). This callback can be used instead of a command-specific Post-RPC-Reply callback function.
Max Callbacks: No limit (except available heap memory)
The following function template definition is used for Command Complete callback functions:
-
typedef void (*agt_cb_command_complete_t)(ses_cb_t *scb, rpc_msg_t *msg, const xmlChar *command_modname, const xmlChar *command_name)
Typedef of the agt_command_complete_cb_t callback.
The Command Complete callback is the user/system callback that is invoked after each client command is executed for the NETCONF or RESTCONF protocols.
The Command Complete is typically used for retrieval operations (get, get-config, get-bulk) to release resources used during GET2 callbacks invoked during the operation.
Max Callbacks: No limit (except available heap memory)
- Param scb:
session control block making the request
- Param msg:
incoming rpc_msg_t in progress
- Param command_modname:
YANG module name of command that is completed
- Param command_name:
YANG RPC object name of command that is completed
Update in Release 23.10-11
RESTCONF Support: As of release 23.10-11, the Command Complete callback has been extended to support RESTCONF requests.
If the 'command_modname' is set to "RESTCONF", the 'command_name' will represent the RESTCONF method name (e.g., GET, POST, PATCH).
If the 'command_modname' is not set to "RESTCONF", NETCONF operations will be handled with a corresponding YANG "rpc" that has its own 'command_modname' and 'command_name'.
Command Complete Callback Initialization and Cleanup
The 'agt_cb_command_complete_register' function is used to declare the Command Complete callback. The registration can be done during the Initialization Phase 2, before or after the running configuration has been loaded from the startup file.
-
status_t agt_cb_command_complete_register(agt_cb_command_complete_t cbfn)
Register a Command Complete callback.
Max Callbacks: No limit (except available heap memory)
- Parameters:
cbfn -- address of callback function to use
- Returns:
the status of the operation.
Example Initialization function for the Command Complete callback:
static status_t my_init (void)
{
status_t res = NO_ERR;
// … load module, etc.
res = agt_cb_command_complete_register(example_command_complete_cbfn);
// ...
}
The 'agt_cb_command_complete_unregister' function can be used to remove this callback. This is optional. The server will cleanup automatically on shutdown.
-
void agt_cb_command_complete_unregister(agt_cb_command_complete_t cbfn)
Unregister a Command Complete callback.
This function unregisters a Command Complete callback.
- Parameters:
cbfn -- address of callback function to use
Example Cleanup function for the Command Complete callback:
static void my_cleanup (void)
{
// ...
agt_cb_command_complete_unregister(example_command_complete_cbfn);
// ...
}
Command Complete Callback Function Example
The following example code shows a Command Complete callback:
/*******************************************************************
* FUNCTION example_command_complete_cbfn
*
* The Command Complete callback is the user/system callback
* that is invoked after each client command is executed
* for the NETCONF or RESTCONF protocols.
*
* The Command Complete is typically used for retrieval
* operations (get, get-config, get-bulk) to release resources
* used during GET2 callbacks invoked during the operation.
*
* Max Callbacks: No limit (except available heap memory)
*
* INPUTS:
* scb == session control block making the request
* msg == incoming rpc_msg_t in progress
* command_modname == YANG module name of command that is completed
* command_name == YANG RPC object name of command that is completed
*
* OUTPUTS:
* none
*
* RETURNS:
* none
*******************************************************************/
static void
example_command_complete_cbfn (ses_cb_t *scb,
rpc_msg_t *msg,
const xmlChar *command_modname,
const xmlChar *command_name)
{
if (!xml_strcmp(command_modname, (const xmlChar *)"RESTCONF")) {
/* RESTCONF specific handling */
if (!xml_stricmp(command_name, (const xmlChar *)"POST") ||
!xml_stricmp(command_name, (const xmlChar *)"PUT") ||
!xml_stricmp(command_name, (const xmlChar *)"PATCH")) {
/* post, put or patch handling */
}
} else {
/* NETCONF operations handling */
if (!xml_strcmp(command_name, (const xmlChar *)"get") ||
!xml_strcmp(command_name, (const xmlChar *)"get-config") ||
!xml_strcmp(command_name, (const xmlChar *)"get-bulk")) {
/* cleanup our internal get cache data
* example_clean_get2_cache(scb, msg);
*/
}
}
}
Note
As of release 23.10-11, when the request is from RESTCONF, do not use RPC-related parameters from the 'msg' structure as they will not be set.
RESTCONF requests are not the same as RPC requests. RESTCONF uses HTTP methods in the command name instead of RPC commands.
NACM External Groups Callback
The NACM External Groups callback function is a user callback that is invoked when the server creates a new client session for NETCONF or RESTCONF sessions. It is used to retrieve a list of group names that should be used for the specified username, just for that session. These group names are added to any NACM configured groups in the ietf-netconf-acm YANG module.
Max Callbacks: 1
File:
agt/agt_acm_ietf.h
The following function template definition is used for NACM External Groups callback functions:
-
typedef status_t (*agt_acm_group_cbfn_t)(const xmlChar *username, xmlChar **retgroups)
typedef for NACM External Groups callback function
Get the list of group names for this username These groups are added to the usergroup cache for the session
- Param username:
return the list of group names that this username is a member
- Param retgroups:
[out]
address of return malloced string
*retgroups is set to a malloced string that will be parsed.
It contains a whitespace delimited list of group named ' group1 group2 group3'
The caller will free this string with m__free
- Return:
status: if an error occurs the session will only use NACM groups
NACM External Groups Callback Initialization and Cleanup
The 'agt_acm_ietf_register_group_cbfn' function is used to declare the NACM External Group callback. The registration can be done during the Initialization Phase 2, before or after the running configuration has been loaded from the startup file.
-
void agt_acm_ietf_register_group_cbfn(agt_acm_group_cbfn_t cbfn)
Register a get-external-groups callback function.
This will be invoked at the start of each session as the acm_cache is created for a session
- Parameters:
cbfn -- callnack function to register
Example Initialization function for the NACM External Group callback:
static status_t my_init (void)
{
status_t res = NO_ERR;
// … load module, etc.
/* example -- Register a NACM External Groups Callback */
agt_acm_ietf_register_group_cbfn(nacm_external_group_cbfn);
return res;
}
There is no unregister function for this callback. The server will cleanup automatically on shutdown.
NACM External Groups Callback Function Example
The following example code shows a NACM External Group callback:
/********************************************************************
* FUNCTION nacm_external_group_cbfn
*
* Get the list of group names for this username
* These groups are added to the usergroup cache for the session
* INPUTS:
* username: return the list of group names that this username
* is a member
* retgroups == address of return malloced string
* OUTPUTS:
* *retgroups is set to a malloced string that will be parsed.
* It contains a whitespace delimited list of group named
* ' group1 group2 group3'
* The caller will free this string with m__free
* RETURNS:
* status: if an error occurs the session will only use NACM groups
*********************************************************************/
static status_t
nacm_external_group_cbfn (const xmlChar *username,
xmlChar **retgroups)
{
if (retgroups == NULL) {
return ERR_NCX_INVALID_VALUE;
}
(void)username;
/* MUST use a function that allocates memory with m__getMem
* Will be freed by the caller with m__free macro
*/
*retgroups = xml_strdup("group1 group2 group5");
if (*retgroups == NULL) {
return ERR_INTERNAL_MEM;
}
return NO_ERR;
}
User Defined Data Types Callbacks
User defined data types are supported with callback functions that apply to all YANG leaf or leaf-list nodes using a specific data type.
There are 3 types of callbacks supported to allow customization of YANG data types:
validate: custom validation function, used when a data node is set
canonical: convert a value to canonical format, used when a data node is set
compare: compare 2 values of the same data type, used when a data node is set
There are several standard YANG data types that are supported with
built-in canonical functions, which can be found in
ncx/ipaddr_typ.c
(if sources are available). The server will
automatically check for validate and canonical callbacks when a data
node is parsed from XML or JSON input. The automatic canonical check can
be disabled using the --with-canonical CLI parameter.
User Defined Data Types Callback Initialization and Cleanup
A user defined type is registered with the 'typ_userdef_register' function.
This must be done after the YANG module containing the typedef statement has been loaded.
Only top-level typedefs are supported.
Typedefs within groupings or nested within containers or lists are not supported.
-
status_t typ_userdef_register(const xmlChar *modname, const xmlChar *typname, typ_validate_fn_t validate_fn, typ_canonical_fn_t canonical_fn, typ_compare_fn_t compare_fn, void *cookie)
Register the callback functions for a user defined type.
At least one callback needs to be set in order for this userdef type to have any affect
- Parameters:
modname -- module name defining the type
typname -- name of the type
validate_fn -- validate callback (may be NULL)
canonical_fn -- canonical callback (may be NULL)
compare_fn -- compare callback (may be NULL)
cookie -- cookie to pass to callback function
- Returns:
status
Example Registration function:
/* ietf-inet-types:ipv6-address */
status_t res =
typ_userdef_register(NCXMOD_IETF_INET_TYPES,
(const xmlChar *)"ipv6-address",
NULL, // validate_fn
ipv6_address_canonical_fn,
NULL, // compare_fn
NULL); // cookie
if (res != NO_ERR) {
return res;
}
typ_validate_fn_t
The validate callback is used for special custom validation of values conforming to a YANG data type.
-
typedef status_t (*typ_validate_fn_t)(typ_def_t *typdef, val_value_t *val, void *cookie)
userdef validate callback function user validation callback for a userdef type
- Param typdef:
type definition for the user defined type
- Param val:
input value to convert
- Param cookie:
cookie value passed to register function
- Return:
the validation status
This function returns NO_ERR
even if it does not do any validation.
It returns an error code if validation fails.
Example Validate Callback function:
/********************************************************************
* FUNCTION admin_validate_fn
*
* validate callback for an administrative string
*
* INPUTS:
* typdef == type definition for the user defined type
* val == input value to validate
* cookie == cookie value passed to register function
* RETURNS:
* status
*/
static status_t
admin_validate_fn (typ_def_t *typdef,
val_value_t *val,
void *cookie)
{
(void)typdef;
(void)cookie;
if (VAL_TYPE(val) != NCX_BT_STRING) {
return ERR_NCX_OPERATION_FAILED;
}
const xmlChar *valstr = val->v.str;
if (valstr == NULL) {
return NO_ERR;
}
/* check if the string passes admin format checks */
if (check_admin_string_ok(valstr)) {
return NO_ERR;
}
return ERR_NCX_INVALID_VALUE;
} /* admin_validate_fn */
typ_canonical_fn_t
The canonical callback is used to convert a data node value to the canonical format for the data type. This is important for list key leafs, or else different representations of the same value (E.g. ipv6-address) will be treated as separate list entries.
This function returns NO_ERR
even if it does not do any conversion
to canonical format.
It returns an error code if some error occurs and conversion to canonical format fails.
-
typedef status_t (*typ_canonical_fn_t)(typ_def_t *typdef, val_value_t *val, void *cookie)
userdef canonical callback function convert the inval to the canonical format for the type
- Param typdef:
type definition for the user defined type
- Param val:
[inout] input value to convert
val can be converted to canonical format
- Param cookie:
cookie value passed to register function
- Return:
status
Example Canonical Callback function:
/********************************************************************
* FUNCTION lowercase_canonical_fn
*
* <generic convert to lowercase>
* canonical callback for a domain name string
* convert the inval to the canonical format for the type
*
* INPUTS:
* typdef == type definition for the user defined type
* val == input value to convert
* cookie == cookie value passed to register function
* OUTPUTS:
* val == can be changed to canonical format
* RETURNS:
* status
*/
static status_t
lowercase_canonical_fn (typ_def_t *typdef,
val_value_t *val,
void *cookie)
{
(void)typdef;
(void)cookie;
if (VAL_TYPE(val) != NCX_BT_STRING) {
return ERR_NCX_OPERATION_FAILED;
}
xmlChar *valstr = VAL_STRING(val);
if (valstr == NULL) {
return NO_ERR;
}
/* convert the string to lowercase in place */
xmlChar *p = valstr;
while (*p) {
*p = (xmlChar)tolower((int)*p);
}
return NO_ERR;
} /* lowercase_canonical_fn */
typ_compare_fn_t
The compare callback is used to compare two values of the same data type. It is used in the val_compare functions. The standard compare function will skipped if this callback is present for the data type. This function is only needed if the standard compare function for the data type is not correct for some reason (E.g: a vendor-specific structured string).
This function returns NO_ERR
if the comparison is done and no need
to do the standard compare.
This function returns ERR_NCX_SKIPPED
if the comparison is not done
so the standard compare function needs to be invoked.
This function returns some error code if an error occurs while
attempting the comparison (E.g. ERR_INTERNAL_MEM
if a malloc fails)
-
typedef status_t (*typ_compare_fn_t)(const typ_def_t *typdef, const val_value_t *val1, const val_value_t *val2, void *cookie, int *retval)
userdef compare callback function compare 2 val_value_t nodes of the same user defined type
- Param typdef:
type definition for the user defined type
- Param val1:
input value 1 to comapre
- Param val2:
input value 2 to comapre
- Param cookie:
cookie value passed to register function
- Param retval:
[out] address of return compare value
*retval return compare value
- Return:
status (ERR_NCX_SKIPPED if no compare done)
Example Compare Callback function:
/********************************************************************
* compare 2 val_value_t nodes of the same user defined type
* INPUTS:
* typdef == type definition for the user defined type
* val1 == input value 1 to compare
* val2 == input value 2 to compare
* cookie == cookie value passed to register function
* retval == address of return compare value
* OUTPUTS:
* *retval == return compare value
* RETURNS:
* status (ERR_NCX_SKIPPED if no compare done)
*/
static status_t
admin_compare_fn (typ_def_t *typdef,
const val_value_t *val1,
const val_value_t *val2,
void *cookie,
int *retval)
{
(void)typdef;
(void)cookie;
if (VAL_TYPE(val1) != NCX_BT_STRING) {
return ERR_NCX_OPERATION_FAILED;
}
if (VAL_TYPE(val12) != NCX_BT_STRING) {
return ERR_NCX_OPERATION_FAILED;
}
const xmlChar *val1str = VAL_STRING(val1);
if (val1str == NULL) {
return ERR_NCX_SKIPPED;
}
const xmlChar *val2str = VAL_STRING(val2);
if (val2str == NULL) {
return ERR_NCX_SKIPPED;
}
/* compare as case-insensitive strings */
int ret = strcasecmp(const char *)val1str, (const char *)val2str);
*retval = ret;
return NO_ERR;
} /* admin_compare_fn */