|
Packit |
8fb591 |
/**
|
|
Packit |
8fb591 |
* @file yangdata.c
|
|
Packit |
8fb591 |
* @author Pavol Vican <vican.pavol@gmail.com>
|
|
Packit |
8fb591 |
* @brief libyang extension plugin - YANG DATA (RFC 8040)
|
|
Packit |
8fb591 |
*
|
|
Packit |
8fb591 |
* Copyright (c) 2018 CESNET, z.s.p.o.
|
|
Packit |
8fb591 |
*
|
|
Packit |
8fb591 |
* This source code is licensed under BSD 3-Clause License (the "License").
|
|
Packit |
8fb591 |
* You may not use this file except in compliance with the License.
|
|
Packit |
8fb591 |
* You may obtain a copy of the License at
|
|
Packit |
8fb591 |
*
|
|
Packit |
8fb591 |
* https://opensource.org/licenses/BSD-3-Clause
|
|
Packit |
8fb591 |
*/
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
#ifdef __GNUC__
|
|
Packit |
8fb591 |
# define UNUSED(x) UNUSED_ ## x __attribute__((__unused__))
|
|
Packit |
8fb591 |
#else
|
|
Packit |
8fb591 |
# define UNUSED(x) UNUSED_ ## x
|
|
Packit |
8fb591 |
#endif
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
#include <stdlib.h>
|
|
Packit |
8fb591 |
#include "../extensions.h"
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
int check_node(struct lys_node *node);
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
/**
|
|
Packit |
8fb591 |
* @brief Callback to check that the yang-data can be instantiated inside the provided node
|
|
Packit |
8fb591 |
*
|
|
Packit |
8fb591 |
* @param[in] parent The parent of the instantiated extension.
|
|
Packit |
8fb591 |
* @param[in] parent_type The type of the structure provided as \p parent.
|
|
Packit |
8fb591 |
* @param[in] substmt_type libyang does not store all the extension instances in the structures where they are
|
|
Packit |
8fb591 |
* instantiated in the module. In some cases (see #LYEXT_SUBSTMT) they are stored in parent
|
|
Packit |
8fb591 |
* structure and marked with flag to know in which substatement of the parent the extension
|
|
Packit |
8fb591 |
* was originally instantiated.
|
|
Packit |
8fb591 |
* @return 0 - ok
|
|
Packit |
8fb591 |
* 1 - error
|
|
Packit |
8fb591 |
*/
|
|
Packit |
8fb591 |
int yang_data_position(const void * UNUSED(parent), LYEXT_PAR parent_type, LYEXT_SUBSTMT UNUSED(substmt_type))
|
|
Packit |
8fb591 |
{
|
|
Packit |
8fb591 |
/* yang-data can appear only at the top level of a YANG module or submodule */
|
|
Packit |
8fb591 |
if (parent_type == LYEXT_PAR_MODULE) {
|
|
Packit |
8fb591 |
return 0;
|
|
Packit |
8fb591 |
} else {
|
|
Packit |
8fb591 |
return 1;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
/* return values - 0 - OK
|
|
Packit |
8fb591 |
* 1 - Something wrong
|
|
Packit |
8fb591 |
* -1 - Absolute wrong
|
|
Packit |
8fb591 |
*/
|
|
Packit |
8fb591 |
int check_choice(struct lys_node *root) {
|
|
Packit |
8fb591 |
struct lys_node *node, *next;
|
|
Packit |
8fb591 |
int result = 1, tmp_result;
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
LY_TREE_FOR_SAFE(root->child, next, node) {
|
|
Packit |
8fb591 |
tmp_result = (node->nodetype == LYS_CASE) ? check_node(node->child) : check_node(node);
|
|
Packit |
8fb591 |
if (tmp_result == -1) {
|
|
Packit |
8fb591 |
return -1;
|
|
Packit |
8fb591 |
} else if (tmp_result == 0) {
|
|
Packit |
8fb591 |
result = 0;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
return result;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
/* return values - 0 - OK
|
|
Packit |
8fb591 |
* 1 - Something wrong
|
|
Packit |
8fb591 |
* -1 - Absolute wrong
|
|
Packit |
8fb591 |
*/
|
|
Packit |
8fb591 |
int check_node(struct lys_node *node) {
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
int result = 0;
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
if (node == NULL) {
|
|
Packit |
8fb591 |
return 1;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
/* check nodes and find only one container */
|
|
Packit |
8fb591 |
if (node->nodetype == LYS_CHOICE) {
|
|
Packit |
8fb591 |
result = check_choice(node);
|
|
Packit |
8fb591 |
} else if (node->nodetype == LYS_USES) {
|
|
Packit |
8fb591 |
result = check_node(((struct lys_node_uses*)node)->grp->child);
|
|
Packit |
8fb591 |
} else if (node->nodetype != LYS_CONTAINER || (node->next != NULL || node->prev != node)) {
|
|
Packit |
8fb591 |
result = -1;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
return result;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
void remove_iffeature(struct lys_iffeature **iffeature, uint8_t *iffeature_size, struct ly_ctx *ctx) {
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
lys_iffeature_free(ctx, *iffeature, *iffeature_size, 0, NULL);
|
|
Packit |
8fb591 |
*iffeature_size = 0;
|
|
Packit |
8fb591 |
*iffeature = NULL;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
void remove_iffeature_type(struct lys_type *type, struct ly_ctx *ctx) {
|
|
Packit |
8fb591 |
unsigned int i;
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
if (type->base == LY_TYPE_ENUM) {
|
|
Packit |
8fb591 |
for (i = 0; i < type->info.enums.count; ++i) {
|
|
Packit |
8fb591 |
remove_iffeature(&type->info.enums.enm[i].iffeature, &type->info.enums.enm[i].iffeature_size, ctx);
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
} else if (type->base == LY_TYPE_BITS) {
|
|
Packit |
8fb591 |
for (i = 0; i < type->info.bits.count; ++i) {
|
|
Packit |
8fb591 |
remove_iffeature(&type->info.bits.bit[i].iffeature, &type->info.bits.bit[i].iffeature_size, ctx);
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
/* fix schema - ignore config flag, iffeature */
|
|
Packit |
8fb591 |
void fix_schema(struct lys_node *root, struct ly_ctx *ctx) {
|
|
Packit |
8fb591 |
struct lys_node *node, *next;
|
|
Packit |
8fb591 |
struct lys_node_container *cont;
|
|
Packit |
8fb591 |
struct lys_node_rpc_action *action;
|
|
Packit |
8fb591 |
struct lys_node_grp *grp;
|
|
Packit |
8fb591 |
struct lys_node_uses *uses;
|
|
Packit |
8fb591 |
int i;
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
LY_TREE_DFS_BEGIN(root, next, node) {
|
|
Packit |
8fb591 |
/* ignore config flag */
|
|
Packit |
8fb591 |
node->flags = node->flags & (~(LYS_CONFIG_MASK | LYS_CONFIG_SET));
|
|
Packit |
8fb591 |
remove_iffeature(&node->iffeature, &node->iffeature_size, ctx);
|
|
Packit |
8fb591 |
switch (node->nodetype) {
|
|
Packit |
8fb591 |
case LYS_CONTAINER:
|
|
Packit |
8fb591 |
cont = (struct lys_node_container *)node;
|
|
Packit |
8fb591 |
for (i = 0; i < cont->tpdf_size; ++i) {
|
|
Packit |
8fb591 |
remove_iffeature_type(&cont->tpdf[i].type, ctx);
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
break;
|
|
Packit |
8fb591 |
case LYS_LEAF:
|
|
Packit |
8fb591 |
remove_iffeature_type(&((struct lys_node_leaf *)node)->type, ctx);
|
|
Packit |
8fb591 |
break;
|
|
Packit |
8fb591 |
case LYS_LEAFLIST:
|
|
Packit |
8fb591 |
remove_iffeature_type(&((struct lys_node_leaflist *)node)->type, ctx);
|
|
Packit |
8fb591 |
break;
|
|
Packit |
8fb591 |
case LYS_ACTION:
|
|
Packit |
8fb591 |
case LYS_NOTIF:
|
|
Packit |
8fb591 |
action = (struct lys_node_rpc_action *)node;
|
|
Packit |
8fb591 |
for (i = 0; i < action->tpdf_size; ++i) {
|
|
Packit |
8fb591 |
remove_iffeature_type(&action->tpdf[i].type, ctx);
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
break;
|
|
Packit |
8fb591 |
case LYS_GROUPING:
|
|
Packit |
8fb591 |
grp = (struct lys_node_grp *)node;
|
|
Packit |
8fb591 |
for (i = 0; i < grp->tpdf_size; ++i) {
|
|
Packit |
8fb591 |
remove_iffeature_type(&grp->tpdf[i].type, ctx);
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
break;
|
|
Packit |
8fb591 |
case LYS_USES:
|
|
Packit |
8fb591 |
uses = (struct lys_node_uses *)node;
|
|
Packit |
8fb591 |
for (i = 0; i < uses->augment_size; ++i) {
|
|
Packit |
8fb591 |
remove_iffeature(&uses->augment[i].iffeature, &uses->augment[i].iffeature_size, ctx);
|
|
Packit |
8fb591 |
fix_schema(uses->augment[i].child, ctx);
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
for (i = 0; i < uses->refine_size; ++i) {
|
|
Packit |
8fb591 |
remove_iffeature(&uses->refine[i].iffeature, &uses->refine[i].iffeature_size, ctx);
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
break;
|
|
Packit |
8fb591 |
default:
|
|
Packit |
8fb591 |
break;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
LY_TREE_DFS_END(root, next, node)
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
int yang_data_result(struct lys_ext_instance *ext) {
|
|
Packit |
8fb591 |
struct lys_node **root;
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
root = lys_ext_complex_get_substmt(LY_STMT_CONTAINER, (struct lys_ext_instance_complex *)ext, NULL);
|
|
Packit |
8fb591 |
if (!root || !(*root) || (*root)->next != NULL || check_node(*root)) {
|
|
Packit |
8fb591 |
return 1;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
fix_schema(*root, ext->def->module->ctx);
|
|
Packit |
8fb591 |
return 0;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
struct lyext_substmt yang_data_substmt[] = {
|
|
Packit |
8fb591 |
{LY_STMT_USES, 0, LY_STMT_CARD_OPT},
|
|
Packit |
8fb591 |
{LY_STMT_CONTAINER, 0, LY_STMT_CARD_OPT},
|
|
Packit |
8fb591 |
{LY_STMT_CHOICE, 0, LY_STMT_CARD_OPT},
|
|
Packit |
8fb591 |
{0, 0, 0} /* terminating item */
|
|
Packit |
8fb591 |
};
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
/**
|
|
Packit |
8fb591 |
* @brief Plugin for the RFC 8040 restconf extension
|
|
Packit |
8fb591 |
*/
|
|
Packit |
8fb591 |
struct lyext_plugin_complex yang_data = {
|
|
Packit |
8fb591 |
.type = LYEXT_COMPLEX,
|
|
Packit |
8fb591 |
.flags = 0,
|
|
Packit |
8fb591 |
.check_position = &yang_data_position,
|
|
Packit |
8fb591 |
.check_result = &yang_data_result,
|
|
Packit |
8fb591 |
.check_inherit = NULL,
|
|
Packit |
8fb591 |
.valid_data = NULL,
|
|
Packit |
8fb591 |
/* specification of allowed substatements of the extension instance */
|
|
Packit |
8fb591 |
.substmt = yang_data_substmt,
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
/* final size of the extension instance structure with the space for storing the substatements */
|
|
Packit |
8fb591 |
.instance_size = (sizeof(struct lys_ext_instance_complex) - 1) + 2 * sizeof(void*)
|
|
Packit |
8fb591 |
};
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
/**
|
|
Packit |
8fb591 |
* @brief list of all extension plugins implemented here
|
|
Packit |
8fb591 |
*
|
|
Packit |
8fb591 |
* MANDATORY object for all libyang extension plugins, the name must match the <name>.so
|
|
Packit |
8fb591 |
*/
|
|
Packit |
8fb591 |
struct lyext_plugin_list yangdata[] = {
|
|
Packit |
8fb591 |
{"ietf-restconf", "2017-01-26", "yang-data", (struct lyext_plugin*)&yang_data},
|
|
Packit |
8fb591 |
{NULL, NULL, NULL, NULL} /* terminating item */
|
|
Packit |
8fb591 |
};
|