How to add the support of the get_object() callback to the 5-c_stats example?

In order to improve the performance of the data provider API callbacks, for both external configuration as well as operational data, when dealing with lists with many leaf elements in them, it is recommended to provide the implementation of the get_object() API. This will reduce the number of round trip calls from the ConfD daemon process for retrieving the leaf elements of each instance in your list as they will all be fetched with a single API call as opposed to via multiple get_elem() calls.

The changes needed to add the get_object() callback support to the 5-c_stats example will be described in this posting. All the changes will be made to the arpstat.c file of the example.

In the main() function, you will add the registration of your get_object() callback as follows:

data.get_object = get_object;

The above statement can go immediately after the “data.get_next = get_next;” statement.

You will then modify the implementation of the find_ae() function as follows:

/* set pos to 0 if called from get_object( ) as the 0th [0][]
   elements of the 2 dimensional hkeypath array contain the 2 keys */
/* set pos to 1 if called from get_elem( ) as the 1st [1][]
   elements of the 2 dimensional hkeypath array contain the 2 keys */
static struct aentry *find_ae(confd_hkeypath_t *keypath, struct arpdata *dp, int pos)
{
    struct in_addr ip = CONFD_GET_IPV4(&keypath->v[pos][0]);
    char *iface = (char*)CONFD_GET_BUFPTR(&keypath->v[pos][1]);

    struct aentry *ae = dp->arp_entries;

    while (ae != NULL) {
        if (ip.s_addr == ae->ip4.s_addr &&
            (strcmp(ae->iface, iface) == 0) )
            return ae;
        ae=ae->next;
    }
    return NULL;
}

Please note that the hashed keypath for a get_object() callback differs from the hashed keypath for a get_elem() callback as explained in the comment blocks above the find_ae() function.

For the get_elem() callback, you will replace the find_ae() call as follows:

struct aentry *ae = find_ae(keypath, tctx->t_opaque, 1);

Please note the additional argument of 1 at the end of the find_ae() function call is used to signify that this is being called from the get_elem() callback.

Finally, the implementation of the get_object() callback is as follows:

/* Keypath example */
/* /arpentries/arpe{192.168.1.1 eth0} */
/*    2         1         0           */

static int get_object(struct confd_trans_ctx *tctx,
                      confd_hkeypath_t *keypath)
{
    confd_value_t v[5];

    struct aentry *ae = find_ae(keypath, tctx->t_opaque, 0);
    if (ae == NULL) {
        confd_data_reply_not_found(tctx);
        return CONFD_OK;
    }

    CONFD_SET_IPV4(&v[0], ae->ip4);
    CONFD_SET_STR(&v[1], ae->iface);
    if (ae->hwaddr == NULL) {
        CONFD_SET_NOEXISTS(&v[2]);
    } else {
        CONFD_SET_STR(&v[2], ae->hwaddr);
    }
    CONFD_SET_BOOL(&v[3], ae->perm);
    CONFD_SET_BOOL(&v[4], ae->pub);

    confd_data_reply_value_array(tctx, v, 5);

    return CONFD_OK;
}

After the above changes are made to the arpstat.c file, you will then be able to rebuild your project and see the get_object() callback in action through the TRACE statements of the arpstat program. An example output is shown below:

TRACE New user session: 11 for user:admin ctx:cli --> CONFD_OK
TRACE CALL trans init(thandle=6,mode="r",db=running) --> CONFD_OK
TRACE CALL data get_next(thandle=6, /arpentries/arpe, -1) --> CONFD_OK
TRACE CALL data get_next(thandle=6, /arpentries/arpe, -1) --> CONFD_OK
TRACE CALL data get_object(thandle=6,/arpentries/arpe{10.0.0.1 en0}) --> CONFD_OK
TRACE CALL data get_next(thandle=6, /arpentries/arpe, 0) --> CONFD_OK
1 Like