The yangdump-pro program will automatically generate functions to queue a specific notification type for processing. It is up to the SIL callback code to invoke this function when the notification event needs to be generated. The SIL code is expected to provide the value nodes that are needed for any notification payload objects.
The function to generate a notification control block and queue it for notification replay and delivery is generated by the yangdump-pro program.
Let us go through simple examples that will illustrate how to utilize notifications for specific purposes. First we need a YANG module. Consider this simplified, but functional, example. You can download this YANG module from attachments and run make_sil_dir_pro to auto-generate stub SIL code for this module.
Note, notifications_send API that is getting generated is not getting called from anywhere from the generated SIL code and it is up to users to invoke notification_send API and it is not part of the auto-generated code and you will need to modify this stub SIL code and add invocation call to the notification_send API.
SIL code Generation command that was used in this example. Please refer to the attached SIL code.
> make_sil_dir_pro notif-example --sil-get2 --sil-edit2
In the example below, the 'restart-notification' notification event contains one container and a list nodes that we will fill in in the SIL code in order to return a notification message
module notif-example { namespace "http://netconfcentral.org/ns/notif-example"; prefix "notif-example"; contact "Andy Bierman <[email protected]>"; revision 2019-01-01 { description "Notification test module in progress."; } grouping resource { container resource { choice resource { case circuit-pack { leaf circuit-pack-name { type string; } } case port { container port { leaf port-name { type string; } } } case connection { leaf connection-name { type string; } } } } list target { leaf target-name { type instance-identifier; } } // list edit } notification restart-notification { uses resource; } rpc test-notif { description "Trigger notification, test that they are working"; } }
In this scenario we also register RPC callbacks in order to trigger notification generation. As a result any time <test-notif> RPC is invoked the notification will be populated with help of the restart_notification_send API call. Refer to the attached SIL code for more information.
/******************************************************************** * FUNCTION test_notif_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 test_notif_invoke (ses_cb_t *scb, rpc_msg_t *msg, xml_node_t *methnode) { status_t res; res = NO_ERR; /* 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 */ /* Send the notification */ restart_notification_send(msg); return res; } /* test_notif_invoke */
The callback function with notification Payload may look as follow.
/******************************************************************** * FUNCTION restart_notification_send * * Send a y_notif_example_restart_notification notification * Called by your code when notification event occurs * ********************************************************************/ void restart_notification_send (rpc_msg_t *msg) { status_t res = NO_ERR; if (!agt_notifications_enabled()) { log_debug2("\nSkipping <restart-notification> notification; disabled"); return; } if (LOGDEBUG) { log_debug("\nGenerating <restart-notification> notification"); } /* Create a new notification message */ agt_not_msg_t *notif = // loaded obj in the Init 1 Phase agt_not_new_notification(restart_notification_obj); if (notif == NULL) { log_error("\nError: malloc failed, cannot send " "<restart-notification> notification"); return; } /* add container resource to payload */ val_value_t *resource_val = agt_make_object(restart_notification_obj, (const xmlChar *)"resource", &res); if (!resource_val) { log_error("\nError: make container failed (%s), cannot send " "<resourse> parameter", get_error_string(res)); res = NO_ERR; } else { /* pass off resource_val malloc here */ agt_not_add_to_payload(notif, resource_val); } /* create a child of a container and then add it to container */ if (resource_val) { val_value_t *leafval = agt_make_leaf(VAL_OBJ(resource_val), (const xmlChar *)"connection-name", (const xmlChar *)"connection-1", &res); if (leafval) { res = val_child_add(leafval, resource_val); if (res != NO_ERR) { val_free_value(leafval); } } } /* add 'target' list nodes * In this example we use custom audit records that * are createad by the server. The record structure is just an * example and is out of the scope of this example code. * Use your own data or structure or other source of the data * to generate list entries. * * Here we loop through the data massive and generate the * notification list values. */ if (msg->rpc_txcb) { agt_cfg_audit_rec_t *auditrec = (agt_cfg_audit_rec_t *)dlq_firstEntry(&msg->rpc_txcb->auditQ); for ( ; auditrec; auditrec = (agt_cfg_audit_rec_t *)dlq_nextEntry(auditrec)) { /* add restart-notification/target list */ val_value_t *listval = agt_make_object(restart_notification_obj, (const xmlChar *)"target", &res); if (listval == NULL) { log_error("\nError: make list failed (%s), cannot send " "<target> parameter", get_error_string(res)); continue; } /* pass off listval malloc here */ agt_not_add_to_payload(notif, listval); /* add restart-notification/target/target-name */ val_value_t *leafval = agt_make_leaf(VAL_OBJ(listval), (const xmlChar *)"target-name", (const xmlChar *)"somename", &res); if (leafval) { res = val_child_add(leafval, listval); if (res != NO_ERR) { val_free_value(leafval); } } else { log_error("\nError: make leaf failed (%s), cannot send " "<target-name> parameter", get_error_string(res)); } } } agt_not_queue_notification(notif); } /* restart_notification_send */
As a result, whenever some north bound agent send <test-notif> RPC the "restart-notification" notification will be generated with a specific values. For more details on how this callback is registered and cleaned up refer to the attached SIL code.
For more example on how to construct different YANG Data nodes refer to the Section YANG Data Tree Handling
As a result the server will populate the notification and the client may receive the following notification from the server after it sends the <test-notif> RPC:
Incoming notification for session 1 [default]: notification { eventTime 2020-11-25T21:49:23Z restart-notification { resource { connection-name connection-1 } } }