mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-15 01:37:53 +00:00
Merge pull request #6414 from opensourcerouting/nb-error-handling
NB context + enhanced error handling
This commit is contained in:
commit
57dd2f0097
@ -116,8 +116,8 @@ int isis_instance_area_address_create(struct nb_cb_create_args *args)
|
|||||||
addr.addr_len = dotformat2buff(buff, net_title);
|
addr.addr_len = dotformat2buff(buff, net_title);
|
||||||
memcpy(addr.area_addr, buff, addr.addr_len);
|
memcpy(addr.area_addr, buff, addr.addr_len);
|
||||||
if (addr.area_addr[addr.addr_len - 1] != 0) {
|
if (addr.area_addr[addr.addr_len - 1] != 0) {
|
||||||
flog_warn(
|
snprintf(
|
||||||
EC_LIB_NB_CB_CONFIG_VALIDATE,
|
args->errmsg, args->errmsg_len,
|
||||||
"nsel byte (last byte) in area address must be 0");
|
"nsel byte (last byte) in area address must be 0");
|
||||||
return NB_ERR_VALIDATION;
|
return NB_ERR_VALIDATION;
|
||||||
}
|
}
|
||||||
@ -125,8 +125,8 @@ int isis_instance_area_address_create(struct nb_cb_create_args *args)
|
|||||||
/* Check that the SystemID portions match */
|
/* Check that the SystemID portions match */
|
||||||
if (memcmp(isis->sysid, GETSYSID((&addr)),
|
if (memcmp(isis->sysid, GETSYSID((&addr)),
|
||||||
ISIS_SYS_ID_LEN)) {
|
ISIS_SYS_ID_LEN)) {
|
||||||
flog_warn(
|
snprintf(
|
||||||
EC_LIB_NB_CB_CONFIG_VALIDATE,
|
args->errmsg, args->errmsg_len,
|
||||||
"System ID must not change when defining additional area addresses");
|
"System ID must not change when defining additional area addresses");
|
||||||
return NB_ERR_VALIDATION;
|
return NB_ERR_VALIDATION;
|
||||||
}
|
}
|
||||||
@ -332,8 +332,8 @@ int isis_instance_lsp_mtu_modify(struct nb_cb_modify_args *args)
|
|||||||
&& circuit->state != C_STATE_UP)
|
&& circuit->state != C_STATE_UP)
|
||||||
continue;
|
continue;
|
||||||
if (lsp_mtu > isis_circuit_pdu_size(circuit)) {
|
if (lsp_mtu > isis_circuit_pdu_size(circuit)) {
|
||||||
flog_warn(
|
snprintf(
|
||||||
EC_LIB_NB_CB_CONFIG_VALIDATE,
|
args->errmsg, args->errmsg_len,
|
||||||
"ISIS area contains circuit %s, which has a maximum PDU size of %zu",
|
"ISIS area contains circuit %s, which has a maximum PDU size of %zu",
|
||||||
circuit->interface->name,
|
circuit->interface->name,
|
||||||
isis_circuit_pdu_size(circuit));
|
isis_circuit_pdu_size(circuit));
|
||||||
@ -1047,6 +1047,7 @@ int isis_instance_redistribute_ipv6_metric_modify(
|
|||||||
*/
|
*/
|
||||||
static int isis_multi_topology_common(enum nb_event event,
|
static int isis_multi_topology_common(enum nb_event event,
|
||||||
const struct lyd_node *dnode,
|
const struct lyd_node *dnode,
|
||||||
|
char *errmsg, size_t errmsg_len,
|
||||||
const char *topology, bool create)
|
const char *topology, bool create)
|
||||||
{
|
{
|
||||||
struct isis_area *area;
|
struct isis_area *area;
|
||||||
@ -1056,8 +1057,8 @@ static int isis_multi_topology_common(enum nb_event event,
|
|||||||
switch (event) {
|
switch (event) {
|
||||||
case NB_EV_VALIDATE:
|
case NB_EV_VALIDATE:
|
||||||
if (mtid == (uint16_t)-1) {
|
if (mtid == (uint16_t)-1) {
|
||||||
flog_warn(EC_LIB_NB_CB_CONFIG_VALIDATE,
|
snprintf(errmsg, errmsg_len, "Unknown topology %s",
|
||||||
"Unknown topology %s", topology);
|
topology);
|
||||||
return NB_ERR_VALIDATION;
|
return NB_ERR_VALIDATION;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -1100,6 +1101,7 @@ int isis_instance_multi_topology_ipv4_multicast_create(
|
|||||||
struct nb_cb_create_args *args)
|
struct nb_cb_create_args *args)
|
||||||
{
|
{
|
||||||
return isis_multi_topology_common(args->event, args->dnode,
|
return isis_multi_topology_common(args->event, args->dnode,
|
||||||
|
args->errmsg, args->errmsg_len,
|
||||||
"ipv4-multicast", true);
|
"ipv4-multicast", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1107,6 +1109,7 @@ int isis_instance_multi_topology_ipv4_multicast_destroy(
|
|||||||
struct nb_cb_destroy_args *args)
|
struct nb_cb_destroy_args *args)
|
||||||
{
|
{
|
||||||
return isis_multi_topology_common(args->event, args->dnode,
|
return isis_multi_topology_common(args->event, args->dnode,
|
||||||
|
args->errmsg, args->errmsg_len,
|
||||||
"ipv4-multicast", false);
|
"ipv4-multicast", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1126,15 +1129,17 @@ int isis_instance_multi_topology_ipv4_multicast_overload_modify(
|
|||||||
int isis_instance_multi_topology_ipv4_management_create(
|
int isis_instance_multi_topology_ipv4_management_create(
|
||||||
struct nb_cb_create_args *args)
|
struct nb_cb_create_args *args)
|
||||||
{
|
{
|
||||||
return isis_multi_topology_common(args->event, args->dnode, "ipv4-mgmt",
|
return isis_multi_topology_common(args->event, args->dnode,
|
||||||
true);
|
args->errmsg, args->errmsg_len,
|
||||||
|
"ipv4-mgmt", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
int isis_instance_multi_topology_ipv4_management_destroy(
|
int isis_instance_multi_topology_ipv4_management_destroy(
|
||||||
struct nb_cb_destroy_args *args)
|
struct nb_cb_destroy_args *args)
|
||||||
{
|
{
|
||||||
return isis_multi_topology_common(args->event, args->dnode, "ipv4-mgmt",
|
return isis_multi_topology_common(args->event, args->dnode,
|
||||||
false);
|
args->errmsg, args->errmsg_len,
|
||||||
|
"ipv4-mgmt", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1154,6 +1159,7 @@ int isis_instance_multi_topology_ipv6_unicast_create(
|
|||||||
struct nb_cb_create_args *args)
|
struct nb_cb_create_args *args)
|
||||||
{
|
{
|
||||||
return isis_multi_topology_common(args->event, args->dnode,
|
return isis_multi_topology_common(args->event, args->dnode,
|
||||||
|
args->errmsg, args->errmsg_len,
|
||||||
"ipv6-unicast", true);
|
"ipv6-unicast", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1161,6 +1167,7 @@ int isis_instance_multi_topology_ipv6_unicast_destroy(
|
|||||||
struct nb_cb_destroy_args *args)
|
struct nb_cb_destroy_args *args)
|
||||||
{
|
{
|
||||||
return isis_multi_topology_common(args->event, args->dnode,
|
return isis_multi_topology_common(args->event, args->dnode,
|
||||||
|
args->errmsg, args->errmsg_len,
|
||||||
"ipv6-unicast", false);
|
"ipv6-unicast", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1181,6 +1188,7 @@ int isis_instance_multi_topology_ipv6_multicast_create(
|
|||||||
struct nb_cb_create_args *args)
|
struct nb_cb_create_args *args)
|
||||||
{
|
{
|
||||||
return isis_multi_topology_common(args->event, args->dnode,
|
return isis_multi_topology_common(args->event, args->dnode,
|
||||||
|
args->errmsg, args->errmsg_len,
|
||||||
"ipv6-multicast", true);
|
"ipv6-multicast", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1188,6 +1196,7 @@ int isis_instance_multi_topology_ipv6_multicast_destroy(
|
|||||||
struct nb_cb_destroy_args *args)
|
struct nb_cb_destroy_args *args)
|
||||||
{
|
{
|
||||||
return isis_multi_topology_common(args->event, args->dnode,
|
return isis_multi_topology_common(args->event, args->dnode,
|
||||||
|
args->errmsg, args->errmsg_len,
|
||||||
"ipv6-multicast", false);
|
"ipv6-multicast", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1207,15 +1216,17 @@ int isis_instance_multi_topology_ipv6_multicast_overload_modify(
|
|||||||
int isis_instance_multi_topology_ipv6_management_create(
|
int isis_instance_multi_topology_ipv6_management_create(
|
||||||
struct nb_cb_create_args *args)
|
struct nb_cb_create_args *args)
|
||||||
{
|
{
|
||||||
return isis_multi_topology_common(args->event, args->dnode, "ipv6-mgmt",
|
return isis_multi_topology_common(args->event, args->dnode,
|
||||||
true);
|
args->errmsg, args->errmsg_len,
|
||||||
|
"ipv6-mgmt", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
int isis_instance_multi_topology_ipv6_management_destroy(
|
int isis_instance_multi_topology_ipv6_management_destroy(
|
||||||
struct nb_cb_destroy_args *args)
|
struct nb_cb_destroy_args *args)
|
||||||
{
|
{
|
||||||
return isis_multi_topology_common(args->event, args->dnode, "ipv6-mgmt",
|
return isis_multi_topology_common(args->event, args->dnode,
|
||||||
false);
|
args->errmsg, args->errmsg_len,
|
||||||
|
"ipv6-mgmt", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1235,6 +1246,7 @@ int isis_instance_multi_topology_ipv6_dstsrc_create(
|
|||||||
struct nb_cb_create_args *args)
|
struct nb_cb_create_args *args)
|
||||||
{
|
{
|
||||||
return isis_multi_topology_common(args->event, args->dnode,
|
return isis_multi_topology_common(args->event, args->dnode,
|
||||||
|
args->errmsg, args->errmsg_len,
|
||||||
"ipv6-dstsrc", true);
|
"ipv6-dstsrc", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1242,6 +1254,7 @@ int isis_instance_multi_topology_ipv6_dstsrc_destroy(
|
|||||||
struct nb_cb_destroy_args *args)
|
struct nb_cb_destroy_args *args)
|
||||||
{
|
{
|
||||||
return isis_multi_topology_common(args->event, args->dnode,
|
return isis_multi_topology_common(args->event, args->dnode,
|
||||||
|
args->errmsg, args->errmsg_len,
|
||||||
"ipv6-dstsrc", false);
|
"ipv6-dstsrc", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1721,7 +1734,7 @@ int lib_interface_isis_create(struct nb_cb_create_args *args)
|
|||||||
min_mtu = DEFAULT_LSP_MTU;
|
min_mtu = DEFAULT_LSP_MTU;
|
||||||
#endif /* ifndef FABRICD */
|
#endif /* ifndef FABRICD */
|
||||||
if (actual_mtu < min_mtu) {
|
if (actual_mtu < min_mtu) {
|
||||||
flog_warn(EC_LIB_NB_CB_CONFIG_VALIDATE,
|
snprintf(args->errmsg, args->errmsg_len,
|
||||||
"Interface %s has MTU %" PRIu32
|
"Interface %s has MTU %" PRIu32
|
||||||
", minimum MTU for the area is %" PRIu32 "",
|
", minimum MTU for the area is %" PRIu32 "",
|
||||||
ifp->name, actual_mtu, min_mtu);
|
ifp->name, actual_mtu, min_mtu);
|
||||||
@ -1801,7 +1814,7 @@ int lib_interface_isis_area_tag_modify(struct nb_cb_modify_args *args)
|
|||||||
area_tag = yang_dnode_get_string(args->dnode, NULL);
|
area_tag = yang_dnode_get_string(args->dnode, NULL);
|
||||||
if (circuit && circuit->area && circuit->area->area_tag
|
if (circuit && circuit->area && circuit->area->area_tag
|
||||||
&& strcmp(circuit->area->area_tag, area_tag)) {
|
&& strcmp(circuit->area->area_tag, area_tag)) {
|
||||||
flog_warn(EC_LIB_NB_CB_CONFIG_VALIDATE,
|
snprintf(args->errmsg, args->errmsg_len,
|
||||||
"ISIS circuit is already defined on %s",
|
"ISIS circuit is already defined on %s",
|
||||||
circuit->area->area_tag);
|
circuit->area->area_tag);
|
||||||
return NB_ERR_VALIDATION;
|
return NB_ERR_VALIDATION;
|
||||||
@ -1839,7 +1852,7 @@ int lib_interface_isis_circuit_type_modify(struct nb_cb_modify_args *args)
|
|||||||
if (circuit && circuit->state == C_STATE_UP
|
if (circuit && circuit->state == C_STATE_UP
|
||||||
&& circuit->area->is_type != IS_LEVEL_1_AND_2
|
&& circuit->area->is_type != IS_LEVEL_1_AND_2
|
||||||
&& circuit->area->is_type != circ_type) {
|
&& circuit->area->is_type != circ_type) {
|
||||||
flog_warn(EC_LIB_NB_CB_CONFIG_VALIDATE,
|
snprintf(args->errmsg, args->errmsg_len,
|
||||||
"Invalid circuit level for area %s",
|
"Invalid circuit level for area %s",
|
||||||
circuit->area->area_tag);
|
circuit->area->area_tag);
|
||||||
return NB_ERR_VALIDATION;
|
return NB_ERR_VALIDATION;
|
||||||
@ -2163,16 +2176,16 @@ int lib_interface_isis_network_type_modify(struct nb_cb_modify_args *args)
|
|||||||
if (!circuit)
|
if (!circuit)
|
||||||
break;
|
break;
|
||||||
if (circuit->circ_type == CIRCUIT_T_LOOPBACK) {
|
if (circuit->circ_type == CIRCUIT_T_LOOPBACK) {
|
||||||
flog_warn(
|
snprintf(
|
||||||
EC_LIB_NB_CB_CONFIG_VALIDATE,
|
args->errmsg, args->errmsg_len,
|
||||||
"Cannot change network type on loopback interface");
|
"Cannot change network type on loopback interface");
|
||||||
return NB_ERR_VALIDATION;
|
return NB_ERR_VALIDATION;
|
||||||
}
|
}
|
||||||
if (net_type == CIRCUIT_T_BROADCAST
|
if (net_type == CIRCUIT_T_BROADCAST
|
||||||
&& circuit->state == C_STATE_UP
|
&& circuit->state == C_STATE_UP
|
||||||
&& !if_is_broadcast(circuit->interface)) {
|
&& !if_is_broadcast(circuit->interface)) {
|
||||||
flog_warn(
|
snprintf(
|
||||||
EC_LIB_NB_CB_CONFIG_VALIDATE,
|
args->errmsg, args->errmsg_len,
|
||||||
"Cannot configure non-broadcast interface for broadcast operation");
|
"Cannot configure non-broadcast interface for broadcast operation");
|
||||||
return NB_ERR_VALIDATION;
|
return NB_ERR_VALIDATION;
|
||||||
}
|
}
|
||||||
@ -2208,7 +2221,7 @@ int lib_interface_isis_passive_modify(struct nb_cb_modify_args *args)
|
|||||||
if (!ifp)
|
if (!ifp)
|
||||||
return NB_OK;
|
return NB_OK;
|
||||||
if (if_is_loopback(ifp)) {
|
if (if_is_loopback(ifp)) {
|
||||||
flog_warn(EC_LIB_NB_CB_CONFIG_VALIDATE,
|
snprintf(args->errmsg, args->errmsg_len,
|
||||||
"Loopback is always passive");
|
"Loopback is always passive");
|
||||||
return NB_ERR_VALIDATION;
|
return NB_ERR_VALIDATION;
|
||||||
}
|
}
|
||||||
@ -2312,7 +2325,8 @@ int lib_interface_isis_disable_three_way_handshake_modify(
|
|||||||
* /frr-interface:lib/interface/frr-isisd:isis/multi-topology/ipv4-unicast
|
* /frr-interface:lib/interface/frr-isisd:isis/multi-topology/ipv4-unicast
|
||||||
*/
|
*/
|
||||||
static int lib_interface_isis_multi_topology_common(
|
static int lib_interface_isis_multi_topology_common(
|
||||||
enum nb_event event, const struct lyd_node *dnode, uint16_t mtid)
|
enum nb_event event, const struct lyd_node *dnode, char *errmsg,
|
||||||
|
size_t errmsg_len, uint16_t mtid)
|
||||||
{
|
{
|
||||||
struct isis_circuit *circuit;
|
struct isis_circuit *circuit;
|
||||||
bool value;
|
bool value;
|
||||||
@ -2321,8 +2335,8 @@ static int lib_interface_isis_multi_topology_common(
|
|||||||
case NB_EV_VALIDATE:
|
case NB_EV_VALIDATE:
|
||||||
circuit = nb_running_get_entry(dnode, NULL, false);
|
circuit = nb_running_get_entry(dnode, NULL, false);
|
||||||
if (circuit && circuit->area && circuit->area->oldmetric) {
|
if (circuit && circuit->area && circuit->area->oldmetric) {
|
||||||
flog_warn(
|
snprintf(
|
||||||
EC_LIB_NB_CB_CONFIG_VALIDATE,
|
errmsg, errmsg_len,
|
||||||
"Multi topology IS-IS can only be used with wide metrics");
|
"Multi topology IS-IS can only be used with wide metrics");
|
||||||
return NB_ERR_VALIDATION;
|
return NB_ERR_VALIDATION;
|
||||||
}
|
}
|
||||||
@ -2344,7 +2358,8 @@ int lib_interface_isis_multi_topology_ipv4_unicast_modify(
|
|||||||
struct nb_cb_modify_args *args)
|
struct nb_cb_modify_args *args)
|
||||||
{
|
{
|
||||||
return lib_interface_isis_multi_topology_common(
|
return lib_interface_isis_multi_topology_common(
|
||||||
args->event, args->dnode, ISIS_MT_IPV4_UNICAST);
|
args->event, args->dnode, args->errmsg, args->errmsg_len,
|
||||||
|
ISIS_MT_IPV4_UNICAST);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -2355,7 +2370,8 @@ int lib_interface_isis_multi_topology_ipv4_multicast_modify(
|
|||||||
struct nb_cb_modify_args *args)
|
struct nb_cb_modify_args *args)
|
||||||
{
|
{
|
||||||
return lib_interface_isis_multi_topology_common(
|
return lib_interface_isis_multi_topology_common(
|
||||||
args->event, args->dnode, ISIS_MT_IPV4_MULTICAST);
|
args->event, args->dnode, args->errmsg, args->errmsg_len,
|
||||||
|
ISIS_MT_IPV4_MULTICAST);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -2366,7 +2382,8 @@ int lib_interface_isis_multi_topology_ipv4_management_modify(
|
|||||||
struct nb_cb_modify_args *args)
|
struct nb_cb_modify_args *args)
|
||||||
{
|
{
|
||||||
return lib_interface_isis_multi_topology_common(
|
return lib_interface_isis_multi_topology_common(
|
||||||
args->event, args->dnode, ISIS_MT_IPV4_MGMT);
|
args->event, args->dnode, args->errmsg, args->errmsg_len,
|
||||||
|
ISIS_MT_IPV4_MGMT);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -2377,7 +2394,8 @@ int lib_interface_isis_multi_topology_ipv6_unicast_modify(
|
|||||||
struct nb_cb_modify_args *args)
|
struct nb_cb_modify_args *args)
|
||||||
{
|
{
|
||||||
return lib_interface_isis_multi_topology_common(
|
return lib_interface_isis_multi_topology_common(
|
||||||
args->event, args->dnode, ISIS_MT_IPV6_UNICAST);
|
args->event, args->dnode, args->errmsg, args->errmsg_len,
|
||||||
|
ISIS_MT_IPV6_UNICAST);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -2388,7 +2406,8 @@ int lib_interface_isis_multi_topology_ipv6_multicast_modify(
|
|||||||
struct nb_cb_modify_args *args)
|
struct nb_cb_modify_args *args)
|
||||||
{
|
{
|
||||||
return lib_interface_isis_multi_topology_common(
|
return lib_interface_isis_multi_topology_common(
|
||||||
args->event, args->dnode, ISIS_MT_IPV6_MULTICAST);
|
args->event, args->dnode, args->errmsg, args->errmsg_len,
|
||||||
|
ISIS_MT_IPV6_MULTICAST);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -2399,7 +2418,8 @@ int lib_interface_isis_multi_topology_ipv6_management_modify(
|
|||||||
struct nb_cb_modify_args *args)
|
struct nb_cb_modify_args *args)
|
||||||
{
|
{
|
||||||
return lib_interface_isis_multi_topology_common(
|
return lib_interface_isis_multi_topology_common(
|
||||||
args->event, args->dnode, ISIS_MT_IPV6_MGMT);
|
args->event, args->dnode, args->errmsg, args->errmsg_len,
|
||||||
|
ISIS_MT_IPV6_MGMT);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -2409,5 +2429,6 @@ int lib_interface_isis_multi_topology_ipv6_dstsrc_modify(
|
|||||||
struct nb_cb_modify_args *args)
|
struct nb_cb_modify_args *args)
|
||||||
{
|
{
|
||||||
return lib_interface_isis_multi_topology_common(
|
return lib_interface_isis_multi_topology_common(
|
||||||
args->event, args->dnode, ISIS_MT_IPV6_DSTSRC);
|
args->event, args->dnode, args->errmsg, args->errmsg_len,
|
||||||
|
ISIS_MT_IPV6_DSTSRC);
|
||||||
}
|
}
|
||||||
|
4
lib/if.c
4
lib/if.c
@ -1567,8 +1567,8 @@ static int lib_interface_destroy(struct nb_cb_destroy_args *args)
|
|||||||
case NB_EV_VALIDATE:
|
case NB_EV_VALIDATE:
|
||||||
ifp = nb_running_get_entry(args->dnode, NULL, true);
|
ifp = nb_running_get_entry(args->dnode, NULL, true);
|
||||||
if (CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE)) {
|
if (CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE)) {
|
||||||
zlog_warn("%s: only inactive interfaces can be deleted",
|
snprintf(args->errmsg, args->errmsg_len,
|
||||||
__func__);
|
"only inactive interfaces can be deleted");
|
||||||
return NB_ERR_VALIDATION;
|
return NB_ERR_VALIDATION;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
14
lib/libfrr.c
14
lib/libfrr.c
@ -902,14 +902,18 @@ static int frr_config_read_in(struct thread *t)
|
|||||||
* reading the configuration file.
|
* reading the configuration file.
|
||||||
*/
|
*/
|
||||||
if (frr_get_cli_mode() == FRR_CLI_TRANSACTIONAL) {
|
if (frr_get_cli_mode() == FRR_CLI_TRANSACTIONAL) {
|
||||||
|
struct nb_context context = {};
|
||||||
|
char errmsg[BUFSIZ] = {0};
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = nb_candidate_commit(vty_shared_candidate_config,
|
context.client = NB_CLIENT_CLI;
|
||||||
NB_CLIENT_CLI, NULL, true,
|
ret = nb_candidate_commit(&context, vty_shared_candidate_config,
|
||||||
"Read configuration file", NULL);
|
true, "Read configuration file", NULL,
|
||||||
|
errmsg, sizeof(errmsg));
|
||||||
if (ret != NB_OK && ret != NB_ERR_NO_CHANGES)
|
if (ret != NB_OK && ret != NB_ERR_NO_CHANGES)
|
||||||
zlog_err("%s: failed to read configuration file.",
|
zlog_err(
|
||||||
__func__);
|
"%s: failed to read configuration file: %s (%s)",
|
||||||
|
__func__, nb_err_name(ret), errmsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
364
lib/northbound.c
364
lib/northbound.c
@ -63,19 +63,24 @@ static struct {
|
|||||||
*/
|
*/
|
||||||
static bool transaction_in_progress;
|
static bool transaction_in_progress;
|
||||||
|
|
||||||
static int nb_callback_pre_validate(const struct nb_node *nb_node,
|
static int nb_callback_pre_validate(struct nb_context *context,
|
||||||
const struct lyd_node *dnode);
|
const struct nb_node *nb_node,
|
||||||
static int nb_callback_configuration(const enum nb_event event,
|
const struct lyd_node *dnode, char *errmsg,
|
||||||
struct nb_config_change *change);
|
size_t errmsg_len);
|
||||||
static struct nb_transaction *nb_transaction_new(struct nb_config *config,
|
static int nb_callback_configuration(struct nb_context *context,
|
||||||
struct nb_config_cbs *changes,
|
const enum nb_event event,
|
||||||
enum nb_client client,
|
struct nb_config_change *change,
|
||||||
const void *user,
|
char *errmsg, size_t errmsg_len);
|
||||||
const char *comment);
|
static struct nb_transaction *
|
||||||
|
nb_transaction_new(struct nb_context *context, struct nb_config *config,
|
||||||
|
struct nb_config_cbs *changes, const char *comment,
|
||||||
|
char *errmsg, size_t errmsg_len);
|
||||||
static void nb_transaction_free(struct nb_transaction *transaction);
|
static void nb_transaction_free(struct nb_transaction *transaction);
|
||||||
static int nb_transaction_process(enum nb_event event,
|
static int nb_transaction_process(enum nb_event event,
|
||||||
struct nb_transaction *transaction);
|
struct nb_transaction *transaction,
|
||||||
static void nb_transaction_apply_finish(struct nb_transaction *transaction);
|
char *errmsg, size_t errmsg_len);
|
||||||
|
static void nb_transaction_apply_finish(struct nb_transaction *transaction,
|
||||||
|
char *errmsg, size_t errmsg_len);
|
||||||
static int nb_oper_data_iter_node(const struct lys_node *snode,
|
static int nb_oper_data_iter_node(const struct lys_node *snode,
|
||||||
const char *xpath, const void *list_entry,
|
const char *xpath, const void *list_entry,
|
||||||
const struct yang_list_keys *list_keys,
|
const struct yang_list_keys *list_keys,
|
||||||
@ -581,20 +586,25 @@ int nb_candidate_update(struct nb_config *candidate)
|
|||||||
* WARNING: lyd_validate() can change the configuration as part of the
|
* WARNING: lyd_validate() can change the configuration as part of the
|
||||||
* validation process.
|
* validation process.
|
||||||
*/
|
*/
|
||||||
static int nb_candidate_validate_yang(struct nb_config *candidate)
|
static int nb_candidate_validate_yang(struct nb_config *candidate, char *errmsg,
|
||||||
|
size_t errmsg_len)
|
||||||
{
|
{
|
||||||
if (lyd_validate(&candidate->dnode,
|
if (lyd_validate(&candidate->dnode,
|
||||||
LYD_OPT_STRICT | LYD_OPT_CONFIG | LYD_OPT_WHENAUTODEL,
|
LYD_OPT_STRICT | LYD_OPT_CONFIG | LYD_OPT_WHENAUTODEL,
|
||||||
ly_native_ctx)
|
ly_native_ctx)
|
||||||
!= 0)
|
!= 0) {
|
||||||
|
yang_print_errors(ly_native_ctx, errmsg, errmsg_len);
|
||||||
return NB_ERR_VALIDATION;
|
return NB_ERR_VALIDATION;
|
||||||
|
}
|
||||||
|
|
||||||
return NB_OK;
|
return NB_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Perform code-level validation using the northbound callbacks. */
|
/* Perform code-level validation using the northbound callbacks. */
|
||||||
static int nb_candidate_validate_code(struct nb_config *candidate,
|
static int nb_candidate_validate_code(struct nb_context *context,
|
||||||
struct nb_config_cbs *changes)
|
struct nb_config *candidate,
|
||||||
|
struct nb_config_cbs *changes,
|
||||||
|
char *errmsg, size_t errmsg_len)
|
||||||
{
|
{
|
||||||
struct nb_config_cb *cb;
|
struct nb_config_cb *cb;
|
||||||
struct lyd_node *root, *next, *child;
|
struct lyd_node *root, *next, *child;
|
||||||
@ -609,7 +619,8 @@ static int nb_candidate_validate_code(struct nb_config *candidate,
|
|||||||
if (!nb_node->cbs.pre_validate)
|
if (!nb_node->cbs.pre_validate)
|
||||||
goto next;
|
goto next;
|
||||||
|
|
||||||
ret = nb_callback_pre_validate(nb_node, child);
|
ret = nb_callback_pre_validate(context, nb_node, child,
|
||||||
|
errmsg, errmsg_len);
|
||||||
if (ret != NB_OK)
|
if (ret != NB_OK)
|
||||||
return NB_ERR_VALIDATION;
|
return NB_ERR_VALIDATION;
|
||||||
|
|
||||||
@ -622,7 +633,8 @@ static int nb_candidate_validate_code(struct nb_config *candidate,
|
|||||||
RB_FOREACH (cb, nb_config_cbs, changes) {
|
RB_FOREACH (cb, nb_config_cbs, changes) {
|
||||||
struct nb_config_change *change = (struct nb_config_change *)cb;
|
struct nb_config_change *change = (struct nb_config_change *)cb;
|
||||||
|
|
||||||
ret = nb_callback_configuration(NB_EV_VALIDATE, change);
|
ret = nb_callback_configuration(context, NB_EV_VALIDATE, change,
|
||||||
|
errmsg, errmsg_len);
|
||||||
if (ret != NB_OK)
|
if (ret != NB_OK)
|
||||||
return NB_ERR_VALIDATION;
|
return NB_ERR_VALIDATION;
|
||||||
}
|
}
|
||||||
@ -630,30 +642,36 @@ static int nb_candidate_validate_code(struct nb_config *candidate,
|
|||||||
return NB_OK;
|
return NB_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int nb_candidate_validate(struct nb_config *candidate)
|
int nb_candidate_validate(struct nb_context *context,
|
||||||
|
struct nb_config *candidate, char *errmsg,
|
||||||
|
size_t errmsg_len)
|
||||||
{
|
{
|
||||||
struct nb_config_cbs changes;
|
struct nb_config_cbs changes;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (nb_candidate_validate_yang(candidate) != NB_OK)
|
if (nb_candidate_validate_yang(candidate, errmsg, sizeof(errmsg_len))
|
||||||
|
!= NB_OK)
|
||||||
return NB_ERR_VALIDATION;
|
return NB_ERR_VALIDATION;
|
||||||
|
|
||||||
RB_INIT(nb_config_cbs, &changes);
|
RB_INIT(nb_config_cbs, &changes);
|
||||||
nb_config_diff(running_config, candidate, &changes);
|
nb_config_diff(running_config, candidate, &changes);
|
||||||
ret = nb_candidate_validate_code(candidate, &changes);
|
ret = nb_candidate_validate_code(context, candidate, &changes, errmsg,
|
||||||
|
errmsg_len);
|
||||||
nb_config_diff_del_changes(&changes);
|
nb_config_diff_del_changes(&changes);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int nb_candidate_commit_prepare(struct nb_config *candidate,
|
int nb_candidate_commit_prepare(struct nb_context *context,
|
||||||
enum nb_client client, const void *user,
|
struct nb_config *candidate,
|
||||||
const char *comment,
|
const char *comment,
|
||||||
struct nb_transaction **transaction)
|
struct nb_transaction **transaction,
|
||||||
|
char *errmsg, size_t errmsg_len)
|
||||||
{
|
{
|
||||||
struct nb_config_cbs changes;
|
struct nb_config_cbs changes;
|
||||||
|
|
||||||
if (nb_candidate_validate_yang(candidate) != NB_OK) {
|
if (nb_candidate_validate_yang(candidate, errmsg, errmsg_len)
|
||||||
|
!= NB_OK) {
|
||||||
flog_warn(EC_LIB_NB_CANDIDATE_INVALID,
|
flog_warn(EC_LIB_NB_CANDIDATE_INVALID,
|
||||||
"%s: failed to validate candidate configuration",
|
"%s: failed to validate candidate configuration",
|
||||||
__func__);
|
__func__);
|
||||||
@ -665,7 +683,9 @@ int nb_candidate_commit_prepare(struct nb_config *candidate,
|
|||||||
if (RB_EMPTY(nb_config_cbs, &changes))
|
if (RB_EMPTY(nb_config_cbs, &changes))
|
||||||
return NB_ERR_NO_CHANGES;
|
return NB_ERR_NO_CHANGES;
|
||||||
|
|
||||||
if (nb_candidate_validate_code(candidate, &changes) != NB_OK) {
|
if (nb_candidate_validate_code(context, candidate, &changes, errmsg,
|
||||||
|
errmsg_len)
|
||||||
|
!= NB_OK) {
|
||||||
flog_warn(EC_LIB_NB_CANDIDATE_INVALID,
|
flog_warn(EC_LIB_NB_CANDIDATE_INVALID,
|
||||||
"%s: failed to validate candidate configuration",
|
"%s: failed to validate candidate configuration",
|
||||||
__func__);
|
__func__);
|
||||||
@ -673,29 +693,37 @@ int nb_candidate_commit_prepare(struct nb_config *candidate,
|
|||||||
return NB_ERR_VALIDATION;
|
return NB_ERR_VALIDATION;
|
||||||
}
|
}
|
||||||
|
|
||||||
*transaction =
|
*transaction = nb_transaction_new(context, candidate, &changes, comment,
|
||||||
nb_transaction_new(candidate, &changes, client, user, comment);
|
errmsg, errmsg_len);
|
||||||
if (*transaction == NULL) {
|
if (*transaction == NULL) {
|
||||||
flog_warn(EC_LIB_NB_TRANSACTION_CREATION_FAILED,
|
flog_warn(EC_LIB_NB_TRANSACTION_CREATION_FAILED,
|
||||||
"%s: failed to create transaction", __func__);
|
"%s: failed to create transaction: %s", __func__,
|
||||||
|
errmsg);
|
||||||
nb_config_diff_del_changes(&changes);
|
nb_config_diff_del_changes(&changes);
|
||||||
return NB_ERR_LOCKED;
|
return NB_ERR_LOCKED;
|
||||||
}
|
}
|
||||||
|
|
||||||
return nb_transaction_process(NB_EV_PREPARE, *transaction);
|
return nb_transaction_process(NB_EV_PREPARE, *transaction, errmsg,
|
||||||
|
errmsg_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
void nb_candidate_commit_abort(struct nb_transaction *transaction)
|
void nb_candidate_commit_abort(struct nb_transaction *transaction)
|
||||||
{
|
{
|
||||||
(void)nb_transaction_process(NB_EV_ABORT, transaction);
|
char errmsg[BUFSIZ] = {0};
|
||||||
|
|
||||||
|
(void)nb_transaction_process(NB_EV_ABORT, transaction, errmsg,
|
||||||
|
sizeof(errmsg));
|
||||||
nb_transaction_free(transaction);
|
nb_transaction_free(transaction);
|
||||||
}
|
}
|
||||||
|
|
||||||
void nb_candidate_commit_apply(struct nb_transaction *transaction,
|
void nb_candidate_commit_apply(struct nb_transaction *transaction,
|
||||||
bool save_transaction, uint32_t *transaction_id)
|
bool save_transaction, uint32_t *transaction_id)
|
||||||
{
|
{
|
||||||
(void)nb_transaction_process(NB_EV_APPLY, transaction);
|
char errmsg[BUFSIZ] = {0};
|
||||||
nb_transaction_apply_finish(transaction);
|
|
||||||
|
(void)nb_transaction_process(NB_EV_APPLY, transaction, errmsg,
|
||||||
|
sizeof(errmsg));
|
||||||
|
nb_transaction_apply_finish(transaction, errmsg, sizeof(errmsg));
|
||||||
|
|
||||||
/* Replace running by candidate. */
|
/* Replace running by candidate. */
|
||||||
transaction->config->version++;
|
transaction->config->version++;
|
||||||
@ -710,15 +738,16 @@ void nb_candidate_commit_apply(struct nb_transaction *transaction,
|
|||||||
nb_transaction_free(transaction);
|
nb_transaction_free(transaction);
|
||||||
}
|
}
|
||||||
|
|
||||||
int nb_candidate_commit(struct nb_config *candidate, enum nb_client client,
|
int nb_candidate_commit(struct nb_context *context, struct nb_config *candidate,
|
||||||
const void *user, bool save_transaction,
|
bool save_transaction, const char *comment,
|
||||||
const char *comment, uint32_t *transaction_id)
|
uint32_t *transaction_id, char *errmsg,
|
||||||
|
size_t errmsg_len)
|
||||||
{
|
{
|
||||||
struct nb_transaction *transaction = NULL;
|
struct nb_transaction *transaction = NULL;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = nb_candidate_commit_prepare(candidate, client, user, comment,
|
ret = nb_candidate_commit_prepare(context, candidate, comment,
|
||||||
&transaction);
|
&transaction, errmsg, errmsg_len);
|
||||||
/*
|
/*
|
||||||
* Apply the changes if the preparation phase succeeded. Otherwise abort
|
* Apply the changes if the preparation phase succeeded. Otherwise abort
|
||||||
* the transaction.
|
* the transaction.
|
||||||
@ -802,78 +831,237 @@ static void nb_log_config_callback(const enum nb_event event,
|
|||||||
value);
|
value);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nb_callback_create(const struct nb_node *nb_node,
|
static int nb_callback_create(struct nb_context *context,
|
||||||
|
const struct nb_node *nb_node,
|
||||||
enum nb_event event, const struct lyd_node *dnode,
|
enum nb_event event, const struct lyd_node *dnode,
|
||||||
union nb_resource *resource)
|
union nb_resource *resource, char *errmsg,
|
||||||
|
size_t errmsg_len)
|
||||||
{
|
{
|
||||||
struct nb_cb_create_args args = {};
|
struct nb_cb_create_args args = {};
|
||||||
|
bool unexpected_error = false;
|
||||||
|
int ret;
|
||||||
|
|
||||||
nb_log_config_callback(event, NB_OP_CREATE, dnode);
|
nb_log_config_callback(event, NB_OP_CREATE, dnode);
|
||||||
|
|
||||||
|
args.context = context;
|
||||||
args.event = event;
|
args.event = event;
|
||||||
args.dnode = dnode;
|
args.dnode = dnode;
|
||||||
args.resource = resource;
|
args.resource = resource;
|
||||||
return nb_node->cbs.create(&args);
|
args.errmsg = errmsg;
|
||||||
|
args.errmsg_len = errmsg_len;
|
||||||
|
ret = nb_node->cbs.create(&args);
|
||||||
|
|
||||||
|
/* Detect and log unexpected errors. */
|
||||||
|
switch (ret) {
|
||||||
|
case NB_OK:
|
||||||
|
case NB_ERR:
|
||||||
|
break;
|
||||||
|
case NB_ERR_VALIDATION:
|
||||||
|
if (event != NB_EV_VALIDATE)
|
||||||
|
unexpected_error = true;
|
||||||
|
break;
|
||||||
|
case NB_ERR_RESOURCE:
|
||||||
|
if (event != NB_EV_PREPARE)
|
||||||
|
unexpected_error = true;
|
||||||
|
break;
|
||||||
|
case NB_ERR_INCONSISTENCY:
|
||||||
|
if (event == NB_EV_VALIDATE)
|
||||||
|
unexpected_error = true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
unexpected_error = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (unexpected_error)
|
||||||
|
DEBUGD(&nb_dbg_cbs_config,
|
||||||
|
"northbound callback: unexpected return value: %s",
|
||||||
|
nb_err_name(ret));
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nb_callback_modify(const struct nb_node *nb_node,
|
static int nb_callback_modify(struct nb_context *context,
|
||||||
|
const struct nb_node *nb_node,
|
||||||
enum nb_event event, const struct lyd_node *dnode,
|
enum nb_event event, const struct lyd_node *dnode,
|
||||||
union nb_resource *resource)
|
union nb_resource *resource, char *errmsg,
|
||||||
|
size_t errmsg_len)
|
||||||
{
|
{
|
||||||
struct nb_cb_modify_args args = {};
|
struct nb_cb_modify_args args = {};
|
||||||
|
bool unexpected_error = false;
|
||||||
|
int ret;
|
||||||
|
|
||||||
nb_log_config_callback(event, NB_OP_MODIFY, dnode);
|
nb_log_config_callback(event, NB_OP_MODIFY, dnode);
|
||||||
|
|
||||||
|
args.context = context;
|
||||||
args.event = event;
|
args.event = event;
|
||||||
args.dnode = dnode;
|
args.dnode = dnode;
|
||||||
args.resource = resource;
|
args.resource = resource;
|
||||||
return nb_node->cbs.modify(&args);
|
args.errmsg = errmsg;
|
||||||
|
args.errmsg_len = errmsg_len;
|
||||||
|
ret = nb_node->cbs.modify(&args);
|
||||||
|
|
||||||
|
/* Detect and log unexpected errors. */
|
||||||
|
switch (ret) {
|
||||||
|
case NB_OK:
|
||||||
|
case NB_ERR:
|
||||||
|
break;
|
||||||
|
case NB_ERR_VALIDATION:
|
||||||
|
if (event != NB_EV_VALIDATE)
|
||||||
|
unexpected_error = true;
|
||||||
|
break;
|
||||||
|
case NB_ERR_RESOURCE:
|
||||||
|
if (event != NB_EV_PREPARE)
|
||||||
|
unexpected_error = true;
|
||||||
|
break;
|
||||||
|
case NB_ERR_INCONSISTENCY:
|
||||||
|
if (event == NB_EV_VALIDATE)
|
||||||
|
unexpected_error = true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
unexpected_error = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (unexpected_error)
|
||||||
|
DEBUGD(&nb_dbg_cbs_config,
|
||||||
|
"northbound callback: unexpected return value: %s",
|
||||||
|
nb_err_name(ret));
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nb_callback_destroy(const struct nb_node *nb_node,
|
static int nb_callback_destroy(struct nb_context *context,
|
||||||
|
const struct nb_node *nb_node,
|
||||||
enum nb_event event,
|
enum nb_event event,
|
||||||
const struct lyd_node *dnode)
|
const struct lyd_node *dnode, char *errmsg,
|
||||||
|
size_t errmsg_len)
|
||||||
{
|
{
|
||||||
struct nb_cb_destroy_args args = {};
|
struct nb_cb_destroy_args args = {};
|
||||||
|
bool unexpected_error = false;
|
||||||
|
int ret;
|
||||||
|
|
||||||
nb_log_config_callback(event, NB_OP_DESTROY, dnode);
|
nb_log_config_callback(event, NB_OP_DESTROY, dnode);
|
||||||
|
|
||||||
|
args.context = context;
|
||||||
args.event = event;
|
args.event = event;
|
||||||
args.dnode = dnode;
|
args.dnode = dnode;
|
||||||
return nb_node->cbs.destroy(&args);
|
args.errmsg = errmsg;
|
||||||
|
args.errmsg_len = errmsg_len;
|
||||||
|
ret = nb_node->cbs.destroy(&args);
|
||||||
|
|
||||||
|
/* Detect and log unexpected errors. */
|
||||||
|
switch (ret) {
|
||||||
|
case NB_OK:
|
||||||
|
case NB_ERR:
|
||||||
|
break;
|
||||||
|
case NB_ERR_VALIDATION:
|
||||||
|
if (event != NB_EV_VALIDATE)
|
||||||
|
unexpected_error = true;
|
||||||
|
break;
|
||||||
|
case NB_ERR_INCONSISTENCY:
|
||||||
|
if (event == NB_EV_VALIDATE)
|
||||||
|
unexpected_error = true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
unexpected_error = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (unexpected_error)
|
||||||
|
DEBUGD(&nb_dbg_cbs_config,
|
||||||
|
"northbound callback: unexpected return value: %s",
|
||||||
|
nb_err_name(ret));
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nb_callback_move(const struct nb_node *nb_node, enum nb_event event,
|
static int nb_callback_move(struct nb_context *context,
|
||||||
const struct lyd_node *dnode)
|
const struct nb_node *nb_node, enum nb_event event,
|
||||||
|
const struct lyd_node *dnode, char *errmsg,
|
||||||
|
size_t errmsg_len)
|
||||||
{
|
{
|
||||||
struct nb_cb_move_args args = {};
|
struct nb_cb_move_args args = {};
|
||||||
|
bool unexpected_error = false;
|
||||||
|
int ret;
|
||||||
|
|
||||||
nb_log_config_callback(event, NB_OP_MOVE, dnode);
|
nb_log_config_callback(event, NB_OP_MOVE, dnode);
|
||||||
|
|
||||||
|
args.context = context;
|
||||||
args.event = event;
|
args.event = event;
|
||||||
args.dnode = dnode;
|
args.dnode = dnode;
|
||||||
return nb_node->cbs.move(&args);
|
args.errmsg = errmsg;
|
||||||
|
args.errmsg_len = errmsg_len;
|
||||||
|
ret = nb_node->cbs.move(&args);
|
||||||
|
|
||||||
|
/* Detect and log unexpected errors. */
|
||||||
|
switch (ret) {
|
||||||
|
case NB_OK:
|
||||||
|
case NB_ERR:
|
||||||
|
break;
|
||||||
|
case NB_ERR_VALIDATION:
|
||||||
|
if (event != NB_EV_VALIDATE)
|
||||||
|
unexpected_error = true;
|
||||||
|
break;
|
||||||
|
case NB_ERR_INCONSISTENCY:
|
||||||
|
if (event == NB_EV_VALIDATE)
|
||||||
|
unexpected_error = true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
unexpected_error = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (unexpected_error)
|
||||||
|
DEBUGD(&nb_dbg_cbs_config,
|
||||||
|
"northbound callback: unexpected return value: %s",
|
||||||
|
nb_err_name(ret));
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nb_callback_pre_validate(const struct nb_node *nb_node,
|
static int nb_callback_pre_validate(struct nb_context *context,
|
||||||
const struct lyd_node *dnode)
|
const struct nb_node *nb_node,
|
||||||
|
const struct lyd_node *dnode, char *errmsg,
|
||||||
|
size_t errmsg_len)
|
||||||
{
|
{
|
||||||
struct nb_cb_pre_validate_args args = {};
|
struct nb_cb_pre_validate_args args = {};
|
||||||
|
bool unexpected_error = false;
|
||||||
|
int ret;
|
||||||
|
|
||||||
nb_log_config_callback(NB_EV_VALIDATE, NB_OP_PRE_VALIDATE, dnode);
|
nb_log_config_callback(NB_EV_VALIDATE, NB_OP_PRE_VALIDATE, dnode);
|
||||||
|
|
||||||
args.dnode = dnode;
|
args.dnode = dnode;
|
||||||
return nb_node->cbs.pre_validate(&args);
|
args.errmsg = errmsg;
|
||||||
|
args.errmsg_len = errmsg_len;
|
||||||
|
ret = nb_node->cbs.pre_validate(&args);
|
||||||
|
|
||||||
|
/* Detect and log unexpected errors. */
|
||||||
|
switch (ret) {
|
||||||
|
case NB_OK:
|
||||||
|
case NB_ERR_VALIDATION:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
unexpected_error = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (unexpected_error)
|
||||||
|
DEBUGD(&nb_dbg_cbs_config,
|
||||||
|
"northbound callback: unexpected return value: %s",
|
||||||
|
nb_err_name(ret));
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void nb_callback_apply_finish(const struct nb_node *nb_node,
|
static void nb_callback_apply_finish(struct nb_context *context,
|
||||||
const struct lyd_node *dnode)
|
const struct nb_node *nb_node,
|
||||||
|
const struct lyd_node *dnode, char *errmsg,
|
||||||
|
size_t errmsg_len)
|
||||||
{
|
{
|
||||||
struct nb_cb_apply_finish_args args = {};
|
struct nb_cb_apply_finish_args args = {};
|
||||||
|
|
||||||
nb_log_config_callback(NB_EV_APPLY, NB_OP_APPLY_FINISH, dnode);
|
nb_log_config_callback(NB_EV_APPLY, NB_OP_APPLY_FINISH, dnode);
|
||||||
|
|
||||||
|
args.context = context;
|
||||||
args.dnode = dnode;
|
args.dnode = dnode;
|
||||||
|
args.errmsg = errmsg;
|
||||||
|
args.errmsg_len = errmsg_len;
|
||||||
nb_node->cbs.apply_finish(&args);
|
nb_node->cbs.apply_finish(&args);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -953,8 +1141,10 @@ int nb_callback_rpc(const struct nb_node *nb_node, const char *xpath,
|
|||||||
* Call the northbound configuration callback associated to a given
|
* Call the northbound configuration callback associated to a given
|
||||||
* configuration change.
|
* configuration change.
|
||||||
*/
|
*/
|
||||||
static int nb_callback_configuration(const enum nb_event event,
|
static int nb_callback_configuration(struct nb_context *context,
|
||||||
struct nb_config_change *change)
|
const enum nb_event event,
|
||||||
|
struct nb_config_change *change,
|
||||||
|
char *errmsg, size_t errmsg_len)
|
||||||
{
|
{
|
||||||
enum nb_operation operation = change->cb.operation;
|
enum nb_operation operation = change->cb.operation;
|
||||||
char xpath[XPATH_MAXLEN];
|
char xpath[XPATH_MAXLEN];
|
||||||
@ -963,7 +1153,6 @@ static int nb_callback_configuration(const enum nb_event event,
|
|||||||
union nb_resource *resource;
|
union nb_resource *resource;
|
||||||
int ret = NB_ERR;
|
int ret = NB_ERR;
|
||||||
|
|
||||||
|
|
||||||
if (event == NB_EV_VALIDATE)
|
if (event == NB_EV_VALIDATE)
|
||||||
resource = NULL;
|
resource = NULL;
|
||||||
else
|
else
|
||||||
@ -971,16 +1160,20 @@ static int nb_callback_configuration(const enum nb_event event,
|
|||||||
|
|
||||||
switch (operation) {
|
switch (operation) {
|
||||||
case NB_OP_CREATE:
|
case NB_OP_CREATE:
|
||||||
ret = nb_callback_create(nb_node, event, dnode, resource);
|
ret = nb_callback_create(context, nb_node, event, dnode,
|
||||||
|
resource, errmsg, errmsg_len);
|
||||||
break;
|
break;
|
||||||
case NB_OP_MODIFY:
|
case NB_OP_MODIFY:
|
||||||
ret = nb_callback_modify(nb_node, event, dnode, resource);
|
ret = nb_callback_modify(context, nb_node, event, dnode,
|
||||||
|
resource, errmsg, errmsg_len);
|
||||||
break;
|
break;
|
||||||
case NB_OP_DESTROY:
|
case NB_OP_DESTROY:
|
||||||
ret = nb_callback_destroy(nb_node, event, dnode);
|
ret = nb_callback_destroy(context, nb_node, event, dnode,
|
||||||
|
errmsg, errmsg_len);
|
||||||
break;
|
break;
|
||||||
case NB_OP_MOVE:
|
case NB_OP_MOVE:
|
||||||
ret = nb_callback_move(nb_node, event, dnode);
|
ret = nb_callback_move(context, nb_node, event, dnode, errmsg,
|
||||||
|
errmsg_len);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
yang_dnode_get_path(dnode, xpath, sizeof(xpath));
|
yang_dnode_get_path(dnode, xpath, sizeof(xpath));
|
||||||
@ -1015,45 +1208,48 @@ static int nb_callback_configuration(const enum nb_event event,
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
flog_err(EC_LIB_DEVELOPMENT,
|
flog_err(EC_LIB_DEVELOPMENT,
|
||||||
"%s: unknown event (%u) [xpath %s]",
|
"%s: unknown event (%u) [xpath %s]", __func__,
|
||||||
__func__, event, xpath);
|
event, xpath);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
flog(priority, ref,
|
flog(priority, ref,
|
||||||
"%s: error processing configuration change: error [%s] event [%s] operation [%s] xpath [%s]",
|
"error processing configuration change: error [%s] event [%s] operation [%s] xpath [%s]",
|
||||||
__func__, nb_err_name(ret), nb_event_name(event),
|
nb_err_name(ret), nb_event_name(event),
|
||||||
nb_operation_name(operation), xpath);
|
nb_operation_name(operation), xpath);
|
||||||
|
if (strlen(errmsg) > 0)
|
||||||
|
flog(priority, ref,
|
||||||
|
"error processing configuration change: %s",
|
||||||
|
errmsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct nb_transaction *
|
static struct nb_transaction *
|
||||||
nb_transaction_new(struct nb_config *config, struct nb_config_cbs *changes,
|
nb_transaction_new(struct nb_context *context, struct nb_config *config,
|
||||||
enum nb_client client, const void *user, const char *comment)
|
struct nb_config_cbs *changes, const char *comment,
|
||||||
|
char *errmsg, size_t errmsg_len)
|
||||||
{
|
{
|
||||||
struct nb_transaction *transaction;
|
struct nb_transaction *transaction;
|
||||||
|
|
||||||
if (nb_running_lock_check(client, user)) {
|
if (nb_running_lock_check(context->client, context->user)) {
|
||||||
flog_warn(
|
strlcpy(errmsg,
|
||||||
EC_LIB_NB_TRANSACTION_CREATION_FAILED,
|
"running configuration is locked by another client",
|
||||||
"%s: running configuration is locked by another client",
|
errmsg_len);
|
||||||
__func__);
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (transaction_in_progress) {
|
if (transaction_in_progress) {
|
||||||
flog_warn(
|
strlcpy(errmsg,
|
||||||
EC_LIB_NB_TRANSACTION_CREATION_FAILED,
|
"there's already another transaction in progress",
|
||||||
"%s: error - there's already another transaction in progress",
|
errmsg_len);
|
||||||
__func__);
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
transaction_in_progress = true;
|
transaction_in_progress = true;
|
||||||
|
|
||||||
transaction = XCALLOC(MTYPE_TMP, sizeof(*transaction));
|
transaction = XCALLOC(MTYPE_TMP, sizeof(*transaction));
|
||||||
transaction->client = client;
|
transaction->context = context;
|
||||||
if (comment)
|
if (comment)
|
||||||
strlcpy(transaction->comment, comment,
|
strlcpy(transaction->comment, comment,
|
||||||
sizeof(transaction->comment));
|
sizeof(transaction->comment));
|
||||||
@ -1072,7 +1268,8 @@ static void nb_transaction_free(struct nb_transaction *transaction)
|
|||||||
|
|
||||||
/* Process all configuration changes associated to a transaction. */
|
/* Process all configuration changes associated to a transaction. */
|
||||||
static int nb_transaction_process(enum nb_event event,
|
static int nb_transaction_process(enum nb_event event,
|
||||||
struct nb_transaction *transaction)
|
struct nb_transaction *transaction,
|
||||||
|
char *errmsg, size_t errmsg_len)
|
||||||
{
|
{
|
||||||
struct nb_config_cb *cb;
|
struct nb_config_cb *cb;
|
||||||
|
|
||||||
@ -1088,7 +1285,8 @@ static int nb_transaction_process(enum nb_event event,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
/* Call the appropriate callback. */
|
/* Call the appropriate callback. */
|
||||||
ret = nb_callback_configuration(event, change);
|
ret = nb_callback_configuration(transaction->context, event,
|
||||||
|
change, errmsg, errmsg_len);
|
||||||
switch (event) {
|
switch (event) {
|
||||||
case NB_EV_PREPARE:
|
case NB_EV_PREPARE:
|
||||||
if (ret != NB_OK)
|
if (ret != NB_OK)
|
||||||
@ -1142,7 +1340,8 @@ nb_apply_finish_cb_find(struct nb_config_cbs *cbs,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Call the 'apply_finish' callbacks. */
|
/* Call the 'apply_finish' callbacks. */
|
||||||
static void nb_transaction_apply_finish(struct nb_transaction *transaction)
|
static void nb_transaction_apply_finish(struct nb_transaction *transaction,
|
||||||
|
char *errmsg, size_t errmsg_len)
|
||||||
{
|
{
|
||||||
struct nb_config_cbs cbs;
|
struct nb_config_cbs cbs;
|
||||||
struct nb_config_cb *cb;
|
struct nb_config_cb *cb;
|
||||||
@ -1201,7 +1400,8 @@ static void nb_transaction_apply_finish(struct nb_transaction *transaction)
|
|||||||
|
|
||||||
/* Call the 'apply_finish' callbacks, sorted by their priorities. */
|
/* Call the 'apply_finish' callbacks, sorted by their priorities. */
|
||||||
RB_FOREACH (cb, nb_config_cbs, &cbs)
|
RB_FOREACH (cb, nb_config_cbs, &cbs)
|
||||||
nb_callback_apply_finish(cb->nb_node, cb->dnode);
|
nb_callback_apply_finish(transaction->context, cb->nb_node,
|
||||||
|
cb->dnode, errmsg, errmsg_len);
|
||||||
|
|
||||||
/* Release memory. */
|
/* Release memory. */
|
||||||
while (!RB_EMPTY(nb_config_cbs, &cbs)) {
|
while (!RB_EMPTY(nb_config_cbs, &cbs)) {
|
||||||
@ -1939,7 +2139,7 @@ const char *nb_err_name(enum nb_error error)
|
|||||||
case NB_ERR_LOCKED:
|
case NB_ERR_LOCKED:
|
||||||
return "resource is locked";
|
return "resource is locked";
|
||||||
case NB_ERR_VALIDATION:
|
case NB_ERR_VALIDATION:
|
||||||
return "validation error";
|
return "validation";
|
||||||
case NB_ERR_RESOURCE:
|
case NB_ERR_RESOURCE:
|
||||||
return "failed to allocate resource";
|
return "failed to allocate resource";
|
||||||
case NB_ERR_INCONSISTENCY:
|
case NB_ERR_INCONSISTENCY:
|
||||||
|
144
lib/northbound.h
144
lib/northbound.h
@ -91,6 +91,9 @@ union nb_resource {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
struct nb_cb_create_args {
|
struct nb_cb_create_args {
|
||||||
|
/* Context of the configuration transaction. */
|
||||||
|
struct nb_context *context;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The transaction phase. Refer to the documentation comments of
|
* The transaction phase. Refer to the documentation comments of
|
||||||
* nb_event for more details.
|
* nb_event for more details.
|
||||||
@ -107,9 +110,18 @@ struct nb_cb_create_args {
|
|||||||
* resource(s). It's set to NULL when the event is NB_EV_VALIDATE.
|
* resource(s). It's set to NULL when the event is NB_EV_VALIDATE.
|
||||||
*/
|
*/
|
||||||
union nb_resource *resource;
|
union nb_resource *resource;
|
||||||
|
|
||||||
|
/* Buffer to store human-readable error message in case of error. */
|
||||||
|
char *errmsg;
|
||||||
|
|
||||||
|
/* Size of errmsg. */
|
||||||
|
size_t errmsg_len;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct nb_cb_modify_args {
|
struct nb_cb_modify_args {
|
||||||
|
/* Context of the configuration transaction. */
|
||||||
|
struct nb_context *context;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The transaction phase. Refer to the documentation comments of
|
* The transaction phase. Refer to the documentation comments of
|
||||||
* nb_event for more details.
|
* nb_event for more details.
|
||||||
@ -126,9 +138,18 @@ struct nb_cb_modify_args {
|
|||||||
* resource(s). It's set to NULL when the event is NB_EV_VALIDATE.
|
* resource(s). It's set to NULL when the event is NB_EV_VALIDATE.
|
||||||
*/
|
*/
|
||||||
union nb_resource *resource;
|
union nb_resource *resource;
|
||||||
|
|
||||||
|
/* Buffer to store human-readable error message in case of error. */
|
||||||
|
char *errmsg;
|
||||||
|
|
||||||
|
/* Size of errmsg. */
|
||||||
|
size_t errmsg_len;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct nb_cb_destroy_args {
|
struct nb_cb_destroy_args {
|
||||||
|
/* Context of the configuration transaction. */
|
||||||
|
struct nb_context *context;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The transaction phase. Refer to the documentation comments of
|
* The transaction phase. Refer to the documentation comments of
|
||||||
* nb_event for more details.
|
* nb_event for more details.
|
||||||
@ -137,9 +158,18 @@ struct nb_cb_destroy_args {
|
|||||||
|
|
||||||
/* libyang data node that is being deleted. */
|
/* libyang data node that is being deleted. */
|
||||||
const struct lyd_node *dnode;
|
const struct lyd_node *dnode;
|
||||||
|
|
||||||
|
/* Buffer to store human-readable error message in case of error. */
|
||||||
|
char *errmsg;
|
||||||
|
|
||||||
|
/* Size of errmsg. */
|
||||||
|
size_t errmsg_len;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct nb_cb_move_args {
|
struct nb_cb_move_args {
|
||||||
|
/* Context of the configuration transaction. */
|
||||||
|
struct nb_context *context;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The transaction phase. Refer to the documentation comments of
|
* The transaction phase. Refer to the documentation comments of
|
||||||
* nb_event for more details.
|
* nb_event for more details.
|
||||||
@ -148,16 +178,40 @@ struct nb_cb_move_args {
|
|||||||
|
|
||||||
/* libyang data node that is being moved. */
|
/* libyang data node that is being moved. */
|
||||||
const struct lyd_node *dnode;
|
const struct lyd_node *dnode;
|
||||||
|
|
||||||
|
/* Buffer to store human-readable error message in case of error. */
|
||||||
|
char *errmsg;
|
||||||
|
|
||||||
|
/* Size of errmsg. */
|
||||||
|
size_t errmsg_len;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct nb_cb_pre_validate_args {
|
struct nb_cb_pre_validate_args {
|
||||||
|
/* Context of the configuration transaction. */
|
||||||
|
struct nb_context *context;
|
||||||
|
|
||||||
/* libyang data node associated with the 'pre_validate' callback. */
|
/* libyang data node associated with the 'pre_validate' callback. */
|
||||||
const struct lyd_node *dnode;
|
const struct lyd_node *dnode;
|
||||||
|
|
||||||
|
/* Buffer to store human-readable error message in case of error. */
|
||||||
|
char *errmsg;
|
||||||
|
|
||||||
|
/* Size of errmsg. */
|
||||||
|
size_t errmsg_len;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct nb_cb_apply_finish_args {
|
struct nb_cb_apply_finish_args {
|
||||||
|
/* Context of the configuration transaction. */
|
||||||
|
struct nb_context *context;
|
||||||
|
|
||||||
/* libyang data node associated with the 'apply_finish' callback. */
|
/* libyang data node associated with the 'apply_finish' callback. */
|
||||||
const struct lyd_node *dnode;
|
const struct lyd_node *dnode;
|
||||||
|
|
||||||
|
/* Buffer to store human-readable error message in case of error. */
|
||||||
|
char *errmsg;
|
||||||
|
|
||||||
|
/* Size of errmsg. */
|
||||||
|
size_t errmsg_len;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct nb_cb_get_elem_args {
|
struct nb_cb_get_elem_args {
|
||||||
@ -305,6 +359,10 @@ struct nb_callbacks {
|
|||||||
* args
|
* args
|
||||||
* Refer to the documentation comments of nb_cb_pre_validate_args for
|
* Refer to the documentation comments of nb_cb_pre_validate_args for
|
||||||
* details.
|
* details.
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* - NB_OK on success.
|
||||||
|
* - NB_ERR_VALIDATION when a validation error occurred.
|
||||||
*/
|
*/
|
||||||
int (*pre_validate)(struct nb_cb_pre_validate_args *args);
|
int (*pre_validate)(struct nb_cb_pre_validate_args *args);
|
||||||
|
|
||||||
@ -538,6 +596,29 @@ enum nb_client {
|
|||||||
NB_CLIENT_GRPC,
|
NB_CLIENT_GRPC,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Northbound context. */
|
||||||
|
struct nb_context {
|
||||||
|
/* Northbound client. */
|
||||||
|
enum nb_client client;
|
||||||
|
|
||||||
|
/* Northbound user (can be NULL). */
|
||||||
|
const void *user;
|
||||||
|
|
||||||
|
/* Client-specific data. */
|
||||||
|
#if 0
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
} cli;
|
||||||
|
struct {
|
||||||
|
} confd;
|
||||||
|
struct {
|
||||||
|
} sysrepo;
|
||||||
|
struct {
|
||||||
|
} grpc;
|
||||||
|
} client_data;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
/* Northbound configuration. */
|
/* Northbound configuration. */
|
||||||
struct nb_config {
|
struct nb_config {
|
||||||
struct lyd_node *dnode;
|
struct lyd_node *dnode;
|
||||||
@ -564,7 +645,7 @@ struct nb_config_change {
|
|||||||
|
|
||||||
/* Northbound configuration transaction. */
|
/* Northbound configuration transaction. */
|
||||||
struct nb_transaction {
|
struct nb_transaction {
|
||||||
enum nb_client client;
|
struct nb_context *context;
|
||||||
char comment[80];
|
char comment[80];
|
||||||
struct nb_config *config;
|
struct nb_config *config;
|
||||||
struct nb_config_cbs changes;
|
struct nb_config_cbs changes;
|
||||||
@ -762,28 +843,36 @@ extern int nb_candidate_update(struct nb_config *candidate);
|
|||||||
* WARNING: the candidate can be modified as part of the validation process
|
* WARNING: the candidate can be modified as part of the validation process
|
||||||
* (e.g. add default nodes).
|
* (e.g. add default nodes).
|
||||||
*
|
*
|
||||||
|
* context
|
||||||
|
* Context of the northbound transaction.
|
||||||
|
*
|
||||||
* candidate
|
* candidate
|
||||||
* Candidate configuration to validate.
|
* Candidate configuration to validate.
|
||||||
*
|
*
|
||||||
|
* errmsg
|
||||||
|
* Buffer to store human-readable error message in case of error.
|
||||||
|
*
|
||||||
|
* errmsg_len
|
||||||
|
* Size of errmsg.
|
||||||
|
*
|
||||||
* Returns:
|
* Returns:
|
||||||
* NB_OK on success, NB_ERR_VALIDATION otherwise.
|
* NB_OK on success, NB_ERR_VALIDATION otherwise.
|
||||||
*/
|
*/
|
||||||
extern int nb_candidate_validate(struct nb_config *candidate);
|
extern int nb_candidate_validate(struct nb_context *context,
|
||||||
|
struct nb_config *candidate, char *errmsg,
|
||||||
|
size_t errmsg_len);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create a new configuration transaction but do not commit it yet. Only
|
* Create a new configuration transaction but do not commit it yet. Only
|
||||||
* validate the candidate and prepare all resources required to apply the
|
* validate the candidate and prepare all resources required to apply the
|
||||||
* configuration changes.
|
* configuration changes.
|
||||||
*
|
*
|
||||||
|
* context
|
||||||
|
* Context of the northbound transaction.
|
||||||
|
*
|
||||||
* candidate
|
* candidate
|
||||||
* Candidate configuration to commit.
|
* Candidate configuration to commit.
|
||||||
*
|
*
|
||||||
* client
|
|
||||||
* Northbound client performing the commit.
|
|
||||||
*
|
|
||||||
* user
|
|
||||||
* Northbound user performing the commit (can be NULL).
|
|
||||||
*
|
|
||||||
* comment
|
* comment
|
||||||
* Optional comment describing the commit.
|
* Optional comment describing the commit.
|
||||||
*
|
*
|
||||||
@ -793,6 +882,12 @@ extern int nb_candidate_validate(struct nb_config *candidate);
|
|||||||
* nb_candidate_commit_abort() or committed using
|
* nb_candidate_commit_abort() or committed using
|
||||||
* nb_candidate_commit_apply().
|
* nb_candidate_commit_apply().
|
||||||
*
|
*
|
||||||
|
* errmsg
|
||||||
|
* Buffer to store human-readable error message in case of error.
|
||||||
|
*
|
||||||
|
* errmsg_len
|
||||||
|
* Size of errmsg.
|
||||||
|
*
|
||||||
* Returns:
|
* Returns:
|
||||||
* - NB_OK on success.
|
* - NB_OK on success.
|
||||||
* - NB_ERR_NO_CHANGES when the candidate is identical to the running
|
* - NB_ERR_NO_CHANGES when the candidate is identical to the running
|
||||||
@ -803,10 +898,11 @@ extern int nb_candidate_validate(struct nb_config *candidate);
|
|||||||
* the candidate configuration.
|
* the candidate configuration.
|
||||||
* - NB_ERR for other errors.
|
* - NB_ERR for other errors.
|
||||||
*/
|
*/
|
||||||
extern int nb_candidate_commit_prepare(struct nb_config *candidate,
|
extern int nb_candidate_commit_prepare(struct nb_context *context,
|
||||||
enum nb_client client, const void *user,
|
struct nb_config *candidate,
|
||||||
const char *comment,
|
const char *comment,
|
||||||
struct nb_transaction **transaction);
|
struct nb_transaction **transaction,
|
||||||
|
char *errmsg, size_t errmsg_len);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Abort a previously created configuration transaction, releasing all resources
|
* Abort a previously created configuration transaction, releasing all resources
|
||||||
@ -842,16 +938,13 @@ extern void nb_candidate_commit_apply(struct nb_transaction *transaction,
|
|||||||
* take into account the results of the preparation phase of multiple managed
|
* take into account the results of the preparation phase of multiple managed
|
||||||
* entities.
|
* entities.
|
||||||
*
|
*
|
||||||
|
* context
|
||||||
|
* Context of the northbound transaction.
|
||||||
|
*
|
||||||
* candidate
|
* candidate
|
||||||
* Candidate configuration to commit. It's preserved regardless if the commit
|
* Candidate configuration to commit. It's preserved regardless if the commit
|
||||||
* operation fails or not.
|
* operation fails or not.
|
||||||
*
|
*
|
||||||
* client
|
|
||||||
* Northbound client performing the commit.
|
|
||||||
*
|
|
||||||
* user
|
|
||||||
* Northbound user performing the commit (can be NULL).
|
|
||||||
*
|
|
||||||
* save_transaction
|
* save_transaction
|
||||||
* Specify whether the transaction should be recorded in the transactions log
|
* Specify whether the transaction should be recorded in the transactions log
|
||||||
* or not.
|
* or not.
|
||||||
@ -862,6 +955,12 @@ extern void nb_candidate_commit_apply(struct nb_transaction *transaction,
|
|||||||
* transaction_id
|
* transaction_id
|
||||||
* Optional output parameter providing the ID of the committed transaction.
|
* Optional output parameter providing the ID of the committed transaction.
|
||||||
*
|
*
|
||||||
|
* errmsg
|
||||||
|
* Buffer to store human-readable error message in case of error.
|
||||||
|
*
|
||||||
|
* errmsg_len
|
||||||
|
* Size of errmsg.
|
||||||
|
*
|
||||||
* Returns:
|
* Returns:
|
||||||
* - NB_OK on success.
|
* - NB_OK on success.
|
||||||
* - NB_ERR_NO_CHANGES when the candidate is identical to the running
|
* - NB_ERR_NO_CHANGES when the candidate is identical to the running
|
||||||
@ -872,10 +971,11 @@ extern void nb_candidate_commit_apply(struct nb_transaction *transaction,
|
|||||||
* the candidate configuration.
|
* the candidate configuration.
|
||||||
* - NB_ERR for other errors.
|
* - NB_ERR for other errors.
|
||||||
*/
|
*/
|
||||||
extern int nb_candidate_commit(struct nb_config *candidate,
|
extern int nb_candidate_commit(struct nb_context *context,
|
||||||
enum nb_client client, const void *user,
|
struct nb_config *candidate,
|
||||||
bool save_transaction, const char *comment,
|
bool save_transaction, const char *comment,
|
||||||
uint32_t *transaction_id);
|
uint32_t *transaction_id, char *errmsg,
|
||||||
|
size_t errmsg_len);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Lock the running configuration.
|
* Lock the running configuration.
|
||||||
@ -1061,8 +1161,8 @@ extern void *nb_running_unset_entry(const struct lyd_node *dnode);
|
|||||||
* Returns:
|
* Returns:
|
||||||
* User pointer if found, NULL otherwise.
|
* User pointer if found, NULL otherwise.
|
||||||
*/
|
*/
|
||||||
extern void *nb_running_get_entry(const struct lyd_node *dnode, const char *xpath,
|
extern void *nb_running_get_entry(const struct lyd_node *dnode,
|
||||||
bool abort_if_not_found);
|
const char *xpath, bool abort_if_not_found);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Return a human-readable string representing a northbound event.
|
* Return a human-readable string representing a northbound event.
|
||||||
|
@ -46,23 +46,11 @@ struct debug nb_dbg_libyang = {0, "libyang debugging"};
|
|||||||
struct nb_config *vty_shared_candidate_config;
|
struct nb_config *vty_shared_candidate_config;
|
||||||
static struct thread_master *master;
|
static struct thread_master *master;
|
||||||
|
|
||||||
static void vty_show_libyang_errors(struct vty *vty, struct ly_ctx *ly_ctx)
|
static void vty_show_nb_errors(struct vty *vty, int error, const char *errmsg)
|
||||||
{
|
{
|
||||||
struct ly_err_item *ei;
|
vty_out(vty, "Error type: %s\n", nb_err_name(error));
|
||||||
const char *path;
|
if (strlen(errmsg) > 0)
|
||||||
|
vty_out(vty, "Error description: %s\n", errmsg);
|
||||||
ei = ly_err_first(ly_ctx);
|
|
||||||
if (!ei)
|
|
||||||
return;
|
|
||||||
|
|
||||||
for (; ei; ei = ei->next)
|
|
||||||
vty_out(vty, "%s\n", ei->msg);
|
|
||||||
|
|
||||||
path = ly_errpath(ly_ctx);
|
|
||||||
if (path)
|
|
||||||
vty_out(vty, "YANG path: %s\n", path);
|
|
||||||
|
|
||||||
ly_err_clean(ly_ctx, NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void nb_cli_enqueue_change(struct vty *vty, const char *xpath,
|
void nb_cli_enqueue_change(struct vty *vty, const char *xpath,
|
||||||
@ -158,24 +146,31 @@ int nb_cli_apply_changes(struct vty *vty, const char *xpath_base_fmt, ...)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
|
char buf[BUFSIZ];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Failure to edit the candidate configuration should never
|
* Failure to edit the candidate configuration should never
|
||||||
* happen in practice, unless there's a bug in the code. When
|
* happen in practice, unless there's a bug in the code. When
|
||||||
* that happens, log the error but otherwise ignore it.
|
* that happens, log the error but otherwise ignore it.
|
||||||
*/
|
*/
|
||||||
vty_out(vty, "%% Failed to edit configuration.\n\n");
|
vty_out(vty, "%% Failed to edit configuration.\n\n");
|
||||||
vty_show_libyang_errors(vty, ly_native_ctx);
|
vty_out(vty, "%s",
|
||||||
|
yang_print_errors(ly_native_ctx, buf, sizeof(buf)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Do an implicit "commit" when using the classic CLI mode. */
|
/* Do an implicit "commit" when using the classic CLI mode. */
|
||||||
if (frr_get_cli_mode() == FRR_CLI_CLASSIC) {
|
if (frr_get_cli_mode() == FRR_CLI_CLASSIC) {
|
||||||
ret = nb_candidate_commit(vty->candidate_config, NB_CLIENT_CLI,
|
struct nb_context context = {};
|
||||||
vty, false, NULL, NULL);
|
char errmsg[BUFSIZ] = {0};
|
||||||
|
|
||||||
|
context.client = NB_CLIENT_CLI;
|
||||||
|
context.user = vty;
|
||||||
|
ret = nb_candidate_commit(&context, vty->candidate_config,
|
||||||
|
false, NULL, NULL, errmsg,
|
||||||
|
sizeof(errmsg));
|
||||||
if (ret != NB_OK && ret != NB_ERR_NO_CHANGES) {
|
if (ret != NB_OK && ret != NB_ERR_NO_CHANGES) {
|
||||||
vty_out(vty, "%% Configuration failed: %s.\n\n",
|
vty_out(vty, "%% Configuration failed.\n\n");
|
||||||
nb_err_name(ret));
|
vty_show_nb_errors(vty, ret, errmsg);
|
||||||
vty_out(vty,
|
|
||||||
"Please check the logs for more details.\n");
|
|
||||||
|
|
||||||
/* Regenerate candidate for consistency. */
|
/* Regenerate candidate for consistency. */
|
||||||
nb_config_replace(vty->candidate_config, running_config,
|
nb_config_replace(vty->candidate_config, running_config,
|
||||||
@ -217,20 +212,27 @@ void nb_cli_confirmed_commit_clean(struct vty *vty)
|
|||||||
|
|
||||||
int nb_cli_confirmed_commit_rollback(struct vty *vty)
|
int nb_cli_confirmed_commit_rollback(struct vty *vty)
|
||||||
{
|
{
|
||||||
|
struct nb_context context = {};
|
||||||
uint32_t transaction_id;
|
uint32_t transaction_id;
|
||||||
|
char errmsg[BUFSIZ] = {0};
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/* Perform the rollback. */
|
/* Perform the rollback. */
|
||||||
|
context.client = NB_CLIENT_CLI;
|
||||||
|
context.user = vty;
|
||||||
ret = nb_candidate_commit(
|
ret = nb_candidate_commit(
|
||||||
vty->confirmed_commit_rollback, NB_CLIENT_CLI, vty, true,
|
&context, vty->confirmed_commit_rollback, true,
|
||||||
"Rollback to previous configuration - confirmed commit has timed out",
|
"Rollback to previous configuration - confirmed commit has timed out",
|
||||||
&transaction_id);
|
&transaction_id, errmsg, sizeof(errmsg));
|
||||||
if (ret == NB_OK)
|
if (ret == NB_OK)
|
||||||
vty_out(vty,
|
vty_out(vty,
|
||||||
"Rollback performed successfully (Transaction ID #%u).\n",
|
"Rollback performed successfully (Transaction ID #%u).\n",
|
||||||
transaction_id);
|
transaction_id);
|
||||||
else
|
else {
|
||||||
vty_out(vty, "Failed to rollback to previous configuration.\n");
|
vty_out(vty,
|
||||||
|
"Failed to rollback to previous configuration.\n\n");
|
||||||
|
vty_show_nb_errors(vty, ret, errmsg);
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -252,7 +254,9 @@ static int nb_cli_confirmed_commit_timeout(struct thread *thread)
|
|||||||
static int nb_cli_commit(struct vty *vty, bool force,
|
static int nb_cli_commit(struct vty *vty, bool force,
|
||||||
unsigned int confirmed_timeout, char *comment)
|
unsigned int confirmed_timeout, char *comment)
|
||||||
{
|
{
|
||||||
|
struct nb_context context = {};
|
||||||
uint32_t transaction_id = 0;
|
uint32_t transaction_id = 0;
|
||||||
|
char errmsg[BUFSIZ] = {0};
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/* Check if there's a pending confirmed commit. */
|
/* Check if there's a pending confirmed commit. */
|
||||||
@ -295,8 +299,11 @@ static int nb_cli_commit(struct vty *vty, bool force,
|
|||||||
&vty->t_confirmed_commit_timeout);
|
&vty->t_confirmed_commit_timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = nb_candidate_commit(vty->candidate_config, NB_CLIENT_CLI, vty,
|
context.client = NB_CLIENT_CLI;
|
||||||
true, comment, &transaction_id);
|
context.user = vty;
|
||||||
|
ret = nb_candidate_commit(&context, vty->candidate_config, true,
|
||||||
|
comment, &transaction_id, errmsg,
|
||||||
|
sizeof(errmsg));
|
||||||
|
|
||||||
/* Map northbound return code to CLI return code. */
|
/* Map northbound return code to CLI return code. */
|
||||||
switch (ret) {
|
switch (ret) {
|
||||||
@ -312,9 +319,8 @@ static int nb_cli_commit(struct vty *vty, bool force,
|
|||||||
return CMD_SUCCESS;
|
return CMD_SUCCESS;
|
||||||
default:
|
default:
|
||||||
vty_out(vty,
|
vty_out(vty,
|
||||||
"%% Failed to commit candidate configuration: %s.\n\n",
|
"%% Failed to commit candidate configuration.\n\n");
|
||||||
nb_err_name(ret));
|
vty_show_nb_errors(vty, ret, errmsg);
|
||||||
vty_out(vty, "Please check the logs for more details.\n");
|
|
||||||
return CMD_WARNING;
|
return CMD_WARNING;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -328,6 +334,7 @@ static int nb_cli_candidate_load_file(struct vty *vty,
|
|||||||
struct lyd_node *dnode;
|
struct lyd_node *dnode;
|
||||||
struct ly_ctx *ly_ctx;
|
struct ly_ctx *ly_ctx;
|
||||||
int ly_format;
|
int ly_format;
|
||||||
|
char buf[BUFSIZ];
|
||||||
|
|
||||||
switch (format) {
|
switch (format) {
|
||||||
case NB_CFG_FMT_CMDS:
|
case NB_CFG_FMT_CMDS:
|
||||||
@ -350,7 +357,9 @@ static int nb_cli_candidate_load_file(struct vty *vty,
|
|||||||
flog_warn(EC_LIB_LIBYANG, "%s: lyd_parse_path() failed",
|
flog_warn(EC_LIB_LIBYANG, "%s: lyd_parse_path() failed",
|
||||||
__func__);
|
__func__);
|
||||||
vty_out(vty, "%% Failed to load configuration:\n\n");
|
vty_out(vty, "%% Failed to load configuration:\n\n");
|
||||||
vty_show_libyang_errors(vty, ly_ctx);
|
vty_out(vty, "%s",
|
||||||
|
yang_print_errors(ly_native_ctx, buf,
|
||||||
|
sizeof(buf)));
|
||||||
return CMD_WARNING;
|
return CMD_WARNING;
|
||||||
}
|
}
|
||||||
if (translator
|
if (translator
|
||||||
@ -371,7 +380,8 @@ static int nb_cli_candidate_load_file(struct vty *vty,
|
|||||||
!= NB_OK) {
|
!= NB_OK) {
|
||||||
vty_out(vty,
|
vty_out(vty,
|
||||||
"%% Failed to merge the loaded configuration:\n\n");
|
"%% Failed to merge the loaded configuration:\n\n");
|
||||||
vty_show_libyang_errors(vty, ly_native_ctx);
|
vty_out(vty, "%s",
|
||||||
|
yang_print_errors(ly_native_ctx, buf, sizeof(buf)));
|
||||||
return CMD_WARNING;
|
return CMD_WARNING;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -383,6 +393,7 @@ static int nb_cli_candidate_load_transaction(struct vty *vty,
|
|||||||
bool replace)
|
bool replace)
|
||||||
{
|
{
|
||||||
struct nb_config *loaded_config;
|
struct nb_config *loaded_config;
|
||||||
|
char buf[BUFSIZ];
|
||||||
|
|
||||||
loaded_config = nb_db_transaction_load(transaction_id);
|
loaded_config = nb_db_transaction_load(transaction_id);
|
||||||
if (!loaded_config) {
|
if (!loaded_config) {
|
||||||
@ -397,7 +408,8 @@ static int nb_cli_candidate_load_transaction(struct vty *vty,
|
|||||||
!= NB_OK) {
|
!= NB_OK) {
|
||||||
vty_out(vty,
|
vty_out(vty,
|
||||||
"%% Failed to merge the loaded configuration:\n\n");
|
"%% Failed to merge the loaded configuration:\n\n");
|
||||||
vty_show_libyang_errors(vty, ly_native_ctx);
|
vty_out(vty, "%s",
|
||||||
|
yang_print_errors(ly_native_ctx, buf, sizeof(buf)));
|
||||||
return CMD_WARNING;
|
return CMD_WARNING;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -690,13 +702,18 @@ DEFPY (config_commit_check,
|
|||||||
"Commit changes into the running configuration\n"
|
"Commit changes into the running configuration\n"
|
||||||
"Check if the configuration changes are valid\n")
|
"Check if the configuration changes are valid\n")
|
||||||
{
|
{
|
||||||
|
struct nb_context context = {};
|
||||||
|
char errmsg[BUFSIZ] = {0};
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = nb_candidate_validate(vty->candidate_config);
|
context.client = NB_CLIENT_CLI;
|
||||||
|
context.user = vty;
|
||||||
|
ret = nb_candidate_validate(&context, vty->candidate_config, errmsg,
|
||||||
|
sizeof(errmsg));
|
||||||
if (ret != NB_OK) {
|
if (ret != NB_OK) {
|
||||||
vty_out(vty,
|
vty_out(vty,
|
||||||
"%% Failed to validate candidate configuration.\n\n");
|
"%% Failed to validate candidate configuration.\n\n");
|
||||||
vty_show_libyang_errors(vty, ly_native_ctx);
|
vty_show_nb_errors(vty, ret, errmsg);
|
||||||
return CMD_WARNING;
|
return CMD_WARNING;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1530,8 +1547,10 @@ DEFPY (show_yang_module_translator,
|
|||||||
static int nb_cli_rollback_configuration(struct vty *vty,
|
static int nb_cli_rollback_configuration(struct vty *vty,
|
||||||
uint32_t transaction_id)
|
uint32_t transaction_id)
|
||||||
{
|
{
|
||||||
|
struct nb_context context = {};
|
||||||
struct nb_config *candidate;
|
struct nb_config *candidate;
|
||||||
char comment[80];
|
char comment[80];
|
||||||
|
char errmsg[BUFSIZ] = {0};
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
candidate = nb_db_transaction_load(transaction_id);
|
candidate = nb_db_transaction_load(transaction_id);
|
||||||
@ -1544,8 +1563,10 @@ static int nb_cli_rollback_configuration(struct vty *vty,
|
|||||||
snprintf(comment, sizeof(comment), "Rollback to transaction %u",
|
snprintf(comment, sizeof(comment), "Rollback to transaction %u",
|
||||||
transaction_id);
|
transaction_id);
|
||||||
|
|
||||||
ret = nb_candidate_commit(candidate, NB_CLIENT_CLI, vty, true, comment,
|
context.client = NB_CLIENT_CLI;
|
||||||
NULL);
|
context.user = vty;
|
||||||
|
ret = nb_candidate_commit(&context, candidate, true, comment, NULL,
|
||||||
|
errmsg, sizeof(errmsg));
|
||||||
nb_config_free(candidate);
|
nb_config_free(candidate);
|
||||||
switch (ret) {
|
switch (ret) {
|
||||||
case NB_OK:
|
case NB_OK:
|
||||||
@ -1558,7 +1579,7 @@ static int nb_cli_rollback_configuration(struct vty *vty,
|
|||||||
return CMD_WARNING;
|
return CMD_WARNING;
|
||||||
default:
|
default:
|
||||||
vty_out(vty, "%% Rollback failed.\n\n");
|
vty_out(vty, "%% Rollback failed.\n\n");
|
||||||
vty_out(vty, "Please check the logs for more details.\n");
|
vty_show_nb_errors(vty, ret, errmsg);
|
||||||
return CMD_WARNING;
|
return CMD_WARNING;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -285,8 +285,10 @@ frr_confd_cdb_diff_iter(confd_hkeypath_t *kp, enum cdb_iter_op cdb_op,
|
|||||||
|
|
||||||
static int frr_confd_cdb_read_cb_prepare(int fd, int *subp, int reslen)
|
static int frr_confd_cdb_read_cb_prepare(int fd, int *subp, int reslen)
|
||||||
{
|
{
|
||||||
|
struct nb_context context = {};
|
||||||
struct nb_config *candidate;
|
struct nb_config *candidate;
|
||||||
struct cdb_iter_args iter_args;
|
struct cdb_iter_args iter_args;
|
||||||
|
char errmsg[BUFSIZ] = {0};
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
candidate = nb_config_dup(running_config);
|
candidate = nb_config_dup(running_config);
|
||||||
@ -321,24 +323,21 @@ static int frr_confd_cdb_read_cb_prepare(int fd, int *subp, int reslen)
|
|||||||
* required to apply them.
|
* required to apply them.
|
||||||
*/
|
*/
|
||||||
transaction = NULL;
|
transaction = NULL;
|
||||||
ret = nb_candidate_commit_prepare(candidate, NB_CLIENT_CONFD, NULL,
|
context.client = NB_CLIENT_CONFD;
|
||||||
NULL, &transaction);
|
ret = nb_candidate_commit_prepare(&context, candidate, NULL,
|
||||||
|
&transaction, errmsg, sizeof(errmsg));
|
||||||
if (ret != NB_OK && ret != NB_ERR_NO_CHANGES) {
|
if (ret != NB_OK && ret != NB_ERR_NO_CHANGES) {
|
||||||
enum confd_errcode errcode;
|
enum confd_errcode errcode;
|
||||||
const char *errmsg;
|
|
||||||
|
|
||||||
switch (ret) {
|
switch (ret) {
|
||||||
case NB_ERR_LOCKED:
|
case NB_ERR_LOCKED:
|
||||||
errcode = CONFD_ERRCODE_IN_USE;
|
errcode = CONFD_ERRCODE_IN_USE;
|
||||||
errmsg = "Configuration is locked by another process";
|
|
||||||
break;
|
break;
|
||||||
case NB_ERR_RESOURCE:
|
case NB_ERR_RESOURCE:
|
||||||
errcode = CONFD_ERRCODE_RESOURCE_DENIED;
|
errcode = CONFD_ERRCODE_RESOURCE_DENIED;
|
||||||
errmsg = "Failed do allocate resources";
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
errcode = CONFD_ERRCODE_INTERNAL;
|
errcode = CONFD_ERRCODE_APPLICATION;
|
||||||
errmsg = "Internal error";
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -612,7 +611,7 @@ static int frr_confd_data_get_elem(struct confd_trans_ctx *tctx,
|
|||||||
confd_hkeypath_t *kp)
|
confd_hkeypath_t *kp)
|
||||||
{
|
{
|
||||||
struct nb_node *nb_node;
|
struct nb_node *nb_node;
|
||||||
char xpath[BUFSIZ];
|
char xpath[XPATH_MAXLEN];
|
||||||
struct yang_data *data;
|
struct yang_data *data;
|
||||||
confd_value_t v;
|
confd_value_t v;
|
||||||
const void *list_entry = NULL;
|
const void *list_entry = NULL;
|
||||||
@ -650,7 +649,7 @@ static int frr_confd_data_get_next(struct confd_trans_ctx *tctx,
|
|||||||
confd_hkeypath_t *kp, long next)
|
confd_hkeypath_t *kp, long next)
|
||||||
{
|
{
|
||||||
struct nb_node *nb_node;
|
struct nb_node *nb_node;
|
||||||
char xpath[BUFSIZ];
|
char xpath[XPATH_MAXLEN];
|
||||||
struct yang_data *data;
|
struct yang_data *data;
|
||||||
const void *parent_list_entry, *nb_next;
|
const void *parent_list_entry, *nb_next;
|
||||||
confd_value_t v[LIST_MAXKEYS];
|
confd_value_t v[LIST_MAXKEYS];
|
||||||
@ -758,8 +757,8 @@ static int frr_confd_data_get_object(struct confd_trans_ctx *tctx,
|
|||||||
{
|
{
|
||||||
struct nb_node *nb_node;
|
struct nb_node *nb_node;
|
||||||
const struct lys_node *child;
|
const struct lys_node *child;
|
||||||
char xpath[BUFSIZ];
|
char xpath[XPATH_MAXLEN];
|
||||||
char xpath_child[XPATH_MAXLEN];
|
char xpath_child[XPATH_MAXLEN * 2];
|
||||||
struct list *elements;
|
struct list *elements;
|
||||||
struct yang_data *data;
|
struct yang_data *data;
|
||||||
const void *list_entry;
|
const void *list_entry;
|
||||||
@ -832,7 +831,7 @@ static int frr_confd_data_get_object(struct confd_trans_ctx *tctx,
|
|||||||
static int frr_confd_data_get_next_object(struct confd_trans_ctx *tctx,
|
static int frr_confd_data_get_next_object(struct confd_trans_ctx *tctx,
|
||||||
confd_hkeypath_t *kp, long next)
|
confd_hkeypath_t *kp, long next)
|
||||||
{
|
{
|
||||||
char xpath[BUFSIZ];
|
char xpath[XPATH_MAXLEN];
|
||||||
struct nb_node *nb_node;
|
struct nb_node *nb_node;
|
||||||
struct list *elements;
|
struct list *elements;
|
||||||
const void *parent_list_entry;
|
const void *parent_list_entry;
|
||||||
@ -916,7 +915,7 @@ static int frr_confd_data_get_next_object(struct confd_trans_ctx *tctx,
|
|||||||
/* Loop through list child nodes. */
|
/* Loop through list child nodes. */
|
||||||
LY_TREE_FOR (nb_node->snode->child, child) {
|
LY_TREE_FOR (nb_node->snode->child, child) {
|
||||||
struct nb_node *nb_node_child = child->priv;
|
struct nb_node *nb_node_child = child->priv;
|
||||||
char xpath_child[XPATH_MAXLEN];
|
char xpath_child[XPATH_MAXLEN * 2];
|
||||||
confd_value_t *v;
|
confd_value_t *v;
|
||||||
|
|
||||||
if (nvalues > CONFD_MAX_CHILD_NODES)
|
if (nvalues > CONFD_MAX_CHILD_NODES)
|
||||||
@ -1059,7 +1058,7 @@ static int frr_confd_action_execute(struct confd_user_info *uinfo,
|
|||||||
struct xml_tag *name, confd_hkeypath_t *kp,
|
struct xml_tag *name, confd_hkeypath_t *kp,
|
||||||
confd_tag_value_t *params, int nparams)
|
confd_tag_value_t *params, int nparams)
|
||||||
{
|
{
|
||||||
char xpath[BUFSIZ];
|
char xpath[XPATH_MAXLEN];
|
||||||
struct nb_node *nb_node;
|
struct nb_node *nb_node;
|
||||||
struct list *input;
|
struct list *input;
|
||||||
struct list *output;
|
struct list *output;
|
||||||
@ -1091,7 +1090,7 @@ static int frr_confd_action_execute(struct confd_user_info *uinfo,
|
|||||||
|
|
||||||
/* Process input nodes. */
|
/* Process input nodes. */
|
||||||
for (int i = 0; i < nparams; i++) {
|
for (int i = 0; i < nparams; i++) {
|
||||||
char xpath_input[BUFSIZ];
|
char xpath_input[XPATH_MAXLEN * 2];
|
||||||
char value_str[YANG_VALUE_MAXLEN];
|
char value_str[YANG_VALUE_MAXLEN];
|
||||||
|
|
||||||
snprintf(xpath_input, sizeof(xpath_input), "%s/%s", xpath,
|
snprintf(xpath_input, sizeof(xpath_input), "%s/%s", xpath,
|
||||||
|
@ -86,7 +86,7 @@ int nb_db_transaction_save(const struct nb_transaction *transaction,
|
|||||||
if (!ss)
|
if (!ss)
|
||||||
goto exit;
|
goto exit;
|
||||||
|
|
||||||
client_name = nb_client_name(transaction->client);
|
client_name = nb_client_name(transaction->context->client);
|
||||||
/* Always record configurations in the XML format. */
|
/* Always record configurations in the XML format. */
|
||||||
if (lyd_print_mem(&config_str, transaction->config->dnode, LYD_XML,
|
if (lyd_print_mem(&config_str, transaction->config->dnode, LYD_XML,
|
||||||
LYP_FORMAT | LYP_WITHSIBLINGS)
|
LYP_FORMAT | LYP_WITHSIBLINGS)
|
||||||
|
@ -175,14 +175,13 @@ class NorthboundImpl
|
|||||||
void HandleGetCapabilities(RpcState<frr::GetCapabilitiesRequest,
|
void HandleGetCapabilities(RpcState<frr::GetCapabilitiesRequest,
|
||||||
frr::GetCapabilitiesResponse> *tag)
|
frr::GetCapabilitiesResponse> *tag)
|
||||||
{
|
{
|
||||||
if (nb_dbg_client_grpc)
|
|
||||||
zlog_debug("received RPC GetCapabilities()");
|
|
||||||
|
|
||||||
switch (tag->state) {
|
switch (tag->state) {
|
||||||
case CREATE:
|
case CREATE:
|
||||||
REQUEST_RPC(GetCapabilities);
|
REQUEST_RPC(GetCapabilities);
|
||||||
tag->state = PROCESS;
|
tag->state = PROCESS;
|
||||||
case PROCESS: {
|
case PROCESS: {
|
||||||
|
if (nb_dbg_client_grpc)
|
||||||
|
zlog_debug("received RPC GetCapabilities()");
|
||||||
|
|
||||||
// Response: string frr_version = 1;
|
// Response: string frr_version = 1;
|
||||||
tag->response.set_frr_version(FRR_VERSION);
|
tag->response.set_frr_version(FRR_VERSION);
|
||||||
@ -298,14 +297,14 @@ class NorthboundImpl
|
|||||||
void HandleCreateCandidate(RpcState<frr::CreateCandidateRequest,
|
void HandleCreateCandidate(RpcState<frr::CreateCandidateRequest,
|
||||||
frr::CreateCandidateResponse> *tag)
|
frr::CreateCandidateResponse> *tag)
|
||||||
{
|
{
|
||||||
if (nb_dbg_client_grpc)
|
|
||||||
zlog_debug("received RPC CreateCandidate()");
|
|
||||||
|
|
||||||
switch (tag->state) {
|
switch (tag->state) {
|
||||||
case CREATE:
|
case CREATE:
|
||||||
REQUEST_RPC(CreateCandidate);
|
REQUEST_RPC(CreateCandidate);
|
||||||
tag->state = PROCESS;
|
tag->state = PROCESS;
|
||||||
case PROCESS: {
|
case PROCESS: {
|
||||||
|
if (nb_dbg_client_grpc)
|
||||||
|
zlog_debug("received RPC CreateCandidate()");
|
||||||
|
|
||||||
struct candidate *candidate = create_candidate();
|
struct candidate *candidate = create_candidate();
|
||||||
if (!candidate) {
|
if (!candidate) {
|
||||||
tag->responder.Finish(
|
tag->responder.Finish(
|
||||||
@ -672,15 +671,22 @@ class NorthboundImpl
|
|||||||
|
|
||||||
|
|
||||||
// Execute the user request.
|
// Execute the user request.
|
||||||
|
struct nb_context context = {};
|
||||||
|
context.client = NB_CLIENT_GRPC;
|
||||||
|
char errmsg[BUFSIZ] = {0};
|
||||||
|
|
||||||
switch (phase) {
|
switch (phase) {
|
||||||
case frr::CommitRequest::VALIDATE:
|
case frr::CommitRequest::VALIDATE:
|
||||||
ret = nb_candidate_validate(candidate->config);
|
ret = nb_candidate_validate(
|
||||||
|
&context, candidate->config, errmsg,
|
||||||
|
sizeof(errmsg));
|
||||||
break;
|
break;
|
||||||
case frr::CommitRequest::PREPARE:
|
case frr::CommitRequest::PREPARE:
|
||||||
ret = nb_candidate_commit_prepare(
|
ret = nb_candidate_commit_prepare(
|
||||||
candidate->config, NB_CLIENT_GRPC, NULL,
|
&context, candidate->config,
|
||||||
comment.c_str(),
|
comment.c_str(),
|
||||||
&candidate->transaction);
|
&candidate->transaction, errmsg,
|
||||||
|
sizeof(errmsg));
|
||||||
break;
|
break;
|
||||||
case frr::CommitRequest::ABORT:
|
case frr::CommitRequest::ABORT:
|
||||||
nb_candidate_commit_abort(
|
nb_candidate_commit_abort(
|
||||||
@ -693,71 +699,51 @@ class NorthboundImpl
|
|||||||
break;
|
break;
|
||||||
case frr::CommitRequest::ALL:
|
case frr::CommitRequest::ALL:
|
||||||
ret = nb_candidate_commit(
|
ret = nb_candidate_commit(
|
||||||
candidate->config, NB_CLIENT_GRPC, NULL,
|
&context, candidate->config, true,
|
||||||
true, comment.c_str(), &transaction_id);
|
comment.c_str(), &transaction_id,
|
||||||
|
errmsg, sizeof(errmsg));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Map northbound error codes to gRPC error codes.
|
// Map northbound error codes to gRPC status codes.
|
||||||
|
grpc::Status status;
|
||||||
switch (ret) {
|
switch (ret) {
|
||||||
|
case NB_OK:
|
||||||
|
status = grpc::Status::OK;
|
||||||
|
break;
|
||||||
case NB_ERR_NO_CHANGES:
|
case NB_ERR_NO_CHANGES:
|
||||||
tag->responder.Finish(
|
status = grpc::Status(grpc::StatusCode::ABORTED,
|
||||||
tag->response,
|
errmsg);
|
||||||
grpc::Status(
|
break;
|
||||||
grpc::StatusCode::ABORTED,
|
|
||||||
"No configuration changes detected"),
|
|
||||||
tag);
|
|
||||||
tag->state = FINISH;
|
|
||||||
return;
|
|
||||||
case NB_ERR_LOCKED:
|
case NB_ERR_LOCKED:
|
||||||
tag->responder.Finish(
|
status = grpc::Status(
|
||||||
tag->response,
|
grpc::StatusCode::UNAVAILABLE, errmsg);
|
||||||
grpc::Status(
|
break;
|
||||||
grpc::StatusCode::UNAVAILABLE,
|
|
||||||
"There's already a transaction in progress"),
|
|
||||||
tag);
|
|
||||||
tag->state = FINISH;
|
|
||||||
return;
|
|
||||||
case NB_ERR_VALIDATION:
|
case NB_ERR_VALIDATION:
|
||||||
tag->responder.Finish(
|
status = grpc::Status(
|
||||||
tag->response,
|
grpc::StatusCode::INVALID_ARGUMENT,
|
||||||
grpc::Status(grpc::StatusCode::
|
errmsg);
|
||||||
INVALID_ARGUMENT,
|
break;
|
||||||
"Validation error"),
|
|
||||||
tag);
|
|
||||||
tag->state = FINISH;
|
|
||||||
return;
|
|
||||||
case NB_ERR_RESOURCE:
|
case NB_ERR_RESOURCE:
|
||||||
tag->responder.Finish(
|
status = grpc::Status(
|
||||||
tag->response,
|
grpc::StatusCode::RESOURCE_EXHAUSTED,
|
||||||
grpc::Status(
|
errmsg);
|
||||||
grpc::StatusCode::
|
break;
|
||||||
RESOURCE_EXHAUSTED,
|
|
||||||
"Failed do allocate resources"),
|
|
||||||
tag);
|
|
||||||
tag->state = FINISH;
|
|
||||||
return;
|
|
||||||
case NB_ERR:
|
case NB_ERR:
|
||||||
tag->responder.Finish(
|
|
||||||
tag->response,
|
|
||||||
grpc::Status(grpc::StatusCode::INTERNAL,
|
|
||||||
"Internal error"),
|
|
||||||
tag);
|
|
||||||
tag->state = FINISH;
|
|
||||||
return;
|
|
||||||
default:
|
default:
|
||||||
|
status = grpc::Status(
|
||||||
|
grpc::StatusCode::INTERNAL, errmsg);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (ret == NB_OK) {
|
||||||
// Response: uint32 transaction_id = 1;
|
// Response: uint32 transaction_id = 1;
|
||||||
if (transaction_id)
|
if (transaction_id)
|
||||||
tag->response.set_transaction_id(
|
tag->response.set_transaction_id(
|
||||||
transaction_id);
|
transaction_id);
|
||||||
|
}
|
||||||
|
|
||||||
tag->responder.Finish(tag->response, grpc::Status::OK,
|
tag->responder.Finish(tag->response, status, tag);
|
||||||
tag);
|
|
||||||
tag->state = FINISH;
|
tag->state = FINISH;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case FINISH:
|
case FINISH:
|
||||||
@ -769,9 +755,6 @@ class NorthboundImpl
|
|||||||
HandleListTransactions(RpcState<frr::ListTransactionsRequest,
|
HandleListTransactions(RpcState<frr::ListTransactionsRequest,
|
||||||
frr::ListTransactionsResponse> *tag)
|
frr::ListTransactionsResponse> *tag)
|
||||||
{
|
{
|
||||||
if (nb_dbg_client_grpc)
|
|
||||||
zlog_debug("received RPC ListTransactions()");
|
|
||||||
|
|
||||||
switch (tag->state) {
|
switch (tag->state) {
|
||||||
case CREATE:
|
case CREATE:
|
||||||
REQUEST_RPC_STREAMING(ListTransactions);
|
REQUEST_RPC_STREAMING(ListTransactions);
|
||||||
@ -781,6 +764,9 @@ class NorthboundImpl
|
|||||||
tag->context);
|
tag->context);
|
||||||
tag->state = PROCESS;
|
tag->state = PROCESS;
|
||||||
case PROCESS: {
|
case PROCESS: {
|
||||||
|
if (nb_dbg_client_grpc)
|
||||||
|
zlog_debug("received RPC ListTransactions()");
|
||||||
|
|
||||||
auto list = static_cast<std::list<std::tuple<
|
auto list = static_cast<std::list<std::tuple<
|
||||||
int, std::string, std::string, std::string>> *>(
|
int, std::string, std::string, std::string>> *>(
|
||||||
tag->context);
|
tag->context);
|
||||||
@ -889,14 +875,14 @@ class NorthboundImpl
|
|||||||
void HandleLockConfig(
|
void HandleLockConfig(
|
||||||
RpcState<frr::LockConfigRequest, frr::LockConfigResponse> *tag)
|
RpcState<frr::LockConfigRequest, frr::LockConfigResponse> *tag)
|
||||||
{
|
{
|
||||||
if (nb_dbg_client_grpc)
|
|
||||||
zlog_debug("received RPC LockConfig()");
|
|
||||||
|
|
||||||
switch (tag->state) {
|
switch (tag->state) {
|
||||||
case CREATE:
|
case CREATE:
|
||||||
REQUEST_RPC(LockConfig);
|
REQUEST_RPC(LockConfig);
|
||||||
tag->state = PROCESS;
|
tag->state = PROCESS;
|
||||||
case PROCESS: {
|
case PROCESS: {
|
||||||
|
if (nb_dbg_client_grpc)
|
||||||
|
zlog_debug("received RPC LockConfig()");
|
||||||
|
|
||||||
if (nb_running_lock(NB_CLIENT_GRPC, NULL)) {
|
if (nb_running_lock(NB_CLIENT_GRPC, NULL)) {
|
||||||
tag->responder.Finish(
|
tag->responder.Finish(
|
||||||
tag->response,
|
tag->response,
|
||||||
@ -922,14 +908,14 @@ class NorthboundImpl
|
|||||||
void HandleUnlockConfig(RpcState<frr::UnlockConfigRequest,
|
void HandleUnlockConfig(RpcState<frr::UnlockConfigRequest,
|
||||||
frr::UnlockConfigResponse> *tag)
|
frr::UnlockConfigResponse> *tag)
|
||||||
{
|
{
|
||||||
if (nb_dbg_client_grpc)
|
|
||||||
zlog_debug("received RPC UnlockConfig()");
|
|
||||||
|
|
||||||
switch (tag->state) {
|
switch (tag->state) {
|
||||||
case CREATE:
|
case CREATE:
|
||||||
REQUEST_RPC(UnlockConfig);
|
REQUEST_RPC(UnlockConfig);
|
||||||
tag->state = PROCESS;
|
tag->state = PROCESS;
|
||||||
case PROCESS: {
|
case PROCESS: {
|
||||||
|
if (nb_dbg_client_grpc)
|
||||||
|
zlog_debug("received RPC UnlockConfig()");
|
||||||
|
|
||||||
if (nb_running_unlock(NB_CLIENT_GRPC, NULL)) {
|
if (nb_running_unlock(NB_CLIENT_GRPC, NULL)) {
|
||||||
tag->responder.Finish(
|
tag->responder.Finish(
|
||||||
tag->response,
|
tag->response,
|
||||||
|
@ -245,7 +245,9 @@ static int frr_sr_config_change_cb_verify(sr_session_ctx_t *session,
|
|||||||
sr_change_oper_t sr_op;
|
sr_change_oper_t sr_op;
|
||||||
sr_val_t *sr_old_val, *sr_new_val;
|
sr_val_t *sr_old_val, *sr_new_val;
|
||||||
char xpath[XPATH_MAXLEN];
|
char xpath[XPATH_MAXLEN];
|
||||||
|
struct nb_context context = {};
|
||||||
struct nb_config *candidate;
|
struct nb_config *candidate;
|
||||||
|
char errmsg[BUFSIZ] = {0};
|
||||||
|
|
||||||
snprintf(xpath, sizeof(xpath), "/%s:*", module_name);
|
snprintf(xpath, sizeof(xpath), "/%s:*", module_name);
|
||||||
ret = sr_get_changes_iter(session, xpath, &it);
|
ret = sr_get_changes_iter(session, xpath, &it);
|
||||||
@ -276,21 +278,33 @@ static int frr_sr_config_change_cb_verify(sr_session_ctx_t *session,
|
|||||||
}
|
}
|
||||||
|
|
||||||
transaction = NULL;
|
transaction = NULL;
|
||||||
|
context.client = NB_CLIENT_SYSREPO;
|
||||||
if (startup_config) {
|
if (startup_config) {
|
||||||
/*
|
/*
|
||||||
* sysrepod sends the entire startup configuration using a
|
* sysrepod sends the entire startup configuration using a
|
||||||
* single event (SR_EV_ENABLED). This means we need to perform
|
* single event (SR_EV_ENABLED). This means we need to perform
|
||||||
* the full two-phase commit protocol in one go here.
|
* the full two-phase commit protocol in one go here.
|
||||||
*/
|
*/
|
||||||
ret = nb_candidate_commit(candidate, NB_CLIENT_SYSREPO, NULL,
|
ret = nb_candidate_commit(&context, candidate, true, NULL, NULL,
|
||||||
true, NULL, NULL);
|
errmsg, sizeof(errmsg));
|
||||||
|
if (ret != NB_OK && ret != NB_ERR_NO_CHANGES)
|
||||||
|
flog_warn(
|
||||||
|
EC_LIB_LIBSYSREPO,
|
||||||
|
"%s: failed to apply startup configuration: %s (%s)",
|
||||||
|
__func__, nb_err_name(ret), errmsg);
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
* Validate the configuration changes and allocate all resources
|
* Validate the configuration changes and allocate all resources
|
||||||
* required to apply them.
|
* required to apply them.
|
||||||
*/
|
*/
|
||||||
ret = nb_candidate_commit_prepare(candidate, NB_CLIENT_SYSREPO,
|
ret = nb_candidate_commit_prepare(&context, candidate, NULL,
|
||||||
NULL, NULL, &transaction);
|
&transaction, errmsg,
|
||||||
|
sizeof(errmsg));
|
||||||
|
if (ret != NB_OK && ret != NB_ERR_NO_CHANGES)
|
||||||
|
flog_warn(
|
||||||
|
EC_LIB_LIBSYSREPO,
|
||||||
|
"%s: failed to prepare configuration transaction: %s (%s)",
|
||||||
|
__func__, nb_err_name(ret), errmsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Map northbound return code to sysrepo return code. */
|
/* Map northbound return code to sysrepo return code. */
|
||||||
|
@ -1082,8 +1082,8 @@ static int lib_vrf_destroy(struct nb_cb_destroy_args *args)
|
|||||||
case NB_EV_VALIDATE:
|
case NB_EV_VALIDATE:
|
||||||
vrfp = nb_running_get_entry(args->dnode, NULL, true);
|
vrfp = nb_running_get_entry(args->dnode, NULL, true);
|
||||||
if (CHECK_FLAG(vrfp->status, VRF_ACTIVE)) {
|
if (CHECK_FLAG(vrfp->status, VRF_ACTIVE)) {
|
||||||
zlog_debug("%s Only inactive VRFs can be deleted",
|
snprintf(args->errmsg, args->errmsg_len,
|
||||||
__func__);
|
"Only inactive VRFs can be deleted");
|
||||||
return NB_ERR_VALIDATION;
|
return NB_ERR_VALIDATION;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
16
lib/vty.c
16
lib/vty.c
@ -2349,12 +2349,18 @@ static void vty_read_file(struct nb_config *config, FILE *confp)
|
|||||||
* reading the configuration file.
|
* reading the configuration file.
|
||||||
*/
|
*/
|
||||||
if (config == NULL) {
|
if (config == NULL) {
|
||||||
ret = nb_candidate_commit(vty->candidate_config, NB_CLIENT_CLI,
|
struct nb_context context = {};
|
||||||
vty, true, "Read configuration file",
|
char errmsg[BUFSIZ] = {0};
|
||||||
NULL);
|
|
||||||
|
context.client = NB_CLIENT_CLI;
|
||||||
|
context.user = vty;
|
||||||
|
ret = nb_candidate_commit(&context, vty->candidate_config, true,
|
||||||
|
"Read configuration file", NULL,
|
||||||
|
errmsg, sizeof(errmsg));
|
||||||
if (ret != NB_OK && ret != NB_ERR_NO_CHANGES)
|
if (ret != NB_OK && ret != NB_ERR_NO_CHANGES)
|
||||||
zlog_err("%s: failed to read configuration file.",
|
zlog_err(
|
||||||
__func__);
|
"%s: failed to read configuration file: %s (%s)",
|
||||||
|
__func__, nb_err_name(ret), errmsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
vty_close(vty);
|
vty_close(vty);
|
||||||
|
@ -43,7 +43,7 @@ extern "C" {
|
|||||||
#define VTY_MAXHIST 20
|
#define VTY_MAXHIST 20
|
||||||
#define VTY_MAXDEPTH 8
|
#define VTY_MAXDEPTH 8
|
||||||
|
|
||||||
#define VTY_MAXCFGCHANGES 8
|
#define VTY_MAXCFGCHANGES 16
|
||||||
|
|
||||||
struct vty_error {
|
struct vty_error {
|
||||||
char error_buf[VTY_BUFSIZ];
|
char error_buf[VTY_BUFSIZ];
|
||||||
|
28
lib/yang.c
28
lib/yang.c
@ -647,6 +647,34 @@ static void ly_log_cb(LY_LOG_LEVEL level, const char *msg, const char *path)
|
|||||||
zlog(priority, "libyang: %s", msg);
|
zlog(priority, "libyang: %s", msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *yang_print_errors(struct ly_ctx *ly_ctx, char *buf, size_t buf_len)
|
||||||
|
{
|
||||||
|
struct ly_err_item *ei;
|
||||||
|
const char *path;
|
||||||
|
|
||||||
|
ei = ly_err_first(ly_ctx);
|
||||||
|
if (!ei)
|
||||||
|
return "";
|
||||||
|
|
||||||
|
strlcpy(buf, "YANG error(s):\n", buf_len);
|
||||||
|
for (; ei; ei = ei->next) {
|
||||||
|
strlcat(buf, " ", buf_len);
|
||||||
|
strlcat(buf, ei->msg, buf_len);
|
||||||
|
strlcat(buf, "\n", buf_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
path = ly_errpath(ly_ctx);
|
||||||
|
if (path) {
|
||||||
|
strlcat(buf, " YANG path: ", buf_len);
|
||||||
|
strlcat(buf, path, buf_len);
|
||||||
|
strlcat(buf, "\n", buf_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
ly_err_clean(ly_ctx, NULL);
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
void yang_debugging_set(bool enable)
|
void yang_debugging_set(bool enable)
|
||||||
{
|
{
|
||||||
if (enable) {
|
if (enable) {
|
||||||
|
18
lib/yang.h
18
lib/yang.h
@ -518,6 +518,24 @@ extern struct ly_ctx *yang_ctx_new_setup(bool embedded_modules);
|
|||||||
*/
|
*/
|
||||||
extern void yang_debugging_set(bool enable);
|
extern void yang_debugging_set(bool enable);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Print libyang error messages into the provided buffer.
|
||||||
|
*
|
||||||
|
* ly_ctx
|
||||||
|
* libyang context to operate on.
|
||||||
|
*
|
||||||
|
* buf
|
||||||
|
* Buffer to store the libyang error messages.
|
||||||
|
*
|
||||||
|
* buf_len
|
||||||
|
* Size of buf.
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* The provided buffer.
|
||||||
|
*/
|
||||||
|
extern const char *yang_print_errors(struct ly_ctx *ly_ctx, char *buf,
|
||||||
|
size_t buf_len);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize the YANG subsystem. Should be called only once during the
|
* Initialize the YANG subsystem. Should be called only once during the
|
||||||
* daemon initialization process.
|
* daemon initialization process.
|
||||||
|
@ -941,12 +941,14 @@ int lib_interface_zebra_ip_addrs_create(struct nb_cb_create_args *args)
|
|||||||
case NB_EV_VALIDATE:
|
case NB_EV_VALIDATE:
|
||||||
if (prefix.family == AF_INET
|
if (prefix.family == AF_INET
|
||||||
&& ipv4_martian(&prefix.u.prefix4)) {
|
&& ipv4_martian(&prefix.u.prefix4)) {
|
||||||
zlog_debug("invalid address %s",
|
snprintf(args->errmsg, args->errmsg_len,
|
||||||
|
"invalid address %s",
|
||||||
prefix2str(&prefix, buf, sizeof(buf)));
|
prefix2str(&prefix, buf, sizeof(buf)));
|
||||||
return NB_ERR_VALIDATION;
|
return NB_ERR_VALIDATION;
|
||||||
} else if (prefix.family == AF_INET6
|
} else if (prefix.family == AF_INET6
|
||||||
&& ipv6_martian(&prefix.u.prefix6)) {
|
&& ipv6_martian(&prefix.u.prefix6)) {
|
||||||
zlog_debug("invalid address %s",
|
snprintf(args->errmsg, args->errmsg_len,
|
||||||
|
"invalid address %s",
|
||||||
prefix2str(&prefix, buf, sizeof(buf)));
|
prefix2str(&prefix, buf, sizeof(buf)));
|
||||||
return NB_ERR_VALIDATION;
|
return NB_ERR_VALIDATION;
|
||||||
}
|
}
|
||||||
@ -982,7 +984,8 @@ int lib_interface_zebra_ip_addrs_destroy(struct nb_cb_destroy_args *args)
|
|||||||
/* Check current interface address. */
|
/* Check current interface address. */
|
||||||
ifc = connected_check_ptp(ifp, &prefix, NULL);
|
ifc = connected_check_ptp(ifp, &prefix, NULL);
|
||||||
if (!ifc) {
|
if (!ifc) {
|
||||||
zlog_debug("interface %s Can't find address\n",
|
snprintf(args->errmsg, args->errmsg_len,
|
||||||
|
"interface %s Can't find address\n",
|
||||||
ifp->name);
|
ifp->name);
|
||||||
return NB_ERR_VALIDATION;
|
return NB_ERR_VALIDATION;
|
||||||
}
|
}
|
||||||
@ -990,7 +993,8 @@ int lib_interface_zebra_ip_addrs_destroy(struct nb_cb_destroy_args *args)
|
|||||||
/* Check current interface address. */
|
/* Check current interface address. */
|
||||||
ifc = connected_check(ifp, &prefix);
|
ifc = connected_check(ifp, &prefix);
|
||||||
if (!ifc) {
|
if (!ifc) {
|
||||||
zlog_debug("interface can't find address %s",
|
snprintf(args->errmsg, args->errmsg_len,
|
||||||
|
"interface can't find address %s",
|
||||||
ifp->name);
|
ifp->name);
|
||||||
return NB_ERR_VALIDATION;
|
return NB_ERR_VALIDATION;
|
||||||
}
|
}
|
||||||
@ -999,7 +1003,8 @@ int lib_interface_zebra_ip_addrs_destroy(struct nb_cb_destroy_args *args)
|
|||||||
|
|
||||||
/* This is not configured address. */
|
/* This is not configured address. */
|
||||||
if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_CONFIGURED)) {
|
if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_CONFIGURED)) {
|
||||||
zlog_debug("interface %s not configured", ifp->name);
|
snprintf(args->errmsg, args->errmsg_len,
|
||||||
|
"interface %s not configured", ifp->name);
|
||||||
return NB_ERR_VALIDATION;
|
return NB_ERR_VALIDATION;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1244,8 +1249,8 @@ int lib_vrf_zebra_ribs_rib_create(struct nb_cb_create_args *args)
|
|||||||
switch (args->event) {
|
switch (args->event) {
|
||||||
case NB_EV_VALIDATE:
|
case NB_EV_VALIDATE:
|
||||||
if (!zrt) {
|
if (!zrt) {
|
||||||
zlog_debug("%s: vrf %s table is not found.", __func__,
|
snprintf(args->errmsg, args->errmsg_len,
|
||||||
vrf->name);
|
"vrf %s table is not found.", vrf->name);
|
||||||
return NB_ERR_VALIDATION;
|
return NB_ERR_VALIDATION;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -1376,7 +1381,8 @@ int lib_route_map_entry_match_condition_source_protocol_modify(
|
|||||||
case NB_EV_VALIDATE:
|
case NB_EV_VALIDATE:
|
||||||
type = yang_dnode_get_string(args->dnode, NULL);
|
type = yang_dnode_get_string(args->dnode, NULL);
|
||||||
if (proto_name2num(type) == -1) {
|
if (proto_name2num(type) == -1) {
|
||||||
zlog_warn("%s: invalid protocol: %s", __func__, type);
|
snprintf(args->errmsg, args->errmsg_len,
|
||||||
|
"invalid protocol: %s", type);
|
||||||
return NB_ERR_VALIDATION;
|
return NB_ERR_VALIDATION;
|
||||||
}
|
}
|
||||||
return NB_OK;
|
return NB_OK;
|
||||||
@ -1470,7 +1476,8 @@ int lib_route_map_entry_set_action_source_v4_modify(
|
|||||||
memset(&p, 0, sizeof(p));
|
memset(&p, 0, sizeof(p));
|
||||||
yang_dnode_get_ipv4p(&p, args->dnode, NULL);
|
yang_dnode_get_ipv4p(&p, args->dnode, NULL);
|
||||||
if (zebra_check_addr(&p) == 0) {
|
if (zebra_check_addr(&p) == 0) {
|
||||||
zlog_warn("%s: invalid IPv4 address: %s", __func__,
|
snprintf(args->errmsg, args->errmsg_len,
|
||||||
|
"invalid IPv4 address: %s",
|
||||||
yang_dnode_get_string(args->dnode, NULL));
|
yang_dnode_get_string(args->dnode, NULL));
|
||||||
return NB_ERR_VALIDATION;
|
return NB_ERR_VALIDATION;
|
||||||
}
|
}
|
||||||
@ -1482,7 +1489,8 @@ int lib_route_map_entry_set_action_source_v4_modify(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (pif == NULL) {
|
if (pif == NULL) {
|
||||||
zlog_warn("%s: is not a local adddress: %s", __func__,
|
snprintf(args->errmsg, args->errmsg_len,
|
||||||
|
"is not a local adddress: %s",
|
||||||
yang_dnode_get_string(args->dnode, NULL));
|
yang_dnode_get_string(args->dnode, NULL));
|
||||||
return NB_ERR_VALIDATION;
|
return NB_ERR_VALIDATION;
|
||||||
}
|
}
|
||||||
@ -1536,7 +1544,8 @@ int lib_route_map_entry_set_action_source_v6_modify(
|
|||||||
memset(&p, 0, sizeof(p));
|
memset(&p, 0, sizeof(p));
|
||||||
yang_dnode_get_ipv6p(&p, args->dnode, NULL);
|
yang_dnode_get_ipv6p(&p, args->dnode, NULL);
|
||||||
if (zebra_check_addr(&p) == 0) {
|
if (zebra_check_addr(&p) == 0) {
|
||||||
zlog_warn("%s: invalid IPv6 address: %s", __func__,
|
snprintf(args->errmsg, args->errmsg_len,
|
||||||
|
"invalid IPv6 address: %s",
|
||||||
yang_dnode_get_string(args->dnode, NULL));
|
yang_dnode_get_string(args->dnode, NULL));
|
||||||
return NB_ERR_VALIDATION;
|
return NB_ERR_VALIDATION;
|
||||||
}
|
}
|
||||||
@ -1548,7 +1557,8 @@ int lib_route_map_entry_set_action_source_v6_modify(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (pif == NULL) {
|
if (pif == NULL) {
|
||||||
zlog_warn("%s: is not a local adddress: %s", __func__,
|
snprintf(args->errmsg, args->errmsg_len,
|
||||||
|
"is not a local adddress: %s",
|
||||||
yang_dnode_get_string(args->dnode, NULL));
|
yang_dnode_get_string(args->dnode, NULL));
|
||||||
return NB_ERR_VALIDATION;
|
return NB_ERR_VALIDATION;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user