Help required in implementing callback for a read only field

Hi,
I have a yang file in which there is a read-only field(config false):

So the sync-state can be locked, holdover, or Free run. It will keep changing. So whenever client tries to fetch the field through netconf-console like : netconf-console- --host=10.10.11.101 -port=2023 --get -x /sync/sync-status/sync-state.
I should receive a callback for the same.so that I can collect the latest state from hardware and return the same to the client. If you can point the sample example through which I can achieve it, will be really helpful.

Regards,
Biswajit

Hello,

this seems to be straightforward use case for simple data provider - e.g. in one of intro examples: examples.confd/intro/5-c_stats.
(it is described in more detail in ConfD User Guide chapter 7 - operational data)

So, adding something like this to your YANG - “sync-state” leaf (or any other element that are also RO):

config false;
tailf:callpoint myCallpointName;

and then implementing the callpoint servicing app as described in UG/example sources…

It’s not clear from your image whether “sync-status” and “sync-state” are parent/child, resp. whether sync-status is (or is not) config false too.
(because config false+callpoint is inherited to all child elements/subtrees…)

In ideal case, you should only need to implement get_elem() callback, assuming you have only “leaf” elements that are RO…

edit: regarding details for implementation - i personally like manual pages the best (e.g. “man confd_lib_dp” in bash) - it imho gives nice insights on all callpoint’s callbacks and what they should return, etc.
It can shield you from some context that might be unnecessary/confusing when looking into example codebase (e.g. some examples may implement simple in-memory storage to simulate external db/source of data, etc.)

Hi ,
Thanks a lot for providing the example.
sync-status is a parent and it has one leaf called sync-state and has one list called supported-reference-types having key field as item.

  < sync xmlns="urn:o-ran:sync:1.0" >
    < sync-status >
         < sync-state/ >
      < supported-reference-types >
        < item/ >
      < /supported-reference-types >
    < /sync-status>

i have created a annotation file for the callpoint like as below and it built successully.

module o-ran-sync-ann {
  yang-version 1.1;
  namespace "urn:o-ran:sync-ann:1.0";
  prefix "o-ran-sync-ann";

  import o-ran-sync {
    prefix syn;
  }
  import tailf-common {
    prefix tailf;
  }
tailf:annotate "/syn:sync" {
tailf:callpoint cb_op_sync;
}
}

But I am facing an issue :
The yang has few rw fields also which is working fine if I will not add the annotation file. I am accessing all RW fields using cdb scribe API. But now when I have just added the annotation file and rebuilt the yang, tested the same rw field before testing operation data, then I am getting error like :

DEBUG badly formatted or nonexistent path - Not a cdb path: /sync.

I am getting the error while calling the cdb_subscribe.
I am providing the path as “/sync” in the 5th argument of cdb_subscribe API.
If you can figure out my mistake then it will be really helpful.

To reconfirm again, Everything is the same in both the case except of adding annotation file

Regards,
Biswajit

you didn’t paste the main YANG part, but i think the problem is due to callpoint placement.

If you put tailf:callpoint; together with config false;, it makes ALL the nested children of the element (if you put it on some container/list) read only data provider implicitly…

If you put tailf:callpoint someplace without config false (resp. with config true), it makes that part of the subrtree (again inherited by all sub-sub-…-children) to be an external database - and, as user guide states (though not explicitly) - you cannot subscribe to external database model… it’s up to DB to notify interested parties about configuration change… (e.g. for confd 7.2 - chapter 8.10. Discussion - CDB versus external DB)

Thus, if your main YANG structure cannot be changed, you will need to modify your callpoint annotation to be put only to all of your RO element(s) specifically… (or only to root of RO only container/list, if it exists / depending in your YANG structure)

edit:
something like: tailf:annotate "/syn:sync/sync-status/sync-state" {...} for one leaf only,
or tailf:annotate "/syn:sync/sync-status" {...} to make “sync-status” container and all of it’s children managed by data subscriber / callpoint

