diff --git a/bgpd/bgp_aspath.h b/bgpd/bgp_aspath.h index ebfc7d087d66..4c4bee9ec8d1 100644 --- a/bgpd/bgp_aspath.h +++ b/bgpd/bgp_aspath.h @@ -65,6 +65,15 @@ struct aspath { #define ASPATH_STR_DEFAULT_LEN 32 +/* `set as-path exclude ASn' */ +struct aspath_exclude { + struct aspath *aspath; + bool exclude_all; + char *exclude_aspath_acl_name; + struct as_list *exclude_aspath_acl; +}; + + /* Prototypes. */ extern void aspath_init(void); extern void aspath_finish(void); diff --git a/bgpd/bgp_filter.c b/bgpd/bgp_filter.c index ad541b67ad44..2140d60e45f6 100644 --- a/bgpd/bgp_filter.c +++ b/bgpd/bgp_filter.c @@ -205,8 +205,17 @@ static struct as_list *as_list_new(void) static void as_list_free(struct as_list *aslist) { + struct bp_as_excl_list *cur_bp = aslist->bp_list; + struct bp_as_excl_list *next_bp = NULL; XFREE(MTYPE_AS_STR, aslist->name); XFREE(MTYPE_AS_LIST, aslist); + + while(cur_bp) { + next_bp = cur_bp->next; + XFREE(MTYPE_ROUTE_MAP_COMPILED, cur_bp); + cur_bp = next_bp; + } + } /* Insert new AS list to list of as_list. Each as_list is sorted by @@ -290,6 +299,7 @@ static void as_list_delete(struct as_list *aslist) { struct as_list_list *list; struct as_filter *filter, *next; + struct bp_as_excl_list *cur_bp; for (filter = aslist->head; filter; filter = next) { next = filter->next; @@ -308,6 +318,14 @@ static void as_list_delete(struct as_list *aslist) else list->head = aslist->next; + cur_bp = aslist->bp_list; + while (cur_bp) { + cur_bp->bp_as_excl->exclude_aspath_acl = NULL; + cur_bp = cur_bp->next; + } + + + as_list_free(aslist); } diff --git a/bgpd/bgp_filter.h b/bgpd/bgp_filter.h index 1890fd3d9664..bfc2712e9889 100644 --- a/bgpd/bgp_filter.h +++ b/bgpd/bgp_filter.h @@ -25,6 +25,13 @@ struct as_filter { int64_t seq; }; + +struct bp_as_excl_list { + struct bp_as_excl_list *next; + struct aspath_exclude *bp_as_excl; +}; + + /* AS path filter list. */ struct as_list { char *name; @@ -34,6 +41,8 @@ struct as_list { struct as_filter *head; struct as_filter *tail; + /* back pointer to the aspath_excludes */ + struct bp_as_excl_list *bp_list; }; diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 36e04c5e681e..7c13de7c0ecc 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -2323,17 +2323,10 @@ static const struct route_map_rule_cmd route_set_aspath_prepend_cmd = { route_set_aspath_prepend_free, }; -/* `set as-path exclude ASn' */ -struct aspath_exclude { - struct aspath *aspath; - bool exclude_all; - char *exclude_aspath_acl_name; - struct as_list *exclude_aspath_acl; -}; - static void *route_aspath_exclude_compile(const char *arg) { struct aspath_exclude *ase; + struct bp_as_excl_list *bp; const char *str = arg; static const char asp_acl[] = "as-path-access-list"; @@ -2348,16 +2341,37 @@ static void *route_aspath_exclude_compile(const char *arg) ase->exclude_aspath_acl = as_list_lookup(str); } else ase->aspath = aspath_str2aspath(str, bgp_get_asnotation(NULL)); + + if (ase->exclude_aspath_acl) { + bp = XCALLOC(MTYPE_ROUTE_MAP_COMPILED, + sizeof(struct bp_as_excl_list)); + bp->bp_as_excl = ase; + bp->next = ase->exclude_aspath_acl->bp_list; + ase->exclude_aspath_acl->bp_list = bp; + } + + return ase; } static void route_aspath_exclude_free(void *rule) { struct aspath_exclude *ase = rule; + struct bp_as_excl_list *cur_bp = NULL; + struct bp_as_excl_list *prev_bp = NULL; aspath_free(ase->aspath); if (ase->exclude_aspath_acl_name) XFREE(MTYPE_TMP, ase->exclude_aspath_acl_name); + if (ase->exclude_aspath_acl) + cur_bp = ase->exclude_aspath_acl->bp_list; + while (cur_bp) { + if (cur_bp->bp_as_excl == ase) { + cur_bp = prev_bp; + XFREE(MTYPE_ROUTE_MAP_COMPILED, cur_bp); + break; + } + } XFREE(MTYPE_ROUTE_MAP_COMPILED, ase); } 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 a0cd89f064ce..16455bb300e0 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 @@ -22,6 +22,7 @@ # pylint: disable=C0413 from lib import topotest from lib.topogen import Topogen, TopoRouter, get_topogen +from time import sleep pytestmark = [pytest.mark.bgpd] @@ -134,12 +135,66 @@ def _bgp_regexp_1(router): } } + # tgen.mininet_cli() test_func = functools.partial(_bgp_regexp_1, tgen.gears["r1"]) _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) assert result is None, "Failed overriding incoming AS-PATH with regex 2 route-map" +def test_no_bgp_set_aspath_exclude_access_list(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + rname = "r1" + r1 = tgen.gears[rname] + + r1.vtysh_cmd( + """ +conf + no bgp as-path access-list SECOND permit 2 + """ + ) + + expected = { + "routes": { + "172.16.255.31/32": [{"path": "65003"}], + "172.16.255.32/32": [{"path": "65003"}], + } + } + + def _bgp_regexp_2(router): + output = json.loads(router.vtysh_cmd("show bgp ipv4 unicast json")) + + return topotest.json_cmp(output, expected) + + test_func = functools.partial(_bgp_regexp_2, tgen.gears["r1"]) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + + assert result is None, "Failed removing bgp as-path access-list" + + r1.vtysh_cmd( + """ +clear bgp * + """ + ) + + expected = { + "routes": { + "172.16.255.31/32": [{"path": "65002 65003"}], + "172.16.255.32/32": [{"path": "65002 65003"}], + } + } + sleep(10) + + test_func = functools.partial(_bgp_regexp_2, tgen.gears["r1"]) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + + assert result is None, "Failed to renegociate with peers" + + if __name__ == "__main__": args = ["-s"] + sys.argv[1:] sys.exit(pytest.main(args))