If you implement operational data to be kept in the CDB operational datastore, and you are writing to large lists / tables, your application performance may benefit from using cdb_set_values()
instead of cdb_set_elem()
or cdb_set_object()
.
cdb_set_values()
allow you to write multiple list / table entries with a single call to CDB operational datastore, instead of using several with cdb_set_object()
– one row per call, or cdb_set_elem()
– one leaf per call.
Here is a diff of how to replace cdb_set_object()
in the $CONFD_DIR/examples.confd/cdb_oper/ifstatus
example. Note how cdb_set_values()
is called one time only to set multiple list entries, where as before cdb_set_object()
was called for every row in the list.
$ diff -u $CONFD_DIR/examples.confd/cdb_oper/ifstatus-orig/ifstatus.c ifstatus.c
--- $CONFD_DIR/examples.confd/cdb_oper/ifstatus-orig/ifstatus.c 2015-07-17 04:56:53.000000000 +0200
+++ ifstatus.c 2015-08-30 16:17:49.983922544 +0200
@@ -28,11 +28,11 @@
{
FILE *proc;
int ret;
- char buf[BUFSIZ];
- char *ifname, *p;
+ char statbuf[BUFSIZ];
+ char *ifname, *p, *buf;
long long counter;
- confd_value_t val[1 + 4 + 1 + 5];
- int i;
+ confd_tag_value_t tval[BUFSIZ];
+ int i,len,nlen;
if ((ret = cdb_start_session(sock, CDB_OPERATIONAL)) != CONFD_OK)
return ret;
@@ -41,46 +41,56 @@
if ((proc = fopen("/proc/net/dev", "r")) == NULL)
return CONFD_ERR;
- while (ret == CONFD_OK && fgets(buf, sizeof(buf), proc) != NULL) {
+ i = 0;
+ buf = &statbuf[0];
+ len = sizeof(statbuf);
+ while (fgets(buf, len, proc) != NULL) {
if ((p = strchr(buf, ':')) == NULL)
continue;
*p = ' ';
if ((ifname = strtok(buf, " \t")) == NULL)
continue;
-
- i = 0;
-
- CONFD_SET_XMLTAG(&val[i], if_receive, if__ns); i++;
+ nlen = strlen(ifname)+3;
+ buf += nlen;
+ len -= nlen;
+ /* <interface> */
+ CONFD_SET_TAG_XMLBEGIN(&tval[i], if_interface, if__ns); i++;
+ /* <name>ifname</name> */
+ CONFD_SET_TAG_STR(&tval[i], if_name, ifname); i++;
+ /* <status> */
+ CONFD_SET_TAG_XMLBEGIN(&tval[i], if_status, if__ns); i++;
+ /* <receive> */
+ CONFD_SET_TAG_XMLBEGIN(&tval[i], if_receive, if__ns); i++;
GET_COUNTER(); /* rx bytes */
- CONFD_SET_UINT64(&val[i], counter); i++;
+ CONFD_SET_TAG_UINT64(&tval[i], if_bytes, counter); i++;
GET_COUNTER(); /* rx packets */
- CONFD_SET_UINT64(&val[i], counter); i++;
+ CONFD_SET_TAG_UINT64(&tval[i], if_packets, counter); i++;
GET_COUNTER(); /* rx errs */
- CONFD_SET_UINT32(&val[i], counter); i++;
+ CONFD_SET_TAG_UINT32(&tval[i], if_errors, counter); i++;
GET_COUNTER(); /* rx drop */
- CONFD_SET_UINT32(&val[i], counter); i++;
+ CONFD_SET_TAG_UINT32(&tval[i], if_dropped, counter); i++;
/* skip remaining rx counters */
GET_COUNTER(); GET_COUNTER(); GET_COUNTER(); GET_COUNTER();
-
- CONFD_SET_XMLTAG(&val[i], if_transmit, if__ns); i++;
+ CONFD_SET_TAG_XMLEND(&tval[i], if_receive, if__ns); i++;
+
+ CONFD_SET_TAG_XMLBEGIN(&tval[i], if_transmit, if__ns); i++;
GET_COUNTER(); /* tx bytes */
- CONFD_SET_UINT64(&val[i], counter); i++;
+ CONFD_SET_TAG_UINT64(&tval[i], if_bytes, counter); i++;
GET_COUNTER(); /* tx packets */
- CONFD_SET_UINT64(&val[i], counter); i++;
+ CONFD_SET_TAG_UINT64(&tval[i], if_packets, counter); i++;
GET_COUNTER(); /* tx errs */
- CONFD_SET_UINT32(&val[i], counter); i++;
+ CONFD_SET_TAG_UINT32(&tval[i], if_errors, counter); i++;
GET_COUNTER(); /* tx drop */
- CONFD_SET_UINT32(&val[i], counter); i++;
+ CONFD_SET_TAG_UINT32(&tval[i], if_dropped, counter); i++;
GET_COUNTER(); /* skip */
GET_COUNTER(); /* tx colls */
- CONFD_SET_UINT32(&val[i], counter); i++;
-
- ret = cdb_set_object(sock, val, i,
- "/interfaces/interface{%s}/status", ifname);
- if (ret == CONFD_ERR && confd_errno == CONFD_ERR_BADPATH)
- /* assume interface doesn't exist in config */
- ret = CONFD_OK;
+ CONFD_SET_TAG_UINT32(&tval[i], if_collisions, counter); i++;
+ CONFD_SET_TAG_XMLEND(&tval[i], if_transmit, if__ns); i++;
+ CONFD_SET_TAG_XMLEND(&tval[i], if_status, if__ns); i++;
+ CONFD_SET_TAG_XMLEND(&tval[i], if_interface, if__ns); i++;
}
+ ret = cdb_set_values(sock, tval, i, "/interfaces");
+
fclose(proc);
We modify the YANG model slightly so that we can with cdb_set_values()
always display all interfaces available with stats.
$ diff -u $CONFD_DIR/examples.confd/cdb_oper/ifstatus-orig/if.yang if.yang
--- $CONFD_DIR/examples.confd/cdb_oper/ifstatus-orig/if.yang 2015-07-17 04:56:53.000000000 +0200
+++ if.yang 2015-08-30 12:05:40.729898471 +0200
@@ -14,24 +14,13 @@
list interface {
key name;
max-elements 1024;
+ config false;
+ tailf:cdb-oper;
+
leaf name {
type string;
}
- list address {
- key name;
- max-elements 64;
- leaf name {
- type inet:ipv4-address;
- }
- leaf prefix-length {
- type int32;
- mandatory true;
- }
- }
container status {
- config false;
- tailf:cdb-oper;
-
container receive {
leaf bytes {
type uint64;
Quick demo:
Terminal window 1
$pwd
$CONFD_DIR/examples.confd/cdb_oper/ifstatus
$ make clean all start
...
### In another terminal window, start the CLI (make cli)
### Starting the ifstatus agent
./ifstatus
Terminal window 2:
$ make cli
...
admin connected from 127.0.0.1 using console on tailf
# show interfaces
NAME BYTES PACKETS ERRORS DROPPED BYTES PACKETS ERRORS DROPPED COLLISIONS
-------------------------------------------------------------------------------------------
eth0 272695599 268326 0 0 15561251 125588 0 0 0
lo 92784568 157955 0 0 92784568 157955 0 0 0