frr/staticd/static_nb_config.c
Carmine Scarpitta 6037ea350c staticd: Fix crash that occurs when modifying an SRv6 SID
When the user modifies an SRv6 SID and then removes all SIDs, staticd
crashes:

```
2025/03/23 08:37:22.691860 STATIC: lib/memory.c:74: mt_count_free(): assertion (mt->n_alloc) failed
STATIC: Received signal 6 at 1742715442 (si_addr 0x8200007cf0); aborting...
STATIC: zlog_signal+0x390                  fcc704a844b8     ffffd7450390 /usr/lib/frr/libfrr.so.0 (mapped at 0xfcc704800000)
STATIC: core_handler+0x1f8                 fcc704b79990     ffffd7450590 /usr/lib/frr/libfrr.so.0 (mapped at 0xfcc704800000)
STATIC:     ---- signal ----
STATIC: ?                                  fcc705c008f8     ffffd74507a0 linux-vdso.so.1 (mapped at 0xfcc705c00000)
STATIC: pthread_key_delete+0x1a0           fcc70458f1f0     ffffd7451a00 /lib/aarch64-linux-gnu/libc.so.6 (mapped at 0xfcc704510000)
STATIC: raise+0x1c                         fcc70454a67c     ffffd7451ad0 /lib/aarch64-linux-gnu/libc.so.6 (mapped at 0xfcc704510000)
STATIC: abort+0xe4                         fcc704537130     ffffd7451af0 /lib/aarch64-linux-gnu/libc.so.6 (mapped at 0xfcc704510000)
STATIC: _zlog_assert_failed+0x3c4          fcc704c407c8     ffffd7451c40 /usr/lib/frr/libfrr.so.0 (mapped at 0xfcc704800000)
STATIC: mt_count_free+0x12c                fcc704a93c74     ffffd7451dc0 /usr/lib/frr/libfrr.so.0 (mapped at 0xfcc704800000)
STATIC: qfree+0x28                         fcc704a93fa0     ffffd7451e70 /usr/lib/frr/libfrr.so.0 (mapped at 0xfcc704800000)
STATIC: static_srv6_sid_free+0x1c          adc1df8fa544     ffffd7451e90 /usr/lib/frr/staticd (mapped at 0xadc1df8a0000)
STATIC: delete_static_srv6_sid+0x14        adc1df8faafc     ffffd7451eb0 /usr/lib/frr/staticd (mapped at 0xadc1df8a0000)
STATIC: list_delete_all_node+0x104         fcc704a60eec     ffffd7451ed0 /usr/lib/frr/libfrr.so.0 (mapped at 0xfcc704800000)
STATIC: list_delete+0x8c                   fcc704a61054     ffffd7451f00 /usr/lib/frr/libfrr.so.0 (mapped at 0xfcc704800000)
STATIC: static_srv6_cleanup+0x20           adc1df8fabdc     ffffd7451f20 /usr/lib/frr/staticd (mapped at 0xadc1df8a0000)
STATIC: sigint+0x40                        adc1df8be544     ffffd7451f30 /usr/lib/frr/staticd (mapped at 0xadc1df8a0000)
STATIC: frr_sigevent_process+0x148         fcc704b79460     ffffd7451f40 /usr/lib/frr/libfrr.so.0 (mapped at 0xfcc704800000)
STATIC: event_fetch+0x1c4                  fcc704bc0834     ffffd7451f60 /usr/lib/frr/libfrr.so.0 (mapped at 0xfcc704800000)
STATIC: frr_run+0x650                      fcc704a5d230     ffffd7452080 /usr/lib/frr/libfrr.so.0 (mapped at 0xfcc704800000)
STATIC: main+0x1d0                         adc1df8be75c     ffffd7452270 /usr/lib/frr/staticd (mapped at 0xadc1df8a0000)
STATIC: __libc_init_first+0x7c             fcc7045373fc     ffffd74522b0 /lib/aarch64-linux-gnu/libc.so.6 (mapped at 0xfcc704510000)
STATIC: __libc_start_main+0x98             fcc7045374cc     ffffd74523c0 /lib/aarch64-linux-gnu/libc.so.6 (mapped at 0xfcc704510000)
STATIC: _start+0x30                        adc1df8be0f0     ffffd7452420 /usr/lib/frr/staticd (mapped at 0xadc1df8a0000)
```

Tracking this down, the crash occurs because every time we modify a
SID, staticd executes some callbacks to modify the SID and finally it
calls `apply_finish`, which re-adds the SID to the list `srv6_sids`.

This leads to having the same SID multiple times in the `srv6_sids`
list. When we delete all SIDs, staticd attempts to deallocate the same
SID multiple times, which leads to the crash.

This commit fixes the issue by moving the code that adds the SID to the
list from the `apply_finish` callback to the `create` callback.
This ensures that the SID is inserted into the list only once, when it
is created. For all subsequent modifications, the SID is modified but
not added to the list.

Signed-off-by: Carmine Scarpitta <cscarpit@cisco.com>
2025-03-23 18:46:45 +01:00

1374 lines
36 KiB
C

// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2018 Vmware
* Vishal Dhingra
*/
#include <zebra.h>
#include "northbound.h"
#include "libfrr.h"
#include "log.h"
#include "lib_errors.h"
#include "prefix.h"
#include "table.h"
#include "vrf.h"
#include "nexthop.h"
#include "srcdest_table.h"
#include "static_vrf.h"
#include "static_routes.h"
#include "static_nb.h"
#include "static_zebra.h"
#include "static_srv6.h"
#include "static_debug.h"
static int static_path_list_create(struct nb_cb_create_args *args)
{
struct route_node *rn;
struct static_path *pn;
const struct lyd_node *vrf_dnode;
const char *vrf;
uint8_t distance;
uint32_t table_id;
switch (args->event) {
case NB_EV_VALIDATE:
vrf_dnode = yang_dnode_get_parent(args->dnode,
"control-plane-protocol");
vrf = yang_dnode_get_string(vrf_dnode, "vrf");
table_id = yang_dnode_get_uint32(args->dnode, "table-id");
/*
* TableId is not applicable for VRF. Consider the case of
* l3mdev, there is one uint32_t space to work with.
* A l3mdev device points at a specific table that it
* relates to and a set of interfaces it belongs to.
*/
if (table_id && (strcmp(vrf, vrf_get_default_name()) != 0)
&& !vrf_is_backend_netns()) {
snprintf(
args->errmsg, args->errmsg_len,
"%% table param only available when running on netns-based vrfs");
return NB_ERR_VALIDATION;
}
break;
case NB_EV_ABORT:
case NB_EV_PREPARE:
break;
case NB_EV_APPLY:
rn = nb_running_get_entry(args->dnode, NULL, true);
distance = yang_dnode_get_uint8(args->dnode, "distance");
table_id = yang_dnode_get_uint32(args->dnode, "table-id");
pn = static_add_path(rn, table_id, distance);
nb_running_set_entry(args->dnode, pn);
}
return NB_OK;
}
static int static_path_list_destroy(struct nb_cb_destroy_args *args)
{
struct static_path *pn;
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
break;
case NB_EV_APPLY:
pn = nb_running_unset_entry(args->dnode);
static_del_path(pn);
break;
}
return NB_OK;
}
static int static_path_list_tag_modify(struct nb_cb_modify_args *args)
{
struct static_path *pn;
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_ABORT:
case NB_EV_PREPARE:
break;
case NB_EV_APPLY:
pn = nb_running_get_entry(args->dnode, NULL, true);
pn->tag = yang_dnode_get_uint32(args->dnode, NULL);
static_install_path(pn);
break;
}
return NB_OK;
}
struct nexthop_iter {
uint32_t count;
bool blackhole;
};
static int nexthop_iter_cb(const struct lyd_node *dnode, void *arg)
{
struct nexthop_iter *iter = arg;
enum static_nh_type nh_type;
nh_type = yang_dnode_get_enum(dnode, "nh-type");
if (nh_type == STATIC_BLACKHOLE)
iter->blackhole = true;
iter->count++;
return YANG_ITER_CONTINUE;
}
static bool static_nexthop_create(struct nb_cb_create_args *args)
{
const struct lyd_node *pn_dnode;
struct nexthop_iter iter;
struct static_path *pn;
struct ipaddr ipaddr;
struct static_nexthop *nh;
enum static_nh_type nh_type;
const char *ifname;
const char *nh_vrf;
switch (args->event) {
case NB_EV_VALIDATE:
ifname = yang_dnode_get_string(args->dnode, "interface");
if (ifname != NULL) {
if (strcasecmp(ifname, "Null0") == 0
|| strcasecmp(ifname, "reject") == 0
|| strcasecmp(ifname, "blackhole") == 0) {
snprintf(args->errmsg, args->errmsg_len,
"%s: Nexthop interface name can not be from reserved keywords(Null0, reject, blackhole)",
ifname);
return NB_ERR_VALIDATION;
}
}
iter.count = 0;
iter.blackhole = false;
pn_dnode = yang_dnode_get_parent(args->dnode, "path-list");
yang_dnode_iterate(nexthop_iter_cb, &iter, pn_dnode,
"./frr-nexthops/nexthop");
if (iter.blackhole && iter.count > 1) {
snprintf(
args->errmsg, args->errmsg_len,
"Route cannot have blackhole and non-blackhole nexthops simultaneously");
return NB_ERR_VALIDATION;
} else if (iter.count > zebra_ecmp_count) {
snprintf(args->errmsg, args->errmsg_len,
"Route cannot have more than %d ECMP nexthops",
zebra_ecmp_count);
return NB_ERR_VALIDATION;
}
break;
case NB_EV_PREPARE:
case NB_EV_ABORT:
break;
case NB_EV_APPLY:
yang_dnode_get_ip(&ipaddr, args->dnode, "gateway");
nh_type = yang_dnode_get_enum(args->dnode, "nh-type");
ifname = yang_dnode_get_string(args->dnode, "interface");
nh_vrf = yang_dnode_get_string(args->dnode, "vrf");
pn = nb_running_get_entry(args->dnode, NULL, true);
if (strmatch(ifname, "(null)"))
ifname = "";
if (!static_add_nexthop_validate(nh_vrf, nh_type, &ipaddr))
flog_warn(
EC_LIB_NB_CB_CONFIG_VALIDATE,
"Warning!! Local connected address is configured as Gateway IP((%s))",
yang_dnode_get_string(args->dnode,
"./gateway"));
nh = static_add_nexthop(pn, nh_type, &ipaddr, ifname, nh_vrf,
0);
nb_running_set_entry(args->dnode, nh);
break;
}
return NB_OK;
}
static bool static_nexthop_destroy(struct nb_cb_destroy_args *args)
{
struct static_nexthop *nh;
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
break;
case NB_EV_APPLY:
nh = nb_running_unset_entry(args->dnode);
static_delete_nexthop(nh);
break;
}
return NB_OK;
}
static int nexthop_srv6_segs_stack_entry_create(struct nb_cb_create_args *args)
{
struct static_nexthop *nh;
uint32_t pos;
uint8_t index;
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
break;
case NB_EV_APPLY:
nh = nb_running_get_entry(args->dnode, NULL, true);
pos = yang_get_list_pos(args->dnode);
if (!pos) {
flog_warn(EC_LIB_NB_CB_CONFIG_APPLY,
"libyang returns invalid seg position");
return NB_ERR;
}
/* Mapping to array = list-index -1 */
index = pos - 1;
memset(&nh->snh_seg.seg[index], 0, sizeof(struct in6_addr));
nh->snh_seg.num_segs++;
break;
}
return NB_OK;
}
static int nexthop_srv6_segs_stack_entry_destroy(struct nb_cb_destroy_args *args)
{
struct static_nexthop *nh;
uint32_t pos;
uint8_t index;
int old_num_segs;
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
break;
case NB_EV_APPLY:
nh = nb_running_get_entry(args->dnode, NULL, true);
pos = yang_get_list_pos(args->dnode);
if (!pos) {
flog_warn(EC_LIB_NB_CB_CONFIG_APPLY,
"libyang returns invalid seg position");
return NB_ERR;
}
index = pos - 1;
old_num_segs = nh->snh_seg.num_segs;
memset(&nh->snh_seg.seg[index], 0, sizeof(struct in6_addr));
nh->snh_seg.num_segs--;
if (old_num_segs != nh->snh_seg.num_segs)
nh->state = STATIC_START;
break;
}
return NB_OK;
}
static int static_nexthop_srv6_segs_modify(struct nb_cb_modify_args *args)
{
struct static_nexthop *nh;
uint32_t pos;
uint8_t index;
struct in6_addr old_seg;
struct in6_addr cli_seg;
nh = nb_running_get_entry(args->dnode, NULL, true);
pos = yang_get_list_pos(lyd_parent(args->dnode));
if (!pos) {
flog_warn(EC_LIB_NB_CB_CONFIG_APPLY,
"libyang returns invalid seg position");
return NB_ERR;
}
/* Mapping to array = list-index -1 */
index = pos - 1;
old_seg = nh->snh_seg.seg[index];
yang_dnode_get_ipv6(&cli_seg, args->dnode, NULL);
memcpy(&nh->snh_seg.seg[index], &cli_seg, sizeof(struct in6_addr));
if (memcmp(&old_seg, &nh->snh_seg.seg[index],
sizeof(struct in6_addr)) != 0)
nh->state = STATIC_START;
return NB_OK;
}
static int nexthop_mpls_label_stack_entry_create(struct nb_cb_create_args *args)
{
struct static_nexthop *nh;
uint32_t pos;
uint8_t index;
switch (args->event) {
case NB_EV_VALIDATE:
if (!mpls_enabled) {
snprintf(
args->errmsg, args->errmsg_len,
"%% MPLS not turned on in kernel ignoring static route");
return NB_ERR_VALIDATION;
}
break;
case NB_EV_PREPARE:
case NB_EV_ABORT:
break;
case NB_EV_APPLY:
nh = nb_running_get_entry(args->dnode, NULL, true);
pos = yang_get_list_pos(args->dnode);
if (!pos) {
flog_warn(EC_LIB_NB_CB_CONFIG_APPLY,
"libyang returns invalid label position");
return NB_ERR;
}
/* Mapping to array = list-index -1 */
index = pos - 1;
nh->snh_label.label[index] = 0;
nh->snh_label.num_labels++;
break;
}
return NB_OK;
}
static int
nexthop_mpls_label_stack_entry_destroy(struct nb_cb_destroy_args *args)
{
struct static_nexthop *nh;
uint32_t pos;
uint8_t index;
uint old_num_labels;
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
break;
case NB_EV_APPLY:
nh = nb_running_get_entry(args->dnode, NULL, true);
pos = yang_get_list_pos(args->dnode);
if (!pos) {
flog_warn(EC_LIB_NB_CB_CONFIG_APPLY,
"libyang returns invalid label position");
return NB_ERR;
}
index = pos - 1;
old_num_labels = nh->snh_label.num_labels;
nh->snh_label.label[index] = 0;
nh->snh_label.num_labels--;
if (old_num_labels != nh->snh_label.num_labels)
nh->state = STATIC_START;
break;
}
return NB_OK;
}
static int static_nexthop_mpls_label_modify(struct nb_cb_modify_args *args)
{
struct static_nexthop *nh;
uint32_t pos;
uint8_t index;
mpls_label_t old_label;
nh = nb_running_get_entry(args->dnode, NULL, true);
pos = yang_get_list_pos(lyd_parent(args->dnode));
if (!pos) {
flog_warn(EC_LIB_NB_CB_CONFIG_APPLY,
"libyang returns invalid label position");
return NB_ERR;
}
/* Mapping to array = list-index -1 */
index = pos - 1;
old_label = nh->snh_label.label[index];
nh->snh_label.label[index] = yang_dnode_get_uint32(args->dnode, NULL);
if (old_label != nh->snh_label.label[index])
nh->state = STATIC_START;
return NB_OK;
}
static int static_nexthop_onlink_modify(struct nb_cb_modify_args *args)
{
struct static_nexthop *nh;
enum static_nh_type nh_type;
bool old_onlink;
switch (args->event) {
case NB_EV_VALIDATE:
nh_type = yang_dnode_get_enum(args->dnode, "../nh-type");
if ((nh_type != STATIC_IPV4_GATEWAY_IFNAME)
&& (nh_type != STATIC_IPV6_GATEWAY_IFNAME)) {
snprintf(
args->errmsg, args->errmsg_len,
"nexthop type is not the ipv4 or ipv6 interface type");
return NB_ERR_VALIDATION;
}
break;
case NB_EV_PREPARE:
case NB_EV_ABORT:
break;
case NB_EV_APPLY:
nh = nb_running_get_entry(args->dnode, NULL, true);
old_onlink = nh->onlink;
nh->onlink = yang_dnode_get_bool(args->dnode, NULL);
if (old_onlink != nh->onlink)
nh->state = STATIC_START;
break;
}
return NB_OK;
}
static int static_nexthop_color_modify(struct nb_cb_modify_args *args)
{
struct static_nexthop *nh;
uint32_t old_color;
nh = nb_running_get_entry(args->dnode, NULL, true);
old_color = nh->color;
nh->color = yang_dnode_get_uint32(args->dnode, NULL);
if (old_color != nh->color)
nh->state = STATIC_START;
return NB_OK;
}
static int static_nexthop_color_destroy(struct nb_cb_destroy_args *args)
{
struct static_nexthop *nh;
uint32_t old_color;
nh = nb_running_get_entry(args->dnode, NULL, true);
old_color = nh->color;
nh->color = 0;
if (old_color != nh->color)
nh->state = STATIC_START;
return NB_OK;
}
static int static_nexthop_bh_type_modify(struct nb_cb_modify_args *args)
{
struct static_nexthop *nh;
enum static_nh_type nh_type;
switch (args->event) {
case NB_EV_VALIDATE:
nh_type = yang_dnode_get_enum(args->dnode, "../nh-type");
if (nh_type != STATIC_BLACKHOLE) {
snprintf(args->errmsg, args->errmsg_len,
"nexthop type is not the blackhole type");
return NB_ERR_VALIDATION;
}
break;
case NB_EV_PREPARE:
case NB_EV_ABORT:
break;
case NB_EV_APPLY:
nh = nb_running_get_entry(args->dnode, NULL, true);
nh->bh_type = yang_dnode_get_enum(args->dnode, NULL);
break;
}
return NB_OK;
}
void routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_apply_finish(
struct nb_cb_apply_finish_args *args)
{
struct static_nexthop *nh;
nh = nb_running_get_entry(args->dnode, NULL, true);
static_install_nexthop(nh);
}
int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_pre_validate(
struct nb_cb_pre_validate_args *args)
{
const struct lyd_node *mls_dnode;
uint32_t count;
mls_dnode = yang_dnode_get(args->dnode, "mpls-label-stack");
count = yang_get_list_elements_count(lyd_child(mls_dnode));
if (count > MPLS_MAX_LABELS) {
snprintf(args->errmsg, args->errmsg_len,
"Too many labels, Enter %d or fewer",
MPLS_MAX_LABELS);
return NB_ERR_VALIDATION;
}
return NB_OK;
}
int routing_control_plane_protocols_name_validate(
struct nb_cb_create_args *args)
{
const char *name;
name = yang_dnode_get_string(args->dnode, "name");
if (!strmatch(name, "staticd")) {
snprintf(args->errmsg, args->errmsg_len,
"static routing supports only one instance with name staticd");
return NB_ERR_VALIDATION;
}
return NB_OK;
}
/*
* XPath:
* /frr-routing:routing/control-plane-protocols/control-plane-protocol
*/
int routing_control_plane_protocols_staticd_create(struct nb_cb_create_args *args)
{
struct static_vrf *svrf;
const char *vrf;
vrf = yang_dnode_get_string(args->dnode, "vrf");
svrf = static_vrf_alloc(vrf);
nb_running_set_entry(args->dnode, svrf);
return NB_OK;
}
int routing_control_plane_protocols_staticd_destroy(
struct nb_cb_destroy_args *args)
{
struct static_vrf *svrf;
struct route_table *stable;
struct route_node *rn;
afi_t afi;
safi_t safi;
svrf = nb_running_unset_entry(args->dnode);
FOREACH_AFI_SAFI (afi, safi) {
stable = svrf->stable[afi][safi];
if (!stable)
continue;
for (rn = route_top(stable); rn; rn = srcdest_route_next(rn))
static_del_route(rn);
}
static_vrf_free(svrf);
return NB_OK;
}
/*
* XPath:
* /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list
*/
int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_create(
struct nb_cb_create_args *args)
{
struct static_vrf *svrf;
struct route_node *rn;
const struct lyd_node *vrf_dnode;
struct prefix prefix, src_prefix, *src_p;
const char *afi_safi;
afi_t prefix_afi;
afi_t afi;
safi_t safi;
switch (args->event) {
case NB_EV_VALIDATE:
yang_dnode_get_prefix(&prefix, args->dnode, "prefix");
yang_dnode_get_prefix(&src_prefix, args->dnode, "src-prefix");
src_p = src_prefix.prefixlen ? &src_prefix : NULL;
afi_safi = yang_dnode_get_string(args->dnode, "afi-safi");
yang_afi_safi_identity2value(afi_safi, &afi, &safi);
prefix_afi = family2afi(prefix.family);
if (afi != prefix_afi) {
flog_warn(
EC_LIB_NB_CB_CONFIG_VALIDATE,
"route node %s creation failed",
yang_dnode_get_string(args->dnode, "prefix"));
return NB_ERR_VALIDATION;
}
if (src_p && afi != AFI_IP6) {
flog_warn(EC_LIB_NB_CB_CONFIG_VALIDATE,
"invalid use of IPv6 dst-src prefix %s on %s",
yang_dnode_get_string(args->dnode, "src-prefix"),
yang_dnode_get_string(args->dnode, "prefix"));
return NB_ERR_VALIDATION;
}
break;
case NB_EV_PREPARE:
case NB_EV_ABORT:
break;
case NB_EV_APPLY:
vrf_dnode = yang_dnode_get_parent(args->dnode,
"control-plane-protocol");
svrf = nb_running_get_entry(vrf_dnode, NULL, true);
yang_dnode_get_prefix(&prefix, args->dnode, "prefix");
yang_dnode_get_prefix(&src_prefix, args->dnode, "src-prefix");
src_p = src_prefix.prefixlen ? &src_prefix : NULL;
afi_safi = yang_dnode_get_string(args->dnode, "afi-safi");
yang_afi_safi_identity2value(afi_safi, &afi, &safi);
rn = static_add_route(afi, safi, &prefix, (struct prefix_ipv6 *)src_p, svrf);
if (!svrf->vrf || svrf->vrf->vrf_id == VRF_UNKNOWN)
snprintf(
args->errmsg, args->errmsg_len,
"Static Route to %s not installed currently because dependent config not fully available",
yang_dnode_get_string(args->dnode, "prefix"));
nb_running_set_entry(args->dnode, rn);
break;
}
return NB_OK;
}
int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_destroy(
struct nb_cb_destroy_args *args)
{
struct route_node *rn;
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
break;
case NB_EV_APPLY:
rn = nb_running_unset_entry(args->dnode);
static_del_route(rn);
break;
}
return NB_OK;
}
/*
* XPath:
* /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/path-list
*/
int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_create(
struct nb_cb_create_args *args)
{
return static_path_list_create(args);
}
int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_destroy(
struct nb_cb_destroy_args *args)
{
return static_path_list_destroy(args);
}
/*
* XPath:
* /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/path-list/tag
*/
int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_tag_modify(
struct nb_cb_modify_args *args)
{
return static_path_list_tag_modify(args);
}
/*
* XPath:
* /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/path-list/frr-nexthops/nexthop
*/
int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_create(
struct nb_cb_create_args *args)
{
return static_nexthop_create(args);
}
int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_destroy(
struct nb_cb_destroy_args *args)
{
return static_nexthop_destroy(args);
}
/*
* XPath:
* /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/path-list/frr-nexthops/nexthop/bh-type
*/
int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_bh_type_modify(
struct nb_cb_modify_args *args)
{
return static_nexthop_bh_type_modify(args);
}
/*
* XPath:
* /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/path-list/frr-nexthops/nexthop/onlink
*/
int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_onlink_modify(
struct nb_cb_modify_args *args)
{
return static_nexthop_onlink_modify(args);
}
/*
* XPath:
* /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/path-list/frr-nexthops/nexthop/srte-color
*/
int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_color_modify(
struct nb_cb_modify_args *args)
{
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
break;
case NB_EV_APPLY:
if (static_nexthop_color_modify(args) != NB_OK)
return NB_ERR;
break;
}
return NB_OK;
}
int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_color_destroy(
struct nb_cb_destroy_args *args)
{
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
break;
case NB_EV_APPLY:
if (static_nexthop_color_destroy(args) != NB_OK)
return NB_ERR;
break;
}
return NB_OK;
}
/*
* XPath:
* /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/path-list/frr-nexthops/nexthop/srv6-segs-stack/entry
*/
int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_srv6_segs_stack_entry_create(
struct nb_cb_create_args *args)
{
return nexthop_srv6_segs_stack_entry_create(args);
}
int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_srv6_segs_stack_entry_destroy(
struct nb_cb_destroy_args *args)
{
return nexthop_srv6_segs_stack_entry_destroy(args);
}
/*
* XPath:
* /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/path-list/frr-nexthops/nexthop/srv6-segs-stack/entry/seg
*/
int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_srv6_segs_stack_entry_seg_modify(
struct nb_cb_modify_args *args)
{
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
break;
case NB_EV_APPLY:
if (static_nexthop_srv6_segs_modify(args) != NB_OK)
return NB_ERR;
break;
}
return NB_OK;
}
int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_srv6_segs_stack_entry_seg_destroy(
struct nb_cb_destroy_args *args)
{
/*
* No operation is required in this call back.
* nexthop_srv6_segs_stack_entry_destroy() will take care
* to reset the seg vaue.
*/
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
case NB_EV_APPLY:
break;
}
return NB_OK;
}
/*
* XPath:
* /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/path-list/frr-nexthops/nexthop/mpls-label-stack/entry
*/
int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_mpls_label_stack_entry_create(
struct nb_cb_create_args *args)
{
return nexthop_mpls_label_stack_entry_create(args);
}
int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_mpls_label_stack_entry_destroy(
struct nb_cb_destroy_args *args)
{
return nexthop_mpls_label_stack_entry_destroy(args);
}
/*
* XPath:
* /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/path-list/frr-nexthops/nexthop/mpls-label-stack/entry/label
*/
int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_mpls_label_stack_entry_label_modify(
struct nb_cb_modify_args *args)
{
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
break;
case NB_EV_APPLY:
if (static_nexthop_mpls_label_modify(args) != NB_OK)
return NB_ERR;
break;
}
return NB_OK;
}
int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_mpls_label_stack_entry_label_destroy(
struct nb_cb_destroy_args *args)
{
/*
* No operation is required in this call back.
* nexthop_mpls_label_stack_entry_destroy() will take care
* to reset the label vaue.
*/
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
case NB_EV_APPLY:
break;
}
return NB_OK;
}
/*
* XPath:
* /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/path-list/frr-nexthops/nexthop/mpls-label-stack/entry/ttl
*/
int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_mpls_label_stack_entry_ttl_modify(
struct nb_cb_modify_args *args)
{
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
case NB_EV_APPLY:
break;
}
return NB_OK;
}
int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_mpls_label_stack_entry_ttl_destroy(
struct nb_cb_destroy_args *args)
{
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
case NB_EV_APPLY:
break;
}
return NB_OK;
}
/*
* XPath:
* /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/path-list/frr-nexthops/nexthop/mpls-label-stack/entry/traffic-class
*/
int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_mpls_label_stack_entry_traffic_class_modify(
struct nb_cb_modify_args *args)
{
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
case NB_EV_APPLY:
break;
}
return NB_OK;
}
int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_mpls_label_stack_entry_traffic_class_destroy(
struct nb_cb_destroy_args *args)
{
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
case NB_EV_APPLY:
break;
}
return NB_OK;
}
/*
* XPath:
* /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/path-list/frr-nexthops/nexthop/bfd-monitoring
*/
int route_next_hop_bfd_create(struct nb_cb_create_args *args)
{
struct static_nexthop *sn;
if (args->event != NB_EV_APPLY)
return NB_OK;
sn = nb_running_get_entry(args->dnode, NULL, true);
static_next_hop_bfd_monitor_enable(sn, args->dnode);
return NB_OK;
}
int route_next_hop_bfd_destroy(struct nb_cb_destroy_args *args)
{
struct static_nexthop *sn;
if (args->event != NB_EV_APPLY)
return NB_OK;
sn = nb_running_get_entry(args->dnode, NULL, true);
static_next_hop_bfd_monitor_disable(sn);
return NB_OK;
}
/*
* XPath:
* /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/path-list/frr-nexthops/nexthop/bfd-monitoring/source
*/
int route_next_hop_bfd_source_modify(struct nb_cb_modify_args *args)
{
struct static_nexthop *sn;
struct ipaddr source;
if (args->event != NB_EV_APPLY)
return NB_OK;
sn = nb_running_get_entry(args->dnode, NULL, true);
yang_dnode_get_ip(&source, args->dnode, NULL);
static_next_hop_bfd_source(sn, &source);
return NB_OK;
}
int route_next_hop_bfd_source_destroy(struct nb_cb_destroy_args *args)
{
struct static_nexthop *sn;
if (args->event != NB_EV_APPLY)
return NB_OK;
sn = nb_running_get_entry(args->dnode, NULL, true);
static_next_hop_bfd_auto_source(sn);
/* NHT information are needed by BFD to automatically find the source
*
* Force zebra to resend the information to BFD by unregistering and
* registering again NHT. The (...)/frr-nexthops/nexthop northbound
* apply_finish function will trigger a call to static_install_nexthop()
* that does a call to static_zebra_nht_register(nh, true);
* static_zebra_nht_register(sn, false);
*/
static_zebra_nht_register(sn, false);
return NB_OK;
}
/*
* XPath:
* /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/path-list/frr-nexthops/nexthop/bfd-monitoring/multi-hop
*/
int route_next_hop_bfd_multi_hop_modify(struct nb_cb_modify_args *args)
{
struct static_nexthop *sn;
if (args->event != NB_EV_APPLY)
return NB_OK;
sn = nb_running_get_entry(args->dnode, NULL, true);
static_next_hop_bfd_multi_hop(sn,
yang_dnode_get_bool(args->dnode, NULL));
return NB_OK;
}
/*
* XPath:
* /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/path-list/frr-nexthops/nexthop/bfd-monitoring/profile
*/
int route_next_hop_bfd_profile_modify(struct nb_cb_modify_args *args)
{
struct static_nexthop *sn;
if (args->event != NB_EV_APPLY)
return NB_OK;
sn = nb_running_get_entry(args->dnode, NULL, true);
static_next_hop_bfd_profile(sn,
yang_dnode_get_string(args->dnode, NULL));
return NB_OK;
}
int route_next_hop_bfd_profile_destroy(struct nb_cb_destroy_args *args)
{
struct static_nexthop *sn;
if (args->event != NB_EV_APPLY)
return NB_OK;
sn = nb_running_get_entry(args->dnode, NULL, true);
static_next_hop_bfd_profile(sn, NULL);
return NB_OK;
}
/*
* XPath:
* /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/segment-routing
*/
int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_create(
struct nb_cb_create_args *args)
{
return NB_OK;
}
int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_destroy(
struct nb_cb_destroy_args *args)
{
return NB_OK;
}
/*
* XPath:
* /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/segment-routing/srv6
*/
int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_create(
struct nb_cb_create_args *args)
{
return NB_OK;
}
int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_destroy(
struct nb_cb_destroy_args *args)
{
return NB_OK;
}
/*
* XPath:
* /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/segment-routing/srv6/static-sids
*/
int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_create(
struct nb_cb_create_args *args)
{
return NB_OK;
}
int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_destroy(
struct nb_cb_destroy_args *args)
{
return NB_OK;
}
/*
* XPath:
* /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/segment-routing/srv6/locators/locator/static-sids/sid
*/
int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_sid_create(
struct nb_cb_create_args *args)
{
struct static_srv6_sid *sid;
struct prefix_ipv6 sid_value;
if (args->event != NB_EV_APPLY)
return NB_OK;
yang_dnode_get_ipv6p(&sid_value, args->dnode, "sid");
sid = static_srv6_sid_alloc(&sid_value);
nb_running_set_entry(args->dnode, sid);
listnode_add(srv6_sids, sid);
return NB_OK;
}
int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_sid_destroy(
struct nb_cb_destroy_args *args)
{
struct static_srv6_sid *sid;
if (args->event != NB_EV_APPLY)
return NB_OK;
sid = nb_running_unset_entry(args->dnode);
listnode_delete(srv6_sids, sid);
static_srv6_sid_del(sid);
return NB_OK;
}
void routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_sid_apply_finish(
struct nb_cb_apply_finish_args *args)
{
struct static_srv6_sid *sid;
struct static_srv6_locator *locator;
sid = nb_running_get_entry(args->dnode, NULL, true);
locator = static_srv6_locator_lookup(sid->locator_name);
if (!locator) {
DEBUGD(&static_dbg_srv6,
"%s: Locator %s not found, trying to get locator information from zebra",
__func__, sid->locator_name);
static_zebra_srv6_manager_get_locator(sid->locator_name);
return;
}
sid->locator = locator;
static_zebra_request_srv6_sid(sid);
}
/*
* XPath:
* /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/segment-routing/srv6/locators/locator/static-sids/sid/behavior
*/
int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_sid_behavior_modify(
struct nb_cb_modify_args *args)
{
struct static_srv6_sid *sid;
if (args->event != NB_EV_APPLY)
return NB_OK;
sid = nb_running_get_entry(args->dnode, NULL, true);
/* Release and uninstall existing SID, if any, before requesting the new one */
if (CHECK_FLAG(sid->flags, STATIC_FLAG_SRV6_SID_VALID)) {
static_zebra_release_srv6_sid(sid);
UNSET_FLAG(sid->flags, STATIC_FLAG_SRV6_SID_VALID);
}
if (CHECK_FLAG(sid->flags, STATIC_FLAG_SRV6_SID_SENT_TO_ZEBRA)) {
static_zebra_srv6_sid_uninstall(sid);
UNSET_FLAG(sid->flags, STATIC_FLAG_SRV6_SID_SENT_TO_ZEBRA);
}
sid->behavior = yang_dnode_get_enum(args->dnode, "../behavior");
return NB_OK;
}
int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_sid_behavior_destroy(
struct nb_cb_destroy_args *args)
{
return NB_OK;
}
/*
* XPath:
* /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/segment-routing/srv6/locators/locator/static-sids/sid/vrf-name
*/
int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_sid_vrf_name_modify(
struct nb_cb_modify_args *args)
{
struct static_srv6_sid *sid;
const char *vrf_name;
if (args->event != NB_EV_APPLY)
return NB_OK;
sid = nb_running_get_entry(args->dnode, NULL, true);
/* Release and uninstall existing SID, if any, before requesting the new one */
if (CHECK_FLAG(sid->flags, STATIC_FLAG_SRV6_SID_VALID)) {
static_zebra_release_srv6_sid(sid);
UNSET_FLAG(sid->flags, STATIC_FLAG_SRV6_SID_VALID);
}
if (CHECK_FLAG(sid->flags, STATIC_FLAG_SRV6_SID_SENT_TO_ZEBRA)) {
static_zebra_srv6_sid_uninstall(sid);
UNSET_FLAG(sid->flags, STATIC_FLAG_SRV6_SID_SENT_TO_ZEBRA);
}
vrf_name = yang_dnode_get_string(args->dnode, "../vrf-name");
snprintf(sid->attributes.vrf_name, sizeof(sid->attributes.vrf_name), "%s", vrf_name);
return NB_OK;
}
int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_sid_vrf_name_destroy(
struct nb_cb_destroy_args *args)
{
return NB_OK;
}
/*
* XPath:
* /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/segment-routing/srv6/locators/locator/static-sids/sid/paths
*/
int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_sid_paths_create(
struct nb_cb_create_args *args)
{
/* Actual setting is done in apply_finish */
return NB_OK;
}
int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_sid_paths_destroy(
struct nb_cb_destroy_args *args)
{
return NB_OK;
}
/*
* XPath:
* /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/segment-routing/srv6/locators/locator/static-sids/sid/paths/interface
*/
int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_sid_paths_interface_modify(
struct nb_cb_modify_args *args)
{
struct static_srv6_sid *sid;
const char *ifname;
if (args->event != NB_EV_APPLY)
return NB_OK;
sid = nb_running_get_entry(args->dnode, NULL, true);
/* Release and uninstall existing SID, if any, before requesting the new one */
if (CHECK_FLAG(sid->flags, STATIC_FLAG_SRV6_SID_VALID)) {
static_zebra_release_srv6_sid(sid);
UNSET_FLAG(sid->flags, STATIC_FLAG_SRV6_SID_VALID);
}
if (CHECK_FLAG(sid->flags, STATIC_FLAG_SRV6_SID_SENT_TO_ZEBRA)) {
static_zebra_srv6_sid_uninstall(sid);
UNSET_FLAG(sid->flags, STATIC_FLAG_SRV6_SID_SENT_TO_ZEBRA);
}
ifname = yang_dnode_get_string(args->dnode, "../interface");
snprintf(sid->attributes.ifname, sizeof(sid->attributes.ifname), "%s", ifname);
return NB_OK;
}
int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_sid_paths_interface_destroy(
struct nb_cb_destroy_args *args)
{
return NB_OK;
}
/*
* XPath:
* /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/segment-routing/srv6/locators/locator/static-sids/sid/paths/next-hop
*/
int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_sid_paths_next_hop_modify(
struct nb_cb_modify_args *args)
{
struct static_srv6_sid *sid;
struct ipaddr nexthop;
switch (args->event) {
case NB_EV_VALIDATE:
yang_dnode_get_ip(&nexthop, args->dnode, "../next-hop");
if (!IS_IPADDR_V6(&nexthop)) {
snprintf(args->errmsg, args->errmsg_len,
"%% Nexthop must be an IPv6 address");
return NB_ERR_VALIDATION;
}
break;
case NB_EV_ABORT:
case NB_EV_PREPARE:
break;
case NB_EV_APPLY:
sid = nb_running_get_entry(args->dnode, NULL, true);
/* Release and uninstall existing SID, if any, before requesting the new one */
if (CHECK_FLAG(sid->flags, STATIC_FLAG_SRV6_SID_VALID)) {
static_zebra_release_srv6_sid(sid);
UNSET_FLAG(sid->flags, STATIC_FLAG_SRV6_SID_VALID);
}
if (CHECK_FLAG(sid->flags, STATIC_FLAG_SRV6_SID_SENT_TO_ZEBRA)) {
static_zebra_srv6_sid_uninstall(sid);
UNSET_FLAG(sid->flags, STATIC_FLAG_SRV6_SID_SENT_TO_ZEBRA);
}
yang_dnode_get_ip(&nexthop, args->dnode, "../next-hop");
sid->attributes.nh6 = nexthop.ipaddr_v6;
break;
}
return NB_OK;
}
int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_sid_paths_next_hop_destroy(
struct nb_cb_destroy_args *args)
{
return NB_OK;
}
/*
* XPath:
* /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/segment-routing/srv6/locators/locator/static-sids/sid/vrf-name
*/
int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_sid_locator_name_modify(
struct nb_cb_modify_args *args)
{
struct static_srv6_sid *sid;
const char *loc_name;
if (args->event != NB_EV_APPLY)
return NB_OK;
sid = nb_running_get_entry(args->dnode, NULL, true);
/* Release and uninstall existing SID, if any, before requesting the new one */
if (CHECK_FLAG(sid->flags, STATIC_FLAG_SRV6_SID_VALID)) {
static_zebra_release_srv6_sid(sid);
UNSET_FLAG(sid->flags, STATIC_FLAG_SRV6_SID_VALID);
}
if (CHECK_FLAG(sid->flags, STATIC_FLAG_SRV6_SID_SENT_TO_ZEBRA)) {
static_zebra_srv6_sid_uninstall(sid);
UNSET_FLAG(sid->flags, STATIC_FLAG_SRV6_SID_SENT_TO_ZEBRA);
}
loc_name = yang_dnode_get_string(args->dnode, "../locator-name");
snprintf(sid->locator_name, sizeof(sid->locator_name), "%s", loc_name);
return NB_OK;
}
int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_sid_locator_name_destroy(
struct nb_cb_destroy_args *args)
{
return NB_OK;
}