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 of the callback */ 
typedef void (*ncx_unload_cbfn_t) (ncx_module_t *mod);


Where, 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, all the fields in this structure should NOT be changed and if accessed, should NOT be accessed directly. This control block ideally should be used only for getting more information about the unloaded module, not for alteration of any of its fields.


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.


Initialization function with the Module Unload callback registration may look as follows:


/******************************************************************** 
* FUNCTION interfaces_init2
* 
* initialize the server instrumentation library.
* Initialization Phase 2
* 
*********************************************************************/ 
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 following example code illustrates how the Module Unload callback can be cleaned up. The callbacks cleanup is getting done during module Cleanup Phase.


/******************************************************************** 
* FUNCTION  interfaces_cleanup
*    cleanup the server instrumentation library 
* 
********************************************************************/ 
void interfaces_cleanup (void)
{
  ...
    ncx_clear_unload_callback(remove_module_callback);

  ...
}


Let us go through simple examples that will illustrate how to utilize the Module Unload callbacks. In this example, the callback code will find a val_value tree, based on the information from MOD pointer, find a tree and remove it from the static data list. In this example we are still using the same “ietf-yang-library” YANG data model.


The following example code illustrates how the Module Unload callback may look like. 


/******************************************************************** 
* FUNCTION remove_module_callback 
* 
* Run an instrumentation-defined function 
* for a 'module-unload' event 
* 
* INPUTS: 
*   mod == module that was added to the registry 
* 
********************************************************************/ 
static void remove_module_callback (ncx_module_t *mod) 
{ 
    remove_module(mod);

} /* add_module_callback */


In the remove_module() function we are removing a val_value tree based on the ncx_module_t information provided by the Module Load event. Any time a new module is unloaded from the server, this callback function will be called with MOD pointer, that contains the complete information about just unloaded module. Based on this information, this callback function will find and remove the static data associated with this module.


/******************************************************************** 
* 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 */


The following functions may be used to obtain required information from the unloaded 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



The mymodules_val pointer represents a parent of the module list.

The following code illustrates how to loop through the mymodules_val parent in order to retrieve all the children modules.


  ...

    val_value_t *module = val_get_first_child(mymodules_val); 
    for (; module; module = val_get_next_child(module)) {      


     }

  ...


Once we got a module list entry pointer, we can try to match its child (module name) with a module name of the unloaded module in order to proceed to the removal. The following code demonstrates how to validate the module name:


  ...

        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 
        } 

  ...


If the module name matched already, we will try to match and the revision date. The revision statement is optional for the module, so we need to make sure that the module actually has the revision statement prior the revision match test. The following code demonstrates how to validate the module revision date:


  ...

        /* 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! 
            } 
        } 

  ...


After we verify that the unloaded module is in the list, we will remove it from the list:


  ... 

       val_remove_child(module); 
       val_free_value(module); 

  ...


The val_remove_child function removes the child value node from its parent value node, from its parent mymodules_val. That is getting freed with val_free_value.