From 094dcc3cdac19d3da65b38effc45aa88d960909f Mon Sep 17 00:00:00 2001 From: Francois Dumontet Date: Tue, 23 Apr 2024 11:16:24 +0200 Subject: [PATCH 001/347] bgpd: fix "bgp as-pah access-list" with "set aspath exclude" set/unset issues whith the following config router bgp 65001 no bgp ebgp-requires-policy neighbor 192.168.1.2 remote-as external neighbor 192.168.1.2 timers 3 10 ! address-family ipv4 unicast neighbor 192.168.1.2 route-map r2 in exit-address-family exit ! bgp as-path access-list FIRST seq 5 permit ^65 bgp as-path access-list SECOND seq 5 permit 2$ ! route-map r2 permit 6 match ip address prefix-list p2 set as-path exclude as-path-access-list SECOND exit ! route-map r2 permit 10 match ip address prefix-list p1 set as-path exclude 65003 exit ! route-map r2 permit 20 match ip address prefix-list p3 set as-path exclude all exit making some no bgp as-path access-list SECOND permit 2$ bgp as-path access-list SECOND permit 3$ clear bgp * no bgp as-path access-list SECOND permit 3$ bgp as-path access-list SECOND permit 2$ clear bgp * will induce some crashes thus we rework the links between aslists and aspath_exclude Signed-off-by: Francois Dumontet --- bgpd/bgp_aspath.c | 47 ++++++++++++++++++++++++++++++++++++ bgpd/bgp_aspath.h | 7 ++++++ bgpd/bgp_filter.c | 41 +++++++++++++++++++------------ bgpd/bgp_filter.h | 13 +++++----- bgpd/bgp_routemap.c | 59 ++++++++++++++++++--------------------------- 5 files changed, 108 insertions(+), 59 deletions(-) diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c index 9dcd0ad1d6..4c1615a5c6 100644 --- a/bgpd/bgp_aspath.c +++ b/bgpd/bgp_aspath.c @@ -77,6 +77,9 @@ static struct hash *ashash; /* Stream for SNMP. See aspath_snmp_pathseg */ static struct stream *snmp_stream; +/* as-path orphan exclude list */ +static struct as_list_list_head as_exclude_list_orphan; + /* Callers are required to initialize the memory */ static as_t *assegment_data_new(int num) { @@ -1558,6 +1561,38 @@ struct aspath *aspath_prepend(struct aspath *as1, struct aspath *as2) /* Not reached */ } +/* insert aspath exclude in head of orphan exclude list*/ +void as_exclude_set_orphan(struct aspath_exclude *ase) +{ + ase->exclude_aspath_acl = NULL; + as_list_list_add_head(&as_exclude_list_orphan, ase); +} + +void as_exclude_remove_orphan(struct aspath_exclude *ase) +{ + if (as_list_list_count(&as_exclude_list_orphan)) + as_list_list_del(&as_exclude_list_orphan, ase); +} + +/* currently provide only one exclude, not a list */ +struct aspath_exclude *as_exclude_lookup_orphan(const char *acl_name) +{ + struct aspath_exclude *ase = NULL; + char *name = NULL; + + frr_each (as_list_list, &as_exclude_list_orphan, ase) { + if (ase->exclude_aspath_acl_name) { + name = ase->exclude_aspath_acl_name; + if (!strcmp(name, acl_name)) + break; + } + } + if (ase) + as_exclude_remove_orphan(ase); + + return ase; +} + /* Iterate over AS_PATH segments and wipe all occurrences of the * listed AS numbers. Hence some segments may lose some or even * all data on the way, the operation is implemented as a smarter @@ -2236,14 +2271,26 @@ void aspath_init(void) { ashash = hash_create_size(32768, aspath_key_make, aspath_cmp, "BGP AS Path"); + + as_list_list_init(&as_exclude_list_orphan); } void aspath_finish(void) { + struct aspath_exclude *ase; + hash_clean_and_free(&ashash, (void (*)(void *))aspath_free); if (snmp_stream) stream_free(snmp_stream); + + while ((ase = as_list_list_pop(&as_exclude_list_orphan))) { + aspath_free(ase->aspath); + if (ase->exclude_aspath_acl_name) + XFREE(MTYPE_TMP, ase->exclude_aspath_acl_name); + XFREE(MTYPE_ROUTE_MAP_COMPILED, ase); + } + as_list_list_fini(&as_exclude_list_orphan); } /* return and as path value */ diff --git a/bgpd/bgp_aspath.h b/bgpd/bgp_aspath.h index 2a831c3a55..f7e57fd66d 100644 --- a/bgpd/bgp_aspath.h +++ b/bgpd/bgp_aspath.h @@ -9,6 +9,7 @@ #include "lib/json.h" #include "bgpd/bgp_route.h" #include "bgpd/bgp_filter.h" +#include /* AS path segment type. */ #define AS_SET 1 @@ -67,11 +68,14 @@ struct aspath { /* `set as-path exclude ASn' */ struct aspath_exclude { + struct as_list_list_item exclude_list; struct aspath *aspath; bool exclude_all; char *exclude_aspath_acl_name; struct as_list *exclude_aspath_acl; }; +DECLARE_DLIST(as_list_list, struct aspath_exclude, exclude_list); + /* Prototypes. */ extern void aspath_init(void); @@ -83,6 +87,9 @@ extern struct aspath *aspath_parse(struct stream *s, size_t length, extern struct aspath *aspath_dup(struct aspath *aspath); extern struct aspath *aspath_aggregate(struct aspath *as1, struct aspath *as2); extern struct aspath *aspath_prepend(struct aspath *as1, struct aspath *as2); +extern void as_exclude_set_orphan(struct aspath_exclude *ase); +extern void as_exclude_remove_orphan(struct aspath_exclude *ase); +extern struct aspath_exclude *as_exclude_lookup_orphan(const char *acl_name); extern struct aspath *aspath_filter_exclude(struct aspath *source, struct aspath *exclude_list); extern struct aspath *aspath_filter_exclude_all(struct aspath *source); diff --git a/bgpd/bgp_filter.c b/bgpd/bgp_filter.c index a85117965a..002f054f5e 100644 --- a/bgpd/bgp_filter.c +++ b/bgpd/bgp_filter.c @@ -16,7 +16,7 @@ #include "bgpd/bgp_aspath.h" #include "bgpd/bgp_regex.h" -/* List of AS filter list. */ +/* List of AS list. */ struct as_list_list { struct as_list *head; struct as_list *tail; @@ -205,14 +205,6 @@ static struct as_list *as_list_new(void) static void as_list_free(struct 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); @@ -299,7 +291,6 @@ 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; @@ -318,12 +309,6 @@ 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); } @@ -431,6 +416,7 @@ DEFUN(as_path, bgp_as_path_cmd, enum as_filter_type type; struct as_filter *asfilter; struct as_list *aslist; + struct aspath_exclude *ase; regex_t *regex; char *regstr; int64_t seqnum = ASPATH_SEQ_NUMBER_AUTO; @@ -482,6 +468,22 @@ DEFUN(as_path, bgp_as_path_cmd, else as_list_filter_add(aslist, asfilter); + /* init the exclude rule list*/ + as_list_list_init(&aslist->exclude_rule); + + /* get aspath orphan exclude that are using this acl */ + ase = as_exclude_lookup_orphan(alname); + if (ase) { + as_list_list_add_head(&aslist->exclude_rule, ase); + /* set reverse pointer */ + ase->exclude_aspath_acl = aslist; + /* set list of aspath excludes using that acl */ + while ((ase = as_exclude_lookup_orphan(alname))) { + as_list_list_add_head(&aslist->exclude_rule, ase); + ase->exclude_aspath_acl = aslist; + } + } + return CMD_SUCCESS; } @@ -502,6 +504,7 @@ DEFUN(no_as_path, no_bgp_as_path_cmd, enum as_filter_type type; struct as_filter *asfilter; struct as_list *aslist; + struct aspath_exclude *ase; char *regstr; regex_t *regex; @@ -556,6 +559,12 @@ DEFUN(no_as_path, no_bgp_as_path_cmd, XFREE(MTYPE_TMP, regstr); + /* put aspath exclude list into orphan */ + if (as_list_list_count(&aslist->exclude_rule)) + while ((ase = as_list_list_pop(&aslist->exclude_rule))) + as_exclude_set_orphan(ase); + + as_list_list_fini(&aslist->exclude_rule); as_list_filter_delete(aslist, asfilter); return CMD_SUCCESS; diff --git a/bgpd/bgp_filter.h b/bgpd/bgp_filter.h index 2d9f07ce84..77a3f3c2f7 100644 --- a/bgpd/bgp_filter.h +++ b/bgpd/bgp_filter.h @@ -6,11 +6,12 @@ #ifndef _QUAGGA_BGP_FILTER_H #define _QUAGGA_BGP_FILTER_H +#include + #define ASPATH_SEQ_NUMBER_AUTO -1 enum as_filter_type { AS_FILTER_DENY, AS_FILTER_PERMIT }; - /* Element of AS path filter. */ struct as_filter { struct as_filter *next; @@ -25,11 +26,7 @@ struct as_filter { int64_t seq; }; -struct aspath_exclude_list { - struct aspath_exclude_list *next; - struct aspath_exclude *bp_as_excl; -}; - +PREDECL_DLIST(as_list_list); /* AS path filter list. */ struct as_list { char *name; @@ -39,7 +36,9 @@ struct as_list { struct as_filter *head; struct as_filter *tail; - struct aspath_exclude_list *exclude_list; + + /* Changes in AS path */ + struct as_list_list_head exclude_rule; }; diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index df5c2557bd..f938869b1c 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -2325,7 +2325,7 @@ static const struct route_map_rule_cmd route_set_aspath_prepend_cmd = { static void *route_aspath_exclude_compile(const char *arg) { struct aspath_exclude *ase; - struct aspath_exclude_list *ael; + struct as_list *aux_aslist; const char *str = arg; static const char asp_acl[] = "as-path-access-list"; @@ -2337,44 +2337,37 @@ static void *route_aspath_exclude_compile(const char *arg) while (*str == ' ') str++; ase->exclude_aspath_acl_name = XSTRDUP(MTYPE_TMP, str); - ase->exclude_aspath_acl = as_list_lookup(str); + aux_aslist = as_list_lookup(str); + if (!aux_aslist) + /* new orphan filter */ + as_exclude_set_orphan(ase); + else + as_list_list_add_head(&aux_aslist->exclude_rule, ase); + + ase->exclude_aspath_acl = aux_aslist; } 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; + struct as_list *acl; + + /* manage references to that rule*/ + if (ase->exclude_aspath_acl) { + acl = ase->exclude_aspath_acl; + as_list_list_del(&acl->exclude_rule, ase); + } else { + /* no ref to acl, this aspath exclude is orphan */ + as_exclude_remove_orphan(ase); + } 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); } @@ -2409,16 +2402,10 @@ route_set_aspath_exclude(void *rule, const struct prefix *dummy, void *object) else if (ase->exclude_all) path->attr->aspath = aspath_filter_exclude_all(new_path); - else if (ase->exclude_aspath_acl_name) { - if (!ase->exclude_aspath_acl) - ase->exclude_aspath_acl = - as_list_lookup(ase->exclude_aspath_acl_name); - if (ase->exclude_aspath_acl) - path->attr->aspath = - aspath_filter_exclude_acl(new_path, - ase->exclude_aspath_acl); - } - + else if (ase->exclude_aspath_acl) + path->attr->aspath = + aspath_filter_exclude_acl(new_path, + ase->exclude_aspath_acl); return RMAP_OKAY; } From 0df2e149970beff39915d0095614d56d5859f3ff Mon Sep 17 00:00:00 2001 From: Francois Dumontet Date: Wed, 24 Apr 2024 14:34:48 +0200 Subject: [PATCH 002/347] tests: improve tests for aspath exclude and bgp access list add some match in route map rules add some set unset bgp access path list add another prefix for better tests discrimination update expected results Signed-off-by: Francois Dumontet --- .../bgp_set_aspath_exclude/r1/bgpd.conf | 9 +++ .../bgp_set_aspath_exclude/r3/zebra.conf | 1 + .../test_bgp_set_aspath_exclude.py | 70 +++++++++++++++---- 3 files changed, 67 insertions(+), 13 deletions(-) diff --git a/tests/topotests/bgp_set_aspath_exclude/r1/bgpd.conf b/tests/topotests/bgp_set_aspath_exclude/r1/bgpd.conf index 9bef24f931..c70b4934a0 100644 --- a/tests/topotests/bgp_set_aspath_exclude/r1/bgpd.conf +++ b/tests/topotests/bgp_set_aspath_exclude/r1/bgpd.conf @@ -8,10 +8,19 @@ router bgp 65001 exit-address-family ! ip prefix-list p1 seq 5 permit 172.16.255.31/32 +ip prefix-list p2 seq 5 permit 172.16.255.32/32 +ip prefix-list p3 seq 5 permit 172.16.255.30/32 ! +bgp as-path access-list FIRST permit ^65 +bgp as-path access-list SECOND permit 2$ + +route-map r2 permit 6 + match ip address prefix-list p2 + set as-path exclude as-path-access-list SECOND route-map r2 permit 10 match ip address prefix-list p1 set as-path exclude 65003 route-map r2 permit 20 + match ip address prefix-list p3 set as-path exclude all ! diff --git a/tests/topotests/bgp_set_aspath_exclude/r3/zebra.conf b/tests/topotests/bgp_set_aspath_exclude/r3/zebra.conf index 3fa6c64484..56893158a4 100644 --- a/tests/topotests/bgp_set_aspath_exclude/r3/zebra.conf +++ b/tests/topotests/bgp_set_aspath_exclude/r3/zebra.conf @@ -1,5 +1,6 @@ ! int lo + ip address 172.16.255.30/32 ip address 172.16.255.31/32 ip address 172.16.255.32/32 ! 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 d373a749fe..85e7b9676d 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 @@ -64,29 +64,33 @@ def teardown_module(mod): expected_1 = { "routes": { + "172.16.255.30/32": [{"path": ""}], "172.16.255.31/32": [{"path": "65002"}], - "172.16.255.32/32": [{"path": ""}], + "172.16.255.32/32": [{"path": "65003"}], } } expected_2 = { "routes": { - "172.16.255.31/32": [{"path": ""}], + "172.16.255.30/32": [{"path": ""}], + "172.16.255.31/32": [{"path": "65002"}], "172.16.255.32/32": [{"path": ""}], } } expected_3 = { "routes": { - "172.16.255.31/32": [{"path": "65003"}], - "172.16.255.32/32": [{"path": "65003"}], + "172.16.255.30/32": [{"path": ""}], + "172.16.255.31/32": [{"path": "65002"}], + "172.16.255.32/32": [{"path": "65002 65003"}], } } expected_4 = { "routes": { - "172.16.255.31/32": [{"path": "65002 65003"}], - "172.16.255.32/32": [{"path": "65002 65003"}], + "172.16.255.30/32": [{"path": ""}], + "172.16.255.31/32": [{"path": "65002"}], + "172.16.255.32/32": [{"path": "65002"}], } } @@ -117,34 +121,42 @@ def test_bgp_set_aspath_exclude_access_list(): rname = "r1" r1 = tgen.gears[rname] + # tgen.mininet_cli() r1.vtysh_cmd( """ conf bgp as-path access-list FIRST permit ^65 route-map r2 permit 6 + no set as-path exclude as-path-access-list SECOND set as-path exclude as-path-access-list FIRST """ ) + # tgen.mininet_cli() + r1.vtysh_cmd( + """ +clear bgp * + """ + ) 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" + assert result is None, "Failed change of exclude rule in route map" r1.vtysh_cmd( """ conf - bgp as-path access-list SECOND permit 2 route-map r2 permit 6 + no set as-path exclude as-path-access-list FIRST set as-path exclude as-path-access-list SECOND """ ) # tgen.mininet_cli() - test_func = functools.partial(bgp_converge, tgen.gears["r1"], expected_3) + 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 regex 2 route-map" + assert result is None, "Failed reverting exclude rule in route map" def test_no_bgp_set_aspath_exclude_access_list(): @@ -159,15 +171,28 @@ def test_no_bgp_set_aspath_exclude_access_list(): r1.vtysh_cmd( """ conf - no bgp as-path access-list SECOND permit 2 + no bgp as-path access-list SECOND permit 2$ + """ + ) + + r1.vtysh_cmd( + """ +clear bgp * """ ) 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" + assert result is None, "Failed to removing current accesslist" + # tgen.mininet_cli() + r1.vtysh_cmd( + """ +conf + bgp as-path access-list SECOND permit 3$ + """ + ) r1.vtysh_cmd( """ clear bgp * @@ -177,7 +202,26 @@ def test_no_bgp_set_aspath_exclude_access_list(): 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" + assert result is None, "Failed to renegotiate with peers 2" + + r1.vtysh_cmd( + """ +conf + route-map r2 permit 6 + no set as-path exclude as-path-access-list SECOND + """ + ) + + r1.vtysh_cmd( + """ +clear bgp * + """ + ) + + 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 to renegotiate with peers 2" if __name__ == "__main__": From 5009f7539ad6bf496158499917dcf3f7ab760753 Mon Sep 17 00:00:00 2001 From: zhou-run <166502045+zhou-run@users.noreply.github.com> Date: Tue, 9 Apr 2024 21:04:39 +0800 Subject: [PATCH 003/347] isisd: Fix memory leaks when the transition of neighbor state from non-UP to DOWN When receiving a hello packet, if the neighbor state transitions directly from a non-ISIS_ADJ_UP state (such as ISIS_ADJ_INITIALIZING) to ISIS_ADJ_DOWN state, the neighbor entry cannot be deleted. If the neighbor is removed or the neighbor's System ID changes, it may result in memory leakage in the neighbor entry. Test Scenario: LAN link between Router A and Router B is established. Router A does not configure neighbor authentication, while Router B is configured with neighbor authentication. When the neighbor entry on Router B ages out, the neighbor state on Router A transitions to INIT. If Router B is then removed, the neighbor state on Router A transitions to DOWN and persists. Signed-off-by: zhou-run <166502045+zhou-run@users.noreply.github.com> fix frrbot styling issues found. fix frrbot styling issues found. Signed-off-by: zhou-run <166502045+zhou-run@users.noreply.github.com> --- isisd/isis_adjacency.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/isisd/isis_adjacency.c b/isisd/isis_adjacency.c index 7acd3a2b4e..d23a865ea4 100644 --- a/isisd/isis_adjacency.c +++ b/isisd/isis_adjacency.c @@ -358,12 +358,15 @@ void isis_adj_state_change(struct isis_adjacency **padj, * purposes */ adj->last_flap = time(NULL); adj->flaps++; - } else if (old_state == ISIS_ADJ_UP) { - circuit->adj_state_changes++; + } else { + if (old_state == ISIS_ADJ_UP) { + circuit->adj_state_changes++; - circuit->upadjcount[level - 1]--; - if (circuit->upadjcount[level - 1] == 0) - isis_tx_queue_clean(circuit->tx_queue); + circuit->upadjcount[level - 1]--; + if (circuit->upadjcount[level - 1] == 0) + isis_tx_queue_clean( + circuit->tx_queue); + } if (new_state == ISIS_ADJ_DOWN) { listnode_delete( @@ -409,10 +412,13 @@ void isis_adj_state_change(struct isis_adjacency **padj, master, send_l2_csnp, circuit, 0, &circuit->t_send_csnp[1]); } - } else if (old_state == ISIS_ADJ_UP) { - circuit->upadjcount[level - 1]--; - if (circuit->upadjcount[level - 1] == 0) - isis_tx_queue_clean(circuit->tx_queue); + } else { + if (old_state == ISIS_ADJ_UP) { + circuit->upadjcount[level - 1]--; + if (circuit->upadjcount[level - 1] == 0) + isis_tx_queue_clean( + circuit->tx_queue); + } if (new_state == ISIS_ADJ_DOWN) { if (adj->circuit->u.p2p.neighbor == adj) From 1f5446d2fc83e2eba9e693bc5f439723d5f48865 Mon Sep 17 00:00:00 2001 From: zhou-run <166502045+zhou-run@users.noreply.github.com> Date: Mon, 27 May 2024 11:08:53 +0800 Subject: [PATCH 004/347] isisd: When operating multiple areas, the system ID behaves abnormally. When clearing the net in one of the areas, the system ID is unconditionally cleared, even if the net does not include the current system ID. Signed-off-by: zhou-run <166502045+zhou-run@users.noreply.github.com> isisd: When operating multiple areas, the system ID behaves abnormally. When deleting one of the areas, even if the net under the area includes the current system ID, the system ID still remains. Signed-off-by: zhou-run <166502045+zhou-run@users.noreply.github.com> isisd: fix frrbot styling issues found fix frrbot styling issues found Signed-off-by: zhou-run <166502045+zhou-run@users.noreply.github.com> isisd: fix frrbot styling issues found fix frrbot styling issues found Signed-off-by: zhou-run <166502045+zhou-run@users.noreply.github.com> isisd: Resolve compilation issues. The higher version updates 'struct area_addr' to 'struct iso_address'. Signed-off-by: zhou-run <166502045+zhou-run@users.noreply.github.com> isisd: fix frrbot styling issues found fix frrbot styling issues found Signed-off-by: zhou-run <166502045+zhou-run@users.noreply.github.com> --- isisd/isis_nb_config.c | 7 +++++-- isisd/isisd.c | 10 ++++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/isisd/isis_nb_config.c b/isisd/isis_nb_config.c index 763b8b73d2..0a343ddc29 100644 --- a/isisd/isis_nb_config.c +++ b/isisd/isis_nb_config.c @@ -252,11 +252,12 @@ int isis_instance_area_address_destroy(struct nb_cb_destroy_args *args) 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) { + if (!memcmp(addrp->area_addr + addrp->addr_len, area->isis->sysid, + ISIS_SYS_ID_LEN) && + 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]) @@ -268,6 +269,8 @@ int isis_instance_area_address_destroy(struct nb_cb_destroy_args *args) zlog_debug("Router has no SystemID"); } + XFREE(MTYPE_ISIS_AREA_ADDR, addrp); + return NB_OK; } diff --git a/isisd/isisd.c b/isisd/isisd.c index 382a6aa3be..2ed4939839 100644 --- a/isisd/isisd.c +++ b/isisd/isisd.c @@ -496,6 +496,7 @@ void isis_area_destroy(struct isis_area *area) { struct listnode *node, *nnode; struct isis_circuit *circuit; + struct iso_address *addr; QOBJ_UNREG(area); @@ -545,6 +546,15 @@ void isis_area_destroy(struct isis_area *area) if (!CHECK_FLAG(im->options, F_ISIS_UNIT_TEST)) isis_redist_area_finish(area); + if (listcount(area->area_addrs) > 0) { + addr = listgetdata(listhead(area->area_addrs)); + if (!memcmp(addr->area_addr + addr->addr_len, area->isis->sysid, + ISIS_SYS_ID_LEN)) { + memset(area->isis->sysid, 0, ISIS_SYS_ID_LEN); + area->isis->sysid_set = 0; + } + } + list_delete(&area->area_addrs); for (int i = SPF_PREFIX_PRIO_CRITICAL; i <= SPF_PREFIX_PRIO_MEDIUM; From 171d2583d0373b456335477dea6688d2e9e95db7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Kwa=C5=9Bny?= Date: Mon, 27 May 2024 11:03:30 +0200 Subject: [PATCH 005/347] bgpd: fixed failing remove of vrf if there is a stale l3vni Problem statement: ================== When a vrf is deleted from the kernel, before its removed from the FRR config, zebra gets to delete the the vrf and assiciated state. It does so by sending a request to delete the l3 vni associated with the vrf followed by a request to delete the vrf itself. 2023/10/06 06:22:18 ZEBRA: [JAESH-BABB8] Send L3_VNI_DEL 1001 VRF testVRF1001 to bgp 2023/10/06 06:22:18 ZEBRA: [XC3P3-1DG4D] MESSAGE: ZEBRA_VRF_DELETE testVRF1001 The zebra client communication is asynchronous and about 1/5 cases the bgp client process them in a different order. 2023/10/06 06:22:18 BGP: [VP18N-HB5R6] VRF testVRF1001(766) is to be deleted. 2023/10/06 06:22:18 BGP: [RH4KQ-X3CYT] VRF testVRF1001(766) is to be disabled. 2023/10/06 06:22:18 BGP: [X8ZE0-9TS5H] VRF disable testVRF1001 id 766 2023/10/06 06:22:18 BGP: [X67AQ-923PR] Deregistering VRF 766 2023/10/06 06:22:18 BGP: [K52W0-YZ4T8] VRF Deletion: testVRF1001(4294967295) .. and a bit later : 2023/10/06 06:22:18 BGP: [MRXGD-9MHNX] DJERNAES: process L3VNI 1001 DEL 2023/10/06 06:22:18 BGP: [NCEPE-BKB1G][EC 33554467] Cannot process L3VNI 1001 Del - Could not find BGP instance When the bgp vrf config is removed later it fails on the sanity check if l3vni is removed. if (bgp->l3vni) { vty_out(vty, "%% Please unconfigure l3vni %u\n", bgp->l3vni); return CMD_WARNING_CONFIG_FAILED; } Solution: ========= The solution is to make bgp cleanup the l3vni a bgp instance is going down. The fix: ======== The fix is to add a function in bgp_evpn.c to be responsible for for deleting the local vni, if it should be needed, and call the function from bgp_instance_down(). Testing: ======== Created a test, which can run in container lab that remove the vrf on the host before removing the vrf and the bgp config form frr. Running this test in a loop trigger the problem 18 times of 100 runs. After the fix it did not fail. To verify the fix a log message (which is not in the code any longer) were used when we had a stale l3vni and needed to call bgp_evpn_local_l3vni_del() to do the cleanup. This were hit 20 times in 100 test runs. Signed-off-by: Kacper Kwasny bgpd: braces {} are not necessary for single line block Signed-off-by: Kacper Kwasny --- bgpd/bgp_evpn.c | 11 +++++++++++ bgpd/bgp_evpn.h | 1 + bgpd/bgpd.c | 3 +++ 3 files changed, 15 insertions(+) diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index ce9666d611..495b60853f 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -6971,6 +6971,17 @@ int bgp_evpn_local_l3vni_del(vni_t l3vni, vrf_id_t vrf_id) return 0; } +/* + * When bgp instance goes down also clean up what might have been left over + * from evpn. + */ +void bgp_evpn_instance_down(struct bgp *bgp) +{ + /* If we have a stale local vni, delete it */ + if (bgp->l3vni) + bgp_evpn_local_l3vni_del(bgp->l3vni, bgp->vrf_id); +} + /* * Handle del of a local VNI. */ diff --git a/bgpd/bgp_evpn.h b/bgpd/bgp_evpn.h index 11a6f45dd0..ff2cb6ea91 100644 --- a/bgpd/bgp_evpn.h +++ b/bgpd/bgp_evpn.h @@ -153,6 +153,7 @@ extern int bgp_evpn_local_l3vni_add(vni_t vni, vrf_id_t vrf_id, struct in_addr originator_ip, int filter, ifindex_t svi_ifindex, bool is_anycast_mac); extern int bgp_evpn_local_l3vni_del(vni_t vni, vrf_id_t vrf_id); +extern void bgp_evpn_instance_down(struct bgp *bgp); extern int bgp_evpn_local_vni_del(struct bgp *bgp, vni_t vni); extern int bgp_evpn_local_vni_add(struct bgp *bgp, vni_t vni, struct in_addr originator_ip, diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 09e64cf9ec..a804f095fa 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -3872,6 +3872,9 @@ void bgp_instance_down(struct bgp *bgp) struct listnode *node; struct listnode *next; + /* Cleanup evpn instance state */ + bgp_evpn_instance_down(bgp); + /* Stop timers. */ if (bgp->t_rmap_def_originate_eval) EVENT_OFF(bgp->t_rmap_def_originate_eval); From e14781eb1d9be38ad89c58dcb20afc64062eab2a Mon Sep 17 00:00:00 2001 From: Christian Hopps Date: Tue, 4 Jun 2024 05:43:49 -0400 Subject: [PATCH 006/347] lib: darr: add free with element cleanup functions - `darr_free_free` to `darr_free` each element prior to `darr_free` the array. - `darr_free_func` to call `func` on each element prior to `darr_free` the array. Signed-off-by: Christian Hopps --- lib/darr.h | 37 +++++++++++++++++++++++++++++++++++++ tests/lib/test_darr.c | 27 +++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) diff --git a/lib/darr.h b/lib/darr.h index 404869d9a2..2b9a0a0c02 100644 --- a/lib/darr.h +++ b/lib/darr.h @@ -24,6 +24,8 @@ * - darr_ensure_i * - darr_ensure_i_mt * - darr_free + * - darr_free_free + * - darr_free_func * - darr_insert * - darr_insert_mt * - darr_insertz @@ -217,6 +219,41 @@ void *__darr_resize(void *a, uint count, size_t esize, struct memtype *mt); } \ } while (0) +/** + * Free memory allocated for the dynamic array `A`, calling `darr_free` for + * each element of the array first. + * + * Args: + * A: The dynamic array, can be NULL. + */ +#define darr_free_free(A) \ + do { \ + for (uint __i = 0; __i < darr_len(A); __i++) \ + if ((A)[__i]) { \ + struct darr_metadata *__meta = \ + _darr_meta((A)[__i]); \ + XFREE(__meta->mtype, __meta); \ + } \ + darr_free(A); \ + } while (0) + +/** + * Free memory allocated for the dynamic array `A`, calling `F` routine + * for each element of the array first. + * + * Args: + * A: The dynamic array, can be NULL. + * F: The function to call for each element. + */ + +#define darr_free_func(A, F) \ + do { \ + for (uint __i = 0; __i < darr_len(A); __i++) { \ + F((A)[__i]); \ + } \ + darr_free(A); \ + } while (0) + /** * Make sure that there is room in the dynamic array `A` to add `C` elements. * diff --git a/tests/lib/test_darr.c b/tests/lib/test_darr.c index 74aedac4b7..87f9e3e564 100644 --- a/tests/lib/test_darr.c +++ b/tests/lib/test_darr.c @@ -20,6 +20,8 @@ * [x] - darr_foreach_i * [x] - darr_foreach_p * [x] - darr_free + * [x] - darr_free_free + * [x] - darr_free_func * [x] - darr_insert * [ ] - darr_insertz * [x] - darr_insert_n @@ -318,6 +320,8 @@ static void test_string(void) uint addlen = strlen(add); char *da1 = NULL; char *da2 = NULL; + const char **strings = NULL; + uint sum = 0; assert(darr_strlen(da1) == 0); @@ -412,6 +416,29 @@ static void test_string(void) da1 = darr_in_strcatf(da1, "0123456789: %08x", 0xDEADBEEF); assert(!strcmp("0123456789: deadbeef", da1)); darr_free(da1); + + sum = 0; + *darr_append(strings) = "1"; + *darr_append(strings) = "2"; + *darr_append(strings) = "3"; +#define adder(x) (sum += atoi(x)) + darr_free_func(strings, adder); + assert(sum == 6); + assert(strings == NULL); + + sum = 0; + darr_free_func(strings, adder); + assert(sum == 0); + assert(strings == NULL); + + *darr_append(strings) = NULL; + *darr_append(strings) = darr_strdup("2"); + *darr_append(strings) = darr_strdup("3"); + darr_free_free(strings); + assert(strings == NULL); + + darr_free_free(strings); + assert(strings == NULL); } int main(int argc, char **argv) From 22eccbfab916b2c6b64037e872a5c5a870d1a4d6 Mon Sep 17 00:00:00 2001 From: Christian Hopps Date: Tue, 4 Jun 2024 06:01:59 -0400 Subject: [PATCH 007/347] lib: fix incorrect use of error checking macro Signed-off-by: Christian Hopps --- lib/yang.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/yang.c b/lib/yang.c index 702fcf436d..44459df4a5 100644 --- a/lib/yang.c +++ b/lib/yang.c @@ -897,7 +897,7 @@ char *yang_convert_lyd_format(const char *data, size_t data_len, assert(out_format != LYD_LYB); - if (in_format != LYD_LYB && !MGMT_MSG_VALIDATE_NUL_TERM(data, data_len)) { + if (in_format != LYD_LYB && (!data_len || data[data_len - 1] != 0)) { zlog_err("Corrupt input data, no NUL terminating byte"); return NULL; } From 33b73f8e3aa13679ba3aad82be2a88d7cb69f426 Mon Sep 17 00:00:00 2001 From: Christian Hopps Date: Tue, 4 Jun 2024 10:28:48 -0400 Subject: [PATCH 008/347] lib: native msg add array of strings support Signed-off-by: Christian Hopps --- lib/mgmt_msg_native.c | 18 ++++++++++++++++++ lib/mgmt_msg_native.h | 40 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/lib/mgmt_msg_native.c b/lib/mgmt_msg_native.c index 39ce9abae6..d0a0b72189 100644 --- a/lib/mgmt_msg_native.c +++ b/lib/mgmt_msg_native.c @@ -6,6 +6,7 @@ * */ #include +#include "darr.h" #include "mgmt_msg_native.h" DEFINE_MGROUP(MSG_NATIVE, "Native message allocations"); @@ -50,3 +51,20 @@ int vmgmt_msg_native_send_error(struct msg_conn *conn, uint64_t sess_or_txn_id, mgmt_msg_native_free_msg(msg); return ret; } + +const char **_mgmt_msg_native_strings_decode(const void *_sdata, int sdlen) +{ + const char *sdata = _sdata; + const char **strings = NULL; + int len; + + if (sdata[sdlen - 1] != 0) + return NULL; + + for (; sdlen; sdata += len, sdlen -= len) { + *darr_append(strings) = darr_strdup(sdata); + len = 1 + darr_strlen(strings[darr_lasti(strings)]); + } + + return strings; +} diff --git a/lib/mgmt_msg_native.h b/lib/mgmt_msg_native.h index 21f702cc61..cb1101d24f 100644 --- a/lib/mgmt_msg_native.h +++ b/lib/mgmt_msg_native.h @@ -524,6 +524,25 @@ extern int vmgmt_msg_native_send_error(struct msg_conn *conn, p; \ }) +/** + * mgmt_msg_native_add_str() - Append [another] string to the msg. + * @msg: (IN/OUT) Pointer to the native message, variable may be updated. + * @s: string to append. + * + * Append string @s to the native message @msg. @msg is assumed to have a + * sequence of NUL-terminated strings at the end of it. This function appends + * the string @s and it's NUL terminating octet to the message. + * + * NOTE: Be aware @msg pointer may change as a result of reallocating the + * message to fit the new data. Any other pointers into the old message should + * be discarded. + */ +#define mgmt_msg_native_add_str(msg, s) \ + do { \ + int __len = strlen(s) + 1; \ + mgmt_msg_native_append(msg, s, __len); \ + } while (0) + /** * mgmt_msg_native_send_msg(msg, short_circuit_ok) - Send a native msg. * @conn: the mgmt_msg connection. @@ -689,6 +708,27 @@ extern int vmgmt_msg_native_send_error(struct msg_conn *conn, #define mgmt_msg_native_data_len_decode(msg, msglen) \ ((msglen) - sizeof(*msg) - msg->vsplit) +/** + * mgmt_msg_native_strings_decode() - Get dynamic array of str ptrs from the msg. + * @msg: Pointer to the native message. + * @msglen: Length of the message. + * @sdata: pointer to the variable length string data at end of @msg. + * + * Given a pointer to a sequence of NUL-terminated strings allocate + * and return a dynamic array of dynamic array strings. This function + * can be used to decode a message that was built using + * mgmt_msg_native_add_str(). + * + * Return: a dynamic array (darr) of string pointers, or NULL if the message + * is corrupt. + */ +#define mgmt_msg_native_strings_decode(msg, msg_len, sdata) \ + _mgmt_msg_native_strings_decode(sdata, \ + (msg_len) - ((sdata) - (char *)(msg))) + +extern const char **_mgmt_msg_native_strings_decode(const void *sdata, + int sdlen); + #ifdef __cplusplus } #endif From 657f1650e697b2020f5f2fb4f5c271a9c6e30c53 Mon Sep 17 00:00:00 2001 From: Christian Hopps Date: Tue, 4 Jun 2024 10:29:46 -0400 Subject: [PATCH 009/347] mgmtd: add front-end notification selector support Signed-off-by: Christian Hopps --- lib/mgmt_msg_native.h | 22 ++++++++++ mgmtd/mgmt_fe_adapter.c | 97 ++++++++++++++++++++++++++++++++++++++--- 2 files changed, 112 insertions(+), 7 deletions(-) diff --git a/lib/mgmt_msg_native.h b/lib/mgmt_msg_native.h index cb1101d24f..e61346e6e5 100644 --- a/lib/mgmt_msg_native.h +++ b/lib/mgmt_msg_native.h @@ -176,6 +176,7 @@ DECLARE_MTYPE(MSG_NATIVE_RPC_REPLY); #define MGMT_MSG_CODE_EDIT_REPLY 6 /* Public API */ #define MGMT_MSG_CODE_RPC 7 /* Public API */ #define MGMT_MSG_CODE_RPC_REPLY 8 /* Public API */ +#define MGMT_MSG_CODE_NOTIFY_SELECT 9 /* Public API */ /* * Datastores @@ -426,6 +427,27 @@ _Static_assert(sizeof(struct mgmt_msg_rpc_reply) == offsetof(struct mgmt_msg_rpc_reply, data), "Size mismatch"); +/** + * struct mgmt_msg_notify_select - Add notification selectors for FE client. + * + * Add xpath prefix notification selectors to limit the notifications sent + * to the front-end client. + * + * @selectors: the xpath prefixes to selectors notifications through. + * @repalce: if true replace existing selectors with `selectors`. + */ +struct mgmt_msg_notify_select { + struct mgmt_msg_header; + uint8_t replace; + uint8_t resv2[7]; + + alignas(8) char selectors[]; +}; + +_Static_assert(sizeof(struct mgmt_msg_notify_select) == + offsetof(struct mgmt_msg_notify_select, selectors), + "Size mismatch"); + /* * Validate that the message ends in a NUL terminating byte */ diff --git a/mgmtd/mgmt_fe_adapter.c b/mgmtd/mgmt_fe_adapter.c index fc1bde0b38..a076dc72f9 100644 --- a/mgmtd/mgmt_fe_adapter.c +++ b/mgmtd/mgmt_fe_adapter.c @@ -43,6 +43,7 @@ struct mgmt_fe_session_ctx { uint64_t txn_id; uint64_t cfg_txn_id; uint8_t ds_locked[MGMTD_DS_MAX_ID]; + const char **notify_xpaths; struct event *proc_cfg_txn_clnp; struct event *proc_show_txn_clnp; @@ -1401,10 +1402,45 @@ static void fe_adapter_handle_edit(struct mgmt_fe_session_ctx *session, } } +/** + * fe_adapter_handle_notify_select() - Handle an Notify Select message. + * @session: the client session. + * @__msg: the message data. + * @msg_len: the length of the message data. + */ +static void fe_adapter_handle_notify_select(struct mgmt_fe_session_ctx *session, + void *__msg, size_t msg_len) +{ + struct mgmt_msg_notify_select *msg = __msg; + uint64_t req_id = msg->req_id; + const char **selectors = NULL; + const char **new; + + /* An empty message clears the selectors */ + if (msg_len >= sizeof(*msg)) { + selectors = mgmt_msg_native_strings_decode(msg, msg_len, + msg->selectors); + if (!selectors) { + fe_adapter_send_error(session, req_id, false, -EINVAL, + "Invalid message"); + return; + } + } + if (msg->replace) { + darr_free_free(session->notify_xpaths); + session->notify_xpaths = selectors; + } else { + new = darr_append_nz(session->notify_xpaths, + darr_len(selectors)); + memcpy(new, selectors, darr_len(selectors) * sizeof(*selectors)); + darr_free(selectors); + } +} + /** * fe_adapter_handle_rpc() - Handle an RPC message from an FE client. * @session: the client session. - * @msg_raw: the message data. + * @__msg: the message data. * @msg_len: the length of the message data. */ static void fe_adapter_handle_rpc(struct mgmt_fe_session_ctx *session, @@ -1503,13 +1539,26 @@ static void fe_adapter_handle_native_msg(struct mgmt_fe_client_adapter *adapter, assert(session->adapter == adapter); switch (msg->code) { - case MGMT_MSG_CODE_GET_DATA: - fe_adapter_handle_get_data(session, msg, msg_len); - break; case MGMT_MSG_CODE_EDIT: + __dbg("adapter %s: session-id %" PRIu64 " received EDIT message", + adapter->name, msg->refer_id); fe_adapter_handle_edit(session, msg, msg_len); break; + case MGMT_MSG_CODE_NOTIFY_SELECT: + __dbg("adapter %s: session-id %" PRIu64 + " received NOTIFY_SELECT message", + adapter->name, msg->refer_id); + fe_adapter_handle_notify_select(session, msg, msg_len); + break; + case MGMT_MSG_CODE_GET_DATA: + __dbg("adapter %s: session-id %" PRIu64 + " received GET_DATA message", + adapter->name, msg->refer_id); + fe_adapter_handle_get_data(session, msg, msg_len); + break; case MGMT_MSG_CODE_RPC: + __dbg("adapter %s: session-id %" PRIu64 " received RPC message", + adapter->name, msg->refer_id); fe_adapter_handle_rpc(session, msg, msg_len); break; default: @@ -1554,14 +1603,48 @@ void mgmt_fe_adapter_send_notify(struct mgmt_msg_notify_data *msg, size_t msglen { struct mgmt_fe_client_adapter *adapter; struct mgmt_fe_session_ctx *session; + struct nb_node *nb_node; + const char **xpath_prefix; + const char *notif; + bool sendit; + uint len; assert(msg->refer_id == 0); + notif = mgmt_msg_native_xpath_decode(msg, msglen); + if (!notif) { + __log_err("Corrupt notify msg"); + return; + } + + /* + * We need the nb_node to obtain a path which does not include any + * specific list entry selectors + */ + nb_node = nb_node_find(notif); + if (!nb_node) { + __log_err("No schema found for notification: %s", notif); + return; + } + FOREACH_ADAPTER_IN_LIST (adapter) { FOREACH_SESSION_IN_LIST (adapter, session) { - msg->refer_id = session->session_id; - (void)fe_adapter_send_native_msg(adapter, msg, msglen, - false); + /* If no selectors then always send */ + sendit = !session->notify_xpaths; + darr_foreach_p (session->notify_xpaths, xpath_prefix) { + len = strlen(*xpath_prefix); + if (!strncmp(*xpath_prefix, notif, len) || + !strncmp(*xpath_prefix, nb_node->xpath, + len)) { + sendit = true; + break; + } + } + if (sendit) { + msg->refer_id = session->session_id; + (void)fe_adapter_send_native_msg(adapter, msg, + msglen, false); + } } } msg->refer_id = 0; From 8772e444a7dca8c80aac9e9918f0ed977e0d7322 Mon Sep 17 00:00:00 2001 From: Christian Hopps Date: Tue, 4 Jun 2024 10:57:10 -0400 Subject: [PATCH 010/347] tests: add notify select support in fe client test utility Signed-off-by: Christian Hopps --- tests/topotests/lib/fe_client.py | 49 +++++++++++++++++++------------- 1 file changed, 29 insertions(+), 20 deletions(-) diff --git a/tests/topotests/lib/fe_client.py b/tests/topotests/lib/fe_client.py index a47544633b..019b3239ca 100755 --- a/tests/topotests/lib/fe_client.py +++ b/tests/topotests/lib/fe_client.py @@ -18,6 +18,8 @@ import time from pathlib import Path +from munet.base import Timeout + CWD = os.path.dirname(os.path.realpath(__file__)) # This is painful but works if you have installed protobuf would be better if we @@ -80,6 +82,8 @@ MSG_NOTIFY_FMT = "=B7x" NOTIFY_FIELD_RESULT_TYPE = 0 +MSG_NOTIFY_SELECT_FMT = "=B7x" + # # Native message codes # @@ -88,6 +92,7 @@ MSG_CODE_TREE_DATA = 2 MSG_CODE_GET_DATA = 3 MSG_CODE_NOTIFY = 4 +MSG_CODE_NOTIFY_SELECT = 9 msg_native_formats = { MSG_CODE_ERROR: MSG_ERROR_FMT, @@ -95,6 +100,7 @@ MSG_CODE_TREE_DATA: MSG_TREE_DATA_FMT, MSG_CODE_GET_DATA: MSG_GET_DATA_FMT, MSG_CODE_NOTIFY: MSG_NOTIFY_FMT, + MSG_CODE_NOTIFY_SELECT: MSG_NOTIFY_SELECT_FMT, } @@ -308,17 +314,22 @@ def get_data(self, query, data=True, config=False): logging.debug("Received GET: %s: %s", mfixed, mdata) return result - # def subscribe(self, notif_xpath): - # # Create the message - # mdata, req_id = self.get_native_msg_header(MSG_CODE_SUBSCRIBE) - # mdata += struct.pack(MSG_SUBSCRIBE_FMT, MSG_FORMAT_JSON) - # mdata += notif_xpath.encode("utf-8") + b"\x00" + def add_notify_select(self, replace, notif_xpaths): + # Create the message + mdata, req_id = self.get_native_msg_header(MSG_CODE_NOTIFY_SELECT) + mdata += struct.pack(MSG_NOTIFY_SELECT_FMT, replace) + + for xpath in notif_xpaths: + mdata += xpath.encode("utf-8") + b"\x00" - # self.send_native_msg(mdata) - # logging.debug("Sent SUBSCRIBE") + self.send_native_msg(mdata) + logging.debug("Sent NOTIFY_SELECT") def recv_notify(self, xpaths=None): - while True: + if xpaths: + self.add_notify_select(True, xpaths) + + for remaining in Timeout(60): logging.debug("Waiting for Notify Message") mhdr, mfixed, mdata = self.recv_native_msg() if mhdr[HDR_FIELD_CODE] == MSG_CODE_NOTIFY: @@ -328,19 +339,11 @@ def recv_notify(self, xpaths=None): vsplit = mhdr[HDR_FIELD_VSPLIT] assert mdata[vsplit - 1] == 0 - xpath = mdata[: vsplit - 1].decode("utf-8") - assert mdata[-1] == 0 - result = mdata[vsplit:-1].decode("utf-8") - - if not xpaths: - return result - js = json.loads(result) - key = [x for x in js.keys()][0] - for xpath in xpaths: - if key.startswith(xpath): - return result - logging.debug("'%s' didn't match xpath filters", key) + # xpath = mdata[: vsplit - 1].decode("utf-8") + return mdata[vsplit:-1].decode("utf-8") + else: + raise TimeoutError("Timeout waiting for notifications") def __parse_args(): @@ -381,6 +384,8 @@ def __server_connect(spath): logging.warn("retry server connection in .5s (%s)", os.strerror(ec)) time.sleep(0.5) logging.info("Connected to server on %s", spath) + # Set a timeout of 5 minutes for socket operations. + sock.settimeout(60 * 5) return sock @@ -412,8 +417,12 @@ def main(): __main() except KeyboardInterrupt: logging.info("Exiting") + except TimeoutError as error: + logging.error("Timeout: %s", error) + sys.exit(2) except Exception as error: logging.error("Unexpected error exiting: %s", error, exc_info=True) + sys.exit(1) if __name__ == "__main__": From 56ce19891b01c07461103de3dd427e85e3cc2252 Mon Sep 17 00:00:00 2001 From: Christian Hopps Date: Thu, 6 Jun 2024 10:06:04 -0400 Subject: [PATCH 011/347] tests: switch test to new fe_client notify selector syntax Signed-off-by: Christian Hopps --- tests/topotests/mgmt_notif/test_notif.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/topotests/mgmt_notif/test_notif.py b/tests/topotests/mgmt_notif/test_notif.py index c85e7ba795..de984b12e1 100644 --- a/tests/topotests/mgmt_notif/test_notif.py +++ b/tests/topotests/mgmt_notif/test_notif.py @@ -51,7 +51,7 @@ def test_frontend_notification(tgen): check_kernel_32(r1, "11.11.11.11", 1, "") - fe_client_path = CWD + "/../lib/fe_client.py" + fe_client_path = CWD + "/../lib/fe_client.py --verbose" rc, _, _ = r1.cmd_status(fe_client_path + " --help") if rc: @@ -61,7 +61,7 @@ def test_frontend_notification(tgen): # So we filter to avoid that, all the rest are frr-ripd:authentication-failure # making our test deterministic output = r1.cmd_raises( - fe_client_path + " --listen frr-ripd:authentication-failure" + fe_client_path + " --listen /frr-ripd:authentication-failure" ) jsout = json.loads(output) From 51f070028692260ea19b5ef0f489c56de5683bbc Mon Sep 17 00:00:00 2001 From: Volodymyr Huti Date: Mon, 13 Nov 2023 22:47:31 +0200 Subject: [PATCH 012/347] nhrp: add `cisco-authentication` password support Implemented: - handling 8 char long password, aka Cisco style. - minimal error inidication routine - test case, password change affects conection Signed-off-by: Volodymyr Huti --- doc/user/nhrpd.rst | 6 ++ nhrpd/nhrp_nhs.c | 4 +- nhrpd/nhrp_packet.c | 27 ++++-- nhrpd/nhrp_peer.c | 98 ++++++++++++++++++--- nhrpd/nhrp_shortcut.c | 4 +- nhrpd/nhrp_vty.c | 63 +++++++++++++ nhrpd/nhrpd.h | 10 ++- nhrpd/subdir.am | 4 + tests/topotests/nhrp_topo/r1/nhrpd.conf | 1 + tests/topotests/nhrp_topo/r2/nhrpd.conf | 1 + tests/topotests/nhrp_topo/test_nhrp_topo.py | 55 ++++++++++-- 11 files changed, 242 insertions(+), 31 deletions(-) diff --git a/doc/user/nhrpd.rst b/doc/user/nhrpd.rst index 54527a0c9a..e0ba90fcc1 100644 --- a/doc/user/nhrpd.rst +++ b/doc/user/nhrpd.rst @@ -84,6 +84,12 @@ Configuring NHRP registration requests are sent. By default registrations are sent every one third of the holdtime. +.. clicmd:: ip nhrp authentication PASSWORD + + Enables Cisco style authentication on NHRP packets. This embeds the + plaintext password to the outgoing NHRP packets. + Maximum length of the is 8 characters. + .. clicmd:: ip nhrp map A.B.C.D|X:X::X:X A.B.C.D|local Map an IP address of a station to the station's NBMA address. diff --git a/nhrpd/nhrp_nhs.c b/nhrpd/nhrp_nhs.c index f779f93486..b8958ba225 100644 --- a/nhrpd/nhrp_nhs.c +++ b/nhrpd/nhrp_nhs.c @@ -216,7 +216,7 @@ static void nhrp_reg_send_req(struct event *t) cie->holding_time = htons(if_ad->holdtime); cie->mtu = htons(if_ad->mtu); - nhrp_ext_request(zb, hdr, ifp); + nhrp_ext_request(zb, hdr); /* Cisco NAT detection extension */ if (sockunion_family(&r->proto_addr) != AF_UNSPEC) { @@ -240,7 +240,7 @@ static void nhrp_reg_send_req(struct event *t) cie->mtu = htons(if_ad->mtu); nhrp_ext_complete(zb, ext); - nhrp_packet_complete(zb, hdr); + nhrp_packet_complete(zb, hdr, ifp); nhrp_peer_send(r->peer, zb); zbuf_free(zb); } diff --git a/nhrpd/nhrp_packet.c b/nhrpd/nhrp_packet.c index c6bd3bbbde..71f5c2f007 100644 --- a/nhrpd/nhrp_packet.c +++ b/nhrpd/nhrp_packet.c @@ -115,14 +115,32 @@ uint16_t nhrp_packet_calculate_checksum(const uint8_t *pdu, uint16_t len) return (~csum) & 0xffff; } -void nhrp_packet_complete(struct zbuf *zb, struct nhrp_packet_header *hdr) +void nhrp_packet_complete(struct zbuf *zb, struct nhrp_packet_header *hdr, + struct interface *ifp) { + nhrp_packet_complete_auth(zb, hdr, ifp, true); +} + +void nhrp_packet_complete_auth(struct zbuf *zb, struct nhrp_packet_header *hdr, + struct interface *ifp, bool auth) +{ + struct nhrp_interface *nifp = ifp->info; + struct zbuf *auth_token = nifp->auth_token; + struct nhrp_extension_header *dst; unsigned short size; + if (auth && auth_token) { + dst = nhrp_ext_push(zb, hdr, + NHRP_EXTENSION_AUTHENTICATION | + NHRP_EXTENSION_FLAG_COMPULSORY); + zbuf_copy_peek(zb, auth_token, zbuf_size(auth_token)); + nhrp_ext_complete(zb, dst); + } + if (hdr->extension_offset) nhrp_ext_push(zb, hdr, - NHRP_EXTENSION_END - | NHRP_EXTENSION_FLAG_COMPULSORY); + NHRP_EXTENSION_END | + NHRP_EXTENSION_FLAG_COMPULSORY); size = zb->tail - (uint8_t *)hdr; hdr->packet_size = htons(size); @@ -225,8 +243,7 @@ struct nhrp_extension_header *nhrp_ext_pull(struct zbuf *zb, return ext; } -void nhrp_ext_request(struct zbuf *zb, struct nhrp_packet_header *hdr, - struct interface *ifp) +void nhrp_ext_request(struct zbuf *zb, struct nhrp_packet_header *hdr) { /* Place holders for standard extensions */ nhrp_ext_push(zb, hdr, diff --git a/nhrpd/nhrp_peer.c b/nhrpd/nhrp_peer.c index 6e7857c777..84fcdb0697 100644 --- a/nhrpd/nhrp_peer.c +++ b/nhrpd/nhrp_peer.c @@ -603,7 +603,7 @@ static void nhrp_handle_resolution_req(struct nhrp_packet_parser *pp) break; } } - nhrp_packet_complete(zb, hdr); + nhrp_packet_complete(zb, hdr, ifp); nhrp_peer_send(peer, zb); err: nhrp_peer_unref(peer); @@ -730,7 +730,8 @@ static void nhrp_handle_registration_request(struct nhrp_packet_parser *p) } } - nhrp_packet_complete(zb, hdr); + // auth ext was validated and copied from the request + nhrp_packet_complete_auth(zb, hdr, ifp, false); nhrp_peer_send(p->peer, zb); err: zbuf_free(zb); @@ -812,7 +813,7 @@ void nhrp_peer_send_indication(struct interface *ifp, uint16_t protocol_type, /* Payload is the packet causing indication */ zbuf_copy(zb, pkt, zbuf_used(pkt)); - nhrp_packet_complete(zb, hdr); + nhrp_packet_complete(zb, hdr, ifp); nhrp_peer_send(p, zb); nhrp_peer_unref(p); zbuf_free(zb); @@ -1063,7 +1064,8 @@ static void nhrp_peer_forward(struct nhrp_peer *p, nhrp_ext_complete(zb, dst); } - nhrp_packet_complete(zb, hdr); + // XXX: auth already handled ??? + nhrp_packet_complete_auth(zb, hdr, pp->ifp, false); nhrp_peer_send(p, zb); zbuf_free(zb); zbuf_free(zb_copy); @@ -1089,8 +1091,7 @@ static void nhrp_packet_debug(struct zbuf *zb, const char *dir) reply = packet_types[hdr->type].type == PACKET_REPLY; debugf(NHRP_DEBUG_COMMON, "%s %s(%d) %pSU -> %pSU", dir, - (packet_types[hdr->type].name ? packet_types[hdr->type].name - : "Unknown"), + (packet_types[hdr->type].name ? : "Unknown"), hdr->type, reply ? &dst_proto : &src_proto, reply ? &src_proto : &dst_proto); } @@ -1106,11 +1107,70 @@ static int proto2afi(uint16_t proto) return AF_UNSPEC; } -struct nhrp_route_info { - int local; - struct interface *ifp; - struct nhrp_vc *vc; -}; +static int nhrp_packet_send_error(struct nhrp_packet_parser *pp, + uint16_t indication_code, uint16_t offset) +{ + union sockunion src_proto, dst_proto; + struct nhrp_packet_header *hdr; + struct zbuf *zb; + + src_proto = pp->src_proto; + dst_proto = pp->dst_proto; + if (packet_types[pp->hdr->type].type != PACKET_REPLY) { + src_proto = pp->dst_proto; + dst_proto = pp->src_proto; + } + /* Create reply */ + zb = zbuf_alloc(1500); // XXX: hardcode -> calculation routine + hdr = nhrp_packet_push(zb, NHRP_PACKET_ERROR_INDICATION, &pp->src_nbma, + &src_proto, &dst_proto); + + hdr->u.error.code = indication_code; + hdr->u.error.offset = htons(offset); + hdr->flags = pp->hdr->flags; + hdr->hop_count = 0; // XXX: cisco returns 255 + + /* Payload is the packet causing error */ + /* Don`t add extension according to RFC */ + /* wireshark gives bad checksum, without exts */ + // pp->hdr->checksum = nhrp_packet_calculate_checksum(zbuf_used(&pp->payload)) + zbuf_put(zb, pp->hdr, sizeof(*pp->hdr)); + zbuf_copy(zb, &pp->payload, zbuf_used(&pp->payload)); + nhrp_packet_complete_auth(zb, hdr, pp->ifp, false); + + /* nhrp_packet_debug(zb, "SEND_ERROR"); */ + nhrp_peer_send(pp->peer, zb); + zbuf_free(zb); + return 0; +} + +static bool nhrp_connection_authorized(struct nhrp_packet_parser *pp) +{ + struct nhrp_cisco_authentication_extension *auth_ext; + struct nhrp_interface *nifp = pp->ifp->info; + struct zbuf *auth = nifp->auth_token; + struct nhrp_extension_header *ext; + struct zbuf *extensions, pl; + int cmp = 0; + + + extensions = zbuf_alloc(zbuf_used(&pp->extensions)); + zbuf_copy_peek(extensions, &pp->extensions, zbuf_used(&pp->extensions)); + while ((ext = nhrp_ext_pull(extensions, &pl)) != NULL) { + switch (htons(ext->type) & ~NHRP_EXTENSION_FLAG_COMPULSORY) { + case NHRP_EXTENSION_AUTHENTICATION: + cmp = memcmp(auth->buf, pl.buf, zbuf_size(auth)); + auth_ext = (struct nhrp_cisco_authentication_extension *) + auth->buf; + debugf(NHRP_DEBUG_COMMON, + "Processing Authentication Extension for (%s:%s|%d)", + auth_ext->secret, (const char *)pl.buf, cmp); + break; + } + } + zbuf_free(extensions); + return cmp == 0; +} void nhrp_peer_recv(struct nhrp_peer *p, struct zbuf *zb) { @@ -1191,10 +1251,20 @@ void nhrp_peer_recv(struct nhrp_peer *p, struct zbuf *zb) goto drop; } + /* RFC2332 5.3.4 - Authentication is always done pairwise on an NHRP + * hop-by-hop basis; i.e. regenerated at each hop. */ nhrp_packet_debug(zb, "Recv"); - - /* FIXME: Check authentication here. This extension needs to be - * pre-handled. */ + if (nifp->auth_token && + (hdr->type != NHRP_PACKET_ERROR_INDICATION || + hdr->u.error.code != NHRP_ERROR_AUTHENTICATION_FAILURE)) { + if (!nhrp_connection_authorized(&pp)) { + nhrp_packet_send_error(&pp, + NHRP_ERROR_AUTHENTICATION_FAILURE, + 0); + info = "authentication failure"; + goto drop; + } + } /* Figure out if this is local */ target_addr = (packet_types[hdr->type].type == PACKET_REPLY) diff --git a/nhrpd/nhrp_shortcut.c b/nhrpd/nhrp_shortcut.c index e83ce7f58f..9b47d974c3 100644 --- a/nhrpd/nhrp_shortcut.c +++ b/nhrpd/nhrp_shortcut.c @@ -425,7 +425,7 @@ static void nhrp_shortcut_send_resolution_req(struct nhrp_shortcut *s) "Shortcut res_req: set cie ht to %u and mtu to %u. shortcut ht is %u", ntohs(cie->holding_time), ntohs(cie->mtu), s->holding_time); - nhrp_ext_request(zb, hdr, ifp); + nhrp_ext_request(zb, hdr); /* Cisco NAT detection extension */ hdr->flags |= htons(NHRP_FLAG_RESOLUTION_NAT); @@ -438,7 +438,7 @@ static void nhrp_shortcut_send_resolution_req(struct nhrp_shortcut *s) nhrp_ext_complete(zb, ext); } - nhrp_packet_complete(zb, hdr); + nhrp_packet_complete(zb, hdr, ifp); nhrp_peer_send(peer, zb); nhrp_peer_unref(peer); diff --git a/nhrpd/nhrp_vty.c b/nhrpd/nhrp_vty.c index 40d38c44d2..66659bdcdb 100644 --- a/nhrpd/nhrp_vty.c +++ b/nhrpd/nhrp_vty.c @@ -12,6 +12,9 @@ #include "nhrpd.h" #include "netlink.h" +#include "nhrp_protocol.h" + +#include "nhrpd/nhrp_vty_clippy.c" static int nhrp_config_write(struct vty *vty); static struct cmd_node zebra_node = { @@ -459,6 +462,56 @@ DEFUN(if_no_nhrp_holdtime, if_no_nhrp_holdtime_cmd, return CMD_SUCCESS; } +#define NHRP_CISCO_PASS_LEN 8 +DEFPY(if_nhrp_authentication, if_nhrp_authentication_cmd, + AFI_CMD "nhrp authentication PASSWORD$password", + AFI_STR + NHRP_STR + "Specify plaint text password used for authenticantion\n" + "Password, plain text, limited to 8 characters\n") +{ + VTY_DECLVAR_CONTEXT(interface, ifp); + struct nhrp_cisco_authentication_extension *auth; + struct nhrp_interface *nifp = ifp->info; + int pass_len = strlen(password); + + if (pass_len > NHRP_CISCO_PASS_LEN) { + vty_out(vty, "Password size limit exceeded (%d>%d)\n", + pass_len, NHRP_CISCO_PASS_LEN); + return CMD_WARNING_CONFIG_FAILED; + } + + if (nifp->auth_token) + zbuf_free(nifp->auth_token); + + nifp->auth_token = zbuf_alloc(pass_len + sizeof(uint32_t)); + auth = (struct nhrp_cisco_authentication_extension *) + nifp->auth_token->buf; + auth->type = htonl(NHRP_AUTHENTICATION_PLAINTEXT); + memcpy(auth->secret, password, pass_len); + + // XXX RFC: reset active (non-authorized) connections? + /* vty_out(vty, "NHRP passwd (%s:%s)", nifp->ifp->name, auth->secret); */ + return CMD_SUCCESS; +} + + +DEFPY(if_no_nhrp_authentication, if_no_nhrp_authentication_cmd, + "no " AFI_CMD "nhrp authentication PASSWORD$password", + NO_STR + AFI_STR + NHRP_STR + "Reset password used for authentication\n" + "Password, plain text\n") +{ + VTY_DECLVAR_CONTEXT(interface, ifp); + struct nhrp_interface *nifp = ifp->info; + if (nifp->auth_token) + zbuf_free(nifp->auth_token); + return CMD_SUCCESS; +} + + DEFUN(if_nhrp_mtu, if_nhrp_mtu_cmd, "ip nhrp mtu <(576-1500)|opennhrp>", IP_STR @@ -1053,6 +1106,7 @@ DEFUN(show_dmvpn, show_dmvpn_cmd, static void clear_nhrp_cache(struct nhrp_cache *c, void *data) { struct info_ctx *ctx = data; + if (c->cur.type <= NHRP_CACHE_DYNAMIC) { nhrp_cache_update_binding(c, c->cur.type, -1, NULL, 0, NULL, NULL); @@ -1129,6 +1183,7 @@ static void interface_config_write_nhrp_map(struct nhrp_cache_config *c, static int interface_config_write(struct vty *vty) { struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT); + struct nhrp_cisco_authentication_extension *auth; struct write_map_ctx mapctx; struct interface *ifp; struct nhrp_interface *nifp; @@ -1155,6 +1210,12 @@ static int interface_config_write(struct vty *vty) if (nifp->source) vty_out(vty, " tunnel source %s\n", nifp->source); + if (nifp->auth_token) { + auth = (struct nhrp_cisco_authentication_extension *) + nifp->auth_token->buf; + vty_out(vty, " ip nhrp authentication %s\n", auth->secret); + } + for (afi = 0; afi < AFI_MAX; afi++) { struct nhrp_afi_data *ad = &nifp->afi[afi]; @@ -1256,6 +1317,8 @@ void nhrp_config_init(void) install_element(INTERFACE_NODE, &if_no_nhrp_network_id_cmd); install_element(INTERFACE_NODE, &if_nhrp_holdtime_cmd); install_element(INTERFACE_NODE, &if_no_nhrp_holdtime_cmd); + install_element(INTERFACE_NODE, &if_nhrp_authentication_cmd); + install_element(INTERFACE_NODE, &if_no_nhrp_authentication_cmd); install_element(INTERFACE_NODE, &if_nhrp_mtu_cmd); install_element(INTERFACE_NODE, &if_no_nhrp_mtu_cmd); install_element(INTERFACE_NODE, &if_nhrp_flags_cmd); diff --git a/nhrpd/nhrpd.h b/nhrpd/nhrpd.h index e389b7489d..344e1d5178 100644 --- a/nhrpd/nhrpd.h +++ b/nhrpd/nhrpd.h @@ -311,6 +311,7 @@ DECLARE_DLIST(nhrp_reglist, struct nhrp_registration, reglist_entry); struct nhrp_interface { struct interface *ifp; + struct zbuf *auth_token; unsigned enabled : 1; char *ipsec_profile, *ipsec_fallback_profile, *source; @@ -480,9 +481,13 @@ struct nhrp_packet_header *nhrp_packet_push(struct zbuf *zb, uint8_t type, const union sockunion *src_nbma, const union sockunion *src_proto, const union sockunion *dst_proto); -void nhrp_packet_complete(struct zbuf *zb, struct nhrp_packet_header *hdr); uint16_t nhrp_packet_calculate_checksum(const uint8_t *pdu, uint16_t len); +void nhrp_packet_complete(struct zbuf *zb, struct nhrp_packet_header *hdr, + struct interface *ifp); +void nhrp_packet_complete_auth(struct zbuf *zb, struct nhrp_packet_header *hdr, + struct interface *ifp, bool auth); + struct nhrp_packet_header *nhrp_packet_pull(struct zbuf *zb, union sockunion *src_nbma, union sockunion *src_proto, @@ -501,8 +506,7 @@ nhrp_ext_push(struct zbuf *zb, struct nhrp_packet_header *hdr, uint16_t type); void nhrp_ext_complete(struct zbuf *zb, struct nhrp_extension_header *ext); struct nhrp_extension_header *nhrp_ext_pull(struct zbuf *zb, struct zbuf *payload); -void nhrp_ext_request(struct zbuf *zb, struct nhrp_packet_header *hdr, - struct interface *); +void nhrp_ext_request(struct zbuf *zb, struct nhrp_packet_header *hdr); int nhrp_ext_reply(struct zbuf *zb, struct nhrp_packet_header *hdr, struct interface *ifp, struct nhrp_extension_header *ext, struct zbuf *extpayload); diff --git a/nhrpd/subdir.am b/nhrpd/subdir.am index 227ff6c678..94fb3bb5be 100644 --- a/nhrpd/subdir.am +++ b/nhrpd/subdir.am @@ -42,3 +42,7 @@ noinst_HEADERS += \ nhrpd/zbuf.h \ nhrpd/znl.h \ # end + +clippy_scan += \ + nhrpd/nhrp_vty.c \ + # end diff --git a/tests/topotests/nhrp_topo/r1/nhrpd.conf b/tests/topotests/nhrp_topo/r1/nhrpd.conf index e5224e4aab..027312dcd5 100644 --- a/tests/topotests/nhrp_topo/r1/nhrpd.conf +++ b/tests/topotests/nhrp_topo/r1/nhrpd.conf @@ -1,6 +1,7 @@ log stdout debugging ! debug nhrp all interface r1-gre0 + ip nhrp authentication secret ip nhrp holdtime 500 ip nhrp shortcut ip nhrp network-id 42 diff --git a/tests/topotests/nhrp_topo/r2/nhrpd.conf b/tests/topotests/nhrp_topo/r2/nhrpd.conf index f9185f9a63..621db6abc8 100644 --- a/tests/topotests/nhrp_topo/r2/nhrpd.conf +++ b/tests/topotests/nhrp_topo/r2/nhrpd.conf @@ -2,6 +2,7 @@ log stdout debugging nhrp nflog-group 1 interface r2-gre0 + ip nhrp authentication secret ip nhrp holdtime 500 ip nhrp redirect ip nhrp network-id 42 diff --git a/tests/topotests/nhrp_topo/test_nhrp_topo.py b/tests/topotests/nhrp_topo/test_nhrp_topo.py index 284c58a8e7..c57d28b709 100644 --- a/tests/topotests/nhrp_topo/test_nhrp_topo.py +++ b/tests/topotests/nhrp_topo/test_nhrp_topo.py @@ -214,19 +214,64 @@ def test_protocols_convergence(): def test_nhrp_connection(): "Assert that the NHRP peers can find themselves." tgen = get_topogen() + pingrouter = tgen.gears["r1"] + hubrouter = tgen.gears["r2"] if tgen.routers_have_failure(): pytest.skip(tgen.errors) - pingrouter = tgen.gears["r1"] - logger.info("Check Ping IPv4 from R1 to R2 = 10.255.255.2)") - output = pingrouter.run("ping 10.255.255.2 -f -c 1000") - logger.info(output) - if "1000 packets transmitted, 1000 received" not in output: + def ping_helper(): + output = pingrouter.run("ping 10.255.255.2 -f -c 100") + logger.info(output) + return output + + # force session to reinitialize + def relink_session(): + for r in ["r1", "r2"]: + tgen.gears[r].vtysh_cmd("clear ip nhrp cache") + tgen.net[r].cmd("ip l del {}-gre0".format(r)); + _populate_iface(); + + ### Passwords are the same + logger.info("Check Ping IPv4 from R1 to R2 = 10.255.255.2") + output = ping_helper() + if "100 packets transmitted, 100 received" not in output: assertmsg = "expected ping IPv4 from R1 to R2 should be ok" assert 0, assertmsg else: logger.info("Check Ping IPv4 from R1 to R2 OK") + ### Passwords are different + logger.info("Modify password and send ping again, should drop") + hubrouter.vtysh_cmd(""" + configure + interface r2-gre0 + ip nhrp authentication secret12 + """) + relink_session() + topotest.sleep(10, "Waiting for session to initialize") + output = ping_helper() + if "Network is unreachable" not in output: + assertmsg = "expected ping IPv4 from R1 to R2 - should be down" + assert 0, assertmsg + else: + logger.info("Check Ping IPv4 from R1 to R2 missing - OK") + + ### Passwords are the same - again + logger.info("Recover password and verify conectivity is back") + hubrouter.vtysh_cmd(""" + configure + interface r2-gre0 + ip nhrp authentication secret + """) + relink_session() + topotest.sleep(10, "Waiting for session to initialize") + output = pingrouter.run("ping 10.255.255.2 -f -c 100") + logger.info(output) + if "100 packets transmitted, 100 received" not in output: + assertmsg = "expected ping IPv4 from R1 to R2 should be ok" + assert 0, assertmsg + else: + logger.info("Check Ping IPv4 from R1 to R2 OK") def test_route_install(): "Test use of NHRP routes by other protocols (sharpd here)." From b5540d326b82ca92ed88f9082fe0ed2433b09c27 Mon Sep 17 00:00:00 2001 From: Dave LeRoy Date: Wed, 5 Jun 2024 12:10:11 -0700 Subject: [PATCH 013/347] nhrpd: add cisco-authentication password support Taking over this development from https://github.com/FRRouting/frr/pull/14788 This commit addresses 4 issues found in the previous PR 1) FRR would accept messages from a spoke without authentication when FRR NHRP had auth configured. 2) The error indication was not being sent in network byte order 3) The debug print in nhrp_connection_authorized was not correctly printing the received password 4) The addresses portion of the mandatory part of the error indication was invalid on the wire (confirmed in wireshark) Signed-off-by: Dave LeRoy Co-authored-by: Volodymyr Huti --- doc/user/nhrpd.rst | 2 +- nhrpd/nhrp_interface.c | 2 + nhrpd/nhrp_peer.c | 31 ++++++++------ nhrpd/nhrp_vty.c | 9 ++-- tests/topotests/nhrp_topo/r1/nhrpd.conf | 2 +- tests/topotests/nhrp_topo/r2/nhrpd.conf | 2 +- tests/topotests/nhrp_topo/test_nhrp_topo.py | 46 ++++++++++----------- 7 files changed, 51 insertions(+), 43 deletions(-) diff --git a/doc/user/nhrpd.rst b/doc/user/nhrpd.rst index e0ba90fcc1..648d56d9c1 100644 --- a/doc/user/nhrpd.rst +++ b/doc/user/nhrpd.rst @@ -88,7 +88,7 @@ Configuring NHRP Enables Cisco style authentication on NHRP packets. This embeds the plaintext password to the outgoing NHRP packets. - Maximum length of the is 8 characters. + Maximum length of the password is 8 characters. .. clicmd:: ip nhrp map A.B.C.D|X:X::X:X A.B.C.D|local diff --git a/nhrpd/nhrp_interface.c b/nhrpd/nhrp_interface.c index 7d0ab9762f..e81a2efbb6 100644 --- a/nhrpd/nhrp_interface.c +++ b/nhrpd/nhrp_interface.c @@ -99,6 +99,8 @@ static int nhrp_if_delete_hook(struct interface *ifp) free(nifp->ipsec_fallback_profile); if (nifp->source) free(nifp->source); + if (nifp->auth_token) + zbuf_free(nifp->auth_token); XFREE(MTYPE_NHRP_IF, ifp->info); return 0; diff --git a/nhrpd/nhrp_peer.c b/nhrpd/nhrp_peer.c index 84fcdb0697..2414541bfa 100644 --- a/nhrpd/nhrp_peer.c +++ b/nhrpd/nhrp_peer.c @@ -730,7 +730,7 @@ static void nhrp_handle_registration_request(struct nhrp_packet_parser *p) } } - // auth ext was validated and copied from the request + /* auth ext was validated and copied from the request */ nhrp_packet_complete_auth(zb, hdr, ifp, false); nhrp_peer_send(p->peer, zb); err: @@ -1064,7 +1064,6 @@ static void nhrp_peer_forward(struct nhrp_peer *p, nhrp_ext_complete(zb, dst); } - // XXX: auth already handled ??? nhrp_packet_complete_auth(zb, hdr, pp->ifp, false); nhrp_peer_send(p, zb); zbuf_free(zb); @@ -1121,24 +1120,26 @@ static int nhrp_packet_send_error(struct nhrp_packet_parser *pp, dst_proto = pp->src_proto; } /* Create reply */ - zb = zbuf_alloc(1500); // XXX: hardcode -> calculation routine + zb = zbuf_alloc(1500); hdr = nhrp_packet_push(zb, NHRP_PACKET_ERROR_INDICATION, &pp->src_nbma, &src_proto, &dst_proto); - hdr->u.error.code = indication_code; + hdr->u.error.code = htons(indication_code); hdr->u.error.offset = htons(offset); hdr->flags = pp->hdr->flags; - hdr->hop_count = 0; // XXX: cisco returns 255 + hdr->hop_count = 0; /* XXX: cisco returns 255 */ /* Payload is the packet causing error */ /* Don`t add extension according to RFC */ - /* wireshark gives bad checksum, without exts */ - // pp->hdr->checksum = nhrp_packet_calculate_checksum(zbuf_used(&pp->payload)) zbuf_put(zb, pp->hdr, sizeof(*pp->hdr)); - zbuf_copy(zb, &pp->payload, zbuf_used(&pp->payload)); + zbuf_put(zb, sockunion_get_addr(&pp->src_nbma), + hdr->src_nbma_address_len); + zbuf_put(zb, sockunion_get_addr(&pp->src_proto), + hdr->src_protocol_address_len); + zbuf_put(zb, sockunion_get_addr(&pp->dst_proto), + hdr->dst_protocol_address_len); nhrp_packet_complete_auth(zb, hdr, pp->ifp, false); - /* nhrp_packet_debug(zb, "SEND_ERROR"); */ nhrp_peer_send(pp->peer, zb); zbuf_free(zb); return 0; @@ -1151,8 +1152,7 @@ static bool nhrp_connection_authorized(struct nhrp_packet_parser *pp) struct zbuf *auth = nifp->auth_token; struct nhrp_extension_header *ext; struct zbuf *extensions, pl; - int cmp = 0; - + int cmp = 1; extensions = zbuf_alloc(zbuf_used(&pp->extensions)); zbuf_copy_peek(extensions, &pp->extensions, zbuf_used(&pp->extensions)); @@ -1164,7 +1164,14 @@ static bool nhrp_connection_authorized(struct nhrp_packet_parser *pp) auth->buf; debugf(NHRP_DEBUG_COMMON, "Processing Authentication Extension for (%s:%s|%d)", - auth_ext->secret, (const char *)pl.buf, cmp); + auth_ext->secret, + ((struct nhrp_cisco_authentication_extension *) + pl.buf) + ->secret, + cmp); + break; + default: + /* Ignoring all received extensions except Authentication*/ break; } } diff --git a/nhrpd/nhrp_vty.c b/nhrpd/nhrp_vty.c index 66659bdcdb..b938ae4cf0 100644 --- a/nhrpd/nhrp_vty.c +++ b/nhrpd/nhrp_vty.c @@ -467,7 +467,7 @@ DEFPY(if_nhrp_authentication, if_nhrp_authentication_cmd, AFI_CMD "nhrp authentication PASSWORD$password", AFI_STR NHRP_STR - "Specify plaint text password used for authenticantion\n" + "Specify plain text password used for authenticantion\n" "Password, plain text, limited to 8 characters\n") { VTY_DECLVAR_CONTEXT(interface, ifp); @@ -490,8 +490,6 @@ DEFPY(if_nhrp_authentication, if_nhrp_authentication_cmd, auth->type = htonl(NHRP_AUTHENTICATION_PLAINTEXT); memcpy(auth->secret, password, pass_len); - // XXX RFC: reset active (non-authorized) connections? - /* vty_out(vty, "NHRP passwd (%s:%s)", nifp->ifp->name, auth->secret); */ return CMD_SUCCESS; } @@ -501,11 +499,12 @@ DEFPY(if_no_nhrp_authentication, if_no_nhrp_authentication_cmd, NO_STR AFI_STR NHRP_STR - "Reset password used for authentication\n" - "Password, plain text\n") + "Specify plain text password used for authenticantion\n" + "Password, plain text, limited to 8 characters\n") { VTY_DECLVAR_CONTEXT(interface, ifp); struct nhrp_interface *nifp = ifp->info; + if (nifp->auth_token) zbuf_free(nifp->auth_token); return CMD_SUCCESS; diff --git a/tests/topotests/nhrp_topo/r1/nhrpd.conf b/tests/topotests/nhrp_topo/r1/nhrpd.conf index 027312dcd5..8ade77d07d 100644 --- a/tests/topotests/nhrp_topo/r1/nhrpd.conf +++ b/tests/topotests/nhrp_topo/r1/nhrpd.conf @@ -2,7 +2,7 @@ log stdout debugging ! debug nhrp all interface r1-gre0 ip nhrp authentication secret - ip nhrp holdtime 500 + ip nhrp holdtime 10 ip nhrp shortcut ip nhrp network-id 42 ip nhrp nhs dynamic nbma 10.2.1.2 diff --git a/tests/topotests/nhrp_topo/r2/nhrpd.conf b/tests/topotests/nhrp_topo/r2/nhrpd.conf index 621db6abc8..d8e59936c8 100644 --- a/tests/topotests/nhrp_topo/r2/nhrpd.conf +++ b/tests/topotests/nhrp_topo/r2/nhrpd.conf @@ -3,7 +3,7 @@ log stdout debugging nhrp nflog-group 1 interface r2-gre0 ip nhrp authentication secret - ip nhrp holdtime 500 + ip nhrp holdtime 10 ip nhrp redirect ip nhrp network-id 42 ip nhrp registration no-unique diff --git a/tests/topotests/nhrp_topo/test_nhrp_topo.py b/tests/topotests/nhrp_topo/test_nhrp_topo.py index c57d28b709..8833003107 100644 --- a/tests/topotests/nhrp_topo/test_nhrp_topo.py +++ b/tests/topotests/nhrp_topo/test_nhrp_topo.py @@ -28,7 +28,7 @@ from lib import topotest from lib.topogen import Topogen, TopoRouter, get_topogen from lib.topolog import logger -from lib.common_config import required_linux_kernel_version +from lib.common_config import required_linux_kernel_version, retry # Required to instantiate the topology builder class. @@ -231,14 +231,27 @@ def relink_session(): tgen.net[r].cmd("ip l del {}-gre0".format(r)); _populate_iface(); + @retry(retry_timeout=40, initial_wait=5) + def verify_same_password(): + output = ping_helper() + if "100 packets transmitted, 100 received" not in output: + assertmsg = "expected ping IPv4 from R1 to R2 should be ok" + assert 0, assertmsg + else: + logger.info("Check Ping IPv4 from R1 to R2 OK") + + @retry(retry_timeout=40, initial_wait=5) + def verify_mismatched_password(): + output = ping_helper() + if "Network is unreachable" not in output: + assertmsg = "expected ping IPv4 from R1 to R2 - should be down" + assert 0, assertmsg + else: + logger.info("Check Ping IPv4 from R1 to R2 missing - OK") + ### Passwords are the same logger.info("Check Ping IPv4 from R1 to R2 = 10.255.255.2") - output = ping_helper() - if "100 packets transmitted, 100 received" not in output: - assertmsg = "expected ping IPv4 from R1 to R2 should be ok" - assert 0, assertmsg - else: - logger.info("Check Ping IPv4 from R1 to R2 OK") + verify_same_password() ### Passwords are different logger.info("Modify password and send ping again, should drop") @@ -248,14 +261,8 @@ def relink_session(): ip nhrp authentication secret12 """) relink_session() - topotest.sleep(10, "Waiting for session to initialize") - output = ping_helper() - if "Network is unreachable" not in output: - assertmsg = "expected ping IPv4 from R1 to R2 - should be down" - assert 0, assertmsg - else: - logger.info("Check Ping IPv4 from R1 to R2 missing - OK") - + verify_mismatched_password() + ### Passwords are the same - again logger.info("Recover password and verify conectivity is back") hubrouter.vtysh_cmd(""" @@ -264,14 +271,7 @@ def relink_session(): ip nhrp authentication secret """) relink_session() - topotest.sleep(10, "Waiting for session to initialize") - output = pingrouter.run("ping 10.255.255.2 -f -c 100") - logger.info(output) - if "100 packets transmitted, 100 received" not in output: - assertmsg = "expected ping IPv4 from R1 to R2 should be ok" - assert 0, assertmsg - else: - logger.info("Check Ping IPv4 from R1 to R2 OK") + verify_same_password() def test_route_install(): "Test use of NHRP routes by other protocols (sharpd here)." From 9fb7d677d3584eadd1d4568bedd542eb880afcd7 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Thu, 30 May 2024 15:47:11 +0200 Subject: [PATCH 014/347] bgpd: fix do not skip paths with same nexthop Under a setup where two BGP prefixes are available from multiple sources, if one of the two prefixes is recursive over the other BGP prefix, then it will not be considered as multipath. The below output shows the two prefixes 192.0.2.24/32 and 192.0.2.21/32. The 192.0.2.[5,6,8] are the known IP addresses visible from the IGP. > # show bgp ipv4 192.0.2.24/32 > *>i 192.0.2.24/32 192.0.2.21 0 100 0 i > * i 192.0.2.21 0 100 0 i > * i 192.0.2.21 0 100 0 i > # show bgp ipv4 192.0.2.21/32 > *>i 192.0.2.21/32 192.0.2.5 0 100 0 i > *=i 192.0.2.6 0 100 0 i > *=i 192.0.2.8 0 100 0 i The bgp best selection algorithm refuses to consider the paths to '192.0.2.24/32' as multipath, whereas the BGP paths which use the BGP peer as nexthop are considered multipath. > ... has the same nexthop as the bestpath, skip it ... Previously, this condition has been added to prevent ZEBRA from installing routes with same nexthop: > Here you can see the two paths with nexthop 210.2.2.2 > superm-redxp-05# show ip route 2.23.24.192/28 > Routing entry for 2.23.24.192/28 > Known via "bgp", distance 20, metric 0, best > Last update 00:32:12 ago > * 210.2.2.2, via swp3 > * 210.2.0.2, via swp1 > * 210.2.1.2, via swp2 > * 210.2.2.2, via swp3 > [..] But today, ZEBRA knows how to handle it. When receiving incoming routes, nexthop groups are used. At creation, duplicated nexthops are identified, and will not be installed. The below output illustrate the duplicate paths to 172.16.0.200 received by an other peer. > r1# show ip route 172.18.1.100 nexthop-group > Routing entry for 172.18.1.100/32 > Known via "bgp", distance 200, metric 0, best > Last update 00:03:03 ago > Nexthop Group ID: 75757580 > 172.16.0.200 (recursive), weight 1 > * 172.31.0.3, via r1-eth1, label 16055, weight 1 > * 172.31.2.4, via r1-eth2, label 16055, weight 1 > * 172.31.0.3, via r1-eth1, label 16006, weight 1 > * 172.31.2.4, via r1-eth2, label 16006, weight 1 > * 172.31.8.7, via r1-eth4, label 16008, weight 1 > 172.16.0.200 (duplicate nexthop removed) (recursive), weight 1 > 172.31.0.3, via r1-eth1 (duplicate nexthop removed), label 16055, weight 1 > 172.31.2.4, via r1-eth2 (duplicate nexthop removed), label 16055, weight 1 > 172.31.0.3, via r1-eth1 (duplicate nexthop removed), label 16006, weight 1 > 172.31.2.4, via r1-eth2 (duplicate nexthop removed), label 16006, weight 1 > 172.31.8.7, via r1-eth4 (duplicate nexthop removed), label 16008, weight 1 Fix this by proposing to let ZEBRA handle this duplicate decision. Fixes: 7dc9d4e4e360 ("bgp may add multiple path entries with the same nexthop") Signed-off-by: Philippe Guibert --- bgpd/bgp_mpath.c | 115 +++++++++++++++++++++++++++++------------------ bgpd/bgp_route.c | 9 ---- 2 files changed, 71 insertions(+), 53 deletions(-) diff --git a/bgpd/bgp_mpath.c b/bgpd/bgp_mpath.c index e12d84b84c..eadd52b8e0 100644 --- a/bgpd/bgp_mpath.c +++ b/bgpd/bgp_mpath.c @@ -605,31 +605,43 @@ void bgp_path_info_mpath_update(struct bgp *bgp, struct bgp_dest *dest, if (mp_node && (listgetdata(mp_node) == cur_mpath)) { list_delete_node(mp_list, mp_node); bgp_path_info_mpath_dequeue(cur_mpath); - if ((mpath_count < maxpaths) - && prev_mpath - && bgp_path_info_nexthop_cmp(prev_mpath, - cur_mpath)) { + if ((mpath_count < maxpaths) && prev_mpath) { + mpath_count++; + if (bgp_path_info_nexthop_cmp(prev_mpath, + cur_mpath)) { + if (ecommunity_linkbw_present( + bgp_attr_get_ecommunity( + cur_mpath->attr), + &bwval) || + ecommunity_linkbw_present( + bgp_attr_get_ipv6_ecommunity( + cur_mpath->attr), + &bwval)) + cum_bw += bwval; + else + all_paths_lb = false; + if (debug) { + bgp_path_info_path_with_addpath_rx_str( + cur_mpath, path_buf, + sizeof(path_buf)); + zlog_debug("%pBD: %s is still multipath, cur count %d", + dest, path_buf, + mpath_count); + } + } else { + if (debug) { + bgp_path_info_path_with_addpath_rx_str( + cur_mpath, path_buf, + sizeof(path_buf)); + zlog_debug("%pBD: nexthop equal, however add mpath %s nexthop %pI4, cur count %d", + dest, path_buf, + &cur_mpath->attr->nexthop, + mpath_count); + } + } bgp_path_info_mpath_enqueue(prev_mpath, cur_mpath); prev_mpath = cur_mpath; - mpath_count++; - if (ecommunity_linkbw_present(bgp_attr_get_ecommunity( - cur_mpath->attr), - &bwval) || - ecommunity_linkbw_present( - bgp_attr_get_ipv6_ecommunity( - cur_mpath->attr), - &bwval)) - cum_bw += bwval; - else - all_paths_lb = false; - if (debug) { - bgp_path_info_path_with_addpath_rx_str( - cur_mpath, path_buf, - sizeof(path_buf)); - zlog_debug("%pBD: %s is still multipath, cur count %d", - dest, path_buf, mpath_count); - } } else { mpath_changed = 1; if (debug) { @@ -693,35 +705,50 @@ void bgp_path_info_mpath_update(struct bgp *bgp, struct bgp_dest *dest, list_delete_node(mp_list, mp_node); assert(new_mpath); assert(prev_mpath); - if ((mpath_count < maxpaths) && (new_mpath != new_best) - && bgp_path_info_nexthop_cmp(prev_mpath, - new_mpath)) { + if ((mpath_count < maxpaths) && (new_mpath != new_best)) { + /* keep duplicate nexthop */ bgp_path_info_mpath_dequeue(new_mpath); bgp_path_info_mpath_enqueue(prev_mpath, new_mpath); - prev_mpath = new_mpath; mpath_changed = 1; mpath_count++; - if (ecommunity_linkbw_present(bgp_attr_get_ecommunity( - new_mpath->attr), - &bwval) || - ecommunity_linkbw_present( - bgp_attr_get_ipv6_ecommunity( - new_mpath->attr), - &bwval)) - cum_bw += bwval; - else - all_paths_lb = false; - if (debug) { - bgp_path_info_path_with_addpath_rx_str( - new_mpath, path_buf, - sizeof(path_buf)); - zlog_debug("%pBD: add mpath %s nexthop %pI4, cur count %d", - dest, path_buf, - &new_mpath->attr->nexthop, - mpath_count); + if (bgp_path_info_nexthop_cmp(prev_mpath, + new_mpath)) { + if (ecommunity_linkbw_present( + bgp_attr_get_ecommunity( + new_mpath->attr), + &bwval) || + ecommunity_linkbw_present( + bgp_attr_get_ipv6_ecommunity( + new_mpath->attr), + &bwval)) + cum_bw += bwval; + else + all_paths_lb = false; + if (debug) { + bgp_path_info_path_with_addpath_rx_str( + new_mpath, path_buf, + sizeof(path_buf)); + zlog_debug("%pBD: add mpath %s nexthop %pI4, cur count %d", + dest, path_buf, + &new_mpath->attr + ->nexthop, + mpath_count); + } + } else { + if (debug) { + bgp_path_info_path_with_addpath_rx_str( + new_mpath, path_buf, + sizeof(path_buf)); + zlog_debug("%pBD: nexthop equal, however add mpath %s nexthop %pI4, cur count %d", + dest, path_buf, + &new_mpath->attr + ->nexthop, + mpath_count); + } } + prev_mpath = new_mpath; } mp_node = mp_next_node; } diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 94c21e1861..4dcb22234a 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -3256,15 +3256,6 @@ void bgp_best_selection(struct bgp *bgp, struct bgp_dest *dest, if (!peer_established(pi->peer->connection)) continue; - if (!bgp_path_info_nexthop_cmp(pi, new_select)) { - if (debug) - zlog_debug( - "%pBD(%s): %s has the same nexthop as the bestpath, skip it", - dest, bgp->name_pretty, - path_buf); - continue; - } - bgp_path_info_cmp(bgp, pi, new_select, &paths_eq, mpath_cfg, debug, pfx_buf, afi, safi, &dest->reason); From a6b1d38d7f038c335143d963b7b7a13377ef5f22 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Mon, 10 Jun 2024 08:38:22 +0200 Subject: [PATCH 015/347] topotests: add API to detect if iproute2 is json capable Some tests may want to use the json facility of iproute2 to dump some results. Add an internal API in lib/topotest.py that tells whether iproute2 is json capable or not. Signed-off-by: Philippe Guibert --- tests/topotests/lib/topotest.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/tests/topotests/lib/topotest.py b/tests/topotests/lib/topotest.py index 087d8454fc..1d4bc2eac6 100644 --- a/tests/topotests/lib/topotest.py +++ b/tests/topotests/lib/topotest.py @@ -602,6 +602,30 @@ def is_linux(): return False +def iproute2_is_json_capable(): + """ + Checks if the iproute2 version installed on the system is capable of + handling JSON outputss + + Returns True if capability can be detected, returns False otherwise. + """ + if is_linux(): + try: + subp = subprocess.Popen( + ["ip", "-json", "route", "show"], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + stdin=subprocess.PIPE, + ) + iproute2_err = subp.communicate()[1].splitlines()[0].split()[0] + + if iproute2_err != "Error:": + return True + except Exception: + pass + return False + + def iproute2_is_vrf_capable(): """ Checks if the iproute2 version installed on the system is capable of From d0bac2796b404e3b206313c9003b770a50b45cdf Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Tue, 4 Jun 2024 18:50:26 +0200 Subject: [PATCH 016/347] topotests: add bgp duplicate nexthop test Add a topotest that ensures that when addpath is enabled and two paths with same nexthop are received, they are sent to ZEBRA which detects 'duplicate nexthop'. Signed-off-by: Philippe Guibert --- .../bgp_duplicate_nexthop/r1/bgpd.conf | 13 + .../bgp_duplicate_nexthop/r1/isisd.conf | 26 + .../bgp_duplicate_nexthop/r1/zebra.conf | 24 + .../bgp_duplicate_nexthop/r3/bgpd.conf | 16 + .../bgp_duplicate_nexthop/r3/isisd.conf | 38 ++ .../bgp_duplicate_nexthop/r3/zebra.conf | 16 + .../bgp_duplicate_nexthop/r4/isisd.conf | 30 ++ .../bgp_duplicate_nexthop/r4/zebra.conf | 20 + .../bgp_duplicate_nexthop/r5/bgpd.conf | 19 + .../bgp_duplicate_nexthop/r5/isisd.conf | 26 + .../bgp_duplicate_nexthop/r5/zebra.conf | 19 + .../bgp_duplicate_nexthop/r6/bgpd.conf | 19 + .../bgp_duplicate_nexthop/r6/isisd.conf | 22 + .../bgp_duplicate_nexthop/r6/zebra.conf | 20 + .../test_bgp_duplicate_nexthop.py | 458 ++++++++++++++++++ tests/topotests/lib/common_check.py | 48 ++ 16 files changed, 814 insertions(+) create mode 100644 tests/topotests/bgp_duplicate_nexthop/r1/bgpd.conf create mode 100644 tests/topotests/bgp_duplicate_nexthop/r1/isisd.conf create mode 100644 tests/topotests/bgp_duplicate_nexthop/r1/zebra.conf create mode 100644 tests/topotests/bgp_duplicate_nexthop/r3/bgpd.conf create mode 100644 tests/topotests/bgp_duplicate_nexthop/r3/isisd.conf create mode 100644 tests/topotests/bgp_duplicate_nexthop/r3/zebra.conf create mode 100644 tests/topotests/bgp_duplicate_nexthop/r4/isisd.conf create mode 100644 tests/topotests/bgp_duplicate_nexthop/r4/zebra.conf create mode 100644 tests/topotests/bgp_duplicate_nexthop/r5/bgpd.conf create mode 100644 tests/topotests/bgp_duplicate_nexthop/r5/isisd.conf create mode 100644 tests/topotests/bgp_duplicate_nexthop/r5/zebra.conf create mode 100644 tests/topotests/bgp_duplicate_nexthop/r6/bgpd.conf create mode 100644 tests/topotests/bgp_duplicate_nexthop/r6/isisd.conf create mode 100644 tests/topotests/bgp_duplicate_nexthop/r6/zebra.conf create mode 100644 tests/topotests/bgp_duplicate_nexthop/test_bgp_duplicate_nexthop.py create mode 100644 tests/topotests/lib/common_check.py diff --git a/tests/topotests/bgp_duplicate_nexthop/r1/bgpd.conf b/tests/topotests/bgp_duplicate_nexthop/r1/bgpd.conf new file mode 100644 index 0000000000..31f06dbb90 --- /dev/null +++ b/tests/topotests/bgp_duplicate_nexthop/r1/bgpd.conf @@ -0,0 +1,13 @@ +router bgp 64500 + bgp router-id 192.0.2.1 + no bgp ebgp-requires-policy + neighbor rrserver peer-group + neighbor rrserver remote-as 64500 + neighbor rrserver update-source lo + neighbor rrserver timers connect 2 + neighbor 192.0.2.3 peer-group rrserver + address-family ipv4 unicast + neighbor rrserver next-hop-self + neighbor rrserver activate + exit-address-family +! diff --git a/tests/topotests/bgp_duplicate_nexthop/r1/isisd.conf b/tests/topotests/bgp_duplicate_nexthop/r1/isisd.conf new file mode 100644 index 0000000000..9660577f4e --- /dev/null +++ b/tests/topotests/bgp_duplicate_nexthop/r1/isisd.conf @@ -0,0 +1,26 @@ +hostname r1 +interface lo + ip router isis 1 + isis passive +! +interface r1-eth1 + ip router isis 1 + isis network point-to-point +! +interface r1-eth2 + ip router isis 1 + isis network point-to-point +! +interface r1-eth4 + ip router isis 1 + isis network point-to-point +! +router isis 1 + net 49.0123.6452.0001.00 + is-type level-2-only + mpls-te on + segment-routing on + segment-routing global-block 16000 17000 + segment-routing node-msd 10 + segment-routing prefix 192.0.2.1/32 index 1 +! diff --git a/tests/topotests/bgp_duplicate_nexthop/r1/zebra.conf b/tests/topotests/bgp_duplicate_nexthop/r1/zebra.conf new file mode 100644 index 0000000000..2e3549a574 --- /dev/null +++ b/tests/topotests/bgp_duplicate_nexthop/r1/zebra.conf @@ -0,0 +1,24 @@ +log stdout +interface lo + ip address 192.0.2.1/32 +! +interface r1-eth0 + ip address 172.31.10.1/24 +! +interface r1-eth1 + ip address 172.31.0.1/24 + mpls enable +! +interface r1-eth2 + ip address 172.31.2.1/24 + mpls enable +! +interface r1-eth3 + ip address 172.31.11.1/24 + mpls enable +! +interface r1-eth4 + ip address 172.31.8.1/24 + mpls enable +! + diff --git a/tests/topotests/bgp_duplicate_nexthop/r3/bgpd.conf b/tests/topotests/bgp_duplicate_nexthop/r3/bgpd.conf new file mode 100644 index 0000000000..2b03f51a23 --- /dev/null +++ b/tests/topotests/bgp_duplicate_nexthop/r3/bgpd.conf @@ -0,0 +1,16 @@ +router bgp 64500 view one + bgp router-id 192.0.2.3 + neighbor rr peer-group + neighbor rr remote-as 64500 + neighbor rr update-source lo + neighbor 192.0.2.1 peer-group rr + neighbor 192.0.2.5 peer-group rr + neighbor 192.0.2.6 peer-group rr + neighbor 192.0.2.8 peer-group rr + ! + address-family ipv4 unicast + neighbor rr activate + neighbor rr route-reflector-client + neighbor rr addpath-tx-all-paths + exit-address-family +! diff --git a/tests/topotests/bgp_duplicate_nexthop/r3/isisd.conf b/tests/topotests/bgp_duplicate_nexthop/r3/isisd.conf new file mode 100644 index 0000000000..ae6bddee92 --- /dev/null +++ b/tests/topotests/bgp_duplicate_nexthop/r3/isisd.conf @@ -0,0 +1,38 @@ +hostname r3 +interface lo + ip router isis 1 + isis passive +! +interface r3-eth0 + ip router isis 1 + isis network point-to-point +! +interface r3-eth1 + ip router isis 1 + isis network point-to-point +! +interface r3-eth2 + ip router isis 1 + isis network point-to-point +! +interface r3-eth3 + ip router isis 1 + isis network point-to-point +! +interface r3-eth4 + ip router isis 1 + isis network point-to-point +! +interface r3-eth5 + ip router isis 1 + isis network point-to-point +! +router isis 1 + net 49.0123.6452.0003.00 + is-type level-2-only + mpls-te on + segment-routing on + segment-routing global-block 16000 17000 + segment-routing node-msd 10 + segment-routing prefix 192.0.2.3/32 index 3 +! diff --git a/tests/topotests/bgp_duplicate_nexthop/r3/zebra.conf b/tests/topotests/bgp_duplicate_nexthop/r3/zebra.conf new file mode 100644 index 0000000000..05b3769fb8 --- /dev/null +++ b/tests/topotests/bgp_duplicate_nexthop/r3/zebra.conf @@ -0,0 +1,16 @@ +log stdout +interface lo + ip address 192.0.2.3/32 +! +interface r3-eth0 + ip address 172.31.0.3/24 + mpls enable +! +interface r3-eth1 + ip address 172.31.4.3/24 + mpls enable +! +interface r3-eth2 + ip address 172.31.5.3/24 + mpls enable +! diff --git a/tests/topotests/bgp_duplicate_nexthop/r4/isisd.conf b/tests/topotests/bgp_duplicate_nexthop/r4/isisd.conf new file mode 100644 index 0000000000..4d49d0de0a --- /dev/null +++ b/tests/topotests/bgp_duplicate_nexthop/r4/isisd.conf @@ -0,0 +1,30 @@ +hostname r4 +interface lo + ip router isis 1 + isis passive +! +interface r4-eth0 + ip router isis 1 + isis network point-to-point +! +interface r4-eth1 + ip router isis 1 + isis network point-to-point +! +interface r4-eth2 + ip router isis 1 + isis network point-to-point +! +interface r4-eth3 + ip router isis 1 + isis network point-to-point +! +router isis 1 + net 49.0123.6452.0004.00 + is-type level-2-only + mpls-te on + segment-routing on + segment-routing global-block 16000 17000 + segment-routing node-msd 10 + segment-routing prefix 192.0.2.4/32 index 4 +! diff --git a/tests/topotests/bgp_duplicate_nexthop/r4/zebra.conf b/tests/topotests/bgp_duplicate_nexthop/r4/zebra.conf new file mode 100644 index 0000000000..9ea1b7ec43 --- /dev/null +++ b/tests/topotests/bgp_duplicate_nexthop/r4/zebra.conf @@ -0,0 +1,20 @@ +log stdout +interface lo + ip address 192.0.2.4/32 +! +interface r4-eth0 + ip address 172.31.2.4/24 + mpls enable +! +interface r4-eth1 + ip address 172.31.6.4/24 + mpls enable +! +interface r4-eth2 + ip address 172.31.7.4/24 + mpls enable +! +interface r4-eth3 + mpls enable +! + diff --git a/tests/topotests/bgp_duplicate_nexthop/r5/bgpd.conf b/tests/topotests/bgp_duplicate_nexthop/r5/bgpd.conf new file mode 100644 index 0000000000..272183b1ac --- /dev/null +++ b/tests/topotests/bgp_duplicate_nexthop/r5/bgpd.conf @@ -0,0 +1,19 @@ +router bgp 64500 + bgp router-id 192.0.2.5 + no bgp ebgp-requires-policy + no bgp network import-check + neighbor rrserver peer-group + neighbor rrserver remote-as 64500 + neighbor rrserver update-source lo + neighbor rrserver timers connect 2 + neighbor 192.0.2.3 peer-group rrserver + address-family ipv4 unicast + network 192.0.2.9/32 + network 192.0.2.8/32 route-map rmap + neighbor rrserver activate + neighbor rrserver addpath-tx-all-paths + exit-address-family +! +route-map rmap permit 1 + set ip next-hop 192.0.2.9 +exit diff --git a/tests/topotests/bgp_duplicate_nexthop/r5/isisd.conf b/tests/topotests/bgp_duplicate_nexthop/r5/isisd.conf new file mode 100644 index 0000000000..46556d9a56 --- /dev/null +++ b/tests/topotests/bgp_duplicate_nexthop/r5/isisd.conf @@ -0,0 +1,26 @@ +hostname r5 +interface lo + ip router isis 1 + isis passive +! +interface r5-eth1 + ip router isis 1 + isis network point-to-point +! +interface r5-eth2 + ip router isis 1 + isis network point-to-point +! +interface r5-eth3 + ip router isis 1 + isis network point-to-point +! +router isis 1 + net 49.0123.6452.0005.00 + is-type level-2-only + mpls-te on + segment-routing on + segment-routing global-block 16000 17000 + segment-routing node-msd 10 + segment-routing prefix 192.0.2.5/32 index 55 +! diff --git a/tests/topotests/bgp_duplicate_nexthop/r5/zebra.conf b/tests/topotests/bgp_duplicate_nexthop/r5/zebra.conf new file mode 100644 index 0000000000..6f326561e7 --- /dev/null +++ b/tests/topotests/bgp_duplicate_nexthop/r5/zebra.conf @@ -0,0 +1,19 @@ +log stdout +mpls label dynamic-block 5000 5999 +interface lo + ip address 192.0.2.5/32 +! +interface r5-eth0 + ip address 172.31.12.5/24 +! +interface r5-eth1 + ip address 172.31.4.5/24 + mpls enable +! +interface r5-eth2 + ip address 172.31.7.5/24 + mpls enable +! +interface r5-eth3 + ip address 172.31.21.5/24 +! diff --git a/tests/topotests/bgp_duplicate_nexthop/r6/bgpd.conf b/tests/topotests/bgp_duplicate_nexthop/r6/bgpd.conf new file mode 100644 index 0000000000..68bd36eb8a --- /dev/null +++ b/tests/topotests/bgp_duplicate_nexthop/r6/bgpd.conf @@ -0,0 +1,19 @@ +router bgp 64500 + bgp router-id 192.0.2.6 + no bgp ebgp-requires-policy + no bgp network import-check + neighbor rrserver peer-group + neighbor rrserver remote-as 64500 + neighbor rrserver update-source lo + neighbor rrserver bfd + neighbor 192.0.2.3 peer-group rrserver + address-family ipv4 unicast + network 192.0.2.9/32 + network 192.0.2.8/32 route-map rmap + neighbor rrserver activate + neighbor rrserver addpath-tx-all-paths + exit-address-family +! +route-map rmap permit 1 + set ip next-hop 192.0.2.9 +exit diff --git a/tests/topotests/bgp_duplicate_nexthop/r6/isisd.conf b/tests/topotests/bgp_duplicate_nexthop/r6/isisd.conf new file mode 100644 index 0000000000..5126a64858 --- /dev/null +++ b/tests/topotests/bgp_duplicate_nexthop/r6/isisd.conf @@ -0,0 +1,22 @@ +hostname r6 +interface lo + ip router isis 1 + isis passive +! +interface r6-eth1 + ip router isis 1 + isis network point-to-point +! +interface r6-eth2 + ip router isis 1 + isis network point-to-point +! +router isis 1 + net 49.0123.6452.0006.00 + is-type level-2-only + mpls-te on + segment-routing on + segment-routing global-block 16000 17000 + segment-routing node-msd 10 + segment-routing prefix 192.0.2.6/32 index 6 +! diff --git a/tests/topotests/bgp_duplicate_nexthop/r6/zebra.conf b/tests/topotests/bgp_duplicate_nexthop/r6/zebra.conf new file mode 100644 index 0000000000..cda62d7e87 --- /dev/null +++ b/tests/topotests/bgp_duplicate_nexthop/r6/zebra.conf @@ -0,0 +1,20 @@ +log stdout +mpls label dynamic-block 6000 6999 +interface lo + ip address 192.0.2.6/32 +! +interface r6-eth0 + ip address 172.31.13.6/24 +! +interface r6-eth1 + ip address 172.31.5.6/24 + mpls enable +! +interface r6-eth2 + ip address 172.31.6.6/24 + mpls enable +! +interface r6-eth3 + ip address 172.31.22.6/24 +! + diff --git a/tests/topotests/bgp_duplicate_nexthop/test_bgp_duplicate_nexthop.py b/tests/topotests/bgp_duplicate_nexthop/test_bgp_duplicate_nexthop.py new file mode 100644 index 0000000000..955881e6f9 --- /dev/null +++ b/tests/topotests/bgp_duplicate_nexthop/test_bgp_duplicate_nexthop.py @@ -0,0 +1,458 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# +# test_bgp_duplicate_nexthop.py +# +# Copyright 2024 6WIND S.A. +# + +""" + test_bgp_nhg_duplicate_nexthop.py: + Check that the FRR BGP daemon on r1 selects updates with same nexthops + + ++---+----+ +---+----+ +--------+ +| | | + | | +| r1 +----------+ r3 +----------+ r5 + +| | | rr + +-----+ | ++++-+----+ +--------+\ / +--------+ + | \/ + | /\ + | +--------+/ \ +--------+ + | | + +-----+ + + +---------------+ r4 +----------+ r6 + + | | | | + +--------+ +--------+ +""" + +import os +import sys +import json +from functools import partial +import pytest +import functools + +# Save the Current Working Directory to find configuration files. +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +# Import topogen and topotest helpers +from lib import topotest +from lib.common_check import ip_check_path_selection, iproute2_check_path_selection +from lib.common_config import step +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topolog import logger + +# Required to instantiate the topology builder class. + + +pytestmark = [pytest.mark.bgpd] + + +def build_topo(tgen): + "Build function" + + # Create 7 PE routers. + tgen.add_router("r1") + tgen.add_router("r3") + tgen.add_router("r4") + tgen.add_router("r5") + tgen.add_router("r6") + + # switch + switch = tgen.add_switch("s1") + switch.add_link(tgen.gears["r1"]) + + switch = tgen.add_switch("s4") + switch.add_link(tgen.gears["r5"]) + + switch = tgen.add_switch("s5") + switch.add_link(tgen.gears["r6"]) + + switch = tgen.add_switch("s6") + switch.add_link(tgen.gears["r1"]) + switch.add_link(tgen.gears["r3"]) + + switch = tgen.add_switch("s7") + switch.add_link(tgen.gears["r1"]) + switch.add_link(tgen.gears["r4"]) + + switch = tgen.add_switch("s8") + switch.add_link(tgen.gears["r3"]) + switch.add_link(tgen.gears["r5"]) + + switch = tgen.add_switch("s9") + switch.add_link(tgen.gears["r3"]) + switch.add_link(tgen.gears["r6"]) + + switch = tgen.add_switch("s10") + switch.add_link(tgen.gears["r4"]) + switch.add_link(tgen.gears["r6"]) + + switch = tgen.add_switch("s11") + switch.add_link(tgen.gears["r4"]) + switch.add_link(tgen.gears["r5"]) + + switch = tgen.add_switch("s12") + switch.add_link(tgen.gears["r5"]) + + switch = tgen.add_switch("s13") + switch.add_link(tgen.gears["r6"]) + + switch = tgen.add_switch("s14") + switch.add_link(tgen.gears["r1"]) + + +def setup_module(mod): + "Sets up the pytest environment" + tgen = Topogen(build_topo, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + + for rname, router in router_list.items(): + router.load_config( + TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) + ) + router.load_config( + TopoRouter.RD_ISIS, os.path.join(CWD, "{}/isisd.conf".format(rname)) + ) + if rname in ("r1", "r3", "r5", "r6"): + router.load_config( + TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname)) + ) + + # Initialize all routers. + tgen.start_router() + + +def teardown_module(_mod): + "Teardown the pytest environment" + tgen = get_topogen() + + tgen.stop_topology() + + +def check_ipv4_prefix_with_multiple_nexthops(prefix, multipath=True): + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info( + f"Check that {prefix} unicast entry is installed with paths for r5 and r6" + ) + + r5_nh = [ + { + "ip": "192.0.2.5", + "active": True, + "recursive": True, + }, + { + "ip": "172.31.0.3", + "interfaceName": "r1-eth1", + "active": True, + "labels": [ + 16055, + ], + }, + { + "ip": "172.31.2.4", + "interfaceName": "r1-eth2", + "active": True, + "labels": [ + 16055, + ], + }, + ] + + r6_nh = [ + { + "ip": "192.0.2.6", + "active": True, + "recursive": True, + }, + { + "ip": "172.31.0.3", + "interfaceName": "r1-eth1", + "active": True, + "labels": [ + 16006, + ], + }, + { + "ip": "172.31.2.4", + "interfaceName": "r1-eth2", + "active": True, + "labels": [ + 16006, + ], + }, + ] + + expected = { + prefix: [ + { + "prefix": prefix, + "protocol": "bgp", + "metric": 0, + "table": 254, + "nexthops": [], + } + ] + } + for nh in r5_nh: + expected[prefix][0]["nexthops"].append(nh) + if multipath: + for nh in r6_nh: + expected[prefix][0]["nexthops"].append(nh) + + test_func = functools.partial( + ip_check_path_selection, tgen.gears["r1"], prefix, expected + ) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert ( + result is None + ), f"Failed to check that {prefix} uses the IGP label 16055 and 16006" + + +def get_nh_formatted(nexthop, fib=True, duplicate=False): + nh = dict(nexthop) + if duplicate: + nh.update({"duplicate": True}) + if fib: + nh.update({"fib": True}) + return nh + + +def check_ipv4_prefix_recursive_with_multiple_nexthops( + prefix, recursive_nexthop, multipath=True +): + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + logger.info( + f"Check that {prefix} unicast entry is correctly recursive via {recursive_nexthop} with paths for r5 and r6" + ) + + r5_nh = [ + { + "ip": "172.31.0.3", + "interfaceName": "r1-eth1", + "active": True, + "labels": [ + 16055, + ], + }, + { + "ip": "172.31.2.4", + "interfaceName": "r1-eth2", + "active": True, + "labels": [ + 16055, + ], + }, + ] + + r6_nh = [ + { + "ip": "172.31.0.3", + "interfaceName": "r1-eth1", + "active": True, + "labels": [ + 16006, + ], + }, + { + "ip": "172.31.2.4", + "interfaceName": "r1-eth2", + "active": True, + "labels": [ + 16006, + ], + }, + ] + + expected = { + prefix: [ + { + "prefix": prefix, + "protocol": "bgp", + "metric": 0, + "table": 254, + "nexthops": [], + } + ] + } + + recursive_nh = [ + { + "ip": recursive_nexthop, + "active": True, + "recursive": True, + }, + ] + for nh in recursive_nh: + expected[prefix][0]["nexthops"].append(get_nh_formatted(nh, fib=False)) + + for nh in r5_nh: + expected[prefix][0]["nexthops"].append(get_nh_formatted(nh)) + + if multipath: + for nh in r6_nh: + expected[prefix][0]["nexthops"].append(get_nh_formatted(nh)) + + for nh in recursive_nh: + expected[prefix][0]["nexthops"].append( + get_nh_formatted(nh, fib=False, duplicate=True) + ) + + for nh in r5_nh: + expected[prefix][0]["nexthops"].append( + get_nh_formatted(nh, fib=False, duplicate=True) + ) + + for nh in r6_nh: + expected[prefix][0]["nexthops"].append( + get_nh_formatted(nh, fib=False, duplicate=True) + ) + + test_func = functools.partial( + ip_check_path_selection, tgen.gears["r1"], prefix, expected + ) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert ( + result is None + ), f"Failed to check that {prefix} is correctly recursive via {recursive_nexthop}" + + +def check_ipv4_prefix_with_multiple_nexthops_linux(prefix): + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + step( + f"Check that {prefix} unicast entry is installed with paths for r5 and r6 on Linux" + ) + + r5_nh = [ + { + "encap": "mpls", + "dst": "16055", + "gateway": "172.31.0.3", + "dev": "r1-eth1", + }, + { + "encap": "mpls", + "dst": "16055", + "gateway": "172.31.2.4", + "dev": "r1-eth2", + }, + ] + + r6_nh = [ + { + "encap": "mpls", + "dst": "16006", + "gateway": "172.31.0.3", + "dev": "r1-eth1", + }, + { + "encap": "mpls", + "dst": "16006", + "gateway": "172.31.2.4", + "dev": "r1-eth2", + }, + ] + + expected = [ + { + "dst": prefix, + "protocol": "bgp", + "metric": 20, + "nexthops": [], + } + ] + + # only one path + for nh in r5_nh: + expected[0]["nexthops"].append(nh) + for nh in r6_nh: + expected[0]["nexthops"].append(nh) + + test_func = functools.partial( + iproute2_check_path_selection, tgen.routers()["r1"], prefix, expected + ) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert ( + result is None + ), f"Failed to check that {prefix} unicast entry is installed with paths for r5 and r6 on Linux" + + +def test_bgp_ipv4_convergence(): + """ + Check that R1 has received the 192.0.2.9/32 prefix from R5, and R6 + """ + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("Ensure that the 192.0.2.9/32 route is available") + check_ipv4_prefix_with_multiple_nexthops("192.0.2.9/32") + + check_ipv4_prefix_with_multiple_nexthops_linux("192.0.2.9") + + +def test_bgp_ipv4_recursive_routes(): + """ + Check that R1 has received the recursive routes, and duplicate nexthops are in zebra, but are not installed + """ + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + check_ipv4_prefix_recursive_with_multiple_nexthops("192.0.2.8/32", "192.0.2.9") + + check_ipv4_prefix_with_multiple_nexthops_linux("192.0.2.8") + + +def test_bgp_ipv4_recursive_routes_when_no_mpath(): + """ + Unconfigure multipath ibgp + Check that duplicate nexthops are not in zebra + """ + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + tgen.gears["r1"].vtysh_cmd( + """ + configure terminal + router bgp + address family ipv4 unicast + maximum-paths ibgp 1 + """, + isjson=False, + ) + tgen.gears["r1"].vtysh_cmd("clear bgp ipv4 *") + check_ipv4_prefix_with_multiple_nexthops("192.0.2.9/32", multipath=False) + + check_ipv4_prefix_recursive_with_multiple_nexthops( + "192.0.2.8/32", "192.0.2.9", multipath=False + ) + + +def test_memory_leak(): + "Run the memory leak test and report results." + tgen = get_topogen() + if not tgen.is_memleak_enabled(): + pytest.skip("Memory leak test/report is disabled") + + tgen.report_memory_leaks() + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/lib/common_check.py b/tests/topotests/lib/common_check.py new file mode 100644 index 0000000000..be3241fd20 --- /dev/null +++ b/tests/topotests/lib/common_check.py @@ -0,0 +1,48 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC +# +# common_check.py +# +# Copyright 2024 6WIND S.A. + +# +import json +from lib import topotest + + +def ip_check_path_selection(router, ipaddr_str, expected, vrf_name=None): + if vrf_name: + cmdstr = f'show ip route vrf {vrf_name} {ipaddr_str} json' + else: + cmdstr = f'show ip route {ipaddr_str} json' + try: + output = json.loads(router.vtysh_cmd(cmdstr)) + except: + output = {} + + ret = topotest.json_cmp(output, expected) + if ret is None: + num_nh_expected = len(expected[ipaddr_str][0]["nexthops"]) + num_nh_observed = len(output[ipaddr_str][0]["nexthops"]) + if num_nh_expected == num_nh_observed: + return ret + return "{}, prefix {} does not have the correct number of nexthops : observed {}, expected {}".format( + router.name, ipaddr_str, num_nh_observed, num_nh_expected + ) + return ret + + +def iproute2_check_path_selection(router, ipaddr_str, expected, vrf_name=None): + if not topotest.iproute2_is_json_capable(): + return None + + if vrf_name: + cmdstr = f'ip -json route show vrf {vrf_name} {ipaddr_str}' + else: + cmdstr = f'ip -json route show {ipaddr_str}' + try: + output = json.loads(cmdstr) + except: + output = [] + + return topotest.json_cmp(output, expected) From e24ff4c275f0729f75be9f68d08be80ac1e0ec56 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Tue, 11 Jun 2024 11:59:37 +0300 Subject: [PATCH 017/347] ospfd: Drop `interfaceIp` from `show ip ospf neigh json` Deprecated. Now it's under interface field directly: ``` { "interfaces":{ "enp3s0":{ "ifUp":true, "ifIndex":2, "mtuBytes":1500, "bandwidthMbit":100, "ifFlags":"", "ospfEnabled":true, "ipAddress":"192.168.10.19", "ipAddressPrefixlen":24, "ospfIfType":"Broadcast", "localIfUsed":"192.168.10.255", "area":"0.0.0.0", "routerId":"100.100.100.100", "networkType":"POINTOPOINT", "cost":1000, "transmitDelaySecs":1, "state":"Point-To-Point", "priority":1, "opaqueCapable":true, "mcastMemberOspfAllRouters":true, "timerMsecs":10000, "timerDeadSecs":40, "timerWaitSecs":40, "timerRetransmitSecs":5, "timerHelloInMsecs":2924, "nbrCount":0, "nbrAdjacentCount":0, "grHelloDelaySecs":10, "prefixSuppression":false, "nbrFilterPrefixList":"N\/A" } } } ``` Signed-off-by: Donatas Abraitis --- ospfd/ospf_vty.c | 192 +++++++---------------------------------------- 1 file changed, 26 insertions(+), 166 deletions(-) diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index 7cb51976f5..21acd402f4 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -3576,7 +3576,6 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, struct route_node *rn; uint32_t bandwidth = ifp->bandwidth ? ifp->bandwidth : ifp->speed; struct ospf_if_params *params; - json_object *json_ois = NULL; json_object *json_oi = NULL; /* Is interface up? */ @@ -3628,33 +3627,20 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, } } - if (use_json) { - json_ois = json_object_new_object(); - json_object_object_add(json_interface_sub, "interfaceIp", - json_ois); - } - for (rn = route_top(IF_OIFS(ifp)); rn; rn = route_next(rn)) { struct ospf_interface *oi = rn->info; if (oi == NULL) continue; -#if CONFDATE > 20240601 - CPP_NOTICE( - "Use all fields following ospfEnabled from interfaceIp hierarchy") -#endif - if (use_json) json_oi = json_object_new_object(); if (CHECK_FLAG(oi->connected->flags, ZEBRA_IFA_UNNUMBERED)) { - if (use_json) { - json_object_boolean_true_add(json_interface_sub, - "ifUnnumbered"); + if (use_json) json_object_boolean_true_add(json_oi, "ifUnnumbered"); - } else + else vty_out(vty, " This interface is UNNUMBERED,"); } else { struct in_addr dest; @@ -3668,13 +3654,6 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, json_object_int_add(json_interface_sub, "ipAddressPrefixlen", oi->address->prefixlen); - - json_object_string_addf( - json_oi, "ipAddress", "%pI4", - &oi->address->u.prefix4); - json_object_int_add(json_oi, - "ipAddressPrefixlen", - oi->address->prefixlen); } else vty_out(vty, " Internet Address %pFX,", oi->address); @@ -3700,26 +3679,14 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, json_object_string_add(json_interface_sub, "ospfIfType", dstr); - json_object_string_add(json_oi, "ospfIfType", - dstr); - - if (oi->type == OSPF_IFTYPE_VIRTUALLINK) { + if (oi->type == OSPF_IFTYPE_VIRTUALLINK) json_object_string_addf( json_interface_sub, "vlinkPeer", "%pI4", &dest); - - json_object_string_addf(json_oi, - "vlinkPeer", - "%pI4", &dest); - } else { + else json_object_string_addf( json_interface_sub, "localIfUsed", "%pI4", &dest); - - json_object_string_addf(json_oi, - "localIfUsed", - "%pI4", &dest); - } } else vty_out(vty, " %s %pI4,", dstr, &dest); @@ -3728,16 +3695,10 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, json_object_string_add(json_interface_sub, "area", ospf_area_desc_string(oi->area)); - json_object_string_add(json_oi, "area", - ospf_area_desc_string(oi->area)); - - if (OSPF_IF_PARAM(oi, mtu_ignore)) { - json_object_boolean_true_add( - json_oi, "mtuMismatchDetect"); + if (OSPF_IF_PARAM(oi, mtu_ignore)) json_object_boolean_true_add( json_interface_sub, "mtuMismatchDetect"); - } json_object_string_addf(json_interface_sub, "routerId", "%pI4", &ospf->router_id); @@ -3754,18 +3715,6 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, oi->state, NULL)); json_object_int_add(json_interface_sub, "priority", PRIORITY(oi)); - - json_object_string_addf(json_oi, "routerId", "%pI4", - &ospf->router_id); - json_object_string_add(json_oi, "networkType", - ospf_network_type_str[oi->type]); - json_object_int_add(json_oi, "cost", oi->output_cost); - json_object_int_add(json_oi, "transmitDelaySecs", - OSPF_IF_PARAM(oi, transmit_delay)); - json_object_string_add(json_oi, "state", - lookup_msg(ospf_ism_state_msg, - oi->state, NULL)); - json_object_int_add(json_oi, "priority", PRIORITY(oi)); json_object_boolean_add( json_interface_sub, "opaqueCapable", OSPF_IF_PARAM(oi, opaque_capable)); @@ -3809,13 +3758,6 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, json_interface_sub, "drAddress", "%pI4", &nbr->address.u.prefix4); - - json_object_string_addf( - json_oi, "drId", "%pI4", - &nbr->router_id); - json_object_string_addf( - json_oi, "drAddress", "%pI4", - &nbr->address.u.prefix4); } else { vty_out(vty, " Designated Router (ID) %pI4", @@ -3841,13 +3783,6 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, json_interface_sub, "bdrAddress", "%pI4", &nbr->address.u.prefix4); - - json_object_string_addf( - json_oi, "bdrId", "%pI4", - &nbr->router_id); - json_object_string_addf( - json_oi, "bdrAddress", "%pI4", - &nbr->address.u.prefix4); } else { vty_out(vty, " Backup Designated Router (ID) %pI4,", @@ -3863,43 +3798,28 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, if (oi->params && ntohl(oi->params->network_lsa_seqnum) != OSPF_INITIAL_SEQUENCE_NUMBER) { - if (use_json) { + if (use_json) json_object_int_add( json_interface_sub, "networkLsaSequence", ntohl(oi->params->network_lsa_seqnum)); - - json_object_int_add( - json_oi, "networkLsaSequence", - ntohl(oi->params->network_lsa_seqnum)); - } else { + else vty_out(vty, " Saved Network-LSA sequence number 0x%x\n", ntohl(oi->params->network_lsa_seqnum)); - } } if (use_json) { if (OI_MEMBER_CHECK(oi, MEMBER_ALLROUTERS) || OI_MEMBER_CHECK(oi, MEMBER_DROUTERS)) { - if (OI_MEMBER_CHECK(oi, MEMBER_ALLROUTERS)) { + if (OI_MEMBER_CHECK(oi, MEMBER_ALLROUTERS)) json_object_boolean_true_add( json_interface_sub, "mcastMemberOspfAllRouters"); - - json_object_boolean_true_add( - json_oi, - "mcastMemberOspfAllRouters"); - } - if (OI_MEMBER_CHECK(oi, MEMBER_DROUTERS)) { + if (OI_MEMBER_CHECK(oi, MEMBER_DROUTERS)) json_object_boolean_true_add( json_interface_sub, "mcastMemberOspfDesignatedRouters"); - - json_object_boolean_true_add( - json_oi, - "mcastMemberOspfDesignatedRouters"); - } } } else { vty_out(vty, " Multicast group memberships:"); @@ -3915,23 +3835,14 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, } if (use_json) { - if (OSPF_IF_PARAM(oi, fast_hello) == 0) { + if (OSPF_IF_PARAM(oi, fast_hello) == 0) json_object_int_add( json_interface_sub, "timerMsecs", OSPF_IF_PARAM(oi, v_hello) * 1000); - - json_object_int_add(json_oi, "timerMsecs", - OSPF_IF_PARAM(oi, v_hello) * - 1000); - } else { + else json_object_int_add( json_interface_sub, "timerMsecs", 1000 / OSPF_IF_PARAM(oi, fast_hello)); - - json_object_int_add( - json_oi, "timerMsecs", - 1000 / OSPF_IF_PARAM(oi, fast_hello)); - } json_object_int_add(json_interface_sub, "timerDeadSecs", OSPF_IF_PARAM(oi, v_wait)); json_object_int_add(json_interface_sub, "timerWaitSecs", @@ -3939,14 +3850,6 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, json_object_int_add( json_interface_sub, "timerRetransmitSecs", OSPF_IF_PARAM(oi, retransmit_interval)); - - json_object_int_add(json_oi, "timerDeadSecs", - OSPF_IF_PARAM(oi, v_wait)); - json_object_int_add(json_oi, "timerWaitSecs", - OSPF_IF_PARAM(oi, v_wait)); - json_object_int_add( - json_oi, "timerRetransmitSecs", - OSPF_IF_PARAM(oi, retransmit_interval)); } else { vty_out(vty, " Timer intervals configured,"); vty_out(vty, " Hello "); @@ -3975,23 +3878,17 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, json_object_int_add(json_interface_sub, "timerHelloInMsecs", time_store); - json_object_int_add(json_oi, - "timerHelloInMsecs", - time_store); } else vty_out(vty, " Hello due in %s\n", ospf_timer_dump(oi->t_hello, timebuf, sizeof(timebuf))); } else /* passive-interface is set */ { - if (use_json) { + if (use_json) json_object_boolean_true_add( json_interface_sub, "timerPassiveIface"); - - json_object_boolean_true_add( - json_oi, "timerPassiveIface"); - } else + else vty_out(vty, " No Hellos (Passive interface)\n"); } @@ -4002,11 +3899,6 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, json_object_int_add(json_interface_sub, "nbrAdjacentCount", ospf_nbr_count(oi, NSM_Full)); - - json_object_int_add(json_oi, "nbrCount", - ospf_nbr_count(oi, 0)); - json_object_int_add(json_oi, "nbrAdjacentCount", - ospf_nbr_count(oi, NSM_Full)); } else vty_out(vty, " Neighbor Count is %d, Adjacent neighbor count is %d\n", @@ -4016,14 +3908,11 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, params = IF_DEF_PARAMS(ifp); if (params && OSPF_IF_PARAM_CONFIGURED(params, v_gr_hello_delay)) { - if (use_json) { + if (use_json) json_object_int_add(json_interface_sub, "grHelloDelaySecs", params->v_gr_hello_delay); - - json_object_int_add(json_oi, "grHelloDelaySecs", - params->v_gr_hello_delay); - } else + else vty_out(vty, " Graceful Restart hello delay: %us\n", params->v_gr_hello_delay); @@ -4031,19 +3920,14 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, ospf_interface_bfd_show(vty, ifp, json_interface_sub); - if (use_json) { + if (use_json) json_object_boolean_add(json_interface_sub, "prefixSuppression", OSPF_IF_PARAM(oi, prefix_suppression)); - json_object_boolean_add(json_oi, "prefixSuppression", - OSPF_IF_PARAM(oi, - prefix_suppression)); - } else { - if (OSPF_IF_PARAM(oi, prefix_suppression)) - vty_out(vty, - " Suppress advertisement of interface IP prefix\n"); - } + else if (OSPF_IF_PARAM(oi, prefix_suppression)) + vty_out(vty, + " Suppress advertisement of interface IP prefix\n"); /* OSPF Authentication information */ ospf_interface_auth_show(vty, oi, json_interface_sub, use_json); @@ -4052,63 +3936,39 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, /* Point-to-Multipoint Interface options. */ if (oi->type == OSPF_IFTYPE_POINTOMULTIPOINT) { - if (use_json) { + if (use_json) json_object_boolean_add(json_interface_sub, "p2mpDelayReflood", oi->p2mp_delay_reflood); - - json_object_boolean_add(json_oi, - "p2mpDelayReflood", - oi->p2mp_delay_reflood); - } else { + else vty_out(vty, " %sDelay reflooding LSAs received on P2MP interface\n", oi->p2mp_delay_reflood ? "" : "Don't "); - } - if (use_json) { + if (use_json) json_object_boolean_add(json_interface_sub, "p2mpNonBroadcast", oi->p2mp_non_broadcast); - - json_object_boolean_add(json_oi, - "p2mpNonBroadcast", - oi->p2mp_non_broadcast); - } else { + else vty_out(vty, " P2MP interface does %ssupport broadcast\n", oi->p2mp_non_broadcast ? "not " : ""); - } } - /* Add ospf_interface object to main json blob using SIP as key - */ - if (use_json) - json_object_object_addf(json_ois, json_oi, "%pI4", - &oi->address->u.prefix4); - if (oi->nbr_filter) { - if (use_json) { + if (use_json) json_object_string_add(json_interface_sub, "nbrFilterPrefixList", prefix_list_name( oi->nbr_filter)); - json_object_string_add(json_oi, - "nbrFilterPrefixList", - prefix_list_name( - oi->nbr_filter)); - } else + else vty_out(vty, " Neighbor filter prefix-list: %s\n", prefix_list_name(oi->nbr_filter)); } else { - if (use_json) { + if (use_json) json_object_string_add(json_interface_sub, "nbrFilterPrefixList", "N/A"); - json_object_string_add(json_oi, - "nbrFilterPrefixList", - "N/A"); - } } } } From ad1244f88a5ffa0bebcc95d70481865a1ea3e57b Mon Sep 17 00:00:00 2001 From: anlan_cs Date: Sat, 8 Jun 2024 23:38:05 +0800 Subject: [PATCH 018/347] yang: fix wrong check for isis metric style Before: ``` anlan(config)# route isis ix anlan(config-router)# metric-style transition ... anlan(config-if)# isis metric 200 % Configuration failed. Error type: validation Error description: YANG error(s): Path: Data location "/frr-interface:lib/interface[name='x']/frr-isisd:isis/metric/level-1". Error: Must condition ". < 64 or /frr-isisd:isis/instance[area-tag = current()/../../area-tag]/metric-style = 'wide' or not(/frr-isisd:isis/instance[area-tag = current()/../../area-tag]/metric-style)" not satisfied. Path: Data location "/frr-interface:lib/interface[name='x']/frr-isisd:isis/metric/level-2". Error: Must condition ". < 64 or /frr-isisd:isis/instance[area-tag = current()/../../area-tag]/metric-style = 'wide' or not(/frr-isisd:isis/instance[area-tag = current()/../../area-tag]/metric-style)" not satisfied ``` After: ``` anlan(config)# route isis ix anlan(config-router)# metric-style transition ... anlan(config-if)# isis metric 200 anlan(config-if)# ``` Signed-off-by: anlan_cs --- yang/frr-isisd.yang | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/yang/frr-isisd.yang b/yang/frr-isisd.yang index d1a08fa976..60914b0be9 100644 --- a/yang/frr-isisd.yang +++ b/yang/frr-isisd.yang @@ -685,7 +685,7 @@ module frr-isisd { type uint32 { range "0..16777215"; } - must ". < 64 or /frr-isisd:isis/instance[area-tag = current()/../../area-tag]/metric-style = 'wide' or not(/frr-isisd:isis/instance[area-tag = current()/../../area-tag]/metric-style)"; + must ". < 64 or not(/frr-isisd:isis/instance[area-tag = current()/../../area-tag]/metric-style) or /frr-isisd:isis/instance[area-tag = current()/../../area-tag]/metric-style != 'narrow'"; default "10"; description "Default level-1 metric for this IS-IS circuit."; @@ -695,7 +695,7 @@ module frr-isisd { type uint32 { range "0..16777215"; } - must ". < 64 or /frr-isisd:isis/instance[area-tag = current()/../../area-tag]/metric-style = 'wide' or not(/frr-isisd:isis/instance[area-tag = current()/../../area-tag]/metric-style)"; + must ". < 64 or not(/frr-isisd:isis/instance[area-tag = current()/../../area-tag]/metric-style) or /frr-isisd:isis/instance[area-tag = current()/../../area-tag]/metric-style != 'narrow'"; default "10"; description "Default level-2 metric for this IS-IS circuit."; From 3cc01bb00b85d9ff74c00130dadeb53913f02e79 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Tue, 11 Jun 2024 15:48:23 +0300 Subject: [PATCH 019/347] tests: Drop `interfaceIp` from OSPF tests Deprecated. Signed-off-by: Donatas Abraitis --- .../ospf_p2mp/test_ospf_p2mp_broadcast.py | 27 ------------------- .../ospf_p2mp/test_ospf_p2mp_non_broadcast.py | 16 ----------- 2 files changed, 43 deletions(-) diff --git a/tests/topotests/ospf_p2mp/test_ospf_p2mp_broadcast.py b/tests/topotests/ospf_p2mp/test_ospf_p2mp_broadcast.py index 1f0f87959a..791d7cb09b 100644 --- a/tests/topotests/ospf_p2mp/test_ospf_p2mp_broadcast.py +++ b/tests/topotests/ospf_p2mp/test_ospf_p2mp_broadcast.py @@ -140,22 +140,6 @@ def verify_p2mp_interface(tgen, router, nbr_cnt, nbr_adj_cnt, nbr_filter): "interfaces": { "r1-eth0": { "ospfEnabled": True, - "interfaceIp": { - "10.1.0.1": { - "ipAddress": "10.1.0.1", - "ipAddressPrefixlen": 24, - "ospfIfType": "Broadcast", - "routerId": "1.1.1.1", - "networkType": "POINTOMULTIPOINT", - "cost": 10, - "state": "Point-To-Point", - "nbrCount": nbr_cnt, - "nbrAdjacentCount": nbr_adj_cnt, - "prefixSuppression": False, - "p2mpDelayReflood": False, - "nbrFilterPrefixList": nbr_filter, - } - }, "ipAddress": "10.1.0.1", "ipAddressPrefixlen": 24, "ospfIfType": "Broadcast", @@ -201,17 +185,6 @@ def verify_non_p2mp_interface(tgen): "interfaces": { "r1-eth0": { "ospfEnabled": True, - "interfaceIp": { - "10.1.0.1": { - "ipAddress": "10.1.0.1", - "ipAddressPrefixlen": 24, - "ospfIfType": "Broadcast", - "routerId": "1.1.1.1", - "networkType": "BROADCAST", - "cost": 10, - "prefixSuppression": False, - } - }, "ipAddress": "10.1.0.1", "ipAddressPrefixlen": 24, "ospfIfType": "Broadcast", diff --git a/tests/topotests/ospf_p2mp/test_ospf_p2mp_non_broadcast.py b/tests/topotests/ospf_p2mp/test_ospf_p2mp_non_broadcast.py index 175dca74e7..f100aa624a 100644 --- a/tests/topotests/ospf_p2mp/test_ospf_p2mp_non_broadcast.py +++ b/tests/topotests/ospf_p2mp/test_ospf_p2mp_non_broadcast.py @@ -144,22 +144,6 @@ def verify_p2mp_interface(tgen, router, nbr_cnt, nbr_adj_cnt, non_broadcast): "interfaces": { "r1-eth0": { "ospfEnabled": True, - "interfaceIp": { - "10.1.0.1": { - "ipAddress": "10.1.0.1", - "ipAddressPrefixlen": 24, - "ospfIfType": "Broadcast", - "routerId": "1.1.1.1", - "networkType": "POINTOMULTIPOINT", - "cost": 10, - "state": "Point-To-Point", - "nbrCount": nbr_cnt, - "nbrAdjacentCount": nbr_adj_cnt, - "prefixSuppression": False, - "p2mpDelayReflood": False, - "p2mpNonBroadcast": non_broadcast, - } - }, "ipAddress": "10.1.0.1", "ipAddressPrefixlen": 24, "ospfIfType": "Broadcast", From 59f5dd686a324f888602fa4a56f6da90e844103c Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Tue, 11 Jun 2024 11:40:40 +0300 Subject: [PATCH 020/347] tests: Check if BFD notification is sent and session remains in down state Signed-off-by: Donatas Abraitis --- .../r1/bfdd.conf | 4 + .../r1/bgpd.conf | 2 +- .../test_bgp_bfd_down_cease_notification.py | 3 + ...gp_bfd_down_cease_notification_shutdown.py | 122 ++++++++++++++++++ 4 files changed, 130 insertions(+), 1 deletion(-) create mode 100644 tests/topotests/bgp_bfd_down_cease_notification/test_bgp_bfd_down_cease_notification_shutdown.py diff --git a/tests/topotests/bgp_bfd_down_cease_notification/r1/bfdd.conf b/tests/topotests/bgp_bfd_down_cease_notification/r1/bfdd.conf index 0ae384eb53..1033b27c56 100644 --- a/tests/topotests/bgp_bfd_down_cease_notification/r1/bfdd.conf +++ b/tests/topotests/bgp_bfd_down_cease_notification/r1/bfdd.conf @@ -1,5 +1,9 @@ bfd + profile r1 + exit + ! peer 192.168.255.2 interface r1-eth0 + profile r1 exit ! exit diff --git a/tests/topotests/bgp_bfd_down_cease_notification/r1/bgpd.conf b/tests/topotests/bgp_bfd_down_cease_notification/r1/bgpd.conf index e855f75c20..58a90d1a49 100644 --- a/tests/topotests/bgp_bfd_down_cease_notification/r1/bgpd.conf +++ b/tests/topotests/bgp_bfd_down_cease_notification/r1/bgpd.conf @@ -3,7 +3,7 @@ router bgp 65001 neighbor 192.168.255.2 remote-as external neighbor 192.168.255.2 timers 3 10 neighbor 192.168.255.2 timers connect 1 - neighbor 192.168.255.2 bfd + neighbor 192.168.255.2 bfd profile r1 neighbor 192.168.255.2 passive address-family ipv4 redistribute connected diff --git a/tests/topotests/bgp_bfd_down_cease_notification/test_bgp_bfd_down_cease_notification.py b/tests/topotests/bgp_bfd_down_cease_notification/test_bgp_bfd_down_cease_notification.py index 00142981c5..3be3430007 100644 --- a/tests/topotests/bgp_bfd_down_cease_notification/test_bgp_bfd_down_cease_notification.py +++ b/tests/topotests/bgp_bfd_down_cease_notification/test_bgp_bfd_down_cease_notification.py @@ -89,6 +89,9 @@ def _bgp_bfd_down_notification(): "192.168.255.1": { "lastNotificationReason": "Cease/BFD Down", "lastNotificationHardReset": True, + "peerBfdInfo": { + "status": "Up", + }, } } return topotest.json_cmp(output, expected) diff --git a/tests/topotests/bgp_bfd_down_cease_notification/test_bgp_bfd_down_cease_notification_shutdown.py b/tests/topotests/bgp_bfd_down_cease_notification/test_bgp_bfd_down_cease_notification_shutdown.py new file mode 100644 index 0000000000..5ffeed5033 --- /dev/null +++ b/tests/topotests/bgp_bfd_down_cease_notification/test_bgp_bfd_down_cease_notification_shutdown.py @@ -0,0 +1,122 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# +# bgp_bfd_down_cease_notification_shutdown.py +# +# Copyright (c) 2024 by +# Donatas Abraitis +# + +""" +Check if Cease/BFD Down notification message is sent/received +when the BFD is down (administratively). +""" + +import os +import sys +import json +import pytest +import functools + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.common_config import kill_router_daemons, step + +pytestmark = [pytest.mark.bfdd, pytest.mark.bgpd] + + +def build_topo(tgen): + for routern in range(1, 3): + tgen.add_router("r{}".format(routern)) + + switch = tgen.add_switch("s1") + switch.add_link(tgen.gears["r1"]) + switch.add_link(tgen.gears["r2"]) + + +def setup_module(mod): + tgen = Topogen(build_topo, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + + for i, (rname, router) in enumerate(router_list.items(), 1): + router.load_config( + TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) + ) + router.load_config( + TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname)) + ) + router.load_config( + TopoRouter.RD_BFD, os.path.join(CWD, "{}/bfdd.conf".format(rname)) + ) + + tgen.start_router() + + +def teardown_module(mod): + tgen = get_topogen() + tgen.stop_topology() + + +def test_bgp_bfd_down_notification_shutdown(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.gears["r1"] + r2 = tgen.gears["r2"] + + def _bgp_converge(): + output = json.loads(r2.vtysh_cmd("show ip bgp neighbor 192.168.255.1 json")) + expected = { + "192.168.255.1": { + "bgpState": "Established", + "addressFamilyInfo": {"ipv4Unicast": {"acceptedPrefixCounter": 2}}, + "peerBfdInfo": {"status": "Up"}, + } + } + return topotest.json_cmp(output, expected) + + def _bgp_bfd_down_notification(): + output = json.loads(r2.vtysh_cmd("show ip bgp neighbor 192.168.255.1 json")) + expected = { + "192.168.255.1": { + "lastNotificationReason": "Cease/BFD Down", + "lastNotificationHardReset": True, + "peerBfdInfo": { + "status": "Down", + }, + } + } + return topotest.json_cmp(output, expected) + + step("Initial BGP converge") + test_func = functools.partial(_bgp_converge) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Failed to see BGP convergence on R2" + + r1.vtysh_cmd( + """ + configure + bfd + profile r1 + shutdown + """ + ) + + step("Check if we received Cease/BFD Down notification message") + test_func = functools.partial(_bgp_bfd_down_notification) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Failed to see BGP Cease/BFD Down notification message on R2" + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) From ae1f3a48513f51c540788a090b05c24750665f55 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Tue, 11 Jun 2024 11:41:53 +0300 Subject: [PATCH 021/347] bgpd: Keep last notification's state about hard reset When we receive a hard-reset notification, we always show it if it was a hard, or not. For sending side, we missed that. Let's display it too. Signed-off-by: Donatas Abraitis --- bgpd/bgp_packet.c | 1 + 1 file changed, 1 insertion(+) diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index 3f38790cbd..8a4453f124 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -982,6 +982,7 @@ static void bgp_notify_send_internal(struct peer_connection *connection, peer->notify.code = bgp_notify.code; peer->notify.subcode = bgp_notify.subcode; peer->notify.length = bgp_notify.length; + peer->notify.hard_reset = hard_reset; if (bgp_notify.length && data) { bgp_notify.data = XMALLOC(MTYPE_BGP_NOTIFICATION, From 3dad09b228e3c4a4ffa6da260fadda6762a77c58 Mon Sep 17 00:00:00 2001 From: Christian Hopps Date: Tue, 11 Jun 2024 05:08:49 -0400 Subject: [PATCH 022/347] mgmtd: add native session-req (create/delete) messages This addition allows for a limited native-message-only front-end interaction. Signed-off-by: Christian Hopps --- lib/mgmt_msg_native.c | 27 +++++++++ lib/mgmt_msg_native.h | 45 ++++++++++++++- mgmtd/mgmt_fe_adapter.c | 124 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 195 insertions(+), 1 deletion(-) diff --git a/lib/mgmt_msg_native.c b/lib/mgmt_msg_native.c index d0a0b72189..b85c7d1b61 100644 --- a/lib/mgmt_msg_native.c +++ b/lib/mgmt_msg_native.c @@ -19,6 +19,33 @@ DEFINE_MTYPE(MSG_NATIVE, MSG_NATIVE_EDIT, "native edit msg"); DEFINE_MTYPE(MSG_NATIVE, MSG_NATIVE_EDIT_REPLY, "native edit reply msg"); DEFINE_MTYPE(MSG_NATIVE, MSG_NATIVE_RPC, "native RPC msg"); DEFINE_MTYPE(MSG_NATIVE, MSG_NATIVE_RPC_REPLY, "native RPC reply msg"); +DEFINE_MTYPE(MSG_NATIVE, MSG_NATIVE_SESSION_REQ, "native session-req msg"); +DEFINE_MTYPE(MSG_NATIVE, MSG_NATIVE_SESSION_REPLY, "native session-reply msg"); + + +size_t mgmt_msg_min_sizes[] = { + [MGMT_MSG_CODE_ERROR] = sizeof(struct mgmt_msg_error), + [MGMT_MSG_CODE_GET_TREE] = sizeof(struct mgmt_msg_get_tree), + [MGMT_MSG_CODE_TREE_DATA] = sizeof(struct mgmt_msg_tree_data), + [MGMT_MSG_CODE_GET_DATA] = sizeof(struct mgmt_msg_get_data), + [MGMT_MSG_CODE_NOTIFY] = sizeof(struct mgmt_msg_notify_data), + [MGMT_MSG_CODE_EDIT] = sizeof(struct mgmt_msg_edit), + [MGMT_MSG_CODE_EDIT_REPLY] = sizeof(struct mgmt_msg_edit_reply), + [MGMT_MSG_CODE_RPC] = sizeof(struct mgmt_msg_rpc), + [MGMT_MSG_CODE_RPC_REPLY] = sizeof(struct mgmt_msg_rpc_reply), + [MGMT_MSG_CODE_NOTIFY_SELECT] = sizeof(struct mgmt_msg_notify_select), + [MGMT_MSG_CODE_SESSION_REQ] = sizeof(struct mgmt_msg_session_req), + [MGMT_MSG_CODE_SESSION_REPLY] = sizeof(struct mgmt_msg_session_reply), +}; +size_t nmgmt_msg_min_sizes = sizeof(mgmt_msg_min_sizes) / + sizeof(*mgmt_msg_min_sizes); + +size_t mgmt_msg_get_min_size(uint code) +{ + if (code >= nmgmt_msg_min_sizes) + return 0; + return mgmt_msg_min_sizes[code]; +} int vmgmt_msg_native_send_error(struct msg_conn *conn, uint64_t sess_or_txn_id, uint64_t req_id, bool short_circuit_ok, diff --git a/lib/mgmt_msg_native.h b/lib/mgmt_msg_native.h index e61346e6e5..76a52658cd 100644 --- a/lib/mgmt_msg_native.h +++ b/lib/mgmt_msg_native.h @@ -163,6 +163,8 @@ DECLARE_MTYPE(MSG_NATIVE_EDIT); DECLARE_MTYPE(MSG_NATIVE_EDIT_REPLY); DECLARE_MTYPE(MSG_NATIVE_RPC); DECLARE_MTYPE(MSG_NATIVE_RPC_REPLY); +DECLARE_MTYPE(MSG_NATIVE_SESSION_REQ); +DECLARE_MTYPE(MSG_NATIVE_SESSION_REPLY); /* * Native message codes @@ -177,6 +179,8 @@ DECLARE_MTYPE(MSG_NATIVE_RPC_REPLY); #define MGMT_MSG_CODE_RPC 7 /* Public API */ #define MGMT_MSG_CODE_RPC_REPLY 8 /* Public API */ #define MGMT_MSG_CODE_NOTIFY_SELECT 9 /* Public API */ +#define MGMT_MSG_CODE_SESSION_REQ 10 /* Public API */ +#define MGMT_MSG_CODE_SESSION_REPLY 11 /* Public API */ /* * Datastores @@ -434,7 +438,7 @@ _Static_assert(sizeof(struct mgmt_msg_rpc_reply) == * to the front-end client. * * @selectors: the xpath prefixes to selectors notifications through. - * @repalce: if true replace existing selectors with `selectors`. + * @replace: if true replace existing selectors with `selectors`. */ struct mgmt_msg_notify_select { struct mgmt_msg_header; @@ -448,12 +452,51 @@ _Static_assert(sizeof(struct mgmt_msg_notify_select) == offsetof(struct mgmt_msg_notify_select, selectors), "Size mismatch"); +/** + * struct mgmt_msg_session_req - Create or delete a front-end session. + * + * @refer_id: Zero for create, otherwise the session-id to delete. + * @req_id: For create will use as client-id. + * @client_name: For first session request the client name, otherwise empty. + */ +struct mgmt_msg_session_req { + struct mgmt_msg_header; + uint8_t resv2[8]; /* bug in compiler produces error w/o this */ + + alignas(8) char client_name[]; +}; + +_Static_assert(sizeof(struct mgmt_msg_session_req) == + offsetof(struct mgmt_msg_session_req, client_name), + "Size mismatch"); + +/** + * struct mgmt_msg_session_reply - Reply to session request message. + * + * @created: true if this is a reply to a create request, otherwise 0. + * @refer_id: The session-id for the action (create or delete) just taken. + */ +struct mgmt_msg_session_reply { + struct mgmt_msg_header; + uint8_t created; + uint8_t resv2[7]; +}; + /* * Validate that the message ends in a NUL terminating byte */ #define MGMT_MSG_VALIDATE_NUL_TERM(msgp, len) \ ((len) >= sizeof(*msgp) + 1 && ((char *)msgp)[(len)-1] == 0) +/** + * mgmt_msg_get_min_size() - Get minimum message size given the type + * @code: The type of the message (MGMT_MSG_CODE_*) + * + * Return: + * The minimum size of a message of the given type or 0 if the message + * code is unknown. + */ +size_t mgmt_msg_get_min_size(uint code); /** * Send a native message error to the other end of the connection. diff --git a/mgmtd/mgmt_fe_adapter.c b/mgmtd/mgmt_fe_adapter.c index a076dc72f9..5f53c928a4 100644 --- a/mgmtd/mgmt_fe_adapter.c +++ b/mgmtd/mgmt_fe_adapter.c @@ -490,6 +490,26 @@ static int fe_adapter_send_get_reply(struct mgmt_fe_session_ctx *session, return fe_adapter_send_msg(session->adapter, &fe_msg, false); } +static int fe_adapter_conn_send_error(struct msg_conn *conn, + uint64_t session_id, uint64_t req_id, + bool short_circuit_ok, int16_t error, + const char *errfmt, ...) PRINTFRR(6, 7); +static int fe_adapter_conn_send_error(struct msg_conn *conn, uint64_t session_id, + uint64_t req_id, bool short_circuit_ok, + int16_t error, const char *errfmt, ...) +{ + va_list ap; + int ret; + + va_start(ap, errfmt); + + ret = vmgmt_msg_native_send_error(conn, session_id, req_id, + short_circuit_ok, error, errfmt, ap); + va_end(ap); + + return ret; +} + static int fe_adapter_send_error(struct mgmt_fe_session_ctx *session, uint64_t req_id, bool short_circuit_ok, int16_t error, const char *errfmt, ...) @@ -1170,6 +1190,88 @@ static int fe_adapter_send_edit_reply(struct mgmt_fe_session_ctx *session, return ret; } +static int +fe_adapter_native_send_session_reply(struct mgmt_fe_client_adapter *adapter, + uint64_t req_id, uint64_t session_id, + bool created) +{ + struct mgmt_msg_session_reply *msg; + int ret; + + msg = mgmt_msg_native_alloc_msg(struct mgmt_msg_session_reply, 0, + MTYPE_MSG_NATIVE_SESSION_REPLY); + msg->refer_id = session_id; + msg->req_id = req_id; + msg->code = MGMT_MSG_CODE_SESSION_REPLY; + msg->created = created; + + __dbg("Sending session-reply from adapter %s to session-id %" PRIu64 + " req-id %" PRIu64 " len %u", + adapter->name, session_id, req_id, + mgmt_msg_native_get_msg_len(msg)); + + ret = fe_adapter_send_native_msg(adapter, msg, + mgmt_msg_native_get_msg_len(msg), + false); + mgmt_msg_native_free_msg(msg); + + return ret; +} + +/** + * fe_adapter_handle_session_req() - Handle a session-req message from a FE client. + * @msg_raw: the message data. + * @msg_len: the length of the message data. + */ +static void fe_adapter_handle_session_req(struct mgmt_fe_client_adapter *adapter, + void *__msg, size_t msg_len) +{ + struct mgmt_msg_session_req *msg = __msg; + struct mgmt_fe_session_ctx *session; + uint64_t client_id; + + __dbg("Got session-req creating: %u for refer-id %" PRIu64 " from '%s'", + msg->refer_id == 0, msg->refer_id, adapter->name); + + if (msg->refer_id) { + uint64_t session_id = msg->refer_id; + + session = mgmt_session_id2ctx(session_id); + if (!session) { + fe_adapter_conn_send_error( + adapter->conn, session_id, msg->req_id, false, + -EINVAL, + "No session to delete for session-id: %" PRIu64, + session_id); + return; + } + fe_adapter_native_send_session_reply(adapter, msg->req_id, + session_id, false); + mgmt_fe_cleanup_session(&session); + return; + } + + client_id = msg->req_id; + + /* See if we have a client name to register */ + if (msg_len > sizeof(*msg)) { + if (!MGMT_MSG_VALIDATE_NUL_TERM(msg, msg_len)) { + fe_adapter_conn_send_error( + adapter->conn, client_id, msg->req_id, false, + -EINVAL, + "Corrupt session-req message rcvd from client-id: %" PRIu64, + client_id); + return; + } + __dbg("Set client-name to '%s'", msg->client_name); + strlcpy(adapter->name, msg->client_name, sizeof(adapter->name)); + } + + session = mgmt_fe_create_session(adapter, client_id); + fe_adapter_native_send_session_reply(adapter, client_id, + session->session_id, true); +} + /** * fe_adapter_handle_get_data() - Handle a get-tree message from a FE client. * @session: the client session. @@ -1529,6 +1631,28 @@ static void fe_adapter_handle_native_msg(struct mgmt_fe_client_adapter *adapter, size_t msg_len) { struct mgmt_fe_session_ctx *session; + size_t min_size = mgmt_msg_get_min_size(msg->code); + + if (msg_len < min_size) { + if (!min_size) + __log_err("adapter %s: recv msg refer-id %" PRIu64 + " unknown message type %u", + adapter->name, msg->refer_id, msg->code); + else + __log_err("adapter %s: recv msg refer-id %" PRIu64 + " short (%zu<%zu) msg for type %u", + adapter->name, msg->refer_id, msg_len, + min_size, msg->code); + return; + } + + if (msg->code == MGMT_MSG_CODE_SESSION_REQ) { + __dbg("adapter %s: session-id %" PRIu64 + " received SESSION_REQ message", + adapter->name, msg->refer_id); + fe_adapter_handle_session_req(adapter, msg, msg_len); + return; + } session = mgmt_session_id2ctx(msg->refer_id); if (!session) { From 27e369487eb602b75ea353e8c21333bd83032a86 Mon Sep 17 00:00:00 2001 From: Christian Hopps Date: Tue, 11 Jun 2024 10:26:08 -0400 Subject: [PATCH 023/347] tests: add native session-req/reply support to fe_client.py Use this to test new native message format for creating sessions. Signed-off-by: Christian Hopps --- tests/topotests/lib/fe_client.py | 61 +++++++++++++++++------- tests/topotests/mgmt_notif/test_notif.py | 2 +- 2 files changed, 46 insertions(+), 17 deletions(-) diff --git a/tests/topotests/lib/fe_client.py b/tests/topotests/lib/fe_client.py index 019b3239ca..d61bc850b4 100755 --- a/tests/topotests/lib/fe_client.py +++ b/tests/topotests/lib/fe_client.py @@ -84,6 +84,11 @@ MSG_NOTIFY_SELECT_FMT = "=B7x" +MSG_SESSION_REQ_FMT = "=8x" + +MSG_SESSION_REPLY_FMT = "=B7x" +SESSION_REPLY_FIELD_CREATED = 0 + # # Native message codes # @@ -93,6 +98,8 @@ MSG_CODE_GET_DATA = 3 MSG_CODE_NOTIFY = 4 MSG_CODE_NOTIFY_SELECT = 9 +MSG_CODE_SESSION_REQ = 10 +MSG_CODE_SESSION_REPLY = 11 msg_native_formats = { MSG_CODE_ERROR: MSG_ERROR_FMT, @@ -101,6 +108,8 @@ MSG_CODE_GET_DATA: MSG_GET_DATA_FMT, MSG_CODE_NOTIFY: MSG_NOTIFY_FMT, MSG_CODE_NOTIFY_SELECT: MSG_NOTIFY_SELECT_FMT, + MSG_CODE_SESSION_REQ: MSG_SESSION_REQ_FMT, + MSG_CODE_SESSION_REPLY: MSG_SESSION_REPLY_FMT, } @@ -183,27 +192,44 @@ class Session: client_id = 1 - def __init__(self, sock): + def __init__(self, sock, use_protobuf): self.sock = sock self.next_req_id = 1 - req = mgmt_pb2.FeMessage() - req.register_req.client_name = "test-client" - self.send_pb_msg(req) - logging.debug("Sent FeRegisterReq: %s", req) + if use_protobuf: + req = mgmt_pb2.FeMessage() + req.register_req.client_name = "test-client" + self.send_pb_msg(req) + logging.debug("Sent FeRegisterReq: %s", req) - req = mgmt_pb2.FeMessage() - req.session_req.create = 1 - req.session_req.client_conn_id = Session.client_id - Session.client_id += 1 - self.send_pb_msg(req) - logging.debug("Sent FeSessionReq: %s", req) + req = mgmt_pb2.FeMessage() + req.session_req.create = 1 + req.session_req.client_conn_id = Session.client_id + Session.client_id += 1 + self.send_pb_msg(req) + logging.debug("Sent FeSessionReq: %s", req) - reply = self.recv_pb_msg(mgmt_pb2.FeMessage()) - logging.debug("Received FeSessionReply: %s", repr(reply)) + reply = self.recv_pb_msg(mgmt_pb2.FeMessage()) + logging.debug("Received FeSessionReply: %s", repr(reply)) - assert reply.session_reply.success - self.sess_id = reply.session_reply.session_id + assert reply.session_reply.success + self.sess_id = reply.session_reply.session_id + else: + self.sess_id = 0 + mdata, req_id = self.get_native_msg_header(MSG_CODE_SESSION_REQ) + mdata += struct.pack(MSG_SESSION_REQ_FMT) + mdata += "test-client".encode("utf-8") + b"\x00" + + self.send_native_msg(mdata) + logging.debug("Sent native SESSION-REQ") + + mhdr, mfixed, mdata = self.recv_native_msg() + if mhdr[HDR_FIELD_CODE] == MSG_CODE_SESSION_REPLY: + logging.debug("Recv native SESSION-REQ Message: %s: %s", mfixed, mdata) + else: + raise Exception(f"Recv NON-SESSION-REPLY Message: {mfixed}: {mdata}") + assert mfixed[0] + self.sess_id = mhdr[HDR_FIELD_SESS_ID] def close(self, clean=True): if clean: @@ -368,6 +394,9 @@ def __parse_args(): "-q", "--query", nargs="+", metavar="XPATH", help="xpath[s] to query" ) parser.add_argument("-s", "--server", default=MPATH, help="path to server socket") + parser.add_argument( + "--use-protobuf", action="store_true", help="Use protobuf when there's a choice" + ) parser.add_argument("-v", "--verbose", action="store_true", help="Be verbose") args = parser.parse_args() @@ -392,7 +421,7 @@ def __server_connect(spath): def __main(): args = __parse_args() sock = __server_connect(Path(args.server)) - sess = Session(sock) + sess = Session(sock, use_protobuf=args.use_protobuf) if args.query: # Performa an xpath query diff --git a/tests/topotests/mgmt_notif/test_notif.py b/tests/topotests/mgmt_notif/test_notif.py index de984b12e1..01466892a8 100644 --- a/tests/topotests/mgmt_notif/test_notif.py +++ b/tests/topotests/mgmt_notif/test_notif.py @@ -69,7 +69,7 @@ def test_frontend_notification(tgen): result = json_cmp(jsout, expected) assert result is None - output = r1.cmd_raises(fe_client_path + " --listen") + output = r1.cmd_raises(fe_client_path + " --use-protobuf --listen") jsout = json.loads(output) expected = {"frr-ripd:authentication-failure": {"interface-name": "r1-eth0"}} From 1fb48f5d13faf4ec1e6d4c2cdded9ca2dcd6d609 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Wed, 12 Jun 2024 08:39:48 +0300 Subject: [PATCH 024/347] bgpd: Do not start BGP session if BFD profile is in shutdown state If we do: ``` bfd profile foo shutdown ``` The session is dropped, but immediately established again because we don't have a proper check on BFD. If BFD is administratively shutdown, ignore starting the session. Fixes: https://github.com/FRRouting/frr/issues/16186 Signed-off-by: Donatas Abraitis --- bgpd/bgpd.c | 6 ++++++ lib/bfd.c | 6 ++++++ lib/bfd.h | 2 ++ 3 files changed, 14 insertions(+) diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 81506f4410..869d2b4552 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -4507,6 +4507,12 @@ bool peer_active(struct peer *peer) { if (BGP_CONNECTION_SU_UNSPEC(peer->connection)) return false; + + if (peer->bfd_config) { + if (bfd_session_is_down(peer->bfd_config->session)) + return false; + } + if (peer->afc[AFI_IP][SAFI_UNICAST] || peer->afc[AFI_IP][SAFI_MULTICAST] || peer->afc[AFI_IP][SAFI_LABELED_UNICAST] || peer->afc[AFI_IP][SAFI_MPLS_VPN] || peer->afc[AFI_IP][SAFI_ENCAP] diff --git a/lib/bfd.c b/lib/bfd.c index 2222bb9547..4535fc1233 100644 --- a/lib/bfd.c +++ b/lib/bfd.c @@ -1334,3 +1334,9 @@ int bfd_nht_update(const struct prefix *match, const struct zapi_route *route) return 0; } + +bool bfd_session_is_down(const struct bfd_session_params *session) +{ + return session->bss.state == BSS_DOWN || + session->bss.state == BSS_ADMIN_DOWN; +} diff --git a/lib/bfd.h b/lib/bfd.h index bfa5287340..48929a9564 100644 --- a/lib/bfd.h +++ b/lib/bfd.h @@ -464,6 +464,8 @@ extern bool bfd_protocol_integration_shutting_down(void); extern int bfd_nht_update(const struct prefix *match, const struct zapi_route *route); +extern bool bfd_session_is_down(const struct bfd_session_params *session); + #ifdef __cplusplus } #endif From a63bfb75669780df7ce29201c87db77b83c6f60a Mon Sep 17 00:00:00 2001 From: Y Bharath Date: Wed, 12 Jun 2024 13:56:34 +0530 Subject: [PATCH 025/347] tests: supress unused variables at topotests For code maintainability, suppressed unused variables with "_" Signed-off-by: y-bharath14 --- tests/topotests/bfd_topo3/test_bfd_topo3.py | 2 +- .../bfd_vrf_topo1/test_bfd_vrf_topo1.py | 2 +- .../bgp_accept_own/test_bgp_accept_own.py | 2 +- .../test_bgp_addpath_best_selected.py | 2 +- ...test_bgp_aggregate_address_matching_med.py | 2 +- .../test_bgp_aggregate-address_origin.py | 6 +- .../test_bgp_aggregate-address_route-map.py | 2 +- .../test_bgp_aggregator_zero.py | 4 +- tests/topotests/bgp_aigp/test_bgp_aigp.py | 2 +- .../bgp_as_override/test_bgp_as_override.py | 2 +- .../test_bgp_as_wide_bgp_identifier.py | 6 +- .../bgp_asdot_regex/test_bgp_asdot_regex.py | 4 +- .../bgp_aspath_zero/test_bgp_aspath_zero.py | 4 +- tests/topotests/bgp_auth/test_bgp_auth1.py | 2 +- tests/topotests/bgp_auth/test_bgp_auth2.py | 2 +- tests/topotests/bgp_auth/test_bgp_auth3.py | 2 +- tests/topotests/bgp_auth/test_bgp_auth4.py | 2 +- .../test_bgp_bfd_down_cease_notification.py | 2 +- .../test_bgp_blackhole_community.py | 10 ++-- .../test_bgp_comm-list_delete.py | 2 +- .../test_bgp_comm_list_match.py | 2 +- .../test_bgp-community-alias.py | 8 +-- .../test_bgp_community_change_update.py | 8 +-- .../test_bgp_conditional_advertisement.py | 58 +++++++++---------- ...gp_conditional_advertisement_track_peer.py | 2 +- .../test_bgp_confederation_astype.py | 2 +- .../test_bgp-default-afi-safi.py | 2 +- .../test_bgp_default_originate_timer.py | 2 +- .../test_bgp_default_originate_withdraw.py | 2 +- .../test_bgp_default-originate.py | 10 ++-- ...t_bgp_default-originate_route-map_match.py | 6 +- ..._bgp_default-originate_route-map_match2.py | 10 ++-- ...p_default-originate_route-map_match_set.py | 6 +- ...est_bgp_default-originate_route-map_set.py | 2 +- .../test_disable_addpath_rx.py | 6 +- .../test_bgp_distance_change.py | 6 +- .../test_bgp_dont_capability_negotiate.py | 2 +- ...gp-ebgp-common-subnet-nexthop-unchanged.py | 6 +- .../test_bgp_ebgp_requires_policy.py | 14 ++--- .../test_bgp_extcomm-list_delete.py | 2 +- ...bgp_extended_optional_parameters_length.py | 2 +- .../test_bgp_gr_notification.py | 2 +- tests/topotests/bgp_gshut/test_bgp_gshut.py | 2 +- .../test_bgp_ipv4_class_e_peer.py | 2 +- .../test_bgp_ipv6_ll_peering.py | 2 +- .../test_bgp_l3vpn_label_export.py | 2 +- .../test_bgp_labeled_unicast_addpath.py | 2 +- ...t_bgp_labeled_unicast_default_originate.py | 2 +- .../test_bgp_large_comm_list_match.py | 2 +- tests/topotests/bgp_llgr/test_bgp_llgr.py | 2 +- .../bgp_local_as/test_bgp_local_as.py | 2 +- ...est_bgp_local_as_dotplus_private_remove.py | 2 +- .../test_bgp_local_as_private_remove.py | 2 +- .../test_bgp_lu_explicitnull.py | 6 +- .../test_bgp_max_med_on_startup.py | 8 +-- .../test_bgp_maximum_prefix_invalid_update.py | 2 +- .../test_bgp_maximum_prefix_out.py | 4 +- .../test_bgp_minimum_holdtime.py | 4 +- .../test_bgp_node_target_extcommunities.py | 2 +- tests/topotests/bgp_orf/test_bgp_orf.py | 2 +- .../test_bgp_path_selection.py | 2 +- .../test_bgp_peer_graceful_shutdown.py | 2 +- .../bgp_peer_group/test_bgp_peer-group.py | 2 +- .../test_bgp_prefix_list_any.py | 2 +- .../bgp_prefix_sid/test_bgp_prefix_sid.py | 8 +-- .../test_bgp_reject_as_sets.py | 8 +-- .../test_bgp_remove_private_as.py | 2 +- .../test_bgp_remove_private_as_route_map.py | 2 +- .../test_bgp_rmap_extcommunity_none.py | 6 +- .../test_bgp_roles_capability.py | 10 ++-- .../test_bgp_roles_filtering.py | 2 +- .../test_bgp_route_map_delay_timer.py | 2 +- .../test_bgp_route_map_match_ipv6_nexthop.py | 4 +- ...est_bgp_route_map_match_source_protocol.py | 2 +- .../test_bgp_route_map_on_match_next.py | 8 +-- .../test_bgp_route_map_vpn_import.py | 2 +- .../test_bgp_route_server_client.py | 2 +- .../bgp_rpki_topo1/test_bgp_rpki_topo1.py | 2 +- .../test_bgp_sender-as-path-loop-detection.py | 2 +- .../test_bgp_set_aspath_exclude.py | 2 +- .../test_bgp_set_aspath_replace.py | 2 +- ...t_bgp_set_local-preference_add_subtract.py | 6 +- .../test_bgp_software_version.py | 2 +- tests/topotests/bgp_soo/test_bgp_soo.py | 2 +- .../test_bgp_srv6l3vpn_sid.py | 4 +- .../test_bgp_srv6l3vpn_to_bgp_vrf.py | 2 +- .../test_bgp_srv6l3vpn_to_bgp_vrf2.py | 2 +- .../test_bgp_srv6l3vpn_to_bgp_vrf3.py | 2 +- .../bgp_suppress_fib/test_bgp_suppress_fib.py | 2 +- .../topotests/bgp_tcp_mss/test_bgp_tcp_mss.py | 10 ++-- .../test_bgp_tcp_mss_passive.py | 2 +- .../bgp_unnumbered/test_bgp_unnumbered.py | 6 +- .../bgp_update_delay/test_bgp_update_delay.py | 20 +++---- .../test_bgp_vpn_5549_route_map.py | 2 +- .../bgp_vpnv4_asbr/test_bgp_vpnv4_asbr.py | 28 ++++----- .../bgp_vpnv4_ebgp/test_bgp_vpnv4_ebgp.py | 14 ++--- .../test_bgp_vpnv4_per_nexthop_label.py | 24 ++++---- .../test_bgp_vpnv6_per_nexthop_label.py | 22 +++---- 98 files changed, 248 insertions(+), 248 deletions(-) diff --git a/tests/topotests/bfd_topo3/test_bfd_topo3.py b/tests/topotests/bfd_topo3/test_bfd_topo3.py index d7b2542f9f..a899a2b464 100644 --- a/tests/topotests/bfd_topo3/test_bfd_topo3.py +++ b/tests/topotests/bfd_topo3/test_bfd_topo3.py @@ -95,7 +95,7 @@ def expect_route_missing(router, iptype, route): "show {} route json".format(iptype), {route: None}, ) - rv, result = topotest.run_and_expect(test_func, None, count=20, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=20, wait=1) assertmsg = '"{}" convergence failure'.format(router) assert result is None, assertmsg diff --git a/tests/topotests/bfd_vrf_topo1/test_bfd_vrf_topo1.py b/tests/topotests/bfd_vrf_topo1/test_bfd_vrf_topo1.py index 9e5a68f0a3..f6adff61d0 100644 --- a/tests/topotests/bfd_vrf_topo1/test_bfd_vrf_topo1.py +++ b/tests/topotests/bfd_vrf_topo1/test_bfd_vrf_topo1.py @@ -61,7 +61,7 @@ def setup_module(mod): router_list = tgen.routers() # check for zebra capability - for rname, router in router_list.items(): + for _, router in router_list.items(): if router.check_capability(TopoRouter.RD_ZEBRA, "--vrfwnetns") == False: return pytest.skip( "Skipping BFD Topo1 VRF NETNS feature. VRF NETNS backend not available on FRR" diff --git a/tests/topotests/bgp_accept_own/test_bgp_accept_own.py b/tests/topotests/bgp_accept_own/test_bgp_accept_own.py index d294da0934..11b24baa82 100644 --- a/tests/topotests/bgp_accept_own/test_bgp_accept_own.py +++ b/tests/topotests/bgp_accept_own/test_bgp_accept_own.py @@ -68,7 +68,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_addpath_best_selected/test_bgp_addpath_best_selected.py b/tests/topotests/bgp_addpath_best_selected/test_bgp_addpath_best_selected.py index 2a610c901e..3d17a2b709 100644 --- a/tests/topotests/bgp_addpath_best_selected/test_bgp_addpath_best_selected.py +++ b/tests/topotests/bgp_addpath_best_selected/test_bgp_addpath_best_selected.py @@ -51,7 +51,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_aggregate_address_matching_med/test_bgp_aggregate_address_matching_med.py b/tests/topotests/bgp_aggregate_address_matching_med/test_bgp_aggregate_address_matching_med.py index 5a4a5fb657..0520b5e136 100644 --- a/tests/topotests/bgp_aggregate_address_matching_med/test_bgp_aggregate_address_matching_med.py +++ b/tests/topotests/bgp_aggregate_address_matching_med/test_bgp_aggregate_address_matching_med.py @@ -49,7 +49,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_aggregate_address_origin/test_bgp_aggregate-address_origin.py b/tests/topotests/bgp_aggregate_address_origin/test_bgp_aggregate-address_origin.py index 739685d417..188bbd0b98 100644 --- a/tests/topotests/bgp_aggregate_address_origin/test_bgp_aggregate-address_origin.py +++ b/tests/topotests/bgp_aggregate_address_origin/test_bgp_aggregate-address_origin.py @@ -49,7 +49,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -89,12 +89,12 @@ def _bgp_aggregate_address_has_metric(router): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_converge, router) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) assert result is None, 'Failed to see bgp convergence in "{}"'.format(router) test_func = functools.partial(_bgp_aggregate_address_has_metric, router) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) assert ( result is None diff --git a/tests/topotests/bgp_aggregate_address_route_map/test_bgp_aggregate-address_route-map.py b/tests/topotests/bgp_aggregate_address_route_map/test_bgp_aggregate-address_route-map.py index eeac7146b1..2343440aaf 100644 --- a/tests/topotests/bgp_aggregate_address_route_map/test_bgp_aggregate-address_route-map.py +++ b/tests/topotests/bgp_aggregate_address_route_map/test_bgp_aggregate-address_route-map.py @@ -52,7 +52,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_aggregator_zero/test_bgp_aggregator_zero.py b/tests/topotests/bgp_aggregator_zero/test_bgp_aggregator_zero.py index d9ef3e1ce1..1a52f8c90e 100644 --- a/tests/topotests/bgp_aggregator_zero/test_bgp_aggregator_zero.py +++ b/tests/topotests/bgp_aggregator_zero/test_bgp_aggregator_zero.py @@ -73,7 +73,7 @@ def _bgp_converge(): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_converge) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, 'Failed bgp convergence in "{}"'.format(tgen.gears["r1"]) @@ -99,7 +99,7 @@ def _bgp_has_correct_aggregator_route_with_good_asn(): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_has_correct_aggregator_route_with_good_asn) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, 'Aggregator AS attribute not found in "{}"'.format( tgen.gears["r1"] diff --git a/tests/topotests/bgp_aigp/test_bgp_aigp.py b/tests/topotests/bgp_aigp/test_bgp_aigp.py index 655e9ad184..e3b32da164 100644 --- a/tests/topotests/bgp_aigp/test_bgp_aigp.py +++ b/tests/topotests/bgp_aigp/test_bgp_aigp.py @@ -73,7 +73,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_as_override/test_bgp_as_override.py b/tests/topotests/bgp_as_override/test_bgp_as_override.py index 7cb4f81cfc..dbbdf2c88f 100644 --- a/tests/topotests/bgp_as_override/test_bgp_as_override.py +++ b/tests/topotests/bgp_as_override/test_bgp_as_override.py @@ -49,7 +49,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_as_wide_bgp_identifier/test_bgp_as_wide_bgp_identifier.py b/tests/topotests/bgp_as_wide_bgp_identifier/test_bgp_as_wide_bgp_identifier.py index 5c09a6b0e0..e8e3b4171a 100644 --- a/tests/topotests/bgp_as_wide_bgp_identifier/test_bgp_as_wide_bgp_identifier.py +++ b/tests/topotests/bgp_as_wide_bgp_identifier/test_bgp_as_wide_bgp_identifier.py @@ -48,7 +48,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -85,12 +85,12 @@ def _bgp_failed(router): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_converge, tgen.gears["r1"]) - success, result = topotest.run_and_expect(test_func, None, count=260, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=260, wait=0.5) assert result is None, 'Failed to converge: "{}"'.format(tgen.gears["r1"]) test_func = functools.partial(_bgp_failed, tgen.gears["r3"]) - success, result = topotest.run_and_expect(test_func, None, count=260, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=260, wait=0.5) assert result is None, 'Bad BGP Identifier notification not sent: "{}"'.format( tgen.gears["r3"] diff --git a/tests/topotests/bgp_asdot_regex/test_bgp_asdot_regex.py b/tests/topotests/bgp_asdot_regex/test_bgp_asdot_regex.py index 4883e847c9..09803dfa84 100644 --- a/tests/topotests/bgp_asdot_regex/test_bgp_asdot_regex.py +++ b/tests/topotests/bgp_asdot_regex/test_bgp_asdot_regex.py @@ -60,7 +60,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -97,7 +97,7 @@ def _bgp_converge(router): logger.info("Check if neighbor sessions are up in {}".format(router1.name)) test_func = partial(_bgp_converge, router1) - success, result = topotest.run_and_expect(test_func, None, count=15, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=15, wait=0.5) assert result is None, 'Failed to see BGP convergence in "{}"'.format(router1.name) logger.info("BGP neighbor session is up in {}".format(router1.name)) diff --git a/tests/topotests/bgp_aspath_zero/test_bgp_aspath_zero.py b/tests/topotests/bgp_aspath_zero/test_bgp_aspath_zero.py index 0f1a08308f..fe89a87621 100644 --- a/tests/topotests/bgp_aspath_zero/test_bgp_aspath_zero.py +++ b/tests/topotests/bgp_aspath_zero/test_bgp_aspath_zero.py @@ -73,7 +73,7 @@ def _bgp_converge(): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_converge) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, "More than one prefix seen at r1, SHOULD be only one." def _bgp_has_correct_routes_without_asn_0(): @@ -82,7 +82,7 @@ def _bgp_has_correct_routes_without_asn_0(): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_has_correct_routes_without_asn_0) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, "Failed listing 192.168.100.101/32, SHOULD be accepted." diff --git a/tests/topotests/bgp_auth/test_bgp_auth1.py b/tests/topotests/bgp_auth/test_bgp_auth1.py index 9d47106c07..c19a740a92 100644 --- a/tests/topotests/bgp_auth/test_bgp_auth1.py +++ b/tests/topotests/bgp_auth/test_bgp_auth1.py @@ -156,7 +156,7 @@ def setup_module(mod): router_list = tgen.routers() # For all registered routers, load the zebra configuration file - for rname, router in router_list.items(): + for _, router in router_list.items(): router.load_config(TopoRouter.RD_ZEBRA, "zebra.conf") router.load_config(TopoRouter.RD_OSPF, "") router.load_config(TopoRouter.RD_BGP, "") diff --git a/tests/topotests/bgp_auth/test_bgp_auth2.py b/tests/topotests/bgp_auth/test_bgp_auth2.py index 6b92036727..2551c1c35b 100644 --- a/tests/topotests/bgp_auth/test_bgp_auth2.py +++ b/tests/topotests/bgp_auth/test_bgp_auth2.py @@ -156,7 +156,7 @@ def setup_module(mod): router_list = tgen.routers() # For all registered routers, load the zebra configuration file - for rname, router in router_list.items(): + for _, router in router_list.items(): router.load_config(TopoRouter.RD_ZEBRA, "zebra.conf") router.load_config(TopoRouter.RD_OSPF, "") router.load_config(TopoRouter.RD_BGP, "") diff --git a/tests/topotests/bgp_auth/test_bgp_auth3.py b/tests/topotests/bgp_auth/test_bgp_auth3.py index 2237c6b1b6..dc4f61d3c9 100644 --- a/tests/topotests/bgp_auth/test_bgp_auth3.py +++ b/tests/topotests/bgp_auth/test_bgp_auth3.py @@ -155,7 +155,7 @@ def setup_module(mod): router_list = tgen.routers() # For all registered routers, load the zebra configuration file - for rname, router in router_list.items(): + for _, router in router_list.items(): router.load_config(TopoRouter.RD_ZEBRA, "zebra.conf") router.load_config(TopoRouter.RD_OSPF, "") router.load_config(TopoRouter.RD_BGP, "") diff --git a/tests/topotests/bgp_auth/test_bgp_auth4.py b/tests/topotests/bgp_auth/test_bgp_auth4.py index d6fe42504b..afe4441e13 100644 --- a/tests/topotests/bgp_auth/test_bgp_auth4.py +++ b/tests/topotests/bgp_auth/test_bgp_auth4.py @@ -155,7 +155,7 @@ def setup_module(mod): router_list = tgen.routers() # For all registered routers, load the zebra configuration file - for rname, router in router_list.items(): + for _, router in router_list.items(): router.load_config(TopoRouter.RD_ZEBRA, "zebra.conf") router.load_config(TopoRouter.RD_OSPF, "") router.load_config(TopoRouter.RD_BGP, "") diff --git a/tests/topotests/bgp_bfd_down_cease_notification/test_bgp_bfd_down_cease_notification.py b/tests/topotests/bgp_bfd_down_cease_notification/test_bgp_bfd_down_cease_notification.py index 00142981c5..8536b3506f 100644 --- a/tests/topotests/bgp_bfd_down_cease_notification/test_bgp_bfd_down_cease_notification.py +++ b/tests/topotests/bgp_bfd_down_cease_notification/test_bgp_bfd_down_cease_notification.py @@ -45,7 +45,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_blackhole_community/test_bgp_blackhole_community.py b/tests/topotests/bgp_blackhole_community/test_bgp_blackhole_community.py index 9f5c0ef924..05a9a1e7f6 100644 --- a/tests/topotests/bgp_blackhole_community/test_bgp_blackhole_community.py +++ b/tests/topotests/bgp_blackhole_community/test_bgp_blackhole_community.py @@ -51,7 +51,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -125,14 +125,14 @@ def _bgp_verify_nexthop_validity(): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_converge) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, 'Failed bgp convergence in "{}"'.format(tgen.gears["r2"]) step("Check if 172.16.255.254/32 is not advertised to eBGP peers") test_func = functools.partial(_bgp_no_advertise_ebgp) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert ( result is None @@ -142,7 +142,7 @@ def _bgp_verify_nexthop_validity(): step("Check if 172.16.255.254/32 is advertised to iBGP peers") test_func = functools.partial(_bgp_no_advertise_ibgp) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert ( result is None @@ -152,7 +152,7 @@ def _bgp_verify_nexthop_validity(): step("Verify if the nexthop set via route-map on r4 is marked valid") test_func = functools.partial(_bgp_verify_nexthop_validity) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, 'Nexthops are not valid "{}"'.format(tgen.gears["r4"]) diff --git a/tests/topotests/bgp_comm_list_delete/test_bgp_comm-list_delete.py b/tests/topotests/bgp_comm_list_delete/test_bgp_comm-list_delete.py index efc8f200a3..2064dac6e6 100644 --- a/tests/topotests/bgp_comm_list_delete/test_bgp_comm-list_delete.py +++ b/tests/topotests/bgp_comm_list_delete/test_bgp_comm-list_delete.py @@ -48,7 +48,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_comm_list_match/test_bgp_comm_list_match.py b/tests/topotests/bgp_comm_list_match/test_bgp_comm_list_match.py index de69ea9387..d0cab26e1a 100644 --- a/tests/topotests/bgp_comm_list_match/test_bgp_comm_list_match.py +++ b/tests/topotests/bgp_comm_list_match/test_bgp_comm_list_match.py @@ -56,7 +56,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_community_alias/test_bgp-community-alias.py b/tests/topotests/bgp_community_alias/test_bgp-community-alias.py index fdae9a3aa7..9df73a51ba 100644 --- a/tests/topotests/bgp_community_alias/test_bgp-community-alias.py +++ b/tests/topotests/bgp_community_alias/test_bgp-community-alias.py @@ -40,7 +40,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -92,7 +92,7 @@ def _bgp_converge(router): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_converge, router) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, "Cannot see BGP community aliases at r1" def _bgp_show_prefixes_by_alias(router): @@ -118,7 +118,7 @@ def _bgp_show_prefixes_by_alias(router): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_show_prefixes_by_alias, router) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, "Cannot see BGP prefixes by community alias at r1" def _bgp_show_prefixes_by_large_community_list(router): @@ -129,7 +129,7 @@ def _bgp_show_prefixes_by_large_community_list(router): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_show_prefixes_by_large_community_list, router) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, "Cannot see BGP prefixes by large community list at r1" diff --git a/tests/topotests/bgp_community_change_update/test_bgp_community_change_update.py b/tests/topotests/bgp_community_change_update/test_bgp_community_change_update.py index 5ad15e0645..c0a92efba9 100644 --- a/tests/topotests/bgp_community_change_update/test_bgp_community_change_update.py +++ b/tests/topotests/bgp_community_change_update/test_bgp_community_change_update.py @@ -97,7 +97,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -133,7 +133,7 @@ def _bgp_converge_initial(): step("Check if an initial topology is converged") test_func = functools.partial(_bgp_converge_initial) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, "Failed to see bgp convergence in c1" step("Disable link between y1 and y2") @@ -146,7 +146,7 @@ def _bgp_converge_link_disabled(): step("Check if a topology is converged after a link down between y1 and y2") test_func = functools.partial(_bgp_converge_link_disabled) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, "Failed to see bgp convergence in y1" def _bgp_check_for_duplicate_updates(): @@ -193,7 +193,7 @@ def _bgp_converge_link_enabled(): step("Check if a topology is converged after a link up between y1 and y2") test_func = functools.partial(_bgp_converge_link_enabled) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, "Failed to see bgp convergence in y1" step( diff --git a/tests/topotests/bgp_conditional_advertisement/test_bgp_conditional_advertisement.py b/tests/topotests/bgp_conditional_advertisement/test_bgp_conditional_advertisement.py index 0128c88349..577bf9fd76 100644 --- a/tests/topotests/bgp_conditional_advertisement/test_bgp_conditional_advertisement.py +++ b/tests/topotests/bgp_conditional_advertisement/test_bgp_conditional_advertisement.py @@ -159,7 +159,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -426,7 +426,7 @@ def test_bgp_conditional_advertisement_tc_2_1(): ) test_func = functools.partial(exist_map_routes_present, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = 'TC21: exist-map routes present in "router2" BGP table - ' assert result is None, msg + failed @@ -455,7 +455,7 @@ def test_bgp_conditional_advertisement_tc_2_2(): ) test_func = functools.partial(exist_map_routes_not_present, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = 'TC22: exist-map routes not present in "router2" BGP table - ' assert result is None, msg + failed @@ -484,7 +484,7 @@ def test_bgp_conditional_advertisement_tc_2_3(): ) test_func = functools.partial(default_route_withdrawn, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC23: advertise-map with exist-map configuration is removed from peer - " assert result is None, msg + failed @@ -513,7 +513,7 @@ def test_bgp_conditional_advertisement_tc_3_1(): ) test_func = functools.partial(non_exist_map_routes_not_present, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = 'TC31: non-exist-map routes not present in "router2" BGP table - ' assert result is None, msg + failed @@ -542,7 +542,7 @@ def test_bgp_conditional_advertisement_tc_3_2(): ) test_func = functools.partial(non_exist_map_routes_present, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = 'TC32: non-exist-map routes present in "router2" BGP table - ' assert result is None, msg + failed @@ -571,7 +571,7 @@ def test_bgp_conditional_advertisement_tc_3_3(): ) test_func = functools.partial(all_routes_advertised, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = ( "TC33: advertise-map with non-exist-map configuration is removed from a peer - " @@ -603,7 +603,7 @@ def test_bgp_conditional_advertisement_tc_4_1(): ) test_func = functools.partial(non_exist_map_no_condition_route_map, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = 'TC41: non-exist-map route-map removed in "router2" - ' assert result is None, msg + failed @@ -632,7 +632,7 @@ def test_bgp_conditional_advertisement_tc_4_2(): ) test_func = functools.partial(exist_map_no_condition_route_map, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = 'TC42: exist-map route-map removed in "router2" - ' assert result is None, msg + failed @@ -665,7 +665,7 @@ def test_bgp_conditional_advertisement_tc_5_1(): ) test_func = functools.partial(exist_map_routes_present_rmap_filter, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC51: exist-map routes present with route-map filter - " assert result is None, msg + failed @@ -694,7 +694,7 @@ def test_bgp_conditional_advertisement_tc_5_2(): ) test_func = functools.partial(exist_map_routes_present_no_rmap_filter, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC52: exist-map routes present, no route-map filter - " assert result is None, msg + failed @@ -724,7 +724,7 @@ def test_bgp_conditional_advertisement_tc_5_3(): ) test_func = functools.partial(non_exist_map_routes_present_rmap_filter, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC53: non-exist-map routes present, with route-map filter - " assert result is None, msg + failed @@ -753,7 +753,7 @@ def test_bgp_conditional_advertisement_tc_5_4(): ) test_func = functools.partial(non_exist_map_routes_present_no_rmap_filter, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC54: non-exist-map routes present, no route-map filter - " assert result is None, msg + failed @@ -791,7 +791,7 @@ def test_bgp_conditional_advertisement_tc_6_1(): ) test_func = functools.partial(exist_map_routes_not_present_rmap_filter, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC61: exist-map routes not present, route-map filter - " assert result is None, msg + failed @@ -820,7 +820,7 @@ def test_bgp_conditional_advertisement_tc_6_2(): ) test_func = functools.partial(exist_map_routes_not_present_no_rmap_filter, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC62: exist-map routes not present, no route-map filter - " assert result is None, msg + failed @@ -850,7 +850,7 @@ def test_bgp_conditional_advertisement_tc_6_3(): ) test_func = functools.partial(non_exist_map_routes_not_present_rmap_filter, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC63: non-exist-map routes not present, route-map filter - " assert result is None, msg + failed @@ -881,7 +881,7 @@ def test_bgp_conditional_advertisement_tc_6_4(): test_func = functools.partial( non_exist_map_routes_not_present_no_rmap_filter, router3 ) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC64: non-exist-map routes not present, no route-map filter - " assert result is None, msg + failed @@ -919,7 +919,7 @@ def test_bgp_conditional_advertisement_tc_7_1(): ) test_func = functools.partial(exist_map_routes_present_rmap2_filter, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC71: exist-map routes present, route-map filter - " assert result is None, msg + failed @@ -948,7 +948,7 @@ def test_bgp_conditional_advertisement_tc_7_2(): ) test_func = functools.partial(exist_map_routes_present_no_rmap2_filter, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC72: exist-map routes present, no route-map filter - " assert result is None, msg + failed @@ -978,7 +978,7 @@ def test_bgp_conditional_advertisement_tc_7_3(): ) test_func = functools.partial(non_exist_map_routes_present_rmap2_filter, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC73: non-exist-map routes present, route-map filter - " assert result is None, msg + failed @@ -1007,7 +1007,7 @@ def test_bgp_conditional_advertisement_tc_7_4(): ) test_func = functools.partial(non_exist_map_routes_present_no_rmap2_filter, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC74: non-exist-map routes present, no route-map filter - " assert result is None, msg + failed @@ -1045,7 +1045,7 @@ def test_bgp_conditional_advertisement_tc_8_1(): ) test_func = functools.partial(exist_map_routes_not_present_rmap2_filter, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC81: exist-map routes not present, route-map filter - " assert result is None, msg + failed @@ -1074,7 +1074,7 @@ def test_bgp_conditional_advertisement_tc_8_2(): ) test_func = functools.partial(exist_map_routes_not_present_no_rmap2_filter, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC82: exist-map routes not present, no route-map filter - " assert result is None, msg + failed @@ -1106,7 +1106,7 @@ def test_bgp_conditional_advertisement_tc_8_3(): test_func = functools.partial( non_exist_map_routes_not_present_rmap2_filter, router3 ) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC83: non-exist-map routes not present, route-map filter - " assert result is None, msg + failed @@ -1137,7 +1137,7 @@ def test_bgp_conditional_advertisement_tc_8_4(): test_func = functools.partial( non_exist_map_routes_not_present_no_rmap2_filter, router3 ) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC84: non-exist-map routes not present, no route-map filter - " assert result is None, msg + failed @@ -1175,7 +1175,7 @@ def test_bgp_conditional_advertisement_tc_9_1(): ) test_func = functools.partial(exist_map_routes_present_rmap2_network, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC91: exist-map routes present, route-map filter and network - " assert result is None, msg + failed @@ -1204,7 +1204,7 @@ def test_bgp_conditional_advertisement_tc_9_2(): ) test_func = functools.partial(exist_map_routes_present_rmap2_no_network, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC92: exist-map routes present, route-map filter and no network - " assert result is None, msg + failed @@ -1244,7 +1244,7 @@ def test_bgp_conditional_advertisement_tc_9_3(): test_func = functools.partial( non_exist_map_routes_not_present_rmap2_network, router3 ) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC93: non-exist-map routes not present, route-map filter and network - " assert result is None, msg + failed @@ -1275,7 +1275,7 @@ def test_bgp_conditional_advertisement_tc_9_4(): test_func = functools.partial( non_exist_map_routes_not_present_rmap2_no_network, router3 ) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC94: non-exist-map routes not present, route-map filter and no network - " assert result is None, msg + failed diff --git a/tests/topotests/bgp_conditional_advertisement_track_peer/test_bgp_conditional_advertisement_track_peer.py b/tests/topotests/bgp_conditional_advertisement_track_peer/test_bgp_conditional_advertisement_track_peer.py index e76307291e..bb98e2fad0 100644 --- a/tests/topotests/bgp_conditional_advertisement_track_peer/test_bgp_conditional_advertisement_track_peer.py +++ b/tests/topotests/bgp_conditional_advertisement_track_peer/test_bgp_conditional_advertisement_track_peer.py @@ -51,7 +51,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_confederation_astype/test_bgp_confederation_astype.py b/tests/topotests/bgp_confederation_astype/test_bgp_confederation_astype.py index 7bc0050109..44b1a2f704 100644 --- a/tests/topotests/bgp_confederation_astype/test_bgp_confederation_astype.py +++ b/tests/topotests/bgp_confederation_astype/test_bgp_confederation_astype.py @@ -35,7 +35,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_default_afi_safi/test_bgp-default-afi-safi.py b/tests/topotests/bgp_default_afi_safi/test_bgp-default-afi-safi.py index 05e07486ae..48dddb4648 100644 --- a/tests/topotests/bgp_default_afi_safi/test_bgp-default-afi-safi.py +++ b/tests/topotests/bgp_default_afi_safi/test_bgp-default-afi-safi.py @@ -48,7 +48,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_default_originate_timer/test_bgp_default_originate_timer.py b/tests/topotests/bgp_default_originate_timer/test_bgp_default_originate_timer.py index b2ba936fb1..c7c40c1bfb 100644 --- a/tests/topotests/bgp_default_originate_timer/test_bgp_default_originate_timer.py +++ b/tests/topotests/bgp_default_originate_timer/test_bgp_default_originate_timer.py @@ -50,7 +50,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_default_originate_withdraw/test_bgp_default_originate_withdraw.py b/tests/topotests/bgp_default_originate_withdraw/test_bgp_default_originate_withdraw.py index e25f85af85..cd4acc9aa4 100644 --- a/tests/topotests/bgp_default_originate_withdraw/test_bgp_default_originate_withdraw.py +++ b/tests/topotests/bgp_default_originate_withdraw/test_bgp_default_originate_withdraw.py @@ -49,7 +49,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_default_route/test_bgp_default-originate.py b/tests/topotests/bgp_default_route/test_bgp_default-originate.py index 333beb067c..e805d06a6a 100644 --- a/tests/topotests/bgp_default_route/test_bgp_default-originate.py +++ b/tests/topotests/bgp_default_route/test_bgp_default-originate.py @@ -40,7 +40,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -85,19 +85,19 @@ def _bgp_route_is_valid(router, prefix): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_check_if_received) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) assert result is None, "No 0.0.0.0/0 at r2 from r1" test_func = functools.partial(_bgp_check_if_originated) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) assert result is None, "No 0.0.0.0/0 from r1 to r2" test_func = functools.partial(_bgp_route_is_valid, tgen.gears["r2"], "0.0.0.0/0") - success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) assert result is None, "Failed to see 0.0.0.0/0 in r2" test_func = functools.partial(_bgp_route_is_valid, tgen.gears["r2"], "0.0.0.0/1") - success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) assert result is None, "Failed to see 0.0.0.0/1 in r2" diff --git a/tests/topotests/bgp_default_route_route_map_match/test_bgp_default-originate_route-map_match.py b/tests/topotests/bgp_default_route_route_map_match/test_bgp_default-originate_route-map_match.py index 9dcb5a1eef..d866b95f7b 100644 --- a/tests/topotests/bgp_default_route_route_map_match/test_bgp_default-originate_route-map_match.py +++ b/tests/topotests/bgp_default_route_route_map_match/test_bgp_default-originate_route-map_match.py @@ -40,7 +40,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -80,12 +80,12 @@ def _bgp_default_route_is_valid(router): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_converge, router) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) assert result is None, 'Failed to see bgp convergence in "{}"'.format(router) test_func = functools.partial(_bgp_default_route_is_valid, router) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) assert ( result is None diff --git a/tests/topotests/bgp_default_route_route_map_match2/test_bgp_default-originate_route-map_match2.py b/tests/topotests/bgp_default_route_route_map_match2/test_bgp_default-originate_route-map_match2.py index 965d348bd7..5a99878b88 100644 --- a/tests/topotests/bgp_default_route_route_map_match2/test_bgp_default-originate_route-map_match2.py +++ b/tests/topotests/bgp_default_route_route_map_match2/test_bgp_default-originate_route-map_match2.py @@ -43,7 +43,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -84,7 +84,7 @@ def _bgp_default_route_is_valid(router): step("Converge network") test_func = functools.partial(_bgp_converge, router) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) assert result is None, "Failed to see bgp convergence at r2" step("Withdraw 10.0.0.0/22 from R2") @@ -94,7 +94,7 @@ def _bgp_default_route_is_valid(router): step("Check if we don't have 0.0.0.0/0 at R2") test_func = functools.partial(_bgp_default_route_is_valid, router) - success, result = topotest.run_and_expect(test_func, not None, count=30, wait=0.5) + _, result = topotest.run_and_expect(test_func, not None, count=30, wait=0.5) assert result is not None, "0.0.0.0/0 exists at r2" step("Announce 10.0.0.0/22 from R2") @@ -102,7 +102,7 @@ def _bgp_default_route_is_valid(router): step("Check if we have 0.0.0.0/0 at R2") test_func = functools.partial(_bgp_default_route_is_valid, router) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) assert result is None, "0.0.0.0/0 does not exist at r2" step("Withdraw 10.0.0.0/22 from R2 again") @@ -112,7 +112,7 @@ def _bgp_default_route_is_valid(router): step("Check if we don't have 0.0.0.0/0 at R2 again") test_func = functools.partial(_bgp_default_route_is_valid, router) - success, result = topotest.run_and_expect(test_func, not None, count=30, wait=0.5) + _, result = topotest.run_and_expect(test_func, not None, count=30, wait=0.5) assert result is not None, "0.0.0.0/0 exists at r2" diff --git a/tests/topotests/bgp_default_route_route_map_match_set/test_bgp_default-originate_route-map_match_set.py b/tests/topotests/bgp_default_route_route_map_match_set/test_bgp_default-originate_route-map_match_set.py index f94620b2c9..3a374c6e9a 100644 --- a/tests/topotests/bgp_default_route_route_map_match_set/test_bgp_default-originate_route-map_match_set.py +++ b/tests/topotests/bgp_default_route_route_map_match_set/test_bgp_default-originate_route-map_match_set.py @@ -42,7 +42,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -90,12 +90,12 @@ def _bgp_default_route_has_metric(router): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_converge, router) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) assert result is None, 'Failed to see bgp convergence in "{}"'.format(router) test_func = functools.partial(_bgp_default_route_has_metric, router) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) assert ( result is None diff --git a/tests/topotests/bgp_default_route_route_map_set/test_bgp_default-originate_route-map_set.py b/tests/topotests/bgp_default_route_route_map_set/test_bgp_default-originate_route-map_set.py index e633b61d1b..ba278295a6 100644 --- a/tests/topotests/bgp_default_route_route_map_set/test_bgp_default-originate_route-map_set.py +++ b/tests/topotests/bgp_default_route_route_map_set/test_bgp_default-originate_route-map_set.py @@ -41,7 +41,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_disable_addpath_rx/test_disable_addpath_rx.py b/tests/topotests/bgp_disable_addpath_rx/test_disable_addpath_rx.py index 70562ce31f..6978008740 100644 --- a/tests/topotests/bgp_disable_addpath_rx/test_disable_addpath_rx.py +++ b/tests/topotests/bgp_disable_addpath_rx/test_disable_addpath_rx.py @@ -46,7 +46,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -98,7 +98,7 @@ def check_bgp_advertised_routes(router): return topotest.json_cmp(output, expected) test_func = functools.partial(check_bgp_advertised_routes, r2) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, "AddPath TX not working." step("Check if AddPath RX is disabled on r1 and we receive only 2 paths.") @@ -120,7 +120,7 @@ def check_bgp_disabled_addpath_rx(router): return topotest.json_cmp(output, expected) test_func = functools.partial(check_bgp_disabled_addpath_rx, r1) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, "AddPath RX advertised, but should not." diff --git a/tests/topotests/bgp_distance_change/test_bgp_distance_change.py b/tests/topotests/bgp_distance_change/test_bgp_distance_change.py index 2ca50aa56e..87802511b5 100644 --- a/tests/topotests/bgp_distance_change/test_bgp_distance_change.py +++ b/tests/topotests/bgp_distance_change/test_bgp_distance_change.py @@ -51,7 +51,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -101,14 +101,14 @@ def _bgp_check_distance_change(router): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_converge, router) - success, result = topotest.run_and_expect(test_func, None, count=15, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=15, wait=0.5) assert result is None, 'Failed to see BGP convergence in "{}"'.format(router) _bgp_distance_change(router) test_func = functools.partial(_bgp_check_distance_change, router) - success, result = topotest.run_and_expect(test_func, None, count=15, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=15, wait=0.5) assert result is None, 'Failed to see applied BGP distance in RIB "{}"'.format( router diff --git a/tests/topotests/bgp_dont_capability_negotiate/test_bgp_dont_capability_negotiate.py b/tests/topotests/bgp_dont_capability_negotiate/test_bgp_dont_capability_negotiate.py index 8269322215..28d6b56303 100644 --- a/tests/topotests/bgp_dont_capability_negotiate/test_bgp_dont_capability_negotiate.py +++ b/tests/topotests/bgp_dont_capability_negotiate/test_bgp_dont_capability_negotiate.py @@ -34,7 +34,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_ebgp_common_subnet_nexthop_unchanged/test_bgp-ebgp-common-subnet-nexthop-unchanged.py b/tests/topotests/bgp_ebgp_common_subnet_nexthop_unchanged/test_bgp-ebgp-common-subnet-nexthop-unchanged.py index d9ccd6979c..a4ac249cb7 100644 --- a/tests/topotests/bgp_ebgp_common_subnet_nexthop_unchanged/test_bgp-ebgp-common-subnet-nexthop-unchanged.py +++ b/tests/topotests/bgp_ebgp_common_subnet_nexthop_unchanged/test_bgp-ebgp-common-subnet-nexthop-unchanged.py @@ -52,7 +52,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -90,7 +90,7 @@ def _bgp_converge(router): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_converge, r3) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, 'Failed bgp convergence in "{}"'.format(r3) @@ -100,7 +100,7 @@ def _bgp_nh_unchanged(router): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_nh_unchanged, r2) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, 'Wrong next-hop in "{}"'.format(r2) diff --git a/tests/topotests/bgp_ebgp_requires_policy/test_bgp_ebgp_requires_policy.py b/tests/topotests/bgp_ebgp_requires_policy/test_bgp_ebgp_requires_policy.py index 6e3b2859c4..f7c0f70445 100644 --- a/tests/topotests/bgp_ebgp_requires_policy/test_bgp_ebgp_requires_policy.py +++ b/tests/topotests/bgp_ebgp_requires_policy/test_bgp_ebgp_requires_policy.py @@ -71,7 +71,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -125,31 +125,31 @@ def _bgp_advertised_routes(router): # Scenario 1. logger.info("Scenario 1: r2 receives 192.168.255.1/32 from r1") test_func = functools.partial(_bgp_converge, "r2") - success, result = topotest.run_and_expect(test_func, None, count=120, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=120, wait=0.5) assert success is True, "Failed bgp convergence (r2)" test_func = functools.partial(_bgp_has_routes, "r2") - success, result = topotest.run_and_expect(test_func, None, count=120, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=120, wait=0.5) assert success is True, "r2 does not receive 192.168.255.1/32" # Scenario 2. logger.info("Scenario 2: r3 must not send 192.168.255.1/32 to r4") test_func = functools.partial(_bgp_converge, "r4") - success, result = topotest.run_and_expect(test_func, None, count=120, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=120, wait=0.5) assert success is True, "Failed bgp convergence (r4)" test_func = functools.partial(_bgp_advertised_routes, "r3") - success, result = topotest.run_and_expect(test_func, None, count=120, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=120, wait=0.5) assert success is True, "r3 announced 192.168.255.1/32 to r4" # Scenario 3. logger.info("Scenario 3: r6 receives 192.168.255.1/32 from r5 (iBGP)") test_func = functools.partial(_bgp_converge, "r6") - success, result = topotest.run_and_expect(test_func, None, count=120, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=120, wait=0.5) assert success is True, "Failed bgp convergence (r6)" test_func = functools.partial(_bgp_has_routes, "r6") - success, result = topotest.run_and_expect(test_func, None, count=120, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=120, wait=0.5) assert success is True, "r6 does not receive 192.168.255.1/32" diff --git a/tests/topotests/bgp_extcomm_list_delete/test_bgp_extcomm-list_delete.py b/tests/topotests/bgp_extcomm_list_delete/test_bgp_extcomm-list_delete.py index a5e5bdcee9..5f6eb17261 100644 --- a/tests/topotests/bgp_extcomm_list_delete/test_bgp_extcomm-list_delete.py +++ b/tests/topotests/bgp_extcomm_list_delete/test_bgp_extcomm-list_delete.py @@ -47,7 +47,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_extended_optional_parameters_length/test_bgp_extended_optional_parameters_length.py b/tests/topotests/bgp_extended_optional_parameters_length/test_bgp_extended_optional_parameters_length.py index a5db20e474..c67bc91f63 100644 --- a/tests/topotests/bgp_extended_optional_parameters_length/test_bgp_extended_optional_parameters_length.py +++ b/tests/topotests/bgp_extended_optional_parameters_length/test_bgp_extended_optional_parameters_length.py @@ -34,7 +34,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_gr_notification/test_bgp_gr_notification.py b/tests/topotests/bgp_gr_notification/test_bgp_gr_notification.py index 2ffcb723ec..16459a25a3 100644 --- a/tests/topotests/bgp_gr_notification/test_bgp_gr_notification.py +++ b/tests/topotests/bgp_gr_notification/test_bgp_gr_notification.py @@ -50,7 +50,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_gshut/test_bgp_gshut.py b/tests/topotests/bgp_gshut/test_bgp_gshut.py index 61a0fe63c1..cfe63d20ba 100644 --- a/tests/topotests/bgp_gshut/test_bgp_gshut.py +++ b/tests/topotests/bgp_gshut/test_bgp_gshut.py @@ -108,7 +108,7 @@ def setup_module(mod): r2.run("ip link set r2-eth3 master vrf1") # Load FRR config and initialize all routers - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_ipv4_class_e_peer/test_bgp_ipv4_class_e_peer.py b/tests/topotests/bgp_ipv4_class_e_peer/test_bgp_ipv4_class_e_peer.py index c7cb213de5..66eeeb468d 100644 --- a/tests/topotests/bgp_ipv4_class_e_peer/test_bgp_ipv4_class_e_peer.py +++ b/tests/topotests/bgp_ipv4_class_e_peer/test_bgp_ipv4_class_e_peer.py @@ -45,7 +45,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_ipv6_ll_peering/test_bgp_ipv6_ll_peering.py b/tests/topotests/bgp_ipv6_ll_peering/test_bgp_ipv6_ll_peering.py index ea974b5302..aaa68ea340 100644 --- a/tests/topotests/bgp_ipv6_ll_peering/test_bgp_ipv6_ll_peering.py +++ b/tests/topotests/bgp_ipv6_ll_peering/test_bgp_ipv6_ll_peering.py @@ -41,7 +41,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_l3vpn_label_export/test_bgp_l3vpn_label_export.py b/tests/topotests/bgp_l3vpn_label_export/test_bgp_l3vpn_label_export.py index 7c23a3e899..84a9c8b723 100644 --- a/tests/topotests/bgp_l3vpn_label_export/test_bgp_l3vpn_label_export.py +++ b/tests/topotests/bgp_l3vpn_label_export/test_bgp_l3vpn_label_export.py @@ -56,7 +56,7 @@ def setup_module(mod): ) tgen.gears["r{}".format(rtr)].run("sysctl -w net.mpls.conf.vrf1.input=1") - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_labeled_unicast_addpath/test_bgp_labeled_unicast_addpath.py b/tests/topotests/bgp_labeled_unicast_addpath/test_bgp_labeled_unicast_addpath.py index f4bb487e40..25fd0dbb71 100644 --- a/tests/topotests/bgp_labeled_unicast_addpath/test_bgp_labeled_unicast_addpath.py +++ b/tests/topotests/bgp_labeled_unicast_addpath/test_bgp_labeled_unicast_addpath.py @@ -57,7 +57,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_labeled_unicast_default_originate/test_bgp_labeled_unicast_default_originate.py b/tests/topotests/bgp_labeled_unicast_default_originate/test_bgp_labeled_unicast_default_originate.py index 34c23d9b6f..d1d384182c 100644 --- a/tests/topotests/bgp_labeled_unicast_default_originate/test_bgp_labeled_unicast_default_originate.py +++ b/tests/topotests/bgp_labeled_unicast_default_originate/test_bgp_labeled_unicast_default_originate.py @@ -42,7 +42,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_large_comm_list_match/test_bgp_large_comm_list_match.py b/tests/topotests/bgp_large_comm_list_match/test_bgp_large_comm_list_match.py index 7023e3a503..49681c6a69 100644 --- a/tests/topotests/bgp_large_comm_list_match/test_bgp_large_comm_list_match.py +++ b/tests/topotests/bgp_large_comm_list_match/test_bgp_large_comm_list_match.py @@ -61,7 +61,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_llgr/test_bgp_llgr.py b/tests/topotests/bgp_llgr/test_bgp_llgr.py index d7897cfcb9..2a3753e26c 100644 --- a/tests/topotests/bgp_llgr/test_bgp_llgr.py +++ b/tests/topotests/bgp_llgr/test_bgp_llgr.py @@ -65,7 +65,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_local_as/test_bgp_local_as.py b/tests/topotests/bgp_local_as/test_bgp_local_as.py index 9e5f146b47..e61bb0d155 100644 --- a/tests/topotests/bgp_local_as/test_bgp_local_as.py +++ b/tests/topotests/bgp_local_as/test_bgp_local_as.py @@ -46,7 +46,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_local_as_dotplus_private_remove/test_bgp_local_as_dotplus_private_remove.py b/tests/topotests/bgp_local_as_dotplus_private_remove/test_bgp_local_as_dotplus_private_remove.py index 930fd791b0..c58322a4c0 100644 --- a/tests/topotests/bgp_local_as_dotplus_private_remove/test_bgp_local_as_dotplus_private_remove.py +++ b/tests/topotests/bgp_local_as_dotplus_private_remove/test_bgp_local_as_dotplus_private_remove.py @@ -63,7 +63,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_local_as_private_remove/test_bgp_local_as_private_remove.py b/tests/topotests/bgp_local_as_private_remove/test_bgp_local_as_private_remove.py index 9d22a799a6..23eb80f316 100644 --- a/tests/topotests/bgp_local_as_private_remove/test_bgp_local_as_private_remove.py +++ b/tests/topotests/bgp_local_as_private_remove/test_bgp_local_as_private_remove.py @@ -50,7 +50,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_lu_explicitnull/test_bgp_lu_explicitnull.py b/tests/topotests/bgp_lu_explicitnull/test_bgp_lu_explicitnull.py index 0656e1ed41..18ffc6a17d 100644 --- a/tests/topotests/bgp_lu_explicitnull/test_bgp_lu_explicitnull.py +++ b/tests/topotests/bgp_lu_explicitnull/test_bgp_lu_explicitnull.py @@ -142,7 +142,7 @@ def test_converge_bgplu(): "192.168.2.2/32", "0", ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "r1, prefix 192.168.2.2/32 from r2 not present" # Check r2 gets prefix 192.168.2.1/32 @@ -153,7 +153,7 @@ def test_converge_bgplu(): "192.168.2.1/32", "0", ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "r2, prefix 192.168.2.1/32 from r1 not present" @@ -178,7 +178,7 @@ def _check_ping(name, dest_addr, src_addr): tgen = get_topogen() func = functools.partial(_check_ping, "r1", "192.168.2.2", "192.168.2.1") # tgen.mininet_cli() - success, result = topotest.run_and_expect(func, None, count=10, wait=0.5) + _, result = topotest.run_and_expect(func, None, count=10, wait=0.5) assert result is None, "r1, ping to 192.168.2.2 from 192.168.2.1 fails" diff --git a/tests/topotests/bgp_max_med_on_startup/test_bgp_max_med_on_startup.py b/tests/topotests/bgp_max_med_on_startup/test_bgp_max_med_on_startup.py index a9810ba264..545d7bd245 100644 --- a/tests/topotests/bgp_max_med_on_startup/test_bgp_max_med_on_startup.py +++ b/tests/topotests/bgp_max_med_on_startup/test_bgp_max_med_on_startup.py @@ -43,7 +43,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -82,17 +82,17 @@ def _bgp_has_routes(router, metric): # Check session is established test_func = functools.partial(_bgp_converge, router2) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) assert result is None, "Failed bgp convergence on r2" # Check metric has value of max-med test_func = functools.partial(_bgp_has_routes, router2, 777) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) assert result is None, "r2 does not receive routes with metric 777" # Check that when the max-med timer expires, metric is updated test_func = functools.partial(_bgp_has_routes, router2, 0) - success, result = topotest.run_and_expect(test_func, None, count=16, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=16, wait=0.5) assert result is None, "r2 does not receive routes with metric 0" diff --git a/tests/topotests/bgp_maximum_prefix_invalid_update/test_bgp_maximum_prefix_invalid_update.py b/tests/topotests/bgp_maximum_prefix_invalid_update/test_bgp_maximum_prefix_invalid_update.py index c6bdbc3c1c..5edc0b55ff 100644 --- a/tests/topotests/bgp_maximum_prefix_invalid_update/test_bgp_maximum_prefix_invalid_update.py +++ b/tests/topotests/bgp_maximum_prefix_invalid_update/test_bgp_maximum_prefix_invalid_update.py @@ -50,7 +50,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_maximum_prefix_out/test_bgp_maximum_prefix_out.py b/tests/topotests/bgp_maximum_prefix_out/test_bgp_maximum_prefix_out.py index 0b346f63d5..aad5f36480 100644 --- a/tests/topotests/bgp_maximum_prefix_out/test_bgp_maximum_prefix_out.py +++ b/tests/topotests/bgp_maximum_prefix_out/test_bgp_maximum_prefix_out.py @@ -45,7 +45,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -177,7 +177,7 @@ def _bgp_converge(router, nb_prefixes): router1.vtysh_cmd(cmd) test_func = functools.partial(_bgp_converge, router2, exp_prfxs) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) assert result is None, 'Failed bgp convergence in "{}"'.format(router2) diff --git a/tests/topotests/bgp_minimum_holdtime/test_bgp_minimum_holdtime.py b/tests/topotests/bgp_minimum_holdtime/test_bgp_minimum_holdtime.py index 9f4d968277..c9ff2ffc7e 100755 --- a/tests/topotests/bgp_minimum_holdtime/test_bgp_minimum_holdtime.py +++ b/tests/topotests/bgp_minimum_holdtime/test_bgp_minimum_holdtime.py @@ -40,7 +40,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -76,7 +76,7 @@ def _bgp_neighbor_check_if_notification_sent(): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_neighbor_check_if_notification_sent) - success, result = topotest.run_and_expect(test_func, None, count=40, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=40, wait=0.5) assert result is None, "Failed to send notification message\n" diff --git a/tests/topotests/bgp_node_target_extcommunities/test_bgp_node_target_extcommunities.py b/tests/topotests/bgp_node_target_extcommunities/test_bgp_node_target_extcommunities.py index 23e820b4fc..b53673ad0f 100644 --- a/tests/topotests/bgp_node_target_extcommunities/test_bgp_node_target_extcommunities.py +++ b/tests/topotests/bgp_node_target_extcommunities/test_bgp_node_target_extcommunities.py @@ -46,7 +46,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname))) tgen.start_router() diff --git a/tests/topotests/bgp_orf/test_bgp_orf.py b/tests/topotests/bgp_orf/test_bgp_orf.py index 47c0556884..bc6a85b4b9 100644 --- a/tests/topotests/bgp_orf/test_bgp_orf.py +++ b/tests/topotests/bgp_orf/test_bgp_orf.py @@ -37,7 +37,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_path_selection/test_bgp_path_selection.py b/tests/topotests/bgp_path_selection/test_bgp_path_selection.py index 30083b4de2..d486a87e9c 100644 --- a/tests/topotests/bgp_path_selection/test_bgp_path_selection.py +++ b/tests/topotests/bgp_path_selection/test_bgp_path_selection.py @@ -57,7 +57,7 @@ def setup_module(mod): tgen.gears["r2"].cmd("ip address add dev vrf1 192.0.2.8/32") tgen.gears["r3"].cmd("ip address add dev vrf1 192.0.2.8/32") - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_peer_graceful_shutdown/test_bgp_peer_graceful_shutdown.py b/tests/topotests/bgp_peer_graceful_shutdown/test_bgp_peer_graceful_shutdown.py index 9269826233..c6ee9aa73c 100644 --- a/tests/topotests/bgp_peer_graceful_shutdown/test_bgp_peer_graceful_shutdown.py +++ b/tests/topotests/bgp_peer_graceful_shutdown/test_bgp_peer_graceful_shutdown.py @@ -34,7 +34,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_peer_group/test_bgp_peer-group.py b/tests/topotests/bgp_peer_group/test_bgp_peer-group.py index 5cbcd19be9..7d476b0538 100644 --- a/tests/topotests/bgp_peer_group/test_bgp_peer-group.py +++ b/tests/topotests/bgp_peer_group/test_bgp_peer-group.py @@ -47,7 +47,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_prefix_list_any/test_bgp_prefix_list_any.py b/tests/topotests/bgp_prefix_list_any/test_bgp_prefix_list_any.py index 5d6440ce6a..1871d3efc8 100644 --- a/tests/topotests/bgp_prefix_list_any/test_bgp_prefix_list_any.py +++ b/tests/topotests/bgp_prefix_list_any/test_bgp_prefix_list_any.py @@ -33,7 +33,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_prefix_sid/test_bgp_prefix_sid.py b/tests/topotests/bgp_prefix_sid/test_bgp_prefix_sid.py index 1e6e731a18..fca60e8cea 100644 --- a/tests/topotests/bgp_prefix_sid/test_bgp_prefix_sid.py +++ b/tests/topotests/bgp_prefix_sid/test_bgp_prefix_sid.py @@ -93,11 +93,11 @@ def _check_type1_r1(router, prefix, remoteLabel, labelIndex): return topotest.json_cmp(output, expected) test_func = functools.partial(_check_type1_r1, router, "3.0.0.1/32", 800001, 1) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert result is None, 'Failed _check_type1_r1 in "{}"'.format(router) test_func = functools.partial(_check_type1_r1, router, "3.0.0.2/32", 800002, 2) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert result is None, 'Failed _check_type1_r1 in "{}"'.format(router) @@ -160,11 +160,11 @@ def _check_type1_peer2(prefix, label): return topotest.json_cmp(output, expected) test_func = functools.partial(_check_type1_peer2, "3.0.0.1/32", label=8001) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert result is None, 'Failed _check_type1_peer2 in "{}"'.format("peer2") test_func = functools.partial(_check_type1_peer2, "3.0.0.2/32", label=8002) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert result is None, 'Failed _check_type1_peer2 in "{}"'.format("peer2") diff --git a/tests/topotests/bgp_reject_as_sets/test_bgp_reject_as_sets.py b/tests/topotests/bgp_reject_as_sets/test_bgp_reject_as_sets.py index 97366ebd53..b9d8ce6819 100644 --- a/tests/topotests/bgp_reject_as_sets/test_bgp_reject_as_sets.py +++ b/tests/topotests/bgp_reject_as_sets/test_bgp_reject_as_sets.py @@ -56,7 +56,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -114,19 +114,19 @@ def _bgp_announce_route_without_as_sets(router): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_converge, router) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, 'Failed bgp convergence in "{}"'.format(router) test_func = functools.partial( _bgp_has_aggregated_route_with_stripped_as_set, router ) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, 'Failed to see an aggregated route in "{}"'.format(router) test_func = functools.partial(_bgp_announce_route_without_as_sets, router) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert ( result is None diff --git a/tests/topotests/bgp_remove_private_as/test_bgp_remove_private_as.py b/tests/topotests/bgp_remove_private_as/test_bgp_remove_private_as.py index e48f81c53d..2d8864c34a 100644 --- a/tests/topotests/bgp_remove_private_as/test_bgp_remove_private_as.py +++ b/tests/topotests/bgp_remove_private_as/test_bgp_remove_private_as.py @@ -109,7 +109,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, f"{rname}/zebra.conf") ) diff --git a/tests/topotests/bgp_remove_private_as_route_map/test_bgp_remove_private_as_route_map.py b/tests/topotests/bgp_remove_private_as_route_map/test_bgp_remove_private_as_route_map.py index d9402f2743..e3e4567aeb 100644 --- a/tests/topotests/bgp_remove_private_as_route_map/test_bgp_remove_private_as_route_map.py +++ b/tests/topotests/bgp_remove_private_as_route_map/test_bgp_remove_private_as_route_map.py @@ -41,7 +41,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname))) tgen.start_router() diff --git a/tests/topotests/bgp_rmap_extcommunity_none/test_bgp_rmap_extcommunity_none.py b/tests/topotests/bgp_rmap_extcommunity_none/test_bgp_rmap_extcommunity_none.py index ef7c94bbab..2e5592e2ab 100644 --- a/tests/topotests/bgp_rmap_extcommunity_none/test_bgp_rmap_extcommunity_none.py +++ b/tests/topotests/bgp_rmap_extcommunity_none/test_bgp_rmap_extcommunity_none.py @@ -43,7 +43,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -86,7 +86,7 @@ def _bgp_converge(router): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_converge, router) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, "BGP Converge failed" def _bgp_extcommunity_strip(router): @@ -111,7 +111,7 @@ def _bgp_extcommunity_strip(router): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_extcommunity_strip, router) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, "Failed to strip incoming extended communities from r2" diff --git a/tests/topotests/bgp_roles_capability/test_bgp_roles_capability.py b/tests/topotests/bgp_roles_capability/test_bgp_roles_capability.py index 52fda695c3..29ff1065fd 100644 --- a/tests/topotests/bgp_roles_capability/test_bgp_roles_capability.py +++ b/tests/topotests/bgp_roles_capability/test_bgp_roles_capability.py @@ -82,7 +82,7 @@ def test_correct_pair(tgen): check_r2_established = functools.partial( check_session_established, router, neighbor_ip ) - success, result = topotest.run_and_expect( + success, _ = topotest.run_and_expect( check_r2_established, True, count=20, wait=3 ) assert success, "Session with r2 is not Established" @@ -100,7 +100,7 @@ def test_role_pair_mismatch(tgen): router = tgen.gears["r3"] neighbor_ip = "192.168.3.1" check_r3_mismatch = functools.partial(check_role_mismatch, router, neighbor_ip) - success, result = topotest.run_and_expect(check_r3_mismatch, True, count=20, wait=3) + success, _ = topotest.run_and_expect(check_r3_mismatch, True, count=20, wait=3) assert success, "Session between r1 and r3 was not correctly closed" @@ -111,7 +111,7 @@ def test_single_role_advertising(tgen): check_r4_established = functools.partial( check_session_established, router, neighbor_ip ) - success, result = topotest.run_and_expect( + success, _ = topotest.run_and_expect( check_r4_established, True, count=20, wait=3 ) assert success, "Session with r4 is not Established" @@ -129,7 +129,7 @@ def test_single_role_receiving(tgen): check_r1_established = functools.partial( check_session_established, router, neighbor_ip ) - success, result = topotest.run_and_expect( + success, _ = topotest.run_and_expect( check_r1_established, True, count=20, wait=3 ) assert success, "Session with r1 is not Established" @@ -145,7 +145,7 @@ def test_role_strict_mode(tgen): router = tgen.gears["r5"] neighbor_ip = "192.168.5.1" check_r5_mismatch = functools.partial(check_role_mismatch, router, neighbor_ip) - success, result = topotest.run_and_expect(check_r5_mismatch, True, count=20, wait=3) + success, _ = topotest.run_and_expect(check_r5_mismatch, True, count=20, wait=3) assert success, "Session between r1 and r5 was not correctly closed" diff --git a/tests/topotests/bgp_roles_filtering/test_bgp_roles_filtering.py b/tests/topotests/bgp_roles_filtering/test_bgp_roles_filtering.py index b3715863b5..a43518bc8a 100644 --- a/tests/topotests/bgp_roles_filtering/test_bgp_roles_filtering.py +++ b/tests/topotests/bgp_roles_filtering/test_bgp_roles_filtering.py @@ -69,7 +69,7 @@ def _routes_half_converged(): ] return output == expected - success, result = topotest.run_and_expect( + success, _ = topotest.run_and_expect( _routes_half_converged, True, count=20, wait=3 ) assert success, "Routes did not converged" diff --git a/tests/topotests/bgp_route_map_delay_timer/test_bgp_route_map_delay_timer.py b/tests/topotests/bgp_route_map_delay_timer/test_bgp_route_map_delay_timer.py index f7a66fdad1..d791ef486b 100644 --- a/tests/topotests/bgp_route_map_delay_timer/test_bgp_route_map_delay_timer.py +++ b/tests/topotests/bgp_route_map_delay_timer/test_bgp_route_map_delay_timer.py @@ -32,7 +32,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_route_map_match_ipv6_nexthop/test_bgp_route_map_match_ipv6_nexthop.py b/tests/topotests/bgp_route_map_match_ipv6_nexthop/test_bgp_route_map_match_ipv6_nexthop.py index 93a514bf6a..35ce092697 100644 --- a/tests/topotests/bgp_route_map_match_ipv6_nexthop/test_bgp_route_map_match_ipv6_nexthop.py +++ b/tests/topotests/bgp_route_map_match_ipv6_nexthop/test_bgp_route_map_match_ipv6_nexthop.py @@ -41,7 +41,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -97,7 +97,7 @@ def _bgp_converge(router): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_converge, router) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, "Can't match routes using ipv6 next-hop access-list" diff --git a/tests/topotests/bgp_route_map_match_source_protocol/test_bgp_route_map_match_source_protocol.py b/tests/topotests/bgp_route_map_match_source_protocol/test_bgp_route_map_match_source_protocol.py index 2828796405..c766f5c1a8 100644 --- a/tests/topotests/bgp_route_map_match_source_protocol/test_bgp_route_map_match_source_protocol.py +++ b/tests/topotests/bgp_route_map_match_source_protocol/test_bgp_route_map_match_source_protocol.py @@ -46,7 +46,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname))) tgen.start_router() diff --git a/tests/topotests/bgp_route_map_on_match_next/test_bgp_route_map_on_match_next.py b/tests/topotests/bgp_route_map_on_match_next/test_bgp_route_map_on_match_next.py index 8fe45a3498..5b5256f43d 100644 --- a/tests/topotests/bgp_route_map_on_match_next/test_bgp_route_map_on_match_next.py +++ b/tests/topotests/bgp_route_map_on_match_next/test_bgp_route_map_on_match_next.py @@ -42,7 +42,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -83,12 +83,12 @@ def _bgp_has_routes(router, metric, weight): # Check thst session is established test_func = functools.partial(_bgp_converge, router2) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) assert result is None, "Failed bgp convergence on r2" # Check that metric is 0 and weight is 100 for the received prefix test_func = functools.partial(_bgp_has_routes, router2, 0, 100) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) assert result is None, "r2 does not receive routes with metric 0 and weight 100" # Update the route-map and add "on-match next" to entry 10 @@ -102,7 +102,7 @@ def _bgp_has_routes(router, metric, weight): # Check that metric is 20 and weight is 100 for the received prefix test_func = functools.partial(_bgp_has_routes, router2, 20, 100) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) assert result is None, "r2 does not receive routes with metric 20 and weight 100" diff --git a/tests/topotests/bgp_route_map_vpn_import/test_bgp_route_map_vpn_import.py b/tests/topotests/bgp_route_map_vpn_import/test_bgp_route_map_vpn_import.py index 37082b484c..5ce8b17f24 100644 --- a/tests/topotests/bgp_route_map_vpn_import/test_bgp_route_map_vpn_import.py +++ b/tests/topotests/bgp_route_map_vpn_import/test_bgp_route_map_vpn_import.py @@ -61,7 +61,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_route_server_client/test_bgp_route_server_client.py b/tests/topotests/bgp_route_server_client/test_bgp_route_server_client.py index 18b7831a4a..29d9842d59 100644 --- a/tests/topotests/bgp_route_server_client/test_bgp_route_server_client.py +++ b/tests/topotests/bgp_route_server_client/test_bgp_route_server_client.py @@ -44,7 +44,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_rpki_topo1/test_bgp_rpki_topo1.py b/tests/topotests/bgp_rpki_topo1/test_bgp_rpki_topo1.py index f52b28a062..7b40bbdae8 100644 --- a/tests/topotests/bgp_rpki_topo1/test_bgp_rpki_topo1.py +++ b/tests/topotests/bgp_rpki_topo1/test_bgp_rpki_topo1.py @@ -44,7 +44,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_sender_as_path_loop_detection/test_bgp_sender-as-path-loop-detection.py b/tests/topotests/bgp_sender_as_path_loop_detection/test_bgp_sender-as-path-loop-detection.py index db6dbc61d2..6983a35173 100644 --- a/tests/topotests/bgp_sender_as_path_loop_detection/test_bgp_sender-as-path-loop-detection.py +++ b/tests/topotests/bgp_sender_as_path_loop_detection/test_bgp_sender-as-path-loop-detection.py @@ -50,7 +50,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) 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 d373a749fe..64cc48e54f 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 @@ -46,7 +46,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_set_aspath_replace/test_bgp_set_aspath_replace.py b/tests/topotests/bgp_set_aspath_replace/test_bgp_set_aspath_replace.py index c0e19fa356..fe4eda60f5 100644 --- a/tests/topotests/bgp_set_aspath_replace/test_bgp_set_aspath_replace.py +++ b/tests/topotests/bgp_set_aspath_replace/test_bgp_set_aspath_replace.py @@ -48,7 +48,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_set_local_preference_add_subtract/test_bgp_set_local-preference_add_subtract.py b/tests/topotests/bgp_set_local_preference_add_subtract/test_bgp_set_local-preference_add_subtract.py index 292cf70d36..e201ec9ff7 100644 --- a/tests/topotests/bgp_set_local_preference_add_subtract/test_bgp_set_local-preference_add_subtract.py +++ b/tests/topotests/bgp_set_local_preference_add_subtract/test_bgp_set_local-preference_add_subtract.py @@ -47,7 +47,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -100,12 +100,12 @@ def _bgp_check_local_preference(router): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_converge, router) - success, result = topotest.run_and_expect(test_func, None, count=15, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=15, wait=0.5) assert result is None, 'Failed to see BGP convergence in "{}"'.format(router) test_func = functools.partial(_bgp_check_local_preference, router) - success, result = topotest.run_and_expect(test_func, None, count=15, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=15, wait=0.5) assert result is None, 'Failed to see applied BGP local-preference in "{}"'.format( router diff --git a/tests/topotests/bgp_software_version/test_bgp_software_version.py b/tests/topotests/bgp_software_version/test_bgp_software_version.py index c867208d39..9aff53a030 100644 --- a/tests/topotests/bgp_software_version/test_bgp_software_version.py +++ b/tests/topotests/bgp_software_version/test_bgp_software_version.py @@ -34,7 +34,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_soo/test_bgp_soo.py b/tests/topotests/bgp_soo/test_bgp_soo.py index 967bed0213..b0c70f208e 100644 --- a/tests/topotests/bgp_soo/test_bgp_soo.py +++ b/tests/topotests/bgp_soo/test_bgp_soo.py @@ -73,7 +73,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_srv6l3vpn_sid/test_bgp_srv6l3vpn_sid.py b/tests/topotests/bgp_srv6l3vpn_sid/test_bgp_srv6l3vpn_sid.py index 984cf97e28..787707cc0f 100755 --- a/tests/topotests/bgp_srv6l3vpn_sid/test_bgp_srv6l3vpn_sid.py +++ b/tests/topotests/bgp_srv6l3vpn_sid/test_bgp_srv6l3vpn_sid.py @@ -106,7 +106,7 @@ def setup_module(mod): tgen = Topogen(build_topo, mod.__name__) tgen.start_topology() router_list = tgen.routers() - for i, (rname, router) in enumerate(tgen.routers().items(), 1): + for _, (rname, router) in enumerate(tgen.routers().items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -180,7 +180,7 @@ def _check(name, cmd, expected_file): logger.info('[+] check {} "{}" {}'.format(name, cmd, expected_file)) tgen = get_topogen() func = functools.partial(_check, name, cmd, expected_file) - success, result = topotest.run_and_expect(func, None, count=10, wait=0.5) + _, result = topotest.run_and_expect(func, None, count=10, wait=0.5) assert result is None, "Failed" diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/test_bgp_srv6l3vpn_to_bgp_vrf.py b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/test_bgp_srv6l3vpn_to_bgp_vrf.py index 4afaeaf78a..5d18083fd5 100755 --- a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/test_bgp_srv6l3vpn_to_bgp_vrf.py +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/test_bgp_srv6l3vpn_to_bgp_vrf.py @@ -147,7 +147,7 @@ def _check(name, cmd, expected_file): logger.info('[+] check {} "{}" {}'.format(name, cmd, expected_file)) tgen = get_topogen() func = functools.partial(_check, name, cmd, expected_file) - success, result = topotest.run_and_expect(func, None, count=10, wait=0.5) + _, result = topotest.run_and_expect(func, None, count=10, wait=0.5) assert result is None, "Failed" diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/test_bgp_srv6l3vpn_to_bgp_vrf2.py b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/test_bgp_srv6l3vpn_to_bgp_vrf2.py index 914c29f0c1..38baf43442 100755 --- a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/test_bgp_srv6l3vpn_to_bgp_vrf2.py +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/test_bgp_srv6l3vpn_to_bgp_vrf2.py @@ -109,7 +109,7 @@ def _check(name, dest_addr, match): logger.info('[+] check {} "{}" {}'.format(name, cmd, expected_file)) tgen = get_topogen() func = functools.partial(_check, name, cmd, expected_file) - success, result = topotest.run_and_expect(func, None, count=10, wait=0.5) + _, result = topotest.run_and_expect(func, None, count=10, wait=0.5) assert result is None, "Failed" diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/test_bgp_srv6l3vpn_to_bgp_vrf3.py b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/test_bgp_srv6l3vpn_to_bgp_vrf3.py index 8a7b558be3..92a30788fc 100644 --- a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/test_bgp_srv6l3vpn_to_bgp_vrf3.py +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/test_bgp_srv6l3vpn_to_bgp_vrf3.py @@ -106,7 +106,7 @@ def _check(name, dest_addr, match): logger.info('[+] check {} "{}" {}'.format(name, cmd, expected_file)) tgen = get_topogen() func = functools.partial(_check, name, cmd, expected_file) - success, result = topotest.run_and_expect(func, None, count=10, wait=0.5) + _, result = topotest.run_and_expect(func, None, count=10, wait=0.5) assert result is None, "Failed" diff --git a/tests/topotests/bgp_suppress_fib/test_bgp_suppress_fib.py b/tests/topotests/bgp_suppress_fib/test_bgp_suppress_fib.py index ec14ef065f..fa8a88297f 100644 --- a/tests/topotests/bgp_suppress_fib/test_bgp_suppress_fib.py +++ b/tests/topotests/bgp_suppress_fib/test_bgp_suppress_fib.py @@ -47,7 +47,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_tcp_mss/test_bgp_tcp_mss.py b/tests/topotests/bgp_tcp_mss/test_bgp_tcp_mss.py index 4855d5c7d2..37949cdc99 100644 --- a/tests/topotests/bgp_tcp_mss/test_bgp_tcp_mss.py +++ b/tests/topotests/bgp_tcp_mss/test_bgp_tcp_mss.py @@ -52,7 +52,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -108,7 +108,7 @@ def _bgp_check_neighbor_tcp_mss(router, neigh): logger.info("Check if neighbor sessions are up in {}".format(router1.name)) test_func = functools.partial(_bgp_converge, router1) - success, result = topotest.run_and_expect(test_func, None, count=15, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=15, wait=0.5) assert result is None, 'Failed to see BGP convergence in "{}"'.format(router1.name) logger.info("BGP neighbor session is up in {}".format(router1.name)) @@ -129,7 +129,7 @@ def _bgp_check_neighbor_tcp_mss(router, neigh): "Check if neighbor session is up after reset in {}".format(router1.name) ) test_func = functools.partial(_bgp_converge, router1) - success, result = topotest.run_and_expect(test_func, None, count=15, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=15, wait=0.5) assert result is None, 'Failed to see BGP convergence after reset in "{}"'.format( router1.name ) @@ -138,7 +138,7 @@ def _bgp_check_neighbor_tcp_mss(router, neigh): "Verify if TCP MSS value is synced with neighbor in {}".format(router1.name) ) test_func = functools.partial(_bgp_check_neighbor_tcp_mss, router1, "192.168.255.2") - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert ( result is None ), 'Failed to sync TCP MSS value over BGP session in "{}"'.format(router1.name) @@ -148,7 +148,7 @@ def _bgp_check_neighbor_tcp_mss(router, neigh): "Verify if TCP MSS value is synced with neighbor in {}".format(router2.name) ) test_func = functools.partial(_bgp_check_neighbor_tcp_mss, router2, "192.168.255.1") - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert ( result is None ), 'Failed to sync TCP MSS value over BGP session in "{}"'.format(router2.name) diff --git a/tests/topotests/bgp_tcp_mss_passive/test_bgp_tcp_mss_passive.py b/tests/topotests/bgp_tcp_mss_passive/test_bgp_tcp_mss_passive.py index cd405f7b22..a2eacc7ab2 100644 --- a/tests/topotests/bgp_tcp_mss_passive/test_bgp_tcp_mss_passive.py +++ b/tests/topotests/bgp_tcp_mss_passive/test_bgp_tcp_mss_passive.py @@ -41,7 +41,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname))) tgen.start_router() diff --git a/tests/topotests/bgp_unnumbered/test_bgp_unnumbered.py b/tests/topotests/bgp_unnumbered/test_bgp_unnumbered.py index 2a53547f59..4d4e29b2f8 100644 --- a/tests/topotests/bgp_unnumbered/test_bgp_unnumbered.py +++ b/tests/topotests/bgp_unnumbered/test_bgp_unnumbered.py @@ -42,7 +42,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -84,7 +84,7 @@ def _bgp_converge(): step("Ensure Convergence of BGP") test_func = functools.partial(_bgp_converge) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) assert result is None, 'Failed bgp convergence in "{}"'.format(tgen.gears["r2"]) @@ -109,7 +109,7 @@ def _bgp_converge(): step("Ensure that BGP does not crash") test_func = functools.partial(_bgp_nexthop_cache) - success, result = topotest.run_and_expect(test_func, True, count=10, wait=1) + _, result = topotest.run_and_expect(test_func, True, count=10, wait=1) assert result is True, "BGP did not crash on r1" diff --git a/tests/topotests/bgp_update_delay/test_bgp_update_delay.py b/tests/topotests/bgp_update_delay/test_bgp_update_delay.py index 4e66cf5548..59f4bcd385 100644 --- a/tests/topotests/bgp_update_delay/test_bgp_update_delay.py +++ b/tests/topotests/bgp_update_delay/test_bgp_update_delay.py @@ -90,7 +90,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -169,7 +169,7 @@ def _bgp_check_vrf_update_delay_and_wait(router): # Check r2 initial convergence in default table test_func = functools.partial(_bgp_converge, router2) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) assert result is None, 'Failed bgp convergence in "{}"'.format(router2) @@ -195,7 +195,7 @@ def _bgp_check_vrf_update_delay_and_wait(router): router2.vtysh_cmd("""clear ip bgp *""") test_func = functools.partial(_bgp_check_update_delay_in_progress, router2) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) assert result is None, 'Failed to set update-delay max-delay timer "{}"'.format( router2 @@ -203,7 +203,7 @@ def _bgp_check_vrf_update_delay_and_wait(router): # Check that r2 only installs route learned from r4 after the max-delay timer expires test_func = functools.partial(_bgp_check_route_install, router2) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) assert result is None, 'Failed to install route after update-delay "{}"'.format( router2 @@ -219,7 +219,7 @@ def _bgp_check_vrf_update_delay_and_wait(router): ) test_func = functools.partial(_bgp_check_update_delay_and_wait, router2) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) assert ( result is None @@ -229,7 +229,7 @@ def _bgp_check_vrf_update_delay_and_wait(router): router2.vtysh_cmd("""clear ip bgp *""") test_func = functools.partial(_bgp_check_route_install, router3) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) assert ( result is None @@ -250,7 +250,7 @@ def _bgp_check_vrf_update_delay_and_wait(router): router2.vtysh_cmd("""clear ip bgp *""") test_func = functools.partial(_bgp_check_route_install, router2) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) assert result is None, 'Failed to remove update-delay delay timing "{}"'.format( router2 @@ -266,14 +266,14 @@ def _bgp_check_vrf_update_delay_and_wait(router): # Check that r2 default instance and vrf1 have the max-delay and establish set test_func = functools.partial(_bgp_check_update_delay_and_wait, router2) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) assert result is None, 'Failed to set update-delay in default instance "{}"'.format( router2 ) test_func = functools.partial(_bgp_check_vrf_update_delay_and_wait, router2) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) assert result is None, 'Failed to set update-delay in vrf1 "{}"'.format(router2) @@ -281,7 +281,7 @@ def _bgp_check_vrf_update_delay_and_wait(router): router2.vtysh_cmd("""clear ip bgp *""") test_func = functools.partial(_bgp_check_route_install, router3) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) assert ( result is None diff --git a/tests/topotests/bgp_vpn_5549_route_map/test_bgp_vpn_5549_route_map.py b/tests/topotests/bgp_vpn_5549_route_map/test_bgp_vpn_5549_route_map.py index eb29875d50..695cfc3d25 100644 --- a/tests/topotests/bgp_vpn_5549_route_map/test_bgp_vpn_5549_route_map.py +++ b/tests/topotests/bgp_vpn_5549_route_map/test_bgp_vpn_5549_route_map.py @@ -67,7 +67,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_vpnv4_asbr/test_bgp_vpnv4_asbr.py b/tests/topotests/bgp_vpnv4_asbr/test_bgp_vpnv4_asbr.py index 39865eb189..8e2e4017df 100644 --- a/tests/topotests/bgp_vpnv4_asbr/test_bgp_vpnv4_asbr.py +++ b/tests/topotests/bgp_vpnv4_asbr/test_bgp_vpnv4_asbr.py @@ -203,7 +203,7 @@ def _check(router, prefix, rd, label, nexthop): ) func = functools.partial(_check, router, prefix, rd, label, nexthop) - success, result = topotest.run_and_expect(func, None, count=20, wait=0.5) + _, result = topotest.run_and_expect(func, None, count=20, wait=0.5) assert_msg = "{}, show bgp ipv4 vpn {}, rd {}, label {} nexthop {}".format( router.name, prefix, rd, label, nexthop ) @@ -324,7 +324,7 @@ def _check_nexthop_available(router, prefix): for prefix, rname_to_test in vpnv4_entries.items(): func = functools.partial(_check_nexthop_available, router, prefix) - success, result = topotest.run_and_expect(func, None, count=20, wait=0.5) + _, result = topotest.run_and_expect(func, None, count=20, wait=0.5) assert result is None, "Failed to detect prefix {} on router {}".format( prefix, router.name ) @@ -456,7 +456,7 @@ def test_r3_prefixes_removed(): prefix, "444:3", ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "{}, vpnv4 update {} still present".format(router.name, prefix) # diagnostic @@ -491,7 +491,7 @@ def test_r3_prefixes_removed(): prefix, "444:3", ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "{}, vpnv4 update {} still present".format(router.name, prefix) logger.info( @@ -502,7 +502,7 @@ def test_r3_prefixes_removed(): test_func = functools.partial( check_show_mpls_table_entry_label_not_found, router, label_ip_entries[prefix] ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "r1, mpls entry with in_label {} still present".format( label_ip_entries[prefix] ) @@ -536,7 +536,7 @@ def test_r3_prefixes_added_back(): prefix, "444:3", ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "{}, vpnv4 update {} not present".format(router.name, prefix) logger.info( @@ -564,7 +564,7 @@ def test_r3_prefixes_added_back(): prefix, "444:3", ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "{}, vpnv4 update {} not present".format(router.name, prefix) # diagnostic @@ -611,7 +611,7 @@ def test_unconfigure_nexthop_change_nexthop_self(): test_func = functools.partial( check_show_mpls_table_entry_label_not_found, router, label ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "r1, mpls entry for {} with in_label {} still present".format( prefix, label ) @@ -626,7 +626,7 @@ def test_unconfigure_nexthop_change_nexthop_self(): "444:3", label=label, ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "{}, mpls vpn update {} label {} is present".format( router.name, prefix, label ) @@ -639,7 +639,7 @@ def test_unconfigure_nexthop_change_nexthop_self(): "444:3", nexthop="192.168.1.3", ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "{}, mpls vpn update {} label {} is present".format( router.name, prefix, label ) @@ -727,7 +727,7 @@ def test_declare_vpn_network_with_different_label(): label=label, nexthop="192.168.1.3", ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "{}, vpnv4 update {}, label {} not present".format( router.name, prefix, label ) @@ -787,7 +787,7 @@ def test_filter_vpn_network_from_r1(): "172.31.0.0/24", "444:1", ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "{}, vpnv4 update {}, is still present".format( router.name, prefix ) @@ -804,7 +804,7 @@ def test_filter_vpn_network_from_r1(): test_func = functools.partial( check_show_mpls_table_entry_label_not_found, router, int(label) ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "r1, mpls entry for {} with in_label {} still present".format( prefix, label ) @@ -833,7 +833,7 @@ def test_unfilter_vpn_network_from_r1(): test_func = functools.partial( check_show_bgp_vpn_prefix_found, router, "ipv4", prefix, "444:1" ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "{}, vpnv4 update {}, is not present".format(router.name, prefix) vpnv4_checks = { diff --git a/tests/topotests/bgp_vpnv4_ebgp/test_bgp_vpnv4_ebgp.py b/tests/topotests/bgp_vpnv4_ebgp/test_bgp_vpnv4_ebgp.py index 189824311d..dd9d54742b 100644 --- a/tests/topotests/bgp_vpnv4_ebgp/test_bgp_vpnv4_ebgp.py +++ b/tests/topotests/bgp_vpnv4_ebgp/test_bgp_vpnv4_ebgp.py @@ -245,7 +245,7 @@ def test_export_route_target_empty(): prefix, "444:1", ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "{}, vpnv4 update {} still present".format(router.name, prefix) @@ -279,7 +279,7 @@ def test_export_route_target_with_routemap_with_export_route_target(): prefix, "444:1", ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "{}, vpnv4 update {} still not present".format(router.name, prefix) @@ -309,7 +309,7 @@ def test_export_route_target_with_routemap_without_export_route_target(): prefix, "444:1", ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "{}, vpnv4 update {} still present".format(router.name, prefix) @@ -339,7 +339,7 @@ def test_export_route_target_with_default_command(): prefix, "444:1", ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "{}, vpnv4 update {} still not present".format(router.name, prefix) @@ -371,7 +371,7 @@ def test_export_suppress_route_target_with_route_map_command(): prefix, "444:1", ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "{}, vpnv4 update {} still present".format(router.name, prefix) @@ -400,7 +400,7 @@ def test_export_add_route_target_to_route_map_command(): prefix, "444:1", ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "{}, vpnv4 update {} still not present".format(router.name, prefix) @@ -482,7 +482,7 @@ def test_adj_rib_in_label_change(): expected, exact=True, ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "r2, vpnv4 update 172.31.0.1 still present" diff --git a/tests/topotests/bgp_vpnv4_per_nexthop_label/test_bgp_vpnv4_per_nexthop_label.py b/tests/topotests/bgp_vpnv4_per_nexthop_label/test_bgp_vpnv4_per_nexthop_label.py index d4c355a44a..b017880545 100644 --- a/tests/topotests/bgp_vpnv4_per_nexthop_label/test_bgp_vpnv4_per_nexthop_label.py +++ b/tests/topotests/bgp_vpnv4_per_nexthop_label/test_bgp_vpnv4_per_nexthop_label.py @@ -174,7 +174,7 @@ def bgp_vpnv4_table_check(router, group, label_list=None, label_value_expected=N stored_label_inited = False for prefix in group: test_func = functools.partial(check_bgp_vpnv4_prefix_presence, router, prefix) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "{}, prefix ipv4 vpn {} is not installed yet".format( router.name, prefix ) @@ -305,7 +305,7 @@ def mpls_table_check(router, blacklist=None, label_list=None, whitelist=None): test_func = functools.partial( check_show_mpls_table, router, blacklist, label_list, whitelist ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "{}, MPLS labels check fail: {}".format(router.name, result) @@ -450,7 +450,7 @@ def _bgp_prefix_not_found(router, vrf, ipversion, prefix): test_func = functools.partial( _bgp_prefix_not_found, tgen.gears["r1"], "vrf1", "ipv4", "172.31.0.11/32" ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert ( success ), "r1, prefix 172.31.0.11/32 from r11 did not disappear. r11 still connected to rr ?" @@ -488,7 +488,7 @@ def test_flapping_bgp_vrf_up(): "172.31.0.11/32", "444:1", ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert ( success ), "r2, prefix 172.31.0.11/32 from r11 not present. r11 still disconnected from rr ?" @@ -518,7 +518,7 @@ def test_recursive_route(): "172.31.0.30/32", "444:1", ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "r2, vpnv4 update 172.31.0.30 not found" bgp_vpnv4_table_check(tgen.gears["r2"], group=PREFIXES_R11 + ["172.31.0.30/32"]) @@ -544,7 +544,7 @@ def test_recursive_route(): "172.31.0.30/32", "444:1", ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "r2, vpnv4 update 172.31.0.30 still present" @@ -570,7 +570,7 @@ def test_prefix_changes_interface(): "172.31.0.50/32", "444:1", ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "r2, vpnv4 update 172.31.0.50 not found" # diagnostic @@ -616,7 +616,7 @@ def test_prefix_changes_interface(): "444:1", label=oldlabel, ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert ( success ), "r2, vpnv4 update 172.31.0.50 with old label {0} still present".format(oldlabel) @@ -633,7 +633,7 @@ def test_prefix_changes_interface(): "172.31.0.50/32", "444:1", ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "r2, vpnv4 update 172.31.0.50 not found" label_list = set() @@ -699,7 +699,7 @@ def test_changing_default_label_value(): test_func = functools.partial( check_show_mpls_table_entry_label_found, router, 222, "vrf1" ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "r1, mpls entry with label 222 not found" # check label repartition is ok @@ -746,7 +746,7 @@ def test_unconfigure_allocation_mode_nexthop(): test_func = functools.partial( check_show_mpls_table_entry_label_not_found, router, 17 ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "r1, mpls entry with label 17 still present" # Check vpnv4 routes from r1 @@ -794,7 +794,7 @@ def test_reconfigure_allocation_mode_nexthop(): test_func = functools.partial( check_show_mpls_table_entry_label_not_found, router, 17 ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "r1, mpls entry with label 17 still present" # Check vpnv4 routes from r1 diff --git a/tests/topotests/bgp_vpnv6_per_nexthop_label/test_bgp_vpnv6_per_nexthop_label.py b/tests/topotests/bgp_vpnv6_per_nexthop_label/test_bgp_vpnv6_per_nexthop_label.py index 3d5f8f643b..3879687aac 100644 --- a/tests/topotests/bgp_vpnv6_per_nexthop_label/test_bgp_vpnv6_per_nexthop_label.py +++ b/tests/topotests/bgp_vpnv6_per_nexthop_label/test_bgp_vpnv6_per_nexthop_label.py @@ -173,7 +173,7 @@ def bgp_vpnv6_table_check(router, group, label_list=None, label_value_expected=N stored_label_inited = False for prefix in group: test_func = functools.partial(check_bgp_vpnv6_prefix_presence, router, prefix) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "{}, prefix ipv6 vpn {} is not installed yet".format( router.name, prefix ) @@ -300,7 +300,7 @@ def mpls_table_check(router, blacklist=None, label_list=None, whitelist=None): test_func = functools.partial( check_show_mpls_table, router, blacklist, label_list, whitelist ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "{}, MPLS labels check fail: {}".format(router.name, result) @@ -446,7 +446,7 @@ def _bgp_prefix_not_found(router, vrf, ipversion, prefix): test_func = functools.partial( _bgp_prefix_not_found, tgen.gears["r1"], "vrf1", "ipv6", "172:31::11/128" ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert ( success ), "r1, prefix 172:31::11/128 from r11 did not disappear. r11 still connected to rr ?" @@ -488,7 +488,7 @@ def test_flapping_bgp_vrf_up(): "172:31::11/128", "444:1", ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert ( success ), "r2, prefix 172:31::11/128 from r11 not present. r11 still disconnected from rr ?" @@ -526,7 +526,7 @@ def _prefix30_found(router): # Check r2 received vpnv6 update with 172:31::30 test_func = functools.partial(_prefix30_found, tgen.gears["r2"]) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "r2, VPNv6 update 172:31::30 not found" # that route should be sent along with label for 192::2:11 @@ -549,7 +549,7 @@ def _prefix30_found(router): # Check r2 removed 172:31::30 vpnv6 update test_func = functools.partial(_prefix30_not_found, tgen.gears["r2"]) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "r2, VPNv6 update 172:31::30 still present" @@ -575,7 +575,7 @@ def test_prefix_changes_interface(): "172:31::50/128", "444:1", ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "r2, VPNv6 update 172:31::50 not found" # diagnostic @@ -621,7 +621,7 @@ def test_prefix_changes_interface(): "444:1", label=oldlabel, ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert ( success ), "r2, vpnv6 update 172:31::50 with old label {0} still present".format(oldlabel) @@ -638,7 +638,7 @@ def test_prefix_changes_interface(): "172:31::50/128", "444:1", ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "r2, vpnv6 update 172:31::50 not found" label_list = set() @@ -704,7 +704,7 @@ def test_changing_default_label_value(): test_func = functools.partial( check_show_mpls_table_entry_label_found, router, 222, "vrf1" ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "r1, mpls entry with label 222 not found" # check label repartition is ok @@ -750,7 +750,7 @@ def test_unconfigure_allocation_mode_nexthop(): test_func = functools.partial( check_show_mpls_table_entry_label_not_found, router, 17 ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "r1, mpls entry with label 17 still present" # Check vpnv6 routes from r1 From e8f5caa21bde40148bc5a8f6cecfe2ca78016fe2 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Wed, 12 Jun 2024 16:28:38 +0300 Subject: [PATCH 026/347] ospfd: Fix memory leak after cleaning cleaning up interfaceIp JSON field ``` ================================================================= ==6717==ERROR: LeakSanitizer: detected memory leaks Direct leak of 1008 byte(s) in 14 object(s) allocated from: 0 0x7f9ea0dc7d28 in __interceptor_calloc (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xded28) 1 0x7f9ea034d51f in json_object_new_object (/lib/x86_64-linux-gnu/libjson-c.so.3+0x351f) 2 0x564b56d0fed6 in show_ip_ospf_interface_common ospfd/ospf_vty.c:4011 3 0x564b56d1068c in show_ip_ospf_interface ospfd/ospf_vty.c:4285 4 0x7f9ea06fe1c0 in cmd_execute_command_real lib/command.c:1002 5 0x7f9ea06fe684 in cmd_execute_command lib/command.c:1060 6 0x7f9ea06feb03 in cmd_execute lib/command.c:1227 7 0x7f9ea08415b2 in vty_command lib/vty.c:616 8 0x7f9ea0841a5d in vty_execute lib/vty.c:1379 9 0x7f9ea084b367 in vtysh_read lib/vty.c:2374 10 0x7f9ea08350cd in event_call lib/event.c:2011 11 0x7f9ea0764386 in frr_run lib/libfrr.c:1217 12 0x564b56c25b18 in main ospfd/ospf_main.c:295 13 0x7f9e9fd5bc86 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21c86) Indirect leak of 7168 byte(s) in 14 object(s) allocated from: 0 0x7f9ea0dc7d28 in __interceptor_calloc (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xded28) 1 0x7f9ea0350fa4 in lh_table_new (/lib/x86_64-linux-gnu/libjson-c.so.3+0x6fa4) Indirect leak of 1232 byte(s) in 14 object(s) allocated from: 0 0x7f9ea0dc7d28 in __interceptor_calloc (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xded28) 1 0x7f9ea0350f82 in lh_table_new (/lib/x86_64-linux-gnu/libjson-c.so.3+0x6f82) SUMMARY: AddressSanitizer: 9408 byte(s) leaked in 42 allocation(s). *********************************************************************************** ``` Fixes: e24ff4c275f0729f75be9f68d08be80ac1e0ec56 ("ospfd: Drop `interfaceIp` from `show ip ospf neigh json") Signed-off-by: Donatas Abraitis --- ospfd/ospf_vty.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index 21acd402f4..3a11b21232 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -3576,7 +3576,6 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, struct route_node *rn; uint32_t bandwidth = ifp->bandwidth ? ifp->bandwidth : ifp->speed; struct ospf_if_params *params; - json_object *json_oi = NULL; /* Is interface up? */ if (use_json) { @@ -3633,12 +3632,9 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, if (oi == NULL) continue; - if (use_json) - json_oi = json_object_new_object(); - if (CHECK_FLAG(oi->connected->flags, ZEBRA_IFA_UNNUMBERED)) { if (use_json) - json_object_boolean_true_add(json_oi, + json_object_boolean_true_add(json_interface_sub, "ifUnnumbered"); else vty_out(vty, " This interface is UNNUMBERED,"); @@ -3932,8 +3928,6 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, /* OSPF Authentication information */ ospf_interface_auth_show(vty, oi, json_interface_sub, use_json); - ospf_interface_auth_show(vty, oi, json_oi, use_json); - /* Point-to-Multipoint Interface options. */ if (oi->type == OSPF_IFTYPE_POINTOMULTIPOINT) { if (use_json) From d8e3121cb8470fe9a934100de9170b4ef48b17a6 Mon Sep 17 00:00:00 2001 From: Jafar Al-Gharaibeh Date: Wed, 12 Jun 2024 12:03:21 -0500 Subject: [PATCH 027/347] build: FRR 10.2 development version Signed-off-by: Jafar Al-Gharaibeh --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index cad8ea12c0..ec409aaf1d 100644 --- a/configure.ac +++ b/configure.ac @@ -7,7 +7,7 @@ ## AC_PREREQ([2.69]) -AC_INIT([frr], [10.1-dev], [https://github.com/frrouting/frr/issues]) +AC_INIT([frr], [10.2-dev], [https://github.com/frrouting/frr/issues]) PACKAGE_URL="https://frrouting.org/" AC_SUBST([PACKAGE_URL]) PACKAGE_FULLNAME="FRRouting" From 5d7af51c4f7980507135babd94d392ca179c1bf7 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Wed, 12 Jun 2024 22:54:45 +0300 Subject: [PATCH 028/347] bgpd: Check if we have really enough data before doing memcpy for software version If we receive CAPABILITY message (software-version), we SHOULD check if we really have enough data before doing memcpy(), that could also lead to buffer overflow. (data + len > end) is not enough, because after this check we do data++ and later memcpy(..., data, len). That means we have one more byte. Hit this through fuzzing by ``` 0 0xaaaaaadf872c in __asan_memcpy (/home/ubuntu/frr-public/frr_public_private-libfuzzer/bgpd/.libs/bgpd+0x35872c) (BuildId: 9c6e455d0d9a20f5a4d2f035b443f50add9564d7) 1 0xaaaaab06bfbc in bgp_dynamic_capability_software_version /home/ubuntu/frr-public/frr_public_private-libfuzzer/bgpd/bgp_packet.c:3713:3 2 0xaaaaab05ccb4 in bgp_capability_msg_parse /home/ubuntu/frr-public/frr_public_private-libfuzzer/bgpd/bgp_packet.c:3839:4 3 0xaaaaab05c074 in bgp_capability_receive /home/ubuntu/frr-public/frr_public_private-libfuzzer/bgpd/bgp_packet.c:3980:9 4 0xaaaaab05e48c in bgp_process_packet /home/ubuntu/frr-public/frr_public_private-libfuzzer/bgpd/bgp_packet.c:4109:11 5 0xaaaaaae36150 in LLVMFuzzerTestOneInput /home/ubuntu/frr-public/frr_public_private-libfuzzer/bgpd/bgp_main.c:582:3 ``` Hit this again by Iggy \m/ Reported-by: Iggy Frankovic Signed-off-by: Donatas Abraitis --- bgpd/bgp_packet.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index 3f38790cbd..5d97894326 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -3694,7 +3694,7 @@ static void bgp_dynamic_capability_software_version(uint8_t *pnt, int action, char soft_version[BGP_MAX_SOFT_VERSION + 1] = {}; if (action == CAPABILITY_ACTION_SET) { - if (data + len > end) { + if (data + len + 1 > end) { zlog_err("%pBP: Received invalid Software Version capability length %d", peer, len); return; From b685ab5e1bdec0848502c20e9596b9716b236639 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Thu, 13 Jun 2024 08:12:10 +0300 Subject: [PATCH 029/347] bgpd: Check if we have really enough data before doing memcpy for FQDN capability We advance data pointer (data++), but we do memcpy() with the length that is 1-byte over, which is technically heap overflow. ``` ==411461==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x50600011da1a at pc 0xc4f45a9786f0 bp 0xffffed1e2740 sp 0xffffed1e1f30 READ of size 4 at 0x50600011da1a thread T0 0 0xc4f45a9786ec in __asan_memcpy (/home/ubuntu/frr-public/frr_public_private-libfuzzer/bgpd/.libs/bgpd+0x3586ec) (BuildId: e794c5f796eee20c8973d7efb9bf5735e54d44cd) 1 0xc4f45abf15f8 in bgp_dynamic_capability_fqdn /home/ubuntu/frr-public/frr_public_private-libfuzzer/bgpd/bgp_packet.c:3457:4 2 0xc4f45abdd408 in bgp_capability_msg_parse /home/ubuntu/frr-public/frr_public_private-libfuzzer/bgpd/bgp_packet.c:3911:4 3 0xc4f45abdbeb4 in bgp_capability_receive /home/ubuntu/frr-public/frr_public_private-libfuzzer/bgpd/bgp_packet.c:3980:9 4 0xc4f45abde2cc in bgp_process_packet /home/ubuntu/frr-public/frr_public_private-libfuzzer/bgpd/bgp_packet.c:4109:11 5 0xc4f45a9b6110 in LLVMFuzzerTestOneInput /home/ubuntu/frr-public/frr_public_private-libfuzzer/bgpd/bgp_main.c:582:3 ``` Found by fuzzing. Reported-by: Iggy Frankovic Signed-off-by: Donatas Abraitis --- bgpd/bgp_packet.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index 3f38790cbd..e54766aa39 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -3437,7 +3437,7 @@ static void bgp_dynamic_capability_fqdn(uint8_t *pnt, int action, } len = *data; - if (data + len > end) { + if (data + len + 1 > end) { zlog_err("%pBP: Received invalid FQDN capability length (host name) %d", peer, hdr->length); return; @@ -3468,7 +3468,7 @@ static void bgp_dynamic_capability_fqdn(uint8_t *pnt, int action, /* domainname */ len = *data; - if (data + len > end) { + if (data + len + 1 > end) { zlog_err("%pBP: Received invalid FQDN capability length (domain name) %d", peer, len); return; From 34b209f0ae2caca0d1ebcde9d4095375ac31b562 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Thu, 13 Jun 2024 08:43:21 +0300 Subject: [PATCH 030/347] bgpd: Adjust the length of tunnel encap sub-tlv by sub-tlv type Fixes: 79563af564ad0fe5b9c8d95bf080d570f87b1859 ("bgpd: Get 1 or 2 octets for Sub-TLV length (Tunnel Encap attr)") Signed-off-by: Donatas Abraitis --- bgpd/bgp_attr.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index da4701d069..9f377589e9 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -2728,10 +2728,13 @@ static int bgp_attr_encap(struct bgp_attr_parser_args *args) if (BGP_ATTR_ENCAP == type) { subtype = stream_getc(BGP_INPUT(peer)); - sublength = (subtype < 128) - ? stream_getc(BGP_INPUT(peer)) - : stream_getw(BGP_INPUT(peer)); - length -= 2; + if (subtype < 128) { + sublength = stream_getc(BGP_INPUT(peer)); + length -= 2; + } else { + sublength = stream_getw(BGP_INPUT(peer)); + length -= 3; + } #ifdef ENABLE_BGP_VNC } else { subtype = stream_getw(BGP_INPUT(peer)); From 9929486d6bdb28469a5b626a17d5bc9991c83ce3 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Thu, 13 Jun 2024 09:00:21 +0300 Subject: [PATCH 031/347] bgpd: Check if we have real stream data for tunnel encapsulation sub-tlvs When the packet is malformed it can use whatever values it wants. Let's check what the real data we have in a stream instead of relying on malformed values. Reported-by: Iggy Frankovic Signed-off-by: Donatas Abraitis --- bgpd/bgp_attr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 9f377589e9..18c7b13535 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -2721,7 +2721,7 @@ static int bgp_attr_encap(struct bgp_attr_parser_args *args) } } - while (length >= 4) { + while (STREAM_READABLE(BGP_INPUT(peer)) >= 4) { uint16_t subtype = 0; uint16_t sublength = 0; struct bgp_attr_encap_subtlv *tlv; From 021386a34eb49893ce6b7df16c2fe1096a8fedf6 Mon Sep 17 00:00:00 2001 From: Carmine Scarpitta Date: Fri, 22 Mar 2024 15:13:00 +0100 Subject: [PATCH 032/347] lib: Add support for SRv6 SID formats Add functionalities to manage SRv6 SID formats (allocate / free). Signed-off-by: Carmine Scarpitta --- lib/srv6.c | 148 +++++++++++++++++++++++++++++++++++++++++------------ lib/srv6.h | 61 ++++++++++++++++++++++ 2 files changed, 175 insertions(+), 34 deletions(-) diff --git a/lib/srv6.c b/lib/srv6.c index a82103e423..abaff7eab8 100644 --- a/lib/srv6.c +++ b/lib/srv6.c @@ -10,8 +10,10 @@ #include "log.h" DEFINE_QOBJ_TYPE(srv6_locator); +DEFINE_QOBJ_TYPE(srv6_sid_format); DEFINE_MTYPE_STATIC(LIB, SRV6_LOCATOR, "SRV6 locator"); DEFINE_MTYPE_STATIC(LIB, SRV6_LOCATOR_CHUNK, "SRV6 locator chunk"); +DEFINE_MTYPE_STATIC(LIB, SRV6_SID_FORMAT, "SRv6 SID format"); const char *seg6local_action2str(uint32_t action) { @@ -154,6 +156,36 @@ void srv6_locator_chunk_free(struct srv6_locator_chunk **chunk) XFREE(MTYPE_SRV6_LOCATOR_CHUNK, *chunk); } +struct srv6_sid_format *srv6_sid_format_alloc(const char *name) +{ + struct srv6_sid_format *format = NULL; + + format = XCALLOC(MTYPE_SRV6_SID_FORMAT, sizeof(struct srv6_sid_format)); + strlcpy(format->name, name, sizeof(format->name)); + + QOBJ_REG(format, srv6_sid_format); + return format; +} + +void srv6_sid_format_free(struct srv6_sid_format *format) +{ + if (!format) + return; + + QOBJ_UNREG(format); + XFREE(MTYPE_SRV6_SID_FORMAT, format); +} + +/** + * Free an SRv6 SID format. + * + * @param val SRv6 SID format to be freed + */ +void delete_srv6_sid_format(void *val) +{ + srv6_sid_format_free((struct srv6_sid_format *)val); +} + json_object *srv6_locator_chunk_json(const struct srv6_locator_chunk *chunk) { json_object *jo_root = NULL; @@ -223,23 +255,47 @@ json_object *srv6_locator_json(const struct srv6_locator *loc) /* set prefix */ json_object_string_addf(jo_root, "prefix", "%pFX", &loc->prefix); - /* set block_bits_length */ - json_object_int_add(jo_root, "blockBitsLength", loc->block_bits_length); - - /* set node_bits_length */ - json_object_int_add(jo_root, "nodeBitsLength", loc->node_bits_length); - - /* set function_bits_length */ - json_object_int_add(jo_root, "functionBitsLength", - loc->function_bits_length); - - /* set argument_bits_length */ - json_object_int_add(jo_root, "argumentBitsLength", - loc->argument_bits_length); - - /* set true if the locator is a Micro-segment (uSID) locator */ - if (CHECK_FLAG(loc->flags, SRV6_LOCATOR_USID)) - json_object_string_add(jo_root, "behavior", "usid"); + if (loc->sid_format) { + /* set block_bits_length */ + json_object_int_add(jo_root, "blockBitsLength", + loc->sid_format->block_len); + + /* set node_bits_length */ + json_object_int_add(jo_root, "nodeBitsLength", + loc->sid_format->node_len); + + /* set function_bits_length */ + json_object_int_add(jo_root, "functionBitsLength", + loc->sid_format->function_len); + + /* set argument_bits_length */ + json_object_int_add(jo_root, "argumentBitsLength", + loc->sid_format->argument_len); + + /* set true if the locator is a Micro-segment (uSID) locator */ + if (loc->sid_format->type == SRV6_SID_FORMAT_TYPE_USID) + json_object_string_add(jo_root, "behavior", "usid"); + } else { + /* set block_bits_length */ + json_object_int_add(jo_root, "blockBitsLength", + loc->block_bits_length); + + /* set node_bits_length */ + json_object_int_add(jo_root, "nodeBitsLength", + loc->node_bits_length); + + /* set function_bits_length */ + json_object_int_add(jo_root, "functionBitsLength", + loc->function_bits_length); + + /* set argument_bits_length */ + json_object_int_add(jo_root, "argumentBitsLength", + loc->argument_bits_length); + + /* set true if the locator is a Micro-segment (uSID) locator */ + if (CHECK_FLAG(loc->flags, SRV6_LOCATOR_USID)) + json_object_string_add(jo_root, "behavior", "usid"); + } /* set status_up */ json_object_boolean_add(jo_root, "statusUp", @@ -272,23 +328,47 @@ json_object *srv6_locator_detailed_json(const struct srv6_locator *loc) /* set prefix */ json_object_string_addf(jo_root, "prefix", "%pFX", &loc->prefix); - /* set block_bits_length */ - json_object_int_add(jo_root, "blockBitsLength", loc->block_bits_length); - - /* set node_bits_length */ - json_object_int_add(jo_root, "nodeBitsLength", loc->node_bits_length); - - /* set function_bits_length */ - json_object_int_add(jo_root, "functionBitsLength", - loc->function_bits_length); - - /* set argument_bits_length */ - json_object_int_add(jo_root, "argumentBitsLength", - loc->argument_bits_length); - - /* set true if the locator is a Micro-segment (uSID) locator */ - if (CHECK_FLAG(loc->flags, SRV6_LOCATOR_USID)) - json_object_string_add(jo_root, "behavior", "usid"); + if (loc->sid_format) { + /* set block_bits_length */ + json_object_int_add(jo_root, "blockBitsLength", + loc->sid_format->block_len); + + /* set node_bits_length */ + json_object_int_add(jo_root, "nodeBitsLength", + loc->sid_format->node_len); + + /* set function_bits_length */ + json_object_int_add(jo_root, "functionBitsLength", + loc->sid_format->function_len); + + /* set argument_bits_length */ + json_object_int_add(jo_root, "argumentBitsLength", + loc->sid_format->argument_len); + + /* set true if the locator is a Micro-segment (uSID) locator */ + if (loc->sid_format->type == SRV6_SID_FORMAT_TYPE_USID) + json_object_string_add(jo_root, "behavior", "usid"); + } else { + /* set block_bits_length */ + json_object_int_add(jo_root, "blockBitsLength", + loc->block_bits_length); + + /* set node_bits_length */ + json_object_int_add(jo_root, "nodeBitsLength", + loc->node_bits_length); + + /* set function_bits_length */ + json_object_int_add(jo_root, "functionBitsLength", + loc->function_bits_length); + + /* set argument_bits_length */ + json_object_int_add(jo_root, "argumentBitsLength", + loc->argument_bits_length); + + /* set true if the locator is a Micro-segment (uSID) locator */ + if (CHECK_FLAG(loc->flags, SRV6_LOCATOR_USID)) + json_object_string_add(jo_root, "behavior", "usid"); + } /* set algonum */ json_object_int_add(jo_root, "algoNum", loc->algonum); diff --git a/lib/srv6.h b/lib/srv6.h index 433c5c14fd..04f560b267 100644 --- a/lib/srv6.h +++ b/lib/srv6.h @@ -20,6 +20,8 @@ #define SRH_BASE_HEADER_LENGTH 8 #define SRH_SEGMENT_LENGTH 16 +#define SRV6_SID_FORMAT_NAME_SIZE 512 + #ifdef __cplusplus extern "C" { #endif @@ -183,6 +185,61 @@ struct nexthop_srv6 { struct seg6_seg_stack *seg6_segs; }; +/* SID format type */ +enum srv6_sid_format_type { + SRV6_SID_FORMAT_TYPE_UNSPEC = 0, + /* SRv6 SID uncompressed format */ + SRV6_SID_FORMAT_TYPE_UNCOMPRESSED = 1, + /* SRv6 SID compressed uSID format */ + SRV6_SID_FORMAT_TYPE_USID = 2, +}; + +/* SRv6 SID format */ +struct srv6_sid_format { + /* Name of the format */ + char name[SRV6_SID_FORMAT_NAME_SIZE]; + + /* Format type: uncompressed vs compressed */ + enum srv6_sid_format_type type; + + /* + * Lengths of block/node/function/argument parts of the SIDs allocated + * using this format + */ + uint8_t block_len; + uint8_t node_len; + uint8_t function_len; + uint8_t argument_len; + + union { + /* Configuration settings for compressed uSID format type */ + struct { + /* Start of the Local ID Block (LIB) range */ + uint32_t lib_start; + + /* Start/End of the Explicit LIB range */ + uint32_t elib_start; + uint32_t elib_end; + + /* Start/End of the Wide LIB range */ + uint32_t wlib_start; + uint32_t wlib_end; + + /* Start/End of the Explicit Wide LIB range */ + uint32_t ewlib_start; + } usid; + + /* Configuration settings for uncompressed format type */ + struct { + /* Start of the Explicit range */ + uint32_t explicit_start; + } uncompressed; + } config; + + QOBJ_FIELDS; +}; +DECLARE_QOBJ_TYPE(srv6_sid_format); + static inline const char *seg6_mode2str(enum seg6_mode_t mode) { switch (mode) { @@ -260,6 +317,10 @@ json_object *srv6_locator_detailed_json(const struct srv6_locator *loc); json_object * srv6_locator_chunk_detailed_json(const struct srv6_locator_chunk *chunk); +extern struct srv6_sid_format *srv6_sid_format_alloc(const char *name); +extern void srv6_sid_format_free(struct srv6_sid_format *format); +extern void delete_srv6_sid_format(void *format); + #ifdef __cplusplus } #endif From 1298867671f7fe76c65730afbb9ae54dcd7264be Mon Sep 17 00:00:00 2001 From: Carmine Scarpitta Date: Thu, 6 Jun 2024 17:23:11 +0200 Subject: [PATCH 033/347] zebra: Add support for SRv6 SID formats Add functionalities to manage SRv6 SID formats (register / unregister / lookup) and create two SID formats upon SRv6 Manager initialization: `uncompressed-f4024` and `usid-f3216`. In future commits, we will add the CLI to allow the user to choose between the two formats. Signed-off-by: Carmine Scarpitta --- zebra/zebra_srv6.c | 132 ++++++++++++++++++++++++++++++++++++++--- zebra/zebra_srv6.h | 29 +++++++++ zebra/zebra_srv6_vty.c | 35 ++++++++--- 3 files changed, 180 insertions(+), 16 deletions(-) diff --git a/zebra/zebra_srv6.c b/zebra/zebra_srv6.c index bb872ef91c..dffc6ca091 100644 --- a/zebra/zebra_srv6.c +++ b/zebra/zebra_srv6.c @@ -90,6 +90,98 @@ static int zebra_srv6_cleanup(struct zserv *client) return 0; } +/* --- Zebra SRv6 SID format management functions --------------------------- */ + +void zebra_srv6_sid_format_register(struct zebra_srv6_sid_format *format) +{ + struct zebra_srv6 *srv6 = zebra_srv6_get_default(); + + /* Ensure that the format is registered only once */ + assert(!zebra_srv6_sid_format_lookup(format->name)); + + listnode_add(srv6->sid_formats, format); +} + +void zebra_srv6_sid_format_unregister(struct zebra_srv6_sid_format *format) +{ + struct zebra_srv6 *srv6 = zebra_srv6_get_default(); + + listnode_delete(srv6->sid_formats, format); +} + +struct zebra_srv6_sid_format *zebra_srv6_sid_format_lookup(const char *name) +{ + struct zebra_srv6 *srv6 = zebra_srv6_get_default(); + struct zebra_srv6_sid_format *format; + struct listnode *node; + + for (ALL_LIST_ELEMENTS_RO(srv6->sid_formats, node, format)) + if (!strncmp(name, format->name, sizeof(format->name))) + return format; + + return NULL; +} + +/* + * Helper function to create the SRv6 compressed format `usid-f3216`. + */ +static struct zebra_srv6_sid_format *create_srv6_sid_format_usid_f3216(void) +{ + struct zebra_srv6_sid_format *format = NULL; + + format = zebra_srv6_sid_format_alloc( + ZEBRA_SRV6_SID_FORMAT_USID_F3216_NAME); + + format->type = SRV6_SID_FORMAT_TYPE_USID; + + /* Define block/node/function length */ + format->block_len = ZEBRA_SRV6_SID_FORMAT_USID_F3216_BLOCK_LEN; + format->node_len = ZEBRA_SRV6_SID_FORMAT_USID_F3216_NODE_LEN; + format->function_len = ZEBRA_SRV6_SID_FORMAT_USID_F3216_FUNCTION_LEN; + format->argument_len = ZEBRA_SRV6_SID_FORMAT_USID_F3216_ARGUMENT_LEN; + + /* Define the ranges from which the SID function can be allocated */ + format->config.usid.lib_start = + ZEBRA_SRV6_SID_FORMAT_USID_F3216_LIB_START; + format->config.usid.elib_start = + ZEBRA_SRV6_SID_FORMAT_USID_F3216_ELIB_START; + format->config.usid.elib_end = ZEBRA_SRV6_SID_FORMAT_USID_F3216_ELIB_END; + format->config.usid.wlib_start = + ZEBRA_SRV6_SID_FORMAT_USID_F3216_WLIB_START; + format->config.usid.wlib_end = ZEBRA_SRV6_SID_FORMAT_USID_F3216_WLIB_END; + format->config.usid.ewlib_start = + ZEBRA_SRV6_SID_FORMAT_USID_F3216_EWLIB_START; + + return format; +} + +/* + * Helper function to create the SRv6 uncompressed format. + */ +static struct zebra_srv6_sid_format *create_srv6_sid_format_uncompressed(void) +{ + struct zebra_srv6_sid_format *format = NULL; + + format = zebra_srv6_sid_format_alloc( + ZEBRA_SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NAME); + + format->type = ZEBRA_SRV6_SID_FORMAT_TYPE_UNCOMPRESSED; + + /* Define block/node/function length */ + format->block_len = ZEBRA_SRV6_SID_FORMAT_UNCOMPRESSED_F4024_BLOCK_LEN; + format->node_len = ZEBRA_SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE_LEN; + format->function_len = + ZEBRA_SRV6_SID_FORMAT_UNCOMPRESSED_F4024_FUNCTION_LEN; + format->argument_len = + ZEBRA_SRV6_SID_FORMAT_UNCOMPRESSED_F4024_ARGUMENT_LEN; + + /* Define the ranges from which the SID function can be allocated */ + format->config.uncompressed.explicit_start = + ZEBRA_SRV6_SID_FORMAT_UNCOMPRESSED_F4024_EXPLICIT_RANGE_START; + + return format; +} + void zebra_srv6_locator_add(struct srv6_locator *locator) { struct zebra_srv6 *srv6 = zebra_srv6_get_default(); @@ -222,10 +314,24 @@ struct zebra_srv6 srv6; struct zebra_srv6 *zebra_srv6_get_default(void) { static bool first_execution = true; + struct zebra_srv6_sid_format *format_usidf3216; + struct zebra_srv6_sid_format *format_uncompressed; if (first_execution) { first_execution = false; srv6.locators = list_new(); + + /* Initialize list of SID formats */ + srv6.sid_formats = list_new(); + srv6.sid_formats->del = delete_zebra_srv6_sid_format; + + /* Create SID format `usid-f3216` */ + format_usidf3216 = create_srv6_sid_format_usid_f3216(); + zebra_srv6_sid_format_register(format_usidf3216); + + /* Create SID format `uncompressed` */ + format_uncompressed = create_srv6_sid_format_uncompressed(); + zebra_srv6_sid_format_register(format_uncompressed); } return &srv6; } @@ -430,18 +536,30 @@ void zebra_srv6_encap_src_addr_unset(void) void zebra_srv6_terminate(void) { struct srv6_locator *locator; + struct zebra_srv6_sid_format *format; - if (!srv6.locators) - return; + if (srv6.locators) { + while (listcount(srv6.locators)) { + locator = listnode_head(srv6.locators); - while (listcount(srv6.locators)) { - locator = listnode_head(srv6.locators); + listnode_delete(srv6.locators, locator); + srv6_locator_free(locator); + } - listnode_delete(srv6.locators, locator); - srv6_locator_free(locator); + list_delete(&srv6.locators); } - list_delete(&srv6.locators); + /* Free SRv6 SID formats */ + if (srv6.sid_formats) { + while (listcount(srv6.sid_formats)) { + format = listnode_head(srv6.sid_formats); + + zebra_srv6_sid_format_unregister(format); + zebra_srv6_sid_format_free(format); + } + + list_delete(&srv6.sid_formats); + } } void zebra_srv6_init(void) diff --git a/zebra/zebra_srv6.h b/zebra/zebra_srv6.h index 21936c3323..a645c5cc0d 100644 --- a/zebra/zebra_srv6.h +++ b/zebra/zebra_srv6.h @@ -16,12 +16,37 @@ #include #include +/* Default config for SRv6 SID `usid-f3216` format */ +#define ZEBRA_SRV6_SID_FORMAT_USID_F3216_NAME "usid-f3216" +#define ZEBRA_SRV6_SID_FORMAT_USID_F3216_BLOCK_LEN 32 +#define ZEBRA_SRV6_SID_FORMAT_USID_F3216_NODE_LEN 16 +#define ZEBRA_SRV6_SID_FORMAT_USID_F3216_FUNCTION_LEN 16 +#define ZEBRA_SRV6_SID_FORMAT_USID_F3216_ARGUMENT_LEN 0 +#define ZEBRA_SRV6_SID_FORMAT_USID_F3216_LIB_START 0xE000 +#define ZEBRA_SRV6_SID_FORMAT_USID_F3216_ELIB_START 0xFE00 +#define ZEBRA_SRV6_SID_FORMAT_USID_F3216_ELIB_END 0xFEFF +#define ZEBRA_SRV6_SID_FORMAT_USID_F3216_WLIB_START 0xFFF0 +#define ZEBRA_SRV6_SID_FORMAT_USID_F3216_WLIB_END 0xFFF7 +#define ZEBRA_SRV6_SID_FORMAT_USID_F3216_EWLIB_START 0xFFF7 + +/* Default config for SRv6 SID `uncompressed` format */ +#define ZEBRA_SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NAME "uncompressed-f4024" +#define ZEBRA_SRV6_SID_FORMAT_UNCOMPRESSED_F4024_BLOCK_LEN 40 +#define ZEBRA_SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE_LEN 24 +#define ZEBRA_SRV6_SID_FORMAT_UNCOMPRESSED_F4024_FUNCTION_LEN 16 +#define ZEBRA_SRV6_SID_FORMAT_UNCOMPRESSED_F4024_ARGUMENT_LEN 0 +#define ZEBRA_SRV6_SID_FORMAT_UNCOMPRESSED_F4024_EXPLICIT_RANGE_START 0xFF00 +#define ZEBRA_SRV6_SID_FORMAT_UNCOMPRESSED_F4024_FUNC_UNRESERVED_MIN 0x40 + /* SRv6 instance structure. */ struct zebra_srv6 { struct list *locators; /* Source address for SRv6 encapsulation */ struct in6_addr encap_src_addr; + + /* SRv6 SID formats */ + struct list *sid_formats; }; /* declare hooks for the basic API, so that it can be specialized or served @@ -74,4 +99,8 @@ extern int release_daemon_srv6_locator_chunks(struct zserv *client); extern void zebra_srv6_encap_src_addr_set(struct in6_addr *src_addr); extern void zebra_srv6_encap_src_addr_unset(void); +void zebra_srv6_sid_format_register(struct zebra_srv6_sid_format *format); +void zebra_srv6_sid_format_unregister(struct zebra_srv6_sid_format *format); +struct zebra_srv6_sid_format *zebra_srv6_sid_format_lookup(const char *name); + #endif /* _ZEBRA_SRV6_H */ diff --git a/zebra/zebra_srv6_vty.c b/zebra/zebra_srv6_vty.c index d5cd30e64b..ddb0922475 100644 --- a/zebra/zebra_srv6_vty.c +++ b/zebra/zebra_srv6_vty.c @@ -198,15 +198,32 @@ DEFUN (show_srv6_locator_detail, prefix2str(&locator->prefix, str, sizeof(str)); vty_out(vty, "Name: %s\n", locator->name); vty_out(vty, "Prefix: %s\n", str); - vty_out(vty, "Block-Bit-Len: %u\n", locator->block_bits_length); - vty_out(vty, "Node-Bit-Len: %u\n", locator->node_bits_length); - vty_out(vty, "Function-Bit-Len: %u\n", - locator->function_bits_length); - vty_out(vty, "Argument-Bit-Len: %u\n", - locator->argument_bits_length); - - if (CHECK_FLAG(locator->flags, SRV6_LOCATOR_USID)) - vty_out(vty, "Behavior: uSID\n"); + if (locator->sid_format) { + vty_out(vty, "Block-Bit-Len: %u\n", + locator->sid_format->block_len); + vty_out(vty, "Node-Bit-Len: %u\n", + locator->sid_format->node_len); + vty_out(vty, "Function-Bit-Len: %u\n", + locator->sid_format->function_len); + vty_out(vty, "Argument-Bit-Len: %u\n", + locator->sid_format->argument_len); + + if (locator->sid_format->type == + SRV6_SID_FORMAT_TYPE_USID) + vty_out(vty, "Behavior: uSID\n"); + } else { + vty_out(vty, "Block-Bit-Len: %u\n", + locator->block_bits_length); + vty_out(vty, "Node-Bit-Len: %u\n", + locator->node_bits_length); + vty_out(vty, "Function-Bit-Len: %u\n", + locator->function_bits_length); + vty_out(vty, "Argument-Bit-Len: %u\n", + locator->argument_bits_length); + + if (CHECK_FLAG(locator->flags, SRV6_LOCATOR_USID)) + vty_out(vty, "Behavior: uSID\n"); + } vty_out(vty, "Chunks:\n"); for (ALL_LIST_ELEMENTS_RO((struct list *)locator->chunks, node, From 35f4bedfa3a5017a69878b2a2b37f06149f94adf Mon Sep 17 00:00:00 2001 From: Carmine Scarpitta Date: Fri, 22 Mar 2024 15:56:15 +0100 Subject: [PATCH 034/347] lib: Add CLI nodes to support SRv6 SID format Add CLI commands to support overriding default configuration of the SID format. Signed-off-by: Carmine Scarpitta --- lib/command.h | 3 +++ zebra/zebra_srv6.c | 31 +++++++++++++++---------------- zebra/zebra_srv6.h | 6 +++--- 3 files changed, 21 insertions(+), 19 deletions(-) diff --git a/lib/command.h b/lib/command.h index e4c575e8d7..6f819c7e36 100644 --- a/lib/command.h +++ b/lib/command.h @@ -161,6 +161,9 @@ enum node_type { SRV6_LOCS_NODE, /* SRv6 locators node */ SRV6_LOC_NODE, /* SRv6 locator node */ SRV6_ENCAP_NODE, /* SRv6 encapsulation node */ + SRV6_SID_FORMATS_NODE, /* SRv6 SID formats config node */ + SRV6_SID_FORMAT_USID_F3216_NODE, /* SRv6 uSID f3216 format config node */ + SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE, /* SRv6 uncompressed f4024 format config node */ VTY_NODE, /* Vty node. */ FPM_NODE, /* Dataplane FPM node. */ LINK_PARAMS_NODE, /* Link-parameters node */ diff --git a/zebra/zebra_srv6.c b/zebra/zebra_srv6.c index dffc6ca091..fa3b4a733b 100644 --- a/zebra/zebra_srv6.c +++ b/zebra/zebra_srv6.c @@ -92,7 +92,7 @@ static int zebra_srv6_cleanup(struct zserv *client) /* --- Zebra SRv6 SID format management functions --------------------------- */ -void zebra_srv6_sid_format_register(struct zebra_srv6_sid_format *format) +void zebra_srv6_sid_format_register(struct srv6_sid_format *format) { struct zebra_srv6 *srv6 = zebra_srv6_get_default(); @@ -102,17 +102,17 @@ void zebra_srv6_sid_format_register(struct zebra_srv6_sid_format *format) listnode_add(srv6->sid_formats, format); } -void zebra_srv6_sid_format_unregister(struct zebra_srv6_sid_format *format) +void zebra_srv6_sid_format_unregister(struct srv6_sid_format *format) { struct zebra_srv6 *srv6 = zebra_srv6_get_default(); listnode_delete(srv6->sid_formats, format); } -struct zebra_srv6_sid_format *zebra_srv6_sid_format_lookup(const char *name) +struct srv6_sid_format *zebra_srv6_sid_format_lookup(const char *name) { struct zebra_srv6 *srv6 = zebra_srv6_get_default(); - struct zebra_srv6_sid_format *format; + struct srv6_sid_format *format; struct listnode *node; for (ALL_LIST_ELEMENTS_RO(srv6->sid_formats, node, format)) @@ -125,12 +125,11 @@ struct zebra_srv6_sid_format *zebra_srv6_sid_format_lookup(const char *name) /* * Helper function to create the SRv6 compressed format `usid-f3216`. */ -static struct zebra_srv6_sid_format *create_srv6_sid_format_usid_f3216(void) +static struct srv6_sid_format *create_srv6_sid_format_usid_f3216(void) { - struct zebra_srv6_sid_format *format = NULL; + struct srv6_sid_format *format = NULL; - format = zebra_srv6_sid_format_alloc( - ZEBRA_SRV6_SID_FORMAT_USID_F3216_NAME); + format = srv6_sid_format_alloc(ZEBRA_SRV6_SID_FORMAT_USID_F3216_NAME); format->type = SRV6_SID_FORMAT_TYPE_USID; @@ -158,11 +157,11 @@ static struct zebra_srv6_sid_format *create_srv6_sid_format_usid_f3216(void) /* * Helper function to create the SRv6 uncompressed format. */ -static struct zebra_srv6_sid_format *create_srv6_sid_format_uncompressed(void) +static struct srv6_sid_format *create_srv6_sid_format_uncompressed(void) { - struct zebra_srv6_sid_format *format = NULL; + struct srv6_sid_format *format = NULL; - format = zebra_srv6_sid_format_alloc( + format = srv6_sid_format_alloc( ZEBRA_SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NAME); format->type = ZEBRA_SRV6_SID_FORMAT_TYPE_UNCOMPRESSED; @@ -314,8 +313,8 @@ struct zebra_srv6 srv6; struct zebra_srv6 *zebra_srv6_get_default(void) { static bool first_execution = true; - struct zebra_srv6_sid_format *format_usidf3216; - struct zebra_srv6_sid_format *format_uncompressed; + struct srv6_sid_format *format_usidf3216; + struct srv6_sid_format *format_uncompressed; if (first_execution) { first_execution = false; @@ -323,7 +322,7 @@ struct zebra_srv6 *zebra_srv6_get_default(void) /* Initialize list of SID formats */ srv6.sid_formats = list_new(); - srv6.sid_formats->del = delete_zebra_srv6_sid_format; + srv6.sid_formats->del = delete_srv6_sid_format; /* Create SID format `usid-f3216` */ format_usidf3216 = create_srv6_sid_format_usid_f3216(); @@ -536,7 +535,7 @@ void zebra_srv6_encap_src_addr_unset(void) void zebra_srv6_terminate(void) { struct srv6_locator *locator; - struct zebra_srv6_sid_format *format; + struct srv6_sid_format *format; if (srv6.locators) { while (listcount(srv6.locators)) { @@ -555,7 +554,7 @@ void zebra_srv6_terminate(void) format = listnode_head(srv6.sid_formats); zebra_srv6_sid_format_unregister(format); - zebra_srv6_sid_format_free(format); + srv6_sid_format_free(format); } list_delete(&srv6.sid_formats); diff --git a/zebra/zebra_srv6.h b/zebra/zebra_srv6.h index a645c5cc0d..57f9d83825 100644 --- a/zebra/zebra_srv6.h +++ b/zebra/zebra_srv6.h @@ -99,8 +99,8 @@ extern int release_daemon_srv6_locator_chunks(struct zserv *client); extern void zebra_srv6_encap_src_addr_set(struct in6_addr *src_addr); extern void zebra_srv6_encap_src_addr_unset(void); -void zebra_srv6_sid_format_register(struct zebra_srv6_sid_format *format); -void zebra_srv6_sid_format_unregister(struct zebra_srv6_sid_format *format); -struct zebra_srv6_sid_format *zebra_srv6_sid_format_lookup(const char *name); +void zebra_srv6_sid_format_register(struct srv6_sid_format *format); +void zebra_srv6_sid_format_unregister(struct srv6_sid_format *format); +struct srv6_sid_format *zebra_srv6_sid_format_lookup(const char *name); #endif /* _ZEBRA_SRV6_H */ From b3ca230a8f02291961219eda7969f1e43aba931c Mon Sep 17 00:00:00 2001 From: Carmine Scarpitta Date: Tue, 26 Mar 2024 08:53:17 +0100 Subject: [PATCH 035/347] vtysh: CLI to override default SID format config Add CLI commands to support overriding default configuration of the SID format. Signed-off-by: Carmine Scarpitta --- vtysh/vtysh.c | 82 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index b1c957d043..573320667c 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -1344,6 +1344,27 @@ static struct cmd_node srv6_encap_node = { .prompt = "%s(config-srv6-encap)# " }; +static struct cmd_node srv6_sid_formats_node = { + .name = "srv6-formats", + .node = SRV6_SID_FORMATS_NODE, + .parent_node = SRV6_NODE, + .prompt = "%s(config-srv6-formats)# ", +}; + +static struct cmd_node srv6_sid_format_usid_f3216_node = { + .name = "srv6-format-usid-f3216", + .node = SRV6_SID_FORMAT_USID_F3216_NODE, + .parent_node = SRV6_SID_FORMATS_NODE, + .prompt = "%s(config-srv6-format)# " +}; + +static struct cmd_node srv6_sid_format_uncompressed_f4024_node = { + .name = "srv6-format-uncompressed-f4024", + .node = SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE, + .parent_node = SRV6_SID_FORMATS_NODE, + .prompt = "%s(config-srv6-format)# " +}; + #ifdef HAVE_PBRD static struct cmd_node pbr_map_node = { .name = "pbr-map", @@ -1715,6 +1736,31 @@ DEFUNSH(VTYSH_ZEBRA, srv6_encap, srv6_encap_cmd, return CMD_SUCCESS; } +DEFUNSH(VTYSH_ZEBRA, srv6_sid_formats, srv6_sid_formats_cmd, "formats", + "Segment Routing SRv6 SID formats\n") +{ + vty->node = SRV6_SID_FORMATS_NODE; + return CMD_SUCCESS; +} + +DEFUNSH(VTYSH_ZEBRA, srv6_sid_format_f3216_usid, srv6_sid_format_f3216_usid_cmd, + "format usid-f3216", + "Configure SRv6 SID format\n" + "Configure the uSID f3216 format\n") +{ + vty->node = SRV6_SID_FORMAT_USID_F3216_NODE; + return CMD_SUCCESS; +} + +DEFUNSH(VTYSH_ZEBRA, srv6_sid_format_f4024_uncompressed, srv6_sid_format_f4024_uncompressed_cmd, + "format uncompressed-f4024", + "Configure SRv6 SID format\n" + "Configure the uncompressed f4024 format\n") +{ + vty->node = SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE; + return CMD_SUCCESS; +} + #ifdef HAVE_BGPD DEFUNSH(VTYSH_BGPD, router_bgp, router_bgp_cmd, "router bgp [ASNUM [ VIEWVRFNAME] [as-notation ]]", @@ -2515,6 +2561,23 @@ DEFUNSH(VTYSH_ZEBRA, exit_srv6_encap, exit_srv6_encap_cmd, "exit", return CMD_SUCCESS; } +DEFUNSH(VTYSH_ZEBRA, exit_srv6_sid_formats, exit_srv6_sid_formats_cmd, "exit", + "Exit from SRv6 SID formats configuration mode\n") +{ + if (vty->node == SRV6_SID_FORMATS_NODE) + vty->node = SRV6_NODE; + return CMD_SUCCESS; +} + +DEFUNSH(VTYSH_ZEBRA, exit_srv6_sid_format, exit_srv6_sid_format_cmd, + "exit", "Exit from SRv6 SID format configuration mode\n") +{ + if (vty->node == SRV6_SID_FORMAT_USID_F3216_NODE || + vty->node == SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE) + vty->node = SRV6_SID_FORMATS_NODE; + return CMD_SUCCESS; +} + #ifdef HAVE_RIPD DEFUNSH(VTYSH_MGMTD, vtysh_exit_ripd, vtysh_exit_ripd_cmd, "exit", "Exit current mode and down to previous mode\n") @@ -5304,6 +5367,7 @@ void vtysh_init_vty(void) install_node(&srv6_node); install_element(SEGMENT_ROUTING_NODE, &srv6_cmd); install_element(SRV6_NODE, &srv6_locators_cmd); + install_element(SRV6_NODE, &srv6_sid_formats_cmd); install_element(SRV6_NODE, &exit_srv6_config_cmd); install_element(SRV6_NODE, &vtysh_end_all_cmd); install_element(SRV6_NODE, &srv6_encap_cmd); @@ -5321,6 +5385,24 @@ void vtysh_init_vty(void) install_element(SRV6_ENCAP_NODE, &exit_srv6_encap_cmd); install_element(SRV6_ENCAP_NODE, &vtysh_end_all_cmd); + install_node(&srv6_sid_formats_node); + install_element(SRV6_SID_FORMATS_NODE, &srv6_sid_format_f3216_usid_cmd); + install_element(SRV6_SID_FORMATS_NODE, + &srv6_sid_format_f4024_uncompressed_cmd); + install_element(SRV6_SID_FORMATS_NODE, &exit_srv6_sid_formats_cmd); + install_element(SRV6_SID_FORMATS_NODE, &vtysh_end_all_cmd); + + install_node(&srv6_sid_format_usid_f3216_node); + install_element(SRV6_SID_FORMAT_USID_F3216_NODE, + &exit_srv6_sid_format_cmd); + install_element(SRV6_SID_FORMAT_USID_F3216_NODE, &vtysh_end_all_cmd); + + install_node(&srv6_sid_format_uncompressed_f4024_node); + install_element(SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE, + &exit_srv6_sid_format_cmd); + install_element(SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE, + &vtysh_end_all_cmd); + install_element(ENABLE_NODE, &vtysh_show_running_config_cmd); install_element(ENABLE_NODE, &vtysh_copy_running_config_cmd); install_element(ENABLE_NODE, &vtysh_copy_to_running_cmd); From 51d3cd8a007d5c2ad6bb27af404f2d95164cf4c2 Mon Sep 17 00:00:00 2001 From: Carmine Scarpitta Date: Tue, 26 Mar 2024 08:53:55 +0100 Subject: [PATCH 036/347] zebra: CLI to override default SID format config Add CLI commands to support overriding default configuration of the SID format. Signed-off-by: Carmine Scarpitta --- zebra/zebra_srv6.c | 57 +++---- zebra/zebra_srv6.h | 42 ++--- zebra/zebra_srv6_vty.c | 365 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 411 insertions(+), 53 deletions(-) diff --git a/zebra/zebra_srv6.c b/zebra/zebra_srv6.c index fa3b4a733b..825f0f7fc2 100644 --- a/zebra/zebra_srv6.c +++ b/zebra/zebra_srv6.c @@ -92,24 +92,24 @@ static int zebra_srv6_cleanup(struct zserv *client) /* --- Zebra SRv6 SID format management functions --------------------------- */ -void zebra_srv6_sid_format_register(struct srv6_sid_format *format) +void srv6_sid_format_register(struct srv6_sid_format *format) { struct zebra_srv6 *srv6 = zebra_srv6_get_default(); /* Ensure that the format is registered only once */ - assert(!zebra_srv6_sid_format_lookup(format->name)); + assert(!srv6_sid_format_lookup(format->name)); listnode_add(srv6->sid_formats, format); } -void zebra_srv6_sid_format_unregister(struct srv6_sid_format *format) +void srv6_sid_format_unregister(struct srv6_sid_format *format) { struct zebra_srv6 *srv6 = zebra_srv6_get_default(); listnode_delete(srv6->sid_formats, format); } -struct srv6_sid_format *zebra_srv6_sid_format_lookup(const char *name) +struct srv6_sid_format *srv6_sid_format_lookup(const char *name) { struct zebra_srv6 *srv6 = zebra_srv6_get_default(); struct srv6_sid_format *format; @@ -129,27 +129,23 @@ static struct srv6_sid_format *create_srv6_sid_format_usid_f3216(void) { struct srv6_sid_format *format = NULL; - format = srv6_sid_format_alloc(ZEBRA_SRV6_SID_FORMAT_USID_F3216_NAME); + format = srv6_sid_format_alloc(SRV6_SID_FORMAT_USID_F3216_NAME); format->type = SRV6_SID_FORMAT_TYPE_USID; /* Define block/node/function length */ - format->block_len = ZEBRA_SRV6_SID_FORMAT_USID_F3216_BLOCK_LEN; - format->node_len = ZEBRA_SRV6_SID_FORMAT_USID_F3216_NODE_LEN; - format->function_len = ZEBRA_SRV6_SID_FORMAT_USID_F3216_FUNCTION_LEN; - format->argument_len = ZEBRA_SRV6_SID_FORMAT_USID_F3216_ARGUMENT_LEN; + format->block_len = SRV6_SID_FORMAT_USID_F3216_BLOCK_LEN; + format->node_len = SRV6_SID_FORMAT_USID_F3216_NODE_LEN; + format->function_len = SRV6_SID_FORMAT_USID_F3216_FUNCTION_LEN; + format->argument_len = SRV6_SID_FORMAT_USID_F3216_ARGUMENT_LEN; /* Define the ranges from which the SID function can be allocated */ - format->config.usid.lib_start = - ZEBRA_SRV6_SID_FORMAT_USID_F3216_LIB_START; - format->config.usid.elib_start = - ZEBRA_SRV6_SID_FORMAT_USID_F3216_ELIB_START; - format->config.usid.elib_end = ZEBRA_SRV6_SID_FORMAT_USID_F3216_ELIB_END; - format->config.usid.wlib_start = - ZEBRA_SRV6_SID_FORMAT_USID_F3216_WLIB_START; - format->config.usid.wlib_end = ZEBRA_SRV6_SID_FORMAT_USID_F3216_WLIB_END; - format->config.usid.ewlib_start = - ZEBRA_SRV6_SID_FORMAT_USID_F3216_EWLIB_START; + format->config.usid.lib_start = SRV6_SID_FORMAT_USID_F3216_LIB_START; + format->config.usid.elib_start = SRV6_SID_FORMAT_USID_F3216_ELIB_START; + format->config.usid.elib_end = SRV6_SID_FORMAT_USID_F3216_ELIB_END; + format->config.usid.wlib_start = SRV6_SID_FORMAT_USID_F3216_WLIB_START; + format->config.usid.wlib_end = SRV6_SID_FORMAT_USID_F3216_WLIB_END; + format->config.usid.ewlib_start = SRV6_SID_FORMAT_USID_F3216_EWLIB_START; return format; } @@ -161,22 +157,19 @@ static struct srv6_sid_format *create_srv6_sid_format_uncompressed(void) { struct srv6_sid_format *format = NULL; - format = srv6_sid_format_alloc( - ZEBRA_SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NAME); + format = srv6_sid_format_alloc(SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NAME); - format->type = ZEBRA_SRV6_SID_FORMAT_TYPE_UNCOMPRESSED; + format->type = SRV6_SID_FORMAT_TYPE_UNCOMPRESSED; /* Define block/node/function length */ - format->block_len = ZEBRA_SRV6_SID_FORMAT_UNCOMPRESSED_F4024_BLOCK_LEN; - format->node_len = ZEBRA_SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE_LEN; - format->function_len = - ZEBRA_SRV6_SID_FORMAT_UNCOMPRESSED_F4024_FUNCTION_LEN; - format->argument_len = - ZEBRA_SRV6_SID_FORMAT_UNCOMPRESSED_F4024_ARGUMENT_LEN; + format->block_len = SRV6_SID_FORMAT_UNCOMPRESSED_F4024_BLOCK_LEN; + format->node_len = SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE_LEN; + format->function_len = SRV6_SID_FORMAT_UNCOMPRESSED_F4024_FUNCTION_LEN; + format->argument_len = SRV6_SID_FORMAT_UNCOMPRESSED_F4024_ARGUMENT_LEN; /* Define the ranges from which the SID function can be allocated */ format->config.uncompressed.explicit_start = - ZEBRA_SRV6_SID_FORMAT_UNCOMPRESSED_F4024_EXPLICIT_RANGE_START; + SRV6_SID_FORMAT_UNCOMPRESSED_F4024_EXPLICIT_RANGE_START; return format; } @@ -326,11 +319,11 @@ struct zebra_srv6 *zebra_srv6_get_default(void) /* Create SID format `usid-f3216` */ format_usidf3216 = create_srv6_sid_format_usid_f3216(); - zebra_srv6_sid_format_register(format_usidf3216); + srv6_sid_format_register(format_usidf3216); /* Create SID format `uncompressed` */ format_uncompressed = create_srv6_sid_format_uncompressed(); - zebra_srv6_sid_format_register(format_uncompressed); + srv6_sid_format_register(format_uncompressed); } return &srv6; } @@ -553,7 +546,7 @@ void zebra_srv6_terminate(void) while (listcount(srv6.sid_formats)) { format = listnode_head(srv6.sid_formats); - zebra_srv6_sid_format_unregister(format); + srv6_sid_format_unregister(format); srv6_sid_format_free(format); } diff --git a/zebra/zebra_srv6.h b/zebra/zebra_srv6.h index 57f9d83825..92e4fcf912 100644 --- a/zebra/zebra_srv6.h +++ b/zebra/zebra_srv6.h @@ -17,26 +17,26 @@ #include /* Default config for SRv6 SID `usid-f3216` format */ -#define ZEBRA_SRV6_SID_FORMAT_USID_F3216_NAME "usid-f3216" -#define ZEBRA_SRV6_SID_FORMAT_USID_F3216_BLOCK_LEN 32 -#define ZEBRA_SRV6_SID_FORMAT_USID_F3216_NODE_LEN 16 -#define ZEBRA_SRV6_SID_FORMAT_USID_F3216_FUNCTION_LEN 16 -#define ZEBRA_SRV6_SID_FORMAT_USID_F3216_ARGUMENT_LEN 0 -#define ZEBRA_SRV6_SID_FORMAT_USID_F3216_LIB_START 0xE000 -#define ZEBRA_SRV6_SID_FORMAT_USID_F3216_ELIB_START 0xFE00 -#define ZEBRA_SRV6_SID_FORMAT_USID_F3216_ELIB_END 0xFEFF -#define ZEBRA_SRV6_SID_FORMAT_USID_F3216_WLIB_START 0xFFF0 -#define ZEBRA_SRV6_SID_FORMAT_USID_F3216_WLIB_END 0xFFF7 -#define ZEBRA_SRV6_SID_FORMAT_USID_F3216_EWLIB_START 0xFFF7 +#define SRV6_SID_FORMAT_USID_F3216_NAME "usid-f3216" +#define SRV6_SID_FORMAT_USID_F3216_BLOCK_LEN 32 +#define SRV6_SID_FORMAT_USID_F3216_NODE_LEN 16 +#define SRV6_SID_FORMAT_USID_F3216_FUNCTION_LEN 16 +#define SRV6_SID_FORMAT_USID_F3216_ARGUMENT_LEN 0 +#define SRV6_SID_FORMAT_USID_F3216_LIB_START 0xE000 +#define SRV6_SID_FORMAT_USID_F3216_ELIB_START 0xFE00 +#define SRV6_SID_FORMAT_USID_F3216_ELIB_END 0xFEFF +#define SRV6_SID_FORMAT_USID_F3216_WLIB_START 0xFFF0 +#define SRV6_SID_FORMAT_USID_F3216_WLIB_END 0xFFF7 +#define SRV6_SID_FORMAT_USID_F3216_EWLIB_START 0xFFF7 /* Default config for SRv6 SID `uncompressed` format */ -#define ZEBRA_SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NAME "uncompressed-f4024" -#define ZEBRA_SRV6_SID_FORMAT_UNCOMPRESSED_F4024_BLOCK_LEN 40 -#define ZEBRA_SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE_LEN 24 -#define ZEBRA_SRV6_SID_FORMAT_UNCOMPRESSED_F4024_FUNCTION_LEN 16 -#define ZEBRA_SRV6_SID_FORMAT_UNCOMPRESSED_F4024_ARGUMENT_LEN 0 -#define ZEBRA_SRV6_SID_FORMAT_UNCOMPRESSED_F4024_EXPLICIT_RANGE_START 0xFF00 -#define ZEBRA_SRV6_SID_FORMAT_UNCOMPRESSED_F4024_FUNC_UNRESERVED_MIN 0x40 +#define SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NAME "uncompressed-f4024" +#define SRV6_SID_FORMAT_UNCOMPRESSED_F4024_BLOCK_LEN 40 +#define SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE_LEN 24 +#define SRV6_SID_FORMAT_UNCOMPRESSED_F4024_FUNCTION_LEN 16 +#define SRV6_SID_FORMAT_UNCOMPRESSED_F4024_ARGUMENT_LEN 0 +#define SRV6_SID_FORMAT_UNCOMPRESSED_F4024_EXPLICIT_RANGE_START 0xFF00 +#define SRV6_SID_FORMAT_UNCOMPRESSED_F4024_FUNC_UNRESERVED_MIN 0x40 /* SRv6 instance structure. */ struct zebra_srv6 { @@ -99,8 +99,8 @@ extern int release_daemon_srv6_locator_chunks(struct zserv *client); extern void zebra_srv6_encap_src_addr_set(struct in6_addr *src_addr); extern void zebra_srv6_encap_src_addr_unset(void); -void zebra_srv6_sid_format_register(struct srv6_sid_format *format); -void zebra_srv6_sid_format_unregister(struct srv6_sid_format *format); -struct srv6_sid_format *zebra_srv6_sid_format_lookup(const char *name); +void srv6_sid_format_register(struct srv6_sid_format *format); +void srv6_sid_format_unregister(struct srv6_sid_format *format); +struct srv6_sid_format *srv6_sid_format_lookup(const char *name); #endif /* _ZEBRA_SRV6_H */ diff --git a/zebra/zebra_srv6_vty.c b/zebra/zebra_srv6_vty.c index ddb0922475..e5fe0d58a9 100644 --- a/zebra/zebra_srv6_vty.c +++ b/zebra/zebra_srv6_vty.c @@ -68,6 +68,27 @@ static struct cmd_node srv6_encap_node = { .prompt = "%s(config-srv6-encap)# " }; +static struct cmd_node srv6_sid_formats_node = { + .name = "srv6-formats", + .node = SRV6_SID_FORMATS_NODE, + .parent_node = SRV6_NODE, + .prompt = "%s(config-srv6-formats)# ", +}; + +static struct cmd_node srv6_sid_format_usid_f3216_node = { + .name = "srv6-format-usid-f3216", + .node = SRV6_SID_FORMAT_USID_F3216_NODE, + .parent_node = SRV6_SID_FORMATS_NODE, + .prompt = "%s(config-srv6-format)# " +}; + +static struct cmd_node srv6_sid_format_uncompressed_f4024_node = { + .name = "srv6-format-uncompressed-f4024", + .node = SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE, + .parent_node = SRV6_SID_FORMATS_NODE, + .prompt = "%s(config-srv6-format)# " +}; + DEFPY (show_srv6_manager, show_srv6_manager_cmd, "show segment-routing srv6 manager [json]", @@ -486,11 +507,276 @@ DEFPY (no_srv6_src_addr, return CMD_SUCCESS; } +DEFUN_NOSH(srv6_sid_formats, + srv6_sid_formats_cmd, + "formats", + "Segment Routing SRv6 SID formats\n") +{ + vty->node = SRV6_SID_FORMATS_NODE; + return CMD_SUCCESS; +} + +DEFUN_NOSH (srv6_sid_format_f3216_usid, + srv6_sid_format_f3216_usid_cmd, + "format usid-f3216", + "Configure SRv6 SID format\n" + "Configure the uSID f3216 format\n") +{ + struct srv6_sid_format *format; + + format = srv6_sid_format_lookup(SRV6_SID_FORMAT_USID_F3216_NAME); + assert(format); + + VTY_PUSH_CONTEXT(SRV6_SID_FORMAT_USID_F3216_NODE, format); + return CMD_SUCCESS; +} + +DEFUN(no_srv6_sid_format_f3216_usid, + no_srv6_sid_format_f3216_usid_cmd, + "no format usid-f3216", + NO_STR + "Configure SRv6 SID format\n" + "Configure the uSID f3216 format\n") +{ + struct srv6_sid_format *format; + + format = srv6_sid_format_lookup(SRV6_SID_FORMAT_USID_F3216_NAME); + assert(format); + + format->config.usid.lib_start = SRV6_SID_FORMAT_USID_F3216_LIB_START; + format->config.usid.elib_start = SRV6_SID_FORMAT_USID_F3216_ELIB_START; + format->config.usid.elib_end = SRV6_SID_FORMAT_USID_F3216_ELIB_END; + format->config.usid.wlib_start = SRV6_SID_FORMAT_USID_F3216_WLIB_START; + format->config.usid.wlib_end = SRV6_SID_FORMAT_USID_F3216_WLIB_END; + format->config.usid.ewlib_start = SRV6_SID_FORMAT_USID_F3216_EWLIB_START; + + return CMD_SUCCESS; +} + +DEFUN_NOSH (srv6_sid_format_f4024_uncompressed, + srv6_sid_format_uncompressed_cmd, + "format uncompressed-f4024", + "Configure SRv6 SID format\n" + "Configure the uncompressed f4024 format\n") +{ + struct srv6_sid_format *format; + + format = srv6_sid_format_lookup(SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NAME); + assert(format); + + VTY_PUSH_CONTEXT(SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE, format); + return CMD_SUCCESS; +} + +DEFUN(no_srv6_sid_format_f4024_uncompressed, + no_srv6_sid_format_f4024_uncompressed_cmd, + "no format uncompressed-f4024", + NO_STR + "Configure SRv6 SID format\n" + "Configure the uncompressed f4024 format\n") +{ + struct srv6_sid_format *format; + + format = srv6_sid_format_lookup(SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NAME); + assert(format); + + format->config.uncompressed.explicit_start = + SRV6_SID_FORMAT_UNCOMPRESSED_F4024_EXPLICIT_RANGE_START; + + return CMD_SUCCESS; +} + +DEFPY(srv6_sid_format_usid_lib, + srv6_sid_format_usid_lib_cmd, + "local-id-block start (0-4294967295)$start", + "Configure LIB\n" + "Configure the start value for the LIB\n" + "Specify the start value for the LIB\n") +{ + VTY_DECLVAR_CONTEXT(srv6_sid_format, format); + + format->config.usid.lib_start = start; + + return CMD_SUCCESS; +} + +DEFPY(no_srv6_sid_format_usid_lib, + no_srv6_sid_format_usid_lib_cmd, + "no local-id-block [start (0-4294967295)]", + NO_STR + "Configure LIB\n" + "Configure the start value for the LIB\n" + "Specify the start value for the LIB\n") +{ + VTY_DECLVAR_CONTEXT(srv6_sid_format, format); + + if (strmatch(format->name, SRV6_SID_FORMAT_USID_F3216_NAME)) + format->config.usid.lib_start = + SRV6_SID_FORMAT_USID_F3216_LIB_START; + else + assert(0); + + return CMD_SUCCESS; +} + +DEFPY(srv6_sid_format_usid_lib_explicit, + srv6_sid_format_usid_lib_explicit_cmd, + "local-id-block explicit start (0-4294967295)$start end (0-4294967295)$end", + "Configure LIB\n" + "Configure the Explicit LIB\n" + "Configure the start value for the Explicit LIB\n" + "Specify the start value for the Explicit LIB\n" + "Configure the end value for the Explicit LIB\n" + "Specify the end value for the Explicit LIB\n") +{ + VTY_DECLVAR_CONTEXT(srv6_sid_format, format); + + format->config.usid.elib_start = start; + format->config.usid.elib_end = end; + + return CMD_SUCCESS; +} + +DEFPY(no_srv6_sid_format_usid_lib_explicit, + no_srv6_sid_format_usid_lib_explicit_cmd, + "no local-id-block explicit [start (0-4294967295) end (0-4294967295)]", + NO_STR + "Configure LIB\n" + "Configure the Explicit LIB\n" + "Configure the start value for the Explicit LIB\n" + "Specify the start value for the Explicit LIB\n" + "Configure the end value for the Explicit LIB\n" + "Specify the end value for the Explicit LIB\n") +{ + VTY_DECLVAR_CONTEXT(srv6_sid_format, format); + + if (strmatch(format->name, SRV6_SID_FORMAT_USID_F3216_NAME)) { + format->config.usid.elib_start = + SRV6_SID_FORMAT_USID_F3216_ELIB_START; + format->config.usid.elib_end = + SRV6_SID_FORMAT_USID_F3216_ELIB_END; + } else { + assert(0); + } + + return CMD_SUCCESS; +} + +DEFPY(srv6_sid_format_usid_wlib, + srv6_sid_format_usid_wlib_cmd, + "wide-local-id-block start (0-4294967295)$start end (0-4294967295)$end", + "Configure Wide LIB\n" + "Configure the start value for the Wide LIB\n" + "Specify the start value for the Wide LIB\n" + "Configure the end value for the Wide LIB\n" + "Specify the end value for the Wide LIB\n") +{ + VTY_DECLVAR_CONTEXT(srv6_sid_format, format); + + format->config.usid.wlib_start = start; + format->config.usid.wlib_end = end; + + return CMD_SUCCESS; +} + +DEFPY(no_srv6_sid_format_usid_wlib, + no_srv6_sid_format_usid_wlib_cmd, + "no wide-local-id-block [start (0-4294967295) end (0-4294967295)]", + NO_STR + "Configure Wide LIB\n" + "Configure the start value for the Wide LIB\n" + "Specify the start value for the Wide LIB\n" + "Configure the end value for the Wide LIB\n" + "Specify the end value for the Wide LIB\n") +{ + VTY_DECLVAR_CONTEXT(srv6_sid_format, format); + + if (strmatch(format->name, SRV6_SID_FORMAT_USID_F3216_NAME)) { + format->config.usid.wlib_start = + SRV6_SID_FORMAT_USID_F3216_WLIB_START; + format->config.usid.wlib_end = + SRV6_SID_FORMAT_USID_F3216_WLIB_END; + } else { + assert(0); + } + + return CMD_SUCCESS; +} + +DEFPY(srv6_sid_format_usid_wide_lib_explicit, + srv6_sid_format_usid_wide_lib_explicit_cmd, + "wide-local-id-block explicit start (0-4294967295)$start", + "Configure Wide LIB\n" + "Configure Explicit Wide LIB\n" + "Configure the start value for the Explicit Wide LIB\n" + "Specify the start value for the Explicit Wide LIB\n") +{ + VTY_DECLVAR_CONTEXT(srv6_sid_format, format); + + format->config.usid.ewlib_start = start; + + return CMD_SUCCESS; +} + +DEFPY(no_srv6_sid_format_usid_wide_lib_explicit, + no_srv6_sid_format_usid_wide_lib_explicit_cmd, + "no wide-local-id-block explicit [start (0-4294967295)]", + NO_STR + "Configure Wide LIB\n" + "Configure Explicit Wide LIB\n" + "Configure the start value for the Explicit Wide LIB\n" + "Specify the start value for the Explicit Wide LIB\n") +{ + VTY_DECLVAR_CONTEXT(srv6_sid_format, format); + + if (strmatch(format->name, SRV6_SID_FORMAT_USID_F3216_NAME)) + format->config.usid.ewlib_start = + SRV6_SID_FORMAT_USID_F3216_EWLIB_START; + else + assert(0); + + return CMD_SUCCESS; +} + +DEFPY(srv6_sid_format_explicit, + srv6_sid_format_explicit_cmd, + "explicit start (0-4294967295)$start", + "Configure Explicit range\n" + "Configure the start value for the Explicit range\n" + "Specify the start value for the Explicit range\n") +{ + VTY_DECLVAR_CONTEXT(srv6_sid_format, format); + + format->config.uncompressed.explicit_start = start; + + return CMD_SUCCESS; +} + +DEFPY(no_srv6_sid_format_explicit, + no_srv6_sid_format_explicit_cmd, + "no explicit [start (0-4294967295)$start]", + NO_STR + "Configure Explicit range\n" + "Configure the start value for the Explicit range\n" + "Specify the start value for the Explicit range\n") +{ + VTY_DECLVAR_CONTEXT(srv6_sid_format, format); + + if (strmatch(format->name, SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NAME)) + format->config.usid.ewlib_start = + SRV6_SID_FORMAT_UNCOMPRESSED_F4024_EXPLICIT_RANGE_START; + else + assert(0); + + return CMD_SUCCESS; +} + static int zebra_sr_config(struct vty *vty) { struct zebra_srv6 *srv6 = zebra_srv6_get_default(); struct listnode *node; struct srv6_locator *locator; + struct srv6_sid_format *format; char str[256]; bool display_source_srv6 = false; @@ -537,6 +823,51 @@ static int zebra_sr_config(struct vty *vty) } vty_out(vty, " exit\n"); vty_out(vty, " !\n"); + vty_out(vty, " formats\n"); + for (ALL_LIST_ELEMENTS_RO(srv6->sid_formats, node, format)) { + if (format->type == SRV6_SID_FORMAT_TYPE_UNCOMPRESSED) { + vty_out(vty, " format %s\n", format->name); + if (format->config.uncompressed.explicit_start != + SRV6_SID_FORMAT_UNCOMPRESSED_F4024_EXPLICIT_RANGE_START) + vty_out(vty, " explicit start %u\n", + format->config.uncompressed + .explicit_start); + } + if (format->type == + SRV6_SID_FORMAT_TYPE_COMPRESSED_USID) { + vty_out(vty, " format %s\n", format->name); + if (format->config.usid.lib_start != + SRV6_SID_FORMAT_USID_F3216_LIB_START) + vty_out(vty, + " local-id-block start %u\n", + format->config.usid.lib_start); + if (format->config.usid.elib_start != + SRV6_SID_FORMAT_USID_F3216_ELIB_START || + format->config.usid.elib_end != + SRV6_SID_FORMAT_USID_F3216_ELIB_END) + vty_out(vty, + " local-id-block explicit start %u end %u\n", + format->config.usid.elib_start, + format->config.usid.elib_end); + if (format->config.usid.wlib_start != + SRV6_SID_FORMAT_USID_F3216_WLIB_START || + format->config.usid.wlib_end != + SRV6_SID_FORMAT_USID_F3216_WLIB_END) + vty_out(vty, + " wide-local-id-block start %u end %u\n", + format->config.usid.wlib_start, + format->config.usid.wlib_end); + if (format->config.usid.ewlib_start != + SRV6_SID_FORMAT_USID_F3216_EWLIB_START) + vty_out(vty, + " wide-local-id-block explicit start %u\n", + format->config.usid.ewlib_start); + } + vty_out(vty, " exit\n"); + vty_out(vty, " !\n"); + } + vty_out(vty, " exit\n"); + vty_out(vty, " !\n"); vty_out(vty, " exit\n"); vty_out(vty, " !\n"); } @@ -555,11 +886,17 @@ void zebra_srv6_vty_init(void) install_node(&srv6_locs_node); install_node(&srv6_loc_node); install_node(&srv6_encap_node); + install_node(&srv6_sid_formats_node); + install_node(&srv6_sid_format_usid_f3216_node); + install_node(&srv6_sid_format_uncompressed_f4024_node); install_default(SEGMENT_ROUTING_NODE); install_default(SRV6_NODE); install_default(SRV6_LOCS_NODE); install_default(SRV6_LOC_NODE); install_default(SRV6_ENCAP_NODE); + install_default(SRV6_SID_FORMATS_NODE); + install_default(SRV6_SID_FORMAT_USID_F3216_NODE); + install_default(SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE); /* Command for change node */ install_element(CONFIG_NODE, &segment_routing_cmd); @@ -567,14 +904,42 @@ void zebra_srv6_vty_init(void) install_element(SEGMENT_ROUTING_NODE, &no_srv6_cmd); install_element(SRV6_NODE, &srv6_locators_cmd); install_element(SRV6_NODE, &srv6_encap_cmd); + install_element(SRV6_NODE, &srv6_sid_formats_cmd); install_element(SRV6_LOCS_NODE, &srv6_locator_cmd); install_element(SRV6_LOCS_NODE, &no_srv6_locator_cmd); + install_element(SRV6_SID_FORMATS_NODE, &srv6_sid_format_f3216_usid_cmd); + install_element(SRV6_SID_FORMATS_NODE, + &srv6_sid_format_uncompressed_cmd); + install_element(SRV6_SID_FORMATS_NODE, + &no_srv6_sid_format_f3216_usid_cmd); + install_element(SRV6_SID_FORMATS_NODE, + &no_srv6_sid_format_f4024_uncompressed_cmd); /* Command for configuration */ install_element(SRV6_LOC_NODE, &locator_prefix_cmd); install_element(SRV6_LOC_NODE, &locator_behavior_cmd); install_element(SRV6_ENCAP_NODE, &srv6_src_addr_cmd); install_element(SRV6_ENCAP_NODE, &no_srv6_src_addr_cmd); + install_element(SRV6_SID_FORMAT_USID_F3216_NODE, + &srv6_sid_format_usid_lib_cmd); + install_element(SRV6_SID_FORMAT_USID_F3216_NODE, + &no_srv6_sid_format_usid_lib_cmd); + install_element(SRV6_SID_FORMAT_USID_F3216_NODE, + &srv6_sid_format_usid_lib_explicit_cmd); + install_element(SRV6_SID_FORMAT_USID_F3216_NODE, + &no_srv6_sid_format_usid_lib_explicit_cmd); + install_element(SRV6_SID_FORMAT_USID_F3216_NODE, + &srv6_sid_format_usid_wlib_cmd); + install_element(SRV6_SID_FORMAT_USID_F3216_NODE, + &no_srv6_sid_format_usid_wlib_cmd); + install_element(SRV6_SID_FORMAT_USID_F3216_NODE, + &srv6_sid_format_usid_wide_lib_explicit_cmd); + install_element(SRV6_SID_FORMAT_USID_F3216_NODE, + &no_srv6_sid_format_usid_wide_lib_explicit_cmd); + install_element(SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE, + &srv6_sid_format_explicit_cmd); + install_element(SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE, + &no_srv6_sid_format_explicit_cmd); /* Command for operation */ install_element(VIEW_NODE, &show_srv6_locator_cmd); From bf10e4437e476c8550f4f146d34cce0828445a5e Mon Sep 17 00:00:00 2001 From: Carmine Scarpitta Date: Fri, 22 Mar 2024 18:19:36 +0100 Subject: [PATCH 037/347] zebra: Add support for SRv6 SID blocks An SRv6 block is an IPv6 prefix from which SIDs are allocated. This commit adds support for SRv6 SID blocks. Specifically, it adds a data structure to store information about an SRv6 block (e.g., its occupancy status, which SIDs have been allocated and which are available, which SID format is used for that block, etc.). It also adds some functions to manage the block (allocate / free / lookup). These functions will be used in the next commits to support the allocation of SIDs from a block in the SID Manager. Signed-off-by: Carmine Scarpitta --- zebra/zebra_srv6.c | 191 +++++++++++++++++++++++++++++++++++++++++ zebra/zebra_srv6.h | 79 +++++++++++++++++ zebra/zebra_srv6_vty.c | 3 +- 3 files changed, 271 insertions(+), 2 deletions(-) diff --git a/zebra/zebra_srv6.c b/zebra/zebra_srv6.c index 825f0f7fc2..2e5c499838 100644 --- a/zebra/zebra_srv6.c +++ b/zebra/zebra_srv6.c @@ -33,6 +33,10 @@ DEFINE_MGROUP(SRV6_MGR, "SRv6 Manager"); DEFINE_MTYPE_STATIC(SRV6_MGR, SRV6M_CHUNK, "SRv6 Manager Chunk"); +DEFINE_MTYPE_STATIC(SRV6_MGR, ZEBRA_SRV6_SID_BLOCK, "SRv6 SID block"); +DEFINE_MTYPE_STATIC(SRV6_MGR, ZEBRA_SRV6_SID_FUNC, "SRv6 SID function"); +DEFINE_MTYPE_STATIC(SRV6_MGR, ZEBRA_SRV6_USID_WLIB, + "SRv6 uSID Wide LIB information"); /* define hooks for the basic API, so that it can be specialized or served * externally @@ -174,6 +178,176 @@ static struct srv6_sid_format *create_srv6_sid_format_uncompressed(void) return format; } +/* --- Zebra SRv6 SID function management functions ---------------------------- */ + +uint32_t *zebra_srv6_sid_func_alloc(uint32_t func) +{ + uint32_t *sid_func_ptr; + + sid_func_ptr = XCALLOC(MTYPE_ZEBRA_SRV6_SID_FUNC, sizeof(uint32_t)); + *sid_func_ptr = func; + + return sid_func_ptr; +} + +void zebra_srv6_sid_func_free(uint32_t *func) +{ + XFREE(MTYPE_ZEBRA_SRV6_SID_FUNC, func); +} + +/** + * Free an SRv6 SID function. + * + * @param val SRv6 SID function to be freed + */ +void delete_zebra_srv6_sid_func(void *val) +{ + zebra_srv6_sid_func_free((uint32_t *)val); +} + +/* --- Zebra SRv6 SID block management functions ---------------------------- */ + +static struct zebra_srv6_sid_block *zebra_srv6_sid_block_alloc_internal(void) +{ + struct zebra_srv6_sid_block *block = NULL; + + block = XCALLOC(MTYPE_ZEBRA_SRV6_SID_BLOCK, + sizeof(struct zebra_srv6_sid_block)); + + return block; +} + +struct zebra_srv6_sid_block * +zebra_srv6_sid_block_alloc(struct srv6_sid_format *format, + struct prefix_ipv6 *prefix) +{ + struct zebra_srv6_sid_block *block; + + block = zebra_srv6_sid_block_alloc_internal(); + block->sid_format = format; + block->prefix = *prefix; + + if (format) { + if (format->type == SRV6_SID_FORMAT_TYPE_USID) { + uint32_t wlib_start, wlib_end, func; + + /* Init uSID LIB */ + block->u.usid.lib.func_allocated = list_new(); + block->u.usid.lib.func_allocated->del = + delete_zebra_srv6_sid_func; + block->u.usid.lib.func_released = list_new(); + block->u.usid.lib.func_released->del = + delete_zebra_srv6_sid_func; + block->u.usid.lib.first_available_func = + format->config.usid.lib_start; + + /* Init uSID Wide LIB */ + wlib_start = block->sid_format->config.usid.wlib_start; + wlib_end = block->sid_format->config.usid.wlib_end; + block->u.usid.wide_lib = + XCALLOC(MTYPE_ZEBRA_SRV6_USID_WLIB, + (wlib_end - wlib_start + 1) * + sizeof(struct wide_lib)); + for (func = 0; func < wlib_end - wlib_start + 1; + func++) { + block->u.usid.wide_lib[func].func_allocated = + list_new(); + block->u.usid.wide_lib[func].func_allocated->del = + delete_zebra_srv6_sid_func; + block->u.usid.wide_lib[func].func_released = + list_new(); + block->u.usid.wide_lib[func].func_released->del = + delete_zebra_srv6_sid_func; + block->u.usid.wide_lib[func].func = func; + } + } else if (format->type == SRV6_SID_FORMAT_TYPE_UNCOMPRESSED) { + block->u.uncompressed.func_allocated = list_new(); + block->u.uncompressed.func_allocated->del = + delete_zebra_srv6_sid_func; + block->u.uncompressed.func_released = list_new(); + block->u.uncompressed.func_released->del = + delete_zebra_srv6_sid_func; + block->u.uncompressed.first_available_func = + SRV6_SID_FORMAT_UNCOMPRESSED_F4024_FUNC_UNRESERVED_MIN; + } else { + /* We should never arrive here */ + assert(0); + } + } else { + block->u.uncompressed.func_allocated = list_new(); + block->u.uncompressed.func_allocated->del = + delete_zebra_srv6_sid_func; + block->u.uncompressed.func_released = list_new(); + block->u.uncompressed.func_released->del = + delete_zebra_srv6_sid_func; + block->u.uncompressed.first_available_func = 1; + } + + return block; +} + +void zebra_srv6_sid_block_free(struct zebra_srv6_sid_block *block) +{ + if (block->sid_format) { + if (block->sid_format->type == SRV6_SID_FORMAT_TYPE_USID) { + uint32_t wlib_start, wlib_end, func; + + /* Free uSID LIB */ + list_delete(&block->u.usid.lib.func_allocated); + list_delete(&block->u.usid.lib.func_released); + + /* Free uSID Wide LIB */ + wlib_start = block->sid_format->config.usid.wlib_start; + wlib_end = block->sid_format->config.usid.wlib_end; + for (func = 0; func < wlib_end - wlib_start + 1; + func++) { + list_delete(&block->u.usid.wide_lib[func] + .func_allocated); + list_delete(&block->u.usid.wide_lib[func] + .func_released); + } + XFREE(MTYPE_ZEBRA_SRV6_USID_WLIB, + block->u.usid.wide_lib); + } else if (block->sid_format->type == + SRV6_SID_FORMAT_TYPE_UNCOMPRESSED) { + list_delete(&block->u.uncompressed.func_allocated); + list_delete(&block->u.uncompressed.func_released); + } else { + /* We should never arrive here */ + assert(0); + } + } else { + list_delete(&block->u.uncompressed.func_allocated); + list_delete(&block->u.uncompressed.func_released); + } + + XFREE(MTYPE_ZEBRA_SRV6_SID_BLOCK, block); +} + +/** + * Free an SRv6 SID block. + * + * @param val SRv6 SID block to be freed + */ +void delete_zebra_srv6_sid_block(void *val) +{ + zebra_srv6_sid_block_free((struct zebra_srv6_sid_block *)val); +} + +struct zebra_srv6_sid_block * +zebra_srv6_sid_block_lookup(struct prefix_ipv6 *prefix) +{ + struct zebra_srv6 *srv6 = zebra_srv6_get_default(); + struct zebra_srv6_sid_block *block; + struct listnode *node; + + for (ALL_LIST_ELEMENTS_RO(srv6->sid_blocks, node, block)) + if (prefix_match(prefix, &block->prefix)) + return block; + + return NULL; +} + void zebra_srv6_locator_add(struct srv6_locator *locator) { struct zebra_srv6 *srv6 = zebra_srv6_get_default(); @@ -324,6 +498,10 @@ struct zebra_srv6 *zebra_srv6_get_default(void) /* Create SID format `uncompressed` */ format_uncompressed = create_srv6_sid_format_uncompressed(); srv6_sid_format_register(format_uncompressed); + + /* Init list to store SRv6 SID blocks */ + srv6.sid_blocks = list_new(); + srv6.sid_blocks->del = delete_zebra_srv6_sid_block; } return &srv6; } @@ -529,6 +707,7 @@ void zebra_srv6_terminate(void) { struct srv6_locator *locator; struct srv6_sid_format *format; + struct zebra_srv6_sid_block *block; if (srv6.locators) { while (listcount(srv6.locators)) { @@ -541,6 +720,18 @@ void zebra_srv6_terminate(void) list_delete(&srv6.locators); } + /* Free SRv6 SID blocks */ + if (srv6.sid_blocks) { + while (listcount(srv6.sid_blocks)) { + block = listnode_head(srv6.sid_blocks); + + listnode_delete(srv6.sid_blocks, block); + zebra_srv6_sid_block_free(block); + } + + list_delete(&srv6.sid_blocks); + } + /* Free SRv6 SID formats */ if (srv6.sid_formats) { while (listcount(srv6.sid_formats)) { diff --git a/zebra/zebra_srv6.h b/zebra/zebra_srv6.h index 92e4fcf912..e81d182419 100644 --- a/zebra/zebra_srv6.h +++ b/zebra/zebra_srv6.h @@ -38,6 +38,70 @@ #define SRV6_SID_FORMAT_UNCOMPRESSED_F4024_EXPLICIT_RANGE_START 0xFF00 #define SRV6_SID_FORMAT_UNCOMPRESSED_F4024_FUNC_UNRESERVED_MIN 0x40 +/* uSID Wide LIB */ +struct wide_lib { + uint32_t func; + uint32_t num_func_allocated; + uint32_t first_available_func; + struct list *func_allocated; + struct list *func_released; +}; + +/* + * SRv6 SID block. + * + * A SID block is an IPv6 prefix from which SRv6 SIDs are allocated. + * Example: + * SID block = fc00:0::/32 + * SID 1 = fc00:0:1:e000:: + * SID 2 = fc00:0:1:fe00:: + * ... + */ +struct zebra_srv6_sid_block { + /* Prefix of this block, e.g. fc00:0::/32 */ + struct prefix_ipv6 prefix; + + /* Reference counter */ + unsigned long refcnt; + + /* + * Pointer to the SID format that defines the structure of the SIDs + * allocated from this block + */ + struct zebra_srv6_sid_format *sid_format; + + /* + * Run-time information/state of this SID block. + * + * This includes stuff like how many SID functions have been allocated + * from this block, which functions are still available to be allocated + * and so on... + */ + union { + /* Information/state for compressed uSID format */ + struct { + /* uSID Local ID Block (LIB) */ + struct { + uint32_t num_func_allocated; + uint32_t first_available_func; + struct list *func_allocated; + struct list *func_released; + } lib; + + /* uSID Wide LIB */ + struct wide_lib *wide_lib; + } usid; + + /* Information/state for uncompressed SID format */ + struct { + uint32_t num_func_allocated; + uint32_t first_available_func; + struct list *func_allocated; + struct list *func_released; + } uncompressed; + } u; +}; + /* SRv6 instance structure. */ struct zebra_srv6 { struct list *locators; @@ -47,6 +111,9 @@ struct zebra_srv6 { /* SRv6 SID formats */ struct list *sid_formats; + + /* SRv6 SID blocks */ + struct list *sid_blocks; }; /* declare hooks for the basic API, so that it can be specialized or served @@ -103,4 +170,16 @@ void srv6_sid_format_register(struct srv6_sid_format *format); void srv6_sid_format_unregister(struct srv6_sid_format *format); struct srv6_sid_format *srv6_sid_format_lookup(const char *name); +uint32_t *zebra_srv6_sid_func_alloc(uint32_t func); +void zebra_srv6_sid_func_free(uint32_t *func); +void delete_zebra_srv6_sid_func(void *val); + +extern struct zebra_srv6_sid_block * +zebra_srv6_sid_block_alloc(struct zebra_srv6_sid_format *format, + struct prefix_ipv6 *prefix); +extern void zebra_srv6_sid_block_free(struct zebra_srv6_sid_block *block); +extern void delete_zebra_srv6_sid_block(void *val); +extern struct zebra_srv6_sid_block * +zebra_srv6_sid_block_lookup(struct prefix_ipv6 *prefix); + #endif /* _ZEBRA_SRV6_H */ diff --git a/zebra/zebra_srv6_vty.c b/zebra/zebra_srv6_vty.c index e5fe0d58a9..963b528b86 100644 --- a/zebra/zebra_srv6_vty.c +++ b/zebra/zebra_srv6_vty.c @@ -833,8 +833,7 @@ static int zebra_sr_config(struct vty *vty) format->config.uncompressed .explicit_start); } - if (format->type == - SRV6_SID_FORMAT_TYPE_COMPRESSED_USID) { + if (format->type == SRV6_SID_FORMAT_TYPE_USID) { vty_out(vty, " format %s\n", format->name); if (format->config.usid.lib_start != SRV6_SID_FORMAT_USID_F3216_LIB_START) From f00554ed563b8a4ce0cc7fff7ea107d3ae8aa6b1 Mon Sep 17 00:00:00 2001 From: Carmine Scarpitta Date: Wed, 8 May 2024 16:41:05 +0200 Subject: [PATCH 038/347] lib: Add function to copy an SRv6 locator Add a new function to copy an SRv6 locator. Signed-off-by: Carmine Scarpitta --- lib/srv6.c | 15 +++++++++++++++ lib/srv6.h | 2 ++ 2 files changed, 17 insertions(+) diff --git a/lib/srv6.c b/lib/srv6.c index abaff7eab8..1f485fb8ac 100644 --- a/lib/srv6.c +++ b/lib/srv6.c @@ -141,6 +141,21 @@ struct srv6_locator_chunk *srv6_locator_chunk_alloc(void) return chunk; } +void srv6_locator_copy(struct srv6_locator *copy, + const struct srv6_locator *locator) +{ + strlcpy(copy->name, locator->name, sizeof(locator->name)); + copy->prefix = locator->prefix; + copy->block_bits_length = locator->block_bits_length; + copy->node_bits_length = locator->node_bits_length; + copy->function_bits_length = locator->function_bits_length; + copy->argument_bits_length = locator->argument_bits_length; + copy->algonum = locator->algonum; + copy->current = locator->current; + copy->status_up = locator->status_up; + copy->flags = locator->flags; +} + void srv6_locator_free(struct srv6_locator *locator) { if (locator) { diff --git a/lib/srv6.h b/lib/srv6.h index 04f560b267..66f1854dab 100644 --- a/lib/srv6.h +++ b/lib/srv6.h @@ -311,6 +311,8 @@ extern struct srv6_locator_chunk *srv6_locator_chunk_alloc(void); extern void srv6_locator_free(struct srv6_locator *locator); extern void srv6_locator_chunk_list_free(void *data); extern void srv6_locator_chunk_free(struct srv6_locator_chunk **chunk); +extern void srv6_locator_copy(struct srv6_locator *copy, + const struct srv6_locator *locator); json_object *srv6_locator_chunk_json(const struct srv6_locator_chunk *chunk); json_object *srv6_locator_json(const struct srv6_locator *loc); json_object *srv6_locator_detailed_json(const struct srv6_locator *loc); From 779d4c2702ac446cc4b96a1a9d2d62d1b0bbe232 Mon Sep 17 00:00:00 2001 From: Carmine Scarpitta Date: Fri, 22 Mar 2024 19:31:01 +0100 Subject: [PATCH 039/347] zebra: CLI to specify format of an SRv6 locator Add the CLI to choose the SID format of a locator. When the SID format of a locator is changed, the SIDs allocated from that locator might no longer be valid (for example, because the new format might involve a different SID allocation schema). In such a case, it is necessary to notify all the zclients so that they can withdraw/uninstall the old SIDs that use the previous format and allocate/install/advertise the new SIDs based on the new format. Signed-off-by: Carmine Scarpitta --- lib/srv6.h | 6 ++ zebra/zapi_msg.c | 18 +++- zebra/zebra_srv6.c | 133 +++++++++++++++++++++++++++ zebra/zebra_srv6.h | 7 +- zebra/zebra_srv6_vty.c | 200 ++++++++++++++++++++++++++++++++++++++--- 5 files changed, 351 insertions(+), 13 deletions(-) diff --git a/lib/srv6.h b/lib/srv6.h index 66f1854dab..4a6ea5c72b 100644 --- a/lib/srv6.h +++ b/lib/srv6.h @@ -129,6 +129,12 @@ struct srv6_locator { uint8_t flags; #define SRV6_LOCATOR_USID (1 << 0) /* The SRv6 Locator is a uSID Locator */ + /* Pointer to the SID format. */ + struct srv6_sid_format *sid_format; + + /* Pointer to the parent SID block of the locator. */ + void *sid_block; + QOBJ_FIELDS; }; DECLARE_QOBJ_TYPE(srv6_locator); diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index d585ef996b..2d580e2972 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -1136,9 +1136,25 @@ static int zsend_table_manager_connect_response(struct zserv *client, int zsend_zebra_srv6_locator_add(struct zserv *client, struct srv6_locator *loc) { struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ); + struct srv6_locator locator = {}; + struct srv6_sid_format *format = loc->sid_format; + + /* + * Copy the locator and fill locator block/node/func/arg length from the format + * before sending the locator to the zclient + */ + srv6_locator_copy(&locator, loc); + if (format) { + locator.block_bits_length = format->block_len; + locator.node_bits_length = format->node_len; + locator.function_bits_length = format->function_len; + locator.argument_bits_length = format->argument_len; + if (format->type == ZEBRA_SRV6_SID_FORMAT_TYPE_USID) + SET_FLAG(locator.flags, SRV6_LOCATOR_USID); + } zclient_create_header(s, ZEBRA_SRV6_LOCATOR_ADD, VRF_DEFAULT); - zapi_srv6_locator_encode(s, loc); + zapi_srv6_locator_encode(s, &locator); stream_putw_at(s, 0, stream_get_endp(s)); return zserv_send_message(client, s); diff --git a/zebra/zebra_srv6.c b/zebra/zebra_srv6.c index 2e5c499838..e6b3c2a252 100644 --- a/zebra/zebra_srv6.c +++ b/zebra/zebra_srv6.c @@ -126,6 +126,139 @@ struct srv6_sid_format *srv6_sid_format_lookup(const char *name) return NULL; } +/* + * Called to change the SID format of a locator. + * + * After switching the locator to a different format, the SIDs allocated + * from the locator may no longer be valid; we need to notify the + * interested zclient that the locator has changed, so that the + * zclients can withdraw/uninstall the old SIDs, allocate/advertise/program + * the new SIDs. + */ +void zebra_srv6_locator_format_set(struct srv6_locator *locator, + struct srv6_sid_format *format) +{ + struct zebra_srv6 *srv6 = zebra_srv6_get_default(); + struct zebra_srv6_sid_block *block_old, *block_new; + struct prefix_ipv6 block_pfx_new; + struct listnode *node, *nnode; + struct zebra_srv6_sid_ctx *ctx; + + if (!locator) + return; + + locator->sid_format = format; + + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: Locator %s format has changed, old=%s new=%s", + __func__, locator->name, + locator->sid_format ? ((struct srv6_sid_format *) + locator->sid_format) + ->name + : NULL, + format ? format->name : NULL); + + /* Notify zclients that the locator is no longer valid */ + zebra_notify_srv6_locator_delete(locator); + + for (ALL_LIST_ELEMENTS(srv6->sids, node, nnode, ctx)) { + if (!ctx->sid || ctx->sid->locator != locator) + continue; + + if (ctx->sid) + zebra_srv6_sid_free(ctx->sid); + + listnode_delete(srv6->sids, ctx); + zebra_srv6_sid_ctx_free(ctx); + } + + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: Locator %s format has changed, send SRV6_LOCATOR_DEL notification to zclients", + __func__, locator->name); + + /* Release the current parent block */ + block_old = locator->sid_block; + if (block_old) { + block_old->refcnt--; + if (block_old->refcnt == 0) { + listnode_delete(srv6->sid_blocks, block_old); + zebra_srv6_sid_block_free(block_old); + } + } + locator->sid_block = NULL; + + block_pfx_new = locator->prefix; + if (format) + block_pfx_new.prefixlen = format->block_len; + else + block_pfx_new.prefixlen = locator->block_bits_length; + apply_mask(&block_pfx_new); + + /* Allocate the new parent block */ + block_new = zebra_srv6_sid_block_lookup(&block_pfx_new); + if (!block_new) { + block_new = zebra_srv6_sid_block_alloc(format, &block_pfx_new); + listnode_add(srv6->sid_blocks, block_new); + } + + block_new->refcnt++; + locator->sid_block = block_new; + + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: Locator %s format has changed, send SRV6_LOCATOR_ADD notification to zclients", + __func__, locator->name); + + /* Notify zclients about the updated locator */ + zebra_srv6_locator_add(locator); +} + +/* + * Called when a SID format is modified by the user. + * + * After modifying a SID format, the SIDs that are using that format may no + * longer be valid. + * This function walks through the list of locators that are using the SID format + * and notifies the zclients that the locator has changed, so that the zclients + * can withdraw/uninstall the old SIDs, allocate/program/advertise the new SIDs. + */ +void zebra_srv6_sid_format_changed_cb(struct srv6_sid_format *format) +{ + struct zebra_srv6 *srv6 = zebra_srv6_get_default(); + struct srv6_locator *locator; + struct listnode *node, *nnode; + struct zebra_srv6_sid_ctx *ctx; + + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: SID format %s has changed. Notifying zclients.", + __func__, format->name); + + for (ALL_LIST_ELEMENTS_RO(srv6->locators, node, locator)) { + if (locator->sid_format == format) { + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: Locator %s has changed because its format (%s) has been modified. Notifying zclients.", + __func__, locator->name, + format->name); + + /* Notify zclients that the locator is no longer valid */ + zebra_notify_srv6_locator_delete(locator); + + for (ALL_LIST_ELEMENTS(srv6->sids, node, nnode, ctx)) { + if (!ctx->sid || ctx->sid->locator != locator) + continue; + + if (ctx->sid) + zebra_srv6_sid_free(ctx->sid); + + listnode_delete(srv6->sids, ctx); + zebra_srv6_sid_ctx_free(ctx); + } + + /* Notify zclients about the updated locator */ + zebra_notify_srv6_locator_add(locator); + } + } +} + /* * Helper function to create the SRv6 compressed format `usid-f3216`. */ diff --git a/zebra/zebra_srv6.h b/zebra/zebra_srv6.h index e81d182419..0a8b58ce61 100644 --- a/zebra/zebra_srv6.h +++ b/zebra/zebra_srv6.h @@ -68,7 +68,7 @@ struct zebra_srv6_sid_block { * Pointer to the SID format that defines the structure of the SIDs * allocated from this block */ - struct zebra_srv6_sid_format *sid_format; + struct srv6_sid_format *sid_format; /* * Run-time information/state of this SID block. @@ -169,13 +169,16 @@ extern void zebra_srv6_encap_src_addr_unset(void); void srv6_sid_format_register(struct srv6_sid_format *format); void srv6_sid_format_unregister(struct srv6_sid_format *format); struct srv6_sid_format *srv6_sid_format_lookup(const char *name); +void zebra_srv6_locator_format_set(struct srv6_locator *locator, + struct srv6_sid_format *format); +void zebra_srv6_sid_format_changed_cb(struct srv6_sid_format *format); uint32_t *zebra_srv6_sid_func_alloc(uint32_t func); void zebra_srv6_sid_func_free(uint32_t *func); void delete_zebra_srv6_sid_func(void *val); extern struct zebra_srv6_sid_block * -zebra_srv6_sid_block_alloc(struct zebra_srv6_sid_format *format, +zebra_srv6_sid_block_alloc(struct srv6_sid_format *format, struct prefix_ipv6 *prefix); extern void zebra_srv6_sid_block_free(struct zebra_srv6_sid_block *block); extern void delete_zebra_srv6_sid_block(void *val); diff --git a/zebra/zebra_srv6_vty.c b/zebra/zebra_srv6_vty.c index 963b528b86..c664a9c69f 100644 --- a/zebra/zebra_srv6_vty.c +++ b/zebra/zebra_srv6_vty.c @@ -232,7 +232,7 @@ DEFUN (show_srv6_locator_detail, if (locator->sid_format->type == SRV6_SID_FORMAT_TYPE_USID) vty_out(vty, "Behavior: uSID\n"); - } else { + } else { vty_out(vty, "Block-Bit-Len: %u\n", locator->block_bits_length); vty_out(vty, "Node-Bit-Len: %u\n", @@ -244,7 +244,7 @@ DEFUN (show_srv6_locator_detail, if (CHECK_FLAG(locator->flags, SRV6_LOCATOR_USID)) vty_out(vty, "Behavior: uSID\n"); - } + } vty_out(vty, "Chunks:\n"); for (ALL_LIST_ELEMENTS_RO((struct list *)locator->chunks, node, @@ -286,9 +286,30 @@ DEFUN (no_srv6, struct zebra_srv6 *srv6 = zebra_srv6_get_default(); struct srv6_locator *locator; struct listnode *node, *nnode; + struct zebra_srv6_sid_block *block; + struct zebra_srv6_sid_ctx *ctx; + + for (ALL_LIST_ELEMENTS(srv6->sids, node, nnode, ctx)) { + if (ctx->sid) + zebra_srv6_sid_free(ctx->sid); + + listnode_delete(srv6->sids, ctx); + zebra_srv6_sid_ctx_free(ctx); + } + + for (ALL_LIST_ELEMENTS(srv6->locators, node, nnode, locator)) { + block = locator->sid_block; + if (block) { + block->refcnt--; + if (block->refcnt == 0) { + listnode_delete(srv6->sid_blocks, block); + zebra_srv6_sid_block_free(block); + } + locator->sid_block = NULL; + } - for (ALL_LIST_ELEMENTS(srv6->locators, node, nnode, locator)) zebra_srv6_locator_delete(locator); + } return CMD_SUCCESS; } @@ -335,12 +356,37 @@ DEFUN (no_srv6_locator, "Segment Routing SRv6 locator\n" "Specify locator-name\n") { + struct zebra_srv6 *srv6 = zebra_srv6_get_default(); + struct zebra_srv6_sid_block *block; + struct listnode *node, *nnode; + struct zebra_srv6_sid_ctx *ctx; struct srv6_locator *locator = zebra_srv6_locator_lookup(argv[2]->arg); if (!locator) { vty_out(vty, "%% Can't find SRv6 locator\n"); return CMD_WARNING_CONFIG_FAILED; } + for (ALL_LIST_ELEMENTS(srv6->sids, node, nnode, ctx)) { + if (!ctx->sid || ctx->sid->locator != locator) + continue; + + if (ctx->sid) + zebra_srv6_sid_free(ctx->sid); + + listnode_delete(srv6->sids, ctx); + zebra_srv6_sid_ctx_free(ctx); + } + + block = locator->sid_block; + if (block) { + block->refcnt--; + if (block->refcnt == 0) { + listnode_delete(srv6->sid_blocks, block); + zebra_srv6_sid_block_free(block); + } + locator->sid_block = NULL; + } + zebra_srv6_locator_delete(locator); return CMD_SUCCESS; } @@ -361,14 +407,37 @@ DEFPY (locator_prefix, VTY_DECLVAR_CONTEXT(srv6_locator, locator); struct srv6_locator_chunk *chunk = NULL; struct listnode *node = NULL; + uint8_t expected_prefixlen; + struct srv6_sid_format *format; locator->prefix = *prefix; func_bit_len = func_bit_len ?: ZEBRA_SRV6_FUNCTION_LENGTH; + expected_prefixlen = prefix->prefixlen; + format = locator->sid_format; + if (format) { + if (strmatch(format->name, SRV6_SID_FORMAT_USID_F3216_NAME)) + expected_prefixlen = + SRV6_SID_FORMAT_USID_F3216_BLOCK_LEN + + SRV6_SID_FORMAT_USID_F3216_NODE_LEN; + else if (strmatch(format->name, + SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NAME)) + expected_prefixlen = + SRV6_SID_FORMAT_UNCOMPRESSED_F4024_BLOCK_LEN + + SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE_LEN; + } + + if (prefix->prefixlen != expected_prefixlen) { + vty_out(vty, + "%% Locator prefix length '%u' inconsistent with configured format '%s'. Please either use a prefix length that is consistent with the format or change the format.\n", + prefix->prefixlen, format->name); + return CMD_WARNING_CONFIG_FAILED; + } + /* Resolve optional arguments */ if (block_bit_len == 0 && node_bit_len == 0) { - block_bit_len = - prefix->prefixlen - ZEBRA_SRV6_LOCATOR_NODE_LENGTH; + block_bit_len = prefix->prefixlen - + ZEBRA_SRV6_LOCATOR_NODE_LENGTH; node_bit_len = ZEBRA_SRV6_LOCATOR_NODE_LENGTH; } else if (block_bit_len == 0) { block_bit_len = prefix->prefixlen - node_bit_len; @@ -439,7 +508,8 @@ DEFPY (locator_prefix, } } - zebra_srv6_locator_add(locator); + zebra_srv6_locator_format_set(locator, locator->sid_format); + return CMD_SUCCESS; } @@ -460,8 +530,9 @@ DEFPY (locator_behavior, /* SRv6 locator uSID flag already set, nothing to do */ return CMD_SUCCESS; - /* Remove old locator from zclients */ - zebra_notify_srv6_locator_delete(locator); + if (!locator->sid_format) + /* Remove old locator from zclients */ + zebra_notify_srv6_locator_delete(locator); /* Set/Unset the SRV6_LOCATOR_USID */ if (no) @@ -469,8 +540,75 @@ DEFPY (locator_behavior, else SET_FLAG(locator->flags, SRV6_LOCATOR_USID); - /* Notify the new locator to zclients */ - zebra_notify_srv6_locator_add(locator); + if (!locator->sid_format) + /* Notify the new locator to zclients */ + zebra_srv6_locator_add(locator); + + return CMD_SUCCESS; +} + +DEFPY(locator_sid_format, + locator_sid_format_cmd, + "format $format", + "Configure SRv6 SID format\n" + "Specify usid-f3216 format\n" + "Specify uncompressed-f4024 format\n") +{ + VTY_DECLVAR_CONTEXT(srv6_locator, locator); + struct srv6_sid_format *sid_format = NULL; + uint8_t expected_prefixlen; + + expected_prefixlen = locator->prefix.prefixlen; + if (strmatch(format, SRV6_SID_FORMAT_USID_F3216_NAME)) + expected_prefixlen = SRV6_SID_FORMAT_USID_F3216_BLOCK_LEN + + SRV6_SID_FORMAT_USID_F3216_NODE_LEN; + else if (strmatch(format, SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NAME)) + expected_prefixlen = + SRV6_SID_FORMAT_UNCOMPRESSED_F4024_BLOCK_LEN + + SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE_LEN; + + if (IPV6_ADDR_SAME(&locator->prefix, &in6addr_any)) { + vty_out(vty, + "%% Unexpected configuration sequence: the prefix of the locator is required before configuring the format. Please configure the prefix first and then configure the format.\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + if (locator->prefix.prefixlen != expected_prefixlen) { + vty_out(vty, + "%% Locator prefix length '%u' inconsistent with configured format '%s'. Please either use a prefix length that is consistent with the format or change the format.\n", + locator->prefix.prefixlen, format); + return CMD_WARNING_CONFIG_FAILED; + } + + sid_format = srv6_sid_format_lookup(format); + if (!sid_format) { + vty_out(vty, "%% Cannot find SRv6 SID format '%s'\n", format); + return CMD_WARNING_CONFIG_FAILED; + } + + if (sid_format == locator->sid_format) + /* Format has not changed, nothing to do */ + return CMD_SUCCESS; + + zebra_srv6_locator_format_set(locator, sid_format); + + return CMD_SUCCESS; +} + +DEFPY (no_locator_sid_format, + no_locator_sid_format_cmd, + "no format [WORD]", + NO_STR + "Configure SRv6 SID format\n" + "Specify SRv6 SID format\n") +{ + VTY_DECLVAR_CONTEXT(srv6_locator, locator); + + if (!locator->sid_format) + /* SID format already unset, nothing to do */ + return CMD_SUCCESS; + + zebra_srv6_locator_format_set(locator, NULL); return CMD_SUCCESS; } @@ -550,6 +688,9 @@ DEFUN(no_srv6_sid_format_f3216_usid, format->config.usid.wlib_end = SRV6_SID_FORMAT_USID_F3216_WLIB_END; format->config.usid.ewlib_start = SRV6_SID_FORMAT_USID_F3216_EWLIB_START; + /* Notify zclients that the format has changed */ + zebra_srv6_sid_format_changed_cb(format); + return CMD_SUCCESS; } @@ -583,6 +724,9 @@ DEFUN(no_srv6_sid_format_f4024_uncompressed, format->config.uncompressed.explicit_start = SRV6_SID_FORMAT_UNCOMPRESSED_F4024_EXPLICIT_RANGE_START; + /* Notify zclients that the format has changed */ + zebra_srv6_sid_format_changed_cb(format); + return CMD_SUCCESS; } @@ -597,6 +741,9 @@ DEFPY(srv6_sid_format_usid_lib, format->config.usid.lib_start = start; + /* Notify zclients that the format has changed */ + zebra_srv6_sid_format_changed_cb(format); + return CMD_SUCCESS; } @@ -616,6 +763,9 @@ DEFPY(no_srv6_sid_format_usid_lib, else assert(0); + /* Notify zclients that the format has changed */ + zebra_srv6_sid_format_changed_cb(format); + return CMD_SUCCESS; } @@ -634,6 +784,9 @@ DEFPY(srv6_sid_format_usid_lib_explicit, format->config.usid.elib_start = start; format->config.usid.elib_end = end; + /* Notify zclients that the format has changed */ + zebra_srv6_sid_format_changed_cb(format); + return CMD_SUCCESS; } @@ -659,6 +812,9 @@ DEFPY(no_srv6_sid_format_usid_lib_explicit, assert(0); } + /* Notify zclients that the format has changed */ + zebra_srv6_sid_format_changed_cb(format); + return CMD_SUCCESS; } @@ -676,6 +832,9 @@ DEFPY(srv6_sid_format_usid_wlib, format->config.usid.wlib_start = start; format->config.usid.wlib_end = end; + /* Notify zclients that the format has changed */ + zebra_srv6_sid_format_changed_cb(format); + return CMD_SUCCESS; } @@ -700,6 +859,9 @@ DEFPY(no_srv6_sid_format_usid_wlib, assert(0); } + /* Notify zclients that the format has changed */ + zebra_srv6_sid_format_changed_cb(format); + return CMD_SUCCESS; } @@ -715,6 +877,9 @@ DEFPY(srv6_sid_format_usid_wide_lib_explicit, format->config.usid.ewlib_start = start; + /* Notify zclients that the format has changed */ + zebra_srv6_sid_format_changed_cb(format); + return CMD_SUCCESS; } @@ -735,6 +900,9 @@ DEFPY(no_srv6_sid_format_usid_wide_lib_explicit, else assert(0); + /* Notify zclients that the format has changed */ + zebra_srv6_sid_format_changed_cb(format); + return CMD_SUCCESS; } @@ -749,6 +917,9 @@ DEFPY(srv6_sid_format_explicit, format->config.uncompressed.explicit_start = start; + /* Notify zclients that the format has changed */ + zebra_srv6_sid_format_changed_cb(format); + return CMD_SUCCESS; } @@ -768,6 +939,9 @@ DEFPY(no_srv6_sid_format_explicit, else assert(0); + /* Notify zclients that the format has changed */ + zebra_srv6_sid_format_changed_cb(format); + return CMD_SUCCESS; } @@ -818,6 +992,10 @@ static int zebra_sr_config(struct vty *vty) vty_out(vty, "\n"); if (CHECK_FLAG(locator->flags, SRV6_LOCATOR_USID)) vty_out(vty, " behavior usid\n"); + if (locator->sid_format) { + format = locator->sid_format; + vty_out(vty, " format %s\n", format->name); + } vty_out(vty, " exit\n"); vty_out(vty, " !\n"); } @@ -917,6 +1095,8 @@ void zebra_srv6_vty_init(void) /* Command for configuration */ install_element(SRV6_LOC_NODE, &locator_prefix_cmd); install_element(SRV6_LOC_NODE, &locator_behavior_cmd); + install_element(SRV6_LOC_NODE, &locator_sid_format_cmd); + install_element(SRV6_LOC_NODE, &no_locator_sid_format_cmd); install_element(SRV6_ENCAP_NODE, &srv6_src_addr_cmd); install_element(SRV6_ENCAP_NODE, &no_srv6_src_addr_cmd); install_element(SRV6_SID_FORMAT_USID_F3216_NODE, From 3cb88e69848d607a8d069b0858798e2de324fd43 Mon Sep 17 00:00:00 2001 From: Carmine Scarpitta Date: Mon, 6 May 2024 17:44:18 +0200 Subject: [PATCH 040/347] lib: Add support for SRv6 SIDs Add a data structure to represent an SRv6 SID context and the related management functions (allocate/free). Signed-off-by: Carmine Scarpitta --- lib/srv6.c | 24 ++++++++++++++++++++ lib/srv6.h | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 89 insertions(+) diff --git a/lib/srv6.c b/lib/srv6.c index 1f485fb8ac..883d429b62 100644 --- a/lib/srv6.c +++ b/lib/srv6.c @@ -14,6 +14,7 @@ DEFINE_QOBJ_TYPE(srv6_sid_format); DEFINE_MTYPE_STATIC(LIB, SRV6_LOCATOR, "SRV6 locator"); DEFINE_MTYPE_STATIC(LIB, SRV6_LOCATOR_CHUNK, "SRV6 locator chunk"); DEFINE_MTYPE_STATIC(LIB, SRV6_SID_FORMAT, "SRv6 SID format"); +DEFINE_MTYPE_STATIC(LIB, SRV6_SID_CTX, "SRv6 SID context"); const char *seg6local_action2str(uint32_t action) { @@ -201,6 +202,29 @@ void delete_srv6_sid_format(void *val) srv6_sid_format_free((struct srv6_sid_format *)val); } +struct srv6_sid_ctx *srv6_sid_ctx_alloc(enum seg6local_action_t behavior, + struct in_addr *nh4, + struct in6_addr *nh6, vrf_id_t vrf_id) +{ + struct srv6_sid_ctx *ctx = NULL; + + ctx = XCALLOC(MTYPE_SRV6_SID_CTX, sizeof(struct srv6_sid_ctx)); + ctx->behavior = behavior; + if (nh4) + ctx->nh4 = *nh4; + if (nh6) + ctx->nh6 = *nh6; + if (vrf_id) + ctx->vrf_id = vrf_id; + + return ctx; +} + +void srv6_sid_ctx_free(struct srv6_sid_ctx *ctx) +{ + XFREE(MTYPE_SRV6_SID_CTX, ctx); +} + json_object *srv6_locator_chunk_json(const struct srv6_locator_chunk *chunk) { json_object *jo_root = NULL; diff --git a/lib/srv6.h b/lib/srv6.h index 4a6ea5c72b..01b0820133 100644 --- a/lib/srv6.h +++ b/lib/srv6.h @@ -246,6 +246,17 @@ struct srv6_sid_format { }; DECLARE_QOBJ_TYPE(srv6_sid_format); +/* Context for an SRv6 SID */ +struct srv6_sid_ctx { + /* Behavior associated with the SID */ + enum seg6local_action_t behavior; + + /* Behavior-specific attributes */ + struct in_addr nh4; + struct in6_addr nh6; + vrf_id_t vrf_id; +}; + static inline const char *seg6_mode2str(enum seg6_mode_t mode) { switch (mode) { @@ -309,6 +320,54 @@ const char *seg6local_context2str(char *str, size_t size, const struct seg6local_context *ctx, uint32_t action); +static inline const char *srv6_sid_ctx2str(char *str, size_t size, + const struct srv6_sid_ctx *ctx) +{ + int len = 0; + + len += snprintf(str + len, size - len, "%s", + seg6local_action2str(ctx->behavior)); + + switch (ctx->behavior) { + case ZEBRA_SEG6_LOCAL_ACTION_UNSPEC: + break; + + case ZEBRA_SEG6_LOCAL_ACTION_END: + len += snprintf(str + len, size - len, " USP"); + break; + + case ZEBRA_SEG6_LOCAL_ACTION_END_X: + case ZEBRA_SEG6_LOCAL_ACTION_END_DX6: + len += snprintfrr(str + len, size - len, " nh6 %pI6", &ctx->nh6); + break; + + case ZEBRA_SEG6_LOCAL_ACTION_END_DX4: + len += snprintfrr(str + len, size - len, " nh4 %pI4", &ctx->nh4); + break; + + case ZEBRA_SEG6_LOCAL_ACTION_END_T: + case ZEBRA_SEG6_LOCAL_ACTION_END_DT6: + case ZEBRA_SEG6_LOCAL_ACTION_END_DT4: + case ZEBRA_SEG6_LOCAL_ACTION_END_DT46: + len += snprintf(str + len, size - len, " vrf_id %u", + ctx->vrf_id); + break; + + case ZEBRA_SEG6_LOCAL_ACTION_END_DX2: + case ZEBRA_SEG6_LOCAL_ACTION_END_B6: + case ZEBRA_SEG6_LOCAL_ACTION_END_B6_ENCAP: + case ZEBRA_SEG6_LOCAL_ACTION_END_BM: + case ZEBRA_SEG6_LOCAL_ACTION_END_S: + case ZEBRA_SEG6_LOCAL_ACTION_END_AS: + case ZEBRA_SEG6_LOCAL_ACTION_END_AM: + case ZEBRA_SEG6_LOCAL_ACTION_END_BPF: + default: + len += snprintf(str + len, size - len, " unknown(%s)", __func__); + } + + return str; +} + int snprintf_seg6_segs(char *str, size_t size, const struct seg6_segs *segs); @@ -329,6 +388,12 @@ extern struct srv6_sid_format *srv6_sid_format_alloc(const char *name); extern void srv6_sid_format_free(struct srv6_sid_format *format); extern void delete_srv6_sid_format(void *format); +extern struct srv6_sid_ctx *srv6_sid_ctx_alloc(enum seg6local_action_t behavior, + struct in_addr *nh4, + struct in6_addr *nh6, + vrf_id_t vrf_id); +extern void srv6_sid_ctx_free(struct srv6_sid_ctx *ctx); + #ifdef __cplusplus } #endif From 8b3f3785467acc27268579d34746d504b00b800f Mon Sep 17 00:00:00 2001 From: Carmine Scarpitta Date: Sat, 23 Mar 2024 13:42:19 +0100 Subject: [PATCH 041/347] zebra: Add support for SRv6 SIDs Add a data structure to represent an SRv6 SID context and the related management functions (allocate/free). Signed-off-by: Carmine Scarpitta --- zebra/zebra_srv6.c | 98 ++++++++++++++++++++++++++++++++++++++++++ zebra/zebra_srv6.h | 105 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 203 insertions(+) diff --git a/zebra/zebra_srv6.c b/zebra/zebra_srv6.c index e6b3c2a252..6e72440274 100644 --- a/zebra/zebra_srv6.c +++ b/zebra/zebra_srv6.c @@ -37,6 +37,8 @@ DEFINE_MTYPE_STATIC(SRV6_MGR, ZEBRA_SRV6_SID_BLOCK, "SRv6 SID block"); DEFINE_MTYPE_STATIC(SRV6_MGR, ZEBRA_SRV6_SID_FUNC, "SRv6 SID function"); DEFINE_MTYPE_STATIC(SRV6_MGR, ZEBRA_SRV6_USID_WLIB, "SRv6 uSID Wide LIB information"); +DEFINE_MTYPE_STATIC(SRV6_MGR, ZEBRA_SRV6_SID, "SRv6 SID"); +DEFINE_MTYPE_STATIC(SRV6_MGR, ZEBRA_SRV6_SID_CTX, "SRv6 SID context"); /* define hooks for the basic API, so that it can be specialized or served * externally @@ -94,6 +96,33 @@ static int zebra_srv6_cleanup(struct zserv *client) return 0; } +/* --- Zebra SRv6 SID context management functions -------------------------- */ + +struct zebra_srv6_sid_ctx *zebra_srv6_sid_ctx_alloc(void) +{ + struct zebra_srv6_sid_ctx *ctx = NULL; + + ctx = XCALLOC(MTYPE_ZEBRA_SRV6_SID_CTX, + sizeof(struct zebra_srv6_sid_ctx)); + + return ctx; +} + +void zebra_srv6_sid_ctx_free(struct zebra_srv6_sid_ctx *ctx) +{ + XFREE(MTYPE_ZEBRA_SRV6_SID_CTX, ctx); +} + +/** + * Free an SRv6 SID context. + * + * @param val SRv6 SID context to be freed + */ +void delete_zebra_srv6_sid_ctx(void *val) +{ + zebra_srv6_sid_ctx_free((struct zebra_srv6_sid_ctx *)val); +} + /* --- Zebra SRv6 SID format management functions --------------------------- */ void srv6_sid_format_register(struct srv6_sid_format *format) @@ -481,6 +510,58 @@ zebra_srv6_sid_block_lookup(struct prefix_ipv6 *prefix) return NULL; } +/* --- Zebra SRv6 SID management functions ---------------------------------- */ + +/** + * Alloc and fill an SRv6 SID. + * + * @param ctx Context associated with the SID to be created + * @param sid_value IPv6 address associated with the SID to be created + * @param locator Parent locator of the SID to be created + * @param sid_block Block from which the SID value has been allocated + * @param sid_func Function part of the SID to be created + * @param alloc_mode Allocation mode of the Function (dynamic vs explicit) + * @return The requested SID + */ +struct zebra_srv6_sid * +zebra_srv6_sid_alloc(struct zebra_srv6_sid_ctx *ctx, struct in6_addr *sid_value, + struct srv6_locator *locator, + struct zebra_srv6_sid_block *sid_block, uint32_t sid_func, + enum srv6_sid_alloc_mode alloc_mode) +{ + struct zebra_srv6_sid *sid; + + if (!ctx || !sid_value) + return NULL; + + sid = XCALLOC(MTYPE_ZEBRA_SRV6_SID, sizeof(struct zebra_srv6_sid)); + sid->ctx = ctx; + sid->value = *sid_value; + sid->locator = locator; + sid->block = sid_block; + sid->func = sid_func; + sid->alloc_mode = alloc_mode; + sid->client_list = list_new(); + + return sid; +} + +void zebra_srv6_sid_free(struct zebra_srv6_sid *sid) +{ + list_delete(&sid->client_list); + XFREE(MTYPE_ZEBRA_SRV6_SID, sid); +} + +/** + * Free an SRv6 SID. + * + * @param val SRv6 SID to be freed + */ +void delete_zebra_srv6_sid(void *val) +{ + zebra_srv6_sid_free((struct zebra_srv6_sid *)val); +} + void zebra_srv6_locator_add(struct srv6_locator *locator) { struct zebra_srv6 *srv6 = zebra_srv6_get_default(); @@ -632,6 +713,10 @@ struct zebra_srv6 *zebra_srv6_get_default(void) format_uncompressed = create_srv6_sid_format_uncompressed(); srv6_sid_format_register(format_uncompressed); + /* Init list to store SRv6 SIDs */ + srv6.sids = list_new(); + srv6.sids->del = delete_zebra_srv6_sid_ctx; + /* Init list to store SRv6 SID blocks */ srv6.sid_blocks = list_new(); srv6.sid_blocks->del = delete_zebra_srv6_sid_block; @@ -841,6 +926,7 @@ void zebra_srv6_terminate(void) struct srv6_locator *locator; struct srv6_sid_format *format; struct zebra_srv6_sid_block *block; + struct zebra_srv6_sid_ctx *sid_ctx; if (srv6.locators) { while (listcount(srv6.locators)) { @@ -853,6 +939,18 @@ void zebra_srv6_terminate(void) list_delete(&srv6.locators); } + /* Free SRv6 SIDs */ + if (srv6.sids) { + while (listcount(srv6.sids)) { + sid_ctx = listnode_head(srv6.sids); + + listnode_delete(srv6.sids, sid_ctx); + zebra_srv6_sid_ctx_free(sid_ctx); + } + + list_delete(&srv6.sids); + } + /* Free SRv6 SID blocks */ if (srv6.sid_blocks) { while (listcount(srv6.sid_blocks)) { diff --git a/zebra/zebra_srv6.h b/zebra/zebra_srv6.h index 0a8b58ce61..ad10092575 100644 --- a/zebra/zebra_srv6.h +++ b/zebra/zebra_srv6.h @@ -102,6 +102,96 @@ struct zebra_srv6_sid_block { } u; }; +/** + * The function part of an SRv6 SID can be allocated in one + * of the following ways: + * - dynamic: allocate any available function + * - explicit: allocate a specific function + */ +enum srv6_sid_alloc_mode { + SRV6_SID_ALLOC_MODE_UNSPEC = 0, + /* Dynamic SID allocation */ + SRV6_SID_ALLOC_MODE_DYNAMIC = 1, + /* Explicit SID allocation */ + SRV6_SID_ALLOC_MODE_EXPLICIT = 2, + SRV6_SID_ALLOC_MODE_MAX = 3, +}; + +/** + * Convert SID allocation mode to string. + * + * @param alloc_mode SID allocation mode + * @return String representing the allocation mode + */ +static inline const char * +srv6_sid_alloc_mode2str(enum srv6_sid_alloc_mode alloc_mode) +{ + switch (alloc_mode) { + case SRV6_SID_ALLOC_MODE_EXPLICIT: + return "explicit"; + case SRV6_SID_ALLOC_MODE_DYNAMIC: + return "dynamic"; + case SRV6_SID_ALLOC_MODE_UNSPEC: + return "unspec"; + case SRV6_SID_ALLOC_MODE_MAX: + default: + return "unknown"; + } +} + +/* SRv6 SID instance. */ +struct zebra_srv6_sid { + /* + * SID context associated with the SID. + * Defines behavior and attributes of the SID. + */ + struct zebra_srv6_sid_ctx *ctx; + + /* SID value (e.g. fc00:0:1:e000::) */ + struct in6_addr value; + + /* Pointer to the SRv6 locator from which the SID has been allocated */ + struct srv6_locator *locator; + + /* Pointer to the SRv6 block from which the SID has been allocated */ + struct zebra_srv6_sid_block *block; + + /* + * Function part of the SID + * Example: + * SID = fc00:0:1:e000:: => func = e000 + */ + uint32_t func; + + /* SID wide function. */ + uint32_t wide_func; + + /* SID allocation mode: dynamic or explicit */ + enum srv6_sid_alloc_mode alloc_mode; + + /* List of clients that are using the SID */ + struct list *client_list; +}; + +/* + * Zebra SRv6 SID context. + * A context defines a behavior and (optionally) some behavior-specific + * attributes. Client daemons (bgp, isis, ...) ask SRv6 Manager to allocate + * a SID for a particular context. SRv6 Manager is responsible for allocating + * a SID from a given SID block and associating with the context. + * + * Example: + * bgp asks to associate a SID to the context {behavior=End.DT46 vrf=Vrf10}. + * SRv6 Manager allocate SID fc00:0:1:e000:: for that context. + */ +struct zebra_srv6_sid_ctx { + /* SRv6 SID context information. */ + struct srv6_sid_ctx ctx; + + /* SID associated with the context. */ + struct zebra_srv6_sid *sid; +}; + /* SRv6 instance structure. */ struct zebra_srv6 { struct list *locators; @@ -112,6 +202,9 @@ struct zebra_srv6 { /* SRv6 SID formats */ struct list *sid_formats; + /* SRv6 SIDs */ + struct list *sids; + /* SRv6 SID blocks */ struct list *sid_blocks; }; @@ -185,4 +278,16 @@ extern void delete_zebra_srv6_sid_block(void *val); extern struct zebra_srv6_sid_block * zebra_srv6_sid_block_lookup(struct prefix_ipv6 *prefix); +extern struct zebra_srv6_sid * +zebra_srv6_sid_alloc(struct zebra_srv6_sid_ctx *ctx, struct in6_addr *sid_value, + struct srv6_locator *locator, + struct zebra_srv6_sid_block *sid_block, uint32_t sid_func, + enum srv6_sid_alloc_mode alloc_mode); +extern void zebra_srv6_sid_free(struct zebra_srv6_sid *sid); +extern void delete_zebra_srv6_sid(void *val); + +extern struct zebra_srv6_sid_ctx *zebra_srv6_sid_ctx_alloc(void); +extern void zebra_srv6_sid_ctx_free(struct zebra_srv6_sid_ctx *ctx); +extern void delete_zebra_srv6_sid_ctx(void *val); + #endif /* _ZEBRA_SRV6_H */ From ded79d7013f00a61b19e029a5104b453f696253a Mon Sep 17 00:00:00 2001 From: Carmine Scarpitta Date: Sat, 23 Mar 2024 15:49:43 +0100 Subject: [PATCH 042/347] lib: Add ZAPI operation get SRv6 locator Add a new ZAPI operation, ZEBRA_SRV6_MANAGER_GET_LOCATOR, which allows a daemon to request information about a specific locator from the SRv6 SID Manager. Signed-off-by: Carmine Scarpitta --- lib/log.c | 1 + lib/zclient.c | 41 +++++++++++++++++++++++++++++++++++++++++ lib/zclient.h | 3 +++ 3 files changed, 45 insertions(+) diff --git a/lib/log.c b/lib/log.c index 969ca79256..427e72703c 100644 --- a/lib/log.c +++ b/lib/log.c @@ -436,6 +436,7 @@ static const struct zebra_desc_table command_types[] = { DESC_ENTRY(ZEBRA_SRV6_LOCATOR_DELETE), DESC_ENTRY(ZEBRA_SRV6_MANAGER_GET_LOCATOR_CHUNK), DESC_ENTRY(ZEBRA_SRV6_MANAGER_RELEASE_LOCATOR_CHUNK), + DESC_ENTRY(ZEBRA_SRV6_MANAGER_GET_LOCATOR), DESC_ENTRY(ZEBRA_ERROR), DESC_ENTRY(ZEBRA_CLIENT_CAPABILITIES), DESC_ENTRY(ZEBRA_OPAQUE_MESSAGE), diff --git a/lib/zclient.c b/lib/zclient.c index 1aab7b48ba..90ec024155 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -3268,6 +3268,47 @@ int srv6_manager_release_locator_chunk(struct zclient *zclient, return zclient_send_message(zclient); } +/** + * Function to request a SRv6 locator in an asynchronous way + * + * @param zclient The zclient used to connect to SRv6 Manager (zebra) + * @param locator_name Name of SRv6 locator + * @return 0 on success, -1 otherwise + */ +int srv6_manager_get_locator(struct zclient *zclient, const char *locator_name) +{ + struct stream *s; + size_t len; + + if (!locator_name) + return -1; + + if (zclient->sock < 0) { + flog_err(EC_LIB_ZAPI_SOCKET, "%s: invalid zclient socket", + __func__); + return -1; + } + + if (zclient_debug) + zlog_debug("Getting SRv6 Locator %s", locator_name); + + len = strlen(locator_name); + + /* Send request */ + s = zclient->obuf; + stream_reset(s); + zclient_create_header(s, ZEBRA_SRV6_MANAGER_GET_LOCATOR, VRF_DEFAULT); + + /* Locator name */ + stream_putw(s, len); + stream_put(s, locator_name, len); + + /* Put length at the first point of the stream. */ + stream_putw_at(s, 0, stream_get_endp(s)); + + return zclient_send_message(zclient); +} + /* * Asynchronous label chunk request * diff --git a/lib/zclient.h b/lib/zclient.h index 3759f94542..87617003d8 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -209,6 +209,7 @@ typedef enum { ZEBRA_SRV6_LOCATOR_DELETE, ZEBRA_SRV6_MANAGER_GET_LOCATOR_CHUNK, ZEBRA_SRV6_MANAGER_RELEASE_LOCATOR_CHUNK, + ZEBRA_SRV6_MANAGER_GET_LOCATOR, ZEBRA_ERROR, ZEBRA_CLIENT_CAPABILITIES, ZEBRA_OPAQUE_MESSAGE, @@ -1074,6 +1075,8 @@ extern int srv6_manager_get_locator_chunk(struct zclient *zclient, const char *locator_name); extern int srv6_manager_release_locator_chunk(struct zclient *zclient, const char *locator_name); +extern int srv6_manager_get_locator(struct zclient *zclient, + const char *locator_name); extern enum zclient_send_status zebra_send_sr_policy(struct zclient *zclient, int cmd, From ee1d20879b0cb44abb77954190a55a07e1921435 Mon Sep 17 00:00:00 2001 From: Carmine Scarpitta Date: Sat, 23 Mar 2024 18:31:12 +0100 Subject: [PATCH 043/347] lib: Add ZAPI operations to get/release SRv6 SIDs Add two new ZAPI operations: `ZEBRA_SRV6_MANAGER_GET_SRV6_SID` and `ZEBRA_SRV6_MANAGER_RELEASE_SRV6_SID`. These APIs allow a daemon to get and release an SRv6 SID, respectively. Signed-off-by: Carmine Scarpitta --- lib/log.c | 2 + lib/zclient.c | 103 ++++++++++++++++++++++++++++++++++++++++++++++++++ lib/zclient.h | 13 +++++++ 3 files changed, 118 insertions(+) diff --git a/lib/log.c b/lib/log.c index 427e72703c..fa8a8734a4 100644 --- a/lib/log.c +++ b/lib/log.c @@ -437,6 +437,8 @@ static const struct zebra_desc_table command_types[] = { DESC_ENTRY(ZEBRA_SRV6_MANAGER_GET_LOCATOR_CHUNK), DESC_ENTRY(ZEBRA_SRV6_MANAGER_RELEASE_LOCATOR_CHUNK), DESC_ENTRY(ZEBRA_SRV6_MANAGER_GET_LOCATOR), + DESC_ENTRY(ZEBRA_SRV6_MANAGER_GET_SRV6_SID), + DESC_ENTRY(ZEBRA_SRV6_MANAGER_RELEASE_SRV6_SID), DESC_ENTRY(ZEBRA_ERROR), DESC_ENTRY(ZEBRA_CLIENT_CAPABILITIES), DESC_ENTRY(ZEBRA_OPAQUE_MESSAGE), diff --git a/lib/zclient.c b/lib/zclient.c index 90ec024155..8308215de9 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -3309,6 +3309,109 @@ int srv6_manager_get_locator(struct zclient *zclient, const char *locator_name) return zclient_send_message(zclient); } +/** + * Function to request an SRv6 SID in an asynchronous way + * + * @param zclient The zclient used to connect to SRv6 manager (zebra) + * @param ctx Context associated with the SRv6 SID + * @param sid_value SRv6 SID value for explicit SID allocation + * @param locator_name Name of the parent locator for dynamic SID allocation + * @param sid_func SID function assigned by the SRv6 Manager + * @result 0 on success, -1 otherwise + */ +int srv6_manager_get_sid(struct zclient *zclient, const struct srv6_sid_ctx *ctx, + struct in6_addr *sid_value, const char *locator_name, + uint32_t *sid_func) +{ + struct stream *s; + uint8_t flags = 0; + size_t len; + char buf[256]; + + if (zclient->sock < 0) { + flog_err(EC_LIB_ZAPI_SOCKET, "%s: invalid zclient socket", + __func__); + return ZCLIENT_SEND_FAILURE; + } + + if (zclient_debug) + zlog_debug("Getting SRv6 SID: %s", + srv6_sid_ctx2str(buf, sizeof(buf), ctx)); + + /* send request */ + s = zclient->obuf; + stream_reset(s); + + zclient_create_header(s, ZEBRA_SRV6_MANAGER_GET_SRV6_SID, VRF_DEFAULT); + + /* Context associated with the SRv6 SID */ + stream_put(s, ctx, sizeof(struct srv6_sid_ctx)); + + /* Flags */ + if (!sid_zero_ipv6(sid_value)) + SET_FLAG(flags, ZAPI_SRV6_MANAGER_SID_FLAG_HAS_SID_VALUE); + if (locator_name) + SET_FLAG(flags, ZAPI_SRV6_MANAGER_SID_FLAG_HAS_LOCATOR); + stream_putc(s, flags); + + /* SRv6 SID value */ + if (CHECK_FLAG(flags, ZAPI_SRV6_MANAGER_SID_FLAG_HAS_SID_VALUE)) + stream_put(s, sid_value, sizeof(struct in6_addr)); + + /* SRv6 locator */ + if (CHECK_FLAG(flags, ZAPI_SRV6_MANAGER_SID_FLAG_HAS_LOCATOR)) { + len = strlen(locator_name); + stream_putw(s, len); + stream_put(s, locator_name, len); + } + + /* Put length at the first point of the stream. */ + stream_putw_at(s, 0, stream_get_endp(s)); + + /* Send the request to SRv6 Manager */ + return zclient_send_message(zclient); +} + +/** + * Function to release an SRv6 SID + * + * @param zclient Zclient used to connect to SRv6 manager (zebra) + * @param ctx Context associated with the SRv6 SID to be removed + * @result 0 on success, -1 otherwise + */ +int srv6_manager_release_sid(struct zclient *zclient, + const struct srv6_sid_ctx *ctx) +{ + struct stream *s; + char buf[256]; + + if (zclient->sock < 0) { + flog_err(EC_LIB_ZAPI_SOCKET, "%s: invalid zclient socket", + __func__); + return -1; + } + + if (zclient_debug) + zlog_debug("Releasing SRv6 SID: %s", + srv6_sid_ctx2str(buf, sizeof(buf), ctx)); + + /* send request */ + s = zclient->obuf; + stream_reset(s); + + zclient_create_header(s, ZEBRA_SRV6_MANAGER_RELEASE_SRV6_SID, + VRF_DEFAULT); + + /* Context associated with the SRv6 SID */ + stream_put(s, ctx, sizeof(struct srv6_sid_ctx)); + + /* Put length at the first point of the stream. */ + stream_putw_at(s, 0, stream_get_endp(s)); + + /* Send the SID release message */ + return zclient_send_message(zclient); +} + /* * Asynchronous label chunk request * diff --git a/lib/zclient.h b/lib/zclient.h index 87617003d8..bb527f0b41 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -210,6 +210,8 @@ typedef enum { ZEBRA_SRV6_MANAGER_GET_LOCATOR_CHUNK, ZEBRA_SRV6_MANAGER_RELEASE_LOCATOR_CHUNK, ZEBRA_SRV6_MANAGER_GET_LOCATOR, + ZEBRA_SRV6_MANAGER_GET_SRV6_SID, + ZEBRA_SRV6_MANAGER_RELEASE_SRV6_SID, ZEBRA_ERROR, ZEBRA_CLIENT_CAPABILITIES, ZEBRA_OPAQUE_MESSAGE, @@ -1071,12 +1073,23 @@ extern int tm_get_table_chunk(struct zclient *zclient, uint32_t chunk_size, uint32_t *start, uint32_t *end); extern int tm_release_table_chunk(struct zclient *zclient, uint32_t start, uint32_t end); + +/* Zebra SRv6 Manager flags */ +#define ZAPI_SRV6_MANAGER_SID_FLAG_HAS_SID_VALUE 0x01 +#define ZAPI_SRV6_MANAGER_SID_FLAG_HAS_LOCATOR 0x02 + extern int srv6_manager_get_locator_chunk(struct zclient *zclient, const char *locator_name); extern int srv6_manager_release_locator_chunk(struct zclient *zclient, const char *locator_name); extern int srv6_manager_get_locator(struct zclient *zclient, const char *locator_name); +extern int srv6_manager_get_sid(struct zclient *zclient, + const struct srv6_sid_ctx *ctx, + struct in6_addr *sid_value, + const char *locator_name, uint32_t *sid_func); +extern int srv6_manager_release_sid(struct zclient *zclient, + const struct srv6_sid_ctx *ctx); extern enum zclient_send_status zebra_send_sr_policy(struct zclient *zclient, int cmd, From 164117f2ec3d85c7ed63bb81413fb0d28651bc84 Mon Sep 17 00:00:00 2001 From: Carmine Scarpitta Date: Mon, 6 May 2024 17:46:44 +0200 Subject: [PATCH 044/347] lib: Add missing info to locator encode/decode Include block/node/function/argument lengthi when encoding/decoding an SRv6 locator. Signed-off-by: Carmine Scarpitta --- lib/zclient.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lib/zclient.c b/lib/zclient.c index 8308215de9..b0e97b0f12 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -1125,6 +1125,10 @@ int zapi_srv6_locator_encode(struct stream *s, const struct srv6_locator *l) stream_put(s, l->name, strlen(l->name)); stream_putw(s, l->prefix.prefixlen); stream_put(s, &l->prefix.prefix, sizeof(l->prefix.prefix)); + stream_putc(s, l->block_bits_length); + stream_putc(s, l->node_bits_length); + stream_putc(s, l->function_bits_length); + stream_putc(s, l->argument_bits_length); stream_putc(s, l->flags); return 0; } @@ -1141,6 +1145,10 @@ int zapi_srv6_locator_decode(struct stream *s, struct srv6_locator *l) STREAM_GETW(s, l->prefix.prefixlen); STREAM_GET(&l->prefix.prefix, s, sizeof(l->prefix.prefix)); l->prefix.family = AF_INET6; + STREAM_GETC(s, l->block_bits_length); + STREAM_GETC(s, l->node_bits_length); + STREAM_GETC(s, l->function_bits_length); + STREAM_GETC(s, l->argument_bits_length); STREAM_GETC(s, l->flags); return 0; From f8da4a29e58ec301c72a17f238686a59b62edef0 Mon Sep 17 00:00:00 2001 From: Carmine Scarpitta Date: Sat, 23 Mar 2024 15:50:24 +0100 Subject: [PATCH 045/347] zebra: Repond to `GET_LOCATOR` ZAPI request The previous commits introduced a new operation, `ZEBRA_SRV6_MANAGER_GET_LOCATOR`, allowing a daemon to request information about a specific SRv6 locator from the SRv6 SID Manager. This commit extends the SID Manager to respond to a `ZEBRA_SRV6_MANAGER_GET_LOCATOR` request and provide the requested locator information. Signed-off-by: Carmine Scarpitta --- zebra/zapi_msg.c | 29 +++++++++++++++++++++++++++++ zebra/zapi_msg.h | 3 +++ zebra/zebra_srv6.c | 37 +++++++++++++++++++++++++++++++++++++ zebra/zebra_srv6.h | 8 ++++++++ 4 files changed, 77 insertions(+) diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index 2d580e2972..21c18a1445 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -3006,6 +3006,31 @@ static void zread_srv6_manager_release_locator_chunk(struct zserv *client, return; } +/** + * Handle SRv6 locator get request received from a client daemon protocol. + * + * @param client The client zapi session + * @param msg The request message + */ +static void zread_srv6_manager_get_locator(struct zserv *client, + struct stream *msg) +{ + struct stream *s = msg; + uint16_t len; + char locator_name[SRV6_LOCNAME_SIZE] = { 0 }; + struct srv6_locator *locator = NULL; + + /* Get data */ + STREAM_GETW(s, len); + STREAM_GET(locator_name, s, len); + + /* Call hook to get the locator info using wrapper */ + srv6_manager_get_locator_call(&locator, client, locator_name); + +stream_failure: + return; +} + static void zread_srv6_manager_request(ZAPI_HANDLER_ARGS) { switch (hdr->command) { @@ -3017,6 +3042,9 @@ static void zread_srv6_manager_request(ZAPI_HANDLER_ARGS) zread_srv6_manager_release_locator_chunk(client, msg, zvrf_id(zvrf)); break; + case ZEBRA_SRV6_MANAGER_GET_LOCATOR: + zread_srv6_manager_get_locator(client, msg); + break; default: zlog_err("%s: unknown SRv6 Manager command", __func__); break; @@ -3965,6 +3993,7 @@ void (*const zserv_handlers[])(ZAPI_HANDLER_ARGS) = { [ZEBRA_MLAG_FORWARD_MSG] = zebra_mlag_forward_client_msg, [ZEBRA_SRV6_MANAGER_GET_LOCATOR_CHUNK] = zread_srv6_manager_request, [ZEBRA_SRV6_MANAGER_RELEASE_LOCATOR_CHUNK] = zread_srv6_manager_request, + [ZEBRA_SRV6_MANAGER_GET_LOCATOR] = zread_srv6_manager_request, [ZEBRA_CLIENT_CAPABILITIES] = zread_client_capabilities, [ZEBRA_NEIGH_DISCOVER] = zread_neigh_discover, [ZEBRA_NHG_ADD] = zread_nhg_add, diff --git a/zebra/zapi_msg.h b/zebra/zapi_msg.h index 43f734d26e..c7123e2593 100644 --- a/zebra/zapi_msg.h +++ b/zebra/zapi_msg.h @@ -110,6 +110,9 @@ extern int zsend_zebra_srv6_locator_delete(struct zserv *client, extern int zsend_srv6_manager_get_locator_chunk_response(struct zserv *client, vrf_id_t vrf_id, struct srv6_locator *loc); +extern int zsend_srv6_manager_get_locator_response(struct zserv *client, + struct srv6_locator *locator); + #ifdef __cplusplus } #endif diff --git a/zebra/zebra_srv6.c b/zebra/zebra_srv6.c index 6e72440274..0217be8c7f 100644 --- a/zebra/zebra_srv6.c +++ b/zebra/zebra_srv6.c @@ -61,6 +61,11 @@ DEFINE_HOOK(srv6_manager_release_chunk, vrf_id_t vrf_id), (client, locator_name, vrf_id)); +DEFINE_HOOK(srv6_manager_get_locator, + (struct srv6_locator **locator, struct zserv *client, + const char *locator_name), + (locator, client, locator_name)); + /* define wrappers to be called in zapi_msg.c (as hooks must be called in * source file where they were defined) */ @@ -91,6 +96,13 @@ int srv6_manager_client_disconnect_cb(struct zserv *client) return 0; } +void srv6_manager_get_locator_call(struct srv6_locator **locator, + struct zserv *client, + const char *locator_name) +{ + hook_call(srv6_manager_get_locator, locator, client, locator_name); +} + static int zebra_srv6_cleanup(struct zserv *client) { return 0; @@ -921,6 +933,28 @@ void zebra_srv6_encap_src_addr_unset(void) memset(&srv6->encap_src_addr, 0, sizeof(struct in6_addr)); } +/** + * Handle a get SRv6 Locator request received from a client. + * + * It looks up the requested locator and send it to the client. + * + * @param locator SRv6 locator returned by this function + * @param client The client that sent the Get SRv6 Locator request + * @param locator_name Name of the locator to look up + * + * @return 0 on success + */ +static int srv6_manager_get_srv6_locator_internal(struct srv6_locator **locator, + struct zserv *client, + const char *locator_name) +{ + *locator = zebra_srv6_locator_lookup(locator_name); + if (!*locator) + return -1; + + return zsend_zebra_srv6_locator_add(client, *locator); +} + void zebra_srv6_terminate(void) { struct srv6_locator *locator; @@ -983,6 +1017,9 @@ void zebra_srv6_init(void) zebra_srv6_manager_get_locator_chunk); hook_register(srv6_manager_release_chunk, zebra_srv6_manager_release_locator_chunk); + + hook_register(srv6_manager_get_locator, + srv6_manager_get_srv6_locator_internal); } bool zebra_srv6_is_enable(void) diff --git a/zebra/zebra_srv6.h b/zebra/zebra_srv6.h index ad10092575..681789e4ac 100644 --- a/zebra/zebra_srv6.h +++ b/zebra/zebra_srv6.h @@ -231,6 +231,10 @@ DECLARE_HOOK(srv6_manager_release_chunk, vrf_id_t vrf_id), (client, locator_name, vrf_id)); +DECLARE_HOOK(srv6_manager_get_locator, + (struct srv6_locator **locator, struct zserv *client, + const char *locator_name), + (locator, client, locator_name)); extern void zebra_srv6_locator_add(struct srv6_locator *locator); extern void zebra_srv6_locator_delete(struct srv6_locator *locator); @@ -286,6 +290,10 @@ zebra_srv6_sid_alloc(struct zebra_srv6_sid_ctx *ctx, struct in6_addr *sid_value, extern void zebra_srv6_sid_free(struct zebra_srv6_sid *sid); extern void delete_zebra_srv6_sid(void *val); +extern void srv6_manager_get_locator_call(struct srv6_locator **locator, + struct zserv *client, + const char *locator_name); + extern struct zebra_srv6_sid_ctx *zebra_srv6_sid_ctx_alloc(void); extern void zebra_srv6_sid_ctx_free(struct zebra_srv6_sid_ctx *ctx); extern void delete_zebra_srv6_sid_ctx(void *val); From c570d2bcaec477167d613d1b2bf57021200d1f89 Mon Sep 17 00:00:00 2001 From: Carmine Scarpitta Date: Sat, 23 Mar 2024 16:30:58 +0100 Subject: [PATCH 046/347] zebra: Add functions to alloc/release SRv6 SIDs Add functions to allocate/release SRv6 SIDs. SIDs can be allocated either explicitly (allocate a specific SID) or dynamically (allocate any available SID). Signed-off-by: Carmine Scarpitta --- zebra/zapi_msg.c | 2 +- zebra/zebra_errors.c | 12 + zebra/zebra_errors.h | 2 + zebra/zebra_srv6.c | 1270 ++++++++++++++++++++++++++++++++++++++++++ zebra/zebra_srv6.h | 5 + 5 files changed, 1290 insertions(+), 1 deletion(-) diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index 21c18a1445..52ee087689 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -1149,7 +1149,7 @@ int zsend_zebra_srv6_locator_add(struct zserv *client, struct srv6_locator *loc) locator.node_bits_length = format->node_len; locator.function_bits_length = format->function_len; locator.argument_bits_length = format->argument_len; - if (format->type == ZEBRA_SRV6_SID_FORMAT_TYPE_USID) + if (format->type == SRV6_SID_FORMAT_TYPE_USID) SET_FLAG(locator.flags, SRV6_LOCATOR_USID); } diff --git a/zebra/zebra_errors.c b/zebra/zebra_errors.c index 09b369e23e..dcfa37d268 100644 --- a/zebra/zebra_errors.c +++ b/zebra/zebra_errors.c @@ -787,6 +787,18 @@ static struct log_ref ferr_zebra_err[] = { .suggestion = "Wait for Zebra to reattempt update.", }, + { + .code = EC_ZEBRA_SM_CANNOT_ASSIGN_SID, + .title = "SRv6 manager unable to assign SID", + .description = "Zebra's SRv6 manager was unable to assign a SID to client.", + .suggestion = "Ensure that Zebra has a sufficient SID range available.", + }, + { + .code = EC_ZEBRA_SM_DAEMON_MISMATCH, + .title = "Daemon mismatch when releasing SRV6 SIDs", + .description = "Zebra noticed a mismatch between a SRv6 SID and a protocol daemon number or instance when releasing unused SRv6 SIDs.", + .suggestion = "Ignore this error.", + }, { .code = END_FERR, } diff --git a/zebra/zebra_errors.h b/zebra/zebra_errors.h index 3ac654bda5..84632e1ad5 100644 --- a/zebra/zebra_errors.h +++ b/zebra/zebra_errors.h @@ -124,6 +124,8 @@ enum zebra_log_refs { EC_ZEBRA_GRE_SET_UPDATE, EC_ZEBRA_SRV6M_UNRELEASED_LOCATOR_CHUNK, EC_ZEBRA_INTF_UPDATE_FAILURE, + EC_ZEBRA_SM_CANNOT_ASSIGN_SID, + EC_ZEBRA_SM_DAEMON_MISMATCH, }; void zebra_error_init(void); diff --git a/zebra/zebra_srv6.c b/zebra/zebra_srv6.c index 0217be8c7f..047422b9e3 100644 --- a/zebra/zebra_srv6.c +++ b/zebra/zebra_srv6.c @@ -40,6 +40,10 @@ DEFINE_MTYPE_STATIC(SRV6_MGR, ZEBRA_SRV6_USID_WLIB, DEFINE_MTYPE_STATIC(SRV6_MGR, ZEBRA_SRV6_SID, "SRv6 SID"); DEFINE_MTYPE_STATIC(SRV6_MGR, ZEBRA_SRV6_SID_CTX, "SRv6 SID context"); +/* Prototypes */ +static int release_srv6_sid_func_dynamic(struct zebra_srv6_sid_block *block, + uint32_t sid_func); + /* define hooks for the basic API, so that it can be specialized or served * externally */ @@ -933,6 +937,1272 @@ void zebra_srv6_encap_src_addr_unset(void) memset(&srv6->encap_src_addr, 0, sizeof(struct in6_addr)); } +/* --- SRv6 SID Allocation/Release functions -------------------------------- */ + +/** + * Return the SRv6 SID obtained composing the locator and function. + * + * @param sid_value SRv6 SID address returned + * @param locator Parent locator of the SRv6 SID + * @param sid_func Function part of the SID + * @return True if success, False otherwise + */ +static bool zebra_srv6_sid_compose(struct in6_addr *sid_value, + struct srv6_locator *locator, + uint32_t sid_func) +{ + uint8_t offset, func_len; + struct srv6_sid_format *format = locator->sid_format; + + if (!sid_value || !locator) + return false; + + if (format) { + offset = format->block_len + format->node_len; + func_len = format->function_len; + } else { + offset = locator->block_bits_length + locator->node_bits_length; + func_len = locator->function_bits_length; + } + + *sid_value = locator->prefix.prefix; + for (uint8_t idx = 0; idx < func_len; idx++) { + uint8_t tidx = offset + idx; + + sid_value->s6_addr[tidx / 8] &= ~(0x1 << (7 - tidx % 8)); + if (sid_func >> (func_len - 1 - idx) & 0x1) + sid_value->s6_addr[tidx / 8] |= 0x1 << (7 - tidx % 8); + } + + return true; +} + +/** + * Return the parent locator and function of an SRv6 SID. + * + * @param sid_value SRv6 SID address to be decomposed + * @param sid_block Parent block of the SRv6 SID + * @param locator Parent locator of the SRv6 SID + * @param sid_func Function part of the SID + * @param sid_wide_func Wide function of the SID + * @return True if success, False otherwise + */ +static bool zebra_srv6_sid_decompose(struct in6_addr *sid_value, + struct zebra_srv6_sid_block **sid_block, + struct srv6_locator **locator, + uint32_t *sid_func, uint32_t *sid_wide_func) +{ + struct zebra_srv6 *srv6 = zebra_srv6_get_default(); + struct srv6_locator *l; + struct zebra_srv6_sid_block *b; + struct srv6_sid_format *format; + struct listnode *node; + struct prefix_ipv6 tmp_prefix; + uint8_t offset, func_len; + + if (!sid_value || !sid_func) + return false; + + *sid_func = 0; + *sid_wide_func = 0; + + /* + * Build a temporary prefix_ipv6 object representing the SRv6 SID. + * This temporary prefix object is used below by the prefix_match + * function to check if the SID belongs to a specific locator. + */ + tmp_prefix.family = AF_INET6; + tmp_prefix.prefixlen = IPV6_MAX_BITLEN; + tmp_prefix.prefix = *sid_value; + + /* + * Lookup the parent locator of the SID and return the locator and + * the function of the SID. + */ + for (ALL_LIST_ELEMENTS_RO(srv6->locators, node, l)) { + /* + * Check if the locator prefix includes the temporary prefix + * representing the SID. + */ + if (prefix_match((struct prefix *)&l->prefix, + (struct prefix *)&tmp_prefix)) { + format = l->sid_format; + + if (format) { + offset = format->block_len + format->node_len; + func_len = format->function_len; + } else { + offset = l->block_bits_length + + l->node_bits_length; + func_len = l->function_bits_length; + } + + for (uint8_t idx = 0; idx < func_len; idx++) { + uint8_t tidx = offset + idx; + *sid_func |= (sid_value->s6_addr[tidx / 8] & + (0x1 << (7 - tidx % 8))) + << (((func_len - 1 - idx) / 8) * 8); + } + + /* + * If function comes from the Wide LIB range, we also + * need to get the Wide function. + */ + if (format && format->type == SRV6_SID_FORMAT_TYPE_USID) { + if (*sid_func >= format->config.usid.wlib_start && + *sid_func <= format->config.usid.wlib_end) { + format = l->sid_format; + + offset = format->block_len + + format->node_len + + format->function_len; + + for (uint8_t idx = 0; idx < 16; idx++) { + uint8_t tidx = offset + idx; + *sid_wide_func |= + (sid_value->s6_addr[tidx / + 8] & + (0x1 << (7 - tidx % 8))) + << (((16 - 1 - idx) / 8) * + 8); + } + } + } + + *locator = l; + *sid_block = l->sid_block; + + return true; + } + } + + /* + * If we arrive here, the SID does not belong to any locator. + * Then, let's try to find the parent block from which the SID + * has been allocated. + */ + + /* + * Lookup the parent block of the SID and return the block and + * the function of the SID. + */ + for (ALL_LIST_ELEMENTS_RO(srv6->sid_blocks, node, b)) { + /* + * Check if the block prefix includes the temporary prefix + * representing the SID + */ + if (prefix_match((struct prefix *)&b->prefix, + (struct prefix *)&tmp_prefix)) { + format = b->sid_format; + + if (!format) + continue; + + offset = format->block_len + format->node_len; + func_len = format->function_len; + + for (uint8_t idx = 0; idx < func_len; idx++) { + uint8_t tidx = offset + idx; + *sid_func |= (sid_value->s6_addr[tidx / 8] & + (0x1 << (7 - tidx % 8))) + << ((func_len - 1 - idx) / 8); + } + + /* + * If function comes from the Wide LIB range, we also + * need to get the Wide function. + */ + if (*sid_func >= format->config.usid.wlib_start && + *sid_func <= format->config.usid.wlib_end) { + format = b->sid_format; + + offset = format->block_len + format->node_len + + format->function_len; + + for (uint8_t idx = 0; idx < 16; idx++) { + uint8_t tidx = offset + idx; + *sid_wide_func |= + (sid_value->s6_addr[tidx / 8] & + (0x1 << (7 - tidx % 8))) + << (((16 - 1 - idx) / 8) * 8); + } + } + + *sid_block = b; + + return true; + } + } + + return false; +} + +/** + * Allocate an explicit SID function (i.e. specific SID function value) from a given SID block. + * + * @param block SRv6 SID block from which the SID function has to be allocated + * @param sid_func SID function to be allocated + * @param sid_wide_func SID wide function to be allocated + * + * @return true on success, false otherwise + */ +static bool alloc_srv6_sid_func_explicit(struct zebra_srv6_sid_block *block, + uint32_t sid_func, + uint32_t sid_wide_func) +{ + struct srv6_sid_format *format; + struct listnode *node; + uint32_t *sid_func_ptr = NULL; + + if (!block) + return false; + + format = block->sid_format; + + if (ZEBRA_DEBUG_PACKET) + zlog_debug("%s: trying to allocate explicit SID function %u from block %pFX", + __func__, sid_func, &block->prefix); + + /* + * Allocate SID function from the corresponding range depending on the SID format type + */ + if (format) { + if (format->type == SRV6_SID_FORMAT_TYPE_USID) { + uint32_t elib_start = format->config.usid.elib_start; + uint32_t elib_end = format->config.usid.elib_end; + uint32_t wlib_end = format->config.usid.wlib_end; + uint32_t ewlib_start = format->config.usid.ewlib_start; + uint32_t ewlib_end = wlib_end; + uint32_t *sid_wide_func_ptr = NULL; + + /* Figure out the range from which the SID function has been allocated and release it */ + if ((sid_func >= elib_start) && (sid_func <= elib_end)) { + /* The SID function has to be allocated from the ELIB range */ + + /* Ensure that the requested SID function has not already been taken */ + for (ALL_LIST_ELEMENTS_RO(block->u.usid.lib + .func_allocated, + node, sid_func_ptr)) + if (*sid_func_ptr == sid_func) + break; + + if (sid_func_ptr) { + zlog_err("%s: invalid SM request arguments: SID function %u already taken", + __func__, sid_func); + return false; + } + + /* + * Mark the SID function as "taken" by adding it to the "func_allocated" list and + * increase the counter of function allocated + */ + sid_func_ptr = + zebra_srv6_sid_func_alloc(sid_func); + listnode_add(block->u.usid.lib.func_allocated, + sid_func_ptr); + block->u.usid.lib.num_func_allocated++; + } else if ((sid_func >= ewlib_start) && + (sid_func <= ewlib_end)) { + /* The SID function has to be allocated from the EWLIB range */ + + /* Ensure that the requested SID function has not already been taken */ + for (ALL_LIST_ELEMENTS_RO(block->u.usid + .wide_lib[sid_func] + .func_allocated, + node, + sid_wide_func_ptr)) + if (*sid_wide_func_ptr == sid_wide_func) + break; + + if (sid_wide_func_ptr) { + zlog_err("%s: invalid SM request arguments: SID function %u already taken", + __func__, sid_func); + return false; + } + + /* + * Mark the SID function as "taken" by adding it to the "func_allocated" list and + * increase the counter of function allocated + */ + sid_wide_func_ptr = zebra_srv6_sid_func_alloc( + sid_wide_func); + listnode_add(block->u.usid.wide_lib[sid_func] + .func_allocated, + sid_wide_func_ptr); + block->u.usid.wide_lib[sid_func] + .num_func_allocated++; + } else { + zlog_warn("%s: function %u is outside ELIB [%u/%u] and EWLIB alloc ranges [%u/%u]", + __func__, sid_func, elib_start, + elib_end, ewlib_start, ewlib_end); + return -1; + } + } else if (format->type == SRV6_SID_FORMAT_TYPE_UNCOMPRESSED) { + uint32_t explicit_start = + format->config.uncompressed.explicit_start; + uint32_t explicit_end = + (uint32_t)((1 << format->function_len) - 1); + + /* Ensure that the SID function comes from the Explicit range */ + if (!(sid_func >= explicit_start && + sid_func <= explicit_end)) { + zlog_err("%s: invalid SM request arguments: SID function %u out of explicit range (%u - %u)", + __func__, sid_func, explicit_start, + explicit_end); + return false; + } + + /* Ensure that the SID function has not already been taken */ + + for (ALL_LIST_ELEMENTS_RO(block->u.uncompressed + .func_allocated, + node, sid_func_ptr)) + if (*sid_func_ptr == sid_func) + break; + + /* SID function already taken */ + if (sid_func_ptr) { + zlog_err("%s: invalid SM request arguments: SID function %u already taken", + __func__, sid_func); + return false; + } + + /* + * Mark the SID function as "taken" by adding it to the "func_allocated" list and + * increase the counter of function allocated + */ + sid_func_ptr = zebra_srv6_sid_func_alloc(sid_func); + listnode_add(block->u.uncompressed.func_allocated, + sid_func_ptr); + block->u.uncompressed.num_func_allocated++; + } else { + /* We should never arrive here */ + zlog_err("%s: unknown SID format type: %u", __func__, + format->type); + assert(0); + } + } else { + /* Ensure that the SID function has not already been taken */ + + for (ALL_LIST_ELEMENTS_RO(block->u.uncompressed.func_allocated, + node, sid_func_ptr)) + if (*sid_func_ptr == sid_func) + break; + + /* SID function already taken */ + if (sid_func_ptr) { + zlog_err("%s: invalid SM request arguments: SID function %u already taken", + __func__, sid_func); + return false; + } + + /* + * Mark the SID function as "taken" by adding it to the "func_allocated" list and + * increase the counter of function allocated + */ + sid_func_ptr = zebra_srv6_sid_func_alloc(sid_func); + listnode_add(block->u.uncompressed.func_allocated, sid_func_ptr); + block->u.uncompressed.num_func_allocated++; + } + + if (ZEBRA_DEBUG_PACKET) + zlog_debug("%s: allocated explicit SID function %u from block %pFX", + __func__, sid_func, &block->prefix); + + return true; +} + +/** + * Allocate a dynamic SID function (i.e. any available SID function value) from a given SID block. + * + * @param block SRv6 SID block from which the SID function has to be allocated + * @param sid_func SID function allocated + * + * @return true on success, false otherwise + */ +static bool alloc_srv6_sid_func_dynamic(struct zebra_srv6_sid_block *block, + uint32_t *sid_func) +{ + struct srv6_sid_format *format; + uint32_t *sid_func_ptr = NULL; + + if (!block || !sid_func) + return false; + + format = block->sid_format; + + if (ZEBRA_DEBUG_PACKET) + zlog_debug("%s: trying to allocate dynamic SID function from block %pFX", + __func__, &block->prefix); + + /* + * Allocate SID function from the corresponding range depending on the SID format type + */ + if (format) { + if (format->type == SRV6_SID_FORMAT_TYPE_USID) { + /* Format is uSID and behavior => allocate SID function from LIB range */ + + /* The Dynamic LIB range ends where the Explicit LIB range begins */ + uint32_t dlib_end = format->config.usid.elib_start - 1; + + /* Check if we ran out of available SID functions */ + if (block->u.usid.lib.first_available_func > dlib_end) { + zlog_warn("%s: SRv6: Warning, SRv6 Dynamic LIB is depleted", + __func__); + return false; + } + + /* + * First, let's check if there are any SID functions that were previously + * allocated and then released. + */ + if (listcount(block->u.usid.lib.func_released) != 0) { + /* + * There are SID functions previously allocated and then released, + * let's pick the first one and reuse it now. + */ + sid_func_ptr = listnode_head( + block->u.usid.lib.func_released); + *sid_func = *sid_func_ptr; + listnode_delete(block->u.usid.lib.func_released, + sid_func_ptr); + zebra_srv6_sid_func_free(sid_func_ptr); + } else { + /* + * There are no SID functions previously allocated and then released, + * let's allocate a new function from the pool of available functions. + */ + *sid_func = + block->u.usid.lib.first_available_func; + block->u.usid.lib.first_available_func++; + } + + /* Increase the counter of SID functions allocated */ + block->u.usid.lib.num_func_allocated++; + + if (block->u.usid.lib.first_available_func > dlib_end) + zlog_warn("%s: SRv6: Warning, SRv6 Dynamic LIB is depleted and next SID request will fail", + __func__); + } else if (format->type == SRV6_SID_FORMAT_TYPE_UNCOMPRESSED) { + /* Format is uncompressed => allocate SID function from Dynamic range */ + + uint32_t dynamic_end = + format->config.uncompressed.explicit_start - 1; + + /* Check if we ran out of available SID functions */ + if (block->u.uncompressed.first_available_func > + dynamic_end) { + zlog_warn("%s: SRv6: Warning, SRv6 SID Dynamic alloc space is depleted", + __func__); + return NULL; + } + + /* + * First, let's check if there are any SID functions that were previously + * allocated and then released. + */ + if (listcount(block->u.uncompressed.func_released) != 0) { + /* + * There are SID functions previously allocated and then released, + * let's pick the first one and reuse it now. + */ + sid_func_ptr = listnode_head( + block->u.uncompressed.func_released); + *sid_func = *sid_func_ptr; + listnode_delete(block->u.uncompressed + .func_released, + sid_func_ptr); + zebra_srv6_sid_func_free(sid_func_ptr); + } else { + /* + * There are no SID functions previously allocated and then released, + * let's allocate a new function from the pool of available functions. + */ + *sid_func = block->u.uncompressed + .first_available_func; + block->u.uncompressed.first_available_func++; + } + + /* Increase the counter of SID functions allocated */ + block->u.uncompressed.num_func_allocated++; + + if (block->u.uncompressed.first_available_func > + dynamic_end) + zlog_warn("%s: SRv6: Warning, SRv6 SID Dynamic alloc space is depleted and next SID request will fail", + __func__); + } else { + /* We should never arrive here */ + zlog_err("%s: unknown SID format type: %u", __func__, + format->type); + assert(0); + } + } else { + /* + * First, let's check if there are any SID functions that were previously + * allocated and then released. + */ + if (listcount(block->u.uncompressed.func_released) != 0) { + /* + * There are SID functions previously allocated and then released, + * let's pick the first one and reuse it now. + */ + sid_func_ptr = listnode_head( + block->u.uncompressed.func_released); + *sid_func = *sid_func_ptr; + listnode_delete(block->u.uncompressed.func_released, + sid_func_ptr); + zebra_srv6_sid_func_free(sid_func_ptr); + } else { + /* + * There are no SID functions previously allocated and then released, + * let's allocate a new function from the pool of available functions. + */ + *sid_func = block->u.uncompressed.first_available_func; + block->u.uncompressed.first_available_func++; + } + + /* Increase the counter of SID functions allocated */ + block->u.uncompressed.num_func_allocated++; + } + + if (ZEBRA_DEBUG_PACKET) + zlog_debug("%s: allocated dynamic SID function %u from block %pFX", + __func__, *sid_func, &block->prefix); + + return true; +} + +/** + * Get an explicit SID (i.e., a specific SID value) for a given context. + * + * If a SID already exists associated with the context, it returns the existing SID. + * Otherwise, it allocates a new SID. + * + * @param sid SID returned + * @param ctx Context for which the SID has been requested + * @param sid_value specific SRv6 SID value (i.e. IPv6 address) to be + * allocated explicitly + * + * @return 0 if the function returned an existing SID and SID value has not changed, + * 1 if a new SID has been allocated or the existing SID value has changed, -1 if an error occurred + */ +static int get_srv6_sid_explicit(struct zebra_srv6_sid **sid, + struct srv6_sid_ctx *ctx, + struct in6_addr *sid_value) +{ + struct zebra_srv6 *srv6 = zebra_srv6_get_default(); + struct zebra_srv6_sid_ctx *s = NULL; + struct zebra_srv6_sid_ctx *zctx = NULL; + struct listnode *node; + uint32_t sid_func = 0, sid_func_wide = 0; + struct srv6_locator *locator = NULL; + struct zebra_srv6_sid_block *block = NULL; + char buf[256]; + + if (!ctx || !sid_value) + return -1; + + /* Check if we already have a SID associated with the provided context */ + for (ALL_LIST_ELEMENTS_RO(srv6->sids, node, s)) { + if (memcmp(&s->ctx, ctx, sizeof(struct srv6_sid_ctx)) == 0) { + /* + * If the context is already associated with a SID that has the same SID value, then + * return the existing SID + */ + if (sid_same(&s->sid->value, sid_value)) { + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: returning existing SRv6 SID %pI6 ctx %s", + __func__, &s->sid->value, + srv6_sid_ctx2str(buf, + sizeof(buf), + ctx)); + *sid = s->sid; + return 0; + } + + /* + * It is not allowed to allocate an explicit SID for a given context if the context + * is already associated with an explicit SID + */ + if (s->sid->alloc_mode == SRV6_SID_ALLOC_MODE_EXPLICIT) { + zlog_err("%s: cannot alloc SID %pI6 for ctx %s: ctx already associated with SID %pI6", + __func__, sid_value, + srv6_sid_ctx2str(buf, sizeof(buf), + &s->ctx), + &s->sid->value); + return -1; + } + + zctx = s; + break; + } + } + + /* Get parent locator and function of the provided SID */ + if (!zebra_srv6_sid_decompose(sid_value, &block, &locator, &sid_func, + &sid_func_wide)) { + zlog_err("%s: invalid SM request arguments: parent block/locator not found for SID %pI6", + __func__, sid_value); + return -1; + } + + if (ctx->behavior == ZEBRA_SEG6_LOCAL_ACTION_END) { + zlog_err("%s: invalid SM request arguments: explicit SID allocation not allowed for End/uN behavior", + __func__); + return -1; + } + + /* Allocate an explicit SID function for the SID */ + if (!alloc_srv6_sid_func_explicit(block, sid_func, sid_func_wide)) { + zlog_err("%s: invalid SM request arguments: failed to allocate SID function %u from block %pFX", + __func__, sid_func, &block->prefix); + return -1; + } + + if (!zctx) { + /* If we don't have a zebra SID context for this context, allocate a new one */ + zctx = zebra_srv6_sid_ctx_alloc(); + zctx->ctx = *ctx; + } else { + /* + * If we already have a SID associated with this context, we need to + * deallocate the current SID function before allocating the new one + */ + if (zctx->sid) { + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: ctx %s already associated with a dynamic SID %pI6, releasing dynamic SID", + __func__, + srv6_sid_ctx2str(buf, sizeof(buf), + ctx), + &zctx->sid->value); + + release_srv6_sid_func_dynamic(block, zctx->sid->func); + zebra_srv6_sid_free(zctx->sid); + zctx->sid = NULL; + } + } + + /* Allocate the SID to store SID information */ + *sid = zebra_srv6_sid_alloc(zctx, sid_value, locator, block, sid_func, + SRV6_SID_ALLOC_MODE_EXPLICIT); + if (!(*sid)) { + flog_err(EC_ZEBRA_SM_CANNOT_ASSIGN_SID, + "%s: failed to create SRv6 SID %s (%pI6)", __func__, + srv6_sid_ctx2str(buf, sizeof(buf), ctx), sid_value); + return -1; + } + (*sid)->ctx = zctx; + zctx->sid = *sid; + listnode_add(srv6->sids, zctx); + + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: allocated explicit SRv6 SID %pI6 for context %s", + __func__, &(*sid)->value, + srv6_sid_ctx2str(buf, sizeof(buf), ctx)); + + return 1; +} + +/** + * Get a dynamic SID (i.e., any available SID value) for a given context. + * + * If a SID already exists associated with the context, it returns the existing SID. + * Otherwise, it allocates a new SID. + * + * @param sid SID returned + * @param ctx Context for which the SID has been requested + * @param locator SRv6 locator from which the SID has to be allocated + * + * @return 0 if the function returned an existing SID and SID value has not changed, + * 1 if a new SID has been allocated or the existing SID value has changed, -1 if an error occurred + */ +static int get_srv6_sid_dynamic(struct zebra_srv6_sid **sid, + struct srv6_sid_ctx *ctx, + struct srv6_locator *locator) +{ + struct zebra_srv6 *srv6 = zebra_srv6_get_default(); + struct zebra_srv6_sid_block *block; + struct srv6_sid_format *format; + struct zebra_srv6_sid_ctx *s = NULL; + struct zebra_srv6_sid_ctx *zctx; + struct listnode *node; + struct in6_addr sid_value; + uint32_t sid_func = 0; + char buf[256]; + + if (!ctx || !locator) + return -1; + + block = locator->sid_block; + format = locator->sid_format; + + /* + * If we already have a SID for the provided context, we return the existing + * SID instead of allocating a new one. + */ + for (ALL_LIST_ELEMENTS_RO(srv6->sids, node, s)) { + if (memcmp(&s->ctx, ctx, sizeof(struct srv6_sid_ctx)) == 0) { + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: returning existing SID %s %pI6", + __func__, + srv6_sid_ctx2str(buf, sizeof(buf), + ctx), + &s->sid->value); + *sid = s->sid; + return 0; + } + } + + if (format && format->type == SRV6_SID_FORMAT_TYPE_USID && + ctx->behavior == ZEBRA_SEG6_LOCAL_ACTION_END) { + /* uN SID is allocated from the GIB range */ + sid_value = locator->prefix.prefix; + } else if (!format && ctx->behavior == ZEBRA_SEG6_LOCAL_ACTION_END) { + /* uN SID is allocated from the GIB range */ + sid_value = locator->prefix.prefix; + } else { + /* Allocate a dynamic SID function for the SID */ + if (!alloc_srv6_sid_func_dynamic(block, &sid_func)) { + zlog_err("%s: invalid SM request arguments: failed to allocate SID function %u from block %pFX", + __func__, sid_func, &block->prefix); + return -1; + } + + /* Compose the SID as the locator followed by the SID function */ + zebra_srv6_sid_compose(&sid_value, locator, sid_func); + } + + /* Allocate a zebra SID context to store SID context information */ + zctx = zebra_srv6_sid_ctx_alloc(); + zctx->ctx = *ctx; + + /* Allocate the SID to store SID information */ + *sid = zebra_srv6_sid_alloc(zctx, &sid_value, locator, block, sid_func, + SRV6_SID_ALLOC_MODE_DYNAMIC); + if (!(*sid)) { + flog_err(EC_ZEBRA_SM_CANNOT_ASSIGN_SID, + "%s: failed to create SRv6 SID ctx %s (%pI6)", __func__, + srv6_sid_ctx2str(buf, sizeof(buf), ctx), &sid_value); + return -1; + } + (*sid)->ctx = zctx; + zctx->sid = *sid; + listnode_add(srv6->sids, zctx); + + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: allocated new dynamic SRv6 SID %pI6 for context %s", + __func__, &(*sid)->value, + srv6_sid_ctx2str(buf, sizeof(buf), ctx)); + + return 1; +} + +/** + * Get an SRv6 SID for a given context. + * + * If a SID already exists associated with the context, it returns the existing SID. + * Otherwise, it allocates a new SID. + * + * If the sid_value parameter is non-NULL, it allocates the requested SID value + * if it is available (explicit SID allocation). + * If the sid_value parameter is NULL, it allocates any available SID value + * (dynamic SID allocation). + * + * @param sid SID returned + * @param ctx Context for which the SID has been requested + * @param sid_value SRv6 SID value to be allocated (for explicit SID allocation) + * @param locator_name Parent SRv6 locator from which the SID has to be allocated (for dynamic SID allocation) + * + * @return 0 if the function returned an existing SID and SID value has not changed, + * 1 if a new SID has been allocated or the existing SID value has changed, -1 if an error occurred + */ +int get_srv6_sid(struct zebra_srv6_sid **sid, struct srv6_sid_ctx *ctx, + struct in6_addr *sid_value, const char *locator_name) +{ + int ret = -1; + struct srv6_locator *locator; + char buf[256]; + + enum srv6_sid_alloc_mode alloc_mode = + (sid_value) ? SRV6_SID_ALLOC_MODE_EXPLICIT + : SRV6_SID_ALLOC_MODE_DYNAMIC; + + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: received SRv6 SID alloc request: SID ctx %s (%pI6), mode=%s", + __func__, srv6_sid_ctx2str(buf, sizeof(buf), ctx), + sid_value, srv6_sid_alloc_mode2str(alloc_mode)); + + switch (alloc_mode) { + case SRV6_SID_ALLOC_MODE_EXPLICIT: + /* + * Explicit SID allocation: allocate a specific SID value + */ + + if (!sid_value) { + zlog_err("%s: invalid SM request arguments: missing SRv6 SID value, necessary for explicit allocation", + __func__); + return -1; + } + + ret = get_srv6_sid_explicit(sid, ctx, sid_value); + + break; + case SRV6_SID_ALLOC_MODE_DYNAMIC: + /* + * Dynamic SID allocation: allocate any available SID value + */ + + if (!locator_name) { + zlog_err("%s: invalid SM request arguments: missing SRv6 locator, necessary for dynamic allocation", + __func__); + return -1; + } + + locator = zebra_srv6_locator_lookup(locator_name); + if (!locator) { + zlog_err("%s: invalid SM request arguments: SRv6 locator '%s' does not exist", + __func__, locator_name); + return -1; + } + + ret = get_srv6_sid_dynamic(sid, ctx, locator); + + break; + case SRV6_SID_ALLOC_MODE_MAX: + case SRV6_SID_ALLOC_MODE_UNSPEC: + default: + flog_err(EC_ZEBRA_SM_CANNOT_ASSIGN_SID, + "%s: SRv6 Manager: Unrecognized alloc mode %u", + __func__, alloc_mode); + /* We should never arrive here */ + assert(0); + } + + return ret; +} + +/** + * Release an explicit SRv6 SID function. + * + * @param block Parent SRv6 SID block of the SID function that has to be released + * @param sid_func SID function to be released + * @return 0 on success, -1 otherwise + */ +static bool release_srv6_sid_func_explicit(struct zebra_srv6_sid_block *block, + uint32_t sid_func, + uint32_t sid_wide_func) +{ + struct srv6_sid_format *format; + struct listnode *node; + uint32_t *sid_func_ptr = NULL; + + if (!block) + return -1; + + format = block->sid_format; + + if (ZEBRA_DEBUG_PACKET) + zlog_debug("%s: trying to release explicit SRv6 SID function %u from block %pFX", + __func__, sid_func, &block->prefix); + + /* + * Release SID function from the corresponding range depending on the SID format type + */ + if (format) { + if (format->type == SRV6_SID_FORMAT_TYPE_USID) { + uint32_t elib_start = format->config.usid.elib_start; + uint32_t elib_end = format->config.usid.elib_end; + uint32_t ewlib_start = format->config.usid.ewlib_start; + uint32_t ewlib_end = format->config.usid.wlib_end; + uint32_t *sid_wide_func_ptr = NULL; + + /* Figure out the range from which the SID function has been allocated and release it */ + if ((sid_func >= elib_start) && (sid_func <= elib_end)) { + /* The SID function comes from the ELIB range */ + + /* Lookup SID function in the functions allocated list of ELIB range */ + for (ALL_LIST_ELEMENTS_RO(block->u.usid.lib + .func_allocated, + node, sid_func_ptr)) + if (*sid_func_ptr == sid_func) + break; + + /* Ensure that the SID function is allocated */ + if (!sid_func_ptr) { + zlog_warn("%s: failed to release SID function %u, function is not allocated", + __func__, sid_func); + return -1; + } + + /* Release the SID function from the ELIB range */ + listnode_delete(block->u.usid.lib.func_allocated, + sid_func_ptr); + zebra_srv6_sid_func_free(sid_func_ptr); + } else if ((sid_func >= ewlib_start) && + (sid_func <= ewlib_end)) { + /* The SID function comes from the EWLIB range */ + + /* Lookup SID function in the functions allocated list of EWLIB range */ + for (ALL_LIST_ELEMENTS_RO(block->u.usid + .wide_lib[sid_func] + .func_allocated, + node, sid_func_ptr)) + if (*sid_wide_func_ptr == sid_wide_func) + break; + + /* Ensure that the SID function is allocated */ + if (!sid_wide_func_ptr) { + zlog_warn("%s: failed to release wide SID function %u, function is not allocated", + __func__, sid_wide_func); + return -1; + } + + /* Release the SID function from the EWLIB range */ + listnode_delete(block->u.usid.wide_lib[sid_func] + .func_allocated, + sid_wide_func_ptr); + zebra_srv6_sid_func_free(sid_wide_func_ptr); + } else { + zlog_warn("%s: function %u is outside ELIB [%u/%u] and EWLIB alloc ranges [%u/%u]", + __func__, sid_func, elib_start, + elib_end, ewlib_start, ewlib_end); + return -1; + } + } else if (format->type == SRV6_SID_FORMAT_TYPE_UNCOMPRESSED) { + uint32_t explicit_start = + format->config.uncompressed.explicit_start; + uint32_t explicit_end = + (uint32_t)((1 << format->function_len) - 1); + + /* Ensure that the SID function comes from the Explicit range */ + if (!(sid_func >= explicit_start && + sid_func <= explicit_end)) { + zlog_warn("%s: function %u is outside explicit alloc range [%u/%u]", + __func__, sid_func, explicit_start, + explicit_end); + return -1; + } + + /* Lookup SID function in the functions allocated list of Explicit range */ + for (ALL_LIST_ELEMENTS_RO(block->u.uncompressed + .func_allocated, + node, sid_func_ptr)) + if (*sid_func_ptr == sid_func) + break; + + /* Ensure that the SID function is allocated */ + if (!sid_func_ptr) { + zlog_warn("%s: failed to release SID function %u, function is not allocated", + __func__, sid_func); + return -1; + } + + /* Release the SID function from the Explicit range */ + listnode_delete(block->u.uncompressed.func_allocated, + sid_func_ptr); + zebra_srv6_sid_func_free(sid_func_ptr); + } else { + /* We should never arrive here */ + assert(0); + } + } else { + /* Lookup SID function in the functions allocated list of Explicit range */ + for (ALL_LIST_ELEMENTS_RO(block->u.uncompressed.func_allocated, + node, sid_func_ptr)) + if (*sid_func_ptr == sid_func) + break; + + /* Ensure that the SID function is allocated */ + if (!sid_func_ptr) { + zlog_warn("%s: failed to release SID function %u, function is not allocated", + __func__, sid_func); + return -1; + } + + /* Release the SID function from the Explicit range */ + listnode_delete(block->u.uncompressed.func_allocated, + sid_func_ptr); + zebra_srv6_sid_func_free(sid_func_ptr); + } + + if (ZEBRA_DEBUG_PACKET) + zlog_debug("%s: released explicit SRv6 SID function %u from block %pFX", + __func__, sid_func, &block->prefix); + + return 0; +} + +/** + * Release a dynamic SRv6 SID function. + * + * @param block Parent SRv6 SID block of the SID function that has to be released + * @param sid_func SID function to be released + * @return 0 on success, -1 otherwise + */ +static int release_srv6_sid_func_dynamic(struct zebra_srv6_sid_block *block, + uint32_t sid_func) +{ + struct srv6_sid_format *format; + struct listnode *node, *nnode; + uint32_t *sid_func_ptr = NULL; + + if (!block) + return -1; + + format = block->sid_format; + + if (ZEBRA_DEBUG_PACKET) + zlog_debug("%s: trying to release dynamic SRv6 SID function %u from block %pFX", + __func__, sid_func, &block->prefix); + + /* + * Release SID function from the corresponding range depending on the SID format type + */ + if (format && format->type == SRV6_SID_FORMAT_TYPE_USID) { + uint32_t dlib_start = format->config.usid.lib_start; + /* The Dynamic LIB range ends where the Explicit LIB range begins */ + uint32_t dlib_end = format->config.usid.elib_start - 1; + + /* Ensure that the SID function to be released comes from the Dynamic LIB (DLIB) range */ + if (!(sid_func >= dlib_start && sid_func <= dlib_end)) { + zlog_warn("%s: function %u is outside Dynamic LIB range [%u/%u]", + __func__, sid_func, dlib_start, dlib_end); + return -1; + } + + if (sid_func == block->u.usid.lib.first_available_func - 1) { + /* + * The SID function to be released precedes the `first_available_func`. + * Reset first_available_func to the first available position. + */ + + block->u.usid.lib.first_available_func -= 1; + + bool found; + + do { + found = false; + for (ALL_LIST_ELEMENTS(block->u.usid.lib + .func_released, + node, nnode, + sid_func_ptr)) + if (*sid_func_ptr == + block->u.usid.lib.first_available_func - + 1) { + listnode_delete(block->u.usid + .lib + .func_released, + sid_func_ptr); + zebra_srv6_sid_func_free( + sid_func_ptr); + block->u.usid.lib + .first_available_func -= + 1; + found = true; + break; + } + } while (found); + } else { + /* + * The SID function to be released does not precede the `first_available_func`. + * Add the released function to the func_released array to indicate + * that it is available again for allocation. + */ + sid_func_ptr = zebra_srv6_sid_func_alloc(sid_func); + listnode_add_head(block->u.usid.lib.func_released, + sid_func_ptr); + } + } else if (format && format->type == SRV6_SID_FORMAT_TYPE_UNCOMPRESSED) { + uint32_t dynamic_start = + SRV6_SID_FORMAT_UNCOMPRESSED_F4024_FUNC_UNRESERVED_MIN; + /* The Dynamic range ends where the Explicit range begins */ + uint32_t dynamic_end = + format->config.uncompressed.explicit_start - 1; + + /* Ensure that the SID function to be released comes from the Dynamic range */ + if (!(sid_func >= dynamic_start && sid_func <= dynamic_end)) { + zlog_warn("%s: function %u is outside dynamic range [%u/%u]", + __func__, sid_func, dynamic_start, + dynamic_end); + return -1; + } + + if (sid_func == block->u.uncompressed.first_available_func - 1) { + /* + * The released SID function precedes the `first_available_func`. + * Reset first_available_func to the first available position. + */ + + block->u.uncompressed.first_available_func -= 1; + + bool found; + + do { + found = false; + for (ALL_LIST_ELEMENTS(block->u.uncompressed + .func_released, + node, nnode, + sid_func_ptr)) + if (*sid_func_ptr == + block->u.uncompressed + .first_available_func - + 1) { + listnode_delete(block->u.uncompressed + .func_released, + sid_func_ptr); + zebra_srv6_sid_func_free( + sid_func_ptr); + block->u.uncompressed + .first_available_func -= + 1; + found = true; + break; + } + } while (found); + } else { + /* + * The released SID function does not precede the `first_available_func`. + * Add the released function to the func_released array to indicate + * that it is available again for allocation. + */ + sid_func_ptr = zebra_srv6_sid_func_alloc(sid_func); + listnode_add_head(block->u.uncompressed.func_released, + sid_func_ptr); + } + } else if (!format) { + if (sid_func == block->u.uncompressed.first_available_func - 1) { + /* + * The released SID function precedes the `first_available_func`. + * Reset first_available_func to the first available position. + */ + + block->u.uncompressed.first_available_func -= 1; + + bool found; + + do { + found = false; + for (ALL_LIST_ELEMENTS(block->u.uncompressed + .func_released, + node, nnode, + sid_func_ptr)) + if (*sid_func_ptr == + block->u.uncompressed + .first_available_func - + 1) { + listnode_delete(block->u.uncompressed + .func_released, + sid_func_ptr); + zebra_srv6_sid_func_free( + sid_func_ptr); + block->u.uncompressed + .first_available_func -= + 1; + found = true; + break; + } + } while (found); + } else { + /* + * The released SID function does not precede the `first_available_func`. + * Add the released function to the func_released array to indicate + * that it is available again for allocation. + */ + sid_func_ptr = zebra_srv6_sid_func_alloc(sid_func); + listnode_add_head(block->u.uncompressed.func_released, + sid_func_ptr); + } + } + + if (ZEBRA_DEBUG_PACKET) + zlog_debug("%s: released dynamic SRv6 SID function %u from block %pFX", + __func__, sid_func, &block->prefix); + + return 0; +} + +/** + * Core function, release the SRv6 SID associated with a given context. + * + * @param client The client for which the SID has to be released + * @param ctx Context associated with the SRv6 SID to be released + * @return 0 on success, -1 otherwise + */ +int release_srv6_sid(struct zserv *client, struct zebra_srv6_sid_ctx *zctx) +{ + struct zebra_srv6 *srv6 = zebra_srv6_get_default(); + char buf[256]; + + if (!zctx || !zctx->sid) + return -1; + + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: releasing SRv6 SID %pI6 associated with ctx %s (proto=%u, instance=%u)", + __func__, &zctx->sid->value, + srv6_sid_ctx2str(buf, sizeof(buf), &zctx->ctx), + client->proto, client->instance); + + /* Ensures the SID is in use by the client */ + if (!listnode_lookup(zctx->sid->client_list, client)) { + flog_err(EC_ZEBRA_SM_DAEMON_MISMATCH, "%s: Daemon mismatch!!", + __func__); + return -1; + } + + /* Remove the client from the list of clients using the SID */ + listnode_delete(zctx->sid->client_list, client); + + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: released SRv6 SID %pI6 associated with ctx %s (proto=%u, instance=%u)", + __func__, &zctx->sid->value, + srv6_sid_ctx2str(buf, sizeof(buf), &zctx->ctx), + client->proto, client->instance); + + /* + * If the SID is not used by any other client, then deallocate it + * and remove it from the SRv6 database. + */ + if (listcount(zctx->sid->client_list) == 0) { + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: SRv6 SID %pI6 associated with ctx %s is no longer in use, removing it from SRv6 database", + __func__, &zctx->sid->value, + srv6_sid_ctx2str(buf, sizeof(buf), + &zctx->ctx)); + + if (!(zctx->sid->block->sid_format && + zctx->sid->block->sid_format->type == + SRV6_SID_FORMAT_TYPE_USID && + zctx->ctx.behavior == ZEBRA_SEG6_LOCAL_ACTION_END) && + !(!zctx->sid->block->sid_format && + zctx->ctx.behavior == ZEBRA_SEG6_LOCAL_ACTION_END)) { + if (zctx->sid->alloc_mode == + SRV6_SID_ALLOC_MODE_EXPLICIT) + /* Release SRv6 SID function */ + release_srv6_sid_func_explicit(zctx->sid->block, + zctx->sid->func, + zctx->sid->wide_func); + else if (zctx->sid->alloc_mode == + SRV6_SID_ALLOC_MODE_DYNAMIC) + /* Release SRv6 SID function */ + release_srv6_sid_func_dynamic(zctx->sid->block, + zctx->sid->func); + else + /* We should never arrive here */ + assert(0); + } + + /* Free the SID */ + zebra_srv6_sid_free(zctx->sid); + zctx->sid = NULL; + + /* Remove the SID context from the list and free memory */ + listnode_delete(srv6->sids, zctx); + zebra_srv6_sid_ctx_free(zctx); + } + + return 0; +} + /** * Handle a get SRv6 Locator request received from a client. * diff --git a/zebra/zebra_srv6.h b/zebra/zebra_srv6.h index 681789e4ac..7d989f180f 100644 --- a/zebra/zebra_srv6.h +++ b/zebra/zebra_srv6.h @@ -294,6 +294,11 @@ extern void srv6_manager_get_locator_call(struct srv6_locator **locator, struct zserv *client, const char *locator_name); +extern int get_srv6_sid(struct zebra_srv6_sid **sid, struct srv6_sid_ctx *ctx, + struct in6_addr *sid_value, const char *locator_name); +extern int release_srv6_sid(struct zserv *client, + struct zebra_srv6_sid_ctx *zctx); + extern struct zebra_srv6_sid_ctx *zebra_srv6_sid_ctx_alloc(void); extern void zebra_srv6_sid_ctx_free(struct zebra_srv6_sid_ctx *ctx); extern void delete_zebra_srv6_sid_ctx(void *val); From 84dd482cb929d522cf12c91c2e7ec1faead848ea Mon Sep 17 00:00:00 2001 From: Carmine Scarpitta Date: Sat, 23 Mar 2024 17:25:39 +0100 Subject: [PATCH 047/347] zebra: Alloc/Release SIDs to daemons upon request Previous commits introduced two new ZAPI operations, `ZEBRA_SRV6_MANAGER_GET_SRV6_SID` and `ZEBRA_SRV6_MANAGER_RELEASE_SRV6_SID`. These operations allow a daemon to interact with the SRv6 SID Manager to get and release an SRv6 SID, respectively. This commit extends the SID Manager by adding logic to process the requests `ZEBRA_SRV6_MANAGER_GET_SRV6_SID` and `ZEBRA_SRV6_MANAGER_RELEASE_SRV6_SID`, and allocate/release SIDs to requesting daemons. Signed-off-by: Carmine Scarpitta --- zebra/zapi_msg.c | 73 ++++++++++++++++++++ zebra/zebra_srv6.c | 163 +++++++++++++++++++++++++++++++++++++++++++++ zebra/zebra_srv6.h | 18 +++++ 3 files changed, 254 insertions(+) diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index 52ee087689..bab4c4fa3d 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -3006,6 +3006,71 @@ static void zread_srv6_manager_release_locator_chunk(struct zserv *client, return; } +/** + * Handle SRv6 SID request received from a client daemon protocol. + * + * @param client The client zapi session + * @param msg The request message + */ +static void zread_srv6_manager_get_srv6_sid(struct zserv *client, + struct stream *msg) +{ + struct stream *s; + struct srv6_sid_ctx ctx = {}; + struct in6_addr sid_value = {}; + struct in6_addr *sid_value_ptr = NULL; + char locator[SRV6_LOCNAME_SIZE] = { 0 }; + uint16_t len; + struct zebra_srv6_sid *sid = NULL; + uint8_t flags; + + /* Get input stream */ + s = msg; + + /* Get data */ + STREAM_GET(&ctx, s, sizeof(struct srv6_sid_ctx)); + STREAM_GETC(s, flags); + if (CHECK_FLAG(flags, ZAPI_SRV6_MANAGER_SID_FLAG_HAS_SID_VALUE)) { + STREAM_GET(&sid_value, s, sizeof(struct in6_addr)); + sid_value_ptr = &sid_value; + } + if (CHECK_FLAG(flags, ZAPI_SRV6_MANAGER_SID_FLAG_HAS_LOCATOR)) { + STREAM_GETW(s, len); + STREAM_GET(locator, s, len); + } + + /* Call hook to get a SID using wrapper */ + srv6_manager_get_sid_call(&sid, client, &ctx, sid_value_ptr, locator); + +stream_failure: + return; +} + +/** + * Handle SRv6 SID release request received from a client daemon protocol. + * + * @param client The client zapi session + * @param msg The request message + */ +static void zread_srv6_manager_release_srv6_sid(struct zserv *client, + struct stream *msg) +{ + struct stream *s; + struct srv6_sid_ctx ctx = {}; + + /* Get input stream */ + s = msg; + + /* Get data */ + STREAM_GET(&ctx, s, sizeof(struct srv6_sid_ctx)); + + /* Call hook to release a SID using wrapper */ + srv6_manager_release_sid_call(client, &ctx); + +stream_failure: + return; +} + /** * Handle SRv6 locator get request received from a client daemon protocol. * @@ -3042,6 +3107,12 @@ static void zread_srv6_manager_request(ZAPI_HANDLER_ARGS) zread_srv6_manager_release_locator_chunk(client, msg, zvrf_id(zvrf)); break; + case ZEBRA_SRV6_MANAGER_GET_SRV6_SID: + zread_srv6_manager_get_srv6_sid(client, msg); + break; + case ZEBRA_SRV6_MANAGER_RELEASE_SRV6_SID: + zread_srv6_manager_release_srv6_sid(client, msg); + break; case ZEBRA_SRV6_MANAGER_GET_LOCATOR: zread_srv6_manager_get_locator(client, msg); break; @@ -3993,6 +4064,8 @@ void (*const zserv_handlers[])(ZAPI_HANDLER_ARGS) = { [ZEBRA_MLAG_FORWARD_MSG] = zebra_mlag_forward_client_msg, [ZEBRA_SRV6_MANAGER_GET_LOCATOR_CHUNK] = zread_srv6_manager_request, [ZEBRA_SRV6_MANAGER_RELEASE_LOCATOR_CHUNK] = zread_srv6_manager_request, + [ZEBRA_SRV6_MANAGER_GET_SRV6_SID] = zread_srv6_manager_request, + [ZEBRA_SRV6_MANAGER_RELEASE_SRV6_SID] = zread_srv6_manager_request, [ZEBRA_SRV6_MANAGER_GET_LOCATOR] = zread_srv6_manager_request, [ZEBRA_CLIENT_CAPABILITIES] = zread_client_capabilities, [ZEBRA_NEIGH_DISCOVER] = zread_neigh_discover, diff --git a/zebra/zebra_srv6.c b/zebra/zebra_srv6.c index 047422b9e3..d93f09f1b4 100644 --- a/zebra/zebra_srv6.c +++ b/zebra/zebra_srv6.c @@ -65,6 +65,13 @@ DEFINE_HOOK(srv6_manager_release_chunk, vrf_id_t vrf_id), (client, locator_name, vrf_id)); +DEFINE_HOOK(srv6_manager_get_sid, + (struct zebra_srv6_sid **sid, struct zserv *client, + struct srv6_sid_ctx *ctx, struct in6_addr *sid_value, + const char *locator_name), + (sid, client, ctx, sid_value, locator_name)); +DEFINE_HOOK(srv6_manager_release_sid, + (struct zserv *client, struct srv6_sid_ctx *ctx), (client, ctx)); DEFINE_HOOK(srv6_manager_get_locator, (struct srv6_locator **locator, struct zserv *client, const char *locator_name), @@ -100,6 +107,22 @@ int srv6_manager_client_disconnect_cb(struct zserv *client) return 0; } + +void srv6_manager_get_sid_call(struct zebra_srv6_sid **sid, + struct zserv *client, struct srv6_sid_ctx *ctx, + struct in6_addr *sid_value, + const char *locator_name) +{ + hook_call(srv6_manager_get_sid, sid, client, ctx, sid_value, + locator_name); +} + +void srv6_manager_release_sid_call(struct zserv *client, + struct srv6_sid_ctx *ctx) +{ + hook_call(srv6_manager_release_sid, client, ctx); +} + void srv6_manager_get_locator_call(struct srv6_locator **locator, struct zserv *client, const char *locator_name) @@ -109,6 +132,8 @@ void srv6_manager_get_locator_call(struct srv6_locator **locator, static int zebra_srv6_cleanup(struct zserv *client) { + /* Client has disconnected, let's release all the SIDs allocated by it. */ + release_daemon_srv6_sids(client); return 0; } @@ -2225,6 +2250,141 @@ static int srv6_manager_get_srv6_locator_internal(struct srv6_locator **locator, return zsend_zebra_srv6_locator_add(client, *locator); } +/** + * Handle a get SID request received from a client. + * + * It gets a SID for a given context. If there is no SID associated with the context yet, + * we allocate one and return it to the client. Otherwise, we return the existing SID. + * + * - When the `sid_value` parameter is non-NULL, SRv6 Manager assigns the requested SID value + * if it is available (explicit SID allocation). + * - When the `sid_value` parameter is NULL, SRv6 Manager assigns any available SID value + * (dynamic SID allocation). + * + * Finally, notify the client whether the SID allocation was successful or failed. + * + * @param sid SID returned by this function + * @param client The client that requested the SID + * @param ctx Context for which the SID was requested + * @param sid_value SID value (i.e., IPv6 address) that has to be assigned to the SID + * (for explicit SID allocation) + * @param locator_name Locator from which the SID has to be allocated (for dynamic SID allocation) + * + * @return 0 on success, -1 otherwise + */ +static int srv6_manager_get_sid_internal(struct zebra_srv6_sid **sid, + struct zserv *client, + struct srv6_sid_ctx *ctx, + struct in6_addr *sid_value, + const char *locator_name) +{ + int ret = -1; + char buf[256]; + + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: getting SRv6 SID for ctx %s, sid_value=%pI6, locator_name=%s", + __func__, srv6_sid_ctx2str(buf, sizeof(buf), ctx), + sid_value, locator_name); + + ret = get_srv6_sid(sid, ctx, sid_value, locator_name); + if (ret < 0) { + zlog_warn("%s: not got SRv6 SID for ctx %s, sid_value=%pI6, locator_name=%s", + __func__, srv6_sid_ctx2str(buf, sizeof(buf), ctx), + sid_value, locator_name); + } else if (ret == 0) { + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: got existing SRv6 SID for ctx %s: sid_value=%pI6 (func=%u) (proto=%u, instance=%u, sessionId=%u), notify client", + __func__, + srv6_sid_ctx2str(buf, sizeof(buf), ctx), + &(*sid)->value, (*sid)->func, client->proto, + client->instance, client->session_id); + if (!listnode_lookup((*sid)->client_list, client)) + listnode_add((*sid)->client_list, client); + } else { + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: got new SRv6 SID for ctx %s: sid_value=%pI6 (func=%u) (proto=%u, instance=%u, sessionId=%u), notifying all clients", + __func__, + srv6_sid_ctx2str(buf, sizeof(buf), ctx), + &(*sid)->value, (*sid)->func, client->proto, + client->instance, client->session_id); + if (!listnode_lookup((*sid)->client_list, client)) + listnode_add((*sid)->client_list, client); + } + + return ret; +} + +/** + * Release SRv6 SIDs from a client. + * + * Called on client disconnection or reconnection. + * + * @param client The client to release SIDs from + * @return Number of SIDs released + */ +int release_daemon_srv6_sids(struct zserv *client) +{ + struct zebra_srv6 *srv6 = zebra_srv6_get_default(); + struct listnode *node, *nnode; + struct zebra_srv6_sid_ctx *ctx; + int count = 0; + int ret; + + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: releasing SRv6 SIDs for client proto %s, instance %d, session %u", + __func__, zebra_route_string(client->proto), + client->instance, client->session_id); + + /* Iterate over the SIDs and release SIDs used by the client daemon */ + for (ALL_LIST_ELEMENTS(srv6->sids, node, nnode, ctx)) { + if (!listnode_lookup(ctx->sid->client_list, client)) + continue; + + ret = release_srv6_sid(client, ctx); + if (ret == 0) + count++; + } + + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: released %d SRv6 SIDs", __func__, count); + + return count; +} + +/** + * Release SRv6 SIDs from a client. + * + * @param client The client zapi session + * @param ctx Context associated with the SRv6 SID + * @return 0 on success, -1 on failure + */ +static int srv6_manager_release_sid_internal(struct zserv *client, + struct srv6_sid_ctx *ctx) +{ + int ret = -1; + struct zebra_srv6 *srv6 = zebra_srv6_get_default(); + struct zebra_srv6_sid_ctx *zctx; + struct listnode *node, *nnode; + char buf[256]; + + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: releasing SRv6 SID associated with ctx %s", + __func__, srv6_sid_ctx2str(buf, sizeof(buf), ctx)); + + /* Lookup Zebra SID context and release it */ + for (ALL_LIST_ELEMENTS(srv6->sids, node, nnode, zctx)) + if (memcmp(&zctx->ctx, ctx, sizeof(struct srv6_sid_ctx)) == 0) { + ret = release_srv6_sid(client, zctx); + break; + } + + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: no SID associated with ctx %s", __func__, + srv6_sid_ctx2str(buf, sizeof(buf), ctx)); + + return ret; +} + void zebra_srv6_terminate(void) { struct srv6_locator *locator; @@ -2288,6 +2448,9 @@ void zebra_srv6_init(void) hook_register(srv6_manager_release_chunk, zebra_srv6_manager_release_locator_chunk); + hook_register(srv6_manager_get_sid, srv6_manager_get_sid_internal); + hook_register(srv6_manager_release_sid, + srv6_manager_release_sid_internal); hook_register(srv6_manager_get_locator, srv6_manager_get_srv6_locator_internal); } diff --git a/zebra/zebra_srv6.h b/zebra/zebra_srv6.h index 7d989f180f..1599fd7adf 100644 --- a/zebra/zebra_srv6.h +++ b/zebra/zebra_srv6.h @@ -231,6 +231,13 @@ DECLARE_HOOK(srv6_manager_release_chunk, vrf_id_t vrf_id), (client, locator_name, vrf_id)); +DECLARE_HOOK(srv6_manager_get_sid, + (struct zebra_srv6_sid **sid, struct zserv *client, + struct srv6_sid_ctx *ctx, struct in6_addr *sid_value, + const char *locator_name), + (sid, client, ctx, sid_value, locator_name)); +DECLARE_HOOK(srv6_manager_release_sid, + (struct zserv *client, struct srv6_sid_ctx *ctx), (client, ctx)); DECLARE_HOOK(srv6_manager_get_locator, (struct srv6_locator **locator, struct zserv *client, const char *locator_name), @@ -290,6 +297,14 @@ zebra_srv6_sid_alloc(struct zebra_srv6_sid_ctx *ctx, struct in6_addr *sid_value, extern void zebra_srv6_sid_free(struct zebra_srv6_sid *sid); extern void delete_zebra_srv6_sid(void *val); +extern void srv6_manager_get_sid_call(struct zebra_srv6_sid **sid, + struct zserv *client, + struct srv6_sid_ctx *ctx, + struct in6_addr *sid_value, + const char *locator_name); +extern void srv6_manager_release_sid_call(struct zserv *client, + struct srv6_sid_ctx *ctx); + extern void srv6_manager_get_locator_call(struct srv6_locator **locator, struct zserv *client, const char *locator_name); @@ -298,6 +313,9 @@ extern int get_srv6_sid(struct zebra_srv6_sid **sid, struct srv6_sid_ctx *ctx, struct in6_addr *sid_value, const char *locator_name); extern int release_srv6_sid(struct zserv *client, struct zebra_srv6_sid_ctx *zctx); +extern int release_daemon_srv6_sids(struct zserv *client); +extern int srv6_manager_get_sid_response(struct zebra_srv6_sid *sid, + struct zserv *client); extern struct zebra_srv6_sid_ctx *zebra_srv6_sid_ctx_alloc(void); extern void zebra_srv6_sid_ctx_free(struct zebra_srv6_sid_ctx *ctx); From b90cb00974ef84beff603fb0e91a7a38b3a1b6a4 Mon Sep 17 00:00:00 2001 From: Carmine Scarpitta Date: Mon, 6 May 2024 17:53:18 +0200 Subject: [PATCH 048/347] lib: Add ZAPI command `ZEBRA_SRV6_SID_NOTIFY` Add a new ZAPI command `ZEBRA_SRV6_SID_NOTIFY` used by zebra to send asynchronous SRv6 SIDs notifications to zclients. Signed-off-by: Carmine Scarpitta --- lib/log.c | 3 ++- lib/zclient.c | 24 ++++++++++++++++++++++++ lib/zclient.h | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 60 insertions(+), 1 deletion(-) diff --git a/lib/log.c b/lib/log.c index fa8a8734a4..880180ae5a 100644 --- a/lib/log.c +++ b/lib/log.c @@ -464,7 +464,8 @@ static const struct zebra_desc_table command_types[] = { DESC_ENTRY(ZEBRA_TC_CLASS_DELETE), DESC_ENTRY(ZEBRA_TC_FILTER_ADD), DESC_ENTRY(ZEBRA_TC_FILTER_DELETE), - DESC_ENTRY(ZEBRA_OPAQUE_NOTIFY) + DESC_ENTRY(ZEBRA_OPAQUE_NOTIFY), + DESC_ENTRY(ZEBRA_SRV6_SID_NOTIFY) }; #undef DESC_ENTRY diff --git a/lib/zclient.c b/lib/zclient.c index b0e97b0f12..e4d02d743a 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -2133,6 +2133,30 @@ bool zapi_iptable_notify_decode(struct stream *s, return false; } +bool zapi_srv6_sid_notify_decode(struct stream *s, struct srv6_sid_ctx *ctx, + struct in6_addr *sid_value, uint32_t *func, + uint32_t *wide_func, + enum zapi_srv6_sid_notify *note) +{ + uint32_t f, wf; + + STREAM_GET(note, s, sizeof(*note)); + STREAM_GET(ctx, s, sizeof(struct srv6_sid_ctx)); + STREAM_GET(sid_value, s, sizeof(struct in6_addr)); + STREAM_GETL(s, f); + STREAM_GETL(s, wf); + + if (func) + *func = f; + if (wide_func) + *wide_func = wf; + + return true; + +stream_failure: + return false; +} + struct nexthop *nexthop_from_zapi_nexthop(const struct zapi_nexthop *znh) { struct nexthop *n = nexthop_new(); diff --git a/lib/zclient.h b/lib/zclient.h index bb527f0b41..bfe955b7ac 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -238,6 +238,7 @@ typedef enum { ZEBRA_TC_FILTER_ADD, ZEBRA_TC_FILTER_DELETE, ZEBRA_OPAQUE_NOTIFY, + ZEBRA_SRV6_SID_NOTIFY, } zebra_message_types_t; /* Zebra message types. Please update the corresponding * command_types array with any changes! @@ -764,6 +765,13 @@ enum zapi_iptable_notify_owner { ZAPI_IPTABLE_FAIL_REMOVE, }; +enum zapi_srv6_sid_notify { + ZAPI_SRV6_SID_FAIL_ALLOC = 0, + ZAPI_SRV6_SID_ALLOCATED, + ZAPI_SRV6_SID_RELEASED, + ZAPI_SRV6_SID_FAIL_RELEASE, +}; + enum zclient_send_status { ZCLIENT_SEND_FAILURE = -1, ZCLIENT_SEND_SUCCESS = 0, @@ -816,6 +824,28 @@ zapi_rule_notify_owner2str(enum zapi_rule_notify_owner note) return ret; } +static inline const char *zapi_srv6_sid_notify2str(enum zapi_srv6_sid_notify note) +{ + const char *ret = "UNKNOWN"; + + switch (note) { + case ZAPI_SRV6_SID_FAIL_ALLOC: + ret = "ZAPI_SRV6_SID_FAIL_ALLOC"; + break; + case ZAPI_SRV6_SID_ALLOCATED: + ret = "ZAPI_SRV6_SID_ALLOCATED"; + break; + case ZAPI_SRV6_SID_FAIL_RELEASE: + ret = "ZAPI_SRV6_SID_FAIL_RELEASE"; + break; + case ZAPI_SRV6_SID_RELEASED: + ret = "ZAPI_SRV6_SID_RELEASED"; + break; + } + + return ret; +} + /* Zebra MAC types */ #define ZEBRA_MACIP_TYPE_STICKY 0x01 /* Sticky MAC*/ #define ZEBRA_MACIP_TYPE_GW 0x02 /* gateway (SVI) mac*/ @@ -1144,6 +1174,10 @@ bool zapi_rule_notify_decode(struct stream *s, uint32_t *seqno, bool zapi_ipset_notify_decode(struct stream *s, uint32_t *unique, enum zapi_ipset_notify_owner *note); +bool zapi_srv6_sid_notify_decode(struct stream *s, struct srv6_sid_ctx *ctx, + struct in6_addr *sid_value, uint32_t *func, + uint32_t *wide_func, + enum zapi_srv6_sid_notify *note); /* Nexthop-group message apis */ extern enum zclient_send_status From efa830e89ca39c93eeddef40ed7c959ba36b1fc1 Mon Sep 17 00:00:00 2001 From: Carmine Scarpitta Date: Thu, 2 May 2024 13:39:49 +0200 Subject: [PATCH 049/347] zebra: Notify daemons about SIDs Send asynchronous notifications to zclients when an SRv6 SID is allocated/released and when a SID alloc/release operation fails. Signed-off-by: Carmine Scarpitta --- zebra/zapi_msg.c | 33 +++++++++++++++++++++++++++++++++ zebra/zapi_msg.h | 5 +++++ zebra/zebra_srv6.c | 22 ++++++++++++++++++++++ 3 files changed, 60 insertions(+) diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index bab4c4fa3d..164c0dd687 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -999,6 +999,39 @@ void zsend_neighbor_notify(int cmd, struct interface *ifp, } } +void zsend_srv6_sid_notify(struct zserv *client, const struct srv6_sid_ctx *ctx, + struct in6_addr *sid_value, uint32_t func, + uint32_t wide_func, enum zapi_srv6_sid_notify note) +{ + struct stream *s; + uint16_t cmd = ZEBRA_SRV6_SID_NOTIFY; + char buf[256]; + + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: notifying %s ctx %s sid %pI6 note %s (proto=%u, instance=%u, sessionId=%u)", + __func__, zserv_command_string(cmd), + srv6_sid_ctx2str(buf, sizeof(buf), ctx), sid_value, + zapi_srv6_sid_notify2str(note), client->proto, + client->instance, client->session_id); + + s = stream_new(ZEBRA_MAX_PACKET_SIZ); + + zclient_create_header(s, cmd, VRF_DEFAULT); + /* Notification type (e.g. ZAPI_SRV6_SID_ALLOCATED, ZAPI_SRV6_SID_FAIL_ALLOC, ...) */ + stream_put(s, ¬e, sizeof(note)); + /* Context associated with the SRv6 SID */ + stream_put(s, ctx, sizeof(struct srv6_sid_ctx)); + /* SRv6 SID value (i.e. IPv6 address) */ + stream_put(s, sid_value, sizeof(struct in6_addr)); + /* SRv6 SID function */ + stream_putl(s, func); + /* SRv6 wide SID function */ + stream_putl(s, wide_func); + stream_putw_at(s, 0, stream_get_endp(s)); + + zserv_send_message(client, s); +} + /* Router-id is updated. Send ZEBRA_ROUTER_ID_UPDATE to client. */ int zsend_router_id_update(struct zserv *client, afi_t afi, struct prefix *p, diff --git a/zebra/zapi_msg.h b/zebra/zapi_msg.h index c7123e2593..3505bc0dc4 100644 --- a/zebra/zapi_msg.h +++ b/zebra/zapi_msg.h @@ -94,6 +94,11 @@ extern int zsend_sr_policy_notify_status(uint32_t color, extern void zsend_neighbor_notify(int cmd, struct interface *ifp, struct ipaddr *ipaddr, int ndm_state, union sockunion *link_layer_ipv4, int ip_len); +extern void zsend_srv6_sid_notify(struct zserv *client, + const struct srv6_sid_ctx *ctx, + struct in6_addr *sid_value, uint32_t func, + uint32_t wide_func, + enum zapi_srv6_sid_notify note); extern int zsend_client_close_notify(struct zserv *client, struct zserv *closed_client); diff --git a/zebra/zebra_srv6.c b/zebra/zebra_srv6.c index d93f09f1b4..663afa2f85 100644 --- a/zebra/zebra_srv6.c +++ b/zebra/zebra_srv6.c @@ -2279,6 +2279,8 @@ static int srv6_manager_get_sid_internal(struct zebra_srv6_sid **sid, const char *locator_name) { int ret = -1; + struct listnode *node; + struct zserv *c; char buf[256]; if (IS_ZEBRA_DEBUG_PACKET) @@ -2291,6 +2293,10 @@ static int srv6_manager_get_sid_internal(struct zebra_srv6_sid **sid, zlog_warn("%s: not got SRv6 SID for ctx %s, sid_value=%pI6, locator_name=%s", __func__, srv6_sid_ctx2str(buf, sizeof(buf), ctx), sid_value, locator_name); + + /* Notify client about SID alloc failure */ + zsend_srv6_sid_notify(client, ctx, NULL, 0, 0, + ZAPI_SRV6_SID_FAIL_ALLOC); } else if (ret == 0) { if (IS_ZEBRA_DEBUG_PACKET) zlog_debug("%s: got existing SRv6 SID for ctx %s: sid_value=%pI6 (func=%u) (proto=%u, instance=%u, sessionId=%u), notify client", @@ -2300,6 +2306,10 @@ static int srv6_manager_get_sid_internal(struct zebra_srv6_sid **sid, client->instance, client->session_id); if (!listnode_lookup((*sid)->client_list, client)) listnode_add((*sid)->client_list, client); + + zsend_srv6_sid_notify(client, ctx, &(*sid)->value, (*sid)->func, + (*sid)->wide_func, + ZAPI_SRV6_SID_ALLOCATED); } else { if (IS_ZEBRA_DEBUG_PACKET) zlog_debug("%s: got new SRv6 SID for ctx %s: sid_value=%pI6 (func=%u) (proto=%u, instance=%u, sessionId=%u), notifying all clients", @@ -2309,6 +2319,11 @@ static int srv6_manager_get_sid_internal(struct zebra_srv6_sid **sid, client->instance, client->session_id); if (!listnode_lookup((*sid)->client_list, client)) listnode_add((*sid)->client_list, client); + + for (ALL_LIST_ELEMENTS_RO((*sid)->client_list, node, c)) + zsend_srv6_sid_notify(c, ctx, &(*sid)->value, + (*sid)->func, (*sid)->wide_func, + ZAPI_SRV6_SID_ALLOCATED); } return ret; @@ -2382,6 +2397,13 @@ static int srv6_manager_release_sid_internal(struct zserv *client, zlog_debug("%s: no SID associated with ctx %s", __func__, srv6_sid_ctx2str(buf, sizeof(buf), ctx)); + if (ret == 0) + zsend_srv6_sid_notify(client, ctx, NULL, 0, 0, + ZAPI_SRV6_SID_RELEASED); + else + zsend_srv6_sid_notify(client, ctx, NULL, 0, 0, + ZAPI_SRV6_SID_FAIL_RELEASE); + return ret; } From 5365c56614191c7184126fd1a32db20953f008eb Mon Sep 17 00:00:00 2001 From: Carmine Scarpitta Date: Thu, 2 May 2024 23:50:38 +0200 Subject: [PATCH 050/347] zebra: Notify all daemons about locator delete Currently, when a locator is deleted in zebra, zebra notifies only the zclient that owns the locator. With the introduction of SID Manager, the locator is no longer owned by any client. Instead, the locator is owned by Zebra, and clients can allocate and release SIDs from the locator using the ZAPI ZEBRA_SRV6_MANAGER_GET_SID and ZEBRA_SRV6_MANAGER_RELEASE_SID. Therefore, when a locator is removed in Zebra, we need to notify all daemons so that they can release/uninstall the SIDs allocated by that locator. Signed-off-by: Carmine Scarpitta --- zebra/zebra_srv6.c | 25 ++----------------------- 1 file changed, 2 insertions(+), 23 deletions(-) diff --git a/zebra/zebra_srv6.c b/zebra/zebra_srv6.c index 663afa2f85..aac4ba86a9 100644 --- a/zebra/zebra_srv6.c +++ b/zebra/zebra_srv6.c @@ -634,7 +634,6 @@ void zebra_srv6_locator_add(struct srv6_locator *locator) void zebra_srv6_locator_delete(struct srv6_locator *locator) { struct listnode *n; - struct srv6_locator_chunk *c; struct zebra_srv6 *srv6 = zebra_srv6_get_default(); struct zserv *client; @@ -649,18 +648,8 @@ void zebra_srv6_locator_delete(struct srv6_locator *locator) * by ZEBRA_SRV6_LOCATOR_DELETE, and this notification is sent to the * owner of each chunk. */ - for (ALL_LIST_ELEMENTS_RO((struct list *)locator->chunks, n, c)) { - if (c->proto == ZEBRA_ROUTE_SYSTEM) - continue; - client = zserv_find_client(c->proto, c->instance); - if (!client) { - zlog_warn( - "%s: Not found zclient(proto=%u, instance=%u).", - __func__, c->proto, c->instance); - continue; - } + for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, n, client)) zsend_zebra_srv6_locator_delete(client, locator); - } listnode_delete(srv6->locators, locator); srv6_locator_free(locator); @@ -703,7 +692,6 @@ void zebra_notify_srv6_locator_add(struct srv6_locator *locator) void zebra_notify_srv6_locator_delete(struct srv6_locator *locator) { struct listnode *n; - struct srv6_locator_chunk *c; struct zserv *client; /* @@ -717,17 +705,8 @@ void zebra_notify_srv6_locator_delete(struct srv6_locator *locator) * by ZEBRA_SRV6_LOCATOR_DELETE, and this notification is sent to the * owner of each chunk. */ - for (ALL_LIST_ELEMENTS_RO((struct list *)locator->chunks, n, c)) { - if (c->proto == ZEBRA_ROUTE_SYSTEM) - continue; - client = zserv_find_client(c->proto, c->instance); - if (!client) { - zlog_warn("Not found zclient(proto=%u, instance=%u).", - c->proto, c->instance); - continue; - } + for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, n, client)) zsend_zebra_srv6_locator_delete(client, locator); - } } struct zebra_srv6 srv6; From 33bd67a006ca3958e094232f80a32c879783227a Mon Sep 17 00:00:00 2001 From: Carmine Scarpitta Date: Thu, 2 May 2024 17:08:15 +0200 Subject: [PATCH 051/347] doc: Add documentation for SRv6 SID formats CLI Signed-off-by: Carmine Scarpitta --- doc/user/zebra.rst | 84 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/doc/user/zebra.rst b/doc/user/zebra.rst index 37644dc88a..900d2fd343 100644 --- a/doc/user/zebra.rst +++ b/doc/user/zebra.rst @@ -1021,6 +1021,35 @@ and this section also helps that case. ! ... +.. clicmd:: format NAME + + Specify the SID allocation schema for the SIDs allocated from this locator. Currently, + FRR supports supports the following allocation schemas: + + - `usid-f3216` + - `uncompressed` + +:: + + router# configure terminal + router(config)# segment-routinig + router(config-sr)# srv6 + router(config-srv6)# locators + router(config-srv6-locators)# locator loc1 + router(config-srv6-locator)# prefix fc00:0:1::/48 + router(config-srv6-locator)# format usid-f3216 + + router(config-srv6-locator)# show run + ... + segment-routing + srv6 + locators + locator loc1 + prefix fc00:0:1::/48 + format usid-f3216 + ! + ... + .. clicmd:: encapsulation Configure parameters for SRv6 encapsulation. @@ -1029,6 +1058,61 @@ and this section also helps that case. Configure the source address of the outer encapsulating IPv6 header. +.. clicmd:: formats + + Configure SRv6 SID formats. + +.. clicmd:: format NAME + + Configure SRv6 SID format. + +.. clicmd:: compressed usid + + Enable SRv6 uSID compression and configure SRv6 uSID compression parameters. + +.. clicmd:: local-id-block start START + + Configure the start value for the Local ID Block (LIB). + +.. clicmd:: local-id-block explicit start START end END + + Configure the start/end values for the Explicit LIB (ELIB). + +.. clicmd:: wide-local-id-block start START end END + + Configure the start/end values for the Wide LIB (W-LIB). + +.. clicmd:: wide-local-id-block explicit start START + + Configure the start value for the Explicit Wide LIB (EW-LIB). + +:: + + router# configure terminal + router(config)# segment-routinig + router(config-sr)# srv6 + router(config-srv6)# formats + router(config-srv6-formats)# format usid-f3216 + router(config-srv6-format)# compressed usid + router(config-srv6-format-usid)# local-id-block start 0xD000 + router(config-srv6-format-usid)# local-id-block explicit start 0xF000 end 0xFDFF + router(config-srv6-format-usid)# wide-local-id-block start 0xFFF4 end 0xFFF5 + router(config-srv6-format-usid)# wide-local-id-block explicit start 0xFFF4 + + router(config-srv6-locator)# show run + ... + segment-routing + srv6 + formats + format usid-f3216 + compressed usid + local-id-block start 0xD000 + local-id-block explicit start 0xF000 end 0xFDFF + wide-local-id-block start 0xFFF4 end 0xFFF5 + wide-local-id-block explicit start 0xFFF4 + ! + ... + .. _multicast-rib-commands: Multicast RIB Commands From 4dcb69e0f91c8698be537a3e46b075b703afe8b3 Mon Sep 17 00:00:00 2001 From: Carmine Scarpitta Date: Fri, 3 May 2024 19:31:56 +0200 Subject: [PATCH 052/347] zebra: Fix checkpatch warning Signed-off-by: Carmine Scarpitta --- lib/zclient.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/zclient.c b/lib/zclient.c index e4d02d743a..a1386e501a 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -3447,7 +3447,7 @@ int srv6_manager_release_sid(struct zclient *zclient, /* * Asynchronous label chunk request * - * @param zclient Zclient used to connect to label manager (zebra) + * @param zclient The zclient used to connect to label manager (zebra) * @param keep Avoid garbage collection * @param chunk_size Amount of labels requested * @param base Base for the label chunk. if MPLS_LABEL_BASE_ANY we do not care From 708f20e58aa928d795eaa9ceb6c6de67341fb4ac Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Fri, 7 Jun 2024 15:46:20 +0200 Subject: [PATCH 053/347] zebra: fix display srv6 address only for explicit-sid Signed-off-by: Philippe Guibert --- zebra/zebra_srv6.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/zebra/zebra_srv6.c b/zebra/zebra_srv6.c index aac4ba86a9..cbf471ae3d 100644 --- a/zebra/zebra_srv6.c +++ b/zebra/zebra_srv6.c @@ -2265,13 +2265,13 @@ static int srv6_manager_get_sid_internal(struct zebra_srv6_sid **sid, if (IS_ZEBRA_DEBUG_PACKET) zlog_debug("%s: getting SRv6 SID for ctx %s, sid_value=%pI6, locator_name=%s", __func__, srv6_sid_ctx2str(buf, sizeof(buf), ctx), - sid_value, locator_name); + sid_value ? sid_value : &in6addr_any, locator_name); ret = get_srv6_sid(sid, ctx, sid_value, locator_name); if (ret < 0) { zlog_warn("%s: not got SRv6 SID for ctx %s, sid_value=%pI6, locator_name=%s", __func__, srv6_sid_ctx2str(buf, sizeof(buf), ctx), - sid_value, locator_name); + sid_value ? sid_value : &in6addr_any, locator_name); /* Notify client about SID alloc failure */ zsend_srv6_sid_notify(client, ctx, NULL, 0, 0, From 35a87b6acda9b6a7be594e743798fb5b66fa7e79 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Fri, 7 Jun 2024 15:46:53 +0200 Subject: [PATCH 054/347] zebra: fix display explicit sid refused > 2024/06/07 15:09:43 ZEBRA: [MZYPC-GBDGR] srv6_manager_get_sid_internal: getting SRv6 SID for ctx End.DT4 vrf vrf1, sid_value=1003::4, locator_name= > [..] > 2024/06/07 15:09:43 ZEBRA: [QGJBT-YJ11W] zsend_srv6_sid_notify: notifying ZEBRA_SRV6_SID_NOTIFY ctx End.DT4 vrf vrf2, sid (null) note ZAPI_SRV6_SID_FAIL_ALLOC (proto=30, instance=0, sessionId=0) Signed-off-by: Philippe Guibert --- zebra/zebra_srv6.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zebra/zebra_srv6.c b/zebra/zebra_srv6.c index cbf471ae3d..4273e52a01 100644 --- a/zebra/zebra_srv6.c +++ b/zebra/zebra_srv6.c @@ -2274,7 +2274,7 @@ static int srv6_manager_get_sid_internal(struct zebra_srv6_sid **sid, sid_value ? sid_value : &in6addr_any, locator_name); /* Notify client about SID alloc failure */ - zsend_srv6_sid_notify(client, ctx, NULL, 0, 0, + zsend_srv6_sid_notify(client, ctx, sid_value, 0, 0, ZAPI_SRV6_SID_FAIL_ALLOC); } else if (ret == 0) { if (IS_ZEBRA_DEBUG_PACKET) From 209223dae298ed33388563f2947923c0471b2ce7 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Tue, 11 Jun 2024 18:14:58 +0200 Subject: [PATCH 055/347] zebra: fix sid allocation should be different with 2 isis instances With 2 ISIS SRv6 instances, the second ISIS instance always gets the same End SID as the first one. > router isis 1 > segment-routing srv6 > locator loc1 > exit > exit > router isis 2 > segment-routing srv6 > locator loc2 > end > segment-routing > srv6 > locators > locator loc1 > prefix 2001::1/64 > exit > locator loc2 > prefix 3001::1/64 > output: > 2024/06/11 17:30:15 ISIS: [N6PCR-FQ5ZA] SRv6 locator (locator loc1, prefix 2001::1/64) set for IS-IS area 1 > 2024/06/11 17:30:15 ISIS: [V4RBG-TYW5S] Requesting SRv6 SIDs for IS-IS area 1 > 2024/06/11 17:30:15 ISIS: [ZRHYM-6RMYK] isis_zebra_srv6_sid_notify: received SRv6 SID notify: ctx End USP sid_value 2001::1 sid_func 0 note ZAPI_SRV6_SID_ALLOCATED > [..] > 2024/06/11 17:36:49 ISIS: [N6PCR-FQ5ZA] SRv6 locator (locator loc2, prefix 3001::1/64) set for IS-IS area 2 > 2024/06/11 17:36:49 ISIS: [V4RBG-TYW5S] Requesting SRv6 SIDs for IS-IS area 2 > 2024/06/11 17:36:49 ISIS: [ZRHYM-6RMYK] isis_zebra_srv6_sid_notify: received SRv6 SID notify: ctx End USP sid_value 2001::1 sid_func 0 note ZAPI_SRV6_SID_ALLOCATED Actually, at the second request, ZEBRA always gives an existing dynamic SID of the first available locator, because the locator name is never checked. > 2024/06/11 17:36:49 ZEBRA: [XMBTQ-GE6EY] get_srv6_sid: received SRv6 SID alloc request: SID ctx End USP ((null)), mode=dynamic > 2024/06/11 17:36:49 ZEBRA: [R61Q3-QWR23] get_srv6_sid_dynamic: returning existing SID End USP 2001::1 > 2024/06/11 17:36:49 ZEBRA: [J1GMY-B6CAK] srv6_manager_get_sid_internal: got existing SRv6 SID for ctx End USP: sid_value=2001::1 (func=0) (proto=9, instance=0, sessionId=0), notify client Fix this by checking the locator of the existing SID. Fixes: b771bf8ce687 ("zebra: Add functions to alloc/release SRv6 SIDs") Signed-off-by: Philippe Guibert --- zebra/zebra_srv6.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/zebra/zebra_srv6.c b/zebra/zebra_srv6.c index 4273e52a01..a6db66bbcc 100644 --- a/zebra/zebra_srv6.c +++ b/zebra/zebra_srv6.c @@ -1645,6 +1645,12 @@ static int get_srv6_sid_dynamic(struct zebra_srv6_sid **sid, * SID instead of allocating a new one. */ for (ALL_LIST_ELEMENTS_RO(srv6->sids, node, s)) { + if (locator && s->sid && s->sid->locator) { + if (strncmp(s->sid->locator->name, locator->name, + SRV6_LOCNAME_SIZE)) { + continue; + } + } if (memcmp(&s->ctx, ctx, sizeof(struct srv6_sid_ctx)) == 0) { if (IS_ZEBRA_DEBUG_PACKET) zlog_debug("%s: returning existing SID %s %pI6", From a23a9385a74dcf31be1224cd7536fa585e6f0283 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Thu, 13 Jun 2024 15:30:00 -0400 Subject: [PATCH 056/347] zebra: Use built in data structure counter Instead of keeping a counter that is independent of the queue's data structure. Just use the queue's built-in counter. Ensure that it's pthread safe by keeping it wrapped inside the mutex for adding/deleting to the queue. Signed-off-by: Donald Sharp --- zebra/dplane_fpm_nl.c | 40 ++++++++++++++++++---------------------- zebra/zebra_dplane.c | 5 +++++ zebra/zebra_dplane.h | 2 ++ 3 files changed, 25 insertions(+), 22 deletions(-) diff --git a/zebra/dplane_fpm_nl.c b/zebra/dplane_fpm_nl.c index 9ad92d6269..28c481d1d8 100644 --- a/zebra/dplane_fpm_nl.c +++ b/zebra/dplane_fpm_nl.c @@ -136,8 +136,6 @@ struct fpm_nl_ctx { /* Amount of data plane context processed. */ _Atomic uint32_t dplane_contexts; - /* Amount of data plane contexts enqueued. */ - _Atomic uint32_t ctxqueue_len; /* Peak amount of data plane contexts enqueued. */ _Atomic uint32_t ctxqueue_len_peak; @@ -399,6 +397,12 @@ DEFUN(fpm_show_counters, fpm_show_counters_cmd, FPM_STR "FPM statistic counters\n") { + uint32_t curr_queue_len; + + frr_with_mutex (&gfnc->ctxqueue_mutex) { + curr_queue_len = dplane_ctx_queue_count(&gfnc->ctxqueue); + } + vty_out(vty, "%30s\n%30s\n", "FPM counters", "============"); #define SHOW_COUNTER(label, counter) \ @@ -412,8 +416,7 @@ DEFUN(fpm_show_counters, fpm_show_counters_cmd, SHOW_COUNTER("Connection errors", gfnc->counters.connection_errors); SHOW_COUNTER("Data plane items processed", gfnc->counters.dplane_contexts); - SHOW_COUNTER("Data plane items enqueued", - gfnc->counters.ctxqueue_len); + SHOW_COUNTER("Data plane items enqueued", curr_queue_len); SHOW_COUNTER("Data plane items queue peak", gfnc->counters.ctxqueue_len_peak); SHOW_COUNTER("Buffer full hits", gfnc->counters.buffer_full); @@ -432,6 +435,12 @@ DEFUN(fpm_show_counters_json, fpm_show_counters_json_cmd, "FPM statistic counters\n" JSON_STR) { + uint32_t curr_queue_len; + + frr_with_mutex (&gfnc->ctxqueue_mutex) { + curr_queue_len = dplane_ctx_queue_count(&gfnc->ctxqueue); + } + struct json_object *jo; jo = json_object_new_object(); @@ -445,8 +454,7 @@ DEFUN(fpm_show_counters_json, fpm_show_counters_json_cmd, gfnc->counters.connection_errors); json_object_int_add(jo, "data-plane-contexts", gfnc->counters.dplane_contexts); - json_object_int_add(jo, "data-plane-contexts-queue", - gfnc->counters.ctxqueue_len); + json_object_int_add(jo, "data-plane-contexts-queue", curr_queue_len); json_object_int_add(jo, "data-plane-contexts-queue-peak", gfnc->counters.ctxqueue_len_peak); json_object_int_add(jo, "buffer-full-hits", gfnc->counters.buffer_full); @@ -1495,8 +1503,6 @@ static void fpm_process_queue(struct event *t) /* Account the processed entries. */ processed_contexts++; - atomic_fetch_sub_explicit(&fnc->counters.ctxqueue_len, 1, - memory_order_relaxed); dplane_ctx_set_status(ctx, ZEBRA_DPLANE_REQUEST_SUCCESS); dplane_provider_enqueue_out_ctx(fnc->prov, ctx); @@ -1670,7 +1676,7 @@ static int fpm_nl_process(struct zebra_dplane_provider *prov) struct zebra_dplane_ctx *ctx; struct fpm_nl_ctx *fnc; int counter, limit; - uint64_t cur_queue, peak_queue = 0, stored_peak_queue; + uint64_t cur_queue = 0, peak_queue = 0, stored_peak_queue; fnc = dplane_provider_get_data(prov); limit = dplane_provider_get_work_limit(prov); @@ -1684,20 +1690,12 @@ static int fpm_nl_process(struct zebra_dplane_provider *prov) * anyway. */ if (fnc->socket != -1 && fnc->connecting == false) { - /* - * Update the number of queued contexts *before* - * enqueueing, to ensure counter consistency. - */ - atomic_fetch_add_explicit(&fnc->counters.ctxqueue_len, - 1, memory_order_relaxed); - frr_with_mutex (&fnc->ctxqueue_mutex) { dplane_ctx_enqueue_tail(&fnc->ctxqueue, ctx); + cur_queue = + dplane_ctx_queue_count(&fnc->ctxqueue); } - cur_queue = atomic_load_explicit( - &fnc->counters.ctxqueue_len, - memory_order_relaxed); if (peak_queue < cur_queue) peak_queue = cur_queue; continue; @@ -1714,9 +1712,7 @@ static int fpm_nl_process(struct zebra_dplane_provider *prov) atomic_store_explicit(&fnc->counters.ctxqueue_len_peak, peak_queue, memory_order_relaxed); - if (atomic_load_explicit(&fnc->counters.ctxqueue_len, - memory_order_relaxed) - > 0) + if (cur_queue > 0) event_add_event(fnc->fthread->master, fpm_process_queue, fnc, 0, &fnc->t_dequeue); diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c index 06b34da209..ee48a571b8 100644 --- a/zebra/zebra_dplane.c +++ b/zebra/zebra_dplane.c @@ -969,6 +969,11 @@ struct zebra_dplane_ctx *dplane_ctx_dequeue(struct dplane_ctx_list_head *q) return ctx; } +uint32_t dplane_ctx_queue_count(struct dplane_ctx_list_head *q) +{ + return dplane_ctx_list_count(q); +} + /* * Accessors for information from the context object */ diff --git a/zebra/zebra_dplane.h b/zebra/zebra_dplane.h index 060b1c8b9e..0e9a8bfb99 100644 --- a/zebra/zebra_dplane.h +++ b/zebra/zebra_dplane.h @@ -323,6 +323,8 @@ struct zebra_dplane_ctx *dplane_ctx_get_head(struct dplane_ctx_list_head *q); /* Init a list of contexts */ void dplane_ctx_q_init(struct dplane_ctx_list_head *q); +uint32_t dplane_ctx_queue_count(struct dplane_ctx_list_head *q); + /* * Accessors for information from the context object */ From 7a905c0d019d1f85092f7fea8f35320d956c5859 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Thu, 6 Jun 2024 15:18:48 +0200 Subject: [PATCH 057/347] isisd: fix 'show isis route prefix-sid backup' command It is not possible to dump both backup and prefix-sid information. Fix this by authorising it. > rt1# show isis route prefix-sid backup > Area 1: > IS-IS paths to level-1 routers that speak IP > Vertex Type Metric Next-Hop Interface Parent > rt1 > 10.12.0.0/24 IP internal 0 rt1(4) > 10.13.0.0/24 IP internal 0 rt1(4) > 1.1.1.1/32 IP internal 0 rt1(4) > rt2 TE-IS 10 rt2 eth-rt2 rt1(4) > rt3 TE-IS 10 rt3 eth-rt3 rt1(4) > 10.12.0.0/24 IP TE 20 rt2 eth-rt2 rt2(4) > 10.23.0.0/24 IP TE 20 rt2 eth-rt2 rt2(4) > rt3 eth-rt3 rt3(4) > 2.2.2.2/32 IP TE 20 rt2 eth-rt2 rt2(4) > 10.13.0.0/24 IP TE 20 rt3 eth-rt3 rt3(4) > 3.3.3.3/32 IP TE 20 rt3 eth-rt3 rt3(4) > > IS-IS L1 IPv4 routing table: > > IS-IS paths to level-1 routers that speak IPv6 > Vertex Type Metric Next-Hop Interface Parent > rt1 > 2001:db8:1000::1/128 IP6 internal 0 rt1(4) > rt2 TE-IS 10 rt2 eth-rt2 rt1(4) > rt3 TE-IS 10 rt3 eth-rt3 rt1(4) > 2001:db8:1000::2/128 IP6 internal 20 rt2 eth-rt2 rt2(4) > 2001:db8:1000::3/128 IP6 internal 20 rt3 eth-rt3 rt3(4) > > IS-IS L1 IPv6 routing table: > Fixes: d47d6089e06c ("isisd: refactor handling of SR Prefix-SIDs") Signed-off-by: Philippe Guibert --- doc/user/isisd.rst | 2 +- isisd/isis_spf.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/user/isisd.rst b/doc/user/isisd.rst index 7412611869..3a0f277bf0 100644 --- a/doc/user/isisd.rst +++ b/doc/user/isisd.rst @@ -325,7 +325,7 @@ Showing ISIS information Show topology IS-IS paths to Intermediate Systems, globally, in area (level-1) or domain (level-2). -.. clicmd:: show isis [vrf ] route [level-1|level-2] [prefix-sid|backup] [algorithm [(128-255)]] +.. clicmd:: show isis [vrf ] route [level-1|level-2] [prefix-sid] [backup] [algorithm [(128-255)]] Show the ISIS routing table, as determined by the most recent SPF calculation. diff --git a/isisd/isis_spf.c b/isisd/isis_spf.c index e349373372..81201023d6 100644 --- a/isisd/isis_spf.c +++ b/isisd/isis_spf.c @@ -3074,7 +3074,7 @@ DEFUN(show_isis_route, show_isis_route_cmd, #ifndef FABRICD " []" #endif /* ifndef FABRICD */ - " []" + " [prefix-sid] [backup]" #ifndef FABRICD " [algorithm [(128-255)]]" #endif /* ifndef FABRICD */ From 686d477242890c575024962188dd50c06160f2a3 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Fri, 14 Jun 2024 10:30:31 +0300 Subject: [PATCH 058/347] docker: Use Alpine Linux 3.20 Signed-off-by: Donatas Abraitis --- docker/alpine/Dockerfile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docker/alpine/Dockerfile b/docker/alpine/Dockerfile index 1cff06feee..3f811455b3 100644 --- a/docker/alpine/Dockerfile +++ b/docker/alpine/Dockerfile @@ -1,7 +1,7 @@ # syntax=docker/dockerfile:1 # Create a basic stage set up to build APKs -FROM alpine:3.19 as alpine-builder +FROM alpine:3.20 as alpine-builder RUN apk add \ --update-cache \ abuild \ @@ -24,7 +24,7 @@ RUN cd /src/libyang \ && abuild -r -P /pkgs/apk # This stage builds a dist tarball from the source -FROM alpine:3.19 as source-builder +FROM alpine:3.20 as source-builder RUN mkdir -p /src/alpine /pkgs/apk COPY alpine/APKBUILD.in /src/alpine COPY --from=alpine-apk-builder-libyang /pkgs/apk/src /pkgs/apk @@ -57,7 +57,7 @@ RUN cd /dist \ && abuild -r -P /pkgs/apk # This stage installs frr from the apk -FROM alpine:3.19 +FROM alpine:3.20 RUN mkdir -p /pkgs/apk COPY --from=alpine-apk-builder /pkgs/apk/ /pkgs/apk/ RUN apk add \ From 2876847d500b7b734fa290e6dc9aa151de9f9a48 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Fri, 14 Jun 2024 10:35:27 +0300 Subject: [PATCH 059/347] docker: Do not require checks for libyang Alpine Linux package build Since Alpine Linux 3.20, we get this: >>> WARNING: libyang: APKBUILD does not run any tests! Alpine policy will soon require that packages have any relevant testsuites run during the build process. To fix, either define a check() function, or declare !check in $options to indicate the package does not have a testsuite. Signed-off-by: Donatas Abraitis --- docker/alpine/libyang/APKBUILD | 1 + 1 file changed, 1 insertion(+) diff --git a/docker/alpine/libyang/APKBUILD b/docker/alpine/libyang/APKBUILD index 6973fd62d8..7979ee1b1e 100755 --- a/docker/alpine/libyang/APKBUILD +++ b/docker/alpine/libyang/APKBUILD @@ -11,6 +11,7 @@ makedepends="bison cmake cmocka-dev flex pcre2-dev" checkdepends="expect grep shunit2" subpackages="$pkgname-dev $pkgname-doc" source="$pkgname-$pkgver.tar.gz::https://github.com/CESNET/libyang/archive/v$pkgver.tar.gz" +options="!check" # secfixes: # 1.0.215-r1: From 0314adac4b906ac6c9abcb702f9fd799b89d93f2 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Fri, 14 Jun 2024 11:37:23 +0300 Subject: [PATCH 060/347] docker: Set ABUILD_APK_INDEX_OPTS for libyang In build() stage of abuild, it does `apk index ...` where libyang* packages are unsigned. We don't sign them here, and thus we need to specify `--allow-untrusted`. Signed-off-by: Donatas Abraitis --- docker/alpine/libyang/APKBUILD | 1 + 1 file changed, 1 insertion(+) diff --git a/docker/alpine/libyang/APKBUILD b/docker/alpine/libyang/APKBUILD index 7979ee1b1e..d8cd4d918a 100755 --- a/docker/alpine/libyang/APKBUILD +++ b/docker/alpine/libyang/APKBUILD @@ -22,6 +22,7 @@ options="!check" # - CVE-2021-28906 build() { + export ABUILD_APK_INDEX_OPTS="--allow-untrusted" if [ "$CBUILD" != "$CHOST" ]; then CMAKE_CROSSOPTS="-DCMAKE_SYSTEM_NAME=Linux -DCMAKE_HOST_SYSTEM_NAME=Linux" fi From 09db258157576999975a9d95add4ae327f7f3a5c Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Fri, 14 Jun 2024 16:33:32 +0300 Subject: [PATCH 061/347] docker: Set ABUILD_APK_INDEX_OPTS for frr build In build() stage of abuild, it does `apk index ...` where frr* packages are unsigned. We don't sign them here, and thus we need to specify `--allow-untrusted`. Signed-off-by: Donatas Abraitis --- alpine/APKBUILD.in | 2 ++ 1 file changed, 2 insertions(+) diff --git a/alpine/APKBUILD.in b/alpine/APKBUILD.in index 2cb3feec15..855b585903 100644 --- a/alpine/APKBUILD.in +++ b/alpine/APKBUILD.in @@ -33,6 +33,8 @@ _libdir=/usr/lib _user=frr build() { + export ABUILD_APK_INDEX_OPTS="--allow-untrusted" + cd "$builddir" ./configure \ From 6faad863f30d29157e4c675ad956e3ccd38991a7 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Fri, 14 Jun 2024 13:36:51 -0400 Subject: [PATCH 062/347] zebra: Prevent starvation in dplane_thread_loop When removing a large number of routes, the linux kernel can take the cpu for an extended amount of time, leaving a situation where FRR detects a starvation event. r1# sharp install routes 10.0.0.0 nexthop 192.168.44.33 1000000 repeat 10 2024-06-14 12:55:49.365 [NTFY] sharpd: [M7Q4P-46WDR] vty[5]@# sharp install routes 10.0.0.0 nexthop 192.168.44.33 1000000 repeat 10 2024-06-14 12:55:49.365 [DEBG] sharpd: [YP4TQ-01TYK] Inserting 1000000 routes 2024-06-14 12:55:57.256 [DEBG] sharpd: [TPHKD-3NYSB] Installed All Items 7.890085 2024-06-14 12:55:57.256 [DEBG] sharpd: [YJ486-NX5R1] Removing 1000000 routes 2024-06-14 12:56:07.802 [WARN] zebra: [QH9AB-Y4XMZ][EC 100663314] STARVATION: task dplane_thread_loop (634377bc8f9e) ran for 7078ms (cpu time 220ms) 2024-06-14 12:56:25.039 [DEBG] sharpd: [WTN53-GK9Y5] Removed all Items 27.783668 2024-06-14 12:56:25.039 [DEBG] sharpd: [YP4TQ-01TYK] Inserting 1000000 routes 2024-06-14 12:56:32.783 [DEBG] sharpd: [TPHKD-3NYSB] Installed All Items 7.743524 2024-06-14 12:56:32.783 [DEBG] sharpd: [YJ486-NX5R1] Removing 1000000 routes 2024-06-14 12:56:41.447 [WARN] zebra: [QH9AB-Y4XMZ][EC 100663314] STARVATION: task dplane_thread_loop (634377bc8f9e) ran for 5175ms (cpu time 179ms) Let's modify the loop in dplane_thread_loop such that after a provider has been run, check to see if the event should yield, if so, stop and reschedule this for the future. Signed-off-by: Donald Sharp --- zebra/zebra_dplane.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c index 06b34da209..3944876439 100644 --- a/zebra/zebra_dplane.c +++ b/zebra/zebra_dplane.c @@ -7441,6 +7441,11 @@ static void dplane_thread_loop(struct event *event) zlog_debug("dplane dequeues %d completed work from provider %s", counter, dplane_provider_get_name(prov)); + if (event_should_yield(event)) { + reschedule = true; + break; + } + /* Locate next provider */ prov = dplane_prov_list_next(&zdplane_info.dg_providers, prov); } From accdf83c5774cf814775e7273057e6191dc1f0f2 Mon Sep 17 00:00:00 2001 From: anlan_cs Date: Sat, 15 Jun 2024 13:56:25 +0800 Subject: [PATCH 063/347] doc: fix one ldp neighbor command Signed-off-by: anlan_cs --- doc/user/ldpd.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/user/ldpd.rst b/doc/user/ldpd.rst index cbed734e42..7a000a49c4 100644 --- a/doc/user/ldpd.rst +++ b/doc/user/ldpd.rst @@ -148,7 +148,7 @@ LDP Configuration configured password. PASSWORD is a clear text password wit its digest sent through the network. -.. clicmd:: neighbor A.B.C.D holdtime HOLDTIME +.. clicmd:: neighbor A.B.C.D session holdtime HOLDTIME The following command located under MPLS router node configures the holdtime value in seconds of the LDP neighbor ID. Configuring it triggers a keepalive From 1919df3a64d3fe6d4084c1d0b050b3e368860170 Mon Sep 17 00:00:00 2001 From: anlan_cs Date: Sat, 15 Jun 2024 20:34:20 +0800 Subject: [PATCH 064/347] ldpd: fix wrong gtsm count In linux networking stack, the received mpls packets will be processed by the host *twice*, one as mpls packet, the other as ip packet, so its ttl decreased 1. So, we need release the `IP_MINTTL` value if gtsm is enabled, it is for the mpls packets of neighbor session caused by the command: `label local advertise explicit-null`. This change makes the gtsm mechanism a bit deviation. Fix PR #8313 Signed-off-by: anlan_cs --- ldpd/neighbor.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/ldpd/neighbor.c b/ldpd/neighbor.c index d40728b043..2596c79481 100644 --- a/ldpd/neighbor.c +++ b/ldpd/neighbor.c @@ -681,6 +681,18 @@ nbr_gtsm_setup(int fd, int af, struct nbr_params *nbrp) if (nbrp && CHECK_FLAG(nbrp->flags, F_NBRP_GTSM_HOPS)) ttl = 256 - nbrp->gtsm_hops; + /* + * In linux networking stack, the received mpls packets + * will be processed by the host twice, one as mpls packet, + * the other as ip packet, so its ttl will be decreased 1. + * This behavior is based on the new kernel (5.10 and 6.1), + * and older versions may behave differently. + * + * Here, decrease 1 for IP_MINTTL if GTSM is enabled. + * And this workaround makes the GTSM mechanism a bit deviation. + */ + ttl -= 1; + switch (af) { case AF_INET: if (sock_set_ipv4_minttl(fd, ttl) == -1) From 5d1298de68b95ab19a3338abb0b794ddb046187c Mon Sep 17 00:00:00 2001 From: zhou-run <166502045+zhou-run@users.noreply.github.com> Date: Mon, 17 Jun 2024 16:45:09 +0800 Subject: [PATCH 065/347] isisd: After the router switches IS-IS type several times, the neighbor adjacency cannot be established. 1. Router A is configured with "is-type level-1-2", while Router B is configured with "is-type level-1". Only level 1 neighbor entries are present on Router A. 2. After configuring Router B with "is-type level-2-only", both level 1 and level 2 neighbor entries exist on Router A. The state of these entries is UP, and the level 1 neighbor entry is currently aging. 3. Before the level 1 neighbor entry on Router A ages out, configuring Router B with "is-type level-1", both level 1 and level 2 neighbor entries exist on Router A. The level 2 neighbor entry is UP and will age out normally. However, the level 1 neighbor entry remains in the Initializing state, preventing the establishment of level 1 neighbor adjacency between Router A and Router B. When the adjacency type of the link is switched in function isis_circuit_is_type_set, the function circuit_resign_level() is called to delete the old level's circuit->u.bc.lan_neighs linked list. If the old level is not level-1-2, the function circuit_commence_level() is called to create a new level's circuit->u.bc.lan_neighs linked list, but neither of these functions handle the circuit->u.bc.adjdb linked list. This leads to a situation where upon receiving hello packets again before the circuit->u.bc.adjdb linked list entries age out, the circuit->u.bc.lan_neighs linked list is not constructed based on the circuit->u.bc.adjdb linked list. As a result, the hello packets sent will consistently lack an SNPA, causing the neighbor to remain unable to establish an adjacency upon receiving the hello packets. Signed-off-by: zhou-run <166502045+zhou-run@users.noreply.github.com> --- isisd/isis_events.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/isisd/isis_events.c b/isisd/isis_events.c index 32231a079f..5574bbc50f 100644 --- a/isisd/isis_events.c +++ b/isisd/isis_events.c @@ -83,6 +83,7 @@ static void circuit_commence_level(struct isis_circuit *circuit, int level) send_hello_sched(circuit, level, TRIGGERED_IIH_DELAY); circuit->u.bc.lan_neighs[level - 1] = list_new(); + circuit->u.bc.adjdb[level - 1] = list_new(); } } @@ -108,6 +109,10 @@ static void circuit_resign_level(struct isis_circuit *circuit, int level) circuit->u.bc.is_dr[idx] = 0; if (circuit->u.bc.lan_neighs[idx] != NULL) list_delete(&circuit->u.bc.lan_neighs[idx]); + if (circuit->u.bc.adjdb[idx]) { + circuit->u.bc.adjdb[idx]->del = isis_delete_adj; + list_delete(&circuit->u.bc.adjdb[idx]); + } } return; From 8381dbd9e258825daff4802c4c44b3d435a7b7e3 Mon Sep 17 00:00:00 2001 From: Y Bharath Date: Sat, 15 Jun 2024 22:36:32 +0530 Subject: [PATCH 066/347] tests: Avoid importing unused modules Signed-off-by: y-bharath14 --- .../topotests/eigrp_topo1/test_eigrp_topo1.py | 1 - .../test_evpn_type5_topo1.py | 3 +-- .../fpm_testing_topo1/test_fpm_topo1.py | 2 -- tests/topotests/grpc_basic/test_basic_grpc.py | 3 +-- .../test_isis_advertise_high_metrics.py | 3 --- .../isis_lfa_topo1/test_isis_lfa_topo1.py | 7 +++--- .../test_isis_lsp_bits_topo1.py | 2 +- .../isis_rlfa_topo1/test_isis_rlfa_topo1.py | 2 +- tests/topotests/isis_snmp/test_isis_snmp.py | 2 +- .../test_isis_sr_flex_algo_topo1.py | 3 +-- .../test_isis_sr_flex_algo_topo2.py | 6 ++--- .../isis_sr_te_topo1/test_isis_sr_te_topo1.py | 4 ++-- .../isis_sr_topo1/test_isis_sr_topo1.py | 2 +- .../isis_srv6_topo1/test_isis_srv6_topo1.py | 5 ++-- .../isis_tilfa_topo1/test_isis_tilfa_topo1.py | 3 +-- tests/topotests/isis_topo1/test_isis_topo1.py | 16 ++++++------- .../isis_topo1_vrf/test_isis_topo1_vrf.py | 4 ++-- .../topotests/key_sendaccept/test_keychain.py | 2 +- .../ldp_oc_acl_topo1/test_ldp_oc_acl_topo1.py | 2 +- .../ldp_oc_topo1/test_ldp_oc_topo1.py | 2 +- .../topotests/ldp_snmp/test_ldp_snmp_topo1.py | 2 +- .../test_ldp_sync_isis_topo1.py | 2 +- .../test_ldp_sync_ospf_topo1.py | 2 +- .../ldp_vpls_topo1/test_ldp_vpls_topo1.py | 2 +- tests/topotests/lib/bgp.py | 20 ++++++++-------- tests/topotests/lib/checkping.py | 2 +- tests/topotests/lib/common_config.py | 13 +++++----- tests/topotests/lib/fe_client.py | 11 ++++----- tests/topotests/lib/ospf.py | 4 ++-- tests/topotests/lib/pim.py | 24 +++++++++---------- .../topotests/mgmt_debug_flags/test_debug.py | 2 +- tests/topotests/mgmt_notif/test_notif.py | 3 +-- tests/topotests/mgmt_oper/oper.py | 4 ++-- tests/topotests/mgmt_oper/test_oper.py | 6 ----- tests/topotests/mgmt_rpc/test_rpc.py | 2 +- tests/topotests/mgmt_tests/test_yang_mgmt.py | 1 - tests/topotests/msdp_topo1/test_msdp_topo1.py | 2 +- .../test_multicast_pim6_sm1.py | 2 +- .../test_multicast_pim6_sm2.py | 2 +- .../test_pim_dr_nondr_with_ospf_topo2.py | 11 --------- .../test_multicast_pim_sm_topo1.py | 3 +-- .../test_multicast_pim_sm_topo2.py | 3 +-- .../test_multicast_pim_sm_topo3.py | 5 ++-- .../test_multicast_pim_sm_topo4.py | 5 ++-- .../test_multicast_pim_static_rp.py | 7 ------ .../test_multicast_pim_static_rp1.py | 5 ---- .../test_multicast_pim_static_rp2.py | 5 ---- .../test_multicast_pim_uplink_topo1.py | 5 ++-- .../test_multicast_pim_uplink_topo2.py | 2 +- tests/topotests/nb_config/test_nb_config.py | 2 +- .../nhrp_redundancy/test_nhrp_redundancy.py | 3 +-- .../ospf6_gr_topo1/test_ospf6_gr_topo1.py | 2 +- .../test_ospf6_loopback_cost.py | 4 ++-- .../test_ospf6_point_to_multipoint.py | 4 ++-- .../topotests/ospf6_topo1/test_ospf6_topo1.py | 6 ++--- .../ospf6_topo1_vrf/test_ospf6_topo1_vrf.py | 6 ++--- .../test_ospf_asbr_summary_topo1.py | 4 ++-- .../test_ospf_asbr_summary_type7_lsa.py | 2 +- .../test_ospf_authentication.py | 2 +- .../test_ospf_chaos.py | 2 +- .../test_ospf_ecmp.py | 4 ++-- .../test_ospf_flood_reduction.py | 5 +--- .../test_ospf_nssa.py | 2 +- .../test_ospf_p2mp.py | 2 +- .../test_ospf_routemaps.py | 2 +- .../test_ospf_rte_calc.py | 6 ++--- .../test_ospf_single_area.py | 2 +- .../ospf_dual_stack/test_ospf_dual_stack.py | 2 +- .../ospf_gr_helper/test_ospf_gr_helper1.py | 2 -- .../ospf_gr_helper/test_ospf_gr_helper3.py | 2 -- .../ospf_gr_topo1/test_ospf_gr_topo1.py | 2 +- .../test_ospf_instance_redistribute.py | 1 - .../test_ospf_metric_propagation.py | 5 ++-- .../test_ospf_multi_vrf_bgp_route_leak.py | 4 ++-- .../ospf_netns_vrf/test_ospf_netns_vrf.py | 4 ++-- .../ospf_nssa_topo1/test_ospf_nssa_topo1.py | 2 +- .../ospf_p2mp/test_ospf_p2mp_broadcast.py | 9 ++----- .../ospf_p2mp/test_ospf_p2mp_non_broadcast.py | 8 ++----- .../test_ospf_prefix_suppression.py | 9 ++----- .../test_ospf_single_switch.py | 5 ++-- .../ospf_sr_te_topo1/test_ospf_sr_te_topo1.py | 2 +- .../ospf_sr_topo1/test_ospf_sr_topo1.py | 2 +- .../ospf_suppress_fa/test_ospf_suppress_fa.py | 1 - .../ospf_tilfa_topo1/test_ospf_tilfa_topo1.py | 2 +- tests/topotests/ospf_topo1/test_ospf_topo1.py | 2 +- tests/topotests/ospf_topo2/test_ospf_topo2.py | 2 +- .../ospf_unnumbered/test_ospf_unnumbered.py | 2 +- ...est_ospf_unnumbered_point_to_multipoint.py | 2 +- .../topotests/ospfapi/test_ospf_clientapi.py | 4 +--- .../test_ospfv3_asbr_summary_topo1.py | 6 ++--- .../test_ospfv3_authentication.py | 11 +++------ .../test_ospfv3_ecmp.py | 4 ++-- .../test_ospfv3_ecmp_lan.py | 15 +----------- .../test_ospfv3_nssa.py | 2 +- .../test_ospfv3_nssa2.py | 14 ----------- .../test_ospfv3_routemaps.py | 2 +- .../test_ospfv3_rte_calc.py | 3 +-- .../test_ospfv3_single_area.py | 3 +-- tests/topotests/pim_acl/test_pim_acl.py | 2 +- tests/topotests/pim_basic/test_pim.py | 2 +- tests/topotests/pim_igmp_vrf/test_pim_vrf.py | 4 ++-- .../rip_allow_ecmp/test_rip_allow_ecmp.py | 4 ++-- .../rip_bfd_topo1/test_rip_bfd_topo1.py | 1 - .../test_rip_passive_interface.py | 4 ++-- .../ripng_allow_ecmp/test_ripng_allow_ecmp.py | 4 ++-- .../ripng_route_map/test_ripng_route_map.py | 5 ++-- .../route_scale/scale_test_common.py | 1 - .../route_scale/test_route_scale1.py | 6 ----- .../route_scale/test_route_scale2.py | 6 ----- .../simple_snmp_test/test_simple_snmp.py | 2 +- .../test_srv6_encap_src_addr.py | 3 +-- .../srv6_locator/test_srv6_locator.py | 6 ++--- .../test_srv6_locator_custom_bits_length.py | 6 ++--- .../test_srv6_locator_usid.py | 6 ++--- .../srv6_static_route/test_srv6_route.py | 4 ++-- .../test_static_routing_mpls.py | 5 +--- .../test_static_routes_topo2_ebgp.py | 2 +- .../test_static_routes_topo3_ebgp.py | 2 +- .../test_static_routes_topo4_ebgp.py | 2 +- .../test_static_routes_topo1_ibgp.py | 2 +- .../test_static_routes_topo2_ibgp.py | 2 +- .../test_static_routes_topo3_ibgp.py | 2 +- .../test_static_routes_topo4_ibgp.py | 2 +- .../static_simple/test_static_simple.py | 8 +++---- .../test_zebra_multiple_connected.py | 4 +--- .../zebra_netlink/test_zebra_netlink.py | 4 +--- .../test_verify_nh_resolution.py | 2 -- .../zebra_opaque/test_zebra_opaque.py | 10 ++++---- tests/topotests/zebra_rib/test_zebra_rib.py | 4 ++-- .../zebra_seg6_route/test_zebra_seg6_route.py | 4 ++-- .../test_zebra_seg6local_route.py | 2 +- 131 files changed, 200 insertions(+), 348 deletions(-) diff --git a/tests/topotests/eigrp_topo1/test_eigrp_topo1.py b/tests/topotests/eigrp_topo1/test_eigrp_topo1.py index b3152f43bc..7ab1572dae 100644 --- a/tests/topotests/eigrp_topo1/test_eigrp_topo1.py +++ b/tests/topotests/eigrp_topo1/test_eigrp_topo1.py @@ -143,7 +143,6 @@ def test_zebra_ipv4_routingTable(): if tgen.routers_have_failure(): pytest.skip(tgen.errors) - failures = 0 router_list = tgen.routers().values() for router in router_list: output = router.vtysh_cmd("show ip route json", isjson=True) diff --git a/tests/topotests/evpn_type5_test_topo1/test_evpn_type5_topo1.py b/tests/topotests/evpn_type5_test_topo1/test_evpn_type5_topo1.py index 10d216ab1e..beb4de432e 100644 --- a/tests/topotests/evpn_type5_test_topo1/test_evpn_type5_topo1.py +++ b/tests/topotests/evpn_type5_test_topo1/test_evpn_type5_topo1.py @@ -22,7 +22,6 @@ import os import sys -import json import time import pytest import platform @@ -69,7 +68,7 @@ verify_attributes_for_evpn_routes, verify_evpn_routes, ) -from lib.topojson import build_topo_from_json, build_config_from_json +from lib.topojson import build_config_from_json pytestmark = [pytest.mark.bgpd, pytest.mark.staticd] diff --git a/tests/topotests/fpm_testing_topo1/test_fpm_topo1.py b/tests/topotests/fpm_testing_topo1/test_fpm_topo1.py index 22fc50b914..66cefcc2a0 100644 --- a/tests/topotests/fpm_testing_topo1/test_fpm_topo1.py +++ b/tests/topotests/fpm_testing_topo1/test_fpm_topo1.py @@ -14,7 +14,6 @@ """ import os -import re import sys import pytest import json @@ -28,7 +27,6 @@ # Import topogen and topotest helpers from lib import topotest from lib.topogen import Topogen, TopoRouter, get_topogen -from lib.topolog import logger pytestmark = [pytest.mark.fpm, pytest.mark.sharpd] diff --git a/tests/topotests/grpc_basic/test_basic_grpc.py b/tests/topotests/grpc_basic/test_basic_grpc.py index cf1c6d0ec7..5ff2894fd1 100644 --- a/tests/topotests/grpc_basic/test_basic_grpc.py +++ b/tests/topotests/grpc_basic/test_basic_grpc.py @@ -19,7 +19,6 @@ from lib.common_config import step from lib.micronet import commander from lib.topogen import Topogen, TopoRouter -from lib.topolog import logger from lib.topotest import json_cmp CWD = os.path.dirname(os.path.realpath(__file__)) @@ -60,7 +59,7 @@ def tgen(request): tgen.start_topology() router_list = tgen.routers() - for rname, router in router_list.items(): + for _, router in router_list.items(): router.load_config(TopoRouter.RD_ZEBRA, "zebra.conf", f"-M grpc:{GRPCP_ZEBRA}") router.load_config(TopoRouter.RD_STATIC, "", f"-M grpc:{GRPCP_STATICD}") # router.load_config(TopoRouter.RD_BFDD, "", f"-M grpc:{GRPCP_BFDD}") diff --git a/tests/topotests/isis_advertise_high_metrics/test_isis_advertise_high_metrics.py b/tests/topotests/isis_advertise_high_metrics/test_isis_advertise_high_metrics.py index ada8c0f5fb..ad896b7422 100644 --- a/tests/topotests/isis_advertise_high_metrics/test_isis_advertise_high_metrics.py +++ b/tests/topotests/isis_advertise_high_metrics/test_isis_advertise_high_metrics.py @@ -30,8 +30,6 @@ import sys import pytest import json -from time import sleep -from functools import partial # Save the Current Working Directory to find configuration files. CWD = os.path.dirname(os.path.realpath(__file__)) @@ -39,7 +37,6 @@ # pylint: disable=C0413 # Import topogen and topotest helpers -from lib import topotest from lib.common_config import ( retry, stop_router, diff --git a/tests/topotests/isis_lfa_topo1/test_isis_lfa_topo1.py b/tests/topotests/isis_lfa_topo1/test_isis_lfa_topo1.py index 44b3dd0b79..af28dbdf3c 100755 --- a/tests/topotests/isis_lfa_topo1/test_isis_lfa_topo1.py +++ b/tests/topotests/isis_lfa_topo1/test_isis_lfa_topo1.py @@ -42,7 +42,6 @@ import sys import pytest import json -import time import tempfile from functools import partial @@ -169,7 +168,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() @@ -832,7 +831,7 @@ def _rt2_neigh_down(router): rname = "rt1" router = tgen.gears[rname] test_func = partial(_rt2_neigh_down, router) - success, result = topotest.run_and_expect(test_func, None, count=200, wait=0.05) + _, result = topotest.run_and_expect(test_func, None, count=200, wait=0.05) assert result is None, 'rt2 neighbor is still present on "{}"'.format(router) router_compare_json_output( @@ -1034,7 +1033,7 @@ def _bfd_down(router): rname = "rt1" router = tgen.gears[rname] test_func = partial(_bfd_down, router) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.3) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.3) assert result is None, 'BFD session is still up on "{}"'.format(router) router_compare_json_output( diff --git a/tests/topotests/isis_lsp_bits_topo1/test_isis_lsp_bits_topo1.py b/tests/topotests/isis_lsp_bits_topo1/test_isis_lsp_bits_topo1.py index c4ce6a30cd..6f4653d2c2 100755 --- a/tests/topotests/isis_lsp_bits_topo1/test_isis_lsp_bits_topo1.py +++ b/tests/topotests/isis_lsp_bits_topo1/test_isis_lsp_bits_topo1.py @@ -131,7 +131,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() diff --git a/tests/topotests/isis_rlfa_topo1/test_isis_rlfa_topo1.py b/tests/topotests/isis_rlfa_topo1/test_isis_rlfa_topo1.py index 15327fe03a..f97c7d2c9c 100755 --- a/tests/topotests/isis_rlfa_topo1/test_isis_rlfa_topo1.py +++ b/tests/topotests/isis_rlfa_topo1/test_isis_rlfa_topo1.py @@ -170,7 +170,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() diff --git a/tests/topotests/isis_snmp/test_isis_snmp.py b/tests/topotests/isis_snmp/test_isis_snmp.py index ddef08008b..81c96b3daf 100755 --- a/tests/topotests/isis_snmp/test_isis_snmp.py +++ b/tests/topotests/isis_snmp/test_isis_snmp.py @@ -147,7 +147,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() diff --git a/tests/topotests/isis_sr_flex_algo_topo1/test_isis_sr_flex_algo_topo1.py b/tests/topotests/isis_sr_flex_algo_topo1/test_isis_sr_flex_algo_topo1.py index c81f63942b..d1fc68291e 100755 --- a/tests/topotests/isis_sr_flex_algo_topo1/test_isis_sr_flex_algo_topo1.py +++ b/tests/topotests/isis_sr_flex_algo_topo1/test_isis_sr_flex_algo_topo1.py @@ -37,7 +37,6 @@ import sys import pytest import json -import tempfile from copy import deepcopy from functools import partial @@ -121,7 +120,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() tgen.stop_topology() diff --git a/tests/topotests/isis_sr_flex_algo_topo2/test_isis_sr_flex_algo_topo2.py b/tests/topotests/isis_sr_flex_algo_topo2/test_isis_sr_flex_algo_topo2.py index 6689cf4c5e..7d063910d0 100755 --- a/tests/topotests/isis_sr_flex_algo_topo2/test_isis_sr_flex_algo_topo2.py +++ b/tests/topotests/isis_sr_flex_algo_topo2/test_isis_sr_flex_algo_topo2.py @@ -47,7 +47,6 @@ import sys import pytest import json -import time from functools import partial # Save the Current Working Directory to find configuration files. @@ -67,7 +66,6 @@ def build_topo(tgen): "Build function" - routers = [] for i in range(0, 10): rt = tgen.add_router("rt{}".format(i)) rt.run("sysctl -w net.ipv4.fib_multipath_hash_policy=1") @@ -140,7 +138,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() tgen.stop_topology() @@ -174,7 +172,7 @@ def _check(name, cmd, expected_file): logger.info('[+] check {} "{}" {}'.format(name, cmd, expected_file)) tgen = get_topogen() func = partial(_check, name, cmd, expected_file) - success, result = topotest.run_and_expect(func, None, count=120, wait=0.5) + _, result = topotest.run_and_expect(func, None, count=120, wait=0.5) assert result is None, "Failed" diff --git a/tests/topotests/isis_sr_te_topo1/test_isis_sr_te_topo1.py b/tests/topotests/isis_sr_te_topo1/test_isis_sr_te_topo1.py index fc2ce7cb4b..cb4f4ffa56 100755 --- a/tests/topotests/isis_sr_te_topo1/test_isis_sr_te_topo1.py +++ b/tests/topotests/isis_sr_te_topo1/test_isis_sr_te_topo1.py @@ -164,7 +164,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() @@ -641,7 +641,7 @@ def test_srte_route_map_with_sr_policy_check_nextop_step5(): ) # (re-)build the SR Policy two times to ensure that reinstalling still works - for i in [1, 2]: + for _ in [1, 2]: cmp_json_output( "rt1", "show ip route bgp json", "step5/show_ip_route_bgp_inactive_srte.ref" ) diff --git a/tests/topotests/isis_sr_topo1/test_isis_sr_topo1.py b/tests/topotests/isis_sr_topo1/test_isis_sr_topo1.py index 9a4085ab55..baf7e98ba1 100644 --- a/tests/topotests/isis_sr_topo1/test_isis_sr_topo1.py +++ b/tests/topotests/isis_sr_topo1/test_isis_sr_topo1.py @@ -137,7 +137,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() diff --git a/tests/topotests/isis_srv6_topo1/test_isis_srv6_topo1.py b/tests/topotests/isis_srv6_topo1/test_isis_srv6_topo1.py index 1a7505dd12..9c1a23f54f 100644 --- a/tests/topotests/isis_srv6_topo1/test_isis_srv6_topo1.py +++ b/tests/topotests/isis_srv6_topo1/test_isis_srv6_topo1.py @@ -60,7 +60,6 @@ """ import os -import re import sys import json import functools @@ -212,7 +211,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" # Teardown the topology @@ -250,7 +249,7 @@ def _check(name, dest_addr, match): logger.info("[+] check {} {} {}".format(name, dest_addr, match)) tgen = get_topogen() func = functools.partial(_check, name, dest_addr, match) - success, result = topotest.run_and_expect(func, None, count=10, wait=1) + _, result = topotest.run_and_expect(func, None, count=10, wait=1) assert result is None, "Failed" diff --git a/tests/topotests/isis_tilfa_topo1/test_isis_tilfa_topo1.py b/tests/topotests/isis_tilfa_topo1/test_isis_tilfa_topo1.py index aaf6af0be4..c8e66befa5 100755 --- a/tests/topotests/isis_tilfa_topo1/test_isis_tilfa_topo1.py +++ b/tests/topotests/isis_tilfa_topo1/test_isis_tilfa_topo1.py @@ -54,7 +54,6 @@ import sys import pytest import json -import tempfile from functools import partial from time import sleep @@ -144,7 +143,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() diff --git a/tests/topotests/isis_topo1/test_isis_topo1.py b/tests/topotests/isis_topo1/test_isis_topo1.py index b388f52bd9..cea284963d 100644 --- a/tests/topotests/isis_topo1/test_isis_topo1.py +++ b/tests/topotests/isis_topo1/test_isis_topo1.py @@ -104,7 +104,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() @@ -160,7 +160,7 @@ def compare_isis_installed_routes(router, expected): return topotest.json_cmp(actual, expected) test_func = functools.partial(compare_isis_installed_routes, router, expected) - (result, diff) = topotest.run_and_expect(test_func, None, wait=1, count=10) + (result, _) = topotest.run_and_expect(test_func, None, wait=1, count=10) assertmsg = "Router '{}' routes mismatch".format(rname) assert result, assertmsg @@ -205,7 +205,7 @@ def compare_isis_v6_installed_routes(router, expected): test_func = functools.partial( compare_isis_v6_installed_routes, router, expected ) - (result, diff) = topotest.run_and_expect(test_func, None, wait=1, count=10) + (result, _) = topotest.run_and_expect(test_func, None, wait=1, count=10) assertmsg = "Router '{}' routes mismatch".format(rname) assert result, assertmsg @@ -237,7 +237,7 @@ def test_isis_summary_json(): pytest.skip(tgen.errors) logger.info("Checking 'show isis summary json'") - for rname, router in tgen.routers().items(): + for rname, _ in tgen.routers().items(): logger.info("Checking router %s", rname) json_output = tgen.gears[rname].vtysh_cmd("show isis summary json", isjson=True) assertmsg = "Test isis summary json failed in '{}' data '{}'".format( @@ -257,7 +257,7 @@ def test_isis_interface_json(): pytest.skip(tgen.errors) logger.info("Checking 'show isis interface json'") - for rname, router in tgen.routers().items(): + for rname, _ in tgen.routers().items(): logger.info("Checking router %s", rname) json_output = tgen.gears[rname].vtysh_cmd( "show isis interface json", isjson=True @@ -294,7 +294,7 @@ def test_isis_neighbor_json(): # tgen.mininet_cli() logger.info("Checking 'show isis neighbor json'") - for rname, router in tgen.routers().items(): + for rname, _ in tgen.routers().items(): logger.info("Checking router %s", rname) json_output = tgen.gears[rname].vtysh_cmd( "show isis neighbor json", isjson=True @@ -330,7 +330,7 @@ def test_isis_database_json(): # tgen.mininet_cli() logger.info("Checking 'show isis database json'") - for rname, router in tgen.routers().items(): + for rname, _ in tgen.routers().items(): logger.info("Checking router %s", rname) json_output = tgen.gears[rname].vtysh_cmd( "show isis database json", isjson=True @@ -755,7 +755,7 @@ def dict_merge(dct, merge_dct): Source: https://gist.github.com/angstwad/bf22d1822c38a92ec0a9 """ - for k, v in merge_dct.items(): + for k, _ in merge_dct.items(): if k in dct and isinstance(dct[k], dict) and topotest.is_mapping(merge_dct[k]): dict_merge(dct[k], merge_dct[k]) else: diff --git a/tests/topotests/isis_topo1_vrf/test_isis_topo1_vrf.py b/tests/topotests/isis_topo1_vrf/test_isis_topo1_vrf.py index 032319c446..7aac7c704d 100644 --- a/tests/topotests/isis_topo1_vrf/test_isis_topo1_vrf.py +++ b/tests/topotests/isis_topo1_vrf/test_isis_topo1_vrf.py @@ -118,7 +118,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() # move back rx-eth0 to default VRF @@ -287,7 +287,7 @@ def dict_merge(dct, merge_dct): Source: https://gist.github.com/angstwad/bf22d1822c38a92ec0a9 """ - for k, v in merge_dct.items(): + for k, _ in merge_dct.items(): if k in dct and isinstance(dct[k], dict) and topotest.is_mapping(merge_dct[k]): dict_merge(dct[k], merge_dct[k]) else: diff --git a/tests/topotests/key_sendaccept/test_keychain.py b/tests/topotests/key_sendaccept/test_keychain.py index b11d31b981..1d24c17004 100644 --- a/tests/topotests/key_sendaccept/test_keychain.py +++ b/tests/topotests/key_sendaccept/test_keychain.py @@ -27,7 +27,7 @@ def tgen(request): tgen.start_topology() router_list = tgen.routers() - for rname, router in router_list.items(): + for _, router in router_list.items(): router.load_frr_config("frr.conf") tgen.start_router() diff --git a/tests/topotests/ldp_oc_acl_topo1/test_ldp_oc_acl_topo1.py b/tests/topotests/ldp_oc_acl_topo1/test_ldp_oc_acl_topo1.py index c2bcaa84ce..8123e04982 100644 --- a/tests/topotests/ldp_oc_acl_topo1/test_ldp_oc_acl_topo1.py +++ b/tests/topotests/ldp_oc_acl_topo1/test_ldp_oc_acl_topo1.py @@ -117,7 +117,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() diff --git a/tests/topotests/ldp_oc_topo1/test_ldp_oc_topo1.py b/tests/topotests/ldp_oc_topo1/test_ldp_oc_topo1.py index 387fd89c20..bfb93d5588 100644 --- a/tests/topotests/ldp_oc_topo1/test_ldp_oc_topo1.py +++ b/tests/topotests/ldp_oc_topo1/test_ldp_oc_topo1.py @@ -116,7 +116,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() diff --git a/tests/topotests/ldp_snmp/test_ldp_snmp_topo1.py b/tests/topotests/ldp_snmp/test_ldp_snmp_topo1.py index 52a67d8bb8..ea404beae4 100644 --- a/tests/topotests/ldp_snmp/test_ldp_snmp_topo1.py +++ b/tests/topotests/ldp_snmp/test_ldp_snmp_topo1.py @@ -136,7 +136,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() diff --git a/tests/topotests/ldp_sync_isis_topo1/test_ldp_sync_isis_topo1.py b/tests/topotests/ldp_sync_isis_topo1/test_ldp_sync_isis_topo1.py index cb6b784d6d..f2c41ebe30 100644 --- a/tests/topotests/ldp_sync_isis_topo1/test_ldp_sync_isis_topo1.py +++ b/tests/topotests/ldp_sync_isis_topo1/test_ldp_sync_isis_topo1.py @@ -129,7 +129,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() diff --git a/tests/topotests/ldp_sync_ospf_topo1/test_ldp_sync_ospf_topo1.py b/tests/topotests/ldp_sync_ospf_topo1/test_ldp_sync_ospf_topo1.py index 760b4e3df5..9e41e06c6a 100644 --- a/tests/topotests/ldp_sync_ospf_topo1/test_ldp_sync_ospf_topo1.py +++ b/tests/topotests/ldp_sync_ospf_topo1/test_ldp_sync_ospf_topo1.py @@ -128,7 +128,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() diff --git a/tests/topotests/ldp_vpls_topo1/test_ldp_vpls_topo1.py b/tests/topotests/ldp_vpls_topo1/test_ldp_vpls_topo1.py index 1f4a4b5fd5..c14c79e6d4 100644 --- a/tests/topotests/ldp_vpls_topo1/test_ldp_vpls_topo1.py +++ b/tests/topotests/ldp_vpls_topo1/test_ldp_vpls_topo1.py @@ -129,7 +129,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() diff --git a/tests/topotests/lib/bgp.py b/tests/topotests/lib/bgp.py index 3a16ed5a09..4250c405f3 100644 --- a/tests/topotests/lib/bgp.py +++ b/tests/topotests/lib/bgp.py @@ -333,7 +333,7 @@ def __create_bgp_global(tgen, input_dict, router, build=False): else: del_action = False - for rs_timer, value in timer.items(): + for rs_timer, _ in timer.items(): rs_timer_value = timer.setdefault(rs_timer, None) if rs_timer_value and rs_timer != "delete": @@ -1229,7 +1229,7 @@ def modify_bgp_config_when_bgpd_down(tgen, topo, input_dict): # Copy bgp config file to /etc/frr for dut in input_dict.keys(): router_list = tgen.routers() - for router, rnode in router_list.items(): + for router, _ in router_list.items(): if router != dut: continue @@ -1750,7 +1750,7 @@ def verify_as_numbers(tgen, topo, input_dict, expected=True): for bgp_neighbor, peer_data in bgp_neighbors.items(): remote_as = input_dict[bgp_neighbor]["bgp"]["local_as"] - for dest_link, peer_dict in peer_data["dest_link"].items(): + for dest_link, _ in peer_data["dest_link"].items(): neighbor_ip = None data = topo["routers"][bgp_neighbor]["links"] @@ -1833,7 +1833,7 @@ def verify_bgp_convergence_from_running_config(tgen, dut=None, expected=True): return errormsg for vrf, addr_family_data in show_bgp_json.items(): - for address_family, neighborship_data in addr_family_data.items(): + for _, neighborship_data in addr_family_data.items(): total_peer = 0 no_of_peer = 0 @@ -1980,7 +1980,7 @@ def clear_bgp_and_verify(tgen, topo, router, rid=None): bgp_neighbors = bgp_addr_type[addr_type]["unicast"]["neighbor"] for bgp_neighbor, peer_data in bgp_neighbors.items(): - for dest_link, peer_dict in peer_data["dest_link"].items(): + for dest_link, _ in peer_data["dest_link"].items(): data = topo["routers"][bgp_neighbor]["links"] if dest_link in data: @@ -3231,7 +3231,7 @@ def verify_graceful_restart( if bgp_neighbor != peer: continue - for dest_link, peer_dict in peer_data["dest_link"].items(): + for dest_link, _ in peer_data["dest_link"].items(): data = topo["routers"][bgp_neighbor]["links"] if dest_link in data: @@ -3479,7 +3479,7 @@ def verify_r_bit(tgen, topo, addr_type, input_dict, dut, peer, expected=True): if bgp_neighbor != peer: continue - for dest_link, peer_dict in peer_data["dest_link"].items(): + for dest_link, _ in peer_data["dest_link"].items(): data = topo["routers"][bgp_neighbor]["links"] if dest_link in data: @@ -3597,7 +3597,7 @@ def verify_eor(tgen, topo, addr_type, input_dict, dut, peer, expected=True): if bgp_neighbor != peer: continue - for dest_link, peer_dict in peer_data["dest_link"].items(): + for dest_link, _ in peer_data["dest_link"].items(): data = topo["routers"][bgp_neighbor]["links"] if dest_link in data: @@ -3762,7 +3762,7 @@ def verify_f_bit(tgen, topo, addr_type, input_dict, dut, peer, expected=True): if bgp_neighbor != peer: continue - for dest_link, peer_dict in peer_data["dest_link"].items(): + for dest_link, _ in peer_data["dest_link"].items(): data = topo["routers"][bgp_neighbor]["links"] if dest_link in data: @@ -3890,7 +3890,7 @@ def verify_graceful_restart_timers(tgen, topo, addr_type, input_dict, dut, peer) if bgp_neighbor != peer: continue - for dest_link, peer_dict in peer_data["dest_link"].items(): + for dest_link, _ in peer_data["dest_link"].items(): data = topo["routers"][bgp_neighbor]["links"] if dest_link in data: diff --git a/tests/topotests/lib/checkping.py b/tests/topotests/lib/checkping.py index 5500807fab..aa95f45b29 100644 --- a/tests/topotests/lib/checkping.py +++ b/tests/topotests/lib/checkping.py @@ -33,5 +33,5 @@ def _check(name, dest_addr, source_addr, match): logger.info("[+] check {} {} {}".format(name, dest_addr, match)) tgen = get_topogen() func = functools.partial(_check, name, dest_addr, source_addr, match) - success, result = topotest.run_and_expect(func, None, count=count, wait=wait) + _, result = topotest.run_and_expect(func, None, count=count, wait=wait) assert result is None, "Failed" diff --git a/tests/topotests/lib/common_config.py b/tests/topotests/lib/common_config.py index 7787b6f74b..e856c23d36 100644 --- a/tests/topotests/lib/common_config.py +++ b/tests/topotests/lib/common_config.py @@ -7,7 +7,6 @@ import functools import ipaddress -import json import os import platform import socket @@ -442,7 +441,7 @@ def check_router_status(tgen): try: router_list = tgen.routers() - for router, rnode in router_list.items(): + for _, rnode in router_list.items(): result = rnode.check_router_running() if result != "": daemons = [] @@ -686,7 +685,7 @@ def prep_load_config_to_routers(tgen, *config_name_list): """ routers = tgen.routers() - for rname, router in routers.items(): + for rname, _ in routers.items(): destname = "{}/{}/{}".format(tgen.logdir, rname, FRRCFG_FILE) wmode = "w" for cfbase in config_name_list: @@ -871,7 +870,7 @@ def get_frr_ipv6_linklocal(tgen, router, intf=None, vrf=None): """ router_list = tgen.routers() - for rname, rnode in router_list.items(): + for rname, _ in router_list.items(): if rname != router: continue @@ -887,7 +886,7 @@ def get_frr_ipv6_linklocal(tgen, router, intf=None, vrf=None): cmd = "show interface vrf {}".format(vrf) else: cmd = "show interface" - for chk_ll in range(0, 60): + for _ in range(0, 60): sleep(1 / 4) ifaces = router_list[router].run('vtysh -c "{}"'.format(cmd)) # Fix newlines (make them all the same) @@ -3095,7 +3094,7 @@ def configure_brctl(tgen, topo, input_dict): "{} dev {} master {}".format(ip_cmd, brctl_name, vrf) ) - for intf_name, data in topo["routers"][dut]["links"].items(): + for _, data in topo["routers"][dut]["links"].items(): if "vrf" not in data: continue @@ -4942,7 +4941,7 @@ def scapy_send_raw_packet(tgen, topo, senderRouter, intf, packet=None): sender_interface = intf rnode = tgen.routers()[senderRouter] - for destLink, data in topo["routers"][senderRouter]["links"].items(): + for _, data in topo["routers"][senderRouter]["links"].items(): if "type" in data and data["type"] == "loopback": continue diff --git a/tests/topotests/lib/fe_client.py b/tests/topotests/lib/fe_client.py index d61bc850b4..784f7d17eb 100755 --- a/tests/topotests/lib/fe_client.py +++ b/tests/topotests/lib/fe_client.py @@ -9,7 +9,6 @@ # noqa: E501 # import argparse -import json import logging import os import socket @@ -216,7 +215,7 @@ def __init__(self, sock, use_protobuf): self.sess_id = reply.session_reply.session_id else: self.sess_id = 0 - mdata, req_id = self.get_native_msg_header(MSG_CODE_SESSION_REQ) + mdata, _ = self.get_native_msg_header(MSG_CODE_SESSION_REQ) mdata += struct.pack(MSG_SESSION_REQ_FMT) mdata += "test-client".encode("utf-8") + b"\x00" @@ -324,7 +323,7 @@ def lock(self, lock=True, ds_id=mgmt_pb2.CANDIDATE_DS): def get_data(self, query, data=True, config=False): # Create the message - mdata, req_id = self.get_native_msg_header(MSG_CODE_GET_DATA) + mdata, _ = self.get_native_msg_header(MSG_CODE_GET_DATA) flags = GET_DATA_FLAG_STATE if data else 0 flags |= GET_DATA_FLAG_CONFIG if config else 0 mdata += struct.pack(MSG_GET_DATA_FMT, MSG_FORMAT_JSON, flags) @@ -333,7 +332,7 @@ def get_data(self, query, data=True, config=False): self.send_native_msg(mdata) logging.debug("Sent GET-TREE") - mhdr, mfixed, mdata = self.recv_native_msg() + _, mfixed, mdata = self.recv_native_msg() assert mdata[-1] == 0 result = mdata[:-1].decode("utf-8") @@ -342,7 +341,7 @@ def get_data(self, query, data=True, config=False): def add_notify_select(self, replace, notif_xpaths): # Create the message - mdata, req_id = self.get_native_msg_header(MSG_CODE_NOTIFY_SELECT) + mdata, _ = self.get_native_msg_header(MSG_CODE_NOTIFY_SELECT) mdata += struct.pack(MSG_NOTIFY_SELECT_FMT, replace) for xpath in notif_xpaths: @@ -355,7 +354,7 @@ def recv_notify(self, xpaths=None): if xpaths: self.add_notify_select(True, xpaths) - for remaining in Timeout(60): + for _ in Timeout(60): logging.debug("Waiting for Notify Message") mhdr, mfixed, mdata = self.recv_native_msg() if mhdr[HDR_FIELD_CODE] == MSG_CODE_NOTIFY: diff --git a/tests/topotests/lib/ospf.py b/tests/topotests/lib/ospf.py index 5b18f8b679..2c876e1989 100644 --- a/tests/topotests/lib/ospf.py +++ b/tests/topotests/lib/ospf.py @@ -1545,7 +1545,7 @@ def verify_ospf_database( ) return errormsg if ospf_external_lsa: - for ospf_ext_lsa, ext_lsa_data in ospf_external_lsa.items(): + for ospf_ext_lsa, _ in ospf_external_lsa.items(): if ospf_ext_lsa in show_ospf_json["AS External Link States"]: logger.info( "[DUT: %s] OSPF LSDB:External LSA %s", router, ospf_ext_lsa @@ -2509,7 +2509,7 @@ def verify_ospf_gr_helper(tgen, topo, dut, input_dict=None): raise ValueError(errormsg) return errormsg - for ospf_gr, gr_data in input_dict.items(): + for ospf_gr, _ in input_dict.items(): try: if input_dict[ospf_gr] == show_ospf_json[ospf_gr]: logger.info( diff --git a/tests/topotests/lib/pim.py b/tests/topotests/lib/pim.py index f7440efd6d..cc56ffdd8c 100644 --- a/tests/topotests/lib/pim.py +++ b/tests/topotests/lib/pim.py @@ -149,7 +149,7 @@ def _add_pim_rp_config(tgen, topo, input_dict, router, build, config_data_dict): # At least one interface must be enabled for PIM on the router pim_if_enabled = False pim6_if_enabled = False - for destLink, data in topo[dut]["links"].items(): + for _, data in topo[dut]["links"].items(): if "pim" in data: pim_if_enabled = True if "pim6" in data: @@ -603,7 +603,7 @@ def find_rp_details(tgen, topo): # ip address of RP rp_addr = rp_dict["rp_addr"] - for link, data in topo["routers"][router]["links"].items(): + for _, data in topo["routers"][router]["links"].items(): if data["ipv4"].split("/")[0] == rp_addr: rp_details[router] = rp_addr @@ -2089,7 +2089,7 @@ def verify_pim_interface( ) return True else: - for destLink, data in topo["routers"][dut]["links"].items(): + for _, data in topo["routers"][dut]["links"].items(): if "type" in data and data["type"] == "loopback": continue @@ -2292,7 +2292,7 @@ def clear_pim_interfaces(tgen, dut): # Waiting for maximum 60 sec fail_intf = [] - for retry in range(1, 13): + for _ in range(1, 13): sleep(5) logger.info("[DUT: %s]: Waiting for 5 sec for PIM neighbors" " to come up", dut) run_json_after = run_frr_cmd(rnode, "show ip pim neighbor json", isjson=True) @@ -2368,7 +2368,7 @@ def clear_igmp_interfaces(tgen, dut): total_groups_before_clear = igmp_json["totalGroups"] - for key, value in igmp_json.items(): + for _, value in igmp_json.items(): if type(value) is not dict: continue @@ -2381,7 +2381,7 @@ def clear_igmp_interfaces(tgen, dut): result = run_frr_cmd(rnode, "clear ip igmp interfaces") # Waiting for maximum 60 sec - for retry in range(1, 13): + for _ in range(1, 13): logger.info( "[DUT: %s]: Waiting for 5 sec for igmp interfaces" " to come up", dut ) @@ -2460,7 +2460,7 @@ def clear_mroute_verify(tgen, dut, expected=True): # RFC 3376: 8.2. Query Interval - Default: 125 seconds # So waiting for maximum 130 sec to get the igmp report - for retry in range(1, 26): + for _ in range(1, 26): logger.info("[DUT: %s]: Waiting for 2 sec for mroutes" " to come up", dut) sleep(5) keys_json1 = mroute_json_1.keys() @@ -2671,7 +2671,7 @@ def add_rp_interfaces_and_pim_config(tgen, topo, interface, rp, rp_mapping): try: config_data = [] - for group, rp_list in rp_mapping.items(): + for _, rp_list in rp_mapping.items(): for _rp in rp_list: config_data.append("interface {}".format(interface)) config_data.append("ip address {}".format(_rp)) @@ -2720,7 +2720,7 @@ def scapy_send_bsr_raw_packet(tgen, topo, senderRouter, receiverRouter, packet=N script_path = os.path.join(CWD, "send_bsr_packet.py") node = tgen.net[senderRouter] - for destLink, data in topo["routers"][senderRouter]["links"].items(): + for _, data in topo["routers"][senderRouter]["links"].items(): if "type" in data and data["type"] == "loopback": continue @@ -2795,12 +2795,12 @@ def find_rp_from_bsrp_info(tgen, dut, bsr, grp=None): # RP with lowest priority if len(priority_dict) != 1: - rp_p, lowest_priority = sorted(rp_priority.items(), key=lambda x: x[1])[0] + rp_p, _ = sorted(rp_priority.items(), key=lambda x: x[1])[0] rp_details[group] = rp_p # RP with highest hash value if len(priority_dict) == 1: - rp_h, highest_hash = sorted(rp_hash.items(), key=lambda x: x[1])[-1] + rp_h, _ = sorted(rp_hash.items(), key=lambda x: x[1])[-1] rp_details[group] = rp_h # RP with highest IP address @@ -3239,7 +3239,7 @@ def verify_pim_join( interface_json = show_pim_join_json[interface] grp_addr = grp_addr.split("/")[0] - for source, data in interface_json[grp_addr].items(): + for _, data in interface_json[grp_addr].items(): # Verify pim join if pim_join: if data["group"] == grp_addr and data["channelJoinName"] == "JOIN": diff --git a/tests/topotests/mgmt_debug_flags/test_debug.py b/tests/topotests/mgmt_debug_flags/test_debug.py index e49d9b7beb..fe659e54ca 100644 --- a/tests/topotests/mgmt_debug_flags/test_debug.py +++ b/tests/topotests/mgmt_debug_flags/test_debug.py @@ -27,7 +27,7 @@ def tgen(request): tgen = Topogen(topodef, request.module.__name__) tgen.start_topology() - for rname, router in tgen.routers().items(): + for _, router in tgen.routers().items(): router.load_frr_config("frr.conf") tgen.start_router() diff --git a/tests/topotests/mgmt_notif/test_notif.py b/tests/topotests/mgmt_notif/test_notif.py index 01466892a8..e5286faae2 100644 --- a/tests/topotests/mgmt_notif/test_notif.py +++ b/tests/topotests/mgmt_notif/test_notif.py @@ -10,7 +10,6 @@ Test YANG Notifications """ import json -import logging import os import pytest @@ -35,7 +34,7 @@ def tgen(request): tgen.start_topology() router_list = tgen.routers() - for rname, router in router_list.items(): + for _, router in router_list.items(): router.load_frr_config("frr.conf") tgen.start_router() diff --git a/tests/topotests/mgmt_oper/oper.py b/tests/topotests/mgmt_oper/oper.py index 162c1eb5cc..934093aeee 100644 --- a/tests/topotests/mgmt_oper/oper.py +++ b/tests/topotests/mgmt_oper/oper.py @@ -146,7 +146,7 @@ def check_kernel(r1, super_prefix, count, add, is_blackhole, vrf, matchvia): # logger.debug("checking kernel routing table%s:\n%s", vrfstr, kernel) - for i, net in enumerate(get_ip_networks(super_prefix, count)): + for _, net in enumerate(get_ip_networks(super_prefix, count)): if not add: assert str(net) not in kernel continue @@ -233,7 +233,7 @@ def do_config( if vrf: f.write("vrf {}\n".format(vrf)) - for i, net in enumerate(get_ip_networks(super_prefix, count)): + for _, net in enumerate(get_ip_networks(super_prefix, count)): if add: f.write("ip route {} {}\n".format(net, via)) else: diff --git a/tests/topotests/mgmt_oper/test_oper.py b/tests/topotests/mgmt_oper/test_oper.py index 8b8a51c29e..e4ceabf352 100644 --- a/tests/topotests/mgmt_oper/test_oper.py +++ b/tests/topotests/mgmt_oper/test_oper.py @@ -12,17 +12,11 @@ import ipaddress import math -import time import pytest from lib.topogen import Topogen from oper import check_kernel_32, do_oper_test -try: - from deepdiff import DeepDiff as dd_json_cmp -except ImportError: - dd_json_cmp = None - pytestmark = [pytest.mark.staticd, pytest.mark.mgmtd] diff --git a/tests/topotests/mgmt_rpc/test_rpc.py b/tests/topotests/mgmt_rpc/test_rpc.py index 618d9022ce..839db97379 100644 --- a/tests/topotests/mgmt_rpc/test_rpc.py +++ b/tests/topotests/mgmt_rpc/test_rpc.py @@ -32,7 +32,7 @@ def tgen(request): tgen.start_topology() router_list = tgen.routers() - for rname, router in router_list.items(): + for _, router in router_list.items(): router.load_frr_config("frr.conf") tgen.start_router() diff --git a/tests/topotests/mgmt_tests/test_yang_mgmt.py b/tests/topotests/mgmt_tests/test_yang_mgmt.py index 605c14285f..52f6ba4db7 100644 --- a/tests/topotests/mgmt_tests/test_yang_mgmt.py +++ b/tests/topotests/mgmt_tests/test_yang_mgmt.py @@ -66,7 +66,6 @@ start_router_daemons, ) from lib.topolog import logger -from lib.bgp import verify_bgp_convergence, create_router_bgp, verify_bgp_rib from lib.topojson import build_config_from_json pytestmark = [pytest.mark.bgpd, pytest.mark.staticd, pytest.mark.mgmtd] diff --git a/tests/topotests/msdp_topo1/test_msdp_topo1.py b/tests/topotests/msdp_topo1/test_msdp_topo1.py index 1af58b0a01..08c37617cf 100755 --- a/tests/topotests/msdp_topo1/test_msdp_topo1.py +++ b/tests/topotests/msdp_topo1/test_msdp_topo1.py @@ -101,7 +101,7 @@ def setup_module(mod): app_helper.init(tgen) -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() app_helper.cleanup() diff --git a/tests/topotests/multicast_pim6_sm_topo1/test_multicast_pim6_sm1.py b/tests/topotests/multicast_pim6_sm_topo1/test_multicast_pim6_sm1.py index 7eb5838037..b8eb67a32e 100644 --- a/tests/topotests/multicast_pim6_sm_topo1/test_multicast_pim6_sm1.py +++ b/tests/topotests/multicast_pim6_sm_topo1/test_multicast_pim6_sm1.py @@ -221,7 +221,7 @@ def verify_state_incremented(state_before, state_after): """ for router, state_data in state_before.items(): - for state, value in state_data.items(): + for state, _ in state_data.items(): if state_before[router][state] >= state_after[router][state]: errormsg = ( "[DUT: %s]: state %s value has not" diff --git a/tests/topotests/multicast_pim6_sm_topo1/test_multicast_pim6_sm2.py b/tests/topotests/multicast_pim6_sm_topo1/test_multicast_pim6_sm2.py index 8b174bf9b8..bab7fddf9e 100644 --- a/tests/topotests/multicast_pim6_sm_topo1/test_multicast_pim6_sm2.py +++ b/tests/topotests/multicast_pim6_sm_topo1/test_multicast_pim6_sm2.py @@ -175,7 +175,7 @@ def verify_state_incremented(state_before, state_after): """ for router, state_data in state_before.items(): - for state, value in state_data.items(): + for state, _ in state_data.items(): if state_before[router][state] >= state_after[router][state]: errormsg = ( "[DUT: %s]: state %s value has not" diff --git a/tests/topotests/multicast_pim_dr_nondr_test/test_pim_dr_nondr_with_ospf_topo2.py b/tests/topotests/multicast_pim_dr_nondr_test/test_pim_dr_nondr_with_ospf_topo2.py index 00d38fe647..5aa2ea65f7 100755 --- a/tests/topotests/multicast_pim_dr_nondr_test/test_pim_dr_nondr_with_ospf_topo2.py +++ b/tests/topotests/multicast_pim_dr_nondr_test/test_pim_dr_nondr_with_ospf_topo2.py @@ -20,10 +20,7 @@ import os import sys -import json import time -import datetime -from time import sleep import pytest # Save the Current Working Directory to find configuration files. @@ -43,14 +40,9 @@ write_test_footer, step, reset_config_on_routers, - shutdown_bringup_interface, apply_raw_config, add_interfaces_to_vlan, - kill_router_daemons, - start_router_daemons, - create_static_routes, check_router_status, - topo_daemons, required_linux_kernel_version, ) from lib.pim import ( @@ -59,9 +51,6 @@ verify_mroutes, clear_mroute, clear_pim_interface_traffic, - verify_pim_config, - verify_upstream_iif, - verify_multicast_traffic, verify_multicast_flag_state, verify_igmp_groups, McastTesterHelper, diff --git a/tests/topotests/multicast_pim_sm_topo1/test_multicast_pim_sm_topo1.py b/tests/topotests/multicast_pim_sm_topo1/test_multicast_pim_sm_topo1.py index f87a90d198..eefa96a389 100755 --- a/tests/topotests/multicast_pim_sm_topo1/test_multicast_pim_sm_topo1.py +++ b/tests/topotests/multicast_pim_sm_topo1/test_multicast_pim_sm_topo1.py @@ -64,7 +64,6 @@ reset_config_on_routers, shutdown_bringup_interface, required_linux_kernel_version, - topo_daemons, ) from lib.pim import ( create_pim_config, @@ -214,7 +213,7 @@ def verify_state_incremented(state_before, state_after): """ for router, state_data in state_before.items(): - for state, value in state_data.items(): + for state, _ in state_data.items(): if state_before[router][state] >= state_after[router][state]: errormsg = ( "[DUT: %s]: state %s value has not" diff --git a/tests/topotests/multicast_pim_sm_topo2/test_multicast_pim_sm_topo2.py b/tests/topotests/multicast_pim_sm_topo2/test_multicast_pim_sm_topo2.py index b62f7bbfc9..0af2efcc7e 100755 --- a/tests/topotests/multicast_pim_sm_topo2/test_multicast_pim_sm_topo2.py +++ b/tests/topotests/multicast_pim_sm_topo2/test_multicast_pim_sm_topo2.py @@ -62,7 +62,6 @@ start_router_daemons, stop_router, required_linux_kernel_version, - topo_daemons, ) from lib.pim import ( create_pim_config, @@ -211,7 +210,7 @@ def verify_state_incremented(state_before, state_after): """ for router, state_data in state_before.items(): - for state, value in state_data.items(): + for state, _ in state_data.items(): if state_before[router][state] >= state_after[router][state]: errormsg = ( "[DUT: %s]: state %s value has not" diff --git a/tests/topotests/multicast_pim_sm_topo3/test_multicast_pim_sm_topo3.py b/tests/topotests/multicast_pim_sm_topo3/test_multicast_pim_sm_topo3.py index ae27546703..9488ae02bf 100755 --- a/tests/topotests/multicast_pim_sm_topo3/test_multicast_pim_sm_topo3.py +++ b/tests/topotests/multicast_pim_sm_topo3/test_multicast_pim_sm_topo3.py @@ -57,7 +57,7 @@ # pylint: disable=C0413 # Import topogen and topotest helpers from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen from lib.common_config import ( start_topology, write_test_header, @@ -68,7 +68,6 @@ apply_raw_config, check_router_status, required_linux_kernel_version, - topo_daemons, ) from lib.pim import ( create_pim_config, @@ -354,7 +353,7 @@ def verify_pim_stats_increament(stats_before, stats_after): """ for router, stats_data in stats_before.items(): - for stats, value in stats_data.items(): + for stats, _ in stats_data.items(): if stats_before[router][stats] >= stats_after[router][stats]: errormsg = ( "[DUT: %s]: state %s value has not" diff --git a/tests/topotests/multicast_pim_sm_topo3/test_multicast_pim_sm_topo4.py b/tests/topotests/multicast_pim_sm_topo3/test_multicast_pim_sm_topo4.py index 825281afbb..11f3cc4254 100755 --- a/tests/topotests/multicast_pim_sm_topo3/test_multicast_pim_sm_topo4.py +++ b/tests/topotests/multicast_pim_sm_topo3/test_multicast_pim_sm_topo4.py @@ -55,7 +55,6 @@ apply_raw_config, create_static_routes, required_linux_kernel_version, - topo_daemons, ) from lib.pim import ( create_pim_config, @@ -191,7 +190,7 @@ def reset_stats(stats): """ for router, state_data in stats.items(): - for state, value in state_data.items(): + for state, _ in state_data.items(): stats[router][state] = 0 logger.info( "[DUT: %s]: stats %s value has reset" " reset, Current value: %s", @@ -214,7 +213,7 @@ def verify_state_incremented(state_before, state_after): """ for router, state_data in state_before.items(): - for state, value in state_data.items(): + for state, _ in state_data.items(): if state_before[router][state] >= state_after[router][state]: errormsg = ( "[DUT: %s]: state %s value has not" diff --git a/tests/topotests/multicast_pim_static_rp_topo1/test_multicast_pim_static_rp.py b/tests/topotests/multicast_pim_static_rp_topo1/test_multicast_pim_static_rp.py index c492d95d40..38b9b2ecb1 100755 --- a/tests/topotests/multicast_pim_static_rp_topo1/test_multicast_pim_static_rp.py +++ b/tests/topotests/multicast_pim_static_rp_topo1/test_multicast_pim_static_rp.py @@ -87,7 +87,6 @@ import os import sys import time -from time import sleep import datetime import pytest @@ -112,10 +111,7 @@ reset_config_on_routers, step, shutdown_bringup_interface, - kill_router_daemons, - start_router_daemons, create_static_routes, - topo_daemons, ) from lib.pim import ( create_pim_config, @@ -128,10 +124,7 @@ verify_pim_rp_info, verify_pim_state, clear_pim_interface_traffic, - clear_igmp_interfaces, - clear_pim_interfaces, clear_mroute, - clear_mroute_verify, McastTesterHelper, ) diff --git a/tests/topotests/multicast_pim_static_rp_topo1/test_multicast_pim_static_rp1.py b/tests/topotests/multicast_pim_static_rp_topo1/test_multicast_pim_static_rp1.py index 690c92f580..6f078a68d8 100755 --- a/tests/topotests/multicast_pim_static_rp_topo1/test_multicast_pim_static_rp1.py +++ b/tests/topotests/multicast_pim_static_rp_topo1/test_multicast_pim_static_rp1.py @@ -112,9 +112,6 @@ reset_config_on_routers, step, shutdown_bringup_interface, - kill_router_daemons, - start_router_daemons, - create_static_routes, ) from lib.pim import ( create_pim_config, @@ -123,9 +120,7 @@ verify_join_state_and_timer, verify_mroutes, verify_pim_neighbors, - get_pim_interface_traffic, verify_pim_rp_info, - verify_pim_state, clear_pim_interface_traffic, clear_igmp_interfaces, clear_pim_interfaces, diff --git a/tests/topotests/multicast_pim_static_rp_topo1/test_multicast_pim_static_rp2.py b/tests/topotests/multicast_pim_static_rp_topo1/test_multicast_pim_static_rp2.py index 8aa2e4efa1..48c0a78f98 100755 --- a/tests/topotests/multicast_pim_static_rp_topo1/test_multicast_pim_static_rp2.py +++ b/tests/topotests/multicast_pim_static_rp_topo1/test_multicast_pim_static_rp2.py @@ -123,14 +123,9 @@ verify_join_state_and_timer, verify_mroutes, verify_pim_neighbors, - get_pim_interface_traffic, verify_pim_rp_info, - verify_pim_state, clear_pim_interface_traffic, - clear_igmp_interfaces, - clear_pim_interfaces, clear_mroute, - clear_mroute_verify, McastTesterHelper, ) diff --git a/tests/topotests/multicast_pim_uplink_topo1/test_multicast_pim_uplink_topo1.py b/tests/topotests/multicast_pim_uplink_topo1/test_multicast_pim_uplink_topo1.py index 5728a4d08e..bbd5501dbb 100644 --- a/tests/topotests/multicast_pim_uplink_topo1/test_multicast_pim_uplink_topo1.py +++ b/tests/topotests/multicast_pim_uplink_topo1/test_multicast_pim_uplink_topo1.py @@ -25,7 +25,6 @@ import os import sys -import json import time import pytest @@ -356,7 +355,7 @@ def verify_state_incremented(state_before, state_after): """ for router, state_data in state_before.items(): - for state, value in state_data.items(): + for state, _ in state_data.items(): if state_before[router][state] > state_after[router][state]: errormsg = ( "[DUT: %s]: state %s value has not" @@ -1682,7 +1681,7 @@ def test_mroutes_updated_correctly_after_source_interface_shut_noshut_p1(request step("Shut and No shut source interface multiple time") - for i in range(0, 2): + for _ in range(0, 2): step("Shut and no shut the source interface from DUT") intf_r1_i2 = topo["routers"]["r1"]["links"]["i2"]["interface"] shutdown_bringup_interface(tgen, "r1", intf_r1_i2, False) diff --git a/tests/topotests/multicast_pim_uplink_topo2/test_multicast_pim_uplink_topo2.py b/tests/topotests/multicast_pim_uplink_topo2/test_multicast_pim_uplink_topo2.py index 1fb81c0d70..893b80083e 100644 --- a/tests/topotests/multicast_pim_uplink_topo2/test_multicast_pim_uplink_topo2.py +++ b/tests/topotests/multicast_pim_uplink_topo2/test_multicast_pim_uplink_topo2.py @@ -213,7 +213,7 @@ def verify_state_incremented(state_before, state_after): """ for router, state_data in state_before.items(): - for state, value in state_data.items(): + for state, _ in state_data.items(): if state_before[router][state] > state_after[router][state]: errormsg = ( "[DUT: %s]: state %s value has not" diff --git a/tests/topotests/nb_config/test_nb_config.py b/tests/topotests/nb_config/test_nb_config.py index 9099ef10b8..09d6407d5b 100644 --- a/tests/topotests/nb_config/test_nb_config.py +++ b/tests/topotests/nb_config/test_nb_config.py @@ -30,7 +30,7 @@ def tgen(request): tgen.start_topology() router_list = tgen.routers() - for rname, router in router_list.items(): + for _, router in router_list.items(): router.load_frr_config("frr.conf") tgen.start_router() diff --git a/tests/topotests/nhrp_redundancy/test_nhrp_redundancy.py b/tests/topotests/nhrp_redundancy/test_nhrp_redundancy.py index 81a22ebfaf..ffd9abc9d4 100644 --- a/tests/topotests/nhrp_redundancy/test_nhrp_redundancy.py +++ b/tests/topotests/nhrp_redundancy/test_nhrp_redundancy.py @@ -10,7 +10,6 @@ import os import sys import json -from time import sleep from functools import partial import pytest @@ -207,7 +206,7 @@ def test_protocols_convergence(): router_list = tgen.routers() # Check NHRP cache on servers and clients - for rname, router in router_list.items(): + for _, router in router_list.items(): json_file = "{}/{}/nhrp_cache.json".format(CWD, router.name) if not os.path.isfile(json_file): diff --git a/tests/topotests/ospf6_gr_topo1/test_ospf6_gr_topo1.py b/tests/topotests/ospf6_gr_topo1/test_ospf6_gr_topo1.py index 45e1bc8db3..ba705e3dfc 100755 --- a/tests/topotests/ospf6_gr_topo1/test_ospf6_gr_topo1.py +++ b/tests/topotests/ospf6_gr_topo1/test_ospf6_gr_topo1.py @@ -135,7 +135,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() diff --git a/tests/topotests/ospf6_loopback_cost/test_ospf6_loopback_cost.py b/tests/topotests/ospf6_loopback_cost/test_ospf6_loopback_cost.py index 8e7a7ea40a..077a9e4205 100644 --- a/tests/topotests/ospf6_loopback_cost/test_ospf6_loopback_cost.py +++ b/tests/topotests/ospf6_loopback_cost/test_ospf6_loopback_cost.py @@ -30,7 +30,7 @@ # pylint: disable=C0413 from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen def setup_module(mod): @@ -46,7 +46,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): tgen = get_topogen() tgen.stop_topology() diff --git a/tests/topotests/ospf6_point_to_multipoint/test_ospf6_point_to_multipoint.py b/tests/topotests/ospf6_point_to_multipoint/test_ospf6_point_to_multipoint.py index 142acf1eb4..73a9022442 100644 --- a/tests/topotests/ospf6_point_to_multipoint/test_ospf6_point_to_multipoint.py +++ b/tests/topotests/ospf6_point_to_multipoint/test_ospf6_point_to_multipoint.py @@ -153,7 +153,7 @@ def setup_module(mod): # tgen.mininet_cli() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() tgen.stop_topology() @@ -229,7 +229,7 @@ def test_ospfv3_routingTable(): # tgen.mininet_cli() # Verify OSPFv3 Routing Table - for router, rnode in tgen.routers().items(): + for router, _ in tgen.routers().items(): logger.info('Waiting for router "%s" convergence', router) # Load expected results from the command diff --git a/tests/topotests/ospf6_topo1/test_ospf6_topo1.py b/tests/topotests/ospf6_topo1/test_ospf6_topo1.py index 5649757010..85075a79aa 100644 --- a/tests/topotests/ospf6_topo1/test_ospf6_topo1.py +++ b/tests/topotests/ospf6_topo1/test_ospf6_topo1.py @@ -153,7 +153,7 @@ def setup_module(mod): # tgen.mininet_cli() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() tgen.stop_topology() @@ -229,7 +229,7 @@ def test_ospfv3_routingTable(): # tgen.mininet_cli() # Verify OSPFv3 Routing Table - for router, rnode in tgen.routers().items(): + for router, _ in tgen.routers().items(): logger.info('Waiting for router "%s" convergence', router) # Load expected results from the command @@ -351,7 +351,7 @@ def test_ospfv3_routingTable_write_multiplier(): r1.vtysh_cmd("clear ipv6 ospf interface r1-sw5") # Verify OSPFv3 Routing Table - for router, rnode in tgen.routers().items(): + for router, _ in tgen.routers().items(): logger.info('Waiting for router "%s" convergence', router) # Load expected results from the command diff --git a/tests/topotests/ospf6_topo1_vrf/test_ospf6_topo1_vrf.py b/tests/topotests/ospf6_topo1_vrf/test_ospf6_topo1_vrf.py index f982990987..ccf25a0fc8 100755 --- a/tests/topotests/ospf6_topo1_vrf/test_ospf6_topo1_vrf.py +++ b/tests/topotests/ospf6_topo1_vrf/test_ospf6_topo1_vrf.py @@ -186,7 +186,7 @@ def setup_module(mod): # tgen.mininet_cli() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() tgen.stop_topology() @@ -260,7 +260,7 @@ def test_ospfv3_routingTable(): # For debugging, uncomment the next line # tgen.mininet_cli() # Verify OSPFv3 Routing Table - for router, rnode in tgen.routers().items(): + for router, _ in tgen.routers().items(): logger.info('Waiting for router "%s" convergence', router) # Load expected results from the command @@ -391,7 +391,7 @@ def test_ospfv3_routingTable_write_multiplier(): r1.vtysh_cmd("clear ipv6 ospf interface r1-sw5") # Verify OSPFv3 Routing Table - for router, rnode in tgen.routers().items(): + for router, _ in tgen.routers().items(): logger.info('Waiting for router "%s" convergence', router) # Load expected results from the command diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_asbr_summary_topo1.py b/tests/topotests/ospf_basic_functionality/test_ospf_asbr_summary_topo1.py index 0531e81d44..18b72772fe 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_asbr_summary_topo1.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_asbr_summary_topo1.py @@ -147,7 +147,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. @@ -2893,7 +2893,7 @@ def test_ospf_type5_summary_tc51_p2(request): step("Configure and re configure all the commands 10 times in a loop.") - for itrate in range(0, 10): + for _ in range(0, 10): ospf_summ_r1 = { "r0": { "ospf": { diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_asbr_summary_type7_lsa.py b/tests/topotests/ospf_basic_functionality/test_ospf_asbr_summary_type7_lsa.py index 603aeadb85..cdc5d126b4 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_asbr_summary_type7_lsa.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_asbr_summary_type7_lsa.py @@ -139,7 +139,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_authentication.py b/tests/topotests/ospf_basic_functionality/test_ospf_authentication.py index 8dd103013b..922c5a0e0b 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_authentication.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_authentication.py @@ -109,7 +109,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_chaos.py b/tests/topotests/ospf_basic_functionality/test_ospf_chaos.py index e58f081f96..dc237e9512 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_chaos.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_chaos.py @@ -118,7 +118,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_ecmp.py b/tests/topotests/ospf_basic_functionality/test_ospf_ecmp.py index aba313db9f..21e767522a 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_ecmp.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_ecmp.py @@ -121,7 +121,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. @@ -193,7 +193,7 @@ def test_ospf_ecmp_tc16_p0(request): step("Verify that route in R2 in stalled with 8 next hops.") nh = [] - for item in range(1, 7): + for _ in range(1, 7): nh.append(topo["routers"]["r0"]["links"]["r1-link1"]["ipv4"].split("/")[0]) nh2 = topo["routers"]["r0"]["links"]["r1"]["ipv4"].split("/")[0] diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_flood_reduction.py b/tests/topotests/ospf_basic_functionality/test_ospf_flood_reduction.py index 62b8212203..7c37af02ac 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_flood_reduction.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_flood_reduction.py @@ -51,7 +51,6 @@ create_static_routes, step, topo_daemons, - shutdown_bringup_interface, check_router_status, start_topology, write_test_header, @@ -65,8 +64,6 @@ write_test_header, write_test_footer, reset_config_on_routers, - stop_router, - start_router, step, create_static_routes, kill_router_daemons, @@ -163,7 +160,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_nssa.py b/tests/topotests/ospf_basic_functionality/test_ospf_nssa.py index 4a40b3e9ec..9c531c03ab 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_nssa.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_nssa.py @@ -119,7 +119,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_p2mp.py b/tests/topotests/ospf_basic_functionality/test_ospf_p2mp.py index a90d7dbdc0..6aec98c71b 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_p2mp.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_p2mp.py @@ -105,7 +105,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_routemaps.py b/tests/topotests/ospf_basic_functionality/test_ospf_routemaps.py index c9f43cdfe4..eee51796c9 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_routemaps.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_routemaps.py @@ -134,7 +134,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_rte_calc.py b/tests/topotests/ospf_basic_functionality/test_ospf_rte_calc.py index d169245f4e..193f5c8c5f 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_rte_calc.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_rte_calc.py @@ -130,7 +130,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. @@ -208,7 +208,7 @@ def test_ospf_redistribution_tc5_p0(request): assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) dut = "r1" - for num in range(0, nretry): + for _ in range(0, nretry): result = verify_ospf_rib(tgen, dut, input_dict, next_hop=nh, expected=False) if result is not True: break @@ -332,7 +332,7 @@ def test_ospf_redistribution_tc6_p0(request): assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) dut = "r1" - for num in range(0, nretry): + for _ in range(0, nretry): result = verify_ospf_rib(tgen, dut, input_dict, next_hop=nh, expected=False) if result is not True: break diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_single_area.py b/tests/topotests/ospf_basic_functionality/test_ospf_single_area.py index 59afc7a8af..33841b9ab2 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_single_area.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_single_area.py @@ -115,7 +115,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. diff --git a/tests/topotests/ospf_dual_stack/test_ospf_dual_stack.py b/tests/topotests/ospf_dual_stack/test_ospf_dual_stack.py index ade55321f9..2d16379952 100644 --- a/tests/topotests/ospf_dual_stack/test_ospf_dual_stack.py +++ b/tests/topotests/ospf_dual_stack/test_ospf_dual_stack.py @@ -72,7 +72,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. diff --git a/tests/topotests/ospf_gr_helper/test_ospf_gr_helper1.py b/tests/topotests/ospf_gr_helper/test_ospf_gr_helper1.py index 79374281cb..3bed390b18 100644 --- a/tests/topotests/ospf_gr_helper/test_ospf_gr_helper1.py +++ b/tests/topotests/ospf_gr_helper/test_ospf_gr_helper1.py @@ -29,7 +29,6 @@ write_test_footer, reset_config_on_routers, step, - create_interfaces_cfg, scapy_send_raw_packet, ) @@ -38,7 +37,6 @@ from lib.ospf import ( verify_ospf_neighbor, - clear_ospf, verify_ospf_gr_helper, create_router_ospf, ) diff --git a/tests/topotests/ospf_gr_helper/test_ospf_gr_helper3.py b/tests/topotests/ospf_gr_helper/test_ospf_gr_helper3.py index 3be28196d8..a9028673d2 100644 --- a/tests/topotests/ospf_gr_helper/test_ospf_gr_helper3.py +++ b/tests/topotests/ospf_gr_helper/test_ospf_gr_helper3.py @@ -29,7 +29,6 @@ write_test_footer, reset_config_on_routers, step, - create_interfaces_cfg, scapy_send_raw_packet, ) @@ -38,7 +37,6 @@ from lib.ospf import ( verify_ospf_neighbor, - clear_ospf, verify_ospf_gr_helper, create_router_ospf, ) diff --git a/tests/topotests/ospf_gr_topo1/test_ospf_gr_topo1.py b/tests/topotests/ospf_gr_topo1/test_ospf_gr_topo1.py index 73185d501d..73b660e590 100755 --- a/tests/topotests/ospf_gr_topo1/test_ospf_gr_topo1.py +++ b/tests/topotests/ospf_gr_topo1/test_ospf_gr_topo1.py @@ -144,7 +144,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() diff --git a/tests/topotests/ospf_instance_redistribute/test_ospf_instance_redistribute.py b/tests/topotests/ospf_instance_redistribute/test_ospf_instance_redistribute.py index 590b0d5e68..ea4507736e 100644 --- a/tests/topotests/ospf_instance_redistribute/test_ospf_instance_redistribute.py +++ b/tests/topotests/ospf_instance_redistribute/test_ospf_instance_redistribute.py @@ -15,7 +15,6 @@ """ import os -import re import sys import pytest import json diff --git a/tests/topotests/ospf_metric_propagation/test_ospf_metric_propagation.py b/tests/topotests/ospf_metric_propagation/test_ospf_metric_propagation.py index 085eb1f9c1..b9c63622f0 100644 --- a/tests/topotests/ospf_metric_propagation/test_ospf_metric_propagation.py +++ b/tests/topotests/ospf_metric_propagation/test_ospf_metric_propagation.py @@ -11,14 +11,13 @@ import os import sys import json -from time import sleep from functools import partial import pytest # pylint: disable=C0413 # Import topogen and topotest helpers from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen from lib.topolog import logger @@ -166,7 +165,7 @@ def setup_module(mod): tgen.set_error("unsupported version") -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() tgen.stop_topology() diff --git a/tests/topotests/ospf_multi_vrf_bgp_route_leak/test_ospf_multi_vrf_bgp_route_leak.py b/tests/topotests/ospf_multi_vrf_bgp_route_leak/test_ospf_multi_vrf_bgp_route_leak.py index ee0a0f6c3b..10a0051a47 100644 --- a/tests/topotests/ospf_multi_vrf_bgp_route_leak/test_ospf_multi_vrf_bgp_route_leak.py +++ b/tests/topotests/ospf_multi_vrf_bgp_route_leak/test_ospf_multi_vrf_bgp_route_leak.py @@ -16,7 +16,7 @@ # pylint: disable=C0413 # Import topogen and topotest helpers from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen from lib.topolog import logger @@ -139,7 +139,7 @@ def setup_module(mod): tgen.set_error("unsupported version") -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() tgen.stop_topology() diff --git a/tests/topotests/ospf_netns_vrf/test_ospf_netns_vrf.py b/tests/topotests/ospf_netns_vrf/test_ospf_netns_vrf.py index 23eef8f5a6..eae8806a59 100644 --- a/tests/topotests/ospf_netns_vrf/test_ospf_netns_vrf.py +++ b/tests/topotests/ospf_netns_vrf/test_ospf_netns_vrf.py @@ -104,13 +104,13 @@ def setup_module(mod): tgen.set_error("unsupported version") -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() # Move interfaces out of vrf namespace and delete the namespace router_list = tgen.routers() - for rname, router in router_list.items(): + for rname, _ in router_list.items(): tgen.net[rname].reset_intf_netns(rname + "-eth0") tgen.net[rname].reset_intf_netns(rname + "-eth1") tgen.net[rname].delete_netns(rname + "-ospf-cust1") diff --git a/tests/topotests/ospf_nssa_topo1/test_ospf_nssa_topo1.py b/tests/topotests/ospf_nssa_topo1/test_ospf_nssa_topo1.py index d8cd1322bd..4a67fa33a6 100644 --- a/tests/topotests/ospf_nssa_topo1/test_ospf_nssa_topo1.py +++ b/tests/topotests/ospf_nssa_topo1/test_ospf_nssa_topo1.py @@ -106,7 +106,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() diff --git a/tests/topotests/ospf_p2mp/test_ospf_p2mp_broadcast.py b/tests/topotests/ospf_p2mp/test_ospf_p2mp_broadcast.py index 1f0f87959a..cce116e974 100644 --- a/tests/topotests/ospf_p2mp/test_ospf_p2mp_broadcast.py +++ b/tests/topotests/ospf_p2mp/test_ospf_p2mp_broadcast.py @@ -9,21 +9,16 @@ import os import sys -import json -from time import sleep from functools import partial import pytest # pylint: disable=C0413 # Import topogen and topotest helpers from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen from lib.topolog import logger from lib.common_config import ( - run_frr_cmd, - shutdown_bringup_interface, - start_router_daemons, step, ) @@ -112,7 +107,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() tgen.stop_topology() diff --git a/tests/topotests/ospf_p2mp/test_ospf_p2mp_non_broadcast.py b/tests/topotests/ospf_p2mp/test_ospf_p2mp_non_broadcast.py index 175dca74e7..3c9e1b1a6f 100644 --- a/tests/topotests/ospf_p2mp/test_ospf_p2mp_non_broadcast.py +++ b/tests/topotests/ospf_p2mp/test_ospf_p2mp_non_broadcast.py @@ -10,7 +10,6 @@ import os import sys -import json from time import sleep from functools import partial import pytest @@ -18,13 +17,10 @@ # pylint: disable=C0413 # Import topogen and topotest helpers from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen from lib.topolog import logger from lib.common_config import ( - run_frr_cmd, - shutdown_bringup_interface, - start_router_daemons, step, ) @@ -116,7 +112,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() tgen.stop_topology() diff --git a/tests/topotests/ospf_prefix_suppression/test_ospf_prefix_suppression.py b/tests/topotests/ospf_prefix_suppression/test_ospf_prefix_suppression.py index d5ea7ebc40..f91cba8d3c 100644 --- a/tests/topotests/ospf_prefix_suppression/test_ospf_prefix_suppression.py +++ b/tests/topotests/ospf_prefix_suppression/test_ospf_prefix_suppression.py @@ -10,21 +10,16 @@ import os import sys -import json -from time import sleep from functools import partial import pytest # pylint: disable=C0413 # Import topogen and topotest helpers from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen from lib.topolog import logger from lib.common_config import ( - run_frr_cmd, - shutdown_bringup_interface, - start_router_daemons, step, ) @@ -125,7 +120,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() tgen.stop_topology() diff --git a/tests/topotests/ospf_single_switch/test_ospf_single_switch.py b/tests/topotests/ospf_single_switch/test_ospf_single_switch.py index e53b5f5b1e..0a8d8456da 100644 --- a/tests/topotests/ospf_single_switch/test_ospf_single_switch.py +++ b/tests/topotests/ospf_single_switch/test_ospf_single_switch.py @@ -14,12 +14,11 @@ import pytest from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen from lib.topolog import logger from lib.common_config import verify_rib from lib.ospf import verify_ospf_rib -from _ast import Try pytestmark = pytest.mark.ospfd @@ -86,7 +85,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Tear-down the test environment" tgen = get_topogen() tgen.stop_topology() diff --git a/tests/topotests/ospf_sr_te_topo1/test_ospf_sr_te_topo1.py b/tests/topotests/ospf_sr_te_topo1/test_ospf_sr_te_topo1.py index 21ae143231..ec076bb3cc 100755 --- a/tests/topotests/ospf_sr_te_topo1/test_ospf_sr_te_topo1.py +++ b/tests/topotests/ospf_sr_te_topo1/test_ospf_sr_te_topo1.py @@ -164,7 +164,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() diff --git a/tests/topotests/ospf_sr_topo1/test_ospf_sr_topo1.py b/tests/topotests/ospf_sr_topo1/test_ospf_sr_topo1.py index 936b438e9d..bac585dd8f 100644 --- a/tests/topotests/ospf_sr_topo1/test_ospf_sr_topo1.py +++ b/tests/topotests/ospf_sr_topo1/test_ospf_sr_topo1.py @@ -136,7 +136,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() diff --git a/tests/topotests/ospf_suppress_fa/test_ospf_suppress_fa.py b/tests/topotests/ospf_suppress_fa/test_ospf_suppress_fa.py index 8b3fc5808a..7f9ad27eab 100644 --- a/tests/topotests/ospf_suppress_fa/test_ospf_suppress_fa.py +++ b/tests/topotests/ospf_suppress_fa/test_ospf_suppress_fa.py @@ -24,7 +24,6 @@ import sys import json from functools import partial -import re import pytest # Save the Current Working Directory to find configuration files. diff --git a/tests/topotests/ospf_tilfa_topo1/test_ospf_tilfa_topo1.py b/tests/topotests/ospf_tilfa_topo1/test_ospf_tilfa_topo1.py index f939f3f578..2466724888 100644 --- a/tests/topotests/ospf_tilfa_topo1/test_ospf_tilfa_topo1.py +++ b/tests/topotests/ospf_tilfa_topo1/test_ospf_tilfa_topo1.py @@ -110,7 +110,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() diff --git a/tests/topotests/ospf_topo1/test_ospf_topo1.py b/tests/topotests/ospf_topo1/test_ospf_topo1.py index a079f5698f..b9bdee3db4 100644 --- a/tests/topotests/ospf_topo1/test_ospf_topo1.py +++ b/tests/topotests/ospf_topo1/test_ospf_topo1.py @@ -93,7 +93,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() tgen.stop_topology() diff --git a/tests/topotests/ospf_topo2/test_ospf_topo2.py b/tests/topotests/ospf_topo2/test_ospf_topo2.py index 8be06e41af..45ae338a24 100644 --- a/tests/topotests/ospf_topo2/test_ospf_topo2.py +++ b/tests/topotests/ospf_topo2/test_ospf_topo2.py @@ -66,7 +66,7 @@ def tgen(request): router_list = tgen.routers() - for rname, router in router_list.items(): + for _, router in router_list.items(): router.load_frr_config("frr.conf") tgen.start_router() diff --git a/tests/topotests/ospf_unnumbered/test_ospf_unnumbered.py b/tests/topotests/ospf_unnumbered/test_ospf_unnumbered.py index d07f5dc5c9..712c4e1d7c 100644 --- a/tests/topotests/ospf_unnumbered/test_ospf_unnumbered.py +++ b/tests/topotests/ospf_unnumbered/test_ospf_unnumbered.py @@ -89,7 +89,7 @@ def setup_module(mod): # tgen.mininet_cli() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() tgen.stop_topology() diff --git a/tests/topotests/ospf_unnumbered_point_to_multipoint/test_ospf_unnumbered_point_to_multipoint.py b/tests/topotests/ospf_unnumbered_point_to_multipoint/test_ospf_unnumbered_point_to_multipoint.py index c0dd85cba0..a97b114547 100644 --- a/tests/topotests/ospf_unnumbered_point_to_multipoint/test_ospf_unnumbered_point_to_multipoint.py +++ b/tests/topotests/ospf_unnumbered_point_to_multipoint/test_ospf_unnumbered_point_to_multipoint.py @@ -92,7 +92,7 @@ def setup_module(mod): # tgen.mininet_cli() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() tgen.stop_topology() diff --git a/tests/topotests/ospfapi/test_ospf_clientapi.py b/tests/topotests/ospfapi/test_ospf_clientapi.py index 626a9d3185..89a34ff9b5 100644 --- a/tests/topotests/ospfapi/test_ospf_clientapi.py +++ b/tests/topotests/ospfapi/test_ospf_clientapi.py @@ -16,7 +16,6 @@ import subprocess import sys import time -from datetime import datetime, timedelta from functools import partial import pytest @@ -35,8 +34,7 @@ # pylint: disable=C0413 # Import topogen and topotest helpers from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen -from lib.topolog import logger +from lib.topogen import Topogen, TopoRouter pytestmark = [pytest.mark.ospfd] diff --git a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_asbr_summary_topo1.py b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_asbr_summary_topo1.py index 49c25ab8f6..c431147e55 100644 --- a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_asbr_summary_topo1.py +++ b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_asbr_summary_topo1.py @@ -29,7 +29,6 @@ from lib.common_config import ( start_topology, write_test_header, - kill_router_daemons, write_test_footer, reset_config_on_routers, stop_router, @@ -37,7 +36,6 @@ verify_rib, create_static_routes, step, - start_router_daemons, create_route_maps, shutdown_bringup_interface, create_prefix_lists, @@ -163,7 +161,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. @@ -2456,7 +2454,7 @@ def test_ospfv3_type5_summary_tc51_p2(request): step("Configure and re configure all the commands 10 times in a loop.") - for itrate in range(0, 10): + for _ in range(0, 10): ospf_summ_r1 = { "r0": { "ospf6": { diff --git a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_authentication.py b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_authentication.py index 00c98ac97c..5f88f6d835 100644 --- a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_authentication.py +++ b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_authentication.py @@ -14,9 +14,7 @@ import time import pytest from time import sleep -from copy import deepcopy import json -from lib.topotest import frr_unicode pytestmark = pytest.mark.ospf6d @@ -39,11 +37,8 @@ shutdown_bringup_interface, ) from lib.topolog import logger -from lib.topojson import build_topo_from_json, build_config_from_json -from lib.ospf import verify_ospf6_neighbor, config_ospf6_interface, clear_ospf -from ipaddress import IPv4Address - -# Global variables +from lib.topojson import build_config_from_json +from lib.ospf import verify_ospf6_neighbor, config_ospf6_interface topo = None # Reading the data from JSON File for topology creation jsonFile = "{}/ospfv3_authentication.json".format(CWD) @@ -118,7 +113,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. * `mod`: module name diff --git a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_ecmp.py b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_ecmp.py index 0c1e3fa43e..45652a3ee8 100644 --- a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_ecmp.py +++ b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_ecmp.py @@ -122,7 +122,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. @@ -285,7 +285,7 @@ def test_ospfv3_ecmp_tc16_p0(request): step("Verify that route in R2 in stalled with 8 next hops.") nh = [] - for item in range(1, 7): + for _ in range(1, 7): nh.append(llip) llip = get_llip("r0", "r1") diff --git a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_ecmp_lan.py b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_ecmp_lan.py index 7c6773260e..95f2493c2a 100644 --- a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_ecmp_lan.py +++ b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_ecmp_lan.py @@ -13,11 +13,6 @@ import sys import time import pytest -import json -from copy import deepcopy -from ipaddress import IPv4Address -from lib.topotest import frr_unicode -import ipaddress # Save the Current Working Directory to find configuration files. CWD = os.path.dirname(os.path.realpath(__file__)) @@ -37,9 +32,6 @@ verify_rib, create_static_routes, step, - create_route_maps, - shutdown_bringup_interface, - create_interfaces_cfg, get_frr_ipv6_linklocal, ) from lib.topolog import logger @@ -47,16 +39,11 @@ from lib.ospf import ( verify_ospf6_neighbor, - config_ospf_interface, clear_ospf, verify_ospf6_rib, create_router_ospf, - verify_ospf6_interface, - verify_ospf6_database, - config_ospf6_interface, ) -from ipaddress import IPv6Address pytestmark = [pytest.mark.ospfd, pytest.mark.staticd] @@ -137,7 +124,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. diff --git a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_nssa.py b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_nssa.py index dc4ce88830..cc96cd1731 100644 --- a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_nssa.py +++ b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_nssa.py @@ -78,7 +78,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. diff --git a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_nssa2.py b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_nssa2.py index 5a6c377aef..4ad725e3e6 100644 --- a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_nssa2.py +++ b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_nssa2.py @@ -13,15 +13,10 @@ import sys import time import pytest -from copy import deepcopy import ipaddress from lib.ospf import ( verify_ospf6_neighbor, - config_ospf6_interface, - clear_ospf, verify_ospf6_rib, - verify_ospf6_interface, - verify_ospf6_database, create_router_ospf, ) @@ -29,12 +24,6 @@ # Import topogen and topotest helpers from lib.topogen import Topogen, get_topogen -from lib.bgp import ( - verify_bgp_convergence, - create_router_bgp, - clear_bgp_and_verify, - verify_bgp_rib, -) from lib.topolog import logger from lib.common_config import ( start_topology, @@ -44,12 +33,9 @@ verify_rib, create_static_routes, step, - create_route_maps, - shutdown_bringup_interface, create_interfaces_cfg, check_router_status, ) -from ipaddress import IPv4Address from lib.topolog import logger from lib.topojson import build_config_from_json diff --git a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_routemaps.py b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_routemaps.py index 069806a3ef..ff88badeeb 100644 --- a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_routemaps.py +++ b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_routemaps.py @@ -136,7 +136,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. diff --git a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_rte_calc.py b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_rte_calc.py index 916f655550..06989db894 100644 --- a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_rte_calc.py +++ b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_rte_calc.py @@ -45,7 +45,6 @@ verify_ospf6_neighbor, clear_ospf, verify_ospf6_rib, - verify_ospf_database, create_router_ospf, config_ospf6_interface, verify_ospf6_interface, @@ -127,7 +126,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. diff --git a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_single_area.py b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_single_area.py index 3bafd27f24..15e0f5316e 100644 --- a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_single_area.py +++ b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_single_area.py @@ -36,7 +36,6 @@ step, create_interfaces_cfg, create_debug_log_config, - apply_raw_config, ) from lib.topolog import logger from lib.topojson import build_config_from_json @@ -121,7 +120,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. diff --git a/tests/topotests/pim_acl/test_pim_acl.py b/tests/topotests/pim_acl/test_pim_acl.py index 6e5092dabb..d8eececf81 100755 --- a/tests/topotests/pim_acl/test_pim_acl.py +++ b/tests/topotests/pim_acl/test_pim_acl.py @@ -169,7 +169,7 @@ def setup_module(module): tgen.start_router() -def teardown_module(module): +def teardown_module(): tgen = get_topogen() tgen.stop_topology() diff --git a/tests/topotests/pim_basic/test_pim.py b/tests/topotests/pim_basic/test_pim.py index 85b49aacc6..ce1abe42bb 100644 --- a/tests/topotests/pim_basic/test_pim.py +++ b/tests/topotests/pim_basic/test_pim.py @@ -88,7 +88,7 @@ def setup_module(mod): # tgen.mininet_cli() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() diff --git a/tests/topotests/pim_igmp_vrf/test_pim_vrf.py b/tests/topotests/pim_igmp_vrf/test_pim_vrf.py index 01c496d703..d6d879d45f 100755 --- a/tests/topotests/pim_igmp_vrf/test_pim_vrf.py +++ b/tests/topotests/pim_igmp_vrf/test_pim_vrf.py @@ -92,7 +92,7 @@ from lib.topogen import Topogen, TopoRouter, get_topogen from lib.topolog import logger from lib.topotest import iproute2_is_vrf_capable -from lib.common_config import required_linux_kernel_version, retry +from lib.common_config import required_linux_kernel_version from lib.pim import McastTesterHelper @@ -205,7 +205,7 @@ def setup_module(module): ) -def teardown_module(module): +def teardown_module(): tgen = get_topogen() tgen.stop_topology() diff --git a/tests/topotests/rip_allow_ecmp/test_rip_allow_ecmp.py b/tests/topotests/rip_allow_ecmp/test_rip_allow_ecmp.py index 7d958fd496..c07b1ffc15 100644 --- a/tests/topotests/rip_allow_ecmp/test_rip_allow_ecmp.py +++ b/tests/topotests/rip_allow_ecmp/test_rip_allow_ecmp.py @@ -20,7 +20,7 @@ # pylint: disable=C0413 from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen from lib.common_config import step pytestmark = [pytest.mark.ripd] @@ -39,7 +39,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): tgen = get_topogen() tgen.stop_topology() diff --git a/tests/topotests/rip_bfd_topo1/test_rip_bfd_topo1.py b/tests/topotests/rip_bfd_topo1/test_rip_bfd_topo1.py index d03d5479fd..26680f5460 100644 --- a/tests/topotests/rip_bfd_topo1/test_rip_bfd_topo1.py +++ b/tests/topotests/rip_bfd_topo1/test_rip_bfd_topo1.py @@ -20,7 +20,6 @@ from functools import partial from lib import topotest from lib.topogen import Topogen, TopoRouter -from lib.topolog import logger pytestmark = [ pytest.mark.bfdd, diff --git a/tests/topotests/rip_passive_interface/test_rip_passive_interface.py b/tests/topotests/rip_passive_interface/test_rip_passive_interface.py index c2b28c4a3e..ebc36d1fdc 100644 --- a/tests/topotests/rip_passive_interface/test_rip_passive_interface.py +++ b/tests/topotests/rip_passive_interface/test_rip_passive_interface.py @@ -21,7 +21,7 @@ # pylint: disable=C0413 from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen from lib.common_config import step pytestmark = [pytest.mark.ripd] @@ -40,7 +40,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): tgen = get_topogen() tgen.stop_topology() diff --git a/tests/topotests/ripng_allow_ecmp/test_ripng_allow_ecmp.py b/tests/topotests/ripng_allow_ecmp/test_ripng_allow_ecmp.py index 08bb999928..060b558f0d 100644 --- a/tests/topotests/ripng_allow_ecmp/test_ripng_allow_ecmp.py +++ b/tests/topotests/ripng_allow_ecmp/test_ripng_allow_ecmp.py @@ -20,7 +20,7 @@ # pylint: disable=C0413 from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen from lib.common_config import step pytestmark = [pytest.mark.ripngd] @@ -39,7 +39,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): tgen = get_topogen() tgen.stop_topology() diff --git a/tests/topotests/ripng_route_map/test_ripng_route_map.py b/tests/topotests/ripng_route_map/test_ripng_route_map.py index e1cc88e9b6..4fadb5fbcf 100644 --- a/tests/topotests/ripng_route_map/test_ripng_route_map.py +++ b/tests/topotests/ripng_route_map/test_ripng_route_map.py @@ -20,8 +20,7 @@ # pylint: disable=C0413 from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen -from lib.common_config import step +from lib.topogen import Topogen, get_topogen pytestmark = [pytest.mark.ripngd] @@ -39,7 +38,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): tgen = get_topogen() tgen.stop_topology() diff --git a/tests/topotests/route_scale/scale_test_common.py b/tests/topotests/route_scale/scale_test_common.py index b3cba1cb4e..3e20296018 100644 --- a/tests/topotests/route_scale/scale_test_common.py +++ b/tests/topotests/route_scale/scale_test_common.py @@ -182,7 +182,6 @@ def route_install_helper(iter): # Build up a list of dicts with params for each step of the test; # use defaults where the step doesn't supply a value - scale_setups = [] s = scale_steps[iter] d = dict(zip(scale_keys, s)) diff --git a/tests/topotests/route_scale/test_route_scale1.py b/tests/topotests/route_scale/test_route_scale1.py index ccbdd51595..68af979c2f 100644 --- a/tests/topotests/route_scale/test_route_scale1.py +++ b/tests/topotests/route_scale/test_route_scale1.py @@ -14,11 +14,8 @@ """ import os -import re import sys import pytest -import json -from functools import partial # Save the Current Working Directory to find configuration files. CWD = os.path.dirname(os.path.realpath(__file__)) @@ -26,9 +23,6 @@ # pylint: disable=C0413 # Import topogen and topotest helpers -from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen -from lib.topolog import logger from scale_test_common import ( scale_build_common, diff --git a/tests/topotests/route_scale/test_route_scale2.py b/tests/topotests/route_scale/test_route_scale2.py index e244d4fbbc..4be8554a0f 100644 --- a/tests/topotests/route_scale/test_route_scale2.py +++ b/tests/topotests/route_scale/test_route_scale2.py @@ -14,11 +14,8 @@ """ import os -import re import sys import pytest -import json -from functools import partial # Save the Current Working Directory to find configuration files. CWD = os.path.dirname(os.path.realpath(__file__)) @@ -26,9 +23,6 @@ # pylint: disable=C0413 # Import topogen and topotest helpers -from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen -from lib.topolog import logger from scale_test_common import ( scale_build_common, diff --git a/tests/topotests/simple_snmp_test/test_simple_snmp.py b/tests/topotests/simple_snmp_test/test_simple_snmp.py index ee02c7b519..0387e29274 100755 --- a/tests/topotests/simple_snmp_test/test_simple_snmp.py +++ b/tests/topotests/simple_snmp_test/test_simple_snmp.py @@ -79,7 +79,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() diff --git a/tests/topotests/srv6_encap_src_addr/test_srv6_encap_src_addr.py b/tests/topotests/srv6_encap_src_addr/test_srv6_encap_src_addr.py index b8bcab8d93..854bc1cdad 100755 --- a/tests/topotests/srv6_encap_src_addr/test_srv6_encap_src_addr.py +++ b/tests/topotests/srv6_encap_src_addr/test_srv6_encap_src_addr.py @@ -18,7 +18,6 @@ import sys import json import pytest -import functools CWD = os.path.dirname(os.path.realpath(__file__)) sys.path.append(os.path.join(CWD, "../")) @@ -56,7 +55,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): tgen = get_topogen() tgen.stop_topology() diff --git a/tests/topotests/srv6_locator/test_srv6_locator.py b/tests/topotests/srv6_locator/test_srv6_locator.py index 3a27d9c2fc..bab6746409 100755 --- a/tests/topotests/srv6_locator/test_srv6_locator.py +++ b/tests/topotests/srv6_locator/test_srv6_locator.py @@ -56,7 +56,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): tgen = get_topogen() tgen.stop_topology() @@ -81,12 +81,12 @@ def _check_sharpd_chunk(router, expected_chunk_file): def check_srv6_locator(router, expected_file): func = functools.partial(_check_srv6_locator, router, expected_file) - success, result = topotest.run_and_expect(func, None, count=10, wait=0.5) + _, result = topotest.run_and_expect(func, None, count=10, wait=0.5) assert result is None, "Failed" def check_sharpd_chunk(router, expected_file): func = functools.partial(_check_sharpd_chunk, router, expected_file) - success, result = topotest.run_and_expect(func, None, count=10, wait=0.5) + _, result = topotest.run_and_expect(func, None, count=10, wait=0.5) assert result is None, "Failed" # FOR DEVELOPER: diff --git a/tests/topotests/srv6_locator_custom_bits_length/test_srv6_locator_custom_bits_length.py b/tests/topotests/srv6_locator_custom_bits_length/test_srv6_locator_custom_bits_length.py index 92980d3b17..d3df902aae 100755 --- a/tests/topotests/srv6_locator_custom_bits_length/test_srv6_locator_custom_bits_length.py +++ b/tests/topotests/srv6_locator_custom_bits_length/test_srv6_locator_custom_bits_length.py @@ -52,7 +52,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): tgen = get_topogen() tgen.stop_topology() @@ -77,12 +77,12 @@ def _check_sharpd_chunk(router, expected_chunk_file): def check_srv6_locator(router, expected_file): func = functools.partial(_check_srv6_locator, router, expected_file) - success, result = topotest.run_and_expect(func, None, count=10, wait=0.5) + _, result = topotest.run_and_expect(func, None, count=10, wait=0.5) assert result is None, "Failed" def check_sharpd_chunk(router, expected_file): func = functools.partial(_check_sharpd_chunk, router, expected_file) - success, result = topotest.run_and_expect(func, None, count=10, wait=0.5) + _, result = topotest.run_and_expect(func, None, count=10, wait=0.5) assert result is None, "Failed" # FOR DEVELOPER: diff --git a/tests/topotests/srv6_locator_usid/test_srv6_locator_usid.py b/tests/topotests/srv6_locator_usid/test_srv6_locator_usid.py index 54187351b2..e0c05c5179 100755 --- a/tests/topotests/srv6_locator_usid/test_srv6_locator_usid.py +++ b/tests/topotests/srv6_locator_usid/test_srv6_locator_usid.py @@ -49,7 +49,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): tgen = get_topogen() tgen.stop_topology() @@ -70,13 +70,13 @@ def _check_sharpd_chunk(router, expected_chunk_file): def check_srv6_locator(router, expected_file): func = functools.partial(_check_srv6_locator, router, expected_file) - success, result = topotest.run_and_expect(func, None, count=5, wait=3) + _, result = topotest.run_and_expect(func, None, count=5, wait=3) assert result is None, "Failed" def check_sharpd_chunk(router, expected_file): func = functools.partial(_check_sharpd_chunk, router, expected_file) - success, result = topotest.run_and_expect(func, None, count=5, wait=3) + _, result = topotest.run_and_expect(func, None, count=5, wait=3) assert result is None, "Failed" diff --git a/tests/topotests/srv6_static_route/test_srv6_route.py b/tests/topotests/srv6_static_route/test_srv6_route.py index 7a4cd39f2d..f23e199d4a 100755 --- a/tests/topotests/srv6_static_route/test_srv6_route.py +++ b/tests/topotests/srv6_static_route/test_srv6_route.py @@ -55,7 +55,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): tgen = get_topogen() tgen.stop_topology() @@ -74,7 +74,7 @@ def _check_srv6_static_route(router, expected_route_file): def check_srv6_static_route(router, expected_file): func = functools.partial(_check_srv6_static_route, router, expected_file) - success, result = topotest.run_and_expect(func, None, count=15, wait=1) + _, result = topotest.run_and_expect(func, None, count=15, wait=1) assert result is None, "Failed" # FOR DEVELOPER: diff --git a/tests/topotests/static_routing_mpls/test_static_routing_mpls.py b/tests/topotests/static_routing_mpls/test_static_routing_mpls.py index c1e249cc8f..a0f11c0126 100644 --- a/tests/topotests/static_routing_mpls/test_static_routing_mpls.py +++ b/tests/topotests/static_routing_mpls/test_static_routing_mpls.py @@ -14,11 +14,8 @@ """ import os -import re import sys import pytest -import json -from functools import partial import functools # Save the Current Working Directory to find configuration files. @@ -113,7 +110,7 @@ def _check_mpls_state(router, interface, configured=True): test_func = functools.partial( _check_mpls_state_interface, router, interface, up=configured ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) return success diff --git a/tests/topotests/static_routing_with_ebgp/test_static_routes_topo2_ebgp.py b/tests/topotests/static_routing_with_ebgp/test_static_routes_topo2_ebgp.py index e01351506d..0d6b3e7b1d 100644 --- a/tests/topotests/static_routing_with_ebgp/test_static_routes_topo2_ebgp.py +++ b/tests/topotests/static_routing_with_ebgp/test_static_routes_topo2_ebgp.py @@ -150,7 +150,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment diff --git a/tests/topotests/static_routing_with_ebgp/test_static_routes_topo3_ebgp.py b/tests/topotests/static_routing_with_ebgp/test_static_routes_topo3_ebgp.py index 9d35b7dcd3..ff349f279e 100644 --- a/tests/topotests/static_routing_with_ebgp/test_static_routes_topo3_ebgp.py +++ b/tests/topotests/static_routing_with_ebgp/test_static_routes_topo3_ebgp.py @@ -134,7 +134,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment diff --git a/tests/topotests/static_routing_with_ebgp/test_static_routes_topo4_ebgp.py b/tests/topotests/static_routing_with_ebgp/test_static_routes_topo4_ebgp.py index 3e03055acd..c74d8d70a6 100644 --- a/tests/topotests/static_routing_with_ebgp/test_static_routes_topo4_ebgp.py +++ b/tests/topotests/static_routing_with_ebgp/test_static_routes_topo4_ebgp.py @@ -113,7 +113,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. diff --git a/tests/topotests/static_routing_with_ibgp/test_static_routes_topo1_ibgp.py b/tests/topotests/static_routing_with_ibgp/test_static_routes_topo1_ibgp.py index abae75e76e..926a9909e1 100644 --- a/tests/topotests/static_routing_with_ibgp/test_static_routes_topo1_ibgp.py +++ b/tests/topotests/static_routing_with_ibgp/test_static_routes_topo1_ibgp.py @@ -110,7 +110,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment diff --git a/tests/topotests/static_routing_with_ibgp/test_static_routes_topo2_ibgp.py b/tests/topotests/static_routing_with_ibgp/test_static_routes_topo2_ibgp.py index 820a736ad7..933e541095 100644 --- a/tests/topotests/static_routing_with_ibgp/test_static_routes_topo2_ibgp.py +++ b/tests/topotests/static_routing_with_ibgp/test_static_routes_topo2_ibgp.py @@ -152,7 +152,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment diff --git a/tests/topotests/static_routing_with_ibgp/test_static_routes_topo3_ibgp.py b/tests/topotests/static_routing_with_ibgp/test_static_routes_topo3_ibgp.py index 1ad963f314..9fabd9d571 100644 --- a/tests/topotests/static_routing_with_ibgp/test_static_routes_topo3_ibgp.py +++ b/tests/topotests/static_routing_with_ibgp/test_static_routes_topo3_ibgp.py @@ -133,7 +133,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment diff --git a/tests/topotests/static_routing_with_ibgp/test_static_routes_topo4_ibgp.py b/tests/topotests/static_routing_with_ibgp/test_static_routes_topo4_ibgp.py index 0fc81aaf1e..f1b7606e79 100644 --- a/tests/topotests/static_routing_with_ibgp/test_static_routes_topo4_ibgp.py +++ b/tests/topotests/static_routing_with_ibgp/test_static_routes_topo4_ibgp.py @@ -111,7 +111,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. diff --git a/tests/topotests/static_simple/test_static_simple.py b/tests/topotests/static_simple/test_static_simple.py index f862d81239..bb3580a1d8 100644 --- a/tests/topotests/static_simple/test_static_simple.py +++ b/tests/topotests/static_simple/test_static_simple.py @@ -13,11 +13,10 @@ import ipaddress import math import os -import sys import re import pytest -from lib.topogen import TopoRouter, Topogen, get_topogen +from lib.topogen import TopoRouter, Topogen from lib.topolog import logger from lib.common_config import retry, step @@ -80,7 +79,7 @@ def check_kernel(r1, super_prefix, count, add, is_blackhole, vrf, matchvia): kernel = r1.run(f"ip -4 route show{vrfstr}") logger.debug("checking kernel routing table%s:\n%s", vrfstr, kernel) - for i, net in enumerate(get_ip_networks(super_prefix, count)): + for _, net in enumerate(get_ip_networks(super_prefix, count)): if not add: assert str(net) not in kernel continue @@ -116,7 +115,6 @@ def do_config( else: super_prefix = "2001::/48" if do_ipv6 else "10.0.0.0/8" - matchtype = "" matchvia = "" if via == "blackhole": pass @@ -146,7 +144,7 @@ def do_config( if vrf: f.write("vrf {}\n".format(vrf)) - for i, net in enumerate(get_ip_networks(super_prefix, count)): + for _, net in enumerate(get_ip_networks(super_prefix, count)): if add: f.write("ip route {} {}\n".format(net, via)) else: diff --git a/tests/topotests/zebra_multiple_connected/test_zebra_multiple_connected.py b/tests/topotests/zebra_multiple_connected/test_zebra_multiple_connected.py index 0b2937c12a..dc47527c74 100644 --- a/tests/topotests/zebra_multiple_connected/test_zebra_multiple_connected.py +++ b/tests/topotests/zebra_multiple_connected/test_zebra_multiple_connected.py @@ -15,7 +15,6 @@ """ import os -import re import sys import pytest import json @@ -29,7 +28,6 @@ # Import topogen and topotest helpers from lib import topotest from lib.topogen import Topogen, TopoRouter, get_topogen -from lib.topolog import logger # Required to instantiate the topology builder class. @@ -157,7 +155,7 @@ def test_zebra_noprefix_connected(): test_func = partial( topotest.router_output_cmp, router, "show ip route 192.168.44.0/24", expected ) - result, diff = topotest.run_and_expect(test_func, "", count=20, wait=1) + result, _ = topotest.run_and_expect(test_func, "", count=20, wait=1) assert result, "Connected Route should not have been added" diff --git a/tests/topotests/zebra_netlink/test_zebra_netlink.py b/tests/topotests/zebra_netlink/test_zebra_netlink.py index d970c04ee2..3748f9c4e3 100644 --- a/tests/topotests/zebra_netlink/test_zebra_netlink.py +++ b/tests/topotests/zebra_netlink/test_zebra_netlink.py @@ -13,9 +13,7 @@ """ # pylint: disable=C0413 import ipaddress -import json import sys -from functools import partial import pytest from lib import topotest @@ -42,7 +40,7 @@ def tgen(request): # Initialize all routers. router_list = tgen.routers() - for rname, router in router_list.items(): + for _, router in router_list.items(): router.load_config(TopoRouter.RD_ZEBRA, "zebra.conf") router.load_config(TopoRouter.RD_SHARP) diff --git a/tests/topotests/zebra_nht_resolution/test_verify_nh_resolution.py b/tests/topotests/zebra_nht_resolution/test_verify_nh_resolution.py index fbef0fefc7..16e458062d 100644 --- a/tests/topotests/zebra_nht_resolution/test_verify_nh_resolution.py +++ b/tests/topotests/zebra_nht_resolution/test_verify_nh_resolution.py @@ -16,7 +16,6 @@ import pytest from lib.common_config import ( - start_topology, verify_rib, verify_ip_nht, step, @@ -24,7 +23,6 @@ ) # pylint: disable=C0413 -from lib import topotest from lib.topogen import Topogen, TopoRouter, get_topogen from lib.topolog import logger diff --git a/tests/topotests/zebra_opaque/test_zebra_opaque.py b/tests/topotests/zebra_opaque/test_zebra_opaque.py index 25fbb97806..4f49a69bdc 100644 --- a/tests/topotests/zebra_opaque/test_zebra_opaque.py +++ b/tests/topotests/zebra_opaque/test_zebra_opaque.py @@ -32,7 +32,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -49,7 +49,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): tgen = get_topogen() tgen.stop_topology() @@ -98,17 +98,17 @@ def _ospf6_converge(router): router = tgen.gears["r1"] test_func = functools.partial(_bgp_converge, router) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, 'Cannot see BGP community aliases "{}"'.format(router) router = tgen.gears["r3"] test_func = functools.partial(_ospf_converge, router) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, 'Cannot see OSPFv2 opaque attributes "{}"'.format(router) router = tgen.gears["r3"] test_func = functools.partial(_ospf6_converge, router) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, 'Cannot see OSPFv3 opaque attributes "{}"'.format(router) diff --git a/tests/topotests/zebra_rib/test_zebra_rib.py b/tests/topotests/zebra_rib/test_zebra_rib.py index 05036fa7ad..93296cd51a 100644 --- a/tests/topotests/zebra_rib/test_zebra_rib.py +++ b/tests/topotests/zebra_rib/test_zebra_rib.py @@ -71,7 +71,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() tgen.stop_topology() @@ -235,7 +235,7 @@ def check_initial_routes_installed(router): return topotest.json_cmp(output, expected) test_func = partial(check_initial_routes_installed, r1) - success, result = topotest.run_and_expect(test_func, None, count=40, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=40, wait=1) static_rmapfile = "%s/r1/static_rmap.ref" % (thisDir) expected = open(static_rmapfile).read().rstrip() diff --git a/tests/topotests/zebra_seg6_route/test_zebra_seg6_route.py b/tests/topotests/zebra_seg6_route/test_zebra_seg6_route.py index 4a4cf0624f..f94b7d4a9c 100755 --- a/tests/topotests/zebra_seg6_route/test_zebra_seg6_route.py +++ b/tests/topotests/zebra_seg6_route/test_zebra_seg6_route.py @@ -80,7 +80,7 @@ def check_connected(router, dest, expected): expected = open_json_file(os.path.join(CWD, "{}/routes_setup.json".format("r1"))) test_func = partial(check_connected, r1, "2001::/64", expected) - success, result = topotest.run_and_expect(test_func, None, count=20, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=20, wait=1) assert result is None, "Failed to fully setup connected routes needed" manifests = open_json_file(os.path.join(CWD, "{}/routes.json".format("r1"))) @@ -96,7 +96,7 @@ def check_connected(router, dest, expected): ) logger.info("CHECK {} {} {}".format(dest, nh, sid)) test_func = partial(check, r1, dest, manifest["out"]) - success, result = topotest.run_and_expect(test_func, None, count=20, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=20, wait=1) assert result is None, "Failed" diff --git a/tests/topotests/zebra_seg6local_route/test_zebra_seg6local_route.py b/tests/topotests/zebra_seg6local_route/test_zebra_seg6local_route.py index 0dc87741aa..a90f5c9c98 100755 --- a/tests/topotests/zebra_seg6local_route/test_zebra_seg6local_route.py +++ b/tests/topotests/zebra_seg6local_route/test_zebra_seg6local_route.py @@ -101,7 +101,7 @@ def check(router, dest, expected): dest, manifest["out"], ) - success, result = topotest.run_and_expect(test_func, None, count=25, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=25, wait=1) assert result is None, "Failed" From 36a310cc9f6ef7694d30fe3527a9462bb7155fd3 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Sat, 8 Jun 2024 07:15:47 +0200 Subject: [PATCH 067/347] zebra, lib: add locator name in sid notify messages In the near future, some daemons may only register SIDs. This may be the case for the pathd daemon when creating SRv6 binding SIDs. When a locator is getting deleted at ZEBRA level, the daemon may have an easy way to find out the SIds to unregister to. This commit proposes to add the locator name to the SID_SRV6_NOTIFY message whenever possible. Only case when an allocation failure happens, the locator will not be present. In all other places, the notify API at procol levels has the locator name extra-parameter. Signed-off-by: Philippe Guibert Signed-off-by: Carmine Scarpitta --- lib/zclient.c | 18 +++++++++++++++++- lib/zclient.h | 3 ++- zebra/zapi_msg.c | 11 ++++++++++- zebra/zapi_msg.h | 2 +- zebra/zebra_srv6.c | 15 ++++++++++++--- 5 files changed, 42 insertions(+), 7 deletions(-) diff --git a/lib/zclient.c b/lib/zclient.c index a1386e501a..586ee9c2cb 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -2136,9 +2136,12 @@ bool zapi_iptable_notify_decode(struct stream *s, bool zapi_srv6_sid_notify_decode(struct stream *s, struct srv6_sid_ctx *ctx, struct in6_addr *sid_value, uint32_t *func, uint32_t *wide_func, - enum zapi_srv6_sid_notify *note) + enum zapi_srv6_sid_notify *note, + char **p_locator_name) { uint32_t f, wf; + uint16_t len; + static char locator_name[SRV6_LOCNAME_SIZE] = {}; STREAM_GET(note, s, sizeof(*note)); STREAM_GET(ctx, s, sizeof(struct srv6_sid_ctx)); @@ -2151,6 +2154,19 @@ bool zapi_srv6_sid_notify_decode(struct stream *s, struct srv6_sid_ctx *ctx, if (wide_func) *wide_func = wf; + STREAM_GETW(s, len); + if (len > SRV6_LOCNAME_SIZE) { + *p_locator_name = NULL; + return false; + } + if (p_locator_name) { + if (len == 0) + *p_locator_name = NULL; + else { + STREAM_GET(locator_name, s, len); + *p_locator_name = locator_name; + } + } return true; stream_failure: diff --git a/lib/zclient.h b/lib/zclient.h index bfe955b7ac..2877b347d8 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -1177,7 +1177,8 @@ bool zapi_ipset_notify_decode(struct stream *s, bool zapi_srv6_sid_notify_decode(struct stream *s, struct srv6_sid_ctx *ctx, struct in6_addr *sid_value, uint32_t *func, uint32_t *wide_func, - enum zapi_srv6_sid_notify *note); + enum zapi_srv6_sid_notify *note, + char **locator_name); /* Nexthop-group message apis */ extern enum zclient_send_status diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index 164c0dd687..2a1eea9594 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -1001,7 +1001,9 @@ void zsend_neighbor_notify(int cmd, struct interface *ifp, void zsend_srv6_sid_notify(struct zserv *client, const struct srv6_sid_ctx *ctx, struct in6_addr *sid_value, uint32_t func, - uint32_t wide_func, enum zapi_srv6_sid_notify note) + uint32_t wide_func, const char *locator_name, + enum zapi_srv6_sid_notify note) + { struct stream *s; uint16_t cmd = ZEBRA_SRV6_SID_NOTIFY; @@ -1027,6 +1029,13 @@ void zsend_srv6_sid_notify(struct zserv *client, const struct srv6_sid_ctx *ctx, stream_putl(s, func); /* SRv6 wide SID function */ stream_putl(s, wide_func); + /* SRv6 locator name optional */ + if (locator_name) { + stream_putw(s, strlen(locator_name)); + stream_put(s, locator_name, strlen(locator_name)); + } else + stream_putw(s, 0); + stream_putw_at(s, 0, stream_get_endp(s)); zserv_send_message(client, s); diff --git a/zebra/zapi_msg.h b/zebra/zapi_msg.h index 3505bc0dc4..9e3ea6fb6e 100644 --- a/zebra/zapi_msg.h +++ b/zebra/zapi_msg.h @@ -97,7 +97,7 @@ extern void zsend_neighbor_notify(int cmd, struct interface *ifp, extern void zsend_srv6_sid_notify(struct zserv *client, const struct srv6_sid_ctx *ctx, struct in6_addr *sid_value, uint32_t func, - uint32_t wide_func, + uint32_t wide_func, const char *locator_name, enum zapi_srv6_sid_notify note); extern int zsend_client_close_notify(struct zserv *client, diff --git a/zebra/zebra_srv6.c b/zebra/zebra_srv6.c index a6db66bbcc..0ca77a4974 100644 --- a/zebra/zebra_srv6.c +++ b/zebra/zebra_srv6.c @@ -2280,7 +2280,7 @@ static int srv6_manager_get_sid_internal(struct zebra_srv6_sid **sid, sid_value ? sid_value : &in6addr_any, locator_name); /* Notify client about SID alloc failure */ - zsend_srv6_sid_notify(client, ctx, sid_value, 0, 0, + zsend_srv6_sid_notify(client, ctx, sid_value, 0, 0, NULL, ZAPI_SRV6_SID_FAIL_ALLOC); } else if (ret == 0) { if (IS_ZEBRA_DEBUG_PACKET) @@ -2294,6 +2294,8 @@ static int srv6_manager_get_sid_internal(struct zebra_srv6_sid **sid, zsend_srv6_sid_notify(client, ctx, &(*sid)->value, (*sid)->func, (*sid)->wide_func, + (*sid)->locator ? (*sid)->locator->name + : NULL, ZAPI_SRV6_SID_ALLOCATED); } else { if (IS_ZEBRA_DEBUG_PACKET) @@ -2308,6 +2310,9 @@ static int srv6_manager_get_sid_internal(struct zebra_srv6_sid **sid, for (ALL_LIST_ELEMENTS_RO((*sid)->client_list, node, c)) zsend_srv6_sid_notify(c, ctx, &(*sid)->value, (*sid)->func, (*sid)->wide_func, + (*sid)->locator + ? (*sid)->locator->name + : NULL, ZAPI_SRV6_SID_ALLOCATED); } @@ -2366,6 +2371,7 @@ static int srv6_manager_release_sid_internal(struct zserv *client, struct zebra_srv6_sid_ctx *zctx; struct listnode *node, *nnode; char buf[256]; + const char *locator_name = NULL; if (IS_ZEBRA_DEBUG_PACKET) zlog_debug("%s: releasing SRv6 SID associated with ctx %s", @@ -2374,6 +2380,9 @@ static int srv6_manager_release_sid_internal(struct zserv *client, /* Lookup Zebra SID context and release it */ for (ALL_LIST_ELEMENTS(srv6->sids, node, nnode, zctx)) if (memcmp(&zctx->ctx, ctx, sizeof(struct srv6_sid_ctx)) == 0) { + if (zctx->sid && zctx->sid->locator) + locator_name = + (const char *)zctx->sid->locator->name; ret = release_srv6_sid(client, zctx); break; } @@ -2383,10 +2392,10 @@ static int srv6_manager_release_sid_internal(struct zserv *client, srv6_sid_ctx2str(buf, sizeof(buf), ctx)); if (ret == 0) - zsend_srv6_sid_notify(client, ctx, NULL, 0, 0, + zsend_srv6_sid_notify(client, ctx, NULL, 0, 0, locator_name, ZAPI_SRV6_SID_RELEASED); else - zsend_srv6_sid_notify(client, ctx, NULL, 0, 0, + zsend_srv6_sid_notify(client, ctx, NULL, 0, 0, locator_name, ZAPI_SRV6_SID_FAIL_RELEASE); return ret; From 83b4706f309a97a1cd6d43e4a028848e94029740 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Tue, 18 Jun 2024 12:06:46 +0300 Subject: [PATCH 068/347] lib: Get the weight from Zebra Signed-off-by: Donatas Abraitis --- lib/zclient.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/zclient.c b/lib/zclient.c index 1aab7b48ba..ca4880da43 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -2134,6 +2134,7 @@ struct nexthop *nexthop_from_zapi_nexthop(const struct zapi_nexthop *znh) n->ifindex = znh->ifindex; n->gate = znh->gate; n->srte_color = znh->srte_color; + n->weight = znh->weight; /* * This function currently handles labels From dbf83cfd36a2c7d32f26a95d6daa70cb2d6d16e7 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Tue, 18 Jun 2024 12:07:23 +0300 Subject: [PATCH 069/347] zebra: Set the weight for non-recursive next-hop If using weighted ECMP, the weight for non-recursive next-hop should be inherited from recursive next-hop. Signed-off-by: Donatas Abraitis --- zebra/zebra_nhg.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 1246e4dba2..55920102bb 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -1747,6 +1747,12 @@ static struct nexthop *nexthop_set_resolved(afi_t afi, SET_FLAG(resolved_hop->flags, NEXTHOP_FLAG_ACTIVE); resolved_hop->vrf_id = nexthop->vrf_id; + + /* Using weighted ECMP, we should respect the weight and use + * the same value for non-recursive next-hop. + */ + resolved_hop->weight = nexthop->weight; + switch (newhop->type) { case NEXTHOP_TYPE_IPV4: case NEXTHOP_TYPE_IPV4_IFINDEX: From 6d5d4f70000622b13ce73c45f69da75092fe35da Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Tue, 18 Jun 2024 12:16:54 +0300 Subject: [PATCH 070/347] tests: Check if recursive weighted ECMP works Signed-off-by: Donatas Abraitis --- .../bgp_weighted_ecmp_recursive/__init__.py | 0 .../bgp_weighted_ecmp_recursive/r1/frr.conf | 16 +++ .../bgp_weighted_ecmp_recursive/r2/frr.conf | 20 ++++ .../bgp_weighted_ecmp_recursive/r3/frr.conf | 20 ++++ .../bgp_weighted_ecmp_recursive/r4/frr.conf | 17 +++ .../bgp_weighted_ecmp_recursive/r5/frr.conf | 17 +++ .../test_bgp_weighted_ecmp_recursive.py | 109 ++++++++++++++++++ 7 files changed, 199 insertions(+) create mode 100644 tests/topotests/bgp_weighted_ecmp_recursive/__init__.py create mode 100644 tests/topotests/bgp_weighted_ecmp_recursive/r1/frr.conf create mode 100644 tests/topotests/bgp_weighted_ecmp_recursive/r2/frr.conf create mode 100644 tests/topotests/bgp_weighted_ecmp_recursive/r3/frr.conf create mode 100644 tests/topotests/bgp_weighted_ecmp_recursive/r4/frr.conf create mode 100644 tests/topotests/bgp_weighted_ecmp_recursive/r5/frr.conf create mode 100644 tests/topotests/bgp_weighted_ecmp_recursive/test_bgp_weighted_ecmp_recursive.py diff --git a/tests/topotests/bgp_weighted_ecmp_recursive/__init__.py b/tests/topotests/bgp_weighted_ecmp_recursive/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/topotests/bgp_weighted_ecmp_recursive/r1/frr.conf b/tests/topotests/bgp_weighted_ecmp_recursive/r1/frr.conf new file mode 100644 index 0000000000..f7c591f75f --- /dev/null +++ b/tests/topotests/bgp_weighted_ecmp_recursive/r1/frr.conf @@ -0,0 +1,16 @@ +! +int r1-eth0 + ip address 192.168.12.1/24 +! +int r1-eth1 + ip address 192.168.13.1/24 +! +router bgp 65000 + no bgp ebgp-requires-policy + neighbor 192.168.12.2 remote-as internal + neighbor 192.168.12.2 timers 1 3 + neighbor 192.168.12.2 timers connect 1 + neighbor 192.168.13.3 remote-as internal + neighbor 192.168.13.3 timers 1 3 + neighbor 192.168.13.3 timers connect 1 +! diff --git a/tests/topotests/bgp_weighted_ecmp_recursive/r2/frr.conf b/tests/topotests/bgp_weighted_ecmp_recursive/r2/frr.conf new file mode 100644 index 0000000000..dc25d4781c --- /dev/null +++ b/tests/topotests/bgp_weighted_ecmp_recursive/r2/frr.conf @@ -0,0 +1,20 @@ +! +int r2-eth0 + ip address 192.168.12.2/24 +! +int r2-eth1 + ip address 192.168.24.2/24 +! +router bgp 65000 + no bgp ebgp-requires-policy + neighbor 192.168.12.1 remote-as internal + neighbor 192.168.12.1 timers 1 3 + neighbor 192.168.12.1 timers connect 1 + neighbor 192.168.24.4 remote-as internal + neighbor 192.168.24.4 timers 1 3 + neighbor 192.168.24.4 timers connect 1 + address-family ipv4 unicast + redistribute connected + neighbor 192.168.12.1 route-reflector-client + exit-address-family +! diff --git a/tests/topotests/bgp_weighted_ecmp_recursive/r3/frr.conf b/tests/topotests/bgp_weighted_ecmp_recursive/r3/frr.conf new file mode 100644 index 0000000000..bdeb35b50f --- /dev/null +++ b/tests/topotests/bgp_weighted_ecmp_recursive/r3/frr.conf @@ -0,0 +1,20 @@ +! +int r3-eth0 + ip address 192.168.13.3/24 +! +int r3-eth1 + ip address 192.168.35.3/24 +! +router bgp 65000 + no bgp ebgp-requires-policy + neighbor 192.168.13.1 remote-as internal + neighbor 192.168.13.1 timers 1 3 + neighbor 192.168.13.1 timers connect 1 + neighbor 192.168.35.5 remote-as internal + neighbor 192.168.35.5 timers 1 3 + neighbor 192.168.35.5 timers connect 1 + address-family ipv4 unicast + redistribute connected + neighbor 192.168.13.1 route-reflector-client + exit-address-family +! diff --git a/tests/topotests/bgp_weighted_ecmp_recursive/r4/frr.conf b/tests/topotests/bgp_weighted_ecmp_recursive/r4/frr.conf new file mode 100644 index 0000000000..0662a4dc49 --- /dev/null +++ b/tests/topotests/bgp_weighted_ecmp_recursive/r4/frr.conf @@ -0,0 +1,17 @@ +! +int r4-eth0 + ip address 192.168.24.4/24 +! +router bgp 65000 + no bgp ebgp-requires-policy + no bgp network import-check + neighbor 192.168.24.2 remote-as internal + neighbor 192.168.24.2 timers 1 3 + neighbor 192.168.24.2 timers connect 1 + address-family ipv4 unicast + network 10.10.10.10/32 route-map rmap + exit-address-family +! +route-map rmap permit 10 + set extcommunity bandwidth 4000 +exit diff --git a/tests/topotests/bgp_weighted_ecmp_recursive/r5/frr.conf b/tests/topotests/bgp_weighted_ecmp_recursive/r5/frr.conf new file mode 100644 index 0000000000..bc24a96b51 --- /dev/null +++ b/tests/topotests/bgp_weighted_ecmp_recursive/r5/frr.conf @@ -0,0 +1,17 @@ +! +int r5-eth0 + ip address 192.168.35.5/24 +! +router bgp 65000 + no bgp ebgp-requires-policy + no bgp network import-check + neighbor 192.168.35.3 remote-as internal + neighbor 192.168.35.3 timers 1 3 + neighbor 192.168.35.3 timers connect 1 + address-family ipv4 unicast + network 10.10.10.10/32 route-map rmap + exit-address-family +! +route-map rmap permit 10 + set extcommunity bandwidth 5000 +exit diff --git a/tests/topotests/bgp_weighted_ecmp_recursive/test_bgp_weighted_ecmp_recursive.py b/tests/topotests/bgp_weighted_ecmp_recursive/test_bgp_weighted_ecmp_recursive.py new file mode 100644 index 0000000000..7a6d068e56 --- /dev/null +++ b/tests/topotests/bgp_weighted_ecmp_recursive/test_bgp_weighted_ecmp_recursive.py @@ -0,0 +1,109 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# Copyright (c) 2024 by +# Donatas Abraitis +# + +""" +Test if weighted ECMP works and recursive weight (link bandwidth) is +inherited to non-recursive next-hops. +""" + +import os +import re +import sys +import json +import pytest +import functools + +pytestmark = [pytest.mark.bgpd] + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.common_config import step + + +def setup_module(mod): + topodef = { + "s1": ("r1", "r2"), + "s2": ("r1", "r3"), + "s3": ("r2", "r4"), + "s4": ("r3", "r5"), + } + tgen = Topogen(topodef, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + + for _, (rname, router) in enumerate(router_list.items(), 1): + router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname))) + + tgen.start_router() + + +def teardown_module(mod): + tgen = get_topogen() + tgen.stop_topology() + + +def test_bgp_weighted_ecmp_recursive(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.gears["r1"] + + def _bgp_converge(): + output = json.loads(r1.vtysh_cmd("show ip route 10.10.10.10/32 json")) + expected = { + "10.10.10.10/32": [ + { + "selected": True, + "installed": True, + "nexthops": [ + { + "ip": "192.168.24.4", + "active": True, + "recursive": True, + "weight": 204, + }, + { + "ip": "192.168.12.2", + "active": True, + "resolver": True, + "weight": 204, + }, + { + "ip": "192.168.35.5", + "active": True, + "recursive": True, + "weight": 255, + }, + { + "ip": "192.168.13.3", + "active": True, + "resolver": True, + "weight": 255, + }, + ], + } + ] + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _bgp_converge, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Can't converge" + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) From 073fec520c75d2468bd0eff0933feaab3283449c Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Tue, 18 Jun 2024 12:11:44 +0200 Subject: [PATCH 071/347] lib: add json API to dump and override row naming convention The following table is not compliant with caml format when displayed in json: > ttable_add_row( > tt, > "Vertex|Type|Metric|Next-Hop|Interface|Parent"); > > ttable_json(tt, "ssdsss"); output observed: > [..] > { > "Vertex":"r1", > "Type":"", > "Metric":0, > "Next-Hop":"", > "Interface":"", > "Parent":"" > } output expected: > [..] > { > "vertex":"r1", > "type":"", > "metric":0, > "nextHop":"", > "interface":"", > "parent":"" > } Override the ttable_json() function with a new function which has an extra paramter: this parameter will redefine the initial row value for json: > ttable_json_with_json_text(tt, > "vertex|type|metric|nextHop|interface|parent"); Signed-off-by: Philippe Guibert --- lib/termtable.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++-- lib/termtable.h | 15 ++++++++++++++ 2 files changed, 65 insertions(+), 2 deletions(-) diff --git a/lib/termtable.c b/lib/termtable.c index 9b36d5ebfa..88cc25bf68 100644 --- a/lib/termtable.c +++ b/lib/termtable.c @@ -496,7 +496,9 @@ char *ttable_dump(struct ttable *tt, const char *newline) * l int64 * s string (default) */ -json_object *ttable_json(struct ttable *tt, const char *const formats) +static json_object *ttable_json_internal(struct ttable *tt, + const char *const formats, + const char *row_text[]) { struct ttable_cell *row; /* iteration pointers */ json_object *json = NULL; @@ -522,9 +524,55 @@ json_object *ttable_json(struct ttable *tt, const char *const formats) default: val = json_object_new_string(row[j].text); } - json_object_object_add(jobj, tt->table[0][j].text, val); + if (row_text) + json_object_object_add(jobj, row_text[j], val); + else + json_object_object_add(jobj, + tt->table[0][j].text, + val); } } return json; } + +json_object *ttable_json(struct ttable *tt, const char *const formats) +{ + return ttable_json_internal(tt, formats, NULL); +} + +json_object *ttable_json_with_json_text(struct ttable *tt, + const char *const formats, + const char *json_override_text) +{ + char **row_name; /* iteration pointers */ + char *res, *section, *orig; + int col = 0; + int ncols = 0, j; + json_object *json = NULL; + + if (json_override_text) { + /* count how many columns we have */ + for (j = 0; json_override_text[j]; j++) + ncols += !!(json_override_text[j] == '|'); + ncols++; + } + if (json_override_text == NULL || ncols != tt->ncols) + return ttable_json_internal(tt, formats, NULL); + + /* CALLOC a block of cells */ + row_name = XCALLOC(MTYPE_TTABLE, ncols * sizeof(char *)); + orig = XSTRDUP(MTYPE_TTABLE, json_override_text); + res = orig; + while (res && col < ncols) { + section = strsep(&res, "|"); + row_name[col] = XSTRDUP(MTYPE_TTABLE, section); + col++; + } + json = ttable_json_internal(tt, formats, (const char **)row_name); + for (j = 0; j < col; j++) + XFREE(MTYPE_TTABLE, row_name[j]); + XFREE(MTYPE_TTABLE, row_name); + XFREE(MTYPE_TTABLE, orig); + return json; +} diff --git a/lib/termtable.h b/lib/termtable.h index 7258682bd8..0782c82abd 100644 --- a/lib/termtable.h +++ b/lib/termtable.h @@ -289,6 +289,21 @@ char *ttable_dump(struct ttable *tt, const char *newline); */ json_object *ttable_json(struct ttable *tt, const char *const formats); +/** + * Convert a table to a JSON array of objects. + * + * Caller must free the returned json_object structure. + * + * @param tt the table to convert + * @param formats an array of characters indicating what JSON type should be + * used. + * @param formats an optinal string of row headers that overrids the first row of the table. + * This is useful to get naming convention that align with caml Format. + */ +json_object *ttable_json_with_json_text(struct ttable *tt, + const char *const formats, + const char *json_override_text); + #ifdef __cplusplus } #endif From 73bfc5865f4ded8297096bbdb3cc67b1ba54600f Mon Sep 17 00:00:00 2001 From: Carmine Scarpitta Date: Sat, 23 Mar 2024 19:40:13 +0100 Subject: [PATCH 072/347] isisd: Add API to get SRv6 locator info Add an API to request information from the SRv6 SID Manager (zebra) regarding a specific SRv6 locator. Signed-off-by: Carmine Scarpitta --- isisd/isis_zebra.c | 18 ++++++++++++++++++ isisd/isis_zebra.h | 2 ++ 2 files changed, 20 insertions(+) diff --git a/isisd/isis_zebra.c b/isisd/isis_zebra.c index 2412ec5e84..f5b3f712be 100644 --- a/isisd/isis_zebra.c +++ b/isisd/isis_zebra.c @@ -1368,6 +1368,24 @@ int isis_zebra_srv6_manager_release_locator_chunk(const char *name) return srv6_manager_release_locator_chunk(zclient, name); } +/** + * Ask the SRv6 Manager (zebra) about a specific locator + * + * @param name Locator name + * @return 0 on success, -1 otherwise + */ +int isis_zebra_srv6_manager_get_locator(const char *name) +{ + if (!name) + return -1; + + /* + * Send the Get Locator request to the SRv6 Manager and return the + * result + */ + return srv6_manager_get_locator(zclient, name); +} + static zclient_handler *const isis_handlers[] = { [ZEBRA_ROUTER_ID_UPDATE] = isis_router_id_update_zebra, [ZEBRA_INTERFACE_ADDRESS_ADD] = isis_zebra_if_address_add, diff --git a/isisd/isis_zebra.h b/isisd/isis_zebra.h index f1684b7c25..bfd23f69f4 100644 --- a/isisd/isis_zebra.h +++ b/isisd/isis_zebra.h @@ -68,4 +68,6 @@ void isis_zebra_srv6_adj_sid_uninstall(struct srv6_adjacency *sra); extern int isis_zebra_srv6_manager_get_locator_chunk(const char *name); extern int isis_zebra_srv6_manager_release_locator_chunk(const char *name); +extern int isis_zebra_srv6_manager_get_locator(const char *name); + #endif /* _ZEBRA_ISIS_ZEBRA_H */ From 3fce2928e293c59bb63ef76455525dca602385dd Mon Sep 17 00:00:00 2001 From: Carmine Scarpitta Date: Thu, 9 May 2024 11:23:53 +0200 Subject: [PATCH 073/347] isisd: Add API to get/release SRv6 SIDs Add an API to get/release SRv6 SIDs through the SRv6 SID Manager. Signed-off-by: Carmine Scarpitta --- isisd/isis_zebra.c | 97 ++++++++++++++++++++++++++++++++++++++++++++++ isisd/isis_zebra.h | 5 +++ 2 files changed, 102 insertions(+) diff --git a/isisd/isis_zebra.c b/isisd/isis_zebra.c index f5b3f712be..226ee56796 100644 --- a/isisd/isis_zebra.c +++ b/isisd/isis_zebra.c @@ -644,6 +644,40 @@ int isis_zebra_request_label_range(uint32_t base, uint32_t chunk_size) return 0; } +/** + * Request an End.X SID for an IS-IS adjacency. + * + * @param adj IS-IS Adjacency + */ +void isis_zebra_request_srv6_sid_endx(struct isis_adjacency *adj) +{ + struct isis_circuit *circuit = adj->circuit; + struct isis_area *area = circuit->area; + struct in6_addr nexthop; + struct srv6_sid_ctx ctx = {}; + struct in6_addr sid_value = {}; + bool ret; + + if (!area || !area->srv6db.srv6_locator) + return; + + /* Determine nexthop IP address */ + if (!circuit->ipv6_router || !adj->ll_ipv6_count) + return; + + nexthop = adj->ll_ipv6_addrs[0]; + + ctx.behavior = ZEBRA_SEG6_LOCAL_ACTION_END_X; + ctx.nh6 = nexthop; + ret = isis_zebra_request_srv6_sid(&ctx, &sid_value, + area->srv6db.config.srv6_locator_name); + if (!ret) { + zlog_err("%s: not allocated new End.X SID for IS-IS area %s", + __func__, area->area_tag); + return; + } +} + /** * Release Label Range to the Label Manager. * @@ -1386,6 +1420,69 @@ int isis_zebra_srv6_manager_get_locator(const char *name) return srv6_manager_get_locator(zclient, name); } +/** + * Ask the SRv6 Manager (zebra) to allocate a SID. + * + * Optionally, it is possible to provide an IPv6 address (sid_value parameter). + * + * When sid_value is provided, the SRv6 Manager allocates the requested SID + * address, if the request can be satisfied (explicit allocation). + * + * When sid_value is not provided, the SRv6 Manager allocates any available SID + * from the provided locator (dynamic allocation). + * + * @param ctx Context to be associated with the request SID + * @param sid_value IPv6 address to be associated with the requested SID (optional) + * @param locator_name Name of the locator from which the SID must be allocated + */ +bool isis_zebra_request_srv6_sid(const struct srv6_sid_ctx *ctx, + struct in6_addr *sid_value, + const char *locator_name) +{ + int ret; + + if (!ctx || !locator_name) + return false; + + /* + * Send the Get SRv6 SID request to the SRv6 Manager and check the + * result + */ + ret = srv6_manager_get_sid(zclient, ctx, sid_value, locator_name, NULL); + if (ret < 0) { + zlog_warn("%s: error getting SRv6 SID!", __func__); + return false; + } + + return true; +} + +/** + * Ask the SRv6 Manager (zebra) to release a previously allocated SID. + * + * This function is used to tell the SRv6 Manager that IS-IS no longer intends + * to use the SID. + * + * @param ctx Context to be associated with the SID to be released + */ +void isis_zebra_release_srv6_sid(const struct srv6_sid_ctx *ctx) +{ + int ret; + + if (!ctx) + return; + + /* + * Send the Release SRv6 SID request to the SRv6 Manager and check the + * result + */ + ret = srv6_manager_release_sid(zclient, ctx); + if (ret < 0) { + zlog_warn("%s: error releasing SRv6 SID!", __func__); + return; + } +} + static zclient_handler *const isis_handlers[] = { [ZEBRA_ROUTER_ID_UPDATE] = isis_router_id_update_zebra, [ZEBRA_INTERFACE_ADDRESS_ADD] = isis_zebra_if_address_add, diff --git a/isisd/isis_zebra.h b/isisd/isis_zebra.h index bfd23f69f4..79da16efac 100644 --- a/isisd/isis_zebra.h +++ b/isisd/isis_zebra.h @@ -69,5 +69,10 @@ extern int isis_zebra_srv6_manager_get_locator_chunk(const char *name); extern int isis_zebra_srv6_manager_release_locator_chunk(const char *name); extern int isis_zebra_srv6_manager_get_locator(const char *name); +extern void isis_zebra_request_srv6_sid_endx(struct isis_adjacency *adj); +extern bool isis_zebra_request_srv6_sid(const struct srv6_sid_ctx *ctx, + struct in6_addr *sid_value, + const char *locator_name); +extern void isis_zebra_release_srv6_sid(const struct srv6_sid_ctx *ctx); #endif /* _ZEBRA_ISIS_ZEBRA_H */ From 9ae38eede814b14051179fb96f9d77ac04a45bf9 Mon Sep 17 00:00:00 2001 From: Carmine Scarpitta Date: Thu, 9 May 2024 09:17:49 +0200 Subject: [PATCH 074/347] isisd: Deal with SRv6 locator instead of chunk Currently, when SRv6 is enabled in IS-IS, IS-IS requests a locator chunk from Zebra. Zebra assigns a locator chunk to IS-IS, and then IS-IS can allocate SIDs from the locator chunk. Recently, the implementation of SRv6 in Zebra has been improved, and a new API has been introduced for obtaining/releasing the SIDs. Now, the daemons no longer need to request a chunk. Instead, the daemons interact with Zebra to obtain information about the locator and subsequently to allocate/release the SIDs. This commit extends IS-IS to use the new SRv6 API. In particular, it removes the chunk throughout the IS-IS code and modifies IS-IS to request/save/advertise the locator instead of the chunk. Signed-off-by: Carmine Scarpitta --- isisd/isis_lsp.c | 13 +++----- isisd/isis_nb_config.c | 6 ++-- isisd/isis_srv6.c | 74 ++++++++++++++++++++++-------------------- isisd/isis_srv6.h | 8 +++-- isisd/isis_zebra.c | 3 ++ 5 files changed, 53 insertions(+), 51 deletions(-) diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c index c98cee06a5..13f5148d4a 100644 --- a/isisd/isis_lsp.c +++ b/isisd/isis_lsp.c @@ -1222,17 +1222,11 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area) } /* Add SRv6 Locator TLV. */ - if (area->srv6db.config.enabled && - !list_isempty(area->srv6db.srv6_locator_chunks)) { + if (area->srv6db.config.enabled && area->srv6db.srv6_locator) { struct isis_srv6_locator locator = {}; - struct srv6_locator_chunk *chunk; - - /* TODO: support more than one locator */ - chunk = (struct srv6_locator_chunk *)listgetdata( - listhead(area->srv6db.srv6_locator_chunks)); locator.metric = 0; - locator.prefix = chunk->prefix; + locator.prefix = area->srv6db.srv6_locator->prefix; locator.flags = 0; locator.algorithm = 0; @@ -1252,7 +1246,8 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area) isis_tlvs_add_ipv6_reach(lsp->tlvs, isis_area_ipv6_topology(area), - &chunk->prefix, 0, false, NULL); + &area->srv6db.srv6_locator->prefix, 0, + false, NULL); } /* IPv4 address and TE router ID TLVs. diff --git a/isisd/isis_nb_config.c b/isisd/isis_nb_config.c index 763b8b73d2..30c90baa54 100644 --- a/isisd/isis_nb_config.c +++ b/isisd/isis_nb_config.c @@ -3518,10 +3518,10 @@ int isis_instance_segment_routing_srv6_locator_modify( 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); + sr_debug("Trying to get locator %s for IS-IS area %s", loc_name, + area->area_tag); - if (isis_zebra_srv6_manager_get_locator_chunk(loc_name) < 0) + if (isis_zebra_srv6_manager_get_locator(loc_name) < 0) return NB_ERR; return NB_OK; diff --git a/isisd/isis_srv6.c b/isisd/isis_srv6.c index 44fd599cbb..7cf1d91b46 100644 --- a/isisd/isis_srv6.c +++ b/isisd/isis_srv6.c @@ -146,6 +146,10 @@ bool isis_srv6_locator_unset(struct isis_area *area) srv6_locator_chunk_free(&chunk); } + /* Clear locator */ + srv6_locator_free(area->srv6db.srv6_locator); + area->srv6db.srv6_locator = NULL; + /* Clear locator name */ memset(area->srv6db.config.srv6_locator_name, 0, sizeof(area->srv6db.config.srv6_locator_name)); @@ -235,16 +239,16 @@ static bool sid_exist(struct isis_area *area, const struct in6_addr *sid) * Request a SID from the SRv6 locator. * * @param area IS-IS area - * @param chunk SRv6 locator chunk + * @param locator SRv6 locator * @param sid_func The FUNCTION part of the SID to be allocated (a negative * number will allocate the first available SID) * * @return First available SID on success or in6addr_any if the SRv6 - * locator chunk is full + * locator is full */ -static struct in6_addr -srv6_locator_request_sid(struct isis_area *area, - struct srv6_locator_chunk *chunk, int sid_func) +static struct in6_addr srv6_locator_request_sid(struct isis_area *area, + struct srv6_locator *locator, + int sid_func) { struct in6_addr sid; uint8_t offset = 0; @@ -252,22 +256,22 @@ srv6_locator_request_sid(struct isis_area *area, uint32_t func_max; bool allocated = false; - if (!area || !chunk) + if (!area || !locator) return in6addr_any; sr_debug("ISIS-SRv6 (%s): requested new SID from locator %s", - area->area_tag, chunk->locator_name); + area->area_tag, locator->name); /* Let's build the SID, step by step. A SID has the following structure (defined in RFC 8986): LOCATOR:FUNCTION:ARGUMENT.*/ /* First, we encode the LOCATOR in the L most significant bits. */ - sid = chunk->prefix.prefix; + sid = locator->prefix.prefix; /* The next part of the SID is the FUNCTION. Let's compute the length * and the offset of the FUNCTION in the SID */ - func_len = chunk->function_bits_length; - offset = chunk->block_bits_length + chunk->node_bits_length; + func_len = locator->function_bits_length; + offset = locator->block_bits_length + locator->node_bits_length; /* Then, encode the FUNCTION */ if (sid_func >= 0) { @@ -298,7 +302,7 @@ srv6_locator_request_sid(struct isis_area *area, if (!allocated) { /* We ran out of available SIDs */ zlog_warn("ISIS-SRv6 (%s): no SIDs available in locator %s", - area->area_tag, chunk->locator_name); + area->area_tag, locator->name); return in6addr_any; } @@ -312,35 +316,34 @@ srv6_locator_request_sid(struct isis_area *area, * Allocate an SRv6 SID from an SRv6 locator. * * @param area IS-IS area - * @param chunk SRv6 locator chunk + * @param locator SRv6 locator * @param behavior SRv6 Endpoint Behavior bound to the SID * * @result the allocated SID on success, NULL otherwise */ struct isis_srv6_sid * -isis_srv6_sid_alloc(struct isis_area *area, struct srv6_locator_chunk *chunk, - enum srv6_endpoint_behavior_codepoint behavior, - int sid_func) +isis_srv6_sid_alloc(struct isis_area *area, struct srv6_locator *locator, + enum srv6_endpoint_behavior_codepoint behavior, int sid_func) { struct isis_srv6_sid *sid = NULL; - if (!area || !chunk) + if (!area || !locator) return NULL; sid = XCALLOC(MTYPE_ISIS_SRV6_SID, sizeof(struct isis_srv6_sid)); - sid->sid = srv6_locator_request_sid(area, chunk, sid_func); + sid->sid = srv6_locator_request_sid(area, locator, sid_func); if (IPV6_ADDR_SAME(&sid->sid, &in6addr_any)) { isis_srv6_sid_free(sid); return NULL; } sid->behavior = behavior; - sid->structure.loc_block_len = chunk->block_bits_length; - sid->structure.loc_node_len = chunk->node_bits_length; - sid->structure.func_len = chunk->function_bits_length; - sid->structure.arg_len = chunk->argument_bits_length; - sid->locator = chunk; + sid->structure.loc_block_len = locator->block_bits_length; + sid->structure.loc_node_len = locator->node_bits_length; + sid->structure.func_len = locator->function_bits_length; + sid->structure.arg_len = locator->argument_bits_length; + sid->locator = locator; sid->area = area; return sid; @@ -387,11 +390,10 @@ void srv6_endx_sid_add_single(struct isis_adjacency *adj, bool backup, struct isis_srv6_lan_endx_sid_subtlv *ladj_sid; struct in6_addr nexthop; uint8_t flags = 0; - struct srv6_locator_chunk *chunk; + struct srv6_locator *locator; uint32_t behavior; - if (!area || !area->srv6db.srv6_locator_chunks || - list_isempty(area->srv6db.srv6_locator_chunks)) + if (!area || !area->srv6db.srv6_locator) return; sr_debug("ISIS-SRv6 (%s): Add %s End.X SID", area->area_tag, @@ -401,10 +403,7 @@ void srv6_endx_sid_add_single(struct isis_adjacency *adj, bool backup, if (!circuit->ipv6_router || !adj->ll_ipv6_count) return; - chunk = (struct srv6_locator_chunk *)listgetdata( - listhead(area->srv6db.srv6_locator_chunks)); - if (!chunk) - return; + locator = area->srv6db.srv6_locator; nexthop = adj->ll_ipv6_addrs[0]; @@ -415,21 +414,21 @@ void srv6_endx_sid_add_single(struct isis_adjacency *adj, bool backup, if (circuit->ext == NULL) circuit->ext = isis_alloc_ext_subtlvs(); - behavior = (CHECK_FLAG(chunk->flags, SRV6_LOCATOR_USID)) + behavior = (CHECK_FLAG(locator->flags, SRV6_LOCATOR_USID)) ? SRV6_ENDPOINT_BEHAVIOR_END_X_NEXT_CSID : SRV6_ENDPOINT_BEHAVIOR_END_X; sra = XCALLOC(MTYPE_ISIS_SRV6_INFO, sizeof(*sra)); sra->type = backup ? ISIS_SRV6_ADJ_BACKUP : ISIS_SRV6_ADJ_NORMAL; sra->behavior = behavior; - sra->locator = chunk; - sra->structure.loc_block_len = chunk->block_bits_length; - sra->structure.loc_node_len = chunk->node_bits_length; - sra->structure.func_len = chunk->function_bits_length; - sra->structure.arg_len = chunk->argument_bits_length; + sra->locator = locator; + sra->structure.loc_block_len = locator->block_bits_length; + sra->structure.loc_node_len = locator->node_bits_length; + sra->structure.func_len = locator->function_bits_length; + sra->structure.arg_len = locator->argument_bits_length; sra->nexthop = nexthop; - sra->sid = srv6_locator_request_sid(area, chunk, -1); + sra->sid = srv6_locator_request_sid(area, locator, -1); if (IPV6_ADDR_SAME(&sra->sid, &in6addr_any)) { XFREE(MTYPE_ISIS_SRV6_INFO, sra); return; @@ -832,6 +831,9 @@ void isis_srv6_area_term(struct isis_area *area) srv6_locator_chunk_free(&chunk); list_delete(&srv6db->srv6_locator_chunks); + srv6_locator_free(area->srv6db.srv6_locator); + area->srv6db.srv6_locator = NULL; + /* Free SRv6 SIDs list */ list_delete(&srv6db->srv6_sids); list_delete(&srv6db->srv6_endx_sids); diff --git a/isisd/isis_srv6.h b/isisd/isis_srv6.h index 7f16712ae3..6abc6d7345 100644 --- a/isisd/isis_srv6.h +++ b/isisd/isis_srv6.h @@ -44,7 +44,7 @@ struct isis_srv6_sid { struct isis_srv6_sid_structure structure; /* Parent SRv6 locator */ - struct srv6_locator_chunk *locator; + struct srv6_locator *locator; /* Backpointer to IS-IS area */ struct isis_area *area; @@ -89,7 +89,7 @@ struct srv6_adjacency { struct isis_srv6_sid_structure structure; /* Parent SRv6 locator */ - struct srv6_locator_chunk *locator; + struct srv6_locator *locator; /* Adjacency-SID nexthop information */ struct in6_addr nexthop; @@ -109,6 +109,8 @@ struct srv6_adjacency { /* Per-area IS-IS SRv6 Data Base (SRv6 DB) */ struct isis_srv6_db { + /* List of SRv6 Locator */ + struct srv6_locator *srv6_locator; /* List of SRv6 Locator chunks */ struct list *srv6_locator_chunks; @@ -149,7 +151,7 @@ bool isis_srv6_locator_unset(struct isis_area *area); void isis_srv6_interface_set(struct isis_area *area, const char *ifname); struct isis_srv6_sid * -isis_srv6_sid_alloc(struct isis_area *area, struct srv6_locator_chunk *chunk, +isis_srv6_sid_alloc(struct isis_area *area, struct srv6_locator *locator, enum srv6_endpoint_behavior_codepoint behavior, int sid_func); extern void isis_srv6_sid_free(struct isis_srv6_sid *sid); diff --git a/isisd/isis_zebra.c b/isisd/isis_zebra.c index 226ee56796..44ef182ba9 100644 --- a/isisd/isis_zebra.c +++ b/isisd/isis_zebra.c @@ -1369,6 +1369,9 @@ static int isis_zebra_process_srv6_locator_delete(ZAPI_CALLBACK_ARGS) } } + srv6_locator_free(area->srv6db.srv6_locator); + area->srv6db.srv6_locator = NULL; + /* Regenerate LSPs to advertise that the locator no longer * exists */ lsp_regenerate_schedule(area, area->is_type, 0); From 1224d15653b98db5b6a7c671501b7ec80b3ce649 Mon Sep 17 00:00:00 2001 From: Carmine Scarpitta Date: Mon, 25 Mar 2024 00:41:50 +0100 Subject: [PATCH 075/347] isisd: Receive SRv6 locator info from zebra This commit extends IS-IS to process locator information received from SRv6 Manager (zebra) and save the locator info in the SRv6 database. Signed-off-by: Carmine Scarpitta --- isisd/isis_zebra.c | 107 +++++++++++++++++++++++++++++++++------------ 1 file changed, 78 insertions(+), 29 deletions(-) diff --git a/isisd/isis_zebra.c b/isisd/isis_zebra.c index 44ef182ba9..be8bb5c406 100644 --- a/isisd/isis_zebra.c +++ b/isisd/isis_zebra.c @@ -678,6 +678,36 @@ void isis_zebra_request_srv6_sid_endx(struct isis_adjacency *adj) } } +static void request_srv6_sids(struct isis_area *area) +{ + struct srv6_sid_ctx ctx = {}; + struct in6_addr sid_value = {}; + struct listnode *node; + struct isis_adjacency *adj; + bool ret; + + if (!area || !area->srv6db.config.enabled || !area->srv6db.srv6_locator) + return; + + sr_debug("Requesting SRv6 SIDs for IS-IS area %s", area->area_tag); + + /* Request new SRv6 End SID */ + ctx.behavior = ZEBRA_SEG6_LOCAL_ACTION_END; + ret = isis_zebra_request_srv6_sid(&ctx, &sid_value, + area->srv6db.config.srv6_locator_name); + if (!ret) { + zlog_err("%s: not allocated new End SID for IS-IS area %s", + __func__, area->area_tag); + return; + } + + /* Create SRv6 End.X SIDs from existing IS-IS Adjacencies */ + for (ALL_LIST_ELEMENTS_RO(area->adjacency_list, node, adj)) { + if (adj->ll_ipv6_count > 0) + isis_zebra_request_srv6_sid_endx(adj); + } +} + /** * Release Label Range to the Label Manager. * @@ -1251,6 +1281,53 @@ static int isis_zebra_process_srv6_locator_chunk(ZAPI_CALLBACK_ARGS) return 0; } +/** + * Internal function to process an SRv6 locator + * + * @param locator The locator to be processed + */ +static int isis_zebra_process_srv6_locator_internal(struct srv6_locator *locator) +{ + struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT); + struct isis_area *area; + struct listnode *node; + + if (!isis || !locator) + return -1; + + zlog_info("%s: Received SRv6 locator %s %pFX, loc-block-len=%u, loc-node-len=%u func-len=%u, arg-len=%u", + __func__, locator->name, &locator->prefix, + locator->block_bits_length, locator->node_bits_length, + locator->function_bits_length, locator->argument_bits_length); + + /* Walk through all areas of the ISIS instance */ + for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) { + /* + * Check if the IS-IS area is configured to use the received + * locator + */ + if (strncmp(area->srv6db.config.srv6_locator_name, locator->name, + sizeof(area->srv6db.config.srv6_locator_name)) != 0) { + zlog_err("%s: SRv6 Locator name unmatch %s:%s", + __func__, area->srv6db.config.srv6_locator_name, + locator->name); + continue; + } + + sr_debug("SRv6 locator (locator %s, prefix %pFX) set for IS-IS area %s", + locator->name, &locator->prefix, area->area_tag); + + /* Store the locator in the IS-IS area */ + area->srv6db.srv6_locator = srv6_locator_alloc(locator->name); + srv6_locator_copy(area->srv6db.srv6_locator, locator); + + /* Request SIDs from the locator */ + request_srv6_sids(area); + } + + return 0; +} + /** * Callback to process an SRv6 locator received from SRv6 Manager (zebra). * @@ -1260,8 +1337,6 @@ static int isis_zebra_process_srv6_locator_add(ZAPI_CALLBACK_ARGS) { struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT); struct srv6_locator loc = {}; - struct listnode *node; - struct isis_area *area; if (!isis) return -1; @@ -1270,33 +1345,7 @@ static int isis_zebra_process_srv6_locator_add(ZAPI_CALLBACK_ARGS) if (zapi_srv6_locator_decode(zclient->ibuf, &loc) < 0) return -1; - sr_debug( - "New SRv6 locator allocated in zebra: name %s, " - "prefix %pFX, block_len %u, node_len %u, func_len %u, arg_len %u", - loc.name, &loc.prefix, loc.block_bits_length, - loc.node_bits_length, loc.function_bits_length, - loc.argument_bits_length); - - /* Lookup on the IS-IS areas */ - for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) { - /* If SRv6 is enabled on this area and the configured locator - * corresponds to the new locator, then request a chunk from the - * locator */ - if (area->srv6db.config.enabled && - strncmp(area->srv6db.config.srv6_locator_name, loc.name, - sizeof(area->srv6db.config.srv6_locator_name)) == 0) { - sr_debug( - "Sending a request to get a chunk from the SRv6 locator %s (%pFX) " - "for IS-IS area %s", - loc.name, &loc.prefix, area->area_tag); - - if (isis_zebra_srv6_manager_get_locator_chunk( - loc.name) < 0) - return -1; - } - } - - return 0; + return isis_zebra_process_srv6_locator_internal(&loc); } /** From 38a62df517bf86941ce60410ab332d893c6b8b2e Mon Sep 17 00:00:00 2001 From: Carmine Scarpitta Date: Thu, 9 May 2024 13:00:30 +0200 Subject: [PATCH 076/347] isisd: Request SRv6 SIDs to SID Manager Currently, IS-IS allocates SIDs without interacting with Zebra. Recently, the SRv6 implementation has been improved. Now, the daemons need to interact with Zebra through ZAPI to obtain and release SIDs. This commit extends IS-IS to request SIDs from Zebra instead of allocating the SIDs on its own. Signed-off-by: Carmine Scarpitta --- isisd/isis_srv6.c | 27 +++++++++++---------------- isisd/isis_srv6.h | 6 +++--- 2 files changed, 14 insertions(+), 19 deletions(-) diff --git a/isisd/isis_srv6.c b/isisd/isis_srv6.c index 7cf1d91b46..0cd7f847f8 100644 --- a/isisd/isis_srv6.c +++ b/isisd/isis_srv6.c @@ -318,25 +318,23 @@ static struct in6_addr srv6_locator_request_sid(struct isis_area *area, * @param area IS-IS area * @param locator SRv6 locator * @param behavior SRv6 Endpoint Behavior bound to the SID + * @param sid_value SRv6 SID value * * @result the allocated SID on success, NULL otherwise */ struct isis_srv6_sid * isis_srv6_sid_alloc(struct isis_area *area, struct srv6_locator *locator, - enum srv6_endpoint_behavior_codepoint behavior, int sid_func) + enum srv6_endpoint_behavior_codepoint behavior, + struct in6_addr *sid_value) { struct isis_srv6_sid *sid = NULL; - if (!area || !locator) + if (!area || !locator || !sid_value) return NULL; sid = XCALLOC(MTYPE_ISIS_SRV6_SID, sizeof(struct isis_srv6_sid)); - sid->sid = srv6_locator_request_sid(area, locator, sid_func); - if (IPV6_ADDR_SAME(&sid->sid, &in6addr_any)) { - isis_srv6_sid_free(sid); - return NULL; - } + sid->sid = *sid_value; sid->behavior = behavior; sid->structure.loc_block_len = locator->block_bits_length; @@ -379,9 +377,10 @@ void isis_area_delete_backup_srv6_endx_sids(struct isis_area *area, int level) * @param adj IS-IS Adjacency * @param backup True to initialize backup Adjacency SID * @param nexthops List of backup nexthops (for backup End.X SIDs only) + * @param sid_value SID value associated to be associated with the adjacency */ void srv6_endx_sid_add_single(struct isis_adjacency *adj, bool backup, - struct list *nexthops) + struct list *nexthops, struct in6_addr *sid_value) { struct isis_circuit *circuit = adj->circuit; struct isis_area *area = circuit->area; @@ -428,11 +427,7 @@ void srv6_endx_sid_add_single(struct isis_adjacency *adj, bool backup, sra->structure.arg_len = locator->argument_bits_length; sra->nexthop = nexthop; - sra->sid = srv6_locator_request_sid(area, locator, -1); - if (IPV6_ADDR_SAME(&sra->sid, &in6addr_any)) { - XFREE(MTYPE_ISIS_SRV6_INFO, sra); - return; - } + sra->sid = *sid_value; switch (circuit->circ_type) { /* SRv6 LAN End.X SID for Broadcast interface section #8.2 */ @@ -504,9 +499,9 @@ void srv6_endx_sid_add_single(struct isis_adjacency *adj, bool backup, * * @param adj IS-IS Adjacency */ -void srv6_endx_sid_add(struct isis_adjacency *adj) +void srv6_endx_sid_add(struct isis_adjacency *adj, struct in6_addr *sid_value) { - srv6_endx_sid_add_single(adj, false, NULL); + srv6_endx_sid_add_single(adj, false, NULL, sid_value); } /** @@ -609,7 +604,7 @@ static int srv6_adj_ip_enabled(struct isis_adjacency *adj, int family, family != AF_INET6) return 0; - srv6_endx_sid_add(adj); + isis_zebra_request_srv6_sid_endx(adj); return 0; } diff --git a/isisd/isis_srv6.h b/isisd/isis_srv6.h index 6abc6d7345..bde14965f6 100644 --- a/isisd/isis_srv6.h +++ b/isisd/isis_srv6.h @@ -153,7 +153,7 @@ void isis_srv6_interface_set(struct isis_area *area, const char *ifname); struct isis_srv6_sid * isis_srv6_sid_alloc(struct isis_area *area, struct srv6_locator *locator, enum srv6_endpoint_behavior_codepoint behavior, - int sid_func); + struct in6_addr *sid_value); extern void isis_srv6_sid_free(struct isis_srv6_sid *sid); extern void isis_srv6_area_init(struct isis_area *area); @@ -171,8 +171,8 @@ void isis_srv6_locator2tlv(const struct isis_srv6_locator *loc, struct isis_srv6_locator_tlv *loc_tlv); void srv6_endx_sid_add_single(struct isis_adjacency *adj, bool backup, - struct list *nexthops); -void srv6_endx_sid_add(struct isis_adjacency *adj); + struct list *nexthops, struct in6_addr *sid_value); +void srv6_endx_sid_add(struct isis_adjacency *adj, struct in6_addr *sid_value); void srv6_endx_sid_del(struct srv6_adjacency *sra); struct srv6_adjacency *isis_srv6_endx_sid_find(struct isis_adjacency *adj, enum srv6_adj_type type); From 7c203a05bf1b3c9e734a819ad42874673aff2e47 Mon Sep 17 00:00:00 2001 From: Carmine Scarpitta Date: Thu, 9 May 2024 13:03:45 +0200 Subject: [PATCH 077/347] isisd: Release SRv6 SIDs to SID Manager Currently, IS-IS allocates SIDs without interacting with Zebra. Recently, the SRv6 implementation has been improved. Now, the daemons need to interact with Zebra through ZAPI to obtain and release SIDs. This commit extends IS-IS to release SIDs to Zebra when they are no longer needed. Signed-off-by: Carmine Scarpitta --- isisd/isis_srv6.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/isisd/isis_srv6.c b/isisd/isis_srv6.c index 0cd7f847f8..c7bc7f0692 100644 --- a/isisd/isis_srv6.c +++ b/isisd/isis_srv6.c @@ -102,6 +102,7 @@ bool isis_srv6_locator_unset(struct isis_area *area) struct srv6_locator_chunk *chunk; struct isis_srv6_sid *sid; struct srv6_adjacency *sra; + struct srv6_sid_ctx ctx = {}; if (strncmp(area->srv6db.config.srv6_locator_name, "", sizeof(area->srv6db.config.srv6_locator_name)) == 0) { @@ -120,13 +121,31 @@ bool isis_srv6_locator_unset(struct isis_area *area) * Zebra */ isis_zebra_srv6_sid_uninstall(area, sid); + /* + * Inform the SID Manager that IS-IS will no longer use the SID, so + * that the SID Manager can remove the SID context ownership from IS-IS + * and release/free the SID context if it is not yes by other protocols. + */ + ctx.behavior = ZEBRA_SEG6_LOCAL_ACTION_END; + isis_zebra_release_srv6_sid(&ctx); + listnode_delete(area->srv6db.srv6_sids, sid); isis_srv6_sid_free(sid); } /* Uninstall all local Adjacency-SIDs. */ - for (ALL_LIST_ELEMENTS(area->srv6db.srv6_endx_sids, node, nnode, sra)) + for (ALL_LIST_ELEMENTS(area->srv6db.srv6_endx_sids, node, nnode, sra)) { + /* + * Inform the SID Manager that IS-IS will no longer use the SID, so + * that the SID Manager can remove the SID context ownership from IS-IS + * and release/free the SID context if it is not yes by other protocols. + */ + ctx.behavior = ZEBRA_SEG6_LOCAL_ACTION_END_X; + ctx.nh6 = sra->nexthop; + isis_zebra_release_srv6_sid(&ctx); + srv6_endx_sid_del(sra); + } /* Inform Zebra that we are releasing the SRv6 locator */ ret = isis_zebra_srv6_manager_release_locator_chunk( From 0af0f4616d32879b8114386e2c44fc6b3250cb14 Mon Sep 17 00:00:00 2001 From: Carmine Scarpitta Date: Thu, 9 May 2024 11:51:16 +0200 Subject: [PATCH 078/347] isisd: Receive SRv6 SIDs notifications from zebra Zebra sends a SRV6_SID_NOTIFY notification to inform clients about the result of a SID alloc/release operation. This commit adds a handler to process a SRV6_SID_NOTIFY notification received from zebra. If the notification indicates that a SID allocation operation was successful, then it stores the allocated SID in the SRv6 database, installs the SID into the RIB, and advertises the SID to the other IS-IS routers. If the notification indicates that an operation has failed, it logs the error. Signed-off-by: Carmine Scarpitta --- isisd/isis_zebra.c | 146 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 146 insertions(+) diff --git a/isisd/isis_zebra.c b/isisd/isis_zebra.c index be8bb5c406..99fd7398ee 100644 --- a/isisd/isis_zebra.c +++ b/isisd/isis_zebra.c @@ -1535,6 +1535,151 @@ void isis_zebra_release_srv6_sid(const struct srv6_sid_ctx *ctx) } } +static int isis_zebra_srv6_sid_notify(ZAPI_CALLBACK_ARGS) +{ + struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT); + struct srv6_sid_ctx ctx; + struct in6_addr sid_addr; + enum zapi_srv6_sid_notify note; + uint32_t sid_func; + struct isis_area *area; + struct listnode *node, *nnode, *n; + char buf[256]; + struct srv6_locator *locator; + struct prefix_ipv6 tmp_prefix; + struct srv6_adjacency *sra; + enum srv6_endpoint_behavior_codepoint behavior; + struct isis_srv6_sid *sid; + struct isis_adjacency *adj; + + if (!isis) + return -1; + + /* Decode the received notification message */ + if (!zapi_srv6_sid_notify_decode(zclient->ibuf, &ctx, &sid_addr, + &sid_func, NULL, ¬e)) { + zlog_err("%s : error in msg decode", __func__); + return -1; + } + + sr_debug("%s: received SRv6 SID notify: ctx %s sid_value %pI6 sid_func %u note %s", + __func__, srv6_sid_ctx2str(buf, sizeof(buf), &ctx), &sid_addr, + sid_func, zapi_srv6_sid_notify2str(note)); + + for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) { + if (!area->srv6db.config.enabled || !area->srv6db.srv6_locator) + continue; + + locator = area->srv6db.srv6_locator; + + /* Verify that the received SID belongs to the configured locator */ + if (note == ZAPI_SRV6_SID_ALLOCATED) { + tmp_prefix.family = AF_INET6; + tmp_prefix.prefixlen = IPV6_MAX_BITLEN; + tmp_prefix.prefix = sid_addr; + + if (!prefix_match((struct prefix *)&locator->prefix, + (struct prefix *)&tmp_prefix)) { + sr_debug("%s : ignoring SRv6 SID notify: locator (area %s) does not match", + __func__, area->area_tag); + continue; + } + } + + /* Handle notification */ + switch (note) { + case ZAPI_SRV6_SID_ALLOCATED: + sr_debug("SRv6 SID %pI6 %s ALLOCATED", &sid_addr, + srv6_sid_ctx2str(buf, sizeof(buf), &ctx)); + + if (ctx.behavior == ZEBRA_SEG6_LOCAL_ACTION_END) { + /* Remove old End SIDs, if any */ + for (ALL_LIST_ELEMENTS(area->srv6db.srv6_sids, + node, nnode, sid)) { + isis_zebra_srv6_sid_uninstall(area, sid); + listnode_delete(area->srv6db.srv6_sids, + sid); + } + + /* Allocate new SRv6 End SID */ + behavior = + (CHECK_FLAG(locator->flags, + SRV6_LOCATOR_USID)) + ? SRV6_ENDPOINT_BEHAVIOR_END_NEXT_CSID + : SRV6_ENDPOINT_BEHAVIOR_END; + sid = isis_srv6_sid_alloc(area, + area->srv6db + .srv6_locator, + behavior, &sid_addr); + if (!sid) { + zlog_warn("%s: isis_srv6_sid_alloc failed", + __func__); + return -1; + } + + /* + * Install the new SRv6 End SID in the forwarding plane through + * Zebra + */ + isis_zebra_srv6_sid_install(area, sid); + + /* Store the SID */ + listnode_add(area->srv6db.srv6_sids, sid); + + } else if (ctx.behavior == + ZEBRA_SEG6_LOCAL_ACTION_END_X) { + for (ALL_LIST_ELEMENTS_RO(area->adjacency_list, + n, adj)) { + /* Check if the End.X SID is for this adjacecny */ + if (adj->ll_ipv6_count == 0 || + memcmp(&adj->ll_ipv6_addrs[0], + &ctx.nh6, + sizeof(struct in6_addr)) != 0) + continue; + + /* Remove old End.X SIDs, if any */ + for (ALL_LIST_ELEMENTS(adj->srv6_endx_sids, + node, nnode, sra)) + srv6_endx_sid_del(sra); + + /* Allocate new End.X SID for the adjacency */ + srv6_endx_sid_add_single(adj, false, + NULL, + &sid_addr); + } + } else { + zlog_warn("%s: unsupported behavior %u", + __func__, ctx.behavior); + return -1; + } + break; + case ZAPI_SRV6_SID_RELEASED: + sr_debug("SRv6 SID %pI6 %s: RELEASED", &sid_addr, + srv6_sid_ctx2str(buf, sizeof(buf), &ctx)); + break; + case ZAPI_SRV6_SID_FAIL_ALLOC: + sr_debug("SRv6 SID %pI6 %s: Failed to allocate", + &sid_addr, + srv6_sid_ctx2str(buf, sizeof(buf), &ctx)); + + /* Error will be logged by zebra module */ + break; + case ZAPI_SRV6_SID_FAIL_RELEASE: + zlog_warn("%s: SRv6 SID %pI6 %s failure to release", + __func__, &sid_addr, + srv6_sid_ctx2str(buf, sizeof(buf), &ctx)); + + /* Error will be logged by zebra module */ + break; + } + + /* Regenerate LSPs to advertise the new locator and the SID */ + lsp_regenerate_schedule(area, area->is_type, 0); + } + + return 0; +} + static zclient_handler *const isis_handlers[] = { [ZEBRA_ROUTER_ID_UPDATE] = isis_router_id_update_zebra, [ZEBRA_INTERFACE_ADDRESS_ADD] = isis_zebra_if_address_add, @@ -1551,6 +1696,7 @@ static zclient_handler *const isis_handlers[] = { isis_zebra_process_srv6_locator_chunk, [ZEBRA_SRV6_LOCATOR_ADD] = isis_zebra_process_srv6_locator_add, [ZEBRA_SRV6_LOCATOR_DELETE] = isis_zebra_process_srv6_locator_delete, + [ZEBRA_SRV6_SID_NOTIFY] = isis_zebra_srv6_sid_notify, }; void isis_zebra_init(struct event_loop *master, int instance) From a2b83a9dec6a9c1021ccbc368c55b2cd6b362d42 Mon Sep 17 00:00:00 2001 From: Carmine Scarpitta Date: Sat, 23 Mar 2024 21:43:17 +0100 Subject: [PATCH 079/347] isisd: Cleanup related to SRv6 Remove unused SRv6 code. Signed-off-by: Carmine Scarpitta --- isisd/isis_srv6.c | 111 --------------------------------------------- isisd/isis_zebra.c | 101 ----------------------------------------- 2 files changed, 212 deletions(-) diff --git a/isisd/isis_srv6.c b/isisd/isis_srv6.c index c7bc7f0692..b5974b1a62 100644 --- a/isisd/isis_srv6.c +++ b/isisd/isis_srv6.c @@ -220,117 +220,6 @@ void isis_srv6_interface_set(struct isis_area *area, const char *ifname) } } -/** - * Encode SID function in the SRv6 SID. - * - * @param sid - * @param func - * @param offset - * @param len - */ -static void encode_sid_func(struct in6_addr *sid, uint32_t func, uint8_t offset, - uint8_t len) -{ - for (uint8_t idx = 0; idx < len; idx++) { - uint8_t tidx = offset + idx; - sid->s6_addr[tidx / 8] &= ~(0x1 << (7 - tidx % 8)); - if (func >> (len - 1 - idx) & 0x1) - sid->s6_addr[tidx / 8] |= 0x1 << (7 - tidx % 8); - } -} - -static bool sid_exist(struct isis_area *area, const struct in6_addr *sid) -{ - struct listnode *node; - struct isis_srv6_sid *s; - struct srv6_adjacency *sra; - - for (ALL_LIST_ELEMENTS_RO(area->srv6db.srv6_sids, node, s)) - if (sid_same(&s->sid, sid)) - return true; - for (ALL_LIST_ELEMENTS_RO(area->srv6db.srv6_endx_sids, node, sra)) - if (sid_same(&sra->sid, sid)) - return true; - return false; -} - -/** - * Request a SID from the SRv6 locator. - * - * @param area IS-IS area - * @param locator SRv6 locator - * @param sid_func The FUNCTION part of the SID to be allocated (a negative - * number will allocate the first available SID) - * - * @return First available SID on success or in6addr_any if the SRv6 - * locator is full - */ -static struct in6_addr srv6_locator_request_sid(struct isis_area *area, - struct srv6_locator *locator, - int sid_func) -{ - struct in6_addr sid; - uint8_t offset = 0; - uint8_t func_len = 0; - uint32_t func_max; - bool allocated = false; - - if (!area || !locator) - return in6addr_any; - - sr_debug("ISIS-SRv6 (%s): requested new SID from locator %s", - area->area_tag, locator->name); - - /* Let's build the SID, step by step. A SID has the following structure - (defined in RFC 8986): LOCATOR:FUNCTION:ARGUMENT.*/ - - /* First, we encode the LOCATOR in the L most significant bits. */ - sid = locator->prefix.prefix; - - /* The next part of the SID is the FUNCTION. Let's compute the length - * and the offset of the FUNCTION in the SID */ - func_len = locator->function_bits_length; - offset = locator->block_bits_length + locator->node_bits_length; - - /* Then, encode the FUNCTION */ - if (sid_func >= 0) { - /* SID FUNCTION has been specified. We need to allocate a SID - * with the requested FUNCTION. */ - encode_sid_func(&sid, sid_func, offset, func_len); - if (sid_exist(area, &sid)) { - zlog_warn( - "ISIS-SRv6 (%s): the requested SID %pI6 is already used", - area->area_tag, &sid); - return sid; - } - allocated = true; - } else { - /* SID FUNCTION not specified. We need to choose a FUNCTION that - * is not already used. So let's iterate through all possible - * functions and get the first available one. */ - func_max = (1 << func_len) - 1; - for (uint32_t func = 1; func < func_max; func++) { - encode_sid_func(&sid, func, offset, func_len); - if (sid_exist(area, &sid)) - continue; - allocated = true; - break; - } - } - - if (!allocated) { - /* We ran out of available SIDs */ - zlog_warn("ISIS-SRv6 (%s): no SIDs available in locator %s", - area->area_tag, locator->name); - return in6addr_any; - } - - sr_debug("ISIS-SRv6 (%s): allocating new SID %pI6", area->area_tag, - &sid); - - return sid; -} - /** * Allocate an SRv6 SID from an SRv6 locator. * diff --git a/isisd/isis_zebra.c b/isisd/isis_zebra.c index 99fd7398ee..021ed1ff49 100644 --- a/isisd/isis_zebra.c +++ b/isisd/isis_zebra.c @@ -1182,105 +1182,6 @@ void isis_zebra_srv6_adj_sid_uninstall(struct srv6_adjacency *sra) ifp->ifindex, action, NULL); } -/** - * Callback to process an SRv6 locator chunk received from SRv6 Manager (zebra). - * - * @result 0 on success, -1 otherwise - */ -static int isis_zebra_process_srv6_locator_chunk(ZAPI_CALLBACK_ARGS) -{ - struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT); - struct stream *s = NULL; - struct listnode *node; - struct isis_area *area; - struct srv6_locator_chunk *c; - struct srv6_locator_chunk *chunk = srv6_locator_chunk_alloc(); - struct isis_srv6_sid *sid; - struct isis_adjacency *adj; - enum srv6_endpoint_behavior_codepoint behavior; - bool allocated = false; - - if (!isis) { - srv6_locator_chunk_free(&chunk); - return -1; - } - - /* Decode the received zebra message */ - s = zclient->ibuf; - if (zapi_srv6_locator_chunk_decode(s, chunk) < 0) { - srv6_locator_chunk_free(&chunk); - return -1; - } - - sr_debug( - "Received SRv6 locator chunk from zebra: name %s, " - "prefix %pFX, block_len %u, node_len %u, func_len %u, arg_len %u", - chunk->locator_name, &chunk->prefix, chunk->block_bits_length, - chunk->node_bits_length, chunk->function_bits_length, - chunk->argument_bits_length); - - /* Walk through all areas of the ISIS instance */ - for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) { - if (strncmp(area->srv6db.config.srv6_locator_name, - chunk->locator_name, - sizeof(area->srv6db.config.srv6_locator_name)) != 0) - continue; - - for (ALL_LIST_ELEMENTS_RO(area->srv6db.srv6_locator_chunks, - node, c)) { - if (!prefix_cmp(&c->prefix, &chunk->prefix)) { - srv6_locator_chunk_free(&chunk); - return 0; - } - } - - sr_debug( - "SRv6 locator chunk (locator %s, prefix %pFX) assigned to IS-IS area %s", - chunk->locator_name, &chunk->prefix, area->area_tag); - - /* Add the SRv6 Locator chunk to the per-area chunks list */ - listnode_add(area->srv6db.srv6_locator_chunks, chunk); - - /* Decide which behavior to use,depending on the locator type - * (i.e. uSID vs classic locator) */ - behavior = (CHECK_FLAG(chunk->flags, SRV6_LOCATOR_USID)) - ? SRV6_ENDPOINT_BEHAVIOR_END_NEXT_CSID - : SRV6_ENDPOINT_BEHAVIOR_END; - - /* Allocate new SRv6 End SID */ - sid = isis_srv6_sid_alloc(area, chunk, behavior, 0); - if (!sid) - return -1; - - /* Install the new SRv6 End SID in the forwarding plane through - * Zebra */ - isis_zebra_srv6_sid_install(area, sid); - - /* Store the SID */ - listnode_add(area->srv6db.srv6_sids, sid); - - /* Create SRv6 End.X SIDs from existing IS-IS Adjacencies */ - for (ALL_LIST_ELEMENTS_RO(area->adjacency_list, node, adj)) { - if (adj->ll_ipv6_count > 0) - srv6_endx_sid_add(adj); - } - - /* Regenerate LSPs to advertise the new locator and the SID */ - lsp_regenerate_schedule(area, area->is_type, 0); - - allocated = true; - break; - } - - if (!allocated) { - sr_debug("No IS-IS area configured for the locator %s", - chunk->locator_name); - srv6_locator_chunk_free(&chunk); - } - - return 0; -} - /** * Internal function to process an SRv6 locator * @@ -1692,8 +1593,6 @@ static zclient_handler *const isis_handlers[] = { [ZEBRA_CLIENT_CLOSE_NOTIFY] = isis_zebra_client_close_notify, - [ZEBRA_SRV6_MANAGER_GET_LOCATOR_CHUNK] = - isis_zebra_process_srv6_locator_chunk, [ZEBRA_SRV6_LOCATOR_ADD] = isis_zebra_process_srv6_locator_add, [ZEBRA_SRV6_LOCATOR_DELETE] = isis_zebra_process_srv6_locator_delete, [ZEBRA_SRV6_SID_NOTIFY] = isis_zebra_srv6_sid_notify, From 9e1803a772510114148b0f8ca9bfb3dcbed76721 Mon Sep 17 00:00:00 2001 From: Carmine Scarpitta Date: Thu, 6 Jun 2024 14:50:06 +0200 Subject: [PATCH 080/347] tests: Update IS-IS SRv6 topotests The locator is no longer split in multiple chunks. Signed-off-by: Carmine Scarpitta --- .../isis_srv6_topo1/rt1/step1/show_srv6_locator_table.ref | 4 ---- .../isis_srv6_topo1/rt1/step3/show_srv6_locator_table.ref | 4 ---- .../isis_srv6_topo1/rt1/step5/show_srv6_locator_table.ref | 4 ---- .../isis_srv6_topo1/rt1/step7/show_srv6_locator_table.ref | 4 ---- .../isis_srv6_topo1/rt1/step9/show_srv6_locator_table.ref | 4 ---- .../isis_srv6_topo1/rt2/step1/show_srv6_locator_table.ref | 4 ---- .../isis_srv6_topo1/rt2/step2/show_srv6_locator_table.ref | 4 ---- .../isis_srv6_topo1/rt2/step3/show_srv6_locator_table.ref | 4 ---- .../isis_srv6_topo1/rt2/step4/show_srv6_locator_table.ref | 4 ---- .../isis_srv6_topo1/rt2/step5/show_srv6_locator_table.ref | 4 ---- .../isis_srv6_topo1/rt2/step6/show_srv6_locator_table.ref | 4 ---- .../isis_srv6_topo1/rt2/step7/show_srv6_locator_table.ref | 4 ---- .../isis_srv6_topo1/rt2/step8/show_srv6_locator_table.ref | 4 ---- .../isis_srv6_topo1/rt2/step9/show_srv6_locator_table.ref | 4 ---- .../isis_srv6_topo1/rt3/step1/show_srv6_locator_table.ref | 4 ---- .../isis_srv6_topo1/rt3/step2/show_srv6_locator_table.ref | 4 ---- .../isis_srv6_topo1/rt3/step3/show_srv6_locator_table.ref | 4 ---- .../isis_srv6_topo1/rt3/step4/show_srv6_locator_table.ref | 4 ---- .../isis_srv6_topo1/rt3/step5/show_srv6_locator_table.ref | 4 ---- .../isis_srv6_topo1/rt3/step6/show_srv6_locator_table.ref | 4 ---- .../isis_srv6_topo1/rt3/step7/show_srv6_locator_table.ref | 4 ---- .../isis_srv6_topo1/rt3/step8/show_srv6_locator_table.ref | 4 ---- .../isis_srv6_topo1/rt3/step9/show_srv6_locator_table.ref | 4 ---- .../isis_srv6_topo1/rt4/step1/show_srv6_locator_table.ref | 4 ---- .../isis_srv6_topo1/rt4/step2/show_srv6_locator_table.ref | 4 ---- .../isis_srv6_topo1/rt4/step3/show_srv6_locator_table.ref | 4 ---- .../isis_srv6_topo1/rt4/step4/show_srv6_locator_table.ref | 4 ---- .../isis_srv6_topo1/rt4/step5/show_srv6_locator_table.ref | 4 ---- .../isis_srv6_topo1/rt4/step6/show_srv6_locator_table.ref | 4 ---- .../isis_srv6_topo1/rt4/step7/show_srv6_locator_table.ref | 4 ---- .../isis_srv6_topo1/rt4/step8/show_srv6_locator_table.ref | 4 ---- .../isis_srv6_topo1/rt4/step9/show_srv6_locator_table.ref | 4 ---- .../isis_srv6_topo1/rt5/step1/show_srv6_locator_table.ref | 4 ---- .../isis_srv6_topo1/rt5/step2/show_srv6_locator_table.ref | 4 ---- .../isis_srv6_topo1/rt5/step3/show_srv6_locator_table.ref | 4 ---- .../isis_srv6_topo1/rt5/step4/show_srv6_locator_table.ref | 4 ---- .../isis_srv6_topo1/rt5/step5/show_srv6_locator_table.ref | 4 ---- .../isis_srv6_topo1/rt5/step6/show_srv6_locator_table.ref | 4 ---- .../isis_srv6_topo1/rt5/step7/show_srv6_locator_table.ref | 4 ---- .../isis_srv6_topo1/rt5/step8/show_srv6_locator_table.ref | 4 ---- .../isis_srv6_topo1/rt5/step9/show_srv6_locator_table.ref | 4 ---- .../isis_srv6_topo1/rt6/step1/show_srv6_locator_table.ref | 4 ---- .../isis_srv6_topo1/rt6/step2/show_srv6_locator_table.ref | 4 ---- .../isis_srv6_topo1/rt6/step3/show_srv6_locator_table.ref | 4 ---- .../isis_srv6_topo1/rt6/step4/show_srv6_locator_table.ref | 4 ---- .../isis_srv6_topo1/rt6/step5/show_srv6_locator_table.ref | 4 ---- .../isis_srv6_topo1/rt6/step6/show_srv6_locator_table.ref | 4 ---- .../isis_srv6_topo1/rt6/step7/show_srv6_locator_table.ref | 4 ---- .../isis_srv6_topo1/rt6/step8/show_srv6_locator_table.ref | 4 ---- .../isis_srv6_topo1/rt6/step9/show_srv6_locator_table.ref | 4 ---- 50 files changed, 200 deletions(-) diff --git a/tests/topotests/isis_srv6_topo1/rt1/step1/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt1/step1/show_srv6_locator_table.ref index bb10aba942..c4a5d7507b 100644 --- a/tests/topotests/isis_srv6_topo1/rt1/step1/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt1/step1/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:1::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt1/step3/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt1/step3/show_srv6_locator_table.ref index bb10aba942..c4a5d7507b 100644 --- a/tests/topotests/isis_srv6_topo1/rt1/step3/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt1/step3/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:1::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt1/step5/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt1/step5/show_srv6_locator_table.ref index bb10aba942..c4a5d7507b 100644 --- a/tests/topotests/isis_srv6_topo1/rt1/step5/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt1/step5/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:1::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt1/step7/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt1/step7/show_srv6_locator_table.ref index bb10aba942..c4a5d7507b 100644 --- a/tests/topotests/isis_srv6_topo1/rt1/step7/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt1/step7/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:1::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt1/step9/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt1/step9/show_srv6_locator_table.ref index bb10aba942..c4a5d7507b 100644 --- a/tests/topotests/isis_srv6_topo1/rt1/step9/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt1/step9/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:1::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt2/step1/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt2/step1/show_srv6_locator_table.ref index f3399319f3..f8a5d93f3c 100644 --- a/tests/topotests/isis_srv6_topo1/rt2/step1/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt2/step1/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:2::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt2/step2/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt2/step2/show_srv6_locator_table.ref index f3399319f3..f8a5d93f3c 100644 --- a/tests/topotests/isis_srv6_topo1/rt2/step2/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt2/step2/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:2::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt2/step3/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt2/step3/show_srv6_locator_table.ref index f3399319f3..f8a5d93f3c 100644 --- a/tests/topotests/isis_srv6_topo1/rt2/step3/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt2/step3/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:2::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt2/step4/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt2/step4/show_srv6_locator_table.ref index f3399319f3..f8a5d93f3c 100644 --- a/tests/topotests/isis_srv6_topo1/rt2/step4/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt2/step4/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:2::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt2/step5/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt2/step5/show_srv6_locator_table.ref index f3399319f3..f8a5d93f3c 100644 --- a/tests/topotests/isis_srv6_topo1/rt2/step5/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt2/step5/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:2::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt2/step6/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt2/step6/show_srv6_locator_table.ref index f3399319f3..f8a5d93f3c 100644 --- a/tests/topotests/isis_srv6_topo1/rt2/step6/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt2/step6/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:2::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt2/step7/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt2/step7/show_srv6_locator_table.ref index f3399319f3..f8a5d93f3c 100644 --- a/tests/topotests/isis_srv6_topo1/rt2/step7/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt2/step7/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:2::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt2/step8/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt2/step8/show_srv6_locator_table.ref index f3399319f3..f8a5d93f3c 100644 --- a/tests/topotests/isis_srv6_topo1/rt2/step8/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt2/step8/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:2::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt2/step9/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt2/step9/show_srv6_locator_table.ref index f3399319f3..f8a5d93f3c 100644 --- a/tests/topotests/isis_srv6_topo1/rt2/step9/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt2/step9/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:2::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt3/step1/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt3/step1/show_srv6_locator_table.ref index ffa626123d..c62870587b 100644 --- a/tests/topotests/isis_srv6_topo1/rt3/step1/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt3/step1/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:3::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt3/step2/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt3/step2/show_srv6_locator_table.ref index ffa626123d..c62870587b 100644 --- a/tests/topotests/isis_srv6_topo1/rt3/step2/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt3/step2/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:3::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt3/step3/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt3/step3/show_srv6_locator_table.ref index ffa626123d..c62870587b 100644 --- a/tests/topotests/isis_srv6_topo1/rt3/step3/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt3/step3/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:3::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt3/step4/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt3/step4/show_srv6_locator_table.ref index ffa626123d..c62870587b 100644 --- a/tests/topotests/isis_srv6_topo1/rt3/step4/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt3/step4/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:3::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt3/step5/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt3/step5/show_srv6_locator_table.ref index ffa626123d..c62870587b 100644 --- a/tests/topotests/isis_srv6_topo1/rt3/step5/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt3/step5/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:3::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt3/step6/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt3/step6/show_srv6_locator_table.ref index ffa626123d..c62870587b 100644 --- a/tests/topotests/isis_srv6_topo1/rt3/step6/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt3/step6/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:3::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt3/step7/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt3/step7/show_srv6_locator_table.ref index ffa626123d..c62870587b 100644 --- a/tests/topotests/isis_srv6_topo1/rt3/step7/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt3/step7/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:3::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt3/step8/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt3/step8/show_srv6_locator_table.ref index ffa626123d..c62870587b 100644 --- a/tests/topotests/isis_srv6_topo1/rt3/step8/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt3/step8/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:3::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt3/step9/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt3/step9/show_srv6_locator_table.ref index ffa626123d..c62870587b 100644 --- a/tests/topotests/isis_srv6_topo1/rt3/step9/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt3/step9/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:3::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt4/step1/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt4/step1/show_srv6_locator_table.ref index 189943f737..cb052dbbb5 100644 --- a/tests/topotests/isis_srv6_topo1/rt4/step1/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt4/step1/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:4::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt4/step2/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt4/step2/show_srv6_locator_table.ref index 189943f737..cb052dbbb5 100644 --- a/tests/topotests/isis_srv6_topo1/rt4/step2/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt4/step2/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:4::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt4/step3/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt4/step3/show_srv6_locator_table.ref index 189943f737..cb052dbbb5 100644 --- a/tests/topotests/isis_srv6_topo1/rt4/step3/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt4/step3/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:4::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt4/step4/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt4/step4/show_srv6_locator_table.ref index 189943f737..cb052dbbb5 100644 --- a/tests/topotests/isis_srv6_topo1/rt4/step4/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt4/step4/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:4::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt4/step5/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt4/step5/show_srv6_locator_table.ref index 189943f737..cb052dbbb5 100644 --- a/tests/topotests/isis_srv6_topo1/rt4/step5/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt4/step5/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:4::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt4/step6/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt4/step6/show_srv6_locator_table.ref index 189943f737..cb052dbbb5 100644 --- a/tests/topotests/isis_srv6_topo1/rt4/step6/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt4/step6/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:4::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt4/step7/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt4/step7/show_srv6_locator_table.ref index 189943f737..cb052dbbb5 100644 --- a/tests/topotests/isis_srv6_topo1/rt4/step7/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt4/step7/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:4::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt4/step8/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt4/step8/show_srv6_locator_table.ref index 189943f737..cb052dbbb5 100644 --- a/tests/topotests/isis_srv6_topo1/rt4/step8/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt4/step8/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:4::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt4/step9/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt4/step9/show_srv6_locator_table.ref index 189943f737..cb052dbbb5 100644 --- a/tests/topotests/isis_srv6_topo1/rt4/step9/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt4/step9/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:4::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt5/step1/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt5/step1/show_srv6_locator_table.ref index 54780fce8a..ec55f24d7b 100644 --- a/tests/topotests/isis_srv6_topo1/rt5/step1/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt5/step1/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:5::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt5/step2/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt5/step2/show_srv6_locator_table.ref index 54780fce8a..ec55f24d7b 100644 --- a/tests/topotests/isis_srv6_topo1/rt5/step2/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt5/step2/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:5::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt5/step3/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt5/step3/show_srv6_locator_table.ref index 54780fce8a..ec55f24d7b 100644 --- a/tests/topotests/isis_srv6_topo1/rt5/step3/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt5/step3/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:5::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt5/step4/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt5/step4/show_srv6_locator_table.ref index 54780fce8a..ec55f24d7b 100644 --- a/tests/topotests/isis_srv6_topo1/rt5/step4/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt5/step4/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:5::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt5/step5/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt5/step5/show_srv6_locator_table.ref index 54780fce8a..ec55f24d7b 100644 --- a/tests/topotests/isis_srv6_topo1/rt5/step5/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt5/step5/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:5::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt5/step6/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt5/step6/show_srv6_locator_table.ref index 54780fce8a..ec55f24d7b 100644 --- a/tests/topotests/isis_srv6_topo1/rt5/step6/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt5/step6/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:5::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt5/step7/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt5/step7/show_srv6_locator_table.ref index 54780fce8a..ec55f24d7b 100644 --- a/tests/topotests/isis_srv6_topo1/rt5/step7/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt5/step7/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:5::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt5/step8/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt5/step8/show_srv6_locator_table.ref index 54780fce8a..ec55f24d7b 100644 --- a/tests/topotests/isis_srv6_topo1/rt5/step8/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt5/step8/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:5::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt5/step9/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt5/step9/show_srv6_locator_table.ref index 54780fce8a..ec55f24d7b 100644 --- a/tests/topotests/isis_srv6_topo1/rt5/step9/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt5/step9/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:5::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt6/step1/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt6/step1/show_srv6_locator_table.ref index 35aa61d8e6..abcdeddea4 100644 --- a/tests/topotests/isis_srv6_topo1/rt6/step1/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt6/step1/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:6::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt6/step2/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt6/step2/show_srv6_locator_table.ref index 35aa61d8e6..abcdeddea4 100644 --- a/tests/topotests/isis_srv6_topo1/rt6/step2/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt6/step2/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:6::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt6/step3/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt6/step3/show_srv6_locator_table.ref index 35aa61d8e6..abcdeddea4 100644 --- a/tests/topotests/isis_srv6_topo1/rt6/step3/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt6/step3/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:6::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt6/step4/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt6/step4/show_srv6_locator_table.ref index 35aa61d8e6..abcdeddea4 100644 --- a/tests/topotests/isis_srv6_topo1/rt6/step4/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt6/step4/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:6::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt6/step5/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt6/step5/show_srv6_locator_table.ref index 35aa61d8e6..abcdeddea4 100644 --- a/tests/topotests/isis_srv6_topo1/rt6/step5/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt6/step5/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:6::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt6/step6/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt6/step6/show_srv6_locator_table.ref index 35aa61d8e6..abcdeddea4 100644 --- a/tests/topotests/isis_srv6_topo1/rt6/step6/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt6/step6/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:6::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt6/step7/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt6/step7/show_srv6_locator_table.ref index 35aa61d8e6..abcdeddea4 100644 --- a/tests/topotests/isis_srv6_topo1/rt6/step7/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt6/step7/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:6::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt6/step8/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt6/step8/show_srv6_locator_table.ref index 35aa61d8e6..abcdeddea4 100644 --- a/tests/topotests/isis_srv6_topo1/rt6/step8/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt6/step8/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:6::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt6/step9/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt6/step9/show_srv6_locator_table.ref index 35aa61d8e6..abcdeddea4 100644 --- a/tests/topotests/isis_srv6_topo1/rt6/step9/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt6/step9/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:6::/48", - "proto":"isis" - } ] } ] From fe5b03a10b583d0a95104a43389a9b60ca9bc397 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Sat, 8 Jun 2024 07:15:47 +0200 Subject: [PATCH 081/347] isisd: add locator name in sid notify messages In the near future, some daemons may only register SIDs. This may be the case for the pathd daemon when creating SRv6 binding SIDs. When a locator is getting deleted at ZEBRA level, the daemon may have an easy way to find out the SIds to unregister to. This commit proposes to add the locator name to the SID_SRV6_NOTIFY message whenever possible. Only case when an allocation failure happens, the locator will not be present. In all other places, the notify API at procol levels has the locator name extra-parameter. Signed-off-by: Philippe Guibert Signed-off-by: Carmine Scarpitta --- isisd/isis_zebra.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/isisd/isis_zebra.c b/isisd/isis_zebra.c index 021ed1ff49..ce4eb74ec6 100644 --- a/isisd/isis_zebra.c +++ b/isisd/isis_zebra.c @@ -1458,7 +1458,7 @@ static int isis_zebra_srv6_sid_notify(ZAPI_CALLBACK_ARGS) /* Decode the received notification message */ if (!zapi_srv6_sid_notify_decode(zclient->ibuf, &ctx, &sid_addr, - &sid_func, NULL, ¬e)) { + &sid_func, NULL, ¬e, NULL)) { zlog_err("%s : error in msg decode", __func__); return -1; } From d10bd26e802eac70395da713423683a5cb624c57 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Fri, 14 Jun 2024 11:32:06 -0400 Subject: [PATCH 082/347] bgpd: Convert over to using vrf name instead of id Use the name for when putting out debugs in bgp_zebra.c. Additionally add an evpn flag for announce_route_actual. Signed-off-by: Donald Sharp --- bgpd/bgp_zebra.c | 73 ++++++++++++++++++++++++------------------------ 1 file changed, 37 insertions(+), 36 deletions(-) diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 8fab0d1c05..4d18078a43 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -195,7 +195,7 @@ static int bgp_ifp_destroy(struct interface *ifp) bgp = ifp->vrf->info; if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("Rx Intf del VRF %u IF %s", ifp->vrf->vrf_id, + zlog_debug("Rx Intf del VRF %s IF %s", ifp->vrf->name, ifp->name); if (bgp) { @@ -220,8 +220,7 @@ static int bgp_ifp_up(struct interface *ifp) bgp_mac_add_mac_entry(ifp); if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("Rx Intf up VRF %u IF %s", ifp->vrf->vrf_id, - ifp->name); + zlog_debug("Rx Intf up VRF %s IF %s", ifp->vrf->name, ifp->name); if (!bgp) return 0; @@ -259,7 +258,7 @@ static int bgp_ifp_down(struct interface *ifp) bgp_mac_del_mac_entry(ifp); if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("Rx Intf down VRF %u IF %s", ifp->vrf->vrf_id, + zlog_debug("Rx Intf down VRF %s IF %s", ifp->vrf->name, ifp->name); if (!bgp) @@ -320,8 +319,8 @@ static int bgp_interface_address_add(ZAPI_CALLBACK_ARGS) return 0; if (bgp_debug_zebra(ifc->address)) - zlog_debug("Rx Intf address add VRF %u IF %s addr %pFX", vrf_id, - ifc->ifp->name, ifc->address); + zlog_debug("Rx Intf address add VRF %s IF %s addr %pFX", + ifc->ifp->vrf->name, ifc->ifp->name, ifc->address); if (!bgp) return 0; @@ -417,8 +416,8 @@ static int bgp_interface_address_delete(ZAPI_CALLBACK_ARGS) return 0; if (bgp_debug_zebra(ifc->address)) - zlog_debug("Rx Intf address del VRF %u IF %s addr %pFX", vrf_id, - ifc->ifp->name, ifc->address); + zlog_debug("Rx Intf address del VRF %s IF %s addr %pFX", + ifc->ifp->vrf->name, ifc->ifp->name, ifc->address); if (bgp && if_is_operative(ifc->ifp)) { bgp_connected_delete(bgp, ifc); @@ -480,8 +479,8 @@ static int bgp_interface_nbr_address_add(ZAPI_CALLBACK_ARGS) return 0; if (bgp_debug_zebra(ifc->address)) - zlog_debug("Rx Intf neighbor add VRF %u IF %s addr %pFX", - vrf_id, ifc->ifp->name, ifc->address); + zlog_debug("Rx Intf neighbor add VRF %s IF %s addr %pFX", + ifc->ifp->vrf->name, ifc->ifp->name, ifc->address); if (if_is_operative(ifc->ifp)) { bgp = bgp_lookup_by_vrf_id(vrf_id); @@ -503,8 +502,8 @@ static int bgp_interface_nbr_address_delete(ZAPI_CALLBACK_ARGS) return 0; if (bgp_debug_zebra(ifc->address)) - zlog_debug("Rx Intf neighbor del VRF %u IF %s addr %pFX", - vrf_id, ifc->ifp->name, ifc->address); + zlog_debug("Rx Intf neighbor del VRF %s IF %s addr %pFX", + ifc->ifp->vrf->name, ifc->ifp->name, ifc->address); if (if_is_operative(ifc->ifp)) { bgp = bgp_lookup_by_vrf_id(vrf_id); @@ -586,13 +585,14 @@ static int zebra_read_route(ZAPI_CALLBACK_ARGS) if (add) { inet_ntop(api.prefix.family, &nexthop, buf, sizeof(buf)); - zlog_debug( - "Rx route ADD VRF %u %s[%d] %pFX nexthop %s (type %d if %u) metric %u distance %u tag %" ROUTE_TAG_PRI, - vrf_id, zebra_route_string(api.type), - api.instance, &api.prefix, buf, nhtype, ifindex, - api.metric, api.distance, api.tag); + zlog_debug("Rx route ADD %s %s[%d] %pFX nexthop %s (type %d if %u) metric %u distance %u tag %" ROUTE_TAG_PRI, + bgp->name_pretty, + zebra_route_string(api.type), api.instance, + &api.prefix, buf, nhtype, ifindex, + api.metric, api.distance, api.tag); } else { - zlog_debug("Rx route DEL VRF %u %s[%d] %pFX", vrf_id, + zlog_debug("Rx route DEL %s %s[%d] %pFX", + bgp->name_pretty, zebra_route_string(api.type), api.instance, &api.prefix); } @@ -1671,11 +1671,11 @@ bgp_zebra_announce_actual(struct bgp_dest *dest, struct bgp_path_info *info, } if (bgp_debug_zebra(p)) { - zlog_debug( - "Tx route %s VRF %u %pFX metric %u tag %" ROUTE_TAG_PRI - " count %d nhg %d", - is_add ? "add" : "delete", bgp->vrf_id, &api.prefix, - api.metric, api.tag, api.nexthop_num, nhg_id); + zlog_debug("Tx route %s %s %pFX metric %u tag %" ROUTE_TAG_PRI + " count %d nhg %d", + is_add ? "add" : "delete", bgp->name_pretty, + &api.prefix, api.metric, api.tag, api.nexthop_num, + nhg_id); bgp_debug_zebra_nh(&api); zlog_debug("%s: %pFX: announcing to zebra (recursion %sset)", @@ -1764,7 +1764,7 @@ enum zclient_send_status bgp_zebra_withdraw_actual(struct bgp_dest *dest, } if (bgp_debug_zebra(p)) - zlog_debug("Tx route delete VRF %u %pFX", bgp->vrf_id, + zlog_debug("Tx route delete %s %pFX", bgp->name_pretty, &api.prefix); return zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api); @@ -1805,8 +1805,9 @@ static void bgp_handle_route_announcements_to_zebra(struct event *e) is_evpn = true; if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("BGP %s route %pBD(%s) with dest %p and flags 0x%x to zebra", - install ? "announcing" : "withdrawing", dest, + zlog_debug("BGP %s%s route %pBD(%s) with dest %p and flags 0x%x to zebra", + install ? "announcing" : "withdrawing", + is_evpn ? " evpn" : " ", dest, table->bgp->name_pretty, dest, dest->flags); if (install) { @@ -2085,8 +2086,8 @@ int bgp_redistribute_set(struct bgp *bgp, afi_t afi, int type, return CMD_SUCCESS; if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("Tx redistribute add VRF %u afi %d %s %d", - bgp->vrf_id, afi, zebra_route_string(type), + zlog_debug("Tx redistribute add %s afi %d %s %d", + bgp->name_pretty, afi, zebra_route_string(type), instance); /* Send distribute add message to zebra. */ @@ -2106,8 +2107,8 @@ int bgp_redistribute_resend(struct bgp *bgp, afi_t afi, int type, return -1; if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("Tx redistribute del/add VRF %u afi %d %s %d", - bgp->vrf_id, afi, zebra_route_string(type), + zlog_debug("Tx redistribute del/add %s afi %d %s %d", + bgp->name_pretty, afi, zebra_route_string(type), instance); /* Send distribute add message to zebra. */ @@ -2201,9 +2202,9 @@ int bgp_redistribute_unreg(struct bgp *bgp, afi_t afi, int type, if (bgp_install_info_to_zebra(bgp)) { /* Send distribute delete message to zebra. */ if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("Tx redistribute del VRF %u afi %d %s %d", - bgp->vrf_id, afi, zebra_route_string(type), - instance); + zlog_debug("Tx redistribute del %s afi %d %s %d", + bgp->name_pretty, afi, + zebra_route_string(type), instance); zebra_redistribute_send(ZEBRA_REDISTRIBUTE_DELETE, zclient, afi, type, instance, bgp->vrf_id); } @@ -2306,7 +2307,7 @@ void bgp_zebra_instance_register(struct bgp *bgp) return; if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("Registering VRF %u", bgp->vrf_id); + zlog_debug("Registering %s", bgp->name_pretty); /* Register for router-id, interfaces, redistributed routes. */ zclient_send_reg_requests(zclient, bgp->vrf_id); @@ -2328,7 +2329,7 @@ void bgp_zebra_instance_deregister(struct bgp *bgp) return; if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("Deregistering VRF %u", bgp->vrf_id); + zlog_debug("Deregistering %s", bgp->name_pretty); /* For EVPN instance, unregister learning about VNIs, if appropriate. */ if (bgp->advertise_all_vni) @@ -3341,7 +3342,7 @@ static int bgp_ifp_create(struct interface *ifp) struct bgp *bgp; if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("Rx Intf add VRF %u IF %s", ifp->vrf->vrf_id, + zlog_debug("Rx Intf add VRF %s IF %s", ifp->vrf->name, ifp->name); bgp = ifp->vrf->info; From b47a92e2e51595f820609e4d909f2b0abb9d6309 Mon Sep 17 00:00:00 2001 From: Chirag Shah Date: Mon, 17 Jun 2024 13:58:03 -0700 Subject: [PATCH 083/347] bgpd: backpressure - fix evpn route sync to zebra In scaled EVPN + ipv4/ipv6 uni route sync to zebra, some of the ipv4/ipv6 routes skipped reinstallation due to incorrect local variable's stale value. Once the local variable value reset in each loop iteration all skipped routes synced to zebra properly. Ticket: #3948828 Signed-off-by: Rajasekar Raja Signed-off-by: Chirag Shah --- bgpd/bgp_zebra.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 8fab0d1c05..c79d7dff16 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -1794,6 +1794,8 @@ static void bgp_handle_route_announcements_to_zebra(struct event *e) bool install; while (count < ZEBRA_ANNOUNCEMENTS_LIMIT) { + is_evpn = false; + dest = zebra_announce_pop(&bm->zebra_announce_head); if (!dest) From 0db469958c9b7c7b763797da457e84d2f033a2f7 Mon Sep 17 00:00:00 2001 From: zhou-run <166502045+zhou-run@users.noreply.github.com> Date: Mon, 17 Jun 2024 18:00:04 +0800 Subject: [PATCH 084/347] isisd: Even after configuring "no hostname dynamic", the topology still displays the hostname. The command "show isis topology" calls print_sys_hostname() to display the system ID or hostname, but it does not check the area->dynhostname flag. Signed-off-by: zhou-run --- isisd/isis_misc.c | 8 +++++--- isisd/isisd.c | 27 +++++++++++++++++++++++++-- isisd/isisd.h | 2 ++ tests/isisd/test_isis_spf.c | 13 +++++++++++++ 4 files changed, 45 insertions(+), 5 deletions(-) diff --git a/isisd/isis_misc.c b/isisd/isis_misc.c index e4ef6c8dfa..833d514341 100644 --- a/isisd/isis_misc.c +++ b/isisd/isis_misc.c @@ -370,18 +370,20 @@ const char *print_sys_hostname(const uint8_t *sysid) struct isis_dynhn *dyn; struct isis *isis = NULL; struct listnode *node; + struct isis_area *area = NULL; if (!sysid) return "nullsysid"; /* For our system ID return our host name */ - isis = isis_lookup_by_sysid(sysid); - if (isis && !CHECK_FLAG(im->options, F_ISIS_UNIT_TEST)) + area = isis_area_lookup_by_sysid(sysid); + if (area && area->dynhostname && !CHECK_FLAG(im->options, F_ISIS_UNIT_TEST)) return cmd_hostname_get(); for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis)) { + area = isis_area_lookup_by_sysid(isis->sysid); dyn = dynhn_find_by_id(isis, sysid); - if (dyn) + if (area && area->dynhostname && dyn) return dyn->hostname; } diff --git a/isisd/isisd.c b/isisd/isisd.c index 982df0839b..1f119dbcc8 100644 --- a/isisd/isisd.c +++ b/isisd/isisd.c @@ -272,7 +272,7 @@ void isis_area_del_circuit(struct isis_area *area, struct isis_circuit *circuit) isis_csm_state_change(ISIS_DISABLE, circuit, area); } -static void delete_area_addr(void *arg) +void isis_area_address_delete(void *arg) { struct iso_address *addr = (struct iso_address *)arg; @@ -330,7 +330,7 @@ struct isis_area *isis_area_create(const char *area_tag, const char *vrf_name) area->circuit_list = list_new(); area->adjacency_list = list_new(); area->area_addrs = list_new(); - area->area_addrs->del = delete_area_addr; + area->area_addrs->del = isis_area_address_delete; if (!CHECK_FLAG(im->options, F_ISIS_UNIT_TEST)) event_add_timer(master, lsp_tick, area, 1, &area->t_tick); @@ -471,6 +471,29 @@ struct isis_area *isis_area_lookup(const char *area_tag, vrf_id_t vrf_id) return NULL; } +struct isis_area *isis_area_lookup_by_sysid(const uint8_t *sysid) +{ + struct isis_area *area; + struct listnode *node; + struct isis *isis; + struct iso_address *addr = NULL; + + isis = isis_lookup_by_sysid(sysid); + if (isis == NULL) + return NULL; + + for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) { + if (listcount(area->area_addrs) > 0) { + addr = listgetdata(listhead(area->area_addrs)); + if (!memcmp(addr->area_addr + addr->addr_len, sysid, + ISIS_SYS_ID_LEN)) + return area; + } + } + + return NULL; +} + int isis_area_get(struct vty *vty, const char *area_tag) { struct isis_area *area; diff --git a/isisd/isisd.h b/isisd/isisd.h index f5042e4ad5..2ed7dd0f10 100644 --- a/isisd/isisd.h +++ b/isisd/isisd.h @@ -285,10 +285,12 @@ void isis_area_add_circuit(struct isis_area *area, void isis_area_del_circuit(struct isis_area *area, struct isis_circuit *circuit); +void isis_area_address_delete(void *arg); struct isis_area *isis_area_create(const char *, const char *); struct isis_area *isis_area_lookup(const char *, vrf_id_t vrf_id); struct isis_area *isis_area_lookup_by_vrf(const char *area_tag, const char *vrf_name); +struct isis_area *isis_area_lookup_by_sysid(const uint8_t *sysid); int isis_area_get(struct vty *vty, const char *area_tag); void isis_area_destroy(struct isis_area *area); void isis_filter_update(struct access_list *access); diff --git a/tests/isisd/test_isis_spf.c b/tests/isisd/test_isis_spf.c index 4ea28cda2f..317ebd729e 100644 --- a/tests/isisd/test_isis_spf.c +++ b/tests/isisd/test_isis_spf.c @@ -245,12 +245,25 @@ static int test_run(struct vty *vty, const struct isis_topology *topology, struct isis_area *area; struct lfa_protected_resource protected_resource = {}; uint8_t fail_id[ISIS_SYS_ID_LEN] = {}; + static char sysidstr[ISO_SYSID_STRLEN]; + char net_title[255]; + uint8_t buff[255]; + struct iso_address *addr = NULL; /* Init topology. */ area = isis_area_create("1", NULL); memcpy(area->isis->sysid, root->sysid, sizeof(area->isis->sysid)); area->is_type = IS_LEVEL_1_AND_2; area->srdb.enabled = true; + area->area_addrs = list_new(); + area->area_addrs->del = isis_area_address_delete; + addr = XMALLOC(MTYPE_ISIS_AREA_ADDR, sizeof(struct iso_address)); + snprintfrr(sysidstr, sizeof(sysidstr), "%pSY", area->isis->sysid); + snprintf(net_title, sizeof(net_title), "49.%s.00", sysidstr); + addr->addr_len = dotformat2buff(buff, net_title); + memcpy(addr->area_addr, buff, addr->addr_len); + addr->addr_len -= (ISIS_SYS_ID_LEN + ISIS_NSEL_LEN); + listnode_add(area->area_addrs, addr); if (test_topology_load(topology, area, area->lspdb) != 0) { vty_out(vty, "%% Failed to load topology\n"); return CMD_WARNING; From c25c7e929d550c2faca3af74a29593b8c0b75db3 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Wed, 19 Jun 2024 14:09:00 +0300 Subject: [PATCH 085/347] bgpd: Set last reset reason to admin shutdown if it was manually Before this patch, we always printed the last reason "Waiting for OPEN", but if it's a manual shutdown, then we technically are not waiting for OPEN. Signed-off-by: Donatas Abraitis --- bgpd/bgpd.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 869d2b4552..0ad9716633 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -4829,6 +4829,8 @@ void bgp_shutdown_enable(struct bgp *bgp, const char *msg) /* iterate through peers of BGP instance */ for (ALL_LIST_ELEMENTS_RO(bgp->peer, node, peer)) { + peer->last_reset = PEER_DOWN_USER_SHUTDOWN; + /* continue, if peer is already in administrative shutdown. */ if (CHECK_FLAG(peer->flags, PEER_FLAG_SHUTDOWN)) continue; @@ -4883,8 +4885,10 @@ void bgp_shutdown_disable(struct bgp *bgp) /* clear the BGP instances shutdown flag */ UNSET_FLAG(bgp->flags, BGP_FLAG_SHUTDOWN); - for (ALL_LIST_ELEMENTS_RO(bgp->peer, node, peer)) + for (ALL_LIST_ELEMENTS_RO(bgp->peer, node, peer)) { bgp_timer_set(peer->connection); + peer->last_reset = PEER_DOWN_WAITING_OPEN; + } } /* Change specified peer flag. */ @@ -4956,6 +4960,10 @@ static int peer_flag_modify(struct peer *peer, uint64_t flag, int set) bgp_zebra_terminate_radv(peer->bgp, peer); } + if (flag == PEER_FLAG_SHUTDOWN) + peer->last_reset = set ? PEER_DOWN_USER_SHUTDOWN + : PEER_DOWN_WAITING_OPEN; + /* Execute flag action on peer. */ if (action.type == peer_change_reset) peer_flag_modify_action(peer, flag); @@ -4991,6 +4999,10 @@ static int peer_flag_modify(struct peer *peer, uint64_t flag, int set) set ? bgp_zebra_initiate_radv(member->bgp, member) : bgp_zebra_terminate_radv(member->bgp, member); + if (flag == PEER_FLAG_SHUTDOWN) + member->last_reset = set ? PEER_DOWN_USER_SHUTDOWN + : PEER_DOWN_WAITING_OPEN; + /* Execute flag action on peer-group member. */ if (action.type == peer_change_reset) peer_flag_modify_action(member, flag); From b5bd626a82b2541bee8e3120139e19ba05e444c8 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Wed, 19 Jun 2024 14:32:16 +0300 Subject: [PATCH 086/347] bgpd: Remove redundant whitespace before printing the reason of the failed peer Before: ``` Neighbor EstdCnt DropCnt ResetTime Reason 127.0.0.1 0 0 never Waiting for peer OPEN (n/a) ``` After: ``` Neighbor EstdCnt DropCnt ResetTime Reason 127.0.0.1 0 0 never Waiting for peer OPEN (n/a) ``` Signed-off-by: Donatas Abraitis --- bgpd/bgp_vty.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index fbe1db9d2a..230fedf4ec 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -11661,10 +11661,9 @@ static void bgp_show_peer_reset(struct vty * vty, struct peer *peer, BGP_NOTIFY_CEASE_HARD_RESET) : ""); } else { - vty_out(vty, " %s (%s)\n", + vty_out(vty, " %s (%s)\n", peer_down_str[(int)peer->last_reset], - peer->soft_version ? peer->soft_version - : "n/a"); + peer->soft_version ? peer->soft_version : "n/a"); } } } From 69b36cdf071a83f57a10206fd69db6cc7da5d10f Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Fri, 31 May 2024 12:03:22 -0400 Subject: [PATCH 087/347] lib: Discourage usage of deprecated data structures Put some verbiage in place to warn people that we are actively discouraging new development that uses an older data structure. Signed-off-by: Donald Sharp --- lib/hash.h | 12 ++++++++++++ lib/linklist.h | 12 ++++++++++++ lib/openbsd-queue.h | 16 ++++++++++++++++ lib/openbsd-tree.h | 15 +++++++++++++++ 4 files changed, 55 insertions(+) diff --git a/lib/hash.h b/lib/hash.h index 2d00a334be..efa7011bc2 100644 --- a/lib/hash.h +++ b/lib/hash.h @@ -13,6 +13,18 @@ extern "C" { #endif +/* + * NOTICE: + * + * If you are reading this file in an effort to add a new hash structure + * this is the wrong place to be using it. Please see the typesafe + * data structures, or ask one of the other developers. + * + * If you are reading this file as a way to update an existing usage + * of this data structure, please consider just converting the data + * structure to one of the typesafe data structures instead. + */ + /* Default hash table size. */ #define HASH_INITIAL_SIZE 256 /* Expansion threshold */ diff --git a/lib/linklist.h b/lib/linklist.h index fd953d0769..f922891df9 100644 --- a/lib/linklist.h +++ b/lib/linklist.h @@ -10,6 +10,18 @@ extern "C" { #endif +/* + * NOTICE: + * + * If you are reading this file in an effort to add a new list structure + * this is the wrong place to be using it. Please see the typesafe + * data structures, or ask one of the other developers. + * + * If you are reading this file as a way to update an existing usage + * of this data structure, please consider just converting the data + * structure to one of the typesafe data structures instead. + */ + /* listnodes must always contain data to be valid. Adding an empty node * to a list is invalid */ diff --git a/lib/openbsd-queue.h b/lib/openbsd-queue.h index df3bbd720f..a2df521f58 100644 --- a/lib/openbsd-queue.h +++ b/lib/openbsd-queue.h @@ -16,6 +16,22 @@ extern "C" { #endif +/* + * NOTICE: + * + * If you are reading this file in an effort to add a new queue structure + * this is the wrong place to be using it. Please see the typesafe + * data structures, or ask one of the other developers. + * + * If you are reading this file as a way to update an existing usage + * of this data structure, please consider just converting the data + * structure to one of the typesafe data structures instead. However, + * among converting datastrucutres, the the BSD ones are the lowest + * priority / should be converted last. They are already typesafe and + * use inline linking nodes, so the only gain is consistency. Please + * convert uses of linklist.h and hash.h first. + */ + /* * This file defines five types of data structures: singly-linked lists, * lists, simple queues, tail queues and XOR simple queues. diff --git a/lib/openbsd-tree.h b/lib/openbsd-tree.h index 4f3985bbca..ecc3a68f15 100644 --- a/lib/openbsd-tree.h +++ b/lib/openbsd-tree.h @@ -10,6 +10,21 @@ #ifdef __cplusplus extern "C" { #endif +/* + * NOTICE: + * + * If you are reading this file in an effort to add a new tree structure + * this is the wrong place to be using it. Please see the typesafe + * data structures, or ask one of the other developers. + * + * If you are reading this file as a way to update an existing usage + * of this data structure, please consider just converting the data + * structure to one of the typesafe data structures instead. However, + * among converting datastrucutres, the the BSD ones are the lowest + * priority / should be converted last. They are already typesafe and + * use inline linking nodes, so the only gain is consistency. Please + * convert uses of linklist.h and hash.h first. + */ /* * This file defines data structures for different types of trees: From 248bf31a4f2880133c57e36a4a2bfbbdcf3d9a9a Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 19 Jun 2024 08:01:16 -0400 Subject: [PATCH 088/347] doc: Document the usage of --enable-undefined-sanitizer Signed-off-by: Donald Sharp --- doc/developer/workflow.rst | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/doc/developer/workflow.rst b/doc/developer/workflow.rst index f720f6279e..166c96da33 100644 --- a/doc/developer/workflow.rst +++ b/doc/developer/workflow.rst @@ -1306,6 +1306,16 @@ MemorySanitizer to ``configure``. +UndefinedSanitizer + Similar to AddressSanitizer, this tool provides runtime instrumentation for + detecting use of undefined behavior in C. Testing your own code with this + tool before submission is encouraged. You can enable it by passing:: + + --enable-undefined-sanitizer + + to ``configure``. If you run FRR with this you will probably also have + to set ``sudo sysctl vm.mmap_rnd_bits=28`` + All of the above tools are available in the Clang/LLVM toolchain since 3.4. AddressSanitizer and ThreadSanitizer are available in recent versions of GCC, but are no longer actively maintained. MemorySanitizer is not available in GCC. From 8aeac1f005d5b462314c73db098878042fe6c444 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Wed, 19 Jun 2024 21:36:17 +0200 Subject: [PATCH 089/347] tests/lib: fix seqlock test seqlock_bump() used to return the value before bumping, but that's unhelpful if you were to actually need it. I had changed it to return the value after, but the update to the test got lost at some point. The return value is not in fact used anywhere in FRR, so while it is a bug, it has zero impact. NB: yes, test_seqlock is not run, which sounds wrong. The problem here is that (a) the test itself uses sleeps and is timing sensitive, which would raise false positives. And (b), the test is meaningless if executed once. It needs to be run millions of times under various conditions (e.g. load) to catch rare races, and it needs to be run on machines with "odd" memory models (in this case I used BE ppc32 and ppc64 systems as test platforms.) Fixes: 6046b690b53 ("lib/seqlock: avoid syscalls in no-waiter cases") Signed-off-by: David Lamparter --- tests/lib/test_seqlock.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/lib/test_seqlock.c b/tests/lib/test_seqlock.c index 288d4a8c25..35501cbd4a 100644 --- a/tests/lib/test_seqlock.c +++ b/tests/lib/test_seqlock.c @@ -82,11 +82,11 @@ int main(int argc, char **argv) assert(seqlock_held(&sqlo)); assert(seqlock_cur(&sqlo) == 1); - assert(seqlock_bump(&sqlo) == 1); - assert(seqlock_cur(&sqlo) == 5); assert(seqlock_bump(&sqlo) == 5); + assert(seqlock_cur(&sqlo) == 5); assert(seqlock_bump(&sqlo) == 9); assert(seqlock_bump(&sqlo) == 13); + assert(seqlock_bump(&sqlo) == 17); assert(seqlock_cur(&sqlo) == 17); assert(seqlock_held(&sqlo)); From 1f67dfb1438e74e5258786d4a769084354fd375b Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Wed, 19 Jun 2024 22:32:54 +0200 Subject: [PATCH 090/347] lib: fix typo in rcu_do() I lost an underscore somewhere along the way. Which never caused issues because we don't use that function macro. It is, however, useful for testing, so fix it. Signed-off-by: David Lamparter --- lib/frrcu.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/frrcu.h b/lib/frrcu.h index 9f07a69b52..81ab5528a9 100644 --- a/lib/frrcu.h +++ b/lib/frrcu.h @@ -156,7 +156,7 @@ extern void rcu_enqueue(struct rcu_head *head, const struct rcu_action *action); #define rcu_call(func, ptr, field) \ do { \ typeof(ptr) _ptr = (ptr); \ - void (*fptype)(typeof(ptr)); \ + void (*_fptype)(typeof(ptr)); \ struct rcu_head *_rcu_head = &_ptr->field; \ static const struct rcu_action _rcu_action = { \ .type = RCUA_CALL, \ From 4836ac071409bfff65f833ce82bd5f0338d0a8ae Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Thu, 20 Jun 2024 10:56:18 +0200 Subject: [PATCH 091/347] tests: silence TSAN warning on test_seqlock exit TSAN warns about leaving the second thread dangling. Doesn't really matter, but just add a pthread_join to get rid of the warning. Signed-off-by: David Lamparter --- tests/lib/test_seqlock.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/lib/test_seqlock.c b/tests/lib/test_seqlock.c index 35501cbd4a..937b3f34f5 100644 --- a/tests/lib/test_seqlock.c +++ b/tests/lib/test_seqlock.c @@ -111,4 +111,5 @@ int main(int argc, char **argv) writestr("main @release\n"); seqlock_release(&sqlo); sleep(1); + pthread_join(thr1, NULL); } From b9541fe77fcb706c3f265d704e15f810b0a98c14 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Thu, 20 Jun 2024 11:13:20 +0200 Subject: [PATCH 092/347] lib: use seqlock slow path with TSAN TSAN doesn't understand the OS specific "fast" seqlock code. Use the pthread mutex/condvar based path when TSAN is enabled. Signed-off-by: David Lamparter --- lib/seqlock.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/lib/seqlock.c b/lib/seqlock.c index 62ce316920..e74e6718bf 100644 --- a/lib/seqlock.c +++ b/lib/seqlock.c @@ -26,6 +26,39 @@ * OS specific synchronization wrappers * ****************************************/ +#ifndef __has_feature /* not available on old GCC */ +#define __has_feature(x) 0 +#endif + +#if (defined(__SANITIZE_THREAD__) || __has_feature(thread_sanitizer)) +/* TSAN really does not understand what is going on with the low-level + * futex/umtx calls. This leads to a whole bunch of warnings, a lot of which + * also have _extremely_ misleading text - since TSAN does not understand that + * there is in fact a synchronization primitive involved, it can end up pulling + * in completely unrelated things. + * + * What does work is the "unsupported platform" seqlock implementation based + * on a pthread mutex + condvar, since TSAN of course suppports these. + * + * It may be possible to also fix this with TSAN annotations (__tsan_acquire + * and __tsan_release), but using those (correctly) is not easy either, and + * for now just get things rolling. + */ + +#ifdef HAVE_SYNC_LINUX_FUTEX +#undef HAVE_SYNC_LINUX_FUTEX +#endif + +#ifdef HAVE_SYNC_OPENBSD_FUTEX +#undef HAVE_SYNC_OPENBSD_FUTEX +#endif + +#ifdef HAVE_SYNC_UMTX_OP +#undef HAVE_SYNC_UMTX_OP +#endif + +#endif /* TSAN */ + /* * Linux: sys_futex() */ From 17fdfe92ab666605070b7d3733332e4e02354ab8 Mon Sep 17 00:00:00 2001 From: Martin Winter Date: Wed, 15 May 2024 10:32:33 +0200 Subject: [PATCH 093/347] debian: Add option to build pkg with grpc support Signed-off-by: Martin Winter --- debian/control | 16 +++++++++++++++- debian/copyright | 25 +++++++++++++++++++++++++ debian/frr-grpc.install | 2 ++ debian/rules | 7 +++++++ doc/developer/packaging-debian.rst | 2 ++ 5 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 debian/frr-grpc.install diff --git a/debian/control b/debian/control index 12b80a77f3..4a02a36b71 100644 --- a/debian/control +++ b/debian/control @@ -33,7 +33,11 @@ Build-Depends: bison, python3-sphinx:native, texinfo (>= 4.7), lua5.3 , - liblua5.3-dev + liblua5.3-dev , + libgrpc-dev (>=1.16.1) , + libgrpc++-dev (>=1.16.1) , + protobuf-compiler (>=3.6.1) , + protobuf-compiler-grpc (>=1.16.1) Standards-Version: 4.5.0.3 Homepage: https://www.frrouting.org/ Vcs-Browser: https://github.com/FRRouting/frr/tree/debian/master @@ -136,3 +140,13 @@ Description: FRRouting suite - Python tools . Without this package installed, "reload" (as a systemd or init script invocation) will not work for the FRR daemons. + +Package: frr-grpc +Architecture: linux-any +Depends: frr (= ${binary:Version}), + ${misc:Depends}, + ${shlibs:Depends} +Description: FRRouting suite - GRPC interface + This provides the GRPC interface to the daemons. +Build-Profiles: + diff --git a/debian/copyright b/debian/copyright index edd73020bd..e1a944b338 100644 --- a/debian/copyright +++ b/debian/copyright @@ -4,6 +4,13 @@ Upstream-Contact: maintainers@frrouting.org, security@frrouting.org Source: https://www.frrouting.org/ Files: * +Comment: Note: GPL Versions of FRR binaries + If GRPC module is installed then please be aware that the + combination of the GRPC (licensed under Apache License) and + FRR (Licensed under GPLv2+) will force the resulting grpc + modules and related binaries to GPLv3 + Impacted binary files: frr/libfrrgrpc_pb.* frr/modules/grpc.so + FRR built or used without GRPC is not impacted Copyright: 1996-2003 by the original Zebra authors: Kunihiro Ishiguro Toshiaki Takada @@ -377,6 +384,24 @@ License: LGPL-2.1+ License version 2.1 can be found in the file `/usr/share/common-licenses/LGPL-2.1'. +License: GPL-3 + This package is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + . + This package is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + . + You should have received a copy of the GNU General Public License + along with this package; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + . + On Debian systems, the complete text of the GNU General + Public License can be found in `/usr/share/common-licenses/GPL-3'. + License: BSD-0-clause Redistribution and use in source and binary forms, with or without modification, are permitted. diff --git a/debian/frr-grpc.install b/debian/frr-grpc.install new file mode 100644 index 0000000000..d006439e6f --- /dev/null +++ b/debian/frr-grpc.install @@ -0,0 +1,2 @@ +usr/lib/*/frr/libfrrgrpc_pb.* +usr/lib/*/frr/modules/grpc.so diff --git a/debian/rules b/debian/rules index 0f84145718..ec8f92f755 100755 --- a/debian/rules +++ b/debian/rules @@ -33,6 +33,12 @@ else CONF_PIM6=--disable-pim6d endif +ifeq ($(filter pkg.frr.grpc,$(DEB_BUILD_PROFILES)),) + CONF_GRPC=--disable-grpc +else + CONF_GRPC=--enable-grpc +endif + export PYTHON=python3 %: @@ -51,6 +57,7 @@ override_dh_auto_configure: $(CONF_RPKI) \ $(CONF_LUA) \ $(CONF_PIM6) \ + $(CONF_GRPC) \ --with-libpam \ --enable-doc \ --enable-doc-html \ diff --git a/doc/developer/packaging-debian.rst b/doc/developer/packaging-debian.rst index c2c3b7e7e1..4109057ee5 100644 --- a/doc/developer/packaging-debian.rst +++ b/doc/developer/packaging-debian.rst @@ -68,6 +68,8 @@ buster.) +----------------+-------------------+-----------------------------------------+ | pkg.frr.pim6d | pkg.frr.nopim6d | builds pim6d (default enabled) | +----------------+-------------------+-----------------------------------------+ + | pkg.frr.grpc | pkg.frr.nogrpc | builds with grpc support (default: no) | + +----------------+-------------------+-----------------------------------------+ * the ``-uc -us`` options to disable signing the packages with your GPG key From a761db826c323c1d69eba59db31ac1f53d13e0b4 Mon Sep 17 00:00:00 2001 From: Martin Winter Date: Wed, 29 May 2024 19:13:19 +0200 Subject: [PATCH 094/347] redhat: Add option to build pkg with grpc support Signed-off-by: Martin Winter --- doc/developer/packaging-redhat.rst | 31 ++++++++++++++++-------------- redhat/frr.spec.in | 29 ++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 14 deletions(-) diff --git a/doc/developer/packaging-redhat.rst b/doc/developer/packaging-redhat.rst index d88f449926..8037873461 100644 --- a/doc/developer/packaging-redhat.rst +++ b/doc/developer/packaging-redhat.rst @@ -67,24 +67,27 @@ Tested on CentOS 6, CentOS 7, CentOS 8 and Fedora 24. ############### FRRouting (FRR) configure options ################# # with-feature options - %{!?with_pam: %global with_pam 0 } - %{!?with_ospfclient: %global with_ospfclient 1 } - %{!?with_ospfapi: %global with_ospfapi 1 } - %{!?with_irdp: %global with_irdp 1 } - %{!?with_rtadv: %global with_rtadv 1 } + %{!?with_babeld: %global with_babeld 1 } + %{!?with_bfdd: %global with_bfdd 1 } + %{!?with_bgp_vnc: %global with_bgp_vnc 0 } + %{!?with_cumulus: %global with_cumulus 0 } + %{!?with_eigrpd: %global with_eigrpd 1 } + %{!?with_fpm: %global with_fpm 1 } + %{!?with_mgmtd_test_be_client: %global with_mgmtd_test_be_client 0 } %{!?with_ldpd: %global with_ldpd 1 } - %{!?with_nhrpd: %global with_nhrpd 1 } - %{!?with_eigrp: %global with_eigrpd 1 } - %{!?with_shared: %global with_shared 1 } %{!?with_multipath: %global with_multipath 256 } - %{!?frr_user: %global frr_user frr } - %{!?vty_group: %global vty_group frrvty } - %{!?with_fpm: %global with_fpm 0 } - %{!?with_watchfrr: %global with_watchfrr 1 } - %{!?with_bgp_vnc: %global with_bgp_vnc 0 } + %{!?with_nhrpd: %global with_nhrpd 1 } + %{!?with_ospfapi: %global with_ospfapi 1 } + %{!?with_ospfclient: %global with_ospfclient 1 } + %{!?with_pam: %global with_pam 0 } + %{!?with_pbrd: %global with_pbrd 1 } %{!?with_pimd: %global with_pimd 1 } %{!?with_pim6d: %global with_pim6d 1 } - %{!?with_rpki: %global with_rpki 0 } + %{!?with_vrrpd: %global with_vrrpd 1 } + %{!?with_rtadv: %global with_rtadv 1 } + %{!?with_watchfrr: %global with_watchfrr 1 } + %{!?with_pathd: %global with_pathd 1 } + %{!?with_grpc: %global with_grpc 0 } 8. Build the RPM:: diff --git a/redhat/frr.spec.in b/redhat/frr.spec.in index f42079cd50..d6775e6e9c 100644 --- a/redhat/frr.spec.in +++ b/redhat/frr.spec.in @@ -30,6 +30,7 @@ %{!?with_rtadv: %global with_rtadv 1 } %{!?with_watchfrr: %global with_watchfrr 1 } %{!?with_pathd: %global with_pathd 1 } +%{!?with_grpc: %global with_grpc 0 } # user and group %{!?frr_user: %global frr_user frr } @@ -201,6 +202,12 @@ BuildRequires: python3-devel BuildRequires: python3-sphinx %endif %endif +%if %{with_grpc} +BuildRequires: grpc-devel >= 1.16.1 +BuildRequires: protobuf-devel >= 3.6.1 +BuildRequires: protobuf-compiler >= 3.6.1 +BuildRequires: protobuf-c-devel +%endif %if 0%{?rhel} > 7 #platform-python-devel is needed for /usr/bin/pathfix.py BuildRequires: platform-python-devel @@ -301,6 +308,17 @@ through the AgentX protocol. Provides read-only access to current routing state through standard SNMP MIBs. +%if %{with_grpc} +%package grpc +Summary: GRPC support for FRR daemons +Group: System Environment/Daemons +License: GPLv3+ +Requires: %{name} = %{version}-%{release} + +%description grpc +Adds GRPC support to the individual FRR daemons. +%endif + %prep %setup -q -n frr-%{frrversion} @@ -424,6 +442,11 @@ routing state through standard SNMP MIBs. --enable-pathd \ %else --disable-pathd \ +%endif +%if %{with_grpc} + --enable-grpc \ +%else + --disable-grpc \ %endif --enable-snmp # end @@ -783,6 +806,12 @@ sed -i 's/ -M rpki//' %{_sysconfdir}/frr/daemons %{_libdir}/frr/modules/*snmp.so +%if %{with_grpc} +%files grpc +%{_libdir}/libfrrgrpc_pb.* +%{_libdir}/frr/modules/grpc.so +%endif + %files devel %{_libdir}/lib*.so %dir %{_includedir}/%{name} From f18cb4fb58cd443fad02ed991387b301885aaaea Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Wed, 8 May 2024 19:27:22 +0200 Subject: [PATCH 095/347] pimd: make clang-format slightly less annoying The YANG module list is really better as 1-item-per-line. Signed-off-by: David Lamparter --- pimd/pim6_main.c | 2 +- pimd/pim_main.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pimd/pim6_main.c b/pimd/pim6_main.c index 5ce6985c45..24443404eb 100644 --- a/pimd/pim6_main.c +++ b/pimd/pim6_main.c @@ -94,6 +94,7 @@ struct frr_signal_t pim6d_signals[] = { }, }; +/* clang-format off */ static const struct frr_yang_module_info *const pim6d_yang_modules[] = { &frr_filter_info, &frr_interface_info, @@ -105,7 +106,6 @@ static const struct frr_yang_module_info *const pim6d_yang_modules[] = { &frr_gmp_info, }; -/* clang-format off */ FRR_DAEMON_INFO(pim6d, PIM6, .vty_port = PIM6D_VTY_PORT, .proghelp = "Protocol Independent Multicast (RFC7761) for IPv6", diff --git a/pimd/pim_main.c b/pimd/pim_main.c index 400db396c2..8f2ce0bed3 100644 --- a/pimd/pim_main.c +++ b/pimd/pim_main.c @@ -59,6 +59,7 @@ struct zebra_privs_t pimd_privs = { .cap_num_p = array_size(_caps_p), .cap_num_i = 0}; +/* clang-format off */ static const struct frr_yang_module_info *const pimd_yang_modules[] = { &frr_filter_info, &frr_interface_info, @@ -70,7 +71,6 @@ static const struct frr_yang_module_info *const pimd_yang_modules[] = { &frr_gmp_info, }; -/* clang-format off */ FRR_DAEMON_INFO(pimd, PIM, .vty_port = PIMD_VTY_PORT, .proghelp = "Implementation of the PIM routing protocol.", From 1f223ae1eed80f2552a279ee34464edf363bba6f Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Mon, 11 Jul 2022 21:58:27 +0200 Subject: [PATCH 096/347] pimd: add debugs for i-am-RP state This proved helpful in debugging the Candidate-RP code. Signed-off-by: David Lamparter --- pimd/pim_rp.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pimd/pim_rp.c b/pimd/pim_rp.c index d8d25712a3..b0fb8a509a 100644 --- a/pimd/pim_rp.c +++ b/pimd/pim_rp.c @@ -543,6 +543,9 @@ int pim_rp_new(struct pim_instance *pim, pim_addr rp_addr, struct prefix group, pim_zebra_update_all_interfaces(pim); pim_rp_check_interfaces(pim, rp_all); + if (rp_all->i_am_rp && PIM_DEBUG_PIM_NHT_RP) + zlog_debug("new RP %pPA for %pFX is ourselves", + &rp_all->rp.rpf_addr, &rp_all->group); pim_rp_refresh_group_to_rp_mapping(pim); pim_find_or_track_nexthop(pim, nht_p, NULL, rp_all, NULL); @@ -634,6 +637,9 @@ int pim_rp_new(struct pim_instance *pim, pim_addr rp_addr, struct prefix group, pim_zebra_update_all_interfaces(pim); pim_rp_check_interfaces(pim, rp_info); + if (rp_info->i_am_rp && PIM_DEBUG_PIM_NHT_RP) + zlog_debug("new RP %pPA for %pFX is ourselves", + &rp_info->rp.rpf_addr, &rp_info->group); pim_rp_refresh_group_to_rp_mapping(pim); /* Register addr with Zebra NHT */ From 18b82f64c9538b6fd3b9f61c86dfff8cbdc8c6b6 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Wed, 8 May 2024 19:25:55 +0200 Subject: [PATCH 097/347] pimd: add prefix_* and IANA_AFI v4/v6 defines The Candidate-RP code is about to use these. Signed-off-by: David Lamparter --- pimd/pim_addr.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pimd/pim_addr.h b/pimd/pim_addr.h index ecba739a5a..7b0c3f0350 100644 --- a/pimd/pim_addr.h +++ b/pimd/pim_addr.h @@ -14,11 +14,13 @@ #if PIM_IPV == 4 typedef struct in_addr pim_addr; +typedef struct prefix_ipv4 prefix_pim; #define PIM_ADDRSTRLEN INET_ADDRSTRLEN #define PIM_AF AF_INET #define PIM_AFI AFI_IP #define PIM_PROTO_REG IPPROTO_RAW +#define PIM_IANA_AFI IANA_AFI_IPV4 #define PIM_IPADDR IPADDR_V4 #define ipaddr_pim ipaddr_v4 #define PIM_MAX_BITLEN IPV4_MAX_BITLEN @@ -44,11 +46,13 @@ union pimprefixconstptr { #else typedef struct in6_addr pim_addr; +typedef struct prefix_ipv6 prefix_pim; #define PIM_ADDRSTRLEN INET6_ADDRSTRLEN #define PIM_AF AF_INET6 #define PIM_AFI AFI_IP6 #define PIM_PROTO_REG IPPROTO_PIM +#define PIM_IANA_AFI IANA_AFI_IPV6 #define PIM_IPADDR IPADDR_V6 #define ipaddr_pim ipaddr_v6 #define PIM_MAX_BITLEN IPV6_MAX_BITLEN From cca9bc193edfebbd93fbdd76bd4c3b8310f007d6 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Sat, 9 Jul 2022 18:47:43 +0200 Subject: [PATCH 098/347] pimd: allow sending packets without pinned iface The upcoming Candidate-RP code needs to send PIM packets that go through normal unicast routing, without forcing a specific output interface. Allow passing in NULL ifp to do that. Signed-off-by: David Lamparter --- pimd/pim_pim.c | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/pimd/pim_pim.c b/pimd/pim_pim.c index 1bc265b138..6a7e8924f2 100644 --- a/pimd/pim_pim.c +++ b/pimd/pim_pim.c @@ -636,17 +636,15 @@ static int pim_msg_send_frame(pim_addr src, pim_addr dst, ifindex_t ifindex, int pim_msg_send(int fd, pim_addr src, pim_addr dst, uint8_t *pim_msg, int pim_msg_size, struct interface *ifp) { - struct pim_interface *pim_ifp; - + if (ifp) { + struct pim_interface *pim_ifp = ifp->info; - pim_ifp = ifp->info; - - if (pim_ifp->pim_passive_enable) { - if (PIM_DEBUG_PIM_PACKETS) - zlog_debug( - "skip sending PIM message on passive interface %s", - ifp->name); - return 0; + if (pim_ifp->pim_passive_enable) { + if (PIM_DEBUG_PIM_PACKETS) + zlog_debug("skip sending PIM message on passive interface %s", + ifp->name); + return 0; + } } #if PIM_IPV == 4 @@ -710,7 +708,7 @@ int pim_msg_send(int fd, pim_addr src, pim_addr dst, uint8_t *pim_msg, if (PIM_DEBUG_PIM_PACKETS) zlog_debug("%s: to %pPA on %s: msg_size=%d checksum=%x", - __func__, &dst, ifp->name, pim_msg_size, + __func__, &dst, ifp ? ifp->name : "*", pim_msg_size, header->checksum); if (PIM_DEBUG_PIM_PACKETDUMP_SEND) { @@ -718,7 +716,7 @@ int pim_msg_send(int fd, pim_addr src, pim_addr dst, uint8_t *pim_msg, } pim_msg_send_frame(fd, (char *)buffer, sendlen, (struct sockaddr *)&to, - tolen, ifp->name); + tolen, ifp ? ifp->name : "*"); return 0; #else @@ -727,7 +725,7 @@ int pim_msg_send(int fd, pim_addr src, pim_addr dst, uint8_t *pim_msg, iovector[0].iov_base = pim_msg; iovector[0].iov_len = pim_msg_size; - pim_msg_send_frame(src, dst, ifp->ifindex, &iovector[0], fd); + pim_msg_send_frame(src, dst, ifp ? ifp->ifindex : 0, &iovector[0], fd); return 0; #endif From b9a02da83b65fa7066ef17f71a32f5aa0648e28e Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Fri, 25 Jun 2021 11:42:38 +0200 Subject: [PATCH 099/347] pimd: prepare NHT for tracking BSM C-RPs For BSMs, we should track which of the RP candidates in the BSM message are actually available, before trying to use them (which also puts them in NHT for that). This applies for both BSRs as well as BSM receivers. Signed-off-by: David Lamparter --- pimd/pim_bsm.c | 5 +++++ pimd/pim_nht.c | 47 ++++++++++++++++++++++++++++++++++++++++------- pimd/pim_nht.h | 7 +++++++ 3 files changed, 52 insertions(+), 7 deletions(-) diff --git a/pimd/pim_bsm.c b/pimd/pim_bsm.c index df9161943d..2d451718a9 100644 --- a/pimd/pim_bsm.c +++ b/pimd/pim_bsm.c @@ -1451,3 +1451,8 @@ int pim_bsm_process(struct interface *ifp, pim_sgaddr *sg, uint8_t *buf, return 0; } + +void pim_crp_nht_update(struct pim_instance *pim, struct pim_nexthop_cache *pnc) +{ + /* stub for Candidate-RP */ +} diff --git a/pimd/pim_nht.c b/pimd/pim_nht.c index 32cdf4bf82..57dcff3b47 100644 --- a/pimd/pim_nht.c +++ b/pimd/pim_nht.c @@ -161,18 +161,27 @@ void pim_nht_bsr_add(struct pim_instance *pim, pim_addr addr) pnc->bsr_count++; } +bool pim_nht_candrp_add(struct pim_instance *pim, pim_addr addr) +{ + struct pim_nexthop_cache *pnc; + + pnc = pim_nht_get(pim, addr); + + pnc->candrp_count++; + return CHECK_FLAG(pnc->flags, PIM_NEXTHOP_VALID); +} + static void pim_nht_drop_maybe(struct pim_instance *pim, struct pim_nexthop_cache *pnc) { if (PIM_DEBUG_PIM_NHT) - zlog_debug( - "%s: NHT %pPA(%s) rp_list count:%d upstream count:%ld BSR count:%u", - __func__, &pnc->rpf.rpf_addr, pim->vrf->name, - pnc->rp_list->count, pnc->upstream_hash->count, - pnc->bsr_count); + zlog_debug("%s: NHT %pPA(%s) rp_list count:%d upstream count:%ld BSR count:%u Cand-RP count:%u", + __func__, &pnc->rpf.rpf_addr, pim->vrf->name, + pnc->rp_list->count, pnc->upstream_hash->count, + pnc->bsr_count, pnc->candrp_count); - if (pnc->rp_list->count == 0 && pnc->upstream_hash->count == 0 - && pnc->bsr_count == 0) { + if (pnc->rp_list->count == 0 && pnc->upstream_hash->count == 0 && + pnc->bsr_count == 0 && pnc->candrp_count == 0) { struct zclient *zclient = pim_zebra_zclient_get(); pim_sendmsg_zebra_rnh(pim, zclient, pnc, @@ -258,6 +267,27 @@ void pim_nht_bsr_del(struct pim_instance *pim, pim_addr addr) pim_nht_drop_maybe(pim, pnc); } +void pim_nht_candrp_del(struct pim_instance *pim, pim_addr addr) +{ + struct pim_nexthop_cache *pnc = NULL; + struct pim_nexthop_cache lookup; + + lookup.rpf.rpf_addr = addr; + + pnc = hash_lookup(pim->rpf_hash, &lookup); + + if (!pnc) { + zlog_warn("attempting to delete nonexistent NHT C-RP entry %pPA", + &addr); + return; + } + + assertf(pnc->candrp_count > 0, "addr=%pPA", &addr); + pnc->candrp_count--; + + pim_nht_drop_maybe(pim, pnc); +} + bool pim_nht_bsr_rpf_check(struct pim_instance *pim, pim_addr bsr_addr, struct interface *src_ifp, pim_addr src_ip) { @@ -900,6 +930,9 @@ void pim_nexthop_update(struct vrf *vrf, struct prefix *match, pim_update_rp_nh(pim, pnc); if (pnc->upstream_hash->count) pim_update_upstream_nh(pim, pnc); + + if (pnc->candrp_count) + pim_crp_nht_update(pim, pnc); } int pim_ecmp_nexthop_lookup(struct pim_instance *pim, diff --git a/pimd/pim_nht.h b/pimd/pim_nht.h index a1feb76e3b..e74b375dc6 100644 --- a/pimd/pim_nht.h +++ b/pimd/pim_nht.h @@ -38,6 +38,7 @@ struct pim_nexthop_cache { * same BSR */ uint32_t bsr_count; + uint32_t candrp_count; }; struct pnc_hash_walk_data { @@ -71,4 +72,10 @@ void pim_nht_bsr_del(struct pim_instance *pim, pim_addr bsr_addr); bool pim_nht_bsr_rpf_check(struct pim_instance *pim, pim_addr bsr_addr, struct interface *src_ifp, pim_addr src_ip); void pim_upstream_nh_if_update(struct pim_instance *pim, struct interface *ifp); + +/* wrappers for usage with Candidate RPs in BSMs */ +bool pim_nht_candrp_add(struct pim_instance *pim, pim_addr addr); +void pim_nht_candrp_del(struct pim_instance *pim, pim_addr addr); +void pim_crp_nht_update(struct pim_instance *pim, struct pim_nexthop_cache *pnc); + #endif From e14c94f2b77692126210f4b7b51cf097d7f847e0 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Thu, 20 Jun 2024 12:02:25 +0200 Subject: [PATCH 100/347] tests: fix TSAN warnings in atomlist test The atomlist test consists of a sequence of (MT) sub-tests, from which counters are collected and verified. TSAN doesn't know that these counters are synchronized by way of the sub-test starting and finishing, so it complains. Just use atomics to get rid of the warning. (This is solely an issue with the test, not the atomlist code. There are no warnings from that.) Signed-off-by: David Lamparter --- tests/lib/test_atomlist.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/lib/test_atomlist.c b/tests/lib/test_atomlist.c index b50216cf92..afcfa98791 100644 --- a/tests/lib/test_atomlist.c +++ b/tests/lib/test_atomlist.c @@ -62,7 +62,7 @@ static struct asort_head shead; static struct testthread { pthread_t pt; struct seqlock sqlo; - size_t counter, nullops; + _Atomic size_t counter, nullops; } thr[NTHREADS]; struct testrun { @@ -97,10 +97,10 @@ static void trfunc_##name(unsigned int offset) \ { \ size_t i = 0, n = 0; -#define endtestrun \ - thr[offset].counter = i; \ - thr[offset].nullops = n; \ -} +#define endtestrun \ + atomic_store_explicit(&thr[offset].counter, i, memory_order_seq_cst); \ + atomic_store_explicit(&thr[offset].nullops, n, memory_order_seq_cst); \ + } deftestrun(add, "add vs. add", 0, false) for (; i < NITEM / NTHREADS; i++) @@ -288,10 +288,10 @@ static void run_tr(struct testrun *tr) sv = seqlock_bump(&sqlo) - SEQLOCK_INCR; for (size_t i = 0; i < NTHREADS; i++) { seqlock_wait(&thr[i].sqlo, seqlock_cur(&sqlo)); - s += thr[i].counter; - n += thr[i].nullops; - thr[i].counter = 0; - thr[i].nullops = 0; + s += atomic_load_explicit(&thr[i].counter, memory_order_seq_cst); + n += atomic_load_explicit(&thr[i].nullops, memory_order_seq_cst); + atomic_store_explicit(&thr[i].counter, 0, memory_order_seq_cst); + atomic_store_explicit(&thr[i].nullops, 0, memory_order_seq_cst); } delta = monotime_since(&tv, NULL); From c494702929d15141e8f3fd4a1d9f85095076a4b7 Mon Sep 17 00:00:00 2001 From: Acee Lindem Date: Fri, 31 May 2024 14:08:04 +0000 Subject: [PATCH 101/347] ospfd: Improve OSPF neighbor retransmission list granularity and precision The current OSPF neighbor retransmission operates on a single per-neighbor periodic timer that sends all LSAs on the list when it expires. Additionally, since it skips the first retransmission of received LSAs so that at least the retransmission interval (resulting in a delay of between the retransmission interval and twice the interval. In environments where the links are lossy on P2MP networks with "delay-reflood" configured (which relies on neighbor retransmission in partial meshs), the implementation is sub-optimal (to say the least). This commit reimplements OSPF neighbor retransmission as follows: 1. A new data structure making use the application managed typesafe.h doubly linked list implements an OSPF LSA list where each node includes a timestamp. 2. The existing neighbor LS retransmission LSDB data structure is augmented with a pointer to the list node on the LSA list to faciliate O(1) removal when the LSA is acknowledged. 3. The neighbor LS retransmission timer is set to the expiration timer of the LSA at the top of the list. 4. When the timer expires, LSAs are retransmitted that within the window of the current time and a small delta (50 milli-secs default). The LSAs that are retransmited are given an updated retransmission time and moved to the end of the LSA list. 5. Configuration is added to set the "retransmission-window" to a value other than 50 milliseconds. 6. Neighbor and interface LSA retransmission counters are added to provide insight into the lossiness of the links. However, these will increment quickly on non-fully meshed P2MP networks with "delay-reflood" configured. 7. Added a topotest to exercise the implementation on a non-fully meshed P2MP network with "delay-reflood" configured. The alternative was to use existing mechanisms to instroduce loss but these seem less determistic in a topotest. Signed-off-by: Acee Lindem --- doc/developer/ospf-ls-retrans.rst | 69 +++++++++ doc/developer/ospf.rst | 1 + doc/user/ospfd.rst | 12 +- lib/libospf.h | 1 + ospfd/ospf_flood.c | 146 +++++++++++++++--- ospfd/ospf_flood.h | 22 +++ ospfd/ospf_interface.c | 5 + ospfd/ospf_interface.h | 3 + ospfd/ospf_lsdb.c | 53 +++++++ ospfd/ospf_lsdb.h | 23 +++ ospfd/ospf_memory.c | 2 + ospfd/ospf_memory.h | 2 + ospfd/ospf_neighbor.c | 8 +- ospfd/ospf_neighbor.h | 7 +- ospfd/ospf_nsm.c | 6 +- ospfd/ospf_packet.c | 91 ++++++----- ospfd/ospf_packet.h | 2 +- ospfd/ospf_vty.c | 140 +++++++++++++---- .../r1/show_ip_ospf_interface.ref | 2 + tests/topotests/ospf_p2mp/r1/frr-p2mp.conf | 6 + tests/topotests/ospf_p2mp/r2/frr-p2mp.conf | 6 + tests/topotests/ospf_p2mp/r3/frr-p2mp.conf | 6 + tests/topotests/ospf_p2mp/r4/frr-p2mp.conf | 6 + .../ospf_p2mp/test_ospf_p2mp_broadcast.py | 112 ++++++++++++-- 24 files changed, 620 insertions(+), 111 deletions(-) create mode 100644 doc/developer/ospf-ls-retrans.rst diff --git a/doc/developer/ospf-ls-retrans.rst b/doc/developer/ospf-ls-retrans.rst new file mode 100644 index 0000000000..230d7a1c5d --- /dev/null +++ b/doc/developer/ospf-ls-retrans.rst @@ -0,0 +1,69 @@ +OSPF Neighor Retransmission List +================================ + +Overview +-------- + +OSPF neighbor link-state retransmission lists are implemented using +both a sparse Link State Database (LSDB) and a doubly-linked list. +Rather than previous per-neighbor periodic timer, a per-neighbor +timer is set to the expiration time of the next scheduled LSA +retransmission. + +Sparse Link State Database (LSDB) +--------------------------------- + +When an explicit or implied acknowledgment is recieved from a +neighbor in 2-way state or higher, the acknowledge LSA must be +removed from the neighbor's link state retransmission list. In order +to do this efficiently, a sparse LSDB is utilized. LSDB entries also +include a pointer to the corresponding list entry so that it may be +efficiently removed from the doubly-linked list. + +The sparse LSDB is implemented using the OSPF functions is +ospf_lsdb.[c,h]. OSPF LSDBs are implemented as an array of route +tables (lib/table.[c,h]). What is unique of the LS Retransmission +list LSDB is that each entry also has a pointer into the doubly-linked +list to facilitate fast deletions. + +Doubly-Linked List +------------------ + +In addition to the sparse LSDB, LSAs on a neighbor LS retransmission +list are also maintained in a linked-list order chronologically +with the LSA scheduled for the next retransmission at the head of +the list. + +The doubly-link list is implemented using the dlist macros in +lib/typesafe.h. + +LSA LS Retransmission List Addition +------------------------------------ + +When an LSA is added to a neighbor retransmission list, it is +added to both the sparse LSDB and the doubly-linked list with a pointer +in the LSDB route-table node to the list entry. The LSA is added to +the tail of the list with the expiration time set to the current time +with the retransmission interval added. If the neighbor retransmission +timer is not set, it is set to expire at the time of the newly added +LSA. + +LSA LS Retransmission List Deletion +----------------------------------- + +When an LSA is deleted from a neighbor retransmission list, it is +deleted from eboth the sparse LSDB and the doubly-linked list with the +pointer the LSDB route-table node used to efficiently delete the entry +from the list. If the LSA at the head of the list was removed, then +the neighbor retransmission timer is reset to the expiration of the +LSA at the head of the list or canceled if the list is empty. + +Neighbor LS Retransmission List Expiration +------------------------------------------ + +When the neighbor retransmission timer expires, the LSA at the top of +list and any in a configured window (e.g., 50 milliseconds) are +retransmitted. The LSAs that have been retransmitted are removed from +the list and readded to the tail of the list with a new expiration time +which is retransmit-interval seconds in the future. + diff --git a/doc/developer/ospf.rst b/doc/developer/ospf.rst index 837a0bd185..da4802533c 100644 --- a/doc/developer/ospf.rst +++ b/doc/developer/ospf.rst @@ -8,6 +8,7 @@ OSPFD :maxdepth: 2 ospf-api + ospf-ls-retrans ospf-sr cspf diff --git a/doc/user/ospfd.rst b/doc/user/ospfd.rst index 70c15e73de..b80adba7f0 100644 --- a/doc/user/ospfd.rst +++ b/doc/user/ospfd.rst @@ -738,7 +738,17 @@ Interfaces retransmitting Database Description and Link State Request packets. The default value is 5 seconds. -.. clicmd:: ip ospf transmit-delay (1-65535) [A.B.C.D] +.. clicmd:: ip ospf retransmit-window (20-1000) + + + Set number of milliseconds in the window for neighbor LSA retransmission. + When a neighbor Link State (LS) retransmission timer expires, LSAs scheduled + to be retransmitted within the number of milliseconds configured are + retransmitted to the neighbor. Any expiring after the window will be + retransmitted the next time the neighbor LS retransmission timer expires. + The default is 50 milliseconds. + + .. clicmd:: ip ospf transmit-delay (1-65535) [A.B.C.D] Set number of seconds for InfTransDelay value. LSAs' age should be diff --git a/lib/libospf.h b/lib/libospf.h index 0ac490a00e..f2dc5d61d9 100644 --- a/lib/libospf.h +++ b/lib/libospf.h @@ -58,6 +58,7 @@ extern "C" { #define OSPF_HELLO_DELAY_DEFAULT 10 #define OSPF_ROUTER_PRIORITY_DEFAULT 1 #define OSPF_RETRANSMIT_INTERVAL_DEFAULT 5 +#define OSPF_RETRANSMIT_WINDOW_DEFAULT 50 /* milliseconds */ #define OSPF_TRANSMIT_DELAY_DEFAULT 1 #define OSPF_DEFAULT_BANDWIDTH 10000 /* Mbps */ diff --git a/ospfd/ospf_flood.c b/ospfd/ospf_flood.c index e15871ac81..e9797ce935 100644 --- a/ospfd/ospf_flood.c +++ b/ospfd/ospf_flood.c @@ -1015,7 +1015,7 @@ void ospf_ls_request_delete(struct ospf_neighbor *nbr, struct ospf_lsa *lsa) ospf_lsdb_delete(&nbr->ls_req, lsa); } -/* Remove all LSA from neighbor's ls-requenst list. */ +/* Remove all LSAs from neighbor's ls-request list. */ void ospf_ls_request_delete_all(struct ospf_neighbor *nbr) { ospf_lsa_unlock(&nbr->ls_req_last); @@ -1061,58 +1061,114 @@ int ospf_ls_retransmit_isempty(struct ospf_neighbor *nbr) /* Add LSA to be retransmitted to neighbor's ls-retransmit list. */ void ospf_ls_retransmit_add(struct ospf_neighbor *nbr, struct ospf_lsa *lsa) { - struct ospf_lsa *old; + struct ospf_lsdb_linked_node *ls_rxmt_node; + struct ospf_lsa_list_entry *ls_rxmt_list_entry; + struct ospf_lsa *old = NULL; + bool rxmt_head_replaced = false; - old = ospf_ls_retransmit_lookup(nbr, lsa); + ls_rxmt_node = ospf_lsdb_linked_lookup(&nbr->ls_rxmt, lsa); + if (ls_rxmt_node) + old = ls_rxmt_node->info; if (ospf_lsa_more_recent(old, lsa) < 0) { if (old) { old->retransmit_counter--; + if (ls_rxmt_node->lsa_list_entry == + ospf_lsa_list_first(&nbr->ls_rxmt_list)) + rxmt_head_replaced = true; + ospf_lsa_list_del(&nbr->ls_rxmt_list, + ls_rxmt_node->lsa_list_entry); + XFREE(MTYPE_OSPF_LSA_LIST, ls_rxmt_node->lsa_list_entry); + ospf_lsdb_delete(&nbr->ls_rxmt, old); if (IS_DEBUG_OSPF(lsa, LSA_FLOODING)) - zlog_debug("RXmtL(%lu)--, NBR(%pI4(%s)), LSA[%s]", + zlog_debug("RXmtL(%lu) NBR(%pI4(%s)) Old Delete LSA[%s] on Add", ospf_ls_retransmit_count(nbr), &nbr->router_id, ospf_get_name(nbr->oi->ospf), - dump_lsa_key(old)); - ospf_lsdb_delete(&nbr->ls_rxmt, old); + dump_lsa_key(lsa)); + ospf_lsa_unlock(&old); } lsa->retransmit_counter++; + ls_rxmt_list_entry = XCALLOC(MTYPE_OSPF_LSA_LIST, + sizeof(struct ospf_lsa_list_entry)); + /* + * Set the LSA retransmission time for the neighbor; + */ + monotime(&ls_rxmt_list_entry->list_entry_time); + ls_rxmt_list_entry->list_entry_time.tv_sec += nbr->v_ls_rxmt; + + /* + * Add the LSA to the neighbor retransmission list. + */ + ls_rxmt_list_entry->lsa = ospf_lsa_lock(lsa); + ospf_lsa_list_add_tail(&nbr->ls_rxmt_list, ls_rxmt_list_entry); + ospf_lsdb_add(&nbr->ls_rxmt, lsa); + /* - * We cannot make use of the newly introduced callback function - * "lsdb->new_lsa_hook" to replace debug output below, just - * because - * it seems no simple and smart way to pass neighbor information - * to - * the common function "ospf_lsdb_add()" -- endo. + * Look up the newly added node and set the list pointer. */ + ls_rxmt_node = ospf_lsdb_linked_lookup(&nbr->ls_rxmt, lsa); + ls_rxmt_node->lsa_list_entry = ls_rxmt_list_entry; + if (IS_DEBUG_OSPF(lsa, LSA_FLOODING)) - zlog_debug("RXmtL(%lu)++, NBR(%pI4(%s)), LSA[%s]", + zlog_debug("RXmtL(%lu) NBR(%pI4(%s)) Add LSA[%s] retrans at (%ld/%ld)", ospf_ls_retransmit_count(nbr), - &nbr->router_id, - ospf_get_name(nbr->oi->ospf), - dump_lsa_key(lsa)); - ospf_lsdb_add(&nbr->ls_rxmt, lsa); + &nbr->router_id, ospf_get_name(nbr->oi->ospf), + dump_lsa_key(lsa), + (long)ls_rxmt_list_entry->list_entry_time + .tv_sec, + (long)ls_rxmt_list_entry->list_entry_time + .tv_usec); + /* + * Reset the neighbor LSA retransmission timer if isn't currently + * running or the LSA at the head of the list was updated. + */ + if (!nbr->t_ls_rxmt || rxmt_head_replaced) + ospf_ls_retransmit_set_timer(nbr); } } /* Remove LSA from neibghbor's ls-retransmit list. */ void ospf_ls_retransmit_delete(struct ospf_neighbor *nbr, struct ospf_lsa *lsa) { - if (ospf_ls_retransmit_lookup(nbr, lsa)) { + struct ospf_lsdb_linked_node *ls_rxmt_node; + + ls_rxmt_node = ospf_lsdb_linked_lookup(&nbr->ls_rxmt, lsa); + + if (ls_rxmt_node) { + bool rxmt_timer_reset; + + if (ls_rxmt_node->lsa_list_entry == + ospf_lsa_list_first(&nbr->ls_rxmt_list)) + rxmt_timer_reset = true; + else + rxmt_timer_reset = false; + lsa->retransmit_counter--; - if (IS_DEBUG_OSPF(lsa, LSA_FLOODING)) /* -- endo. */ - zlog_debug("RXmtL(%lu)--, NBR(%pI4(%s)), LSA[%s]", + ospf_lsa_list_del(&nbr->ls_rxmt_list, + ls_rxmt_node->lsa_list_entry); + XFREE(MTYPE_OSPF_LSA_LIST, ls_rxmt_node->lsa_list_entry); + ospf_lsdb_delete(&nbr->ls_rxmt, lsa); + if (IS_DEBUG_OSPF(lsa, LSA_FLOODING)) + zlog_debug("RXmtL(%lu) NBR(%pI4(%s)) Delete LSA[%s]", ospf_ls_retransmit_count(nbr), - &nbr->router_id, - ospf_get_name(nbr->oi->ospf), + &nbr->router_id, ospf_get_name(nbr->oi->ospf), dump_lsa_key(lsa)); - ospf_lsdb_delete(&nbr->ls_rxmt, lsa); + ospf_lsa_unlock(&lsa); + + /* + * If the LS retransmission entry at the head of the list was + * deleted, reset the timer. + */ + if (rxmt_timer_reset) + ospf_ls_retransmit_set_timer(nbr); } } /* Clear neighbor's ls-retransmit list. */ void ospf_ls_retransmit_clear(struct ospf_neighbor *nbr) { + struct ospf_lsa_list_entry *ls_rxmt_list_entry; struct ospf_lsdb *lsdb; int i; @@ -1128,10 +1184,54 @@ void ospf_ls_retransmit_clear(struct ospf_neighbor *nbr) ospf_ls_retransmit_delete(nbr, lsa); } + frr_each_safe (ospf_lsa_list, &nbr->ls_rxmt_list, ls_rxmt_list_entry) { + ospf_lsa_list_del(&nbr->ls_rxmt_list, ls_rxmt_list_entry); + ospf_lsa_unlock(&ls_rxmt_list_entry->lsa); + XFREE(MTYPE_OSPF_LSA_LIST, ls_rxmt_list_entry); + } + ospf_lsa_unlock(&nbr->ls_req_last); nbr->ls_req_last = NULL; } +/* + * Set the neighbor's ls-retransmit timer based on the next + * LSA retransmit time. + */ +void ospf_ls_retransmit_set_timer(struct ospf_neighbor *nbr) +{ + struct ospf_lsa_list_entry *ls_rxmt_list_entry; + + if (nbr->t_ls_rxmt) + EVENT_OFF(nbr->t_ls_rxmt); + + ls_rxmt_list_entry = ospf_lsa_list_first(&nbr->ls_rxmt_list); + if (ls_rxmt_list_entry) { + struct timeval current_time, delay; + unsigned long delay_milliseconds; + + monotime(¤t_time); + if (timercmp(¤t_time, + &ls_rxmt_list_entry->list_entry_time, >=)) + delay_milliseconds = 10; + else { + timersub(&ls_rxmt_list_entry->list_entry_time, + ¤t_time, &delay); + delay_milliseconds = (delay.tv_sec * 1000) + + (delay.tv_usec / 1000); + } + + event_add_timer_msec(master, ospf_ls_rxmt_timer, nbr, + delay_milliseconds, &nbr->t_ls_rxmt); + if (IS_DEBUG_OSPF(lsa, LSA_FLOODING)) + zlog_debug("RXmtL(%lu) NBR(%pI4(%s)) retrans timer set in %ld msecs - Head LSA(%s)", + ospf_ls_retransmit_count(nbr), + &nbr->router_id, ospf_get_name(nbr->oi->ospf), + delay_milliseconds, + dump_lsa_key(ls_rxmt_list_entry->lsa)); + } +} + /* Lookup LSA from neighbor's ls-retransmit list. */ struct ospf_lsa *ospf_ls_retransmit_lookup(struct ospf_neighbor *nbr, struct ospf_lsa *lsa) diff --git a/ospfd/ospf_flood.h b/ospfd/ospf_flood.h index 3757400d0c..d9d9537351 100644 --- a/ospfd/ospf_flood.h +++ b/ospfd/ospf_flood.h @@ -7,6 +7,26 @@ #ifndef _ZEBRA_OSPF_FLOOD_H #define _ZEBRA_OSPF_FLOOD_H +/* + * OSPF Temporal LSA List + */ +PREDECL_DLIST(ospf_lsa_list); + +struct ospf_lsa_list_entry { + /* Linkage for LSA List */ + struct ospf_lsa_list_item list_linkage; + + /* + * Time associated with the list entry. For example, for a neigbhor + * link retransmission list, this is the retransmission time. + */ + struct timeval list_entry_time; + + struct ospf_lsa *lsa; +}; + +DECLARE_DLIST(ospf_lsa_list, struct ospf_lsa_list_entry, list_linkage); + extern int ospf_flood(struct ospf *, struct ospf_neighbor *, struct ospf_lsa *, struct ospf_lsa *); extern int ospf_flood_through(struct ospf *, struct ospf_neighbor *, @@ -36,6 +56,8 @@ extern void ospf_ls_retransmit_add(struct ospf_neighbor *, struct ospf_lsa *); extern void ospf_ls_retransmit_delete(struct ospf_neighbor *, struct ospf_lsa *); extern void ospf_ls_retransmit_clear(struct ospf_neighbor *); +extern void ospf_ls_retransmit_set_timer(struct ospf_neighbor *nbr); + extern struct ospf_lsa *ospf_ls_retransmit_lookup(struct ospf_neighbor *, struct ospf_lsa *); extern void ospf_ls_retransmit_delete_nbr_area(struct ospf_area *, diff --git a/ospfd/ospf_interface.c b/ospfd/ospf_interface.c index 11ac7af7c9..803c36861d 100644 --- a/ospfd/ospf_interface.c +++ b/ospfd/ospf_interface.c @@ -542,6 +542,7 @@ static struct ospf_if_params *ospf_new_if_params(void) UNSET_IF_PARAM(oip, output_cost_cmd); UNSET_IF_PARAM(oip, transmit_delay); UNSET_IF_PARAM(oip, retransmit_interval); + UNSET_IF_PARAM(oip, retransmit_window); UNSET_IF_PARAM(oip, passive_interface); UNSET_IF_PARAM(oip, v_hello); UNSET_IF_PARAM(oip, fast_hello); @@ -599,6 +600,7 @@ void ospf_free_if_params(struct interface *ifp, struct in_addr addr) if (!OSPF_IF_PARAM_CONFIGURED(oip, output_cost_cmd) && !OSPF_IF_PARAM_CONFIGURED(oip, transmit_delay) && !OSPF_IF_PARAM_CONFIGURED(oip, retransmit_interval) && + !OSPF_IF_PARAM_CONFIGURED(oip, retransmit_window) && !OSPF_IF_PARAM_CONFIGURED(oip, passive_interface) && !OSPF_IF_PARAM_CONFIGURED(oip, v_hello) && !OSPF_IF_PARAM_CONFIGURED(oip, fast_hello) && @@ -695,6 +697,9 @@ int ospf_if_new_hook(struct interface *ifp) IF_DEF_PARAMS(ifp)->retransmit_interval = OSPF_RETRANSMIT_INTERVAL_DEFAULT; + SET_IF_PARAM(IF_DEF_PARAMS(ifp), retransmit_window); + IF_DEF_PARAMS(ifp)->retransmit_window = OSPF_RETRANSMIT_WINDOW_DEFAULT; + SET_IF_PARAM(IF_DEF_PARAMS(ifp), priority); IF_DEF_PARAMS(ifp)->priority = OSPF_ROUTER_PRIORITY_DEFAULT; diff --git a/ospfd/ospf_interface.h b/ospfd/ospf_interface.h index 45d0b7943a..a944847b5d 100644 --- a/ospfd/ospf_interface.h +++ b/ospfd/ospf_interface.h @@ -47,6 +47,8 @@ struct ospf_if_params { output_cost_cmd); /* Command Interface Output Cost */ DECLARE_IF_PARAM(uint32_t, retransmit_interval); /* Retransmission Interval */ + DECLARE_IF_PARAM(uint32_t, + retransmit_window); /* Retransmission Window */ DECLARE_IF_PARAM(uint8_t, passive_interface); /* OSPF Interface is passive: no sending or receiving (no need to @@ -296,6 +298,7 @@ struct ospf_interface { uint32_t ls_ack_out; /* LS Ack message output count. */ uint32_t discarded; /* discarded input count by error. */ uint32_t state_change; /* Number of status change. */ + uint32_t ls_rxmt_lsa; /* Number of LSAs retransmitted. */ uint32_t full_nbrs; diff --git a/ospfd/ospf_lsdb.c b/ospfd/ospf_lsdb.c index 0111c4924e..d1b3eb0d35 100644 --- a/ospfd/ospf_lsdb.c +++ b/ospfd/ospf_lsdb.c @@ -34,6 +34,59 @@ void ospf_lsdb_init(struct ospf_lsdb *lsdb) lsdb->type[i].db = route_table_init(); } +static struct route_node * +ospf_lsdb_linked_node_create(route_table_delegate_t *delegate, + struct route_table *table) +{ + struct ospf_lsdb_linked_node *node; + + node = XCALLOC(MTYPE_OSPF_LSDB_NODE, + sizeof(struct ospf_lsdb_linked_node)); + + return (struct route_node *)node; +} + +static void ospf_lsdb_linked_node_destroy(route_table_delegate_t *delegate, + struct route_table *table, + struct route_node *node) +{ + struct ospf_lsdb_linked_node *lsdb_linked_node = + (struct ospf_lsdb_linked_node *)node; + + XFREE(MTYPE_OSPF_LSDB_NODE, lsdb_linked_node); +} + +static route_table_delegate_t ospf_lsdb_linked_table_delegate = { + .create_node = ospf_lsdb_linked_node_create, + .destroy_node = ospf_lsdb_linked_node_destroy, +}; + +void ospf_lsdb_linked_init(struct ospf_lsdb *lsdb) +{ + int i; + + for (i = OSPF_MIN_LSA; i < OSPF_MAX_LSA; i++) + lsdb->type[i].db = route_table_init_with_delegate( + &ospf_lsdb_linked_table_delegate); +} + +struct ospf_lsdb_linked_node *ospf_lsdb_linked_lookup(struct ospf_lsdb *lsdb, + struct ospf_lsa *lsa) +{ + struct ospf_lsdb_linked_node *lsdb_linked_node; + struct route_table *table; + struct prefix_ls lp; + + table = lsdb->type[lsa->data->type].db; + ls_prefix_set(&lp, lsa); + lsdb_linked_node = (struct ospf_lsdb_linked_node *) + route_node_lookup(table, (struct prefix *)&lp); + if (lsdb_linked_node) + route_unlock_node((struct route_node *)lsdb_linked_node); + + return lsdb_linked_node; +} + void ospf_lsdb_free(struct ospf_lsdb *lsdb) { ospf_lsdb_cleanup(lsdb); diff --git a/ospfd/ospf_lsdb.h b/ospfd/ospf_lsdb.h index bf295ca830..e5e3be8baa 100644 --- a/ospfd/ospf_lsdb.h +++ b/ospfd/ospf_lsdb.h @@ -7,6 +7,9 @@ #ifndef _ZEBRA_OSPF_LSDB_H #define _ZEBRA_OSPF_LSDB_H +#include "prefix.h" +#include "table.h" + /* OSPF LSDB structure. */ struct ospf_lsdb { struct { @@ -43,9 +46,29 @@ struct ospf_lsdb { #define AREA_LSDB(A,T) ((A)->lsdb->type[(T)].db) #define AS_LSDB(O,T) ((O)->lsdb->type[(T)].db) +/* + * Alternate route node structure for LSDB nodes linked to + * list elements. + */ +struct ospf_lsdb_linked_node { + /* + * Caution these must be the very first fields + */ + ROUTE_NODE_FIELDS + + /* + * List entry on an LSA list, e.g., a neighbor + * retransmission list. + */ + struct ospf_lsa_list_entry *lsa_list_entry; +}; + /* OSPF LSDB related functions. */ extern struct ospf_lsdb *ospf_lsdb_new(void); extern void ospf_lsdb_init(struct ospf_lsdb *); +extern void ospf_lsdb_linked_init(struct ospf_lsdb *lsdb); +extern struct ospf_lsdb_linked_node * +ospf_lsdb_linked_lookup(struct ospf_lsdb *lsdb, struct ospf_lsa *lsa); extern void ospf_lsdb_free(struct ospf_lsdb *); extern void ospf_lsdb_cleanup(struct ospf_lsdb *); extern void ls_prefix_set(struct prefix_ls *lp, struct ospf_lsa *lsa); diff --git a/ospfd/ospf_memory.c b/ospfd/ospf_memory.c index 9854c8cae8..478af323d3 100644 --- a/ospfd/ospf_memory.c +++ b/ospfd/ospf_memory.c @@ -45,3 +45,5 @@ DEFINE_MTYPE(OSPFD, OSPF_GR_HELPER, "OSPF Graceful Restart Helper"); DEFINE_MTYPE(OSPFD, OSPF_EXTERNAL_RT_AGGR, "OSPF External Route Summarisation"); DEFINE_MTYPE(OSPFD, OSPF_P_SPACE, "OSPF TI-LFA P-Space"); DEFINE_MTYPE(OSPFD, OSPF_Q_SPACE, "OSPF TI-LFA Q-Space"); +DEFINE_MTYPE(OSPFD, OSPF_LSA_LIST, "OSPF LSA List"); +DEFINE_MTYPE(OSPFD, OSPF_LSDB_NODE, "OSPF LSDB Linked Node"); diff --git a/ospfd/ospf_memory.h b/ospfd/ospf_memory.h index d11b69abb0..e2139b517b 100644 --- a/ospfd/ospf_memory.h +++ b/ospfd/ospf_memory.h @@ -44,5 +44,7 @@ DECLARE_MTYPE(OSPF_GR_HELPER); DECLARE_MTYPE(OSPF_EXTERNAL_RT_AGGR); DECLARE_MTYPE(OSPF_P_SPACE); DECLARE_MTYPE(OSPF_Q_SPACE); +DECLARE_MTYPE(OSPF_LSA_LIST); +DECLARE_MTYPE(OSPF_LSDB_NODE); #endif /* _QUAGGA_OSPF_MEMORY_H */ diff --git a/ospfd/ospf_neighbor.c b/ospfd/ospf_neighbor.c index d47d581605..2514fc0ab3 100644 --- a/ospfd/ospf_neighbor.c +++ b/ospfd/ospf_neighbor.c @@ -68,7 +68,7 @@ struct ospf_neighbor *ospf_nbr_new(struct ospf_interface *oi) nbr->v_inactivity = OSPF_IF_PARAM(oi, v_wait); nbr->v_db_desc = OSPF_IF_PARAM(oi, retransmit_interval); nbr->v_ls_req = OSPF_IF_PARAM(oi, retransmit_interval); - nbr->v_ls_upd = OSPF_IF_PARAM(oi, retransmit_interval); + nbr->v_ls_rxmt = OSPF_IF_PARAM(oi, retransmit_interval); nbr->priority = -1; /* DD flags. */ @@ -80,8 +80,10 @@ struct ospf_neighbor *ospf_nbr_new(struct ospf_interface *oi) nbr->nbr_nbma = NULL; ospf_lsdb_init(&nbr->db_sum); - ospf_lsdb_init(&nbr->ls_rxmt); + + ospf_lsdb_linked_init(&nbr->ls_rxmt); ospf_lsdb_init(&nbr->ls_req); + ospf_lsa_list_init(&nbr->ls_rxmt_list); nbr->crypt_seqnum = 0; @@ -128,7 +130,7 @@ void ospf_nbr_free(struct ospf_neighbor *nbr) EVENT_OFF(nbr->t_inactivity); EVENT_OFF(nbr->t_db_desc); EVENT_OFF(nbr->t_ls_req); - EVENT_OFF(nbr->t_ls_upd); + EVENT_OFF(nbr->t_ls_rxmt); /* Cancel all events. */ /* Thread lookup cost would be negligible. */ event_cancel_event(master, nbr); diff --git a/ospfd/ospf_neighbor.h b/ospfd/ospf_neighbor.h index 07d095f03d..0e041f9e6d 100644 --- a/ospfd/ospf_neighbor.h +++ b/ospfd/ospf_neighbor.h @@ -9,6 +9,7 @@ #include #include +#include /* Neighbor Data Structure */ struct ospf_neighbor { @@ -44,6 +45,7 @@ struct ospf_neighbor { /* LSA data. */ struct ospf_lsdb ls_rxmt; + struct ospf_lsa_list_head ls_rxmt_list; struct ospf_lsdb db_sum; struct ospf_lsdb ls_req; struct ospf_lsa *ls_req_last; @@ -54,13 +56,13 @@ struct ospf_neighbor { uint32_t v_inactivity; uint32_t v_db_desc; uint32_t v_ls_req; - uint32_t v_ls_upd; + uint32_t v_ls_rxmt; /* Threads. */ struct event *t_inactivity; struct event *t_db_desc; struct event *t_ls_req; - struct event *t_ls_upd; + struct event *t_ls_rxmt; struct event *t_hello_reply; /* NBMA configured neighbour */ @@ -71,6 +73,7 @@ struct ospf_neighbor { struct timeval ts_last_regress; /* last regressive NSM change */ const char *last_regress_str; /* Event which last regressed NSM */ uint32_t state_change; /* NSM state change counter */ + uint32_t ls_rxmt_lsa; /* Number of LSAs retransmited. */ /* BFD information */ struct bfd_session_params *bfd_session; diff --git a/ospfd/ospf_nsm.c b/ospfd/ospf_nsm.c index c466ddcc6f..079a1fa55e 100644 --- a/ospfd/ospf_nsm.c +++ b/ospfd/ospf_nsm.c @@ -112,18 +112,16 @@ static void nsm_timer_set(struct ospf_neighbor *nbr) case NSM_Init: case NSM_TwoWay: EVENT_OFF(nbr->t_db_desc); - EVENT_OFF(nbr->t_ls_upd); + EVENT_OFF(nbr->t_ls_rxmt); EVENT_OFF(nbr->t_ls_req); break; case NSM_ExStart: OSPF_NSM_TIMER_ON(nbr->t_db_desc, ospf_db_desc_timer, nbr->v_db_desc); - EVENT_OFF(nbr->t_ls_upd); + EVENT_OFF(nbr->t_ls_rxmt); EVENT_OFF(nbr->t_ls_req); break; case NSM_Exchange: - OSPF_NSM_TIMER_ON(nbr->t_ls_upd, ospf_ls_upd_timer, - nbr->v_ls_upd); if (!IS_SET_DD_MS(nbr->dd_flags)) EVENT_OFF(nbr->t_db_desc); break; diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c index 87aaccad92..86f877b621 100644 --- a/ospfd/ospf_packet.c +++ b/ospfd/ospf_packet.c @@ -292,54 +292,66 @@ void ospf_ls_req_event(struct ospf_neighbor *nbr) event_add_event(master, ospf_ls_req_timer, nbr, 0, &nbr->t_ls_req); } -/* Cyclic timer function. Fist registered in ospf_nbr_new () in - ospf_neighbor.c */ -void ospf_ls_upd_timer(struct event *thread) +/* + * OSPF neighbor link state retransmission timer handler. Unicast + * unacknowledged LSAs to the neigbhors. + */ +void ospf_ls_rxmt_timer(struct event *thread) { struct ospf_neighbor *nbr; + int retransmit_interval, retransmit_window, rxmt_lsa_count = 0; nbr = EVENT_ARG(thread); - nbr->t_ls_upd = NULL; + nbr->t_ls_rxmt = NULL; + retransmit_interval = nbr->v_ls_rxmt; + retransmit_window = OSPF_IF_PARAM(nbr->oi, retransmit_window); /* Send Link State Update. */ if (ospf_ls_retransmit_count(nbr) > 0) { + struct ospf_lsa_list_entry *ls_rxmt_list_entry; + struct timeval current_time, latest_rxmt_time, next_rxmt_time; + struct timeval rxmt_interval = { retransmit_interval, 0 }; + struct timeval rxmt_window; struct list *update; - struct ospf_lsdb *lsdb; - int i; - int retransmit_interval; - retransmit_interval = - OSPF_IF_PARAM(nbr->oi, retransmit_interval); + /* + * Set the retransmission window based on the configured value + * in milliseconds. + */ + rxmt_window.tv_sec = retransmit_window / 1000; + rxmt_window.tv_usec = (retransmit_window % 1000) * 1000; + + /* + * Calculate the latest retransmit time for LSAs transmited in + * this timer pass by adding the retransmission window to the + * current time. Calculate the next retransmission time by adding + * the retransmit interval to the current time. + */ + monotime(¤t_time); + timeradd(¤t_time, &rxmt_window, &latest_rxmt_time); + timeradd(¤t_time, &rxmt_interval, &next_rxmt_time); - lsdb = &nbr->ls_rxmt; update = list_new(); + while ((ls_rxmt_list_entry = + ospf_lsa_list_first(&nbr->ls_rxmt_list))) { + if (timercmp(&ls_rxmt_list_entry->list_entry_time, + &latest_rxmt_time, >)) + break; - for (i = OSPF_MIN_LSA; i < OSPF_MAX_LSA; i++) { - struct route_table *table = lsdb->type[i].db; - struct route_node *rn; - - for (rn = route_top(table); rn; rn = route_next(rn)) { - struct ospf_lsa *lsa; - - if ((lsa = rn->info) != NULL) { - /* Don't retransmit an LSA if we - received it within - the last RxmtInterval seconds - this - is to allow the - neighbour a chance to acknowledge the - LSA as it may - have ben just received before the - retransmit timer - fired. This is a small tweak to what - is in the RFC, - but it will cut out out a lot of - retransmit traffic - - MAG */ - if (monotime_since(&lsa->tv_recv, NULL) - >= retransmit_interval * 1000000LL) - listnode_add(update, rn->info); - } - } + listnode_add(update, ls_rxmt_list_entry->lsa); + rxmt_lsa_count++; + + /* + * Set the next retransmit time for the LSA and move it + * to the end of the neighbor's retransmission list. + */ + ls_rxmt_list_entry->list_entry_time = next_rxmt_time; + ospf_lsa_list_del(&nbr->ls_rxmt_list, + ls_rxmt_list_entry); + ospf_lsa_list_add_tail(&nbr->ls_rxmt_list, + ls_rxmt_list_entry); + nbr->ls_rxmt_lsa++; + nbr->oi->ls_rxmt_lsa++; } if (listcount(update) > 0) @@ -348,8 +360,13 @@ void ospf_ls_upd_timer(struct event *thread) list_delete(&update); } + if (IS_DEBUG_OSPF_EVENT) + zlog_debug("RXmtL(%lu) NBR(%pI4(%s)) timer event - sent %u LSAs", + ospf_ls_retransmit_count(nbr), &nbr->router_id, + ospf_get_name(nbr->oi->ospf), rxmt_lsa_count); + /* Set LS Update retransmission timer. */ - OSPF_NSM_TIMER_ON(nbr->t_ls_upd, ospf_ls_upd_timer, nbr->v_ls_upd); + ospf_ls_retransmit_set_timer(nbr); } void ospf_ls_ack_timer(struct event *thread) diff --git a/ospfd/ospf_packet.h b/ospfd/ospf_packet.h index 234738979e..2c9dba6c88 100644 --- a/ospfd/ospf_packet.h +++ b/ospfd/ospf_packet.h @@ -140,7 +140,7 @@ extern void ospf_ls_ack_send_delayed(struct ospf_interface *); extern void ospf_ls_retransmit(struct ospf_interface *, struct ospf_lsa *); extern void ospf_ls_req_event(struct ospf_neighbor *); -extern void ospf_ls_upd_timer(struct event *thread); +extern void ospf_ls_rxmt_timer(struct event *thread); extern void ospf_ls_ack_timer(struct event *thread); extern void ospf_poll_timer(struct event *thread); extern void ospf_hello_reply_timer(struct event *thread); diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index 3a11b21232..7a7a684dd6 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -815,6 +815,7 @@ struct ospf_vl_config_data { int del_keychain; int hello_interval; /* Obvious what these are... */ int retransmit_interval; + int retransmit_window; int transmit_delay; int dead_interval; }; @@ -957,6 +958,12 @@ static int ospf_vl_set_timers(struct ospf_vl_data *vl_data, vl_config->retransmit_interval; } + if (vl_config->retransmit_window) { + SET_IF_PARAM(IF_DEF_PARAMS(ifp), retransmit_window); + IF_DEF_PARAMS(ifp)->retransmit_window = + vl_config->retransmit_window; + } + if (vl_config->transmit_delay) { SET_IF_PARAM(IF_DEF_PARAMS(ifp), transmit_delay); IF_DEF_PARAMS(ifp)->transmit_delay = vl_config->transmit_delay; @@ -1012,14 +1019,16 @@ static int ospf_vl_set(struct ospf *ospf, struct ospf_vl_config_data *vl_config) "Use null authentication\n" \ "Use message-digest authentication\n" -#define VLINK_HELPSTR_TIME_PARAM \ - "Time between HELLO packets\n" \ - "Seconds\n" \ - "Time between retransmitting lost link state advertisements\n" \ - "Seconds\n" \ - "Link state transmit delay\n" \ - "Seconds\n" \ - "Interval time after which a neighbor is declared down\n" \ +#define VLINK_HELPSTR_TIME_PARAM \ + "Time between HELLO packets\n" \ + "Seconds\n" \ + "Time between retransmitting lost link state advertisements\n" \ + "Seconds\n" \ + "Window for LSA retransmit - Retransmit LSAs expiring in this window\n" \ + "Milliseconds\n" \ + "Link state transmit delay\n" \ + "Seconds\n" \ + "Interval time after which a neighbor is declared down\n" \ "Seconds\n" #define VLINK_HELPSTR_AUTH_SIMPLE \ @@ -1204,7 +1213,7 @@ DEFUN (no_ospf_area_vlink, DEFUN (ospf_area_vlink_intervals, ospf_area_vlink_intervals_cmd, - "area virtual-link A.B.C.D {hello-interval (1-65535)|retransmit-interval (1-65535)|transmit-delay (1-65535)|dead-interval (1-65535)}", + "area virtual-link A.B.C.D {hello-interval (1-65535)|retransmit-interval (1-65535)|retransmit-window (20-10000)|transmit-delay (1-65535)|dead-interval (1-65535)}", VLINK_HELPSTR_IPADDR VLINK_HELPSTR_TIME_PARAM) { @@ -1236,6 +1245,9 @@ DEFUN (ospf_area_vlink_intervals, else if (strmatch(argv[idx]->text, "retransmit-interval")) vl_config.retransmit_interval = strtol(argv[++idx]->arg, NULL, 10); + else if (strmatch(argv[idx]->text, "retransmit-window")) + vl_config.retransmit_window = strtol(argv[++idx]->arg, + NULL, 10); else if (strmatch(argv[idx]->text, "transmit-delay")) vl_config.transmit_delay = strtol(argv[++idx]->arg, NULL, 10); @@ -1250,7 +1262,7 @@ DEFUN (ospf_area_vlink_intervals, DEFUN (no_ospf_area_vlink_intervals, no_ospf_area_vlink_intervals_cmd, - "no area virtual-link A.B.C.D {hello-interval (1-65535)|retransmit-interval (1-65535)|transmit-delay (1-65535)|dead-interval (1-65535)}", + "no area virtual-link A.B.C.D {hello-interval (1-65535)|retransmit-interval (1-65535)|retransmit-window (20-1000)|transmit-delay (1-65535)|dead-interval (1-65535)}", NO_STR VLINK_HELPSTR_IPADDR VLINK_HELPSTR_TIME_PARAM) @@ -1282,6 +1294,9 @@ DEFUN (no_ospf_area_vlink_intervals, else if (strmatch(argv[idx]->text, "retransmit-interval")) vl_config.retransmit_interval = OSPF_RETRANSMIT_INTERVAL_DEFAULT; + else if (strmatch(argv[idx]->text, "retransmit-window")) + vl_config.retransmit_window = + OSPF_RETRANSMIT_WINDOW_DEFAULT; else if (strmatch(argv[idx]->text, "transmit-delay")) vl_config.transmit_delay = OSPF_TRANSMIT_DELAY_DEFAULT; else if (strmatch(argv[idx]->text, "dead-interval")) @@ -3846,6 +3861,10 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, json_object_int_add( json_interface_sub, "timerRetransmitSecs", OSPF_IF_PARAM(oi, retransmit_interval)); + json_object_int_add(json_interface_sub, + "timerRetransmitWindowMsecs", + OSPF_IF_PARAM(oi, + retransmit_window)); } else { vty_out(vty, " Timer intervals configured,"); vty_out(vty, " Hello "); @@ -3964,6 +3983,16 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, "nbrFilterPrefixList", "N/A"); } + + /* Non-Traffic interface counters + */ + if (use_json) + json_object_int_add(json_interface_sub, + "lsaRetransmissions", + oi->ls_rxmt_lsa); + else + vty_out(vty, " LSA retransmissions: %u\n", + oi->ls_rxmt_lsa); } } @@ -5177,12 +5206,20 @@ static void show_ip_ospf_neighbor_detail_sub(struct vty *vty, lookup_msg(ospf_ism_state_msg, ospf_nbr_ism_state(nbr), NULL)); } + /* Show state changes. */ if (use_json) json_object_int_add(json_neigh, "stateChangeCounter", nbr->state_change); else - vty_out(vty, " %d state changes\n", nbr->state_change); + vty_out(vty, " %d state changes\n", nbr->state_change); + + /* Show LSA retransmissions. */ + if (use_json) + json_object_int_add(json_neigh, "lsaRetransmissions", + nbr->ls_rxmt_lsa); + else + vty_out(vty, " %u LSA retransmissions\n", nbr->ls_rxmt_lsa); if (nbr->ts_last_progress.tv_sec || nbr->ts_last_progress.tv_usec) { struct timeval res; @@ -5231,7 +5268,7 @@ static void show_ip_ospf_neighbor_detail_sub(struct vty *vty, if (DR(oi).s_addr == INADDR_ANY) { if (!use_json) vty_out(vty, - " No designated router on this network\n"); + " No designated router on this network\n"); } else { nbr_dr = ospf_nbr_lookup_by_addr(oi->nbrs, &DR(oi)); if (nbr_dr) { @@ -5250,14 +5287,14 @@ static void show_ip_ospf_neighbor_detail_sub(struct vty *vty, if (nbr_bdr == NULL) { if (!use_json) vty_out(vty, - " No backup designated router on this network\n"); + " No backup designated router on this network\n"); } else { if (use_json) json_object_string_addf(json_neigh, "routerDesignatedBackupId", "%pI4", &nbr_bdr->router_id); else - vty_out(vty, " BDR is %pI4\n", &nbr_bdr->router_id); + vty_out(vty, " BDR is %pI4\n", &nbr_bdr->router_id); } /* Show options. */ @@ -5347,7 +5384,7 @@ static void show_ip_ospf_neighbor_detail_sub(struct vty *vty, /* Show Link State Update Retransmission thread. */ if (use_json) { - if (nbr->t_ls_upd != NULL) + if (nbr->t_ls_rxmt != NULL) json_object_string_add( json_neigh, "threadLinkStateUpdateRetransmission", @@ -5355,7 +5392,7 @@ static void show_ip_ospf_neighbor_detail_sub(struct vty *vty, } else vty_out(vty, " Thread Link State Update Retransmission %s\n\n", - nbr->t_ls_upd != NULL ? "on" : "off"); + nbr->t_ls_rxmt != NULL ? "on" : "off"); if (!use_json) { vty_out(vty, " Graceful restart Helper info:\n"); @@ -7993,7 +8030,7 @@ static void ospf_nbr_timer_update(struct ospf_interface *oi) nbr->v_inactivity = OSPF_IF_PARAM(oi, v_wait); nbr->v_db_desc = OSPF_IF_PARAM(oi, retransmit_interval); nbr->v_ls_req = OSPF_IF_PARAM(oi, retransmit_interval); - nbr->v_ls_upd = OSPF_IF_PARAM(oi, retransmit_interval); + nbr->v_ls_rxmt = OSPF_IF_PARAM(oi, retransmit_interval); } } @@ -8728,6 +8765,40 @@ DEFUN_HIDDEN (no_ospf_retransmit_interval, return no_ip_ospf_retransmit_interval(self, vty, argc, argv); } +DEFPY(ip_ospf_retransmit_window, ip_ospf_retransmit_window_addr_cmd, + "[no] ip ospf retransmit-window ![(20-1000)]$retransmit-window [A.B.C.D]$ip_addr", NO_STR + "IP Information\n" + "OSPF interface commands\n" + "Window for LSA retransmit - Retransmit LSAs expiring in this window\n" + "Milliseconds\n" + "Address of interface\n") +{ + VTY_DECLVAR_CONTEXT(interface, ifp); + struct ospf_if_params *params; + + params = IF_DEF_PARAMS(ifp); + + if (ip_addr.s_addr != INADDR_ANY) { + params = ospf_get_if_params(ifp, ip_addr); + ospf_if_update_params(ifp, ip_addr); + } + + if (no) { + UNSET_IF_PARAM(params, retransmit_window); + params->retransmit_window = OSPF_RETRANSMIT_WINDOW_DEFAULT; + } else { + SET_IF_PARAM(params, retransmit_window); + params->retransmit_window = retransmit_window; + } + + /* + * There is nothing to do when the retransmit-window changes, any + * change will take effect the next time the interface LSA retransmision + * timer expires. + */ + return CMD_SUCCESS; +} + DEFPY (ip_ospf_gr_hdelay, ip_ospf_gr_hdelay_cmd, "ip ospf graceful-restart hello-delay (1-1800)", @@ -12210,6 +12281,17 @@ static int config_write_interface_one(struct vty *vty, struct vrf *vrf) vty_out(vty, "\n"); } + /* Retransmit Window print. */ + if (OSPF_IF_PARAM_CONFIGURED(params, retransmit_window) && + params->retransmit_window != + OSPF_RETRANSMIT_WINDOW_DEFAULT) { + vty_out(vty, " ip ospf retransmit-window %u", + params->retransmit_window); + if (params != IF_DEF_PARAMS(ifp) && rn) + vty_out(vty, " %pI4", &rn->p.u.prefix4); + vty_out(vty, "\n"); + } + /* Transmit Delay print. */ if (OSPF_IF_PARAM_CONFIGURED(params, transmit_delay) && params->transmit_delay @@ -12567,19 +12649,22 @@ static int config_write_virtual_link(struct vty *vty, struct ospf *ospf) oi = vl_data->vl_oi; /* timers */ - if (OSPF_IF_PARAM(oi, v_hello) - != OSPF_HELLO_INTERVAL_DEFAULT - || OSPF_IF_PARAM(oi, v_wait) - != OSPF_ROUTER_DEAD_INTERVAL_DEFAULT - || OSPF_IF_PARAM(oi, retransmit_interval) - != OSPF_RETRANSMIT_INTERVAL_DEFAULT - || OSPF_IF_PARAM(oi, transmit_delay) - != OSPF_TRANSMIT_DELAY_DEFAULT) + if (OSPF_IF_PARAM(oi, v_hello) != + OSPF_HELLO_INTERVAL_DEFAULT || + OSPF_IF_PARAM(oi, v_wait) != + OSPF_ROUTER_DEAD_INTERVAL_DEFAULT || + OSPF_IF_PARAM(oi, retransmit_interval) != + OSPF_RETRANSMIT_INTERVAL_DEFAULT || + OSPF_IF_PARAM(oi, retransmit_window) != + OSPF_RETRANSMIT_WINDOW_DEFAULT || + OSPF_IF_PARAM(oi, transmit_delay) != + OSPF_TRANSMIT_DELAY_DEFAULT) vty_out(vty, - " area %s virtual-link %pI4 hello-interval %d retransmit-interval %d transmit-delay %d dead-interval %d\n", + " area %s virtual-link %pI4 hello-interval %d retransmit-interval %d retransmit-window %d transmit-delay %d dead-interval %d\n", buf, &vl_data->vl_peer, OSPF_IF_PARAM(oi, v_hello), OSPF_IF_PARAM(oi, retransmit_interval), + OSPF_IF_PARAM(oi, retransmit_window), OSPF_IF_PARAM(oi, transmit_delay), OSPF_IF_PARAM(oi, v_wait)); else @@ -13112,6 +13197,9 @@ static void ospf_vty_if_init(void) install_element(INTERFACE_NODE, &no_ip_ospf_retransmit_interval_addr_cmd); + /* "ip ospf retransmit-window" commands. */ + install_element(INTERFACE_NODE, &ip_ospf_retransmit_window_addr_cmd); + /* "ip ospf transmit-delay" commands. */ install_element(INTERFACE_NODE, &ip_ospf_transmit_delay_addr_cmd); install_element(INTERFACE_NODE, &no_ip_ospf_transmit_delay_addr_cmd); diff --git a/tests/topotests/all_protocol_startup/r1/show_ip_ospf_interface.ref b/tests/topotests/all_protocol_startup/r1/show_ip_ospf_interface.ref index f52b51d9d8..e4e3290111 100644 --- a/tests/topotests/all_protocol_startup/r1/show_ip_ospf_interface.ref +++ b/tests/topotests/all_protocol_startup/r1/show_ip_ospf_interface.ref @@ -11,6 +11,7 @@ r1-eth0 is up Hello due in XX.XXXs Neighbor Count is 0, Adjacent neighbor count is 0 Graceful Restart hello delay: 10s + LSA retransmissions: 0 r1-eth3 is up ifindex X, MTU 1500 bytes, BW XX Mbit Internet Address 192.168.3.1/26, Broadcast 192.168.3.63, Area 0.0.0.0 @@ -24,3 +25,4 @@ r1-eth3 is up Hello due in XX.XXXs Neighbor Count is 0, Adjacent neighbor count is 0 Graceful Restart hello delay: 10s + LSA retransmissions: 0 diff --git a/tests/topotests/ospf_p2mp/r1/frr-p2mp.conf b/tests/topotests/ospf_p2mp/r1/frr-p2mp.conf index cb4538c0e3..89f255bb44 100644 --- a/tests/topotests/ospf_p2mp/r1/frr-p2mp.conf +++ b/tests/topotests/ospf_p2mp/r1/frr-p2mp.conf @@ -1,4 +1,10 @@ ! +!log file ospfd.log debug +! debug ospf event +! debug ospf client +! debug ospf lsa +! debug ospf packet all + hostname r1 password zebra log file /tmp/r1-frr.log diff --git a/tests/topotests/ospf_p2mp/r2/frr-p2mp.conf b/tests/topotests/ospf_p2mp/r2/frr-p2mp.conf index 0ca8aec3bf..429330987e 100644 --- a/tests/topotests/ospf_p2mp/r2/frr-p2mp.conf +++ b/tests/topotests/ospf_p2mp/r2/frr-p2mp.conf @@ -1,4 +1,10 @@ ! +!log file ospfd.log debug +! debug ospf event +! debug ospf client +! debug ospf lsa +! debug ospf packet all +! hostname r2 password zebra log file /tmp/r1-frr.log diff --git a/tests/topotests/ospf_p2mp/r3/frr-p2mp.conf b/tests/topotests/ospf_p2mp/r3/frr-p2mp.conf index 41ea70d443..eada78450e 100644 --- a/tests/topotests/ospf_p2mp/r3/frr-p2mp.conf +++ b/tests/topotests/ospf_p2mp/r3/frr-p2mp.conf @@ -1,4 +1,10 @@ ! +!log file ospfd.log debug +! debug ospf event +! debug ospf client +! debug ospf lsa +! debug ospf packet all +! hostname r3 password zebra log file /tmp/r1-frr.log diff --git a/tests/topotests/ospf_p2mp/r4/frr-p2mp.conf b/tests/topotests/ospf_p2mp/r4/frr-p2mp.conf index 21fa9c72f9..3146ea0957 100644 --- a/tests/topotests/ospf_p2mp/r4/frr-p2mp.conf +++ b/tests/topotests/ospf_p2mp/r4/frr-p2mp.conf @@ -1,4 +1,10 @@ ! +!log file ospfd.log debug +! debug ospf event +! debug ospf client +! debug ospf lsa +! debug ospf packet all +! hostname r4 password zebra log file /tmp/r1-frr.log diff --git a/tests/topotests/ospf_p2mp/test_ospf_p2mp_broadcast.py b/tests/topotests/ospf_p2mp/test_ospf_p2mp_broadcast.py index d52c8147fe..455c737f0d 100644 --- a/tests/topotests/ospf_p2mp/test_ospf_p2mp_broadcast.py +++ b/tests/topotests/ospf_p2mp/test_ospf_p2mp_broadcast.py @@ -9,6 +9,7 @@ import os import sys +from time import sleep from functools import partial import pytest @@ -113,7 +114,9 @@ def teardown_module(): tgen.stop_topology() -def verify_p2mp_interface(tgen, router, nbr_cnt, nbr_adj_cnt, nbr_filter): +def verify_p2mp_interface( + tgen, router, nbr_cnt, nbr_adj_cnt, delay_reflood, nbr_filter +): "Verify the P2MP Configuration and interface settings" topo_router = tgen.gears[router] @@ -147,7 +150,7 @@ def verify_p2mp_interface(tgen, router, nbr_cnt, nbr_adj_cnt, nbr_filter): "nbrCount": nbr_cnt, "nbrAdjacentCount": nbr_adj_cnt, "prefixSuppression": False, - "p2mpDelayReflood": False, + "p2mpDelayReflood": delay_reflood, "nbrFilterPrefixList": nbr_filter, } } @@ -280,7 +283,7 @@ def test_p2mp_broadcast_interface(): pytest.skip("Skipped because of router(s) failure") step("Verify router r1 interface r1-eth0 p2mp configuration") - verify_p2mp_interface(tgen, "r1", 3, 3, "N/A") + verify_p2mp_interface(tgen, "r1", 3, 3, False, "N/A") step("Verify router r1 p2mp interface r1-eth0 neighbors") verify_p2mp_neighbor( @@ -305,7 +308,7 @@ def test_p2mp_broadcast_interface(): step("Verify router r1 interface r1-eth0 p2mp configuration application") r1.vtysh_cmd("conf t\ninterface r1-eth0\nip ospf network point-to-multipoint") - verify_p2mp_interface(tgen, "r1", 3, 3, "N/A") + verify_p2mp_interface(tgen, "r1", 3, 3, False, "N/A") step("Verify restablishment of r1-eth0 p2mp neighbors") verify_p2mp_neighbor( @@ -324,14 +327,14 @@ def test_p2mp_broadcast_interface(): verify_p2mp_route(tgen, "r1", "10.1.4.0/24", 24, "10.1.0.4", "r1-eth0") -def test_p2mp_broadcast_neighbor_filter(): +def p2mp_broadcast_neighbor_filter_common(delay_reflood): tgen = get_topogen() if tgen.routers_have_failure(): pytest.skip("Skipped because of router(s) failure") step("Verify router r1 interface r1-eth0 p2mp configuration") - verify_p2mp_interface(tgen, "r1", 3, 3, "N/A") + verify_p2mp_interface(tgen, "r1", 3, 3, delay_reflood, "N/A") step("Verify router r1 p2mp interface r1-eth0 neighbors") verify_p2mp_neighbor( @@ -362,7 +365,7 @@ def test_p2mp_broadcast_neighbor_filter(): assert neighbor_filter_cfg == " ip ospf neighbor-filter nbr-filter", assertmsg step("Verify non-existent neighbor-filter is not applied to r1 interfaces") - verify_p2mp_interface(tgen, "r1", 3, 3, "N/A") + verify_p2mp_interface(tgen, "r1", 3, 3, delay_reflood, "N/A") step("Add nbr-filter prefix-list configuration to r1") r1.vtysh_cmd("conf t\nip prefix-list nbr-filter seq 200 permit any") @@ -370,7 +373,7 @@ def test_p2mp_broadcast_neighbor_filter(): step( "Verify neighbor-filter is now applied to r1 interface and neighbors still adjacent" ) - verify_p2mp_interface(tgen, "r1", 3, 3, "nbr-filter") + verify_p2mp_interface(tgen, "r1", 3, 3, delay_reflood, "nbr-filter") step("Add nbr-filter prefix-list configuration to block r4") r1.vtysh_cmd("conf t\nip prefix-list nbr-filter seq 10 deny 10.1.0.4/32") @@ -378,7 +381,7 @@ def test_p2mp_broadcast_neighbor_filter(): step( "Verify neighbor-filter is now applied to r1 interface and r4 is no longer adjacent" ) - verify_p2mp_interface(tgen, "r1", 2, 2, "nbr-filter") + verify_p2mp_interface(tgen, "r1", 2, 2, delay_reflood, "nbr-filter") verify_p2mp_neighbor_missing(tgen, "r1", "4.4.4.4") step("Verify route to r4 subnet is now through r2") @@ -390,7 +393,7 @@ def test_p2mp_broadcast_neighbor_filter(): step( "Verify neighbor-filter is now applied to r1 interface and r2 is no longer adjacent" ) - verify_p2mp_interface(tgen, "r1", 1, 1, "nbr-filter") + verify_p2mp_interface(tgen, "r1", 1, 1, delay_reflood, "nbr-filter") verify_p2mp_neighbor_missing(tgen, "r1", "2.2.2.2") step("Verify route to r4 and r2 subnet are now through r3") @@ -406,24 +409,105 @@ def test_p2mp_broadcast_neighbor_filter(): assert rc, assertmsg step("Verify interface neighbor-filter is removed and neighbors present") - verify_p2mp_interface(tgen, "r1", 3, 3, "N/A") + verify_p2mp_interface(tgen, "r1", 3, 3, delay_reflood, "N/A") step("Add neighbor filter configuration and verify neighbors are filtered") r1.vtysh_cmd("conf t\ninterface r1-eth0\nip ospf neighbor-filter nbr-filter") - verify_p2mp_interface(tgen, "r1", 1, 1, "nbr-filter") + verify_p2mp_interface(tgen, "r1", 1, 1, delay_reflood, "nbr-filter") verify_p2mp_neighbor_missing(tgen, "r1", "2.2.2.2") verify_p2mp_neighbor_missing(tgen, "r1", "4.4.4.4") step("Remove nbr-filter prefix-list configuration to block r2 and verify neighbor") r1.vtysh_cmd("conf t\nno ip prefix-list nbr-filter seq 20") - verify_p2mp_interface(tgen, "r1", 2, 2, "nbr-filter") + verify_p2mp_interface(tgen, "r1", 2, 2, delay_reflood, "nbr-filter") verify_p2mp_neighbor( tgen, "r1", "2.2.2.2", "Full/DROther", "10.1.0.2", "r1-eth0:10.1.0.1" ) step("Delete nbr-filter prefix-list and verify neighbors are present") r1.vtysh_cmd("conf t\nno ip prefix-list nbr-filter") - verify_p2mp_interface(tgen, "r1", 3, 3, "N/A") + verify_p2mp_interface(tgen, "r1", 3, 3, delay_reflood, "N/A") + + +def test_p2mp_broadcast_neighbor_filter(): + p2mp_broadcast_neighbor_filter_common(False) + + +def test_p2mp_broadcast_neighbor_filter_delay_reflood(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip("Skipped because of router(s) failure") + + step("Modify router r1 interface r1-eth0 p2mp delay-reflood configuration") + r1 = tgen.gears["r1"] + r1.vtysh_cmd( + "conf t\ninterface r1-eth0\nip ospf network point-to-multipoint delay-reflood" + ) + verify_p2mp_interface(tgen, "r1", 3, 3, True, "N/A") + + step("Modify router r2 interface r2-eth0 p2mp delay-reflood configuration") + r2 = tgen.gears["r2"] + r2.vtysh_cmd( + "conf t\ninterface r2-eth0\nip ospf network point-to-multipoint delay-reflood" + ) + + step("Modify router r3 interface r3-eth0 p2mp delay-reflood configuration") + r3 = tgen.gears["r3"] + r3.vtysh_cmd( + "conf t\ninterface r3-eth0\nip ospf network point-to-multipoint delay-reflood" + ) + + step("Modify router r4 interface r4-eth0 p2mp delay-reflood configuration") + r4 = tgen.gears["r4"] + r4.vtysh_cmd( + "conf t\ninterface r4-eth0\nip ospf network point-to-multipoint delay-reflood" + ) + + p2mp_broadcast_neighbor_filter_common(True) + + step("Recreate a partial P2MP mesh with neighbor filters") + step("Add nbr-filter prefix-list configuration to block r4") + r1.vtysh_cmd("conf t\nip prefix-list nbr-filter seq 30 permit any") + r1.vtysh_cmd("conf t\nip prefix-list nbr-filter seq 10 deny 10.1.0.3/32") + r1.vtysh_cmd("conf t\nip prefix-list nbr-filter seq 20 deny 10.1.0.4/32") + r1.vtysh_cmd("conf t\ninterface r1-eth0\nip ospf neighbor-filter nbr-filter") + + r2.vtysh_cmd("conf t\nip prefix-list nbr-filter seq 30 permit any") + r2.vtysh_cmd("conf t\nip prefix-list nbr-filter seq 10 deny 10.1.0.4/32") + r2.vtysh_cmd("conf t\ninterface r2-eth0\nip ospf neighbor-filter nbr-filter") + + r3.vtysh_cmd("conf t\nip prefix-list nbr-filter seq 30 permit any") + r3.vtysh_cmd("conf t\nip prefix-list nbr-filter seq 10 deny 10.1.0.1/32") + r3.vtysh_cmd("conf t\ninterface r3-eth0\nip ospf neighbor-filter nbr-filter") + + r4.vtysh_cmd("conf t\nip prefix-list nbr-filter seq 30 permit any") + r4.vtysh_cmd("conf t\nip prefix-list nbr-filter seq 10 deny 10.1.0.1/32") + r4.vtysh_cmd("conf t\nip prefix-list nbr-filter seq 20 deny 10.1.0.2/32") + r4.vtysh_cmd("conf t\ninterface r4-eth0\nip ospf neighbor-filter nbr-filter") + + step( + "Add redistribution and spaced static routes to r1 to test delay flood retransmission" + ) + r1.vtysh_cmd("conf t\nrouter ospf\nredistribute static") + r1.vtysh_cmd("conf t\nip route 20.1.1.1/32 null0") + sleep(1) + r1.vtysh_cmd("conf t\nip route 20.1.1.2/32 null0") + sleep(1) + r1.vtysh_cmd("conf t\nip route 20.1.1.3/32 null0") + sleep(1) + r1.vtysh_cmd("conf t\nip route 20.1.1.4/32 null0") + sleep(1) + r1.vtysh_cmd("conf t\nip route 20.1.1.5/32 null0") + sleep(1) + + step( + "Verify the routes are installed on r1 with delay-reflood in P2MP partial mesh" + ) + verify_p2mp_route(tgen, "r4", "20.1.1.1/32", 32, "10.1.0.3", "r4-eth0") + verify_p2mp_route(tgen, "r4", "20.1.1.2/32", 32, "10.1.0.3", "r4-eth0") + verify_p2mp_route(tgen, "r4", "20.1.1.3/32", 32, "10.1.0.3", "r4-eth0") + verify_p2mp_route(tgen, "r4", "20.1.1.4/32", 32, "10.1.0.3", "r4-eth0") def test_memory_leak(): From e4d843b438ae7cbae89ae47af0754fb1db153c6c Mon Sep 17 00:00:00 2001 From: Chirag Shah Date: Tue, 18 Jun 2024 17:21:49 -0700 Subject: [PATCH 102/347] zebra: fix evpn mh bond member proto reinstall In case of EVPN MH bond, a member port going in protodown state due to external reason (one case being linkflap), frr updates the state correctly but upon manually clearing external reason trigger FRR to reinstate protodown without any reason code. Fix is to ensure if the protodown reason was external and new state is to have protodown 'off' then do no reinstate protodown. Ticket: #3947432 Testing: switch:#ip link show swp1 4: swp1: mtu 9216 qdisc pfifo_fast master bond1 state DOWN mode DEFAULT group default qlen 1000 link/ether 1c:34:da:2c:aa:68 brd ff:ff:ff:ff:ff:ff protodown on protodown_reason switch:#ip link set swp1 protodown off protodown_reason linkflap off switch:#ip link show swp1 4: swp1: mtu 9216 qdisc pfifo_fast master bond1 state DOWN mode DEFAULT group default qlen 1000 link/ether 1c:34:da:2c:aa:68 brd ff:ff:ff:ff:ff:ff Signed-off-by: Chirag Shah --- zebra/interface.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/zebra/interface.c b/zebra/interface.c index b824977f9e..f1f24cc29f 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -1656,8 +1656,10 @@ static void interface_if_protodown(struct interface *ifp, bool protodown, uint32_t rc_bitfield) { struct zebra_if *zif = ifp->info; - bool old_protodown; + bool old_protodown, reason_extern; + reason_extern = !!CHECK_FLAG(zif->protodown_rc, + ZEBRA_PROTODOWN_EXTERNAL); /* * Set our reason code to note it wasn't us. * If the reason we got from the kernel is ONLY frr though, don't @@ -1673,8 +1675,8 @@ static void interface_if_protodown(struct interface *ifp, bool protodown, return; if (IS_ZEBRA_DEBUG_EVPN_MH_ES || IS_ZEBRA_DEBUG_DPLANE) - zlog_debug("interface %s dplane change, protodown %s", - ifp->name, protodown ? "on" : "off"); + zlog_debug("interface %s dplane change, protodown %s curr reason_extern %u", + ifp->name, protodown ? "on" : "off", reason_extern); /* Set protodown, respectively */ COND_FLAG(zif->flags, ZIF_FLAG_PROTODOWN, protodown); @@ -1699,6 +1701,13 @@ static void interface_if_protodown(struct interface *ifp, bool protodown, return; } + if (!protodown && reason_extern) { + if (IS_ZEBRA_DEBUG_EVPN_MH_ES || IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("bond member %s has protodown reason external and clear the reason, skip reinstall.", + ifp->name); + return; + } + if (IS_ZEBRA_DEBUG_EVPN_MH_ES || IS_ZEBRA_DEBUG_KERNEL) zlog_debug( "bond mbr %s reinstate protodown %s in the dplane", From d4390fc21795b09b84a6b95b1f8fa1ac2b3dcda9 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Thu, 20 Jun 2024 18:02:26 +0200 Subject: [PATCH 103/347] bgpd: fix do not use api.backup_nexthop in ZAPI message The backup_nexthop entry list has been populated by mistake, and should not. Fix this by reverting the introduced behavior. Fixes: 237ebf8d4503 ("bgpd: rework bgp_zebra_announce() function, separate nexthop handling") Signed-off-by: Philippe Guibert --- bgpd/bgp_zebra.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 73543f9fb4..7f91e3149e 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -1331,10 +1331,7 @@ static void bgp_zebra_announce_parse_nexthop( &nh_weight)) continue; } - if (CHECK_FLAG(info->flags, BGP_PATH_SELECTED)) - api_nh = &api->nexthops[*valid_nh_count]; - else - api_nh = &api->backup_nexthops[*valid_nh_count]; + api_nh = &api->nexthops[*valid_nh_count]; api_nh->srte_color = bgp_attr_get_color(info->attr); From 56c16ee529b546058c8d1fabbb701d8ed2fded75 Mon Sep 17 00:00:00 2001 From: Sindhu Parvathi Gopinathan Date: Wed, 19 Jun 2024 07:35:31 -0700 Subject: [PATCH 104/347] zebra: clear evpn dup-addr return error-msg when there is no vni clear evpn dup-addr cli returns error-msg for below conditions, - If evpn is not enabled & - If there is no VNI exists. supported command: ``` clear evpn dup-addr vni ``` Ticket: #3495573 Testing: bharat# clear evpn dup-addr vni all Error type: validation Error description: % EVPN not enabled bharat# clear evpn dup-addr vni 20 Error type: validation Error description: % VNI 20 does not exist Signed-off-by: Sindhu Parvathi Gopinathan's Signed-off-by: Chirag Shah --- zebra/zebra_nb_rpcs.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/zebra/zebra_nb_rpcs.c b/zebra/zebra_nb_rpcs.c index 938193df2f..744ba620f2 100644 --- a/zebra/zebra_nb_rpcs.c +++ b/zebra/zebra_nb_rpcs.c @@ -12,6 +12,8 @@ #include "zebra/zebra_router.h" #include "zebra/zebra_vrf.h" #include "zebra/zebra_vxlan.h" +#include "zebra/zebra_vxlan_if.h" +#include "zebra/zebra_evpn.h" /* * XPath: /frr-zebra:clear-evpn-dup-addr @@ -21,6 +23,11 @@ int clear_evpn_dup_addr_rpc(struct nb_cb_rpc_args *args) struct zebra_vrf *zvrf; int ret = NB_OK; + if (!is_evpn_enabled()) { + snprintf(args->errmsg, args->errmsg_len, + "%% EVPN not enabled\n"); + return NB_ERR_VALIDATION; + } zvrf = zebra_vrf_get_evpn(); if (yang_dnode_exists(args->input, "all-vnis")) { @@ -30,6 +37,12 @@ int clear_evpn_dup_addr_rpc(struct nb_cb_rpc_args *args) struct ipaddr host_ip = {.ipa_type = IPADDR_NONE}; struct ethaddr mac; + if (!zebra_evpn_lookup(vni)) { + snprintf(args->errmsg, args->errmsg_len, + "%% VNI %u does not exist\n", vni); + return NB_ERR_VALIDATION; + } + if (yang_dnode_exists(args->input, "mac-addr")) { yang_dnode_get_mac(&mac, args->input, "mac-addr"); ret = zebra_vxlan_clear_dup_detect_vni_mac(zvrf, vni, From f9d4d1626d47944715eb522af38909cc90a1d53c Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Fri, 21 Jun 2024 11:32:05 +0200 Subject: [PATCH 105/347] tools/checkpatch: accept pim_* typedefs pimd uses "v4/v6 dispatch" typedefs. Don't complain about those in checkpatch. Signed-off-by: David Lamparter --- tools/checkpatch.pl | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/checkpatch.pl b/tools/checkpatch.pl index f52f1a1616..3e7abeda39 100755 --- a/tools/checkpatch.pl +++ b/tools/checkpatch.pl @@ -4668,6 +4668,7 @@ sub process { # check for new typedefs, only function parameters and sparse annotations # make sense. if ($line =~ /\btypedef\s/ && + $line !~ /\btypedef.*\s(pim_[^\s]+|[^\s]+_pim)\s*;/ && $line !~ /\btypedef\s+$Type\s*\(\s*\*?$Ident\s*\)\s*\(/ && $line !~ /\btypedef\s+$Type\s+$Ident\s*\(/ && $line !~ /\b$typeTypedefs\b/ && From df723ccfb70e4c416bb74fc52cfc8b9dd1384314 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Thu, 6 Jun 2024 18:03:24 +0200 Subject: [PATCH 106/347] isisd: show isis route uses ttable for paths This is a preliminary commit, so that route paths are visible from json. Before: > IS-IS paths to level-1 routers that speak IPv6 > Vertex Type Metric Next-Hop Interface Parent > rt1 > 2001:db8:1000::1/128 IP6 internal 0 rt1(4) > rt2 TE-IS 10 rt2 eth-rt2 rt1(4) > rt3 TE-IS 10 rt3 eth-rt3 rt1(4) > 2001:db8:1000::2/128 IP6 internal 20 rt2 eth-rt2 rt2(4) > 2001:db8:1000::3/128 IP6 internal 20 rt3 eth-rt3 rt3(4) After: > Vertex Type Metric Next-Hop Interface Parent > ------------------------------------------------------------------------- > rt1 > 2001:db8:1000::1/128 IP6 internal 0 rt1(4) > rt2 TE-IS 10 rt2 eth-rt2 rt1(4) > rt3 TE-IS 10 rt3 eth-rt3 rt1(4) > 2001:db8:1000::2/128 IP6 internal 20 rt2 eth-rt2 rt2(4) > 2001:db8:1000::3/128 IP6 internal 20 rt3 eth-rt3 rt3(4) Signed-off-by: Philippe Guibert --- isisd/isis_spf.c | 79 +- tests/isisd/test_isis_spf.refout | 4266 ++++++++++++++++-------------- 2 files changed, 2303 insertions(+), 2042 deletions(-) diff --git a/isisd/isis_spf.c b/isisd/isis_spf.c index 81201023d6..4892479ac2 100644 --- a/isisd/isis_spf.c +++ b/isisd/isis_spf.c @@ -2232,16 +2232,30 @@ static void isis_print_paths(struct vty *vty, struct isis_vertex_queue *queue, struct listnode *node; struct isis_vertex *vertex; char buff[VID2STR_BUFFER]; + char vertex_name[VID2STR_BUFFER]; + char vertex_typestr[VID2STR_BUFFER]; + char vertex_interface[VID2STR_BUFFER]; + char vertex_parent[VID2STR_BUFFER + 11]; + char vertex_nexthop[VID2STR_BUFFER]; + char vertex_metricstr[20]; + struct ttable *tt; + char *table; - vty_out(vty, - "Vertex Type Metric Next-Hop Interface Parent\n"); + /* Prepare table. */ + tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]); + ttable_add_row(tt, "Vertex|Type|Metric|Next-Hop|Interface|Parent"); + tt->style.cell.rpad = 2; + tt->style.corner = '+'; + ttable_restyle(tt); + ttable_rowseps(tt, 0, BOTTOM, true, '-'); for (ALL_QUEUE_ELEMENTS_RO(queue, node, vertex)) { if (VTYPE_IS(vertex->type) && memcmp(vertex->N.id, root_sysid, ISIS_SYS_ID_LEN) == 0) { - vty_out(vty, "%-20s %-12s %-6s", - print_sys_hostname(root_sysid), "", ""); - vty_out(vty, "%-30s\n", ""); + /* display here */ + ttable_add_row(tt, "%s|%s|%s|%s|%s|%s", + print_sys_hostname(root_sysid), "", "", + "", "", ""); continue; } @@ -2251,9 +2265,12 @@ static void isis_print_paths(struct vty *vty, struct isis_vertex_queue *queue, struct isis_vertex_adj *vadj; struct isis_vertex *pvertex; - vty_out(vty, "%-20s %-12s %-6u ", - vid2string(vertex, buff, sizeof(buff)), - vtype2string(vertex->type), vertex->d_N); + snprintf(vertex_name, sizeof(vertex_name), "%s", + vid2string(vertex, buff, sizeof(buff))); + snprintf(vertex_typestr, sizeof(vertex_typestr), "%s", + vtype2string(vertex->type)); + snprintf(vertex_metricstr, sizeof(vertex_metricstr), "%u", + vertex->d_N); for (unsigned int i = 0; i < MAX(vertex->Adj_N ? listcount(vertex->Adj_N) : 0, vertex->parents ? listcount(vertex->parents) : 0); @@ -2273,33 +2290,51 @@ static void isis_print_paths(struct vty *vty, struct isis_vertex_queue *queue, } if (rows) { - vty_out(vty, "\n"); - vty_out(vty, "%-20s %-12s %-6s ", "", "", ""); + /* display here */ + ttable_add_row(tt, "%s|%s|%s|%s|%s|%s", + vertex_name, vertex_typestr, + vertex_metricstr, vertex_nexthop, + vertex_interface, vertex_parent); + + /* store the first 3 elements */ + vertex_name[0] = '\0'; + vertex_typestr[0] = '\0'; + vertex_metricstr[0] = '\0'; } if (vadj) { struct isis_spf_adj *sadj = vadj->sadj; - vty_out(vty, "%-20s %-9s ", - print_sys_hostname(sadj->id), - sadj->adj ? sadj->adj->circuit - ->interface->name - : "-"); + snprintf(vertex_nexthop, sizeof(vertex_nexthop), + "%s", print_sys_hostname(sadj->id)); + snprintf(vertex_interface, + sizeof(vertex_interface), "%s", + sadj->adj ? sadj->adj->circuit + ->interface->name + : "-"); } if (pvertex) { - if (!vadj) - vty_out(vty, "%-20s %-9s ", "", ""); - - vty_out(vty, "%s(%d)", - vid2string(pvertex, buff, sizeof(buff)), - pvertex->type); + if (!vadj) { + vertex_nexthop[0] = '\0'; + vertex_interface[0] = '\0'; + } + snprintf(vertex_parent, sizeof(vertex_parent), + "%s(%d)", + vid2string(pvertex, buff, sizeof(buff)), + pvertex->type); } ++rows; } - vty_out(vty, "\n"); + ttable_add_row(tt, "%s|%s|%s|%s|%s|%s", vertex_name, + vertex_typestr, vertex_metricstr, vertex_nexthop, + vertex_interface, vertex_parent); } + table = ttable_dump(tt, "\n"); + vty_out(vty, "%s\n", table); + XFREE(MTYPE_TMP, table); + ttable_del(tt); } void isis_print_spftree(struct vty *vty, struct isis_spftree *spftree) diff --git a/tests/isisd/test_isis_spf.refout b/tests/isisd/test_isis_spf.refout index 23d41b9e5d..255d920c10 100644 --- a/tests/isisd/test_isis_spf.refout +++ b/tests/isisd/test_isis_spf.refout @@ -1,20 +1,22 @@ test# test isis topology 1 root rt1 spf IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) -rt5 TE-IS 20 rt3 - rt3(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt6 TE-IS 30 rt2 - rt4(4) - rt3 - rt5(4) -10.0.255.4/32 IP TE 30 rt2 - rt4(4) -10.0.255.5/32 IP TE 30 rt3 - rt5(4) -10.0.255.6/32 IP TE 40 rt2 - rt6(4) - rt3 - + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + rt5 TE-IS 20 rt3 - rt3(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt6 TE-IS 30 rt2 - rt4(4) + rt3 - rt5(4) + 10.0.255.4/32 IP TE 30 rt2 - rt4(4) + 10.0.255.5/32 IP TE 30 rt3 - rt5(4) + 10.0.255.6/32 IP TE 40 rt2 - rt6(4) + rt3 - rt6(4) + IS-IS L1 IPv4 routing table: @@ -29,21 +31,23 @@ IS-IS L1 IPv4 routing table: - rt3 16060 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt1 -2001:db8::1/128 IP6 internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) -rt5 TE-IS 20 rt3 - rt3(4) -2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) -2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) -rt6 TE-IS 30 rt2 - rt4(4) - rt3 - rt5(4) -2001:db8::4/128 IP6 internal 30 rt2 - rt4(4) -2001:db8::5/128 IP6 internal 30 rt3 - rt5(4) -2001:db8::6/128 IP6 internal 40 rt2 - rt6(4) - rt3 - + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt1 + 2001:db8::1/128 IP6 internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + rt5 TE-IS 20 rt3 - rt3(4) + 2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) + 2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) + rt6 TE-IS 30 rt2 - rt4(4) + rt3 - rt5(4) + 2001:db8::4/128 IP6 internal 30 rt2 - rt4(4) + 2001:db8::5/128 IP6 internal 30 rt3 - rt5(4) + 2001:db8::6/128 IP6 internal 40 rt2 - rt6(4) + rt3 - rt6(4) + IS-IS L1 IPv6 routing table: @@ -59,22 +63,24 @@ IS-IS L1 IPv6 routing table: test# test isis topology 2 root rt1 spf IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt4 TE-IS 10 rt4 - rt1(4) -rt5 TE-IS 10 rt5 - rt1(4) -rt2 TE-IS 15 rt2 - rt1(4) -rt1 -rt6 TE-IS 20 rt4 - rt4(4) - rt5 - rt5(4) -10.0.255.4/32 IP TE 20 rt4 - rt4(4) -10.0.255.5/32 IP TE 20 rt5 - rt5(4) -10.0.255.2/32 IP TE 25 rt2 - rt2(4) -rt3 TE-IS 30 rt3 - rt1(4) -10.0.255.6/32 IP TE 30 rt4 - rt6(4) - rt5 - -10.0.255.3/32 IP TE 40 rt3 - rt3(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt4 TE-IS 10 rt4 - rt1(4) + rt5 TE-IS 10 rt5 - rt1(4) + rt2 TE-IS 15 rt2 - rt1(4) + rt1 + rt6 TE-IS 20 rt4 - rt4(4) + rt5 - rt5(4) + 10.0.255.4/32 IP TE 20 rt4 - rt4(4) + 10.0.255.5/32 IP TE 20 rt5 - rt5(4) + 10.0.255.2/32 IP TE 25 rt2 - rt2(4) + rt3 TE-IS 30 rt3 - rt1(4) + 10.0.255.6/32 IP TE 30 rt4 - rt6(4) + rt5 - rt6(4) + 10.0.255.3/32 IP TE 40 rt3 - rt3(4) + IS-IS L1 IPv4 routing table: @@ -89,22 +95,24 @@ IS-IS L1 IPv4 routing table: - rt5 16060 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt1 -2001:db8::1/128 IP6 internal 0 rt1(4) -rt4 TE-IS 10 rt4 - rt1(4) -rt5 TE-IS 10 rt5 - rt1(4) -rt2 TE-IS 15 rt2 - rt1(4) -rt1 -rt6 TE-IS 20 rt4 - rt4(4) - rt5 - rt5(4) -2001:db8::4/128 IP6 internal 20 rt4 - rt4(4) -2001:db8::5/128 IP6 internal 20 rt5 - rt5(4) -2001:db8::2/128 IP6 internal 25 rt2 - rt2(4) -rt3 TE-IS 30 rt3 - rt1(4) -2001:db8::6/128 IP6 internal 30 rt4 - rt6(4) - rt5 - -2001:db8::3/128 IP6 internal 40 rt3 - rt3(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt1 + 2001:db8::1/128 IP6 internal 0 rt1(4) + rt4 TE-IS 10 rt4 - rt1(4) + rt5 TE-IS 10 rt5 - rt1(4) + rt2 TE-IS 15 rt2 - rt1(4) + rt1 + rt6 TE-IS 20 rt4 - rt4(4) + rt5 - rt5(4) + 2001:db8::4/128 IP6 internal 20 rt4 - rt4(4) + 2001:db8::5/128 IP6 internal 20 rt5 - rt5(4) + 2001:db8::2/128 IP6 internal 25 rt2 - rt2(4) + rt3 TE-IS 30 rt3 - rt1(4) + 2001:db8::6/128 IP6 internal 30 rt4 - rt6(4) + rt5 - rt6(4) + 2001:db8::3/128 IP6 internal 40 rt3 - rt3(4) + IS-IS L1 IPv6 routing table: @@ -120,19 +128,21 @@ IS-IS L1 IPv6 routing table: test# test isis topology 3 root rt1 spf ipv4-only IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt5 TE-IS 30 rt2 - rt4(4) -rt6 TE-IS 30 rt2 - rt4(4) -10.0.255.4/32 IP TE 30 rt2 - rt4(4) -10.0.255.5/32 IP TE 40 rt2 - rt5(4) -10.0.255.6/32 IP TE 40 rt2 - rt6(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt5 TE-IS 30 rt2 - rt4(4) + rt6 TE-IS 30 rt2 - rt4(4) + 10.0.255.4/32 IP TE 30 rt2 - rt4(4) + 10.0.255.5/32 IP TE 40 rt2 - rt5(4) + 10.0.255.6/32 IP TE 40 rt2 - rt6(4) + IS-IS L1 IPv4 routing table: @@ -147,23 +157,25 @@ IS-IS L1 IPv4 routing table: test# test isis topology 4 root rt1 spf ipv4-only IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) -rt5 TE-IS 20 rt3 - rt3(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt6 TE-IS 30 rt2 - rt4(4) -rt7 TE-IS 30 rt3 - rt5(4) -10.0.255.4/32 IP TE 30 rt2 - rt4(4) -10.0.255.5/32 IP TE 30 rt3 - rt5(4) -rt8 TE-IS 40 rt2 - rt6(4) -10.0.255.6/32 IP TE 40 rt2 - rt6(4) -10.0.255.7/32 IP TE 40 rt3 - rt7(4) -10.0.255.8/32 IP TE 50 rt2 - rt8(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + rt5 TE-IS 20 rt3 - rt3(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt6 TE-IS 30 rt2 - rt4(4) + rt7 TE-IS 30 rt3 - rt5(4) + 10.0.255.4/32 IP TE 30 rt2 - rt4(4) + 10.0.255.5/32 IP TE 30 rt3 - rt5(4) + rt8 TE-IS 40 rt2 - rt6(4) + 10.0.255.6/32 IP TE 40 rt2 - rt6(4) + 10.0.255.7/32 IP TE 40 rt3 - rt7(4) + 10.0.255.8/32 IP TE 50 rt2 - rt8(4) + IS-IS L1 IPv4 routing table: @@ -180,25 +192,27 @@ IS-IS L1 IPv4 routing table: test# test isis topology 5 root rt1 spf ipv4-only IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) -rt5 TE-IS 20 rt3 - rt3(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt6 TE-IS 30 rt2 - rt4(4) -rt7 TE-IS 30 rt3 - rt5(4) -10.0.255.4/32 IP TE 30 rt2 - rt4(4) -10.0.255.5/32 IP TE 30 rt3 - rt5(4) -rt8 TE-IS 40 rt2 - rt6(4) - rt3 - rt7(4) -10.0.255.6/32 IP TE 40 rt2 - rt6(4) -10.0.255.7/32 IP TE 40 rt3 - rt7(4) -10.0.255.8/32 IP TE 50 rt2 - rt8(4) - rt3 - + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + rt5 TE-IS 20 rt3 - rt3(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt6 TE-IS 30 rt2 - rt4(4) + rt7 TE-IS 30 rt3 - rt5(4) + 10.0.255.4/32 IP TE 30 rt2 - rt4(4) + 10.0.255.5/32 IP TE 30 rt3 - rt5(4) + rt8 TE-IS 40 rt2 - rt6(4) + rt3 - rt7(4) + 10.0.255.6/32 IP TE 40 rt2 - rt6(4) + 10.0.255.7/32 IP TE 40 rt3 - rt7(4) + 10.0.255.8/32 IP TE 50 rt2 - rt8(4) + rt3 - rt8(4) + IS-IS L1 IPv4 routing table: @@ -216,33 +230,35 @@ IS-IS L1 IPv4 routing table: test# test isis topology 6 root rt1 spf ipv4-only IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) - rt3 - rt3(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt6 TE-IS 30 rt2 - rt4(4) - rt3 - -10.0.255.4/32 IP TE 30 rt2 - rt4(4) - rt3 - -rt5 TE-IS 40 rt2 - rt6(4) - rt3 - -rt8 TE-IS 40 rt2 - rt6(4) - rt3 - -10.0.255.6/32 IP TE 40 rt2 - rt6(4) - rt3 - -rt7 TE-IS 50 rt2 - rt5(4) - rt3 - rt8(4) -10.0.255.5/32 IP TE 50 rt2 - rt5(4) - rt3 - -10.0.255.8/32 IP TE 50 rt2 - rt8(4) - rt3 - -10.0.255.7/32 IP TE 60 rt2 - rt7(4) - rt3 - + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + rt3 - rt3(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt6 TE-IS 30 rt2 - rt4(4) + rt3 - rt4(4) + 10.0.255.4/32 IP TE 30 rt2 - rt4(4) + rt3 - rt4(4) + rt5 TE-IS 40 rt2 - rt6(4) + rt3 - rt6(4) + rt8 TE-IS 40 rt2 - rt6(4) + rt3 - rt6(4) + 10.0.255.6/32 IP TE 40 rt2 - rt6(4) + rt3 - rt6(4) + rt7 TE-IS 50 rt2 - rt5(4) + rt3 - rt8(4) + 10.0.255.5/32 IP TE 50 rt2 - rt5(4) + rt3 - rt5(4) + 10.0.255.8/32 IP TE 50 rt2 - rt8(4) + rt3 - rt8(4) + 10.0.255.7/32 IP TE 60 rt2 - rt7(4) + rt3 - rt7(4) + IS-IS L1 IPv4 routing table: @@ -264,34 +280,36 @@ IS-IS L1 IPv4 routing table: test# test isis topology 7 root rt1 spf ipv4-only IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt4 TE-IS 10 rt4 - rt1(4) -rt5 TE-IS 20 rt4 - rt4(4) -rt7 TE-IS 20 rt4 - rt4(4) -10.0.255.4/32 IP TE 20 rt4 - rt4(4) -rt2 TE-IS 30 rt4 - rt5(4) -rt6 TE-IS 30 rt4 - rt5(4) -rt8 TE-IS 30 rt4 - rt5(4) - rt7(4) -10.0.255.5/32 IP TE 30 rt4 - rt5(4) -10.0.255.7/32 IP TE 30 rt4 - rt7(4) -rt10 TE-IS 40 rt4 - rt7(4) -rt3 TE-IS 40 rt4 - rt2(4) - rt6(4) -rt9 TE-IS 40 rt4 - rt8(4) -rt11 TE-IS 40 rt4 - rt8(4) -10.0.255.2/32 IP TE 40 rt4 - rt2(4) -10.0.255.6/32 IP TE 40 rt4 - rt6(4) -10.0.255.8/32 IP TE 40 rt4 - rt8(4) -rt12 TE-IS 50 rt4 - rt9(4) - rt11(4) -10.0.255.10/32 IP TE 50 rt4 - rt10(4) -10.0.255.3/32 IP TE 50 rt4 - rt3(4) -10.0.255.9/32 IP TE 50 rt4 - rt9(4) -10.0.255.11/32 IP TE 50 rt4 - rt11(4) -10.0.255.12/32 IP TE 60 rt4 - rt12(4) + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt4 TE-IS 10 rt4 - rt1(4) + rt5 TE-IS 20 rt4 - rt4(4) + rt7 TE-IS 20 rt4 - rt4(4) + 10.0.255.4/32 IP TE 20 rt4 - rt4(4) + rt2 TE-IS 30 rt4 - rt5(4) + rt6 TE-IS 30 rt4 - rt5(4) + rt8 TE-IS 30 rt4 - rt5(4) + rt7(4) + 10.0.255.5/32 IP TE 30 rt4 - rt5(4) + 10.0.255.7/32 IP TE 30 rt4 - rt7(4) + rt10 TE-IS 40 rt4 - rt7(4) + rt3 TE-IS 40 rt4 - rt2(4) + rt6(4) + rt9 TE-IS 40 rt4 - rt8(4) + rt11 TE-IS 40 rt4 - rt8(4) + 10.0.255.2/32 IP TE 40 rt4 - rt2(4) + 10.0.255.6/32 IP TE 40 rt4 - rt6(4) + 10.0.255.8/32 IP TE 40 rt4 - rt8(4) + rt12 TE-IS 50 rt4 - rt9(4) + rt11(4) + 10.0.255.10/32 IP TE 50 rt4 - rt10(4) + 10.0.255.3/32 IP TE 50 rt4 - rt3(4) + 10.0.255.9/32 IP TE 50 rt4 - rt9(4) + 10.0.255.11/32 IP TE 50 rt4 - rt11(4) + 10.0.255.12/32 IP TE 60 rt4 - rt12(4) + IS-IS L1 IPv4 routing table: @@ -312,33 +330,35 @@ IS-IS L1 IPv4 routing table: test# test isis topology 8 root rt1 spf ipv4-only IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt4 TE-IS 10 rt4 - rt1(4) -rt3 TE-IS 20 rt2 - rt2(4) -rt5 TE-IS 20 rt2 - rt2(4) -rt7 TE-IS 20 rt4 - rt4(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.4/32 IP TE 20 rt4 - rt4(4) -rt6 TE-IS 30 rt2 - rt3(4) - rt5(4) -rt8 TE-IS 30 rt2 - rt5(4) -rt10 TE-IS 30 rt4 - rt7(4) -10.0.255.3/32 IP TE 30 rt2 - rt3(4) -10.0.255.5/32 IP TE 30 rt2 - rt5(4) -10.0.255.7/32 IP TE 30 rt4 - rt7(4) -rt9 TE-IS 40 rt2 - rt8(4) -rt11 TE-IS 40 rt2 - rt8(4) -10.0.255.6/32 IP TE 40 rt2 - rt6(4) -10.0.255.8/32 IP TE 40 rt2 - rt8(4) -10.0.255.10/32 IP TE 40 rt4 - rt10(4) -rt12 TE-IS 50 rt2 - rt9(4) - rt11(4) -10.0.255.9/32 IP TE 50 rt2 - rt9(4) -10.0.255.11/32 IP TE 50 rt2 - rt11(4) -10.0.255.12/32 IP TE 60 rt2 - rt12(4) + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt4 TE-IS 10 rt4 - rt1(4) + rt3 TE-IS 20 rt2 - rt2(4) + rt5 TE-IS 20 rt2 - rt2(4) + rt7 TE-IS 20 rt4 - rt4(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.4/32 IP TE 20 rt4 - rt4(4) + rt6 TE-IS 30 rt2 - rt3(4) + rt5(4) + rt8 TE-IS 30 rt2 - rt5(4) + rt10 TE-IS 30 rt4 - rt7(4) + 10.0.255.3/32 IP TE 30 rt2 - rt3(4) + 10.0.255.5/32 IP TE 30 rt2 - rt5(4) + 10.0.255.7/32 IP TE 30 rt4 - rt7(4) + rt9 TE-IS 40 rt2 - rt8(4) + rt11 TE-IS 40 rt2 - rt8(4) + 10.0.255.6/32 IP TE 40 rt2 - rt6(4) + 10.0.255.8/32 IP TE 40 rt2 - rt8(4) + 10.0.255.10/32 IP TE 40 rt4 - rt10(4) + rt12 TE-IS 50 rt2 - rt9(4) + rt11(4) + 10.0.255.9/32 IP TE 50 rt2 - rt9(4) + 10.0.255.11/32 IP TE 50 rt2 - rt11(4) + 10.0.255.12/32 IP TE 60 rt2 - rt12(4) + IS-IS L1 IPv4 routing table: @@ -359,28 +379,30 @@ IS-IS L1 IPv4 routing table: test# test isis topology 9 root rt1 spf IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt5 TE-IS 30 rt2 - rt4(4) -10.0.255.4/32 IP TE 30 rt2 - rt4(4) -rt9 TE-IS 40 rt2 - rt5(4) -10.0.255.5/32 IP TE 40 rt2 - rt5(4) -rt6 TE-IS 50 rt2 - rt4(4) - rt9(4) -rt7 TE-IS 50 rt2 - rt4(4) - rt9(4) -rt8 TE-IS 50 rt2 - rt4(4) - rt9(4) -10.0.255.9/32 IP TE 50 rt2 - rt9(4) -10.0.255.6/32 IP TE 60 rt2 - rt6(4) -10.0.255.7/32 IP TE 60 rt2 - rt7(4) -10.0.255.8/32 IP TE 60 rt2 - rt8(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt5 TE-IS 30 rt2 - rt4(4) + 10.0.255.4/32 IP TE 30 rt2 - rt4(4) + rt9 TE-IS 40 rt2 - rt5(4) + 10.0.255.5/32 IP TE 40 rt2 - rt5(4) + rt6 TE-IS 50 rt2 - rt4(4) + rt9(4) + rt7 TE-IS 50 rt2 - rt4(4) + rt9(4) + rt8 TE-IS 50 rt2 - rt4(4) + rt9(4) + 10.0.255.9/32 IP TE 50 rt2 - rt9(4) + 10.0.255.6/32 IP TE 60 rt2 - rt6(4) + 10.0.255.7/32 IP TE 60 rt2 - rt7(4) + 10.0.255.8/32 IP TE 60 rt2 - rt8(4) + IS-IS L1 IPv4 routing table: @@ -397,28 +419,30 @@ IS-IS L1 IPv4 routing table: 10.0.255.9/32 50 - rt2 16090 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt1 -2001:db8::1/128 IP6 internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) -2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) -2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) -rt5 TE-IS 30 rt2 - rt4(4) -2001:db8::4/128 IP6 internal 30 rt2 - rt4(4) -rt9 TE-IS 40 rt2 - rt5(4) -2001:db8::5/128 IP6 internal 40 rt2 - rt5(4) -rt6 TE-IS 50 rt2 - rt4(4) - rt9(4) -rt7 TE-IS 50 rt2 - rt4(4) - rt9(4) -rt8 TE-IS 50 rt2 - rt4(4) - rt9(4) -2001:db8::9/128 IP6 internal 50 rt2 - rt9(4) -2001:db8::6/128 IP6 internal 60 rt2 - rt6(4) -2001:db8::7/128 IP6 internal 60 rt2 - rt7(4) -2001:db8::8/128 IP6 internal 60 rt2 - rt8(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt1 + 2001:db8::1/128 IP6 internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + 2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) + 2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) + rt5 TE-IS 30 rt2 - rt4(4) + 2001:db8::4/128 IP6 internal 30 rt2 - rt4(4) + rt9 TE-IS 40 rt2 - rt5(4) + 2001:db8::5/128 IP6 internal 40 rt2 - rt5(4) + rt6 TE-IS 50 rt2 - rt4(4) + rt9(4) + rt7 TE-IS 50 rt2 - rt4(4) + rt9(4) + rt8 TE-IS 50 rt2 - rt4(4) + rt9(4) + 2001:db8::9/128 IP6 internal 50 rt2 - rt9(4) + 2001:db8::6/128 IP6 internal 60 rt2 - rt6(4) + 2001:db8::7/128 IP6 internal 60 rt2 - rt7(4) + 2001:db8::8/128 IP6 internal 60 rt2 - rt8(4) + IS-IS L1 IPv6 routing table: @@ -436,23 +460,25 @@ IS-IS L1 IPv6 routing table: test# test isis topology 10 root rt1 spf IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 20 rt3 - rt1(4) -rt4 TE-IS 20 rt4 - rt1(4) -rt5 TE-IS 20 rt2 - rt2(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -rt6 TE-IS 30 rt3 - rt3(4) -rt7 TE-IS 30 rt4 - rt4(4) -rt8 TE-IS 30 rt2 - rt5(4) -10.0.255.3/32 IP TE 30 rt3 - rt3(4) -10.0.255.4/32 IP TE 30 rt4 - rt4(4) -10.0.255.5/32 IP TE 30 rt2 - rt5(4) -10.0.255.6/32 IP TE 40 rt3 - rt6(4) -10.0.255.7/32 IP TE 40 rt4 - rt7(4) -10.0.255.8/32 IP TE 40 rt2 - rt8(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 20 rt3 - rt1(4) + rt4 TE-IS 20 rt4 - rt1(4) + rt5 TE-IS 20 rt2 - rt2(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + rt6 TE-IS 30 rt3 - rt3(4) + rt7 TE-IS 30 rt4 - rt4(4) + rt8 TE-IS 30 rt2 - rt5(4) + 10.0.255.3/32 IP TE 30 rt3 - rt3(4) + 10.0.255.4/32 IP TE 30 rt4 - rt4(4) + 10.0.255.5/32 IP TE 30 rt2 - rt5(4) + 10.0.255.6/32 IP TE 40 rt3 - rt6(4) + 10.0.255.7/32 IP TE 40 rt4 - rt7(4) + 10.0.255.8/32 IP TE 40 rt2 - rt8(4) + IS-IS L1 IPv4 routing table: @@ -468,23 +494,25 @@ IS-IS L1 IPv4 routing table: 10.0.255.8/32 40 - rt2 16080 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt1 -2001:db8::1/128 IP6 internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 20 rt3 - rt1(4) -rt4 TE-IS 20 rt4 - rt1(4) -rt5 TE-IS 20 rt2 - rt2(4) -2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) -rt6 TE-IS 30 rt3 - rt3(4) -rt7 TE-IS 30 rt4 - rt4(4) -rt8 TE-IS 30 rt2 - rt5(4) -2001:db8::3/128 IP6 internal 30 rt3 - rt3(4) -2001:db8::4/128 IP6 internal 30 rt4 - rt4(4) -2001:db8::5/128 IP6 internal 30 rt2 - rt5(4) -2001:db8::6/128 IP6 internal 40 rt3 - rt6(4) -2001:db8::7/128 IP6 internal 40 rt4 - rt7(4) -2001:db8::8/128 IP6 internal 40 rt2 - rt8(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt1 + 2001:db8::1/128 IP6 internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 20 rt3 - rt1(4) + rt4 TE-IS 20 rt4 - rt1(4) + rt5 TE-IS 20 rt2 - rt2(4) + 2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) + rt6 TE-IS 30 rt3 - rt3(4) + rt7 TE-IS 30 rt4 - rt4(4) + rt8 TE-IS 30 rt2 - rt5(4) + 2001:db8::3/128 IP6 internal 30 rt3 - rt3(4) + 2001:db8::4/128 IP6 internal 30 rt4 - rt4(4) + 2001:db8::5/128 IP6 internal 30 rt2 - rt5(4) + 2001:db8::6/128 IP6 internal 40 rt3 - rt6(4) + 2001:db8::7/128 IP6 internal 40 rt4 - rt7(4) + 2001:db8::8/128 IP6 internal 40 rt2 - rt8(4) + IS-IS L1 IPv6 routing table: @@ -501,22 +529,24 @@ IS-IS L1 IPv6 routing table: test# test isis topology 11 root rt1 spf IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt2 pseudo_TE-IS 20 rt3 - rt3(4) -rt4 TE-IS 20 rt2 - rt2(4) -rt5 TE-IS 20 rt3 - rt3(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt6 TE-IS 30 rt2 - rt4(4) - rt3 - rt5(4) -10.0.255.4/32 IP TE 30 rt2 - rt4(4) -10.0.255.5/32 IP TE 30 rt3 - rt5(4) -10.0.255.6/32 IP TE 40 rt2 - rt6(4) - rt3 - + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------ + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt2 pseudo_TE-IS 20 rt3 - rt3(4) + rt4 TE-IS 20 rt2 - rt2(4) + rt5 TE-IS 20 rt3 - rt3(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt6 TE-IS 30 rt2 - rt4(4) + rt3 - rt5(4) + 10.0.255.4/32 IP TE 30 rt2 - rt4(4) + 10.0.255.5/32 IP TE 30 rt3 - rt5(4) + 10.0.255.6/32 IP TE 40 rt2 - rt6(4) + rt3 - rt6(4) + IS-IS L1 IPv4 routing table: @@ -531,22 +561,24 @@ IS-IS L1 IPv4 routing table: - rt3 16060 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt1 -2001:db8::1/128 IP6 internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt2 pseudo_TE-IS 20 rt3 - rt3(4) -rt4 TE-IS 20 rt2 - rt2(4) -rt5 TE-IS 20 rt3 - rt3(4) -2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) -2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) -rt6 TE-IS 30 rt2 - rt4(4) - rt3 - rt5(4) -2001:db8::4/128 IP6 internal 30 rt2 - rt4(4) -2001:db8::5/128 IP6 internal 30 rt3 - rt5(4) -2001:db8::6/128 IP6 internal 40 rt2 - rt6(4) - rt3 - + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt1 + 2001:db8::1/128 IP6 internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt2 pseudo_TE-IS 20 rt3 - rt3(4) + rt4 TE-IS 20 rt2 - rt2(4) + rt5 TE-IS 20 rt3 - rt3(4) + 2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) + 2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) + rt6 TE-IS 30 rt2 - rt4(4) + rt3 - rt5(4) + 2001:db8::4/128 IP6 internal 30 rt2 - rt4(4) + 2001:db8::5/128 IP6 internal 30 rt3 - rt5(4) + 2001:db8::6/128 IP6 internal 40 rt2 - rt6(4) + rt3 - rt6(4) + IS-IS L1 IPv6 routing table: @@ -562,27 +594,29 @@ IS-IS L1 IPv6 routing table: test# test isis topology 12 root rt1 spf ipv4-only IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) -rt5 TE-IS 20 rt3 - rt3(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt6 TE-IS 30 rt2 - rt4(4) -rt7 TE-IS 30 rt3 - rt5(4) -10.0.255.4/32 IP TE 30 rt2 - rt4(4) -10.0.255.5/32 IP TE 30 rt3 - rt5(4) -rt8 TE-IS 40 rt2 - rt6(4) -rt9 TE-IS 40 rt3 - rt7(4) -10.0.255.6/32 IP TE 40 rt2 - rt6(4) -10.0.255.7/32 IP TE 40 rt3 - rt7(4) -rt10 TE-IS 50 rt2 - rt8(4) -10.0.255.8/32 IP TE 50 rt2 - rt8(4) -10.0.255.9/32 IP TE 50 rt3 - rt9(4) -10.0.255.10/32 IP TE 60 rt2 - rt10(4) + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + rt5 TE-IS 20 rt3 - rt3(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt6 TE-IS 30 rt2 - rt4(4) + rt7 TE-IS 30 rt3 - rt5(4) + 10.0.255.4/32 IP TE 30 rt2 - rt4(4) + 10.0.255.5/32 IP TE 30 rt3 - rt5(4) + rt8 TE-IS 40 rt2 - rt6(4) + rt9 TE-IS 40 rt3 - rt7(4) + 10.0.255.6/32 IP TE 40 rt2 - rt6(4) + 10.0.255.7/32 IP TE 40 rt3 - rt7(4) + rt10 TE-IS 50 rt2 - rt8(4) + 10.0.255.8/32 IP TE 50 rt2 - rt8(4) + 10.0.255.9/32 IP TE 50 rt3 - rt9(4) + 10.0.255.10/32 IP TE 60 rt2 - rt10(4) + IS-IS L1 IPv4 routing table: @@ -601,24 +635,26 @@ IS-IS L1 IPv4 routing table: test# test isis topology 13 root rt1 spf ipv4-only IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) - rt3 - rt3(4) -rt5 TE-IS 20 rt3 - rt3(4) -rt6 TE-IS 20 rt3 - rt3(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt7 TE-IS 30 rt3 - rt5(4) - rt6(4) -10.0.255.4/32 IP TE 30 rt2 - rt4(4) - rt3 - -10.0.255.5/32 IP TE 30 rt3 - rt5(4) -10.0.255.6/32 IP TE 30 rt3 - rt6(4) -10.0.255.7/32 IP TE 40 rt3 - rt7(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + rt3 - rt3(4) + rt5 TE-IS 20 rt3 - rt3(4) + rt6 TE-IS 20 rt3 - rt3(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt7 TE-IS 30 rt3 - rt5(4) + rt6(4) + 10.0.255.4/32 IP TE 30 rt2 - rt4(4) + rt3 - rt4(4) + 10.0.255.5/32 IP TE 30 rt3 - rt5(4) + 10.0.255.6/32 IP TE 30 rt3 - rt6(4) + 10.0.255.7/32 IP TE 40 rt3 - rt7(4) + IS-IS L1 IPv4 routing table: @@ -636,23 +672,25 @@ IS-IS L1 IPv4 routing table: test# test# test isis topology 4 root rt1 reverse-spf ipv4-only IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) -rt5 TE-IS 20 rt3 - rt3(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt6 TE-IS 30 rt2 - rt4(4) -rt7 TE-IS 30 rt3 - rt5(4) -10.0.255.4/32 IP TE 30 rt2 - rt4(4) -10.0.255.5/32 IP TE 30 rt3 - rt5(4) -rt8 TE-IS 40 rt2 - rt6(4) -10.0.255.6/32 IP TE 40 rt2 - rt6(4) -10.0.255.7/32 IP TE 40 rt3 - rt7(4) -10.0.255.8/32 IP TE 50 rt2 - rt8(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + rt5 TE-IS 20 rt3 - rt3(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt6 TE-IS 30 rt2 - rt4(4) + rt7 TE-IS 30 rt3 - rt5(4) + 10.0.255.4/32 IP TE 30 rt2 - rt4(4) + 10.0.255.5/32 IP TE 30 rt3 - rt5(4) + rt8 TE-IS 40 rt2 - rt6(4) + 10.0.255.6/32 IP TE 40 rt2 - rt6(4) + 10.0.255.7/32 IP TE 40 rt3 - rt7(4) + 10.0.255.8/32 IP TE 50 rt2 - rt8(4) + IS-IS L1 IPv4 routing table: @@ -669,21 +707,23 @@ IS-IS L1 IPv4 routing table: test# test isis topology 11 root rt1 reverse-spf IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt2 pseudo_TE-IS 20 rt3 - rt3(4) -rt4 TE-IS 20 rt2(4) -rt5 TE-IS 20 rt3 - rt3(4) -10.0.255.2/32 IP TE 20 rt2(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt6 TE-IS 30 rt3 - rt4(4) - rt5(4) -10.0.255.4/32 IP TE 30 rt4(4) -10.0.255.5/32 IP TE 30 rt3 - rt5(4) -10.0.255.6/32 IP TE 40 rt3 - rt6(4) + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------ + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt2 pseudo_TE-IS 20 rt3 - rt3(4) + rt4 TE-IS 20 rt2(4) + rt5 TE-IS 20 rt3 - rt3(4) + 10.0.255.2/32 IP TE 20 rt2(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt6 TE-IS 30 rt3 - rt4(4) + rt5(4) + 10.0.255.4/32 IP TE 30 rt4(4) + 10.0.255.5/32 IP TE 30 rt3 - rt5(4) + 10.0.255.6/32 IP TE 40 rt3 - rt6(4) + IS-IS L1 IPv4 routing table: @@ -695,21 +735,23 @@ IS-IS L1 IPv4 routing table: 10.0.255.6/32 40 - rt3 16060 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt1 -2001:db8::1/128 IP6 internal 0 rt1(4) -rt2 TE-IS 10 rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt2 pseudo_TE-IS 20 rt3 - rt3(4) -rt4 TE-IS 20 rt2(4) -rt5 TE-IS 20 rt3 - rt3(4) -2001:db8::2/128 IP6 internal 20 rt2(4) -2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) -rt6 TE-IS 30 rt3 - rt4(4) - rt5(4) -2001:db8::4/128 IP6 internal 30 rt4(4) -2001:db8::5/128 IP6 internal 30 rt3 - rt5(4) -2001:db8::6/128 IP6 internal 40 rt3 - rt6(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt1 + 2001:db8::1/128 IP6 internal 0 rt1(4) + rt2 TE-IS 10 rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt2 pseudo_TE-IS 20 rt3 - rt3(4) + rt4 TE-IS 20 rt2(4) + rt5 TE-IS 20 rt3 - rt3(4) + 2001:db8::2/128 IP6 internal 20 rt2(4) + 2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) + rt6 TE-IS 30 rt3 - rt4(4) + rt5(4) + 2001:db8::4/128 IP6 internal 30 rt4(4) + 2001:db8::5/128 IP6 internal 30 rt3 - rt5(4) + 2001:db8::6/128 IP6 internal 40 rt3 - rt6(4) + IS-IS L1 IPv6 routing table: @@ -723,21 +765,23 @@ IS-IS L1 IPv6 routing table: test# test# test isis topology 1 root rt1 lfa system-id rt2 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) -rt5 TE-IS 20 rt3 - rt3(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt6 TE-IS 30 rt2 - rt4(4) - rt3 - rt5(4) -10.0.255.4/32 IP TE 30 rt2 - rt4(4) -10.0.255.5/32 IP TE 30 rt3 - rt5(4) -10.0.255.6/32 IP TE 40 rt2 - rt6(4) - rt3 - + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + rt5 TE-IS 20 rt3 - rt3(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt6 TE-IS 30 rt2 - rt4(4) + rt3 - rt5(4) + 10.0.255.4/32 IP TE 30 rt2 - rt4(4) + 10.0.255.5/32 IP TE 30 rt3 - rt5(4) + 10.0.255.6/32 IP TE 40 rt2 - rt6(4) + rt3 - rt6(4) + Main: IS-IS L1 IPv4 routing table: @@ -756,21 +800,23 @@ Backup: IS-IS L1 IPv4 routing table: IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt1 -2001:db8::1/128 IP6 internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) -rt5 TE-IS 20 rt3 - rt3(4) -2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) -2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) -rt6 TE-IS 30 rt2 - rt4(4) - rt3 - rt5(4) -2001:db8::4/128 IP6 internal 30 rt2 - rt4(4) -2001:db8::5/128 IP6 internal 30 rt3 - rt5(4) -2001:db8::6/128 IP6 internal 40 rt2 - rt6(4) - rt3 - + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt1 + 2001:db8::1/128 IP6 internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + rt5 TE-IS 20 rt3 - rt3(4) + 2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) + 2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) + rt6 TE-IS 30 rt2 - rt4(4) + rt3 - rt5(4) + 2001:db8::4/128 IP6 internal 30 rt2 - rt4(4) + 2001:db8::5/128 IP6 internal 30 rt3 - rt5(4) + 2001:db8::6/128 IP6 internal 40 rt2 - rt6(4) + rt3 - rt6(4) + Main: IS-IS L1 IPv6 routing table: @@ -790,21 +836,23 @@ IS-IS L1 IPv6 routing table: test# test isis topology 2 root rt4 lfa system-id rt1 pseudonode-id 1 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt4 -10.0.255.4/32 IP internal 0 rt4(4) -rt1 TE-IS 10 rt1 - rt4(4) -rt5 TE-IS 10 rt5 - rt4(4) -rt6 TE-IS 10 rt6 - rt4(4) -rt1 pseudo_TE-IS 20 rt1 - rt1(4) - rt5 - rt5(4) -10.0.255.1/32 IP TE 20 rt1 - rt1(4) -10.0.255.5/32 IP TE 20 rt5 - rt5(4) -10.0.255.6/32 IP TE 20 rt6 - rt6(4) -rt2 TE-IS 25 rt1 - rt1(4) -10.0.255.2/32 IP TE 35 rt1 - rt2(4) -rt3 TE-IS 40 rt1 - rt1(4) -10.0.255.3/32 IP TE 50 rt1 - rt3(4) + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------ + rt4 + 10.0.255.4/32 IP internal 0 rt4(4) + rt1 TE-IS 10 rt1 - rt4(4) + rt5 TE-IS 10 rt5 - rt4(4) + rt6 TE-IS 10 rt6 - rt4(4) + rt1 pseudo_TE-IS 20 rt1 - rt1(4) + rt5 - rt5(4) + 10.0.255.1/32 IP TE 20 rt1 - rt1(4) + 10.0.255.5/32 IP TE 20 rt5 - rt5(4) + 10.0.255.6/32 IP TE 20 rt6 - rt6(4) + rt2 TE-IS 25 rt1 - rt1(4) + 10.0.255.2/32 IP TE 35 rt1 - rt2(4) + rt3 TE-IS 40 rt1 - rt1(4) + 10.0.255.3/32 IP TE 50 rt1 - rt3(4) + Main: IS-IS L1 IPv4 routing table: @@ -826,21 +874,23 @@ IS-IS L1 IPv4 routing table: 10.0.255.2/32 50 - rt2 implicit-null IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt4 -2001:db8::4/128 IP6 internal 0 rt4(4) -rt1 TE-IS 10 rt1 - rt4(4) -rt5 TE-IS 10 rt5 - rt4(4) -rt6 TE-IS 10 rt6 - rt4(4) -rt1 pseudo_TE-IS 20 rt1 - rt1(4) - rt5 - rt5(4) -2001:db8::1/128 IP6 internal 20 rt1 - rt1(4) -2001:db8::5/128 IP6 internal 20 rt5 - rt5(4) -2001:db8::6/128 IP6 internal 20 rt6 - rt6(4) -rt2 TE-IS 25 rt1 - rt1(4) -2001:db8::2/128 IP6 internal 35 rt1 - rt2(4) -rt3 TE-IS 40 rt1 - rt1(4) -2001:db8::3/128 IP6 internal 50 rt1 - rt3(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt4 + 2001:db8::4/128 IP6 internal 0 rt4(4) + rt1 TE-IS 10 rt1 - rt4(4) + rt5 TE-IS 10 rt5 - rt4(4) + rt6 TE-IS 10 rt6 - rt4(4) + rt1 pseudo_TE-IS 20 rt1 - rt1(4) + rt5 - rt5(4) + 2001:db8::1/128 IP6 internal 20 rt1 - rt1(4) + 2001:db8::5/128 IP6 internal 20 rt5 - rt5(4) + 2001:db8::6/128 IP6 internal 20 rt6 - rt6(4) + rt2 TE-IS 25 rt1 - rt1(4) + 2001:db8::2/128 IP6 internal 35 rt1 - rt2(4) + rt3 TE-IS 40 rt1 - rt1(4) + 2001:db8::3/128 IP6 internal 50 rt1 - rt3(4) + Main: IS-IS L1 IPv6 routing table: @@ -863,21 +913,23 @@ IS-IS L1 IPv6 routing table: test# test isis topology 2 root rt4 lfa system-id rt6 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt4 -10.0.255.4/32 IP internal 0 rt4(4) -rt1 TE-IS 10 rt1 - rt4(4) -rt5 TE-IS 10 rt5 - rt4(4) -rt6 TE-IS 10 rt6 - rt4(4) -rt1 pseudo_TE-IS 20 rt1 - rt1(4) - rt5 - rt5(4) -10.0.255.1/32 IP TE 20 rt1 - rt1(4) -10.0.255.5/32 IP TE 20 rt5 - rt5(4) -10.0.255.6/32 IP TE 20 rt6 - rt6(4) -rt2 TE-IS 25 rt1 - rt1(4) -10.0.255.2/32 IP TE 35 rt1 - rt2(4) -rt3 TE-IS 40 rt1 - rt1(4) -10.0.255.3/32 IP TE 50 rt1 - rt3(4) + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------ + rt4 + 10.0.255.4/32 IP internal 0 rt4(4) + rt1 TE-IS 10 rt1 - rt4(4) + rt5 TE-IS 10 rt5 - rt4(4) + rt6 TE-IS 10 rt6 - rt4(4) + rt1 pseudo_TE-IS 20 rt1 - rt1(4) + rt5 - rt5(4) + 10.0.255.1/32 IP TE 20 rt1 - rt1(4) + 10.0.255.5/32 IP TE 20 rt5 - rt5(4) + 10.0.255.6/32 IP TE 20 rt6 - rt6(4) + rt2 TE-IS 25 rt1 - rt1(4) + 10.0.255.2/32 IP TE 35 rt1 - rt2(4) + rt3 TE-IS 40 rt1 - rt1(4) + 10.0.255.3/32 IP TE 50 rt1 - rt3(4) + Main: IS-IS L1 IPv4 routing table: @@ -899,21 +951,23 @@ IS-IS L1 IPv4 routing table: 10.0.255.6/32 30 - rt5 16060 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt4 -2001:db8::4/128 IP6 internal 0 rt4(4) -rt1 TE-IS 10 rt1 - rt4(4) -rt5 TE-IS 10 rt5 - rt4(4) -rt6 TE-IS 10 rt6 - rt4(4) -rt1 pseudo_TE-IS 20 rt1 - rt1(4) - rt5 - rt5(4) -2001:db8::1/128 IP6 internal 20 rt1 - rt1(4) -2001:db8::5/128 IP6 internal 20 rt5 - rt5(4) -2001:db8::6/128 IP6 internal 20 rt6 - rt6(4) -rt2 TE-IS 25 rt1 - rt1(4) -2001:db8::2/128 IP6 internal 35 rt1 - rt2(4) -rt3 TE-IS 40 rt1 - rt1(4) -2001:db8::3/128 IP6 internal 50 rt1 - rt3(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt4 + 2001:db8::4/128 IP6 internal 0 rt4(4) + rt1 TE-IS 10 rt1 - rt4(4) + rt5 TE-IS 10 rt5 - rt4(4) + rt6 TE-IS 10 rt6 - rt4(4) + rt1 pseudo_TE-IS 20 rt1 - rt1(4) + rt5 - rt5(4) + 2001:db8::1/128 IP6 internal 20 rt1 - rt1(4) + 2001:db8::5/128 IP6 internal 20 rt5 - rt5(4) + 2001:db8::6/128 IP6 internal 20 rt6 - rt6(4) + rt2 TE-IS 25 rt1 - rt1(4) + 2001:db8::2/128 IP6 internal 35 rt1 - rt2(4) + rt3 TE-IS 40 rt1 - rt1(4) + 2001:db8::3/128 IP6 internal 50 rt1 - rt3(4) + Main: IS-IS L1 IPv6 routing table: @@ -936,19 +990,21 @@ IS-IS L1 IPv6 routing table: test# test isis topology 3 root rt1 lfa system-id rt2 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt5 TE-IS 30 rt2 - rt4(4) -rt6 TE-IS 30 rt2 - rt4(4) -10.0.255.4/32 IP TE 30 rt2 - rt4(4) -10.0.255.5/32 IP TE 40 rt2 - rt5(4) -10.0.255.6/32 IP TE 40 rt2 - rt6(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt5 TE-IS 30 rt2 - rt4(4) + rt6 TE-IS 30 rt2 - rt4(4) + 10.0.255.4/32 IP TE 30 rt2 - rt4(4) + 10.0.255.5/32 IP TE 40 rt2 - rt5(4) + 10.0.255.6/32 IP TE 40 rt2 - rt6(4) + Main: IS-IS L1 IPv4 routing table: @@ -973,10 +1029,12 @@ IS-IS L1 IPv4 routing table: 10.0.255.6/32 50 - rt3 16060 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt1 -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) + Vertex Type Metric Next-Hop Interface Parent + ---------------------------------------------------- + rt1 + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + Main: IS-IS L1 IPv6 routing table: @@ -986,19 +1044,21 @@ IS-IS L1 IPv6 routing table: test# test isis topology 3 root rt1 lfa system-id rt3 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt5 TE-IS 30 rt2 - rt4(4) -rt6 TE-IS 30 rt2 - rt4(4) -10.0.255.4/32 IP TE 30 rt2 - rt4(4) -10.0.255.5/32 IP TE 40 rt2 - rt5(4) -10.0.255.6/32 IP TE 40 rt2 - rt6(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt5 TE-IS 30 rt2 - rt4(4) + rt6 TE-IS 30 rt2 - rt4(4) + 10.0.255.4/32 IP TE 30 rt2 - rt4(4) + 10.0.255.5/32 IP TE 40 rt2 - rt5(4) + 10.0.255.6/32 IP TE 40 rt2 - rt6(4) + Main: IS-IS L1 IPv4 routing table: @@ -1020,10 +1080,12 @@ IS-IS L1 IPv4 routing table: 10.0.255.3/32 30 - rt2 16030 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt1 -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) + Vertex Type Metric Next-Hop Interface Parent + ---------------------------------------------------- + rt1 + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + Main: IS-IS L1 IPv6 routing table: @@ -1033,34 +1095,36 @@ IS-IS L1 IPv6 routing table: test# test isis topology 7 root rt1 lfa system-id rt4 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt4 TE-IS 10 rt4 - rt1(4) -rt5 TE-IS 20 rt4 - rt4(4) -rt7 TE-IS 20 rt4 - rt4(4) -10.0.255.4/32 IP TE 20 rt4 - rt4(4) -rt2 TE-IS 30 rt4 - rt5(4) -rt6 TE-IS 30 rt4 - rt5(4) -rt8 TE-IS 30 rt4 - rt5(4) - rt7(4) -10.0.255.5/32 IP TE 30 rt4 - rt5(4) -10.0.255.7/32 IP TE 30 rt4 - rt7(4) -rt10 TE-IS 40 rt4 - rt7(4) -rt3 TE-IS 40 rt4 - rt2(4) - rt6(4) -rt9 TE-IS 40 rt4 - rt8(4) -rt11 TE-IS 40 rt4 - rt8(4) -10.0.255.2/32 IP TE 40 rt4 - rt2(4) -10.0.255.6/32 IP TE 40 rt4 - rt6(4) -10.0.255.8/32 IP TE 40 rt4 - rt8(4) -rt12 TE-IS 50 rt4 - rt9(4) - rt11(4) -10.0.255.10/32 IP TE 50 rt4 - rt10(4) -10.0.255.3/32 IP TE 50 rt4 - rt3(4) -10.0.255.9/32 IP TE 50 rt4 - rt9(4) -10.0.255.11/32 IP TE 50 rt4 - rt11(4) -10.0.255.12/32 IP TE 60 rt4 - rt12(4) + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt4 TE-IS 10 rt4 - rt1(4) + rt5 TE-IS 20 rt4 - rt4(4) + rt7 TE-IS 20 rt4 - rt4(4) + 10.0.255.4/32 IP TE 20 rt4 - rt4(4) + rt2 TE-IS 30 rt4 - rt5(4) + rt6 TE-IS 30 rt4 - rt5(4) + rt8 TE-IS 30 rt4 - rt5(4) + rt7(4) + 10.0.255.5/32 IP TE 30 rt4 - rt5(4) + 10.0.255.7/32 IP TE 30 rt4 - rt7(4) + rt10 TE-IS 40 rt4 - rt7(4) + rt3 TE-IS 40 rt4 - rt2(4) + rt6(4) + rt9 TE-IS 40 rt4 - rt8(4) + rt11 TE-IS 40 rt4 - rt8(4) + 10.0.255.2/32 IP TE 40 rt4 - rt2(4) + 10.0.255.6/32 IP TE 40 rt4 - rt6(4) + 10.0.255.8/32 IP TE 40 rt4 - rt8(4) + rt12 TE-IS 50 rt4 - rt9(4) + rt11(4) + 10.0.255.10/32 IP TE 50 rt4 - rt10(4) + 10.0.255.3/32 IP TE 50 rt4 - rt3(4) + 10.0.255.9/32 IP TE 50 rt4 - rt9(4) + 10.0.255.11/32 IP TE 50 rt4 - rt11(4) + 10.0.255.12/32 IP TE 60 rt4 - rt12(4) + Main: IS-IS L1 IPv4 routing table: @@ -1098,10 +1162,12 @@ IS-IS L1 IPv4 routing table: 10.0.255.12/32 90 - rt2 16120 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt1 -rt4 TE-IS 10 rt4 - rt1(4) -rt2 TE-IS 40 rt2 - rt1(4) + Vertex Type Metric Next-Hop Interface Parent + ---------------------------------------------------- + rt1 + rt4 TE-IS 10 rt4 - rt1(4) + rt2 TE-IS 40 rt2 - rt1(4) + Main: IS-IS L1 IPv6 routing table: @@ -1111,40 +1177,42 @@ IS-IS L1 IPv6 routing table: test# test isis topology 7 root rt7 lfa system-id rt8 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt7 -10.0.255.7/32 IP internal 0 rt7(4) -rt4 TE-IS 10 rt4 - rt7(4) -rt8 TE-IS 10 rt8 - rt7(4) -rt10 TE-IS 20 rt10 - rt7(4) -rt1 TE-IS 20 rt4 - rt4(4) -rt5 TE-IS 20 rt4 - rt4(4) - rt8 - rt8(4) -rt9 TE-IS 20 rt8 - rt8(4) -rt11 TE-IS 20 rt8 - rt8(4) -10.0.255.4/32 IP TE 20 rt4 - rt4(4) -10.0.255.8/32 IP TE 20 rt8 - rt8(4) -rt2 TE-IS 30 rt4 - rt5(4) - rt8 - -rt6 TE-IS 30 rt4 - rt5(4) - rt8 - -rt12 TE-IS 30 rt8 - rt9(4) - rt11(4) -10.0.255.10/32 IP TE 30 rt10 - rt10(4) -10.0.255.1/32 IP TE 30 rt4 - rt1(4) -10.0.255.5/32 IP TE 30 rt4 - rt5(4) - rt8 - -10.0.255.9/32 IP TE 30 rt8 - rt9(4) -10.0.255.11/32 IP TE 30 rt8 - rt11(4) -rt3 TE-IS 40 rt4 - rt2(4) - rt8 - rt6(4) -10.0.255.2/32 IP TE 40 rt4 - rt2(4) - rt8 - -10.0.255.6/32 IP TE 40 rt4 - rt6(4) - rt8 - -10.0.255.12/32 IP TE 40 rt8 - rt12(4) -10.0.255.3/32 IP TE 50 rt4 - rt3(4) - rt8 - + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------- + rt7 + 10.0.255.7/32 IP internal 0 rt7(4) + rt4 TE-IS 10 rt4 - rt7(4) + rt8 TE-IS 10 rt8 - rt7(4) + rt10 TE-IS 20 rt10 - rt7(4) + rt1 TE-IS 20 rt4 - rt4(4) + rt5 TE-IS 20 rt4 - rt4(4) + rt8 - rt8(4) + rt9 TE-IS 20 rt8 - rt8(4) + rt11 TE-IS 20 rt8 - rt8(4) + 10.0.255.4/32 IP TE 20 rt4 - rt4(4) + 10.0.255.8/32 IP TE 20 rt8 - rt8(4) + rt2 TE-IS 30 rt4 - rt5(4) + rt8 - rt5(4) + rt6 TE-IS 30 rt4 - rt5(4) + rt8 - rt5(4) + rt12 TE-IS 30 rt8 - rt9(4) + rt11(4) + 10.0.255.10/32 IP TE 30 rt10 - rt10(4) + 10.0.255.1/32 IP TE 30 rt4 - rt1(4) + 10.0.255.5/32 IP TE 30 rt4 - rt5(4) + rt8 - rt5(4) + 10.0.255.9/32 IP TE 30 rt8 - rt9(4) + 10.0.255.11/32 IP TE 30 rt8 - rt11(4) + rt3 TE-IS 40 rt4 - rt2(4) + rt8 - rt6(4) + 10.0.255.2/32 IP TE 40 rt4 - rt2(4) + rt8 - rt2(4) + 10.0.255.6/32 IP TE 40 rt4 - rt6(4) + rt8 - rt6(4) + 10.0.255.12/32 IP TE 40 rt8 - rt12(4) + 10.0.255.3/32 IP TE 50 rt4 - rt3(4) + rt8 - rt3(4) + Main: IS-IS L1 IPv4 routing table: @@ -1179,11 +1247,13 @@ IS-IS L1 IPv4 routing table: 10.0.255.12/32 50 - rt10 16120 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt7 -rt4 TE-IS 10 rt4 - rt7(4) -rt8 TE-IS 10 rt8 - rt7(4) -rt10 TE-IS 20 rt10 - rt7(4) + Vertex Type Metric Next-Hop Interface Parent + ---------------------------------------------------- + rt7 + rt4 TE-IS 10 rt4 - rt7(4) + rt8 TE-IS 10 rt8 - rt7(4) + rt10 TE-IS 20 rt10 - rt7(4) + Main: IS-IS L1 IPv6 routing table: @@ -1193,38 +1263,40 @@ IS-IS L1 IPv6 routing table: test# test isis topology 7 root rt8 lfa system-id rt11 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt8 -10.0.255.8/32 IP internal 0 rt8(4) -rt5 TE-IS 10 rt5 - rt8(4) -rt7 TE-IS 10 rt7 - rt8(4) -rt9 TE-IS 10 rt9 - rt8(4) -rt11 TE-IS 10 rt11 - rt8(4) -rt2 TE-IS 20 rt5 - rt5(4) -rt4 TE-IS 20 rt5 - rt5(4) - rt7 - rt7(4) -rt6 TE-IS 20 rt5 - rt5(4) -rt12 TE-IS 20 rt9 - rt9(4) - rt11 - rt11(4) -rt10 TE-IS 20 rt11 - rt11(4) -10.0.255.5/32 IP TE 20 rt5 - rt5(4) -10.0.255.7/32 IP TE 20 rt7 - rt7(4) -10.0.255.9/32 IP TE 20 rt9 - rt9(4) -10.0.255.11/32 IP TE 20 rt11 - rt11(4) -rt3 TE-IS 30 rt5 - rt2(4) - rt6(4) -rt1 TE-IS 30 rt5 - rt4(4) - rt7 - -10.0.255.2/32 IP TE 30 rt5 - rt2(4) -10.0.255.4/32 IP TE 30 rt5 - rt4(4) - rt7 - -10.0.255.6/32 IP TE 30 rt5 - rt6(4) -10.0.255.12/32 IP TE 30 rt9 - rt12(4) - rt11 - -10.0.255.10/32 IP TE 30 rt11 - rt10(4) -10.0.255.3/32 IP TE 40 rt5 - rt3(4) -10.0.255.1/32 IP TE 40 rt5 - rt1(4) - rt7 - + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------- + rt8 + 10.0.255.8/32 IP internal 0 rt8(4) + rt5 TE-IS 10 rt5 - rt8(4) + rt7 TE-IS 10 rt7 - rt8(4) + rt9 TE-IS 10 rt9 - rt8(4) + rt11 TE-IS 10 rt11 - rt8(4) + rt2 TE-IS 20 rt5 - rt5(4) + rt4 TE-IS 20 rt5 - rt5(4) + rt7 - rt7(4) + rt6 TE-IS 20 rt5 - rt5(4) + rt12 TE-IS 20 rt9 - rt9(4) + rt11 - rt11(4) + rt10 TE-IS 20 rt11 - rt11(4) + 10.0.255.5/32 IP TE 20 rt5 - rt5(4) + 10.0.255.7/32 IP TE 20 rt7 - rt7(4) + 10.0.255.9/32 IP TE 20 rt9 - rt9(4) + 10.0.255.11/32 IP TE 20 rt11 - rt11(4) + rt3 TE-IS 30 rt5 - rt2(4) + rt6(4) + rt1 TE-IS 30 rt5 - rt4(4) + rt7 - rt4(4) + 10.0.255.2/32 IP TE 30 rt5 - rt2(4) + 10.0.255.4/32 IP TE 30 rt5 - rt4(4) + rt7 - rt4(4) + 10.0.255.6/32 IP TE 30 rt5 - rt6(4) + 10.0.255.12/32 IP TE 30 rt9 - rt12(4) + rt11 - rt12(4) + 10.0.255.10/32 IP TE 30 rt11 - rt10(4) + 10.0.255.3/32 IP TE 40 rt5 - rt3(4) + 10.0.255.1/32 IP TE 40 rt5 - rt1(4) + rt7 - rt1(4) + Main: IS-IS L1 IPv4 routing table: @@ -1255,12 +1327,14 @@ IS-IS L1 IPv4 routing table: 10.0.255.10/32 40 - rt7 16100 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt8 -rt5 TE-IS 10 rt5 - rt8(4) -rt7 TE-IS 10 rt7 - rt8(4) -rt9 TE-IS 10 rt9 - rt8(4) -rt11 TE-IS 10 rt11 - rt8(4) + Vertex Type Metric Next-Hop Interface Parent + ---------------------------------------------------- + rt8 + rt5 TE-IS 10 rt5 - rt8(4) + rt7 TE-IS 10 rt7 - rt8(4) + rt9 TE-IS 10 rt9 - rt8(4) + rt11 TE-IS 10 rt11 - rt8(4) + Main: IS-IS L1 IPv6 routing table: @@ -1270,28 +1344,30 @@ IS-IS L1 IPv6 routing table: test# test isis topology 9 root rt3 lfa system-id rt1 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt3 -10.0.255.3/32 IP internal 0 rt3(4) -rt1 TE-IS 10 rt1 - rt3(4) -rt2 TE-IS 20 rt1 - rt1(4) -10.0.255.1/32 IP TE 20 rt1 - rt1(4) -rt4 TE-IS 30 rt1 - rt2(4) -10.0.255.2/32 IP TE 30 rt1 - rt2(4) -rt5 TE-IS 40 rt1 - rt4(4) -10.0.255.4/32 IP TE 40 rt1 - rt4(4) -rt9 TE-IS 50 rt1 - rt5(4) -10.0.255.5/32 IP TE 50 rt1 - rt5(4) -rt6 TE-IS 60 rt1 - rt4(4) - rt9(4) -rt7 TE-IS 60 rt1 - rt4(4) - rt9(4) -rt8 TE-IS 60 rt1 - rt4(4) - rt9(4) -10.0.255.9/32 IP TE 60 rt1 - rt9(4) -10.0.255.6/32 IP TE 70 rt1 - rt6(4) -10.0.255.7/32 IP TE 70 rt1 - rt7(4) -10.0.255.8/32 IP TE 70 rt1 - rt8(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt3 + 10.0.255.3/32 IP internal 0 rt3(4) + rt1 TE-IS 10 rt1 - rt3(4) + rt2 TE-IS 20 rt1 - rt1(4) + 10.0.255.1/32 IP TE 20 rt1 - rt1(4) + rt4 TE-IS 30 rt1 - rt2(4) + 10.0.255.2/32 IP TE 30 rt1 - rt2(4) + rt5 TE-IS 40 rt1 - rt4(4) + 10.0.255.4/32 IP TE 40 rt1 - rt4(4) + rt9 TE-IS 50 rt1 - rt5(4) + 10.0.255.5/32 IP TE 50 rt1 - rt5(4) + rt6 TE-IS 60 rt1 - rt4(4) + rt9(4) + rt7 TE-IS 60 rt1 - rt4(4) + rt9(4) + rt8 TE-IS 60 rt1 - rt4(4) + rt9(4) + 10.0.255.9/32 IP TE 60 rt1 - rt9(4) + 10.0.255.6/32 IP TE 70 rt1 - rt6(4) + 10.0.255.7/32 IP TE 70 rt1 - rt7(4) + 10.0.255.8/32 IP TE 70 rt1 - rt8(4) + Main: IS-IS L1 IPv4 routing table: @@ -1323,28 +1399,30 @@ IS-IS L1 IPv4 routing table: 10.0.255.9/32 130 - rt4 16090 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt3 -2001:db8::3/128 IP6 internal 0 rt3(4) -rt1 TE-IS 10 rt1 - rt3(4) -rt2 TE-IS 20 rt1 - rt1(4) -2001:db8::1/128 IP6 internal 20 rt1 - rt1(4) -rt4 TE-IS 30 rt1 - rt2(4) -2001:db8::2/128 IP6 internal 30 rt1 - rt2(4) -rt5 TE-IS 40 rt1 - rt4(4) -2001:db8::4/128 IP6 internal 40 rt1 - rt4(4) -rt9 TE-IS 50 rt1 - rt5(4) -2001:db8::5/128 IP6 internal 50 rt1 - rt5(4) -rt6 TE-IS 60 rt1 - rt4(4) - rt9(4) -rt7 TE-IS 60 rt1 - rt4(4) - rt9(4) -rt8 TE-IS 60 rt1 - rt4(4) - rt9(4) -2001:db8::9/128 IP6 internal 60 rt1 - rt9(4) -2001:db8::6/128 IP6 internal 70 rt1 - rt6(4) -2001:db8::7/128 IP6 internal 70 rt1 - rt7(4) -2001:db8::8/128 IP6 internal 70 rt1 - rt8(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt3 + 2001:db8::3/128 IP6 internal 0 rt3(4) + rt1 TE-IS 10 rt1 - rt3(4) + rt2 TE-IS 20 rt1 - rt1(4) + 2001:db8::1/128 IP6 internal 20 rt1 - rt1(4) + rt4 TE-IS 30 rt1 - rt2(4) + 2001:db8::2/128 IP6 internal 30 rt1 - rt2(4) + rt5 TE-IS 40 rt1 - rt4(4) + 2001:db8::4/128 IP6 internal 40 rt1 - rt4(4) + rt9 TE-IS 50 rt1 - rt5(4) + 2001:db8::5/128 IP6 internal 50 rt1 - rt5(4) + rt6 TE-IS 60 rt1 - rt4(4) + rt9(4) + rt7 TE-IS 60 rt1 - rt4(4) + rt9(4) + rt8 TE-IS 60 rt1 - rt4(4) + rt9(4) + 2001:db8::9/128 IP6 internal 60 rt1 - rt9(4) + 2001:db8::6/128 IP6 internal 70 rt1 - rt6(4) + 2001:db8::7/128 IP6 internal 70 rt1 - rt7(4) + 2001:db8::8/128 IP6 internal 70 rt1 - rt8(4) + Main: IS-IS L1 IPv6 routing table: @@ -1377,23 +1455,25 @@ IS-IS L1 IPv6 routing table: test# test isis topology 10 root rt8 lfa system-id rt5 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt8 -10.0.255.8/32 IP internal 0 rt8(4) -rt5 TE-IS 10 rt5 - rt8(4) -rt2 TE-IS 20 rt5 - rt5(4) -10.0.255.5/32 IP TE 20 rt5 - rt5(4) -rt1 TE-IS 30 rt5 - rt2(4) -10.0.255.2/32 IP TE 30 rt5 - rt2(4) -10.0.255.1/32 IP TE 40 rt5 - rt1(4) -rt6 TE-IS 50 rt6 - rt8(4) -rt7 TE-IS 50 rt7 - rt8(4) -rt3 TE-IS 50 rt5 - rt1(4) -rt4 TE-IS 50 rt5 - rt1(4) -10.0.255.6/32 IP TE 60 rt6 - rt6(4) -10.0.255.7/32 IP TE 60 rt7 - rt7(4) -10.0.255.3/32 IP TE 60 rt5 - rt3(4) -10.0.255.4/32 IP TE 60 rt5 - rt4(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt8 + 10.0.255.8/32 IP internal 0 rt8(4) + rt5 TE-IS 10 rt5 - rt8(4) + rt2 TE-IS 20 rt5 - rt5(4) + 10.0.255.5/32 IP TE 20 rt5 - rt5(4) + rt1 TE-IS 30 rt5 - rt2(4) + 10.0.255.2/32 IP TE 30 rt5 - rt2(4) + 10.0.255.1/32 IP TE 40 rt5 - rt1(4) + rt6 TE-IS 50 rt6 - rt8(4) + rt7 TE-IS 50 rt7 - rt8(4) + rt3 TE-IS 50 rt5 - rt1(4) + rt4 TE-IS 50 rt5 - rt1(4) + 10.0.255.6/32 IP TE 60 rt6 - rt6(4) + 10.0.255.7/32 IP TE 60 rt7 - rt7(4) + 10.0.255.3/32 IP TE 60 rt5 - rt3(4) + 10.0.255.4/32 IP TE 60 rt5 - rt4(4) + Main: IS-IS L1 IPv4 routing table: @@ -1426,23 +1506,25 @@ IS-IS L1 IPv4 routing table: - rt7 16050 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt8 -2001:db8::8/128 IP6 internal 0 rt8(4) -rt5 TE-IS 10 rt5 - rt8(4) -rt2 TE-IS 20 rt5 - rt5(4) -2001:db8::5/128 IP6 internal 20 rt5 - rt5(4) -rt1 TE-IS 30 rt5 - rt2(4) -2001:db8::2/128 IP6 internal 30 rt5 - rt2(4) -2001:db8::1/128 IP6 internal 40 rt5 - rt1(4) -rt6 TE-IS 50 rt6 - rt8(4) -rt7 TE-IS 50 rt7 - rt8(4) -rt3 TE-IS 50 rt5 - rt1(4) -rt4 TE-IS 50 rt5 - rt1(4) -2001:db8::6/128 IP6 internal 60 rt6 - rt6(4) -2001:db8::7/128 IP6 internal 60 rt7 - rt7(4) -2001:db8::3/128 IP6 internal 60 rt5 - rt3(4) -2001:db8::4/128 IP6 internal 60 rt5 - rt4(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt8 + 2001:db8::8/128 IP6 internal 0 rt8(4) + rt5 TE-IS 10 rt5 - rt8(4) + rt2 TE-IS 20 rt5 - rt5(4) + 2001:db8::5/128 IP6 internal 20 rt5 - rt5(4) + rt1 TE-IS 30 rt5 - rt2(4) + 2001:db8::2/128 IP6 internal 30 rt5 - rt2(4) + 2001:db8::1/128 IP6 internal 40 rt5 - rt1(4) + rt6 TE-IS 50 rt6 - rt8(4) + rt7 TE-IS 50 rt7 - rt8(4) + rt3 TE-IS 50 rt5 - rt1(4) + rt4 TE-IS 50 rt5 - rt1(4) + 2001:db8::6/128 IP6 internal 60 rt6 - rt6(4) + 2001:db8::7/128 IP6 internal 60 rt7 - rt7(4) + 2001:db8::3/128 IP6 internal 60 rt5 - rt3(4) + 2001:db8::4/128 IP6 internal 60 rt5 - rt4(4) + Main: IS-IS L1 IPv6 routing table: @@ -1476,22 +1558,24 @@ IS-IS L1 IPv6 routing table: test# test isis topology 11 root rt3 lfa system-id rt5 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt3 -10.0.255.3/32 IP internal 0 rt3(4) -rt1 TE-IS 10 rt1 - rt3(4) -rt2 TE-IS 10 rt2 - rt3(4) -rt5 TE-IS 10 rt5 - rt3(4) -rt2 pseudo_TE-IS 20 rt1 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) - rt5 - rt5(4) -rt6 TE-IS 20 rt5 - rt5(4) -10.0.255.1/32 IP TE 20 rt1 - rt1(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.5/32 IP TE 20 rt5 - rt5(4) -10.0.255.4/32 IP TE 30 rt2 - rt4(4) - rt5 - -10.0.255.6/32 IP TE 30 rt5 - rt6(4) + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------ + rt3 + 10.0.255.3/32 IP internal 0 rt3(4) + rt1 TE-IS 10 rt1 - rt3(4) + rt2 TE-IS 10 rt2 - rt3(4) + rt5 TE-IS 10 rt5 - rt3(4) + rt2 pseudo_TE-IS 20 rt1 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + rt5 - rt5(4) + rt6 TE-IS 20 rt5 - rt5(4) + 10.0.255.1/32 IP TE 20 rt1 - rt1(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.5/32 IP TE 20 rt5 - rt5(4) + 10.0.255.4/32 IP TE 30 rt2 - rt4(4) + rt5 - rt4(4) + 10.0.255.6/32 IP TE 30 rt5 - rt6(4) + Main: IS-IS L1 IPv4 routing table: @@ -1515,22 +1599,24 @@ IS-IS L1 IPv4 routing table: 10.0.255.6/32 40 - rt2 16060 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt3 -2001:db8::3/128 IP6 internal 0 rt3(4) -rt1 TE-IS 10 rt1 - rt3(4) -rt2 TE-IS 10 rt2 - rt3(4) -rt5 TE-IS 10 rt5 - rt3(4) -rt2 pseudo_TE-IS 20 rt1 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) - rt5 - rt5(4) -rt6 TE-IS 20 rt5 - rt5(4) -2001:db8::1/128 IP6 internal 20 rt1 - rt1(4) -2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) -2001:db8::5/128 IP6 internal 20 rt5 - rt5(4) -2001:db8::4/128 IP6 internal 30 rt2 - rt4(4) - rt5 - -2001:db8::6/128 IP6 internal 30 rt5 - rt6(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt3 + 2001:db8::3/128 IP6 internal 0 rt3(4) + rt1 TE-IS 10 rt1 - rt3(4) + rt2 TE-IS 10 rt2 - rt3(4) + rt5 TE-IS 10 rt5 - rt3(4) + rt2 pseudo_TE-IS 20 rt1 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + rt5 - rt5(4) + rt6 TE-IS 20 rt5 - rt5(4) + 2001:db8::1/128 IP6 internal 20 rt1 - rt1(4) + 2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) + 2001:db8::5/128 IP6 internal 20 rt5 - rt5(4) + 2001:db8::4/128 IP6 internal 30 rt2 - rt4(4) + rt5 - rt4(4) + 2001:db8::6/128 IP6 internal 30 rt5 - rt6(4) + Main: IS-IS L1 IPv6 routing table: @@ -1555,24 +1641,26 @@ IS-IS L1 IPv6 routing table: test# test isis topology 13 root rt4 lfa system-id rt3 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt4 -10.0.255.4/32 IP internal 0 rt4(4) -rt2 TE-IS 10 rt2 - rt4(4) -rt3 TE-IS 10 rt3 - rt4(4) -rt1 TE-IS 20 rt2 - rt2(4) - rt3 - rt3(4) -rt5 TE-IS 20 rt3 - rt3(4) -rt6 TE-IS 20 rt3 - rt3(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt7 TE-IS 30 rt3 - rt5(4) - rt6(4) -10.0.255.1/32 IP TE 30 rt2 - rt1(4) - rt3 - -10.0.255.5/32 IP TE 30 rt3 - rt5(4) -10.0.255.6/32 IP TE 30 rt3 - rt6(4) -10.0.255.7/32 IP TE 40 rt3 - rt7(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt4 + 10.0.255.4/32 IP internal 0 rt4(4) + rt2 TE-IS 10 rt2 - rt4(4) + rt3 TE-IS 10 rt3 - rt4(4) + rt1 TE-IS 20 rt2 - rt2(4) + rt3 - rt3(4) + rt5 TE-IS 20 rt3 - rt3(4) + rt6 TE-IS 20 rt3 - rt3(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt7 TE-IS 30 rt3 - rt5(4) + rt6(4) + 10.0.255.1/32 IP TE 30 rt2 - rt1(4) + rt3 - rt1(4) + 10.0.255.5/32 IP TE 30 rt3 - rt5(4) + 10.0.255.6/32 IP TE 30 rt3 - rt6(4) + 10.0.255.7/32 IP TE 40 rt3 - rt7(4) + Main: IS-IS L1 IPv4 routing table: @@ -1599,11 +1687,13 @@ IS-IS L1 IPv4 routing table: 10.0.255.7/32 120 - rt5 16070 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt4 -rt2 TE-IS 10 rt2 - rt4(4) -rt3 TE-IS 10 rt3 - rt4(4) -rt5 TE-IS 100 rt5 - rt4(4) + Vertex Type Metric Next-Hop Interface Parent + ---------------------------------------------------- + rt4 + rt2 TE-IS 10 rt2 - rt4(4) + rt3 TE-IS 10 rt3 - rt4(4) + rt5 TE-IS 100 rt5 - rt4(4) + Main: IS-IS L1 IPv6 routing table: @@ -1613,18 +1703,20 @@ IS-IS L1 IPv6 routing table: test# test isis topology 14 root rt1 lfa system-id rt1 pseudonode-id 1 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 10 rt4 - rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt1 -rt5 TE-IS 20 rt4 - rt4(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -10.0.255.4/32 IP TE 20 rt4 - rt4(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.5/32 IP TE 30 rt4 - rt5(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 10 rt4 - rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt1 + rt5 TE-IS 20 rt4 - rt4(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + 10.0.255.4/32 IP TE 20 rt4 - rt4(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.5/32 IP TE 30 rt4 - rt5(4) + Main: IS-IS L1 IPv4 routing table: @@ -1641,18 +1733,20 @@ Backup: IS-IS L1 IPv4 routing table: IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt1 -2001:db8::1/128 IP6 internal 0 rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 10 rt4 - rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt1 -rt5 TE-IS 20 rt4 - rt4(4) -2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) -2001:db8::4/128 IP6 internal 20 rt4 - rt4(4) -2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) -2001:db8::5/128 IP6 internal 30 rt4 - rt5(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt1 + 2001:db8::1/128 IP6 internal 0 rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 10 rt4 - rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt1 + rt5 TE-IS 20 rt4 - rt4(4) + 2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) + 2001:db8::4/128 IP6 internal 20 rt4 - rt4(4) + 2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) + 2001:db8::5/128 IP6 internal 30 rt4 - rt5(4) + Main: IS-IS L1 IPv6 routing table: @@ -1670,18 +1764,20 @@ IS-IS L1 IPv6 routing table: test# test isis topology 14 root rt1 lfa system-id rt2 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 10 rt4 - rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt1 -rt5 TE-IS 20 rt4 - rt4(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -10.0.255.4/32 IP TE 20 rt4 - rt4(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.5/32 IP TE 30 rt4 - rt5(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 10 rt4 - rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt1 + rt5 TE-IS 20 rt4 - rt4(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + 10.0.255.4/32 IP TE 20 rt4 - rt4(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.5/32 IP TE 30 rt4 - rt5(4) + Main: IS-IS L1 IPv4 routing table: @@ -1702,18 +1798,20 @@ IS-IS L1 IPv4 routing table: 10.0.255.2/32 30 - rt3 - IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt1 -2001:db8::1/128 IP6 internal 0 rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 10 rt4 - rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt1 -rt5 TE-IS 20 rt4 - rt4(4) -2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) -2001:db8::4/128 IP6 internal 20 rt4 - rt4(4) -2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) -2001:db8::5/128 IP6 internal 30 rt4 - rt5(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt1 + 2001:db8::1/128 IP6 internal 0 rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 10 rt4 - rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt1 + rt5 TE-IS 20 rt4 - rt4(4) + 2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) + 2001:db8::4/128 IP6 internal 20 rt4 - rt4(4) + 2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) + 2001:db8::5/128 IP6 internal 30 rt4 - rt5(4) + Main: IS-IS L1 IPv6 routing table: @@ -1735,19 +1833,21 @@ IS-IS L1 IPv6 routing table: test# test isis topology 14 root rt5 lfa system-id rt4 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt5 -10.0.255.5/32 IP internal 0 rt5(4) -rt4 TE-IS 10 rt4 - rt5(4) -rt1 pseudo_TE-IS 20 rt4 - rt4(4) -rt1 TE-IS 20 rt4 - rt1(2) -rt3 TE-IS 20 rt4 - rt1(2) -10.0.255.4/32 IP TE 20 rt4 - rt4(4) -rt2 TE-IS 30 rt4 - rt1(4) - rt3(4) -10.0.255.1/32 IP TE 30 rt4 - rt1(4) -10.0.255.3/32 IP TE 30 rt4 - rt3(4) -10.0.255.2/32 IP TE 40 rt4 - rt2(4) + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------ + rt5 + 10.0.255.5/32 IP internal 0 rt5(4) + rt4 TE-IS 10 rt4 - rt5(4) + rt1 pseudo_TE-IS 20 rt4 - rt4(4) + rt1 TE-IS 20 rt4 - rt1(2) + rt3 TE-IS 20 rt4 - rt1(2) + 10.0.255.4/32 IP TE 20 rt4 - rt4(4) + rt2 TE-IS 30 rt4 - rt1(4) + rt3(4) + 10.0.255.1/32 IP TE 30 rt4 - rt1(4) + 10.0.255.3/32 IP TE 30 rt4 - rt3(4) + 10.0.255.2/32 IP TE 40 rt4 - rt2(4) + Main: IS-IS L1 IPv4 routing table: @@ -1771,19 +1871,21 @@ IS-IS L1 IPv4 routing table: 10.0.255.4/32 70 - rt3 - IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt5 -2001:db8::5/128 IP6 internal 0 rt5(4) -rt4 TE-IS 10 rt4 - rt5(4) -rt1 pseudo_TE-IS 20 rt4 - rt4(4) -rt1 TE-IS 20 rt4 - rt1(2) -rt3 TE-IS 20 rt4 - rt1(2) -2001:db8::4/128 IP6 internal 20 rt4 - rt4(4) -rt2 TE-IS 30 rt4 - rt1(4) - rt3(4) -2001:db8::1/128 IP6 internal 30 rt4 - rt1(4) -2001:db8::3/128 IP6 internal 30 rt4 - rt3(4) -2001:db8::2/128 IP6 internal 40 rt4 - rt2(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt5 + 2001:db8::5/128 IP6 internal 0 rt5(4) + rt4 TE-IS 10 rt4 - rt5(4) + rt1 pseudo_TE-IS 20 rt4 - rt4(4) + rt1 TE-IS 20 rt4 - rt1(2) + rt3 TE-IS 20 rt4 - rt1(2) + 2001:db8::4/128 IP6 internal 20 rt4 - rt4(4) + rt2 TE-IS 30 rt4 - rt1(4) + rt3(4) + 2001:db8::1/128 IP6 internal 30 rt4 - rt1(4) + 2001:db8::3/128 IP6 internal 30 rt4 - rt3(4) + 2001:db8::2/128 IP6 internal 40 rt4 - rt2(4) + Main: IS-IS L1 IPv6 routing table: @@ -1823,36 +1925,40 @@ Q-space: rt6 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt5 TE-IS 20 rt3 - rt3(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt6 TE-IS 30 rt3 - rt5(4) -10.0.255.5/32 IP TE 30 rt3 - rt5(4) -rt4 TE-IS 40 rt3 - rt6(4) -10.0.255.6/32 IP TE 40 rt3 - rt6(4) -rt2 TE-IS 50 rt3 - rt4(4) -10.0.255.4/32 IP TE 50 rt3 - rt4(4) -10.0.255.2/32 IP TE 60 rt3 - rt2(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt5 TE-IS 20 rt3 - rt3(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt6 TE-IS 30 rt3 - rt5(4) + 10.0.255.5/32 IP TE 30 rt3 - rt5(4) + rt4 TE-IS 40 rt3 - rt6(4) + 10.0.255.6/32 IP TE 40 rt3 - rt6(4) + rt2 TE-IS 50 rt3 - rt4(4) + 10.0.255.4/32 IP TE 50 rt3 - rt4(4) + 10.0.255.2/32 IP TE 60 rt3 - rt2(4) + IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) -rt5 TE-IS 20 rt3 - rt3(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt6 TE-IS 30 rt2 - rt4(4) - rt3 - rt5(4) -10.0.255.4/32 IP TE 30 rt2 - rt4(4) -10.0.255.5/32 IP TE 30 rt3 - rt5(4) -10.0.255.6/32 IP TE 40 rt2 - rt6(4) - rt3 - + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + rt5 TE-IS 20 rt3 - rt3(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt6 TE-IS 30 rt2 - rt4(4) + rt3 - rt5(4) + 10.0.255.4/32 IP TE 30 rt2 - rt4(4) + 10.0.255.5/32 IP TE 30 rt3 - rt5(4) + 10.0.255.6/32 IP TE 40 rt2 - rt6(4) + rt3 - rt6(4) + Main: IS-IS L1 IPv4 routing table: @@ -1890,36 +1996,40 @@ Q-space: rt6 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt1 -2001:db8::1/128 IP6 internal 0 rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt5 TE-IS 20 rt3 - rt3(4) -2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) -rt6 TE-IS 30 rt3 - rt5(4) -2001:db8::5/128 IP6 internal 30 rt3 - rt5(4) -rt4 TE-IS 40 rt3 - rt6(4) -2001:db8::6/128 IP6 internal 40 rt3 - rt6(4) -rt2 TE-IS 50 rt3 - rt4(4) -2001:db8::4/128 IP6 internal 50 rt3 - rt4(4) -2001:db8::2/128 IP6 internal 60 rt3 - rt2(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt1 + 2001:db8::1/128 IP6 internal 0 rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt5 TE-IS 20 rt3 - rt3(4) + 2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) + rt6 TE-IS 30 rt3 - rt5(4) + 2001:db8::5/128 IP6 internal 30 rt3 - rt5(4) + rt4 TE-IS 40 rt3 - rt6(4) + 2001:db8::6/128 IP6 internal 40 rt3 - rt6(4) + rt2 TE-IS 50 rt3 - rt4(4) + 2001:db8::4/128 IP6 internal 50 rt3 - rt4(4) + 2001:db8::2/128 IP6 internal 60 rt3 - rt2(4) + IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt1 -2001:db8::1/128 IP6 internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) -rt5 TE-IS 20 rt3 - rt3(4) -2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) -2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) -rt6 TE-IS 30 rt2 - rt4(4) - rt3 - rt5(4) -2001:db8::4/128 IP6 internal 30 rt2 - rt4(4) -2001:db8::5/128 IP6 internal 30 rt3 - rt5(4) -2001:db8::6/128 IP6 internal 40 rt2 - rt6(4) - rt3 - + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt1 + 2001:db8::1/128 IP6 internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + rt5 TE-IS 20 rt3 - rt3(4) + 2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) + 2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) + rt6 TE-IS 30 rt2 - rt4(4) + rt3 - rt5(4) + 2001:db8::4/128 IP6 internal 30 rt2 - rt4(4) + 2001:db8::5/128 IP6 internal 30 rt3 - rt5(4) + 2001:db8::6/128 IP6 internal 40 rt2 - rt6(4) + rt3 - rt6(4) + Main: IS-IS L1 IPv6 routing table: @@ -1964,39 +2074,43 @@ Q-space: rt6 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt5 -10.0.255.5/32 IP internal 0 rt5(4) -rt6 TE-IS 10 rt6 - rt5(4) -rt4 TE-IS 20 rt6 - rt6(4) -10.0.255.6/32 IP TE 20 rt6 - rt6(4) -rt1 pseudo_TE-IS 30 rt6 - rt4(4) -rt1 TE-IS 30 rt6 - rt1(2) -10.0.255.4/32 IP TE 30 rt6 - rt4(4) -rt3 TE-IS 40 rt3 - rt5(4) -10.0.255.1/32 IP TE 40 rt6 - rt1(4) -rt2 TE-IS 45 rt6 - rt1(4) -10.0.255.3/32 IP TE 50 rt3 - rt3(4) -10.0.255.2/32 IP TE 55 rt6 - rt2(4) + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------ + rt5 + 10.0.255.5/32 IP internal 0 rt5(4) + rt6 TE-IS 10 rt6 - rt5(4) + rt4 TE-IS 20 rt6 - rt6(4) + 10.0.255.6/32 IP TE 20 rt6 - rt6(4) + rt1 pseudo_TE-IS 30 rt6 - rt4(4) + rt1 TE-IS 30 rt6 - rt1(2) + 10.0.255.4/32 IP TE 30 rt6 - rt4(4) + rt3 TE-IS 40 rt3 - rt5(4) + 10.0.255.1/32 IP TE 40 rt6 - rt1(4) + rt2 TE-IS 45 rt6 - rt1(4) + 10.0.255.3/32 IP TE 50 rt3 - rt3(4) + 10.0.255.2/32 IP TE 55 rt6 - rt2(4) + IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt5 -10.0.255.5/32 IP internal 0 rt5(4) -rt1 TE-IS 10 rt1 - rt5(4) -rt4 TE-IS 10 rt4 - rt5(4) -rt6 TE-IS 10 rt6 - rt5(4) -rt1 pseudo_TE-IS 20 rt1 - rt1(4) - rt4 - rt4(4) -10.0.255.1/32 IP TE 20 rt1 - rt1(4) -10.0.255.4/32 IP TE 20 rt4 - rt4(4) -10.0.255.6/32 IP TE 20 rt6 - rt6(4) -rt2 TE-IS 25 rt1 - rt1(4) -10.0.255.2/32 IP TE 35 rt1 - rt2(4) -rt3 TE-IS 40 rt3 - rt5(4) - rt1 - rt1(4) -10.0.255.3/32 IP TE 50 rt3 - rt3(4) - rt1 - + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------ + rt5 + 10.0.255.5/32 IP internal 0 rt5(4) + rt1 TE-IS 10 rt1 - rt5(4) + rt4 TE-IS 10 rt4 - rt5(4) + rt6 TE-IS 10 rt6 - rt5(4) + rt1 pseudo_TE-IS 20 rt1 - rt1(4) + rt4 - rt4(4) + 10.0.255.1/32 IP TE 20 rt1 - rt1(4) + 10.0.255.4/32 IP TE 20 rt4 - rt4(4) + 10.0.255.6/32 IP TE 20 rt6 - rt6(4) + rt2 TE-IS 25 rt1 - rt1(4) + 10.0.255.2/32 IP TE 35 rt1 - rt2(4) + rt3 TE-IS 40 rt3 - rt5(4) + rt1 - rt1(4) + 10.0.255.3/32 IP TE 50 rt3 - rt3(4) + rt1 - rt3(4) + Main: IS-IS L1 IPv4 routing table: @@ -2041,39 +2155,43 @@ Q-space: rt6 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt5 -2001:db8::5/128 IP6 internal 0 rt5(4) -rt6 TE-IS 10 rt6 - rt5(4) -rt4 TE-IS 20 rt6 - rt6(4) -2001:db8::6/128 IP6 internal 20 rt6 - rt6(4) -rt1 pseudo_TE-IS 30 rt6 - rt4(4) -rt1 TE-IS 30 rt6 - rt1(2) -2001:db8::4/128 IP6 internal 30 rt6 - rt4(4) -rt3 TE-IS 40 rt3 - rt5(4) -2001:db8::1/128 IP6 internal 40 rt6 - rt1(4) -rt2 TE-IS 45 rt6 - rt1(4) -2001:db8::3/128 IP6 internal 50 rt3 - rt3(4) -2001:db8::2/128 IP6 internal 55 rt6 - rt2(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt5 + 2001:db8::5/128 IP6 internal 0 rt5(4) + rt6 TE-IS 10 rt6 - rt5(4) + rt4 TE-IS 20 rt6 - rt6(4) + 2001:db8::6/128 IP6 internal 20 rt6 - rt6(4) + rt1 pseudo_TE-IS 30 rt6 - rt4(4) + rt1 TE-IS 30 rt6 - rt1(2) + 2001:db8::4/128 IP6 internal 30 rt6 - rt4(4) + rt3 TE-IS 40 rt3 - rt5(4) + 2001:db8::1/128 IP6 internal 40 rt6 - rt1(4) + rt2 TE-IS 45 rt6 - rt1(4) + 2001:db8::3/128 IP6 internal 50 rt3 - rt3(4) + 2001:db8::2/128 IP6 internal 55 rt6 - rt2(4) + IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt5 -2001:db8::5/128 IP6 internal 0 rt5(4) -rt1 TE-IS 10 rt1 - rt5(4) -rt4 TE-IS 10 rt4 - rt5(4) -rt6 TE-IS 10 rt6 - rt5(4) -rt1 pseudo_TE-IS 20 rt1 - rt1(4) - rt4 - rt4(4) -2001:db8::1/128 IP6 internal 20 rt1 - rt1(4) -2001:db8::4/128 IP6 internal 20 rt4 - rt4(4) -2001:db8::6/128 IP6 internal 20 rt6 - rt6(4) -rt2 TE-IS 25 rt1 - rt1(4) -2001:db8::2/128 IP6 internal 35 rt1 - rt2(4) -rt3 TE-IS 40 rt3 - rt5(4) - rt1 - rt1(4) -2001:db8::3/128 IP6 internal 50 rt3 - rt3(4) - rt1 - + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt5 + 2001:db8::5/128 IP6 internal 0 rt5(4) + rt1 TE-IS 10 rt1 - rt5(4) + rt4 TE-IS 10 rt4 - rt5(4) + rt6 TE-IS 10 rt6 - rt5(4) + rt1 pseudo_TE-IS 20 rt1 - rt1(4) + rt4 - rt4(4) + 2001:db8::1/128 IP6 internal 20 rt1 - rt1(4) + 2001:db8::4/128 IP6 internal 20 rt4 - rt4(4) + 2001:db8::6/128 IP6 internal 20 rt6 - rt6(4) + rt2 TE-IS 25 rt1 - rt1(4) + 2001:db8::2/128 IP6 internal 35 rt1 - rt2(4) + rt3 TE-IS 40 rt3 - rt5(4) + rt1 - rt1(4) + 2001:db8::3/128 IP6 internal 50 rt3 - rt3(4) + rt1 - rt3(4) + Main: IS-IS L1 IPv6 routing table: @@ -2123,38 +2241,42 @@ Q-space: rt6 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt5 -10.0.255.5/32 IP internal 0 rt5(4) -rt6 TE-IS 10 rt6 - rt5(4) -rt4 TE-IS 20 rt6 - rt6(4) -10.0.255.6/32 IP TE 20 rt6 - rt6(4) -rt3 TE-IS 30 rt3 - rt5(4) -rt2 TE-IS 30 rt6 - rt4(4) -10.0.255.4/32 IP TE 30 rt6 - rt4(4) -rt1 TE-IS 40 rt3 - rt3(4) - rt6 - rt2(4) -10.0.255.3/32 IP TE 40 rt3 - rt3(4) -10.0.255.2/32 IP TE 40 rt6 - rt2(4) -10.0.255.1/32 IP TE 50 rt3 - rt1(4) - rt6 - + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt5 + 10.0.255.5/32 IP internal 0 rt5(4) + rt6 TE-IS 10 rt6 - rt5(4) + rt4 TE-IS 20 rt6 - rt6(4) + 10.0.255.6/32 IP TE 20 rt6 - rt6(4) + rt3 TE-IS 30 rt3 - rt5(4) + rt2 TE-IS 30 rt6 - rt4(4) + 10.0.255.4/32 IP TE 30 rt6 - rt4(4) + rt1 TE-IS 40 rt3 - rt3(4) + rt6 - rt2(4) + 10.0.255.3/32 IP TE 40 rt3 - rt3(4) + 10.0.255.2/32 IP TE 40 rt6 - rt2(4) + 10.0.255.1/32 IP TE 50 rt3 - rt1(4) + rt6 - rt1(4) + IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt5 -10.0.255.5/32 IP internal 0 rt5(4) -rt4 TE-IS 10 rt4 - rt5(4) -rt6 TE-IS 10 rt6 - rt5(4) -rt2 TE-IS 20 rt4 - rt4(4) -10.0.255.4/32 IP TE 20 rt4 - rt4(4) -10.0.255.6/32 IP TE 20 rt6 - rt6(4) -rt3 TE-IS 30 rt3 - rt5(4) - rt4 - rt2(4) -rt1 TE-IS 30 rt4 - rt2(4) -10.0.255.2/32 IP TE 30 rt4 - rt2(4) -10.0.255.3/32 IP TE 40 rt3 - rt3(4) - rt4 - -10.0.255.1/32 IP TE 40 rt4 - rt1(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt5 + 10.0.255.5/32 IP internal 0 rt5(4) + rt4 TE-IS 10 rt4 - rt5(4) + rt6 TE-IS 10 rt6 - rt5(4) + rt2 TE-IS 20 rt4 - rt4(4) + 10.0.255.4/32 IP TE 20 rt4 - rt4(4) + 10.0.255.6/32 IP TE 20 rt6 - rt6(4) + rt3 TE-IS 30 rt3 - rt5(4) + rt4 - rt2(4) + rt1 TE-IS 30 rt4 - rt2(4) + 10.0.255.2/32 IP TE 30 rt4 - rt2(4) + 10.0.255.3/32 IP TE 40 rt3 - rt3(4) + rt4 - rt3(4) + 10.0.255.1/32 IP TE 40 rt4 - rt1(4) + Main: IS-IS L1 IPv4 routing table: @@ -2210,36 +2332,40 @@ Q-space: rt6 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt5 -10.0.255.5/32 IP internal 0 rt5(4) -rt4 TE-IS 10 rt4 - rt5(4) -rt6 TE-IS 10 rt6 - rt5(4) -rt2 TE-IS 20 rt4 - rt4(4) -10.0.255.4/32 IP TE 20 rt4 - rt4(4) -10.0.255.6/32 IP TE 20 rt6 - rt6(4) -rt1 TE-IS 30 rt4 - rt2(4) -rt3 TE-IS 30 rt4 - rt2(4) -10.0.255.2/32 IP TE 30 rt4 - rt2(4) -10.0.255.1/32 IP TE 40 rt4 - rt1(4) -10.0.255.3/32 IP TE 40 rt4 - rt3(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt5 + 10.0.255.5/32 IP internal 0 rt5(4) + rt4 TE-IS 10 rt4 - rt5(4) + rt6 TE-IS 10 rt6 - rt5(4) + rt2 TE-IS 20 rt4 - rt4(4) + 10.0.255.4/32 IP TE 20 rt4 - rt4(4) + 10.0.255.6/32 IP TE 20 rt6 - rt6(4) + rt1 TE-IS 30 rt4 - rt2(4) + rt3 TE-IS 30 rt4 - rt2(4) + 10.0.255.2/32 IP TE 30 rt4 - rt2(4) + 10.0.255.1/32 IP TE 40 rt4 - rt1(4) + 10.0.255.3/32 IP TE 40 rt4 - rt3(4) + IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt5 -10.0.255.5/32 IP internal 0 rt5(4) -rt4 TE-IS 10 rt4 - rt5(4) -rt6 TE-IS 10 rt6 - rt5(4) -rt2 TE-IS 20 rt4 - rt4(4) -10.0.255.4/32 IP TE 20 rt4 - rt4(4) -10.0.255.6/32 IP TE 20 rt6 - rt6(4) -rt3 TE-IS 30 rt3 - rt5(4) - rt4 - rt2(4) -rt1 TE-IS 30 rt4 - rt2(4) -10.0.255.2/32 IP TE 30 rt4 - rt2(4) -10.0.255.3/32 IP TE 40 rt3 - rt3(4) - rt4 - -10.0.255.1/32 IP TE 40 rt4 - rt1(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt5 + 10.0.255.5/32 IP internal 0 rt5(4) + rt4 TE-IS 10 rt4 - rt5(4) + rt6 TE-IS 10 rt6 - rt5(4) + rt2 TE-IS 20 rt4 - rt4(4) + 10.0.255.4/32 IP TE 20 rt4 - rt4(4) + 10.0.255.6/32 IP TE 20 rt6 - rt6(4) + rt3 TE-IS 30 rt3 - rt5(4) + rt4 - rt2(4) + rt1 TE-IS 30 rt4 - rt2(4) + 10.0.255.2/32 IP TE 30 rt4 - rt2(4) + 10.0.255.3/32 IP TE 40 rt3 - rt3(4) + rt4 - rt3(4) + 10.0.255.1/32 IP TE 40 rt4 - rt1(4) + Main: IS-IS L1 IPv4 routing table: @@ -2276,44 +2402,48 @@ Q-space: rt8 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt5 TE-IS 20 rt3 - rt3(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt7 TE-IS 30 rt3 - rt5(4) -10.0.255.5/32 IP TE 30 rt3 - rt5(4) -rt8 TE-IS 40 rt3 - rt7(4) -10.0.255.7/32 IP TE 40 rt3 - rt7(4) -rt6 TE-IS 50 rt3 - rt8(4) -10.0.255.8/32 IP TE 50 rt3 - rt8(4) -rt4 TE-IS 60 rt3 - rt6(4) -10.0.255.6/32 IP TE 60 rt3 - rt6(4) -rt2 TE-IS 70 rt3 - rt4(4) -10.0.255.4/32 IP TE 70 rt3 - rt4(4) -10.0.255.2/32 IP TE 80 rt3 - rt2(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt5 TE-IS 20 rt3 - rt3(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt7 TE-IS 30 rt3 - rt5(4) + 10.0.255.5/32 IP TE 30 rt3 - rt5(4) + rt8 TE-IS 40 rt3 - rt7(4) + 10.0.255.7/32 IP TE 40 rt3 - rt7(4) + rt6 TE-IS 50 rt3 - rt8(4) + 10.0.255.8/32 IP TE 50 rt3 - rt8(4) + rt4 TE-IS 60 rt3 - rt6(4) + 10.0.255.6/32 IP TE 60 rt3 - rt6(4) + rt2 TE-IS 70 rt3 - rt4(4) + 10.0.255.4/32 IP TE 70 rt3 - rt4(4) + 10.0.255.2/32 IP TE 80 rt3 - rt2(4) + IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) -rt5 TE-IS 20 rt3 - rt3(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt6 TE-IS 30 rt2 - rt4(4) -rt7 TE-IS 30 rt3 - rt5(4) -10.0.255.4/32 IP TE 30 rt2 - rt4(4) -10.0.255.5/32 IP TE 30 rt3 - rt5(4) -rt8 TE-IS 40 rt2 - rt6(4) - rt3 - rt7(4) -10.0.255.6/32 IP TE 40 rt2 - rt6(4) -10.0.255.7/32 IP TE 40 rt3 - rt7(4) -10.0.255.8/32 IP TE 50 rt2 - rt8(4) - rt3 - + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + rt5 TE-IS 20 rt3 - rt3(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt6 TE-IS 30 rt2 - rt4(4) + rt7 TE-IS 30 rt3 - rt5(4) + 10.0.255.4/32 IP TE 30 rt2 - rt4(4) + 10.0.255.5/32 IP TE 30 rt3 - rt5(4) + rt8 TE-IS 40 rt2 - rt6(4) + rt3 - rt7(4) + 10.0.255.6/32 IP TE 40 rt2 - rt6(4) + 10.0.255.7/32 IP TE 40 rt3 - rt7(4) + 10.0.255.8/32 IP TE 50 rt2 - rt8(4) + rt3 - rt8(4) + Main: IS-IS L1 IPv4 routing table: @@ -2362,46 +2492,50 @@ Q-space: rt3 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt4 -10.0.255.4/32 IP internal 0 rt4(4) -rt2 TE-IS 10 rt2 - rt4(4) -rt6 TE-IS 10 rt6 - rt4(4) -rt1 TE-IS 20 rt2 - rt2(4) -rt5 TE-IS 20 rt6 - rt6(4) -rt8 TE-IS 20 rt6 - rt6(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.6/32 IP TE 20 rt6 - rt6(4) -rt3 TE-IS 30 rt2 - rt1(4) -rt7 TE-IS 30 rt6 - rt5(4) - rt8(4) -10.0.255.1/32 IP TE 30 rt2 - rt1(4) -10.0.255.5/32 IP TE 30 rt6 - rt5(4) -10.0.255.8/32 IP TE 30 rt6 - rt8(4) -10.0.255.3/32 IP TE 40 rt2 - rt3(4) -10.0.255.7/32 IP TE 40 rt6 - rt7(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt4 + 10.0.255.4/32 IP internal 0 rt4(4) + rt2 TE-IS 10 rt2 - rt4(4) + rt6 TE-IS 10 rt6 - rt4(4) + rt1 TE-IS 20 rt2 - rt2(4) + rt5 TE-IS 20 rt6 - rt6(4) + rt8 TE-IS 20 rt6 - rt6(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.6/32 IP TE 20 rt6 - rt6(4) + rt3 TE-IS 30 rt2 - rt1(4) + rt7 TE-IS 30 rt6 - rt5(4) + rt8(4) + 10.0.255.1/32 IP TE 30 rt2 - rt1(4) + 10.0.255.5/32 IP TE 30 rt6 - rt5(4) + 10.0.255.8/32 IP TE 30 rt6 - rt8(4) + 10.0.255.3/32 IP TE 40 rt2 - rt3(4) + 10.0.255.7/32 IP TE 40 rt6 - rt7(4) + IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt4 -10.0.255.4/32 IP internal 0 rt4(4) -rt2 TE-IS 10 rt2 - rt4(4) -rt3 TE-IS 10 rt3 - rt4(4) -rt6 TE-IS 10 rt6 - rt4(4) -rt1 TE-IS 20 rt2 - rt2(4) - rt3 - rt3(4) -rt5 TE-IS 20 rt6 - rt6(4) -rt8 TE-IS 20 rt6 - rt6(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -10.0.255.6/32 IP TE 20 rt6 - rt6(4) -rt7 TE-IS 30 rt6 - rt5(4) - rt8(4) -10.0.255.1/32 IP TE 30 rt2 - rt1(4) - rt3 - -10.0.255.5/32 IP TE 30 rt6 - rt5(4) -10.0.255.8/32 IP TE 30 rt6 - rt8(4) -10.0.255.7/32 IP TE 40 rt6 - rt7(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt4 + 10.0.255.4/32 IP internal 0 rt4(4) + rt2 TE-IS 10 rt2 - rt4(4) + rt3 TE-IS 10 rt3 - rt4(4) + rt6 TE-IS 10 rt6 - rt4(4) + rt1 TE-IS 20 rt2 - rt2(4) + rt3 - rt3(4) + rt5 TE-IS 20 rt6 - rt6(4) + rt8 TE-IS 20 rt6 - rt6(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + 10.0.255.6/32 IP TE 20 rt6 - rt6(4) + rt7 TE-IS 30 rt6 - rt5(4) + rt8(4) + 10.0.255.1/32 IP TE 30 rt2 - rt1(4) + rt3 - rt1(4) + 10.0.255.5/32 IP TE 30 rt6 - rt5(4) + 10.0.255.8/32 IP TE 30 rt6 - rt8(4) + 10.0.255.7/32 IP TE 40 rt6 - rt7(4) + Main: IS-IS L1 IPv4 routing table: @@ -2452,64 +2586,68 @@ Q-space: rt9 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt11 -10.0.255.11/32 IP internal 0 rt11(4) -rt10 TE-IS 10 rt10 - rt11(4) -rt12 TE-IS 10 rt12 - rt11(4) -rt9 TE-IS 20 rt12 - rt12(4) -10.0.255.10/32 IP TE 20 rt10 - rt10(4) -10.0.255.12/32 IP TE 20 rt12 - rt12(4) -rt7 TE-IS 30 rt10 - rt10(4) -rt8 TE-IS 30 rt12 - rt9(4) -10.0.255.9/32 IP TE 30 rt12 - rt9(4) -rt4 TE-IS 40 rt10 - rt7(4) -rt5 TE-IS 40 rt12 - rt8(4) -10.0.255.7/32 IP TE 40 rt10 - rt7(4) -10.0.255.8/32 IP TE 40 rt12 - rt8(4) -rt6 TE-IS 50 rt12 - rt9(4) - rt5(4) -rt1 TE-IS 50 rt10 - rt4(4) -rt2 TE-IS 50 rt12 - rt5(4) -10.0.255.4/32 IP TE 50 rt10 - rt4(4) -10.0.255.5/32 IP TE 50 rt12 - rt5(4) -rt3 TE-IS 60 rt12 - rt6(4) - rt2(4) -10.0.255.6/32 IP TE 60 rt12 - rt6(4) -10.0.255.1/32 IP TE 60 rt10 - rt1(4) -10.0.255.2/32 IP TE 60 rt12 - rt2(4) -10.0.255.3/32 IP TE 70 rt12 - rt3(4) + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------- + rt11 + 10.0.255.11/32 IP internal 0 rt11(4) + rt10 TE-IS 10 rt10 - rt11(4) + rt12 TE-IS 10 rt12 - rt11(4) + rt9 TE-IS 20 rt12 - rt12(4) + 10.0.255.10/32 IP TE 20 rt10 - rt10(4) + 10.0.255.12/32 IP TE 20 rt12 - rt12(4) + rt7 TE-IS 30 rt10 - rt10(4) + rt8 TE-IS 30 rt12 - rt9(4) + 10.0.255.9/32 IP TE 30 rt12 - rt9(4) + rt4 TE-IS 40 rt10 - rt7(4) + rt5 TE-IS 40 rt12 - rt8(4) + 10.0.255.7/32 IP TE 40 rt10 - rt7(4) + 10.0.255.8/32 IP TE 40 rt12 - rt8(4) + rt6 TE-IS 50 rt12 - rt9(4) + rt5(4) + rt1 TE-IS 50 rt10 - rt4(4) + rt2 TE-IS 50 rt12 - rt5(4) + 10.0.255.4/32 IP TE 50 rt10 - rt4(4) + 10.0.255.5/32 IP TE 50 rt12 - rt5(4) + rt3 TE-IS 60 rt12 - rt6(4) + rt2(4) + 10.0.255.6/32 IP TE 60 rt12 - rt6(4) + 10.0.255.1/32 IP TE 60 rt10 - rt1(4) + 10.0.255.2/32 IP TE 60 rt12 - rt2(4) + 10.0.255.3/32 IP TE 70 rt12 - rt3(4) + IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt11 -10.0.255.11/32 IP internal 0 rt11(4) -rt8 TE-IS 10 rt8 - rt11(4) -rt10 TE-IS 10 rt10 - rt11(4) -rt12 TE-IS 10 rt12 - rt11(4) -rt5 TE-IS 20 rt8 - rt8(4) -rt7 TE-IS 20 rt8 - rt8(4) -rt9 TE-IS 20 rt8 - rt8(4) - rt12 - rt12(4) -10.0.255.8/32 IP TE 20 rt8 - rt8(4) -10.0.255.10/32 IP TE 20 rt10 - rt10(4) -10.0.255.12/32 IP TE 20 rt12 - rt12(4) -rt2 TE-IS 30 rt8 - rt5(4) -rt4 TE-IS 30 rt8 - rt5(4) - rt7(4) -rt6 TE-IS 30 rt8 - rt5(4) -10.0.255.5/32 IP TE 30 rt8 - rt5(4) -10.0.255.7/32 IP TE 30 rt8 - rt7(4) -10.0.255.9/32 IP TE 30 rt8 - rt9(4) - rt12 - -rt3 TE-IS 40 rt8 - rt2(4) - rt6(4) -rt1 TE-IS 40 rt8 - rt4(4) -10.0.255.2/32 IP TE 40 rt8 - rt2(4) -10.0.255.4/32 IP TE 40 rt8 - rt4(4) -10.0.255.6/32 IP TE 40 rt8 - rt6(4) -10.0.255.3/32 IP TE 50 rt8 - rt3(4) -10.0.255.1/32 IP TE 50 rt8 - rt1(4) + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------- + rt11 + 10.0.255.11/32 IP internal 0 rt11(4) + rt8 TE-IS 10 rt8 - rt11(4) + rt10 TE-IS 10 rt10 - rt11(4) + rt12 TE-IS 10 rt12 - rt11(4) + rt5 TE-IS 20 rt8 - rt8(4) + rt7 TE-IS 20 rt8 - rt8(4) + rt9 TE-IS 20 rt8 - rt8(4) + rt12 - rt12(4) + 10.0.255.8/32 IP TE 20 rt8 - rt8(4) + 10.0.255.10/32 IP TE 20 rt10 - rt10(4) + 10.0.255.12/32 IP TE 20 rt12 - rt12(4) + rt2 TE-IS 30 rt8 - rt5(4) + rt4 TE-IS 30 rt8 - rt5(4) + rt7(4) + rt6 TE-IS 30 rt8 - rt5(4) + 10.0.255.5/32 IP TE 30 rt8 - rt5(4) + 10.0.255.7/32 IP TE 30 rt8 - rt7(4) + 10.0.255.9/32 IP TE 30 rt8 - rt9(4) + rt12 - rt9(4) + rt3 TE-IS 40 rt8 - rt2(4) + rt6(4) + rt1 TE-IS 40 rt8 - rt4(4) + 10.0.255.2/32 IP TE 40 rt8 - rt2(4) + 10.0.255.4/32 IP TE 40 rt8 - rt4(4) + 10.0.255.6/32 IP TE 40 rt8 - rt6(4) + 10.0.255.3/32 IP TE 50 rt8 - rt3(4) + 10.0.255.1/32 IP TE 50 rt8 - rt1(4) + Main: IS-IS L1 IPv4 routing table: @@ -2577,73 +2715,77 @@ Q-space: rt12 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt6 -10.0.255.6/32 IP internal 0 rt6(4) -rt3 TE-IS 10 rt3 - rt6(4) -rt2 TE-IS 20 rt3 - rt3(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt9 TE-IS 30 rt9 - rt6(4) -rt5 TE-IS 30 rt3 - rt2(4) -10.0.255.2/32 IP TE 30 rt3 - rt2(4) -rt8 TE-IS 40 rt9 - rt9(4) - rt3 - rt5(4) -rt12 TE-IS 40 rt9 - rt9(4) -rt4 TE-IS 40 rt3 - rt5(4) -10.0.255.9/32 IP TE 40 rt9 - rt9(4) -10.0.255.5/32 IP TE 40 rt3 - rt5(4) -rt7 TE-IS 50 rt9 - rt8(4) - rt3 - rt4(4) -rt11 TE-IS 50 rt9 - rt8(4) - rt3 - rt12(4) -rt1 TE-IS 50 rt3 - rt4(4) -10.0.255.8/32 IP TE 50 rt9 - rt8(4) - rt3 - -10.0.255.12/32 IP TE 50 rt9 - rt12(4) -10.0.255.4/32 IP TE 50 rt3 - rt4(4) -rt10 TE-IS 60 rt9 - rt11(4) - rt3 - -10.0.255.7/32 IP TE 60 rt9 - rt7(4) - rt3 - -10.0.255.11/32 IP TE 60 rt9 - rt11(4) - rt3 - -10.0.255.1/32 IP TE 60 rt3 - rt1(4) -10.0.255.10/32 IP TE 70 rt9 - rt10(4) - rt3 - + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------- + rt6 + 10.0.255.6/32 IP internal 0 rt6(4) + rt3 TE-IS 10 rt3 - rt6(4) + rt2 TE-IS 20 rt3 - rt3(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt9 TE-IS 30 rt9 - rt6(4) + rt5 TE-IS 30 rt3 - rt2(4) + 10.0.255.2/32 IP TE 30 rt3 - rt2(4) + rt8 TE-IS 40 rt9 - rt9(4) + rt3 - rt5(4) + rt12 TE-IS 40 rt9 - rt9(4) + rt4 TE-IS 40 rt3 - rt5(4) + 10.0.255.9/32 IP TE 40 rt9 - rt9(4) + 10.0.255.5/32 IP TE 40 rt3 - rt5(4) + rt7 TE-IS 50 rt9 - rt8(4) + rt3 - rt4(4) + rt11 TE-IS 50 rt9 - rt8(4) + rt3 - rt12(4) + rt1 TE-IS 50 rt3 - rt4(4) + 10.0.255.8/32 IP TE 50 rt9 - rt8(4) + rt3 - rt8(4) + 10.0.255.12/32 IP TE 50 rt9 - rt12(4) + 10.0.255.4/32 IP TE 50 rt3 - rt4(4) + rt10 TE-IS 60 rt9 - rt11(4) + rt3 - rt11(4) + 10.0.255.7/32 IP TE 60 rt9 - rt7(4) + rt3 - rt7(4) + 10.0.255.11/32 IP TE 60 rt9 - rt11(4) + rt3 - rt11(4) + 10.0.255.1/32 IP TE 60 rt3 - rt1(4) + 10.0.255.10/32 IP TE 70 rt9 - rt10(4) + rt3 - rt10(4) + IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt6 -10.0.255.6/32 IP internal 0 rt6(4) -rt3 TE-IS 10 rt3 - rt6(4) -rt5 TE-IS 10 rt5 - rt6(4) -rt2 TE-IS 20 rt3 - rt3(4) - rt5 - rt5(4) -rt4 TE-IS 20 rt5 - rt5(4) -rt8 TE-IS 20 rt5 - rt5(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -10.0.255.5/32 IP TE 20 rt5 - rt5(4) -rt9 TE-IS 30 rt9 - rt6(4) - rt5 - rt8(4) -rt1 TE-IS 30 rt5 - rt4(4) -rt7 TE-IS 30 rt5 - rt4(4) - rt8(4) -rt11 TE-IS 30 rt5 - rt8(4) -10.0.255.2/32 IP TE 30 rt3 - rt2(4) - rt5 - -10.0.255.4/32 IP TE 30 rt5 - rt4(4) -10.0.255.8/32 IP TE 30 rt5 - rt8(4) -rt12 TE-IS 40 rt9 - rt9(4) - rt5 - rt11(4) -rt10 TE-IS 40 rt5 - rt11(4) -10.0.255.9/32 IP TE 40 rt9 - rt9(4) - rt5 - -10.0.255.1/32 IP TE 40 rt5 - rt1(4) -10.0.255.7/32 IP TE 40 rt5 - rt7(4) -10.0.255.11/32 IP TE 40 rt5 - rt11(4) -10.0.255.12/32 IP TE 50 rt9 - rt12(4) - rt5 - -10.0.255.10/32 IP TE 50 rt5 - rt10(4) + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------- + rt6 + 10.0.255.6/32 IP internal 0 rt6(4) + rt3 TE-IS 10 rt3 - rt6(4) + rt5 TE-IS 10 rt5 - rt6(4) + rt2 TE-IS 20 rt3 - rt3(4) + rt5 - rt5(4) + rt4 TE-IS 20 rt5 - rt5(4) + rt8 TE-IS 20 rt5 - rt5(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + 10.0.255.5/32 IP TE 20 rt5 - rt5(4) + rt9 TE-IS 30 rt9 - rt6(4) + rt5 - rt8(4) + rt1 TE-IS 30 rt5 - rt4(4) + rt7 TE-IS 30 rt5 - rt4(4) + rt8(4) + rt11 TE-IS 30 rt5 - rt8(4) + 10.0.255.2/32 IP TE 30 rt3 - rt2(4) + rt5 - rt2(4) + 10.0.255.4/32 IP TE 30 rt5 - rt4(4) + 10.0.255.8/32 IP TE 30 rt5 - rt8(4) + rt12 TE-IS 40 rt9 - rt9(4) + rt5 - rt11(4) + rt10 TE-IS 40 rt5 - rt11(4) + 10.0.255.9/32 IP TE 40 rt9 - rt9(4) + rt5 - rt9(4) + 10.0.255.1/32 IP TE 40 rt5 - rt1(4) + 10.0.255.7/32 IP TE 40 rt5 - rt7(4) + 10.0.255.11/32 IP TE 40 rt5 - rt11(4) + 10.0.255.12/32 IP TE 50 rt9 - rt12(4) + rt5 - rt12(4) + 10.0.255.10/32 IP TE 50 rt5 - rt10(4) + Main: IS-IS L1 IPv4 routing table: @@ -2706,62 +2848,66 @@ Q-space: rt12 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt2 -10.0.255.2/32 IP internal 0 rt2(4) -rt1 TE-IS 10 rt1 - rt2(4) -rt3 TE-IS 10 rt3 - rt2(4) -rt4 TE-IS 20 rt1 - rt1(4) -rt6 TE-IS 20 rt3 - rt3(4) -10.0.255.1/32 IP TE 20 rt1 - rt1(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt7 TE-IS 30 rt1 - rt4(4) -rt5 TE-IS 30 rt3 - rt6(4) -10.0.255.4/32 IP TE 30 rt1 - rt4(4) -10.0.255.6/32 IP TE 30 rt3 - rt6(4) -rt10 TE-IS 40 rt1 - rt7(4) -rt8 TE-IS 40 rt3 - rt5(4) -10.0.255.7/32 IP TE 40 rt1 - rt7(4) -10.0.255.5/32 IP TE 40 rt3 - rt5(4) -rt9 TE-IS 50 rt3 - rt8(4) -rt11 TE-IS 50 rt3 - rt8(4) -10.0.255.10/32 IP TE 50 rt1 - rt10(4) -10.0.255.8/32 IP TE 50 rt3 - rt8(4) -rt12 TE-IS 60 rt3 - rt9(4) - rt11(4) -10.0.255.9/32 IP TE 60 rt3 - rt9(4) -10.0.255.11/32 IP TE 60 rt3 - rt11(4) -10.0.255.12/32 IP TE 70 rt3 - rt12(4) + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------- + rt2 + 10.0.255.2/32 IP internal 0 rt2(4) + rt1 TE-IS 10 rt1 - rt2(4) + rt3 TE-IS 10 rt3 - rt2(4) + rt4 TE-IS 20 rt1 - rt1(4) + rt6 TE-IS 20 rt3 - rt3(4) + 10.0.255.1/32 IP TE 20 rt1 - rt1(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt7 TE-IS 30 rt1 - rt4(4) + rt5 TE-IS 30 rt3 - rt6(4) + 10.0.255.4/32 IP TE 30 rt1 - rt4(4) + 10.0.255.6/32 IP TE 30 rt3 - rt6(4) + rt10 TE-IS 40 rt1 - rt7(4) + rt8 TE-IS 40 rt3 - rt5(4) + 10.0.255.7/32 IP TE 40 rt1 - rt7(4) + 10.0.255.5/32 IP TE 40 rt3 - rt5(4) + rt9 TE-IS 50 rt3 - rt8(4) + rt11 TE-IS 50 rt3 - rt8(4) + 10.0.255.10/32 IP TE 50 rt1 - rt10(4) + 10.0.255.8/32 IP TE 50 rt3 - rt8(4) + rt12 TE-IS 60 rt3 - rt9(4) + rt11(4) + 10.0.255.9/32 IP TE 60 rt3 - rt9(4) + 10.0.255.11/32 IP TE 60 rt3 - rt11(4) + 10.0.255.12/32 IP TE 70 rt3 - rt12(4) + IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt2 -10.0.255.2/32 IP internal 0 rt2(4) -rt1 TE-IS 10 rt1 - rt2(4) -rt3 TE-IS 10 rt3 - rt2(4) -rt5 TE-IS 10 rt5 - rt2(4) -rt4 TE-IS 20 rt1 - rt1(4) -rt6 TE-IS 20 rt3 - rt3(4) - rt5 - rt5(4) -rt8 TE-IS 20 rt5 - rt5(4) -10.0.255.1/32 IP TE 20 rt1 - rt1(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -10.0.255.5/32 IP TE 20 rt5 - rt5(4) -rt7 TE-IS 30 rt1 - rt4(4) -rt9 TE-IS 30 rt5 - rt8(4) -rt11 TE-IS 30 rt5 - rt8(4) -10.0.255.4/32 IP TE 30 rt1 - rt4(4) -10.0.255.6/32 IP TE 30 rt3 - rt6(4) - rt5 - -10.0.255.8/32 IP TE 30 rt5 - rt8(4) -rt10 TE-IS 40 rt1 - rt7(4) -rt12 TE-IS 40 rt5 - rt9(4) - rt11(4) -10.0.255.7/32 IP TE 40 rt1 - rt7(4) -10.0.255.9/32 IP TE 40 rt5 - rt9(4) -10.0.255.11/32 IP TE 40 rt5 - rt11(4) -10.0.255.10/32 IP TE 50 rt1 - rt10(4) -10.0.255.12/32 IP TE 50 rt5 - rt12(4) + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------- + rt2 + 10.0.255.2/32 IP internal 0 rt2(4) + rt1 TE-IS 10 rt1 - rt2(4) + rt3 TE-IS 10 rt3 - rt2(4) + rt5 TE-IS 10 rt5 - rt2(4) + rt4 TE-IS 20 rt1 - rt1(4) + rt6 TE-IS 20 rt3 - rt3(4) + rt5 - rt5(4) + rt8 TE-IS 20 rt5 - rt5(4) + 10.0.255.1/32 IP TE 20 rt1 - rt1(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + 10.0.255.5/32 IP TE 20 rt5 - rt5(4) + rt7 TE-IS 30 rt1 - rt4(4) + rt9 TE-IS 30 rt5 - rt8(4) + rt11 TE-IS 30 rt5 - rt8(4) + 10.0.255.4/32 IP TE 30 rt1 - rt4(4) + 10.0.255.6/32 IP TE 30 rt3 - rt6(4) + rt5 - rt6(4) + 10.0.255.8/32 IP TE 30 rt5 - rt8(4) + rt10 TE-IS 40 rt1 - rt7(4) + rt12 TE-IS 40 rt5 - rt9(4) + rt11(4) + 10.0.255.7/32 IP TE 40 rt1 - rt7(4) + 10.0.255.9/32 IP TE 40 rt5 - rt9(4) + 10.0.255.11/32 IP TE 40 rt5 - rt11(4) + 10.0.255.10/32 IP TE 50 rt1 - rt10(4) + 10.0.255.12/32 IP TE 50 rt5 - rt12(4) + Main: IS-IS L1 IPv4 routing table: @@ -2815,36 +2961,40 @@ Q-space: rt6 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt2 -10.0.255.2/32 IP internal 0 rt2(4) -rt1 TE-IS 50 rt1 - rt2(4) -rt3 TE-IS 50 rt3 - rt2(4) -rt2 -rt5 TE-IS 60 rt3 - rt3(4) -10.0.255.1/32 IP TE 60 rt1 - rt1(4) -10.0.255.3/32 IP TE 60 rt3 - rt3(4) -rt4 TE-IS 70 rt3 - rt5(4) -rt6 TE-IS 70 rt3 - rt5(4) -10.0.255.5/32 IP TE 70 rt3 - rt5(4) -10.0.255.4/32 IP TE 80 rt3 - rt4(4) -10.0.255.6/32 IP TE 80 rt3 - rt6(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt2 + 10.0.255.2/32 IP internal 0 rt2(4) + rt1 TE-IS 50 rt1 - rt2(4) + rt3 TE-IS 50 rt3 - rt2(4) + rt2 + rt5 TE-IS 60 rt3 - rt3(4) + 10.0.255.1/32 IP TE 60 rt1 - rt1(4) + 10.0.255.3/32 IP TE 60 rt3 - rt3(4) + rt4 TE-IS 70 rt3 - rt5(4) + rt6 TE-IS 70 rt3 - rt5(4) + 10.0.255.5/32 IP TE 70 rt3 - rt5(4) + 10.0.255.4/32 IP TE 80 rt3 - rt4(4) + 10.0.255.6/32 IP TE 80 rt3 - rt6(4) + IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt2 -10.0.255.2/32 IP internal 0 rt2(4) -rt4 TE-IS 10 rt4 - rt2(4) -rt5 TE-IS 20 rt4 - rt4(4) -rt6 TE-IS 20 rt4 - rt4(4) -10.0.255.4/32 IP TE 20 rt4 - rt4(4) -rt3 TE-IS 30 rt4 - rt5(4) -10.0.255.5/32 IP TE 30 rt4 - rt5(4) -10.0.255.6/32 IP TE 30 rt4 - rt6(4) -rt2 -rt1 TE-IS 40 rt4 - rt2(2) -10.0.255.3/32 IP TE 40 rt4 - rt3(4) -10.0.255.1/32 IP TE 50 rt4 - rt1(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt2 + 10.0.255.2/32 IP internal 0 rt2(4) + rt4 TE-IS 10 rt4 - rt2(4) + rt5 TE-IS 20 rt4 - rt4(4) + rt6 TE-IS 20 rt4 - rt4(4) + 10.0.255.4/32 IP TE 20 rt4 - rt4(4) + rt3 TE-IS 30 rt4 - rt5(4) + 10.0.255.5/32 IP TE 30 rt4 - rt5(4) + 10.0.255.6/32 IP TE 30 rt4 - rt6(4) + rt2 + rt1 TE-IS 40 rt4 - rt2(2) + 10.0.255.3/32 IP TE 40 rt4 - rt3(4) + 10.0.255.1/32 IP TE 50 rt4 - rt1(4) + Main: IS-IS L1 IPv4 routing table: @@ -2893,36 +3043,40 @@ Q-space: rt6 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt2 -2001:db8::2/128 IP6 internal 0 rt2(4) -rt1 TE-IS 50 rt1 - rt2(4) -rt3 TE-IS 50 rt3 - rt2(4) -rt2 -rt5 TE-IS 60 rt3 - rt3(4) -2001:db8::1/128 IP6 internal 60 rt1 - rt1(4) -2001:db8::3/128 IP6 internal 60 rt3 - rt3(4) -rt4 TE-IS 70 rt3 - rt5(4) -rt6 TE-IS 70 rt3 - rt5(4) -2001:db8::5/128 IP6 internal 70 rt3 - rt5(4) -2001:db8::4/128 IP6 internal 80 rt3 - rt4(4) -2001:db8::6/128 IP6 internal 80 rt3 - rt6(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt2 + 2001:db8::2/128 IP6 internal 0 rt2(4) + rt1 TE-IS 50 rt1 - rt2(4) + rt3 TE-IS 50 rt3 - rt2(4) + rt2 + rt5 TE-IS 60 rt3 - rt3(4) + 2001:db8::1/128 IP6 internal 60 rt1 - rt1(4) + 2001:db8::3/128 IP6 internal 60 rt3 - rt3(4) + rt4 TE-IS 70 rt3 - rt5(4) + rt6 TE-IS 70 rt3 - rt5(4) + 2001:db8::5/128 IP6 internal 70 rt3 - rt5(4) + 2001:db8::4/128 IP6 internal 80 rt3 - rt4(4) + 2001:db8::6/128 IP6 internal 80 rt3 - rt6(4) + IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt2 -2001:db8::2/128 IP6 internal 0 rt2(4) -rt4 TE-IS 10 rt4 - rt2(4) -rt5 TE-IS 20 rt4 - rt4(4) -rt6 TE-IS 20 rt4 - rt4(4) -2001:db8::4/128 IP6 internal 20 rt4 - rt4(4) -rt3 TE-IS 30 rt4 - rt5(4) -2001:db8::5/128 IP6 internal 30 rt4 - rt5(4) -2001:db8::6/128 IP6 internal 30 rt4 - rt6(4) -rt2 -rt1 TE-IS 40 rt4 - rt2(2) -2001:db8::3/128 IP6 internal 40 rt4 - rt3(4) -2001:db8::1/128 IP6 internal 50 rt4 - rt1(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt2 + 2001:db8::2/128 IP6 internal 0 rt2(4) + rt4 TE-IS 10 rt4 - rt2(4) + rt5 TE-IS 20 rt4 - rt4(4) + rt6 TE-IS 20 rt4 - rt4(4) + 2001:db8::4/128 IP6 internal 20 rt4 - rt4(4) + rt3 TE-IS 30 rt4 - rt5(4) + 2001:db8::5/128 IP6 internal 30 rt4 - rt5(4) + 2001:db8::6/128 IP6 internal 30 rt4 - rt6(4) + rt2 + rt1 TE-IS 40 rt4 - rt2(2) + 2001:db8::3/128 IP6 internal 40 rt4 - rt3(4) + 2001:db8::1/128 IP6 internal 50 rt4 - rt1(4) + Main: IS-IS L1 IPv6 routing table: @@ -2966,42 +3120,46 @@ Q-space: rt7 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -rt3 TE-IS 30 rt2 - rt4(4) -10.0.255.4/32 IP TE 30 rt2 - rt4(4) -rt5 TE-IS 40 rt2 - rt3(4) -rt6 TE-IS 40 rt2 - rt3(4) -10.0.255.3/32 IP TE 40 rt2 - rt3(4) -rt7 TE-IS 50 rt2 - rt5(4) - rt6(4) -10.0.255.5/32 IP TE 50 rt2 - rt5(4) -10.0.255.6/32 IP TE 50 rt2 - rt6(4) -10.0.255.7/32 IP TE 60 rt2 - rt7(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + rt3 TE-IS 30 rt2 - rt4(4) + 10.0.255.4/32 IP TE 30 rt2 - rt4(4) + rt5 TE-IS 40 rt2 - rt3(4) + rt6 TE-IS 40 rt2 - rt3(4) + 10.0.255.3/32 IP TE 40 rt2 - rt3(4) + rt7 TE-IS 50 rt2 - rt5(4) + rt6(4) + 10.0.255.5/32 IP TE 50 rt2 - rt5(4) + 10.0.255.6/32 IP TE 50 rt2 - rt6(4) + 10.0.255.7/32 IP TE 60 rt2 - rt7(4) + IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) - rt3 - rt3(4) -rt5 TE-IS 20 rt3 - rt3(4) -rt6 TE-IS 20 rt3 - rt3(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt7 TE-IS 30 rt3 - rt5(4) - rt6(4) -10.0.255.4/32 IP TE 30 rt2 - rt4(4) - rt3 - -10.0.255.5/32 IP TE 30 rt3 - rt5(4) -10.0.255.6/32 IP TE 30 rt3 - rt6(4) -10.0.255.7/32 IP TE 40 rt3 - rt7(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + rt3 - rt3(4) + rt5 TE-IS 20 rt3 - rt3(4) + rt6 TE-IS 20 rt3 - rt3(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt7 TE-IS 30 rt3 - rt5(4) + rt6(4) + 10.0.255.4/32 IP TE 30 rt2 - rt4(4) + rt3 - rt4(4) + 10.0.255.5/32 IP TE 30 rt3 - rt5(4) + 10.0.255.6/32 IP TE 30 rt3 - rt6(4) + 10.0.255.7/32 IP TE 40 rt3 - rt7(4) + Main: IS-IS L1 IPv4 routing table: @@ -3044,19 +3202,21 @@ Q-space: rt6 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt5 TE-IS 20 rt3 - rt3(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt6 TE-IS 30 rt3 - rt5(4) -10.0.255.5/32 IP TE 30 rt3 - rt5(4) -rt4 TE-IS 40 rt3 - rt6(4) -10.0.255.6/32 IP TE 40 rt3 - rt6(4) -rt2 TE-IS 50 rt3 - rt4(4) -10.0.255.4/32 IP TE 50 rt3 - rt4(4) -10.0.255.2/32 IP TE 60 rt3 - rt2(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt5 TE-IS 20 rt3 - rt3(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt6 TE-IS 30 rt3 - rt5(4) + 10.0.255.5/32 IP TE 30 rt3 - rt5(4) + rt4 TE-IS 40 rt3 - rt6(4) + 10.0.255.6/32 IP TE 40 rt3 - rt6(4) + rt2 TE-IS 50 rt3 - rt4(4) + 10.0.255.4/32 IP TE 50 rt3 - rt4(4) + 10.0.255.2/32 IP TE 60 rt3 - rt2(4) + IS-IS L1 IPv4 routing table: @@ -3080,19 +3240,21 @@ Q-space: rt6 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt1 -2001:db8::1/128 IP6 internal 0 rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt5 TE-IS 20 rt3 - rt3(4) -2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) -rt6 TE-IS 30 rt3 - rt5(4) -2001:db8::5/128 IP6 internal 30 rt3 - rt5(4) -rt4 TE-IS 40 rt3 - rt6(4) -2001:db8::6/128 IP6 internal 40 rt3 - rt6(4) -rt2 TE-IS 50 rt3 - rt4(4) -2001:db8::4/128 IP6 internal 50 rt3 - rt4(4) -2001:db8::2/128 IP6 internal 60 rt3 - rt2(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt1 + 2001:db8::1/128 IP6 internal 0 rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt5 TE-IS 20 rt3 - rt3(4) + 2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) + rt6 TE-IS 30 rt3 - rt5(4) + 2001:db8::5/128 IP6 internal 30 rt3 - rt5(4) + rt4 TE-IS 40 rt3 - rt6(4) + 2001:db8::6/128 IP6 internal 40 rt3 - rt6(4) + rt2 TE-IS 50 rt3 - rt4(4) + 2001:db8::4/128 IP6 internal 50 rt3 - rt4(4) + 2001:db8::2/128 IP6 internal 60 rt3 - rt2(4) + IS-IS L1 IPv6 routing table: @@ -3127,22 +3289,24 @@ Q-space: rt3 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt4 TE-IS 10 rt4 - rt1(4) -rt5 TE-IS 10 rt5 - rt1(4) -rt2 TE-IS 15 rt2 - rt1(4) -rt1 -rt6 TE-IS 20 rt4 - rt4(4) - rt5 - rt5(4) -10.0.255.4/32 IP TE 20 rt4 - rt4(4) -10.0.255.5/32 IP TE 20 rt5 - rt5(4) -10.0.255.2/32 IP TE 25 rt2 - rt2(4) -10.0.255.6/32 IP TE 30 rt4 - rt6(4) - rt5 - -rt3 TE-IS 50 rt5 - rt5(4) -10.0.255.3/32 IP TE 60 rt5 - rt3(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt4 TE-IS 10 rt4 - rt1(4) + rt5 TE-IS 10 rt5 - rt1(4) + rt2 TE-IS 15 rt2 - rt1(4) + rt1 + rt6 TE-IS 20 rt4 - rt4(4) + rt5 - rt5(4) + 10.0.255.4/32 IP TE 20 rt4 - rt4(4) + 10.0.255.5/32 IP TE 20 rt5 - rt5(4) + 10.0.255.2/32 IP TE 25 rt2 - rt2(4) + 10.0.255.6/32 IP TE 30 rt4 - rt6(4) + rt5 - rt6(4) + rt3 TE-IS 50 rt5 - rt5(4) + 10.0.255.3/32 IP TE 60 rt5 - rt3(4) + IS-IS L1 IPv4 routing table: @@ -3175,22 +3339,24 @@ Q-space: rt3 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt1 -2001:db8::1/128 IP6 internal 0 rt1(4) -rt4 TE-IS 10 rt4 - rt1(4) -rt5 TE-IS 10 rt5 - rt1(4) -rt2 TE-IS 15 rt2 - rt1(4) -rt1 -rt6 TE-IS 20 rt4 - rt4(4) - rt5 - rt5(4) -2001:db8::4/128 IP6 internal 20 rt4 - rt4(4) -2001:db8::5/128 IP6 internal 20 rt5 - rt5(4) -2001:db8::2/128 IP6 internal 25 rt2 - rt2(4) -2001:db8::6/128 IP6 internal 30 rt4 - rt6(4) - rt5 - -rt3 TE-IS 50 rt5 - rt5(4) -2001:db8::3/128 IP6 internal 60 rt5 - rt3(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt1 + 2001:db8::1/128 IP6 internal 0 rt1(4) + rt4 TE-IS 10 rt4 - rt1(4) + rt5 TE-IS 10 rt5 - rt1(4) + rt2 TE-IS 15 rt2 - rt1(4) + rt1 + rt6 TE-IS 20 rt4 - rt4(4) + rt5 - rt5(4) + 2001:db8::4/128 IP6 internal 20 rt4 - rt4(4) + 2001:db8::5/128 IP6 internal 20 rt5 - rt5(4) + 2001:db8::2/128 IP6 internal 25 rt2 - rt2(4) + 2001:db8::6/128 IP6 internal 30 rt4 - rt6(4) + rt5 - rt6(4) + rt3 TE-IS 50 rt5 - rt5(4) + 2001:db8::3/128 IP6 internal 60 rt5 - rt3(4) + IS-IS L1 IPv6 routing table: @@ -3217,20 +3383,22 @@ Q-space: rt6 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 15 rt2 - rt1(4) -10.0.255.2/32 IP TE 25 rt2 - rt2(4) -rt3 TE-IS 30 rt3 - rt1(4) -10.0.255.3/32 IP TE 40 rt3 - rt3(4) -rt4 TE-IS 55 rt2 - rt2(4) -rt1 -rt6 TE-IS 65 rt2 - rt4(4) -rt5 TE-IS 65 rt2 - rt1(2) -10.0.255.4/32 IP TE 65 rt2 - rt4(4) -10.0.255.6/32 IP TE 75 rt2 - rt6(4) -10.0.255.5/32 IP TE 75 rt2 - rt5(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 15 rt2 - rt1(4) + 10.0.255.2/32 IP TE 25 rt2 - rt2(4) + rt3 TE-IS 30 rt3 - rt1(4) + 10.0.255.3/32 IP TE 40 rt3 - rt3(4) + rt4 TE-IS 55 rt2 - rt2(4) + rt1 + rt6 TE-IS 65 rt2 - rt4(4) + rt5 TE-IS 65 rt2 - rt1(2) + 10.0.255.4/32 IP TE 65 rt2 - rt4(4) + 10.0.255.6/32 IP TE 75 rt2 - rt6(4) + 10.0.255.5/32 IP TE 75 rt2 - rt5(4) + IS-IS L1 IPv4 routing table: @@ -3258,20 +3426,22 @@ Q-space: rt6 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt1 -2001:db8::1/128 IP6 internal 0 rt1(4) -rt2 TE-IS 15 rt2 - rt1(4) -2001:db8::2/128 IP6 internal 25 rt2 - rt2(4) -rt3 TE-IS 30 rt3 - rt1(4) -2001:db8::3/128 IP6 internal 40 rt3 - rt3(4) -rt4 TE-IS 55 rt2 - rt2(4) -rt1 -rt6 TE-IS 65 rt2 - rt4(4) -rt5 TE-IS 65 rt2 - rt1(2) -2001:db8::4/128 IP6 internal 65 rt2 - rt4(4) -2001:db8::6/128 IP6 internal 75 rt2 - rt6(4) -2001:db8::5/128 IP6 internal 75 rt2 - rt5(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt1 + 2001:db8::1/128 IP6 internal 0 rt1(4) + rt2 TE-IS 15 rt2 - rt1(4) + 2001:db8::2/128 IP6 internal 25 rt2 - rt2(4) + rt3 TE-IS 30 rt3 - rt1(4) + 2001:db8::3/128 IP6 internal 40 rt3 - rt3(4) + rt4 TE-IS 55 rt2 - rt2(4) + rt1 + rt6 TE-IS 65 rt2 - rt4(4) + rt5 TE-IS 65 rt2 - rt1(2) + 2001:db8::4/128 IP6 internal 65 rt2 - rt4(4) + 2001:db8::6/128 IP6 internal 75 rt2 - rt6(4) + 2001:db8::5/128 IP6 internal 75 rt2 - rt5(4) + IS-IS L1 IPv6 routing table: @@ -3303,20 +3473,22 @@ Q-space: rt6 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt5 -10.0.255.5/32 IP internal 0 rt5(4) -rt6 TE-IS 10 rt6 - rt5(4) -rt4 TE-IS 20 rt6 - rt6(4) -10.0.255.6/32 IP TE 20 rt6 - rt6(4) -rt1 pseudo_TE-IS 30 rt6 - rt4(4) -rt1 TE-IS 30 rt6 - rt1(2) -10.0.255.4/32 IP TE 30 rt6 - rt4(4) -rt3 TE-IS 40 rt3 - rt5(4) -10.0.255.1/32 IP TE 40 rt6 - rt1(4) -rt2 TE-IS 45 rt6 - rt1(4) -10.0.255.3/32 IP TE 50 rt3 - rt3(4) -10.0.255.2/32 IP TE 55 rt6 - rt2(4) + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------ + rt5 + 10.0.255.5/32 IP internal 0 rt5(4) + rt6 TE-IS 10 rt6 - rt5(4) + rt4 TE-IS 20 rt6 - rt6(4) + 10.0.255.6/32 IP TE 20 rt6 - rt6(4) + rt1 pseudo_TE-IS 30 rt6 - rt4(4) + rt1 TE-IS 30 rt6 - rt1(2) + 10.0.255.4/32 IP TE 30 rt6 - rt4(4) + rt3 TE-IS 40 rt3 - rt5(4) + 10.0.255.1/32 IP TE 40 rt6 - rt1(4) + rt2 TE-IS 45 rt6 - rt1(4) + 10.0.255.3/32 IP TE 50 rt3 - rt3(4) + 10.0.255.2/32 IP TE 55 rt6 - rt2(4) + IS-IS L1 IPv4 routing table: @@ -3347,20 +3519,22 @@ Q-space: rt6 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt5 -2001:db8::5/128 IP6 internal 0 rt5(4) -rt6 TE-IS 10 rt6 - rt5(4) -rt4 TE-IS 20 rt6 - rt6(4) -2001:db8::6/128 IP6 internal 20 rt6 - rt6(4) -rt1 pseudo_TE-IS 30 rt6 - rt4(4) -rt1 TE-IS 30 rt6 - rt1(2) -2001:db8::4/128 IP6 internal 30 rt6 - rt4(4) -rt3 TE-IS 40 rt3 - rt5(4) -2001:db8::1/128 IP6 internal 40 rt6 - rt1(4) -rt2 TE-IS 45 rt6 - rt1(4) -2001:db8::3/128 IP6 internal 50 rt3 - rt3(4) -2001:db8::2/128 IP6 internal 55 rt6 - rt2(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt5 + 2001:db8::5/128 IP6 internal 0 rt5(4) + rt6 TE-IS 10 rt6 - rt5(4) + rt4 TE-IS 20 rt6 - rt6(4) + 2001:db8::6/128 IP6 internal 20 rt6 - rt6(4) + rt1 pseudo_TE-IS 30 rt6 - rt4(4) + rt1 TE-IS 30 rt6 - rt1(2) + 2001:db8::4/128 IP6 internal 30 rt6 - rt4(4) + rt3 TE-IS 40 rt3 - rt5(4) + 2001:db8::1/128 IP6 internal 40 rt6 - rt1(4) + rt2 TE-IS 45 rt6 - rt1(4) + 2001:db8::3/128 IP6 internal 50 rt3 - rt3(4) + 2001:db8::2/128 IP6 internal 55 rt6 - rt2(4) + IS-IS L1 IPv6 routing table: @@ -3396,21 +3570,23 @@ Q-space: rt6 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt5 -10.0.255.5/32 IP internal 0 rt5(4) -rt6 TE-IS 10 rt6 - rt5(4) -rt4 TE-IS 20 rt6 - rt6(4) -10.0.255.6/32 IP TE 20 rt6 - rt6(4) -rt3 TE-IS 30 rt3 - rt5(4) -rt2 TE-IS 30 rt6 - rt4(4) -10.0.255.4/32 IP TE 30 rt6 - rt4(4) -rt1 TE-IS 40 rt3 - rt3(4) - rt6 - rt2(4) -10.0.255.3/32 IP TE 40 rt3 - rt3(4) -10.0.255.2/32 IP TE 40 rt6 - rt2(4) -10.0.255.1/32 IP TE 50 rt3 - rt1(4) - rt6 - + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt5 + 10.0.255.5/32 IP internal 0 rt5(4) + rt6 TE-IS 10 rt6 - rt5(4) + rt4 TE-IS 20 rt6 - rt6(4) + 10.0.255.6/32 IP TE 20 rt6 - rt6(4) + rt3 TE-IS 30 rt3 - rt5(4) + rt2 TE-IS 30 rt6 - rt4(4) + 10.0.255.4/32 IP TE 30 rt6 - rt4(4) + rt1 TE-IS 40 rt3 - rt3(4) + rt6 - rt2(4) + 10.0.255.3/32 IP TE 40 rt3 - rt3(4) + 10.0.255.2/32 IP TE 40 rt6 - rt2(4) + 10.0.255.1/32 IP TE 50 rt3 - rt1(4) + rt6 - rt1(4) + IS-IS L1 IPv4 routing table: @@ -3450,19 +3626,21 @@ Q-space: rt6 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt5 -10.0.255.5/32 IP internal 0 rt5(4) -rt4 TE-IS 10 rt4 - rt5(4) -rt6 TE-IS 10 rt6 - rt5(4) -rt2 TE-IS 20 rt4 - rt4(4) -10.0.255.4/32 IP TE 20 rt4 - rt4(4) -10.0.255.6/32 IP TE 20 rt6 - rt6(4) -rt1 TE-IS 30 rt4 - rt2(4) -rt3 TE-IS 30 rt4 - rt2(4) -10.0.255.2/32 IP TE 30 rt4 - rt2(4) -10.0.255.1/32 IP TE 40 rt4 - rt1(4) -10.0.255.3/32 IP TE 40 rt4 - rt3(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt5 + 10.0.255.5/32 IP internal 0 rt5(4) + rt4 TE-IS 10 rt4 - rt5(4) + rt6 TE-IS 10 rt6 - rt5(4) + rt2 TE-IS 20 rt4 - rt4(4) + 10.0.255.4/32 IP TE 20 rt4 - rt4(4) + 10.0.255.6/32 IP TE 20 rt6 - rt6(4) + rt1 TE-IS 30 rt4 - rt2(4) + rt3 TE-IS 30 rt4 - rt2(4) + 10.0.255.2/32 IP TE 30 rt4 - rt2(4) + 10.0.255.1/32 IP TE 40 rt4 - rt1(4) + 10.0.255.3/32 IP TE 40 rt4 - rt3(4) + IS-IS L1 IPv4 routing table: @@ -3484,23 +3662,25 @@ Q-space: rt8 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt5 TE-IS 20 rt3 - rt3(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt7 TE-IS 30 rt3 - rt5(4) -10.0.255.5/32 IP TE 30 rt3 - rt5(4) -10.0.255.7/32 IP TE 40 rt3 - rt7(4) -rt6 TE-IS 70 rt3 - rt5(4) -rt4 TE-IS 80 rt3 - rt6(4) -rt8 TE-IS 80 rt3 - rt6(4) -10.0.255.6/32 IP TE 80 rt3 - rt6(4) -rt2 TE-IS 90 rt3 - rt4(4) -10.0.255.4/32 IP TE 90 rt3 - rt4(4) -10.0.255.8/32 IP TE 90 rt3 - rt8(4) -10.0.255.2/32 IP TE 100 rt3 - rt2(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt5 TE-IS 20 rt3 - rt3(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt7 TE-IS 30 rt3 - rt5(4) + 10.0.255.5/32 IP TE 30 rt3 - rt5(4) + 10.0.255.7/32 IP TE 40 rt3 - rt7(4) + rt6 TE-IS 70 rt3 - rt5(4) + rt4 TE-IS 80 rt3 - rt6(4) + rt8 TE-IS 80 rt3 - rt6(4) + 10.0.255.6/32 IP TE 80 rt3 - rt6(4) + rt2 TE-IS 90 rt3 - rt4(4) + 10.0.255.4/32 IP TE 90 rt3 - rt4(4) + 10.0.255.8/32 IP TE 90 rt3 - rt8(4) + 10.0.255.2/32 IP TE 100 rt3 - rt2(4) + IS-IS L1 IPv4 routing table: @@ -3531,23 +3711,25 @@ Q-space: rt8 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt4 -10.0.255.4/32 IP internal 0 rt4(4) -rt2 TE-IS 10 rt2 - rt4(4) -rt1 TE-IS 20 rt2 - rt2(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -rt3 TE-IS 30 rt2 - rt1(4) -10.0.255.1/32 IP TE 30 rt2 - rt1(4) -rt5 TE-IS 40 rt2 - rt3(4) -10.0.255.3/32 IP TE 40 rt2 - rt3(4) -rt7 TE-IS 50 rt2 - rt5(4) -10.0.255.5/32 IP TE 50 rt2 - rt5(4) -10.0.255.7/32 IP TE 60 rt2 - rt7(4) -rt6 TE-IS 90 rt2 - rt5(4) -rt8 TE-IS 100 rt2 - rt6(4) -10.0.255.6/32 IP TE 100 rt2 - rt6(4) -10.0.255.8/32 IP TE 110 rt2 - rt8(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt4 + 10.0.255.4/32 IP internal 0 rt4(4) + rt2 TE-IS 10 rt2 - rt4(4) + rt1 TE-IS 20 rt2 - rt2(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + rt3 TE-IS 30 rt2 - rt1(4) + 10.0.255.1/32 IP TE 30 rt2 - rt1(4) + rt5 TE-IS 40 rt2 - rt3(4) + 10.0.255.3/32 IP TE 40 rt2 - rt3(4) + rt7 TE-IS 50 rt2 - rt5(4) + 10.0.255.5/32 IP TE 50 rt2 - rt5(4) + 10.0.255.7/32 IP TE 60 rt2 - rt7(4) + rt6 TE-IS 90 rt2 - rt5(4) + rt8 TE-IS 100 rt2 - rt6(4) + 10.0.255.6/32 IP TE 100 rt2 - rt6(4) + 10.0.255.8/32 IP TE 110 rt2 - rt8(4) + IS-IS L1 IPv4 routing table: @@ -3575,23 +3757,25 @@ Q-space: rt8 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt5 TE-IS 20 rt3 - rt3(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt7 TE-IS 30 rt3 - rt5(4) -10.0.255.5/32 IP TE 30 rt3 - rt5(4) -rt8 TE-IS 40 rt3 - rt7(4) -10.0.255.7/32 IP TE 40 rt3 - rt7(4) -rt6 TE-IS 50 rt3 - rt8(4) -10.0.255.8/32 IP TE 50 rt3 - rt8(4) -rt4 TE-IS 60 rt3 - rt6(4) -10.0.255.6/32 IP TE 60 rt3 - rt6(4) -rt2 TE-IS 70 rt3 - rt4(4) -10.0.255.4/32 IP TE 70 rt3 - rt4(4) -10.0.255.2/32 IP TE 80 rt3 - rt2(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt5 TE-IS 20 rt3 - rt3(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt7 TE-IS 30 rt3 - rt5(4) + 10.0.255.5/32 IP TE 30 rt3 - rt5(4) + rt8 TE-IS 40 rt3 - rt7(4) + 10.0.255.7/32 IP TE 40 rt3 - rt7(4) + rt6 TE-IS 50 rt3 - rt8(4) + 10.0.255.8/32 IP TE 50 rt3 - rt8(4) + rt4 TE-IS 60 rt3 - rt6(4) + 10.0.255.6/32 IP TE 60 rt3 - rt6(4) + rt2 TE-IS 70 rt3 - rt4(4) + 10.0.255.4/32 IP TE 70 rt3 - rt4(4) + 10.0.255.2/32 IP TE 80 rt3 - rt2(4) + IS-IS L1 IPv4 routing table: @@ -3624,24 +3808,26 @@ Q-space: rt3 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt4 -10.0.255.4/32 IP internal 0 rt4(4) -rt2 TE-IS 10 rt2 - rt4(4) -rt6 TE-IS 10 rt6 - rt4(4) -rt1 TE-IS 20 rt2 - rt2(4) -rt5 TE-IS 20 rt6 - rt6(4) -rt8 TE-IS 20 rt6 - rt6(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.6/32 IP TE 20 rt6 - rt6(4) -rt3 TE-IS 30 rt2 - rt1(4) -rt7 TE-IS 30 rt6 - rt5(4) - rt8(4) -10.0.255.1/32 IP TE 30 rt2 - rt1(4) -10.0.255.5/32 IP TE 30 rt6 - rt5(4) -10.0.255.8/32 IP TE 30 rt6 - rt8(4) -10.0.255.3/32 IP TE 40 rt2 - rt3(4) -10.0.255.7/32 IP TE 40 rt6 - rt7(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt4 + 10.0.255.4/32 IP internal 0 rt4(4) + rt2 TE-IS 10 rt2 - rt4(4) + rt6 TE-IS 10 rt6 - rt4(4) + rt1 TE-IS 20 rt2 - rt2(4) + rt5 TE-IS 20 rt6 - rt6(4) + rt8 TE-IS 20 rt6 - rt6(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.6/32 IP TE 20 rt6 - rt6(4) + rt3 TE-IS 30 rt2 - rt1(4) + rt7 TE-IS 30 rt6 - rt5(4) + rt8(4) + 10.0.255.1/32 IP TE 30 rt2 - rt1(4) + 10.0.255.5/32 IP TE 30 rt6 - rt5(4) + 10.0.255.8/32 IP TE 30 rt6 - rt8(4) + 10.0.255.3/32 IP TE 40 rt2 - rt3(4) + 10.0.255.7/32 IP TE 40 rt6 - rt7(4) + IS-IS L1 IPv4 routing table: @@ -3676,33 +3862,35 @@ Q-space: rt9 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt11 -10.0.255.11/32 IP internal 0 rt11(4) -rt10 TE-IS 10 rt10 - rt11(4) -rt12 TE-IS 10 rt12 - rt11(4) -rt9 TE-IS 20 rt12 - rt12(4) -10.0.255.10/32 IP TE 20 rt10 - rt10(4) -10.0.255.12/32 IP TE 20 rt12 - rt12(4) -rt7 TE-IS 30 rt10 - rt10(4) -rt8 TE-IS 30 rt12 - rt9(4) -10.0.255.9/32 IP TE 30 rt12 - rt9(4) -rt4 TE-IS 40 rt10 - rt7(4) -rt5 TE-IS 40 rt12 - rt8(4) -10.0.255.7/32 IP TE 40 rt10 - rt7(4) -10.0.255.8/32 IP TE 40 rt12 - rt8(4) -rt6 TE-IS 50 rt12 - rt9(4) - rt5(4) -rt1 TE-IS 50 rt10 - rt4(4) -rt2 TE-IS 50 rt12 - rt5(4) -10.0.255.4/32 IP TE 50 rt10 - rt4(4) -10.0.255.5/32 IP TE 50 rt12 - rt5(4) -rt3 TE-IS 60 rt12 - rt6(4) - rt2(4) -10.0.255.6/32 IP TE 60 rt12 - rt6(4) -10.0.255.1/32 IP TE 60 rt10 - rt1(4) -10.0.255.2/32 IP TE 60 rt12 - rt2(4) -10.0.255.3/32 IP TE 70 rt12 - rt3(4) + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------- + rt11 + 10.0.255.11/32 IP internal 0 rt11(4) + rt10 TE-IS 10 rt10 - rt11(4) + rt12 TE-IS 10 rt12 - rt11(4) + rt9 TE-IS 20 rt12 - rt12(4) + 10.0.255.10/32 IP TE 20 rt10 - rt10(4) + 10.0.255.12/32 IP TE 20 rt12 - rt12(4) + rt7 TE-IS 30 rt10 - rt10(4) + rt8 TE-IS 30 rt12 - rt9(4) + 10.0.255.9/32 IP TE 30 rt12 - rt9(4) + rt4 TE-IS 40 rt10 - rt7(4) + rt5 TE-IS 40 rt12 - rt8(4) + 10.0.255.7/32 IP TE 40 rt10 - rt7(4) + 10.0.255.8/32 IP TE 40 rt12 - rt8(4) + rt6 TE-IS 50 rt12 - rt9(4) + rt5(4) + rt1 TE-IS 50 rt10 - rt4(4) + rt2 TE-IS 50 rt12 - rt5(4) + 10.0.255.4/32 IP TE 50 rt10 - rt4(4) + 10.0.255.5/32 IP TE 50 rt12 - rt5(4) + rt3 TE-IS 60 rt12 - rt6(4) + rt2(4) + 10.0.255.6/32 IP TE 60 rt12 - rt6(4) + 10.0.255.1/32 IP TE 60 rt10 - rt1(4) + 10.0.255.2/32 IP TE 60 rt12 - rt2(4) + 10.0.255.3/32 IP TE 70 rt12 - rt3(4) + IS-IS L1 IPv4 routing table: @@ -3750,39 +3938,41 @@ Q-space: rt12 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt6 -10.0.255.6/32 IP internal 0 rt6(4) -rt3 TE-IS 10 rt3 - rt6(4) -rt2 TE-IS 20 rt3 - rt3(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt9 TE-IS 30 rt9 - rt6(4) -rt5 TE-IS 30 rt3 - rt2(4) -10.0.255.2/32 IP TE 30 rt3 - rt2(4) -rt8 TE-IS 40 rt9 - rt9(4) - rt3 - rt5(4) -rt12 TE-IS 40 rt9 - rt9(4) -rt4 TE-IS 40 rt3 - rt5(4) -10.0.255.9/32 IP TE 40 rt9 - rt9(4) -10.0.255.5/32 IP TE 40 rt3 - rt5(4) -rt7 TE-IS 50 rt9 - rt8(4) - rt3 - rt4(4) -rt11 TE-IS 50 rt9 - rt8(4) - rt3 - rt12(4) -rt1 TE-IS 50 rt3 - rt4(4) -10.0.255.8/32 IP TE 50 rt9 - rt8(4) - rt3 - -10.0.255.12/32 IP TE 50 rt9 - rt12(4) -10.0.255.4/32 IP TE 50 rt3 - rt4(4) -rt10 TE-IS 60 rt9 - rt11(4) - rt3 - -10.0.255.7/32 IP TE 60 rt9 - rt7(4) - rt3 - -10.0.255.11/32 IP TE 60 rt9 - rt11(4) - rt3 - -10.0.255.1/32 IP TE 60 rt3 - rt1(4) -10.0.255.10/32 IP TE 70 rt9 - rt10(4) - rt3 - + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------- + rt6 + 10.0.255.6/32 IP internal 0 rt6(4) + rt3 TE-IS 10 rt3 - rt6(4) + rt2 TE-IS 20 rt3 - rt3(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt9 TE-IS 30 rt9 - rt6(4) + rt5 TE-IS 30 rt3 - rt2(4) + 10.0.255.2/32 IP TE 30 rt3 - rt2(4) + rt8 TE-IS 40 rt9 - rt9(4) + rt3 - rt5(4) + rt12 TE-IS 40 rt9 - rt9(4) + rt4 TE-IS 40 rt3 - rt5(4) + 10.0.255.9/32 IP TE 40 rt9 - rt9(4) + 10.0.255.5/32 IP TE 40 rt3 - rt5(4) + rt7 TE-IS 50 rt9 - rt8(4) + rt3 - rt4(4) + rt11 TE-IS 50 rt9 - rt8(4) + rt3 - rt12(4) + rt1 TE-IS 50 rt3 - rt4(4) + 10.0.255.8/32 IP TE 50 rt9 - rt8(4) + rt3 - rt8(4) + 10.0.255.12/32 IP TE 50 rt9 - rt12(4) + 10.0.255.4/32 IP TE 50 rt3 - rt4(4) + rt10 TE-IS 60 rt9 - rt11(4) + rt3 - rt11(4) + 10.0.255.7/32 IP TE 60 rt9 - rt7(4) + rt3 - rt7(4) + 10.0.255.11/32 IP TE 60 rt9 - rt11(4) + rt3 - rt11(4) + 10.0.255.1/32 IP TE 60 rt3 - rt1(4) + 10.0.255.10/32 IP TE 70 rt9 - rt10(4) + rt3 - rt10(4) + IS-IS L1 IPv4 routing table: @@ -3829,34 +4019,36 @@ Q-space: rt10 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt2 -10.0.255.2/32 IP internal 0 rt2(4) -rt3 TE-IS 10 rt3 - rt2(4) -rt5 TE-IS 10 rt5 - rt2(4) -rt6 TE-IS 20 rt3 - rt3(4) - rt5 - rt5(4) -rt8 TE-IS 20 rt5 - rt5(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -10.0.255.5/32 IP TE 20 rt5 - rt5(4) -rt9 TE-IS 30 rt5 - rt8(4) -rt11 TE-IS 30 rt5 - rt8(4) -10.0.255.6/32 IP TE 30 rt3 - rt6(4) - rt5 - -10.0.255.8/32 IP TE 30 rt5 - rt8(4) -rt12 TE-IS 40 rt5 - rt9(4) - rt11(4) -10.0.255.9/32 IP TE 40 rt5 - rt9(4) -10.0.255.11/32 IP TE 40 rt5 - rt11(4) -10.0.255.12/32 IP TE 50 rt5 - rt12(4) -rt10 TE-IS 60 rt5 - rt11(4) -rt7 TE-IS 70 rt5 - rt10(4) -10.0.255.10/32 IP TE 70 rt5 - rt10(4) -rt4 TE-IS 80 rt5 - rt7(4) -10.0.255.7/32 IP TE 80 rt5 - rt7(4) -rt1 TE-IS 90 rt5 - rt4(4) -10.0.255.4/32 IP TE 90 rt5 - rt4(4) -10.0.255.1/32 IP TE 100 rt5 - rt1(4) + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------- + rt2 + 10.0.255.2/32 IP internal 0 rt2(4) + rt3 TE-IS 10 rt3 - rt2(4) + rt5 TE-IS 10 rt5 - rt2(4) + rt6 TE-IS 20 rt3 - rt3(4) + rt5 - rt5(4) + rt8 TE-IS 20 rt5 - rt5(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + 10.0.255.5/32 IP TE 20 rt5 - rt5(4) + rt9 TE-IS 30 rt5 - rt8(4) + rt11 TE-IS 30 rt5 - rt8(4) + 10.0.255.6/32 IP TE 30 rt3 - rt6(4) + rt5 - rt6(4) + 10.0.255.8/32 IP TE 30 rt5 - rt8(4) + rt12 TE-IS 40 rt5 - rt9(4) + rt11(4) + 10.0.255.9/32 IP TE 40 rt5 - rt9(4) + 10.0.255.11/32 IP TE 40 rt5 - rt11(4) + 10.0.255.12/32 IP TE 50 rt5 - rt12(4) + rt10 TE-IS 60 rt5 - rt11(4) + rt7 TE-IS 70 rt5 - rt10(4) + 10.0.255.10/32 IP TE 70 rt5 - rt10(4) + rt4 TE-IS 80 rt5 - rt7(4) + 10.0.255.7/32 IP TE 80 rt5 - rt7(4) + rt1 TE-IS 90 rt5 - rt4(4) + 10.0.255.4/32 IP TE 90 rt5 - rt4(4) + 10.0.255.1/32 IP TE 100 rt5 - rt1(4) + IS-IS L1 IPv4 routing table: @@ -3894,32 +4086,34 @@ Q-space: rt12 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt2 -10.0.255.2/32 IP internal 0 rt2(4) -rt1 TE-IS 10 rt1 - rt2(4) -rt3 TE-IS 10 rt3 - rt2(4) -rt4 TE-IS 20 rt1 - rt1(4) -rt6 TE-IS 20 rt3 - rt3(4) -10.0.255.1/32 IP TE 20 rt1 - rt1(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt7 TE-IS 30 rt1 - rt4(4) -rt5 TE-IS 30 rt3 - rt6(4) -10.0.255.4/32 IP TE 30 rt1 - rt4(4) -10.0.255.6/32 IP TE 30 rt3 - rt6(4) -rt10 TE-IS 40 rt1 - rt7(4) -rt8 TE-IS 40 rt3 - rt5(4) -10.0.255.7/32 IP TE 40 rt1 - rt7(4) -10.0.255.5/32 IP TE 40 rt3 - rt5(4) -rt9 TE-IS 50 rt3 - rt8(4) -rt11 TE-IS 50 rt3 - rt8(4) -10.0.255.10/32 IP TE 50 rt1 - rt10(4) -10.0.255.8/32 IP TE 50 rt3 - rt8(4) -rt12 TE-IS 60 rt3 - rt9(4) - rt11(4) -10.0.255.9/32 IP TE 60 rt3 - rt9(4) -10.0.255.11/32 IP TE 60 rt3 - rt11(4) -10.0.255.12/32 IP TE 70 rt3 - rt12(4) + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------- + rt2 + 10.0.255.2/32 IP internal 0 rt2(4) + rt1 TE-IS 10 rt1 - rt2(4) + rt3 TE-IS 10 rt3 - rt2(4) + rt4 TE-IS 20 rt1 - rt1(4) + rt6 TE-IS 20 rt3 - rt3(4) + 10.0.255.1/32 IP TE 20 rt1 - rt1(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt7 TE-IS 30 rt1 - rt4(4) + rt5 TE-IS 30 rt3 - rt6(4) + 10.0.255.4/32 IP TE 30 rt1 - rt4(4) + 10.0.255.6/32 IP TE 30 rt3 - rt6(4) + rt10 TE-IS 40 rt1 - rt7(4) + rt8 TE-IS 40 rt3 - rt5(4) + 10.0.255.7/32 IP TE 40 rt1 - rt7(4) + 10.0.255.5/32 IP TE 40 rt3 - rt5(4) + rt9 TE-IS 50 rt3 - rt8(4) + rt11 TE-IS 50 rt3 - rt8(4) + 10.0.255.10/32 IP TE 50 rt1 - rt10(4) + 10.0.255.8/32 IP TE 50 rt3 - rt8(4) + rt12 TE-IS 60 rt3 - rt9(4) + rt11(4) + 10.0.255.9/32 IP TE 60 rt3 - rt9(4) + 10.0.255.11/32 IP TE 60 rt3 - rt11(4) + 10.0.255.12/32 IP TE 70 rt3 - rt12(4) + IS-IS L1 IPv4 routing table: @@ -3954,28 +4148,30 @@ Q-space: rt3 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -rt5 TE-IS 30 rt2 - rt4(4) -10.0.255.4/32 IP TE 30 rt2 - rt4(4) -rt9 TE-IS 40 rt2 - rt5(4) -10.0.255.5/32 IP TE 40 rt2 - rt5(4) -rt6 TE-IS 50 rt2 - rt4(4) - rt9(4) -rt7 TE-IS 50 rt2 - rt4(4) - rt9(4) -rt8 TE-IS 50 rt2 - rt4(4) - rt9(4) -10.0.255.9/32 IP TE 50 rt2 - rt9(4) -10.0.255.6/32 IP TE 60 rt2 - rt6(4) -10.0.255.7/32 IP TE 60 rt2 - rt7(4) -10.0.255.8/32 IP TE 60 rt2 - rt8(4) -rt3 TE-IS 120 rt2 - rt4(4) -10.0.255.3/32 IP TE 130 rt2 - rt3(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + rt5 TE-IS 30 rt2 - rt4(4) + 10.0.255.4/32 IP TE 30 rt2 - rt4(4) + rt9 TE-IS 40 rt2 - rt5(4) + 10.0.255.5/32 IP TE 40 rt2 - rt5(4) + rt6 TE-IS 50 rt2 - rt4(4) + rt9(4) + rt7 TE-IS 50 rt2 - rt4(4) + rt9(4) + rt8 TE-IS 50 rt2 - rt4(4) + rt9(4) + 10.0.255.9/32 IP TE 50 rt2 - rt9(4) + 10.0.255.6/32 IP TE 60 rt2 - rt6(4) + 10.0.255.7/32 IP TE 60 rt2 - rt7(4) + 10.0.255.8/32 IP TE 60 rt2 - rt8(4) + rt3 TE-IS 120 rt2 - rt4(4) + 10.0.255.3/32 IP TE 130 rt2 - rt3(4) + IS-IS L1 IPv4 routing table: @@ -4005,28 +4201,30 @@ Q-space: rt3 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt1 -2001:db8::1/128 IP6 internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) -2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) -rt5 TE-IS 30 rt2 - rt4(4) -2001:db8::4/128 IP6 internal 30 rt2 - rt4(4) -rt9 TE-IS 40 rt2 - rt5(4) -2001:db8::5/128 IP6 internal 40 rt2 - rt5(4) -rt6 TE-IS 50 rt2 - rt4(4) - rt9(4) -rt7 TE-IS 50 rt2 - rt4(4) - rt9(4) -rt8 TE-IS 50 rt2 - rt4(4) - rt9(4) -2001:db8::9/128 IP6 internal 50 rt2 - rt9(4) -2001:db8::6/128 IP6 internal 60 rt2 - rt6(4) -2001:db8::7/128 IP6 internal 60 rt2 - rt7(4) -2001:db8::8/128 IP6 internal 60 rt2 - rt8(4) -rt3 TE-IS 120 rt2 - rt4(4) -2001:db8::3/128 IP6 internal 130 rt2 - rt3(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt1 + 2001:db8::1/128 IP6 internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + 2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) + rt5 TE-IS 30 rt2 - rt4(4) + 2001:db8::4/128 IP6 internal 30 rt2 - rt4(4) + rt9 TE-IS 40 rt2 - rt5(4) + 2001:db8::5/128 IP6 internal 40 rt2 - rt5(4) + rt6 TE-IS 50 rt2 - rt4(4) + rt9(4) + rt7 TE-IS 50 rt2 - rt4(4) + rt9(4) + rt8 TE-IS 50 rt2 - rt4(4) + rt9(4) + 2001:db8::9/128 IP6 internal 50 rt2 - rt9(4) + 2001:db8::6/128 IP6 internal 60 rt2 - rt6(4) + 2001:db8::7/128 IP6 internal 60 rt2 - rt7(4) + 2001:db8::8/128 IP6 internal 60 rt2 - rt8(4) + rt3 TE-IS 120 rt2 - rt4(4) + 2001:db8::3/128 IP6 internal 130 rt2 - rt3(4) + IS-IS L1 IPv6 routing table: @@ -4051,28 +4249,30 @@ Q-space: rt9 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt4 TE-IS 110 rt3 - rt3(4) -rt2 TE-IS 120 rt3 - rt4(4) -rt5 TE-IS 120 rt3 - rt4(4) -10.0.255.4/32 IP TE 120 rt3 - rt4(4) -rt9 TE-IS 130 rt3 - rt5(4) -10.0.255.2/32 IP TE 130 rt3 - rt2(4) -10.0.255.5/32 IP TE 130 rt3 - rt5(4) -rt6 TE-IS 140 rt3 - rt4(4) - rt9(4) -rt7 TE-IS 140 rt3 - rt4(4) - rt9(4) -rt8 TE-IS 140 rt3 - rt4(4) - rt9(4) -10.0.255.9/32 IP TE 140 rt3 - rt9(4) -10.0.255.6/32 IP TE 150 rt3 - rt6(4) -10.0.255.7/32 IP TE 150 rt3 - rt7(4) -10.0.255.8/32 IP TE 150 rt3 - rt8(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt4 TE-IS 110 rt3 - rt3(4) + rt2 TE-IS 120 rt3 - rt4(4) + rt5 TE-IS 120 rt3 - rt4(4) + 10.0.255.4/32 IP TE 120 rt3 - rt4(4) + rt9 TE-IS 130 rt3 - rt5(4) + 10.0.255.2/32 IP TE 130 rt3 - rt2(4) + 10.0.255.5/32 IP TE 130 rt3 - rt5(4) + rt6 TE-IS 140 rt3 - rt4(4) + rt9(4) + rt7 TE-IS 140 rt3 - rt4(4) + rt9(4) + rt8 TE-IS 140 rt3 - rt4(4) + rt9(4) + 10.0.255.9/32 IP TE 140 rt3 - rt9(4) + 10.0.255.6/32 IP TE 150 rt3 - rt6(4) + 10.0.255.7/32 IP TE 150 rt3 - rt7(4) + 10.0.255.8/32 IP TE 150 rt3 - rt8(4) + IS-IS L1 IPv4 routing table: @@ -4102,28 +4302,30 @@ Q-space: rt9 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt1 -2001:db8::1/128 IP6 internal 0 rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) -rt4 TE-IS 110 rt3 - rt3(4) -rt2 TE-IS 120 rt3 - rt4(4) -rt5 TE-IS 120 rt3 - rt4(4) -2001:db8::4/128 IP6 internal 120 rt3 - rt4(4) -rt9 TE-IS 130 rt3 - rt5(4) -2001:db8::2/128 IP6 internal 130 rt3 - rt2(4) -2001:db8::5/128 IP6 internal 130 rt3 - rt5(4) -rt6 TE-IS 140 rt3 - rt4(4) - rt9(4) -rt7 TE-IS 140 rt3 - rt4(4) - rt9(4) -rt8 TE-IS 140 rt3 - rt4(4) - rt9(4) -2001:db8::9/128 IP6 internal 140 rt3 - rt9(4) -2001:db8::6/128 IP6 internal 150 rt3 - rt6(4) -2001:db8::7/128 IP6 internal 150 rt3 - rt7(4) -2001:db8::8/128 IP6 internal 150 rt3 - rt8(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt1 + 2001:db8::1/128 IP6 internal 0 rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + 2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) + rt4 TE-IS 110 rt3 - rt3(4) + rt2 TE-IS 120 rt3 - rt4(4) + rt5 TE-IS 120 rt3 - rt4(4) + 2001:db8::4/128 IP6 internal 120 rt3 - rt4(4) + rt9 TE-IS 130 rt3 - rt5(4) + 2001:db8::2/128 IP6 internal 130 rt3 - rt2(4) + 2001:db8::5/128 IP6 internal 130 rt3 - rt5(4) + rt6 TE-IS 140 rt3 - rt4(4) + rt9(4) + rt7 TE-IS 140 rt3 - rt4(4) + rt9(4) + rt8 TE-IS 140 rt3 - rt4(4) + rt9(4) + 2001:db8::9/128 IP6 internal 140 rt3 - rt9(4) + 2001:db8::6/128 IP6 internal 150 rt3 - rt6(4) + 2001:db8::7/128 IP6 internal 150 rt3 - rt7(4) + 2001:db8::8/128 IP6 internal 150 rt3 - rt8(4) + IS-IS L1 IPv6 routing table: @@ -4160,45 +4362,47 @@ Q-space: rt5 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt9 -10.0.255.9/32 IP internal 0 rt9(4) -rt6 TE-IS 10 rt6 - rt9(4) -rt7 TE-IS 10 rt7 - rt9(4) -rt8 TE-IS 10 rt8 - rt9(4) -10.0.255.6/32 IP TE 20 rt6 - rt6(4) -10.0.255.7/32 IP TE 20 rt7 - rt7(4) -10.0.255.8/32 IP TE 20 rt8 - rt8(4) -rt4 TE-IS 40 rt6 - rt6(4) - rt7 - rt7(4) - rt8 - rt8(4) -rt2 TE-IS 50 rt6 - rt4(4) - rt7 - - rt8 - -rt5 TE-IS 50 rt6 - rt4(4) - rt7 - - rt8 - -10.0.255.4/32 IP TE 50 rt6 - rt4(4) - rt7 - - rt8 - -rt1 TE-IS 60 rt6 - rt2(4) - rt7 - - rt8 - -10.0.255.2/32 IP TE 60 rt6 - rt2(4) - rt7 - - rt8 - -10.0.255.5/32 IP TE 60 rt6 - rt5(4) - rt7 - - rt8 - -rt3 TE-IS 70 rt6 - rt1(4) - rt7 - - rt8 - -10.0.255.1/32 IP TE 70 rt6 - rt1(4) - rt7 - - rt8 - -10.0.255.3/32 IP TE 80 rt6 - rt3(4) - rt7 - - rt8 - + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt9 + 10.0.255.9/32 IP internal 0 rt9(4) + rt6 TE-IS 10 rt6 - rt9(4) + rt7 TE-IS 10 rt7 - rt9(4) + rt8 TE-IS 10 rt8 - rt9(4) + 10.0.255.6/32 IP TE 20 rt6 - rt6(4) + 10.0.255.7/32 IP TE 20 rt7 - rt7(4) + 10.0.255.8/32 IP TE 20 rt8 - rt8(4) + rt4 TE-IS 40 rt6 - rt6(4) + rt7 - rt7(4) + rt8 - rt8(4) + rt2 TE-IS 50 rt6 - rt4(4) + rt7 - rt4(4) + rt8 - rt4(4) + rt5 TE-IS 50 rt6 - rt4(4) + rt7 - rt4(4) + rt8 - rt4(4) + 10.0.255.4/32 IP TE 50 rt6 - rt4(4) + rt7 - rt4(4) + rt8 - rt4(4) + rt1 TE-IS 60 rt6 - rt2(4) + rt7 - rt2(4) + rt8 - rt2(4) + 10.0.255.2/32 IP TE 60 rt6 - rt2(4) + rt7 - rt2(4) + rt8 - rt2(4) + 10.0.255.5/32 IP TE 60 rt6 - rt5(4) + rt7 - rt5(4) + rt8 - rt5(4) + rt3 TE-IS 70 rt6 - rt1(4) + rt7 - rt1(4) + rt8 - rt1(4) + 10.0.255.1/32 IP TE 70 rt6 - rt1(4) + rt7 - rt1(4) + rt8 - rt1(4) + 10.0.255.3/32 IP TE 80 rt6 - rt3(4) + rt7 - rt3(4) + rt8 - rt3(4) + IS-IS L1 IPv4 routing table: @@ -4242,45 +4446,47 @@ Q-space: rt5 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt9 -2001:db8::9/128 IP6 internal 0 rt9(4) -rt6 TE-IS 10 rt6 - rt9(4) -rt7 TE-IS 10 rt7 - rt9(4) -rt8 TE-IS 10 rt8 - rt9(4) -2001:db8::6/128 IP6 internal 20 rt6 - rt6(4) -2001:db8::7/128 IP6 internal 20 rt7 - rt7(4) -2001:db8::8/128 IP6 internal 20 rt8 - rt8(4) -rt4 TE-IS 40 rt6 - rt6(4) - rt7 - rt7(4) - rt8 - rt8(4) -rt2 TE-IS 50 rt6 - rt4(4) - rt7 - - rt8 - -rt5 TE-IS 50 rt6 - rt4(4) - rt7 - - rt8 - -2001:db8::4/128 IP6 internal 50 rt6 - rt4(4) - rt7 - - rt8 - -rt1 TE-IS 60 rt6 - rt2(4) - rt7 - - rt8 - -2001:db8::2/128 IP6 internal 60 rt6 - rt2(4) - rt7 - - rt8 - -2001:db8::5/128 IP6 internal 60 rt6 - rt5(4) - rt7 - - rt8 - -rt3 TE-IS 70 rt6 - rt1(4) - rt7 - - rt8 - -2001:db8::1/128 IP6 internal 70 rt6 - rt1(4) - rt7 - - rt8 - -2001:db8::3/128 IP6 internal 80 rt6 - rt3(4) - rt7 - - rt8 - + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt9 + 2001:db8::9/128 IP6 internal 0 rt9(4) + rt6 TE-IS 10 rt6 - rt9(4) + rt7 TE-IS 10 rt7 - rt9(4) + rt8 TE-IS 10 rt8 - rt9(4) + 2001:db8::6/128 IP6 internal 20 rt6 - rt6(4) + 2001:db8::7/128 IP6 internal 20 rt7 - rt7(4) + 2001:db8::8/128 IP6 internal 20 rt8 - rt8(4) + rt4 TE-IS 40 rt6 - rt6(4) + rt7 - rt7(4) + rt8 - rt8(4) + rt2 TE-IS 50 rt6 - rt4(4) + rt7 - rt4(4) + rt8 - rt4(4) + rt5 TE-IS 50 rt6 - rt4(4) + rt7 - rt4(4) + rt8 - rt4(4) + 2001:db8::4/128 IP6 internal 50 rt6 - rt4(4) + rt7 - rt4(4) + rt8 - rt4(4) + rt1 TE-IS 60 rt6 - rt2(4) + rt7 - rt2(4) + rt8 - rt2(4) + 2001:db8::2/128 IP6 internal 60 rt6 - rt2(4) + rt7 - rt2(4) + rt8 - rt2(4) + 2001:db8::5/128 IP6 internal 60 rt6 - rt5(4) + rt7 - rt5(4) + rt8 - rt5(4) + rt3 TE-IS 70 rt6 - rt1(4) + rt7 - rt1(4) + rt8 - rt1(4) + 2001:db8::1/128 IP6 internal 70 rt6 - rt1(4) + rt7 - rt1(4) + rt8 - rt1(4) + 2001:db8::3/128 IP6 internal 80 rt6 - rt3(4) + rt7 - rt3(4) + rt8 - rt3(4) + IS-IS L1 IPv6 routing table: @@ -4329,25 +4535,27 @@ Q-space: rt8 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt9 -10.0.255.9/32 IP internal 0 rt9(4) -rt5 TE-IS 10 rt5 - rt9(4) -rt6 TE-IS 10 rt6 - rt9(4) -rt7 TE-IS 10 rt7 - rt9(4) -rt4 TE-IS 20 rt5 - rt5(4) -10.0.255.5/32 IP TE 20 rt5 - rt5(4) -10.0.255.6/32 IP TE 20 rt6 - rt6(4) -10.0.255.7/32 IP TE 20 rt7 - rt7(4) -rt2 TE-IS 30 rt5 - rt4(4) -10.0.255.4/32 IP TE 30 rt5 - rt4(4) -rt1 TE-IS 40 rt5 - rt2(4) -10.0.255.2/32 IP TE 40 rt5 - rt2(4) -rt8 TE-IS 50 rt5 - rt4(4) -rt3 TE-IS 50 rt5 - rt1(4) -10.0.255.1/32 IP TE 50 rt5 - rt1(4) -10.0.255.8/32 IP TE 60 rt5 - rt8(4) -10.0.255.3/32 IP TE 60 rt5 - rt3(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt9 + 10.0.255.9/32 IP internal 0 rt9(4) + rt5 TE-IS 10 rt5 - rt9(4) + rt6 TE-IS 10 rt6 - rt9(4) + rt7 TE-IS 10 rt7 - rt9(4) + rt4 TE-IS 20 rt5 - rt5(4) + 10.0.255.5/32 IP TE 20 rt5 - rt5(4) + 10.0.255.6/32 IP TE 20 rt6 - rt6(4) + 10.0.255.7/32 IP TE 20 rt7 - rt7(4) + rt2 TE-IS 30 rt5 - rt4(4) + 10.0.255.4/32 IP TE 30 rt5 - rt4(4) + rt1 TE-IS 40 rt5 - rt2(4) + 10.0.255.2/32 IP TE 40 rt5 - rt2(4) + rt8 TE-IS 50 rt5 - rt4(4) + rt3 TE-IS 50 rt5 - rt1(4) + 10.0.255.1/32 IP TE 50 rt5 - rt1(4) + 10.0.255.8/32 IP TE 60 rt5 - rt8(4) + 10.0.255.3/32 IP TE 60 rt5 - rt3(4) + IS-IS L1 IPv4 routing table: @@ -4381,25 +4589,27 @@ Q-space: rt8 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt9 -2001:db8::9/128 IP6 internal 0 rt9(4) -rt5 TE-IS 10 rt5 - rt9(4) -rt6 TE-IS 10 rt6 - rt9(4) -rt7 TE-IS 10 rt7 - rt9(4) -rt4 TE-IS 20 rt5 - rt5(4) -2001:db8::5/128 IP6 internal 20 rt5 - rt5(4) -2001:db8::6/128 IP6 internal 20 rt6 - rt6(4) -2001:db8::7/128 IP6 internal 20 rt7 - rt7(4) -rt2 TE-IS 30 rt5 - rt4(4) -2001:db8::4/128 IP6 internal 30 rt5 - rt4(4) -rt1 TE-IS 40 rt5 - rt2(4) -2001:db8::2/128 IP6 internal 40 rt5 - rt2(4) -rt8 TE-IS 50 rt5 - rt4(4) -rt3 TE-IS 50 rt5 - rt1(4) -2001:db8::1/128 IP6 internal 50 rt5 - rt1(4) -2001:db8::8/128 IP6 internal 60 rt5 - rt8(4) -2001:db8::3/128 IP6 internal 60 rt5 - rt3(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt9 + 2001:db8::9/128 IP6 internal 0 rt9(4) + rt5 TE-IS 10 rt5 - rt9(4) + rt6 TE-IS 10 rt6 - rt9(4) + rt7 TE-IS 10 rt7 - rt9(4) + rt4 TE-IS 20 rt5 - rt5(4) + 2001:db8::5/128 IP6 internal 20 rt5 - rt5(4) + 2001:db8::6/128 IP6 internal 20 rt6 - rt6(4) + 2001:db8::7/128 IP6 internal 20 rt7 - rt7(4) + rt2 TE-IS 30 rt5 - rt4(4) + 2001:db8::4/128 IP6 internal 30 rt5 - rt4(4) + rt1 TE-IS 40 rt5 - rt2(4) + 2001:db8::2/128 IP6 internal 40 rt5 - rt2(4) + rt8 TE-IS 50 rt5 - rt4(4) + rt3 TE-IS 50 rt5 - rt1(4) + 2001:db8::1/128 IP6 internal 50 rt5 - rt1(4) + 2001:db8::8/128 IP6 internal 60 rt5 - rt8(4) + 2001:db8::3/128 IP6 internal 60 rt5 - rt3(4) + IS-IS L1 IPv6 routing table: @@ -4428,29 +4638,31 @@ Q-space: rt8 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt3 TE-IS 20 rt3 - rt1(4) -rt4 TE-IS 20 rt4 - rt1(4) -rt6 TE-IS 30 rt3 - rt3(4) -rt7 TE-IS 30 rt4 - rt4(4) -10.0.255.3/32 IP TE 30 rt3 - rt3(4) -10.0.255.4/32 IP TE 30 rt4 - rt4(4) -10.0.255.6/32 IP TE 40 rt3 - rt6(4) -10.0.255.7/32 IP TE 40 rt4 - rt7(4) -rt8 TE-IS 80 rt3 - rt6(4) - rt4 - rt7(4) -rt5 TE-IS 90 rt3 - rt8(4) - rt4 - -10.0.255.8/32 IP TE 90 rt3 - rt8(4) - rt4 - -rt2 TE-IS 100 rt3 - rt5(4) - rt4 - -10.0.255.5/32 IP TE 100 rt3 - rt5(4) - rt4 - -10.0.255.2/32 IP TE 110 rt3 - rt2(4) - rt4 - + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt3 TE-IS 20 rt3 - rt1(4) + rt4 TE-IS 20 rt4 - rt1(4) + rt6 TE-IS 30 rt3 - rt3(4) + rt7 TE-IS 30 rt4 - rt4(4) + 10.0.255.3/32 IP TE 30 rt3 - rt3(4) + 10.0.255.4/32 IP TE 30 rt4 - rt4(4) + 10.0.255.6/32 IP TE 40 rt3 - rt6(4) + 10.0.255.7/32 IP TE 40 rt4 - rt7(4) + rt8 TE-IS 80 rt3 - rt6(4) + rt4 - rt7(4) + rt5 TE-IS 90 rt3 - rt8(4) + rt4 - rt8(4) + 10.0.255.8/32 IP TE 90 rt3 - rt8(4) + rt4 - rt8(4) + rt2 TE-IS 100 rt3 - rt5(4) + rt4 - rt5(4) + 10.0.255.5/32 IP TE 100 rt3 - rt5(4) + rt4 - rt5(4) + 10.0.255.2/32 IP TE 110 rt3 - rt2(4) + rt4 - rt2(4) + IS-IS L1 IPv4 routing table: @@ -4483,29 +4695,31 @@ Q-space: rt8 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt1 -2001:db8::1/128 IP6 internal 0 rt1(4) -rt3 TE-IS 20 rt3 - rt1(4) -rt4 TE-IS 20 rt4 - rt1(4) -rt6 TE-IS 30 rt3 - rt3(4) -rt7 TE-IS 30 rt4 - rt4(4) -2001:db8::3/128 IP6 internal 30 rt3 - rt3(4) -2001:db8::4/128 IP6 internal 30 rt4 - rt4(4) -2001:db8::6/128 IP6 internal 40 rt3 - rt6(4) -2001:db8::7/128 IP6 internal 40 rt4 - rt7(4) -rt8 TE-IS 80 rt3 - rt6(4) - rt4 - rt7(4) -rt5 TE-IS 90 rt3 - rt8(4) - rt4 - -2001:db8::8/128 IP6 internal 90 rt3 - rt8(4) - rt4 - -rt2 TE-IS 100 rt3 - rt5(4) - rt4 - -2001:db8::5/128 IP6 internal 100 rt3 - rt5(4) - rt4 - -2001:db8::2/128 IP6 internal 110 rt3 - rt2(4) - rt4 - + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt1 + 2001:db8::1/128 IP6 internal 0 rt1(4) + rt3 TE-IS 20 rt3 - rt1(4) + rt4 TE-IS 20 rt4 - rt1(4) + rt6 TE-IS 30 rt3 - rt3(4) + rt7 TE-IS 30 rt4 - rt4(4) + 2001:db8::3/128 IP6 internal 30 rt3 - rt3(4) + 2001:db8::4/128 IP6 internal 30 rt4 - rt4(4) + 2001:db8::6/128 IP6 internal 40 rt3 - rt6(4) + 2001:db8::7/128 IP6 internal 40 rt4 - rt7(4) + rt8 TE-IS 80 rt3 - rt6(4) + rt4 - rt7(4) + rt5 TE-IS 90 rt3 - rt8(4) + rt4 - rt8(4) + 2001:db8::8/128 IP6 internal 90 rt3 - rt8(4) + rt4 - rt8(4) + rt2 TE-IS 100 rt3 - rt5(4) + rt4 - rt5(4) + 2001:db8::5/128 IP6 internal 100 rt3 - rt5(4) + rt4 - rt5(4) + 2001:db8::2/128 IP6 internal 110 rt3 - rt2(4) + rt4 - rt2(4) + IS-IS L1 IPv6 routing table: @@ -4540,23 +4754,25 @@ Q-space: rt7 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 20 rt3 - rt1(4) -rt5 TE-IS 20 rt2 - rt2(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -rt6 TE-IS 30 rt3 - rt3(4) -rt8 TE-IS 30 rt2 - rt5(4) -10.0.255.3/32 IP TE 30 rt3 - rt3(4) -10.0.255.5/32 IP TE 30 rt2 - rt5(4) -10.0.255.6/32 IP TE 40 rt3 - rt6(4) -10.0.255.8/32 IP TE 40 rt2 - rt8(4) -rt7 TE-IS 80 rt2 - rt8(4) -rt4 TE-IS 90 rt2 - rt7(4) -10.0.255.7/32 IP TE 90 rt2 - rt7(4) -10.0.255.4/32 IP TE 100 rt2 - rt4(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 20 rt3 - rt1(4) + rt5 TE-IS 20 rt2 - rt2(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + rt6 TE-IS 30 rt3 - rt3(4) + rt8 TE-IS 30 rt2 - rt5(4) + 10.0.255.3/32 IP TE 30 rt3 - rt3(4) + 10.0.255.5/32 IP TE 30 rt2 - rt5(4) + 10.0.255.6/32 IP TE 40 rt3 - rt6(4) + 10.0.255.8/32 IP TE 40 rt2 - rt8(4) + rt7 TE-IS 80 rt2 - rt8(4) + rt4 TE-IS 90 rt2 - rt7(4) + 10.0.255.7/32 IP TE 90 rt2 - rt7(4) + 10.0.255.4/32 IP TE 100 rt2 - rt4(4) + IS-IS L1 IPv4 routing table: @@ -4586,23 +4802,25 @@ Q-space: rt7 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt1 -2001:db8::1/128 IP6 internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 20 rt3 - rt1(4) -rt5 TE-IS 20 rt2 - rt2(4) -2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) -rt6 TE-IS 30 rt3 - rt3(4) -rt8 TE-IS 30 rt2 - rt5(4) -2001:db8::3/128 IP6 internal 30 rt3 - rt3(4) -2001:db8::5/128 IP6 internal 30 rt2 - rt5(4) -2001:db8::6/128 IP6 internal 40 rt3 - rt6(4) -2001:db8::8/128 IP6 internal 40 rt2 - rt8(4) -rt7 TE-IS 80 rt2 - rt8(4) -rt4 TE-IS 90 rt2 - rt7(4) -2001:db8::7/128 IP6 internal 90 rt2 - rt7(4) -2001:db8::4/128 IP6 internal 100 rt2 - rt4(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt1 + 2001:db8::1/128 IP6 internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 20 rt3 - rt1(4) + rt5 TE-IS 20 rt2 - rt2(4) + 2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) + rt6 TE-IS 30 rt3 - rt3(4) + rt8 TE-IS 30 rt2 - rt5(4) + 2001:db8::3/128 IP6 internal 30 rt3 - rt3(4) + 2001:db8::5/128 IP6 internal 30 rt2 - rt5(4) + 2001:db8::6/128 IP6 internal 40 rt3 - rt6(4) + 2001:db8::8/128 IP6 internal 40 rt2 - rt8(4) + rt7 TE-IS 80 rt2 - rt8(4) + rt4 TE-IS 90 rt2 - rt7(4) + 2001:db8::7/128 IP6 internal 90 rt2 - rt7(4) + 2001:db8::4/128 IP6 internal 100 rt2 - rt4(4) + IS-IS L1 IPv6 routing table: @@ -4633,20 +4851,22 @@ Q-space: rt6 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt2 -10.0.255.2/32 IP internal 0 rt2(4) -rt1 TE-IS 50 rt1 - rt2(4) -rt3 TE-IS 50 rt3 - rt2(4) -rt2 -rt5 TE-IS 60 rt3 - rt3(4) -10.0.255.1/32 IP TE 60 rt1 - rt1(4) -10.0.255.3/32 IP TE 60 rt3 - rt3(4) -rt4 TE-IS 70 rt3 - rt5(4) -rt6 TE-IS 70 rt3 - rt5(4) -10.0.255.5/32 IP TE 70 rt3 - rt5(4) -10.0.255.4/32 IP TE 80 rt3 - rt4(4) -10.0.255.6/32 IP TE 80 rt3 - rt6(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt2 + 10.0.255.2/32 IP internal 0 rt2(4) + rt1 TE-IS 50 rt1 - rt2(4) + rt3 TE-IS 50 rt3 - rt2(4) + rt2 + rt5 TE-IS 60 rt3 - rt3(4) + 10.0.255.1/32 IP TE 60 rt1 - rt1(4) + 10.0.255.3/32 IP TE 60 rt3 - rt3(4) + rt4 TE-IS 70 rt3 - rt5(4) + rt6 TE-IS 70 rt3 - rt5(4) + 10.0.255.5/32 IP TE 70 rt3 - rt5(4) + 10.0.255.4/32 IP TE 80 rt3 - rt4(4) + 10.0.255.6/32 IP TE 80 rt3 - rt6(4) + IS-IS L1 IPv4 routing table: @@ -4679,20 +4899,22 @@ Q-space: rt6 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt2 -2001:db8::2/128 IP6 internal 0 rt2(4) -rt1 TE-IS 50 rt1 - rt2(4) -rt3 TE-IS 50 rt3 - rt2(4) -rt2 -rt5 TE-IS 60 rt3 - rt3(4) -2001:db8::1/128 IP6 internal 60 rt1 - rt1(4) -2001:db8::3/128 IP6 internal 60 rt3 - rt3(4) -rt4 TE-IS 70 rt3 - rt5(4) -rt6 TE-IS 70 rt3 - rt5(4) -2001:db8::5/128 IP6 internal 70 rt3 - rt5(4) -2001:db8::4/128 IP6 internal 80 rt3 - rt4(4) -2001:db8::6/128 IP6 internal 80 rt3 - rt6(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt2 + 2001:db8::2/128 IP6 internal 0 rt2(4) + rt1 TE-IS 50 rt1 - rt2(4) + rt3 TE-IS 50 rt3 - rt2(4) + rt2 + rt5 TE-IS 60 rt3 - rt3(4) + 2001:db8::1/128 IP6 internal 60 rt1 - rt1(4) + 2001:db8::3/128 IP6 internal 60 rt3 - rt3(4) + rt4 TE-IS 70 rt3 - rt5(4) + rt6 TE-IS 70 rt3 - rt5(4) + 2001:db8::5/128 IP6 internal 70 rt3 - rt5(4) + 2001:db8::4/128 IP6 internal 80 rt3 - rt4(4) + 2001:db8::6/128 IP6 internal 80 rt3 - rt6(4) + IS-IS L1 IPv6 routing table: @@ -4723,27 +4945,29 @@ Q-space: rt3 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -rt6 TE-IS 30 rt2 - rt4(4) -10.0.255.4/32 IP TE 30 rt2 - rt4(4) -rt8 TE-IS 40 rt2 - rt6(4) -10.0.255.6/32 IP TE 40 rt2 - rt6(4) -rt10 TE-IS 50 rt2 - rt8(4) -10.0.255.8/32 IP TE 50 rt2 - rt8(4) -10.0.255.10/32 IP TE 60 rt2 - rt10(4) -rt7 TE-IS 140 rt2 - rt8(4) -rt9 TE-IS 150 rt2 - rt7(4) -10.0.255.7/32 IP TE 150 rt2 - rt7(4) -10.0.255.9/32 IP TE 160 rt2 - rt9(4) -rt5 TE-IS 340 rt2 - rt7(4) -10.0.255.5/32 IP TE 350 rt2 - rt5(4) -rt3 TE-IS 740 rt2 - rt5(4) -10.0.255.3/32 IP TE 750 rt2 - rt3(4) + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + rt6 TE-IS 30 rt2 - rt4(4) + 10.0.255.4/32 IP TE 30 rt2 - rt4(4) + rt8 TE-IS 40 rt2 - rt6(4) + 10.0.255.6/32 IP TE 40 rt2 - rt6(4) + rt10 TE-IS 50 rt2 - rt8(4) + 10.0.255.8/32 IP TE 50 rt2 - rt8(4) + 10.0.255.10/32 IP TE 60 rt2 - rt10(4) + rt7 TE-IS 140 rt2 - rt8(4) + rt9 TE-IS 150 rt2 - rt7(4) + 10.0.255.7/32 IP TE 150 rt2 - rt7(4) + 10.0.255.9/32 IP TE 160 rt2 - rt9(4) + rt5 TE-IS 340 rt2 - rt7(4) + 10.0.255.5/32 IP TE 350 rt2 - rt5(4) + rt3 TE-IS 740 rt2 - rt5(4) + 10.0.255.3/32 IP TE 750 rt2 - rt3(4) + IS-IS L1 IPv4 routing table: @@ -4770,22 +4994,24 @@ Q-space: rt7 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -rt3 TE-IS 30 rt2 - rt4(4) -10.0.255.4/32 IP TE 30 rt2 - rt4(4) -rt5 TE-IS 40 rt2 - rt3(4) -rt6 TE-IS 40 rt2 - rt3(4) -10.0.255.3/32 IP TE 40 rt2 - rt3(4) -rt7 TE-IS 50 rt2 - rt5(4) - rt6(4) -10.0.255.5/32 IP TE 50 rt2 - rt5(4) -10.0.255.6/32 IP TE 50 rt2 - rt6(4) -10.0.255.7/32 IP TE 60 rt2 - rt7(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + rt3 TE-IS 30 rt2 - rt4(4) + 10.0.255.4/32 IP TE 30 rt2 - rt4(4) + rt5 TE-IS 40 rt2 - rt3(4) + rt6 TE-IS 40 rt2 - rt3(4) + 10.0.255.3/32 IP TE 40 rt2 - rt3(4) + rt7 TE-IS 50 rt2 - rt5(4) + rt6(4) + 10.0.255.5/32 IP TE 50 rt2 - rt5(4) + 10.0.255.6/32 IP TE 50 rt2 - rt6(4) + 10.0.255.7/32 IP TE 60 rt2 - rt7(4) + IS-IS L1 IPv4 routing table: @@ -4796,5 +5022,5 @@ IS-IS L1 IPv4 routing table: 10.0.255.6/32 50 - rt2 16040/16060 10.0.255.7/32 60 - rt2 16040/16070 -test# -end. +test# +end. From 3a2554e4a23a69c6030253f78644f4f03b3bdcab Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Thu, 6 Jun 2024 17:08:56 +0200 Subject: [PATCH 107/347] isisd: add json support to display spf paths in 'show isis route' The 'show isis route json' command never displays the list of paths. Add the json support for this sub-part. > # show isis route json > [..] > "ipv6-paths":[ > { > "Vertex":"rt1", > "Type":"", > "Metric":0, > "Next-Hop":"", > "Interface":"", > "Parent":"" > }, > { > "Vertex":"2001:db8:1000::1\/128", > "Type":"IP6 internal", > "Metric":0, > "Next-Hop":"", > "Interface":"", > "Parent":"rt1(4)" > }, Signed-off-by: Philippe Guibert --- isisd/isis_spf.c | 64 ++++++++++++++++++++++++++----------- isisd/isis_spf.h | 3 +- tests/isisd/test_isis_spf.c | 10 +++--- 3 files changed, 52 insertions(+), 25 deletions(-) diff --git a/isisd/isis_spf.c b/isisd/isis_spf.c index 4892479ac2..c64bf67df5 100644 --- a/isisd/isis_spf.c +++ b/isisd/isis_spf.c @@ -2227,7 +2227,7 @@ int _isis_spf_schedule(struct isis_area *area, int level, } static void isis_print_paths(struct vty *vty, struct isis_vertex_queue *queue, - uint8_t *root_sysid) + uint8_t *root_sysid, struct json_object **json) { struct listnode *node; struct isis_vertex *vertex; @@ -2331,13 +2331,17 @@ static void isis_print_paths(struct vty *vty, struct isis_vertex_queue *queue, vertex_typestr, vertex_metricstr, vertex_nexthop, vertex_interface, vertex_parent); } - table = ttable_dump(tt, "\n"); - vty_out(vty, "%s\n", table); - XFREE(MTYPE_TMP, table); + if (json == NULL) { + table = ttable_dump(tt, "\n"); + vty_out(vty, "%s\n", table); + XFREE(MTYPE_TMP, table); + } else + *json = ttable_json(tt, "ssdsss"); ttable_del(tt); } -void isis_print_spftree(struct vty *vty, struct isis_spftree *spftree) +void isis_print_spftree(struct vty *vty, struct isis_spftree *spftree, + struct json_object **json) { const char *tree_id_text = NULL; @@ -2359,10 +2363,13 @@ void isis_print_spftree(struct vty *vty, struct isis_spftree *spftree) return; } - vty_out(vty, "IS-IS paths to level-%d routers %s\n", spftree->level, - tree_id_text); - isis_print_paths(vty, &spftree->paths, spftree->sysid); - vty_out(vty, "\n"); + if (!json) + vty_out(vty, "IS-IS paths to level-%d routers %s\n", + spftree->level, tree_id_text); + + isis_print_paths(vty, &spftree->paths, spftree->sysid, json); + if (!json) + vty_out(vty, "\n"); } static void show_isis_topology_common(struct vty *vty, int levels, @@ -2420,7 +2427,7 @@ static void show_isis_topology_common(struct vty *vty, int levels, spftree = area->spftree[SPFTREE_IPV4] [level - 1]; - isis_print_spftree(vty, spftree); + isis_print_spftree(vty, spftree, NULL); } if (area->ipv6_circuits > 0) { #ifndef FABRICD @@ -2431,7 +2438,7 @@ static void show_isis_topology_common(struct vty *vty, int levels, #endif /* ifndef FABRICD */ spftree = area->spftree[SPFTREE_IPV6] [level - 1]; - isis_print_spftree(vty, spftree); + isis_print_spftree(vty, spftree, NULL); } if (isis_area_ipv6_dstsrc_enabled(area)) { #ifndef FABRICD @@ -2443,14 +2450,15 @@ static void show_isis_topology_common(struct vty *vty, int levels, #endif /* ifndef FABRICD */ spftree = area->spftree[SPFTREE_DSTSRC] [level - 1]; - isis_print_spftree(vty, spftree); + isis_print_spftree(vty, spftree, NULL); } } if (fabricd_spftree(area)) { vty_out(vty, "IS-IS paths to level-2 routers with hop-by-hop metric\n"); - isis_print_paths(vty, &fabricd_spftree(area)->paths, isis->sysid); + isis_print_paths(vty, &fabricd_spftree(area)->paths, + isis->sysid, NULL); vty_out(vty, "\n"); } @@ -3006,8 +3014,14 @@ static void show_isis_route_common(struct vty *vty, int levels, spftree = area->spftree[SPFTREE_IPV4] [level - 1]; - if (!json) - isis_print_spftree(vty, spftree); + isis_print_spftree(vty, spftree, + json ? &json_val : NULL); + if (json && json_val) { + json_object_object_add(json_level, + "ipv4-paths", + json_val); + json_val = NULL; + } isis_print_routes(vty, spftree, json ? &json_val : NULL, @@ -3028,8 +3042,14 @@ static void show_isis_route_common(struct vty *vty, int levels, spftree = area->spftree[SPFTREE_IPV6] [level - 1]; - if (!json) - isis_print_spftree(vty, spftree); + isis_print_spftree(vty, spftree, + json ? &json_val : NULL); + if (json && json_val) { + json_object_object_add(json_level, + "ipv6-paths", + json_val); + json_val = NULL; + } isis_print_routes(vty, spftree, json ? &json_val : NULL, @@ -3051,8 +3071,14 @@ static void show_isis_route_common(struct vty *vty, int levels, spftree = area->spftree[SPFTREE_DSTSRC] [level - 1]; - if (!json) - isis_print_spftree(vty, spftree); + isis_print_spftree(vty, spftree, + json ? &json_val : NULL); + if (json && json_val) { + json_object_object_add(json_level, + "ipv6-dstsrc-paths", + json_val); + json_val = NULL; + } isis_print_routes(vty, spftree, json ? &json_val : NULL, prefix_sid, backup); diff --git a/isisd/isis_spf.h b/isisd/isis_spf.h index 7e9754d9bf..ee2d29abe3 100644 --- a/isisd/isis_spf.h +++ b/isisd/isis_spf.h @@ -61,7 +61,8 @@ struct isis_lsp *isis_root_system_lsp(struct lspdb_head *lspdb, __FILE__, __LINE__) int _isis_spf_schedule(struct isis_area *area, int level, const char *func, const char *file, int line); -void isis_print_spftree(struct vty *vty, struct isis_spftree *spftree); +void isis_print_spftree(struct vty *vty, struct isis_spftree *spftree, + struct json_object **json); void isis_print_routes(struct vty *vty, struct isis_spftree *spftree, json_object **json, bool prefix_sid, bool backup); void isis_spf_init(void); diff --git a/tests/isisd/test_isis_spf.c b/tests/isisd/test_isis_spf.c index 4ea28cda2f..6fe6993fdf 100644 --- a/tests/isisd/test_isis_spf.c +++ b/tests/isisd/test_isis_spf.c @@ -55,7 +55,7 @@ static void test_run_spf(struct vty *vty, const struct isis_topology *topology, isis_run_spf(spftree); /* Print the SPT and the corresponding routing table. */ - isis_print_spftree(vty, spftree); + isis_print_spftree(vty, spftree, NULL); isis_print_routes(vty, spftree, NULL, false, false); /* Cleanup SPF tree. */ @@ -85,7 +85,7 @@ static void test_run_lfa(struct vty *vty, const struct isis_topology *topology, isis_lfa_compute(area, NULL, spftree_self, protected_resource); /* Print the SPT and the corresponding main/backup routing tables. */ - isis_print_spftree(vty, spftree_self); + isis_print_spftree(vty, spftree_self, NULL); vty_out(vty, "Main:\n"); isis_print_routes(vty, spftree_self, NULL, false, false); vty_out(vty, "Backup:\n"); @@ -148,7 +148,7 @@ static void test_run_rlfa(struct vty *vty, const struct isis_topology *topology, vty_out(vty, "\n"); /* Print the post-convergence SPT. */ - isis_print_spftree(vty, spftree_pc); + isis_print_spftree(vty, spftree_pc, NULL); /* * Activate the computed RLFAs (if any) using artificial LDP labels for @@ -164,7 +164,7 @@ static void test_run_rlfa(struct vty *vty, const struct isis_topology *topology, } /* Print the SPT and the corresponding main/backup routing tables. */ - isis_print_spftree(vty, spftree_self); + isis_print_spftree(vty, spftree_self, NULL); vty_out(vty, "Main:\n"); isis_print_routes(vty, spftree_self, NULL, false, false); vty_out(vty, "Backup:\n"); @@ -228,7 +228,7 @@ static void test_run_ti_lfa(struct vty *vty, /* * Print the post-convergence SPT and the corresponding routing table. */ - isis_print_spftree(vty, spftree_pc); + isis_print_spftree(vty, spftree_pc, NULL); isis_print_routes(vty, spftree_self, NULL, false, true); /* Cleanup everything. */ From f72a8eb4b5840e8fb73138df0768c23f4ebcfc86 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Fri, 14 Jun 2024 08:57:16 +0200 Subject: [PATCH 108/347] isisd: add json support for 'show isis topology' command Add the json keyword for dumping isis topology. Signed-off-by: Philippe Guibert --- isisd/isis_spf.c | 125 +++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 104 insertions(+), 21 deletions(-) diff --git a/isisd/isis_spf.c b/isisd/isis_spf.c index c64bf67df5..86d998c419 100644 --- a/isisd/isis_spf.c +++ b/isisd/isis_spf.c @@ -2373,7 +2373,8 @@ void isis_print_spftree(struct vty *vty, struct isis_spftree *spftree, } static void show_isis_topology_common(struct vty *vty, int levels, - struct isis *isis, uint8_t algo) + struct isis *isis, uint8_t algo, + json_object **json) { #ifndef FABRICD struct isis_flex_algo_data *fa_data; @@ -2382,10 +2383,15 @@ static void show_isis_topology_common(struct vty *vty, int levels, struct isis_spftree *spftree; struct listnode *node; struct isis_area *area; + json_object *json_level = NULL, *jstr = NULL, *json_val; + char key[18]; if (!isis->area_list || isis->area_list->count == 0) return; + if (json) + *json = json_object_new_object(); + for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) { #ifndef FABRICD /* @@ -2403,21 +2409,37 @@ static void show_isis_topology_common(struct vty *vty, int levels, fa_data = NULL; #endif /* ifndef FABRICD */ - vty_out(vty, - "Area %s:", area->area_tag ? area->area_tag : "null"); + if (json) { + jstr = json_object_new_string( + area->area_tag ? area->area_tag : "null"); + json_object_object_add(*json, "area", jstr); + json_object_int_add(*json, "algorithm", algo); + } else { + vty_out(vty, "Area %s:", + area->area_tag ? area->area_tag : "null"); #ifndef FABRICD - if (algo != SR_ALGORITHM_SPF) - vty_out(vty, " Algorithm %hhu\n", algo); - else + if (algo != SR_ALGORITHM_SPF) + vty_out(vty, " Algorithm %hhu\n", algo); + else #endif /* ifndef FABRICD */ - vty_out(vty, "\n"); + vty_out(vty, "\n"); + } for (int level = ISIS_LEVEL1; level <= ISIS_LEVELS; level++) { if ((level & levels) == 0) continue; + if (json) { + json_level = json_object_new_object(); + jstr = json_object_new_string( + area->area_tag ? area->area_tag + : "null"); + json_object_object_add(json_level, "area", jstr); + } + if (area->ip_circuits > 0) { + json_val = NULL; #ifndef FABRICD if (fa_data) spftree = fa_data->spftree[SPFTREE_IPV4] @@ -2427,9 +2449,16 @@ static void show_isis_topology_common(struct vty *vty, int levels, spftree = area->spftree[SPFTREE_IPV4] [level - 1]; - isis_print_spftree(vty, spftree, NULL); + isis_print_spftree(vty, spftree, + json ? &json_val : NULL); + if (json && json_val) { + json_object_object_add(json_level, + "ipv4-paths", + json_val); + } } if (area->ipv6_circuits > 0) { + json_val = NULL; #ifndef FABRICD if (fa_data) spftree = fa_data->spftree[SPFTREE_IPV6] @@ -2438,9 +2467,16 @@ static void show_isis_topology_common(struct vty *vty, int levels, #endif /* ifndef FABRICD */ spftree = area->spftree[SPFTREE_IPV6] [level - 1]; - isis_print_spftree(vty, spftree, NULL); + isis_print_spftree(vty, spftree, + json ? &json_val : NULL); + if (json && json_val) { + json_object_object_add(json_level, + "ipv6-paths", + json_val); + } } if (isis_area_ipv6_dstsrc_enabled(area)) { + json_val = NULL; #ifndef FABRICD if (fa_data) spftree = @@ -2450,19 +2486,36 @@ static void show_isis_topology_common(struct vty *vty, int levels, #endif /* ifndef FABRICD */ spftree = area->spftree[SPFTREE_DSTSRC] [level - 1]; - isis_print_spftree(vty, spftree, NULL); + isis_print_spftree(vty, spftree, + json ? &json_val : NULL); + if (json && json_val) { + json_object_object_add(json_level, + "ipv6-dstsrc-paths", + json_val); + } + } + if (json) { + snprintf(key, sizeof(key), "level-%d", level); + json_object_object_add(*json, key, json_level); } } if (fabricd_spftree(area)) { + json_val = NULL; + vty_out(vty, "IS-IS paths to level-2 routers with hop-by-hop metric\n"); isis_print_paths(vty, &fabricd_spftree(area)->paths, - isis->sysid, NULL); - vty_out(vty, "\n"); + isis->sysid, json ? &json_val : NULL); + if (json && json_val) + json_object_object_add(json_level, + "fabricd-paths", + json_val); + else + vty_out(vty, "\n"); } - - vty_out(vty, "\n"); + if (!json) + vty_out(vty, "\n"); } } @@ -2473,6 +2526,7 @@ DEFUN(show_isis_topology, show_isis_topology_cmd, " []" " [algorithm [(128-255)]]" #endif /* ifndef FABRICD */ + " [json$uj]" , SHOW_STR PROTO_HELP VRF_CMD_HELP_STR "All VRFs\n" @@ -2483,6 +2537,7 @@ DEFUN(show_isis_topology, show_isis_topology_cmd, "Show Flex-algo routes\n" "Algorithm number\n" #endif /* ifndef FABRICD */ + JSON_STR ) { int levels = ISIS_LEVELS; @@ -2493,6 +2548,8 @@ DEFUN(show_isis_topology, show_isis_topology_cmd, bool all_algorithm = false; int idx_vrf = 0; uint16_t algorithm = SR_ALGORITHM_SPF; + bool uj = use_json(argc, argv); + json_object *json = NULL, *json_vrf = NULL; #ifndef FABRICD int idx = 0; @@ -2516,21 +2573,33 @@ DEFUN(show_isis_topology, show_isis_topology_cmd, } ISIS_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf); + if (uj) + json = json_object_new_array(); + if (all_vrf) { for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis)) { if (all_algorithm) { for (algorithm = SR_ALGORITHM_FLEX_MIN; algorithm <= SR_ALGORITHM_FLEX_MAX; algorithm++) - show_isis_topology_common( - vty, levels, isis, - (uint8_t)algorithm); + show_isis_topology_common(vty, levels, + isis, + (uint8_t)algorithm, + uj ? &json_vrf + : NULL); } else { show_isis_topology_common(vty, levels, isis, - (uint8_t)algorithm); + (uint8_t)algorithm, + uj ? &json_vrf : NULL); + } + if (uj) { + json_object_object_add(json_vrf, "vrf_id", + json_object_new_int( + isis->vrf_id)); + json_object_array_add(json, json_vrf); } } - return CMD_SUCCESS; + goto out; } isis = isis_lookup_by_vrfname(vrf_name); if (isis == NULL) @@ -2539,10 +2608,24 @@ DEFUN(show_isis_topology, show_isis_topology_cmd, for (algorithm = SR_ALGORITHM_FLEX_MIN; algorithm <= SR_ALGORITHM_FLEX_MAX; algorithm++) { show_isis_topology_common(vty, levels, isis, - (uint8_t)algorithm); + (uint8_t)algorithm, + uj ? &json_vrf : NULL); } } else - show_isis_topology_common(vty, levels, isis, (uint8_t)algorithm); + show_isis_topology_common(vty, levels, isis, (uint8_t)algorithm, + uj ? &json_vrf : NULL); + if (uj) { + json_object_object_add(json_vrf, "vrf_id", + json_object_new_int(isis->vrf_id)); + json_object_array_add(json, json_vrf); + } +out: + if (uj) { + vty_out(vty, "%s\n", + json_object_to_json_string_ext(json, + JSON_C_TO_STRING_PRETTY)); + json_object_free(json); + } return CMD_SUCCESS; } From cd68ea344792aa730cb89ae52b388360e3235f07 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Fri, 14 Jun 2024 10:18:15 +0200 Subject: [PATCH 109/347] topotests: isis_topo1, use 'show isis topology json' command Add the json support from ISIS vty command. Signed-off-by: Philippe Guibert --- .../topotests/isis_topo1/r1/r1_topology.json | 188 ++++----- .../topotests/isis_topo1/r2/r2_topology.json | 188 ++++----- .../topotests/isis_topo1/r3/r3_topology.json | 386 +++++++++--------- .../topotests/isis_topo1/r4/r4_topology.json | 386 +++++++++--------- .../topotests/isis_topo1/r5/r5_topology.json | 306 +++++++------- tests/topotests/isis_topo1/test_isis_topo1.py | 57 +-- 6 files changed, 731 insertions(+), 780 deletions(-) diff --git a/tests/topotests/isis_topo1/r1/r1_topology.json b/tests/topotests/isis_topo1/r1/r1_topology.json index 337d6bf5ef..d52346df6f 100644 --- a/tests/topotests/isis_topo1/r1/r1_topology.json +++ b/tests/topotests/isis_topo1/r1/r1_topology.json @@ -1,96 +1,98 @@ -{ - "1": { - "level-1": { - "ipv4": [ - { - "vertex": "r1" - } - ], - "ipv6": [ - { - "vertex": "r1" - } - ] - }, - "level-2": { - "ipv4": [ - { - "vertex": "r1" - }, - { - "metric": "0", - "parent": "r1(4)", - "type": "IP internal", - "vertex": "10.0.20.0/24" - }, - { - "interface": "r1-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r1(4)", - "type": "TE-IS", - "vertex": "r3" - }, - { - "interface": "r1-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r3(4)", - "type": "IP TE", - "vertex": "10.0.10.0/24" - }, - { - "interface": "r1-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r3(4)", - "type": "IP TE", - "vertex": "10.0.20.0/24" - }, - { - "interface": "r1-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r3(4)", - "type": "IP TE", - "vertex": "10.254.0.3/32" - } - ], - "ipv6": [ - { - "vertex": "r1" - }, - { - "metric": "0", - "parent": "r1(4)", - "type": "IP6 internal", - "vertex": "2001:db8:1:1::/64" - }, - { - "interface": "r1-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r1(4)", - "type": "TE-IS", - "vertex": "r3" - }, - { - "metric": "10", - "interface": "r1-eth0", - "next-hop": "r3", - "parent": "r3(4)", - "type": "IP6 internal", - "vertex": "2001:db8:2:1::/64" +[ + { + "area": "1", + "algorithm": 0, + "level-1": { + "ipv4-paths": [ + { + "Vertex": "r1" + } + ], + "ipv6-paths": [ + { + "Vertex": "r1" + } + ] }, - { - "metric": "10", - "interface": "r1-eth0", - "next-hop": "r3", - "parent": "r3(4)", - "type": "IP6 internal", - "vertex": "2001:db8:f::3/128" + "level-2": { + "ipv4-paths": [ + { + "Vertex": "r1" + }, + { + "Metric": 0, + "Parent": "r1(4)", + "Type": "IP internal", + "Vertex": "10.0.20.0/24" + }, + { + "Interface": "r1-eth0", + "Metric": 10, + "Next-Hop": "r3", + "Parent": "r1(4)", + "Type": "TE-IS", + "Vertex": "r3" + }, + { + "Interface": "r1-eth0", + "Metric": 10, + "Next-Hop": "r3", + "Parent": "r3(4)", + "Type": "IP TE", + "Vertex": "10.0.10.0/24" + }, + { + "Interface": "r1-eth0", + "Metric": 10, + "Next-Hop": "r3", + "Parent": "r3(4)", + "Type": "IP TE", + "Vertex": "10.0.20.0/24" + }, + { + "Interface": "r1-eth0", + "Metric": 10, + "Next-Hop": "r3", + "Parent": "r3(4)", + "Type": "IP TE", + "Vertex": "10.254.0.3/32" + } + ], + "ipv6-paths": [ + { + "Vertex": "r1" + }, + { + "Metric": 0, + "Parent": "r1(4)", + "Type": "IP6 internal", + "Vertex": "2001:db8:1:1::/64" + }, + { + "Interface": "r1-eth0", + "Metric": 10, + "Next-Hop": "r3", + "Parent": "r1(4)", + "Type": "TE-IS", + "Vertex": "r3" + }, + { + "Metric": 10, + "Interface": "r1-eth0", + "Next-Hop": "r3", + "Parent": "r3(4)", + "Type": "IP6 internal", + "Vertex": "2001:db8:2:1::/64" + }, + { + "Metric": 10, + "Interface": "r1-eth0", + "Next-Hop": "r3", + "Parent": "r3(4)", + "Type": "IP6 internal", + "Vertex": "2001:db8:f::3/128" + } + ] } - ] } - } -} +] diff --git a/tests/topotests/isis_topo1/r2/r2_topology.json b/tests/topotests/isis_topo1/r2/r2_topology.json index de90fb5a32..d0a1f90fd0 100644 --- a/tests/topotests/isis_topo1/r2/r2_topology.json +++ b/tests/topotests/isis_topo1/r2/r2_topology.json @@ -1,96 +1,98 @@ -{ - "1": { - "level-1": { - "ipv4": [ - { - "vertex": "r2" - } - ], - "ipv6": [ - { - "vertex": "r2" - } - ] - }, - "level-2": { - "ipv4": [ - { - "vertex": "r2" - }, - { - "metric": "0", - "parent": "r2(4)", - "type": "IP internal", - "vertex": "10.0.21.0/24" - }, - { - "interface": "r2-eth0", - "metric": "10", - "next-hop": "r4", - "parent": "r2(4)", - "type": "TE-IS", - "vertex": "r4" - }, - { - "interface": "r2-eth0", - "metric": "10", - "next-hop": "r4", - "parent": "r4(4)", - "type": "IP TE", - "vertex": "10.0.11.0/24" - }, - { - "interface": "r2-eth0", - "metric": "10", - "next-hop": "r4", - "parent": "r4(4)", - "type": "IP TE", - "vertex": "10.0.21.0/24" - }, - { - "interface": "r2-eth0", - "metric": "10", - "next-hop": "r4", - "parent": "r4(4)", - "type": "IP TE", - "vertex": "10.254.0.4/32" - } - ], - "ipv6": [ - { - "vertex": "r2" - }, - { - "metric": "0", - "parent": "r2(4)", - "type": "IP6 internal", - "vertex": "2001:db8:1:2::/64" - }, - { - "interface": "r2-eth0", - "metric": "10", - "next-hop": "r4", - "parent": "r2(4)", - "type": "TE-IS", - "vertex": "r4" - }, - { - "metric": "10", - "interface": "r2-eth0", - "next-hop": "r4", - "parent": "r4(4)", - "type": "IP6 internal", - "vertex": "2001:db8:2:2::/64" +[ + { + "area": "1", + "algorithm": 0, + "level-1": { + "ipv4-paths": [ + { + "Vertex": "r2" + } + ], + "ipv6-paths": [ + { + "Vertex": "r2" + } + ] }, - { - "metric": "10", - "interface": "r2-eth0", - "next-hop": "r4", - "parent": "r4(4)", - "type": "IP6 internal", - "vertex": "2001:db8:f::4/128" + "level-2": { + "ipv4-paths": [ + { + "Vertex": "r2" + }, + { + "Metric": 0, + "Parent": "r2(4)", + "Type": "IP internal", + "Vertex": "10.0.21.0/24" + }, + { + "Interface": "r2-eth0", + "Metric": 10, + "Next-Hop": "r4", + "Parent": "r2(4)", + "Type": "TE-IS", + "Vertex": "r4" + }, + { + "Interface": "r2-eth0", + "Metric": 10, + "Next-Hop": "r4", + "Parent": "r4(4)", + "Type": "IP TE", + "Vertex": "10.0.11.0/24" + }, + { + "Interface": "r2-eth0", + "Metric": 10, + "Next-Hop": "r4", + "Parent": "r4(4)", + "Type": "IP TE", + "Vertex": "10.0.21.0/24" + }, + { + "Interface": "r2-eth0", + "Metric": 10, + "Next-Hop": "r4", + "Parent": "r4(4)", + "Type": "IP TE", + "Vertex": "10.254.0.4/32" + } + ], + "ipv6-paths": [ + { + "Vertex": "r2" + }, + { + "Metric": 0, + "Parent": "r2(4)", + "Type": "IP6 internal", + "Vertex": "2001:db8:1:2::/64" + }, + { + "Interface": "r2-eth0", + "Metric": 10, + "Next-Hop": "r4", + "Parent": "r2(4)", + "Type": "TE-IS", + "Vertex": "r4" + }, + { + "Metric": 10, + "Interface": "r2-eth0", + "Next-Hop": "r4", + "Parent": "r4(4)", + "Type": "IP6 internal", + "Vertex": "2001:db8:2:2::/64" + }, + { + "Metric": 10, + "Interface": "r2-eth0", + "Next-Hop": "r4", + "Parent": "r4(4)", + "Type": "IP6 internal", + "Vertex": "2001:db8:f::4/128" + } + ] } - ] } - } -} +] diff --git a/tests/topotests/isis_topo1/r3/r3_topology.json b/tests/topotests/isis_topo1/r3/r3_topology.json index 2d36f9b427..9265e62786 100644 --- a/tests/topotests/isis_topo1/r3/r3_topology.json +++ b/tests/topotests/isis_topo1/r3/r3_topology.json @@ -1,194 +1,196 @@ -{ - "1": { - "level-1": { - "ipv4": [ - { - "vertex": "r3" - }, - { - "metric": "0", - "parent": "r3(4)", - "type": "IP internal", - "vertex": "10.0.10.0/24" - }, - { - "interface": "r3-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r3(4)", - "type": "TE-IS", - "vertex": "r5" - }, - { - "interface": "r3-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r5(4)", - "type": "IP TE", - "vertex": "10.0.10.0/24" - }, - { - "interface": "r3-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r5(4)", - "type": "IP TE", - "vertex": "10.0.11.0/24" - }, - { - "interface": "r3-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r5(4)", - "type": "IP TE", - "vertex": "10.254.0.5/32" - }, - { - "interface": "r3-eth1", - "metric": "20", - "next-hop": "r5", - "type": "TE-IS", - "vertex": "r4" - }, - { - "interface": "r3-eth1", - "metric": "20", - "next-hop": "r5", - "parent": "r4(4)", - "type": "IP TE", - "vertex": "10.0.21.0/24" - }, - { - "interface": "r3-eth1", - "metric": "20", - "next-hop": "r5", - "parent": "r4(4)", - "type": "IP TE", - "vertex": "10.254.0.4/32" - } - ], - "ipv6": [ - { - "vertex": "r3" - }, - { - "metric": "0", - "parent": "r3(4)", - "type": "IP6 internal", - "vertex": "2001:db8:2:1::/64" - }, - { - "interface": "r3-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r3(4)", - "type": "TE-IS", - "vertex": "r5" - }, - { - "metric": "10", - "interface": "r3-eth1", - "next-hop": "r5", - "parent": "r5(4)", - "type": "IP6 internal", - "vertex": "2001:db8:2:2::/64" - }, - { - "metric": "10", - "interface": "r3-eth1", - "next-hop": "r5", - "parent": "r5(4)", - "type": "IP6 internal", - "vertex": "2001:db8:f::5/128" - }, - { - "interface": "r3-eth1", - "metric": "20", - "next-hop": "r5", - "type": "TE-IS", - "vertex": "r4" - }, - { - "metric": "20", - "interface": "r3-eth1", - "next-hop": "r5", - "parent": "r4(4)", - "type": "IP6 internal", - "vertex": "2001:db8:1:2::/64" - }, - { - "metric": "20", - "interface": "r3-eth1", - "next-hop": "r5", - "parent": "r4(4)", - "type": "IP6 internal", - "vertex": "2001:db8:f::4/128" - } - ] - }, - "level-2": { - "ipv4": [ - { - "vertex": "r3" - }, - { - "metric": "0", - "parent": "r3(4)", - "type": "IP internal", - "vertex": "10.0.20.0/24" - }, - { - "interface": "r3-eth0", - "metric": "10", - "next-hop": "r1", - "parent": "r3(4)", - "type": "TE-IS", - "vertex": "r1" - }, - { - "interface": "r3-eth0", - "metric": "10", - "next-hop": "r1", - "parent": "r1(4)", - "type": "IP TE", - "vertex": "10.0.20.0/24" - }, - { - "interface": "r3-eth0", - "metric": "10", - "next-hop": "r1", - "parent": "r1(4)", - "type": "IP TE", - "vertex": "10.254.0.1/32" - } - ], - "ipv6": [ - { - "vertex": "r3" - }, - { - "metric": "0", - "parent": "r3(4)", - "type": "IP6 internal", - "vertex": "2001:db8:1:1::/64" - }, - { - "interface": "r3-eth0", - "metric": "10", - "next-hop": "r1", - "parent": "r3(4)", - "type": "TE-IS", - "vertex": "r1" - }, - { - "metric": "10", - "interface": "r3-eth0", - "next-hop": "r1", - "parent": "r1(4)", - "type": "IP6 internal", - "vertex": "2001:db8:f::1/128" +[ + { + "area": "1", + "algorithm": 0, + "level-1": { + "ipv4-paths": [ + { + "Vertex": "r3" + }, + { + "Metric": 0, + "Parent": "r3(4)", + "Type": "IP internal", + "Vertex": "10.0.10.0/24" + }, + { + "Interface": "r3-eth1", + "Metric": 10, + "Next-Hop": "r5", + "Parent": "r3(4)", + "Type": "TE-IS", + "Vertex": "r5" + }, + { + "Interface": "r3-eth1", + "Metric": 10, + "Next-Hop": "r5", + "Parent": "r5(4)", + "Type": "IP TE", + "Vertex": "10.0.10.0/24" + }, + { + "Interface": "r3-eth1", + "Metric": 10, + "Next-Hop": "r5", + "Parent": "r5(4)", + "Type": "IP TE", + "Vertex": "10.0.11.0/24" + }, + { + "Interface": "r3-eth1", + "Metric": 10, + "Next-Hop": "r5", + "Parent": "r5(4)", + "Type": "IP TE", + "Vertex": "10.254.0.5/32" + }, + { + "Interface": "r3-eth1", + "Metric": 20, + "Next-Hop": "r5", + "Type": "TE-IS", + "Vertex": "r4" + }, + { + "Interface": "r3-eth1", + "Metric": 20, + "Next-Hop": "r5", + "Parent": "r4(4)", + "Type": "IP TE", + "Vertex": "10.0.21.0/24" + }, + { + "Interface": "r3-eth1", + "Metric": 20, + "Next-Hop": "r5", + "Parent": "r4(4)", + "Type": "IP TE", + "Vertex": "10.254.0.4/32" + } + ], + "ipv6-paths": [ + { + "Vertex": "r3" + }, + { + "Metric": 0, + "Parent": "r3(4)", + "Type": "IP6 internal", + "Vertex": "2001:db8:2:1::/64" + }, + { + "Interface": "r3-eth1", + "Metric": 10, + "Next-Hop": "r5", + "Parent": "r3(4)", + "Type": "TE-IS", + "Vertex": "r5" + }, + { + "Metric": 10, + "Interface": "r3-eth1", + "Next-Hop": "r5", + "Parent": "r5(4)", + "Type": "IP6 internal", + "Vertex": "2001:db8:2:2::/64" + }, + { + "Metric": 10, + "Interface": "r3-eth1", + "Next-Hop": "r5", + "Parent": "r5(4)", + "Type": "IP6 internal", + "Vertex": "2001:db8:f::5/128" + }, + { + "Interface": "r3-eth1", + "Metric": 20, + "Next-Hop": "r5", + "Type": "TE-IS", + "Vertex": "r4" + }, + { + "Metric": 20, + "Interface": "r3-eth1", + "Next-Hop": "r5", + "Parent": "r4(4)", + "Type": "IP6 internal", + "Vertex": "2001:db8:1:2::/64" + }, + { + "Metric": 20, + "Interface": "r3-eth1", + "Next-Hop": "r5", + "Parent": "r4(4)", + "Type": "IP6 internal", + "Vertex": "2001:db8:f::4/128" + } + ] + }, + "level-2": { + "ipv4-paths": [ + { + "Vertex": "r3" + }, + { + "Metric": 0, + "Parent": "r3(4)", + "Type": "IP internal", + "Vertex": "10.0.20.0/24" + }, + { + "Interface": "r3-eth0", + "Metric": 10, + "Next-Hop": "r1", + "Parent": "r3(4)", + "Type": "TE-IS", + "Vertex": "r1" + }, + { + "Interface": "r3-eth0", + "Metric": 10, + "Next-Hop": "r1", + "Parent": "r1(4)", + "Type": "IP TE", + "Vertex": "10.0.20.0/24" + }, + { + "Interface": "r3-eth0", + "Metric": 10, + "Next-Hop": "r1", + "Parent": "r1(4)", + "Type": "IP TE", + "Vertex": "10.254.0.1/32" + } + ], + "ipv6-paths": [ + { + "Vertex": "r3" + }, + { + "Metric": 0, + "Parent": "r3(4)", + "Type": "IP6 internal", + "Vertex": "2001:db8:1:1::/64" + }, + { + "Interface": "r3-eth0", + "Metric": 10, + "Next-Hop": "r1", + "Parent": "r3(4)", + "Type": "TE-IS", + "Vertex": "r1" + }, + { + "Metric": 10, + "Interface": "r3-eth0", + "Next-Hop": "r1", + "Parent": "r1(4)", + "Type": "IP6 internal", + "Vertex": "2001:db8:f::1/128" + } + ] } - ] } - } -} +] diff --git a/tests/topotests/isis_topo1/r4/r4_topology.json b/tests/topotests/isis_topo1/r4/r4_topology.json index e7d7841912..240c7588fc 100644 --- a/tests/topotests/isis_topo1/r4/r4_topology.json +++ b/tests/topotests/isis_topo1/r4/r4_topology.json @@ -1,194 +1,196 @@ -{ - "1": { - "level-1": { - "ipv4": [ - { - "vertex": "r4" - }, - { - "metric": "0", - "parent": "r4(4)", - "type": "IP internal", - "vertex": "10.0.11.0/24" - }, - { - "interface": "r4-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r4(4)", - "type": "TE-IS", - "vertex": "r5" - }, - { - "interface": "r4-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r5(4)", - "type": "IP TE", - "vertex": "10.0.10.0/24" - }, - { - "interface": "r4-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r5(4)", - "type": "IP TE", - "vertex": "10.0.11.0/24" - }, - { - "interface": "r4-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r5(4)", - "type": "IP TE", - "vertex": "10.254.0.5/32" - }, - { - "interface": "r4-eth1", - "metric": "20", - "next-hop": "r5", - "type": "TE-IS", - "vertex": "r3" - }, - { - "interface": "r4-eth1", - "metric": "20", - "next-hop": "r5", - "parent": "r3(4)", - "type": "IP TE", - "vertex": "10.0.20.0/24" - }, - { - "interface": "r4-eth1", - "metric": "20", - "next-hop": "r5", - "parent": "r3(4)", - "type": "IP TE", - "vertex": "10.254.0.3/32" - } - ], - "ipv6": [ - { - "vertex": "r4" - }, - { - "metric": "0", - "parent": "r4(4)", - "type": "IP6 internal", - "vertex": "2001:db8:2:2::/64" - }, - { - "interface": "r4-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r4(4)", - "type": "TE-IS", - "vertex": "r5" - }, - { - "metric": "10", - "interface": "r4-eth1", - "next-hop": "r5", - "parent": "r5(4)", - "type": "IP6 internal", - "vertex": "2001:db8:2:1::/64" - }, - { - "metric": "10", - "interface": "r4-eth1", - "next-hop": "r5", - "parent": "r5(4)", - "type": "IP6 internal", - "vertex": "2001:db8:f::5/128" - }, - { - "interface": "r4-eth1", - "metric": "20", - "next-hop": "r5", - "type": "TE-IS", - "vertex": "r3" - }, - { - "metric": "20", - "interface": "r4-eth1", - "next-hop": "r5", - "parent": "r3(4)", - "type": "IP6 internal", - "vertex": "2001:db8:1:1::/64" - }, - { - "metric": "20", - "interface": "r4-eth1", - "next-hop": "r5", - "parent": "r3(4)", - "type": "IP6 internal", - "vertex": "2001:db8:f::3/128" - } - ] - }, - "level-2": { - "ipv4": [ - { - "vertex": "r4" - }, - { - "metric": "0", - "parent": "r4(4)", - "type": "IP internal", - "vertex": "10.0.21.0/24" - }, - { - "interface": "r4-eth0", - "metric": "10", - "next-hop": "r2", - "parent": "r4(4)", - "type": "TE-IS", - "vertex": "r2" - }, - { - "interface": "r4-eth0", - "metric": "10", - "next-hop": "r2", - "parent": "r2(4)", - "type": "IP TE", - "vertex": "10.0.21.0/24" - }, - { - "interface": "r4-eth0", - "metric": "10", - "next-hop": "r2", - "parent": "r2(4)", - "type": "IP TE", - "vertex": "10.254.0.2/32" - } - ], - "ipv6": [ - { - "vertex": "r4" - }, - { - "metric": "0", - "parent": "r4(4)", - "type": "IP6 internal", - "vertex": "2001:db8:1:2::/64" - }, - { - "interface": "r4-eth0", - "metric": "10", - "next-hop": "r2", - "parent": "r4(4)", - "type": "TE-IS", - "vertex": "r2" - }, - { - "metric": "10", - "interface": "r4-eth0", - "next-hop": "r2", - "parent": "r2(4)", - "type": "IP6 internal", - "vertex": "2001:db8:f::2/128" +[ + { + "area": "1", + "algorithm": 0, + "level-1": { + "ipv4-paths": [ + { + "Vertex": "r4" + }, + { + "Metric": 0, + "Parent": "r4(4)", + "Type": "IP internal", + "Vertex": "10.0.11.0/24" + }, + { + "Interface": "r4-eth1", + "Metric": 10, + "Next-Hop": "r5", + "Parent": "r4(4)", + "Type": "TE-IS", + "Vertex": "r5" + }, + { + "Interface": "r4-eth1", + "Metric": 10, + "Next-Hop": "r5", + "Parent": "r5(4)", + "Type": "IP TE", + "Vertex": "10.0.10.0/24" + }, + { + "Interface": "r4-eth1", + "Metric": 10, + "Next-Hop": "r5", + "Parent": "r5(4)", + "Type": "IP TE", + "Vertex": "10.0.11.0/24" + }, + { + "Interface": "r4-eth1", + "Metric": 10, + "Next-Hop": "r5", + "Parent": "r5(4)", + "Type": "IP TE", + "Vertex": "10.254.0.5/32" + }, + { + "Interface": "r4-eth1", + "Metric": 20, + "Next-Hop": "r5", + "Type": "TE-IS", + "Vertex": "r3" + }, + { + "Interface": "r4-eth1", + "Metric": 20, + "Next-Hop": "r5", + "Parent": "r3(4)", + "Type": "IP TE", + "Vertex": "10.0.20.0/24" + }, + { + "Interface": "r4-eth1", + "Metric": 20, + "Next-Hop": "r5", + "Parent": "r3(4)", + "Type": "IP TE", + "Vertex": "10.254.0.3/32" + } + ], + "ipv6-paths": [ + { + "Vertex": "r4" + }, + { + "Metric": 0, + "Parent": "r4(4)", + "Type": "IP6 internal", + "Vertex": "2001:db8:2:2::/64" + }, + { + "Interface": "r4-eth1", + "Metric": 10, + "Next-Hop": "r5", + "Parent": "r4(4)", + "Type": "TE-IS", + "Vertex": "r5" + }, + { + "Metric": 10, + "Interface": "r4-eth1", + "Next-Hop": "r5", + "Parent": "r5(4)", + "Type": "IP6 internal", + "Vertex": "2001:db8:2:1::/64" + }, + { + "Metric": 10, + "Interface": "r4-eth1", + "Next-Hop": "r5", + "Parent": "r5(4)", + "Type": "IP6 internal", + "Vertex": "2001:db8:f::5/128" + }, + { + "Interface": "r4-eth1", + "Metric": 20, + "Next-Hop": "r5", + "Type": "TE-IS", + "Vertex": "r3" + }, + { + "Metric": 20, + "Interface": "r4-eth1", + "Next-Hop": "r5", + "Parent": "r3(4)", + "Type": "IP6 internal", + "Vertex": "2001:db8:1:1::/64" + }, + { + "Metric": 20, + "Interface": "r4-eth1", + "Next-Hop": "r5", + "Parent": "r3(4)", + "Type": "IP6 internal", + "Vertex": "2001:db8:f::3/128" + } + ] + }, + "level-2": { + "ipv4-paths": [ + { + "Vertex": "r4" + }, + { + "Metric": 0, + "Parent": "r4(4)", + "Type": "IP internal", + "Vertex": "10.0.21.0/24" + }, + { + "Interface": "r4-eth0", + "Metric": 10, + "Next-Hop": "r2", + "Parent": "r4(4)", + "Type": "TE-IS", + "Vertex": "r2" + }, + { + "Interface": "r4-eth0", + "Metric": 10, + "Next-Hop": "r2", + "Parent": "r2(4)", + "Type": "IP TE", + "Vertex": "10.0.21.0/24" + }, + { + "Interface": "r4-eth0", + "Metric": 10, + "Next-Hop": "r2", + "Parent": "r2(4)", + "Type": "IP TE", + "Vertex": "10.254.0.2/32" + } + ], + "ipv6-paths": [ + { + "Vertex": "r4" + }, + { + "Metric": 0, + "Parent": "r4(4)", + "Type": "IP6 internal", + "Vertex": "2001:db8:1:2::/64" + }, + { + "Interface": "r4-eth0", + "Metric": 10, + "Next-Hop": "r2", + "Parent": "r4(4)", + "Type": "TE-IS", + "Vertex": "r2" + }, + { + "Metric": 10, + "Interface": "r4-eth0", + "Next-Hop": "r2", + "Parent": "r2(4)", + "Type": "IP6 internal", + "Vertex": "2001:db8:f::2/128" + } + ] } - ] } - } -} +] diff --git a/tests/topotests/isis_topo1/r5/r5_topology.json b/tests/topotests/isis_topo1/r5/r5_topology.json index 3d887b7cea..37da1a08e3 100644 --- a/tests/topotests/isis_topo1/r5/r5_topology.json +++ b/tests/topotests/isis_topo1/r5/r5_topology.json @@ -1,156 +1,154 @@ -{ - "1": { - "level-1": { - "ipv4": [ - { - "vertex": "r5" - }, - { - "metric": "0", - "parent": "r5(4)", - "type": "IP internal", - "vertex": "10.0.10.0/24" - }, - { - "metric": "0", - "parent": "r5(4)", - "type": "IP internal", - "vertex": "10.0.11.0/24" - }, - { - "interface": "r5-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r5(4)", - "type": "TE-IS", - "vertex": "r3" - }, - { - "interface": "r5-eth1", - "metric": "10", - "next-hop": "r4", - "parent": "r5(4)", - "type": "TE-IS", - "vertex": "r4" - }, - { - "interface": "r5-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r3(4)", - "type": "IP TE", - "vertex": "10.0.10.0/24" - }, - { - "interface": "r5-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r3(4)", - "type": "IP TE", - "vertex": "10.0.20.0/24" - }, - { - "interface": "r5-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r3(4)", - "type": "IP TE", - "vertex": "10.254.0.3/32" - }, - { - "interface": "r5-eth1", - "metric": "10", - "next-hop": "r4", - "parent": "r4(4)", - "type": "IP TE", - "vertex": "10.0.11.0/24" - }, - { - "interface": "r5-eth1", - "metric": "10", - "next-hop": "r4", - "parent": "r4(4)", - "type": "IP TE", - "vertex": "10.0.21.0/24" - }, - { - "interface": "r5-eth1", - "metric": "10", - "next-hop": "r4", - "parent": "r4(4)", - "type": "IP TE", - "vertex": "10.254.0.4/32" +[ + { + "area": "1", + "algorithm": 0, + "level-1": { + "ipv4-paths": [ + { + "Vertex": "r5" + }, + { + "Metric": 0, + "Parent": "r5(4)", + "Type": "IP internal", + "Vertex": "10.0.10.0/24" + }, + { + "Metric": 0, + "Parent": "r5(4)", + "Type": "IP internal", + "Vertex": "10.0.11.0/24" + }, + { + "Interface": "r5-eth0", + "Metric": 10, + "Next-Hop": "r3", + "Parent": "r5(4)", + "Type": "TE-IS", + "Vertex": "r3" + }, + { + "Interface": "r5-eth1", + "Metric": 10, + "Next-Hop": "r4", + "Parent": "r5(4)", + "Type": "TE-IS", + "Vertex": "r4" + }, + { + "Interface": "r5-eth0", + "Metric": 10, + "Next-Hop": "r3", + "Parent": "r3(4)", + "Type": "IP TE", + "Vertex": "10.0.10.0/24" + }, + { + "Interface": "r5-eth0", + "Metric": 10, + "Next-Hop": "r3", + "Parent": "r3(4)", + "Type": "IP TE", + "Vertex": "10.0.20.0/24" + }, + { + "Interface": "r5-eth0", + "Metric": 10, + "Next-Hop": "r3", + "Parent": "r3(4)", + "Type": "IP TE", + "Vertex": "10.254.0.3/32" + }, + { + "Interface": "r5-eth1", + "Metric": 10, + "Next-Hop": "r4", + "Parent": "r4(4)", + "Type": "IP TE", + "Vertex": "10.0.11.0/24" + }, + { + "Interface": "r5-eth1", + "Metric": 10, + "Next-Hop": "r4", + "Parent": "r4(4)", + "Type": "IP TE", + "Vertex": "10.0.21.0/24" + }, + { + "Interface": "r5-eth1", + "Metric": 10, + "Next-Hop": "r4", + "Parent": "r4(4)", + "Type": "IP TE", + "Vertex": "10.254.0.4/32" + } + ], + "ipv6-paths": [ + { + "Vertex": "r5" + }, + { + "Metric": 0, + "Parent": "r5(4)", + "Type": "IP6 internal", + "Vertex": "2001:db8:2:1::/64" + }, + { + "Metric": 0, + "Parent": "r5(4)", + "Type": "IP6 internal", + "Vertex": "2001:db8:2:2::/64" + }, + { + "Interface": "r5-eth0", + "Metric": 10, + "Next-Hop": "r3", + "Parent": "r5(4)", + "Type": "TE-IS", + "Vertex": "r3" + }, + { + "Interface": "r5-eth1", + "Metric": 10, + "Next-Hop": "r4", + "Parent": "r5(4)", + "Type": "TE-IS", + "Vertex": "r4" + }, + { + "Metric": 10, + "Interface": "r5-eth0", + "Next-Hop": "r3", + "Parent": "r3(4)", + "Type": "IP6 internal", + "Vertex": "2001:db8:1:1::/64" + }, + { + "Metric": 10, + "Interface": "r5-eth0", + "Next-Hop": "r3", + "Parent": "r3(4)", + "Type": "IP6 internal", + "Vertex": "2001:db8:f::3/128" + }, + { + "Metric": 10, + "Interface": "r5-eth1", + "Next-Hop": "r4", + "Parent": "r4(4)", + "Type": "IP6 internal", + "Vertex": "2001:db8:1:2::/64" + }, + { + "Metric": 10, + "Interface": "r5-eth1", + "Next-Hop": "r4", + "Parent": "r4(4)", + "Type": "IP6 internal", + "Vertex": "2001:db8:f::4/128" + } + ] } - ], - "ipv6": [ - { - "vertex": "r5" - }, - { - "metric": "0", - "parent": "r5(4)", - "type": "IP6 internal", - "vertex": "2001:db8:2:1::/64" - }, - { - "metric": "0", - "parent": "r5(4)", - "type": "IP6 internal", - "vertex": "2001:db8:2:2::/64" - }, - { - "interface": "r5-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r5(4)", - "type": "TE-IS", - "vertex": "r3" - }, - { - "interface": "r5-eth1", - "metric": "10", - "next-hop": "r4", - "parent": "r5(4)", - "type": "TE-IS", - "vertex": "r4" - }, - { - "metric": "10", - "interface": "r5-eth0", - "next-hop": "r3", - "parent": "r3(4)", - "type": "IP6 internal", - "vertex": "2001:db8:1:1::/64" - }, - { - "metric": "10", - "interface": "r5-eth0", - "next-hop": "r3", - "parent": "r3(4)", - "type": "IP6 internal", - "vertex": "2001:db8:f::3/128" - }, - { - "metric": "10", - "interface": "r5-eth1", - "next-hop": "r4", - "parent": "r4(4)", - "type": "IP6 internal", - "vertex": "2001:db8:1:2::/64" - }, - { - "metric": "10", - "interface": "r5-eth1", - "next-hop": "r4", - "parent": "r4(4)", - "type": "IP6 internal", - "vertex": "2001:db8:f::4/128" - } - ] - }, - "level-2": { - "ipv4": [], - "ipv6": [] } - } -} +] diff --git a/tests/topotests/isis_topo1/test_isis_topo1.py b/tests/topotests/isis_topo1/test_isis_topo1.py index cea284963d..8b6fb98612 100644 --- a/tests/topotests/isis_topo1/test_isis_topo1.py +++ b/tests/topotests/isis_topo1/test_isis_topo1.py @@ -120,19 +120,13 @@ def test_isis_convergence(): pytest.skip(tgen.errors) logger.info("waiting for ISIS protocol to converge") - # Code to generate the json files. - # for rname, router in tgen.routers().items(): - # open('/tmp/{}_topology.json'.format(rname), 'w').write( - # json.dumps(show_isis_topology(router), indent=2, sort_keys=True) - # ) - for rname, router in tgen.routers().items(): filename = "{0}/{1}/{1}_topology.json".format(CWD, rname) expected = json.loads(open(filename).read()) def compare_isis_topology(router, expected): "Helper function to test ISIS topology convergence." - actual = show_isis_topology(router) + actual = json.loads(router.vtysh_cmd("show isis topology json")) return topotest.json_cmp(actual, expected) test_func = functools.partial(compare_isis_topology, router, expected) @@ -845,52 +839,3 @@ def parse_topology(lines, level): continue return areas - - -def show_isis_topology(router): - """ - Get the ISIS topology in a dictionary format. - - Sample: - { - 'area-name': { - 'level-1': [ - { - 'vertex': 'r1' - } - ], - 'level-2': [ - { - 'vertex': '10.0.0.1/24', - 'type': 'IP', - 'parent': '0', - 'metric': 'internal' - } - ] - }, - 'area-name-2': { - 'level-2': [ - { - "interface": "rX-ethY", - "metric": "Z", - "next-hop": "rA", - "parent": "rC(B)", - "type": "TE-IS", - "vertex": "rD" - } - ] - } - } - """ - l1out = topotest.normalize_text( - router.vtysh_cmd("show isis topology level-1") - ).splitlines() - l2out = topotest.normalize_text( - router.vtysh_cmd("show isis topology level-2") - ).splitlines() - - l1 = parse_topology(l1out, "level-1") - l2 = parse_topology(l2out, "level-2") - - dict_merge(l1, l2) - return l1 From ea6ad95ab578dbbb90c263ea4ed65b3ab392f709 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Fri, 14 Jun 2024 16:22:56 +0200 Subject: [PATCH 110/347] topotests: isis_topo1_vrf, align json support on 'show isis topology' command Add the json support from ISIS vty command. > show isis vrf vrf1 topology json Signed-off-by: Philippe Guibert --- .../isis_topo1_vrf/r1/r1_topology.json | 156 +++++----- .../isis_topo1_vrf/r2/r2_topology.json | 156 +++++----- .../isis_topo1_vrf/r3/r3_topology.json | 274 +++++++++--------- .../isis_topo1_vrf/r4/r4_topology.json | 274 +++++++++--------- .../isis_topo1_vrf/r5/r5_topology.json | 242 ++++++++-------- .../isis_topo1_vrf/test_isis_topo1_vrf.py | 54 +--- 6 files changed, 571 insertions(+), 585 deletions(-) diff --git a/tests/topotests/isis_topo1_vrf/r1/r1_topology.json b/tests/topotests/isis_topo1_vrf/r1/r1_topology.json index 666fa52b19..8d4ccc84cc 100644 --- a/tests/topotests/isis_topo1_vrf/r1/r1_topology.json +++ b/tests/topotests/isis_topo1_vrf/r1/r1_topology.json @@ -1,80 +1,82 @@ -{ - "1": { - "level-1": { - "ipv4": [ - { - "vertex": "r1" - } - ], - "ipv6": [ - { - "vertex": "r1" - } - ] - }, - "level-2": { - "ipv4": [ - { - "vertex": "r1" - }, - { - "metric": "0", - "parent": "r1(4)", - "type": "IP internal", - "vertex": "10.0.20.0/24" - }, - { - "interface": "r1-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r1(4)", - "type": "TE-IS", - "vertex": "r3" - }, - { - "interface": "r1-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r3(4)", - "type": "IP TE", - "vertex": "10.0.20.0/24" - }, - { - "interface": "r1-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r3(4)", - "type": "IP TE", - "vertex": "10.0.10.0/24" - } - ], - "ipv6": [ - { - "vertex": "r1" - }, - { - "metric": "0", - "parent": "r1(4)", - "type": "IP6 internal", - "vertex": "2001:db8:1:1::/64" - }, - { - "interface": "r1-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r1(4)", - "type": "TE-IS", - "vertex": "r3" +[ + { + "area": "1", + "algorithm": 0, + "level-1": { + "ipv4-paths": [ + { + "Vertex": "r1" + } + ], + "ipv6-paths": [ + { + "Vertex": "r1" + } + ] }, - { - "metric": "10", - "interface": "r1-eth0", - "next-hop": "r3", - "parent": "r3(4)", - "type": "IP6 internal", - "vertex": "2001:db8:2:1::/64" + "level-2": { + "ipv4-paths": [ + { + "Vertex": "r1" + }, + { + "Metric": 0, + "Parent": "r1(4)", + "Type": "IP internal", + "Vertex": "10.0.20.0/24" + }, + { + "Interface": "r1-eth0", + "Metric": 10, + "Next-Hop": "r3", + "Parent": "r1(4)", + "Type": "TE-IS", + "Vertex": "r3" + }, + { + "Interface": "r1-eth0", + "Metric": 10, + "Next-Hop": "r3", + "Parent": "r3(4)", + "Type": "IP TE", + "Vertex": "10.0.10.0/24" + }, + { + "Interface": "r1-eth0", + "Metric": 10, + "Next-Hop": "r3", + "Parent": "r3(4)", + "Type": "IP TE", + "Vertex": "10.0.20.0/24" + } + ], + "ipv6-paths": [ + { + "Vertex": "r1" + }, + { + "Metric": 0, + "Parent": "r1(4)", + "Type": "IP6 internal", + "Vertex": "2001:db8:1:1::/64" + }, + { + "Interface": "r1-eth0", + "Metric": 10, + "Next-Hop": "r3", + "Parent": "r1(4)", + "Type": "TE-IS", + "Vertex": "r3" + }, + { + "Metric": 10, + "Interface": "r1-eth0", + "Next-Hop": "r3", + "Parent": "r3(4)", + "Type": "IP6 internal", + "Vertex": "2001:db8:2:1::/64" + } + ] } - ] } - } -} +] diff --git a/tests/topotests/isis_topo1_vrf/r2/r2_topology.json b/tests/topotests/isis_topo1_vrf/r2/r2_topology.json index c26ad1ee37..dc87c42822 100644 --- a/tests/topotests/isis_topo1_vrf/r2/r2_topology.json +++ b/tests/topotests/isis_topo1_vrf/r2/r2_topology.json @@ -1,80 +1,82 @@ -{ - "1": { - "level-1": { - "ipv4": [ - { - "vertex": "r2" - } - ], - "ipv6": [ - { - "vertex": "r2" - } - ] - }, - "level-2": { - "ipv4": [ - { - "vertex": "r2" - }, - { - "metric": "0", - "parent": "r2(4)", - "type": "IP internal", - "vertex": "10.0.21.0/24" - }, - { - "interface": "r2-eth0", - "metric": "10", - "next-hop": "r4", - "parent": "r2(4)", - "type": "TE-IS", - "vertex": "r4" - }, - { - "interface": "r2-eth0", - "metric": "10", - "next-hop": "r4", - "parent": "r4(4)", - "type": "IP TE", - "vertex": "10.0.21.0/24" - }, - { - "interface": "r2-eth0", - "metric": "10", - "next-hop": "r4", - "parent": "r4(4)", - "type": "IP TE", - "vertex": "10.0.11.0/24" - } - ], - "ipv6": [ - { - "vertex": "r2" - }, - { - "metric": "0", - "parent": "r2(4)", - "type": "IP6 internal", - "vertex": "2001:db8:1:2::/64" - }, - { - "interface": "r2-eth0", - "metric": "10", - "next-hop": "r4", - "parent": "r2(4)", - "type": "TE-IS", - "vertex": "r4" +[ + { + "area": "1", + "algorithm": 0, + "level-1": { + "ipv4-paths": [ + { + "Vertex": "r2" + } + ], + "ipv6-paths": [ + { + "Vertex": "r2" + } + ] }, - { - "metric": "10", - "interface": "r2-eth0", - "next-hop": "r4", - "parent": "r4(4)", - "type": "IP6 internal", - "vertex": "2001:db8:2:2::/64" + "level-2": { + "ipv4-paths": [ + { + "Vertex": "r2" + }, + { + "Metric": 0, + "Parent": "r2(4)", + "Type": "IP internal", + "Vertex": "10.0.21.0/24" + }, + { + "Interface": "r2-eth0", + "Metric": 10, + "Next-Hop": "r4", + "Parent": "r2(4)", + "Type": "TE-IS", + "Vertex": "r4" + }, + { + "Interface": "r2-eth0", + "Metric": 10, + "Next-Hop": "r4", + "Parent": "r4(4)", + "Type": "IP TE", + "Vertex": "10.0.11.0/24" + }, + { + "Interface": "r2-eth0", + "Metric": 10, + "Next-Hop": "r4", + "Parent": "r4(4)", + "Type": "IP TE", + "Vertex": "10.0.21.0/24" + } + ], + "ipv6-paths": [ + { + "Vertex": "r2" + }, + { + "Metric": 0, + "Parent": "r2(4)", + "Type": "IP6 internal", + "Vertex": "2001:db8:1:2::/64" + }, + { + "Interface": "r2-eth0", + "Metric": 10, + "Next-Hop": "r4", + "Parent": "r2(4)", + "Type": "TE-IS", + "Vertex": "r4" + }, + { + "Metric": 10, + "Interface": "r2-eth0", + "Next-Hop": "r4", + "Parent": "r4(4)", + "Type": "IP6 internal", + "Vertex": "2001:db8:2:2::/64" + } + ] } - ] } - } -} +] diff --git a/tests/topotests/isis_topo1_vrf/r3/r3_topology.json b/tests/topotests/isis_topo1_vrf/r3/r3_topology.json index 044a6c0438..602dc7df55 100644 --- a/tests/topotests/isis_topo1_vrf/r3/r3_topology.json +++ b/tests/topotests/isis_topo1_vrf/r3/r3_topology.json @@ -1,132 +1,148 @@ -{ - "1": { - "level-1": { - "ipv4": [ - { - "vertex": "r3" +[ + { + "area": "1", + "algorithm": 0, + "level-1": { + "ipv4-paths": [ + { + "Vertex": "r3" + }, + { + "Metric": 0, + "Parent": "r3(4)", + "Type": "IP internal", + "Vertex": "10.0.10.0/24" + }, + { + "Interface": "r3-eth1", + "Metric": 10, + "Next-Hop": "r5", + "Parent": "r3(4)", + "Type": "TE-IS", + "Vertex": "r5" + }, + { + "Interface": "r3-eth1", + "Metric": 10, + "Next-Hop": "r5", + "Parent": "r5(4)", + "Type": "IP TE", + "Vertex": "10.0.10.0/24" + }, + { + "Interface": "r3-eth1", + "Metric": 10, + "Next-Hop": "r5", + "Parent": "r5(4)", + "Type": "IP TE", + "Vertex": "10.0.11.0/24" + }, + { + "Interface": "r3-eth1", + "Metric": 20, + "Next-Hop": "r5", + "Type": "TE-IS", + "Vertex": "r4" + }, + { + "Interface": "r3-eth1", + "Metric": 20, + "Next-Hop": "r5", + "Parent": "r4(4)", + "Type": "IP TE", + "Vertex": "10.0.21.0/24" + } + ], + "ipv6-paths": [ + { + "Vertex": "r3" + }, + { + "Metric": 0, + "Parent": "r3(4)", + "Type": "IP6 internal", + "Vertex": "2001:db8:2:1::/64" + }, + { + "Interface": "r3-eth1", + "Metric": 10, + "Next-Hop": "r5", + "Parent": "r3(4)", + "Type": "TE-IS", + "Vertex": "r5" + }, + { + "Metric": 10, + "Interface": "r3-eth1", + "Next-Hop": "r5", + "Parent": "r5(4)", + "Type": "IP6 internal", + "Vertex": "2001:db8:2:2::/64" + }, + { + "Interface": "r3-eth1", + "Metric": 20, + "Next-Hop": "r5", + "Type": "TE-IS", + "Vertex": "r4" + }, + { + "Metric": 20, + "Interface": "r3-eth1", + "Next-Hop": "r5", + "Parent": "r4(4)", + "Type": "IP6 internal", + "Vertex": "2001:db8:1:2::/64" + } + ] }, - { - "metric": "0", - "parent": "r3(4)", - "type": "IP internal", - "vertex": "10.0.10.0/24" - }, - { - "interface": "r3-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r3(4)", - "type": "TE-IS", - "vertex": "r5" - }, - { - "interface": "r3-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r5(4)", - "type": "IP TE", - "vertex": "10.0.10.0/24" - }, - { - "interface": "r3-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r5(4)", - "type": "IP TE", - "vertex": "10.0.11.0/24" - }, - { - "interface": "r3-eth1", - "metric": "20", - "next-hop": "r5", - "parent": "r4(4)", - "type": "IP TE", - "vertex": "10.0.21.0/24" - } - ], - "ipv6": [ - { - "vertex": "r3" - }, - { - "metric": "0", - "parent": "r3(4)", - "type": "IP6 internal", - "vertex": "2001:db8:2:1::/64" - }, - { - "interface": "r3-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r3(4)", - "type": "TE-IS", - "vertex": "r5" - }, - { - "metric": "10", - "interface": "r3-eth1", - "next-hop": "r5", - "parent": "r5(4)", - "type": "IP6 internal", - "vertex": "2001:db8:2:2::/64" - }, - { - "metric": "20", - "interface": "r3-eth1", - "next-hop": "r5", - "parent": "r4(4)", - "type": "IP6 internal", - "vertex": "2001:db8:1:2::/64" - } - ] - }, - "level-2": { - "ipv4": [ - { - "vertex": "r3" - }, - { - "metric": "0", - "parent": "r3(4)", - "type": "IP internal", - "vertex": "10.0.20.0/24" - }, - { - "interface": "r3-eth0", - "metric": "10", - "next-hop": "r1", - "parent": "r3(4)", - "type": "TE-IS", - "vertex": "r1" - }, - { - "interface": "r3-eth0", - "metric": "10", - "next-hop": "r1", - "parent": "r1(4)", - "type": "IP TE", - "vertex": "10.0.20.0/24" - } - ], - "ipv6": [ - { - "vertex": "r3" - }, - { - "metric": "0", - "parent": "r3(4)", - "type": "IP6 internal", - "vertex": "2001:db8:1:1::/64" - }, - { - "interface": "r3-eth0", - "metric": "10", - "next-hop": "r1", - "parent": "r3(4)", - "type": "TE-IS", - "vertex": "r1" + "level-2": { + "ipv4-paths": [ + { + "Vertex": "r3" + }, + { + "Metric": 0, + "Parent": "r3(4)", + "Type": "IP internal", + "Vertex": "10.0.20.0/24" + }, + { + "Interface": "r3-eth0", + "Metric": 10, + "Next-Hop": "r1", + "Parent": "r3(4)", + "Type": "TE-IS", + "Vertex": "r1" + }, + { + "Interface": "r3-eth0", + "Metric": 10, + "Next-Hop": "r1", + "Parent": "r1(4)", + "Type": "IP TE", + "Vertex": "10.0.20.0/24" + } + ], + "ipv6-paths": [ + { + "Vertex": "r3" + }, + { + "Metric": 0, + "Parent": "r3(4)", + "Type": "IP6 internal", + "Vertex": "2001:db8:1:1::/64" + }, + { + "Interface": "r3-eth0", + "Metric": 10, + "Next-Hop": "r1", + "Parent": "r3(4)", + "Type": "TE-IS", + "Vertex": "r1" + } + ] } - ] } - } -} +] diff --git a/tests/topotests/isis_topo1_vrf/r4/r4_topology.json b/tests/topotests/isis_topo1_vrf/r4/r4_topology.json index d40008aa30..f4c1bb3768 100644 --- a/tests/topotests/isis_topo1_vrf/r4/r4_topology.json +++ b/tests/topotests/isis_topo1_vrf/r4/r4_topology.json @@ -1,132 +1,148 @@ -{ - "1": { - "level-1": { - "ipv4": [ - { - "vertex": "r4" +[ + { + "area": "1", + "algorithm": 0, + "level-1": { + "ipv4-paths": [ + { + "Vertex": "r4" + }, + { + "Metric": 0, + "Parent": "r4(4)", + "Type": "IP internal", + "Vertex": "10.0.11.0/24" + }, + { + "Interface": "r4-eth1", + "Metric": 10, + "Next-Hop": "r5", + "Parent": "r4(4)", + "Type": "TE-IS", + "Vertex": "r5" + }, + { + "Interface": "r4-eth1", + "Metric": 10, + "Next-Hop": "r5", + "Parent": "r5(4)", + "Type": "IP TE", + "Vertex": "10.0.10.0/24" + }, + { + "Interface": "r4-eth1", + "Metric": 10, + "Next-Hop": "r5", + "Parent": "r5(4)", + "Type": "IP TE", + "Vertex": "10.0.11.0/24" + }, + { + "Interface": "r4-eth1", + "Metric": 20, + "Next-Hop": "r5", + "Type": "TE-IS", + "Vertex": "r3" + }, + { + "Interface": "r4-eth1", + "Metric": 20, + "Next-Hop": "r5", + "Parent": "r3(4)", + "Type": "IP TE", + "Vertex": "10.0.20.0/24" + } + ], + "ipv6-paths": [ + { + "Vertex": "r4" + }, + { + "Metric": 0, + "Parent": "r4(4)", + "Type": "IP6 internal", + "Vertex": "2001:db8:2:2::/64" + }, + { + "Interface": "r4-eth1", + "Metric": 10, + "Next-Hop": "r5", + "Parent": "r4(4)", + "Type": "TE-IS", + "Vertex": "r5" + }, + { + "Metric": 10, + "Interface": "r4-eth1", + "Next-Hop": "r5", + "Parent": "r5(4)", + "Type": "IP6 internal", + "Vertex": "2001:db8:2:1::/64" + }, + { + "Interface": "r4-eth1", + "Metric": 20, + "Next-Hop": "r5", + "Type": "TE-IS", + "Vertex": "r3" + }, + { + "Metric": 20, + "Interface": "r4-eth1", + "Next-Hop": "r5", + "Parent": "r3(4)", + "Type": "IP6 internal", + "Vertex": "2001:db8:1:1::/64" + } + ] }, - { - "metric": "0", - "parent": "r4(4)", - "type": "IP internal", - "vertex": "10.0.11.0/24" - }, - { - "interface": "r4-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r4(4)", - "type": "TE-IS", - "vertex": "r5" - }, - { - "interface": "r4-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r5(4)", - "type": "IP TE", - "vertex": "10.0.10.0/24" - }, - { - "interface": "r4-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r5(4)", - "type": "IP TE", - "vertex": "10.0.11.0/24" - }, - { - "interface": "r4-eth1", - "metric": "20", - "next-hop": "r5", - "parent": "r3(4)", - "type": "IP TE", - "vertex": "10.0.20.0/24" - } - ], - "ipv6": [ - { - "vertex": "r4" - }, - { - "metric": "0", - "parent": "r4(4)", - "type": "IP6 internal", - "vertex": "2001:db8:2:2::/64" - }, - { - "interface": "r4-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r4(4)", - "type": "TE-IS", - "vertex": "r5" - }, - { - "metric": "10", - "interface": "r4-eth1", - "next-hop": "r5", - "parent": "r5(4)", - "type": "IP6 internal", - "vertex": "2001:db8:2:1::/64" - }, - { - "metric": "20", - "interface": "r4-eth1", - "next-hop": "r5", - "parent": "r3(4)", - "type": "IP6 internal", - "vertex": "2001:db8:1:1::/64" - } - ] - }, - "level-2": { - "ipv4": [ - { - "vertex": "r4" - }, - { - "metric": "0", - "parent": "r4(4)", - "type": "IP internal", - "vertex": "10.0.21.0/24" - }, - { - "interface": "r4-eth0", - "metric": "10", - "next-hop": "r2", - "parent": "r4(4)", - "type": "TE-IS", - "vertex": "r2" - }, - { - "interface": "r4-eth0", - "metric": "10", - "next-hop": "r2", - "parent": "r2(4)", - "type": "IP TE", - "vertex": "10.0.21.0/24" - } - ], - "ipv6": [ - { - "vertex": "r4" - }, - { - "metric": "0", - "parent": "r4(4)", - "type": "IP6 internal", - "vertex": "2001:db8:1:2::/64" - }, - { - "interface": "r4-eth0", - "metric": "10", - "next-hop": "r2", - "parent": "r4(4)", - "type": "TE-IS", - "vertex": "r2" + "level-2": { + "ipv4-paths": [ + { + "Vertex": "r4" + }, + { + "Metric": 0, + "Parent": "r4(4)", + "Type": "IP internal", + "Vertex": "10.0.21.0/24" + }, + { + "Interface": "r4-eth0", + "Metric": 10, + "Next-Hop": "r2", + "Parent": "r4(4)", + "Type": "TE-IS", + "Vertex": "r2" + }, + { + "Interface": "r4-eth0", + "Metric": 10, + "Next-Hop": "r2", + "Parent": "r2(4)", + "Type": "IP TE", + "Vertex": "10.0.21.0/24" + } + ], + "ipv6-paths": [ + { + "Vertex": "r4" + }, + { + "Metric": 0, + "Parent": "r4(4)", + "Type": "IP6 internal", + "Vertex": "2001:db8:1:2::/64" + }, + { + "Interface": "r4-eth0", + "Metric": 10, + "Next-Hop": "r2", + "Parent": "r4(4)", + "Type": "TE-IS", + "Vertex": "r2" + } + ] } - ] } - } -} +] diff --git a/tests/topotests/isis_topo1_vrf/r5/r5_topology.json b/tests/topotests/isis_topo1_vrf/r5/r5_topology.json index 2a088cae30..669f31c474 100644 --- a/tests/topotests/isis_topo1_vrf/r5/r5_topology.json +++ b/tests/topotests/isis_topo1_vrf/r5/r5_topology.json @@ -1,124 +1,122 @@ -{ - "1": { - "level-1": { - "ipv4": [ - { - "vertex": "r5" - }, - { - "metric": "0", - "parent": "r5(4)", - "type": "IP internal", - "vertex": "10.0.10.0/24" - }, - { - "metric": "0", - "parent": "r5(4)", - "type": "IP internal", - "vertex": "10.0.11.0/24" - }, - { - "interface": "r5-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r5(4)", - "type": "TE-IS", - "vertex": "r3" - }, - { - "interface": "r5-eth1", - "metric": "10", - "next-hop": "r4", - "parent": "r5(4)", - "type": "TE-IS", - "vertex": "r4" - }, - { - "interface": "r5-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r3(4)", - "type": "IP TE", - "vertex": "10.0.20.0/24" - }, - { - "interface": "r5-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r3(4)", - "type": "IP TE", - "vertex": "10.0.10.0/24" - }, - { - "interface": "r5-eth1", - "metric": "10", - "next-hop": "r4", - "parent": "r4(4)", - "type": "IP TE", - "vertex": "10.0.21.0/24" - }, - { - "interface": "r5-eth1", - "metric": "10", - "next-hop": "r4", - "parent": "r4(4)", - "type": "IP TE", - "vertex": "10.0.11.0/24" +[ + { + "area": "1", + "algorithm": 0, + "level-1": { + "ipv4-paths": [ + { + "Vertex": "r5" + }, + { + "Metric": 0, + "Parent": "r5(4)", + "Type": "IP internal", + "Vertex": "10.0.10.0/24" + }, + { + "Metric": 0, + "Parent": "r5(4)", + "Type": "IP internal", + "Vertex": "10.0.11.0/24" + }, + { + "Interface": "r5-eth0", + "Metric": 10, + "Next-Hop": "r3", + "Parent": "r5(4)", + "Type": "TE-IS", + "Vertex": "r3" + }, + { + "Interface": "r5-eth1", + "Metric": 10, + "Next-Hop": "r4", + "Parent": "r5(4)", + "Type": "TE-IS", + "Vertex": "r4" + }, + { + "Interface": "r5-eth0", + "Metric": 10, + "Next-Hop": "r3", + "Parent": "r3(4)", + "Type": "IP TE", + "Vertex": "10.0.10.0/24" + }, + { + "Interface": "r5-eth0", + "Metric": 10, + "Next-Hop": "r3", + "Parent": "r3(4)", + "Type": "IP TE", + "Vertex": "10.0.20.0/24" + }, + { + "Interface": "r5-eth1", + "Metric": 10, + "Next-Hop": "r4", + "Parent": "r4(4)", + "Type": "IP TE", + "Vertex": "10.0.11.0/24" + }, + { + "Interface": "r5-eth1", + "Metric": 10, + "Next-Hop": "r4", + "Parent": "r4(4)", + "Type": "IP TE", + "Vertex": "10.0.21.0/24" + } + ], + "ipv6-paths": [ + { + "Vertex": "r5" + }, + { + "Metric": 0, + "Parent": "r5(4)", + "Type": "IP6 internal", + "Vertex": "2001:db8:2:1::/64" + }, + { + "Metric": 0, + "Parent": "r5(4)", + "Type": "IP6 internal", + "Vertex": "2001:db8:2:2::/64" + }, + { + "Interface": "r5-eth0", + "Metric": 10, + "Next-Hop": "r3", + "Parent": "r5(4)", + "Type": "TE-IS", + "Vertex": "r3" + }, + { + "Interface": "r5-eth1", + "Metric": 10, + "Next-Hop": "r4", + "Parent": "r5(4)", + "Type": "TE-IS", + "Vertex": "r4" + }, + { + "Metric": 10, + "Interface": "r5-eth0", + "Next-Hop": "r3", + "Parent": "r3(4)", + "Type": "IP6 internal", + "Vertex": "2001:db8:1:1::/64" + }, + { + "Metric": 10, + "Interface": "r5-eth1", + "Next-Hop": "r4", + "Parent": "r4(4)", + "Type": "IP6 internal", + "Vertex": "2001:db8:1:2::/64" + } + ] } - ], - "ipv6": [ - { - "vertex": "r5" - }, - { - "metric": "0", - "parent": "r5(4)", - "type": "IP6 internal", - "vertex": "2001:db8:2:1::/64" - }, - { - "metric": "0", - "parent": "r5(4)", - "type": "IP6 internal", - "vertex": "2001:db8:2:2::/64" - }, - { - "interface": "r5-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r5(4)", - "type": "TE-IS", - "vertex": "r3" - }, - { - "interface": "r5-eth1", - "metric": "10", - "next-hop": "r4", - "parent": "r5(4)", - "type": "TE-IS", - "vertex": "r4" - }, - { - "metric": "10", - "interface": "r5-eth0", - "next-hop": "r3", - "parent": "r3(4)", - "type": "IP6 internal", - "vertex": "2001:db8:1:1::/64" - }, - { - "metric": "10", - "interface": "r5-eth1", - "next-hop": "r4", - "parent": "r4(4)", - "type": "IP6 internal", - "vertex": "2001:db8:1:2::/64" - } - ] - }, - "level-2": { - "ipv4": [], - "ipv6": [] } - } -} +] diff --git a/tests/topotests/isis_topo1_vrf/test_isis_topo1_vrf.py b/tests/topotests/isis_topo1_vrf/test_isis_topo1_vrf.py index 7aac7c704d..afc6864b98 100644 --- a/tests/topotests/isis_topo1_vrf/test_isis_topo1_vrf.py +++ b/tests/topotests/isis_topo1_vrf/test_isis_topo1_vrf.py @@ -141,8 +141,9 @@ def test_isis_convergence(): def compare_isis_topology(router, expected): "Helper function to test ISIS vrf topology convergence." - actual = show_isis_topology(router) - + actual = json.loads( + router.vtysh_cmd(f"show isis vrf {router.name}-cust1 topology json") + ) return topotest.json_cmp(actual, expected) test_func = functools.partial(compare_isis_topology, router, expected) @@ -377,52 +378,3 @@ def parse_topology(lines, level): continue return areas - - -def show_isis_topology(router): - """ - Get the ISIS vrf topology in a dictionary format. - - Sample: - { - 'area-name': { - 'level-1': [ - { - 'vertex': 'r1' - } - ], - 'level-2': [ - { - 'vertex': '10.0.0.1/24', - 'type': 'IP', - 'parent': '0', - 'metric': 'internal' - } - ] - }, - 'area-name-2': { - 'level-2': [ - { - "interface": "rX-ethY", - "metric": "Z", - "next-hop": "rA", - "parent": "rC(B)", - "type": "TE-IS", - "vertex": "rD" - } - ] - } - } - """ - l1out = topotest.normalize_text( - router.vtysh_cmd("show isis vrf {}-cust1 topology level-1".format(router.name)) - ).splitlines() - l2out = topotest.normalize_text( - router.vtysh_cmd("show isis vrf {}-cust1 topology level-2".format(router.name)) - ).splitlines() - - l1 = parse_topology(l1out, "level-1") - l2 = parse_topology(l2out, "level-2") - - dict_merge(l1, l2) - return l1 From d0a142aae46789fd9a7e541e61b9b7b52ea742cd Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Wed, 19 Jun 2024 16:05:33 +0200 Subject: [PATCH 111/347] isisd: override json fields for monitored paths The json output for isis route paths should use caml format. Signed-off-by: Philippe Guibert --- isisd/isis_spf.c | 4 +- .../topotests/isis_topo1/r1/r1_topology.json | 108 ++++---- .../topotests/isis_topo1/r2/r2_topology.json | 108 ++++---- .../topotests/isis_topo1/r3/r3_topology.json | 252 +++++++++--------- .../topotests/isis_topo1/r4/r4_topology.json | 252 +++++++++--------- .../topotests/isis_topo1/r5/r5_topology.json | 204 +++++++------- .../isis_topo1_vrf/r1/r1_topology.json | 84 +++--- .../isis_topo1_vrf/r2/r2_topology.json | 84 +++--- .../isis_topo1_vrf/r3/r3_topology.json | 180 ++++++------- .../isis_topo1_vrf/r4/r4_topology.json | 180 ++++++------- .../isis_topo1_vrf/r5/r5_topology.json | 156 +++++------ 11 files changed, 807 insertions(+), 805 deletions(-) diff --git a/isisd/isis_spf.c b/isisd/isis_spf.c index 86d998c419..d6ce76960b 100644 --- a/isisd/isis_spf.c +++ b/isisd/isis_spf.c @@ -2336,7 +2336,9 @@ static void isis_print_paths(struct vty *vty, struct isis_vertex_queue *queue, vty_out(vty, "%s\n", table); XFREE(MTYPE_TMP, table); } else - *json = ttable_json(tt, "ssdsss"); + *json = ttable_json_with_json_text( + tt, "ssdsss", + "vertex|type|metric|nextHop|interface|parent"); ttable_del(tt); } diff --git a/tests/topotests/isis_topo1/r1/r1_topology.json b/tests/topotests/isis_topo1/r1/r1_topology.json index d52346df6f..6b3374cc4d 100644 --- a/tests/topotests/isis_topo1/r1/r1_topology.json +++ b/tests/topotests/isis_topo1/r1/r1_topology.json @@ -5,92 +5,92 @@ "level-1": { "ipv4-paths": [ { - "Vertex": "r1" + "vertex": "r1" } ], "ipv6-paths": [ { - "Vertex": "r1" + "vertex": "r1" } ] }, "level-2": { "ipv4-paths": [ { - "Vertex": "r1" + "vertex": "r1" }, { - "Metric": 0, - "Parent": "r1(4)", - "Type": "IP internal", - "Vertex": "10.0.20.0/24" + "metric": 0, + "parent": "r1(4)", + "type": "IP internal", + "vertex": "10.0.20.0/24" }, { - "Interface": "r1-eth0", - "Metric": 10, - "Next-Hop": "r3", - "Parent": "r1(4)", - "Type": "TE-IS", - "Vertex": "r3" + "interface": "r1-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r1(4)", + "type": "TE-IS", + "vertex": "r3" }, { - "Interface": "r1-eth0", - "Metric": 10, - "Next-Hop": "r3", - "Parent": "r3(4)", - "Type": "IP TE", - "Vertex": "10.0.10.0/24" + "interface": "r1-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r3(4)", + "type": "IP TE", + "vertex": "10.0.10.0/24" }, { - "Interface": "r1-eth0", - "Metric": 10, - "Next-Hop": "r3", - "Parent": "r3(4)", - "Type": "IP TE", - "Vertex": "10.0.20.0/24" + "interface": "r1-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r3(4)", + "type": "IP TE", + "vertex": "10.0.20.0/24" }, { - "Interface": "r1-eth0", - "Metric": 10, - "Next-Hop": "r3", - "Parent": "r3(4)", - "Type": "IP TE", - "Vertex": "10.254.0.3/32" + "interface": "r1-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r3(4)", + "type": "IP TE", + "vertex": "10.254.0.3/32" } ], "ipv6-paths": [ { - "Vertex": "r1" + "vertex": "r1" }, { - "Metric": 0, - "Parent": "r1(4)", - "Type": "IP6 internal", - "Vertex": "2001:db8:1:1::/64" + "metric": 0, + "parent": "r1(4)", + "type": "IP6 internal", + "vertex": "2001:db8:1:1::/64" }, { - "Interface": "r1-eth0", - "Metric": 10, - "Next-Hop": "r3", - "Parent": "r1(4)", - "Type": "TE-IS", - "Vertex": "r3" + "interface": "r1-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r1(4)", + "type": "TE-IS", + "vertex": "r3" }, { - "Metric": 10, - "Interface": "r1-eth0", - "Next-Hop": "r3", - "Parent": "r3(4)", - "Type": "IP6 internal", - "Vertex": "2001:db8:2:1::/64" + "metric": 10, + "interface": "r1-eth0", + "nextHop": "r3", + "parent": "r3(4)", + "type": "IP6 internal", + "vertex": "2001:db8:2:1::/64" }, { - "Metric": 10, - "Interface": "r1-eth0", - "Next-Hop": "r3", - "Parent": "r3(4)", - "Type": "IP6 internal", - "Vertex": "2001:db8:f::3/128" + "metric": 10, + "interface": "r1-eth0", + "nextHop": "r3", + "parent": "r3(4)", + "type": "IP6 internal", + "vertex": "2001:db8:f::3/128" } ] } diff --git a/tests/topotests/isis_topo1/r2/r2_topology.json b/tests/topotests/isis_topo1/r2/r2_topology.json index d0a1f90fd0..8720bc1cac 100644 --- a/tests/topotests/isis_topo1/r2/r2_topology.json +++ b/tests/topotests/isis_topo1/r2/r2_topology.json @@ -5,92 +5,92 @@ "level-1": { "ipv4-paths": [ { - "Vertex": "r2" + "vertex": "r2" } ], "ipv6-paths": [ { - "Vertex": "r2" + "vertex": "r2" } ] }, "level-2": { "ipv4-paths": [ { - "Vertex": "r2" + "vertex": "r2" }, { - "Metric": 0, - "Parent": "r2(4)", - "Type": "IP internal", - "Vertex": "10.0.21.0/24" + "metric": 0, + "parent": "r2(4)", + "type": "IP internal", + "vertex": "10.0.21.0/24" }, { - "Interface": "r2-eth0", - "Metric": 10, - "Next-Hop": "r4", - "Parent": "r2(4)", - "Type": "TE-IS", - "Vertex": "r4" + "interface": "r2-eth0", + "metric": 10, + "nextHop": "r4", + "parent": "r2(4)", + "type": "TE-IS", + "vertex": "r4" }, { - "Interface": "r2-eth0", - "Metric": 10, - "Next-Hop": "r4", - "Parent": "r4(4)", - "Type": "IP TE", - "Vertex": "10.0.11.0/24" + "interface": "r2-eth0", + "metric": 10, + "nextHop": "r4", + "parent": "r4(4)", + "type": "IP TE", + "vertex": "10.0.11.0/24" }, { - "Interface": "r2-eth0", - "Metric": 10, - "Next-Hop": "r4", - "Parent": "r4(4)", - "Type": "IP TE", - "Vertex": "10.0.21.0/24" + "interface": "r2-eth0", + "metric": 10, + "nextHop": "r4", + "parent": "r4(4)", + "type": "IP TE", + "vertex": "10.0.21.0/24" }, { - "Interface": "r2-eth0", - "Metric": 10, - "Next-Hop": "r4", - "Parent": "r4(4)", - "Type": "IP TE", - "Vertex": "10.254.0.4/32" + "interface": "r2-eth0", + "metric": 10, + "nextHop": "r4", + "parent": "r4(4)", + "type": "IP TE", + "vertex": "10.254.0.4/32" } ], "ipv6-paths": [ { - "Vertex": "r2" + "vertex": "r2" }, { - "Metric": 0, - "Parent": "r2(4)", - "Type": "IP6 internal", - "Vertex": "2001:db8:1:2::/64" + "metric": 0, + "parent": "r2(4)", + "type": "IP6 internal", + "vertex": "2001:db8:1:2::/64" }, { - "Interface": "r2-eth0", - "Metric": 10, - "Next-Hop": "r4", - "Parent": "r2(4)", - "Type": "TE-IS", - "Vertex": "r4" + "interface": "r2-eth0", + "metric": 10, + "nextHop": "r4", + "parent": "r2(4)", + "type": "TE-IS", + "vertex": "r4" }, { - "Metric": 10, - "Interface": "r2-eth0", - "Next-Hop": "r4", - "Parent": "r4(4)", - "Type": "IP6 internal", - "Vertex": "2001:db8:2:2::/64" + "metric": 10, + "interface": "r2-eth0", + "nextHop": "r4", + "parent": "r4(4)", + "type": "IP6 internal", + "vertex": "2001:db8:2:2::/64" }, { - "Metric": 10, - "Interface": "r2-eth0", - "Next-Hop": "r4", - "Parent": "r4(4)", - "Type": "IP6 internal", - "Vertex": "2001:db8:f::4/128" + "metric": 10, + "interface": "r2-eth0", + "nextHop": "r4", + "parent": "r4(4)", + "type": "IP6 internal", + "vertex": "2001:db8:f::4/128" } ] } diff --git a/tests/topotests/isis_topo1/r3/r3_topology.json b/tests/topotests/isis_topo1/r3/r3_topology.json index 9265e62786..568b6dfeed 100644 --- a/tests/topotests/isis_topo1/r3/r3_topology.json +++ b/tests/topotests/isis_topo1/r3/r3_topology.json @@ -5,190 +5,190 @@ "level-1": { "ipv4-paths": [ { - "Vertex": "r3" + "vertex": "r3" }, { - "Metric": 0, - "Parent": "r3(4)", - "Type": "IP internal", - "Vertex": "10.0.10.0/24" + "metric": 0, + "parent": "r3(4)", + "type": "IP internal", + "vertex": "10.0.10.0/24" }, { - "Interface": "r3-eth1", - "Metric": 10, - "Next-Hop": "r5", - "Parent": "r3(4)", - "Type": "TE-IS", - "Vertex": "r5" + "interface": "r3-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r3(4)", + "type": "TE-IS", + "vertex": "r5" }, { - "Interface": "r3-eth1", - "Metric": 10, - "Next-Hop": "r5", - "Parent": "r5(4)", - "Type": "IP TE", - "Vertex": "10.0.10.0/24" + "interface": "r3-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r5(4)", + "type": "IP TE", + "vertex": "10.0.10.0/24" }, { - "Interface": "r3-eth1", - "Metric": 10, - "Next-Hop": "r5", - "Parent": "r5(4)", - "Type": "IP TE", - "Vertex": "10.0.11.0/24" + "interface": "r3-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r5(4)", + "type": "IP TE", + "vertex": "10.0.11.0/24" }, { - "Interface": "r3-eth1", - "Metric": 10, - "Next-Hop": "r5", - "Parent": "r5(4)", - "Type": "IP TE", - "Vertex": "10.254.0.5/32" + "interface": "r3-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r5(4)", + "type": "IP TE", + "vertex": "10.254.0.5/32" }, { - "Interface": "r3-eth1", - "Metric": 20, - "Next-Hop": "r5", - "Type": "TE-IS", - "Vertex": "r4" + "interface": "r3-eth1", + "metric": 20, + "nextHop": "r5", + "type": "TE-IS", + "vertex": "r4" }, { - "Interface": "r3-eth1", - "Metric": 20, - "Next-Hop": "r5", - "Parent": "r4(4)", - "Type": "IP TE", - "Vertex": "10.0.21.0/24" + "interface": "r3-eth1", + "metric": 20, + "nextHop": "r5", + "parent": "r4(4)", + "type": "IP TE", + "vertex": "10.0.21.0/24" }, { - "Interface": "r3-eth1", - "Metric": 20, - "Next-Hop": "r5", - "Parent": "r4(4)", - "Type": "IP TE", - "Vertex": "10.254.0.4/32" + "interface": "r3-eth1", + "metric": 20, + "nextHop": "r5", + "parent": "r4(4)", + "type": "IP TE", + "vertex": "10.254.0.4/32" } ], "ipv6-paths": [ { - "Vertex": "r3" + "vertex": "r3" }, { - "Metric": 0, - "Parent": "r3(4)", - "Type": "IP6 internal", - "Vertex": "2001:db8:2:1::/64" + "metric": 0, + "parent": "r3(4)", + "type": "IP6 internal", + "vertex": "2001:db8:2:1::/64" }, { - "Interface": "r3-eth1", - "Metric": 10, - "Next-Hop": "r5", - "Parent": "r3(4)", - "Type": "TE-IS", - "Vertex": "r5" + "interface": "r3-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r3(4)", + "type": "TE-IS", + "vertex": "r5" }, { - "Metric": 10, - "Interface": "r3-eth1", - "Next-Hop": "r5", - "Parent": "r5(4)", - "Type": "IP6 internal", - "Vertex": "2001:db8:2:2::/64" + "metric": 10, + "interface": "r3-eth1", + "nextHop": "r5", + "parent": "r5(4)", + "type": "IP6 internal", + "vertex": "2001:db8:2:2::/64" }, { - "Metric": 10, - "Interface": "r3-eth1", - "Next-Hop": "r5", - "Parent": "r5(4)", - "Type": "IP6 internal", - "Vertex": "2001:db8:f::5/128" + "metric": 10, + "interface": "r3-eth1", + "nextHop": "r5", + "parent": "r5(4)", + "type": "IP6 internal", + "vertex": "2001:db8:f::5/128" }, { - "Interface": "r3-eth1", - "Metric": 20, - "Next-Hop": "r5", - "Type": "TE-IS", - "Vertex": "r4" + "interface": "r3-eth1", + "metric": 20, + "nextHop": "r5", + "type": "TE-IS", + "vertex": "r4" }, { - "Metric": 20, - "Interface": "r3-eth1", - "Next-Hop": "r5", - "Parent": "r4(4)", - "Type": "IP6 internal", - "Vertex": "2001:db8:1:2::/64" + "metric": 20, + "interface": "r3-eth1", + "nextHop": "r5", + "parent": "r4(4)", + "type": "IP6 internal", + "vertex": "2001:db8:1:2::/64" }, { - "Metric": 20, - "Interface": "r3-eth1", - "Next-Hop": "r5", - "Parent": "r4(4)", - "Type": "IP6 internal", - "Vertex": "2001:db8:f::4/128" + "metric": 20, + "interface": "r3-eth1", + "nextHop": "r5", + "parent": "r4(4)", + "type": "IP6 internal", + "vertex": "2001:db8:f::4/128" } ] }, "level-2": { "ipv4-paths": [ { - "Vertex": "r3" + "vertex": "r3" }, { - "Metric": 0, - "Parent": "r3(4)", - "Type": "IP internal", - "Vertex": "10.0.20.0/24" + "metric": 0, + "parent": "r3(4)", + "type": "IP internal", + "vertex": "10.0.20.0/24" }, { - "Interface": "r3-eth0", - "Metric": 10, - "Next-Hop": "r1", - "Parent": "r3(4)", - "Type": "TE-IS", - "Vertex": "r1" + "interface": "r3-eth0", + "metric": 10, + "nextHop": "r1", + "parent": "r3(4)", + "type": "TE-IS", + "vertex": "r1" }, { - "Interface": "r3-eth0", - "Metric": 10, - "Next-Hop": "r1", - "Parent": "r1(4)", - "Type": "IP TE", - "Vertex": "10.0.20.0/24" + "interface": "r3-eth0", + "metric": 10, + "nextHop": "r1", + "parent": "r1(4)", + "type": "IP TE", + "vertex": "10.0.20.0/24" }, { - "Interface": "r3-eth0", - "Metric": 10, - "Next-Hop": "r1", - "Parent": "r1(4)", - "Type": "IP TE", - "Vertex": "10.254.0.1/32" + "interface": "r3-eth0", + "metric": 10, + "nextHop": "r1", + "parent": "r1(4)", + "type": "IP TE", + "vertex": "10.254.0.1/32" } ], "ipv6-paths": [ { - "Vertex": "r3" + "vertex": "r3" }, { - "Metric": 0, - "Parent": "r3(4)", - "Type": "IP6 internal", - "Vertex": "2001:db8:1:1::/64" + "metric": 0, + "parent": "r3(4)", + "type": "IP6 internal", + "vertex": "2001:db8:1:1::/64" }, { - "Interface": "r3-eth0", - "Metric": 10, - "Next-Hop": "r1", - "Parent": "r3(4)", - "Type": "TE-IS", - "Vertex": "r1" + "interface": "r3-eth0", + "metric": 10, + "nextHop": "r1", + "parent": "r3(4)", + "type": "TE-IS", + "vertex": "r1" }, { - "Metric": 10, - "Interface": "r3-eth0", - "Next-Hop": "r1", - "Parent": "r1(4)", - "Type": "IP6 internal", - "Vertex": "2001:db8:f::1/128" + "metric": 10, + "interface": "r3-eth0", + "nextHop": "r1", + "parent": "r1(4)", + "type": "IP6 internal", + "vertex": "2001:db8:f::1/128" } ] } diff --git a/tests/topotests/isis_topo1/r4/r4_topology.json b/tests/topotests/isis_topo1/r4/r4_topology.json index 240c7588fc..9a53955cc9 100644 --- a/tests/topotests/isis_topo1/r4/r4_topology.json +++ b/tests/topotests/isis_topo1/r4/r4_topology.json @@ -5,190 +5,190 @@ "level-1": { "ipv4-paths": [ { - "Vertex": "r4" + "vertex": "r4" }, { - "Metric": 0, - "Parent": "r4(4)", - "Type": "IP internal", - "Vertex": "10.0.11.0/24" + "metric": 0, + "parent": "r4(4)", + "type": "IP internal", + "vertex": "10.0.11.0/24" }, { - "Interface": "r4-eth1", - "Metric": 10, - "Next-Hop": "r5", - "Parent": "r4(4)", - "Type": "TE-IS", - "Vertex": "r5" + "interface": "r4-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r4(4)", + "type": "TE-IS", + "vertex": "r5" }, { - "Interface": "r4-eth1", - "Metric": 10, - "Next-Hop": "r5", - "Parent": "r5(4)", - "Type": "IP TE", - "Vertex": "10.0.10.0/24" + "interface": "r4-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r5(4)", + "type": "IP TE", + "vertex": "10.0.10.0/24" }, { - "Interface": "r4-eth1", - "Metric": 10, - "Next-Hop": "r5", - "Parent": "r5(4)", - "Type": "IP TE", - "Vertex": "10.0.11.0/24" + "interface": "r4-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r5(4)", + "type": "IP TE", + "vertex": "10.0.11.0/24" }, { - "Interface": "r4-eth1", - "Metric": 10, - "Next-Hop": "r5", - "Parent": "r5(4)", - "Type": "IP TE", - "Vertex": "10.254.0.5/32" + "interface": "r4-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r5(4)", + "type": "IP TE", + "vertex": "10.254.0.5/32" }, { - "Interface": "r4-eth1", - "Metric": 20, - "Next-Hop": "r5", - "Type": "TE-IS", - "Vertex": "r3" + "interface": "r4-eth1", + "metric": 20, + "nextHop": "r5", + "type": "TE-IS", + "vertex": "r3" }, { - "Interface": "r4-eth1", - "Metric": 20, - "Next-Hop": "r5", - "Parent": "r3(4)", - "Type": "IP TE", - "Vertex": "10.0.20.0/24" + "interface": "r4-eth1", + "metric": 20, + "nextHop": "r5", + "parent": "r3(4)", + "type": "IP TE", + "vertex": "10.0.20.0/24" }, { - "Interface": "r4-eth1", - "Metric": 20, - "Next-Hop": "r5", - "Parent": "r3(4)", - "Type": "IP TE", - "Vertex": "10.254.0.3/32" + "interface": "r4-eth1", + "metric": 20, + "nextHop": "r5", + "parent": "r3(4)", + "type": "IP TE", + "vertex": "10.254.0.3/32" } ], "ipv6-paths": [ { - "Vertex": "r4" + "vertex": "r4" }, { - "Metric": 0, - "Parent": "r4(4)", - "Type": "IP6 internal", - "Vertex": "2001:db8:2:2::/64" + "metric": 0, + "parent": "r4(4)", + "type": "IP6 internal", + "vertex": "2001:db8:2:2::/64" }, { - "Interface": "r4-eth1", - "Metric": 10, - "Next-Hop": "r5", - "Parent": "r4(4)", - "Type": "TE-IS", - "Vertex": "r5" + "interface": "r4-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r4(4)", + "type": "TE-IS", + "vertex": "r5" }, { - "Metric": 10, - "Interface": "r4-eth1", - "Next-Hop": "r5", - "Parent": "r5(4)", - "Type": "IP6 internal", - "Vertex": "2001:db8:2:1::/64" + "metric": 10, + "interface": "r4-eth1", + "nextHop": "r5", + "parent": "r5(4)", + "type": "IP6 internal", + "vertex": "2001:db8:2:1::/64" }, { - "Metric": 10, - "Interface": "r4-eth1", - "Next-Hop": "r5", - "Parent": "r5(4)", - "Type": "IP6 internal", - "Vertex": "2001:db8:f::5/128" + "metric": 10, + "interface": "r4-eth1", + "nextHop": "r5", + "parent": "r5(4)", + "type": "IP6 internal", + "vertex": "2001:db8:f::5/128" }, { - "Interface": "r4-eth1", - "Metric": 20, - "Next-Hop": "r5", - "Type": "TE-IS", - "Vertex": "r3" + "interface": "r4-eth1", + "metric": 20, + "nextHop": "r5", + "type": "TE-IS", + "vertex": "r3" }, { - "Metric": 20, - "Interface": "r4-eth1", - "Next-Hop": "r5", - "Parent": "r3(4)", - "Type": "IP6 internal", - "Vertex": "2001:db8:1:1::/64" + "metric": 20, + "interface": "r4-eth1", + "nextHop": "r5", + "parent": "r3(4)", + "type": "IP6 internal", + "vertex": "2001:db8:1:1::/64" }, { - "Metric": 20, - "Interface": "r4-eth1", - "Next-Hop": "r5", - "Parent": "r3(4)", - "Type": "IP6 internal", - "Vertex": "2001:db8:f::3/128" + "metric": 20, + "interface": "r4-eth1", + "nextHop": "r5", + "parent": "r3(4)", + "type": "IP6 internal", + "vertex": "2001:db8:f::3/128" } ] }, "level-2": { "ipv4-paths": [ { - "Vertex": "r4" + "vertex": "r4" }, { - "Metric": 0, - "Parent": "r4(4)", - "Type": "IP internal", - "Vertex": "10.0.21.0/24" + "metric": 0, + "parent": "r4(4)", + "type": "IP internal", + "vertex": "10.0.21.0/24" }, { - "Interface": "r4-eth0", - "Metric": 10, - "Next-Hop": "r2", - "Parent": "r4(4)", - "Type": "TE-IS", - "Vertex": "r2" + "interface": "r4-eth0", + "metric": 10, + "nextHop": "r2", + "parent": "r4(4)", + "type": "TE-IS", + "vertex": "r2" }, { - "Interface": "r4-eth0", - "Metric": 10, - "Next-Hop": "r2", - "Parent": "r2(4)", - "Type": "IP TE", - "Vertex": "10.0.21.0/24" + "interface": "r4-eth0", + "metric": 10, + "nextHop": "r2", + "parent": "r2(4)", + "type": "IP TE", + "vertex": "10.0.21.0/24" }, { - "Interface": "r4-eth0", - "Metric": 10, - "Next-Hop": "r2", - "Parent": "r2(4)", - "Type": "IP TE", - "Vertex": "10.254.0.2/32" + "interface": "r4-eth0", + "metric": 10, + "nextHop": "r2", + "parent": "r2(4)", + "type": "IP TE", + "vertex": "10.254.0.2/32" } ], "ipv6-paths": [ { - "Vertex": "r4" + "vertex": "r4" }, { - "Metric": 0, - "Parent": "r4(4)", - "Type": "IP6 internal", - "Vertex": "2001:db8:1:2::/64" + "metric": 0, + "parent": "r4(4)", + "type": "IP6 internal", + "vertex": "2001:db8:1:2::/64" }, { - "Interface": "r4-eth0", - "Metric": 10, - "Next-Hop": "r2", - "Parent": "r4(4)", - "Type": "TE-IS", - "Vertex": "r2" + "interface": "r4-eth0", + "metric": 10, + "nextHop": "r2", + "parent": "r4(4)", + "type": "TE-IS", + "vertex": "r2" }, { - "Metric": 10, - "Interface": "r4-eth0", - "Next-Hop": "r2", - "Parent": "r2(4)", - "Type": "IP6 internal", - "Vertex": "2001:db8:f::2/128" + "metric": 10, + "interface": "r4-eth0", + "nextHop": "r2", + "parent": "r2(4)", + "type": "IP6 internal", + "vertex": "2001:db8:f::2/128" } ] } diff --git a/tests/topotests/isis_topo1/r5/r5_topology.json b/tests/topotests/isis_topo1/r5/r5_topology.json index 37da1a08e3..64590d8eb2 100644 --- a/tests/topotests/isis_topo1/r5/r5_topology.json +++ b/tests/topotests/isis_topo1/r5/r5_topology.json @@ -5,148 +5,148 @@ "level-1": { "ipv4-paths": [ { - "Vertex": "r5" + "vertex": "r5" }, { - "Metric": 0, - "Parent": "r5(4)", - "Type": "IP internal", - "Vertex": "10.0.10.0/24" + "metric": 0, + "parent": "r5(4)", + "type": "IP internal", + "vertex": "10.0.10.0/24" }, { - "Metric": 0, - "Parent": "r5(4)", - "Type": "IP internal", - "Vertex": "10.0.11.0/24" + "metric": 0, + "parent": "r5(4)", + "type": "IP internal", + "vertex": "10.0.11.0/24" }, { - "Interface": "r5-eth0", - "Metric": 10, - "Next-Hop": "r3", - "Parent": "r5(4)", - "Type": "TE-IS", - "Vertex": "r3" + "interface": "r5-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r5(4)", + "type": "TE-IS", + "vertex": "r3" }, { - "Interface": "r5-eth1", - "Metric": 10, - "Next-Hop": "r4", - "Parent": "r5(4)", - "Type": "TE-IS", - "Vertex": "r4" + "interface": "r5-eth1", + "metric": 10, + "nextHop": "r4", + "parent": "r5(4)", + "type": "TE-IS", + "vertex": "r4" }, { - "Interface": "r5-eth0", - "Metric": 10, - "Next-Hop": "r3", - "Parent": "r3(4)", - "Type": "IP TE", - "Vertex": "10.0.10.0/24" + "interface": "r5-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r3(4)", + "type": "IP TE", + "vertex": "10.0.10.0/24" }, { - "Interface": "r5-eth0", - "Metric": 10, - "Next-Hop": "r3", - "Parent": "r3(4)", - "Type": "IP TE", - "Vertex": "10.0.20.0/24" + "interface": "r5-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r3(4)", + "type": "IP TE", + "vertex": "10.0.20.0/24" }, { - "Interface": "r5-eth0", - "Metric": 10, - "Next-Hop": "r3", - "Parent": "r3(4)", - "Type": "IP TE", - "Vertex": "10.254.0.3/32" + "interface": "r5-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r3(4)", + "type": "IP TE", + "vertex": "10.254.0.3/32" }, { - "Interface": "r5-eth1", - "Metric": 10, - "Next-Hop": "r4", - "Parent": "r4(4)", - "Type": "IP TE", - "Vertex": "10.0.11.0/24" + "interface": "r5-eth1", + "metric": 10, + "nextHop": "r4", + "parent": "r4(4)", + "type": "IP TE", + "vertex": "10.0.11.0/24" }, { - "Interface": "r5-eth1", - "Metric": 10, - "Next-Hop": "r4", - "Parent": "r4(4)", - "Type": "IP TE", - "Vertex": "10.0.21.0/24" + "interface": "r5-eth1", + "metric": 10, + "nextHop": "r4", + "parent": "r4(4)", + "type": "IP TE", + "vertex": "10.0.21.0/24" }, { - "Interface": "r5-eth1", - "Metric": 10, - "Next-Hop": "r4", - "Parent": "r4(4)", - "Type": "IP TE", - "Vertex": "10.254.0.4/32" + "interface": "r5-eth1", + "metric": 10, + "nextHop": "r4", + "parent": "r4(4)", + "type": "IP TE", + "vertex": "10.254.0.4/32" } ], "ipv6-paths": [ { - "Vertex": "r5" + "vertex": "r5" }, { - "Metric": 0, - "Parent": "r5(4)", - "Type": "IP6 internal", - "Vertex": "2001:db8:2:1::/64" + "metric": 0, + "parent": "r5(4)", + "type": "IP6 internal", + "vertex": "2001:db8:2:1::/64" }, { - "Metric": 0, - "Parent": "r5(4)", - "Type": "IP6 internal", - "Vertex": "2001:db8:2:2::/64" + "metric": 0, + "parent": "r5(4)", + "type": "IP6 internal", + "vertex": "2001:db8:2:2::/64" }, { - "Interface": "r5-eth0", - "Metric": 10, - "Next-Hop": "r3", - "Parent": "r5(4)", - "Type": "TE-IS", - "Vertex": "r3" + "interface": "r5-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r5(4)", + "type": "TE-IS", + "vertex": "r3" }, { - "Interface": "r5-eth1", - "Metric": 10, - "Next-Hop": "r4", - "Parent": "r5(4)", - "Type": "TE-IS", - "Vertex": "r4" + "interface": "r5-eth1", + "metric": 10, + "nextHop": "r4", + "parent": "r5(4)", + "type": "TE-IS", + "vertex": "r4" }, { - "Metric": 10, - "Interface": "r5-eth0", - "Next-Hop": "r3", - "Parent": "r3(4)", - "Type": "IP6 internal", - "Vertex": "2001:db8:1:1::/64" + "metric": 10, + "interface": "r5-eth0", + "nextHop": "r3", + "parent": "r3(4)", + "type": "IP6 internal", + "vertex": "2001:db8:1:1::/64" }, { - "Metric": 10, - "Interface": "r5-eth0", - "Next-Hop": "r3", - "Parent": "r3(4)", - "Type": "IP6 internal", - "Vertex": "2001:db8:f::3/128" + "metric": 10, + "interface": "r5-eth0", + "nextHop": "r3", + "parent": "r3(4)", + "type": "IP6 internal", + "vertex": "2001:db8:f::3/128" }, { - "Metric": 10, - "Interface": "r5-eth1", - "Next-Hop": "r4", - "Parent": "r4(4)", - "Type": "IP6 internal", - "Vertex": "2001:db8:1:2::/64" + "metric": 10, + "interface": "r5-eth1", + "nextHop": "r4", + "parent": "r4(4)", + "type": "IP6 internal", + "vertex": "2001:db8:1:2::/64" }, { - "Metric": 10, - "Interface": "r5-eth1", - "Next-Hop": "r4", - "Parent": "r4(4)", - "Type": "IP6 internal", - "Vertex": "2001:db8:f::4/128" + "metric": 10, + "interface": "r5-eth1", + "nextHop": "r4", + "parent": "r4(4)", + "type": "IP6 internal", + "vertex": "2001:db8:f::4/128" } ] } diff --git a/tests/topotests/isis_topo1_vrf/r1/r1_topology.json b/tests/topotests/isis_topo1_vrf/r1/r1_topology.json index 8d4ccc84cc..da537c552b 100644 --- a/tests/topotests/isis_topo1_vrf/r1/r1_topology.json +++ b/tests/topotests/isis_topo1_vrf/r1/r1_topology.json @@ -5,76 +5,76 @@ "level-1": { "ipv4-paths": [ { - "Vertex": "r1" + "vertex": "r1" } ], "ipv6-paths": [ { - "Vertex": "r1" + "vertex": "r1" } ] }, "level-2": { "ipv4-paths": [ { - "Vertex": "r1" + "vertex": "r1" }, { - "Metric": 0, - "Parent": "r1(4)", - "Type": "IP internal", - "Vertex": "10.0.20.0/24" + "metric": 0, + "parent": "r1(4)", + "type": "IP internal", + "vertex": "10.0.20.0/24" }, { - "Interface": "r1-eth0", - "Metric": 10, - "Next-Hop": "r3", - "Parent": "r1(4)", - "Type": "TE-IS", - "Vertex": "r3" + "interface": "r1-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r1(4)", + "type": "TE-IS", + "vertex": "r3" }, { - "Interface": "r1-eth0", - "Metric": 10, - "Next-Hop": "r3", - "Parent": "r3(4)", - "Type": "IP TE", - "Vertex": "10.0.10.0/24" + "interface": "r1-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r3(4)", + "type": "IP TE", + "vertex": "10.0.10.0/24" }, { - "Interface": "r1-eth0", - "Metric": 10, - "Next-Hop": "r3", - "Parent": "r3(4)", - "Type": "IP TE", - "Vertex": "10.0.20.0/24" + "interface": "r1-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r3(4)", + "type": "IP TE", + "vertex": "10.0.20.0/24" } ], "ipv6-paths": [ { - "Vertex": "r1" + "vertex": "r1" }, { - "Metric": 0, - "Parent": "r1(4)", - "Type": "IP6 internal", - "Vertex": "2001:db8:1:1::/64" + "metric": 0, + "parent": "r1(4)", + "type": "IP6 internal", + "vertex": "2001:db8:1:1::/64" }, { - "Interface": "r1-eth0", - "Metric": 10, - "Next-Hop": "r3", - "Parent": "r1(4)", - "Type": "TE-IS", - "Vertex": "r3" + "interface": "r1-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r1(4)", + "type": "TE-IS", + "vertex": "r3" }, { - "Metric": 10, - "Interface": "r1-eth0", - "Next-Hop": "r3", - "Parent": "r3(4)", - "Type": "IP6 internal", - "Vertex": "2001:db8:2:1::/64" + "metric": 10, + "interface": "r1-eth0", + "nextHop": "r3", + "parent": "r3(4)", + "type": "IP6 internal", + "vertex": "2001:db8:2:1::/64" } ] } diff --git a/tests/topotests/isis_topo1_vrf/r2/r2_topology.json b/tests/topotests/isis_topo1_vrf/r2/r2_topology.json index dc87c42822..bf965659be 100644 --- a/tests/topotests/isis_topo1_vrf/r2/r2_topology.json +++ b/tests/topotests/isis_topo1_vrf/r2/r2_topology.json @@ -5,76 +5,76 @@ "level-1": { "ipv4-paths": [ { - "Vertex": "r2" + "vertex": "r2" } ], "ipv6-paths": [ { - "Vertex": "r2" + "vertex": "r2" } ] }, "level-2": { "ipv4-paths": [ { - "Vertex": "r2" + "vertex": "r2" }, { - "Metric": 0, - "Parent": "r2(4)", - "Type": "IP internal", - "Vertex": "10.0.21.0/24" + "metric": 0, + "parent": "r2(4)", + "type": "IP internal", + "vertex": "10.0.21.0/24" }, { - "Interface": "r2-eth0", - "Metric": 10, - "Next-Hop": "r4", - "Parent": "r2(4)", - "Type": "TE-IS", - "Vertex": "r4" + "interface": "r2-eth0", + "metric": 10, + "nextHop": "r4", + "parent": "r2(4)", + "type": "TE-IS", + "vertex": "r4" }, { - "Interface": "r2-eth0", - "Metric": 10, - "Next-Hop": "r4", - "Parent": "r4(4)", - "Type": "IP TE", - "Vertex": "10.0.11.0/24" + "interface": "r2-eth0", + "metric": 10, + "nextHop": "r4", + "parent": "r4(4)", + "type": "IP TE", + "vertex": "10.0.11.0/24" }, { - "Interface": "r2-eth0", - "Metric": 10, - "Next-Hop": "r4", - "Parent": "r4(4)", - "Type": "IP TE", - "Vertex": "10.0.21.0/24" + "interface": "r2-eth0", + "metric": 10, + "nextHop": "r4", + "parent": "r4(4)", + "type": "IP TE", + "vertex": "10.0.21.0/24" } ], "ipv6-paths": [ { - "Vertex": "r2" + "vertex": "r2" }, { - "Metric": 0, - "Parent": "r2(4)", - "Type": "IP6 internal", - "Vertex": "2001:db8:1:2::/64" + "metric": 0, + "parent": "r2(4)", + "type": "IP6 internal", + "vertex": "2001:db8:1:2::/64" }, { - "Interface": "r2-eth0", - "Metric": 10, - "Next-Hop": "r4", - "Parent": "r2(4)", - "Type": "TE-IS", - "Vertex": "r4" + "interface": "r2-eth0", + "metric": 10, + "nextHop": "r4", + "parent": "r2(4)", + "type": "TE-IS", + "vertex": "r4" }, { - "Metric": 10, - "Interface": "r2-eth0", - "Next-Hop": "r4", - "Parent": "r4(4)", - "Type": "IP6 internal", - "Vertex": "2001:db8:2:2::/64" + "metric": 10, + "interface": "r2-eth0", + "nextHop": "r4", + "parent": "r4(4)", + "type": "IP6 internal", + "vertex": "2001:db8:2:2::/64" } ] } diff --git a/tests/topotests/isis_topo1_vrf/r3/r3_topology.json b/tests/topotests/isis_topo1_vrf/r3/r3_topology.json index 602dc7df55..94592b50a7 100644 --- a/tests/topotests/isis_topo1_vrf/r3/r3_topology.json +++ b/tests/topotests/isis_topo1_vrf/r3/r3_topology.json @@ -5,142 +5,142 @@ "level-1": { "ipv4-paths": [ { - "Vertex": "r3" + "vertex": "r3" }, { - "Metric": 0, - "Parent": "r3(4)", - "Type": "IP internal", - "Vertex": "10.0.10.0/24" + "metric": 0, + "parent": "r3(4)", + "type": "IP internal", + "vertex": "10.0.10.0/24" }, { - "Interface": "r3-eth1", - "Metric": 10, - "Next-Hop": "r5", - "Parent": "r3(4)", - "Type": "TE-IS", - "Vertex": "r5" + "interface": "r3-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r3(4)", + "type": "TE-IS", + "vertex": "r5" }, { - "Interface": "r3-eth1", - "Metric": 10, - "Next-Hop": "r5", - "Parent": "r5(4)", - "Type": "IP TE", - "Vertex": "10.0.10.0/24" + "interface": "r3-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r5(4)", + "type": "IP TE", + "vertex": "10.0.10.0/24" }, { - "Interface": "r3-eth1", - "Metric": 10, - "Next-Hop": "r5", - "Parent": "r5(4)", - "Type": "IP TE", - "Vertex": "10.0.11.0/24" + "interface": "r3-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r5(4)", + "type": "IP TE", + "vertex": "10.0.11.0/24" }, { - "Interface": "r3-eth1", - "Metric": 20, - "Next-Hop": "r5", - "Type": "TE-IS", - "Vertex": "r4" + "interface": "r3-eth1", + "metric": 20, + "nextHop": "r5", + "type": "TE-IS", + "vertex": "r4" }, { - "Interface": "r3-eth1", - "Metric": 20, - "Next-Hop": "r5", - "Parent": "r4(4)", - "Type": "IP TE", - "Vertex": "10.0.21.0/24" + "interface": "r3-eth1", + "metric": 20, + "nextHop": "r5", + "parent": "r4(4)", + "type": "IP TE", + "vertex": "10.0.21.0/24" } ], "ipv6-paths": [ { - "Vertex": "r3" + "vertex": "r3" }, { - "Metric": 0, - "Parent": "r3(4)", - "Type": "IP6 internal", - "Vertex": "2001:db8:2:1::/64" + "metric": 0, + "parent": "r3(4)", + "type": "IP6 internal", + "vertex": "2001:db8:2:1::/64" }, { - "Interface": "r3-eth1", - "Metric": 10, - "Next-Hop": "r5", - "Parent": "r3(4)", - "Type": "TE-IS", - "Vertex": "r5" + "interface": "r3-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r3(4)", + "type": "TE-IS", + "vertex": "r5" }, { - "Metric": 10, - "Interface": "r3-eth1", - "Next-Hop": "r5", - "Parent": "r5(4)", - "Type": "IP6 internal", - "Vertex": "2001:db8:2:2::/64" + "metric": 10, + "interface": "r3-eth1", + "nextHop": "r5", + "parent": "r5(4)", + "type": "IP6 internal", + "vertex": "2001:db8:2:2::/64" }, { - "Interface": "r3-eth1", - "Metric": 20, - "Next-Hop": "r5", - "Type": "TE-IS", - "Vertex": "r4" + "interface": "r3-eth1", + "metric": 20, + "nextHop": "r5", + "type": "TE-IS", + "vertex": "r4" }, { - "Metric": 20, - "Interface": "r3-eth1", - "Next-Hop": "r5", - "Parent": "r4(4)", - "Type": "IP6 internal", - "Vertex": "2001:db8:1:2::/64" + "metric": 20, + "interface": "r3-eth1", + "nextHop": "r5", + "parent": "r4(4)", + "type": "IP6 internal", + "vertex": "2001:db8:1:2::/64" } ] }, "level-2": { "ipv4-paths": [ { - "Vertex": "r3" + "vertex": "r3" }, { - "Metric": 0, - "Parent": "r3(4)", - "Type": "IP internal", - "Vertex": "10.0.20.0/24" + "metric": 0, + "parent": "r3(4)", + "type": "IP internal", + "vertex": "10.0.20.0/24" }, { - "Interface": "r3-eth0", - "Metric": 10, - "Next-Hop": "r1", - "Parent": "r3(4)", - "Type": "TE-IS", - "Vertex": "r1" + "interface": "r3-eth0", + "metric": 10, + "nextHop": "r1", + "parent": "r3(4)", + "type": "TE-IS", + "vertex": "r1" }, { - "Interface": "r3-eth0", - "Metric": 10, - "Next-Hop": "r1", - "Parent": "r1(4)", - "Type": "IP TE", - "Vertex": "10.0.20.0/24" + "interface": "r3-eth0", + "metric": 10, + "nextHop": "r1", + "parent": "r1(4)", + "type": "IP TE", + "vertex": "10.0.20.0/24" } ], "ipv6-paths": [ { - "Vertex": "r3" + "vertex": "r3" }, { - "Metric": 0, - "Parent": "r3(4)", - "Type": "IP6 internal", - "Vertex": "2001:db8:1:1::/64" + "metric": 0, + "parent": "r3(4)", + "type": "IP6 internal", + "vertex": "2001:db8:1:1::/64" }, { - "Interface": "r3-eth0", - "Metric": 10, - "Next-Hop": "r1", - "Parent": "r3(4)", - "Type": "TE-IS", - "Vertex": "r1" + "interface": "r3-eth0", + "metric": 10, + "nextHop": "r1", + "parent": "r3(4)", + "type": "TE-IS", + "vertex": "r1" } ] } diff --git a/tests/topotests/isis_topo1_vrf/r4/r4_topology.json b/tests/topotests/isis_topo1_vrf/r4/r4_topology.json index f4c1bb3768..b8295e87b9 100644 --- a/tests/topotests/isis_topo1_vrf/r4/r4_topology.json +++ b/tests/topotests/isis_topo1_vrf/r4/r4_topology.json @@ -5,142 +5,142 @@ "level-1": { "ipv4-paths": [ { - "Vertex": "r4" + "vertex": "r4" }, { - "Metric": 0, - "Parent": "r4(4)", - "Type": "IP internal", - "Vertex": "10.0.11.0/24" + "metric": 0, + "parent": "r4(4)", + "type": "IP internal", + "vertex": "10.0.11.0/24" }, { - "Interface": "r4-eth1", - "Metric": 10, - "Next-Hop": "r5", - "Parent": "r4(4)", - "Type": "TE-IS", - "Vertex": "r5" + "interface": "r4-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r4(4)", + "type": "TE-IS", + "vertex": "r5" }, { - "Interface": "r4-eth1", - "Metric": 10, - "Next-Hop": "r5", - "Parent": "r5(4)", - "Type": "IP TE", - "Vertex": "10.0.10.0/24" + "interface": "r4-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r5(4)", + "type": "IP TE", + "vertex": "10.0.10.0/24" }, { - "Interface": "r4-eth1", - "Metric": 10, - "Next-Hop": "r5", - "Parent": "r5(4)", - "Type": "IP TE", - "Vertex": "10.0.11.0/24" + "interface": "r4-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r5(4)", + "type": "IP TE", + "vertex": "10.0.11.0/24" }, { - "Interface": "r4-eth1", - "Metric": 20, - "Next-Hop": "r5", - "Type": "TE-IS", - "Vertex": "r3" + "interface": "r4-eth1", + "metric": 20, + "nextHop": "r5", + "type": "TE-IS", + "vertex": "r3" }, { - "Interface": "r4-eth1", - "Metric": 20, - "Next-Hop": "r5", - "Parent": "r3(4)", - "Type": "IP TE", - "Vertex": "10.0.20.0/24" + "interface": "r4-eth1", + "metric": 20, + "nextHop": "r5", + "parent": "r3(4)", + "type": "IP TE", + "vertex": "10.0.20.0/24" } ], "ipv6-paths": [ { - "Vertex": "r4" + "vertex": "r4" }, { - "Metric": 0, - "Parent": "r4(4)", - "Type": "IP6 internal", - "Vertex": "2001:db8:2:2::/64" + "metric": 0, + "parent": "r4(4)", + "type": "IP6 internal", + "vertex": "2001:db8:2:2::/64" }, { - "Interface": "r4-eth1", - "Metric": 10, - "Next-Hop": "r5", - "Parent": "r4(4)", - "Type": "TE-IS", - "Vertex": "r5" + "interface": "r4-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r4(4)", + "type": "TE-IS", + "vertex": "r5" }, { - "Metric": 10, - "Interface": "r4-eth1", - "Next-Hop": "r5", - "Parent": "r5(4)", - "Type": "IP6 internal", - "Vertex": "2001:db8:2:1::/64" + "metric": 10, + "interface": "r4-eth1", + "nextHop": "r5", + "parent": "r5(4)", + "type": "IP6 internal", + "vertex": "2001:db8:2:1::/64" }, { - "Interface": "r4-eth1", - "Metric": 20, - "Next-Hop": "r5", - "Type": "TE-IS", - "Vertex": "r3" + "interface": "r4-eth1", + "metric": 20, + "nextHop": "r5", + "type": "TE-IS", + "vertex": "r3" }, { - "Metric": 20, - "Interface": "r4-eth1", - "Next-Hop": "r5", - "Parent": "r3(4)", - "Type": "IP6 internal", - "Vertex": "2001:db8:1:1::/64" + "metric": 20, + "interface": "r4-eth1", + "nextHop": "r5", + "parent": "r3(4)", + "type": "IP6 internal", + "vertex": "2001:db8:1:1::/64" } ] }, "level-2": { "ipv4-paths": [ { - "Vertex": "r4" + "vertex": "r4" }, { - "Metric": 0, - "Parent": "r4(4)", - "Type": "IP internal", - "Vertex": "10.0.21.0/24" + "metric": 0, + "parent": "r4(4)", + "type": "IP internal", + "vertex": "10.0.21.0/24" }, { - "Interface": "r4-eth0", - "Metric": 10, - "Next-Hop": "r2", - "Parent": "r4(4)", - "Type": "TE-IS", - "Vertex": "r2" + "interface": "r4-eth0", + "metric": 10, + "nextHop": "r2", + "parent": "r4(4)", + "type": "TE-IS", + "vertex": "r2" }, { - "Interface": "r4-eth0", - "Metric": 10, - "Next-Hop": "r2", - "Parent": "r2(4)", - "Type": "IP TE", - "Vertex": "10.0.21.0/24" + "interface": "r4-eth0", + "metric": 10, + "nextHop": "r2", + "parent": "r2(4)", + "type": "IP TE", + "vertex": "10.0.21.0/24" } ], "ipv6-paths": [ { - "Vertex": "r4" + "vertex": "r4" }, { - "Metric": 0, - "Parent": "r4(4)", - "Type": "IP6 internal", - "Vertex": "2001:db8:1:2::/64" + "metric": 0, + "parent": "r4(4)", + "type": "IP6 internal", + "vertex": "2001:db8:1:2::/64" }, { - "Interface": "r4-eth0", - "Metric": 10, - "Next-Hop": "r2", - "Parent": "r4(4)", - "Type": "TE-IS", - "Vertex": "r2" + "interface": "r4-eth0", + "metric": 10, + "nextHop": "r2", + "parent": "r4(4)", + "type": "TE-IS", + "vertex": "r2" } ] } diff --git a/tests/topotests/isis_topo1_vrf/r5/r5_topology.json b/tests/topotests/isis_topo1_vrf/r5/r5_topology.json index 669f31c474..8b5159cbfb 100644 --- a/tests/topotests/isis_topo1_vrf/r5/r5_topology.json +++ b/tests/topotests/isis_topo1_vrf/r5/r5_topology.json @@ -5,116 +5,116 @@ "level-1": { "ipv4-paths": [ { - "Vertex": "r5" + "vertex": "r5" }, { - "Metric": 0, - "Parent": "r5(4)", - "Type": "IP internal", - "Vertex": "10.0.10.0/24" + "metric": 0, + "parent": "r5(4)", + "type": "IP internal", + "vertex": "10.0.10.0/24" }, { - "Metric": 0, - "Parent": "r5(4)", - "Type": "IP internal", - "Vertex": "10.0.11.0/24" + "metric": 0, + "parent": "r5(4)", + "type": "IP internal", + "vertex": "10.0.11.0/24" }, { - "Interface": "r5-eth0", - "Metric": 10, - "Next-Hop": "r3", - "Parent": "r5(4)", - "Type": "TE-IS", - "Vertex": "r3" + "interface": "r5-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r5(4)", + "type": "TE-IS", + "vertex": "r3" }, { - "Interface": "r5-eth1", - "Metric": 10, - "Next-Hop": "r4", - "Parent": "r5(4)", - "Type": "TE-IS", - "Vertex": "r4" + "interface": "r5-eth1", + "metric": 10, + "nextHop": "r4", + "parent": "r5(4)", + "type": "TE-IS", + "vertex": "r4" }, { - "Interface": "r5-eth0", - "Metric": 10, - "Next-Hop": "r3", - "Parent": "r3(4)", - "Type": "IP TE", - "Vertex": "10.0.10.0/24" + "interface": "r5-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r3(4)", + "type": "IP TE", + "vertex": "10.0.10.0/24" }, { - "Interface": "r5-eth0", - "Metric": 10, - "Next-Hop": "r3", - "Parent": "r3(4)", - "Type": "IP TE", - "Vertex": "10.0.20.0/24" + "interface": "r5-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r3(4)", + "type": "IP TE", + "vertex": "10.0.20.0/24" }, { - "Interface": "r5-eth1", - "Metric": 10, - "Next-Hop": "r4", - "Parent": "r4(4)", - "Type": "IP TE", - "Vertex": "10.0.11.0/24" + "interface": "r5-eth1", + "metric": 10, + "nextHop": "r4", + "parent": "r4(4)", + "type": "IP TE", + "vertex": "10.0.11.0/24" }, { - "Interface": "r5-eth1", - "Metric": 10, - "Next-Hop": "r4", - "Parent": "r4(4)", - "Type": "IP TE", - "Vertex": "10.0.21.0/24" + "interface": "r5-eth1", + "metric": 10, + "nextHop": "r4", + "parent": "r4(4)", + "type": "IP TE", + "vertex": "10.0.21.0/24" } ], "ipv6-paths": [ { - "Vertex": "r5" + "vertex": "r5" }, { - "Metric": 0, - "Parent": "r5(4)", - "Type": "IP6 internal", - "Vertex": "2001:db8:2:1::/64" + "metric": 0, + "parent": "r5(4)", + "type": "IP6 internal", + "vertex": "2001:db8:2:1::/64" }, { - "Metric": 0, - "Parent": "r5(4)", - "Type": "IP6 internal", - "Vertex": "2001:db8:2:2::/64" + "metric": 0, + "parent": "r5(4)", + "type": "IP6 internal", + "vertex": "2001:db8:2:2::/64" }, { - "Interface": "r5-eth0", - "Metric": 10, - "Next-Hop": "r3", - "Parent": "r5(4)", - "Type": "TE-IS", - "Vertex": "r3" + "interface": "r5-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r5(4)", + "type": "TE-IS", + "vertex": "r3" }, { - "Interface": "r5-eth1", - "Metric": 10, - "Next-Hop": "r4", - "Parent": "r5(4)", - "Type": "TE-IS", - "Vertex": "r4" + "interface": "r5-eth1", + "metric": 10, + "nextHop": "r4", + "parent": "r5(4)", + "type": "TE-IS", + "vertex": "r4" }, { - "Metric": 10, - "Interface": "r5-eth0", - "Next-Hop": "r3", - "Parent": "r3(4)", - "Type": "IP6 internal", - "Vertex": "2001:db8:1:1::/64" + "metric": 10, + "interface": "r5-eth0", + "nextHop": "r3", + "parent": "r3(4)", + "type": "IP6 internal", + "vertex": "2001:db8:1:1::/64" }, { - "Metric": 10, - "Interface": "r5-eth1", - "Next-Hop": "r4", - "Parent": "r4(4)", - "Type": "IP6 internal", - "Vertex": "2001:db8:1:2::/64" + "metric": 10, + "interface": "r5-eth1", + "nextHop": "r4", + "parent": "r4(4)", + "type": "IP6 internal", + "vertex": "2001:db8:1:2::/64" } ] } From 611f83f324a4e2a9cb0611fd74de8b32a8d22dd6 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Wed, 19 Jun 2024 16:10:48 +0200 Subject: [PATCH 112/347] isisd: change the json output for isis routes The json format for json routes should be compliant with caml format. Before: > "Prefix|Metric|Interface|Nexthop|SID|LabelOp|Algo": > "Prefix|Metric|Interface|Nexthop|Label(s)"); After: > "prefix|metric|interface|nextHop|segmentIdentifier|labelOperation|Algorithm": > "prefix|metric|interface|nextHop|label(s)"); Signed-off-by: Philippe Guibert --- isisd/isis_spf.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/isisd/isis_spf.c b/isisd/isis_spf.c index d6ce76960b..7aa9147e71 100644 --- a/isisd/isis_spf.c +++ b/isisd/isis_spf.c @@ -3015,7 +3015,11 @@ void isis_print_routes(struct vty *vty, struct isis_spftree *spftree, vty_out(vty, "%s\n", table); XFREE(MTYPE_TMP, table); } else if (json) { - *json = ttable_json(tt, prefix_sid ? "sdssdsdd" : "sdsss"); + *json = ttable_json_with_json_text( + tt, prefix_sid ? "sdssdsdd" : "sdsss", + prefix_sid + ? "prefix|metric|interface|nextHop|segmentIdentifier|labelOperation|Algorithm" + : "prefix|metric|interface|nextHop|label(s)"); } ttable_del(tt); } From c06fb90b63ccf2c4d1220f4d8e4b423bc4fc6a40 Mon Sep 17 00:00:00 2001 From: Louis Scalbert Date: Fri, 21 Jun 2024 10:59:43 +0200 Subject: [PATCH 113/347] isisd: fix display crash srv6 sid structure in json Fix a crash when doing "show isis database detail json" in isis_srv6_topo1 topotest. > #0 raise (sig=) at ../sysdeps/unix/sysv/linux/raise.c:50 > #1 0x00007fad89524e2c in core_handler (signo=6, siginfo=0x7ffe86a4b8b0, context=0x7ffe86a4b780) at lib/sigevent.c:258 > #2 > #3 __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:50 > #4 0x00007fad8904e537 in __GI_abort () at abort.c:79 > #5 0x00007fad8904e40f in __assert_fail_base (fmt=0x7fad891c5688 "%s%s%s:%u: %s%sAssertion `%s' failed.\n%n", assertion=0x7fad8a3e70e8 "json_object_get_type(jso) == json_type_object", > file=0x7fad8a3e7064 "./json_object.c", line=590, function=) at assert.c:92 > #6 0x00007fad8905d662 in __GI___assert_fail (assertion=0x7fad8a3e70e8 "json_object_get_type(jso) == json_type_object", file=0x7fad8a3e7064 "./json_object.c", line=590, > function=0x7fad8a3e7440 "json_object_object_add_ex") at assert.c:101 > #7 0x00007fad8a3dfe93 in json_object_object_add_ex () from /lib/x86_64-linux-gnu/libjson-c.so.5 > #8 0x000055708e3f8f7f in format_subsubtlv_srv6_sid_structure (sid_struct=0x602000172b70, buf=0x0, json=0x6040000a21d0, indent=6) at isisd/isis_tlvs.c:2880 > #9 0x000055708e3f9acb in isis_format_subsubtlvs (subsubtlvs=0x602000172b50, buf=0x0, json=0x6040000a21d0, indent=6) at isisd/isis_tlvs.c:3022 > #10 0x000055708e3eefb0 in format_item_ext_subtlvs (exts=0x614000047440, buf=0x0, json=0x6040000a2190, indent=2, mtid=2) at isisd/isis_tlvs.c:1313 > #11 0x000055708e3fd599 in format_item_extended_reach (mtid=2, i=0x60300015aed0, buf=0x0, json=0x6040000a1bd0, indent=0) at isisd/isis_tlvs.c:3763 > #12 0x000055708e40d46a in format_item (mtid=2, context=ISIS_CONTEXT_LSP, type=ISIS_TLV_MT_REACH, i=0x60300015aed0, buf=0x0, json=0x6040000a1bd0, indent=0) at isisd/isis_tlvs.c:6789 > #13 0x000055708e40d4fc in format_items_ (mtid=2, context=ISIS_CONTEXT_LSP, type=ISIS_TLV_MT_REACH, items=0x60600021d160, buf=0x0, json=0x6040000a1bd0, indent=0) at isisd/isis_tlvs.c:6804 > #14 0x000055708e40edbc in format_mt_items (context=ISIS_CONTEXT_LSP, type=ISIS_TLV_MT_REACH, m=0x6180000845d8, buf=0x0, json=0x6040000a1bd0, indent=0) at isisd/isis_tlvs.c:7147 > #15 0x000055708e4111e9 in format_tlvs (tlvs=0x618000084480, buf=0x0, json=0x6040000a1bd0, indent=0) at isisd/isis_tlvs.c:7572 > #16 0x000055708e4114ce in isis_format_tlvs (tlvs=0x618000084480, json=0x6040000a1bd0) at isisd/isis_tlvs.c:7613 > #17 0x000055708e36f167 in lsp_print_detail (lsp=0x612000058b40, vty=0x0, json=0x6040000a1bd0, dynhost=1 '\001', isis=0x60d00001f800) at isisd/isis_lsp.c:785 > #18 0x000055708e36f31f in lsp_print_all (vty=0x0, json=0x6040000a0490, head=0x61f000005488, detail=1 '\001', dynhost=1 '\001', isis=0x60d00001f800) at isisd/isis_lsp.c:820 > #19 0x000055708e4379fc in show_isis_database_lspdb_json (json=0x6040000a0450, area=0x61f000005480, level=0, lspdb=0x61f000005488, sysid_str=0x0, ui_level=1) at isisd/isisd.c:2683 > #20 0x000055708e437ef9 in show_isis_database_json (json=0x6040000a0310, sysid_str=0x0, ui_level=1, isis=0x60d00001f800) at isisd/isisd.c:2754 > #21 0x000055708e438357 in show_isis_database_common (vty=0x62e000060400, json=0x6040000a0310, sysid_str=0x0, ui_level=1, isis=0x60d00001f800) at isisd/isisd.c:2788 > #22 0x000055708e438591 in show_isis_database (vty=0x62e000060400, json=0x6040000a0310, sysid_str=0x0, ui_level=1, vrf_name=0x7fad89806300 "default", all_vrf=false) > at isisd/isisd.c:2825 > #23 0x000055708e43891d in show_database (self=0x55708e5519c0 , vty=0x62e000060400, argc=5, argv=0x6040000a02d0) at isisd/isisd.c:2855 > #24 0x00007fad893a9767 in cmd_execute_command_real (vline=0x60300015f220, vty=0x62e000060400, cmd=0x0, up_level=0) at lib/command.c:1002 > #25 0x00007fad893a9adc in cmd_execute_command (vline=0x60300015f220, vty=0x62e000060400, cmd=0x0, vtysh=0) at lib/command.c:1061 > #26 0x00007fad893aa728 in cmd_execute (vty=0x62e000060400, cmd=0x621000025900 "show isis database detail json ", matched=0x0, vtysh=0) at lib/command.c:1227 Note that prior to 2e670cd779, there was no crash but only the last "srv6-sid-structure" was displayed. A "srv6-sid-structure" should be displayed for each "sid". This commit also fix this. Was: > "srv6-lan-endx-sid": [ > { > "sid": "fc00:0:1:1::", > "weight": 0, > "algorithm": "SPF", > "neighbor-id": "0000.0000.0002" > }, > { > "sid": "fc00:0:1:2::", > "weight": 0, > "algorithm": "SPF", > "neighbor-id": "0000.0000.0003" > } > ], > "srv6-sid-structure": { > "loc-block-len": 32, > "loc-node-len": 16, > "func-len": 16, > "arg-len": 0 > }, Now (srv6-sid-structure are identical but they are not always): > "srv6-lan-endx-sid": [ > { > "sid": "fc00:0:1:1::", > "algorithm": "SPF", > "neighbor-id": "0000.0000.0002", > "srv6-sid-structure": { > "loc-block-len": 32, > "loc-node-len": 16, > "func-len": 8, > "arg-len": 0 > }, > }, > { > "sid": "fc00:0:1:2::", > "algorithm": "SPF", > "neighbor-id": "0000.0000.0003", > "srv6-sid-structure": { > "loc-block-len": 32, > "loc-node-len": 16, > "func-len": 16, > "arg-len": 0 > }, > } > ], Fixes: 2e670cd779 ("isisd: fix display of srv6 subsubtlvs") Fixes: 648a158802 ("isisd: Add SRv6 End.X SID to Sub-TLV format func") Signed-off-by: Louis Scalbert --- isisd/isis_tlvs.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/isisd/isis_tlvs.c b/isisd/isis_tlvs.c index 3bb8a48246..1c34550152 100644 --- a/isisd/isis_tlvs.c +++ b/isisd/isis_tlvs.c @@ -1311,8 +1311,7 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, json_object_array_add(arr_adj_json, flags_json); if (adj->subsubtlvs) isis_format_subsubtlvs(adj->subsubtlvs, - NULL, - arr_adj_json, + NULL, flags_json, indent + 4); } /* end old deprecated key format */ @@ -1350,8 +1349,7 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, json_object_array_add(arr_adj_json, flags_json); if (adj->subsubtlvs) isis_format_subsubtlvs(adj->subsubtlvs, - NULL, - arr_adj_json, + NULL, flags_json, indent + 4); } } else @@ -1432,8 +1430,7 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, json_object_array_add(arr_adj_json, flags_json); if (lan->subsubtlvs) isis_format_subsubtlvs(lan->subsubtlvs, - NULL, - arr_adj_json, + NULL, flags_json, indent + 4); } /* end old deprecated key format */ @@ -1477,8 +1474,7 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, json_object_array_add(arr_adj_json, flags_json); if (lan->subsubtlvs) isis_format_subsubtlvs(lan->subsubtlvs, - NULL, - arr_adj_json, + NULL, flags_json, indent + 4); } } else From fdb89ab51a83cd4cb1c4ce3068eba5e3a431954b Mon Sep 17 00:00:00 2001 From: Carmine Scarpitta Date: Fri, 21 Jun 2024 17:01:49 +0200 Subject: [PATCH 114/347] zebra: Remove dead SRv6 code At line 1736, `alloc_mode` is set to `SRV6_SID_ALLOC_MODE_EXPLICIT` or `SRV6_SID_ALLOC_MODE_DYNAMIC` depending on the `sid_value` variable. There will never be a case where alloc_mode will be `SRV6_SID_ALLOC_MODE_MAX` or `SRV6_SID_ALLOC_MODE_UNSPEC`. Let's replace the `switch(alloc_mode) {...}` with an if-else. Fixes CID 1594015. ** CID 1594015: (DEADCODE) /zebra/zebra_srv6.c: 1782 in get_srv6_sid() /zebra/zebra_srv6.c: 1781 in get_srv6_sid() ________________________________________________________________________________________________________ *** CID 1594015: (DEADCODE) /zebra/zebra_srv6.c: 1782 in get_srv6_sid() 1776 } 1777 1778 ret = get_srv6_sid_dynamic(sid, ctx, locator); 1779 1780 break; 1781 case SRV6_SID_ALLOC_MODE_MAX: CID 1594015: (DEADCODE) Execution cannot reach this statement: "case SRV6_SID_ALLOC_MODE_UN...". 1782 case SRV6_SID_ALLOC_MODE_UNSPEC: 1783 default: 1784 flog_err(EC_ZEBRA_SM_CANNOT_ASSIGN_SID, 1785 "%s: SRv6 Manager: Unrecognized alloc mode %u", 1786 __func__, alloc_mode); 1787 /* We should never arrive here */ /zebra/zebra_srv6.c: 1781 in get_srv6_sid() 1775 return -1; 1776 } 1777 1778 ret = get_srv6_sid_dynamic(sid, ctx, locator); 1779 1780 break; CID 1594015: (DEADCODE) Execution cannot reach this statement: "case SRV6_SID_ALLOC_MODE_MAX:". 1781 case SRV6_SID_ALLOC_MODE_MAX: 1782 case SRV6_SID_ALLOC_MODE_UNSPEC: 1783 default: 1784 flog_err(EC_ZEBRA_SM_CANNOT_ASSIGN_SID, 1785 "%s: SRv6 Manager: Unrecognized alloc mode %u", 1786 __func__, alloc_mode); Signed-off-by: Carmine Scarpitta --- zebra/zebra_srv6.c | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/zebra/zebra_srv6.c b/zebra/zebra_srv6.c index 0ca77a4974..2c1f86a3fc 100644 --- a/zebra/zebra_srv6.c +++ b/zebra/zebra_srv6.c @@ -1742,8 +1742,7 @@ int get_srv6_sid(struct zebra_srv6_sid **sid, struct srv6_sid_ctx *ctx, __func__, srv6_sid_ctx2str(buf, sizeof(buf), ctx), sid_value, srv6_sid_alloc_mode2str(alloc_mode)); - switch (alloc_mode) { - case SRV6_SID_ALLOC_MODE_EXPLICIT: + if (alloc_mode == SRV6_SID_ALLOC_MODE_EXPLICIT) { /* * Explicit SID allocation: allocate a specific SID value */ @@ -1755,9 +1754,7 @@ int get_srv6_sid(struct zebra_srv6_sid **sid, struct srv6_sid_ctx *ctx, } ret = get_srv6_sid_explicit(sid, ctx, sid_value); - - break; - case SRV6_SID_ALLOC_MODE_DYNAMIC: + } else { /* * Dynamic SID allocation: allocate any available SID value */ @@ -1776,16 +1773,6 @@ int get_srv6_sid(struct zebra_srv6_sid **sid, struct srv6_sid_ctx *ctx, } ret = get_srv6_sid_dynamic(sid, ctx, locator); - - break; - case SRV6_SID_ALLOC_MODE_MAX: - case SRV6_SID_ALLOC_MODE_UNSPEC: - default: - flog_err(EC_ZEBRA_SM_CANNOT_ASSIGN_SID, - "%s: SRv6 Manager: Unrecognized alloc mode %u", - __func__, alloc_mode); - /* We should never arrive here */ - assert(0); } return ret; From 375a02d2a30cd7a06b568187e23226ad5d083c87 Mon Sep 17 00:00:00 2001 From: Carmine Scarpitta Date: Fri, 21 Jun 2024 17:41:34 +0200 Subject: [PATCH 115/347] zebra: Fix wrong variable used in `for` loop The `for` loop starting at line 1848 searches the `func_allocated` array for a pointer that points to a specific `sid_wide_func` element. The loop should iterate over all the elements of the `func_allocated` array and dereference each element to see if it is the one we are looking for. Currently, the loop is using the wrong variable to iterate over the array. Let's fix this issue by using the correct variable in the loop. Fixes CID 1594014 Fixes CID 1594016 ** CID 1594014: Null pointer dereferences (FORWARD_NULL) /zebra/zebra_srv6.c: 1860 in release_srv6_sid_func_explicit() ________________________________________________________________________________________________________ *** CID 1594014: Null pointer dereferences (FORWARD_NULL) /zebra/zebra_srv6.c: 1860 in release_srv6_sid_func_explicit() 1854 1855 /* Lookup SID function in the functions allocated list of EWLIB range */ 1856 for (ALL_LIST_ELEMENTS_RO(block->u.usid 1857 .wide_lib[sid_func] 1858 .func_allocated, 1859 node, sid_func_ptr)) CID 1594014: Null pointer dereferences (FORWARD_NULL) Dereferencing null pointer "sid_wide_func_ptr". 1860 if (*sid_wide_func_ptr == sid_wide_func) 1861 break; 1862 1863 /* Ensure that the SID function is allocated */ 1864 if (!sid_wide_func_ptr) { 1865 zlog_warn("%s: failed to release wide SID function %u, function is not allocated", ** CID 1594016: Possible Control flow issues (DEADCODE) /zebra/zebra_srv6.c: 1871 in release_srv6_sid_func_explicit() ________________________________________________________________________________________________________ *** CID 1594016: Possible Control flow issues (DEADCODE) /zebra/zebra_srv6.c: 1871 in release_srv6_sid_func_explicit() 1865 zlog_warn("%s: failed to release wide SID function %u, function is not allocated", 1866 __func__, sid_wide_func); 1867 return -1; 1868 } 1869 1870 /* Release the SID function from the EWLIB range */ CID 1594016: Possible Control flow issues (DEADCODE) Execution cannot reach this statement: "listnode_delete(block->u.us...". 1871 listnode_delete(block->u.usid.wide_lib[sid_func] 1872 .func_allocated, 1873 sid_wide_func_ptr); 1874 zebra_srv6_sid_func_free(sid_wide_func_ptr); 1875 } else { 1876 zlog_warn("%s: function %u is outside ELIB [%u/%u] and EWLIB alloc ranges [%u/%u]", Signed-off-by: Carmine Scarpitta --- zebra/zebra_srv6.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zebra/zebra_srv6.c b/zebra/zebra_srv6.c index 2c1f86a3fc..be335a5ded 100644 --- a/zebra/zebra_srv6.c +++ b/zebra/zebra_srv6.c @@ -1843,7 +1843,7 @@ static bool release_srv6_sid_func_explicit(struct zebra_srv6_sid_block *block, for (ALL_LIST_ELEMENTS_RO(block->u.usid .wide_lib[sid_func] .func_allocated, - node, sid_func_ptr)) + node, sid_wide_func_ptr)) if (*sid_wide_func_ptr == sid_wide_func) break; From df97a9d13318f15c59bb055b90529e9e8378a619 Mon Sep 17 00:00:00 2001 From: Carmine Scarpitta Date: Fri, 21 Jun 2024 17:47:46 +0200 Subject: [PATCH 116/347] zebra: Fix NULL pointer dereference The `locator` pointer is dereferenced before ensuring it is not NULL. Fix the issue by checking that the pointer is not NULL before dereferencing it. Fixes 1594013 ** CID 1594013: Null pointer dereferences (REVERSE_INULL) /zebra/zebra_srv6.c: 961 in zebra_srv6_sid_compose() ________________________________________________________________________________________________________ *** CID 1594013: Null pointer dereferences (REVERSE_INULL) /zebra/zebra_srv6.c: 961 in zebra_srv6_sid_compose() 955 struct srv6_locator *locator, 956 uint32_t sid_func) 957 { 958 uint8_t offset, func_len; 959 struct srv6_sid_format *format = locator->sid_format; 960 CID 1594013: Null pointer dereferences (REVERSE_INULL) Null-checking "locator" suggests that it may be null, but it has already been dereferenced on all paths leading to the check. 961 if (!sid_value || !locator) 962 return false; 963 964 if (format) { 965 offset = format->block_len + format->node_len; 966 func_len = format->function_len; Signed-off-by: Carmine Scarpitta --- zebra/zebra_srv6.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/zebra/zebra_srv6.c b/zebra/zebra_srv6.c index be335a5ded..e82b781c6f 100644 --- a/zebra/zebra_srv6.c +++ b/zebra/zebra_srv6.c @@ -956,11 +956,12 @@ static bool zebra_srv6_sid_compose(struct in6_addr *sid_value, uint32_t sid_func) { uint8_t offset, func_len; - struct srv6_sid_format *format = locator->sid_format; + struct srv6_sid_format *format; if (!sid_value || !locator) return false; + format = locator->sid_format; if (format) { offset = format->block_len + format->node_len; func_len = format->function_len; From c554b5d90a40d16423a015849b76d56045fb7702 Mon Sep 17 00:00:00 2001 From: Louis Scalbert Date: Fri, 21 Jun 2024 11:17:32 +0200 Subject: [PATCH 117/347] isisd: remane flags_json variable The variable flags_json was incorrectly named, leading to confusion and causing the bug fixed in the previous commit. Rename the variable to refer to SRv6 End SID instead. Cosmetic change. Signed-off-by: Louis Scalbert --- isisd/isis_tlvs.c | 373 ++++++++++++++++++++++++---------------------- 1 file changed, 195 insertions(+), 178 deletions(-) diff --git a/isisd/isis_tlvs.c b/isisd/isis_tlvs.c index 1c34550152..4ea384ef23 100644 --- a/isisd/isis_tlvs.c +++ b/isisd/isis_tlvs.c @@ -1010,7 +1010,7 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, struct isis_adj_sid *adj; if (json) { - struct json_object *arr_adj_json, *flags_json; + struct json_object *arr_adj_json, *adj_sid_json; #if CONFDATE > 20240916 CPP_NOTICE("remove deprecated key format with -") @@ -1022,42 +1022,37 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, adj; adj = adj->next) { snprintfrr(cnt_buf, sizeof(cnt_buf), "%d", adj->sid); - flags_json = json_object_new_object(); - json_object_int_add(flags_json, "sid", + adj_sid_json = json_object_new_object(); + json_object_int_add(adj_sid_json, "sid", adj->sid); - json_object_int_add(flags_json, "weight", + json_object_int_add(adj_sid_json, "weight", adj->weight); - json_object_string_add( - flags_json, "flag-f", - adj->flags & EXT_SUBTLV_LINK_ADJ_SID_FFLG - ? "1" - : "0"); - json_object_string_add( - flags_json, "flag-b", - adj->flags & EXT_SUBTLV_LINK_ADJ_SID_BFLG - ? "1" - : "0"); - json_object_string_add( - flags_json, "flag-v", - adj->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG - ? "1" - : "0"); - json_object_string_add( - flags_json, "flag-l", - adj->flags & EXT_SUBTLV_LINK_ADJ_SID_LFLG - ? "1" - : "0"); - json_object_string_add( - flags_json, "flag-s", - adj->flags & EXT_SUBTLV_LINK_ADJ_SID_SFLG - ? "1" - : "0"); - json_object_string_add( - flags_json, "flag-p", - adj->flags & EXT_SUBTLV_LINK_ADJ_SID_PFLG - ? "1" - : "0"); - json_object_array_add(arr_adj_json, flags_json); + json_object_string_add(adj_sid_json, "flag-f", + adj->flags & EXT_SUBTLV_LINK_ADJ_SID_FFLG + ? "1" + : "0"); + json_object_string_add(adj_sid_json, "flag-b", + adj->flags & EXT_SUBTLV_LINK_ADJ_SID_BFLG + ? "1" + : "0"); + json_object_string_add(adj_sid_json, "flag-v", + adj->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG + ? "1" + : "0"); + json_object_string_add(adj_sid_json, "flag-l", + adj->flags & EXT_SUBTLV_LINK_ADJ_SID_LFLG + ? "1" + : "0"); + json_object_string_add(adj_sid_json, "flag-s", + adj->flags & EXT_SUBTLV_LINK_ADJ_SID_SFLG + ? "1" + : "0"); + json_object_string_add(adj_sid_json, "flag-p", + adj->flags & EXT_SUBTLV_LINK_ADJ_SID_PFLG + ? "1" + : "0"); + json_object_array_add(arr_adj_json, + adj_sid_json); } /* end old deprecated key format */ @@ -1067,35 +1062,37 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, adj; adj = adj->next) { snprintfrr(cnt_buf, sizeof(cnt_buf), "%d", adj->sid); - flags_json = json_object_new_object(); - json_object_int_add(flags_json, "sid", adj->sid); - json_object_int_add(flags_json, "weight", + adj_sid_json = json_object_new_object(); + json_object_int_add(adj_sid_json, "sid", + adj->sid); + json_object_int_add(adj_sid_json, "weight", adj->weight); - json_object_boolean_add(flags_json, "flagF", + json_object_boolean_add(adj_sid_json, "flagF", adj->flags & EXT_SUBTLV_LINK_ADJ_SID_FFLG ? true : false); - json_object_boolean_add(flags_json, "flagB", + json_object_boolean_add(adj_sid_json, "flagB", adj->flags & EXT_SUBTLV_LINK_ADJ_SID_BFLG ? true : false); - json_object_boolean_add(flags_json, "flagV", + json_object_boolean_add(adj_sid_json, "flagV", adj->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG ? true : false); - json_object_boolean_add(flags_json, "flagL", + json_object_boolean_add(adj_sid_json, "flagL", adj->flags & EXT_SUBTLV_LINK_ADJ_SID_LFLG ? true : false); - json_object_boolean_add(flags_json, "flagS", + json_object_boolean_add(adj_sid_json, "flagS", adj->flags & EXT_SUBTLV_LINK_ADJ_SID_SFLG ? true : false); - json_object_boolean_add(flags_json, "flagP", + json_object_boolean_add(adj_sid_json, "flagP", adj->flags & EXT_SUBTLV_LINK_ADJ_SID_PFLG ? true : false); - json_object_array_add(arr_adj_json, flags_json); + json_object_array_add(arr_adj_json, + adj_sid_json); } } else for (adj = (struct isis_adj_sid *)exts->adj_sid.head; @@ -1128,7 +1125,7 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, if (IS_SUBTLV(exts, EXT_LAN_ADJ_SID)) { struct isis_lan_adj_sid *lan; if (json) { - struct json_object *arr_adj_json, *flags_json; + struct json_object *arr_adj_json, *lan_adj_json; #if CONFDATE > 20240916 CPP_NOTICE("remove deprecated key format with -") @@ -1147,42 +1144,37 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, continue; snprintfrr(cnt_buf, sizeof(cnt_buf), "%d", lan->sid); - flags_json = json_object_new_object(); - json_object_int_add(flags_json, "sid", + lan_adj_json = json_object_new_object(); + json_object_int_add(lan_adj_json, "sid", lan->sid); - json_object_int_add(flags_json, "weight", + json_object_int_add(lan_adj_json, "weight", lan->weight); - json_object_string_add( - flags_json, "flag-f", - lan->flags & EXT_SUBTLV_LINK_ADJ_SID_FFLG - ? "1" - : "0"); - json_object_string_add( - flags_json, "flag-b", - lan->flags & EXT_SUBTLV_LINK_ADJ_SID_BFLG - ? "1" - : "0"); - json_object_string_add( - flags_json, "flag-v", - lan->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG - ? "1" - : "0"); - json_object_string_add( - flags_json, "flag-l", - lan->flags & EXT_SUBTLV_LINK_ADJ_SID_LFLG - ? "1" - : "0"); - json_object_string_add( - flags_json, "flag-s", - lan->flags & EXT_SUBTLV_LINK_ADJ_SID_SFLG - ? "1" - : "0"); - json_object_string_add( - flags_json, "flag-p", - lan->flags & EXT_SUBTLV_LINK_ADJ_SID_PFLG - ? "1" - : "0"); - json_object_array_add(arr_adj_json, flags_json); + json_object_string_add(lan_adj_json, "flag-f", + lan->flags & EXT_SUBTLV_LINK_ADJ_SID_FFLG + ? "1" + : "0"); + json_object_string_add(lan_adj_json, "flag-b", + lan->flags & EXT_SUBTLV_LINK_ADJ_SID_BFLG + ? "1" + : "0"); + json_object_string_add(lan_adj_json, "flag-v", + lan->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG + ? "1" + : "0"); + json_object_string_add(lan_adj_json, "flag-l", + lan->flags & EXT_SUBTLV_LINK_ADJ_SID_LFLG + ? "1" + : "0"); + json_object_string_add(lan_adj_json, "flag-s", + lan->flags & EXT_SUBTLV_LINK_ADJ_SID_SFLG + ? "1" + : "0"); + json_object_string_add(lan_adj_json, "flag-p", + lan->flags & EXT_SUBTLV_LINK_ADJ_SID_PFLG + ? "1" + : "0"); + json_object_array_add(arr_adj_json, + lan_adj_json); } /* end old deprecated key format */ @@ -1197,35 +1189,37 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, continue; snprintfrr(cnt_buf, sizeof(cnt_buf), "%d", lan->sid); - flags_json = json_object_new_object(); - json_object_int_add(flags_json, "sid", lan->sid); - json_object_int_add(flags_json, "weight", + lan_adj_json = json_object_new_object(); + json_object_int_add(lan_adj_json, "sid", + lan->sid); + json_object_int_add(lan_adj_json, "weight", lan->weight); - json_object_boolean_add(flags_json, "flagF", + json_object_boolean_add(lan_adj_json, "flagF", lan->flags & EXT_SUBTLV_LINK_ADJ_SID_FFLG ? true : false); - json_object_boolean_add(flags_json, "flagB", + json_object_boolean_add(lan_adj_json, "flagB", lan->flags & EXT_SUBTLV_LINK_ADJ_SID_BFLG ? true : false); - json_object_boolean_add(flags_json, "flagV", + json_object_boolean_add(lan_adj_json, "flagV", lan->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG ? true : false); - json_object_boolean_add(flags_json, "flagL", + json_object_boolean_add(lan_adj_json, "flagL", lan->flags & EXT_SUBTLV_LINK_ADJ_SID_LFLG ? true : false); - json_object_boolean_add(flags_json, "flagS", + json_object_boolean_add(lan_adj_json, "flagS", lan->flags & EXT_SUBTLV_LINK_ADJ_SID_SFLG ? true : false); - json_object_boolean_add(flags_json, "flagP", + json_object_boolean_add(lan_adj_json, "flagP", lan->flags & EXT_SUBTLV_LINK_ADJ_SID_PFLG ? true : false); - json_object_array_add(arr_adj_json, flags_json); + json_object_array_add(arr_adj_json, + lan_adj_json); } } else @@ -1268,7 +1262,7 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, struct isis_srv6_endx_sid_subtlv *adj; if (json) { - struct json_object *arr_adj_json, *flags_json; + struct json_object *arr_adj_json, *srv6_endx_sid_json; #if CONFDATE > 20240916 CPP_NOTICE("remove deprecated key format with -") @@ -1282,36 +1276,41 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, adj; adj = adj->next) { snprintfrr(cnt_buf, sizeof(cnt_buf), "%pI6", &adj->sid); - flags_json = json_object_new_object(); - json_object_string_addf(flags_json, "sid", - "%pI6", &adj->sid); - json_object_string_add( - flags_json, "algorithm", - sr_algorithm_string(adj->algorithm)); - json_object_int_add(flags_json, "weight", - adj->weight); - json_object_string_add( - flags_json, "behavior", - seg6local_action2str(adj->behavior)); - json_object_string_add( - flags_json, "flag-b", - adj->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_BFLG - ? "1" - : "0"); - json_object_string_add( - flags_json, "flag-s", - adj->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_SFLG - ? "1" - : "0"); - json_object_string_add( - flags_json, "flag-p", - adj->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_PFLG - ? "1" - : "0"); - json_object_array_add(arr_adj_json, flags_json); + srv6_endx_sid_json = json_object_new_object(); + json_object_string_addf(srv6_endx_sid_json, + "sid", "%pI6", + &adj->sid); + json_object_string_add(srv6_endx_sid_json, + "algorithm", + sr_algorithm_string( + adj->algorithm)); + json_object_int_add(srv6_endx_sid_json, + "weight", adj->weight); + json_object_string_add(srv6_endx_sid_json, + "behavior", + seg6local_action2str( + adj->behavior)); + json_object_string_add(srv6_endx_sid_json, + "flag-b", + adj->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_BFLG + ? "1" + : "0"); + json_object_string_add(srv6_endx_sid_json, + "flag-s", + adj->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_SFLG + ? "1" + : "0"); + json_object_string_add(srv6_endx_sid_json, + "flag-p", + adj->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_PFLG + ? "1" + : "0"); + json_object_array_add(arr_adj_json, + srv6_endx_sid_json); if (adj->subsubtlvs) isis_format_subsubtlvs(adj->subsubtlvs, - NULL, flags_json, + NULL, + srv6_endx_sid_json, indent + 4); } /* end old deprecated key format */ @@ -1323,33 +1322,38 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, adj; adj = adj->next) { snprintfrr(cnt_buf, sizeof(cnt_buf), "%pI6", &adj->sid); - flags_json = json_object_new_object(); - json_object_string_addf(flags_json, "sid", - "%pI6", &adj->sid); - json_object_string_add(flags_json, "algorithm", + srv6_endx_sid_json = json_object_new_object(); + json_object_string_addf(srv6_endx_sid_json, + "sid", "%pI6", + &adj->sid); + json_object_string_add(srv6_endx_sid_json, + "algorithm", sr_algorithm_string( adj->algorithm)); - json_object_int_add(flags_json, "weight", - adj->weight); - json_object_string_add(flags_json, "behavior", + json_object_int_add(srv6_endx_sid_json, + "weight", adj->weight); + json_object_string_add(srv6_endx_sid_json, + "behavior", seg6local_action2str( adj->behavior)); json_object_boolean_add( - flags_json, "flagB", + srv6_endx_sid_json, "flagB", !!(adj->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_BFLG)); json_object_boolean_add( - flags_json, "flagS", + srv6_endx_sid_json, "flagS", !!(adj->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_SFLG)); json_object_boolean_add( - flags_json, "flagP", + srv6_endx_sid_json, "flagP", !!(adj->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_PFLG)); - json_object_array_add(arr_adj_json, flags_json); + json_object_array_add(arr_adj_json, + srv6_endx_sid_json); if (adj->subsubtlvs) isis_format_subsubtlvs(adj->subsubtlvs, - NULL, flags_json, + NULL, + srv6_endx_sid_json, indent + 4); } } else @@ -1382,7 +1386,8 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, if (IS_SUBTLV(exts, EXT_SRV6_LAN_ENDX_SID)) { struct isis_srv6_lan_endx_sid_subtlv *lan; if (json) { - struct json_object *arr_adj_json, *flags_json; + struct json_object *arr_adj_json, + *srv6_lan_endx_sid_json; #if CONFDATE > 20240916 CPP_NOTICE("remove deprecated key format with -") @@ -1396,41 +1401,47 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, lan; lan = lan->next) { snprintfrr(cnt_buf, sizeof(cnt_buf), "%pI6", &lan->sid); - flags_json = json_object_new_object(); - json_object_string_addf(flags_json, "sid", - "%pI6", &lan->sid); - json_object_int_add(flags_json, "weight", - lan->weight); - json_object_string_add( - flags_json, "algorithm", - sr_algorithm_string(lan->algorithm)); - json_object_int_add(flags_json, "weight", - lan->weight); - json_object_string_add( - flags_json, "behavior", - seg6local_action2str(lan->behavior)); - json_object_string_add( - flags_json, "flag-b", - lan->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_BFLG - ? "1" - : "0"); - json_object_string_add( - flags_json, "flag-s", - lan->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_SFLG - ? "1" - : "0"); - json_object_string_add( - flags_json, "flag-p", - lan->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_PFLG - ? "1" - : "0"); - json_object_string_addf(flags_json, + srv6_lan_endx_sid_json = + json_object_new_object(); + json_object_string_addf(srv6_lan_endx_sid_json, + "sid", "%pI6", + &lan->sid); + json_object_int_add(srv6_lan_endx_sid_json, + "weight", lan->weight); + json_object_string_add(srv6_lan_endx_sid_json, + "algorithm", + sr_algorithm_string( + lan->algorithm)); + json_object_int_add(srv6_lan_endx_sid_json, + "weight", lan->weight); + json_object_string_add(srv6_lan_endx_sid_json, + "behavior", + seg6local_action2str( + lan->behavior)); + json_object_string_add(srv6_lan_endx_sid_json, + "flag-b", + lan->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_BFLG + ? "1" + : "0"); + json_object_string_add(srv6_lan_endx_sid_json, + "flag-s", + lan->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_SFLG + ? "1" + : "0"); + json_object_string_add(srv6_lan_endx_sid_json, + "flag-p", + lan->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_PFLG + ? "1" + : "0"); + json_object_string_addf(srv6_lan_endx_sid_json, "neighbor-id", "%pSY", lan->neighbor_id); - json_object_array_add(arr_adj_json, flags_json); + json_object_array_add(arr_adj_json, + srv6_lan_endx_sid_json); if (lan->subsubtlvs) isis_format_subsubtlvs(lan->subsubtlvs, - NULL, flags_json, + NULL, + srv6_lan_endx_sid_json, indent + 4); } /* end old deprecated key format */ @@ -1443,38 +1454,44 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, lan; lan = lan->next) { snprintfrr(cnt_buf, sizeof(cnt_buf), "%pI6", &lan->sid); - flags_json = json_object_new_object(); - json_object_string_addf(flags_json, "sid", - "%pI6", &lan->sid); - json_object_int_add(flags_json, "weight", - lan->weight); - json_object_string_add(flags_json, "algorithm", + srv6_lan_endx_sid_json = + json_object_new_object(); + json_object_string_addf(srv6_lan_endx_sid_json, + "sid", "%pI6", + &lan->sid); + json_object_int_add(srv6_lan_endx_sid_json, + "weight", lan->weight); + json_object_string_add(srv6_lan_endx_sid_json, + "algorithm", sr_algorithm_string( lan->algorithm)); - json_object_int_add(flags_json, "weight", - lan->weight); - json_object_string_add(flags_json, "behavior", + json_object_int_add(srv6_lan_endx_sid_json, + "weight", lan->weight); + json_object_string_add(srv6_lan_endx_sid_json, + "behavior", seg6local_action2str( lan->behavior)); json_object_boolean_add( - flags_json, "flagB", + srv6_lan_endx_sid_json, "flagB", !!(lan->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_BFLG)); json_object_boolean_add( - flags_json, "flagS", + srv6_lan_endx_sid_json, "flagS", !!(lan->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_SFLG)); json_object_boolean_add( - flags_json, "flagP", + srv6_lan_endx_sid_json, "flagP", !!(lan->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_PFLG)); - json_object_string_addf(flags_json, + json_object_string_addf(srv6_lan_endx_sid_json, "neighbor-id", "%pSY", lan->neighbor_id); - json_object_array_add(arr_adj_json, flags_json); + json_object_array_add(arr_adj_json, + srv6_lan_endx_sid_json); if (lan->subsubtlvs) isis_format_subsubtlvs(lan->subsubtlvs, - NULL, flags_json, + NULL, + srv6_lan_endx_sid_json, indent + 4); } } else From 3e82cf29286407eb1b088c33a5deb4b673574a74 Mon Sep 17 00:00:00 2001 From: Louis Scalbert Date: Fri, 21 Jun 2024 11:18:59 +0200 Subject: [PATCH 118/347] isisd: fix neighbor id json key d5879267aa ("isisd: fix show database json format") renamed JSON keys to a standard format but forgot to rename the neighbor-id key. Fixes: d5879267aa ("isisd: fix show database json format") Signed-off-by: Louis Scalbert --- isisd/isis_tlvs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/isisd/isis_tlvs.c b/isisd/isis_tlvs.c index 4ea384ef23..8405ad089c 100644 --- a/isisd/isis_tlvs.c +++ b/isisd/isis_tlvs.c @@ -1484,7 +1484,7 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, !!(lan->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_PFLG)); json_object_string_addf(srv6_lan_endx_sid_json, - "neighbor-id", "%pSY", + "neighborID", "%pSY", lan->neighbor_id); json_object_array_add(arr_adj_json, srv6_lan_endx_sid_json); From cd2e872e65c0512b2d57a92517622efe21cf306e Mon Sep 17 00:00:00 2001 From: Louis Scalbert Date: Mon, 24 Jun 2024 13:38:37 +0200 Subject: [PATCH 119/347] isisd: fix srv6 endx sid key name srv6EndSID is actually srv6EndXSID. Fixes: d5879267aa ("isisd: fix show database json format") Signed-off-by: Louis Scalbert --- isisd/isis_tlvs.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/isisd/isis_tlvs.c b/isisd/isis_tlvs.c index 8405ad089c..c7f45b2469 100644 --- a/isisd/isis_tlvs.c +++ b/isisd/isis_tlvs.c @@ -1316,7 +1316,8 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, /* end old deprecated key format */ arr_adj_json = json_object_new_array(); - json_object_object_add(json, "srv6EndSID", arr_adj_json); + json_object_object_add(json, "srv6EndXSID", + arr_adj_json); for (adj = (struct isis_srv6_endx_sid_subtlv *) exts->srv6_endx_sid.head; adj; adj = adj->next) { From 3b98ddf5018cf7526b50c15018cbaf71a38fa752 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Mon, 24 Jun 2024 20:16:16 +0300 Subject: [PATCH 120/347] bgpd: Relax OAD (One-Administration-Domain) for RFC8212 RFC 8212 defines leak prevention for eBGP peers, but BGP-OAD defines a new peering type One Administrative Domain (OAD), where multiple ASNs could be used inside a single administrative domain. OAD allows sending non-transitive attributes, so this prevention should be relaxed too. Signed-off-by: Donatas Abraitis --- bgpd/bgp_route.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 4dcb22234a..9c3602311f 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -6333,7 +6333,7 @@ void bgp_set_stale_route(struct peer *peer, afi_t afi, safi_t safi) bool bgp_outbound_policy_exists(struct peer *peer, struct bgp_filter *filter) { - if (peer->sort == BGP_PEER_IBGP) + if (peer->sort == BGP_PEER_IBGP || peer->sub_sort == BGP_PEER_EBGP_OAD) return true; if (peer->sort == BGP_PEER_EBGP && @@ -6346,7 +6346,7 @@ bool bgp_outbound_policy_exists(struct peer *peer, struct bgp_filter *filter) bool bgp_inbound_policy_exists(struct peer *peer, struct bgp_filter *filter) { - if (peer->sort == BGP_PEER_IBGP) + if (peer->sort == BGP_PEER_IBGP || peer->sub_sort == BGP_PEER_EBGP_OAD) return true; if (peer->sort == BGP_PEER_EBGP From 8044d733009dd428c291460eb8b0e539b53b78fa Mon Sep 17 00:00:00 2001 From: Piotr Suchy Date: Wed, 22 May 2024 10:41:52 +0200 Subject: [PATCH 121/347] bgpd: Ignore routes from evpn if VRF is unknown Fix for a bug, where FRR fails to install route received for an unknown but later-created VRF - detailed description can be found here https://github.com/FRRouting/frr/issues/13708 Signed-off-by: Piotr Suchy --- bgpd/bgp_evpn.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index 5d6a5a59f5..6680b54f76 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -3037,6 +3037,9 @@ static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf, vrf_id_to_name(bgp_vrf->vrf_id), evp, parent_pi, parent_pi->flags); + if (bgp_vrf->vrf_id == VRF_UNKNOWN) + return -1; + /* Create (or fetch) route within the VRF. */ /* NOTE: There is no RD here. */ if (is_evpn_prefix_ipaddr_v4(evp)) { From 8ef75009a77718ceda4bb79f7a43cf7577271afa Mon Sep 17 00:00:00 2001 From: Quentin Young Date: Tue, 25 Jun 2024 13:48:33 -0400 Subject: [PATCH 122/347] doc: improve table-of-contents organization The current TOC organization is not really following Sphinx best practices and is resulting in a jumble of articles showing up in the sidebar. This change primarily organizes existing articles into three major sections: * Introduction - Contains system requirements, architecture & design, installation, basic setup * Basics - Covers basic commands, concepts, and some random things that don't fit elsewhere * Protocols - Contains all protocol documentation, and other miscellaneous daemon docs such as those on Zebra, watchfrr, mgmtd, etc. The appendix has been left as is, but the TOC now has a caption which has the effect of adding a section separator in the nav sidebar. In order to make the new structure make sense: * Some content has been lifted up from the "Overview" page into the index page * Most content has been pushed down from the "Overview" page into the "About" page (new) * BFD's page is now titled "BFD" for consistencty; it was the only one that had the full protocol name written out in the title And a couple drivebys: * BFD's intro description paragraph was rewritten to make more sense * Old language stating that we publish platform packages on the Github releases page was removed * References to source building instructions were consolidated into that section Signed-off-by: Quentin Young --- doc/user/{overview.rst => about.rst} | 57 +++----------------- doc/user/basics.rst | 23 ++++++++ doc/user/bfd.rst | 19 ++++--- doc/user/index.rst | 81 ++++++---------------------- doc/user/installation.rst | 31 ++++++----- doc/user/introduction.rst | 13 +++++ doc/user/protocols.rst | 35 ++++++++++++ doc/user/subdir.am | 2 +- 8 files changed, 125 insertions(+), 136 deletions(-) rename doc/user/{overview.rst => about.rst} (94%) create mode 100644 doc/user/basics.rst create mode 100644 doc/user/introduction.rst create mode 100644 doc/user/protocols.rst diff --git a/doc/user/overview.rst b/doc/user/about.rst similarity index 94% rename from doc/user/overview.rst rename to doc/user/about.rst index 2ef88acd7a..7d30a86154 100644 --- a/doc/user/overview.rst +++ b/doc/user/about.rst @@ -1,47 +1,8 @@ .. _overview: -******** -Overview -******** - -`FRR`_ is a fully featured, high performance, free software IP routing suite. - -FRR implements all standard routing protocols such as BGP, RIP, OSPF, IS-IS and -more (see :ref:`feature-matrix`), as well as many of their extensions. - -FRR is a high performance suite written primarily in C. It can easily handle -full Internet routing tables and is suitable for use on hardware ranging from -cheap SBCs to commercial grade routers. It is actively used in production by -hundreds of companies, universities, research labs and governments. - -FRR is distributed under GPLv2, with development modeled after the Linux -kernel. Anyone may contribute features, bug fixes, tools, documentation -updates, or anything else. - -FRR is a fork of `Quagga `_. - -.. _how-to-get-frr: - -How to get FRR -============== - -The official FRR website is located at |PACKAGE_URL| and contains further -information, as well as links to additional resources. - -Several distributions provide packages for FRR. Check your distribution's -repositories to find out if a suitable version is available. - -Up-to-date Debian & Redhat packages are available at https://deb.frrouting.org/ -& https://rpm.frrouting.org/ respectively. - -For instructions on installing from source, refer to the -`developer documentation `_. - - -.. _about-frr: - +********* About FRR -========= +********* FRR provides IP routing services. Its role in a networking stack is to exchange routing information with other routers, make routing and policy decisions, and @@ -55,11 +16,8 @@ light L2 functionality as well, but this is mostly left to the platform. This makes it suitable for deployments ranging from small home networks with static routes to Internet exchanges running full Internet tables. -FRR runs on all modern \*NIX operating systems, including Linux and the BSDs. -Feature support varies by platform; see the :ref:`feature-matrix`. - System Requirements -------------------- +=================== System resources needed by FRR are highly dependent on workload. Routing software performance is particularly susceptible to external factors such as: @@ -86,8 +44,8 @@ information with peers about how to forward packets. Forwarding plane performance largely depends on choice of NIC / ASIC. -System Architecture -------------------- +Architecture +============ .. index:: pair: architecture; FRR @@ -146,9 +104,8 @@ routing stack. .. _supported-platforms: -Supported Platforms -------------------- - +Platform Support +================ Currently FRR supports GNU/Linux and BSD. Porting FRR to other platforms is not too difficult as platform dependent code should be mostly limited to the diff --git a/doc/user/basics.rst b/doc/user/basics.rst new file mode 100644 index 0000000000..4504e9893c --- /dev/null +++ b/doc/user/basics.rst @@ -0,0 +1,23 @@ +.. _basics: + +###### +Basics +###### + +.. toctree:: + :maxdepth: 2 + + basic + extlog + vtysh + grpc + filter + routemap + affinitymap + ipv6 + kernel + snmp + scripting + nexthop_groups + + diff --git a/doc/user/bfd.rst b/doc/user/bfd.rst index 3ca104a3a9..b2127e8955 100644 --- a/doc/user/bfd.rst +++ b/doc/user/bfd.rst @@ -1,12 +1,19 @@ .. _bfd: -********************************** -Bidirectional Forwarding Detection -********************************** +*** +BFD +*** -:abbr:`BFD (Bidirectional Forwarding Detection)` stands for -Bidirectional Forwarding Detection and it is described and extended by -the following RFCs: +:abbr:`BFD (Bidirectional Forwarding Detection)` is: + + a protocol intended to detect faults in the bidirectional path between two + forwarding engines, including interfaces, data link(s), and to the extent + possible the forwarding engines themselves, with potentially very low + latency. + + -- :rfc:`5880` + +It is described and extended by the following RFCs: * :rfc:`5880` * :rfc:`5881` diff --git a/doc/user/index.rst b/doc/user/index.rst index 4789677a9a..d3b632a8de 100644 --- a/doc/user/index.rst +++ b/doc/user/index.rst @@ -1,80 +1,31 @@ FRRouting User Guide ==================== -############ -Introduction -############ +FRR is a fully featured, high performance, free software IP routing suite. It +implements all standard routing protocols such as BGP, RIP, OSPF, IS-IS and +more (see :ref:`feature-matrix`), as well as many of their extensions. It can +handle full Internet routing tables and is suitable for use on hardware ranging +from cheap SBCs to commercial grade routers, and is actively used in production +by hundreds of companies, universities, research labs and governments. -.. _introduction: -.. toctree:: - :maxdepth: 2 - - overview - installation - setup - -###### -Basics -###### +FRR runs on all modern \*NIX operating systems, including Linux and the BSDs. +Feature support varies by platform; see the :ref:`feature-matrix`. -.. _basics: -.. toctree:: - :maxdepth: 2 +FRR is distributed under GPLv2, with development modeled after the Linux +kernel. Anyone may contribute features, bug fixes, tools, documentation +updates, or anything else. - basic - extlog - vtysh - grpc - filter - routemap - affinitymap - ipv6 - kernel - snmp - scripting - nexthop_groups -.. modules +FRR is a fork of `Quagga `_. -######### -Protocols -######### - -.. _protocols: .. toctree:: :maxdepth: 2 - zebra - bfd - bgp - babeld - fabricd - ldpd - eigrpd - evpn - isisd - nhrpd - ospfd - ospf6d - pathd - pim - pimv6 - pbr - ripd - ripngd - sharp - static - vnc - vrrp - bmp - watchfrr - mgmtd - -######## -Appendix -######## + introduction + basics + protocols -.. _appendix: .. toctree:: + :caption: Appendix :maxdepth: 2 bugs diff --git a/doc/user/installation.rst b/doc/user/installation.rst index e49f10491e..4d2017c0f8 100644 --- a/doc/user/installation.rst +++ b/doc/user/installation.rst @@ -3,22 +3,25 @@ single: Installing FRR single: Building FRR -.. _installation: - Installation ============ -This section covers the basics of building, installing and setting up FRR. +This section covers the basics of building, installing and setting up +FRR. +The official FRR website is located at |PACKAGE_URL| and contains further +information, as well as links to additional resources. From Packages ------------- -The project publishes packages for Red Hat, Centos, Debian and Ubuntu on the -`GitHub releases `_. page. External -contributors offer packages for many other platforms including \*BSD, Alpine, -Gentoo, Docker, and others. There is currently no documentation on how to use -those but we hope to add it soon. +Up-to-date Debian & Redhat packages are available at +https://deb.frrouting.org/ & https://rpm.frrouting.org/ respectively. + +Several distributions also provide packages for FRR. Check your +distribution's repositories to find out if a suitable version is +available. + From Snapcraft -------------- @@ -29,12 +32,12 @@ universal Snap images, available at https://snapcraft.io/frr. From Source ----------- -Building FRR from source is the best way to ensure you have the latest features -and bug fixes. Details for each supported platform, including dependency -package listings, permissions, and other gotchas, are in the `developer's -documentation -`_. This -section provides a brief overview on the process. +Building FRR from source is the best way to ensure you have the latest +features and bug fixes. Details for each supported platform, including +dependency package listings, permissions, and other gotchas, are in the +`developer's documentation +`_. +This section provides a brief overview on the process. Getting the Source diff --git a/doc/user/introduction.rst b/doc/user/introduction.rst new file mode 100644 index 0000000000..89866b9c29 --- /dev/null +++ b/doc/user/introduction.rst @@ -0,0 +1,13 @@ +.. _introduction: + +############ +Introduction +############ + +.. toctree:: + :maxdepth: 2 + + about + installation + setup + diff --git a/doc/user/protocols.rst b/doc/user/protocols.rst new file mode 100644 index 0000000000..e571cd66fc --- /dev/null +++ b/doc/user/protocols.rst @@ -0,0 +1,35 @@ +.. _protocols: + +######### +Protocols +######### + +.. toctree:: + :maxdepth: 2 + + zebra + bfd + bgp + babeld + fabricd + ldpd + eigrpd + evpn + isisd + nhrpd + ospfd + ospf6d + pathd + pim + pimv6 + pbr + ripd + ripngd + sharp + static + vnc + vrrp + bmp + watchfrr + mgmtd + diff --git a/doc/user/subdir.am b/doc/user/subdir.am index 4879f7f7ef..395ce305fe 100644 --- a/doc/user/subdir.am +++ b/doc/user/subdir.am @@ -29,7 +29,7 @@ user_RSTFILES = \ doc/user/ospf6d.rst \ doc/user/ospfd.rst \ doc/user/ospf_fundamentals.rst \ - doc/user/overview.rst \ + doc/user/about.rst \ doc/user/packet-dumps.rst \ doc/user/pathd.rst \ doc/user/pim.rst \ From e0ae285eb8beeef7b43bdadc073d8ae346eaeb6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Sang?= Date: Wed, 19 Jun 2024 16:19:22 +0200 Subject: [PATCH 123/347] bgpd: avoid clearing routes for peers that were never established MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Under heavy system load with many peers in passive mode and a large number of routes, bgpd can enter an infinite loop. This occurs while processing timeout BGP_OPEN messages, which prevents it from accepting new connections. The following log entries illustrate the issue: >bgpd[6151]: [VX6SM-8YE5W][EC 33554460] 3.3.2.224: nexthop_set failed, resetting connection - intf 0x0 >bgpd[6151]: [P790V-THJKS][EC 100663299] bgp_open_receive: bgp_getsockname() failed for peer: 3.3.2.224 >bgpd[6151]: [HTQD2-0R1WR][EC 33554451] bgp_process_packet: BGP OPEN receipt failed for peer: 3.3.2.224 ... repeating The issue occurs when bgpd handles a massive number of routes in the RIB while receiving numerous BGP_OPEN packets. If bgpd is overloaded, it fails to process these packets promptly, leading the remote peer to close the connection and resend BGP_OPEN packets. When bgpd eventually starts processing these timeout BGP_OPEN packets, it finds the TCP connection closed by the remote peer, resulting in "bgp_stop()" being called. For each timeout peer, bgpd must iterate through the routing table, which is time-consuming and causes new incoming BGP_OPEN packets to timeout, perpetuating the infinite loop. To address this issue, the code is modified to check if the peer has been established at least once before calling "bgp_clear_route_all()". This ensures that routes are only cleared for peers that had a successful session, preventing unnecessary iterations over the routing table for peers that never established a connection. With this change, BGP_OPEN timeout messages may still occur, but in the worst case, bgpd will stabilize. Before this patch, bgpd could enter a loop where it was unable to accpet any new connections. Signed-off-by: Loïc Sang --- bgpd/bgp_fsm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index 15cc5dbe2e..d41ef8abba 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -1241,7 +1241,7 @@ void bgp_fsm_change_status(struct peer_connection *connection, /* Transition into Clearing or Deleted must /always/ clear all routes.. * (and must do so before actually changing into Deleted.. */ - if (status >= Clearing) { + if (status >= Clearing && (peer->established || peer == bgp->peer_self)) { bgp_clear_route_all(peer); /* If no route was queued for the clear-node processing, From 163a3f582f671b1ac4a0c21cb97da341c756ed2e Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 25 Jun 2024 14:37:27 +0200 Subject: [PATCH 124/347] pimd: fix misplaced braces/logic error The `!rp_info ||` check got added during a cleanup pass. Unfortunately the braces/and/or combination is not correct :( Fixes: b1945363fbf ("pimd: Various buffer overflow reads and crashes") Signed-off-by: David Lamparter --- pimd/pim_rp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pimd/pim_rp.c b/pimd/pim_rp.c index b0fb8a509a..4703ff8a6a 100644 --- a/pimd/pim_rp.c +++ b/pimd/pim_rp.c @@ -1115,8 +1115,8 @@ int pim_rp_set_upstream_addr(struct pim_instance *pim, pim_addr *up, rp_info = pim_rp_find_match_group(pim, &g); - if (!rp_info || ((pim_rpf_addr_is_inaddr_any(&rp_info->rp)) && - (pim_addr_is_any(source)))) { + if ((!rp_info || (pim_rpf_addr_is_inaddr_any(&rp_info->rp))) && + (pim_addr_is_any(source))) { if (PIM_DEBUG_PIM_NHT_RP) zlog_debug("%s: Received a (*,G) with no RP configured", __func__); From 759e93302d8f3120ff101f047c30100430728617 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Wed, 26 Jun 2024 16:13:50 +0200 Subject: [PATCH 125/347] pimd: refactor `pim_rp_set_upstream_addr` Somehow this tiny function ended up being written in a very convoluted way that enabled the braces mixup in the previous commit. Rewrite it to be less confusing. Signed-off-by: David Lamparter --- pimd/pim_rp.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/pimd/pim_rp.c b/pimd/pim_rp.c index 4703ff8a6a..49be9c0a73 100644 --- a/pimd/pim_rp.c +++ b/pimd/pim_rp.c @@ -1107,16 +1107,17 @@ int pim_rp_set_upstream_addr(struct pim_instance *pim, pim_addr *up, pim_addr source, pim_addr group) { struct rp_info *rp_info; - struct prefix g; + struct prefix g = {}; - memset(&g, 0, sizeof(g)); + if (!pim_addr_is_any(source)) { + *up = source; + return 1; + } pim_addr_to_prefix(&g, group); - rp_info = pim_rp_find_match_group(pim, &g); - if ((!rp_info || (pim_rpf_addr_is_inaddr_any(&rp_info->rp))) && - (pim_addr_is_any(source))) { + if (!rp_info || pim_rpf_addr_is_inaddr_any(&rp_info->rp)) { if (PIM_DEBUG_PIM_NHT_RP) zlog_debug("%s: Received a (*,G) with no RP configured", __func__); @@ -1124,11 +1125,7 @@ int pim_rp_set_upstream_addr(struct pim_instance *pim, pim_addr *up, return 0; } - if (pim_addr_is_any(source)) - *up = rp_info->rp.rpf_addr; - else - *up = source; - + *up = rp_info->rp.rpf_addr; return 1; } From 10231d5b99065b7567b04756ecfda8f5cbb19f47 Mon Sep 17 00:00:00 2001 From: Quentin Young Date: Wed, 26 Jun 2024 15:44:08 -0400 Subject: [PATCH 126/347] doc: reformat Sphinx conf.py files Style checking is complaining about these, rightly so. Reformat. Signed-off-by: Quentin Young --- doc/developer/conf.py | 33 ++++++++++++++++++--------------- doc/user/conf.py | 22 ++++++++++++---------- 2 files changed, 30 insertions(+), 25 deletions(-) diff --git a/doc/developer/conf.py b/doc/developer/conf.py index 495c604ae0..6a3ffe1638 100644 --- a/doc/developer/conf.py +++ b/doc/developer/conf.py @@ -18,6 +18,7 @@ import pygments from sphinx.highlighting import lexers from sphinx.util import logging + logger = logging.getLogger(__name__) # If extensions (or modules to document with autodoc) are in another directory, @@ -53,18 +54,18 @@ master_doc = "index" # General information about the project. -project = u"FRR" -copyright = u"2017, FRR" -author = u"FRR authors" +project = "FRR" +copyright = "2017, FRR" +author = "FRR authors" # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # The short X.Y version. -version = u"?.?" +version = "?.?" # The full version, including alpha/beta/rc tags. -release = u"?.?-?" +release = "?.?-?" # ----------------------------------------------------------------------------- @@ -287,7 +288,7 @@ # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ - (master_doc, "FRR.tex", u"FRR Developer's Manual", u"FRR", "manual"), + (master_doc, "FRR.tex", "FRR Developer's Manual", "FRR", "manual"), ] # The name of an image file (relative to this directory) to place at the top of @@ -315,7 +316,7 @@ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). -man_pages = [(master_doc, "frr", u"FRR Developer's Manual", [author], 1)] +man_pages = [(master_doc, "frr", "FRR Developer's Manual", [author], 1)] # If true, show URL addresses after external links. # man_show_urls = False @@ -330,7 +331,7 @@ ( master_doc, "frr", - u"FRR Developer's Manual", + "FRR Developer's Manual", author, "FRR", "One line description of project.", @@ -358,27 +359,29 @@ with open("../extra/frrlexer.py", "rb") as lex: frrlexerpy = lex.read() -frrfmt_re = re.compile(r'^\s*%(?P[^\s]+)\s+\((?P.*)\)\s*$') +frrfmt_re = re.compile(r"^\s*%(?P[^\s]+)\s+\((?P.*)\)\s*$") + def parse_frrfmt(env, text, node): from sphinx import addnodes m = frrfmt_re.match(text) if not m: - logger.warning('could not parse frrfmt:: %r' % (text), location=node) + logger.warning("could not parse frrfmt:: %r" % (text), location=node) node += addnodes.desc_name(text, text) return text - spec, types = m.group('spec'), m.group('types') + spec, types = m.group("spec"), m.group("types") - node += addnodes.desc_sig_operator('%', '%') - node += addnodes.desc_name(spec + ' ', spec + ' ') + node += addnodes.desc_sig_operator("%", "%") + node += addnodes.desc_name(spec + " ", spec + " ") plist = addnodes.desc_parameterlist() - for typ in types.split(','): + for typ in types.split(","): typ = typ.strip() plist += addnodes.desc_parameter(typ, typ) node += plist - return '%' + spec + return "%" + spec + # custom extensions here def setup(app): diff --git a/doc/user/conf.py b/doc/user/conf.py index 728f9c9364..629a972726 100644 --- a/doc/user/conf.py +++ b/doc/user/conf.py @@ -52,18 +52,18 @@ master_doc = "index" # General information about the project. -project = u"FRR" -copyright = u"2017, FRR" -author = u"FRR authors" +project = "FRR" +copyright = "2017, FRR" +author = "FRR authors" # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # The short X.Y version. -version = u"?.?" +version = "?.?" # The full version, including alpha/beta/rc tags. -release = u"?.?-?" +release = "?.?-?" # ----------------------------------------------------------------------------- @@ -287,7 +287,7 @@ # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ - (master_doc, "FRR.tex", u"FRR User Manual", u"FRR", "manual"), + (master_doc, "FRR.tex", "FRR User Manual", "FRR", "manual"), ] # The name of an image file (relative to this directory) to place at the top of @@ -315,7 +315,7 @@ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). -man_pages = [(master_doc, "frr", u"FRR User Manual", [author], 1)] +man_pages = [(master_doc, "frr", "FRR User Manual", [author], 1)] # If true, show URL addresses after external links. # man_show_urls = False @@ -330,7 +330,7 @@ ( master_doc, "frr", - u"FRR User Manual", + "FRR User Manual", author, "FRR", "One line description of project.", @@ -358,6 +358,7 @@ with open("../extra/frrlexer.py", "rb") as lex: frrlexerpy = lex.read() + # Parse version string into int array def vparse(s): a = [] @@ -376,7 +377,9 @@ def vparse(s): def setup(app): # object type for FRR CLI commands, can be extended to document parent CLI # node later on - app.add_object_type("clicmd", "clicmd", indextemplate="pair: %s; configuration command") + app.add_object_type( + "clicmd", "clicmd", indextemplate="pair: %s; configuration command" + ) # I dont care how stupid this is if "add_js_file" in dir(app): @@ -389,7 +392,6 @@ def setup(app): else: app.add_stylesheet("overrides.css") - # load Pygments lexer for FRR config syntax # # NB: in Pygments 2.2+ this can be done with `load_lexer_from_file`, but we From a970bb51b5fe32335c783860a03bb02ce74a49aa Mon Sep 17 00:00:00 2001 From: zhou-run Date: Thu, 27 Jun 2024 11:51:02 +0800 Subject: [PATCH 127/347] isisd: fix crash when obtaining the next hop to calculate LFA on LAN links When a neighbor connection is disconnected, it may trigger LSP re-generation as a timer task, but this process may be delayed. As a result, the list of neighbors in area->adjacency_list may be inconsistent with the neighbors in lsp->tlvs->oldstyle_reach/extended_reach. For example, the area->adjacency_list may lack certain neighbors even though they are present in the LSP. When computing SPF, the call to isis_spf_build_adj_list() generates the spftree->sadj_list, which reflects the real neighbors in the area->adjacency_list. However, in the case of LAN links, spftree->sadj_list may include additional pseudo neighbors. The pre-loading of tents through the call to isis_spf_preload_tent involves two steps: 1. isis_spf_process_lsp() is called to generate real neighbor vertices based on the root LSP and pseudo LSP. 2. isis_spf_add_local() is called to add corresponding next hops to the vertex->Adj_N list for the real neighbor vertices. In the case of LAN links, the absence of corresponding real neighbors in the spftree->sadj_list prevents the execution of the second step. Consequently, the vertex->Adj_N list for the real neighbor vertices lacks corresponding next hops. This leads to a null pointer access when isis_lfa_compute() is called to calculate LFA. As for P2P links, since there are no pseudo neighbors, only the second step is executed, which does not create real neighbor vertices and therefore does not encounter this issue. The backtrace is as follows: (gdb) bt #0 0x00007fd065277fe1 in raise () from /lib/x86_64-linux-gnu/libpthread.so.0 #1 0x00007fd065398972 in core_handler (signo=11, siginfo=0x7ffc5c0636b0, context=0x7ffc5c063580) at ../lib/sigevent.c:261 #2 #3 0x00005564d82f8408 in isis_lfa_compute (area=0x5564d8b143f0, circuit=0x5564d8b21d10, spftree=0x5564d8b06bf0, resource=0x7ffc5c064410) at ../isisd/isis_lfa.c:2134 #4 0x00005564d82f8d78 in isis_spf_run_lfa (area=0x5564d8b143f0, spftree=0x5564d8b06bf0) at ../isisd/isis_lfa.c:2344 #5 0x00005564d8315964 in isis_run_spf_with_protection (area=0x5564d8b143f0, spftree=0x5564d8b06bf0) at ../isisd/isis_spf.c:1827 #6 0x00005564d8315c15 in isis_run_spf_cb (thread=0x7ffc5c064590) at ../isisd/isis_spf.c:1889 #7 0x00007fd0653b1f04 in thread_call (thread=0x7ffc5c064590) at ../lib/thread.c:1990 #8 0x00007fd06534a97b in frr_run (master=0x5564d88103c0) at ../lib/libfrr.c:1198 #9 0x00005564d82e7d5d in main (argc=5, argv=0x7ffc5c0647b8, envp=0x7ffc5c0647e8) at ../isisd/isis_main.c:273 (gdb) f 3 #3 0x00005564d82f8408 in isis_lfa_compute (area=0x5564d8b143f0, circuit=0x5564d8b21d10, spftree=0x5564d8b06bf0, resource=0x7ffc5c064410) at ../isisd/isis_lfa.c:2134 2134 ../isisd/isis_lfa.c: No such file or directory. (gdb) p vadj_primary $1 = (struct isis_vertex_adj *) 0x0 (gdb) p vertex->Adj_N->head $2 = (struct listnode *) 0x0 (gdb) p (struct isis_vertex *)spftree->paths->l.list->head->next->next->next->next->data $8 = (struct isis_vertex *) 0x5564d8b5b240 (gdb) p $8->type $9 = VTYPE_NONPSEUDO_TE_IS (gdb) p $8->N.id $10 = "\000\000\000\000\000\002" (gdb) p $8->Adj_N->count $11 = 0 (gdb) p (struct isis_vertex *)spftree->paths->l.list->head->next->next->next->next->next->data $12 = (struct isis_vertex *) 0x5564d8b73dd0 (gdb) p $12->type $13 = VTYPE_NONPSEUDO_TE_IS (gdb) p $12->N.id $14 = "\000\000\000\000\000\003" (gdb) p $12->Adj_N->count $15 = 0 (gdb) p area->adjacency_list->count $16 = 0 The backtrace provided above pertains to version 8.5.4, but it seems that the same issue exists in the code of the master branch as well. The scenario where a vertex has no next hop is normal. For example, the "clear isis neighbor" command invokes isis_vertex_adj_del() to delete the next hop of a vertex. Upon reviewing all the instances where the vertex->Adj_N list is used, I found that only isis_lfa_compute() lacks a null check. Therefore, I believe that modifying this part will be sufficient. Additionally, the vertex->parents list for IP vertices is guaranteed not to be empty. Test scenario: Setting up LFA for LAN links and executing the "clear isis neighbor" command easily reproduces the issue. Signed-off-by: zhou-run --- isisd/isis_lfa.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/isisd/isis_lfa.c b/isisd/isis_lfa.c index 4eb57aefb0..dc8f0b96c0 100644 --- a/isisd/isis_lfa.c +++ b/isisd/isis_lfa.c @@ -2126,9 +2126,16 @@ void isis_lfa_compute(struct isis_area *area, struct isis_circuit *circuit, } vadj_primary = listnode_head(vertex->Adj_N); + if (!vadj_primary) { + if (IS_DEBUG_LFA) + zlog_debug( + "ISIS-LFA: skipping computing LFAs due to no adjacencies"); + continue; + } sadj_primary = vadj_primary->sadj; parent_vertex = listnode_head(vertex->parents); + assert(parent_vertex); prefix_metric = vertex->d_N - parent_vertex->d_N; /* From 1a64fe4254759245a67fb279d67478922e00255e Mon Sep 17 00:00:00 2001 From: T-Nicolas Date: Mon, 17 Jun 2024 15:05:58 +0200 Subject: [PATCH 128/347] ripd: Change the start value of sequence 1 to 0 Signed-off-by: T-Nicolas --- ripd/ripd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ripd/ripd.c b/ripd/ripd.c index b8a140c9ca..ab4ffe5a92 100644 --- a/ripd/ripd.c +++ b/ripd/ripd.c @@ -1051,7 +1051,7 @@ static size_t rip_auth_md5_ah_write(struct stream *s, struct rip_interface *ri, /* RFC2080: The value used in the sequence number is arbitrary, but two suggestions are the time of the message's creation or a simple message counter. */ - stream_putl(s, ++seq); + stream_putl(s, seq++); /* Reserved field must be zero. */ stream_putl(s, 0); From 4e276b93def930f3cdf475360f57a3531a9ff2c5 Mon Sep 17 00:00:00 2001 From: vivek Date: Sat, 24 Oct 2020 14:38:58 -0700 Subject: [PATCH 129/347] bgpd: Implement BGP-wide configuration for graceful restart Add support for a BGP-wide setting for graceful restart modes and parameters. This setting will apply to all BGP peers across all BGP instances, but per-neighbor configuration can override it. Per-instance configuration is disallowed if the BGP-wide setting is in effect. Signed-off-by: Vivek Venkatraman --- bgpd/bgp_vty.c | 371 ++++++++++++++++++++++++++++++++++++++++--------- bgpd/bgpd.c | 28 +++- bgpd/bgpd.h | 12 ++ 3 files changed, 343 insertions(+), 68 deletions(-) diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 230fedf4ec..ba392e39e6 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -3019,6 +3019,98 @@ DEFUN (no_bgp_deterministic_med, return CMD_SUCCESS; } +static int bgp_inst_gr_config_vty(struct vty *vty, struct bgp *bgp, bool on, + bool disable) +{ + int ret = BGP_GR_FAILURE; + + /* + * Update the instance and all its peers, if appropriate. + * Then, inform zebra of BGP's GR capabilities, if needed. + */ + if (disable) + ret = bgp_gr_update_all(bgp, on ? GLOBAL_DISABLE_CMD + : NO_GLOBAL_DISABLE_CMD); + else + ret = bgp_gr_update_all(bgp, + on ? GLOBAL_GR_CMD : NO_GLOBAL_GR_CMD); + + VTY_BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(bgp, bgp->peer, + ret); + return ret; +} + +static int bgp_global_gr_config_vty(struct vty *vty, bool on, bool disable) +{ + struct listnode *node, *nnode; + struct bgp *bgp; + bool vrf_cfg = false; + int ret = BGP_GR_FAILURE; + + if (disable) { + if ((on && CHECK_FLAG(bm->flags, BM_FLAG_GR_DISABLED)) || + (!on && !CHECK_FLAG(bm->flags, BM_FLAG_GR_DISABLED))) + return CMD_SUCCESS; + } else { + if ((on && CHECK_FLAG(bm->flags, BM_FLAG_GR_RESTARTER)) || + (!on && !CHECK_FLAG(bm->flags, BM_FLAG_GR_RESTARTER))) + return CMD_SUCCESS; + } + + /* See if GR is set per-vrf and warn user to delete */ + if (!CHECK_FLAG(bm->flags, BM_FLAG_GR_CONFIGURED)) { + for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) { + enum global_mode gr_mode = bgp_global_gr_mode_get(bgp); + + if (gr_mode != GLOBAL_HELPER) { + vty_out(vty, + "%% graceful-restart configuration found in %s, mode %d\n", + bgp->name_pretty, gr_mode); + vrf_cfg = true; + } + } + } + + if (vrf_cfg) { + vty_out(vty, + "%%Failed: global graceful-restart not permitted with per-vrf configuration\n"); + return CMD_WARNING; + } + + /* Set flag globally */ + if (on) { + if (disable) { + UNSET_FLAG(bm->flags, BM_FLAG_GR_RESTARTER); + SET_FLAG(bm->flags, BM_FLAG_GR_DISABLED); + } else { + SET_FLAG(bm->flags, BM_FLAG_GR_RESTARTER); + UNSET_FLAG(bm->flags, BM_FLAG_GR_DISABLED); + } + } else { + if (disable) + UNSET_FLAG(bm->flags, BM_FLAG_GR_DISABLED); + else + UNSET_FLAG(bm->flags, BM_FLAG_GR_RESTARTER); + } + + /* Initiate processing for all BGP instances. */ + for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) { + ret = bgp_inst_gr_config_vty(vty, bgp, on, disable); + if (ret != BGP_GR_SUCCESS) + vty_out(vty, + "%% Applying global graceful-restart %s config to vrf %s failed, error %d\n", + (disable) ? "disable" : "", + bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT + ? "Default" + : bgp->name, + ret); + } + + vty_out(vty, + "Graceful restart configuration changed, reset all peers to take effect\n"); + return bgp_vty_return(vty, ret); +} + /* "bgp graceful-restart mode" configuration. */ DEFUN (bgp_graceful_restart, bgp_graceful_restart_cmd, @@ -3027,6 +3119,9 @@ DEFUN (bgp_graceful_restart, GR_CMD ) { + if (vty->node == CONFIG_NODE) + return bgp_global_gr_config_vty(vty, true, false); + int ret = BGP_GR_FAILURE; if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) @@ -3034,11 +3129,8 @@ DEFUN (bgp_graceful_restart, VTY_DECLVAR_CONTEXT(bgp, bgp); - ret = bgp_gr_update_all(bgp, GLOBAL_GR_CMD); + ret = bgp_inst_gr_config_vty(vty, bgp, true, false); if (ret == BGP_GR_SUCCESS) { - VTY_BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(bgp, - bgp->peer, - ret); vty_out(vty, "Graceful restart configuration changed, reset all peers to take effect\n"); } @@ -3057,6 +3149,9 @@ DEFUN (no_bgp_graceful_restart, NO_GR_CMD ) { + if (vty->node == CONFIG_NODE) + return bgp_global_gr_config_vty(vty, false, false); + VTY_DECLVAR_CONTEXT(bgp, bgp); if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) @@ -3064,7 +3159,7 @@ DEFUN (no_bgp_graceful_restart, int ret = BGP_GR_FAILURE; - ret = bgp_gr_update_all(bgp, NO_GLOBAL_GR_CMD); + ret = bgp_inst_gr_config_vty(vty, bgp, false, false); if (ret == BGP_GR_SUCCESS) { VTY_BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(bgp, bgp->peer, @@ -3087,12 +3182,21 @@ DEFUN (bgp_graceful_restart_stalepath_time, "Set the max time to hold onto restarting peer's stale paths\n" "Delay value (seconds)\n") { - VTY_DECLVAR_CONTEXT(bgp, bgp); int idx_number = 3; uint32_t stalepath; stalepath = strtoul(argv[idx_number]->arg, NULL, 10); - bgp->stalepath_time = stalepath; + if (vty->node == CONFIG_NODE) { + struct listnode *node, *nnode; + struct bgp *bgp; + + bm->stalepath_time = stalepath; + for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) + bgp->stalepath_time = stalepath; + } else { + VTY_DECLVAR_CONTEXT(bgp, bgp); + bgp->stalepath_time = stalepath; + } return CMD_SUCCESS; } @@ -3104,20 +3208,32 @@ DEFUN (bgp_graceful_restart_restart_time, "Set the time to wait to delete stale routes before a BGP open message is received\n" "Delay value (seconds)\n") { - VTY_DECLVAR_CONTEXT(bgp, bgp); int idx_number = 3; uint32_t restart; struct listnode *node, *nnode; struct peer *peer; restart = strtoul(argv[idx_number]->arg, NULL, 10); - bgp->restart_time = restart; - for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) - bgp_capability_send(peer, AFI_IP, SAFI_UNICAST, - CAPABILITY_CODE_RESTART, - CAPABILITY_ACTION_SET); + if (vty->node == CONFIG_NODE) { + struct bgp *bgp; + bm->restart_time = restart; + for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) { + bgp->restart_time = restart; + for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) + bgp_capability_send(peer, AFI_IP, SAFI_UNICAST, + CAPABILITY_CODE_RESTART, + CAPABILITY_ACTION_SET); + } + } else { + VTY_DECLVAR_CONTEXT(bgp, bgp); + bgp->restart_time = restart; + for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) + bgp_capability_send(peer, AFI_IP, SAFI_UNICAST, + CAPABILITY_CODE_RESTART, + CAPABILITY_ACTION_SET); + } return CMD_SUCCESS; } @@ -3129,16 +3245,32 @@ DEFUN (bgp_graceful_restart_select_defer_time, "Set the time to defer the BGP route selection after restart\n" "Delay value (seconds, 0 - disable)\n") { - VTY_DECLVAR_CONTEXT(bgp, bgp); int idx_number = 3; uint32_t defer_time; defer_time = strtoul(argv[idx_number]->arg, NULL, 10); - bgp->select_defer_time = defer_time; - if (defer_time == 0) - SET_FLAG(bgp->flags, BGP_FLAG_SELECT_DEFER_DISABLE); - else - UNSET_FLAG(bgp->flags, BGP_FLAG_SELECT_DEFER_DISABLE); + if (vty->node == CONFIG_NODE) { + struct listnode *node, *nnode; + struct bgp *bgp; + + bm->select_defer_time = defer_time; + for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) { + bgp->select_defer_time = defer_time; + if (defer_time == 0) + SET_FLAG(bgp->flags, + BGP_FLAG_SELECT_DEFER_DISABLE); + else + UNSET_FLAG(bgp->flags, + BGP_FLAG_SELECT_DEFER_DISABLE); + } + } else { + VTY_DECLVAR_CONTEXT(bgp, bgp); + bgp->select_defer_time = defer_time; + if (defer_time == 0) + SET_FLAG(bgp->flags, BGP_FLAG_SELECT_DEFER_DISABLE); + else + UNSET_FLAG(bgp->flags, BGP_FLAG_SELECT_DEFER_DISABLE); + } return CMD_SUCCESS; } @@ -3152,9 +3284,17 @@ DEFUN (no_bgp_graceful_restart_stalepath_time, "Set the max time to hold onto restarting peer's stale paths\n" "Delay value (seconds)\n") { - VTY_DECLVAR_CONTEXT(bgp, bgp); + if (vty->node == CONFIG_NODE) { + struct listnode *node, *nnode; + struct bgp *bgp; - bgp->stalepath_time = BGP_DEFAULT_STALEPATH_TIME; + bm->stalepath_time = BGP_DEFAULT_STALEPATH_TIME; + for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) + bgp->stalepath_time = BGP_DEFAULT_STALEPATH_TIME; + } else { + VTY_DECLVAR_CONTEXT(bgp, bgp); + bgp->stalepath_time = BGP_DEFAULT_STALEPATH_TIME; + } return CMD_SUCCESS; } @@ -3167,17 +3307,30 @@ DEFUN (no_bgp_graceful_restart_restart_time, "Set the time to wait to delete stale routes before a BGP open message is received\n" "Delay value (seconds)\n") { - VTY_DECLVAR_CONTEXT(bgp, bgp); struct listnode *node, *nnode; struct peer *peer; - bgp->restart_time = BGP_DEFAULT_RESTART_TIME; + if (vty->node == CONFIG_NODE) { + struct bgp *bgp; - for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) - bgp_capability_send(peer, AFI_IP, SAFI_UNICAST, - CAPABILITY_CODE_RESTART, - CAPABILITY_ACTION_UNSET); + bm->restart_time = BGP_DEFAULT_RESTART_TIME; + for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) { + bgp->restart_time = BGP_DEFAULT_RESTART_TIME; + for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) + bgp_capability_send(peer, AFI_IP, SAFI_UNICAST, + CAPABILITY_CODE_RESTART, + CAPABILITY_ACTION_UNSET); + } + } else { + VTY_DECLVAR_CONTEXT(bgp, bgp); + bgp->restart_time = BGP_DEFAULT_RESTART_TIME; + + for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) + bgp_capability_send(peer, AFI_IP, SAFI_UNICAST, + CAPABILITY_CODE_RESTART, + CAPABILITY_ACTION_UNSET); + } return CMD_SUCCESS; } @@ -3190,10 +3343,21 @@ DEFUN (no_bgp_graceful_restart_select_defer_time, "Set the time to defer the BGP route selection after restart\n" "Delay value (seconds)\n") { - VTY_DECLVAR_CONTEXT(bgp, bgp); + if (vty->node == CONFIG_NODE) { + struct listnode *node, *nnode; + struct bgp *bgp; - bgp->select_defer_time = BGP_DEFAULT_SELECT_DEFERRAL_TIME; - UNSET_FLAG(bgp->flags, BGP_FLAG_SELECT_DEFER_DISABLE); + bm->select_defer_time = BGP_DEFAULT_SELECT_DEFERRAL_TIME; + for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) { + bgp->select_defer_time = + BGP_DEFAULT_SELECT_DEFERRAL_TIME; + UNSET_FLAG(bgp->flags, BGP_FLAG_SELECT_DEFER_DISABLE); + } + } else { + VTY_DECLVAR_CONTEXT(bgp, bgp); + bgp->select_defer_time = BGP_DEFAULT_SELECT_DEFERRAL_TIME; + UNSET_FLAG(bgp->flags, BGP_FLAG_SELECT_DEFER_DISABLE); + } return CMD_SUCCESS; } @@ -3205,8 +3369,17 @@ DEFUN (bgp_graceful_restart_preserve_fw, "Graceful restart capability parameters\n" "Sets F-bit indication that fib is preserved while doing Graceful Restart\n") { - VTY_DECLVAR_CONTEXT(bgp, bgp); - SET_FLAG(bgp->flags, BGP_FLAG_GR_PRESERVE_FWD); + if (vty->node == CONFIG_NODE) { + struct listnode *node, *nnode; + struct bgp *bgp; + + SET_FLAG(bm->flags, BM_FLAG_GR_PRESERVE_FWD); + for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) + SET_FLAG(bgp->flags, BGP_FLAG_GR_PRESERVE_FWD); + } else { + VTY_DECLVAR_CONTEXT(bgp, bgp); + SET_FLAG(bgp->flags, BGP_FLAG_GR_PRESERVE_FWD); + } return CMD_SUCCESS; } @@ -3218,8 +3391,17 @@ DEFUN (no_bgp_graceful_restart_preserve_fw, "Graceful restart capability parameters\n" "Unsets F-bit indication that fib is preserved while doing Graceful Restart\n") { - VTY_DECLVAR_CONTEXT(bgp, bgp); - UNSET_FLAG(bgp->flags, BGP_FLAG_GR_PRESERVE_FWD); + if (vty->node == CONFIG_NODE) { + struct listnode *node, *nnode; + struct bgp *bgp; + + UNSET_FLAG(bm->flags, BM_FLAG_GR_PRESERVE_FWD); + for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) + UNSET_FLAG(bgp->flags, BGP_FLAG_GR_PRESERVE_FWD); + } else { + VTY_DECLVAR_CONTEXT(bgp, bgp); + UNSET_FLAG(bgp->flags, BGP_FLAG_GR_PRESERVE_FWD); + } return CMD_SUCCESS; } @@ -3271,6 +3453,9 @@ DEFUN (bgp_graceful_restart_disable, BGP_STR GR_DISABLE) { + if (vty->node == CONFIG_NODE) + return bgp_global_gr_config_vty(vty, true, true); + int ret = BGP_GR_FAILURE; struct listnode *node, *nnode; struct peer *peer; @@ -3281,11 +3466,8 @@ DEFUN (bgp_graceful_restart_disable, VTY_DECLVAR_CONTEXT(bgp, bgp); - ret = bgp_gr_update_all(bgp, GLOBAL_DISABLE_CMD); + ret = bgp_inst_gr_config_vty(vty, bgp, true, true); if (ret == BGP_GR_SUCCESS) { - VTY_BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(bgp, - bgp->peer, - ret); vty_out(vty, "Graceful restart configuration changed, reset all peers to take effect\n"); @@ -3313,6 +3495,9 @@ DEFUN (no_bgp_graceful_restart_disable, NO_GR_DISABLE ) { + if (vty->node == CONFIG_NODE) + return bgp_global_gr_config_vty(vty, false, true); + VTY_DECLVAR_CONTEXT(bgp, bgp); if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) @@ -3321,11 +3506,8 @@ DEFUN (no_bgp_graceful_restart_disable, int ret = BGP_GR_FAILURE; - ret = bgp_gr_update_all(bgp, NO_GLOBAL_DISABLE_CMD); + ret = bgp_inst_gr_config_vty(vty, bgp, false, true); if (ret == BGP_GR_SUCCESS) { - VTY_BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(bgp, - bgp->peer, - ret); vty_out(vty, "Graceful restart configuration changed, reset all peers to take effect\n"); } @@ -19166,6 +19348,7 @@ int bgp_config_write(struct vty *vty) hook_call(bgp_snmp_traps_config_write, vty); + vty_out(vty, "!\n"); if (bm->rmap_update_timer != RMAP_DEFAULT_UPDATE_TIMER) vty_out(vty, "bgp route-map delay-timer %u\n", bm->rmap_update_timer); @@ -19180,6 +19363,30 @@ int bgp_config_write(struct vty *vty) if (bm->wait_for_fib) vty_out(vty, "bgp suppress-fib-pending\n"); + if (bm->stalepath_time != BGP_DEFAULT_STALEPATH_TIME) + vty_out(vty, "bgp graceful-restart stalepath-time %u\n", + bm->stalepath_time); + + if (bm->restart_time != BGP_DEFAULT_RESTART_TIME) + vty_out(vty, "bgp graceful-restart restart-time %u\n", + bm->restart_time); + + if (bm->select_defer_time != BGP_DEFAULT_SELECT_DEFERRAL_TIME) + vty_out(vty, "bgp graceful-restart select-defer-time %u\n", + bm->select_defer_time); + + if (CHECK_FLAG(bm->flags, BM_FLAG_GR_RESTARTER)) + vty_out(vty, "bgp graceful-restart\n"); + else if (CHECK_FLAG(bm->flags, BM_FLAG_GR_DISABLED)) + vty_out(vty, "bgp graceful-restart-disable\n"); + + if (CHECK_FLAG(bm->flags, BM_FLAG_GR_PRESERVE_FWD)) + vty_out(vty, "bgp graceful-restart preserve-fw-state\n"); + + if (bm->rib_stale_time != BGP_DEFAULT_RIB_STALE_TIME) + vty_out(vty, "bgp graceful-restart rib-stale-time %u\n", + bm->rib_stale_time); + if (CHECK_FLAG(bm->flags, BM_FLAG_GRACEFUL_SHUTDOWN)) vty_out(vty, "bgp graceful-shutdown\n"); @@ -19442,15 +19649,21 @@ int bgp_config_write(struct vty *vty) " bgp long-lived-graceful-restart stale-time %u\n", bgp->llgr_stale_time); - /* BGP graceful-restart. */ - if (bgp->stalepath_time != BGP_DEFAULT_STALEPATH_TIME) - vty_out(vty, - " bgp graceful-restart stalepath-time %u\n", - bgp->stalepath_time); + /* BGP per-instance graceful-restart. */ + /* BGP-wide settings and per-instance settings are mutually + * exclusive. + */ + if (bm->stalepath_time == BGP_DEFAULT_STALEPATH_TIME) + if (bgp->stalepath_time != BGP_DEFAULT_STALEPATH_TIME) + vty_out(vty, + " bgp graceful-restart stalepath-time %u\n", + bgp->stalepath_time); - if (bgp->restart_time != BGP_DEFAULT_RESTART_TIME) - vty_out(vty, " bgp graceful-restart restart-time %u\n", - bgp->restart_time); + if (bm->restart_time == BGP_DEFAULT_RESTART_TIME) + if (bgp->restart_time != BGP_DEFAULT_RESTART_TIME) + vty_out(vty, + " bgp graceful-restart restart-time %u\n", + bgp->restart_time); if (!!CHECK_FLAG(bgp->flags, BGP_FLAG_GRACEFUL_NOTIFICATION) != SAVE_BGP_GRACEFUL_NOTIFICATION) @@ -19460,30 +19673,34 @@ int bgp_config_write(struct vty *vty) ? "" : "no "); - if (bgp->select_defer_time != BGP_DEFAULT_SELECT_DEFERRAL_TIME) - vty_out(vty, - " bgp graceful-restart select-defer-time %u\n", - bgp->select_defer_time); + if (bm->select_defer_time == BGP_DEFAULT_SELECT_DEFERRAL_TIME) + if (bgp->select_defer_time != + BGP_DEFAULT_SELECT_DEFERRAL_TIME) + vty_out(vty, + " bgp graceful-restart select-defer-time %u\n", + bgp->select_defer_time); - if (bgp_global_gr_mode_get(bgp) == GLOBAL_GR) - vty_out(vty, " bgp graceful-restart\n"); + if (!CHECK_FLAG(bm->flags, BM_FLAG_GR_CONFIGURED)) { + if (bgp_global_gr_mode_get(bgp) == GLOBAL_GR) + vty_out(vty, " bgp graceful-restart\n"); - if (bgp_global_gr_mode_get(bgp) == GLOBAL_DISABLE) - vty_out(vty, " bgp graceful-restart-disable\n"); + if (bgp_global_gr_mode_get(bgp) == GLOBAL_DISABLE) + vty_out(vty, " bgp graceful-restart-disable\n"); + } - /* BGP graceful-restart Preserve State F bit. */ - if (CHECK_FLAG(bgp->flags, BGP_FLAG_GR_PRESERVE_FWD)) - vty_out(vty, - " bgp graceful-restart preserve-fw-state\n"); + if (!CHECK_FLAG(bm->flags, BM_FLAG_GR_PRESERVE_FWD)) + if (CHECK_FLAG(bgp->flags, BGP_FLAG_GR_PRESERVE_FWD)) + vty_out(vty, + " bgp graceful-restart preserve-fw-state\n"); /* BGP TCP keepalive */ bgp_config_tcp_keepalive(vty, bgp); - /* Stale timer for RIB */ - if (bgp->rib_stale_time != BGP_DEFAULT_RIB_STALE_TIME) - vty_out(vty, - " bgp graceful-restart rib-stale-time %u\n", - bgp->rib_stale_time); + if (bm->rib_stale_time == BGP_DEFAULT_RIB_STALE_TIME) + if (bgp->rib_stale_time != BGP_DEFAULT_RIB_STALE_TIME) + vty_out(vty, + " bgp graceful-restart rib-stale-time %u\n", + bgp->rib_stale_time); /* BGP bestpath method. */ if (CHECK_FLAG(bgp->flags, BGP_FLAG_ASPATH_IGNORE)) @@ -20142,6 +20359,26 @@ void bgp_vty_init(void) install_element(CONFIG_NODE, &bgp_graceful_shutdown_cmd); install_element(CONFIG_NODE, &no_bgp_graceful_shutdown_cmd); + /* BGP-wide graceful-restart commands. */ + install_element(CONFIG_NODE, &bgp_graceful_restart_cmd); + install_element(CONFIG_NODE, &no_bgp_graceful_restart_cmd); + install_element(CONFIG_NODE, &bgp_graceful_restart_disable_cmd); + install_element(CONFIG_NODE, &no_bgp_graceful_restart_disable_cmd); + install_element(CONFIG_NODE, &bgp_graceful_restart_stalepath_time_cmd); + install_element(CONFIG_NODE, + &no_bgp_graceful_restart_stalepath_time_cmd); + install_element(CONFIG_NODE, &bgp_graceful_restart_restart_time_cmd); + install_element(CONFIG_NODE, &no_bgp_graceful_restart_restart_time_cmd); + install_element(CONFIG_NODE, + &bgp_graceful_restart_select_defer_time_cmd); + install_element(CONFIG_NODE, + &no_bgp_graceful_restart_select_defer_time_cmd); + install_element(CONFIG_NODE, &bgp_graceful_restart_preserve_fw_cmd); + install_element(CONFIG_NODE, &no_bgp_graceful_restart_preserve_fw_cmd); + install_element(CONFIG_NODE, &bgp_graceful_restart_rib_stale_time_cmd); + install_element(CONFIG_NODE, + &no_bgp_graceful_restart_rib_stale_time_cmd); + /* Dummy commands (Currently not supported) */ install_element(BGP_NODE, &no_synchronization_cmd); install_element(BGP_NODE, &no_auto_summary_cmd); diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index e42b7f5ca5..c9abeb35da 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -1391,9 +1391,31 @@ int bgp_global_gr_init(struct bgp *bgp) memcpy(bgp->GLOBAL_GR_FSM, local_GLOBAL_GR_FSM, sizeof(local_GLOBAL_GR_FSM)); - bgp->global_gr_present_state = GLOBAL_HELPER; + /* Inherit any BGP-wide configuration. */ + if (CHECK_FLAG(bm->flags, BM_FLAG_GR_RESTARTER)) + bgp->global_gr_present_state = GLOBAL_GR; + else if (CHECK_FLAG(bm->flags, BM_FLAG_GR_DISABLED)) + bgp->global_gr_present_state = GLOBAL_DISABLE; + else + bgp->global_gr_present_state = GLOBAL_HELPER; + + if (bm->restart_time != BGP_DEFAULT_RESTART_TIME) + bgp->restart_time = bm->restart_time; + if (bm->stalepath_time != BGP_DEFAULT_STALEPATH_TIME) + bgp->stalepath_time = bm->stalepath_time; + if (bm->select_defer_time != BGP_DEFAULT_SELECT_DEFERRAL_TIME) + bgp->select_defer_time = bm->select_defer_time; + if (bm->rib_stale_time != BGP_DEFAULT_RIB_STALE_TIME) + bgp->rib_stale_time = bm->rib_stale_time; + if (CHECK_FLAG(bm->flags, BM_FLAG_GR_PRESERVE_FWD)) + SET_FLAG(bgp->flags, BGP_FLAG_GR_PRESERVE_FWD); + bgp->present_zebra_gr_state = ZEBRA_GR_DISABLE; + if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) + zlog_debug("%s: Global GR state is %s", bgp->name_pretty, + print_global_gr_mode(bgp->global_gr_present_state)); + return BGP_GR_SUCCESS; } @@ -8405,6 +8427,10 @@ void bgp_master_init(struct event_loop *master, const int buffer_size, bm->t_bgp_sync_label_manager = NULL; bm->t_bgp_start_label_manager = NULL; bm->t_bgp_zebra_route = NULL; + bm->restart_time = BGP_DEFAULT_RESTART_TIME; + bm->stalepath_time = BGP_DEFAULT_STALEPATH_TIME; + bm->select_defer_time = BGP_DEFAULT_SELECT_DEFERRAL_TIME; + bm->rib_stale_time = BGP_DEFAULT_RIB_STALE_TIME; bgp_mac_init(); /* init the rd id space. diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 1f8cc53349..77955fd5c9 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -163,6 +163,18 @@ struct bgp_master { uint32_t flags; #define BM_FLAG_GRACEFUL_SHUTDOWN (1 << 0) #define BM_FLAG_SEND_EXTRA_DATA_TO_ZEBRA (1 << 1) +#define BM_FLAG_MAINTENANCE_MODE (1 << 2) +#define BM_FLAG_GR_RESTARTER (1 << 3) +#define BM_FLAG_GR_DISABLED (1 << 4) +#define BM_FLAG_GR_PRESERVE_FWD (1 << 5) + +#define BM_FLAG_GR_CONFIGURED (BM_FLAG_GR_RESTARTER | BM_FLAG_GR_DISABLED) + + /* BGP-wide graceful restart config params */ + uint32_t restart_time; + uint32_t stalepath_time; + uint32_t select_defer_time; + uint32_t rib_stale_time; bool terminating; /* global flag that sigint terminate seen */ From f0210cbacccf4497a79ed6f45fa61831ec5c24f9 Mon Sep 17 00:00:00 2001 From: Pooja Jagadeesh Doijode Date: Wed, 29 May 2024 14:14:20 -0700 Subject: [PATCH 130/347] bgpd: Added ! after BGP global config Signed-off-by: Pooja Jagadeesh Doijode --- bgpd/bgp_vty.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index ba392e39e6..3dec4dd265 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -19408,6 +19408,8 @@ int bgp_config_write(struct vty *vty) if (bm->outq_limit != BM_DEFAULT_Q_LIMIT) vty_out(vty, "bgp output-queue-limit %u\n", bm->outq_limit); + vty_out(vty, "!\n"); + /* BGP configuration. */ for (ALL_LIST_ELEMENTS(bm->bgp, mnode, mnnode, bgp)) { From 15403f521a12b668e87ef8961c78e0ed97c6ff92 Mon Sep 17 00:00:00 2001 From: vivek Date: Sun, 25 Oct 2020 11:31:42 -0700 Subject: [PATCH 131/347] bgpd: Streamline GR config, act on change immediately Streamline the BGP graceful-restart configuration at the global and peer level some more. Similar to many other neighbor capability parameters like MP and ENHE, reset the session immediately upon a change to the configuration. This will be more aligned with the transactional UI model also and will not require a separate 'clear' command to be executed. Note: Peer-group graceful-restart configuration is not yet supported. Signed-off-by: Vivek Venkatraman --- bgpd/bgp_fsm.c | 379 +++++++++++++++++-------------------------------- bgpd/bgp_fsm.h | 5 +- bgpd/bgp_vty.c | 124 ++++------------ bgpd/bgp_vty.h | 47 +++--- bgpd/bgpd.c | 4 +- 5 files changed, 187 insertions(+), 372 deletions(-) diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index d41ef8abba..8e1462f24b 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -2695,53 +2695,56 @@ int bgp_event_update(struct peer_connection *connection, } /* BGP GR Code */ -int bgp_gr_lookup_n_update_all_peer(struct bgp *bgp, - enum global_mode global_new_state, - enum global_mode global_old_state) +static inline void +bgp_peer_inherit_global_gr_mode(struct peer *peer, + enum global_mode global_gr_mode) +{ + switch (global_gr_mode) { + case GLOBAL_HELPER: + BGP_PEER_GR_HELPER_ENABLE(peer); + case GLOBAL_GR: + BGP_PEER_GR_ENABLE(peer); + case GLOBAL_DISABLE: + BGP_PEER_GR_DISABLE(peer); + default: + zlog_err("Unexpected Global GR mode %d", global_gr_mode); + } +} + +static void bgp_gr_update_mode_of_all_peers(struct bgp *bgp, + enum global_mode global_new_state) { struct peer *peer = {0}; struct listnode *node = {0}; struct listnode *nnode = {0}; enum peer_mode peer_old_state = PEER_INVALID; - for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { - - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("%s [BGP_GR] Peer: (%s) :", __func__, - peer->host); + /* TODO: Need to handle peer-groups. */ + for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { peer_old_state = bgp_peer_gr_mode_get(peer); + if (peer_old_state != PEER_GLOBAL_INHERIT) + continue; - if (peer_old_state == PEER_GLOBAL_INHERIT) { + bgp_peer_inherit_global_gr_mode(peer, global_new_state); + bgp_peer_gr_flags_update(peer); - /* - *Reset only these peers and send a - *new open message with the change capabilities. - *Considering the mode to be "global_new_state" and - *do all operation accordingly - */ + if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) + zlog_debug("%pBP: Inherited Global GR mode, GR flags 0x%x peer flags 0x%" PRIx64 + "...resetting session", + peer, peer->peer_gr_new_status_flag, + peer->flags); - switch (global_new_state) { - case GLOBAL_HELPER: - BGP_PEER_GR_HELPER_ENABLE(peer); - break; - case GLOBAL_GR: - BGP_PEER_GR_ENABLE(peer); - break; - case GLOBAL_DISABLE: - BGP_PEER_GR_DISABLE(peer); - break; - case GLOBAL_INVALID: - zlog_debug("%s [BGP_GR] GLOBAL_INVALID", - __func__); - return BGP_ERR_GR_OPERATION_FAILED; - } - } + /* Reset session to match with behavior for other peer + * configs that require the session to be re-setup. + */ + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) { + peer->last_reset = PEER_DOWN_CAPABILITY_CHANGE; + bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, + BGP_NOTIFY_CEASE_CONFIG_CHANGE); + } else + bgp_session_reset(peer); } - - bgp->global_gr_present_state = global_new_state; - - return BGP_GR_SUCCESS; } int bgp_gr_update_all(struct bgp *bgp, enum global_gr_command global_gr_cmd) @@ -2749,46 +2752,27 @@ int bgp_gr_update_all(struct bgp *bgp, enum global_gr_command global_gr_cmd) enum global_mode global_new_state = GLOBAL_INVALID; enum global_mode global_old_state = GLOBAL_INVALID; - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("%s [BGP_GR]START: global_gr_cmd :%s:", __func__, - print_global_gr_cmd(global_gr_cmd)); - global_old_state = bgp_global_gr_mode_get(bgp); + global_new_state = bgp->GLOBAL_GR_FSM[global_old_state][global_gr_cmd]; if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("[BGP_GR] global_old_gr_state :%s:", - print_global_gr_mode(global_old_state)); + zlog_debug("%s: Handle GR command %s, current GR state %s, new GR state %s", + bgp->name_pretty, print_global_gr_cmd(global_gr_cmd), + print_global_gr_mode(global_old_state), + print_global_gr_mode(global_new_state)); - if (global_old_state != GLOBAL_INVALID) { - global_new_state = - bgp->GLOBAL_GR_FSM[global_old_state][global_gr_cmd]; - - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("[BGP_GR] global_new_gr_state :%s:", - print_global_gr_mode(global_new_state)); - } else { - zlog_err("%s [BGP_GR] global_old_state == GLOBAL_INVALID", - __func__); + if (global_old_state == GLOBAL_INVALID) return BGP_ERR_GR_OPERATION_FAILED; - } - - if (global_new_state == GLOBAL_INVALID) { - zlog_err("%s [BGP_GR] global_new_state == GLOBAL_INVALID", - __func__); + if (global_new_state == GLOBAL_INVALID) return BGP_ERR_GR_INVALID_CMD; - } - if (global_new_state == global_old_state) { - /* Trace msg */ - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "%s [BGP_GR] global_new_state == global_old_state :%s", - __func__, - print_global_gr_mode(global_new_state)); + if (global_new_state == global_old_state) return BGP_GR_NO_OPERATION; - } - return bgp_gr_lookup_n_update_all_peer(bgp, global_new_state, - global_old_state); + /* Update global GR mode and process all peers in instance. */ + bgp->global_gr_present_state = global_new_state; + bgp_gr_update_mode_of_all_peers(bgp, global_new_state); + + return BGP_GR_SUCCESS; } const char *print_peer_gr_mode(enum peer_mode pr_mode) @@ -2903,179 +2887,101 @@ int bgp_neighbor_graceful_restart(struct peer *peer, { enum peer_mode peer_new_state = PEER_INVALID; enum peer_mode peer_old_state = PEER_INVALID; - struct bgp_peer_gr peer_state; + struct bgp_peer_gr gr_fsm; int result = BGP_GR_FAILURE; - /* - * fetch peer_old_state from peer structure also - * fetch global_old_state from bgp structure, - * peer had a back pointer to bgpo struct ; - */ - - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("%s [BGP_GR] START:Peer: (%s) : peer_gr_cmd :%s:", - __func__, peer->host, - print_peer_gr_cmd(peer_gr_cmd)); - peer_old_state = bgp_peer_gr_mode_get(peer); + gr_fsm = peer->PEER_GR_FSM[peer_old_state][peer_gr_cmd]; + peer_new_state = gr_fsm.next_state; if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("%s [BGP_GR] peer_old_state: %d", __func__, - peer_old_state); + zlog_debug("%pBP: Handle GR command %s, current GR state %s, new GR state %s", + peer, print_peer_gr_cmd(peer_gr_cmd), + print_peer_gr_mode(peer_old_state), + print_peer_gr_mode(peer_new_state)); if (peer_old_state == PEER_INVALID) return BGP_ERR_GR_OPERATION_FAILED; - peer_state = peer->PEER_GR_FSM[peer_old_state][peer_gr_cmd]; - peer_new_state = peer_state.next_state; - - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("%s [BGP_GR] peer_new_state: %d", __func__, - peer_new_state); - if (peer_new_state == PEER_INVALID) return BGP_ERR_GR_INVALID_CMD; - if (peer_new_state != peer_old_state) { - result = peer_state.action_fun(peer, peer_old_state, - peer_new_state); - } else { - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] peer_old_state == peer_new_state !"); + if (peer_new_state == peer_old_state) return BGP_GR_NO_OPERATION; - } - if (result == BGP_GR_SUCCESS) { - - /* Update the mode i.e peer_new_state into the peer structure */ - peer->peer_gr_present_state = peer_new_state; - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] Successfully change the state of the peer to : %s : !", - print_peer_gr_mode(peer_new_state)); - - return BGP_GR_SUCCESS; - } + result = gr_fsm.action_fun(peer, peer_old_state, peer_new_state); return result; } -unsigned int bgp_peer_gr_action(struct peer *peer, enum peer_mode old_peer_state, - enum peer_mode new_peer_state) +static inline bool gr_mode_matches(enum peer_mode peer_gr_mode, + enum global_mode global_gr_mode) { - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "%s [BGP_GR] Move peer from old_peer_state :%s: to new_peer_state :%s: !!!!", - __func__, print_peer_gr_mode(old_peer_state), - print_peer_gr_mode(new_peer_state)); + if ((peer_gr_mode == PEER_HELPER && global_gr_mode == GLOBAL_HELPER) || + (peer_gr_mode == PEER_GR && global_gr_mode == GLOBAL_GR) || + (peer_gr_mode == PEER_DISABLE && global_gr_mode == GLOBAL_DISABLE)) + return true; + return false; +} - enum global_mode bgp_gr_global_mode = GLOBAL_INVALID; - unsigned int ret = BGP_GR_FAILURE; +unsigned int bgp_peer_gr_action(struct peer *peer, enum peer_mode old_state, + enum peer_mode new_state) +{ + enum global_mode global_gr_mode = bgp_global_gr_mode_get(peer->bgp); + bool session_reset = true; - if (old_peer_state == new_peer_state) { - /* Nothing to do over here as the present and old state is the - * same */ + if (old_state == new_state) return BGP_GR_NO_OPERATION; - } - if ((old_peer_state == PEER_INVALID) - || (new_peer_state == PEER_INVALID)) { - /* something bad happend , print error message */ + if ((old_state == PEER_INVALID) || (new_state == PEER_INVALID)) return BGP_ERR_GR_INVALID_CMD; - } - - bgp_gr_global_mode = bgp_global_gr_mode_get(peer->bgp); - - if ((old_peer_state == PEER_GLOBAL_INHERIT) - && (new_peer_state != PEER_GLOBAL_INHERIT)) { - /* fetch the Mode running in the Global state machine - *from the bgp structure into a variable called - *bgp_gr_global_mode - */ - - /* Here we are checking if the - *1. peer_new_state == global_mode == helper_mode - *2. peer_new_state == global_mode == GR_mode - *3. peer_new_state == global_mode == disabled_mode - */ + global_gr_mode = bgp_global_gr_mode_get(peer->bgp); + if ((old_state == PEER_GLOBAL_INHERIT) && + (new_state != PEER_GLOBAL_INHERIT)) { BGP_PEER_GR_GLOBAL_INHERIT_UNSET(peer); - if ((int)new_peer_state == (int)bgp_gr_global_mode) { - /* This is incremental updates i.e no tear down - * of the existing session - * as the peer is already working in the same mode. + if (gr_mode_matches(new_state, global_gr_mode)) + /* Peer was inheriting the global state and + * its new state still is the same, so a + * session reset is not needed. */ - ret = BGP_GR_SUCCESS; - } else { - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] Peer state changed from :%s ", - print_peer_gr_mode(old_peer_state)); - - bgp_peer_move_to_gr_mode(peer, new_peer_state); - - ret = BGP_GR_SUCCESS; - } - } - /* In the case below peer is going into Global inherit mode i.e. - * the peer would work as the mode configured at the global level - */ - else if ((new_peer_state == PEER_GLOBAL_INHERIT) - && (old_peer_state != PEER_GLOBAL_INHERIT)) { - /* Here in this case it would be destructive - * in all the cases except one case when, - * Global GR is configured Disabled - * and present_peer_state is not disable - */ - + session_reset = false; + } else if ((new_state == PEER_GLOBAL_INHERIT) && + (old_state != PEER_GLOBAL_INHERIT)) { BGP_PEER_GR_GLOBAL_INHERIT_SET(peer); - if ((int)old_peer_state == (int)bgp_gr_global_mode) { - /* This is incremental updates - *i.e no tear down of the existing session - *as the peer is already working in the same mode. - */ - ret = BGP_GR_SUCCESS; - } else { - /* Destructive always */ - /* Tear down the old session - * and send the new capability - * as per the bgp_gr_global_mode + if (gr_mode_matches(old_state, global_gr_mode)) + /* Peer is inheriting the global state and + * its old state was also the same, so a + * session reset is not needed. */ + session_reset = false; + } - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] Peer state changed from :%s", - print_peer_gr_mode(old_peer_state)); - - bgp_peer_move_to_gr_mode(peer, bgp_gr_global_mode); + /* Ensure we move to the new state and update flags */ + bgp_peer_move_to_gr_mode(peer, new_state); - ret = BGP_GR_SUCCESS; - } - } else { - /* - *This else case, it include all the cases except --> - *(new_peer_state != Peer_Global) && - *( old_peer_state != Peer_Global ) + if (session_reset) { + /* Reset session to match with behavior for other peer + * configs that require the session to be re-setup. */ - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("[BGP_GR] Peer state changed from :%s", - print_peer_gr_mode(old_peer_state)); - - bgp_peer_move_to_gr_mode(peer, new_peer_state); - - ret = BGP_GR_SUCCESS; + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) { + peer->last_reset = PEER_DOWN_CAPABILITY_CHANGE; + bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, + BGP_NOTIFY_CEASE_CONFIG_CHANGE); + } else + bgp_session_reset(peer); } - return ret; + return BGP_GR_SUCCESS; } -inline void bgp_peer_move_to_gr_mode(struct peer *peer, int new_state) +void bgp_peer_move_to_gr_mode(struct peer *peer, enum peer_mode new_state) { - int bgp_global_gr_mode = bgp_global_gr_mode_get(peer->bgp); + enum global_mode global_gr_mode = bgp_global_gr_mode_get(peer->bgp); + enum peer_mode old_state = bgp_peer_gr_mode_get(peer); switch (new_state) { case PEER_HELPER: @@ -3089,57 +2995,38 @@ inline void bgp_peer_move_to_gr_mode(struct peer *peer, int new_state) break; case PEER_GLOBAL_INHERIT: BGP_PEER_GR_GLOBAL_INHERIT_SET(peer); - - if (bgp_global_gr_mode == GLOBAL_HELPER) { - BGP_PEER_GR_HELPER_ENABLE(peer); - } else if (bgp_global_gr_mode == GLOBAL_GR) { - BGP_PEER_GR_ENABLE(peer); - } else if (bgp_global_gr_mode == GLOBAL_DISABLE) { - BGP_PEER_GR_DISABLE(peer); - } else { - zlog_err( - "[BGP_GR] Default switch inherit mode ::: SOMETHING IS WRONG !!!"); - } + bgp_peer_inherit_global_gr_mode(peer, global_gr_mode); break; + case PEER_INVALID: default: zlog_err( "[BGP_GR] Default switch mode ::: SOMETHING IS WRONG !!!"); break; } + bgp_peer_gr_flags_update(peer); + peer->peer_gr_present_state = new_state; + if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("[BGP_GR] Peer state changed --to--> : %d : !", - new_state); + zlog_debug("%pBP: Peer GR mode changed from %s to %s, GR flags 0x%x peer flags 0x%" PRIx64, + peer, print_peer_gr_mode(old_state), + print_peer_gr_mode(new_state), + peer->peer_gr_new_status_flag, peer->flags); } void bgp_peer_gr_flags_update(struct peer *peer) { - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("%s [BGP_GR] called !", __func__); if (CHECK_FLAG(peer->peer_gr_new_status_flag, PEER_GRACEFUL_RESTART_NEW_STATE_HELPER)) SET_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART_HELPER); else UNSET_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART_HELPER); - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] Peer %s Flag PEER_FLAG_GRACEFUL_RESTART_HELPER : %s : !", - peer->host, - (CHECK_FLAG(peer->flags, - PEER_FLAG_GRACEFUL_RESTART_HELPER) - ? "Set" - : "UnSet")); + if (CHECK_FLAG(peer->peer_gr_new_status_flag, PEER_GRACEFUL_RESTART_NEW_STATE_RESTART)) SET_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART); else UNSET_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART); - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] Peer %s Flag PEER_FLAG_GRACEFUL_RESTART : %s : !", - peer->host, - (CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART) - ? "Set" - : "UnSet")); + if (CHECK_FLAG(peer->peer_gr_new_status_flag, PEER_GRACEFUL_RESTART_NEW_STATE_INHERIT)) SET_FLAG(peer->flags, @@ -3147,28 +3034,28 @@ void bgp_peer_gr_flags_update(struct peer *peer) else UNSET_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART_GLOBAL_INHERIT); + if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] Peer %s Flag PEER_FLAG_GRACEFUL_RESTART_GLOBAL_INHERIT : %s : !", - peer->host, - (CHECK_FLAG(peer->flags, - PEER_FLAG_GRACEFUL_RESTART_GLOBAL_INHERIT) - ? "Set" - : "UnSet")); - - if (!CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART) - && !CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART_HELPER)) { - zlog_debug("[BGP_GR] Peer %s UNSET PEER_STATUS_NSF_MODE!", - peer->host); + zlog_debug("%pBP: Peer flags updated to 0x%" PRIx64 + ", GR flags 0x%x, GR mode %s", + peer, peer->flags, peer->peer_gr_new_status_flag, + print_peer_gr_mode(bgp_peer_gr_mode_get(peer))); + /* + * If GR has been completely disabled for the peer and we were + * acting as the Helper for the peer (i.e., keeping stale routes + * and running the restart timer or stalepath timer), clear those + * states. + */ + if (!CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART) && + !CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART_HELPER)) { UNSET_FLAG(peer->sflags, PEER_STATUS_NSF_MODE); if (CHECK_FLAG(peer->sflags, PEER_STATUS_NSF_WAIT)) { - + if (bgp_debug_neighbor_events(peer)) + zlog_debug("%pBP: GR disabled, stopping NSF and clearing stale routes", + peer); peer_nsf_stop(peer); - zlog_debug( - "[BGP_GR] Peer %s UNSET PEER_STATUS_NSF_WAIT!", - peer->host); } } } diff --git a/bgpd/bgp_fsm.h b/bgpd/bgp_fsm.h index bcdd49193f..85c488962f 100644 --- a/bgpd/bgp_fsm.h +++ b/bgpd/bgp_fsm.h @@ -151,7 +151,7 @@ int bgp_neighbor_graceful_restart(struct peer *peer, enum peer_gr_command peer_gr_cmd); unsigned int bgp_peer_gr_action(struct peer *peer, enum peer_mode old_peer_state, enum peer_mode new_peer_state); -void bgp_peer_move_to_gr_mode(struct peer *peer, int new_state); +void bgp_peer_move_to_gr_mode(struct peer *peer, enum peer_mode new_state); unsigned int bgp_peer_gr_helper_enable(struct peer *peer); unsigned int bgp_peer_gr_enable(struct peer *peer); unsigned int bgp_peer_gr_global_inherit(struct peer *peer); @@ -160,9 +160,6 @@ enum peer_mode bgp_peer_gr_mode_get(struct peer *peer); enum global_mode bgp_global_gr_mode_get(struct bgp *bgp); enum peer_mode bgp_get_peer_gr_mode_from_flags(struct peer *peer); unsigned int bgp_peer_gr_global_inherit_unset(struct peer *peer); -int bgp_gr_lookup_n_update_all_peer(struct bgp *bgp, - enum global_mode global_new_state, - enum global_mode global_old_state); void bgp_peer_gr_flags_update(struct peer *peer); const char *print_peer_gr_mode(enum peer_mode pr_mode); const char *print_peer_gr_cmd(enum peer_gr_command pr_gr_cmd); diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 3dec4dd265..f5aa2e03bf 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -3123,10 +3123,6 @@ DEFUN (bgp_graceful_restart, return bgp_global_gr_config_vty(vty, true, false); int ret = BGP_GR_FAILURE; - - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("[BGP_GR] bgp_graceful_restart_cmd : START "); - VTY_DECLVAR_CONTEXT(bgp, bgp); ret = bgp_inst_gr_config_vty(vty, bgp, true, false); @@ -3135,9 +3131,6 @@ DEFUN (bgp_graceful_restart, "Graceful restart configuration changed, reset all peers to take effect\n"); } - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("[BGP_GR] bgp_graceful_restart_cmd : END "); - return bgp_vty_return(vty, ret); } @@ -3153,10 +3146,6 @@ DEFUN (no_bgp_graceful_restart, return bgp_global_gr_config_vty(vty, false, false); VTY_DECLVAR_CONTEXT(bgp, bgp); - - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("[BGP_GR] no_bgp_graceful_restart_cmd : START "); - int ret = BGP_GR_FAILURE; ret = bgp_inst_gr_config_vty(vty, bgp, false, false); @@ -3168,9 +3157,6 @@ DEFUN (no_bgp_graceful_restart, "Graceful restart configuration changed, reset all peers to take effect\n"); } - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("[BGP_GR] no_bgp_graceful_restart_cmd : END "); - return bgp_vty_return(vty, ret); } @@ -3460,10 +3446,6 @@ DEFUN (bgp_graceful_restart_disable, struct listnode *node, *nnode; struct peer *peer; - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] bgp_graceful_restart_disable_cmd : START "); - VTY_DECLVAR_CONTEXT(bgp, bgp); ret = bgp_inst_gr_config_vty(vty, bgp, true, true); @@ -3481,9 +3463,6 @@ DEFUN (bgp_graceful_restart_disable, } } - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("[BGP_GR] bgp_graceful_restart_disable_cmd : END "); - return bgp_vty_return(vty, ret); } @@ -3499,11 +3478,6 @@ DEFUN (no_bgp_graceful_restart_disable, return bgp_global_gr_config_vty(vty, false, true); VTY_DECLVAR_CONTEXT(bgp, bgp); - - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] no_bgp_graceful_restart_disable_cmd : START "); - int ret = BGP_GR_FAILURE; ret = bgp_inst_gr_config_vty(vty, bgp, false, true); @@ -3512,10 +3486,6 @@ DEFUN (no_bgp_graceful_restart_disable, "Graceful restart configuration changed, reset all peers to take effect\n"); } - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] no_bgp_graceful_restart_disable_cmd : END "); - return bgp_vty_return(vty, ret); } @@ -3533,13 +3503,14 @@ DEFUN (bgp_neighbor_graceful_restart_set, VTY_BGP_GR_DEFINE_LOOP_VARIABLE; - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] bgp_neighbor_graceful_restart_set_cmd : START "); - peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg); if (!peer) return CMD_WARNING_CONFIG_FAILED; + if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { + vty_out(vty, + "Per peer-group graceful-restart configuration is not yet supported\n"); + return CMD_WARNING_CONFIG_FAILED; + } result = bgp_neighbor_graceful_restart(peer, PEER_GR_CMD); if (result == BGP_GR_SUCCESS) { @@ -3549,15 +3520,7 @@ DEFUN (bgp_neighbor_graceful_restart_set, "Graceful restart configuration changed, reset this peer to take effect\n"); } - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] bgp_neighbor_graceful_restart_set_cmd : END "); - - if (ret != BGP_GR_SUCCESS) - vty_out(vty, - "As part of configuring graceful-restart, capability send to zebra failed\n"); - - return bgp_vty_return(vty, result); + return bgp_vty_return(vty, ret); } DEFUN (no_bgp_neighbor_graceful_restart, @@ -3578,10 +3541,11 @@ DEFUN (no_bgp_neighbor_graceful_restart, peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg); if (!peer) return CMD_WARNING_CONFIG_FAILED; - - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] no_bgp_neighbor_graceful_restart_set_cmd : START "); + if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { + vty_out(vty, + "Per peer-group graceful-restart configuration is not yet supported\n"); + return CMD_WARNING_CONFIG_FAILED; + } result = bgp_neighbor_graceful_restart(peer, NO_PEER_GR_CMD); if (ret == BGP_GR_SUCCESS) { @@ -3591,14 +3555,6 @@ DEFUN (no_bgp_neighbor_graceful_restart, "Graceful restart configuration changed, reset this peer to take effect\n"); } - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] no_bgp_neighbor_graceful_restart_set_cmd : END "); - - if (ret != BGP_GR_SUCCESS) - vty_out(vty, - "As part of configuring graceful-restart, capability send to zebra failed\n"); - return bgp_vty_return(vty, result); } @@ -3616,15 +3572,14 @@ DEFUN (bgp_neighbor_graceful_restart_helper_set, VTY_BGP_GR_DEFINE_LOOP_VARIABLE; - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] bgp_neighbor_graceful_restart_helper_set_cmd : START "); - peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg); - if (!peer) return CMD_WARNING_CONFIG_FAILED; - + if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { + vty_out(vty, + "Per peer-group graceful-restart configuration is not yet supported\n"); + return CMD_WARNING_CONFIG_FAILED; + } ret = bgp_neighbor_graceful_restart(peer, PEER_HELPER_CMD); if (ret == BGP_GR_SUCCESS) { @@ -3634,10 +3589,6 @@ DEFUN (bgp_neighbor_graceful_restart_helper_set, "Graceful restart configuration changed, reset this peer to take effect\n"); } - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] bgp_neighbor_graceful_restart_helper_set_cmd : END "); - return bgp_vty_return(vty, ret); } @@ -3659,10 +3610,11 @@ DEFUN (no_bgp_neighbor_graceful_restart_helper, peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg); if (!peer) return CMD_WARNING_CONFIG_FAILED; - - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] no_bgp_neighbor_graceful_restart_helper_set_cmd : START "); + if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { + vty_out(vty, + "Per peer-group graceful-restart configuration is not yet supported\n"); + return CMD_WARNING_CONFIG_FAILED; + } ret = bgp_neighbor_graceful_restart(peer, NO_PEER_HELPER_CMD); if (ret == BGP_GR_SUCCESS) { @@ -3672,10 +3624,6 @@ DEFUN (no_bgp_neighbor_graceful_restart_helper, "Graceful restart configuration changed, reset this peer to take effect\n"); } - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] no_bgp_neighbor_graceful_restart_helper_set_cmd : END "); - return bgp_vty_return(vty, ret); } @@ -3693,13 +3641,14 @@ DEFUN (bgp_neighbor_graceful_restart_disable_set, VTY_BGP_GR_DEFINE_LOOP_VARIABLE; - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] bgp_neighbor_graceful_restart_disable_set_cmd : START "); - peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg); if (!peer) return CMD_WARNING_CONFIG_FAILED; + if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { + vty_out(vty, + "Per peer-group graceful-restart configuration is not yet supported\n"); + return CMD_WARNING_CONFIG_FAILED; + } ret = bgp_neighbor_graceful_restart(peer, PEER_DISABLE_CMD); if (ret == BGP_GR_SUCCESS) { @@ -3708,14 +3657,8 @@ DEFUN (bgp_neighbor_graceful_restart_disable_set, VTY_BGP_GR_ROUTER_DETECT(bgp, peer, peer->bgp->peer); VTY_SEND_BGP_GR_CAPABILITY_TO_ZEBRA(peer->bgp, ret); - vty_out(vty, - "Graceful restart configuration changed, reset this peer to take effect\n"); } - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR]bgp_neighbor_graceful_restart_disable_set_cmd : END "); - return bgp_vty_return(vty, ret); } @@ -3737,23 +3680,18 @@ DEFUN (no_bgp_neighbor_graceful_restart_disable, peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg); if (!peer) return CMD_WARNING_CONFIG_FAILED; - - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] no_bgp_neighbor_graceful_restart_disable_set_cmd : START "); + if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { + vty_out(vty, + "Per peer-group graceful-restart configuration is not yet supported\n"); + return CMD_WARNING_CONFIG_FAILED; + } ret = bgp_neighbor_graceful_restart(peer, NO_PEER_DISABLE_CMD); if (ret == BGP_GR_SUCCESS) { VTY_BGP_GR_ROUTER_DETECT(bgp, peer, peer->bgp->peer); VTY_SEND_BGP_GR_CAPABILITY_TO_ZEBRA(peer->bgp, ret); - vty_out(vty, - "Graceful restart configuration changed, reset this peer to take effect\n"); } - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] no_bgp_neighbor_graceful_restart_disable_set_cmd : END "); - return bgp_vty_return(vty, ret); } diff --git a/bgpd/bgp_vty.h b/bgpd/bgp_vty.h index addd71757d..6d86f6ba08 100644 --- a/bgpd/bgp_vty.h +++ b/bgpd/bgp_vty.h @@ -60,8 +60,6 @@ struct bgp; #define VTY_BGP_GR_ROUTER_DETECT(_bgp, _peer, _peer_list) \ do { \ - if (_peer->bgp->t_startup) \ - bgp_peer_gr_flags_update(_peer); \ for (ALL_LIST_ELEMENTS(_peer_list, node, nnode, peer_loop)) { \ if (CHECK_FLAG(peer_loop->flags, \ PEER_FLAG_GRACEFUL_RESTART)) \ @@ -84,30 +82,27 @@ struct bgp; } \ } while (0) -#define VTY_BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA( \ - _bgp, _peer_list, _ret) \ - do { \ - struct peer *peer_loop; \ - bool gr_router_detected = false; \ - struct listnode *node = {0}; \ - struct listnode *nnode = {0}; \ - for (ALL_LIST_ELEMENTS(_peer_list, node, nnode, peer_loop)) { \ - if (peer_loop->bgp->t_startup) \ - bgp_peer_gr_flags_update(peer_loop); \ - if (CHECK_FLAG(peer_loop->flags, \ - PEER_FLAG_GRACEFUL_RESTART)) \ - gr_router_detected = true; \ - } \ - if (gr_router_detected \ - && _bgp->present_zebra_gr_state == ZEBRA_GR_DISABLE) { \ - if (bgp_zebra_send_capabilities(_bgp, false)) \ - _ret = BGP_ERR_INVALID_VALUE; \ - } else if (!gr_router_detected \ - && _bgp->present_zebra_gr_state \ - == ZEBRA_GR_ENABLE) { \ - if (bgp_zebra_send_capabilities(_bgp, true)) \ - _ret = BGP_ERR_INVALID_VALUE; \ - } \ +#define VTY_BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(_bgp, \ + _peer_list, _ret) \ + do { \ + struct peer *peer_loop; \ + bool gr_router_detected = false; \ + struct listnode *node = { 0 }; \ + struct listnode *nnode = { 0 }; \ + for (ALL_LIST_ELEMENTS(_peer_list, node, nnode, peer_loop)) { \ + if (CHECK_FLAG(peer_loop->flags, \ + PEER_FLAG_GRACEFUL_RESTART)) \ + gr_router_detected = true; \ + } \ + if (gr_router_detected && \ + _bgp->present_zebra_gr_state == ZEBRA_GR_DISABLE) { \ + if (bgp_zebra_send_capabilities(_bgp, false)) \ + _ret = BGP_ERR_INVALID_VALUE; \ + } else if (!gr_router_detected && \ + _bgp->present_zebra_gr_state == ZEBRA_GR_ENABLE) { \ + if (bgp_zebra_send_capabilities(_bgp, true)) \ + _ret = BGP_ERR_INVALID_VALUE; \ + } \ } while (0) diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index c9abeb35da..17d94bd575 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -1475,9 +1475,7 @@ int bgp_peer_gr_init(struct peer *peer) { PEER_HELPER, bgp_peer_gr_action }, { PEER_GLOBAL_INHERIT, NULL } } }; - memcpy(&peer->PEER_GR_FSM, local_Peer_GR_FSM, - sizeof(local_Peer_GR_FSM)); - peer->peer_gr_present_state = PEER_GLOBAL_INHERIT; + memcpy(&peer->PEER_GR_FSM, local_Peer_GR_FSM, sizeof(local_Peer_GR_FSM)); bgp_peer_move_to_gr_mode(peer, PEER_GLOBAL_INHERIT); return BGP_GR_SUCCESS; From dc00f2dc1d4d3f6435c31bf8d4777ff78b851d12 Mon Sep 17 00:00:00 2001 From: Quentin Young Date: Thu, 28 Sep 2023 20:11:31 -0400 Subject: [PATCH 132/347] doc: add ability to disambiguate clicmds Multiple daemons have the same CLI commands defined, but the current directive used to document CLI commands only takes the command definition string. Since CLI command objects can be cross-referenced using the :clicmd: directive, and are placed in the index, each object needs to be unique. To accomplish this, add a custom directive. This directive extends the directive class used by sphinx's add_object_type to add a :daemon: option. By specifying this option where needed, the object name becomes "() ", disambiguating it. Signed-off-by: Quentin Young --- doc/user/conf.py | 50 ++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 44 insertions(+), 6 deletions(-) diff --git a/doc/user/conf.py b/doc/user/conf.py index 629a972726..a36d4406f3 100644 --- a/doc/user/conf.py +++ b/doc/user/conf.py @@ -18,6 +18,8 @@ import pygments import sphinx from sphinx.highlighting import lexers +from sphinx.domains.std import GenericObject +from docutils.parsers.rst import directives # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the @@ -373,13 +375,49 @@ def vparse(s): return a[:3] -# custom extensions here +class ClicmdDirective(GenericObject): + """ + Directive for documenting CLI commands. + + The xref string, if no option is provided, will be the verbatim command + string. If the :daemon: option is provided, then it's + "() )". + + Options: + :daemon: - specify the daemon this command belongs to. Useful for + disambiguating multiple definitions of the same command. + """ + + has_content = True + required_arguments = 1 + optional_arguments = 0 + option_spec = { + **GenericObject.option_spec, + "daemon": directives.unchanged, + } + + def handle_signature(self, sig, signode): + name = super().handle_signature(sig, signode) + daemon = self.options["daemon"] if "daemon" in self.options else "" + prefix = f"({daemon}) " if daemon else "" + return prefix + name + + def run(self): + daemon = self.options["daemon"] if "daemon" in self.options else "" + if daemon: + self.indextemplate = f"pair: ({daemon}) %s; configuration command" + else: + self.indextemplate = f"pair: %s; configuration command" + + nodes = super().run() + + return nodes + + def setup(app): - # object type for FRR CLI commands, can be extended to document parent CLI - # node later on - app.add_object_type( - "clicmd", "clicmd", indextemplate="pair: %s; configuration command" - ) + app.add_object_type("clicmd", "clicmd", objname="CLI command") + # Override the directive that was just created for us + app.add_directive_to_domain("std", "clicmd", ClicmdDirective, override=True) # I dont care how stupid this is if "add_js_file" in dir(app): From ffbad581fc2f3b6e75b59b0e91393dfe0039d861 Mon Sep 17 00:00:00 2001 From: Quentin Young Date: Wed, 26 Jun 2024 18:17:07 -0400 Subject: [PATCH 133/347] doc: do not use custom directive on old sphinx Not supported. Signed-off-by: Quentin Young --- doc/user/conf.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/doc/user/conf.py b/doc/user/conf.py index a36d4406f3..395875520d 100644 --- a/doc/user/conf.py +++ b/doc/user/conf.py @@ -415,9 +415,14 @@ def run(self): def setup(app): - app.add_object_type("clicmd", "clicmd", objname="CLI command") # Override the directive that was just created for us - app.add_directive_to_domain("std", "clicmd", ClicmdDirective, override=True) + if int(sphinx.__version__.split(".")[0]) >= 2: + app.add_object_type("clicmd", "clicmd", objname="CLI command") + app.add_directive_to_domain("std", "clicmd", ClicmdDirective, override=True) + else: + app.add_object_type( + "clicmd", "clicmd", indextemplate="pair: %s; configuration command" + ) # I dont care how stupid this is if "add_js_file" in dir(app): From fa2cc09d45d3f843564f7bd1e02346373c5741a8 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Thu, 27 Jun 2024 22:46:58 +0300 Subject: [PATCH 134/347] bgpd: Ignore RFC8212 for BGP Confederations RFC 8212 should be restricted for eBGP peers. Signed-off-by: Donatas Abraitis --- bgpd/bgp_route.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 9c3602311f..71e4199530 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -6333,7 +6333,8 @@ void bgp_set_stale_route(struct peer *peer, afi_t afi, safi_t safi) bool bgp_outbound_policy_exists(struct peer *peer, struct bgp_filter *filter) { - if (peer->sort == BGP_PEER_IBGP || peer->sub_sort == BGP_PEER_EBGP_OAD) + if (peer->sort == BGP_PEER_CONFED || peer->sort == BGP_PEER_IBGP || + peer->sub_sort == BGP_PEER_EBGP_OAD) return true; if (peer->sort == BGP_PEER_EBGP && @@ -6346,7 +6347,8 @@ bool bgp_outbound_policy_exists(struct peer *peer, struct bgp_filter *filter) bool bgp_inbound_policy_exists(struct peer *peer, struct bgp_filter *filter) { - if (peer->sort == BGP_PEER_IBGP || peer->sub_sort == BGP_PEER_EBGP_OAD) + if (peer->sort == BGP_PEER_CONFED || peer->sort == BGP_PEER_IBGP || + peer->sub_sort == BGP_PEER_EBGP_OAD) return true; if (peer->sort == BGP_PEER_EBGP From dd6a679e3a0e9415827643942bcc103c48a89adb Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Thu, 27 Jun 2024 22:53:24 +0300 Subject: [PATCH 135/347] tests: Test if RFC 8212 is not involved for BGP confederations Signed-off-by: Donatas Abraitis --- tests/topotests/bgp_confed1/r2/bgpd.conf | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/topotests/bgp_confed1/r2/bgpd.conf b/tests/topotests/bgp_confed1/r2/bgpd.conf index fe13dfe729..ba2da4160e 100644 --- a/tests/topotests/bgp_confed1/r2/bgpd.conf +++ b/tests/topotests/bgp_confed1/r2/bgpd.conf @@ -4,7 +4,6 @@ !debug bgp updates out ! router bgp 200 - no bgp ebgp-requires-policy bgp confederation identifier 300 bgp confederation peers 300 neighbor 192.0.2.1 remote-as 100 @@ -12,7 +11,9 @@ router bgp 200 ! address-family ipv4 unicast network 203.0.113.16/28 + neighbor 192.0.2.1 route-map any in + neighbor 192.0.2.1 route-map any out neighbor 192.0.2.18 default-originate exit-address-family ! - +route-map any permit 10 From c6ed1cc16d083198cc5774971126aa371e653718 Mon Sep 17 00:00:00 2001 From: vivek Date: Sun, 25 Oct 2020 17:05:48 -0700 Subject: [PATCH 136/347] bgpd: Refine restarter operation - R-bit & F-bit Introduce BGP-wide flags to denote if BGP has started gracefully and GR is in progress or not. Use this for setting of the R-bit in the GR capability, and not a timer which is set for any new instance creation. Mark graceful restart is complete when the deferred path selection has been done and route sync with zebra as well as deferred EOR advertisement has been initiated. Introduce a function to check on F-bit setting rather than just base it on configuration. Subsequent commits will extend these functionalities. Signed-off-by: Vivek Venkatraman --- bgpd/bgp_fsm.c | 16 +++++++----- bgpd/bgp_main.c | 2 ++ bgpd/bgp_open.c | 54 +++++++++++++++++++-------------------- bgpd/bgp_packet.c | 2 +- bgpd/bgp_route.c | 18 ++++++++++++- bgpd/bgp_vty.c | 2 +- bgpd/bgpd.h | 65 +++++++++++++++++++++++++++++++++++++++++++++-- 7 files changed, 121 insertions(+), 38 deletions(-) diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index 8e1462f24b..76624fee9e 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -2046,9 +2046,10 @@ static int bgp_start_deferral_timer(struct bgp *bgp, afi_t afi, safi_t safi, } gr_info->eor_required++; /* Send message to RIB indicating route update pending */ - if (gr_info->af_enabled[afi][safi] == false) { - gr_info->af_enabled[afi][safi] = true; - /* Send message to RIB */ + if (gr_info->af_enabled == false) { + gr_info->af_enabled = true; + gr_info->route_sync = false; + bgp->gr_route_sync_pending = true; bgp_zebra_update(bgp, afi, safi, ZEBRA_CLIENT_ROUTE_UPDATE_PENDING); } @@ -2082,7 +2083,7 @@ static int bgp_update_gr_info(struct peer *peer, afi_t afi, safi_t safi) if (BGP_PEER_GRACEFUL_RESTART_CAPABLE(peer) && BGP_PEER_RESTARTING_MODE(peer)) { /* Check if the forwarding state is preserved */ - if (CHECK_FLAG(bgp->flags, BGP_FLAG_GR_PRESERVE_FWD)) { + if (bgp_gr_is_forwarding_preserved(bgp)) { gr_info = &(bgp->gr_info[afi][safi]); ret = bgp_start_deferral_timer(bgp, afi, safi, gr_info); } @@ -2199,8 +2200,7 @@ bgp_establish(struct peer_connection *connection) } else { if (BGP_PEER_GRACEFUL_RESTART_CAPABLE(peer) && BGP_PEER_RESTARTING_MODE(peer) && - CHECK_FLAG(peer->bgp->flags, - BGP_FLAG_GR_PRESERVE_FWD)) + bgp_gr_is_forwarding_preserved(peer->bgp)) peer->bgp->gr_info[afi][safi] .eor_required++; } @@ -2702,10 +2702,14 @@ bgp_peer_inherit_global_gr_mode(struct peer *peer, switch (global_gr_mode) { case GLOBAL_HELPER: BGP_PEER_GR_HELPER_ENABLE(peer); + break; case GLOBAL_GR: BGP_PEER_GR_ENABLE(peer); + break; case GLOBAL_DISABLE: BGP_PEER_GR_DISABLE(peer); + break; + case GLOBAL_INVALID: default: zlog_err("Unexpected Global GR mode %d", global_gr_mode); } diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c index 97658d340b..bfedb50156 100644 --- a/bgpd/bgp_main.c +++ b/bgpd/bgp_main.c @@ -511,6 +511,7 @@ int main(int argc, char **argv) /* BGP master init. */ bgp_master_init(frr_init(), buffer_size, addresses); + bm->startup_time = monotime(NULL); bm->port = bgp_port; if (bgp_port == 0) bgp_option_set(BGP_OPT_NO_LISTEN); @@ -518,6 +519,7 @@ int main(int argc, char **argv) bgp_option_set(BGP_OPT_NO_FIB); if (no_zebra_flag) bgp_option_set(BGP_OPT_NO_ZEBRA); + SET_FLAG(bm->flags, BM_FLAG_GRACEFUL_RESTART); bgp_error_init(); /* Initializations. */ libagentx_init(); diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c index 248d478fe1..b516701b80 100644 --- a/bgpd/bgp_open.c +++ b/bgpd/bgp_open.c @@ -1587,15 +1587,12 @@ static void bgp_peer_send_gr_capability(struct stream *s, struct peer *peer, uint32_t restart_time; unsigned long capp = 0; unsigned long rcapp = 0; + struct bgp *bgp = peer->bgp; if (!CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART) && !CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART_HELPER)) return; - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("[BGP_GR] Sending helper Capability for Peer :%s :", - peer->host); - SET_FLAG(peer->cap, PEER_CAP_RESTART_ADV); stream_putc(s, BGP_OPEN_OPT_CAP); capp = stream_get_endp(s); /* Set Capability Len Pointer */ @@ -1605,42 +1602,41 @@ static void bgp_peer_send_gr_capability(struct stream *s, struct peer *peer, /* Set Restart Capability Len Pointer */ rcapp = stream_get_endp(s); stream_putc(s, 0); - restart_time = peer->bgp->restart_time; - if (peer->bgp->t_startup) { + restart_time = bgp->restart_time; + if (peer->bgp->t_startup || bgp_in_graceful_restart()) { SET_FLAG(restart_time, GRACEFUL_RESTART_R_BIT); SET_FLAG(peer->cap, PEER_CAP_GRACEFUL_RESTART_R_BIT_ADV); - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("[BGP_GR] Sending R-Bit for peer: %s", - peer->host); } - if (CHECK_FLAG(peer->bgp->flags, BGP_FLAG_GRACEFUL_NOTIFICATION)) { + if (CHECK_FLAG(bgp->flags, BGP_FLAG_GRACEFUL_NOTIFICATION)) { SET_FLAG(restart_time, GRACEFUL_RESTART_N_BIT); SET_FLAG(peer->cap, PEER_CAP_GRACEFUL_RESTART_N_BIT_ADV); - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("[BGP_GR] Sending N-Bit for peer: %s", - peer->host); } stream_putw(s, restart_time); + if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) + zlog_debug("%s: Sending GR Capability, Restart time %d R-bit %s, N-bit %s", + peer->host, bgp->restart_time, + CHECK_FLAG(peer->cap, + PEER_CAP_GRACEFUL_RESTART_R_BIT_ADV) + ? "SET" + : "NOT-SET", + CHECK_FLAG(peer->cap, + PEER_CAP_GRACEFUL_RESTART_N_BIT_ADV) + ? "SET" + : "NOT-SET"); + /* Send address-family specific graceful-restart capability * only when GR config is present */ if (CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART)) { - if (CHECK_FLAG(peer->bgp->flags, BGP_FLAG_GR_PRESERVE_FWD) - && BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("[BGP_GR] F bit Set"); - FOREACH_AFI_SAFI (afi, safi) { + bool f_bit = false; + if (!peer->afc[afi][safi]) continue; - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] Sending GR Capability for AFI :%d :, SAFI :%d:", - afi, safi); - /* Convert AFI, SAFI to values for * packet. */ @@ -1648,11 +1644,15 @@ static void bgp_peer_send_gr_capability(struct stream *s, struct peer *peer, &pkt_safi); stream_putw(s, pkt_afi); stream_putc(s, pkt_safi); - if (CHECK_FLAG(peer->bgp->flags, - BGP_FLAG_GR_PRESERVE_FWD)) - stream_putc(s, GRACEFUL_RESTART_F_BIT); - else - stream_putc(s, 0); + + f_bit = bgp_gr_is_forwarding_preserved(bgp); + + if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) + zlog_debug("... F-bit %s for %s", + f_bit ? "SET" : "NOT-SET", + get_afi_safi_str(afi, safi, false)); + + stream_putc(s, f_bit ? GRACEFUL_RESTART_F_BIT : 0); } } diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index 8825136e17..157468f8c9 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -1296,7 +1296,7 @@ void bgp_capability_send(struct peer *peer, afi_t afi, safi_t safi, stream_putc(s, 0); gr_restart_time = peer->bgp->restart_time; - if (peer->bgp->t_startup) { + if (peer->bgp->t_startup || bgp_in_graceful_restart()) { SET_FLAG(gr_restart_time, GRACEFUL_RESTART_R_BIT); SET_FLAG(peer->cap, PEER_CAP_GRACEFUL_RESTART_R_BIT_ADV); } diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 9c3602311f..c7e7b7a740 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -3877,6 +3877,7 @@ void bgp_best_path_select_defer(struct bgp *bgp, afi_t afi, safi_t safi) struct bgp_dest *dest; int cnt = 0; struct afi_safi_info *thread_info; + bool route_sync_pending = false; if (bgp->gr_info[afi][safi].t_route_select) { struct event *t = bgp->gr_info[afi][safi].t_route_select; @@ -3886,7 +3887,7 @@ void bgp_best_path_select_defer(struct bgp *bgp, afi_t afi, safi_t safi) EVENT_OFF(bgp->gr_info[afi][safi].t_route_select); } - if (BGP_DEBUG(update, UPDATE_OUT)) { + if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) { zlog_debug("%s: processing route for %s : cnt %d", __func__, get_afi_safi_str(afi, safi, false), bgp->gr_info[afi][safi].gr_deferred); @@ -3919,6 +3920,21 @@ void bgp_best_path_select_defer(struct bgp *bgp, afi_t afi, safi_t safi) /* Send route processing complete message to RIB */ bgp_zebra_update(bgp, afi, safi, ZEBRA_CLIENT_ROUTE_UPDATE_COMPLETE); + bgp->gr_info[afi][safi].route_sync = true; + + /* If this instance is all done, check for GR completion overall */ + FOREACH_AFI_SAFI_NSF (afi, safi) { + if (bgp->gr_info[afi][safi].af_enabled && + !bgp->gr_info[afi][safi].route_sync) { + route_sync_pending = true; + break; + } + } + + if (!route_sync_pending) { + bgp->gr_route_sync_pending = false; + bgp_update_gr_completion(); + } return; } diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index f5aa2e03bf..8ba167364c 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -3652,7 +3652,7 @@ DEFUN (bgp_neighbor_graceful_restart_disable_set, ret = bgp_neighbor_graceful_restart(peer, PEER_DISABLE_CMD); if (ret == BGP_GR_SUCCESS) { - if (peer->bgp->t_startup) + if (peer->bgp->t_startup || bgp_in_graceful_restart()) bgp_peer_gr_flags_update(peer); VTY_BGP_GR_ROUTER_DETECT(bgp, peer, peer->bgp->peer); diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 77955fd5c9..3c5826113d 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -167,6 +167,8 @@ struct bgp_master { #define BM_FLAG_GR_RESTARTER (1 << 3) #define BM_FLAG_GR_DISABLED (1 << 4) #define BM_FLAG_GR_PRESERVE_FWD (1 << 5) +#define BM_FLAG_GRACEFUL_RESTART (1 << 6) +#define BM_FLAG_GR_COMPLETE (1 << 7) #define BM_FLAG_GR_CONFIGURED (BM_FLAG_GR_RESTARTER | BM_FLAG_GR_DISABLED) @@ -176,6 +178,9 @@ struct bgp_master { uint32_t select_defer_time; uint32_t rib_stale_time; + time_t startup_time; + time_t gr_completion_time; + bool terminating; /* global flag that sigint terminate seen */ /* TOS value for outgoing packets in BGP connections */ @@ -305,9 +310,9 @@ struct graceful_restart_info { /* Best route select */ struct event *t_route_select; /* AFI, SAFI enabled */ - bool af_enabled[AFI_MAX][SAFI_MAX]; + bool af_enabled; /* Route update completed */ - bool route_sync[AFI_MAX][SAFI_MAX]; + bool route_sync; }; enum global_mode { @@ -559,6 +564,9 @@ struct bgp { */ enum zebra_gr_mode present_zebra_gr_state; + /* Is deferred path selection still not complete? */ + bool gr_route_sync_pending; + /* BGP Per AF flags */ uint16_t af_flags[AFI_MAX][SAFI_MAX]; #define BGP_CONFIG_DAMPENING (1 << 0) @@ -2754,6 +2762,59 @@ static inline bool bgp_in_graceful_shutdown(struct bgp *bgp) !!CHECK_FLAG(bm->flags, BM_FLAG_GRACEFUL_SHUTDOWN)); } +static inline bool bgp_in_graceful_restart(void) +{ + /* True if BGP has (re)started gracefully (based on flags + * noted at startup) and GR is not complete. + */ + return (CHECK_FLAG(bm->flags, BM_FLAG_GRACEFUL_RESTART) && + !CHECK_FLAG(bm->flags, BM_FLAG_GR_COMPLETE)); +} + +static inline bool bgp_is_graceful_restart_complete(void) +{ + /* True if BGP has (re)started gracefully (based on flags + * noted at startup) and GR is marked as complete. + */ + return (CHECK_FLAG(bm->flags, BM_FLAG_GRACEFUL_RESTART) && + CHECK_FLAG(bm->flags, BM_FLAG_GR_COMPLETE)); +} + +static inline void bgp_update_gr_completion(void) +{ + struct listnode *node, *nnode; + struct bgp *bgp; + + /* + * Check and mark GR complete. This is done when deferred + * path selection has been completed for all instances and + * route-advertisement/EOR and route-sync with zebra has + * been invoked. + */ + if (!CHECK_FLAG(bm->flags, BM_FLAG_GRACEFUL_RESTART) || + CHECK_FLAG(bm->flags, BM_FLAG_GR_COMPLETE)) + return; + + for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) { + if (bgp->gr_route_sync_pending) + return; + } + + SET_FLAG(bm->flags, BM_FLAG_GR_COMPLETE); + bm->gr_completion_time = monotime(NULL); +} + +static inline bool bgp_gr_is_forwarding_preserved(struct bgp *bgp) +{ + /* + * Is forwarding state preserved? Based either on config + * or if BGP restarted gracefully. + * TBD: Additional AFI/SAFI based checks etc. + */ + return (CHECK_FLAG(bm->flags, BM_FLAG_GRACEFUL_RESTART) || + CHECK_FLAG(bgp->flags, BGP_FLAG_GR_PRESERVE_FWD)); +} + /* For benefit of rfapi */ extern struct peer *peer_new(struct bgp *bgp); From 496b2d1be452538607ca1e9db1bf557c9f299fb8 Mon Sep 17 00:00:00 2001 From: vivek Date: Sun, 25 Oct 2020 21:16:32 -0700 Subject: [PATCH 137/347] bgpd: Refine OPEN debug logs for graceful restart This also fixes Rx F-bit log which was incorrect. Signed-off-by: Vivek Venkatraman --- bgpd/bgp_open.c | 39 +++++++++++++++++---------------------- 1 file changed, 17 insertions(+), 22 deletions(-) diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c index b516701b80..945076709c 100644 --- a/bgpd/bgp_open.c +++ b/bgpd/bgp_open.c @@ -519,20 +519,17 @@ static int bgp_capability_restart(struct peer *peer, UNSET_FLAG(restart_flag_time, 0xF000); peer->v_gr_restart = restart_flag_time; - if (bgp_debug_neighbor_events(peer)) { - zlog_debug( - "%s Peer has%srestarted. Restart Time: %d, N-bit set: %s", - peer->host, - CHECK_FLAG(peer->cap, - PEER_CAP_GRACEFUL_RESTART_R_BIT_RCV) - ? " " - : " not ", - peer->v_gr_restart, - CHECK_FLAG(peer->cap, - PEER_CAP_GRACEFUL_RESTART_N_BIT_RCV) - ? "yes" - : "no"); - } + if (bgp_debug_neighbor_events(peer)) + zlog_debug("%pBP OPEN has GR capability, Restart time %d R-bit %s N-bit %s", + peer, peer->v_gr_restart, + CHECK_FLAG(peer->cap, + PEER_CAP_GRACEFUL_RESTART_R_BIT_RCV) + ? "SET" + : "NOT-SET", + CHECK_FLAG(peer->cap, + PEER_CAP_GRACEFUL_RESTART_N_BIT_RCV) + ? "SET" + : "NOT-SET"); while (stream_get_getp(s) + 4 <= end) { afi_t afi; @@ -556,14 +553,12 @@ static int bgp_capability_restart(struct peer *peer, iana_safi2str(pkt_safi)); } else { if (bgp_debug_neighbor_events(peer)) - zlog_debug( - "%s Address family %s is%spreserved", - peer->host, get_afi_safi_str(afi, safi, false), - CHECK_FLAG( - peer->af_cap[afi][safi], - PEER_CAP_RESTART_AF_PRESERVE_RCV) - ? " " - : " not "); + zlog_debug("%pBP F-bit %s for %s", peer, + CHECK_FLAG(peer->af_cap[afi][safi], + PEER_CAP_RESTART_AF_PRESERVE_RCV) + ? "SET" + : "NOT-SET", + get_afi_safi_str(afi, safi, false)); SET_FLAG(peer->af_cap[afi][safi], PEER_CAP_RESTART_AF_RCV); From 75040a0295e3b6096bde58d12d54771a491d3454 Mon Sep 17 00:00:00 2001 From: vivek Date: Sun, 25 Oct 2020 21:21:55 -0700 Subject: [PATCH 138/347] bgpd: Enhance OPEN Tx debug log Signed-off-by: Vivek Venkatraman --- bgpd/bgp_packet.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index 157468f8c9..9a047b9d45 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -696,10 +696,9 @@ void bgp_open_send(struct peer_connection *connection) bgp_packet_set_size(s); if (bgp_debug_neighbor_events(peer)) - zlog_debug( - "%s sending OPEN, version %d, my as %u, holdtime %d, id %pI4", - peer->host, BGP_VERSION_4, local_as, send_holdtime, - &peer->local_id); + zlog_debug("%pBP fd %d sending OPEN, version %d, my as %u, holdtime %d, id %pI4", + peer, peer->connection->fd, BGP_VERSION_4, local_as, + send_holdtime, &peer->local_id); /* Dump packet if debug option is set. */ /* bgp_packet_dump (s); */ From c30b6833388a9ea858d483c583b2d73ec2f3409e Mon Sep 17 00:00:00 2001 From: vivek Date: Sun, 25 Oct 2020 21:54:13 -0700 Subject: [PATCH 139/347] bgpd: Refine debug logs for zebra GR registration Signed-off-by: Vivek Venkatraman --- bgpd/bgp_zebra.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 7f91e3149e..3508f2d341 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -3979,6 +3979,11 @@ int bgp_zebra_send_capabilities(struct bgp *bgp, bool disable) return BGP_GR_FAILURE; } + if (BGP_DEBUG(zebra, ZEBRA)) + zlog_debug("%s(%d): Sending GR capability %s to zebra", + bgp->name_pretty, bgp->vrf_id, + disable ? "disabled" : "enabled"); + /* Check if capability is already sent. If the flag force is set * send the capability since this can be initial bgp configuration */ @@ -3994,8 +3999,8 @@ int bgp_zebra_send_capabilities(struct bgp *bgp, bool disable) if (zclient_capabilities_send(ZEBRA_CLIENT_CAPABILITIES, zclient, &api) == ZCLIENT_SEND_FAILURE) { - zlog_err("%s: %s error sending capability", __func__, - bgp->name_pretty); + zlog_err("%s(%d): Error sending GR capability to zebra", + bgp->name_pretty, bgp->vrf_id); ret = BGP_GR_FAILURE; } else { if (disable) @@ -4003,9 +4008,6 @@ int bgp_zebra_send_capabilities(struct bgp *bgp, bool disable) else bgp->present_zebra_gr_state = ZEBRA_GR_ENABLE; - if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("%s: %s send capabilty success", __func__, - bgp->name_pretty); ret = BGP_GR_SUCCESS; } return ret; From ecbca1ae1be5e4e3f68bc712696f28d01909803c Mon Sep 17 00:00:00 2001 From: Pooja Jagadeesh Doijode Date: Wed, 26 Jun 2024 17:34:44 -0700 Subject: [PATCH 140/347] tests: Updated topotest and documentation Added topotest and documentation for BGP wide GR configurations Signed-off-by: Pooja Jagadeesh Doijode --- doc/user/bgp.rst | 46 +++ .../test_bgp_gr_functionality_topo1-4.py | 301 ++++++++++++++++++ .../test_bgp_gr_notification.py | 10 +- tests/topotests/lib/bgp.py | 77 ++++- 4 files changed, 412 insertions(+), 22 deletions(-) diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst index 150a915e3a..034d579568 100644 --- a/doc/user/bgp.rst +++ b/doc/user/bgp.rst @@ -1080,6 +1080,52 @@ Default global mode is helper and default peer per mode is inherit from global. If per peer mode is configured, the GR mode of this particular peer will override the global mode. +.. _bgp-GR-config-mode-cmd: + +BGP GR Config Mode Commands +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. clicmd:: bgp graceful-restart + + This command will enable BGP graceful restart functionality for all BGP instances. + +.. clicmd:: bgp graceful-restart-disable + + This command will disable both the functionality graceful restart and helper + mode for all BGP instances + +.. clicmd:: bgp graceful-restart select-defer-time (0-3600) + + This is command, will set deferral time to value specified. + +.. clicmd:: bgp graceful-restart rib-stale-time (1-3600) + + This is command, will set the time for which stale routes are kept in RIB. + +.. clicmd:: bgp graceful-restart restart-time (0-4095) + + Set the time to wait to delete stale routes before a BGP open message + is received. + + Using with Long-lived Graceful Restart capability, this is recommended + setting this timer to 0 and control stale routes with + ``bgp long-lived-graceful-restart stale-time``. + + Default value is 120. + +.. clicmd:: bgp graceful-restart stalepath-time (1-4095) + + This is command, will set the max time (in seconds) to hold onto + restarting peer's stale paths. + + It also controls Enhanced Route-Refresh timer. + + If this command is configured and the router does not receive a Route-Refresh EoRR + message, the router removes the stale routes from the BGP table after the timer + expires. The stale path timer is started when the router receives a Route-Refresh + BoRR message + + .. _bgp-GR-global-mode-cmd: BGP GR Global Mode Commands diff --git a/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-4.py b/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-4.py index 31aaa0b8a6..de4b94032c 100644 --- a/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-4.py +++ b/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-4.py @@ -81,6 +81,8 @@ import sys import time import pytest +import functools +import json # Save the Current Working Directory to find configuration files. CWD = os.path.dirname(os.path.realpath(__file__)) @@ -91,6 +93,7 @@ # Import topogen and topotest helpers from lib.topogen import Topogen, get_topogen from lib.topolog import logger +from lib import topotest # Required to instantiate the topology builder class. @@ -1680,6 +1683,304 @@ def BGP_GR_TC_52_p1(request): write_test_footer(tc_name) +def test_BGP_GR_TC_53_p1(request): + """ + Test Objective : Peer-level inherit from BGP wide Restarting + Global Mode : GR Restart + PerPeer Mode : None + GR Mode effective : GR Restart + + """ + + tgen = get_topogen() + tc_name = request.node.name + write_test_header(tc_name) + + # Check router status + check_router_status(tgen) + + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # Creating configuration from JSON + reset_config_on_routers(tgen) + + step("Configure R1 as GR restarting node in global level") + + input_dict = { + "r1": {"graceful-restart": {"graceful-restart": True}}, + "r2": {"graceful-restart": {"graceful-restart-helper": True}}, + } + + output = tgen.gears["r1"].vtysh_cmd( + """ + configure terminal + bgp graceful-restart + ! + """ + ) + + step("Verify that R2 receives GR restarting capabilities" " from R1") + + for addr_type in ADDR_TYPES: + result = verify_graceful_restart( + tgen, topo, addr_type, input_dict, dut="r1", peer="r2" + ) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + result = verify_graceful_restart( + tgen, topo, addr_type, input_dict, dut="r2", peer="r1" + ) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + for addr_type in ADDR_TYPES: + dut = "r1" + peer = "r2" + protocol = "bgp" + next_hop = next_hop_per_address_family( + tgen, dut, peer, addr_type, NEXT_HOP_IP_2 + ) + input_topo = {"r2": topo["routers"]["r2"]} + result = verify_rib(tgen, addr_type, dut, input_topo, next_hop, protocol) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + dut = "r2" + peer = "r1" + next_hop = next_hop_per_address_family( + tgen, dut, peer, addr_type, NEXT_HOP_IP_1 + ) + input_topo = {"r1": topo["routers"]["r1"]} + result = verify_bgp_rib(tgen, addr_type, dut, input_topo, next_hop) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + result = verify_rib(tgen, addr_type, dut, input_topo, next_hop, protocol) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + step("Kill BGPd on router R1") + + kill_router_daemons(tgen, "r1", ["bgpd"]) + + step( + "Verify that R1 keeps the stale entries in FIB and R2 keeps stale entries in RIB & FIB" + ) + + for addr_type in ADDR_TYPES: + dut = "r1" + peer = "r2" + protocol = "bgp" + next_hop = next_hop_per_address_family( + tgen, dut, peer, addr_type, NEXT_HOP_IP_2 + ) + input_topo = {"r2": topo["routers"]["r2"]} + result = verify_rib(tgen, addr_type, dut, input_topo, next_hop, protocol) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + dut = "r2" + peer = "r1" + next_hop = next_hop_per_address_family( + tgen, dut, peer, addr_type, NEXT_HOP_IP_1 + ) + input_topo = {"r1": topo["routers"]["r1"]} + result = verify_bgp_rib(tgen, addr_type, dut, input_topo, next_hop) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + result = verify_rib(tgen, addr_type, dut, input_topo, next_hop, protocol) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + # Configure graceful-restart-disable at config global level verify that the functionality works + step("Bring up BGP on R1 and configure graceful-restart-disable") + + start_router_daemons(tgen, "r1", ["bgpd"]) + + input_dict = { + "r1": {"graceful-restart": {"graceful-restart-disable": True}}, + "r2": {"graceful-restart": {"graceful-restart-helper": True}}, + } + + output = tgen.gears["r1"].vtysh_cmd( + """ + configure terminal + bgp graceful-restart-disable + ! + """ + ) + + step("Verify on R2 that R1 does't advertise any GR capabilities") + + for addr_type in ADDR_TYPES: + result = verify_graceful_restart( + tgen, topo, addr_type, input_dict, dut="r1", peer="r2" + ) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + result = verify_graceful_restart( + tgen, topo, addr_type, input_dict, dut="r2", peer="r1" + ) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + for addr_type in ADDR_TYPES: + dut = "r1" + peer = "r2" + protocol = "bgp" + next_hop = next_hop_per_address_family( + tgen, dut, peer, addr_type, NEXT_HOP_IP_2 + ) + input_topo = {"r2": topo["routers"]["r2"]} + result = verify_rib(tgen, addr_type, dut, input_topo, next_hop, protocol) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + dut = "r2" + peer = "r1" + next_hop = next_hop_per_address_family( + tgen, dut, peer, addr_type, NEXT_HOP_IP_1 + ) + input_topo = {"r1": topo["routers"]["r1"]} + result = verify_bgp_rib(tgen, addr_type, dut, input_topo, next_hop) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + result = verify_rib(tgen, addr_type, dut, input_topo, next_hop, protocol) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + step("Kill BGP on R1") + + kill_router_daemons(tgen, "r1", ["bgpd"]) + + step("Verify on R2 and R1 that none of the routers keep stale entries") + + for addr_type in ADDR_TYPES: + dut = "r1" + peer = "r2" + protocol = "bgp" + next_hop = next_hop_per_address_family( + tgen, dut, peer, addr_type, NEXT_HOP_IP_2 + ) + input_topo = {"r2": topo["routers"]["r2"]} + result = verify_rib( + tgen, addr_type, dut, input_topo, next_hop, protocol, expected=False + ) + assert result is not True, ( + "Testcase {} : Failed \n " + "Expected: Routes should not be present in {} FIB \n " + "Found: {}".format(tc_name, dut, result) + ) + + dut = "r2" + peer = "r1" + next_hop = next_hop_per_address_family( + tgen, dut, peer, addr_type, NEXT_HOP_IP_1 + ) + input_topo = {"r1": topo["routers"]["r1"]} + result = verify_bgp_rib( + tgen, addr_type, dut, input_topo, next_hop, expected=False + ) + assert result is not True, ( + "Testcase {} : Failed \n " + "Expected: Routes should not be present in {} BGP RIB \n " + "Found: {}".format(tc_name, dut, result) + ) + + result = verify_rib( + tgen, addr_type, dut, input_topo, next_hop, protocol, expected=False + ) + assert result is not True, ( + "Testcase {} : Failed \n " + "Expected: Routes should not be present in {} FIB \n " + "Found: {}".format(tc_name, dut, result) + ) + + step( + "Bring up BGP on R1, enable GR and configure bgp graceful-restart restart-time at global level" + ) + + start_router_daemons(tgen, "r1", ["bgpd"]) + + output = tgen.gears["r1"].vtysh_cmd( + """ + configure terminal + no bgp graceful-restart-disable + bgp graceful-restart + bgp graceful-restart stalepath-time 420 + bgp graceful-restart restart-time 240 + bgp graceful-restart select-defer-time 420 + ! + """ + ) + + step("Verify on R2 that R1 sent the updated GR restart-time") + + def _bgp_check_if_gr_restart_time_was_updated(): + output = json.loads(tgen.gears["r2"].vtysh_cmd("show bgp neighbor json")) + + expected = { + "192.168.0.1": { + "gracefulRestartInfo": { + "localGrMode": "Helper*", + "remoteGrMode": "Restart", + "timers": { + "configuredRestartTimer": 120, + "receivedRestartTimer": 240, + }, + }, + }, + "fd00::1": { + "gracefulRestartInfo": { + "localGrMode": "Helper*", + "remoteGrMode": "Restart", + "timers": { + "configuredRestartTimer": 120, + "receivedRestartTimer": 240, + }, + }, + }, + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _bgp_check_if_gr_restart_time_was_updated, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "R2 did not receive the updated GR restart-time of 240s" + + def _bgp_check_if_gr_timer_on_restarting_node_was_updated(): + output = json.loads(tgen.gears["r1"].vtysh_cmd("show bgp neighbor json")) + + expected = { + "192.168.0.2": { + "gracefulRestartInfo": { + "localGrMode": "Restart*", + "remoteGrMode": "Helper", + "timers": { + "configuredRestartTimer": 240, + "receivedRestartTimer": 120, + }, + "ipv4Unicast": { + "timers": {"stalePathTimer": 420, "selectionDeferralTimer": 420} + }, + }, + }, + "fd00::2": { + "gracefulRestartInfo": { + "localGrMode": "Restart*", + "remoteGrMode": "Helper", + "timers": { + "configuredRestartTimer": 240, + "receivedRestartTimer": 120, + }, + "ipv6Unicast": { + "timers": {"stalePathTimer": 420, "selectionDeferralTimer": 420} + }, + }, + }, + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _bgp_check_if_gr_timer_on_restarting_node_was_updated, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert ( + result is None + ), "R1 did not update the GR select-deferral and stale-path timer to 420s" + + write_test_footer(tc_name) + + if __name__ == "__main__": args = ["-s"] + sys.argv[1:] sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_gr_notification/test_bgp_gr_notification.py b/tests/topotests/bgp_gr_notification/test_bgp_gr_notification.py index 16459a25a3..5d8338d6eb 100644 --- a/tests/topotests/bgp_gr_notification/test_bgp_gr_notification.py +++ b/tests/topotests/bgp_gr_notification/test_bgp_gr_notification.py @@ -195,16 +195,16 @@ def _bgp_clear_r1_and_shutdown(): step("Reset and shutdown R1") _bgp_clear_r1_and_shutdown() - step("Check if Hard Reset notification wasn't sent from R2") - test_func = functools.partial(_bgp_check_hard_reset) - _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) - assert result is None, "Failed to send Administrative Reset notification from R2" - step("Check if stale routes are retained on R1") test_func = functools.partial(_bgp_check_gr_notification_stale) _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, "Failed to see retained stale routes on R1" + step("Check if Hard Reset notification wasn't sent from R2") + test_func = functools.partial(_bgp_check_hard_reset) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result is None, "Failed to send Administrative Reset notification from R2" + if __name__ == "__main__": args = ["-s"] + sys.argv[1:] diff --git a/tests/topotests/lib/bgp.py b/tests/topotests/lib/bgp.py index 4250c405f3..3f4ed6e0b8 100644 --- a/tests/topotests/lib/bgp.py +++ b/tests/topotests/lib/bgp.py @@ -3266,27 +3266,48 @@ def verify_graceful_restart( lmode = None rmode = None - # Local GR mode - if "address_family" in input_dict[dut]["bgp"]: - bgp_neighbors = input_dict[dut]["bgp"]["address_family"][addr_type][ - "unicast" - ]["neighbor"][peer]["dest_link"] - for dest_link, data in bgp_neighbors.items(): + # Local GR mode + if "bgp" not in input_dict[dut] and "graceful-restart" in input_dict[dut]: if ( - "graceful-restart-helper" in data - and data["graceful-restart-helper"] + "graceful-restart" in input_dict[dut]["graceful-restart"] + and input_dict[dut]["graceful-restart"][ + "graceful-restart" + ] ): - lmode = "Helper" - elif "graceful-restart" in data and data["graceful-restart"]: - lmode = "Restart" + lmode = "Restart*" elif ( - "graceful-restart-disable" in data - and data["graceful-restart-disable"] + "graceful-restart-disable" + in input_dict[dut]["graceful-restart"] + and input_dict[dut]["graceful-restart"][ + "graceful-restart-disable" + ] ): - lmode = "Disable" + lmode = "Disable*" else: - lmode = None + lmode = "Helper*" + + if lmode is None: + if "address_family" in input_dict[dut]["bgp"]: + bgp_neighbors = input_dict[dut]["bgp"]["address_family"][addr_type][ + "unicast" + ]["neighbor"][peer]["dest_link"] + + for dest_link, data in bgp_neighbors.items(): + if ( + "graceful-restart-helper" in data + and data["graceful-restart-helper"] + ): + lmode = "Helper" + elif "graceful-restart" in data and data["graceful-restart"]: + lmode = "Restart" + elif ( + "graceful-restart-disable" in data + and data["graceful-restart-disable"] + ): + lmode = "Disable" + else: + lmode = None if lmode is None: if "graceful-restart" in input_dict[dut]["bgp"]: @@ -3314,7 +3335,8 @@ def verify_graceful_restart( return True # Remote GR mode - if "address_family" in input_dict[peer]["bgp"]: + + if "bgp" in input_dict[peer] and "address_family" in input_dict[peer]["bgp"]: bgp_neighbors = input_dict[peer]["bgp"]["address_family"][addr_type][ "unicast" ]["neighbor"][dut]["dest_link"] @@ -3336,7 +3358,7 @@ def verify_graceful_restart( rmode = None if rmode is None: - if "graceful-restart" in input_dict[peer]["bgp"]: + if "bgp" in input_dict[peer] and "graceful-restart" in input_dict[peer]["bgp"]: if ( "graceful-restart" in input_dict[peer]["bgp"]["graceful-restart"] @@ -3355,6 +3377,27 @@ def verify_graceful_restart( rmode = "Disable" else: rmode = "Helper" + + if rmode is None: + if "bgp" not in input_dict[peer] and "graceful-restart" in input_dict[peer]: + if ( + "graceful-restart" + in input_dict[peer]["graceful-restart"] + and input_dict[peer]["graceful-restart"][ + "graceful-restart" + ] + ): + rmode = "Restart" + elif ( + "graceful-restart-disable" + in input_dict[peer]["graceful-restart"] + and input_dict[peer]["graceful-restart"][ + "graceful-restart-disable" + ] + ): + rmode = "Disable" + else: + rmode = "Helper" else: rmode = "Helper" From b5682ffbf0051b54af972e6da4c3319adb7a292f Mon Sep 17 00:00:00 2001 From: vivek Date: Wed, 26 Jun 2024 15:49:45 -0700 Subject: [PATCH 141/347] *: Add and use option for graceful (re)start Add a new start option "-K" to libfrr to denote a graceful start, and use it in zebra and bgpd. zebra will use this option to denote a planned FRR graceful restart (supporting only bgpd currently) to wait for a route sync completion from bgpd before cleaning up old stale routes from the FIB. An optional timer provides an upper-bounds for this cleanup. bgpd will use this option to denote either a planned FRR graceful restart or a bgpd-only graceful restart, and this will drive the BGP GR restarting router procedures. Signed-off-by: Vivek Venkatraman --- bgpd/bgp_main.c | 4 +- bgpd/bgp_vty.c | 3 +- doc/user/bgp.rst | 6 +++ lib/libfrr.c | 45 +++++++++++++-------- lib/libfrr.h | 2 + tests/topotests/lib/bgp.py | 55 +++++++++++++------------- zebra/main.c | 33 +++++++++------- zebra/rib.h | 4 +- zebra/zapi_msg.c | 1 + zebra/zebra_gr.c | 81 ++++++++++++++++++++++++++------------ zebra/zebra_rib.c | 11 +++++- zebra/zebra_router.c | 2 +- zebra/zebra_router.h | 10 ++++- zebra/zebra_vty.c | 14 +++++++ zebra/zserv.c | 40 +++++++++++++++++++ zebra/zserv.h | 2 + 16 files changed, 221 insertions(+), 92 deletions(-) diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c index bfedb50156..5e6a62c9b9 100644 --- a/bgpd/bgp_main.c +++ b/bgpd/bgp_main.c @@ -519,7 +519,9 @@ int main(int argc, char **argv) bgp_option_set(BGP_OPT_NO_FIB); if (no_zebra_flag) bgp_option_set(BGP_OPT_NO_ZEBRA); - SET_FLAG(bm->flags, BM_FLAG_GRACEFUL_RESTART); + if (bgpd_di.graceful_restart) + SET_FLAG(bm->flags, BM_FLAG_GRACEFUL_RESTART); + bgp_error_init(); /* Initializations. */ libagentx_init(); diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 8ba167364c..e9a79766ec 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -3706,9 +3706,10 @@ DEFPY (neighbor_graceful_shutdown, afi_t afi; safi_t safi; struct peer *peer; - VTY_DECLVAR_CONTEXT(bgp, bgp); int ret; + VTY_DECLVAR_CONTEXT(bgp, bgp); + peer = peer_and_group_lookup_vty(vty, neighbor); if (!peer) return CMD_WARNING_CONFIG_FAILED; diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst index 034d579568..98834c7c23 100644 --- a/doc/user/bgp.rst +++ b/doc/user/bgp.rst @@ -92,6 +92,12 @@ be specified (:ref:`common-invocation-options`). the operator has turned off communication to zebra and is running bgpd as a complete standalone process. +.. option:: -K, --graceful_restart + + Bgpd will use this option to denote either a planned FRR graceful + restart or a bgpd-only graceful restart, and this will drive the BGP + GR restarting router procedures. + LABEL MANAGER ------------- diff --git a/lib/libfrr.c b/lib/libfrr.c index 876efe23a8..338a7d0340 100644 --- a/lib/libfrr.c +++ b/lib/libfrr.c @@ -102,23 +102,25 @@ static void opt_extend(const struct optspec *os) #define OPTION_SCRIPTDIR 1009 static const struct option lo_always[] = { - {"help", no_argument, NULL, 'h'}, - {"version", no_argument, NULL, 'v'}, - {"daemon", no_argument, NULL, 'd'}, - {"module", no_argument, NULL, 'M'}, - {"profile", required_argument, NULL, 'F'}, - {"pathspace", required_argument, NULL, 'N'}, - {"vrfdefaultname", required_argument, NULL, 'o'}, - {"vty_socket", required_argument, NULL, OPTION_VTYSOCK}, - {"moduledir", required_argument, NULL, OPTION_MODULEDIR}, - {"scriptdir", required_argument, NULL, OPTION_SCRIPTDIR}, - {"log", required_argument, NULL, OPTION_LOG}, - {"log-level", required_argument, NULL, OPTION_LOGLEVEL}, - {"command-log-always", no_argument, NULL, OPTION_LOGGING}, - {"limit-fds", required_argument, NULL, OPTION_LIMIT_FDS}, - {NULL}}; + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, 'v' }, + { "daemon", no_argument, NULL, 'd' }, + { "module", no_argument, NULL, 'M' }, + { "profile", required_argument, NULL, 'F' }, + { "pathspace", required_argument, NULL, 'N' }, + { "vrfdefaultname", required_argument, NULL, 'o' }, + { "graceful_restart", optional_argument, NULL, 'K' }, + { "vty_socket", required_argument, NULL, OPTION_VTYSOCK }, + { "moduledir", required_argument, NULL, OPTION_MODULEDIR }, + { "scriptdir", required_argument, NULL, OPTION_SCRIPTDIR }, + { "log", required_argument, NULL, OPTION_LOG }, + { "log-level", required_argument, NULL, OPTION_LOGLEVEL }, + { "command-log-always", no_argument, NULL, OPTION_LOGGING }, + { "limit-fds", required_argument, NULL, OPTION_LIMIT_FDS }, + { NULL } +}; static const struct optspec os_always = { - "hvdM:F:N:o:", + "hvdM:F:N:o:K::", " -h, --help Display this help and exit\n" " -v, --version Print program version\n" " -d, --daemon Runs in daemon mode\n" @@ -126,13 +128,15 @@ static const struct optspec os_always = { " -F, --profile Use specified configuration profile\n" " -N, --pathspace Insert prefix into config & socket paths\n" " -o, --vrfdefaultname Set default VRF name.\n" + " -K, --graceful_restart FRR starting in Graceful Restart mode, with optional route-cleanup timer\n" " --vty_socket Override vty socket path\n" " --moduledir Override modules directory\n" " --scriptdir Override scripts directory\n" " --log Set Logging to stdout, syslog, or file:\n" " --log-level Set Logging Level to use, debug, info, warn, etc\n" " --limit-fds Limit number of fds supported\n", - lo_always}; + lo_always +}; static bool logging_to_stdout = false; /* set when --log stdout specified */ @@ -358,6 +362,8 @@ void frr_preinit(struct frr_daemon_info *daemon, int argc, char **argv) strlcpy(frr_protonameinst, di->logname, sizeof(frr_protonameinst)); di->cli_mode = FRR_CLI_CLASSIC; + di->graceful_restart = false; + di->gr_cleanup_time = 0; /* we may be starting with extra FDs open for whatever purpose, * e.g. logging, some module, etc. Recording them here allows later @@ -520,6 +526,11 @@ static int frr_opt(int opt) di->db_file = optarg; break; #endif + case 'K': + di->graceful_restart = true; + if (optarg) + di->gr_cleanup_time = atoi(optarg); + break; case 'C': if (di->flags & FRR_NO_SPLIT_CONFIG) return 1; diff --git a/lib/libfrr.h b/lib/libfrr.h index 77d70448a9..db9cfbcb1f 100644 --- a/lib/libfrr.h +++ b/lib/libfrr.h @@ -118,6 +118,8 @@ struct frr_daemon_info { bool dryrun; bool daemon_mode; bool terminal; + bool graceful_restart; + int gr_cleanup_time; enum frr_cli_mode cli_mode; struct event *read_in; diff --git a/tests/topotests/lib/bgp.py b/tests/topotests/lib/bgp.py index 3f4ed6e0b8..bcd1c74812 100644 --- a/tests/topotests/lib/bgp.py +++ b/tests/topotests/lib/bgp.py @@ -3269,29 +3269,24 @@ def verify_graceful_restart( # Local GR mode if "bgp" not in input_dict[dut] and "graceful-restart" in input_dict[dut]: - if ( - "graceful-restart" in input_dict[dut]["graceful-restart"] - and input_dict[dut]["graceful-restart"][ - "graceful-restart" - ] - ): - lmode = "Restart*" - elif ( - "graceful-restart-disable" - in input_dict[dut]["graceful-restart"] - and input_dict[dut]["graceful-restart"][ - "graceful-restart-disable" - ] - ): - lmode = "Disable*" - else: - lmode = "Helper*" + if ( + "graceful-restart" in input_dict[dut]["graceful-restart"] + and input_dict[dut]["graceful-restart"]["graceful-restart"] + ): + lmode = "Restart*" + elif ( + "graceful-restart-disable" in input_dict[dut]["graceful-restart"] + and input_dict[dut]["graceful-restart"]["graceful-restart-disable"] + ): + lmode = "Disable*" + else: + lmode = "Helper*" if lmode is None: if "address_family" in input_dict[dut]["bgp"]: bgp_neighbors = input_dict[dut]["bgp"]["address_family"][addr_type][ - "unicast" - ]["neighbor"][peer]["dest_link"] + "unicast" + ]["neighbor"][peer]["dest_link"] for dest_link, data in bgp_neighbors.items(): if ( @@ -3336,7 +3331,10 @@ def verify_graceful_restart( # Remote GR mode - if "bgp" in input_dict[peer] and "address_family" in input_dict[peer]["bgp"]: + if ( + "bgp" in input_dict[peer] + and "address_family" in input_dict[peer]["bgp"] + ): bgp_neighbors = input_dict[peer]["bgp"]["address_family"][addr_type][ "unicast" ]["neighbor"][dut]["dest_link"] @@ -3358,7 +3356,10 @@ def verify_graceful_restart( rmode = None if rmode is None: - if "bgp" in input_dict[peer] and "graceful-restart" in input_dict[peer]["bgp"]: + if ( + "bgp" in input_dict[peer] + and "graceful-restart" in input_dict[peer]["bgp"] + ): if ( "graceful-restart" in input_dict[peer]["bgp"]["graceful-restart"] @@ -3379,13 +3380,13 @@ def verify_graceful_restart( rmode = "Helper" if rmode is None: - if "bgp" not in input_dict[peer] and "graceful-restart" in input_dict[peer]: + if ( + "bgp" not in input_dict[peer] + and "graceful-restart" in input_dict[peer] + ): if ( - "graceful-restart" - in input_dict[peer]["graceful-restart"] - and input_dict[peer]["graceful-restart"][ - "graceful-restart" - ] + "graceful-restart" in input_dict[peer]["graceful-restart"] + and input_dict[peer]["graceful-restart"]["graceful-restart"] ): rmode = "Restart" elif ( diff --git a/zebra/main.c b/zebra/main.c index ea1e1cbdbb..687da70cab 100644 --- a/zebra/main.c +++ b/zebra/main.c @@ -65,8 +65,6 @@ struct mgmt_be_client *mgmt_be_client; /* Route retain mode flag. */ int retain_mode = 0; -int graceful_restart; - /* Receive buffer size for kernel control sockets */ #define RCVBUFSIZE_MIN 4194304 #ifdef HAVE_NETLINK @@ -88,7 +86,6 @@ const struct option longopts[] = { { "socket", required_argument, NULL, 'z' }, { "ecmp", required_argument, NULL, 'e' }, { "retain", no_argument, NULL, 'r' }, - { "graceful_restart", required_argument, NULL, 'K' }, { "asic-offload", optional_argument, NULL, OPTION_ASIC_OFFLOAD }, { "v6-with-v4-nexthops", no_argument, NULL, OPTION_V6_WITH_V4_NEXTHOP }, #ifdef HAVE_NETLINK @@ -96,7 +93,7 @@ const struct option longopts[] = { { "nl-bufsize", required_argument, NULL, 's' }, { "v6-rr-semantics", no_argument, NULL, OPTION_V6_RR_SEMANTICS }, #endif /* HAVE_NETLINK */ - {"routing-table", optional_argument, NULL, 'R'}, + { "routing-table", optional_argument, NULL, 'R' }, { 0 } }; @@ -326,7 +323,6 @@ int main(int argc, char **argv) bool v6_with_v4_nexthop = false; bool notify_on_ack = true; - graceful_restart = 0; vrf_configure_backend(VRF_BACKEND_VRF_LITE); frr_preinit(&zebra_di, argc, argv); @@ -342,7 +338,6 @@ int main(int argc, char **argv) " -z, --socket Set path of zebra socket\n" " -e, --ecmp Specify ECMP to use.\n" " -r, --retain When program terminates, retain added route by zebra.\n" - " -K, --graceful_restart Graceful restart at the kernel level, timer in seconds for expiration\n" " -A, --asic-offload FRR is interacting with an asic underneath the linux kernel\n" " --v6-with-v4-nexthops Underlying dataplane supports v6 routes with v4 nexthops" #ifdef HAVE_NETLINK @@ -352,8 +347,7 @@ int main(int argc, char **argv) #else " -s, Set kernel socket receive buffer size\n" #endif /* HAVE_NETLINK */ - " -R, --routing-table Set kernel routing table\n" - ); + " -R, --routing-table Set kernel routing table\n"); while (1) { int opt = frr_getopt(argc, argv, NULL); @@ -397,9 +391,6 @@ int main(int argc, char **argv) case 'r': retain_mode = 1; break; - case 'K': - graceful_restart = atoi(optarg); - break; case 's': rcvbufsize = atoi(optarg); if (rcvbufsize < RCVBUFSIZE_MIN) @@ -488,11 +479,25 @@ int main(int argc, char **argv) * Clean up zebra-originated routes. The requests will be sent to OS * immediately, so originating PID in notifications from kernel * will be equal to the current getpid(). To know about such routes, - * we have to have route_read() called before. + * we have to have route_read() called before. + * If FRR is gracefully restarting, we either wait for clients + * (e.g., BGP) to signal GR is complete else we wait for specified + * duration. */ zrouter.startup_time = monotime(NULL); - event_add_timer(zrouter.master, rib_sweep_route, NULL, graceful_restart, - &zrouter.sweeper); + zrouter.rib_sweep_time = 0; + zrouter.graceful_restart = zebra_di.graceful_restart; + if (!zrouter.graceful_restart) + event_add_timer(zrouter.master, rib_sweep_route, NULL, 0, NULL); + else { + int gr_cleanup_time; + + gr_cleanup_time = zebra_di.gr_cleanup_time + ? zebra_di.gr_cleanup_time + : ZEBRA_GR_DEFAULT_RIB_SWEEP_TIME; + event_add_timer(zrouter.master, rib_sweep_route, NULL, + gr_cleanup_time, &zrouter.t_rib_sweep); + } /* Needed for BSD routing socket. */ pid = getpid(); diff --git a/zebra/rib.h b/zebra/rib.h index a721f4bac4..84ea766c47 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -622,10 +622,10 @@ static inline struct nexthop_group *rib_get_fib_backup_nhg( } extern void zebra_gr_process_client(afi_t afi, vrf_id_t vrf_id, uint8_t proto, - uint8_t instance); + uint8_t instance, time_t restart_time); extern int rib_add_gr_run(afi_t afi, vrf_id_t vrf_id, uint8_t proto, - uint8_t instance); + uint8_t instance, time_t restart_time); extern void zebra_vty_init(void); diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index 2a1eea9594..654ade8063 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -2414,6 +2414,7 @@ static void zsend_capabilities(struct zserv *client, struct zebra_vrf *zvrf) stream_putl(s, zrouter.multipath_num); stream_putc(s, zebra_mlag_get_role()); stream_putc(s, zrouter.v6_with_v4_nexthop); + stream_putc(s, zrouter.graceful_restart); stream_putw_at(s, 0, stream_get_endp(s)); zserv_send_message(client, s); } diff --git a/zebra/zebra_gr.c b/zebra/zebra_gr.c index cee66cc055..d84f680e22 100644 --- a/zebra/zebra_gr.c +++ b/zebra/zebra_gr.c @@ -103,6 +103,7 @@ static struct client_gr_info *zebra_gr_client_info_create(struct zserv *client) info->stale_client_ptr = client; TAILQ_INSERT_TAIL(&(client->gr_info_queue), info, gr_info); + info->client_ptr = client; return info; } @@ -290,6 +291,7 @@ struct zebra_gr_afi_clean { afi_t afi; uint8_t proto; uint8_t instance; + time_t restart_time; struct event *t_gac; }; @@ -420,7 +422,7 @@ void zread_client_capabilities(ZAPI_HANDLER_ARGS) * Schedule for after anything already in the meta Q */ rib_add_gr_run(api.afi, api.vrf_id, client->proto, - client->instance); + client->instance, client->restart_time); zebra_gr_process_client_stale_routes(client, info); break; case ZEBRA_CLIENT_ROUTE_UPDATE_PENDING: @@ -455,7 +457,11 @@ static void zebra_gr_route_stale_delete_timer_expiry(struct event *thread) struct zserv *client; struct vrf *vrf = vrf_lookup_by_id(info->vrf_id); - client = (struct zserv *)info->stale_client_ptr; + info->t_stale_removal = NULL; + if (zrouter.graceful_restart) + client = (struct zserv *)info->client_ptr; + else + client = (struct zserv *)info->stale_client_ptr; cnt = zebra_gr_delete_stale_routes(info); @@ -486,16 +492,24 @@ static void zebra_gr_route_stale_delete_timer_expiry(struct event *thread) * * Returns true when a node is deleted else false */ -static bool zebra_gr_process_route_entry(struct zserv *client, - struct route_node *rn, - struct route_entry *re) +static bool zebra_gr_process_route_entry(struct route_node *rn, + struct route_entry *re, + time_t compare_time, uint8_t proto) { + struct nexthop *nexthop; + char buf[PREFIX2STR_BUFFER]; + /* If the route is not refreshed after restart, delete the entry */ - if (re->uptime < client->restart_time) { - if (IS_ZEBRA_DEBUG_RIB) - zlog_debug("%s: Client %s stale route %pFX is deleted", - __func__, zebra_route_string(client->proto), - &rn->p); + if (re->uptime < compare_time) { + if (IS_ZEBRA_DEBUG_RIB) { + prefix2str(&rn->p, buf, sizeof(buf)); + zlog_debug("%s: Client %s stale route %s is deleted", + __func__, zebra_route_string(proto), buf); + } + SET_FLAG(re->status, ROUTE_ENTRY_INSTALLED); + for (ALL_NEXTHOPS(re->nhe->nhg, nexthop)) + SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB); + rib_delnode(rn, re); return true; @@ -532,8 +546,9 @@ static void zebra_gr_delete_stale_route_table_afi(struct event *event) if (re->type == gac->proto && re->instance == gac->instance && - zebra_gr_process_route_entry( - gac->info->stale_client_ptr, rn, re)) + zebra_gr_process_route_entry(rn, re, + gac->restart_time, + gac->proto)) n++; /* If the max route count is reached @@ -567,28 +582,42 @@ static int32_t zebra_gr_delete_stale_route(struct client_gr_info *info, uint8_t proto; uint16_t instance; struct zserv *s_client; + struct zserv *client; + time_t restart_time = time(NULL); - s_client = info->stale_client_ptr; - if (s_client == NULL) { - LOG_GR("%s: Stale client %s(%u) not present", __func__, - zvrf->vrf->name, zvrf->vrf->vrf_id); + if ((info == NULL) || (zvrf == NULL)) return -1; - } - proto = s_client->proto; - instance = s_client->instance; + if (zrouter.graceful_restart) { + client = info->client_ptr; + if (client == NULL) { + LOG_GR("%s: client not present", __func__); + return -1; + } + proto = client->proto; + instance = client->instance; + restart_time = zrouter.startup_time; + } else { + s_client = info->stale_client_ptr; + if (s_client == NULL) { + LOG_GR("%s: Stale client not present", __func__); + return -1; + } + proto = s_client->proto; + instance = s_client->instance; + restart_time = s_client->restart_time; + } LOG_GR("%s: Client %s %s(%u) stale routes are being deleted", __func__, zebra_route_string(proto), zvrf->vrf->name, zvrf->vrf->vrf_id); /* Process routes for all AFI */ for (afi = AFI_IP; afi < AFI_MAX; afi++) { - /* * Schedule for immediately after anything in the * meta-Q */ - rib_add_gr_run(afi, info->vrf_id, proto, instance); + rib_add_gr_run(afi, info->vrf_id, proto, instance, restart_time); } return 0; } @@ -641,12 +670,13 @@ static void zebra_gr_process_client_stale_routes(struct zserv *client, /* * Route update completed for all AFI, SAFI - * Cancel the stale timer, routes are already being processed + * Also perform the cleanup if FRR itself is gracefully restarting. */ - if (info->t_stale_removal) { + info->route_sync_done_time = monotime(NULL); + if (info->t_stale_removal || zrouter.graceful_restart) { struct vrf *vrf = vrf_lookup_by_id(info->vrf_id); - LOG_GR("%s: Client %s canceled stale delete timer vrf %s(%d)", + LOG_GR("%s: Client %s route update complete for all AFI/SAFI in vrf %s(%d)", __func__, zebra_route_string(client->proto), VRF_LOGNAME(vrf), info->vrf_id); EVENT_OFF(info->t_stale_removal); @@ -654,7 +684,7 @@ static void zebra_gr_process_client_stale_routes(struct zserv *client, } void zebra_gr_process_client(afi_t afi, vrf_id_t vrf_id, uint8_t proto, - uint8_t instance) + uint8_t instance, time_t restart_time) { struct zserv *client = zserv_find_client(proto, instance); struct client_gr_info *info = NULL; @@ -676,6 +706,7 @@ void zebra_gr_process_client(afi_t afi, vrf_id_t vrf_id, uint8_t proto, gac->afi = afi; gac->proto = proto; gac->instance = instance; + gac->restart_time = restart_time; event_add_event(zrouter.master, zebra_gr_delete_stale_route_table_afi, gac, 0, &gac->t_gac); diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 5b95d8668a..b176ea2fe6 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -3159,6 +3159,7 @@ struct meta_q_gr_run { vrf_id_t vrf_id; uint8_t proto; uint8_t instance; + time_t restart_time; }; static void process_subq_gr_run(struct listnode *lnode) @@ -3166,7 +3167,7 @@ static void process_subq_gr_run(struct listnode *lnode) struct meta_q_gr_run *gr_run = listgetdata(lnode); zebra_gr_process_client(gr_run->afi, gr_run->vrf_id, gr_run->proto, - gr_run->instance); + gr_run->instance, gr_run->restart_time); XFREE(MTYPE_WQ_WRAPPER, gr_run); } @@ -4266,7 +4267,8 @@ static int rib_meta_queue_early_route_add(struct meta_queue *mq, void *data) return 0; } -int rib_add_gr_run(afi_t afi, vrf_id_t vrf_id, uint8_t proto, uint8_t instance) +int rib_add_gr_run(afi_t afi, vrf_id_t vrf_id, uint8_t proto, uint8_t instance, + time_t restart_time) { struct meta_q_gr_run *gr_run; @@ -4276,6 +4278,7 @@ int rib_add_gr_run(afi_t afi, vrf_id_t vrf_id, uint8_t proto, uint8_t instance) gr_run->proto = proto; gr_run->vrf_id = vrf_id; gr_run->instance = instance; + gr_run->restart_time = restart_time; return mq_add_handler(gr_run, rib_meta_queue_gr_run_add); } @@ -4694,6 +4697,10 @@ void rib_sweep_route(struct event *t) struct vrf *vrf; struct zebra_vrf *zvrf; + zrouter.rib_sweep_time = monotime(NULL); + /* TODO: Change to debug */ + zlog_info("Sweeping the RIB for stale routes..."); + RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) { if ((zvrf = vrf->info) == NULL) continue; diff --git a/zebra/zebra_router.c b/zebra/zebra_router.c index 3fd4e6eb1f..8d6b2f3476 100644 --- a/zebra/zebra_router.c +++ b/zebra/zebra_router.c @@ -238,7 +238,7 @@ void zebra_router_terminate(void) { struct zebra_router_table *zrt, *tmp; - EVENT_OFF(zrouter.sweeper); + EVENT_OFF(zrouter.t_rib_sweep); RB_FOREACH_SAFE (zrt, zebra_router_table_head, &zrouter.tables, tmp) zebra_router_free_table(zrt); diff --git a/zebra/zebra_router.h b/zebra/zebra_router.h index 3041707439..c86c6be1ef 100644 --- a/zebra/zebra_router.h +++ b/zebra/zebra_router.h @@ -191,10 +191,16 @@ struct zebra_router { enum multicast_mode ipv4_multicast_mode; /* - * Time for when we sweep the rib from old routes + * zebra start time and time of sweeping RIB of old routes */ time_t startup_time; - struct event *sweeper; + time_t rib_sweep_time; + + /* FRR fast/graceful restart info */ + bool graceful_restart; + int gr_cleanup_time; +#define ZEBRA_GR_DEFAULT_RIB_SWEEP_TIME 500 + struct event *t_rib_sweep; /* * The hash of nexthop groups associated with this router diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index c31218a7c3..858e503031 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -3825,6 +3825,20 @@ DEFUN (show_zebra, struct vrf *vrf; struct ttable *table = ttable_new(&ttable_styles[TTSTYLE_BLANK]); char *out; + char timebuf[MONOTIME_STRLEN]; + + time_to_string(zrouter.startup_time, timebuf); + vty_out(vty, "Zebra started%s at time %s", + zrouter.graceful_restart ? " gracefully" : "", timebuf); + + if (zrouter.t_rib_sweep) + vty_out(vty, + "Zebra RIB sweep timer running, remaining time %lds\n", + event_timer_remain_second(zrouter.t_rib_sweep)); + else { + time_to_string(zrouter.rib_sweep_time, timebuf); + vty_out(vty, "Zebra RIB sweep happened at %s", timebuf); + } ttable_rowseps(table, 0, BOTTOM, true, '-'); ttable_add_row(table, "OS|%s(%s)", cmd_system_get(), cmd_release_get()); diff --git a/zebra/zserv.c b/zebra/zserv.c index 27668534ee..a731f7f278 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -1031,6 +1031,7 @@ static char *zserv_time_buf(time_t *time1, char *buf, int buflen) /* Display client info details */ static void zebra_show_client_detail(struct vty *vty, struct zserv *client) { + struct client_gr_info *info; char cbuf[ZEBRA_TIME_BUF], rbuf[ZEBRA_TIME_BUF]; char wbuf[ZEBRA_TIME_BUF], nhbuf[ZEBRA_TIME_BUF], mbuf[ZEBRA_TIME_BUF]; time_t connect_time, last_read_time, last_write_time; @@ -1125,6 +1126,45 @@ static void zebra_show_client_detail(struct vty *vty, struct zserv *client) vty_out(vty, "ES-EVI %-12u%-12u%-12u\n", client->local_es_evi_add_cnt, 0, client->local_es_evi_del_cnt); vty_out(vty, "Errors: %u\n", client->error_cnt); + + TAILQ_FOREACH (info, &client->gr_info_queue, gr_info) { + afi_t afi; + bool route_sync_done = true; + char timebuf[MONOTIME_STRLEN]; + + vty_out(vty, "VRF : %s\n", vrf_id_to_name(info->vrf_id)); + vty_out(vty, "Capabilities : "); + switch (info->capabilities) { + case ZEBRA_CLIENT_GR_CAPABILITIES: + vty_out(vty, "Graceful Restart\n"); + break; + case ZEBRA_CLIENT_ROUTE_UPDATE_COMPLETE: + case ZEBRA_CLIENT_ROUTE_UPDATE_PENDING: + case ZEBRA_CLIENT_GR_DISABLE: + case ZEBRA_CLIENT_RIB_STALE_TIME: + vty_out(vty, "None\n"); + break; + } + for (afi = AFI_IP; afi < AFI_MAX; afi++) { + if (info->af_enabled[afi]) { + if (info->route_sync[afi]) + vty_out(vty, + "AFI %d enabled, route sync DONE\n", + afi); + else { + vty_out(vty, + "AFI %d enabled, route sync NOT DONE\n", + afi); + route_sync_done = false; + } + } + } + if (route_sync_done) { + time_to_string(info->route_sync_done_time, timebuf); + vty_out(vty, "Route sync finished at %s", timebuf); + } + } + vty_out(vty, "Input Fifo: %zu:%zu Output Fifo: %zu:%zu\n", client->ibuf_fifo->count, client->ibuf_fifo->max_count, client->obuf_fifo->count, client->obuf_fifo->max_count); diff --git a/zebra/zserv.h b/zebra/zserv.h index 57d673060f..87d2b4adbf 100644 --- a/zebra/zserv.h +++ b/zebra/zserv.h @@ -64,6 +64,8 @@ struct client_gr_info { /* Book keeping */ void *stale_client_ptr; struct event *t_stale_removal; + void *client_ptr; + time_t route_sync_done_time; TAILQ_ENTRY(client_gr_info) gr_info; }; From 7bde7a698c416bb4bbfbbc9aee5e52f89257e4cd Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Tue, 2 Jul 2024 17:57:06 +0300 Subject: [PATCH 142/347] tests: Add basic BGP per-safi dampening topotest Signed-off-by: Donatas Abraitis --- .../bgp_dampening_per_safi/__init__.py | 0 .../bgp_dampening_per_safi/r1/frr.conf | 13 ++ .../bgp_dampening_per_safi/r2/frr.conf | 17 ++ .../test_bgp_dampening_per_safi.py | 194 ++++++++++++++++++ 4 files changed, 224 insertions(+) create mode 100644 tests/topotests/bgp_dampening_per_safi/__init__.py create mode 100644 tests/topotests/bgp_dampening_per_safi/r1/frr.conf create mode 100644 tests/topotests/bgp_dampening_per_safi/r2/frr.conf create mode 100644 tests/topotests/bgp_dampening_per_safi/test_bgp_dampening_per_safi.py diff --git a/tests/topotests/bgp_dampening_per_safi/__init__.py b/tests/topotests/bgp_dampening_per_safi/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/topotests/bgp_dampening_per_safi/r1/frr.conf b/tests/topotests/bgp_dampening_per_safi/r1/frr.conf new file mode 100644 index 0000000000..b4e82f581d --- /dev/null +++ b/tests/topotests/bgp_dampening_per_safi/r1/frr.conf @@ -0,0 +1,13 @@ +! +int r1-eth0 + ip address 192.168.1.1/24 +! +router bgp 65001 + no bgp ebgp-requires-policy + neighbor 192.168.1.2 remote-as external + neighbor 192.168.1.2 timers 1 3 + neighbor 192.168.1.2 timers connect 1 + address-family ipv4 unicast + bgp dampening 1 1 1 1 + exit-address-family +! diff --git a/tests/topotests/bgp_dampening_per_safi/r2/frr.conf b/tests/topotests/bgp_dampening_per_safi/r2/frr.conf new file mode 100644 index 0000000000..d68d13d075 --- /dev/null +++ b/tests/topotests/bgp_dampening_per_safi/r2/frr.conf @@ -0,0 +1,17 @@ +! +int lo + ip address 10.10.10.10/32 +! +int r2-eth0 + ip address 192.168.1.2/24 +! +router bgp 65002 + no bgp ebgp-requires-policy + neighbor 192.168.1.1 remote-as external + neighbor 192.168.1.1 timers 1 3 + neighbor 192.168.1.1 timers connect 1 + ! + address-family ipv4 unicast + redistribute connected + exit-address-family +! diff --git a/tests/topotests/bgp_dampening_per_safi/test_bgp_dampening_per_safi.py b/tests/topotests/bgp_dampening_per_safi/test_bgp_dampening_per_safi.py new file mode 100644 index 0000000000..c8d7e675d1 --- /dev/null +++ b/tests/topotests/bgp_dampening_per_safi/test_bgp_dampening_per_safi.py @@ -0,0 +1,194 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# Copyright (c) 2024 by +# Donatas Abraitis +# + +import os +import re +import sys +import json +import pytest +import functools + +pytestmark = [pytest.mark.bgpd] + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +from lib import topotest +from lib.topogen import Topogen, get_topogen + + +def setup_module(mod): + topodef = {"s1": ("r1", "r2")} + tgen = Topogen(topodef, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + + for _, (rname, router) in enumerate(router_list.items(), 1): + router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname))) + + tgen.start_router() + + +def teardown_module(mod): + tgen = get_topogen() + tgen.stop_topology() + + +def test_bgp_dampening_per_peer(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.gears["r1"] + r2 = tgen.gears["r2"] + + def _show_dampening_parameters(): + output = json.loads(r1.vtysh_cmd("show ip bgp dampening parameters json")) + expected = { + "halfLifeSecs": 60, + "reusePenalty": 1, + "suppressPenalty": 1, + "maxSuppressTimeSecs": 60, + "maxSuppressPenalty": 2, + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _show_dampening_parameters, + ) + _, result = topotest.run_and_expect(test_func, None, count=15, wait=1) + assert result is None, "Can't show BGP per-safi dampening parameters" + + def _converge(): + output = json.loads(r1.vtysh_cmd("show bgp ipv4 unicast 10.10.10.10/32 json")) + expected = { + "paths": [ + { + "valid": True, + "nexthops": [ + { + "hostname": "r2", + "accessible": True, + } + ], + } + ] + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _converge, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Can't converge" + + #### + # Withdraw 10.10.10.10/32, and check if it's flagged as history. + #### + r2.vtysh_cmd( + """ + configure terminal + router bgp + address-family ipv4 unicast + no redistribute connected + """ + ) + + def _check_bgp_dampening_history(): + output = json.loads(r1.vtysh_cmd("show bgp ipv4 unicast 10.10.10.10/32 json")) + expected = { + "paths": [ + { + "dampeningHistoryEntry": True, + "nexthops": [ + { + "hostname": "r2", + "accessible": True, + } + ], + } + ], + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _check_bgp_dampening_history, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "10.10.10.10/32 is not flagged as history entry" + + #### + # Reannounce 10.10.10.10/32, and check if it's flagged as dampened. + #### + r2.vtysh_cmd( + """ + configure terminal + router bgp + address-family ipv4 unicast + redistribute connected + """ + ) + + def _check_bgp_dampening_dampened(): + output = json.loads(r1.vtysh_cmd("show bgp ipv4 unicast 10.10.10.10/32 json")) + expected = { + "paths": [ + { + "valid": True, + "dampeningSuppressed": True, + "nexthops": [ + { + "hostname": "r2", + "accessible": True, + } + ], + } + ], + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _check_bgp_dampening_dampened, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "10.10.10.10/32 is not flagged as dampened entry" + + #### + # Check if the route becomes non-dampened again after some time. + #### + def _check_bgp_dampening_undampened(): + output = json.loads(r1.vtysh_cmd("show bgp ipv4 unicast 10.10.10.10/32 json")) + expected = { + "paths": [ + { + "valid": True, + "dampeningHistoryEntry": None, + "dampeningSuppressed": None, + "nexthops": [ + { + "hostname": "r2", + "accessible": True, + } + ], + } + ], + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _check_bgp_dampening_undampened, + ) + _, result = topotest.run_and_expect(test_func, None, count=120, wait=10) + assert result is None, "10.10.10.10/32 is flagged as history/dampened" + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) From c9426177f6b699f43f299e83bd421633028e5bfb Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Tue, 2 Jul 2024 18:35:48 +0300 Subject: [PATCH 143/347] bgpd: Drop memset() before encoding EVPN extended communities memset() is already handled inside the helpers for a particular extended community. Signed-off-by: Donatas Abraitis --- bgpd/bgp_evpn.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index 6680b54f76..e5c7cb3801 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -1161,7 +1161,6 @@ static void build_evpn_route_extcomm(struct bgpevpn *vpn, struct attr *attr, /* Add MAC mobility (sticky) if needed. */ if (attr->sticky) { seqnum = 0; - memset(&ecom_sticky, 0, sizeof(ecom_sticky)); encode_mac_mobility_extcomm(1, seqnum, &eval_sticky); ecom_sticky.size = 1; ecom_sticky.unit_size = ECOMMUNITY_SIZE; @@ -1180,7 +1179,6 @@ static void build_evpn_route_extcomm(struct bgpevpn *vpn, struct attr *attr, /* Add default gateway, if needed. */ if (attr->default_gw) { - memset(&ecom_default_gw, 0, sizeof(ecom_default_gw)); encode_default_gw_extcomm(&eval_default_gw); ecom_default_gw.size = 1; ecom_default_gw.unit_size = ECOMMUNITY_SIZE; @@ -1192,7 +1190,6 @@ static void build_evpn_route_extcomm(struct bgpevpn *vpn, struct attr *attr, proxy = !!(attr->es_flags & ATTR_ES_PROXY_ADVERT); if (attr->router_flag || proxy) { - memset(&ecom_na, 0, sizeof(ecom_na)); encode_na_flag_extcomm(&eval_na, attr->router_flag, proxy); ecom_na.size = 1; ecom_na.unit_size = ECOMMUNITY_SIZE; From bb637fd82990a9c30819335e64ff0574206dc443 Mon Sep 17 00:00:00 2001 From: Y Bharath Date: Wed, 3 Jul 2024 15:57:01 +0530 Subject: [PATCH 144/347] yang: Corrected typo at yang file Corrected typo at yang file Signed-off-by: y-bharath14 --- yang/frr-route-map.yang | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yang/frr-route-map.yang b/yang/frr-route-map.yang index 26d56acc03..c875a6ec7f 100644 --- a/yang/frr-route-map.yang +++ b/yang/frr-route-map.yang @@ -360,16 +360,16 @@ module frr-route-map { case set-min-metric { when "derived-from-or-self(../action, 'set-min-metric')"; - choice minimun-metric-value { + choice minimum-metric-value { description - "Mimimum metric to set or use"; + "Minimum metric to set or use"; case min-metric { leaf min-metric { type uint32 { range "0..4294967295"; } description - "Use the following mimumn metric value"; + "Use the following minimum metric value"; } } } From 266b0619942edd8d838235e14dc0cb71a772f585 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 7 Feb 2024 14:56:15 -0500 Subject: [PATCH 145/347] zebra: Properly note that a nhg's nexthop has gone down Current code when a link is set down is to just mark the nexthop group as not properly setup. Leaving situations where when an interface goes down and show output is entered we see incorrect state. This is true for anything that would be checking those flags at that point in time. Modify the interface down nexthop group code to notice the nexthops appropriately ( and I mean set the appropriate flags ) and to allow a `show ip route` command to actually display what is going on with the nexthops. eva# show ip route 1.0.0.0 Routing entry for 1.0.0.0/32 Known via "sharp", distance 150, metric 0, best Last update 00:00:06 ago * 192.168.44.33, via dummy1, weight 1 * 192.168.45.33, via dummy2, weight 1 sharpd@eva:~/frr1$ sudo ip link set dummy2 down eva# show ip route 1.0.0.0 Routing entry for 1.0.0.0/32 Known via "sharp", distance 150, metric 0, best Last update 00:00:12 ago * 192.168.44.33, via dummy1, weight 1 192.168.45.33, via dummy2 inactive, weight 1 Notice now that the 1.0.0.0/32 route now correctly displays the route for the nexthop group entry. Signed-off-by: Donald Sharp --- .../rt5/step10/show_ip_route.ref | 3 +- zebra/zebra_nhg.c | 28 ++++++++++++++++++- zebra/zebra_vty.c | 2 +- 3 files changed, 29 insertions(+), 4 deletions(-) diff --git a/tests/topotests/isis_tilfa_topo1/rt5/step10/show_ip_route.ref b/tests/topotests/isis_tilfa_topo1/rt5/step10/show_ip_route.ref index 06f432c455..ff8ace25be 100644 --- a/tests/topotests/isis_tilfa_topo1/rt5/step10/show_ip_route.ref +++ b/tests/topotests/isis_tilfa_topo1/rt5/step10/show_ip_route.ref @@ -457,8 +457,7 @@ "fib":true, "ip":"10.0.8.6", "afi":"ipv4", - "interfaceName":"eth-rt6", - "active":true + "interfaceName":"eth-rt6" } ] } diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 55920102bb..b4e25daad8 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -1050,8 +1050,27 @@ static void zebra_nhg_set_valid(struct nhg_hash_entry *nhe, bool valid) } /* Update validity of nexthops depending on it */ - frr_each(nhg_connected_tree, &nhe->nhg_dependents, rb_node_dep) + frr_each (nhg_connected_tree, &nhe->nhg_dependents, rb_node_dep) { + if (!valid) { + /* + * Grab the first nexthop from the depending nexthop group + * then let's find the nexthop in that group that matches + * my individual nexthop and mark it as no longer ACTIVE + */ + struct nexthop *nexthop = rb_node_dep->nhe->nhg.nexthop; + + while (nexthop) { + if (nexthop_same(nexthop, nhe->nhg.nexthop)) + break; + + nexthop = nexthop->next; + } + + if (nexthop) + UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); + } zebra_nhg_set_valid(rb_node_dep->nhe, valid); + } } void zebra_nhg_check_valid(struct nhg_hash_entry *nhe) @@ -1059,6 +1078,13 @@ void zebra_nhg_check_valid(struct nhg_hash_entry *nhe) struct nhg_connected *rb_node_dep = NULL; bool valid = false; + /* + * If I have other nhe's depending on me, then this is a + * singleton nhe so set this nexthops flag as appropriate. + */ + if (nhg_connected_tree_count(&nhe->nhg_depends)) + UNSET_FLAG(nhe->nhg.nexthop->flags, NEXTHOP_FLAG_ACTIVE); + /* If anthing else in the group is valid, the group is valid */ frr_each(nhg_connected_tree, &nhe->nhg_depends, rb_node_dep) { if (CHECK_FLAG(rb_node_dep->nhe->flags, NEXTHOP_GROUP_VALID)) { diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 858e503031..5742c38e23 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -215,7 +215,7 @@ static char re_status_output_char(const struct route_entry *re, if (is_fib) { star_p = !!CHECK_FLAG(nhop->flags, NEXTHOP_FLAG_FIB); - } else + } else if (CHECK_FLAG(nhop->flags, NEXTHOP_FLAG_ACTIVE)) star_p = true; } From 6952bea5cdd38057bf8c0a5e9c0fbe916dc73953 Mon Sep 17 00:00:00 2001 From: Louis Scalbert Date: Fri, 28 Jun 2024 13:22:36 +0200 Subject: [PATCH 146/347] pimd: fix crash on non-existent interface Fix the following crash when pim options are (un)configured on an non-existent interface. > r1(config)# int fgljdsf > r1(config-if)# no ip pim unicast-bsm > vtysh: error reading from pimd: Connection reset by peer (104)Warning: closing connection to pimd because of an I/O error! > #0 raise (sig=) at ../sysdeps/unix/sysv/linux/raise.c:50 > #1 0x00007f70c8f32249 in core_handler (signo=11, siginfo=0x7fffff88e4f0, context=0x7fffff88e3c0) at lib/sigevent.c:258 > #2 > #3 0x0000556cfdd9b16d in lib_interface_pim_address_family_unicast_bsm_modify (args=0x7fffff88f130) at pimd/pim_nb_config.c:1910 > #4 0x00007f70c8efdcb5 in nb_callback_modify (context=0x556d00032b60, nb_node=0x556cffeeb9b0, event=NB_EV_APPLY, dnode=0x556d00031670, resource=0x556d00032b48, errmsg=0x7fffff88f710 "", errmsg_len=8192) > at lib/northbound.c:1538 > #5 0x00007f70c8efe949 in nb_callback_configuration (context=0x556d00032b60, event=NB_EV_APPLY, change=0x556d00032b10, errmsg=0x7fffff88f710 "", errmsg_len=8192) at lib/northbound.c:1888 > #6 0x00007f70c8efee82 in nb_transaction_process (event=NB_EV_APPLY, transaction=0x556d00032b60, errmsg=0x7fffff88f710 "", errmsg_len=8192) at lib/northbound.c:2016 > #7 0x00007f70c8efd658 in nb_candidate_commit_apply (transaction=0x556d00032b60, save_transaction=true, transaction_id=0x0, errmsg=0x7fffff88f710 "", errmsg_len=8192) at lib/northbound.c:1356 > #8 0x00007f70c8efd78e in nb_candidate_commit (context=..., candidate=0x556cffeb0e80, save_transaction=true, comment=0x0, transaction_id=0x0, errmsg=0x7fffff88f710 "", errmsg_len=8192) at lib/northbound.c:1389 > #9 0x00007f70c8f03e58 in nb_cli_classic_commit (vty=0x556d00025a80) at lib/northbound_cli.c:51 > #10 0x00007f70c8f043f8 in nb_cli_apply_changes_internal (vty=0x556d00025a80, > xpath_base=0x7fffff893bb0 "/frr-interface:lib/interface[name='fgljdsf']/frr-pim:pim/address-family[address-family='frr-routing:ipv4']", clear_pending=false) at lib/northbound_cli.c:178 > #11 0x00007f70c8f0475d in nb_cli_apply_changes (vty=0x556d00025a80, xpath_base_fmt=0x556cfdde9fe0 "./frr-pim:pim/address-family[address-family='%s']") at lib/northbound_cli.c:234 > #12 0x0000556cfdd8298f in pim_process_no_unicast_bsm_cmd (vty=0x556d00025a80) at pimd/pim_cmd_common.c:3493 > #13 0x0000556cfddcf782 in no_ip_pim_ucast_bsm (self=0x556cfde40b20 , vty=0x556d00025a80, argc=4, argv=0x556d00031500) at pimd/pim_cmd.c:4950 > #14 0x00007f70c8e942f0 in cmd_execute_command_real (vline=0x556d00032070, vty=0x556d00025a80, cmd=0x0, up_level=0) at lib/command.c:1002 > #15 0x00007f70c8e94451 in cmd_execute_command (vline=0x556d00032070, vty=0x556d00025a80, cmd=0x0, vtysh=0) at lib/command.c:1061 > #16 0x00007f70c8e9499f in cmd_execute (vty=0x556d00025a80, cmd=0x556d00030320 "no ip pim unicast-bsm", matched=0x0, vtysh=0) at lib/command.c:1227 > #17 0x00007f70c8f51e44 in vty_command (vty=0x556d00025a80, buf=0x556d00030320 "no ip pim unicast-bsm") at lib/vty.c:616 > #18 0x00007f70c8f53bdd in vty_execute (vty=0x556d00025a80) at lib/vty.c:1379 > #19 0x00007f70c8f55d59 in vtysh_read (thread=0x7fffff896600) at lib/vty.c:2374 > #20 0x00007f70c8f4b209 in event_call (thread=0x7fffff896600) at lib/event.c:2011 > #21 0x00007f70c8ed109e in frr_run (master=0x556cffdb4ea0) at lib/libfrr.c:1217 > #22 0x0000556cfdddec12 in main (argc=2, argv=0x7fffff896828, envp=0x7fffff896840) at pimd/pim_main.c:165 > (gdb) f 3 > #3 0x0000556cfdd9b16d in lib_interface_pim_address_family_unicast_bsm_modify (args=0x7fffff88f130) at pimd/pim_nb_config.c:1910 > 1910 pim_ifp->ucast_bsm_accept = > (gdb) list > 1905 case NB_EV_ABORT: > 1906 break; > 1907 case NB_EV_APPLY: > 1908 ifp = nb_running_get_entry(args->dnode, NULL, true); > 1909 pim_ifp = ifp->info; > 1910 pim_ifp->ucast_bsm_accept = > 1911 yang_dnode_get_bool(args->dnode, NULL); > 1912 > 1913 break; > 1914 } > (gdb) p pim_ifp > $1 = (struct pim_interface *) 0x0 Fixes: 3bb513c399 ("lib: adapt to version 2 of libyang") Signed-off-by: Louis Scalbert --- pimd/pim_nb_config.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/pimd/pim_nb_config.c b/pimd/pim_nb_config.c index 4f1a4a1852..be0be8588b 100644 --- a/pimd/pim_nb_config.c +++ b/pimd/pim_nb_config.c @@ -1504,11 +1504,19 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_re */ int lib_interface_pim_address_family_create(struct nb_cb_create_args *args) { + struct interface *ifp; + switch (args->event) { case NB_EV_VALIDATE: - case NB_EV_PREPARE: - case NB_EV_ABORT: case NB_EV_APPLY: + case NB_EV_ABORT: + break; + case NB_EV_PREPARE: + ifp = nb_running_get_entry(args->dnode, NULL, true); + if (ifp->info) + return NB_OK; + + pim_if_new(ifp, false, false, false, false); break; } From d4c577e483504d916629dd095d256030884231a7 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Tue, 2 Jul 2024 19:31:14 +0300 Subject: [PATCH 147/347] bgpd: Move sticky, default_gw, router_flag into a single flags variable Instead of using 3 uint8_t variables under struct attr, let's use a single uint8_t as the flags. Saving 2-bytes. Not a big deal, but it's even easier to track EVPN-related flags/variables. Signed-off-by: Donatas Abraitis --- bgpd/bgp_attr.c | 12 ++++------ bgpd/bgp_attr.h | 14 +++++------ bgpd/bgp_attr_evpn.c | 21 ++++++++--------- bgpd/bgp_attr_evpn.h | 8 +++---- bgpd/bgp_evpn.c | 52 ++++++++++++++++++++++------------------- bgpd/bgp_evpn_private.h | 2 +- bgpd/bgp_route.c | 11 ++++++--- 7 files changed, 61 insertions(+), 59 deletions(-) diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 18c7b13535..3eb39d8009 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -2575,7 +2575,6 @@ bgp_attr_ext_communities(struct bgp_attr_parser_args *args) struct peer *const peer = args->peer; struct attr *const attr = args->attr; const bgp_size_t length = args->length; - uint8_t sticky = 0; bool proxy = false; struct ecommunity *ecomm; @@ -2605,21 +2604,20 @@ bgp_attr_ext_communities(struct bgp_attr_parser_args *args) attr->df_pref = bgp_attr_df_pref_from_ec(attr, &attr->df_alg); /* Extract MAC mobility sequence number, if any. */ - attr->mm_seqnum = bgp_attr_mac_mobility_seqnum(attr, &sticky); - attr->sticky = sticky; + attr->mm_seqnum = bgp_attr_mac_mobility_seqnum(attr); /* Check if this is a Gateway MAC-IP advertisement */ - attr->default_gw = bgp_attr_default_gw(attr); + bgp_attr_default_gw(attr); /* Handle scenario where router flag ecommunity is not * set but default gw ext community is present. * Use default gateway, set and propogate R-bit. */ - if (attr->default_gw) - attr->router_flag = 1; + if (CHECK_FLAG(attr->evpn_flags, ATTR_EVPN_FLAG_DEFAULT_GW)) + SET_FLAG(attr->evpn_flags, ATTR_EVPN_FLAG_ROUTER); /* Check EVPN Neighbor advertisement flags, R-bit */ - bgp_attr_evpn_na_flag(attr, &attr->router_flag, &proxy); + bgp_attr_evpn_na_flag(attr, &proxy); if (proxy) attr->es_flags |= ATTR_ES_PROXY_ADVERT; diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h index f353e76913..3519dc3401 100644 --- a/bgpd/bgp_attr.h +++ b/bgpd/bgp_attr.h @@ -197,9 +197,6 @@ struct attr { #define ATTR_ES_L3_NHG_ACTIVE (1 << 6) #define ATTR_ES_L3_NHG (ATTR_ES_L3_NHG_USE | ATTR_ES_L3_NHG_ACTIVE) - /* NA router flag (R-bit) support in EVPN */ - uint8_t router_flag; - /* Distance as applied by Route map */ uint8_t distance; @@ -256,11 +253,12 @@ struct attr { /* MP Nexthop length */ uint8_t mp_nexthop_len; - /* Static MAC for EVPN */ - uint8_t sticky; - - /* Flag for default gateway extended community in EVPN */ - uint8_t default_gw; + /* EVPN flags */ + uint8_t evpn_flags; +#define ATTR_EVPN_FLAG_STICKY (1 << 0) +#define ATTR_EVPN_FLAG_DEFAULT_GW (1 << 1) +/* NA router flag (R-bit) support in EVPN */ +#define ATTR_EVPN_FLAG_ROUTER (1 << 2) /* route tag */ route_tag_t tag; diff --git a/bgpd/bgp_attr_evpn.c b/bgpd/bgp_attr_evpn.c index bbc4ba9525..086c36f36c 100644 --- a/bgpd/bgp_attr_evpn.c +++ b/bgpd/bgp_attr_evpn.c @@ -115,14 +115,14 @@ bool bgp_attr_rmac(struct attr *attr, struct ethaddr *rmac) /* * return true if attr contains default gw extended community */ -uint8_t bgp_attr_default_gw(struct attr *attr) +void bgp_attr_default_gw(struct attr *attr) { struct ecommunity *ecom; uint32_t i; ecom = bgp_attr_get_ecommunity(attr); if (!ecom || !ecom->size) - return 0; + return; /* If there is a default gw extendd community return true otherwise * return 0 */ @@ -136,10 +136,9 @@ uint8_t bgp_attr_default_gw(struct attr *attr) if ((type == ECOMMUNITY_ENCODE_OPAQUE && sub_type == ECOMMUNITY_EVPN_SUBTYPE_DEF_GW)) - return 1; + SET_FLAG(attr->evpn_flags, ATTR_EVPN_FLAG_DEFAULT_GW); } - - return 0; + UNSET_FLAG(attr->evpn_flags, ATTR_EVPN_FLAG_DEFAULT_GW); } /* @@ -183,7 +182,7 @@ uint16_t bgp_attr_df_pref_from_ec(struct attr *attr, uint8_t *alg) * Fetch and return the sequence number from MAC Mobility extended * community, if present, else 0. */ -uint32_t bgp_attr_mac_mobility_seqnum(struct attr *attr, uint8_t *sticky) +uint32_t bgp_attr_mac_mobility_seqnum(struct attr *attr) { struct ecommunity *ecom; uint32_t i; @@ -213,9 +212,9 @@ uint32_t bgp_attr_mac_mobility_seqnum(struct attr *attr, uint8_t *sticky) flags = *pnt++; if (flags & ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY_FLAG_STICKY) - *sticky = 1; + SET_FLAG(attr->evpn_flags, ATTR_EVPN_FLAG_STICKY); else - *sticky = 0; + UNSET_FLAG(attr->evpn_flags, ATTR_EVPN_FLAG_STICKY); pnt++; pnt = ptr_get_be32(pnt, &seq_num); @@ -229,8 +228,7 @@ uint32_t bgp_attr_mac_mobility_seqnum(struct attr *attr, uint8_t *sticky) /* * return true if attr contains router flag extended community */ -void bgp_attr_evpn_na_flag(struct attr *attr, - uint8_t *router_flag, bool *proxy) +void bgp_attr_evpn_na_flag(struct attr *attr, bool *proxy) { struct ecommunity *ecom; uint32_t i; @@ -254,7 +252,8 @@ void bgp_attr_evpn_na_flag(struct attr *attr, val = *pnt++; if (val & ECOMMUNITY_EVPN_SUBTYPE_ND_ROUTER_FLAG) - *router_flag = 1; + SET_FLAG(attr->evpn_flags, + ATTR_EVPN_FLAG_ROUTER); if (val & ECOMMUNITY_EVPN_SUBTYPE_PROXY_FLAG) *proxy = true; diff --git a/bgpd/bgp_attr_evpn.h b/bgpd/bgp_attr_evpn.h index f8d3978b96..e12fc3a86c 100644 --- a/bgpd/bgp_attr_evpn.h +++ b/bgpd/bgp_attr_evpn.h @@ -36,12 +36,10 @@ extern void bgp_add_routermac_ecom(struct attr *attr, extern int bgp_build_evpn_prefix(int type, uint32_t eth_tag, struct prefix *dst); extern bool bgp_attr_rmac(struct attr *attr, struct ethaddr *rmac); -extern uint32_t bgp_attr_mac_mobility_seqnum(struct attr *attr, - uint8_t *sticky); -extern uint8_t bgp_attr_default_gw(struct attr *attr); +extern uint32_t bgp_attr_mac_mobility_seqnum(struct attr *attr); +extern void bgp_attr_default_gw(struct attr *attr); -extern void bgp_attr_evpn_na_flag(struct attr *attr, uint8_t *router_flag, - bool *proxy); +extern void bgp_attr_evpn_na_flag(struct attr *attr, bool *proxy); extern uint16_t bgp_attr_df_pref_from_ec(struct attr *attr, uint8_t *alg); diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index e5c7cb3801..75a7d85e88 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -1159,7 +1159,7 @@ static void build_evpn_route_extcomm(struct bgpevpn *vpn, struct attr *attr, } /* Add MAC mobility (sticky) if needed. */ - if (attr->sticky) { + if (CHECK_FLAG(attr->evpn_flags, ATTR_EVPN_FLAG_STICKY)) { seqnum = 0; encode_mac_mobility_extcomm(1, seqnum, &eval_sticky); ecom_sticky.size = 1; @@ -1178,7 +1178,7 @@ static void build_evpn_route_extcomm(struct bgpevpn *vpn, struct attr *attr, } /* Add default gateway, if needed. */ - if (attr->default_gw) { + if (CHECK_FLAG(attr->evpn_flags, ATTR_EVPN_FLAG_DEFAULT_GW)) { encode_default_gw_extcomm(&eval_default_gw); ecom_default_gw.size = 1; ecom_default_gw.unit_size = ECOMMUNITY_SIZE; @@ -1189,8 +1189,11 @@ static void build_evpn_route_extcomm(struct bgpevpn *vpn, struct attr *attr, } proxy = !!(attr->es_flags & ATTR_ES_PROXY_ADVERT); - if (attr->router_flag || proxy) { - encode_na_flag_extcomm(&eval_na, attr->router_flag, proxy); + if (CHECK_FLAG(attr->evpn_flags, ATTR_EVPN_FLAG_ROUTER) || proxy) { + encode_na_flag_extcomm(&eval_na, + CHECK_FLAG(attr->evpn_flags, + ATTR_EVPN_FLAG_ROUTER), + proxy); ecom_na.size = 1; ecom_na.unit_size = ECOMMUNITY_SIZE; ecom_na.val = (uint8_t *)eval_na.val; @@ -1275,12 +1278,15 @@ enum zclient_send_status evpn_zebra_install(struct bgp *bgp, struct bgpevpn *vpn flags = 0; if (pi->sub_type == BGP_ROUTE_IMPORTED) { - if (pi->attr->sticky) + if (CHECK_FLAG(pi->attr->evpn_flags, + ATTR_EVPN_FLAG_STICKY)) SET_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY); - if (pi->attr->default_gw) + if (CHECK_FLAG(pi->attr->evpn_flags, + ATTR_EVPN_FLAG_DEFAULT_GW)) SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW); if (is_evpn_prefix_ipaddr_v6(p) && - pi->attr->router_flag) + CHECK_FLAG(pi->attr->evpn_flags, + ATTR_EVPN_FLAG_ROUTER)) SET_FLAG(flags, ZEBRA_MACIP_TYPE_ROUTER_FLAG); seq = mac_mobility_seqnum(pi->attr); @@ -1834,7 +1840,8 @@ static void bgp_evpn_get_sync_info(struct bgp *bgp, esi_t *esi, *active_on_peer = true; } - if (second_best_path->attr->router_flag) + if (CHECK_FLAG(second_best_path->attr->evpn_flags, + ATTR_EVPN_FLAG_ROUTER)) *peer_router = true; /* we use both proxy and non-proxy imports to @@ -1934,7 +1941,6 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn, struct attr local_attr; struct bgp_labels bgp_labels = {}; int route_change = 1; - uint8_t sticky = 0; const struct prefix_evpn *evp; *pi = NULL; @@ -1966,9 +1972,7 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn, local_attr = *attr; /* Extract MAC mobility sequence number, if any. */ - local_attr.mm_seqnum = - bgp_attr_mac_mobility_seqnum(&local_attr, &sticky); - local_attr.sticky = sticky; + local_attr.mm_seqnum = bgp_attr_mac_mobility_seqnum(&local_attr); /* Add (or update) attribute to hash. */ attr_new = bgp_attr_intern(&local_attr); @@ -2063,9 +2067,8 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn, BGP_PATH_ATTR_CHANGED); /* Extract MAC mobility sequence number, if any. */ - local_attr.mm_seqnum = bgp_attr_mac_mobility_seqnum( - &local_attr, &sticky); - local_attr.sticky = sticky; + local_attr.mm_seqnum = + bgp_attr_mac_mobility_seqnum(&local_attr); attr_new = bgp_attr_intern(&local_attr); @@ -2198,10 +2201,12 @@ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn, attr.nexthop = vpn->originator_ip; attr.mp_nexthop_global_in = vpn->originator_ip; attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4; - attr.sticky = CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY) ? 1 : 0; - attr.default_gw = CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW) ? 1 : 0; - attr.router_flag = CHECK_FLAG(flags, - ZEBRA_MACIP_TYPE_ROUTER_FLAG) ? 1 : 0; + if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY)) + SET_FLAG(attr.evpn_flags, ATTR_EVPN_FLAG_STICKY); + if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW)) + SET_FLAG(attr.evpn_flags, ATTR_EVPN_FLAG_DEFAULT_GW); + if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_ROUTER_FLAG)) + SET_FLAG(attr.evpn_flags, ATTR_EVPN_FLAG_ROUTER); if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_PROXY_ADVERT)) attr.es_flags |= ATTR_ES_PROXY_ADVERT; @@ -2503,13 +2508,12 @@ void bgp_evpn_update_type2_route_entry(struct bgp *bgp, struct bgpevpn *vpn, attr.nexthop = vpn->originator_ip; attr.mp_nexthop_global_in = vpn->originator_ip; attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4; - attr.sticky = (local_pi->attr->sticky) ? 1 : 0; - attr.router_flag = (local_pi->attr->router_flag) ? 1 : 0; + attr.evpn_flags = local_pi->attr->evpn_flags; attr.es_flags = local_pi->attr->es_flags; - if (local_pi->attr->default_gw) { - attr.default_gw = 1; + if (CHECK_FLAG(local_pi->attr->evpn_flags, ATTR_EVPN_FLAG_DEFAULT_GW)) { + SET_FLAG(attr.evpn_flags, ATTR_EVPN_FLAG_DEFAULT_GW); if (is_evpn_prefix_ipaddr_v6(&evp)) - attr.router_flag = 1; + SET_FLAG(attr.evpn_flags, ATTR_EVPN_FLAG_ROUTER); } memcpy(&attr.esi, &local_pi->attr->esi, sizeof(esi_t)); bgp_evpn_get_rmac_nexthop(vpn, &evp, &attr, diff --git a/bgpd/bgp_evpn_private.h b/bgpd/bgp_evpn_private.h index 07bba9b426..b05df3d82a 100644 --- a/bgpd/bgp_evpn_private.h +++ b/bgpd/bgp_evpn_private.h @@ -382,7 +382,7 @@ static inline void encode_mac_mobility_extcomm(int static_mac, uint32_t seq, } static inline void encode_na_flag_extcomm(struct ecommunity_val *eval, - uint8_t na_flag, bool proxy) + bool na_flag, bool proxy) { memset(eval, 0, sizeof(*eval)); eval->val[0] = ECOMMUNITY_ENCODE_EVPN; diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 6a35935c7e..2a9fc6ce0d 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -851,8 +851,13 @@ int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, * with the * sticky flag. */ - if (newattr->sticky != existattr->sticky) { - if (newattr->sticky && !existattr->sticky) { + bool new_sticky = CHECK_FLAG(newattr->evpn_flags, + ATTR_EVPN_FLAG_STICKY); + bool exist_sticky = CHECK_FLAG(existattr->evpn_flags, + ATTR_EVPN_FLAG_STICKY); + + if (new_sticky != exist_sticky) { + if (new_sticky && !exist_sticky) { *reason = bgp_path_selection_evpn_sticky_mac; if (debug) zlog_debug( @@ -861,7 +866,7 @@ int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, return 1; } - if (!newattr->sticky && existattr->sticky) { + if (!new_sticky && exist_sticky) { *reason = bgp_path_selection_evpn_sticky_mac; if (debug) zlog_debug( From 0dfe25697f5299326046fcfb66f2c6beca7c423c Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Thu, 4 Jul 2024 14:42:19 +0300 Subject: [PATCH 148/347] bgpd: Implement `neighbor X remote-as auto` In some cases (large scale) it's desired to avoid changing configurations, but let the BGP to automatically handle ASN changes. `auto` means the peering can be iBGP or eBGP. It will be automatically detected and adjusted from the OPEN message. Signed-off-by: Donatas Abraitis --- bgpd/bgp_attr.c | 2 + bgpd/bgp_packet.c | 8 ++ bgpd/bgp_updgrp.c | 7 +- bgpd/bgp_vty.c | 62 ++++++--- bgpd/bgpd.c | 25 ++-- bgpd/bgpd.h | 10 +- doc/user/bgp.rst | 6 +- .../topotests/bgp_remote_as_auto/__init__.py | 0 .../topotests/bgp_remote_as_auto/r1/frr.conf | 17 +++ .../topotests/bgp_remote_as_auto/r2/frr.conf | 10 ++ .../topotests/bgp_remote_as_auto/r3/frr.conf | 10 ++ .../test_bgp_remote_as_auto.py | 130 ++++++++++++++++++ 12 files changed, 251 insertions(+), 36 deletions(-) create mode 100644 tests/topotests/bgp_remote_as_auto/__init__.py create mode 100644 tests/topotests/bgp_remote_as_auto/r1/frr.conf create mode 100644 tests/topotests/bgp_remote_as_auto/r2/frr.conf create mode 100644 tests/topotests/bgp_remote_as_auto/r3/frr.conf create mode 100644 tests/topotests/bgp_remote_as_auto/test_bgp_remote_as_auto.py diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 18c7b13535..f2f7cfa93d 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -4468,6 +4468,8 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer, bgp_packet_mpattr_end(s, mpattrlen_pos); } + (void)peer_sort(peer); + /* Origin attribute. */ stream_putc(s, BGP_ATTR_FLAG_TRANS); stream_putc(s, BGP_ATTR_ORIGIN); diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index 9a047b9d45..4625f15778 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -1977,6 +1977,14 @@ static int bgp_open_receive(struct peer_connection *connection, BGP_NOTIFY_OPEN_BAD_PEER_AS, notify_data_remote_as, 2); return BGP_Stop; + } else if (peer->as_type == AS_AUTO) { + if (remote_as == peer->bgp->as) { + peer->as = peer->local_as; + SET_FLAG(peer->as_type, AS_INTERNAL); + } else { + peer->as = remote_as; + SET_FLAG(peer->as_type, AS_EXTERNAL); + } } else if (peer->as_type == AS_INTERNAL) { if (remote_as != peer->bgp->as) { if (bgp_debug_neighbor_events(peer)) diff --git a/bgpd/bgp_updgrp.c b/bgpd/bgp_updgrp.c index 124e7a388b..b717793a45 100644 --- a/bgpd/bgp_updgrp.c +++ b/bgpd/bgp_updgrp.c @@ -343,7 +343,12 @@ static unsigned int updgrp_hash_key_make(const void *p) key = 0; - key = jhash_1word(peer->sort, key); /* EBGP or IBGP */ + /* `remote-as auto` technically uses identical peer->sort. + * After OPEN message is parsed, this is updated accordingly, but + * we need to call the peer_sort() here also to properly create + * separate subgroups. + */ + key = jhash_1word(peer_sort((struct peer *)peer), key); key = jhash_1word(peer->sub_sort, key); /* OAD */ key = jhash_1word((peer->flags & PEER_UPDGRP_FLAGS), key); key = jhash_1word((flags & PEER_UPDGRP_AF_FLAGS), key); diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index e9a79766ec..13911b6879 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -4871,6 +4871,9 @@ static int peer_remote_as_vty(struct vty *vty, const char *peer_str, } else if (as_str[0] == 'e') { as = 0; as_type = AS_EXTERNAL; + } else if (as_str[0] == 'a') { + as = 0; + as_type = AS_AUTO; } else if (!asn_str2asn(as_str, &as)) as_type = AS_UNSPECIFIED; @@ -4976,13 +4979,14 @@ ALIAS(no_bgp_shutdown, no_bgp_shutdown_msg_cmd, DEFUN (neighbor_remote_as, neighbor_remote_as_cmd, - "neighbor remote-as ", + "neighbor remote-as ", NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Specify a BGP neighbor\n" AS_STR "Internal BGP peer\n" - "External BGP peer\n") + "External BGP peer\n" + "Automatically detect remote ASN\n") { int idx_peer = 1; int idx_remote_as = 3; @@ -5054,6 +5058,8 @@ static int peer_conf_interface_get(struct vty *vty, const char *conf_if, as_type = AS_INTERNAL; } else if (as_str[0] == 'e') { as_type = AS_EXTERNAL; + } else if (as_str[0] == 'a') { + as_type = AS_AUTO; } else { /* Get AS number. */ if (asn_str2asn(as_str, &as)) @@ -5170,14 +5176,15 @@ DEFUN (neighbor_interface_config_v6only, DEFUN (neighbor_interface_config_remote_as, neighbor_interface_config_remote_as_cmd, - "neighbor WORD interface remote-as ", + "neighbor WORD interface remote-as ", NEIGHBOR_STR "Interface name or neighbor tag\n" "Enable BGP on interface\n" "Specify a BGP neighbor\n" AS_STR "Internal BGP peer\n" - "External BGP peer\n") + "External BGP peer\n" + "Automatically detect remote ASN\n") { int idx_word = 1; int idx_remote_as = 4; @@ -5187,7 +5194,7 @@ DEFUN (neighbor_interface_config_remote_as, DEFUN (neighbor_interface_v6only_config_remote_as, neighbor_interface_v6only_config_remote_as_cmd, - "neighbor WORD interface v6only remote-as ", + "neighbor WORD interface v6only remote-as ", NEIGHBOR_STR "Interface name or neighbor tag\n" "Enable BGP with v6 link-local only\n" @@ -5195,7 +5202,8 @@ DEFUN (neighbor_interface_v6only_config_remote_as, "Specify a BGP neighbor\n" AS_STR "Internal BGP peer\n" - "External BGP peer\n") + "External BGP peer\n" + "Automatically detect remote ASN\n") { int idx_word = 1; int idx_remote_as = 5; @@ -5232,14 +5240,15 @@ DEFUN (neighbor_peer_group, DEFUN (no_neighbor, no_neighbor_cmd, - "no neighbor [remote-as <(1-4294967295)|internal|external>]>", + "no neighbor [remote-as <(1-4294967295)|internal|external|auto>]>", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Specify a BGP neighbor\n" AS_STR "Internal BGP peer\n" - "External BGP peer\n") + "External BGP peer\n" + "Automatically detect remote ASN\n") { VTY_DECLVAR_CONTEXT(bgp, bgp); int idx_peer = 2; @@ -5310,7 +5319,7 @@ DEFUN (no_neighbor, DEFUN (no_neighbor_interface_config, no_neighbor_interface_config_cmd, - "no neighbor WORD interface [v6only] [peer-group PGNAME] [remote-as <(1-4294967295)|internal|external>]", + "no neighbor WORD interface [v6only] [peer-group PGNAME] [remote-as <(1-4294967295)|internal|external|auto>]", NO_STR NEIGHBOR_STR "Interface name\n" @@ -5321,7 +5330,8 @@ DEFUN (no_neighbor_interface_config, "Specify a BGP neighbor\n" AS_STR "Internal BGP peer\n" - "External BGP peer\n") + "External BGP peer\n" + "Automatically detect remote ASN\n") { VTY_DECLVAR_CONTEXT(bgp, bgp); int idx_word = 2; @@ -5378,14 +5388,15 @@ DEFUN (no_neighbor_peer_group, DEFUN (no_neighbor_interface_peer_group_remote_as, no_neighbor_interface_peer_group_remote_as_cmd, - "no neighbor WORD remote-as ", + "no neighbor WORD remote-as ", NO_STR NEIGHBOR_STR "Interface name or neighbor tag\n" "Specify a BGP neighbor\n" AS_STR "Internal BGP peer\n" - "External BGP peer\n") + "External BGP peer\n" + "Automatically detect remote ASN\n") { VTY_DECLVAR_CONTEXT(bgp, bgp); int idx_word = 2; @@ -11887,7 +11898,7 @@ static bool bgp_show_summary_is_peer_filtered(struct peer *peer, /* filter remote-as (internal|external) */ if (as_type != AS_UNSPECIFIED) { if (peer->as_type == AS_SPECIFIED) { - if (as_type == AS_INTERNAL) { + if (CHECK_FLAG(as_type, AS_INTERNAL)) { if (peer->as != peer->local_as) return true; } else if (peer->as == peer->local_as) @@ -12879,6 +12890,8 @@ DEFPY(show_ip_bgp_summary, show_ip_bgp_summary_cmd, as_type = AS_INTERNAL; else if (argv[idx + 1]->arg[0] == 'e') as_type = AS_EXTERNAL; + else if (argv[idx + 1]->arg[0] == 'a') + as_type = AS_AUTO; else if (!asn_str2asn(argv[idx + 1]->arg, &as)) { vty_out(vty, "%% Invalid neighbor remote-as value: %s\n", @@ -14002,9 +14015,10 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json, json_object_boolean_true_add(json_neigh, "localAsReplaceAs"); } else { - if ((p->as_type == AS_SPECIFIED) || - (p->as_type == AS_EXTERNAL) || - (p->as_type == AS_INTERNAL)) { + if (p->as_type == AS_SPECIFIED || + CHECK_FLAG(p->as_type, AS_AUTO) || + CHECK_FLAG(p->as_type, AS_EXTERNAL) || + CHECK_FLAG(p->as_type, AS_INTERNAL)) { vty_out(vty, "remote AS "); vty_out(vty, ASN_FORMAT(bgp->asnotation), &p->as); vty_out(vty, ", "); @@ -14023,7 +14037,7 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json, : ""); } /* peer type internal or confed-internal */ - if ((p->as == p->local_as) || (p->as_type == AS_INTERNAL)) { + if ((p->as == p->local_as) || (CHECK_FLAG(p->as_type, AS_INTERNAL))) { if (use_json) { if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION)) json_object_boolean_true_add( @@ -17011,7 +17025,7 @@ static int bgp_show_one_peer_group(struct vty *vty, struct peer_group *group, &conf->as); vty_out(vty, "\n"); } - } else if (conf->as_type == AS_INTERNAL) { + } else if (CHECK_FLAG(conf->as_type, AS_INTERNAL)) { if (json) asn_asn2json(json, "remoteAs", group->bgp->as, group->bgp->asnotation); @@ -17023,7 +17037,8 @@ static int bgp_show_one_peer_group(struct vty *vty, struct peer_group *group, vty_out(vty, "\nBGP peer-group %s\n", group->name); } - if ((group->bgp->as == conf->as) || (conf->as_type == AS_INTERNAL)) { + if ((group->bgp->as == conf->as) || + CHECK_FLAG(conf->as_type, AS_INTERNAL)) { if (json) json_object_string_add(json_peer_group, "type", "internal"); @@ -18525,6 +18540,9 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp, } else if (peer->as_type == AS_EXTERNAL) { vty_out(vty, " remote-as external"); if_ras_printed = true; + } else if (CHECK_FLAG(peer->as_type, AS_AUTO)) { + vty_out(vty, " remote-as auto"); + if_ras_printed = true; } vty_out(vty, "\n"); @@ -18547,6 +18565,9 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp, vty_out(vty, " neighbor %s remote-as external\n", addr); + } else if (CHECK_FLAG(peer->as_type, AS_AUTO)) { + vty_out(vty, " neighbor %s remote-as auto\n", + addr); } } @@ -18576,6 +18597,9 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp, vty_out(vty, " neighbor %s remote-as external\n", addr); + } else if (CHECK_FLAG(peer->as_type, AS_AUTO)) { + vty_out(vty, " neighbor %s remote-as auto\n", + addr); } } } diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 17d94bd575..ca752da6b4 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -1074,10 +1074,10 @@ static inline enum bgp_peer_sort peer_calc_sort(struct peer *peer) /* Peer-group */ if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { - if (peer->as_type == AS_INTERNAL) + if (CHECK_FLAG(peer->as_type, AS_INTERNAL)) return BGP_PEER_IBGP; - else if (peer->as_type == AS_EXTERNAL) + if (CHECK_FLAG(peer->as_type, AS_EXTERNAL)) return BGP_PEER_EBGP; else if (peer->as_type == AS_SPECIFIED && peer->as) { @@ -1132,17 +1132,20 @@ static inline enum bgp_peer_sort peer_calc_sort(struct peer *peer) return BGP_PEER_IBGP; else return BGP_PEER_EBGP; - } else if (peer->group->conf->as_type - == AS_INTERNAL) + } else if (CHECK_FLAG(peer->group->conf->as_type, + AS_INTERNAL)) return BGP_PEER_IBGP; else return BGP_PEER_EBGP; } /* no AS information anywhere, let caller know */ return BGP_PEER_UNSPECIFIED; - } else if (peer->as_type != AS_SPECIFIED) - return (peer->as_type == AS_INTERNAL ? BGP_PEER_IBGP - : BGP_PEER_EBGP); + } else if (peer->as_type != AS_SPECIFIED) { + if (CHECK_FLAG(peer->as_type, AS_INTERNAL)) + return BGP_PEER_IBGP; + else if (CHECK_FLAG(peer->as_type, AS_EXTERNAL)) + return BGP_PEER_EBGP; + } return (local_as == 0 ? BGP_PEER_INTERNAL : local_as == peer->as ? BGP_PEER_IBGP @@ -2201,10 +2204,10 @@ int peer_remote_as(struct bgp *bgp, union sockunion *su, const char *conf_if, } } else { /* internal/external used, compare as-types */ - if (((peer_sort_type == BGP_PEER_IBGP) - && (as_type != AS_INTERNAL)) - || ((peer_sort_type == BGP_PEER_EBGP) - && (as_type != AS_EXTERNAL))) { + if (((peer_sort_type == BGP_PEER_IBGP) && + !CHECK_FLAG(as_type, AS_INTERNAL)) || + ((peer_sort_type == BGP_PEER_EBGP) && + !CHECK_FLAG(as_type, AS_EXTERNAL))) { *as = peer->as; return BGP_ERR_PEER_GROUP_PEER_TYPE_DIFFERENT; } diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 3c5826113d..709411b06e 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -56,10 +56,12 @@ struct bgp_pbr_config; * behavior * in the system. */ -enum { AS_UNSPECIFIED = 0, - AS_SPECIFIED, - AS_INTERNAL, - AS_EXTERNAL, +enum peer_asn_type { + AS_UNSPECIFIED = 1, + AS_SPECIFIED = 2, + AS_INTERNAL = 4, + AS_EXTERNAL = 8, + AS_AUTO = 16, }; /* Zebra Gracaful Restart states */ diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst index 98834c7c23..a569a9af28 100644 --- a/doc/user/bgp.rst +++ b/doc/user/bgp.rst @@ -1561,6 +1561,10 @@ Defining Peers peers ASN is the same as mine as specified under the :clicmd:`router bgp ASN` command the connection will be denied. +.. clicmd:: neighbor PEER remote-as auto + + The neighbor's ASN is detected automatically from the OPEN message. + .. clicmd:: neighbor PEER oad Mark a peer belonging to the One Administrative Domain. @@ -1699,7 +1703,7 @@ Configuring Peers IPv4 session addresses, see the ``neighbor PEER update-source`` command below. -.. clicmd:: neighbor PEER interface remote-as +.. clicmd:: neighbor PEER interface remote-as Configure an unnumbered BGP peer. ``PEER`` should be an interface name. The session will be established via IPv6 link locals. Use ``internal`` for iBGP diff --git a/tests/topotests/bgp_remote_as_auto/__init__.py b/tests/topotests/bgp_remote_as_auto/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/topotests/bgp_remote_as_auto/r1/frr.conf b/tests/topotests/bgp_remote_as_auto/r1/frr.conf new file mode 100644 index 0000000000..aec0e76a3f --- /dev/null +++ b/tests/topotests/bgp_remote_as_auto/r1/frr.conf @@ -0,0 +1,17 @@ +! +int r1-eth0 + ip address 192.168.1.1/24 +! +router bgp 65001 + no bgp ebgp-requires-policy + no bgp network import-check + neighbor 192.168.1.2 remote-as auto + neighbor 192.168.1.2 timers 1 3 + neighbor 192.168.1.2 timers connect 1 + neighbor 192.168.1.3 remote-as auto + neighbor 192.168.1.3 timers 1 3 + neighbor 192.168.1.3 timers connect 1 + address-family ipv4 unicast + network 10.0.0.1/32 + exit-address-family +! diff --git a/tests/topotests/bgp_remote_as_auto/r2/frr.conf b/tests/topotests/bgp_remote_as_auto/r2/frr.conf new file mode 100644 index 0000000000..f8d19a0bfd --- /dev/null +++ b/tests/topotests/bgp_remote_as_auto/r2/frr.conf @@ -0,0 +1,10 @@ +! +int r2-eth0 + ip address 192.168.1.2/24 +! +router bgp 65001 + no bgp ebgp-requires-policy + neighbor 192.168.1.1 remote-as auto + neighbor 192.168.1.1 timers 1 3 + neighbor 192.168.1.1 timers connect 1 +! diff --git a/tests/topotests/bgp_remote_as_auto/r3/frr.conf b/tests/topotests/bgp_remote_as_auto/r3/frr.conf new file mode 100644 index 0000000000..fc6862764f --- /dev/null +++ b/tests/topotests/bgp_remote_as_auto/r3/frr.conf @@ -0,0 +1,10 @@ +! +int r3-eth0 + ip address 192.168.1.3/24 +! +router bgp 65003 + no bgp ebgp-requires-policy + neighbor 192.168.1.1 remote-as auto + neighbor 192.168.1.1 timers 1 3 + neighbor 192.168.1.1 timers connect 1 +! diff --git a/tests/topotests/bgp_remote_as_auto/test_bgp_remote_as_auto.py b/tests/topotests/bgp_remote_as_auto/test_bgp_remote_as_auto.py new file mode 100644 index 0000000000..b932920e09 --- /dev/null +++ b/tests/topotests/bgp_remote_as_auto/test_bgp_remote_as_auto.py @@ -0,0 +1,130 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# Copyright (c) 2024 by +# Donatas Abraitis +# + +import os +import re +import sys +import json +import pytest +import functools + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +from lib import topotest +from lib.topogen import Topogen, get_topogen + +pytestmark = [pytest.mark.bgpd] + + +def setup_module(mod): + topodef = {"s1": ("r1", "r2", "r3")} + tgen = Topogen(topodef, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + + for _, (rname, router) in enumerate(router_list.items(), 1): + router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname))) + + tgen.start_router() + + +def teardown_module(mod): + tgen = get_topogen() + tgen.stop_topology() + + +def test_bgp_remote_as_auto(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.gears["r1"] + r2 = tgen.gears["r2"] + r3 = tgen.gears["r3"] + + def _bgp_converge(): + output = json.loads(r1.vtysh_cmd("show bgp ipv4 unicast summary json")) + expected = { + "peers": { + "192.168.1.2": { + "hostname": "r2", + "remoteAs": 65001, + "localAs": 65001, + "state": "Established", + }, + "192.168.1.3": { + "hostname": "r3", + "remoteAs": 65003, + "localAs": 65001, + "state": "Established", + }, + } + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _bgp_converge, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Can't see automatic iBGP/eBGP peerings" + + def _bgp_converge_internal(): + output = json.loads(r2.vtysh_cmd("show bgp ipv4 unicast 10.0.0.1/32 json")) + expected = { + "paths": [ + { + "aspath": { + "string": "Local", + }, + "valid": True, + "peer": { + "hostname": "r1", + "type": "internal", + }, + } + ] + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _bgp_converge_internal, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Can't see automatic iBGP peering" + + def _bgp_converge_external(): + output = json.loads(r3.vtysh_cmd("show bgp ipv4 unicast 10.0.0.1/32 json")) + expected = { + "paths": [ + { + "aspath": { + "string": "65001", + }, + "valid": True, + "peer": { + "hostname": "r1", + "type": "external", + }, + } + ] + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _bgp_converge_external, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Can't see automatic eBGP peering" + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) From 7f2a9114af2584c420f8c98072693b9ce2cad859 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Tue, 18 Jun 2024 17:40:08 +0200 Subject: [PATCH 149/347] sharpd: fix set ZAPI_MESSAGE_NEXTHOP in nhg only when nexthops used The ZAPI_MESSAGE_NEXTHOP flag is systematically set, even if the route message does not include any nexthops. Limit the usage of this value only when nexthops are present. Fixes: 8a71d93d85a6 ("sharpd: Add Super Happy Advanced Routing Protocol") Signed-off-by: Philippe Guibert --- sharpd/sharp_zebra.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sharpd/sharp_zebra.c b/sharpd/sharp_zebra.c index 133da918fa..1048436b43 100644 --- a/sharpd/sharp_zebra.c +++ b/sharpd/sharp_zebra.c @@ -247,12 +247,12 @@ static bool route_add(const struct prefix *p, vrf_id_t vrf_id, uint8_t instance, memcpy(&api.prefix, p, sizeof(*p)); api.flags = flags; - SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); /* Only send via ID if nhgroup has been successfully installed */ if (nhgid && sharp_nhgroup_id_is_installed(nhgid)) { zapi_route_set_nhg_id(&api, &nhgid); } else { + SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); for (ALL_NEXTHOPS_PTR(nhg, nh)) { /* Check if we set a VNI label */ if (nh->nh_label && From 0ed36e44f8bf3c866d99ec549f7ed041af62e8a5 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Thu, 4 Jul 2024 23:07:01 +0300 Subject: [PATCH 150/347] bgpd: Convert int to enum peer_asn_type Signed-off-by: Donatas Abraitis --- bgpd/bgp_evpn_vty.c | 2 +- bgpd/bgp_vty.c | 23 ++++++++++++----------- bgpd/bgp_vty.h | 5 +++-- bgpd/bgpd.c | 12 ++++++------ bgpd/bgpd.h | 17 +++++++++-------- 5 files changed, 31 insertions(+), 28 deletions(-) diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c index 846a82ba90..c28cdb4a65 100644 --- a/bgpd/bgp_evpn_vty.c +++ b/bgpd/bgp_evpn_vty.c @@ -4840,7 +4840,7 @@ DEFUN(show_bgp_l2vpn_evpn_summary, show_bgp_l2vpn_evpn_summary_cmd, char *vrf = NULL; char *neighbor = NULL; as_t as = 0; /* 0 means AS filter not set */ - int as_type = AS_UNSPECIFIED; + enum peer_asn_type as_type = AS_UNSPECIFIED; uint16_t show_flags = 0; if (argv_find(argv, argc, "vrf", &idx_vrf)) diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 13911b6879..0ef1351835 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -4862,7 +4862,7 @@ static int peer_remote_as_vty(struct vty *vty, const char *peer_str, VTY_DECLVAR_CONTEXT(bgp, bgp); int ret; as_t as; - int as_type = AS_SPECIFIED; + enum peer_asn_type as_type = AS_SPECIFIED; union sockunion su; if (as_str[0] == 'i') { @@ -5041,7 +5041,7 @@ static int peer_conf_interface_get(struct vty *vty, const char *conf_if, { VTY_DECLVAR_CONTEXT(bgp, bgp); as_t as = 0; - int as_type = AS_UNSPECIFIED; + enum peer_asn_type as_type = AS_UNSPECIFIED; struct peer *peer; struct peer_group *group; int ret = 0; @@ -11887,7 +11887,8 @@ static char *bgp_peer_description_stripped(char *desc, uint32_t size) /* Determine whether var peer should be filtered out of the summary. */ static bool bgp_show_summary_is_peer_filtered(struct peer *peer, - struct peer *fpeer, int as_type, + struct peer *fpeer, + enum peer_asn_type as_type, as_t as) { @@ -11921,8 +11922,8 @@ static bool bgp_show_summary_is_peer_filtered(struct peer *peer, * whitespaces and the whole output will be tricky. */ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi, - struct peer *fpeer, int as_type, as_t as, - uint16_t show_flags) + struct peer *fpeer, enum peer_asn_type as_type, + as_t as, uint16_t show_flags) { struct peer *peer; struct listnode *node, *nnode; @@ -12729,10 +12730,9 @@ static void bgp_show_summary_afi_safi(struct vty *vty, struct bgp *bgp, int afi, } static void bgp_show_all_instances_summary_vty(struct vty *vty, afi_t afi, - safi_t safi, - const char *neighbor, - int as_type, as_t as, - uint16_t show_flags) + safi_t safi, const char *neighbor, + enum peer_asn_type as_type, + as_t as, uint16_t show_flags) { struct listnode *node, *nnode; struct bgp *bgp; @@ -12774,8 +12774,9 @@ static void bgp_show_all_instances_summary_vty(struct vty *vty, afi_t afi, } int bgp_show_summary_vty(struct vty *vty, const char *name, afi_t afi, - safi_t safi, const char *neighbor, int as_type, - as_t as, uint16_t show_flags) + safi_t safi, const char *neighbor, + enum peer_asn_type as_type, as_t as, + uint16_t show_flags) { struct bgp *bgp; bool use_json = CHECK_FLAG(show_flags, BGP_SHOW_OPT_JSON); diff --git a/bgpd/bgp_vty.h b/bgpd/bgp_vty.h index 6d86f6ba08..f88f5c8125 100644 --- a/bgpd/bgp_vty.h +++ b/bgpd/bgp_vty.h @@ -161,8 +161,9 @@ extern int bgp_vty_find_and_parse_afi_safi_bgp(struct vty *vty, int bgp_vty_find_and_parse_bgp(struct vty *vty, struct cmd_token **argv, int argc, struct bgp **bgp, bool use_json); extern int bgp_show_summary_vty(struct vty *vty, const char *name, afi_t afi, - safi_t safi, const char *neighbor, int as_type, - as_t as, uint16_t show_flags); + safi_t safi, const char *neighbor, + enum peer_asn_type as_type, as_t as, + uint16_t show_flags); extern bool peergroup_flag_check(struct peer *peer, uint64_t flag); extern bool peergroup_af_flag_check(struct peer *peer, afi_t afi, safi_t safi, uint64_t flag); diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index ca752da6b4..3810413adc 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -1952,7 +1952,7 @@ void bgp_recalculate_all_bestpaths(struct bgp *bgp) */ struct peer *peer_create(union sockunion *su, const char *conf_if, struct bgp *bgp, as_t local_as, as_t remote_as, - int as_type, struct peer_group *group, + enum peer_asn_type as_type, struct peer_group *group, bool config_node, const char *as_str) { int active; @@ -2084,7 +2084,7 @@ bool bgp_afi_safi_peer_exists(struct bgp *bgp, afi_t afi, safi_t safi) } /* Change peer's AS number. */ -void peer_as_change(struct peer *peer, as_t as, int as_specified, +void peer_as_change(struct peer *peer, as_t as, enum peer_asn_type as_type, const char *as_str) { enum bgp_peer_sort origtype, newtype; @@ -2100,13 +2100,13 @@ void peer_as_change(struct peer *peer, as_t as, int as_specified, } origtype = peer_sort_lookup(peer); peer->as = as; - if (as_specified == AS_SPECIFIED && as_str) { + if (as_type == AS_SPECIFIED && as_str) { if (peer->as_pretty) XFREE(MTYPE_BGP_NAME, peer->as_pretty); peer->as_pretty = XSTRDUP(MTYPE_BGP_NAME, as_str); } else if (peer->as_type == AS_UNSPECIFIED && peer->as_pretty) XFREE(MTYPE_BGP_NAME, peer->as_pretty); - peer->as_type = as_specified; + peer->as_type = as_type; if (bgp_config_check(peer->bgp, BGP_CONFIG_CONFEDERATION) && !bgp_confederation_peers_check(peer->bgp, as) @@ -2163,7 +2163,7 @@ void peer_as_change(struct peer *peer, as_t as, int as_specified, /* If peer does not exist, create new one. If peer already exists, set AS number to the peer. */ int peer_remote_as(struct bgp *bgp, union sockunion *su, const char *conf_if, - as_t *as, int as_type, const char *as_str) + as_t *as, enum peer_asn_type as_type, const char *as_str) { struct peer *peer; as_t local_as; @@ -3028,7 +3028,7 @@ static void peer_group2peer_config_copy(struct peer_group *group, /* Peer group's remote AS configuration. */ int peer_group_remote_as(struct bgp *bgp, const char *group_name, as_t *as, - int as_type, const char *as_str) + enum peer_asn_type as_type, const char *as_str) { struct peer_group *group; struct peer *peer; diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 709411b06e..95ddba4cdd 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -1248,7 +1248,7 @@ struct peer { struct peer_af *peer_af_array[BGP_AF_MAX]; /* Peer's remote AS number. */ - int as_type; + enum peer_asn_type as_type; as_t as; /* for vty as format */ char *as_pretty; @@ -2283,8 +2283,9 @@ extern bool peer_afc_advertised(struct peer *peer); extern void bgp_recalculate_all_bestpaths(struct bgp *bgp); extern struct peer *peer_create(union sockunion *su, const char *conf_if, struct bgp *bgp, as_t local_as, as_t remote_as, - int as_type, struct peer_group *group, - bool config_node, const char *as_str); + enum peer_asn_type as_type, + struct peer_group *group, bool config_node, + const char *as_str); extern struct peer *peer_create_accept(struct bgp *); extern void peer_xfer_config(struct peer *dst, struct peer *src); extern char *peer_uptime(time_t uptime2, char *buf, size_t len, bool use_json, @@ -2357,13 +2358,13 @@ extern void bgp_listen_limit_unset(struct bgp *bgp); extern bool bgp_update_delay_active(struct bgp *); extern bool bgp_update_delay_configured(struct bgp *); extern bool bgp_afi_safi_peer_exists(struct bgp *bgp, afi_t afi, safi_t safi); -extern void peer_as_change(struct peer *peer, as_t as, int as_type, - const char *as_str); +extern void peer_as_change(struct peer *peer, as_t as, + enum peer_asn_type as_type, const char *as_str); extern int peer_remote_as(struct bgp *bgp, union sockunion *su, - const char *conf_if, as_t *as, int as_type, - const char *as_str); + const char *conf_if, as_t *as, + enum peer_asn_type as_type, const char *as_str); extern int peer_group_remote_as(struct bgp *bgp, const char *peer_str, as_t *as, - int as_type, const char *as_str); + enum peer_asn_type as_type, const char *as_str); extern int peer_delete(struct peer *peer); extern void peer_notify_unconfig(struct peer *peer); extern int peer_group_delete(struct peer_group *); From 2aa27ac0e935286ef8ee1f3d8f3dd12960683810 Mon Sep 17 00:00:00 2001 From: anlan_cs Date: Sun, 16 Jun 2024 13:20:00 +0800 Subject: [PATCH 151/347] ripngd: adjust header for display command Both rip and ripng can import routes from other protocols, e.g. ISIS. But their header doesn't list the description for these abbreviations. Adjust `show ipv6 ripng` 's header for display command. Before: ``` Codes: R - RIPng, C - connected, S - Static, O - OSPF, B - BGP Sub-codes: ``` After: ``` Codes: K - kernel route, C - connected, L - local, S - static, R - RIPng, O - OSPF, I - IS-IS, B - BGP, E - EIGRP, N - NHRP, T - Table, v - VNC, V - VNC-Direct, A - Babel, F - PBR, f - OpenFabric, t - Table-Direct Sub-codes: ``` Signed-off-by: anlan_cs --- ripngd/ripngd.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ripngd/ripngd.c b/ripngd/ripngd.c index f4dadf377d..0aa2a9e486 100644 --- a/ripngd/ripngd.c +++ b/ripngd/ripngd.c @@ -2070,7 +2070,10 @@ DEFUN (show_ipv6_ripng, /* Header of display. */ vty_out(vty, - "Codes: R - RIPng, C - connected, S - Static, O - OSPF, B - BGP\n" + "Codes: K - kernel route, C - connected, L - local, S - static,\n" + " R - RIPng, O - OSPF, I - IS-IS, B - BGP, E - EIGRP, N - NHRP,\n" + " T - Table, v - VNC, V - VNC-Direct, A - Babel, F - PBR,\n" + " f - OpenFabric, t - Table-Direct\n" "Sub-codes:\n" " (n) - normal, (s) - static, (d) - default, (r) - redistribute,\n" " (i) - interface, (a/S) - aggregated/Suppressed\n\n" From c0b6095856072604cf7da5864d349a56ec37b272 Mon Sep 17 00:00:00 2001 From: anlan_cs Date: Tue, 25 Jun 2024 14:32:44 +0800 Subject: [PATCH 152/347] ripd: adjust header for display command Continue to adjust `show ip rip` 's header for display comand. Signed-off-by: anlan_cs --- ripd/ripd.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ripd/ripd.c b/ripd/ripd.c index ab4ffe5a92..8768819fe2 100644 --- a/ripd/ripd.c +++ b/ripd/ripd.c @@ -3054,7 +3054,10 @@ DEFUN (show_ip_rip, } vty_out(vty, - "Codes: R - RIP, C - connected, S - Static, O - OSPF, B - BGP\n" + "Codes: K - kernel route, C - connected, L - local, S - static,\n" + " R - RIP, O - OSPF, I - IS-IS, B - BGP, E - EIGRP, N - NHRP,\n" + " T - Table, v - VNC, V - VNC-Direct, A - Babel, F - PBR,\n" + " f - OpenFabric, t - Table-Direct\n" "Sub-codes:\n" " (n) - normal, (s) - static, (d) - default, (r) - redistribute,\n" " (i) - interface\n\n" From b707ed8fe9d6e127372dcc94e79e060f866fc528 Mon Sep 17 00:00:00 2001 From: anlan_cs Date: Thu, 4 Jul 2024 21:23:08 +0800 Subject: [PATCH 153/347] tests: update tests for ripd and ripngd Since the displayed header of "show ip rip" and "show ipv6 ripng" are changed, we should update tests of ripd and ripngd. Signed-off-by: anlan_cs --- tests/topotests/rip_topo1/r1/show_ip_rip.ref | 5 ++++- tests/topotests/rip_topo1/r2/show_ip_rip.ref | 5 ++++- tests/topotests/rip_topo1/r3/show_ip_rip.ref | 5 ++++- tests/topotests/ripng_topo1/r1/show_ipv6_ripng.ref | 5 ++++- tests/topotests/ripng_topo1/r2/show_ipv6_ripng.ref | 5 ++++- tests/topotests/ripng_topo1/r3/show_ipv6_ripng.ref | 5 ++++- 6 files changed, 24 insertions(+), 6 deletions(-) diff --git a/tests/topotests/rip_topo1/r1/show_ip_rip.ref b/tests/topotests/rip_topo1/r1/show_ip_rip.ref index a0b77c886e..b49a042dac 100644 --- a/tests/topotests/rip_topo1/r1/show_ip_rip.ref +++ b/tests/topotests/rip_topo1/r1/show_ip_rip.ref @@ -1,4 +1,7 @@ -Codes: R - RIP, C - connected, S - Static, O - OSPF, B - BGP +Codes: K - kernel route, C - connected, L - local, S - static, + R - RIP, O - OSPF, I - IS-IS, B - BGP, E - EIGRP, N - NHRP, + T - Table, v - VNC, V - VNC-Direct, A - Babel, F - PBR, + f - OpenFabric, t - Table-Direct Sub-codes: (n) - normal, (s) - static, (d) - default, (r) - redistribute, (i) - interface diff --git a/tests/topotests/rip_topo1/r2/show_ip_rip.ref b/tests/topotests/rip_topo1/r2/show_ip_rip.ref index b61fb45eac..d0e7e81bc5 100644 --- a/tests/topotests/rip_topo1/r2/show_ip_rip.ref +++ b/tests/topotests/rip_topo1/r2/show_ip_rip.ref @@ -1,4 +1,7 @@ -Codes: R - RIP, C - connected, S - Static, O - OSPF, B - BGP +Codes: K - kernel route, C - connected, L - local, S - static, + R - RIP, O - OSPF, I - IS-IS, B - BGP, E - EIGRP, N - NHRP, + T - Table, v - VNC, V - VNC-Direct, A - Babel, F - PBR, + f - OpenFabric, t - Table-Direct Sub-codes: (n) - normal, (s) - static, (d) - default, (r) - redistribute, (i) - interface diff --git a/tests/topotests/rip_topo1/r3/show_ip_rip.ref b/tests/topotests/rip_topo1/r3/show_ip_rip.ref index 1df299b5e6..bb4afc76b7 100644 --- a/tests/topotests/rip_topo1/r3/show_ip_rip.ref +++ b/tests/topotests/rip_topo1/r3/show_ip_rip.ref @@ -1,4 +1,7 @@ -Codes: R - RIP, C - connected, S - Static, O - OSPF, B - BGP +Codes: K - kernel route, C - connected, L - local, S - static, + R - RIP, O - OSPF, I - IS-IS, B - BGP, E - EIGRP, N - NHRP, + T - Table, v - VNC, V - VNC-Direct, A - Babel, F - PBR, + f - OpenFabric, t - Table-Direct Sub-codes: (n) - normal, (s) - static, (d) - default, (r) - redistribute, (i) - interface diff --git a/tests/topotests/ripng_topo1/r1/show_ipv6_ripng.ref b/tests/topotests/ripng_topo1/r1/show_ipv6_ripng.ref index 30d0f31e18..8645979cc0 100644 --- a/tests/topotests/ripng_topo1/r1/show_ipv6_ripng.ref +++ b/tests/topotests/ripng_topo1/r1/show_ipv6_ripng.ref @@ -1,4 +1,7 @@ -Codes: R - RIPng, C - connected, S - Static, O - OSPF, B - BGP +Codes: K - kernel route, C - connected, L - local, S - static, + R - RIPng, O - OSPF, I - IS-IS, B - BGP, E - EIGRP, N - NHRP, + T - Table, v - VNC, V - VNC-Direct, A - Babel, F - PBR, + f - OpenFabric, t - Table-Direct Sub-codes: (n) - normal, (s) - static, (d) - default, (r) - redistribute, (i) - interface, (a/S) - aggregated/Suppressed diff --git a/tests/topotests/ripng_topo1/r2/show_ipv6_ripng.ref b/tests/topotests/ripng_topo1/r2/show_ipv6_ripng.ref index fe5bcc8b31..2c4db1ab54 100644 --- a/tests/topotests/ripng_topo1/r2/show_ipv6_ripng.ref +++ b/tests/topotests/ripng_topo1/r2/show_ipv6_ripng.ref @@ -1,4 +1,7 @@ -Codes: R - RIPng, C - connected, S - Static, O - OSPF, B - BGP +Codes: K - kernel route, C - connected, L - local, S - static, + R - RIPng, O - OSPF, I - IS-IS, B - BGP, E - EIGRP, N - NHRP, + T - Table, v - VNC, V - VNC-Direct, A - Babel, F - PBR, + f - OpenFabric, t - Table-Direct Sub-codes: (n) - normal, (s) - static, (d) - default, (r) - redistribute, (i) - interface, (a/S) - aggregated/Suppressed diff --git a/tests/topotests/ripng_topo1/r3/show_ipv6_ripng.ref b/tests/topotests/ripng_topo1/r3/show_ipv6_ripng.ref index 909ad663ba..2ba0aa6d8f 100644 --- a/tests/topotests/ripng_topo1/r3/show_ipv6_ripng.ref +++ b/tests/topotests/ripng_topo1/r3/show_ipv6_ripng.ref @@ -1,4 +1,7 @@ -Codes: R - RIPng, C - connected, S - Static, O - OSPF, B - BGP +Codes: K - kernel route, C - connected, L - local, S - static, + R - RIPng, O - OSPF, I - IS-IS, B - BGP, E - EIGRP, N - NHRP, + T - Table, v - VNC, V - VNC-Direct, A - Babel, F - PBR, + f - OpenFabric, t - Table-Direct Sub-codes: (n) - normal, (s) - static, (d) - default, (r) - redistribute, (i) - interface, (a/S) - aggregated/Suppressed From cd9bb4dd7e19e7b383d18f5837fbcde2f5799a1e Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Fri, 5 Jul 2024 15:57:52 +0300 Subject: [PATCH 154/347] tests: Extended bgp_remote_as_auto topotest with unnumbered case Signed-off-by: Donatas Abraitis --- .../topotests/bgp_remote_as_auto/r1/frr.conf | 6 ++++ .../topotests/bgp_remote_as_auto/r4/frr.conf | 10 ++++++ .../test_bgp_remote_as_auto.py | 33 ++++++++++++++++++- 3 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 tests/topotests/bgp_remote_as_auto/r4/frr.conf diff --git a/tests/topotests/bgp_remote_as_auto/r1/frr.conf b/tests/topotests/bgp_remote_as_auto/r1/frr.conf index aec0e76a3f..2f1bcd275f 100644 --- a/tests/topotests/bgp_remote_as_auto/r1/frr.conf +++ b/tests/topotests/bgp_remote_as_auto/r1/frr.conf @@ -2,6 +2,9 @@ int r1-eth0 ip address 192.168.1.1/24 ! +int r1-eth1 + ip address 192.168.14.1/24 +! router bgp 65001 no bgp ebgp-requires-policy no bgp network import-check @@ -11,6 +14,9 @@ router bgp 65001 neighbor 192.168.1.3 remote-as auto neighbor 192.168.1.3 timers 1 3 neighbor 192.168.1.3 timers connect 1 + neighbor r1-eth1 interface remote-as auto + neighbor r1-eth1 timers 1 3 + neighbor r1-eth1 timers connect 1 address-family ipv4 unicast network 10.0.0.1/32 exit-address-family diff --git a/tests/topotests/bgp_remote_as_auto/r4/frr.conf b/tests/topotests/bgp_remote_as_auto/r4/frr.conf new file mode 100644 index 0000000000..e280a6c6e8 --- /dev/null +++ b/tests/topotests/bgp_remote_as_auto/r4/frr.conf @@ -0,0 +1,10 @@ +! +int r4-eth0 + ip address 192.168.14.4/24 +! +router bgp 65004 + no bgp ebgp-requires-policy + neighbor r4-eth0 interface remote-as auto + neighbor r4-eth0 timers 1 3 + neighbor r4-eth0 timers connect 1 +! diff --git a/tests/topotests/bgp_remote_as_auto/test_bgp_remote_as_auto.py b/tests/topotests/bgp_remote_as_auto/test_bgp_remote_as_auto.py index b932920e09..1db6d98a42 100644 --- a/tests/topotests/bgp_remote_as_auto/test_bgp_remote_as_auto.py +++ b/tests/topotests/bgp_remote_as_auto/test_bgp_remote_as_auto.py @@ -23,7 +23,7 @@ def setup_module(mod): - topodef = {"s1": ("r1", "r2", "r3")} + topodef = {"s1": ("r1", "r2", "r3"), "s2": ("r1", "r4")} tgen = Topogen(topodef, mod.__name__) tgen.start_topology() @@ -49,11 +49,18 @@ def test_bgp_remote_as_auto(): r1 = tgen.gears["r1"] r2 = tgen.gears["r2"] r3 = tgen.gears["r3"] + r4 = tgen.gears["r4"] def _bgp_converge(): output = json.loads(r1.vtysh_cmd("show bgp ipv4 unicast summary json")) expected = { "peers": { + "r1-eth1": { + "hostname": "r4", + "remoteAs": 65004, + "localAs": 65001, + "state": "Established", + }, "192.168.1.2": { "hostname": "r2", "remoteAs": 65001, @@ -124,6 +131,30 @@ def _bgp_converge_external(): _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) assert result is None, "Can't see automatic eBGP peering" + def _bgp_converge_external_unnumbered(): + output = json.loads(r4.vtysh_cmd("show bgp ipv4 unicast 10.0.0.1/32 json")) + expected = { + "paths": [ + { + "aspath": { + "string": "65001", + }, + "valid": True, + "peer": { + "hostname": "r1", + "type": "external", + }, + } + ] + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _bgp_converge_external_unnumbered, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Can't see automatic unnumbered eBGP peering" + if __name__ == "__main__": args = ["-s"] + sys.argv[1:] From ed480148844259b7e9e30ed92489cdf44085457e Mon Sep 17 00:00:00 2001 From: Acee Lindem Date: Fri, 5 Jul 2024 20:44:30 +0000 Subject: [PATCH 155/347] ospfd: Fix several problems with direct acknowledgments and improved delay acks. 1. On P2MP interfaces, direct ack would include the same LSA multiple times multiple packets are processed before the OSPF interfae direct LSA acknowledgment event is processed. Now duplicates LSA in the same event are suppressed. 2. On non-broadcast interfaces, direct acks for multiple neighbors would be unicast to the same neighbor due to the multiple OSPF LS Update packets being process prior to the OSPF interface direct ack event. Now, separate direct acks are unicast to the neighbors requiring them. 3. The interface delayed acknowledgment timer runs would run continously (every second as long as the interace is up). Now, the timer is set when delayed acknowledgments are queued and all queued delayed acknowledges are sent when it fires. 4. For non-broadcast interface delayed acknowledgments, the logic to send to multiple neighbors wasn't working because the list was emptied while building the packet for the first neighbor. Signed-off-by: Acee Lindem --- lib/libospf.h | 1 + ospfd/ospf_flood.c | 26 ++++- ospfd/ospf_flood.h | 23 +++- ospfd/ospf_interface.c | 44 +++++--- ospfd/ospf_interface.h | 17 +-- ospfd/ospf_ism.c | 14 +-- ospfd/ospf_packet.c | 243 ++++++++++++++++++++++++++++++----------- ospfd/ospf_packet.h | 5 +- 8 files changed, 265 insertions(+), 108 deletions(-) diff --git a/lib/libospf.h b/lib/libospf.h index f2dc5d61d9..8a208beb3c 100644 --- a/lib/libospf.h +++ b/lib/libospf.h @@ -61,6 +61,7 @@ extern "C" { #define OSPF_RETRANSMIT_WINDOW_DEFAULT 50 /* milliseconds */ #define OSPF_TRANSMIT_DELAY_DEFAULT 1 #define OSPF_DEFAULT_BANDWIDTH 10000 /* Mbps */ +#define OSPF_ACK_DELAY_DEFAULT 1 #define OSPF_DEFAULT_REF_BANDWIDTH 100000 /* Kbps */ diff --git a/ospfd/ospf_flood.c b/ospfd/ospf_flood.c index e9797ce935..2af4ae3170 100644 --- a/ospfd/ospf_flood.c +++ b/ospfd/ospf_flood.c @@ -110,6 +110,9 @@ void ospf_area_update_fr_state(struct ospf_area *area) static void ospf_flood_delayed_lsa_ack(struct ospf_neighbor *inbr, struct ospf_lsa *lsa) { + struct ospf_lsa_list_entry *ls_ack_list_entry; + struct ospf_interface *oi = inbr->oi; + /* LSA is more recent than database copy, but was not flooded back out receiving interface. Delayed acknowledgment sent. If interface is in Backup state @@ -122,12 +125,27 @@ static void ospf_flood_delayed_lsa_ack(struct ospf_neighbor *inbr, worked out previously */ /* Deal with router as BDR */ - if (inbr->oi->state == ISM_Backup && !NBR_IS_DR(inbr)) + if (oi->state == ISM_Backup && !NBR_IS_DR(inbr)) return; - /* Schedule a delayed LSA Ack to be sent */ - listnode_add(inbr->oi->ls_ack, - ospf_lsa_lock(lsa)); /* delayed LSA Ack */ + if (IS_DEBUG_OSPF(lsa, LSA_FLOODING)) + zlog_debug("%s:Add LSA[Type%d:%pI4:%pI4]: seq 0x%x age %u NBR %pI4 (%s) ack queue", + __func__, lsa->data->type, &lsa->data->id, + &lsa->data->adv_router, ntohl(lsa->data->ls_seqnum), + ntohs(lsa->data->ls_age), &inbr->router_id, + IF_NAME(inbr->oi)); + + /* Add the LSA to the interface delayed Ack list. */ + ls_ack_list_entry = XCALLOC(MTYPE_OSPF_LSA_LIST, + sizeof(struct ospf_lsa_list_entry)); + ls_ack_list_entry->lsa = ospf_lsa_lock(lsa); + ospf_lsa_list_add_tail(&oi->ls_ack_delayed, ls_ack_list_entry); + + /* Set LS Ack timer if it is not already scheduled. */ + if (!oi->t_ls_ack_delayed) + OSPF_ISM_TIMER_ON(oi->t_ls_ack_delayed, + ospf_ls_ack_delayed_timer, + oi->v_ls_ack_delayed); } /* Check LSA is related to external info. */ diff --git a/ospfd/ospf_flood.h b/ospfd/ospf_flood.h index d9d9537351..2412052970 100644 --- a/ospfd/ospf_flood.h +++ b/ospfd/ospf_flood.h @@ -7,6 +7,8 @@ #ifndef _ZEBRA_OSPF_FLOOD_H #define _ZEBRA_OSPF_FLOOD_H +#include "typesafe.h" + /* * OSPF Temporal LSA List */ @@ -16,14 +18,25 @@ struct ospf_lsa_list_entry { /* Linkage for LSA List */ struct ospf_lsa_list_item list_linkage; - /* - * Time associated with the list entry. For example, for a neigbhor - * link retransmission list, this is the retransmission time. - */ - struct timeval list_entry_time; + union { + /* + * Time associated with the list entry. For example, for a + * neigbhor link retransmission list, this is the + * retransmission time. + */ + struct timeval list_entry_timeval; + + /* + * Destanation address specific to the LSA list. For example, + * the distination for an associated direct LS acknowledgment. + */ + struct in_addr list_entry_dst_addr; + } u; struct ospf_lsa *lsa; }; +#define list_entry_time u.list_entry_timeval +#define list_entry_dst u.list_entry_dst_addr DECLARE_DLIST(ospf_lsa_list, struct ospf_lsa_list_entry, list_linkage); diff --git a/ospfd/ospf_interface.c b/ospfd/ospf_interface.c index 803c36861d..c4210eb70c 100644 --- a/ospfd/ospf_interface.c +++ b/ospfd/ospf_interface.c @@ -186,10 +186,12 @@ static void ospf_if_default_variables(struct ospf_interface *oi) oi->crypt_seqnum = 0; - /* This must be short, (less than RxmtInterval) - - RFC 2328 Section 13.5 para 3. Set to 1 second to avoid Acks being - held back for too long - MAG */ - oi->v_ls_ack = 1; + /* + * The OSPF LS ACK Delay timer must be less than the LS Retransmision + * timer. As per RFC 2328 Section 13.5 paragraph 3, Set to 1 second + * to avoid Acks being held back for too long + */ + oi->v_ls_ack_delayed = OSPF_ACK_DELAY_DEFAULT; } /* lookup oi for specified prefix/ifp */ @@ -272,9 +274,9 @@ struct ospf_interface *ospf_if_new(struct ospf *ospf, struct interface *ifp, /* Initialize static neighbor list. */ oi->nbr_nbma = list_new(); - /* Initialize Link State Acknowledgment list. */ - oi->ls_ack = list_new(); - oi->ls_ack_direct.ls_ack = list_new(); + /* Initialize Link State Acknowledgment lists. */ + ospf_lsa_list_init(&oi->ls_ack_delayed); + ospf_lsa_list_init(&oi->ls_ack_direct); /* Set default values. */ ospf_if_default_variables(oi); @@ -306,6 +308,22 @@ struct ospf_interface *ospf_if_new(struct ospf *ospf, struct interface *ifp, return oi; } +/* + * Cleanup Interface Ack List + */ +static void ospf_if_cleanup_ack_list(struct ospf_lsa_list_head *ls_ack_list) +{ + struct ospf_lsa_list_entry *ls_ack_list_entry; + struct ospf_lsa *lsa; + + frr_each_safe (ospf_lsa_list, ls_ack_list, ls_ack_list_entry) { + lsa = ls_ack_list_entry->lsa; + ospf_lsa_list_del(ls_ack_list, ls_ack_list_entry); + XFREE(MTYPE_OSPF_LSA_LIST, ls_ack_list_entry); + ospf_lsa_unlock(&lsa); + } +} + /* Restore an interface to its pre UP state Used from ism_interface_down only */ void ospf_if_cleanup(struct ospf_interface *oi) @@ -314,7 +332,6 @@ void ospf_if_cleanup(struct ospf_interface *oi) struct listnode *node, *nnode; struct ospf_neighbor *nbr; struct ospf_nbr_nbma *nbr_nbma; - struct ospf_lsa *lsa; /* oi->nbrs and oi->nbr_nbma should be deleted on InterfaceDown event */ /* delete all static neighbors attached to this interface */ @@ -338,10 +355,9 @@ void ospf_if_cleanup(struct ospf_interface *oi) OSPF_NSM_EVENT_EXECUTE(nbr, NSM_KillNbr); } - /* Cleanup Link State Acknowlegdment list. */ - for (ALL_LIST_ELEMENTS(oi->ls_ack, node, nnode, lsa)) - ospf_lsa_unlock(&lsa); /* oi->ls_ack */ - list_delete_all_node(oi->ls_ack); + /* Cleanup Link State Delayed Acknowlegdment list. */ + ospf_if_cleanup_ack_list(&oi->ls_ack_delayed); + ospf_if_cleanup_ack_list(&oi->ls_ack_direct); oi->crypt_seqnum = 0; @@ -377,8 +393,8 @@ void ospf_if_free(struct ospf_interface *oi) /* Free any lists that should be freed */ list_delete(&oi->nbr_nbma); - list_delete(&oi->ls_ack); - list_delete(&oi->ls_ack_direct.ls_ack); + ospf_if_cleanup_ack_list(&oi->ls_ack_delayed); + ospf_if_cleanup_ack_list(&oi->ls_ack_direct); if (IS_DEBUG_OSPF_EVENT) zlog_debug("%s: ospf interface %s vrf %s id %u deleted", diff --git a/ospfd/ospf_interface.h b/ospfd/ospf_interface.h index a944847b5d..78a4fb9e59 100644 --- a/ospfd/ospf_interface.h +++ b/ospfd/ospf_interface.h @@ -13,6 +13,7 @@ #include "keychain.h" #include "ospfd/ospf_packet.h" #include "ospfd/ospf_spf.h" +#include #define IF_OSPF_IF_INFO(I) ((struct ospf_if_info *)((I)->info)) #define IF_DEF_PARAMS(I) (IF_OSPF_IF_INFO (I)->def_params) @@ -265,20 +266,20 @@ struct ospf_interface { struct route_table *ls_upd_queue; - struct list *ls_ack; /* Link State Acknowledgment list. */ - - struct { - struct list *ls_ack; - struct in_addr dst; - } ls_ack_direct; + /* + * List of LSAs for delayed and direct link + * state acknowledgment transmission. + */ + struct ospf_lsa_list_head ls_ack_delayed; + struct ospf_lsa_list_head ls_ack_direct; /* Timer values. */ - uint32_t v_ls_ack; /* Delayed Link State Acknowledgment */ + uint32_t v_ls_ack_delayed; /* Delayed Link State Acknowledgment */ /* Threads. */ struct event *t_hello; /* timer */ struct event *t_wait; /* timer */ - struct event *t_ls_ack; /* timer */ + struct event *t_ls_ack_delayed; /* timer */ struct event *t_ls_ack_direct; /* event */ struct event *t_ls_upd_event; /* event */ struct event *t_opaque_lsa_self; /* Type-9 Opaque-LSAs */ diff --git a/ospfd/ospf_ism.c b/ospfd/ospf_ism.c index 878ab725bd..377e7a6bcc 100644 --- a/ospfd/ospf_ism.c +++ b/ospfd/ospf_ism.c @@ -285,7 +285,7 @@ static void ism_timer_set(struct ospf_interface *oi) reset also. */ EVENT_OFF(oi->t_hello); EVENT_OFF(oi->t_wait); - EVENT_OFF(oi->t_ls_ack); + EVENT_OFF(oi->t_ls_ack_delayed); EVENT_OFF(oi->gr.hello_delay.t_grace_send); break; case ISM_Loopback: @@ -293,7 +293,7 @@ static void ism_timer_set(struct ospf_interface *oi) unavailable for regular data traffic. */ EVENT_OFF(oi->t_hello); EVENT_OFF(oi->t_wait); - EVENT_OFF(oi->t_ls_ack); + EVENT_OFF(oi->t_ls_ack_delayed); EVENT_OFF(oi->gr.hello_delay.t_grace_send); break; case ISM_Waiting: @@ -304,7 +304,7 @@ static void ism_timer_set(struct ospf_interface *oi) OSPF_ISM_TIMER_MSEC_ON(oi->t_hello, ospf_hello_timer, 1); OSPF_ISM_TIMER_ON(oi->t_wait, ospf_wait_timer, OSPF_IF_PARAM(oi, v_wait)); - EVENT_OFF(oi->t_ls_ack); + EVENT_OFF(oi->t_ls_ack_delayed); break; case ISM_PointToPoint: /* The interface connects to a physical Point-to-point network @@ -314,8 +314,6 @@ static void ism_timer_set(struct ospf_interface *oi) /* send first hello immediately */ OSPF_ISM_TIMER_MSEC_ON(oi->t_hello, ospf_hello_timer, 1); EVENT_OFF(oi->t_wait); - OSPF_ISM_TIMER_ON(oi->t_ls_ack, ospf_ls_ack_timer, - oi->v_ls_ack); break; case ISM_DROther: /* The network type of the interface is broadcast or NBMA @@ -324,8 +322,6 @@ static void ism_timer_set(struct ospf_interface *oi) Backup Designated Router. */ OSPF_HELLO_TIMER_ON(oi); EVENT_OFF(oi->t_wait); - OSPF_ISM_TIMER_ON(oi->t_ls_ack, ospf_ls_ack_timer, - oi->v_ls_ack); break; case ISM_Backup: /* The network type of the interface is broadcast os NBMA @@ -333,8 +329,6 @@ static void ism_timer_set(struct ospf_interface *oi) and the router is Backup Designated Router. */ OSPF_HELLO_TIMER_ON(oi); EVENT_OFF(oi->t_wait); - OSPF_ISM_TIMER_ON(oi->t_ls_ack, ospf_ls_ack_timer, - oi->v_ls_ack); break; case ISM_DR: /* The network type of the interface is broadcast or NBMA @@ -342,8 +336,6 @@ static void ism_timer_set(struct ospf_interface *oi) and the router is Designated Router. */ OSPF_HELLO_TIMER_ON(oi); EVENT_OFF(oi->t_wait); - OSPF_ISM_TIMER_ON(oi->t_ls_ack, ospf_ls_ack_timer, - oi->v_ls_ack); break; } } diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c index 86f877b621..2d15a7ecca 100644 --- a/ospfd/ospf_packet.c +++ b/ospfd/ospf_packet.c @@ -369,19 +369,16 @@ void ospf_ls_rxmt_timer(struct event *thread) ospf_ls_retransmit_set_timer(nbr); } -void ospf_ls_ack_timer(struct event *thread) +void ospf_ls_ack_delayed_timer(struct event *thread) { struct ospf_interface *oi; oi = EVENT_ARG(thread); - oi->t_ls_ack = NULL; + oi->t_ls_ack_delayed = NULL; /* Send Link State Acknowledgment. */ - if (listcount(oi->ls_ack) > 0) + if (ospf_lsa_list_count(&oi->ls_ack_delayed)) ospf_ls_ack_send_delayed(oi); - - /* Set LS Ack timer. */ - OSPF_ISM_TIMER_ON(oi->t_ls_ack, ospf_ls_ack_timer, oi->v_ls_ack); } #ifdef WANT_OSPF_WRITE_FRAGMENT @@ -1820,7 +1817,7 @@ static void ospf_ls_upd(struct ospf *ospf, struct ip *iph, if (IS_LSA_MAXAGE(lsa) && !current && ospf_check_nbr_status(oi->ospf)) { /* (4a) Response Link State Acknowledgment. */ - ospf_ls_ack_send(nbr, lsa); + ospf_ls_ack_send_direct(nbr, lsa); /* (4b) Discard LSA. */ if (IS_DEBUG_OSPF(lsa, LSA)) { @@ -1845,7 +1842,7 @@ static void ospf_ls_upd(struct ospf *ospf, struct ip *iph, if (IS_LSA_MAXAGE(lsa)) { zlog_info("LSA[%s]: Boomerang effect?", dump_lsa_key(lsa)); - ospf_ls_ack_send(nbr, lsa); + ospf_ls_ack_send_direct(nbr, lsa); ospf_lsa_discard(lsa); if (current != NULL && !IS_LSA_MAXAGE(current)) @@ -1879,7 +1876,7 @@ static void ospf_ls_upd(struct ospf *ospf, struct ip *iph, SET_FLAG(lsa->flags, OSPF_LSA_SELF); - ospf_ls_ack_send(nbr, lsa); + ospf_ls_ack_send_direct(nbr, lsa); if (!ospf->gr_info.restart_in_progress) { ospf_opaque_self_originated_lsa_received( @@ -2018,9 +2015,8 @@ static void ospf_ls_upd(struct ospf *ospf, struct ip *iph, */ if (oi->state == ISM_Backup) if (NBR_IS_DR(nbr)) - listnode_add( - oi->ls_ack, - ospf_lsa_lock(lsa)); + ospf_ls_ack_send_direct(nbr, + lsa); DISCARD_LSA(lsa, 6); } else @@ -2029,7 +2025,7 @@ static void ospf_ls_upd(struct ospf *ospf, struct ip *iph, receiving interface. */ { - ospf_ls_ack_send(nbr, lsa); + ospf_ls_ack_send_direct(nbr, lsa); DISCARD_LSA(lsa, 7); } } @@ -3331,17 +3327,36 @@ static int ospf_make_ls_upd(struct ospf_interface *oi, struct list *update, return length; } -static int ospf_make_ls_ack(struct ospf_interface *oi, struct list *ack, - struct stream *s) +static int ospf_make_ls_ack(struct ospf_interface *oi, + struct ospf_lsa_list_head *ls_ack_list, + bool direct_ack, bool delete_ack, struct stream *s) { - struct listnode *node, *nnode; + struct ospf_lsa_list_entry *ls_ack_list_first; + struct ospf_lsa_list_entry *ls_ack_list_entry; uint16_t length = OSPF_LS_ACK_MIN_SIZE; - unsigned long delta = OSPF_LSA_HEADER_SIZE; struct ospf_lsa *lsa; + struct in_addr first_dst_addr; - for (ALL_LIST_ELEMENTS(ack, node, nnode, lsa)) { + /* + * For direct LS Acks, assure the destination address doesn't + * change between queued acknowledgments. + */ + if (direct_ack) { + ls_ack_list_first = ospf_lsa_list_first(ls_ack_list); + if (ls_ack_list_first) + first_dst_addr.s_addr = + ls_ack_list_first->list_entry_dst.s_addr; + } else + first_dst_addr.s_addr = INADDR_ANY; + + frr_each_safe (ospf_lsa_list, ls_ack_list, ls_ack_list_entry) { + lsa = ls_ack_list_entry->lsa; assert(lsa); + if (direct_ack && (ls_ack_list_entry->list_entry_dst.s_addr != + first_dst_addr.s_addr)) + break; + /* LS Ack packet overflows interface MTU * delta is just number of bytes required for * 1 LS Ack(1 LS Hdr) ospf_packet_max will return @@ -3350,19 +3365,46 @@ static int ospf_make_ls_ack(struct ospf_interface *oi, struct list *ack, * against ospf_packet_max to check if it can fit * another ls header in the same packet. */ - if ((length + delta) > ospf_packet_max(oi)) + if ((length + OSPF_LSA_HEADER_SIZE) > ospf_packet_max(oi)) break; stream_put(s, lsa->data, OSPF_LSA_HEADER_SIZE); length += OSPF_LSA_HEADER_SIZE; - listnode_delete(ack, lsa); - ospf_lsa_unlock(&lsa); /* oi->ls_ack_direct.ls_ack */ + if (delete_ack) { + ospf_lsa_list_del(ls_ack_list, ls_ack_list_entry); + XFREE(MTYPE_OSPF_LSA_LIST, ls_ack_list_entry); + ospf_lsa_unlock(&lsa); + } } return length; } +/* + * On non-braodcast networks, the same LS acks must be sent to multiple + * neighbors and deletion must be deferred until after the LS Ack packet + * is sent to all neighbors. + */ +static void ospf_delete_ls_ack_delayed(struct ospf_interface *oi) +{ + struct ospf_lsa_list_entry *ls_ack_list_entry; + struct ospf_lsa *lsa; + uint16_t length = OSPF_LS_ACK_MIN_SIZE; + + frr_each_safe (ospf_lsa_list, &oi->ls_ack_delayed, ls_ack_list_entry) { + lsa = ls_ack_list_entry->lsa; + assert(lsa); + if ((length + OSPF_LSA_HEADER_SIZE) > ospf_packet_max(oi)) + break; + + length += OSPF_LSA_HEADER_SIZE; + ospf_lsa_list_del(&oi->ls_ack_delayed, ls_ack_list_entry); + XFREE(MTYPE_OSPF_LSA_LIST, ls_ack_list_entry); + ospf_lsa_unlock(&lsa); + } +} + static void ospf_hello_send_sub(struct ospf_interface *oi, in_addr_t addr) { struct ospf_packet *op; @@ -3934,10 +3976,13 @@ void ospf_ls_upd_send(struct ospf_neighbor *nbr, struct list *update, int flag, &oi->t_ls_upd_event); } -static void ospf_ls_ack_send_list(struct ospf_interface *oi, struct list *ack, +static void ospf_ls_ack_send_list(struct ospf_interface *oi, + struct ospf_lsa_list_head *ls_ack_list, + bool direct_ack, bool delete_ack, struct in_addr dst) { struct ospf_packet *op; + struct ospf_lsa_list_entry *ls_ack_list_first; uint16_t length = OSPF_HEADER_SIZE; op = ospf_packet_new(oi->ifp->mtu); @@ -3945,8 +3990,18 @@ static void ospf_ls_ack_send_list(struct ospf_interface *oi, struct list *ack, /* Prepare OSPF common header. */ ospf_make_header(OSPF_MSG_LS_ACK, oi, op->s); + /* Determine the destination address - for direct acks, + * the list entries always include the distination address. + */ + if (direct_ack) { + ls_ack_list_first = ospf_lsa_list_first(ls_ack_list); + op->dst.s_addr = ls_ack_list_first->list_entry_dst.s_addr; + } else + op->dst.s_addr = dst.s_addr; + /* Prepare OSPF Link State Acknowledgment body. */ - length += ospf_make_ls_ack(oi, ack, op->s); + length += ospf_make_ls_ack(oi, ls_ack_list, direct_ack, delete_ack, + op->s); /* Fill OSPF header. */ ospf_fill_header(oi, op->s, length); @@ -3954,14 +4009,6 @@ static void ospf_ls_ack_send_list(struct ospf_interface *oi, struct list *ack, /* Set packet length. */ op->length = length; - /* Decide destination address. */ - if (oi->type == OSPF_IFTYPE_POINTOPOINT || - (oi->type == OSPF_IFTYPE_POINTOMULTIPOINT && - !oi->p2mp_non_broadcast)) - op->dst.s_addr = htonl(OSPF_ALLSPFROUTERS); - else - op->dst.s_addr = dst.s_addr; - /* Add packet to the interface output queue. */ ospf_packet_add(oi, op); @@ -3969,34 +4016,96 @@ static void ospf_ls_ack_send_list(struct ospf_interface *oi, struct list *ack, OSPF_ISM_WRITE_ON(oi->ospf); } -static void ospf_ls_ack_send_event(struct event *thread) +static void ospf_ls_ack_send_direct_event(struct event *thread) { struct ospf_interface *oi = EVENT_ARG(thread); + struct in_addr dst = { INADDR_ANY }; oi->t_ls_ack_direct = NULL; - while (listcount(oi->ls_ack_direct.ls_ack)) - ospf_ls_ack_send_list(oi, oi->ls_ack_direct.ls_ack, - oi->ls_ack_direct.dst); + while (ospf_lsa_list_count(&oi->ls_ack_direct)) + ospf_ls_ack_send_list(oi, &(oi->ls_ack_direct), true, true, dst); } -void ospf_ls_ack_send(struct ospf_neighbor *nbr, struct ospf_lsa *lsa) +void ospf_ls_ack_send_direct(struct ospf_neighbor *nbr, struct ospf_lsa *lsa) { + struct ospf_lsa_list_entry *ls_ack_list_entry; struct ospf_interface *oi = nbr->oi; + if (IS_DEBUG_OSPF(lsa, LSA_FLOODING)) + zlog_debug("%s:Add LSA[Type%d:%pI4:%pI4]: seq 0x%x age %u NBR %pI4 (%s) ack queue", + __func__, lsa->data->type, &lsa->data->id, + &lsa->data->adv_router, ntohl(lsa->data->ls_seqnum), + ntohs(lsa->data->ls_age), &nbr->router_id, + IF_NAME(nbr->oi)); + + /* + * On Point-to-Multipoint broadcast-capabile interfaces, + * where direct acks from are sent to the ALLSPFRouters + * address and one direct ack send event, may include LSAs + * from multiple neighbors, there is a possibility of the same + * LSA being processed more than once in the same send event. + * In this case, the instances subsequent to the first can be + * ignored. + */ + if (oi->type == OSPF_IFTYPE_POINTOMULTIPOINT && !oi->p2mp_non_broadcast) { + struct ospf_lsa_list_entry *ls_ack_list_entry; + struct ospf_lsa *ack_queue_lsa; + + frr_each (ospf_lsa_list, &oi->ls_ack_direct, ls_ack_list_entry) { + ack_queue_lsa = ls_ack_list_entry->lsa; + if ((lsa == ack_queue_lsa) || + ((lsa->data->type == ack_queue_lsa->data->type) && + (lsa->data->id.s_addr == + ack_queue_lsa->data->id.s_addr) && + (lsa->data->adv_router.s_addr == + ack_queue_lsa->data->adv_router.s_addr) && + (lsa->data->ls_seqnum == + ack_queue_lsa->data->ls_seqnum))) { + if (IS_DEBUG_OSPF(lsa, LSA_FLOODING)) + zlog_debug("%s:LSA[Type%d:%pI4:%pI4]: seq 0x%x age %u NBR %pI4 (%s) ack queue duplicate", + __func__, lsa->data->type, + &lsa->data->id, + &lsa->data->adv_router, + ntohl(lsa->data->ls_seqnum), + ntohs(lsa->data->ls_age), + &nbr->router_id, + IF_NAME(nbr->oi)); + return; + } + } + } + if (IS_GRACE_LSA(lsa)) { if (IS_DEBUG_OSPF_GR) zlog_debug("%s, Sending GRACE ACK to Restarter.", __func__); } - if (listcount(oi->ls_ack_direct.ls_ack) == 0) - oi->ls_ack_direct.dst = nbr->address.u.prefix4; + ls_ack_list_entry = XCALLOC(MTYPE_OSPF_LSA_LIST, + sizeof(struct ospf_lsa_list_entry)); - listnode_add(oi->ls_ack_direct.ls_ack, ospf_lsa_lock(lsa)); + /* + * Determine the destination address - Direct LS acknowledgments + * are sent the AllSPFRouters multicast address on Point-to-Point + * and Point-to-Multipoint broadcast-capable interfaces. For all other + * interface types, they are unicast directly to the neighbor. + */ + if (oi->type == OSPF_IFTYPE_POINTOPOINT || + (oi->type == OSPF_IFTYPE_POINTOMULTIPOINT && + !oi->p2mp_non_broadcast)) + ls_ack_list_entry->list_entry_dst.s_addr = + htonl(OSPF_ALLSPFROUTERS); + else + ls_ack_list_entry->list_entry_dst.s_addr = + nbr->address.u.prefix4.s_addr; - event_add_event(master, ospf_ls_ack_send_event, oi, 0, - &oi->t_ls_ack_direct); + ls_ack_list_entry->lsa = ospf_lsa_lock(lsa); + ospf_lsa_list_add_tail(&nbr->oi->ls_ack_direct, ls_ack_list_entry); + + if (oi->t_ls_ack_direct == NULL) + event_add_event(master, ospf_ls_ack_send_direct_event, oi, 0, + &oi->t_ls_ack_direct); } /* Send Link State Acknowledgment delayed. */ @@ -4013,33 +4122,39 @@ void ospf_ls_ack_send_delayed(struct ospf_interface *oi) struct ospf_neighbor *nbr; struct route_node *rn; - for (rn = route_top(oi->nbrs); rn; rn = route_next(rn)) { - nbr = rn->info; + while (ospf_lsa_list_count(&oi->ls_ack_delayed)) { + for (rn = route_top(oi->nbrs); rn; rn = route_next(rn)) { + nbr = rn->info; - if (!nbr) - continue; + if (!nbr) + continue; - if (nbr != oi->nbr_self && nbr->state >= NSM_Exchange) - while (listcount(oi->ls_ack)) - ospf_ls_ack_send_list( - oi, oi->ls_ack, - nbr->address.u.prefix4); + if (nbr != oi->nbr_self && + nbr->state >= NSM_Exchange) + ospf_ls_ack_send_list(oi, + &oi->ls_ack_delayed, + false, false, + nbr->address.u + .prefix4); + } + ospf_delete_ls_ack_delayed(oi); } - return; - } - if (oi->type == OSPF_IFTYPE_VIRTUALLINK) - dst.s_addr = oi->vl_data->peer_addr.s_addr; - else if (oi->state == ISM_DR || oi->state == ISM_Backup) - dst.s_addr = htonl(OSPF_ALLSPFROUTERS); - else if (oi->type == OSPF_IFTYPE_POINTOPOINT) - dst.s_addr = htonl(OSPF_ALLSPFROUTERS); - else if (oi->type == OSPF_IFTYPE_POINTOMULTIPOINT) - dst.s_addr = htonl(OSPF_ALLSPFROUTERS); - else - dst.s_addr = htonl(OSPF_ALLDROUTERS); + } else { + if (oi->type == OSPF_IFTYPE_VIRTUALLINK) + dst.s_addr = oi->vl_data->peer_addr.s_addr; + else if (oi->state == ISM_DR || oi->state == ISM_Backup) + dst.s_addr = htonl(OSPF_ALLSPFROUTERS); + else if (oi->type == OSPF_IFTYPE_POINTOPOINT) + dst.s_addr = htonl(OSPF_ALLSPFROUTERS); + else if (oi->type == OSPF_IFTYPE_POINTOMULTIPOINT) + dst.s_addr = htonl(OSPF_ALLSPFROUTERS); + else + dst.s_addr = htonl(OSPF_ALLDROUTERS); - while (listcount(oi->ls_ack)) - ospf_ls_ack_send_list(oi, oi->ls_ack, dst); + while (ospf_lsa_list_count(&oi->ls_ack_delayed)) + ospf_ls_ack_send_list(oi, &oi->ls_ack_delayed, false, + true, dst); + } } /* diff --git a/ospfd/ospf_packet.h b/ospfd/ospf_packet.h index 2c9dba6c88..84e4b027e6 100644 --- a/ospfd/ospf_packet.h +++ b/ospfd/ospf_packet.h @@ -135,13 +135,14 @@ extern void ospf_ls_upd_send(struct ospf_neighbor *, struct list *, int, int); extern void ospf_ls_upd_queue_send(struct ospf_interface *oi, struct list *update, struct in_addr addr, int send_lsupd_now); -extern void ospf_ls_ack_send(struct ospf_neighbor *, struct ospf_lsa *); +extern void ospf_ls_ack_send_direct(struct ospf_neighbor *nbr, + struct ospf_lsa *lsa); extern void ospf_ls_ack_send_delayed(struct ospf_interface *); extern void ospf_ls_retransmit(struct ospf_interface *, struct ospf_lsa *); extern void ospf_ls_req_event(struct ospf_neighbor *); extern void ospf_ls_rxmt_timer(struct event *thread); -extern void ospf_ls_ack_timer(struct event *thread); +extern void ospf_ls_ack_delayed_timer(struct event *thread); extern void ospf_poll_timer(struct event *thread); extern void ospf_hello_reply_timer(struct event *thread); From 6477f73c0b0e16d2364d2c5f972f3988c387fa44 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Sun, 7 Jul 2024 18:26:30 +0300 Subject: [PATCH 156/347] tests: Rename BGP OAD test function Signed-off-by: Donatas Abraitis --- tests/topotests/bgp_oad/test_bgp_oad.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/topotests/bgp_oad/test_bgp_oad.py b/tests/topotests/bgp_oad/test_bgp_oad.py index a2ca37a2b7..bb779462db 100644 --- a/tests/topotests/bgp_oad/test_bgp_oad.py +++ b/tests/topotests/bgp_oad/test_bgp_oad.py @@ -46,7 +46,7 @@ def teardown_module(mod): tgen.stop_topology() -def test_bgp_dynamic_capability_role(): +def test_bgp_oad(): tgen = get_topogen() if tgen.routers_have_failure(): From d7144594cab0708139dcd736ba5166a052be9d3b Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Sun, 7 Jul 2024 18:42:08 +0300 Subject: [PATCH 157/347] bgpd: Drop unnecessary is_add check for bgp_zebra_announce_actual() Fixes: ccfe452763d16c432fa81fd20e805bec819b345e ("bgpd : backpressure - Handle BGP-Zebra Install evt Creation") Signed-off-by: Donatas Abraitis --- bgpd/bgp_zebra.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 3508f2d341..13f5337cdf 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -1556,7 +1556,6 @@ bgp_zebra_announce_actual(struct bgp_dest *dest, struct bgp_path_info *info, struct peer *peer; uint32_t metric; route_tag_t tag; - bool is_add; uint32_t nhg_id = 0; struct bgp_table *table = bgp_dest_table(dest); const struct prefix *p = bgp_dest_get_prefix(dest); @@ -1610,9 +1609,7 @@ bgp_zebra_announce_actual(struct bgp_dest *dest, struct bgp_path_info *info, table->afi, table->safi, &nhg_id, &metric, &tag, &allow_recursion); - is_add = (valid_nh_count || nhg_id) ? true : false; - - if (is_add && CHECK_FLAG(bm->flags, BM_FLAG_SEND_EXTRA_DATA_TO_ZEBRA)) { + if (CHECK_FLAG(bm->flags, BM_FLAG_SEND_EXTRA_DATA_TO_ZEBRA)) { struct bgp_zebra_opaque bzo = {}; const char *reason = bgp_path_selection_reason2str(dest->reason); @@ -1668,18 +1665,17 @@ bgp_zebra_announce_actual(struct bgp_dest *dest, struct bgp_path_info *info, } if (bgp_debug_zebra(p)) { - zlog_debug("Tx route %s %s %pFX metric %u tag %" ROUTE_TAG_PRI + zlog_debug("Tx route add %s %pFX metric %u tag %" ROUTE_TAG_PRI " count %d nhg %d", - is_add ? "add" : "delete", bgp->name_pretty, - &api.prefix, api.metric, api.tag, api.nexthop_num, - nhg_id); + bgp->name_pretty, &api.prefix, api.metric, api.tag, + api.nexthop_num, nhg_id); bgp_debug_zebra_nh(&api); zlog_debug("%s: %pFX: announcing to zebra (recursion %sset)", __func__, p, (allow_recursion ? "" : "NOT ")); } - return zclient_route_send(is_add ? ZEBRA_ROUTE_ADD : ZEBRA_ROUTE_DELETE, - zclient, &api); + + return zclient_route_send(ZEBRA_ROUTE_ADD, zclient, &api); } From 16bfdf58f757681230eb05a7f2d2da4ecdf66d0c Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Sun, 7 Jul 2024 18:49:05 +0300 Subject: [PATCH 158/347] bgpd: Print tableid when sending (add/remove) routes to Zebra In case this is used under `set table X` via route-maps, it's good to know in debugs the table id. Signed-off-by: Donatas Abraitis --- bgpd/bgp_zebra.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 13f5337cdf..72620de7d9 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -1665,10 +1665,10 @@ bgp_zebra_announce_actual(struct bgp_dest *dest, struct bgp_path_info *info, } if (bgp_debug_zebra(p)) { - zlog_debug("Tx route add %s %pFX metric %u tag %" ROUTE_TAG_PRI + zlog_debug("Tx route add %s (table id %u) %pFX metric %u tag %" ROUTE_TAG_PRI " count %d nhg %d", - bgp->name_pretty, &api.prefix, api.metric, api.tag, - api.nexthop_num, nhg_id); + bgp->name_pretty, api.tableid, &api.prefix, + api.metric, api.tag, api.nexthop_num, nhg_id); bgp_debug_zebra_nh(&api); zlog_debug("%s: %pFX: announcing to zebra (recursion %sset)", @@ -1757,8 +1757,8 @@ enum zclient_send_status bgp_zebra_withdraw_actual(struct bgp_dest *dest, } if (bgp_debug_zebra(p)) - zlog_debug("Tx route delete %s %pFX", bgp->name_pretty, - &api.prefix); + zlog_debug("Tx route delete %s (table id %u) %pFX", + bgp->name_pretty, api.tableid, &api.prefix); return zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api); } From f54970ff43d6dc376081328614febb31f58df75d Mon Sep 17 00:00:00 2001 From: zhou-run Date: Fri, 21 Jun 2024 14:26:44 +0800 Subject: [PATCH 159/347] isisd: The neighbor entry still displays the deleted hostname of the neighbor MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. The lsp_update_data() function will check for the presence of the ISIS_TLV_DYNAMIC_HOSTNAME in the LSP, and then call isis_dynhn_insert() to add a hostname entry corresponding to the LSP ID. However, when the ISIS_TLV_DYNAMIC_HOSTNAME is not present in the LSP, the hostname entry corresponding to the LSP ID should also be deleted. 2. The command “show isis neighbor” invokes isis_adj_name() to display the System ID or hostname, but it does not check the area->dynhostname flag. 3. When the LSP expires and is removed, the corresponding hostname entry should also be deleted. 4. The TLV for LSP fragmentation will not contain the hostname and should be skipped. Signed-off-by: zhou-run --- isisd/isis_adjacency.c | 2 +- isisd/isis_lsp.c | 24 +++++++++++++------ tests/topotests/isis_topo1/test_isis_topo1.py | 3 +++ 3 files changed, 21 insertions(+), 8 deletions(-) diff --git a/isisd/isis_adjacency.c b/isisd/isis_adjacency.c index 430bee92bf..ad63398715 100644 --- a/isisd/isis_adjacency.c +++ b/isisd/isis_adjacency.c @@ -293,7 +293,7 @@ const char *isis_adj_name(const struct isis_adjacency *adj) struct isis_dynhn *dyn; dyn = dynhn_find_by_id(adj->circuit->isis, adj->sysid); - if (dyn) + if (adj->circuit->area->dynhostname && dyn) return dyn->hostname; snprintfrr(buf, sizeof(buf), "%pSY", adj->sysid); diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c index c98cee06a5..79c2914445 100644 --- a/isisd/isis_lsp.c +++ b/isisd/isis_lsp.c @@ -482,13 +482,19 @@ static void lsp_update_data(struct isis_lsp *lsp, struct isis_lsp_hdr *hdr, lsp->tlvs = tlvs; - if (area->dynhostname && lsp->tlvs->hostname - && lsp->hdr.rem_lifetime) { - isis_dynhn_insert( - area->isis, lsp->hdr.lsp_id, lsp->tlvs->hostname, - (lsp->hdr.lsp_bits & LSPBIT_IST) == IS_LEVEL_1_AND_2 - ? IS_LEVEL_2 - : IS_LEVEL_1); + if (area->dynhostname && lsp->hdr.rem_lifetime) { + if (lsp->tlvs->hostname) { + isis_dynhn_insert(area->isis, lsp->hdr.lsp_id, + lsp->tlvs->hostname, + (lsp->hdr.lsp_bits & LSPBIT_IST) == + IS_LEVEL_1_AND_2 + ? IS_LEVEL_2 + : IS_LEVEL_1); + } else { + if (!LSP_PSEUDO_ID(lsp->hdr.lsp_id) && + !LSP_FRAGMENT(lsp->hdr.lsp_id)) + isis_dynhn_remove(area->isis, lsp->hdr.lsp_id); + } } return; @@ -2225,6 +2231,10 @@ void lsp_tick(struct event *thread) &area->lspdb[level], next); + if (!LSP_PSEUDO_ID(lsp->hdr.lsp_id)) + isis_dynhn_remove(area->isis, + lsp->hdr.lsp_id); + lspdb_del(&area->lspdb[level], lsp); lsp_destroy(lsp); lsp = NULL; diff --git a/tests/topotests/isis_topo1/test_isis_topo1.py b/tests/topotests/isis_topo1/test_isis_topo1.py index b388f52bd9..9615d30d3c 100644 --- a/tests/topotests/isis_topo1/test_isis_topo1.py +++ b/tests/topotests/isis_topo1/test_isis_topo1.py @@ -685,6 +685,9 @@ def _check_lsp_overload_bit(router, overloaded_router_lsp, att_p_ol_expected): ) database_json = json.loads(isis_database_output) + if "lsps" not in database_json["areas"][0]["levels"][1]: + return "The LSP of {} has not been synchronized yet ".format(router.name) + att_p_ol = database_json["areas"][0]["levels"][1]["lsps"][0]["attPOl"] if att_p_ol == att_p_ol_expected: return True From 66a84c7c107d7b70befdae77f923b72f3d5956b2 Mon Sep 17 00:00:00 2001 From: Xiao Liang Date: Fri, 17 Nov 2023 10:44:10 +0800 Subject: [PATCH 160/347] tests: Add IPv6 network adv/withdraw case in bgp_evpn_rt5 topotest Note that withdrawing IPv6 route should not affect IPv4. Signed-off-by: Xiao Liang --- tests/topotests/bgp_evpn_rt5/r1/bgpd.conf | 4 + tests/topotests/bgp_evpn_rt5/r1/zebra.conf | 1 + tests/topotests/bgp_evpn_rt5/r2/bgpd.conf | 4 + tests/topotests/bgp_evpn_rt5/r2/zebra.conf | 1 + tests/topotests/bgp_evpn_rt5/test_bgp_evpn.py | 125 +++++++++++++++++- 5 files changed, 134 insertions(+), 1 deletion(-) diff --git a/tests/topotests/bgp_evpn_rt5/r1/bgpd.conf b/tests/topotests/bgp_evpn_rt5/r1/bgpd.conf index ccbeae6ed7..c8c4faf222 100644 --- a/tests/topotests/bgp_evpn_rt5/r1/bgpd.conf +++ b/tests/topotests/bgp_evpn_rt5/r1/bgpd.conf @@ -20,7 +20,11 @@ router bgp 65000 vrf r1-vrf-101 address-family ipv4 unicast network 192.168.102.21/32 exit-address-family + address-family ipv6 unicast + network fd00::1/128 + exit-address-family address-family l2vpn evpn advertise ipv4 unicast + advertise ipv6 unicast exit-address-family ! diff --git a/tests/topotests/bgp_evpn_rt5/r1/zebra.conf b/tests/topotests/bgp_evpn_rt5/r1/zebra.conf index 4f1804c676..c3d508c2b6 100644 --- a/tests/topotests/bgp_evpn_rt5/r1/zebra.conf +++ b/tests/topotests/bgp_evpn_rt5/r1/zebra.conf @@ -17,6 +17,7 @@ interface r1-eth0 ! interface loop101 vrf r1-vrf-101 ip address 192.168.102.21/32 + ipv6 address fd00::1/128 ! diff --git a/tests/topotests/bgp_evpn_rt5/r2/bgpd.conf b/tests/topotests/bgp_evpn_rt5/r2/bgpd.conf index 744c259d9a..de5a0efc44 100644 --- a/tests/topotests/bgp_evpn_rt5/r2/bgpd.conf +++ b/tests/topotests/bgp_evpn_rt5/r2/bgpd.conf @@ -21,7 +21,11 @@ router bgp 65000 vrf r2-vrf-101 address-family ipv4 unicast network 192.168.101.41/32 exit-address-family + address-family ipv6 unicast + network fd00::2/128 + exit-address-family address-family l2vpn evpn advertise ipv4 unicast + advertise ipv6 unicast exit-address-family ! diff --git a/tests/topotests/bgp_evpn_rt5/r2/zebra.conf b/tests/topotests/bgp_evpn_rt5/r2/zebra.conf index 7d19a5b381..7db40cb59c 100644 --- a/tests/topotests/bgp_evpn_rt5/r2/zebra.conf +++ b/tests/topotests/bgp_evpn_rt5/r2/zebra.conf @@ -11,6 +11,7 @@ vrf r2-vrf-101 ! interface loop101 vrf r2-vrf-101 ip address 192.168.101.41/32 + ipv6 address fd00::2/128 ! interface r2-eth0 ip address 192.168.100.41/24 diff --git a/tests/topotests/bgp_evpn_rt5/test_bgp_evpn.py b/tests/topotests/bgp_evpn_rt5/test_bgp_evpn.py index d9177b4d25..2d027081cb 100644 --- a/tests/topotests/bgp_evpn_rt5/test_bgp_evpn.py +++ b/tests/topotests/bgp_evpn_rt5/test_bgp_evpn.py @@ -25,6 +25,8 @@ # pylint: disable=C0413 # Import topogen and topotest helpers from lib import topotest +from lib.bgp import verify_bgp_rib +from lib.common_config import apply_raw_config from lib.topogen import Topogen, TopoRouter, get_topogen from lib.topolog import logger @@ -179,12 +181,18 @@ def test_protocols_convergence(): output = tgen.gears["r1"].vtysh_cmd("show bgp vrf r1-vrf-101 ipv4", isjson=False) logger.info("==== result from show bgp vrf r1-vrf-101 ipv4") logger.info(output) + output = tgen.gears["r1"].vtysh_cmd("show bgp vrf r1-vrf-101 ipv6", isjson=False) + logger.info("==== result from show bgp vrf r1-vrf-101 ipv6") + logger.info(output) output = tgen.gears["r1"].vtysh_cmd("show bgp vrf r1-vrf-101", isjson=False) logger.info("==== result from show bgp vrf r1-vrf-101 ") logger.info(output) output = tgen.gears["r1"].vtysh_cmd("show ip route vrf r1-vrf-101", isjson=False) logger.info("==== result from show ip route vrf r1-vrf-101") logger.info(output) + output = tgen.gears["r1"].vtysh_cmd("show ipv6 route vrf r1-vrf-101", isjson=False) + logger.info("==== result from show ipv6 route vrf r1-vrf-101") + logger.info(output) output = tgen.gears["r1"].vtysh_cmd("show evpn vni detail", isjson=False) logger.info("==== result from show evpn vni detail") logger.info(output) @@ -192,8 +200,49 @@ def test_protocols_convergence(): logger.info("==== result from show evpn next-hops vni all") logger.info(output) output = tgen.gears["r1"].vtysh_cmd("show evpn rmac vni all", isjson=False) - logger.info("==== result from show evpn next-hops vni all") + logger.info("==== result from show evpn rmac vni all") logger.info(output) + + expected = { + "fd00::2/128": [ + { + "prefix": "fd00::2/128", + "vrfName": "r1-vrf-101", + "nexthops": [ + { + "ip": "::ffff:c0a8:6429", + } + ], + } + ] + } + result = topotest.router_json_cmp( + tgen.gears["r1"], "show ipv6 route vrf r1-vrf-101 fd00::2/128 json", expected + ) + assert result is None, "ipv6 route check failed" + + expected = { + "101": { + "numNextHops": 2, + "192.168.100.41": { + "nexthopIp": "192.168.100.41", + }, + "::ffff:c0a8:6429": { + "nexthopIp": "::ffff:c0a8:6429", + }, + } + } + result = topotest.router_json_cmp( + tgen.gears["r1"], "show evpn next-hops vni all json", expected + ) + assert result is None, "evpn next-hops check failed" + + expected = {"101": {"numRmacs": 1}} + result = topotest.router_json_cmp( + tgen.gears["r1"], "show evpn rmac vni all json", expected + ) + assert result is None, "evpn rmac number check failed" + # Check IPv4 and IPv6 connectivity between r1 and r2 ( routing vxlan evpn) pingrouter = tgen.gears["r1"] logger.info( @@ -209,6 +258,80 @@ def test_protocols_convergence(): else: logger.info("Check Ping IPv4 from R1(r1-vrf-101) to R2(192.168.101.41) OK") + logger.info("Check Ping IPv6 from R1(r1-vrf-101) to R2(r2-vrf-101 = fd00::2)") + output = pingrouter.run("ip netns exec r1-vrf-101 ping fd00::2 -f -c 1000") + logger.info(output) + if "1000 packets transmitted, 1000 received" not in output: + assert 0, "expected ping IPv6 from R1(r1-vrf-101) to R2(fd00::2) should be ok" + else: + logger.info("Check Ping IPv6 from R1(r1-vrf-101) to R2(fd00::2) OK") + + config_no_ipv6 = { + "r2": { + "raw_config": [ + "router bgp 65000 vrf r2-vrf-101", + "address-family ipv6 unicast", + "no network fd00::2/128", + ] + } + } + + logger.info("==== Remove IPv6 network on R2") + result = apply_raw_config(tgen, config_no_ipv6) + assert result is True, "Failed to remove IPv6 network on R2, Error: {} ".format( + result + ) + ipv6_routes = { + "r1": { + "static_routes": [ + { + "vrf": "r1-vrf-101", + "network": ["fd00::2/128"], + } + ] + } + } + result = verify_bgp_rib(tgen, "ipv6", "r1", ipv6_routes, expected=False) + assert result is not True, "expect IPv6 route fd00::2/128 withdrawn" + output = tgen.gears["r1"].vtysh_cmd("show evpn next-hops vni all", isjson=False) + logger.info("==== result from show evpn next-hops vni all") + logger.info(output) + output = tgen.gears["r1"].vtysh_cmd("show evpn rmac vni all", isjson=False) + logger.info("==== result from show evpn next-hops vni all") + logger.info(output) + + expected = { + "101": { + "numNextHops": 1, + "192.168.100.41": { + "nexthopIp": "192.168.100.41", + }, + } + } + result = topotest.router_json_cmp( + tgen.gears["r1"], "show evpn next-hops vni all json", expected + ) + assert result is None, "evpn next-hops check failed" + + expected = {"101": {"numRmacs": 1}} + result = topotest.router_json_cmp( + tgen.gears["r1"], "show evpn rmac vni all json", expected + ) + assert result is None, "evpn rmac number check failed" + + logger.info( + "Check Ping IPv4 from R1(r1-vrf-101) to R2(r2-vrf-101 = 192.168.101.41)" + ) + output = pingrouter.run("ip netns exec r1-vrf-101 ping 192.168.101.41 -f -c 1000") + logger.info(output) + if "1000 packets transmitted, 1000 received" not in output: + assertmsg = ( + "expected ping IPv4 from R1(r1-vrf-101) to R2(192.168.101.41) should be ok" + ) + assert 0, assertmsg + else: + logger.info("Check Ping IPv4 from R1(r1-vrf-101) to R2(192.168.101.41) OK") + def test_memory_leak(): "Run the memory leak test and report results." From f883c7119e76e264fb8045bf1884e436eb66527a Mon Sep 17 00:00:00 2001 From: Eugene Crosser Date: Tue, 2 Jul 2024 19:02:53 +0200 Subject: [PATCH 161/347] zebra: evpn: not coerce VTEP IP to IPv4 in nh_list In L3 BGP-EVPN, if there are both IPv4 and IPv6 routes in the VPN, zebra maintains two instances of `struct zebra_neigh` object: one with IPv4 address of the nexthop, and another with IPv6 address that is an IPv4 mapped to IPv6, but only one intance of `struct zebra_mac` object, that contains a list of nexthop addresses that use this mac. The code in `zebra_vxlan` module uses the fact that the list is empty as the indication that the `zebra_mac` object is unused, and needs to be dropped. However, preexisting code used nexthop address converted to IPv4 notation for the element of this list. As a result, when two `zebra_neigh` objects, one IPv4 and one IPv6-mapped-IPv4 were linked to the `zebra_mac` object, only one element was added to the list. Consequently, when one of the two `zebra_neigh` objects was dropped, the only element in the list was removed, making it empty, and `zebra_mac` object was dropped, and neigbrour cache elements uninstalled from the kernel. As a result, after the last route in _one_ family was removed from a remote vtep, all remaining routes in the _other_ family became unreachable, because RMAC of the vtep was removed. This commit makes `zebra_mac` use uncoerced IP address of the `zebra_neigh` object for the entries in the `nh_list`. This way, `zebra_mac` object no longer loses track of `zebra_neigh` objects that need it. Bug-URL: https://github.com/FRRouting/frr/issues/16340 Signed-off-by: Eugene Crosser --- zebra/zebra_vxlan.c | 78 ++++++++++++++++++++------------------------- 1 file changed, 34 insertions(+), 44 deletions(-) diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index b8c11e186a..f1ae42e320 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -1356,6 +1356,18 @@ static int zl3vni_remote_rmac_add(struct zebra_l3vni *zl3vni, { struct zebra_mac *zrmac = NULL; struct ipaddr *vtep = NULL; + struct ipaddr ipv4_vtep; + + /* vtep_ip may be v4 or v6-mapped-v4. But zrmac->fwd_info + * can only contain v4 version. So convert if needed + */ + memset(&ipv4_vtep, 0, sizeof(ipv4_vtep)); + ipv4_vtep.ipa_type = IPADDR_V4; + if (vtep_ip->ipa_type == IPADDR_V6) + ipv4_mapped_ipv6_to_ipv4(&vtep_ip->ipaddr_v6, + &(ipv4_vtep.ipaddr_v4)); + else + IPV4_ADDR_COPY(&(ipv4_vtep.ipaddr_v4), &vtep_ip->ipaddr_v4); zrmac = zl3vni_rmac_lookup(zl3vni, rmac); if (!zrmac) { @@ -1369,7 +1381,7 @@ static int zl3vni_remote_rmac_add(struct zebra_l3vni *zl3vni, return -1; } memset(&zrmac->fwd_info, 0, sizeof(zrmac->fwd_info)); - zrmac->fwd_info.r_vtep_ip = vtep_ip->ipaddr_v4; + zrmac->fwd_info.r_vtep_ip = ipv4_vtep.ipaddr_v4; vtep = XCALLOC(MTYPE_EVPN_VTEP, sizeof(struct ipaddr)); memcpy(vtep, vtep_ip, sizeof(struct ipaddr)); @@ -1383,14 +1395,14 @@ static int zl3vni_remote_rmac_add(struct zebra_l3vni *zl3vni, /* install rmac in kernel */ zl3vni_rmac_install(zl3vni, zrmac); } else if (!IPV4_ADDR_SAME(&zrmac->fwd_info.r_vtep_ip, - &vtep_ip->ipaddr_v4)) { + &(ipv4_vtep.ipaddr_v4))) { if (IS_ZEBRA_DEBUG_VXLAN) zlog_debug( "L3VNI %u Remote VTEP change(%pI4 -> %pIA) for RMAC %pEA", zl3vni->vni, &zrmac->fwd_info.r_vtep_ip, vtep_ip, rmac); - zrmac->fwd_info.r_vtep_ip = vtep_ip->ipaddr_v4; + zrmac->fwd_info.r_vtep_ip = ipv4_vtep.ipaddr_v4; vtep = XCALLOC(MTYPE_EVPN_VTEP, sizeof(struct ipaddr)); memcpy(vtep, vtep_ip, sizeof(struct ipaddr)); @@ -1410,36 +1422,29 @@ static void zl3vni_remote_rmac_del(struct zebra_l3vni *zl3vni, struct zebra_mac *zrmac, struct ipaddr *vtep_ip) { - struct ipaddr ipv4_vtep; - if (!zl3vni_nh_lookup(zl3vni, vtep_ip)) { - memset(&ipv4_vtep, 0, sizeof(ipv4_vtep)); - ipv4_vtep.ipa_type = IPADDR_V4; - if (vtep_ip->ipa_type == IPADDR_V6) - ipv4_mapped_ipv6_to_ipv4(&vtep_ip->ipaddr_v6, - &ipv4_vtep.ipaddr_v4); - else - memcpy(&(ipv4_vtep.ipaddr_v4), &vtep_ip->ipaddr_v4, - sizeof(struct in_addr)); - /* remove nh from rmac's list */ - l3vni_rmac_nh_list_nh_delete(zl3vni, zrmac, &ipv4_vtep); - /* delete nh is same as current selected, fall back to - * one present in the list - */ - if (IPV4_ADDR_SAME(&zrmac->fwd_info.r_vtep_ip, - &ipv4_vtep.ipaddr_v4) && - listcount(zrmac->nh_list)) { + l3vni_rmac_nh_list_nh_delete(zl3vni, zrmac, vtep_ip); + /* If there are remaining entries, use IPv4 from one */ + if (listcount(zrmac->nh_list)) { struct ipaddr *vtep; + struct ipaddr ipv4_vtep; vtep = listgetdata(listhead(zrmac->nh_list)); - zrmac->fwd_info.r_vtep_ip = vtep->ipaddr_v4; + memset(&ipv4_vtep, 0, sizeof(ipv4_vtep)); + ipv4_vtep.ipa_type = IPADDR_V4; + if (vtep->ipa_type == IPADDR_V6) + ipv4_mapped_ipv6_to_ipv4(&vtep->ipaddr_v6, + &(ipv4_vtep.ipaddr_v4)); + else + IPV4_ADDR_COPY(&(ipv4_vtep.ipaddr_v4), + &vtep->ipaddr_v4); + zrmac->fwd_info.r_vtep_ip = ipv4_vtep.ipaddr_v4; if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug( - "L3VNI %u Remote VTEP nh change(%pIA -> %pI4) for RMAC %pEA", - zl3vni->vni, &ipv4_vtep, - &zrmac->fwd_info.r_vtep_ip, - &zrmac->macaddr); + zlog_debug("L3VNI %u Remote VTEP nh change(%pIA -> %pI4) for RMAC %pEA", + zl3vni->vni, vtep_ip, + &zrmac->fwd_info.r_vtep_ip, + &zrmac->macaddr); /* install rmac in kernel */ zl3vni_rmac_install(zl3vni, zrmac); @@ -2531,7 +2536,6 @@ void zebra_vxlan_evpn_vrf_route_add(vrf_id_t vrf_id, const struct ethaddr *rmac, const struct prefix *host_prefix) { struct zebra_l3vni *zl3vni = NULL; - struct ipaddr ipv4_vtep; zl3vni = zl3vni_from_vrf(vrf_id); if (!zl3vni || !is_l3vni_oper_up(zl3vni)) @@ -2547,24 +2551,10 @@ void zebra_vxlan_evpn_vrf_route_add(vrf_id_t vrf_id, const struct ethaddr *rmac, svd_remote_nh_add(zl3vni, vtep_ip, rmac, host_prefix); /* - * if the remote vtep is a ipv4 mapped ipv6 address convert it to ipv4 - * address. Rmac is programmed against the ipv4 vtep because we only - * support ipv4 tunnels in the h/w right now - */ - memset(&ipv4_vtep, 0, sizeof(ipv4_vtep)); - ipv4_vtep.ipa_type = IPADDR_V4; - if (vtep_ip->ipa_type == IPADDR_V6) - ipv4_mapped_ipv6_to_ipv4(&vtep_ip->ipaddr_v6, - &(ipv4_vtep.ipaddr_v4)); - else - memcpy(&(ipv4_vtep.ipaddr_v4), &vtep_ip->ipaddr_v4, - sizeof(struct in_addr)); - - /* - * add the rmac - remote rmac to be installed is against the ipv4 + * add the rmac - remote rmac to be installed is against the * nexthop address */ - zl3vni_remote_rmac_add(zl3vni, rmac, &ipv4_vtep); + zl3vni_remote_rmac_add(zl3vni, rmac, vtep_ip); } /* handle evpn vrf route delete */ From 7dfe12eef838f2a8be15e8c58e47f4bcd8b64239 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Wed, 3 Jul 2024 14:37:52 +0200 Subject: [PATCH 162/347] topotests: bgp_peer_type_multipath_relax, adds the duplicate flag During the bgp_peer_type_multipath_relax_test, the test does not check the 'duplicate' flag value of the duplicate nexthop. Fix this by adding the duplicate value in the expected json files. Fixes: ee88563ac2ea ("bgpd: Add 'bgp bestpath peer-type multipath-relax'") Signed-off-by: Philippe Guibert --- .../bgp_peer_type_multipath_relax/r1/prefix1-eBGP-confed.json | 1 + .../bgp_peer_type_multipath_relax/r1/prefix1-eBGP-iBGP.json | 1 + 2 files changed, 2 insertions(+) diff --git a/tests/topotests/bgp_peer_type_multipath_relax/r1/prefix1-eBGP-confed.json b/tests/topotests/bgp_peer_type_multipath_relax/r1/prefix1-eBGP-confed.json index 22ec2c298b..791b92df65 100644 --- a/tests/topotests/bgp_peer_type_multipath_relax/r1/prefix1-eBGP-confed.json +++ b/tests/topotests/bgp_peer_type_multipath_relax/r1/prefix1-eBGP-confed.json @@ -24,6 +24,7 @@ }, { "fib":true, + "duplicate":true, "ip":"10.0.3.2", "active":true } diff --git a/tests/topotests/bgp_peer_type_multipath_relax/r1/prefix1-eBGP-iBGP.json b/tests/topotests/bgp_peer_type_multipath_relax/r1/prefix1-eBGP-iBGP.json index facddcda46..1fe9a6799f 100644 --- a/tests/topotests/bgp_peer_type_multipath_relax/r1/prefix1-eBGP-iBGP.json +++ b/tests/topotests/bgp_peer_type_multipath_relax/r1/prefix1-eBGP-iBGP.json @@ -24,6 +24,7 @@ }, { "fib":true, + "duplicate":true, "ip":"10.0.3.2", "active":true } From 731f74e35fa2c1636208f4bf64650d2d00a199b4 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Wed, 3 Jul 2024 08:51:51 +0200 Subject: [PATCH 163/347] zebra, topotests: do not set nexthop's FIB flag when DUPLICATE present The bgp_duplicate_nexthop test installs routes with nexthop's flags set to both DUPLICATE and FIB: this should not happen. The DUPLICATE flag of a nexthop indicates this nexthop is already used in the same nexthop-group, and there is no need to install it twice in the system; having the FIB flag set indicates that the nexthop is installed in the system. This is why both flags should not be set on the same nexthop. This case happens at installation time, but can also happen at update time. - Fix this by not setting the FIB flag value when the DUPLICATE flag is present. - Modify the bgp_duplicate_test to check that the FIB flag is not present on duplicated nexthops. - Modify the bgp_peer_type_multipath_relax test. Signed-off-by: Philippe Guibert --- .../test_bgp_duplicate_nexthop.py | 2 +- .../r1/prefix1-eBGP-confed.json | 1 - .../r1/prefix1-eBGP-iBGP.json | 1 - tests/topotests/lib/common_check.py | 27 +++++++++++++++---- zebra/zebra_dplane.c | 4 +++ zebra/zebra_rib.c | 3 +++ 6 files changed, 30 insertions(+), 8 deletions(-) diff --git a/tests/topotests/bgp_duplicate_nexthop/test_bgp_duplicate_nexthop.py b/tests/topotests/bgp_duplicate_nexthop/test_bgp_duplicate_nexthop.py index 955881e6f9..83fae71bf5 100644 --- a/tests/topotests/bgp_duplicate_nexthop/test_bgp_duplicate_nexthop.py +++ b/tests/topotests/bgp_duplicate_nexthop/test_bgp_duplicate_nexthop.py @@ -320,7 +320,7 @@ def check_ipv4_prefix_recursive_with_multiple_nexthops( ) test_func = functools.partial( - ip_check_path_selection, tgen.gears["r1"], prefix, expected + ip_check_path_selection, tgen.gears["r1"], prefix, expected, check_fib=True ) _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert ( diff --git a/tests/topotests/bgp_peer_type_multipath_relax/r1/prefix1-eBGP-confed.json b/tests/topotests/bgp_peer_type_multipath_relax/r1/prefix1-eBGP-confed.json index 791b92df65..483165c0f3 100644 --- a/tests/topotests/bgp_peer_type_multipath_relax/r1/prefix1-eBGP-confed.json +++ b/tests/topotests/bgp_peer_type_multipath_relax/r1/prefix1-eBGP-confed.json @@ -23,7 +23,6 @@ "recursive":true }, { - "fib":true, "duplicate":true, "ip":"10.0.3.2", "active":true diff --git a/tests/topotests/bgp_peer_type_multipath_relax/r1/prefix1-eBGP-iBGP.json b/tests/topotests/bgp_peer_type_multipath_relax/r1/prefix1-eBGP-iBGP.json index 1fe9a6799f..638a825395 100644 --- a/tests/topotests/bgp_peer_type_multipath_relax/r1/prefix1-eBGP-iBGP.json +++ b/tests/topotests/bgp_peer_type_multipath_relax/r1/prefix1-eBGP-iBGP.json @@ -23,7 +23,6 @@ "recursive":true }, { - "fib":true, "duplicate":true, "ip":"10.0.3.2", "active":true diff --git a/tests/topotests/lib/common_check.py b/tests/topotests/lib/common_check.py index be3241fd20..19f02dbadc 100644 --- a/tests/topotests/lib/common_check.py +++ b/tests/topotests/lib/common_check.py @@ -10,11 +10,13 @@ from lib import topotest -def ip_check_path_selection(router, ipaddr_str, expected, vrf_name=None): +def ip_check_path_selection( + router, ipaddr_str, expected, vrf_name=None, check_fib=False +): if vrf_name: - cmdstr = f'show ip route vrf {vrf_name} {ipaddr_str} json' + cmdstr = f"show ip route vrf {vrf_name} {ipaddr_str} json" else: - cmdstr = f'show ip route {ipaddr_str} json' + cmdstr = f"show ip route {ipaddr_str} json" try: output = json.loads(router.vtysh_cmd(cmdstr)) except: @@ -25,6 +27,21 @@ def ip_check_path_selection(router, ipaddr_str, expected, vrf_name=None): num_nh_expected = len(expected[ipaddr_str][0]["nexthops"]) num_nh_observed = len(output[ipaddr_str][0]["nexthops"]) if num_nh_expected == num_nh_observed: + if check_fib: + # special case: when fib flag is unset, + # an extra test should be done to check that the flag is really unset + for nh_output, nh_expected in zip( + output[ipaddr_str][0]["nexthops"], + expected[ipaddr_str][0]["nexthops"], + ): + if ( + "fib" in nh_output.keys() + and nh_output["fib"] + and ("fib" not in nh_expected.keys() or not nh_expected["fib"]) + ): + return "{}, prefix {} nexthop {} has the fib flag set, whereas it is not expected".format( + router.name, ipaddr_str, nh_output["ip"] + ) return ret return "{}, prefix {} does not have the correct number of nexthops : observed {}, expected {}".format( router.name, ipaddr_str, num_nh_observed, num_nh_expected @@ -37,9 +54,9 @@ def iproute2_check_path_selection(router, ipaddr_str, expected, vrf_name=None): return None if vrf_name: - cmdstr = f'ip -json route show vrf {vrf_name} {ipaddr_str}' + cmdstr = f"ip -json route show vrf {vrf_name} {ipaddr_str}" else: - cmdstr = f'ip -json route show {ipaddr_str}' + cmdstr = f"ip -json route show {ipaddr_str}" try: output = json.loads(cmdstr) except: diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c index 7910559c4b..0844b34672 100644 --- a/zebra/zebra_dplane.c +++ b/zebra/zebra_dplane.c @@ -4314,6 +4314,10 @@ dplane_route_update_internal(struct route_node *rn, NEXTHOP_FLAG_RECURSIVE)) continue; + if (CHECK_FLAG(nexthop->flags, + NEXTHOP_FLAG_DUPLICATE)) + continue; + if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) SET_FLAG(nexthop->flags, diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index b176ea2fe6..142f83fb36 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -1659,6 +1659,9 @@ static bool rib_update_nhg_from_ctx(struct nexthop_group *re_nhg, if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) continue; + if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_DUPLICATE)) + continue; + /* Check for a FIB nexthop corresponding to the RIB nexthop */ if (!nexthop_same(ctx_nexthop, nexthop)) { /* If the FIB doesn't know about the nexthop, From 54b72028c6059c8c69ec77335a5e828884fffbfe Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Wed, 10 Jul 2024 09:49:51 +0200 Subject: [PATCH 164/347] ospfd: fix state location mixup In the "2x2 matrix" of these, I accidentally edited "row-wise" when I should've edited "column-wise"... *sigh* Reported-by: github.com/rbfnet Fixes: #16349 Fixes: 110945ba0d2 ("ospfd: fix GR state location") Signed-off-by: David Lamparter --- ospfd/ospf_main.c | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/ospfd/ospf_main.c b/ospfd/ospf_main.c index fdb4e5c587..5c11027506 100644 --- a/ospfd/ospf_main.c +++ b/ospfd/ospf_main.c @@ -48,14 +48,20 @@ #include "ospfd/ospf_apiserver.h" #define OSPFD_STATE_NAME "%s/ospfd.json", frr_libstatedir -#define OSPFD_INST_STATE_NAME(i) "%s/ospfd-%d.json", frr_runstatedir, i +#define OSPFD_INST_STATE_NAME(i) "%s/ospfd-%d.json", frr_libstatedir, i /* this one includes the path... because the instance number was in the path * before :( ... which totally didn't have a mkdir anywhere. + * + * ... and libstatedir & runstatedir got switched around while changing this; + * for non-instance it read the wrong path, for instance it wrote the wrong + * path. (There is no COMPAT2 for non-instance because it was writing to the + * right place, i.e. no extra path to check exists from reading a wrong path.) */ -#define OSPFD_COMPAT_STATE_NAME "%s/ospfd-gr.json", frr_libstatedir -#define OSPFD_COMPAT_INST_STATE_NAME(i) \ +#define OSPFD_COMPAT_STATE_NAME "%s/ospfd-gr.json", frr_runstatedir +#define OSPFD_COMPAT1_INST_STATE_NAME(i) \ "%s-%d/ospfd-gr.json", frr_runstatedir, i +#define OSPFD_COMPAT2_INST_STATE_NAME(i) "%s/ospfd-%d.json", frr_runstatedir, i /* ospfd privileges */ zebra_capabilities_t _caps_p[] = {ZCAP_NET_RAW, ZCAP_BIND, ZCAP_NET_ADMIN, @@ -139,10 +145,12 @@ static const struct frr_yang_module_info *const ospfd_yang_modules[] = { /* actual paths filled in main() */ static char state_path[512]; -static char state_compat_path[512]; +static char state_compat1_path[512]; +static char state_compat2_path[512]; static char *state_paths[] = { state_path, - state_compat_path, + state_compat1_path, + state_compat2_path, /* NULLed out if not needed */ NULL, }; @@ -242,12 +250,18 @@ int main(int argc, char **argv) if (ospf_instance) { snprintf(state_path, sizeof(state_path), OSPFD_INST_STATE_NAME(ospf_instance)); - snprintf(state_compat_path, sizeof(state_compat_path), - OSPFD_COMPAT_INST_STATE_NAME(ospf_instance)); + snprintf(state_compat1_path, sizeof(state_compat1_path), + OSPFD_COMPAT1_INST_STATE_NAME(ospf_instance)); + snprintf(state_compat2_path, sizeof(state_compat2_path), + OSPFD_COMPAT2_INST_STATE_NAME(ospf_instance)); } else { snprintf(state_path, sizeof(state_path), OSPFD_STATE_NAME); - snprintf(state_compat_path, sizeof(state_compat_path), + snprintf(state_compat1_path, sizeof(state_compat1_path), OSPFD_COMPAT_STATE_NAME); + /* no COMPAT2 here since it was reading that was broken, + * there is no additional path that would've been written + */ + state_paths[2] = NULL; } /* OSPF master init. */ From ae885a7e7fcdf91db9f72bb9e3c637903775146f Mon Sep 17 00:00:00 2001 From: Y Bharath Date: Thu, 6 Jun 2024 18:49:07 +0530 Subject: [PATCH 165/347] babel: Added null check after retrieving babel_ifp Asserting the further instructions when the babel interface pointer is NULL Signed-off-by: y-bharath14 --- babeld/babel_interface.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/babeld/babel_interface.c b/babeld/babel_interface.c index c4349b509e..76ecd4fe4e 100644 --- a/babeld/babel_interface.c +++ b/babeld/babel_interface.c @@ -108,6 +108,7 @@ babel_interface_address_add (ZAPI_CALLBACK_ARGS) if (prefix->family == AF_INET) { flush_interface_routes(ifc->ifp, 0); babel_ifp = babel_get_if_nfo(ifc->ifp); + assert (babel_ifp != NULL); if (babel_ifp->ipv4 == NULL) { babel_ifp->ipv4 = malloc(4); if (babel_ifp->ipv4 == NULL) { @@ -144,6 +145,7 @@ babel_interface_address_delete (ZAPI_CALLBACK_ARGS) if (prefix->family == AF_INET) { flush_interface_routes(ifc->ifp, 0); babel_ifp = babel_get_if_nfo(ifc->ifp); + assert (babel_ifp != NULL); if (babel_ifp->ipv4 != NULL && memcmp(babel_ifp->ipv4, &prefix->u.prefix4, IPV4_MAX_BYTELEN) == 0) { @@ -542,7 +544,10 @@ DEFPY (babel_set_channel, unsigned jitter(babel_interface_nfo *babel_ifp, int urgent) { - unsigned interval = babel_ifp->hello_interval; + unsigned interval; + + assert (babel_ifp != NULL); + interval = babel_ifp->hello_interval; if(urgent) interval = MIN(interval, 100); else @@ -553,7 +558,10 @@ jitter(babel_interface_nfo *babel_ifp, int urgent) unsigned update_jitter(babel_interface_nfo *babel_ifp, int urgent) { - unsigned interval = babel_ifp->hello_interval; + unsigned interval; + + assert (babel_ifp != NULL); + interval = babel_ifp->hello_interval; if(urgent) interval = MIN(interval, 100); else @@ -566,10 +574,11 @@ update_jitter(babel_interface_nfo *babel_ifp, int urgent) static int interface_recalculate(struct interface *ifp) { - babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); unsigned char *tmp = NULL; int mtu, rc; struct ipv6_mreq mreq; + babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); + assert (babel_ifp != NULL); if (!IS_ENABLE(ifp)) return -1; @@ -656,6 +665,7 @@ interface_reset(struct interface *ifp) int rc; struct ipv6_mreq mreq; babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); + assert (babel_ifp != NULL); if (!CHECK_FLAG(babel_ifp->flags, BABEL_IF_IS_UP)) return 0; @@ -777,6 +787,7 @@ show_babel_interface_sub (struct vty *vty, struct interface *ifp) return; } babel_ifp = babel_get_if_nfo (ifp); + assert (babel_ifp != NULL); vty_out (vty, " Babel protocol is running on this interface\n"); vty_out (vty, " Operating mode is \"%s\"\n", CHECK_FLAG(babel_ifp->flags, BABEL_IF_WIRED) ? "wired" : "wireless"); @@ -1228,6 +1239,7 @@ interface_config_write (struct vty *vty) if (ifp->desc) vty_out (vty, " description %s\n",ifp->desc); babel_interface_nfo *babel_ifp = babel_get_if_nfo (ifp); + assert (babel_ifp != NULL); /* wireless is the default*/ if (CHECK_FLAG (babel_ifp->flags, BABEL_IF_WIRED)) { @@ -1330,6 +1342,7 @@ babel_interface_allocate (void) { babel_interface_nfo *babel_ifp; babel_ifp = XCALLOC(MTYPE_BABEL_IF, sizeof(babel_interface_nfo)); + assert (babel_ifp != NULL); /* All flags are unset */ babel_ifp->bucket_time = babel_now.tv_sec; babel_ifp->bucket = BUCKET_TOKENS_MAX; @@ -1349,6 +1362,8 @@ babel_interface_allocate (void) static void babel_interface_free (babel_interface_nfo *babel_ifp) { + assert (babel_ifp != NULL); + if (babel_ifp->ipv4){ free(babel_ifp->ipv4); babel_ifp->ipv4 = NULL; From e905177a8c9d67713682d46934c7a87a0913c250 Mon Sep 17 00:00:00 2001 From: zhou-run Date: Thu, 11 Jul 2024 11:35:34 +0800 Subject: [PATCH 166/347] isisd: fix crash when calculating the neighbor spanning tree based on the fragmented LSP 1. When the root IS regenerates an LSP, it calls lsp_build() -> lsp_clear_data() to free the TLV memory of the first fragment and all other fragments. If the number of fragments in the regenerated LSP decreases or if no fragmentation is needed, the extra LSP fragments are not immediately deleted. Instead, lsp_seqno_update() -> lsp_purge() is called to set the remaining time to zero and start aging, while also notifying other IS nodes to age these fragments. lsp_purge() usually does not reset lsp->hdr.seqno to zero because the LSP might recover during the aging process. 2. When other IS nodes receive an LSP, they always call process_lsp() -> isis_unpack_tlvs() to allocate TLV memory for the LSP. This does not differentiate whether the received LSP has a remaining lifetime of zero. Therefore, it is rare for an LSP of a non-root IS to have empty TLVs. Of course, if an LSP with a remaining time of zero and already corrupted is received, lsp_update() -> lsp_purge() will be called to free the TLV memory of the LSP, but this scenario is rare. 3. In LFA calculations, neighbors of the root IS are traversed, and each neighbor is taken as a new root to compute the neighbor SPT. During this process, the old root IS will serve as a neighbor of the new root IS, triggering a call to isis_spf_process_lsp() to parse the LSP of the old root IS and obtain its IP vertices and neighboring IS vertices. However, isis_spf_process_lsp() only checks whether the TLVs in the first fragment of the LSP exist, and does not check the TLVs in the fragmented LSP. If the TLV memory of the fragmented LSP of the old root IS has been freed, it can lead to a null pointer access, causing the current crash. Additionally, for the base SPT, there are only two places where the LSP of the root IS is parsed: 1. When obtaining the UP neighbors of the root IS via spf_adj_list_parse_lsp(). 2. When preloading the IP vertices of the root IS via isis_lsp_iterate_ip_reach(). Both of these checks ensure that frag->tlvs is not null, and they do not subsequently call isis_spf_process_lsp() to parse the root IS's LSP. It is very rare for non-root IS LSPs to have empty TLVs unless they are corrupted LSPs awaiting deletion. If it happens, a crash will occur. The backtrace is as follows: (gdb) bt #0 0x00007f3097281fe1 in raise () from /lib/x86_64-linux-gnu/libpthread.so.0 #1 0x00007f30973a2972 in core_handler (signo=11, siginfo=0x7ffce66c2870, context=0x7ffce66c2740) at ../lib/sigevent.c:261 #2 #3 0x000055dfa805512b in isis_spf_process_lsp (spftree=0x55dfa950eee0, lsp=0x55dfa94cb590, cost=10, depth=1, root_sysid=0x55dfa950ef6c "", parent=0x55dfa952fca0) at ../isisd/isis_spf.c:898 #4 0x000055dfa805743b in isis_spf_loop (spftree=0x55dfa950eee0, root_sysid=0x55dfa950ef6c "") at ../isisd/isis_spf.c:1688 #5 0x000055dfa805784f in isis_run_spf (spftree=0x55dfa950eee0) at ../isisd/isis_spf.c:1808 #6 0x000055dfa8037ff5 in isis_spf_run_neighbors (spftree=0x55dfa9474440) at ../isisd/isis_lfa.c:1259 #7 0x000055dfa803ac17 in isis_spf_run_lfa (area=0x55dfa9477510, spftree=0x55dfa9474440) at ../isisd/isis_lfa.c:2300 #8 0x000055dfa8057964 in isis_run_spf_with_protection (area=0x55dfa9477510, spftree=0x55dfa9474440) at ../isisd/isis_spf.c:1827 #9 0x000055dfa8057c15 in isis_run_spf_cb (thread=0x7ffce66c38e0) at ../isisd/isis_spf.c:1889 #10 0x00007f30973bbf04 in thread_call (thread=0x7ffce66c38e0) at ../lib/thread.c:1990 #11 0x00007f309735497b in frr_run (master=0x55dfa91733c0) at ../lib/libfrr.c:1198 #12 0x000055dfa8029d5d in main (argc=5, argv=0x7ffce66c3b08, envp=0x7ffce66c3b38) at ../isisd/isis_main.c:273 (gdb) f 3 #3 0x000055dfa805512b in isis_spf_process_lsp (spftree=0x55dfa950eee0, lsp=0x55dfa94cb590, cost=10, depth=1, root_sysid=0x55dfa950ef6c "", parent=0x55dfa952fca0) at ../isisd/isis_spf.c:898 898 ../isisd/isis_spf.c: No such file or directory. (gdb) p te_neighs $1 = (struct isis_item_list *) 0x120 (gdb) p lsp->tlvs $2 = (struct isis_tlvs *) 0x0 (gdb) p lsp->hdr $3 = {pdu_len = 27, rem_lifetime = 0, lsp_id = "\000\000\000\000\000\001\000\001", seqno = 4, checksum = 59918, lsp_bits = 1 '\001'} The backtrace provided above pertains to version 8.5.4, but it seems that the same issue exists in the code of the master branch as well. I have reviewed the process for calculating the SPT based on the LSP, and isis_spf_process_lsp() is the only function that does not check whether the TLVs in the fragments are empty. Therefore, I believe that modifying this function alone should be sufficient. If the TLVs of the current fragment are already empty, we do not need to continue processing subsequent fragments. This is consistent with the behavior where we do not process fragments if the TLVs of the first fragment are empty. Of course, one could argue that lsp_purge() should still retain the TLV memory, freeing it and then reallocating it if needed. However, this is a debatable point because in some scenarios, it is permissible for the LSP to have empty TLVs. For example, after receiving an SNP (Sequence Number PDU) message, an empty LSP (with lsp->hdr.seqno = 0) might be created by calling lsp_new. If the corresponding LSP message is discarded due to domain or area authentication failure, the TLV memory wouldn't be allocated. Test scenario: In an LFA network, importing a sufficient number of static routes to cause LSP fragmentation, and then rolling back the imported static routes so that the LSP is no longer fragmented, can easily result in this issue. Signed-off-by: zhou-run --- isisd/isis_spf.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/isisd/isis_spf.c b/isisd/isis_spf.c index 7aa9147e71..86302076f8 100644 --- a/isisd/isis_spf.c +++ b/isisd/isis_spf.c @@ -873,6 +873,9 @@ static int isis_spf_process_lsp(struct isis_spftree *spftree, || (mt_router_info && !mt_router_info->overload)); lspfragloop: + if (!lsp->tlvs) + return ISIS_OK; + if (lsp->hdr.seqno == 0) { zlog_warn("%s: lsp with 0 seq_num - ignore", __func__); return ISIS_WARNING; From 6ade526f7b14a725d61c98700d403dea050ccd85 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Thu, 11 Jul 2024 05:38:36 +0200 Subject: [PATCH 167/347] lib: add some quick explainers for path vars It's not immediately obvious what exactly the `frr_*dir` variables exported from lib/libfrr.c are for. Add a little text each to clarify. Signed-off-by: David Lamparter --- lib/libfrr.h | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/lib/libfrr.h b/lib/libfrr.h index db9cfbcb1f..8018672c1a 100644 --- a/lib/libfrr.h +++ b/lib/libfrr.h @@ -222,10 +222,39 @@ extern void frr_fini(void); extern char config_default[512]; extern char frr_zclientpath[512]; + +/* refer to lib/config_paths.h (generated during ./configure) for build config + * values of the following: + */ + +/* sysconfdir is generally /etc/frr/, some BSDs may use /usr/local/etc/frr/. + * Will NOT include "pathspace" (namespace) suffix from -N. (libfrr.c handles + * pathspace'ing config files.) Has a slash at the end for "historical" + * reasons. + */ extern const char frr_sysconfdir[]; + +/* runstatedir is *ephemeral* across reboots. It may either be a ramdisk, + * or be wiped during boot. Use only for pid files, sockets, and the like, + * not state. Commonly /run/frr or /var/run/frr. + * Will include "pathspace" (namespace) suffix from -N. + */ extern char frr_runstatedir[256]; + +/* libstatedir is *persistent*. It's the place to put state like sequence + * numbers or databases. Commonly /var/lib/frr. + * Will include "pathspace" (namespace) suffix from -N. + */ extern char frr_libstatedir[256]; + +/* moduledir is something along the lines of /usr/lib/frr/modules or + * /usr/lib/x86_64-linux-gnu/frr/modules. It is not guaranteed to be a + * subdirectory of the directory that the daemon binaries reside in. (e.g. + * the "x86_64-linux-gnu" component will be absent from daemon paths.) + */ extern const char frr_moduledir[]; + +/* scriptdir is for Lua scripts, generally ${frr_sysconfdir}/scripts */ extern const char frr_scriptdir[]; extern char frr_protoname[]; From 4e76df05476e728d3bdd53821c0f20e4139db1f8 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Fri, 22 Dec 2023 11:35:09 +0100 Subject: [PATCH 168/347] isis, lib: add isis srv6 end sid to ls_prefix According to draft-ietf-lsr-isis-srv6-extensions draft, the End SID should be available in link state prefix information. Add the SID information in the link state prefix, by getting the END SID from the locator TLV information. Signed-off-by: Philippe Guibert --- isisd/isis_lsp.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++ isisd/isis_lsp.h | 2 ++ isisd/isis_te.c | 45 +++++++++++++++++++++++++++++++++++++++++-- isisd/isis_te.h | 1 + lib/link_state.c | 36 +++++++++++++++++++++++++++++++++- lib/link_state.h | 6 ++++++ 6 files changed, 137 insertions(+), 3 deletions(-) diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c index bda7ed89a4..391d42fba1 100644 --- a/isisd/isis_lsp.c +++ b/isisd/isis_lsp.c @@ -2340,6 +2340,56 @@ static int lsp_handle_adj_state_change(struct isis_adjacency *adj) return 0; } +/* + * Iterate over all SRv6 locator TLVs + */ +int isis_lsp_iterate_srv6_locator(struct isis_lsp *lsp, uint16_t mtid, + lsp_ip_reach_iter_cb cb, void *arg) +{ + bool pseudo_lsp = LSP_PSEUDO_ID(lsp->hdr.lsp_id); + struct isis_lsp *frag; + struct listnode *node; + + if (lsp->hdr.seqno == 0 || lsp->hdr.rem_lifetime == 0) + return LSP_ITER_CONTINUE; + + /* Parse LSP */ + if (lsp->tlvs) { + if (!pseudo_lsp) { + struct isis_item_list *srv6_locator_reachs; + struct isis_srv6_locator_tlv *r; + + srv6_locator_reachs = + isis_lookup_mt_items(&lsp->tlvs->srv6_locator, + mtid); + + for (r = srv6_locator_reachs + ? (struct isis_srv6_locator_tlv *) + srv6_locator_reachs->head + : NULL; + r; r = r->next) { + if ((*cb)((struct prefix *)&r->prefix, + r->metric, false /* ignore */, + r->subtlvs, arg) == LSP_ITER_STOP) + return LSP_ITER_STOP; + } + } + } + + /* Parse LSP fragments if it is not a fragment itself */ + if (!LSP_FRAGMENT(lsp->hdr.lsp_id)) + for (ALL_LIST_ELEMENTS_RO(lsp->lspu.frags, node, frag)) { + if (!frag->tlvs) + continue; + + if (isis_lsp_iterate_srv6_locator(frag, mtid, cb, + arg) == LSP_ITER_STOP) + return LSP_ITER_STOP; + } + + return LSP_ITER_CONTINUE; +} + /* * Iterate over all IP reachability TLVs in a LSP (all fragments) of the given * address-family and MT-ID. diff --git a/isisd/isis_lsp.h b/isisd/isis_lsp.h index 3839a9504c..15db88b02f 100644 --- a/isisd/isis_lsp.h +++ b/isisd/isis_lsp.h @@ -143,6 +143,8 @@ int isis_lsp_iterate_ip_reach(struct isis_lsp *lsp, int family, uint16_t mtid, lsp_ip_reach_iter_cb cb, void *arg); int isis_lsp_iterate_is_reach(struct isis_lsp *lsp, uint16_t mtid, lsp_is_reach_iter_cb cb, void *arg); +int isis_lsp_iterate_srv6_locator(struct isis_lsp *lsp, uint16_t mtid, + lsp_ip_reach_iter_cb cb, void *arg); #define lsp_flood(lsp, circuit) \ _lsp_flood((lsp), (circuit), __func__, __FILE__, __LINE__) diff --git a/isisd/isis_te.c b/isisd/isis_te.c index 3683f74558..bb73a44257 100644 --- a/isisd/isis_te.c +++ b/isisd/isis_te.c @@ -1258,8 +1258,11 @@ static int lsp_to_subnet_cb(const struct prefix *prefix, uint32_t metric, if (!args || !prefix) return LSP_ITER_CONTINUE; - te_debug(" |- Process Extended %s Reachability %pFX", - prefix->family == AF_INET ? "IP" : "IPv6", prefix); + if (args->srv6_locator) + te_debug(" |- Process SRv6 Locator %pFX", prefix); + else + te_debug(" |- Process Extended %s Reachability %pFX", + prefix->family == AF_INET ? "IP" : "IPv6", prefix); vertex = args->vertex; @@ -1386,6 +1389,38 @@ static int lsp_to_subnet_cb(const struct prefix *prefix, uint32_t metric, } } + /* Update SRv6 SID and locator if any */ + if (subtlvs && subtlvs->srv6_end_sids.count != 0) { + struct isis_srv6_end_sid_subtlv *psid; + struct ls_srv6_sid sr = {}; + + psid = (struct isis_srv6_end_sid_subtlv *) + subtlvs->srv6_end_sids.head; + sr.behavior = psid->behavior; + sr.flags = psid->flags; + memcpy(&sr.sid, &psid->sid, sizeof(struct in6_addr)); + + if (!CHECK_FLAG(ls_pref->flags, LS_PREF_SRV6) || + memcmp(&ls_pref->srv6, &sr, sizeof(struct ls_srv6_sid))) { + memcpy(&ls_pref->srv6, &sr, sizeof(struct ls_srv6_sid)); + SET_FLAG(ls_pref->flags, LS_PREF_SRV6); + if (subnet->status != NEW) + subnet->status = UPDATE; + } else { + if (subnet->status == ORPHAN) + subnet->status = SYNC; + } + } else { + if (CHECK_FLAG(ls_pref->flags, LS_PREF_SRV6)) { + UNSET_FLAG(ls_pref->flags, LS_PREF_SRV6); + if (subnet->status != NEW) + subnet->status = UPDATE; + } else { + if (subnet->status == ORPHAN) + subnet->status = SYNC; + } + } + /* Update status and Export Link State Edge if needed */ if (subnet->status != SYNC) { if (args->export) @@ -1454,12 +1489,18 @@ static void isis_te_parse_lsp(struct mpls_te_area *mta, struct isis_lsp *lsp) &args); /* Process all Extended IP (v4 & v6) in LSP (all fragments) */ + args.srv6_locator = false; isis_lsp_iterate_ip_reach(lsp, AF_INET, ISIS_MT_IPV4_UNICAST, lsp_to_subnet_cb, &args); isis_lsp_iterate_ip_reach(lsp, AF_INET6, ISIS_MT_IPV6_UNICAST, lsp_to_subnet_cb, &args); isis_lsp_iterate_ip_reach(lsp, AF_INET6, ISIS_MT_IPV4_UNICAST, lsp_to_subnet_cb, &args); + args.srv6_locator = true; + isis_lsp_iterate_srv6_locator(lsp, ISIS_MT_STANDARD, lsp_to_subnet_cb, + &args); + isis_lsp_iterate_srv6_locator(lsp, ISIS_MT_IPV6_UNICAST, + lsp_to_subnet_cb, &args); /* Clean remaining Orphan Edges or Subnets */ if (IS_EXPORT_TE(mta)) diff --git a/isisd/isis_te.h b/isisd/isis_te.h index bf1dc2b9bb..532a24e7e4 100644 --- a/isisd/isis_te.h +++ b/isisd/isis_te.h @@ -103,6 +103,7 @@ struct isis_te_args { struct ls_ted *ted; struct ls_vertex *vertex; bool export; + bool srv6_locator; }; enum lsp_event { LSP_UNKNOWN, LSP_ADD, LSP_UPD, LSP_DEL, LSP_INC, LSP_TICK }; diff --git a/lib/link_state.c b/lib/link_state.c index c758b7f575..3d96c75f6d 100644 --- a/lib/link_state.c +++ b/lib/link_state.c @@ -414,6 +414,13 @@ int ls_prefix_same(struct ls_prefix *p1, struct ls_prefix *p2) || (p1->sr.sid_flag != p2->sr.sid_flag)) return 0; } + if (CHECK_FLAG(p1->flags, LS_PREF_SRV6)) { + if (memcmp(&p1->srv6.sid, &p2->srv6.sid, + sizeof(struct in6_addr)) || + (p1->srv6.flags != p2->srv6.flags) || + (p1->srv6.behavior != p2->srv6.behavior)) + return 0; + } /* OK, p1 & p2 are equal */ return 1; @@ -1388,6 +1395,11 @@ static struct ls_prefix *ls_parse_prefix(struct stream *s) STREAM_GETC(s, ls_pref->sr.sid_flag); STREAM_GETC(s, ls_pref->sr.algo); } + if (CHECK_FLAG(ls_pref->flags, LS_PREF_SRV6)) { + STREAM_GET(&ls_pref->srv6.sid, s, sizeof(struct in6_addr)); + STREAM_GETW(s, ls_pref->srv6.behavior); + STREAM_GETC(s, ls_pref->srv6.flags); + } return ls_pref; @@ -1632,6 +1644,11 @@ static int ls_format_prefix(struct stream *s, struct ls_prefix *ls_pref) stream_putc(s, ls_pref->sr.sid_flag); stream_putc(s, ls_pref->sr.algo); } + if (CHECK_FLAG(ls_pref->flags, LS_PREF_SRV6)) { + stream_put(s, &ls_pref->srv6.sid, sizeof(struct in6_addr)); + stream_putw(s, ls_pref->srv6.behavior); + stream_putc(s, ls_pref->srv6.flags); + } return 0; } @@ -2748,6 +2765,13 @@ static void ls_show_subnet_vty(struct ls_subnet *subnet, struct vty *vty, sbuf_push(&sbuf, 4, "SID: %d\tAlgorithm: %d\tFlags: 0x%x\n", pref->sr.sid, pref->sr.algo, pref->sr.sid_flag); + if (CHECK_FLAG(pref->flags, LS_PREF_SRV6)) + sbuf_push(&sbuf, 4, + "SIDv6: %pI6\tEndpoint behavior: %s\tFlags: 0x%x\n", + &pref->srv6.sid, + seg6local_action2str(pref->srv6.behavior), + pref->srv6.flags); + end: vty_out(vty, "%s\n", sbuf_buf(&sbuf)); sbuf_free(&sbuf); @@ -2757,7 +2781,7 @@ static void ls_show_subnet_json(struct ls_subnet *subnet, struct json_object *json) { struct ls_prefix *pref; - json_object *jsr; + json_object *jsr, *jsrv6; char buf[INET6_BUFSIZ]; pref = subnet->ls_pref; @@ -2787,6 +2811,16 @@ static void ls_show_subnet_json(struct ls_subnet *subnet, snprintfrr(buf, INET6_BUFSIZ, "0x%x", pref->sr.sid_flag); json_object_string_add(jsr, "flags", buf); } + if (CHECK_FLAG(pref->flags, LS_PREF_SRV6)) { + jsrv6 = json_object_new_object(); + json_object_object_add(json, "segment-routing-ipv6", jsrv6); + snprintfrr(buf, INET6_BUFSIZ, "%pI6", &pref->srv6.sid); + json_object_string_add(jsrv6, "sid", buf); + json_object_string_add(jsrv6, "behavior", + seg6local_action2str(pref->srv6.behavior)); + snprintfrr(buf, INET6_BUFSIZ, "0x%x", pref->srv6.flags); + json_object_string_add(jsrv6, "flags", buf); + } } void ls_show_subnet(struct ls_subnet *subnet, struct vty *vty, diff --git a/lib/link_state.h b/lib/link_state.h index d819c20db7..c54e2ec6d9 100644 --- a/lib/link_state.h +++ b/lib/link_state.h @@ -243,6 +243,7 @@ struct ls_attributes { #define LS_PREF_EXTENDED_TAG 0x04 #define LS_PREF_METRIC 0x08 #define LS_PREF_SR 0x10 +#define LS_PREF_SRV6 0x20 /* Link State Prefix */ struct ls_prefix { @@ -258,6 +259,11 @@ struct ls_prefix { uint8_t sid_flag; /* Segment Routing Flags */ uint8_t algo; /* Algorithm for Segment Routing */ } sr; + struct ls_srv6_sid { + struct in6_addr sid; /* Segment Routing ID */ + uint16_t behavior; /* Endpoint behavior bound to the SID */ + uint8_t flags; /* Flags */ + } srv6; }; /** From 728f2942f96e258c1dfc101e228f0ccccd14292d Mon Sep 17 00:00:00 2001 From: Y Bharath Date: Thu, 11 Jul 2024 22:31:22 +0530 Subject: [PATCH 169/347] yang: Added default value to leaf Added default value to yang Signed-off-by: y-bharath14 --- yang/frr-zebra.yang | 1 + 1 file changed, 1 insertion(+) diff --git a/yang/frr-zebra.yang b/yang/frr-zebra.yang index 79c524a40a..1c7d1c8ef4 100644 --- a/yang/frr-zebra.yang +++ b/yang/frr-zebra.yang @@ -626,6 +626,7 @@ module frr-zebra { leaf table-id { type uint32; + default "254"; description "Routing Table id (default id - 254)."; } From 4518d386f7683289b079708fcdb0c42ced4754d9 Mon Sep 17 00:00:00 2001 From: anlan_cs Date: Fri, 12 Jul 2024 17:03:03 +0800 Subject: [PATCH 170/347] zebra: fix missing static routes Use `vtysh` with this input file: ``` ip route A nh1 ip route A nh2 ip route B nh1 ip route B nh2 ``` When running "ip route B" with "nh1" and "nh2", the procedure maybe is: 1) Create the two nexthops: "nh1" and "nh2". 2) Register "nh1" with `static_zebra_nht_register()`, then the states of both "nh1" and "nht2" are set to "STATIC_SENT_TO_ZEBRA". 3) Register "nh2" with `static_zebra_nht_register()`, then only the routes with nexthop of "STATIC_START" will be sent to zebra. So, send the routes with the nexthop of "STATIC_SENT_TO_ZEBRA" to zebra. Signed-off-by: anlan_cs --- staticd/static_zebra.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/staticd/static_zebra.c b/staticd/static_zebra.c index c4efc14a9d..420ed7903b 100644 --- a/staticd/static_zebra.c +++ b/staticd/static_zebra.c @@ -341,7 +341,8 @@ void static_zebra_nht_register(struct static_nexthop *nh, bool reg) /* refresh with existing data */ afi_t afi = prefix_afi(&lookup.nh); - if (nh->state == STATIC_NOT_INSTALLED) + if (nh->state == STATIC_NOT_INSTALLED || + nh->state == STATIC_SENT_TO_ZEBRA) nh->state = STATIC_START; static_nht_update(&rn->p, &nhtd->nh, nhtd->nh_num, afi, si->safi, nh->nh_vrf_id); From ad7a1f9487edc75fbfaf932e929a008c8bcbc4f9 Mon Sep 17 00:00:00 2001 From: Jafar Al-Gharaibeh Date: Wed, 10 Jul 2024 14:18:51 -0500 Subject: [PATCH 171/347] tests: tweak timers to avoid frequent failures on slow CI hardware Signed-off-by: Jafar Al-Gharaibeh --- .../ospf_metric_propagation/r1/frr.conf | 6 +++--- .../r1/show_ip_route-1.json | 19 +------------------ .../r1/show_ip_route-2.json | 19 +------------------ .../r1/show_ip_route-3.json | 19 +------------------ .../r1/show_ip_route-4.json | 19 +------------------ .../r1/show_ip_route-5.json | 19 +------------------ .../r1/show_ip_route-6.json | 19 +------------------ .../ospf_metric_propagation/r2/frr.conf | 6 +++--- .../ospf_metric_propagation/r3/frr.conf | 6 +++--- .../ospf_metric_propagation/r4/frr.conf | 6 +++--- .../ospf_metric_propagation/ra/frr.conf | 6 +++--- .../ospf_metric_propagation/rb/frr.conf | 6 +++--- .../ospf_metric_propagation/rc/frr.conf | 4 ++-- .../test_ospf_metric_propagation.py | 12 ++++++------ 14 files changed, 32 insertions(+), 134 deletions(-) diff --git a/tests/topotests/ospf_metric_propagation/r1/frr.conf b/tests/topotests/ospf_metric_propagation/r1/frr.conf index 85230494dd..4966e6a9da 100644 --- a/tests/topotests/ospf_metric_propagation/r1/frr.conf +++ b/tests/topotests/ospf_metric_propagation/r1/frr.conf @@ -8,18 +8,18 @@ interface r1-eth0 ip address 10.0.1.1/24 ip ospf cost 100 ip ospf hello-interval 1 - ip ospf dead-interval 30 + ip ospf dead-interval 40 ! interface r1-eth1 vrf blue ip address 10.0.10.1/24 ip ospf hello-interval 1 - ip ospf dead-interval 30 + ip ospf dead-interval 40 ! ! interface r1-eth2 vrf green ip address 10.0.91.1/24 ip ospf hello-interval 1 - ip ospf dead-interval 30 + ip ospf dead-interval 40 ! ! router ospf diff --git a/tests/topotests/ospf_metric_propagation/r1/show_ip_route-1.json b/tests/topotests/ospf_metric_propagation/r1/show_ip_route-1.json index 4f1ced81fb..2392b40fa9 100644 --- a/tests/topotests/ospf_metric_propagation/r1/show_ip_route-1.json +++ b/tests/topotests/ospf_metric_propagation/r1/show_ip_route-1.json @@ -2,32 +2,15 @@ "10.0.94.0/24":[ { "prefix":"10.0.94.0/24", - "prefixLen":24, "protocol":"bgp", "vrfName":"green", - "selected":true, - "destSelected":true, - "distance":20, "metric":34, "installed":true, - "table":12, - "internalStatus":16, - "internalFlags":8, - "internalNextHopNum":1, - "internalNextHopActiveNum":1, - "nexthopGroupId":"*", - "installedNexthopGroupId":"*", - "uptime":"*", "nexthops":[ { - "flags":3, - "fib":true, "ip":"10.0.10.5", - "afi":"ipv4", "interfaceName":"r1-eth1", - "vrf":"blue", - "active":true, - "weight":1 + "vrf":"blue" } ] } diff --git a/tests/topotests/ospf_metric_propagation/r1/show_ip_route-2.json b/tests/topotests/ospf_metric_propagation/r1/show_ip_route-2.json index 882d3ca4f0..9a3d3d87b7 100644 --- a/tests/topotests/ospf_metric_propagation/r1/show_ip_route-2.json +++ b/tests/topotests/ospf_metric_propagation/r1/show_ip_route-2.json @@ -2,32 +2,15 @@ "10.0.94.0/24":[ { "prefix":"10.0.94.0/24", - "prefixLen":24, "protocol":"bgp", "vrfName":"green", - "selected":true, - "destSelected":true, - "distance":20, "metric":136, "installed":true, - "table":12, - "internalStatus":16, - "internalFlags":8, - "internalNextHopNum":1, - "internalNextHopActiveNum":1, - "nexthopGroupId":"*", - "installedNexthopGroupId":"*", - "uptime":"*", "nexthops":[ { - "flags":3, - "fib":true, "ip":"10.0.1.2", - "afi":"ipv4", "interfaceName":"r1-eth0", - "vrf":"default", - "active":true, - "weight":1 + "vrf":"default" } ] } diff --git a/tests/topotests/ospf_metric_propagation/r1/show_ip_route-3.json b/tests/topotests/ospf_metric_propagation/r1/show_ip_route-3.json index cd528459ab..5f0331f3cd 100644 --- a/tests/topotests/ospf_metric_propagation/r1/show_ip_route-3.json +++ b/tests/topotests/ospf_metric_propagation/r1/show_ip_route-3.json @@ -2,32 +2,15 @@ "10.0.94.0/24":[ { "prefix":"10.0.94.0/24", - "prefixLen":24, "protocol":"bgp", "vrfName":"green", - "selected":true, - "destSelected":true, - "distance":20, "metric":1138, "installed":true, - "table":12, - "internalStatus":16, - "internalFlags":8, - "internalNextHopNum":1, - "internalNextHopActiveNum":1, - "nexthopGroupId":"*", - "installedNexthopGroupId":"*", - "uptime":"*", "nexthops":[ { - "flags":3, - "fib":true, "ip":"10.0.1.2", - "afi":"ipv4", "interfaceName":"r1-eth0", - "vrf":"default", - "active":true, - "weight":1 + "vrf":"default" } ] } diff --git a/tests/topotests/ospf_metric_propagation/r1/show_ip_route-4.json b/tests/topotests/ospf_metric_propagation/r1/show_ip_route-4.json index 133f37549e..f312291e86 100644 --- a/tests/topotests/ospf_metric_propagation/r1/show_ip_route-4.json +++ b/tests/topotests/ospf_metric_propagation/r1/show_ip_route-4.json @@ -2,32 +2,15 @@ "10.0.94.0/24":[ { "prefix":"10.0.94.0/24", - "prefixLen":24, "protocol":"bgp", "vrfName":"green", - "selected":true, - "destSelected":true, - "distance":20, "metric":1218, "installed":true, - "table":12, - "internalStatus":16, - "internalFlags":8, - "internalNextHopNum":1, - "internalNextHopActiveNum":1, - "nexthopGroupId":"*", - "installedNexthopGroupId":"*", - "uptime":"*", "nexthops":[ { - "flags":3, - "fib":true, "ip":"10.0.1.2", - "afi":"ipv4", "interfaceName":"r1-eth0", - "vrf":"default", - "active":true, - "weight":1 + "vrf":"default" } ] } diff --git a/tests/topotests/ospf_metric_propagation/r1/show_ip_route-5.json b/tests/topotests/ospf_metric_propagation/r1/show_ip_route-5.json index 5d80509021..e88c037174 100644 --- a/tests/topotests/ospf_metric_propagation/r1/show_ip_route-5.json +++ b/tests/topotests/ospf_metric_propagation/r1/show_ip_route-5.json @@ -2,32 +2,15 @@ "10.0.94.0/24":[ { "prefix":"10.0.94.0/24", - "prefixLen":24, "protocol":"bgp", "vrfName":"green", - "selected":true, - "destSelected":true, - "distance":20, "metric":238, "installed":true, - "table":12, - "internalStatus":16, - "internalFlags":8, - "internalNextHopNum":1, - "internalNextHopActiveNum":1, - "nexthopGroupId":"*", - "installedNexthopGroupId":"*", - "uptime":"*", "nexthops":[ { - "flags":3, - "fib":true, "ip":"10.0.1.2", - "afi":"ipv4", "interfaceName":"r1-eth0", - "vrf":"default", - "active":true, - "weight":1 + "vrf":"default" } ] } diff --git a/tests/topotests/ospf_metric_propagation/r1/show_ip_route-6.json b/tests/topotests/ospf_metric_propagation/r1/show_ip_route-6.json index 1b59707b98..f1fec860a9 100644 --- a/tests/topotests/ospf_metric_propagation/r1/show_ip_route-6.json +++ b/tests/topotests/ospf_metric_propagation/r1/show_ip_route-6.json @@ -2,32 +2,15 @@ "10.0.94.0/24":[ { "prefix":"10.0.94.0/24", - "prefixLen":24, "protocol":"bgp", "vrfName":"green", - "selected":true, - "destSelected":true, - "distance":20, "metric":136, "installed":true, - "table":12, - "internalStatus":16, - "internalFlags":8, - "internalNextHopNum":1, - "internalNextHopActiveNum":1, - "nexthopGroupId":"*", - "installedNexthopGroupId":"*", - "uptime":"*", "nexthops":[ { - "flags":3, - "fib":true, "ip":"10.0.10.5", - "afi":"ipv4", "interfaceName":"r1-eth1", - "vrf":"blue", - "active":true, - "weight":1 + "vrf":"blue" } ] } diff --git a/tests/topotests/ospf_metric_propagation/r2/frr.conf b/tests/topotests/ospf_metric_propagation/r2/frr.conf index e67a374ff5..0ac5001b1b 100644 --- a/tests/topotests/ospf_metric_propagation/r2/frr.conf +++ b/tests/topotests/ospf_metric_propagation/r2/frr.conf @@ -8,18 +8,18 @@ interface r2-eth0 ip address 10.0.1.2/24 ip ospf cost 100 ip ospf hello-interval 1 - ip ospf dead-interval 30 + ip ospf dead-interval 40 ! interface r2-eth1 vrf blue ip address 10.0.20.2/24 ip ospf hello-interval 1 - ip ospf dead-interval 30 + ip ospf dead-interval 40 ! interface r2-eth2 vrf green ip address 10.0.70.2/24 ip ospf cost 1000 ip ospf hello-interval 1 - ip ospf dead-interval 30 + ip ospf dead-interval 40 ! router ospf ospf router-id 10.0.255.2 diff --git a/tests/topotests/ospf_metric_propagation/r3/frr.conf b/tests/topotests/ospf_metric_propagation/r3/frr.conf index 175851d427..0859173f79 100644 --- a/tests/topotests/ospf_metric_propagation/r3/frr.conf +++ b/tests/topotests/ospf_metric_propagation/r3/frr.conf @@ -8,18 +8,18 @@ interface r3-eth0 ip address 10.0.3.3/24 ip ospf cost 100 ip ospf hello-interval 1 - ip ospf dead-interval 30 + ip ospf dead-interval 40 ! interface r3-eth1 vrf blue ip address 10.0.30.3/24 ip ospf hello-interval 1 - ip ospf dead-interval 30 + ip ospf dead-interval 40 ! interface r3-eth2 vrf green ip address 10.0.80.3/24 ip ospf cost 1000 ip ospf hello-interval 1 - ip ospf dead-interval 30 + ip ospf dead-interval 40 ! router ospf ospf router-id 10.0.255.3 diff --git a/tests/topotests/ospf_metric_propagation/r4/frr.conf b/tests/topotests/ospf_metric_propagation/r4/frr.conf index 70a47e34fa..743da27272 100644 --- a/tests/topotests/ospf_metric_propagation/r4/frr.conf +++ b/tests/topotests/ospf_metric_propagation/r4/frr.conf @@ -8,17 +8,17 @@ interface r4-eth0 ip address 10.0.3.4/24 ip ospf cost 100 ip ospf hello-interval 1 - ip ospf dead-interval 30 + ip ospf dead-interval 40 ! interface r4-eth1 vrf blue ip address 10.0.40.4/24 ip ospf hello-interval 1 - ip ospf dead-interval 30 + ip ospf dead-interval 40 ! interface r4-eth2 vrf green ip address 10.0.94.4/24 ip ospf hello-interval 1 - ip ospf dead-interval 30 + ip ospf dead-interval 40 ! router ospf ospf router-id 10.0.255.4 diff --git a/tests/topotests/ospf_metric_propagation/ra/frr.conf b/tests/topotests/ospf_metric_propagation/ra/frr.conf index 7be9e5c33e..2434faeabc 100644 --- a/tests/topotests/ospf_metric_propagation/ra/frr.conf +++ b/tests/topotests/ospf_metric_propagation/ra/frr.conf @@ -7,17 +7,17 @@ ip forwarding interface ra-eth0 ip address 10.0.50.5/24 ip ospf hello-interval 1 - ip ospf dead-interval 30 + ip ospf dead-interval 40 ! interface ra-eth1 ip address 10.0.10.5/24 ip ospf hello-interval 1 - ip ospf dead-interval 30 + ip ospf dead-interval 40 ! interface ra-eth2 ip address 10.0.20.5/24 ip ospf hello-interval 1 - ip ospf dead-interval 30 + ip ospf dead-interval 40 ! router ospf ospf router-id 10.0.255.5 diff --git a/tests/topotests/ospf_metric_propagation/rb/frr.conf b/tests/topotests/ospf_metric_propagation/rb/frr.conf index a7dbf82278..b83532a840 100644 --- a/tests/topotests/ospf_metric_propagation/rb/frr.conf +++ b/tests/topotests/ospf_metric_propagation/rb/frr.conf @@ -7,17 +7,17 @@ ip forwarding interface rb-eth0 ip address 10.0.50.6/24 ip ospf hello-interval 1 - ip ospf dead-interval 30 + ip ospf dead-interval 40 ! interface rb-eth1 ip address 10.0.30.6/24 ip ospf hello-interval 1 - ip ospf dead-interval 30 + ip ospf dead-interval 40 ! interface rb-eth2 ip address 10.0.40.6/24 ip ospf hello-interval 1 - ip ospf dead-interval 30 + ip ospf dead-interval 40 ! router ospf ospf router-id 10.0.255.6 diff --git a/tests/topotests/ospf_metric_propagation/rc/frr.conf b/tests/topotests/ospf_metric_propagation/rc/frr.conf index f5a2ed7c4f..dd8077c394 100644 --- a/tests/topotests/ospf_metric_propagation/rc/frr.conf +++ b/tests/topotests/ospf_metric_propagation/rc/frr.conf @@ -7,12 +7,12 @@ ip forwarding interface rc-eth0 ip address 10.0.70.7/24 ip ospf hello-interval 1 - ip ospf dead-interval 30 + ip ospf dead-interval 40 ! interface rc-eth1 ip address 10.0.80.7/24 ip ospf hello-interval 1 - ip ospf dead-interval 30 + ip ospf dead-interval 40 ! router ospf ospf router-id 10.0.255.7 diff --git a/tests/topotests/ospf_metric_propagation/test_ospf_metric_propagation.py b/tests/topotests/ospf_metric_propagation/test_ospf_metric_propagation.py index b9c63622f0..b97b86bff9 100644 --- a/tests/topotests/ospf_metric_propagation/test_ospf_metric_propagation.py +++ b/tests/topotests/ospf_metric_propagation/test_ospf_metric_propagation.py @@ -282,7 +282,7 @@ def test_link_1_2_3_4_down(): assert result is None, assertmsg -def test_link_1_2_4_down(): +def test_link_1_2_4_down_3_up(): "Test path R1 -> R2 -> Rc -> R3 -> R4" tgen = get_topogen() @@ -304,7 +304,7 @@ def test_link_1_2_4_down(): assert result is None, assertmsg -def test_link_1_4_down(): +def test_link_1_4_down_2_up(): "Test path R1 -> R2 -> Ra -> Rb -> R3 -> R4" tgen = get_topogen() @@ -320,13 +320,13 @@ def test_link_1_4_down(): test_func = partial( topotest.router_json_cmp, r1, "show ip route vrf green 10.0.94.2 json", expected ) - _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=120, wait=2) assertmsg = "r1 JSON output mismatches" assert result is None, assertmsg -def test_link_4_down(): +def test_link_4_down_1_up(): "Test path R1 -> Ra -> Rb -> R3 -> R4" tgen = get_topogen() @@ -342,7 +342,7 @@ def test_link_4_down(): test_func = partial( topotest.router_json_cmp, r1, "show ip route vrf green 10.0.94.2 json", expected ) - _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=120, wait=2) assertmsg = "r1 JSON output mismatches" assert result is None, assertmsg @@ -364,7 +364,7 @@ def test_link_1_2_3_4_up(): test_func = partial( topotest.router_json_cmp, r1, "show ip route vrf green 10.0.94.2 json", expected ) - _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=120, wait=2) assertmsg = "r1 JSON output mismatches" assert result is None, assertmsg From c77e15710d6a3a9be71f41a9ce608f06b2795dfb Mon Sep 17 00:00:00 2001 From: Rajasekar Raja Date: Fri, 5 Jul 2024 16:02:12 -0700 Subject: [PATCH 172/347] zebra: Fix to avoid two Vrfs with same table ids During internal testing, when the following sequence is followed, two non default vrfs end up pointing to the same table-id - Initially vrf201 has table id 1002 - ip link add dev vrf202 type vrf table 1002 - ip link set dev vrf202 up - ip link set dev master vrf202 This will ideally lead to zebra exit since this is a misconfiguration as expected. However if we perform a restart frr.service at this point, we end up having two vrfs pointing to same table-id and bad things can happen. This is because in the interface_vrf_change, we incorrectly check for vrf_lookup_by_id() to evaluate if there is a misconfig. This works well for a non restart case but not for the startup case. root@mlx-3700-20:mgmt:/var/log/frr# sudo vtysh -c "sh vrf" vrf mgmt id 37 table 1001 vrf vrf201 id 46 table 1002 vrf vrf202 id 59 table 1002 >>>> Fix: in all cases of misconfiguration, exit zebra as expected. Ticket :#3970414 Signed-off-by: Donald Sharp Signed-off-by: Rajasekar Raja --- zebra/interface.c | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/zebra/interface.c b/zebra/interface.c index f1f24cc29f..b3adc4483e 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -1483,23 +1483,27 @@ static void interface_vrf_change(enum dplane_op_e op, ifindex_t ifindex, "DPLANE_OP_INTF_UPDATE for VRF %s(%u) table %u", name, ifindex, tableid); - if (!vrf_lookup_by_id((vrf_id_t)ifindex)) { - vrf_id_t exist_id; - - exist_id = zebra_vrf_lookup_by_table(tableid, ns_id); - if (exist_id != VRF_DEFAULT) { - vrf = vrf_lookup_by_id(exist_id); - - if (vrf) - flog_err(EC_ZEBRA_VRF_MISCONFIGURED, - "VRF %s id %u table id overlaps existing vrf %s(%d), misconfiguration exiting", - name, ifindex, vrf->name, - vrf->vrf_id); - else - flog_err(EC_ZEBRA_VRF_NOT_FOUND, - "VRF %s id %u does not exist", - name, ifindex); + /* + * For a given tableid, if there already exists a vrf and it + * is different from the current vrf to be operated, then there + * is a misconfiguration and zebra will exit. + */ + vrf_id_t exist_id = zebra_vrf_lookup_by_table(tableid, ns_id); + + if (exist_id != VRF_DEFAULT) { + vrf = vrf_lookup_by_id(exist_id); + + if (!vrf_lookup_by_id((vrf_id_t)ifindex) && !vrf) { + flog_err(EC_ZEBRA_VRF_NOT_FOUND, + "VRF %s id %u does not exist", name, + ifindex); + exit(-1); + } + if (vrf && strcmp(name, vrf->name)) { + flog_err(EC_ZEBRA_VRF_MISCONFIGURED, + "VRF %s id %u table id overlaps existing vrf %s(%d), misconfiguration exiting", + name, ifindex, vrf->name, vrf->vrf_id); exit(-1); } } From 5b06a17715c63f7639640a97be338ace8fc76f79 Mon Sep 17 00:00:00 2001 From: Y Bharath Date: Wed, 19 Jun 2024 12:51:05 +0530 Subject: [PATCH 173/347] tests: Refactoring FRR test suites Signed-off-by: y-bharath14 --- .../test_all_protocol_startup.py | 2 -- .../topotests/babel_topo1/test_babel_topo1.py | 2 -- .../bfd_ospf_topo1/test_bfd_ospf_topo1.py | 1 - .../test_bgp_6vpe_ebgp_topo1.py | 1 - .../test_bgp_addpath_paths_limit.py | 2 +- tests/topotests/bgp_aigp/test_bgp_aigp.py | 1 - .../bgp_as_allow_in/test_bgp_as_allow_in.py | 3 +-- tests/topotests/bgp_auth/bgp_auth_common.py | 13 +++------- tests/topotests/bgp_auth/test_bgp_auth1.py | 4 +--- tests/topotests/bgp_auth/test_bgp_auth2.py | 4 +--- tests/topotests/bgp_auth/test_bgp_auth3.py | 4 +--- tests/topotests/bgp_auth/test_bgp_auth4.py | 4 +--- tests/topotests/bgp_bmp/test_bgp_bmp.py | 1 - .../test_bgp_color_extcommunities.py | 1 - .../test_bgp_communities_topo2.py | 1 - ..._conditional_advertisement_static_route.py | 3 +-- .../test_bgp_dampening_per_peer.py | 1 - .../test_bgp_default_originate_2links.py | 6 +---- .../test_bgp_default_originate_topo1_1.py | 16 ------------- .../test_bgp_default_originate_topo1_2.py | 12 ---------- .../test_default_orginate_vrf.py | 18 -------------- ..._default_originate_conditional_routemap.py | 1 - .../test_bgp_admin_dist.py | 9 ------- .../test_bgp_dynamic_capability_addpath.py | 3 +-- .../test_bgp_dynamic_capability_fqdn.py | 3 +-- ...bgp_dynamic_capability_graceful_restart.py | 3 +-- .../test_bgp_dynamic_capability_orf.py | 3 +-- .../test_bgp_dynamic_capability_role.py | 3 +-- ...bgp_dynamic_capability_software_version.py | 2 +- .../bgp_ecmp_topo2/test_ibgp_ecmp_topo2.py | 5 +--- .../test_bgp_evpn_maximum_prefix.py | 3 +-- tests/topotests/bgp_evpn_mh/test_evpn_mh.py | 2 +- .../test_bgp_evpn_overlay_index_gateway.py | 2 +- .../test_bgp_evpn_route_map_match.py | 4 +--- .../test_bgp_extcomm-list_delete.py | 1 - .../test_bgp_extended_link_bandwidth.py | 3 +-- .../bgp_features/test_bgp_features.py | 1 - .../test_bgp_gr_functionality_topo1-1.py | 1 - .../test_bgp_gr_functionality_topo1-2.py | 2 -- .../test_bgp_gr_functionality_topo1-3.py | 1 - .../test_bgp_gr_functionality_topo1-4.py | 3 --- .../test_bgp_gr_functionality_topo2-1.py | 5 +--- .../test_bgp_gr_functionality_topo2-2.py | 4 +--- .../test_bgp_gr_functionality_topo2-3.py | 5 +--- .../test_bgp_gr_functionality_topo2-4.py | 7 +----- .../test_bgp_gr_functionality_topo3.py | 24 ++----------------- ...p_gr_per_neighbor_restart_retain_routes.py | 2 +- .../test_bgp_gr_restart_retain_routes.py | 2 +- .../test_rfc5549_ebgp_unnumbered_nbr.py | 2 +- .../test_bgp_l3vpn_label_export.py | 2 +- ...t_bgp_labeled_unicast_default_originate.py | 1 - tests/topotests/bgp_llgr/test_bgp_llgr.py | 1 - .../bgp_local_asn/test_bgp_local_asn_agg.py | 1 - .../bgp_local_asn/test_bgp_local_asn_ecmp.py | 2 -- .../bgp_local_asn/test_bgp_local_asn_topo1.py | 1 - .../bgp_local_asn/test_bgp_local_asn_topo2.py | 1 - .../test_bgp_local_asn_vrf_topo1.py | 1 - .../test_bgp_local_asn_vrf_topo2.py | 1 - .../test_bgp_local_asn_dot_agg.py | 1 - .../test_bgp_local_asn_dot_ecmp.py | 2 -- .../test_bgp_local_asn_dot_topo1.py | 1 - .../test_bgp_multi_vrf_topo2.py | 6 ++--- .../test_nexthop_mp_ipv4_6.py | 1 - .../test_bgp_node_target_extcommunities.py | 2 +- tests/topotests/bgp_oad/test_bgp_oad.py | 4 +--- .../test_bgp_path_attribute_discard.py | 2 +- .../bgp_prefix_sid2/test_bgp_prefix_sid2.py | 2 +- .../test_bgp_redistribute_table.py | 2 +- .../test_bgp_remove_private_as.py | 1 - .../test_bgp_remove_private_as_route_map.py | 3 +-- .../test_bgp_roles_capability.py | 17 ++++--------- .../test_bgp_roles_filtering.py | 11 +++------ .../test_bgp_aggregation.py | 2 +- ...est_bgp_route_map_match_source_protocol.py | 2 +- .../test_bgp_route_map_match_tag_untagged.py | 2 +- .../test_bgp_route_map_vpn_import.py | 1 - .../test_bgp_route_origin_parser.py | 1 - .../bgp_rr_ibgp/test_bgp_rr_ibgp_topo1.py | 1 - .../test_bgp_snmp_mplsvpn.py | 1 - .../test_bgp_srv6_sid_reachability.py | 5 ---- .../test_bgp_srv6l3vpn_over_ipv6.py | 5 ---- .../test_bgp_srv6l3vpn_route_leak.py | 3 --- .../test_bgp_srv6l3vpn_sid.py | 1 - .../test_bgp_srv6l3vpn_to_bgp_vrf2.py | 1 - .../bgp_suppress_fib/test_bgp_suppress_fib.py | 1 - .../bgp_tcp_mss/test_bgp_vrf_tcp_mss.py | 23 +----------------- .../test_bgp_tcp_mss_passive.py | 2 +- .../bgp_unnumbered/test_bgp_unnumbered.py | 1 - .../test_bgp_vpn_5549_route_map.py | 1 - .../bgp_vpnv4_asbr/test_bgp_vpnv4_asbr.py | 2 +- .../test_bgp_vpnv4_noretain.py | 4 ++-- .../test_bgp_vpnv4_per_nexthop_label.py | 4 ++-- .../test_bgp_vpnv6_per_nexthop_label.py | 6 ++--- .../test_bgp_vrf_dynamic_route_leak_topo2.py | 3 +-- .../test_bgp_vrf_dynamic_route_leak_topo3.py | 2 -- ...test_bgp_vrf_dynamic_route_leak_topo4-1.py | 6 ----- ...test_bgp_vrf_dynamic_route_leak_topo4-2.py | 6 ----- ...test_bgp_vrf_dynamic_route_leak_topo4-3.py | 6 ----- .../test_bgp_vrf_leaking.py | 3 --- .../test_bgp_vrf_lite_best_path_topo1.py | 2 -- .../test_bgp_vrf_lite_best_path_topo2.py | 1 - 101 files changed, 64 insertions(+), 306 deletions(-) diff --git a/tests/topotests/all_protocol_startup/test_all_protocol_startup.py b/tests/topotests/all_protocol_startup/test_all_protocol_startup.py index b4bc1e14ad..902343ce42 100644 --- a/tests/topotests/all_protocol_startup/test_all_protocol_startup.py +++ b/tests/topotests/all_protocol_startup/test_all_protocol_startup.py @@ -38,7 +38,6 @@ required_linux_kernel_version, ) -from lib.topolog import logger import json fatal_error = "" @@ -153,7 +152,6 @@ def test_error_messages_vtysh(): print("\n\n** Check for error messages on VTYSH") print("******************************************\n") - failures = 0 for i in range(1, 2): # # First checking Standard Output diff --git a/tests/topotests/babel_topo1/test_babel_topo1.py b/tests/topotests/babel_topo1/test_babel_topo1.py index decf0c2a6f..13bbe5bd4e 100644 --- a/tests/topotests/babel_topo1/test_babel_topo1.py +++ b/tests/topotests/babel_topo1/test_babel_topo1.py @@ -15,7 +15,6 @@ """ import os -import re import sys import pytest import json @@ -130,7 +129,6 @@ def test_zebra_ipv4_routingTable(): if tgen.routers_have_failure(): pytest.skip(tgen.errors) - failures = 0 router_list = tgen.routers().values() for router in router_list: assertmsg = "Zebra IPv4 Routing Table verification failed for router {}".format( diff --git a/tests/topotests/bfd_ospf_topo1/test_bfd_ospf_topo1.py b/tests/topotests/bfd_ospf_topo1/test_bfd_ospf_topo1.py index b9e8b73c1d..6919371ac5 100755 --- a/tests/topotests/bfd_ospf_topo1/test_bfd_ospf_topo1.py +++ b/tests/topotests/bfd_ospf_topo1/test_bfd_ospf_topo1.py @@ -59,7 +59,6 @@ import sys import pytest import json -from time import sleep from functools import partial # Save the Current Working Directory to find configuration files. diff --git a/tests/topotests/bgp_6vpe_ebgp_topo1/test_bgp_6vpe_ebgp_topo1.py b/tests/topotests/bgp_6vpe_ebgp_topo1/test_bgp_6vpe_ebgp_topo1.py index cbed8f0896..477cfa206b 100644 --- a/tests/topotests/bgp_6vpe_ebgp_topo1/test_bgp_6vpe_ebgp_topo1.py +++ b/tests/topotests/bgp_6vpe_ebgp_topo1/test_bgp_6vpe_ebgp_topo1.py @@ -12,7 +12,6 @@ import os import sys import json -import functools from functools import partial import pytest diff --git a/tests/topotests/bgp_addpath_paths_limit/test_bgp_addpath_paths_limit.py b/tests/topotests/bgp_addpath_paths_limit/test_bgp_addpath_paths_limit.py index b7a1cfbb27..fb863e454f 100644 --- a/tests/topotests/bgp_addpath_paths_limit/test_bgp_addpath_paths_limit.py +++ b/tests/topotests/bgp_addpath_paths_limit/test_bgp_addpath_paths_limit.py @@ -20,7 +20,7 @@ # pylint: disable=C0413 from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen pytestmark = [pytest.mark.bgpd] diff --git a/tests/topotests/bgp_aigp/test_bgp_aigp.py b/tests/topotests/bgp_aigp/test_bgp_aigp.py index e3b32da164..b81c543297 100644 --- a/tests/topotests/bgp_aigp/test_bgp_aigp.py +++ b/tests/topotests/bgp_aigp/test_bgp_aigp.py @@ -29,7 +29,6 @@ # pylint: disable=C0413 from lib import topotest from lib.topogen import Topogen, TopoRouter, get_topogen -from lib.common_config import step pytestmark = [pytest.mark.bgpd] diff --git a/tests/topotests/bgp_as_allow_in/test_bgp_as_allow_in.py b/tests/topotests/bgp_as_allow_in/test_bgp_as_allow_in.py index c49a2e5384..537ccc9df6 100644 --- a/tests/topotests/bgp_as_allow_in/test_bgp_as_allow_in.py +++ b/tests/topotests/bgp_as_allow_in/test_bgp_as_allow_in.py @@ -28,7 +28,6 @@ import os import sys import time -import json import pytest # Save the Current Working Directory to find configuration files. @@ -59,7 +58,7 @@ create_router_bgp, verify_bgp_rib, ) -from lib.topojson import build_topo_from_json, build_config_from_json +from lib.topojson import build_config_from_json pytestmark = [pytest.mark.bgpd, pytest.mark.staticd] diff --git a/tests/topotests/bgp_auth/bgp_auth_common.py b/tests/topotests/bgp_auth/bgp_auth_common.py index 824498ef90..7ba3169caf 100644 --- a/tests/topotests/bgp_auth/bgp_auth_common.py +++ b/tests/topotests/bgp_auth/bgp_auth_common.py @@ -34,16 +34,9 @@ import json import os -import platform -import sys -from time import sleep - -from lib import common_config, topotest -from lib.common_config import ( - save_initial_config_on_routers, - reset_with_new_configs, -) -from lib.topogen import Topogen, TopoRouter, get_topogen + +from lib import common_config +from lib.topogen import get_topogen CWD = os.path.dirname(os.path.realpath(__file__)) diff --git a/tests/topotests/bgp_auth/test_bgp_auth1.py b/tests/topotests/bgp_auth/test_bgp_auth1.py index c19a740a92..b0389474d4 100644 --- a/tests/topotests/bgp_auth/test_bgp_auth1.py +++ b/tests/topotests/bgp_auth/test_bgp_auth1.py @@ -32,14 +32,12 @@ """ # pylint: disable=C0413 -import json import os import platform import sys -from time import sleep import pytest -from lib import common_config, topotest +from lib import topotest from lib.common_config import ( save_initial_config_on_routers, reset_with_new_configs, diff --git a/tests/topotests/bgp_auth/test_bgp_auth2.py b/tests/topotests/bgp_auth/test_bgp_auth2.py index 2551c1c35b..2b8f4673ea 100644 --- a/tests/topotests/bgp_auth/test_bgp_auth2.py +++ b/tests/topotests/bgp_auth/test_bgp_auth2.py @@ -32,14 +32,12 @@ """ # pylint: disable=C0413 -import json import os import platform import sys -from time import sleep import pytest -from lib import common_config, topotest +from lib import topotest from lib.common_config import ( save_initial_config_on_routers, reset_with_new_configs, diff --git a/tests/topotests/bgp_auth/test_bgp_auth3.py b/tests/topotests/bgp_auth/test_bgp_auth3.py index dc4f61d3c9..d103d8075d 100644 --- a/tests/topotests/bgp_auth/test_bgp_auth3.py +++ b/tests/topotests/bgp_auth/test_bgp_auth3.py @@ -32,14 +32,12 @@ """ # pylint: disable=C0413 -import json import os import platform import sys -from time import sleep import pytest -from lib import common_config, topotest +from lib import topotest from lib.common_config import ( save_initial_config_on_routers, reset_with_new_configs, diff --git a/tests/topotests/bgp_auth/test_bgp_auth4.py b/tests/topotests/bgp_auth/test_bgp_auth4.py index afe4441e13..792aa80d50 100644 --- a/tests/topotests/bgp_auth/test_bgp_auth4.py +++ b/tests/topotests/bgp_auth/test_bgp_auth4.py @@ -32,14 +32,12 @@ """ # pylint: disable=C0413 -import json import os import platform import sys -from time import sleep import pytest -from lib import common_config, topotest +from lib import topotest from lib.common_config import ( save_initial_config_on_routers, reset_with_new_configs, diff --git a/tests/topotests/bgp_bmp/test_bgp_bmp.py b/tests/topotests/bgp_bmp/test_bgp_bmp.py index 02de805068..80e291b2bd 100644 --- a/tests/topotests/bgp_bmp/test_bgp_bmp.py +++ b/tests/topotests/bgp_bmp/test_bgp_bmp.py @@ -26,7 +26,6 @@ from ipaddress import ip_network import json import os -import platform import pytest import sys diff --git a/tests/topotests/bgp_color_extcommunities/test_bgp_color_extcommunities.py b/tests/topotests/bgp_color_extcommunities/test_bgp_color_extcommunities.py index e0c1b4953e..09091198a8 100644 --- a/tests/topotests/bgp_color_extcommunities/test_bgp_color_extcommunities.py +++ b/tests/topotests/bgp_color_extcommunities/test_bgp_color_extcommunities.py @@ -16,7 +16,6 @@ import sys import json import functools -from functools import partial import pytest # Save the Current Working Directory to find configuration files. diff --git a/tests/topotests/bgp_communities_topo1/test_bgp_communities_topo2.py b/tests/topotests/bgp_communities_topo1/test_bgp_communities_topo2.py index 324f53f3a6..82a67a0b84 100644 --- a/tests/topotests/bgp_communities_topo1/test_bgp_communities_topo2.py +++ b/tests/topotests/bgp_communities_topo1/test_bgp_communities_topo2.py @@ -171,7 +171,6 @@ def test_bgp_no_export_local_as_communities_p0(request): ) for comm_type in ["no-export", "local-AS"]: - step("Create a route-map on R1 to set community as {}".format(comm_type)) seq_id = 10 diff --git a/tests/topotests/bgp_conditional_advertisement_static_route/test_bgp_conditional_advertisement_static_route.py b/tests/topotests/bgp_conditional_advertisement_static_route/test_bgp_conditional_advertisement_static_route.py index e9114bdbab..ea0f53cc97 100644 --- a/tests/topotests/bgp_conditional_advertisement_static_route/test_bgp_conditional_advertisement_static_route.py +++ b/tests/topotests/bgp_conditional_advertisement_static_route/test_bgp_conditional_advertisement_static_route.py @@ -11,7 +11,6 @@ """ import os -import re import sys import json import pytest @@ -24,7 +23,7 @@ # pylint: disable=C0413 from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen from lib.common_config import step diff --git a/tests/topotests/bgp_dampening_per_peer/test_bgp_dampening_per_peer.py b/tests/topotests/bgp_dampening_per_peer/test_bgp_dampening_per_peer.py index 2066d848d3..f8916e1c4d 100644 --- a/tests/topotests/bgp_dampening_per_peer/test_bgp_dampening_per_peer.py +++ b/tests/topotests/bgp_dampening_per_peer/test_bgp_dampening_per_peer.py @@ -6,7 +6,6 @@ # import os -import re import sys import json import pytest diff --git a/tests/topotests/bgp_default_originate/test_bgp_default_originate_2links.py b/tests/topotests/bgp_default_originate/test_bgp_default_originate_2links.py index 75e66566b7..f4f874f942 100644 --- a/tests/topotests/bgp_default_originate/test_bgp_default_originate_2links.py +++ b/tests/topotests/bgp_default_originate/test_bgp_default_originate_2links.py @@ -17,7 +17,6 @@ import time import pytest import datetime -from copy import deepcopy from lib.topolog import logger from time import sleep @@ -214,7 +213,6 @@ def get_rib_route_uptime(tgen, addr_type, dut, input_dict): logger.info("Entering lib API: get_rib_route_uptime()") route_time = [] - out_route_dict = {} router_list = tgen.routers() for routerInput in input_dict.keys(): for router, rnode in router_list.items(): @@ -234,7 +232,6 @@ def get_rib_route_uptime(tgen, addr_type, dut, input_dict): for static_route in static_routes: if "vrf" in static_route and static_route["vrf"] is not None: - logger.info( "[DUT: {}]: Verifying routes for VRF:" " {}".format(router, static_route["vrf"]) @@ -307,7 +304,6 @@ def get_best_path_route_in_FIB(tgen, topo, dut, network): on failure : return error message with boolean False """ is_ipv4_best_path_found = False - is_ipv6_best_path_found = False rnode = tgen.routers()[dut] ipv4_show_bgp_json = run_frr_cmd(rnode, "sh ip bgp json ", isjson=True) ipv6_show_bgp_json = run_frr_cmd( @@ -1575,7 +1571,7 @@ def ping_router(): ipv_dict = get_best_path_route_in_FIB(tgen, topo, dut="r2", network=network) dut_links = topo["routers"]["r1"]["links"] active_interface = None - for key, values in dut_links.items(): + for key, _ in dut_links.items(): ipv4_address = dut_links[key]["ipv4"].split("/")[0] ipv6_address = dut_links[key]["ipv6"].split("/")[0] if ipv_dict["ipv4"] == ipv4_address and ipv_dict["ipv6"] == ipv6_address: diff --git a/tests/topotests/bgp_default_originate/test_bgp_default_originate_topo1_1.py b/tests/topotests/bgp_default_originate/test_bgp_default_originate_topo1_1.py index 50a1938ae3..142b3e430f 100644 --- a/tests/topotests/bgp_default_originate/test_bgp_default_originate_topo1_1.py +++ b/tests/topotests/bgp_default_originate/test_bgp_default_originate_topo1_1.py @@ -18,8 +18,6 @@ import sys import time import pytest -from time import sleep -from copy import deepcopy from lib.topolog import logger # pylint: disable=C0413 @@ -30,32 +28,18 @@ from lib.bgp import ( verify_bgp_convergence, - verify_graceful_restart, create_router_bgp, - verify_router_id, modify_as_number, - verify_as_numbers, - clear_bgp_and_verify, - clear_bgp, verify_bgp_rib, get_prefix_count_route, get_dut_as_number, verify_rib_default_route, - verify_fib_default_route, - verify_bgp_advertised_routes_from_neighbor, - verify_bgp_received_routes_from_neighbor, ) from lib.common_config import ( - interface_status, verify_prefix_lists, verify_fib_routes, - kill_router_daemons, - start_router_daemons, - shutdown_bringup_interface, step, required_linux_kernel_version, - stop_router, - start_router, create_route_maps, create_prefix_lists, get_frr_ipv6_linklocal, diff --git a/tests/topotests/bgp_default_originate/test_bgp_default_originate_topo1_2.py b/tests/topotests/bgp_default_originate/test_bgp_default_originate_topo1_2.py index 4e8bda55cf..a6918916df 100644 --- a/tests/topotests/bgp_default_originate/test_bgp_default_originate_topo1_2.py +++ b/tests/topotests/bgp_default_originate/test_bgp_default_originate_topo1_2.py @@ -17,8 +17,6 @@ import sys import time import pytest -from time import sleep -from copy import deepcopy from lib.topolog import logger # pylint: disable=C0413 @@ -31,13 +29,8 @@ verify_bgp_convergence, verify_graceful_restart, create_router_bgp, - verify_router_id, modify_as_number, - verify_as_numbers, - clear_bgp_and_verify, - clear_bgp, verify_bgp_rib, - get_prefix_count_route, get_dut_as_number, verify_rib_default_route, verify_fib_default_route, @@ -45,16 +38,12 @@ verify_bgp_received_routes_from_neighbor, ) from lib.common_config import ( - interface_status, verify_prefix_lists, verify_fib_routes, kill_router_daemons, start_router_daemons, - shutdown_bringup_interface, step, required_linux_kernel_version, - stop_router, - start_router, create_route_maps, create_prefix_lists, get_frr_ipv6_linklocal, @@ -65,7 +54,6 @@ reset_config_on_routers, create_static_routes, check_router_status, - delete_route_maps, ) diff --git a/tests/topotests/bgp_default_originate/test_default_orginate_vrf.py b/tests/topotests/bgp_default_originate/test_default_orginate_vrf.py index 4dedac5535..1506b02e5d 100644 --- a/tests/topotests/bgp_default_originate/test_default_orginate_vrf.py +++ b/tests/topotests/bgp_default_originate/test_default_orginate_vrf.py @@ -10,8 +10,6 @@ import sys import time import pytest -from time import sleep -from copy import deepcopy from lib.topolog import logger # pylint: disable=C0413 @@ -22,32 +20,17 @@ from lib.bgp import ( verify_bgp_convergence, - verify_graceful_restart, create_router_bgp, - verify_router_id, modify_as_number, - verify_as_numbers, - clear_bgp_and_verify, - clear_bgp, verify_bgp_rib, get_prefix_count_route, get_dut_as_number, - verify_rib_default_route, - verify_fib_default_route, - verify_bgp_advertised_routes_from_neighbor, - verify_bgp_received_routes_from_neighbor, ) from lib.common_config import ( - interface_status, verify_prefix_lists, verify_rib, - kill_router_daemons, - start_router_daemons, - shutdown_bringup_interface, step, required_linux_kernel_version, - stop_router, - start_router, create_route_maps, create_prefix_lists, get_frr_ipv6_linklocal, @@ -58,7 +41,6 @@ reset_config_on_routers, create_static_routes, check_router_status, - delete_route_maps, ) pytestmark = [pytest.mark.bgpd, pytest.mark.staticd] diff --git a/tests/topotests/bgp_default_originate/test_default_originate_conditional_routemap.py b/tests/topotests/bgp_default_originate/test_default_originate_conditional_routemap.py index f67a431c7e..97a7e62e7c 100644 --- a/tests/topotests/bgp_default_originate/test_default_originate_conditional_routemap.py +++ b/tests/topotests/bgp_default_originate/test_default_originate_conditional_routemap.py @@ -19,7 +19,6 @@ import sys import time import pytest -from copy import deepcopy from lib.topolog import logger # pylint: disable=C0413 diff --git a/tests/topotests/bgp_distance_change/test_bgp_admin_dist.py b/tests/topotests/bgp_distance_change/test_bgp_admin_dist.py index 0bd3d2814b..0307ee2f4e 100755 --- a/tests/topotests/bgp_distance_change/test_bgp_admin_dist.py +++ b/tests/topotests/bgp_distance_change/test_bgp_admin_dist.py @@ -215,7 +215,6 @@ def test_bgp_admin_distance_ebgp_ecmp_p0(): step("Configure static route in R4 and R5, redistribute in bgp") for addr_type in ADDR_TYPES: - input_dict = { "r4": { "static_routes": [{"network": NETWORK[addr_type], "next_hop": "Null0"}] @@ -228,7 +227,6 @@ def test_bgp_admin_distance_ebgp_ecmp_p0(): ) for addr_type in ADDR_TYPES: - input_dict = { "r5": { "static_routes": [{"network": NETWORK[addr_type], "next_hop": "Null0"}] @@ -268,7 +266,6 @@ def test_bgp_admin_distance_ebgp_ecmp_p0(): step("Configure the static route in R3 (Dut).") for addr_type in ADDR_TYPES: - input_dict = { "r3": { "static_routes": [ @@ -305,7 +302,6 @@ def test_bgp_admin_distance_ebgp_ecmp_p0(): step(" Configure the admin distance of 254 to static route in R3.") for addr_type in ADDR_TYPES: - input_dict = { "r3": { "static_routes": [ @@ -571,7 +567,6 @@ def test_bgp_admin_distance_ebgp_ecmp_p0(): step("Reconfigure the static route without admin distance") for addr_type in ADDR_TYPES: - input_dict = { "r3": { "static_routes": [ @@ -993,7 +988,6 @@ def test_bgp_admin_distance_ibgp_p0(): step("Configure static route Without any admin distance") for addr_type in ADDR_TYPES: - input_dict = { "r3": { "static_routes": [{"network": NETWORK[addr_type], "next_hop": "Null0"}] @@ -1009,7 +1003,6 @@ def test_bgp_admin_distance_ibgp_p0(): protocol = "static" for addr_type in ADDR_TYPES: - input_dict = { "r3": { "static_routes": [{"network": NETWORK[addr_type], "next_hop": "Null0"}] @@ -1023,7 +1016,6 @@ def test_bgp_admin_distance_ibgp_p0(): step("Configure static route with admin distance of 253") for addr_type in ADDR_TYPES: - input_dict = { "r3": { "static_routes": [ @@ -1086,7 +1078,6 @@ def test_bgp_admin_distance_ibgp_p0(): step("Delete the static route.") for addr_type in ADDR_TYPES: - input_dict = { "r3": { "static_routes": [ diff --git a/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_addpath.py b/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_addpath.py index 4d7d46c3e8..91df89b1b5 100644 --- a/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_addpath.py +++ b/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_addpath.py @@ -14,7 +14,6 @@ """ import os -import re import sys import json import pytest @@ -27,7 +26,7 @@ # pylint: disable=C0413 from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen def setup_module(mod): diff --git a/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_fqdn.py b/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_fqdn.py index 26fae17c5e..bf05ce8edd 100644 --- a/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_fqdn.py +++ b/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_fqdn.py @@ -10,7 +10,6 @@ """ import os -import re import sys import json import pytest @@ -23,7 +22,7 @@ # pylint: disable=C0413 from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen from lib.common_config import step diff --git a/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_graceful_restart.py b/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_graceful_restart.py index d67bfea45e..514b29cd70 100644 --- a/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_graceful_restart.py +++ b/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_graceful_restart.py @@ -12,7 +12,6 @@ """ import os -import re import sys import json import pytest @@ -25,7 +24,7 @@ # pylint: disable=C0413 from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen from lib.common_config import step diff --git a/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_orf.py b/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_orf.py index 9e1f26f21e..39e7ded1e6 100644 --- a/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_orf.py +++ b/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_orf.py @@ -10,7 +10,6 @@ """ import os -import re import sys import json import pytest @@ -23,7 +22,7 @@ # pylint: disable=C0413 from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen from lib.common_config import step diff --git a/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_role.py b/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_role.py index f6c1e25fd6..7d36634728 100644 --- a/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_role.py +++ b/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_role.py @@ -10,7 +10,6 @@ """ import os -import re import sys import json import pytest @@ -23,7 +22,7 @@ # pylint: disable=C0413 from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen from lib.common_config import step diff --git a/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_software_version.py b/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_software_version.py index 128283bbc3..591fc5a817 100644 --- a/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_software_version.py +++ b/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_software_version.py @@ -23,7 +23,7 @@ # pylint: disable=C0413 from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen from lib.common_config import step diff --git a/tests/topotests/bgp_ecmp_topo2/test_ibgp_ecmp_topo2.py b/tests/topotests/bgp_ecmp_topo2/test_ibgp_ecmp_topo2.py index b347042dcf..5991f2e7ca 100644 --- a/tests/topotests/bgp_ecmp_topo2/test_ibgp_ecmp_topo2.py +++ b/tests/topotests/bgp_ecmp_topo2/test_ibgp_ecmp_topo2.py @@ -106,7 +106,7 @@ def setup_module(mod): # Api call verify whether BGP is converged ADDR_TYPES = check_address_types() - for addr_type in ADDR_TYPES: + for _ in ADDR_TYPES: BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo) assert BGP_CONVERGENCE is True, "setup_module :Failed \n Error:" " {}".format( BGP_CONVERGENCE @@ -153,7 +153,6 @@ def teardown_module(): def static_or_nw(tgen, topo, tc_name, test_type, dut): - if test_type == "redist_static": input_dict_static = { dut: { @@ -363,7 +362,6 @@ def test_ecmp_remove_redistribute_static(request): reset_config_on_routers(tgen) static_or_nw(tgen, topo, tc_name, "redist_static", "r2") for addr_type in ADDR_TYPES: - # Verifying RIB routes dut = "r3" protocol = "bgp" @@ -406,7 +404,6 @@ def test_ecmp_remove_redistribute_static(request): assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) for addr_type in ADDR_TYPES: - # Verifying RIB routes dut = "r3" protocol = "bgp" diff --git a/tests/topotests/bgp_evpn_maximum_prefix/test_bgp_evpn_maximum_prefix.py b/tests/topotests/bgp_evpn_maximum_prefix/test_bgp_evpn_maximum_prefix.py index 5469eff144..876c205f19 100644 --- a/tests/topotests/bgp_evpn_maximum_prefix/test_bgp_evpn_maximum_prefix.py +++ b/tests/topotests/bgp_evpn_maximum_prefix/test_bgp_evpn_maximum_prefix.py @@ -6,7 +6,6 @@ # import os -import re import sys import json import pytest @@ -17,7 +16,7 @@ # pylint: disable=C0413 from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen pytestmark = [pytest.mark.bgpd] diff --git a/tests/topotests/bgp_evpn_mh/test_evpn_mh.py b/tests/topotests/bgp_evpn_mh/test_evpn_mh.py index b033e9c2eb..ba2fb62661 100644 --- a/tests/topotests/bgp_evpn_mh/test_evpn_mh.py +++ b/tests/topotests/bgp_evpn_mh/test_evpn_mh.py @@ -455,7 +455,7 @@ def check_remote_es(esi, vtep_ips, dut_name, down_vteps): else: tor_ips_rack = tor_ips_rack_1 - for tor_name, tor_ip in tor_ips_rack.items(): + for _, tor_ip in tor_ips_rack.items(): remote_ips.append(tor_ip) # remove down VTEPs from the remote check list diff --git a/tests/topotests/bgp_evpn_overlay_index_gateway/test_bgp_evpn_overlay_index_gateway.py b/tests/topotests/bgp_evpn_overlay_index_gateway/test_bgp_evpn_overlay_index_gateway.py index 603f069fe3..d441a256fd 100755 --- a/tests/topotests/bgp_evpn_overlay_index_gateway/test_bgp_evpn_overlay_index_gateway.py +++ b/tests/topotests/bgp_evpn_overlay_index_gateway/test_bgp_evpn_overlay_index_gateway.py @@ -241,7 +241,7 @@ def evpn_gateway_ip_show_op_check(trigger=" "): expected_op = json.loads(open(expected_op_file).read()) test_func = partial(topotest.router_json_cmp, pe, command, expected_op) - ret, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) assertmsg = '"{0}" JSON output mismatch for {1}'.format(name, command) if result is not None: return result, assertmsg diff --git a/tests/topotests/bgp_evpn_route_map_match/test_bgp_evpn_route_map_match.py b/tests/topotests/bgp_evpn_route_map_match/test_bgp_evpn_route_map_match.py index 2df0fd0e6c..36c79d6b2b 100644 --- a/tests/topotests/bgp_evpn_route_map_match/test_bgp_evpn_route_map_match.py +++ b/tests/topotests/bgp_evpn_route_map_match/test_bgp_evpn_route_map_match.py @@ -10,7 +10,6 @@ """ import os -import re import sys import json import pytest @@ -23,8 +22,7 @@ # pylint: disable=C0413 from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen -from lib.common_config import step +from lib.topogen import Topogen, get_topogen def setup_module(mod): diff --git a/tests/topotests/bgp_extcomm_list_delete/test_bgp_extcomm-list_delete.py b/tests/topotests/bgp_extcomm_list_delete/test_bgp_extcomm-list_delete.py index 5f6eb17261..e4d330e13c 100644 --- a/tests/topotests/bgp_extcomm_list_delete/test_bgp_extcomm-list_delete.py +++ b/tests/topotests/bgp_extcomm_list_delete/test_bgp_extcomm-list_delete.py @@ -25,7 +25,6 @@ # pylint: disable=C0413 from lib.topogen import Topogen, TopoRouter, get_topogen -from lib.topolog import logger from lib import topotest diff --git a/tests/topotests/bgp_extended_link_bandwidth/test_bgp_extended_link_bandwidth.py b/tests/topotests/bgp_extended_link_bandwidth/test_bgp_extended_link_bandwidth.py index e7058f5392..e9006b81c9 100644 --- a/tests/topotests/bgp_extended_link_bandwidth/test_bgp_extended_link_bandwidth.py +++ b/tests/topotests/bgp_extended_link_bandwidth/test_bgp_extended_link_bandwidth.py @@ -6,7 +6,6 @@ # import os -import re import sys import json import pytest @@ -17,7 +16,7 @@ # pylint: disable=C0413 from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen pytestmark = [pytest.mark.bgpd] diff --git a/tests/topotests/bgp_features/test_bgp_features.py b/tests/topotests/bgp_features/test_bgp_features.py index 43f4905d41..0f5d9dea42 100644 --- a/tests/topotests/bgp_features/test_bgp_features.py +++ b/tests/topotests/bgp_features/test_bgp_features.py @@ -18,7 +18,6 @@ import os import sys import pytest -import re import time # Save the Current Working Directory to find configuration files. diff --git a/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-1.py b/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-1.py index 5e2b2f37b2..2e2c8119a2 100644 --- a/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-1.py +++ b/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-1.py @@ -102,7 +102,6 @@ verify_graceful_restart, create_router_bgp, verify_r_bit, - verify_f_bit, verify_bgp_convergence, verify_bgp_convergence_from_running_config, ) diff --git a/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-2.py b/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-2.py index 13c5ba538c..9f79c52e3a 100644 --- a/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-2.py +++ b/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-2.py @@ -117,8 +117,6 @@ check_address_types, write_test_footer, check_router_status, - shutdown_bringup_interface, - step, get_frr_ipv6_linklocal, required_linux_kernel_version, ) diff --git a/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-3.py b/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-3.py index 1a8f8302ff..0873c24b7f 100644 --- a/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-3.py +++ b/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-3.py @@ -117,7 +117,6 @@ check_address_types, write_test_footer, check_router_status, - shutdown_bringup_interface, step, get_frr_ipv6_linklocal, required_linux_kernel_version, diff --git a/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-4.py b/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-4.py index de4b94032c..710514b056 100644 --- a/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-4.py +++ b/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-4.py @@ -104,8 +104,6 @@ verify_bgp_rib, verify_graceful_restart, create_router_bgp, - verify_r_bit, - verify_f_bit, verify_bgp_convergence, verify_bgp_convergence_from_running_config, ) @@ -120,7 +118,6 @@ check_address_types, write_test_footer, check_router_status, - shutdown_bringup_interface, step, get_frr_ipv6_linklocal, required_linux_kernel_version, diff --git a/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-1.py b/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-1.py index cb6bf56967..01ab10b82f 100644 --- a/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-1.py +++ b/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-1.py @@ -94,13 +94,10 @@ verify_bgp_rib, verify_graceful_restart, create_router_bgp, - verify_r_bit, verify_eor, - verify_f_bit, verify_bgp_convergence, verify_gr_address_family, modify_bgp_config_when_bgpd_down, - verify_graceful_restart_timers, verify_bgp_convergence_from_running_config, ) @@ -169,7 +166,7 @@ def setup_module(mod): # Api call verify whether BGP is converged ADDR_TYPES = check_address_types() - for addr_type in ADDR_TYPES: + for _ in ADDR_TYPES: BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo) assert BGP_CONVERGENCE is True, "setup_module : Failed \n Error:" " {}".format( BGP_CONVERGENCE diff --git a/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-2.py b/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-2.py index cf9a474a81..989d2d554a 100644 --- a/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-2.py +++ b/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-2.py @@ -95,7 +95,6 @@ verify_graceful_restart, create_router_bgp, verify_r_bit, - verify_eor, verify_f_bit, verify_bgp_convergence, verify_gr_address_family, @@ -114,7 +113,6 @@ check_address_types, write_test_footer, check_router_status, - step, get_frr_ipv6_linklocal, required_linux_kernel_version, ) @@ -169,7 +167,7 @@ def setup_module(mod): # Api call verify whether BGP is converged ADDR_TYPES = check_address_types() - for addr_type in ADDR_TYPES: + for _ in ADDR_TYPES: BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo) assert BGP_CONVERGENCE is True, "setup_module : Failed \n Error:" " {}".format( BGP_CONVERGENCE diff --git a/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-3.py b/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-3.py index 4746d71a32..05fb8bf796 100644 --- a/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-3.py +++ b/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-3.py @@ -98,9 +98,7 @@ verify_eor, verify_f_bit, verify_bgp_convergence, - verify_gr_address_family, modify_bgp_config_when_bgpd_down, - verify_graceful_restart_timers, verify_bgp_convergence_from_running_config, ) @@ -114,7 +112,6 @@ check_address_types, write_test_footer, check_router_status, - step, get_frr_ipv6_linklocal, required_linux_kernel_version, ) @@ -169,7 +166,7 @@ def setup_module(mod): # Api call verify whether BGP is converged ADDR_TYPES = check_address_types() - for addr_type in ADDR_TYPES: + for _ in ADDR_TYPES: BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo) assert BGP_CONVERGENCE is True, "setup_module : Failed \n Error:" " {}".format( BGP_CONVERGENCE diff --git a/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-4.py b/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-4.py index 1c41df98e1..950733c3af 100644 --- a/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-4.py +++ b/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-4.py @@ -96,13 +96,9 @@ verify_bgp_rib, verify_graceful_restart, create_router_bgp, - verify_r_bit, verify_eor, - verify_f_bit, verify_bgp_convergence, - verify_gr_address_family, modify_bgp_config_when_bgpd_down, - verify_graceful_restart_timers, verify_bgp_convergence_from_running_config, ) @@ -116,7 +112,6 @@ check_address_types, write_test_footer, check_router_status, - step, get_frr_ipv6_linklocal, required_linux_kernel_version, ) @@ -171,7 +166,7 @@ def setup_module(mod): # Api call verify whether BGP is converged ADDR_TYPES = check_address_types() - for addr_type in ADDR_TYPES: + for _ in ADDR_TYPES: BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo) assert BGP_CONVERGENCE is True, "setup_module : Failed \n Error:" " {}".format( BGP_CONVERGENCE diff --git a/tests/topotests/bgp_gr_functionality_topo3/test_bgp_gr_functionality_topo3.py b/tests/topotests/bgp_gr_functionality_topo3/test_bgp_gr_functionality_topo3.py index 593a8d6417..e24f31d862 100644 --- a/tests/topotests/bgp_gr_functionality_topo3/test_bgp_gr_functionality_topo3.py +++ b/tests/topotests/bgp_gr_functionality_topo3/test_bgp_gr_functionality_topo3.py @@ -12,7 +12,6 @@ import pytest from time import sleep -import traceback import ipaddress # Save the Current Working Directory to find configuration files. @@ -34,37 +33,21 @@ verify_bgp_rib, verify_graceful_restart, create_router_bgp, - verify_r_bit, - verify_eor, - verify_f_bit, verify_bgp_convergence, - verify_gr_address_family, - modify_bgp_config_when_bgpd_down, - verify_graceful_restart_timers, verify_bgp_convergence_from_running_config, ) # Import common_config to use commomnly used APIs from lib.common_config import ( - create_common_configuration, - InvalidCLIError, - retry, generate_ips, - FRRCFG_FILE, - find_interface_with_greater_ip, check_address_types, validate_ip_address, run_frr_cmd, - get_frr_ipv6_linklocal, ) from lib.common_config import ( write_test_header, - reset_config_on_routers, start_topology, - kill_router_daemons, - start_router_daemons, - verify_rib, check_address_types, write_test_footer, check_router_status, @@ -154,9 +137,6 @@ def verify_stale_routes_list(tgen, addr_type, dut, input_dict): """ logger.debug("Entering lib API: verify_stale_routes_list()") router_list = tgen.routers() - additional_nexthops_in_required_nhs = [] - list1 = [] - list2 = [] found_hops = [] for routerInput in input_dict.keys(): for router, rnode in router_list.items(): @@ -266,7 +246,7 @@ def setup_module(mod): # Api call verify whether BGP is converged ADDR_TYPES = check_address_types() - for addr_type in ADDR_TYPES: + for _ in ADDR_TYPES: BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo) assert BGP_CONVERGENCE is True, "setup_module : Failed \n Error:" " {}".format( BGP_CONVERGENCE @@ -442,7 +422,7 @@ def test_bgp_gr_stale_routes(request): ) assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) - for iteration in range(5): + for _ in range(5): step("graceful-restart-disable:True at R3") input_dict = { "r3": { diff --git a/tests/topotests/bgp_gr_restart_retain_routes/test_bgp_gr_per_neighbor_restart_retain_routes.py b/tests/topotests/bgp_gr_restart_retain_routes/test_bgp_gr_per_neighbor_restart_retain_routes.py index 2354c0cd3d..e61efefa5a 100644 --- a/tests/topotests/bgp_gr_restart_retain_routes/test_bgp_gr_per_neighbor_restart_retain_routes.py +++ b/tests/topotests/bgp_gr_restart_retain_routes/test_bgp_gr_per_neighbor_restart_retain_routes.py @@ -22,7 +22,7 @@ # pylint: disable=C0413 from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen from lib.common_config import step, stop_router pytestmark = [pytest.mark.bgpd] diff --git a/tests/topotests/bgp_gr_restart_retain_routes/test_bgp_gr_restart_retain_routes.py b/tests/topotests/bgp_gr_restart_retain_routes/test_bgp_gr_restart_retain_routes.py index abf737ff34..d7ae43338a 100644 --- a/tests/topotests/bgp_gr_restart_retain_routes/test_bgp_gr_restart_retain_routes.py +++ b/tests/topotests/bgp_gr_restart_retain_routes/test_bgp_gr_restart_retain_routes.py @@ -21,7 +21,7 @@ # pylint: disable=C0413 from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen from lib.common_config import step, stop_router pytestmark = [pytest.mark.bgpd] diff --git a/tests/topotests/bgp_ipv4_over_ipv6/test_rfc5549_ebgp_unnumbered_nbr.py b/tests/topotests/bgp_ipv4_over_ipv6/test_rfc5549_ebgp_unnumbered_nbr.py index 395ef2d919..803b51c043 100644 --- a/tests/topotests/bgp_ipv4_over_ipv6/test_rfc5549_ebgp_unnumbered_nbr.py +++ b/tests/topotests/bgp_ipv4_over_ipv6/test_rfc5549_ebgp_unnumbered_nbr.py @@ -23,7 +23,7 @@ from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen from lib.common_config import ( write_test_header, diff --git a/tests/topotests/bgp_l3vpn_label_export/test_bgp_l3vpn_label_export.py b/tests/topotests/bgp_l3vpn_label_export/test_bgp_l3vpn_label_export.py index 84a9c8b723..a0871a4922 100644 --- a/tests/topotests/bgp_l3vpn_label_export/test_bgp_l3vpn_label_export.py +++ b/tests/topotests/bgp_l3vpn_label_export/test_bgp_l3vpn_label_export.py @@ -146,7 +146,7 @@ def check_mpls_table(label, protocol): if label == "auto" and protocol: output_copy = deepcopy(output) - for key, data in output_copy.items(): + for _, data in output_copy.items(): for nexthop in data.get("nexthops", []): if nexthop.get("type", None) != protocol: continue diff --git a/tests/topotests/bgp_labeled_unicast_default_originate/test_bgp_labeled_unicast_default_originate.py b/tests/topotests/bgp_labeled_unicast_default_originate/test_bgp_labeled_unicast_default_originate.py index d1d384182c..009b39eef0 100644 --- a/tests/topotests/bgp_labeled_unicast_default_originate/test_bgp_labeled_unicast_default_originate.py +++ b/tests/topotests/bgp_labeled_unicast_default_originate/test_bgp_labeled_unicast_default_originate.py @@ -22,7 +22,6 @@ # pylint: disable=C0413 from lib import topotest from lib.topogen import Topogen, TopoRouter, get_topogen -from lib.common_config import step pytestmark = [pytest.mark.bgpd] diff --git a/tests/topotests/bgp_llgr/test_bgp_llgr.py b/tests/topotests/bgp_llgr/test_bgp_llgr.py index 2a3753e26c..547c998c2b 100644 --- a/tests/topotests/bgp_llgr/test_bgp_llgr.py +++ b/tests/topotests/bgp_llgr/test_bgp_llgr.py @@ -32,7 +32,6 @@ from lib.common_config import ( kill_router_daemons, - start_router_daemons, step, ) diff --git a/tests/topotests/bgp_local_asn/test_bgp_local_asn_agg.py b/tests/topotests/bgp_local_asn/test_bgp_local_asn_agg.py index c84fce6a9d..214b24eed8 100644 --- a/tests/topotests/bgp_local_asn/test_bgp_local_asn_agg.py +++ b/tests/topotests/bgp_local_asn/test_bgp_local_asn_agg.py @@ -25,7 +25,6 @@ # pylint: disable=C0413 # Import topogen and topotest helpers from lib.topogen import Topogen, get_topogen -from lib.topotest import version_cmp from lib.common_config import ( start_topology, diff --git a/tests/topotests/bgp_local_asn/test_bgp_local_asn_ecmp.py b/tests/topotests/bgp_local_asn/test_bgp_local_asn_ecmp.py index 8a1157052e..ce448329eb 100644 --- a/tests/topotests/bgp_local_asn/test_bgp_local_asn_ecmp.py +++ b/tests/topotests/bgp_local_asn/test_bgp_local_asn_ecmp.py @@ -21,7 +21,6 @@ import sys import time import pytest -import platform # Save the Current Working Directory to find configuration files. CWD = os.path.dirname(os.path.realpath(__file__)) @@ -31,7 +30,6 @@ # pylint: disable=C0413 # Import topogen and topotest helpers from lib.topogen import Topogen, get_topogen -from lib.topotest import version_cmp from lib.common_config import ( start_topology, diff --git a/tests/topotests/bgp_local_asn/test_bgp_local_asn_topo1.py b/tests/topotests/bgp_local_asn/test_bgp_local_asn_topo1.py index 25c9bee93c..ff1a81472d 100644 --- a/tests/topotests/bgp_local_asn/test_bgp_local_asn_topo1.py +++ b/tests/topotests/bgp_local_asn/test_bgp_local_asn_topo1.py @@ -39,7 +39,6 @@ # pylint: disable=C0413 # Import topogen and topotest helpers from lib.topogen import Topogen, get_topogen -from lib.topotest import version_cmp from lib.common_config import ( start_topology, diff --git a/tests/topotests/bgp_local_asn/test_bgp_local_asn_topo2.py b/tests/topotests/bgp_local_asn/test_bgp_local_asn_topo2.py index 0c10c6409f..5d290ce427 100644 --- a/tests/topotests/bgp_local_asn/test_bgp_local_asn_topo2.py +++ b/tests/topotests/bgp_local_asn/test_bgp_local_asn_topo2.py @@ -31,7 +31,6 @@ # pylint: disable=C0413 # Import topogen and topotest helpers from lib.topogen import Topogen, get_topogen -from lib.topotest import version_cmp from lib.common_config import ( start_topology, diff --git a/tests/topotests/bgp_local_asn/test_bgp_local_asn_vrf_topo1.py b/tests/topotests/bgp_local_asn/test_bgp_local_asn_vrf_topo1.py index ea6ab59b3f..0c7e7cf5c1 100644 --- a/tests/topotests/bgp_local_asn/test_bgp_local_asn_vrf_topo1.py +++ b/tests/topotests/bgp_local_asn/test_bgp_local_asn_vrf_topo1.py @@ -26,7 +26,6 @@ # pylint: disable=C0413 # Import topogen and topotest helpers from lib.topogen import Topogen, get_topogen -from lib.topotest import version_cmp from lib.common_config import ( start_topology, diff --git a/tests/topotests/bgp_local_asn/test_bgp_local_asn_vrf_topo2.py b/tests/topotests/bgp_local_asn/test_bgp_local_asn_vrf_topo2.py index b1204bf583..5a0f34132a 100644 --- a/tests/topotests/bgp_local_asn/test_bgp_local_asn_vrf_topo2.py +++ b/tests/topotests/bgp_local_asn/test_bgp_local_asn_vrf_topo2.py @@ -24,7 +24,6 @@ # pylint: disable=C0413 # Import topogen and topotest helpers from lib.topogen import Topogen, get_topogen -from lib.topotest import version_cmp from lib.common_config import ( start_topology, diff --git a/tests/topotests/bgp_local_asn_dot/test_bgp_local_asn_dot_agg.py b/tests/topotests/bgp_local_asn_dot/test_bgp_local_asn_dot_agg.py index cfaab9bbe2..453f058223 100644 --- a/tests/topotests/bgp_local_asn_dot/test_bgp_local_asn_dot_agg.py +++ b/tests/topotests/bgp_local_asn_dot/test_bgp_local_asn_dot_agg.py @@ -38,7 +38,6 @@ # pylint: disable=C0413 # Import topogen and topotest helpers from lib.topogen import Topogen, get_topogen -from lib.topotest import version_cmp from lib.common_config import ( start_topology, diff --git a/tests/topotests/bgp_local_asn_dot/test_bgp_local_asn_dot_ecmp.py b/tests/topotests/bgp_local_asn_dot/test_bgp_local_asn_dot_ecmp.py index 6937a61c33..d52ed4c334 100644 --- a/tests/topotests/bgp_local_asn_dot/test_bgp_local_asn_dot_ecmp.py +++ b/tests/topotests/bgp_local_asn_dot/test_bgp_local_asn_dot_ecmp.py @@ -34,7 +34,6 @@ import sys import time import pytest -import platform # Save the Current Working Directory to find configuration files. CWD = os.path.dirname(os.path.realpath(__file__)) @@ -44,7 +43,6 @@ # pylint: disable=C0413 # Import topogen and topotest helpers from lib.topogen import Topogen, get_topogen -from lib.topotest import version_cmp from lib.common_config import ( start_topology, diff --git a/tests/topotests/bgp_local_asn_dot/test_bgp_local_asn_dot_topo1.py b/tests/topotests/bgp_local_asn_dot/test_bgp_local_asn_dot_topo1.py index bacef47664..4ee112ebbf 100644 --- a/tests/topotests/bgp_local_asn_dot/test_bgp_local_asn_dot_topo1.py +++ b/tests/topotests/bgp_local_asn_dot/test_bgp_local_asn_dot_topo1.py @@ -52,7 +52,6 @@ # pylint: disable=C0413 # Import topogen and topotest helpers from lib.topogen import Topogen, get_topogen -from lib.topotest import version_cmp from lib.common_config import ( start_topology, diff --git a/tests/topotests/bgp_multi_vrf_topo2/test_bgp_multi_vrf_topo2.py b/tests/topotests/bgp_multi_vrf_topo2/test_bgp_multi_vrf_topo2.py index 40a28fbcf4..012b643dde 100644 --- a/tests/topotests/bgp_multi_vrf_topo2/test_bgp_multi_vrf_topo2.py +++ b/tests/topotests/bgp_multi_vrf_topo2/test_bgp_multi_vrf_topo2.py @@ -1845,7 +1845,7 @@ def test_vrf_vlan_routing_table_p1(request): dut = "r3" vrf = "RED_A" - for c_link, c_data in topo["routers"][dut]["links"].items(): + for _, c_data in topo["routers"][dut]["links"].items(): if c_data["vrf"] != vrf: continue @@ -2634,7 +2634,7 @@ def test_delete_and_re_add_vrf_p1(request): vrfs = ["RED_A", "BLUE_A"] for vrf in vrfs: - for c_link, c_data in topo["routers"][dut]["links"].items(): + for _, c_data in topo["routers"][dut]["links"].items(): if c_data["vrf"] != vrf: continue @@ -3584,7 +3584,7 @@ def test_vrf_name_significance_p1(request): vrfs = ["GREY_A", "PINK_A"] for vrf in vrfs: - for c_link, c_data in topo_modify["routers"][dut]["links"].items(): + for _, c_data in topo_modify["routers"][dut]["links"].items(): if c_data["vrf"] != vrf: continue diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/test_nexthop_mp_ipv4_6.py b/tests/topotests/bgp_nexthop_mp_ipv4_6/test_nexthop_mp_ipv4_6.py index 911a6d757f..e1c28084de 100644 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/test_nexthop_mp_ipv4_6.py +++ b/tests/topotests/bgp_nexthop_mp_ipv4_6/test_nexthop_mp_ipv4_6.py @@ -12,7 +12,6 @@ import os import sys import json -import functools from functools import partial import pytest diff --git a/tests/topotests/bgp_node_target_extcommunities/test_bgp_node_target_extcommunities.py b/tests/topotests/bgp_node_target_extcommunities/test_bgp_node_target_extcommunities.py index b53673ad0f..32f78c44f9 100644 --- a/tests/topotests/bgp_node_target_extcommunities/test_bgp_node_target_extcommunities.py +++ b/tests/topotests/bgp_node_target_extcommunities/test_bgp_node_target_extcommunities.py @@ -24,7 +24,7 @@ # pylint: disable=C0413 from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen pytestmark = [pytest.mark.bgpd] diff --git a/tests/topotests/bgp_oad/test_bgp_oad.py b/tests/topotests/bgp_oad/test_bgp_oad.py index bb779462db..6dd46fbdaa 100644 --- a/tests/topotests/bgp_oad/test_bgp_oad.py +++ b/tests/topotests/bgp_oad/test_bgp_oad.py @@ -11,7 +11,6 @@ """ import os -import re import sys import json import pytest @@ -24,8 +23,7 @@ # pylint: disable=C0413 from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen -from lib.common_config import step +from lib.topogen import Topogen, get_topogen def setup_module(mod): diff --git a/tests/topotests/bgp_path_attribute_discard/test_bgp_path_attribute_discard.py b/tests/topotests/bgp_path_attribute_discard/test_bgp_path_attribute_discard.py index bd8cd8e18a..adc92f59fe 100644 --- a/tests/topotests/bgp_path_attribute_discard/test_bgp_path_attribute_discard.py +++ b/tests/topotests/bgp_path_attribute_discard/test_bgp_path_attribute_discard.py @@ -23,7 +23,7 @@ # pylint: disable=C0413 from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen from lib.common_config import step pytestmark = [pytest.mark.bgpd] diff --git a/tests/topotests/bgp_prefix_sid2/test_bgp_prefix_sid2.py b/tests/topotests/bgp_prefix_sid2/test_bgp_prefix_sid2.py index d6b94329e4..cf0c9fea2e 100755 --- a/tests/topotests/bgp_prefix_sid2/test_bgp_prefix_sid2.py +++ b/tests/topotests/bgp_prefix_sid2/test_bgp_prefix_sid2.py @@ -90,7 +90,7 @@ def check(name, cmd, expected_file): logger.info('[+] check {} "{}" {}'.format(name, cmd, expected_file)) tgen = get_topogen() func = functools.partial(_check, name, cmd, expected_file) - success, result = topotest.run_and_expect(func, None, count=10, wait=0.5) + _, result = topotest.run_and_expect(func, None, count=10, wait=0.5) assert result is None, "Failed" check("r1", "show bgp ipv6 vpn 2001:1::/64 json", "r1/vpnv6_rib_entry1.json") diff --git a/tests/topotests/bgp_redistribute_table/test_bgp_redistribute_table.py b/tests/topotests/bgp_redistribute_table/test_bgp_redistribute_table.py index 08b70ae0da..614610ccd6 100644 --- a/tests/topotests/bgp_redistribute_table/test_bgp_redistribute_table.py +++ b/tests/topotests/bgp_redistribute_table/test_bgp_redistribute_table.py @@ -86,7 +86,7 @@ def _router_json_cmp_exact_filter(router, cmd, expected): json_output = json.loads(output) # filter out tableVersion, version, nhVrfId and vrfId - for route, attrs in json_output.items(): + for _, attrs in json_output.items(): for attr in attrs: if "table" in attr: attr.pop("table") diff --git a/tests/topotests/bgp_remove_private_as/test_bgp_remove_private_as.py b/tests/topotests/bgp_remove_private_as/test_bgp_remove_private_as.py index 2d8864c34a..8b965a1614 100644 --- a/tests/topotests/bgp_remove_private_as/test_bgp_remove_private_as.py +++ b/tests/topotests/bgp_remove_private_as/test_bgp_remove_private_as.py @@ -32,7 +32,6 @@ import os import sys import json -import time import pytest CWD = os.path.dirname(os.path.realpath(__file__)) diff --git a/tests/topotests/bgp_remove_private_as_route_map/test_bgp_remove_private_as_route_map.py b/tests/topotests/bgp_remove_private_as_route_map/test_bgp_remove_private_as_route_map.py index e3e4567aeb..10896e2b22 100644 --- a/tests/topotests/bgp_remove_private_as_route_map/test_bgp_remove_private_as_route_map.py +++ b/tests/topotests/bgp_remove_private_as_route_map/test_bgp_remove_private_as_route_map.py @@ -10,7 +10,6 @@ """ import os -import re import sys import json import pytest @@ -23,7 +22,7 @@ # pylint: disable=C0413 from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen def build_topo(tgen): diff --git a/tests/topotests/bgp_roles_capability/test_bgp_roles_capability.py b/tests/topotests/bgp_roles_capability/test_bgp_roles_capability.py index 29ff1065fd..9223cbd759 100644 --- a/tests/topotests/bgp_roles_capability/test_bgp_roles_capability.py +++ b/tests/topotests/bgp_roles_capability/test_bgp_roles_capability.py @@ -24,8 +24,7 @@ # pylint: disable=C0413 from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen -from lib.topolog import logger +from lib.topogen import Topogen, TopoRouter pytestmark = [pytest.mark.bgpd] @@ -38,7 +37,7 @@ def tgen(request): tgen = Topogen(topodef, request.module.__name__) tgen.start_topology() router_list = tgen.routers() - for rname, router in router_list.items(): + for _, router in router_list.items(): router.load_config(TopoRouter.RD_ZEBRA, "zebra.conf") router.load_config(TopoRouter.RD_BGP, "bgpd.conf") tgen.start_router() @@ -82,9 +81,7 @@ def test_correct_pair(tgen): check_r2_established = functools.partial( check_session_established, router, neighbor_ip ) - success, _ = topotest.run_and_expect( - check_r2_established, True, count=20, wait=3 - ) + success, _ = topotest.run_and_expect(check_r2_established, True, count=20, wait=3) assert success, "Session with r2 is not Established" neighbor_status = find_neighbor_status(router, neighbor_ip) @@ -111,9 +108,7 @@ def test_single_role_advertising(tgen): check_r4_established = functools.partial( check_session_established, router, neighbor_ip ) - success, _ = topotest.run_and_expect( - check_r4_established, True, count=20, wait=3 - ) + success, _ = topotest.run_and_expect(check_r4_established, True, count=20, wait=3) assert success, "Session with r4 is not Established" neighbor_status = find_neighbor_status(router, neighbor_ip) @@ -129,9 +124,7 @@ def test_single_role_receiving(tgen): check_r1_established = functools.partial( check_session_established, router, neighbor_ip ) - success, _ = topotest.run_and_expect( - check_r1_established, True, count=20, wait=3 - ) + success, _ = topotest.run_and_expect(check_r1_established, True, count=20, wait=3) assert success, "Session with r1 is not Established" neighbor_status = find_neighbor_status(router, neighbor_ip) diff --git a/tests/topotests/bgp_roles_filtering/test_bgp_roles_filtering.py b/tests/topotests/bgp_roles_filtering/test_bgp_roles_filtering.py index a43518bc8a..ffbf454ded 100644 --- a/tests/topotests/bgp_roles_filtering/test_bgp_roles_filtering.py +++ b/tests/topotests/bgp_roles_filtering/test_bgp_roles_filtering.py @@ -16,7 +16,6 @@ import json import os import sys -import functools import pytest CWD = os.path.dirname(os.path.realpath(__file__)) @@ -24,9 +23,7 @@ # pylint: disable=C0413 from lib import topotest -from lib.bgp import verify_bgp_convergence_from_running_config -from lib.topogen import Topogen, TopoRouter, get_topogen -from lib.topolog import logger +from lib.topogen import Topogen, TopoRouter pytestmark = [pytest.mark.bgpd] @@ -39,7 +36,7 @@ def tgen(request): tgen = Topogen(topodef, request.module.__name__) tgen.start_topology() router_list = tgen.routers() - for rname, router in router_list.items(): + for _, router in router_list.items(): router.load_config(TopoRouter.RD_ZEBRA, "zebra.conf") router.load_config(TopoRouter.RD_BGP, "bgpd.conf") tgen.start_router() @@ -69,9 +66,7 @@ def _routes_half_converged(): ] return output == expected - success, _ = topotest.run_and_expect( - _routes_half_converged, True, count=20, wait=3 - ) + success, _ = topotest.run_and_expect(_routes_half_converged, True, count=20, wait=3) assert success, "Routes did not converged" routes_with_otc = list() diff --git a/tests/topotests/bgp_route_aggregation/test_bgp_aggregation.py b/tests/topotests/bgp_route_aggregation/test_bgp_aggregation.py index d50d67b60e..94bf092c76 100644 --- a/tests/topotests/bgp_route_aggregation/test_bgp_aggregation.py +++ b/tests/topotests/bgp_route_aggregation/test_bgp_aggregation.py @@ -119,7 +119,7 @@ def setup_module(mod): # Api call verify whether BGP is converged ADDR_TYPES = check_address_types() - for addr_type in ADDR_TYPES: + for _ in ADDR_TYPES: BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo) assert BGP_CONVERGENCE is True, "setup_module :Failed \n Error:" " {}".format( BGP_CONVERGENCE diff --git a/tests/topotests/bgp_route_map_match_source_protocol/test_bgp_route_map_match_source_protocol.py b/tests/topotests/bgp_route_map_match_source_protocol/test_bgp_route_map_match_source_protocol.py index c766f5c1a8..7116deaea4 100644 --- a/tests/topotests/bgp_route_map_match_source_protocol/test_bgp_route_map_match_source_protocol.py +++ b/tests/topotests/bgp_route_map_match_source_protocol/test_bgp_route_map_match_source_protocol.py @@ -22,7 +22,7 @@ # pylint: disable=C0413 from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen pytestmark = [pytest.mark.bgpd] diff --git a/tests/topotests/bgp_route_map_match_tag_untagged/test_bgp_route_map_match_tag_untagged.py b/tests/topotests/bgp_route_map_match_tag_untagged/test_bgp_route_map_match_tag_untagged.py index 7dd63fdac0..6ffa078f0c 100644 --- a/tests/topotests/bgp_route_map_match_tag_untagged/test_bgp_route_map_match_tag_untagged.py +++ b/tests/topotests/bgp_route_map_match_tag_untagged/test_bgp_route_map_match_tag_untagged.py @@ -17,7 +17,7 @@ # pylint: disable=C0413 from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen pytestmark = [pytest.mark.bgpd] diff --git a/tests/topotests/bgp_route_map_vpn_import/test_bgp_route_map_vpn_import.py b/tests/topotests/bgp_route_map_vpn_import/test_bgp_route_map_vpn_import.py index 5ce8b17f24..a6641348f7 100644 --- a/tests/topotests/bgp_route_map_vpn_import/test_bgp_route_map_vpn_import.py +++ b/tests/topotests/bgp_route_map_vpn_import/test_bgp_route_map_vpn_import.py @@ -24,7 +24,6 @@ # pylint: disable=C0413 from lib import topotest from lib.topogen import Topogen, TopoRouter, get_topogen -from lib.common_config import step pytestmark = [pytest.mark.bgpd] diff --git a/tests/topotests/bgp_route_origin_parser/test_bgp_route_origin_parser.py b/tests/topotests/bgp_route_origin_parser/test_bgp_route_origin_parser.py index 673efc2c73..16afda8bcc 100644 --- a/tests/topotests/bgp_route_origin_parser/test_bgp_route_origin_parser.py +++ b/tests/topotests/bgp_route_origin_parser/test_bgp_route_origin_parser.py @@ -11,7 +11,6 @@ import os import sys -import json import pytest import functools diff --git a/tests/topotests/bgp_rr_ibgp/test_bgp_rr_ibgp_topo1.py b/tests/topotests/bgp_rr_ibgp/test_bgp_rr_ibgp_topo1.py index 9984abaa85..5022a4a4a3 100644 --- a/tests/topotests/bgp_rr_ibgp/test_bgp_rr_ibgp_topo1.py +++ b/tests/topotests/bgp_rr_ibgp/test_bgp_rr_ibgp_topo1.py @@ -132,7 +132,6 @@ def test_zebra_ipv4_routingTable(): if tgen.routers_have_failure(): pytest.skip(tgen.errors) - failures = 0 router_list = tgen.routers().values() for router in router_list: output = router.vtysh_cmd("show ip route json", isjson=True) diff --git a/tests/topotests/bgp_snmp_mplsl3vpn/test_bgp_snmp_mplsvpn.py b/tests/topotests/bgp_snmp_mplsl3vpn/test_bgp_snmp_mplsvpn.py index 0131e12579..09eef51338 100755 --- a/tests/topotests/bgp_snmp_mplsl3vpn/test_bgp_snmp_mplsvpn.py +++ b/tests/topotests/bgp_snmp_mplsl3vpn/test_bgp_snmp_mplsvpn.py @@ -325,7 +325,6 @@ def router_interface_get_ifindex(router, interface): def generate_vrf_ifindex_oid(vrf, ifindex): - intoid = snmp_uint32_to_oid(int(ifindex)) vrfoid = snmp_str_to_oid(vrf) oid = "{}.{}".format(vrfoid, intoid) diff --git a/tests/topotests/bgp_srv6_sid_reachability/test_bgp_srv6_sid_reachability.py b/tests/topotests/bgp_srv6_sid_reachability/test_bgp_srv6_sid_reachability.py index 92315bce04..f8385401c5 100755 --- a/tests/topotests/bgp_srv6_sid_reachability/test_bgp_srv6_sid_reachability.py +++ b/tests/topotests/bgp_srv6_sid_reachability/test_bgp_srv6_sid_reachability.py @@ -8,10 +8,7 @@ # import os -import re import sys -import json -import functools import pytest CWD = os.path.dirname(os.path.realpath(__file__)) @@ -19,9 +16,7 @@ # pylint: disable=C0413 # Import topogen and topotest helpers -from lib import topotest from lib.topogen import Topogen, TopoRouter, get_topogen -from lib.topolog import logger from lib.common_config import required_linux_kernel_version from lib.checkping import check_ping diff --git a/tests/topotests/bgp_srv6l3vpn_over_ipv6/test_bgp_srv6l3vpn_over_ipv6.py b/tests/topotests/bgp_srv6l3vpn_over_ipv6/test_bgp_srv6l3vpn_over_ipv6.py index 14b9ba8498..0b52c87d27 100755 --- a/tests/topotests/bgp_srv6l3vpn_over_ipv6/test_bgp_srv6l3vpn_over_ipv6.py +++ b/tests/topotests/bgp_srv6l3vpn_over_ipv6/test_bgp_srv6l3vpn_over_ipv6.py @@ -9,10 +9,7 @@ # import os -import re import sys -import json -import functools import pytest CWD = os.path.dirname(os.path.realpath(__file__)) @@ -20,9 +17,7 @@ # pylint: disable=C0413 # Import topogen and topotest helpers -from lib import topotest from lib.topogen import Topogen, TopoRouter, get_topogen -from lib.topolog import logger from lib.common_config import required_linux_kernel_version from lib.checkping import check_ping diff --git a/tests/topotests/bgp_srv6l3vpn_route_leak/test_bgp_srv6l3vpn_route_leak.py b/tests/topotests/bgp_srv6l3vpn_route_leak/test_bgp_srv6l3vpn_route_leak.py index f0c9144248..4bd5fdf165 100755 --- a/tests/topotests/bgp_srv6l3vpn_route_leak/test_bgp_srv6l3vpn_route_leak.py +++ b/tests/topotests/bgp_srv6l3vpn_route_leak/test_bgp_srv6l3vpn_route_leak.py @@ -6,10 +6,8 @@ # import os -import re import sys import json -import functools import pytest CWD = os.path.dirname(os.path.realpath(__file__)) @@ -20,7 +18,6 @@ from lib import topotest from lib.topogen import Topogen, TopoRouter, get_topogen from lib.topolog import logger -from lib.common_config import required_linux_kernel_version pytestmark = [pytest.mark.bgpd] diff --git a/tests/topotests/bgp_srv6l3vpn_sid/test_bgp_srv6l3vpn_sid.py b/tests/topotests/bgp_srv6l3vpn_sid/test_bgp_srv6l3vpn_sid.py index 787707cc0f..8d303a774b 100755 --- a/tests/topotests/bgp_srv6l3vpn_sid/test_bgp_srv6l3vpn_sid.py +++ b/tests/topotests/bgp_srv6l3vpn_sid/test_bgp_srv6l3vpn_sid.py @@ -20,7 +20,6 @@ # import os -import re import sys import json import functools diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/test_bgp_srv6l3vpn_to_bgp_vrf2.py b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/test_bgp_srv6l3vpn_to_bgp_vrf2.py index 38baf43442..b75d0d8751 100755 --- a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/test_bgp_srv6l3vpn_to_bgp_vrf2.py +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/test_bgp_srv6l3vpn_to_bgp_vrf2.py @@ -9,7 +9,6 @@ # import os -import re import sys import json import functools diff --git a/tests/topotests/bgp_suppress_fib/test_bgp_suppress_fib.py b/tests/topotests/bgp_suppress_fib/test_bgp_suppress_fib.py index fa8a88297f..f7ac827e26 100644 --- a/tests/topotests/bgp_suppress_fib/test_bgp_suppress_fib.py +++ b/tests/topotests/bgp_suppress_fib/test_bgp_suppress_fib.py @@ -15,7 +15,6 @@ import json import pytest from functools import partial -from time import sleep from lib.topolog import logger CWD = os.path.dirname(os.path.realpath(__file__)) diff --git a/tests/topotests/bgp_tcp_mss/test_bgp_vrf_tcp_mss.py b/tests/topotests/bgp_tcp_mss/test_bgp_vrf_tcp_mss.py index aeb9bf529d..4a03cb0a6d 100644 --- a/tests/topotests/bgp_tcp_mss/test_bgp_vrf_tcp_mss.py +++ b/tests/topotests/bgp_tcp_mss/test_bgp_vrf_tcp_mss.py @@ -17,12 +17,7 @@ import os import sys -import json import pytest -import functools -import platform -import socket -import subprocess # add after imports, before defining classes or functions: pytestmark = [pytest.mark.bgpd] @@ -31,43 +26,27 @@ sys.path.append(os.path.join(CWD, "../")) # pylint: disable=C0413 -from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen from lib.topojson import build_config_from_json -from lib.topolog import logger import time from lib.bgp import ( clear_bgp, - clear_bgp_and_verify, create_router_bgp, - modify_as_number, - verify_as_numbers, verify_bgp_convergence, verify_bgp_rib, - verify_bgp_timers_and_functionality, - verify_router_id, verify_tcp_mss, ) from lib.common_config import ( kill_router_daemons, start_router_daemons, - addKernelRoute, apply_raw_config, check_address_types, check_router_status, - create_prefix_lists, - create_route_maps, create_static_routes, required_linux_kernel_version, - reset_config_on_routers, start_topology, step, - verify_admin_distance_for_static_routes, - verify_bgp_community, - verify_fib_routes, - verify_rib, write_test_footer, - write_test_header, ) # Global variables diff --git a/tests/topotests/bgp_tcp_mss_passive/test_bgp_tcp_mss_passive.py b/tests/topotests/bgp_tcp_mss_passive/test_bgp_tcp_mss_passive.py index a2eacc7ab2..44336efed2 100644 --- a/tests/topotests/bgp_tcp_mss_passive/test_bgp_tcp_mss_passive.py +++ b/tests/topotests/bgp_tcp_mss_passive/test_bgp_tcp_mss_passive.py @@ -21,7 +21,7 @@ # pylint: disable=C0413 from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen pytestmark = [pytest.mark.bgpd] diff --git a/tests/topotests/bgp_unnumbered/test_bgp_unnumbered.py b/tests/topotests/bgp_unnumbered/test_bgp_unnumbered.py index 4d4e29b2f8..09b13e6a2f 100644 --- a/tests/topotests/bgp_unnumbered/test_bgp_unnumbered.py +++ b/tests/topotests/bgp_unnumbered/test_bgp_unnumbered.py @@ -27,7 +27,6 @@ def build_topo(tgen): - tgen.add_router("r1") tgen.add_router("r2") diff --git a/tests/topotests/bgp_vpn_5549_route_map/test_bgp_vpn_5549_route_map.py b/tests/topotests/bgp_vpn_5549_route_map/test_bgp_vpn_5549_route_map.py index 695cfc3d25..08d6e140a1 100644 --- a/tests/topotests/bgp_vpn_5549_route_map/test_bgp_vpn_5549_route_map.py +++ b/tests/topotests/bgp_vpn_5549_route_map/test_bgp_vpn_5549_route_map.py @@ -22,7 +22,6 @@ # pylint: disable=C0413 from lib import topotest from lib.topogen import Topogen, TopoRouter, get_topogen -from lib.common_config import step pytestmark = [pytest.mark.bgpd] diff --git a/tests/topotests/bgp_vpnv4_asbr/test_bgp_vpnv4_asbr.py b/tests/topotests/bgp_vpnv4_asbr/test_bgp_vpnv4_asbr.py index 8e2e4017df..5467cf4d84 100644 --- a/tests/topotests/bgp_vpnv4_asbr/test_bgp_vpnv4_asbr.py +++ b/tests/topotests/bgp_vpnv4_asbr/test_bgp_vpnv4_asbr.py @@ -312,7 +312,7 @@ def _check_nexthop_available(router, prefix): return "{0}, {1}, route distinguisher not present".format( router.name, prefix ) - for rd, pathes in dump.items(): + for _, pathes in dump.items(): for path in pathes["paths"]: if "remoteLabel" not in path.keys(): return "{0}, {1}, remoteLabel not present".format( diff --git a/tests/topotests/bgp_vpnv4_noretain/test_bgp_vpnv4_noretain.py b/tests/topotests/bgp_vpnv4_noretain/test_bgp_vpnv4_noretain.py index 037dd40390..6237decfc3 100644 --- a/tests/topotests/bgp_vpnv4_noretain/test_bgp_vpnv4_noretain.py +++ b/tests/topotests/bgp_vpnv4_noretain/test_bgp_vpnv4_noretain.py @@ -141,7 +141,7 @@ def router_json_cmp_exact_filter(router, cmd, expected): # filter out tableVersion, version and nhVrfID json_output.pop("tableVersion") for rd, data in json_output["routes"]["routeDistinguishers"].items(): - for prefix, attrs in data.items(): + for _, attrs in data.items(): for attr in attrs: if "nhVrfId" in attr: attr.pop("nhVrfId") @@ -171,7 +171,7 @@ def router_vrf_json_cmp_exact_filter(router, cmd, expected): data.pop("tableVersion") if "routes" not in data: continue - for route, attrs in data["routes"].items(): + for _, attrs in data["routes"].items(): for attr in attrs: if "nhVrfId" in attr: attr.pop("nhVrfId") diff --git a/tests/topotests/bgp_vpnv4_per_nexthop_label/test_bgp_vpnv4_per_nexthop_label.py b/tests/topotests/bgp_vpnv4_per_nexthop_label/test_bgp_vpnv4_per_nexthop_label.py index b017880545..cf1d3cb2b8 100644 --- a/tests/topotests/bgp_vpnv4_per_nexthop_label/test_bgp_vpnv4_per_nexthop_label.py +++ b/tests/topotests/bgp_vpnv4_per_nexthop_label/test_bgp_vpnv4_per_nexthop_label.py @@ -183,7 +183,7 @@ def bgp_vpnv4_table_check(router, group, label_list=None, label_value_expected=N assert dump, "{0}, {1}, route distinguisher not present".format( router.name, prefix ) - for rd, pathes in dump.items(): + for _, pathes in dump.items(): for path in pathes["paths"]: assert ( "remoteLabel" in path.keys() @@ -305,7 +305,7 @@ def mpls_table_check(router, blacklist=None, label_list=None, whitelist=None): test_func = functools.partial( check_show_mpls_table, router, blacklist, label_list, whitelist ) - success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "{}, MPLS labels check fail: {}".format(router.name, result) diff --git a/tests/topotests/bgp_vpnv6_per_nexthop_label/test_bgp_vpnv6_per_nexthop_label.py b/tests/topotests/bgp_vpnv6_per_nexthop_label/test_bgp_vpnv6_per_nexthop_label.py index 3879687aac..f8d26427eb 100644 --- a/tests/topotests/bgp_vpnv6_per_nexthop_label/test_bgp_vpnv6_per_nexthop_label.py +++ b/tests/topotests/bgp_vpnv6_per_nexthop_label/test_bgp_vpnv6_per_nexthop_label.py @@ -179,7 +179,7 @@ def bgp_vpnv6_table_check(router, group, label_list=None, label_value_expected=N ) dump = router.vtysh_cmd("show bgp ipv6 vpn {} json".format(prefix), isjson=True) - for rd, pathes in dump.items(): + for _, pathes in dump.items(): for path in pathes["paths"]: assert ( "remoteLabel" in path.keys() @@ -300,7 +300,7 @@ def mpls_table_check(router, blacklist=None, label_list=None, whitelist=None): test_func = functools.partial( check_show_mpls_table, router, blacklist, label_list, whitelist ) - success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "{}, MPLS labels check fail: {}".format(router.name, result) @@ -798,7 +798,7 @@ def test_reconfigure_allocation_mode_nexthop(): test_func = functools.partial( check_show_mpls_table_entry_label_not_found, router, 17 ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "r1, mpls entry with label 17 still present" # Check vpnv6 routes from r1 diff --git a/tests/topotests/bgp_vrf_dynamic_route_leak/test_bgp_vrf_dynamic_route_leak_topo2.py b/tests/topotests/bgp_vrf_dynamic_route_leak/test_bgp_vrf_dynamic_route_leak_topo2.py index 32643c27b8..8d73e5f8ac 100644 --- a/tests/topotests/bgp_vrf_dynamic_route_leak/test_bgp_vrf_dynamic_route_leak_topo2.py +++ b/tests/topotests/bgp_vrf_dynamic_route_leak/test_bgp_vrf_dynamic_route_leak_topo2.py @@ -18,7 +18,6 @@ import os import sys -import json import time import pytest import platform @@ -58,7 +57,7 @@ verify_best_path_as_per_bgp_attribute, verify_bgp_rib, ) -from lib.topojson import build_topo_from_json, build_config_from_json +from lib.topojson import build_config_from_json pytestmark = [pytest.mark.bgpd, pytest.mark.staticd] diff --git a/tests/topotests/bgp_vrf_dynamic_route_leak_topo3/test_bgp_vrf_dynamic_route_leak_topo3.py b/tests/topotests/bgp_vrf_dynamic_route_leak_topo3/test_bgp_vrf_dynamic_route_leak_topo3.py index 726afcb6ae..25a73b58c7 100644 --- a/tests/topotests/bgp_vrf_dynamic_route_leak_topo3/test_bgp_vrf_dynamic_route_leak_topo3.py +++ b/tests/topotests/bgp_vrf_dynamic_route_leak_topo3/test_bgp_vrf_dynamic_route_leak_topo3.py @@ -23,7 +23,6 @@ import time import pytest import platform -from time import sleep # Save the Current Working Directory to find configuration files. CWD = os.path.dirname(os.path.realpath(__file__)) @@ -49,7 +48,6 @@ create_static_routes, create_prefix_lists, create_bgp_community_lists, - get_frr_ipv6_linklocal, ) from lib.topolog import logger diff --git a/tests/topotests/bgp_vrf_dynamic_route_leak_topo4/test_bgp_vrf_dynamic_route_leak_topo4-1.py b/tests/topotests/bgp_vrf_dynamic_route_leak_topo4/test_bgp_vrf_dynamic_route_leak_topo4-1.py index 45d7b0309e..53f0239c4d 100644 --- a/tests/topotests/bgp_vrf_dynamic_route_leak_topo4/test_bgp_vrf_dynamic_route_leak_topo4-1.py +++ b/tests/topotests/bgp_vrf_dynamic_route_leak_topo4/test_bgp_vrf_dynamic_route_leak_topo4-1.py @@ -24,7 +24,6 @@ import time import pytest import platform -from time import sleep # Save the Current Working Directory to find configuration files. CWD = os.path.dirname(os.path.realpath(__file__)) @@ -46,18 +45,13 @@ reset_config_on_routers, verify_rib, step, - create_route_maps, create_static_routes, - create_prefix_lists, - create_bgp_community_lists, - get_frr_ipv6_linklocal, ) from lib.topolog import logger from lib.bgp import ( verify_bgp_convergence, create_router_bgp, - verify_bgp_community, verify_bgp_rib, ) from lib.topojson import build_config_from_json diff --git a/tests/topotests/bgp_vrf_dynamic_route_leak_topo4/test_bgp_vrf_dynamic_route_leak_topo4-2.py b/tests/topotests/bgp_vrf_dynamic_route_leak_topo4/test_bgp_vrf_dynamic_route_leak_topo4-2.py index d29edf59b8..7b0eac3f74 100644 --- a/tests/topotests/bgp_vrf_dynamic_route_leak_topo4/test_bgp_vrf_dynamic_route_leak_topo4-2.py +++ b/tests/topotests/bgp_vrf_dynamic_route_leak_topo4/test_bgp_vrf_dynamic_route_leak_topo4-2.py @@ -24,7 +24,6 @@ import time import pytest import platform -from time import sleep # Save the Current Working Directory to find configuration files. CWD = os.path.dirname(os.path.realpath(__file__)) @@ -46,18 +45,13 @@ reset_config_on_routers, verify_rib, step, - create_route_maps, create_static_routes, - create_prefix_lists, - create_bgp_community_lists, - get_frr_ipv6_linklocal, ) from lib.topolog import logger from lib.bgp import ( verify_bgp_convergence, create_router_bgp, - verify_bgp_community, verify_bgp_rib, ) from lib.topojson import build_config_from_json diff --git a/tests/topotests/bgp_vrf_dynamic_route_leak_topo4/test_bgp_vrf_dynamic_route_leak_topo4-3.py b/tests/topotests/bgp_vrf_dynamic_route_leak_topo4/test_bgp_vrf_dynamic_route_leak_topo4-3.py index c118ffc090..ec7b25c7cc 100644 --- a/tests/topotests/bgp_vrf_dynamic_route_leak_topo4/test_bgp_vrf_dynamic_route_leak_topo4-3.py +++ b/tests/topotests/bgp_vrf_dynamic_route_leak_topo4/test_bgp_vrf_dynamic_route_leak_topo4-3.py @@ -24,7 +24,6 @@ import time import pytest import platform -from time import sleep # Save the Current Working Directory to find configuration files. CWD = os.path.dirname(os.path.realpath(__file__)) @@ -46,18 +45,13 @@ reset_config_on_routers, verify_rib, step, - create_route_maps, create_static_routes, - create_prefix_lists, - create_bgp_community_lists, - get_frr_ipv6_linklocal, ) from lib.topolog import logger from lib.bgp import ( verify_bgp_convergence, create_router_bgp, - verify_bgp_community, verify_bgp_rib, ) from lib.topojson import build_config_from_json diff --git a/tests/topotests/bgp_vrf_leaking_5549_routes/test_bgp_vrf_leaking.py b/tests/topotests/bgp_vrf_leaking_5549_routes/test_bgp_vrf_leaking.py index b20819264d..3539d06ac3 100755 --- a/tests/topotests/bgp_vrf_leaking_5549_routes/test_bgp_vrf_leaking.py +++ b/tests/topotests/bgp_vrf_leaking_5549_routes/test_bgp_vrf_leaking.py @@ -6,10 +6,8 @@ # import os -import re import sys import json -import functools import pytest CWD = os.path.dirname(os.path.realpath(__file__)) @@ -20,7 +18,6 @@ from lib import topotest from lib.topogen import Topogen, TopoRouter, get_topogen from lib.topolog import logger -from lib.common_config import required_linux_kernel_version pytestmark = [pytest.mark.bgpd] diff --git a/tests/topotests/bgp_vrf_lite_best_path_test/test_bgp_vrf_lite_best_path_topo1.py b/tests/topotests/bgp_vrf_lite_best_path_test/test_bgp_vrf_lite_best_path_topo1.py index f3521969d3..3790446dc9 100644 --- a/tests/topotests/bgp_vrf_lite_best_path_test/test_bgp_vrf_lite_best_path_topo1.py +++ b/tests/topotests/bgp_vrf_lite_best_path_test/test_bgp_vrf_lite_best_path_topo1.py @@ -49,9 +49,7 @@ from lib.bgp import ( verify_bgp_convergence, create_router_bgp, - verify_bgp_community, verify_bgp_rib, - clear_bgp, verify_best_path_as_per_bgp_attribute, ) from lib.topojson import build_config_from_json diff --git a/tests/topotests/bgp_vrf_lite_best_path_test/test_bgp_vrf_lite_best_path_topo2.py b/tests/topotests/bgp_vrf_lite_best_path_test/test_bgp_vrf_lite_best_path_topo2.py index 3cb31809fe..262cacd147 100644 --- a/tests/topotests/bgp_vrf_lite_best_path_test/test_bgp_vrf_lite_best_path_topo2.py +++ b/tests/topotests/bgp_vrf_lite_best_path_test/test_bgp_vrf_lite_best_path_topo2.py @@ -19,7 +19,6 @@ import time import pytest import platform -from time import sleep # Save the Current Working Directory to find configuration files. CWD = os.path.dirname(os.path.realpath(__file__)) From 80a4f87c9a38d5e893f7e24da11cc0c885db682e Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Fri, 12 Jul 2024 17:09:16 +0300 Subject: [PATCH 174/347] bgpd: Mark VRF instance as auto created if import vrf is configured for this instance If we create a new BGP instance (in this case VRF instance), it MUST be marked as auto created, to avoid bgpd changing VRF instance's ASN to the default VRF's. That's because of the ordering when FRR reload is happening. Signed-off-by: Donatas Abraitis --- bgpd/bgp_vty.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 0ef1351835..624edff0af 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -10567,12 +10567,20 @@ DEFPY(bgp_imexport_vrf, bgp_imexport_vrf_cmd, vrf_bgp = bgp_lookup_by_name(import_name); if (!vrf_bgp) { - if (strcmp(import_name, VRF_DEFAULT_NAME) == 0) + if (strcmp(import_name, VRF_DEFAULT_NAME) == 0) { vrf_bgp = bgp_default; - else + } else { /* Auto-create assuming the same AS */ ret = bgp_get_vty(&vrf_bgp, &as, import_name, bgp_type, NULL, ASNOTATION_UNDEFINED); + + /* Auto created VRF instances should be marked + * properly, otherwise we have a state after bgpd + * restart where VRF instance has default VRF's ASN. + */ + SET_FLAG(vrf_bgp->vrf_flags, BGP_VRF_AUTO); + } + if (ret) { vty_out(vty, "VRF %s is not configured as a bgp instance\n", From 7540364e58b08da7442927c1a9ffbd535d94fc46 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Sat, 13 Jul 2024 12:43:31 +0300 Subject: [PATCH 175/347] tests: Check if multiple VRF instances can have different ASNs Signed-off-by: Donatas Abraitis --- .../bgp_vrf_different_asn/__init__.py | 0 .../bgp_vrf_different_asn/r1/frr.conf | 18 ++++ .../test_bgp_vrf_different_asn.py | 89 +++++++++++++++++++ 3 files changed, 107 insertions(+) create mode 100644 tests/topotests/bgp_vrf_different_asn/__init__.py create mode 100644 tests/topotests/bgp_vrf_different_asn/r1/frr.conf create mode 100644 tests/topotests/bgp_vrf_different_asn/test_bgp_vrf_different_asn.py diff --git a/tests/topotests/bgp_vrf_different_asn/__init__.py b/tests/topotests/bgp_vrf_different_asn/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/topotests/bgp_vrf_different_asn/r1/frr.conf b/tests/topotests/bgp_vrf_different_asn/r1/frr.conf new file mode 100644 index 0000000000..b325dfb7f0 --- /dev/null +++ b/tests/topotests/bgp_vrf_different_asn/r1/frr.conf @@ -0,0 +1,18 @@ +! +vrf vrf100 + vni 10100 +exit-vrf +! +interface r1-eth0 vrf vrf100 + ip address 192.168.1.1/24 +! +router bgp 65000 + address-family ipv4 unicast + import vrf vrf100 + exit-address-family +! +router bgp 65100 vrf vrf100 + address-family ipv4 unicast + redistribute connected + exit-address-family +! diff --git a/tests/topotests/bgp_vrf_different_asn/test_bgp_vrf_different_asn.py b/tests/topotests/bgp_vrf_different_asn/test_bgp_vrf_different_asn.py new file mode 100644 index 0000000000..7334305ae4 --- /dev/null +++ b/tests/topotests/bgp_vrf_different_asn/test_bgp_vrf_different_asn.py @@ -0,0 +1,89 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# +# Copyright (c) 2024 by +# Donatas Abraitis +# + +import os +import sys +import json +import pytest +import functools + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen + +pytestmark = [pytest.mark.bgpd] + + +def build_topo(tgen): + for routern in range(1, 2): + tgen.add_router("r{}".format(routern)) + + switch = tgen.add_switch("s1") + switch.add_link(tgen.gears["r1"]) + + +def setup_module(mod): + tgen = Topogen(build_topo, mod.__name__) + tgen.start_topology() + + r1 = tgen.gears["r1"] + r1.run("ip link add vrf100 type vrf table 1001") + r1.run("ip link set up dev vrf100") + r1.run("ip link set r1-eth0 master vrf100") + + router_list = tgen.routers() + + for _, (rname, router) in enumerate(router_list.items(), 1): + router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname))) + + tgen.start_router() + + +def teardown_module(mod): + tgen = get_topogen() + tgen.stop_topology() + + +def test_bgp_vrf_different_asn(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + def _bgp_check_imported_route(): + output = json.loads( + tgen.gears["r1"].vtysh_cmd("show ip route 192.168.1.0/24 json") + ) + expected = { + "192.168.1.0/24": [ + { + "installed": True, + "selected": True, + "nexthops": [ + { + "interfaceName": "vrf100", + "vrf": "vrf100", + "active": True, + } + ], + } + ] + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial(_bgp_check_imported_route) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Can't see 192.168.1.0/24 being imported into a default VRF" + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) From 03c086866bdee9daf55420b88593345b9eb6be15 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Sat, 13 Jul 2024 23:19:57 +0300 Subject: [PATCH 176/347] bgpd: Skip automatically created BGP instances for show CMDs When using e.g. `adverise-all-vni`, and/or `import vrf ...`, the VRF instance is created with a default's VRF ASN and tagged as AUTO_VRF. We MUST skip them here also. Signed-off-by: Donatas Abraitis --- bgpd/bgp_vty.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 624edff0af..0d50a23902 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -12753,6 +12753,9 @@ static void bgp_show_all_instances_summary_vty(struct vty *vty, afi_t afi, vty_out(vty, "{\n"); for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) { + if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_AUTO)) + continue; + nbr_output = true; if (use_json) { if (!is_first) @@ -16138,6 +16141,9 @@ static void bgp_show_all_instances_neighbors_vty(struct vty *vty, vty_out(vty, "{\n"); for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) { + if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_AUTO)) + continue; + nbr_output = true; if (use_json) { if (!(json = json_object_new_object())) { @@ -16697,6 +16703,9 @@ static int bgp_show_all_instance_route_leak_vty(struct vty *vty, afi_t afi, if (bgp->inst_type != BGP_INSTANCE_TYPE_DEFAULT) vrf_name = bgp->name; + if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_AUTO)) + continue; + if (use_json) { json_vrf = json_object_new_object(); } else { @@ -16787,6 +16796,9 @@ static void bgp_show_all_instances_updgrps_vty(struct vty *vty, afi_t afi, struct bgp *bgp; for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) { + if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_AUTO)) + continue; + if (!uj) vty_out(vty, "\nInstance %s:\n", (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT) From c6c0403c61c157a9507781c332e152a2b220da52 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Sat, 13 Jul 2024 13:14:33 +0300 Subject: [PATCH 177/347] tests: Check if VRF instance has a different ASN than a default VRF Signed-off-by: Donatas Abraitis --- .../test_bgp_vrf_different_asn.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tests/topotests/bgp_vrf_different_asn/test_bgp_vrf_different_asn.py b/tests/topotests/bgp_vrf_different_asn/test_bgp_vrf_different_asn.py index 7334305ae4..9a1a9ec766 100644 --- a/tests/topotests/bgp_vrf_different_asn/test_bgp_vrf_different_asn.py +++ b/tests/topotests/bgp_vrf_different_asn/test_bgp_vrf_different_asn.py @@ -58,6 +58,24 @@ def test_bgp_vrf_different_asn(): if tgen.routers_have_failure(): pytest.skip(tgen.errors) + def _bgp_check_instances(): + output = json.loads(tgen.gears["r1"].vtysh_cmd("show bgp vrf all json")) + expected = { + "default": { + "vrfName": "default", + "localAS": 65000, + }, + "vrf100": { + "vrfName": "vrf100", + "localAS": 65100, + }, + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial(_bgp_check_instances) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Can't see vrf100 to be under 65100 ASN" + def _bgp_check_imported_route(): output = json.loads( tgen.gears["r1"].vtysh_cmd("show ip route 192.168.1.0/24 json") From bfedb38110e8d3e5471718a0f9abe8836ffc7143 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Mon, 15 Jul 2024 16:20:31 +0300 Subject: [PATCH 178/347] bgpd: Skip empty (auto created) VRF instances when deleting a default BGP instance Auto created VRF instances does not have any config, so it's not relevant depending on them. Signed-off-by: Donatas Abraitis --- bgpd/bgp_vty.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 0d50a23902..bce8202377 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -1701,6 +1701,10 @@ DEFUN (no_router_bgp, for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, tmp_bgp)) { if (tmp_bgp->inst_type != BGP_INSTANCE_TYPE_VRF) continue; + + if (CHECK_FLAG(tmp_bgp->vrf_flags, BGP_VRF_AUTO)) + continue; + if (CHECK_FLAG( tmp_bgp->af_flags[AFI_IP] [SAFI_UNICAST], From c2f2dde5c1b13aeccf0c9532bba32136abe33c0d Mon Sep 17 00:00:00 2001 From: sri-mohan1 Date: Sun, 19 May 2024 14:40:55 +0530 Subject: [PATCH 179/347] zebra: changes for code maintainability these changes are for improving the code maintainability and readability Signed-off-by: sri-mohan1 --- zebra/zebra_vxlan_if.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/zebra/zebra_vxlan_if.c b/zebra/zebra_vxlan_if.c index f4b859b861..17ab05c1f3 100644 --- a/zebra/zebra_vxlan_if.c +++ b/zebra/zebra_vxlan_if.c @@ -208,13 +208,13 @@ static int zebra_vxlan_if_update_vni(struct interface *ifp, chgflags); /* Removed from bridge? Cleanup and return */ - if ((chgflags & ZEBRA_VXLIF_MASTER_CHANGE) && + if (CHECK_FLAG(chgflags, ZEBRA_VXLIF_MASTER_CHANGE) && (zif->brslave_info.bridge_ifindex == IFINDEX_INTERNAL)) { zebra_vxlan_process_l3vni_oper_down(zl3vni); return 0; } - if ((chgflags & ZEBRA_VXLIF_MASTER_MAC_CHANGE) && + if (CHECK_FLAG(chgflags, ZEBRA_VXLIF_MASTER_MAC_CHANGE) && if_is_operative(ifp) && is_l3vni_oper_up(zl3vni)) { zebra_vxlan_process_l3vni_oper_down(zl3vni); zebra_vxlan_process_l3vni_oper_up(zl3vni); @@ -224,7 +224,7 @@ static int zebra_vxlan_if_update_vni(struct interface *ifp, /* access-vlan change - process oper down, associate with new * svi_if and then process oper up again */ - if (chgflags & ZEBRA_VXLIF_VLAN_CHANGE) { + if (CHECK_FLAG(chgflags, ZEBRA_VXLIF_VLAN_CHANGE)) { if (if_is_operative(ifp)) { zebra_vxlan_process_l3vni_oper_down(zl3vni); zl3vni->svi_if = NULL; @@ -242,7 +242,7 @@ static int zebra_vxlan_if_update_vni(struct interface *ifp, * local-ip change - process oper down, associate with new * local-ip and then process oper up again */ - if (chgflags & ZEBRA_VXLIF_LOCAL_IP_CHANGE) { + if (CHECK_FLAG(chgflags, ZEBRA_VXLIF_LOCAL_IP_CHANGE)) { if (if_is_operative(ifp)) { zebra_vxlan_process_l3vni_oper_down(zl3vni); zl3vni->local_vtep_ip = vxl->vtep_ip; @@ -262,7 +262,7 @@ static int zebra_vxlan_if_update_vni(struct interface *ifp, zl3vni_bridge_if_set(zl3vni, br_if, true /* set */); /* if we have a valid new master, process l3-vni oper up */ - if (chgflags & ZEBRA_VXLIF_MASTER_CHANGE) { + if (CHECK_FLAG(chgflags, ZEBRA_VXLIF_MASTER_CHANGE)) { if (if_is_operative(ifp) && is_l3vni_oper_up(zl3vni)) zebra_vxlan_process_l3vni_oper_up(zl3vni); } @@ -285,7 +285,7 @@ static int zebra_vxlan_if_update_vni(struct interface *ifp, chgflags); /* Removed from bridge? Cleanup and return */ - if ((chgflags & ZEBRA_VXLIF_MASTER_CHANGE) && + if (CHECK_FLAG(chgflags, ZEBRA_VXLIF_MASTER_CHANGE) && (zif->brslave_info.bridge_ifindex == IFINDEX_INTERNAL)) { /* Delete from client, remove all remote VTEPs */ /* Also, free up all MACs and neighbors. */ @@ -298,7 +298,7 @@ static int zebra_vxlan_if_update_vni(struct interface *ifp, } /* Handle other changes. */ - if (chgflags & ZEBRA_VXLIF_VLAN_CHANGE) { + if (CHECK_FLAG(chgflags, ZEBRA_VXLIF_VLAN_CHANGE)) { /* Remove all existing local neigh and MACs for this VNI * (including from BGP) */ @@ -341,9 +341,10 @@ static int zebra_vxlan_if_update_vni(struct interface *ifp, return 0; /* Inform BGP, if there is a change of interest. */ - if (chgflags & - (ZEBRA_VXLIF_MASTER_CHANGE | ZEBRA_VXLIF_LOCAL_IP_CHANGE | - ZEBRA_VXLIF_MCAST_GRP_CHANGE | ZEBRA_VXLIF_VLAN_CHANGE)) + if (CHECK_FLAG(chgflags, (ZEBRA_VXLIF_MASTER_CHANGE | + ZEBRA_VXLIF_LOCAL_IP_CHANGE | + ZEBRA_VXLIF_MCAST_GRP_CHANGE | + ZEBRA_VXLIF_VLAN_CHANGE))) zebra_evpn_send_add_to_client(zevpn); /* If there is a valid new master or a VLAN mapping change, @@ -351,9 +352,9 @@ static int zebra_vxlan_if_update_vni(struct interface *ifp, * Also, reinstall any remote MACs and neighbors * for this VNI (based on new VLAN). */ - if (chgflags & ZEBRA_VXLIF_MASTER_CHANGE) + if (CHECK_FLAG(chgflags, ZEBRA_VXLIF_MASTER_CHANGE)) zebra_evpn_read_mac_neigh(zevpn, ifp); - else if (chgflags & ZEBRA_VXLIF_VLAN_CHANGE) { + else if (CHECK_FLAG(chgflags, ZEBRA_VXLIF_VLAN_CHANGE)) { struct neigh_walk_ctx n_wctx; zebra_evpn_read_mac_neigh(zevpn, ifp); From 4395fcd8e120958a91d3a11f918e9071b1cb5619 Mon Sep 17 00:00:00 2001 From: Rajasekar Raja Date: Wed, 10 Jul 2024 16:46:29 -0700 Subject: [PATCH 180/347] bgpd: backpressure - fix to properly remove dest for bgp under deletion In case of imported routes (L3vni/vrf leaks), when a bgp instance is being deleted, the peer->bgp comparision with the incoming bgp to remove the dest from the pending fifo is wrong. This can lead to the fifo having stale entries resulting in crash. Two changes are done here. - Instead of pop/push items in list if the struct bgp doesnt match, simply iterate the list and remove the expected ones. - Corrected the way bgp is fetched from dest rather than relying on path_info->peer so that it works for all kinds of routes. Ticket :#3980988 Signed-off-by: Chirag Shah Signed-off-by: Rajasekar Raja --- bgpd/bgp_evpn.c | 12 ++++++------ bgpd/bgpd.c | 20 +++++++++++++------- 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index 75a7d85e88..baf1d4ca6d 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -6333,16 +6333,16 @@ struct bgpevpn *bgp_evpn_new(struct bgp *bgp, vni_t vni, void bgp_evpn_free(struct bgp *bgp, struct bgpevpn *vpn) { struct bgp_dest *dest = NULL; - uint32_t ann_count = zebra_announce_count(&bm->zebra_announce_head); + struct bgp_dest *dest_next = NULL; - while (ann_count) { - dest = zebra_announce_pop(&bm->zebra_announce_head); - ann_count--; + for (dest = zebra_announce_first(&bm->zebra_announce_head); dest; + dest = dest_next) { + dest_next = zebra_announce_next(&bm->zebra_announce_head, dest); if (dest->za_vpn == vpn) { bgp_path_info_unlock(dest->za_bgp_pi); bgp_dest_unlock_node(dest); - } else - zebra_announce_add_tail(&bm->zebra_announce_head, dest); + zebra_announce_del(&bm->zebra_announce_head, dest); + } } bgp_evpn_remote_ip_hash_destroy(vpn); diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 3810413adc..b6f7e29db2 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -3936,19 +3936,25 @@ int bgp_delete(struct bgp *bgp) safi_t safi; int i; struct bgp_dest *dest = NULL; + struct bgp_dest *dest_next = NULL; + struct bgp_table *dest_table = NULL; struct graceful_restart_info *gr_info; - uint32_t ann_count = zebra_announce_count(&bm->zebra_announce_head); assert(bgp); - while (ann_count) { - dest = zebra_announce_pop(&bm->zebra_announce_head); - ann_count--; - if (dest->za_bgp_pi->peer->bgp == bgp) { + /* + * Iterate the pending dest list and remove all the dest pertaininig to + * the bgp under delete. + */ + for (dest = zebra_announce_first(&bm->zebra_announce_head); dest; + dest = dest_next) { + dest_next = zebra_announce_next(&bm->zebra_announce_head, dest); + dest_table = bgp_dest_table(dest); + if (dest_table->bgp == bgp) { bgp_path_info_unlock(dest->za_bgp_pi); bgp_dest_unlock_node(dest); - } else - zebra_announce_add_tail(&bm->zebra_announce_head, dest); + zebra_announce_del(&bm->zebra_announce_head, dest); + } } bgp_soft_reconfig_table_task_cancel(bgp, NULL, NULL); From 186db96c06e4f44b4450fcba88f0fa680ee0b92d Mon Sep 17 00:00:00 2001 From: Rajasekar Raja Date: Wed, 10 Jul 2024 20:17:14 -0700 Subject: [PATCH 181/347] bgpd: backpressure - Improve debuggability Improve debuggability in backpressure code. Ticket :#3980988 Signed-off-by: Rajasekar Raja --- bgpd/bgpd.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index b6f7e29db2..476a01b8ef 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -3939,6 +3939,7 @@ int bgp_delete(struct bgp *bgp) struct bgp_dest *dest_next = NULL; struct bgp_table *dest_table = NULL; struct graceful_restart_info *gr_info; + uint32_t cnt_before, cnt_after; assert(bgp); @@ -3946,6 +3947,7 @@ int bgp_delete(struct bgp *bgp) * Iterate the pending dest list and remove all the dest pertaininig to * the bgp under delete. */ + cnt_before = zebra_announce_count(&bm->zebra_announce_head); for (dest = zebra_announce_first(&bm->zebra_announce_head); dest; dest = dest_next) { dest_next = zebra_announce_next(&bm->zebra_announce_head, dest); @@ -3957,6 +3959,11 @@ int bgp_delete(struct bgp *bgp) } } + cnt_after = zebra_announce_count(&bm->zebra_announce_head); + if (BGP_DEBUG(zebra, ZEBRA)) + zlog_debug("Zebra Announce Fifo cleanup count before %u and after %u during BGP %s deletion", + cnt_before, cnt_after, bgp->name_pretty); + bgp_soft_reconfig_table_task_cancel(bgp, NULL, NULL); /* make sure we withdraw any exported routes */ From d9e51c6399a655acd408224f044acd62765bcefe Mon Sep 17 00:00:00 2001 From: sri-mohan1 Date: Tue, 16 Jul 2024 15:23:52 +0530 Subject: [PATCH 182/347] bfdd: changes for code maintainability these changes are for improving the code maintainability and readability Signed-off-by: sri-mohan1 --- bfdd/bfd.c | 4 ++-- bfdd/bfd.h | 25 +++++++++++++------------ bfdd/bfd_packet.c | 4 ++-- 3 files changed, 17 insertions(+), 16 deletions(-) diff --git a/bfdd/bfd.c b/bfdd/bfd.c index 3096f47d5c..b6b437a791 100644 --- a/bfdd/bfd.c +++ b/bfdd/bfd.c @@ -410,8 +410,8 @@ static uint32_t ptm_bfd_gen_ID(void) * random session identification numbers. */ do { - session_id = ((frr_weak_random() << 16) & 0xFFFF0000) - | (frr_weak_random() & 0x0000FFFF); + session_id = CHECK_FLAG((frr_weak_random() << 16), 0xFFFF0000) | + CHECK_FLAG(frr_weak_random(), 0x0000FFFF); } while (session_id == 0 || bfd_id_lookup(session_id) != NULL); return session_id; diff --git a/bfdd/bfd.h b/bfdd/bfd.h index f4ff884e00..be04e655ab 100644 --- a/bfdd/bfd.h +++ b/bfdd/bfd.h @@ -97,8 +97,9 @@ struct bfd_echo_pkt { /* Macros for manipulating control packets */ #define BFD_VERMASK 0x07 #define BFD_DIAGMASK 0x1F -#define BFD_GETVER(diag) ((diag >> 5) & BFD_VERMASK) -#define BFD_SETVER(diag, val) ((diag) |= (val & BFD_VERMASK) << 5) +#define BFD_GETVER(diag) (CHECK_FLAG((diag >> 5), BFD_VERMASK)) +#define BFD_SETVER(diag, val) \ + SET_FLAG((diag), CHECK_FLAG(val, BFD_VERMASK) << 5) #define BFD_VERSION 1 #define BFD_PBIT 0x20 #define BFD_FBIT 0x10 @@ -106,36 +107,36 @@ struct bfd_echo_pkt { #define BFD_ABIT 0x04 #define BFD_DEMANDBIT 0x02 #define BFD_MBIT 0x01 -#define BFD_GETMBIT(flags) (flags & BFD_MBIT) +#define BFD_GETMBIT(flags) (CHECK_FLAG(flags, BFD_MBIT)) #define BFD_SETDEMANDBIT(flags, val) \ { \ if ((val)) \ - flags |= BFD_DEMANDBIT; \ + SET_FLAG(flags, BFD_DEMANDBIT); \ } #define BFD_SETPBIT(flags, val) \ { \ if ((val)) \ - flags |= BFD_PBIT; \ + SET_FLAG(flags, BFD_PBIT); \ } -#define BFD_GETPBIT(flags) (flags & BFD_PBIT) +#define BFD_GETPBIT(flags) (CHECK_FLAG(flags, BFD_PBIT)) #define BFD_SETFBIT(flags, val) \ { \ if ((val)) \ - flags |= BFD_FBIT; \ + SET_FLAG(flags, BFD_FBIT); \ } -#define BFD_GETFBIT(flags) (flags & BFD_FBIT) +#define BFD_GETFBIT(flags) (CHECK_FLAG(flags, BFD_FBIT)) #define BFD_SETSTATE(flags, val) \ { \ if ((val)) \ - flags |= (val & 0x3) << 6; \ + SET_FLAG(flags, (CHECK_FLAG(val, 0x3) << 6)); \ } -#define BFD_GETSTATE(flags) ((flags >> 6) & 0x3) +#define BFD_GETSTATE(flags) (CHECK_FLAG((flags >> 6), 0x3)) #define BFD_SETCBIT(flags, val) \ { \ if ((val)) \ - flags |= val; \ + SET_FLAG(flags, val); \ } -#define BFD_GETCBIT(flags) (flags & BFD_CBIT) +#define BFD_GETCBIT(flags) (CHECK_FLAG(flags, BFD_CBIT)) #define BFD_ECHO_VERSION 1 #define BFD_ECHO_PKT_LEN sizeof(struct bfd_echo_pkt) diff --git a/bfdd/bfd_packet.c b/bfdd/bfd_packet.c index 8110f434c2..f9397fa128 100644 --- a/bfdd/bfd_packet.c +++ b/bfdd/bfd_packet.c @@ -982,7 +982,7 @@ void bfd_recv_cb(struct event *t) } /* Save remote diagnostics before state switch. */ - bfd->remote_diag = cp->diag & BFD_DIAGMASK; + bfd->remote_diag = CHECK_FLAG(cp->diag, BFD_DIAGMASK); /* Update remote timers settings. */ bfd->remote_timers.desired_min_tx = ntohl(cp->timers.desired_min_tx); @@ -1738,7 +1738,7 @@ void bfd_peer_mac_set(int sd, struct bfd_session *bfd, if (CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_MAC_SET)) return; - if (ifp->flags & IFF_NOARP) + if (CHECK_FLAG(ifp->flags, IFF_NOARP)) return; if (peer->sa_sin.sin_family == AF_INET) { From 895e97c8da89f182781583f1de3816d604e91059 Mon Sep 17 00:00:00 2001 From: Louis Scalbert Date: Tue, 16 Jul 2024 13:35:14 +0200 Subject: [PATCH 183/347] build: display local state dir configuration Configure is displaying the run state directory but not the local state directory. > FRRouting configuration > ------------------------------ > state file directory : /usr/var/run/frr > config file directory : /etc/frr Display the local state directory as well. > local state file dir : /usr/var/lib/frr > run state file dir : /usr/var/run/frr > config file directory : /etc/frr Signed-off-by: Louis Scalbert --- configure.ac | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index ec409aaf1d..59636194f7 100644 --- a/configure.ac +++ b/configure.ac @@ -2913,7 +2913,8 @@ compiler : ${CC} compiler flags : ${CFLAGS} ${WERROR} ${AC_CFLAGS} ${SAN_FLAGS} make : ${MAKE-make} linker flags : ${LDFLAGS} ${SAN_FLAGS} ${LIBS} ${LIBCAP} ${LIBREADLINE} ${LIBM} -state file directory : ${e_frr_runstatedir} +local state file dir : ${e_frr_libstatedir} +run state file dir : ${e_frr_runstatedir} config file directory : ${e_frr_sysconfdir} module directory : ${e_moduledir} script directory : ${e_scriptdir} From fd8edc3dfbd41ff1ba8c21ea258276f3dab71e4b Mon Sep 17 00:00:00 2001 From: Nathan Bahr Date: Wed, 12 Jun 2024 16:26:48 +0000 Subject: [PATCH 184/347] pimd, lib, vtysh: Added new 'router pim[6] [vrf NAME]' config node Moved all existing global/vrf PIM config to the new subnode. Existing configuration updated to be hidden and deprecated. Both versions of configuration still work together. Signed-off-by: Nathan Bahr --- lib/command.h | 2 + pimd/pim6_cmd.c | 1127 ++++++++++++++-- pimd/pim_addr.h | 2 + pimd/pim_cmd.c | 2845 +++++++++++++++++++++++++++++++++-------- pimd/pim_cmd_common.c | 188 +-- pimd/pim_cmd_common.h | 2 + pimd/pim_instance.c | 21 +- pimd/pim_msdp.c | 18 +- pimd/pim_msdp.h | 11 +- pimd/pim_nb.h | 4 - pimd/pim_rp.c | 13 +- pimd/pim_rp.h | 3 +- pimd/pim_vty.c | 68 +- vtysh/vtysh.c | 89 ++ vtysh/vtysh_config.c | 5 + 15 files changed, 3523 insertions(+), 875 deletions(-) diff --git a/lib/command.h b/lib/command.h index 6f819c7e36..57e3b9cda0 100644 --- a/lib/command.h +++ b/lib/command.h @@ -182,6 +182,8 @@ enum node_type { ISIS_SRV6_NODE_MSD_NODE, /* ISIS SRv6 Node MSDs node */ MGMTD_NODE, /* MGMTD node. */ RPKI_VRF_NODE, /* RPKI node for VRF */ + PIM_NODE, /* PIM protocol mode */ + PIM6_NODE, /* PIM protocol for IPv6 mode */ NODE_TYPE_MAX, /* maximum */ }; /* clang-format on */ diff --git a/pimd/pim6_cmd.c b/pimd/pim6_cmd.c index ec912700d1..99f1474712 100644 --- a/pimd/pim6_cmd.c +++ b/pimd/pim6_cmd.c @@ -41,45 +41,207 @@ static struct cmd_node debug_node = { .config_write = pim_debug_config_write, }; -DEFPY (ipv6_pim_joinprune_time, - ipv6_pim_joinprune_time_cmd, - "ipv6 pim join-prune-interval (1-65535)$jpi", - IPV6_STR - PIM_STR +DEFPY_NOSH (router_pim6, + router_pim6_cmd, + "router pim6 [vrf NAME]", + "Enable a routing process\n" + "Start PIM6 configuration\n" + VRF_CMD_HELP_STR) +{ + char xpath[XPATH_MAXLEN]; + const char *vrf_name; + + if (vrf) + vrf_name = vrf; + else + vrf_name = VRF_DEFAULT_NAME; + + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", + vrf_name, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) != CMD_SUCCESS) + return CMD_WARNING_CONFIG_FAILED; + + VTY_PUSH_XPATH(PIM6_NODE, xpath); + + return CMD_SUCCESS; +} + +DEFPY (no_router_pim6, + no_router_pim6_cmd, + "no router pim6 [vrf NAME]", + NO_STR + "Enable a routing process\n" + "Start PIM6 configuration\n" + VRF_CMD_HELP_STR) +{ + char xpath[XPATH_MAXLEN]; + const char *vrf_name; + + if (vrf) + vrf_name = vrf; + else + vrf_name = VRF_DEFAULT_NAME; + + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", + vrf_name, FRR_PIM_AF_XPATH_VAL); + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY (pim6_joinprune_time, + pim6_joinprune_time_cmd, + "join-prune-interval (1-65535)$jpi", "Join Prune Send Interval\n" "Seconds\n") { return pim_process_join_prune_cmd(vty, jpi_str); } +DEFPY_ATTR(ipv6_joinprune_time, + ipv6_pim_joinprune_time_cmd, + "ipv6 pim join-prune-interval (1-65535)$jpi", + IPV6_STR PIM_STR + "Join Prune Send Interval\n" + "Seconds\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM6_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_join_prune_cmd(vty, jpi_str); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} -DEFPY (no_ipv6_pim_joinprune_time, - no_ipv6_pim_joinprune_time_cmd, - "no ipv6 pim join-prune-interval [(1-65535)]", +DEFPY (no_pim6_joinprune_time, + no_pim6_joinprune_time_cmd, + "no join-prune-interval [(1-65535)]", NO_STR - IPV6_STR - PIM_STR "Join Prune Send Interval\n" IGNORED_IN_NO_STR) { return pim_process_no_join_prune_cmd(vty); } +DEFPY_ATTR(no_ipv6_pim_joinprune_time, + no_ipv6_pim_joinprune_time_cmd, + "no ipv6 pim join-prune-interval [(1-65535)]", + NO_STR + IPV6_STR + PIM_STR + "Join Prune Send Interval\n" + IGNORED_IN_NO_STR, + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM6_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_no_join_prune_cmd(vty); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} -DEFPY (ipv6_pim_spt_switchover_infinity, - ipv6_pim_spt_switchover_infinity_cmd, - "ipv6 pim spt-switchover infinity-and-beyond", - IPV6_STR - PIM_STR +DEFPY (pim6_spt_switchover_infinity, + pim6_spt_switchover_infinity_cmd, + "spt-switchover infinity-and-beyond", "SPT-Switchover\n" "Never switch to SPT Tree\n") { return pim_process_spt_switchover_infinity_cmd(vty); } +DEFPY_ATTR(ipv6_spt_switchover_infinity, + ipv6_pim_spt_switchover_infinity_cmd, + "ipv6 pim spt-switchover infinity-and-beyond", + IPV6_STR + PIM_STR + "SPT-Switchover\n" + "Never switch to SPT Tree\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM6_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_spt_switchover_infinity_cmd(vty); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} -DEFPY (ipv6_pim_spt_switchover_infinity_plist, - ipv6_pim_spt_switchover_infinity_plist_cmd, - "ipv6 pim spt-switchover infinity-and-beyond prefix-list PREFIXLIST6_NAME$plist", - IPV6_STR - PIM_STR +DEFPY (pim6_spt_switchover_infinity_plist, + pim6_spt_switchover_infinity_plist_cmd, + "spt-switchover infinity-and-beyond prefix-list PREFIXLIST6_NAME$plist", "SPT-Switchover\n" "Never switch to SPT Tree\n" "Prefix-List to control which groups to switch\n" @@ -87,25 +249,104 @@ DEFPY (ipv6_pim_spt_switchover_infinity_plist, { return pim_process_spt_switchover_prefixlist_cmd(vty, plist); } +DEFPY_ATTR(ipv6_spt_switchover_infinity_plist, + ipv6_pim_spt_switchover_infinity_plist_cmd, + "ipv6 pim spt-switchover infinity-and-beyond prefix-list PREFIXLIST6_NAME$plist", + IPV6_STR + PIM_STR + "SPT-Switchover\n" + "Never switch to SPT Tree\n" + "Prefix-List to control which groups to switch\n" + "Prefix-List name\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM6_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_spt_switchover_prefixlist_cmd(vty, plist); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} -DEFPY (no_ipv6_pim_spt_switchover_infinity, - no_ipv6_pim_spt_switchover_infinity_cmd, - "no ipv6 pim spt-switchover infinity-and-beyond", +DEFPY (no_pim6_spt_switchover_infinity, + no_pim6_spt_switchover_infinity_cmd, + "no spt-switchover infinity-and-beyond", NO_STR - IPV6_STR - PIM_STR "SPT_Switchover\n" "Never switch to SPT Tree\n") { return pim_process_no_spt_switchover_cmd(vty); } +DEFPY_ATTR(no_ipv6_pim_spt_switchover_infinity, + no_ipv6_pim_spt_switchover_infinity_cmd, + "no ipv6 pim spt-switchover infinity-and-beyond", + NO_STR + IPV6_STR + PIM_STR + "SPT_Switchover\n" + "Never switch to SPT Tree\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM6_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_no_spt_switchover_cmd(vty); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} -DEFPY (no_ipv6_pim_spt_switchover_infinity_plist, - no_ipv6_pim_spt_switchover_infinity_plist_cmd, - "no ipv6 pim spt-switchover infinity-and-beyond prefix-list PREFIXLIST6_NAME", +DEFPY (no_pim6_spt_switchover_infinity_plist, + no_pim6_spt_switchover_infinity_plist_cmd, + "no spt-switchover infinity-and-beyond prefix-list PREFIXLIST6_NAME", NO_STR - IPV6_STR - PIM_STR "SPT_Switchover\n" "Never switch to SPT Tree\n" "Prefix-List to control which groups to switch\n" @@ -113,100 +354,453 @@ DEFPY (no_ipv6_pim_spt_switchover_infinity_plist, { return pim_process_no_spt_switchover_cmd(vty); } +DEFPY_ATTR(no_ipv6_pim_spt_switchover_infinity_plist, + no_ipv6_pim_spt_switchover_infinity_plist_cmd, + "no ipv6 pim spt-switchover infinity-and-beyond prefix-list PREFIXLIST6_NAME", + NO_STR + IPV6_STR + PIM_STR + "SPT_Switchover\n" + "Never switch to SPT Tree\n" + "Prefix-List to control which groups to switch\n" + "Prefix-List name\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM6_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_no_spt_switchover_cmd(vty); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} -DEFPY (ipv6_pim_packets, - ipv6_pim_packets_cmd, - "ipv6 pim packets (1-255)", - IPV6_STR - PIM_STR +DEFPY (pim6_packets, + pim6_packets_cmd, + "packets (1-255)", "packets to process at one time per fd\n" "Number of packets\n") { return pim_process_pim_packet_cmd(vty, packets_str); } +DEFPY_ATTR(ipv6_pim_packets, + ipv6_pim_packets_cmd, + "ipv6 pim packets (1-255)", + IPV6_STR + PIM_STR + "packets to process at one time per fd\n" + "Number of packets\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM6_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_pim_packet_cmd(vty, packets_str); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} -DEFPY (no_ipv6_pim_packets, - no_ipv6_pim_packets_cmd, - "no ipv6 pim packets [(1-255)]", +DEFPY (no_pim6_packets, + no_pim6_packets_cmd, + "no packets [(1-255)]", NO_STR - IPV6_STR - PIM_STR "packets to process at one time per fd\n" IGNORED_IN_NO_STR) { return pim_process_no_pim_packet_cmd(vty); } +DEFPY_ATTR(no_ipv6_pim_packets, + no_ipv6_pim_packets_cmd, + "no ipv6 pim packets [(1-255)]", + NO_STR + IPV6_STR + PIM_STR + "packets to process at one time per fd\n" + IGNORED_IN_NO_STR, + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM6_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } -DEFPY (ipv6_pim_keep_alive, - ipv6_pim_keep_alive_cmd, - "ipv6 pim keep-alive-timer (1-65535)$kat", - IPV6_STR - PIM_STR + ret = pim_process_no_pim_packet_cmd(vty); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} + +DEFPY (pim6_keep_alive, + pim6_keep_alive_cmd, + "keep-alive-timer (1-65535)$kat", "Keep alive Timer\n" "Seconds\n") { return pim_process_keepalivetimer_cmd(vty, kat_str); } +DEFPY_ATTR(ipv6_pim_keep_alive, + ipv6_pim_keep_alive_cmd, + "ipv6 pim keep-alive-timer (1-65535)$kat", + IPV6_STR + PIM_STR + "Keep alive Timer\n" + "Seconds\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM6_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_keepalivetimer_cmd(vty, kat_str); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} -DEFPY (no_ipv6_pim_keep_alive, - no_ipv6_pim_keep_alive_cmd, - "no ipv6 pim keep-alive-timer [(1-65535)]", +DEFPY (no_pim6_keep_alive, + no_pim6_keep_alive_cmd, + "no keep-alive-timer [(1-65535)]", NO_STR - IPV6_STR - PIM_STR "Keep alive Timer\n" IGNORED_IN_NO_STR) { return pim_process_no_keepalivetimer_cmd(vty); } +DEFPY_ATTR(no_ipv6_pim_keep_alive, + no_ipv6_pim_keep_alive_cmd, + "no ipv6 pim keep-alive-timer [(1-65535)]", + NO_STR + IPV6_STR + PIM_STR + "Keep alive Timer\n" + IGNORED_IN_NO_STR, + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM6_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_no_keepalivetimer_cmd(vty); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} -DEFPY (ipv6_pim_rp_keep_alive, - ipv6_pim_rp_keep_alive_cmd, - "ipv6 pim rp keep-alive-timer (1-65535)$kat", - IPV6_STR - PIM_STR +DEFPY (pim6_rp_keep_alive, + pim6_rp_keep_alive_cmd, + "rp keep-alive-timer (1-65535)$kat", "Rendezvous Point\n" "Keep alive Timer\n" "Seconds\n") { return pim_process_rp_kat_cmd(vty, kat_str); } +DEFPY_ATTR(ipv6_pim_rp_keep_alive, + ipv6_pim_rp_keep_alive_cmd, + "ipv6 pim rp keep-alive-timer (1-65535)$kat", + IPV6_STR + PIM_STR + "Rendezvous Point\n" + "Keep alive Timer\n" + "Seconds\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM6_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_rp_kat_cmd(vty, kat_str); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} -DEFPY (no_ipv6_pim_rp_keep_alive, - no_ipv6_pim_rp_keep_alive_cmd, - "no ipv6 pim rp keep-alive-timer [(1-65535)]", +DEFPY (no_pim6_rp_keep_alive, + no_pim6_rp_keep_alive_cmd, + "no rp keep-alive-timer [(1-65535)]", NO_STR - IPV6_STR - PIM_STR "Rendezvous Point\n" "Keep alive Timer\n" IGNORED_IN_NO_STR) { return pim_process_no_rp_kat_cmd(vty); } +DEFPY_ATTR(no_ipv6_pim_rp_keep_alive, + no_ipv6_pim_rp_keep_alive_cmd, + "no ipv6 pim rp keep-alive-timer [(1-65535)]", + NO_STR + IPV6_STR + PIM_STR + "Rendezvous Point\n" + "Keep alive Timer\n" + IGNORED_IN_NO_STR, + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM6_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } -DEFPY (ipv6_pim_register_suppress, - ipv6_pim_register_suppress_cmd, - "ipv6 pim register-suppress-time (1-65535)$rst", - IPV6_STR - PIM_STR + ret = pim_process_no_rp_kat_cmd(vty); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} + +DEFPY (pim6_register_suppress, + pim6_register_suppress_cmd, + "register-suppress-time (1-65535)$rst", "Register Suppress Timer\n" "Seconds\n") { return pim_process_register_suppress_cmd(vty, rst_str); } +DEFPY_ATTR(ipv6_pim_register_suppress, + ipv6_pim_register_suppress_cmd, + "ipv6 pim register-suppress-time (1-65535)$rst", + IPV6_STR + PIM_STR + "Register Suppress Timer\n" + "Seconds\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM6_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_register_suppress_cmd(vty, rst_str); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} -DEFPY (no_ipv6_pim_register_suppress, - no_ipv6_pim_register_suppress_cmd, - "no ipv6 pim register-suppress-time [(1-65535)]", +DEFPY (no_pim6_register_suppress, + no_pim6_register_suppress_cmd, + "no register-suppress-time [(1-65535)]", NO_STR - IPV6_STR - PIM_STR "Register Suppress Timer\n" IGNORED_IN_NO_STR) { return pim_process_no_register_suppress_cmd(vty); } +DEFPY_ATTR(no_ipv6_pim_register_suppress, + no_ipv6_pim_register_suppress_cmd, + "no ipv6 pim register-suppress-time [(1-65535)]", + NO_STR + IPV6_STR + PIM_STR + "Register Suppress Timer\n" + IGNORED_IN_NO_STR, + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM6_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_no_register_suppress_cmd(vty); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} DEFPY (interface_ipv6_pim, interface_ipv6_pim_cmd, @@ -405,11 +999,9 @@ DEFPY (interface_no_ipv6_mroute, source_str); } -DEFPY (ipv6_pim_rp, - ipv6_pim_rp_cmd, - "ipv6 pim rp X:X::X:X$rp [X:X::X:X/M]$gp", - IPV6_STR - PIM_STR +DEFPY (pim6_rp, + pim6_rp_cmd, + "rp X:X::X:X$rp [X:X::X:X/M]$gp", "Rendezvous Point\n" "ipv6 address of RP\n" "Group Address range to cover\n") @@ -418,13 +1010,53 @@ DEFPY (ipv6_pim_rp, return pim_process_rp_cmd(vty, rp_str, group_str); } +DEFPY_ATTR(ipv6_pim_rp, + ipv6_pim_rp_cmd, + "ipv6 pim rp X:X::X:X$rp [X:X::X:X/M]$gp", + IPV6_STR + PIM_STR + "Rendezvous Point\n" + "ipv6 address of RP\n" + "Group Address range to cover\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *group_str = (gp_str) ? gp_str : "FF00::0/8"; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM6_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_rp_cmd(vty, rp_str, group_str); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} -DEFPY (no_ipv6_pim_rp, - no_ipv6_pim_rp_cmd, - "no ipv6 pim rp X:X::X:X$rp [X:X::X:X/M]$gp", +DEFPY (no_pim6_rp, + no_pim6_rp_cmd, + "no rp X:X::X:X$rp [X:X::X:X/M]$gp", NO_STR - IPV6_STR - PIM_STR "Rendezvous Point\n" "ipv6 address of RP\n" "Group Address range to cover\n") @@ -433,12 +1065,53 @@ DEFPY (no_ipv6_pim_rp, return pim_process_no_rp_cmd(vty, rp_str, group_str); } +DEFPY_ATTR(no_ipv6_pim_rp, + no_ipv6_pim_rp_cmd, + "no ipv6 pim rp X:X::X:X$rp [X:X::X:X/M]$gp", + NO_STR + IPV6_STR + PIM_STR + "Rendezvous Point\n" + "ipv6 address of RP\n" + "Group Address range to cover\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *group_str = (gp_str) ? gp_str : "FF00::0/8"; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM6_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } -DEFPY (ipv6_pim_rp_prefix_list, - ipv6_pim_rp_prefix_list_cmd, - "ipv6 pim rp X:X::X:X$rp prefix-list PREFIXLIST6_NAME$plist", - IPV6_STR - PIM_STR + ret = pim_process_no_rp_cmd(vty, rp_str, group_str); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} + +DEFPY (pim6_rp_prefix_list, + pim6_rp_prefix_list_cmd, + "rp X:X::X:X$rp prefix-list PREFIXLIST6_NAME$plist", "Rendezvous Point\n" "ipv6 address of RP\n" "group prefix-list filter\n" @@ -446,13 +1119,53 @@ DEFPY (ipv6_pim_rp_prefix_list, { return pim_process_rp_plist_cmd(vty, rp_str, plist); } +DEFPY_ATTR(ipv6_pim_rp_prefix_list, + ipv6_pim_rp_prefix_list_cmd, + "ipv6 pim rp X:X::X:X$rp prefix-list PREFIXLIST6_NAME$plist", + IPV6_STR + PIM_STR + "Rendezvous Point\n" + "ipv6 address of RP\n" + "group prefix-list filter\n" + "Name of a prefix-list\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM6_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_rp_plist_cmd(vty, rp_str, plist); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} -DEFPY (no_ipv6_pim_rp_prefix_list, - no_ipv6_pim_rp_prefix_list_cmd, - "no ipv6 pim rp X:X::X:X$rp prefix-list PREFIXLIST6_NAME$plist", +DEFPY (no_pim6_rp_prefix_list, + no_pim6_rp_prefix_list_cmd, + "no rp X:X::X:X$rp prefix-list PREFIXLIST6_NAME$plist", NO_STR - IPV6_STR - PIM_STR "Rendezvous Point\n" "ipv6 address of RP\n" "group prefix-list filter\n" @@ -460,6 +1173,49 @@ DEFPY (no_ipv6_pim_rp_prefix_list, { return pim_process_no_rp_plist_cmd(vty, rp_str, plist); } +DEFPY_ATTR(no_ipv6_pim_rp_prefix_list, + no_ipv6_pim_rp_prefix_list_cmd, + "no ipv6 pim rp X:X::X:X$rp prefix-list PREFIXLIST6_NAME$plist", + NO_STR + IPV6_STR + PIM_STR + "Rendezvous Point\n" + "ipv6 address of RP\n" + "group prefix-list filter\n" + "Name of a prefix-list\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM6_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_no_rp_plist_cmd(vty, rp_str, plist); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} DEFPY (ipv6_pim_bsm, ipv6_pim_bsm_cmd, @@ -503,10 +1259,9 @@ DEFPY (no_ipv6_pim_ucast_bsm, return pim_process_no_unicast_bsm_cmd(vty); } -DEFPY (ipv6_ssmpingd, - ipv6_ssmpingd_cmd, - "ipv6 ssmpingd [X:X::X:X]$source", - IPV6_STR +DEFPY (pim6_ssmpingd, + pim6_ssmpingd_cmd, + "ssmpingd [X:X::X:X]$source", CONF_SSMPINGD_STR "Source address\n") { @@ -514,20 +1269,99 @@ DEFPY (ipv6_ssmpingd, return pim_process_ssmpingd_cmd(vty, NB_OP_CREATE, src_str); } +DEFPY_ATTR(ipv6_ssmpingd, + ipv6_ssmpingd_cmd, + "ipv6 ssmpingd [X:X::X:X]$source", + IPV6_STR + CONF_SSMPINGD_STR + "Source address\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *src_str = (source_str) ? source_str : "::"; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM6_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + ret = pim_process_ssmpingd_cmd(vty, NB_OP_CREATE, src_str); -DEFPY (no_ipv6_ssmpingd, - no_ipv6_ssmpingd_cmd, - "no ipv6 ssmpingd [X:X::X:X]$source", - NO_STR - IPV6_STR - CONF_SSMPINGD_STR - "Source address\n") + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} + +DEFPY (no_pim6_ssmpingd, + no_pim6_ssmpingd_cmd, + "no ssmpingd [X:X::X:X]$source", + NO_STR + CONF_SSMPINGD_STR + "Source address\n") { const char *src_str = (source_str) ? source_str : "::"; return pim_process_ssmpingd_cmd(vty, NB_OP_DESTROY, src_str); } +DEFPY_ATTR(no_ipv6_ssmpingd, + no_ipv6_ssmpingd_cmd, + "no ipv6 ssmpingd [X:X::X:X]$source", + NO_STR + IPV6_STR + CONF_SSMPINGD_STR + "Source address\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *src_str = (source_str) ? source_str : "::"; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM6_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_ssmpingd_cmd(vty, NB_OP_DESTROY, src_str); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} DEFPY (interface_ipv6_mld_join, interface_ipv6_mld_join_cmd, @@ -1733,12 +2567,16 @@ DEFPY (debug_pimv6_bsm, return CMD_SUCCESS; } -void pim_cmd_init(void) -{ - if_cmd_init(pim_interface_config_write); - - install_node(&debug_node); +struct cmd_node pim6_node = { + .name = "pim6", + .node = PIM6_NODE, + .parent_node = CONFIG_NODE, + .prompt = "%s(config-pim6)# ", + .config_write = pim_router_config_write, +}; +static void pim_install_deprecated(void) +{ install_element(CONFIG_NODE, &ipv6_pim_joinprune_time_cmd); install_element(CONFIG_NODE, &no_ipv6_pim_joinprune_time_cmd); install_element(CONFIG_NODE, &ipv6_pim_spt_switchover_infinity_cmd); @@ -1753,6 +2591,60 @@ void pim_cmd_init(void) install_element(CONFIG_NODE, &no_ipv6_pim_rp_keep_alive_cmd); install_element(CONFIG_NODE, &ipv6_pim_register_suppress_cmd); install_element(CONFIG_NODE, &no_ipv6_pim_register_suppress_cmd); + install_element(CONFIG_NODE, &ipv6_pim_rp_cmd); + install_element(VRF_NODE, &ipv6_pim_rp_cmd); + install_element(CONFIG_NODE, &no_ipv6_pim_rp_cmd); + install_element(VRF_NODE, &no_ipv6_pim_rp_cmd); + install_element(CONFIG_NODE, &ipv6_pim_rp_prefix_list_cmd); + install_element(VRF_NODE, &ipv6_pim_rp_prefix_list_cmd); + install_element(CONFIG_NODE, &no_ipv6_pim_rp_prefix_list_cmd); + install_element(VRF_NODE, &no_ipv6_pim_rp_prefix_list_cmd); + install_element(CONFIG_NODE, &ipv6_ssmpingd_cmd); + install_element(VRF_NODE, &ipv6_ssmpingd_cmd); + install_element(CONFIG_NODE, &no_ipv6_ssmpingd_cmd); + install_element(VRF_NODE, &no_ipv6_ssmpingd_cmd); +} + +void pim_cmd_init(void) +{ + if_cmd_init(pim_interface_config_write); + + install_node(&debug_node); + + pim_install_deprecated(); + + install_element(CONFIG_NODE, &router_pim6_cmd); + install_element(CONFIG_NODE, &no_router_pim6_cmd); + + install_node(&pim6_node); + install_default(PIM6_NODE); + + install_element(PIM6_NODE, &pim6_joinprune_time_cmd); + install_element(PIM6_NODE, &no_pim6_joinprune_time_cmd); + install_element(PIM6_NODE, &pim6_spt_switchover_infinity_cmd); + install_element(PIM6_NODE, &pim6_spt_switchover_infinity_plist_cmd); + install_element(PIM6_NODE, &no_pim6_spt_switchover_infinity_cmd); + install_element(PIM6_NODE, &no_pim6_spt_switchover_infinity_plist_cmd); + install_element(PIM6_NODE, &pim6_packets_cmd); + install_element(PIM6_NODE, &no_pim6_packets_cmd); + install_element(PIM6_NODE, &pim6_keep_alive_cmd); + install_element(PIM6_NODE, &no_pim6_keep_alive_cmd); + install_element(PIM6_NODE, &pim6_rp_keep_alive_cmd); + install_element(PIM6_NODE, &no_pim6_rp_keep_alive_cmd); + install_element(PIM6_NODE, &pim6_register_suppress_cmd); + install_element(PIM6_NODE, &no_pim6_register_suppress_cmd); + install_element(PIM6_NODE, &pim6_rp_cmd); + install_element(PIM6_NODE, &no_pim6_rp_cmd); + install_element(PIM6_NODE, &pim6_rp_prefix_list_cmd); + install_element(PIM6_NODE, &no_pim6_rp_prefix_list_cmd); + install_element(PIM6_NODE, &pim6_ssmpingd_cmd); + install_element(PIM6_NODE, &no_pim6_ssmpingd_cmd); + + install_element(CONFIG_NODE, &ipv6_mld_group_watermark_cmd); + install_element(VRF_NODE, &ipv6_mld_group_watermark_cmd); + install_element(CONFIG_NODE, &no_ipv6_mld_group_watermark_cmd); + install_element(VRF_NODE, &no_ipv6_mld_group_watermark_cmd); + install_element(INTERFACE_NODE, &interface_ipv6_pim_cmd); install_element(INTERFACE_NODE, &interface_no_ipv6_pim_cmd); install_element(INTERFACE_NODE, &interface_ipv6_pim_drprio_cmd); @@ -1764,10 +2656,8 @@ void pim_cmd_init(void) install_element(INTERFACE_NODE, &interface_no_ipv6_pim_ssm_cmd); install_element(INTERFACE_NODE, &interface_ipv6_pim_sm_cmd); install_element(INTERFACE_NODE, &interface_no_ipv6_pim_sm_cmd); - install_element(INTERFACE_NODE, - &interface_ipv6_pim_boundary_oil_cmd); - install_element(INTERFACE_NODE, - &interface_no_ipv6_pim_boundary_oil_cmd); + install_element(INTERFACE_NODE, &interface_ipv6_pim_boundary_oil_cmd); + install_element(INTERFACE_NODE, &interface_no_ipv6_pim_boundary_oil_cmd); install_element(INTERFACE_NODE, &interface_ipv6_mroute_cmd); install_element(INTERFACE_NODE, &interface_no_ipv6_mroute_cmd); /* Install BSM command */ @@ -1775,18 +2665,7 @@ void pim_cmd_init(void) install_element(INTERFACE_NODE, &no_ipv6_pim_bsm_cmd); install_element(INTERFACE_NODE, &ipv6_pim_ucast_bsm_cmd); install_element(INTERFACE_NODE, &no_ipv6_pim_ucast_bsm_cmd); - install_element(CONFIG_NODE, &ipv6_pim_rp_cmd); - install_element(VRF_NODE, &ipv6_pim_rp_cmd); - install_element(CONFIG_NODE, &no_ipv6_pim_rp_cmd); - install_element(VRF_NODE, &no_ipv6_pim_rp_cmd); - install_element(CONFIG_NODE, &ipv6_pim_rp_prefix_list_cmd); - install_element(VRF_NODE, &ipv6_pim_rp_prefix_list_cmd); - install_element(CONFIG_NODE, &no_ipv6_pim_rp_prefix_list_cmd); - install_element(VRF_NODE, &no_ipv6_pim_rp_prefix_list_cmd); - install_element(CONFIG_NODE, &ipv6_ssmpingd_cmd); - install_element(VRF_NODE, &ipv6_ssmpingd_cmd); - install_element(CONFIG_NODE, &no_ipv6_ssmpingd_cmd); - install_element(VRF_NODE, &no_ipv6_ssmpingd_cmd); + install_element(INTERFACE_NODE, &interface_ipv6_mld_cmd); install_element(INTERFACE_NODE, &interface_no_ipv6_mld_cmd); install_element(INTERFACE_NODE, &interface_ipv6_mld_join_cmd); @@ -1796,10 +2675,6 @@ void pim_cmd_init(void) install_element(INTERFACE_NODE, &interface_ipv6_mld_query_interval_cmd); install_element(INTERFACE_NODE, &interface_no_ipv6_mld_query_interval_cmd); - install_element(CONFIG_NODE, &ipv6_mld_group_watermark_cmd); - install_element(VRF_NODE, &ipv6_mld_group_watermark_cmd); - install_element(CONFIG_NODE, &no_ipv6_mld_group_watermark_cmd); - install_element(VRF_NODE, &no_ipv6_mld_group_watermark_cmd); install_element(INTERFACE_NODE, &interface_ipv6_mld_query_max_response_time_cmd); install_element(INTERFACE_NODE, diff --git a/pimd/pim_addr.h b/pimd/pim_addr.h index 7b0c3f0350..c1416e1dd0 100644 --- a/pimd/pim_addr.h +++ b/pimd/pim_addr.h @@ -26,6 +26,7 @@ typedef struct prefix_ipv4 prefix_pim; #define PIM_MAX_BITLEN IPV4_MAX_BITLEN #define PIM_AF_NAME "ip" #define PIM_AF_DBG "pim" +#define PIM_AF_ROUTER "pim" #define GM_AF_DBG "igmp" #define PIM_MROUTE_DBG "mroute" #define PIMREG "pimreg" @@ -58,6 +59,7 @@ typedef struct prefix_ipv6 prefix_pim; #define PIM_MAX_BITLEN IPV6_MAX_BITLEN #define PIM_AF_NAME "ipv6" #define PIM_AF_DBG "pimv6" +#define PIM_AF_ROUTER "pim6" #define GM_AF_DBG "mld" #define PIM_MROUTE_DBG "mroute6" #define PIMREG "pim6reg" diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index a2d756a96a..2b8d3e56e5 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -1457,19 +1457,13 @@ static void clear_interfaces(struct pim_instance *pim) static void pim_cli_legacy_mesh_group_behavior(struct vty *vty, const char *gname) { - const char *vrfname; char xpath_value[XPATH_MAXLEN]; char xpath_member_value[XPATH_MAXLEN]; const struct lyd_node *member_dnode; - vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) - return; - /* Get mesh group base XPath. */ snprintf(xpath_value, sizeof(xpath_value), - FRR_PIM_VRF_XPATH "/msdp-mesh-groups[name='%s']", - "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4", gname); + "%s/msdp-mesh-groups[name='%s']", VTY_CURR_XPATH, gname); /* Group must exists, otherwise just quit. */ if (!yang_dnode_exists(vty->candidate_config->dnode, xpath_value)) return; @@ -1477,8 +1471,7 @@ static void pim_cli_legacy_mesh_group_behavior(struct vty *vty, /* Group members check: */ strlcpy(xpath_member_value, xpath_value, sizeof(xpath_member_value)); strlcat(xpath_member_value, "/members", sizeof(xpath_member_value)); - if (yang_dnode_exists(vty->candidate_config->dnode, - xpath_member_value)) { + if (yang_dnode_exists(vty->candidate_config->dnode, xpath_member_value)) { member_dnode = yang_dnode_get(vty->candidate_config->dnode, xpath_member_value); if (!member_dnode || !yang_is_last_list_dnode(member_dnode)) @@ -2989,22 +2982,108 @@ DEFUN (show_ip_ssmpingd, return CMD_SUCCESS; } -DEFUN (ip_pim_spt_switchover_infinity, - ip_pim_spt_switchover_infinity_cmd, - "ip pim spt-switchover infinity-and-beyond", - IP_STR - PIM_STR +DEFPY_NOSH (router_pim, + router_pim_cmd, + "router pim [vrf NAME]", + "Enable a routing process\n" + "Start PIM configuration\n" + VRF_CMD_HELP_STR) +{ + char xpath[XPATH_MAXLEN]; + const char *vrf_name; + + if (vrf) + vrf_name = vrf; + else + vrf_name = VRF_DEFAULT_NAME; + + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", + vrf_name, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) != CMD_SUCCESS) + return CMD_WARNING_CONFIG_FAILED; + + VTY_PUSH_XPATH(PIM_NODE, xpath); + return CMD_SUCCESS; +} + +DEFPY (no_router_pim, + no_router_pim_cmd, + "no router pim [vrf NAME]", + NO_STR + "Enable a routing process\n" + "Start PIM configuration\n" + VRF_CMD_HELP_STR) +{ + char xpath[XPATH_MAXLEN]; + const char *vrf_name; + + if (vrf) + vrf_name = vrf; + else + vrf_name = VRF_DEFAULT_NAME; + + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", + vrf_name, FRR_PIM_AF_XPATH_VAL); + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); +} + + +DEFPY (pim_spt_switchover_infinity, + pim_spt_switchover_infinity_cmd, + "spt-switchover infinity-and-beyond", "SPT-Switchover\n" "Never switch to SPT Tree\n") { return pim_process_spt_switchover_infinity_cmd(vty); } +DEFPY_ATTR(ip_pim_spt_switchover_infinity, + ip_pim_spt_switchover_infinity_cmd, + "ip pim spt-switchover infinity-and-beyond", + IP_STR + PIM_STR + "SPT-Switchover\n" + "Never switch to SPT Tree\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_spt_switchover_infinity_cmd(vty); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} -DEFPY (ip_pim_spt_switchover_infinity_plist, - ip_pim_spt_switchover_infinity_plist_cmd, - "ip pim spt-switchover infinity-and-beyond prefix-list PREFIXLIST4_NAME$plist", - IP_STR - PIM_STR +DEFPY (pim_spt_switchover_infinity_plist, + pim_spt_switchover_infinity_plist_cmd, + "spt-switchover infinity-and-beyond prefix-list PREFIXLIST4_NAME$plist", "SPT-Switchover\n" "Never switch to SPT Tree\n" "Prefix-List to control which groups to switch\n" @@ -3012,25 +3091,104 @@ DEFPY (ip_pim_spt_switchover_infinity_plist, { return pim_process_spt_switchover_prefixlist_cmd(vty, plist); } +DEFPY_ATTR(ip_pim_spt_switchover_infinity_plist, + ip_pim_spt_switchover_infinity_plist_cmd, + "ip pim spt-switchover infinity-and-beyond prefix-list PREFIXLIST4_NAME$plist", + IP_STR + PIM_STR + "SPT-Switchover\n" + "Never switch to SPT Tree\n" + "Prefix-List to control which groups to switch\n" + "Prefix-List name\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_spt_switchover_prefixlist_cmd(vty, plist); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} -DEFUN (no_ip_pim_spt_switchover_infinity, - no_ip_pim_spt_switchover_infinity_cmd, - "no ip pim spt-switchover infinity-and-beyond", +DEFPY (no_pim_spt_switchover_infinity, + no_pim_spt_switchover_infinity_cmd, + "no spt-switchover infinity-and-beyond", NO_STR - IP_STR - PIM_STR "SPT_Switchover\n" "Never switch to SPT Tree\n") { return pim_process_no_spt_switchover_cmd(vty); } +DEFPY_ATTR(no_ip_pim_spt_switchover_infinity, + no_ip_pim_spt_switchover_infinity_cmd, + "no ip pim spt-switchover infinity-and-beyond", + NO_STR + IP_STR + PIM_STR + "SPT_Switchover\n" + "Never switch to SPT Tree\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_no_spt_switchover_cmd(vty); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} -DEFUN (no_ip_pim_spt_switchover_infinity_plist, - no_ip_pim_spt_switchover_infinity_plist_cmd, - "no ip pim spt-switchover infinity-and-beyond prefix-list PREFIXLIST4_NAME", +DEFPY (no_pim_spt_switchover_infinity_plist, + no_pim_spt_switchover_infinity_plist_cmd, + "no spt-switchover infinity-and-beyond prefix-list PREFIXLIST4_NAME", NO_STR - IP_STR - PIM_STR "SPT_Switchover\n" "Never switch to SPT Tree\n" "Prefix-List to control which groups to switch\n" @@ -3038,28 +3196,61 @@ DEFUN (no_ip_pim_spt_switchover_infinity_plist, { return pim_process_no_spt_switchover_cmd(vty); } +DEFPY_ATTR(no_ip_pim_spt_switchover_infinity_plist, + no_ip_pim_spt_switchover_infinity_plist_cmd, + "no ip pim spt-switchover infinity-and-beyond prefix-list PREFIXLIST4_NAME", + NO_STR + IP_STR + PIM_STR + "SPT_Switchover\n" + "Never switch to SPT Tree\n" + "Prefix-List to control which groups to switch\n" + "Prefix-List name\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_no_spt_switchover_cmd(vty); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} DEFPY (pim_register_accept_list, pim_register_accept_list_cmd, - "[no] ip pim register-accept-list PREFIXLIST4_NAME$word", + "[no] register-accept-list PREFIXLIST4_NAME$word", NO_STR - IP_STR - PIM_STR "Only accept registers from a specific source prefix list\n" "Prefix-List name\n") { - const char *vrfname; char reg_alist_xpath[XPATH_MAXLEN]; - vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) - return CMD_WARNING_CONFIG_FAILED; - snprintf(reg_alist_xpath, sizeof(reg_alist_xpath), - FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, - "frr-routing:ipv4"); - strlcat(reg_alist_xpath, "/register-accept-list", - sizeof(reg_alist_xpath)); + "./register-accept-list"); if (no) nb_cli_enqueue_change(vty, reg_alist_xpath, @@ -3070,123 +3261,560 @@ DEFPY (pim_register_accept_list, return nb_cli_apply_changes(vty, NULL); } +DEFPY_ATTR(ip_pim_register_accept_list, + ip_pim_register_accept_list_cmd, + "[no] ip pim register-accept-list PREFIXLIST4_NAME$word", + NO_STR + IP_STR + PIM_STR + "Only accept registers from a specific source prefix list\n" + "Prefix-List name\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + char reg_alist_xpath[XPATH_MAXLEN]; + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; -DEFPY (ip_pim_joinprune_time, - ip_pim_joinprune_time_cmd, - "ip pim join-prune-interval (1-65535)$jpi", - IP_STR - "pim multicast routing\n" + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + snprintf(reg_alist_xpath, sizeof(reg_alist_xpath), + "./register-accept-list"); + + if (no) + nb_cli_enqueue_change(vty, reg_alist_xpath, NB_OP_DESTROY, NULL); + else + nb_cli_enqueue_change(vty, reg_alist_xpath, NB_OP_MODIFY, word); + + ret = nb_cli_apply_changes(vty, NULL); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} + +DEFPY (pim_joinprune_time, + pim_joinprune_time_cmd, + "join-prune-interval (1-65535)$jpi", "Join Prune Send Interval\n" "Seconds\n") { return pim_process_join_prune_cmd(vty, jpi_str); } +DEFPY_ATTR(ip_pim_joinprune_time, + ip_pim_joinprune_time_cmd, + "ip pim join-prune-interval (1-65535)$jpi", + IP_STR + PIM_STR + "Join Prune Send Interval\n" + "Seconds\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_join_prune_cmd(vty, jpi_str); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} -DEFUN (no_ip_pim_joinprune_time, - no_ip_pim_joinprune_time_cmd, - "no ip pim join-prune-interval [(1-65535)]", +DEFPY (no_pim_joinprune_time, + no_pim_joinprune_time_cmd, + "no join-prune-interval [(1-65535)]", NO_STR - IP_STR - "pim multicast routing\n" "Join Prune Send Interval\n" IGNORED_IN_NO_STR) { return pim_process_no_join_prune_cmd(vty); } +DEFPY_ATTR(no_ip_pim_joinprune_time, + no_ip_pim_joinprune_time_cmd, + "no ip pim join-prune-interval [(1-65535)]", + NO_STR + IP_STR + PIM_STR + "Join Prune Send Interval\n" + IGNORED_IN_NO_STR, + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; -DEFPY (ip_pim_register_suppress, - ip_pim_register_suppress_cmd, - "ip pim register-suppress-time (1-65535)$rst", - IP_STR - "pim multicast routing\n" + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_no_join_prune_cmd(vty); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} + +DEFPY (pim_register_suppress, + pim_register_suppress_cmd, + "register-suppress-time (1-65535)$rst", "Register Suppress Timer\n" "Seconds\n") { return pim_process_register_suppress_cmd(vty, rst_str); } +DEFPY_ATTR(ip_pim_register_suppress, + ip_pim_register_suppress_cmd, + "ip pim register-suppress-time (1-65535)$rst", + IP_STR + PIM_STR + "Register Suppress Timer\n" + "Seconds\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_register_suppress_cmd(vty, rst_str); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} -DEFUN (no_ip_pim_register_suppress, - no_ip_pim_register_suppress_cmd, - "no ip pim register-suppress-time [(1-65535)]", +DEFPY (no_pim_register_suppress, + no_pim_register_suppress_cmd, + "no register-suppress-time [(1-65535)]", NO_STR - IP_STR - "pim multicast routing\n" "Register Suppress Timer\n" IGNORED_IN_NO_STR) { return pim_process_no_register_suppress_cmd(vty); } +DEFPY_ATTR(no_ip_pim_register_suppress, + no_ip_pim_register_suppress_cmd, + "no ip pim register-suppress-time [(1-65535)]", + NO_STR + IP_STR + PIM_STR + "Register Suppress Timer\n" + IGNORED_IN_NO_STR, + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_no_register_suppress_cmd(vty); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} -DEFPY (ip_pim_rp_keep_alive, - ip_pim_rp_keep_alive_cmd, - "ip pim rp keep-alive-timer (1-65535)$kat", - IP_STR - "pim multicast routing\n" +DEFPY (pim_rp_keep_alive, + pim_rp_keep_alive_cmd, + "rp keep-alive-timer (1-65535)$kat", "Rendezvous Point\n" "Keep alive Timer\n" "Seconds\n") { return pim_process_rp_kat_cmd(vty, kat_str); } +DEFPY_ATTR(ip_pim_rp_keep_alive, + ip_pim_rp_keep_alive_cmd, + "ip pim rp keep-alive-timer (1-65535)$kat", + IP_STR + PIM_STR + "Rendezvous Point\n" + "Keep alive Timer\n" + "Seconds\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_rp_kat_cmd(vty, kat_str); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} -DEFUN (no_ip_pim_rp_keep_alive, - no_ip_pim_rp_keep_alive_cmd, - "no ip pim rp keep-alive-timer [(1-65535)]", +DEFPY (no_pim_rp_keep_alive, + no_pim_rp_keep_alive_cmd, + "no rp keep-alive-timer [(1-65535)]", NO_STR - IP_STR - "pim multicast routing\n" "Rendezvous Point\n" "Keep alive Timer\n" IGNORED_IN_NO_STR) { return pim_process_no_rp_kat_cmd(vty); } +DEFPY_ATTR(no_ip_pim_rp_keep_alive, + no_ip_pim_rp_keep_alive_cmd, + "no ip pim rp keep-alive-timer [(1-65535)]", + NO_STR + IP_STR + PIM_STR + "Rendezvous Point\n" + "Keep alive Timer\n" + IGNORED_IN_NO_STR, + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; -DEFPY (ip_pim_keep_alive, - ip_pim_keep_alive_cmd, - "ip pim keep-alive-timer (1-65535)$kat", - IP_STR - "pim multicast routing\n" + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_no_rp_kat_cmd(vty); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} + +DEFPY (pim_keep_alive, + pim_keep_alive_cmd, + "keep-alive-timer (1-65535)$kat", "Keep alive Timer\n" "Seconds\n") { return pim_process_keepalivetimer_cmd(vty, kat_str); } - -DEFUN (no_ip_pim_keep_alive, - no_ip_pim_keep_alive_cmd, - "no ip pim keep-alive-timer [(1-65535)]", - NO_STR - IP_STR - "pim multicast routing\n" - "Keep alive Timer\n" - IGNORED_IN_NO_STR) +DEFPY_ATTR(ip_pim_keep_alive, + ip_pim_keep_alive_cmd, + "ip pim keep-alive-timer (1-65535)$kat", + IP_STR + PIM_STR + "Keep alive Timer\n" + "Seconds\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) { - return pim_process_no_keepalivetimer_cmd(vty); -} + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; -DEFPY (ip_pim_packets, - ip_pim_packets_cmd, - "ip pim packets (1-255)", - IP_STR - "pim multicast routing\n" - "packets to process at one time per fd\n" - "Number of packets\n") + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_keepalivetimer_cmd(vty, kat_str); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} + +DEFPY (no_pim_keep_alive, + no_pim_keep_alive_cmd, + "no keep-alive-timer [(1-65535)]", + NO_STR + "Keep alive Timer\n" + IGNORED_IN_NO_STR) +{ + return pim_process_no_keepalivetimer_cmd(vty); +} +DEFPY_ATTR(no_ip_pim_keep_alive, + no_ip_pim_keep_alive_cmd, + "no ip pim keep-alive-timer [(1-65535)]", + NO_STR + IP_STR + PIM_STR + "Keep alive Timer\n" + IGNORED_IN_NO_STR, + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_no_keepalivetimer_cmd(vty); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} + +DEFPY (pim_packets, + pim_packets_cmd, + "packets (1-255)", + "packets to process at one time per fd\n" + "Number of packets\n") { return pim_process_pim_packet_cmd(vty, packets_str); } +DEFPY_ATTR(ip_pim_packets, + ip_pim_packets_cmd, + "ip pim packets (1-255)", + IP_STR + PIM_STR + "packets to process at one time per fd\n" + "Number of packets\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_pim_packet_cmd(vty, packets_str); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } -DEFUN (no_ip_pim_packets, - no_ip_pim_packets_cmd, - "no ip pim packets [(1-255)]", + return ret; +} + +DEFPY (no_pim_packets, + no_pim_packets_cmd, + "no packets [(1-255)]", NO_STR - IP_STR - "pim multicast routing\n" "packets to process at one time per fd\n" IGNORED_IN_NO_STR) { return pim_process_no_pim_packet_cmd(vty); } +DEFPY_ATTR(no_ip_pim_packets, + no_ip_pim_packets_cmd, + "no ip pim packets [(1-255)]", + NO_STR + IP_STR + PIM_STR + "packets to process at one time per fd\n" + IGNORED_IN_NO_STR, + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_no_pim_packet_cmd(vty); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} DEFPY (ip_igmp_group_watermark, ip_igmp_group_watermark_cmd, @@ -3217,64 +3845,131 @@ DEFPY (no_ip_igmp_group_watermark, return CMD_SUCCESS; } -DEFUN (ip_pim_v6_secondary, - ip_pim_v6_secondary_cmd, - "ip pim send-v6-secondary", - IP_STR - "pim multicast routing\n" +DEFPY (pim_v6_secondary, + pim_v6_secondary_cmd, + "send-v6-secondary", "Send v6 secondary addresses\n") { - const char *vrfname; char send_v6_secondary_xpath[XPATH_MAXLEN]; + snprintf(send_v6_secondary_xpath, sizeof(send_v6_secondary_xpath), + "./send-v6-secondary"); + + nb_cli_enqueue_change(vty, send_v6_secondary_xpath, NB_OP_MODIFY, + "true"); + + return nb_cli_apply_changes(vty, NULL); +} +DEFPY_ATTR(ip_pim_v6_secondary, + ip_pim_v6_secondary_cmd, + "ip pim send-v6-secondary", + IP_STR + PIM_STR + "Send v6 secondary addresses\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + char send_v6_secondary_xpath[XPATH_MAXLEN]; + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); return CMD_WARNING_CONFIG_FAILED; + } snprintf(send_v6_secondary_xpath, sizeof(send_v6_secondary_xpath), - FRR_PIM_VRF_XPATH, - "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); - strlcat(send_v6_secondary_xpath, "/send-v6-secondary", - sizeof(send_v6_secondary_xpath)); - + "./send-v6-secondary"); nb_cli_enqueue_change(vty, send_v6_secondary_xpath, NB_OP_MODIFY, "true"); + ret = nb_cli_apply_changes(vty, NULL); - return nb_cli_apply_changes(vty, NULL); + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; } -DEFUN (no_ip_pim_v6_secondary, - no_ip_pim_v6_secondary_cmd, - "no ip pim send-v6-secondary", +DEFPY (no_pim_v6_secondary, + no_pim_v6_secondary_cmd, + "no send-v6-secondary", NO_STR - IP_STR - "pim multicast routing\n" "Send v6 secondary addresses\n") { - const char *vrfname; char send_v6_secondary_xpath[XPATH_MAXLEN]; + snprintf(send_v6_secondary_xpath, sizeof(send_v6_secondary_xpath), + "./send-v6-secondary"); + + nb_cli_enqueue_change(vty, send_v6_secondary_xpath, NB_OP_MODIFY, + "false"); + + return nb_cli_apply_changes(vty, NULL); +} +DEFPY_ATTR(no_ip_pim_v6_secondary, + no_ip_pim_v6_secondary_cmd, + "no ip pim send-v6-secondary", + NO_STR + IP_STR + PIM_STR + "Send v6 secondary addresses\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + char send_v6_secondary_xpath[XPATH_MAXLEN]; + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); return CMD_WARNING_CONFIG_FAILED; + } snprintf(send_v6_secondary_xpath, sizeof(send_v6_secondary_xpath), - FRR_PIM_VRF_XPATH, - "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); - strlcat(send_v6_secondary_xpath, "/send-v6-secondary", - sizeof(send_v6_secondary_xpath)); - + "./send-v6-secondary"); nb_cli_enqueue_change(vty, send_v6_secondary_xpath, NB_OP_MODIFY, "false"); + ret = nb_cli_apply_changes(vty, NULL); - return nb_cli_apply_changes(vty, NULL); + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; } -DEFPY (ip_pim_rp, - ip_pim_rp_cmd, - "ip pim rp A.B.C.D$rp [A.B.C.D/M]$gp", - IP_STR - "pim multicast routing\n" +DEFPY (pim_rp, + pim_rp_cmd, + "rp A.B.C.D$rp [A.B.C.D/M]$gp", "Rendezvous Point\n" "ip address of RP\n" "Group Address range to cover\n") @@ -3283,12 +3978,52 @@ DEFPY (ip_pim_rp, return pim_process_rp_cmd(vty, rp_str, group_str); } +DEFPY_ATTR(ip_pim_rp, + ip_pim_rp_cmd, + "ip pim rp A.B.C.D$rp [A.B.C.D/M]$gp", + IP_STR + PIM_STR + "Rendezvous Point\n" + "ip address of RP\n" + "Group Address range to cover\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + const char *group_str = (gp_str) ? gp_str : "224.0.0.0/4"; + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; -DEFPY (ip_pim_rp_prefix_list, - ip_pim_rp_prefix_list_cmd, - "ip pim rp A.B.C.D$rp prefix-list PREFIXLIST4_NAME$plist", - IP_STR - "pim multicast routing\n" + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_rp_cmd(vty, rp_str, group_str); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} + +DEFPY (pim_rp_prefix_list, + pim_rp_prefix_list_cmd, + "rp A.B.C.D$rp prefix-list PREFIXLIST4_NAME$plist", "Rendezvous Point\n" "ip address of RP\n" "group prefix-list filter\n" @@ -3296,13 +4031,53 @@ DEFPY (ip_pim_rp_prefix_list, { return pim_process_rp_plist_cmd(vty, rp_str, plist); } +DEFPY_ATTR(ip_pim_rp_prefix_list, + ip_pim_rp_prefix_list_cmd, + "ip pim rp A.B.C.D$rp prefix-list PREFIXLIST4_NAME$plist", + IP_STR + PIM_STR + "Rendezvous Point\n" + "ip address of RP\n" + "group prefix-list filter\n" + "Name of a prefix-list\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_rp_plist_cmd(vty, rp_str, plist); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} -DEFPY (no_ip_pim_rp, - no_ip_pim_rp_cmd, - "no ip pim rp A.B.C.D$rp [A.B.C.D/M]$gp", +DEFPY (no_pim_rp, + no_pim_rp_cmd, + "no rp A.B.C.D$rp [A.B.C.D/M]$gp", NO_STR - IP_STR - "pim multicast routing\n" "Rendezvous Point\n" "ip address of RP\n" "Group Address range to cover\n") @@ -3311,13 +4086,54 @@ DEFPY (no_ip_pim_rp, return pim_process_no_rp_cmd(vty, rp_str, group_str); } +DEFPY_ATTR(no_ip_pim_rp, + no_ip_pim_rp_cmd, + "no ip pim rp A.B.C.D$rp [A.B.C.D/M]$gp", + NO_STR + IP_STR + PIM_STR + "Rendezvous Point\n" + "ip address of RP\n" + "Group Address range to cover\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + const char *group_str = (gp_str) ? gp_str : "224.0.0.0/4"; + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_no_rp_cmd(vty, rp_str, group_str); -DEFPY (no_ip_pim_rp_prefix_list, - no_ip_pim_rp_prefix_list_cmd, - "no ip pim rp A.B.C.D$rp prefix-list PREFIXLIST4_NAME$plist", + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} + +DEFPY (no_pim_rp_prefix_list, + no_pim_rp_prefix_list_cmd, + "no rp A.B.C.D$rp prefix-list PREFIXLIST4_NAME$plist", NO_STR - IP_STR - "pim multicast routing\n" "Rendezvous Point\n" "ip address of RP\n" "group prefix-list filter\n" @@ -3325,104 +4141,264 @@ DEFPY (no_ip_pim_rp_prefix_list, { return pim_process_no_rp_plist_cmd(vty, rp_str, plist); } +DEFPY_ATTR(no_ip_pim_rp_prefix_list, + no_ip_pim_rp_prefix_list_cmd, + "no ip pim rp A.B.C.D$rp prefix-list PREFIXLIST4_NAME$plist", + NO_STR + IP_STR + PIM_STR + "Rendezvous Point\n" + "ip address of RP\n" + "group prefix-list filter\n" + "Name of a prefix-list\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; -DEFUN (ip_pim_ssm_prefix_list, - ip_pim_ssm_prefix_list_cmd, - "ip pim ssm prefix-list PREFIXLIST4_NAME", - IP_STR - "pim multicast routing\n" + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_no_rp_plist_cmd(vty, rp_str, plist); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} + +DEFPY (pim_ssm_prefix_list, + pim_ssm_prefix_list_cmd, + "ssm prefix-list PREFIXLIST4_NAME$plist", "Source Specific Multicast\n" "group range prefix-list filter\n" "Name of a prefix-list\n") { - const char *vrfname; char ssm_plist_xpath[XPATH_MAXLEN]; + snprintf(ssm_plist_xpath, sizeof(ssm_plist_xpath), "./ssm-prefix-list"); + + nb_cli_enqueue_change(vty, ssm_plist_xpath, NB_OP_MODIFY, plist); + + return nb_cli_apply_changes(vty, NULL); +} +DEFPY_ATTR(ip_pim_ssm_prefix_list, + ip_pim_ssm_prefix_list_cmd, + "ip pim ssm prefix-list PREFIXLIST4_NAME$plist", + IP_STR + PIM_STR + "Source Specific Multicast\n" + "group range prefix-list filter\n" + "Name of a prefix-list\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + char ssm_plist_xpath[XPATH_MAXLEN]; + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); return CMD_WARNING_CONFIG_FAILED; + } - snprintf(ssm_plist_xpath, sizeof(ssm_plist_xpath), FRR_PIM_VRF_XPATH, - "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); - strlcat(ssm_plist_xpath, "/ssm-prefix-list", sizeof(ssm_plist_xpath)); + snprintf(ssm_plist_xpath, sizeof(ssm_plist_xpath), "./ssm-prefix-list"); + nb_cli_enqueue_change(vty, ssm_plist_xpath, NB_OP_MODIFY, plist); + ret = nb_cli_apply_changes(vty, NULL); - nb_cli_enqueue_change(vty, ssm_plist_xpath, NB_OP_MODIFY, argv[4]->arg); + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } - return nb_cli_apply_changes(vty, NULL); + return ret; } -DEFUN (no_ip_pim_ssm_prefix_list, - no_ip_pim_ssm_prefix_list_cmd, - "no ip pim ssm prefix-list", +DEFPY (no_pim_ssm_prefix_list, + no_pim_ssm_prefix_list_cmd, + "no ssm prefix-list", NO_STR - IP_STR - "pim multicast routing\n" "Source Specific Multicast\n" "group range prefix-list filter\n") { - const char *vrfname; char ssm_plist_xpath[XPATH_MAXLEN]; + snprintf(ssm_plist_xpath, sizeof(ssm_plist_xpath), "./ssm-prefix-list"); + + nb_cli_enqueue_change(vty, ssm_plist_xpath, NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); +} +DEFPY_ATTR(no_ip_pim_ssm_prefix_list, + no_ip_pim_ssm_prefix_list_cmd, + "no ip pim ssm prefix-list", + NO_STR + IP_STR + PIM_STR + "Source Specific Multicast\n" + "group range prefix-list filter\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + char ssm_plist_xpath[XPATH_MAXLEN]; + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); return CMD_WARNING_CONFIG_FAILED; + } - snprintf(ssm_plist_xpath, sizeof(ssm_plist_xpath), - FRR_PIM_VRF_XPATH, - "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); - strlcat(ssm_plist_xpath, "/ssm-prefix-list", sizeof(ssm_plist_xpath)); - + snprintf(ssm_plist_xpath, sizeof(ssm_plist_xpath), "./ssm-prefix-list"); nb_cli_enqueue_change(vty, ssm_plist_xpath, NB_OP_DESTROY, NULL); + ret = nb_cli_apply_changes(vty, NULL); - return nb_cli_apply_changes(vty, NULL); + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; } -DEFUN (no_ip_pim_ssm_prefix_list_name, - no_ip_pim_ssm_prefix_list_name_cmd, - "no ip pim ssm prefix-list PREFIXLIST4_NAME", +DEFPY (no_pim_ssm_prefix_list_name, + no_pim_ssm_prefix_list_name_cmd, + "no ssm prefix-list PREFIXLIST4_NAME$plist", NO_STR - IP_STR - "pim multicast routing\n" "Source Specific Multicast\n" "group range prefix-list filter\n" "Name of a prefix-list\n") { - const char *vrfname; const struct lyd_node *ssm_plist_dnode; char ssm_plist_xpath[XPATH_MAXLEN]; const char *ssm_plist_name; - vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) - return CMD_WARNING_CONFIG_FAILED; - - snprintf(ssm_plist_xpath, sizeof(ssm_plist_xpath), - FRR_PIM_VRF_XPATH, - "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); - strlcat(ssm_plist_xpath, "/ssm-prefix-list", sizeof(ssm_plist_xpath)); + snprintf(ssm_plist_xpath, sizeof(ssm_plist_xpath), "%s/ssm-prefix-list", + VTY_CURR_XPATH); ssm_plist_dnode = yang_dnode_get(vty->candidate_config->dnode, ssm_plist_xpath); if (!ssm_plist_dnode) { - vty_out(vty, - "%% pim ssm prefix-list %s doesn't exist\n", - argv[5]->arg); + vty_out(vty, "%% pim ssm prefix-list %s doesn't exist\n", plist); return CMD_WARNING_CONFIG_FAILED; } ssm_plist_name = yang_dnode_get_string(ssm_plist_dnode, "."); - if (ssm_plist_name && !strcmp(ssm_plist_name, argv[5]->arg)) { - nb_cli_enqueue_change(vty, ssm_plist_xpath, NB_OP_DESTROY, - NULL); - + if (ssm_plist_name && !strcmp(ssm_plist_name, plist)) { + nb_cli_enqueue_change(vty, ssm_plist_xpath, NB_OP_DESTROY, NULL); return nb_cli_apply_changes(vty, NULL); } - vty_out(vty, "%% pim ssm prefix-list %s doesn't exist\n", argv[5]->arg); + vty_out(vty, "%% pim ssm prefix-list %s doesn't exist\n", plist); return CMD_WARNING_CONFIG_FAILED; } +DEFPY_ATTR(no_ip_pim_ssm_prefix_list_name, + no_ip_pim_ssm_prefix_list_name_cmd, + "no ip pim ssm prefix-list PREFIXLIST4_NAME$plist", + NO_STR + IP_STR + PIM_STR + "Source Specific Multicast\n" + "group range prefix-list filter\n" + "Name of a prefix-list\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + const struct lyd_node *ssm_plist_dnode; + char ssm_plist_xpath[XPATH_MAXLEN]; + const char *ssm_plist_name; + int ret = CMD_WARNING_CONFIG_FAILED; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + snprintf(ssm_plist_xpath, sizeof(ssm_plist_xpath), "%s/ssm-prefix-list", + VTY_CURR_XPATH); + ssm_plist_dnode = yang_dnode_get(vty->candidate_config->dnode, + ssm_plist_xpath); + if (ssm_plist_dnode) { + ssm_plist_name = yang_dnode_get_string(ssm_plist_dnode, "."); + if (ssm_plist_name && !strcmp(ssm_plist_name, plist)) { + nb_cli_enqueue_change(vty, ssm_plist_xpath, + NB_OP_DESTROY, NULL); + ret = nb_cli_apply_changes(vty, NULL); + } else { + vty_out(vty, "%% pim ssm prefix-list %s doesn't exist\n", + plist); + } + } else { + vty_out(vty, "%% pim ssm prefix-list %s doesn't exist\n", plist); + } + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} DEFUN (show_ip_pim_ssm_range, show_ip_pim_ssm_range_cmd, @@ -3511,135 +4487,354 @@ DEFPY (show_ip_pim_bsr, return pim_show_bsr_helper(vrf, vty, !!json); } -DEFUN (ip_ssmpingd, - ip_ssmpingd_cmd, - "ip ssmpingd [A.B.C.D]", - IP_STR +DEFPY (pim_ssmpingd, + pim_ssmpingd_cmd, + "ssmpingd [A.B.C.D]$src", CONF_SSMPINGD_STR "Source address\n") { - int idx_ipv4 = 2; - const char *src_str = (argc == 3) ? argv[idx_ipv4]->arg : "0.0.0.0"; + if (src_str) + return pim_process_ssmpingd_cmd(vty, NB_OP_CREATE, src_str); + else + return pim_process_ssmpingd_cmd(vty, NB_OP_CREATE, "0.0.0.0"); +} +DEFPY_ATTR(ip_pim_ssmpingd, + ip_ssmpingd_cmd, + "ip ssmpingd [A.B.C.D]$src", + IP_STR + CONF_SSMPINGD_STR + "Source address\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; - return pim_process_ssmpingd_cmd(vty, NB_OP_CREATE, src_str); + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + if (src_str) + ret = pim_process_ssmpingd_cmd(vty, NB_OP_CREATE, src_str); + else + ret = pim_process_ssmpingd_cmd(vty, NB_OP_CREATE, "0.0.0.0"); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; } -DEFUN (no_ip_ssmpingd, - no_ip_ssmpingd_cmd, - "no ip ssmpingd [A.B.C.D]", +DEFPY (no_pim_ssmpingd, + no_pim_ssmpingd_cmd, + "no ssmpingd [A.B.C.D]$src", NO_STR - IP_STR CONF_SSMPINGD_STR "Source address\n") { - int idx_ipv4 = 3; - const char *src_str = (argc == 4) ? argv[idx_ipv4]->arg : "0.0.0.0"; + if (src_str) + return pim_process_ssmpingd_cmd(vty, NB_OP_DESTROY, src_str); + else + return pim_process_ssmpingd_cmd(vty, NB_OP_DESTROY, "0.0.0.0"); +} +DEFPY_ATTR(no_ip_pim_ssmpingd, + no_ip_ssmpingd_cmd, + "no ip ssmpingd [A.B.C.D]$src", + NO_STR + IP_STR + CONF_SSMPINGD_STR + "Source address\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + if (src_str) + ret = pim_process_ssmpingd_cmd(vty, NB_OP_DESTROY, src_str); + else + ret = pim_process_ssmpingd_cmd(vty, NB_OP_DESTROY, "0.0.0.0"); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } - return pim_process_ssmpingd_cmd(vty, NB_OP_DESTROY, src_str); + return ret; } -DEFUN (ip_pim_ecmp, - ip_pim_ecmp_cmd, - "ip pim ecmp", - IP_STR - "pim multicast routing\n" +DEFPY (pim_ecmp, + pim_ecmp_cmd, + "ecmp", "Enable PIM ECMP \n") { - const char *vrfname; char ecmp_xpath[XPATH_MAXLEN]; + snprintf(ecmp_xpath, sizeof(ecmp_xpath), "./ecmp"); + nb_cli_enqueue_change(vty, ecmp_xpath, NB_OP_MODIFY, "true"); + + return nb_cli_apply_changes(vty, NULL); +} +DEFPY_ATTR(ip_pim_ecmp, + ip_pim_ecmp_cmd, + "ip pim ecmp", + IP_STR + PIM_STR + "Enable PIM ECMP \n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + char ecmp_xpath[XPATH_MAXLEN]; + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); return CMD_WARNING_CONFIG_FAILED; + } - snprintf(ecmp_xpath, sizeof(ecmp_xpath), FRR_PIM_VRF_XPATH, - "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); - strlcat(ecmp_xpath, "/ecmp", sizeof(ecmp_xpath)); - + snprintf(ecmp_xpath, sizeof(ecmp_xpath), "./ecmp"); nb_cli_enqueue_change(vty, ecmp_xpath, NB_OP_MODIFY, "true"); - return nb_cli_apply_changes(vty, NULL); + ret = nb_cli_apply_changes(vty, NULL); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; } -DEFUN (no_ip_pim_ecmp, - no_ip_pim_ecmp_cmd, - "no ip pim ecmp", +DEFPY (no_pim_ecmp, + no_pim_ecmp_cmd, + "no ecmp", NO_STR - IP_STR - "pim multicast routing\n" "Disable PIM ECMP \n") { - const char *vrfname; char ecmp_xpath[XPATH_MAXLEN]; + snprintf(ecmp_xpath, sizeof(ecmp_xpath), "./ecmp"); + nb_cli_enqueue_change(vty, ecmp_xpath, NB_OP_MODIFY, "false"); + + return nb_cli_apply_changes(vty, NULL); +} +DEFPY_ATTR(no_ip_pim_ecmp, + no_ip_pim_ecmp_cmd, + "no ip pim ecmp", + NO_STR + IP_STR + PIM_STR + "Disable PIM ECMP \n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + char ecmp_xpath[XPATH_MAXLEN]; + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); return CMD_WARNING_CONFIG_FAILED; + } - snprintf(ecmp_xpath, sizeof(ecmp_xpath), FRR_PIM_VRF_XPATH, - "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); - strlcat(ecmp_xpath, "/ecmp", sizeof(ecmp_xpath)); - + snprintf(ecmp_xpath, sizeof(ecmp_xpath), "./ecmp"); nb_cli_enqueue_change(vty, ecmp_xpath, NB_OP_MODIFY, "false"); + ret = nb_cli_apply_changes(vty, NULL); - return nb_cli_apply_changes(vty, NULL); + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; } -DEFUN (ip_pim_ecmp_rebalance, - ip_pim_ecmp_rebalance_cmd, - "ip pim ecmp rebalance", - IP_STR - "pim multicast routing\n" +DEFPY (pim_ecmp_rebalance, + pim_ecmp_rebalance_cmd, + "ecmp rebalance", "Enable PIM ECMP \n" "Enable PIM ECMP Rebalance\n") { - const char *vrfname; char ecmp_xpath[XPATH_MAXLEN]; char ecmp_rebalance_xpath[XPATH_MAXLEN]; + snprintf(ecmp_xpath, sizeof(ecmp_xpath), "./ecmp"); + snprintf(ecmp_rebalance_xpath, sizeof(ecmp_rebalance_xpath), + "./ecmp-rebalance"); + + nb_cli_enqueue_change(vty, ecmp_xpath, NB_OP_MODIFY, "true"); + nb_cli_enqueue_change(vty, ecmp_rebalance_xpath, NB_OP_MODIFY, "true"); + + return nb_cli_apply_changes(vty, NULL); +} +DEFPY_ATTR(ip_pim_ecmp_rebalance, + ip_pim_ecmp_rebalance_cmd, + "ip pim ecmp rebalance", + IP_STR + PIM_STR + "Enable PIM ECMP \n" + "Enable PIM ECMP Rebalance\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + char ecmp_xpath[XPATH_MAXLEN]; + char ecmp_rebalance_xpath[XPATH_MAXLEN]; + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); return CMD_WARNING_CONFIG_FAILED; + } - snprintf(ecmp_xpath, sizeof(ecmp_xpath), FRR_PIM_VRF_XPATH, - "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); - strlcat(ecmp_xpath, "/ecmp", sizeof(ecmp_xpath)); + snprintf(ecmp_xpath, sizeof(ecmp_xpath), "./ecmp"); snprintf(ecmp_rebalance_xpath, sizeof(ecmp_rebalance_xpath), - FRR_PIM_VRF_XPATH, - "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); - strlcat(ecmp_rebalance_xpath, "/ecmp-rebalance", - sizeof(ecmp_rebalance_xpath)); - + "./ecmp-rebalance"); nb_cli_enqueue_change(vty, ecmp_xpath, NB_OP_MODIFY, "true"); nb_cli_enqueue_change(vty, ecmp_rebalance_xpath, NB_OP_MODIFY, "true"); + ret = nb_cli_apply_changes(vty, NULL); - return nb_cli_apply_changes(vty, NULL); + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; } -DEFUN (no_ip_pim_ecmp_rebalance, - no_ip_pim_ecmp_rebalance_cmd, - "no ip pim ecmp rebalance", +DEFPY (no_pim_ecmp_rebalance, + no_pim_ecmp_rebalance_cmd, + "no ecmp rebalance", NO_STR - IP_STR - "pim multicast routing\n" "Disable PIM ECMP \n" "Disable PIM ECMP Rebalance\n") { - const char *vrfname; char ecmp_rebalance_xpath[XPATH_MAXLEN]; + snprintf(ecmp_rebalance_xpath, sizeof(ecmp_rebalance_xpath), + "./ecmp-rebalance"); + + nb_cli_enqueue_change(vty, ecmp_rebalance_xpath, NB_OP_MODIFY, "false"); + + return nb_cli_apply_changes(vty, NULL); +} +DEFPY_ATTR(no_ip_pim_ecmp_rebalance, + no_ip_pim_ecmp_rebalance_cmd, + "no ip pim ecmp rebalance", + NO_STR + IP_STR + PIM_STR + "Disable PIM ECMP \n" + "Disable PIM ECMP Rebalance\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + char ecmp_rebalance_xpath[XPATH_MAXLEN]; + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); return CMD_WARNING_CONFIG_FAILED; + } snprintf(ecmp_rebalance_xpath, sizeof(ecmp_rebalance_xpath), - FRR_PIM_VRF_XPATH, - "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); - strlcat(ecmp_rebalance_xpath, "/ecmp-rebalance", - sizeof(ecmp_rebalance_xpath)); - + "./ecmp-rebalance"); nb_cli_enqueue_change(vty, ecmp_rebalance_xpath, NB_OP_MODIFY, "false"); + ret = nb_cli_apply_changes(vty, NULL); - return nb_cli_apply_changes(vty, NULL); + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; } DEFUN (interface_ip_igmp, @@ -4648,15 +5843,24 @@ DEFPY (debug_pim_zebra, return CMD_SUCCESS; } -DEFUN(debug_pim_mlag, debug_pim_mlag_cmd, "debug pim mlag", - DEBUG_STR DEBUG_PIM_STR DEBUG_PIM_MLAG_STR) +DEFUN(debug_pim_mlag, + debug_pim_mlag_cmd, + "debug pim mlag", + DEBUG_STR + DEBUG_PIM_STR + DEBUG_PIM_MLAG_STR) { PIM_DO_DEBUG_MLAG; return CMD_SUCCESS; } -DEFUN(no_debug_pim_mlag, no_debug_pim_mlag_cmd, "no debug pim mlag", - NO_STR DEBUG_STR DEBUG_PIM_STR DEBUG_PIM_MLAG_STR) +DEFUN(no_debug_pim_mlag, + no_debug_pim_mlag_cmd, + "no debug pim mlag", + NO_STR + DEBUG_STR + DEBUG_PIM_STR + DEBUG_PIM_MLAG_STR) { PIM_DONT_DEBUG_MLAG; return CMD_SUCCESS; @@ -5016,145 +6220,333 @@ ALIAS(no_ip_pim_bfd, no_ip_pim_bfd_param_cmd, "Desired min transmit interval\n") #endif /* !HAVE_BFDD */ -DEFPY(ip_msdp_peer, ip_msdp_peer_cmd, - "ip msdp peer A.B.C.D$peer source A.B.C.D$source", - IP_STR +DEFPY(pim_msdp_peer, pim_msdp_peer_cmd, + "msdp peer A.B.C.D$peer source A.B.C.D$source", CFG_MSDP_STR "Configure MSDP peer\n" "Peer IP address\n" "Source address for TCP connection\n" "Local IP address\n") { - const char *vrfname; - char temp_xpath[XPATH_MAXLEN]; char msdp_peer_source_xpath[XPATH_MAXLEN]; + snprintf(msdp_peer_source_xpath, sizeof(msdp_peer_source_xpath), + "./msdp-peer[peer-ip='%s']/source-ip", peer_str); + nb_cli_enqueue_change(vty, msdp_peer_source_xpath, NB_OP_MODIFY, + source_str); + + return nb_cli_apply_changes(vty, NULL); +} +DEFPY_ATTR(ip_pim_msdp_peer, + ip_msdp_peer_cmd, + "ip msdp peer A.B.C.D$peer source A.B.C.D$source", + IP_STR + CFG_MSDP_STR + "Configure MSDP peer\n" + "Peer IP address\n" + "Source address for TCP connection\n" + "Local IP address\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + char msdp_peer_source_xpath[XPATH_MAXLEN]; + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); return CMD_WARNING_CONFIG_FAILED; + } snprintf(msdp_peer_source_xpath, sizeof(msdp_peer_source_xpath), - FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, - "frr-routing:ipv4"); - snprintf(temp_xpath, sizeof(temp_xpath), - "/msdp-peer[peer-ip='%s']/source-ip", peer_str); - strlcat(msdp_peer_source_xpath, temp_xpath, - sizeof(msdp_peer_source_xpath)); - + "./msdp-peer[peer-ip='%s']/source-ip", peer_str); nb_cli_enqueue_change(vty, msdp_peer_source_xpath, NB_OP_MODIFY, source_str); + ret = nb_cli_apply_changes(vty, NULL); - return nb_cli_apply_changes(vty, - FRR_PIM_INTERFACE_XPATH, "frr-routing:ipv4"); + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; } -DEFPY(ip_msdp_timers, ip_msdp_timers_cmd, - "ip msdp timers (1-65535)$keepalive (1-65535)$holdtime [(1-65535)$connretry]", - IP_STR +DEFPY(pim_msdp_timers, pim_msdp_timers_cmd, + "msdp timers (1-65535)$keepalive (1-65535)$holdtime [(1-65535)$connretry]", CFG_MSDP_STR "MSDP timers configuration\n" "Keep alive period (in seconds)\n" "Hold time period (in seconds)\n" "Connection retry period (in seconds)\n") { + nb_cli_enqueue_change(vty, "./msdp/hold-time", NB_OP_MODIFY, + holdtime_str); + nb_cli_enqueue_change(vty, "./msdp/keep-alive", NB_OP_MODIFY, + keepalive_str); + if (connretry_str) + nb_cli_enqueue_change(vty, "./msdp/connection-retry", + NB_OP_MODIFY, connretry_str); + else + nb_cli_enqueue_change(vty, "./msdp/connection-retry", + NB_OP_DESTROY, NULL); + + nb_cli_apply_changes(vty, NULL); + return CMD_SUCCESS; +} +DEFPY_ATTR(ip_pim_msdp_timers, + ip_msdp_timers_cmd, + "ip msdp timers (1-65535)$keepalive (1-65535)$holdtime [(1-65535)$connretry]", + IP_STR + CFG_MSDP_STR + "MSDP timers configuration\n" + "Keep alive period (in seconds)\n" + "Hold time period (in seconds)\n" + "Connection retry period (in seconds)\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); return CMD_WARNING_CONFIG_FAILED; + } - nb_cli_enqueue_change(vty, "./hold-time", NB_OP_MODIFY, holdtime_str); - nb_cli_enqueue_change(vty, "./keep-alive", NB_OP_MODIFY, keepalive_str); + nb_cli_enqueue_change(vty, "./msdp/hold-time", NB_OP_MODIFY, + holdtime_str); + nb_cli_enqueue_change(vty, "./msdp/keep-alive", NB_OP_MODIFY, + keepalive_str); if (connretry_str) - nb_cli_enqueue_change(vty, "./connection-retry", NB_OP_MODIFY, - connretry_str); + nb_cli_enqueue_change(vty, "./msdp/connection-retry", + NB_OP_MODIFY, connretry_str); else - nb_cli_enqueue_change(vty, "./connection-retry", NB_OP_DESTROY, - NULL); + nb_cli_enqueue_change(vty, "./msdp/connection-retry", + NB_OP_DESTROY, NULL); + ret = nb_cli_apply_changes(vty, NULL); - nb_cli_apply_changes(vty, FRR_PIM_MSDP_XPATH, "frr-pim:pimd", "pim", - vrfname, "frr-routing:ipv4"); - return CMD_SUCCESS; + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; } -DEFPY(no_ip_msdp_timers, no_ip_msdp_timers_cmd, - "no ip msdp timers [(1-65535) (1-65535) [(1-65535)]]", +DEFPY(no_pim_msdp_timers, no_pim_msdp_timers_cmd, + "no msdp timers [(1-65535) (1-65535) [(1-65535)]]", NO_STR - IP_STR CFG_MSDP_STR "MSDP timers configuration\n" IGNORED_IN_NO_STR IGNORED_IN_NO_STR IGNORED_IN_NO_STR) { + nb_cli_enqueue_change(vty, "./msdp/hold-time", NB_OP_DESTROY, NULL); + nb_cli_enqueue_change(vty, "./msdp/keep-alive", NB_OP_DESTROY, NULL); + nb_cli_enqueue_change(vty, "./msdp/connection-retry", NB_OP_DESTROY, + NULL); + nb_cli_apply_changes(vty, NULL); + return CMD_SUCCESS; +} +DEFPY_ATTR(no_ip_pim_msdp_timers, + no_ip_msdp_timers_cmd, + "no ip msdp timers [(1-65535) (1-65535) [(1-65535)]]", + NO_STR + IP_STR + CFG_MSDP_STR + "MSDP timers configuration\n" + IGNORED_IN_NO_STR + IGNORED_IN_NO_STR + IGNORED_IN_NO_STR, + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); return CMD_WARNING_CONFIG_FAILED; + } - nb_cli_enqueue_change(vty, "./hold-time", NB_OP_DESTROY, NULL); - nb_cli_enqueue_change(vty, "./keep-alive", NB_OP_DESTROY, NULL); - nb_cli_enqueue_change(vty, "./connection-retry", NB_OP_DESTROY, NULL); + nb_cli_enqueue_change(vty, "./msdp/hold-time", NB_OP_DESTROY, NULL); + nb_cli_enqueue_change(vty, "./msdp/keep-alive", NB_OP_DESTROY, NULL); + nb_cli_enqueue_change(vty, "./msdp/connection-retry", NB_OP_DESTROY, + NULL); + ret = nb_cli_apply_changes(vty, NULL); - nb_cli_apply_changes(vty, FRR_PIM_MSDP_XPATH, "frr-pim:pimd", "pim", - vrfname, "frr-routing:ipv4"); + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } - return CMD_SUCCESS; + return ret; } -DEFUN (no_ip_msdp_peer, - no_ip_msdp_peer_cmd, - "no ip msdp peer A.B.C.D", +DEFPY (no_pim_msdp_peer, + no_pim_msdp_peer_cmd, + "no msdp peer A.B.C.D", NO_STR - IP_STR CFG_MSDP_STR "Delete MSDP peer\n" "peer ip address\n") { - const char *vrfname; char msdp_peer_xpath[XPATH_MAXLEN]; - char temp_xpath[XPATH_MAXLEN]; + + snprintf(msdp_peer_xpath, sizeof(msdp_peer_xpath), + "./msdp-peer[peer-ip='%s']", peer_str); + nb_cli_enqueue_change(vty, msdp_peer_xpath, NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); +} +DEFPY_ATTR(no_ip_pim_msdp_peer, + no_ip_msdp_peer_cmd, + "no ip msdp peer A.B.C.D", + NO_STR + IP_STR + CFG_MSDP_STR + "Delete MSDP peer\n" + "peer ip address\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + char msdp_peer_xpath[XPATH_MAXLEN]; + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); return CMD_WARNING_CONFIG_FAILED; + } snprintf(msdp_peer_xpath, sizeof(msdp_peer_xpath), - FRR_PIM_VRF_XPATH, - "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); - snprintf(temp_xpath, sizeof(temp_xpath), - "/msdp-peer[peer-ip='%s']", - argv[4]->arg); - - strlcat(msdp_peer_xpath, temp_xpath, sizeof(msdp_peer_xpath)); - + "./msdp-peer[peer-ip='%s']", peer_str); nb_cli_enqueue_change(vty, msdp_peer_xpath, NB_OP_DESTROY, NULL); + ret = nb_cli_apply_changes(vty, NULL); - return nb_cli_apply_changes(vty, NULL); + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; } -DEFPY(ip_msdp_mesh_group_member, - ip_msdp_mesh_group_member_cmd, - "ip msdp mesh-group WORD$gname member A.B.C.D$maddr", - IP_STR +DEFPY(pim_msdp_mesh_group_member, + pim_msdp_mesh_group_member_cmd, + "msdp mesh-group WORD$gname member A.B.C.D$maddr", CFG_MSDP_STR "Configure MSDP mesh-group\n" "Mesh group name\n" "Mesh group member\n" "Peer IP address\n") { - const char *vrfname; char xpath_value[XPATH_MAXLEN]; + /* Create mesh group. */ + snprintf(xpath_value, sizeof(xpath_value), + "./msdp-mesh-groups[name='%s']", gname); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_CREATE, NULL); + + /* Create mesh group member. */ + strlcat(xpath_value, "/members[address='", sizeof(xpath_value)); + strlcat(xpath_value, maddr_str, sizeof(xpath_value)); + strlcat(xpath_value, "']", sizeof(xpath_value)); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_CREATE, NULL); + + return nb_cli_apply_changes(vty, NULL); +} +DEFPY_ATTR(ip_pim_msdp_mesh_group_member, + ip_msdp_mesh_group_member_cmd, + "ip msdp mesh-group WORD$gname member A.B.C.D$maddr", + IP_STR + CFG_MSDP_STR + "Configure MSDP mesh-group\n" + "Mesh group name\n" + "Mesh group member\n" + "Peer IP address\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + char xpath_value[XPATH_MAXLEN]; + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); return CMD_WARNING_CONFIG_FAILED; + } /* Create mesh group. */ snprintf(xpath_value, sizeof(xpath_value), - FRR_PIM_VRF_XPATH "/msdp-mesh-groups[name='%s']", - "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4", gname); + "./msdp-mesh-groups[name='%s']", gname); nb_cli_enqueue_change(vty, xpath_value, NB_OP_CREATE, NULL); /* Create mesh group member. */ @@ -5162,33 +6554,32 @@ DEFPY(ip_msdp_mesh_group_member, strlcat(xpath_value, maddr_str, sizeof(xpath_value)); strlcat(xpath_value, "']", sizeof(xpath_value)); nb_cli_enqueue_change(vty, xpath_value, NB_OP_CREATE, NULL); + ret = nb_cli_apply_changes(vty, NULL); - return nb_cli_apply_changes(vty, NULL); + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; } -DEFPY(no_ip_msdp_mesh_group_member, - no_ip_msdp_mesh_group_member_cmd, - "no ip msdp mesh-group WORD$gname member A.B.C.D$maddr", +DEFPY(no_pim_msdp_mesh_group_member, + no_pim_msdp_mesh_group_member_cmd, + "no msdp mesh-group WORD$gname member A.B.C.D$maddr", NO_STR - IP_STR CFG_MSDP_STR "Delete MSDP mesh-group member\n" "Mesh group name\n" "Mesh group member\n" "Peer IP address\n") { - const char *vrfname; char xpath_value[XPATH_MAXLEN]; char xpath_member_value[XPATH_MAXLEN]; - vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) - return CMD_WARNING_CONFIG_FAILED; - /* Get mesh group base XPath. */ snprintf(xpath_value, sizeof(xpath_value), - FRR_PIM_VRF_XPATH "/msdp-mesh-groups[name='%s']", - "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4", gname); + "%s/msdp-mesh-groups[name='%s']", VTY_CURR_XPATH, gname); if (!yang_dnode_exists(vty->candidate_config->dnode, xpath_value)) { vty_out(vty, "%% mesh-group does not exist\n"); @@ -5217,59 +6608,221 @@ DEFPY(no_ip_msdp_mesh_group_member, return nb_cli_apply_changes(vty, NULL); } +DEFPY_ATTR(no_ip_pim_msdp_mesh_group_member, + no_ip_msdp_mesh_group_member_cmd, + "no ip msdp mesh-group WORD$gname member A.B.C.D$maddr", + NO_STR + IP_STR + CFG_MSDP_STR + "Delete MSDP mesh-group member\n" + "Mesh group name\n" + "Mesh group member\n" + "Peer IP address\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + char xpath_value[XPATH_MAXLEN]; + char xpath_member_value[XPATH_MAXLEN]; + int ret = CMD_WARNING_CONFIG_FAILED; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; -DEFPY(ip_msdp_mesh_group_source, - ip_msdp_mesh_group_source_cmd, - "ip msdp mesh-group WORD$gname source A.B.C.D$saddr", - IP_STR + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + /* Get mesh group base XPath. */ + snprintf(xpath_value, sizeof(xpath_value), + "%s/msdp-mesh-groups[name='%s']", VTY_CURR_XPATH, gname); + + if (yang_dnode_exists(vty->candidate_config->dnode, xpath_value)) { + /* Remove mesh group member. */ + strlcpy(xpath_member_value, xpath_value, + sizeof(xpath_member_value)); + strlcat(xpath_member_value, "/members[address='", + sizeof(xpath_member_value)); + strlcat(xpath_member_value, maddr_str, + sizeof(xpath_member_value)); + strlcat(xpath_member_value, "']", sizeof(xpath_member_value)); + if (yang_dnode_exists(vty->candidate_config->dnode, + xpath_member_value)) { + nb_cli_enqueue_change(vty, xpath_member_value, + NB_OP_DESTROY, NULL); + + /* + * If this is the last member, then we must remove the group altogether + * to not break legacy CLI behaviour. + */ + pim_cli_legacy_mesh_group_behavior(vty, gname); + ret = nb_cli_apply_changes(vty, NULL); + } else { + vty_out(vty, "%% mesh-group member does not exist\n"); + } + } else { + vty_out(vty, "%% mesh-group does not exist\n"); + } + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} + +DEFPY(pim_msdp_mesh_group_source, + pim_msdp_mesh_group_source_cmd, + "msdp mesh-group WORD$gname source A.B.C.D$saddr", CFG_MSDP_STR "Configure MSDP mesh-group\n" "Mesh group name\n" "Mesh group local address\n" "Source IP address for the TCP connection\n") { - const char *vrfname; char xpath_value[XPATH_MAXLEN]; + /* Create mesh group. */ + snprintf(xpath_value, sizeof(xpath_value), + "./msdp-mesh-groups[name='%s']", gname); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_CREATE, NULL); + + /* Create mesh group source. */ + strlcat(xpath_value, "/source", sizeof(xpath_value)); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, saddr_str); + + return nb_cli_apply_changes(vty, NULL); +} +DEFPY_ATTR(ip_pim_msdp_mesh_group_source, + ip_msdp_mesh_group_source_cmd, + "ip msdp mesh-group WORD$gname source A.B.C.D$saddr", + IP_STR + CFG_MSDP_STR + "Configure MSDP mesh-group\n" + "Mesh group name\n" + "Mesh group local address\n" + "Source IP address for the TCP connection\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + char xpath_value[XPATH_MAXLEN]; + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); return CMD_WARNING_CONFIG_FAILED; + } /* Create mesh group. */ snprintf(xpath_value, sizeof(xpath_value), - FRR_PIM_VRF_XPATH "/msdp-mesh-groups[name='%s']", - "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4", gname); + "./msdp-mesh-groups[name='%s']", gname); nb_cli_enqueue_change(vty, xpath_value, NB_OP_CREATE, NULL); - /* Create mesh group source. */ strlcat(xpath_value, "/source", sizeof(xpath_value)); nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, saddr_str); + ret = nb_cli_apply_changes(vty, NULL); - return nb_cli_apply_changes(vty, NULL); + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; } -DEFPY(no_ip_msdp_mesh_group_source, - no_ip_msdp_mesh_group_source_cmd, - "no ip msdp mesh-group WORD$gname source [A.B.C.D]", +DEFPY(no_pim_msdp_mesh_group_source, + no_pim_msdp_mesh_group_source_cmd, + "no msdp mesh-group WORD$gname source [A.B.C.D]", NO_STR - IP_STR CFG_MSDP_STR "Delete MSDP mesh-group source\n" "Mesh group name\n" "Mesh group source\n" "Mesh group local address\n") { - const char *vrfname; char xpath_value[XPATH_MAXLEN]; + /* Get mesh group base XPath. */ + snprintf(xpath_value, sizeof(xpath_value), + "./msdp-mesh-groups[name='%s']", gname); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_CREATE, NULL); + + /* Create mesh group source. */ + strlcat(xpath_value, "/source", sizeof(xpath_value)); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_DESTROY, NULL); + + /* + * If this is the last member, then we must remove the group altogether + * to not break legacy CLI behaviour. + */ + pim_cli_legacy_mesh_group_behavior(vty, gname); + + return nb_cli_apply_changes(vty, NULL); +} +DEFPY_ATTR(no_ip_pim_msdp_mesh_group_source, + no_ip_msdp_mesh_group_source_cmd, + "no ip msdp mesh-group WORD$gname source [A.B.C.D]", + NO_STR + IP_STR + CFG_MSDP_STR + "Delete MSDP mesh-group source\n" + "Mesh group name\n" + "Mesh group source\n" + "Mesh group local address\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + char xpath_value[XPATH_MAXLEN]; + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); return CMD_WARNING_CONFIG_FAILED; + } /* Get mesh group base XPath. */ snprintf(xpath_value, sizeof(xpath_value), - FRR_PIM_VRF_XPATH "/msdp-mesh-groups[name='%s']", - "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4", gname); + "./msdp-mesh-groups[name='%s']", gname); nb_cli_enqueue_change(vty, xpath_value, NB_OP_CREATE, NULL); /* Create mesh group source. */ @@ -5281,36 +6834,83 @@ DEFPY(no_ip_msdp_mesh_group_source, * to not break legacy CLI behaviour. */ pim_cli_legacy_mesh_group_behavior(vty, gname); + ret = nb_cli_apply_changes(vty, NULL); - return nb_cli_apply_changes(vty, NULL); + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; } -DEFPY(no_ip_msdp_mesh_group, - no_ip_msdp_mesh_group_cmd, - "no ip msdp mesh-group WORD$gname", +DEFPY(no_pim_msdp_mesh_group, + no_pim_msdp_mesh_group_cmd, + "no msdp mesh-group WORD$gname", NO_STR - IP_STR CFG_MSDP_STR "Delete MSDP mesh-group\n" "Mesh group name\n") { - const char *vrfname; char xpath_value[XPATH_MAXLEN]; - vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) - return CMD_WARNING_CONFIG_FAILED; - /* Get mesh group base XPath. */ snprintf(xpath_value, sizeof(xpath_value), - FRR_PIM_VRF_XPATH "/msdp-mesh-groups[name='%s']", - "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4", gname); + "%s/msdp-mesh-groups[name='%s']", VTY_CURR_XPATH, gname); if (!yang_dnode_exists(vty->candidate_config->dnode, xpath_value)) return CMD_SUCCESS; nb_cli_enqueue_change(vty, xpath_value, NB_OP_DESTROY, NULL); return nb_cli_apply_changes(vty, NULL); } +DEFPY_ATTR(no_ip_pim_msdp_mesh_group, + no_ip_msdp_mesh_group_cmd, + "no ip msdp mesh-group WORD$gname", + NO_STR + IP_STR + CFG_MSDP_STR + "Delete MSDP mesh-group\n" + "Mesh group name\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + char xpath_value[XPATH_MAXLEN]; + int ret = CMD_SUCCESS; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + /* Get mesh group base XPath. */ + snprintf(xpath_value, sizeof(xpath_value), + "%s/msdp-mesh-groups[name='%s']", VTY_CURR_XPATH, gname); + if (yang_dnode_exists(vty->candidate_config->dnode, xpath_value)) { + nb_cli_enqueue_change(vty, xpath_value, NB_OP_DESTROY, NULL); + ret = nb_cli_apply_changes(vty, NULL); + } + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} static void ip_msdp_show_mesh_group(struct vty *vty, struct pim_msdp_mg *mg, struct json_object *json) @@ -5329,7 +6929,8 @@ static void ip_msdp_show_mesh_group(struct vty *vty, struct pim_msdp_mg *mg, if (json) { /* currently there is only one mesh group but we should still * make - * it a dict with mg-name as key */ + * it a dict with mg-name as key + */ json_mg_row = json_object_new_object(); json_object_string_add(json_mg_row, "name", mg->mesh_group_name); @@ -6311,119 +7912,224 @@ DEFUN_HIDDEN (show_ip_pim_vxlan_sg_work, return CMD_SUCCESS; } -DEFUN_HIDDEN (no_ip_pim_mlag, - no_ip_pim_mlag_cmd, - "no ip pim mlag", +DEFPY_HIDDEN (no_pim_mlag, + no_pim_mlag_cmd, + "no mlag", NO_STR - IP_STR - PIM_STR "MLAG\n") { char mlag_xpath[XPATH_MAXLEN]; - snprintf(mlag_xpath, sizeof(mlag_xpath), FRR_PIM_VRF_XPATH, - "frr-pim:pimd", "pim", "default", "frr-routing:ipv4"); - strlcat(mlag_xpath, "/mlag", sizeof(mlag_xpath)); + snprintf(mlag_xpath, sizeof(mlag_xpath), "./mlag"); + nb_cli_enqueue_change(vty, mlag_xpath, NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); +} +DEFPY_ATTR(no_ip_pim_mlag, + no_ip_pim_mlag_cmd, + "no ip pim mlag", + NO_STR + IP_STR + PIM_STR + "MLAG\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + char mlag_xpath[XPATH_MAXLEN]; + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + snprintf(mlag_xpath, sizeof(mlag_xpath), "./mlag"); nb_cli_enqueue_change(vty, mlag_xpath, NB_OP_DESTROY, NULL); + ret = nb_cli_apply_changes(vty, NULL); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} + +DEFPY_HIDDEN (pim_mlag, + pim_mlag_cmd, + "mlag INTERFACE$iface role [primary|secondary]$role state [up|down]$state addr A.B.C.D$addr", + "MLAG\n" + "peerlink sub interface\n" + "MLAG role\n" + "MLAG role primary\n" + "MLAG role secondary\n" + "peer session state\n" + "peer session state up\n" + "peer session state down\n" + "configure PIP\n" + "unique ip address\n") +{ + char mlag_peerlink_rif_xpath[XPATH_MAXLEN]; + char mlag_my_role_xpath[XPATH_MAXLEN]; + char mlag_peer_state_xpath[XPATH_MAXLEN]; + char mlag_reg_address_xpath[XPATH_MAXLEN]; + + snprintf(mlag_peerlink_rif_xpath, sizeof(mlag_peerlink_rif_xpath), + "./mlag/peerlink-rif"); + nb_cli_enqueue_change(vty, mlag_peerlink_rif_xpath, NB_OP_MODIFY, iface); + + snprintf(mlag_my_role_xpath, sizeof(mlag_my_role_xpath), + "./mlag/my-role"); + if (!strcmp(role, "primary")) { + nb_cli_enqueue_change(vty, mlag_my_role_xpath, NB_OP_MODIFY, + "MLAG_ROLE_PRIMARY"); + } else if (!strcmp(role, "secondary")) { + nb_cli_enqueue_change(vty, mlag_my_role_xpath, NB_OP_MODIFY, + "MLAG_ROLE_SECONDARY"); + } else { + vty_out(vty, "unknown MLAG role %s\n", role); + return CMD_WARNING; + } + + snprintf(mlag_peer_state_xpath, sizeof(mlag_peer_state_xpath), + "./mlag/peer-state"); + if (!strcmp(state, "up")) { + nb_cli_enqueue_change(vty, mlag_peer_state_xpath, NB_OP_MODIFY, + "true"); + } else if (strcmp(state, "down")) { + nb_cli_enqueue_change(vty, mlag_peer_state_xpath, NB_OP_MODIFY, + "false"); + } else { + vty_out(vty, "unknown MLAG state %s\n", state); + return CMD_WARNING; + } + snprintf(mlag_reg_address_xpath, sizeof(mlag_reg_address_xpath), + "./mlag/reg-address"); + nb_cli_enqueue_change(vty, mlag_reg_address_xpath, NB_OP_MODIFY, + addr_str); return nb_cli_apply_changes(vty, NULL); } - -DEFUN_HIDDEN (ip_pim_mlag, - ip_pim_mlag_cmd, - "ip pim mlag INTERFACE role [primary|secondary] state [up|down] addr A.B.C.D", - IP_STR - PIM_STR - "MLAG\n" - "peerlink sub interface\n" - "MLAG role\n" - "MLAG role primary\n" - "MLAG role secondary\n" - "peer session state\n" - "peer session state up\n" - "peer session state down\n" - "configure PIP\n" - "unique ip address\n") +DEFPY_ATTR(ip_pim_mlag, + ip_pim_mlag_cmd, + "ip pim mlag INTERFACE$iface role [primary|secondary]$role state [up|down]$state addr A.B.C.D$addr", + IP_STR + PIM_STR + "MLAG\n" + "peerlink sub interface\n" + "MLAG role\n" + "MLAG role primary\n" + "MLAG role secondary\n" + "peer session state\n" + "peer session state up\n" + "peer session state down\n" + "configure PIP\n" + "unique ip address\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) { - int idx; char mlag_peerlink_rif_xpath[XPATH_MAXLEN]; char mlag_my_role_xpath[XPATH_MAXLEN]; char mlag_peer_state_xpath[XPATH_MAXLEN]; char mlag_reg_address_xpath[XPATH_MAXLEN]; + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; - snprintf(mlag_peerlink_rif_xpath, sizeof(mlag_peerlink_rif_xpath), - FRR_PIM_VRF_XPATH, - "frr-pim:pimd", "pim", "default", "frr-routing:ipv4"); - strlcat(mlag_peerlink_rif_xpath, "/mlag/peerlink-rif", - sizeof(mlag_peerlink_rif_xpath)); + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } - idx = 3; - nb_cli_enqueue_change(vty, mlag_peerlink_rif_xpath, NB_OP_MODIFY, - argv[idx]->arg); + snprintf(mlag_peerlink_rif_xpath, sizeof(mlag_peerlink_rif_xpath), + "./mlag/peerlink-rif"); + nb_cli_enqueue_change(vty, mlag_peerlink_rif_xpath, NB_OP_MODIFY, iface); snprintf(mlag_my_role_xpath, sizeof(mlag_my_role_xpath), - FRR_PIM_VRF_XPATH, - "frr-pim:pimd", "pim", "default", "frr-routing:ipv4"); - strlcat(mlag_my_role_xpath, "/mlag/my-role", - sizeof(mlag_my_role_xpath)); - - idx += 2; - if (!strcmp(argv[idx]->arg, "primary")) { + "./mlag/my-role"); + if (!strcmp(role, "primary")) { nb_cli_enqueue_change(vty, mlag_my_role_xpath, NB_OP_MODIFY, "MLAG_ROLE_PRIMARY"); - - } else if (!strcmp(argv[idx]->arg, "secondary")) { + } else if (!strcmp(role, "secondary")) { nb_cli_enqueue_change(vty, mlag_my_role_xpath, NB_OP_MODIFY, "MLAG_ROLE_SECONDARY"); - } else { - vty_out(vty, "unknown MLAG role %s\n", argv[idx]->arg); - return CMD_WARNING; + vty_out(vty, "unknown MLAG role %s\n", role); + ret = CMD_WARNING; + goto done; } snprintf(mlag_peer_state_xpath, sizeof(mlag_peer_state_xpath), - FRR_PIM_VRF_XPATH, - "frr-pim:pimd", "pim", "default", "frr-routing:ipv4"); - strlcat(mlag_peer_state_xpath, "/mlag/peer-state", - sizeof(mlag_peer_state_xpath)); - - idx += 2; - if (!strcmp(argv[idx]->arg, "up")) { + "./mlag/peer-state"); + if (!strcmp(state, "up")) { nb_cli_enqueue_change(vty, mlag_peer_state_xpath, NB_OP_MODIFY, "true"); - - } else if (strcmp(argv[idx]->arg, "down")) { + } else if (strcmp(state, "down")) { nb_cli_enqueue_change(vty, mlag_peer_state_xpath, NB_OP_MODIFY, "false"); - } else { - vty_out(vty, "unknown MLAG state %s\n", argv[idx]->arg); - return CMD_WARNING; + vty_out(vty, "unknown MLAG state %s\n", state); + ret = CMD_WARNING; + goto done; } snprintf(mlag_reg_address_xpath, sizeof(mlag_reg_address_xpath), - FRR_PIM_VRF_XPATH, - "frr-pim:pimd", "pim", "default", "frr-routing:ipv4"); - strlcat(mlag_reg_address_xpath, "/mlag/reg-address", - sizeof(mlag_reg_address_xpath)); - - idx += 2; + "./mlag/reg-address"); nb_cli_enqueue_change(vty, mlag_reg_address_xpath, NB_OP_MODIFY, - argv[idx]->arg); + addr_str); - return nb_cli_apply_changes(vty, NULL); -} + ret = nb_cli_apply_changes(vty, NULL); -void pim_cmd_init(void) -{ - if_cmd_init(pim_interface_config_write); +done: + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } - install_node(&debug_node); + return ret; +} - install_element(ENABLE_NODE, &pim_test_sg_keepalive_cmd); +struct cmd_node pim_node = { + .name = "pim", + .node = PIM_NODE, + .parent_node = CONFIG_NODE, + .prompt = "%s(config-pim)# ", + .config_write = pim_router_config_write, +}; +/* This function installs all of the deprecated PIM configuration commands that live in the global config and/or VRF nodes + * This configuration has been moved to the new 'router pim' config node instead like all the other routing protocols. + * No new commands should be added here. + */ +static void pim_install_deprecated(void) +{ install_element(CONFIG_NODE, &ip_pim_rp_cmd); install_element(VRF_NODE, &ip_pim_rp_cmd); install_element(CONFIG_NODE, &no_ip_pim_rp_cmd); @@ -6449,8 +8155,8 @@ void pim_cmd_init(void) install_element(CONFIG_NODE, &no_ip_pim_spt_switchover_infinity_plist_cmd); install_element(VRF_NODE, &no_ip_pim_spt_switchover_infinity_plist_cmd); - install_element(CONFIG_NODE, &pim_register_accept_list_cmd); - install_element(VRF_NODE, &pim_register_accept_list_cmd); + install_element(CONFIG_NODE, &ip_pim_register_accept_list_cmd); + install_element(VRF_NODE, &ip_pim_register_accept_list_cmd); install_element(CONFIG_NODE, &ip_pim_joinprune_time_cmd); install_element(CONFIG_NODE, &no_ip_pim_joinprune_time_cmd); install_element(CONFIG_NODE, &ip_pim_keep_alive_cmd); @@ -6467,14 +8173,6 @@ void pim_cmd_init(void) install_element(VRF_NODE, &ip_pim_v6_secondary_cmd); install_element(CONFIG_NODE, &no_ip_pim_v6_secondary_cmd); install_element(VRF_NODE, &no_ip_pim_v6_secondary_cmd); - install_element(CONFIG_NODE, &ip_ssmpingd_cmd); - install_element(VRF_NODE, &ip_ssmpingd_cmd); - install_element(CONFIG_NODE, &no_ip_ssmpingd_cmd); - install_element(VRF_NODE, &no_ip_ssmpingd_cmd); - install_element(CONFIG_NODE, &ip_msdp_peer_cmd); - install_element(VRF_NODE, &ip_msdp_peer_cmd); - install_element(CONFIG_NODE, &no_ip_msdp_peer_cmd); - install_element(VRF_NODE, &no_ip_msdp_peer_cmd); install_element(CONFIG_NODE, &ip_pim_ecmp_cmd); install_element(VRF_NODE, &ip_pim_ecmp_cmd); install_element(CONFIG_NODE, &no_ip_pim_ecmp_cmd); @@ -6485,10 +8183,87 @@ void pim_cmd_init(void) install_element(VRF_NODE, &no_ip_pim_ecmp_rebalance_cmd); install_element(CONFIG_NODE, &ip_pim_mlag_cmd); install_element(CONFIG_NODE, &no_ip_pim_mlag_cmd); - install_element(CONFIG_NODE, &ip_igmp_group_watermark_cmd); - install_element(VRF_NODE, &ip_igmp_group_watermark_cmd); - install_element(CONFIG_NODE, &no_ip_igmp_group_watermark_cmd); - install_element(VRF_NODE, &no_ip_igmp_group_watermark_cmd); + + install_element(CONFIG_NODE, &ip_ssmpingd_cmd); + install_element(VRF_NODE, &ip_ssmpingd_cmd); + install_element(CONFIG_NODE, &no_ip_ssmpingd_cmd); + install_element(VRF_NODE, &no_ip_ssmpingd_cmd); + + install_element(CONFIG_NODE, &ip_msdp_peer_cmd); + install_element(VRF_NODE, &ip_msdp_peer_cmd); + install_element(CONFIG_NODE, &no_ip_msdp_peer_cmd); + install_element(VRF_NODE, &no_ip_msdp_peer_cmd); + install_element(CONFIG_NODE, &ip_msdp_timers_cmd); + install_element(VRF_NODE, &ip_msdp_timers_cmd); + install_element(CONFIG_NODE, &no_ip_msdp_timers_cmd); + install_element(VRF_NODE, &no_ip_msdp_timers_cmd); + install_element(CONFIG_NODE, &ip_msdp_mesh_group_member_cmd); + install_element(VRF_NODE, &ip_msdp_mesh_group_member_cmd); + install_element(CONFIG_NODE, &no_ip_msdp_mesh_group_member_cmd); + install_element(VRF_NODE, &no_ip_msdp_mesh_group_member_cmd); + install_element(CONFIG_NODE, &ip_msdp_mesh_group_source_cmd); + install_element(VRF_NODE, &ip_msdp_mesh_group_source_cmd); + install_element(CONFIG_NODE, &no_ip_msdp_mesh_group_source_cmd); + install_element(VRF_NODE, &no_ip_msdp_mesh_group_source_cmd); + install_element(CONFIG_NODE, &no_ip_msdp_mesh_group_cmd); + install_element(VRF_NODE, &no_ip_msdp_mesh_group_cmd); +} + +void pim_cmd_init(void) +{ + if_cmd_init(pim_interface_config_write); + + install_node(&debug_node); + + install_element(CONFIG_NODE, &router_pim_cmd); + install_element(CONFIG_NODE, &no_router_pim_cmd); + + install_node(&pim_node); + install_default(PIM_NODE); + + install_element(PIM_NODE, &pim_rp_cmd); + install_element(PIM_NODE, &no_pim_rp_cmd); + install_element(PIM_NODE, &pim_rp_prefix_list_cmd); + install_element(PIM_NODE, &no_pim_rp_prefix_list_cmd); + install_element(PIM_NODE, &no_pim_ssm_prefix_list_cmd); + install_element(PIM_NODE, &no_pim_ssm_prefix_list_name_cmd); + install_element(PIM_NODE, &pim_ssm_prefix_list_cmd); + install_element(PIM_NODE, &pim_register_suppress_cmd); + install_element(PIM_NODE, &no_pim_register_suppress_cmd); + install_element(PIM_NODE, &pim_spt_switchover_infinity_cmd); + install_element(PIM_NODE, &pim_spt_switchover_infinity_plist_cmd); + install_element(PIM_NODE, &no_pim_spt_switchover_infinity_cmd); + install_element(PIM_NODE, &no_pim_spt_switchover_infinity_plist_cmd); + install_element(PIM_NODE, &pim_register_accept_list_cmd); + install_element(PIM_NODE, &pim_joinprune_time_cmd); + install_element(PIM_NODE, &no_pim_joinprune_time_cmd); + install_element(PIM_NODE, &pim_keep_alive_cmd); + install_element(PIM_NODE, &pim_rp_keep_alive_cmd); + install_element(PIM_NODE, &no_pim_keep_alive_cmd); + install_element(PIM_NODE, &no_pim_rp_keep_alive_cmd); + install_element(PIM_NODE, &pim_packets_cmd); + install_element(PIM_NODE, &no_pim_packets_cmd); + install_element(PIM_NODE, &pim_v6_secondary_cmd); + install_element(PIM_NODE, &no_pim_v6_secondary_cmd); + install_element(PIM_NODE, &pim_ecmp_cmd); + install_element(PIM_NODE, &no_pim_ecmp_cmd); + install_element(PIM_NODE, &pim_ecmp_rebalance_cmd); + install_element(PIM_NODE, &no_pim_ecmp_rebalance_cmd); + install_element(PIM_NODE, &pim_mlag_cmd); + install_element(PIM_NODE, &no_pim_mlag_cmd); + + install_element(PIM_NODE, &pim_ssmpingd_cmd); + install_element(PIM_NODE, &no_pim_ssmpingd_cmd); + + install_element(PIM_NODE, &pim_msdp_peer_cmd); + install_element(PIM_NODE, &no_pim_msdp_peer_cmd); + install_element(PIM_NODE, &pim_msdp_timers_cmd); + install_element(PIM_NODE, &no_pim_msdp_timers_cmd); + install_element(PIM_NODE, &pim_msdp_mesh_group_member_cmd); + install_element(PIM_NODE, &no_pim_msdp_mesh_group_member_cmd); + install_element(PIM_NODE, &pim_msdp_mesh_group_source_cmd); + install_element(PIM_NODE, &no_pim_msdp_mesh_group_source_cmd); + install_element(PIM_NODE, &no_pim_msdp_mesh_group_cmd); install_element(INTERFACE_NODE, &interface_ip_igmp_cmd); install_element(INTERFACE_NODE, &interface_no_ip_igmp_cmd); @@ -6534,6 +8309,22 @@ void pim_cmd_init(void) install_element(INTERFACE_NODE, &interface_ip_mroute_cmd); install_element(INTERFACE_NODE, &interface_no_ip_mroute_cmd); + install_element(INTERFACE_NODE, &interface_pim_use_source_cmd); + install_element(INTERFACE_NODE, &interface_no_pim_use_source_cmd); + /* Install BSM command */ + install_element(INTERFACE_NODE, &ip_pim_bsm_cmd); + install_element(INTERFACE_NODE, &no_ip_pim_bsm_cmd); + install_element(INTERFACE_NODE, &ip_pim_ucast_bsm_cmd); + install_element(INTERFACE_NODE, &no_ip_pim_ucast_bsm_cmd); + /* Install BFD command */ + install_element(INTERFACE_NODE, &ip_pim_bfd_cmd); + install_element(INTERFACE_NODE, &ip_pim_bfd_param_cmd); + install_element(INTERFACE_NODE, &no_ip_pim_bfd_profile_cmd); + install_element(INTERFACE_NODE, &no_ip_pim_bfd_cmd); +#if HAVE_BFDD == 0 + install_element(INTERFACE_NODE, &no_ip_pim_bfd_param_cmd); +#endif /* !HAVE_BFDD */ + install_element(VIEW_NODE, &show_ip_igmp_interface_cmd); install_element(VIEW_NODE, &show_ip_igmp_interface_vrf_all_cmd); install_element(VIEW_NODE, &show_ip_igmp_join_cmd); @@ -6590,6 +8381,20 @@ void pim_cmd_init(void) install_element(VIEW_NODE, &show_ip_pim_bsrp_cmd); install_element(VIEW_NODE, &show_ip_pim_bsm_db_cmd); install_element(VIEW_NODE, &show_ip_pim_statistics_cmd); + install_element(VIEW_NODE, &show_ip_msdp_peer_detail_cmd); + install_element(VIEW_NODE, &show_ip_msdp_peer_detail_vrf_all_cmd); + install_element(VIEW_NODE, &show_ip_msdp_sa_detail_cmd); + install_element(VIEW_NODE, &show_ip_msdp_sa_detail_vrf_all_cmd); + install_element(VIEW_NODE, &show_ip_msdp_sa_sg_cmd); + install_element(VIEW_NODE, &show_ip_msdp_sa_sg_vrf_all_cmd); + install_element(VIEW_NODE, &show_ip_msdp_mesh_group_cmd); + install_element(VIEW_NODE, &show_ip_msdp_mesh_group_vrf_all_cmd); + install_element(VIEW_NODE, &show_ip_pim_ssm_range_cmd); + install_element(VIEW_NODE, &show_ip_pim_group_type_cmd); + install_element(VIEW_NODE, &show_ip_pim_vxlan_sg_cmd); + install_element(VIEW_NODE, &show_ip_pim_vxlan_sg_work_cmd); + + install_element(ENABLE_NODE, &pim_test_sg_keepalive_cmd); install_element(ENABLE_NODE, &clear_ip_mroute_count_cmd); install_element(ENABLE_NODE, &clear_ip_interfaces_cmd); @@ -6604,134 +8409,98 @@ void pim_cmd_init(void) install_element(ENABLE_NODE, &show_debugging_pim_cmd); install_element(ENABLE_NODE, &debug_igmp_cmd); - install_element(ENABLE_NODE, &no_debug_igmp_cmd); - install_element(ENABLE_NODE, &debug_igmp_events_cmd); - install_element(ENABLE_NODE, &no_debug_igmp_events_cmd); - install_element(ENABLE_NODE, &debug_igmp_packets_cmd); - install_element(ENABLE_NODE, &no_debug_igmp_packets_cmd); - install_element(ENABLE_NODE, &debug_igmp_trace_cmd); - install_element(ENABLE_NODE, &no_debug_igmp_trace_cmd); - install_element(ENABLE_NODE, &debug_igmp_trace_detail_cmd); - install_element(ENABLE_NODE, &no_debug_igmp_trace_detail_cmd); - install_element(ENABLE_NODE, &debug_mroute_cmd); - install_element(ENABLE_NODE, &debug_mroute_detail_cmd); - install_element(ENABLE_NODE, &no_debug_mroute_cmd); - install_element(ENABLE_NODE, &no_debug_mroute_detail_cmd); - install_element(ENABLE_NODE, &debug_pim_static_cmd); - install_element(ENABLE_NODE, &no_debug_pim_static_cmd); - install_element(ENABLE_NODE, &debug_pim_cmd); - install_element(ENABLE_NODE, &debug_pim_nht_cmd); - install_element(ENABLE_NODE, &debug_pim_nht_det_cmd); - install_element(ENABLE_NODE, &debug_pim_nht_rp_cmd); - install_element(ENABLE_NODE, &no_debug_pim_nht_rp_cmd); - install_element(ENABLE_NODE, &debug_pim_events_cmd); - install_element(ENABLE_NODE, &debug_pim_packets_cmd); - install_element(ENABLE_NODE, &debug_pim_packetdump_send_cmd); - install_element(ENABLE_NODE, &debug_pim_packetdump_recv_cmd); - install_element(ENABLE_NODE, &debug_pim_trace_cmd); - install_element(ENABLE_NODE, &debug_pim_trace_detail_cmd); - install_element(ENABLE_NODE, &debug_ssmpingd_cmd); - install_element(ENABLE_NODE, &no_debug_ssmpingd_cmd); - install_element(ENABLE_NODE, &debug_pim_zebra_cmd); - install_element(ENABLE_NODE, &debug_pim_mlag_cmd); - install_element(ENABLE_NODE, &no_debug_pim_mlag_cmd); - install_element(ENABLE_NODE, &debug_pim_vxlan_cmd); - install_element(ENABLE_NODE, &no_debug_pim_vxlan_cmd); - install_element(ENABLE_NODE, &debug_msdp_cmd); - install_element(ENABLE_NODE, &no_debug_msdp_cmd); - install_element(ENABLE_NODE, &debug_msdp_events_cmd); - install_element(ENABLE_NODE, &no_debug_msdp_events_cmd); - install_element(ENABLE_NODE, &debug_msdp_packets_cmd); - install_element(ENABLE_NODE, &no_debug_msdp_packets_cmd); - install_element(ENABLE_NODE, &debug_mtrace_cmd); - install_element(ENABLE_NODE, &no_debug_mtrace_cmd); - install_element(ENABLE_NODE, &debug_bsm_cmd); - install_element(ENABLE_NODE, &no_debug_bsm_cmd); - install_element(CONFIG_NODE, &debug_igmp_cmd); + install_element(ENABLE_NODE, &no_debug_igmp_cmd); install_element(CONFIG_NODE, &no_debug_igmp_cmd); + install_element(ENABLE_NODE, &debug_igmp_events_cmd); install_element(CONFIG_NODE, &debug_igmp_events_cmd); + install_element(ENABLE_NODE, &no_debug_igmp_events_cmd); install_element(CONFIG_NODE, &no_debug_igmp_events_cmd); + install_element(ENABLE_NODE, &debug_igmp_packets_cmd); install_element(CONFIG_NODE, &debug_igmp_packets_cmd); + install_element(ENABLE_NODE, &no_debug_igmp_packets_cmd); install_element(CONFIG_NODE, &no_debug_igmp_packets_cmd); + install_element(ENABLE_NODE, &debug_igmp_trace_cmd); install_element(CONFIG_NODE, &debug_igmp_trace_cmd); + install_element(ENABLE_NODE, &no_debug_igmp_trace_cmd); install_element(CONFIG_NODE, &no_debug_igmp_trace_cmd); + install_element(ENABLE_NODE, &debug_igmp_trace_detail_cmd); install_element(CONFIG_NODE, &debug_igmp_trace_detail_cmd); + install_element(ENABLE_NODE, &no_debug_igmp_trace_detail_cmd); install_element(CONFIG_NODE, &no_debug_igmp_trace_detail_cmd); + install_element(ENABLE_NODE, &debug_mroute_cmd); install_element(CONFIG_NODE, &debug_mroute_cmd); + install_element(ENABLE_NODE, &debug_mroute_detail_cmd); install_element(CONFIG_NODE, &debug_mroute_detail_cmd); + install_element(ENABLE_NODE, &no_debug_mroute_cmd); install_element(CONFIG_NODE, &no_debug_mroute_cmd); + install_element(ENABLE_NODE, &no_debug_mroute_detail_cmd); install_element(CONFIG_NODE, &no_debug_mroute_detail_cmd); + install_element(ENABLE_NODE, &debug_pim_static_cmd); install_element(CONFIG_NODE, &debug_pim_static_cmd); + install_element(ENABLE_NODE, &no_debug_pim_static_cmd); install_element(CONFIG_NODE, &no_debug_pim_static_cmd); + install_element(ENABLE_NODE, &debug_pim_cmd); install_element(CONFIG_NODE, &debug_pim_cmd); + install_element(ENABLE_NODE, &debug_pim_nht_cmd); install_element(CONFIG_NODE, &debug_pim_nht_cmd); + install_element(ENABLE_NODE, &debug_pim_nht_det_cmd); install_element(CONFIG_NODE, &debug_pim_nht_det_cmd); + install_element(ENABLE_NODE, &debug_pim_nht_rp_cmd); install_element(CONFIG_NODE, &debug_pim_nht_rp_cmd); + install_element(ENABLE_NODE, &no_debug_pim_nht_rp_cmd); install_element(CONFIG_NODE, &no_debug_pim_nht_rp_cmd); + install_element(ENABLE_NODE, &debug_pim_events_cmd); install_element(CONFIG_NODE, &debug_pim_events_cmd); + install_element(ENABLE_NODE, &debug_pim_packets_cmd); install_element(CONFIG_NODE, &debug_pim_packets_cmd); + install_element(ENABLE_NODE, &debug_pim_packetdump_send_cmd); install_element(CONFIG_NODE, &debug_pim_packetdump_send_cmd); + install_element(ENABLE_NODE, &debug_pim_packetdump_recv_cmd); install_element(CONFIG_NODE, &debug_pim_packetdump_recv_cmd); + install_element(ENABLE_NODE, &debug_pim_trace_cmd); install_element(CONFIG_NODE, &debug_pim_trace_cmd); + install_element(ENABLE_NODE, &debug_pim_trace_detail_cmd); install_element(CONFIG_NODE, &debug_pim_trace_detail_cmd); + install_element(ENABLE_NODE, &debug_ssmpingd_cmd); install_element(CONFIG_NODE, &debug_ssmpingd_cmd); + install_element(ENABLE_NODE, &no_debug_ssmpingd_cmd); install_element(CONFIG_NODE, &no_debug_ssmpingd_cmd); + install_element(ENABLE_NODE, &debug_pim_zebra_cmd); install_element(CONFIG_NODE, &debug_pim_zebra_cmd); + install_element(ENABLE_NODE, &debug_pim_mlag_cmd); install_element(CONFIG_NODE, &debug_pim_mlag_cmd); + install_element(ENABLE_NODE, &no_debug_pim_mlag_cmd); install_element(CONFIG_NODE, &no_debug_pim_mlag_cmd); + install_element(ENABLE_NODE, &debug_pim_vxlan_cmd); install_element(CONFIG_NODE, &debug_pim_vxlan_cmd); + install_element(ENABLE_NODE, &no_debug_pim_vxlan_cmd); install_element(CONFIG_NODE, &no_debug_pim_vxlan_cmd); + install_element(ENABLE_NODE, &debug_msdp_cmd); install_element(CONFIG_NODE, &debug_msdp_cmd); + install_element(ENABLE_NODE, &no_debug_msdp_cmd); install_element(CONFIG_NODE, &no_debug_msdp_cmd); + install_element(ENABLE_NODE, &debug_msdp_events_cmd); install_element(CONFIG_NODE, &debug_msdp_events_cmd); + install_element(ENABLE_NODE, &no_debug_msdp_events_cmd); install_element(CONFIG_NODE, &no_debug_msdp_events_cmd); + install_element(ENABLE_NODE, &debug_msdp_packets_cmd); install_element(CONFIG_NODE, &debug_msdp_packets_cmd); + install_element(ENABLE_NODE, &no_debug_msdp_packets_cmd); install_element(CONFIG_NODE, &no_debug_msdp_packets_cmd); + install_element(ENABLE_NODE, &debug_mtrace_cmd); install_element(CONFIG_NODE, &debug_mtrace_cmd); + install_element(ENABLE_NODE, &no_debug_mtrace_cmd); install_element(CONFIG_NODE, &no_debug_mtrace_cmd); + install_element(ENABLE_NODE, &debug_bsm_cmd); install_element(CONFIG_NODE, &debug_bsm_cmd); + install_element(ENABLE_NODE, &no_debug_bsm_cmd); install_element(CONFIG_NODE, &no_debug_bsm_cmd); - install_element(CONFIG_NODE, &ip_msdp_timers_cmd); - install_element(VRF_NODE, &ip_msdp_timers_cmd); - install_element(CONFIG_NODE, &no_ip_msdp_timers_cmd); - install_element(VRF_NODE, &no_ip_msdp_timers_cmd); - install_element(CONFIG_NODE, &ip_msdp_mesh_group_member_cmd); - install_element(VRF_NODE, &ip_msdp_mesh_group_member_cmd); - install_element(CONFIG_NODE, &no_ip_msdp_mesh_group_member_cmd); - install_element(VRF_NODE, &no_ip_msdp_mesh_group_member_cmd); - install_element(CONFIG_NODE, &ip_msdp_mesh_group_source_cmd); - install_element(VRF_NODE, &ip_msdp_mesh_group_source_cmd); - install_element(CONFIG_NODE, &no_ip_msdp_mesh_group_source_cmd); - install_element(VRF_NODE, &no_ip_msdp_mesh_group_source_cmd); - install_element(CONFIG_NODE, &no_ip_msdp_mesh_group_cmd); - install_element(VRF_NODE, &no_ip_msdp_mesh_group_cmd); - install_element(VIEW_NODE, &show_ip_msdp_peer_detail_cmd); - install_element(VIEW_NODE, &show_ip_msdp_peer_detail_vrf_all_cmd); - install_element(VIEW_NODE, &show_ip_msdp_sa_detail_cmd); - install_element(VIEW_NODE, &show_ip_msdp_sa_detail_vrf_all_cmd); - install_element(VIEW_NODE, &show_ip_msdp_sa_sg_cmd); - install_element(VIEW_NODE, &show_ip_msdp_sa_sg_vrf_all_cmd); - install_element(VIEW_NODE, &show_ip_msdp_mesh_group_cmd); - install_element(VIEW_NODE, &show_ip_msdp_mesh_group_vrf_all_cmd); - install_element(VIEW_NODE, &show_ip_pim_ssm_range_cmd); - install_element(VIEW_NODE, &show_ip_pim_group_type_cmd); - install_element(VIEW_NODE, &show_ip_pim_vxlan_sg_cmd); - install_element(VIEW_NODE, &show_ip_pim_vxlan_sg_work_cmd); - install_element(INTERFACE_NODE, &interface_pim_use_source_cmd); - install_element(INTERFACE_NODE, &interface_no_pim_use_source_cmd); - /* Install BSM command */ - install_element(INTERFACE_NODE, &ip_pim_bsm_cmd); - install_element(INTERFACE_NODE, &no_ip_pim_bsm_cmd); - install_element(INTERFACE_NODE, &ip_pim_ucast_bsm_cmd); - install_element(INTERFACE_NODE, &no_ip_pim_ucast_bsm_cmd); - /* Install BFD command */ - install_element(INTERFACE_NODE, &ip_pim_bfd_cmd); - install_element(INTERFACE_NODE, &ip_pim_bfd_param_cmd); - install_element(INTERFACE_NODE, &no_ip_pim_bfd_profile_cmd); - install_element(INTERFACE_NODE, &no_ip_pim_bfd_cmd); -#if HAVE_BFDD == 0 - install_element(INTERFACE_NODE, &no_ip_pim_bfd_param_cmd); -#endif /* !HAVE_BFDD */ + install_element(CONFIG_NODE, &ip_igmp_group_watermark_cmd); + install_element(VRF_NODE, &ip_igmp_group_watermark_cmd); + install_element(CONFIG_NODE, &no_ip_igmp_group_watermark_cmd); + install_element(VRF_NODE, &no_ip_igmp_group_watermark_cmd); + + pim_install_deprecated(); } diff --git a/pimd/pim_cmd_common.c b/pimd/pim_cmd_common.c index 5e50a09355..c6cb28c097 100644 --- a/pimd/pim_cmd_common.c +++ b/pimd/pim_cmd_common.c @@ -100,25 +100,13 @@ int pim_process_no_join_prune_cmd(struct vty *vty) int pim_process_spt_switchover_infinity_cmd(struct vty *vty) { - const char *vrfname; char spt_plist_xpath[XPATH_MAXLEN]; char spt_action_xpath[XPATH_MAXLEN]; - vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) - return CMD_WARNING_CONFIG_FAILED; - snprintf(spt_plist_xpath, sizeof(spt_plist_xpath), - FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, - FRR_PIM_AF_XPATH_VAL); - strlcat(spt_plist_xpath, "/spt-switchover/spt-infinity-prefix-list", - sizeof(spt_plist_xpath)); - + "%s/spt-switchover/spt-infinity-prefix-list", VTY_CURR_XPATH); snprintf(spt_action_xpath, sizeof(spt_action_xpath), - FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, - FRR_PIM_AF_XPATH_VAL); - strlcat(spt_action_xpath, "/spt-switchover/spt-action", - sizeof(spt_action_xpath)); + "%s/spt-switchover/spt-action", VTY_CURR_XPATH); if (yang_dnode_exists(vty->candidate_config->dnode, spt_plist_xpath)) nb_cli_enqueue_change(vty, spt_plist_xpath, NB_OP_DESTROY, @@ -132,55 +120,30 @@ int pim_process_spt_switchover_infinity_cmd(struct vty *vty) int pim_process_spt_switchover_prefixlist_cmd(struct vty *vty, const char *plist) { - const char *vrfname; char spt_plist_xpath[XPATH_MAXLEN]; char spt_action_xpath[XPATH_MAXLEN]; - vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) - return CMD_WARNING_CONFIG_FAILED; - snprintf(spt_plist_xpath, sizeof(spt_plist_xpath), - FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, - FRR_PIM_AF_XPATH_VAL); - strlcat(spt_plist_xpath, "/spt-switchover/spt-infinity-prefix-list", - sizeof(spt_plist_xpath)); - + "./spt-switchover/spt-infinity-prefix-list"); snprintf(spt_action_xpath, sizeof(spt_action_xpath), - FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, - FRR_PIM_AF_XPATH_VAL); - strlcat(spt_action_xpath, "/spt-switchover/spt-action", - sizeof(spt_action_xpath)); + "./spt-switchover/spt-action"); nb_cli_enqueue_change(vty, spt_action_xpath, NB_OP_MODIFY, "PIM_SPT_INFINITY"); - nb_cli_enqueue_change(vty, spt_plist_xpath, NB_OP_MODIFY, - plist); + nb_cli_enqueue_change(vty, spt_plist_xpath, NB_OP_MODIFY, plist); return nb_cli_apply_changes(vty, NULL); } int pim_process_no_spt_switchover_cmd(struct vty *vty) { - const char *vrfname; char spt_plist_xpath[XPATH_MAXLEN]; char spt_action_xpath[XPATH_MAXLEN]; - vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) - return CMD_WARNING_CONFIG_FAILED; - snprintf(spt_plist_xpath, sizeof(spt_plist_xpath), - FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, - FRR_PIM_AF_XPATH_VAL); - strlcat(spt_plist_xpath, "/spt-switchover/spt-infinity-prefix-list", - sizeof(spt_plist_xpath)); - + "./spt-switchover/spt-infinity-prefix-list"); snprintf(spt_action_xpath, sizeof(spt_action_xpath), - FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, - FRR_PIM_AF_XPATH_VAL); - strlcat(spt_action_xpath, "/spt-switchover/spt-action", - sizeof(spt_action_xpath)); + "./spt-switchover/spt-action"); nb_cli_enqueue_change(vty, spt_plist_xpath, NB_OP_DESTROY, NULL); nb_cli_enqueue_change(vty, spt_action_xpath, NB_OP_MODIFY, @@ -217,35 +180,20 @@ int pim_process_no_pim_packet_cmd(struct vty *vty) int pim_process_keepalivetimer_cmd(struct vty *vty, const char *kat) { - const char *vrfname; char ka_timer_xpath[XPATH_MAXLEN]; - vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) - return CMD_WARNING_CONFIG_FAILED; - - snprintf(ka_timer_xpath, sizeof(ka_timer_xpath), FRR_PIM_VRF_XPATH, - "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); - strlcat(ka_timer_xpath, "/keep-alive-timer", sizeof(ka_timer_xpath)); + snprintf(ka_timer_xpath, sizeof(ka_timer_xpath), "./keep-alive-timer"); - nb_cli_enqueue_change(vty, ka_timer_xpath, NB_OP_MODIFY, - kat); + nb_cli_enqueue_change(vty, ka_timer_xpath, NB_OP_MODIFY, kat); return nb_cli_apply_changes(vty, NULL); } int pim_process_no_keepalivetimer_cmd(struct vty *vty) { - const char *vrfname; char ka_timer_xpath[XPATH_MAXLEN]; - vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) - return CMD_WARNING_CONFIG_FAILED; - - snprintf(ka_timer_xpath, sizeof(ka_timer_xpath), FRR_PIM_VRF_XPATH, - "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); - strlcat(ka_timer_xpath, "/keep-alive-timer", sizeof(ka_timer_xpath)); + snprintf(ka_timer_xpath, sizeof(ka_timer_xpath), "./keep-alive-timer"); nb_cli_enqueue_change(vty, ka_timer_xpath, NB_OP_DESTROY, NULL); @@ -254,35 +202,25 @@ int pim_process_no_keepalivetimer_cmd(struct vty *vty) int pim_process_rp_kat_cmd(struct vty *vty, const char *rpkat) { - const char *vrfname; char rp_ka_timer_xpath[XPATH_MAXLEN]; - vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) - return CMD_WARNING_CONFIG_FAILED; - snprintf(rp_ka_timer_xpath, sizeof(rp_ka_timer_xpath), - FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, - FRR_PIM_AF_XPATH_VAL); - strlcat(rp_ka_timer_xpath, "/rp-keep-alive-timer", - sizeof(rp_ka_timer_xpath)); + "./rp-keep-alive-timer"); - nb_cli_enqueue_change(vty, rp_ka_timer_xpath, NB_OP_MODIFY, - rpkat); + nb_cli_enqueue_change(vty, rp_ka_timer_xpath, NB_OP_MODIFY, rpkat); return nb_cli_apply_changes(vty, NULL); } int pim_process_no_rp_kat_cmd(struct vty *vty) { - const char *vrfname; char rp_ka_timer[6]; char rp_ka_timer_xpath[XPATH_MAXLEN]; uint v; char rs_timer_xpath[XPATH_MAXLEN]; - snprintf(rs_timer_xpath, sizeof(rs_timer_xpath), - FRR_PIM_ROUTER_XPATH, FRR_PIM_AF_XPATH_VAL); + snprintf(rs_timer_xpath, sizeof(rs_timer_xpath), FRR_PIM_ROUTER_XPATH, + FRR_PIM_AF_XPATH_VAL); strlcat(rs_timer_xpath, "/register-suppress-time", sizeof(rs_timer_xpath)); @@ -301,18 +239,10 @@ int pim_process_no_rp_kat_cmd(struct vty *vty) v = UINT16_MAX; snprintf(rp_ka_timer, sizeof(rp_ka_timer), "%u", v); - vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) - return CMD_WARNING_CONFIG_FAILED; - snprintf(rp_ka_timer_xpath, sizeof(rp_ka_timer_xpath), - FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, - FRR_PIM_AF_XPATH_VAL); - strlcat(rp_ka_timer_xpath, "/rp-keep-alive-timer", - sizeof(rp_ka_timer_xpath)); + "./rp-keep-alive-timer"); - nb_cli_enqueue_change(vty, rp_ka_timer_xpath, NB_OP_MODIFY, - rp_ka_timer); + nb_cli_enqueue_change(vty, rp_ka_timer_xpath, NB_OP_MODIFY, rp_ka_timer); return nb_cli_apply_changes(vty, NULL); } @@ -531,9 +461,7 @@ int pim_process_no_ip_mroute_cmd(struct vty *vty, const char *interface, int pim_process_rp_cmd(struct vty *vty, const char *rp_str, const char *group_str) { - const char *vrfname; char group_xpath[XPATH_MAXLEN]; - char rp_xpath[XPATH_MAXLEN]; int printed; int result = 0; struct prefix group; @@ -575,14 +503,9 @@ int pim_process_rp_cmd(struct vty *vty, const char *rp_str, } #endif - vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) - return CMD_WARNING_CONFIG_FAILED; - - snprintf(rp_xpath, sizeof(rp_xpath), FRR_PIM_STATIC_RP_XPATH, - "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL, rp_str); printed = snprintf(group_xpath, sizeof(group_xpath), - "%s/group-list[.='%s']", rp_xpath, group_str); + "./" FRR_PIM_STATIC_RP_XPATH "/group-list[.='%s']", + rp_str, group_str); if (printed >= (int)(sizeof(group_xpath))) { vty_out(vty, "Xpath too long (%d > %u)", printed + 1, @@ -601,15 +524,10 @@ int pim_process_no_rp_cmd(struct vty *vty, const char *rp_str, char group_xpath[XPATH_MAXLEN]; char rp_xpath[XPATH_MAXLEN]; int printed; - const char *vrfname; const struct lyd_node *group_dnode; - vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) - return CMD_WARNING_CONFIG_FAILED; - - snprintf(rp_xpath, sizeof(rp_xpath), FRR_PIM_STATIC_RP_XPATH, - "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL, rp_str); + snprintf(rp_xpath, sizeof(rp_xpath), "%s/" FRR_PIM_STATIC_RP_XPATH, + VTY_CURR_XPATH, rp_str); printed = snprintf(group_xpath, sizeof(group_xpath), "%s/group-list[.='%s']", rp_xpath, group_str); @@ -636,16 +554,10 @@ int pim_process_no_rp_cmd(struct vty *vty, const char *rp_str, int pim_process_rp_plist_cmd(struct vty *vty, const char *rp_str, const char *prefix_list) { - const char *vrfname; char rp_plist_xpath[XPATH_MAXLEN]; - vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) - return CMD_WARNING_CONFIG_FAILED; - snprintf(rp_plist_xpath, sizeof(rp_plist_xpath), - FRR_PIM_STATIC_RP_XPATH, "frr-pim:pimd", "pim", vrfname, - FRR_PIM_AF_XPATH_VAL, rp_str); + "./" FRR_PIM_STATIC_RP_XPATH, rp_str); strlcat(rp_plist_xpath, "/prefix-list", sizeof(rp_plist_xpath)); nb_cli_enqueue_change(vty, rp_plist_xpath, NB_OP_MODIFY, prefix_list); @@ -658,19 +570,12 @@ int pim_process_no_rp_plist_cmd(struct vty *vty, const char *rp_str, { char rp_xpath[XPATH_MAXLEN]; char plist_xpath[XPATH_MAXLEN]; - const char *vrfname; const struct lyd_node *plist_dnode; const char *plist; - vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) - return CMD_WARNING_CONFIG_FAILED; - - snprintf(rp_xpath, sizeof(rp_xpath), FRR_PIM_STATIC_RP_XPATH, - "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL, rp_str); - - snprintf(plist_xpath, sizeof(plist_xpath), FRR_PIM_STATIC_RP_XPATH, - "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL, rp_str); + snprintf(rp_xpath, sizeof(rp_xpath), "%s/" FRR_PIM_STATIC_RP_XPATH, + VTY_CURR_XPATH, rp_str); + snprintf(plist_xpath, sizeof(plist_xpath), "%s", rp_xpath); strlcat(plist_xpath, "/prefix-list", sizeof(plist_xpath)); plist_dnode = yang_dnode_get(vty->candidate_config->dnode, plist_xpath); @@ -679,7 +584,7 @@ int pim_process_no_rp_plist_cmd(struct vty *vty, const char *rp_str, return NB_OK; } - plist = yang_dnode_get_string(plist_dnode, "%s", plist_xpath); + plist = yang_dnode_get_string(plist_dnode, NULL); if (strcmp(prefix_list, plist)) { vty_out(vty, "%% Unable to find specified RP\n"); return NB_OK; @@ -3408,21 +3313,11 @@ int gm_process_no_last_member_query_interval_cmd(struct vty *vty) int pim_process_ssmpingd_cmd(struct vty *vty, enum nb_operation operation, const char *src_str) { - const char *vrfname; - char ssmpingd_ip_xpath[XPATH_MAXLEN]; char ssmpingd_src_ip_xpath[XPATH_MAXLEN]; int printed; - vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) - return CMD_WARNING_CONFIG_FAILED; - - snprintf(ssmpingd_ip_xpath, sizeof(ssmpingd_ip_xpath), - FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, - FRR_PIM_AF_XPATH_VAL); printed = snprintf(ssmpingd_src_ip_xpath, sizeof(ssmpingd_src_ip_xpath), - "%s/ssm-pingd-source-ip[.='%s']", ssmpingd_ip_xpath, - src_str); + "./ssm-pingd-source-ip[.='%s']", src_str); if (printed >= (int)sizeof(ssmpingd_src_ip_xpath)) { vty_out(vty, "Xpath too long (%d > %u)", printed + 1, XPATH_MAXLEN); @@ -5705,3 +5600,34 @@ int pim_show_bsm_db_helper(const char *vrf, struct vty *vty, bool uj) return CMD_SUCCESS; } + +int pim_router_config_write(struct vty *vty) +{ + struct vrf *vrf; + struct pim_instance *pim; + int writes = 0; + char framestr[64] = { 0 }; + + RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { + pim = vrf->info; + + if (!pim) + continue; + + snprintfrr(framestr, sizeof(framestr), "router %s", + PIM_AF_ROUTER); + if (vrf->vrf_id != VRF_DEFAULT) { + strlcat(framestr, " vrf ", sizeof(framestr)); + strlcat(framestr, vrf->name, sizeof(framestr)); + } + vty_frame(vty, "%s\n", framestr); + ++writes; + + writes += pim_global_config_write_worker(pim, vty); + + vty_endframe(vty, "exit\n"); + ++writes; + } + + return writes; +} diff --git a/pimd/pim_cmd_common.h b/pimd/pim_cmd_common.h index e30203fad7..da2e44be58 100644 --- a/pimd/pim_cmd_common.h +++ b/pimd/pim_cmd_common.h @@ -182,6 +182,8 @@ int pim_show_interface_traffic_helper(const char *vrf, const char *if_name, void clear_pim_interfaces(struct pim_instance *pim); void pim_show_bsr(struct pim_instance *pim, struct vty *vty, bool uj); int pim_show_bsr_helper(const char *vrf, struct vty *vty, bool uj); +int pim_router_config_write(struct vty *vty); + /* * Special Macro to allow us to get the correct pim_instance; */ diff --git a/pimd/pim_instance.c b/pimd/pim_instance.c index b3410d15af..a9eec9a9d2 100644 --- a/pimd/pim_instance.c +++ b/pimd/pim_instance.c @@ -201,6 +201,7 @@ static int pim_vrf_config_write(struct vty *vty) { struct vrf *vrf; struct pim_instance *pim; + char spaces[10]; RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { pim = vrf->info; @@ -208,10 +209,24 @@ static int pim_vrf_config_write(struct vty *vty) if (!pim) continue; - if (vrf->vrf_id != VRF_DEFAULT) + if (vrf->vrf_id != VRF_DEFAULT) { vty_frame(vty, "vrf %s\n", vrf->name); - - pim_global_config_write_worker(pim, vty); + snprintf(spaces, sizeof(spaces), "%s", " "); + } else { + snprintf(spaces, sizeof(spaces), "%s", ""); + } + + /* Global IGMP/MLD configuration */ + if (pim->gm_watermark_limit != 0) { +#if PIM_IPV == 4 + vty_out(vty, + "%s" PIM_AF_NAME " igmp watermark-warn %u\n", + spaces, pim->gm_watermark_limit); +#else + vty_out(vty, "%s" PIM_AF_NAME " mld watermark-warn %u\n", + spaces, pim->gm_watermark_limit); +#endif + } if (vrf->vrf_id != VRF_DEFAULT) vty_endframe(vty, "exit-vrf\n!\n"); diff --git a/pimd/pim_msdp.c b/pimd/pim_msdp.c index 623c14bb03..04b4d296dd 100644 --- a/pimd/pim_msdp.c +++ b/pimd/pim_msdp.c @@ -1276,8 +1276,7 @@ static void pim_msdp_src_del(struct pim_msdp_mg *mg) } /*********************** MSDP feature APIs *********************************/ -int pim_msdp_config_write(struct pim_instance *pim, struct vty *vty, - const char *spaces) +int pim_msdp_config_write(struct pim_instance *pim, struct vty *vty) { struct pim_msdp_mg *mg; struct listnode *mbrnode; @@ -1292,14 +1291,14 @@ int pim_msdp_config_write(struct pim_instance *pim, struct vty *vty, if (mg->src_ip.s_addr != INADDR_ANY) { pim_inet4_dump("", mg->src_ip, src_str, sizeof(src_str)); - vty_out(vty, "%sip msdp mesh-group %s source %s\n", - spaces, mg->mesh_group_name, src_str); + vty_out(vty, " msdp mesh-group %s source %s\n", + mg->mesh_group_name, src_str); ++count; } for (ALL_LIST_ELEMENTS_RO(mg->mbr_list, mbrnode, mbr)) { - vty_out(vty, "%sip msdp mesh-group %s member %pI4\n", - spaces, mg->mesh_group_name, &mbr->mbr_ip); + vty_out(vty, " msdp mesh-group %s member %pI4\n", + mg->mesh_group_name, &mbr->mbr_ip); ++count; } } @@ -1307,8 +1306,7 @@ int pim_msdp_config_write(struct pim_instance *pim, struct vty *vty, return count; } -bool pim_msdp_peer_config_write(struct vty *vty, struct pim_instance *pim, - const char *spaces) +bool pim_msdp_peer_config_write(struct vty *vty, struct pim_instance *pim) { struct pim_msdp_peer *mp; struct listnode *node; @@ -1319,8 +1317,8 @@ bool pim_msdp_peer_config_write(struct vty *vty, struct pim_instance *pim, if (mp->flags & PIM_MSDP_PEERF_IN_GROUP) continue; - vty_out(vty, "%sip msdp peer %pI4 source %pI4\n", spaces, - &mp->peer, &mp->local); + vty_out(vty, " msdp peer %pI4 source %pI4\n", &mp->peer, + &mp->local); written = true; } diff --git a/pimd/pim_msdp.h b/pimd/pim_msdp.h index ddc015f9b6..80ca003dc5 100644 --- a/pimd/pim_msdp.h +++ b/pimd/pim_msdp.h @@ -228,10 +228,8 @@ void pim_msdp_peer_pkt_rxed(struct pim_msdp_peer *mp); void pim_msdp_peer_stop_tcp_conn(struct pim_msdp_peer *mp, bool chg_state); void pim_msdp_peer_reset_tcp_conn(struct pim_msdp_peer *mp, const char *rc_str); void pim_msdp_write(struct event *thread); -int pim_msdp_config_write(struct pim_instance *pim, struct vty *vty, - const char *spaces); -bool pim_msdp_peer_config_write(struct vty *vty, struct pim_instance *pim, - const char *spaces); +int pim_msdp_config_write(struct pim_instance *pim, struct vty *vty); +bool pim_msdp_peer_config_write(struct vty *vty, struct pim_instance *pim); void pim_msdp_peer_pkt_txed(struct pim_msdp_peer *mp); void pim_msdp_sa_ref(struct pim_instance *pim, struct pim_msdp_peer *mp, pim_sgaddr *sg, struct in_addr rp); @@ -339,14 +337,13 @@ static inline void pim_msdp_sa_local_del(struct pim_instance *pim, } static inline int pim_msdp_config_write(struct pim_instance *pim, - struct vty *vty, const char *spaces) + struct vty *vty) { return 0; } static inline bool pim_msdp_peer_config_write(struct vty *vty, - struct pim_instance *pim, - const char *spaces) + struct pim_instance *pim) { return false; } diff --git a/pimd/pim_nb.h b/pimd/pim_nb.h index 0321d076f0..2d854d73de 100644 --- a/pimd/pim_nb.h +++ b/pimd/pim_nb.h @@ -207,9 +207,6 @@ int routing_control_plane_protocols_name_validate( "./frr-pim:pim/address-family[address-family='%s']/" \ "mroute[source-addr='%s'][group-addr='%s']" #define FRR_PIM_STATIC_RP_XPATH \ - "/frr-routing:routing/control-plane-protocols/" \ - "control-plane-protocol[type='%s'][name='%s'][vrf='%s']/" \ - "frr-pim:pim/address-family[address-family='%s']/" \ "frr-pim-rp:rp/static-rp/rp-list[rp-address='%s']" #define FRR_GMP_INTERFACE_XPATH \ "./frr-gmp:gmp/address-family[address-family='%s']" @@ -218,6 +215,5 @@ int routing_control_plane_protocols_name_validate( #define FRR_GMP_JOIN_XPATH \ "./frr-gmp:gmp/address-family[address-family='%s']/" \ "static-group[group-addr='%s'][source-addr='%s']" -#define FRR_PIM_MSDP_XPATH FRR_PIM_VRF_XPATH "/msdp" #endif /* _FRR_PIM_NB_H_ */ diff --git a/pimd/pim_rp.c b/pimd/pim_rp.c index 49be9c0a73..0f8940bb16 100644 --- a/pimd/pim_rp.c +++ b/pimd/pim_rp.c @@ -1129,8 +1129,7 @@ int pim_rp_set_upstream_addr(struct pim_instance *pim, pim_addr *up, return 1; } -int pim_rp_config_write(struct pim_instance *pim, struct vty *vty, - const char *spaces) +int pim_rp_config_write(struct pim_instance *pim, struct vty *vty) { struct listnode *node; struct rp_info *rp_info; @@ -1146,13 +1145,11 @@ int pim_rp_config_write(struct pim_instance *pim, struct vty *vty, rp_addr = rp_info->rp.rpf_addr; if (rp_info->plist) - vty_out(vty, - "%s" PIM_AF_NAME - " pim rp %pPA prefix-list %s\n", - spaces, &rp_addr, rp_info->plist); + vty_out(vty, " rp %pPA prefix-list %s\n", &rp_addr, + rp_info->plist); else - vty_out(vty, "%s" PIM_AF_NAME " pim rp %pPA %pFX\n", - spaces, &rp_addr, &rp_info->group); + vty_out(vty, " rp %pPA %pFX\n", &rp_addr, + &rp_info->group); count++; } diff --git a/pimd/pim_rp.h b/pimd/pim_rp.h index 9416a9a8a8..32c6306740 100644 --- a/pimd/pim_rp.h +++ b/pimd/pim_rp.h @@ -46,8 +46,7 @@ int pim_rp_change(struct pim_instance *pim, pim_addr new_rp_addr, void pim_rp_prefix_list_update(struct pim_instance *pim, struct prefix_list *plist); -int pim_rp_config_write(struct pim_instance *pim, struct vty *vty, - const char *spaces); +int pim_rp_config_write(struct pim_instance *pim, struct vty *vty); void pim_rp_setup(struct pim_instance *pim); diff --git a/pimd/pim_vty.c b/pimd/pim_vty.c index 0f6547ee2e..1910a68495 100644 --- a/pimd/pim_vty.c +++ b/pimd/pim_vty.c @@ -172,89 +172,66 @@ int pim_global_config_write_worker(struct pim_instance *pim, struct vty *vty) { int writes = 0; struct pim_ssm *ssm = pim->ssm_info; - char spaces[10]; - if (pim->vrf->vrf_id == VRF_DEFAULT) - snprintf(spaces, sizeof(spaces), "%s", ""); - else - snprintf(spaces, sizeof(spaces), "%s", " "); - - writes += pim_msdp_peer_config_write(vty, pim, spaces); - writes += pim_msdp_config_write(pim, vty, spaces); + writes += pim_msdp_peer_config_write(vty, pim); + writes += pim_msdp_config_write(pim, vty); if (!pim->send_v6_secondary) { - vty_out(vty, "%sno ip pim send-v6-secondary\n", spaces); + vty_out(vty, " no send-v6-secondary\n"); ++writes; } - writes += pim_rp_config_write(pim, vty, spaces); + writes += pim_rp_config_write(pim, vty); if (pim->vrf->vrf_id == VRF_DEFAULT) { if (router->register_suppress_time != PIM_REGISTER_SUPPRESSION_TIME_DEFAULT) { - vty_out(vty, "%s" PIM_AF_NAME " pim register-suppress-time %d\n", - spaces, router->register_suppress_time); + vty_out(vty, " register-suppress-time %d\n", + router->register_suppress_time); ++writes; } if (router->t_periodic != PIM_DEFAULT_T_PERIODIC) { - vty_out(vty, "%s" PIM_AF_NAME " pim join-prune-interval %d\n", - spaces, router->t_periodic); + vty_out(vty, " join-prune-interval %d\n", + router->t_periodic); ++writes; } if (router->packet_process != PIM_DEFAULT_PACKET_PROCESS) { - vty_out(vty, "%s" PIM_AF_NAME " pim packets %d\n", spaces, - router->packet_process); + vty_out(vty, " packets %d\n", router->packet_process); ++writes; } } if (pim->keep_alive_time != PIM_KEEPALIVE_PERIOD) { - vty_out(vty, "%s" PIM_AF_NAME " pim keep-alive-timer %d\n", - spaces, pim->keep_alive_time); + vty_out(vty, " keep-alive-timer %d\n", pim->keep_alive_time); ++writes; } if (pim->rp_keep_alive_time != (unsigned int)PIM_RP_KEEPALIVE_PERIOD) { - vty_out(vty, "%s" PIM_AF_NAME " pim rp keep-alive-timer %d\n", - spaces, pim->rp_keep_alive_time); + vty_out(vty, " rp keep-alive-timer %d\n", + pim->rp_keep_alive_time); ++writes; } if (ssm->plist_name) { - vty_out(vty, "%sip pim ssm prefix-list %s\n", spaces, - ssm->plist_name); + vty_out(vty, " ssm prefix-list %s\n", ssm->plist_name); ++writes; } if (pim->register_plist) { - vty_out(vty, "%sip pim register-accept-list %s\n", spaces, - pim->register_plist); + vty_out(vty, " register-accept-list %s\n", pim->register_plist); ++writes; } if (pim->spt.switchover == PIM_SPT_INFINITY) { if (pim->spt.plist) vty_out(vty, - "%s" PIM_AF_NAME " pim spt-switchover infinity-and-beyond prefix-list %s\n", - spaces, pim->spt.plist); + " spt-switchover infinity-and-beyond prefix-list %s\n", + pim->spt.plist); else - vty_out(vty, - "%s" PIM_AF_NAME " pim spt-switchover infinity-and-beyond\n", - spaces); + vty_out(vty, " spt-switchover infinity-and-beyond\n"); ++writes; } if (pim->ecmp_rebalance_enable) { - vty_out(vty, "%sip pim ecmp rebalance\n", spaces); + vty_out(vty, " ecmp rebalance\n"); ++writes; } else if (pim->ecmp_enable) { - vty_out(vty, "%sip pim ecmp\n", spaces); - ++writes; - } - - if (pim->gm_watermark_limit != 0) { -#if PIM_IPV == 4 - vty_out(vty, "%s" PIM_AF_NAME " igmp watermark-warn %u\n", - spaces, pim->gm_watermark_limit); -#else - vty_out(vty, "%s" PIM_AF_NAME " mld watermark-warn %u\n", - spaces, pim->gm_watermark_limit); -#endif + vty_out(vty, " ecmp\n"); ++writes; } @@ -263,8 +240,7 @@ int pim_global_config_write_worker(struct pim_instance *pim, struct vty *vty) struct ssmpingd_sock *ss; ++writes; for (ALL_LIST_ELEMENTS_RO(pim->ssmpingd_list, node, ss)) { - vty_out(vty, "%s" PIM_AF_NAME " ssmpingd %pPA\n", - spaces, &ss->source_addr); + vty_out(vty, " ssmpingd %pPA\n", &ss->source_addr); ++writes; } } @@ -272,8 +248,8 @@ int pim_global_config_write_worker(struct pim_instance *pim, struct vty *vty) if (pim->msdp.hold_time != PIM_MSDP_PEER_HOLD_TIME || pim->msdp.keep_alive != PIM_MSDP_PEER_KA_TIME || pim->msdp.connection_retry != PIM_MSDP_PEER_CONNECT_RETRY_TIME) { - vty_out(vty, "%sip msdp timers %u %u", spaces, - pim->msdp.hold_time, pim->msdp.keep_alive); + vty_out(vty, " msdp timers %u %u", pim->msdp.hold_time, + pim->msdp.keep_alive); if (pim->msdp.connection_retry != PIM_MSDP_PEER_CONNECT_RETRY_TIME) vty_out(vty, " %u", pim->msdp.connection_retry); diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index 573320667c..1f6dde83c1 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -1677,6 +1677,24 @@ static struct cmd_node bfd_profile_node = { }; #endif /* HAVE_BFDD */ +#ifdef HAVE_PIMD +static struct cmd_node pim_node = { + .name = "pim", + .node = PIM_NODE, + .parent_node = CONFIG_NODE, + .prompt = "%s(config-pim)# ", +}; +#endif /* HAVE_PIMD */ + +#ifdef HAVE_PIM6D +static struct cmd_node pim6_node = { + .name = "pim6", + .node = PIM6_NODE, + .parent_node = CONFIG_NODE, + .prompt = "%s(config-pim6)# ", +}; +#endif /* HAVE_PIM6D */ + /* Defined in lib/vty.c */ extern struct cmd_node vty_node; @@ -2413,6 +2431,30 @@ DEFUNSH(VTYSH_BFDD, bfd_profile_enter, bfd_profile_enter_cmd, } #endif /* HAVE_BFDD */ +#ifdef HAVE_PIMD +DEFUNSH(VTYSH_PIMD, router_pim, router_pim_cmd, + "router pim [vrf NAME]", + ROUTER_STR + "Start PIM configuration\n" + VRF_CMD_HELP_STR) +{ + vty->node = PIM_NODE; + return CMD_SUCCESS; +} +#endif /* HAVE_PIMD */ + +#ifdef HAVE_PIM6D +DEFUNSH(VTYSH_PIM6D, router_pim6, router_pim6_cmd, + "router pim6 [vrf NAME]", + ROUTER_STR + "Start PIMv6 configuration\n" + VRF_CMD_HELP_STR) +{ + vty->node = PIM6_NODE; + return CMD_SUCCESS; +} +#endif /* HAVE_PIM6D*/ + DEFUNSH(VTYSH_ALL, vtysh_line_vty, vtysh_line_vty_cmd, "line vty", "Configure a terminal line\n" "Virtual terminal\n") @@ -2826,6 +2868,34 @@ DEFUNSH(VTYSH_PATHD, vtysh_quit_pathd, vtysh_quit_pathd_cmd, "quit", } #endif /* HAVE_PATHD */ +#ifdef HAVE_PIMD +DEFUNSH(VTYSH_PIMD, vtysh_exit_pimd, vtysh_exit_pimd_cmd, "exit", + "Exit current mode and down to previous mode\n") +{ + return vtysh_exit(vty); +} + +DEFUNSH(VTYSH_PIMD, vtysh_quit_pimd, vtysh_quit_pimd_cmd, "quit", + "Exit current mode and down to previous mode\n") +{ + return vtysh_exit_pimd(self, vty, argc, argv); +} +#endif /* HAVE_PIMD */ + +#ifdef HAVE_PIM6D +DEFUNSH(VTYSH_PIM6D, vtysh_exit_pim6d, vtysh_exit_pim6d_cmd, "exit", + "Exit current mode and down to previous mode\n") +{ + return vtysh_exit(vty); +} + +DEFUNSH(VTYSH_PIM6D, vtysh_quit_pim6d, vtysh_quit_pim6d_cmd, "quit", + "Exit current mode and down to previous mode\n") +{ + return vtysh_exit_pim6d(self, vty, argc, argv); +} +#endif /* HAVE_PIM6D */ + DEFUNSH(VTYSH_ALL, vtysh_exit_line_vty, vtysh_exit_line_vty_cmd, "exit", "Exit current mode and down to previous mode\n") { @@ -5293,6 +5363,25 @@ void vtysh_init_vty(void) install_element(INTERFACE_NODE, &vtysh_exit_interface_cmd); install_element(INTERFACE_NODE, &vtysh_quit_interface_cmd); + /* pimd */ +#ifdef HAVE_PIMD + install_node(&pim_node); + install_element(CONFIG_NODE, &router_pim_cmd); + install_element(PIM_NODE, &vtysh_exit_pimd_cmd); + install_element(PIM_NODE, &vtysh_quit_pimd_cmd); + install_element(PIM_NODE, &vtysh_end_all_cmd); +#endif /* HAVE_PIMD */ + + /* pim6d */ +#ifdef HAVE_PIM6D + install_node(&pim6_node); + install_element(CONFIG_NODE, &router_pim6_cmd); + install_element(PIM6_NODE, &vtysh_exit_pim6d_cmd); + install_element(PIM6_NODE, &vtysh_quit_pim6d_cmd); + install_element(PIM6_NODE, &vtysh_end_all_cmd); +#endif /* HAVE_PIM6D */ + + /* zebra and all, cont. */ install_node(&link_params_node); install_element(INTERFACE_NODE, &vtysh_link_params_cmd); install_element(LINK_PARAMS_NODE, &no_link_params_enable_cmd); diff --git a/vtysh/vtysh_config.c b/vtysh/vtysh_config.c index c207e4d427..8f7cd84818 100644 --- a/vtysh/vtysh_config.c +++ b/vtysh/vtysh_config.c @@ -497,6 +497,11 @@ void vtysh_config_parse_line(void *arg, const char *line) config = config_get(BFD_NODE, line); else if (strncmp(line, "rpki", strlen("rpki")) == 0) config = config_get(RPKI_NODE, line); + else if (strncmp(line, "router pim", strlen("router pim")) == 0) + config = config_get(PIM_NODE, line); + else if (strncmp(line, "router pim6", strlen("router pim6")) == + 0) + config = config_get(PIM6_NODE, line); else { if (strncmp(line, "log", strlen("log")) == 0 || strncmp(line, "hostname", strlen("hostname")) == 0 || From 98d47f43fbba4e376c8351c724e8c625799805f7 Mon Sep 17 00:00:00 2001 From: Nathan Bahr Date: Mon, 17 Jun 2024 12:58:30 -0500 Subject: [PATCH 185/347] tools: Fix frr-reload to support legacy pim configuration from file Fix load from file in frr-reload to detect and convert legacy pim configuration so that the tool can continue to be used with legacy configurations. Signed-off-by: Nathan Bahr --- tools/frr-reload.py | 64 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 60 insertions(+), 4 deletions(-) diff --git a/tools/frr-reload.py b/tools/frr-reload.py index 461f0e8c61..47e3637550 100755 --- a/tools/frr-reload.py +++ b/tools/frr-reload.py @@ -94,7 +94,7 @@ def is_config_available(self): output = self("configure") - if "VTY configuration is locked by other VTY" in output: + if "configuration is locked" in output.lower(): log.error("vtysh 'configure' returned\n%s\n" % (output)) return False @@ -261,6 +261,8 @@ def get_normalized_interface_vrf(line): "router ospf6": {}, "router eigrp ": {}, "router babel": {}, + "router pim": {}, + "router pim6": {}, "mpls ldp": {"address-family ": {"interface ": {}}}, "l2vpn ": {"member pseudowire ": {}}, "key chain ": {"key ": {}}, @@ -306,12 +308,62 @@ def load_from_file(self, filename): file_output = self.vtysh.mark_file(filename) + vrf_context = None + pim_vrfs = [] + for line in file_output.split("\n"): line = line.strip() # Compress duplicate whitespaces line = " ".join(line.split()) + # Detect when we are within a vrf context for converting legacy PIM commands + if vrf_context: + re_vrf = re.match("^(exit-vrf|exit|end)$", line) + if re_vrf: + vrf_context = None + else: + re_vrf = re.match("^vrf ([a-z]+)$", line) + if re_vrf: + vrf_context = re_vrf.group(1) + + # Detect legacy pim commands that need to move under the router pim context + re_pim = re.match("^ip(v6)? pim ((ecmp|join|keep|mlag|packets|register|rp|send|spt|ssm).*)$", line) + if re_pim and re_pim.group(2): + router_pim = "router pim" + if re_pim.group(1): + router_pim += "6" + if vrf_context: + router_pim += " vrf " + vrf_context + + if vrf_context: + pim_vrfs.append(router_pim) + pim_vrfs.append(re_pim.group(2)) + pim_vrfs.append("exit") + line="# PIM VRF LINE MOVED TO ROUTER PIM" + else: + self.lines.append(router_pim) + self.lines.append(re_pim.group(2)) + line = "exit" + + re_pim = re.match("^ip(v6)? ((ssmpingd|msdp).*)$", line) + if re_pim and re_pim.group(2): + router_pim = "router pim" + if re_pim.group(1): + router_pim += "6" + if vrf_context: + router_pim += " vrf " + vrf_context + + if vrf_context: + pim_vrfs.append(router_pim) + pim_vrfs.append(re_pim.group(2)) + pim_vrfs.append("exit") + line="# PIM VRF LINE MOVED TO ROUTER PIM" + else: + self.lines.append(router_pim) + self.lines.append(re_pim.group(2)) + line = "exit" + # Remove 'vrf ' from 'interface vrf ' if line.startswith("interface ") and "vrf" in line: line = get_normalized_interface_vrf(line) @@ -348,6 +400,8 @@ def load_from_file(self, filename): self.lines.append(line) + self.lines.append(pim_vrfs) + self.load_contexts() def load_from_show_running(self, daemon): @@ -1683,9 +1737,11 @@ def compare_context_objects(newconf, running): lines_to_del.append((running_ctx_keys, None)) # We cannot do 'no interface' or 'no vrf' in FRR, and so deal with it - elif running_ctx_keys[0].startswith("interface") or running_ctx_keys[ - 0 - ].startswith("vrf"): + elif ( + running_ctx_keys[0].startswith("interface") + or running_ctx_keys[0].startswith("vrf") + or running_ctx_keys[0].startswith("router pim") + ): for line in running_ctx.lines: lines_to_del.append((running_ctx_keys, line)) From b58592d05b7466081555394052367dbec9137572 Mon Sep 17 00:00:00 2001 From: Nathan Bahr Date: Mon, 24 Jun 2024 12:45:42 -0500 Subject: [PATCH 186/347] doc: Update PIM[6] configure docs Document 'router pim[6] [vrf NAME]' configuration. All the commands are basically the same, just dropped the 'ip pim[6]' prefix and document them under the router pim block. Signed-off-by: Nathan Bahr --- doc/user/pim.rst | 73 ++++++++++++++++++++++++++-------------------- doc/user/pimv6.rst | 43 +++++++++++++++------------ 2 files changed, 67 insertions(+), 49 deletions(-) diff --git a/doc/user/pim.rst b/doc/user/pim.rst index b19bb9d1b3..4c62f7528b 100644 --- a/doc/user/pim.rst +++ b/doc/user/pim.rst @@ -55,16 +55,22 @@ Certain signals have special meanings to *pimd*. *pimd* invocation options. Common options that can be specified (:ref:`common-invocation-options`). -.. clicmd:: ip pim rp A.B.C.D A.B.C.D/M +PIM Routers +----------- + +.. clicmd:: router pim [vrf NAME] + Configure global PIM protocol + +.. clicmd:: rp A.B.C.D A.B.C.D/M In order to use pim, it is necessary to configure a RP for join messages to be sent to. Currently the only methodology to do this is via static rp commands. All routers in the pim network must agree on these values. The first ip address is the RP's address and the second value is the matching prefix of group ranges covered. This command is vrf aware, to configure for - a vrf, enter the vrf submode. + a vrf, specify the vrf in the router pim block. -.. clicmd:: ip pim rp keep-alive-timer (1-65535) +.. clicmd:: rp keep-alive-timer (1-65535) Modify the time out value for a S,G flow from 1-65535 seconds at RP. The normal keepalive period for the KAT(S,G) defaults to 210 seconds. @@ -74,41 +80,41 @@ Certain signals have special meanings to *pimd*. max(Keepalive_Period, RP_Keepalive_Period) when a Register-Stop is sent. If choosing a value below 31 seconds be aware that some hardware platforms cannot see data flowing in better than 30 second chunks. This command is - vrf aware, to configure for a vrf, enter the vrf submode. + vrf aware, to configure for a vrf, specify the vrf in the router pim block. -.. clicmd:: ip pim register-accept-list PLIST +.. clicmd:: register-accept-list PLIST When pim receives a register packet the source of the packet will be compared to the prefix-list specified, PLIST, and if a permit is received normal processing continues. If a deny is returned for the source address of the register packet a register stop message is sent to the source. -.. clicmd:: ip pim spt-switchover infinity-and-beyond [prefix-list PLIST] +.. clicmd:: spt-switchover infinity-and-beyond [prefix-list PLIST] On the last hop router if it is desired to not switch over to the SPT tree configure this command. Optional parameter prefix-list can be use to control which groups to switch or not switch. If a group is PERMIT as per the PLIST, then the SPT switchover does not happen for it and if it is DENY, then the SPT switchover happens. - This command is vrf aware, to configure for a vrf, - enter the vrf submode. + This command is vrf aware, to configure for a vrf, specify the vrf in the + router pim block. -.. clicmd:: ip pim ecmp +.. clicmd:: ecmp If pim has the a choice of ECMP nexthops for a particular RPF, pim will cause S,G flows to be spread out amongst the nexthops. If this command is not specified then the first nexthop found will be used. This command is vrf - aware, to configure for a vrf, enter the vrf submode. + aware, to configure for a vrf, specify the vrf in the router pim block. -.. clicmd:: ip pim ecmp rebalance +.. clicmd:: ecmp rebalance If pim is using ECMP and an interface goes down, cause pim to rebalance all S,G flows across the remaining nexthops. If this command is not configured pim only modifies those S,G flows that were using the interface that went - down. This command is vrf aware, to configure for a vrf, enter the vrf - submode. + down. This command is vrf aware, to configure for a vrf, specify the vrf in + the router pim block. -.. clicmd:: ip pim join-prune-interval (1-65535) +.. clicmd:: join-prune-interval (1-65535) Modify the join/prune interval that pim uses to the new value. Time is specified in seconds. This command is vrf aware, to configure for a vrf, @@ -116,39 +122,42 @@ Certain signals have special meanings to *pimd*. a value smaller than 60 seconds be aware that this can and will affect convergence at scale. -.. clicmd:: ip pim keep-alive-timer (1-65535) +.. clicmd:: keep-alive-timer (1-65535) Modify the time out value for a S,G flow from 1-65535 seconds. If choosing a value below 31 seconds be aware that some hardware platforms cannot see data flowing in better than 30 second chunks. This command is vrf aware, to - configure for a vrf, enter the vrf submode. + configure for a vrf, specify the vrf in the router pim block. -.. clicmd:: ip pim packets (1-255) +.. clicmd:: packets (1-255) When processing packets from a neighbor process the number of packets incoming at one time before moving on to the next task. The default value is 3 packets. This command is only useful at scale when you can possibly have a large number of pim control packets flowing. This command is vrf aware, to - configure for a vrf, enter the vrf submode. + configure for a vrf, specify the vrf in the router pim block. -.. clicmd:: ip pim register-suppress-time (1-65535) +.. clicmd:: register-suppress-time (1-65535) Modify the time that pim will register suppress a FHR will send register notifications to the kernel. This command is vrf aware, to configure for a - vrf, enter the vrf submode. + vrf, specify the vrf in the router pim block. -.. clicmd:: ip pim send-v6-secondary +.. clicmd:: send-v6-secondary When sending pim hello packets tell pim to send any v6 secondary addresses on the interface. This information is used to allow pim to use v6 nexthops in it's decision for RPF lookup. This command is vrf aware, to configure for - a vrf, enter the vrf submode. + a vrf, specify the vrf in the router pim block. -.. clicmd:: ip pim ssm prefix-list WORD +.. clicmd:: ssm prefix-list WORD Specify a range of group addresses via a prefix-list that forces pim to - never do SM over. This command is vrf aware, to configure for a vrf, enter - the vrf submode. + never do SM over. This command is vrf aware, to configure for a vrf, specify + the vrf in the router pim block. + +Global Multicast +---------------- .. clicmd:: ip multicast rpf-lookup-mode WORD @@ -334,11 +343,12 @@ MSDP can be setup in different ways: .. note:: MSDP default peer and SA filtering is not implemented. + MSDP configuration is available under 'router pim' Commands available for MSDP: -.. clicmd:: ip msdp timers (1-65535) (1-65535) [(1-65535)] +.. clicmd:: msdp timers (1-65535) (1-65535) [(1-65535)] Configure global MSDP timers. @@ -354,16 +364,16 @@ Commands available for MSDP: configures the interval between connection attempts. The default value is 30 seconds. -.. clicmd:: ip msdp mesh-group WORD member A.B.C.D +.. clicmd:: msdp mesh-group WORD member A.B.C.D Create or update a mesh group to include the specified MSDP peer. -.. clicmd:: ip msdp mesh-group WORD source A.B.C.D +.. clicmd:: msdp mesh-group WORD source A.B.C.D Create or update a mesh group to set the source address used to connect to peers. -.. clicmd:: ip msdp peer A.B.C.D source A.B.C.D +.. clicmd:: msdp peer A.B.C.D source A.B.C.D Create a regular MSDP session with peer using the specified source address. @@ -734,8 +744,9 @@ Sample configuration ! You may want to enable ssmpingd for troubleshooting ! See http://www.venaas.no/multicast/ssmping/ ! - ip ssmpingd 1.1.1.1 - ip ssmpingd 2.2.2.2 + router pim + ssmpingd 1.1.1.1 + ssmpingd 2.2.2.2 ! HINTS: ! - Enable "ip pim ssm" on the interface directly attached to the diff --git a/doc/user/pimv6.rst b/doc/user/pimv6.rst index b8567e4863..fa78eeb70c 100644 --- a/doc/user/pimv6.rst +++ b/doc/user/pimv6.rst @@ -47,21 +47,28 @@ Certain signals have special meanings to *pim6d*. *pim6d* invocation options. Common options that can be specified (:ref:`common-invocation-options`). -.. clicmd:: ipv6 pim rp X:X::X:X Y:Y::Y:Y/M +PIMv6 Router +------------ + +.. clicmd:: router pim6 [vrf NAME] + + Configure the global PIMv6 protocol + +.. clicmd:: rp X:X::X:X Y:Y::Y:Y/M In order to use pimv6, it is necessary to configure a RP for join messages to be sent to. Currently the only methodology to do this is via static rp commands. All routers in the pimv6 network must agree on these values. The first ipv6 address is the RP's address and the second value is the matching prefix of group ranges covered. This command is vrf aware, to configure for - a vrf, enter the vrf submode. + a vrf, specify the vrf in the router pim6 block. -.. clicmd:: ipv6 pim rp X:X::X:X prefix-list WORD +.. clicmd:: rp X:X::X:X prefix-list WORD This CLI helps in configuring RP address for a range of groups specified by the prefix-list. -.. clicmd:: ipv6 pim rp keep-alive-timer (1-65535) +.. clicmd:: rp keep-alive-timer (1-65535) Modify the time out value for a S,G flow from 1-65535 seconds at RP. The normal keepalive period for the KAT(S,G) defaults to 210 seconds. @@ -71,19 +78,19 @@ Certain signals have special meanings to *pim6d*. max(Keepalive_Period, RP_Keepalive_Period) when a Register-Stop is sent. If choosing a value below 31 seconds be aware that some hardware platforms cannot see data flowing in better than 30 second chunks. This command is - vrf aware, to configure for a vrf, enter the vrf submode. + vrf aware, to configure for a vrf, specify the vrf in the router pim6 block. -.. clicmd:: ipv6 pim spt-switchover infinity-and-beyond [prefix-list PLIST] +.. clicmd:: spt-switchover infinity-and-beyond [prefix-list PLIST] On the last hop router if it is desired to not switch over to the SPT tree configure this command. Optional parameter prefix-list can be use to control which groups to switch or not switch. If a group is PERMIT as per the PLIST, then the SPT switchover does not happen for it and if it is DENY, then the SPT switchover happens. - This command is vrf aware, to configure for a vrf, - enter the vrf submode. + This command is vrf aware, to configure for a vrf, specify the vrf in the + router pim6 block. -.. clicmd:: ipv6 pim join-prune-interval (1-65535) +.. clicmd:: join-prune-interval (1-65535) Modify the join/prune interval that pim uses to the new value. Time is specified in seconds. This command is vrf aware, to configure for a vrf, @@ -91,28 +98,28 @@ Certain signals have special meanings to *pim6d*. a value smaller than 60 seconds be aware that this can and will affect convergence at scale. -.. clicmd:: ipv6 pim keep-alive-timer (1-65535) +.. clicmd:: keep-alive-timer (1-65535) Modify the time out value for a S,G flow from 1-65535 seconds. If choosing a value below 31 seconds be aware that some hardware platforms cannot see data flowing in better than 30 second chunks. This command is vrf aware, to - configure for a vrf, enter the vrf submode. + configure for a vrf, specify the vrf in the router pim6 block. -.. clicmd:: ipv6 pim packets (1-255) +.. clicmd:: packets (1-255) When processing packets from a neighbor process the number of packets incoming at one time before moving on to the next task. The default value is 3 packets. This command is only useful at scale when you can possibly have a large number of pim control packets flowing. This command is vrf aware, to - configure for a vrf, enter the vrf submode. + configure for a vrf, specify the vrf in the router pim6 block. -.. clicmd:: ipv6 pim register-suppress-time (1-65535) +.. clicmd:: register-suppress-time (1-65535) Modify the time that pim will register suppress a FHR will send register notifications to the kernel. This command is vrf aware, to configure for a - vrf, enter the vrf submode. + vrf, specify the vrf in the router pim6 block. -.. clicmd:: ipv6 ssmpingd [X:X::X:X] +.. clicmd:: ssmpingd [X:X::X:X] Enable ipv6 ssmpingd configuration. A network level management tool to check whether one can receive multicast packets via SSM from host. @@ -417,7 +424,7 @@ Clear commands reset various variables. .. clicmd:: clear ipv6 pim [vrf NAME] interface traffic - When this command is issued, resets the information about the + When this command is issued, resets the information about the number of PIM protocol packets sent/received on an interface. .. clicmd:: clear ipv6 pim oil @@ -494,7 +501,7 @@ the config was written out. .. clicmd:: debug mld trace [detail] - This traces mld code and how it is running. + This traces mld code and how it is running. .. clicmd:: debug pimv6 bsm From f46ce043fc0cba104c6fb4e13c1fd031928de346 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Wed, 17 Jul 2024 02:12:48 +0300 Subject: [PATCH 187/347] lib, vtysh: Removed deprecated aliases for `show thread ...` Signed-off-by: Donatas Abraitis --- lib/event.c | 28 ---------------------------- vtysh/vtysh.c | 3 --- 2 files changed, 31 deletions(-) diff --git a/lib/event.c b/lib/event.c index fc46a11c0b..c04d309bc2 100644 --- a/lib/event.c +++ b/lib/event.c @@ -304,9 +304,6 @@ static uint8_t parse_filter(const char *filterstr) return filter; } -#if CONFDATE > 20240707 - CPP_NOTICE("Remove `show thread ...` commands") -#endif DEFUN_NOSH (show_event_cpu, show_event_cpu_cmd, "show event cpu [FILTER]", @@ -332,14 +329,6 @@ DEFUN_NOSH (show_event_cpu, return CMD_SUCCESS; } -ALIAS(show_event_cpu, - show_thread_cpu_cmd, - "show thread cpu [FILTER]", - SHOW_STR - "Thread information\n" - "Thread CPU usage\n" - "Display filter (rwtex)\n") - DEFPY (service_cputime_stats, service_cputime_stats_cmd, "[no] service cputime-stats", @@ -440,13 +429,6 @@ DEFUN_NOSH (show_event_poll, return CMD_SUCCESS; } -ALIAS(show_event_poll, - show_thread_poll_cmd, - "show thread poll", - SHOW_STR - "Thread information\n" - "Show poll FD's and information\n") - DEFUN (clear_thread_cpu, clear_thread_cpu_cmd, "clear thread cpu [FILTER]", @@ -507,18 +489,9 @@ DEFPY_NOSH (show_event_timers, return CMD_SUCCESS; } -ALIAS(show_event_timers, - show_thread_timers_cmd, - "show thread timers", - SHOW_STR - "Thread information\n" - "Show all timers and how long they have in the system\n") - void event_cmd_init(void) { - install_element(VIEW_NODE, &show_thread_cpu_cmd); install_element(VIEW_NODE, &show_event_cpu_cmd); - install_element(VIEW_NODE, &show_thread_poll_cmd); install_element(VIEW_NODE, &show_event_poll_cmd); install_element(ENABLE_NODE, &clear_thread_cpu_cmd); @@ -526,7 +499,6 @@ void event_cmd_init(void) install_element(CONFIG_NODE, &service_cputime_warning_cmd); install_element(CONFIG_NODE, &service_walltime_warning_cmd); - install_element(VIEW_NODE, &show_thread_timers_cmd); install_element(VIEW_NODE, &show_event_timers_cmd); } /* CLI end ------------------------------------------------------------------ */ diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index 573320667c..9d56f04472 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -2988,9 +2988,6 @@ static int show_one_daemon(struct vty *vty, struct cmd_token **argv, int argc, return ret; } -#if CONFDATE > 20240707 - CPP_NOTICE("Remove `show thread ...` commands") -#endif DEFUN (vtysh_show_event_timer, vtysh_show_event_timer_cmd, "show event timers", From 193e14e401c88d2d9e822a2474b0f777efff4958 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Wed, 17 Jul 2024 02:17:59 +0300 Subject: [PATCH 188/347] lib: Rename `clear thread cpu ...` to `clear event cpu ...` Add a deprecation cycle also. Signed-off-by: Donatas Abraitis --- lib/event.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/lib/event.c b/lib/event.c index c04d309bc2..f4aa7c58b9 100644 --- a/lib/event.c +++ b/lib/event.c @@ -429,12 +429,15 @@ DEFUN_NOSH (show_event_poll, return CMD_SUCCESS; } -DEFUN (clear_thread_cpu, - clear_thread_cpu_cmd, - "clear thread cpu [FILTER]", +#if CONFDATE > 20241231 +CPP_NOTICE("Remove `clear thread cpu` command") +#endif +DEFUN (clear_event_cpu, + clear_event_cpu_cmd, + "clear event cpu [FILTER]", "Clear stored data in all pthreads\n" - "Thread information\n" - "Thread CPU usage\n" + "Event information\n" + "Event CPU usage\n" "Display filter (rwtexb)\n") { uint8_t filter = (uint8_t)-1U; @@ -454,6 +457,14 @@ DEFUN (clear_thread_cpu, return CMD_SUCCESS; } +ALIAS (clear_event_cpu, + clear_thread_cpu_cmd, + "clear thread cpu [FILTER]", + "Clear stored data in all pthreads\n" + "Thread information\n" + "Thread CPU usage\n" + "Display filter (rwtexb)\n") + static void show_event_timers_helper(struct vty *vty, struct event_loop *m) { const char *name = m->name ? m->name : "main"; @@ -494,6 +505,7 @@ void event_cmd_init(void) install_element(VIEW_NODE, &show_event_cpu_cmd); install_element(VIEW_NODE, &show_event_poll_cmd); install_element(ENABLE_NODE, &clear_thread_cpu_cmd); + install_element(ENABLE_NODE, &clear_event_cpu_cmd); install_element(CONFIG_NODE, &service_cputime_stats_cmd); install_element(CONFIG_NODE, &service_cputime_warning_cmd); From 0546572d70c34a9b810aae6d517afdb655ec299f Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Wed, 17 Jul 2024 08:10:13 +0300 Subject: [PATCH 189/347] tools: Ignore ALIAS_* macros for clang-formatter Signed-off-by: Donatas Abraitis --- .clang-format | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.clang-format b/.clang-format index 06769c9661..7aefafa58f 100644 --- a/.clang-format +++ b/.clang-format @@ -224,4 +224,8 @@ WhitespaceSensitiveMacros: - "DEFUN_YANG_NOSH" - "DEFUNSH" - "DEFUNSH_HIDDEN" + - "ALIAS" + - "ALIAS_HIDDEN" + - "ALIAS_YANG" + - "ALIAS_DEPRECATED" ... From 5a70378a47f541b0354fbb96770dd0a65ec552b8 Mon Sep 17 00:00:00 2001 From: Christian Breunig Date: Sat, 13 Jul 2024 08:43:36 +0200 Subject: [PATCH 190/347] ospfd: fix internal ldp-sync state flags when feature is disabled When enabling "mpls ldp-sync" under "router ospf" ospfd configures SET_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_IF_CONFIG) so internally knowing that the ldp-sync feature is enabled. However the flag is not cleared when turning of the feature using "nompls ldp-sync"! https://github.com/FRRouting/frr/issues/16375 Signed-off-by: Christian Breunig --- ospfd/ospf_ldp_sync.c | 2 +- tests/topotests/ldp_sync_ospf_topo1/r2/show_ospf_ldp_sync.ref | 4 ++-- .../r2/show_ospf_ldp_sync_r1_eth1_shutdown.ref | 4 ++-- .../r2/show_ospf_ldp_sync_r2_eth1_shutdown.ref | 4 ++-- tests/topotests/ldp_sync_ospf_topo1/r3/show_ospf_ldp_sync.ref | 4 ++-- .../r3/show_ospf_ldp_sync_r1_eth1_shutdown.ref | 4 ++-- .../r3/show_ospf_ldp_sync_r2_eth1_shutdown.ref | 4 ++-- 7 files changed, 13 insertions(+), 13 deletions(-) diff --git a/ospfd/ospf_ldp_sync.c b/ospfd/ospf_ldp_sync.c index d1ef85c9a6..496ae5b4bd 100644 --- a/ospfd/ospf_ldp_sync.c +++ b/ospfd/ospf_ldp_sync.c @@ -901,7 +901,7 @@ DEFPY (no_mpls_ldp_sync, * stop holddown timer if running * restore ospf cost */ - SET_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_IF_CONFIG); + UNSET_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_IF_CONFIG); ldp_sync_info->enabled = LDP_IGP_SYNC_DEFAULT; ldp_sync_info->state = LDP_IGP_SYNC_STATE_NOT_REQUIRED; EVENT_OFF(ldp_sync_info->t_holddown); diff --git a/tests/topotests/ldp_sync_ospf_topo1/r2/show_ospf_ldp_sync.ref b/tests/topotests/ldp_sync_ospf_topo1/r2/show_ospf_ldp_sync.ref index 6c27a10427..846be5b849 100644 --- a/tests/topotests/ldp_sync_ospf_topo1/r2/show_ospf_ldp_sync.ref +++ b/tests/topotests/ldp_sync_ospf_topo1/r2/show_ospf_ldp_sync.ref @@ -5,8 +5,8 @@ "ldpIgpSyncState":"Sync achieved" }, "r2-eth2":{ - "ldpIgpSyncEnabled":false, + "ldpIgpSyncEnabled":true, "holdDownTimeInSec":50, - "ldpIgpSyncState":"Sync not required" + "ldpIgpSyncState":"Sync achieved" } } diff --git a/tests/topotests/ldp_sync_ospf_topo1/r2/show_ospf_ldp_sync_r1_eth1_shutdown.ref b/tests/topotests/ldp_sync_ospf_topo1/r2/show_ospf_ldp_sync_r1_eth1_shutdown.ref index 889f69ed7f..ad3b8b5ca4 100644 --- a/tests/topotests/ldp_sync_ospf_topo1/r2/show_ospf_ldp_sync_r1_eth1_shutdown.ref +++ b/tests/topotests/ldp_sync_ospf_topo1/r2/show_ospf_ldp_sync_r1_eth1_shutdown.ref @@ -5,8 +5,8 @@ "ldpIgpSyncState":"Holding down until Sync" }, "r2-eth2":{ - "ldpIgpSyncEnabled":false, + "ldpIgpSyncEnabled":true, "holdDownTimeInSec":50, - "ldpIgpSyncState":"Sync not required" + "ldpIgpSyncState":"Sync achieved" } } diff --git a/tests/topotests/ldp_sync_ospf_topo1/r2/show_ospf_ldp_sync_r2_eth1_shutdown.ref b/tests/topotests/ldp_sync_ospf_topo1/r2/show_ospf_ldp_sync_r2_eth1_shutdown.ref index d9036e124b..d5e4b88d07 100644 --- a/tests/topotests/ldp_sync_ospf_topo1/r2/show_ospf_ldp_sync_r2_eth1_shutdown.ref +++ b/tests/topotests/ldp_sync_ospf_topo1/r2/show_ospf_ldp_sync_r2_eth1_shutdown.ref @@ -1,7 +1,7 @@ { "r2-eth2":{ - "ldpIgpSyncEnabled":false, + "ldpIgpSyncEnabled":true, "holdDownTimeInSec":50, - "ldpIgpSyncState":"Sync not required" + "ldpIgpSyncState":"Sync achieved" } } diff --git a/tests/topotests/ldp_sync_ospf_topo1/r3/show_ospf_ldp_sync.ref b/tests/topotests/ldp_sync_ospf_topo1/r3/show_ospf_ldp_sync.ref index b417ab040a..5b9542d5a9 100644 --- a/tests/topotests/ldp_sync_ospf_topo1/r3/show_ospf_ldp_sync.ref +++ b/tests/topotests/ldp_sync_ospf_topo1/r3/show_ospf_ldp_sync.ref @@ -1,8 +1,8 @@ { "r3-eth1":{ - "ldpIgpSyncEnabled":false, + "ldpIgpSyncEnabled":true, "holdDownTimeInSec":50, - "ldpIgpSyncState":"Sync not required" + "ldpIgpSyncState":"Sync achieved" }, "r3-eth2":{ "ldpIgpSyncEnabled":true, diff --git a/tests/topotests/ldp_sync_ospf_topo1/r3/show_ospf_ldp_sync_r1_eth1_shutdown.ref b/tests/topotests/ldp_sync_ospf_topo1/r3/show_ospf_ldp_sync_r1_eth1_shutdown.ref index b417ab040a..5b9542d5a9 100644 --- a/tests/topotests/ldp_sync_ospf_topo1/r3/show_ospf_ldp_sync_r1_eth1_shutdown.ref +++ b/tests/topotests/ldp_sync_ospf_topo1/r3/show_ospf_ldp_sync_r1_eth1_shutdown.ref @@ -1,8 +1,8 @@ { "r3-eth1":{ - "ldpIgpSyncEnabled":false, + "ldpIgpSyncEnabled":true, "holdDownTimeInSec":50, - "ldpIgpSyncState":"Sync not required" + "ldpIgpSyncState":"Sync achieved" }, "r3-eth2":{ "ldpIgpSyncEnabled":true, diff --git a/tests/topotests/ldp_sync_ospf_topo1/r3/show_ospf_ldp_sync_r2_eth1_shutdown.ref b/tests/topotests/ldp_sync_ospf_topo1/r3/show_ospf_ldp_sync_r2_eth1_shutdown.ref index b417ab040a..5b9542d5a9 100644 --- a/tests/topotests/ldp_sync_ospf_topo1/r3/show_ospf_ldp_sync_r2_eth1_shutdown.ref +++ b/tests/topotests/ldp_sync_ospf_topo1/r3/show_ospf_ldp_sync_r2_eth1_shutdown.ref @@ -1,8 +1,8 @@ { "r3-eth1":{ - "ldpIgpSyncEnabled":false, + "ldpIgpSyncEnabled":true, "holdDownTimeInSec":50, - "ldpIgpSyncState":"Sync not required" + "ldpIgpSyncState":"Sync achieved" }, "r3-eth2":{ "ldpIgpSyncEnabled":true, From 55be38d98e4ba7ca4c7a88f0c0eef8c484e67d47 Mon Sep 17 00:00:00 2001 From: anlan_cs Date: Wed, 17 Jul 2024 15:16:44 +0800 Subject: [PATCH 191/347] doc: adjust some commands for pim/pimv6 bsr Signed-off-by: anlan_cs --- doc/user/pim.rst | 4 ++-- doc/user/pimv6.rst | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/user/pim.rst b/doc/user/pim.rst index b19bb9d1b3..862469852f 100644 --- a/doc/user/pim.rst +++ b/doc/user/pim.rst @@ -576,11 +576,11 @@ cause great confusion. Display current bsr, its uptime and last received bsm age. -.. clicmd:: show ip pim bsrp-info +.. clicmd:: show ip pim bsrp-info [vrf NAME] [json] Display group-to-rp mappings received from E-BSR. -.. clicmd:: show ip pim bsm-database +.. clicmd:: show ip pim bsm-database [vrf NAME] [json] Display all fragments of stored bootstrap message in user readable format. diff --git a/doc/user/pimv6.rst b/doc/user/pimv6.rst index b8567e4863..a166149bf7 100644 --- a/doc/user/pimv6.rst +++ b/doc/user/pimv6.rst @@ -388,11 +388,11 @@ General multicast routing state Display current bsr, its uptime and last received bsm age. -.. clicmd:: show ipv6 pim bsrp-info +.. clicmd:: show ipv6 pim bsrp-info [vrf NAME] [json] Display group-to-rp mappings received from E-BSR. -.. clicmd:: show ipv6 pim bsm-database +.. clicmd:: show ipv6 pim bsm-database [vrf NAME] [json] Display all fragments of stored bootstrap message in user readable format. From e36e570c6c2c4ee9be618ffef667e9d1a5758478 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Wed, 17 Jul 2024 11:28:10 +0200 Subject: [PATCH 192/347] zebra: add nexthop counter to 'show zebra dplane' command The nexthop updates counter value was never displayed. Add it. > # show zebra dplane > Zebra dataplane: > Route updates: 7673010 > Route update errors: 0 > Nexthop updates: 1100 > Nexthop update errors: 0 > [..] Signed-off-by: Philippe Guibert --- zebra/zebra_dplane.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c index 0844b34672..1cee1ebb93 100644 --- a/zebra/zebra_dplane.c +++ b/zebra/zebra_dplane.c @@ -6003,6 +6003,14 @@ int dplane_show_helper(struct vty *vty, bool detailed) vty_out(vty, "Zebra dataplane:\nRoute updates: %"PRIu64"\n", incoming); vty_out(vty, "Route update errors: %"PRIu64"\n", errs); + + incoming = atomic_load_explicit(&zdplane_info.dg_nexthops_in, + memory_order_relaxed); + errs = atomic_load_explicit(&zdplane_info.dg_nexthop_errors, + memory_order_relaxed); + vty_out(vty, "Nexthop updates: %" PRIu64 "\n", incoming); + vty_out(vty, "Nexthop update errors: %" PRIu64 "\n", errs); + vty_out(vty, "Other errors : %"PRIu64"\n", other_errs); vty_out(vty, "Route update queue limit: %"PRIu64"\n", limit); vty_out(vty, "Route update queue depth: %"PRIu64"\n", queued); From 329a4192f65aa454c2d041da9285235143d7f270 Mon Sep 17 00:00:00 2001 From: Y Bharath Date: Wed, 17 Jul 2024 16:20:13 +0530 Subject: [PATCH 193/347] yang: Fixed pyang warnings at frr-bfdd yang file Fixed warnings at frr-bfdd yang file Signed-off-by: y-bharath14 --- yang/frr-bfdd.yang | 3 --- 1 file changed, 3 deletions(-) diff --git a/yang/frr-bfdd.yang b/yang/frr-bfdd.yang index ffba42b53b..02ed921459 100644 --- a/yang/frr-bfdd.yang +++ b/yang/frr-bfdd.yang @@ -16,9 +16,6 @@ module frr-bfdd { import frr-vrf { prefix frr-vrf; } - import frr-route-types { - prefix frr-route-types; - } organization "FRRouting"; contact From 8b81f32e97876eefe13370d1efba6a7aeb1c6771 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Sang?= Date: Tue, 16 Jul 2024 14:03:11 +0200 Subject: [PATCH 194/347] bgpd: fix label lost when vrf loopback comes back MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit VRF-label association drops when the VRF loopback goes down, however, it does not return once the interface is enabled again. Logs show that when VRF loopback goes down, a label drop message is sent to zebra and immediately resent label installation to zebra, trigged by "vpn_leak_postchange_all()": 2024/07/16 13:26:29 BGP: [RVJ1J-J2T22] ifp down r1-cust1 vrf id 7 2024/07/16 13:26:29 BGP: [WA2QY-06STJ] vpn_leak_zebra_vrf_label_withdraw: deleting label for vrf VRF r1-cust1 (id=7) 2024/07/16 13:26:30 BGP: [S82AC-6YAC8] vpn_leak_zebra_vrf_label_update: vrf VRF r1-cust1: afi IPv4: setting label 80 for vrf id 7 Since the interface is down, the netlink message is not send to kernel. Once the interface comes back, zebra ignore the installation assuming the label is already seen. To fix this, add a check for the interface status before attempting to reinstall the label. Signed-off-by: Loïc Sang --- bgpd/bgp_mplsvpn.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index 90881621b3..a1d0a8512c 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -280,7 +280,8 @@ int bgp_nlri_parse_vpn(struct peer *peer, struct attr *attr, * * Sending this vrf-label association is qualified by a) whether vrf->vpn * exporting is active ("export vpn" is enabled, vpn-policy RD and RT list - * are set) and b) whether vpn-policy label is set. + * are set), b) whether vpn-policy label is set and c) the vrf loopback + * interface is up. * * If any of these conditions do not hold, then we send MPLS_LABEL_NONE * for this vrf, which zebra interprets to mean "delete this vrf-label @@ -288,6 +289,7 @@ int bgp_nlri_parse_vpn(struct peer *peer, struct attr *attr, */ void vpn_leak_zebra_vrf_label_update(struct bgp *bgp, afi_t afi) { + struct interface *ifp; mpls_label_t label = MPLS_LABEL_NONE; int debug = BGP_DEBUG(vpn, VPN_LEAK_LABEL); @@ -301,7 +303,9 @@ void vpn_leak_zebra_vrf_label_update(struct bgp *bgp, afi_t afi) } if (vpn_leak_to_vpn_active(bgp, afi, NULL, false)) { - label = bgp->vpn_policy[afi].tovpn_label; + ifp = if_get_vrf_loopback(bgp->vrf_id); + if (ifp && if_is_vrf(ifp) && if_is_up(ifp)) + label = bgp->vpn_policy[afi].tovpn_label; } if (debug) { From c21c597d5d885b46765ede114a96634d51071530 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Sang?= Date: Wed, 17 Jul 2024 14:40:09 +0200 Subject: [PATCH 195/347] bgpd: do not update leak label at loopback up down MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The up/down state of the lo loopback interface does not determine the availability of the default vrf-lite. Do not update leak label at lo loopback up/down change. Fixes: b45c5cd959 ("bgpd: update route leak when vrf state changes") Signed-off-by: Louis Scalbert Signed-off-by: Loïc Sang --- bgpd/bgp_zebra.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 7f91e3149e..180f4264ec 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -234,7 +234,7 @@ static int bgp_ifp_up(struct interface *ifp) hook_call(bgp_vrf_status_changed, bgp, ifp); bgp_nht_ifp_up(ifp); - if (bgp_get_default() && if_is_loopback(ifp)) { + if (bgp_get_default() && if_is_vrf(ifp)) { vpn_leak_zebra_vrf_label_update(bgp, AFI_IP); vpn_leak_zebra_vrf_label_update(bgp, AFI_IP6); vpn_leak_zebra_vrf_sid_update(bgp, AFI_IP); @@ -289,7 +289,7 @@ static int bgp_ifp_down(struct interface *ifp) hook_call(bgp_vrf_status_changed, bgp, ifp); bgp_nht_ifp_down(ifp); - if (bgp_get_default() && if_is_loopback(ifp)) { + if (bgp_get_default() && if_is_vrf(ifp)) { vpn_leak_zebra_vrf_label_withdraw(bgp, AFI_IP); vpn_leak_zebra_vrf_label_withdraw(bgp, AFI_IP6); vpn_leak_zebra_vrf_sid_withdraw(bgp, AFI_IP); From ddc1c2eeae981232e4b9a7021ecf4cdaf33f3a05 Mon Sep 17 00:00:00 2001 From: Nathan Bahr Date: Wed, 17 Jul 2024 11:10:53 -0500 Subject: [PATCH 196/347] tests: OSPFv3 hello tests investigation, make assert output unique These failing tests are hard to track down. Added numbering to each assert to easily tell where the test fails. Signed-off-by: Nathan Bahr --- .../test_ospfv3_single_area.py | 97 +++++++++++++------ 1 file changed, 69 insertions(+), 28 deletions(-) diff --git a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_single_area.py b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_single_area.py index 15e0f5316e..d981a84597 100644 --- a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_single_area.py +++ b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_single_area.py @@ -388,6 +388,11 @@ def test_ospfv3_hello_tc10_p0(request): step("Bring up the base config as per the topology") reset_config_on_routers(tgen) + ospf_covergence = verify_ospf6_neighbor(tgen) + assert ( + ospf_covergence is True + ), "Testcase {} [01]: Reset Failed \n Error: {}".format(tc_name, ospf_covergence) + step("modify hello timer from default value to some other value on r1") topo1 = { @@ -402,7 +407,9 @@ def test_ospfv3_hello_tc10_p0(request): } result = create_interfaces_cfg(tgen, topo1) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + assert result is True, "Testcase {} [02]: Failed \n Error: {}".format( + tc_name, result + ) step( "verify that new timer value is configured and applied using " @@ -422,7 +429,9 @@ def test_ospfv3_hello_tc10_p0(request): } } result = verify_ospf6_interface(tgen, topo, dut=dut, input_dict=input_dict) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + assert result is True, "Testcase {} [03]: Failed \n Error: {}".format( + tc_name, result + ) step("modify hello timer from default value to r1 hello timer on r2") @@ -438,7 +447,9 @@ def test_ospfv3_hello_tc10_p0(request): } result = create_interfaces_cfg(tgen, topo1) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + assert result is True, "Testcase {} [04]: Failed \n Error: {}".format( + tc_name, result + ) step("verify that new timer value is configured.") input_dict = { @@ -455,12 +466,14 @@ def test_ospfv3_hello_tc10_p0(request): } dut = "r0" result = verify_ospf6_interface(tgen, topo, dut=dut, input_dict=input_dict) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + assert result is True, "Testcase {} [05]: Failed \n Error: {}".format( + tc_name, result + ) step("verify that ospf neighbours are full") ospf_covergence = verify_ospf6_neighbor(tgen, topo, dut=dut) - assert ospf_covergence is True, "Testcase Failed \n Error: {}".format( - ospf_covergence + assert ospf_covergence is True, "Testcase {} [06]: Failed \n Error: {}".format( + tc_name, ospf_covergence ) step("reconfigure the default hello timer value to default on r1 and r2") @@ -477,7 +490,9 @@ def test_ospfv3_hello_tc10_p0(request): } result = create_interfaces_cfg(tgen, topo1) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + assert result is True, "Testcase {} [07]: Failed \n Error: {}".format( + tc_name, result + ) topo1 = { "r1": { @@ -491,7 +506,9 @@ def test_ospfv3_hello_tc10_p0(request): } result = create_interfaces_cfg(tgen, topo1) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + assert result is True, "Testcase {} [08]: Failed \n Error: {}".format( + tc_name, result + ) step("verify that new timer value is configured.") input_dict = { @@ -508,12 +525,14 @@ def test_ospfv3_hello_tc10_p0(request): } dut = "r0" result = verify_ospf6_interface(tgen, topo, dut=dut, input_dict=input_dict) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + assert result is True, "Testcase {} [09]: Failed \n Error: {}".format( + tc_name, result + ) step("verify that ospf neighbours are full") ospf_covergence = verify_ospf6_neighbor(tgen, topo, dut=dut) - assert ospf_covergence is True, "Testcase Failed \n Error: {}".format( - ospf_covergence + assert ospf_covergence is True, "Testcase {} [10]: Failed \n Error: {}".format( + tc_name, ospf_covergence ) step("reconfigure the default hello timer value to default on r1 and r2") @@ -530,7 +549,9 @@ def test_ospfv3_hello_tc10_p0(request): } result = create_interfaces_cfg(tgen, topo1) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + assert result is True, "Testcase {} [11]: Failed \n Error: {}".format( + tc_name, result + ) topo1 = { "r1": { @@ -544,7 +565,9 @@ def test_ospfv3_hello_tc10_p0(request): } result = create_interfaces_cfg(tgen, topo1) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + assert result is True, "Testcase {} [12]: Failed \n Error: {}".format( + tc_name, result + ) step("verify that new timer value is configured.") input_dict = { @@ -561,12 +584,14 @@ def test_ospfv3_hello_tc10_p0(request): } dut = "r0" result = verify_ospf6_interface(tgen, topo, dut=dut, input_dict=input_dict) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + assert result is True, "Testcase {} [13]: Failed \n Error: {}".format( + tc_name, result + ) step("verify that ospf neighbours are full") ospf_covergence = verify_ospf6_neighbor(tgen, topo, dut=dut) - assert ospf_covergence is True, "Testcase Failed \n Error: {}".format( - ospf_covergence + assert ospf_covergence is True, "Testcase {} [14]: Failed \n Error: {}".format( + tc_name, ospf_covergence ) step("configure hello timer = 1 on r1 and r2") @@ -582,7 +607,9 @@ def test_ospfv3_hello_tc10_p0(request): } result = create_interfaces_cfg(tgen, topo1) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + assert result is True, "Testcase {} [15]: Failed \n Error: {}".format( + tc_name, result + ) topo1 = { "r1": { @@ -596,7 +623,9 @@ def test_ospfv3_hello_tc10_p0(request): } result = create_interfaces_cfg(tgen, topo1) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + assert result is True, "Testcase {} [16]: Failed \n Error: {}".format( + tc_name, result + ) step("verify that new timer value is configured.") input_dict = { @@ -613,12 +642,14 @@ def test_ospfv3_hello_tc10_p0(request): } dut = "r0" result = verify_ospf6_interface(tgen, topo, dut=dut, input_dict=input_dict) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + assert result is True, "Testcase {} [17]: Failed \n Error: {}".format( + tc_name, result + ) step("verify that ospf neighbours are full") ospf_covergence = verify_ospf6_neighbor(tgen, topo, dut=dut) - assert ospf_covergence is True, "Testcase Failed \n Error: {}".format( - ospf_covergence + assert ospf_covergence is True, "Testcase {} [18]: Failed \n Error: {}".format( + tc_name, ospf_covergence ) step(" Configure hello timer = 65535") @@ -634,7 +665,9 @@ def test_ospfv3_hello_tc10_p0(request): } result = create_interfaces_cfg(tgen, topo1) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + assert result is True, "Testcase {} [19]: Failed \n Error: {}".format( + tc_name, result + ) topo1 = { "r1": { @@ -648,7 +681,9 @@ def test_ospfv3_hello_tc10_p0(request): } result = create_interfaces_cfg(tgen, topo1) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + assert result is True, "Testcase {} [20]: Failed \n Error: {}".format( + tc_name, result + ) step("verify that new timer value is configured.") input_dict = { @@ -665,11 +700,13 @@ def test_ospfv3_hello_tc10_p0(request): } dut = "r0" result = verify_ospf6_interface(tgen, topo, dut=dut, input_dict=input_dict) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + assert result is True, "Testcase {} [21]: Failed \n Error: {}".format( + tc_name, result + ) step("verify that ospf neighbours are full") ospf_covergence = verify_ospf6_neighbor(tgen, topo, dut=dut) - assert ospf_covergence is True, "Testcase {} : Failed \n Error: {}".format( + assert ospf_covergence is True, "Testcase {} [22]: Failed \n Error: {}".format( tc_name, ospf_covergence ) step(" Try configuring timer values outside range for example 65536") @@ -687,7 +724,7 @@ def test_ospfv3_hello_tc10_p0(request): result = create_interfaces_cfg(tgen, topo1) assert ( result is not True - ), "Testcase {} : Failed \n Create interface failed. Error: {}".format( + ), "Testcase {} [23]: Failed \n Create interface failed. Error: {}".format( tc_name, result ) @@ -706,13 +743,17 @@ def test_ospfv3_hello_tc10_p0(request): } result = create_interfaces_cfg(tgen, topo1) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + assert result is True, "Testcase {} [24]: Failed \n Error: {}".format( + tc_name, result + ) step("Verify that timer value is deleted from intf & set to default value 40 sec.") input_dict = {"r1": {"links": {"r0": {"ospf6": {"timerIntervalsConfigHello": 10}}}}} dut = "r1" result = verify_ospf6_interface(tgen, topo, dut=dut, input_dict=input_dict) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + assert result is True, "Testcase {} [25]: Failed \n Error: {}".format( + tc_name, result + ) write_test_footer(tc_name) From 55de91d8535d15c6cc08f8a36be5363b021e65ce Mon Sep 17 00:00:00 2001 From: Dave LeRoy Date: Wed, 17 Jul 2024 10:37:44 -0700 Subject: [PATCH 197/347] nhrpd: Fixes auth config change bug Freeing auth-token does not set nifp->auth_token to NULL. Explicitly set auth_token to NULL when deleting auth config in order for write config logic to succeed. Fix bug #16359 Signed-off-by: Dave LeRoy --- nhrpd/nhrp_vty.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/nhrpd/nhrp_vty.c b/nhrpd/nhrp_vty.c index b938ae4cf0..22b6bdcec7 100644 --- a/nhrpd/nhrp_vty.c +++ b/nhrpd/nhrp_vty.c @@ -481,8 +481,10 @@ DEFPY(if_nhrp_authentication, if_nhrp_authentication_cmd, return CMD_WARNING_CONFIG_FAILED; } - if (nifp->auth_token) + if (nifp->auth_token) { zbuf_free(nifp->auth_token); + nifp->auth_token = NULL; + } nifp->auth_token = zbuf_alloc(pass_len + sizeof(uint32_t)); auth = (struct nhrp_cisco_authentication_extension *) @@ -505,8 +507,10 @@ DEFPY(if_no_nhrp_authentication, if_no_nhrp_authentication_cmd, VTY_DECLVAR_CONTEXT(interface, ifp); struct nhrp_interface *nifp = ifp->info; - if (nifp->auth_token) + if (nifp->auth_token) { zbuf_free(nifp->auth_token); + nifp->auth_token = NULL; + } return CMD_SUCCESS; } From c531584a37bb34e7d8cf62887fd27c701270cd4b Mon Sep 17 00:00:00 2001 From: Dave LeRoy Date: Thu, 18 Jul 2024 10:19:30 -0700 Subject: [PATCH 198/347] nhrpd: Fixes auth no redirect bug The nhrp_peer_forward() routine was not explicitly handling the Authentication Extension in the switch statement and instead fell through to the default case which checked whether this was an unhandled Compulsory extension and errored out, never forwarding the Resolution Request. Fix bug #16371 Signed-off-by: Dave LeRoy --- nhrpd/nhrp_peer.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/nhrpd/nhrp_peer.c b/nhrpd/nhrp_peer.c index 2414541bfa..0407b86be8 100644 --- a/nhrpd/nhrp_peer.c +++ b/nhrpd/nhrp_peer.c @@ -1046,6 +1046,13 @@ static void nhrp_peer_forward(struct nhrp_peer *p, zbuf_put(zb, extpl.head, len); } break; + case NHRP_EXTENSION_AUTHENTICATION: + /* At this point, received packet has been authenticated. + * Just need to regenerate auth extension before forwarding. + * This will be done below in nhrp_packet_complete_auth(). + */ + break; + default: if (htons(ext->type) & NHRP_EXTENSION_FLAG_COMPULSORY) /* FIXME: RFC says to just copy, but not @@ -1064,7 +1071,7 @@ static void nhrp_peer_forward(struct nhrp_peer *p, nhrp_ext_complete(zb, dst); } - nhrp_packet_complete_auth(zb, hdr, pp->ifp, false); + nhrp_packet_complete_auth(zb, hdr, pp->ifp, true); nhrp_peer_send(p, zb); zbuf_free(zb); zbuf_free(zb_copy); From e8169f9385f8423b7086f2a14ee0591811320444 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Fri, 19 Jul 2024 05:20:04 +0300 Subject: [PATCH 199/347] bgpd: Show extended parameters support for the OPEN messages We did that for the receiving side, but not for a sending side, let's fix it. Signed-off-by: Donatas Abraitis --- bgpd/bgp_packet.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index 4625f15778..0fb59a94c2 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -651,6 +651,7 @@ void bgp_open_send(struct peer_connection *connection) uint16_t send_holdtime; as_t local_as; struct peer *peer = connection->peer; + bool ext_opt_params = false; if (CHECK_FLAG(peer->flags, PEER_FLAG_TIMER)) send_holdtime = peer->holdtime; @@ -677,15 +678,17 @@ void bgp_open_send(struct peer_connection *connection) /* Set capabilities */ if (CHECK_FLAG(peer->flags, PEER_FLAG_EXTENDED_OPT_PARAMS)) { - (void)bgp_open_capability(s, peer, true); + ext_opt_params = true; + (void)bgp_open_capability(s, peer, ext_opt_params); } else { struct stream *tmp = stream_new(STREAM_SIZE(s)); stream_copy(tmp, s); - if (bgp_open_capability(tmp, peer, false) - > BGP_OPEN_NON_EXT_OPT_LEN) { + if (bgp_open_capability(tmp, peer, ext_opt_params) > + BGP_OPEN_NON_EXT_OPT_LEN) { stream_free(tmp); - (void)bgp_open_capability(s, peer, true); + ext_opt_params = true; + (void)bgp_open_capability(s, peer, ext_opt_params); } else { stream_copy(s, tmp); stream_free(tmp); @@ -696,9 +699,10 @@ void bgp_open_send(struct peer_connection *connection) bgp_packet_set_size(s); if (bgp_debug_neighbor_events(peer)) - zlog_debug("%pBP fd %d sending OPEN, version %d, my as %u, holdtime %d, id %pI4", - peer, peer->connection->fd, BGP_VERSION_4, local_as, - send_holdtime, &peer->local_id); + zlog_debug("%pBP fd %d sending OPEN%s, version %d, my as %u, holdtime %d, id %pI4", + peer, peer->connection->fd, + ext_opt_params ? " (Extended)" : "", BGP_VERSION_4, + local_as, send_holdtime, &peer->local_id); /* Dump packet if debug option is set. */ /* bgp_packet_dump (s); */ From c4bbb5b4369133f5b76275700ec79e90411a490d Mon Sep 17 00:00:00 2001 From: Rajasekar Raja Date: Tue, 16 Jul 2024 23:34:15 -0700 Subject: [PATCH 200/347] bgpd: backpressure - fix ret value evpn_route_select_install The return value of evpn_route_select_install is ignored in all cases except during vni route table install/uninstall and based on the returned value, an error is logged. Fixing this. Ticket :#3992392 Signed-off-by: Rajasekar Raja --- bgpd/bgp_evpn.c | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index 75a7d85e88..9f0e267965 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -1490,11 +1490,12 @@ int evpn_route_select_install(struct bgp *bgp, struct bgpevpn *vpn, && !bgp_addpath_is_addpath_used(&bgp->tx_addpath, afi, safi)) { if (bgp_zebra_has_route_changed(old_select)) { if (CHECK_FLAG(bgp->flags, BGP_FLAG_DELETE_IN_PROGRESS)) - evpn_zebra_install(bgp, vpn, - (const struct prefix_evpn *) - bgp_dest_get_prefix( - dest), - old_select); + ret = evpn_zebra_install(bgp, vpn, + (const struct prefix_evpn + *) + bgp_dest_get_prefix( + dest), + old_select); else bgp_zebra_route_install(dest, old_select, bgp, true, vpn, false); @@ -1532,10 +1533,11 @@ int evpn_route_select_install(struct bgp *bgp, struct bgpevpn *vpn, && (new_select->sub_type == BGP_ROUTE_IMPORTED || bgp_evpn_attr_is_sync(new_select->attr))) { if (CHECK_FLAG(bgp->flags, BGP_FLAG_DELETE_IN_PROGRESS)) - evpn_zebra_install(bgp, vpn, - (const struct prefix_evpn *) - bgp_dest_get_prefix(dest), - new_select); + ret = evpn_zebra_install(bgp, vpn, + (const struct prefix_evpn *) + bgp_dest_get_prefix( + dest), + new_select); else bgp_zebra_route_install(dest, new_select, bgp, true, vpn, false); @@ -1559,11 +1561,12 @@ int evpn_route_select_install(struct bgp *bgp, struct bgpevpn *vpn, old_select->sub_type == BGP_ROUTE_IMPORTED) { if (CHECK_FLAG(bgp->flags, BGP_FLAG_DELETE_IN_PROGRESS) || CHECK_FLAG(bgp->flags, BGP_FLAG_VNI_DOWN)) - evpn_zebra_uninstall(bgp, vpn, - (const struct prefix_evpn *) - bgp_dest_get_prefix( - dest), - old_select, false); + ret = evpn_zebra_uninstall(bgp, vpn, + (const struct prefix_evpn + *) + bgp_dest_get_prefix( + dest), + old_select, false); else bgp_zebra_route_install(dest, old_select, bgp, false, vpn, false); From 6cf5b7931101c343f6efaa1668f72fdf156f51c7 Mon Sep 17 00:00:00 2001 From: Rajasekar Raja Date: Thu, 18 Jul 2024 22:23:23 -0700 Subject: [PATCH 201/347] bgpd: backpressure - log error for evpn when route install to zebra fails. log error for evpn in case route install to zebra fails. Ticket :#3992392 Signed-off-by: Rajasekar Raja --- bgpd/bgp_zebra.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 72620de7d9..2ab02bbafc 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -1785,6 +1785,7 @@ static void bgp_handle_route_announcements_to_zebra(struct event *e) struct bgp_table *table = NULL; enum zclient_send_status status = ZCLIENT_SEND_SUCCESS; bool install; + const struct prefix_evpn *evp = NULL; while (count < ZEBRA_ANNOUNCEMENTS_LIMIT) { is_evpn = false; @@ -1796,8 +1797,11 @@ static void bgp_handle_route_announcements_to_zebra(struct event *e) table = bgp_dest_table(dest); install = CHECK_FLAG(dest->flags, BGP_NODE_SCHEDULE_FOR_INSTALL); - if (table->afi == AFI_L2VPN && table->safi == SAFI_EVPN) + if (table->afi == AFI_L2VPN && table->safi == SAFI_EVPN) { is_evpn = true; + evp = (const struct prefix_evpn *)bgp_dest_get_prefix( + dest); + } if (BGP_DEBUG(zebra, ZEBRA)) zlog_debug("BGP %s%s route %pBD(%s) with dest %p and flags 0x%x to zebra", @@ -1835,6 +1839,17 @@ static void bgp_handle_route_announcements_to_zebra(struct event *e) UNSET_FLAG(dest->flags, BGP_NODE_SCHEDULE_FOR_DELETE); } + if (is_evpn && status == ZCLIENT_SEND_FAILURE) + flog_err(EC_BGP_EVPN_FAIL, + "%s (%u): Failed to %s EVPN %pFX %s route in VNI %u", + vrf_id_to_name(table->bgp->vrf_id), + table->bgp->vrf_id, + install ? "install" : "uninstall", evp, + evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE + ? "MACIP" + : "IMET", + dest->za_vpn->vni); + bgp_path_info_unlock(dest->za_bgp_pi); dest->za_bgp_pi = NULL; dest->za_vpn = NULL; From 8e5e19baaf88c82d8569ae6f3b950ba814e6184b Mon Sep 17 00:00:00 2001 From: Y Bharath Date: Tue, 16 Jul 2024 12:49:10 +0530 Subject: [PATCH 202/347] yang: Corrected range in yang file Corrected range in yang file Signed-off-by: y-bharath14 --- yang/frr-eigrpd.yang | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yang/frr-eigrpd.yang b/yang/frr-eigrpd.yang index f672dd5571..d3d9db2f62 100644 --- a/yang/frr-eigrpd.yang +++ b/yang/frr-eigrpd.yang @@ -75,7 +75,7 @@ module frr-eigrpd { typedef autonomous-system { description "Administrative domain identification for a network"; type uint16 { - range 1..65535; + range "1..65535"; } } From d022a4099c5476b78b2215fcc2f1c06559ceaf09 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Sat, 20 Jul 2024 03:29:21 +0300 Subject: [PATCH 203/347] tools: Do not append an empty list (pim_vrfs) to the config lines If pim_vrfs is empty, we append [] into the lines array, and the reload is broken since it expects only strings, but gets an array inside at the end. ``` Traceback (most recent call last): File "/usr/lib/frr/frr-reload.py", line 2227, in log.debug("New Frr Config\n%s", newconf.get_lines()) File "/usr/lib/frr/frr-reload.py", line 436, in get_lines return "\n".join(self.lines) TypeError: sequence item 45: expected str instance, list found ``` Fixes: 98d47f43fbba4e376c8351c724e8c625799805f7 ("tools: Fix frr-reload to support legacy pim configuration from file") Signed-off-by: Donatas Abraitis --- tools/frr-reload.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/frr-reload.py b/tools/frr-reload.py index 47e3637550..8a39f4204d 100755 --- a/tools/frr-reload.py +++ b/tools/frr-reload.py @@ -400,7 +400,8 @@ def load_from_file(self, filename): self.lines.append(line) - self.lines.append(pim_vrfs) + if len(pim_vrfs) > 0: + self.lines.append(pim_vrfs) self.load_contexts() From 01b7bd3b133e0d09d86ff7d626616c2a66606694 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Sat, 20 Jul 2024 03:30:08 +0300 Subject: [PATCH 204/347] tools: Apply black formatting for the recent frr-reload.py changes Signed-off-by: Donatas Abraitis --- tools/frr-reload.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/tools/frr-reload.py b/tools/frr-reload.py index 8a39f4204d..342c57964c 100755 --- a/tools/frr-reload.py +++ b/tools/frr-reload.py @@ -328,7 +328,10 @@ def load_from_file(self, filename): vrf_context = re_vrf.group(1) # Detect legacy pim commands that need to move under the router pim context - re_pim = re.match("^ip(v6)? pim ((ecmp|join|keep|mlag|packets|register|rp|send|spt|ssm).*)$", line) + re_pim = re.match( + "^ip(v6)? pim ((ecmp|join|keep|mlag|packets|register|rp|send|spt|ssm).*)$", + line, + ) if re_pim and re_pim.group(2): router_pim = "router pim" if re_pim.group(1): @@ -340,7 +343,7 @@ def load_from_file(self, filename): pim_vrfs.append(router_pim) pim_vrfs.append(re_pim.group(2)) pim_vrfs.append("exit") - line="# PIM VRF LINE MOVED TO ROUTER PIM" + line = "# PIM VRF LINE MOVED TO ROUTER PIM" else: self.lines.append(router_pim) self.lines.append(re_pim.group(2)) @@ -358,7 +361,7 @@ def load_from_file(self, filename): pim_vrfs.append(router_pim) pim_vrfs.append(re_pim.group(2)) pim_vrfs.append("exit") - line="# PIM VRF LINE MOVED TO ROUTER PIM" + line = "# PIM VRF LINE MOVED TO ROUTER PIM" else: self.lines.append(router_pim) self.lines.append(re_pim.group(2)) From 44ee7a4abe7f0a7fd56de75f762d328a63ec418c Mon Sep 17 00:00:00 2001 From: Carmine Scarpitta Date: Sun, 21 Jul 2024 09:36:28 +0200 Subject: [PATCH 205/347] tests: Fix warnings in `bgp_srv6l3vpn_to_bgp_vrf` When performing the `bgp_srv6l3vpn_to_bgp_vrf` topotest, the following warnings are observed: ``` 2024-07-21 08:01:51,390 WARNING: r1: Router(r1): proc failed: rc 127 pid 52974 args: /usr/bin/nsenter --mount=/proc/52322/ns/mnt --net=/proc/52322/ns/net --uts=/proc/52322/ns/uts -F /bin/bash -c /bin/bash /media/workspace/frr/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r1/setup.sh stdout: /bin/bash: /media/workspace/frr/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r1/setup.sh: No such file or directory stderr: *empty* 2024-07-21 08:01:51,522 WARNING: r2: Router(r2): proc failed: rc 127 pid 52984 args: /usr/bin/nsenter --mount=/proc/52397/ns/mnt --net=/proc/52397/ns/net --uts=/proc/52397/ns/uts -F /bin/bash -c /bin/bash /media/workspace/frr/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r2/setup.sh stdout: /bin/bash: /media/workspace/frr/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r2/setup.sh: No such file or directory stderr: *empty* 2024-07-21 08:01:51,632 WARNING: ce1: Router(ce1): proc failed: rc 127 pid 52994 args: /usr/bin/nsenter --mount=/proc/52472/ns/mnt --net=/proc/52472/ns/net --uts=/proc/52472/ns/uts -F /bin/bash -c /bin/bash /media/workspace/frr/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/ce1/setup.sh stdout: /bin/bash: /media/workspace/frr/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/ce1/setup.sh: No such file or directory stderr: *empty* 2024-07-21 08:01:51,757 WARNING: ce2: Router(ce2): proc failed: rc 127 pid 53004 args: /usr/bin/nsenter --mount=/proc/52547/ns/mnt --net=/proc/52547/ns/net --uts=/proc/52547/ns/uts -F /bin/bash -c /bin/bash /media/workspace/frr/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/ce2/setup.sh stdout: /bin/bash: /media/workspace/frr/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/ce2/setup.sh: No such file or directory stderr: *empty* 2024-07-21 08:01:51,878 WARNING: ce3: Router(ce3): proc failed: rc 127 pid 53014 args: /usr/bin/nsenter --mount=/proc/52622/ns/mnt --net=/proc/52622/ns/net --uts=/proc/52622/ns/uts -F /bin/bash -c /bin/bash /media/workspace/frr/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/ce3/setup.sh stdout: /bin/bash: /media/workspace/frr/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/ce3/setup.sh: No such file or directory stderr: *empty* 2024-07-21 08:01:51,997 WARNING: ce4: Router(ce4): proc failed: rc 127 pid 53024 args: /usr/bin/nsenter --mount=/proc/52697/ns/mnt --net=/proc/52697/ns/net --uts=/proc/52697/ns/uts -F /bin/bash -c /bin/bash /media/workspace/frr/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/ce4/setup.sh stdout: /bin/bash: /media/workspace/frr/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/ce4/setup.sh: No such file or directory stderr: *empty* 2024-07-21 08:01:52,109 WARNING: ce5: Router(ce5): proc failed: rc 127 pid 53034 args: /usr/bin/nsenter --mount=/proc/52772/ns/mnt --net=/proc/52772/ns/net --uts=/proc/52772/ns/uts -F /bin/bash -c /bin/bash /media/workspace/frr/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/ce5/setup.sh stdout: /bin/bash: /media/workspace/frr/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/ce5/setup.sh: No such file or directory stderr: *empty* 2024-07-21 08:01:52,225 WARNING: ce6: Router(ce6): proc failed: rc 127 pid 53044 args: /usr/bin/nsenter --mount=/proc/52847/ns/mnt --net=/proc/52847/ns/net --uts=/proc/52847/ns/uts -F /bin/bash -c /bin/bash /media/workspace/frr/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/ce6/setup.sh stdout: /bin/bash: /media/workspace/frr/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/ce6/setup.sh: No such file or directory stderr: *empty* ```` This occurs because the topotest attempts to execute the `setup.sh` file, and the file does not exist. Let's fix the issue by checking if the `setup.sh` file exists and executing it only if it does. Signed-off-by: Carmine Scarpitta --- .../bgp_srv6l3vpn_to_bgp_vrf/test_bgp_srv6l3vpn_to_bgp_vrf.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/test_bgp_srv6l3vpn_to_bgp_vrf.py b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/test_bgp_srv6l3vpn_to_bgp_vrf.py index 5d18083fd5..a6938668ad 100755 --- a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/test_bgp_srv6l3vpn_to_bgp_vrf.py +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/test_bgp_srv6l3vpn_to_bgp_vrf.py @@ -92,7 +92,8 @@ def setup_module(mod): tgen.start_topology() router_list = tgen.routers() for rname, router in tgen.routers().items(): - router.run("/bin/bash {}/{}/setup.sh".format(CWD, rname)) + if os.path.exists("{}/{}/setup.sh".format(CWD, rname)): + router.run("/bin/bash {}/{}/setup.sh".format(CWD, rname)) router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) From 5d76346266e3db37501494400ac96b714ebffc32 Mon Sep 17 00:00:00 2001 From: Carmine Scarpitta Date: Sun, 21 Jul 2024 09:36:47 +0200 Subject: [PATCH 206/347] tests: Fix warnings in `bgp_srv6l3vpn_to_bgp_vrf2` When performing the `bgp_srv6l3vpn_to_bgp_vrf2` topotest, the following warnings are observed: ``` 2024-07-21 08:01:51,390 WARNING: r1: Router(r1): proc failed: rc 127 pid 52974 args: /usr/bin/nsenter --mount=/proc/52322/ns/mnt --net=/proc/52322/ns/net --uts=/proc/52322/ns/uts -F /bin/bash -c /bin/bash /media/workspace/frr/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r1/setup.sh stdout: /bin/bash: /media/workspace/frr/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r1/setup.sh: No such file or directory stderr: *empty* 2024-07-21 08:01:51,522 WARNING: r2: Router(r2): proc failed: rc 127 pid 52984 args: /usr/bin/nsenter --mount=/proc/52397/ns/mnt --net=/proc/52397/ns/net --uts=/proc/52397/ns/uts -F /bin/bash -c /bin/bash /media/workspace/frr/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r2/setup.sh stdout: /bin/bash: /media/workspace/frr/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r2/setup.sh: No such file or directory stderr: *empty* 2024-07-21 08:01:51,632 WARNING: ce1: Router(ce1): proc failed: rc 127 pid 52994 args: /usr/bin/nsenter --mount=/proc/52472/ns/mnt --net=/proc/52472/ns/net --uts=/proc/52472/ns/uts -F /bin/bash -c /bin/bash /media/workspace/frr/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce1/setup.sh stdout: /bin/bash: /media/workspace/frr/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce1/setup.sh: No such file or directory stderr: *empty* 2024-07-21 08:01:51,757 WARNING: ce2: Router(ce2): proc failed: rc 127 pid 53004 args: /usr/bin/nsenter --mount=/proc/52547/ns/mnt --net=/proc/52547/ns/net --uts=/proc/52547/ns/uts -F /bin/bash -c /bin/bash /media/workspace/frr/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce2/setup.sh stdout: /bin/bash: /media/workspace/frr/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce2/setup.sh: No such file or directory stderr: *empty* 2024-07-21 08:01:51,878 WARNING: ce3: Router(ce3): proc failed: rc 127 pid 53014 args: /usr/bin/nsenter --mount=/proc/52622/ns/mnt --net=/proc/52622/ns/net --uts=/proc/52622/ns/uts -F /bin/bash -c /bin/bash /media/workspace/frr/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce3/setup.sh stdout: /bin/bash: /media/workspace/frr/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce3/setup.sh: No such file or directory stderr: *empty* 2024-07-21 08:01:51,997 WARNING: ce4: Router(ce4): proc failed: rc 127 pid 53024 args: /usr/bin/nsenter --mount=/proc/52697/ns/mnt --net=/proc/52697/ns/net --uts=/proc/52697/ns/uts -F /bin/bash -c /bin/bash /media/workspace/frr/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce4/setup.sh stdout: /bin/bash: /media/workspace/frr/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce4/setup.sh: No such file or directory stderr: *empty* 2024-07-21 08:01:52,109 WARNING: ce5: Router(ce5): proc failed: rc 127 pid 53034 args: /usr/bin/nsenter --mount=/proc/52772/ns/mnt --net=/proc/52772/ns/net --uts=/proc/52772/ns/uts -F /bin/bash -c /bin/bash /media/workspace/frr/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce5/setup.sh stdout: /bin/bash: /media/workspace/frr/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce5/setup.sh: No such file or directory stderr: *empty* 2024-07-21 08:01:52,225 WARNING: ce6: Router(ce6): proc failed: rc 127 pid 53044 args: /usr/bin/nsenter --mount=/proc/52847/ns/mnt --net=/proc/52847/ns/net --uts=/proc/52847/ns/uts -F /bin/bash -c /bin/bash /media/workspace/frr/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce6/setup.sh stdout: /bin/bash: /media/workspace/frr/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce6/setup.sh: No such file or directory stderr: *empty* ```` This occurs because the topotest attempts to execute the `setup.sh` file, and the file does not exist. Let's fix the issue by checking if the `setup.sh` file exists and executing it only if it does. Signed-off-by: Carmine Scarpitta --- .../test_bgp_srv6l3vpn_to_bgp_vrf2.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/test_bgp_srv6l3vpn_to_bgp_vrf2.py b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/test_bgp_srv6l3vpn_to_bgp_vrf2.py index 38baf43442..3e21875503 100755 --- a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/test_bgp_srv6l3vpn_to_bgp_vrf2.py +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/test_bgp_srv6l3vpn_to_bgp_vrf2.py @@ -56,7 +56,8 @@ def setup_module(mod): tgen = Topogen(build_topo, mod.__name__) tgen.start_topology() for rname, router in tgen.routers().items(): - router.run("/bin/bash {}/{}/setup.sh".format(CWD, rname)) + if os.path.exists("{}/{}/setup.sh".format(CWD, rname)): + router.run("/bin/bash {}/{}/setup.sh".format(CWD, rname)) router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) From e3282e26e44573dd261da9c02c62e520912c101c Mon Sep 17 00:00:00 2001 From: Carmine Scarpitta Date: Sun, 21 Jul 2024 09:37:06 +0200 Subject: [PATCH 207/347] tests: Fix warnings in `bgp_srv6l3vpn_to_bgp_vrf3` When performing the `bgp_srv6l3vpn_to_bgp_vrf3` topotest, the following warnings are observed: ``` 2024-07-21 08:01:51,390 WARNING: r1: Router(r1): proc failed: rc 127 pid 52974 args: /usr/bin/nsenter --mount=/proc/52322/ns/mnt --net=/proc/52322/ns/net --uts=/proc/52322/ns/uts -F /bin/bash -c /bin/bash /media/workspace/frr/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/setup.sh stdout: /bin/bash: /media/workspace/frr/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/setup.sh: No such file or directory stderr: *empty* 2024-07-21 08:01:51,522 WARNING: r2: Router(r2): proc failed: rc 127 pid 52984 args: /usr/bin/nsenter --mount=/proc/52397/ns/mnt --net=/proc/52397/ns/net --uts=/proc/52397/ns/uts -F /bin/bash -c /bin/bash /media/workspace/frr/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/setup.sh stdout: /bin/bash: /media/workspace/frr/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/setup.sh: No such file or directory stderr: *empty* 2024-07-21 08:01:51,632 WARNING: ce1: Router(ce1): proc failed: rc 127 pid 52994 args: /usr/bin/nsenter --mount=/proc/52472/ns/mnt --net=/proc/52472/ns/net --uts=/proc/52472/ns/uts -F /bin/bash -c /bin/bash /media/workspace/frr/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce1/setup.sh stdout: /bin/bash: /media/workspace/frr/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce1/setup.sh: No such file or directory stderr: *empty* 2024-07-21 08:01:51,757 WARNING: ce2: Router(ce2): proc failed: rc 127 pid 53004 args: /usr/bin/nsenter --mount=/proc/52547/ns/mnt --net=/proc/52547/ns/net --uts=/proc/52547/ns/uts -F /bin/bash -c /bin/bash /media/workspace/frr/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce2/setup.sh stdout: /bin/bash: /media/workspace/frr/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce2/setup.sh: No such file or directory stderr: *empty* 2024-07-21 08:01:51,878 WARNING: ce3: Router(ce3): proc failed: rc 127 pid 53014 args: /usr/bin/nsenter --mount=/proc/52622/ns/mnt --net=/proc/52622/ns/net --uts=/proc/52622/ns/uts -F /bin/bash -c /bin/bash /media/workspace/frr/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce3/setup.sh stdout: /bin/bash: /media/workspace/frr/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce3/setup.sh: No such file or directory stderr: *empty* 2024-07-21 08:01:51,997 WARNING: ce4: Router(ce4): proc failed: rc 127 pid 53024 args: /usr/bin/nsenter --mount=/proc/52697/ns/mnt --net=/proc/52697/ns/net --uts=/proc/52697/ns/uts -F /bin/bash -c /bin/bash /media/workspace/frr/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce4/setup.sh stdout: /bin/bash: /media/workspace/frr/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce4/setup.sh: No such file or directory stderr: *empty* 2024-07-21 08:01:52,109 WARNING: ce5: Router(ce5): proc failed: rc 127 pid 53034 args: /usr/bin/nsenter --mount=/proc/52772/ns/mnt --net=/proc/52772/ns/net --uts=/proc/52772/ns/uts -F /bin/bash -c /bin/bash /media/workspace/frr/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce5/setup.sh stdout: /bin/bash: /media/workspace/frr/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce5/setup.sh: No such file or directory stderr: *empty* 2024-07-21 08:01:52,225 WARNING: ce6: Router(ce6): proc failed: rc 127 pid 53044 args: /usr/bin/nsenter --mount=/proc/52847/ns/mnt --net=/proc/52847/ns/net --uts=/proc/52847/ns/uts -F /bin/bash -c /bin/bash /media/workspace/frr/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce6/setup.sh stdout: /bin/bash: /media/workspace/frr/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce6/setup.sh: No such file or directory stderr: *empty* ```` This occurs because the topotest attempts to execute the `setup.sh` file, and the file does not exist. Let's fix the issue by checking if the `setup.sh` file exists and executing it only if it does. Signed-off-by: Carmine Scarpitta --- .../test_bgp_srv6l3vpn_to_bgp_vrf3.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/test_bgp_srv6l3vpn_to_bgp_vrf3.py b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/test_bgp_srv6l3vpn_to_bgp_vrf3.py index 92a30788fc..2400cd2853 100644 --- a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/test_bgp_srv6l3vpn_to_bgp_vrf3.py +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/test_bgp_srv6l3vpn_to_bgp_vrf3.py @@ -53,7 +53,8 @@ def setup_module(mod): tgen = Topogen(build_topo, mod.__name__) tgen.start_topology() for rname, router in tgen.routers().items(): - router.run("/bin/bash {}/{}/setup.sh".format(CWD, rname)) + if os.path.exists("{}/{}/setup.sh".format(CWD, rname)): + router.run("/bin/bash {}/{}/setup.sh".format(CWD, rname)) router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) From 1f24bbe1813ff2a3e89dbfb27fec2b9d1daa6776 Mon Sep 17 00:00:00 2001 From: sri-mohan1 Date: Wed, 17 Jul 2024 12:32:53 +0530 Subject: [PATCH 208/347] bgpd: changes for code maintainability these changes are for improving the code maintainability and readability Signed-off-by: sri-mohan1 --- bgpd/bgpd.c | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 476a01b8ef..ec329d0c54 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -2283,7 +2283,7 @@ static void peer_group2peer_config_copy_af(struct peer_group *group, flags_tmp = conf->af_flags[afi][safi] & ~pflags_ovrd; flags_tmp ^= conf->af_flags_invert[afi][safi] ^ peer->af_flags_invert[afi][safi]; - flags_tmp &= ~pflags_ovrd; + UNSET_FLAG(flags_tmp, pflags_ovrd); UNSET_FLAG(peer->af_flags[afi][safi], ~pflags_ovrd); SET_FLAG(peer->af_flags[afi][safi], flags_tmp); @@ -2523,10 +2523,10 @@ int peer_activate(struct peer *peer, afi_t afi, safi_t safi) group = peer->group; for (ALL_LIST_ELEMENTS(group->peer, node, nnode, tmp_peer)) { - ret |= peer_activate_af(tmp_peer, afi, safi); + SET_FLAG(ret, peer_activate_af(tmp_peer, afi, safi)); } } else { - ret |= peer_activate_af(peer, afi, safi); + SET_FLAG(ret, peer_activate_af(peer, afi, safi)); } /* If this is the first peer to be activated for this @@ -2625,10 +2625,11 @@ int peer_deactivate(struct peer *peer, afi_t afi, safi_t safi) group = peer->group; for (ALL_LIST_ELEMENTS(group->peer, node, nnode, tmp_peer)) { - ret |= non_peergroup_deactivate_af(tmp_peer, afi, safi); + SET_FLAG(ret, non_peergroup_deactivate_af(tmp_peer, afi, + safi)); } } else { - ret |= non_peergroup_deactivate_af(peer, afi, safi); + SET_FLAG(ret, non_peergroup_deactivate_af(peer, afi, safi)); } bgp = peer->bgp; @@ -2930,9 +2931,9 @@ static void peer_group2peer_config_copy(struct peer_group *group, peer->gtsm_hops = conf->gtsm_hops; /* peer flags apply */ - flags_tmp = conf->flags & ~peer->flags_override; + flags_tmp = CHECK_FLAG(conf->flags, ~peer->flags_override); flags_tmp ^= conf->flags_invert ^ peer->flags_invert; - flags_tmp &= ~peer->flags_override; + UNSET_FLAG(flags_tmp, peer->flags_override); UNSET_FLAG(peer->flags, ~peer->flags_override); SET_FLAG(peer->flags, flags_tmp); @@ -4758,7 +4759,7 @@ static int peer_flag_action_set(const struct peer_flag_action *action_list, if (match->flag == 0) break; - if (match->flag & flag) { + if (CHECK_FLAG(match->flag, flag)) { found = 1; if (match->type == peer_change_reset_in) @@ -5085,15 +5086,17 @@ static int peer_af_flag_modify(struct peer *peer, afi_t afi, safi_t safi, ptype = peer_sort(peer); /* Special check for reflector client. */ - if (flag & PEER_FLAG_REFLECTOR_CLIENT && ptype != BGP_PEER_IBGP) + if (CHECK_FLAG(flag, PEER_FLAG_REFLECTOR_CLIENT) && + ptype != BGP_PEER_IBGP) return BGP_ERR_NOT_INTERNAL_PEER; /* Special check for remove-private-AS. */ - if (flag & PEER_FLAG_REMOVE_PRIVATE_AS && ptype == BGP_PEER_IBGP) + if (CHECK_FLAG(flag, PEER_FLAG_REMOVE_PRIVATE_AS) && + ptype == BGP_PEER_IBGP) return BGP_ERR_REMOVE_PRIVATE_AS; /* as-override is not allowed for IBGP peers */ - if (flag & PEER_FLAG_AS_OVERRIDE && ptype == BGP_PEER_IBGP) + if (CHECK_FLAG(flag, PEER_FLAG_AS_OVERRIDE) && ptype == BGP_PEER_IBGP) return BGP_ERR_AS_OVERRIDE; /* Handle flag updates where desired state matches current state. */ @@ -5144,7 +5147,7 @@ static int peer_af_flag_modify(struct peer *peer, afi_t afi, safi_t safi, * If the peer is a route server client let's not * muck with the nexthop on the way out the door */ - if (flag & PEER_FLAG_RSERVER_CLIENT) { + if (CHECK_FLAG(flag, PEER_FLAG_RSERVER_CLIENT)) { if (set) SET_FLAG(peer->af_flags[afi][safi], PEER_FLAG_NEXTHOP_UNCHANGED); From ed832b70ec0ea7ad0cf22a844de2151592b5b0e8 Mon Sep 17 00:00:00 2001 From: Y Bharath Date: Mon, 22 Jul 2024 16:47:54 +0530 Subject: [PATCH 209/347] yang: Added missed prefix to the yang file Corrected warning by including the module Signed-off-by: y-bharath14 --- yang/ietf/frr-deviations-ietf-routing.yang | 3 +++ 1 file changed, 3 insertions(+) diff --git a/yang/ietf/frr-deviations-ietf-routing.yang b/yang/ietf/frr-deviations-ietf-routing.yang index 15ceb6b929..5c0ae30bea 100644 --- a/yang/ietf/frr-deviations-ietf-routing.yang +++ b/yang/ietf/frr-deviations-ietf-routing.yang @@ -6,6 +6,9 @@ module frr-deviations-ietf-routing { import ietf-routing { prefix ietf-routing; } + import ietf-rip { + prefix ietf-rip; + } organization "FRRouting"; From 7afd7d99f2fa39be073625c630d46f96e5dd66a5 Mon Sep 17 00:00:00 2001 From: Christian Hopps Date: Mon, 22 Jul 2024 07:52:10 -0400 Subject: [PATCH 210/347] lib: move non-error from __log_err to __dbg Additionally, print `errmsg_if_any` in successful debug messages if non-NULL. fixes #16386 #16043 Signed-off-by: Christian Hopps --- lib/vty.c | 15 +++++++++------ mgmtd/mgmt_txn.c | 6 +++--- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/lib/vty.c b/lib/vty.c index 0dcd118a97..ecb5383a53 100644 --- a/lib/vty.c +++ b/lib/vty.c @@ -3591,8 +3591,9 @@ static void vty_mgmt_set_config_result_notified( vty_out(vty, "%s\n", errmsg_if_any); } else { debug_fe_client("SET_CONFIG request for client 0x%" PRIx64 - " req-id %" PRIu64 " was successfull", - client_id, req_id); + " req-id %" PRIu64 " was successfull%s%s", + client_id, req_id, errmsg_if_any ? ": " : "", + errmsg_if_any ?: ""); } if (implicit_commit) { @@ -3624,8 +3625,9 @@ static void vty_mgmt_commit_config_result_notified( vty_out(vty, "%s\n", errmsg_if_any); } else { debug_fe_client("COMMIT_CONFIG request for client 0x%" PRIx64 - " req-id %" PRIu64 " was successfull", - client_id, req_id); + " req-id %" PRIu64 " was successfull%s%s", + client_id, req_id, errmsg_if_any ? ": " : "", + errmsg_if_any ?: ""); if (errmsg_if_any) vty_out(vty, "MGMTD: %s\n", errmsg_if_any); } @@ -3656,8 +3658,9 @@ static int vty_mgmt_get_data_result_notified( } debug_fe_client("GET_DATA request succeeded, client 0x%" PRIx64 - " req-id %" PRIu64, - client_id, req_id); + " req-id %" PRIu64 "%s%s", + client_id, req_id, errmsg_if_any ? ": " : "", + errmsg_if_any ?: ""); if (req_id != mgmt_last_req_id) { mgmt_last_req_id = req_id; diff --git a/mgmtd/mgmt_txn.c b/mgmtd/mgmt_txn.c index 0a80b3bbf7..0f0cccbbd4 100644 --- a/mgmtd/mgmt_txn.c +++ b/mgmtd/mgmt_txn.c @@ -980,8 +980,8 @@ static int mgmt_txn_create_config_batches(struct mgmt_txn_req *txn_req, } if (!chg_clients) - __log_err("No connected daemon is interested in XPATH %s", - xpath); + __dbg("Daemons interested in XPATH are not currently connected: %s", + xpath); cmtcfg_req->clients |= chg_clients; @@ -992,7 +992,7 @@ static int mgmt_txn_create_config_batches(struct mgmt_txn_req *txn_req, if (!num_chgs) { (void)mgmt_txn_send_commit_cfg_reply(txn_req->txn, MGMTD_NO_CFG_CHANGES, - "No changes found to commit!"); + "No connected daemons interested in changes"); return -1; } From 7b0b8a8b089d20841bde03eb009a7d1db929fa75 Mon Sep 17 00:00:00 2001 From: Jafar Al-Gharaibeh Date: Mon, 22 Jul 2024 11:19:50 -0500 Subject: [PATCH 211/347] pimd: fix compile warnings Signed-off-by: Jafar Al-Gharaibeh --- pimd/pim_cmd.c | 14 +++++++------- pimd/pim_cmd_common.c | 10 +++++----- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index 2b8d3e56e5..92214eced4 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -1457,7 +1457,7 @@ static void clear_interfaces(struct pim_instance *pim) static void pim_cli_legacy_mesh_group_behavior(struct vty *vty, const char *gname) { - char xpath_value[XPATH_MAXLEN]; + char xpath_value[XPATH_MAXLEN + 26]; char xpath_member_value[XPATH_MAXLEN]; const struct lyd_node *member_dnode; @@ -4314,7 +4314,7 @@ DEFPY (no_pim_ssm_prefix_list_name, "Name of a prefix-list\n") { const struct lyd_node *ssm_plist_dnode; - char ssm_plist_xpath[XPATH_MAXLEN]; + char ssm_plist_xpath[XPATH_MAXLEN + 16]; const char *ssm_plist_name; snprintf(ssm_plist_xpath, sizeof(ssm_plist_xpath), "%s/ssm-prefix-list", @@ -4350,7 +4350,7 @@ DEFPY_ATTR(no_ip_pim_ssm_prefix_list_name, CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) { const struct lyd_node *ssm_plist_dnode; - char ssm_plist_xpath[XPATH_MAXLEN]; + char ssm_plist_xpath[XPATH_MAXLEN + 16]; const char *ssm_plist_name; int ret = CMD_WARNING_CONFIG_FAILED; const char *vrfname; @@ -6574,7 +6574,7 @@ DEFPY(no_pim_msdp_mesh_group_member, "Mesh group member\n" "Peer IP address\n") { - char xpath_value[XPATH_MAXLEN]; + char xpath_value[XPATH_MAXLEN + 26]; char xpath_member_value[XPATH_MAXLEN]; /* Get mesh group base XPath. */ @@ -6620,7 +6620,7 @@ DEFPY_ATTR(no_ip_pim_msdp_mesh_group_member, "Peer IP address\n", CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) { - char xpath_value[XPATH_MAXLEN]; + char xpath_value[XPATH_MAXLEN + 26]; char xpath_member_value[XPATH_MAXLEN]; int ret = CMD_WARNING_CONFIG_FAILED; const char *vrfname; @@ -6852,7 +6852,7 @@ DEFPY(no_pim_msdp_mesh_group, "Delete MSDP mesh-group\n" "Mesh group name\n") { - char xpath_value[XPATH_MAXLEN]; + char xpath_value[XPATH_MAXLEN + 26]; /* Get mesh group base XPath. */ snprintf(xpath_value, sizeof(xpath_value), @@ -6873,7 +6873,7 @@ DEFPY_ATTR(no_ip_pim_msdp_mesh_group, "Mesh group name\n", CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) { - char xpath_value[XPATH_MAXLEN]; + char xpath_value[XPATH_MAXLEN + 26]; int ret = CMD_SUCCESS; const char *vrfname; char xpath[XPATH_MAXLEN]; diff --git a/pimd/pim_cmd_common.c b/pimd/pim_cmd_common.c index c6cb28c097..d1368ff1ff 100644 --- a/pimd/pim_cmd_common.c +++ b/pimd/pim_cmd_common.c @@ -100,8 +100,8 @@ int pim_process_no_join_prune_cmd(struct vty *vty) int pim_process_spt_switchover_infinity_cmd(struct vty *vty) { - char spt_plist_xpath[XPATH_MAXLEN]; - char spt_action_xpath[XPATH_MAXLEN]; + char spt_plist_xpath[XPATH_MAXLEN + 40]; + char spt_action_xpath[XPATH_MAXLEN + 26]; snprintf(spt_plist_xpath, sizeof(spt_plist_xpath), "%s/spt-switchover/spt-infinity-prefix-list", VTY_CURR_XPATH); @@ -522,7 +522,7 @@ int pim_process_no_rp_cmd(struct vty *vty, const char *rp_str, const char *group_str) { char group_xpath[XPATH_MAXLEN]; - char rp_xpath[XPATH_MAXLEN]; + char rp_xpath[XPATH_MAXLEN + 47]; int printed; const struct lyd_node *group_dnode; @@ -568,8 +568,8 @@ int pim_process_rp_plist_cmd(struct vty *vty, const char *rp_str, int pim_process_no_rp_plist_cmd(struct vty *vty, const char *rp_str, const char *prefix_list) { - char rp_xpath[XPATH_MAXLEN]; - char plist_xpath[XPATH_MAXLEN]; + char rp_xpath[XPATH_MAXLEN + 47]; + char plist_xpath[XPATH_MAXLEN + 1070]; const struct lyd_node *plist_dnode; const char *plist; From 40965e599975b019bbe6f4b1dfb3ff22d8980876 Mon Sep 17 00:00:00 2001 From: Rajasekar Raja Date: Mon, 22 Jul 2024 10:13:19 -0700 Subject: [PATCH 212/347] bgpd: backpressure - Avoid use after free Coverity complains there is a use after free (1598495 and 1598496) At this point, most likely dest->refcount cannot go 1 and free up the dest, but there might be some code path where this can happen. Fixing this with a simple order change (no harm fix). Ticket :#4001204 Signed-off-by: Rajasekar Raja --- bgpd/bgp_evpn.c | 2 +- bgpd/bgpd.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index baf1d4ca6d..7706a3eca4 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -6339,9 +6339,9 @@ void bgp_evpn_free(struct bgp *bgp, struct bgpevpn *vpn) dest = dest_next) { dest_next = zebra_announce_next(&bm->zebra_announce_head, dest); if (dest->za_vpn == vpn) { + zebra_announce_del(&bm->zebra_announce_head, dest); bgp_path_info_unlock(dest->za_bgp_pi); bgp_dest_unlock_node(dest); - zebra_announce_del(&bm->zebra_announce_head, dest); } } diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index ec329d0c54..043a6e201c 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -3954,9 +3954,9 @@ int bgp_delete(struct bgp *bgp) dest_next = zebra_announce_next(&bm->zebra_announce_head, dest); dest_table = bgp_dest_table(dest); if (dest_table->bgp == bgp) { + zebra_announce_del(&bm->zebra_announce_head, dest); bgp_path_info_unlock(dest->za_bgp_pi); bgp_dest_unlock_node(dest); - zebra_announce_del(&bm->zebra_announce_head, dest); } } From 8916953b534f64a7545860ad5b4b36dc2544f33a Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 23 Jul 2024 10:21:42 -0700 Subject: [PATCH 213/347] build: fix a few python string escape warnings When using a regex (or anything that uses `\?` escapes) in python, raw strings (`r"content"`) should be used so python doesn't consume the escapes itself. Otherwise we get either broken behavior and/or `SyntaxWarning: invalid escape sequence '\['` Signed-off-by: David Lamparter --- doc/developer/conf.py | 2 +- doc/manpages/conf.py | 2 +- doc/user/conf.py | 2 +- python/firstheader.py | 2 +- python/makefile.py | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/developer/conf.py b/doc/developer/conf.py index 6a3ffe1638..76dd1e4f28 100644 --- a/doc/developer/conf.py +++ b/doc/developer/conf.py @@ -96,7 +96,7 @@ # extract version information, installation location, other stuff we need to # use when building final documents -val = re.compile('^S\["([^"]+)"\]="(.*)"$') +val = re.compile(r'^S\["([^"]+)"\]="(.*)"$') try: with open("../../config.status", "r") as cfgstatus: for ln in cfgstatus.readlines(): diff --git a/doc/manpages/conf.py b/doc/manpages/conf.py index 73dea094ae..995885b220 100644 --- a/doc/manpages/conf.py +++ b/doc/manpages/conf.py @@ -91,7 +91,7 @@ # extract version information, installation location, other stuff we need to # use when building final documents -val = re.compile('^S\["([^"]+)"\]="(.*)"$') +val = re.compile(r'^S\["([^"]+)"\]="(.*)"$') try: with open("../../config.status", "r") as cfgstatus: for ln in cfgstatus.readlines(): diff --git a/doc/user/conf.py b/doc/user/conf.py index 395875520d..18f048bc08 100644 --- a/doc/user/conf.py +++ b/doc/user/conf.py @@ -96,7 +96,7 @@ # extract version information, installation location, other stuff we need to # use when building final documents -val = re.compile('^S\["([^"]+)"\]="(.*)"$') +val = re.compile(r'^S\["([^"]+)"\]="(.*)"$') try: with open("../../config.status", "r") as cfgstatus: for ln in cfgstatus.readlines(): diff --git a/python/firstheader.py b/python/firstheader.py index 06e2895845..1a3cadfd5e 100644 --- a/python/firstheader.py +++ b/python/firstheader.py @@ -15,7 +15,7 @@ argp.add_argument("--warn-empty", action="store_const", const=True) argp.add_argument("--pipe", action="store_const", const=True) -include_re = re.compile('^#\s*include\s+["<]([^ ">]+)[">]', re.M) +include_re = re.compile(r'^#\s*include\s+["<]([^ ">]+)[">]', re.M) ignore = [ lambda fn: fn.startswith("tools/"), diff --git a/python/makefile.py b/python/makefile.py index 573871fb68..45f032296f 100644 --- a/python/makefile.py +++ b/python/makefile.py @@ -91,7 +91,7 @@ autoderp = "#AUTODERP# " out_lines = [] bcdeps = [] -make_rule_re = re.compile("^([^:\s]+):\s*([^:\s]+)\s*($|\n)") +make_rule_re = re.compile(r"^([^:\s]+):\s*([^:\s]+)\s*($|\n)") while lines: line = lines.pop(0) From be9a6fc0ea8180a4aaa558c5402ea543427e2e7e Mon Sep 17 00:00:00 2001 From: Christian Hopps Date: Tue, 23 Jul 2024 17:42:07 -0400 Subject: [PATCH 214/347] lib: mgmtd: fix too early daemon detach of mgmtd Correct FRR startup counts on a daemon's vty socket to be open when the parent process exits. The parent process waits for `frr_check_detach()` to be called by the child before exiting. The problem is when the `FRR_MANUAL_VTY_START` flag is set the vty socket was not opened but `frr_check_detach()` was called anyway. Instead add a bool option for `frr_check_detach()` to be called when the socket is opened with `frr_vty_serv_start()`, and do so when "manually" calling said function (i.e., when FRR_MANUAL_VTY_START is set). The `FRR_MANUAL_VTY_START` flag is only set by mgmtd. The reason we wait to open the vty socket is so that mgmtd can parse the various daemon specific config files it has taken over, after the event loop has started, but before we receive any possible new config from `vtysh`. fixes #16362 Signed-off-by: Christian Hopps --- lib/libfrr.c | 30 +++++++++++++++++------------- lib/libfrr.h | 2 +- lib/vty.c | 2 +- 3 files changed, 19 insertions(+), 15 deletions(-) diff --git a/lib/libfrr.c b/lib/libfrr.c index 338a7d0340..328c6ec8b2 100644 --- a/lib/libfrr.c +++ b/lib/libfrr.c @@ -1051,7 +1051,17 @@ void frr_config_fork(void) zlog_tls_buffer_init(); } -void frr_vty_serv_start(void) +static void frr_check_detach(void) +{ + if (nodetach_term || nodetach_daemon) + return; + + if (daemon_ctl_sock != -1) + close(daemon_ctl_sock); + daemon_ctl_sock = -1; +} + +void frr_vty_serv_start(bool check_detach) { /* allow explicit override of vty_path in the future * (not currently set anywhere) */ @@ -1074,6 +1084,9 @@ void frr_vty_serv_start(void) } vty_serv_start(di->vty_addr, di->vty_port, di->vty_path); + + if (check_detach) + frr_check_detach(); } void frr_vty_serv_stop(void) @@ -1084,16 +1097,6 @@ void frr_vty_serv_stop(void) unlink(di->vty_path); } -static void frr_check_detach(void) -{ - if (nodetach_term || nodetach_daemon) - return; - - if (daemon_ctl_sock != -1) - close(daemon_ctl_sock); - daemon_ctl_sock = -1; -} - static void frr_terminal_close(int isexit) { int nullfd; @@ -1179,7 +1182,7 @@ void frr_run(struct event_loop *master) char instanceinfo[64] = ""; if (!(di->flags & FRR_MANUAL_VTY_START)) - frr_vty_serv_start(); + frr_vty_serv_start(false); if (di->instance) snprintf(instanceinfo, sizeof(instanceinfo), "instance %u ", @@ -1217,7 +1220,8 @@ void frr_run(struct event_loop *master) close(nullfd); } - frr_check_detach(); + if (!(di->flags & FRR_MANUAL_VTY_START)) + frr_check_detach(); } /* end fixed stderr startup logging */ diff --git a/lib/libfrr.h b/lib/libfrr.h index 8018672c1a..3248670c83 100644 --- a/lib/libfrr.h +++ b/lib/libfrr.h @@ -202,7 +202,7 @@ extern void frr_config_fork(void); extern void frr_run(struct event_loop *master); extern void frr_detach(void); -extern void frr_vty_serv_start(void); +extern void frr_vty_serv_start(bool check_detach); extern void frr_vty_serv_stop(void); extern bool frr_zclient_addr(struct sockaddr_storage *sa, socklen_t *sa_len, diff --git a/lib/vty.c b/lib/vty.c index ecb5383a53..d0bbf0e61a 100644 --- a/lib/vty.c +++ b/lib/vty.c @@ -3502,7 +3502,7 @@ static void vty_mgmt_server_connected(struct mgmt_fe_client *client, /* Start or stop listening for vty connections */ if (connected) - frr_vty_serv_start(); + frr_vty_serv_start(true); else frr_vty_serv_stop(); } From 15fb7209eede6226bbe15a9618a8d06b88d44a08 Mon Sep 17 00:00:00 2001 From: Louis Scalbert Date: Mon, 22 Jul 2024 10:57:21 +0200 Subject: [PATCH 215/347] bgpd: fix ipv4-mapped ipv6 for ipv6 over ipv4 peer When IPv6 prefixes are sent over an IPv4 session, the UPDATE is sent with a link-local nexthop as global nexthop instead of a IPv4-mapped IPv6 address. If the peer interface has no IPv6 address, routes are not installed. Seen with bgp_nexthop_mp_ipv4_6 topotests on step2: > root@r2:/# vtysh -c 'show bgp ipv6 fd00:100::/64 json' | jq . > { > "prefix": "fd00:100::/64", > "paths": [ > { > "nexthops": [ > { > "ip": "fe80::449a:f8ff:fe67:1f93", > "hostname": "r1", > "afi": "ipv6", > "scope": "global", > "metric": 0, > "accessible": true > }, > { > "ip": "fe80::449a:f8ff:fe67:1f93", > "hostname": "r1", > "afi": "ipv6", > "scope": "link-local", > "accessible": true, > "used": true > } > ], > } > ] > } Now: > root@r2:/# vtysh -c 'show bgp ipv6 fd00:100::/64 json' | jq . > { > "prefix": "fd00:100::/64", > "paths": [ > "nexthops": [ > { > "ip": "::ffff:172.16.0.1", > "hostname": "r1", > "afi": "ipv6", > "scope": "global", > "metric": 0, > "accessible": true > }, > { > "ip": "fe80::3842:28ff:fe90:f815", > "hostname": "r1", > "afi": "ipv6", > "scope": "link-local", > "accessible": true, > "used": true > } > ], > } > ] > } Note that the link-local is still preferred over the global address. Fixes: 25995695f5 ("bgpd: set ipv4-mapped ipv6 for ipv4 with ipv6 nexthop") Signed-off-by: Louis Scalbert --- bgpd/bgp_updgrp_packet.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/bgpd/bgp_updgrp_packet.c b/bgpd/bgp_updgrp_packet.c index 6e30d4f846..468bf47715 100644 --- a/bgpd/bgp_updgrp_packet.c +++ b/bgpd/bgp_updgrp_packet.c @@ -526,8 +526,10 @@ struct stream *bpacket_reformat_for_peer(struct bpacket *pkt, if (peer->nexthop.v4.s_addr != INADDR_ANY && (IN6_IS_ADDR_UNSPECIFIED(mod_v6nhg) || (IN6_IS_ADDR_LINKLOCAL(mod_v6nhg) && - peer->connection->su.sa.sa_family == AF_INET6 && - paf->afi == AFI_IP))) { + ((peer->connection->su.sa.sa_family == AF_INET6 && + paf->afi == AFI_IP) || + (peer->connection->su.sa.sa_family == AF_INET && + paf->afi == AFI_IP6))))) { ipv4_to_ipv4_mapped_ipv6(mod_v6nhg, peer->nexthop.v4); gnh_modified = 1; } From 6e8897fcf527299f546c4a26ef020e4d30fd68ed Mon Sep 17 00:00:00 2001 From: Louis Scalbert Date: Mon, 22 Jul 2024 16:17:40 +0200 Subject: [PATCH 216/347] bgpd: fix nexthop resolution of ipv4-mapped ipv6 Fix nexthop resolution of ipv4-mapped ipv6 nexthop addresses. Fixes: 5dd731af84 ("bgpd: prefer link-local to a ipv4-mapped ipv6 global") Signed-off-by: Louis Scalbert --- bgpd/bgp_nht.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c index 8ce45558e9..67e7463fe4 100644 --- a/bgpd/bgp_nht.c +++ b/bgpd/bgp_nht.c @@ -351,7 +351,9 @@ int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop, } return 0; } - + if (afi == AFI_IP6 && p.family == AF_INET) + /* IPv4 mapped IPv6 nexthop address */ + afi = AFI_IP; srte_color = bgp_attr_get_color(pi->attr); } else if (peer) { @@ -1078,14 +1080,25 @@ static int make_prefix(int afi, struct bgp_path_info *pi, struct prefix *p) &ipv4); p->u.prefix4 = ipv4; p->prefixlen = IPV4_MAX_BITLEN; + p->family = AF_INET; } else p->u.prefix6 = pi->attr->mp_nexthop_global; } else p->u.prefix6 = pi->attr->mp_nexthop_local; - } else - p->u.prefix6 = pi->attr->mp_nexthop_global; + } else { + if (IS_MAPPED_IPV6( + &pi->attr->mp_nexthop_global)) { + ipv4_mapped_ipv6_to_ipv4(&pi->attr->mp_nexthop_global, + &ipv4); + p->u.prefix4 = ipv4; + p->prefixlen = IPV4_MAX_BITLEN; + p->family = AF_INET; + } else + p->u.prefix6 = + pi->attr->mp_nexthop_global; + } } break; default: From 5d2289db26803caed3533706076523c670754b6e Mon Sep 17 00:00:00 2001 From: Louis Scalbert Date: Tue, 23 Jul 2024 10:26:36 +0200 Subject: [PATCH 217/347] bgpd: replace ipv4-mapped ipv6 at update forwarding Replace IPv4-mapped IPv6 at update forwarding because the peer may not be able to create a route with the IPv4-mapped IPv6. Signed-off-by: Louis Scalbert --- bgpd/bgp_updgrp_packet.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/bgpd/bgp_updgrp_packet.c b/bgpd/bgp_updgrp_packet.c index 468bf47715..12feac8353 100644 --- a/bgpd/bgp_updgrp_packet.c +++ b/bgpd/bgp_updgrp_packet.c @@ -508,6 +508,9 @@ struct stream *bpacket_reformat_for_peer(struct bpacket *pkt, gnh_modified = 1; } } else if (IN6_IS_ADDR_UNSPECIFIED(&v6nhglobal)) { + /* the UPDATE is originating from the local router. + * Build the global nexthop. + */ mod_v6nhg = &peer->nexthop.v6_global; gnh_modified = 1; } else if ((peer->sort == BGP_PEER_EBGP) @@ -521,6 +524,14 @@ struct stream *bpacket_reformat_for_peer(struct bpacket *pkt, */ mod_v6nhg = &peer->nexthop.v6_global; gnh_modified = 1; + } else if (IS_MAPPED_IPV6(&v6nhglobal) && + !IN6_IS_ADDR_LINKLOCAL(&peer->nexthop.v6_global)) { + /* prefer a IPv6 native global address over + * an IPv4-mapped IPv6 address as nexthop when + * forwarding UPDATEs. + */ + mod_v6nhg = &peer->nexthop.v6_global; + gnh_modified = 1; } if (peer->nexthop.v4.s_addr != INADDR_ANY && @@ -535,6 +546,10 @@ struct stream *bpacket_reformat_for_peer(struct bpacket *pkt, } if (IS_MAPPED_IPV6(&peer->nexthop.v6_global)) { + /* If the interface to the peer has no global IPv6 + * address, replace the nexthop in UPDATE with + * the IPv4-mapped IPv6 address if any. + */ mod_v6nhg = &peer->nexthop.v6_global; gnh_modified = 1; } From d61843621140cb8c5730786fb7ce738f3ce72e72 Mon Sep 17 00:00:00 2001 From: Louis Scalbert Date: Tue, 23 Jul 2024 10:38:04 +0200 Subject: [PATCH 218/347] topotests: bgp_nexthop_mp_ipv4_6, test ipv4-mapped Test that a IPv4-mapped IPv6 is sent from a peer that has no global IPv6 address. Signed-off-by: Louis Scalbert --- tests/topotests/bgp_nexthop_mp_ipv4_6/r2/bgp_ipv6_step2.json | 5 +++++ tests/topotests/bgp_nexthop_mp_ipv4_6/r3/bgp_ipv6_step2.json | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r2/bgp_ipv6_step2.json b/tests/topotests/bgp_nexthop_mp_ipv4_6/r2/bgp_ipv6_step2.json index 21f36089b6..6738d45750 100644 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r2/bgp_ipv6_step2.json +++ b/tests/topotests/bgp_nexthop_mp_ipv4_6/r2/bgp_ipv6_step2.json @@ -6,6 +6,11 @@ "bestpath": true, "path": "65100", "nexthops": [ + { + "ip": "::ffff:ac10:1", + "afi": "ipv6", + "scope": "global" + }, { "afi": "ipv6", "scope": "link-local", diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r3/bgp_ipv6_step2.json b/tests/topotests/bgp_nexthop_mp_ipv4_6/r3/bgp_ipv6_step2.json index 21f36089b6..807806ff8d 100644 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r3/bgp_ipv6_step2.json +++ b/tests/topotests/bgp_nexthop_mp_ipv4_6/r3/bgp_ipv6_step2.json @@ -6,6 +6,11 @@ "bestpath": true, "path": "65100", "nexthops": [ + { + "ip": "::ffff:ac10:101", + "afi": "ipv6", + "scope": "global" + }, { "afi": "ipv6", "scope": "link-local", From 91e67abb610d6d39d304c24b2233a38b8c26e08a Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Wed, 24 Jul 2024 14:30:32 +0300 Subject: [PATCH 219/347] tests: Delay initial OPEN after we do `clear bgp` Under some circumstances it might happen that the session is quickly UP in the middle of `clear bgp ...` and `shutdown`. That leads to session be UP, and the stale routes being cleared quickly. Signed-off-by: Donatas Abraitis --- tests/topotests/bgp_gr_notification/r1/bgpd.conf | 2 +- tests/topotests/bgp_gr_notification/r2/bgpd.conf | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/topotests/bgp_gr_notification/r1/bgpd.conf b/tests/topotests/bgp_gr_notification/r1/bgpd.conf index 6119f67436..0af042f6be 100644 --- a/tests/topotests/bgp_gr_notification/r1/bgpd.conf +++ b/tests/topotests/bgp_gr_notification/r1/bgpd.conf @@ -3,7 +3,7 @@ router bgp 65001 bgp graceful-restart neighbor 192.168.255.2 remote-as external neighbor 192.168.255.2 timers 1 3 - neighbor 192.168.255.2 timers connect 1 + neighbor 192.168.255.2 timers delayopen 10 address-family ipv4 redistribute connected exit-address-family diff --git a/tests/topotests/bgp_gr_notification/r2/bgpd.conf b/tests/topotests/bgp_gr_notification/r2/bgpd.conf index 05e17f0564..8325e21d2c 100644 --- a/tests/topotests/bgp_gr_notification/r2/bgpd.conf +++ b/tests/topotests/bgp_gr_notification/r2/bgpd.conf @@ -4,7 +4,7 @@ router bgp 65002 bgp graceful-restart neighbor 192.168.255.1 remote-as external neighbor 192.168.255.1 timers 1 3 - neighbor 192.168.255.1 timers connect 1 + neighbor 192.168.255.1 timers delayopen 10 address-family ipv4 redistribute connected exit-address-family From 45f80de734db1ecc677096f743d0f8cacdb6528d Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Wed, 24 Jul 2024 15:30:43 +0300 Subject: [PATCH 220/347] bgpd: Pass a connection struct directly for EVENT_OFF() Signed-off-by: Donatas Abraitis --- bgpd/bgp_fsm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index 76624fee9e..b67cf3b874 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -1482,7 +1482,7 @@ enum bgp_fsm_state_progress bgp_stop(struct peer_connection *connection) EVENT_OFF(connection->t_connect); EVENT_OFF(connection->t_holdtime); EVENT_OFF(connection->t_routeadv); - EVENT_OFF(peer->connection->t_delayopen); + EVENT_OFF(connection->t_delayopen); /* Clear input and output buffer. */ frr_with_mutex (&connection->io_mtx) { From 0a68626e48e0786c043562bb029e99f69b43fb6d Mon Sep 17 00:00:00 2001 From: Carmine Scarpitta Date: Wed, 24 Jul 2024 23:38:04 +0200 Subject: [PATCH 221/347] zebra: Remove duplicate `#include ` Signed-off-by: Carmine Scarpitta --- zebra/zebra_srv6.c | 1 - 1 file changed, 1 deletion(-) diff --git a/zebra/zebra_srv6.c b/zebra/zebra_srv6.c index e82b781c6f..0ea2ba3dac 100644 --- a/zebra/zebra_srv6.c +++ b/zebra/zebra_srv6.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include From c432aa0bb4f8c3f4e2b75c23dfb017e7250c934f Mon Sep 17 00:00:00 2001 From: Carmine Scarpitta Date: Wed, 24 Jul 2024 23:38:27 +0200 Subject: [PATCH 222/347] zebra: Remove duplicate `#include ` Signed-off-by: Carmine Scarpitta --- zebra/zebra_srv6.c | 1 - 1 file changed, 1 deletion(-) diff --git a/zebra/zebra_srv6.c b/zebra/zebra_srv6.c index 0ea2ba3dac..4e0cc8d147 100644 --- a/zebra/zebra_srv6.c +++ b/zebra/zebra_srv6.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include From 22aa0ffb81762f3b58e10cba6fd86f2843c1d844 Mon Sep 17 00:00:00 2001 From: Carmine Scarpitta Date: Wed, 24 Jul 2024 23:38:55 +0200 Subject: [PATCH 223/347] zebra: Remove duplicate `#include ` Signed-off-by: Carmine Scarpitta --- zebra/zebra_srv6.c | 1 - 1 file changed, 1 deletion(-) diff --git a/zebra/zebra_srv6.c b/zebra/zebra_srv6.c index 4e0cc8d147..d305e5ce1b 100644 --- a/zebra/zebra_srv6.c +++ b/zebra/zebra_srv6.c @@ -20,7 +20,6 @@ #include "zebra/ge_netlink.h" #include #include -#include #include #include From 4ca8332922ce6242a926439349c6796c0cb76e67 Mon Sep 17 00:00:00 2001 From: Carmine Scarpitta Date: Wed, 24 Jul 2024 23:39:14 +0200 Subject: [PATCH 224/347] zebra: Remove duplicate `#include ` Signed-off-by: Carmine Scarpitta --- zebra/zebra_srv6.c | 1 - 1 file changed, 1 deletion(-) diff --git a/zebra/zebra_srv6.c b/zebra/zebra_srv6.c index d305e5ce1b..d0892aba03 100644 --- a/zebra/zebra_srv6.c +++ b/zebra/zebra_srv6.c @@ -19,7 +19,6 @@ #include "zebra/zebra_errors.h" #include "zebra/ge_netlink.h" #include -#include #include #include From 8b206b0cd7067ada1206e5733d1972309d55c33e Mon Sep 17 00:00:00 2001 From: Carmine Scarpitta Date: Wed, 24 Jul 2024 23:39:34 +0200 Subject: [PATCH 225/347] zebra: Remove duplicate `#include ` Signed-off-by: Carmine Scarpitta --- zebra/zebra_srv6.c | 1 - 1 file changed, 1 deletion(-) diff --git a/zebra/zebra_srv6.c b/zebra/zebra_srv6.c index d0892aba03..082d4609aa 100644 --- a/zebra/zebra_srv6.c +++ b/zebra/zebra_srv6.c @@ -18,7 +18,6 @@ #include "zebra/zebra_srv6.h" #include "zebra/zebra_errors.h" #include "zebra/ge_netlink.h" -#include #include #include From bcf7bc1ce8f93505a52c39d914a0916ffdcf4d2f Mon Sep 17 00:00:00 2001 From: Carmine Scarpitta Date: Wed, 24 Jul 2024 23:41:09 +0200 Subject: [PATCH 226/347] zebra: Remove duplicate `#include "zebra/debug.h"` Signed-off-by: Carmine Scarpitta --- zebra/dplane_fpm_nl.c | 1 - 1 file changed, 1 deletion(-) diff --git a/zebra/dplane_fpm_nl.c b/zebra/dplane_fpm_nl.c index 28c481d1d8..f6c20fdad8 100644 --- a/zebra/dplane_fpm_nl.c +++ b/zebra/dplane_fpm_nl.c @@ -42,7 +42,6 @@ #include "zebra/zebra_evpn_mac.h" #include "zebra/kernel_netlink.h" #include "zebra/rt_netlink.h" -#include "zebra/debug.h" #include "fpm/fpm.h" #include "zebra/dplane_fpm_nl_clippy.c" From e2cb3ab5c6d3c512b853fffe1b986dc0aa40e9b0 Mon Sep 17 00:00:00 2001 From: Carmine Scarpitta Date: Wed, 24 Jul 2024 23:41:29 +0200 Subject: [PATCH 227/347] zebra: Remove duplicate `#include "zebra/interface.h"` Signed-off-by: Carmine Scarpitta --- zebra/dplane_fpm_nl.c | 1 - 1 file changed, 1 deletion(-) diff --git a/zebra/dplane_fpm_nl.c b/zebra/dplane_fpm_nl.c index f6c20fdad8..09080aa616 100644 --- a/zebra/dplane_fpm_nl.c +++ b/zebra/dplane_fpm_nl.c @@ -36,7 +36,6 @@ #include "zebra/zebra_dplane.h" #include "zebra/zebra_mpls.h" #include "zebra/zebra_router.h" -#include "zebra/interface.h" #include "zebra/zebra_vxlan_private.h" #include "zebra/zebra_evpn.h" #include "zebra/zebra_evpn_mac.h" From 846bbcba0d3496d66b5b03625022634c87d88568 Mon Sep 17 00:00:00 2001 From: Carmine Scarpitta Date: Wed, 24 Jul 2024 23:50:02 +0200 Subject: [PATCH 228/347] zebra: Remove duplicate `#include "zebra/interface.h"` Signed-off-by: Carmine Scarpitta --- zebra/interface.c | 1 - 1 file changed, 1 deletion(-) diff --git a/zebra/interface.c b/zebra/interface.c index b3adc4483e..03b710e1a0 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -32,7 +32,6 @@ #include "zebra/zebra_ptm.h" #include "zebra/rt_netlink.h" #include "zebra/if_netlink.h" -#include "zebra/interface.h" #include "zebra/zebra_vxlan.h" #include "zebra/zebra_errors.h" #include "zebra/zebra_evpn_mh.h" From 7b91b0b3caa4ce3dc05e454c3bc7ea5494ed4519 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Thu, 25 Jul 2024 11:52:45 +0300 Subject: [PATCH 229/347] doc: Add RFC 5701 to the supported RFCs list Signed-off-by: Donatas Abraitis --- doc/user/about.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/user/about.rst b/doc/user/about.rst index 7d30a86154..ba80a324d3 100644 --- a/doc/user/about.rst +++ b/doc/user/about.rst @@ -323,6 +323,8 @@ BGP :t:`Dissemination of Flow Specification Rules. P. Marques, N. Sheth, R. Raszuk, B. Greene, J. Mauch, D. McPherson. August 2009.` - :rfc:`5668` :t:`4-Octet AS Specific BGP Extended Community. Y. Rekhter, S. Sangli, D. Tappan October 2009.` +- :rfc:`5701` + :t:`IPv6 Address Specific BGP Extended Community Attribute. Y. Rekhter. 2009.` - :rfc:`6286` :t:`Autonomous-System-Wide Unique BGP Identifier for BGP-4. E. Chen, J. Yuan. June 2011.` - :rfc:`6472` From 743b16938455efd44f6e59b42d8800c3881f9889 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Thu, 25 Jul 2024 13:06:46 +0300 Subject: [PATCH 230/347] bgpd: Set the last_reset if we change the password also ``` donatas.net(config-router)# do show ip bgp summary failed IPv4 Unicast Summary: BGP router identifier 1.1.1.1, local AS number 65001 VRF default vrf-id 0 BGP table version 0 RIB entries 0, using 0 bytes of memory Peers 1, using 24 KiB of memory Neighbor EstdCnt DropCnt ResetTime Reason 127.0.0.1 2 2 00:02:02 Password config change (GoBGP/3.26.0) Displayed neighbors 1 Total number of neighbors 1 ``` Signed-off-by: Donatas Abraitis --- bgpd/bgp_fsm.c | 1 + bgpd/bgpd.c | 2 ++ bgpd/bgpd.h | 1 + 3 files changed, 4 insertions(+) diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index b67cf3b874..e911c2d18e 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -602,6 +602,7 @@ const char *const peer_down_str[] = { "Socket Error", "Admin. shutdown (RTT)", "Suppress Fib Turned On or Off", + "Password config change", }; static void bgp_graceful_restart_timer_off(struct peer_connection *connection, diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 043a6e201c..a59a9b6b0f 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -6790,6 +6790,7 @@ int peer_password_set(struct peer *peer, const char *password) /* Check if handling a regular peer. */ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { + peer->last_reset = PEER_DOWN_PASSWORD_CHANGE; /* Send notification or reset peer depending on state. */ if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, @@ -6827,6 +6828,7 @@ int peer_password_set(struct peer *peer, const char *password) XFREE(MTYPE_PEER_PASSWORD, member->password); member->password = XSTRDUP(MTYPE_PEER_PASSWORD, password); + member->last_reset = PEER_DOWN_PASSWORD_CHANGE; /* Send notification or reset peer depending on state. */ if (BGP_IS_VALID_STATE_FOR_NOTIF(member->connection->status)) bgp_notify_send(member->connection, BGP_NOTIFY_CEASE, diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 95ddba4cdd..6e6358bac7 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -1819,6 +1819,7 @@ struct peer { #define PEER_DOWN_SOCKET_ERROR 34U /* Some socket error happened */ #define PEER_DOWN_RTT_SHUTDOWN 35U /* Automatically shutdown due to RTT */ #define PEER_DOWN_SUPPRESS_FIB_PENDING 36U /* Suppress fib pending changed */ +#define PEER_DOWN_PASSWORD_CHANGE 37U /* neighbor password command */ /* * Remember to update peer_down_str in bgp_fsm.c when you add * a new value to the last_reset reason From fa9bd07ae5e93479ff4e7b81791393ab883cc722 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Thu, 25 Jul 2024 13:22:27 +0300 Subject: [PATCH 231/347] bgpd: Keep the last reset reason before we reset the peer If we send a notification, there is no point setting the last_reset, because bgp_notify_send() sets last_reset to PEER_DOWN_NOTIFY_SEND (almost everywhere). Signed-off-by: Donatas Abraitis --- bgpd/bgp_fsm.c | 14 +++--- bgpd/bgp_vty.c | 17 ++++--- bgpd/bgpd.c | 121 ++++++++++++++++++++++++------------------------- 3 files changed, 75 insertions(+), 77 deletions(-) diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index e911c2d18e..1eeb141155 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -2740,14 +2740,15 @@ static void bgp_gr_update_mode_of_all_peers(struct bgp *bgp, peer, peer->peer_gr_new_status_flag, peer->flags); + peer->last_reset = PEER_DOWN_CAPABILITY_CHANGE; + /* Reset session to match with behavior for other peer * configs that require the session to be re-setup. */ - if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) { - peer->last_reset = PEER_DOWN_CAPABILITY_CHANGE; + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); - } else + else bgp_session_reset(peer); } } @@ -2968,14 +2969,15 @@ unsigned int bgp_peer_gr_action(struct peer *peer, enum peer_mode old_state, bgp_peer_move_to_gr_mode(peer, new_state); if (session_reset) { + peer->last_reset = PEER_DOWN_CAPABILITY_CHANGE; + /* Reset session to match with behavior for other peer * configs that require the session to be re-setup. */ - if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) { - peer->last_reset = PEER_DOWN_CAPABILITY_CHANGE; + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); - } else + else bgp_session_reset(peer); } diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index bce8202377..1ecbba0ab5 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -2928,11 +2928,10 @@ DEFUN(bgp_reject_as_sets, bgp_reject_as_sets_cmd, * with aspath containing AS_SET or AS_CONFED_SET. */ for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { - if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) { - peer->last_reset = PEER_DOWN_AS_SETS_REJECT; + peer->last_reset = PEER_DOWN_AS_SETS_REJECT; + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); - } } return CMD_SUCCESS; @@ -2954,11 +2953,10 @@ DEFUN(no_bgp_reject_as_sets, no_bgp_reject_as_sets_cmd, * with aspath containing AS_SET or AS_CONFED_SET. */ for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { - if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) { - peer->last_reset = PEER_DOWN_AS_SETS_REJECT; + peer->last_reset = PEER_DOWN_AS_SETS_REJECT; + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); - } } return CMD_SUCCESS; @@ -5107,12 +5105,13 @@ static int peer_conf_interface_get(struct vty *vty, const char *conf_if, else peer_flag_unset(peer, PEER_FLAG_IFPEER_V6ONLY); + peer->last_reset = PEER_DOWN_V6ONLY_CHANGE; + /* v6only flag changed. Reset bgp seesion */ - if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) { - peer->last_reset = PEER_DOWN_V6ONLY_CHANGE; + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); - } else + else bgp_session_reset(peer); } diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index a59a9b6b0f..b32a4640f0 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -306,11 +306,11 @@ static int bgp_router_id_set(struct bgp *bgp, const struct in_addr *id, for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { IPV4_ADDR_COPY(&peer->local_id, id); - if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) { - peer->last_reset = PEER_DOWN_RID_CHANGE; + peer->last_reset = PEER_DOWN_RID_CHANGE; + + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); - } } /* EVPN uses router id in RD, update them */ @@ -440,11 +440,12 @@ void bm_wait_for_fib_set(bool set) */ for (ALL_LIST_ELEMENTS_RO(bm->bgp, next, bgp)) { for (ALL_LIST_ELEMENTS_RO(bgp->peer, node, peer)) { + peer->last_reset = PEER_DOWN_SUPPRESS_FIB_PENDING; + if (!BGP_IS_VALID_STATE_FOR_NOTIF( peer->connection->status)) continue; - peer->last_reset = PEER_DOWN_SUPPRESS_FIB_PENDING; bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } @@ -496,10 +497,11 @@ void bgp_suppress_fib_pending_set(struct bgp *bgp, bool set) * let's just start over */ for (ALL_LIST_ELEMENTS_RO(bgp->peer, node, peer)) { + peer->last_reset = PEER_DOWN_SUPPRESS_FIB_PENDING; + if (!BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) continue; - peer->last_reset = PEER_DOWN_SUPPRESS_FIB_PENDING; bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } @@ -523,11 +525,11 @@ void bgp_cluster_id_set(struct bgp *bgp, struct in_addr *cluster_id) if (peer->sort != BGP_PEER_IBGP) continue; - if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) { - peer->last_reset = PEER_DOWN_CLID_CHANGE; + peer->last_reset = PEER_DOWN_CLID_CHANGE; + + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); - } } } @@ -547,11 +549,11 @@ void bgp_cluster_id_unset(struct bgp *bgp) if (peer->sort != BGP_PEER_IBGP) continue; - if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) { - peer->last_reset = PEER_DOWN_CLID_CHANGE; + peer->last_reset = PEER_DOWN_CLID_CHANGE; + + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); - } } } @@ -676,14 +678,12 @@ void bgp_confederation_id_unset(struct bgp *bgp) /* We're looking for peers who's AS is not local */ if (peer_sort(peer) != BGP_PEER_IBGP) { peer->local_as = bgp->as; + peer->last_reset = PEER_DOWN_CONFED_ID_CHANGE; if (BGP_IS_VALID_STATE_FOR_NOTIF( - peer->connection->status)) { - peer->last_reset = PEER_DOWN_CONFED_ID_CHANGE; + peer->connection->status)) bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); - } - else bgp_session_reset_safe(peer, &nnode); } @@ -2091,11 +2091,11 @@ void peer_as_change(struct peer *peer, as_t as, enum peer_asn_type as_type, /* Stop peer. */ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { - if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) { - peer->last_reset = PEER_DOWN_REMOTE_AS_CHANGE; + peer->last_reset = PEER_DOWN_REMOTE_AS_CHANGE; + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); - } else + else bgp_session_reset(peer); } origtype = peer_sort_lookup(peer); @@ -2446,6 +2446,8 @@ static int peer_activate_af(struct peer *peer, afi_t afi, safi_t safi) if (!active && peer_active(peer)) { bgp_timer_set(peer->connection); } else { + peer->last_reset = PEER_DOWN_AF_ACTIVATE; + if (peer_established(peer->connection)) { if (CHECK_FLAG(peer->cap, PEER_CAP_DYNAMIC_RCV)) { peer->afc_adv[afi][safi] = 1; @@ -2458,18 +2460,15 @@ static int peer_activate_af(struct peer *peer, afi_t afi, safi_t safi) false); } } else { - peer->last_reset = PEER_DOWN_AF_ACTIVATE; bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } } if (peer->connection->status == OpenSent || - peer->connection->status == OpenConfirm) { - peer->last_reset = PEER_DOWN_AF_ACTIVATE; + peer->connection->status == OpenConfirm) bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); - } /* * If we are turning on a AFI/SAFI locally and we've * started bringing a peer up, we need to tell @@ -2481,11 +2480,9 @@ static int peer_activate_af(struct peer *peer, afi_t afi, safi_t safi) */ other = peer->doppelganger; if (other && (other->connection->status == OpenSent || - other->connection->status == OpenConfirm)) { - other->last_reset = PEER_DOWN_AF_ACTIVATE; + other->connection->status == OpenConfirm)) bgp_notify_send(other->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); - } } return 0; @@ -2579,6 +2576,8 @@ static bool non_peergroup_deactivate_af(struct peer *peer, afi_t afi, } if (peer_established(peer->connection)) { + peer->last_reset = PEER_DOWN_NEIGHBOR_DELETE; + if (CHECK_FLAG(peer->cap, PEER_CAP_DYNAMIC_RCV)) { peer->afc_adv[afi][safi] = 0; peer->afc_nego[afi][safi] = 0; @@ -2590,13 +2589,11 @@ static bool non_peergroup_deactivate_af(struct peer *peer, afi_t afi, bgp_clear_route(peer, afi, safi); peer->pcount[afi][safi] = 0; } else { - peer->last_reset = PEER_DOWN_NEIGHBOR_DELETE; bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } } else { - peer->last_reset = PEER_DOWN_NEIGHBOR_DELETE; bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } @@ -3346,13 +3343,13 @@ int peer_group_bind(struct bgp *bgp, union sockunion *su, struct peer *peer, SET_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE); - if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) { - peer->last_reset = PEER_DOWN_RMAP_BIND; + peer->last_reset = PEER_DOWN_RMAP_BIND; + + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); - } else { + else bgp_session_reset(peer); - } } /* Create a new peer. */ @@ -4790,6 +4787,13 @@ static int peer_flag_action_set(const struct peer_flag_action *action_list, static void peer_flag_modify_action(struct peer *peer, uint64_t flag) { + if (flag == PEER_FLAG_DYNAMIC_CAPABILITY) + peer->last_reset = PEER_DOWN_CAPABILITY_CHANGE; + else if (flag == PEER_FLAG_PASSIVE) + peer->last_reset = PEER_DOWN_PASSIVE_CHANGE; + else if (flag == PEER_FLAG_DISABLE_CONNECTED_CHECK) + peer->last_reset = PEER_DOWN_MULTIHOP_CHANGE; + if (flag == PEER_FLAG_SHUTDOWN) { if (CHECK_FLAG(peer->flags, flag)) { if (CHECK_FLAG(peer->sflags, PEER_STATUS_NSF_WAIT)) @@ -4838,13 +4842,6 @@ static void peer_flag_modify_action(struct peer *peer, uint64_t flag) BGP_EVENT_ADD(peer->connection, BGP_Stop); } } else if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) { - if (flag == PEER_FLAG_DYNAMIC_CAPABILITY) - peer->last_reset = PEER_DOWN_CAPABILITY_CHANGE; - else if (flag == PEER_FLAG_PASSIVE) - peer->last_reset = PEER_DOWN_PASSIVE_CHANGE; - else if (flag == PEER_FLAG_DISABLE_CONNECTED_CHECK) - peer->last_reset = PEER_DOWN_MULTIHOP_CHANGE; - bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } else @@ -5564,12 +5561,12 @@ int peer_update_source_if_set(struct peer *peer, const char *ifname) /* Check if handling a regular peer. */ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { + peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; /* Send notification or reset peer depending on state. */ - if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) { - peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); - } else + else bgp_session_reset(peer); /* Apply new source configuration to BFD session. */ @@ -5601,13 +5598,13 @@ int peer_update_source_if_set(struct peer *peer, const char *ifname) member->update_if = XSTRDUP(MTYPE_PEER_UPDATE_SOURCE, ifname); sockunion_free(member->update_source); member->update_source = NULL; + member->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; /* Send notification or reset peer depending on state. */ - if (BGP_IS_VALID_STATE_FOR_NOTIF(member->connection->status)) { - member->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; + if (BGP_IS_VALID_STATE_FOR_NOTIF(member->connection->status)) bgp_notify_send(member->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); - } else + else bgp_session_reset(member); /* Apply new source configuration to BFD session. */ @@ -5635,12 +5632,12 @@ void peer_update_source_addr_set(struct peer *peer, const union sockunion *su) /* Check if handling a regular peer. */ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { + peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; /* Send notification or reset peer depending on state. */ - if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) { - peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); - } else + else bgp_session_reset(peer); /* Apply new source configuration to BFD session. */ @@ -5671,13 +5668,13 @@ void peer_update_source_addr_set(struct peer *peer, const union sockunion *su) SET_FLAG(member->flags, PEER_FLAG_UPDATE_SOURCE); member->update_source = sockunion_dup(su); XFREE(MTYPE_PEER_UPDATE_SOURCE, member->update_if); + member->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; /* Send notification or reset peer depending on state. */ - if (BGP_IS_VALID_STATE_FOR_NOTIF(member->connection->status)) { - member->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; + if (BGP_IS_VALID_STATE_FOR_NOTIF(member->connection->status)) bgp_notify_send(member->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); - } else + else bgp_session_reset(member); /* Apply new source configuration to BFD session. */ @@ -5723,12 +5720,12 @@ void peer_update_source_unset(struct peer *peer) /* Check if handling a regular peer. */ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { + peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; /* Send notification or reset peer depending on state. */ - if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) { - peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); - } else + else bgp_session_reset(peer); /* Apply new source configuration to BFD session. */ @@ -5758,13 +5755,13 @@ void peer_update_source_unset(struct peer *peer) sockunion_free(member->update_source); member->update_source = NULL; XFREE(MTYPE_PEER_UPDATE_SOURCE, member->update_if); + member->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; /* Send notification or reset peer depending on state. */ - if (BGP_IS_VALID_STATE_FOR_NOTIF(member->connection->status)) { - member->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; + if (BGP_IS_VALID_STATE_FOR_NOTIF(member->connection->status)) bgp_notify_send(member->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); - } else + else bgp_session_reset(member); /* Apply new source configuration to BFD session. */ @@ -6730,12 +6727,12 @@ int peer_local_as_unset(struct peer *peer) /* Check if handling a regular peer. */ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { + peer->last_reset = PEER_DOWN_LOCAL_AS_CHANGE; /* Send notification or stop peer depending on state. */ - if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) { - peer->last_reset = PEER_DOWN_LOCAL_AS_CHANGE; + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); - } else + else BGP_EVENT_ADD(peer->connection, BGP_Stop); /* Skip peer-group mechanics for regular peers. */ @@ -6757,13 +6754,13 @@ int peer_local_as_unset(struct peer *peer) UNSET_FLAG(member->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS); member->change_local_as = 0; XFREE(MTYPE_BGP_NAME, member->change_local_as_pretty); + member->last_reset = PEER_DOWN_LOCAL_AS_CHANGE; /* Send notification or stop peer depending on state. */ - if (BGP_IS_VALID_STATE_FOR_NOTIF(member->connection->status)) { - member->last_reset = PEER_DOWN_LOCAL_AS_CHANGE; + if (BGP_IS_VALID_STATE_FOR_NOTIF(member->connection->status)) bgp_notify_send(member->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); - } else + else bgp_session_reset(member); } From b1b1c922a519af3c2af1eed5790ec6ac7fe27da5 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Thu, 25 Jul 2024 13:41:23 +0300 Subject: [PATCH 232/347] bgpd: Do not increment treat-as-withdraw counters if debug is enabled Increment only if we really treat the UPDATE as withdrawn. Signed-off-by: Donatas Abraitis --- bgpd/bgp_packet.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index 0fb59a94c2..842fd1734a 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -2390,13 +2390,13 @@ static int bgp_update_receive(struct peer_connection *connection, ret = bgp_dump_attr(&attr, peer->rcvd_attr_str, sizeof(peer->rcvd_attr_str)); - peer->stat_upd_7606++; - - if (attr_parse_ret == BGP_ATTR_PARSE_WITHDRAW) + if (attr_parse_ret == BGP_ATTR_PARSE_WITHDRAW) { + peer->stat_upd_7606++; flog_err( EC_BGP_UPDATE_RCV, "%pBP rcvd UPDATE with errors in attr(s)!! Withdrawing route.", peer); + } if (ret && bgp_debug_update(peer, NULL, NULL, 1) && BGP_DEBUG(update, UPDATE_DETAIL)) { From c4b4c242ec8cfcdb23f0f90faaa0ff76577e1364 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Thu, 25 Jul 2024 07:50:32 -0400 Subject: [PATCH 233/347] pimd: Fix msdp setting of sa->rp The code is clearly incorrect. After consultation with the original author this is the decided change. Signed-off-by: Donald Sharp --- pimd/pim_msdp.c | 8 +++----- tests/topotests/msdp_topo1/test_msdp_topo1.py | 4 ++-- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/pimd/pim_msdp.c b/pimd/pim_msdp.c index 623c14bb03..ea8c84cca5 100644 --- a/pimd/pim_msdp.c +++ b/pimd/pim_msdp.c @@ -411,12 +411,10 @@ void pim_msdp_sa_ref(struct pim_instance *pim, struct pim_msdp_peer *mp, pim_addr_to_prefix(&grp, sa->sg.grp); rp_info = pim_rp_find_match_group(pim, &grp); if (rp_info) { - sa->rp = rp_info->rp.rpf_addr; - } else - { - sa->rp = pim->msdp.originator_id; + sa->rp = rp_info->rp.rpf_addr; + } else { + sa->rp = pim->msdp.originator_id; } - sa->rp = pim->msdp.originator_id; pim_msdp_pkt_sa_tx_one(sa); } sa->flags &= ~PIM_MSDP_SAF_STALE; diff --git a/tests/topotests/msdp_topo1/test_msdp_topo1.py b/tests/topotests/msdp_topo1/test_msdp_topo1.py index 08c37617cf..4b54ef29ff 100755 --- a/tests/topotests/msdp_topo1/test_msdp_topo1.py +++ b/tests/topotests/msdp_topo1/test_msdp_topo1.py @@ -359,7 +359,7 @@ def test_msdp(): "192.168.10.100": { "source": "192.168.10.100", "group": "229.1.2.3", - "rp": "192.168.1.1", + "rp": "10.254.254.1", "local": "no", "sptSetup": "no", } @@ -394,7 +394,7 @@ def test_msdp(): "192.168.10.100": { "source": "192.168.10.100", "group": "229.1.2.3", - "rp": "192.168.1.1", + "rp": "10.254.254.1", "local": "no", "sptSetup": "yes", } From 968ae852523381cf727a6491c5e22a02a5de8077 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Thu, 25 Jul 2024 15:07:57 +0300 Subject: [PATCH 234/347] bgpd: Show software version in bgp summary E.g.: ``` $ vtysh -c 'show bgp summary json' | jq '.ipv4Unicast.peers' { "127.0.0.1": { "hostname": "donatas.net", "softwareVersion": "GoBGP/3.26.0", "remoteAs": 65001, "localAs": 65001, "version": 4, "msgRcvd": 12, "msgSent": 16, "tableVersion": 0, "outq": 0, "inq": 0, "peerUptime": "00:00:10", "peerUptimeMsec": 10000, "peerUptimeEstablishedEpoch": 1721908563, "pfxRcd": 0, "pfxSnt": 0, "state": "Established", "peerState": "OK", "connectionsEstablished": 1, "connectionsDropped": 0, "idType": "ipv4" }, "127.0.0.3": { "hostname": "putin-xujlo", "domainname": "donatas.net", "softwareVersion": "ExaBGP/5.0.0-20240725+main-a56c70e84a", "remoteAs": 65003, "localAs": 65001, "version": 4, "msgRcvd": 3, "msgSent": 7, "tableVersion": 0, "outq": 0, "inq": 0, "peerUptime": "00:00:13", "peerUptimeMsec": 13000, "peerUptimeEstablishedEpoch": 1721908560, "pfxRcd": 0, "pfxSnt": 0, "state": "Established", "peerState": "OK", "connectionsEstablished": 1, "connectionsDropped": 0, "idType": "ipv4" } } ``` Signed-off-by: Donatas Abraitis --- bgpd/bgp_vty.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index bce8202377..2c02abd0d8 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -12329,6 +12329,12 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi, json_object_string_add(json_peer, "domainname", peer->domainname); + json_object_string_add(json_peer, + "softwareVersion", + peer->soft_version + ? peer->soft_version + : "n/a"); + asn_asn2json(json_peer, "remoteAs", peer->as, bgp->asnotation); asn_asn2json(json_peer, "localAs", From 88a9aa9c6bec8049b36212fa3eb48b357b03b83a Mon Sep 17 00:00:00 2001 From: Rafael Zalamena Date: Tue, 16 Jul 2024 15:50:16 -0300 Subject: [PATCH 235/347] bfdd: remove control socket obsolete code Let's remove the obsolete BFD control socket. If the functionality is needed then YANG/northbound notifications / getting should be used instead. Signed-off-by: Rafael Zalamena --- bfdd/bfd.c | 78 +-- bfdd/bfd.h | 158 +++--- bfdd/bfdctl.h | 157 ------ bfdd/bfdd.c | 27 +- bfdd/bfdd_vty.c | 15 +- bfdd/config.c | 592 ----------------------- bfdd/control.c | 844 --------------------------------- bfdd/dplane.c | 2 +- bfdd/ptm_adapter.c | 9 +- bfdd/subdir.am | 3 - snapcraft/scripts/bfdd-service | 3 +- snapcraft/snapcraft.yaml.in | 2 +- 12 files changed, 78 insertions(+), 1812 deletions(-) delete mode 100644 bfdd/bfdctl.h delete mode 100644 bfdd/config.c delete mode 100644 bfdd/control.c diff --git a/bfdd/bfd.c b/bfdd/bfd.c index b6b437a791..eb9c300313 100644 --- a/bfdd/bfd.c +++ b/bfdd/bfd.c @@ -256,19 +256,8 @@ void gen_bfd_key(struct bfd_key *key, struct sockaddr_any *peer, struct bfd_session *bs_peer_find(struct bfd_peer_cfg *bpc) { - struct bfd_session *bs; - struct peer_label *pl; struct bfd_key key; - /* Try to find label first. */ - if (bpc->bpc_has_label) { - pl = pl_find(bpc->bpc_label); - if (pl != NULL) { - bs = pl->pl_bs; - return bs; - } - } - /* Otherwise fallback to peer/local hash lookup. */ gen_bfd_key(&key, &bpc->bpc_peer, &bpc->bpc_local, bpc->bpc_mhop, bpc->bpc_localif, bpc->bpc_vrfname); @@ -327,10 +316,8 @@ int bfd_session_enable(struct bfd_session *bs) bs->ifp = ifp; /* Attempt to use data plane. */ - if (bglobal.bg_use_dplane && bfd_dplane_add_session(bs) == 0) { - control_notify_config(BCM_NOTIFY_CONFIG_ADD, bs); + if (bglobal.bg_use_dplane && bfd_dplane_add_session(bs) == 0) return 0; - } /* Sanity check: don't leak open sockets. */ if (bs->sock != -1) { @@ -502,7 +489,7 @@ void ptm_bfd_sess_up(struct bfd_session *bfd) /* Start sending control packets with poll bit immediately. */ ptm_bfd_snd(bfd, 0); - control_notify(bfd, bfd->ses_state); + ptm_bfd_notify(bfd, bfd->ses_state); if (old_state != bfd->ses_state) { bfd->stats.session_up++; @@ -538,7 +525,7 @@ void ptm_bfd_sess_dn(struct bfd_session *bfd, uint8_t diag) /* only signal clients when going from up->down state */ if (old_state == PTM_BFD_UP) - control_notify(bfd, PTM_BFD_DOWN); + ptm_bfd_notify(bfd, PTM_BFD_DOWN); /* Stop echo packet transmission if they are active */ if (CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_ECHO_ACTIVE)) @@ -690,38 +677,6 @@ struct bfd_session *bfd_session_new(void) return bs; } -int bfd_session_update_label(struct bfd_session *bs, const char *nlabel) -{ - /* New label treatment: - * - Check if the label is taken; - * - Try to allocate the memory for it and register; - */ - if (bs->pl == NULL) { - if (pl_find(nlabel) != NULL) { - /* Someone is already using it. */ - return -1; - } - - pl_new(nlabel, bs); - - return 0; - } - - /* - * Test label change consistency: - * - Do nothing if it's the same label; - * - Check if the future label is already taken; - * - Change label; - */ - if (strcmp(nlabel, bs->pl->pl_label) == 0) - return -1; - if (pl_find(nlabel) != NULL) - return -1; - - strlcpy(bs->pl->pl_label, nlabel, sizeof(bs->pl->pl_label)); - return 0; -} - static void _bfd_session_update(struct bfd_session *bs, struct bfd_peer_cfg *bpc) { @@ -750,9 +705,6 @@ static void _bfd_session_update(struct bfd_session *bs, bs->peer_profile.min_echo_tx = bs->timers.desired_min_echo_tx; } - if (bpc->bpc_has_label) - bfd_session_update_label(bs, bpc->bpc_label); - if (bpc->bpc_cbit) SET_FLAG(bs->flags, BFD_SESS_FLAG_CBIT); else @@ -792,8 +744,6 @@ static int bfd_session_update(struct bfd_session *bs, struct bfd_peer_cfg *bpc) _bfd_session_update(bs, bpc); - control_notify_config(BCM_NOTIFY_CONFIG_UPDATE, bs); - return 0; } @@ -819,8 +769,6 @@ void bfd_session_free(struct bfd_session *bs) if (bso != NULL) bs_observer_del(bso); - pl_free(bs->pl); - XFREE(MTYPE_BFDD_PROFILE, bs->profile_name); XFREE(MTYPE_BFDD_CONFIG, bs); } @@ -917,8 +865,6 @@ struct bfd_session *bs_registrate(struct bfd_session *bfd) if (bglobal.debug_peer_event) zlog_debug("session-new: %s", bs_to_string(bfd)); - control_notify_config(BCM_NOTIFY_CONFIG_ADD, bfd); - return bfd; } @@ -941,8 +887,6 @@ int ptm_bfd_sess_del(struct bfd_peer_cfg *bpc) if (bglobal.debug_peer_event) zlog_debug("%s: %s", __func__, bs_to_string(bs)); - control_notify_config(BCM_NOTIFY_CONFIG_DELETE, bs); - bfd_session_free(bs); return 0; @@ -1166,11 +1110,8 @@ void bs_final_handler(struct bfd_session *bs) * When using demand mode we must disable the detection timer * for lost control packets. */ - if (bs->demand_mode) { - /* Notify watchers about changed timers. */ - control_notify_config(BCM_NOTIFY_CONFIG_UPDATE, bs); + if (bs->demand_mode) return; - } /* * Calculate transmission time based on new timers. @@ -1189,9 +1130,6 @@ void bs_final_handler(struct bfd_session *bs) /* Apply new transmission timer immediately. */ ptm_bfd_start_xmt_timer(bs, false); - - /* Notify watchers about changed timers. */ - control_notify_config(BCM_NOTIFY_CONFIG_UPDATE, bs); } void bs_set_slow_timers(struct bfd_session *bs) @@ -1261,7 +1199,7 @@ void bfd_set_shutdown(struct bfd_session *bs, bool shutdown) if (bs->bdc) { bs->ses_state = PTM_BFD_ADM_DOWN; bfd_dplane_update_session(bs); - control_notify(bs, bs->ses_state); + ptm_bfd_notify(bs, bs->ses_state); return; } @@ -1273,7 +1211,7 @@ void bfd_set_shutdown(struct bfd_session *bs, bool shutdown) /* Change and notify state change. */ bs->ses_state = PTM_BFD_ADM_DOWN; - control_notify(bs, bs->ses_state); + ptm_bfd_notify(bs, bs->ses_state); /* Don't try to send packets with a disabled session. */ if (bs->sock != -1) @@ -1289,13 +1227,13 @@ void bfd_set_shutdown(struct bfd_session *bs, bool shutdown) if (bs->bdc) { bs->ses_state = PTM_BFD_DOWN; bfd_dplane_update_session(bs); - control_notify(bs, bs->ses_state); + ptm_bfd_notify(bs, bs->ses_state); return; } /* Change and notify state change. */ bs->ses_state = PTM_BFD_DOWN; - control_notify(bs, bs->ses_state); + ptm_bfd_notify(bs, bs->ses_state); /* Enable timers if non passive, otherwise stop them. */ if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_PASSIVE)) { diff --git a/bfdd/bfd.h b/bfdd/bfd.h index be04e655ab..2f83b245eb 100644 --- a/bfdd/bfd.h +++ b/bfdd/bfd.h @@ -20,19 +20,73 @@ #include "lib/queue.h" #include "lib/vrf.h" -#include "bfdctl.h" - #ifdef BFD_DEBUG #define BFDD_JSON_CONV_OPTIONS (JSON_C_TO_STRING_PRETTY) #else #define BFDD_JSON_CONV_OPTIONS (0) #endif +#ifndef MAXNAMELEN +#define MAXNAMELEN 32 +#endif + +#define BPC_DEF_DETECTMULTIPLIER 3 +#define BPC_DEF_RECEIVEINTERVAL 300 /* milliseconds */ +#define BPC_DEF_TRANSMITINTERVAL 300 /* milliseconds */ +#define BPC_DEF_ECHORECEIVEINTERVAL 50 /* milliseconds */ +#define BPC_DEF_ECHOTRANSMITINTERVAL 50 /* milliseconds */ + DECLARE_MGROUP(BFDD); -DECLARE_MTYPE(BFDD_CONTROL); -DECLARE_MTYPE(BFDD_NOTIFICATION); +DECLARE_MTYPE(BFDD_CLIENT); +DECLARE_MTYPE(BFDD_CLIENT_NOTIFICATION); + +struct sockaddr_any { + union { + struct sockaddr_in sa_sin; + struct sockaddr_in6 sa_sin6; + }; +}; + +struct bfd_peer_cfg { + bool bpc_mhop; + bool bpc_ipv4; + struct sockaddr_any bpc_peer; + struct sockaddr_any bpc_local; + + bool bpc_has_localif; + char bpc_localif[MAXNAMELEN + 1]; + + bool bpc_has_vrfname; + char bpc_vrfname[MAXNAMELEN + 1]; + + bool bpc_has_detectmultiplier; + uint8_t bpc_detectmultiplier; + + bool bpc_has_recvinterval; + uint64_t bpc_recvinterval; + + bool bpc_has_txinterval; + uint64_t bpc_txinterval; -#define BFDD_SOCK_NAME "%s/bfdd.sock", frr_runstatedir + bool bpc_has_echorecvinterval; + uint64_t bpc_echorecvinterval; + + bool bpc_has_echotxinterval; + uint64_t bpc_echotxinterval; + + bool bpc_has_minimum_ttl; + uint8_t bpc_minimum_ttl; + + bool bpc_echo; + bool bpc_createonly; + bool bpc_shutdown; + + bool bpc_cbit; + bool bpc_passive; + + bool bpc_has_profile; + char bpc_profile[64]; +}; /* bfd Authentication Type. */ #define BFD_AUTH_NULL 0 @@ -246,9 +300,6 @@ struct bfd_profile { /** Profile list type. */ TAILQ_HEAD(bfdproflist, bfd_profile); -/* bfd_session shortcut label forwarding. */ -struct peer_label; - struct bfd_config_timers { uint32_t desired_min_tx; uint32_t required_min_rx; @@ -326,14 +377,6 @@ struct bfd_session { uint64_t rtt[BFD_RTT_SAMPLE]; /* RRT in usec for echo to be looped */ }; -struct peer_label { - TAILQ_ENTRY(peer_label) pl_entry; - - struct bfd_session *pl_bs; - char pl_label[MAXNAMELEN]; -}; -TAILQ_HEAD(pllist, peer_label); - struct bfd_diag_str_list { const char *str; int type; @@ -385,64 +428,6 @@ TAILQ_HEAD(obslist, bfd_session_observer); #define BFD_DEF_ECHO_PORT 3785 #define BFD_DEF_MHOP_DEST_PORT 4784 -/* - * control.c - * - * Daemon control code to speak with local consumers. - */ - -/* See 'bfdctrl.h' for client protocol definitions. */ - -struct bfd_control_buffer { - size_t bcb_left; - size_t bcb_pos; - union { - struct bfd_control_msg *bcb_bcm; - uint8_t *bcb_buf; - }; -}; - -struct bfd_control_queue { - TAILQ_ENTRY(bfd_control_queue) bcq_entry; - - struct bfd_control_buffer bcq_bcb; -}; -TAILQ_HEAD(bcqueue, bfd_control_queue); - -struct bfd_notify_peer { - TAILQ_ENTRY(bfd_notify_peer) bnp_entry; - - struct bfd_session *bnp_bs; -}; -TAILQ_HEAD(bnplist, bfd_notify_peer); - -struct bfd_control_socket { - TAILQ_ENTRY(bfd_control_socket) bcs_entry; - - int bcs_sd; - struct event *bcs_ev; - struct event *bcs_outev; - struct bcqueue bcs_bcqueue; - - /* Notification data */ - uint64_t bcs_notify; - struct bnplist bcs_bnplist; - - enum bc_msg_version bcs_version; - enum bc_msg_type bcs_type; - - /* Message buffering */ - struct bfd_control_buffer bcs_bin; - struct bfd_control_buffer *bcs_bout; -}; -TAILQ_HEAD(bcslist, bfd_control_socket); - -int control_init(const char *path); -void control_shutdown(void); -int control_notify(struct bfd_session *bs, uint8_t notify_state); -int control_notify_config(const char *op, struct bfd_session *bs); -void control_accept(struct event *t); - /* * bfdd.c @@ -468,9 +453,6 @@ TAILQ_HEAD(dplane_queue, bfd_dplane_ctx); struct bfd_global { int bg_csock; struct event *bg_csockev; - struct bcslist bg_bcslist; - - struct pllist bg_pllist; struct obslist bg_obslist; @@ -516,27 +498,6 @@ extern const struct bfd_state_str_list state_list[]; void socket_close(int *s); -/* - * config.c - * - * Contains the code related with loading/reloading configuration. - */ -int parse_config(const char *fname); -int config_request_add(const char *jsonstr); -int config_request_del(const char *jsonstr); -char *config_response(const char *status, const char *error); -char *config_notify(struct bfd_session *bs); -char *config_notify_config(const char *op, struct bfd_session *bs); - -typedef int (*bpc_handle)(struct bfd_peer_cfg *, void *arg); -int config_notify_request(struct bfd_control_socket *bcs, const char *jsonstr, - bpc_handle bh); - -struct peer_label *pl_new(const char *label, struct bfd_session *bs); -struct peer_label *pl_find(const char *label); -void pl_free(struct peer_label *pl); - - /* * logging - alias to zebra log */ @@ -621,7 +582,6 @@ struct bfd_session *ptm_bfd_sess_find(struct bfd_pkt *cp, bool is_mhop); struct bfd_session *bs_peer_find(struct bfd_peer_cfg *bpc); -int bfd_session_update_label(struct bfd_session *bs, const char *nlabel); void bfd_set_polling(struct bfd_session *bs); void bs_state_handler(struct bfd_session *bs, int nstate); void bs_echo_timer_handler(struct bfd_session *bs); diff --git a/bfdd/bfdctl.h b/bfdd/bfdctl.h deleted file mode 100644 index f1f8185c3b..0000000000 --- a/bfdd/bfdctl.h +++ /dev/null @@ -1,157 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/********************************************************************* - * Copyright 2017-2018 Network Device Education Foundation, Inc. ("NetDEF") - * - * bfdctl.h: all BFDd control socket protocol definitions. - * - * Authors - * ------- - * Rafael Zalamena - */ - -#ifndef _BFDCTRL_H_ -#define _BFDCTRL_H_ - -#include - -#include -#include - -/* - * Auxiliary definitions - */ -struct sockaddr_any { - union { - struct sockaddr_in sa_sin; - struct sockaddr_in6 sa_sin6; - }; -}; - -#ifndef MAXNAMELEN -#define MAXNAMELEN 32 -#endif - -#define BPC_DEF_DETECTMULTIPLIER 3 -#define BPC_DEF_RECEIVEINTERVAL 300 /* milliseconds */ -#define BPC_DEF_TRANSMITINTERVAL 300 /* milliseconds */ -#define BPC_DEF_ECHORECEIVEINTERVAL 50 /* milliseconds */ -#define BPC_DEF_ECHOTRANSMITINTERVAL 50 /* milliseconds */ - -/* Peer status */ -enum bfd_peer_status { - BPS_SHUTDOWN = 0, /* == PTM_BFD_ADM_DOWN, "adm-down" */ - BPS_DOWN = 1, /* == PTM_BFD_DOWN, "down" */ - BPS_INIT = 2, /* == PTM_BFD_INIT, "init" */ - BPS_UP = 3, /* == PTM_BFD_UP, "up" */ -}; - -struct bfd_peer_cfg { - bool bpc_mhop; - bool bpc_ipv4; - struct sockaddr_any bpc_peer; - struct sockaddr_any bpc_local; - - bool bpc_has_label; - char bpc_label[MAXNAMELEN]; - - bool bpc_has_localif; - char bpc_localif[MAXNAMELEN + 1]; - - bool bpc_has_vrfname; - char bpc_vrfname[MAXNAMELEN + 1]; - - bool bpc_has_detectmultiplier; - uint8_t bpc_detectmultiplier; - - bool bpc_has_recvinterval; - uint64_t bpc_recvinterval; - - bool bpc_has_txinterval; - uint64_t bpc_txinterval; - - bool bpc_has_echorecvinterval; - uint64_t bpc_echorecvinterval; - - bool bpc_has_echotxinterval; - uint64_t bpc_echotxinterval; - - bool bpc_has_minimum_ttl; - uint8_t bpc_minimum_ttl; - - bool bpc_echo; - bool bpc_createonly; - bool bpc_shutdown; - - bool bpc_cbit; - bool bpc_passive; - - bool bpc_has_profile; - char bpc_profile[64]; - - /* Status information */ - enum bfd_peer_status bpc_bps; - uint32_t bpc_id; - uint32_t bpc_remoteid; - uint8_t bpc_diag; - uint8_t bpc_remotediag; - uint8_t bpc_remote_detectmultiplier; - uint64_t bpc_remote_recvinterval; - uint64_t bpc_remote_txinterval; - uint64_t bpc_remote_echointerval; - uint64_t bpc_lastevent; -}; - - -/* - * Protocol definitions - */ -enum bc_msg_version { - BMV_VERSION_1 = 1, -}; - -enum bc_msg_type { - BMT_RESPONSE = 1, - BMT_REQUEST_ADD = 2, - BMT_REQUEST_DEL = 3, - BMT_NOTIFY = 4, - BMT_NOTIFY_ADD = 5, - BMT_NOTIFY_DEL = 6, -}; - -/* Notify flags to use with bcm_notify. */ -#define BCM_NOTIFY_ALL ((uint64_t)-1) -#define BCM_NOTIFY_PEER_STATE (1ULL << 0) -#define BCM_NOTIFY_CONFIG (1ULL << 1) -#define BCM_NOTIFY_NONE 0 - -/* Response 'status' definitions. */ -#define BCM_RESPONSE_OK "ok" -#define BCM_RESPONSE_ERROR "error" - -/* Notify operation. */ -#define BCM_NOTIFY_PEER_STATUS "status" -#define BCM_NOTIFY_CONFIG_ADD "add" -#define BCM_NOTIFY_CONFIG_DELETE "delete" -#define BCM_NOTIFY_CONFIG_UPDATE "update" - -/* Notification special ID. */ -#define BCM_NOTIFY_ID 0 - -struct bfd_control_msg { - /* Total length without the header. */ - uint32_t bcm_length; - /* - * Message request/response id. - * All requests will have a correspondent response with the - * same id. - */ - uint16_t bcm_id; - /* Message type. */ - uint8_t bcm_type; - /* Message version. */ - uint8_t bcm_ver; - /* Message payload. */ - uint8_t bcm_data[0]; -}; - -#endif diff --git a/bfdd/bfdd.c b/bfdd/bfdd.c index 243cf5c129..c2d8e926bf 100644 --- a/bfdd/bfdd.c +++ b/bfdd/bfdd.c @@ -28,8 +28,8 @@ * FRR related code. */ DEFINE_MGROUP(BFDD, "Bidirectional Forwarding Detection Daemon"); -DEFINE_MTYPE(BFDD, BFDD_CONTROL, "control socket memory"); -DEFINE_MTYPE(BFDD, BFDD_NOTIFICATION, "control notification data"); +DEFINE_MTYPE(BFDD, BFDD_CLIENT, "BFD client data"); +DEFINE_MTYPE(BFDD, BFDD_CLIENT_NOTIFICATION, "BFD client notification data"); /* Master of threads. */ struct event_loop *master; @@ -67,9 +67,6 @@ static void sigterm_handler(void) /* Stop receiving message from zebra. */ bfdd_zclient_stop(); - /* Shutdown controller to avoid receiving anymore commands. */ - control_shutdown(); - /* Shutdown and free all protocol related memory. */ bfd_shutdown(); @@ -132,10 +129,8 @@ FRR_DAEMON_INFO(bfdd, BFD, ); /* clang-format on */ -#define OPTION_CTLSOCK 1001 #define OPTION_DPLANEADDR 2000 static const struct option longopts[] = { - {"bfdctl", required_argument, NULL, OPTION_CTLSOCK}, {"dplaneaddr", required_argument, NULL, OPTION_DPLANEADDR}, {0} }; @@ -319,7 +314,6 @@ static void bg_init(void) .cap_num_i = 0, }; - TAILQ_INIT(&bglobal.bg_bcslist); TAILQ_INIT(&bglobal.bg_obslist); memcpy(&bglobal.bfdd_privs, &bfdd_privs, @@ -328,8 +322,7 @@ static void bg_init(void) int main(int argc, char *argv[]) { - char ctl_path[512], dplane_addr[512]; - bool ctlsockused = false; + char dplane_addr[512]; int opt; bglobal.bg_use_dplane = false; @@ -339,7 +332,6 @@ int main(int argc, char *argv[]) frr_preinit(&bfdd_di, argc, argv); frr_opt_add("", longopts, - " --bfdctl Specify bfdd control socket\n" " --dplaneaddr Specify BFD data plane address\n"); while (true) { @@ -348,10 +340,6 @@ int main(int argc, char *argv[]) break; switch (opt) { - case OPTION_CTLSOCK: - strlcpy(ctl_path, optarg, sizeof(ctl_path)); - ctlsockused = true; - break; case OPTION_DPLANEADDR: strlcpy(dplane_addr, optarg, sizeof(dplane_addr)); bglobal.bg_use_dplane = true; @@ -362,15 +350,9 @@ int main(int argc, char *argv[]) } } - if (!ctlsockused) - snprintf(ctl_path, sizeof(ctl_path), BFDD_SOCK_NAME); - /* Initialize FRR infrastructure. */ master = frr_init(); - /* Initialize control socket. */ - control_init(ctl_path); - /* Initialize BFD data structures. */ bfd_initialize(); @@ -381,9 +363,6 @@ int main(int argc, char *argv[]) /* Initialize zebra connection. */ bfdd_zclient_init(&bglobal.bfdd_privs); - event_add_read(master, control_accept, NULL, bglobal.bg_csock, - &bglobal.bg_csockev); - /* Install commands. */ bfdd_vty_init(); diff --git a/bfdd/bfdd_vty.c b/bfdd/bfdd_vty.c index 496d5019b5..26554e1496 100644 --- a/bfdd/bfdd_vty.c +++ b/bfdd/bfdd_vty.c @@ -84,9 +84,6 @@ static void _display_peer_header(struct vty *vty, struct bfd_session *bs) if (bs->key.ifname[0]) vty_out(vty, " interface %s", bs->key.ifname); vty_out(vty, "\n"); - - if (bs->pl) - vty_out(vty, "\t\tlabel: %s\n", bs->pl->pl_label); } static void _display_peer(struct vty *vty, struct bfd_session *bs) @@ -200,9 +197,6 @@ static struct json_object *_peer_json_header(struct bfd_session *bs) if (bs->key.ifname[0]) json_object_string_add(jo, "interface", bs->key.ifname); - if (bs->pl) - json_object_string_add(jo, "label", bs->pl->pl_label); - return jo; } @@ -561,17 +555,11 @@ _find_peer_or_error(struct vty *vty, int argc, struct cmd_token **argv, int idx; bool mhop; struct bfd_session *bs = NULL; - struct peer_label *pl; struct bfd_peer_cfg bpc; struct sockaddr_any psa, lsa, *lsap; char errormsg[128]; - /* Look up the BFD peer. */ - if (label) { - pl = pl_find(label); - if (pl) - bs = pl->pl_bs; - } else if (peer_str) { + if (peer_str) { strtosa(peer_str, &psa); if (local_str) { strtosa(local_str, &lsa); @@ -879,7 +867,6 @@ static int bfd_configure_peer(struct bfd_peer_cfg *bpc, bool mhop, bpc->bpc_txinterval = BPC_DEF_TRANSMITINTERVAL; bpc->bpc_echorecvinterval = BPC_DEF_ECHORECEIVEINTERVAL; bpc->bpc_echotxinterval = BPC_DEF_ECHOTRANSMITINTERVAL; - bpc->bpc_lastevent = monotime(NULL); /* Safety check: when no error buf is provided len must be zero. */ if (ebuf == NULL) diff --git a/bfdd/config.c b/bfdd/config.c deleted file mode 100644 index 22d7d7deee..0000000000 --- a/bfdd/config.c +++ /dev/null @@ -1,592 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/********************************************************************* - * Copyright 2017-2018 Network Device Education Foundation, Inc. ("NetDEF") - * - * config.c: implements the BFD daemon configuration handling. - * - * Authors - * ------- - * Rafael Zalamena - */ - -#include - -#include - -#include "lib/json.h" - -#include "bfd.h" - -DEFINE_MTYPE_STATIC(BFDD, BFDD_LABEL, "long-lived label memory"); - -/* - * Definitions - */ -enum peer_list_type { - PLT_IPV4, - PLT_IPV6, - PLT_LABEL, -}; - - -/* - * Prototypes - */ -static int parse_config_json(struct json_object *jo, bpc_handle h, void *arg); -static int parse_list(struct json_object *jo, enum peer_list_type plt, - bpc_handle h, void *arg); -static int parse_peer_config(struct json_object *jo, struct bfd_peer_cfg *bpc); -static int parse_peer_label_config(struct json_object *jo, - struct bfd_peer_cfg *bpc); - -static int config_add(struct bfd_peer_cfg *bpc, void *arg); -static int config_del(struct bfd_peer_cfg *bpc, void *arg); - -static int json_object_add_peer(struct json_object *jo, struct bfd_session *bs); - - -/* - * Implementation - */ -static int config_add(struct bfd_peer_cfg *bpc, - void *arg __attribute__((unused))) -{ - return ptm_bfd_sess_new(bpc) == NULL; -} - -static int config_del(struct bfd_peer_cfg *bpc, - void *arg __attribute__((unused))) -{ - return ptm_bfd_sess_del(bpc) != 0; -} - -static int parse_config_json(struct json_object *jo, bpc_handle h, void *arg) -{ - const char *key, *sval; - struct json_object *jo_val; - struct json_object_iterator joi, join; - int error = 0; - - JSON_FOREACH (jo, joi, join) { - key = json_object_iter_peek_name(&joi); - jo_val = json_object_iter_peek_value(&joi); - - if (strcmp(key, "ipv4") == 0) { - error += parse_list(jo_val, PLT_IPV4, h, arg); - } else if (strcmp(key, "ipv6") == 0) { - error += parse_list(jo_val, PLT_IPV6, h, arg); - } else if (strcmp(key, "label") == 0) { - error += parse_list(jo_val, PLT_LABEL, h, arg); - } else { - sval = json_object_get_string(jo_val); - zlog_warn("%s:%d invalid configuration: %s", __func__, - __LINE__, sval); - error++; - } - } - - /* - * Our callers never call free() on json_object and only expect - * the return value, so lets free() it here. - */ - json_object_put(jo); - - return error; -} - -int parse_config(const char *fname) -{ - struct json_object *jo; - - jo = json_object_from_file(fname); - if (jo == NULL) - return -1; - - return parse_config_json(jo, config_add, NULL); -} - -static int parse_list(struct json_object *jo, enum peer_list_type plt, - bpc_handle h, void *arg) -{ - struct json_object *jo_val; - struct bfd_peer_cfg bpc; - int allen, idx; - int error = 0, result; - - allen = json_object_array_length(jo); - for (idx = 0; idx < allen; idx++) { - jo_val = json_object_array_get_idx(jo, idx); - - /* Set defaults. */ - memset(&bpc, 0, sizeof(bpc)); - bpc.bpc_detectmultiplier = BFD_DEFDETECTMULT; - bpc.bpc_recvinterval = BFD_DEFREQUIREDMINRX; - bpc.bpc_txinterval = BFD_DEFDESIREDMINTX; - bpc.bpc_echorecvinterval = BFD_DEF_REQ_MIN_ECHO_RX; - bpc.bpc_echotxinterval = BFD_DEF_DES_MIN_ECHO_TX; - - switch (plt) { - case PLT_IPV4: - zlog_debug("ipv4 peers %d:", allen); - bpc.bpc_ipv4 = true; - break; - case PLT_IPV6: - zlog_debug("ipv6 peers %d:", allen); - bpc.bpc_ipv4 = false; - break; - case PLT_LABEL: - zlog_debug("label peers %d:", allen); - if (parse_peer_label_config(jo_val, &bpc) != 0) { - error++; - continue; - } - break; - - default: - error++; - zlog_err("%s:%d: unsupported peer type", __func__, - __LINE__); - break; - } - - result = parse_peer_config(jo_val, &bpc); - error += result; - if (result == 0) - error += (h(&bpc, arg) != 0); - } - - return error; -} - -static int parse_peer_config(struct json_object *jo, struct bfd_peer_cfg *bpc) -{ - const char *key, *sval; - struct json_object *jo_val; - struct json_object_iterator joi, join; - int family_type = (bpc->bpc_ipv4) ? AF_INET : AF_INET6; - int error = 0; - - zlog_debug(" peer: %s", bpc->bpc_ipv4 ? "ipv4" : "ipv6"); - - JSON_FOREACH (jo, joi, join) { - key = json_object_iter_peek_name(&joi); - jo_val = json_object_iter_peek_value(&joi); - - if (strcmp(key, "multihop") == 0) { - bpc->bpc_mhop = json_object_get_boolean(jo_val); - zlog_debug(" multihop: %s", - bpc->bpc_mhop ? "true" : "false"); - } else if (strcmp(key, "peer-address") == 0) { - sval = json_object_get_string(jo_val); - if (strtosa(sval, &bpc->bpc_peer) != 0 - || bpc->bpc_peer.sa_sin.sin_family != family_type) { - zlog_debug( - "%s:%d failed to parse peer-address '%s'", - __func__, __LINE__, sval); - error++; - } - zlog_debug(" peer-address: %s", sval); - } else if (strcmp(key, "local-address") == 0) { - sval = json_object_get_string(jo_val); - if (strtosa(sval, &bpc->bpc_local) != 0 - || bpc->bpc_local.sa_sin.sin_family - != family_type) { - zlog_debug( - "%s:%d failed to parse local-address '%s'", - __func__, __LINE__, sval); - error++; - } - zlog_debug(" local-address: %s", sval); - } else if (strcmp(key, "local-interface") == 0) { - bpc->bpc_has_localif = true; - sval = json_object_get_string(jo_val); - if (strlcpy(bpc->bpc_localif, sval, - sizeof(bpc->bpc_localif)) - > sizeof(bpc->bpc_localif)) { - zlog_debug( - " local-interface: %s (truncated)", - sval); - error++; - } else { - zlog_debug(" local-interface: %s", sval); - } - } else if (strcmp(key, "vrf-name") == 0) { - bpc->bpc_has_vrfname = true; - sval = json_object_get_string(jo_val); - if (strlcpy(bpc->bpc_vrfname, sval, - sizeof(bpc->bpc_vrfname)) - > sizeof(bpc->bpc_vrfname)) { - zlog_debug(" vrf-name: %s (truncated)", - sval); - error++; - } else { - zlog_debug(" vrf-name: %s", sval); - } - } else if (strcmp(key, "detect-multiplier") == 0) { - bpc->bpc_detectmultiplier = - json_object_get_int64(jo_val); - bpc->bpc_has_detectmultiplier = true; - zlog_debug(" detect-multiplier: %u", - bpc->bpc_detectmultiplier); - } else if (strcmp(key, "receive-interval") == 0) { - bpc->bpc_recvinterval = json_object_get_int64(jo_val); - bpc->bpc_has_recvinterval = true; - zlog_debug(" receive-interval: %" PRIu64, - bpc->bpc_recvinterval); - } else if (strcmp(key, "transmit-interval") == 0) { - bpc->bpc_txinterval = json_object_get_int64(jo_val); - bpc->bpc_has_txinterval = true; - zlog_debug(" transmit-interval: %" PRIu64, - bpc->bpc_txinterval); - } else if (strcmp(key, "echo-receive-interval") == 0) { - bpc->bpc_echorecvinterval = json_object_get_int64(jo_val); - bpc->bpc_has_echorecvinterval = true; - zlog_debug(" echo-receive-interval: %" PRIu64, - bpc->bpc_echorecvinterval); - } else if (strcmp(key, "echo-transmit-interval") == 0) { - bpc->bpc_echotxinterval = json_object_get_int64(jo_val); - bpc->bpc_has_echotxinterval = true; - zlog_debug(" echo-transmit-interval: %" PRIu64, - bpc->bpc_echotxinterval); - } else if (strcmp(key, "create-only") == 0) { - bpc->bpc_createonly = json_object_get_boolean(jo_val); - zlog_debug(" create-only: %s", - bpc->bpc_createonly ? "true" : "false"); - } else if (strcmp(key, "shutdown") == 0) { - bpc->bpc_shutdown = json_object_get_boolean(jo_val); - zlog_debug(" shutdown: %s", - bpc->bpc_shutdown ? "true" : "false"); - } else if (strcmp(key, "echo-mode") == 0) { - bpc->bpc_echo = json_object_get_boolean(jo_val); - zlog_debug(" echo-mode: %s", - bpc->bpc_echo ? "true" : "false"); - } else if (strcmp(key, "label") == 0) { - bpc->bpc_has_label = true; - sval = json_object_get_string(jo_val); - if (strlcpy(bpc->bpc_label, sval, - sizeof(bpc->bpc_label)) - > sizeof(bpc->bpc_label)) { - zlog_debug(" label: %s (truncated)", - sval); - error++; - } else { - zlog_debug(" label: %s", sval); - } - } else { - sval = json_object_get_string(jo_val); - zlog_warn("%s:%d invalid configuration: '%s: %s'", - __func__, __LINE__, key, sval); - error++; - } - } - - if (bpc->bpc_peer.sa_sin.sin_family == 0) { - zlog_debug("%s:%d no peer address provided", __func__, - __LINE__); - error++; - } - - return error; -} - -static int parse_peer_label_config(struct json_object *jo, - struct bfd_peer_cfg *bpc) -{ - struct peer_label *pl; - struct json_object *label; - const char *sval; - - /* Get label and translate it to BFD daemon key. */ - if (!json_object_object_get_ex(jo, "label", &label)) - return 1; - - sval = json_object_get_string(label); - - pl = pl_find(sval); - if (pl == NULL) - return 1; - - zlog_debug(" peer-label: %s", sval); - - /* Translate the label into BFD address keys. */ - bs_to_bpc(pl->pl_bs, bpc); - - return 0; -} - - -/* - * Control socket JSON parsing. - */ -int config_request_add(const char *jsonstr) -{ - struct json_object *jo; - - jo = json_tokener_parse(jsonstr); - if (jo == NULL) - return -1; - - return parse_config_json(jo, config_add, NULL); -} - -int config_request_del(const char *jsonstr) -{ - struct json_object *jo; - - jo = json_tokener_parse(jsonstr); - if (jo == NULL) - return -1; - - return parse_config_json(jo, config_del, NULL); -} - -char *config_response(const char *status, const char *error) -{ - struct json_object *resp, *jo; - char *jsonstr; - - resp = json_object_new_object(); - if (resp == NULL) - return NULL; - - /* Add 'status' response key. */ - jo = json_object_new_string(status); - if (jo == NULL) { - json_object_put(resp); - return NULL; - } - - json_object_object_add(resp, "status", jo); - - /* Add 'error' response key. */ - if (error != NULL) { - jo = json_object_new_string(error); - if (jo == NULL) { - json_object_put(resp); - return NULL; - } - - json_object_object_add(resp, "error", jo); - } - - /* Generate JSON response. */ - jsonstr = XSTRDUP( - MTYPE_BFDD_NOTIFICATION, - json_object_to_json_string_ext(resp, BFDD_JSON_CONV_OPTIONS)); - json_object_put(resp); - - return jsonstr; -} - -char *config_notify(struct bfd_session *bs) -{ - struct json_object *resp; - char *jsonstr; - time_t now; - - resp = json_object_new_object(); - if (resp == NULL) - return NULL; - - json_object_string_add(resp, "op", BCM_NOTIFY_PEER_STATUS); - - json_object_add_peer(resp, bs); - - /* Add status information */ - json_object_int_add(resp, "id", bs->discrs.my_discr); - json_object_int_add(resp, "remote-id", bs->discrs.my_discr); - - switch (bs->ses_state) { - case PTM_BFD_UP: - json_object_string_add(resp, "state", "up"); - - now = monotime(NULL); - json_object_int_add(resp, "uptime", now - bs->uptime.tv_sec); - break; - case PTM_BFD_ADM_DOWN: - json_object_string_add(resp, "state", "adm-down"); - break; - case PTM_BFD_DOWN: - json_object_string_add(resp, "state", "down"); - - now = monotime(NULL); - json_object_int_add(resp, "downtime", - now - bs->downtime.tv_sec); - break; - case PTM_BFD_INIT: - json_object_string_add(resp, "state", "init"); - break; - - default: - json_object_string_add(resp, "state", "unknown"); - break; - } - - json_object_int_add(resp, "diagnostics", bs->local_diag); - json_object_int_add(resp, "remote-diagnostics", bs->remote_diag); - - /* Generate JSON response. */ - jsonstr = XSTRDUP( - MTYPE_BFDD_NOTIFICATION, - json_object_to_json_string_ext(resp, BFDD_JSON_CONV_OPTIONS)); - json_object_put(resp); - - return jsonstr; -} - -char *config_notify_config(const char *op, struct bfd_session *bs) -{ - struct json_object *resp; - char *jsonstr; - - resp = json_object_new_object(); - if (resp == NULL) - return NULL; - - json_object_string_add(resp, "op", op); - - json_object_add_peer(resp, bs); - - /* On peer deletion we don't need to add any additional information. */ - if (strcmp(op, BCM_NOTIFY_CONFIG_DELETE) == 0) - goto skip_config; - - json_object_int_add(resp, "detect-multiplier", bs->detect_mult); - json_object_int_add(resp, "receive-interval", - bs->timers.required_min_rx / 1000); - json_object_int_add(resp, "transmit-interval", - bs->timers.desired_min_tx / 1000); - json_object_int_add(resp, "echo-receive-interval", - bs->timers.required_min_echo_rx / 1000); - json_object_int_add(resp, "echo-transmit-interval", - bs->timers.desired_min_echo_tx / 1000); - - json_object_int_add(resp, "remote-detect-multiplier", - bs->remote_detect_mult); - json_object_int_add(resp, "remote-receive-interval", - bs->remote_timers.required_min_rx / 1000); - json_object_int_add(resp, "remote-transmit-interval", - bs->remote_timers.desired_min_tx / 1000); - json_object_int_add(resp, "remote-echo-receive-interval", - bs->remote_timers.required_min_echo / 1000); - - if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO)) - json_object_boolean_true_add(resp, "echo-mode"); - else - json_object_boolean_false_add(resp, "echo-mode"); - - if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN)) - json_object_boolean_true_add(resp, "shutdown"); - else - json_object_boolean_false_add(resp, "shutdown"); - -skip_config: - /* Generate JSON response. */ - jsonstr = XSTRDUP( - MTYPE_BFDD_NOTIFICATION, - json_object_to_json_string_ext(resp, BFDD_JSON_CONV_OPTIONS)); - json_object_put(resp); - - return jsonstr; -} - -int config_notify_request(struct bfd_control_socket *bcs, const char *jsonstr, - bpc_handle bh) -{ - struct json_object *jo; - - jo = json_tokener_parse(jsonstr); - if (jo == NULL) - return -1; - - return parse_config_json(jo, bh, bcs); -} - -static int json_object_add_peer(struct json_object *jo, struct bfd_session *bs) -{ - char addr_buf[INET6_ADDRSTRLEN]; - - /* Add peer 'key' information. */ - if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_IPV6)) - json_object_boolean_true_add(jo, "ipv6"); - else - json_object_boolean_false_add(jo, "ipv6"); - - if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) { - json_object_boolean_true_add(jo, "multihop"); - json_object_string_add(jo, "peer-address", - inet_ntop(bs->key.family, &bs->key.peer, - addr_buf, sizeof(addr_buf))); - json_object_string_add(jo, "local-address", - inet_ntop(bs->key.family, &bs->key.local, - addr_buf, sizeof(addr_buf))); - if (bs->key.vrfname[0]) - json_object_string_add(jo, "vrf-name", bs->key.vrfname); - } else { - json_object_boolean_false_add(jo, "multihop"); - json_object_string_add(jo, "peer-address", - inet_ntop(bs->key.family, &bs->key.peer, - addr_buf, sizeof(addr_buf))); - if (memcmp(&bs->key.local, &zero_addr, sizeof(bs->key.local))) - json_object_string_add( - jo, "local-address", - inet_ntop(bs->key.family, &bs->key.local, - addr_buf, sizeof(addr_buf))); - if (bs->key.ifname[0]) - json_object_string_add(jo, "local-interface", - bs->key.ifname); - } - - if (bs->pl) - json_object_string_add(jo, "label", bs->pl->pl_label); - - return 0; -} - - -/* - * Label handling - */ -struct peer_label *pl_find(const char *label) -{ - struct peer_label *pl; - - TAILQ_FOREACH (pl, &bglobal.bg_pllist, pl_entry) { - if (strcmp(pl->pl_label, label) != 0) - continue; - - return pl; - } - - return NULL; -} - -struct peer_label *pl_new(const char *label, struct bfd_session *bs) -{ - struct peer_label *pl; - - pl = XCALLOC(MTYPE_BFDD_LABEL, sizeof(*pl)); - - if (strlcpy(pl->pl_label, label, sizeof(pl->pl_label)) - > sizeof(pl->pl_label)) - zlog_warn("%s:%d: label was truncated", __func__, __LINE__); - - pl->pl_bs = bs; - bs->pl = pl; - - TAILQ_INSERT_HEAD(&bglobal.bg_pllist, pl, pl_entry); - - return pl; -} - -void pl_free(struct peer_label *pl) -{ - if (pl == NULL) - return; - - /* Remove the pointer back. */ - pl->pl_bs->pl = NULL; - - TAILQ_REMOVE(&bglobal.bg_pllist, pl, pl_entry); - XFREE(MTYPE_BFDD_LABEL, pl); -} diff --git a/bfdd/control.c b/bfdd/control.c deleted file mode 100644 index 98fd813ef7..0000000000 --- a/bfdd/control.c +++ /dev/null @@ -1,844 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/********************************************************************* - * Copyright 2017-2018 Network Device Education Foundation, Inc. ("NetDEF") - * - * control.c: implements the BFD daemon control socket. It will be used - * to talk with clients daemon/scripts/consumers. - * - * Authors - * ------- - * Rafael Zalamena - */ - -#include - -#include -#include - -#include - -#include "bfd.h" - -/* - * Prototypes - */ -static int sock_set_nonblock(int fd); -struct bfd_control_queue *control_queue_new(struct bfd_control_socket *bcs); -static void control_queue_free(struct bfd_control_socket *bcs, - struct bfd_control_queue *bcq); -static int control_queue_dequeue(struct bfd_control_socket *bcs); -static int control_queue_enqueue(struct bfd_control_socket *bcs, - struct bfd_control_msg *bcm); -static int control_queue_enqueue_first(struct bfd_control_socket *bcs, - struct bfd_control_msg *bcm); -struct bfd_notify_peer *control_notifypeer_new(struct bfd_control_socket *bcs, - struct bfd_session *bs); -static void control_notifypeer_free(struct bfd_control_socket *bcs, - struct bfd_notify_peer *bnp); -struct bfd_notify_peer *control_notifypeer_find(struct bfd_control_socket *bcs, - struct bfd_session *bs); - - -struct bfd_control_socket *control_new(int sd); -static void control_free(struct bfd_control_socket *bcs); -static void control_reset_buf(struct bfd_control_buffer *bcb); -static void control_read(struct event *t); -static void control_write(struct event *t); - -static void control_handle_request_add(struct bfd_control_socket *bcs, - struct bfd_control_msg *bcm); -static void control_handle_request_del(struct bfd_control_socket *bcs, - struct bfd_control_msg *bcm); -static int notify_add_cb(struct bfd_peer_cfg *bpc, void *arg); -static int notify_del_cb(struct bfd_peer_cfg *bpc, void *arg); -static void control_handle_notify_add(struct bfd_control_socket *bcs, - struct bfd_control_msg *bcm); -static void control_handle_notify_del(struct bfd_control_socket *bcs, - struct bfd_control_msg *bcm); -static void _control_handle_notify(struct hash_bucket *hb, void *arg); -static void control_handle_notify(struct bfd_control_socket *bcs, - struct bfd_control_msg *bcm); -static void control_response(struct bfd_control_socket *bcs, uint16_t id, - const char *status, const char *error); - -static void _control_notify_config(struct bfd_control_socket *bcs, - const char *op, struct bfd_session *bs); -static void _control_notify(struct bfd_control_socket *bcs, - struct bfd_session *bs); - - -/* - * Functions - */ -static int sock_set_nonblock(int fd) -{ - int flags; - - flags = fcntl(fd, F_GETFL, 0); - if (flags == -1) { - zlog_warn("%s: fcntl F_GETFL: %s", __func__, strerror(errno)); - return -1; - } - - flags |= O_NONBLOCK; - if (fcntl(fd, F_SETFL, flags) == -1) { - zlog_warn("%s: fcntl F_SETFL: %s", __func__, strerror(errno)); - return -1; - } - - return 0; -} - -int control_init(const char *path) -{ - int sd; - mode_t umval; - struct sockaddr_un sun_ = { - .sun_family = AF_UNIX, - }; - - assert(path); - - strlcpy(sun_.sun_path, path, sizeof(sun_.sun_path)); - - /* Remove previously created sockets. */ - unlink(sun_.sun_path); - - sd = socket(AF_UNIX, SOCK_STREAM, PF_UNSPEC); - if (sd == -1) { - zlog_err("%s: socket: %s", __func__, strerror(errno)); - return -1; - } - - umval = umask(0); - if (bind(sd, (struct sockaddr *)&sun_, sizeof(sun_)) == -1) { - zlog_err("%s: bind: %s", __func__, strerror(errno)); - close(sd); - return -1; - } - umask(umval); - - if (listen(sd, SOMAXCONN) == -1) { - zlog_err("%s: listen: %s", __func__, strerror(errno)); - close(sd); - return -1; - } - - sock_set_nonblock(sd); - - bglobal.bg_csock = sd; - - return 0; -} - -void control_shutdown(void) -{ - struct bfd_control_socket *bcs; - - event_cancel(&bglobal.bg_csockev); - - socket_close(&bglobal.bg_csock); - - while (!TAILQ_EMPTY(&bglobal.bg_bcslist)) { - bcs = TAILQ_FIRST(&bglobal.bg_bcslist); - control_free(bcs); - } -} - -void control_accept(struct event *t) -{ - int csock, sd = EVENT_FD(t); - - csock = accept(sd, NULL, 0); - if (csock == -1) { - zlog_warn("%s: accept: %s", __func__, strerror(errno)); - return; - } - - control_new(csock); - - event_add_read(master, control_accept, NULL, sd, &bglobal.bg_csockev); -} - - -/* - * Client handling - */ -struct bfd_control_socket *control_new(int sd) -{ - struct bfd_control_socket *bcs; - - bcs = XCALLOC(MTYPE_BFDD_CONTROL, sizeof(*bcs)); - - /* Disable notifications by default. */ - bcs->bcs_notify = 0; - - bcs->bcs_sd = sd; - event_add_read(master, control_read, bcs, sd, &bcs->bcs_ev); - - TAILQ_INIT(&bcs->bcs_bcqueue); - TAILQ_INIT(&bcs->bcs_bnplist); - TAILQ_INSERT_TAIL(&bglobal.bg_bcslist, bcs, bcs_entry); - - return bcs; -} - -static void control_free(struct bfd_control_socket *bcs) -{ - struct bfd_control_queue *bcq; - struct bfd_notify_peer *bnp; - - event_cancel(&(bcs->bcs_ev)); - event_cancel(&(bcs->bcs_outev)); - - close(bcs->bcs_sd); - - TAILQ_REMOVE(&bglobal.bg_bcslist, bcs, bcs_entry); - - /* Empty output queue. */ - while (!TAILQ_EMPTY(&bcs->bcs_bcqueue)) { - bcq = TAILQ_FIRST(&bcs->bcs_bcqueue); - control_queue_free(bcs, bcq); - } - - /* Empty notification list. */ - while (!TAILQ_EMPTY(&bcs->bcs_bnplist)) { - bnp = TAILQ_FIRST(&bcs->bcs_bnplist); - control_notifypeer_free(bcs, bnp); - } - - control_reset_buf(&bcs->bcs_bin); - XFREE(MTYPE_BFDD_CONTROL, bcs); -} - -struct bfd_notify_peer *control_notifypeer_new(struct bfd_control_socket *bcs, - struct bfd_session *bs) -{ - struct bfd_notify_peer *bnp; - - bnp = control_notifypeer_find(bcs, bs); - if (bnp) - return bnp; - - bnp = XCALLOC(MTYPE_BFDD_CONTROL, sizeof(*bnp)); - - TAILQ_INSERT_TAIL(&bcs->bcs_bnplist, bnp, bnp_entry); - bnp->bnp_bs = bs; - bs->refcount++; - - return bnp; -} - -static void control_notifypeer_free(struct bfd_control_socket *bcs, - struct bfd_notify_peer *bnp) -{ - TAILQ_REMOVE(&bcs->bcs_bnplist, bnp, bnp_entry); - bnp->bnp_bs->refcount--; - XFREE(MTYPE_BFDD_CONTROL, bnp); -} - -struct bfd_notify_peer *control_notifypeer_find(struct bfd_control_socket *bcs, - struct bfd_session *bs) -{ - struct bfd_notify_peer *bnp; - - TAILQ_FOREACH (bnp, &bcs->bcs_bnplist, bnp_entry) { - if (bnp->bnp_bs == bs) - return bnp; - } - - return NULL; -} - -struct bfd_control_queue *control_queue_new(struct bfd_control_socket *bcs) -{ - struct bfd_control_queue *bcq; - - bcq = XCALLOC(MTYPE_BFDD_NOTIFICATION, sizeof(*bcq)); - - control_reset_buf(&bcq->bcq_bcb); - TAILQ_INSERT_TAIL(&bcs->bcs_bcqueue, bcq, bcq_entry); - - return bcq; -} - -static void control_queue_free(struct bfd_control_socket *bcs, - struct bfd_control_queue *bcq) -{ - control_reset_buf(&bcq->bcq_bcb); - TAILQ_REMOVE(&bcs->bcs_bcqueue, bcq, bcq_entry); - XFREE(MTYPE_BFDD_NOTIFICATION, bcq); -} - -static int control_queue_dequeue(struct bfd_control_socket *bcs) -{ - struct bfd_control_queue *bcq; - - /* List is empty, nothing to do. */ - if (TAILQ_EMPTY(&bcs->bcs_bcqueue)) - goto empty_list; - - bcq = TAILQ_FIRST(&bcs->bcs_bcqueue); - control_queue_free(bcs, bcq); - - /* Get the next buffer to send. */ - if (TAILQ_EMPTY(&bcs->bcs_bcqueue)) - goto empty_list; - - bcq = TAILQ_FIRST(&bcs->bcs_bcqueue); - bcs->bcs_bout = &bcq->bcq_bcb; - - bcs->bcs_outev = NULL; - event_add_write(master, control_write, bcs, bcs->bcs_sd, - &bcs->bcs_outev); - - return 1; - -empty_list: - event_cancel(&(bcs->bcs_outev)); - bcs->bcs_bout = NULL; - return 0; -} - -static int control_queue_enqueue(struct bfd_control_socket *bcs, - struct bfd_control_msg *bcm) -{ - struct bfd_control_queue *bcq; - struct bfd_control_buffer *bcb; - - bcq = control_queue_new(bcs); - - bcb = &bcq->bcq_bcb; - bcb->bcb_left = sizeof(struct bfd_control_msg) + ntohl(bcm->bcm_length); - bcb->bcb_pos = 0; - bcb->bcb_bcm = bcm; - - /* If this is the first item, then dequeue and start using it. */ - if (bcs->bcs_bout == NULL) { - bcs->bcs_bout = bcb; - - /* New messages, active write events. */ - event_add_write(master, control_write, bcs, bcs->bcs_sd, - &bcs->bcs_outev); - } - - return 0; -} - -static int control_queue_enqueue_first(struct bfd_control_socket *bcs, - struct bfd_control_msg *bcm) -{ - struct bfd_control_queue *bcq, *bcqn; - struct bfd_control_buffer *bcb; - - /* Enqueue it somewhere. */ - if (control_queue_enqueue(bcs, bcm) == -1) - return -1; - - /* - * The item is either the first or the last. So we must first - * check the best case where the item is already the first. - */ - bcq = TAILQ_FIRST(&bcs->bcs_bcqueue); - bcb = &bcq->bcq_bcb; - if (bcm == bcb->bcb_bcm) - return 0; - - /* - * The item was not the first, so it is the last. We'll try to - * assign it to the head of the queue, however if there is a - * transfer in progress, then we have to make the item as the - * next one. - * - * Interrupting the transfer of in progress message will cause - * the client to lose track of the message position/data. - */ - bcqn = TAILQ_LAST(&bcs->bcs_bcqueue, bcqueue); - TAILQ_REMOVE(&bcs->bcs_bcqueue, bcqn, bcq_entry); - if (bcb->bcb_pos != 0) { - /* - * First position is already being sent, insert into - * second position. - */ - TAILQ_INSERT_AFTER(&bcs->bcs_bcqueue, bcq, bcqn, bcq_entry); - } else { - /* - * Old message didn't start being sent, we still have - * time to put this one in the head of the queue. - */ - TAILQ_INSERT_HEAD(&bcs->bcs_bcqueue, bcqn, bcq_entry); - bcb = &bcqn->bcq_bcb; - bcs->bcs_bout = bcb; - } - - return 0; -} - -static void control_reset_buf(struct bfd_control_buffer *bcb) -{ - /* Get ride of old data. */ - XFREE(MTYPE_BFDD_NOTIFICATION, bcb->bcb_buf); - bcb->bcb_pos = 0; - bcb->bcb_left = 0; -} - -static void control_read(struct event *t) -{ - struct bfd_control_socket *bcs = EVENT_ARG(t); - struct bfd_control_buffer *bcb = &bcs->bcs_bin; - int sd = bcs->bcs_sd; - struct bfd_control_msg bcm; - ssize_t bread; - size_t plen; - - /* - * Check if we have already downloaded message content, if so then skip - * to - * download the rest of it and process. - * - * Otherwise download a new message header and allocate the necessary - * memory. - */ - if (bcb->bcb_buf != NULL) - goto skip_header; - - bread = read(sd, &bcm, sizeof(bcm)); - if (bread == 0) { - control_free(bcs); - return; - } - if (bread < 0) { - if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) - goto schedule_next_read; - - zlog_warn("%s: read: %s", __func__, strerror(errno)); - control_free(bcs); - return; - } - - /* Validate header fields. */ - plen = ntohl(bcm.bcm_length); - if (plen < 2) { - zlog_debug("%s: client closed due small message length: %d", - __func__, bcm.bcm_length); - control_free(bcs); - return; - } - -#define FRR_BFD_MAXLEN 10 * 1024 - - if (plen > FRR_BFD_MAXLEN) { - zlog_debug("%s: client closed, invalid message length: %d", - __func__, bcm.bcm_length); - control_free(bcs); - return; - } - - if (bcm.bcm_ver != BMV_VERSION_1) { - zlog_debug("%s: client closed due bad version: %d", __func__, - bcm.bcm_ver); - control_free(bcs); - return; - } - - /* Prepare the buffer to load the message. */ - bcs->bcs_version = bcm.bcm_ver; - bcs->bcs_type = bcm.bcm_type; - - bcb->bcb_pos = sizeof(bcm); - bcb->bcb_left = plen; - bcb->bcb_buf = XMALLOC(MTYPE_BFDD_NOTIFICATION, - sizeof(bcm) + bcb->bcb_left + 1); - if (bcb->bcb_buf == NULL) { - zlog_warn("%s: not enough memory for message size: %zu", - __func__, bcb->bcb_left); - control_free(bcs); - return; - } - - memcpy(bcb->bcb_buf, &bcm, sizeof(bcm)); - - /* Terminate data string with NULL for later processing. */ - bcb->bcb_buf[sizeof(bcm) + bcb->bcb_left] = 0; - -skip_header: - /* Download the remaining data of the message and process it. */ - bread = read(sd, &bcb->bcb_buf[bcb->bcb_pos], bcb->bcb_left); - if (bread == 0) { - control_free(bcs); - return; - } - if (bread < 0) { - if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) - goto schedule_next_read; - - zlog_warn("%s: read: %s", __func__, strerror(errno)); - control_free(bcs); - return; - } - - bcb->bcb_pos += bread; - bcb->bcb_left -= bread; - /* We need more data, return to wait more. */ - if (bcb->bcb_left > 0) - goto schedule_next_read; - - switch (bcb->bcb_bcm->bcm_type) { - case BMT_REQUEST_ADD: - control_handle_request_add(bcs, bcb->bcb_bcm); - break; - case BMT_REQUEST_DEL: - control_handle_request_del(bcs, bcb->bcb_bcm); - break; - case BMT_NOTIFY: - control_handle_notify(bcs, bcb->bcb_bcm); - break; - case BMT_NOTIFY_ADD: - control_handle_notify_add(bcs, bcb->bcb_bcm); - break; - case BMT_NOTIFY_DEL: - control_handle_notify_del(bcs, bcb->bcb_bcm); - break; - - default: - zlog_debug("%s: unhandled message type: %d", __func__, - bcb->bcb_bcm->bcm_type); - control_response(bcs, bcb->bcb_bcm->bcm_id, BCM_RESPONSE_ERROR, - "invalid message type"); - break; - } - - bcs->bcs_version = 0; - bcs->bcs_type = 0; - control_reset_buf(bcb); - -schedule_next_read: - bcs->bcs_ev = NULL; - event_add_read(master, control_read, bcs, sd, &bcs->bcs_ev); -} - -static void control_write(struct event *t) -{ - struct bfd_control_socket *bcs = EVENT_ARG(t); - struct bfd_control_buffer *bcb = bcs->bcs_bout; - int sd = bcs->bcs_sd; - ssize_t bwrite; - - bwrite = write(sd, &bcb->bcb_buf[bcb->bcb_pos], bcb->bcb_left); - if (bwrite == 0) { - control_free(bcs); - return; - } - if (bwrite < 0) { - if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) { - bcs->bcs_outev = NULL; - event_add_write(master, control_write, bcs, bcs->bcs_sd, - &bcs->bcs_outev); - return; - } - - zlog_warn("%s: write: %s", __func__, strerror(errno)); - control_free(bcs); - return; - } - - bcb->bcb_pos += bwrite; - bcb->bcb_left -= bwrite; - if (bcb->bcb_left > 0) { - bcs->bcs_outev = NULL; - event_add_write(master, control_write, bcs, bcs->bcs_sd, - &bcs->bcs_outev); - return; - } - - control_queue_dequeue(bcs); -} - - -/* - * Message processing - */ -static void control_handle_request_add(struct bfd_control_socket *bcs, - struct bfd_control_msg *bcm) -{ - const char *json = (const char *)bcm->bcm_data; - - if (config_request_add(json) == 0) - control_response(bcs, bcm->bcm_id, BCM_RESPONSE_OK, NULL); - else - control_response(bcs, bcm->bcm_id, BCM_RESPONSE_ERROR, - "request add failed"); -} - -static void control_handle_request_del(struct bfd_control_socket *bcs, - struct bfd_control_msg *bcm) -{ - const char *json = (const char *)bcm->bcm_data; - - if (config_request_del(json) == 0) - control_response(bcs, bcm->bcm_id, BCM_RESPONSE_OK, NULL); - else - control_response(bcs, bcm->bcm_id, BCM_RESPONSE_ERROR, - "request del failed"); -} - -static struct bfd_session *_notify_find_peer(struct bfd_peer_cfg *bpc) -{ - struct peer_label *pl; - - if (bpc->bpc_has_label) { - pl = pl_find(bpc->bpc_label); - if (pl) - return pl->pl_bs; - } - - return bs_peer_find(bpc); -} - -static void _control_handle_notify(struct hash_bucket *hb, void *arg) -{ - struct bfd_control_socket *bcs = arg; - struct bfd_session *bs = hb->data; - - /* Notify peer configuration. */ - if (bcs->bcs_notify & BCM_NOTIFY_CONFIG) - _control_notify_config(bcs, BCM_NOTIFY_CONFIG_ADD, bs); - - /* Notify peer status. */ - if (bcs->bcs_notify & BCM_NOTIFY_PEER_STATE) - _control_notify(bcs, bs); -} - -static void control_handle_notify(struct bfd_control_socket *bcs, - struct bfd_control_msg *bcm) -{ - memcpy(&bcs->bcs_notify, bcm->bcm_data, sizeof(bcs->bcs_notify)); - - control_response(bcs, bcm->bcm_id, BCM_RESPONSE_OK, NULL); - - /* - * If peer asked for notification configuration, send everything that - * was configured until the moment to sync up. - */ - if (bcs->bcs_notify & (BCM_NOTIFY_CONFIG | BCM_NOTIFY_PEER_STATE)) - bfd_id_iterate(_control_handle_notify, bcs); -} - -static int notify_add_cb(struct bfd_peer_cfg *bpc, void *arg) -{ - struct bfd_control_socket *bcs = arg; - struct bfd_session *bs = _notify_find_peer(bpc); - - if (bs == NULL) - return -1; - - control_notifypeer_new(bcs, bs); - - /* Notify peer status. */ - _control_notify(bcs, bs); - - return 0; -} - -static int notify_del_cb(struct bfd_peer_cfg *bpc, void *arg) -{ - struct bfd_control_socket *bcs = arg; - struct bfd_session *bs = _notify_find_peer(bpc); - struct bfd_notify_peer *bnp; - - if (bs == NULL) - return -1; - - bnp = control_notifypeer_find(bcs, bs); - if (bnp) - control_notifypeer_free(bcs, bnp); - - return 0; -} - -static void control_handle_notify_add(struct bfd_control_socket *bcs, - struct bfd_control_msg *bcm) -{ - const char *json = (const char *)bcm->bcm_data; - - if (config_notify_request(bcs, json, notify_add_cb) == 0) { - control_response(bcs, bcm->bcm_id, BCM_RESPONSE_OK, NULL); - return; - } - - control_response(bcs, bcm->bcm_id, BCM_RESPONSE_ERROR, - "failed to parse notify data"); -} - -static void control_handle_notify_del(struct bfd_control_socket *bcs, - struct bfd_control_msg *bcm) -{ - const char *json = (const char *)bcm->bcm_data; - - if (config_notify_request(bcs, json, notify_del_cb) == 0) { - control_response(bcs, bcm->bcm_id, BCM_RESPONSE_OK, NULL); - return; - } - - control_response(bcs, bcm->bcm_id, BCM_RESPONSE_ERROR, - "failed to parse notify data"); -} - - -/* - * Internal functions used by the BFD daemon. - */ -static void control_response(struct bfd_control_socket *bcs, uint16_t id, - const char *status, const char *error) -{ - struct bfd_control_msg *bcm; - char *jsonstr; - size_t jsonstrlen; - - /* Generate JSON response. */ - jsonstr = config_response(status, error); - if (jsonstr == NULL) { - zlog_warn("%s: config_response: failed to get JSON str", - __func__); - return; - } - - /* Allocate data and answer. */ - jsonstrlen = strlen(jsonstr); - bcm = XMALLOC(MTYPE_BFDD_NOTIFICATION, - sizeof(struct bfd_control_msg) + jsonstrlen); - - bcm->bcm_length = htonl(jsonstrlen); - bcm->bcm_ver = BMV_VERSION_1; - bcm->bcm_type = BMT_RESPONSE; - bcm->bcm_id = id; - memcpy(bcm->bcm_data, jsonstr, jsonstrlen); - XFREE(MTYPE_BFDD_NOTIFICATION, jsonstr); - - control_queue_enqueue_first(bcs, bcm); -} - -static void _control_notify(struct bfd_control_socket *bcs, - struct bfd_session *bs) -{ - struct bfd_control_msg *bcm; - char *jsonstr; - size_t jsonstrlen; - - /* Generate JSON response. */ - jsonstr = config_notify(bs); - if (jsonstr == NULL) { - zlog_warn("%s: config_notify: failed to get JSON str", - __func__); - return; - } - - /* Allocate data and answer. */ - jsonstrlen = strlen(jsonstr); - bcm = XMALLOC(MTYPE_BFDD_NOTIFICATION, - sizeof(struct bfd_control_msg) + jsonstrlen); - - bcm->bcm_length = htonl(jsonstrlen); - bcm->bcm_ver = BMV_VERSION_1; - bcm->bcm_type = BMT_NOTIFY; - bcm->bcm_id = htons(BCM_NOTIFY_ID); - memcpy(bcm->bcm_data, jsonstr, jsonstrlen); - XFREE(MTYPE_BFDD_NOTIFICATION, jsonstr); - - control_queue_enqueue(bcs, bcm); -} - -int control_notify(struct bfd_session *bs, uint8_t notify_state) -{ - struct bfd_control_socket *bcs; - struct bfd_notify_peer *bnp; - - /* Notify zebra listeners as well. */ - ptm_bfd_notify(bs, notify_state); - - /* - * PERFORMANCE: reuse the bfd_control_msg allocated data for - * all control sockets to avoid wasting memory. - */ - TAILQ_FOREACH (bcs, &bglobal.bg_bcslist, bcs_entry) { - /* - * Test for all notifications first, then search for - * specific peers. - */ - if ((bcs->bcs_notify & BCM_NOTIFY_PEER_STATE) == 0) { - bnp = control_notifypeer_find(bcs, bs); - /* - * If the notification is not configured here, - * don't send it. - */ - if (bnp == NULL) - continue; - } - - _control_notify(bcs, bs); - } - - return 0; -} - -static void _control_notify_config(struct bfd_control_socket *bcs, - const char *op, struct bfd_session *bs) -{ - struct bfd_control_msg *bcm; - char *jsonstr; - size_t jsonstrlen; - - /* Generate JSON response. */ - jsonstr = config_notify_config(op, bs); - if (jsonstr == NULL) { - zlog_warn("%s: config_notify_config: failed to get JSON str", - __func__); - return; - } - - /* Allocate data and answer. */ - jsonstrlen = strlen(jsonstr); - bcm = XMALLOC(MTYPE_BFDD_NOTIFICATION, - sizeof(struct bfd_control_msg) + jsonstrlen); - - bcm->bcm_length = htonl(jsonstrlen); - bcm->bcm_ver = BMV_VERSION_1; - bcm->bcm_type = BMT_NOTIFY; - bcm->bcm_id = htons(BCM_NOTIFY_ID); - memcpy(bcm->bcm_data, jsonstr, jsonstrlen); - XFREE(MTYPE_BFDD_NOTIFICATION, jsonstr); - - control_queue_enqueue(bcs, bcm); -} - -int control_notify_config(const char *op, struct bfd_session *bs) -{ - struct bfd_control_socket *bcs; - struct bfd_notify_peer *bnp; - - /* Remove the control sockets notification for this peer. */ - if (strcmp(op, BCM_NOTIFY_CONFIG_DELETE) == 0 && bs->refcount > 0) { - TAILQ_FOREACH (bcs, &bglobal.bg_bcslist, bcs_entry) { - bnp = control_notifypeer_find(bcs, bs); - if (bnp) - control_notifypeer_free(bcs, bnp); - } - } - - /* - * PERFORMANCE: reuse the bfd_control_msg allocated data for - * all control sockets to avoid wasting memory. - */ - TAILQ_FOREACH (bcs, &bglobal.bg_bcslist, bcs_entry) { - /* - * Test for all notifications first, then search for - * specific peers. - */ - if ((bcs->bcs_notify & BCM_NOTIFY_CONFIG) == 0) - continue; - - _control_notify_config(bcs, op, bs); - } - - return 0; -} diff --git a/bfdd/dplane.c b/bfdd/dplane.c index d8539812e0..7f55f34073 100644 --- a/bfdd/dplane.c +++ b/bfdd/dplane.c @@ -354,7 +354,7 @@ bfd_dplane_session_state_change(struct bfd_dplane_ctx *bdc, bs->remote_timers.required_min_echo = ntohl(state->required_echo_rx); /* Notify and update counters. */ - control_notify(bs, bs->ses_state); + ptm_bfd_notify(bs, bs->ses_state); /* No state change. */ if (old_state == bs->ses_state) diff --git a/bfdd/ptm_adapter.c b/bfdd/ptm_adapter.c index b5ab2ef1d0..f6ebefb7be 100644 --- a/bfdd/ptm_adapter.c +++ b/bfdd/ptm_adapter.c @@ -148,7 +148,6 @@ static void _ptm_bfd_session_del(struct bfd_session *bs, uint8_t diag) "ptm-del-session: [%s] session refcount is zero but it was configured by CLI", bs_to_string(bs)); } else { - control_notify_config(BCM_NOTIFY_CONFIG_DELETE, bs); bfd_session_free(bs); } } @@ -892,7 +891,7 @@ static struct ptm_client *pc_new(uint32_t pid) return pc; /* Allocate the client data and save it. */ - pc = XCALLOC(MTYPE_BFDD_CONTROL, sizeof(*pc)); + pc = XCALLOC(MTYPE_BFDD_CLIENT, sizeof(*pc)); pc->pc_pid = pid; TAILQ_INSERT_HEAD(&pcqueue, pc, pc_entry); @@ -910,7 +909,7 @@ static void pc_free(struct ptm_client *pc) pcn_free(pcn); } - XFREE(MTYPE_BFDD_CONTROL, pc); + XFREE(MTYPE_BFDD_CLIENT, pc); } static void pc_free_all(void) @@ -934,7 +933,7 @@ static struct ptm_client_notification *pcn_new(struct ptm_client *pc, return pcn; /* Save the client notification data. */ - pcn = XCALLOC(MTYPE_BFDD_NOTIFICATION, sizeof(*pcn)); + pcn = XCALLOC(MTYPE_BFDD_CLIENT_NOTIFICATION, sizeof(*pcn)); TAILQ_INSERT_HEAD(&pc->pc_pcnqueue, pcn, pcn_entry); pcn->pcn_pc = pc; @@ -982,5 +981,5 @@ static void pcn_free(struct ptm_client_notification *pcn) pcn->pcn_pc = NULL; TAILQ_REMOVE(&pc->pc_pcnqueue, pcn, pcn_entry); - XFREE(MTYPE_BFDD_NOTIFICATION, pcn); + XFREE(MTYPE_BFDD_CLIENT_NOTIFICATION, pcn); } diff --git a/bfdd/subdir.am b/bfdd/subdir.am index b86a18967e..5d2d8fda5c 100644 --- a/bfdd/subdir.am +++ b/bfdd/subdir.am @@ -17,8 +17,6 @@ bfdd_libbfd_a_SOURCES = \ bfdd/bfdd_vty.c \ bfdd/bfdd_cli.c \ bfdd/bfd_packet.c \ - bfdd/config.c \ - bfdd/control.c \ bfdd/dplane.c \ bfdd/event.c \ bfdd/ptm_adapter.c \ @@ -37,7 +35,6 @@ clippy_scan += \ # end noinst_HEADERS += \ - bfdd/bfdctl.h \ bfdd/bfdd_nb.h \ bfdd/bfd.h \ # end diff --git a/snapcraft/scripts/bfdd-service b/snapcraft/scripts/bfdd-service index f94a7abb4b..5e41d1ae6d 100644 --- a/snapcraft/scripts/bfdd-service +++ b/snapcraft/scripts/bfdd-service @@ -9,6 +9,5 @@ exec $SNAP/sbin/bfdd \ -f $SNAP_DATA/bfdd.conf \ --pid_file $SNAP_DATA/bfdd.pid \ --socket $SNAP_DATA/zsock \ - --vty_socket $SNAP_DATA \ - --bfdctl $SNAP_DATA/bfdd.sock + --vty_socket $SNAP_DATA diff --git a/snapcraft/snapcraft.yaml.in b/snapcraft/snapcraft.yaml.in index d90236f7a2..eea9bfc0ee 100644 --- a/snapcraft/snapcraft.yaml.in +++ b/snapcraft/snapcraft.yaml.in @@ -249,7 +249,7 @@ apps: - network-bind - network-control bfdd-debug: - command: sbin/bfdd -f $SNAP_DATA/bfdd.conf --pid_file $SNAP_DATA/bfdd.pid --socket $SNAP_DATA/zsock --vty_socket $SNAP_DATA --bfdctl $SNAP_DATA/bfdd.sock + command: sbin/bfdd -f $SNAP_DATA/bfdd.conf --pid_file $SNAP_DATA/bfdd.pid --socket $SNAP_DATA/zsock --vty_socket $SNAP_DATA plugs: - network - network-bind From 5340fcf144b8041cf3a979c91814c9de81bec9d4 Mon Sep 17 00:00:00 2001 From: Rafael Zalamena Date: Wed, 24 Jul 2024 11:19:40 -0300 Subject: [PATCH 236/347] doc: missing distributed BFD man page bit Signed-off-by: Rafael Zalamena --- doc/manpages/bfd-options.rst | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/doc/manpages/bfd-options.rst b/doc/manpages/bfd-options.rst index e335ed120b..9cd43aa2fc 100644 --- a/doc/manpages/bfd-options.rst +++ b/doc/manpages/bfd-options.rst @@ -1,10 +1,39 @@ -BFD SOCKET ----------- +BFD +--- -The following option controls the BFD daemon control socket location. +The following options controls the BFD daemon auxiliary sockets. .. option:: --bfdctl bfd-control-socket Opens the BFD daemon control socket located at the pointed location. (default: |INSTALL_PREFIX_STATE|/bfdd.sock) + +.. option:: --dplaneaddr :
[<:port>] + + Configure the distributed BFD data plane listening socket bind address. + + One would expect the data plane to run in the same machine as FRR, so + the suggested configuration would be: + + ``--dplaneaddr unix:/var/run/frr/bfdd_dplane.sock`` + + Or using IPv4: + + ``--dplaneaddr ipv4:127.0.0.1`` + + Or using IPv6: + + ``--dplaneaddr ipv6:[::1]`` + + It is also possible to specify a port (for IPv4/IPv6 only): + + ``--dplaneaddr ipv6:[::1]:50701`` + + (if ommited the default port is ``50700``). + + It is also possible to operate in client mode (instead of listening for + connections). To connect to a data plane server append the letter 'c' to + the protocol, example: + + ``--dplaneaddr ipv4c:127.0.0.1`` From c4867fe2f2af19a18f9313b99ca4338a72bed81f Mon Sep 17 00:00:00 2001 From: Rafael Zalamena Date: Wed, 24 Jul 2024 11:42:11 -0300 Subject: [PATCH 237/347] doc: remove BFD control socket documentation Signed-off-by: Rafael Zalamena --- doc/manpages/bfd-options.rst | 6 ------ doc/user/bfd.rst | 13 ------------- 2 files changed, 19 deletions(-) diff --git a/doc/manpages/bfd-options.rst b/doc/manpages/bfd-options.rst index 9cd43aa2fc..2bad5f1521 100644 --- a/doc/manpages/bfd-options.rst +++ b/doc/manpages/bfd-options.rst @@ -3,12 +3,6 @@ BFD The following options controls the BFD daemon auxiliary sockets. -.. option:: --bfdctl bfd-control-socket - - Opens the BFD daemon control socket located at the pointed location. - - (default: |INSTALL_PREFIX_STATE|/bfdd.sock) - .. option:: --dplaneaddr :
[<:port>] Configure the distributed BFD data plane listening socket bind address. diff --git a/doc/user/bfd.rst b/doc/user/bfd.rst index b2127e8955..5c5584e28f 100644 --- a/doc/user/bfd.rst +++ b/doc/user/bfd.rst @@ -45,19 +45,6 @@ may also be specified (:ref:`common-invocation-options`). .. program:: bfdd -.. option:: --bfdctl - - Set the BFD daemon control socket location. If using a non-default - socket location:: - - /usr/lib/frr/bfdd --bfdctl /tmp/bfdd.sock - - - The default UNIX socket location is |INSTALL_PREFIX_STATE|/bfdd.sock - - This option overrides the location addition that the -N option provides - to the bfdd.sock - .. option:: --dplaneaddr :
[<:port>] Configure the distributed BFD data plane listening socket bind address. From 67e2718e1cd050a26e368e9f7ce409ae80faf131 Mon Sep 17 00:00:00 2001 From: Louis Scalbert Date: Fri, 26 Jul 2024 09:40:10 +0200 Subject: [PATCH 238/347] lib: remove duplicated flex_algos_free prototype Remove duplicated flex_algos_free prototype Signed-off-by: Louis Scalbert --- lib/flex_algo.h | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/flex_algo.h b/lib/flex_algo.h index e617e7cae8..ee1f617e29 100644 --- a/lib/flex_algo.h +++ b/lib/flex_algo.h @@ -117,7 +117,6 @@ struct flex_algo *flex_algo_alloc(struct flex_algos *flex_algos, uint8_t algorithm, void *arg); struct flex_algo *flex_algo_lookup(struct flex_algos *flex_algos, uint8_t algorithm); -void flex_algos_free(struct flex_algos *flex_algos); bool flex_algo_definition_cmp(struct flex_algo *fa1, struct flex_algo *fa2); void flex_algo_delete(struct flex_algos *flex_algos, uint8_t algorithm); bool flex_algo_id_valid(uint16_t algorithm); From 9c0e668050b2ae77257cdcb780d444edb78c036b Mon Sep 17 00:00:00 2001 From: Louis Scalbert Date: Fri, 26 Jul 2024 09:28:40 +0200 Subject: [PATCH 239/347] isisd: move flex_algo_delete into flex_algo_destroy Move flex_algo_delete() content into isis_instance_flex_algo_destroy() because it is called only once. Rename _flex_algo_delete to flex_algo_free() Cosmetic change. Signed-off-by: Louis Scalbert --- isisd/isis_nb_config.c | 8 +++++++- lib/flex_algo.c | 21 ++------------------- lib/flex_algo.h | 2 +- 3 files changed, 10 insertions(+), 21 deletions(-) diff --git a/isisd/isis_nb_config.c b/isisd/isis_nb_config.c index 8926b624ea..f67b28cd7c 100644 --- a/isisd/isis_nb_config.c +++ b/isisd/isis_nb_config.c @@ -2875,6 +2875,8 @@ int isis_instance_flex_algo_create(struct nb_cb_create_args *args) int isis_instance_flex_algo_destroy(struct nb_cb_destroy_args *args) { + struct listnode *node, *nnode; + struct flex_algo *fa; struct isis_area *area; uint32_t algorithm; @@ -2883,7 +2885,11 @@ int isis_instance_flex_algo_destroy(struct nb_cb_destroy_args *args) switch (args->event) { case NB_EV_APPLY: - flex_algo_delete(area->flex_algos, algorithm); + for (ALL_LIST_ELEMENTS(area->flex_algos->flex_algos, node, + nnode, fa)) { + if (fa->algorithm == algorithm) + flex_algo_free(area->flex_algos, fa); + } lsp_regenerate_schedule(area, area->is_type, 0); break; case NB_EV_VALIDATE: diff --git a/lib/flex_algo.c b/lib/flex_algo.c index f48117ff1b..ab0eef67cb 100644 --- a/lib/flex_algo.c +++ b/lib/flex_algo.c @@ -20,9 +20,6 @@ DEFINE_MTYPE_STATIC(LIB, FLEX_ALGO_DATABASE, "Flex-Algo database"); DEFINE_MTYPE_STATIC(LIB, FLEX_ALGO, "Flex-Algo algorithm information"); -static void _flex_algo_delete(struct flex_algos *flex_algos, - struct flex_algo *fa); - struct flex_algos *flex_algos_alloc(flex_algo_allocator_t allocator, flex_algo_releaser_t releaser) { @@ -42,7 +39,7 @@ void flex_algos_free(struct flex_algos *flex_algos) struct flex_algo *fa; for (ALL_LIST_ELEMENTS(flex_algos->flex_algos, node, nnode, fa)) - _flex_algo_delete(flex_algos, fa); + flex_algo_free(flex_algos, fa); list_delete(&flex_algos->flex_algos); XFREE(MTYPE_FLEX_ALGO_DATABASE, flex_algos); } @@ -63,8 +60,7 @@ struct flex_algo *flex_algo_alloc(struct flex_algos *flex_algos, return fa; } -static void _flex_algo_delete(struct flex_algos *flex_algos, - struct flex_algo *fa) +void flex_algo_free(struct flex_algos *flex_algos, struct flex_algo *fa) { if (flex_algos->releaser) flex_algos->releaser(fa->data); @@ -75,19 +71,6 @@ static void _flex_algo_delete(struct flex_algos *flex_algos, XFREE(MTYPE_FLEX_ALGO, fa); } - -void flex_algo_delete(struct flex_algos *flex_algos, uint8_t algorithm) -{ - struct listnode *node, *nnode; - struct flex_algo *fa; - - for (ALL_LIST_ELEMENTS(flex_algos->flex_algos, node, nnode, fa)) { - if (fa->algorithm != algorithm) - continue; - _flex_algo_delete(flex_algos, fa); - } -} - /** * @brief Look up the local flex-algo object by its algorithm number. * @param algorithm flex-algo algorithm number diff --git a/lib/flex_algo.h b/lib/flex_algo.h index ee1f617e29..54b37783e6 100644 --- a/lib/flex_algo.h +++ b/lib/flex_algo.h @@ -115,10 +115,10 @@ struct flex_algos *flex_algos_alloc(flex_algo_allocator_t allocator, void flex_algos_free(struct flex_algos *flex_algos); struct flex_algo *flex_algo_alloc(struct flex_algos *flex_algos, uint8_t algorithm, void *arg); +void flex_algo_free(struct flex_algos *flex_algos, struct flex_algo *fa); struct flex_algo *flex_algo_lookup(struct flex_algos *flex_algos, uint8_t algorithm); bool flex_algo_definition_cmp(struct flex_algo *fa1, struct flex_algo *fa2); -void flex_algo_delete(struct flex_algos *flex_algos, uint8_t algorithm); bool flex_algo_id_valid(uint16_t algorithm); char *flex_algo_metric_type_print(char *type_str, size_t sz, enum flex_algo_metric_type metric_type); From ae27101e6ff8b636f02254ba0aa2217239d896e1 Mon Sep 17 00:00:00 2001 From: Louis Scalbert Date: Thu, 25 Jul 2024 09:34:10 +0200 Subject: [PATCH 240/347] isisd: fix building asla at first flex-algo config When an color affinity is set on an interface before configuring the flex-algorithm, the ASLA (Application Specific Link-Attribute) sub-TLV is not build. Flex-algo fails to build the paths when a affinity constraint is required because of the lacking of information contained in ASLA. There are no problems when the configuration order is reversed. For example: > affinity-map red bit-position 1 > > interface eth2 > link-params > affinity red > > router isis 1 > mpls-te on > flex-algo 129 > dataplane sr-mpls > advertise-definition > affinity include-any green In isis_link_params_update_asla(), the ASLA sub-TLV is not build when the list of flex-algos is empty. Update ASLA when the first flex-algorithm is configured. Fixes: 893882ee20 ("isisd: add isis flex-algo configuration backend") Signed-off-by: Louis Scalbert --- isisd/isis_nb_config.c | 11 ++++++++++- isisd/isis_te.c | 4 ++-- isisd/isis_te.h | 2 ++ 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/isisd/isis_nb_config.c b/isisd/isis_nb_config.c index f67b28cd7c..66b66194c8 100644 --- a/isisd/isis_nb_config.c +++ b/isisd/isis_nb_config.c @@ -2838,7 +2838,9 @@ int isis_instance_flex_algo_create(struct nb_cb_create_args *args) { struct isis_area *area; struct flex_algo *fa; - bool advertise; + bool advertise, update_te; + struct isis_circuit *circuit; + struct listnode *node; uint32_t algorithm; uint32_t priority = FLEX_ALGO_PRIO_DEFAULT; struct isis_flex_algo_alloc_arg arg; @@ -2851,6 +2853,7 @@ int isis_instance_flex_algo_create(struct nb_cb_create_args *args) area = nb_running_get_entry(args->dnode, NULL, true); arg.algorithm = algorithm; arg.area = area; + update_te = list_isempty(area->flex_algos->flex_algos); fa = flex_algo_alloc(area->flex_algos, algorithm, &arg); fa->priority = priority; fa->advertise_definition = advertise; @@ -2862,6 +2865,12 @@ int isis_instance_flex_algo_create(struct nb_cb_create_args *args) admin_group_allow_explicit_zero( &fa->admin_group_include_all); } + if (update_te) { + for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, + circuit)) + isis_link_params_update_asla(circuit, + circuit->interface); + } lsp_regenerate_schedule(area, area->is_type, 0); break; case NB_EV_VALIDATE: diff --git a/isisd/isis_te.c b/isisd/isis_te.c index 3683f74558..fead826fcd 100644 --- a/isisd/isis_te.c +++ b/isisd/isis_te.c @@ -164,8 +164,8 @@ void isis_mpls_te_term(struct isis_area *area) XFREE(MTYPE_ISIS_MPLS_TE, area->mta); } -static void isis_link_params_update_asla(struct isis_circuit *circuit, - struct interface *ifp) +void isis_link_params_update_asla(struct isis_circuit *circuit, + struct interface *ifp) { struct isis_asla_subtlvs *asla; struct listnode *node, *nnode; diff --git a/isisd/isis_te.h b/isisd/isis_te.h index bf1dc2b9bb..326e50479d 100644 --- a/isisd/isis_te.h +++ b/isisd/isis_te.h @@ -112,6 +112,8 @@ void isis_mpls_te_init(void); void isis_mpls_te_create(struct isis_area *area); void isis_mpls_te_disable(struct isis_area *area); void isis_mpls_te_term(struct isis_area *area); +void isis_link_params_update_asla(struct isis_circuit *circuit, + struct interface *ifp); void isis_link_params_update(struct isis_circuit *, struct interface *); int isis_mpls_te_update(struct interface *); void isis_te_lsp_event(struct isis_lsp *lsp, enum lsp_event event); From e3634cb7c53a280d023fbdd0bf055f13356e0a8e Mon Sep 17 00:00:00 2001 From: Louis Scalbert Date: Fri, 26 Jul 2024 09:56:14 +0200 Subject: [PATCH 241/347] isisd: free asla at last flex-algo unconfiguration Free ASLA when the last flex-algo is unconfigured. Signed-off-by: Louis Scalbert --- isisd/isis_nb_config.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/isisd/isis_nb_config.c b/isisd/isis_nb_config.c index 66b66194c8..2b47d5cbeb 100644 --- a/isisd/isis_nb_config.c +++ b/isisd/isis_nb_config.c @@ -2884,6 +2884,7 @@ int isis_instance_flex_algo_create(struct nb_cb_create_args *args) int isis_instance_flex_algo_destroy(struct nb_cb_destroy_args *args) { + struct isis_circuit *circuit; struct listnode *node, *nnode; struct flex_algo *fa; struct isis_area *area; @@ -2899,6 +2900,12 @@ int isis_instance_flex_algo_destroy(struct nb_cb_destroy_args *args) if (fa->algorithm == algorithm) flex_algo_free(area->flex_algos, fa); } + if (list_isempty(area->flex_algos->flex_algos)) { + for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, + circuit)) + isis_link_params_update_asla(circuit, + circuit->interface); + } lsp_regenerate_schedule(area, area->is_type, 0); break; case NB_EV_VALIDATE: From c682ddd1002070179735ec8dfd3087a61fea84df Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Tue, 23 Jul 2024 10:31:02 -0400 Subject: [PATCH 242/347] tests: Increase timing of bgp_duplicate_nexthop a) Make timers more aggressive for this test b) Double run_and_expect time for one sub test. These two changes cause this test to pass regularly for me when this test used to fail regularly for me. Signed-off-by: Donald Sharp --- tests/topotests/bgp_duplicate_nexthop/r1/bgpd.conf | 1 + tests/topotests/bgp_duplicate_nexthop/r3/bgpd.conf | 1 + tests/topotests/bgp_duplicate_nexthop/r5/bgpd.conf | 1 + tests/topotests/bgp_duplicate_nexthop/r6/bgpd.conf | 1 + .../bgp_duplicate_nexthop/test_bgp_duplicate_nexthop.py | 2 +- 5 files changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/topotests/bgp_duplicate_nexthop/r1/bgpd.conf b/tests/topotests/bgp_duplicate_nexthop/r1/bgpd.conf index 31f06dbb90..8084962587 100644 --- a/tests/topotests/bgp_duplicate_nexthop/r1/bgpd.conf +++ b/tests/topotests/bgp_duplicate_nexthop/r1/bgpd.conf @@ -1,5 +1,6 @@ router bgp 64500 bgp router-id 192.0.2.1 + timers bgp 3 9 no bgp ebgp-requires-policy neighbor rrserver peer-group neighbor rrserver remote-as 64500 diff --git a/tests/topotests/bgp_duplicate_nexthop/r3/bgpd.conf b/tests/topotests/bgp_duplicate_nexthop/r3/bgpd.conf index 2b03f51a23..7312dba407 100644 --- a/tests/topotests/bgp_duplicate_nexthop/r3/bgpd.conf +++ b/tests/topotests/bgp_duplicate_nexthop/r3/bgpd.conf @@ -1,4 +1,5 @@ router bgp 64500 view one + timers bgp 3 9 bgp router-id 192.0.2.3 neighbor rr peer-group neighbor rr remote-as 64500 diff --git a/tests/topotests/bgp_duplicate_nexthop/r5/bgpd.conf b/tests/topotests/bgp_duplicate_nexthop/r5/bgpd.conf index 272183b1ac..e46d7c5ed4 100644 --- a/tests/topotests/bgp_duplicate_nexthop/r5/bgpd.conf +++ b/tests/topotests/bgp_duplicate_nexthop/r5/bgpd.conf @@ -1,4 +1,5 @@ router bgp 64500 + timers bgp 3 9 bgp router-id 192.0.2.5 no bgp ebgp-requires-policy no bgp network import-check diff --git a/tests/topotests/bgp_duplicate_nexthop/r6/bgpd.conf b/tests/topotests/bgp_duplicate_nexthop/r6/bgpd.conf index 68bd36eb8a..3aa9adb18b 100644 --- a/tests/topotests/bgp_duplicate_nexthop/r6/bgpd.conf +++ b/tests/topotests/bgp_duplicate_nexthop/r6/bgpd.conf @@ -1,4 +1,5 @@ router bgp 64500 + timers bgp 3 9 bgp router-id 192.0.2.6 no bgp ebgp-requires-policy no bgp network import-check diff --git a/tests/topotests/bgp_duplicate_nexthop/test_bgp_duplicate_nexthop.py b/tests/topotests/bgp_duplicate_nexthop/test_bgp_duplicate_nexthop.py index 83fae71bf5..b458c64e33 100644 --- a/tests/topotests/bgp_duplicate_nexthop/test_bgp_duplicate_nexthop.py +++ b/tests/topotests/bgp_duplicate_nexthop/test_bgp_duplicate_nexthop.py @@ -212,7 +212,7 @@ def check_ipv4_prefix_with_multiple_nexthops(prefix, multipath=True): test_func = functools.partial( ip_check_path_selection, tgen.gears["r1"], prefix, expected ) - _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=120, wait=0.5) assert ( result is None ), f"Failed to check that {prefix} uses the IGP label 16055 and 16006" From 6914cceea2ac6c9caed6cd7035e7c163ebc9d6ce Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Fri, 26 Jul 2024 14:02:31 -0400 Subject: [PATCH 243/347] tests: Fix test_bgp_vpnv4_per_nexthop_label.py to handle timing changes So the test script is making changes to a vpn configuration by changing something fundamental about the vpn. This is causing a window where routes we are interested in are: present ( from pre-change ) then withdrawn ( the test change causes this ) then present ( with the new data ) The test code was trying to test for this by checking to see if the prefix was there, but due to timing issues it's not always there when we look for it. Modify the test to get the vpn table version prior to the change( as that it should not be moving around ) and then change the test for the prefix to look for a version that is later than the vpn's table version. Then we know that it is *after* everything has stabilized again. Signed-off-by: Donald Sharp --- .../test_bgp_vpnv4_per_nexthop_label.py | 31 ++++++++++++++----- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/tests/topotests/bgp_vpnv4_per_nexthop_label/test_bgp_vpnv4_per_nexthop_label.py b/tests/topotests/bgp_vpnv4_per_nexthop_label/test_bgp_vpnv4_per_nexthop_label.py index cf1d3cb2b8..8a41b55ffb 100644 --- a/tests/topotests/bgp_vpnv4_per_nexthop_label/test_bgp_vpnv4_per_nexthop_label.py +++ b/tests/topotests/bgp_vpnv4_per_nexthop_label/test_bgp_vpnv4_per_nexthop_label.py @@ -151,17 +151,24 @@ def teardown_module(_mod): tgen.stop_topology() -def check_bgp_vpnv4_prefix_presence(router, prefix): +def check_bgp_vpnv4_prefix_presence(router, prefix, table_version): "Check the presence of a prefix" tgen = get_topogen() dump = router.vtysh_cmd("show bgp ipv4 vpn {} json".format(prefix), isjson=True) if not dump: return "{}, prefix ipv4 vpn {} is not installed yet".format(router.name, prefix) + + for _, paths in dump.items(): + for path in paths["paths"]: + new_version = path["version"] + if new_version <= table_version: + return "{}, prefix ipv4 vpn {} has not been updated yet".format(router.name, prefix) + return None -def bgp_vpnv4_table_check(router, group, label_list=None, label_value_expected=None): +def bgp_vpnv4_table_check(router, group, label_list=None, label_value_expected=None, table_version=0): """ Dump and check that vpnv4 entries have the same MPLS label value * 'router': the router to check @@ -173,7 +180,7 @@ def bgp_vpnv4_table_check(router, group, label_list=None, label_value_expected=N stored_label_inited = False for prefix in group: - test_func = functools.partial(check_bgp_vpnv4_prefix_presence, router, prefix) + test_func = functools.partial(check_bgp_vpnv4_prefix_presence, router, prefix, table_version) success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "{}, prefix ipv4 vpn {} is not installed yet".format( router.name, prefix @@ -218,7 +225,7 @@ def bgp_vpnv4_table_check(router, group, label_list=None, label_value_expected=N ) -def bgp_vpnv4_table_check_all(router, label_list=None, same=False): +def bgp_vpnv4_table_check_all(router, label_list=None, same=False, table_version=0): """ Dump and check that vpnv4 entries are correctly configured with specific label values * 'router': the router to check @@ -236,6 +243,7 @@ def bgp_vpnv4_table_check_all(router, label_list=None, same=False): + PREFIXES_REDIST + PREFIXES_CONNECTED, label_list=label_list, + table_version=table_version ) else: for group in ( @@ -245,7 +253,7 @@ def bgp_vpnv4_table_check_all(router, label_list=None, same=False): PREFIXES_REDIST, PREFIXES_CONNECTED, ): - bgp_vpnv4_table_check(router, group=group, label_list=label_list) + bgp_vpnv4_table_check(router, group=group, label_list=label_list, table_version=table_version) def check_show_mpls_table(router, blacklist=None, label_list=None, whitelist=None): @@ -349,6 +357,9 @@ def check_show_mpls_table_entry_label_not_found(router, inlabel): return "not good" return None +def get_table_version(router): + table = router.vtysh_cmd("show bgp ipv4 vpn json", isjson=True) + return table["tableVersion"] def mpls_entry_get_interface(router, label): """ @@ -686,6 +697,7 @@ def test_changing_default_label_value(): old_len != 1 ), "r1, number of labels used should be greater than 1, oberved {} ".format(old_len) + table_version = get_table_version(router) logger.info("r1, vrf1, changing the default MPLS label value to export to 222") router.vtysh_cmd( "configure terminal\nrouter bgp 65500 vrf vrf1\naddress-family ipv4 unicast\nlabel vpn export 222\n", @@ -705,7 +717,7 @@ def test_changing_default_label_value(): # check label repartition is ok logger.info("r1, vpnv4 table, check the number of labels used after modification") label_list = set() - bgp_vpnv4_table_check_all(router, label_list) + bgp_vpnv4_table_check_all(router, label_list, table_version=table_version) new_len = len(label_list) assert ( old_len == new_len @@ -734,6 +746,7 @@ def test_unconfigure_allocation_mode_nexthop(): logger.info("Unconfiguring allocation mode per nexthop") router = tgen.gears["r1"] + table_version = get_table_version(router) router.vtysh_cmd( "configure terminal\nrouter bgp 65500 vrf vrf1\naddress-family ipv4 unicast\nno label vpn export allocation-mode per-nexthop\n", isjson=False, @@ -752,7 +765,7 @@ def test_unconfigure_allocation_mode_nexthop(): # Check vpnv4 routes from r1 logger.info("Checking vpnv4 routes on r1") label_list = set() - bgp_vpnv4_table_check_all(router, label_list=label_list, same=True) + bgp_vpnv4_table_check_all(router, label_list=label_list, same=True, table_version=table_version) assert len(label_list) == 1, "r1, multiple Label values found for vpnv4 updates" new_label = label_list.pop() @@ -782,6 +795,8 @@ def test_reconfigure_allocation_mode_nexthop(): logger.info("Reconfiguring allocation mode per nexthop") router = tgen.gears["r1"] + + table_version = get_table_version(router) router.vtysh_cmd( "configure terminal\nrouter bgp 65500 vrf vrf1\naddress-family ipv4 unicast\nlabel vpn export allocation-mode per-nexthop\n", isjson=False, @@ -800,7 +815,7 @@ def test_reconfigure_allocation_mode_nexthop(): # Check vpnv4 routes from r1 logger.info("Checking vpnv4 routes on r1") label_list = set() - bgp_vpnv4_table_check_all(router, label_list=label_list) + bgp_vpnv4_table_check_all(router, label_list=label_list, table_version=table_version) assert len(label_list) != 1, "r1, only 1 label values found for vpnv4 updates" # Check mpls table with all values From 77a296cb0898b1839ef4a86a7ad1a4b7d33270e8 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Fri, 26 Jul 2024 14:15:40 -0400 Subject: [PATCH 244/347] tests: Fix test_bgp_vpnv6_per_nexthop_label.py to handle timing changes So the test script is making changes to a vpn configuration by changing something fundamental about the vpn. This is causing a window where routes we are interested in are: present ( from pre-change ) then withdrawn ( the test change causes this ) then present ( with the new data ) The test code was trying to test for this by checking to see if the prefix was there, but due to timing issues it's not always there when we look for it. Modify the test to get the vpn table version prior to the change( as that it should not be moving around ) and then change the test for the prefix to look for a version that is later than the vpn's table version. Then we know that it is *after* everything has stabilized again. Signed-off-by: Donald Sharp --- .../test_bgp_vpnv6_per_nexthop_label.py | 29 ++++++++++++++----- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/tests/topotests/bgp_vpnv6_per_nexthop_label/test_bgp_vpnv6_per_nexthop_label.py b/tests/topotests/bgp_vpnv6_per_nexthop_label/test_bgp_vpnv6_per_nexthop_label.py index f8d26427eb..8f10b3bc7e 100644 --- a/tests/topotests/bgp_vpnv6_per_nexthop_label/test_bgp_vpnv6_per_nexthop_label.py +++ b/tests/topotests/bgp_vpnv6_per_nexthop_label/test_bgp_vpnv6_per_nexthop_label.py @@ -150,17 +150,24 @@ def teardown_module(_mod): tgen.stop_topology() -def check_bgp_vpnv6_prefix_presence(router, prefix): +def check_bgp_vpnv6_prefix_presence(router, prefix, table_version): "Check the presence of a prefix" tgen = get_topogen() dump = router.vtysh_cmd("show bgp ipv6 vpn {} json".format(prefix), isjson=True) if not dump: return "{}, prefix ipv6 vpn {} is not installed yet".format(router.name, prefix) + + for _, paths in dump.items(): + for path in paths["paths"]: + new_version = path["version"] + if new_version <= table_version: + return "{}, prefix ipv6 vpn {} has not been updated yet".format(router.name, prefix) + return None -def bgp_vpnv6_table_check(router, group, label_list=None, label_value_expected=None): +def bgp_vpnv6_table_check(router, group, label_list=None, label_value_expected=None, table_version=0): """ Dump and check that vpnv6 entries have the same MPLS label value * 'router': the router to check @@ -172,7 +179,7 @@ def bgp_vpnv6_table_check(router, group, label_list=None, label_value_expected=N stored_label_inited = False for prefix in group: - test_func = functools.partial(check_bgp_vpnv6_prefix_presence, router, prefix) + test_func = functools.partial(check_bgp_vpnv6_prefix_presence, router, prefix, table_version) success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "{}, prefix ipv6 vpn {} is not installed yet".format( router.name, prefix @@ -214,7 +221,7 @@ def bgp_vpnv6_table_check(router, group, label_list=None, label_value_expected=N ) -def bgp_vpnv6_table_check_all(router, label_list=None, same=False): +def bgp_vpnv6_table_check_all(router, label_list=None, same=False, table_version=0): """ Dump and check that vpnv6 entries are correctly configured with specific label values * 'router': the router to check @@ -231,6 +238,7 @@ def bgp_vpnv6_table_check_all(router, label_list=None, same=False): + PREFIXES_REDIST_R14 + PREFIXES_CONNECTED, label_list=label_list, + table_version=table_version ) else: for group in ( @@ -239,7 +247,7 @@ def bgp_vpnv6_table_check_all(router, label_list=None, same=False): PREFIXES_REDIST_R14, PREFIXES_CONNECTED, ): - bgp_vpnv6_table_check(router, group=group, label_list=label_list) + bgp_vpnv6_table_check(router, group=group, label_list=label_list, table_version=table_version) def check_show_mpls_table(router, blacklist=None, label_list=None, whitelist=None): @@ -345,6 +353,11 @@ def check_show_mpls_table_entry_label_not_found(router, inlabel): return None +def get_table_version(router): + table = router.vtysh_cmd("show bgp ipv6 vpn json", isjson=True) + return table["tableVersion"] + + def mpls_entry_get_interface(router, label): """ Assert that the label is in MPLS table @@ -691,6 +704,7 @@ def test_changing_default_label_value(): old_len != 1 ), "r1, number of labels used should be greater than 1, oberved {} ".format(old_len) + table_version = get_table_version(router) logger.info("r1, vrf1, changing the default MPLS label value to export to 222") router.vtysh_cmd( "configure terminal\nrouter bgp 65500 vrf vrf1\naddress-family ipv6 unicast\nlabel vpn export 222\n", @@ -710,7 +724,7 @@ def test_changing_default_label_value(): # check label repartition is ok logger.info("r1, VPNv6 table, check the number of labels used after modification") label_list = set() - bgp_vpnv6_table_check_all(router, label_list) + bgp_vpnv6_table_check_all(router, label_list, table_version=table_version) new_len = len(label_list) assert ( old_len == new_len @@ -786,6 +800,7 @@ def test_reconfigure_allocation_mode_nexthop(): logger.info("Reconfiguring allocation mode per nexthop") router = tgen.gears["r1"] + table_version = get_table_version(router) dump = router.vtysh_cmd( "configure terminal\nrouter bgp 65500 vrf vrf1\naddress-family ipv6 unicast\nlabel vpn export allocation-mode per-nexthop\n", isjson=False, @@ -804,7 +819,7 @@ def test_reconfigure_allocation_mode_nexthop(): # Check vpnv6 routes from r1 logger.info("Checking VPNv6 routes on r1") label_list = set() - bgp_vpnv6_table_check_all(router, label_list=label_list) + bgp_vpnv6_table_check_all(router, label_list=label_list, table_version=table_version) assert len(label_list) != 1, "r1, only 1 label values found for VPNv6 updates" # Check mpls table with all values From ce3cea38dd624af75a1298dd42ff3ddb7a7d0134 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Fri, 26 Jul 2024 14:16:36 -0400 Subject: [PATCH 245/347] tests: Run black on bgp_vpnv[4|6]_per_nexthop_label I did not have my formatting right, let's get it right for these two. Signed-off-by: Donald Sharp --- .../test_bgp_vpnv4_per_nexthop_label.py | 28 ++++++++++++++----- .../test_bgp_vpnv6_per_nexthop_label.py | 22 +++++++++++---- 2 files changed, 37 insertions(+), 13 deletions(-) diff --git a/tests/topotests/bgp_vpnv4_per_nexthop_label/test_bgp_vpnv4_per_nexthop_label.py b/tests/topotests/bgp_vpnv4_per_nexthop_label/test_bgp_vpnv4_per_nexthop_label.py index 8a41b55ffb..146687d588 100644 --- a/tests/topotests/bgp_vpnv4_per_nexthop_label/test_bgp_vpnv4_per_nexthop_label.py +++ b/tests/topotests/bgp_vpnv4_per_nexthop_label/test_bgp_vpnv4_per_nexthop_label.py @@ -163,12 +163,16 @@ def check_bgp_vpnv4_prefix_presence(router, prefix, table_version): for path in paths["paths"]: new_version = path["version"] if new_version <= table_version: - return "{}, prefix ipv4 vpn {} has not been updated yet".format(router.name, prefix) + return "{}, prefix ipv4 vpn {} has not been updated yet".format( + router.name, prefix + ) return None -def bgp_vpnv4_table_check(router, group, label_list=None, label_value_expected=None, table_version=0): +def bgp_vpnv4_table_check( + router, group, label_list=None, label_value_expected=None, table_version=0 +): """ Dump and check that vpnv4 entries have the same MPLS label value * 'router': the router to check @@ -180,7 +184,9 @@ def bgp_vpnv4_table_check(router, group, label_list=None, label_value_expected=N stored_label_inited = False for prefix in group: - test_func = functools.partial(check_bgp_vpnv4_prefix_presence, router, prefix, table_version) + test_func = functools.partial( + check_bgp_vpnv4_prefix_presence, router, prefix, table_version + ) success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "{}, prefix ipv4 vpn {} is not installed yet".format( router.name, prefix @@ -243,7 +249,7 @@ def bgp_vpnv4_table_check_all(router, label_list=None, same=False, table_version + PREFIXES_REDIST + PREFIXES_CONNECTED, label_list=label_list, - table_version=table_version + table_version=table_version, ) else: for group in ( @@ -253,7 +259,9 @@ def bgp_vpnv4_table_check_all(router, label_list=None, same=False, table_version PREFIXES_REDIST, PREFIXES_CONNECTED, ): - bgp_vpnv4_table_check(router, group=group, label_list=label_list, table_version=table_version) + bgp_vpnv4_table_check( + router, group=group, label_list=label_list, table_version=table_version + ) def check_show_mpls_table(router, blacklist=None, label_list=None, whitelist=None): @@ -357,10 +365,12 @@ def check_show_mpls_table_entry_label_not_found(router, inlabel): return "not good" return None + def get_table_version(router): table = router.vtysh_cmd("show bgp ipv4 vpn json", isjson=True) return table["tableVersion"] + def mpls_entry_get_interface(router, label): """ Assert that the label is in MPLS table @@ -765,7 +775,9 @@ def test_unconfigure_allocation_mode_nexthop(): # Check vpnv4 routes from r1 logger.info("Checking vpnv4 routes on r1") label_list = set() - bgp_vpnv4_table_check_all(router, label_list=label_list, same=True, table_version=table_version) + bgp_vpnv4_table_check_all( + router, label_list=label_list, same=True, table_version=table_version + ) assert len(label_list) == 1, "r1, multiple Label values found for vpnv4 updates" new_label = label_list.pop() @@ -815,7 +827,9 @@ def test_reconfigure_allocation_mode_nexthop(): # Check vpnv4 routes from r1 logger.info("Checking vpnv4 routes on r1") label_list = set() - bgp_vpnv4_table_check_all(router, label_list=label_list, table_version=table_version) + bgp_vpnv4_table_check_all( + router, label_list=label_list, table_version=table_version + ) assert len(label_list) != 1, "r1, only 1 label values found for vpnv4 updates" # Check mpls table with all values diff --git a/tests/topotests/bgp_vpnv6_per_nexthop_label/test_bgp_vpnv6_per_nexthop_label.py b/tests/topotests/bgp_vpnv6_per_nexthop_label/test_bgp_vpnv6_per_nexthop_label.py index 8f10b3bc7e..5fef6e9e60 100644 --- a/tests/topotests/bgp_vpnv6_per_nexthop_label/test_bgp_vpnv6_per_nexthop_label.py +++ b/tests/topotests/bgp_vpnv6_per_nexthop_label/test_bgp_vpnv6_per_nexthop_label.py @@ -162,12 +162,16 @@ def check_bgp_vpnv6_prefix_presence(router, prefix, table_version): for path in paths["paths"]: new_version = path["version"] if new_version <= table_version: - return "{}, prefix ipv6 vpn {} has not been updated yet".format(router.name, prefix) + return "{}, prefix ipv6 vpn {} has not been updated yet".format( + router.name, prefix + ) return None -def bgp_vpnv6_table_check(router, group, label_list=None, label_value_expected=None, table_version=0): +def bgp_vpnv6_table_check( + router, group, label_list=None, label_value_expected=None, table_version=0 +): """ Dump and check that vpnv6 entries have the same MPLS label value * 'router': the router to check @@ -179,7 +183,9 @@ def bgp_vpnv6_table_check(router, group, label_list=None, label_value_expected=N stored_label_inited = False for prefix in group: - test_func = functools.partial(check_bgp_vpnv6_prefix_presence, router, prefix, table_version) + test_func = functools.partial( + check_bgp_vpnv6_prefix_presence, router, prefix, table_version + ) success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "{}, prefix ipv6 vpn {} is not installed yet".format( router.name, prefix @@ -238,7 +244,7 @@ def bgp_vpnv6_table_check_all(router, label_list=None, same=False, table_version + PREFIXES_REDIST_R14 + PREFIXES_CONNECTED, label_list=label_list, - table_version=table_version + table_version=table_version, ) else: for group in ( @@ -247,7 +253,9 @@ def bgp_vpnv6_table_check_all(router, label_list=None, same=False, table_version PREFIXES_REDIST_R14, PREFIXES_CONNECTED, ): - bgp_vpnv6_table_check(router, group=group, label_list=label_list, table_version=table_version) + bgp_vpnv6_table_check( + router, group=group, label_list=label_list, table_version=table_version + ) def check_show_mpls_table(router, blacklist=None, label_list=None, whitelist=None): @@ -819,7 +827,9 @@ def test_reconfigure_allocation_mode_nexthop(): # Check vpnv6 routes from r1 logger.info("Checking VPNv6 routes on r1") label_list = set() - bgp_vpnv6_table_check_all(router, label_list=label_list, table_version=table_version) + bgp_vpnv6_table_check_all( + router, label_list=label_list, table_version=table_version + ) assert len(label_list) != 1, "r1, only 1 label values found for VPNv6 updates" # Check mpls table with all values From 7c20ffaaba228fe5a6893d49caf50ec1df1ec142 Mon Sep 17 00:00:00 2001 From: Dave LeRoy Date: Thu, 25 Jul 2024 11:58:22 -0700 Subject: [PATCH 246/347] nhrpd: fixes duplicate auth extension When an NHRP server was forwarding a message, it was copying all extensions from the originally received packet. The authentication extension must be regenerated hop by hop per RFC2332. The copied auth extension had an incorrect length. This fix checks for the auth extension when copying extensions and omits the original packet auth and instead regenerates a new auth extension. Fix bug #16466 Signed-off-by: Dave LeRoy --- nhrpd/nhrp_peer.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/nhrpd/nhrp_peer.c b/nhrpd/nhrp_peer.c index 0407b86be8..3495317d4c 100644 --- a/nhrpd/nhrp_peer.c +++ b/nhrpd/nhrp_peer.c @@ -959,9 +959,12 @@ static void nhrp_peer_forward(struct nhrp_peer *p, if (type == NHRP_EXTENSION_END) break; - dst = nhrp_ext_push(zb, hdr, htons(ext->type)); - if (!dst) - goto err; + dst = NULL; + if (type != NHRP_EXTENSION_AUTHENTICATION) { + dst = nhrp_ext_push(zb, hdr, htons(ext->type)); + if (!dst) + goto err; + } switch (type) { case NHRP_EXTENSION_FORWARD_TRANSIT_NHS: @@ -1047,12 +1050,11 @@ static void nhrp_peer_forward(struct nhrp_peer *p, } break; case NHRP_EXTENSION_AUTHENTICATION: - /* At this point, received packet has been authenticated. - * Just need to regenerate auth extension before forwarding. - * This will be done below in nhrp_packet_complete_auth(). + /* Extensions can be copied from original packet except + * authentication extension which must be regenerated + * hop by hop. */ break; - default: if (htons(ext->type) & NHRP_EXTENSION_FLAG_COMPULSORY) /* FIXME: RFC says to just copy, but not @@ -1068,7 +1070,8 @@ static void nhrp_peer_forward(struct nhrp_peer *p, zbuf_copy(zb, &extpl, len); break; } - nhrp_ext_complete(zb, dst); + if (dst) + nhrp_ext_complete(zb, dst); } nhrp_packet_complete_auth(zb, hdr, pp->ifp, true); From bfae003b62a9dde706ab55250ebda7ea3cb1e676 Mon Sep 17 00:00:00 2001 From: Rafael Zalamena Date: Mon, 3 May 2021 08:37:51 -0300 Subject: [PATCH 247/347] yang: MSDP SA filtering support Add option to configure MSDP peer SA incoming/outgoing filtering. Signed-off-by: Rafael Zalamena --- yang/frr-pim.yang | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/yang/frr-pim.yang b/yang/frr-pim.yang index 732a38a9e3..cc8d6445aa 100644 --- a/yang/frr-pim.yang +++ b/yang/frr-pim.yang @@ -5,6 +5,10 @@ module frr-pim { prefix frr-pim; + import frr-filter { + prefix frr-filter; + } + import frr-interface { prefix frr-interface; } @@ -267,6 +271,18 @@ module frr-pim { description "MSDP source IP address."; } + + leaf sa-filter-in { + type frr-filter:access-list-name; + description + "Access list name used to filter the incoming SAs exchanged."; + } + + leaf sa-filter-out { + type frr-filter:access-list-name; + description + "Access list name used to filter the outgoing SAs exchanged."; + } } container mlag { From be3bfe5daa721acc0182d6c3f003a9d9d80e6612 Mon Sep 17 00:00:00 2001 From: Rafael Zalamena Date: Mon, 3 May 2021 10:25:52 -0300 Subject: [PATCH 248/347] pimd: MSDP SA filtering Implement MSDP peer incoming/outgoing SA filter. Note ---- Cisco extended access list has a special meaning: the first address is the source address to filter. Example: ! The rules below filter some LAN prefix to be leaked out access-list filter-lan-source deny ip 192.168.0.0 0.0.255.255 224.0.0.0 0.255.255.255 access-list filter-lan-source permit any router pim msdp peer 192.168.0.1 sa-filter filter-lan-source out ! The rules below filter some special management group from being ! learned access-list filter-management-group deny 230.0.0.0 0.255.255.255 access-list filter-management-group permit any router pim msdp peer 192.168.0.1 sa-filter filter-management-group in Signed-off-by: Rafael Zalamena --- pimd/pim_cmd.c | 65 ++++++++++++++++ pimd/pim_msdp.c | 9 +++ pimd/pim_msdp.h | 5 ++ pimd/pim_msdp_packet.c | 164 +++++++++++++++++++++++++++++++++++------ pimd/pim_msdp_packet.h | 2 + pimd/pim_nb.c | 14 ++++ pimd/pim_nb.h | 4 + pimd/pim_nb_config.c | 88 ++++++++++++++++++++++ 8 files changed, 327 insertions(+), 24 deletions(-) diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index 92214eced4..1e3e090868 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -6486,6 +6486,69 @@ DEFPY_ATTR(no_ip_pim_msdp_peer, return ret; } +DEFPY(msdp_peer_sa_filter, msdp_peer_sa_filter_cmd, + "msdp peer A.B.C.D$peer sa-filter ACL_NAME$acl_name $dir", + CFG_MSDP_STR + "Configure MSDP peer\n" + "MSDP Peer address\n" + "SA access-list filter\n" + "SA access-list name\n" + "Filter incoming SAs\n" + "Filter outgoing SAs\n") +{ + const struct lyd_node *peer_node; + char xpath[XPATH_MAXLEN + 24]; + + snprintf(xpath, sizeof(xpath), "%s/msdp-peer[peer-ip='%s']", + VTY_CURR_XPATH, peer_str); + peer_node = yang_dnode_get(vty->candidate_config->dnode, xpath); + if (peer_node == NULL) { + vty_out(vty, "%% MSDP peer %s not yet configured\n", peer_str); + return CMD_SUCCESS; + } + + if (strcmp(dir, "in") == 0) + nb_cli_enqueue_change(vty, "./sa-filter-in", NB_OP_MODIFY, + acl_name); + else + nb_cli_enqueue_change(vty, "./sa-filter-out", NB_OP_MODIFY, + acl_name); + + return nb_cli_apply_changes(vty, "%s", xpath); +} + +DEFPY(no_msdp_peer_sa_filter, no_ip_msdp_peer_sa_filter_cmd, + "no msdp peer A.B.C.D$peer sa-filter ACL_NAME $dir", + NO_STR + CFG_MSDP_STR + "Configure MSDP peer\n" + "MSDP Peer address\n" + "SA access-list filter\n" + "SA access-list name\n" + "Filter incoming SAs\n" + "Filter outgoing SAs\n") +{ + const struct lyd_node *peer_node; + char xpath[XPATH_MAXLEN + 24]; + + snprintf(xpath, sizeof(xpath), "%s/msdp-peer[peer-ip='%s']", + VTY_CURR_XPATH, peer_str); + peer_node = yang_dnode_get(vty->candidate_config->dnode, xpath); + if (peer_node == NULL) { + vty_out(vty, "%% MSDP peer %s not yet configured\n", peer_str); + return CMD_SUCCESS; + } + + if (strcmp(dir, "in") == 0) + nb_cli_enqueue_change(vty, "./sa-filter-in", NB_OP_DESTROY, + NULL); + else + nb_cli_enqueue_change(vty, "./sa-filter-out", NB_OP_DESTROY, + NULL); + + return nb_cli_apply_changes(vty, "%s", xpath); +} + DEFPY(pim_msdp_mesh_group_member, pim_msdp_mesh_group_member_cmd, "msdp mesh-group WORD$gname member A.B.C.D$maddr", @@ -8259,6 +8322,8 @@ void pim_cmd_init(void) install_element(PIM_NODE, &no_pim_msdp_peer_cmd); install_element(PIM_NODE, &pim_msdp_timers_cmd); install_element(PIM_NODE, &no_pim_msdp_timers_cmd); + install_element(PIM_NODE, &msdp_peer_sa_filter_cmd); + install_element(PIM_NODE, &no_ip_msdp_peer_sa_filter_cmd); install_element(PIM_NODE, &pim_msdp_mesh_group_member_cmd); install_element(PIM_NODE, &no_pim_msdp_mesh_group_member_cmd); install_element(PIM_NODE, &pim_msdp_mesh_group_source_cmd); diff --git a/pimd/pim_msdp.c b/pimd/pim_msdp.c index 3393cebdd2..0bb2d93a3a 100644 --- a/pimd/pim_msdp.c +++ b/pimd/pim_msdp.c @@ -1317,6 +1317,15 @@ bool pim_msdp_peer_config_write(struct vty *vty, struct pim_instance *pim) vty_out(vty, " msdp peer %pI4 source %pI4\n", &mp->peer, &mp->local); + + if (mp->acl_in) + vty_out(vty, " msdp peer %pI4 sa-filter %s in\n", + &mp->peer, mp->acl_in); + + if (mp->acl_out) + vty_out(vty, " msdp peer %pI4 sa-filter %s out\n", + &mp->peer, mp->acl_out); + written = true; } diff --git a/pimd/pim_msdp.h b/pimd/pim_msdp.h index 80ca003dc5..a45726cb85 100644 --- a/pimd/pim_msdp.h +++ b/pimd/pim_msdp.h @@ -138,6 +138,11 @@ struct pim_msdp_peer { /* timestamps */ int64_t uptime; + + /** SA input access list name. */ + char *acl_in; + /** SA output access list name. */ + char *acl_out; }; struct pim_msdp_mg_mbr { diff --git a/pimd/pim_msdp_packet.c b/pimd/pim_msdp_packet.c index 4324a96bef..27f4966a1c 100644 --- a/pimd/pim_msdp_packet.c +++ b/pimd/pim_msdp_packet.c @@ -6,7 +6,9 @@ #include #include +#include #include +#include #include #include "frrevent.h" #include @@ -322,8 +324,8 @@ void pim_msdp_pkt_ka_tx(struct pim_msdp_peer *mp) pim_msdp_pkt_send(mp, s); } -static void pim_msdp_pkt_sa_push_to_one_peer(struct pim_instance *pim, - struct pim_msdp_peer *mp) +static void pim_msdp_pkt_sa_push(struct pim_instance *pim, + struct pim_msdp_peer *mp) { struct stream *s; @@ -338,25 +340,6 @@ static void pim_msdp_pkt_sa_push_to_one_peer(struct pim_instance *pim, } } -/* push the stream into the obuf fifo of all the peers */ -static void pim_msdp_pkt_sa_push(struct pim_instance *pim, - struct pim_msdp_peer *mp) -{ - struct listnode *mpnode; - - if (mp) { - pim_msdp_pkt_sa_push_to_one_peer(pim, mp); - } else { - for (ALL_LIST_ELEMENTS_RO(pim->msdp.peer_list, mpnode, mp)) { - if (PIM_DEBUG_MSDP_INTERNAL) { - zlog_debug("MSDP peer %s pim_msdp_pkt_sa_push", - mp->key_str); - } - pim_msdp_pkt_sa_push_to_one_peer(pim, mp); - } - } -} - static int pim_msdp_pkt_sa_fill_hdr(struct pim_instance *pim, int local_cnt, struct in_addr rp) { @@ -384,6 +367,90 @@ static void pim_msdp_pkt_sa_fill_one(struct pim_msdp_sa *sa) stream_put_ipv4(sa->pim->msdp.work_obuf, sa->sg.src.s_addr); } +static bool msdp_cisco_match(const struct filter *filter, + const struct in_addr *source, + const struct in_addr *group) +{ + const struct filter_cisco *cfilter = &filter->u.cfilter; + uint32_t source_addr; + uint32_t group_addr; + + group_addr = group->s_addr & ~cfilter->mask_mask.s_addr; + + if (cfilter->extended) { + source_addr = source->s_addr & ~cfilter->addr_mask.s_addr; + if (group_addr == cfilter->mask.s_addr && + source_addr == cfilter->addr.s_addr) + return true; + } else if (group_addr == cfilter->addr.s_addr) + return true; + + return false; +} + +static enum filter_type msdp_access_list_apply(struct access_list *access, + const struct in_addr *source, + const struct in_addr *group) +{ + struct filter *filter; + struct prefix group_prefix; + + if (access == NULL) + return FILTER_DENY; + + for (filter = access->head; filter; filter = filter->next) { + if (filter->cisco) { + if (msdp_cisco_match(filter, source, group)) + return filter->type; + } else { + group_prefix.family = AF_INET; + group_prefix.prefixlen = IPV4_MAX_BITLEN; + group_prefix.u.prefix4.s_addr = group->s_addr; + if (access_list_apply(access, &group_prefix)) + return filter->type; + } + } + + return FILTER_DENY; +} + +bool msdp_peer_sa_filter(const struct pim_msdp_peer *mp, + const struct pim_msdp_sa *sa) +{ + struct access_list *acl; + + /* No output filter configured, just quit. */ + if (mp->acl_out == NULL) + return false; + + /* Find access list and test it. */ + acl = access_list_lookup(AFI_IP, mp->acl_out); + if (msdp_access_list_apply(acl, &sa->sg.src, &sa->sg.grp) == FILTER_DENY) + return true; + + return false; +} + +/** Count the number of SAs to be sent for a specific peer. */ +static size_t pim_msdp_peer_sa_count(const struct pim_instance *pim, + const struct pim_msdp_peer *peer) +{ + const struct pim_msdp_sa *sa; + const struct listnode *node; + size_t sa_count = 0; + + for (ALL_LIST_ELEMENTS_RO(pim->msdp.sa_list, node, sa)) { + if (!CHECK_FLAG(sa->flags, PIM_MSDP_SAF_LOCAL)) + continue; + if (msdp_peer_sa_filter(peer, sa)) + continue; + + sa_count++; + } + + return sa_count; +} + static void pim_msdp_pkt_sa_gen(struct pim_instance *pim, struct pim_msdp_peer *mp) { @@ -393,7 +460,7 @@ static void pim_msdp_pkt_sa_gen(struct pim_instance *pim, struct prefix group_all; struct in_addr rp; int sa_count; - int local_cnt = pim->msdp.local_cnt; + int local_cnt = pim_msdp_peer_sa_count(pim, mp); sa_count = 0; if (PIM_DEBUG_MSDP_INTERNAL) { @@ -418,6 +485,15 @@ static void pim_msdp_pkt_sa_gen(struct pim_instance *pim, * peers */ continue; } + + if (msdp_peer_sa_filter(mp, sa)) { + if (PIM_DEBUG_MSDP_EVENTS) + zlog_debug("MSDP peer %pI4 filter SA out %s", + &mp->peer, sa->sg_str); + + continue; + } + /* add sa into scratch pad */ pim_msdp_pkt_sa_fill_one(sa); ++sa_count; @@ -457,15 +533,32 @@ static void pim_msdp_pkt_sa_tx_done(struct pim_instance *pim) void pim_msdp_pkt_sa_tx(struct pim_instance *pim) { - pim_msdp_pkt_sa_gen(pim, NULL /* mp */); + struct pim_msdp_peer *mp; + struct listnode *node; + + for (ALL_LIST_ELEMENTS_RO(pim->msdp.peer_list, node, mp)) + pim_msdp_pkt_sa_gen(pim, mp); + pim_msdp_pkt_sa_tx_done(pim); } void pim_msdp_pkt_sa_tx_one(struct pim_msdp_sa *sa) { + struct pim_msdp_peer *mp; + struct listnode *node; + pim_msdp_pkt_sa_fill_hdr(sa->pim, 1 /* cnt */, sa->rp); pim_msdp_pkt_sa_fill_one(sa); - pim_msdp_pkt_sa_push(sa->pim, NULL); + for (ALL_LIST_ELEMENTS_RO(sa->pim->msdp.peer_list, node, mp)) { + if (msdp_peer_sa_filter(mp, sa)) { + if (PIM_DEBUG_MSDP_EVENTS) + zlog_debug("MSDP peer %pI4 filter SA out %s", + &mp->peer, sa->sg_str); + continue; + } + + pim_msdp_pkt_sa_push(sa->pim, mp); + } pim_msdp_pkt_sa_tx_done(sa->pim); } @@ -487,6 +580,15 @@ void pim_msdp_pkt_sa_tx_one_to_one_peer(struct pim_msdp_peer *mp, /* Fills the message contents. */ sa.pim = mp->pim; sa.sg = sg; + + /* Don't push it if filtered. */ + if (msdp_peer_sa_filter(mp, &sa)) { + if (PIM_DEBUG_MSDP_EVENTS) + zlog_debug("MSDP peer %pI4 filter SA out (%pI4, %pI4)", + &mp->peer, &sa.sg.src, &sa.sg.grp); + return; + } + pim_msdp_pkt_sa_fill_one(&sa); /* Pushes the message. */ @@ -511,6 +613,7 @@ static void pim_msdp_pkt_ka_rx(struct pim_msdp_peer *mp, int len) static void pim_msdp_pkt_sa_rx_one(struct pim_msdp_peer *mp, struct in_addr rp) { + struct access_list *acl; int prefix_len; pim_sgaddr sg; struct listnode *peer_node; @@ -534,6 +637,19 @@ static void pim_msdp_pkt_sa_rx_one(struct pim_msdp_peer *mp, struct in_addr rp) if (PIM_DEBUG_MSDP_PACKETS) { zlog_debug(" sg %pSG", &sg); } + + /* Filter incoming SA with configured access list. */ + if (mp->acl_in) { + acl = access_list_lookup(AFI_IP, mp->acl_in); + if (msdp_access_list_apply(acl, &sg.src, &sg.grp) == + FILTER_DENY) { + if (PIM_DEBUG_MSDP_EVENTS) + zlog_debug("MSDP peer %pI4 filter SA in (%pI4, %pI4)", + &mp->peer, &sg.src, &sg.grp); + return; + } + } + pim_msdp_sa_ref(mp->pim, mp, &sg, rp); /* Forwards the SA to the peers that are not in the RPF to the RP nor in diff --git a/pimd/pim_msdp_packet.h b/pimd/pim_msdp_packet.h index 1584a24539..3af8d93685 100644 --- a/pimd/pim_msdp_packet.h +++ b/pimd/pim_msdp_packet.h @@ -57,5 +57,7 @@ void pim_msdp_pkt_sa_tx_one(struct pim_msdp_sa *sa); void pim_msdp_pkt_sa_tx_to_one_peer(struct pim_msdp_peer *mp); void pim_msdp_pkt_sa_tx_one_to_one_peer(struct pim_msdp_peer *mp, struct in_addr rp, pim_sgaddr sg); +bool msdp_peer_sa_filter(const struct pim_msdp_peer *mp, + const struct pim_msdp_sa *sa); #endif diff --git a/pimd/pim_nb.c b/pimd/pim_nb.c index 339935f81a..6f4e325220 100644 --- a/pimd/pim_nb.c +++ b/pimd/pim_nb.c @@ -163,6 +163,20 @@ const struct frr_yang_module_info frr_pim_info = { .modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_peer_source_ip_modify, } }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-peer/sa-filter-in", + .cbs = { + .modify = pim_msdp_peer_sa_filter_in_modify, + .destroy = pim_msdp_peer_sa_filter_in_destroy, + } + }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-peer/sa-filter-out", + .cbs = { + .modify = pim_msdp_peer_sa_filter_out_modify, + .destroy = pim_msdp_peer_sa_filter_out_destroy, + } + }, { .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/mlag", .cbs = { diff --git a/pimd/pim_nb.h b/pimd/pim_nb.h index 2d854d73de..56153bafba 100644 --- a/pimd/pim_nb.h +++ b/pimd/pim_nb.h @@ -65,6 +65,10 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_ms struct nb_cb_destroy_args *args); int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_peer_source_ip_modify( struct nb_cb_modify_args *args); +int pim_msdp_peer_sa_filter_in_modify(struct nb_cb_modify_args *args); +int pim_msdp_peer_sa_filter_in_destroy(struct nb_cb_destroy_args *args); +int pim_msdp_peer_sa_filter_out_modify(struct nb_cb_modify_args *args); +int pim_msdp_peer_sa_filter_out_destroy(struct nb_cb_destroy_args *args); int routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_create( struct nb_cb_create_args *args); int routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_destroy( diff --git a/pimd/pim_nb_config.c b/pimd/pim_nb_config.c index be0be8588b..49bd9a5ce7 100644 --- a/pimd/pim_nb_config.c +++ b/pimd/pim_nb_config.c @@ -1286,6 +1286,94 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_ms } #endif /* PIM_IPV != 6 */ +/* + * XPath: + * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-peer/sa-filter-in + */ +int pim_msdp_peer_sa_filter_in_modify(struct nb_cb_modify_args *args) +{ + struct pim_msdp_peer *mp; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + mp = nb_running_get_entry(args->dnode, NULL, true); + XFREE(MTYPE_TMP, mp->acl_in); + mp->acl_in = XSTRDUP(MTYPE_TMP, + yang_dnode_get_string(args->dnode, NULL)); + break; + } + + return NB_OK; +} + +int pim_msdp_peer_sa_filter_in_destroy(struct nb_cb_destroy_args *args) +{ + struct pim_msdp_peer *mp; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + mp = nb_running_get_entry(args->dnode, NULL, true); + XFREE(MTYPE_TMP, mp->acl_in); + break; + } + + return NB_OK; +} + +/* + * XPath: + * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-peer/sa-filter-out + */ +int pim_msdp_peer_sa_filter_out_modify(struct nb_cb_modify_args *args) +{ + struct pim_msdp_peer *mp; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + mp = nb_running_get_entry(args->dnode, NULL, true); + XFREE(MTYPE_TMP, mp->acl_out); + mp->acl_out = XSTRDUP(MTYPE_TMP, + yang_dnode_get_string(args->dnode, NULL)); + break; + } + + return NB_OK; +} + +int pim_msdp_peer_sa_filter_out_destroy(struct nb_cb_destroy_args *args) +{ + struct pim_msdp_peer *mp; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + mp = nb_running_get_entry(args->dnode, NULL, true); + XFREE(MTYPE_TMP, mp->acl_out); + break; + } + + return NB_OK; +} + /* * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/mlag */ From ae31d9b17baf69c675eb62db12083758b830d52e Mon Sep 17 00:00:00 2001 From: Rafael Zalamena Date: Mon, 3 May 2021 10:34:49 -0300 Subject: [PATCH 249/347] doc: document new MSDP filter command Let user know how to use the MSDP SA filtering command Signed-off-by: Rafael Zalamena --- doc/user/pim.rst | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/doc/user/pim.rst b/doc/user/pim.rst index 90d37b2d7e..20a4f1f7ab 100644 --- a/doc/user/pim.rst +++ b/doc/user/pim.rst @@ -342,7 +342,7 @@ MSDP can be setup in different ways: .. note:: - MSDP default peer and SA filtering is not implemented. + MSDP default peer is not implemented. MSDP configuration is available under 'router pim' @@ -377,6 +377,15 @@ Commands available for MSDP: Create a regular MSDP session with peer using the specified source address. +.. clicmd:: msdp peer A.B.C.D sa-filter ACL_NAME + + Configure incoming or outgoing SA filtering rule. + + .. note:: + + The filtering will only take effect starting from the command + application. + .. _show-pim-information: From 7b650fb8369d180198f6b78e0dd36c9b28c933ed Mon Sep 17 00:00:00 2001 From: Rafael Zalamena Date: Fri, 9 Dec 2022 14:34:13 -0300 Subject: [PATCH 250/347] topotests: test MSDP SA filtering Modify existing MSDP topology to use test SA filtering: - Add new multicast host (so we get two sources for same group) - Test group only filtering - Test source / group filtering Signed-off-by: Rafael Zalamena --- tests/topotests/msdp_topo1/r4/pimd.conf | 13 +++ tests/topotests/msdp_topo1/test_msdp_topo1.py | 84 ++++++++++++++++++- 2 files changed, 96 insertions(+), 1 deletion(-) diff --git a/tests/topotests/msdp_topo1/r4/pimd.conf b/tests/topotests/msdp_topo1/r4/pimd.conf index 28085913fb..46de4fbe38 100644 --- a/tests/topotests/msdp_topo1/r4/pimd.conf +++ b/tests/topotests/msdp_topo1/r4/pimd.conf @@ -20,3 +20,16 @@ ip msdp peer 192.168.2.1 source 192.168.2.2 ip msdp peer 192.168.3.1 source 192.168.3.2 ip pim rp 10.254.254.4 ip pim join-prune-interval 5 +! +access-list forbidden-multicast seq 5 deny 229.2.1.0 0.0.0.255 +access-list forbidden-multicast seq 1000 permit any +access-list local-only-multicast seq 5 deny 229.3.1.0 0.0.0.255 +access-list local-only-multicast seq 6 deny ip 192.168.4.100 0.0.0.0 229.10.1.0 0.0.0.255 +access-list local-only-multicast seq 1000 permit any +! +router pim + msdp peer 192.168.2.1 sa-filter forbidden-multicast in + msdp peer 192.168.2.1 sa-filter local-only-multicast out + msdp peer 192.168.3.1 sa-filter forbidden-multicast in + msdp peer 192.168.3.1 sa-filter local-only-multicast out +! diff --git a/tests/topotests/msdp_topo1/test_msdp_topo1.py b/tests/topotests/msdp_topo1/test_msdp_topo1.py index 4b54ef29ff..ff80052d26 100755 --- a/tests/topotests/msdp_topo1/test_msdp_topo1.py +++ b/tests/topotests/msdp_topo1/test_msdp_topo1.py @@ -66,7 +66,9 @@ def build_topo(tgen): # Create a host connected and direct at r4: tgen.add_host("h1", "192.168.4.100/24", "via 192.168.4.1") + tgen.add_host("h3", "192.168.4.120/24", "via 192.168.4.1") switch.add_link(tgen.gears["h1"]) + switch.add_link(tgen.gears["h3"]) # Create a host connected and direct at r1: switch = tgen.add_switch("s6") @@ -82,7 +84,6 @@ def setup_module(mod): router_list = tgen.routers() for rname, router in router_list.items(): - daemon_file = "{}/{}/zebra.conf".format(CWD, rname) if os.path.isfile(daemon_file): router.load_config(TopoRouter.RD_ZEBRA, daemon_file) @@ -428,6 +429,87 @@ def test_msdp(): assert val is None, "multicast route convergence failure" +def test_msdp_sa_filter(): + "Start a number of multicast streams and check if filtering works" + + tgen = get_topogen() + + # Flow from r1 -> r4 + for multicast_address in ["229.2.1.1", "229.2.1.2", "229.2.2.1"]: + app_helper.run("h1", [multicast_address, "h1-eth0"]) + app_helper.run("h2", ["--send=0.7", multicast_address, "h2-eth0"]) + + # Flow from r4 -> r1 + for multicast_address in ["229.3.1.1", "229.3.1.2", "229.3.2.1"]: + app_helper.run("h1", ["--send=0.7", multicast_address, "h1-eth0"]) + app_helper.run("h2", [multicast_address, "h2-eth0"]) + + # Flow from r4 -> r1 but with more sources + for multicast_address in ["229.10.1.1", "229.11.1.1"]: + app_helper.run("h1", ["--send=0.7", multicast_address, "h1-eth0"]) + app_helper.run("h2", [multicast_address, "h2-eth0"]) + app_helper.run("h3", ["--send=0.7", multicast_address, "h3-eth0"]) + + # Test that we don't learn any filtered multicast streams. + r4_sa_expected = { + "229.2.1.1": None, + "229.2.1.2": None, + "229.2.2.1": { + "192.168.10.100": { + "local": "no", + "sptSetup": "yes", + } + }, + } + test_func = partial( + topotest.router_json_cmp, + tgen.gears["r4"], + "show ip msdp sa json", + r4_sa_expected, + ) + logger.info("Waiting for r4 MDSP SA data") + _, val = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert val is None, "multicast route convergence failure" + + # Test that we don't send any filtered multicast streams. + r1_sa_expected = { + "229.3.1.1": None, + "229.3.1.2": None, + "229.3.2.1": { + "192.168.4.100": { + "local": "no", + "sptSetup": "yes", + } + }, + "229.10.1.1": { + "192.168.4.100": None, + "192.168.4.120": { + "local": "no", + "sptSetup": "yes", + }, + }, + "229.11.1.1": { + "192.168.4.100": { + "local": "no", + "sptSetup": "yes", + }, + "192.168.4.120": { + "local": "no", + "sptSetup": "yes", + }, + }, + } + test_func = partial( + topotest.router_json_cmp, + tgen.gears["r1"], + "show ip msdp sa json", + r1_sa_expected, + ) + logger.info("Waiting for r1 MDSP SA data") + _, val = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert val is None, "multicast route convergence failure" + + def test_memory_leak(): "Run the memory leak test and report results." tgen = get_topogen() From e64d15b17a4577aefda10a87312baed6876f3586 Mon Sep 17 00:00:00 2001 From: Adriano Marto Reis Date: Sun, 28 Jul 2024 14:34:24 +1000 Subject: [PATCH 251/347] tests: Test MSDP RPF Adding a MSDP test with multiple possible routes. Signed-off-by: "Adriano Marto Reis" --- tests/topotests/msdp_topo2/r1/bgpd.conf | 8 + tests/topotests/msdp_topo2/r1/pimd.conf | 20 + tests/topotests/msdp_topo2/r1/zebra.conf | 14 + tests/topotests/msdp_topo2/r2/bgpd.conf | 8 + tests/topotests/msdp_topo2/r2/pimd.conf | 16 + tests/topotests/msdp_topo2/r2/zebra.conf | 11 + tests/topotests/msdp_topo2/r3/bgpd.conf | 8 + tests/topotests/msdp_topo2/r3/pimd.conf | 16 + tests/topotests/msdp_topo2/r3/zebra.conf | 11 + tests/topotests/msdp_topo2/r4/bgpd.conf | 8 + tests/topotests/msdp_topo2/r4/pimd.conf | 16 + tests/topotests/msdp_topo2/r4/zebra.conf | 11 + tests/topotests/msdp_topo2/r5/bgpd.conf | 8 + tests/topotests/msdp_topo2/r5/pimd.conf | 20 + tests/topotests/msdp_topo2/r5/zebra.conf | 14 + tests/topotests/msdp_topo2/test_msdp_topo2.py | 376 ++++++++++++++++++ 16 files changed, 565 insertions(+) create mode 100644 tests/topotests/msdp_topo2/r1/bgpd.conf create mode 100644 tests/topotests/msdp_topo2/r1/pimd.conf create mode 100644 tests/topotests/msdp_topo2/r1/zebra.conf create mode 100644 tests/topotests/msdp_topo2/r2/bgpd.conf create mode 100644 tests/topotests/msdp_topo2/r2/pimd.conf create mode 100644 tests/topotests/msdp_topo2/r2/zebra.conf create mode 100644 tests/topotests/msdp_topo2/r3/bgpd.conf create mode 100644 tests/topotests/msdp_topo2/r3/pimd.conf create mode 100644 tests/topotests/msdp_topo2/r3/zebra.conf create mode 100644 tests/topotests/msdp_topo2/r4/bgpd.conf create mode 100644 tests/topotests/msdp_topo2/r4/pimd.conf create mode 100644 tests/topotests/msdp_topo2/r4/zebra.conf create mode 100644 tests/topotests/msdp_topo2/r5/bgpd.conf create mode 100644 tests/topotests/msdp_topo2/r5/pimd.conf create mode 100644 tests/topotests/msdp_topo2/r5/zebra.conf create mode 100755 tests/topotests/msdp_topo2/test_msdp_topo2.py diff --git a/tests/topotests/msdp_topo2/r1/bgpd.conf b/tests/topotests/msdp_topo2/r1/bgpd.conf new file mode 100644 index 0000000000..67f04d8eab --- /dev/null +++ b/tests/topotests/msdp_topo2/r1/bgpd.conf @@ -0,0 +1,8 @@ +router bgp 65001 + no bgp ebgp-requires-policy + neighbor 192.168.1.2 remote-as 65002 + neighbor 192.168.3.3 remote-as 65003 + address-family ipv4 unicast + redistribute connected + exit-address-family +! diff --git a/tests/topotests/msdp_topo2/r1/pimd.conf b/tests/topotests/msdp_topo2/r1/pimd.conf new file mode 100644 index 0000000000..58a4c21e40 --- /dev/null +++ b/tests/topotests/msdp_topo2/r1/pimd.conf @@ -0,0 +1,20 @@ +! debug pim +! debug pim zebra +! +interface lo + ip pim + ip pim use-source 10.254.254.1 +! +interface r1-eth0 + ip pim +! +interface r1-eth1 + ip pim +! +interface r1-eth2 + ip pim + ip igmp +! +ip msdp peer 192.168.1.2 source 192.168.1.1 +ip msdp peer 192.168.3.3 source 192.168.3.1 +ip pim rp 10.254.254.1 diff --git a/tests/topotests/msdp_topo2/r1/zebra.conf b/tests/topotests/msdp_topo2/r1/zebra.conf new file mode 100644 index 0000000000..3219fad36d --- /dev/null +++ b/tests/topotests/msdp_topo2/r1/zebra.conf @@ -0,0 +1,14 @@ +ip forwarding +! +interface r1-eth0 + ip address 192.168.1.1/24 +! +interface r1-eth1 + ip address 192.168.3.1/24 +! +interface r1-eth2 + ip address 192.168.6.1/24 +! +interface lo + ip address 10.254.254.1/32 +! diff --git a/tests/topotests/msdp_topo2/r2/bgpd.conf b/tests/topotests/msdp_topo2/r2/bgpd.conf new file mode 100644 index 0000000000..b9f316898c --- /dev/null +++ b/tests/topotests/msdp_topo2/r2/bgpd.conf @@ -0,0 +1,8 @@ +router bgp 65002 + no bgp ebgp-requires-policy + neighbor 192.168.1.1 remote-as 65001 + neighbor 192.168.2.5 remote-as 65005 + address-family ipv4 unicast + redistribute connected + exit-address-family +! diff --git a/tests/topotests/msdp_topo2/r2/pimd.conf b/tests/topotests/msdp_topo2/r2/pimd.conf new file mode 100644 index 0000000000..66e630264c --- /dev/null +++ b/tests/topotests/msdp_topo2/r2/pimd.conf @@ -0,0 +1,16 @@ +! debug pim +! debug pim zebra +! +interface lo + ip pim + ip pim use-source 10.254.254.2 +! +interface r2-eth0 + ip pim +! +interface r2-eth1 + ip pim +! +ip msdp peer 192.168.1.1 source 192.168.1.2 +ip msdp peer 192.168.2.5 source 192.168.2.2 +ip pim rp 10.254.254.2 diff --git a/tests/topotests/msdp_topo2/r2/zebra.conf b/tests/topotests/msdp_topo2/r2/zebra.conf new file mode 100644 index 0000000000..740b51a4f0 --- /dev/null +++ b/tests/topotests/msdp_topo2/r2/zebra.conf @@ -0,0 +1,11 @@ +ip forwarding +! +interface r2-eth0 + ip address 192.168.1.2/24 +! +interface r2-eth1 + ip address 192.168.2.2/24 +! +interface lo + ip address 10.254.254.2/32 +! diff --git a/tests/topotests/msdp_topo2/r3/bgpd.conf b/tests/topotests/msdp_topo2/r3/bgpd.conf new file mode 100644 index 0000000000..ecd25b050e --- /dev/null +++ b/tests/topotests/msdp_topo2/r3/bgpd.conf @@ -0,0 +1,8 @@ +router bgp 65003 + no bgp ebgp-requires-policy + neighbor 192.168.3.1 remote-as 65001 + neighbor 192.168.4.4 remote-as 65004 + address-family ipv4 unicast + redistribute connected + exit-address-family +! diff --git a/tests/topotests/msdp_topo2/r3/pimd.conf b/tests/topotests/msdp_topo2/r3/pimd.conf new file mode 100644 index 0000000000..e8e53268e3 --- /dev/null +++ b/tests/topotests/msdp_topo2/r3/pimd.conf @@ -0,0 +1,16 @@ +! debug pim +! debug pim zebra +! +interface lo + ip pim + ip pim use-source 10.254.254.3 +! +interface r3-eth0 + ip pim +! +interface r3-eth1 + ip pim +! +ip msdp peer 192.168.3.1 source 192.168.3.3 +ip msdp peer 192.168.4.4 source 192.168.4.3 +ip pim rp 10.254.254.3 diff --git a/tests/topotests/msdp_topo2/r3/zebra.conf b/tests/topotests/msdp_topo2/r3/zebra.conf new file mode 100644 index 0000000000..d1be65f636 --- /dev/null +++ b/tests/topotests/msdp_topo2/r3/zebra.conf @@ -0,0 +1,11 @@ +ip forwarding +! +interface r3-eth0 + ip address 192.168.3.3/24 +! +interface r3-eth1 + ip address 192.168.4.3/24 +! +interface lo + ip address 10.254.254.3/32 +! diff --git a/tests/topotests/msdp_topo2/r4/bgpd.conf b/tests/topotests/msdp_topo2/r4/bgpd.conf new file mode 100644 index 0000000000..430517bc2b --- /dev/null +++ b/tests/topotests/msdp_topo2/r4/bgpd.conf @@ -0,0 +1,8 @@ +router bgp 65004 + no bgp ebgp-requires-policy + neighbor 192.168.4.3 remote-as 65003 + neighbor 192.168.5.5 remote-as 65005 + address-family ipv4 unicast + redistribute connected + exit-address-family +! diff --git a/tests/topotests/msdp_topo2/r4/pimd.conf b/tests/topotests/msdp_topo2/r4/pimd.conf new file mode 100644 index 0000000000..32e3c613fa --- /dev/null +++ b/tests/topotests/msdp_topo2/r4/pimd.conf @@ -0,0 +1,16 @@ +! debug pim +! debug pim zebra +! +interface lo + ip pim + ip pim use-source 10.254.254.4 +! +interface r4-eth0 + ip pim +! +interface r4-eth1 + ip pim +! +ip msdp peer 192.168.4.3 source 192.168.4.4 +ip msdp peer 192.168.5.5 source 192.168.5.4 +ip pim rp 10.254.254.4 diff --git a/tests/topotests/msdp_topo2/r4/zebra.conf b/tests/topotests/msdp_topo2/r4/zebra.conf new file mode 100644 index 0000000000..045d2e8070 --- /dev/null +++ b/tests/topotests/msdp_topo2/r4/zebra.conf @@ -0,0 +1,11 @@ +ip forwarding +! +interface r4-eth0 + ip address 192.168.4.4/24 +! +interface r4-eth1 + ip address 192.168.5.4/24 +! +interface lo + ip address 10.254.254.4/32 +! diff --git a/tests/topotests/msdp_topo2/r5/bgpd.conf b/tests/topotests/msdp_topo2/r5/bgpd.conf new file mode 100644 index 0000000000..053dd3d3ef --- /dev/null +++ b/tests/topotests/msdp_topo2/r5/bgpd.conf @@ -0,0 +1,8 @@ +router bgp 65005 + no bgp ebgp-requires-policy + neighbor 192.168.2.2 remote-as 65002 + neighbor 192.168.5.4 remote-as 65004 + address-family ipv4 unicast + redistribute connected + exit-address-family +! diff --git a/tests/topotests/msdp_topo2/r5/pimd.conf b/tests/topotests/msdp_topo2/r5/pimd.conf new file mode 100644 index 0000000000..e6cdd14c82 --- /dev/null +++ b/tests/topotests/msdp_topo2/r5/pimd.conf @@ -0,0 +1,20 @@ +! debug pim +! debug pim zebra +! +interface lo + ip pim + ip pim use-source 10.254.254.5 +! +interface r5-eth0 + ip pim +! +interface r5-eth1 + ip pim +! +interface r5-eth2 + ip pim + ip igmp +! +ip msdp peer 192.168.2.2 source 192.168.2.5 +ip msdp peer 192.168.5.4 source 192.168.5.5 +ip pim rp 10.254.254.5 diff --git a/tests/topotests/msdp_topo2/r5/zebra.conf b/tests/topotests/msdp_topo2/r5/zebra.conf new file mode 100644 index 0000000000..195e003510 --- /dev/null +++ b/tests/topotests/msdp_topo2/r5/zebra.conf @@ -0,0 +1,14 @@ +ip forwarding +! +interface r5-eth0 + ip address 192.168.2.5/24 +! +interface r5-eth1 + ip address 192.168.5.5/24 +! +interface r5-eth2 + ip address 192.168.7.5/24 +! +interface lo + ip address 10.254.254.5/32 +! diff --git a/tests/topotests/msdp_topo2/test_msdp_topo2.py b/tests/topotests/msdp_topo2/test_msdp_topo2.py new file mode 100755 index 0000000000..def5368f41 --- /dev/null +++ b/tests/topotests/msdp_topo2/test_msdp_topo2.py @@ -0,0 +1,376 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# +# test_msdp_topo1.py +# Part of NetDEF Topology Tests +# +# Copyright (c) 2024 by +# Adriano Marto Reis +# + +""" +test_msdp_topo2.py: Test the FRR PIM MSDP peer. + + ────────────────────► + shortest path + ┌──┐ + ┌───────┤r2├───────┐ +sender │ s1 └──┘ s2 │ receiver + ┌──┐ ┌─┴┐ ┌─┴┐ ┌──┐ + │h1├────┤r1│ │r5├────┤h2│ + └──┘ s6 └─┬┘ └─┬┘ s7 └──┘ + │ ┌──┐ ┌──┐ │ + └───┤r3├────┤r4├───┘ + s3 └──┘ s4 └──┘ s5 +""" + +import os +import sys +import json +from functools import partial +import pytest + +# Save the Current Working Directory to find configuration files. +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +# Import topogen and topotest helpers +from lib import topotest + +# Required to instantiate the topology builder class. +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topolog import logger + +from lib.pim import McastTesterHelper + +pytestmark = [pytest.mark.bgpd, pytest.mark.pimd] + +app_helper = McastTesterHelper() + +MCAST_ADDR = "229.1.2.3" + +def build_topo(tgen): + "Build function" + + for routern in range(1, 6): + tgen.add_router("r{}".format(routern)) + + switch = tgen.add_switch("s1") + switch.add_link(tgen.gears["r1"]) + switch.add_link(tgen.gears["r2"]) + + switch = tgen.add_switch("s2") + switch.add_link(tgen.gears["r2"]) + switch.add_link(tgen.gears["r5"]) + + switch = tgen.add_switch("s3") + switch.add_link(tgen.gears["r1"]) + switch.add_link(tgen.gears["r3"]) + + switch = tgen.add_switch("s4") + switch.add_link(tgen.gears["r3"]) + switch.add_link(tgen.gears["r4"]) + + switch = tgen.add_switch("s5") + switch.add_link(tgen.gears["r4"]) + switch.add_link(tgen.gears["r5"]) + + switch = tgen.add_switch("s6") + tgen.add_host("h1", "192.168.6.100/24", "via 192.168.6.1") + switch.add_link(tgen.gears["h1"]) + switch.add_link(tgen.gears["r1"]) + + switch = tgen.add_switch("s7") + tgen.add_host("h2", "192.168.7.100/24", "via 192.168.7.5") + switch.add_link(tgen.gears["h2"]) + switch.add_link(tgen.gears["r5"]) + + +def setup_module(mod): + "Sets up the pytest environment" + + tgen = Topogen(build_topo, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + for rname, router in router_list.items(): + + daemon_file = "{}/{}/zebra.conf".format(CWD, rname) + if os.path.isfile(daemon_file): + router.load_config(TopoRouter.RD_ZEBRA, daemon_file) + + daemon_file = "{}/{}/bgpd.conf".format(CWD, rname) + if os.path.isfile(daemon_file): + router.load_config(TopoRouter.RD_BGP, daemon_file) + + daemon_file = "{}/{}/pimd.conf".format(CWD, rname) + if os.path.isfile(daemon_file): + router.load_config(TopoRouter.RD_PIM, daemon_file) + + tgen.start_router() + + app_helper.init(tgen) + + +def teardown_module(): + "Teardown the pytest environment" + tgen = get_topogen() + app_helper.cleanup() + tgen.stop_topology() + + +def test_bgp_convergence(): + """ + Wait for BGP protocol convergence + All the loopback addresses (10.254.254.x) must be reachable from all + routers. + """ + + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + routes = { + "r1": "10.254.254.1/32", + "r2": "10.254.254.2/32", + "r3": "10.254.254.3/32", + "r4": "10.254.254.4/32", + "r5": "10.254.254.5/32", + } + + for router1 in routes.keys(): + for router2, route in routes.items(): + if router1 != router2: + logger.info("waiting route {} in {}".format(route, router1)) + test_func = partial( + topotest.router_json_cmp, + tgen.gears[router1], + "show ip route json", + {route: [{"protocol": "bgp"}]}, + ) + _, result = topotest.run_and_expect(test_func, None, count=130, wait=1) + assertmsg = '"{}" convergence failure'.format(router1) + assert result is None, assertmsg + + +def test_msdp_peers(): + """ + Waits for the MSPD peer connections to be established. + """ + + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + expected_msdp_peers = { + "r1": { + "192.168.1.2": { + "peer": "192.168.1.2", + "local": "192.168.1.1", + "state": "established", + }, + "192.168.3.3": { + "peer": "192.168.3.3", + "local": "192.168.3.1", + "state": "established", + }, + }, + "r2": { + "192.168.1.1": { + "peer": "192.168.1.1", + "local": "192.168.1.2", + "state": "established", + }, + "192.168.2.5": { + "peer": "192.168.2.5", + "local": "192.168.2.2", + "state": "established", + }, + }, + "r3": { + "192.168.3.1": { + "peer": "192.168.3.1", + "local": "192.168.3.3", + "state": "established", + }, + "192.168.4.4": { + "peer": "192.168.4.4", + "local": "192.168.4.3", + "state": "established", + }, + }, + "r4": { + "192.168.4.3": { + "peer": "192.168.4.3", + "local": "192.168.4.4", + "state": "established", + }, + "192.168.5.5": { + "peer": "192.168.5.5", + "local": "192.168.5.4", + "state": "established", + }, + }, + "r5": { + "192.168.2.2": { + "peer": "192.168.2.2", + "local": "192.168.2.5", + "state": "established", + }, + "192.168.5.4": { + "peer": "192.168.5.4", + "local": "192.168.5.5", + "state": "established", + }, + }, + } + + for router, peers in expected_msdp_peers.items(): + logger.info("Waiting for {} msdp peer data".format(router)) + test_function = partial( + topotest.router_json_cmp, + tgen.gears[router], + "show ip msdp peer json", + peers, + ) + _, val = topotest.run_and_expect(test_function, None, count=30, wait=1) + assert val is None, "multicast route convergence failure" + + +def test_msdp_sa(): + """ + Waits for the MSDP SA to be propagated. + The MSDP SA must be present on all routers. The MSDP SA must indicate + the original RP. + """ + + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + app_helper.run("h1", ["--send=0.7", MCAST_ADDR, "h1-eth0"]) + app_helper.run("h2", [MCAST_ADDR, "h2-eth0"]) + + expected_sa_r1 = { + MCAST_ADDR: { + "192.168.6.100": { + "source": "192.168.6.100", + "group": MCAST_ADDR, + "rp": "-", + "local": "yes", + } + } + } + + expected_sa_r2_r3_r4_r5 = { + MCAST_ADDR: { + "192.168.6.100": { + "source": "192.168.6.100", + "group": MCAST_ADDR, + "rp": "10.254.254.1", + "local": "no", + } + } + } + + expected_sa = { + "r1": expected_sa_r1, + "r2": expected_sa_r2_r3_r4_r5, + "r3": expected_sa_r2_r3_r4_r5, + "r4": expected_sa_r2_r3_r4_r5, + "r5": expected_sa_r2_r3_r4_r5, + } + + for router, sa in expected_sa.items(): + logger.info("Waiting for {} msdp peer data".format(router)) + test_function = partial( + topotest.router_json_cmp, + tgen.gears[router], + "show ip msdp sa json", + sa, + ) + _, val = topotest.run_and_expect(test_function, None, count=30, wait=1) + assert val is None, "multicast route convergence failure" + + +def test_mroute(): + """ + Wait for the multicast routes. + The multicast routes must connect the shortest path between h1 and h2: + h1 ─► r1 ─► r2 ─► r5 ─► h2 + + The routers r3 and r4 must have no multicast routes, as they are not + included in the shortest path between h1 and h2. + """ + + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + app_helper.run("h1", ["--send=0.7", MCAST_ADDR, "h1-eth0"]) + app_helper.run("h2", [MCAST_ADDR, "h2-eth0"]) + + expected_mroutes = { + "r1": { + MCAST_ADDR: { + "192.168.6.100": { + "iif": "r1-eth2", + "oil": { + "r1-eth0": {"source": "192.168.6.100", "group": MCAST_ADDR}, + "r1-eth1": None, + }, + }, + }, + }, + "r2": { + MCAST_ADDR: { + "192.168.6.100": { + "iif": "r2-eth0", + "oil": { + "r2-eth1": {"source": "192.168.6.100", "group": MCAST_ADDR}, + }, + }, + }, + }, + "r3": { + }, + "r4": { + }, + "r5": { + MCAST_ADDR: { + "192.168.6.100": { + "iif": "r5-eth0", + "oil": { + "r5-eth1": None, + "r5-eth2": {"source": "192.168.6.100", "group": MCAST_ADDR}, + }, + }, + }, + }, + } + + for router, mroute in expected_mroutes.items(): + logger.info("Waiting for {} mroute data".format(router)) + test_function = partial( + topotest.router_json_cmp, + tgen.gears[router], + "show ip mroute json", + mroute, + ) + _, val = topotest.run_and_expect(test_function, None, count=30, wait=1) + assert val is None, "mroute convergence failure" + + +def test_memory_leak(): + "Run the memory leak test and report results." + tgen = get_topogen() + if not tgen.is_memleak_enabled(): + pytest.skip("Memory leak test/report is disabled") + tgen.report_memory_leaks() + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) From 04f9372409a11a59dafbbf8423f0cf832b99cf0e Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Sun, 28 Jul 2024 14:26:13 +0300 Subject: [PATCH 252/347] bgpd: Do not process VRF import/export to/from auto created VRF instances Fixes the crash: ``` (gdb) bt 0 __pthread_kill_implementation (no_tid=0, signo=11, threadid=124583315603008) at ./nptl/pthread_kill.c:44 1 __pthread_kill_internal (signo=11, threadid=124583315603008) at ./nptl/pthread_kill.c:78 2 __GI___pthread_kill (threadid=124583315603008, signo=signo@entry=11) at ./nptl/pthread_kill.c:89 3 0x0000714ed0242476 in __GI_raise (sig=11) at ../sysdeps/posix/raise.c:26 4 0x0000714ed074cfb7 in core_handler (signo=11, siginfo=0x7ffe6d9792b0, context=0x7ffe6d979180) at lib/sigevent.c:258 5 6 0x000060f55e33ffdd in route_table_get_info (table=0x0) at ./lib/table.h:177 7 0x000060f55e340053 in bgp_dest_table (dest=0x60f56dabb840) at ./bgpd/bgp_table.h:156 8 0x000060f55e340c9f in is_route_injectable_into_vpn (pi=0x60f56dbc4a60) at ./bgpd/bgp_mplsvpn.h:331 9 0x000060f55e34507c in vpn_leak_from_vrf_update (to_bgp=0x60f56da52070, from_bgp=0x60f56da75af0, path_vrf=0x60f56dbc4a60) at bgpd/bgp_mplsvpn.c:1575 10 0x000060f55e346657 in vpn_leak_from_vrf_update_all (to_bgp=0x60f56da52070, from_bgp=0x60f56da75af0, afi=AFI_IP) at bgpd/bgp_mplsvpn.c:2028 11 0x000060f55e340c10 in vpn_leak_postchange (direction=BGP_VPN_POLICY_DIR_TOVPN, afi=AFI_IP, bgp_vpn=0x60f56da52070, bgp_vrf=0x60f56da75af0) at ./bgpd/bgp_mplsvpn.h:310 12 0x000060f55e34a692 in vpn_leak_postchange_all () at bgpd/bgp_mplsvpn.c:3737 13 0x000060f55e3d91fc in router_bgp (self=0x60f55e5cbc20 , vty=0x60f56e2d7660, argc=3, argv=0x60f56da19830) at bgpd/bgp_vty.c:1601 14 0x0000714ed069ddf5 in cmd_execute_command_real (vline=0x60f56da32a80, vty=0x60f56e2d7660, cmd=0x0, up_level=0) at lib/command.c:1002 15 0x0000714ed069df6e in cmd_execute_command (vline=0x60f56da32a80, vty=0x60f56e2d7660, cmd=0x0, vtysh=0) at lib/command.c:1061 16 0x0000714ed069e51e in cmd_execute (vty=0x60f56e2d7660, cmd=0x60f56dbf07d0 "router bgp 100\n", matched=0x0, vtysh=0) at lib/command.c:1227 17 0x0000714ed076faa0 in vty_command (vty=0x60f56e2d7660, buf=0x60f56dbf07d0 "router bgp 100\n") at lib/vty.c:616 18 0x0000714ed07719c4 in vty_execute (vty=0x60f56e2d7660) at lib/vty.c:1379 19 0x0000714ed07740f0 in vtysh_read (thread=0x7ffe6d97c700) at lib/vty.c:2374 20 0x0000714ed07685c4 in event_call (thread=0x7ffe6d97c700) at lib/event.c:1995 21 0x0000714ed06e3351 in frr_run (master=0x60f56d1d2e40) at lib/libfrr.c:1232 22 0x000060f55e2c4b44 in main (argc=7, argv=0x7ffe6d97c978) at bgpd/bgp_main.c:555 (gdb) ``` Fixes https://github.com/FRRouting/frr/issues/16484 Signed-off-by: Donatas Abraitis --- bgpd/bgp_mplsvpn.c | 6 ++++++ bgpd/bgp_vty.c | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index a1d0a8512c..b03171b4c8 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -3734,6 +3734,9 @@ void vpn_leak_postchange_all(void) if (bgp->inst_type != BGP_INSTANCE_TYPE_VRF) continue; + if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_AUTO)) + continue; + vpn_leak_postchange( BGP_VPN_POLICY_DIR_TOVPN, AFI_IP, @@ -3753,6 +3756,9 @@ void vpn_leak_postchange_all(void) if (bgp->inst_type != BGP_INSTANCE_TYPE_VRF) continue; + if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_AUTO)) + continue; + vpn_leak_postchange( BGP_VPN_POLICY_DIR_FROMVPN, AFI_IP, diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index ae14abe9e3..828fa711b2 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -1703,7 +1703,7 @@ DEFUN (no_router_bgp, continue; if (CHECK_FLAG(tmp_bgp->vrf_flags, BGP_VRF_AUTO)) - continue; + bgp_delete(tmp_bgp); if (CHECK_FLAG( tmp_bgp->af_flags[AFI_IP] From 460703f3e8ce63baf86f8b4f8f54fe5d77d1317c Mon Sep 17 00:00:00 2001 From: "G. Paul Ziemba" Date: Sat, 27 Jul 2024 11:56:54 -0700 Subject: [PATCH 253/347] tests: add wait to RequireVpnRoutes, RequireUnicastRoutes Signed-off-by: G. Paul Ziemba --- tests/topotests/lib/bgprib.py | 112 +++++++++++++++++++++++++++------- 1 file changed, 90 insertions(+), 22 deletions(-) diff --git a/tests/topotests/lib/bgprib.py b/tests/topotests/lib/bgprib.py index 699c7a4da6..f01a440b9e 100644 --- a/tests/topotests/lib/bgprib.py +++ b/tests/topotests/lib/bgprib.py @@ -64,10 +64,9 @@ def routes_include_wanted(self, pfxtbl, want, debug): self.log("missing route: pfx=" + want["p"] + ", nh=" + want["n"]) return 0 - def RequireVpnRoutes(self, target, title, wantroutes, debug=0): + def RequireVpnRoutesOne(self, target, title, wantroutes, debug=0): import json - logstr = "RequireVpnRoutes " + str(wantroutes) # non json form for humans luCommand( target, @@ -86,11 +85,18 @@ def RequireVpnRoutes(self, target, title, wantroutes, debug=0): if re.search(r"^\s*$", ret): # degenerate case: empty json means no routes if len(wantroutes) > 0: - luResult(target, False, title, logstr) - return - luResult(target, True, title, logstr) + return False + return True rib = json.loads(ret) - rds = rib["routes"]["routeDistinguishers"] + try: + rds = rib["routes"]["routeDistinguishers"] + except KeyError as err: + # KeyError: 'routes' probably means missing/bad VRF + # This error also happens if we are too quick and the routing + # table has not been fully populated yet. + if debug: + self.log("KeyError, no routes") + return False for want in wantroutes: found = 0 if debug: @@ -105,11 +111,39 @@ def RequireVpnRoutes(self, target, title, wantroutes, debug=0): found = 1 break if not found: - luResult(target, False, title, logstr) - return - luResult(target, True, title, logstr) + return False + return True + + def RequireVpnRoutes( + self, target, title, wantroutes, debug=0, wait=10, wait_time=0.5 + ): + import time + import math + + logstr = "RequireVpnRoutes " + str(wantroutes) + found = False + n = 0 + startt = time.time() + + # Calculate the amount of `sleep`s we are going to peform. + wait_count = int(math.ceil(wait / wait_time)) + 1 + + while wait_count > 0: + n += 1 + found = self.RequireVpnRoutesOne(target, title, wantroutes, debug) + if found is not False: + break - def RequireUnicastRoutes(self, target, afi, vrf, title, wantroutes, debug=0): + wait_count -= 1 + if wait_count > 0: + time.sleep(wait_time) + + delta = time.time() - startt + self.log("Done after %d loops, time=%s, Found=%s" % (n, delta, found)) + luResult(target, found, title, logstr) + return found + + def RequireUnicastRoutesOne(self, target, afi, vrf, title, wantroutes, debug=0): logstr = "RequireUnicastRoutes %s" % str(wantroutes) vrfstr = "" if vrf != "": @@ -129,9 +163,8 @@ def RequireUnicastRoutes(self, target, afi, vrf, title, wantroutes, debug=0): if re.search(r"^\s*$", ret): # degenerate case: empty json means no routes if len(wantroutes) > 0: - luResult(target, False, title, logstr) - return - luResult(target, True, title, logstr) + return False, "" + return True, "" rib = json.loads(ret) try: table = rib["routes"] @@ -141,25 +174,60 @@ def RequireUnicastRoutes(self, target, afi, vrf, title, wantroutes, debug=0): errstr = "-script ERROR: check if wrong vrf (%s)" % (vrf) else: errstr = "-script ERROR: check if vrf missing" - luResult(target, False, title + errstr, logstr) - return + self.log(errstr) + return False, errstr # if debug: # self.log("table=%s" % table) for want in wantroutes: if debug: self.log("want=%s" % want) if not self.routes_include_wanted(table, want, debug): - luResult(target, False, title, logstr) - return - luResult(target, True, title, logstr) + return False, "" + return True, "" + + def RequireUnicastRoutes( + self, target, afi, vrf, title, wantroutes, debug=0, wait=10, wait_time=0.5 + ): + import time + import math + + logstr = "RequireUnicastRoutes %s" % str(wantroutes) + found = False + n = 0 + startt = time.time() + errstr = "" + + # Calculate the amount of `sleep`s we are going to peform. + wait_count = int(math.ceil(wait / wait_time)) + 1 + + while wait_count > 0: + n += 1 + found, errstr = self.RequireUnicastRoutesOne( + target, afi, vrf, title, wantroutes, debug + ) + if found is not False: + break + + wait_count -= 1 + if wait_count > 0: + time.sleep(wait_time) + + delta = time.time() - startt + self.log("Done after %d loops, time=%s, Found=%s" % (n, delta, found)) + luResult(target, found, title + errstr, logstr) + return found BgpRib = BgpRib() -def bgpribRequireVpnRoutes(target, title, wantroutes, debug=0): - BgpRib.RequireVpnRoutes(target, title, wantroutes, debug) +def bgpribRequireVpnRoutes(target, title, wantroutes, debug=0, wait=10, wait_time=0.5): + BgpRib.RequireVpnRoutes(target, title, wantroutes, debug, wait, wait_time) -def bgpribRequireUnicastRoutes(target, afi, vrf, title, wantroutes, debug=0): - BgpRib.RequireUnicastRoutes(target, afi, vrf, title, wantroutes, debug) +def bgpribRequireUnicastRoutes( + target, afi, vrf, title, wantroutes, debug=0, wait=10, wait_time=0.5 +): + BgpRib.RequireUnicastRoutes( + target, afi, vrf, title, wantroutes, debug, wait, wait_time + ) From 13126dec147ec7c8f94ca2adb870e5b6646fb3bb Mon Sep 17 00:00:00 2001 From: Rafael Zalamena Date: Tue, 6 Dec 2022 09:58:22 -0300 Subject: [PATCH 254/347] yang: MSDP authentication support Specify MSDP authentication specification model. Signed-off-by: Rafael Zalamena --- yang/frr-pim.yang | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/yang/frr-pim.yang b/yang/frr-pim.yang index cc8d6445aa..6a6c52185d 100644 --- a/yang/frr-pim.yang +++ b/yang/frr-pim.yang @@ -122,6 +122,37 @@ module frr-pim { } } + grouping msdp-authentication { + description + "MSDP authentication options."; + + leaf authentication-type { + type enumeration { + enum None { + value 0; + description + "No authentication."; + } + enum MD5 { + value 1; + description + "Use MD5 digest."; + } + } + default None; + description + "Authentication method."; + } + + leaf authentication-key { + when "../authentication-type = 'MD5'"; + mandatory true; + type string; + description + "Authentication key."; + } + } + grouping global-pim-config-attributes { description "A grouping defining per address family pim global attributes"; @@ -283,6 +314,8 @@ module frr-pim { description "Access list name used to filter the outgoing SAs exchanged."; } + + uses msdp-authentication; } container mlag { From bd838d8c896140ae43b41bb7f8fcf88a26ec5a0f Mon Sep 17 00:00:00 2001 From: Rafael Zalamena Date: Wed, 7 Dec 2022 10:13:39 -0300 Subject: [PATCH 255/347] pimd: add support for MSDP authentication Implement MSDP MD5 authentication connection support. Implementation details: - Move the MSDP socket creation code to a generic function so it can be parametrized to be used with/without authentication. - The MSDP peer connection will not change when the configuration is set, instead it will only be applied next connection or when `clear ip msdp peer A.B.C.D` is called. Signed-off-by: Rafael Zalamena --- pimd/pim_cmd.c | 87 +++++++++++++ pimd/pim_memory.c | 1 + pimd/pim_memory.h | 1 + pimd/pim_msdp.c | 37 +++++- pimd/pim_msdp.h | 21 ++++ pimd/pim_msdp_socket.c | 280 +++++++++++++++++++++++++++++++---------- pimd/pim_msdp_socket.h | 3 + pimd/pim_nb.c | 13 ++ pimd/pim_nb.h | 3 + pimd/pim_nb_config.c | 79 ++++++++++++ 10 files changed, 457 insertions(+), 68 deletions(-) diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index 1e3e090868..dcfad2a4f8 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -2823,6 +2823,39 @@ DEFPY (clear_ip_mroute_count, return clear_ip_mroute_count_command(vty, name); } +DEFPY(clear_ip_msdp_peer, clear_ip_msdp_peer_cmd, + "clear ip msdp peer A.B.C.D$peer [vrf WORD$vrfname]", + CLEAR_STR + IP_STR + MSDP_STR + "Restart MSDP peer\n" + "MSDP peer address\n" + VRF_CMD_HELP_STR) +{ + const struct pim_instance *pim; + const struct listnode *node; + const struct vrf *vrf; + struct pim_msdp_peer *mp; + + if (vrfname) { + vrf = vrf_lookup_by_name(vrfname); + if (vrf == NULL) + return CMD_WARNING; + } else + vrf = vrf_lookup_by_id(VRF_DEFAULT); + + pim = vrf->info; + for (ALL_LIST_ELEMENTS_RO(pim->msdp.peer_list, node, mp)) { + if (mp->peer.s_addr != peer.s_addr) + continue; + + pim_msdp_peer_restart(mp); + break; + } + + return CMD_SUCCESS; +} + DEFPY (show_ip_mroute_count, show_ip_mroute_count_cmd, "show ip mroute [vrf NAME] count [json$json]", @@ -6285,6 +6318,57 @@ DEFPY_ATTR(ip_pim_msdp_peer, return ret; } +DEFPY(msdp_peer_md5, msdp_peer_md5_cmd, + "msdp peer A.B.C.D$peer password WORD$psk", + CFG_MSDP_STR + "Configure MSDP peer\n" + "MSDP Peer address\n" + "Use MD5 authentication\n" + "MD5 pre shared key\n") +{ + const struct lyd_node *peer_node; + char xpath[XPATH_MAXLEN + 24]; + + snprintf(xpath, sizeof(xpath), "%s/msdp-peer[peer-ip='%s']", + VTY_CURR_XPATH, peer_str); + peer_node = yang_dnode_get(vty->candidate_config->dnode, xpath); + if (peer_node == NULL) { + vty_out(vty, "%% MSDP peer %s not yet configured\n", peer_str); + return CMD_SUCCESS; + } + + nb_cli_enqueue_change(vty, "./authentication-type", NB_OP_MODIFY, "MD5"); + nb_cli_enqueue_change(vty, "./authentication-key", NB_OP_MODIFY, psk); + + return nb_cli_apply_changes(vty, "%s", xpath); +} + +DEFPY(no_msdp_peer_md5, no_msdp_peer_md5_cmd, + "no msdp peer A.B.C.D$peer password [WORD]", + NO_STR + CFG_MSDP_STR + "Configure MSDP peer\n" + "MSDP Peer address\n" + "Use MD5 authentication\n" + "MD5 pre shared key\n") +{ + const struct lyd_node *peer_node; + char xpath[XPATH_MAXLEN + 24]; + + snprintf(xpath, sizeof(xpath), "%s/msdp-peer[peer-ip='%s']", + VTY_CURR_XPATH, peer_str); + peer_node = yang_dnode_get(vty->candidate_config->dnode, xpath); + if (peer_node == NULL) { + vty_out(vty, "%% MSDP peer %s not yet configured\n", peer_str); + return CMD_SUCCESS; + } + + nb_cli_enqueue_change(vty, "./authentication-type", NB_OP_MODIFY, + "None"); + + return nb_cli_apply_changes(vty, "%s", xpath); +} + DEFPY(pim_msdp_timers, pim_msdp_timers_cmd, "msdp timers (1-65535)$keepalive (1-65535)$holdtime [(1-65535)$connretry]", CFG_MSDP_STR @@ -8320,6 +8404,8 @@ void pim_cmd_init(void) install_element(PIM_NODE, &pim_msdp_peer_cmd); install_element(PIM_NODE, &no_pim_msdp_peer_cmd); + install_element(PIM_NODE, &msdp_peer_md5_cmd); + install_element(PIM_NODE, &no_msdp_peer_md5_cmd); install_element(PIM_NODE, &pim_msdp_timers_cmd); install_element(PIM_NODE, &no_pim_msdp_timers_cmd); install_element(PIM_NODE, &msdp_peer_sa_filter_cmd); @@ -8462,6 +8548,7 @@ void pim_cmd_init(void) install_element(ENABLE_NODE, &pim_test_sg_keepalive_cmd); install_element(ENABLE_NODE, &clear_ip_mroute_count_cmd); + install_element(ENABLE_NODE, &clear_ip_msdp_peer_cmd); install_element(ENABLE_NODE, &clear_ip_interfaces_cmd); install_element(ENABLE_NODE, &clear_ip_igmp_interfaces_cmd); install_element(ENABLE_NODE, &clear_ip_mroute_cmd); diff --git a/pimd/pim_memory.c b/pimd/pim_memory.c index 85780f013b..604e24482d 100644 --- a/pimd/pim_memory.c +++ b/pimd/pim_memory.c @@ -26,6 +26,7 @@ DEFINE_MTYPE(PIMD, PIM_RP, "PIM RP info"); DEFINE_MTYPE(PIMD, PIM_FILTER_NAME, "PIM RP filter info"); DEFINE_MTYPE(PIMD, PIM_MSDP_PEER, "PIM MSDP peer"); DEFINE_MTYPE(PIMD, PIM_MSDP_MG_NAME, "PIM MSDP mesh-group name"); +DEFINE_MTYPE(PIMD, PIM_MSDP_AUTH_KEY, "PIM MSDP authentication key"); DEFINE_MTYPE(PIMD, PIM_MSDP_SA, "PIM MSDP source-active cache"); DEFINE_MTYPE(PIMD, PIM_MSDP_MG, "PIM MSDP mesh group"); DEFINE_MTYPE(PIMD, PIM_MSDP_MG_MBR, "PIM MSDP mesh group mbr"); diff --git a/pimd/pim_memory.h b/pimd/pim_memory.h index 41730e7522..353e09a71c 100644 --- a/pimd/pim_memory.h +++ b/pimd/pim_memory.h @@ -28,6 +28,7 @@ DECLARE_MTYPE(PIM_MSDP_MG_NAME); DECLARE_MTYPE(PIM_MSDP_SA); DECLARE_MTYPE(PIM_MSDP_MG); DECLARE_MTYPE(PIM_MSDP_MG_MBR); +DECLARE_MTYPE(PIM_MSDP_AUTH_KEY); DECLARE_MTYPE(PIM_SEC_ADDR); DECLARE_MTYPE(PIM_JP_AGG_GROUP); DECLARE_MTYPE(PIM_JP_AGG_SOURCE); diff --git a/pimd/pim_msdp.c b/pimd/pim_msdp.c index 0bb2d93a3a..215cc3c502 100644 --- a/pimd/pim_msdp.c +++ b/pimd/pim_msdp.c @@ -773,7 +773,10 @@ static void pim_msdp_peer_listen(struct pim_msdp_peer *mp) * first listening peer is configured; but don't bother tearing it down * when * all the peers go down */ - pim_msdp_sock_listen(mp->pim); + if (mp->auth_type == MSDP_AUTH_NONE) + pim_msdp_sock_listen(mp->pim); + else + pim_msdp_sock_auth_listen(mp); } /* 11.2.A4 and 11.2.A5: transition active or passive peer to @@ -1045,6 +1048,7 @@ struct pim_msdp_peer *pim_msdp_peer_add(struct pim_instance *pim, mp->state = PIM_MSDP_INACTIVE; mp->fd = -1; + mp->auth_listen_sock = -1; strlcpy(mp->last_reset, "-", sizeof(mp->last_reset)); /* higher IP address is listener */ if (ntohl(mp->local.s_addr) > ntohl(mp->peer.s_addr)) { @@ -1100,6 +1104,12 @@ static void pim_msdp_peer_free(struct pim_msdp_peer *mp) stream_fifo_free(mp->obuf); } + /* Free authentication data. */ + event_cancel(&mp->auth_listen_ev); + XFREE(MTYPE_PIM_MSDP_AUTH_KEY, mp->auth_key); + if (mp->auth_listen_sock != -1) + close(mp->auth_listen_sock); + XFREE(MTYPE_PIM_MSDP_MG_NAME, mp->mesh_group_name); mp->pim = NULL; @@ -1128,19 +1138,32 @@ void pim_msdp_peer_del(struct pim_msdp_peer **mp) *mp = NULL; } -void pim_msdp_peer_change_source(struct pim_msdp_peer *mp, - const struct in_addr *addr) +void pim_msdp_peer_restart(struct pim_msdp_peer *mp) { - pim_msdp_peer_stop_tcp_conn(mp, true); + /* Stop auth listening socket if any. */ + event_cancel(&mp->auth_listen_ev); + if (mp->auth_listen_sock != -1) { + close(mp->auth_listen_sock); + mp->auth_listen_sock = -1; + } - mp->local = *addr; + /* Stop previously running connection. */ + pim_msdp_peer_stop_tcp_conn(mp, true); + /* Start connection again. */ if (PIM_MSDP_PEER_IS_LISTENER(mp)) pim_msdp_peer_listen(mp); else pim_msdp_peer_connect(mp); } +void pim_msdp_peer_change_source(struct pim_msdp_peer *mp, + const struct in_addr *addr) +{ + mp->local = *addr; + pim_msdp_peer_restart(mp); +} + /* peer hash and peer list helpers */ static unsigned int pim_msdp_peer_hash_key_make(const void *p) { @@ -1318,6 +1341,10 @@ bool pim_msdp_peer_config_write(struct vty *vty, struct pim_instance *pim) vty_out(vty, " msdp peer %pI4 source %pI4\n", &mp->peer, &mp->local); + if (mp->auth_type == MSDP_AUTH_MD5) + vty_out(vty, " msdp peer %pI4 password %s\n", &mp->peer, + mp->auth_key); + if (mp->acl_in) vty_out(vty, " msdp peer %pI4 sa-filter %s in\n", &mp->peer, mp->acl_in); diff --git a/pimd/pim_msdp.h b/pimd/pim_msdp.h index a45726cb85..f77b0e1a3a 100644 --- a/pimd/pim_msdp.h +++ b/pimd/pim_msdp.h @@ -89,6 +89,11 @@ enum pim_msdp_peer_flags { PIM_MSDP_PEERF_IN_GROUP = (1 << 2), }; +enum msdp_auth_type { + MSDP_AUTH_NONE = 0, + MSDP_AUTH_MD5 = 1, +}; + struct pim_msdp_peer { struct pim_instance *pim; @@ -98,6 +103,13 @@ struct pim_msdp_peer { char *mesh_group_name; char key_str[INET_ADDRSTRLEN]; + /* Authentication data. */ + enum msdp_auth_type auth_type; + char *auth_key; + + int auth_listen_sock; + struct event *auth_listen_ev; + /* state */ enum pim_msdp_peer_state state; enum pim_msdp_peer_flags flags; @@ -309,6 +321,15 @@ void pim_msdp_peer_del(struct pim_msdp_peer **mp); void pim_msdp_peer_change_source(struct pim_msdp_peer *mp, const struct in_addr *addr); +/** + * Restart peer's connection. + * + * This is used internally in MSDP and should be used by northbound + * when wanting to immediately apply connections settings such as + * authentication. + */ +void pim_msdp_peer_restart(struct pim_msdp_peer *mp); + #else /* PIM_IPV == 6 */ static inline void pim_msdp_init(struct pim_instance *pim, struct event_loop *master) diff --git a/pimd/pim_msdp_socket.c b/pimd/pim_msdp_socket.c index fe8d5e934a..2fb0bb87c7 100644 --- a/pimd/pim_msdp_socket.c +++ b/pimd/pim_msdp_socket.c @@ -49,6 +49,192 @@ static void pim_msdp_update_sock_send_buffer_size(int fd) } } +/** + * Helper function to reduce code duplication. + * + * \param vrf VRF pointer (`NULL` means default VRF) + * \param mp the MSDP session pointer. + * \returns valid file descriptor otherwise `-1`. + */ +static int _pim_msdp_sock_listen(const struct vrf *vrf, + const struct pim_msdp_peer *mp) +{ + const struct interface *ifp; + int sock; + int rv; + socklen_t socklen; + struct sockaddr_in sin = {}; + union sockunion su_peer = {}; + + sock = socket(AF_INET, SOCK_STREAM, 0); + if (sock == -1) { + zlog_warn("%s: socket: %s", __func__, strerror(errno)); + return -1; + } + + socklen = sizeof(sin); + sin.sin_family = AF_INET; + sin.sin_port = htons(PIM_MSDP_TCP_PORT); +#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN + sin.sin_len = socklen; +#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ + if (mp) + sin.sin_addr = mp->local; + + sockopt_reuseaddr(sock); + sockopt_reuseport(sock); + + /* Bind socket to VRF/address. */ + if (vrf && vrf->vrf_id != VRF_DEFAULT) { + ifp = if_lookup_by_name(vrf->name, vrf->vrf_id); + if (ifp == NULL) { + flog_err(EC_LIB_INTERFACE, + "%s: Unable to lookup vrf interface: %s", + __func__, vrf->name); + close(sock); + return -1; + } + + if (vrf_bind(vrf->vrf_id, sock, ifp->name) == -1) { + flog_err_sys(EC_LIB_SOCKET, + "%s: Unable to bind to socket: %s", + __func__, safe_strerror(errno)); + close(sock); + return -1; + } + } + + frr_with_privs (&pimd_privs) { + rv = bind(sock, (struct sockaddr *)&sin, socklen); + } + if (rv == -1) { + flog_err_sys(EC_LIB_SOCKET, + "pim_msdp_socket bind to port %d: %s", + ntohs(sin.sin_port), safe_strerror(errno)); + close(sock); + return -1; + } + + /* Set MD5 authentication. */ + if (mp && mp->auth_key) { + su_peer = mp->su_peer; + frr_with_privs (&pimd_privs) { + sockopt_tcp_signature(sock, &su_peer, mp->auth_key); + } + } + + + /* Start listening. */ + rv = listen(sock, SOMAXCONN); + if (rv == -1) { + flog_err_sys(EC_LIB_SOCKET, "pim_msdp_socket listen: %s", + safe_strerror(errno)); + close(sock); + return -1; + } + + /* Set socket DSCP byte */ + if (setsockopt_ipv4_tos(sock, IPTOS_PREC_INTERNETCONTROL)) { + zlog_warn("can't set sockopt IP_TOS to MSDP socket %d: %s", + sock, safe_strerror(errno)); + } + + return sock; +} + +static void pim_msdp_sock_auth_accept(struct event *t) +{ + struct pim_msdp_peer *mp = EVENT_ARG(t); + int sock; + socklen_t sinlen; + struct sockaddr_in sin = {}; + + /* accept client connection. */ + sinlen = sizeof(sin); + sock = accept(mp->auth_listen_sock, (struct sockaddr *)&sin, &sinlen); + if (sock == -1) { + flog_err_sys(EC_LIB_SOCKET, "pim_msdp_sock_accept failed (%s)", + safe_strerror(errno)); + + /* Accept failed, schedule listen again. */ + event_add_read(router->master, pim_msdp_sock_auth_accept, mp, + mp->auth_listen_sock, &mp->auth_listen_ev); + return; + } + + /* + * Previous connection still going. + * + * We must wait for the user to close the previous connection in order + * to establish the new one. User can manually force that by calling + * `clear ip msdp peer A.B.C.D`. + */ + if (mp->fd != -1) { + ++mp->pim->msdp.rejected_accepts; + if (PIM_DEBUG_MSDP_EVENTS) { + flog_err(EC_PIM_MSDP_PACKET, + "msdp peer connection refused from %pI4: old connection still running", + &sin.sin_addr); + } + close(sock); + + /* Unexpected connection, schedule listen again. */ + event_add_read(router->master, pim_msdp_sock_auth_accept, mp, + mp->auth_listen_sock, &mp->auth_listen_ev); + return; + } + + /* Unexpected client connected. */ + if (mp->peer.s_addr != sin.sin_addr.s_addr) { + ++mp->pim->msdp.rejected_accepts; + if (PIM_DEBUG_MSDP_EVENTS) { + flog_err(EC_PIM_MSDP_PACKET, + "msdp peer connection refused from %pI4", + &sin.sin_addr); + } + close(sock); + + /* Unexpected peer, schedule listen again. */ + event_add_read(router->master, pim_msdp_sock_auth_accept, mp, + mp->auth_listen_sock, &mp->auth_listen_ev); + return; + } + + if (PIM_DEBUG_MSDP_INTERNAL) + zlog_debug("MSDP peer %s accept success", mp->key_str); + + /* Configure socket. */ + mp->fd = sock; + set_nonblocking(mp->fd); + pim_msdp_update_sock_send_buffer_size(mp->fd); + pim_msdp_peer_established(mp); + + /* Stop listening. */ + close(mp->auth_listen_sock); + mp->auth_listen_sock = -1; +} + +int pim_msdp_sock_auth_listen(struct pim_msdp_peer *mp) +{ + /* Clear any listening connection if it exists. */ + event_cancel(&mp->auth_listen_ev); + if (mp->auth_listen_sock != -1) { + close(mp->auth_listen_sock); + mp->auth_listen_sock = -1; + } + + /* Start new listening socket. */ + mp->auth_listen_sock = _pim_msdp_sock_listen(mp->pim->vrf, mp); + if (mp->auth_listen_sock == -1) + return -1; + + /* Listen for connections and connected only with the expected end. */ + event_add_read(router->master, pim_msdp_sock_auth_accept, mp, + mp->auth_listen_sock, &mp->auth_listen_ev); + + return 0; +} + /* passive peer socket accept */ static void pim_msdp_sock_accept(struct event *thread) { @@ -91,6 +277,21 @@ static void pim_msdp_sock_accept(struct event *thread) return; } + /* + * If authentication is configured then we can not accept + * unauthenticated connections. + */ + if (mp->auth_type != MSDP_AUTH_NONE) { + ++pim->msdp.rejected_accepts; + if (PIM_DEBUG_MSDP_EVENTS) { + flog_err(EC_PIM_MSDP_PACKET, + "msdp peer unauthenticated connection refused from %pSU", + &su); + } + close(msdp_sock); + return; + } + if (PIM_DEBUG_MSDP_INTERNAL) { zlog_debug("MSDP peer %s accept success%s", mp->key_str, mp->fd >= 0 ? "(dup)" : ""); @@ -116,9 +317,6 @@ static void pim_msdp_sock_accept(struct event *thread) int pim_msdp_sock_listen(struct pim_instance *pim) { int sock; - int socklen; - struct sockaddr_in sin; - int rc; struct pim_msdp_listener *listener = &pim->msdp.listener; if (pim->msdp.flags & PIM_MSDPF_LISTENER) { @@ -126,72 +324,20 @@ int pim_msdp_sock_listen(struct pim_instance *pim) return 0; } - sock = socket(AF_INET, SOCK_STREAM, 0); - if (sock < 0) { - flog_err_sys(EC_LIB_SOCKET, "socket: %s", safe_strerror(errno)); - return sock; - } + sock = _pim_msdp_sock_listen(pim->vrf, NULL); + if (sock == -1) + return -1; - memset(&sin, 0, sizeof(struct sockaddr_in)); - sin.sin_family = AF_INET; - sin.sin_port = htons(PIM_MSDP_TCP_PORT); - socklen = sizeof(struct sockaddr_in); + + memset(&listener->su.sin, 0, sizeof(listener->su.sin)); + listener->su.sin.sin_family = AF_INET; + listener->su.sin.sin_port = htons(PIM_MSDP_TCP_PORT); #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN - sin.sin_len = socklen; + listener->su.sin.sin_len = sizeof(listener->su.sin); #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ - sockopt_reuseaddr(sock); - sockopt_reuseport(sock); - - if (pim->vrf->vrf_id != VRF_DEFAULT) { - struct interface *ifp = - if_lookup_by_name(pim->vrf->name, pim->vrf->vrf_id); - if (!ifp) { - flog_err(EC_LIB_INTERFACE, - "%s: Unable to lookup vrf interface: %s", - __func__, pim->vrf->name); - close(sock); - return -1; - } - if (pim_socket_bind(sock, ifp)) { - flog_err_sys(EC_LIB_SOCKET, - "%s: Unable to bind to socket: %s", - __func__, safe_strerror(errno)); - close(sock); - return -1; - } - } - - frr_with_privs(&pimd_privs) { - /* bind to well known TCP port */ - rc = bind(sock, (struct sockaddr *)&sin, socklen); - } - - if (rc < 0) { - flog_err_sys(EC_LIB_SOCKET, - "pim_msdp_socket bind to port %d: %s", - ntohs(sin.sin_port), safe_strerror(errno)); - close(sock); - return rc; - } - - rc = listen(sock, 3 /* backlog */); - if (rc < 0) { - flog_err_sys(EC_LIB_SOCKET, "pim_msdp_socket listen: %s", - safe_strerror(errno)); - close(sock); - return rc; - } - - /* Set socket DSCP byte */ - if (setsockopt_ipv4_tos(sock, IPTOS_PREC_INTERNETCONTROL)) { - zlog_warn("can't set sockopt IP_TOS to MSDP socket %d: %s", - sock, safe_strerror(errno)); - } - /* add accept thread */ listener->fd = sock; - memcpy(&listener->su, &sin, socklen); event_add_read(pim->msdp.master, pim_msdp_sock_accept, pim, sock, &listener->thread); @@ -272,6 +418,14 @@ int pim_msdp_sock_connect(struct pim_msdp_peer *mp) mp->fd, safe_strerror(errno)); } + /* Set authentication (if configured). */ + if (mp->auth_key) { + frr_with_privs (&pimd_privs) { + sockopt_tcp_signature(mp->fd, &mp->su_peer, + mp->auth_key); + } + } + /* Connect to the remote mp. */ return (sockunion_connect(mp->fd, &mp->su_peer, htons(PIM_MSDP_TCP_PORT), 0)); diff --git a/pimd/pim_msdp_socket.h b/pimd/pim_msdp_socket.h index ae31664f9c..d2c601409a 100644 --- a/pimd/pim_msdp_socket.h +++ b/pimd/pim_msdp_socket.h @@ -6,6 +6,9 @@ #ifndef PIM_MSDP_SOCKET_H #define PIM_MSDP_SOCKET_H +struct pim_msdp_peer; + +int pim_msdp_sock_auth_listen(struct pim_msdp_peer *mp); int pim_msdp_sock_listen(struct pim_instance *pim); int pim_msdp_sock_connect(struct pim_msdp_peer *mp); #endif diff --git a/pimd/pim_nb.c b/pimd/pim_nb.c index 6f4e325220..72b5bdefc9 100644 --- a/pimd/pim_nb.c +++ b/pimd/pim_nb.c @@ -177,6 +177,19 @@ const struct frr_yang_module_info frr_pim_info = { .destroy = pim_msdp_peer_sa_filter_out_destroy, } }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-peer/authentication-type", + .cbs = { + .modify = pim_msdp_peer_authentication_type_modify, + } + }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-peer/authentication-key", + .cbs = { + .modify = pim_msdp_peer_authentication_key_modify, + .destroy = pim_msdp_peer_authentication_key_destroy, + } + }, { .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/mlag", .cbs = { diff --git a/pimd/pim_nb.h b/pimd/pim_nb.h index 56153bafba..3c7ab49ab3 100644 --- a/pimd/pim_nb.h +++ b/pimd/pim_nb.h @@ -69,6 +69,9 @@ int pim_msdp_peer_sa_filter_in_modify(struct nb_cb_modify_args *args); int pim_msdp_peer_sa_filter_in_destroy(struct nb_cb_destroy_args *args); int pim_msdp_peer_sa_filter_out_modify(struct nb_cb_modify_args *args); int pim_msdp_peer_sa_filter_out_destroy(struct nb_cb_destroy_args *args); +int pim_msdp_peer_authentication_type_modify(struct nb_cb_modify_args *args); +int pim_msdp_peer_authentication_key_modify(struct nb_cb_modify_args *args); +int pim_msdp_peer_authentication_key_destroy(struct nb_cb_destroy_args *args); int routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_create( struct nb_cb_create_args *args); int routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_destroy( diff --git a/pimd/pim_nb_config.c b/pimd/pim_nb_config.c index 49bd9a5ce7..328463c40e 100644 --- a/pimd/pim_nb_config.c +++ b/pimd/pim_nb_config.c @@ -15,6 +15,7 @@ #include "pim_pim.h" #include "pim_mlag.h" #include "pim_bfd.h" +#include "pim_msdp_socket.h" #include "pim_static.h" #include "pim_ssm.h" #include "pim_ssmpingd.h" @@ -1053,6 +1054,9 @@ pim6_msdp_err(routing_control_plane_protocols_control_plane_protocol_pim_address nb_cb_destroy_args); pim6_msdp_err(routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_peer_create, nb_cb_create_args); +pim6_msdp_err(pim_msdp_peer_authentication_type_modify, nb_cb_modify_args); +pim6_msdp_err(pim_msdp_peer_authentication_key_modify, nb_cb_modify_args); +pim6_msdp_err(pim_msdp_peer_authentication_key_destroy, nb_cb_destroy_args); #if PIM_IPV != 6 /* @@ -1154,6 +1158,81 @@ int pim_msdp_mesh_group_source_destroy(struct nb_cb_destroy_args *args) return NB_OK; } +/* + * XPath: + * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-peer/authentication-type + */ +int pim_msdp_peer_authentication_type_modify(struct nb_cb_modify_args *args) +{ + struct pim_msdp_peer *mp; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + mp = nb_running_get_entry(args->dnode, NULL, true); + mp->auth_type = yang_dnode_get_enum(args->dnode, NULL); + break; + } + + return NB_OK; +} + +/* + * XPath: + * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-peer/authentication-key + */ +int pim_msdp_peer_authentication_key_modify(struct nb_cb_modify_args *args) +{ + struct pim_msdp_peer *mp; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + if (strlen(yang_dnode_get_string(args->dnode, NULL)) > + TCP_MD5SIG_MAXKEYLEN) { + snprintf(args->errmsg, args->errmsg_len, + "MD5 authentication key too long"); + return NB_ERR_VALIDATION; + } + break; + case NB_EV_APPLY: + mp = nb_running_get_entry(args->dnode, NULL, true); + XFREE(MTYPE_PIM_MSDP_AUTH_KEY, mp->auth_key); + mp->auth_key = XSTRDUP(MTYPE_PIM_MSDP_AUTH_KEY, + yang_dnode_get_string(args->dnode, NULL)); + + /* We must start listening the new authentication key now. */ + if (PIM_MSDP_PEER_IS_LISTENER(mp)) + pim_msdp_sock_auth_listen(mp); + break; + } + + return NB_OK; +} + +int pim_msdp_peer_authentication_key_destroy(struct nb_cb_destroy_args *args) +{ + struct pim_msdp_peer *mp; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + mp = nb_running_get_entry(args->dnode, NULL, true); + XFREE(MTYPE_PIM_MSDP_AUTH_KEY, mp->auth_key); + break; + } + + return NB_OK; +} /* * XPath: From 2d206c89c65e085943d00da8e6ea1ec938af9325 Mon Sep 17 00:00:00 2001 From: Rafael Zalamena Date: Tue, 10 May 2022 08:22:53 -0300 Subject: [PATCH 256/347] doc: document MSDP authentication and reset Tell user how to use the new authentication and clear commands. Signed-off-by: Rafael Zalamena --- doc/user/pim.rst | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/doc/user/pim.rst b/doc/user/pim.rst index 20a4f1f7ab..d8e52f471e 100644 --- a/doc/user/pim.rst +++ b/doc/user/pim.rst @@ -386,6 +386,17 @@ Commands available for MSDP: The filtering will only take effect starting from the command application. +.. clicmd:: msdp peer A.B.C.D password WORD + + Use MD5 authentication to connect with the remote peer. + + .. note:: + + The authentication will only take effect when starting a new + connection. + + To apply it immediately call `clear ip msdp peer A.B.C.D`. + .. _show-pim-information: @@ -715,6 +726,13 @@ Clear commands reset various variables. removes the next hop tracking for the bsr and resets the upstreams for the dynamically learnt RPs. +.. clicmd:: clear ip msdp peer A.B.C.D + + Reset MSDP peer connection. + + Use this command to set/unset MD5 authentication. + + PIM EVPN configuration ====================== To use PIM in the underlay for overlay BUM forwarding associate a multicast From a2209b597a23cefaf9a7cddf01a2932ab49799c2 Mon Sep 17 00:00:00 2001 From: Rafael Zalamena Date: Tue, 10 May 2022 08:23:06 -0300 Subject: [PATCH 257/347] lib: define constant for plataforms missing it Add definition of `TCP_MD5SIG_MAXKEYLEN` in the `sockopt.h` header so users of it have the definition of the maximum key length for socket authentication operations. The following OSes reported failure in CI while building: - NetBSD 8 - FreeBSD 11 - FreeBSD 12 Signed-off-by: Rafael Zalamena --- lib/sockopt.h | 10 ++++++++++ pimd/pim_nb_config.c | 1 + 2 files changed, 11 insertions(+) diff --git a/lib/sockopt.h b/lib/sockopt.h index ce7d665fab..e6fb78d5e4 100644 --- a/lib/sockopt.h +++ b/lib/sockopt.h @@ -60,6 +60,16 @@ extern int setsockopt_ipv6_tclass(int, int); (((af) == AF_INET) : SOPT_SIZE_CMSG_IFINDEX_IPV4() \ ? SOPT_SIZE_CMSG_PKTINFO_IPV6()) +/* + * If not defined then define the value for `TCP_MD5SIG_MAXKEYLEN`. This seems + * to be unavailable for NetBSD 8, FreeBSD 11 and FreeBSD 12. + * + * The value below was copied from `linux/tcp.h` from the Linux kernel headers. + */ +#ifndef TCP_MD5SIG_MAXKEYLEN +#define TCP_MD5SIG_MAXKEYLEN 80 +#endif + extern int setsockopt_ipv4_multicast_if(int sock, struct in_addr if_addr, ifindex_t ifindex); extern int setsockopt_ipv4_multicast(int sock, int optname, diff --git a/pimd/pim_nb_config.c b/pimd/pim_nb_config.c index 328463c40e..bc7338ce18 100644 --- a/pimd/pim_nb_config.c +++ b/pimd/pim_nb_config.c @@ -9,6 +9,7 @@ #include "pimd.h" #include "pim_nb.h" #include "lib/northbound_cli.h" +#include "lib/sockopt.h" #include "pim_igmpv3.h" #include "pim_neighbor.h" #include "pim_nht.h" From e900c9ba31646642019980b440c1821e6b7d1993 Mon Sep 17 00:00:00 2001 From: Rafael Zalamena Date: Mon, 10 May 2021 11:36:16 -0300 Subject: [PATCH 258/347] topotests: test MSDP authentication Modify existing MSDP topology to use authentication. Signed-off-by: Rafael Zalamena --- tests/topotests/msdp_topo1/r1/pimd.conf | 4 ++++ tests/topotests/msdp_topo1/r2/pimd.conf | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/tests/topotests/msdp_topo1/r1/pimd.conf b/tests/topotests/msdp_topo1/r1/pimd.conf index 5bb268ebef..3c116a003b 100644 --- a/tests/topotests/msdp_topo1/r1/pimd.conf +++ b/tests/topotests/msdp_topo1/r1/pimd.conf @@ -20,3 +20,7 @@ ip msdp peer 192.168.0.2 source 192.168.0.1 ip msdp peer 192.168.1.2 source 192.168.1.1 ip pim rp 10.254.254.1 ip pim join-prune-interval 5 +! +router pim + msdp peer 192.168.0.2 password 1234 +! diff --git a/tests/topotests/msdp_topo1/r2/pimd.conf b/tests/topotests/msdp_topo1/r2/pimd.conf index 733bd6f2f1..4ea2c82314 100644 --- a/tests/topotests/msdp_topo1/r2/pimd.conf +++ b/tests/topotests/msdp_topo1/r2/pimd.conf @@ -16,3 +16,7 @@ ip msdp peer 192.168.0.1 source 192.168.0.2 ip msdp peer 192.168.2.2 source 192.168.2.1 ip pim rp 10.254.254.2 ip pim join-prune-interval 5 +! +router pim + msdp peer 192.168.0.1 password 1234 +! From e53fa582bcfe1ab7e26e43f4972b68222f4d1f9c Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Tue, 30 Jul 2024 07:21:58 -0400 Subject: [PATCH 259/347] zebra: Fix removal of routes on MetaQ when client goes down It is possible that right before an upper level protocol dies or is killed routes would be installed into zebra. These routes could be on the Meta-Q for early route-processing. Leaving us with a situation where the client is removed, and all it's routes that are in the rib at that time, and then after that the MetaQ is run and the routes are reprocessed leaving routes from an upper level daemon post daemon going away from zebra's perspective. These routes will be abandoned. Signed-off-by: Donald Sharp --- zebra/zebra_rib.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 142f83fb36..0f02b0a2ec 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -3837,7 +3837,8 @@ static void rib_meta_queue_free(struct meta_queue *mq, struct list *l, } static void early_route_meta_queue_free(struct meta_queue *mq, struct list *l, - struct zebra_vrf *zvrf) + const struct zebra_vrf *zvrf, + uint8_t proto, uint8_t instance) { struct zebra_early_route *ere; struct listnode *node, *nnode; @@ -3846,6 +3847,10 @@ static void early_route_meta_queue_free(struct meta_queue *mq, struct list *l, if (zvrf && ere->re->vrf_id != zvrf->vrf->vrf_id) continue; + if (proto != ZEBRA_ROUTE_ALL && + (proto != ere->re->type && instance != ere->re->instance)) + continue; + early_route_memory_free(ere); node->data = NULL; list_delete_node(l, node); @@ -3884,7 +3889,8 @@ void meta_queue_free(struct meta_queue *mq, struct zebra_vrf *zvrf) evpn_meta_queue_free(mq, mq->subq[i], zvrf); break; case META_QUEUE_EARLY_ROUTE: - early_route_meta_queue_free(mq, mq->subq[i], zvrf); + early_route_meta_queue_free(mq, mq->subq[i], zvrf, + ZEBRA_ROUTE_ALL, 0); break; case META_QUEUE_EARLY_LABEL: early_label_meta_queue_free(mq, mq->subq[i], zvrf); @@ -4752,6 +4758,10 @@ unsigned long rib_score_proto(uint8_t proto, unsigned short instance) if (!zvrf) continue; + early_route_meta_queue_free(zrouter.mq, + zrouter.mq->subq[META_QUEUE_EARLY_ROUTE], + zvrf, proto, instance); + cnt += rib_score_proto_table(proto, instance, zvrf->table[AFI_IP][SAFI_UNICAST]) + rib_score_proto_table( From 3dec216d385ed1218dc7ffdfa4653d2203824f9d Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Tue, 30 Jul 2024 13:57:44 -0400 Subject: [PATCH 260/347] doc: Add some topotest documentation about how to reproduce failures Add some hints for developers about how to reproduce failure conditions in the test. Signed-off-by: Donald Sharp --- doc/developer/topotests.rst | 40 +++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/doc/developer/topotests.rst b/doc/developer/topotests.rst index e1702c47c7..586c096740 100644 --- a/doc/developer/topotests.rst +++ b/doc/developer/topotests.rst @@ -750,6 +750,46 @@ IDE/editor if supported (e.g., the emacs ``cov-mode`` package) NOTE: the *.gcda files in ``/tmp/topotests/gcda`` are cumulative so if you do not remove them they will aggregate data across multiple topotest runs. +How to reproduce failed Tests +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Generally tests fail but recreating the test failure reliably is not necessarily +easy, or it happens once every 10 runs locally. Here are some generic strategies +that are employed to allow for the test to be reproduced reliably + +.. code:: console + + cd + ln -s test_the_test_name.py test_a.py + ln -s test_the_test_name.py test_b.py + +This allows you to run multiple copies of the same test with one full test run. +Additionally if you need to modify the test you don't need to recopy everything +to make it work. By adding multiple copies of the same occassionally failing test +you raise the odds of it failing again. Additionally you have easily accessible +good and bad runs to compare. + +.. code:: console + + sudo -E python3 -m pytest -n --dist=loadfile + +Choose a n value that is greater than the number of cpu's avalaible on the system. +This changes the timing and may or may not make it more likely that the test fails. +Be aware, though, that this changes memory requirements as well as may make other +tests fail more often as well. You should choose values that do not cause the system +to go into swap usage. + +.. code:: console + + stress -n + +By filling up cpu's with programs that do nothing you also change the timing again and +may cause the problem to happen more often. + +There is no magic bullet here. You as a developer might have to experiment with different +values and different combinations of the above to cause the problem to happen more often. +These are just the tools that we know of at this point in time. + .. _topotests_docker: From 0998b38e4d61179441f90dd7e7fd6a3a8b7bd8c5 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Wed, 31 Jul 2024 08:35:14 +0300 Subject: [PATCH 261/347] bgpd: Check the actual remaining stream length before taking TLV value ``` 0 0xb50b9f898028 in __sanitizer_print_stack_trace (/home/ubuntu/frr-public/frr_public_private-libfuzzer/bgpd/.libs/bgpd+0x368028) (BuildId: 3292703ed7958b20076550c967f879db8dc27ca7) 1 0xb50b9f7ed8e4 in fuzzer::PrintStackTrace() (/home/ubuntu/frr-public/frr_public_private-libfuzzer/bgpd/.libs/bgpd+0x2bd8e4) (BuildId: 3292703ed7958b20076550c967f879db8dc27ca7) 2 0xb50b9f7d4d9c in fuzzer::Fuzzer::CrashCallback() (/home/ubuntu/frr-public/frr_public_private-libfuzzer/bgpd/.libs/bgpd+0x2a4d9c) (BuildId: 3292703ed7958b20076550c967f879db8dc27ca7) 3 0xe0d12d7469cc (linux-vdso.so.1+0x9cc) (BuildId: 1a77697e9d723fe22246cfd7641b140c427b7e11) 4 0xe0d12c88f1fc in __pthread_kill_implementation nptl/pthread_kill.c:43:17 5 0xe0d12c84a678 in gsignal signal/../sysdeps/posix/raise.c:26:13 6 0xe0d12c83712c in abort stdlib/abort.c:79:7 7 0xe0d12d214724 in _zlog_assert_failed /home/ubuntu/frr-public/frr_public_private-libfuzzer/lib/zlog.c:789:2 8 0xe0d12d1285e4 in stream_get /home/ubuntu/frr-public/frr_public_private-libfuzzer/lib/stream.c:324:3 9 0xb50b9f8e47c4 in bgp_attr_encap /home/ubuntu/frr-public/frr_public_private-libfuzzer/bgpd/bgp_attr.c:2758:3 10 0xb50b9f8dcd38 in bgp_attr_parse /home/ubuntu/frr-public/frr_public_private-libfuzzer/bgpd/bgp_attr.c:3783:10 11 0xb50b9faf74b4 in bgp_update_receive /home/ubuntu/frr-public/frr_public_private-libfuzzer/bgpd/bgp_packet.c:2383:20 12 0xb50b9faf1dcc in bgp_process_packet /home/ubuntu/frr-public/frr_public_private-libfuzzer/bgpd/bgp_packet.c:4075:11 13 0xb50b9f8c90d0 in LLVMFuzzerTestOneInput /home/ubuntu/frr-public/frr_public_private-libfuzzer/bgpd/bgp_main.c:582:3 ``` Reported-by: Iggy Frankovic Signed-off-by: Donatas Abraitis --- bgpd/bgp_attr.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 2ed49935e5..ac5d08b6fe 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -2749,6 +2749,14 @@ static int bgp_attr_encap(struct bgp_attr_parser_args *args) args->total); } + if (STREAM_READABLE(BGP_INPUT(peer)) < sublength) { + zlog_err("Tunnel Encap attribute sub-tlv length %d exceeds remaining stream length %zu", + sublength, STREAM_READABLE(BGP_INPUT(peer))); + return bgp_attr_malformed(args, + BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, + args->total); + } + /* alloc and copy sub-tlv */ /* TBD make sure these are freed when attributes are released */ tlv = XCALLOC(MTYPE_ENCAP_TLV, From 9c710eef0c08b334c0591addb30b8cdcf509f03f Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Wed, 31 Jul 2024 11:43:19 +0300 Subject: [PATCH 262/347] bgpd: Use bgp_session_reset_safe() for GR update all peers It might cause this use-after-free: ``` ==6523==ERROR: AddressSanitizer: heap-use-after-free on address 0x60300058d720 at pc 0x55f3ab62ab1f bp 0x7ffe5b95a0d0 sp 0x7ffe5b95a0c8 READ of size 8 at 0x60300058d720 thread T0 #0 0x55f3ab62ab1e in bgp_gr_update_mode_of_all_peers bgpd/bgp_fsm.c:2729 #1 0x55f3ab62ab1e in bgp_gr_update_all bgpd/bgp_fsm.c:2779 #2 0x55f3ab73557e in bgp_inst_gr_config_vty bgpd/bgp_vty.c:3037 #3 0x55f3ab74db69 in bgp_graceful_restart bgpd/bgp_vty.c:3130 #4 0x7fc5539a9584 in cmd_execute_command_real lib/command.c:1002 #5 0x7fc5539a98a3 in cmd_execute_command lib/command.c:1061 #6 0x7fc5539a9dcf in cmd_execute lib/command.c:1227 #7 0x7fc553ae493f in vty_command lib/vty.c:616 #8 0x7fc553ae4e92 in vty_execute lib/vty.c:1379 #9 0x7fc553aedd34 in vtysh_read lib/vty.c:2374 #10 0x7fc553ad8a64 in event_call lib/event.c:1995 #11 0x7fc553a0c429 in frr_run lib/libfrr.c:1232 #12 0x55f3ab57b78d in main bgpd/bgp_main.c:555 #13 0x7fc55342d249 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58 #14 0x7fc55342d304 in __libc_start_main_impl ../csu/libc-start.c:360 #15 0x55f3ab5799a0 in _start (/usr/lib/frr/bgpd+0x2e19a0) 0x60300058d720 is located 16 bytes inside of 24-byte region [0x60300058d710,0x60300058d728) freed by thread T0 here: #0 0x7fc553eb76a8 in __interceptor_free ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:52 #1 0x7fc553a2b713 in qfree lib/memory.c:130 #2 0x7fc553a0e50d in listnode_free lib/linklist.c:81 #3 0x7fc553a0e50d in list_delete_node lib/linklist.c:379 #4 0x55f3ab7ae353 in peer_delete bgpd/bgpd.c:2796 #5 0x55f3ab7ae91f in bgp_session_reset bgpd/bgpd.c:141 #6 0x55f3ab62ab17 in bgp_gr_update_mode_of_all_peers bgpd/bgp_fsm.c:2752 #7 0x55f3ab62ab17 in bgp_gr_update_all bgpd/bgp_fsm.c:2779 #8 0x55f3ab73557e in bgp_inst_gr_config_vty bgpd/bgp_vty.c:3037 #9 0x55f3ab74db69 in bgp_graceful_restart bgpd/bgp_vty.c:3130 #10 0x7fc5539a9584 in cmd_execute_command_real lib/command.c:1002 #11 0x7fc5539a98a3 in cmd_execute_command lib/command.c:1061 #12 0x7fc5539a9dcf in cmd_execute lib/command.c:1227 #13 0x7fc553ae493f in vty_command lib/vty.c:616 #14 0x7fc553ae4e92 in vty_execute lib/vty.c:1379 #15 0x7fc553aedd34 in vtysh_read lib/vty.c:2374 #16 0x7fc553ad8a64 in event_call lib/event.c:1995 #17 0x7fc553a0c429 in frr_run lib/libfrr.c:1232 #18 0x55f3ab57b78d in main bgpd/bgp_main.c:555 #19 0x7fc55342d249 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58 previously allocated by thread T0 here: #0 0x7fc553eb83b7 in __interceptor_calloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:77 #1 0x7fc553a2ae20 in qcalloc lib/memory.c:105 #2 0x7fc553a0d056 in listnode_new lib/linklist.c:71 #3 0x7fc553a0d85b in listnode_add_sort lib/linklist.c:197 #4 0x55f3ab7baec4 in peer_create bgpd/bgpd.c:1996 #5 0x55f3ab65be8b in bgp_accept bgpd/bgp_network.c:604 #6 0x7fc553ad8a64 in event_call lib/event.c:1995 #7 0x7fc553a0c429 in frr_run lib/libfrr.c:1232 #8 0x55f3ab57b78d in main bgpd/bgp_main.c:555 #9 0x7fc55342d249 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58 ``` Signed-off-by: Donatas Abraitis --- bgpd/bgp_fsm.c | 2 +- bgpd/bgpd.c | 2 +- bgpd/bgpd.h | 2 ++ 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index 1eeb141155..98ebf51385 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -2749,7 +2749,7 @@ static void bgp_gr_update_mode_of_all_peers(struct bgp *bgp, bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); else - bgp_session_reset(peer); + bgp_session_reset_safe(peer, &nnode); } } diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index b32a4640f0..44cd24565a 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -149,7 +149,7 @@ void bgp_session_reset(struct peer *peer) * during walk of peer list, we would end up accessing the freed next * node. This function moves the next node along. */ -static void bgp_session_reset_safe(struct peer *peer, struct listnode **nnode) +void bgp_session_reset_safe(struct peer *peer, struct listnode **nnode) { struct listnode *n; struct peer *npeer; diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 6e6358bac7..b733be9f0d 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -2858,6 +2858,8 @@ extern bool bgp_path_attribute_treat_as_withdraw(struct peer *peer, char *buf, extern void srv6_function_free(struct bgp_srv6_function *func); +extern void bgp_session_reset_safe(struct peer *peer, struct listnode **nnode); + #ifdef _FRR_ATTRIBUTE_PRINTFRR /* clang-format off */ #pragma FRR printfrr_ext "%pBP" (struct peer *) From 2419fc510499ec1a4a4ec9f171030fa29e2cdc48 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Wed, 31 Jul 2024 13:20:59 +0300 Subject: [PATCH 263/347] bgpd: Show which AFI is affected when prefix-list is not found When the prefix-list is not found, show which AFI is the real one we are looking for. E.g.: looking at this output is not clear: ``` [RYF1Z-ZKDRS] route_match_address_prefix_list: Prefix List p1 specified does not exist defaulting to NO_MATCH ``` route_match_address_prefix_list() is called by route_match_ipv6_address_prefix_list(), and route_match_ip_address_prefix_list(). Signed-off-by: Donatas Abraitis --- bgpd/bgp_routemap.c | 5 ++--- zebra/zebra_routemap.c | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 97ae92c899..3ba368aaf7 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -680,9 +680,8 @@ route_match_address_prefix_list(void *rule, afi_t afi, plist = prefix_list_lookup(afi, (char *)rule); if (plist == NULL) { if (unlikely(CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP_DETAIL))) - zlog_debug( - "%s: Prefix List %s specified does not exist defaulting to NO_MATCH", - __func__, (char *)rule); + zlog_debug("%s: Prefix List %s (%s) specified does not exist defaulting to NO_MATCH", + __func__, (char *)rule, afi2str(afi)); return RMAP_NOMATCH; } diff --git a/zebra/zebra_routemap.c b/zebra/zebra_routemap.c index c1ec5067d9..46afbcecfa 100644 --- a/zebra/zebra_routemap.c +++ b/zebra/zebra_routemap.c @@ -650,9 +650,8 @@ route_match_address_prefix_list(void *rule, const struct prefix *prefix, plist = prefix_list_lookup(afi, (char *)rule); if (plist == NULL) { if (unlikely(CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP_DETAIL))) - zlog_debug( - "%s: Prefix List %s specified does not exist defaulting to NO_MATCH", - __func__, (char *)rule); + zlog_debug("%s: Prefix List %s (%s) specified does not exist defaulting to NO_MATCH", + __func__, (char *)rule, afi2str(afi)); return RMAP_NOMATCH; } From 05e915984c641d59b4d4b0e83c1f301de4cba460 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Sun, 21 Jul 2024 09:46:58 -0700 Subject: [PATCH 264/347] lib: remove unused vector_copy() Not used anywhere in FRR, kill it. Signed-off-by: David Lamparter --- lib/vector.c | 16 ---------------- lib/vector.h | 1 - 2 files changed, 17 deletions(-) diff --git a/lib/vector.c b/lib/vector.c index 60d383101a..16b45254cb 100644 --- a/lib/vector.c +++ b/lib/vector.c @@ -34,22 +34,6 @@ void vector_free(vector v) XFREE(MTYPE_VECTOR, v); } -vector vector_copy(vector v) -{ - unsigned int size; - vector new = XCALLOC(MTYPE_VECTOR, sizeof(struct _vector)); - - new->active = v->active; - new->alloced = v->alloced; - new->count = v->count; - - size = sizeof(void *) * (v->alloced); - new->index = XCALLOC(MTYPE_VECTOR_INDEX, size); - memcpy(new->index, v->index, size); - - return new; -} - /* Check assigned index, and if it runs short double index pointer */ void vector_ensure(vector v, unsigned int num) { diff --git a/lib/vector.h b/lib/vector.h index fcbc13257a..534def4f37 100644 --- a/lib/vector.h +++ b/lib/vector.h @@ -51,7 +51,6 @@ static inline unsigned int vector_count(vector v) } extern void vector_free(vector v); -extern vector vector_copy(vector v); extern void *vector_lookup(vector, unsigned int); extern void *vector_lookup_ensure(vector, unsigned int); From 0bf664527d003cb3670529f0609d51ce38bcf0ab Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Sat, 20 Jul 2024 18:28:53 -0700 Subject: [PATCH 265/347] lib: allow static/pre-initialized vectors Use alloced=0 to indicate that the array used in a vector is not in fact dynamically allocated memory (yet). Signed-off-by: David Lamparter --- lib/vector.c | 35 +++++++++++++++++++++++++---------- lib/vector.h | 21 +++++++++++++++++++-- 2 files changed, 44 insertions(+), 12 deletions(-) diff --git a/lib/vector.c b/lib/vector.c index 16b45254cb..0636154960 100644 --- a/lib/vector.c +++ b/lib/vector.c @@ -24,29 +24,44 @@ vector vector_init(unsigned int size) v->alloced = size; v->active = 0; v->count = 0; + v->dynamic = true; v->index = XCALLOC(MTYPE_VECTOR_INDEX, sizeof(void *) * size); return v; } void vector_free(vector v) { - XFREE(MTYPE_VECTOR_INDEX, v->index); - XFREE(MTYPE_VECTOR, v); + if (v->alloced) + XFREE(MTYPE_VECTOR_INDEX, v->index); + if (v->dynamic) + XFREE(MTYPE_VECTOR, v); } -/* Check assigned index, and if it runs short double index pointer */ +/* resize vector to a minimum of num + * may resize larger to avoid excessive realloc overhead + */ void vector_ensure(vector v, unsigned int num) { + unsigned int newsz; + if (v->alloced > num) return; - v->index = XREALLOC(MTYPE_VECTOR_INDEX, v->index, - sizeof(void *) * (v->alloced * 2)); - memset(&v->index[v->alloced], 0, sizeof(void *) * v->alloced); - v->alloced *= 2; + newsz = MAX(v->active * 2, num + 1); + + if (!v->alloced && v->index) { + /* currently using global variable, not malloc'd memory */ + void **orig_index = v->index; - if (v->alloced <= num) - vector_ensure(v, num); + v->index = XMALLOC(MTYPE_VECTOR_INDEX, sizeof(void *) * newsz); + memcpy(v->index, orig_index, v->active * sizeof(void *)); + v->alloced = v->active; + } else + v->index = XREALLOC(MTYPE_VECTOR_INDEX, v->index, + sizeof(void *) * newsz); + + memset(&v->index[v->alloced], 0, sizeof(void *) * (newsz - v->alloced)); + v->alloced = newsz; } /* This function only returns next empty slot index. It dose not mean @@ -124,7 +139,7 @@ void *vector_lookup_ensure(vector v, unsigned int i) /* Unset value at specified index slot. */ void vector_unset(vector v, unsigned int i) { - if (i >= v->alloced) + if (i >= v->active) return; if (v->index[i]) diff --git a/lib/vector.h b/lib/vector.h index 534def4f37..ae05d4d3e0 100644 --- a/lib/vector.h +++ b/lib/vector.h @@ -15,9 +15,26 @@ extern "C" { /* struct for vector */ struct _vector { - unsigned int active; /* number of active slots */ - unsigned int alloced; /* number of allocated slot */ + /* active: index of last non-NULL item (+1) + * count: number of non-NULL items (+1) + * + * the two will be different if a slot is set to NULL (without pulling + * up later items in the array). Whether this happens depends on + * which vector functions are used. If no empty slots are used, the + * two fields will be identical. + * + * alloced: size of array pointed to by index. If this is 0, index + * points at a global variable rather than a malloc'd bit of memory. + * The vector code will convert to malloc'd memory if necessary to + * perform updates. + */ + unsigned int active; + unsigned int alloced; unsigned int count; + + /* whether struct _vector itself is dynamically allocated */ + bool dynamic; + void **index; /* index to data */ }; typedef struct _vector *vector; From 67a76894b70f73c62b7eb2d05a02ef282c16ec82 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Sun, 21 Jul 2024 12:19:44 -0700 Subject: [PATCH 266/347] tools/checkpatch: recognize `+` as unary operator Allow using "+1" when meaningful (i.e. cmd_graph_merge wants -1 or +1) Signed-off-by: David Lamparter --- tools/checkpatch.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/checkpatch.pl b/tools/checkpatch.pl index 3e7abeda39..2c773f7fbc 100755 --- a/tools/checkpatch.pl +++ b/tools/checkpatch.pl @@ -5150,7 +5150,7 @@ sub process { # none after. May be left adjacent to another # unary operator, or a cast } elsif ($op eq '!' || $op eq '~' || - $opv eq '*U' || $opv eq '-U' || + $opv eq '*U' || $opv eq '-U' || $opv eq '+U' || $opv eq '&U' || $opv eq '&&U') { if ($ctx !~ /[WEBC]x./ && $ca !~ /(?:\)|!|~|\*|-|\&|\||\+\+|\-\-|\{)$/) { if (ERROR("SPACING", From cf37c79f3132285a7d02f54573b1cfa85cb6b919 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Sat, 20 Jul 2024 15:29:59 -0700 Subject: [PATCH 267/347] lib/clippy: dynamically wrap graph nodes The number of nodes in a graph will change as soon as cmd_graph_merge is supported as an operation, therefore size this dynamically. Signed-off-by: David Lamparter --- lib/command_py.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/lib/command_py.c b/lib/command_py.c index f8abcf8ef4..ccdbfc5f8e 100644 --- a/lib/command_py.c +++ b/lib/command_py.c @@ -68,6 +68,7 @@ struct wrap_graph { char *definition; struct graph *graph; + size_t n_nodewrappers; struct wrap_graph_node **nodewrappers; }; @@ -138,6 +139,8 @@ static PyMethodDef methods_graph_node[] = { static void graph_node_wrap_free(void *arg) { struct wrap_graph_node *wrap = arg; + + assert(wrap->idx < wrap->wgraph->n_nodewrappers); wrap->wgraph->nodewrappers[wrap->idx] = NULL; Py_DECREF(wrap->wgraph); } @@ -166,6 +169,15 @@ static PyObject *graph_to_pyobj(struct wrap_graph *wgraph, PyErr_SetString(PyExc_ValueError, "cannot find node in graph"); return NULL; } + if (i >= wgraph->n_nodewrappers) { + wgraph->nodewrappers = + realloc(wgraph->nodewrappers, + (i + 1) * sizeof(wgraph->nodewrappers[0])); + memset(wgraph->nodewrappers + wgraph->n_nodewrappers, 0, + sizeof(wgraph->nodewrappers[0]) * + (i + 1 - wgraph->n_nodewrappers)); + wgraph->n_nodewrappers = i + 1; + } if (wgraph->nodewrappers[i]) { PyObject *obj = (PyObject *)wgraph->nodewrappers[i]; Py_INCREF(obj); @@ -298,8 +310,6 @@ static PyObject *graph_parse(PyTypeObject *type, PyObject *args, PyObject *kwds) gwrap->graph = graph; gwrap->definition = strdup(def); - gwrap->nodewrappers = calloc(vector_active(graph->nodes), - sizeof(gwrap->nodewrappers[0])); return (PyObject *)gwrap; } From 7fb8729a32e53a11f5cb0c5c741a35c59f33a273 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Sat, 20 Jul 2024 15:30:09 -0700 Subject: [PATCH 268/347] lib/clippy: allow creating empty graph When merging graphs, it makes sense to allow starting with an empty one. Signed-off-by: David Lamparter --- lib/command_py.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/lib/command_py.c b/lib/command_py.c index ccdbfc5f8e..ada0f0d386 100644 --- a/lib/command_py.c +++ b/lib/command_py.c @@ -296,7 +296,7 @@ static PyObject *graph_parse(PyTypeObject *type, PyObject *args, PyObject *kwds) if (!gwrap) return NULL; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|s", (char **)kwnames, + if (!PyArg_ParseTupleAndKeywords(args, kwds, "z|s", (char **)kwnames, &def, &doc)) return NULL; @@ -304,12 +304,18 @@ static PyObject *graph_parse(PyTypeObject *type, PyObject *args, PyObject *kwds) struct cmd_token *token = cmd_token_new(START_TKN, 0, NULL, NULL); graph_new_node(graph, token, (void (*)(void *)) & cmd_token_del); - struct cmd_element cmd = {.string = def, .doc = doc}; - cmd_graph_parse(graph, &cmd); - cmd_graph_names(graph); + if (def) { + struct cmd_element cmd = { .string = def, .doc = doc }; + + cmd_graph_parse(graph, &cmd); + cmd_graph_names(graph); + + gwrap->definition = strdup(def); + } else { + gwrap->definition = strdup("NULL"); + } gwrap->graph = graph; - gwrap->definition = strdup(def); return (PyObject *)gwrap; } From 34a4f858b7823c07fd1d7faa385f6a692136fc2f Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Sat, 20 Jul 2024 15:36:20 -0700 Subject: [PATCH 269/347] lib/clippy: wrap cmd_graph_merge via Graph.merge() Export cmd_graph_merge() to python code via graph1.merge(graph2). Signed-off-by: David Lamparter --- lib/command_py.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/lib/command_py.c b/lib/command_py.c index ada0f0d386..82ca5a8ffc 100644 --- a/lib/command_py.c +++ b/lib/command_py.c @@ -258,9 +258,13 @@ static PyObject *graph_first(PyObject *self, PyObject *args) return graph_to_pyobj(gwrap, gn); }; +static PyObject *graph_merge(PyObject *self, PyObject *args); + static PyMethodDef methods_graph[] = { - {"first", graph_first, METH_NOARGS, "first graph node"}, - {}}; + { "first", graph_first, METH_NOARGS, "first graph node" }, + { "merge", graph_merge, METH_VARARGS, "merge graphs" }, + {} +}; static PyObject *graph_parse(PyTypeObject *type, PyObject *args, PyObject *kwds); @@ -285,6 +289,20 @@ static PyTypeObject typeobj_graph = { .tp_methods = methods_graph, }; +static PyObject *graph_merge(PyObject *self, PyObject *args) +{ + PyObject *py_other; + struct wrap_graph *gwrap = (struct wrap_graph *)self; + struct wrap_graph *gother; + + if (!PyArg_ParseTuple(args, "O!", &typeobj_graph, &py_other)) + return NULL; + + gother = (struct wrap_graph *)py_other; + cmd_graph_merge(gwrap->graph, gother->graph, +1); + Py_RETURN_NONE; +} + /* top call / entrypoint for python code */ static PyObject *graph_parse(PyTypeObject *type, PyObject *args, PyObject *kwds) { From f85e58af12ae3ebff84262af6b7d15a137875881 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Sat, 20 Jul 2024 15:55:43 -0700 Subject: [PATCH 270/347] lib/clippy: add a __repr__ for graph nodes Make it a little easier to work on python code using this wrapper. Signed-off-by: David Lamparter --- lib/command_py.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/lib/command_py.c b/lib/command_py.c index 82ca5a8ffc..a80925d2d9 100644 --- a/lib/command_py.c +++ b/lib/command_py.c @@ -145,6 +145,14 @@ static void graph_node_wrap_free(void *arg) Py_DECREF(wrap->wgraph); } +static PyObject *repr_graph_node(PyObject *arg) +{ + struct wrap_graph_node *wrap = (struct wrap_graph_node *)arg; + + return PyUnicode_FromFormat("<_clippy.GraphNode %p [%zu] %s>", + wrap->node, wrap->idx, wrap->type); +} + static PyTypeObject typeobj_graph_node = { PyVarObject_HEAD_INIT(NULL, 0).tp_name = "_clippy.GraphNode", .tp_basicsize = sizeof(struct wrap_graph_node), @@ -154,6 +162,7 @@ static PyTypeObject typeobj_graph_node = { .tp_free = graph_node_wrap_free, .tp_members = members_graph_node, .tp_methods = methods_graph_node, + .tp_repr = repr_graph_node, }; static PyObject *graph_to_pyobj(struct wrap_graph *wgraph, From 8511f39987e1ee3438d7ff836e7edf7f619667d8 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Sat, 20 Jul 2024 16:08:04 -0700 Subject: [PATCH 271/347] lib/clippy: allow accessing graph nodes by index Add len(graph) and graph[i] wrappers to access arbitrary nodes in a graph. Signed-off-by: David Lamparter --- lib/command_py.c | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/lib/command_py.c b/lib/command_py.c index a80925d2d9..6c051f55cd 100644 --- a/lib/command_py.c +++ b/lib/command_py.c @@ -29,6 +29,7 @@ struct wrap_graph; static PyObject *graph_to_pyobj(struct wrap_graph *graph, struct graph_node *gn); +static PyObject *graph_to_pyobj_idx(struct wrap_graph *wgraph, size_t i); /* * nodes are wrapped as follows: @@ -168,7 +169,6 @@ static PyTypeObject typeobj_graph_node = { static PyObject *graph_to_pyobj(struct wrap_graph *wgraph, struct graph_node *gn) { - struct wrap_graph_node *wrap; size_t i; for (i = 0; i < vector_active(wgraph->graph->nodes); i++) @@ -178,6 +178,15 @@ static PyObject *graph_to_pyobj(struct wrap_graph *wgraph, PyErr_SetString(PyExc_ValueError, "cannot find node in graph"); return NULL; } + + return graph_to_pyobj_idx(wgraph, i); +} + +static PyObject *graph_to_pyobj_idx(struct wrap_graph *wgraph, size_t i) +{ + struct wrap_graph_node *wrap; + struct graph_node *gn = vector_slot(wgraph->graph->nodes, i); + if (i >= wgraph->n_nodewrappers) { wgraph->nodewrappers = realloc(wgraph->nodewrappers, @@ -287,6 +296,30 @@ static void graph_wrap_free(void *arg) free(wgraph->definition); } +static Py_ssize_t graph_length(PyObject *self) +{ + struct wrap_graph *gwrap = (struct wrap_graph *)self; + + return vector_active(gwrap->graph->nodes); +} + +static PyObject *graph_item(PyObject *self, Py_ssize_t idx) +{ + struct wrap_graph *gwrap = (struct wrap_graph *)self; + + if (idx >= vector_active(gwrap->graph->nodes)) + return PyErr_Format(PyExc_IndexError, + "index %zd past graph size %u", idx, + vector_active(gwrap->graph->nodes)); + + return graph_to_pyobj_idx(gwrap, idx); +} + +static PySequenceMethods seq_graph = { + .sq_length = graph_length, + .sq_item = graph_item, +}; + static PyTypeObject typeobj_graph = { PyVarObject_HEAD_INIT(NULL, 0).tp_name = "_clippy.Graph", .tp_basicsize = sizeof(struct wrap_graph), @@ -296,6 +329,7 @@ static PyTypeObject typeobj_graph = { .tp_free = graph_wrap_free, .tp_members = members_graph, .tp_methods = methods_graph, + .tp_as_sequence = &seq_graph, }; static PyObject *graph_merge(PyObject *self, PyObject *args) From 3c1556f386a6c5866e1b5352571e44ed3e22da76 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Sat, 20 Jul 2024 16:19:29 -0700 Subject: [PATCH 272/347] lib/clippy: expose graph nodes' back pointers There's a wrapper for nodes' outgoing pointers, but not incoming yet. Signed-off-by: David Lamparter --- lib/command_py.c | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/lib/command_py.c b/lib/command_py.c index 6c051f55cd..411caa52d6 100644 --- a/lib/command_py.c +++ b/lib/command_py.c @@ -109,6 +109,24 @@ static PyObject *graph_node_next(PyObject *self, PyObject *args) pylist = PyList_New(vector_active(wrap->node->to)); for (size_t i = 0; i < vector_active(wrap->node->to); i++) { struct graph_node *gn = vector_slot(wrap->node->to, i); + + PyList_SetItem(pylist, i, graph_to_pyobj(wrap->wgraph, gn)); + } + return pylist; +}; + +static PyObject *graph_node_prev(PyObject *self, PyObject *args) +{ + struct wrap_graph_node *wrap = (struct wrap_graph_node *)self; + PyObject *pylist; + + if (wrap->node->data && + ((struct cmd_token *)wrap->node->data)->type == START_TKN) + return PyList_New(0); + pylist = PyList_New(vector_active(wrap->node->from)); + for (size_t i = 0; i < vector_active(wrap->node->from); i++) { + struct graph_node *gn = vector_slot(wrap->node->from, i); + PyList_SetItem(pylist, i, graph_to_pyobj(wrap->wgraph, gn)); } return pylist; @@ -133,9 +151,11 @@ static PyObject *graph_node_join(PyObject *self, PyObject *args) }; static PyMethodDef methods_graph_node[] = { - {"next", graph_node_next, METH_NOARGS, "outbound graph edge list"}, - {"join", graph_node_join, METH_NOARGS, "outbound join node"}, - {}}; + { "next", graph_node_next, METH_NOARGS, "outbound graph edge list" }, + { "prev", graph_node_prev, METH_NOARGS, "inbound graph edge list" }, + { "join", graph_node_join, METH_NOARGS, "outbound join node" }, + {} +}; static void graph_node_wrap_free(void *arg) { From e2344206ca26169bbc64b16a838856253013c1df Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Sat, 20 Jul 2024 18:29:11 -0700 Subject: [PATCH 273/347] lib/clippy: expose JOIN_TKN's fork node FORK_TKN's join node is already exposed, mirror to expose JOIN_TKN's fork node. (contains minor cleanup to make checkpatch.pl shut up) Signed-off-by: David Lamparter --- lib/command_py.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/lib/command_py.c b/lib/command_py.c index 411caa52d6..99438d4f5a 100644 --- a/lib/command_py.c +++ b/lib/command_py.c @@ -138,22 +138,40 @@ static PyObject *graph_node_prev(PyObject *self, PyObject *args) static PyObject *graph_node_join(PyObject *self, PyObject *args) { struct wrap_graph_node *wrap = (struct wrap_graph_node *)self; + struct cmd_token *tok; if (!wrap->node->data || ((struct cmd_token *)wrap->node->data)->type == END_TKN) Py_RETURN_NONE; - struct cmd_token *tok = wrap->node->data; + tok = wrap->node->data; if (tok->type != FORK_TKN) Py_RETURN_NONE; return graph_to_pyobj(wrap->wgraph, tok->forkjoin); }; +static PyObject *graph_node_fork(PyObject *self, PyObject *args) +{ + struct wrap_graph_node *wrap = (struct wrap_graph_node *)self; + struct cmd_token *tok; + + if (!wrap->node->data || + ((struct cmd_token *)wrap->node->data)->type == END_TKN) + Py_RETURN_NONE; + + tok = wrap->node->data; + if (tok->type != JOIN_TKN) + Py_RETURN_NONE; + + return graph_to_pyobj(wrap->wgraph, tok->forkjoin); +}; + static PyMethodDef methods_graph_node[] = { { "next", graph_node_next, METH_NOARGS, "outbound graph edge list" }, { "prev", graph_node_prev, METH_NOARGS, "inbound graph edge list" }, { "join", graph_node_join, METH_NOARGS, "outbound join node" }, + { "fork", graph_node_fork, METH_NOARGS, "inbound fork node" }, {} }; From cb9d20b712c6b09ee6516f134e44e2a4a7181694 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Sat, 20 Jul 2024 18:29:51 -0700 Subject: [PATCH 274/347] lib/clippy: improve graph node member access Expose all of the struct members of cmd_token, and retrieve them dynamically rather than copying them around. The problem with copying them is that they can change as a result of merge(), and if there is an existing wrapper object around it will not have its copy updated to match. Signed-off-by: David Lamparter --- lib/command_py.c | 91 +++++++++++++++++++++++++++++++++++++----------- 1 file changed, 70 insertions(+), 21 deletions(-) diff --git a/lib/command_py.c b/lib/command_py.c index 99438d4f5a..e459071426 100644 --- a/lib/command_py.c +++ b/lib/command_py.c @@ -45,13 +45,6 @@ struct wrap_graph_node { bool allowrepeat; const char *type; - bool deprecated; - bool hidden; - const char *text; - const char *desc; - const char *varname; - long long min, max; - struct graph_node *node; struct wrap_graph *wgraph; size_t idx; @@ -86,11 +79,75 @@ static PyObject *refuse_new(PyTypeObject *type, PyObject *args, PyObject *kwds) READONLY, (char *)#name " (" #type ")" \ } static PyMemberDef members_graph_node[] = { - member(allowrepeat, T_BOOL), member(type, T_STRING), - member(deprecated, T_BOOL), member(hidden, T_BOOL), - member(text, T_STRING), member(desc, T_STRING), - member(min, T_LONGLONG), member(max, T_LONGLONG), - member(varname, T_STRING), {}, + /* clang-format off */ + member(type, T_STRING), + member(idx, T_ULONG), + {}, + /* clang-format on */ +}; +#undef member + +static PyObject *graph_node_get_str(PyObject *self, void *poffset) +{ + struct wrap_graph_node *wrap = (struct wrap_graph_node *)self; + void *offset = (char *)wrap->node->data + (ptrdiff_t)poffset; + const char *val = *(const char **)offset; + + if (!val) + Py_RETURN_NONE; + return PyUnicode_FromString(val); +} + +static PyObject *graph_node_get_bool(PyObject *self, void *poffset) +{ + struct wrap_graph_node *wrap = (struct wrap_graph_node *)self; + void *offset = (char *)wrap->node->data + (ptrdiff_t)poffset; + bool val = *(bool *)offset; + + return PyBool_FromLong(val); +} + +static PyObject *graph_node_get_ll(PyObject *self, void *poffset) +{ + struct wrap_graph_node *wrap = (struct wrap_graph_node *)self; + void *offset = (char *)wrap->node->data + (ptrdiff_t)poffset; + long long val = *(long long *)offset; + + return PyLong_FromLongLong(val); +} + +static PyObject *graph_node_get_u8(PyObject *self, void *poffset) +{ + struct wrap_graph_node *wrap = (struct wrap_graph_node *)self; + void *offset = (char *)wrap->node->data + (ptrdiff_t)poffset; + uint8_t val = *(uint8_t *)offset; + + return PyLong_FromUnsignedLong(val); +} + +/* clang-format off */ +#define member(name, variant) \ + { \ + (char *)#name, \ + graph_node_get_##variant, \ + NULL, \ + (char *)#name " (" #variant ")", \ + (void *)offsetof(struct cmd_token, name), \ + } +/* clang-format on */ + +static PyGetSetDef getset_graph_node[] = { + /* clang-format off */ + member(attr, u8), + member(allowrepeat, bool), + member(varname_src, u8), + member(text, str), + member(desc, str), + member(min, ll), + member(max, ll), + member(varname, str), + {}, + /* clang-format on */ }; #undef member @@ -200,6 +257,7 @@ static PyTypeObject typeobj_graph_node = { .tp_new = refuse_new, .tp_free = graph_node_wrap_free, .tp_members = members_graph_node, + .tp_getset = getset_graph_node, .tp_methods = methods_graph_node, .tp_repr = repr_graph_node, }; @@ -281,15 +339,6 @@ static PyObject *graph_to_pyobj_idx(struct wrap_graph *wgraph, size_t i) default: wrap->type = "???"; } - - wrap->deprecated = !!(tok->attr & CMD_ATTR_DEPRECATED); - wrap->hidden = !!(tok->attr & CMD_ATTR_HIDDEN); - wrap->text = tok->text; - wrap->desc = tok->desc; - wrap->varname = tok->varname; - wrap->min = tok->min; - wrap->max = tok->max; - wrap->allowrepeat = tok->allowrepeat; } return (PyObject *)wrap; From ece3132471a1f361b82dde47bbf8cbf9675a12a8 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Sat, 20 Jul 2024 18:28:35 -0700 Subject: [PATCH 275/347] lib/clippy: add `CMD_ELEMENT_TKN` The command graph has its tail end nodes pointing at the `struct cmd_element` rather than a `struct cmd_token`. This is a bit weird to begin with, but becomes very annoying for the python bindings where there is just no `struct cmd_element`. Create a `CMD_ELEMENT_TKN` type for `cmd_token` instead, and replace the tail end token in the python bindings with an instance of that. Signed-off-by: David Lamparter --- lib/command_graph.c | 3 +++ lib/command_graph.h | 3 +++ lib/command_py.c | 21 +++++++++++++++------ 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/lib/command_graph.c b/lib/command_graph.c index ff3c11db69..20ab6b321b 100644 --- a/lib/command_graph.c +++ b/lib/command_graph.c @@ -267,6 +267,9 @@ static bool cmd_nodes_equal(struct graph_node *ga, struct graph_node *gb) case NEG_ONLY_TKN: case WORD_TKN: case ASNUM_TKN: +#ifdef BUILDING_CLIPPY + case CMD_ELEMENT_TKN: +#endif return true; } diff --git a/lib/command_graph.h b/lib/command_graph.h index 25aa47db7b..313c97fe87 100644 --- a/lib/command_graph.h +++ b/lib/command_graph.h @@ -54,6 +54,9 @@ enum cmd_token_type { END_TKN, // last token in line NEG_ONLY_TKN, // filter token, match if "no ..." command +#ifdef BUILDING_CLIPPY + CMD_ELEMENT_TKN, // python bindings only +#endif SPECIAL_TKN = FORK_TKN, }; /* clang-format on */ diff --git a/lib/command_py.c b/lib/command_py.c index e459071426..a77adcd7dc 100644 --- a/lib/command_py.c +++ b/lib/command_py.c @@ -160,8 +160,8 @@ static PyObject *graph_node_next(PyObject *self, PyObject *args) struct wrap_graph_node *wrap = (struct wrap_graph_node *)self; PyObject *pylist; - if (wrap->node->data - && ((struct cmd_token *)wrap->node->data)->type == END_TKN) + if (wrap->node->data && + ((struct cmd_token *)wrap->node->data)->type == CMD_ELEMENT_TKN) return PyList_New(0); pylist = PyList_New(vector_active(wrap->node->to)); for (size_t i = 0; i < vector_active(wrap->node->to); i++) { @@ -335,6 +335,7 @@ static PyObject *graph_to_pyobj_idx(struct wrap_graph *wgraph, size_t i) item(START_TKN); item(END_TKN); item(NEG_ONLY_TKN); + item(CMD_ELEMENT_TKN); #undef item default: wrap->type = "???"; @@ -436,16 +437,16 @@ static PyObject *graph_merge(PyObject *self, PyObject *args) /* top call / entrypoint for python code */ static PyObject *graph_parse(PyTypeObject *type, PyObject *args, PyObject *kwds) { - const char *def, *doc = NULL; + const char *def, *doc = NULL, *name = NULL; struct wrap_graph *gwrap; - static const char *kwnames[] = {"cmddef", "doc", NULL}; + static const char *const kwnames[] = { "cmddef", "doc", "name", NULL }; gwrap = (struct wrap_graph *)typeobj_graph.tp_alloc(&typeobj_graph, 0); if (!gwrap) return NULL; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "z|s", (char **)kwnames, - &def, &doc)) + if (!PyArg_ParseTupleAndKeywords(args, kwds, "z|ss", (char **)kwnames, + &def, &doc, &name)) return NULL; struct graph *graph = graph_new(); @@ -454,10 +455,18 @@ static PyObject *graph_parse(PyTypeObject *type, PyObject *args, PyObject *kwds) if (def) { struct cmd_element cmd = { .string = def, .doc = doc }; + struct graph_node *last; cmd_graph_parse(graph, &cmd); cmd_graph_names(graph); + last = vector_slot(graph->nodes, + vector_active(graph->nodes) - 1); + assert(last->data == &cmd); + + last->data = cmd_token_new(CMD_ELEMENT_TKN, 0, name, def); + last->del = (void (*)(void *))cmd_token_del; + gwrap->definition = strdup(def); } else { gwrap->definition = strdup("NULL"); From e26c580588b3689463c76aa96888147e53a48885 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Sat, 20 Jul 2024 18:30:31 -0700 Subject: [PATCH 276/347] vtysh: de-conditionalize and reorder install_node There is entirely no point to these being conditional. And pull them up so the upcoming pre-parse code can work on a clean slate. Signed-off-by: David Lamparter --- lib/command.h | 4 + vtysh/vtysh.c | 182 ++++++++++++++++++--------------------------- vtysh/vtysh_main.c | 1 - 3 files changed, 78 insertions(+), 109 deletions(-) diff --git a/lib/command.h b/lib/command.h index 57e3b9cda0..f364f1e8fa 100644 --- a/lib/command.h +++ b/lib/command.h @@ -252,6 +252,8 @@ struct cmd_node { /* Argc max counts. */ #define CMD_ARGC_MAX 256 +/* clang-format off */ + /* helper defines for end-user DEFUN* macros */ #define DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, attrs, dnum) \ static const struct cmd_element cmdname = { \ @@ -376,6 +378,8 @@ struct cmd_node { #define ALIAS_YANG(funcname, cmdname, cmdstr, helpstr) \ ALIAS_ATTR(funcname, cmdname, cmdstr, helpstr, CMD_ATTR_YANG) +/* clang-format on */ + /* Some macroes */ /* diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index e657aa8af0..c43e1909e3 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -1161,14 +1161,12 @@ static char **new_completion(const char *text, int start, int end) } /* Vty node structures. */ -#ifdef HAVE_BGPD static struct cmd_node bgp_node = { .name = "bgp", .node = BGP_NODE, .parent_node = CONFIG_NODE, .prompt = "%s(config-router)# ", }; -#endif /* HAVE_BGPD */ static struct cmd_node rip_node = { .name = "rip", @@ -1177,7 +1175,6 @@ static struct cmd_node rip_node = { .prompt = "%s(config-router)# ", }; -#ifdef HAVE_ISISD static struct cmd_node isis_node = { .name = "isis", .node = ISIS_NODE, @@ -1205,16 +1202,13 @@ static struct cmd_node isis_srv6_node_msd_node = { .parent_node = ISIS_SRV6_NODE, .prompt = "%s(config-router-srv6-node-msd)# ", }; -#endif /* HAVE_ISISD */ -#ifdef HAVE_FABRICD static struct cmd_node openfabric_node = { .name = "openfabric", .node = OPENFABRIC_NODE, .parent_node = CONFIG_NODE, .prompt = "%s(config-router)# ", }; -#endif /* HAVE_FABRICD */ static struct cmd_node interface_node = { .name = "interface", @@ -1237,7 +1231,6 @@ static struct cmd_node segment_routing_node = { .prompt = "%s(config-sr)# ", }; -#if defined(HAVE_PATHD) static struct cmd_node sr_traffic_eng_node = { .name = "sr traffic-eng", .node = SR_TRAFFIC_ENG_NODE, @@ -1293,7 +1286,6 @@ static struct cmd_node pcep_pce_config_node = { .parent_node = PCEP_NODE, .prompt = "%s(pcep-sr-te-pcep-pce-config)# ", }; -#endif /* HAVE_PATHD */ static struct cmd_node vrf_node = { .name = "vrf", @@ -1365,14 +1357,12 @@ static struct cmd_node srv6_sid_format_uncompressed_f4024_node = { .prompt = "%s(config-srv6-format)# " }; -#ifdef HAVE_PBRD static struct cmd_node pbr_map_node = { .name = "pbr-map", .node = PBRMAP_NODE, .parent_node = CONFIG_NODE, .prompt = "%s(config-pbr-map)# ", }; -#endif /* HAVE_PBRD */ static struct cmd_node zebra_node = { .name = "zebra", @@ -1381,7 +1371,6 @@ static struct cmd_node zebra_node = { .prompt = "%s(config-router)# ", }; -#ifdef HAVE_BGPD static struct cmd_node bgp_vpnv4_node = { .name = "bgp vpnv4", .node = BGP_VPNV4_NODE, @@ -1477,7 +1466,6 @@ static struct cmd_node bgp_ipv6l_node = { .no_xpath = true, }; -#ifdef ENABLE_BGP_VNC static struct cmd_node bgp_vnc_defaults_node = { .name = "bgp vnc defaults", .node = BGP_VNC_DEFAULTS_NODE, @@ -1505,7 +1493,6 @@ static struct cmd_node bgp_vnc_l2_group_node = { .parent_node = BGP_NODE, .prompt = "%s(config-router-vnc-l2-group)# ", }; -#endif /* ENABLE_BGP_VNC */ static struct cmd_node bmp_node = { .name = "bmp", @@ -1520,34 +1507,27 @@ static struct cmd_node bgp_srv6_node = { .parent_node = BGP_NODE, .prompt = "%s(config-router-srv6)# ", }; -#endif /* HAVE_BGPD */ -#ifdef HAVE_OSPFD static struct cmd_node ospf_node = { .name = "ospf", .node = OSPF_NODE, .parent_node = CONFIG_NODE, .prompt = "%s(config-router)# ", }; -#endif /* HAVE_OSPFD */ -#ifdef HAVE_EIGRPD static struct cmd_node eigrp_node = { .name = "eigrp", .node = EIGRP_NODE, .parent_node = CONFIG_NODE, .prompt = "%s(config-router)# ", }; -#endif /* HAVE_EIGRPD */ -#ifdef HAVE_BABELD static struct cmd_node babel_node = { .name = "babel", .node = BABEL_NODE, .parent_node = CONFIG_NODE, .prompt = "%s(config-router)# ", }; -#endif /* HAVE_BABELD */ static struct cmd_node ripng_node = { .name = "ripng", @@ -1556,16 +1536,13 @@ static struct cmd_node ripng_node = { .prompt = "%s(config-router)# ", }; -#ifdef HAVE_OSPF6D static struct cmd_node ospf6_node = { .name = "ospf6", .node = OSPF6_NODE, .parent_node = CONFIG_NODE, .prompt = "%s(config-ospf6)# ", }; -#endif /* HAVE_OSPF6D */ -#ifdef HAVE_LDPD static struct cmd_node ldp_node = { .name = "ldp", .node = LDP_NODE, @@ -1614,7 +1591,6 @@ static struct cmd_node ldp_pseudowire_node = { .parent_node = LDP_L2VPN_NODE, .prompt = "%s(config-l2vpn-pw)# ", }; -#endif /* HAVE_LDPD */ static struct cmd_node keychain_node = { .name = "keychain", @@ -1637,7 +1613,6 @@ struct cmd_node link_params_node = { .prompt = "%s(config-link-params)# ", }; -#ifdef HAVE_BGPD static struct cmd_node rpki_node = { .name = "rpki", .node = RPKI_NODE, @@ -1652,9 +1627,6 @@ static struct cmd_node rpki_vrf_node = { .prompt = "%s(config-vrf-rpki)# ", }; -#endif /* HAVE_BGPD */ - -#if HAVE_BFDD > 0 static struct cmd_node bfd_node = { .name = "bfd", .node = BFD_NODE, @@ -1675,25 +1647,20 @@ static struct cmd_node bfd_profile_node = { .parent_node = BFD_NODE, .prompt = "%s(config-bfd-profile)# ", }; -#endif /* HAVE_BFDD */ -#ifdef HAVE_PIMD static struct cmd_node pim_node = { .name = "pim", .node = PIM_NODE, .parent_node = CONFIG_NODE, .prompt = "%s(config-pim)# ", }; -#endif /* HAVE_PIMD */ -#ifdef HAVE_PIM6D static struct cmd_node pim6_node = { .name = "pim6", .node = PIM6_NODE, .parent_node = CONFIG_NODE, .prompt = "%s(config-pim6)# ", }; -#endif /* HAVE_PIM6D */ /* Defined in lib/vty.c */ extern struct cmd_node vty_node; @@ -4954,15 +4921,87 @@ void vtysh_init_vty(void) cmd_init(0); cmd_variable_handler_register(vtysh_var_handler); + install_node(&bgp_node); + install_node(&babel_node); + install_node(&bgp_vpnv4_node); + install_node(&bgp_vpnv6_node); + install_node(&bgp_flowspecv4_node); + install_node(&bgp_flowspecv6_node); + install_node(&bgp_ipv4_node); + install_node(&bgp_ipv4m_node); + install_node(&bgp_ipv4l_node); + install_node(&bgp_ipv6_node); + install_node(&bgp_ipv6m_node); + install_node(&bgp_ipv6l_node); + install_node(&bgp_vrf_policy_node); + install_node(&bgp_vnc_defaults_node); + install_node(&bgp_vnc_nve_group_node); + install_node(&bgp_vnc_l2_group_node); + install_node(&bgp_evpn_node); + install_node(&bgp_evpn_vni_node); + install_node(&rpki_node); + install_node(&bmp_node); + install_node(&bgp_srv6_node); + install_node(&rip_node); + install_node(&ripng_node); + install_node(&ospf_node); + install_node(&ospf6_node); + install_node(&ldp_node); + install_node(&ldp_ipv4_node); + install_node(&ldp_ipv6_node); + install_node(&ldp_ipv4_iface_node); + install_node(&ldp_ipv6_iface_node); + install_node(&ldp_l2vpn_node); + install_node(&ldp_pseudowire_node); + install_node(&eigrp_node); + install_node(&isis_node); + install_node(&isis_flex_algo_node); + install_node(&isis_srv6_node); + install_node(&isis_srv6_node_msd_node); + install_node(&openfabric_node); + install_node(&pbr_map_node); + install_node(&bfd_node); + install_node(&bfd_peer_node); + install_node(&bfd_profile_node); + install_node(&segment_routing_node); + install_node(&sr_traffic_eng_node); + install_node(&srte_segment_list_node); + install_node(&srte_policy_node); + install_node(&srte_candidate_dyn_node); + install_node(&pcep_node); + install_node(&pcep_pcc_node); + install_node(&pcep_pce_node); + install_node(&pcep_pce_config_node); + install_node(&keychain_node); + install_node(&keychain_key_node); + install_node(&nh_group_node); + install_node(&zebra_node); + install_node(&interface_node); + install_node(&pim_node); + install_node(&pim6_node); + install_node(&link_params_node); + install_node(&pw_node); + install_node(&vrf_node); + install_node(&rpki_vrf_node); + install_node(&rmap_node); + install_node(&vty_node); + install_node(&srv6_node); + install_node(&srv6_locs_node); + install_node(&srv6_loc_node); + install_node(&srv6_encap_node); + install_node(&srv6_sid_formats_node); + install_node(&srv6_sid_format_usid_f3216_node); + install_node(&srv6_sid_format_uncompressed_f4024_node); + + vtysh_init_cmd(); + /* bgpd */ #ifdef HAVE_BGPD - install_node(&bgp_node); install_element(CONFIG_NODE, &router_bgp_cmd); install_element(BGP_NODE, &vtysh_exit_bgpd_cmd); install_element(BGP_NODE, &vtysh_quit_bgpd_cmd); install_element(BGP_NODE, &vtysh_end_all_cmd); - install_node(&bgp_vpnv4_node); install_element(BGP_NODE, &address_family_ipv4_vpn_cmd); #ifdef KEEP_OLD_VPN_COMMANDS install_element(BGP_NODE, &address_family_vpnv4_cmd); @@ -4972,7 +5011,6 @@ void vtysh_init_vty(void) install_element(BGP_VPNV4_NODE, &vtysh_end_all_cmd); install_element(BGP_VPNV4_NODE, &exit_address_family_cmd); - install_node(&bgp_vpnv6_node); install_element(BGP_NODE, &address_family_ipv6_vpn_cmd); #ifdef KEEP_OLD_VPN_COMMANDS install_element(BGP_NODE, &address_family_vpnv6_cmd); @@ -4982,56 +5020,48 @@ void vtysh_init_vty(void) install_element(BGP_VPNV6_NODE, &vtysh_end_all_cmd); install_element(BGP_VPNV6_NODE, &exit_address_family_cmd); - install_node(&bgp_flowspecv4_node); install_element(BGP_NODE, &address_family_flowspecv4_cmd); install_element(BGP_FLOWSPECV4_NODE, &vtysh_exit_bgpd_cmd); install_element(BGP_FLOWSPECV4_NODE, &vtysh_quit_bgpd_cmd); install_element(BGP_FLOWSPECV4_NODE, &vtysh_end_all_cmd); install_element(BGP_FLOWSPECV4_NODE, &exit_address_family_cmd); - install_node(&bgp_flowspecv6_node); install_element(BGP_NODE, &address_family_flowspecv6_cmd); install_element(BGP_FLOWSPECV6_NODE, &vtysh_exit_bgpd_cmd); install_element(BGP_FLOWSPECV6_NODE, &vtysh_quit_bgpd_cmd); install_element(BGP_FLOWSPECV6_NODE, &vtysh_end_all_cmd); install_element(BGP_FLOWSPECV6_NODE, &exit_address_family_cmd); - install_node(&bgp_ipv4_node); install_element(BGP_NODE, &address_family_ipv4_cmd); install_element(BGP_IPV4_NODE, &vtysh_exit_bgpd_cmd); install_element(BGP_IPV4_NODE, &vtysh_quit_bgpd_cmd); install_element(BGP_IPV4_NODE, &vtysh_end_all_cmd); install_element(BGP_IPV4_NODE, &exit_address_family_cmd); - install_node(&bgp_ipv4m_node); install_element(BGP_NODE, &address_family_ipv4_multicast_cmd); install_element(BGP_IPV4M_NODE, &vtysh_exit_bgpd_cmd); install_element(BGP_IPV4M_NODE, &vtysh_quit_bgpd_cmd); install_element(BGP_IPV4M_NODE, &vtysh_end_all_cmd); install_element(BGP_IPV4M_NODE, &exit_address_family_cmd); - install_node(&bgp_ipv4l_node); install_element(BGP_NODE, &address_family_ipv4_labeled_unicast_cmd); install_element(BGP_IPV4L_NODE, &vtysh_exit_bgpd_cmd); install_element(BGP_IPV4L_NODE, &vtysh_quit_bgpd_cmd); install_element(BGP_IPV4L_NODE, &vtysh_end_all_cmd); install_element(BGP_IPV4L_NODE, &exit_address_family_cmd); - install_node(&bgp_ipv6_node); install_element(BGP_NODE, &address_family_ipv6_cmd); install_element(BGP_IPV6_NODE, &vtysh_exit_bgpd_cmd); install_element(BGP_IPV6_NODE, &vtysh_quit_bgpd_cmd); install_element(BGP_IPV6_NODE, &vtysh_end_all_cmd); install_element(BGP_IPV6_NODE, &exit_address_family_cmd); - install_node(&bgp_ipv6m_node); install_element(BGP_NODE, &address_family_ipv6_multicast_cmd); install_element(BGP_IPV6M_NODE, &vtysh_exit_bgpd_cmd); install_element(BGP_IPV6M_NODE, &vtysh_quit_bgpd_cmd); install_element(BGP_IPV6M_NODE, &vtysh_end_all_cmd); install_element(BGP_IPV6M_NODE, &exit_address_family_cmd); - install_node(&bgp_ipv6l_node); install_element(BGP_NODE, &address_family_ipv6_labeled_unicast_cmd); install_element(BGP_IPV6L_NODE, &vtysh_exit_bgpd_cmd); install_element(BGP_IPV6L_NODE, &vtysh_quit_bgpd_cmd); @@ -5039,28 +5069,24 @@ void vtysh_init_vty(void) install_element(BGP_IPV6L_NODE, &exit_address_family_cmd); #if defined(ENABLE_BGP_VNC) - install_node(&bgp_vrf_policy_node); install_element(BGP_NODE, &vnc_vrf_policy_cmd); install_element(BGP_VRF_POLICY_NODE, &vtysh_exit_bgpd_cmd); install_element(BGP_VRF_POLICY_NODE, &vtysh_quit_bgpd_cmd); install_element(BGP_VRF_POLICY_NODE, &vtysh_end_all_cmd); install_element(BGP_VRF_POLICY_NODE, &exit_vrf_policy_cmd); - install_node(&bgp_vnc_defaults_node); install_element(BGP_NODE, &vnc_defaults_cmd); install_element(BGP_VNC_DEFAULTS_NODE, &vtysh_exit_bgpd_cmd); install_element(BGP_VNC_DEFAULTS_NODE, &vtysh_quit_bgpd_cmd); install_element(BGP_VNC_DEFAULTS_NODE, &vtysh_end_all_cmd); install_element(BGP_VNC_DEFAULTS_NODE, &exit_vnc_config_cmd); - install_node(&bgp_vnc_nve_group_node); install_element(BGP_NODE, &vnc_nve_group_cmd); install_element(BGP_VNC_NVE_GROUP_NODE, &vtysh_exit_bgpd_cmd); install_element(BGP_VNC_NVE_GROUP_NODE, &vtysh_quit_bgpd_cmd); install_element(BGP_VNC_NVE_GROUP_NODE, &vtysh_end_all_cmd); install_element(BGP_VNC_NVE_GROUP_NODE, &exit_vnc_config_cmd); - install_node(&bgp_vnc_l2_group_node); install_element(BGP_NODE, &vnc_l2_group_cmd); install_element(BGP_VNC_L2_GROUP_NODE, &vtysh_exit_bgpd_cmd); install_element(BGP_VNC_L2_GROUP_NODE, &vtysh_quit_bgpd_cmd); @@ -5068,33 +5094,28 @@ void vtysh_init_vty(void) install_element(BGP_VNC_L2_GROUP_NODE, &exit_vnc_config_cmd); #endif - install_node(&bgp_evpn_node); install_element(BGP_NODE, &address_family_evpn_cmd); install_element(BGP_EVPN_NODE, &vtysh_quit_bgpd_cmd); install_element(BGP_EVPN_NODE, &vtysh_exit_bgpd_cmd); install_element(BGP_EVPN_NODE, &vtysh_end_all_cmd); install_element(BGP_EVPN_NODE, &exit_address_family_cmd); - install_node(&bgp_evpn_vni_node); install_element(BGP_EVPN_NODE, &bgp_evpn_vni_cmd); install_element(BGP_EVPN_VNI_NODE, &vtysh_exit_bgpd_cmd); install_element(BGP_EVPN_VNI_NODE, &vtysh_quit_bgpd_cmd); install_element(BGP_EVPN_VNI_NODE, &vtysh_end_all_cmd); install_element(BGP_EVPN_VNI_NODE, &exit_vni_cmd); - install_node(&rpki_node); install_element(CONFIG_NODE, &rpki_cmd); install_element(RPKI_NODE, &rpki_exit_cmd); install_element(RPKI_NODE, &rpki_quit_cmd); install_element(RPKI_NODE, &vtysh_end_all_cmd); - install_node(&bmp_node); install_element(BGP_NODE, &bmp_targets_cmd); install_element(BMP_NODE, &bmp_exit_cmd); install_element(BMP_NODE, &bmp_quit_cmd); install_element(BMP_NODE, &vtysh_end_all_cmd); - install_node(&bgp_srv6_node); install_element(BGP_NODE, &bgp_srv6_cmd); install_element(BGP_SRV6_NODE, &exit_bgp_srv6_cmd); install_element(BGP_SRV6_NODE, &quit_bgp_srv6_cmd); @@ -5102,7 +5123,6 @@ void vtysh_init_vty(void) #endif /* HAVE_BGPD */ /* ripd */ - install_node(&rip_node); #ifdef HAVE_RIPD install_element(CONFIG_NODE, &router_rip_cmd); install_element(RIP_NODE, &vtysh_exit_ripd_cmd); @@ -5111,7 +5131,6 @@ void vtysh_init_vty(void) #endif /* HAVE_RIPD */ /* ripngd */ - install_node(&ripng_node); #ifdef HAVE_RIPNGD install_element(CONFIG_NODE, &router_ripng_cmd); install_element(RIPNG_NODE, &vtysh_exit_ripngd_cmd); @@ -5121,7 +5140,6 @@ void vtysh_init_vty(void) /* ospfd */ #ifdef HAVE_OSPFD - install_node(&ospf_node); install_element(CONFIG_NODE, &router_ospf_cmd); install_element(OSPF_NODE, &vtysh_exit_ospfd_cmd); install_element(OSPF_NODE, &vtysh_quit_ospfd_cmd); @@ -5130,7 +5148,6 @@ void vtysh_init_vty(void) /* ospf6d */ #ifdef HAVE_OSPF6D - install_node(&ospf6_node); install_element(CONFIG_NODE, &router_ospf6_cmd); install_element(OSPF6_NODE, &vtysh_exit_ospf6d_cmd); install_element(OSPF6_NODE, &vtysh_quit_ospf6d_cmd); @@ -5139,45 +5156,38 @@ void vtysh_init_vty(void) /* ldpd */ #if defined(HAVE_LDPD) - install_node(&ldp_node); install_element(CONFIG_NODE, &ldp_mpls_ldp_cmd); install_element(LDP_NODE, &vtysh_exit_ldpd_cmd); install_element(LDP_NODE, &vtysh_quit_ldpd_cmd); install_element(LDP_NODE, &vtysh_end_all_cmd); - install_node(&ldp_ipv4_node); install_element(LDP_NODE, &ldp_address_family_ipv4_cmd); install_element(LDP_IPV4_NODE, &vtysh_exit_ldpd_cmd); install_element(LDP_IPV4_NODE, &vtysh_quit_ldpd_cmd); install_element(LDP_IPV4_NODE, &ldp_exit_address_family_cmd); install_element(LDP_IPV4_NODE, &vtysh_end_all_cmd); - install_node(&ldp_ipv6_node); install_element(LDP_NODE, &ldp_address_family_ipv6_cmd); install_element(LDP_IPV6_NODE, &vtysh_exit_ldpd_cmd); install_element(LDP_IPV6_NODE, &vtysh_quit_ldpd_cmd); install_element(LDP_IPV6_NODE, &ldp_exit_address_family_cmd); install_element(LDP_IPV6_NODE, &vtysh_end_all_cmd); - install_node(&ldp_ipv4_iface_node); install_element(LDP_IPV4_NODE, &ldp_interface_ifname_cmd); install_element(LDP_IPV4_IFACE_NODE, &vtysh_exit_ldpd_cmd); install_element(LDP_IPV4_IFACE_NODE, &vtysh_quit_ldpd_cmd); install_element(LDP_IPV4_IFACE_NODE, &vtysh_end_all_cmd); - install_node(&ldp_ipv6_iface_node); install_element(LDP_IPV6_NODE, &ldp_interface_ifname_cmd); install_element(LDP_IPV6_IFACE_NODE, &vtysh_exit_ldpd_cmd); install_element(LDP_IPV6_IFACE_NODE, &vtysh_quit_ldpd_cmd); install_element(LDP_IPV6_IFACE_NODE, &vtysh_end_all_cmd); - install_node(&ldp_l2vpn_node); install_element(CONFIG_NODE, &ldp_l2vpn_word_type_vpls_cmd); install_element(LDP_L2VPN_NODE, &vtysh_exit_ldpd_cmd); install_element(LDP_L2VPN_NODE, &vtysh_quit_ldpd_cmd); install_element(LDP_L2VPN_NODE, &vtysh_end_all_cmd); - install_node(&ldp_pseudowire_node); install_element(LDP_L2VPN_NODE, &ldp_member_pseudowire_ifname_cmd); install_element(LDP_PSEUDOWIRE_NODE, &vtysh_exit_ldpd_cmd); install_element(LDP_PSEUDOWIRE_NODE, &vtysh_quit_ldpd_cmd); @@ -5186,7 +5196,6 @@ void vtysh_init_vty(void) /* eigrpd */ #ifdef HAVE_EIGRPD - install_node(&eigrp_node); install_element(CONFIG_NODE, &router_eigrp_cmd); install_element(EIGRP_NODE, &vtysh_exit_eigrpd_cmd); install_element(EIGRP_NODE, &vtysh_quit_eigrpd_cmd); @@ -5195,7 +5204,6 @@ void vtysh_init_vty(void) /* babeld */ #ifdef HAVE_BABELD - install_node(&babel_node); install_element(CONFIG_NODE, &router_babel_cmd); install_element(BABEL_NODE, &vtysh_exit_babeld_cmd); install_element(BABEL_NODE, &vtysh_quit_babeld_cmd); @@ -5204,25 +5212,21 @@ void vtysh_init_vty(void) /* isisd */ #ifdef HAVE_ISISD - install_node(&isis_node); install_element(CONFIG_NODE, &router_isis_cmd); install_element(ISIS_NODE, &vtysh_exit_isisd_cmd); install_element(ISIS_NODE, &vtysh_quit_isisd_cmd); install_element(ISIS_NODE, &vtysh_end_all_cmd); - install_node(&isis_flex_algo_node); install_element(ISIS_NODE, &isis_flex_algo_cmd); install_element(ISIS_FLEX_ALGO_NODE, &vtysh_exit_isis_flex_algo_cmd); install_element(ISIS_FLEX_ALGO_NODE, &vtysh_quit_isis_flex_algo_cmd); install_element(ISIS_FLEX_ALGO_NODE, &vtysh_end_all_cmd); - install_node(&isis_srv6_node); install_element(ISIS_NODE, &isis_srv6_enable_cmd); install_element(ISIS_SRV6_NODE, &isis_srv6_node_msd_cmd); install_element(ISIS_SRV6_NODE, &vtysh_exit_isis_srv6_enable_cmd); install_element(ISIS_SRV6_NODE, &vtysh_quit_isis_srv6_enable_cmd); install_element(ISIS_SRV6_NODE, &vtysh_end_all_cmd); - install_node(&isis_srv6_node_msd_node); install_element(ISIS_SRV6_NODE_MSD_NODE, &vtysh_exit_isis_srv6_node_msd_cmd); install_element(ISIS_SRV6_NODE_MSD_NODE, @@ -5232,7 +5236,6 @@ void vtysh_init_vty(void) /* fabricd */ #ifdef HAVE_FABRICD - install_node(&openfabric_node); install_element(CONFIG_NODE, &router_openfabric_cmd); install_element(OPENFABRIC_NODE, &vtysh_exit_fabricd_cmd); install_element(OPENFABRIC_NODE, &vtysh_quit_fabricd_cmd); @@ -5241,7 +5244,6 @@ void vtysh_init_vty(void) /* pbrd */ #ifdef HAVE_PBRD - install_node(&pbr_map_node); install_element(CONFIG_NODE, &vtysh_pbr_map_cmd); install_element(CONFIG_NODE, &vtysh_no_pbr_map_cmd); install_element(PBRMAP_NODE, &vtysh_exit_pbr_map_cmd); @@ -5251,37 +5253,28 @@ void vtysh_init_vty(void) /* bfdd */ #if HAVE_BFDD > 0 - install_node(&bfd_node); install_element(CONFIG_NODE, &bfd_enter_cmd); install_element(BFD_NODE, &vtysh_exit_bfdd_cmd); install_element(BFD_NODE, &vtysh_quit_bfdd_cmd); install_element(BFD_NODE, &vtysh_end_all_cmd); - install_node(&bfd_peer_node); install_element(BFD_NODE, &bfd_peer_enter_cmd); install_element(BFD_PEER_NODE, &vtysh_exit_bfdd_cmd); install_element(BFD_PEER_NODE, &vtysh_quit_bfdd_cmd); install_element(BFD_PEER_NODE, &vtysh_end_all_cmd); - install_node(&bfd_profile_node); install_element(BFD_NODE, &bfd_profile_enter_cmd); install_element(BFD_PROFILE_NODE, &vtysh_exit_bfdd_cmd); install_element(BFD_PROFILE_NODE, &vtysh_quit_bfdd_cmd); install_element(BFD_PROFILE_NODE, &vtysh_end_all_cmd); #endif /* HAVE_BFDD */ - install_node(&segment_routing_node); install_element(CONFIG_NODE, &segment_routing_cmd); install_element(SEGMENT_ROUTING_NODE, &vtysh_exit_sr_cmd); install_element(SEGMENT_ROUTING_NODE, &vtysh_quit_sr_cmd); install_element(SEGMENT_ROUTING_NODE, &vtysh_end_all_cmd); #if defined(HAVE_PATHD) - install_node(&sr_traffic_eng_node); - install_node(&srte_segment_list_node); - install_node(&srte_policy_node); - install_node(&srte_candidate_dyn_node); - install_element(SR_TRAFFIC_ENG_NODE, &vtysh_exit_pathd_cmd); install_element(SR_TRAFFIC_ENG_NODE, &vtysh_quit_pathd_cmd); install_element(SR_SEGMENT_LIST_NODE, &vtysh_exit_pathd_cmd); @@ -5302,11 +5295,6 @@ void vtysh_init_vty(void) install_element(SR_TRAFFIC_ENG_NODE, &srte_policy_cmd); install_element(SR_POLICY_NODE, &srte_policy_candidate_dyn_path_cmd); - install_node(&pcep_node); - install_node(&pcep_pcc_node); - install_node(&pcep_pce_node); - install_node(&pcep_pce_config_node); - install_element(PCEP_NODE, &vtysh_exit_pathd_cmd); install_element(PCEP_NODE, &vtysh_quit_pathd_cmd); install_element(PCEP_PCC_NODE, &vtysh_exit_pathd_cmd); @@ -5329,14 +5317,12 @@ void vtysh_init_vty(void) #endif /* HAVE_PATHD */ /* keychain */ - install_node(&keychain_node); install_element(CONFIG_NODE, &key_chain_cmd); install_element(KEYCHAIN_NODE, &key_chain_cmd); install_element(KEYCHAIN_NODE, &vtysh_exit_keys_cmd); install_element(KEYCHAIN_NODE, &vtysh_quit_keys_cmd); install_element(KEYCHAIN_NODE, &vtysh_end_all_cmd); - install_node(&keychain_key_node); install_element(KEYCHAIN_NODE, &key_cmd); install_element(KEYCHAIN_KEY_NODE, &key_chain_cmd); install_element(KEYCHAIN_KEY_NODE, &vtysh_exit_keys_cmd); @@ -5344,7 +5330,6 @@ void vtysh_init_vty(void) install_element(KEYCHAIN_KEY_NODE, &vtysh_end_all_cmd); /* nexthop-group */ - install_node(&nh_group_node); install_element(CONFIG_NODE, &vtysh_nexthop_group_cmd); install_element(CONFIG_NODE, &vtysh_no_nexthop_group_cmd); install_element(NH_GROUP_NODE, &vtysh_end_all_cmd); @@ -5352,9 +5337,6 @@ void vtysh_init_vty(void) install_element(NH_GROUP_NODE, &vtysh_quit_nexthop_group_cmd); /* zebra and all */ - install_node(&zebra_node); - - install_node(&interface_node); install_element(CONFIG_NODE, &vtysh_interface_cmd); install_element(INTERFACE_NODE, &vtysh_end_all_cmd); install_element(INTERFACE_NODE, &vtysh_exit_interface_cmd); @@ -5362,7 +5344,6 @@ void vtysh_init_vty(void) /* pimd */ #ifdef HAVE_PIMD - install_node(&pim_node); install_element(CONFIG_NODE, &router_pim_cmd); install_element(PIM_NODE, &vtysh_exit_pimd_cmd); install_element(PIM_NODE, &vtysh_quit_pimd_cmd); @@ -5371,15 +5352,12 @@ void vtysh_init_vty(void) /* pim6d */ #ifdef HAVE_PIM6D - install_node(&pim6_node); install_element(CONFIG_NODE, &router_pim6_cmd); install_element(PIM6_NODE, &vtysh_exit_pim6d_cmd); install_element(PIM6_NODE, &vtysh_quit_pim6d_cmd); install_element(PIM6_NODE, &vtysh_end_all_cmd); #endif /* HAVE_PIM6D */ - /* zebra and all, cont. */ - install_node(&link_params_node); install_element(INTERFACE_NODE, &vtysh_link_params_cmd); install_element(LINK_PARAMS_NODE, &no_link_params_enable_cmd); install_element(LINK_PARAMS_NODE, &exit_link_params_cmd); @@ -5387,13 +5365,11 @@ void vtysh_init_vty(void) install_element(LINK_PARAMS_NODE, &vtysh_exit_link_params_cmd); install_element(LINK_PARAMS_NODE, &vtysh_quit_link_params_cmd); - install_node(&pw_node); install_element(CONFIG_NODE, &vtysh_pseudowire_cmd); install_element(PW_NODE, &vtysh_end_all_cmd); install_element(PW_NODE, &vtysh_exit_pseudowire_cmd); install_element(PW_NODE, &vtysh_quit_pseudowire_cmd); - install_node(&vrf_node); install_element(CONFIG_NODE, &vtysh_vrf_cmd); install_element(VRF_NODE, &exit_vrf_config_cmd); install_element(VRF_NODE, &vtysh_end_all_cmd); @@ -5401,7 +5377,6 @@ void vtysh_init_vty(void) install_element(VRF_NODE, &vtysh_quit_vrf_cmd); #ifdef HAVE_BGPD - install_node(&rpki_vrf_node); install_element(VRF_NODE, &rpki_cmd); install_element(RPKI_VRF_NODE, &rpki_exit_cmd); install_element(RPKI_VRF_NODE, &rpki_quit_cmd); @@ -5411,13 +5386,11 @@ void vtysh_init_vty(void) install_element(CONFIG_NODE, &vtysh_affinity_map_cmd); install_element(CONFIG_NODE, &vtysh_no_affinity_map_cmd); - install_node(&rmap_node); install_element(CONFIG_NODE, &vtysh_route_map_cmd); install_element(RMAP_NODE, &vtysh_exit_rmap_cmd); install_element(RMAP_NODE, &vtysh_quit_rmap_cmd); install_element(RMAP_NODE, &vtysh_end_all_cmd); - install_node(&vty_node); install_element(CONFIG_NODE, &vtysh_line_vty_cmd); install_element(VTY_NODE, &vtysh_exit_line_vty_cmd); install_element(VTY_NODE, &vtysh_quit_line_vty_cmd); @@ -5450,7 +5423,6 @@ void vtysh_init_vty(void) install_element(ENABLE_NODE, &vtysh_end_all_cmd); /* SRv6 Data-plane */ - install_node(&srv6_node); install_element(SEGMENT_ROUTING_NODE, &srv6_cmd); install_element(SRV6_NODE, &srv6_locators_cmd); install_element(SRV6_NODE, &srv6_sid_formats_cmd); @@ -5458,32 +5430,26 @@ void vtysh_init_vty(void) install_element(SRV6_NODE, &vtysh_end_all_cmd); install_element(SRV6_NODE, &srv6_encap_cmd); - install_node(&srv6_locs_node); install_element(SRV6_LOCS_NODE, &srv6_locator_cmd); install_element(SRV6_LOCS_NODE, &exit_srv6_locs_config_cmd); install_element(SRV6_LOCS_NODE, &vtysh_end_all_cmd); - install_node(&srv6_loc_node); install_element(SRV6_LOC_NODE, &exit_srv6_loc_config_cmd); install_element(SRV6_LOC_NODE, &vtysh_end_all_cmd); - install_node(&srv6_encap_node); install_element(SRV6_ENCAP_NODE, &exit_srv6_encap_cmd); install_element(SRV6_ENCAP_NODE, &vtysh_end_all_cmd); - install_node(&srv6_sid_formats_node); install_element(SRV6_SID_FORMATS_NODE, &srv6_sid_format_f3216_usid_cmd); install_element(SRV6_SID_FORMATS_NODE, &srv6_sid_format_f4024_uncompressed_cmd); install_element(SRV6_SID_FORMATS_NODE, &exit_srv6_sid_formats_cmd); install_element(SRV6_SID_FORMATS_NODE, &vtysh_end_all_cmd); - install_node(&srv6_sid_format_usid_f3216_node); install_element(SRV6_SID_FORMAT_USID_F3216_NODE, &exit_srv6_sid_format_cmd); install_element(SRV6_SID_FORMAT_USID_F3216_NODE, &vtysh_end_all_cmd); - install_node(&srv6_sid_format_uncompressed_f4024_node); install_element(SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE, &exit_srv6_sid_format_cmd); install_element(SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE, diff --git a/vtysh/vtysh_main.c b/vtysh/vtysh_main.c index 464d82cf7f..64198132cc 100644 --- a/vtysh/vtysh_main.c +++ b/vtysh/vtysh_main.c @@ -489,7 +489,6 @@ int main(int argc, char **argv, char **env) /* Make vty structure and register commands. */ vtysh_init_vty(); - vtysh_init_cmd(); vtysh_user_init(); vtysh_config_init(); From 4bc41193e810d3c93fc0ff0a5a7d7fe0f18c669b Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Sat, 20 Jul 2024 18:30:06 -0700 Subject: [PATCH 277/347] vtysh, lib: preprocess CLI graphs Store a parsed and built graph of the CLI nodes in vtysh, rather than parsing and building that graph every time vtysh starts up. This provides a 3x to 5x reduction in vtysh startup overhead: `vtysh -c 'configure' -c 'interface lo' -c 'do show version'` - before: 92.9M cycles, 1114 samples - after: 16.5M cycles, 330 samples This improvement is particularly visible for users scripting `vtysh -c` calls, which notably includes topotests. Signed-off-by: David Lamparter --- lib/command.h | 11 +-- lib/subdir.am | 25 ++++++- python/xref2vtysh.py | 166 ++++++++++++++++++++++++++++++++++++++++--- python/xrelfo.py | 18 +++-- tests/lib/subdir.am | 2 +- vtysh/.gitignore | 1 + vtysh/subdir.am | 3 - 7 files changed, 202 insertions(+), 24 deletions(-) diff --git a/lib/command.h b/lib/command.h index f364f1e8fa..cb105c656c 100644 --- a/lib/command.h +++ b/lib/command.h @@ -256,7 +256,7 @@ struct cmd_node { /* helper defines for end-user DEFUN* macros */ #define DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, attrs, dnum) \ - static const struct cmd_element cmdname = { \ + const struct cmd_element cmdname = { \ .string = cmdstr, \ .func = funcname, \ .doc = helpstr, \ @@ -283,7 +283,7 @@ struct cmd_node { /* DEFPY variants */ #define DEFPY_ATTR(funcname, cmdname, cmdstr, helpstr, attr) \ - DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, attr, 0) \ + static DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, attr, 0) \ funcdecl_##funcname #define DEFPY(funcname, cmdname, cmdstr, helpstr) \ @@ -310,7 +310,7 @@ struct cmd_node { #define DEFUN_ATTR(funcname, cmdname, cmdstr, helpstr, attr) \ DEFUN_CMD_FUNC_DECL(funcname) \ - DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, attr, 0) \ + static DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, attr, 0) \ DEFUN_CMD_FUNC_TEXT(funcname) #define DEFUN(funcname, cmdname, cmdstr, helpstr) \ @@ -347,7 +347,8 @@ struct cmd_node { /* DEFUN + DEFSH */ #define DEFUNSH_ATTR(daemon, funcname, cmdname, cmdstr, helpstr, attr) \ DEFUN_CMD_FUNC_DECL(funcname) \ - DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, attr, daemon) \ + static DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, attr, \ + daemon) \ DEFUN_CMD_FUNC_TEXT(funcname) #define DEFUNSH(daemon, funcname, cmdname, cmdstr, helpstr) \ @@ -359,7 +360,7 @@ struct cmd_node { /* ALIAS macro which define existing command's alias. */ #define ALIAS_ATTR(funcname, cmdname, cmdstr, helpstr, attr) \ - DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, attr, 0) + static DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, attr, 0) #define ALIAS(funcname, cmdname, cmdstr, helpstr) \ ALIAS_ATTR(funcname, cmdname, cmdstr, helpstr, 0) diff --git a/lib/subdir.am b/lib/subdir.am index 3264f31af7..4bcce9a2b0 100644 --- a/lib/subdir.am +++ b/lib/subdir.am @@ -504,20 +504,41 @@ SUFFIXES += .xref %.xref: % $(CLIPPY) $(AM_V_XRELFO) $(CLIPPY) $(top_srcdir)/python/xrelfo.py $(WERROR) $(XRELFO_FLAGS) -o $@ $< +# these run up to a total of 350k lines at the time of writing. That's a lot +# for the compiler to chug down - enough to warrant splitting it up so it can +# benefit from parallel build. +vtysh_cmd_split = \ + vtysh/vtysh_cmd.1.c \ + vtysh/vtysh_cmd.2.c \ + vtysh/vtysh_cmd.3.c \ + vtysh/vtysh_cmd.4.c \ + vtysh/vtysh_cmd.5.c \ + vtysh/vtysh_cmd.6.c \ + vtysh/vtysh_cmd.7.c \ + vtysh/vtysh_cmd.8.c \ + # end + # dependencies added in python/makefile.py frr.xref: - $(AM_V_XRELFO) $(CLIPPY) $(top_srcdir)/python/xrelfo.py -o $@ -c vtysh/vtysh_cmd.c $^ + $(AM_V_XRELFO) $(CLIPPY) $(top_srcdir)/python/xrelfo.py -o $@ $^ \ + -c vtysh/vtysh_cmd.c $(vtysh_cmd_split) all-am: frr.xref clean-xref: -rm -rf $(xrefs) frr.xref clean-local: clean-xref -CLEANFILES += vtysh/vtysh_cmd.c vtysh/vtysh_cmd.c: frr.xref @test -f $@ || rm -f frr.xref || true @test -f $@ || $(MAKE) $(AM_MAKEFLAGS) frr.xref +vtysh/vtysh_cmd.%.c: vtysh/vtysh_cmd.c + @test -f $@ || rm -f vtysh/vtysh_cmd.c || true + @test -f $@ || $(MAKE) $(AM_MAKEFLAGS) vtysh/vtysh_cmd.c + +nodist_vtysh_vtysh_SOURCES = vtysh/vtysh_cmd.c $(vtysh_cmd_split) +CLEANFILES += vtysh/vtysh_cmd.c $(vtysh_cmd_split) + ## automake's "ylwrap" is a great piece of GNU software... not. .l.c: $(AM_V_LEX)$(am__skiplex) $(LEXCOMPILE) $< diff --git a/python/xref2vtysh.py b/python/xref2vtysh.py index 75d9ccf367..0cfb11e721 100644 --- a/python/xref2vtysh.py +++ b/python/xref2vtysh.py @@ -26,6 +26,8 @@ except ImportError: pass +import _clippy + frr_top_src = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # vtysh needs to know which daemon(s) to send commands to. For lib/, this is @@ -58,6 +60,16 @@ #include "linklist.h" #include "vtysh/vtysh.h" + +#pragma GCC visibility push(internal) + +#define MAKE_VECTOR(name, len, ...) \\ + static void * name ## _vitems[] = { __VA_ARGS__ }; \\ + static struct _vector name = { \\ + .active = len, \\ + .count = len, \\ + .index = name ## _vitems, \\ + } """ if sys.stderr.isatty(): @@ -335,23 +347,159 @@ def output_defs(cls, ofd): ofd.write(entry.get_def()) @classmethod - def output_install(cls, ofd, nodes): - ofd.write("\nvoid vtysh_init_cmd(void)\n{\n") + def output_node_graph(cls, ofd, node, cmds, splitfile): + graph = _clippy.Graph(None) + + for _, cmd in sorted(cmds.items()): + cg = _clippy.Graph(cmd.cmd, cmd._spec["doc"], cmd.name) + graph.merge(cg) + + if len(graph) <= 2: + return [] + + ofd.write("\n") + ofd.write(f"static struct cmd_token ctkn_{node}[];\n") + ofd.write(f"static struct graph_node gn_{node}[];\n") + ofd.write("\n") + + vectors = [] + cmdels = set() + + ofd.write(f"static struct cmd_token ctkn_{node}[] = {'{'}\n") + for i, token in enumerate(graph): + vectors.append( + ( + list(i.idx for i in token.next()), + list(i.idx for i in token.prev()), + ) + ) - for name, items in sorted(nodes.items_named()): - for item in sorted(items.values(), key=lambda i: i.name): - ofd.write("\tinstall_element(%s, &%s_vtysh);\n" % (name, item.name)) + if token.type == "CMD_ELEMENT_TKN": + ofd.write(f"\t{'{'} /* [{i}] = {token.text} */ {'}'},\n") + cmdels.add(token.text) + continue + + ofd.write(f"\t{'{'} /* [{i}] */\n\t\t.type = {token.type},\n") + if token.attr: + ofd.write(f"\t\t.attr = {token.attr},\n") + if token.allowrepeat: + ofd.write(f"\t\t.allowrepeat = true,\n") + if token.varname_src: + ofd.write(f"\t\t.varname_src = {token.varname_src},\n") + if token.text: + ofd.write(f'\t\t.text = (char *)"{c_escape(token.text)}",\n') + if token.desc: + ofd.write(f'\t\t.desc = (char *)"{c_escape(token.desc)}",\n') + if token.min: + ofd.write(f"\t\t.min = {token.min},\n") + if token.max: + ofd.write(f"\t\t.max = {token.max},\n") + if token.varname: + ofd.write(f'\t\t.varname = (char *)"{c_escape(token.varname)}",\n') + + if token.type == "FORK_TKN": + fj = token.join() + ofd.write(f"\t\t.forkjoin = &gn_{node}[{fj.idx}],\n") + if token.type == "JOIN_TKN": + fj = token.fork() + ofd.write(f"\t\t.forkjoin = &gn_{node}[{fj.idx}],\n") + + ofd.write(f"\t{'}'},\n") + + ofd.write("};\n\n") + + if splitfile: + for cmdel in sorted(cmdels): + ofd.write(f"extern struct cmd_element {cmdel}_vtysh;\n") + ofd.write("\n") + + for i, next_prev in enumerate(vectors): + n, p = next_prev + items = ", ".join(f"&gn_{node}[{i}]" for i in n) + ofd.write(f"MAKE_VECTOR(gn_{node}_{i}_next, {len(n)}, {items});\n") + items = ", ".join(f"&gn_{node}[{i}]" for i in p) + ofd.write(f"MAKE_VECTOR(gn_{node}_{i}_prev, {len(p)}, {items});\n") + + ofd.write(f"\nstatic struct graph_node gn_{node}[] = {'{'}\n") + for i, token in enumerate(graph): + ofd.write("\t{\n") + ofd.write(f"\t\t.from = &gn_{node}_{i}_prev,\n") + ofd.write(f"\t\t.to = &gn_{node}_{i}_next,\n") + if token.type == "CMD_ELEMENT_TKN": + ofd.write(f"\t\t.data = (void *)&{token.text}_vtysh,\n") + else: + ofd.write(f"\t\t.data = &ctkn_{node}[{i}],\n") + ofd.write("\t},\n") + ofd.write("};\n") + + items = ", ".join(f"&gn_{node}[{i}]" for i in range(0, len(graph))) + ofd.write(f"MAKE_VECTOR(gvec_{node}, {len(graph)}, {items});\n") + + ofd.write( + f""" +{"extern " if splitfile else "static "}void install_{node}(void);\n +{"" if splitfile else "static "}void install_{node}(void)\n +{'{'} + unsigned node_id = {node}; + struct cmd_node *node; + + assert(node_id < vector_active(cmdvec)); + node = vector_slot(cmdvec, node_id); + assert(node); + assert(vector_active(node->cmdgraph->nodes) == 1); + graph_delete_node(node->cmdgraph, vector_slot(node->cmdgraph->nodes, 0)); + vector_free(node->cmdgraph->nodes); + node->cmdgraph->nodes = &gvec_{node}; +{'}'} +""" + ) - ofd.write("}\n") + return [node] @classmethod - def run(cls, xref, ofd): - ofd.write(vtysh_cmd_head) + def run(cls, xref, ofds): + for ofd in ofds: + ofd.write(vtysh_cmd_head) + + ofd = ofds.pop(0) NodeDict.load_nodenames() nodes = cls.load(xref) cls.output_defs(ofd) - cls.output_install(ofd, nodes) + + out_nodes = [] + for nodeid, cmds in nodes.items(): + node = nodes.nodename(nodeid) + + if ofds: + gfd, splitfile = ofds[nodeid % len(ofds)], True + else: + gfd, splitfile = ofd, False + + # install_element(VIEW_NODE, x) implies install_element(ENABLE_NODE, x) + # this needs to be handled here. + if node == "ENABLE_NODE": + nodeid_view = list( + k for k, v in nodes.nodenames.items() if v == "VIEW_NODE" + ) + assert len(nodeid_view) == 1 + cmds.update(nodes[nodeid_view[0]]) + + out_nodes.extend(cls.output_node_graph(gfd, node, cmds, splitfile)) + + out_nodes.sort() + + if ofds: + ofd.write("\n") + for name in out_nodes: + ofd.write(f"extern void install_{name}(void);\n") + + ofd.write("\nvoid vtysh_init_cmd(void)\n{\n") + + for name in out_nodes: + ofd.write(f"\tinstall_{name}();\n") + + ofd.write("}\n") def main(): diff --git a/python/xrelfo.py b/python/xrelfo.py index 07cd74071f..5f7616f250 100644 --- a/python/xrelfo.py +++ b/python/xrelfo.py @@ -447,7 +447,9 @@ def main(): argp = argparse.ArgumentParser(description="FRR xref ELF extractor") argp.add_argument("-o", dest="output", type=str, help="write JSON output") argp.add_argument("--out-by-file", type=str, help="write by-file JSON output") - argp.add_argument("-c", dest="vtysh_cmds", type=str, help="write vtysh_cmd.c") + argp.add_argument( + "-c", dest="vtysh_cmds", type=str, help="write vtysh_cmd.c", nargs="*" + ) argp.add_argument("-Wlog-format", action="store_const", const=True) argp.add_argument("-Wlog-args", action="store_const", const=True) argp.add_argument("-Werror", action="store_const", const=True) @@ -528,9 +530,17 @@ def _main(args): os.rename(args.out_by_file + ".tmp", args.out_by_file) if args.vtysh_cmds: - with open(args.vtysh_cmds + ".tmp", "w") as fd: - CommandEntry.run(out, fd) - os.rename(args.vtysh_cmds + ".tmp", args.vtysh_cmds) + fds = [] + for filename in args.vtysh_cmds: + fds.append(open(filename + ".tmp", "w")) + + CommandEntry.run(out, fds) + + while fds: + fds.pop(0).close() + for filename in args.vtysh_cmds: + os.rename(filename + ".tmp", filename) + if args.Werror and CommandEntry.warn_counter: sys.exit(1) diff --git a/tests/lib/subdir.am b/tests/lib/subdir.am index 185b895079..1a21684f16 100644 --- a/tests/lib/subdir.am +++ b/tests/lib/subdir.am @@ -100,7 +100,7 @@ check_PROGRAMS += tests/lib/cli/test_commands tests_lib_cli_test_commands_CFLAGS = $(TESTS_CFLAGS) tests_lib_cli_test_commands_CPPFLAGS = $(TESTS_CPPFLAGS) tests_lib_cli_test_commands_LDADD = $(ALL_TESTS_LDADD) -nodist_tests_lib_cli_test_commands_SOURCES = tests/lib/cli/test_commands_defun.c +nodist_tests_lib_cli_test_commands_SOURCES = tests/lib/cli/test_commands_defun.c $(vtysh_cmd_split) tests_lib_cli_test_commands_SOURCES = tests/lib/cli/test_commands.c tests/helpers/c/prng.c tests/lib/cli/test_commands_defun.c: vtysh/vtysh_cmd.c @$(MKDIR_P) tests/lib/cli diff --git a/vtysh/.gitignore b/vtysh/.gitignore index a6c3d4abc6..9cbd248f2f 100644 --- a/vtysh/.gitignore +++ b/vtysh/.gitignore @@ -1,5 +1,6 @@ vtysh vtysh_cmd.c +vtysh_cmd.*.c # does not exist anymore - remove 2023-10-04 or so extract.pl diff --git a/vtysh/subdir.am b/vtysh/subdir.am index 2eae16d629..d39987eb83 100644 --- a/vtysh/subdir.am +++ b/vtysh/subdir.am @@ -17,9 +17,6 @@ vtysh_vtysh_SOURCES = \ vtysh/vtysh_user.c \ vtysh/vtysh_config.c \ # end -nodist_vtysh_vtysh_SOURCES = \ - vtysh/vtysh_cmd.c \ - # end noinst_HEADERS += \ vtysh/vtysh.h \ From d6d49f291c45cf28736f8b2686fd0a401e54533c Mon Sep 17 00:00:00 2001 From: Rafael Zalamena Date: Wed, 31 Jul 2024 10:18:47 -0300 Subject: [PATCH 278/347] pimd: fix possible NULL dereference Coverity scan ID: 1598684 Signed-off-by: Rafael Zalamena --- pimd/pim_cmd.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index dcfad2a4f8..f57048c703 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -2837,13 +2837,14 @@ DEFPY(clear_ip_msdp_peer, clear_ip_msdp_peer_cmd, const struct vrf *vrf; struct pim_msdp_peer *mp; - if (vrfname) { + if (vrfname) vrf = vrf_lookup_by_name(vrfname); - if (vrf == NULL) - return CMD_WARNING; - } else + else vrf = vrf_lookup_by_id(VRF_DEFAULT); + if (vrf == NULL || vrf->info == NULL) + return CMD_WARNING; + pim = vrf->info; for (ALL_LIST_ELEMENTS_RO(pim->msdp.peer_list, node, mp)) { if (mp->peer.s_addr != peer.s_addr) From 6f2aea5a1309ce69f269ca4e95ed5c1f476a3735 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 31 Jul 2024 10:45:38 -0400 Subject: [PATCH 279/347] tests: Increase route_scale timeouts This test is frequently failing in the upstream CI. Most log failures are stating that we expected something like 1 million routes but we have 900k+. Looks like the system is just loaded a bit more than expected. Let's give these tests a bit more time to complete. Signed-off-by: Donald Sharp --- tests/topotests/route_scale/scale_test_common.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/topotests/route_scale/scale_test_common.py b/tests/topotests/route_scale/scale_test_common.py index 3e20296018..0b239dc04b 100644 --- a/tests/topotests/route_scale/scale_test_common.py +++ b/tests/topotests/route_scale/scale_test_common.py @@ -165,7 +165,7 @@ def route_install_helper(iter): # Table of defaults, used for timeout values and 'expected' objects scale_defaults = dict( - zip(scale_keys, [None, None, 10, 50, expected_installed, expected_removed]) + zip(scale_keys, [None, None, 10, 60, expected_installed, expected_removed]) ) # List of params for each step in the test; note extra time given From 08bf9cd9f5f37cf7afefa181d82d0836809109a4 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 31 Jul 2024 10:37:59 -0400 Subject: [PATCH 280/347] tests: Shorten reconnect timer when something goes wrong When running bfd_bgp_cbit_topo3 and an intial connection goes wrong, try to connect again as fast as possible as that the timer is 2 minutes otherwise and the test will never come back from it. Signed-off-by: Donald Sharp --- tests/topotests/bfd_bgp_cbit_topo3/r1/bgpd.conf | 1 + tests/topotests/bfd_bgp_cbit_topo3/r3/bgpd.conf | 1 + 2 files changed, 2 insertions(+) diff --git a/tests/topotests/bfd_bgp_cbit_topo3/r1/bgpd.conf b/tests/topotests/bfd_bgp_cbit_topo3/r1/bgpd.conf index f8ad1f3a66..054b12832a 100644 --- a/tests/topotests/bfd_bgp_cbit_topo3/r1/bgpd.conf +++ b/tests/topotests/bfd_bgp_cbit_topo3/r1/bgpd.conf @@ -7,6 +7,7 @@ router bgp 101 bgp graceful-restart neighbor 2001:db8:4::1 remote-as 102 neighbor 2001:db8:4::1 timers 3 10 + neighbor 2001:db8:4::1 timers connect 1 neighbor 2001:db8:4::1 remote-as external neighbor 2001:db8:4::1 bfd neighbor 2001:db8:4::1 bfd check-control-plane-failure diff --git a/tests/topotests/bfd_bgp_cbit_topo3/r3/bgpd.conf b/tests/topotests/bfd_bgp_cbit_topo3/r3/bgpd.conf index 42953a075c..d7e10210f3 100644 --- a/tests/topotests/bfd_bgp_cbit_topo3/r3/bgpd.conf +++ b/tests/topotests/bfd_bgp_cbit_topo3/r3/bgpd.conf @@ -11,6 +11,7 @@ router bgp 102 bgp graceful-restart restart-time 900 neighbor 2001:db8:1::1 remote-as 101 neighbor 2001:db8:1::1 timers 3 10 + neighbor 2001:db8:1::1 timers connect 1 neighbor 2001:db8:1::1 remote-as external neighbor 2001:db8:1::1 update-source 2001:db8:4::1 neighbor 2001:db8:1::1 bfd From b52346efe404de8da5e0dd6ff41e6a1ec4dd1621 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 31 Jul 2024 11:00:38 -0400 Subject: [PATCH 281/347] tests: need aggressive timers in bgp_route_map_match_ipv6_nexthop Add some timers to make the convergence happen as fast as possible when a connection fails on the initial attempt. Signed-off-by: Donald Sharp --- tests/topotests/bgp_route_map_match_ipv6_nexthop/r1/bgpd.conf | 2 ++ tests/topotests/bgp_route_map_match_ipv6_nexthop/r2/bgpd.conf | 2 ++ 2 files changed, 4 insertions(+) diff --git a/tests/topotests/bgp_route_map_match_ipv6_nexthop/r1/bgpd.conf b/tests/topotests/bgp_route_map_match_ipv6_nexthop/r1/bgpd.conf index 8b743bd320..11e57ca932 100644 --- a/tests/topotests/bgp_route_map_match_ipv6_nexthop/r1/bgpd.conf +++ b/tests/topotests/bgp_route_map_match_ipv6_nexthop/r1/bgpd.conf @@ -11,6 +11,8 @@ router bgp 65001 bgp router-id 10.10.10.1 no bgp ebgp-requires-policy neighbor 2001:db8::2 remote-as external + neighbor 2001:db8::2 timers 3 10 + neighbor 2001:db8::2 timers connect 1 address-family ipv6 unicast neighbor 2001:db8::2 activate neighbor 2001:db8::2 route-map r2 in diff --git a/tests/topotests/bgp_route_map_match_ipv6_nexthop/r2/bgpd.conf b/tests/topotests/bgp_route_map_match_ipv6_nexthop/r2/bgpd.conf index 61c36d366b..abd0ab9a41 100644 --- a/tests/topotests/bgp_route_map_match_ipv6_nexthop/r2/bgpd.conf +++ b/tests/topotests/bgp_route_map_match_ipv6_nexthop/r2/bgpd.conf @@ -5,6 +5,8 @@ router bgp 65002 bgp router-id 10.10.10.2 no bgp ebgp-requires-policy neighbor 2001:db8::1 remote-as external + neighbor 2001:db8::1 timers 3 10 + neighbor 2001:db8::1 timers connect 1 address-family ipv6 unicast redistribute connected neighbor 2001:db8::1 activate From 9af1f5e8237a74ed756cdec258a3a2921b536707 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 31 Jul 2024 11:43:07 -0400 Subject: [PATCH 282/347] tests: need aggressive timers in bgp_prefix_list_any Add some timers to make convergence happan as fast as possible when a connection fails on the intial attempt. Signed-off-by: Donald Sharp --- tests/topotests/bgp_prefix_list_any/r1/bgpd.conf | 4 ++++ tests/topotests/bgp_prefix_list_any/r2/bgpd.conf | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/tests/topotests/bgp_prefix_list_any/r1/bgpd.conf b/tests/topotests/bgp_prefix_list_any/r1/bgpd.conf index 14c28ca906..593442a42a 100644 --- a/tests/topotests/bgp_prefix_list_any/r1/bgpd.conf +++ b/tests/topotests/bgp_prefix_list_any/r1/bgpd.conf @@ -4,6 +4,10 @@ router bgp 65001 no bgp network import-check neighbor 192.168.1.2 remote-as external neighbor 2001:db8:1::2 remote-as external + neighbor 192.168.1.2 timers 3 10 + neighbor 192.168.1.2 timers connect 1 + neighbor 2001:db8:1::2 timers 3 10 + neighbor 2001:db8:1::2 timers connect 1 address-family ipv4 unicast network 192.168.0.1/32 no neighbor 2001:db8:1::2 activate diff --git a/tests/topotests/bgp_prefix_list_any/r2/bgpd.conf b/tests/topotests/bgp_prefix_list_any/r2/bgpd.conf index 733205928f..0de5bd3355 100644 --- a/tests/topotests/bgp_prefix_list_any/r2/bgpd.conf +++ b/tests/topotests/bgp_prefix_list_any/r2/bgpd.conf @@ -6,6 +6,10 @@ router bgp 65002 no bgp network import-check neighbor 192.168.1.1 remote-as external neighbor 2001:db8:1::1 remote-as external + neighbor 192.168.1.1 timers 3 10 + neighbor 192.168.1.1 timers connect 1 + neighbor 2001:db8:1::1 timers 3 10 + neighbor 2001:db8:1::1 timers connect 1 address-family ipv4 unicast network 10.10.10.1/32 network 10.10.10.2/32 From 1d181dfb98750549d904b1f1a48e0799e9264fa4 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Tue, 6 Aug 2024 18:19:40 +0300 Subject: [PATCH 283/347] bgpd: Clear previously allocated capabilities values before parsing a new OPEN Signed-off-by: Donatas Abraitis --- bgpd/bgp_packet.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index 842fd1734a..2a2c9bdba9 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -1804,6 +1804,23 @@ static int bgp_open_receive(struct peer_connection *connection, mp_capability = 0; optlen = stream_getc(peer->curr); + /* If we previously had some more capabilities e.g.: + * FQDN, SOFT_VERSION, we MUST clear the values we used + * before, to avoid using stale data. + * Checking peer->cap is enough before checking for the real + * data, but we don't have this check everywhere in the code, + * thus let's clear the data here too before parsing the + * capabilities. + */ + if (peer->hostname) + XFREE(MTYPE_BGP_PEER_HOST, peer->hostname); + + if (peer->domainname) + XFREE(MTYPE_BGP_PEER_HOST, peer->domainname); + + if (peer->soft_version) + XFREE(MTYPE_BGP_SOFT_VERSION, peer->soft_version); + /* Extended Optional Parameters Length for BGP OPEN Message */ if (optlen == BGP_OPEN_NON_EXT_OPT_LEN || CHECK_FLAG(peer->flags, PEER_FLAG_EXTENDED_OPT_PARAMS)) { From 2ee9f4d11fad259b3226e386375c2edf072ba28a Mon Sep 17 00:00:00 2001 From: Christian Hopps Date: Wed, 7 Aug 2024 09:27:57 -0400 Subject: [PATCH 284/347] tests: wait for test client to connect before running test Vtysh has been improved to startup very quickly this exposed a race in this test, where the `clear ip rip...` command ran before the test client that handles it had finished connecting to mgmtd. Add a retried check for the test client being connected before issuing the `clear ip rip ...` test command. Signed-off-by: Christian Hopps --- tests/topotests/mgmt_rpc/test_rpc.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/topotests/mgmt_rpc/test_rpc.py b/tests/topotests/mgmt_rpc/test_rpc.py index 839db97379..4d073fd0c9 100644 --- a/tests/topotests/mgmt_rpc/test_rpc.py +++ b/tests/topotests/mgmt_rpc/test_rpc.py @@ -14,6 +14,7 @@ import threading import pytest +from lib.common_config import retry from lib.topogen import Topogen from lib.topotest import json_cmp @@ -40,12 +41,20 @@ def tgen(request): tgen.stop_topology() +# Verify the backend test client has connected +@retry(retry_timeout=10) +def check_client_connect(r1): + out = r1.vtysh_cmd("show mgmt backend-adapter all") + assert "mgmtd-testc" in out + + def test_backend_rpc(tgen): if tgen.routers_have_failure(): pytest.skip(tgen.errors) r1 = tgen.gears["r1"] + # Run the backend test client which registers to handle the `clear ip rip` command. be_client_path = "/usr/lib/frr/mgmtd_testc" rc, _, _ = r1.net.cmd_status(be_client_path + " --help") @@ -63,6 +72,10 @@ def run_testc(): t = threading.Thread(target=run_testc) t.start() + # We need to wait for mgmtd_testc to connect before issuing the command. + res = check_client_connect(r1) + assert res is None + r1.vtysh_cmd("clear ip rip vrf testname") t.join() From 14b5c78d44d5d1b9dad9a1b896edd0a561562df0 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Wed, 7 Aug 2024 17:39:28 +0300 Subject: [PATCH 285/347] bgpd: Remove BGP_UPDATE_DELAY_MIN/MAX Found randomly, and seems not used anymore. Signed-off-by: Donatas Abraitis --- bgpd/bgp_vty.c | 10 +++++----- bgpd/bgpd.c | 4 ++-- bgpd/bgpd.h | 4 +--- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 828fa711b2..a3180fd707 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -2267,9 +2267,9 @@ static int bgp_global_update_delay_config_vty(struct vty *vty, * Note that we only need to check this if this is the first time * setting the global config. */ - if (bm->v_update_delay == BGP_UPDATE_DELAY_DEF) { + if (bm->v_update_delay == BGP_UPDATE_DELAY_DEFAULT) { for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) { - if (bgp->v_update_delay != BGP_UPDATE_DELAY_DEF) { + if (bgp->v_update_delay != BGP_UPDATE_DELAY_DEFAULT) { vty_out(vty, "%% update-delay configuration found in vrf %s\n", bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT @@ -2314,7 +2314,7 @@ static int bgp_global_update_delay_deconfig_vty(struct vty *vty) struct listnode *node, *nnode; struct bgp *bgp; - bm->v_update_delay = BGP_UPDATE_DELAY_DEF; + bm->v_update_delay = BGP_UPDATE_DELAY_DEFAULT; bm->v_establish_wait = bm->v_update_delay; for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) { @@ -2368,7 +2368,7 @@ static int bgp_update_delay_deconfig_vty(struct vty *vty) "%%Failed: bgp update-delay configured globally. Delete per-vrf not permitted\n"); return CMD_WARNING_CONFIG_FAILED; } - bgp->v_update_delay = BGP_UPDATE_DELAY_DEF; + bgp->v_update_delay = BGP_UPDATE_DELAY_DEFAULT; bgp->v_establish_wait = bgp->v_update_delay; return CMD_SUCCESS; @@ -19346,7 +19346,7 @@ int bgp_config_write(struct vty *vty) vty_out(vty, "bgp route-map delay-timer %u\n", bm->rmap_update_timer); - if (bm->v_update_delay != BGP_UPDATE_DELAY_DEF) { + if (bm->v_update_delay != BGP_UPDATE_DELAY_DEFAULT) { vty_out(vty, "bgp update-delay %d", bm->v_update_delay); if (bm->v_update_delay != bm->v_establish_wait) vty_out(vty, " %d", bm->v_establish_wait); diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 44cd24565a..a88de651f5 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -8432,8 +8432,8 @@ void bgp_master_init(struct event_loop *master, const int buffer_size, bm->start_time = monotime(NULL); bm->t_rmap_update = NULL; bm->rmap_update_timer = RMAP_DEFAULT_UPDATE_TIMER; - bm->v_update_delay = BGP_UPDATE_DELAY_DEF; - bm->v_establish_wait = BGP_UPDATE_DELAY_DEF; + bm->v_update_delay = BGP_UPDATE_DELAY_DEFAULT; + bm->v_establish_wait = BGP_UPDATE_DELAY_DEFAULT; bm->terminating = false; bm->socket_buffer = buffer_size; bm->wait_for_fib = false; diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index b733be9f0d..626a76ba0b 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -489,9 +489,7 @@ struct bgp { uint32_t restarted_peers; uint32_t implicit_eors; uint32_t explicit_eors; -#define BGP_UPDATE_DELAY_DEF 0 -#define BGP_UPDATE_DELAY_MIN 0 -#define BGP_UPDATE_DELAY_MAX 3600 +#define BGP_UPDATE_DELAY_DEFAULT 0 /* Reference bandwidth for BGP link-bandwidth. Used when * the LB value has to be computed based on some other From 61e8d5e0b9f0ccb7647a04974f7134ede67fedd8 Mon Sep 17 00:00:00 2001 From: Igor Ryzhov Date: Thu, 8 Aug 2024 00:40:51 +0300 Subject: [PATCH 286/347] mgmtd: don't add implicit state data when reading config from file When mgmt reads configuration from file, it shouldn't add implicit state data to the candidate datastore. Configuration datastores like candidate should never store state, otherwise they fail validation. Fixes #15814 Signed-off-by: Igor Ryzhov --- mgmtd/mgmt_ds.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mgmtd/mgmt_ds.c b/mgmtd/mgmt_ds.c index eaf52dfb29..dabae4afd1 100644 --- a/mgmtd/mgmt_ds.c +++ b/mgmtd/mgmt_ds.c @@ -127,7 +127,8 @@ static int mgmt_ds_load_cfg_from_file(const char *filepath, *dnode = NULL; ret = lyd_parse_data_path(ly_native_ctx, filepath, LYD_JSON, - LYD_PARSE_STRICT, 0, dnode); + LYD_PARSE_NO_STATE | LYD_PARSE_STRICT, + LYD_VALIDATE_NO_STATE, dnode); if (ret != LY_SUCCESS) { if (*dnode) From 2b12d62e38bf41648b2703b5a5c48e47eb01edc7 Mon Sep 17 00:00:00 2001 From: Igor Ryzhov Date: Thu, 8 Aug 2024 01:17:11 +0300 Subject: [PATCH 287/347] lib: fix crash on distribute-list delete The destroy callback must be executed only once on APPLY stage. Fixes #16528 Signed-off-by: Igor Ryzhov --- lib/distribute.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/distribute.c b/lib/distribute.c index ccd1f1379e..90a73c3635 100644 --- a/lib/distribute.c +++ b/lib/distribute.c @@ -458,6 +458,8 @@ int group_distribute_list_create_helper( int group_distribute_list_destroy(struct nb_cb_destroy_args *args) { + if (args->event != NB_EV_APPLY) + return NB_OK; nb_running_unset_entry(args->dnode); return NB_OK; } From 25d94ec3eedca978ce7c37359105b0518dcf0f5f Mon Sep 17 00:00:00 2001 From: Igor Ryzhov Date: Thu, 8 Aug 2024 01:25:02 +0300 Subject: [PATCH 288/347] ripd: fix show run output for distribute-list CLI show callbacks should be defined in frr_ripd_cli_info instead of frr_ripd_info, because only the former is loaded by mgmtd and only its callbacks are getting called for config output. Signed-off-by: Igor Ryzhov --- ripd/rip_cli.c | 16 ++++++++++++++++ ripd/rip_nb.c | 4 ---- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/ripd/rip_cli.c b/ripd/rip_cli.c index 7066485be0..5712a0b825 100644 --- a/ripd/rip_cli.c +++ b/ripd/rip_cli.c @@ -1374,6 +1374,22 @@ const struct frr_yang_module_info frr_ripd_cli_info = { .xpath = "/frr-ripd:ripd/instance/non-passive-interface", .cbs.cli_show = cli_show_rip_non_passive_interface, }, + { + .xpath = "/frr-ripd:ripd/instance/distribute-list/in/access-list", + .cbs.cli_show = group_distribute_list_ipv4_cli_show, + }, + { + .xpath = "/frr-ripd:ripd/instance/distribute-list/out/access-list", + .cbs.cli_show = group_distribute_list_ipv4_cli_show, + }, + { + .xpath = "/frr-ripd:ripd/instance/distribute-list/in/prefix-list", + .cbs.cli_show = group_distribute_list_ipv4_cli_show, + }, + { + .xpath = "/frr-ripd:ripd/instance/distribute-list/out/prefix-list", + .cbs.cli_show = group_distribute_list_ipv4_cli_show, + }, { .xpath = "/frr-ripd:ripd/instance/redistribute", .cbs.cli_show = cli_show_rip_redistribute, diff --git a/ripd/rip_nb.c b/ripd/rip_nb.c index d5df5916ad..231099d3ac 100644 --- a/ripd/rip_nb.c +++ b/ripd/rip_nb.c @@ -143,7 +143,6 @@ const struct frr_yang_module_info frr_ripd_info = { .cbs = { .modify = group_distribute_list_ipv4_modify, .destroy = group_distribute_list_ipv4_destroy, - .cli_show = group_distribute_list_ipv4_cli_show, } }, { @@ -151,7 +150,6 @@ const struct frr_yang_module_info frr_ripd_info = { .cbs = { .modify = group_distribute_list_ipv4_modify, .destroy = group_distribute_list_ipv4_destroy, - .cli_show = group_distribute_list_ipv4_cli_show, } }, { @@ -159,7 +157,6 @@ const struct frr_yang_module_info frr_ripd_info = { .cbs = { .modify = group_distribute_list_ipv4_modify, .destroy = group_distribute_list_ipv4_destroy, - .cli_show = group_distribute_list_ipv4_cli_show, } }, { @@ -167,7 +164,6 @@ const struct frr_yang_module_info frr_ripd_info = { .cbs = { .modify = group_distribute_list_ipv4_modify, .destroy = group_distribute_list_ipv4_destroy, - .cli_show = group_distribute_list_ipv4_cli_show, } }, { From 850076b3a1fb09b70c8a5da1bd14202238e0e321 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Wed, 7 Aug 2024 17:46:57 +0300 Subject: [PATCH 289/347] tools: Fix python string escape warnings for frr-reload.py When using a regex (or anything that uses `\?` escapes) in python, raw strings (`r"content"`) should be used so python doesn't consume the escapes itself. Otherwise we get either broken behavior and/or `SyntaxWarning: invalid escape sequence '\['` Fixes: 8916953b534f64a7545860ad5b4b36dc2544f33a ("build: fix a few python string escape warnings") Fixes: https://github.com/FRRouting/frr/issues/16522 Signed-off-by: Donatas Abraitis --- tools/frr-reload.py | 50 ++++++++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/tools/frr-reload.py b/tools/frr-reload.py index 342c57964c..a88f6b616d 100755 --- a/tools/frr-reload.py +++ b/tools/frr-reload.py @@ -228,7 +228,7 @@ def get_normalized_interface_vrf(line): correctly and configurations are matched appropriately. """ - intf_vrf = re.search("interface (\S+) vrf (\S+)", line) + intf_vrf = re.search(r"interface (\S+) vrf (\S+)", line) if intf_vrf: old_line = "vrf %s" % intf_vrf.group(2) new_line = line.replace(old_line, "").strip() @@ -894,13 +894,13 @@ def bgp_delete_nbr_remote_as_line(lines_to_add): if ctx_keys[0] in pg_dict: for pg_key in pg_dict[ctx_keys[0]]: # Find 'neighbor remote-as' - pg_rmtas = "neighbor %s remote-as (\S+)" % pg_key + pg_rmtas = r"neighbor %s remote-as (\S+)" % pg_key re_pg_rmtas = re.search(pg_rmtas, line) if re_pg_rmtas: pg_dict[ctx_keys[0]][pg_key]["remoteas"] = True # Find 'neighbor [interface] peer-group ' - nb_pg = "neighbor (\S+) peer-group %s$" % pg_key + nb_pg = r"neighbor (\S+) peer-group %s$" % pg_key re_nbr_pg = re.search(nb_pg, line) if ( re_nbr_pg @@ -918,7 +918,7 @@ def bgp_delete_nbr_remote_as_line(lines_to_add): and line and line.startswith("neighbor ") ): - nbr_rmtas = "neighbor (\S+) remote-as.*" + nbr_rmtas = r"neighbor (\S+) remote-as.*" re_nbr_rmtas = re.search(nbr_rmtas, line) if re_nbr_rmtas and ctx_keys[0] in pg_dict: for pg in pg_dict[ctx_keys[0]]: @@ -947,8 +947,8 @@ def bgp_remove_neighbor_cfg(lines_to_del, del_nbr_dict): ): if ctx_keys[0] in del_nbr_dict: for nbr in del_nbr_dict[ctx_keys[0]]: - re_nbr_pg = re.search("neighbor (\S+) .*peer-group (\S+)", line) - nb_exp = "neighbor %s .*" % nbr + re_nbr_pg = re.search(r"neighbor (\S+) .*peer-group (\S+)", line) + nb_exp = r"neighbor %s .*" % nbr if not re_nbr_pg: re_nb = re.search(nb_exp, line) if re_nb: @@ -1046,7 +1046,7 @@ def bgp_delete_move_lines(lines_to_add, lines_to_del): # neighbor uplink1 interface remote-as internal # # 'no neighbor peer [interface] remote-as <>' - nb_remoteas = "neighbor (\S+) .*remote-as (\S+)" + nb_remoteas = r"neighbor (\S+) .*remote-as (\S+)" re_nb_remoteas = re.search(nb_remoteas, line) if re_nb_remoteas: lines_to_del_to_app.append((ctx_keys, line)) @@ -1054,7 +1054,7 @@ def bgp_delete_move_lines(lines_to_add, lines_to_del): # 'no neighbor peer [interface] peer-group <>' is in lines_to_del # copy the neighbor and look for all config removal lines associated # to neighbor and delete them from the lines_to_del - re_nbr_pg = re.search("neighbor (\S+) .*peer-group (\S+)", line) + re_nbr_pg = re.search(r"neighbor (\S+) .*peer-group (\S+)", line) if re_nbr_pg: if ctx_keys[0] not in del_nbr_dict: del_nbr_dict[ctx_keys[0]] = list() @@ -1093,7 +1093,7 @@ def bgp_delete_move_lines(lines_to_add, lines_to_del): if ctx_keys[0] in del_dict: for pg_key in del_dict[ctx_keys[0]]: # 'neighbor [interface] peer-group ' - nb_pg = "neighbor (\S+) .*peer-group %s$" % pg_key + nb_pg = r"neighbor (\S+) .*peer-group %s$" % pg_key re_nbr_pg = re.search(nb_pg, line) if ( re_nbr_pg @@ -1111,7 +1111,7 @@ def bgp_delete_move_lines(lines_to_add, lines_to_del): if ctx_keys[0] in del_dict: for pg in del_dict[ctx_keys[0]]: for nbr in del_dict[ctx_keys[0]][pg]: - nb_exp = "neighbor %s .*" % nbr + nb_exp = r"neighbor %s .*" % nbr re_nb = re.search(nb_exp, line) # add peer configs to delete list. if re_nb and line not in lines_to_del_to_del: @@ -1151,7 +1151,7 @@ def pim_delete_move_lines(lines_to_add, lines_to_del): # no ip msdp peer <> does not accept source so strip it off. if line and line.startswith("ip msdp peer "): - pim_msdp_peer = re.search("ip msdp peer (\S+) source (\S+)", line) + pim_msdp_peer = re.search(r"ip msdp peer (\S+) source (\S+)", line) if pim_msdp_peer: source_sub_str = "source %s" % pim_msdp_peer.group(2) new_line = line.replace(source_sub_str, "").strip() @@ -1244,10 +1244,10 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del): # # If so then chop the del line and the corresponding add lines re_swpx_int_peergroup = re.search( - "neighbor (\S+) interface peer-group (\S+)", line + r"neighbor (\S+) interface peer-group (\S+)", line ) re_swpx_int_v6only_peergroup = re.search( - "neighbor (\S+) interface v6only peer-group (\S+)", line + r"neighbor (\S+) interface v6only peer-group (\S+)", line ) if re_swpx_int_peergroup or re_swpx_int_v6only_peergroup: @@ -1304,7 +1304,7 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del): if re_nbr_bfd_timers: nbr = re_nbr_bfd_timers.group(1) - bfd_nbr = "neighbor %s" % nbr + bfd_nbr = r"neighbor %s" % nbr bfd_search_string = bfd_nbr + r" bfd (\S+) (\S+) (\S+)" for ctx_keys, add_line in lines_to_add: @@ -1329,13 +1329,13 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del): # they actually match and if we are going from a very old style # command such that the neighbor command is under the `router # bgp ..` node that we need to handle that appropriately - re_nbr_rm = re.search("neighbor(.*)route-map(.*)(in|out)$", line) + re_nbr_rm = re.search(r"neighbor(.*)route-map(.*)(in|out)$", line) if re_nbr_rm: adjust_for_bgp_node = 0 neighbor_name = re_nbr_rm.group(1) rm_name_del = re_nbr_rm.group(2) dir = re_nbr_rm.group(3) - search = "neighbor%sroute-map(.*)%s" % (neighbor_name, dir) + search = r"neighbor%sroute-map(.*)%s" % (neighbor_name, dir) save_line = "EMPTY" for ctx_keys_al, add_line in lines_to_add: if ctx_keys_al[0].startswith("router bgp"): @@ -1388,10 +1388,10 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del): # # If so then chop the del line and the corresponding add lines re_swpx_int_remoteas = re.search( - "neighbor (\S+) interface remote-as (\S+)", line + r"neighbor (\S+) interface remote-as (\S+)", line ) re_swpx_int_v6only_remoteas = re.search( - "neighbor (\S+) interface v6only remote-as (\S+)", line + r"neighbor (\S+) interface v6only remote-as (\S+)", line ) if re_swpx_int_remoteas or re_swpx_int_v6only_remoteas: @@ -1431,7 +1431,7 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del): # unnecessary session resets. if "multipath-relax" in line: re_asrelax_new = re.search( - "^bgp\s+bestpath\s+as-path\s+multipath-relax$", line + r"^bgp\s+bestpath\s+as-path\s+multipath-relax$", line ) old_asrelax_cmd = "bgp bestpath as-path multipath-relax no-as-set" found_asrelax_old = line_exist(lines_to_add, ctx_keys, old_asrelax_cmd) @@ -1456,7 +1456,7 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del): # the new syntax. This causes an unnecessary 'no import-table' followed # by the same old 'ip import-table' which causes perturbations in # announced routes leading to traffic blackholes. Fix this issue. - re_importtbl = re.search("^ip\s+import-table\s+(\d+)$", ctx_keys[0]) + re_importtbl = re.search(r"^ip\s+import-table\s+(\d+)$", ctx_keys[0]) if re_importtbl: table_num = re_importtbl.group(1) for ctx in lines_to_add: @@ -1477,7 +1477,7 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del): # access-list FOO seq 5 permit 2.2.2.2/32 # ipv6 access-list BAR seq 5 permit 2:2:2::2/128 re_acl_pfxlst = re.search( - "^(ip |ipv6 |)(prefix-list|access-list)(\s+\S+\s+)(seq \d+\s+)(permit|deny)(.*)$", + r"^(ip |ipv6 |)(prefix-list|access-list)(\s+\S+\s+)(seq \d+\s+)(permit|deny)(.*)$", ctx_keys[0], ) if re_acl_pfxlst: @@ -1510,7 +1510,7 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del): # bgp large-community-list standard llist seq 5 permit 65001:65001:1 # bgp extcommunity-list standard elist seq 5 permit soo 123:123 re_bgp_lists = re.search( - "^(bgp )(community-list|large-community-list|extcommunity-list)(\s+\S+\s+)(\S+\s+)(seq \d+\s+)(permit|deny)(.*)$", + r"^(bgp )(community-list|large-community-list|extcommunity-list)(\s+\S+\s+)(\S+\s+)(seq \d+\s+)(permit|deny)(.*)$", ctx_keys[0], ) if re_bgp_lists: @@ -1539,7 +1539,7 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del): # Examples: # bgp as-path access-list important_internet_bgp_as_numbers seq 30 permit _40841_" re_bgp_as_path = re.search( - "^(bgp )(as-path )(access-list )(\S+\s+)(seq \d+\s+)(permit|deny)(.*)$", + r"^(bgp )(as-path )(access-list )(\S+\s+)(seq \d+\s+)(permit|deny)(.*)$", ctx_keys[0], ) if re_bgp_as_path: @@ -1569,7 +1569,7 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del): and ctx_keys[2].startswith("vni") ): re_route_target = ( - re.search("^route-target import (.*)$", line) + re.search(r"^route-target import (.*)$", line) if line is not None else False ) @@ -1706,7 +1706,7 @@ def compare_context_objects(newconf, running): pcclist_to_del = [] candidates_to_add = [] delete_bgpd = False - area_stub_no_sum = "area (\S+) stub no-summary" + area_stub_no_sum = r"area (\S+) stub no-summary" deleted_keychains = [] # Find contexts that are in newconf but not in running From 5d027fc79194870d26d14373d5c15f2ea4d58bd5 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Thu, 8 Aug 2024 10:05:45 +0200 Subject: [PATCH 290/347] lib: add seg6localContext json attribute in nexthop information Some srv6 behaviors have a context attached that is visible if no json is requested: > # show ipv6 route > [..] > B>* 2001:db8:1:1:100::/128 [20/0] is directly connected, vrf10, seg6local End.DT6 table 10, weight 1, 00:00:14 > B>* 2001:db8:1:1:200::/128 [20/0] is directly connected, vrf20, seg6local End.DT6 table 20, weight 1, 00:00:14 > The json does not dump this attribute: > # show ipv6 route 2001:db8:1:1:100::/128 json > [..] > "nexthops":[ > { > "flags":3, > "fib":true, > "directlyConnected":true, > "interfaceIndex":6, > "interfaceName":"vrf10", > "active":true, > "weight":1, > "seg6local":{ > "action":"End.DT6" > }, > } > Add the json support for this. > "nexthops":[ > { > "flags":3, > "fib":true, > "directlyConnected":true, > "interfaceIndex":6, > "interfaceName":"vrf10", > "active":true, > "weight":1, > "seg6local":{ > "action":"End.DT6" > }, > "seg6localContext":{ > "table":10 > } > } > Signed-off-by: Philippe Guibert --- lib/nexthop.c | 9 +++++++++ lib/srv6.c | 38 ++++++++++++++++++++++++++++++++++++++ lib/srv6.h | 2 ++ 3 files changed, 49 insertions(+) diff --git a/lib/nexthop.c b/lib/nexthop.c index 26c338256f..65c12c1e69 100644 --- a/lib/nexthop.c +++ b/lib/nexthop.c @@ -1166,6 +1166,7 @@ void nexthop_json_helper(json_object *json_nexthop, json_object *json_labels = NULL; json_object *json_backups = NULL; json_object *json_seg6local = NULL; + json_object *json_seg6local_context = NULL; json_object *json_seg6 = NULL; json_object *json_segs = NULL; int i; @@ -1331,8 +1332,16 @@ void nexthop_json_helper(json_object *json_nexthop, seg6local_action2str( nexthop->nh_srv6 ->seg6local_action)); + json_seg6local_context = json_object_new_object(); json_object_object_add(json_nexthop, "seg6local", json_seg6local); + + seg6local_context2json(&nexthop->nh_srv6->seg6local_ctx, + nexthop->nh_srv6->seg6local_action, + json_seg6local_context); + json_object_object_add(json_nexthop, "seg6localContext", + json_seg6local_context); + if (nexthop->nh_srv6->seg6_segs && nexthop->nh_srv6->seg6_segs->num_segs == 1) { json_seg6 = json_object_new_object(); diff --git a/lib/srv6.c b/lib/srv6.c index 883d429b62..e6fc375fbb 100644 --- a/lib/srv6.c +++ b/lib/srv6.c @@ -71,6 +71,44 @@ int snprintf_seg6_segs(char *str, return strlen(str); } +void seg6local_context2json(const struct seg6local_context *ctx, + uint32_t action, json_object *json) +{ + switch (action) { + case ZEBRA_SEG6_LOCAL_ACTION_END: + json_object_boolean_add(json, "USP", true); + return; + case ZEBRA_SEG6_LOCAL_ACTION_END_X: + case ZEBRA_SEG6_LOCAL_ACTION_END_DX6: + json_object_string_addf(json, "nh6", "%pI6", &ctx->nh6); + return; + case ZEBRA_SEG6_LOCAL_ACTION_END_DX4: + json_object_string_addf(json, "nh4", "%pI4", &ctx->nh4); + return; + case ZEBRA_SEG6_LOCAL_ACTION_END_T: + case ZEBRA_SEG6_LOCAL_ACTION_END_DT6: + case ZEBRA_SEG6_LOCAL_ACTION_END_DT4: + case ZEBRA_SEG6_LOCAL_ACTION_END_DT46: + json_object_int_add(json, "table", ctx->table); + return; + case ZEBRA_SEG6_LOCAL_ACTION_END_DX2: + json_object_boolean_add(json, "none", true); + return; + case ZEBRA_SEG6_LOCAL_ACTION_END_B6: + case ZEBRA_SEG6_LOCAL_ACTION_END_B6_ENCAP: + json_object_string_addf(json, "nh6", "%pI6", &ctx->nh6); + return; + case ZEBRA_SEG6_LOCAL_ACTION_END_BM: + case ZEBRA_SEG6_LOCAL_ACTION_END_S: + case ZEBRA_SEG6_LOCAL_ACTION_END_AS: + case ZEBRA_SEG6_LOCAL_ACTION_END_AM: + case ZEBRA_SEG6_LOCAL_ACTION_UNSPEC: + default: + json_object_boolean_add(json, "unknown", true); + return; + } +} + const char *seg6local_context2str(char *str, size_t size, const struct seg6local_context *ctx, uint32_t action) diff --git a/lib/srv6.h b/lib/srv6.h index 01b0820133..03ada7fcfc 100644 --- a/lib/srv6.h +++ b/lib/srv6.h @@ -319,6 +319,8 @@ seg6local_action2str(uint32_t action); const char *seg6local_context2str(char *str, size_t size, const struct seg6local_context *ctx, uint32_t action); +void seg6local_context2json(const struct seg6local_context *ctx, + uint32_t action, json_object *json); static inline const char *srv6_sid_ctx2str(char *str, size_t size, const struct srv6_sid_ctx *ctx) From 5891afb8246a860b70f60a5cf39dcd3a357eb663 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Thu, 8 Aug 2024 12:01:14 -0400 Subject: [PATCH 291/347] sharpd: Eliminate leaked list for locator-chunks Signed-off-by: Donald Sharp --- sharpd/sharp_main.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sharpd/sharp_main.c b/sharpd/sharp_main.c index f4ce147978..2e72a4b990 100644 --- a/sharpd/sharp_main.c +++ b/sharpd/sharp_main.c @@ -65,9 +65,18 @@ static void sharp_global_init(void) sg.srv6_locators = list_new(); } +static void sharp_srv6_locators_list_delete(void *item) +{ + struct sharp_srv6_locator *loc = item; + + list_delete(&loc->chunks); +} + static void sharp_global_destroy(void) { list_delete(&sg.nhs); + + sg.srv6_locators->del = sharp_srv6_locators_list_delete; list_delete(&sg.srv6_locators); } From b44972b65c86a99d2c29f75b04efc0a1becdaf85 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Thu, 8 Aug 2024 13:09:34 -0400 Subject: [PATCH 292/347] isisd: Free up memory associated with rm/vrf's Signed-off-by: Donald Sharp --- isisd/isis_main.c | 5 +++++ isisd/isis_zebra.c | 1 - 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/isisd/isis_main.c b/isisd/isis_main.c index 8dd3a97aa1..7270e37e28 100644 --- a/isisd/isis_main.c +++ b/isisd/isis_main.c @@ -103,6 +103,11 @@ static __attribute__((__noreturn__)) void terminate(int i) isis_sr_term(); isis_srv6_term(); isis_zebra_stop(); + + route_map_finish(); + vrf_terminate(); + + frr_fini(); exit(i); } diff --git a/isisd/isis_zebra.c b/isisd/isis_zebra.c index ce4eb74ec6..caf7d3ddfb 100644 --- a/isisd/isis_zebra.c +++ b/isisd/isis_zebra.c @@ -1628,5 +1628,4 @@ void isis_zebra_stop(void) zclient_free(zclient_sync); zclient_stop(zclient); zclient_free(zclient); - frr_fini(); } From 2e7d915ca292dae09b95f31fb52b21b8b935c5dc Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Thu, 8 Aug 2024 13:17:42 -0400 Subject: [PATCH 293/347] isisd: Cleanup leaked hash on shut in circuit Signed-off-by: Donald Sharp --- isisd/isis_circuit.c | 4 ++-- isisd/isis_lfa.c | 6 +++--- isisd/isis_lfa.h | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c index 7819b20e8f..fa1ce3007f 100644 --- a/isisd/isis_circuit.c +++ b/isisd/isis_circuit.c @@ -198,8 +198,8 @@ void isis_circuit_del(struct isis_circuit *circuit) ldp_sync_info_free(&circuit->ldp_sync_info); circuit_mt_finish(circuit); - isis_lfa_excluded_ifaces_clear(circuit, ISIS_LEVEL1); - isis_lfa_excluded_ifaces_clear(circuit, ISIS_LEVEL2); + isis_lfa_excluded_ifaces_delete(circuit, ISIS_LEVEL1); + isis_lfa_excluded_ifaces_delete(circuit, ISIS_LEVEL2); list_delete(&circuit->ip_addrs); list_delete(&circuit->ipv6_link); diff --git a/isisd/isis_lfa.c b/isisd/isis_lfa.c index dc8f0b96c0..887f27eec5 100644 --- a/isisd/isis_lfa.c +++ b/isisd/isis_lfa.c @@ -238,10 +238,10 @@ void isis_lfa_excluded_ifaces_init(struct isis_circuit *circuit, int level) * * @param nodes List of SPF nodes */ -void isis_lfa_excluded_ifaces_clear(struct isis_circuit *circuit, int level) +void isis_lfa_excluded_ifaces_delete(struct isis_circuit *circuit, int level) { - hash_clean(circuit->lfa_excluded_ifaces[level - 1], - lfa_excl_interface_hash_free); + hash_clean_and_free(&circuit->lfa_excluded_ifaces[level - 1], + lfa_excl_interface_hash_free); } /** diff --git a/isisd/isis_lfa.h b/isisd/isis_lfa.h index 0ba1c1cef5..58ff115b02 100644 --- a/isisd/isis_lfa.h +++ b/isisd/isis_lfa.h @@ -133,7 +133,7 @@ struct lfa_tiebreaker *isis_lfa_tiebreaker_add(struct isis_area *area, void isis_lfa_tiebreaker_delete(struct isis_area *area, int level, struct lfa_tiebreaker *tie_b); void isis_lfa_excluded_ifaces_init(struct isis_circuit *circuit, int level); -void isis_lfa_excluded_ifaces_clear(struct isis_circuit *circuit, int level); +void isis_lfa_excluded_ifaces_delete(struct isis_circuit *circuit, int level); void isis_lfa_excluded_iface_add(struct isis_circuit *circuit, int level, const char *ifname); void isis_lfa_excluded_iface_delete(struct isis_circuit *circuit, int level, From bc16c8ce8d928e4f59f106a4beea0b29fdbe4b44 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Thu, 8 Aug 2024 13:52:37 -0400 Subject: [PATCH 294/347] isisd: Free up isis master list of instances Signed-off-by: Donald Sharp --- isisd/isis_main.c | 1 + isisd/isisd.c | 5 +++++ isisd/isisd.h | 1 + 3 files changed, 7 insertions(+) diff --git a/isisd/isis_main.c b/isisd/isis_main.c index 7270e37e28..b7ed8f7605 100644 --- a/isisd/isis_main.c +++ b/isisd/isis_main.c @@ -104,6 +104,7 @@ static __attribute__((__noreturn__)) void terminate(int i) isis_srv6_term(); isis_zebra_stop(); + isis_master_terminate(); route_map_finish(); vrf_terminate(); diff --git a/isisd/isisd.c b/isisd/isisd.c index e67f5fb1c8..2863fd913f 100644 --- a/isisd/isisd.c +++ b/isisd/isisd.c @@ -176,6 +176,11 @@ void isis_master_init(struct event_loop *master) im->master = master; } +void isis_master_terminate(void) +{ + list_delete(&im->isis); +} + struct isis *isis_new(const char *vrf_name) { struct vrf *vrf; diff --git a/isisd/isisd.h b/isisd/isisd.h index 2ed7dd0f10..1ae39f0ae9 100644 --- a/isisd/isisd.h +++ b/isisd/isisd.h @@ -268,6 +268,7 @@ DECLARE_HOOK(isis_area_overload_bit_update, (struct isis_area * area), (area)); void isis_terminate(void); void isis_master_init(struct event_loop *master); +void isis_master_terminate(void); void isis_vrf_link(struct isis *isis, struct vrf *vrf); void isis_vrf_unlink(struct isis *isis, struct vrf *vrf); struct isis *isis_lookup_by_vrfid(vrf_id_t vrf_id); From db986aded4eb6b3bd76010c196378f43b6e02015 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Thu, 8 Aug 2024 13:54:12 -0400 Subject: [PATCH 295/347] lib: Cleanup memory associated with modules on shutdown Signed-off-by: Donald Sharp --- lib/libfrr.c | 2 ++ lib/module.c | 12 ++++++++++++ lib/module.h | 1 + 3 files changed, 15 insertions(+) diff --git a/lib/libfrr.c b/lib/libfrr.c index 328c6ec8b2..8ea38368b7 100644 --- a/lib/libfrr.c +++ b/lib/libfrr.c @@ -1267,6 +1267,8 @@ void frr_fini(void) /* frrmod_init -> nothing needed / hooks */ rcu_shutdown(); + frrmod_terminate(); + /* also log memstats to stderr when stderr goes to a file*/ if (debug_memstats_at_exit || !isatty(STDERR_FILENO)) have_leftovers = log_memstats(stderr, di->name); diff --git a/lib/module.c b/lib/module.c index af7d20c3da..9d178bb0e4 100644 --- a/lib/module.c +++ b/lib/module.c @@ -202,3 +202,15 @@ void frrmod_unload(struct frrmod_runtime *module) { } #endif + +void frrmod_terminate(void) +{ + struct frrmod_runtime *rtinfo = frrmod_list; + + while (rtinfo) { + XFREE(MTYPE_MODULE_LOADNAME, rtinfo->load_name); + XFREE(MTYPE_MODULE_LOADARGS, rtinfo->load_args); + + rtinfo = rtinfo->next; + } +} diff --git a/lib/module.h b/lib/module.h index cd2be474e7..1810b335f6 100644 --- a/lib/module.h +++ b/lib/module.h @@ -79,6 +79,7 @@ extern union _frrmod_runtime_u _frrmod_this_module; extern struct frrmod_runtime *frrmod_list; extern void frrmod_init(struct frrmod_runtime *modinfo); +extern void frrmod_terminate(void); extern struct frrmod_runtime *frrmod_load(const char *spec, const char *dir, void (*pFerrlog)(const void *, const char *), From 208c53c90e06843b741839c65cb438764ecd5e4d Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Thu, 8 Aug 2024 14:04:42 -0400 Subject: [PATCH 296/347] isisd, lib: Cleanup linked list associated with snmp Signed-off-by: Donald Sharp --- isisd/isis_snmp.c | 8 ++++++++ lib/agentx.c | 5 +++++ lib/smux.h | 1 + 3 files changed, 14 insertions(+) diff --git a/isisd/isis_snmp.c b/isisd/isis_snmp.c index f9e3780e29..83a06b6998 100644 --- a/isisd/isis_snmp.c +++ b/isisd/isis_snmp.c @@ -2826,6 +2826,13 @@ static int isis_snmp_init(struct event_loop *tm) return 0; } +static int isis_snmp_terminate(void) +{ + smux_terminate(); + + return 0; +} + /* * ISIS notification functions: we have one function per notification */ @@ -3448,6 +3455,7 @@ static int isis_snmp_module_init(void) hook_register(isis_circuit_del_hook, isis_circuit_snmp_id_free); hook_register(frr_late_init, isis_snmp_init); + hook_register(frr_fini, isis_snmp_terminate); return 0; } diff --git a/lib/agentx.c b/lib/agentx.c index 19f2a6b7fc..2e621d06a4 100644 --- a/lib/agentx.c +++ b/lib/agentx.c @@ -377,4 +377,9 @@ void smux_events_update(void) agentx_events_update(); } +void smux_terminate(void) +{ + if (events) + list_delete(&events); +} #endif /* SNMP_AGENTX */ diff --git a/lib/smux.h b/lib/smux.h index 8ec847afd0..0ed41410f5 100644 --- a/lib/smux.h +++ b/lib/smux.h @@ -101,6 +101,7 @@ extern bool smux_enabled(void); extern void libagentx_init(void); extern void smux_init(struct event_loop *tm); +extern void smux_terminate(void); extern void smux_agentx_enable(void); extern void smux_register_mib(const char *, struct variable *, size_t, int, oid[], size_t); From cecf5716d5c8e74aa5afaeec836db624d6f68879 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Thu, 8 Aug 2024 14:58:04 -0400 Subject: [PATCH 297/347] lib: Don't print warning if not a daemon vtysh will print out the `stupidly large FD limit` upon every run of the program if the ulimit is set stupidly large. Prevent this from being displayed for vtysh. Fixes: #16516 Signed-off-by: Donald Sharp --- lib/event.c | 5 +++-- lib/libfrr.c | 8 ++++++++ lib/libfrr.h | 2 +- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/lib/event.c b/lib/event.c index f4aa7c58b9..d925d0d5f0 100644 --- a/lib/event.c +++ b/lib/event.c @@ -555,8 +555,9 @@ struct event_loop *event_master_create(const char *name) } if (rv->fd_limit > STUPIDLY_LARGE_FD_SIZE) { - zlog_warn("FD Limit set: %u is stupidly large. Is this what you intended? Consider using --limit-fds also limiting size to %u", - rv->fd_limit, STUPIDLY_LARGE_FD_SIZE); + if (frr_is_daemon()) + zlog_warn("FD Limit set: %u is stupidly large. Is this what you intended? Consider using --limit-fds also limiting size to %u", + rv->fd_limit, STUPIDLY_LARGE_FD_SIZE); rv->fd_limit = STUPIDLY_LARGE_FD_SIZE; } diff --git a/lib/libfrr.c b/lib/libfrr.c index 328c6ec8b2..2a973c9106 100644 --- a/lib/libfrr.c +++ b/lib/libfrr.c @@ -1474,3 +1474,11 @@ const char *frr_vers2str(uint32_t version, char *buf, int buflen) return buf; } + +bool frr_is_daemon(void) +{ + if (di) + return true; + + return false; +} diff --git a/lib/libfrr.h b/lib/libfrr.h index 3248670c83..7ed7be4d98 100644 --- a/lib/libfrr.h +++ b/lib/libfrr.h @@ -190,7 +190,7 @@ extern const char *frr_get_progname(void); extern enum frr_cli_mode frr_get_cli_mode(void); extern uint32_t frr_get_fd_limit(void); extern bool frr_is_startup_fd(int fd); - +extern bool frr_is_daemon(void); /* call order of these hooks is as ordered here */ DECLARE_HOOK(frr_early_init, (struct event_loop * tm), (tm)); DECLARE_HOOK(frr_late_init, (struct event_loop * tm), (tm)); From 3eb7d1641166872591554519607483f6d77657f5 Mon Sep 17 00:00:00 2001 From: Mark Stapp Date: Fri, 9 Aug 2024 10:08:21 -0400 Subject: [PATCH 298/347] isisd: fix memory handling in isis_adj_process_threeway() The adj_process_threeway() api may call the adj_state_change() api, which may delete the adj struct being examined. Change the signature so that callers pass a ptr-to-ptr so that they will see that deletion. Signed-off-by: Mark Stapp --- isisd/isis_adjacency.c | 8 ++++---- isisd/isis_adjacency.h | 2 +- isisd/isis_pdu.c | 16 ++++++++-------- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/isisd/isis_adjacency.c b/isisd/isis_adjacency.c index 3ed6fe95f5..078280acf5 100644 --- a/isisd/isis_adjacency.c +++ b/isisd/isis_adjacency.c @@ -231,11 +231,12 @@ static void isis_adj_route_switchover(struct isis_adjacency *adj) } } -void isis_adj_process_threeway(struct isis_adjacency *adj, +void isis_adj_process_threeway(struct isis_adjacency **padj, struct isis_threeway_adj *tw_adj, enum isis_adj_usage adj_usage) { enum isis_threeway_state next_tw_state = ISIS_THREEWAY_DOWN; + struct isis_adjacency *adj = *padj; if (tw_adj && !adj->circuit->disable_threeway_adj) { if (tw_adj->state == ISIS_THREEWAY_DOWN) { @@ -265,14 +266,13 @@ void isis_adj_process_threeway(struct isis_adjacency *adj, fabricd_initial_sync_hello(adj->circuit); if (next_tw_state == ISIS_THREEWAY_DOWN) { - isis_adj_state_change(&adj, ISIS_ADJ_DOWN, - "Neighbor restarted"); + isis_adj_state_change(padj, ISIS_ADJ_DOWN, "Neighbor restarted"); return; } if (next_tw_state == ISIS_THREEWAY_UP) { if (adj->adj_state != ISIS_ADJ_UP) { - isis_adj_state_change(&adj, ISIS_ADJ_UP, NULL); + isis_adj_state_change(padj, ISIS_ADJ_UP, NULL); adj->adj_usage = adj_usage; } } diff --git a/isisd/isis_adjacency.h b/isisd/isis_adjacency.h index b5c7dd8d73..0ad36e4c5f 100644 --- a/isisd/isis_adjacency.h +++ b/isisd/isis_adjacency.h @@ -111,7 +111,7 @@ struct isis_adjacency *isis_adj_find(const struct isis_area *area, int level, struct isis_adjacency *isis_new_adj(const uint8_t *id, const uint8_t *snpa, int level, struct isis_circuit *circuit); void isis_delete_adj(void *adj); -void isis_adj_process_threeway(struct isis_adjacency *adj, +void isis_adj_process_threeway(struct isis_adjacency **padj, struct isis_threeway_adj *tw_adj, enum isis_adj_usage adj_usage); DECLARE_HOOK(isis_adj_state_change_hook, (struct isis_adjacency *adj), (adj)); diff --git a/isisd/isis_pdu.c b/isisd/isis_pdu.c index 5be317018e..23238d314a 100644 --- a/isisd/isis_pdu.c +++ b/isisd/isis_pdu.c @@ -281,14 +281,14 @@ static int process_p2p_hello(struct iih_info *iih) if (iih->calculated_type == IS_LEVEL_1) { switch (iih->circ_type) { case IS_LEVEL_1: - isis_adj_process_threeway(adj, tw_adj, + isis_adj_process_threeway(&adj, tw_adj, iih->calculated_type); break; case IS_LEVEL_1_AND_2: if ((adj->adj_state != ISIS_ADJ_UP) || (adj->adj_usage == ISIS_ADJ_LEVEL1) || (adj->adj_usage == ISIS_ADJ_LEVEL1AND2)) { - isis_adj_process_threeway(adj, tw_adj, + isis_adj_process_threeway(&adj, tw_adj, iih->calculated_type); } break; @@ -301,7 +301,7 @@ static int process_p2p_hello(struct iih_info *iih) case IS_LEVEL_1: if (adj->adj_state != ISIS_ADJ_UP || adj->adj_usage == ISIS_ADJ_LEVEL1) { - isis_adj_process_threeway(adj, tw_adj, + isis_adj_process_threeway(&adj, tw_adj, iih->calculated_type); } else if ((adj->adj_usage == ISIS_ADJ_LEVEL2) || (adj->adj_usage == @@ -315,7 +315,7 @@ static int process_p2p_hello(struct iih_info *iih) case IS_LEVEL_2: if (adj->adj_state != ISIS_ADJ_UP || adj->adj_usage == ISIS_ADJ_LEVEL2) { - isis_adj_process_threeway(adj, tw_adj, + isis_adj_process_threeway(&adj, tw_adj, iih->calculated_type); } else if ((adj->adj_usage == ISIS_ADJ_LEVEL1) || (adj->adj_usage == @@ -329,7 +329,7 @@ static int process_p2p_hello(struct iih_info *iih) case IS_LEVEL_1_AND_2: if (adj->adj_state != ISIS_ADJ_UP || adj->adj_usage == ISIS_ADJ_LEVEL1AND2) { - isis_adj_process_threeway(adj, tw_adj, + isis_adj_process_threeway(&adj, tw_adj, iih->calculated_type); } else if ((adj->adj_usage == ISIS_ADJ_LEVEL1) || (adj->adj_usage == ISIS_ADJ_LEVEL2)) { @@ -349,12 +349,12 @@ static int process_p2p_hello(struct iih_info *iih) if (adj->adj_state != ISIS_ADJ_UP || adj->adj_usage == ISIS_ADJ_LEVEL2 || adj->adj_usage == ISIS_ADJ_LEVEL1AND2) { - isis_adj_process_threeway(adj, tw_adj, + isis_adj_process_threeway(&adj, tw_adj, iih->calculated_type); } break; case IS_LEVEL_2: - isis_adj_process_threeway(adj, tw_adj, + isis_adj_process_threeway(&adj, tw_adj, iih->calculated_type); break; } @@ -401,7 +401,7 @@ static int process_p2p_hello(struct iih_info *iih) case IS_LEVEL_2: if (adj->adj_state != ISIS_ADJ_UP || adj->adj_usage == ISIS_ADJ_LEVEL2) { - isis_adj_process_threeway(adj, tw_adj, + isis_adj_process_threeway(&adj, tw_adj, iih->calculated_type); } else if (adj->adj_usage == ISIS_ADJ_LEVEL1) { /* (7) down - wrong system */ From 8b66a236e849e3cca4b02c92a7fbe5f2bf0f97a1 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Fri, 9 Aug 2024 16:32:02 +0300 Subject: [PATCH 299/347] bgpd: Reduce encap_tunneltype to 1 byte It's not used as a bitmask, no point to use it as 2 bytes. Signed-off-by: Donatas Abraitis --- bgpd/bgp_attr.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h index 3519dc3401..34393a0f1b 100644 --- a/bgpd/bgp_attr.h +++ b/bgpd/bgp_attr.h @@ -293,7 +293,7 @@ struct attr { /* EVPN local router-mac */ struct ethaddr rmac; - uint16_t encap_tunneltype; + uint8_t encap_tunneltype; /* rmap set table */ uint32_t rmap_table_id; From 5c84cddab8ec7fd4343ed7bc2c7602b01d4f6846 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Fri, 9 Aug 2024 16:33:52 +0300 Subject: [PATCH 300/347] bgpd: Shrink rmap_change_flags to 2-bytes 4 bytes is not needed for this thing clearly. Signed-off-by: Donatas Abraitis --- bgpd/bgp_attr.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h index 34393a0f1b..561024e7c8 100644 --- a/bgpd/bgp_attr.h +++ b/bgpd/bgp_attr.h @@ -209,7 +209,7 @@ struct attr { /* has the route-map changed any attribute? Used on the peer outbound side. */ - uint32_t rmap_change_flags; + uint16_t rmap_change_flags; /* Multi-Protocol Nexthop, AFI IPv6 */ struct in6_addr mp_nexthop_global; From 8fad4f317ebd3de7677d7600e7a024f713b20d70 Mon Sep 17 00:00:00 2001 From: Igor Ryzhov Date: Sat, 10 Aug 2024 01:32:55 +0300 Subject: [PATCH 301/347] lib: fix distribute-list deletion When a whole distribute-list is deleted (can be done only using API), all its children must be cleaned up manually. Fixes #16538 Signed-off-by: Igor Ryzhov --- lib/distribute.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/lib/distribute.c b/lib/distribute.c index 90a73c3635..c0693b0849 100644 --- a/lib/distribute.c +++ b/lib/distribute.c @@ -456,10 +456,43 @@ int group_distribute_list_create_helper( * XPath: /frr-ripd:ripd/instance/distribute-lists/distribute-list/{in,out}/{access,prefix}-list */ +static int distribute_list_leaf_update(const struct lyd_node *dnode, + int ip_version, bool no); + int group_distribute_list_destroy(struct nb_cb_destroy_args *args) { + struct lyd_node *dnode; + if (args->event != NB_EV_APPLY) return NB_OK; + + /* + * We don't keep the IP version of distribute-list anywhere, so we're + * trying to remove both. If one doesn't exist, it's simply skipped by + * the remove function. + */ + + dnode = yang_dnode_get(args->dnode, "in/access-list"); + if (dnode) { + distribute_list_leaf_update(dnode, 4, true); + distribute_list_leaf_update(dnode, 6, true); + } + dnode = yang_dnode_get(args->dnode, "in/prefix-list"); + if (dnode) { + distribute_list_leaf_update(dnode, 4, true); + distribute_list_leaf_update(dnode, 6, true); + } + dnode = yang_dnode_get(args->dnode, "out/access-list"); + if (dnode) { + distribute_list_leaf_update(dnode, 4, true); + distribute_list_leaf_update(dnode, 6, true); + } + dnode = yang_dnode_get(args->dnode, "out/prefix-list"); + if (dnode) { + distribute_list_leaf_update(dnode, 4, true); + distribute_list_leaf_update(dnode, 6, true); + } + nb_running_unset_entry(args->dnode); return NB_OK; } From 87c9060f90b6b9b5a69ad1e6ba6e8ebc58d94374 Mon Sep 17 00:00:00 2001 From: "Lu.Mao" Date: Thu, 1 Aug 2024 09:54:14 +0800 Subject: [PATCH 302/347] lib: Fix LYD_NEW_PATH_OUTPUT issue to support libyang v3.x Fix the LYD_NEW_PATH_OUTPUT undeclared error to support the latest libyang v3.x version, and also compatible with old version. Signed-off-by: Lu Mao --- lib/yang.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/yang.c b/lib/yang.c index 44459df4a5..6a8e5223a0 100644 --- a/lib/yang.c +++ b/lib/yang.c @@ -25,6 +25,11 @@ DEFINE_MTYPE_STATIC(LIB, YANG_DATA, "YANG data structure"); #define yang_lyd_find_xpath3(ctx_node, tree, xpath, format, prefix_data, vars, \ set) \ lyd_find_xpath3(ctx_node, tree, xpath, vars, set) + +#ifndef LYD_NEW_VAL_OUTPUT +#define LYD_NEW_VAL_OUTPUT LYD_NEW_PATH_OUTPUT +#endif + #else #define yang_lyd_find_xpath3(ctx_node, tree, xpath, format, prefix_data, vars, \ set) \ @@ -671,7 +676,7 @@ void yang_dnode_rpc_output_add(struct lyd_node *output, const char *xpath, LY_ERR err; err = lyd_new_path(output, ly_native_ctx, xpath, value, - LYD_NEW_PATH_OUTPUT | LYD_NEW_PATH_UPDATE, NULL); + LYD_NEW_VAL_OUTPUT | LYD_NEW_PATH_UPDATE, NULL); assert(err == LY_SUCCESS); } From 5a1b61aeba1b83825e1656a047aab35be0c1db55 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Sat, 10 Aug 2024 19:43:08 -0400 Subject: [PATCH 303/347] zebra: Ensure non-equal id's are not same nhg's The function zebra_nhg_hash_equal is only used as a hash function for storage of NHG's and retrieval. If you have say two nhg's: 31 (25/26) 32 (25/26) This function would return them as being equal. Which of course leads to the problem when you attempt to hash_release 32 but release 31 from the hash. Then later when you attempt to do hash comparisons 32 has actually been freed leaving to use after free situations and shit goes down hill fast. This hash is only used as part of the hash comparison function for nexthop group storage. Since this is so let's always return the 31/32 nhg's are not equal at all. We possibly have a different problem where we are creating 31 and 32 ( when 31 should have just been used instead of 32 ) but we need to prevent any type of hash release problem at all. This supercedes any other issue( that should be tracked down on it's own ). Since you can have use after free situation that leads to a crash -vs- some possible nexthop group duplication which is very minor in comparison. Signed-off-by: Donald Sharp --- zebra/zebra_nhg.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index b4e25daad8..8164e2a56f 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -525,9 +525,18 @@ bool zebra_nhg_hash_equal(const void *arg1, const void *arg2) struct nexthop *nexthop1; struct nexthop *nexthop2; - /* No matter what if they equal IDs, assume equal */ - if (nhe1->id && nhe2->id && (nhe1->id == nhe2->id)) - return true; + /* If both NHG's have id's then we can just know that + * they are either identical or not. This comparison + * is only ever used for hash equality. NHE's id + * is sufficient to distinguish them. This is especially + * true if NHG's are owned by an upper level protocol. + */ + if (nhe1->id && nhe2->id) { + if (nhe1->id == nhe2->id) + return true; + + return false; + } if (nhe1->type != nhe2->type) return false; From 0ec96ab52589327ef8236a6787a20e4b7688210f Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Sat, 10 Aug 2024 20:21:27 -0400 Subject: [PATCH 304/347] mgmtd: Add to .gitignore for mgmtd_testc program This program, mgmtd_testc, is built with the --enable-mgmtd-test-be-client configure option but it is not .gitignore'd. Let's fix that Signed-off-by: Donald Sharp --- mgmtd/.gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/mgmtd/.gitignore b/mgmtd/.gitignore index 7ce107e93b..e12bcc08cd 100644 --- a/mgmtd/.gitignore +++ b/mgmtd/.gitignore @@ -1 +1,2 @@ mgmtd +mgmtd_testc From 79cbde8095ec3f8f20be63f518b29d47b24101d2 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Sun, 11 Aug 2024 12:51:53 +0300 Subject: [PATCH 305/347] tests: Convert self.unified_config to boolean Signed-off-by: Donatas Abraitis --- tests/topotests/lib/topotest.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/topotests/lib/topotest.py b/tests/topotests/lib/topotest.py index 1d4bc2eac6..5a8c2e5964 100644 --- a/tests/topotests/lib/topotest.py +++ b/tests/topotests/lib/topotest.py @@ -1430,7 +1430,7 @@ def __init__(self, name, *posargs, **params): self.daemondir = None self.hasmpls = False self.routertype = "frr" - self.unified_config = None + self.unified_config = False self.daemons = { "zebra": 0, "ripd": 0, @@ -1653,7 +1653,7 @@ def loadConf(self, daemon, source=None, param=None): # print "Daemons before:", self.daemons if daemon in self.daemons.keys() or daemon == "frr": if daemon == "frr": - self.unified_config = 1 + self.unified_config = True else: self.daemons[daemon] = 1 if param is not None: From 3901cfea2335f1a1bee493cfad616e8db4ce8340 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Sun, 11 Aug 2024 13:47:08 +0300 Subject: [PATCH 306/347] doc: Document on how to run specific daemons with unified config in topotests Signed-off-by: Donatas Abraitis --- doc/developer/topotests.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/doc/developer/topotests.rst b/doc/developer/topotests.rst index 586c096740..66946f6c37 100644 --- a/doc/developer/topotests.rst +++ b/doc/developer/topotests.rst @@ -1332,6 +1332,15 @@ Example: router.load_config(TopoRouter.RD_ZEBRA, "zebra.conf") router.load_config(TopoRouter.RD_OSPF) +or using unified config (specifying which daemons to run is optional): + +.. code:: py + + for _, (rname, router) in enumerate(router_list.items(), 1): + router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname)), [ + TopoRouter.RD_ZEBRA + TopoRouter.RD_MGMTD, + TopoRouter.RD_BGP]) - The topology definition or build function From 4ace11d0101450d6e3ae6be26cdb07313e171a46 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Sun, 11 Aug 2024 13:59:13 +0300 Subject: [PATCH 307/347] bgpd: Move evpn_overlay to a pointer Before this convertion: ``` /* --- cacheline 3 boundary (192 bytes) --- */ struct bgp_attr_encap_subtlv * encap_subtlvs; /* 192 8 */ struct bgp_attr_encap_subtlv * vnc_subtlvs; /* 200 8 */ struct bgp_route_evpn evpn_overlay; /* 208 36 */ ``` After this convertion: ``` /* --- cacheline 3 boundary (192 bytes) --- */ struct bgp_attr_encap_subtlv * encap_subtlvs; /* 192 8 */ struct bgp_attr_encap_subtlv * vnc_subtlvs; /* 200 8 */ struct bgp_route_evpn * evpn_overlay; /* 208 8 */ ``` Saving 28 bytes when EVPN is not used. Signed-off-by: Donatas Abraitis --- bgpd/bgp_attr.c | 102 +++++++++++++++++++++++++++++ bgpd/bgp_attr.h | 10 +-- bgpd/bgp_attr_evpn.c | 7 ++ bgpd/bgp_attr_evpn.h | 1 + bgpd/bgp_evpn.c | 126 ++++++++++++++++++------------------ bgpd/bgp_evpn_mh.c | 6 +- bgpd/bgp_flowspec.c | 2 +- bgpd/bgp_label.c | 2 +- bgpd/bgp_mac.c | 7 +- bgpd/bgp_memory.c | 2 + bgpd/bgp_memory.h | 2 + bgpd/bgp_mplsvpn.c | 2 +- bgpd/bgp_nht.c | 4 +- bgpd/bgp_route.c | 63 ++++++++++-------- bgpd/bgp_route.h | 3 +- bgpd/bgp_routemap.c | 8 ++- bgpd/bgp_updgrp_packet.c | 3 +- bgpd/bgp_zebra.c | 14 ++-- bgpd/rfapi/vnc_export_bgp.c | 46 ++++++------- 19 files changed, 265 insertions(+), 145 deletions(-) diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index ac5d08b6fe..e85918bf53 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -198,6 +198,7 @@ static struct hash *vnc_hash = NULL; #endif static struct hash *srv6_l3vpn_hash; static struct hash *srv6_vpn_hash; +static struct hash *evpn_overlay_hash; struct bgp_attr_encap_subtlv *encap_tlv_dup(struct bgp_attr_encap_subtlv *orig) { @@ -549,6 +550,81 @@ static bool bgp_attr_aigp_valid(uint8_t *pnt, int length) return true; } +static void *evpn_overlay_hash_alloc(void *p) +{ + return p; +} + +static void evpn_overlay_free(struct bgp_route_evpn *bre) +{ + XFREE(MTYPE_BGP_EVPN_OVERLAY, bre); +} + +static struct bgp_route_evpn *evpn_overlay_intern(struct bgp_route_evpn *bre) +{ + struct bgp_route_evpn *find; + + find = hash_get(evpn_overlay_hash, bre, evpn_overlay_hash_alloc); + if (find != bre) + evpn_overlay_free(bre); + find->refcnt++; + return find; +} + +static void evpn_overlay_unintern(struct bgp_route_evpn **brep) +{ + struct bgp_route_evpn *bre = *brep; + + if (!*brep) + return; + + if (bre->refcnt) + bre->refcnt--; + + if (bre->refcnt == 0) { + hash_release(evpn_overlay_hash, bre); + evpn_overlay_free(bre); + *brep = NULL; + } +} + +static uint32_t evpn_overlay_hash_key_make(const void *p) +{ + const struct bgp_route_evpn *bre = p; + uint32_t key = 0; + + if (IS_IPADDR_V4(&bre->gw_ip)) + key = jhash_1word(bre->gw_ip.ipaddr_v4.s_addr, 0); + else + key = jhash2(bre->gw_ip.ipaddr_v6.s6_addr32, + array_size(bre->gw_ip.ipaddr_v6.s6_addr32), 0); + + key = jhash_1word(bre->type, key); + key = jhash(bre->eth_s_id.val, sizeof(bre->eth_s_id.val), 0); + return key; +} + +static bool evpn_overlay_hash_cmp(const void *p1, const void *p2) +{ + const struct bgp_route_evpn *bre1 = p1; + const struct bgp_route_evpn *bre2 = p2; + + return bgp_route_evpn_same(bre1, bre2); +} + +static void evpn_overlay_init(void) +{ + evpn_overlay_hash = hash_create(evpn_overlay_hash_key_make, + evpn_overlay_hash_cmp, + "BGP EVPN Overlay"); +} + +static void evpn_overlay_finish(void) +{ + hash_clean_and_free(&evpn_overlay_hash, + (void (*)(void *))evpn_overlay_free); +} + static void *srv6_l3vpn_hash_alloc(void *p) { return p; @@ -788,6 +864,8 @@ unsigned int attrhash_key_make(const void *p) MIX(encap_hash_key_make(attr->encap_subtlvs)); if (attr->srv6_l3vpn) MIX(srv6_l3vpn_hash_key_make(attr->srv6_l3vpn)); + if (bgp_attr_get_evpn_overlay(attr)) + MIX(evpn_overlay_hash_key_make(bgp_attr_get_evpn_overlay(attr))); if (attr->srv6_vpn) MIX(srv6_vpn_hash_key_make(attr->srv6_vpn)); #ifdef ENABLE_BGP_VNC @@ -961,6 +1039,7 @@ struct attr *bgp_attr_intern(struct attr *attr) struct ecommunity *ipv6_ecomm = NULL; struct lcommunity *lcomm = NULL; struct community *comm = NULL; + struct bgp_route_evpn *bre = NULL; /* Intern referenced structure. */ if (attr->aspath) { @@ -1027,6 +1106,16 @@ struct attr *bgp_attr_intern(struct attr *attr) else attr->encap_subtlvs->refcnt++; } + + bre = bgp_attr_get_evpn_overlay(attr); + if (bre) { + if (!bre->refcnt) + bgp_attr_set_evpn_overlay(attr, + evpn_overlay_intern(bre)); + else + bre->refcnt++; + } + if (attr->srv6_l3vpn) { if (!attr->srv6_l3vpn->refcnt) attr->srv6_l3vpn = srv6_l3vpn_intern(attr->srv6_l3vpn); @@ -1216,6 +1305,7 @@ void bgp_attr_unintern_sub(struct attr *attr) struct lcommunity *lcomm = NULL; struct community *comm = NULL; struct transit *transit; + struct bgp_route_evpn *bre; /* aspath refcount shoud be decrement. */ aspath_unintern(&attr->aspath); @@ -1257,6 +1347,10 @@ void bgp_attr_unintern_sub(struct attr *attr) srv6_l3vpn_unintern(&attr->srv6_l3vpn); srv6_vpn_unintern(&attr->srv6_vpn); + + bre = bgp_attr_get_evpn_overlay(attr); + evpn_overlay_unintern(&bre); + bgp_attr_set_evpn_overlay(attr, NULL); } /* Free bgp attribute and aspath. */ @@ -1289,6 +1383,7 @@ void bgp_attr_flush(struct attr *attr) struct cluster_list *cluster; struct lcommunity *lcomm; struct community *comm; + struct bgp_route_evpn *bre; if (attr->aspath && !attr->aspath->refcnt) { aspath_free(attr->aspath); @@ -1347,6 +1442,11 @@ void bgp_attr_flush(struct attr *attr) bgp_attr_set_vnc_subtlvs(attr, NULL); } #endif + bre = bgp_attr_get_evpn_overlay(attr); + if (bre && !bre->refcnt) { + evpn_overlay_free(bre); + bgp_attr_set_evpn_overlay(attr, NULL); + } } /* Implement draft-scudder-idr-optional-transitive behaviour and @@ -5006,6 +5106,7 @@ void bgp_attr_init(void) transit_init(); encap_init(); srv6_init(); + evpn_overlay_init(); } void bgp_attr_finish(void) @@ -5019,6 +5120,7 @@ void bgp_attr_finish(void) transit_finish(); encap_finish(); srv6_finish(); + evpn_overlay_finish(); } /* Make attribute packet. */ diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h index 561024e7c8..f4b800737e 100644 --- a/bgpd/bgp_attr.h +++ b/bgpd/bgp_attr.h @@ -278,7 +278,7 @@ struct attr { struct bgp_attr_encap_subtlv *vnc_subtlvs; /* VNC-specific */ #endif /* EVPN */ - struct bgp_route_evpn evpn_overlay; + struct bgp_route_evpn *evpn_overlay; /* EVPN MAC Mobility sequence number, if any. */ uint32_t mm_seqnum; @@ -614,16 +614,16 @@ static inline void bgp_attr_set_cluster(struct attr *attr, UNSET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST)); } -static inline const struct bgp_route_evpn * +static inline struct bgp_route_evpn * bgp_attr_get_evpn_overlay(const struct attr *attr) { - return &attr->evpn_overlay; + return attr->evpn_overlay; } static inline void bgp_attr_set_evpn_overlay(struct attr *attr, - struct bgp_route_evpn *eo) + struct bgp_route_evpn *bre) { - memcpy(&attr->evpn_overlay, eo, sizeof(struct bgp_route_evpn)); + attr->evpn_overlay = bre; } static inline struct bgp_attr_encap_subtlv * diff --git a/bgpd/bgp_attr_evpn.c b/bgpd/bgp_attr_evpn.c index 086c36f36c..fc7548d9bf 100644 --- a/bgpd/bgp_attr_evpn.c +++ b/bgpd/bgp_attr_evpn.c @@ -24,6 +24,13 @@ bool bgp_route_evpn_same(const struct bgp_route_evpn *e1, const struct bgp_route_evpn *e2) { + if (!e1 && e2) + return false; + if (!e2 && e1) + return false; + if (!e1 && !e2) + return true; + return (e1->type == e2->type && !memcmp(&(e1->eth_s_id), &(e2->eth_s_id), sizeof(esi_t)) && !ipaddr_cmp(&(e1->gw_ip), &(e2->gw_ip))); diff --git a/bgpd/bgp_attr_evpn.h b/bgpd/bgp_attr_evpn.h index e12fc3a86c..cc0e3e4400 100644 --- a/bgpd/bgp_attr_evpn.h +++ b/bgpd/bgp_attr_evpn.h @@ -23,6 +23,7 @@ enum overlay_index_type { * MAC overlay index is stored in the RMAC attribute. */ struct bgp_route_evpn { + unsigned long refcnt; enum overlay_index_type type; esi_t eth_s_id; struct ipaddr gw_ip; diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index 55896ee7ea..fc54babaa3 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -1741,20 +1741,30 @@ static int update_evpn_type5_route(struct bgp *bgp_vrf, struct prefix_evpn *evp, BGP_L2VPN_EVPN_ADV_IPV6_UNICAST_GW_IP)) { if (src_attr && !IN6_IS_ADDR_UNSPECIFIED(&src_attr->mp_nexthop_global)) { - attr.evpn_overlay.type = OVERLAY_INDEX_GATEWAY_IP; - SET_IPADDR_V6(&attr.evpn_overlay.gw_ip); - memcpy(&attr.evpn_overlay.gw_ip.ipaddr_v6, + struct bgp_route_evpn *bre = + XCALLOC(MTYPE_BGP_EVPN_OVERLAY, + sizeof(struct bgp_route_evpn)); + + bre->type = OVERLAY_INDEX_GATEWAY_IP; + SET_IPADDR_V6(&bre->gw_ip); + memcpy(&bre->gw_ip.ipaddr_v6, &src_attr->mp_nexthop_global, sizeof(struct in6_addr)); + bgp_attr_set_evpn_overlay(&attr, bre); } } else if (src_afi == AFI_IP && CHECK_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN], BGP_L2VPN_EVPN_ADV_IPV4_UNICAST_GW_IP)) { if (src_attr && src_attr->nexthop.s_addr != 0) { - attr.evpn_overlay.type = OVERLAY_INDEX_GATEWAY_IP; - SET_IPADDR_V4(&attr.evpn_overlay.gw_ip); - memcpy(&attr.evpn_overlay.gw_ip.ipaddr_v4, - &src_attr->nexthop, sizeof(struct in_addr)); + struct bgp_route_evpn *bre = + XCALLOC(MTYPE_BGP_EVPN_OVERLAY, + sizeof(struct bgp_route_evpn)); + + bre->type = OVERLAY_INDEX_GATEWAY_IP; + SET_IPADDR_V4(&bre->gw_ip); + memcpy(&bre->gw_ip.ipaddr_v4, &src_attr->nexthop, + sizeof(struct in_addr)); + bgp_attr_set_evpn_overlay(&attr, bre); } } @@ -3031,6 +3041,7 @@ static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf, bool use_l3nhg = false; bool is_l3nhg_active = false; char buf1[INET6_ADDRSTRLEN]; + struct bgp_route_evpn *bre; memset(pp, 0, sizeof(struct prefix)); ip_prefix_from_evpn_prefix(evp, pp); @@ -3064,35 +3075,33 @@ static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf, * make sure to set the flag for next hop attribute. */ attr = *parent_pi->attr; - if (attr.evpn_overlay.type != OVERLAY_INDEX_GATEWAY_IP) { - if (afi == AFI_IP6) - evpn_convert_nexthop_to_ipv6(&attr); - else { - attr.nexthop = attr.mp_nexthop_global_in; - attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP); - } - } else { - + bre = bgp_attr_get_evpn_overlay(&attr); + if (bre && bre->type == OVERLAY_INDEX_GATEWAY_IP) { /* * If gateway IP overlay index is specified in the NLRI of * EVPN RT-5, this gateway IP should be used as the nexthop * for the prefix in the VRF */ if (bgp_debug_zebra(NULL)) { - zlog_debug( - "Install gateway IP %s as nexthop for prefix %pFX in vrf %s", - inet_ntop(pp->family, &attr.evpn_overlay.gw_ip, - buf1, sizeof(buf1)), pp, - vrf_id_to_name(bgp_vrf->vrf_id)); + zlog_debug("Install gateway IP %s as nexthop for prefix %pFX in vrf %s", + inet_ntop(pp->family, &bre->gw_ip, buf1, + sizeof(buf1)), + pp, vrf_id_to_name(bgp_vrf->vrf_id)); } if (afi == AFI_IP6) { - memcpy(&attr.mp_nexthop_global, - &attr.evpn_overlay.gw_ip.ipaddr_v6, + memcpy(&attr.mp_nexthop_global, &bre->gw_ip.ipaddr_v6, sizeof(struct in6_addr)); attr.mp_nexthop_len = IPV6_MAX_BYTELEN; } else { - attr.nexthop = attr.evpn_overlay.gw_ip.ipaddr_v4; + attr.nexthop = bre->gw_ip.ipaddr_v4; + attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP); + } + } else { + if (afi == AFI_IP6) + evpn_convert_nexthop_to_ipv6(&attr); + else { + attr.nexthop = attr.mp_nexthop_global_in; attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP); } } @@ -3144,22 +3153,20 @@ static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf, } /* Gateway IP nexthop should be resolved */ - if (attr.evpn_overlay.type == OVERLAY_INDEX_GATEWAY_IP) { + if (bre && bre->type == OVERLAY_INDEX_GATEWAY_IP) { if (bgp_find_or_add_nexthop(bgp_vrf, bgp_vrf, afi, safi, pi, NULL, 0, NULL)) bgp_path_info_set_flag(dest, pi, BGP_PATH_VALID); else { if (BGP_DEBUG(nht, NHT)) { - inet_ntop(pp->family, - &attr.evpn_overlay.gw_ip, - buf1, sizeof(buf1)); + inet_ntop(pp->family, &bre->gw_ip, buf1, + sizeof(buf1)); zlog_debug("%s: gateway IP NH unresolved", buf1); } bgp_path_info_unset_flag(dest, pi, BGP_PATH_VALID); } } else { - /* as it is an importation, change nexthop */ bgp_path_info_set_flag(dest, pi, BGP_PATH_ANNC_NH_SELF); } @@ -4690,7 +4697,6 @@ static int process_type2_route(struct peer *peer, afi_t afi, safi_t safi, { struct prefix_rd prd; struct prefix_evpn p = {}; - struct bgp_route_evpn evpn = {}; uint8_t ipaddr_len; uint8_t macaddr_len; /* holds the VNI(s) as in packet */ @@ -4792,11 +4798,11 @@ static int process_type2_route(struct peer *peer, afi_t afi, safi_t safi, if (attr) bgp_update(peer, (struct prefix *)&p, addpath_id, attr, afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, - &label[0], num_labels, 0, &evpn); + &label[0], num_labels, 0, NULL); else bgp_withdraw(peer, (struct prefix *)&p, addpath_id, afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, &label[0], - num_labels, &evpn); + num_labels); goto done; fail: @@ -4886,8 +4892,7 @@ static int process_type3_route(struct peer *peer, afi_t afi, safi_t safi, 0, 0, NULL); else bgp_withdraw(peer, (struct prefix *)&p, addpath_id, afi, safi, - ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, NULL, 0, - NULL); + ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, NULL, 0); return 0; } @@ -4900,7 +4905,8 @@ static int process_type5_route(struct peer *peer, afi_t afi, safi_t safi, { struct prefix_rd prd; struct prefix_evpn p; - struct bgp_route_evpn evpn; + struct bgp_route_evpn *evpn = XCALLOC(MTYPE_BGP_EVPN_OVERLAY, + sizeof(struct bgp_route_evpn)); uint8_t ippfx_len; uint32_t eth_tag; mpls_label_t label; /* holds the VNI as in the packet */ @@ -4930,12 +4936,9 @@ static int process_type5_route(struct peer *peer, afi_t afi, safi_t safi, p.prefixlen = EVPN_ROUTE_PREFIXLEN; p.prefix.route_type = BGP_EVPN_IP_PREFIX_ROUTE; - /* Additional information outside of prefix - ESI and GW IP */ - memset(&evpn, 0, sizeof(evpn)); - /* Fetch ESI overlay index */ if (attr) - memcpy(&evpn.eth_s_id, pfx, sizeof(esi_t)); + memcpy(&evpn->eth_s_id, pfx, sizeof(esi_t)); pfx += ESI_BYTES; /* Fetch Ethernet Tag. */ @@ -4962,16 +4965,16 @@ static int process_type5_route(struct peer *peer, afi_t afi, safi_t safi, SET_IPADDR_V4(&p.prefix.prefix_addr.ip); memcpy(&p.prefix.prefix_addr.ip.ipaddr_v4, pfx, 4); pfx += 4; - SET_IPADDR_V4(&evpn.gw_ip); - memcpy(&evpn.gw_ip.ipaddr_v4, pfx, 4); + SET_IPADDR_V4(&evpn->gw_ip); + memcpy(&evpn->gw_ip.ipaddr_v4, pfx, 4); pfx += 4; } else { SET_IPADDR_V6(&p.prefix.prefix_addr.ip); memcpy(&p.prefix.prefix_addr.ip.ipaddr_v6, pfx, IPV6_MAX_BYTELEN); pfx += IPV6_MAX_BYTELEN; - SET_IPADDR_V6(&evpn.gw_ip); - memcpy(&evpn.gw_ip.ipaddr_v6, pfx, IPV6_MAX_BYTELEN); + SET_IPADDR_V6(&evpn->gw_ip); + memcpy(&evpn->gw_ip.ipaddr_v6, pfx, IPV6_MAX_BYTELEN); pfx += IPV6_MAX_BYTELEN; } @@ -4989,20 +4992,20 @@ static int process_type5_route(struct peer *peer, afi_t afi, safi_t safi, * An update containing a non-zero gateway IP and a non-zero ESI * at the same time is should be treated as withdraw */ - if (bgp_evpn_is_esi_valid(&evpn.eth_s_id) && - !ipaddr_is_zero(&evpn.gw_ip)) { + if (bgp_evpn_is_esi_valid(&evpn->eth_s_id) && + !ipaddr_is_zero(&evpn->gw_ip)) { flog_err(EC_BGP_EVPN_ROUTE_INVALID, "%s - Rx EVPN Type-5 ESI and gateway-IP both non-zero.", peer->host); is_valid_update = false; - } else if (bgp_evpn_is_esi_valid(&evpn.eth_s_id)) - evpn.type = OVERLAY_INDEX_ESI; - else if (!ipaddr_is_zero(&evpn.gw_ip)) - evpn.type = OVERLAY_INDEX_GATEWAY_IP; + } else if (bgp_evpn_is_esi_valid(&evpn->eth_s_id)) + evpn->type = OVERLAY_INDEX_ESI; + else if (!ipaddr_is_zero(&evpn->gw_ip)) + evpn->type = OVERLAY_INDEX_GATEWAY_IP; if (attr) { if (is_zero_mac(&attr->rmac) && - !bgp_evpn_is_esi_valid(&evpn.eth_s_id) && - ipaddr_is_zero(&evpn.gw_ip) && label == 0) { + !bgp_evpn_is_esi_valid(&evpn->eth_s_id) && + ipaddr_is_zero(&evpn->gw_ip) && label == 0) { flog_err(EC_BGP_EVPN_ROUTE_INVALID, "%s - Rx EVPN Type-5 ESI, gateway-IP, RMAC and label all zero", peer->host); @@ -5017,7 +5020,7 @@ static int process_type5_route(struct peer *peer, afi_t afi, safi_t safi, if (attr && is_valid_update) bgp_update(peer, (struct prefix *)&p, addpath_id, attr, afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, - &label, 1, 0, &evpn); + &label, 1, 0, evpn); else { if (!is_valid_update) { char attr_str[BUFSIZ] = {0}; @@ -5029,8 +5032,7 @@ static int process_type5_route(struct peer *peer, afi_t afi, safi_t safi, attr_str); } bgp_withdraw(peer, (struct prefix *)&p, addpath_id, afi, safi, - ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, &label, 1, - &evpn); + ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, &label, 1); } return 0; @@ -5044,12 +5046,16 @@ static void evpn_mpattr_encode_type5(struct stream *s, const struct prefix *p, int len; char temp[16]; const struct evpn_addr *p_evpn_p; + struct bgp_route_evpn *bre = NULL; memset(&temp, 0, sizeof(temp)); if (p->family != AF_EVPN) return; p_evpn_p = &(p->u.prefix_evpn); + if (attr) + bre = bgp_attr_get_evpn_overlay(attr); + /* len denites the total len of IP and GW-IP in the route IP and GW-IP have to be both ipv4 or ipv6 */ @@ -5060,7 +5066,7 @@ static void evpn_mpattr_encode_type5(struct stream *s, const struct prefix *p, /* Prefix contains RD, ESI, EthTag, IP length, IP, GWIP and VNI */ stream_putc(s, 8 + 10 + 4 + 1 + len + 3); stream_put(s, prd->val, 8); - if (attr && attr->evpn_overlay.type == OVERLAY_INDEX_ESI) + if (attr && bre && bre->type == OVERLAY_INDEX_ESI) stream_put(s, &attr->esi, sizeof(esi_t)); else stream_put(s, 0, sizeof(esi_t)); @@ -5070,15 +5076,11 @@ static void evpn_mpattr_encode_type5(struct stream *s, const struct prefix *p, stream_put_ipv4(s, p_evpn_p->prefix_addr.ip.ipaddr_v4.s_addr); else stream_put(s, &p_evpn_p->prefix_addr.ip.ipaddr_v6, 16); - if (attr && attr->evpn_overlay.type == OVERLAY_INDEX_GATEWAY_IP) { - const struct bgp_route_evpn *evpn_overlay = - bgp_attr_get_evpn_overlay(attr); - + if (attr && bre && bre->type == OVERLAY_INDEX_GATEWAY_IP) { if (IS_IPADDR_V4(&p_evpn_p->prefix_addr.ip)) - stream_put_ipv4(s, - evpn_overlay->gw_ip.ipaddr_v4.s_addr); + stream_put_ipv4(s, bre->gw_ip.ipaddr_v4.s_addr); else - stream_put(s, &(evpn_overlay->gw_ip.ipaddr_v6), 16); + stream_put(s, &(bre->gw_ip.ipaddr_v6), 16); } else { if (IS_IPADDR_V4(&p_evpn_p->prefix_addr.ip)) stream_put_ipv4(s, 0); diff --git a/bgpd/bgp_evpn_mh.c b/bgpd/bgp_evpn_mh.c index d723a2b1be..f4528defc2 100644 --- a/bgpd/bgp_evpn_mh.c +++ b/bgpd/bgp_evpn_mh.c @@ -770,8 +770,7 @@ int bgp_evpn_type4_route_process(struct peer *peer, afi_t afi, safi_t safi, 0, 0, NULL); } else { bgp_withdraw(peer, (struct prefix *)&p, addpath_id, afi, safi, - ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, NULL, 0, - NULL); + ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, NULL, 0); } return 0; } @@ -1239,8 +1238,7 @@ int bgp_evpn_type1_route_process(struct peer *peer, afi_t afi, safi_t safi, 0, 0, NULL); } else { bgp_withdraw(peer, (struct prefix *)&p, addpath_id, afi, safi, - ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, NULL, 0, - NULL); + ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, NULL, 0); } return 0; } diff --git a/bgpd/bgp_flowspec.c b/bgpd/bgp_flowspec.c index 6165bf892e..bd04970fd5 100644 --- a/bgpd/bgp_flowspec.c +++ b/bgpd/bgp_flowspec.c @@ -195,7 +195,7 @@ int bgp_nlri_parse_flowspec(struct peer *peer, struct attr *attr, NULL, 0, 0, NULL); } else { bgp_withdraw(peer, &p, 0, afi, safi, ZEBRA_ROUTE_BGP, - BGP_ROUTE_NORMAL, NULL, NULL, 0, NULL); + BGP_ROUTE_NORMAL, NULL, NULL, 0); } XFREE(MTYPE_TMP, temp); diff --git a/bgpd/bgp_label.c b/bgpd/bgp_label.c index 839437e120..ad40fef62c 100644 --- a/bgpd/bgp_label.c +++ b/bgpd/bgp_label.c @@ -576,7 +576,7 @@ int bgp_nlri_parse_label(struct peer *peer, struct attr *attr, } else { bgp_withdraw(peer, &p, addpath_id, packet->afi, SAFI_UNICAST, ZEBRA_ROUTE_BGP, - BGP_ROUTE_NORMAL, NULL, &label, 1, NULL); + BGP_ROUTE_NORMAL, NULL, &label, 1); } } diff --git a/bgpd/bgp_mac.c b/bgpd/bgp_mac.c index 31e84d13c4..bc44a212cd 100644 --- a/bgpd/bgp_mac.c +++ b/bgpd/bgp_mac.c @@ -143,7 +143,6 @@ static void bgp_process_mac_rescan_table(struct bgp *bgp, struct peer *peer, const struct prefix *p = bgp_dest_get_prefix(dest); struct prefix_evpn *pevpn = (struct prefix_evpn *)dest; struct prefix_rd prd; - struct bgp_route_evpn *evpn; if (pevpn->family == AF_EVPN && pevpn->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE @@ -195,12 +194,10 @@ static void bgp_process_mac_rescan_table(struct bgp *bgp, struct peer *peer, continue; } - memcpy(&evpn, bgp_attr_get_evpn_overlay(pi->attr), - sizeof(evpn)); bgp_update(peer, p, pi->addpath_rx_id, pi->attr, AFI_L2VPN, SAFI_EVPN, ZEBRA_ROUTE_BGP, - BGP_ROUTE_NORMAL, &prd, label_pnt, - num_labels, 1, evpn); + BGP_ROUTE_NORMAL, &prd, label_pnt, num_labels, + 1, bgp_attr_get_evpn_overlay(pi->attr)); } } } diff --git a/bgpd/bgp_memory.c b/bgpd/bgp_memory.c index c1804fb70a..c2599ade58 100644 --- a/bgpd/bgp_memory.c +++ b/bgpd/bgp_memory.c @@ -135,3 +135,5 @@ DEFINE_MTYPE(BGPD, EVPN_REMOTE_IP, "BGP EVPN Remote IP hash entry"); DEFINE_MTYPE(BGPD, BGP_NOTIFICATION, "BGP Notification Message"); DEFINE_MTYPE(BGPD, BGP_SOFT_VERSION, "Software Version"); + +DEFINE_MTYPE(BGPD, BGP_EVPN_OVERLAY, "BGP EVPN Overlay"); diff --git a/bgpd/bgp_memory.h b/bgpd/bgp_memory.h index 4ae49a2c17..1f76945da3 100644 --- a/bgpd/bgp_memory.h +++ b/bgpd/bgp_memory.h @@ -134,4 +134,6 @@ DECLARE_MTYPE(BGP_NOTIFICATION); DECLARE_MTYPE(BGP_SOFT_VERSION); +DECLARE_MTYPE(BGP_EVPN_OVERLAY); + #endif /* _QUAGGA_BGP_MEMORY_H */ diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index b03171b4c8..9de1c5f4c2 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -245,7 +245,7 @@ int bgp_nlri_parse_vpn(struct peer *peer, struct attr *attr, } else { bgp_withdraw(peer, &p, addpath_id, packet->afi, SAFI_MPLS_VPN, ZEBRA_ROUTE_BGP, - BGP_ROUTE_NORMAL, &prd, &label, 1, NULL); + BGP_ROUTE_NORMAL, &prd, &label, 1); } } /* Packet length consistency check. */ diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c index 8ce45558e9..504428b0d6 100644 --- a/bgpd/bgp_nht.c +++ b/bgpd/bgp_nht.c @@ -1300,11 +1300,13 @@ void evaluate_paths(struct bgp_nexthop_cache *bnc) bool bnc_is_valid_nexthop = false; bool path_valid = false; + struct bgp_route_evpn *bre = + bgp_attr_get_evpn_overlay(path->attr); if (safi == SAFI_UNICAST && path->sub_type == BGP_ROUTE_IMPORTED && bgp_path_info_num_labels(path) && - (path->attr->evpn_overlay.type != OVERLAY_INDEX_GATEWAY_IP)) { + !(bre && bre->type == OVERLAY_INDEX_GATEWAY_IP)) { bnc_is_valid_nexthop = bgp_isvalid_nexthop_for_l3vpn(bnc, path) ? true diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 2a9fc6ce0d..fbccce4edd 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -4608,10 +4608,8 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, * will not be interned. In which case, it is ok to update the * attr->evpn_overlay, so that, this can be stored in adj_in. */ - if ((afi == AFI_L2VPN) && evpn) { - memcpy(&attr->evpn_overlay, evpn, - sizeof(struct bgp_route_evpn)); - } + if ((afi == AFI_L2VPN) && evpn) + bgp_attr_set_evpn_overlay(attr, evpn); bgp_adj_in_set(dest, peer, attr, addpath_id, &bgp_labels); } @@ -4773,8 +4771,7 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, * evpn to new_atr.evpn_overlay before it is interned. */ if (soft_reconfig && (afi == AFI_L2VPN) && evpn) - memcpy(&new_attr.evpn_overlay, evpn, - sizeof(struct bgp_route_evpn)); + bgp_attr_set_evpn_overlay(&new_attr, evpn); /* Apply incoming route-map. * NB: new_attr may now contain newly allocated values from route-map @@ -5450,7 +5447,7 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, void bgp_withdraw(struct peer *peer, const struct prefix *p, uint32_t addpath_id, afi_t afi, safi_t safi, int type, int sub_type, struct prefix_rd *prd, mpls_label_t *label, - uint8_t num_labels, struct bgp_route_evpn *evpn) + uint8_t num_labels) { struct bgp *bgp; char pfx_buf[BGP_PRD_PATH_STRLEN]; @@ -5679,7 +5676,7 @@ static void bgp_soft_reconfig_table_update(struct peer *peer, struct bgp_path_info *pi; uint8_t num_labels; mpls_label_t *label_pnt; - struct bgp_route_evpn evpn; + struct bgp_route_evpn *bre = NULL; for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) if (pi->peer == peer) @@ -5687,15 +5684,13 @@ static void bgp_soft_reconfig_table_update(struct peer *peer, num_labels = ain->labels ? ain->labels->num_labels : 0; label_pnt = num_labels ? &ain->labels->label[0] : NULL; + if (pi) - memcpy(&evpn, bgp_attr_get_evpn_overlay(pi->attr), - sizeof(evpn)); - else - memset(&evpn, 0, sizeof(evpn)); + bre = bgp_attr_get_evpn_overlay(pi->attr); bgp_update(peer, bgp_dest_get_prefix(dest), ain->addpath_rx_id, ain->attr, afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, prd, - label_pnt, num_labels, 1, &evpn); + label_pnt, num_labels, 1, bre); } static void bgp_soft_reconfig_table(struct peer *peer, afi_t afi, safi_t safi, @@ -6614,7 +6609,7 @@ int bgp_nlri_parse_ip(struct peer *peer, struct attr *attr, else bgp_withdraw(peer, &p, addpath_id, afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, NULL, - NULL, 0, NULL); + NULL, 0); /* Do not send BGP notification twice when maximum-prefix count * overflow. */ @@ -6745,15 +6740,25 @@ void bgp_static_update(struct bgp *bgp, const struct prefix *p, if (afi == AFI_L2VPN) { if (bgp_static->gatewayIp.family == AF_INET) { - SET_IPADDR_V4(&attr.evpn_overlay.gw_ip); - memcpy(&attr.evpn_overlay.gw_ip.ipaddr_v4, + struct bgp_route_evpn *bre = + XCALLOC(MTYPE_BGP_EVPN_OVERLAY, + sizeof(struct bgp_route_evpn)); + + SET_IPADDR_V4(&bre->gw_ip); + memcpy(&bre->gw_ip.ipaddr_v4, &bgp_static->gatewayIp.u.prefix4, IPV4_MAX_BYTELEN); + bgp_attr_set_evpn_overlay(&attr, bre); } else if (bgp_static->gatewayIp.family == AF_INET6) { - SET_IPADDR_V6(&attr.evpn_overlay.gw_ip); - memcpy(&attr.evpn_overlay.gw_ip.ipaddr_v6, + struct bgp_route_evpn *bre = + XCALLOC(MTYPE_BGP_EVPN_OVERLAY, + sizeof(struct bgp_route_evpn)); + + SET_IPADDR_V6(&bre->gw_ip); + memcpy(&bre->gw_ip.ipaddr_v6, &bgp_static->gatewayIp.u.prefix6, IPV6_MAX_BYTELEN); + bgp_attr_set_evpn_overlay(&attr, bre); } memcpy(&attr.esi, bgp_static->eth_s_id, sizeof(esi_t)); if (bgp_static->encap_tunneltype == BGP_ENCAP_TYPE_VXLAN) { @@ -10114,6 +10119,7 @@ void route_vty_out_overlay(struct vty *vty, const struct prefix *p, json_object *json_path = NULL; json_object *json_nexthop = NULL; json_object *json_overlay = NULL; + struct bgp_route_evpn *bre = NULL; if (!path->extra) return; @@ -10179,12 +10185,14 @@ void route_vty_out_overlay(struct vty *vty, const struct prefix *p, } } - const struct bgp_route_evpn *eo = bgp_attr_get_evpn_overlay(attr); - - if (!json_path) - vty_out(vty, "/%pIA", &eo->gw_ip); - else - json_object_string_addf(json_overlay, "gw", "%pIA", &eo->gw_ip); + bre = bgp_attr_get_evpn_overlay(attr); + if (bre) { + if (!json_path) + vty_out(vty, "/%pIA", &bre->gw_ip); + else + json_object_string_addf(json_overlay, "gw", "%pIA", + &bre->gw_ip); + } if (bgp_attr_get_ecommunity(attr)) { char *mac = NULL; @@ -10519,6 +10527,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, mpls_label_t label = MPLS_INVALID_LABEL; struct bgp_path_info *bpi_ultimate = bgp_get_imported_bpi_ultimate(path); + struct bgp_route_evpn *bre = bgp_attr_get_evpn_overlay(attr); if (json_paths) { json_path = json_object_new_object(); @@ -10545,12 +10554,10 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, } } - if (safi == SAFI_EVPN - && attr->evpn_overlay.type == OVERLAY_INDEX_GATEWAY_IP) { + if (safi == SAFI_EVPN && bre && bre->type == OVERLAY_INDEX_GATEWAY_IP) { char gwip_buf[INET6_ADDRSTRLEN]; - ipaddr2str(&attr->evpn_overlay.gw_ip, gwip_buf, - sizeof(gwip_buf)); + ipaddr2str(&bre->gw_ip, gwip_buf, sizeof(gwip_buf)); if (json_paths) json_object_string_add(json_path, "gatewayIP", diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index 89449ac5b9..5b433b5558 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -798,8 +798,7 @@ extern void bgp_update(struct peer *peer, const struct prefix *p, extern void bgp_withdraw(struct peer *peer, const struct prefix *p, uint32_t addpath_id, afi_t afi, safi_t safi, int type, int sub_type, struct prefix_rd *prd, - mpls_label_t *label, uint8_t num_labels, - struct bgp_route_evpn *evpn); + mpls_label_t *label, uint8_t num_labels); /* for bgp_nexthop and bgp_damp */ extern void bgp_process(struct bgp *bgp, struct bgp_dest *dest, diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 3ba368aaf7..79c61e2ee2 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -1236,6 +1236,8 @@ route_set_evpn_gateway_ip(void *rule, const struct prefix *prefix, void *object) struct ipaddr *gw_ip = rule; struct bgp_path_info *path; struct prefix_evpn *evp; + struct bgp_route_evpn *bre = XCALLOC(MTYPE_BGP_EVPN_OVERLAY, + sizeof(struct bgp_route_evpn)); if (prefix->family != AF_EVPN) return RMAP_OKAY; @@ -1251,9 +1253,9 @@ route_set_evpn_gateway_ip(void *rule, const struct prefix *prefix, void *object) path = object; /* Set gateway-ip value. */ - path->attr->evpn_overlay.type = OVERLAY_INDEX_GATEWAY_IP; - memcpy(&path->attr->evpn_overlay.gw_ip, &gw_ip->ip.addr, - IPADDRSZ(gw_ip)); + bre->type = OVERLAY_INDEX_GATEWAY_IP; + memcpy(&bre->gw_ip, &gw_ip->ip.addr, IPADDRSZ(gw_ip)); + bgp_attr_set_evpn_overlay(path->attr, bre); return RMAP_OKAY; } diff --git a/bgpd/bgp_updgrp_packet.c b/bgpd/bgp_updgrp_packet.c index 6e30d4f846..b7d5f66450 100644 --- a/bgpd/bgp_updgrp_packet.c +++ b/bgpd/bgp_updgrp_packet.c @@ -863,7 +863,8 @@ struct bpacket *subgroup_update_packet(struct update_subgroup *subgrp) bgp_debug_rdpfxpath2str(afi, safi, prd, dest_p, label_pnt, num_labels, addpath_capable, addpath_tx_id, - &adv->baa->attr->evpn_overlay, + bgp_attr_get_evpn_overlay( + adv->baa->attr), pfx_buf, sizeof(pfx_buf)); zlog_debug("u%" PRIu64 ":s%" PRIu64 " send UPDATE %s", subgrp->update_group->id, subgrp->id, diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 006d46d843..52c5f5129d 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -1128,6 +1128,8 @@ static bool update_ipv4nh_for_route_install(int nh_othervrf, struct bgp *nh_bgp, struct attr *attr, bool is_evpn, struct zapi_nexthop *api_nh) { + struct bgp_route_evpn *bre = bgp_attr_get_evpn_overlay(attr); + api_nh->gate.ipv4 = *nexthop; api_nh->vrf_id = nh_bgp->vrf_id; @@ -1144,7 +1146,7 @@ static bool update_ipv4nh_for_route_install(int nh_othervrf, struct bgp *nh_bgp, * treat the nexthop as NEXTHOP_TYPE_IPV4 * Else, mark the nexthop as onlink. */ - if (attr->evpn_overlay.type == OVERLAY_INDEX_GATEWAY_IP) + if (bre && bre->type == OVERLAY_INDEX_GATEWAY_IP) api_nh->type = NEXTHOP_TYPE_IPV4; else { api_nh->type = NEXTHOP_TYPE_IPV4_IFINDEX; @@ -1170,9 +1172,11 @@ static bool update_ipv6nh_for_route_install(int nh_othervrf, struct bgp *nh_bgp, struct zapi_nexthop *api_nh) { struct attr *attr; + struct bgp_route_evpn *bre; attr = pi->attr; api_nh->vrf_id = nh_bgp->vrf_id; + bre = bgp_attr_get_evpn_overlay(attr); if (attr->nh_type == NEXTHOP_TYPE_BLACKHOLE) { api_nh->type = attr->nh_type; @@ -1183,7 +1187,7 @@ static bool update_ipv6nh_for_route_install(int nh_othervrf, struct bgp *nh_bgp, * treat the nexthop as NEXTHOP_TYPE_IPV4 * Else, mark the nexthop as onlink. */ - if (attr->evpn_overlay.type == OVERLAY_INDEX_GATEWAY_IP) + if (bre && bre->type == OVERLAY_INDEX_GATEWAY_IP) api_nh->type = NEXTHOP_TYPE_IPV6; else { api_nh->type = NEXTHOP_TYPE_IPV6_IFINDEX; @@ -1281,6 +1285,7 @@ static void bgp_zebra_announce_parse_nexthop( uint32_t ttl = 0; uint32_t bos = 0; uint32_t exp = 0; + struct bgp_route_evpn *bre = NULL; /* Determine if we're doing weighted ECMP or not */ do_wt_ecmp = bgp_path_info_mpath_chkwtd(bgp, info); @@ -1395,6 +1400,7 @@ static void bgp_zebra_announce_parse_nexthop( } is_evpn = !!CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_EVPN); + bre = bgp_attr_get_evpn_overlay(mpinfo->attr); /* Did we get proper nexthop info to update zebra? */ if (!nh_updated) @@ -1430,9 +1436,7 @@ static void bgp_zebra_announce_parse_nexthop( api_nh->labels[0] = nh_label; } - if (is_evpn - && mpinfo->attr->evpn_overlay.type - != OVERLAY_INDEX_GATEWAY_IP) + if (is_evpn && !(bre && bre->type == OVERLAY_INDEX_GATEWAY_IP)) memcpy(&api_nh->rmac, &(mpinfo->attr->rmac), sizeof(struct ethaddr)); diff --git a/bgpd/rfapi/vnc_export_bgp.c b/bgpd/rfapi/vnc_export_bgp.c index 7decb75782..4de2306609 100644 --- a/bgpd/rfapi/vnc_export_bgp.c +++ b/bgpd/rfapi/vnc_export_bgp.c @@ -388,7 +388,7 @@ void vnc_direct_bgp_del_route_ce(struct bgp *bgp, struct agg_node *rn, bgp_withdraw(bpi->peer, p, 0, /* addpath_id */ afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT, BGP_ROUTE_REDISTRIBUTE, NULL, /* RD not used for unicast */ - NULL, 0, NULL); /* tag not used for unicast */ + NULL, 0); /* tag not used for unicast */ } static void vnc_direct_bgp_vpn_enable_ce(struct bgp *bgp, afi_t afi) @@ -473,16 +473,14 @@ static void vnc_direct_bgp_vpn_disable_ce(struct bgp *bgp, afi_t afi) if (ri->type == ZEBRA_ROUTE_VNC_DIRECT && ri->sub_type == BGP_ROUTE_REDISTRIBUTE) { - - bgp_withdraw( - ri->peer, bgp_dest_get_prefix(dest), - 0, /* addpath_id */ - AFI_IP, SAFI_UNICAST, - ZEBRA_ROUTE_VNC_DIRECT, - BGP_ROUTE_REDISTRIBUTE, - NULL, /* RD not used for unicast */ - NULL, 0, - NULL); /* tag not used for unicast */ + bgp_withdraw(ri->peer, bgp_dest_get_prefix(dest), + 0, /* addpath_id */ + AFI_IP, SAFI_UNICAST, + ZEBRA_ROUTE_VNC_DIRECT, + BGP_ROUTE_REDISTRIBUTE, + NULL, /* RD not used for unicast */ + NULL, + 0); /* tag not used for unicast */ } } } @@ -863,9 +861,8 @@ void vnc_direct_bgp_del_prefix(struct bgp *bgp, 0, /* addpath_id */ afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT, BGP_ROUTE_REDISTRIBUTE, - NULL, /* RD not used for unicast */ - NULL, 0, - NULL); /* tag not used for unicast */ + NULL, /* RD not used for unicast */ + NULL, 0); /* tag not used for unicast */ /* * yuck! * - but consistent with rest of function @@ -892,9 +889,8 @@ void vnc_direct_bgp_del_prefix(struct bgp *bgp, 0, /* addpath_id */ afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT, BGP_ROUTE_REDISTRIBUTE, - NULL, /* RD not used for unicast */ - NULL, 0, - NULL); /* tag not used for unicast */ + NULL, /* RD not used for unicast */ + NULL, 0); /* tag not used for unicast */ } } } @@ -1125,13 +1121,13 @@ void vnc_direct_bgp_del_nve(struct bgp *bgp, struct rfapi_descriptor *rfd) continue; bgp_withdraw(irfd->peer, p, /* prefix */ - 0, /* addpath_id */ + 0, /* addpath_id */ afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT, BGP_ROUTE_REDISTRIBUTE, NULL, /* RD not used for unicast */ - NULL, 0, NULL); /* tag not + NULL, 0); /* tag not used for unicast */ } @@ -1359,7 +1355,7 @@ static void vnc_direct_del_rn_group_rd(struct bgp *bgp, 0, /* addpath_id */ afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT, BGP_ROUTE_REDISTRIBUTE, NULL, /* RD not used for unicast */ - NULL, 0, NULL); /* tag not used for unicast */ + NULL, 0); /* tag not used for unicast */ return; } @@ -1471,16 +1467,15 @@ static void vnc_direct_bgp_unexport_table(afi_t afi, struct agg_table *rt, for (ALL_LIST_ELEMENTS_RO(nve_list, hln, irfd)) { - bgp_withdraw(irfd->peer, agg_node_get_prefix(rn), - 0, /* addpath_id */ + 0, /* addpath_id */ afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT, BGP_ROUTE_REDISTRIBUTE, NULL, /* RD not used for unicast */ - NULL, 0, NULL); /* tag not + NULL, 0); /* tag not used for unicast, EVPN @@ -1715,8 +1710,7 @@ static void vncExportWithdrawTimer(struct event *t) bgp_withdraw(eti->peer, p, 0, /* addpath_id */ family2afi(p->family), SAFI_UNICAST, eti->type, eti->subtype, NULL, /* RD not used for unicast */ - NULL, 0, - NULL); /* tag not used for unicast, EVPN neither */ + NULL, 0); /* tag not used for unicast, EVPN neither */ /* * Free the eti @@ -2001,7 +1995,7 @@ void vnc_direct_bgp_rh_vpn_disable(struct bgp *bgp, afi_t afi) ZEBRA_ROUTE_VNC_DIRECT_RH, BGP_ROUTE_REDISTRIBUTE, NULL, /* RD not used for unicast */ - NULL, 0, NULL); /* tag not used for + NULL, 0); /* tag not used for unicast, EVPN neither */ } From d95f9a35d4fb59b2c453aaf5f0509237f9565deb Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Thu, 18 Jul 2024 14:43:45 +0200 Subject: [PATCH 308/347] bgpd, doc: add bgp snmp traps rfc4382 command Add a trap command to disable or enable the traps defined by the RFC4382. Signed-off-by: Philippe Guibert --- bgpd/bgp_mplsvpn_snmp.c | 5 +++++ bgpd/bgp_snmp.c | 22 ++++++++++++++++++++++ bgpd/bgpd.h | 1 + doc/user/snmptrap.rst | 6 ++++++ 4 files changed, 34 insertions(+) diff --git a/bgpd/bgp_mplsvpn_snmp.c b/bgpd/bgp_mplsvpn_snmp.c index 3344e9e0a5..93d9f67245 100644 --- a/bgpd/bgp_mplsvpn_snmp.c +++ b/bgpd/bgp_mplsvpn_snmp.c @@ -590,6 +590,11 @@ static int bgp_vrf_check_update_active(struct bgp *bgp, struct interface *ifp) /* add trap in here */ bgp->snmp_stats->active = new_active; + if (!CHECK_FLAG(bm->options, BGP_OPT_TRAPS_RFC4382)) { + bgp_mpls_l3vpn_update_last_changed(bgp); + return 0; + } + /* send relevent trap */ if (bgp->snmp_stats->active) trap = MPLSL3VPNVRFUP; diff --git a/bgpd/bgp_snmp.c b/bgpd/bgp_snmp.c index 065ea7672c..eff7c5e0f6 100644 --- a/bgpd/bgp_snmp.c +++ b/bgpd/bgp_snmp.c @@ -50,6 +50,21 @@ DEFPY(bgp_snmp_traps_rfc4273, bgp_snmp_traps_rfc4273_cmd, return CMD_SUCCESS; } +DEFPY(bgp_snmp_traps_rfc4382, bgp_snmp_traps_rfc4382_cmd, + "[no$no] bgp snmp traps rfc4382", + NO_STR BGP_STR + "Configure BGP SNMP\n" + "Configure SNMP traps for BGP\n" + "Configure use of rfc4382 SNMP traps for BGP\n") +{ + if (no) { + UNSET_FLAG(bm->options, BGP_OPT_TRAPS_RFC4382); + return CMD_SUCCESS; + } + SET_FLAG(bm->options, BGP_OPT_TRAPS_RFC4382); + return CMD_SUCCESS; +} + DEFPY(bgp_snmp_traps_bgp4_mibv2, bgp_snmp_traps_bgp4_mibv2_cmd, "[no$no] bgp snmp traps bgp4-mibv2", NO_STR BGP_STR @@ -69,9 +84,12 @@ static void bgp_snmp_traps_init(void) { install_element(CONFIG_NODE, &bgp_snmp_traps_rfc4273_cmd); install_element(CONFIG_NODE, &bgp_snmp_traps_bgp4_mibv2_cmd); + install_element(CONFIG_NODE, &bgp_snmp_traps_rfc4382_cmd); SET_FLAG(bm->options, BGP_OPT_TRAPS_RFC4273); /* BGP4MIBv2 traps are disabled by default */ + + SET_FLAG(bm->options, BGP_OPT_TRAPS_RFC4382); } int bgp_cli_snmp_traps_config_write(struct vty *vty) @@ -86,6 +104,10 @@ int bgp_cli_snmp_traps_config_write(struct vty *vty) vty_out(vty, "bgp snmp traps bgp4-mibv2\n"); write++; } + if (!CHECK_FLAG(bm->options, BGP_OPT_TRAPS_RFC4382)) { + vty_out(vty, "no bgp snmp traps rfc4382\n"); + write++; + } return write; } diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 626a76ba0b..7f1b82d9c7 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -131,6 +131,7 @@ struct bgp_master { #define BGP_OPT_NO_ZEBRA (1 << 2) #define BGP_OPT_TRAPS_RFC4273 (1 << 3) #define BGP_OPT_TRAPS_BGP4MIBV2 (1 << 4) +#define BGP_OPT_TRAPS_RFC4382 (1 << 5) uint64_t updgrp_idspace; uint64_t subgrp_idspace; diff --git a/doc/user/snmptrap.rst b/doc/user/snmptrap.rst index df534e28bd..52b1904665 100644 --- a/doc/user/snmptrap.rst +++ b/doc/user/snmptrap.rst @@ -215,3 +215,9 @@ possibility to select the MIB he wants to receive traps from: By default, only rfc4273 traps are enabled and sent. .. [Draft-IETF-idr-bgp4-mibv2-11] + +The :rfc:`4382` also defines traps to inform when an L3VPN network changes +the operational status of its VRF interface. The user can choose to suppress +those traps or not. + +.. clicmd:: bgp snmp traps rfc4382 From b8b38a593c40fbea5bbe799af930528bef8c20a4 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Fri, 9 Aug 2024 14:50:59 -0400 Subject: [PATCH 309/347] lib: Fix memory leak in snmp on shutdown The events list is storing a `struct event *` allocated as a MTYPE_TMP pointer, on shutdown ensure that it is properly free'd up. Signed-off-by: Donald Sharp --- lib/agentx.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/agentx.c b/lib/agentx.c index 2e621d06a4..2a3ff2355e 100644 --- a/lib/agentx.c +++ b/lib/agentx.c @@ -377,9 +377,16 @@ void smux_events_update(void) agentx_events_update(); } +static void smux_events_delete_thread(void *arg) +{ + XFREE(MTYPE_TMP, arg); +} + void smux_terminate(void) { - if (events) + if (events) { + events->del = smux_events_delete_thread; list_delete(&events); + } } #endif /* SNMP_AGENTX */ From 33af3c027862ae8bd4524e8df0f4ac608b3f8db2 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Mon, 12 Aug 2024 10:14:31 -0400 Subject: [PATCH 310/347] pathd: Cleanup shutdown memory leaks Just some code to cleanup the shutdown memory leaks that are in pathd. Signed-off-by: Donald Sharp --- pathd/pathd.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/pathd/pathd.c b/pathd/pathd.c index 6c13503c7d..9bb7dbae84 100644 --- a/pathd/pathd.c +++ b/pathd/pathd.c @@ -148,6 +148,16 @@ void srte_segment_list_del(struct srte_segment_list *segment_list) XFREE(MTYPE_PATH_SEGMENT_LIST, segment_list); } +static void srte_segment_list_terminate(void) +{ + while (!RB_EMPTY(srte_segment_list_head, &srte_segment_lists)) { + struct srte_segment_list *sl = RB_ROOT(srte_segment_list_head, + &srte_segment_lists); + + srte_segment_list_del(sl); + } +} + /** * Search for a segment list by name. * @@ -1281,6 +1291,11 @@ void pathd_shutdown(void) { path_ted_teardown(); srte_clean_zebra(); + + srte_segment_list_terminate(); + + vrf_terminate(); + frr_fini(); } From 1563d9f9c816a75839bcb6d1a135d948a39ace88 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Mon, 12 Aug 2024 13:55:26 -0400 Subject: [PATCH 311/347] tests: Fix bgp_duplicate_nexthop python warning Signed-off-by: Donald Sharp --- .../bgp_duplicate_nexthop/test_bgp_duplicate_nexthop.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/topotests/bgp_duplicate_nexthop/test_bgp_duplicate_nexthop.py b/tests/topotests/bgp_duplicate_nexthop/test_bgp_duplicate_nexthop.py index b458c64e33..5c125869e2 100644 --- a/tests/topotests/bgp_duplicate_nexthop/test_bgp_duplicate_nexthop.py +++ b/tests/topotests/bgp_duplicate_nexthop/test_bgp_duplicate_nexthop.py @@ -7,7 +7,7 @@ # Copyright 2024 6WIND S.A. # -""" +r""" test_bgp_nhg_duplicate_nexthop.py: Check that the FRR BGP daemon on r1 selects updates with same nexthops From 33ce5d2410dadab9d6960709b41ad0eef0783bae Mon Sep 17 00:00:00 2001 From: Nathan Bahr Date: Mon, 12 Aug 2024 16:00:06 +0000 Subject: [PATCH 312/347] doc: Fix up pim user docs. Signed-off-by: Nathan Bahr --- doc/user/pim.rst | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/doc/user/pim.rst b/doc/user/pim.rst index d8e52f471e..1740828f26 100644 --- a/doc/user/pim.rst +++ b/doc/user/pim.rst @@ -59,6 +59,7 @@ PIM Routers ----------- .. clicmd:: router pim [vrf NAME] + Configure global PIM protocol .. clicmd:: rp A.B.C.D A.B.C.D/M @@ -159,6 +160,9 @@ PIM Routers Global Multicast ---------------- +These commands are valid at the top-level of the configuration (or also per +vrf where indicated), instead of under the 'router pim' submode. + .. clicmd:: ip multicast rpf-lookup-mode WORD Modify how PIM does RPF lookups in the zebra routing table. You can use @@ -343,10 +347,13 @@ MSDP can be setup in different ways: .. note:: MSDP default peer is not implemented. - MSDP configuration is available under 'router pim' +Commands available for MSDP +--------------------------- + +.. note:: -Commands available for MSDP: + MSDP configuration is available under 'router pim'. .. clicmd:: msdp timers (1-65535) (1-65535) [(1-65535)] @@ -415,15 +422,9 @@ cause great confusion. .. clicmd:: show ip igmp [vrf NAME] join [json] - Display IGMP static join information for a specific vrf. - -.. index:: show ip igmp [vrf NAME$vrf_name] groups [INTERFACE$ifname [GROUP$grp_str]] [detail] [json$json] -.. clicmd:: show ip igmp [vrf NAME$vrf_name] groups [INTERFACE$ifname [GROUP$grp_str]] [detail] [json$json] - - Display IGMP static join information for all the vrfs present. + Display IGMP static join information. -.. index:: show ip igmp vrf all groups [GROUP$grp_str] [detail$detail] [json$json] -.. clicmd:: show ip igmp vrf all groups [GROUP$grp_str] [detail$detail] [json$json] +.. clicmd:: show ip igmp [vrf NAME] groups [INTERFACE [GROUP]] [detail] [json] Display IGMP groups information. @@ -788,4 +789,3 @@ Sample configuration interface eth0 ip pim ssm ip igmp - From ce4e451c5b86d3f79c88283e2a7425ce32e9df1b Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Tue, 13 Aug 2024 08:49:01 -0400 Subject: [PATCH 313/347] bgpd: Free up non-freed json memory on function return json_peers is allocated in the above if statement block for json but is not freed in this code path. Noticed by running Address Sanitizer. Signed-off-by: Donald Sharp --- bgpd/bgp_vty.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index a3180fd707..43e267c5e8 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -12046,6 +12046,8 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi, if (show_failed && !failed_count) { if (use_json) { + json_object_free(json_peers); + json_object_int_add(json, "failedPeersCount", 0); json_object_int_add(json, "dynamicPeers", dn_count); json_object_int_add(json, "totalPeers", count); From 2de9d71a5cc93f04ed2abacd44d22ea6ccda4cfc Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Tue, 13 Aug 2024 08:58:29 -0400 Subject: [PATCH 314/347] doc: Add doc to show sysctl setting for Sanitizers In order to run the XXXX Sanitizers over the code as a developer modern linux distro's require a specific sysctl. Let's document that so that people are aware of it. Signed-off-by: Donald Sharp --- doc/developer/topotests.rst | 8 ++++++++ doc/developer/workflow.rst | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/doc/developer/topotests.rst b/doc/developer/topotests.rst index 586c096740..eaa8e38a9c 100644 --- a/doc/developer/topotests.rst +++ b/doc/developer/topotests.rst @@ -411,6 +411,14 @@ for ``master`` branch: and create ``frr`` user and ``frrvty`` group as shown above. +Newer versions of Address Sanitizers require a sysctl to be changed +to allow for the tests to be successfully run. This is also true +for Undefined behavior Sanitizers as well as Memory Sanitizer. + +.. code:: shell + + sysctl vm.mmap_rnd_bits=28 + Debugging Topotest Failures ^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/doc/developer/workflow.rst b/doc/developer/workflow.rst index 166c96da33..a6bdec1e5b 100644 --- a/doc/developer/workflow.rst +++ b/doc/developer/workflow.rst @@ -1325,6 +1325,14 @@ but are no longer actively maintained. MemorySanitizer is not available in GCC. The different Sanitizers are mostly incompatible with each other. Please refer to GCC/LLVM documentation for details. +.. note:: + + The different sanitizers also require setting + + sysctl vm.mmap_rnd_bits=28 + + in order to work properly. + frr-format plugin This is a GCC plugin provided with FRR that does extended type checks for ``%pFX``-style printfrr extensions. To use this plugin, From 1e288c9b559c186ce1a4765997b36ec4a9f3fbf5 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Tue, 13 Aug 2024 18:00:30 +0300 Subject: [PATCH 315/347] zebra: Do not forget to free opaque data for route entry Signed-off-by: Donatas Abraitis --- zebra/rt_netlink.c | 2 +- zebra/zapi_msg.c | 18 ++++++++---------- zebra/zapi_msg.h | 2 +- zebra/zebra_rib.c | 10 ++++------ zebra/zebra_rnh.c | 2 +- 5 files changed, 15 insertions(+), 19 deletions(-) diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 01b527ea80..768090badb 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -1040,7 +1040,7 @@ int netlink_route_change_read_unicast_internal(struct nlmsghdr *h, zlog_err( "%s: %pFX multipath RTM_NEWROUTE has a invalid nexthop group from the kernel", __func__, &p); - XFREE(MTYPE_RE, re); + zebra_rib_route_entry_free(re); } } else { if (ctx) { diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index 654ade8063..aecbba2ebc 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -2148,7 +2148,7 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) __func__, &api.prefix, zebra_route_string(client->proto)); - XFREE(MTYPE_RE, re); + zebra_rib_route_entry_free(re); return; } @@ -2173,7 +2173,7 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) nexthop_group_delete(&ng); zebra_nhg_backup_free(&bnhg); - XFREE(MTYPE_RE, re); + zebra_rib_route_entry_free(re); return; } @@ -2192,8 +2192,7 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) __func__); nexthop_group_delete(&ng); zebra_nhg_backup_free(&bnhg); - XFREE(MTYPE_RE_OPAQUE, re->opaque); - XFREE(MTYPE_RE, re); + zebra_rib_route_entry_free(re); return; } if (CHECK_FLAG(api.message, ZAPI_MESSAGE_SRCPFX)) @@ -2205,8 +2204,7 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) __func__, api.safi); nexthop_group_delete(&ng); zebra_nhg_backup_free(&bnhg); - XFREE(MTYPE_RE_OPAQUE, re->opaque); - XFREE(MTYPE_RE, re); + zebra_rib_route_entry_free(re); return; } @@ -2235,8 +2233,7 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) */ if (ret == -1) { client->error_cnt++; - XFREE(MTYPE_RE_OPAQUE, re->opaque); - XFREE(MTYPE_RE, re); + zebra_rib_route_entry_free(re); } /* At this point, these allocations are not needed: 're' has been @@ -2264,9 +2261,10 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) } } -void zapi_re_opaque_free(struct re_opaque *opaque) +void zapi_re_opaque_free(struct route_entry *re) { - XFREE(MTYPE_RE_OPAQUE, opaque); + XFREE(MTYPE_RE_OPAQUE, re->opaque); + re->opaque = NULL; } static void zread_route_del(ZAPI_HANDLER_ARGS) diff --git a/zebra/zapi_msg.h b/zebra/zapi_msg.h index 9e3ea6fb6e..a59ccc838b 100644 --- a/zebra/zapi_msg.h +++ b/zebra/zapi_msg.h @@ -106,7 +106,7 @@ extern int zsend_client_close_notify(struct zserv *client, int zsend_nhg_notify(uint16_t type, uint16_t instance, uint32_t session_id, uint32_t id, enum zapi_nhg_notify_owner note); -extern void zapi_re_opaque_free(struct re_opaque *opaque); +extern void zapi_re_opaque_free(struct route_entry *re); extern int zsend_zebra_srv6_locator_add(struct zserv *client, struct srv6_locator *loc); diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 0f02b0a2ec..59190e9dd3 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -2696,8 +2696,7 @@ static void early_route_memory_free(struct zebra_early_route *ere) if (ere->re_nhe) zebra_nhg_free(ere->re_nhe); - zapi_re_opaque_free(ere->re->opaque); - XFREE(MTYPE_RE, ere->re); + zebra_rib_route_entry_free(ere->re); XFREE(MTYPE_WQ_WRAPPER, ere); } @@ -4070,9 +4069,7 @@ void rib_unlink(struct route_node *rn, struct route_entry *re) rib_re_nhg_free(re); - zapi_re_opaque_free(re->opaque); - - XFREE(MTYPE_RE, re); + zebra_rib_route_entry_free(re); } void rib_delnode(struct route_node *rn, struct route_entry *re) @@ -4319,6 +4316,7 @@ struct route_entry *zebra_rib_route_entry_new(vrf_id_t vrf_id, int type, void zebra_rib_route_entry_free(struct route_entry *re) { + zapi_re_opaque_free(re); XFREE(MTYPE_RE, re); } @@ -4389,7 +4387,7 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, /* In error cases, free the route also */ if (ret < 0) - XFREE(MTYPE_RE, re); + zebra_rib_route_entry_free(re); return ret; } diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c index bff8258879..303a81bb3e 100644 --- a/zebra/zebra_rnh.c +++ b/zebra/zebra_rnh.c @@ -826,7 +826,7 @@ static void free_state(vrf_id_t vrf_id, struct route_entry *re, /* free RE and nexthops */ zebra_nhg_free(re->nhe); - XFREE(MTYPE_RE, re); + zebra_rib_route_entry_free(re); } static void copy_state(struct rnh *rnh, const struct route_entry *re, From f01205bb9617d3474edf5b3b617db51935c18aca Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Tue, 13 Aug 2024 14:11:07 -0400 Subject: [PATCH 316/347] pbrd: Call vrf_terminate on shutdown Free up vrf memory on shutdown. Signed-off-by: Donald Sharp --- pbrd/pbr_vrf.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pbrd/pbr_vrf.c b/pbrd/pbr_vrf.c index ef4a4c2c63..d8adb91fef 100644 --- a/pbrd/pbr_vrf.c +++ b/pbrd/pbr_vrf.c @@ -123,4 +123,6 @@ void pbr_vrf_terminate(void) FOR_ALL_INTERFACES (vrf, ifp) pbr_if_del(ifp); } + + vrf_terminate(); } From 68fff4905627b73f92f12b1e6c023e8de561fd99 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Tue, 13 Aug 2024 14:12:05 -0400 Subject: [PATCH 317/347] babeld: Free up memory on shutdown a) call vector_delete on created vector on shutdown. b) Call babel_clean_routing_process on shutdown Signed-off-by: Donald Sharp --- babeld/babel_interface.c | 5 +++++ babeld/babel_interface.h | 1 + babeld/babel_main.c | 4 ++-- babeld/babeld.c | 3 +-- babeld/babeld.h | 1 + 5 files changed, 10 insertions(+), 4 deletions(-) diff --git a/babeld/babel_interface.c b/babeld/babel_interface.c index 76ecd4fe4e..943ae9def1 100644 --- a/babeld/babel_interface.c +++ b/babeld/babel_interface.c @@ -1171,6 +1171,11 @@ DEFUN (show_babel_parameters, return CMD_SUCCESS; } +void babel_if_terminate(void) +{ + vector_free(babel_enable_if); +} + void babel_if_init(void) { diff --git a/babeld/babel_interface.h b/babeld/babel_interface.h index a585e23afc..ab08ded91a 100644 --- a/babeld/babel_interface.h +++ b/babeld/babel_interface.h @@ -94,6 +94,7 @@ struct buffered_update { /* init function */ void babel_if_init(void); +void babel_if_terminate(void); /* Callback functions for zebra client */ int babel_interface_up (int, struct zclient *, zebra_size_t, vrf_id_t); diff --git a/babeld/babel_main.c b/babeld/babel_main.c index 10ab1b53c3..ddc75f7182 100644 --- a/babeld/babel_main.c +++ b/babeld/babel_main.c @@ -305,9 +305,9 @@ babel_exit_properly(void) /* Uninstall and flush all routes. */ debugf(BABEL_DEBUG_COMMON, "Uninstall routes."); - flush_all_routes(); - babel_interface_close_all(); + babel_clean_routing_process(); babel_zebra_close_connexion(); + babel_if_terminate(); babel_save_state_file(); debugf(BABEL_DEBUG_COMMON, "Remove pid file."); debugf(BABEL_DEBUG_COMMON, "Done."); diff --git a/babeld/babeld.c b/babeld/babeld.c index 6f0a5a7bb4..73deb1dd92 100644 --- a/babeld/babeld.c +++ b/babeld/babeld.c @@ -299,8 +299,7 @@ babel_initial_noise(void) } /* Delete all the added babel routes, make babeld only speak to zebra. */ -static void -babel_clean_routing_process(void) +void babel_clean_routing_process(void) { flush_all_routes(); babel_interface_close_all(); diff --git a/babeld/babeld.h b/babeld/babeld.h index 5573719ab3..17a0381d2c 100644 --- a/babeld/babeld.h +++ b/babeld/babeld.h @@ -98,5 +98,6 @@ extern int redistribute_filter(const unsigned char *prefix, unsigned short plen, extern int resize_receive_buffer(int size); extern void schedule_neighbours_check(int msecs, int override); extern struct babel *babel_lookup(void); +extern void babel_clean_routing_process(void); #endif /* BABEL_BABELD_H */ From 464212db08fad3e61b1581040ed6381dc21287a0 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Wed, 14 Aug 2024 10:16:01 +0300 Subject: [PATCH 318/347] bgpd: Avoid use-after-free when doing `no router bgp` with auto created instances ``` ==1145965==ERROR: AddressSanitizer: heap-use-after-free on address 0x6030007159c0 at pc 0x55ade8d962d1 bp 0x7ffec4ce74c0 sp 0x7ffec4ce74b0 READ of size 8 at 0x6030007159c0 thread T0 0 0x55ade8d962d0 in no_router_bgp bgpd/bgp_vty.c:1701 1 0x7efe5aed19ed in cmd_execute_command_real lib/command.c:1002 2 0x7efe5aed1da3 in cmd_execute_command lib/command.c:1061 3 0x7efe5aed2303 in cmd_execute lib/command.c:1227 4 0x7efe5af6c023 in vty_command lib/vty.c:616 5 0x7efe5af6d2d2 in vty_execute lib/vty.c:1379 6 0x7efe5af77df2 in vtysh_read lib/vty.c:2374 7 0x7efe5af64c9b in event_call lib/event.c:1996 8 0x7efe5af03887 in frr_run lib/libfrr.c:1232 9 0x55ade8cd9850 in main bgpd/bgp_main.c:555 10 0x7efe5aa29d8f in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58 11 0x7efe5aa29e3f in __libc_start_main_impl ../csu/libc-start.c:392 12 0x55ade8cdc314 in _start (/usr/lib/frr/bgpd+0x16f314) ``` Signed-off-by: Donatas Abraitis --- bgpd/bgp_vty.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index a3180fd707..f09074c7cd 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -1695,15 +1695,18 @@ DEFUN (no_router_bgp, /* Cannot delete default instance if vrf instances exist */ if (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT) { - struct listnode *node; + struct listnode *node, *nnode; struct bgp *tmp_bgp; - for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, tmp_bgp)) { + for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, tmp_bgp)) { if (tmp_bgp->inst_type != BGP_INSTANCE_TYPE_VRF) continue; - if (CHECK_FLAG(tmp_bgp->vrf_flags, BGP_VRF_AUTO)) + if (CHECK_FLAG(tmp_bgp->vrf_flags, + BGP_VRF_AUTO)) { bgp_delete(tmp_bgp); + continue; + } if (CHECK_FLAG( tmp_bgp->af_flags[AFI_IP] From dd146614df69bbc519a47776981f6a2ecce188cf Mon Sep 17 00:00:00 2001 From: Mark Stapp Date: Wed, 14 Aug 2024 08:37:00 -0400 Subject: [PATCH 319/347] tests: add retries to nhg tests in all_proto_startup The all_protocol_startup topotest needs to allow for some delay between configuring nexthop-groups and their installation. Add some wait periods in a couple of nhg test cases. Signed-off-by: Mark Stapp --- .../test_all_protocol_startup.py | 63 +++++++++++++++---- 1 file changed, 50 insertions(+), 13 deletions(-) diff --git a/tests/topotests/all_protocol_startup/test_all_protocol_startup.py b/tests/topotests/all_protocol_startup/test_all_protocol_startup.py index 902343ce42..80bd2505a7 100644 --- a/tests/topotests/all_protocol_startup/test_all_protocol_startup.py +++ b/tests/topotests/all_protocol_startup/test_all_protocol_startup.py @@ -39,7 +39,9 @@ ) import json +import functools +# Global that must be set on a failure to stop subsequent tests from being run fatal_error = "" @@ -400,17 +402,27 @@ def test_converge_protocols(): def route_get_nhg_id(route_str): - net = get_topogen().net - output = net["r1"].cmd( - 'vtysh -c "show ip route {} nexthop-group"'.format(route_str) - ) - match = re.search(r"Nexthop Group ID: (\d+)", output) - assert match is not None, "Nexthop Group ID not found for sharpd route {}".format( - route_str - ) + global fatal_error - nhg_id = int(match.group(1)) - return nhg_id + def get_func(route_str): + net = get_topogen().net + output = net["r1"].cmd( + 'vtysh -c "show ip route {} nexthop-group"'.format(route_str) + ) + match = re.search(r"Nexthop Group ID: (\d+)", output) + if match is not None: + nhg_id = int(match.group(1)) + return nhg_id + else: + return None + + test_func = functools.partial(get_func, route_str) + _, nhg_id = topotest.run_and_expect_type(test_func, int, count=30, wait=1) + if nhg_id == None: + fatal_error = "Nexthop Group ID not found for route {}".format(route_str) + assert nhg_id != None, fatal_error + else: + return nhg_id def verify_nexthop_group(nhg_id, recursive=False, ecmp=0): @@ -487,8 +499,12 @@ def verify_nexthop_group(nhg_id, recursive=False, ecmp=0): def verify_route_nexthop_group(route_str, recursive=False, ecmp=0): + global fatal_error + # Verify route and that zebra created NHGs for and they are valid/installed + nhg_id = route_get_nhg_id(route_str) + verify_nexthop_group(nhg_id, recursive, ecmp) @@ -1648,8 +1664,13 @@ def test_mpls_interfaces(): def test_resilient_nexthop_group(): + global fatal_error net = get_topogen().net + # Skip if previous fatal error condition is raised + if fatal_error != "": + pytest.skip(fatal_error) + result = required_linux_kernel_version("5.19") if result is not True: pytest.skip("Kernel requirements are not met, kernel version should be >= 5.19") @@ -1658,8 +1679,18 @@ def test_resilient_nexthop_group(): 'vtysh -c "conf" -c "nexthop-group resilience" -c "resilient buckets 64 idle-timer 128 unbalanced-timer 256" -c "nexthop 1.1.1.1 r1-eth1 onlink" -c "nexthop 1.1.1.2 r1-eth2 onlink"' ) - output = net["r1"].cmd('vtysh -c "show nexthop-group rib sharp"') - buckets = re.findall(r"Buckets", output) + # Temporary helper function + def _show_func(): + output = net["r1"].cmd('vtysh -c "show nexthop-group rib sharp"') + buckets = re.findall(r"Buckets", output) + + return len(buckets) + + _, result = topotest.run_and_expect(_show_func, 1, count=30, wait=1) + if result != 1: + fatal_error = "Resilient NHG not created in zebra" + + assert result == 1, fatal_error output = net["r1"].cmd('vtysh -c "show nexthop-group rib sharp json"') @@ -1672,8 +1703,14 @@ def test_resilient_nexthop_group(): if "buckets" in n: break + if "buckets" not in n: + fatal_error = "Resilient NHG not found in json output" + assert "buckets" in n, fatal_error + verify_nexthop_group(int(nhgid)) - assert len(buckets) == 1, "Resilient NHG not created in zebra" + + # Remove NHG + net["r1"].cmd('vtysh -c "conf" -c "no nexthop-group resilience"') def test_shutdown_check_stderr(): From 64594f8a6830eec5cc20b9c8a8676d1f62a16bcd Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Wed, 14 Aug 2024 15:36:36 +0200 Subject: [PATCH 320/347] bgpd: fix memory type for static->prd_pretty A crash happens when executing the following command: > ubuntu2204hwe# conf > ubuntu2204hwe(config)# router bgp 65500 > ubuntu2204hwe(config-router)# ! > ubuntu2204hwe(config-router)# address-family ipv4 unicast > ubuntu2204hwe(config-router-af)# sid vpn export auto > ubuntu2204hwe(config-router-af)# exit-address-family > ubuntu2204hwe(config-router)# ! > ubuntu2204hwe(config-router)# address-family ipv4 vpn > ubuntu2204hwe(config-router-af)# network 4.4.4.4/32 rd 55:55 label 556 > ubuntu2204hwe(config-router-af)# network 5.5.5.5/32 rd 662:33 label 232 > ubuntu2204hwe(config-router-af)# exit-address-family > ubuntu2204hwe(config-router)# exit > ubuntu2204hwe(config)# ! > ubuntu2204hwe(config)# no router bgp The crash analysis indicates a memory item has been freed. > #6 0x000076066a629c15 in mt_count_free (mt=0x56b57be85e00 , ptr=0x60200038b4f0) > at lib/memory.c:73 > #7 mt_count_free (ptr=0x60200038b4f0, mt=0x56b57be85e00 ) at lib/memory.c:69 > #8 qfree (mt=mt@entry=0x56b57be85e00 , ptr=0x60200038b4f0) at lib/memory.c:129 > #9 0x000056b57bb09ce9 in bgp_free (bgp=) at bgpd/bgpd.c:4120 > #10 0x000056b57bb0aa73 in bgp_unlock (bgp=) at ./bgpd/bgpd.h:2513 > #11 peer_free (peer=0x62a000000200) at bgpd/bgpd.c:1313 > #12 0x000056b57bb0aca8 in peer_unlock_with_caller (name=, peer=) > at bgpd/bgpd.c:1344 > #13 0x000076066a6dbb2c in event_call (thread=thread@entry=0x7ffc8cae1d60) at lib/event.c:2011 > #14 0x000076066a60aa88 in frr_run (master=0x613000000040) at lib/libfrr.c:1214 > #15 0x000056b57b8b2c44 in main (argc=, argv=) at bgpd/bgp_main.c:543 Actually, the BGP_NAME item has not been used at allocation for static->prd_pretty, and this results in reaching 0 quicker at bgp deletion. Fix this by reassigning MTYPE_BGP_NAME to prd_pretty. Fixes: 16600df2c4f4 ("bgpd: fix show run of network route-distinguisher") Signed-off-by: Philippe Guibert --- bgpd/bgp_route.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 2a9fc6ce0d..5b5c0fa6d4 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -7177,7 +7177,7 @@ int bgp_static_set(struct vty *vty, bool negate, const char *ip_str, bgp_static->prd = prd; if (rd_str) - bgp_static->prd_pretty = XSTRDUP(MTYPE_BGP, + bgp_static->prd_pretty = XSTRDUP(MTYPE_BGP_NAME, rd_str); if (rmap) { From b0c86804f8cae69a442a3521bb3c47401928f213 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 14 Aug 2024 10:18:41 -0400 Subject: [PATCH 321/347] tests: Fix route_scale startup issues Upstream CI is frequently running into a situation where the routes are not being installed. These routes start at the beginning and suddenly in the middle they start working properly. D 1.0.15.183/32 [150/0] via 192.168.0.1, r1-eth0 inactive, weight 1, 00:10:17 via 192.168.1.1, r1-eth1 inactive, weight 1, 00:10:17 D 1.0.15.184/32 [150/0] via 192.168.0.1, r1-eth0 inactive, weight 1, 00:10:17 via 192.168.1.1, r1-eth1 inactive, weight 1, 00:10:17 D 1.0.15.185/32 [150/0] via 192.168.0.1, r1-eth0 inactive, weight 1, 00:10:17 via 192.168.1.1, r1-eth1 inactive, weight 1, 00:10:17 D>* 1.0.15.186/32 [150/0] via 192.168.0.1, r1-eth0, weight 1, 00:10:17 * via 192.168.1.1, r1-eth1, weight 1, 00:10:17 D>* 1.0.15.187/32 [150/0] via 192.168.0.1, r1-eth0, weight 1, 00:10:17 * via 192.168.1.1, r1-eth1, weight 1, 00:10:17 D>* 1.0.15.188/32 [150/0] via 192.168.0.1, r1-eth0, weight 1, 00:10:17 Turning on some debugs showed that the failed installed routes are trying to be matched against the default route. Thus implying all the connected routes for the test are not yet successfully installed. Let's modify the test(s) on startup to just ensure that the connected routes are installed correctly. I am no longer seeing the problem after this change. Signed-off-by: Donald Sharp --- .../topotests/route_scale/scale_test_common.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tests/topotests/route_scale/scale_test_common.py b/tests/topotests/route_scale/scale_test_common.py index 0b239dc04b..4b19bebe67 100644 --- a/tests/topotests/route_scale/scale_test_common.py +++ b/tests/topotests/route_scale/scale_test_common.py @@ -86,6 +86,23 @@ def scale_converge_protocols(): if tgen.routers_have_failure(): pytest.skip(tgen.errors) + logger.info("Ensuring that Connected Routes are actually installed") + r1 = tgen.gears["r1"] + expected = { + "routes": [ + {"fib": 32, "rib": 32, "type": "connected"}, + {"fib": 32, "rib": 32, "type": "local"}, + ], + "routesTotal": 64, + "routesTotalFib": 64, + } + + test_func = partial( + topotest.router_json_cmp, r1, "show ip route summary json", expected + ) + success, result = topotest.run_and_expect(test_func, None, 60, 1) + assert success, "Connected routes are not properly installed:\n{}".format(result) + def run_one_setup(r1, s): "Run one ecmp config" From 88c6471720650a0563e55fc3ebf8982171b4a171 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Wed, 14 Aug 2024 20:13:44 +0300 Subject: [PATCH 322/347] Revert "bgpd: fix sending ipv6 local nexthop if global present" This reverts commit 424fe0bf809c1d84f16aba3f5e5f8249af29083b. --- bgpd/bgp_zebra.c | 33 +++++---------------------------- 1 file changed, 5 insertions(+), 28 deletions(-) diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 5bb177b2f7..e72a739798 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -303,12 +303,11 @@ static int bgp_ifp_down(struct interface *ifp) static int bgp_interface_address_add(ZAPI_CALLBACK_ARGS) { - struct connected *ifc, *connected; + struct connected *ifc; struct bgp *bgp; struct peer *peer; struct prefix *addr; struct listnode *node, *nnode; - bool v6_ll_in_nh_global; afi_t afi; safi_t safi; @@ -343,27 +342,6 @@ static int bgp_interface_address_add(ZAPI_CALLBACK_ARGS) addr = ifc->address; for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { - v6_ll_in_nh_global = false; - - if (IN6_IS_ADDR_LINKLOCAL(&peer->nexthop.v6_global)) { - frr_each (if_connected, ifc->ifp->connected, - connected) { - if (connected->address->family != - AF_INET6) - continue; - if (!IPV6_ADDR_SAME(&connected->address - ->u.prefix6, - &peer->nexthop - .v6_global)) - continue; - /* peer->nexthop.v6_global contains a link-local address - * that needs to be replaced by the global address. - */ - v6_ll_in_nh_global = true; - break; - } - } - /* * If the Peer's interface name matches the * interface name for which BGP received the @@ -374,11 +352,10 @@ static int bgp_interface_address_add(ZAPI_CALLBACK_ARGS) * into peer's v6_global and send updates out * with new nexthop addr. */ - if (v6_ll_in_nh_global || - (peer->conf_if && - strcmp(peer->conf_if, ifc->ifp->name) == 0 && - (IS_MAPPED_IPV6(&peer->nexthop.v6_global) || - IN6_IS_ADDR_LINKLOCAL(&peer->nexthop.v6_global)))) { + if ((peer->conf_if && + (strcmp(peer->conf_if, ifc->ifp->name) == 0)) && + ((IS_MAPPED_IPV6(&peer->nexthop.v6_global)) || + IN6_IS_ADDR_LINKLOCAL(&peer->nexthop.v6_global))) { if (bgp_debug_zebra(ifc->address)) { zlog_debug("Update peer %pBP's current intf global addr from %pI6 to %pI6 and send updates", peer, From e85077c69d01e3ab9a2309734fcea00760d6a97b Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Wed, 14 Aug 2024 20:14:12 +0300 Subject: [PATCH 323/347] Revert "bgpd: log new ipv6 global in bgp_interface_address_add" This reverts commit b083885198157555bbb916ecae9809c5d67a567b. --- bgpd/bgp_zebra.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index e72a739798..c407008d57 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -357,10 +357,9 @@ static int bgp_interface_address_add(ZAPI_CALLBACK_ARGS) ((IS_MAPPED_IPV6(&peer->nexthop.v6_global)) || IN6_IS_ADDR_LINKLOCAL(&peer->nexthop.v6_global))) { if (bgp_debug_zebra(ifc->address)) { - zlog_debug("Update peer %pBP's current intf global addr from %pI6 to %pI6 and send updates", + zlog_debug("Update peer %pBP's current intf addr %pI6 and send updates", peer, - &peer->nexthop.v6_global, - &addr->u.prefix6); + &peer->nexthop.v6_global); } memcpy(&peer->nexthop.v6_global, &addr->u.prefix6, IPV6_MAX_BYTELEN); From 0a7e9711878074ba6c223238bb1c130be28cb1d4 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Wed, 14 Aug 2024 20:14:16 +0300 Subject: [PATCH 324/347] Revert "bgpd: reduce bgp_interface_address_add indentation" This reverts commit 778e0df87b7a846f46d84f61ea889a32fe578e49. --- bgpd/bgp_zebra.c | 84 ++++++++++++++++++++++++++---------------------- 1 file changed, 45 insertions(+), 39 deletions(-) diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index c407008d57..79bb43bda9 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -325,47 +325,53 @@ static int bgp_interface_address_add(ZAPI_CALLBACK_ARGS) if (!bgp) return 0; - if (!if_is_operative(ifc->ifp)) - return 0; - - bgp_connected_add(bgp, ifc); - - /* If we have learnt of any neighbors on this interface, - * check to kick off any BGP interface-based neighbors, - * but only if this is a link-local address. - */ - if (IN6_IS_ADDR_LINKLOCAL(&ifc->address->u.prefix6) && - !list_isempty(ifc->ifp->nbr_connected)) - bgp_start_interface_nbrs(bgp, ifc->ifp); - else if (ifc->address->family == AF_INET6 && - !IN6_IS_ADDR_LINKLOCAL(&ifc->address->u.prefix6)) { - addr = ifc->address; + if (if_is_operative(ifc->ifp)) { + bgp_connected_add(bgp, ifc); - for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { - /* - * If the Peer's interface name matches the - * interface name for which BGP received the - * update and if the received interface address - * is a globalV6 and if the peer is currently - * using a v4-mapped-v6 addr or a link local - * address, then copy the Rxed global v6 addr - * into peer's v6_global and send updates out - * with new nexthop addr. - */ - if ((peer->conf_if && - (strcmp(peer->conf_if, ifc->ifp->name) == 0)) && - ((IS_MAPPED_IPV6(&peer->nexthop.v6_global)) || - IN6_IS_ADDR_LINKLOCAL(&peer->nexthop.v6_global))) { - if (bgp_debug_zebra(ifc->address)) { - zlog_debug("Update peer %pBP's current intf addr %pI6 and send updates", - peer, - &peer->nexthop.v6_global); + /* If we have learnt of any neighbors on this interface, + * check to kick off any BGP interface-based neighbors, + * but only if this is a link-local address. + */ + if (IN6_IS_ADDR_LINKLOCAL(&ifc->address->u.prefix6) + && !list_isempty(ifc->ifp->nbr_connected)) + bgp_start_interface_nbrs(bgp, ifc->ifp); + else if (ifc->address->family == AF_INET6 && + !IN6_IS_ADDR_LINKLOCAL(&ifc->address->u.prefix6)) { + addr = ifc->address; + + for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { + /* + * If the Peer's interface name matches the + * interface name for which BGP received the + * update and if the received interface address + * is a globalV6 and if the peer is currently + * using a v4-mapped-v6 addr or a link local + * address, then copy the Rxed global v6 addr + * into peer's v6_global and send updates out + * with new nexthop addr. + */ + if ((peer->conf_if && + (strcmp(peer->conf_if, ifc->ifp->name) == + 0)) && + ((IS_MAPPED_IPV6( + &peer->nexthop.v6_global)) || + IN6_IS_ADDR_LINKLOCAL( + &peer->nexthop.v6_global))) { + + if (bgp_debug_zebra(ifc->address)) { + zlog_debug( + "Update peer %pBP's current intf addr %pI6 and send updates", + peer, + &peer->nexthop + .v6_global); + } + memcpy(&peer->nexthop.v6_global, + &addr->u.prefix6, + IPV6_MAX_BYTELEN); + FOREACH_AFI_SAFI (afi, safi) + bgp_announce_route(peer, afi, + safi, true); } - memcpy(&peer->nexthop.v6_global, - &addr->u.prefix6, IPV6_MAX_BYTELEN); - FOREACH_AFI_SAFI (afi, safi) - bgp_announce_route(peer, afi, safi, - true); } } } From 8a7c4c023e2a4cbecfd93ad0b680a773c2964e37 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Wed, 14 Aug 2024 20:14:20 +0300 Subject: [PATCH 325/347] Revert "bgpd: optimize bgp_interface_address_add" This reverts commit 8599fe2b5e34b2ac1a46a14983ddcc2336e9116d. --- bgpd/bgp_zebra.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 79bb43bda9..00013b1e7a 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -335,11 +335,13 @@ static int bgp_interface_address_add(ZAPI_CALLBACK_ARGS) if (IN6_IS_ADDR_LINKLOCAL(&ifc->address->u.prefix6) && !list_isempty(ifc->ifp->nbr_connected)) bgp_start_interface_nbrs(bgp, ifc->ifp); - else if (ifc->address->family == AF_INET6 && - !IN6_IS_ADDR_LINKLOCAL(&ifc->address->u.prefix6)) { + else { addr = ifc->address; for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { + if (addr->family == AF_INET) + continue; + /* * If the Peer's interface name matches the * interface name for which BGP received the @@ -353,6 +355,7 @@ static int bgp_interface_address_add(ZAPI_CALLBACK_ARGS) if ((peer->conf_if && (strcmp(peer->conf_if, ifc->ifp->name) == 0)) && + !IN6_IS_ADDR_LINKLOCAL(&addr->u.prefix6) && ((IS_MAPPED_IPV6( &peer->nexthop.v6_global)) || IN6_IS_ADDR_LINKLOCAL( From efd8f613f97480a0aeb90f0446c78bf87f6442f4 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Wed, 14 Aug 2024 20:14:55 +0300 Subject: [PATCH 326/347] Revert "topotests: update bgp_vrf_leaking_5549_routes" This reverts commit f1b8364ab3784cebfc0689883efdb21ac7d06213. --- .../pe1/results/vrf10_ipv4_unicast.json | 7 +++---- .../pe1/results/vrf20_ipv4_unicast.json | 7 +++---- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/tests/topotests/bgp_vrf_leaking_5549_routes/pe1/results/vrf10_ipv4_unicast.json b/tests/topotests/bgp_vrf_leaking_5549_routes/pe1/results/vrf10_ipv4_unicast.json index f664bb6b52..768bffbe9d 100644 --- a/tests/topotests/bgp_vrf_leaking_5549_routes/pe1/results/vrf10_ipv4_unicast.json +++ b/tests/topotests/bgp_vrf_leaking_5549_routes/pe1/results/vrf10_ipv4_unicast.json @@ -15,16 +15,15 @@ "origin": "incomplete", "nexthops": [ { - "ip": "::ffff:c000:202", "hostname": "ce1", "afi": "ipv6", - "scope": "global" + "scope": "global", + "used": true }, { "hostname": "ce1", "afi": "ipv6", - "scope": "link-local", - "used": true + "scope": "link-local" } ] } diff --git a/tests/topotests/bgp_vrf_leaking_5549_routes/pe1/results/vrf20_ipv4_unicast.json b/tests/topotests/bgp_vrf_leaking_5549_routes/pe1/results/vrf20_ipv4_unicast.json index 3498ed4326..1e93715270 100644 --- a/tests/topotests/bgp_vrf_leaking_5549_routes/pe1/results/vrf20_ipv4_unicast.json +++ b/tests/topotests/bgp_vrf_leaking_5549_routes/pe1/results/vrf20_ipv4_unicast.json @@ -17,16 +17,15 @@ "nhVrfName": "vrf10", "nexthops": [ { - "ip": "::ffff:c000:202", "hostname": "pe1", "afi": "ipv6", - "scope": "global" + "scope": "global", + "used": true }, { "hostname": "pe1", "afi": "ipv6", - "scope": "link-local", - "used": true + "scope": "link-local" } ] } From 863da18d1e15b1538438f1e15b59419094ecd797 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Wed, 14 Aug 2024 20:14:59 +0300 Subject: [PATCH 327/347] Revert "bgpd: prefer link-local to a ipv4-mapped ipv6 global" This reverts commit 5dd731af8421e8b3070eec0b3af4ad234c95c6bb. --- bgpd/bgp_nht.c | 41 +++++++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c index 8ce45558e9..dc6dc54a3b 100644 --- a/bgpd/bgp_nht.c +++ b/bgpd/bgp_nht.c @@ -320,6 +320,11 @@ int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop, afi = BGP_ATTR_MP_NEXTHOP_LEN_IP6(pi->attr) ? AFI_IP6 : AFI_IP; + /* Validation for the ipv4 mapped ipv6 nexthop. */ + if (IS_MAPPED_IPV6(&pi->attr->mp_nexthop_global)) { + afi = AFI_IP; + } + /* This will return true if the global IPv6 NH is a link local * addr */ if (make_prefix(afi, pi, &p) < 0) @@ -1035,11 +1040,19 @@ static int make_prefix(int afi, struct bgp_path_info *pi, struct prefix *p) p->u.prefix4 = p_orig->u.prefix4; p->prefixlen = p_orig->prefixlen; } else { - if (p_orig->family == AF_EVPN) - p->u.prefix4 = pi->attr->mp_nexthop_global_in; - else - p->u.prefix4 = pi->attr->nexthop; - p->prefixlen = IPV4_MAX_BITLEN; + if (IS_MAPPED_IPV6(&pi->attr->mp_nexthop_global)) { + ipv4_mapped_ipv6_to_ipv4( + &pi->attr->mp_nexthop_global, &ipv4); + p->u.prefix4 = ipv4; + p->prefixlen = IPV4_MAX_BITLEN; + } else { + if (p_orig->family == AF_EVPN) + p->u.prefix4 = + pi->attr->mp_nexthop_global_in; + else + p->u.prefix4 = pi->attr->nexthop; + p->prefixlen = IPV4_MAX_BITLEN; + } } break; case AFI_IP6: @@ -1055,7 +1068,6 @@ static int make_prefix(int afi, struct bgp_path_info *pi, struct prefix *p) /* If we receive MP_REACH nexthop with ::(LL) * or LL(LL), use LL address as nexthop cache. */ - p->prefixlen = IPV6_MAX_BITLEN; if (pi->attr && pi->attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL && @@ -1070,22 +1082,15 @@ static int make_prefix(int afi, struct bgp_path_info *pi, struct prefix *p) pi->attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) { if (CHECK_FLAG(pi->attr->nh_flags, - BGP_ATTR_NH_MP_PREFER_GLOBAL)) { - if (IS_MAPPED_IPV6( - &pi->attr->mp_nexthop_global)) { - ipv4_mapped_ipv6_to_ipv4( - &pi->attr->mp_nexthop_global, - &ipv4); - p->u.prefix4 = ipv4; - p->prefixlen = IPV4_MAX_BITLEN; - } else - p->u.prefix6 = - pi->attr->mp_nexthop_global; - } else + BGP_ATTR_NH_MP_PREFER_GLOBAL)) + p->u.prefix6 = + pi->attr->mp_nexthop_global; + else p->u.prefix6 = pi->attr->mp_nexthop_local; } else p->u.prefix6 = pi->attr->mp_nexthop_global; + p->prefixlen = IPV6_MAX_BITLEN; } break; default: From 8dffec1c4e0ee4c2e26486b345b086c8fb1a1ced Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Wed, 14 Aug 2024 20:15:04 +0300 Subject: [PATCH 328/347] Revert "bgpd: set ipv4-mapped ipv6 for ipv4 with ipv6 nexthop" This reverts commit fc5a738409eac9ca938cbb398872ea77d9cc5023. --- bgpd/bgp_updgrp_packet.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/bgpd/bgp_updgrp_packet.c b/bgpd/bgp_updgrp_packet.c index 6e30d4f846..7c92bbd514 100644 --- a/bgpd/bgp_updgrp_packet.c +++ b/bgpd/bgp_updgrp_packet.c @@ -523,13 +523,11 @@ struct stream *bpacket_reformat_for_peer(struct bpacket *pkt, gnh_modified = 1; } - if (peer->nexthop.v4.s_addr != INADDR_ANY && - (IN6_IS_ADDR_UNSPECIFIED(mod_v6nhg) || - (IN6_IS_ADDR_LINKLOCAL(mod_v6nhg) && - peer->connection->su.sa.sa_family == AF_INET6 && - paf->afi == AFI_IP))) { - ipv4_to_ipv4_mapped_ipv6(mod_v6nhg, peer->nexthop.v4); - gnh_modified = 1; + if (IN6_IS_ADDR_UNSPECIFIED(mod_v6nhg)) { + if (peer->nexthop.v4.s_addr != INADDR_ANY) { + ipv4_to_ipv4_mapped_ipv6(mod_v6nhg, + peer->nexthop.v4); + } } if (IS_MAPPED_IPV6(&peer->nexthop.v6_global)) { From 9a5c3b931e0c4cf6f8bf7f9b2e31a04ea96250af Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Wed, 14 Aug 2024 20:15:08 +0300 Subject: [PATCH 329/347] Revert "tests: ipv6 global removal in bgp_nexthop_mp_ipv4_6" This reverts commit 04c220bedb63334a65677a46ef84938cc812221f. --- .../r1/bgp_ipv6_step2.json | 90 ------------------- .../r2/bgp_ipv6_step2.json | 48 ---------- .../r3/bgp_ipv6_step2.json | 48 ---------- .../r4/bgp_ipv6_step2.json | 49 ---------- .../r5/bgp_ipv6_step2.json | 49 ---------- .../r6/bgp_ipv6_step2.json | 48 ---------- .../r7/bgp_ipv6_step2.json | 48 ---------- .../r8/bgp_ipv6_step2.json | 48 ---------- .../rr1/bgp_ipv6_step2.json | 62 ------------- .../test_nexthop_mp_ipv4_6.py | 52 ----------- 10 files changed, 542 deletions(-) delete mode 100755 tests/topotests/bgp_nexthop_mp_ipv4_6/r1/bgp_ipv6_step2.json delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/r2/bgp_ipv6_step2.json delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/r3/bgp_ipv6_step2.json delete mode 100755 tests/topotests/bgp_nexthop_mp_ipv4_6/r4/bgp_ipv6_step2.json delete mode 100755 tests/topotests/bgp_nexthop_mp_ipv4_6/r5/bgp_ipv6_step2.json delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/r6/bgp_ipv6_step2.json delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/r7/bgp_ipv6_step2.json delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/r8/bgp_ipv6_step2.json delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/rr1/bgp_ipv6_step2.json diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r1/bgp_ipv6_step2.json b/tests/topotests/bgp_nexthop_mp_ipv4_6/r1/bgp_ipv6_step2.json deleted file mode 100755 index f7c5c7c3b5..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r1/bgp_ipv6_step2.json +++ /dev/null @@ -1,90 +0,0 @@ -{ - "routes": { - "fd00:100::/64": [ - { - "valid": true, - "bestpath": true, - "path": "", - "nexthops": [ - { - "ip": "::", - "afi": "ipv6", - "used": true - } - ] - } - ], - "fd00:700::/64": [ - { - "valid": true, - "multipath": true, - "path": "65000 65700", - "nexthops": [ - { - "ip": "fd00:0:2::3", - "afi": "ipv6", - "scope": "global" - }, - { - "afi": "ipv6", - "scope": "link-local", - "used": true - } - ] - }, - { - "valid": true, - "bestpath": true, - "path": "65000 65700", - "nexthops": [ - { - "ip": "fd00:0:1::2", - "afi": "ipv6", - "scope": "global" - }, - { - "afi": "ipv6", - "scope": "link-local", - "used": true - } - ] - } - ], - "fd00:800::/64": [ - { - "valid": true, - "multipath": true, - "path": "65000 65800", - "nexthops": [ - { - "ip": "fd00:0:2::3", - "afi": "ipv6", - "scope": "global" - }, - { - "afi": "ipv6", - "scope": "link-local", - "used": true - } - ] - }, - { - "valid": true, - "bestpath": true, - "path": "65000 65800", - "nexthops": [ - { - "ip": "fd00:0:1::2", - "afi": "ipv6", - "scope": "global" - }, - { - "afi": "ipv6", - "scope": "link-local", - "used": true - } - ] - } - ] - } -} diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r2/bgp_ipv6_step2.json b/tests/topotests/bgp_nexthop_mp_ipv4_6/r2/bgp_ipv6_step2.json deleted file mode 100644 index 21f36089b6..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r2/bgp_ipv6_step2.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "routes": { - "fd00:100::/64": [ - { - "valid": true, - "bestpath": true, - "path": "65100", - "nexthops": [ - { - "afi": "ipv6", - "scope": "link-local", - "used": true - } - ] - } - ], - "fd00:700::/64": [ - { - "valid": true, - "bestpath": true, - "path": "65700", - "nexthops": [ - { - "ip": "fd00:0:9::7", - "scope": "global", - "afi": "ipv6", - "used": true - } - ] - } - ], - "fd00:800::/64": [ - { - "valid": true, - "bestpath": true, - "path": "65800", - "nexthops": [ - { - "ip": "fd00:0:9::8", - "scope": "global", - "afi": "ipv6", - "used": true - } - ] - } - ] - } -} diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r3/bgp_ipv6_step2.json b/tests/topotests/bgp_nexthop_mp_ipv4_6/r3/bgp_ipv6_step2.json deleted file mode 100644 index 21f36089b6..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r3/bgp_ipv6_step2.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "routes": { - "fd00:100::/64": [ - { - "valid": true, - "bestpath": true, - "path": "65100", - "nexthops": [ - { - "afi": "ipv6", - "scope": "link-local", - "used": true - } - ] - } - ], - "fd00:700::/64": [ - { - "valid": true, - "bestpath": true, - "path": "65700", - "nexthops": [ - { - "ip": "fd00:0:9::7", - "scope": "global", - "afi": "ipv6", - "used": true - } - ] - } - ], - "fd00:800::/64": [ - { - "valid": true, - "bestpath": true, - "path": "65800", - "nexthops": [ - { - "ip": "fd00:0:9::8", - "scope": "global", - "afi": "ipv6", - "used": true - } - ] - } - ] - } -} diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r4/bgp_ipv6_step2.json b/tests/topotests/bgp_nexthop_mp_ipv4_6/r4/bgp_ipv6_step2.json deleted file mode 100755 index 7d0786c0ef..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r4/bgp_ipv6_step2.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "routes": { - "fd00:100::/64": [ - { - "valid": true, - "bestpath": true, - "path": "65100", - "nexthops": [ - { - "ip": "2001:db8::2", - "afi": "ipv6", - "scope": "global", - "used": true - } - ] - } - ], - "fd00:700::/64": [ - { - "valid": true, - "bestpath": true, - "path": "65700", - "nexthops": [ - { - "ip": "fd00:0:9::7", - "scope": "global", - "afi": "ipv6", - "used": true - } - ] - } - ], - "fd00:800::/64": [ - { - "valid": true, - "bestpath": true, - "path": "65800", - "nexthops": [ - { - "ip": "fd00:0:9::8", - "scope": "global", - "afi": "ipv6", - "used": true - } - ] - } - ] - } -} diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r5/bgp_ipv6_step2.json b/tests/topotests/bgp_nexthop_mp_ipv4_6/r5/bgp_ipv6_step2.json deleted file mode 100755 index 7d0786c0ef..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r5/bgp_ipv6_step2.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "routes": { - "fd00:100::/64": [ - { - "valid": true, - "bestpath": true, - "path": "65100", - "nexthops": [ - { - "ip": "2001:db8::2", - "afi": "ipv6", - "scope": "global", - "used": true - } - ] - } - ], - "fd00:700::/64": [ - { - "valid": true, - "bestpath": true, - "path": "65700", - "nexthops": [ - { - "ip": "fd00:0:9::7", - "scope": "global", - "afi": "ipv6", - "used": true - } - ] - } - ], - "fd00:800::/64": [ - { - "valid": true, - "bestpath": true, - "path": "65800", - "nexthops": [ - { - "ip": "fd00:0:9::8", - "scope": "global", - "afi": "ipv6", - "used": true - } - ] - } - ] - } -} diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r6/bgp_ipv6_step2.json b/tests/topotests/bgp_nexthop_mp_ipv4_6/r6/bgp_ipv6_step2.json deleted file mode 100644 index 55912dd74c..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r6/bgp_ipv6_step2.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "routes": { - "fd00:100::/64": [ - { - "valid": true, - "bestpath": true, - "nexthops": [ - { - "ip": "2001:db8::2", - "afi": "ipv6", - "scope": "global", - "used": true - } - ] - } - ], - "fd00:700::/64": [ - { - "valid": true, - "bestpath": true, - "path": "65700", - "nexthops": [ - { - "ip": "fd00:0:9::7", - "afi": "ipv6", - "scope": "global", - "used": true - } - ] - } - ], - "fd00:800::/64": [ - { - "valid": true, - "bestpath": true, - "path": "65800", - "nexthops": [ - { - "ip": "fd00:0:9::8", - "afi": "ipv6", - "scope": "global", - "used": true - } - ] - } - ] - } -} diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r7/bgp_ipv6_step2.json b/tests/topotests/bgp_nexthop_mp_ipv4_6/r7/bgp_ipv6_step2.json deleted file mode 100644 index 8fe5f7c1de..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r7/bgp_ipv6_step2.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "routes": { - "fd00:100::/64": [ - { - "valid": true, - "bestpath": true, - "path": "65000 65100", - "nexthops": [ - { - "ip": "fd00:0:9::6", - "afi": "ipv6", - "scope": "global", - "used": true - } - ] - } - ], - "fd00:700::/64": [ - { - "valid": true, - "bestpath": true, - "path": "", - "nexthops": [ - { - "ip": "::", - "afi": "ipv6", - "used": true - } - ] - } - ], - "fd00:800::/64": [ - { - "valid": true, - "bestpath": true, - "path": "65800", - "nexthops": [ - { - "ip": "fd00:0:9::8", - "afi": "ipv6", - "scope": "global", - "used": true - } - ] - } - ] - } -} diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r8/bgp_ipv6_step2.json b/tests/topotests/bgp_nexthop_mp_ipv4_6/r8/bgp_ipv6_step2.json deleted file mode 100644 index 20f4940328..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r8/bgp_ipv6_step2.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "routes": { - "fd00:100::/64": [ - { - "valid": true, - "bestpath": true, - "path": "65000 65100", - "nexthops": [ - { - "ip": "fd00:0:9::6", - "afi": "ipv6", - "scope": "global", - "used": true - } - ] - } - ], - "fd00:700::/64": [ - { - "valid": true, - "bestpath": true, - "path": "65700", - "nexthops": [ - { - "ip": "fd00:0:9::7", - "afi": "ipv6", - "scope": "global", - "used": true - } - ] - } - ], - "fd00:800::/64": [ - { - "valid": true, - "bestpath": true, - "path": "", - "nexthops": [ - { - "ip": "::", - "afi": "ipv6", - "used": true - } - ] - } - ] - } -} diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/rr1/bgp_ipv6_step2.json b/tests/topotests/bgp_nexthop_mp_ipv4_6/rr1/bgp_ipv6_step2.json deleted file mode 100644 index 4ab0e1c2ae..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/rr1/bgp_ipv6_step2.json +++ /dev/null @@ -1,62 +0,0 @@ -{ - "routes": { - "fd00:100::/64": [ - { - "valid": true, - "bestpath": true, - "path": "65100", - "nexthops": [ - { - "ip": "2001:db8::2", - "afi": "ipv6", - "scope": "global", - "used": true - } - ] - }, - { - "valid": true, - "multipath": true, - "path": "65100", - "nexthops": [ - { - "ip": "2001:db8::3", - "afi": "ipv6", - "scope": "global", - "used": true - } - ] - } - ], - "fd00:700::/64": [ - { - "valid": true, - "bestpath": true, - "path": "65700", - "nexthops": [ - { - "ip": "fd00:0:9::7", - "afi": "ipv6", - "scope": "global", - "used": true - } - ] - } - ], - "fd00:800::/64": [ - { - "valid": true, - "bestpath": true, - "path": "65800", - "nexthops": [ - { - "ip": "fd00:0:9::8", - "afi": "ipv6", - "scope": "global", - "used": true - } - ] - } - ] - } -} diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/test_nexthop_mp_ipv4_6.py b/tests/topotests/bgp_nexthop_mp_ipv4_6/test_nexthop_mp_ipv4_6.py index 911a6d757f..4da13b16d1 100644 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/test_nexthop_mp_ipv4_6.py +++ b/tests/topotests/bgp_nexthop_mp_ipv4_6/test_nexthop_mp_ipv4_6.py @@ -226,58 +226,6 @@ def test_bgp_ping_ok_step1(): check_ping("h1", "fd00:800::1", True, 5, 1) -def test_bgp_ipv6_nexthop_step2(): - """ - Remove IPv6 global on r1 and r7 - Assert that BGP has correct ipv6 nexthops. - """ - - tgen = get_topogen() - if tgen.routers_have_failure(): - pytest.skip(tgen.errors) - - tgen.gears["r1"].vtysh_cmd( - """ -configure -interface eth-r2 - no ipv6 address fd00:0:1::1/64 -! -interface eth-r3 - no ipv6 address fd00:0:2::1/64 -""" - ) - - for rname, router in tgen.routers().items(): - if "h" in rname: - # hosts - continue - if "rs1" in rname: - continue - ref_file = "{}/{}/bgp_ipv6_step2.json".format(CWD, rname) - expected = json.loads(open(ref_file).read()) - test_func = partial( - topotest.router_json_cmp, - router, - "show bgp ipv6 unicast json", - expected, - ) - _, res = topotest.run_and_expect(test_func, None, count=30, wait=1) - assertmsg = "{}: BGP IPv6 Nexthop failure".format(rname) - assert res is None, assertmsg - - -def test_bgp_ping_ok_step2(): - "Check that h1 pings h2 and h3" - tgen = get_topogen() - if tgen.routers_have_failure(): - pytest.skip(tgen.errors) - - check_ping("h1", "192.168.7.1", True, 5, 1) - check_ping("h1", "fd00:700::1", True, 5, 1) - check_ping("h1", "192.168.8.1", True, 5, 1) - check_ping("h1", "fd00:800::1", True, 5, 1) - - if __name__ == "__main__": args = ["-s"] + sys.argv[1:] sys.exit(pytest.main(args)) From 3e7094e2b19459c81aac40fa00b4ea0812c1902e Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Wed, 14 Aug 2024 20:15:13 +0300 Subject: [PATCH 330/347] Revert "bgpd: fix "used" json key on link-local nexthop" This reverts commit 2de4dfc97adfec788e45e148b4204196d612c81c. --- bgpd/bgp_route.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index f6fe87e352..9e40e165fa 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -9659,7 +9659,10 @@ void route_vty_out(struct vty *vty, const struct prefix *p, json_object_string_add(json_nexthop_ll, "scope", "link-local"); - if (!CHECK_FLAG(attr->nh_flags, + if ((IPV6_ADDR_CMP(&attr->mp_nexthop_global, + &attr->mp_nexthop_local) != + 0) && + !CHECK_FLAG(attr->nh_flags, BGP_ATTR_NH_MP_PREFER_GLOBAL)) json_object_boolean_true_add( json_nexthop_ll, "used"); From 2fd44b1bbbca9e3f9554a8bf2530619f646e7f34 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Wed, 14 Aug 2024 20:15:18 +0300 Subject: [PATCH 331/347] Revert "bgpd: fix removing ipv6 global nexhop" This reverts commit ee0378cdbb458f9d3710f1fb557368ace8d72477. --- bgpd/bgp_zebra.c | 27 ++++----------------------- 1 file changed, 4 insertions(+), 23 deletions(-) diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 00013b1e7a..d4a0209ea2 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -385,12 +385,10 @@ static int bgp_interface_address_add(ZAPI_CALLBACK_ARGS) static int bgp_interface_address_delete(ZAPI_CALLBACK_ARGS) { struct listnode *node, *nnode; - struct connected *ifc, *connected; + struct connected *ifc; struct peer *peer; struct bgp *bgp; struct prefix *addr; - struct in6_addr *v6_global = NULL; - struct in6_addr *v6_local = NULL; afi_t afi; safi_t safi; @@ -412,17 +410,7 @@ static int bgp_interface_address_delete(ZAPI_CALLBACK_ARGS) addr = ifc->address; if (bgp && addr->family == AF_INET6 && - !IN6_IS_ADDR_LINKLOCAL(&addr->u.prefix6)) { - /* find another IPv6 global if possible and find the IPv6 link-local */ - frr_each (if_connected, ifc->ifp->connected, connected) { - if (connected->address->family != AF_INET6) - continue; - if (IN6_IS_ADDR_LINKLOCAL(&connected->address->u.prefix6)) - v6_local = &connected->address->u.prefix6; - else - v6_global = &connected->address->u.prefix6; - } - + !IN6_IS_ADDR_LINKLOCAL(&addr->u.prefix)) { /* * When we are using the v6 global as part of the peering * nexthops and we are removing it, then we need to @@ -433,15 +421,8 @@ static int bgp_interface_address_delete(ZAPI_CALLBACK_ARGS) for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { if (IPV6_ADDR_SAME(&peer->nexthop.v6_global, &addr->u.prefix6)) { - if (v6_global) - IPV6_ADDR_COPY(&peer->nexthop.v6_global, - v6_global); - else if (v6_local) - IPV6_ADDR_COPY(&peer->nexthop.v6_global, - v6_local); - else - memset(&peer->nexthop.v6_global, 0, - IPV6_MAX_BYTELEN); + memset(&peer->nexthop.v6_global, 0, + IPV6_MAX_BYTELEN); FOREACH_AFI_SAFI (afi, safi) bgp_announce_route(peer, afi, safi, true); From 72b4ca50d06b18a24eb9855d5dfc8d4973117977 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Wed, 14 Aug 2024 20:15:22 +0300 Subject: [PATCH 332/347] Revert "bgpd: optimize bgp_interface_address_del" This reverts commit fc1dd2e5060b6e470daa203080bdb9473a637407. --- bgpd/bgp_zebra.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index d4a0209ea2..c3b93adc26 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -389,8 +389,6 @@ static int bgp_interface_address_delete(ZAPI_CALLBACK_ARGS) struct peer *peer; struct bgp *bgp; struct prefix *addr; - afi_t afi; - safi_t safi; bgp = bgp_lookup_by_vrf_id(vrf_id); @@ -409,8 +407,7 @@ static int bgp_interface_address_delete(ZAPI_CALLBACK_ARGS) addr = ifc->address; - if (bgp && addr->family == AF_INET6 && - !IN6_IS_ADDR_LINKLOCAL(&addr->u.prefix)) { + if (bgp) { /* * When we are using the v6 global as part of the peering * nexthops and we are removing it, then we need to @@ -419,10 +416,17 @@ static int bgp_interface_address_delete(ZAPI_CALLBACK_ARGS) * we do not want the peering to bounce. */ for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { - if (IPV6_ADDR_SAME(&peer->nexthop.v6_global, - &addr->u.prefix6)) { - memset(&peer->nexthop.v6_global, 0, - IPV6_MAX_BYTELEN); + afi_t afi; + safi_t safi; + + if (addr->family == AF_INET) + continue; + + if (!IN6_IS_ADDR_LINKLOCAL(&addr->u.prefix6) + && memcmp(&peer->nexthop.v6_global, + &addr->u.prefix6, 16) + == 0) { + memset(&peer->nexthop.v6_global, 0, 16); FOREACH_AFI_SAFI (afi, safi) bgp_announce_route(peer, afi, safi, true); From 9e3aa8c1ac2c2fe13fe3c31b62a85b6d96768b6d Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Wed, 14 Aug 2024 20:28:13 +0300 Subject: [PATCH 333/347] Revert "topotests: add bgp_nexthop_mp_ipv4_6 test" This reverts commit 62913cb15d8195c41229c2f6090d7e189e04646e. Signed-off-by: Donatas Abraitis --- .../bgp_nexthop_mp_ipv4_6/__init__.py | 0 .../bgp_nexthop_mp_ipv4_6/h1/zebra.conf | 6 - .../bgp_nexthop_mp_ipv4_6/h2/zebra.conf | 6 - .../bgp_nexthop_mp_ipv4_6/h3/zebra.conf | 6 - .../bgp_nexthop_mp_ipv4_6/r1/bgp_ipv4.json | 70 ------ .../r1/bgp_ipv6_step1.json | 90 ------- .../bgp_nexthop_mp_ipv4_6/r1/bgpd.conf | 23 -- .../bgp_nexthop_mp_ipv4_6/r1/zebra.conf | 16 -- .../bgp_nexthop_mp_ipv4_6/r2/bgp_ipv4.json | 46 ---- .../r2/bgp_ipv6_step1.json | 53 ---- .../bgp_nexthop_mp_ipv4_6/r2/bgpd.conf | 11 - .../bgp_nexthop_mp_ipv4_6/r2/isisd.conf | 24 -- .../bgp_nexthop_mp_ipv4_6/r2/zebra.conf | 12 - .../bgp_nexthop_mp_ipv4_6/r3/bgp_ipv4.json | 46 ---- .../r3/bgp_ipv6_step1.json | 53 ---- .../bgp_nexthop_mp_ipv4_6/r3/bgpd.conf | 11 - .../bgp_nexthop_mp_ipv4_6/r3/isisd.conf | 24 -- .../bgp_nexthop_mp_ipv4_6/r3/zebra.conf | 12 - .../bgp_nexthop_mp_ipv4_6/r4/bgp_ipv4.json | 46 ---- .../r4/bgp_ipv6_step1.json | 49 ---- .../bgp_nexthop_mp_ipv4_6/r4/bgpd.conf | 13 - .../bgp_nexthop_mp_ipv4_6/r4/isisd.conf | 26 -- .../bgp_nexthop_mp_ipv4_6/r4/zebra.conf | 12 - .../bgp_nexthop_mp_ipv4_6/r5/bgp_ipv4.json | 46 ---- .../r5/bgp_ipv6_step1.json | 49 ---- .../bgp_nexthop_mp_ipv4_6/r5/bgpd.conf | 13 - .../bgp_nexthop_mp_ipv4_6/r5/isisd.conf | 26 -- .../bgp_nexthop_mp_ipv4_6/r5/zebra.conf | 12 - .../bgp_nexthop_mp_ipv4_6/r6/bgp_ipv4.json | 46 ---- .../r6/bgp_ipv6_step1.json | 48 ---- .../bgp_nexthop_mp_ipv4_6/r6/bgpd.conf | 17 -- .../bgp_nexthop_mp_ipv4_6/r6/isisd.conf | 31 --- .../bgp_nexthop_mp_ipv4_6/r6/zebra.conf | 16 -- .../bgp_nexthop_mp_ipv4_6/r7/bgp_ipv4.json | 46 ---- .../r7/bgp_ipv6_step1.json | 48 ---- .../bgp_nexthop_mp_ipv4_6/r7/bgpd.conf | 21 -- .../bgp_nexthop_mp_ipv4_6/r7/zebra.conf | 12 - .../bgp_nexthop_mp_ipv4_6/r8/bgp_ipv4.json | 46 ---- .../r8/bgp_ipv6_step1.json | 48 ---- .../bgp_nexthop_mp_ipv4_6/r8/bgpd.conf | 21 -- .../bgp_nexthop_mp_ipv4_6/r8/zebra.conf | 12 - .../bgp_nexthop_mp_ipv4_6/rr1/bgp_ipv4.json | 58 ----- .../rr1/bgp_ipv6_step1.json | 62 ----- .../bgp_nexthop_mp_ipv4_6/rr1/bgpd.conf | 26 -- .../bgp_nexthop_mp_ipv4_6/rr1/isisd.conf | 40 --- .../bgp_nexthop_mp_ipv4_6/rr1/zebra.conf | 21 -- .../bgp_nexthop_mp_ipv4_6/rs1/bgpd.conf | 21 -- .../bgp_nexthop_mp_ipv4_6/rs1/isisd.conf | 36 --- .../bgp_nexthop_mp_ipv4_6/rs1/zebra.conf | 8 - .../test_nexthop_mp_ipv4_6.py | 231 ------------------ 50 files changed, 1716 deletions(-) delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/__init__.py delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/h1/zebra.conf delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/h2/zebra.conf delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/h3/zebra.conf delete mode 100755 tests/topotests/bgp_nexthop_mp_ipv4_6/r1/bgp_ipv4.json delete mode 100755 tests/topotests/bgp_nexthop_mp_ipv4_6/r1/bgp_ipv6_step1.json delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/r1/bgpd.conf delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/r1/zebra.conf delete mode 100755 tests/topotests/bgp_nexthop_mp_ipv4_6/r2/bgp_ipv4.json delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/r2/bgp_ipv6_step1.json delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/r2/bgpd.conf delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/r2/isisd.conf delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/r2/zebra.conf delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/r3/bgp_ipv4.json delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/r3/bgp_ipv6_step1.json delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/r3/bgpd.conf delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/r3/isisd.conf delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/r3/zebra.conf delete mode 100755 tests/topotests/bgp_nexthop_mp_ipv4_6/r4/bgp_ipv4.json delete mode 100755 tests/topotests/bgp_nexthop_mp_ipv4_6/r4/bgp_ipv6_step1.json delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/r4/bgpd.conf delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/r4/isisd.conf delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/r4/zebra.conf delete mode 100755 tests/topotests/bgp_nexthop_mp_ipv4_6/r5/bgp_ipv4.json delete mode 100755 tests/topotests/bgp_nexthop_mp_ipv4_6/r5/bgp_ipv6_step1.json delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/r5/bgpd.conf delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/r5/isisd.conf delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/r5/zebra.conf delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/r6/bgp_ipv4.json delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/r6/bgp_ipv6_step1.json delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/r6/bgpd.conf delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/r6/isisd.conf delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/r6/zebra.conf delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/r7/bgp_ipv4.json delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/r7/bgp_ipv6_step1.json delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/r7/bgpd.conf delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/r7/zebra.conf delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/r8/bgp_ipv4.json delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/r8/bgp_ipv6_step1.json delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/r8/bgpd.conf delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/r8/zebra.conf delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/rr1/bgp_ipv4.json delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/rr1/bgp_ipv6_step1.json delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/rr1/bgpd.conf delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/rr1/isisd.conf delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/rr1/zebra.conf delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/rs1/bgpd.conf delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/rs1/isisd.conf delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/rs1/zebra.conf delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/test_nexthop_mp_ipv4_6.py diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/__init__.py b/tests/topotests/bgp_nexthop_mp_ipv4_6/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/h1/zebra.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/h1/zebra.conf deleted file mode 100644 index 9b19b2cfbd..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/h1/zebra.conf +++ /dev/null @@ -1,6 +0,0 @@ -ipv6 route ::/0 fd00:100::2 -ip route 0.0.0.0/0 192.168.1.2 -interface eth-r1 - ip address 192.168.1.1/24 - ipv6 address fd00:100::1/64 -! diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/h2/zebra.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/h2/zebra.conf deleted file mode 100644 index 2bf4a66680..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/h2/zebra.conf +++ /dev/null @@ -1,6 +0,0 @@ -ipv6 route ::/0 fd00:700::2 -ip route 0.0.0.0/0 192.168.7.2 -interface eth-r7 - ip address 192.168.7.1/24 - ipv6 address fd00:700::1/64 -! diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/h3/zebra.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/h3/zebra.conf deleted file mode 100644 index e8b6ac6e26..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/h3/zebra.conf +++ /dev/null @@ -1,6 +0,0 @@ -ipv6 route ::/0 fd00:800::2 -ip route 0.0.0.0/0 192.168.8.2 -interface eth-r8 - ip address 192.168.8.1/24 - ipv6 address fd00:800::1/64 -! diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r1/bgp_ipv4.json b/tests/topotests/bgp_nexthop_mp_ipv4_6/r1/bgp_ipv4.json deleted file mode 100755 index 12fecee39f..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r1/bgp_ipv4.json +++ /dev/null @@ -1,70 +0,0 @@ -{ - "routes": { - "192.168.1.0/24": [ - { - "valid": true, - "bestpath": true, - "path": "", - "nexthops": [ - { - "ip": "0.0.0.0", - "afi": "ipv4", - "used": true - } - ] - } - ], - "192.168.7.0/24": [ - { - "valid": true, - "multipath": true, - "path": "65000 65700", - "nexthops": [ - { - "ip": "172.16.1.3", - "afi": "ipv4", - "used": true - } - ] - }, - { - "valid": true, - "bestpath": true, - "path": "65000 65700", - "nexthops": [ - { - "ip": "172.16.0.2", - "afi": "ipv4", - "used": true - } - ] - } - ], - "192.168.8.0/24": [ - { - "valid": true, - "multipath": true, - "path": "65000 65800", - "nexthops": [ - { - "ip": "172.16.1.3", - "afi": "ipv4", - "used": true - } - ] - }, - { - "valid": true, - "bestpath": true, - "path": "65000 65800", - "nexthops": [ - { - "ip": "172.16.0.2", - "afi": "ipv4", - "used": true - } - ] - } - ] - } -} diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r1/bgp_ipv6_step1.json b/tests/topotests/bgp_nexthop_mp_ipv4_6/r1/bgp_ipv6_step1.json deleted file mode 100755 index f7c5c7c3b5..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r1/bgp_ipv6_step1.json +++ /dev/null @@ -1,90 +0,0 @@ -{ - "routes": { - "fd00:100::/64": [ - { - "valid": true, - "bestpath": true, - "path": "", - "nexthops": [ - { - "ip": "::", - "afi": "ipv6", - "used": true - } - ] - } - ], - "fd00:700::/64": [ - { - "valid": true, - "multipath": true, - "path": "65000 65700", - "nexthops": [ - { - "ip": "fd00:0:2::3", - "afi": "ipv6", - "scope": "global" - }, - { - "afi": "ipv6", - "scope": "link-local", - "used": true - } - ] - }, - { - "valid": true, - "bestpath": true, - "path": "65000 65700", - "nexthops": [ - { - "ip": "fd00:0:1::2", - "afi": "ipv6", - "scope": "global" - }, - { - "afi": "ipv6", - "scope": "link-local", - "used": true - } - ] - } - ], - "fd00:800::/64": [ - { - "valid": true, - "multipath": true, - "path": "65000 65800", - "nexthops": [ - { - "ip": "fd00:0:2::3", - "afi": "ipv6", - "scope": "global" - }, - { - "afi": "ipv6", - "scope": "link-local", - "used": true - } - ] - }, - { - "valid": true, - "bestpath": true, - "path": "65000 65800", - "nexthops": [ - { - "ip": "fd00:0:1::2", - "afi": "ipv6", - "scope": "global" - }, - { - "afi": "ipv6", - "scope": "link-local", - "used": true - } - ] - } - ] - } -} diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r1/bgpd.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/r1/bgpd.conf deleted file mode 100644 index 23b986d130..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r1/bgpd.conf +++ /dev/null @@ -1,23 +0,0 @@ -router bgp 65100 - no bgp ebgp-requires-policy - neighbor 172.16.0.2 remote-as external - neighbor 172.16.1.3 remote-as external - ! neighbor 172.16.0.2 capability extended-nexthop - ! - address-family ipv4 unicast - redistribute connected route-map RMAP4 - ! - address-family ipv6 unicast - redistribute connected route-map RMAP6 - neighbor 172.16.0.2 activate - neighbor 172.16.1.3 activate - ! - -ip prefix-list RANGE4 seq 10 permit 192.168.0.0/16 le 24 -ipv6 prefix-list RANGE6 seq 10 permit fd00:100::0/64 - -route-map RMAP4 permit 10 - match ip address prefix-list RANGE4 -! -route-map RMAP6 permit 10 - match ipv6 address prefix-list RANGE6 diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r1/zebra.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/r1/zebra.conf deleted file mode 100644 index 79cbafb5b8..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r1/zebra.conf +++ /dev/null @@ -1,16 +0,0 @@ -! -interface eth-h1 - ip address 192.168.1.2/24 - ipv6 address fd00:100::2/64 -! -interface eth-r2 - ip address 172.16.0.1/24 - ipv6 address fd00:0:1::1/64 -! -interface eth-r3 - ip address 172.16.1.1/24 - ipv6 address fd00:0:2::1/64 -! -interface lo - ip address 192.0.2.1/32 - ipv6 address 2001:db8::1/128 diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r2/bgp_ipv4.json b/tests/topotests/bgp_nexthop_mp_ipv4_6/r2/bgp_ipv4.json deleted file mode 100755 index 64dadf680c..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r2/bgp_ipv4.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - "routes": { - "192.168.1.0/24": [ - { - "valid": true, - "bestpath": true, - "path": "65100", - "nexthops": [ - { - "ip": "172.16.0.1", - "afi": "ipv4", - "used": true - } - ] - } - ], - "192.168.7.0/24": [ - { - "valid": true, - "bestpath": true, - "path": "65700", - "nexthops": [ - { - "ip": "172.17.0.7", - "afi": "ipv4", - "used": true - } - ] - } - ], - "192.168.8.0/24": [ - { - "valid": true, - "bestpath": true, - "path": "65800", - "nexthops": [ - { - "ip": "172.17.0.8", - "afi": "ipv4", - "used": true - } - ] - } - ] - } -} diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r2/bgp_ipv6_step1.json b/tests/topotests/bgp_nexthop_mp_ipv4_6/r2/bgp_ipv6_step1.json deleted file mode 100644 index 4f86a1a648..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r2/bgp_ipv6_step1.json +++ /dev/null @@ -1,53 +0,0 @@ -{ - "routes": { - "fd00:100::/64": [ - { - "valid": true, - "bestpath": true, - "path": "65100", - "nexthops": [ - { - "ip": "fd00:0:1::1", - "afi": "ipv6", - "scope": "global" - }, - { - "afi": "ipv6", - "scope": "link-local", - "used": true - } - ] - } - ], - "fd00:700::/64": [ - { - "valid": true, - "bestpath": true, - "path": "65700", - "nexthops": [ - { - "ip": "fd00:0:9::7", - "scope": "global", - "afi": "ipv6", - "used": true - } - ] - } - ], - "fd00:800::/64": [ - { - "valid": true, - "bestpath": true, - "path": "65800", - "nexthops": [ - { - "ip": "fd00:0:9::8", - "scope": "global", - "afi": "ipv6", - "used": true - } - ] - } - ] - } -} diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r2/bgpd.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/r2/bgpd.conf deleted file mode 100644 index badb11cbeb..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r2/bgpd.conf +++ /dev/null @@ -1,11 +0,0 @@ -router bgp 65000 - no bgp ebgp-requires-policy - neighbor 172.16.0.1 remote-as external - ! neighbor 172.16.0.1 capability extended-nexthop - neighbor 192.0.2.101 remote-as internal - neighbor 192.0.2.101 update-source 192.0.2.2 - ! - address-family ipv6 unicast - neighbor 172.16.0.1 activate - neighbor 192.0.2.101 activate - ! diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r2/isisd.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/r2/isisd.conf deleted file mode 100644 index 16963798f8..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r2/isisd.conf +++ /dev/null @@ -1,24 +0,0 @@ -! -interface lo - ip router isis 1 - ipv6 router isis 1 - isis passive -! -interface eth-rr1 - ip router isis 1 - ipv6 router isis 1 - isis hello-interval 1 - isis hello-multiplier 3 - isis network point-to-point -! -interface eth-r1 - ip router isis 1 - ipv6 router isis 1 - isis passive -! -router isis 1 - net 49.0000.0000.0000.0002.00 - is-type level-1 - lsp-gen-interval 1 - topology ipv6-unicast -! diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r2/zebra.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/r2/zebra.conf deleted file mode 100644 index 8997115d87..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r2/zebra.conf +++ /dev/null @@ -1,12 +0,0 @@ -! -interface eth-r1 - ip address 172.16.0.2/24 - ipv6 address fd00:0:1::2/64 -! -interface eth-rr1 - ip address 10.0.0.2/24 - ipv6 address fd00:0:3::2/64 -! -interface lo - ip address 192.0.2.2/32 - ipv6 address 2001:db8::2/128 diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r3/bgp_ipv4.json b/tests/topotests/bgp_nexthop_mp_ipv4_6/r3/bgp_ipv4.json deleted file mode 100644 index 0f18a43bf5..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r3/bgp_ipv4.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - "routes": { - "192.168.1.0/24": [ - { - "valid": true, - "bestpath": true, - "path": "65100", - "nexthops": [ - { - "ip": "172.16.1.1", - "afi": "ipv4", - "used": true - } - ] - } - ], - "192.168.7.0/24": [ - { - "valid": true, - "bestpath": true, - "path": "65700", - "nexthops": [ - { - "ip": "172.17.0.7", - "afi": "ipv4", - "used": true - } - ] - } - ], - "192.168.8.0/24": [ - { - "valid": true, - "bestpath": true, - "path": "65800", - "nexthops": [ - { - "ip": "172.17.0.8", - "afi": "ipv4", - "used": true - } - ] - } - ] - } -} diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r3/bgp_ipv6_step1.json b/tests/topotests/bgp_nexthop_mp_ipv4_6/r3/bgp_ipv6_step1.json deleted file mode 100644 index f44121c30e..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r3/bgp_ipv6_step1.json +++ /dev/null @@ -1,53 +0,0 @@ -{ - "routes": { - "fd00:100::/64": [ - { - "valid": true, - "bestpath": true, - "path": "65100", - "nexthops": [ - { - "ip": "fd00:0:2::1", - "afi": "ipv6", - "scope": "global" - }, - { - "afi": "ipv6", - "scope": "link-local", - "used": true - } - ] - } - ], - "fd00:700::/64": [ - { - "valid": true, - "bestpath": true, - "path": "65700", - "nexthops": [ - { - "ip": "fd00:0:9::7", - "scope": "global", - "afi": "ipv6", - "used": true - } - ] - } - ], - "fd00:800::/64": [ - { - "valid": true, - "bestpath": true, - "path": "65800", - "nexthops": [ - { - "ip": "fd00:0:9::8", - "scope": "global", - "afi": "ipv6", - "used": true - } - ] - } - ] - } -} diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r3/bgpd.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/r3/bgpd.conf deleted file mode 100644 index 4dec311f51..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r3/bgpd.conf +++ /dev/null @@ -1,11 +0,0 @@ -router bgp 65000 - no bgp ebgp-requires-policy - neighbor 172.16.1.1 remote-as external - ! neighbor 172.16.1.1 capability extended-nexthop - neighbor 192.0.2.101 remote-as internal - neighbor 192.0.2.101 update-source 192.0.2.3 - ! - address-family ipv6 unicast - neighbor 172.16.1.1 activate - neighbor 192.0.2.101 activate - ! diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r3/isisd.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/r3/isisd.conf deleted file mode 100644 index fe3e307b42..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r3/isisd.conf +++ /dev/null @@ -1,24 +0,0 @@ -! -interface lo - ip router isis 1 - ipv6 router isis 1 - isis passive -! -interface eth-rr1 - ip router isis 1 - ipv6 router isis 1 - isis hello-interval 1 - isis hello-multiplier 3 - isis network point-to-point -! -interface eth-r1 - ip router isis 1 - ipv6 router isis 1 - isis passive -! -router isis 1 - net 49.0000.0000.0000.0003.00 - is-type level-1 - lsp-gen-interval 1 - topology ipv6-unicast -! diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r3/zebra.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/r3/zebra.conf deleted file mode 100644 index 8074bbdcde..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r3/zebra.conf +++ /dev/null @@ -1,12 +0,0 @@ -! -interface eth-r1 - ip address 172.16.1.3/24 - ipv6 address fd00:0:2::3/64 -! -interface eth-rr1 - ip address 10.0.1.3/24 - ipv6 address fd00:0:4::3/64 -! -interface lo - ip address 192.0.2.3/32 - ipv6 address 2001:db8::3/128 diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r4/bgp_ipv4.json b/tests/topotests/bgp_nexthop_mp_ipv4_6/r4/bgp_ipv4.json deleted file mode 100755 index 64dadf680c..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r4/bgp_ipv4.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - "routes": { - "192.168.1.0/24": [ - { - "valid": true, - "bestpath": true, - "path": "65100", - "nexthops": [ - { - "ip": "172.16.0.1", - "afi": "ipv4", - "used": true - } - ] - } - ], - "192.168.7.0/24": [ - { - "valid": true, - "bestpath": true, - "path": "65700", - "nexthops": [ - { - "ip": "172.17.0.7", - "afi": "ipv4", - "used": true - } - ] - } - ], - "192.168.8.0/24": [ - { - "valid": true, - "bestpath": true, - "path": "65800", - "nexthops": [ - { - "ip": "172.17.0.8", - "afi": "ipv4", - "used": true - } - ] - } - ] - } -} diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r4/bgp_ipv6_step1.json b/tests/topotests/bgp_nexthop_mp_ipv4_6/r4/bgp_ipv6_step1.json deleted file mode 100755 index 756a78e3b1..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r4/bgp_ipv6_step1.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "routes": { - "fd00:100::/64": [ - { - "valid": true, - "bestpath": true, - "path": "65100", - "nexthops": [ - { - "ip": "fd00:0:1::1", - "afi": "ipv6", - "scope": "global", - "used": true - } - ] - } - ], - "fd00:700::/64": [ - { - "valid": true, - "bestpath": true, - "path": "65700", - "nexthops": [ - { - "ip": "fd00:0:9::7", - "scope": "global", - "afi": "ipv6", - "used": true - } - ] - } - ], - "fd00:800::/64": [ - { - "valid": true, - "bestpath": true, - "path": "65800", - "nexthops": [ - { - "ip": "fd00:0:9::8", - "scope": "global", - "afi": "ipv6", - "used": true - } - ] - } - ] - } -} diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r4/bgpd.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/r4/bgpd.conf deleted file mode 100644 index 2dbc4acddc..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r4/bgpd.conf +++ /dev/null @@ -1,13 +0,0 @@ -router bgp 65000 - neighbor 192.0.2.5 remote-as internal - neighbor 192.0.2.6 remote-as internal - neighbor 192.0.2.101 remote-as internal - neighbor 192.0.2.5 update-source 192.0.2.4 - neighbor 192.0.2.6 update-source 192.0.2.4 - neighbor 192.0.2.101 update-source 192.0.2.4 - ! - address-family ipv6 unicast - neighbor 192.0.2.5 activate - neighbor 192.0.2.6 activate - neighbor 192.0.2.101 activate - ! diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r4/isisd.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/r4/isisd.conf deleted file mode 100644 index 21eb80f58b..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r4/isisd.conf +++ /dev/null @@ -1,26 +0,0 @@ -! -interface lo - ip router isis 1 - ipv6 router isis 1 - isis passive -! -interface eth-rr1 - ip router isis 1 - ipv6 router isis 1 - isis hello-interval 1 - isis hello-multiplier 3 - isis network point-to-point -! -interface eth-r6 - ip router isis 1 - ipv6 router isis 1 - isis hello-interval 1 - isis hello-multiplier 3 - isis network point-to-point -! -router isis 1 - net 49.0000.0000.0000.0004.00 - is-type level-1 - lsp-gen-interval 1 - topology ipv6-unicast -! diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r4/zebra.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/r4/zebra.conf deleted file mode 100644 index c598b345e5..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r4/zebra.conf +++ /dev/null @@ -1,12 +0,0 @@ -! -interface eth-r6 - ip address 10.0.4.4/24 - ipv6 address fd00:0:7::4/64 -! -interface eth-rr1 - ip address 10.0.2.4/24 - ipv6 address fd00:0:5::4/64 -! -interface lo - ip address 192.0.2.4/32 - ipv6 address 2001:db8::4/128 diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r5/bgp_ipv4.json b/tests/topotests/bgp_nexthop_mp_ipv4_6/r5/bgp_ipv4.json deleted file mode 100755 index 64dadf680c..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r5/bgp_ipv4.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - "routes": { - "192.168.1.0/24": [ - { - "valid": true, - "bestpath": true, - "path": "65100", - "nexthops": [ - { - "ip": "172.16.0.1", - "afi": "ipv4", - "used": true - } - ] - } - ], - "192.168.7.0/24": [ - { - "valid": true, - "bestpath": true, - "path": "65700", - "nexthops": [ - { - "ip": "172.17.0.7", - "afi": "ipv4", - "used": true - } - ] - } - ], - "192.168.8.0/24": [ - { - "valid": true, - "bestpath": true, - "path": "65800", - "nexthops": [ - { - "ip": "172.17.0.8", - "afi": "ipv4", - "used": true - } - ] - } - ] - } -} diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r5/bgp_ipv6_step1.json b/tests/topotests/bgp_nexthop_mp_ipv4_6/r5/bgp_ipv6_step1.json deleted file mode 100755 index 756a78e3b1..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r5/bgp_ipv6_step1.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "routes": { - "fd00:100::/64": [ - { - "valid": true, - "bestpath": true, - "path": "65100", - "nexthops": [ - { - "ip": "fd00:0:1::1", - "afi": "ipv6", - "scope": "global", - "used": true - } - ] - } - ], - "fd00:700::/64": [ - { - "valid": true, - "bestpath": true, - "path": "65700", - "nexthops": [ - { - "ip": "fd00:0:9::7", - "scope": "global", - "afi": "ipv6", - "used": true - } - ] - } - ], - "fd00:800::/64": [ - { - "valid": true, - "bestpath": true, - "path": "65800", - "nexthops": [ - { - "ip": "fd00:0:9::8", - "scope": "global", - "afi": "ipv6", - "used": true - } - ] - } - ] - } -} diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r5/bgpd.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/r5/bgpd.conf deleted file mode 100644 index 101edbd71b..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r5/bgpd.conf +++ /dev/null @@ -1,13 +0,0 @@ -router bgp 65000 - neighbor 192.0.2.4 remote-as internal - neighbor 192.0.2.6 remote-as internal - neighbor 192.0.2.101 remote-as internal - neighbor 192.0.2.4 update-source 192.0.2.5 - neighbor 192.0.2.6 update-source 192.0.2.5 - neighbor 192.0.2.101 update-source 192.0.2.5 - ! - address-family ipv6 unicast - neighbor 192.0.2.4 activate - neighbor 192.0.2.6 activate - neighbor 192.0.2.101 activate - ! diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r5/isisd.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/r5/isisd.conf deleted file mode 100644 index f998e805b5..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r5/isisd.conf +++ /dev/null @@ -1,26 +0,0 @@ -! -interface lo - ip router isis 1 - ipv6 router isis 1 - isis passive -! -interface eth-rr1 - ip router isis 1 - ipv6 router isis 1 - isis hello-interval 1 - isis hello-multiplier 3 - isis network point-to-point -! -interface eth-r6 - ip router isis 1 - ipv6 router isis 1 - isis hello-interval 1 - isis hello-multiplier 3 - isis network point-to-point -! -router isis 1 - net 49.0000.0000.0000.0005.00 - is-type level-1 - lsp-gen-interval 1 - topology ipv6-unicast -! diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r5/zebra.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/r5/zebra.conf deleted file mode 100644 index 7b43db0958..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r5/zebra.conf +++ /dev/null @@ -1,12 +0,0 @@ -! -interface eth-r6 - ip address 10.0.5.5/24 - ipv6 address fd00:0:8::5/64 -! -interface eth-rr1 - ip address 10.0.3.5/24 - ipv6 address fd00:0:6::5/64 -! -interface lo - ip address 192.0.2.5/32 - ipv6 address 2001:db8::5/128 diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r6/bgp_ipv4.json b/tests/topotests/bgp_nexthop_mp_ipv4_6/r6/bgp_ipv4.json deleted file mode 100644 index 64dadf680c..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r6/bgp_ipv4.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - "routes": { - "192.168.1.0/24": [ - { - "valid": true, - "bestpath": true, - "path": "65100", - "nexthops": [ - { - "ip": "172.16.0.1", - "afi": "ipv4", - "used": true - } - ] - } - ], - "192.168.7.0/24": [ - { - "valid": true, - "bestpath": true, - "path": "65700", - "nexthops": [ - { - "ip": "172.17.0.7", - "afi": "ipv4", - "used": true - } - ] - } - ], - "192.168.8.0/24": [ - { - "valid": true, - "bestpath": true, - "path": "65800", - "nexthops": [ - { - "ip": "172.17.0.8", - "afi": "ipv4", - "used": true - } - ] - } - ] - } -} diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r6/bgp_ipv6_step1.json b/tests/topotests/bgp_nexthop_mp_ipv4_6/r6/bgp_ipv6_step1.json deleted file mode 100644 index 1a01ead2cd..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r6/bgp_ipv6_step1.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "routes": { - "fd00:100::/64": [ - { - "valid": true, - "bestpath": true, - "nexthops": [ - { - "ip": "fd00:0:1::1", - "afi": "ipv6", - "scope": "global", - "used": true - } - ] - } - ], - "fd00:700::/64": [ - { - "valid": true, - "bestpath": true, - "path": "65700", - "nexthops": [ - { - "ip": "fd00:0:9::7", - "afi": "ipv6", - "scope": "global", - "used": true - } - ] - } - ], - "fd00:800::/64": [ - { - "valid": true, - "bestpath": true, - "path": "65800", - "nexthops": [ - { - "ip": "fd00:0:9::8", - "afi": "ipv6", - "scope": "global", - "used": true - } - ] - } - ] - } -} diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r6/bgpd.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/r6/bgpd.conf deleted file mode 100644 index e036a779ae..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r6/bgpd.conf +++ /dev/null @@ -1,17 +0,0 @@ -router bgp 65000 - no bgp ebgp-requires-policy - no bgp enforce-first-as - neighbor 192.0.2.4 remote-as internal - neighbor 192.0.2.5 remote-as internal - neighbor 192.0.2.101 remote-as internal - neighbor 172.17.0.201 remote-as external - neighbor 192.0.2.4 update-source 192.0.2.6 - neighbor 192.0.2.5 update-source 192.0.2.6 - neighbor 192.0.2.101 update-source 192.0.2.6 - ! - address-family ipv6 unicast - neighbor 192.0.2.4 activate - neighbor 192.0.2.5 activate - neighbor 192.0.2.101 activate - neighbor 172.17.0.201 activate - ! diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r6/isisd.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/r6/isisd.conf deleted file mode 100644 index b575290e9b..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r6/isisd.conf +++ /dev/null @@ -1,31 +0,0 @@ -! -interface lo - ip router isis 1 - ipv6 router isis 1 - isis passive -! -interface eth-r4 - ip router isis 1 - ipv6 router isis 1 - isis hello-interval 1 - isis hello-multiplier 3 - isis network point-to-point -! -interface eth-r5 - ip router isis 1 - ipv6 router isis 1 - isis hello-interval 1 - isis hello-multiplier 3 - isis network point-to-point -! -interface eth-sw1 - ip router isis 1 - ipv6 router isis 1 - isis passive -! -router isis 1 - net 49.0000.0000.0000.0006.00 - is-type level-1 - lsp-gen-interval 1 - topology ipv6-unicast -! diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r6/zebra.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/r6/zebra.conf deleted file mode 100644 index fce74c146c..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r6/zebra.conf +++ /dev/null @@ -1,16 +0,0 @@ -! -interface eth-r4 - ip address 10.0.4.6/24 - ipv6 address fd00:0:7::6/64 -! -interface eth-r5 - ip address 10.0.5.6/24 - ipv6 address fd00:0:8::6/64 -! -interface eth-sw1 - ip address 172.17.0.6/24 - ipv6 address fd00:0:9::6/64 -! -interface lo - ip address 192.0.2.6/32 - ipv6 address 2001:db8::6/128 diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r7/bgp_ipv4.json b/tests/topotests/bgp_nexthop_mp_ipv4_6/r7/bgp_ipv4.json deleted file mode 100644 index 72b0f03c51..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r7/bgp_ipv4.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - "routes": { - "192.168.1.0/24": [ - { - "valid": true, - "bestpath": true, - "path": "65000 65100", - "nexthops": [ - { - "ip": "172.17.0.6", - "afi": "ipv4", - "used": true - } - ] - } - ], - "192.168.7.0/24": [ - { - "valid": true, - "bestpath": true, - "path": "", - "nexthops": [ - { - "ip": "0.0.0.0", - "afi": "ipv4", - "used": true - } - ] - } - ], - "192.168.8.0/24": [ - { - "valid": true, - "bestpath": true, - "path": "65800", - "nexthops": [ - { - "ip": "172.17.0.8", - "afi": "ipv4", - "used": true - } - ] - } - ] - } -} diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r7/bgp_ipv6_step1.json b/tests/topotests/bgp_nexthop_mp_ipv4_6/r7/bgp_ipv6_step1.json deleted file mode 100644 index 8fe5f7c1de..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r7/bgp_ipv6_step1.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "routes": { - "fd00:100::/64": [ - { - "valid": true, - "bestpath": true, - "path": "65000 65100", - "nexthops": [ - { - "ip": "fd00:0:9::6", - "afi": "ipv6", - "scope": "global", - "used": true - } - ] - } - ], - "fd00:700::/64": [ - { - "valid": true, - "bestpath": true, - "path": "", - "nexthops": [ - { - "ip": "::", - "afi": "ipv6", - "used": true - } - ] - } - ], - "fd00:800::/64": [ - { - "valid": true, - "bestpath": true, - "path": "65800", - "nexthops": [ - { - "ip": "fd00:0:9::8", - "afi": "ipv6", - "scope": "global", - "used": true - } - ] - } - ] - } -} diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r7/bgpd.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/r7/bgpd.conf deleted file mode 100644 index a707b23af0..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r7/bgpd.conf +++ /dev/null @@ -1,21 +0,0 @@ -router bgp 65700 - no bgp ebgp-requires-policy - no bgp enforce-first-as - neighbor 172.17.0.201 remote-as external - ! - address-family ipv4 unicast - redistribute connected route-map RMAP4 - ! - address-family ipv6 unicast - redistribute connected route-map RMAP6 - neighbor 172.17.0.201 activate - ! - -ip prefix-list RANGE4 seq 10 permit 192.168.0.0/16 le 24 -ipv6 prefix-list RANGE6 seq 10 permit fd00:700::0/64 - -route-map RMAP4 permit 10 - match ip address prefix-list RANGE4 -! -route-map RMAP6 permit 10 - match ipv6 address prefix-list RANGE6 diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r7/zebra.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/r7/zebra.conf deleted file mode 100644 index 75448297eb..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r7/zebra.conf +++ /dev/null @@ -1,12 +0,0 @@ -! -interface eth-h2 - ip address 192.168.7.2/24 - ipv6 address fd00:700::2/64 -! -interface eth-sw1 - ip address 172.17.0.7/24 - ipv6 address fd00:0:9::7/64 -! -interface lo - ip address 192.0.2.7/32 - ipv6 address 2001:db8::7/128 diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r8/bgp_ipv4.json b/tests/topotests/bgp_nexthop_mp_ipv4_6/r8/bgp_ipv4.json deleted file mode 100644 index 596ee4b40b..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r8/bgp_ipv4.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - "routes": { - "192.168.1.0/24": [ - { - "valid": true, - "bestpath": true, - "path": "65000 65100", - "nexthops": [ - { - "ip": "172.17.0.6", - "afi": "ipv4", - "used": true - } - ] - } - ], - "192.168.7.0/24": [ - { - "valid": true, - "bestpath": true, - "path": "65700", - "nexthops": [ - { - "ip": "172.17.0.7", - "afi": "ipv4", - "used": true - } - ] - } - ], - "192.168.8.0/24": [ - { - "valid": true, - "bestpath": true, - "path": "", - "nexthops": [ - { - "ip": "0.0.0.0", - "afi": "ipv4", - "used": true - } - ] - } - ] - } -} diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r8/bgp_ipv6_step1.json b/tests/topotests/bgp_nexthop_mp_ipv4_6/r8/bgp_ipv6_step1.json deleted file mode 100644 index 20f4940328..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r8/bgp_ipv6_step1.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "routes": { - "fd00:100::/64": [ - { - "valid": true, - "bestpath": true, - "path": "65000 65100", - "nexthops": [ - { - "ip": "fd00:0:9::6", - "afi": "ipv6", - "scope": "global", - "used": true - } - ] - } - ], - "fd00:700::/64": [ - { - "valid": true, - "bestpath": true, - "path": "65700", - "nexthops": [ - { - "ip": "fd00:0:9::7", - "afi": "ipv6", - "scope": "global", - "used": true - } - ] - } - ], - "fd00:800::/64": [ - { - "valid": true, - "bestpath": true, - "path": "", - "nexthops": [ - { - "ip": "::", - "afi": "ipv6", - "used": true - } - ] - } - ] - } -} diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r8/bgpd.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/r8/bgpd.conf deleted file mode 100644 index d57712dcdd..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r8/bgpd.conf +++ /dev/null @@ -1,21 +0,0 @@ -router bgp 65800 - no bgp ebgp-requires-policy - no bgp enforce-first-as - neighbor 172.17.0.201 remote-as external - ! - address-family ipv4 unicast - redistribute connected route-map RMAP4 - ! - address-family ipv6 unicast - redistribute connected route-map RMAP6 - neighbor 172.17.0.201 activate - ! - -ip prefix-list RANGE4 seq 10 permit 192.168.0.0/16 le 24 -ipv6 prefix-list RANGE6 seq 10 permit fd00:800::0/64 - -route-map RMAP4 permit 10 - match ip address prefix-list RANGE4 -! -route-map RMAP6 permit 10 - match ipv6 address prefix-list RANGE6 diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r8/zebra.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/r8/zebra.conf deleted file mode 100644 index 7e2479b751..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r8/zebra.conf +++ /dev/null @@ -1,12 +0,0 @@ -! -interface eth-h3 - ip address 192.168.8.2/24 - ipv6 address fd00:800::2/64 -! -interface eth-sw1 - ip address 172.17.0.8/24 - ipv6 address fd00:0:9::8/64 -! -interface lo - ip address 192.0.2.8/32 - ipv6 address 2001:db8::8/128 diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/rr1/bgp_ipv4.json b/tests/topotests/bgp_nexthop_mp_ipv4_6/rr1/bgp_ipv4.json deleted file mode 100644 index ac67fe069c..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/rr1/bgp_ipv4.json +++ /dev/null @@ -1,58 +0,0 @@ -{ - "routes": { - "192.168.1.0/24": [ - { - "valid": true, - "bestpath": true, - "path": "65100", - "nexthops": [ - { - "ip": "172.16.0.1", - "afi": "ipv4", - "used": true - } - ] - }, - { - "valid": true, - "multipath": true, - "path": "65100", - "nexthops": [ - { - "ip": "172.16.1.1", - "afi": "ipv4", - "used": true - } - ] - } - ], - "192.168.7.0/24": [ - { - "valid": true, - "bestpath": true, - "path": "65700", - "nexthops": [ - { - "ip": "172.17.0.7", - "afi": "ipv4", - "used": true - } - ] - } - ], - "192.168.8.0/24": [ - { - "valid": true, - "bestpath": true, - "path": "65800", - "nexthops": [ - { - "ip": "172.17.0.8", - "afi": "ipv4", - "used": true - } - ] - } - ] - } -} diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/rr1/bgp_ipv6_step1.json b/tests/topotests/bgp_nexthop_mp_ipv4_6/rr1/bgp_ipv6_step1.json deleted file mode 100644 index 4e359fd97f..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/rr1/bgp_ipv6_step1.json +++ /dev/null @@ -1,62 +0,0 @@ -{ - "routes": { - "fd00:100::/64": [ - { - "valid": true, - "bestpath": true, - "path": "65100", - "nexthops": [ - { - "ip": "fd00:0:1::1", - "afi": "ipv6", - "scope": "global", - "used": true - } - ] - }, - { - "valid": true, - "multipath": true, - "path": "65100", - "nexthops": [ - { - "ip": "fd00:0:2::1", - "afi": "ipv6", - "scope": "global", - "used": true - } - ] - } - ], - "fd00:700::/64": [ - { - "valid": true, - "bestpath": true, - "path": "65700", - "nexthops": [ - { - "ip": "fd00:0:9::7", - "afi": "ipv6", - "scope": "global", - "used": true - } - ] - } - ], - "fd00:800::/64": [ - { - "valid": true, - "bestpath": true, - "path": "65800", - "nexthops": [ - { - "ip": "fd00:0:9::8", - "scope": "global", - "afi": "ipv6", - "used": true - } - ] - } - ] - } -} diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/rr1/bgpd.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/rr1/bgpd.conf deleted file mode 100644 index 9bbac8b68e..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/rr1/bgpd.conf +++ /dev/null @@ -1,26 +0,0 @@ -router bgp 65000 - neighbor 192.0.2.2 remote-as internal - neighbor 192.0.2.3 remote-as internal - neighbor 192.0.2.4 remote-as internal - neighbor 192.0.2.5 remote-as internal - neighbor 192.0.2.6 remote-as internal - neighbor 192.0.2.2 update-source 192.0.2.101 - neighbor 192.0.2.3 update-source 192.0.2.101 - neighbor 192.0.2.4 update-source 192.0.2.101 - neighbor 192.0.2.5 update-source 192.0.2.101 - neighbor 192.0.2.6 update-source 192.0.2.101 - ! - address-family ipv4 unicast - neighbor 192.0.2.2 route-reflector-client - neighbor 192.0.2.3 route-reflector-client - - ! - address-family ipv6 unicast - neighbor 192.0.2.2 activate - neighbor 192.0.2.3 activate - neighbor 192.0.2.4 activate - neighbor 192.0.2.5 activate - neighbor 192.0.2.6 activate - neighbor 192.0.2.2 route-reflector-client - neighbor 192.0.2.3 route-reflector-client - ! diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/rr1/isisd.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/rr1/isisd.conf deleted file mode 100644 index fe5bcfb9f1..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/rr1/isisd.conf +++ /dev/null @@ -1,40 +0,0 @@ -! -interface lo - ip router isis 1 - ipv6 router isis 1 - isis passive -! -interface eth-r2 - ip router isis 1 - ipv6 router isis 1 - isis hello-interval 1 - isis hello-multiplier 3 - isis network point-to-point -! -interface eth-r3 - ip router isis 1 - ipv6 router isis 1 - isis hello-interval 1 - isis hello-multiplier 3 - isis network point-to-point -! -interface eth-r4 - ip router isis 1 - ipv6 router isis 1 - isis hello-interval 1 - isis hello-multiplier 3 - isis network point-to-point -! -interface eth-r5 - ip router isis 1 - ipv6 router isis 1 - isis hello-interval 1 - isis hello-multiplier 3 - isis network point-to-point -! -router isis 1 - net 49.0000.0000.0000.0101.00 - is-type level-1 - lsp-gen-interval 1 - topology ipv6-unicast -! diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/rr1/zebra.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/rr1/zebra.conf deleted file mode 100644 index 7f5c8d1c61..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/rr1/zebra.conf +++ /dev/null @@ -1,21 +0,0 @@ -! -interface eth-r2 - ip address 10.0.0.101/24 - ipv6 address fd00:0:3::101/64 -! -interface eth-r3 - ip address 10.0.1.101/24 - ipv6 address fd00:0:4::101/64 -! -interface eth-r4 - ip address 10.0.2.101/24 - ipv6 address fd00:0:5::101/64 -! -interface eth-r5 - ip address 10.0.3.101/24 - ipv6 address fd00:0:6::101/64 -! -interface lo - ip address 192.0.2.101/32 - ipv6 address 2001:db8::101/128 - diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/rs1/bgpd.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/rs1/bgpd.conf deleted file mode 100644 index 596cc3e25c..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/rs1/bgpd.conf +++ /dev/null @@ -1,21 +0,0 @@ -router bgp 65200 view RS - bgp router-id 192.0.2.201 - no bgp ebgp-requires-policy - neighbor 172.17.0.6 remote-as external - neighbor 172.17.0.7 remote-as external - neighbor 172.17.0.8 remote-as external - ! - address-family ipv4 unicast - neighbor 172.17.0.6 route-server-client - neighbor 172.17.0.7 route-server-client - neighbor 172.17.0.8 route-server-client - - ! - address-family ipv6 unicast - neighbor 172.17.0.6 activate - neighbor 172.17.0.7 activate - neighbor 172.17.0.8 activate - neighbor 172.17.0.6 route-server-client - neighbor 172.17.0.7 route-server-client - neighbor 172.17.0.8 route-server-client - ! diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/rs1/isisd.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/rs1/isisd.conf deleted file mode 100644 index 892b4e7b74..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/rs1/isisd.conf +++ /dev/null @@ -1,36 +0,0 @@ -! -interface lo - ip router isis 1 - ipv6 router isis 1 - isis passive -! -interface eth-r2 - ip router isis 1 - ipv6 router isis 1 - isis hello-interval 1 - isis hello-multiplier 3 -! -interface eth-r3 - ip router isis 1 - ipv6 router isis 1 - isis hello-interval 1 - isis hello-multiplier 3 -! -interface eth-r4 - ip router isis 1 - ipv6 router isis 1 - isis hello-interval 1 - isis hello-multiplier 3 -! -interface eth-r5 - ip router isis 1 - ipv6 router isis 1 - isis hello-interval 1 - isis hello-multiplier 3 -! -router isis 1 - net 49.0000.0000.0000.0101.00 - is-type level-1 - lsp-gen-interval 1 - topology ipv6-unicast -! diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/rs1/zebra.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/rs1/zebra.conf deleted file mode 100644 index 75ee08363a..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/rs1/zebra.conf +++ /dev/null @@ -1,8 +0,0 @@ -interface eth-sw1 - ip address 172.17.0.201/24 - ipv6 address fd00:0:9::201/64 -! -interface lo - ip address 192.0.2.201/32 - ipv6 address 2001:db8::201/128 - diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/test_nexthop_mp_ipv4_6.py b/tests/topotests/bgp_nexthop_mp_ipv4_6/test_nexthop_mp_ipv4_6.py deleted file mode 100644 index 4da13b16d1..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/test_nexthop_mp_ipv4_6.py +++ /dev/null @@ -1,231 +0,0 @@ -#!/usr/bin/env python -# SPDX-License-Identifier: ISC - -# -# Copyright (c) 2024 by 6WIND -# - -""" -Test BGP nexthop conformity with IPv4,6 MP-BGP over IPv4 peering -""" - -import os -import sys -import json -import functools -from functools import partial -import pytest - -# Save the Current Working Directory to find configuration files. -CWD = os.path.dirname(os.path.realpath(__file__)) -sys.path.append(os.path.join(CWD, "../")) - -# pylint: disable=C0413 -# Import topogen and topotest helpers -from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen -from lib.topolog import logger -from lib.checkping import check_ping -from lib.bgp import verify_bgp_convergence_from_running_config - -pytestmark = [pytest.mark.bgpd, pytest.mark.isisd] - - -def build_topo(tgen): - r""" - +---+ - | h1| - +---+ - | - +---+ - | r1| AS 65100 - +---+ - / \ _____________ - / \ - +---+ +---+ - | r2| | r3| rr1 is route-reflector - +---+ +---+ for r2 and r3 - \ / - \ / - +---+ - |rr1| AS 65000 - +---+ - / \ - / \ - +---+ +---+ - | r4| | r5| iBGP full-mesh between - +---+ +---+ rr1, r4, r5 and r6 - \ / - \ / - +---+ - | r6| - +---+ - | _____________ - | - | +---+ - [sw1]-----|rs1| AS 65200 - /\ +---+ rs1: route-server - / \ - / \ _____________ - +---+ +---+ - | r7| | r8| AS 65700 (r7) - +---+ +---+ AS 65800 (r8) - | | - +---+ +---+ - | h2| | h3| - +---+ +---+ - """ - - def connect_routers(tgen, left, right): - for rname in [left, right]: - if rname not in tgen.routers().keys(): - tgen.add_router(rname) - - switch = tgen.add_switch("s-{}-{}".format(left, right)) - switch.add_link(tgen.gears[left], nodeif="eth-{}".format(right)) - switch.add_link(tgen.gears[right], nodeif="eth-{}".format(left)) - - def connect_switchs(tgen, rname, switch): - if rname not in tgen.routers().keys(): - tgen.add_router(rname) - - switch.add_link(tgen.gears[rname], nodeif="eth-{}".format(switch.name)) - - connect_routers(tgen, "h1", "r1") - connect_routers(tgen, "r1", "r2") - connect_routers(tgen, "r1", "r3") - connect_routers(tgen, "r2", "rr1") - connect_routers(tgen, "r3", "rr1") - connect_routers(tgen, "rr1", "r4") - connect_routers(tgen, "rr1", "r5") - connect_routers(tgen, "r4", "r6") - connect_routers(tgen, "r5", "r6") - - sw1 = tgen.add_switch("sw1") - connect_switchs(tgen, "r6", sw1) - connect_switchs(tgen, "rs1", sw1) - connect_switchs(tgen, "r7", sw1) - connect_switchs(tgen, "r8", sw1) - - connect_routers(tgen, "r7", "h2") - connect_routers(tgen, "r8", "h3") - - -def setup_module(mod): - "Sets up the pytest environment" - - tgen = Topogen(build_topo, mod.__name__) - tgen.start_topology() - logger.info("setup_module") - - for rname, router in tgen.routers().items(): - router.load_config( - TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) - ) - if "h" in rname: - # hosts - continue - - router.load_config( - TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname)) - ) - - if rname in ["r1", "r7", "r8", "rs1"]: - # external routers - continue - - router.load_config( - TopoRouter.RD_ISIS, os.path.join(CWD, "{}/isisd.conf".format(rname)) - ) - - # Initialize all routers. - tgen.start_router() - - -def teardown_module(_mod): - "Teardown the pytest environment" - tgen = get_topogen() - tgen.stop_topology() - - -def test_bgp_convergence(): - "Assert that BGP is converging." - tgen = get_topogen() - if tgen.routers_have_failure(): - pytest.skip(tgen.errors) - - logger.info("waiting for bgp peers to go up") - - for rname in tgen.routers().keys(): - if "h" in rname: - # hosts - continue - result = verify_bgp_convergence_from_running_config(tgen, dut=rname) - assert result is True, "BGP is not converging on {}".format(rname) - - -def test_bgp_ipv4_nexthop_step1(): - "Assert that BGP has correct ipv4 nexthops." - tgen = get_topogen() - if tgen.routers_have_failure(): - pytest.skip(tgen.errors) - - for rname, router in tgen.routers().items(): - if "h" in rname: - # hosts - continue - if "rs1" in rname: - continue - ref_file = "{}/{}/bgp_ipv4.json".format(CWD, rname) - expected = json.loads(open(ref_file).read()) - test_func = partial( - topotest.router_json_cmp, - router, - "show bgp ipv4 unicast json", - expected, - ) - _, res = topotest.run_and_expect(test_func, None, count=30, wait=1) - assertmsg = "{}: BGP IPv4 Nexthop failure".format(rname) - assert res is None, assertmsg - - -def test_bgp_ipv6_nexthop_step1(): - "Assert that BGP has correct ipv6 nexthops." - tgen = get_topogen() - if tgen.routers_have_failure(): - pytest.skip(tgen.errors) - - for rname, router in tgen.routers().items(): - if "h" in rname: - # hosts - continue - if "rs1" in rname: - continue - ref_file = "{}/{}/bgp_ipv6_step1.json".format(CWD, rname) - expected = json.loads(open(ref_file).read()) - test_func = partial( - topotest.router_json_cmp, - router, - "show bgp ipv6 unicast json", - expected, - ) - _, res = topotest.run_and_expect(test_func, None, count=30, wait=1) - assertmsg = "{}: BGP IPv6 Nexthop failure".format(rname) - assert res is None, assertmsg - - -def test_bgp_ping_ok_step1(): - "Check that h1 pings h2 and h3" - tgen = get_topogen() - if tgen.routers_have_failure(): - pytest.skip(tgen.errors) - - check_ping("h1", "192.168.7.1", True, 5, 1) - check_ping("h1", "fd00:700::1", True, 5, 1) - check_ping("h1", "192.168.8.1", True, 5, 1) - check_ping("h1", "fd00:800::1", True, 5, 1) - - -if __name__ == "__main__": - args = ["-s"] + sys.argv[1:] - sys.exit(pytest.main(args)) From 91a0edb0c50f8c0c03a0c0c174cc4ac65105b33f Mon Sep 17 00:00:00 2001 From: Rodrigo Nardi Date: Thu, 15 Aug 2024 10:50:34 -0300 Subject: [PATCH 334/347] doc: bgp_vty fixing default name --- bgpd/bgp_vty.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 1a87799ad2..92c15b7d2c 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -2267,9 +2267,9 @@ static int bgp_global_update_delay_config_vty(struct vty *vty, * Note that we only need to check this if this is the first time * setting the global config. */ - if (bm->v_update_delay == BGP_UPDATE_DELAY_DEF) { + if (bm->v_update_delay == BGP_UPDATE_DELAY_DEFAULT) { for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) { - if (bgp->v_update_delay != BGP_UPDATE_DELAY_DEF) { + if (bgp->v_update_delay != BGP_UPDATE_DELAY_DEFAULT) { vty_out(vty, "%% update-delay configuration found in vrf %s\n", bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT @@ -2314,7 +2314,7 @@ static int bgp_global_update_delay_deconfig_vty(struct vty *vty) struct listnode *node, *nnode; struct bgp *bgp; - bm->v_update_delay = BGP_UPDATE_DELAY_DEF; + bm->v_update_delay = BGP_UPDATE_DELAY_DEFAULT; bm->v_establish_wait = bm->v_update_delay; for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) { @@ -2368,7 +2368,7 @@ static int bgp_update_delay_deconfig_vty(struct vty *vty) "%%Failed: bgp update-delay configured globally. Delete per-vrf not permitted\n"); return CMD_WARNING_CONFIG_FAILED; } - bgp->v_update_delay = BGP_UPDATE_DELAY_DEF; + bgp->v_update_delay = BGP_UPDATE_DELAY_DEFAULT; bgp->v_establish_wait = bgp->v_update_delay; return CMD_SUCCESS; @@ -19194,7 +19194,7 @@ int bgp_config_write(struct vty *vty) vty_out(vty, "bgp route-map delay-timer %u\n", bm->rmap_update_timer); - if (bm->v_update_delay != BGP_UPDATE_DELAY_DEF) { + if (bm->v_update_delay != BGP_UPDATE_DELAY_DEFAULT) { vty_out(vty, "bgp update-delay %d", bm->v_update_delay); if (bm->v_update_delay != bm->v_establish_wait) vty_out(vty, " %d", bm->v_establish_wait); From e5030e5eee0e90bf85aa3e782eb40a94ec395c28 Mon Sep 17 00:00:00 2001 From: Rodrigo Nardi Date: Thu, 15 Aug 2024 11:18:02 -0300 Subject: [PATCH 335/347] doc: bgp_vty fixing default name --- bgpd/bgp_vty.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/bgpd/bgp_vty.h b/bgpd/bgp_vty.h index f88f5c8125..6d86f6ba08 100644 --- a/bgpd/bgp_vty.h +++ b/bgpd/bgp_vty.h @@ -161,9 +161,8 @@ extern int bgp_vty_find_and_parse_afi_safi_bgp(struct vty *vty, int bgp_vty_find_and_parse_bgp(struct vty *vty, struct cmd_token **argv, int argc, struct bgp **bgp, bool use_json); extern int bgp_show_summary_vty(struct vty *vty, const char *name, afi_t afi, - safi_t safi, const char *neighbor, - enum peer_asn_type as_type, as_t as, - uint16_t show_flags); + safi_t safi, const char *neighbor, int as_type, + as_t as, uint16_t show_flags); extern bool peergroup_flag_check(struct peer *peer, uint64_t flag); extern bool peergroup_af_flag_check(struct peer *peer, afi_t afi, safi_t safi, uint64_t flag); From 66c9bb360db8ffd6a6cee1cf52e19f14a490d67a Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Wed, 14 Aug 2024 20:13:44 +0300 Subject: [PATCH 336/347] Revert "bgpd: fix sending ipv6 local nexthop if global present" This reverts commit 424fe0bf809c1d84f16aba3f5e5f8249af29083b. --- bgpd/bgp_zebra.c | 33 +++++---------------------------- 1 file changed, 5 insertions(+), 28 deletions(-) diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 5bb177b2f7..e72a739798 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -303,12 +303,11 @@ static int bgp_ifp_down(struct interface *ifp) static int bgp_interface_address_add(ZAPI_CALLBACK_ARGS) { - struct connected *ifc, *connected; + struct connected *ifc; struct bgp *bgp; struct peer *peer; struct prefix *addr; struct listnode *node, *nnode; - bool v6_ll_in_nh_global; afi_t afi; safi_t safi; @@ -343,27 +342,6 @@ static int bgp_interface_address_add(ZAPI_CALLBACK_ARGS) addr = ifc->address; for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { - v6_ll_in_nh_global = false; - - if (IN6_IS_ADDR_LINKLOCAL(&peer->nexthop.v6_global)) { - frr_each (if_connected, ifc->ifp->connected, - connected) { - if (connected->address->family != - AF_INET6) - continue; - if (!IPV6_ADDR_SAME(&connected->address - ->u.prefix6, - &peer->nexthop - .v6_global)) - continue; - /* peer->nexthop.v6_global contains a link-local address - * that needs to be replaced by the global address. - */ - v6_ll_in_nh_global = true; - break; - } - } - /* * If the Peer's interface name matches the * interface name for which BGP received the @@ -374,11 +352,10 @@ static int bgp_interface_address_add(ZAPI_CALLBACK_ARGS) * into peer's v6_global and send updates out * with new nexthop addr. */ - if (v6_ll_in_nh_global || - (peer->conf_if && - strcmp(peer->conf_if, ifc->ifp->name) == 0 && - (IS_MAPPED_IPV6(&peer->nexthop.v6_global) || - IN6_IS_ADDR_LINKLOCAL(&peer->nexthop.v6_global)))) { + if ((peer->conf_if && + (strcmp(peer->conf_if, ifc->ifp->name) == 0)) && + ((IS_MAPPED_IPV6(&peer->nexthop.v6_global)) || + IN6_IS_ADDR_LINKLOCAL(&peer->nexthop.v6_global))) { if (bgp_debug_zebra(ifc->address)) { zlog_debug("Update peer %pBP's current intf global addr from %pI6 to %pI6 and send updates", peer, From 2910840240288a2c9c9e491c50ebde9fef970f0c Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Wed, 14 Aug 2024 20:14:12 +0300 Subject: [PATCH 337/347] Revert "bgpd: log new ipv6 global in bgp_interface_address_add" This reverts commit b083885198157555bbb916ecae9809c5d67a567b. --- bgpd/bgp_zebra.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index e72a739798..c407008d57 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -357,10 +357,9 @@ static int bgp_interface_address_add(ZAPI_CALLBACK_ARGS) ((IS_MAPPED_IPV6(&peer->nexthop.v6_global)) || IN6_IS_ADDR_LINKLOCAL(&peer->nexthop.v6_global))) { if (bgp_debug_zebra(ifc->address)) { - zlog_debug("Update peer %pBP's current intf global addr from %pI6 to %pI6 and send updates", + zlog_debug("Update peer %pBP's current intf addr %pI6 and send updates", peer, - &peer->nexthop.v6_global, - &addr->u.prefix6); + &peer->nexthop.v6_global); } memcpy(&peer->nexthop.v6_global, &addr->u.prefix6, IPV6_MAX_BYTELEN); From 64d6da59b22d8a12512170261649d902ead45622 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Wed, 14 Aug 2024 20:14:16 +0300 Subject: [PATCH 338/347] Revert "bgpd: reduce bgp_interface_address_add indentation" This reverts commit 778e0df87b7a846f46d84f61ea889a32fe578e49. --- bgpd/bgp_zebra.c | 84 ++++++++++++++++++++++++++---------------------- 1 file changed, 45 insertions(+), 39 deletions(-) diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index c407008d57..79bb43bda9 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -325,47 +325,53 @@ static int bgp_interface_address_add(ZAPI_CALLBACK_ARGS) if (!bgp) return 0; - if (!if_is_operative(ifc->ifp)) - return 0; - - bgp_connected_add(bgp, ifc); - - /* If we have learnt of any neighbors on this interface, - * check to kick off any BGP interface-based neighbors, - * but only if this is a link-local address. - */ - if (IN6_IS_ADDR_LINKLOCAL(&ifc->address->u.prefix6) && - !list_isempty(ifc->ifp->nbr_connected)) - bgp_start_interface_nbrs(bgp, ifc->ifp); - else if (ifc->address->family == AF_INET6 && - !IN6_IS_ADDR_LINKLOCAL(&ifc->address->u.prefix6)) { - addr = ifc->address; + if (if_is_operative(ifc->ifp)) { + bgp_connected_add(bgp, ifc); - for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { - /* - * If the Peer's interface name matches the - * interface name for which BGP received the - * update and if the received interface address - * is a globalV6 and if the peer is currently - * using a v4-mapped-v6 addr or a link local - * address, then copy the Rxed global v6 addr - * into peer's v6_global and send updates out - * with new nexthop addr. - */ - if ((peer->conf_if && - (strcmp(peer->conf_if, ifc->ifp->name) == 0)) && - ((IS_MAPPED_IPV6(&peer->nexthop.v6_global)) || - IN6_IS_ADDR_LINKLOCAL(&peer->nexthop.v6_global))) { - if (bgp_debug_zebra(ifc->address)) { - zlog_debug("Update peer %pBP's current intf addr %pI6 and send updates", - peer, - &peer->nexthop.v6_global); + /* If we have learnt of any neighbors on this interface, + * check to kick off any BGP interface-based neighbors, + * but only if this is a link-local address. + */ + if (IN6_IS_ADDR_LINKLOCAL(&ifc->address->u.prefix6) + && !list_isempty(ifc->ifp->nbr_connected)) + bgp_start_interface_nbrs(bgp, ifc->ifp); + else if (ifc->address->family == AF_INET6 && + !IN6_IS_ADDR_LINKLOCAL(&ifc->address->u.prefix6)) { + addr = ifc->address; + + for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { + /* + * If the Peer's interface name matches the + * interface name for which BGP received the + * update and if the received interface address + * is a globalV6 and if the peer is currently + * using a v4-mapped-v6 addr or a link local + * address, then copy the Rxed global v6 addr + * into peer's v6_global and send updates out + * with new nexthop addr. + */ + if ((peer->conf_if && + (strcmp(peer->conf_if, ifc->ifp->name) == + 0)) && + ((IS_MAPPED_IPV6( + &peer->nexthop.v6_global)) || + IN6_IS_ADDR_LINKLOCAL( + &peer->nexthop.v6_global))) { + + if (bgp_debug_zebra(ifc->address)) { + zlog_debug( + "Update peer %pBP's current intf addr %pI6 and send updates", + peer, + &peer->nexthop + .v6_global); + } + memcpy(&peer->nexthop.v6_global, + &addr->u.prefix6, + IPV6_MAX_BYTELEN); + FOREACH_AFI_SAFI (afi, safi) + bgp_announce_route(peer, afi, + safi, true); } - memcpy(&peer->nexthop.v6_global, - &addr->u.prefix6, IPV6_MAX_BYTELEN); - FOREACH_AFI_SAFI (afi, safi) - bgp_announce_route(peer, afi, safi, - true); } } } From de1d794ec006ed110b38463d1420aabc5c3011d9 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Wed, 14 Aug 2024 20:14:20 +0300 Subject: [PATCH 339/347] Revert "bgpd: optimize bgp_interface_address_add" This reverts commit 8599fe2b5e34b2ac1a46a14983ddcc2336e9116d. --- bgpd/bgp_zebra.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 79bb43bda9..00013b1e7a 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -335,11 +335,13 @@ static int bgp_interface_address_add(ZAPI_CALLBACK_ARGS) if (IN6_IS_ADDR_LINKLOCAL(&ifc->address->u.prefix6) && !list_isempty(ifc->ifp->nbr_connected)) bgp_start_interface_nbrs(bgp, ifc->ifp); - else if (ifc->address->family == AF_INET6 && - !IN6_IS_ADDR_LINKLOCAL(&ifc->address->u.prefix6)) { + else { addr = ifc->address; for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { + if (addr->family == AF_INET) + continue; + /* * If the Peer's interface name matches the * interface name for which BGP received the @@ -353,6 +355,7 @@ static int bgp_interface_address_add(ZAPI_CALLBACK_ARGS) if ((peer->conf_if && (strcmp(peer->conf_if, ifc->ifp->name) == 0)) && + !IN6_IS_ADDR_LINKLOCAL(&addr->u.prefix6) && ((IS_MAPPED_IPV6( &peer->nexthop.v6_global)) || IN6_IS_ADDR_LINKLOCAL( From d10419ee7a444eda21a84d1cf591199496692613 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Wed, 14 Aug 2024 20:14:55 +0300 Subject: [PATCH 340/347] Revert "topotests: update bgp_vrf_leaking_5549_routes" This reverts commit f1b8364ab3784cebfc0689883efdb21ac7d06213. --- .../pe1/results/vrf10_ipv4_unicast.json | 7 +++---- .../pe1/results/vrf20_ipv4_unicast.json | 7 +++---- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/tests/topotests/bgp_vrf_leaking_5549_routes/pe1/results/vrf10_ipv4_unicast.json b/tests/topotests/bgp_vrf_leaking_5549_routes/pe1/results/vrf10_ipv4_unicast.json index f664bb6b52..768bffbe9d 100644 --- a/tests/topotests/bgp_vrf_leaking_5549_routes/pe1/results/vrf10_ipv4_unicast.json +++ b/tests/topotests/bgp_vrf_leaking_5549_routes/pe1/results/vrf10_ipv4_unicast.json @@ -15,16 +15,15 @@ "origin": "incomplete", "nexthops": [ { - "ip": "::ffff:c000:202", "hostname": "ce1", "afi": "ipv6", - "scope": "global" + "scope": "global", + "used": true }, { "hostname": "ce1", "afi": "ipv6", - "scope": "link-local", - "used": true + "scope": "link-local" } ] } diff --git a/tests/topotests/bgp_vrf_leaking_5549_routes/pe1/results/vrf20_ipv4_unicast.json b/tests/topotests/bgp_vrf_leaking_5549_routes/pe1/results/vrf20_ipv4_unicast.json index 3498ed4326..1e93715270 100644 --- a/tests/topotests/bgp_vrf_leaking_5549_routes/pe1/results/vrf20_ipv4_unicast.json +++ b/tests/topotests/bgp_vrf_leaking_5549_routes/pe1/results/vrf20_ipv4_unicast.json @@ -17,16 +17,15 @@ "nhVrfName": "vrf10", "nexthops": [ { - "ip": "::ffff:c000:202", "hostname": "pe1", "afi": "ipv6", - "scope": "global" + "scope": "global", + "used": true }, { "hostname": "pe1", "afi": "ipv6", - "scope": "link-local", - "used": true + "scope": "link-local" } ] } From 4e2d8dbb292601f572d6b6bf5d033f622409f629 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Wed, 14 Aug 2024 20:14:59 +0300 Subject: [PATCH 341/347] Revert "bgpd: prefer link-local to a ipv4-mapped ipv6 global" This reverts commit 5dd731af8421e8b3070eec0b3af4ad234c95c6bb. --- bgpd/bgp_nht.c | 41 +++++++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c index 8ce45558e9..dc6dc54a3b 100644 --- a/bgpd/bgp_nht.c +++ b/bgpd/bgp_nht.c @@ -320,6 +320,11 @@ int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop, afi = BGP_ATTR_MP_NEXTHOP_LEN_IP6(pi->attr) ? AFI_IP6 : AFI_IP; + /* Validation for the ipv4 mapped ipv6 nexthop. */ + if (IS_MAPPED_IPV6(&pi->attr->mp_nexthop_global)) { + afi = AFI_IP; + } + /* This will return true if the global IPv6 NH is a link local * addr */ if (make_prefix(afi, pi, &p) < 0) @@ -1035,11 +1040,19 @@ static int make_prefix(int afi, struct bgp_path_info *pi, struct prefix *p) p->u.prefix4 = p_orig->u.prefix4; p->prefixlen = p_orig->prefixlen; } else { - if (p_orig->family == AF_EVPN) - p->u.prefix4 = pi->attr->mp_nexthop_global_in; - else - p->u.prefix4 = pi->attr->nexthop; - p->prefixlen = IPV4_MAX_BITLEN; + if (IS_MAPPED_IPV6(&pi->attr->mp_nexthop_global)) { + ipv4_mapped_ipv6_to_ipv4( + &pi->attr->mp_nexthop_global, &ipv4); + p->u.prefix4 = ipv4; + p->prefixlen = IPV4_MAX_BITLEN; + } else { + if (p_orig->family == AF_EVPN) + p->u.prefix4 = + pi->attr->mp_nexthop_global_in; + else + p->u.prefix4 = pi->attr->nexthop; + p->prefixlen = IPV4_MAX_BITLEN; + } } break; case AFI_IP6: @@ -1055,7 +1068,6 @@ static int make_prefix(int afi, struct bgp_path_info *pi, struct prefix *p) /* If we receive MP_REACH nexthop with ::(LL) * or LL(LL), use LL address as nexthop cache. */ - p->prefixlen = IPV6_MAX_BITLEN; if (pi->attr && pi->attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL && @@ -1070,22 +1082,15 @@ static int make_prefix(int afi, struct bgp_path_info *pi, struct prefix *p) pi->attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) { if (CHECK_FLAG(pi->attr->nh_flags, - BGP_ATTR_NH_MP_PREFER_GLOBAL)) { - if (IS_MAPPED_IPV6( - &pi->attr->mp_nexthop_global)) { - ipv4_mapped_ipv6_to_ipv4( - &pi->attr->mp_nexthop_global, - &ipv4); - p->u.prefix4 = ipv4; - p->prefixlen = IPV4_MAX_BITLEN; - } else - p->u.prefix6 = - pi->attr->mp_nexthop_global; - } else + BGP_ATTR_NH_MP_PREFER_GLOBAL)) + p->u.prefix6 = + pi->attr->mp_nexthop_global; + else p->u.prefix6 = pi->attr->mp_nexthop_local; } else p->u.prefix6 = pi->attr->mp_nexthop_global; + p->prefixlen = IPV6_MAX_BITLEN; } break; default: From 8beb5c4ca60ef2582b4d34c206f93f375d10db0e Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Wed, 14 Aug 2024 20:15:04 +0300 Subject: [PATCH 342/347] Revert "bgpd: set ipv4-mapped ipv6 for ipv4 with ipv6 nexthop" This reverts commit fc5a738409eac9ca938cbb398872ea77d9cc5023. --- bgpd/bgp_updgrp_packet.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/bgpd/bgp_updgrp_packet.c b/bgpd/bgp_updgrp_packet.c index 6e30d4f846..7c92bbd514 100644 --- a/bgpd/bgp_updgrp_packet.c +++ b/bgpd/bgp_updgrp_packet.c @@ -523,13 +523,11 @@ struct stream *bpacket_reformat_for_peer(struct bpacket *pkt, gnh_modified = 1; } - if (peer->nexthop.v4.s_addr != INADDR_ANY && - (IN6_IS_ADDR_UNSPECIFIED(mod_v6nhg) || - (IN6_IS_ADDR_LINKLOCAL(mod_v6nhg) && - peer->connection->su.sa.sa_family == AF_INET6 && - paf->afi == AFI_IP))) { - ipv4_to_ipv4_mapped_ipv6(mod_v6nhg, peer->nexthop.v4); - gnh_modified = 1; + if (IN6_IS_ADDR_UNSPECIFIED(mod_v6nhg)) { + if (peer->nexthop.v4.s_addr != INADDR_ANY) { + ipv4_to_ipv4_mapped_ipv6(mod_v6nhg, + peer->nexthop.v4); + } } if (IS_MAPPED_IPV6(&peer->nexthop.v6_global)) { From 163a65dee2129ba6530c684e4bdd8a533f055645 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Wed, 14 Aug 2024 20:15:08 +0300 Subject: [PATCH 343/347] Revert "tests: ipv6 global removal in bgp_nexthop_mp_ipv4_6" This reverts commit 04c220bedb63334a65677a46ef84938cc812221f. --- .../r1/bgp_ipv6_step2.json | 90 ------------------- .../r2/bgp_ipv6_step2.json | 48 ---------- .../r3/bgp_ipv6_step2.json | 48 ---------- .../r4/bgp_ipv6_step2.json | 49 ---------- .../r5/bgp_ipv6_step2.json | 49 ---------- .../r6/bgp_ipv6_step2.json | 48 ---------- .../r7/bgp_ipv6_step2.json | 48 ---------- .../r8/bgp_ipv6_step2.json | 48 ---------- .../rr1/bgp_ipv6_step2.json | 62 ------------- .../test_nexthop_mp_ipv4_6.py | 52 ----------- 10 files changed, 542 deletions(-) delete mode 100755 tests/topotests/bgp_nexthop_mp_ipv4_6/r1/bgp_ipv6_step2.json delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/r2/bgp_ipv6_step2.json delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/r3/bgp_ipv6_step2.json delete mode 100755 tests/topotests/bgp_nexthop_mp_ipv4_6/r4/bgp_ipv6_step2.json delete mode 100755 tests/topotests/bgp_nexthop_mp_ipv4_6/r5/bgp_ipv6_step2.json delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/r6/bgp_ipv6_step2.json delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/r7/bgp_ipv6_step2.json delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/r8/bgp_ipv6_step2.json delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/rr1/bgp_ipv6_step2.json diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r1/bgp_ipv6_step2.json b/tests/topotests/bgp_nexthop_mp_ipv4_6/r1/bgp_ipv6_step2.json deleted file mode 100755 index f7c5c7c3b5..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r1/bgp_ipv6_step2.json +++ /dev/null @@ -1,90 +0,0 @@ -{ - "routes": { - "fd00:100::/64": [ - { - "valid": true, - "bestpath": true, - "path": "", - "nexthops": [ - { - "ip": "::", - "afi": "ipv6", - "used": true - } - ] - } - ], - "fd00:700::/64": [ - { - "valid": true, - "multipath": true, - "path": "65000 65700", - "nexthops": [ - { - "ip": "fd00:0:2::3", - "afi": "ipv6", - "scope": "global" - }, - { - "afi": "ipv6", - "scope": "link-local", - "used": true - } - ] - }, - { - "valid": true, - "bestpath": true, - "path": "65000 65700", - "nexthops": [ - { - "ip": "fd00:0:1::2", - "afi": "ipv6", - "scope": "global" - }, - { - "afi": "ipv6", - "scope": "link-local", - "used": true - } - ] - } - ], - "fd00:800::/64": [ - { - "valid": true, - "multipath": true, - "path": "65000 65800", - "nexthops": [ - { - "ip": "fd00:0:2::3", - "afi": "ipv6", - "scope": "global" - }, - { - "afi": "ipv6", - "scope": "link-local", - "used": true - } - ] - }, - { - "valid": true, - "bestpath": true, - "path": "65000 65800", - "nexthops": [ - { - "ip": "fd00:0:1::2", - "afi": "ipv6", - "scope": "global" - }, - { - "afi": "ipv6", - "scope": "link-local", - "used": true - } - ] - } - ] - } -} diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r2/bgp_ipv6_step2.json b/tests/topotests/bgp_nexthop_mp_ipv4_6/r2/bgp_ipv6_step2.json deleted file mode 100644 index 21f36089b6..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r2/bgp_ipv6_step2.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "routes": { - "fd00:100::/64": [ - { - "valid": true, - "bestpath": true, - "path": "65100", - "nexthops": [ - { - "afi": "ipv6", - "scope": "link-local", - "used": true - } - ] - } - ], - "fd00:700::/64": [ - { - "valid": true, - "bestpath": true, - "path": "65700", - "nexthops": [ - { - "ip": "fd00:0:9::7", - "scope": "global", - "afi": "ipv6", - "used": true - } - ] - } - ], - "fd00:800::/64": [ - { - "valid": true, - "bestpath": true, - "path": "65800", - "nexthops": [ - { - "ip": "fd00:0:9::8", - "scope": "global", - "afi": "ipv6", - "used": true - } - ] - } - ] - } -} diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r3/bgp_ipv6_step2.json b/tests/topotests/bgp_nexthop_mp_ipv4_6/r3/bgp_ipv6_step2.json deleted file mode 100644 index 21f36089b6..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r3/bgp_ipv6_step2.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "routes": { - "fd00:100::/64": [ - { - "valid": true, - "bestpath": true, - "path": "65100", - "nexthops": [ - { - "afi": "ipv6", - "scope": "link-local", - "used": true - } - ] - } - ], - "fd00:700::/64": [ - { - "valid": true, - "bestpath": true, - "path": "65700", - "nexthops": [ - { - "ip": "fd00:0:9::7", - "scope": "global", - "afi": "ipv6", - "used": true - } - ] - } - ], - "fd00:800::/64": [ - { - "valid": true, - "bestpath": true, - "path": "65800", - "nexthops": [ - { - "ip": "fd00:0:9::8", - "scope": "global", - "afi": "ipv6", - "used": true - } - ] - } - ] - } -} diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r4/bgp_ipv6_step2.json b/tests/topotests/bgp_nexthop_mp_ipv4_6/r4/bgp_ipv6_step2.json deleted file mode 100755 index 7d0786c0ef..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r4/bgp_ipv6_step2.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "routes": { - "fd00:100::/64": [ - { - "valid": true, - "bestpath": true, - "path": "65100", - "nexthops": [ - { - "ip": "2001:db8::2", - "afi": "ipv6", - "scope": "global", - "used": true - } - ] - } - ], - "fd00:700::/64": [ - { - "valid": true, - "bestpath": true, - "path": "65700", - "nexthops": [ - { - "ip": "fd00:0:9::7", - "scope": "global", - "afi": "ipv6", - "used": true - } - ] - } - ], - "fd00:800::/64": [ - { - "valid": true, - "bestpath": true, - "path": "65800", - "nexthops": [ - { - "ip": "fd00:0:9::8", - "scope": "global", - "afi": "ipv6", - "used": true - } - ] - } - ] - } -} diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r5/bgp_ipv6_step2.json b/tests/topotests/bgp_nexthop_mp_ipv4_6/r5/bgp_ipv6_step2.json deleted file mode 100755 index 7d0786c0ef..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r5/bgp_ipv6_step2.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "routes": { - "fd00:100::/64": [ - { - "valid": true, - "bestpath": true, - "path": "65100", - "nexthops": [ - { - "ip": "2001:db8::2", - "afi": "ipv6", - "scope": "global", - "used": true - } - ] - } - ], - "fd00:700::/64": [ - { - "valid": true, - "bestpath": true, - "path": "65700", - "nexthops": [ - { - "ip": "fd00:0:9::7", - "scope": "global", - "afi": "ipv6", - "used": true - } - ] - } - ], - "fd00:800::/64": [ - { - "valid": true, - "bestpath": true, - "path": "65800", - "nexthops": [ - { - "ip": "fd00:0:9::8", - "scope": "global", - "afi": "ipv6", - "used": true - } - ] - } - ] - } -} diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r6/bgp_ipv6_step2.json b/tests/topotests/bgp_nexthop_mp_ipv4_6/r6/bgp_ipv6_step2.json deleted file mode 100644 index 55912dd74c..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r6/bgp_ipv6_step2.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "routes": { - "fd00:100::/64": [ - { - "valid": true, - "bestpath": true, - "nexthops": [ - { - "ip": "2001:db8::2", - "afi": "ipv6", - "scope": "global", - "used": true - } - ] - } - ], - "fd00:700::/64": [ - { - "valid": true, - "bestpath": true, - "path": "65700", - "nexthops": [ - { - "ip": "fd00:0:9::7", - "afi": "ipv6", - "scope": "global", - "used": true - } - ] - } - ], - "fd00:800::/64": [ - { - "valid": true, - "bestpath": true, - "path": "65800", - "nexthops": [ - { - "ip": "fd00:0:9::8", - "afi": "ipv6", - "scope": "global", - "used": true - } - ] - } - ] - } -} diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r7/bgp_ipv6_step2.json b/tests/topotests/bgp_nexthop_mp_ipv4_6/r7/bgp_ipv6_step2.json deleted file mode 100644 index 8fe5f7c1de..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r7/bgp_ipv6_step2.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "routes": { - "fd00:100::/64": [ - { - "valid": true, - "bestpath": true, - "path": "65000 65100", - "nexthops": [ - { - "ip": "fd00:0:9::6", - "afi": "ipv6", - "scope": "global", - "used": true - } - ] - } - ], - "fd00:700::/64": [ - { - "valid": true, - "bestpath": true, - "path": "", - "nexthops": [ - { - "ip": "::", - "afi": "ipv6", - "used": true - } - ] - } - ], - "fd00:800::/64": [ - { - "valid": true, - "bestpath": true, - "path": "65800", - "nexthops": [ - { - "ip": "fd00:0:9::8", - "afi": "ipv6", - "scope": "global", - "used": true - } - ] - } - ] - } -} diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r8/bgp_ipv6_step2.json b/tests/topotests/bgp_nexthop_mp_ipv4_6/r8/bgp_ipv6_step2.json deleted file mode 100644 index 20f4940328..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r8/bgp_ipv6_step2.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "routes": { - "fd00:100::/64": [ - { - "valid": true, - "bestpath": true, - "path": "65000 65100", - "nexthops": [ - { - "ip": "fd00:0:9::6", - "afi": "ipv6", - "scope": "global", - "used": true - } - ] - } - ], - "fd00:700::/64": [ - { - "valid": true, - "bestpath": true, - "path": "65700", - "nexthops": [ - { - "ip": "fd00:0:9::7", - "afi": "ipv6", - "scope": "global", - "used": true - } - ] - } - ], - "fd00:800::/64": [ - { - "valid": true, - "bestpath": true, - "path": "", - "nexthops": [ - { - "ip": "::", - "afi": "ipv6", - "used": true - } - ] - } - ] - } -} diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/rr1/bgp_ipv6_step2.json b/tests/topotests/bgp_nexthop_mp_ipv4_6/rr1/bgp_ipv6_step2.json deleted file mode 100644 index 4ab0e1c2ae..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/rr1/bgp_ipv6_step2.json +++ /dev/null @@ -1,62 +0,0 @@ -{ - "routes": { - "fd00:100::/64": [ - { - "valid": true, - "bestpath": true, - "path": "65100", - "nexthops": [ - { - "ip": "2001:db8::2", - "afi": "ipv6", - "scope": "global", - "used": true - } - ] - }, - { - "valid": true, - "multipath": true, - "path": "65100", - "nexthops": [ - { - "ip": "2001:db8::3", - "afi": "ipv6", - "scope": "global", - "used": true - } - ] - } - ], - "fd00:700::/64": [ - { - "valid": true, - "bestpath": true, - "path": "65700", - "nexthops": [ - { - "ip": "fd00:0:9::7", - "afi": "ipv6", - "scope": "global", - "used": true - } - ] - } - ], - "fd00:800::/64": [ - { - "valid": true, - "bestpath": true, - "path": "65800", - "nexthops": [ - { - "ip": "fd00:0:9::8", - "afi": "ipv6", - "scope": "global", - "used": true - } - ] - } - ] - } -} diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/test_nexthop_mp_ipv4_6.py b/tests/topotests/bgp_nexthop_mp_ipv4_6/test_nexthop_mp_ipv4_6.py index 911a6d757f..4da13b16d1 100644 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/test_nexthop_mp_ipv4_6.py +++ b/tests/topotests/bgp_nexthop_mp_ipv4_6/test_nexthop_mp_ipv4_6.py @@ -226,58 +226,6 @@ def test_bgp_ping_ok_step1(): check_ping("h1", "fd00:800::1", True, 5, 1) -def test_bgp_ipv6_nexthop_step2(): - """ - Remove IPv6 global on r1 and r7 - Assert that BGP has correct ipv6 nexthops. - """ - - tgen = get_topogen() - if tgen.routers_have_failure(): - pytest.skip(tgen.errors) - - tgen.gears["r1"].vtysh_cmd( - """ -configure -interface eth-r2 - no ipv6 address fd00:0:1::1/64 -! -interface eth-r3 - no ipv6 address fd00:0:2::1/64 -""" - ) - - for rname, router in tgen.routers().items(): - if "h" in rname: - # hosts - continue - if "rs1" in rname: - continue - ref_file = "{}/{}/bgp_ipv6_step2.json".format(CWD, rname) - expected = json.loads(open(ref_file).read()) - test_func = partial( - topotest.router_json_cmp, - router, - "show bgp ipv6 unicast json", - expected, - ) - _, res = topotest.run_and_expect(test_func, None, count=30, wait=1) - assertmsg = "{}: BGP IPv6 Nexthop failure".format(rname) - assert res is None, assertmsg - - -def test_bgp_ping_ok_step2(): - "Check that h1 pings h2 and h3" - tgen = get_topogen() - if tgen.routers_have_failure(): - pytest.skip(tgen.errors) - - check_ping("h1", "192.168.7.1", True, 5, 1) - check_ping("h1", "fd00:700::1", True, 5, 1) - check_ping("h1", "192.168.8.1", True, 5, 1) - check_ping("h1", "fd00:800::1", True, 5, 1) - - if __name__ == "__main__": args = ["-s"] + sys.argv[1:] sys.exit(pytest.main(args)) From 572b1c2e2051ce49dc92116507d04eec23df4dac Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Wed, 14 Aug 2024 20:15:13 +0300 Subject: [PATCH 344/347] Revert "bgpd: fix "used" json key on link-local nexthop" This reverts commit 2de4dfc97adfec788e45e148b4204196d612c81c. --- bgpd/bgp_route.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 714216c1f8..8efcdaa7cc 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -9659,7 +9659,10 @@ void route_vty_out(struct vty *vty, const struct prefix *p, json_object_string_add(json_nexthop_ll, "scope", "link-local"); - if (!CHECK_FLAG(attr->nh_flags, + if ((IPV6_ADDR_CMP(&attr->mp_nexthop_global, + &attr->mp_nexthop_local) != + 0) && + !CHECK_FLAG(attr->nh_flags, BGP_ATTR_NH_MP_PREFER_GLOBAL)) json_object_boolean_true_add( json_nexthop_ll, "used"); From 63094de7b9a0cb3f285d453e1d1267d92b7d7d49 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Wed, 14 Aug 2024 20:15:18 +0300 Subject: [PATCH 345/347] Revert "bgpd: fix removing ipv6 global nexhop" This reverts commit ee0378cdbb458f9d3710f1fb557368ace8d72477. --- bgpd/bgp_zebra.c | 27 ++++----------------------- 1 file changed, 4 insertions(+), 23 deletions(-) diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 00013b1e7a..d4a0209ea2 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -385,12 +385,10 @@ static int bgp_interface_address_add(ZAPI_CALLBACK_ARGS) static int bgp_interface_address_delete(ZAPI_CALLBACK_ARGS) { struct listnode *node, *nnode; - struct connected *ifc, *connected; + struct connected *ifc; struct peer *peer; struct bgp *bgp; struct prefix *addr; - struct in6_addr *v6_global = NULL; - struct in6_addr *v6_local = NULL; afi_t afi; safi_t safi; @@ -412,17 +410,7 @@ static int bgp_interface_address_delete(ZAPI_CALLBACK_ARGS) addr = ifc->address; if (bgp && addr->family == AF_INET6 && - !IN6_IS_ADDR_LINKLOCAL(&addr->u.prefix6)) { - /* find another IPv6 global if possible and find the IPv6 link-local */ - frr_each (if_connected, ifc->ifp->connected, connected) { - if (connected->address->family != AF_INET6) - continue; - if (IN6_IS_ADDR_LINKLOCAL(&connected->address->u.prefix6)) - v6_local = &connected->address->u.prefix6; - else - v6_global = &connected->address->u.prefix6; - } - + !IN6_IS_ADDR_LINKLOCAL(&addr->u.prefix)) { /* * When we are using the v6 global as part of the peering * nexthops and we are removing it, then we need to @@ -433,15 +421,8 @@ static int bgp_interface_address_delete(ZAPI_CALLBACK_ARGS) for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { if (IPV6_ADDR_SAME(&peer->nexthop.v6_global, &addr->u.prefix6)) { - if (v6_global) - IPV6_ADDR_COPY(&peer->nexthop.v6_global, - v6_global); - else if (v6_local) - IPV6_ADDR_COPY(&peer->nexthop.v6_global, - v6_local); - else - memset(&peer->nexthop.v6_global, 0, - IPV6_MAX_BYTELEN); + memset(&peer->nexthop.v6_global, 0, + IPV6_MAX_BYTELEN); FOREACH_AFI_SAFI (afi, safi) bgp_announce_route(peer, afi, safi, true); From 8b537e08c20b3ab1840abc8a08d25c5af53ed4d0 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Wed, 14 Aug 2024 20:15:22 +0300 Subject: [PATCH 346/347] Revert "bgpd: optimize bgp_interface_address_del" This reverts commit fc1dd2e5060b6e470daa203080bdb9473a637407. --- bgpd/bgp_zebra.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index d4a0209ea2..c3b93adc26 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -389,8 +389,6 @@ static int bgp_interface_address_delete(ZAPI_CALLBACK_ARGS) struct peer *peer; struct bgp *bgp; struct prefix *addr; - afi_t afi; - safi_t safi; bgp = bgp_lookup_by_vrf_id(vrf_id); @@ -409,8 +407,7 @@ static int bgp_interface_address_delete(ZAPI_CALLBACK_ARGS) addr = ifc->address; - if (bgp && addr->family == AF_INET6 && - !IN6_IS_ADDR_LINKLOCAL(&addr->u.prefix)) { + if (bgp) { /* * When we are using the v6 global as part of the peering * nexthops and we are removing it, then we need to @@ -419,10 +416,17 @@ static int bgp_interface_address_delete(ZAPI_CALLBACK_ARGS) * we do not want the peering to bounce. */ for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { - if (IPV6_ADDR_SAME(&peer->nexthop.v6_global, - &addr->u.prefix6)) { - memset(&peer->nexthop.v6_global, 0, - IPV6_MAX_BYTELEN); + afi_t afi; + safi_t safi; + + if (addr->family == AF_INET) + continue; + + if (!IN6_IS_ADDR_LINKLOCAL(&addr->u.prefix6) + && memcmp(&peer->nexthop.v6_global, + &addr->u.prefix6, 16) + == 0) { + memset(&peer->nexthop.v6_global, 0, 16); FOREACH_AFI_SAFI (afi, safi) bgp_announce_route(peer, afi, safi, true); From 0b550c4b0fef5b53ecc14bd5ce3fbd5792c72ff2 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Wed, 14 Aug 2024 20:28:13 +0300 Subject: [PATCH 347/347] Revert "topotests: add bgp_nexthop_mp_ipv4_6 test" This reverts commit 62913cb15d8195c41229c2f6090d7e189e04646e. Signed-off-by: Donatas Abraitis --- .../bgp_nexthop_mp_ipv4_6/__init__.py | 0 .../bgp_nexthop_mp_ipv4_6/h1/zebra.conf | 6 - .../bgp_nexthop_mp_ipv4_6/h2/zebra.conf | 6 - .../bgp_nexthop_mp_ipv4_6/h3/zebra.conf | 6 - .../bgp_nexthop_mp_ipv4_6/r1/bgp_ipv4.json | 70 ------ .../r1/bgp_ipv6_step1.json | 90 ------- .../bgp_nexthop_mp_ipv4_6/r1/bgpd.conf | 23 -- .../bgp_nexthop_mp_ipv4_6/r1/zebra.conf | 16 -- .../bgp_nexthop_mp_ipv4_6/r2/bgp_ipv4.json | 46 ---- .../r2/bgp_ipv6_step1.json | 53 ---- .../bgp_nexthop_mp_ipv4_6/r2/bgpd.conf | 11 - .../bgp_nexthop_mp_ipv4_6/r2/isisd.conf | 24 -- .../bgp_nexthop_mp_ipv4_6/r2/zebra.conf | 12 - .../bgp_nexthop_mp_ipv4_6/r3/bgp_ipv4.json | 46 ---- .../r3/bgp_ipv6_step1.json | 53 ---- .../bgp_nexthop_mp_ipv4_6/r3/bgpd.conf | 11 - .../bgp_nexthop_mp_ipv4_6/r3/isisd.conf | 24 -- .../bgp_nexthop_mp_ipv4_6/r3/zebra.conf | 12 - .../bgp_nexthop_mp_ipv4_6/r4/bgp_ipv4.json | 46 ---- .../r4/bgp_ipv6_step1.json | 49 ---- .../bgp_nexthop_mp_ipv4_6/r4/bgpd.conf | 13 - .../bgp_nexthop_mp_ipv4_6/r4/isisd.conf | 26 -- .../bgp_nexthop_mp_ipv4_6/r4/zebra.conf | 12 - .../bgp_nexthop_mp_ipv4_6/r5/bgp_ipv4.json | 46 ---- .../r5/bgp_ipv6_step1.json | 49 ---- .../bgp_nexthop_mp_ipv4_6/r5/bgpd.conf | 13 - .../bgp_nexthop_mp_ipv4_6/r5/isisd.conf | 26 -- .../bgp_nexthop_mp_ipv4_6/r5/zebra.conf | 12 - .../bgp_nexthop_mp_ipv4_6/r6/bgp_ipv4.json | 46 ---- .../r6/bgp_ipv6_step1.json | 48 ---- .../bgp_nexthop_mp_ipv4_6/r6/bgpd.conf | 17 -- .../bgp_nexthop_mp_ipv4_6/r6/isisd.conf | 31 --- .../bgp_nexthop_mp_ipv4_6/r6/zebra.conf | 16 -- .../bgp_nexthop_mp_ipv4_6/r7/bgp_ipv4.json | 46 ---- .../r7/bgp_ipv6_step1.json | 48 ---- .../bgp_nexthop_mp_ipv4_6/r7/bgpd.conf | 21 -- .../bgp_nexthop_mp_ipv4_6/r7/zebra.conf | 12 - .../bgp_nexthop_mp_ipv4_6/r8/bgp_ipv4.json | 46 ---- .../r8/bgp_ipv6_step1.json | 48 ---- .../bgp_nexthop_mp_ipv4_6/r8/bgpd.conf | 21 -- .../bgp_nexthop_mp_ipv4_6/r8/zebra.conf | 12 - .../bgp_nexthop_mp_ipv4_6/rr1/bgp_ipv4.json | 58 ----- .../rr1/bgp_ipv6_step1.json | 62 ----- .../bgp_nexthop_mp_ipv4_6/rr1/bgpd.conf | 26 -- .../bgp_nexthop_mp_ipv4_6/rr1/isisd.conf | 40 --- .../bgp_nexthop_mp_ipv4_6/rr1/zebra.conf | 21 -- .../bgp_nexthop_mp_ipv4_6/rs1/bgpd.conf | 21 -- .../bgp_nexthop_mp_ipv4_6/rs1/isisd.conf | 36 --- .../bgp_nexthop_mp_ipv4_6/rs1/zebra.conf | 8 - .../test_nexthop_mp_ipv4_6.py | 231 ------------------ 50 files changed, 1716 deletions(-) delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/__init__.py delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/h1/zebra.conf delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/h2/zebra.conf delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/h3/zebra.conf delete mode 100755 tests/topotests/bgp_nexthop_mp_ipv4_6/r1/bgp_ipv4.json delete mode 100755 tests/topotests/bgp_nexthop_mp_ipv4_6/r1/bgp_ipv6_step1.json delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/r1/bgpd.conf delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/r1/zebra.conf delete mode 100755 tests/topotests/bgp_nexthop_mp_ipv4_6/r2/bgp_ipv4.json delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/r2/bgp_ipv6_step1.json delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/r2/bgpd.conf delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/r2/isisd.conf delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/r2/zebra.conf delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/r3/bgp_ipv4.json delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/r3/bgp_ipv6_step1.json delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/r3/bgpd.conf delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/r3/isisd.conf delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/r3/zebra.conf delete mode 100755 tests/topotests/bgp_nexthop_mp_ipv4_6/r4/bgp_ipv4.json delete mode 100755 tests/topotests/bgp_nexthop_mp_ipv4_6/r4/bgp_ipv6_step1.json delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/r4/bgpd.conf delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/r4/isisd.conf delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/r4/zebra.conf delete mode 100755 tests/topotests/bgp_nexthop_mp_ipv4_6/r5/bgp_ipv4.json delete mode 100755 tests/topotests/bgp_nexthop_mp_ipv4_6/r5/bgp_ipv6_step1.json delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/r5/bgpd.conf delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/r5/isisd.conf delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/r5/zebra.conf delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/r6/bgp_ipv4.json delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/r6/bgp_ipv6_step1.json delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/r6/bgpd.conf delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/r6/isisd.conf delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/r6/zebra.conf delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/r7/bgp_ipv4.json delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/r7/bgp_ipv6_step1.json delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/r7/bgpd.conf delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/r7/zebra.conf delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/r8/bgp_ipv4.json delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/r8/bgp_ipv6_step1.json delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/r8/bgpd.conf delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/r8/zebra.conf delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/rr1/bgp_ipv4.json delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/rr1/bgp_ipv6_step1.json delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/rr1/bgpd.conf delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/rr1/isisd.conf delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/rr1/zebra.conf delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/rs1/bgpd.conf delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/rs1/isisd.conf delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/rs1/zebra.conf delete mode 100644 tests/topotests/bgp_nexthop_mp_ipv4_6/test_nexthop_mp_ipv4_6.py diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/__init__.py b/tests/topotests/bgp_nexthop_mp_ipv4_6/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/h1/zebra.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/h1/zebra.conf deleted file mode 100644 index 9b19b2cfbd..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/h1/zebra.conf +++ /dev/null @@ -1,6 +0,0 @@ -ipv6 route ::/0 fd00:100::2 -ip route 0.0.0.0/0 192.168.1.2 -interface eth-r1 - ip address 192.168.1.1/24 - ipv6 address fd00:100::1/64 -! diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/h2/zebra.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/h2/zebra.conf deleted file mode 100644 index 2bf4a66680..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/h2/zebra.conf +++ /dev/null @@ -1,6 +0,0 @@ -ipv6 route ::/0 fd00:700::2 -ip route 0.0.0.0/0 192.168.7.2 -interface eth-r7 - ip address 192.168.7.1/24 - ipv6 address fd00:700::1/64 -! diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/h3/zebra.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/h3/zebra.conf deleted file mode 100644 index e8b6ac6e26..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/h3/zebra.conf +++ /dev/null @@ -1,6 +0,0 @@ -ipv6 route ::/0 fd00:800::2 -ip route 0.0.0.0/0 192.168.8.2 -interface eth-r8 - ip address 192.168.8.1/24 - ipv6 address fd00:800::1/64 -! diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r1/bgp_ipv4.json b/tests/topotests/bgp_nexthop_mp_ipv4_6/r1/bgp_ipv4.json deleted file mode 100755 index 12fecee39f..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r1/bgp_ipv4.json +++ /dev/null @@ -1,70 +0,0 @@ -{ - "routes": { - "192.168.1.0/24": [ - { - "valid": true, - "bestpath": true, - "path": "", - "nexthops": [ - { - "ip": "0.0.0.0", - "afi": "ipv4", - "used": true - } - ] - } - ], - "192.168.7.0/24": [ - { - "valid": true, - "multipath": true, - "path": "65000 65700", - "nexthops": [ - { - "ip": "172.16.1.3", - "afi": "ipv4", - "used": true - } - ] - }, - { - "valid": true, - "bestpath": true, - "path": "65000 65700", - "nexthops": [ - { - "ip": "172.16.0.2", - "afi": "ipv4", - "used": true - } - ] - } - ], - "192.168.8.0/24": [ - { - "valid": true, - "multipath": true, - "path": "65000 65800", - "nexthops": [ - { - "ip": "172.16.1.3", - "afi": "ipv4", - "used": true - } - ] - }, - { - "valid": true, - "bestpath": true, - "path": "65000 65800", - "nexthops": [ - { - "ip": "172.16.0.2", - "afi": "ipv4", - "used": true - } - ] - } - ] - } -} diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r1/bgp_ipv6_step1.json b/tests/topotests/bgp_nexthop_mp_ipv4_6/r1/bgp_ipv6_step1.json deleted file mode 100755 index f7c5c7c3b5..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r1/bgp_ipv6_step1.json +++ /dev/null @@ -1,90 +0,0 @@ -{ - "routes": { - "fd00:100::/64": [ - { - "valid": true, - "bestpath": true, - "path": "", - "nexthops": [ - { - "ip": "::", - "afi": "ipv6", - "used": true - } - ] - } - ], - "fd00:700::/64": [ - { - "valid": true, - "multipath": true, - "path": "65000 65700", - "nexthops": [ - { - "ip": "fd00:0:2::3", - "afi": "ipv6", - "scope": "global" - }, - { - "afi": "ipv6", - "scope": "link-local", - "used": true - } - ] - }, - { - "valid": true, - "bestpath": true, - "path": "65000 65700", - "nexthops": [ - { - "ip": "fd00:0:1::2", - "afi": "ipv6", - "scope": "global" - }, - { - "afi": "ipv6", - "scope": "link-local", - "used": true - } - ] - } - ], - "fd00:800::/64": [ - { - "valid": true, - "multipath": true, - "path": "65000 65800", - "nexthops": [ - { - "ip": "fd00:0:2::3", - "afi": "ipv6", - "scope": "global" - }, - { - "afi": "ipv6", - "scope": "link-local", - "used": true - } - ] - }, - { - "valid": true, - "bestpath": true, - "path": "65000 65800", - "nexthops": [ - { - "ip": "fd00:0:1::2", - "afi": "ipv6", - "scope": "global" - }, - { - "afi": "ipv6", - "scope": "link-local", - "used": true - } - ] - } - ] - } -} diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r1/bgpd.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/r1/bgpd.conf deleted file mode 100644 index 23b986d130..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r1/bgpd.conf +++ /dev/null @@ -1,23 +0,0 @@ -router bgp 65100 - no bgp ebgp-requires-policy - neighbor 172.16.0.2 remote-as external - neighbor 172.16.1.3 remote-as external - ! neighbor 172.16.0.2 capability extended-nexthop - ! - address-family ipv4 unicast - redistribute connected route-map RMAP4 - ! - address-family ipv6 unicast - redistribute connected route-map RMAP6 - neighbor 172.16.0.2 activate - neighbor 172.16.1.3 activate - ! - -ip prefix-list RANGE4 seq 10 permit 192.168.0.0/16 le 24 -ipv6 prefix-list RANGE6 seq 10 permit fd00:100::0/64 - -route-map RMAP4 permit 10 - match ip address prefix-list RANGE4 -! -route-map RMAP6 permit 10 - match ipv6 address prefix-list RANGE6 diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r1/zebra.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/r1/zebra.conf deleted file mode 100644 index 79cbafb5b8..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r1/zebra.conf +++ /dev/null @@ -1,16 +0,0 @@ -! -interface eth-h1 - ip address 192.168.1.2/24 - ipv6 address fd00:100::2/64 -! -interface eth-r2 - ip address 172.16.0.1/24 - ipv6 address fd00:0:1::1/64 -! -interface eth-r3 - ip address 172.16.1.1/24 - ipv6 address fd00:0:2::1/64 -! -interface lo - ip address 192.0.2.1/32 - ipv6 address 2001:db8::1/128 diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r2/bgp_ipv4.json b/tests/topotests/bgp_nexthop_mp_ipv4_6/r2/bgp_ipv4.json deleted file mode 100755 index 64dadf680c..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r2/bgp_ipv4.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - "routes": { - "192.168.1.0/24": [ - { - "valid": true, - "bestpath": true, - "path": "65100", - "nexthops": [ - { - "ip": "172.16.0.1", - "afi": "ipv4", - "used": true - } - ] - } - ], - "192.168.7.0/24": [ - { - "valid": true, - "bestpath": true, - "path": "65700", - "nexthops": [ - { - "ip": "172.17.0.7", - "afi": "ipv4", - "used": true - } - ] - } - ], - "192.168.8.0/24": [ - { - "valid": true, - "bestpath": true, - "path": "65800", - "nexthops": [ - { - "ip": "172.17.0.8", - "afi": "ipv4", - "used": true - } - ] - } - ] - } -} diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r2/bgp_ipv6_step1.json b/tests/topotests/bgp_nexthop_mp_ipv4_6/r2/bgp_ipv6_step1.json deleted file mode 100644 index 4f86a1a648..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r2/bgp_ipv6_step1.json +++ /dev/null @@ -1,53 +0,0 @@ -{ - "routes": { - "fd00:100::/64": [ - { - "valid": true, - "bestpath": true, - "path": "65100", - "nexthops": [ - { - "ip": "fd00:0:1::1", - "afi": "ipv6", - "scope": "global" - }, - { - "afi": "ipv6", - "scope": "link-local", - "used": true - } - ] - } - ], - "fd00:700::/64": [ - { - "valid": true, - "bestpath": true, - "path": "65700", - "nexthops": [ - { - "ip": "fd00:0:9::7", - "scope": "global", - "afi": "ipv6", - "used": true - } - ] - } - ], - "fd00:800::/64": [ - { - "valid": true, - "bestpath": true, - "path": "65800", - "nexthops": [ - { - "ip": "fd00:0:9::8", - "scope": "global", - "afi": "ipv6", - "used": true - } - ] - } - ] - } -} diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r2/bgpd.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/r2/bgpd.conf deleted file mode 100644 index badb11cbeb..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r2/bgpd.conf +++ /dev/null @@ -1,11 +0,0 @@ -router bgp 65000 - no bgp ebgp-requires-policy - neighbor 172.16.0.1 remote-as external - ! neighbor 172.16.0.1 capability extended-nexthop - neighbor 192.0.2.101 remote-as internal - neighbor 192.0.2.101 update-source 192.0.2.2 - ! - address-family ipv6 unicast - neighbor 172.16.0.1 activate - neighbor 192.0.2.101 activate - ! diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r2/isisd.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/r2/isisd.conf deleted file mode 100644 index 16963798f8..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r2/isisd.conf +++ /dev/null @@ -1,24 +0,0 @@ -! -interface lo - ip router isis 1 - ipv6 router isis 1 - isis passive -! -interface eth-rr1 - ip router isis 1 - ipv6 router isis 1 - isis hello-interval 1 - isis hello-multiplier 3 - isis network point-to-point -! -interface eth-r1 - ip router isis 1 - ipv6 router isis 1 - isis passive -! -router isis 1 - net 49.0000.0000.0000.0002.00 - is-type level-1 - lsp-gen-interval 1 - topology ipv6-unicast -! diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r2/zebra.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/r2/zebra.conf deleted file mode 100644 index 8997115d87..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r2/zebra.conf +++ /dev/null @@ -1,12 +0,0 @@ -! -interface eth-r1 - ip address 172.16.0.2/24 - ipv6 address fd00:0:1::2/64 -! -interface eth-rr1 - ip address 10.0.0.2/24 - ipv6 address fd00:0:3::2/64 -! -interface lo - ip address 192.0.2.2/32 - ipv6 address 2001:db8::2/128 diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r3/bgp_ipv4.json b/tests/topotests/bgp_nexthop_mp_ipv4_6/r3/bgp_ipv4.json deleted file mode 100644 index 0f18a43bf5..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r3/bgp_ipv4.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - "routes": { - "192.168.1.0/24": [ - { - "valid": true, - "bestpath": true, - "path": "65100", - "nexthops": [ - { - "ip": "172.16.1.1", - "afi": "ipv4", - "used": true - } - ] - } - ], - "192.168.7.0/24": [ - { - "valid": true, - "bestpath": true, - "path": "65700", - "nexthops": [ - { - "ip": "172.17.0.7", - "afi": "ipv4", - "used": true - } - ] - } - ], - "192.168.8.0/24": [ - { - "valid": true, - "bestpath": true, - "path": "65800", - "nexthops": [ - { - "ip": "172.17.0.8", - "afi": "ipv4", - "used": true - } - ] - } - ] - } -} diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r3/bgp_ipv6_step1.json b/tests/topotests/bgp_nexthop_mp_ipv4_6/r3/bgp_ipv6_step1.json deleted file mode 100644 index f44121c30e..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r3/bgp_ipv6_step1.json +++ /dev/null @@ -1,53 +0,0 @@ -{ - "routes": { - "fd00:100::/64": [ - { - "valid": true, - "bestpath": true, - "path": "65100", - "nexthops": [ - { - "ip": "fd00:0:2::1", - "afi": "ipv6", - "scope": "global" - }, - { - "afi": "ipv6", - "scope": "link-local", - "used": true - } - ] - } - ], - "fd00:700::/64": [ - { - "valid": true, - "bestpath": true, - "path": "65700", - "nexthops": [ - { - "ip": "fd00:0:9::7", - "scope": "global", - "afi": "ipv6", - "used": true - } - ] - } - ], - "fd00:800::/64": [ - { - "valid": true, - "bestpath": true, - "path": "65800", - "nexthops": [ - { - "ip": "fd00:0:9::8", - "scope": "global", - "afi": "ipv6", - "used": true - } - ] - } - ] - } -} diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r3/bgpd.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/r3/bgpd.conf deleted file mode 100644 index 4dec311f51..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r3/bgpd.conf +++ /dev/null @@ -1,11 +0,0 @@ -router bgp 65000 - no bgp ebgp-requires-policy - neighbor 172.16.1.1 remote-as external - ! neighbor 172.16.1.1 capability extended-nexthop - neighbor 192.0.2.101 remote-as internal - neighbor 192.0.2.101 update-source 192.0.2.3 - ! - address-family ipv6 unicast - neighbor 172.16.1.1 activate - neighbor 192.0.2.101 activate - ! diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r3/isisd.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/r3/isisd.conf deleted file mode 100644 index fe3e307b42..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r3/isisd.conf +++ /dev/null @@ -1,24 +0,0 @@ -! -interface lo - ip router isis 1 - ipv6 router isis 1 - isis passive -! -interface eth-rr1 - ip router isis 1 - ipv6 router isis 1 - isis hello-interval 1 - isis hello-multiplier 3 - isis network point-to-point -! -interface eth-r1 - ip router isis 1 - ipv6 router isis 1 - isis passive -! -router isis 1 - net 49.0000.0000.0000.0003.00 - is-type level-1 - lsp-gen-interval 1 - topology ipv6-unicast -! diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r3/zebra.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/r3/zebra.conf deleted file mode 100644 index 8074bbdcde..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r3/zebra.conf +++ /dev/null @@ -1,12 +0,0 @@ -! -interface eth-r1 - ip address 172.16.1.3/24 - ipv6 address fd00:0:2::3/64 -! -interface eth-rr1 - ip address 10.0.1.3/24 - ipv6 address fd00:0:4::3/64 -! -interface lo - ip address 192.0.2.3/32 - ipv6 address 2001:db8::3/128 diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r4/bgp_ipv4.json b/tests/topotests/bgp_nexthop_mp_ipv4_6/r4/bgp_ipv4.json deleted file mode 100755 index 64dadf680c..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r4/bgp_ipv4.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - "routes": { - "192.168.1.0/24": [ - { - "valid": true, - "bestpath": true, - "path": "65100", - "nexthops": [ - { - "ip": "172.16.0.1", - "afi": "ipv4", - "used": true - } - ] - } - ], - "192.168.7.0/24": [ - { - "valid": true, - "bestpath": true, - "path": "65700", - "nexthops": [ - { - "ip": "172.17.0.7", - "afi": "ipv4", - "used": true - } - ] - } - ], - "192.168.8.0/24": [ - { - "valid": true, - "bestpath": true, - "path": "65800", - "nexthops": [ - { - "ip": "172.17.0.8", - "afi": "ipv4", - "used": true - } - ] - } - ] - } -} diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r4/bgp_ipv6_step1.json b/tests/topotests/bgp_nexthop_mp_ipv4_6/r4/bgp_ipv6_step1.json deleted file mode 100755 index 756a78e3b1..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r4/bgp_ipv6_step1.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "routes": { - "fd00:100::/64": [ - { - "valid": true, - "bestpath": true, - "path": "65100", - "nexthops": [ - { - "ip": "fd00:0:1::1", - "afi": "ipv6", - "scope": "global", - "used": true - } - ] - } - ], - "fd00:700::/64": [ - { - "valid": true, - "bestpath": true, - "path": "65700", - "nexthops": [ - { - "ip": "fd00:0:9::7", - "scope": "global", - "afi": "ipv6", - "used": true - } - ] - } - ], - "fd00:800::/64": [ - { - "valid": true, - "bestpath": true, - "path": "65800", - "nexthops": [ - { - "ip": "fd00:0:9::8", - "scope": "global", - "afi": "ipv6", - "used": true - } - ] - } - ] - } -} diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r4/bgpd.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/r4/bgpd.conf deleted file mode 100644 index 2dbc4acddc..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r4/bgpd.conf +++ /dev/null @@ -1,13 +0,0 @@ -router bgp 65000 - neighbor 192.0.2.5 remote-as internal - neighbor 192.0.2.6 remote-as internal - neighbor 192.0.2.101 remote-as internal - neighbor 192.0.2.5 update-source 192.0.2.4 - neighbor 192.0.2.6 update-source 192.0.2.4 - neighbor 192.0.2.101 update-source 192.0.2.4 - ! - address-family ipv6 unicast - neighbor 192.0.2.5 activate - neighbor 192.0.2.6 activate - neighbor 192.0.2.101 activate - ! diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r4/isisd.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/r4/isisd.conf deleted file mode 100644 index 21eb80f58b..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r4/isisd.conf +++ /dev/null @@ -1,26 +0,0 @@ -! -interface lo - ip router isis 1 - ipv6 router isis 1 - isis passive -! -interface eth-rr1 - ip router isis 1 - ipv6 router isis 1 - isis hello-interval 1 - isis hello-multiplier 3 - isis network point-to-point -! -interface eth-r6 - ip router isis 1 - ipv6 router isis 1 - isis hello-interval 1 - isis hello-multiplier 3 - isis network point-to-point -! -router isis 1 - net 49.0000.0000.0000.0004.00 - is-type level-1 - lsp-gen-interval 1 - topology ipv6-unicast -! diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r4/zebra.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/r4/zebra.conf deleted file mode 100644 index c598b345e5..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r4/zebra.conf +++ /dev/null @@ -1,12 +0,0 @@ -! -interface eth-r6 - ip address 10.0.4.4/24 - ipv6 address fd00:0:7::4/64 -! -interface eth-rr1 - ip address 10.0.2.4/24 - ipv6 address fd00:0:5::4/64 -! -interface lo - ip address 192.0.2.4/32 - ipv6 address 2001:db8::4/128 diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r5/bgp_ipv4.json b/tests/topotests/bgp_nexthop_mp_ipv4_6/r5/bgp_ipv4.json deleted file mode 100755 index 64dadf680c..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r5/bgp_ipv4.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - "routes": { - "192.168.1.0/24": [ - { - "valid": true, - "bestpath": true, - "path": "65100", - "nexthops": [ - { - "ip": "172.16.0.1", - "afi": "ipv4", - "used": true - } - ] - } - ], - "192.168.7.0/24": [ - { - "valid": true, - "bestpath": true, - "path": "65700", - "nexthops": [ - { - "ip": "172.17.0.7", - "afi": "ipv4", - "used": true - } - ] - } - ], - "192.168.8.0/24": [ - { - "valid": true, - "bestpath": true, - "path": "65800", - "nexthops": [ - { - "ip": "172.17.0.8", - "afi": "ipv4", - "used": true - } - ] - } - ] - } -} diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r5/bgp_ipv6_step1.json b/tests/topotests/bgp_nexthop_mp_ipv4_6/r5/bgp_ipv6_step1.json deleted file mode 100755 index 756a78e3b1..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r5/bgp_ipv6_step1.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "routes": { - "fd00:100::/64": [ - { - "valid": true, - "bestpath": true, - "path": "65100", - "nexthops": [ - { - "ip": "fd00:0:1::1", - "afi": "ipv6", - "scope": "global", - "used": true - } - ] - } - ], - "fd00:700::/64": [ - { - "valid": true, - "bestpath": true, - "path": "65700", - "nexthops": [ - { - "ip": "fd00:0:9::7", - "scope": "global", - "afi": "ipv6", - "used": true - } - ] - } - ], - "fd00:800::/64": [ - { - "valid": true, - "bestpath": true, - "path": "65800", - "nexthops": [ - { - "ip": "fd00:0:9::8", - "scope": "global", - "afi": "ipv6", - "used": true - } - ] - } - ] - } -} diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r5/bgpd.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/r5/bgpd.conf deleted file mode 100644 index 101edbd71b..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r5/bgpd.conf +++ /dev/null @@ -1,13 +0,0 @@ -router bgp 65000 - neighbor 192.0.2.4 remote-as internal - neighbor 192.0.2.6 remote-as internal - neighbor 192.0.2.101 remote-as internal - neighbor 192.0.2.4 update-source 192.0.2.5 - neighbor 192.0.2.6 update-source 192.0.2.5 - neighbor 192.0.2.101 update-source 192.0.2.5 - ! - address-family ipv6 unicast - neighbor 192.0.2.4 activate - neighbor 192.0.2.6 activate - neighbor 192.0.2.101 activate - ! diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r5/isisd.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/r5/isisd.conf deleted file mode 100644 index f998e805b5..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r5/isisd.conf +++ /dev/null @@ -1,26 +0,0 @@ -! -interface lo - ip router isis 1 - ipv6 router isis 1 - isis passive -! -interface eth-rr1 - ip router isis 1 - ipv6 router isis 1 - isis hello-interval 1 - isis hello-multiplier 3 - isis network point-to-point -! -interface eth-r6 - ip router isis 1 - ipv6 router isis 1 - isis hello-interval 1 - isis hello-multiplier 3 - isis network point-to-point -! -router isis 1 - net 49.0000.0000.0000.0005.00 - is-type level-1 - lsp-gen-interval 1 - topology ipv6-unicast -! diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r5/zebra.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/r5/zebra.conf deleted file mode 100644 index 7b43db0958..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r5/zebra.conf +++ /dev/null @@ -1,12 +0,0 @@ -! -interface eth-r6 - ip address 10.0.5.5/24 - ipv6 address fd00:0:8::5/64 -! -interface eth-rr1 - ip address 10.0.3.5/24 - ipv6 address fd00:0:6::5/64 -! -interface lo - ip address 192.0.2.5/32 - ipv6 address 2001:db8::5/128 diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r6/bgp_ipv4.json b/tests/topotests/bgp_nexthop_mp_ipv4_6/r6/bgp_ipv4.json deleted file mode 100644 index 64dadf680c..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r6/bgp_ipv4.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - "routes": { - "192.168.1.0/24": [ - { - "valid": true, - "bestpath": true, - "path": "65100", - "nexthops": [ - { - "ip": "172.16.0.1", - "afi": "ipv4", - "used": true - } - ] - } - ], - "192.168.7.0/24": [ - { - "valid": true, - "bestpath": true, - "path": "65700", - "nexthops": [ - { - "ip": "172.17.0.7", - "afi": "ipv4", - "used": true - } - ] - } - ], - "192.168.8.0/24": [ - { - "valid": true, - "bestpath": true, - "path": "65800", - "nexthops": [ - { - "ip": "172.17.0.8", - "afi": "ipv4", - "used": true - } - ] - } - ] - } -} diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r6/bgp_ipv6_step1.json b/tests/topotests/bgp_nexthop_mp_ipv4_6/r6/bgp_ipv6_step1.json deleted file mode 100644 index 1a01ead2cd..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r6/bgp_ipv6_step1.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "routes": { - "fd00:100::/64": [ - { - "valid": true, - "bestpath": true, - "nexthops": [ - { - "ip": "fd00:0:1::1", - "afi": "ipv6", - "scope": "global", - "used": true - } - ] - } - ], - "fd00:700::/64": [ - { - "valid": true, - "bestpath": true, - "path": "65700", - "nexthops": [ - { - "ip": "fd00:0:9::7", - "afi": "ipv6", - "scope": "global", - "used": true - } - ] - } - ], - "fd00:800::/64": [ - { - "valid": true, - "bestpath": true, - "path": "65800", - "nexthops": [ - { - "ip": "fd00:0:9::8", - "afi": "ipv6", - "scope": "global", - "used": true - } - ] - } - ] - } -} diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r6/bgpd.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/r6/bgpd.conf deleted file mode 100644 index e036a779ae..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r6/bgpd.conf +++ /dev/null @@ -1,17 +0,0 @@ -router bgp 65000 - no bgp ebgp-requires-policy - no bgp enforce-first-as - neighbor 192.0.2.4 remote-as internal - neighbor 192.0.2.5 remote-as internal - neighbor 192.0.2.101 remote-as internal - neighbor 172.17.0.201 remote-as external - neighbor 192.0.2.4 update-source 192.0.2.6 - neighbor 192.0.2.5 update-source 192.0.2.6 - neighbor 192.0.2.101 update-source 192.0.2.6 - ! - address-family ipv6 unicast - neighbor 192.0.2.4 activate - neighbor 192.0.2.5 activate - neighbor 192.0.2.101 activate - neighbor 172.17.0.201 activate - ! diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r6/isisd.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/r6/isisd.conf deleted file mode 100644 index b575290e9b..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r6/isisd.conf +++ /dev/null @@ -1,31 +0,0 @@ -! -interface lo - ip router isis 1 - ipv6 router isis 1 - isis passive -! -interface eth-r4 - ip router isis 1 - ipv6 router isis 1 - isis hello-interval 1 - isis hello-multiplier 3 - isis network point-to-point -! -interface eth-r5 - ip router isis 1 - ipv6 router isis 1 - isis hello-interval 1 - isis hello-multiplier 3 - isis network point-to-point -! -interface eth-sw1 - ip router isis 1 - ipv6 router isis 1 - isis passive -! -router isis 1 - net 49.0000.0000.0000.0006.00 - is-type level-1 - lsp-gen-interval 1 - topology ipv6-unicast -! diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r6/zebra.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/r6/zebra.conf deleted file mode 100644 index fce74c146c..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r6/zebra.conf +++ /dev/null @@ -1,16 +0,0 @@ -! -interface eth-r4 - ip address 10.0.4.6/24 - ipv6 address fd00:0:7::6/64 -! -interface eth-r5 - ip address 10.0.5.6/24 - ipv6 address fd00:0:8::6/64 -! -interface eth-sw1 - ip address 172.17.0.6/24 - ipv6 address fd00:0:9::6/64 -! -interface lo - ip address 192.0.2.6/32 - ipv6 address 2001:db8::6/128 diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r7/bgp_ipv4.json b/tests/topotests/bgp_nexthop_mp_ipv4_6/r7/bgp_ipv4.json deleted file mode 100644 index 72b0f03c51..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r7/bgp_ipv4.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - "routes": { - "192.168.1.0/24": [ - { - "valid": true, - "bestpath": true, - "path": "65000 65100", - "nexthops": [ - { - "ip": "172.17.0.6", - "afi": "ipv4", - "used": true - } - ] - } - ], - "192.168.7.0/24": [ - { - "valid": true, - "bestpath": true, - "path": "", - "nexthops": [ - { - "ip": "0.0.0.0", - "afi": "ipv4", - "used": true - } - ] - } - ], - "192.168.8.0/24": [ - { - "valid": true, - "bestpath": true, - "path": "65800", - "nexthops": [ - { - "ip": "172.17.0.8", - "afi": "ipv4", - "used": true - } - ] - } - ] - } -} diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r7/bgp_ipv6_step1.json b/tests/topotests/bgp_nexthop_mp_ipv4_6/r7/bgp_ipv6_step1.json deleted file mode 100644 index 8fe5f7c1de..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r7/bgp_ipv6_step1.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "routes": { - "fd00:100::/64": [ - { - "valid": true, - "bestpath": true, - "path": "65000 65100", - "nexthops": [ - { - "ip": "fd00:0:9::6", - "afi": "ipv6", - "scope": "global", - "used": true - } - ] - } - ], - "fd00:700::/64": [ - { - "valid": true, - "bestpath": true, - "path": "", - "nexthops": [ - { - "ip": "::", - "afi": "ipv6", - "used": true - } - ] - } - ], - "fd00:800::/64": [ - { - "valid": true, - "bestpath": true, - "path": "65800", - "nexthops": [ - { - "ip": "fd00:0:9::8", - "afi": "ipv6", - "scope": "global", - "used": true - } - ] - } - ] - } -} diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r7/bgpd.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/r7/bgpd.conf deleted file mode 100644 index a707b23af0..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r7/bgpd.conf +++ /dev/null @@ -1,21 +0,0 @@ -router bgp 65700 - no bgp ebgp-requires-policy - no bgp enforce-first-as - neighbor 172.17.0.201 remote-as external - ! - address-family ipv4 unicast - redistribute connected route-map RMAP4 - ! - address-family ipv6 unicast - redistribute connected route-map RMAP6 - neighbor 172.17.0.201 activate - ! - -ip prefix-list RANGE4 seq 10 permit 192.168.0.0/16 le 24 -ipv6 prefix-list RANGE6 seq 10 permit fd00:700::0/64 - -route-map RMAP4 permit 10 - match ip address prefix-list RANGE4 -! -route-map RMAP6 permit 10 - match ipv6 address prefix-list RANGE6 diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r7/zebra.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/r7/zebra.conf deleted file mode 100644 index 75448297eb..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r7/zebra.conf +++ /dev/null @@ -1,12 +0,0 @@ -! -interface eth-h2 - ip address 192.168.7.2/24 - ipv6 address fd00:700::2/64 -! -interface eth-sw1 - ip address 172.17.0.7/24 - ipv6 address fd00:0:9::7/64 -! -interface lo - ip address 192.0.2.7/32 - ipv6 address 2001:db8::7/128 diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r8/bgp_ipv4.json b/tests/topotests/bgp_nexthop_mp_ipv4_6/r8/bgp_ipv4.json deleted file mode 100644 index 596ee4b40b..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r8/bgp_ipv4.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - "routes": { - "192.168.1.0/24": [ - { - "valid": true, - "bestpath": true, - "path": "65000 65100", - "nexthops": [ - { - "ip": "172.17.0.6", - "afi": "ipv4", - "used": true - } - ] - } - ], - "192.168.7.0/24": [ - { - "valid": true, - "bestpath": true, - "path": "65700", - "nexthops": [ - { - "ip": "172.17.0.7", - "afi": "ipv4", - "used": true - } - ] - } - ], - "192.168.8.0/24": [ - { - "valid": true, - "bestpath": true, - "path": "", - "nexthops": [ - { - "ip": "0.0.0.0", - "afi": "ipv4", - "used": true - } - ] - } - ] - } -} diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r8/bgp_ipv6_step1.json b/tests/topotests/bgp_nexthop_mp_ipv4_6/r8/bgp_ipv6_step1.json deleted file mode 100644 index 20f4940328..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r8/bgp_ipv6_step1.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "routes": { - "fd00:100::/64": [ - { - "valid": true, - "bestpath": true, - "path": "65000 65100", - "nexthops": [ - { - "ip": "fd00:0:9::6", - "afi": "ipv6", - "scope": "global", - "used": true - } - ] - } - ], - "fd00:700::/64": [ - { - "valid": true, - "bestpath": true, - "path": "65700", - "nexthops": [ - { - "ip": "fd00:0:9::7", - "afi": "ipv6", - "scope": "global", - "used": true - } - ] - } - ], - "fd00:800::/64": [ - { - "valid": true, - "bestpath": true, - "path": "", - "nexthops": [ - { - "ip": "::", - "afi": "ipv6", - "used": true - } - ] - } - ] - } -} diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r8/bgpd.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/r8/bgpd.conf deleted file mode 100644 index d57712dcdd..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r8/bgpd.conf +++ /dev/null @@ -1,21 +0,0 @@ -router bgp 65800 - no bgp ebgp-requires-policy - no bgp enforce-first-as - neighbor 172.17.0.201 remote-as external - ! - address-family ipv4 unicast - redistribute connected route-map RMAP4 - ! - address-family ipv6 unicast - redistribute connected route-map RMAP6 - neighbor 172.17.0.201 activate - ! - -ip prefix-list RANGE4 seq 10 permit 192.168.0.0/16 le 24 -ipv6 prefix-list RANGE6 seq 10 permit fd00:800::0/64 - -route-map RMAP4 permit 10 - match ip address prefix-list RANGE4 -! -route-map RMAP6 permit 10 - match ipv6 address prefix-list RANGE6 diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r8/zebra.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/r8/zebra.conf deleted file mode 100644 index 7e2479b751..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r8/zebra.conf +++ /dev/null @@ -1,12 +0,0 @@ -! -interface eth-h3 - ip address 192.168.8.2/24 - ipv6 address fd00:800::2/64 -! -interface eth-sw1 - ip address 172.17.0.8/24 - ipv6 address fd00:0:9::8/64 -! -interface lo - ip address 192.0.2.8/32 - ipv6 address 2001:db8::8/128 diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/rr1/bgp_ipv4.json b/tests/topotests/bgp_nexthop_mp_ipv4_6/rr1/bgp_ipv4.json deleted file mode 100644 index ac67fe069c..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/rr1/bgp_ipv4.json +++ /dev/null @@ -1,58 +0,0 @@ -{ - "routes": { - "192.168.1.0/24": [ - { - "valid": true, - "bestpath": true, - "path": "65100", - "nexthops": [ - { - "ip": "172.16.0.1", - "afi": "ipv4", - "used": true - } - ] - }, - { - "valid": true, - "multipath": true, - "path": "65100", - "nexthops": [ - { - "ip": "172.16.1.1", - "afi": "ipv4", - "used": true - } - ] - } - ], - "192.168.7.0/24": [ - { - "valid": true, - "bestpath": true, - "path": "65700", - "nexthops": [ - { - "ip": "172.17.0.7", - "afi": "ipv4", - "used": true - } - ] - } - ], - "192.168.8.0/24": [ - { - "valid": true, - "bestpath": true, - "path": "65800", - "nexthops": [ - { - "ip": "172.17.0.8", - "afi": "ipv4", - "used": true - } - ] - } - ] - } -} diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/rr1/bgp_ipv6_step1.json b/tests/topotests/bgp_nexthop_mp_ipv4_6/rr1/bgp_ipv6_step1.json deleted file mode 100644 index 4e359fd97f..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/rr1/bgp_ipv6_step1.json +++ /dev/null @@ -1,62 +0,0 @@ -{ - "routes": { - "fd00:100::/64": [ - { - "valid": true, - "bestpath": true, - "path": "65100", - "nexthops": [ - { - "ip": "fd00:0:1::1", - "afi": "ipv6", - "scope": "global", - "used": true - } - ] - }, - { - "valid": true, - "multipath": true, - "path": "65100", - "nexthops": [ - { - "ip": "fd00:0:2::1", - "afi": "ipv6", - "scope": "global", - "used": true - } - ] - } - ], - "fd00:700::/64": [ - { - "valid": true, - "bestpath": true, - "path": "65700", - "nexthops": [ - { - "ip": "fd00:0:9::7", - "afi": "ipv6", - "scope": "global", - "used": true - } - ] - } - ], - "fd00:800::/64": [ - { - "valid": true, - "bestpath": true, - "path": "65800", - "nexthops": [ - { - "ip": "fd00:0:9::8", - "scope": "global", - "afi": "ipv6", - "used": true - } - ] - } - ] - } -} diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/rr1/bgpd.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/rr1/bgpd.conf deleted file mode 100644 index 9bbac8b68e..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/rr1/bgpd.conf +++ /dev/null @@ -1,26 +0,0 @@ -router bgp 65000 - neighbor 192.0.2.2 remote-as internal - neighbor 192.0.2.3 remote-as internal - neighbor 192.0.2.4 remote-as internal - neighbor 192.0.2.5 remote-as internal - neighbor 192.0.2.6 remote-as internal - neighbor 192.0.2.2 update-source 192.0.2.101 - neighbor 192.0.2.3 update-source 192.0.2.101 - neighbor 192.0.2.4 update-source 192.0.2.101 - neighbor 192.0.2.5 update-source 192.0.2.101 - neighbor 192.0.2.6 update-source 192.0.2.101 - ! - address-family ipv4 unicast - neighbor 192.0.2.2 route-reflector-client - neighbor 192.0.2.3 route-reflector-client - - ! - address-family ipv6 unicast - neighbor 192.0.2.2 activate - neighbor 192.0.2.3 activate - neighbor 192.0.2.4 activate - neighbor 192.0.2.5 activate - neighbor 192.0.2.6 activate - neighbor 192.0.2.2 route-reflector-client - neighbor 192.0.2.3 route-reflector-client - ! diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/rr1/isisd.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/rr1/isisd.conf deleted file mode 100644 index fe5bcfb9f1..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/rr1/isisd.conf +++ /dev/null @@ -1,40 +0,0 @@ -! -interface lo - ip router isis 1 - ipv6 router isis 1 - isis passive -! -interface eth-r2 - ip router isis 1 - ipv6 router isis 1 - isis hello-interval 1 - isis hello-multiplier 3 - isis network point-to-point -! -interface eth-r3 - ip router isis 1 - ipv6 router isis 1 - isis hello-interval 1 - isis hello-multiplier 3 - isis network point-to-point -! -interface eth-r4 - ip router isis 1 - ipv6 router isis 1 - isis hello-interval 1 - isis hello-multiplier 3 - isis network point-to-point -! -interface eth-r5 - ip router isis 1 - ipv6 router isis 1 - isis hello-interval 1 - isis hello-multiplier 3 - isis network point-to-point -! -router isis 1 - net 49.0000.0000.0000.0101.00 - is-type level-1 - lsp-gen-interval 1 - topology ipv6-unicast -! diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/rr1/zebra.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/rr1/zebra.conf deleted file mode 100644 index 7f5c8d1c61..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/rr1/zebra.conf +++ /dev/null @@ -1,21 +0,0 @@ -! -interface eth-r2 - ip address 10.0.0.101/24 - ipv6 address fd00:0:3::101/64 -! -interface eth-r3 - ip address 10.0.1.101/24 - ipv6 address fd00:0:4::101/64 -! -interface eth-r4 - ip address 10.0.2.101/24 - ipv6 address fd00:0:5::101/64 -! -interface eth-r5 - ip address 10.0.3.101/24 - ipv6 address fd00:0:6::101/64 -! -interface lo - ip address 192.0.2.101/32 - ipv6 address 2001:db8::101/128 - diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/rs1/bgpd.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/rs1/bgpd.conf deleted file mode 100644 index 596cc3e25c..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/rs1/bgpd.conf +++ /dev/null @@ -1,21 +0,0 @@ -router bgp 65200 view RS - bgp router-id 192.0.2.201 - no bgp ebgp-requires-policy - neighbor 172.17.0.6 remote-as external - neighbor 172.17.0.7 remote-as external - neighbor 172.17.0.8 remote-as external - ! - address-family ipv4 unicast - neighbor 172.17.0.6 route-server-client - neighbor 172.17.0.7 route-server-client - neighbor 172.17.0.8 route-server-client - - ! - address-family ipv6 unicast - neighbor 172.17.0.6 activate - neighbor 172.17.0.7 activate - neighbor 172.17.0.8 activate - neighbor 172.17.0.6 route-server-client - neighbor 172.17.0.7 route-server-client - neighbor 172.17.0.8 route-server-client - ! diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/rs1/isisd.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/rs1/isisd.conf deleted file mode 100644 index 892b4e7b74..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/rs1/isisd.conf +++ /dev/null @@ -1,36 +0,0 @@ -! -interface lo - ip router isis 1 - ipv6 router isis 1 - isis passive -! -interface eth-r2 - ip router isis 1 - ipv6 router isis 1 - isis hello-interval 1 - isis hello-multiplier 3 -! -interface eth-r3 - ip router isis 1 - ipv6 router isis 1 - isis hello-interval 1 - isis hello-multiplier 3 -! -interface eth-r4 - ip router isis 1 - ipv6 router isis 1 - isis hello-interval 1 - isis hello-multiplier 3 -! -interface eth-r5 - ip router isis 1 - ipv6 router isis 1 - isis hello-interval 1 - isis hello-multiplier 3 -! -router isis 1 - net 49.0000.0000.0000.0101.00 - is-type level-1 - lsp-gen-interval 1 - topology ipv6-unicast -! diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/rs1/zebra.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/rs1/zebra.conf deleted file mode 100644 index 75ee08363a..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/rs1/zebra.conf +++ /dev/null @@ -1,8 +0,0 @@ -interface eth-sw1 - ip address 172.17.0.201/24 - ipv6 address fd00:0:9::201/64 -! -interface lo - ip address 192.0.2.201/32 - ipv6 address 2001:db8::201/128 - diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/test_nexthop_mp_ipv4_6.py b/tests/topotests/bgp_nexthop_mp_ipv4_6/test_nexthop_mp_ipv4_6.py deleted file mode 100644 index 4da13b16d1..0000000000 --- a/tests/topotests/bgp_nexthop_mp_ipv4_6/test_nexthop_mp_ipv4_6.py +++ /dev/null @@ -1,231 +0,0 @@ -#!/usr/bin/env python -# SPDX-License-Identifier: ISC - -# -# Copyright (c) 2024 by 6WIND -# - -""" -Test BGP nexthop conformity with IPv4,6 MP-BGP over IPv4 peering -""" - -import os -import sys -import json -import functools -from functools import partial -import pytest - -# Save the Current Working Directory to find configuration files. -CWD = os.path.dirname(os.path.realpath(__file__)) -sys.path.append(os.path.join(CWD, "../")) - -# pylint: disable=C0413 -# Import topogen and topotest helpers -from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen -from lib.topolog import logger -from lib.checkping import check_ping -from lib.bgp import verify_bgp_convergence_from_running_config - -pytestmark = [pytest.mark.bgpd, pytest.mark.isisd] - - -def build_topo(tgen): - r""" - +---+ - | h1| - +---+ - | - +---+ - | r1| AS 65100 - +---+ - / \ _____________ - / \ - +---+ +---+ - | r2| | r3| rr1 is route-reflector - +---+ +---+ for r2 and r3 - \ / - \ / - +---+ - |rr1| AS 65000 - +---+ - / \ - / \ - +---+ +---+ - | r4| | r5| iBGP full-mesh between - +---+ +---+ rr1, r4, r5 and r6 - \ / - \ / - +---+ - | r6| - +---+ - | _____________ - | - | +---+ - [sw1]-----|rs1| AS 65200 - /\ +---+ rs1: route-server - / \ - / \ _____________ - +---+ +---+ - | r7| | r8| AS 65700 (r7) - +---+ +---+ AS 65800 (r8) - | | - +---+ +---+ - | h2| | h3| - +---+ +---+ - """ - - def connect_routers(tgen, left, right): - for rname in [left, right]: - if rname not in tgen.routers().keys(): - tgen.add_router(rname) - - switch = tgen.add_switch("s-{}-{}".format(left, right)) - switch.add_link(tgen.gears[left], nodeif="eth-{}".format(right)) - switch.add_link(tgen.gears[right], nodeif="eth-{}".format(left)) - - def connect_switchs(tgen, rname, switch): - if rname not in tgen.routers().keys(): - tgen.add_router(rname) - - switch.add_link(tgen.gears[rname], nodeif="eth-{}".format(switch.name)) - - connect_routers(tgen, "h1", "r1") - connect_routers(tgen, "r1", "r2") - connect_routers(tgen, "r1", "r3") - connect_routers(tgen, "r2", "rr1") - connect_routers(tgen, "r3", "rr1") - connect_routers(tgen, "rr1", "r4") - connect_routers(tgen, "rr1", "r5") - connect_routers(tgen, "r4", "r6") - connect_routers(tgen, "r5", "r6") - - sw1 = tgen.add_switch("sw1") - connect_switchs(tgen, "r6", sw1) - connect_switchs(tgen, "rs1", sw1) - connect_switchs(tgen, "r7", sw1) - connect_switchs(tgen, "r8", sw1) - - connect_routers(tgen, "r7", "h2") - connect_routers(tgen, "r8", "h3") - - -def setup_module(mod): - "Sets up the pytest environment" - - tgen = Topogen(build_topo, mod.__name__) - tgen.start_topology() - logger.info("setup_module") - - for rname, router in tgen.routers().items(): - router.load_config( - TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) - ) - if "h" in rname: - # hosts - continue - - router.load_config( - TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname)) - ) - - if rname in ["r1", "r7", "r8", "rs1"]: - # external routers - continue - - router.load_config( - TopoRouter.RD_ISIS, os.path.join(CWD, "{}/isisd.conf".format(rname)) - ) - - # Initialize all routers. - tgen.start_router() - - -def teardown_module(_mod): - "Teardown the pytest environment" - tgen = get_topogen() - tgen.stop_topology() - - -def test_bgp_convergence(): - "Assert that BGP is converging." - tgen = get_topogen() - if tgen.routers_have_failure(): - pytest.skip(tgen.errors) - - logger.info("waiting for bgp peers to go up") - - for rname in tgen.routers().keys(): - if "h" in rname: - # hosts - continue - result = verify_bgp_convergence_from_running_config(tgen, dut=rname) - assert result is True, "BGP is not converging on {}".format(rname) - - -def test_bgp_ipv4_nexthop_step1(): - "Assert that BGP has correct ipv4 nexthops." - tgen = get_topogen() - if tgen.routers_have_failure(): - pytest.skip(tgen.errors) - - for rname, router in tgen.routers().items(): - if "h" in rname: - # hosts - continue - if "rs1" in rname: - continue - ref_file = "{}/{}/bgp_ipv4.json".format(CWD, rname) - expected = json.loads(open(ref_file).read()) - test_func = partial( - topotest.router_json_cmp, - router, - "show bgp ipv4 unicast json", - expected, - ) - _, res = topotest.run_and_expect(test_func, None, count=30, wait=1) - assertmsg = "{}: BGP IPv4 Nexthop failure".format(rname) - assert res is None, assertmsg - - -def test_bgp_ipv6_nexthop_step1(): - "Assert that BGP has correct ipv6 nexthops." - tgen = get_topogen() - if tgen.routers_have_failure(): - pytest.skip(tgen.errors) - - for rname, router in tgen.routers().items(): - if "h" in rname: - # hosts - continue - if "rs1" in rname: - continue - ref_file = "{}/{}/bgp_ipv6_step1.json".format(CWD, rname) - expected = json.loads(open(ref_file).read()) - test_func = partial( - topotest.router_json_cmp, - router, - "show bgp ipv6 unicast json", - expected, - ) - _, res = topotest.run_and_expect(test_func, None, count=30, wait=1) - assertmsg = "{}: BGP IPv6 Nexthop failure".format(rname) - assert res is None, assertmsg - - -def test_bgp_ping_ok_step1(): - "Check that h1 pings h2 and h3" - tgen = get_topogen() - if tgen.routers_have_failure(): - pytest.skip(tgen.errors) - - check_ping("h1", "192.168.7.1", True, 5, 1) - check_ping("h1", "fd00:700::1", True, 5, 1) - check_ping("h1", "192.168.8.1", True, 5, 1) - check_ping("h1", "fd00:800::1", True, 5, 1) - - -if __name__ == "__main__": - args = ["-s"] + sys.argv[1:] - sys.exit(pytest.main(args))