The Set Order Hook callback function is the user/system callback that is used to provide an access for a specific list instance object and modify its secondary SIL priority.
The Set Order Hook is invoked in document order for each edited instance of the specified object. The callback returns the desired secondary SIL priority for the specific list instance. This callback is invoked once per edited instance and after any Set Hook is called for the object and instance.
The following function template definition is used for Set Order Hook callback functions:
/* Typedef of the callback */ typedef uint8 (*agt_cb_order_hook_t) (agt_cfg_transaction_t *txcb, op_editop_t editop, val_value_t *newval, val_value_t *curval, status_t *res);
Register Callback
The Set Order Hook callback function is hooked into the server with the agt_cb_order_hook_register function, described below.
extern status_t agt_cb_order_hook_register (const xmlChar *defpath, agt_cb_order_hook_t cbfn);
The register function is used to declare a specific callback function for the Set Order Hook callback. The registration is done during the Initialization Phase 1 before the startup configuration is loaded into the running configuration database and before running configurations are loaded. Initialization function with the registration of the Set Order Hook callback may look as follows:
/******************************************************************** * FUNCTION interfaces_init * * initialize the server instrumentation library. * Initialization Phase 1 * *********************************************************************/ static status_t interfaces_init (void) { ... /* Register an object specific Set-Order-Hook callback function */ res = agt_cb_order_hook_register((const xmlChar*)"/if:interface/if:interface", set_order_hook); if (res != NO_ERR) { return res; } ... }
Now, whenever the /if:interface/if:interface list is getting modified, the callback function will be invoked and desired secondary SIL priority for the list instance can be specified. As a result, the server will apply list of edits based on this priority, the lower priority number is set to the instance the earlier the server will apply the edit.
Callback Cleanup
The following example code illustrates how the callbacks can be cleaned up. The callbacks cleanup is getting done during module Cleanup Phase.
extern void agt_cb_order_hook_unregister (const xmlChar *defpath);
Cleanup function with of the Set Order Hook callback may look as follows:
/******************************************************************** * FUNCTION interfaces_cleanup * cleanup the server instrumentation library * ********************************************************************/ void interfaces_cleanup (void) { ... /* Unregister an object specific Set-Order-Hook callback function */ agt_cb_order_hook_unregister((const xmlChar*)"/if:interface/if:interface"); ... }
EXAMPLE
The following sections illustrates how to utilize the Set Order Hook callback in examples.
NOTE:
The Set Order Hook callback function can be registered only for “list” YANG objects.
In this example, the Set Order Hook callback function applies priority to a list edit based on a key value. The purpose of this function is to prioritize edits and give more flexible and easier development.
The following example code illustrates how the Set Order Hook callback may look like:
/******************************************************************** * FUNCTION set_order_hook * * Callback function is * used to provide a callback for a specific named object * * This callback is invoked once per instance before any * Set Hook or Post Set Hook is called for the object and instance. * * INPUTS: * txcb == transaction control block in progress * editop == edit operation enumeration for the node being edited * newval == container object holding the proposed changes to * apply to the current config, depending on * the editop value. Will not be NULL. * curval == current container values from the <running> * or <candidate> configuration, if any. Could be NULL * for create and other operations. * res == address of return status * OUTPUTS: * *res == status of callback; status == error will cause the * transaction to be terminated and rollback started * RETURNS: * the secondary SIL priority to assign to the object instance ********************************************************************/ static uint8 set_order_hook (agt_cfg_transaction_t *txcb, op_editop_t editop, val_value_t *newval, val_value_t *curval, status_t *res) { (void)txcb; (void)editop; (void)curval; uint8 retprior = 0; /* Set the priority only if the operation is not delete and if * a new value has keys, that will be compared later */ if (newval && val_has_index(newval)) { /* Get the first index entry, if any for this value node */ const val_index_t *c1 = val_get_first_index(newval); if (!c1) { return ERR_INTERNAL_VAL; } if (!xml_strcmp(VAL_STR(c1->val), (const xmlChar *)"vlan1")) { log_debug("\n Setting Priority to 140 for index:%s \n", VAL_STR(c1->val)); retprior = 100; } else if (!xml_strcmp(VAL_STR(c1->val), (const xmlChar *)"ethernet1/1/10")) { log_debug("\n Setting Priority to 160 for index:%s \n", VAL_STR(c1->val)); retprior = 150; } else { log_debug("\n Setting Priority to 130 for index:%s \n", VAL_STR(c1->val)); retprior = 200; } } return retprior; } /* set_order_hook */
So, whenever some north bound agent edits an /if:interfaces/if:interface node the callback is invoked and additionally assigns desired priority to this edit. Note, that in the example above, the priority will be assigned only if there is a new value. It will be assigned only if the edit operation is not “delete” or “remove” because during the edits for those operations the server does not allocate a new value. Use a current value for any comparisons or validations during “delete” or “remove” edit operations.
To exemplify, if the north bound agent is creating 3 interfaces with different key values at the same time using the following <edit-config> RPC:
<edit-config> <target> <candidate/> </target> <default-operation>merge</default-operation> <test-option>set</test-option> <config> <interfaces> <interface> <name>ethernet1/1/1</name> </interface> <interface> <name>vlan1</name> </interface> <interface> <name>ethernet1/1/10</name> </interface> </interfaces> </config> </edit-config>
By the regular server logic, the server would validate/apply/commit these interfaces in order they are specified in the edit. However, using the Set Order Hook the server now will apply these “interfaces” based on their priority assigned in the callback function. The first list instance that will be processed by the server will be the “interface” with the key value set to “vlan1” since it has the highest priority - “100”.
So, the edits order would look as follows, from the server's logging:
***** start commit phase on candidate for session 5, transaction 1234358 ***** Start full commit of transaction 1234358: 3 edits on candidate config edit-transaction 1234358: on session 5 by --@::1 message-id: -- trace-id: -- datastore: candidate operation: create target: /if:interfaces/if:interface[if:name="vlan1"] comment: none edit-transaction 1234358: on session 5 by --@::1 message-id: -- trace-id: -- datastore: candidate operation: create target: /if:interfaces/if:interface[if:name="ethernet1/1/10"] comment: none edit-transaction 1234358: on session 5 by --@::1 message-id: -- trace-id: -- datastore: candidate operation: create target: /if:interfaces/if:interface[if:name="ethernet1/1/1"] comment: none
The Set Order Hook callback can be extremely useful in cooperation with the Set Hook or Post Set Hook callback or by itself. The power to prioritize all the edits in the transaction provides wide spectrum of utilization. The fact that the Set Order Hook is getting invoked before SIL or any other callbacks for the same object provides possibility to customize the transaction as desired.