summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp_aspath.h8
-rw-r--r--bgpd/bgp_filter.c20
-rw-r--r--bgpd/bgp_filter.h6
-rw-r--r--bgpd/bgp_routemap.c34
-rw-r--r--bgpd/bgp_routemap_nb.c11
-rw-r--r--bgpd/bgp_routemap_nb.h17
-rw-r--r--bgpd/bgp_routemap_nb_config.c134
-rw-r--r--lib/filter_nb.c69
-rw-r--r--lib/mgmt_fe_client.c30
-rw-r--r--lib/mgmt_fe_client.h3
-rw-r--r--lib/northbound.c31
-rw-r--r--tests/topotests/bgp_set_aspath_exclude/test_bgp_set_aspath_exclude.py104
-rw-r--r--tests/topotests/mgmt_config/test_regression.py20
-rw-r--r--tests/topotests/nb_config/r1/frr.conf6
-rw-r--r--tests/topotests/nb_config/test_nb_config.py69
-rw-r--r--yang/frr-bgp-route-map.yang6
-rw-r--r--zebra/zebra_nb.c16
-rw-r--r--zebra/zebra_nb.h6
-rw-r--r--zebra/zebra_nb_config.c75
19 files changed, 518 insertions, 147 deletions
diff --git a/bgpd/bgp_aspath.h b/bgpd/bgp_aspath.h
index ebfc7d087d..2a831c3a55 100644
--- a/bgpd/bgp_aspath.h
+++ b/bgpd/bgp_aspath.h
@@ -65,6 +65,14 @@ struct aspath {
#define ASPATH_STR_DEFAULT_LEN 32
+/* `set as-path exclude ASn' */
+struct aspath_exclude {
+ struct aspath *aspath;
+ bool exclude_all;
+ char *exclude_aspath_acl_name;
+ struct as_list *exclude_aspath_acl;
+};
+
/* Prototypes. */
extern void aspath_init(void);
extern void aspath_finish(void);
diff --git a/bgpd/bgp_filter.c b/bgpd/bgp_filter.c
index ad541b67ad..a85117965a 100644
--- a/bgpd/bgp_filter.c
+++ b/bgpd/bgp_filter.c
@@ -205,8 +205,17 @@ static struct as_list *as_list_new(void)
static void as_list_free(struct as_list *aslist)
{
- XFREE(MTYPE_AS_STR, aslist->name);
- XFREE(MTYPE_AS_LIST, aslist);
+ struct aspath_exclude_list *cur_bp = aslist->exclude_list;
+ struct aspath_exclude_list *next_bp = NULL;
+
+ while (cur_bp) {
+ next_bp = cur_bp->next;
+ XFREE(MTYPE_ROUTE_MAP_COMPILED, cur_bp);
+ cur_bp = next_bp;
+ }
+
+ XFREE (MTYPE_AS_STR, aslist->name);
+ XFREE (MTYPE_AS_LIST, aslist);
}
/* Insert new AS list to list of as_list. Each as_list is sorted by
@@ -290,6 +299,7 @@ static void as_list_delete(struct as_list *aslist)
{
struct as_list_list *list;
struct as_filter *filter, *next;
+ struct aspath_exclude_list *cur_bp;
for (filter = aslist->head; filter; filter = next) {
next = filter->next;
@@ -308,6 +318,12 @@ static void as_list_delete(struct as_list *aslist)
else
list->head = aslist->next;
+ cur_bp = aslist->exclude_list;
+ while (cur_bp) {
+ cur_bp->bp_as_excl->exclude_aspath_acl = NULL;
+ cur_bp = cur_bp->next;
+ }
+
as_list_free(aslist);
}
diff --git a/bgpd/bgp_filter.h b/bgpd/bgp_filter.h
index 1890fd3d96..2d9f07ce84 100644
--- a/bgpd/bgp_filter.h
+++ b/bgpd/bgp_filter.h
@@ -25,6 +25,11 @@ struct as_filter {
int64_t seq;
};
+struct aspath_exclude_list {
+ struct aspath_exclude_list *next;
+ struct aspath_exclude *bp_as_excl;
+};
+
/* AS path filter list. */
struct as_list {
char *name;
@@ -34,6 +39,7 @@ struct as_list {
struct as_filter *head;
struct as_filter *tail;
+ struct aspath_exclude_list *exclude_list;
};
diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c
index 36e04c5e68..f4ebd4aa9b 100644
--- a/bgpd/bgp_routemap.c
+++ b/bgpd/bgp_routemap.c
@@ -2323,17 +2323,10 @@ static const struct route_map_rule_cmd route_set_aspath_prepend_cmd = {
route_set_aspath_prepend_free,
};
-/* `set as-path exclude ASn' */
-struct aspath_exclude {
- struct aspath *aspath;
- bool exclude_all;
- char *exclude_aspath_acl_name;
- struct as_list *exclude_aspath_acl;
-};
-
static void *route_aspath_exclude_compile(const char *arg)
{
struct aspath_exclude *ase;
+ struct aspath_exclude_list *ael;
const char *str = arg;
static const char asp_acl[] = "as-path-access-list";
@@ -2348,16 +2341,41 @@ static void *route_aspath_exclude_compile(const char *arg)
ase->exclude_aspath_acl = as_list_lookup(str);
} else
ase->aspath = aspath_str2aspath(str, bgp_get_asnotation(NULL));
+
+ if (ase->exclude_aspath_acl) {
+ ael = XCALLOC(MTYPE_ROUTE_MAP_COMPILED,
+ sizeof(struct aspath_exclude_list));
+ ael->bp_as_excl = ase;
+ ael->next = ase->exclude_aspath_acl->exclude_list;
+ ase->exclude_aspath_acl->exclude_list = ael;
+ }
+
return ase;
}
static void route_aspath_exclude_free(void *rule)
{
struct aspath_exclude *ase = rule;
+ struct aspath_exclude_list *cur_ael = NULL;
+ struct aspath_exclude_list *prev_ael = NULL;
aspath_free(ase->aspath);
if (ase->exclude_aspath_acl_name)
XFREE(MTYPE_TMP, ase->exclude_aspath_acl_name);
+ if (ase->exclude_aspath_acl)
+ cur_ael = ase->exclude_aspath_acl->exclude_list;
+ while (cur_ael) {
+ if (cur_ael->bp_as_excl == ase) {
+ if (prev_ael)
+ prev_ael->next = cur_ael->next;
+ else
+ ase->exclude_aspath_acl->exclude_list = NULL;
+ XFREE(MTYPE_ROUTE_MAP_COMPILED, cur_ael);
+ break;
+ }
+ prev_ael = cur_ael;
+ cur_ael = cur_ael->next;
+ }
XFREE(MTYPE_ROUTE_MAP_COMPILED, ase);
}
diff --git a/bgpd/bgp_routemap_nb.c b/bgpd/bgp_routemap_nb.c
index abebfe5155..096502aaa9 100644
--- a/bgpd/bgp_routemap_nb.c
+++ b/bgpd/bgp_routemap_nb.c
@@ -147,6 +147,8 @@ const struct frr_yang_module_info frr_bgp_route_map_info = {
{
.xpath = "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:comm-list",
.cbs = {
+ .create = lib_route_map_entry_match_condition_rmap_match_condition_comm_list_create,
+ .destroy = lib_route_map_entry_match_condition_rmap_match_condition_comm_list_destroy,
.apply_finish = lib_route_map_entry_match_condition_rmap_match_condition_comm_list_finish,
}
},
@@ -154,7 +156,6 @@ const struct frr_yang_module_info frr_bgp_route_map_info = {
.xpath = "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name",
.cbs = {
.modify = lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_name_modify,
- .destroy = lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_name_destroy,
}
},
{
@@ -356,6 +357,8 @@ const struct frr_yang_module_info frr_bgp_route_map_info = {
{
.xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:aggregator",
.cbs = {
+ .create = lib_route_map_entry_set_action_rmap_set_action_aggregator_create,
+ .destroy = lib_route_map_entry_set_action_rmap_set_action_aggregator_destroy,
.apply_finish = lib_route_map_entry_set_action_rmap_set_action_aggregator_finish,
}
},
@@ -363,14 +366,12 @@ const struct frr_yang_module_info frr_bgp_route_map_info = {
.xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:aggregator/aggregator-asn",
.cbs = {
.modify = lib_route_map_entry_set_action_rmap_set_action_aggregator_aggregator_asn_modify,
- .destroy = lib_route_map_entry_set_action_rmap_set_action_aggregator_aggregator_asn_destroy,
}
},
{
.xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:aggregator/aggregator-address",
.cbs = {
.modify = lib_route_map_entry_set_action_rmap_set_action_aggregator_aggregator_address_modify,
- .destroy = lib_route_map_entry_set_action_rmap_set_action_aggregator_aggregator_address_destroy,
}
},
{
@@ -390,6 +391,8 @@ const struct frr_yang_module_info frr_bgp_route_map_info = {
{
.xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:extcommunity-lb",
.cbs = {
+ .create = lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_create,
+ .destroy = lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_destroy,
.apply_finish = lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_finish,
}
},
@@ -397,7 +400,6 @@ const struct frr_yang_module_info frr_bgp_route_map_info = {
.xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:extcommunity-lb/lb-type",
.cbs = {
.modify = lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_lb_type_modify,
- .destroy = lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_lb_type_destroy,
}
},
{
@@ -418,7 +420,6 @@ const struct frr_yang_module_info frr_bgp_route_map_info = {
.xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:extcommunity-lb/two-octet-as-specific",
.cbs = {
.modify = lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_two_octet_as_specific_modify,
- .destroy = lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_two_octet_as_specific_destroy,
}
},
{
diff --git a/bgpd/bgp_routemap_nb.h b/bgpd/bgp_routemap_nb.h
index 28e4188026..d7f0cea30e 100644
--- a/bgpd/bgp_routemap_nb.h
+++ b/bgpd/bgp_routemap_nb.h
@@ -60,9 +60,12 @@ int lib_route_map_entry_match_condition_rmap_match_condition_evpn_route_type_mod
int lib_route_map_entry_match_condition_rmap_match_condition_evpn_route_type_destroy(struct nb_cb_destroy_args *args);
int lib_route_map_entry_match_condition_rmap_match_condition_route_distinguisher_modify(struct nb_cb_modify_args *args);
int lib_route_map_entry_match_condition_rmap_match_condition_route_distinguisher_destroy(struct nb_cb_destroy_args *args);
+int lib_route_map_entry_match_condition_rmap_match_condition_comm_list_create(
+ struct nb_cb_create_args *args);
+int lib_route_map_entry_match_condition_rmap_match_condition_comm_list_destroy(
+ struct nb_cb_destroy_args *args);
void lib_route_map_entry_match_condition_rmap_match_condition_comm_list_finish(struct nb_cb_apply_finish_args *args);
int lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_name_modify(struct nb_cb_modify_args *args);
-int lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_name_destroy(struct nb_cb_destroy_args *args);
int lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_name_exact_match_modify(struct nb_cb_modify_args *args);
int lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_name_exact_match_destroy(struct nb_cb_destroy_args *args);
int lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_name_any_modify(
@@ -127,24 +130,28 @@ int lib_route_map_entry_set_action_rmap_set_action_large_community_none_modify(s
int lib_route_map_entry_set_action_rmap_set_action_large_community_none_destroy(struct nb_cb_destroy_args *args);
int lib_route_map_entry_set_action_rmap_set_action_large_community_string_modify(struct nb_cb_modify_args *args);
int lib_route_map_entry_set_action_rmap_set_action_large_community_string_destroy(struct nb_cb_destroy_args *args);
+int lib_route_map_entry_set_action_rmap_set_action_aggregator_create(
+ struct nb_cb_create_args *args);
+int lib_route_map_entry_set_action_rmap_set_action_aggregator_destroy(
+ struct nb_cb_destroy_args *args);
void lib_route_map_entry_set_action_rmap_set_action_aggregator_finish(struct nb_cb_apply_finish_args *args);
int lib_route_map_entry_set_action_rmap_set_action_aggregator_aggregator_asn_modify(struct nb_cb_modify_args *args);
-int lib_route_map_entry_set_action_rmap_set_action_aggregator_aggregator_asn_destroy(struct nb_cb_destroy_args *args);
int lib_route_map_entry_set_action_rmap_set_action_aggregator_aggregator_address_modify(struct nb_cb_modify_args *args);
-int lib_route_map_entry_set_action_rmap_set_action_aggregator_aggregator_address_destroy(struct nb_cb_destroy_args *args);
int lib_route_map_entry_set_action_rmap_set_action_comm_list_num_modify(struct nb_cb_modify_args *args);
int lib_route_map_entry_set_action_rmap_set_action_comm_list_num_destroy(struct nb_cb_destroy_args *args);
int lib_route_map_entry_set_action_rmap_set_action_comm_list_num_extended_modify(struct nb_cb_modify_args *args);
int lib_route_map_entry_set_action_rmap_set_action_comm_list_num_extended_destroy(struct nb_cb_destroy_args *args);
int lib_route_map_entry_set_action_rmap_set_action_comm_list_name_modify(struct nb_cb_modify_args *args);
int lib_route_map_entry_set_action_rmap_set_action_comm_list_name_destroy(struct nb_cb_destroy_args *args);
+int lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_create(
+ struct nb_cb_create_args *args);
+int lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_destroy(
+ struct nb_cb_destroy_args *args);
void lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_finish(struct nb_cb_apply_finish_args *args);
int lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_lb_type_modify(struct nb_cb_modify_args *args);
-int lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_lb_type_destroy(struct nb_cb_destroy_args *args);
int lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_bandwidth_modify(struct nb_cb_modify_args *args);
int lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_bandwidth_destroy(struct nb_cb_destroy_args *args);
int lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_two_octet_as_specific_modify(struct nb_cb_modify_args *args);
-int lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_two_octet_as_specific_destroy(struct nb_cb_destroy_args *args);
int lib_route_map_entry_set_action_rmap_set_action_extcommunity_none_modify(
struct nb_cb_modify_args *args);
int lib_route_map_entry_set_action_rmap_set_action_extcommunity_none_destroy(
diff --git a/bgpd/bgp_routemap_nb_config.c b/bgpd/bgp_routemap_nb_config.c
index d6fcb6b8dc..c1d6ee12e1 100644
--- a/bgpd/bgp_routemap_nb_config.c
+++ b/bgpd/bgp_routemap_nb_config.c
@@ -1121,6 +1121,27 @@ lib_route_map_entry_match_condition_rmap_match_condition_route_distinguisher_des
/*
* XPath = /frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:comm-list
*/
+int lib_route_map_entry_match_condition_rmap_match_condition_comm_list_create(
+ struct nb_cb_create_args *args)
+{
+ return NB_OK;
+}
+
+int lib_route_map_entry_match_condition_rmap_match_condition_comm_list_destroy(
+ struct nb_cb_destroy_args *args)
+{
+ switch (args->event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ break;
+ case NB_EV_APPLY:
+ return lib_route_map_entry_match_destroy(args);
+ }
+
+ return NB_OK;
+}
+
void
lib_route_map_entry_match_condition_rmap_match_condition_comm_list_finish(
struct nb_cb_apply_finish_args *args)
@@ -1211,23 +1232,6 @@ lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_nam
return NB_OK;
}
-int
-lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_name_destroy(
- struct nb_cb_destroy_args *args)
-{
- switch (args->event) {
- case NB_EV_VALIDATE:
- case NB_EV_PREPARE:
- case NB_EV_ABORT:
- break;
- case NB_EV_APPLY:
- return lib_route_map_entry_match_destroy(args);
- }
-
- return NB_OK;
-
-}
-
/*
* XPath:
* /frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name-any
@@ -1253,9 +1257,8 @@ int lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
- break;
case NB_EV_APPLY:
- return lib_route_map_entry_match_destroy(args);
+ break;
}
return NB_OK;
@@ -1287,9 +1290,8 @@ lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_nam
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
- break;
case NB_EV_APPLY:
- return lib_route_map_entry_match_destroy(args);
+ break;
}
return NB_OK;
@@ -2735,6 +2737,27 @@ lib_route_map_entry_set_action_rmap_set_action_large_community_string_destroy(
* xpath =
* /frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:aggregator
*/
+int lib_route_map_entry_set_action_rmap_set_action_aggregator_create(
+ struct nb_cb_create_args *args)
+{
+ return NB_OK;
+}
+
+int lib_route_map_entry_set_action_rmap_set_action_aggregator_destroy(
+ struct nb_cb_destroy_args *args)
+{
+ switch (args->event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ break;
+ case NB_EV_APPLY:
+ return lib_route_map_entry_set_destroy(args);
+ }
+
+ return NB_OK;
+}
+
void lib_route_map_entry_set_action_rmap_set_action_aggregator_finish(
struct nb_cb_apply_finish_args *args)
{
@@ -2799,22 +2822,6 @@ lib_route_map_entry_set_action_rmap_set_action_aggregator_aggregator_asn_modify(
return NB_OK;
}
-int
-lib_route_map_entry_set_action_rmap_set_action_aggregator_aggregator_asn_destroy(
- struct nb_cb_destroy_args *args)
-{
- switch (args->event) {
- case NB_EV_VALIDATE:
- case NB_EV_PREPARE:
- case NB_EV_ABORT:
- break;
- case NB_EV_APPLY:
- return lib_route_map_entry_set_destroy(args);
- }
-
- return NB_OK;
-}
-
/*
* XPath:
* /frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:aggregator/aggregator-address
@@ -2834,22 +2841,6 @@ lib_route_map_entry_set_action_rmap_set_action_aggregator_aggregator_address_mod
return NB_OK;
}
-int
-lib_route_map_entry_set_action_rmap_set_action_aggregator_aggregator_address_destroy(
- struct nb_cb_destroy_args *args)
-{
- switch (args->event) {
- case NB_EV_VALIDATE:
- case NB_EV_PREPARE:
- case NB_EV_ABORT:
- break;
- case NB_EV_APPLY:
- return lib_route_map_entry_set_destroy(args);
- }
-
- return NB_OK;
-}
-
/*
* XPath:
* /frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:comm-list-name
@@ -2918,6 +2909,27 @@ lib_route_map_entry_set_action_rmap_set_action_comm_list_name_destroy(
* XPath:
* /frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:extcommunity-lb
*/
+int lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_create(
+ struct nb_cb_create_args *args)
+{
+ return NB_OK;
+}
+
+int lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_destroy(
+ struct nb_cb_destroy_args *args)
+{
+ switch (args->event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ break;
+ case NB_EV_APPLY:
+ return lib_route_map_entry_set_destroy(args);
+ }
+
+ return NB_OK;
+}
+
void
lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_finish(
struct nb_cb_apply_finish_args *args)
@@ -2973,13 +2985,6 @@ lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_lb_type_modify(
return NB_OK;
}
-int
-lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_lb_type_destroy(
- struct nb_cb_destroy_args *args)
-{
- return lib_route_map_entry_set_destroy(args);
-}
-
/*
* XPath:
* /frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:extcommunity-lb/bandwidth
@@ -2995,7 +3000,7 @@ int
lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_bandwidth_destroy(
struct nb_cb_destroy_args *args)
{
- return lib_route_map_entry_set_destroy(args);
+ return NB_OK;
}
/*
@@ -3061,13 +3066,6 @@ lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_two_octet_as_spec
return NB_OK;
}
-int
-lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_two_octet_as_specific_destroy(
- struct nb_cb_destroy_args *args)
-{
- return lib_route_map_entry_set_destroy(args);
-}
-
/*
* XPath:
* /frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:extcommunity-none
diff --git a/lib/filter_nb.c b/lib/filter_nb.c
index eba4e421c0..ec31f6d395 100644
--- a/lib/filter_nb.c
+++ b/lib/filter_nb.c
@@ -757,6 +757,32 @@ lib_access_list_entry_host_destroy(struct nb_cb_destroy_args *args)
}
/*
+ * XPath: /frr-filter:lib/access-list/entry/network
+ */
+static int lib_access_list_entry_network_create(struct nb_cb_create_args *args)
+{
+ /* Nothing to do here, everything is done in children callbacks */
+ return NB_OK;
+}
+
+static int lib_access_list_entry_network_destroy(struct nb_cb_destroy_args *args)
+{
+ struct filter_cisco *fc;
+ struct filter *f;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ f = nb_running_get_entry(args->dnode, NULL, true);
+ fc = &f->u.cfilter;
+ cisco_unset_addr_mask(&fc->addr, &fc->addr_mask);
+
+ acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_DELETED);
+
+ return NB_OK;
+}
+
+/*
* XPath: /frr-filter:lib/access-list/entry/network/address
*/
static int
@@ -928,6 +954,35 @@ static int lib_access_list_entry_destination_host_destroy(
}
/*
+ * XPath: /frr-filter:lib/access-list/entry/destination-network
+ */
+static int
+lib_access_list_entry_destination_network_create(struct nb_cb_create_args *args)
+{
+ /* Nothing to do here, everything is done in children callbacks */
+ return NB_OK;
+}
+
+static int lib_access_list_entry_destination_network_destroy(
+ struct nb_cb_destroy_args *args)
+{
+ struct filter_cisco *fc;
+ struct filter *f;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ f = nb_running_get_entry(args->dnode, NULL, true);
+ fc = &f->u.cfilter;
+ fc->extended = 0;
+ cisco_unset_addr_mask(&fc->mask, &fc->mask_mask);
+
+ acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_DELETED);
+
+ return NB_OK;
+}
+
+/*
* XPath: /frr-filter:lib/access-list/entry/destination-network/address
*/
static int lib_access_list_entry_destination_network_address_modify(
@@ -1629,6 +1684,13 @@ const struct frr_yang_module_info frr_filter_info = {
}
},
{
+ .xpath = "/frr-filter:lib/access-list/entry/network",
+ .cbs = {
+ .create = lib_access_list_entry_network_create,
+ .destroy = lib_access_list_entry_network_destroy,
+ }
+ },
+ {
.xpath = "/frr-filter:lib/access-list/entry/network/address",
.cbs = {
.modify = lib_access_list_entry_network_address_modify,
@@ -1655,6 +1717,13 @@ const struct frr_yang_module_info frr_filter_info = {
}
},
{
+ .xpath = "/frr-filter:lib/access-list/entry/destination-network",
+ .cbs = {
+ .create = lib_access_list_entry_destination_network_create,
+ .destroy = lib_access_list_entry_destination_network_destroy,
+ }
+ },
+ {
.xpath = "/frr-filter:lib/access-list/entry/destination-network/address",
.cbs = {
.modify = lib_access_list_entry_destination_network_address_modify,
diff --git a/lib/mgmt_fe_client.c b/lib/mgmt_fe_client.c
index bfdecedc4e..a107582bea 100644
--- a/lib/mgmt_fe_client.c
+++ b/lib/mgmt_fe_client.c
@@ -510,14 +510,11 @@ static void fe_client_handle_native_msg(struct mgmt_fe_client *client,
debug_fe_client("Got native message for session-id %" PRIu64,
msg->refer_id);
- if (msg->code != MGMT_MSG_CODE_NOTIFY) {
- session = mgmt_fe_find_session_by_session_id(client,
- msg->refer_id);
- if (!session || !session->client) {
- log_err_fe_client("No session for received native msg session-id %" PRIu64,
- msg->refer_id);
- return;
- }
+ session = mgmt_fe_find_session_by_session_id(client, msg->refer_id);
+ if (!session || !session->client) {
+ log_err_fe_client("No session for received native msg session-id %" PRIu64,
+ msg->refer_id);
+ return;
}
switch (msg->code) {
@@ -558,6 +555,9 @@ static void fe_client_handle_native_msg(struct mgmt_fe_client *client,
tree_msg->partial_error);
break;
case MGMT_MSG_CODE_NOTIFY:
+ if (!session->client->cbs.async_notification)
+ return;
+
notify_msg = (typeof(notify_msg))msg;
if (msg_len < sizeof(*notify_msg)) {
log_err_fe_client("Corrupt notify-data msg recv");
@@ -579,15 +579,13 @@ static void fe_client_handle_native_msg(struct mgmt_fe_client *client,
notify_msg->result_type);
return;
}
- FOREACH_SESSION_IN_LIST (client, session) {
- if (!session->client->cbs.async_notification)
- continue;
- session->client->cbs
- .async_notification(client, client->user_data,
- session->client_id,
- session->user_ctx, data);
- }
+ session->client->cbs.async_notification(client,
+ client->user_data,
+ session->client_id,
+ msg->refer_id,
+ session->user_ctx, data);
+
if (notify_msg->result_type != LYD_JSON)
darr_free(data);
break;
diff --git a/lib/mgmt_fe_client.h b/lib/mgmt_fe_client.h
index 7af1270071..eee4594e17 100644
--- a/lib/mgmt_fe_client.h
+++ b/lib/mgmt_fe_client.h
@@ -117,7 +117,8 @@ struct mgmt_fe_client_cbs {
/* Called with asynchronous notifications from backends */
int (*async_notification)(struct mgmt_fe_client *client,
uintptr_t user_data, uint64_t client_id,
- uintptr_t session_ctx, const char *result);
+ uint64_t session_id, uintptr_t session_ctx,
+ const char *result);
/* Called when new native error is returned */
int (*error_notify)(struct mgmt_fe_client *client, uintptr_t user_data,
diff --git a/lib/northbound.c b/lib/northbound.c
index 6b31b818c5..25ea658bc4 100644
--- a/lib/northbound.c
+++ b/lib/northbound.c
@@ -157,7 +157,7 @@ void nb_nodes_delete(void)
struct nb_node *nb_node_find(const char *path)
{
const struct lysc_node *snode;
- uint32_t llopts;
+ uint32_t llopts = 0;
/*
* Use libyang to find the schema node associated to the path and get
@@ -165,8 +165,6 @@ struct nb_node *nb_node_find(const char *path)
* disable logging temporarily to avoid libyang from logging an error
* message when the node is not found.
*/
- llopts = ly_log_options(LY_LOSTORE);
- llopts &= ~LY_LOLOG;
ly_temp_log_options(&llopts);
snode = yang_find_snode(ly_native_ctx, path, 0);
@@ -391,14 +389,27 @@ void nb_config_replace(struct nb_config *config_dst,
static inline int nb_config_cb_compare(const struct nb_config_cb *a,
const struct nb_config_cb *b)
{
+ bool a_destroy = a->operation == NB_CB_DESTROY;
+ bool b_destroy = b->operation == NB_CB_DESTROY;
+
+ /*
+ * Sort by operation first. All "destroys" must come first, to correctly
+ * process the change of a "case" inside a "choice". The old "case" must
+ * be deleted before the new "case" is created.
+ */
+ if (a_destroy && !b_destroy)
+ return -1;
+ if (!a_destroy && b_destroy)
+ return 1;
+
/*
- * Sort by priority first. If the operation is "destroy", reverse the
- * order, so that the dependencies are destroyed before the dependants.
+ * Then sort by priority. If the operation is "destroy", reverse the
+ * order, so that the dependants are deleted before the dependencies.
*/
if (a->nb_node->priority < b->nb_node->priority)
- return a->operation != NB_CB_DESTROY ? -1 : 1;
+ return !a_destroy ? -1 : 1;
if (a->nb_node->priority > b->nb_node->priority)
- return a->operation != NB_CB_DESTROY ? 1 : -1;
+ return !a_destroy ? 1 : -1;
/*
* Preserve the order of the configuration changes as told by libyang.
@@ -1814,6 +1825,7 @@ nb_apply_finish_cb_new(struct nb_config_cbs *cbs, const struct nb_node *nb_node,
struct nb_config_cb *cb;
cb = XCALLOC(MTYPE_TMP, sizeof(*cb));
+ cb->operation = NB_CB_APPLY_FINISH;
cb->nb_node = nb_node;
cb->dnode = dnode;
RB_INSERT(nb_config_cbs, cbs, cb);
@@ -1828,6 +1840,7 @@ nb_apply_finish_cb_find(struct nb_config_cbs *cbs,
{
struct nb_config_cb s;
+ s.operation = NB_CB_APPLY_FINISH;
s.seq = 0;
s.nb_node = nb_node;
s.dnode = dnode;
@@ -1925,6 +1938,8 @@ bool nb_cb_operation_is_valid(enum nb_cb_operation operation,
return false;
break;
case LYS_CONTAINER:
+ if (snode->parent && snode->parent->nodetype == LYS_CASE)
+ return true;
scontainer = (struct lysc_node_container *)snode;
if (!CHECK_FLAG(scontainer->flags, LYS_PRESENCE))
return false;
@@ -1979,6 +1994,8 @@ bool nb_cb_operation_is_valid(enum nb_cb_operation operation,
return false;
break;
case LYS_CONTAINER:
+ if (snode->parent && snode->parent->nodetype == LYS_CASE)
+ return true;
scontainer = (struct lysc_node_container *)snode;
if (!CHECK_FLAG(scontainer->flags, LYS_PRESENCE))
return false;
diff --git a/tests/topotests/bgp_set_aspath_exclude/test_bgp_set_aspath_exclude.py b/tests/topotests/bgp_set_aspath_exclude/test_bgp_set_aspath_exclude.py
index a0cd89f064..d373a749fe 100644
--- a/tests/topotests/bgp_set_aspath_exclude/test_bgp_set_aspath_exclude.py
+++ b/tests/topotests/bgp_set_aspath_exclude/test_bgp_set_aspath_exclude.py
@@ -62,23 +62,48 @@ def teardown_module(mod):
tgen.stop_topology()
+expected_1 = {
+ "routes": {
+ "172.16.255.31/32": [{"path": "65002"}],
+ "172.16.255.32/32": [{"path": ""}],
+ }
+}
+
+expected_2 = {
+ "routes": {
+ "172.16.255.31/32": [{"path": ""}],
+ "172.16.255.32/32": [{"path": ""}],
+ }
+}
+
+expected_3 = {
+ "routes": {
+ "172.16.255.31/32": [{"path": "65003"}],
+ "172.16.255.32/32": [{"path": "65003"}],
+ }
+}
+
+expected_4 = {
+ "routes": {
+ "172.16.255.31/32": [{"path": "65002 65003"}],
+ "172.16.255.32/32": [{"path": "65002 65003"}],
+ }
+}
+
+
+def bgp_converge(router, expected):
+ output = json.loads(router.vtysh_cmd("show bgp ipv4 unicast json"))
+
+ return topotest.json_cmp(output, expected)
+
+
def test_bgp_set_aspath_exclude():
tgen = get_topogen()
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
- def _bgp_converge(router):
- output = json.loads(router.vtysh_cmd("show bgp ipv4 unicast json"))
- expected = {
- "routes": {
- "172.16.255.31/32": [{"path": "65002"}],
- "172.16.255.32/32": [{"path": ""}],
- }
- }
- return topotest.json_cmp(output, expected)
-
- test_func = functools.partial(_bgp_converge, tgen.gears["r1"])
+ test_func = functools.partial(bgp_converge, tgen.gears["r1"], expected_1)
_, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5)
assert result is None, "Failed overriding incoming AS-PATH with route-map"
@@ -102,19 +127,7 @@ conf
"""
)
- expected = {
- "routes": {
- "172.16.255.31/32": [{"path": ""}],
- "172.16.255.32/32": [{"path": ""}],
- }
- }
-
- def _bgp_regexp_1(router):
- output = json.loads(router.vtysh_cmd("show bgp ipv4 unicast json"))
-
- return topotest.json_cmp(output, expected)
-
- test_func = functools.partial(_bgp_regexp_1, tgen.gears["r1"])
+ test_func = functools.partial(bgp_converge, tgen.gears["r1"], expected_2)
_, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5)
assert result is None, "Failed overriding incoming AS-PATH with regex 1 route-map"
@@ -127,19 +140,46 @@ conf
"""
)
- expected = {
- "routes": {
- "172.16.255.31/32": [{"path": "65003"}],
- "172.16.255.32/32": [{"path": "65003"}],
- }
- }
-
- test_func = functools.partial(_bgp_regexp_1, tgen.gears["r1"])
+ # tgen.mininet_cli()
+ test_func = functools.partial(bgp_converge, tgen.gears["r1"], expected_3)
_, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5)
assert result is None, "Failed overriding incoming AS-PATH with regex 2 route-map"
+def test_no_bgp_set_aspath_exclude_access_list():
+ tgen = get_topogen()
+
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ rname = "r1"
+ r1 = tgen.gears[rname]
+
+ r1.vtysh_cmd(
+ """
+conf
+ no bgp as-path access-list SECOND permit 2
+ """
+ )
+
+ test_func = functools.partial(bgp_converge, tgen.gears["r1"], expected_3)
+ _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5)
+
+ assert result is None, "Failed removing bgp as-path access-list"
+
+ r1.vtysh_cmd(
+ """
+clear bgp *
+ """
+ )
+
+ test_func = functools.partial(bgp_converge, tgen.gears["r1"], expected_4)
+ _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5)
+
+ assert result is None, "Failed to renegotiate with peers"
+
+
if __name__ == "__main__":
args = ["-s"] + sys.argv[1:]
sys.exit(pytest.main(args))
diff --git a/tests/topotests/mgmt_config/test_regression.py b/tests/topotests/mgmt_config/test_regression.py
index 70f38d2ec7..928151a23a 100644
--- a/tests/topotests/mgmt_config/test_regression.py
+++ b/tests/topotests/mgmt_config/test_regression.py
@@ -51,3 +51,23 @@ def test_regression_issue_13920(tgen):
)
output = r1.net.checkRouterCores()
assert not output.strip()
+
+
+def test_regression_pullreq_15423(tgen):
+ r1 = tgen.gears["r1"]
+ r1.vtysh_multicmd(
+ """
+ conf t
+ access-list test seq 1 permit ip any 10.10.10.0 0.0.0.255
+ """
+ )
+
+ output = r1.vtysh_multicmd(
+ """
+ conf terminal file-lock
+ mgmt delete-config /frr-filter:lib/access-list[name='test'][type='ipv4']/entry[sequence='1']/destination-network
+ mgmt commit apply
+ end
+ """
+ )
+ assert "No changes found" not in output
diff --git a/tests/topotests/nb_config/r1/frr.conf b/tests/topotests/nb_config/r1/frr.conf
new file mode 100644
index 0000000000..677ec0b86d
--- /dev/null
+++ b/tests/topotests/nb_config/r1/frr.conf
@@ -0,0 +1,6 @@
+log timestamp precision 6
+log file frr.log
+
+interface r1-eth0
+ ip address 1.1.1.1/24
+exit
diff --git a/tests/topotests/nb_config/test_nb_config.py b/tests/topotests/nb_config/test_nb_config.py
new file mode 100644
index 0000000000..f699a4e20e
--- /dev/null
+++ b/tests/topotests/nb_config/test_nb_config.py
@@ -0,0 +1,69 @@
+# -*- coding: utf-8 eval: (blacken-mode 1) -*-
+# SPDX-License-Identifier: ISC
+#
+# February 24 2024, Christian Hopps <chopps@labn.net>
+#
+# Copyright (c) 2024, LabN Consulting, L.L.C.
+#
+"""
+Test Northbound Config Operations
+"""
+import json
+import os
+
+import pytest
+from lib.topogen import Topogen
+from lib.topotest import json_cmp
+
+pytestmark = [pytest.mark.mgmtd]
+
+CWD = os.path.dirname(os.path.realpath(__file__))
+
+
+@pytest.fixture(scope="module")
+def tgen(request):
+ "Setup/Teardown the environment and provide tgen argument to tests"
+
+ topodef = {
+ "s1": ("r1",)
+ }
+
+ tgen = Topogen(topodef, request.module.__name__)
+ tgen.start_topology()
+
+ router_list = tgen.routers()
+ for rname, router in router_list.items():
+ router.load_frr_config("frr.conf")
+
+ tgen.start_router()
+ yield tgen
+ tgen.stop_topology()
+
+
+def test_access_list_config_ordering(tgen):
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ r1 = tgen.gears["r1"]
+
+ output = r1.vtysh_multicmd([
+ "conf t",
+ "access-list test seq 1 permit host 10.0.0.1"])
+ output = r1.vtysh_cmd("show ip access-list test json")
+ got = json.loads(output)
+ expected = json.loads('{"ZEBRA":{"test":{"type":"Standard", "addressFamily":"IPv4", "rules":[{"sequenceNumber":1, "filterType":"permit", "address":"10.0.0.1", "mask":"0.0.0.0"}]}}}')
+ result = json_cmp(got, expected)
+ assert result is None
+
+ #
+ # If the northbound mis-orders the create/delete then this test fails.
+ # https://github.com/FRRouting/frr/pull/15423/commits/38b85e0c2bc555b8827dbd2cb6515b6febf548b4
+ #
+ output = r1.vtysh_multicmd([
+ "conf t",
+ "access-list test seq 1 permit 10.0.0.0/8"])
+ output = r1.vtysh_cmd("show ip access-list test json")
+ got = json.loads(output)
+ expected = json.loads('{"ZEBRA":{"test":{"type":"Zebra", "addressFamily":"IPv4", "rules":[{"sequenceNumber":1, "filterType":"permit", "prefix":"10.0.0.0/8", "exact-match":false}]}}}')
+ result = json_cmp(got, expected)
+ assert result is None
diff --git a/yang/frr-bgp-route-map.yang b/yang/frr-bgp-route-map.yang
index c50c51389e..c679f3b911 100644
--- a/yang/frr-bgp-route-map.yang
+++ b/yang/frr-bgp-route-map.yang
@@ -379,6 +379,7 @@ identity set-extcommunity-color {
grouping extcommunity-non-transitive-types {
leaf two-octet-as-specific {
type boolean;
+ default false;
description
"Non-Transitive Two-Octet AS-Specific Extended Community";
}
@@ -769,6 +770,7 @@ identity set-extcommunity-color {
+ "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:match-condition/frr-route-map:condition, 'frr-bgp-route-map:match-extcommunity')";
container comm-list {
leaf comm-list-name {
+ mandatory true;
type bgp-filter:bgp-list-name;
}
@@ -872,11 +874,13 @@ identity set-extcommunity-color {
description
"Value of the ext-community.";
leaf lb-type {
+ mandatory true;
type frr-bgp-route-map:extcommunity-lb-type;
}
leaf bandwidth {
when "../lb-type = 'explicit-bandwidth'";
+ mandatory true;
type uint16 {
range "1..25600";
}
@@ -1108,12 +1112,14 @@ identity set-extcommunity-color {
container aggregator {
leaf aggregator-asn {
type asn-type;
+ mandatory true;
description
"ASN of the aggregator";
}
leaf aggregator-address {
type inet:ipv4-address;
+ mandatory true;
description
"IPv4 address of the aggregator";
}
diff --git a/zebra/zebra_nb.c b/zebra/zebra_nb.c
index 7e1c43c204..e1ca5ec19b 100644
--- a/zebra/zebra_nb.c
+++ b/zebra/zebra_nb.c
@@ -456,6 +456,8 @@ const struct frr_yang_module_info frr_zebra_info = {
{
.xpath = "/frr-interface:lib/interface/frr-zebra:zebra/link-params/affinities",
.cbs = {
+ .create = lib_interface_zebra_affinities_create,
+ .destroy = lib_interface_zebra_affinities_destroy,
},
},
{
@@ -531,6 +533,13 @@ const struct frr_yang_module_info frr_zebra_info = {
}
},
{
+ .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/evpn-mh/type-0",
+ .cbs = {
+ .create = lib_interface_zebra_evpn_mh_type_0_create,
+ .destroy = lib_interface_zebra_evpn_mh_type_0_destroy,
+ }
+ },
+ {
.xpath = "/frr-interface:lib/interface/frr-zebra:zebra/evpn-mh/type-0/esi",
.cbs = {
.modify = lib_interface_zebra_evpn_mh_type_0_esi_modify,
@@ -538,6 +547,13 @@ const struct frr_yang_module_info frr_zebra_info = {
}
},
{
+ .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/evpn-mh/type-3",
+ .cbs = {
+ .create = lib_interface_zebra_evpn_mh_type_3_create,
+ .destroy = lib_interface_zebra_evpn_mh_type_3_destroy,
+ }
+ },
+ {
.xpath = "/frr-interface:lib/interface/frr-zebra:zebra/evpn-mh/type-3/system-mac",
.cbs = {
.modify = lib_interface_zebra_evpn_mh_type_3_system_mac_modify,
diff --git a/zebra/zebra_nb.h b/zebra/zebra_nb.h
index 97979ef962..d7cf5f4040 100644
--- a/zebra/zebra_nb.h
+++ b/zebra/zebra_nb.h
@@ -145,6 +145,8 @@ int lib_interface_zebra_link_params_utilized_bandwidth_destroy(
int lib_interface_zebra_legacy_admin_group_modify(struct nb_cb_modify_args *args);
int lib_interface_zebra_legacy_admin_group_destroy(
struct nb_cb_destroy_args *args);
+int lib_interface_zebra_affinities_create(struct nb_cb_create_args *args);
+int lib_interface_zebra_affinities_destroy(struct nb_cb_destroy_args *args);
int lib_interface_zebra_affinity_create(struct nb_cb_create_args *args);
int lib_interface_zebra_affinity_destroy(struct nb_cb_destroy_args *args);
int lib_interface_zebra_affinity_mode_modify(struct nb_cb_modify_args *args);
@@ -175,9 +177,13 @@ int lib_interface_zebra_link_params_packet_loss_modify(
struct nb_cb_modify_args *args);
int lib_interface_zebra_link_params_packet_loss_destroy(
struct nb_cb_destroy_args *args);
+int lib_interface_zebra_evpn_mh_type_0_create(struct nb_cb_create_args *args);
+int lib_interface_zebra_evpn_mh_type_0_destroy(struct nb_cb_destroy_args *args);
int lib_interface_zebra_evpn_mh_type_0_esi_modify(struct nb_cb_modify_args *args);
int lib_interface_zebra_evpn_mh_type_0_esi_destroy(
struct nb_cb_destroy_args *args);
+int lib_interface_zebra_evpn_mh_type_3_create(struct nb_cb_create_args *args);
+int lib_interface_zebra_evpn_mh_type_3_destroy(struct nb_cb_destroy_args *args);
int lib_interface_zebra_evpn_mh_type_3_system_mac_modify(
struct nb_cb_modify_args *args);
int lib_interface_zebra_evpn_mh_type_3_system_mac_destroy(
diff --git a/zebra/zebra_nb_config.c b/zebra/zebra_nb_config.c
index 46c95e6c0f..5cb9985ee4 100644
--- a/zebra/zebra_nb_config.c
+++ b/zebra/zebra_nb_config.c
@@ -1746,9 +1746,6 @@ int lib_interface_zebra_legacy_admin_group_modify(
iflp->admin_grp = admin_group_value;
SET_PARAM(iflp, LP_ADM_GRP);
-
- admin_group_clear(&iflp->ext_admin_grp);
- UNSET_PARAM(iflp, LP_EXTEND_ADM_GRP);
break;
}
return NB_OK;
@@ -1778,6 +1775,35 @@ int lib_interface_zebra_legacy_admin_group_destroy(
/*
* XPath:
+ * /frr-interface:lib/interface/frr-zebra:zebra/link-params/affinities
+ */
+int lib_interface_zebra_affinities_create(struct nb_cb_create_args *args)
+{
+ return NB_OK;
+}
+
+int lib_interface_zebra_affinities_destroy(struct nb_cb_destroy_args *args)
+{
+ struct interface *ifp;
+ struct if_link_params *iflp;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ ifp = nb_running_get_entry(args->dnode, NULL, true);
+ iflp = if_link_params_get(ifp);
+
+ iflp->admin_grp = 0;
+ UNSET_PARAM(iflp, LP_ADM_GRP);
+
+ admin_group_clear(&iflp->ext_admin_grp);
+ UNSET_PARAM(iflp, LP_EXTEND_ADM_GRP);
+
+ return NB_OK;
+}
+
+/*
+ * XPath:
* /frr-interface:lib/interface/frr-zebra:zebra/link-params/affinities/affinity
*/
int lib_interface_zebra_affinity_create(struct nb_cb_create_args *args)
@@ -2282,6 +2308,27 @@ static bool esi_unique(struct lyd_node *dnode)
}
/*
+ * XPath: /frr-interface:lib/interface/frr-zebra:zebra/evpn-mh/type-0
+ */
+int lib_interface_zebra_evpn_mh_type_0_create(struct nb_cb_create_args *args)
+{
+ return NB_OK;
+}
+
+int lib_interface_zebra_evpn_mh_type_0_destroy(struct nb_cb_destroy_args *args)
+{
+ struct interface *ifp;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ ifp = nb_running_get_entry(args->dnode, NULL, true);
+ zebra_evpn_es_type0_esi_update(ifp->info, NULL);
+
+ return NB_OK;
+}
+
+/*
* XPath: /frr-interface:lib/interface/frr-zebra:zebra/evpn-mh/type-0/esi
*/
int lib_interface_zebra_evpn_mh_type_0_esi_modify(struct nb_cb_modify_args *args)
@@ -2325,6 +2372,28 @@ int lib_interface_zebra_evpn_mh_type_0_esi_destroy(struct nb_cb_destroy_args *ar
}
/*
+ * XPath: /frr-interface:lib/interface/frr-zebra:zebra/evpn-mh/type-3
+ */
+int lib_interface_zebra_evpn_mh_type_3_create(struct nb_cb_create_args *args)
+{
+ return NB_OK;
+}
+
+int lib_interface_zebra_evpn_mh_type_3_destroy(struct nb_cb_destroy_args *args)
+{
+ struct interface *ifp;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ ifp = nb_running_get_entry(args->dnode, NULL, true);
+ zebra_evpn_es_sys_mac_update(ifp->info, NULL);
+ zebra_evpn_es_lid_update(ifp->info, 0);
+
+ return NB_OK;
+}
+
+/*
* XPath: /frr-interface:lib/interface/frr-zebra:zebra/evpn-mh/type-3/system-mac
*/
int lib_interface_zebra_evpn_mh_type_3_system_mac_modify(