diff options
Diffstat (limited to 'isisd/isis_nb_config.c')
-rw-r--r-- | isisd/isis_nb_config.c | 4947 |
1 files changed, 4947 insertions, 0 deletions
diff --git a/isisd/isis_nb_config.c b/isisd/isis_nb_config.c new file mode 100644 index 0000000..b6ee073 --- /dev/null +++ b/isisd/isis_nb_config.c @@ -0,0 +1,4947 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2001,2002 Sampo Saaristo + * Tampere University of Technology + * Institute of Communications Engineering + * Copyright (C) 2018 Volta Networks + * Emanuele Di Pascale + */ + +#include <zebra.h> + +#include "printfrr.h" +#include "northbound.h" +#include "linklist.h" +#include "log.h" +#include "bfd.h" +#include "filter.h" +#include "plist.h" +#include "spf_backoff.h" +#include "lib_errors.h" +#include "vrf.h" +#include "ldp_sync.h" +#include "link_state.h" +#include "affinitymap.h" + +#include "isisd/isisd.h" +#include "isisd/isis_nb.h" +#include "isisd/isis_common.h" +#include "isisd/isis_bfd.h" +#include "isisd/isis_circuit.h" +#include "isisd/isis_lsp.h" +#include "isisd/isis_dynhn.h" +#include "isisd/isis_misc.h" +#include "isisd/isis_csm.h" +#include "isisd/isis_adjacency.h" +#include "isisd/isis_spf.h" +#include "isisd/isis_spf_private.h" +#include "isisd/isis_srv6.h" +#include "isisd/isis_te.h" +#include "isisd/isis_mt.h" +#include "isisd/isis_redist.h" +#include "isisd/isis_ldp_sync.h" +#include "isisd/isis_dr.h" +#include "isisd/isis_sr.h" +#include "isisd/isis_flex_algo.h" +#include "isisd/isis_zebra.h" + +#define AFFINITY_INCLUDE_ANY 0 +#define AFFINITY_INCLUDE_ALL 1 +#define AFFINITY_EXCLUDE_ANY 2 + +/* + * XPath: /frr-isisd:isis/instance + */ +int isis_instance_create(struct nb_cb_create_args *args) +{ + struct isis_area *area; + const char *area_tag; + const char *vrf_name; + + if (args->event != NB_EV_APPLY) + return NB_OK; + vrf_name = yang_dnode_get_string(args->dnode, "./vrf"); + area_tag = yang_dnode_get_string(args->dnode, "./area-tag"); + + area = isis_area_lookup_by_vrf(area_tag, vrf_name); + if (area) + return NB_ERR_INCONSISTENCY; + + area = isis_area_create(area_tag, vrf_name); + + /* save area in dnode to avoid looking it up all the time */ + nb_running_set_entry(args->dnode, area); + + return NB_OK; +} + +int isis_instance_destroy(struct nb_cb_destroy_args *args) +{ + struct isis_area *area; + struct isis *isis; + + if (args->event != NB_EV_APPLY) + return NB_OK; + area = nb_running_unset_entry(args->dnode); + isis = area->isis; + isis_area_destroy(area); + + if (listcount(isis->area_list) == 0) + isis_finish(isis); + + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/is-type + */ +int isis_instance_is_type_modify(struct nb_cb_modify_args *args) +{ + struct isis_area *area; + int type; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + area = nb_running_get_entry(args->dnode, NULL, true); + type = yang_dnode_get_enum(args->dnode, NULL); + isis_area_is_type_set(area, type); + + return NB_OK; +} + +struct sysid_iter { + struct iso_address *addr; + bool same; +}; + +static int sysid_iter_cb(const struct lyd_node *dnode, void *arg) +{ + struct sysid_iter *iter = arg; + struct iso_address addr; + const char *net; + + net = yang_dnode_get_string(dnode, NULL); + addr.addr_len = dotformat2buff(addr.area_addr, net); + + if (memcmp(GETSYSID(iter->addr), GETSYSID((&addr)), ISIS_SYS_ID_LEN)) { + iter->same = false; + return YANG_ITER_STOP; + } + + return YANG_ITER_CONTINUE; +} + +/* + * XPath: /frr-isisd:isis/instance/area-address + */ +int isis_instance_area_address_create(struct nb_cb_create_args *args) +{ + struct isis_area *area; + struct iso_address addr, *addrr = NULL, *addrp = NULL; + struct listnode *node; + struct sysid_iter iter; + uint8_t buff[255]; + const char *net_title = yang_dnode_get_string(args->dnode, NULL); + + switch (args->event) { + case NB_EV_VALIDATE: + addr.addr_len = dotformat2buff(buff, net_title); + memcpy(addr.area_addr, buff, addr.addr_len); + if (addr.area_addr[addr.addr_len - 1] != 0) { + snprintf( + args->errmsg, args->errmsg_len, + "nsel byte (last byte) in area address must be 0"); + return NB_ERR_VALIDATION; + } + + iter.addr = &addr; + iter.same = true; + + yang_dnode_iterate(sysid_iter_cb, &iter, args->dnode, + "../area-address"); + + if (!iter.same) { + snprintf( + args->errmsg, args->errmsg_len, + "System ID must not change when defining additional area addresses"); + return NB_ERR_VALIDATION; + } + break; + case NB_EV_PREPARE: + addrr = XMALLOC(MTYPE_ISIS_AREA_ADDR, + sizeof(struct iso_address)); + addrr->addr_len = dotformat2buff(buff, net_title); + memcpy(addrr->area_addr, buff, addrr->addr_len); + args->resource->ptr = addrr; + break; + case NB_EV_ABORT: + XFREE(MTYPE_ISIS_AREA_ADDR, args->resource->ptr); + break; + case NB_EV_APPLY: + area = nb_running_get_entry(args->dnode, NULL, true); + addrr = args->resource->ptr; + assert(area); + + if (area->isis->sysid_set == 0) { + /* + * First area address - get the SystemID for this router + */ + memcpy(area->isis->sysid, GETSYSID(addrr), + ISIS_SYS_ID_LEN); + area->isis->sysid_set = 1; + } else { + /* check that we don't already have this address */ + for (ALL_LIST_ELEMENTS_RO(area->area_addrs, node, + addrp)) { + if ((addrp->addr_len + ISIS_SYS_ID_LEN + + ISIS_NSEL_LEN) + != (addrr->addr_len)) + continue; + if (!memcmp(addrp->area_addr, addrr->area_addr, + addrr->addr_len)) { + XFREE(MTYPE_ISIS_AREA_ADDR, addrr); + return NB_OK; /* silent fail */ + } + } + } + + /*Forget the systemID part of the address */ + addrr->addr_len -= (ISIS_SYS_ID_LEN + ISIS_NSEL_LEN); + assert(area->area_addrs); /* to silence scan-build sillyness */ + listnode_add(area->area_addrs, addrr); + + /* only now we can safely generate our LSPs for this area */ + if (listcount(area->area_addrs) > 0) { + if (area->is_type & IS_LEVEL_1) + lsp_generate(area, IS_LEVEL_1); + if (area->is_type & IS_LEVEL_2) + lsp_generate(area, IS_LEVEL_2); + } + break; + } + + return NB_OK; +} + +int isis_instance_area_address_destroy(struct nb_cb_destroy_args *args) +{ + struct iso_address addr, *addrp = NULL; + struct listnode *node; + uint8_t buff[255]; + struct isis_area *area; + const char *net_title; + struct listnode *cnode; + struct isis_circuit *circuit; + int lvl; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + net_title = yang_dnode_get_string(args->dnode, NULL); + addr.addr_len = dotformat2buff(buff, net_title); + memcpy(addr.area_addr, buff, (int)addr.addr_len); + area = nb_running_get_entry(args->dnode, NULL, true); + + for (ALL_LIST_ELEMENTS_RO(area->area_addrs, node, addrp)) { + if ((addrp->addr_len + ISIS_SYS_ID_LEN + 1) == addr.addr_len + && !memcmp(addrp->area_addr, addr.area_addr, addr.addr_len)) + break; + } + if (!addrp) + return NB_ERR_INCONSISTENCY; + + listnode_delete(area->area_addrs, addrp); + XFREE(MTYPE_ISIS_AREA_ADDR, addrp); + /* + * Last area address - reset the SystemID for this router + */ + if (listcount(area->area_addrs) == 0) { + for (ALL_LIST_ELEMENTS_RO(area->circuit_list, cnode, circuit)) + for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; ++lvl) { + if (circuit->u.bc.is_dr[lvl - 1]) + isis_dr_resign(circuit, lvl); + } + memset(area->isis->sysid, 0, ISIS_SYS_ID_LEN); + area->isis->sysid_set = 0; + if (IS_DEBUG_EVENTS) + zlog_debug("Router has no SystemID"); + } + + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/dynamic-hostname + */ +int isis_instance_dynamic_hostname_modify(struct nb_cb_modify_args *args) +{ + struct isis_area *area; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + area = nb_running_get_entry(args->dnode, NULL, true); + isis_area_dynhostname_set(area, yang_dnode_get_bool(args->dnode, NULL)); + + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/attach-send + */ +int isis_instance_attached_send_modify(struct nb_cb_modify_args *args) +{ + struct isis_area *area; + bool attached; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + area = nb_running_get_entry(args->dnode, NULL, true); + attached = yang_dnode_get_bool(args->dnode, NULL); + isis_area_attached_bit_send_set(area, attached); + + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/attach-receive-ignore + */ +int isis_instance_attached_receive_modify(struct nb_cb_modify_args *args) +{ + struct isis_area *area; + bool attached; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + area = nb_running_get_entry(args->dnode, NULL, true); + attached = yang_dnode_get_bool(args->dnode, NULL); + isis_area_attached_bit_receive_set(area, attached); + + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/attached + */ +int isis_instance_attached_modify(struct nb_cb_modify_args *args) +{ + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/overload/enabled + */ +int isis_instance_overload_enabled_modify(struct nb_cb_modify_args *args) +{ + struct isis_area *area; + bool overload; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + area = nb_running_get_entry(args->dnode, NULL, true); + overload = yang_dnode_get_bool(args->dnode, NULL); + area->overload_configured = overload; + + isis_area_overload_bit_set(area, overload); + + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/overload/on-startup + */ +int isis_instance_overload_on_startup_modify(struct nb_cb_modify_args *args) +{ + struct isis_area *area; + uint32_t overload_time; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + overload_time = yang_dnode_get_uint32(args->dnode, NULL); + area = nb_running_get_entry(args->dnode, NULL, true); + isis_area_overload_on_startup_set(area, overload_time); + + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/advertise-high-metrics + */ +int isis_instance_advertise_high_metrics_modify(struct nb_cb_modify_args *args) +{ + struct isis_area *area; + bool advertise_high_metrics; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + advertise_high_metrics = yang_dnode_get_bool(args->dnode, NULL); + area = nb_running_get_entry(args->dnode, NULL, true); + isis_area_advertise_high_metrics_set(area, advertise_high_metrics); + + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/metric-style + */ +int isis_instance_metric_style_modify(struct nb_cb_modify_args *args) +{ + struct isis_area *area; + bool old_metric, new_metric; + enum isis_metric_style metric_style = + yang_dnode_get_enum(args->dnode, NULL); + + if (args->event != NB_EV_APPLY) + return NB_OK; + + area = nb_running_get_entry(args->dnode, NULL, true); + old_metric = (metric_style == ISIS_WIDE_METRIC) ? false : true; + new_metric = (metric_style == ISIS_NARROW_METRIC) ? false : true; + isis_area_metricstyle_set(area, old_metric, new_metric); + + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/purge-originator + */ +int isis_instance_purge_originator_modify(struct nb_cb_modify_args *args) +{ + struct isis_area *area; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + area = nb_running_get_entry(args->dnode, NULL, true); + area->purge_originator = yang_dnode_get_bool(args->dnode, NULL); + + return NB_OK; +} + + +/* + * XPath: /frr-isisd:isis/instance/admin-group-send-zero + */ +int isis_instance_admin_group_send_zero_modify(struct nb_cb_modify_args *args) +{ + struct isis_circuit *circuit; + struct isis_area *area; + struct listnode *node; + struct flex_algo *fa; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + area = nb_running_get_entry(args->dnode, NULL, true); + area->admin_group_send_zero = yang_dnode_get_bool(args->dnode, NULL); + + if (area->admin_group_send_zero) { + for (ALL_LIST_ELEMENTS_RO(area->flex_algos->flex_algos, node, + fa)) { + admin_group_allow_explicit_zero( + &fa->admin_group_exclude_any); + admin_group_allow_explicit_zero( + &fa->admin_group_include_any); + admin_group_allow_explicit_zero( + &fa->admin_group_include_all); + } + } else { + for (ALL_LIST_ELEMENTS_RO(area->flex_algos->flex_algos, node, + fa)) { + admin_group_disallow_explicit_zero( + &fa->admin_group_exclude_any); + admin_group_disallow_explicit_zero( + &fa->admin_group_include_any); + admin_group_disallow_explicit_zero( + &fa->admin_group_include_all); + } + } + + for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit)) + isis_link_params_update(circuit, circuit->interface); + + lsp_regenerate_schedule(area, IS_LEVEL_1 | IS_LEVEL_2, 0); + + return NB_OK; +} + + +/* + * XPath: /frr-isisd:isis/instance/asla-legacy-flag + */ +int isis_instance_asla_legacy_flag_modify(struct nb_cb_modify_args *args) +{ + struct isis_area *area; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + area = nb_running_get_entry(args->dnode, NULL, true); + area->asla_legacy_flag = yang_dnode_get_bool(args->dnode, NULL); + lsp_regenerate_schedule(area, IS_LEVEL_1 | IS_LEVEL_2, 0); + + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/lsp/mtu + */ +int isis_instance_lsp_mtu_modify(struct nb_cb_modify_args *args) +{ + uint16_t lsp_mtu = yang_dnode_get_uint16(args->dnode, NULL); + struct isis_area *area; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + area = nb_running_get_entry(args->dnode, NULL, true); + isis_area_lsp_mtu_set(area, lsp_mtu); + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/advertise-passive-only + */ +int isis_instance_advertise_passive_only_modify(struct nb_cb_modify_args *args) +{ + struct isis_area *area; + bool advertise_passive_only; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + area = nb_running_get_entry(args->dnode, NULL, true); + advertise_passive_only = yang_dnode_get_bool(args->dnode, NULL); + area->advertise_passive_only = advertise_passive_only; + + lsp_regenerate_schedule(area, IS_LEVEL_1 | IS_LEVEL_2, 1); + + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/lsp/timers/level-1/refresh-interval + */ +int isis_instance_lsp_refresh_interval_level_1_modify( + struct nb_cb_modify_args *args) +{ + struct isis_area *area; + uint16_t refr_int; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + refr_int = yang_dnode_get_uint16(args->dnode, NULL); + area = nb_running_get_entry(args->dnode, NULL, true); + isis_area_lsp_refresh_set(area, IS_LEVEL_1, refr_int); + + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/lsp/timers/level-2/refresh-interval + */ +int isis_instance_lsp_refresh_interval_level_2_modify( + struct nb_cb_modify_args *args) +{ + struct isis_area *area; + uint16_t refr_int; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + refr_int = yang_dnode_get_uint16(args->dnode, NULL); + area = nb_running_get_entry(args->dnode, NULL, true); + isis_area_lsp_refresh_set(area, IS_LEVEL_2, refr_int); + + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/lsp/timers/level-1/maximum-lifetime + */ +int isis_instance_lsp_maximum_lifetime_level_1_modify( + struct nb_cb_modify_args *args) +{ + struct isis_area *area; + uint16_t max_lt; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + max_lt = yang_dnode_get_uint16(args->dnode, NULL); + area = nb_running_get_entry(args->dnode, NULL, true); + isis_area_max_lsp_lifetime_set(area, IS_LEVEL_1, max_lt); + + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/lsp/timers/level-2/maximum-lifetime + */ +int isis_instance_lsp_maximum_lifetime_level_2_modify( + struct nb_cb_modify_args *args) +{ + struct isis_area *area; + uint16_t max_lt; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + max_lt = yang_dnode_get_uint16(args->dnode, NULL); + area = nb_running_get_entry(args->dnode, NULL, true); + isis_area_max_lsp_lifetime_set(area, IS_LEVEL_2, max_lt); + + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/lsp/timers/level-1/generation-interval + */ +int isis_instance_lsp_generation_interval_level_1_modify( + struct nb_cb_modify_args *args) +{ + struct isis_area *area; + uint16_t gen_int; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + gen_int = yang_dnode_get_uint16(args->dnode, NULL); + area = nb_running_get_entry(args->dnode, NULL, true); + area->lsp_gen_interval[0] = gen_int; + + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/lsp/timers/level-2/generation-interval + */ +int isis_instance_lsp_generation_interval_level_2_modify( + struct nb_cb_modify_args *args) +{ + struct isis_area *area; + uint16_t gen_int; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + gen_int = yang_dnode_get_uint16(args->dnode, NULL); + area = nb_running_get_entry(args->dnode, NULL, true); + area->lsp_gen_interval[1] = gen_int; + + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/spf/ietf-backoff-delay + */ +void ietf_backoff_delay_apply_finish(struct nb_cb_apply_finish_args *args) +{ + long init_delay = yang_dnode_get_uint16(args->dnode, "./init-delay"); + long short_delay = yang_dnode_get_uint16(args->dnode, "./short-delay"); + long long_delay = yang_dnode_get_uint16(args->dnode, "./long-delay"); + long holddown = yang_dnode_get_uint16(args->dnode, "./hold-down"); + long timetolearn = + yang_dnode_get_uint16(args->dnode, "./time-to-learn"); + struct isis_area *area = nb_running_get_entry(args->dnode, NULL, true); + size_t bufsiz = strlen(area->area_tag) + sizeof("IS-IS Lx"); + char *buf = XCALLOC(MTYPE_TMP, bufsiz); + + snprintf(buf, bufsiz, "IS-IS %s L1", area->area_tag); + spf_backoff_free(area->spf_delay_ietf[0]); + area->spf_delay_ietf[0] = + spf_backoff_new(master, buf, init_delay, short_delay, + long_delay, holddown, timetolearn); + + snprintf(buf, bufsiz, "IS-IS %s L2", area->area_tag); + spf_backoff_free(area->spf_delay_ietf[1]); + area->spf_delay_ietf[1] = + spf_backoff_new(master, buf, init_delay, short_delay, + long_delay, holddown, timetolearn); + + XFREE(MTYPE_TMP, buf); +} + +int isis_instance_spf_ietf_backoff_delay_create(struct nb_cb_create_args *args) +{ + /* All the work is done in the apply_finish */ + return NB_OK; +} + +int isis_instance_spf_ietf_backoff_delay_destroy( + struct nb_cb_destroy_args *args) +{ + struct isis_area *area; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + area = nb_running_get_entry(args->dnode, NULL, true); + spf_backoff_free(area->spf_delay_ietf[0]); + spf_backoff_free(area->spf_delay_ietf[1]); + area->spf_delay_ietf[0] = NULL; + area->spf_delay_ietf[1] = NULL; + + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/spf/ietf-backoff-delay/init-delay + */ +int isis_instance_spf_ietf_backoff_delay_init_delay_modify( + struct nb_cb_modify_args *args) +{ + /* All the work is done in the apply_finish */ + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/spf/ietf-backoff-delay/short-delay + */ +int isis_instance_spf_ietf_backoff_delay_short_delay_modify( + struct nb_cb_modify_args *args) +{ + /* All the work is done in the apply_finish */ + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/spf/ietf-backoff-delay/long-delay + */ +int isis_instance_spf_ietf_backoff_delay_long_delay_modify( + struct nb_cb_modify_args *args) +{ + /* All the work is done in the apply_finish */ + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/spf/ietf-backoff-delay/hold-down + */ +int isis_instance_spf_ietf_backoff_delay_hold_down_modify( + struct nb_cb_modify_args *args) +{ + /* All the work is done in the apply_finish */ + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/spf/ietf-backoff-delay/time-to-learn + */ +int isis_instance_spf_ietf_backoff_delay_time_to_learn_modify( + struct nb_cb_modify_args *args) +{ + /* All the work is done in the apply_finish */ + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/spf/minimum-interval/level-1 + */ +int isis_instance_spf_minimum_interval_level_1_modify( + struct nb_cb_modify_args *args) +{ + struct isis_area *area; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + area = nb_running_get_entry(args->dnode, NULL, true); + area->min_spf_interval[0] = yang_dnode_get_uint16(args->dnode, NULL); + + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/spf/minimum-interval/level-2 + */ +int isis_instance_spf_minimum_interval_level_2_modify( + struct nb_cb_modify_args *args) +{ + struct isis_area *area; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + area = nb_running_get_entry(args->dnode, NULL, true); + area->min_spf_interval[1] = yang_dnode_get_uint16(args->dnode, NULL); + + return NB_OK; +} + +/* + * XPath: + * /frr-isisd:isis/instance/spf/prefix-priorities/critical/access-list-name + */ +int isis_instance_spf_prefix_priorities_critical_access_list_name_modify( + struct nb_cb_modify_args *args) +{ + struct isis_area *area; + const char *acl_name; + struct spf_prefix_priority_acl *ppa; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + area = nb_running_get_entry(args->dnode, NULL, true); + acl_name = yang_dnode_get_string(args->dnode, NULL); + + ppa = &area->spf_prefix_priorities[SPF_PREFIX_PRIO_CRITICAL]; + XFREE(MTYPE_ISIS_ACL_NAME, ppa->name); + ppa->name = XSTRDUP(MTYPE_ISIS_ACL_NAME, acl_name); + ppa->list_v4 = access_list_lookup(AFI_IP, acl_name); + ppa->list_v6 = access_list_lookup(AFI_IP6, acl_name); + lsp_regenerate_schedule(area, area->is_type, 0); + + return NB_OK; +} + +int isis_instance_spf_prefix_priorities_critical_access_list_name_destroy( + struct nb_cb_destroy_args *args) +{ + struct isis_area *area; + struct spf_prefix_priority_acl *ppa; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + area = nb_running_get_entry(args->dnode, NULL, true); + + ppa = &area->spf_prefix_priorities[SPF_PREFIX_PRIO_CRITICAL]; + XFREE(MTYPE_ISIS_ACL_NAME, ppa->name); + ppa->list_v4 = NULL; + ppa->list_v6 = NULL; + lsp_regenerate_schedule(area, area->is_type, 0); + + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/spf/prefix-priorities/high/access-list-name + */ +int isis_instance_spf_prefix_priorities_high_access_list_name_modify( + struct nb_cb_modify_args *args) +{ + struct isis_area *area; + const char *acl_name; + struct spf_prefix_priority_acl *ppa; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + area = nb_running_get_entry(args->dnode, NULL, true); + acl_name = yang_dnode_get_string(args->dnode, NULL); + + ppa = &area->spf_prefix_priorities[SPF_PREFIX_PRIO_HIGH]; + XFREE(MTYPE_ISIS_ACL_NAME, ppa->name); + ppa->name = XSTRDUP(MTYPE_ISIS_ACL_NAME, acl_name); + ppa->list_v4 = access_list_lookup(AFI_IP, acl_name); + ppa->list_v6 = access_list_lookup(AFI_IP6, acl_name); + lsp_regenerate_schedule(area, area->is_type, 0); + + return NB_OK; +} + +int isis_instance_spf_prefix_priorities_high_access_list_name_destroy( + struct nb_cb_destroy_args *args) +{ + struct isis_area *area; + struct spf_prefix_priority_acl *ppa; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + area = nb_running_get_entry(args->dnode, NULL, true); + + ppa = &area->spf_prefix_priorities[SPF_PREFIX_PRIO_HIGH]; + XFREE(MTYPE_ISIS_ACL_NAME, ppa->name); + ppa->list_v4 = NULL; + ppa->list_v6 = NULL; + lsp_regenerate_schedule(area, area->is_type, 0); + + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/spf/prefix-priorities/medium/access-list-name + */ +int isis_instance_spf_prefix_priorities_medium_access_list_name_modify( + struct nb_cb_modify_args *args) +{ + struct isis_area *area; + const char *acl_name; + struct spf_prefix_priority_acl *ppa; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + area = nb_running_get_entry(args->dnode, NULL, true); + acl_name = yang_dnode_get_string(args->dnode, NULL); + + ppa = &area->spf_prefix_priorities[SPF_PREFIX_PRIO_MEDIUM]; + XFREE(MTYPE_ISIS_ACL_NAME, ppa->name); + ppa->name = XSTRDUP(MTYPE_ISIS_ACL_NAME, acl_name); + ppa->list_v4 = access_list_lookup(AFI_IP, acl_name); + ppa->list_v6 = access_list_lookup(AFI_IP6, acl_name); + lsp_regenerate_schedule(area, area->is_type, 0); + + return NB_OK; +} + +int isis_instance_spf_prefix_priorities_medium_access_list_name_destroy( + struct nb_cb_destroy_args *args) +{ + struct isis_area *area; + struct spf_prefix_priority_acl *ppa; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + area = nb_running_get_entry(args->dnode, NULL, true); + + ppa = &area->spf_prefix_priorities[SPF_PREFIX_PRIO_MEDIUM]; + XFREE(MTYPE_ISIS_ACL_NAME, ppa->name); + ppa->list_v4 = NULL; + ppa->list_v6 = NULL; + lsp_regenerate_schedule(area, area->is_type, 0); + + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/area-password + */ +void area_password_apply_finish(struct nb_cb_apply_finish_args *args) +{ + const char *password = yang_dnode_get_string(args->dnode, "./password"); + struct isis_area *area = nb_running_get_entry(args->dnode, NULL, true); + int pass_type = yang_dnode_get_enum(args->dnode, "./password-type"); + uint8_t snp_auth = + yang_dnode_get_enum(args->dnode, "./authenticate-snp"); + + switch (pass_type) { + case ISIS_PASSWD_TYPE_CLEARTXT: + isis_area_passwd_cleartext_set(area, IS_LEVEL_1, password, + snp_auth); + break; + case ISIS_PASSWD_TYPE_HMAC_MD5: + isis_area_passwd_hmac_md5_set(area, IS_LEVEL_1, password, + snp_auth); + break; + } +} + +int isis_instance_area_password_create(struct nb_cb_create_args *args) +{ + /* actual setting is done in apply_finish */ + return NB_OK; +} + +int isis_instance_area_password_destroy(struct nb_cb_destroy_args *args) +{ + struct isis_area *area; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + area = nb_running_get_entry(args->dnode, NULL, true); + isis_area_passwd_unset(area, IS_LEVEL_1); + + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/area-password/password + */ +int isis_instance_area_password_password_modify(struct nb_cb_modify_args *args) +{ + /* actual setting is done in apply_finish */ + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/area-password/password-type + */ +int isis_instance_area_password_password_type_modify( + struct nb_cb_modify_args *args) +{ + /* actual setting is done in apply_finish */ + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/area-password/authenticate-snp + */ +int isis_instance_area_password_authenticate_snp_modify( + struct nb_cb_modify_args *args) +{ + /* actual setting is done in apply_finish */ + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/domain-password + */ +void domain_password_apply_finish(struct nb_cb_apply_finish_args *args) +{ + const char *password = yang_dnode_get_string(args->dnode, "./password"); + struct isis_area *area = nb_running_get_entry(args->dnode, NULL, true); + int pass_type = yang_dnode_get_enum(args->dnode, "./password-type"); + uint8_t snp_auth = + yang_dnode_get_enum(args->dnode, "./authenticate-snp"); + + switch (pass_type) { + case ISIS_PASSWD_TYPE_CLEARTXT: + isis_area_passwd_cleartext_set(area, IS_LEVEL_2, password, + snp_auth); + break; + case ISIS_PASSWD_TYPE_HMAC_MD5: + isis_area_passwd_hmac_md5_set(area, IS_LEVEL_2, password, + snp_auth); + break; + } +} + +int isis_instance_domain_password_create(struct nb_cb_create_args *args) +{ + /* actual setting is done in apply_finish */ + return NB_OK; +} + +int isis_instance_domain_password_destroy(struct nb_cb_destroy_args *args) +{ + struct isis_area *area; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + area = nb_running_get_entry(args->dnode, NULL, true); + isis_area_passwd_unset(area, IS_LEVEL_2); + + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/domain-password/password + */ +int isis_instance_domain_password_password_modify( + struct nb_cb_modify_args *args) +{ + /* actual setting is done in apply_finish */ + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/domain-password/password-type + */ +int isis_instance_domain_password_password_type_modify( + struct nb_cb_modify_args *args) +{ + /* actual setting is done in apply_finish */ + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/domain-password/authenticate-snp + */ +int isis_instance_domain_password_authenticate_snp_modify( + struct nb_cb_modify_args *args) +{ + /* actual setting is done in apply_finish */ + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/default-information-originate/ipv4 + */ +void default_info_origin_apply_finish(const struct lyd_node *dnode, int family) +{ + int originate_type = DEFAULT_ORIGINATE; + unsigned long metric = 0; + const char *routemap = NULL; + struct isis_area *area = nb_running_get_entry(dnode, NULL, true); + int level = yang_dnode_get_enum(dnode, "./level"); + + if (yang_dnode_get_bool(dnode, "./always")) { + originate_type = DEFAULT_ORIGINATE_ALWAYS; + } else if (family == AF_INET6) { + zlog_warn( + "%s: Zebra doesn't implement default-originate for IPv6 yet, so use with care or use default-originate always.", + __func__); + } + + if (yang_dnode_exists(dnode, "./metric")) + metric = yang_dnode_get_uint32(dnode, "./metric"); + if (yang_dnode_exists(dnode, "./route-map")) + routemap = yang_dnode_get_string(dnode, "./route-map"); + + isis_redist_set(area, level, family, DEFAULT_ROUTE, metric, routemap, + originate_type, 0); +} + +void default_info_origin_ipv4_apply_finish(struct nb_cb_apply_finish_args *args) +{ + default_info_origin_apply_finish(args->dnode, AF_INET); +} + +void default_info_origin_ipv6_apply_finish(struct nb_cb_apply_finish_args *args) +{ + default_info_origin_apply_finish(args->dnode, AF_INET6); +} + +int isis_instance_default_information_originate_ipv4_create( + struct nb_cb_create_args *args) +{ + /* It's all done by default_info_origin_apply_finish */ + return NB_OK; +} + +int isis_instance_default_information_originate_ipv4_destroy( + struct nb_cb_destroy_args *args) +{ + struct isis_area *area; + int level; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + area = nb_running_get_entry(args->dnode, NULL, true); + level = yang_dnode_get_enum(args->dnode, "./level"); + isis_redist_unset(area, level, AF_INET, DEFAULT_ROUTE, 0); + + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/default-information-originate/ipv4/always + */ +int isis_instance_default_information_originate_ipv4_always_modify( + struct nb_cb_modify_args *args) +{ + /* It's all done by default_info_origin_apply_finish */ + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/default-information-originate/ipv4/route-map + */ +int isis_instance_default_information_originate_ipv4_route_map_modify( + struct nb_cb_modify_args *args) +{ + /* It's all done by default_info_origin_apply_finish */ + return NB_OK; +} + +int isis_instance_default_information_originate_ipv4_route_map_destroy( + struct nb_cb_destroy_args *args) +{ + /* It's all done by default_info_origin_apply_finish */ + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/default-information-originate/ipv4/metric + */ +int isis_instance_default_information_originate_ipv4_metric_modify( + struct nb_cb_modify_args *args) +{ + /* It's all done by default_info_origin_apply_finish */ + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/default-information-originate/ipv6 + */ +int isis_instance_default_information_originate_ipv6_create( + struct nb_cb_create_args *args) +{ + /* It's all done by default_info_origin_apply_finish */ + return NB_OK; +} + +int isis_instance_default_information_originate_ipv6_destroy( + struct nb_cb_destroy_args *args) +{ + struct isis_area *area; + int level; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + area = nb_running_get_entry(args->dnode, NULL, true); + level = yang_dnode_get_enum(args->dnode, "./level"); + isis_redist_unset(area, level, AF_INET6, DEFAULT_ROUTE, 0); + + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/default-information-originate/ipv6/always + */ +int isis_instance_default_information_originate_ipv6_always_modify( + struct nb_cb_modify_args *args) +{ + /* It's all done by default_info_origin_apply_finish */ + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/default-information-originate/ipv6/route-map + */ +int isis_instance_default_information_originate_ipv6_route_map_modify( + struct nb_cb_modify_args *args) +{ + /* It's all done by default_info_origin_apply_finish */ + return NB_OK; +} + +int isis_instance_default_information_originate_ipv6_route_map_destroy( + struct nb_cb_destroy_args *args) +{ + /* It's all done by default_info_origin_apply_finish */ + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/default-information-originate/ipv6/metric + */ +int isis_instance_default_information_originate_ipv6_metric_modify( + struct nb_cb_modify_args *args) +{ + /* It's all done by default_info_origin_apply_finish */ + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/redistribute/ipv4 + */ +void redistribute_apply_finish(const struct lyd_node *dnode, int family) +{ + assert(family == AF_INET || family == AF_INET6); + int type, level; + unsigned long metric = 0; + const char *routemap = NULL; + struct isis_area *area; + + type = yang_dnode_get_enum(dnode, "./protocol"); + level = yang_dnode_get_enum(dnode, "./level"); + area = nb_running_get_entry(dnode, NULL, true); + + if (yang_dnode_exists(dnode, "./metric")) + metric = yang_dnode_get_uint32(dnode, "./metric"); + if (yang_dnode_exists(dnode, "./route-map")) + routemap = yang_dnode_get_string(dnode, "./route-map"); + + isis_redist_set(area, level, family, type, metric, routemap, 0, 0); +} + +void redistribute_ipv4_apply_finish(struct nb_cb_apply_finish_args *args) +{ + redistribute_apply_finish(args->dnode, AF_INET); +} + +void redistribute_ipv6_apply_finish(struct nb_cb_apply_finish_args *args) +{ + redistribute_apply_finish(args->dnode, AF_INET6); +} + +int isis_instance_redistribute_ipv4_create(struct nb_cb_create_args *args) +{ + /* It's all done by redistribute_apply_finish */ + return NB_OK; +} + +int isis_instance_redistribute_ipv4_destroy(struct nb_cb_destroy_args *args) +{ + struct isis_area *area; + int level, type; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + area = nb_running_get_entry(args->dnode, NULL, true); + level = yang_dnode_get_enum(args->dnode, "./level"); + type = yang_dnode_get_enum(args->dnode, "./protocol"); + isis_redist_unset(area, level, AF_INET, type, 0); + + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/redistribute/ipv4/route-map + * XPath: /frr-isisd:isis/instance/redistribute/ipv4/table/route-map + */ +int isis_instance_redistribute_ipv4_route_map_modify( + struct nb_cb_modify_args *args) +{ + /* It's all done by redistribute_apply_finish */ + return NB_OK; +} + +int isis_instance_redistribute_ipv4_route_map_destroy( + struct nb_cb_destroy_args *args) +{ + /* It's all done by redistribute_apply_finish */ + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/redistribute/ipv4/metric + * XPath: /frr-isisd:isis/instance/redistribute/ipv4/table/metric + */ +int isis_instance_redistribute_ipv4_metric_modify( + struct nb_cb_modify_args *args) +{ + /* It's all done by redistribute_apply_finish */ + return NB_OK; +} + +int isis_instance_redistribute_ipv4_metric_destroy(struct nb_cb_destroy_args *args) +{ + /* It's all done by redistribute_apply_finish */ + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/redistribute/ipv4/table + */ +int isis_instance_redistribute_ipv4_table_create(struct nb_cb_create_args *args) +{ + uint16_t table; + int type, level; + unsigned long metric = 0; + const char *routemap = NULL; + struct isis_area *area; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + type = yang_dnode_get_enum(args->dnode, "../protocol"); + level = yang_dnode_get_enum(args->dnode, "../level"); + area = nb_running_get_entry(args->dnode, "../.", true); + + if (yang_dnode_exists(args->dnode, "./metric")) + metric = yang_dnode_get_uint32(args->dnode, "./metric"); + if (yang_dnode_exists(args->dnode, "./route-map")) + routemap = yang_dnode_get_string(args->dnode, "./route-map"); + + table = yang_dnode_get_uint16(args->dnode, "./table"); + isis_redist_set(area, level, AF_INET, type, metric, routemap, 0, table); + + return NB_OK; +} +int isis_instance_redistribute_ipv4_table_destroy(struct nb_cb_destroy_args *args) +{ + struct isis_area *area; + int level, type; + uint16_t table; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + area = nb_running_get_entry(args->dnode, "../.", true); + level = yang_dnode_get_enum(args->dnode, "../level"); + type = yang_dnode_get_enum(args->dnode, "../protocol"); + table = yang_dnode_get_uint16(args->dnode, "./table"); + isis_redist_unset(area, level, AF_INET, type, table); + + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/redistribute/ipv6 + */ +int isis_instance_redistribute_ipv6_create(struct nb_cb_create_args *args) +{ + /* It's all done by redistribute_apply_finish */ + return NB_OK; +} + +int isis_instance_redistribute_ipv6_destroy(struct nb_cb_destroy_args *args) +{ + struct isis_area *area; + int level, type; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + area = nb_running_get_entry(args->dnode, NULL, true); + level = yang_dnode_get_enum(args->dnode, "./level"); + type = yang_dnode_get_enum(args->dnode, "./protocol"); + isis_redist_unset(area, level, AF_INET6, type, 0); + + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/redistribute/ipv6/route-map + */ +int isis_instance_redistribute_ipv6_route_map_modify( + struct nb_cb_modify_args *args) +{ + /* It's all done by redistribute_apply_finish */ + return NB_OK; +} + +int isis_instance_redistribute_ipv6_route_map_destroy( + struct nb_cb_destroy_args *args) +{ + /* It's all done by redistribute_apply_finish */ + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/redistribute/ipv6/metric + */ +int isis_instance_redistribute_ipv6_metric_modify( + struct nb_cb_modify_args *args) +{ + /* It's all done by redistribute_apply_finish */ + return NB_OK; +} + +int isis_instance_redistribute_ipv6_metric_destroy(struct nb_cb_destroy_args *args) +{ + /* It's all done by redistribute_apply_finish */ + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/redistribute/ipv6/table + */ +int isis_instance_redistribute_ipv6_table_create(struct nb_cb_create_args *args) +{ + if (args->event != NB_EV_APPLY) + return NB_OK; + + /* TODO */ + return NB_OK; +} + +int isis_instance_redistribute_ipv6_table_destroy(struct nb_cb_destroy_args *args) +{ + if (args->event != NB_EV_APPLY) + return NB_OK; + + /* TODO */ + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/multi-topology/ipv4-multicast + */ +static int isis_multi_topology_common(enum nb_event event, + const struct lyd_node *dnode, + char *errmsg, size_t errmsg_len, + const char *topology, bool create) +{ + struct isis_area *area; + struct isis_area_mt_setting *setting; + uint16_t mtid = isis_str2mtid(topology); + + switch (event) { + case NB_EV_VALIDATE: + if (mtid == (uint16_t)-1) { + snprintf(errmsg, errmsg_len, "Unknown topology %s", + topology); + return NB_ERR_VALIDATION; + } + break; + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + area = nb_running_get_entry(dnode, NULL, true); + setting = area_get_mt_setting(area, mtid); + setting->enabled = create; + lsp_regenerate_schedule(area, IS_LEVEL_1 | IS_LEVEL_2, 0); + break; + } + + return NB_OK; +} + +static int isis_multi_topology_overload_common(enum nb_event event, + const struct lyd_node *dnode, + const char *topology) +{ + struct isis_area *area; + struct isis_area_mt_setting *setting; + uint16_t mtid = isis_str2mtid(topology); + + /* validation is done in isis_multi_topology_common */ + if (event != NB_EV_APPLY) + return NB_OK; + + area = nb_running_get_entry(dnode, NULL, true); + setting = area_get_mt_setting(area, mtid); + setting->overload = yang_dnode_get_bool(dnode, NULL); + if (setting->enabled) + lsp_regenerate_schedule(area, IS_LEVEL_1 | IS_LEVEL_2, 0); + + return NB_OK; +} + +int isis_instance_multi_topology_ipv4_multicast_create( + struct nb_cb_create_args *args) +{ + return isis_multi_topology_common(args->event, args->dnode, + args->errmsg, args->errmsg_len, + "ipv4-multicast", true); +} + +int isis_instance_multi_topology_ipv4_multicast_destroy( + struct nb_cb_destroy_args *args) +{ + return isis_multi_topology_common(args->event, args->dnode, + args->errmsg, args->errmsg_len, + "ipv4-multicast", false); +} + +/* + * XPath: /frr-isisd:isis/instance/multi-topology/ipv4-multicast/overload + */ +int isis_instance_multi_topology_ipv4_multicast_overload_modify( + struct nb_cb_modify_args *args) +{ + return isis_multi_topology_overload_common(args->event, args->dnode, + "ipv4-multicast"); +} + +/* + * XPath: /frr-isisd:isis/instance/multi-topology/ipv4-management + */ +int isis_instance_multi_topology_ipv4_management_create( + struct nb_cb_create_args *args) +{ + return isis_multi_topology_common(args->event, args->dnode, + args->errmsg, args->errmsg_len, + "ipv4-mgmt", true); +} + +int isis_instance_multi_topology_ipv4_management_destroy( + struct nb_cb_destroy_args *args) +{ + return isis_multi_topology_common(args->event, args->dnode, + args->errmsg, args->errmsg_len, + "ipv4-mgmt", false); +} + +/* + * XPath: /frr-isisd:isis/instance/multi-topology/ipv4-management/overload + */ +int isis_instance_multi_topology_ipv4_management_overload_modify( + struct nb_cb_modify_args *args) +{ + return isis_multi_topology_overload_common(args->event, args->dnode, + "ipv4-mgmt"); +} + +/* + * XPath: /frr-isisd:isis/instance/multi-topology/ipv6-unicast + */ +int isis_instance_multi_topology_ipv6_unicast_create( + struct nb_cb_create_args *args) +{ + return isis_multi_topology_common(args->event, args->dnode, + args->errmsg, args->errmsg_len, + "ipv6-unicast", true); +} + +int isis_instance_multi_topology_ipv6_unicast_destroy( + struct nb_cb_destroy_args *args) +{ + return isis_multi_topology_common(args->event, args->dnode, + args->errmsg, args->errmsg_len, + "ipv6-unicast", false); +} + +/* + * XPath: /frr-isisd:isis/instance/multi-topology/ipv6-unicast/overload + */ +int isis_instance_multi_topology_ipv6_unicast_overload_modify( + struct nb_cb_modify_args *args) +{ + return isis_multi_topology_overload_common(args->event, args->dnode, + "ipv6-unicast"); +} + +/* + * XPath: /frr-isisd:isis/instance/multi-topology/ipv6-multicast + */ +int isis_instance_multi_topology_ipv6_multicast_create( + struct nb_cb_create_args *args) +{ + return isis_multi_topology_common(args->event, args->dnode, + args->errmsg, args->errmsg_len, + "ipv6-multicast", true); +} + +int isis_instance_multi_topology_ipv6_multicast_destroy( + struct nb_cb_destroy_args *args) +{ + return isis_multi_topology_common(args->event, args->dnode, + args->errmsg, args->errmsg_len, + "ipv6-multicast", false); +} + +/* + * XPath: /frr-isisd:isis/instance/multi-topology/ipv6-multicast/overload + */ +int isis_instance_multi_topology_ipv6_multicast_overload_modify( + struct nb_cb_modify_args *args) +{ + return isis_multi_topology_overload_common(args->event, args->dnode, + "ipv6-multicast"); +} + +/* + * XPath: /frr-isisd:isis/instance/multi-topology/ipv6-management + */ +int isis_instance_multi_topology_ipv6_management_create( + struct nb_cb_create_args *args) +{ + return isis_multi_topology_common(args->event, args->dnode, + args->errmsg, args->errmsg_len, + "ipv6-mgmt", true); +} + +int isis_instance_multi_topology_ipv6_management_destroy( + struct nb_cb_destroy_args *args) +{ + return isis_multi_topology_common(args->event, args->dnode, + args->errmsg, args->errmsg_len, + "ipv6-mgmt", false); +} + +/* + * XPath: /frr-isisd:isis/instance/multi-topology/ipv6-management/overload + */ +int isis_instance_multi_topology_ipv6_management_overload_modify( + struct nb_cb_modify_args *args) +{ + return isis_multi_topology_overload_common(args->event, args->dnode, + "ipv6-mgmt"); +} + +/* + * XPath: /frr-isisd:isis/instance/multi-topology/ipv6-dstsrc + */ +int isis_instance_multi_topology_ipv6_dstsrc_create( + struct nb_cb_create_args *args) +{ + return isis_multi_topology_common(args->event, args->dnode, + args->errmsg, args->errmsg_len, + "ipv6-dstsrc", true); +} + +int isis_instance_multi_topology_ipv6_dstsrc_destroy( + struct nb_cb_destroy_args *args) +{ + return isis_multi_topology_common(args->event, args->dnode, + args->errmsg, args->errmsg_len, + "ipv6-dstsrc", false); +} + +/* + * XPath: /frr-isisd:isis/instance/multi-topology/ipv6-dstsrc/overload + */ +int isis_instance_multi_topology_ipv6_dstsrc_overload_modify( + struct nb_cb_modify_args *args) +{ + return isis_multi_topology_overload_common(args->event, args->dnode, + "ipv6-dstsrc"); +} + +/* + * XPath: /frr-isisd:isis/instance/fast-reroute/level-1/lfa/load-sharing + */ +int isis_instance_fast_reroute_level_1_lfa_load_sharing_modify( + struct nb_cb_modify_args *args) +{ + struct isis_area *area; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + area = nb_running_get_entry(args->dnode, NULL, true); + area->lfa_load_sharing[0] = yang_dnode_get_bool(args->dnode, NULL); + lsp_regenerate_schedule(area, area->is_type, 0); + + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/fast-reroute/level-1/lfa/priority-limit + */ +int isis_instance_fast_reroute_level_1_lfa_priority_limit_modify( + struct nb_cb_modify_args *args) +{ + struct isis_area *area; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + area = nb_running_get_entry(args->dnode, NULL, true); + area->lfa_priority_limit[0] = yang_dnode_get_enum(args->dnode, NULL); + lsp_regenerate_schedule(area, area->is_type, 0); + + return NB_OK; +} + +int isis_instance_fast_reroute_level_1_lfa_priority_limit_destroy( + struct nb_cb_destroy_args *args) +{ + struct isis_area *area; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + area = nb_running_get_entry(args->dnode, NULL, true); + area->lfa_priority_limit[0] = SPF_PREFIX_PRIO_LOW; + lsp_regenerate_schedule(area, area->is_type, 0); + + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/fast-reroute/level-1/lfa/tiebreaker + */ +int isis_instance_fast_reroute_level_1_lfa_tiebreaker_create( + struct nb_cb_create_args *args) +{ + struct isis_area *area; + uint8_t index; + enum lfa_tiebreaker_type type; + struct lfa_tiebreaker *tie_b; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + area = nb_running_get_entry(args->dnode, NULL, true); + index = yang_dnode_get_uint8(args->dnode, "./index"); + type = yang_dnode_get_enum(args->dnode, "./type"); + + tie_b = isis_lfa_tiebreaker_add(area, ISIS_LEVEL1, index, type); + nb_running_set_entry(args->dnode, tie_b); + lsp_regenerate_schedule(area, area->is_type, 0); + + return NB_OK; +} + +int isis_instance_fast_reroute_level_1_lfa_tiebreaker_destroy( + struct nb_cb_destroy_args *args) +{ + struct lfa_tiebreaker *tie_b; + struct isis_area *area; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + tie_b = nb_running_unset_entry(args->dnode); + area = tie_b->area; + isis_lfa_tiebreaker_delete(area, ISIS_LEVEL1, tie_b); + lsp_regenerate_schedule(area, area->is_type, 0); + + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/fast-reroute/level-1/lfa/tiebreaker/type + */ +int isis_instance_fast_reroute_level_1_lfa_tiebreaker_type_modify( + struct nb_cb_modify_args *args) +{ + struct lfa_tiebreaker *tie_b; + struct isis_area *area; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + tie_b = nb_running_get_entry(args->dnode, NULL, true); + area = tie_b->area; + tie_b->type = yang_dnode_get_enum(args->dnode, NULL); + lsp_regenerate_schedule(area, area->is_type, 0); + + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/fast-reroute/level-1/remote-lfa/prefix-list + */ +int isis_instance_fast_reroute_level_1_remote_lfa_prefix_list_modify( + struct nb_cb_modify_args *args) +{ + struct isis_area *area; + const char *plist_name; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + area = nb_running_get_entry(args->dnode, NULL, true); + plist_name = yang_dnode_get_string(args->dnode, NULL); + + area->rlfa_plist_name[0] = XSTRDUP(MTYPE_ISIS_PLIST_NAME, plist_name); + area->rlfa_plist[0] = prefix_list_lookup(AFI_IP, plist_name); + lsp_regenerate_schedule(area, area->is_type, 0); + + return NB_OK; +} + +int isis_instance_fast_reroute_level_1_remote_lfa_prefix_list_destroy( + struct nb_cb_destroy_args *args) +{ + struct isis_area *area; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + area = nb_running_get_entry(args->dnode, NULL, true); + + XFREE(MTYPE_ISIS_PLIST_NAME, area->rlfa_plist_name[0]); + area->rlfa_plist[0] = NULL; + lsp_regenerate_schedule(area, area->is_type, 0); + + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/fast-reroute/level-2/lfa/load-sharing + */ +int isis_instance_fast_reroute_level_2_lfa_load_sharing_modify( + struct nb_cb_modify_args *args) +{ + struct isis_area *area; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + area = nb_running_get_entry(args->dnode, NULL, true); + area->lfa_load_sharing[1] = yang_dnode_get_bool(args->dnode, NULL); + + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/fast-reroute/level-2/lfa/priority-limit + */ +int isis_instance_fast_reroute_level_2_lfa_priority_limit_modify( + struct nb_cb_modify_args *args) +{ + struct isis_area *area; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + area = nb_running_get_entry(args->dnode, NULL, true); + area->lfa_priority_limit[1] = yang_dnode_get_enum(args->dnode, NULL); + + return NB_OK; +} + +int isis_instance_fast_reroute_level_2_lfa_priority_limit_destroy( + struct nb_cb_destroy_args *args) +{ + struct isis_area *area; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + area = nb_running_get_entry(args->dnode, NULL, true); + area->lfa_priority_limit[1] = SPF_PREFIX_PRIO_LOW; + + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/fast-reroute/level-2/lfa/tiebreaker + */ +int isis_instance_fast_reroute_level_2_lfa_tiebreaker_create( + struct nb_cb_create_args *args) +{ + struct isis_area *area; + uint8_t index; + enum lfa_tiebreaker_type type; + struct lfa_tiebreaker *tie_b; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + area = nb_running_get_entry(args->dnode, NULL, true); + index = yang_dnode_get_uint8(args->dnode, "./index"); + type = yang_dnode_get_enum(args->dnode, "./type"); + + tie_b = isis_lfa_tiebreaker_add(area, ISIS_LEVEL2, index, type); + nb_running_set_entry(args->dnode, tie_b); + lsp_regenerate_schedule(area, area->is_type, 0); + + return NB_OK; +} + +int isis_instance_fast_reroute_level_2_lfa_tiebreaker_destroy( + struct nb_cb_destroy_args *args) +{ + struct lfa_tiebreaker *tie_b; + struct isis_area *area; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + tie_b = nb_running_unset_entry(args->dnode); + area = tie_b->area; + isis_lfa_tiebreaker_delete(area, ISIS_LEVEL2, tie_b); + lsp_regenerate_schedule(area, area->is_type, 0); + + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/fast-reroute/level-2/lfa/tiebreaker/type + */ +int isis_instance_fast_reroute_level_2_lfa_tiebreaker_type_modify( + struct nb_cb_modify_args *args) +{ + struct lfa_tiebreaker *tie_b; + struct isis_area *area; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + tie_b = nb_running_get_entry(args->dnode, NULL, true); + area = tie_b->area; + tie_b->type = yang_dnode_get_enum(args->dnode, NULL); + lsp_regenerate_schedule(area, area->is_type, 0); + + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/fast-reroute/level-2/remote-lfa/prefix-list + */ +int isis_instance_fast_reroute_level_2_remote_lfa_prefix_list_modify( + struct nb_cb_modify_args *args) +{ + struct isis_area *area; + const char *plist_name; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + area = nb_running_get_entry(args->dnode, NULL, true); + plist_name = yang_dnode_get_string(args->dnode, NULL); + + area->rlfa_plist_name[1] = XSTRDUP(MTYPE_ISIS_PLIST_NAME, plist_name); + area->rlfa_plist[1] = prefix_list_lookup(AFI_IP, plist_name); + lsp_regenerate_schedule(area, area->is_type, 0); + + return NB_OK; +} + +int isis_instance_fast_reroute_level_2_remote_lfa_prefix_list_destroy( + struct nb_cb_destroy_args *args) +{ + struct isis_area *area; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + area = nb_running_get_entry(args->dnode, NULL, true); + + XFREE(MTYPE_ISIS_PLIST_NAME, area->rlfa_plist_name[1]); + area->rlfa_plist[1] = NULL; + lsp_regenerate_schedule(area, area->is_type, 0); + + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/log-adjacency-changes + */ +int isis_instance_log_adjacency_changes_modify(struct nb_cb_modify_args *args) +{ + struct isis_area *area; + bool log = yang_dnode_get_bool(args->dnode, NULL); + + if (args->event != NB_EV_APPLY) + return NB_OK; + + area = nb_running_get_entry(args->dnode, NULL, true); + area->log_adj_changes = log ? 1 : 0; + + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/log-pdu-drops + */ +int isis_instance_log_pdu_drops_modify(struct nb_cb_modify_args *args) +{ + struct isis_area *area; + bool log = yang_dnode_get_bool(args->dnode, NULL); + + if (args->event != NB_EV_APPLY) + return NB_OK; + + area = nb_running_get_entry(args->dnode, NULL, true); + area->log_pdu_drops = log ? 1 : 0; + + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/mpls-te + */ +int isis_instance_mpls_te_create(struct nb_cb_create_args *args) +{ + struct isis_area *area; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + area = nb_running_get_entry(args->dnode, NULL, true); + isis_mpls_te_create(area); + + /* Reoriginate STD_TE & GMPLS circuits */ + lsp_regenerate_schedule(area, area->is_type, 0); + + return NB_OK; +} + +int isis_instance_mpls_te_destroy(struct nb_cb_destroy_args *args) +{ + struct isis_area *area; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + area = nb_running_get_entry(args->dnode, NULL, true); + if (!IS_MPLS_TE(area->mta)) + return NB_OK; + + isis_mpls_te_disable(area); + + /* Reoriginate STD_TE & GMPLS circuits */ + lsp_regenerate_schedule(area, area->is_type, 0); + + zlog_debug("ISIS-TE(%s): Disabled MPLS Traffic Engineering", + area->area_tag); + + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/mpls-te/router-address + */ +int isis_instance_mpls_te_router_address_modify(struct nb_cb_modify_args *args) +{ + struct in_addr value; + struct isis_area *area; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + area = nb_running_get_entry(args->dnode, NULL, true); + /* only proceed if MPLS-TE is enabled */ + if (!IS_MPLS_TE(area->mta)) + return NB_OK; + + /* Update Area Router ID */ + yang_dnode_get_ipv4(&value, args->dnode, NULL); + area->mta->router_id.s_addr = value.s_addr; + + /* And re-schedule LSP update */ + lsp_regenerate_schedule(area, area->is_type, 0); + + return NB_OK; +} + +int isis_instance_mpls_te_router_address_destroy( + struct nb_cb_destroy_args *args) +{ + struct isis_area *area; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + area = nb_running_get_entry(args->dnode, NULL, true); + /* only proceed if MPLS-TE is enabled */ + if (!IS_MPLS_TE(area->mta)) + return NB_OK; + + /* Reset Area Router ID */ + area->mta->router_id.s_addr = INADDR_ANY; + + /* And re-schedule LSP update */ + lsp_regenerate_schedule(area, area->is_type, 0); + + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/mpls-te/router-address-v6 + */ +int isis_instance_mpls_te_router_address_ipv6_modify( + struct nb_cb_modify_args *args) +{ + struct in6_addr value; + struct isis_area *area; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + area = nb_running_get_entry(args->dnode, NULL, true); + /* only proceed if MPLS-TE is enabled */ + if (!IS_MPLS_TE(area->mta)) + return NB_OK; + + yang_dnode_get_ipv6(&value, args->dnode, NULL); + /* Update Area IPv6 Router ID if different */ + if (!IPV6_ADDR_SAME(&area->mta->router_id_ipv6, &value)) { + IPV6_ADDR_COPY(&area->mta->router_id_ipv6, &value); + + /* And re-schedule LSP update */ + lsp_regenerate_schedule(area, area->is_type, 0); + } + + return NB_OK; +} + +int isis_instance_mpls_te_router_address_ipv6_destroy( + struct nb_cb_destroy_args *args) +{ + struct isis_area *area; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + area = nb_running_get_entry(args->dnode, NULL, true); + /* only proceed if MPLS-TE is enabled */ + if (!IS_MPLS_TE(area->mta)) + return NB_OK; + + /* Reset Area Router ID */ + IPV6_ADDR_COPY(&area->mta->router_id_ipv6, &in6addr_any); + + /* And re-schedule LSP update */ + lsp_regenerate_schedule(area, area->is_type, 0); + + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/mpls-te/export + */ +int isis_instance_mpls_te_export_modify(struct nb_cb_modify_args *args) +{ + struct isis_area *area; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + area = nb_running_get_entry(args->dnode, NULL, true); + /* only proceed if MPLS-TE is enabled */ + if (!IS_MPLS_TE(area->mta)) + return NB_OK; + + area->mta->export = yang_dnode_get_bool(args->dnode, NULL); + if (area->mta->export) { + if (IS_DEBUG_EVENTS) + zlog_debug("MPLS-TE: Enabled Link State export"); + if (isis_zebra_ls_register(true) != 0) + zlog_warn("Unable to register Link State"); + } else { + if (IS_DEBUG_EVENTS) + zlog_debug("MPLS-TE: Disable Link State export"); + if (isis_zebra_ls_register(false) != 0) + zlog_warn("Unable to register Link State"); + } + + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/segment-routing/enabled + */ +int isis_instance_segment_routing_enabled_modify( + struct nb_cb_modify_args *args) +{ + struct isis_area *area; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + area = nb_running_get_entry(args->dnode, NULL, true); + area->srdb.config.enabled = yang_dnode_get_bool(args->dnode, NULL); + + if (area->srdb.config.enabled) { + if (IS_DEBUG_EVENTS) + zlog_debug("SR: Segment Routing: OFF -> ON"); + + isis_sr_start(area); + } else { + if (IS_DEBUG_EVENTS) + zlog_debug("SR: Segment Routing: ON -> OFF"); + + isis_sr_stop(area); + } + + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/segment-routing/label-blocks + */ +int isis_instance_segment_routing_label_blocks_pre_validate( + struct nb_cb_pre_validate_args *args) +{ + uint32_t srgb_lbound; + uint32_t srgb_ubound; + uint32_t srlb_lbound; + uint32_t srlb_ubound; + + srgb_lbound = yang_dnode_get_uint32(args->dnode, "./srgb/lower-bound"); + srgb_ubound = yang_dnode_get_uint32(args->dnode, "./srgb/upper-bound"); + srlb_lbound = yang_dnode_get_uint32(args->dnode, "./srlb/lower-bound"); + srlb_ubound = yang_dnode_get_uint32(args->dnode, "./srlb/upper-bound"); + + /* Check that the block size does not exceed 65535 */ + if ((srgb_ubound - srgb_lbound + 1) > 65535) { + snprintf( + args->errmsg, args->errmsg_len, + "New SR Global Block (%u/%u) exceed the limit of 65535", + srgb_lbound, srgb_ubound); + return NB_ERR_VALIDATION; + } + if ((srlb_ubound - srlb_lbound + 1) > 65535) { + snprintf(args->errmsg, args->errmsg_len, + "New SR Local Block (%u/%u) exceed the limit of 65535", + srlb_lbound, srlb_ubound); + return NB_ERR_VALIDATION; + } + + /* Validate SRGB against SRLB */ + if (!((srgb_ubound < srlb_lbound) || (srgb_lbound > srlb_ubound))) { + snprintf( + args->errmsg, args->errmsg_len, + "SR Global Block (%u/%u) conflicts with Local Block (%u/%u)", + srgb_lbound, srgb_ubound, srlb_lbound, srlb_ubound); + return NB_ERR_VALIDATION; + } + + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/segment-routing/label-blocks/srgb + */ + +void isis_instance_segment_routing_srgb_apply_finish( + struct nb_cb_apply_finish_args *args) +{ + struct isis_area *area; + uint32_t lower_bound, upper_bound; + + area = nb_running_get_entry(args->dnode, NULL, true); + lower_bound = yang_dnode_get_uint32(args->dnode, "./lower-bound"); + upper_bound = yang_dnode_get_uint32(args->dnode, "./upper-bound"); + + isis_sr_cfg_srgb_update(area, lower_bound, upper_bound); +} + +/* + * XPath: /frr-isisd:isis/instance/segment-routing/label-blocks/srgb/lower-bound + */ +int isis_instance_segment_routing_srgb_lower_bound_modify( + struct nb_cb_modify_args *args) +{ + uint32_t lower_bound = yang_dnode_get_uint32(args->dnode, NULL); + + switch (args->event) { + case NB_EV_VALIDATE: + if (!IS_MPLS_UNRESERVED_LABEL(lower_bound)) { + snprintf(args->errmsg, args->errmsg_len, + "Invalid SRGB lower bound: %u", lower_bound); + return NB_ERR_VALIDATION; + } + break; + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/segment-routing/label-blocks/srgb/upper-bound + */ +int isis_instance_segment_routing_srgb_upper_bound_modify( + struct nb_cb_modify_args *args) +{ + uint32_t upper_bound = yang_dnode_get_uint32(args->dnode, NULL); + + switch (args->event) { + case NB_EV_VALIDATE: + if (!IS_MPLS_UNRESERVED_LABEL(upper_bound)) { + snprintf(args->errmsg, args->errmsg_len, + "Invalid SRGB upper bound: %u", upper_bound); + return NB_ERR_VALIDATION; + } + break; + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/segment-routing/label-blocks/srlb + */ +void isis_instance_segment_routing_srlb_apply_finish( + struct nb_cb_apply_finish_args *args) +{ + struct isis_area *area; + uint32_t lower_bound, upper_bound; + + area = nb_running_get_entry(args->dnode, NULL, true); + lower_bound = yang_dnode_get_uint32(args->dnode, "./lower-bound"); + upper_bound = yang_dnode_get_uint32(args->dnode, "./upper-bound"); + + isis_sr_cfg_srlb_update(area, lower_bound, upper_bound); +} + +/* + * XPath: /frr-isisd:isis/instance/segment-routing/label-blocks/srlb/lower-bound + */ +int isis_instance_segment_routing_srlb_lower_bound_modify( + struct nb_cb_modify_args *args) +{ + uint32_t lower_bound = yang_dnode_get_uint32(args->dnode, NULL); + + switch (args->event) { + case NB_EV_VALIDATE: + if (!IS_MPLS_UNRESERVED_LABEL(lower_bound)) { + snprintf(args->errmsg, args->errmsg_len, + "Invalid SRLB lower bound: %u", lower_bound); + return NB_ERR_VALIDATION; + } + break; + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/segment-routing/label-blocks/srlb/upper-bound + */ +int isis_instance_segment_routing_srlb_upper_bound_modify( + struct nb_cb_modify_args *args) +{ + uint32_t upper_bound = yang_dnode_get_uint32(args->dnode, NULL); + + switch (args->event) { + case NB_EV_VALIDATE: + if (!IS_MPLS_UNRESERVED_LABEL(upper_bound)) { + snprintf(args->errmsg, args->errmsg_len, + "Invalid SRLB upper bound: %u", upper_bound); + return NB_ERR_VALIDATION; + } + break; + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/segment-routing/msd/node-msd + */ +int isis_instance_segment_routing_msd_node_msd_modify( + struct nb_cb_modify_args *args) +{ + struct isis_area *area; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + area = nb_running_get_entry(args->dnode, NULL, true); + area->srdb.config.msd = yang_dnode_get_uint8(args->dnode, NULL); + + /* Update and regenerate LSP */ + lsp_regenerate_schedule(area, area->is_type, 0); + + return NB_OK; +} + +int isis_instance_segment_routing_msd_node_msd_destroy( + struct nb_cb_destroy_args *args) +{ + struct isis_area *area; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + area = nb_running_get_entry(args->dnode, NULL, true); + area->srdb.config.msd = 0; + + /* Update and regenerate LSP */ + lsp_regenerate_schedule(area, area->is_type, 0); + + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/segment-routing/prefix-sid-map/prefix-sid + */ +int isis_instance_segment_routing_prefix_sid_map_prefix_sid_create( + struct nb_cb_create_args *args) +{ + struct isis_area *area; + struct prefix prefix; + struct sr_prefix_cfg *pcfg; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + area = nb_running_get_entry(args->dnode, NULL, true); + yang_dnode_get_prefix(&prefix, args->dnode, "./prefix"); + + pcfg = isis_sr_cfg_prefix_add(area, &prefix, SR_ALGORITHM_SPF); + nb_running_set_entry(args->dnode, pcfg); + + return NB_OK; +} + +int isis_instance_segment_routing_prefix_sid_map_prefix_sid_destroy( + struct nb_cb_destroy_args *args) +{ + struct sr_prefix_cfg *pcfg; + struct isis_area *area; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + pcfg = nb_running_unset_entry(args->dnode); + area = pcfg->area; + isis_sr_cfg_prefix_del(pcfg); + lsp_regenerate_schedule(area, area->is_type, 0); + + return NB_OK; +} + +int isis_instance_segment_routing_prefix_sid_map_prefix_sid_pre_validate( + struct nb_cb_pre_validate_args *args) +{ + const struct lyd_node *area_dnode; + struct isis_area *area; + struct prefix prefix; + uint32_t srgb_lbound; + uint32_t srgb_ubound; + uint32_t srgb_range; + uint32_t sid; + enum sr_sid_value_type sid_type; + struct isis_prefix_sid psid = {}; + + yang_dnode_get_prefix(&prefix, args->dnode, "./prefix"); + srgb_lbound = yang_dnode_get_uint32( + args->dnode, "../../label-blocks/srgb/lower-bound"); + srgb_ubound = yang_dnode_get_uint32( + args->dnode, "../../label-blocks/srgb/upper-bound"); + sid = yang_dnode_get_uint32(args->dnode, "./sid-value"); + sid_type = yang_dnode_get_enum(args->dnode, "./sid-value-type"); + + /* Check for invalid indexes/labels. */ + srgb_range = srgb_ubound - srgb_lbound + 1; + psid.value = sid; + switch (sid_type) { + case SR_SID_VALUE_TYPE_INDEX: + if (sid >= srgb_range) { + snprintf(args->errmsg, args->errmsg_len, + "SID index %u falls outside local SRGB range", + sid); + return NB_ERR_VALIDATION; + } + break; + case SR_SID_VALUE_TYPE_ABSOLUTE: + if (!IS_MPLS_UNRESERVED_LABEL(sid)) { + snprintf(args->errmsg, args->errmsg_len, + "Invalid absolute SID %u", sid); + return NB_ERR_VALIDATION; + } + SET_FLAG(psid.flags, ISIS_PREFIX_SID_VALUE); + SET_FLAG(psid.flags, ISIS_PREFIX_SID_LOCAL); + break; + } + + /* Check for Prefix-SID collisions. */ + area_dnode = yang_dnode_get_parent(args->dnode, "instance"); + area = nb_running_get_entry(area_dnode, NULL, false); + if (area) { + for (int tree = SPFTREE_IPV4; tree < SPFTREE_COUNT; tree++) { + for (int level = ISIS_LEVEL1; level <= ISIS_LEVEL2; + level++) { + struct isis_spftree *spftree; + struct isis_vertex *vertex_psid; + + if (!(area->is_type & level)) + continue; + spftree = area->spftree[tree][level - 1]; + if (!spftree) + continue; + + vertex_psid = isis_spf_prefix_sid_lookup( + spftree, &psid); + if (vertex_psid + && !prefix_same(&vertex_psid->N.ip.p.dest, + &prefix)) { + snprintfrr( + args->errmsg, args->errmsg_len, + "Prefix-SID collision detected, SID %s %u is already in use by prefix %pFX (L%u)", + CHECK_FLAG( + psid.flags, + ISIS_PREFIX_SID_VALUE) + ? "label" + : "index", + psid.value, + &vertex_psid->N.ip.p.dest, + level); + return NB_ERR_VALIDATION; + } + } + } + } + + return NB_OK; +} + +void isis_instance_segment_routing_prefix_sid_map_prefix_sid_apply_finish( + struct nb_cb_apply_finish_args *args) +{ + struct sr_prefix_cfg *pcfg; + struct isis_area *area; + + pcfg = nb_running_get_entry(args->dnode, NULL, true); + area = pcfg->area; + lsp_regenerate_schedule(area, area->is_type, 0); +} + +/* + * XPath: + * /frr-isisd:isis/instance/segment-routing/prefix-sid-map/prefix-sid/sid-value-type + */ +int isis_instance_segment_routing_prefix_sid_map_prefix_sid_sid_value_type_modify( + struct nb_cb_modify_args *args) +{ + struct sr_prefix_cfg *pcfg; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + pcfg = nb_running_get_entry(args->dnode, NULL, true); + pcfg->sid_type = yang_dnode_get_enum(args->dnode, NULL); + + return NB_OK; +} + +/* + * XPath: + * /frr-isisd:isis/instance/segment-routing/prefix-sid-map/prefix-sid/sid-value + */ +int isis_instance_segment_routing_prefix_sid_map_prefix_sid_sid_value_modify( + struct nb_cb_modify_args *args) +{ + struct sr_prefix_cfg *pcfg; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + pcfg = nb_running_get_entry(args->dnode, NULL, true); + pcfg->sid = yang_dnode_get_uint32(args->dnode, NULL); + + return NB_OK; +} + +/* + * XPath: + * /frr-isisd:isis/instance/segment-routing/prefix-sid-map/prefix-sid/last-hop-behavior + */ +int isis_instance_segment_routing_prefix_sid_map_prefix_sid_last_hop_behavior_modify( + struct nb_cb_modify_args *args) +{ + struct sr_prefix_cfg *pcfg; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + pcfg = nb_running_get_entry(args->dnode, NULL, true); + pcfg->last_hop_behavior = yang_dnode_get_enum(args->dnode, NULL); + + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/segment-routing/prefix-sid-map/prefix-sid/n-flag-clear + */ +int isis_instance_segment_routing_prefix_sid_map_prefix_sid_n_flag_clear_modify( + struct nb_cb_modify_args *args) +{ + struct sr_prefix_cfg *pcfg; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + pcfg = nb_running_get_entry(args->dnode, NULL, true); + pcfg->n_flag_clear = yang_dnode_get_bool(args->dnode, NULL); + + return NB_OK; +} + +/* + * XPath: + * /frr-isisd:isis/instance/segment-routing/algorithm-prefix-sids/algorithm-prefix-sid + */ +int isis_instance_segment_routing_algorithm_prefix_sid_create( + struct nb_cb_create_args *args) +{ + struct isis_area *area; + struct prefix prefix; + struct sr_prefix_cfg *pcfg; + uint32_t algorithm; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + area = nb_running_get_entry(args->dnode, NULL, true); + yang_dnode_get_prefix(&prefix, args->dnode, "./prefix"); + algorithm = yang_dnode_get_uint32(args->dnode, "./algo"); + + pcfg = isis_sr_cfg_prefix_add(area, &prefix, algorithm); + pcfg->algorithm = algorithm; + nb_running_set_entry(args->dnode, pcfg); + + return NB_OK; +} + +int isis_instance_segment_routing_algorithm_prefix_sid_destroy( + struct nb_cb_destroy_args *args) +{ + struct sr_prefix_cfg *pcfg; + struct isis_area *area; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + pcfg = nb_running_unset_entry(args->dnode); + area = pcfg->area; + isis_sr_cfg_prefix_del(pcfg); + lsp_regenerate_schedule(area, area->is_type, 0); + + return NB_OK; +} + +int isis_instance_segment_routing_algorithm_prefix_sid_pre_validate( + struct nb_cb_pre_validate_args *args) +{ + const struct lyd_node *area_dnode; + struct isis_area *area; + struct prefix prefix; + uint32_t srgb_lbound; + uint32_t srgb_ubound; + uint32_t srgb_range; + uint32_t sid; + enum sr_sid_value_type sid_type; + struct isis_prefix_sid psid = {}; + + yang_dnode_get_prefix(&prefix, args->dnode, "./prefix"); + srgb_lbound = yang_dnode_get_uint32( + args->dnode, "../../label-blocks/srgb/lower-bound"); + srgb_ubound = yang_dnode_get_uint32( + args->dnode, "../../label-blocks/srgb/upper-bound"); + sid = yang_dnode_get_uint32(args->dnode, "./sid-value"); + sid_type = yang_dnode_get_enum(args->dnode, "./sid-value-type"); + + /* Check for invalid indexes/labels. */ + srgb_range = srgb_ubound - srgb_lbound + 1; + psid.value = sid; + switch (sid_type) { + case SR_SID_VALUE_TYPE_INDEX: + if (sid >= srgb_range) { + snprintf(args->errmsg, args->errmsg_len, + "SID index %u falls outside local SRGB range", + sid); + return NB_ERR_VALIDATION; + } + break; + case SR_SID_VALUE_TYPE_ABSOLUTE: + if (!IS_MPLS_UNRESERVED_LABEL(sid)) { + snprintf(args->errmsg, args->errmsg_len, + "Invalid absolute SID %u", sid); + return NB_ERR_VALIDATION; + } + SET_FLAG(psid.flags, ISIS_PREFIX_SID_VALUE); + SET_FLAG(psid.flags, ISIS_PREFIX_SID_LOCAL); + break; + } + + /* Check for Prefix-SID collisions. */ + area_dnode = yang_dnode_get_parent(args->dnode, "instance"); + area = nb_running_get_entry(area_dnode, NULL, false); + if (!area) + return NB_OK; + + for (int tree = SPFTREE_IPV4; tree < SPFTREE_COUNT; tree++) { + for (int level = ISIS_LEVEL1; level <= ISIS_LEVEL2; level++) { + struct isis_spftree *spftree; + struct isis_vertex *vertex_psid; + + if (!(area->is_type & level)) + continue; + spftree = area->spftree[tree][level - 1]; + if (!spftree) + continue; + + vertex_psid = + isis_spf_prefix_sid_lookup(spftree, &psid); + if (vertex_psid && + !prefix_same(&vertex_psid->N.ip.p.dest, &prefix)) { + snprintfrr( + args->errmsg, args->errmsg_len, + "Prefix-SID collision detected, SID %s %u is already in use by prefix %pFX (L%u)", + CHECK_FLAG(psid.flags, + ISIS_PREFIX_SID_VALUE) + ? "label" + : "index", + psid.value, &vertex_psid->N.ip.p.dest, + level); + return NB_ERR_VALIDATION; + } + } + } + + return NB_OK; +} + +void isis_instance_segment_routing_algorithm_prefix_sid_apply_finish( + struct nb_cb_apply_finish_args *args) +{ + struct sr_prefix_cfg *pcfg; + struct isis_area *area; + + pcfg = nb_running_get_entry(args->dnode, NULL, true); + area = pcfg->area; + lsp_regenerate_schedule(area, area->is_type, 0); +} + +/* + * XPath: + * /frr-isisd:isis/instance/segment-routing/algorithm-prefix-sids/algorithm-prefix-sid/sid-value-type + */ +int isis_instance_segment_routing_algorithm_prefix_sid_sid_value_type_modify( + struct nb_cb_modify_args *args) +{ + struct sr_prefix_cfg *pcfg; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + pcfg = nb_running_get_entry(args->dnode, NULL, true); + pcfg->sid_type = yang_dnode_get_enum(args->dnode, NULL); + + return NB_OK; +} + +/* + * XPath: + * /frr-isisd:isis/instance/segment-routing/algorithm-prefix-sids/algorithm-prefix-sid/sid-value + */ +int isis_instance_segment_routing_algorithm_prefix_sid_sid_value_modify( + struct nb_cb_modify_args *args) +{ + struct sr_prefix_cfg *pcfg; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + pcfg = nb_running_get_entry(args->dnode, NULL, true); + pcfg->sid = yang_dnode_get_uint32(args->dnode, NULL); + + return NB_OK; +} + +/* + * XPath: + * /frr-isisd:isis/instance/segment-routing/algorithm-prefix-sid-map/algorithm-prefix-sid/last-hop-behavior + */ +int isis_instance_segment_routing_algorithm_prefix_sid_last_hop_behavior_modify( + struct nb_cb_modify_args *args) +{ + struct sr_prefix_cfg *pcfg; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + pcfg = nb_running_get_entry(args->dnode, NULL, true); + pcfg->last_hop_behavior = yang_dnode_get_enum(args->dnode, NULL); + + return NB_OK; +} + +/* + * XPath: + * /frr-isisd:isis/instance/segment-routing/algorithm-prefix-sids/algorithm-prefix-sid/n-flag-clear + */ +int isis_instance_segment_routing_algorithm_prefix_sid_n_flag_clear_modify( + struct nb_cb_modify_args *args) +{ + struct sr_prefix_cfg *pcfg; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + pcfg = nb_running_get_entry(args->dnode, NULL, true); + pcfg->n_flag_clear = yang_dnode_get_bool(args->dnode, NULL); + + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/flex-algos/flex-algo + */ +int isis_instance_flex_algo_create(struct nb_cb_create_args *args) +{ + struct isis_area *area; + struct flex_algo *fa; + bool advertise; + uint32_t algorithm; + uint32_t priority = FLEX_ALGO_PRIO_DEFAULT; + struct isis_flex_algo_alloc_arg arg; + + algorithm = yang_dnode_get_uint32(args->dnode, "./flex-algo"); + advertise = yang_dnode_exists(args->dnode, "./advertise-definition"); + + switch (args->event) { + case NB_EV_APPLY: + area = nb_running_get_entry(args->dnode, NULL, true); + arg.algorithm = algorithm; + arg.area = area; + fa = flex_algo_alloc(area->flex_algos, algorithm, &arg); + fa->priority = priority; + fa->advertise_definition = advertise; + if (area->admin_group_send_zero) { + admin_group_allow_explicit_zero( + &fa->admin_group_exclude_any); + admin_group_allow_explicit_zero( + &fa->admin_group_include_any); + admin_group_allow_explicit_zero( + &fa->admin_group_include_all); + } + lsp_regenerate_schedule(area, area->is_type, 0); + break; + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + } + + return NB_OK; +} + +int isis_instance_flex_algo_destroy(struct nb_cb_destroy_args *args) +{ + struct isis_area *area; + uint32_t algorithm; + + algorithm = yang_dnode_get_uint32(args->dnode, "./flex-algo"); + area = nb_running_get_entry(args->dnode, NULL, true); + + switch (args->event) { + case NB_EV_APPLY: + flex_algo_delete(area->flex_algos, algorithm); + lsp_regenerate_schedule(area, area->is_type, 0); + break; + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/flex-algos/flex-algo/advertise-definition + */ +int isis_instance_flex_algo_advertise_definition_modify( + struct nb_cb_modify_args *args) +{ + struct isis_area *area; + struct flex_algo *fa; + bool advertise; + uint32_t algorithm; + + + algorithm = yang_dnode_get_uint32(args->dnode, "./../flex-algo"); + advertise = yang_dnode_exists(args->dnode, "./../advertise-definition"); + + switch (args->event) { + case NB_EV_APPLY: + area = nb_running_get_entry(args->dnode, NULL, true); + fa = flex_algo_lookup(area->flex_algos, algorithm); + if (!fa) { + snprintf(args->errmsg, args->errmsg_len, + "flex-algo object not found"); + return NB_ERR_RESOURCE; + } + fa->advertise_definition = advertise; + lsp_regenerate_schedule(area, area->is_type, 0); + break; + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + } + + return NB_OK; +} + +int isis_instance_flex_algo_advertise_definition_destroy( + struct nb_cb_destroy_args *args) +{ + struct isis_area *area; + struct flex_algo *fa; + uint32_t algorithm; + + area = nb_running_get_entry(args->dnode, NULL, true); + + algorithm = yang_dnode_get_uint32(args->dnode, "./../flex-algo"); + + switch (args->event) { + case NB_EV_APPLY: + fa = flex_algo_lookup(area->flex_algos, algorithm); + if (!fa) { + snprintf(args->errmsg, args->errmsg_len, + "flex-algo object not found"); + return NB_ERR_RESOURCE; + } + fa->advertise_definition = false; + lsp_regenerate_schedule(area, area->is_type, 0); + break; + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + } + + return NB_OK; +} + +static int isis_instance_flex_algo_affinity_set(struct nb_cb_create_args *args, + int type) +{ + struct affinity_map *map; + struct isis_area *area; + struct admin_group *ag; + struct flex_algo *fa; + uint32_t algorithm; + const char *val; + + algorithm = yang_dnode_get_uint32(args->dnode, "../../flex-algo"); + area = nb_running_get_entry(args->dnode, NULL, true); + val = yang_dnode_get_string(args->dnode, "."); + + switch (args->event) { + case NB_EV_VALIDATE: + fa = flex_algo_lookup(area->flex_algos, algorithm); + if (!fa) { + snprintf(args->errmsg, args->errmsg_len, + "flex-algo object not found"); + return NB_ERR_RESOURCE; + } + map = affinity_map_get(val); + if (!map) { + snprintf(args->errmsg, args->errmsg_len, + "affinity map %s isn't found", val); + return NB_ERR_VALIDATION; + } + break; + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + fa = flex_algo_lookup(area->flex_algos, algorithm); + if (!fa) { + snprintf(args->errmsg, args->errmsg_len, + "flex-algo object not found"); + return NB_ERR_RESOURCE; + } + map = affinity_map_get(val); + if (!map) { + snprintf(args->errmsg, args->errmsg_len, + "affinity map %s isn't found", val); + return NB_ERR_RESOURCE; + } + if (type == AFFINITY_INCLUDE_ANY) + ag = &fa->admin_group_include_any; + else if (type == AFFINITY_INCLUDE_ALL) + ag = &fa->admin_group_include_all; + else if (type == AFFINITY_EXCLUDE_ANY) + ag = &fa->admin_group_exclude_any; + else + break; + + admin_group_set(ag, map->bit_position); + lsp_regenerate_schedule(area, area->is_type, 0); + break; + } + + return NB_OK; +} + +static int +isis_instance_flex_algo_affinity_unset(struct nb_cb_destroy_args *args, + int type) +{ + struct affinity_map *map; + struct isis_area *area; + struct admin_group *ag; + struct flex_algo *fa; + uint32_t algorithm; + const char *val; + + algorithm = yang_dnode_get_uint32(args->dnode, "../../flex-algo"); + area = nb_running_get_entry(args->dnode, NULL, true); + val = yang_dnode_get_string(args->dnode, "."); + + switch (args->event) { + case NB_EV_VALIDATE: + fa = flex_algo_lookup(area->flex_algos, algorithm); + if (!fa) { + snprintf(args->errmsg, args->errmsg_len, + "flex-algo object not found"); + return NB_ERR_RESOURCE; + } + map = affinity_map_get(val); + if (!map) { + snprintf(args->errmsg, args->errmsg_len, + "affinity map %s isn't found", val); + return NB_ERR_VALIDATION; + } + break; + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + fa = flex_algo_lookup(area->flex_algos, algorithm); + if (!fa) { + snprintf(args->errmsg, args->errmsg_len, + "flex-algo object not found"); + return NB_ERR_RESOURCE; + } + map = affinity_map_get(val); + if (!map) { + snprintf(args->errmsg, args->errmsg_len, + "affinity map %s isn't found", val); + return NB_ERR_RESOURCE; + } + if (type == AFFINITY_INCLUDE_ANY) + ag = &fa->admin_group_include_any; + else if (type == AFFINITY_INCLUDE_ALL) + ag = &fa->admin_group_include_all; + else if (type == AFFINITY_EXCLUDE_ANY) + ag = &fa->admin_group_exclude_any; + else + break; + + admin_group_unset(ag, map->bit_position); + if (area->admin_group_send_zero) + admin_group_allow_explicit_zero(ag); + lsp_regenerate_schedule(area, area->is_type, 0); + break; + } + + return NB_OK; +} + +/* + * XPath: + * /frr-isisd:isis/instance/flex-algos/flex-algo/affinity-include-anies/affinity-include-any + */ +int isis_instance_flex_algo_affinity_include_any_create( + struct nb_cb_create_args *args) +{ + return isis_instance_flex_algo_affinity_set(args, AFFINITY_INCLUDE_ANY); +} + +int isis_instance_flex_algo_affinity_include_any_destroy( + struct nb_cb_destroy_args *args) +{ + return isis_instance_flex_algo_affinity_unset(args, + AFFINITY_INCLUDE_ANY); +} + +/* + * XPath: + * /frr-isisd:isis/instance/flex-algos/flex-algo/affinity-include-alls/affinity-include-all + */ +int isis_instance_flex_algo_affinity_include_all_create( + struct nb_cb_create_args *args) +{ + return isis_instance_flex_algo_affinity_set(args, AFFINITY_INCLUDE_ALL); +} + +int isis_instance_flex_algo_affinity_include_all_destroy( + struct nb_cb_destroy_args *args) +{ + return isis_instance_flex_algo_affinity_unset(args, + AFFINITY_INCLUDE_ALL); +} + +/* + * XPath: + * /frr-isisd:isis/instance/flex-algos/flex-algo/affinity-exclude-anies/affinity-exclude-any + */ +int isis_instance_flex_algo_affinity_exclude_any_create( + struct nb_cb_create_args *args) +{ + return isis_instance_flex_algo_affinity_set(args, AFFINITY_EXCLUDE_ANY); +} + +int isis_instance_flex_algo_affinity_exclude_any_destroy( + struct nb_cb_destroy_args *args) +{ + return isis_instance_flex_algo_affinity_unset(args, + AFFINITY_EXCLUDE_ANY); +} + +/* + * XPath: /frr-isisd:isis/instance/flex-algos/flex-algo/prefix-metric + */ + +int isis_instance_flex_algo_prefix_metric_create(struct nb_cb_create_args *args) +{ + struct isis_area *area; + const char *area_tag; + struct flex_algo *fa; + uint32_t algorithm; + + area_tag = yang_dnode_get_string(args->dnode, "../../../area-tag"); + area = isis_area_lookup(area_tag, VRF_DEFAULT); + if (!area) + return NB_ERR_RESOURCE; + + algorithm = yang_dnode_get_uint32(args->dnode, "./../flex-algo"); + + switch (args->event) { + case NB_EV_APPLY: + fa = flex_algo_lookup(area->flex_algos, algorithm); + if (!fa) { + snprintf(args->errmsg, args->errmsg_len, + "flex-algo object not found"); + return NB_ERR_RESOURCE; + } + SET_FLAG(fa->flags, FAD_FLAG_M); + lsp_regenerate_schedule(area, area->is_type, 0); + break; + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + } + + return NB_OK; +} + +int isis_instance_flex_algo_prefix_metric_destroy( + struct nb_cb_destroy_args *args) +{ + struct isis_area *area; + const char *area_tag; + struct flex_algo *fa; + uint32_t algorithm; + + area_tag = yang_dnode_get_string(args->dnode, "../../../area-tag"); + area = isis_area_lookup(area_tag, VRF_DEFAULT); + if (!area) + return NB_ERR_RESOURCE; + + algorithm = yang_dnode_get_uint32(args->dnode, "./../flex-algo"); + + switch (args->event) { + case NB_EV_APPLY: + fa = flex_algo_lookup(area->flex_algos, algorithm); + if (!fa) { + snprintf(args->errmsg, args->errmsg_len, + "flex-algo object not found"); + return NB_ERR_RESOURCE; + } + UNSET_FLAG(fa->flags, FAD_FLAG_M); + lsp_regenerate_schedule(area, area->is_type, 0); + break; + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + } + + return NB_OK; +} + +static int isis_instance_flex_algo_dplane_set(struct nb_cb_create_args *args, + int type) +{ + struct isis_area *area; + const char *area_tag; + struct flex_algo *fa; + uint32_t algorithm; + + area_tag = yang_dnode_get_string(args->dnode, "../../../area-tag"); + area = isis_area_lookup(area_tag, VRF_DEFAULT); + if (!area) + return NB_ERR_RESOURCE; + + algorithm = yang_dnode_get_uint32(args->dnode, "./../flex-algo"); + + switch (args->event) { + case NB_EV_APPLY: + fa = flex_algo_lookup(area->flex_algos, algorithm); + if (!fa) { + snprintf(args->errmsg, args->errmsg_len, + "flex-algo object not found"); + return NB_ERR_RESOURCE; + } + SET_FLAG(fa->dataplanes, type); + lsp_regenerate_schedule(area, area->is_type, 0); + break; + case NB_EV_VALIDATE: + if (type == FLEX_ALGO_SRV6 || type == FLEX_ALGO_IP) { + snprintf(args->errmsg, args->errmsg_len, + "%s Flex-algo dataplane is not yet supported.", + type == FLEX_ALGO_SRV6 ? "SRv6" : "IP"); + return NB_ERR_VALIDATION; + } + break; + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + } + + return NB_OK; +} + +static int isis_instance_flex_algo_dplane_unset(struct nb_cb_destroy_args *args, + int type) +{ + struct isis_area *area; + const char *area_tag; + struct flex_algo *fa; + uint32_t algorithm; + + area_tag = yang_dnode_get_string(args->dnode, "../../../area-tag"); + area = isis_area_lookup(area_tag, VRF_DEFAULT); + if (!area) + return NB_ERR_RESOURCE; + + algorithm = yang_dnode_get_uint32(args->dnode, "./../flex-algo"); + + switch (args->event) { + case NB_EV_APPLY: + fa = flex_algo_lookup(area->flex_algos, algorithm); + if (!fa) { + snprintf(args->errmsg, args->errmsg_len, + "flex-algo object not found"); + return NB_ERR_RESOURCE; + } + UNSET_FLAG(fa->dataplanes, type); + lsp_regenerate_schedule(area, area->is_type, 0); + break; + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/flex-algos/flex-algo/dplane-sr-mpls + */ + +int isis_instance_flex_algo_dplane_sr_mpls_create( + struct nb_cb_create_args *args) +{ + return isis_instance_flex_algo_dplane_set(args, FLEX_ALGO_SR_MPLS); +} + +int isis_instance_flex_algo_dplane_sr_mpls_destroy( + struct nb_cb_destroy_args *args) +{ + return isis_instance_flex_algo_dplane_unset(args, FLEX_ALGO_SR_MPLS); +} + +/* + * XPath: /frr-isisd:isis/instance/flex-algos/flex-algo/dplane-srv6 + */ + +int isis_instance_flex_algo_dplane_srv6_create(struct nb_cb_create_args *args) +{ + return isis_instance_flex_algo_dplane_set(args, FLEX_ALGO_SRV6); +} + +int isis_instance_flex_algo_dplane_srv6_destroy(struct nb_cb_destroy_args *args) +{ + return isis_instance_flex_algo_dplane_unset(args, FLEX_ALGO_SRV6); +} + +/* + * XPath: /frr-isisd:isis/instance/flex-algos/flex-algo/dplane-ip + */ + +int isis_instance_flex_algo_dplane_ip_create(struct nb_cb_create_args *args) +{ + return isis_instance_flex_algo_dplane_set(args, FLEX_ALGO_IP); +} + +int isis_instance_flex_algo_dplane_ip_destroy(struct nb_cb_destroy_args *args) +{ + return isis_instance_flex_algo_dplane_unset(args, FLEX_ALGO_IP); +} + +/* + * XPath: /frr-isisd:isis/instance/flex-algos/flex-algo/metric-type + */ + +int isis_instance_flex_algo_metric_type_modify(struct nb_cb_modify_args *args) +{ + struct isis_area *area; + const char *area_tag; + struct flex_algo *fa; + uint32_t algorithm; + enum flex_algo_metric_type metric_type; + + area_tag = yang_dnode_get_string(args->dnode, "../../../area-tag"); + area = isis_area_lookup(area_tag, VRF_DEFAULT); + if (!area) + return NB_ERR_RESOURCE; + + algorithm = yang_dnode_get_uint32(args->dnode, "./../flex-algo"); + metric_type = yang_dnode_get_enum(args->dnode, NULL); + + switch (args->event) { + case NB_EV_APPLY: + fa = flex_algo_lookup(area->flex_algos, algorithm); + if (!fa) { + snprintf(args->errmsg, args->errmsg_len, + "flex-algo object not found"); + return NB_ERR_RESOURCE; + } + fa->metric_type = metric_type; + lsp_regenerate_schedule(area, area->is_type, 0); + break; + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/flex-algos/flex-algo/priority + */ + +int isis_instance_flex_algo_priority_modify(struct nb_cb_modify_args *args) +{ + struct isis_area *area; + const char *area_tag; + struct flex_algo *fa; + uint32_t algorithm; + uint32_t priority; + + area_tag = yang_dnode_get_string(args->dnode, "../../../area-tag"); + area = isis_area_lookup(area_tag, VRF_DEFAULT); + if (!area) + return NB_ERR_RESOURCE; + + algorithm = yang_dnode_get_uint32(args->dnode, "./../flex-algo"); + priority = yang_dnode_get_uint32(args->dnode, NULL); + + switch (args->event) { + case NB_EV_APPLY: + fa = flex_algo_lookup(area->flex_algos, algorithm); + if (!fa) { + snprintf(args->errmsg, args->errmsg_len, + "flex-algo object not found"); + return NB_ERR_RESOURCE; + } + fa->priority = priority; + lsp_regenerate_schedule(area, area->is_type, 0); + break; + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + } + + return NB_OK; +} + +int isis_instance_flex_algo_priority_destroy(struct nb_cb_destroy_args *args) +{ + struct isis_area *area; + const char *area_tag; + struct flex_algo *fa; + uint32_t algorithm; + uint32_t priority = FLEX_ALGO_PRIO_DEFAULT; + + area_tag = yang_dnode_get_string(args->dnode, "../../../area-tag"); + area = isis_area_lookup(area_tag, VRF_DEFAULT); + if (!area) + return NB_ERR_RESOURCE; + + algorithm = yang_dnode_get_uint32(args->dnode, "./../flex-algo"); + priority = yang_dnode_get_uint32(args->dnode, NULL); + + switch (args->event) { + case NB_EV_APPLY: + fa = flex_algo_lookup(area->flex_algos, algorithm); + if (!fa) { + snprintf(args->errmsg, args->errmsg_len, + "flex-algo object not found"); + return NB_ERR_RESOURCE; + } + fa->priority = priority; + lsp_regenerate_schedule(area, area->is_type, 0); + break; + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/segment-routing-srv6/enabled + */ +int isis_instance_segment_routing_srv6_enabled_modify( + struct nb_cb_modify_args *args) +{ + struct isis_area *area; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + area = nb_running_get_entry(args->dnode, NULL, true); + area->srv6db.config.enabled = yang_dnode_get_bool(args->dnode, NULL); + + if (area->srv6db.config.enabled) { + if (IS_DEBUG_EVENTS) + zlog_debug( + "Segment Routing over IPv6 (SRv6): OFF -> ON"); + } else { + if (IS_DEBUG_EVENTS) + zlog_debug( + "Segment Routing over IPv6 (SRv6): ON -> OFF"); + } + + /* Regenerate LSPs to advertise SRv6 capabilities or signal that the + * node is no longer SRv6-capable. */ + lsp_regenerate_schedule(area, area->is_type, 0); + + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/segment-routing-srv6/locator + */ +int isis_instance_segment_routing_srv6_locator_modify( + struct nb_cb_modify_args *args) +{ + struct isis_area *area; + const char *loc_name; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + area = nb_running_get_entry(lyd_parent(lyd_parent(args->dnode)), NULL, + true); + + loc_name = yang_dnode_get_string(args->dnode, NULL); + + if (strncmp(loc_name, area->srv6db.config.srv6_locator_name, + sizeof(area->srv6db.config.srv6_locator_name)) == 0) { + snprintf(args->errmsg, args->errmsg_len, + "SRv6 locator %s is already configured", loc_name); + return NB_ERR_NO_CHANGES; + } + + /* Remove previously configured locator */ + if (strncmp(area->srv6db.config.srv6_locator_name, "", + sizeof(area->srv6db.config.srv6_locator_name)) != 0) { + sr_debug("Unsetting previously configured SRv6 locator"); + if (!isis_srv6_locator_unset(area)) { + zlog_warn("Failed to unset SRv6 locator"); + return NB_ERR; + } + } + + strlcpy(area->srv6db.config.srv6_locator_name, loc_name, + sizeof(area->srv6db.config.srv6_locator_name)); + + sr_debug("Configured SRv6 locator %s for IS-IS area %s", loc_name, + area->area_tag); + + sr_debug("Trying to get a chunk from locator %s for IS-IS area %s", + loc_name, area->area_tag); + + if (isis_zebra_srv6_manager_get_locator_chunk(loc_name) < 0) + return NB_ERR; + + return NB_OK; +} + +int isis_instance_segment_routing_srv6_locator_destroy( + struct nb_cb_destroy_args *args) +{ + struct isis_area *area; + const char *loc_name; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + area = nb_running_get_entry(lyd_parent(lyd_parent(args->dnode)), NULL, + true); + + loc_name = yang_dnode_get_string(args->dnode, NULL); + + sr_debug("Trying to unset SRv6 locator %s", loc_name); + + if (strncmp(loc_name, area->srv6db.config.srv6_locator_name, + sizeof(area->srv6db.config.srv6_locator_name)) != 0) { + sr_debug("SRv6 locator %s is not configured", loc_name); + snprintf(args->errmsg, args->errmsg_len, + "SRv6 locator %s is not configured", loc_name); + return NB_ERR_NO_CHANGES; + } + + if (!isis_srv6_locator_unset(area)) { + zlog_warn("Failed to unset SRv6 locator"); + return NB_ERR; + } + + sr_debug("Deleted SRv6 locator %s for IS-IS area %s", loc_name, + area->area_tag); + + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/segment-routing-srv6/msd/node-msd/max-segs-left + */ +int isis_instance_segment_routing_srv6_msd_node_msd_max_segs_left_modify( + struct nb_cb_modify_args *args) +{ + struct isis_area *area; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + area = nb_running_get_entry(args->dnode, NULL, true); + area->srv6db.config.max_seg_left_msd = yang_dnode_get_uint8(args->dnode, + NULL); + + /* Update and regenerate LSP */ + lsp_regenerate_schedule(area, area->is_type, 0); + + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/segment-routing-srv6/msd/node-msd/max-end-pop + */ +int isis_instance_segment_routing_srv6_msd_node_msd_max_end_pop_modify( + struct nb_cb_modify_args *args) +{ + struct isis_area *area; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + area = nb_running_get_entry(args->dnode, NULL, true); + area->srv6db.config.max_end_pop_msd = yang_dnode_get_uint8(args->dnode, + NULL); + + /* Update and regenerate LSP */ + lsp_regenerate_schedule(area, area->is_type, 0); + + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/segment-routing-srv6/msd/node-msd/max-h-encaps + */ +int isis_instance_segment_routing_srv6_msd_node_msd_max_h_encaps_modify( + struct nb_cb_modify_args *args) +{ + struct isis_area *area; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + area = nb_running_get_entry(args->dnode, NULL, true); + area->srv6db.config.max_h_encaps_msd = yang_dnode_get_uint8(args->dnode, + NULL); + + /* Update and regenerate LSP */ + lsp_regenerate_schedule(area, area->is_type, 0); + + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/segment-routing-srv6/msd/node-msd/max-end-d + */ +int isis_instance_segment_routing_srv6_msd_node_msd_max_end_d_modify( + struct nb_cb_modify_args *args) +{ + struct isis_area *area; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + area = nb_running_get_entry(args->dnode, NULL, true); + area->srv6db.config.max_end_d_msd = yang_dnode_get_uint8(args->dnode, + NULL); + + /* Update and regenerate LSP */ + lsp_regenerate_schedule(area, area->is_type, 0); + + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/segment-routing-srv6/interface + */ +int isis_instance_segment_routing_srv6_interface_modify( + struct nb_cb_modify_args *args) +{ + struct isis_area *area; + const char *ifname; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + area = nb_running_get_entry(lyd_parent(lyd_parent(args->dnode)), NULL, + true); + + ifname = yang_dnode_get_string(args->dnode, NULL); + + sr_debug("Changing SRv6 interface for IS-IS area %s to %s", + area->area_tag, ifname); + + isis_srv6_interface_set(area, ifname); + + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/mpls/ldp-sync + */ +int isis_instance_mpls_ldp_sync_create(struct nb_cb_create_args *args) +{ + struct isis_area *area; + const char *vrfname; + + switch (args->event) { + case NB_EV_VALIDATE: + vrfname = yang_dnode_get_string( + lyd_parent(lyd_parent(args->dnode)), "./vrf"); + + if (strcmp(vrfname, VRF_DEFAULT_NAME)) { + snprintf(args->errmsg, args->errmsg_len, + "LDP-Sync only runs on Default VRF"); + return NB_ERR_VALIDATION; + } + break; + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + area = nb_running_get_entry(args->dnode, NULL, true); + isis_area_ldp_sync_enable(area); + break; + } + return NB_OK; +} + +int isis_instance_mpls_ldp_sync_destroy(struct nb_cb_destroy_args *args) +{ + struct isis_area *area; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + area = nb_running_get_entry(args->dnode, NULL, true); + isis_area_ldp_sync_disable(area); + + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/mpls/ldp-sync/holddown + */ +int isis_instance_mpls_ldp_sync_holddown_modify(struct nb_cb_modify_args *args) +{ + struct isis_area *area; + uint16_t holddown; + const char *vrfname; + + switch (args->event) { + case NB_EV_VALIDATE: + vrfname = yang_dnode_get_string( + lyd_parent(lyd_parent(lyd_parent(args->dnode))), + "./vrf"); + + if (strcmp(vrfname, VRF_DEFAULT_NAME)) { + snprintf(args->errmsg, args->errmsg_len, + "LDP-Sync only runs on Default VRF"); + return NB_ERR_VALIDATION; + } + break; + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + area = nb_running_get_entry(args->dnode, NULL, true); + holddown = yang_dnode_get_uint16(args->dnode, NULL); + isis_area_ldp_sync_set_holddown(area, holddown); + break; + } + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-isisd:isis + */ +int lib_interface_isis_create(struct nb_cb_create_args *args) +{ + struct interface *ifp; + struct isis_circuit *circuit = NULL; + const char *area_tag = yang_dnode_get_string(args->dnode, "./area-tag"); + + switch (args->event) { + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_VALIDATE: + break; + case NB_EV_APPLY: + ifp = nb_running_get_entry(args->dnode, NULL, true); + circuit = isis_circuit_new(ifp, area_tag); + nb_running_set_entry(args->dnode, circuit); + break; + } + + return NB_OK; +} + +int lib_interface_isis_destroy(struct nb_cb_destroy_args *args) +{ + struct isis_circuit *circuit; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + circuit = nb_running_unset_entry(args->dnode); + + isis_circuit_del(circuit); + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-isisd:isis/area-tag + */ +int lib_interface_isis_area_tag_modify(struct nb_cb_modify_args *args) +{ + struct isis_circuit *circuit; + + if (args->event == NB_EV_VALIDATE) { + circuit = nb_running_get_entry_non_rec(lyd_parent(args->dnode), + NULL, false); + if (circuit) { + snprintf(args->errmsg, args->errmsg_len, + "Changing area tag is not allowed"); + return NB_ERR_VALIDATION; + } + } + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-isisd:isis/circuit-type + */ +int lib_interface_isis_circuit_type_modify(struct nb_cb_modify_args *args) +{ + int circ_type = yang_dnode_get_enum(args->dnode, NULL); + struct isis_circuit *circuit; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + circuit = nb_running_get_entry(args->dnode, NULL, true); + circuit->is_type_config = circ_type; + isis_circuit_is_type_set(circuit, circ_type); + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-isisd:isis/ipv4-routing + */ +int lib_interface_isis_ipv4_routing_modify(struct nb_cb_modify_args *args) +{ + bool ipv4, ipv6; + struct isis_circuit *circuit; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + circuit = nb_running_get_entry(args->dnode, NULL, true); + ipv4 = yang_dnode_get_bool(args->dnode, NULL); + ipv6 = yang_dnode_get_bool(args->dnode, "../ipv6-routing"); + isis_circuit_af_set(circuit, ipv4, ipv6); + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-isisd:isis/ipv6-routing + */ +int lib_interface_isis_ipv6_routing_modify(struct nb_cb_modify_args *args) +{ + bool ipv4, ipv6; + struct isis_circuit *circuit; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + circuit = nb_running_get_entry(args->dnode, NULL, true); + ipv4 = yang_dnode_get_bool(args->dnode, "../ipv4-routing"); + ipv6 = yang_dnode_get_bool(args->dnode, NULL); + isis_circuit_af_set(circuit, ipv4, ipv6); + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-isisd:isis/bfd-monitoring + */ +void lib_interface_isis_bfd_monitoring_apply_finish( + struct nb_cb_apply_finish_args *args) +{ + struct isis_circuit *circuit; + + circuit = nb_running_get_entry(args->dnode, NULL, true); + isis_bfd_circuit_cmd(circuit); +} + +/* + * XPath: /frr-interface:lib/interface/frr-isisd:isis/bfd-monitoring/enabled + */ +int lib_interface_isis_bfd_monitoring_enabled_modify( + struct nb_cb_modify_args *args) +{ + struct isis_circuit *circuit; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + circuit = nb_running_get_entry(args->dnode, NULL, true); + circuit->bfd_config.enabled = yang_dnode_get_bool(args->dnode, NULL); + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-isisd:isis/bfd-monitoring/profile + */ +int lib_interface_isis_bfd_monitoring_profile_modify( + struct nb_cb_modify_args *args) +{ + struct isis_circuit *circuit; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + circuit = nb_running_get_entry(args->dnode, NULL, true); + XFREE(MTYPE_TMP, circuit->bfd_config.profile); + circuit->bfd_config.profile = + XSTRDUP(MTYPE_TMP, yang_dnode_get_string(args->dnode, NULL)); + + return NB_OK; +} + +int lib_interface_isis_bfd_monitoring_profile_destroy( + struct nb_cb_destroy_args *args) +{ + struct isis_circuit *circuit; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + circuit = nb_running_get_entry(args->dnode, NULL, true); + XFREE(MTYPE_TMP, circuit->bfd_config.profile); + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-isisd:isis/csnp-interval/level-1 + */ +int lib_interface_isis_csnp_interval_level_1_modify( + struct nb_cb_modify_args *args) +{ + struct isis_circuit *circuit; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + circuit = nb_running_get_entry(args->dnode, NULL, true); + circuit->csnp_interval[0] = yang_dnode_get_uint16(args->dnode, NULL); + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-isisd:isis/csnp-interval/level-2 + */ +int lib_interface_isis_csnp_interval_level_2_modify( + struct nb_cb_modify_args *args) +{ + struct isis_circuit *circuit; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + circuit = nb_running_get_entry(args->dnode, NULL, true); + circuit->csnp_interval[1] = yang_dnode_get_uint16(args->dnode, NULL); + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-isisd:isis/psnp-interval/level-1 + */ +int lib_interface_isis_psnp_interval_level_1_modify( + struct nb_cb_modify_args *args) +{ + struct isis_circuit *circuit; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + circuit = nb_running_get_entry(args->dnode, NULL, true); + circuit->psnp_interval[0] = yang_dnode_get_uint16(args->dnode, NULL); + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-isisd:isis/psnp-interval/level-2 + */ +int lib_interface_isis_psnp_interval_level_2_modify( + struct nb_cb_modify_args *args) +{ + struct isis_circuit *circuit; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + circuit = nb_running_get_entry(args->dnode, NULL, true); + circuit->psnp_interval[1] = yang_dnode_get_uint16(args->dnode, NULL); + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-isisd:isis/hello/padding + */ +int lib_interface_isis_hello_padding_modify(struct nb_cb_modify_args *args) +{ + struct isis_circuit *circuit; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + circuit = nb_running_get_entry(args->dnode, NULL, true); + circuit->pad_hellos = yang_dnode_get_enum(args->dnode, NULL); + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-isisd:isis/hello/interval/level-1 + */ +int lib_interface_isis_hello_interval_level_1_modify( + struct nb_cb_modify_args *args) +{ + struct isis_circuit *circuit; + uint32_t interval; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + circuit = nb_running_get_entry(args->dnode, NULL, true); + interval = yang_dnode_get_uint32(args->dnode, NULL); + circuit->hello_interval[0] = interval; + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-isisd:isis/hello/interval/level-2 + */ +int lib_interface_isis_hello_interval_level_2_modify( + struct nb_cb_modify_args *args) +{ + struct isis_circuit *circuit; + uint32_t interval; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + circuit = nb_running_get_entry(args->dnode, NULL, true); + interval = yang_dnode_get_uint32(args->dnode, NULL); + circuit->hello_interval[1] = interval; + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-isisd:isis/hello/multiplier/level-1 + */ +int lib_interface_isis_hello_multiplier_level_1_modify( + struct nb_cb_modify_args *args) +{ + struct isis_circuit *circuit; + uint16_t multi; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + circuit = nb_running_get_entry(args->dnode, NULL, true); + multi = yang_dnode_get_uint16(args->dnode, NULL); + circuit->hello_multiplier[0] = multi; + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-isisd:isis/hello/multiplier/level-2 + */ +int lib_interface_isis_hello_multiplier_level_2_modify( + struct nb_cb_modify_args *args) +{ + struct isis_circuit *circuit; + uint16_t multi; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + circuit = nb_running_get_entry(args->dnode, NULL, true); + multi = yang_dnode_get_uint16(args->dnode, NULL); + circuit->hello_multiplier[1] = multi; + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-isisd:isis/metric/level-1 + */ +int lib_interface_isis_metric_level_1_modify(struct nb_cb_modify_args *args) +{ + struct isis_circuit *circuit; + unsigned int met; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + circuit = nb_running_get_entry(args->dnode, NULL, true); + met = yang_dnode_get_uint32(args->dnode, NULL); + isis_circuit_metric_set(circuit, IS_LEVEL_1, met); + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-isisd:isis/metric/level-2 + */ +int lib_interface_isis_metric_level_2_modify(struct nb_cb_modify_args *args) +{ + struct isis_circuit *circuit; + unsigned int met; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + circuit = nb_running_get_entry(args->dnode, NULL, true); + met = yang_dnode_get_uint32(args->dnode, NULL); + isis_circuit_metric_set(circuit, IS_LEVEL_2, met); + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-isisd:isis/priority/level-1 + */ +int lib_interface_isis_priority_level_1_modify(struct nb_cb_modify_args *args) +{ + struct isis_circuit *circuit; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + circuit = nb_running_get_entry(args->dnode, NULL, true); + circuit->priority[0] = yang_dnode_get_uint8(args->dnode, NULL); + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-isisd:isis/priority/level-2 + */ +int lib_interface_isis_priority_level_2_modify(struct nb_cb_modify_args *args) +{ + struct isis_circuit *circuit; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + circuit = nb_running_get_entry(args->dnode, NULL, true); + circuit->priority[1] = yang_dnode_get_uint8(args->dnode, NULL); + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-isisd:isis/network-type + */ +int lib_interface_isis_network_type_modify(struct nb_cb_modify_args *args) +{ + struct isis_circuit *circuit; + int net_type = yang_dnode_get_enum(args->dnode, NULL); + + switch (args->event) { + case NB_EV_VALIDATE: + circuit = nb_running_get_entry(args->dnode, NULL, false); + if (!circuit) + break; + if (circuit->circ_type == CIRCUIT_T_LOOPBACK) { + snprintf( + args->errmsg, args->errmsg_len, + "Cannot change network type on loopback interface"); + return NB_ERR_VALIDATION; + } + if (net_type == CIRCUIT_T_BROADCAST + && circuit->state == C_STATE_UP + && !if_is_broadcast(circuit->interface)) { + snprintf( + args->errmsg, args->errmsg_len, + "Cannot configure non-broadcast interface for broadcast operation"); + return NB_ERR_VALIDATION; + } + break; + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + circuit = nb_running_get_entry(args->dnode, NULL, true); + isis_circuit_circ_type_set(circuit, net_type); + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-isisd:isis/passive + */ +int lib_interface_isis_passive_modify(struct nb_cb_modify_args *args) +{ + struct isis_circuit *circuit; + bool passive = yang_dnode_get_bool(args->dnode, NULL); + + if (args->event != NB_EV_APPLY) + return NB_OK; + + circuit = nb_running_get_entry(args->dnode, NULL, true); + isis_circuit_passive_set(circuit, passive); + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-isisd:isis/password + */ +int lib_interface_isis_password_create(struct nb_cb_create_args *args) +{ + return NB_OK; +} + +int lib_interface_isis_password_destroy(struct nb_cb_destroy_args *args) +{ + struct isis_circuit *circuit; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + circuit = nb_running_get_entry(args->dnode, NULL, true); + isis_circuit_passwd_unset(circuit); + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-isisd:isis/password/password + */ +int lib_interface_isis_password_password_modify(struct nb_cb_modify_args *args) +{ + struct isis_circuit *circuit; + const char *password; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + password = yang_dnode_get_string(args->dnode, NULL); + circuit = nb_running_get_entry(args->dnode, NULL, true); + + isis_circuit_passwd_set(circuit, circuit->passwd.type, password); + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-isisd:isis/password/password-type + */ +int lib_interface_isis_password_password_type_modify( + struct nb_cb_modify_args *args) +{ + struct isis_circuit *circuit; + uint8_t pass_type; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + pass_type = yang_dnode_get_enum(args->dnode, NULL); + circuit = nb_running_get_entry(args->dnode, NULL, true); + circuit->passwd.type = pass_type; + + return NB_OK; +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-isisd:isis/disable-three-way-handshake + */ +int lib_interface_isis_disable_three_way_handshake_modify( + struct nb_cb_modify_args *args) +{ + struct isis_circuit *circuit; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + circuit = nb_running_get_entry(args->dnode, NULL, true); + circuit->disable_threeway_adj = yang_dnode_get_bool(args->dnode, NULL); + + return NB_OK; +} + +static int lib_interface_isis_multi_topology_common( + enum nb_event event, const struct lyd_node *dnode, char *errmsg, + size_t errmsg_len, uint16_t mtid) +{ + struct isis_circuit *circuit; + bool value; + + switch (event) { + case NB_EV_VALIDATE: + circuit = nb_running_get_entry(dnode, NULL, false); + if (circuit && circuit->area && circuit->area->oldmetric) { + snprintf( + errmsg, errmsg_len, + "Multi topology IS-IS can only be used with wide metrics"); + return NB_ERR_VALIDATION; + } + break; + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + circuit = nb_running_get_entry(dnode, NULL, true); + value = yang_dnode_get_bool(dnode, NULL); + isis_circuit_mt_enabled_set(circuit, mtid, value); + break; + } + + return NB_OK; +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-isisd:isis/multi-topology/standard + */ +int lib_interface_isis_multi_topology_standard_modify( + struct nb_cb_modify_args *args) +{ + return lib_interface_isis_multi_topology_common( + args->event, args->dnode, args->errmsg, args->errmsg_len, + ISIS_MT_STANDARD); +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-isisd:isis/multi-topology/ipv4-multicast + */ +int lib_interface_isis_multi_topology_ipv4_multicast_modify( + struct nb_cb_modify_args *args) +{ + return lib_interface_isis_multi_topology_common( + args->event, args->dnode, args->errmsg, args->errmsg_len, + ISIS_MT_IPV4_MULTICAST); +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-isisd:isis/multi-topology/ipv4-management + */ +int lib_interface_isis_multi_topology_ipv4_management_modify( + struct nb_cb_modify_args *args) +{ + return lib_interface_isis_multi_topology_common( + args->event, args->dnode, args->errmsg, args->errmsg_len, + ISIS_MT_IPV4_MGMT); +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-isisd:isis/multi-topology/ipv6-unicast + */ +int lib_interface_isis_multi_topology_ipv6_unicast_modify( + struct nb_cb_modify_args *args) +{ + return lib_interface_isis_multi_topology_common( + args->event, args->dnode, args->errmsg, args->errmsg_len, + ISIS_MT_IPV6_UNICAST); +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-isisd:isis/multi-topology/ipv6-multicast + */ +int lib_interface_isis_multi_topology_ipv6_multicast_modify( + struct nb_cb_modify_args *args) +{ + return lib_interface_isis_multi_topology_common( + args->event, args->dnode, args->errmsg, args->errmsg_len, + ISIS_MT_IPV6_MULTICAST); +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-isisd:isis/multi-topology/ipv6-management + */ +int lib_interface_isis_multi_topology_ipv6_management_modify( + struct nb_cb_modify_args *args) +{ + return lib_interface_isis_multi_topology_common( + args->event, args->dnode, args->errmsg, args->errmsg_len, + ISIS_MT_IPV6_MGMT); +} + +/* + * XPath: /frr-interface:lib/interface/frr-isisd:isis/multi-topology/ipv6-dstsrc + */ +int lib_interface_isis_multi_topology_ipv6_dstsrc_modify( + struct nb_cb_modify_args *args) +{ + return lib_interface_isis_multi_topology_common( + args->event, args->dnode, args->errmsg, args->errmsg_len, + ISIS_MT_IPV6_DSTSRC); +} + +/* + * XPath: /frr-interface:lib/interface/frr-isisd:isis/mpls/ldp-sync + */ +int lib_interface_isis_mpls_ldp_sync_modify(struct nb_cb_modify_args *args) +{ + struct isis_circuit *circuit; + struct ldp_sync_info *ldp_sync_info; + bool ldp_sync_enable; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + circuit = nb_running_get_entry(args->dnode, NULL, true); + ldp_sync_enable = yang_dnode_get_bool(args->dnode, NULL); + + ldp_sync_info = circuit->ldp_sync_info; + + SET_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_IF_CONFIG); + ldp_sync_info->enabled = ldp_sync_enable; + + if (circuit->area) { + if (ldp_sync_enable) + isis_if_ldp_sync_enable(circuit); + else + isis_if_ldp_sync_disable(circuit); + } + break; + } + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-isisd:isis/mpls/holddown + */ +int lib_interface_isis_mpls_holddown_modify(struct nb_cb_modify_args *args) +{ + struct isis_circuit *circuit; + struct ldp_sync_info *ldp_sync_info; + uint16_t holddown; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + circuit = nb_running_get_entry(args->dnode, NULL, true); + holddown = yang_dnode_get_uint16(args->dnode, NULL); + + ldp_sync_info = circuit->ldp_sync_info; + + SET_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_HOLDDOWN); + ldp_sync_info->holddown = holddown; + break; + } + return NB_OK; +} + +int lib_interface_isis_mpls_holddown_destroy(struct nb_cb_destroy_args *args) +{ + struct isis_circuit *circuit; + struct ldp_sync_info *ldp_sync_info; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + circuit = nb_running_get_entry(args->dnode, NULL, true); + ldp_sync_info = circuit->ldp_sync_info; + + UNSET_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_HOLDDOWN); + + if (circuit->area) + isis_if_set_ldp_sync_holddown(circuit); + break; + } + + return NB_OK; +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-1/lfa/enable + */ +int lib_interface_isis_fast_reroute_level_1_lfa_enable_modify( + struct nb_cb_modify_args *args) +{ + struct isis_area *area; + struct isis_circuit *circuit; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + circuit = nb_running_get_entry(args->dnode, NULL, true); + circuit->lfa_protection[0] = yang_dnode_get_bool(args->dnode, NULL); + + area = circuit->area; + if (area) { + if (circuit->lfa_protection[0]) + area->lfa_protected_links[0]++; + else { + assert(area->lfa_protected_links[0] > 0); + area->lfa_protected_links[0]--; + } + + lsp_regenerate_schedule(area, area->is_type, 0); + } + + return NB_OK; +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-1/lfa/exclude-interface + */ +int lib_interface_isis_fast_reroute_level_1_lfa_exclude_interface_create( + struct nb_cb_create_args *args) +{ + struct isis_area *area; + struct isis_circuit *circuit; + const char *exclude_ifname; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + circuit = nb_running_get_entry(args->dnode, NULL, true); + exclude_ifname = yang_dnode_get_string(args->dnode, NULL); + + isis_lfa_excluded_iface_add(circuit, ISIS_LEVEL1, exclude_ifname); + area = circuit->area; + if (area) + lsp_regenerate_schedule(area, area->is_type, 0); + + return NB_OK; +} + +int lib_interface_isis_fast_reroute_level_1_lfa_exclude_interface_destroy( + struct nb_cb_destroy_args *args) +{ + struct isis_area *area; + struct isis_circuit *circuit; + const char *exclude_ifname; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + circuit = nb_running_get_entry(args->dnode, NULL, true); + exclude_ifname = yang_dnode_get_string(args->dnode, NULL); + + isis_lfa_excluded_iface_delete(circuit, ISIS_LEVEL1, exclude_ifname); + area = circuit->area; + if (area) + lsp_regenerate_schedule(area, area->is_type, 0); + + return NB_OK; +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-1/remote-lfa/enable + */ +int lib_interface_isis_fast_reroute_level_1_remote_lfa_enable_modify( + struct nb_cb_modify_args *args) +{ + struct isis_area *area; + struct isis_circuit *circuit; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + circuit = nb_running_get_entry(args->dnode, NULL, true); + circuit->rlfa_protection[0] = yang_dnode_get_bool(args->dnode, NULL); + + area = circuit->area; + if (area) { + if (circuit->rlfa_protection[0]) + area->rlfa_protected_links[0]++; + else { + assert(area->rlfa_protected_links[0] > 0); + area->rlfa_protected_links[0]--; + } + + lsp_regenerate_schedule(area, area->is_type, 0); + } + + return NB_OK; +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-1/remote-lfa/maximum-metric + */ +int lib_interface_isis_fast_reroute_level_1_remote_lfa_maximum_metric_modify( + struct nb_cb_modify_args *args) +{ + struct isis_area *area; + struct isis_circuit *circuit; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + circuit = nb_running_get_entry(args->dnode, NULL, true); + circuit->rlfa_max_metric[0] = yang_dnode_get_uint32(args->dnode, NULL); + + area = circuit->area; + if (area) + lsp_regenerate_schedule(area, area->is_type, 0); + + return NB_OK; +} + +int lib_interface_isis_fast_reroute_level_1_remote_lfa_maximum_metric_destroy( + struct nb_cb_destroy_args *args) +{ + struct isis_area *area; + struct isis_circuit *circuit; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + circuit = nb_running_get_entry(args->dnode, NULL, true); + circuit->rlfa_max_metric[0] = 0; + + area = circuit->area; + if (area) + lsp_regenerate_schedule(area, area->is_type, 0); + + return NB_OK; +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-1/ti-lfa/enable + */ +int lib_interface_isis_fast_reroute_level_1_ti_lfa_enable_modify( + struct nb_cb_modify_args *args) +{ + struct isis_area *area; + struct isis_circuit *circuit; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + circuit = nb_running_get_entry(args->dnode, NULL, true); + circuit->tilfa_protection[0] = yang_dnode_get_bool(args->dnode, NULL); + + area = circuit->area; + if (area) { + if (circuit->tilfa_protection[0]) + area->tilfa_protected_links[0]++; + else { + assert(area->tilfa_protected_links[0] > 0); + area->tilfa_protected_links[0]--; + } + + lsp_regenerate_schedule(area, area->is_type, 0); + } + + return NB_OK; +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-1/ti-lfa/node-protection + */ +int lib_interface_isis_fast_reroute_level_1_ti_lfa_node_protection_modify( + struct nb_cb_modify_args *args) +{ + struct isis_area *area; + struct isis_circuit *circuit; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + circuit = nb_running_get_entry(args->dnode, NULL, true); + circuit->tilfa_node_protection[0] = + yang_dnode_get_bool(args->dnode, NULL); + + area = circuit->area; + if (area) + lsp_regenerate_schedule(area, area->is_type, 0); + + return NB_OK; +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-1/ti-lfa/link-fallback + */ +int lib_interface_isis_fast_reroute_level_1_ti_lfa_link_fallback_modify( + struct nb_cb_modify_args *args) +{ + struct isis_area *area; + struct isis_circuit *circuit; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + circuit = nb_running_get_entry(args->dnode, NULL, true); + circuit->tilfa_link_fallback[0] = + yang_dnode_get_bool(args->dnode, NULL); + + area = circuit->area; + if (area) + lsp_regenerate_schedule(area, area->is_type, 0); + + return NB_OK; +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-2/lfa/enable + */ +int lib_interface_isis_fast_reroute_level_2_lfa_enable_modify( + struct nb_cb_modify_args *args) +{ + struct isis_area *area; + struct isis_circuit *circuit; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + circuit = nb_running_get_entry(args->dnode, NULL, true); + circuit->lfa_protection[1] = yang_dnode_get_bool(args->dnode, NULL); + + area = circuit->area; + if (area) { + if (circuit->lfa_protection[1]) + area->lfa_protected_links[1]++; + else { + assert(area->lfa_protected_links[1] > 0); + area->lfa_protected_links[1]--; + } + + lsp_regenerate_schedule(area, area->is_type, 0); + } + + return NB_OK; +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-2/lfa/exclude-interface + */ +int lib_interface_isis_fast_reroute_level_2_lfa_exclude_interface_create( + struct nb_cb_create_args *args) +{ + struct isis_area *area; + struct isis_circuit *circuit; + const char *exclude_ifname; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + circuit = nb_running_get_entry(args->dnode, NULL, true); + exclude_ifname = yang_dnode_get_string(args->dnode, NULL); + + isis_lfa_excluded_iface_add(circuit, ISIS_LEVEL2, exclude_ifname); + area = circuit->area; + if (area) + lsp_regenerate_schedule(area, area->is_type, 0); + + return NB_OK; +} + +int lib_interface_isis_fast_reroute_level_2_lfa_exclude_interface_destroy( + struct nb_cb_destroy_args *args) +{ + struct isis_area *area; + struct isis_circuit *circuit; + const char *exclude_ifname; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + circuit = nb_running_get_entry(args->dnode, NULL, true); + exclude_ifname = yang_dnode_get_string(args->dnode, NULL); + + isis_lfa_excluded_iface_delete(circuit, ISIS_LEVEL2, exclude_ifname); + area = circuit->area; + if (area) + lsp_regenerate_schedule(area, area->is_type, 0); + + return NB_OK; +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-2/remote-lfa/enable + */ +int lib_interface_isis_fast_reroute_level_2_remote_lfa_enable_modify( + struct nb_cb_modify_args *args) +{ + struct isis_area *area; + struct isis_circuit *circuit; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + circuit = nb_running_get_entry(args->dnode, NULL, true); + circuit->rlfa_protection[1] = yang_dnode_get_bool(args->dnode, NULL); + + area = circuit->area; + if (area) { + if (circuit->rlfa_protection[1]) + area->rlfa_protected_links[1]++; + else { + assert(area->rlfa_protected_links[1] > 0); + area->rlfa_protected_links[1]--; + } + + lsp_regenerate_schedule(area, area->is_type, 0); + } + + return NB_OK; +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-2/remote-lfa/maximum-metric + */ +int lib_interface_isis_fast_reroute_level_2_remote_lfa_maximum_metric_modify( + struct nb_cb_modify_args *args) +{ + struct isis_area *area; + struct isis_circuit *circuit; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + circuit = nb_running_get_entry(args->dnode, NULL, true); + circuit->rlfa_max_metric[1] = yang_dnode_get_uint32(args->dnode, NULL); + + area = circuit->area; + if (area) + lsp_regenerate_schedule(area, area->is_type, 0); + + return NB_OK; +} + +int lib_interface_isis_fast_reroute_level_2_remote_lfa_maximum_metric_destroy( + struct nb_cb_destroy_args *args) +{ + struct isis_area *area; + struct isis_circuit *circuit; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + circuit = nb_running_get_entry(args->dnode, NULL, true); + circuit->rlfa_max_metric[1] = 0; + + area = circuit->area; + if (area) + lsp_regenerate_schedule(area, area->is_type, 0); + + return NB_OK; +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-2/ti-lfa/enable + */ +int lib_interface_isis_fast_reroute_level_2_ti_lfa_enable_modify( + struct nb_cb_modify_args *args) +{ + struct isis_area *area; + struct isis_circuit *circuit; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + circuit = nb_running_get_entry(args->dnode, NULL, true); + circuit->tilfa_protection[1] = yang_dnode_get_bool(args->dnode, NULL); + + area = circuit->area; + if (area) { + if (circuit->tilfa_protection[1]) + area->tilfa_protected_links[1]++; + else { + assert(area->tilfa_protected_links[1] > 0); + area->tilfa_protected_links[1]--; + } + + lsp_regenerate_schedule(area, area->is_type, 0); + } + + return NB_OK; +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-2/ti-lfa/node-protection + */ +int lib_interface_isis_fast_reroute_level_2_ti_lfa_node_protection_modify( + struct nb_cb_modify_args *args) +{ + struct isis_area *area; + struct isis_circuit *circuit; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + circuit = nb_running_get_entry(args->dnode, NULL, true); + circuit->tilfa_node_protection[1] = + yang_dnode_get_bool(args->dnode, NULL); + + area = circuit->area; + if (area) + lsp_regenerate_schedule(area, area->is_type, 0); + + return NB_OK; +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-2/ti-lfa/link-fallback + */ +int lib_interface_isis_fast_reroute_level_2_ti_lfa_link_fallback_modify( + struct nb_cb_modify_args *args) +{ + struct isis_area *area; + struct isis_circuit *circuit; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + circuit = nb_running_get_entry(args->dnode, NULL, true); + circuit->tilfa_link_fallback[1] = + yang_dnode_get_bool(args->dnode, NULL); + + area = circuit->area; + if (area) + lsp_regenerate_schedule(area, area->is_type, 0); + + return NB_OK; +} |