Table of Contents
ConfD can deliver various classes of events to subscribing
applications. The architecture is based on notification
sockets. The application(s) connect a notifications socket to
ConfD. The application provides a bit mask indicating which types
of events the application is interested in. The application
polls the socket and invokes the API function
confd_read_notification()
whenever the
socket is ready to read. The API function populates a
struct confd_notification
structure.
The following is a list of the different asynchronous event
classes that can be delivered from ConfD to the application(s).
See also the confd_lib_events(3) manual page.
The program
misc/notifications/confd_notifications.c
in
the examples collection illustrates subscription and processing
for all these events, and can also be used standalone in a
development environment to monitor ConfD events.
CONFD_NOTIF_AUDIT
- Audit events.
CONFD_NOTIF_AUDIT_SYNC
- Indicates that
audit notifications (CONFD_NOTIF_AUDIT) must be synced by the
application.
CONFD_NOTIF_DAEMON
- Syslog events that
also go to /confdConf/logs/confdLog
.
CONFD_NOTIF_NETCONF
- Syslog events that
also go to /confdConf/logs/netconfLog
.
CONFD_NOTIF_DEVEL
- Syslog events that
also go to /confdConf/logs/developerLog
.
CONFD_NOTIF_TAKEOVER_SYSLOG
- Syslog control.
CONFD_NOTIF_COMMIT_SIMPLE
- Commit message.
CONFD_NOTIF_COMMIT_DIFF
- A
complete diff compared to previous configuration.
CONFD_NOTIF_COMMIT_FAILED
-
Possible data inconsistency event.
CONFD_NOTIF_CONFIRMED_COMMIT
- Events
concerning confirmed commit processing.
CONFD_NOTIF_COMMIT_PROGRESS
- Events
with commit progress information.
CONFD_NOTIF_USER_SESSION
- Whenever
a user session is started or stopped.
CONFD_NOTIF_HA_INFO
- Changes in
ConfD's perception of the cluster configuration.
CONFD_NOTIF_HA_INFO_SYNC
- Indicates that
HA notifications (CONFD_NOTIF_HA_INFO) must be synced by the
application.
CONFD_NOTIF_SUBAGENT_INFO
-
Subagent related events.
CONFD_NOTIF_SNMPA
- SNMP agent
audit log.
CONFD_NOTIF_FORWARD_INFO
- Events related
to forwarding (proxying) of northbound agents.
CONFD_NOTIF_UPGRADE_EVENT
- Events
generated for in-service upgrade.
CONFD_NOTIF_HEARTBEAT
- Heartbeat events.
CONFD_NOTIF_HEALTH_CHECK
- Health check events.
CONFD_NOTIF_STREAM_EVENT
- Notification
stream events.
Many applications need explicit control over where and in which
format the various audit messages are sent. By audit messages
here we mean any message related to user login/logout/reconfig
activity. The list of different audit messages that are possible
to receive can be found in the file
confd_logsyms.h
In order to receive the audit message we must first connect a notifications socket.
Example 12.1. Creating a notification socket
confd_init("Foobar", stderr, debuglevel); if ((notsock = socket(PF_INET, SOCK_STREAM, 0)) < 0 ) confd_fatal("Failed to open notsocket\n"); inet_aton("127.0.0.1", &in); addr.sin_addr.s_addr = in.s_addr; addr.sin_family = AF_INET; addr.sin_port = htons(CONFD_PORT); dflag = CONFD_NOTIF_AUDIT; if (confd_notifications_connect( notsock, (struct sockaddr*)&addr, sizeof (struct sockaddr_in), dflag) < 0 ) { confd_fatal("Failed to confd_connect() to confd \n"); }
The dflags
argument is bit mask indicating which
classes of notifications messages we wish to receive over the socket.
It is possible to receive several different
classes of notifications messages over the same socket.
Once we have the socket setup, we add it to our pollset
and invoke confd_read_notification()
once the socket
is ready to read.
Example 12.2. reading the audit data
while (1) { struct pollfd set[1]; struct confd_notification n; set[0].fd = notsock; set[0].events = POLLIN; set[0].revents = 0; if (poll(&set[0], 1, -1) < 0) { perror("Poll failed:"); continue; } if (set[0].revents & POLLIN) { if (confd_read_notification(notsock, &n) != CONFD_OK) exit(1); switch(n.type) { case CONFD_NOTIF_AUDIT: printf("audit: sym=%d, user=%s/%d %s\n", n.n.audit.logno, n.n.audit.user, n.n.audit.usid, n.n.audit.msg); break; .......
The structure struct confd_notification is defined as:
enum confd_notification_type { CONFD_NOTIF_AUDIT = (1 << 0), CONFD_NOTIF_DAEMON = (1 << 1), CONFD_NOTIF_TAKEOVER_SYSLOG = (1 << 2), CONFD_NOTIF_COMMIT_SIMPLE = (1 << 3), CONFD_NOTIF_COMMIT_DIFF = (1 << 4), CONFD_NOTIF_USER_SESSION = (1 << 5), CONFD_NOTIF_HA_INFO = (1 << 6), CONFD_NOTIF_SUBAGENT_INFO = (1 << 7), CONFD_NOTIF_COMMIT_FAILED = (1 << 8), CONFD_NOTIF_SNMPA = (1 << 9), CONFD_NOTIF_FORWARD_INFO = (1 << 10), CONFD_NOTIF_NETCONF = (1 << 11), CONFD_NOTIF_DEVEL = (1 << 12), CONFD_NOTIF_HEARTBEAT = (1 << 13), CONFD_NOTIF_CONFIRMED_COMMIT = (1 << 14), CONFD_NOTIF_UPGRADE_EVENT = (1 << 15), CONFD_NOTIF_COMMIT_PROGRESS = (1 << 16), CONFD_NOTIF_AUDIT_SYNC = (1 << 17), CONFD_NOTIF_HEALTH_CHECK = (1 << 18), CONFD_NOTIF_STREAM_EVENT = (1 << 19), CONFD_NOTIF_HA_INFO_SYNC = (1 << 20), NCS_NOTIF_PACKAGE_RELOAD = (1 << 21), NCS_NOTIF_CQ_PROGRESS = (1 << 22), CONFD_NOTIF_REOPEN_LOGS = (1 << 23) }; struct confd_notification { enum confd_notification_type type; union { struct confd_audit_notification audit; struct confd_syslog_notification syslog; struct confd_commit_notification commit; struct confd_commit_diff_notification commit_diff; struct confd_user_sess_notification user_sess; struct confd_ha_notification hnot; struct confd_subagent_notification subagent; struct confd_forward_notification forward; struct confd_commit_failed_notification cfail; struct confd_snmpa_notification snmpa; struct confd_confirmed_commit_notification confirm; struct confd_upgrade_notification upgrade; struct confd_progress_notification progress; struct confd_stream_notification stream; struct ncs_cq_progress_notification cq_progress; } n; };
Where the field type
indicates the type
of the message. Depending on the type, one of the other
union structures is populated by the
confd_read_notification()
API function
In our case with audit messages, we get a struct confd_audit_notification structure populated.
struct confd_audit_notification { int logno; /* number from confd_logsyms.h */ char user[MAXUSERNAMELEN]; char msg[BUFSIZ]; int usid; /* session id (0 means - not applicable ) */ };
The logno
is an integer which defines the
event. All log and audit events generated by confd are
enumerated and documented in the include file
confd_logsyms.h
.
If we have indicated that we want to synchronize audit messages
with ConfD, we must call confd_sync_audit_notification()
after receiving an audit message, to signal ConfD that it can continue
processing.
Some applications have explicit requirements not only where
to send syslog messages (this can be easily configured in
confd.conf
) but also how and on which
format to send the syslog messages. By default, ConfD will
simply invoke the standard libc
syslog()
function.
It is possible to subscribe to ConfD syslog messages and also at
the same time suppress ConfD's own syslogging. To subscribe to
syslog messages, the application needs to use one or more of the
flags CONFD_NOTIF_DAEMON
,
CONFD_NOTIF_NETCONF
, and
CONFD_NOTIF_DEVEL
in the mask given to
confd_notifications_connect()
.
If the mask given to
confd_notifications_connect()
contains
the flag CONFD_NOTIF_TAKEOVER_SYSLOG
,
ConfD will not invoke the regular
syslog()
function. Thus in this case,
it is entirely up to the application to actually report the
messages.
If all notifications subscribers that have requested the
CONFD_NOTIF_TAKEOVER_SYSLOG
feature
close their notifications sockets, ConfD will revert to the
behavior of invoking libc
syslog()
. Similarly, when ConfD is
starting, before any application processes has connected and
requested the
CONFD_NOTIF_TAKEOVER_SYSLOG
feature,
ConfD will of course use the standard
syslog()
functionality
When subscribing to syslog messages we receive a populated struct confd_syslog_notification structure:
struct confd_syslog_notification { int prio; /* from syslog.h */ int logno; /* number from confd_logsyms.h */ char msg[BUFSIZ]; };
The logno
is an integer which defines the
event. All syslog and audit events generated by confd are
enumerated and documented in the include file
confd_logsyms.h
.
There are two different types of commit events we can
subscribe to. One really simple which just indicates that a
commit from a north bound agent has occurred. This is
achieved by setting the subscription bitmask to contain the
flag: CONFD_NOTIF_COMMIT_SIMPLE
. The
message we receive contains a struct
confd_commit_notification structure:
struct confd_commit_notification { enum confd_dbname database; int diff_available; struct confd_user_info uinfo; int flags; };
This just provides information on which user committed to which database e.g. running or the candidate. The other commit notification is considerably more complex and it provides information on exactly which nodes were changed.
The flag value is
CONFD_NOTIF_COMMIT_DIFF
, and the
structure we receive is:
struct confd_commit_diff_notification { enum confd_dbname database; struct confd_user_info uinfo; struct confd_trans_ctx *tctx; int flags; };
The structure contains a transaction context which we can choose
to use with maapi_attach()
and thus attach
to the currently executing transaction. When the event is
generated, this transaction has successfully been committed by all
data providers, but the commit operation has not completed and it
is hanging, waiting for the application to
invoke confd_diff_notification_done()
.
maapi_attach()
attaches a transaction
context. We can then use that transaction context to read
from the transaction. The transaction has a list of nodes which
constitute the configuration changes in the transaction. We can
traverse this list using the function
maapi_diff_iterate()
which will invoke
a user supplied function for each and every modification in the
transaction.
The purpose of this feature is not to be able to check the commit diff. All such checking should be done using the normal validation routines. The purpose is rather to be able to log diffs on a per commit basis.
Thus the first thing we need if we want to traverse the diff list is a function to be invoked for every diff item. Our example here will just format the data and print to stdout.
static enum maapi_iter_ret iter(confd_hkeypath_t *kp, enum maapi_iter_op op, confd_value_t *oldv, confd_value_t *v, void *state) { char path[BUFSIZ]; char value[BUFSIZ]; char *opstr; struct confd_cs_node *node; confd_hkeypath_t *dkp; int i; confd_pp_kpath(path, sizeof(path), kp); value[0] = 0; switch (op) { case MOP_CREATED: opstr = "created"; break; case MOP_DELETED: opstr = "deleted"; break; case MOP_MODIFIED: opstr = "modified"; break; case MOP_VALUE_SET: opstr = "value_set"; node = confd_find_cs_node(kp, kp->len); confd_val2str(node->info.type, v, value, sizeof(value)); break; case MOP_MOVED_AFTER: if (v == NULL) { opstr = "moved first"; } else { opstr = "moved after"; /* create+print a hkeypath for the entry this one was moved after */ dkp = confd_hkeypath_dup(kp); for (i = 0; v[i].type != C_NOEXISTS; i++) { confd_free_value(&dkp->v[0][i]); confd_value_dup_to(&v[i], &dkp->v[0][i]); } confd_pp_kpath(value, sizeof(value), dkp); confd_free_hkeypath(dkp); } break; case MOP_ATTR_SET: if (v[1].type == C_NOEXISTS) { opstr = "attr_del"; snprintf(value, sizeof(value), "%s", attr_str(&v[0])); } else { opstr = "attr_set"; i = snprintf(value, sizeof(value), "%s -> ", attr_str(&v[0])); confd_pp_value(&value[i], sizeof(value) - i, &v[1]); } break; } printf ("ITER %s %s %s\n", path, opstr, value); return ITER_RECURSE; }
The iteration function must return an enum maapi_iter_ret indicating to ConfD what to continue to do. We have the following possible return values:
ITER_STOP
- Stop. Do not invoke the
iteration function any more for this transaction
ITER_RECURSE
- Iteration continues with
all children of the modified node.
ITER_CONTINUE
- Iteration ignores the
children of the node and continues with the node's
sibling.
The iteration function is called for each modified node in the
configuration. See the description of
maapi_diff_iterate()
in confd_lib_maapi(3) for a detailed description
of when the different op
values
MOP_CREATED
,
MOP_DELETED
,
MOP_MODIFIED
,
MOP_VALUE_SET
, and
MOP_MOVED_AFTER
are used.
Finally we must have a function which is invoked whenever we
receive a notification of type
CONFD_NOTIF_COMMIT_DIFF
. The function must
use the supplied transaction context and attach, and when it is
done traversing the diff it must call
confd_diff_notification_done()
.
static void handle_diff_notif(struct confd_trans_ctx *tctx) { /* first we need a maapi socket */ int maapi_socket; if ((maapi_socket = socket(PF_INET, SOCK_STREAM, 0)) < 0 ) confd_fatal("Failed to open socket\n"); if (maapi_connect(maapi_socket, (struct sockaddr*)&addr, sizeof (struct sockaddr_in)) < 0) confd_fatal("Failed to confd_connect() to confd \n"); /* no namespace needed for this */ OK(maapi_attach(maapi_socket, -1, tctx)); /* Now we can iterate through the currently hanging transaction */ /* and read out all the diffs */ OK(maapi_diff_iterate(maapi_socket, tctx->thandle, iter, ITER_WANT_ATTR, NULL)); /* and finally call done to release data and let */ /* the transaction finish */ OK(confd_diff_notification_done(notif_socket, tctx)); close(maapi_socket); }
The CONFD_NOTIF_COMMIT_FAILED
event is
generated when a data provider fails in its commit
callback. ConfD executes a two-phase commit procedure towards
all data providers when committing transactions. When a provider
fails in commit, the system is an unknown state. See confd_lib_maapi(3) and the function
maapi_get_running_db_status()
. If the
provider is "external", the name of the failing daemon is
provided. If the provider is another NETCONF agent, the IP
address and port of that agent is provided.
When a a user has started a confirmed commit, when a confirming
commit is issued, or when a confirmed commit is aborted, a
CONFD_NOTIF_CONFIRMED_COMMIT
event is
generated. The application receives a struct
confd_confirmed_commit_notification, which gives the specific
action and user session info for the committer. For a confirmed
commit, the timeout value is also given.
By subscribing to the
CONFD_NOTIF_COMMIT_PROGRESS
event, the
application can receive the same commit progress information that
is reported when the commit | details CLI
command is used. The application receives a struct
confd_progress_notification structure.
We can get notifications on user sessions and on user session events. A user session corresponds to an actual user logging in to the system, for example a NETCONF manager
The struct confd_user_sess_notification structure is defined as:
enum confd_user_sess_type { CONFD_USER_SESS_START = 1, /* a user session is started */ CONFD_USER_SESS_STOP = 2, CONFD_USER_SESS_LOCK = 3, /* a database is locked */ CONFD_USER_SESS_UNLOCK = 4, CONFD_USER_SESS_START_TRANS = 5, /* a database transaction is started */ CONFD_USER_SESS_STOP_TRANS = 6 }; struct confd_user_sess_notification { enum confd_user_sess_type type; struct confd_user_info uinfo; enum confd_dbname database; };
This means that we can follow the progress of a user session, which databases are touched by the session etc.
ConfD HA capabilities are described in Chapter 24, High Availability. This section describes the various
events that are asynchronously produced by ConfD when the
cluster configuration is changed. These changes may be
induced explicitly by the application through invocation of
the various HA related API functions in
libconfd
or they may be induced by
ConfD itself when the sockets between the HA nodes get
closed. It is vital that the High-Availability-Framework
(HAFW) subscribes to these messages and acts accordingly.
The struct confd_notification structure
received by confd_read_notification()
will populate the hnot
field with a
struct confd_ha_notification. This in its turn
is yet another union structure with a type field.
struct confd_ha_notification { enum confd_ha_info_type type; /* additional info for various info types */ union { int nomaster; /* CONFD_HA_INFO_NOMASTER */ struct confd_ha_node slave_died; /* CONFD_HA_INFO_SLAVE_DIED */ struct confd_ha_node slave_arrived;/* CONFD_HA_INFO_SLAVE_ARRIVED*/ int cdb_initialized_by_copy; /* CONFD_HA_INFO_SLAVE_INITIALIZED */ int beslave_result; /* CONFD_HA_INFO_BESLAVE_RESULT */ } data; };
We start with a listing of types of the different HA related events that ConfD can send to the subscribing application. The enum is defined as:
enum confd_ha_info_type { CONFD_HA_INFO_NOMASTER = 1, /* we have no master */ CONFD_HA_INFO_SLAVE_DIED = 2, /* a slave disappeared */ CONFD_HA_INFO_SLAVE_ARRIVED = 3, /* a slave arrived to us */ CONFD_HA_INFO_SLAVE_INITIALIZED = 4, /* CDB is initialized */ CONFD_HA_INFO_IS_MASTER = 5, /* we are now master */ CONFD_HA_INFO_IS_NONE = 6, /* we are now none */ CONFD_HA_INFO_BESLAVE_RESULT = 7 /* result of async beslave() */ };
Each of the different informational messages has additional data associated to it.
CONFD_HA_INFO_NOMASTER
A node
(which is a slave node) has lost contact with the master
and is now in HA state
CONFD_HA_STATE_NONE
. Only sent on
the slave node.
Whenever we receive this message the
nomaster
field is populated. This is
either the integer
CONFD_ERR_HA_CLOSED
if the slave
lost contact with master due to the socket getting
closed or the integer
CONFD_ERR_HA_NOTICK
if the slave
has not received any live ticks from the master.
CONFD_HA_INFO_SLAVE_DIED
A master
node lost contact with a slave node. Only sent on the
master node. The field slave_died
is
populated with a struct confd_ha_node
indicating which particular slave died.
CONFD_HA_INFO_SLAVE_ARRIVED
A
master node was connected to by a slave
node. Authentication was ok and the slave is initializing
its CDB database. Only sent at the master node. The
field slave_arrived
is populated with
a struct confd_ha_node indicating which
slave arrived.
CONFD_HA_INFO_SLAVE_INITIALIZED
A
slave node has just finished its initialization and
synchronization of the database. The slave is now fully
operational. Only sent at slave nodes. The field
cdb_initialized_by_copy
is set to
1 if ConfD concluded that the
entire CDB database has to be copied and
0 if a copy was avoided.
CONFD_HA_INFO_IS_MASTER
The
node has been successfully elevated to master.
This is only sent at the master node, i.e. the node that
just became master.
CONFD_HA_INFO_IS_NONE
The
node has been set to NONE mode.
CONFD_HA_INFO_BESLAVE_RESULT
If we use
asynchronous invocation of the
confd_ha_beslave()
function, i.e. with
the parameter waitreply
set to 0, this
message is sent when the operation has completed. The field
beslave_result
is set to indicate the
result which would have been returned by a synchronous
invocation of confd_ha_beslave()
. Thus if
beslave_result
is 0, the node has
successfully become a slave, otherwise
beslave_result
is one of the
confd_errno
values that can be returned by
synchronous invocation of confd_ha_beslave()
.
If we have indicated that we want to synchronize HA messages
with ConfD, we must call confd_sync_ha_notification()
after receiving a HA message, to signal ConfD that it can continue
processing.
The subagent mechanism is described in Chapter 26, Subagents and Proxies. This section describes the related events which ConfD generates when acting as a master agent.
When the notification type is
CONFD_NOTIF_SUBAGENT_INFO
, the
struct confd_notification structure received by
confd_read_notification()
will populate
the subagent
field with a struct
confd_subagent_notification.
struct confd_subagent_notification { enum confd_subagent_info_type type; char name[MAXAGENTNAMELEN]; };
The type
field is one of the values
CONFD_SUBAGENT_INFO_UP
or
CONFD_SUBAGENT_INFO_DOWN
.
At first, each subagent is marked as being down. When ConfD successfully communicates with a subagent, it is marked as up, and a corresponding event is generated. A down event is generated only if ConfD tries to communicate with a subagent, but fails. Thus, if a subagent closes an idle connection to the master agent, it is not marked as down.
The SNMP agent log is activated through the
/confdCfg/logs/snmpLog
element in the
confd.conf
configuration file.
The SNMP audit log messages can also be received and processed by an external C program over a notification socket. The application receives a struct confd_snmpa_notification structure. The structure contains a series of fields describing the sent or received SNMP PDU. It also contains a list of all varbinds in the PDU.
Each varbind contains a confd_value_t with the
string representation of the SNMP value. Thus the type of the
value in a varbind is always C_BUF
. See
confd_events.h
include file for the details of the
received structure.
The following code exemplifies how we write a program which establishes a notification socket and subscribes to all SNMP PDUs in and out of the system.
We start off with some auxiliary function to format the PDU type and the type of a "varbind"
char *vb_type(struct confd_snmp_varbind *vb) { switch (vb->vartype) { case CONFD_SNMP_NULL: return "NULL"; case CONFD_SNMP_INTEGER: return "INTEGER"; case CONFD_SNMP_Interger32: return "Integer32"; case CONFD_SNMP_OCTET_STRING: return "OCTET STRING"; case CONFD_SNMP_OBJECT_IDENTIFIER: return "OBJECT IDENTIFIER"; case CONFD_SNMP_IpAddress: return "IpAddress"; case CONFD_SNMP_Counter32: return "Counter32"; case CONFD_SNMP_TimeTicks: return "TimeTicks"; case CONFD_SNMP_Opaque: return "Opaque"; case CONFD_SNMP_Counter64: return "Counter64"; case CONFD_SNMP_Unsigned32: return "Unsigned32"; } return ""; } char *pdutype(struct confd_snmpa_notification *snmp) { switch (snmp->pdu_type) { case CONFD_SNMPA_PDU_V1TRAP: return("V1TRAP"); case CONFD_SNMPA_PDU_V2TRAP: return("V2TRAP"); case CONFD_SNMPA_PDU_INFORM: return("INFORM"); case CONFD_SNMPA_PDU_GET_RESPONSE: return("GET_RESPONSE"); case CONFD_SNMPA_PDU_GET_REQUEST: return("GET_REQUEST"); case CONFD_SNMPA_PDU_GET_NEXT_REQUEST: return("GET_NEXT_REQUEST"); case CONFD_SNMPA_PDU_REPORT: return("REPORT"); case CONFD_SNMPA_PDU_GET_BULK_REQUEST: return("GET_BULK_REQUEST"); case CONFD_SNMPA_PDU_SET_REQUEST: return("SET_REQUEST"); default: return ""; } }
Following that we show the code which invokes
confd_read_notification()
and reads a C
structure of the type struct
confd_snmpa_notification
The structure contains the type of the PDU, various other fields and also the complete SNMP "varbind" lists in the PDU. The code prints the PDU type and then loops through all the varbinds and prints the value of each varbind.
if (confd_read_notification(notsock, &n) != CONFD_OK) exit(1); switch(n.type) { case CONFD_NOTIF_SNMPA: { int i,j; char buf[BUFSIZ]; buf[0] = 0; char *ptr = &buf[0]; struct confd_snmpa_notification *snmp = &n.n.snmpa; ptr += sprintf(ptr, "%s ", pdutype(snmp)); ptr += sprintf(ptr,"Id = %d ", snmp->request_id); struct confd_ip *ip = &(snmp->ip); ptr += sprintf(ptr, " %s:%d ", inet_ntoa(ip->ip.v4), snmp->port); if ((snmp->error_status !=0 || snmp->error_index != 0)) { ptr += sprintf(ptr, "ErrIx = %d ", snmp->error_index); } else if (snmp->pdu_type == CONFD_SNMPA_PDU_V1TRAP) { ptr += sprintf(ptr,"Generic=%d Specific=%d", snmp->v1_trap->generic_trap, snmp->v1_trap->specific_trap); struct confd_snmp_oid *enterp = &snmp->v1_trap->enterprise; ptr += sprintf(ptr, " Enterprise="); for(i=0; i < enterp->len; i++) { ptr += sprintf(ptr,".%d", enterp->oid[i]); } } for (i=0; i < snmp->num_variables; i++) { struct confd_snmp_varbind *vb = &snmp->vb[i]; ptr += sprintf(ptr,"\n "); switch (vb->type) { case CONFD_SNMP_VARIABLE: ptr += sprintf(ptr, " %s ", vb_type(vb)); ptr += sprintf(ptr,"%s=", vb->var.name); break; case CONFD_SNMP_OID: ptr += sprintf(ptr, " %s ", vb_type(vb)); for (j=0; j < vb->var.oid.len; j++) { ptr += sprintf(ptr,"%d", vb->var.oid.oid[j]); if (j != vb->var.oid.len-1) ptr += sprintf(ptr,"."); } break; case CONFD_SNMP_COL_ROW: ptr += sprintf(ptr, " %s ", vb_type(vb)); ptr += sprintf(ptr, "%s", vb->var.cr.column); for(j=0; j<vb->var.cr.rowindex.len; j++) { ptr += sprintf(ptr,".%d", vb->var.cr.rowindex.oid[j]); } break; } if (vb->val.type == C_BUF) { char buf2[BUFSIZ]; confd_pp_value(buf2, BUFSIZ, &vb->val); ptr += sprintf(ptr, "=%s", buf2); } } printf("%s\n\n", buf); confd_free_notification(&n); }
ConfD can forward (proxy) connections from northbound agents.
When forwarding starts, ends, or fails, a
CONFD_NOTIF_FORWARD_INFO
event is generated.
The application receives a struct
confd_forward_notification structure which gives
the type of forwarding event, the name of the target for the
forwarding, and user session information for the user that
requested the forwarding.
During in-service upgrade, the CONFD_NOTIF_UPGRADE_EVENT event is generated with different values for the enum confd_upgrade_event_type event. The events correspond to the different phases of the upgrade, see Chapter 13, In-service Data Model Upgrade and confd_lib_maapi(3) for a detailed description.
The CONFD_NOTIF_HEARTBEAT
and
CONFD_NOTIF_HEALTH_CHECK
events can be used
by applications that wish to monitor the health and liveness of
ConfD itself. See confd_lib_events(3) for
more details about this.
The CONFD_NOTIF_STREAM_EVENT
event is
generated for a notification stream, i.e. event notifications sent
by an application as described in the section called “NOTIFICATION STREAMS” of confd_lib_dp(3). See confd_lib_events(3) for more details about
this.