static struct confd_notification_ctx *live_ctx;
static bool confd_connected;
static struct list *confd_spoints;
+static struct nb_transaction *transaction;
static void frr_confd_finish_cdb(void);
static void frr_confd_finish_dp(void);
return 0;
}
-/* Obtain list keys from ConfD hashed keypath. */
-static void frr_confd_hkeypath_get_keys(const confd_hkeypath_t *kp,
- struct yang_list_keys *keys)
+/* Obtain list entry from ConfD hashed keypath. */
+static int frr_confd_hkeypath_get_list_entry(const confd_hkeypath_t *kp,
+ struct nb_node *nb_node,
+ const void **list_entry)
{
- memset(keys, 0, sizeof(*keys));
- for (int i = 0; i < kp->len; i++) {
+ struct nb_node *nb_node_list;
+ int parent_lists = 0;
+ int curr_list = 0;
+
+ *list_entry = NULL;
+
+ /*
+ * Count the number of YANG lists in the path, disconsidering the
+ * last element.
+ */
+ nb_node_list = nb_node;
+ while (nb_node_list->parent_list) {
+ nb_node_list = nb_node_list->parent_list;
+ parent_lists++;
+ }
+ if (nb_node->snode->nodetype != LYS_LIST && parent_lists == 0)
+ return 0;
+
+ /* Start from the beginning and move down the tree. */
+ for (int i = kp->len; i >= 0; i--) {
+ struct yang_list_keys keys;
+
+ /* Not a YANG list. */
if (kp->v[i][0].type != C_BUF)
continue;
+ /* Obtain list keys. */
+ memset(&keys, 0, sizeof(keys));
for (int j = 0; kp->v[i][j].type != C_NOEXISTS; j++) {
- strlcpy(keys->key[keys->num].value,
+ strlcpy(keys.key[keys.num],
(char *)kp->v[i][j].val.buf.ptr,
- sizeof(keys->key[keys->num].value));
- keys->num++;
+ sizeof(keys.key[keys.num]));
+ keys.num++;
+ }
+
+ /* Obtain northbound node associated to the YANG list. */
+ nb_node_list = nb_node;
+ for (int j = curr_list; j < parent_lists; j++)
+ nb_node_list = nb_node_list->parent_list;
+
+ /* Obtain list entry. */
+ if (!CHECK_FLAG(nb_node_list->flags, F_NB_NODE_KEYLESS_LIST)) {
+ *list_entry = nb_node_list->cbs.lookup_entry(
+ *list_entry, &keys);
+ if (*list_entry == NULL)
+ return -1;
+ } else {
+ unsigned long ptr_ulong;
+
+ /* Retrieve list entry from pseudo-key (string). */
+ if (sscanf(keys.key[0], "%lu", &ptr_ulong) != 1)
+ return -1;
+ *list_entry = (const void *)ptr_ulong;
}
+
+ curr_list++;
}
+
+ return 0;
}
/* Fill the current date and time into a confd_datetime structure. */
return ITER_RECURSE;
}
-static int frr_confd_cdb_read_cb(struct thread *thread)
+static int frr_confd_cdb_read_cb_prepare(int fd, int *subp, int reslen)
{
- int fd = THREAD_FD(thread);
- int *subp = NULL;
- enum cdb_sub_notification cdb_ev;
- int flags;
- int reslen = 0;
struct nb_config *candidate;
struct cdb_iter_args iter_args;
int ret;
- thread = NULL;
- thread_add_read(master, frr_confd_cdb_read_cb, NULL, fd, &thread);
-
- if (cdb_read_subscription_socket2(fd, &cdb_ev, &flags, &subp, &reslen)
- != CONFD_OK) {
- flog_err_confd("cdb_read_subscription_socket2");
- return -1;
- }
-
- /*
- * Ignore CDB_SUB_ABORT and CDB_SUB_COMMIT. We'll leverage the
- * northbound layer itself to abort or apply the configuration changes
- * when a transaction is created.
- */
- if (cdb_ev != CDB_SUB_PREPARE) {
- free(subp);
- if (cdb_sync_subscription_socket(fd, CDB_DONE_PRIORITY)
- != CONFD_OK) {
- flog_err_confd("cdb_sync_subscription_socket");
- return -1;
- }
- return 0;
- }
-
candidate = nb_config_dup(running_config);
/* Iterate over all configuration changes. */
return 0;
}
- ret = nb_candidate_commit(candidate, NB_CLIENT_CONFD, true, NULL, NULL);
- nb_config_free(candidate);
+ /*
+ * Validate the configuration changes and allocate all resources
+ * required to apply them.
+ */
+ transaction = NULL;
+ ret = nb_candidate_commit_prepare(candidate, NB_CLIENT_CONFD, NULL,
+ &transaction);
if (ret != NB_OK && ret != NB_ERR_NO_CHANGES) {
enum confd_errcode errcode;
const char *errmsg;
break;
}
+ /* Reject the configuration changes. */
if (cdb_sub_abort_trans(cdb_sub_sock, errcode, 0, 0, "%s",
errmsg)
!= CONFD_OK) {
return -1;
}
} else {
+ /* Acknowledge the notification. */
if (cdb_sync_subscription_socket(fd, CDB_DONE_PRIORITY)
!= CONFD_OK) {
flog_err_confd("cdb_sync_subscription_socket");
return -1;
}
+
+ /* No configuration changes. */
+ if (!transaction)
+ nb_config_free(candidate);
+ }
+
+ return 0;
+}
+
+static int frr_confd_cdb_read_cb_commit(int fd, int *subp, int reslen)
+{
+ /*
+ * No need to process the configuration changes again as we're already
+ * keeping track of them in the "transaction" variable.
+ */
+ free(subp);
+
+ /* Apply the transaction. */
+ if (transaction) {
+ struct nb_config *candidate = transaction->config;
+
+ nb_candidate_commit_apply(transaction, true, NULL);
+ nb_config_free(candidate);
+ }
+
+ /* Acknowledge the notification. */
+ if (cdb_sync_subscription_socket(fd, CDB_DONE_PRIORITY) != CONFD_OK) {
+ flog_err_confd("cdb_sync_subscription_socket");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int frr_confd_cdb_read_cb_abort(int fd, int *subp, int reslen)
+{
+ /*
+ * No need to process the configuration changes again as we're already
+ * keeping track of them in the "transaction" variable.
+ */
+ free(subp);
+
+ /* Abort the transaction. */
+ if (transaction) {
+ struct nb_config *candidate = transaction->config;
+
+ nb_candidate_commit_abort(transaction);
+ nb_config_free(candidate);
+ }
+
+ /* Acknowledge the notification. */
+ if (cdb_sync_subscription_socket(fd, CDB_DONE_PRIORITY) != CONFD_OK) {
+ flog_err_confd("cdb_sync_subscription_socket");
+ return -1;
}
return 0;
}
+static int frr_confd_cdb_read_cb(struct thread *thread)
+{
+ int fd = THREAD_FD(thread);
+ enum cdb_sub_notification cdb_ev;
+ int flags;
+ int *subp = NULL;
+ int reslen = 0;
+
+ thread = NULL;
+ thread_add_read(master, frr_confd_cdb_read_cb, NULL, fd, &thread);
+
+ if (cdb_read_subscription_socket2(fd, &cdb_ev, &flags, &subp, &reslen)
+ != CONFD_OK) {
+ flog_err_confd("cdb_read_subscription_socket2");
+ return -1;
+ }
+
+ switch (cdb_ev) {
+ case CDB_SUB_PREPARE:
+ return frr_confd_cdb_read_cb_prepare(fd, subp, reslen);
+ case CDB_SUB_COMMIT:
+ return frr_confd_cdb_read_cb_commit(fd, subp, reslen);
+ case CDB_SUB_ABORT:
+ return frr_confd_cdb_read_cb_abort(fd, subp, reslen);
+ default:
+ flog_err_confd("unknown CDB event");
+ return -1;
+ }
+}
+
/* Trigger CDB subscriptions to read the startup configuration. */
static void *thread_cdb_trigger_subscriptions(void *data)
{
continue;
}
+ if (CHECK_FLAG(snode->flags, LYS_CONFIG_R))
+ continue;
+
nb_node = snode->priv;
if (debug_northbound)
zlog_debug("%s: subscribing to '%s'", __func__,
return CONFD_OK;
}
+#define CONFD_MAX_CHILD_NODES 32
+
static int frr_confd_data_get_elem(struct confd_trans_ctx *tctx,
confd_hkeypath_t *kp)
{
- struct nb_node *nb_node, *parent_list;
+ struct nb_node *nb_node;
char xpath[BUFSIZ];
- struct yang_list_keys keys;
struct yang_data *data;
confd_value_t v;
const void *list_entry = NULL;
return CONFD_OK;
}
- parent_list = nb_node->parent_list;
- if (parent_list) {
- frr_confd_hkeypath_get_keys(kp, &keys);
- list_entry = parent_list->cbs.lookup_entry(&keys);
- if (!list_entry) {
- flog_warn(EC_LIB_NB_CB_STATE,
- "%s: list entry not found: %s", __func__,
- xpath);
- confd_data_reply_not_found(tctx);
- return CONFD_OK;
- }
+ if (frr_confd_hkeypath_get_list_entry(kp, nb_node, &list_entry) != 0) {
+ confd_data_reply_not_found(tctx);
+ return CONFD_OK;
}
data = nb_node->cbs.get_elem(xpath, list_entry);
{
struct nb_node *nb_node;
char xpath[BUFSIZ];
- struct yang_list_keys keys;
- const void *nb_next;
+ struct yang_data *data;
+ const void *parent_list_entry, *nb_next;
confd_value_t v[LIST_MAXKEYS];
frr_confd_get_xpath(kp, xpath, sizeof(xpath));
return CONFD_OK;
}
- nb_next = nb_node->cbs.get_next(xpath,
- (next == -1) ? NULL : (void *)next);
- if (!nb_next) {
- /* End of the list. */
+ if (frr_confd_hkeypath_get_list_entry(kp, nb_node, &parent_list_entry)
+ != 0) {
+ /* List entry doesn't exist anymore. */
confd_data_reply_next_key(tctx, NULL, -1, -1);
return CONFD_OK;
}
- if (nb_node->cbs.get_keys(nb_next, &keys) != NB_OK) {
- flog_warn(EC_LIB_NB_CB_STATE, "%s: failed to get list keys",
- __func__);
+
+ nb_next = nb_node->cbs.get_next(parent_list_entry,
+ (next == -1) ? NULL : (void *)next);
+ if (!nb_next) {
+ /* End of the list or leaf-list. */
confd_data_reply_next_key(tctx, NULL, -1, -1);
return CONFD_OK;
}
- /* Feed keys to ConfD. */
- for (size_t i = 0; i < keys.num; i++)
- CONFD_SET_STR(&v[i], keys.key[i].value);
- confd_data_reply_next_key(tctx, v, keys.num, (long)nb_next);
+ switch (nb_node->snode->nodetype) {
+ case LYS_LIST:
+ if (!CHECK_FLAG(nb_node->flags, F_NB_NODE_KEYLESS_LIST)) {
+ struct yang_list_keys keys;
+
+ memset(&keys, 0, sizeof(keys));
+ if (nb_node->cbs.get_keys(nb_next, &keys) != NB_OK) {
+ flog_warn(EC_LIB_NB_CB_STATE,
+ "%s: failed to get list keys",
+ __func__);
+ confd_data_reply_next_key(tctx, NULL, -1, -1);
+ return CONFD_OK;
+ }
+
+ /* Feed keys to ConfD. */
+ for (size_t i = 0; i < keys.num; i++)
+ CONFD_SET_STR(&v[i], keys.key[i]);
+ confd_data_reply_next_key(tctx, v, keys.num,
+ (long)nb_next);
+ } else {
+ char pointer_str[16];
+
+ /*
+ * ConfD 6.6 user guide, chapter 6.11 (Operational data
+ * lists without keys):
+ * "To support this without having completely separate
+ * APIs, we use a "pseudo" key in the ConfD APIs for
+ * this type of list. This key is not part of the data
+ * model, and completely hidden in the northbound agent
+ * interfaces, but is used with e.g. the get_next() and
+ * get_elem() callbacks as if it were a normal key. This
+ * "pseudo" key is always a single signed 64-bit
+ * integer, i.e. the confd_value_t type is C_INT64. The
+ * values can be chosen arbitrarily by the application,
+ * as long as a key value returned by get_next() can be
+ * used to get the data for the corresponding list entry
+ * with get_elem() or get_object() as usual. It could
+ * e.g. be an index into an array that holds the data,
+ * or even a memory address in integer form".
+ *
+ * Since we're using the CONFD_DAEMON_FLAG_STRINGSONLY
+ * option, we must convert our pseudo-key (a void
+ * pointer) to a string before sending it to confd.
+ */
+ snprintf(pointer_str, sizeof(pointer_str), "%lu",
+ (unsigned long)nb_next);
+ CONFD_SET_STR(&v[0], pointer_str);
+ confd_data_reply_next_key(tctx, v, 1, (long)nb_next);
+ }
+ break;
+ case LYS_LEAFLIST:
+ data = nb_node->cbs.get_elem(xpath, nb_next);
+ if (data) {
+ if (data->value) {
+ CONFD_SET_STR(&v[0], data->value);
+ confd_data_reply_next_key(tctx, v, 1,
+ (long)nb_next);
+ }
+ yang_data_free(data);
+ } else
+ confd_data_reply_next_key(tctx, NULL, -1, -1);
+ break;
+ default:
+ break;
+ }
return CONFD_OK;
}
confd_hkeypath_t *kp)
{
struct nb_node *nb_node;
+ const struct lys_node *child;
char xpath[BUFSIZ];
- char xpath_children[XPATH_MAXLEN];
char xpath_child[XPATH_MAXLEN];
- struct yang_list_keys keys;
struct list *elements;
struct yang_data *data;
const void *list_entry;
- struct ly_set *set;
- confd_value_t *values;
+ confd_value_t values[CONFD_MAX_CHILD_NODES];
+ size_t nvalues = 0;
frr_confd_get_xpath(kp, xpath, sizeof(xpath));
flog_warn(EC_LIB_YANG_UNKNOWN_DATA_PATH,
"%s: unknown data path: %s", __func__, xpath);
confd_data_reply_not_found(tctx);
- return CONFD_OK;
+ return CONFD_ERR;
}
- frr_confd_hkeypath_get_keys(kp, &keys);
- list_entry = nb_node->cbs.lookup_entry(&keys);
- if (!list_entry) {
- flog_warn(EC_LIB_NB_CB_STATE, "%s: list entry not found: %s",
- __func__, xpath);
+ if (frr_confd_hkeypath_get_list_entry(kp, nb_node, &list_entry) != 0) {
confd_data_reply_not_found(tctx);
return CONFD_OK;
}
- /* Find list child nodes. */
- snprintf(xpath_children, sizeof(xpath_children), "%s/*", xpath);
- set = lys_find_path(nb_node->snode->module, NULL, xpath_children);
- if (!set) {
- flog_warn(EC_LIB_LIBYANG, "%s: lys_find_path() failed",
- __func__);
- return CONFD_ERR;
- }
-
elements = yang_data_list_new();
- values = XMALLOC(MTYPE_CONFD, set->number * sizeof(*values));
/* Loop through list child nodes. */
- for (size_t i = 0; i < set->number; i++) {
- struct lys_node *child;
- struct nb_node *nb_node_child;
+ LY_TREE_FOR (nb_node->snode->child, child) {
+ struct nb_node *nb_node_child = child->priv;
+ confd_value_t *v;
- child = set->set.s[i];
- nb_node_child = child->priv;
+ if (nvalues > CONFD_MAX_CHILD_NODES)
+ break;
+
+ v = &values[nvalues++];
+
+ /* Non-presence containers, lists and leaf-lists. */
+ if (!nb_node_child->cbs.get_elem) {
+ CONFD_SET_NOEXISTS(v);
+ continue;
+ }
snprintf(xpath_child, sizeof(xpath_child), "%s/%s", xpath,
child->name);
-
data = nb_node_child->cbs.get_elem(xpath_child, list_entry);
if (data) {
if (data->value)
- CONFD_SET_STR(&values[i], data->value);
- else
- CONFD_SET_NOEXISTS(&values[i]);
+ CONFD_SET_STR(v, data->value);
+ else {
+ /* Presence containers and empty leafs. */
+ CONFD_SET_XMLTAG(
+ v, nb_node_child->confd_hash,
+ confd_str2hash(nb_node_child->snode
+ ->module->ns));
+ }
listnode_add(elements, data);
} else
- CONFD_SET_NOEXISTS(&values[i]);
+ CONFD_SET_NOEXISTS(v);
}
- confd_data_reply_value_array(tctx, values, set->number);
+ confd_data_reply_value_array(tctx, values, nvalues);
/* Release memory. */
- ly_set_free(set);
- XFREE(MTYPE_CONFD, values);
list_delete(&elements);
return CONFD_OK;
confd_hkeypath_t *kp, long next)
{
char xpath[BUFSIZ];
- char xpath_children[XPATH_MAXLEN];
struct nb_node *nb_node;
- struct ly_set *set;
struct list *elements;
+ const void *parent_list_entry;
const void *nb_next;
#define CONFD_OBJECTS_PER_TIME 100
struct confd_next_object objects[CONFD_OBJECTS_PER_TIME + 1];
+ char pseudo_keys[CONFD_OBJECTS_PER_TIME][16];
int nobjects = 0;
frr_confd_get_xpath(kp, xpath, sizeof(xpath));
return CONFD_OK;
}
- /* Find list child nodes. */
- snprintf(xpath_children, sizeof(xpath_children), "%s/*", xpath);
- set = lys_find_path(nb_node->snode->module, NULL, xpath_children);
- if (!set) {
- flog_warn(EC_LIB_LIBYANG, "%s: lys_find_path() failed",
- __func__);
- return CONFD_ERR;
+ if (frr_confd_hkeypath_get_list_entry(kp, nb_node, &parent_list_entry)
+ != 0) {
+ confd_data_reply_next_object_array(tctx, NULL, 0, 0);
+ return CONFD_OK;
}
elements = yang_data_list_new();
memset(objects, 0, sizeof(objects));
for (int j = 0; j < CONFD_OBJECTS_PER_TIME; j++) {
struct confd_next_object *object;
- struct yang_list_keys keys;
+ struct lys_node *child;
struct yang_data *data;
- const void *list_entry;
+ size_t nvalues = 0;
object = &objects[j];
- nb_next = nb_node->cbs.get_next(xpath, nb_next);
+ nb_next = nb_node->cbs.get_next(parent_list_entry, nb_next);
if (!nb_next)
/* End of the list. */
break;
- if (nb_node->cbs.get_keys(nb_next, &keys) != NB_OK) {
- flog_warn(EC_LIB_NB_CB_STATE,
- "%s: failed to get list keys", __func__);
- continue;
- }
object->next = (long)nb_next;
- list_entry = nb_node->cbs.lookup_entry(&keys);
- if (!list_entry) {
- flog_warn(EC_LIB_NB_CB_STATE,
- "%s: failed to lookup list entry", __func__);
- continue;
+ /* Leaf-lists require special handling. */
+ if (nb_node->snode->nodetype == LYS_LEAFLIST) {
+ object->v = XMALLOC(MTYPE_CONFD, sizeof(confd_value_t));
+ data = nb_node->cbs.get_elem(xpath, nb_next);
+ assert(data && data->value);
+ CONFD_SET_STR(object->v, data->value);
+ nvalues++;
+ listnode_add(elements, data);
+ goto next;
}
- object->v = XMALLOC(MTYPE_CONFD,
- set->number * sizeof(confd_value_t));
+ object->v =
+ XMALLOC(MTYPE_CONFD,
+ CONFD_MAX_CHILD_NODES * sizeof(confd_value_t));
+
+ /*
+ * ConfD 6.6 user guide, chapter 6.11 (Operational data lists
+ * without keys):
+ * "In the response to the get_next_object() callback, the data
+ * provider is expected to provide the key values along with the
+ * other leafs in an array that is populated according to the
+ * data model. This must be done also for this type of list,
+ * even though the key isn't actually in the data model. The
+ * "pseudo" key must always be the first element in the array".
+ */
+ if (CHECK_FLAG(nb_node->flags, F_NB_NODE_KEYLESS_LIST)) {
+ confd_value_t *v;
+
+ snprintf(pseudo_keys[j], sizeof(pseudo_keys[j]), "%lu",
+ (unsigned long)nb_next);
+
+ v = &object->v[nvalues++];
+ CONFD_SET_STR(v, pseudo_keys[j]);
+ }
/* Loop through list child nodes. */
- for (unsigned int i = 0; i < set->number; i++) {
- struct lys_node *child;
- struct nb_node *nb_node_child;
+ LY_TREE_FOR (nb_node->snode->child, child) {
+ struct nb_node *nb_node_child = child->priv;
char xpath_child[XPATH_MAXLEN];
- confd_value_t *v = &object->v[i];
+ confd_value_t *v;
+
+ if (nvalues > CONFD_MAX_CHILD_NODES)
+ break;
- child = set->set.s[i];
- nb_node_child = child->priv;
+ v = &object->v[nvalues++];
+
+ /* Non-presence containers, lists and leaf-lists. */
+ if (!nb_node_child->cbs.get_elem) {
+ CONFD_SET_NOEXISTS(v);
+ continue;
+ }
snprintf(xpath_child, sizeof(xpath_child), "%s/%s",
xpath, child->name);
-
data = nb_node_child->cbs.get_elem(xpath_child,
- list_entry);
+ nb_next);
if (data) {
if (data->value)
CONFD_SET_STR(v, data->value);
- else
- CONFD_SET_NOEXISTS(v);
+ else {
+ /*
+ * Presence containers and empty leafs.
+ */
+ CONFD_SET_XMLTAG(
+ v, nb_node_child->confd_hash,
+ confd_str2hash(
+ nb_node_child->snode
+ ->module->ns));
+ }
listnode_add(elements, data);
} else
CONFD_SET_NOEXISTS(v);
}
- object->n = set->number;
+ next:
+ object->n = nvalues;
nobjects++;
}
- ly_set_free(set);
if (nobjects == 0) {
confd_data_reply_next_object_array(tctx, NULL, 0, 0);
CONFD_SET_TAG_XMLBEGIN(&values[i++], nb_node->confd_hash,
module->confd_hash);
for (ALL_LIST_ELEMENTS_RO(arguments, node, data)) {
- struct nb_node *option_arg;
+ struct nb_node *nb_node_arg;
+
+ nb_node_arg = nb_node_find(data->xpath);
+ if (!nb_node_arg) {
+ flog_warn(EC_LIB_YANG_UNKNOWN_DATA_PATH,
+ "%s: unknown data path: %s", __func__,
+ data->xpath);
+ XFREE(MTYPE_CONFD, values);
+ return NB_ERR;
+ }
- option_arg = data->snode->priv;
- CONFD_SET_TAG_STR(&values[i++], option_arg->confd_hash,
+ CONFD_SET_TAG_STR(&values[i++], nb_node_arg->confd_hash,
data->value);
}
CONFD_SET_TAG_XMLEND(&values[i++], nb_node->confd_hash,
listcount(output) * sizeof(*reply));
for (ALL_LIST_ELEMENTS_RO(output, node, data)) {
+ struct nb_node *nb_node_output;
int hash;
- hash = confd_str2hash(data->snode->name);
+ nb_node_output = nb_node_find(data->xpath);
+ if (!nb_node_output) {
+ flog_warn(EC_LIB_YANG_UNKNOWN_DATA_PATH,
+ "%s: unknown data path: %s", __func__,
+ data->xpath);
+ goto exit;
+ }
+
+ hash = confd_str2hash(nb_node_output->snode->name);
CONFD_SET_TAG_STR(&reply[i++], hash, data->value);
}
confd_action_reply_values(uinfo, reply, listcount(output));
ret = confd_fd_ready(dctx, fd);
if (ret == CONFD_EOF) {
flog_err_confd("confd_fd_ready");
+ frr_confd_finish();
return -1;
} else if (ret == CONFD_ERR && confd_errno != CONFD_ERR_EXTERNAL) {
flog_err_confd("confd_fd_ready");
+ frr_confd_finish();
return -1;
}
return 0;
}
-static void frr_confd_subscribe_state(const struct lys_node *snode, void *arg1,
- void *arg2)
+static int frr_confd_subscribe_state(const struct lys_node *snode, void *arg)
{
struct nb_node *nb_node = snode->priv;
- struct confd_data_cbs *data_cbs = arg1;
+ struct confd_data_cbs *data_cbs = arg;
- if (!(snode->flags & LYS_CONFIG_R))
- return;
+ if (!CHECK_FLAG(snode->flags, LYS_CONFIG_R))
+ return YANG_ITER_CONTINUE;
/* We only need to subscribe to the root of the state subtrees. */
- if (snode->parent && (snode->parent->flags & LYS_CONFIG_R))
- return;
+ if (snode->parent && CHECK_FLAG(snode->parent->flags, LYS_CONFIG_R))
+ return YANG_ITER_CONTINUE;
if (debug_northbound)
zlog_debug("%s: providing data to '%s' (callpoint %s)",
strlcpy(data_cbs->callpoint, snode->name, sizeof(data_cbs->callpoint));
if (confd_register_data_cb(dctx, data_cbs) != CONFD_OK)
flog_err_confd("confd_register_data_cb");
+
+ return YANG_ITER_CONTINUE;
}
static int frr_confd_init_dp(const char *program_name)
* Iterate over all loaded YANG modules and subscribe to the paths
* referent to state data.
*/
- yang_all_snodes_iterate(frr_confd_subscribe_state, 0, &data_cbs, NULL);
+ yang_snodes_iterate_all(frr_confd_subscribe_state, 0, &data_cbs);
/* Register notification stream. */
memset(&ncbs, 0, sizeof(ncbs));
/* ------------ Main ------------ */
-static void frr_confd_calculate_snode_hash(const struct lys_node *snode,
- void *arg1, void *arg2)
+static int frr_confd_calculate_snode_hash(const struct lys_node *snode,
+ void *arg)
{
struct nb_node *nb_node = snode->priv;
nb_node->confd_hash = confd_str2hash(snode->name);
+
+ return YANG_ITER_CONTINUE;
}
static int frr_confd_init(const char *program_name)
goto error;
}
- yang_all_snodes_iterate(frr_confd_calculate_snode_hash, 0, NULL, NULL);
+ yang_snodes_iterate_all(frr_confd_calculate_snode_hash, 0, NULL);
hook_register(nb_notification_send, frr_confd_notification_send);