Hi Josephm,
You are absolutely Correct in finding my mistake. Yesterday night while debugging I got the same and fixed.
The Yang looks like :

 grouping sync-group {
    container sync-status {
      config false;

  description
    "Object of this class provides synchronization state of the module.";

  leaf sync-state {
    type enumeration {
      enum LOCKED {
        description
          "equipment is in the locked mode, as defined in ITU-T G.810";
      }
      enum HOLDOVER {
        description
          "equipment clock is in holdover mode";
      }
      enum FREERUN {
        description
          "equipment clock isn't locked to an input reference, and is not in the holdover mode";
      }
    }
    mandatory true;
    description
      "State of DU synchronization";
  }

  list supported-reference-types {
    key item;
    min-elements 1;
    description
      "Type of a synchronization supported source.";
    leaf item {
      type enumeration {
        enum GNSS {
          description
            "GPS can be taken as a synchronization source";
        }
        enum PTP {
          description
            "Precision Time Protocol can be taken as a synchronization source";
        }
        enum SYNCE {
          description
            "Synchronous Ethernet can be taken as a synchronization source";
        }
      }
      mandatory true;

      description
        "supported reference-type";
    }
  }
}

suppose I have provided the callpoint as /syn:sync/sync-status
I am currently trying to implement a framework(wrapper function) for operational data that can be used for all the yang files.
So for that, I am having few doubts:

  1. in current yang, there is “item” field under the supported-reference-types list and sync-state under sync-status. So can you please help me in understanding the sample code.
    the get_elem() function can provide a callback to all the config false leaf of sync-status But for the supported-reference-types list, we need to use the get_next() function. Let me know whether my understanding is correct or not.
    2.what is the use case of s_init() & s_exit() function.
    3.What’s the main use of confd_register_data_cb function…I have gone through the user guide but didn’t able to understand.

If you can help me in designing a wrapper API for the same then it will really helpful.

Regards,
Biswajit

1.in current yang, there is “item” field under the supported-reference-types list and sync-state under sync-status. So can you please help me in understanding the sample code.
the get_elem() function can provide a callback to all the config false leaf of sync-status But for the supported-reference-types list, we need to use the get_next() function. Let me know whether my understanding is correct or not.

yes - if your YANG has some lists (or leaf-lists), you to implement get_next() callback too.

There are more examples or similar implementations in other examples, try grepping for confd_data_reply_next_key that is to be used as a response inside get-next()…
(or, manual pages for nice description.details again)

Some of other examples are not data providers but transformations, but principle is almost same.

2.what is the use case of s_init() & s_exit() function.

Sort of typical constructor/destructor of data provider transaction.
Inside this intro example, it just prepares/cleans the internal in-memory “database”/structures that keep example operational data, to provide values to ConfD whenever it invokes callbacks…
If you need e.g. user session specific allocations/work, you can do it here, etc.

3.What’s the main use of confd_register_data_cb function…I have gone through the user guide but didn’t able to understand.

With this function, you tell ConfD:

  • use this confd_data_cbs structure (input parameter of function) whenever someone wants to do stuff with YANG data managed by the callpoint.

(i didnt write “read data”, because this same procedure can be used to register RO data provider callpoints, but also RW transformation callpoints)

Callpoint name is part of input parameter, so you can register many different callpoints if you need/want, and separate code for different parts of YANG model.

confd_data_cbs is a wrapper for set of callback procedures that you must implement (get_elem(), get_next(), …).

Depending on how your YANG model looks, you need to implement some of (or even all) of various callbacks… e.g. you need:

  • get_elem() - if you have some leaves (which is usually always :slight_smile: )
  • get_next() - if you have lists or leaf-lists in YANG
  • get_case() - if you have choice statements
    etc.

In your YANG, you can put same callpoint (e.g. tailf:callpoint "helloCp";") to several different places. e.g. to two different leaves, one list, and other places, no problem…

When the callback code is invoked by ConfD, you will have input parameters of callback.
This will tell you for which element specifically you need to create the response…

Nice description of each callback and parameters etc. in man page for:
int confd_register_data_cb(struct confd_daemon_ctx *dx, const struct confd_data_cbs *data);

Best way to play with DP (data provider) implementation is IMHO to print/see all the input parameters of callback procedures (like get_elem(), get_next(), exists_optional(), etc.) to see the which types of “questions” come from confd, and how it depends on YANG model.

Plus if you do not have some of the callpoints registered, but confd needs it, you will see complaints in confd-library log in your app, or in confd devel log.

Hi Josephm,
Thanks alot for clarifying the doubts.
Currently when i am executing below command:
/new-home/buildtools/confd/7.3/x86_64/bin/netconf-console-tcp --host=10.10.11.101 -port=2023 --get -x /sync/sync-status/sync-state
Then on Confd, i am getting below error :

DEBUG No descriptor set for trans
Bad protocol usage or unexpected retval, last err No descriptor set for trans

But the debug message kept in assigned callback function of confd_trans_cbs(trans.init) ,is printing.
Not sure where is the issue.

Regards,
Biswajit