From 7f7940e6bf13b86ee359605f4bdeb1fb76965e1a Mon Sep 17 00:00:00 2001 From: Madhuri Kuruganti Date: Tue, 29 Sep 2020 15:16:04 +0530 Subject: [PATCH 1/8] bgpd: conditional advertisement Implemented as per the feature description given in the source link. Descriprion: The BGP conditional advertisement feature uses the non-exist-map or exist-map and the advertise-map keywords of the neighbor advertise-map command in order to track routes by the route prefix. non-exist-map : If a route prefix is not present in output of the non-exist-map command, then the route specified by the advertise-map command is announced. exist-map : If a route prefix is present in output of the exist-map command, then the route specified by the advertise-map command is announced. The conditional BGP announcements are sent in addition to the normal announcements that a BGP router sends to its peers. The conditional advertisement process is triggered by the BGP scanner process, which runs every 60 seconds. This means that the maximum time for the conditional advertisement to take effect is 60 seconds. The conditional advertisement can take effect sooner, depending on when the tracked route is removed from the BGP table and when the next instance of the BGP scanner occurs. Sample Configuration on DUT --------------------------- Router2# show running-config Building configuration... Current configuration: ! frr version 7.6-dev-MyOwnFRRVersion frr defaults traditional hostname router log file /var/log/frr/bgpd.log log syslog informational hostname Router2 service integrated-vtysh-config ! debug bgp updates in debug bgp updates out ! debug route-map ! ip route 200.200.0.0/16 blackhole ipv6 route 2001:db8::200/128 blackhole ! interface enp0s9 ip address 10.10.10.2/24 ! interface enp0s10 ip address 10.10.20.2/24 ! interface lo ip address 2.2.2.2/24 ipv6 address 2001:db8::2/128 ! router bgp 2 bgp log-neighbor-changes no bgp ebgp-requires-policy neighbor 10.10.10.1 remote-as 1 neighbor 10.10.20.3 remote-as 3 ! address-family ipv4 unicast network 2.2.2.0/24 network 200.200.0.0/16 neighbor 10.10.10.1 soft-reconfiguration inbound neighbor 10.10.10.1 advertise-map ADVERTISE non-exist-map CONDITION neighbor 10.10.20.3 soft-reconfiguration inbound exit-address-family ! address-family ipv6 unicast network 2001:db8::2/128 network 2001:db8::200/128 neighbor 10.10.10.1 activate neighbor 10.10.10.1 soft-reconfiguration inbound neighbor 10.10.10.1 advertise-map ADVERTISE_6 non-exist-map CONDITION_6 neighbor 10.10.20.3 activate neighbor 10.10.20.3 soft-reconfiguration inbound exit-address-family ! access-list CONDITION seq 5 permit 3.3.3.0/24 access-list ADVERTISE seq 5 permit 2.2.2.0/24 access-list ADVERTISE seq 6 permit 200.200.0.0/16 access-list ADVERTISE seq 7 permit 20.20.0.0/16 ! ipv6 access-list ADVERTISE_6 seq 5 permit 2001:db8::2/128 ipv6 access-list CONDITION_6 seq 5 permit 2001:db8::3/128 ! route-map ADVERTISE permit 10 match ip address ADVERTISE ! route-map CONDITION permit 10 match ip address CONDITION ! route-map ADVERTISE_6 permit 10 match ipv6 address ADVERTISE_6 ! route-map CONDITION_6 permit 10 match ipv6 address CONDITION_6 ! line vty ! end Router2# Withdraw when non-exist-map prefixes present in BGP table: ---------------------------------------------------------- Router2# show ip bgp all wide For address family: IPv4 Unicast BGP table version is 8, local router ID is 2.2.2.2, vrf id 0 Default local pref 100, local AS 2 Status codes: s suppressed, d damped, h history, * valid, > best, = multipath, i internal, r RIB-failure, S Stale, R Removed Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self Origin codes: i - IGP, e - EGP, ? - incomplete Network Next Hop Metric LocPrf Weight Path *> 1.1.1.0/24 10.10.10.1 0 0 1 i *> 2.2.2.0/24 0.0.0.0 0 32768 i *> 3.3.3.0/24 10.10.20.3 0 0 3 i *> 200.200.0.0/16 0.0.0.0 0 32768 i Displayed 4 routes and 4 total paths For address family: IPv6 Unicast BGP table version is 8, local router ID is 2.2.2.2, vrf id 0 Default local pref 100, local AS 2 Status codes: s suppressed, d damped, h history, * valid, > best, = multipath, i internal, r RIB-failure, S Stale, R Removed Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self Origin codes: i - IGP, e - EGP, ? - incomplete Network Next Hop Metric LocPrf Weight Path *> 2001:db8::1/128 fe80::a00:27ff:fecb:ad57 0 0 1 i *> 2001:db8::2/128 :: 0 32768 i *> 2001:db8::3/128 fe80::a00:27ff:fe76:6738 0 0 3 i *> 2001:db8::200/128 :: 0 32768 i Displayed 4 routes and 4 total paths Router2# Router2# show ip bgp neighbors 10.10.10.1 BGP neighbor is 10.10.10.1, remote AS 1, local AS 2, external link !--- Output suppressed. For address family: IPv4 Unicast Update group 9, subgroup 5 Packet Queue length 0 Inbound soft reconfiguration allowed Community attribute sent to this neighbor(all) Condition NON_EXIST, Condition-map *CONDITION, Advertise-map *ADVERTISE, status: Withdraw 1 accepted prefixes For address family: IPv6 Unicast Update group 10, subgroup 6 Packet Queue length 0 Inbound soft reconfiguration allowed Community attribute sent to this neighbor(all) Condition NON_EXIST, Condition-map *CONDITION_6, Advertise-map *ADVERTISE_6, status: Withdraw 1 accepted prefixes !--- Output suppressed. Router2# Here 2.2.2.0/24 & 200.200.0.0/16 (prefixes in advertise-map) are withdrawn by conditional advertisement scanner as the prefix(3.3.3.0/24) specified by non-exist-map is present in BGP table. Router2# show ip bgp all neighbors 10.10.10.1 advertised-routes wide For address family: IPv4 Unicast BGP table version is 8, local router ID is 2.2.2.2, vrf id 0 Default local pref 100, local AS 2 Status codes: s suppressed, d damped, h history, * valid, > best, = multipath, i internal, r RIB-failure, S Stale, R Removed Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self Origin codes: i - IGP, e - EGP, ? - incomplete Network Next Hop Metric LocPrf Weight Path *> 1.1.1.0/24 0.0.0.0 0 1 i *> 3.3.3.0/24 0.0.0.0 0 3 i Total number of prefixes 2 For address family: IPv6 Unicast BGP table version is 8, local router ID is 2.2.2.2, vrf id 0 Default local pref 100, local AS 2 Status codes: s suppressed, d damped, h history, * valid, > best, = multipath, i internal, r RIB-failure, S Stale, R Removed Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self Origin codes: i - IGP, e - EGP, ? - incomplete Network Next Hop Metric LocPrf Weight Path *> 2001:db8::1/128 :: 0 1 i *> 2001:db8::3/128 :: 0 3 i *> 2001:db8::200/128 :: 0 32768 i Total number of prefixes 3 Router2# Advertise when non-exist-map prefixes not present in BGP table: --------------------------------------------------------------- After Removing 3.3.3.0/24 (prefix present in non-exist-map), 2.2.2.0/24 & 200.200.0.0/16 (prefixes present in advertise-map) are advertised Router2# show ip bgp all wide For address family: IPv4 Unicast BGP table version is 9, local router ID is 2.2.2.2, vrf id 0 Default local pref 100, local AS 2 Status codes: s suppressed, d damped, h history, * valid, > best, = multipath, i internal, r RIB-failure, S Stale, R Removed Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self Origin codes: i - IGP, e - EGP, ? - incomplete Network Next Hop Metric LocPrf Weight Path *> 1.1.1.0/24 10.10.10.1 0 0 1 i *> 2.2.2.0/24 0.0.0.0 0 32768 i *> 200.200.0.0/16 0.0.0.0 0 32768 i Displayed 3 routes and 3 total paths For address family: IPv6 Unicast BGP table version is 9, local router ID is 2.2.2.2, vrf id 0 Default local pref 100, local AS 2 Status codes: s suppressed, d damped, h history, * valid, > best, = multipath, i internal, r RIB-failure, S Stale, R Removed Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self Origin codes: i - IGP, e - EGP, ? - incomplete Network Next Hop Metric LocPrf Weight Path *> 2001:db8::1/128 fe80::a00:27ff:fecb:ad57 0 0 1 i *> 2001:db8::2/128 :: 0 32768 i *> 2001:db8::200/128 :: 0 32768 i Displayed 3 routes and 3 total paths Router2# Router2# show ip bgp neighbors 10.10.10.1 !--- Output suppressed. For address family: IPv4 Unicast Update group 9, subgroup 5 Packet Queue length 0 Inbound soft reconfiguration allowed Community attribute sent to this neighbor(all) Condition NON_EXIST, Condition-map *CONDITION, Advertise-map *ADVERTISE, status: Advertise 1 accepted prefixes For address family: IPv6 Unicast Update group 10, subgroup 6 Packet Queue length 0 Inbound soft reconfiguration allowed Community attribute sent to this neighbor(all) Condition NON_EXIST, Condition-map *CONDITION_6, Advertise-map *ADVERTISE_6, status: Advertise 1 accepted prefixes !--- Output suppressed. Router2# Router2# show ip bgp all neighbors 10.10.10.1 advertised-routes wide For address family: IPv4 Unicast BGP table version is 9, local router ID is 2.2.2.2, vrf id 0 Default local pref 100, local AS 2 Status codes: s suppressed, d damped, h history, * valid, > best, = multipath, i internal, r RIB-failure, S Stale, R Removed Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self Origin codes: i - IGP, e - EGP, ? - incomplete Network Next Hop Metric LocPrf Weight Path *> 1.1.1.0/24 0.0.0.0 0 1 i *> 2.2.2.0/24 0.0.0.0 0 32768 i *> 200.200.0.0/16 0.0.0.0 0 32768 i Total number of prefixes 3 For address family: IPv6 Unicast BGP table version is 9, local router ID is 2.2.2.2, vrf id 0 Default local pref 100, local AS 2 Status codes: s suppressed, d damped, h history, * valid, > best, = multipath, i internal, r RIB-failure, S Stale, R Removed Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self Origin codes: i - IGP, e - EGP, ? - incomplete Network Next Hop Metric LocPrf Weight Path *> 2001:db8::1/128 :: 0 1 i *> 2001:db8::2/128 :: 0 32768 i *> 2001:db8::200/128 :: 0 32768 i Total number of prefixes 3 Router2# Signed-off-by: Madhuri Kuruganti --- bgpd/bgp_conditional_adv.c | 484 +++++++++++++++++++++++++++++++++++++ bgpd/bgp_conditional_adv.h | 142 +++++++++++ bgpd/bgp_route.c | 10 +- bgpd/bgp_route.h | 11 +- bgpd/bgp_routemap.c | 12 + bgpd/bgp_updgrp.c | 28 +++ bgpd/bgp_updgrp_adv.c | 5 +- bgpd/bgp_vty.c | 175 ++++++++++++++ bgpd/bgpd.c | 187 ++++++++++++++ bgpd/bgpd.h | 41 ++++ bgpd/subdir.am | 2 + doc/user/bgp.rst | 176 ++++++++++++++ 12 files changed, 1267 insertions(+), 6 deletions(-) create mode 100644 bgpd/bgp_conditional_adv.c create mode 100644 bgpd/bgp_conditional_adv.h diff --git a/bgpd/bgp_conditional_adv.c b/bgpd/bgp_conditional_adv.c new file mode 100644 index 0000000000..f38ef902ea --- /dev/null +++ b/bgpd/bgp_conditional_adv.c @@ -0,0 +1,484 @@ +/* + * BGP Conditional advertisement + * Copyright (C) 2020 Samsung Research Institute Bangalore. + * Madhurilatha Kuruganti + * + * This program 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 2 of the License, or (at your option) + * any later version. + * + * This program 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 program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "bgpd/bgp_conditional_adv.h" + +const char *get_afi_safi_str(afi_t afi, safi_t safi, bool for_json); + +/* We just need bgp_dest node matches with filter prefix. So no need to + * traverse each path here. + */ +struct bgp_dest *bgp_dest_matches_filter_prefix(struct bgp_table *table, + struct filter *filter) +{ + uint32_t check_addr; + uint32_t check_mask; + struct in_addr mask; + struct bgp_dest *dest = NULL; + struct bgp_path_info *pi = NULL; + const struct prefix *dest_p = NULL; + struct filter_cisco *cfilter = NULL; + struct filter_zebra *zfilter = NULL; + + if (filter->cisco) { + cfilter = &filter->u.cfilter; + for (dest = bgp_table_top(table); dest; + dest = bgp_route_next(dest)) { + dest_p = (struct prefix *)bgp_dest_get_prefix(dest); + if (!dest_p) + continue; + pi = bgp_dest_get_bgp_path_info(dest); + if (!pi) + continue; + check_addr = dest_p->u.prefix4.s_addr + & ~cfilter->addr_mask.s_addr; + if (memcmp(&check_addr, &cfilter->addr.s_addr, + sizeof(check_addr)) + != 0) + continue; + if (cfilter->extended) { + masklen2ip(dest_p->prefixlen, &mask); + check_mask = mask.s_addr + & ~cfilter->mask_mask.s_addr; + if (memcmp(&check_mask, &cfilter->mask.s_addr, + sizeof(check_mask)) + != 0) + continue; + } + return dest; + } + } else { + zfilter = &filter->u.zfilter; + for (dest = bgp_table_top(table); dest; + dest = bgp_route_next(dest)) { + dest_p = bgp_dest_get_prefix(dest); + if (!dest_p) + continue; + pi = bgp_dest_get_bgp_path_info(dest); + if (!pi) + continue; + if ((zfilter->prefix.family != dest_p->family) + || (zfilter->exact + && (zfilter->prefix.prefixlen + != dest_p->prefixlen))) + continue; + else if (!prefix_match(&zfilter->prefix, dest_p)) + continue; + else + return dest; + } + } + return NULL; +} + +enum route_map_cmd_result_t +bgp_check_rmap_prefixes_in_bgp_table(struct bgp_table *table, + struct route_map *rmap) +{ + afi_t afi; + struct access_list *alist = NULL; + struct filter *alist_filter = NULL; + struct bgp_dest *dest = NULL; + struct route_map_rule *match = NULL; + enum route_map_cmd_result_t ret = RMAP_NOOP; + + if (!is_rmap_valid(rmap)) + return ret; + + /* If several match commands are configured, all must succeed for a + * given route in order for that route to match the clause (logical AND) + */ + for (match = rmap->head->match_list.head; match; match = match->next) { + + if (!match->cmd || !match->cmd->str || !match->value) + continue; + + ret = RMAP_NOMATCH; + + afi = get_afi_from_match_rule(match->cmd->str); + if (afi == AFI_MAX) + return ret; + + alist = access_list_lookup(afi, (char *)match->value); + if (!alist) + return ret; + + /* If a match command refers to several objects in one + * command either of them should match (i.e logical OR) + */ + FOREACH_ACCESS_LIST_FILTER(alist, alist_filter) { + dest = bgp_dest_matches_filter_prefix(table, + alist_filter); + if (!dest) + continue; + + ret = RMAP_MATCH; + break; + } + /* None of the access-list's filter prefix of this Match rule is + * not matched with BGP table. + * So we do not need to process the remaining match rules + */ + if (ret != RMAP_MATCH) + break; + } + + /* route-map prefix not matched with prefixes in BGP table */ + return ret; +} + +bool bgp_conditional_adv_routes(struct peer *peer, afi_t afi, safi_t safi, + struct bgp_table *table, struct route_map *rmap, + bool advertise) +{ + int addpath_capable; + afi_t match_afi; + bool ret = false; + bool route_advertised = false; + struct peer_af *paf = NULL; + struct bgp_dest *dest = NULL; + struct access_list *alist = NULL; + struct filter *alist_filter = NULL; + struct route_map_rule *match = NULL; + struct update_subgroup *subgrp = NULL; + + paf = peer_af_find(peer, afi, safi); + if (!paf) + return ret; + + subgrp = PAF_SUBGRP(paf); + /* Ignore if subgroup doesn't exist (implies AF is not negotiated) */ + if (!subgrp) + return ret; + + if (!is_rmap_valid(rmap)) + return ret; + + addpath_capable = bgp_addpath_encode_tx(peer, afi, safi); + + /* If several match commands are configured, all must succeed for a + * given route in order for that route to match the clause (i.e. logical + * AND). But we are skipping this rule and advertising if match rule is + * valid and access-lists are having valid prefix - To be discussed + */ + for (match = rmap->head->match_list.head; match; match = match->next) { + + if (!match->cmd || !match->cmd->str || !match->value) + continue; + + match_afi = get_afi_from_match_rule(match->cmd->str); + if (match_afi == AFI_MAX) + continue; + + alist = access_list_lookup(match_afi, (char *)match->value); + if (!alist) + continue; + + if (safi == SAFI_LABELED_UNICAST) + safi = SAFI_UNICAST; + + /* If a match command refers to several objects in one + * command either of them should match (i.e logical OR) + */ + FOREACH_ACCESS_LIST_FILTER(alist, alist_filter) { + dest = bgp_dest_matches_filter_prefix(table, + alist_filter); + if (!dest) + continue; + + ret = advertise_dest_routes(subgrp, dest, peer, afi, + safi, addpath_capable, + advertise); + + /* Atleast one route advertised */ + if (!route_advertised && ret) + route_advertised = true; + } + } + return route_advertised; +} + +/* Handler of conditional advertisement timer event. + * Each route in the condition-map is evaluated. + */ +static int bgp_conditional_adv_timer(struct thread *t) +{ + afi_t afi; + safi_t safi; + int pfx_rcd_safi; + struct bgp *bgp = NULL; + struct peer *peer = NULL; + struct peer_af *paf = NULL; + struct bgp_table *table = NULL; + struct bgp_filter *filter = NULL; + struct listnode *node, *nnode = NULL; + struct update_subgroup *subgrp = NULL; + enum route_map_cmd_result_t ret, prev_ret; + bool route_advertised = false; + bool adv_withdrawn = false; + int adv_conditional = 0; + + bgp = THREAD_ARG(t); + assert(bgp); + + bgp->t_condition_check = NULL; + thread_add_timer(bm->master, bgp_conditional_adv_timer, bgp, + CONDITIONAL_ROUTES_POLL_TIME, &bgp->t_condition_check); + + /* loop through each peer and advertise or withdraw routes if + * advertise-map is configured and prefix(es) in condition-map + * does exist(exist-map)/not exist(non-exist-map) in BGP table based on + * condition(exist-map or non-exist map) + */ + FOREACH_AFI_SAFI (afi, safi) { + if (strmatch(get_afi_safi_str(afi, safi, true), "Unknown")) + continue; + + /* labeled-unicast routes are installed in the unicast table + * so in order to display the correct PfxRcd value we must + * look at SAFI_UNICAST + */ + pfx_rcd_safi = + (safi == SAFI_LABELED_UNICAST) ? SAFI_UNICAST : safi; + + table = bgp->rib[afi][pfx_rcd_safi]; + if (!table) + continue; + + /* Process conditional advertisement for each peer */ + for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { + if (!CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE)) + continue; + if (!peer->afc[afi][safi]) + continue; + + filter = &peer->filter[afi][safi]; + + if ((!filter->advmap.aname) || (!filter->advmap.cname) + || (!filter->advmap.amap) || (!filter->advmap.cmap)) + continue; + + /* cmap (route-map attached to exist-map or + * non-exist-map) map validation + */ + adv_withdrawn = false; + adv_conditional = 0; + + ret = bgp_check_rmap_prefixes_in_bgp_table(table, + filter->advmap.cmap); + prev_ret = + peer->advmap_info[afi][safi].cmap_prev_status; + + switch (ret) { + case RMAP_NOOP: + if (prev_ret == RMAP_NOOP) + continue; + + peer->advmap_info[afi][safi].cmap_prev_status = + ret; + if (filter->advmap.status) + continue; + + /* advertise previously withdrawn routes */ + adv_withdrawn = true; + break; + + case RMAP_MATCH: + /* Handle configuration changes */ + if (peer->advmap_info[afi][safi] + .config_change) { + /* If configuration(ACL filetr prefixes) + * is changed and if the advertise-map + * filter previous status was withdraw + * then we need to advertise the + * previously withdrawn routes. + * Nothing to do if the filter status + * was advertise. + */ + if ((prev_ret != RMAP_NOOP) + && !filter->advmap.status) + adv_withdrawn = true; + + adv_conditional = + (filter->advmap.condition + == CONDITION_EXIST) + ? NLRI + : WITHDRAW; + peer->advmap_info[afi][safi] + .config_change = false; + } else { + if (prev_ret != RMAP_MATCH) + adv_conditional = + (filter->advmap + .condition + == CONDITION_EXIST) + ? NLRI + : WITHDRAW; + } + peer->advmap_info[afi][safi].cmap_prev_status = + ret; + break; + + case RMAP_NOMATCH: + /* Handle configuration changes */ + if (peer->advmap_info[afi][safi] + .config_change) { + /* If configuration(ACL filetr prefixes) + * is changed and if the advertise-map + * filter previous status was withdraw + * then we need to advertise the + * previously withdrawn routes. + * Nothing to do if the filter status + * was advertise. + */ + if ((prev_ret != RMAP_NOOP) + && !filter->advmap.status) + adv_withdrawn = true; + + adv_conditional = + (filter->advmap.condition + == CONDITION_EXIST) + ? WITHDRAW + : NLRI; + peer->advmap_info[afi][safi] + .config_change = false; + } else { + if (prev_ret != RMAP_NOMATCH) + adv_conditional = + (filter->advmap + .condition + == CONDITION_EXIST) + ? WITHDRAW + : NLRI; + } + peer->advmap_info[afi][safi].cmap_prev_status = + ret; + break; + + case RMAP_OKAY: + case RMAP_ERROR: + default: + break; + } + + /* amap (route-map attached to advertise-map) + * validation. + */ + ret = is_rmap_valid(filter->advmap.amap) ? RMAP_MATCH + : RMAP_NOOP; + prev_ret = + peer->advmap_info[afi][safi].amap_prev_status; + + if (ret == RMAP_NOOP) { + if (prev_ret == RMAP_NOOP) { + if (!adv_withdrawn) + continue; + /* Should not reach here. */ + } + if (filter->advmap.status && !adv_withdrawn) + continue; + } + + /* Derive conditional advertisement status from + * condition and return value of condition-map + * validation. + */ + if (adv_conditional == NLRI) + filter->advmap.status = true; + else if (adv_conditional == WITHDRAW) + filter->advmap.status = false; + else { + /* no change in advertise status. So, only + * previously withdrawn routes will be + * advertised if needed. + */ + } + + if (adv_withdrawn) { + paf = peer_af_find(peer, afi, safi); + if (paf) { + update_subgroup_split_peer(paf, NULL); + subgrp = paf->subgroup; + if (subgrp && subgrp->update_group) + subgroup_announce_table( + paf->subgroup, NULL); + } + } + if (adv_conditional) { + route_advertised = bgp_conditional_adv_routes( + peer, afi, safi, table, + filter->advmap.amap, + filter->advmap.status); + + /* amap_prev_status is only to check whether we + * have announced any routes(advertise/withdraw) + * or not. filter->advmap.status will have the + * actual filter status + */ + peer->advmap_info[afi][safi].amap_prev_status = + route_advertised ? RMAP_MATCH + : RMAP_NOOP; + } + } + } + return 0; +} + +void bgp_conditional_adv_enable(struct peer *peer, afi_t afi, safi_t safi) +{ + struct bgp *bgp = peer->bgp; + + assert(bgp); + + /* This flag is used to monitor conditional routes status in BGP table, + * and advertise/withdraw routes only when there is a change in BGP + * table w.r.t conditional routes + */ + peer->advmap_info[afi][safi].amap_prev_status = RMAP_NOOP; + peer->advmap_info[afi][safi].cmap_prev_status = RMAP_NOOP; + peer->advmap_info[afi][safi].config_change = true; + + /* advertise-map is already configured on atleast one of its + * neighbors (AFI/SAFI). So just increment the counter. + */ + if (++bgp->condition_filter_count > 1) + return; + + /* Register for conditional routes polling timer */ + thread_add_timer(bm->master, bgp_conditional_adv_timer, bgp, + CONDITIONAL_ROUTES_POLL_TIME, &bgp->t_condition_check); +} + +void bgp_conditional_adv_disable(struct peer *peer, afi_t afi, safi_t safi) +{ + struct bgp *bgp = peer->bgp; + + assert(bgp); + + /* advertise-map is not configured on any of its neighbors or + * it is configured on more than one neighbor(AFI/SAFI). + * So there's nothing to do except decrementing the counter. + */ + if (--bgp->condition_filter_count != 0) + return; + + /* Last filter removed. So cancel conditional routes polling thread. */ + THREAD_OFF(bgp->t_condition_check); +} diff --git a/bgpd/bgp_conditional_adv.h b/bgpd/bgp_conditional_adv.h new file mode 100644 index 0000000000..cd857958a2 --- /dev/null +++ b/bgpd/bgp_conditional_adv.h @@ -0,0 +1,142 @@ +/* + * BGP Conditional advertisement + * Copyright (C) 2020 Samsung Research Institute Bangalore. + * Madhurilatha Kuruganti + * + * This program 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 2 of the License, or (at your option) + * any later version. + * + * This program 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 program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _FRR_BGP_CONDITION_ADV_H +#define _FRR_BGP_CONDITION_ADV_H +#include +#include "prefix.h" +#include "bgpd/bgp_addpath.h" +#include "bgpd/bgp_attr.h" +#include "bgpd/bgpd.h" +#include "bgpd/bgp_debug.h" +#include "bgpd/bgp_route.h" +#include "bgpd/bgp_updgrp.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Polling time for monitoring condition-map routes in route table */ +#define CONDITIONAL_ROUTES_POLL_TIME 60 + +#define FOREACH_ACCESS_LIST_FILTER(alist, filter) \ + for (filter = alist->head; filter; filter = filter->next) + +static inline bool is_rmap_valid(struct route_map *rmap) +{ + if (!rmap || !rmap->head) + return false; + + /* Doesn't make sense to configure advertise + * or condition map in deny/any clause. + */ + if (rmap->head->type != RMAP_PERMIT) + return false; + + /* If a match command is not present, all routes match the clause */ + if (!rmap->head->match_list.head) + return false; + + return true; +} + +static inline afi_t get_afi_from_match_rule(const char *str) +{ + if (!strcmp(str, "ip address")) + return AFI_IP; + else if (!strcmp(str, "ipv6 address")) + return AFI_IP6; + else + return AFI_MAX; +} + +static inline bool advertise_dest_routes(struct update_subgroup *subgrp, + struct bgp_dest *dest, + struct peer *peer, afi_t afi, + safi_t safi, int addpath_capable, + bool advertise) +{ + struct attr attr; + struct bgp_path_info *pi = NULL; + const struct prefix *dest_p = NULL; + bool route_advertised = false; + + dest_p = (struct prefix *)bgp_dest_get_prefix(dest); + if (!dest_p) + return route_advertised; + + for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) { + if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED) + || (addpath_capable + && bgp_addpath_tx_path(peer->addpath_type[afi][safi], + pi))) { + + /* Skip route-map checks in subgroup_announce_check + * while executing from the conditional advertise + * scanner process. otherwise when route-map is also + * configured on same peer, routes in advertise-map + * may not be advertised as expected. + */ + if (advertise + && subgroup_announce_check(dest, pi, subgrp, dest_p, + &attr, true)) { + bgp_adj_out_set_subgroup(dest, subgrp, &attr, + pi); + route_advertised = true; + } else { + /* If default originate is enabled for the + * peer, do not send explicit withdraw. + * This will prevent deletion of default route + * advertised through default originate. + */ + if (CHECK_FLAG(peer->af_flags[afi][safi], + PEER_FLAG_DEFAULT_ORIGINATE) + && is_default_prefix(dest_p)) + break; + + bgp_adj_out_unset_subgroup( + dest, subgrp, 1, + bgp_addpath_id_for_peer( + peer, afi, safi, + &pi->tx_addpath)); + route_advertised = true; + } + } + } + return route_advertised; +} + +struct bgp_dest *bgp_dest_matches_filter_prefix(struct bgp_table *table, + struct filter *filter); +extern enum route_map_cmd_result_t +bgp_check_rmap_prefixes_in_bgp_table(struct bgp_table *table, + struct route_map *rmap); +extern void bgp_conditional_adv_enable(struct peer *peer, afi_t afi, + safi_t safi); +extern void bgp_conditional_adv_disable(struct peer *peer, afi_t afi, + safi_t safi); +extern bool bgp_conditional_adv_routes(struct peer *peer, afi_t afi, + safi_t safi, struct bgp_table *table, + struct route_map *rmap, bool advertise); +#ifdef __cplusplus +} +#endif + +#endif /* _FRR_BGP_CONDITION_ADV_H */ diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index b637191d10..e64cf4a541 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -1671,7 +1671,8 @@ static void subgroup_announce_reset_nhop(uint8_t family, struct attr *attr) bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi, struct update_subgroup *subgrp, - const struct prefix *p, struct attr *attr) + const struct prefix *p, struct attr *attr, + bool skip_rmap_check) { struct bgp_filter *filter; struct peer *from; @@ -1986,7 +1987,9 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi, bgp_peer_as_override(bgp, afi, safi, peer, attr); /* Route map & unsuppress-map apply. */ - if (ROUTE_MAP_OUT_NAME(filter) || bgp_path_suppressed(pi)) { + if (!skip_rmap_check + && (ROUTE_MAP_OUT_NAME(filter) + || (pi->extra && pi->extra->suppress))) { struct bgp_path_info rmap_path = {0}; struct bgp_path_info_extra dummy_rmap_path_extra = {0}; struct attr dummy_attr = {0}; @@ -2484,7 +2487,8 @@ void subgroup_process_announce_selected(struct update_subgroup *subgrp, /* Announcement to the subgroup. If the route is filtered withdraw it. */ if (selected) { - if (subgroup_announce_check(dest, selected, subgrp, p, &attr)) + if (subgroup_announce_check(dest, selected, subgrp, p, &attr, + false)) bgp_adj_out_set_subgroup(dest, subgrp, &attr, selected); else bgp_adj_out_unset_subgroup(dest, subgrp, 1, diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index 4a4959298a..f770f9cb8d 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -454,6 +454,14 @@ struct bgp_aggregate { #define UNSUPPRESS_MAP_NAME(F) ((F)->usmap.name) #define UNSUPPRESS_MAP(F) ((F)->usmap.map) +#define ADVERTISE_MAP_NAME(F) ((F)->advmap.aname) +#define ADVERTISE_MAP(F) ((F)->advmap.amap) + +#define ADVERTISE_CONDITION(F) ((F)->advmap.condition) + +#define CONDITION_MAP_NAME(F) ((F)->advmap.cname) +#define CONDITION_MAP(F) ((F)->advmap.cmap) + /* path PREFIX (addpath rxid NUMBER) */ #define PATH_ADDPATH_STR_BUFFER PREFIX2STR_BUFFER + 32 @@ -671,7 +679,8 @@ extern void subgroup_process_announce_selected(struct update_subgroup *subgrp, extern bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi, struct update_subgroup *subgrp, - const struct prefix *p, struct attr *attr); + const struct prefix *p, struct attr *attr, + bool skip_rmap_check); extern void bgp_peer_clear_node_queue_drain_immediate(struct peer *peer); extern void bgp_process_queues_drain_immediate(void); diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index c655743936..c8504cfc8f 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -3695,6 +3695,18 @@ static void bgp_route_map_process_peer(const char *rmap_name, if (filter->usmap.name && (strcmp(rmap_name, filter->usmap.name) == 0)) filter->usmap.map = map; + if (filter->advmap.aname + && (strcmp(rmap_name, filter->advmap.aname) == 0)) { + filter->advmap.amap = map; + peer->advmap_info[afi][safi].config_change = true; + } + + if (filter->advmap.cname + && (strcmp(rmap_name, filter->advmap.cname) == 0)) { + filter->advmap.cmap = map; + peer->advmap_info[afi][safi].config_change = true; + } + if (peer->default_rmap[afi][safi].name && (strcmp(rmap_name, peer->default_rmap[afi][safi].name) == 0)) peer->default_rmap[afi][safi].map = map; diff --git a/bgpd/bgp_updgrp.c b/bgpd/bgp_updgrp.c index 21eca78abc..2788a8ea4f 100644 --- a/bgpd/bgp_updgrp.c +++ b/bgpd/bgp_updgrp.c @@ -195,6 +195,19 @@ static void conf_copy(struct peer *dst, struct peer *src, afi_t afi, MTYPE_BGP_FILTER_NAME, UNSUPPRESS_MAP_NAME(srcfilter)); UNSUPPRESS_MAP(dstfilter) = UNSUPPRESS_MAP(srcfilter); } + + if (ADVERTISE_MAP_NAME(srcfilter)) { + ADVERTISE_MAP_NAME(dstfilter) = XSTRDUP( + MTYPE_BGP_FILTER_NAME, ADVERTISE_MAP_NAME(srcfilter)); + ADVERTISE_MAP(dstfilter) = ADVERTISE_MAP(srcfilter); + ADVERTISE_CONDITION(dstfilter) = ADVERTISE_CONDITION(srcfilter); + } + + if (CONDITION_MAP_NAME(srcfilter)) { + CONDITION_MAP_NAME(dstfilter) = XSTRDUP( + MTYPE_BGP_FILTER_NAME, CONDITION_MAP_NAME(srcfilter)); + CONDITION_MAP(dstfilter) = CONDITION_MAP(srcfilter); + } } /** @@ -218,6 +231,10 @@ static void conf_release(struct peer *src, afi_t afi, safi_t safi) XFREE(MTYPE_BGP_FILTER_NAME, srcfilter->usmap.name); + XFREE(MTYPE_BGP_FILTER_NAME, srcfilter->advmap.aname); + + XFREE(MTYPE_BGP_FILTER_NAME, srcfilter->advmap.cname); + XFREE(MTYPE_BGP_PEER_HOST, src->host); } @@ -353,6 +370,11 @@ static unsigned int updgrp_hash_key_make(const void *p) strlen(filter->usmap.name), SEED1), key); + if (filter->advmap.aname) + key = jhash_1word(jhash(filter->advmap.aname, + strlen(filter->advmap.aname), SEED1), + key); + if (peer->default_rmap[afi][safi].name) key = jhash_1word( jhash(peer->default_rmap[afi][safi].name, @@ -481,6 +503,12 @@ static bool updgrp_hash_cmp(const void *p1, const void *p2) && strcmp(fl1->usmap.name, fl2->usmap.name))) return false; + if ((fl1->advmap.aname && !fl2->advmap.aname) + || (!fl1->advmap.aname && fl2->advmap.aname) + || (fl1->advmap.aname && fl2->advmap.aname + && strcmp(fl1->advmap.aname, fl2->advmap.aname))) + return false; + if ((pe1->default_rmap[afi][safi].name && !pe2->default_rmap[afi][safi].name) || (!pe1->default_rmap[afi][safi].name diff --git a/bgpd/bgp_updgrp_adv.c b/bgpd/bgp_updgrp_adv.c index 2e59bb3a5f..ae1359ae46 100644 --- a/bgpd/bgp_updgrp_adv.c +++ b/bgpd/bgp_updgrp_adv.c @@ -642,7 +642,8 @@ void subgroup_announce_table(struct update_subgroup *subgrp, peer->addpath_type[afi][safi], ri))) { if (subgroup_announce_check(dest, ri, subgrp, - dest_p, &attr)) + dest_p, &attr, + false)) bgp_adj_out_set_subgroup(dest, subgrp, &attr, ri); else { @@ -827,7 +828,7 @@ void subgroup_default_originate(struct update_subgroup *subgrp, int withdraw) if (subgroup_announce_check( dest, pi, subgrp, bgp_dest_get_prefix(dest), - &attr)) + &attr, false)) bgp_adj_out_set_subgroup( dest, subgrp, &attr, pi); diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 087836425b..480e3172af 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -7043,6 +7043,132 @@ ALIAS_HIDDEN(no_neighbor_filter_list, no_neighbor_filter_list_hidden_cmd, "Filter incoming routes\n" "Filter outgoing routes\n") +/* Set advertise-map to the peer. */ +static int peer_advertise_map_set_vty(struct vty *vty, const char *ip_str, + afi_t afi, safi_t safi, + const char *advertise_str, bool condition, + const char *condition_str) +{ + int ret = CMD_WARNING_CONFIG_FAILED; + struct peer *peer; + struct route_map *advertise_map; + struct route_map *condition_map; + + peer = peer_and_group_lookup_vty(vty, ip_str); + if (!peer) + return ret; + + condition_map = route_map_lookup_warn_noexist(vty, condition_str); + advertise_map = route_map_lookup_warn_noexist(vty, advertise_str); + + ret = peer_advertise_map_set(peer, afi, safi, advertise_str, + advertise_map, condition, condition_str, + condition_map); + + return bgp_vty_return(vty, ret); +} + +static int peer_advertise_map_unset_vty(struct vty *vty, const char *ip_str, + afi_t afi, safi_t safi, + const char *advertise_str, + bool condition, + const char *condition_str) +{ + int ret = CMD_WARNING_CONFIG_FAILED; + struct peer *peer; + struct route_map *advertise_map; + struct route_map *condition_map; + + + peer = peer_and_group_lookup_vty(vty, ip_str); + if (!peer) + return ret; + + condition_map = route_map_lookup_warn_noexist(vty, condition_str); + advertise_map = route_map_lookup_warn_noexist(vty, advertise_str); + + ret = peer_advertise_map_unset(peer, afi, safi, advertise_str, + advertise_map, condition, condition_str, + condition_map); + + return bgp_vty_return(vty, ret); +} + +DEFUN (neighbor_advertise_map, + neighbor_advertise_map_cmd, + "neighbor advertise-map WORD ", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Route-map to conditionally advertise routes\n" + "Name of advertise map\n" + "Advertise routes only if prefixes in exist-map are installed in BGP table\n" + "Name of the exist map\n" + "Advertise routes only if prefixes in non-exist-map are not installed in BGP table\n" + "Name of the non exist map\n") +{ + int idx = 0; + int idx_peer = 1; + int idx_advertise_word = 3; + int idx_condition_word = 5; + bool condition = CONDITION_EXIST; + + if (argv_find(argv, argc, "non-exist-map", &idx)) + condition = CONDITION_NON_EXIST; + + return peer_advertise_map_set_vty( + vty, argv[idx_peer]->arg, bgp_node_afi(vty), bgp_node_safi(vty), + argv[idx_advertise_word]->arg, condition, + argv[idx_condition_word]->arg); +} + +ALIAS_HIDDEN(neighbor_advertise_map, neighbor_advertise_map_hidden_cmd, + "neighbor advertise-map WORD ", + NEIGHBOR_STR NEIGHBOR_ADDR_STR2 + "Route-map to conditionally advertise routes\n" + "Name of advertise map\n" + "Advertise routes only if prefixes in exist-map are installed in BGP table\n" + "Name of the exist map\n" + "Advertise routes only if prefixes in non-exist-map are not installed in BGP table\n" + "Name of the non exist map\n") + +DEFUN (no_neighbor_advertise_map, + no_neighbor_advertise_map_cmd, + "no neighbor advertise-map WORD ", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Route-map to conditionally advertise routes\n" + "Name of advertise map\n" + "Advertise routes only if prefixes in exist-map are installed in BGP table\n" + "Name of the exist map\n" + "Advertise routes only if prefixes in non-exist-map are not installed in BGP table\n" + "Name of the non exist map\n") +{ + int idx = 0; + int idx_peer = 2; + int idx_advertise_word = 4; + int idx_condition_word = 6; + bool condition = CONDITION_EXIST; + + if (argv_find(argv, argc, "non-exist-map", &idx)) + condition = CONDITION_NON_EXIST; + + return peer_advertise_map_unset_vty( + vty, argv[idx_peer]->arg, bgp_node_afi(vty), bgp_node_safi(vty), + argv[idx_advertise_word]->arg, condition, + argv[idx_condition_word]->arg); +} + +ALIAS_HIDDEN(no_neighbor_advertise_map, no_neighbor_advertise_map_hidden_cmd, + "no neighbor advertise-map WORD ", + NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 + "Route-map to conditionally advertise routes\n" + "Name of advertise map\n" + "Advertise routes only if prefixes in exist-map are installed in BGP table\n" + "Name of the exist map\n" + "Advertise routes only if prefixes in non-exist-map are not installed in BGP table\n" + "Name of the non exist map\n") + /* Set route-map to the peer. */ static int peer_route_map_set_vty(struct vty *vty, const char *ip_str, afi_t afi, safi_t safi, const char *name_str, @@ -11281,6 +11407,19 @@ static void bgp_show_peer_afi(struct vty *vty, struct peer *p, afi_t afi, filter->usmap.map ? "*" : "", filter->usmap.name); + /* advertise-map */ + if (filter->advmap.aname && filter->advmap.cname) + vty_out(vty, + " Condition %s, Condition-map %s%s, Advertise-map %s%s, status: %s\n", + filter->advmap.condition ? "EXIST" + : "NON_EXIST", + filter->advmap.cmap ? "*" : "", + filter->advmap.cname, + filter->advmap.amap ? "*" : "", + filter->advmap.aname, + filter->advmap.status ? "Advertise" + : "Withdraw"); + /* Receive prefix count */ vty_out(vty, " %u accepted prefixes\n", p->pcount[afi][safi]); @@ -14996,6 +15135,10 @@ static bool peergroup_filter_check(struct peer *peer, afi_t afi, safi_t safi, return !!(filter->map[direct].name); case PEER_FT_UNSUPPRESS_MAP: return !!(filter->usmap.name); + case PEER_FT_ADVERTISE_MAP: + return !!(filter->advmap.aname + && ((filter->advmap.condition == direct) + && filter->advmap.cname)); default: return false; } @@ -15181,6 +15324,18 @@ static void bgp_config_write_filter(struct vty *vty, struct peer *peer, vty_out(vty, " neighbor %s unsuppress-map %s\n", addr, filter->usmap.name); + /* advertise-map : always applied in OUT direction*/ + if (peergroup_filter_check(peer, afi, safi, PEER_FT_ADVERTISE_MAP, + CONDITION_NON_EXIST)) + vty_out(vty, + " neighbor %s advertise-map %s non-exist-map %s\n", + addr, filter->advmap.aname, filter->advmap.cname); + + if (peergroup_filter_check(peer, afi, safi, PEER_FT_ADVERTISE_MAP, + CONDITION_EXIST)) + vty_out(vty, " neighbor %s advertise-map %s exist-map %s\n", + addr, filter->advmap.aname, filter->advmap.cname); + /* filter-list. */ if (peergroup_filter_check(peer, afi, safi, PEER_FT_FILTER_LIST, FILTER_IN)) @@ -17385,6 +17540,26 @@ void bgp_vty_init(void) install_element(BGP_VPNV6_NODE, &neighbor_unsuppress_map_cmd); install_element(BGP_VPNV6_NODE, &no_neighbor_unsuppress_map_cmd); + /* "neighbor advertise-map" commands. */ + install_element(BGP_NODE, &neighbor_advertise_map_hidden_cmd); + install_element(BGP_NODE, &no_neighbor_advertise_map_hidden_cmd); + install_element(BGP_IPV4_NODE, &neighbor_advertise_map_cmd); + install_element(BGP_IPV4_NODE, &no_neighbor_advertise_map_cmd); + install_element(BGP_IPV4M_NODE, &neighbor_advertise_map_cmd); + install_element(BGP_IPV4M_NODE, &no_neighbor_advertise_map_cmd); + install_element(BGP_IPV4L_NODE, &neighbor_advertise_map_cmd); + install_element(BGP_IPV4L_NODE, &no_neighbor_advertise_map_cmd); + install_element(BGP_IPV6_NODE, &neighbor_advertise_map_cmd); + install_element(BGP_IPV6_NODE, &no_neighbor_advertise_map_cmd); + install_element(BGP_IPV6M_NODE, &neighbor_advertise_map_cmd); + install_element(BGP_IPV6M_NODE, &no_neighbor_advertise_map_cmd); + install_element(BGP_IPV6L_NODE, &neighbor_advertise_map_cmd); + install_element(BGP_IPV6L_NODE, &no_neighbor_advertise_map_cmd); + install_element(BGP_VPNV4_NODE, &neighbor_advertise_map_cmd); + install_element(BGP_VPNV4_NODE, &no_neighbor_advertise_map_cmd); + install_element(BGP_VPNV6_NODE, &neighbor_advertise_map_cmd); + install_element(BGP_VPNV6_NODE, &no_neighbor_advertise_map_cmd); + /* neighbor maximum-prefix-out commands. */ install_element(BGP_NODE, &neighbor_maximum_prefix_out_cmd); install_element(BGP_NODE, &no_neighbor_maximum_prefix_out_cmd); diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index be3322e468..7fbad67e93 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -54,6 +54,7 @@ #include "bgpd/bgp_debug.h" #include "bgpd/bgp_errors.h" #include "bgpd/bgp_community.h" +#include "bgpd/bgp_conditional_adv.h" #include "bgpd/bgp_attr.h" #include "bgpd/bgp_regex.h" #include "bgpd/bgp_clist.h" @@ -6585,6 +6586,192 @@ int peer_unsuppress_map_unset(struct peer *peer, afi_t afi, safi_t safi) return 0; } +/* Set advertise-map to the peer but do not process peer route updates here. * + * Hold filter changes until the conditional routes polling thread is called * + * AS we need to advertise/withdraw prefixes (in advertise-map) based on the * + * condition (exist-map/non-exist-map) and routes(specified in condition-map) * + * in BGP table. So do not call peer_on_policy_change() here, only create * + * polling timer thread, update filters and increment condition_filter_count. + */ +int peer_advertise_map_set(struct peer *peer, afi_t afi, safi_t safi, + const char *advertise_name, + struct route_map *advertise_map, bool condition, + const char *condition_name, + struct route_map *condition_map) +{ + bool filter_exists = false; + struct peer *member; + struct bgp_filter *filter; + struct listnode *node, *nnode; + + /* Set configuration on peer. */ + filter = &peer->filter[afi][safi]; + + if (filter->advmap.aname) { + /* advertise-map filter is already configured on this peer */ + filter_exists = true; + + XFREE(MTYPE_BGP_FILTER_NAME, filter->advmap.aname); + XFREE(MTYPE_BGP_FILTER_NAME, filter->advmap.cname); + filter->advmap.condition = CONDITION_NON_EXIST; + } + + route_map_counter_decrement(filter->advmap.amap); + filter->advmap.aname = XSTRDUP(MTYPE_BGP_FILTER_NAME, advertise_name); + filter->advmap.cname = XSTRDUP(MTYPE_BGP_FILTER_NAME, condition_name); + filter->advmap.amap = advertise_map; + filter->advmap.cmap = condition_map; + filter->advmap.condition = condition; + route_map_counter_increment(advertise_map); + peer->advmap_info[afi][safi].config_change = true; + + /* Check if handling a regular peer. */ + if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { + /* Set override-flag and process peer route updates. */ + SET_FLAG(peer->filter_override[afi][safi][RMAP_OUT], + PEER_FT_ADVERTISE_MAP); + + /* Hold peer_on_policy_change() until timer thread is called */ + + /* To increment condition_filter_count and/or create timer */ + if (!filter_exists) { + filter->advmap.status = true; + bgp_conditional_adv_enable(peer, afi, safi); + } + /* Skip peer-group mechanics for regular peers. */ + return 0; + } + + /* + * Set configuration on all peer-group members, unless they are + * explicitely overriding peer-group configuration. + */ + for (ALL_LIST_ELEMENTS(peer->group->peer, node, nnode, member)) { + /* Skip peers with overridden configuration. */ + if (CHECK_FLAG(member->filter_override[afi][safi][RMAP_OUT], + PEER_FT_ADVERTISE_MAP)) + continue; + + /* Set configuration on peer-group member. */ + filter = &member->filter[afi][safi]; + if (filter->advmap.aname) { + /* advertise-map filter is already configured. */ + filter_exists = true; + XFREE(MTYPE_BGP_FILTER_NAME, filter->advmap.aname); + XFREE(MTYPE_BGP_FILTER_NAME, filter->advmap.cname); + filter->advmap.condition = CONDITION_NON_EXIST; + } + route_map_counter_decrement(filter->advmap.amap); + filter->advmap.aname = + XSTRDUP(MTYPE_BGP_FILTER_NAME, advertise_name); + filter->advmap.amap = advertise_map; + filter->advmap.cname = + XSTRDUP(MTYPE_BGP_FILTER_NAME, condition_name); + filter->advmap.cmap = condition_map; + filter->advmap.condition = condition; + route_map_counter_increment(advertise_map); + + /* Hold peer_on_policy_change() until timer thread is called */ + + /* increment condition_filter_count, create timer if 1st one */ + if (!filter_exists) { + filter->advmap.status = true; + bgp_conditional_adv_enable(member, afi, safi); + } + } + + return 0; +} + +/* Unset advertise-map from the peer. */ +int peer_advertise_map_unset(struct peer *peer, afi_t afi, safi_t safi, + const char *advertise_name, + struct route_map *advertise_map, bool condition, + const char *condition_name, + struct route_map *condition_map) +{ + bool filter_exists = false; + struct peer *member; + struct bgp_filter *filter; + struct listnode *node, *nnode; + + /* Unset override-flag unconditionally. */ + UNSET_FLAG(peer->filter_override[afi][safi][RMAP_OUT], + PEER_FT_ADVERTISE_MAP); + + /* Inherit configuration from peer-group if peer is member. */ + if (peer_group_active(peer)) { + PEER_STR_ATTR_INHERIT(peer, peer->group, + filter[afi][safi].advmap.aname, + MTYPE_BGP_FILTER_NAME); + PEER_ATTR_INHERIT(peer, peer->group, + filter[afi][safi].advmap.amap); + } else { + /* Otherwise remove configuration from peer. */ + filter = &peer->filter[afi][safi]; + if (filter->advmap.aname) { + /* advertise-map filter is already configured. */ + filter_exists = true; + XFREE(MTYPE_BGP_FILTER_NAME, filter->advmap.aname); + XFREE(MTYPE_BGP_FILTER_NAME, filter->advmap.cname); + } + route_map_counter_decrement(filter->advmap.amap); + filter->advmap.aname = NULL; + filter->advmap.amap = NULL; + filter->advmap.cname = NULL; + filter->advmap.cmap = NULL; + filter->advmap.condition = CONDITION_NON_EXIST; + } + + /* Check if handling a regular peer. */ + if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { + /* Process peer route updates. */ + peer_on_policy_change(peer, afi, safi, 1); + + /* decrement condition_filter_count delete timer if last one */ + if (filter_exists) + bgp_conditional_adv_disable(peer, afi, safi); + + /* Skip peer-group mechanics for regular peers. */ + return 0; + } + + /* + * Remove configuration on all peer-group members, unless they are + * explicitely overriding peer-group configuration. + */ + for (ALL_LIST_ELEMENTS(peer->group->peer, node, nnode, member)) { + /* Skip peers with overridden configuration. */ + if (CHECK_FLAG(member->filter_override[afi][safi][RMAP_OUT], + PEER_FT_ADVERTISE_MAP)) + continue; + + /* Remove configuration on peer-group member. */ + filter = &member->filter[afi][safi]; + if (filter->advmap.aname) { + /* advertise-map filter is already configured. */ + filter_exists = true; + XFREE(MTYPE_BGP_FILTER_NAME, filter->advmap.aname); + XFREE(MTYPE_BGP_FILTER_NAME, filter->advmap.cname); + } + route_map_counter_decrement(filter->advmap.amap); + filter->advmap.aname = NULL; + filter->advmap.amap = NULL; + filter->advmap.cname = NULL; + filter->advmap.cmap = NULL; + filter->advmap.condition = CONDITION_NON_EXIST; + + /* decrement condition_filter_count delete timer if last one */ + if (filter_exists) + bgp_conditional_adv_disable(peer, afi, safi); + + /* Process peer route updates. */ + peer_on_policy_change(member, afi, safi, 1); + } + + return 0; +} + int peer_maximum_prefix_set(struct peer *peer, afi_t afi, safi_t safi, uint32_t max, uint8_t threshold, int warning, uint16_t restart, bool force) diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index eae3d97730..293583460f 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -681,6 +681,10 @@ struct bgp { /* Process Queue for handling routes */ struct work_queue *process_queue; + + /* BGP Conditional advertisement */ + int condition_filter_count; + struct thread *t_condition_check; QOBJ_FIELDS }; @@ -759,6 +763,10 @@ struct bgp_nexthop { #define BGP_GTSM_HOPS_DISABLED 0 #define BGP_GTSM_HOPS_CONNECTED 1 +/* Advertise map */ +#define CONDITION_NON_EXIST 0 +#define CONDITION_EXIST 1 + #include "filter.h" /* BGP filter structure. */ @@ -792,6 +800,19 @@ struct bgp_filter { char *name; struct route_map *map; } usmap; + + /* Advertise-map */ + struct { + char *aname; + struct route_map *amap; + + bool condition; + + char *cname; + struct route_map *cmap; + + bool status; + } advmap; }; /* IBGP/EBGP identifier. We also have a CONFED peer, which is to say, @@ -1355,6 +1376,7 @@ struct peer { #define PEER_FT_PREFIX_LIST (1U << 2) /* prefix-list */ #define PEER_FT_ROUTE_MAP (1U << 3) /* route-map */ #define PEER_FT_UNSUPPRESS_MAP (1U << 4) /* unsuppress-map */ +#define PEER_FT_ADVERTISE_MAP (1U << 5) /* advertise-map */ /* ORF Prefix-list */ struct prefix_list *orf_plist[AFI_MAX][SAFI_MAX]; @@ -1448,6 +1470,13 @@ struct peer { /* Sender side AS path loop detection. */ bool as_path_loop_detection; + /* Conditional advertisement */ + struct { + bool config_change; + enum route_map_cmd_result_t amap_prev_status; + enum route_map_cmd_result_t cmap_prev_status; + } advmap_info[AFI_MAX][SAFI_MAX]; + QOBJ_FIELDS }; DECLARE_QOBJ_TYPE(peer) @@ -1939,11 +1968,23 @@ extern int peer_unsuppress_map_set(struct peer *peer, afi_t afi, safi_t safi, const char *name, struct route_map *route_map); +extern int peer_advertise_map_set(struct peer *peer, afi_t afi, safi_t safi, + const char *advertise_name, + struct route_map *advertise_map, + bool condition, const char *condition_name, + struct route_map *condition_map); + extern int peer_password_set(struct peer *, const char *); extern int peer_password_unset(struct peer *); extern int peer_unsuppress_map_unset(struct peer *, afi_t, safi_t); +extern int peer_advertise_map_unset(struct peer *peer, afi_t afi, safi_t safi, + const char *advertise_name, + struct route_map *advertise_map, + bool condition, const char *condition_name, + struct route_map *condition_map); + extern int peer_maximum_prefix_set(struct peer *, afi_t, safi_t, uint32_t, uint8_t, int, uint16_t, bool force); extern int peer_maximum_prefix_unset(struct peer *, afi_t, safi_t); diff --git a/bgpd/subdir.am b/bgpd/subdir.am index 3cb32b1f08..ea60b921d1 100644 --- a/bgpd/subdir.am +++ b/bgpd/subdir.am @@ -61,6 +61,7 @@ bgpd_libbgp_a_SOURCES = \ bgpd/bgp_bfd.c \ bgpd/bgp_clist.c \ bgpd/bgp_community.c \ + bgpd/bgp_conditional_adv.c \ bgpd/bgp_damp.c \ bgpd/bgp_debug.c \ bgpd/bgp_dump.c \ @@ -137,6 +138,7 @@ noinst_HEADERS += \ bgpd/bgp_bfd.h \ bgpd/bgp_clist.h \ bgpd/bgp_community.h \ + bgpd/bgp_conditional_adv.h \ bgpd/bgp_damp.h \ bgpd/bgp_debug.h \ bgpd/bgp_dump.h \ diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst index 79e5afde7c..f79d33a260 100644 --- a/doc/user/bgp.rst +++ b/doc/user/bgp.rst @@ -2595,6 +2595,182 @@ This makes it possible to separate not only layer 3 networks like VRF-lite netwo Also, VRF netns based make possible to separate layer 2 networks on separate VRF instances. +.. _bgp-conditional-advertisement: + +BGP Conditional Advertisement +----------------------------- +The BGP conditional advertisement feature uses the ``non-exist-map`` or the +``exist-map`` and the ``advertise-map`` keywords of the neighbor advertise-map +command in order to track routes by the route prefix. + +``non-exist-map`` + 1. If a route prefix is not present in the output of non-exist-map command, + then advertise the route specified by the advertise-map command. + + 2. If a route prefix is present in the output of non-exist-map command, + then do not advertise the route specified by the addvertise-map command. + +``exist-map`` + 1. If a route prefix is present in the output of exist-map command, + then advertise the route specified by the advertise-map command. + + 2. If a route prefix is not present in the output of exist-map command, + then do not advertise the route specified by the advertise-map command. + +This feature is useful when some prefixes are advertised to one of its peers +only if the information from the other peer is not present (due to failure in +peering session or partial reachability etc). + +The conditional BGP announcements are sent in addition to the normal +announcements that a BGP router sends to its peer. + +The conditional advertisement process is triggered by the BGP scanner process, +which runs every 60 seconds. This means that the maximum time for the conditional +advertisement to take effect is 60 seconds. The conditional advertisement can take +effect depending on when the tracked route is removed from the BGP table and +when the next instance of the BGP scanner occurs. + +.. index:: [no] neighbor A.B.C.D advertise-map NAME [exist-map|non-exist-map] NAME +.. clicmd:: [no] neighbor A.B.C.D advertise-map NAME [exist-map|non-exist-map] NAME + + This command enables BGP scanner process to monitor route specified by + exist-map or non-exist-map command in BGP table and conditionally advertises + the route specified by advertise-map command. + +Sample Configuration +^^^^^^^^^^^^^^^^^^^^^ +.. code-block:: frr + + interface lo + ip address 2.2.2.2/24 + ! + router bgp 2 + bgp log-neighbor-changes + no bgp ebgp-requires-policy + neighbor 10.10.10.1 remote-as 1 + neighbor 10.10.20.3 remote-as 3 + ! + address-family ipv4 unicast + network 2.2.2.0/24 + network 20.20.0.0/16 + neighbor 10.10.10.1 soft-reconfiguration inbound + neighbor 10.10.10.1 advertise-map ADVERTISE non-exist-map CONDITION + neighbor 10.10.20.3 soft-reconfiguration inbound + exit-address-family + ! + access-list CONDITION seq 5 permit 3.3.3.0/24 + access-list ADVERTISE seq 5 permit 2.2.2.0/24 + ! + route-map ADVERTISE permit 10 + match ip address ADVERTISE + ! + route-map CONDITION permit 10 + match ip address CONDITION + ! + +Sample Output +^^^^^^^^^^^^^ + +When 3.3.3.0/24 route is in R2'2 BGP rable, 2.2.2/0/24 is not adevrtised to R1. + +.. code-block:: frr + + Router2# show ip bgp + BGP table version is 24, local router ID is 128.16.16.1, vrf id 0 + Default local pref 100, local AS 2 + Status codes: s suppressed, d damped, h history, * valid, > best, = multipath, + i internal, r RIB-failure, S Stale, R Removed + Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self + Origin codes: i - IGP, e - EGP, ? - incomplete + + Network Next Hop Metric LocPrf Weight Path + *> 1.1.1.0/24 10.10.10.1 0 0 1 i + *> 2.2.2.0/24 0.0.0.0 0 32768 i + *> 3.3.3.0/24 10.10.20.3 0 0 3 i + *> 20.20.0.0/16 0.0.0.0 0 32768 i + + Displayed 4 routes and 4 total paths + Router2# + + Router2# show ip bgp neighbors 10.10.10.1 + + !--- Output suppressed. + + For address family: IPv4 Unicast + Update group 5, subgroup 1 + Packet Queue length 0 + Inbound soft reconfiguration allowed + Community attribute sent to this neighbor(all) + Condition NON_EXIST, Condition-map *CONDITION, Advertise-map *ADVERTISE, status: Withdraw + 1 accepted prefixes + + !--- Output suppressed. + + Router2# show ip bgp neighbors 10.10.10.1 advertised-routes + BGP table version is 24, local router ID is 128.16.16.1, vrf id 0 + Default local pref 100, local AS 2 + Status codes: s suppressed, d damped, h history, * valid, > best, = multipath, + i internal, r RIB-failure, S Stale, R Removed + Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self + Origin codes: i - IGP, e - EGP, ? - incomplete + + Network Next Hop Metric LocPrf Weight Path + *> 1.1.1.0/24 0.0.0.0 0 1 i + *> 3.3.3.0/24 0.0.0.0 0 3 i + *> 20.20.0.0/16 0.0.0.0 0 32768 i + + Total number of prefixes 3 + Router2# + +When 3.3.3.0/24 route is not in R2'2 BGP rable, 2.2.2/0/24 is adevrtised to R1. + +.. code-block:: frr + + Router2# show ip bgp + BGP table version is 25, local router ID is 128.16.16.1, vrf id 0 + Default local pref 100, local AS 2 + Status codes: s suppressed, d damped, h history, * valid, > best, = multipath, + i internal, r RIB-failure, S Stale, R Removed + Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self + Origin codes: i - IGP, e - EGP, ? - incomplete + + Network Next Hop Metric LocPrf Weight Path + *> 1.1.1.0/24 10.10.10.1 0 0 1 i + *> 2.2.2.0/24 0.0.0.0 0 32768 i + *> 20.20.0.0/16 0.0.0.0 0 32768 i + + Displayed 3 routes and 3 total paths + Router2# + + Router2# show ip bgp neighbors 10.10.10.1 + + !--- Output suppressed. + + For address family: IPv4 Unicast + Update group 5, subgroup 1 + Packet Queue length 0 + Inbound soft reconfiguration allowed + Community attribute sent to this neighbor(all) + Condition NON_EXIST, Condition-map *CONDITION, Advertise-map *ADVERTISE, status: Advertise + 1 accepted prefixes + + !--- Output suppressed. + + Router2# show ip bgp neighbors 10.10.10.1 advertised-routes + BGP table version is 25, local router ID is 128.16.16.1, vrf id 0 + Default local pref 100, local AS 2 + Status codes: s suppressed, d damped, h history, * valid, > best, = multipath, + i internal, r RIB-failure, S Stale, R Removed + Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self + Origin codes: i - IGP, e - EGP, ? - incomplete + + Network Next Hop Metric LocPrf Weight Path + *> 1.1.1.0/24 0.0.0.0 0 1 i + *> 2.2.2.0/24 0.0.0.0 0 32768 i + *> 20.20.0.0/16 0.0.0.0 0 32768 i + + Total number of prefixes 3 + .. _bgp-debugging: Debugging From c5aec50b81afbd19b554838bc42401ed7b40fbb9 Mon Sep 17 00:00:00 2001 From: Madhuri Kuruganti Date: Fri, 2 Oct 2020 02:10:48 +0530 Subject: [PATCH 2/8] bgpd: conditional advertisement - with route-map filter Sample configuration along with route-map filter ------------------------------------------------ Router2# show running-config Building configuration... Current configuration: ! frr version 7.6-dev-MyOwnFRRVersion frr defaults traditional hostname router log file /var/log/frr/bgpd.log log syslog informational hostname Router2 service integrated-vtysh-config ! debug bgp updates in debug bgp updates out ! debug route-map ! ip route 200.200.0.0/16 blackhole ipv6 route 2001:db8::200/128 blackhole ! interface enp0s9 ip address 10.10.10.2/24 ! interface enp0s10 ip address 10.10.20.2/24 ! interface lo ip address 2.2.2.2/24 ipv6 address 2001:db8::2/128 ! router bgp 2 bgp log-neighbor-changes no bgp ebgp-requires-policy neighbor 10.10.10.1 remote-as 1 neighbor 10.10.20.3 remote-as 3 ! address-family ipv4 unicast network 2.2.2.0/24 network 200.200.0.0/16 neighbor 10.10.10.1 soft-reconfiguration inbound neighbor 10.10.10.1 route-map RMAP_PERMIT_100 out neighbor 10.10.10.1 advertise-map ADVERTISE non-exist-map CONDITION neighbor 10.10.20.3 soft-reconfiguration inbound exit-address-family ! address-family ipv6 unicast network 2001:db8::2/128 network 2001:db8::200/128 neighbor 10.10.10.1 activate neighbor 10.10.10.1 soft-reconfiguration inbound neighbor 10.10.10.1 route-map CONDITION_6 out neighbor 10.10.10.1 advertise-map ADVERTISE_6 non-exist-map CONDITION_6 neighbor 10.10.20.3 activate neighbor 10.10.20.3 soft-reconfiguration inbound exit-address-family ! access-list CONDITION seq 5 permit 3.3.3.0/24 access-list ADVERTISE seq 6 permit 200.200.0.0/16 access-list ADVERTISE seq 7 permit 20.20.0.0/16 access-list ADVERTISE seq 5 permit 2.2.2.0/24 access-list RMAP_PERMIT_100 seq 4 permit 100.100.0.0/16 ! ipv6 access-list ADVERTISE_6 seq 5 permit 2001:db8::2/128 ipv6 access-list CONDITION_6 seq 5 permit 2001:db8::3/128 ! route-map ADVERTISE permit 10 match ip address ADVERTISE ! route-map CONDITION permit 10 match ip address CONDITION ! route-map ADVERTISE_6 permit 10 match ipv6 address ADVERTISE_6 ! route-map CONDITION_6 permit 10 match ipv6 address CONDITION_6 ! route-map RMAP_PERMIT_100 permit 10 match ip address RMAP_PERMIT_100 ! line vty ! end Sample output when non-exist-map prefixes present in BGP table -------------------------------------------------------------- Router2# show ip bgp all wide For address family: IPv4 Unicast BGP table version is 5, local router ID is 2.2.2.2, vrf id 0 Default local pref 100, local AS 2 Status codes: s suppressed, d damped, h history, * valid, > best, = multipath, i internal, r RIB-failure, S Stale, R Removed Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self Origin codes: i - IGP, e - EGP, ? - incomplete Network Next Hop Metric LocPrf Weight Path *> 1.1.1.0/24 10.10.10.1 0 0 1 i *> 2.2.2.0/24 0.0.0.0 0 32768 i *> 3.3.3.0/24 10.10.20.3 0 0 3 i *> 100.100.0.0/16 10.10.20.3 0 0 3 i *> 200.200.0.0/16 0.0.0.0 0 32768 i Displayed 5 routes and 5 total paths For address family: IPv6 Unicast BGP table version is 4, local router ID is 2.2.2.2, vrf id 0 Default local pref 100, local AS 2 Status codes: s suppressed, d damped, h history, * valid, > best, = multipath, i internal, r RIB-failure, S Stale, R Removed Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self Origin codes: i - IGP, e - EGP, ? - incomplete Network Next Hop Metric LocPrf Weight Path *> 2001:db8::1/128 fe80::a00:27ff:fecb:ad57 0 0 1 i *> 2001:db8::2/128 :: 0 32768 i *> 2001:db8::3/128 fe80::a00:27ff:fe76:6738 0 0 3 i *> 2001:db8::200/128 :: 0 32768 i Displayed 4 routes and 4 total paths Router2# Router2# Router2# Router2# Router2# show ip bgp all neighbors 10.10.10.1 advertised-routes wide For address family: IPv4 Unicast BGP table version is 5, local router ID is 2.2.2.2, vrf id 0 Default local pref 100, local AS 2 Status codes: s suppressed, d damped, h history, * valid, > best, = multipath, i internal, r RIB-failure, S Stale, R Removed Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self Origin codes: i - IGP, e - EGP, ? - incomplete Network Next Hop Metric LocPrf Weight Path *> 100.100.0.0/16 0.0.0.0 0 3 i Total number of prefixes 1 For address family: IPv6 Unicast BGP table version is 4, local router ID is 2.2.2.2, vrf id 0 Default local pref 100, local AS 2 Status codes: s suppressed, d damped, h history, * valid, > best, = multipath, i internal, r RIB-failure, S Stale, R Removed Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self Origin codes: i - IGP, e - EGP, ? - incomplete Network Next Hop Metric LocPrf Weight Path *> 2001:db8::3/128 :: 0 3 i Total number of prefixes 1 Router2# Sample output when non-exist-map prefixes not present in BGP table ------------------------------------------------------------------ Router2# show ip bgp all wide For address family: IPv4 Unicast BGP table version is 6, local router ID is 2.2.2.2, vrf id 0 Default local pref 100, local AS 2 Status codes: s suppressed, d damped, h history, * valid, > best, = multipath, i internal, r RIB-failure, S Stale, R Removed Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self Origin codes: i - IGP, e - EGP, ? - incomplete Network Next Hop Metric LocPrf Weight Path *> 1.1.1.0/24 10.10.10.1 0 0 1 i *> 2.2.2.0/24 0.0.0.0 0 32768 i *> 100.100.0.0/16 10.10.20.3 0 0 3 i *> 200.200.0.0/16 0.0.0.0 0 32768 i Displayed 4 routes and 4 total paths For address family: IPv6 Unicast BGP table version is 5, local router ID is 2.2.2.2, vrf id 0 Default local pref 100, local AS 2 Status codes: s suppressed, d damped, h history, * valid, > best, = multipath, i internal, r RIB-failure, S Stale, R Removed Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self Origin codes: i - IGP, e - EGP, ? - incomplete Network Next Hop Metric LocPrf Weight Path *> 2001:db8::1/128 fe80::a00:27ff:fecb:ad57 0 0 1 i *> 2001:db8::2/128 :: 0 32768 i *> 2001:db8::200/128 :: 0 32768 i Displayed 3 routes and 3 total paths Router2# Router2# show ip bgp all neighbors 10.10.10.1 advertised-routes wide For address family: IPv4 Unicast BGP table version is 6, local router ID is 2.2.2.2, vrf id 0 Default local pref 100, local AS 2 Status codes: s suppressed, d damped, h history, * valid, > best, = multipath, i internal, r RIB-failure, S Stale, R Removed Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self Origin codes: i - IGP, e - EGP, ? - incomplete Network Next Hop Metric LocPrf Weight Path *> 2.2.2.0/24 0.0.0.0 0 32768 i *> 100.100.0.0/16 0.0.0.0 0 3 i *> 200.200.0.0/16 0.0.0.0 0 32768 i Total number of prefixes 3 For address family: IPv6 Unicast BGP table version is 5, local router ID is 2.2.2.2, vrf id 0 Default local pref 100, local AS 2 Status codes: s suppressed, d damped, h history, * valid, > best, = multipath, i internal, r RIB-failure, S Stale, R Removed Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self Origin codes: i - IGP, e - EGP, ? - incomplete Network Next Hop Metric LocPrf Weight Path *> 2001:db8::2/128 :: 0 32768 i Total number of prefixes 1 Router2# Signed-off-by: Madhuri Kuruganti --- bgpd/bgp_conditional_adv.c | 63 +++++++++----------------------------- bgpd/bgp_route.c | 4 +++ bgpd/bgp_routemap.c | 5 +-- 3 files changed, 22 insertions(+), 50 deletions(-) diff --git a/bgpd/bgp_conditional_adv.c b/bgpd/bgp_conditional_adv.c index f38ef902ea..f601e7a795 100644 --- a/bgpd/bgp_conditional_adv.c +++ b/bgpd/bgp_conditional_adv.c @@ -232,7 +232,6 @@ static int bgp_conditional_adv_timer(struct thread *t) struct update_subgroup *subgrp = NULL; enum route_map_cmd_result_t ret, prev_ret; bool route_advertised = false; - bool adv_withdrawn = false; int adv_conditional = 0; bgp = THREAD_ARG(t); @@ -278,7 +277,6 @@ static int bgp_conditional_adv_timer(struct thread *t) /* cmap (route-map attached to exist-map or * non-exist-map) map validation */ - adv_withdrawn = false; adv_conditional = 0; ret = bgp_check_rmap_prefixes_in_bgp_table(table, @@ -288,41 +286,25 @@ static int bgp_conditional_adv_timer(struct thread *t) switch (ret) { case RMAP_NOOP: - if (prev_ret == RMAP_NOOP) + if (prev_ret == RMAP_NOOP) { + peer->advmap_info[afi][safi] + .config_change = false; continue; - + } peer->advmap_info[afi][safi].cmap_prev_status = ret; - if (filter->advmap.status) - continue; - /* advertise previously withdrawn routes */ - adv_withdrawn = true; break; case RMAP_MATCH: /* Handle configuration changes */ if (peer->advmap_info[afi][safi] .config_change) { - /* If configuration(ACL filetr prefixes) - * is changed and if the advertise-map - * filter previous status was withdraw - * then we need to advertise the - * previously withdrawn routes. - * Nothing to do if the filter status - * was advertise. - */ - if ((prev_ret != RMAP_NOOP) - && !filter->advmap.status) - adv_withdrawn = true; - adv_conditional = (filter->advmap.condition == CONDITION_EXIST) ? NLRI : WITHDRAW; - peer->advmap_info[afi][safi] - .config_change = false; } else { if (prev_ret != RMAP_MATCH) adv_conditional = @@ -340,25 +322,11 @@ static int bgp_conditional_adv_timer(struct thread *t) /* Handle configuration changes */ if (peer->advmap_info[afi][safi] .config_change) { - /* If configuration(ACL filetr prefixes) - * is changed and if the advertise-map - * filter previous status was withdraw - * then we need to advertise the - * previously withdrawn routes. - * Nothing to do if the filter status - * was advertise. - */ - if ((prev_ret != RMAP_NOOP) - && !filter->advmap.status) - adv_withdrawn = true; - adv_conditional = (filter->advmap.condition == CONDITION_EXIST) ? WITHDRAW : NLRI; - peer->advmap_info[afi][safi] - .config_change = false; } else { if (prev_ret != RMAP_NOMATCH) adv_conditional = @@ -383,18 +351,9 @@ static int bgp_conditional_adv_timer(struct thread *t) */ ret = is_rmap_valid(filter->advmap.amap) ? RMAP_MATCH : RMAP_NOOP; - prev_ret = - peer->advmap_info[afi][safi].amap_prev_status; - if (ret == RMAP_NOOP) { - if (prev_ret == RMAP_NOOP) { - if (!adv_withdrawn) - continue; - /* Should not reach here. */ - } - if (filter->advmap.status && !adv_withdrawn) - continue; - } + if ((ret == RMAP_NOOP) && (prev_ret == RMAP_NOOP)) + continue; /* Derive conditional advertisement status from * condition and return value of condition-map @@ -411,7 +370,11 @@ static int bgp_conditional_adv_timer(struct thread *t) */ } - if (adv_withdrawn) { + /* Send regular update as per the existing policy. + * There is a change in route-map, match-rule, ACLs, + * or route-map filter configuration on the same peer. + */ + if (peer->advmap_info[afi][safi].config_change) { paf = peer_af_find(peer, afi, safi); if (paf) { update_subgroup_split_peer(paf, NULL); @@ -420,7 +383,11 @@ static int bgp_conditional_adv_timer(struct thread *t) subgroup_announce_table( paf->subgroup, NULL); } + peer->advmap_info[afi][safi].config_change = + false; } + + /* Send update as per the conditional advertisement */ if (adv_conditional) { route_advertised = bgp_conditional_adv_routes( peer, afi, safi, table, diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index e64cf4a541..48f38dfec7 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -4361,6 +4361,10 @@ static int bgp_announce_route_timer_expired(struct thread *t) return 0; peer_af_announce_route(paf, 1); + + /* Notify BGP conditional advertisement scanner percess */ + peer->advmap_info[paf->afi][paf->safi].config_change = true; + return 0; } diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index c8504cfc8f..2abebbcbc3 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -3698,18 +3698,19 @@ static void bgp_route_map_process_peer(const char *rmap_name, if (filter->advmap.aname && (strcmp(rmap_name, filter->advmap.aname) == 0)) { filter->advmap.amap = map; - peer->advmap_info[afi][safi].config_change = true; } if (filter->advmap.cname && (strcmp(rmap_name, filter->advmap.cname) == 0)) { filter->advmap.cmap = map; - peer->advmap_info[afi][safi].config_change = true; } if (peer->default_rmap[afi][safi].name && (strcmp(rmap_name, peer->default_rmap[afi][safi].name) == 0)) peer->default_rmap[afi][safi].map = map; + + /* Notify BGP conditional advertisement scanner percess */ + peer->advmap_info[afi][safi].config_change = true; } static void bgp_route_map_update_peer_group(const char *rmap_name, From c385f82af3dd9ad84b842b79c5fe83616c2507bd Mon Sep 17 00:00:00 2001 From: Madhuri Kuruganti Date: Mon, 5 Oct 2020 23:10:56 +0530 Subject: [PATCH 3/8] bgpd: conditional advertisement - other match rules support Sample Configuration with prefix-list and community match rules --------------------------------------------------------------- R1 ------- R2(DUT) ------- R3 Router2# show running-config Building configuration... Current configuration: ! frr version 7.6-dev-MyOwnFRRVersion frr defaults traditional hostname router log file /var/log/frr/bgpd.log log syslog informational hostname Router2 service integrated-vtysh-config ! debug bgp updates in debug bgp updates out ! debug route-map ! ip route 20.20.0.0/16 blackhole ipv6 route 2001:db8::200/128 blackhole ! interface enp0s9 ip address 10.10.10.2/24 ! interface enp0s10 ip address 10.10.20.2/24 ! interface lo ip address 2.2.2.2/32 ! router bgp 2 bgp log-neighbor-changes no bgp ebgp-requires-policy neighbor 10.10.10.1 remote-as 1 neighbor 10.10.20.3 remote-as 3 ! address-family ipv4 unicast neighbor 10.10.10.1 soft-reconfiguration inbound neighbor 10.10.20.3 soft-reconfiguration inbound neighbor 10.10.20.3 advertise-map ADV-MAP non-exist-map EXIST-MAP exit-address-family ! ip prefix-list DEFAULT seq 5 permit 1.1.1.5/32 ip prefix-list DEFAULT seq 10 permit 1.1.1.1/32 ip prefix-list EXIST seq 5 permit 10.10.10.10/32 ip prefix-list DEFAULT-ROUTE seq 5 permit 0.0.0.0/0 ip prefix-list IP1 seq 5 permit 10.139.224.0/20 ip prefix-list T2 seq 5 permit 1.1.1.5/32 ! bgp community-list standard DC-ROUTES seq 5 permit 64952:3008 bgp community-list standard DC-ROUTES seq 10 permit 64671:501 bgp community-list standard DC-ROUTES seq 15 permit 64950:3009 bgp community-list standard DEFAULT-ROUTE seq 5 permit 65013:200 ! route-map ADV-MAP permit 10 match ip address prefix-list IP1 ! route-map ADV-MAP permit 20 match community DC-ROUTES ! route-map EXIST-MAP permit 10 match community DEFAULT-ROUTE match ip address prefix-list DEFAULT-ROUTE ! line vty ! end Router2# Router2# show ip bgp 0.0.0.0 BGP routing table entry for 0.0.0.0/0 Paths: (1 available, best #1, table default) Advertised to non peer-group peers: 10.10.10.1 10.10.20.3 1 10.10.10.1 from 10.10.10.1 (10.139.224.1) Origin IGP, metric 0, valid, external, best (First path received) Community: 64848:3011 65011:200 65013:200 Last update: Tue Oct 6 02:39:42 2020 Router2# Sample output with non-exist-map when default route present in table -------------------------------------------------------------------- Router2# show ip bgp BGP table version is 4, local router ID is 2.2.2.2, vrf id 0 Default local pref 100, local AS 2 Status codes: s suppressed, d damped, h history, * valid, > best, = multipath, i internal, r RIB-failure, S Stale, R Removed Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self Origin codes: i - IGP, e - EGP, ? - incomplete Network Next Hop Metric LocPrf Weight Path *> 0.0.0.0/0 10.10.10.1 0 0 1 i *> 1.1.1.1/32 10.10.10.1 0 0 1 i *> 1.1.1.5/32 10.10.10.1 0 0 1 i *> 10.139.224.0/20 10.10.10.1 0 0 1 ? Displayed 4 routes and 4 total paths Router2# show ip bgp neighbors 10.10.20.3 advertised-routes BGP table version is 4, local router ID is 2.2.2.2, vrf id 0 Default local pref 100, local AS 2 Status codes: s suppressed, d damped, h history, * valid, > best, = multipath, i internal, r RIB-failure, S Stale, R Removed Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self Origin codes: i - IGP, e - EGP, ? - incomplete Network Next Hop Metric LocPrf Weight Path *> 0.0.0.0/0 0.0.0.0 0 1 i *> 1.1.1.5/32 0.0.0.0 0 1 i <<<<<<<<< non-exist-map : 0.0.0.0/0 is present so, 10.139.224.0/20 not advertised Total number of prefixes 2 Sample output with non-exist-map when default route not present in table ------------------------------------------------------------------------ Router2# show ip bgp BGP table version is 5, local router ID is 2.2.2.2, vrf id 0 Default local pref 100, local AS 2 Status codes: s suppressed, d damped, h history, * valid, > best, = multipath, i internal, r RIB-failure, S Stale, R Removed Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self Origin codes: i - IGP, e - EGP, ? - incomplete Network Next Hop Metric LocPrf Weight Path *> 1.1.1.1/32 10.10.10.1 0 0 1 i *> 1.1.1.5/32 10.10.10.1 0 0 1 i *> 10.139.224.0/20 10.10.10.1 0 0 1 ? Displayed 3 routes and 3 total paths Router2# Router2# Router2# show ip bgp neighbors 10.10.20.3 advertised-routes BGP table version is 5, local router ID is 2.2.2.2, vrf id 0 Default local pref 100, local AS 2 Status codes: s suppressed, d damped, h history, * valid, > best, = multipath, i internal, r RIB-failure, S Stale, R Removed Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self Origin codes: i - IGP, e - EGP, ? - incomplete Network Next Hop Metric LocPrf Weight Path *> 1.1.1.1/32 0.0.0.0 0 1 i *> 1.1.1.5/32 0.0.0.0 0 1 i *> 10.139.224.0/20 0.0.0.0 0 1 ? <<<<<<<<< non-exist-map : 0.0.0.0/0 is not present so, 10.139.224.0/20 advertised Total number of prefixes 3 Router2# Sample output with exist-map when default route present in table -------------------------------------------------------------------- Router2# show ip bgp BGP table version is 8, local router ID is 2.2.2.2, vrf id 0 Default local pref 100, local AS 2 Status codes: s suppressed, d damped, h history, * valid, > best, = multipath, i internal, r RIB-failure, S Stale, R Removed Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self Origin codes: i - IGP, e - EGP, ? - incomplete Network Next Hop Metric LocPrf Weight Path *> 0.0.0.0/0 10.10.10.1 0 0 1 i *> 1.1.1.1/32 10.10.10.1 0 0 1 i *> 1.1.1.5/32 10.10.10.1 0 0 1 i *> 10.139.224.0/20 10.10.10.1 0 0 1 ? Displayed 4 routes and 4 total paths Router2# Router2# Router2# Router2# Router2# show ip bgp neighbors 10.10.20.3 advertised-routes BGP table version is 8, local router ID is 2.2.2.2, vrf id 0 Default local pref 100, local AS 2 Status codes: s suppressed, d damped, h history, * valid, > best, = multipath, i internal, r RIB-failure, S Stale, R Removed Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self Origin codes: i - IGP, e - EGP, ? - incomplete Network Next Hop Metric LocPrf Weight Path *> 0.0.0.0/0 0.0.0.0 0 1 i *> 1.1.1.1/32 0.0.0.0 0 1 i *> 1.1.1.5/32 0.0.0.0 0 1 i *> 10.139.224.0/20 0.0.0.0 0 1 ? <<<<<<<<< exist-map : 0.0.0.0/0 is present so, 10.139.224.0/20 advertised Total number of prefixes 4 Router2# Sample output with exist-map when default route not present in table -------------------------------------------------------------------- Router2# show ip bgp BGP table version is 9, local router ID is 2.2.2.2, vrf id 0 Default local pref 100, local AS 2 Status codes: s suppressed, d damped, h history, * valid, > best, = multipath, i internal, r RIB-failure, S Stale, R Removed Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self Origin codes: i - IGP, e - EGP, ? - incomplete Network Next Hop Metric LocPrf Weight Path *> 1.1.1.1/32 10.10.10.1 0 0 1 i *> 1.1.1.5/32 10.10.10.1 0 0 1 i *> 10.139.224.0/20 10.10.10.1 0 0 1 ? Displayed 3 routes and 3 total paths Router2# Router2# Router2# Router2# show ip bgp neighbors 10.10.20.3 advertised-routes BGP table version is 9, local router ID is 2.2.2.2, vrf id 0 Default local pref 100, local AS 2 Status codes: s suppressed, d damped, h history, * valid, > best, = multipath, i internal, r RIB-failure, S Stale, R Removed Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self Origin codes: i - IGP, e - EGP, ? - incomplete Network Next Hop Metric LocPrf Weight Path *> 1.1.1.5/32 0.0.0.0 0 1 i <<<<<<<<< exist-map : 0.0.0.0/0 is not present so, 10.139.224.0/20 not advertised Total number of prefixes 1 Router2# Signed-off-by: Madhuri Kuruganti --- bgpd/bgp_conditional_adv.c | 405 +++++++++++-------------------------- bgpd/bgp_conditional_adv.h | 95 --------- bgpd/bgp_packet.c | 3 + bgpd/bgp_route.c | 23 ++- bgpd/bgp_routemap.c | 2 +- bgpd/bgp_vty.c | 5 +- bgpd/bgpd.c | 18 +- bgpd/bgpd.h | 17 +- 8 files changed, 164 insertions(+), 404 deletions(-) diff --git a/bgpd/bgp_conditional_adv.c b/bgpd/bgp_conditional_adv.c index f601e7a795..999326d9c3 100644 --- a/bgpd/bgp_conditional_adv.c +++ b/bgpd/bgp_conditional_adv.c @@ -22,197 +22,115 @@ const char *get_afi_safi_str(afi_t afi, safi_t safi, bool for_json); -/* We just need bgp_dest node matches with filter prefix. So no need to - * traverse each path here. - */ -struct bgp_dest *bgp_dest_matches_filter_prefix(struct bgp_table *table, - struct filter *filter) -{ - uint32_t check_addr; - uint32_t check_mask; - struct in_addr mask; - struct bgp_dest *dest = NULL; - struct bgp_path_info *pi = NULL; - const struct prefix *dest_p = NULL; - struct filter_cisco *cfilter = NULL; - struct filter_zebra *zfilter = NULL; - - if (filter->cisco) { - cfilter = &filter->u.cfilter; - for (dest = bgp_table_top(table); dest; - dest = bgp_route_next(dest)) { - dest_p = (struct prefix *)bgp_dest_get_prefix(dest); - if (!dest_p) - continue; - pi = bgp_dest_get_bgp_path_info(dest); - if (!pi) - continue; - check_addr = dest_p->u.prefix4.s_addr - & ~cfilter->addr_mask.s_addr; - if (memcmp(&check_addr, &cfilter->addr.s_addr, - sizeof(check_addr)) - != 0) - continue; - if (cfilter->extended) { - masklen2ip(dest_p->prefixlen, &mask); - check_mask = mask.s_addr - & ~cfilter->mask_mask.s_addr; - if (memcmp(&check_mask, &cfilter->mask.s_addr, - sizeof(check_mask)) - != 0) - continue; - } - return dest; - } - } else { - zfilter = &filter->u.zfilter; - for (dest = bgp_table_top(table); dest; - dest = bgp_route_next(dest)) { - dest_p = bgp_dest_get_prefix(dest); - if (!dest_p) - continue; - pi = bgp_dest_get_bgp_path_info(dest); - if (!pi) - continue; - if ((zfilter->prefix.family != dest_p->family) - || (zfilter->exact - && (zfilter->prefix.prefixlen - != dest_p->prefixlen))) - continue; - else if (!prefix_match(&zfilter->prefix, dest_p)) - continue; - else - return dest; - } - } - return NULL; -} - -enum route_map_cmd_result_t +static route_map_result_t bgp_check_rmap_prefixes_in_bgp_table(struct bgp_table *table, struct route_map *rmap) { - afi_t afi; - struct access_list *alist = NULL; - struct filter *alist_filter = NULL; - struct bgp_dest *dest = NULL; - struct route_map_rule *match = NULL; - enum route_map_cmd_result_t ret = RMAP_NOOP; + struct bgp_dest *dest; + struct attr dummy_attr; + struct bgp_path_info path; + const struct prefix *dest_p; + struct bgp_path_info *pi; + route_map_result_t ret = RMAP_PERMITMATCH; - if (!is_rmap_valid(rmap)) - return ret; - - /* If several match commands are configured, all must succeed for a - * given route in order for that route to match the clause (logical AND) - */ - for (match = rmap->head->match_list.head; match; match = match->next) { - - if (!match->cmd || !match->cmd->str || !match->value) + for (dest = bgp_table_top(table); dest; dest = bgp_route_next(dest)) { + dest_p = bgp_dest_get_prefix(dest); + if (!dest_p) continue; - ret = RMAP_NOMATCH; + for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) { + dummy_attr = *pi->attr; + path.peer = pi->peer; + path.attr = &dummy_attr; - afi = get_afi_from_match_rule(match->cmd->str); - if (afi == AFI_MAX) - return ret; - - alist = access_list_lookup(afi, (char *)match->value); - if (!alist) - return ret; - - /* If a match command refers to several objects in one - * command either of them should match (i.e logical OR) - */ - FOREACH_ACCESS_LIST_FILTER(alist, alist_filter) { - dest = bgp_dest_matches_filter_prefix(table, - alist_filter); - if (!dest) - continue; - - ret = RMAP_MATCH; - break; + ret = route_map_apply(rmap, dest_p, RMAP_BGP, &path); + if (ret == RMAP_PERMITMATCH) + return ret; } - /* None of the access-list's filter prefix of this Match rule is - * not matched with BGP table. - * So we do not need to process the remaining match rules - */ - if (ret != RMAP_MATCH) - break; } - - /* route-map prefix not matched with prefixes in BGP table */ return ret; } -bool bgp_conditional_adv_routes(struct peer *peer, afi_t afi, safi_t safi, - struct bgp_table *table, struct route_map *rmap, - bool advertise) +static void bgp_conditional_adv_routes(struct peer *peer, afi_t afi, + safi_t safi, struct bgp_table *table, + struct route_map *rmap, + enum advertise advertise) { int addpath_capable; - afi_t match_afi; - bool ret = false; - bool route_advertised = false; + const struct prefix *dest_p; + struct attr dummy_attr, attr; + struct bgp_path_info path; + struct bgp_path_info *pi; struct peer_af *paf = NULL; struct bgp_dest *dest = NULL; - struct access_list *alist = NULL; - struct filter *alist_filter = NULL; - struct route_map_rule *match = NULL; struct update_subgroup *subgrp = NULL; paf = peer_af_find(peer, afi, safi); if (!paf) - return ret; + return; subgrp = PAF_SUBGRP(paf); /* Ignore if subgroup doesn't exist (implies AF is not negotiated) */ if (!subgrp) - return ret; - - if (!is_rmap_valid(rmap)) - return ret; + return; addpath_capable = bgp_addpath_encode_tx(peer, afi, safi); - /* If several match commands are configured, all must succeed for a - * given route in order for that route to match the clause (i.e. logical - * AND). But we are skipping this rule and advertising if match rule is - * valid and access-lists are having valid prefix - To be discussed - */ - for (match = rmap->head->match_list.head; match; match = match->next) { - - if (!match->cmd || !match->cmd->str || !match->value) + for (dest = bgp_table_top(table); dest; dest = bgp_route_next(dest)) { + dest_p = bgp_dest_get_prefix(dest); + if (!dest_p) continue; - match_afi = get_afi_from_match_rule(match->cmd->str); - if (match_afi == AFI_MAX) - continue; + for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) { + dummy_attr = *pi->attr; + path.peer = pi->peer; + path.attr = &dummy_attr; - alist = access_list_lookup(match_afi, (char *)match->value); - if (!alist) - continue; - - if (safi == SAFI_LABELED_UNICAST) - safi = SAFI_UNICAST; - - /* If a match command refers to several objects in one - * command either of them should match (i.e logical OR) - */ - FOREACH_ACCESS_LIST_FILTER(alist, alist_filter) { - dest = bgp_dest_matches_filter_prefix(table, - alist_filter); - if (!dest) + if (route_map_apply(rmap, dest_p, RMAP_BGP, &path) + != RMAP_PERMITMATCH) continue; - ret = advertise_dest_routes(subgrp, dest, peer, afi, - safi, addpath_capable, - advertise); + if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED) + || (addpath_capable + && bgp_addpath_tx_path( + peer->addpath_type[afi][safi], + pi))) { - /* Atleast one route advertised */ - if (!route_advertised && ret) - route_advertised = true; + /* Skip route-map checks in + * subgroup_announce_check while executing from + * the conditional advertise scanner process. + * otherwise when route-map is also configured + * on same peer, routes in advertise-map may not + * be advertised as expected. + */ + if ((advertise == ADVERTISE) + && subgroup_announce_check(dest, pi, subgrp, + dest_p, &attr, + true)) + bgp_adj_out_set_subgroup(dest, subgrp, + &attr, pi); + else { + /* If default originate is enabled for + * the peer, do not send explicit + * withdraw. This will prevent deletion + * of default route advertised through + * default originate. + */ + if (CHECK_FLAG( + peer->af_flags[afi][safi], + PEER_FLAG_DEFAULT_ORIGINATE) + && is_default_prefix(dest_p)) + break; + + bgp_adj_out_unset_subgroup( + dest, subgrp, 1, + bgp_addpath_id_for_peer( + peer, afi, safi, + &pi->tx_addpath)); + } + } } } - return route_advertised; } /* Handler of conditional advertisement timer event. @@ -230,9 +148,7 @@ static int bgp_conditional_adv_timer(struct thread *t) struct bgp_filter *filter = NULL; struct listnode *node, *nnode = NULL; struct update_subgroup *subgrp = NULL; - enum route_map_cmd_result_t ret, prev_ret; - bool route_advertised = false; - int adv_conditional = 0; + route_map_result_t ret; bgp = THREAD_ARG(t); assert(bgp); @@ -243,138 +159,67 @@ static int bgp_conditional_adv_timer(struct thread *t) /* loop through each peer and advertise or withdraw routes if * advertise-map is configured and prefix(es) in condition-map - * does exist(exist-map)/not exist(non-exist-map) in BGP table based on - * condition(exist-map or non-exist map) + * does exist(exist-map)/not exist(non-exist-map) in BGP table + * based on condition(exist-map or non-exist map) */ - FOREACH_AFI_SAFI (afi, safi) { - if (strmatch(get_afi_safi_str(afi, safi, true), "Unknown")) + for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { + if (!CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE)) continue; - /* labeled-unicast routes are installed in the unicast table - * so in order to display the correct PfxRcd value we must - * look at SAFI_UNICAST - */ - pfx_rcd_safi = - (safi == SAFI_LABELED_UNICAST) ? SAFI_UNICAST : safi; - - table = bgp->rib[afi][pfx_rcd_safi]; - if (!table) - continue; - - /* Process conditional advertisement for each peer */ - for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { - if (!CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE)) + FOREACH_AFI_SAFI (afi, safi) { + if (strmatch(get_afi_safi_str(afi, safi, true), + "Unknown")) continue; + if (!peer->afc[afi][safi]) continue; + /* labeled-unicast routes are installed in the unicast + * table so in order to display the correct PfxRcd value + * we must look at SAFI_UNICAST + */ + pfx_rcd_safi = (safi == SAFI_LABELED_UNICAST) + ? SAFI_UNICAST + : safi; + + table = bgp->rib[afi][pfx_rcd_safi]; + if (!table) + continue; + filter = &peer->filter[afi][safi]; - if ((!filter->advmap.aname) || (!filter->advmap.cname) - || (!filter->advmap.amap) || (!filter->advmap.cmap)) + if (!filter->advmap.aname || !filter->advmap.cname + || !filter->advmap.amap || !filter->advmap.cmap) + continue; + + if (!peer->advmap_config_change[afi][safi] + && !peer->advmap_table_change) continue; /* cmap (route-map attached to exist-map or * non-exist-map) map validation */ - adv_conditional = 0; - - ret = bgp_check_rmap_prefixes_in_bgp_table(table, - filter->advmap.cmap); - prev_ret = - peer->advmap_info[afi][safi].cmap_prev_status; - - switch (ret) { - case RMAP_NOOP: - if (prev_ret == RMAP_NOOP) { - peer->advmap_info[afi][safi] - .config_change = false; - continue; - } - peer->advmap_info[afi][safi].cmap_prev_status = - ret; - - break; - - case RMAP_MATCH: - /* Handle configuration changes */ - if (peer->advmap_info[afi][safi] - .config_change) { - adv_conditional = - (filter->advmap.condition - == CONDITION_EXIST) - ? NLRI - : WITHDRAW; - } else { - if (prev_ret != RMAP_MATCH) - adv_conditional = - (filter->advmap - .condition - == CONDITION_EXIST) - ? NLRI - : WITHDRAW; - } - peer->advmap_info[afi][safi].cmap_prev_status = - ret; - break; - - case RMAP_NOMATCH: - /* Handle configuration changes */ - if (peer->advmap_info[afi][safi] - .config_change) { - adv_conditional = - (filter->advmap.condition - == CONDITION_EXIST) - ? WITHDRAW - : NLRI; - } else { - if (prev_ret != RMAP_NOMATCH) - adv_conditional = - (filter->advmap - .condition - == CONDITION_EXIST) - ? WITHDRAW - : NLRI; - } - peer->advmap_info[afi][safi].cmap_prev_status = - ret; - break; - - case RMAP_OKAY: - case RMAP_ERROR: - default: - break; - } - - /* amap (route-map attached to advertise-map) - * validation. - */ - ret = is_rmap_valid(filter->advmap.amap) ? RMAP_MATCH - : RMAP_NOOP; - - if ((ret == RMAP_NOOP) && (prev_ret == RMAP_NOOP)) - continue; + ret = bgp_check_rmap_prefixes_in_bgp_table( + table, filter->advmap.cmap); /* Derive conditional advertisement status from * condition and return value of condition-map * validation. */ - if (adv_conditional == NLRI) - filter->advmap.status = true; - else if (adv_conditional == WITHDRAW) - filter->advmap.status = false; - else { - /* no change in advertise status. So, only - * previously withdrawn routes will be - * advertised if needed. - */ - } + if (filter->advmap.condition == CONDITION_EXIST) + filter->advmap.advertise = + (ret == RMAP_PERMITMATCH) ? ADVERTISE + : WITHDRAW; + else + filter->advmap.advertise = + (ret == RMAP_PERMITMATCH) ? WITHDRAW + : ADVERTISE; /* Send regular update as per the existing policy. * There is a change in route-map, match-rule, ACLs, * or route-map filter configuration on the same peer. */ - if (peer->advmap_info[afi][safi].config_change) { + if (peer->advmap_config_change[afi][safi]) { paf = peer_af_find(peer, afi, safi); if (paf) { update_subgroup_split_peer(paf, NULL); @@ -383,27 +228,15 @@ static int bgp_conditional_adv_timer(struct thread *t) subgroup_announce_table( paf->subgroup, NULL); } - peer->advmap_info[afi][safi].config_change = - false; + peer->advmap_config_change[afi][safi] = false; } /* Send update as per the conditional advertisement */ - if (adv_conditional) { - route_advertised = bgp_conditional_adv_routes( - peer, afi, safi, table, - filter->advmap.amap, - filter->advmap.status); - - /* amap_prev_status is only to check whether we - * have announced any routes(advertise/withdraw) - * or not. filter->advmap.status will have the - * actual filter status - */ - peer->advmap_info[afi][safi].amap_prev_status = - route_advertised ? RMAP_MATCH - : RMAP_NOOP; - } + bgp_conditional_adv_routes(peer, afi, safi, table, + filter->advmap.amap, + filter->advmap.advertise); } + peer->advmap_table_change = false; } return 0; } @@ -418,9 +251,7 @@ void bgp_conditional_adv_enable(struct peer *peer, afi_t afi, safi_t safi) * and advertise/withdraw routes only when there is a change in BGP * table w.r.t conditional routes */ - peer->advmap_info[afi][safi].amap_prev_status = RMAP_NOOP; - peer->advmap_info[afi][safi].cmap_prev_status = RMAP_NOOP; - peer->advmap_info[afi][safi].config_change = true; + peer->advmap_config_change[afi][safi] = true; /* advertise-map is already configured on atleast one of its * neighbors (AFI/SAFI). So just increment the counter. diff --git a/bgpd/bgp_conditional_adv.h b/bgpd/bgp_conditional_adv.h index cd857958a2..5dcd3607d9 100644 --- a/bgpd/bgp_conditional_adv.h +++ b/bgpd/bgp_conditional_adv.h @@ -36,105 +36,10 @@ extern "C" { /* Polling time for monitoring condition-map routes in route table */ #define CONDITIONAL_ROUTES_POLL_TIME 60 -#define FOREACH_ACCESS_LIST_FILTER(alist, filter) \ - for (filter = alist->head; filter; filter = filter->next) - -static inline bool is_rmap_valid(struct route_map *rmap) -{ - if (!rmap || !rmap->head) - return false; - - /* Doesn't make sense to configure advertise - * or condition map in deny/any clause. - */ - if (rmap->head->type != RMAP_PERMIT) - return false; - - /* If a match command is not present, all routes match the clause */ - if (!rmap->head->match_list.head) - return false; - - return true; -} - -static inline afi_t get_afi_from_match_rule(const char *str) -{ - if (!strcmp(str, "ip address")) - return AFI_IP; - else if (!strcmp(str, "ipv6 address")) - return AFI_IP6; - else - return AFI_MAX; -} - -static inline bool advertise_dest_routes(struct update_subgroup *subgrp, - struct bgp_dest *dest, - struct peer *peer, afi_t afi, - safi_t safi, int addpath_capable, - bool advertise) -{ - struct attr attr; - struct bgp_path_info *pi = NULL; - const struct prefix *dest_p = NULL; - bool route_advertised = false; - - dest_p = (struct prefix *)bgp_dest_get_prefix(dest); - if (!dest_p) - return route_advertised; - - for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) { - if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED) - || (addpath_capable - && bgp_addpath_tx_path(peer->addpath_type[afi][safi], - pi))) { - - /* Skip route-map checks in subgroup_announce_check - * while executing from the conditional advertise - * scanner process. otherwise when route-map is also - * configured on same peer, routes in advertise-map - * may not be advertised as expected. - */ - if (advertise - && subgroup_announce_check(dest, pi, subgrp, dest_p, - &attr, true)) { - bgp_adj_out_set_subgroup(dest, subgrp, &attr, - pi); - route_advertised = true; - } else { - /* If default originate is enabled for the - * peer, do not send explicit withdraw. - * This will prevent deletion of default route - * advertised through default originate. - */ - if (CHECK_FLAG(peer->af_flags[afi][safi], - PEER_FLAG_DEFAULT_ORIGINATE) - && is_default_prefix(dest_p)) - break; - - bgp_adj_out_unset_subgroup( - dest, subgrp, 1, - bgp_addpath_id_for_peer( - peer, afi, safi, - &pi->tx_addpath)); - route_advertised = true; - } - } - } - return route_advertised; -} - -struct bgp_dest *bgp_dest_matches_filter_prefix(struct bgp_table *table, - struct filter *filter); -extern enum route_map_cmd_result_t -bgp_check_rmap_prefixes_in_bgp_table(struct bgp_table *table, - struct route_map *rmap); extern void bgp_conditional_adv_enable(struct peer *peer, afi_t afi, safi_t safi); extern void bgp_conditional_adv_disable(struct peer *peer, afi_t afi, safi_t safi); -extern bool bgp_conditional_adv_routes(struct peer *peer, afi_t afi, - safi_t safi, struct bgp_table *table, - struct route_map *rmap, bool advertise); #ifdef __cplusplus } #endif diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index d75d032c5c..a23acda0a8 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -1783,6 +1783,9 @@ static int bgp_update_receive(struct peer *peer, bgp_size_t size) peer->update_time = bgp_clock(); + /* Notify BGP Conditional advertisement scanner process */ + peer->advmap_table_change = true; + return Receive_UPDATE_message; } diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 48f38dfec7..1b611ebe7b 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -2030,6 +2030,27 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi, peer->host, p); bgp_attr_flush(attr); + + /* TBD : Not sure if this is the correct way to fetch + * peer from group. + * Notify BGP Conditional advertisement scanner process. + */ + if (ADVERTISE_MAP_NAME(filter) + || CONDITION_MAP_NAME(filter)) { + struct peer *temp_peer; + struct listnode *temp_node, *temp_nnode = NULL; + for (ALL_LIST_ELEMENTS(bgp->peer, temp_node, + temp_nnode, temp_peer)) { + if (!CHECK_FLAG(peer->flags, + PEER_FLAG_CONFIG_NODE)) + continue; + if (strcmp(peer->host, temp_peer->host) + != 0) + continue; + temp_peer->advmap_table_change = true; + break; + } + } return false; } } @@ -4363,7 +4384,7 @@ static int bgp_announce_route_timer_expired(struct thread *t) peer_af_announce_route(paf, 1); /* Notify BGP conditional advertisement scanner percess */ - peer->advmap_info[paf->afi][paf->safi].config_change = true; + peer->advmap_config_change[paf->afi][paf->safi] = true; return 0; } diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 2abebbcbc3..e4a9c29000 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -3710,7 +3710,7 @@ static void bgp_route_map_process_peer(const char *rmap_name, peer->default_rmap[afi][safi].map = map; /* Notify BGP conditional advertisement scanner percess */ - peer->advmap_info[afi][safi].config_change = true; + peer->advmap_config_change[afi][safi] = true; } static void bgp_route_map_update_peer_group(const char *rmap_name, diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 480e3172af..5bfda7d570 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -11417,8 +11417,9 @@ static void bgp_show_peer_afi(struct vty *vty, struct peer *p, afi_t afi, filter->advmap.cname, filter->advmap.amap ? "*" : "", filter->advmap.aname, - filter->advmap.status ? "Advertise" - : "Withdraw"); + filter->advmap.advertise == ADVERTISE + ? "Advertise" + : "Withdraw"); /* Receive prefix count */ vty_out(vty, " %u accepted prefixes\n", diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 7fbad67e93..194049f017 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -6623,7 +6623,7 @@ int peer_advertise_map_set(struct peer *peer, afi_t afi, safi_t safi, filter->advmap.cmap = condition_map; filter->advmap.condition = condition; route_map_counter_increment(advertise_map); - peer->advmap_info[afi][safi].config_change = true; + peer->advmap_config_change[afi][safi] = true; /* Check if handling a regular peer. */ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { @@ -6631,11 +6631,11 @@ int peer_advertise_map_set(struct peer *peer, afi_t afi, safi_t safi, SET_FLAG(peer->filter_override[afi][safi][RMAP_OUT], PEER_FT_ADVERTISE_MAP); - /* Hold peer_on_policy_change() until timer thread is called */ - - /* To increment condition_filter_count and/or create timer */ + /* Hold peer_on_policy_change() until timer thread is called. + * Increment condition_filter_count and/or create timer. + */ if (!filter_exists) { - filter->advmap.status = true; + filter->advmap.advertise = ADVERTISE; bgp_conditional_adv_enable(peer, afi, safi); } /* Skip peer-group mechanics for regular peers. */ @@ -6671,11 +6671,11 @@ int peer_advertise_map_set(struct peer *peer, afi_t afi, safi_t safi, filter->advmap.condition = condition; route_map_counter_increment(advertise_map); - /* Hold peer_on_policy_change() until timer thread is called */ - - /* increment condition_filter_count, create timer if 1st one */ + /* Hold peer_on_policy_change() until timer thread is called. + * Increment condition_filter_count, create timer if 1st one + */ if (!filter_exists) { - filter->advmap.status = true; + filter->advmap.advertise = ADVERTISE; bgp_conditional_adv_enable(member, afi, safi); } } diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 293583460f..05fe2330b4 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -683,7 +683,7 @@ struct bgp { struct work_queue *process_queue; /* BGP Conditional advertisement */ - int condition_filter_count; + uint32_t condition_filter_count; struct thread *t_condition_check; QOBJ_FIELDS @@ -764,8 +764,10 @@ struct bgp_nexthop { #define BGP_GTSM_HOPS_CONNECTED 1 /* Advertise map */ -#define CONDITION_NON_EXIST 0 -#define CONDITION_EXIST 1 +#define CONDITION_NON_EXIST false +#define CONDITION_EXIST true + +enum advertise { WITHDRAW, ADVERTISE }; #include "filter.h" @@ -811,7 +813,7 @@ struct bgp_filter { char *cname; struct route_map *cmap; - bool status; + enum advertise advertise; } advmap; }; @@ -1471,11 +1473,8 @@ struct peer { bool as_path_loop_detection; /* Conditional advertisement */ - struct { - bool config_change; - enum route_map_cmd_result_t amap_prev_status; - enum route_map_cmd_result_t cmap_prev_status; - } advmap_info[AFI_MAX][SAFI_MAX]; + bool advmap_config_change[AFI_MAX][SAFI_MAX]; + bool advmap_table_change; QOBJ_FIELDS }; From cf2ad4d8a6d72885aff7487dffc68cfad65b9a07 Mon Sep 17 00:00:00 2001 From: Madhuri Kuruganti Date: Wed, 7 Oct 2020 17:40:00 +0530 Subject: [PATCH 4/8] bgpd: conditional advertisement - comments addressed Signed-off-by: Madhuri Kuruganti --- bgpd/bgp_conditional_adv.c | 2 +- bgpd/bgp_route.c | 1 + bgpd/bgp_vty.c | 106 +++++---------------- bgpd/bgpd.c | 186 +++++++++++++++++-------------------- bgpd/bgpd.h | 26 ++++-- 5 files changed, 126 insertions(+), 195 deletions(-) diff --git a/bgpd/bgp_conditional_adv.c b/bgpd/bgp_conditional_adv.c index 999326d9c3..89ee71df89 100644 --- a/bgpd/bgp_conditional_adv.c +++ b/bgpd/bgp_conditional_adv.c @@ -54,7 +54,7 @@ bgp_check_rmap_prefixes_in_bgp_table(struct bgp_table *table, static void bgp_conditional_adv_routes(struct peer *peer, afi_t afi, safi_t safi, struct bgp_table *table, struct route_map *rmap, - enum advertise advertise) + enum update_type advertise) { int addpath_capable; const struct prefix *dest_p; diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 1b611ebe7b..3074531476 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -2039,6 +2039,7 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi, || CONDITION_MAP_NAME(filter)) { struct peer *temp_peer; struct listnode *temp_node, *temp_nnode = NULL; + for (ALL_LIST_ELEMENTS(bgp->peer, temp_node, temp_nnode, temp_peer)) { if (!CHECK_FLAG(peer->flags, diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 5bfda7d570..765d27c243 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -7046,8 +7046,9 @@ ALIAS_HIDDEN(no_neighbor_filter_list, no_neighbor_filter_list_hidden_cmd, /* Set advertise-map to the peer. */ static int peer_advertise_map_set_vty(struct vty *vty, const char *ip_str, afi_t afi, safi_t safi, - const char *advertise_str, bool condition, - const char *condition_str) + const char *advertise_str, + const char *condition_str, bool condition, + bool set) { int ret = CMD_WARNING_CONFIG_FAILED; struct peer *peer; @@ -7061,42 +7062,22 @@ static int peer_advertise_map_set_vty(struct vty *vty, const char *ip_str, condition_map = route_map_lookup_warn_noexist(vty, condition_str); advertise_map = route_map_lookup_warn_noexist(vty, advertise_str); - ret = peer_advertise_map_set(peer, afi, safi, advertise_str, - advertise_map, condition, condition_str, - condition_map); + if (set) + ret = peer_advertise_map_set(peer, afi, safi, advertise_str, + advertise_map, condition_str, + condition_map, condition); + else + ret = peer_advertise_map_unset(peer, afi, safi, advertise_str, + advertise_map, condition_str, + condition_map, condition); return bgp_vty_return(vty, ret); } -static int peer_advertise_map_unset_vty(struct vty *vty, const char *ip_str, - afi_t afi, safi_t safi, - const char *advertise_str, - bool condition, - const char *condition_str) -{ - int ret = CMD_WARNING_CONFIG_FAILED; - struct peer *peer; - struct route_map *advertise_map; - struct route_map *condition_map; - - - peer = peer_and_group_lookup_vty(vty, ip_str); - if (!peer) - return ret; - - condition_map = route_map_lookup_warn_noexist(vty, condition_str); - advertise_map = route_map_lookup_warn_noexist(vty, advertise_str); - - ret = peer_advertise_map_unset(peer, afi, safi, advertise_str, - advertise_map, condition, condition_str, - condition_map); - - return bgp_vty_return(vty, ret); -} - -DEFUN (neighbor_advertise_map, +DEFPY (neighbor_advertise_map, neighbor_advertise_map_cmd, - "neighbor advertise-map WORD ", + "[no$no] neighbor advertise-map WORD ", + NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Route-map to conditionally advertise routes\n" @@ -7112,55 +7093,23 @@ DEFUN (neighbor_advertise_map, int idx_condition_word = 5; bool condition = CONDITION_EXIST; + if (no) { + idx_peer++; + idx_advertise_word++; + idx_condition_word++; + } + if (argv_find(argv, argc, "non-exist-map", &idx)) condition = CONDITION_NON_EXIST; return peer_advertise_map_set_vty( vty, argv[idx_peer]->arg, bgp_node_afi(vty), bgp_node_safi(vty), - argv[idx_advertise_word]->arg, condition, - argv[idx_condition_word]->arg); + argv[idx_advertise_word]->arg, argv[idx_condition_word]->arg, + condition, !no); } ALIAS_HIDDEN(neighbor_advertise_map, neighbor_advertise_map_hidden_cmd, - "neighbor advertise-map WORD ", - NEIGHBOR_STR NEIGHBOR_ADDR_STR2 - "Route-map to conditionally advertise routes\n" - "Name of advertise map\n" - "Advertise routes only if prefixes in exist-map are installed in BGP table\n" - "Name of the exist map\n" - "Advertise routes only if prefixes in non-exist-map are not installed in BGP table\n" - "Name of the non exist map\n") - -DEFUN (no_neighbor_advertise_map, - no_neighbor_advertise_map_cmd, - "no neighbor advertise-map WORD ", - NO_STR - NEIGHBOR_STR - NEIGHBOR_ADDR_STR2 - "Route-map to conditionally advertise routes\n" - "Name of advertise map\n" - "Advertise routes only if prefixes in exist-map are installed in BGP table\n" - "Name of the exist map\n" - "Advertise routes only if prefixes in non-exist-map are not installed in BGP table\n" - "Name of the non exist map\n") -{ - int idx = 0; - int idx_peer = 2; - int idx_advertise_word = 4; - int idx_condition_word = 6; - bool condition = CONDITION_EXIST; - - if (argv_find(argv, argc, "non-exist-map", &idx)) - condition = CONDITION_NON_EXIST; - - return peer_advertise_map_unset_vty( - vty, argv[idx_peer]->arg, bgp_node_afi(vty), bgp_node_safi(vty), - argv[idx_advertise_word]->arg, condition, - argv[idx_condition_word]->arg); -} - -ALIAS_HIDDEN(no_neighbor_advertise_map, no_neighbor_advertise_map_hidden_cmd, - "no neighbor advertise-map WORD ", + "[no$no] neighbor advertise-map WORD ", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Route-map to conditionally advertise routes\n" "Name of advertise map\n" @@ -17543,23 +17492,14 @@ void bgp_vty_init(void) /* "neighbor advertise-map" commands. */ install_element(BGP_NODE, &neighbor_advertise_map_hidden_cmd); - install_element(BGP_NODE, &no_neighbor_advertise_map_hidden_cmd); install_element(BGP_IPV4_NODE, &neighbor_advertise_map_cmd); - install_element(BGP_IPV4_NODE, &no_neighbor_advertise_map_cmd); install_element(BGP_IPV4M_NODE, &neighbor_advertise_map_cmd); - install_element(BGP_IPV4M_NODE, &no_neighbor_advertise_map_cmd); install_element(BGP_IPV4L_NODE, &neighbor_advertise_map_cmd); - install_element(BGP_IPV4L_NODE, &no_neighbor_advertise_map_cmd); install_element(BGP_IPV6_NODE, &neighbor_advertise_map_cmd); - install_element(BGP_IPV6_NODE, &no_neighbor_advertise_map_cmd); install_element(BGP_IPV6M_NODE, &neighbor_advertise_map_cmd); - install_element(BGP_IPV6M_NODE, &no_neighbor_advertise_map_cmd); install_element(BGP_IPV6L_NODE, &neighbor_advertise_map_cmd); - install_element(BGP_IPV6L_NODE, &no_neighbor_advertise_map_cmd); install_element(BGP_VPNV4_NODE, &neighbor_advertise_map_cmd); - install_element(BGP_VPNV4_NODE, &no_neighbor_advertise_map_cmd); install_element(BGP_VPNV6_NODE, &neighbor_advertise_map_cmd); - install_element(BGP_VPNV6_NODE, &no_neighbor_advertise_map_cmd); /* neighbor maximum-prefix-out commands. */ install_element(BGP_NODE, &neighbor_maximum_prefix_out_cmd); diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 194049f017..fd4595274d 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -6586,6 +6586,59 @@ int peer_unsuppress_map_unset(struct peer *peer, afi_t afi, safi_t safi) return 0; } +static void peer_update_rmap_filter_data(struct peer *peer, afi_t afi, + safi_t safi, const char *rmap_name1, + struct route_map *rmap1, + const char *rmap_name2, + struct route_map *rmap2, + uint8_t config_flags) +{ + struct bgp_filter *filter; + bool filter_exists = false; + + filter = &peer->filter[afi][safi]; + + if (CHECK_FLAG(config_flags, BGP_PEER_ADVERTISE_MAP)) { + /* advertise-map is already configured. */ + if (filter->advmap.aname) { + filter_exists = true; + XFREE(MTYPE_BGP_FILTER_NAME, filter->advmap.aname); + XFREE(MTYPE_BGP_FILTER_NAME, filter->advmap.cname); + } + route_map_counter_decrement(filter->advmap.amap); + + /* Removed advertise-map configuration */ + if (!CHECK_FLAG(config_flags, BGP_PEER_RMAP_SET)) { + memset(filter, 0, sizeof(struct bgp_filter)); + + /* decrement condition_filter_count delete timer if last + * one */ + if (filter_exists) + bgp_conditional_adv_disable(peer, afi, safi); + + return; + } + + /* Update filter data with newly configured values. */ + filter->advmap.aname = + XSTRDUP(MTYPE_BGP_FILTER_NAME, rmap_name1); + filter->advmap.cname = + XSTRDUP(MTYPE_BGP_FILTER_NAME, rmap_name2); + filter->advmap.amap = rmap1; + filter->advmap.cmap = rmap2; + filter->advmap.condition = + CHECK_FLAG(config_flags, BGP_PEER_CONDITION_EXIST); + route_map_counter_increment(filter->advmap.amap); + peer->advmap_config_change[afi][safi] = true; + + /* Increment condition_filter_count and/or create timer. */ + if (!filter_exists) { + filter->advmap.advertise = ADVERTISE; + bgp_conditional_adv_enable(peer, afi, safi); + } + } +} + /* Set advertise-map to the peer but do not process peer route updates here. * * Hold filter changes until the conditional routes polling thread is called * * AS we need to advertise/withdraw prefixes (in advertise-map) based on the * @@ -6595,50 +6648,29 @@ int peer_unsuppress_map_unset(struct peer *peer, afi_t afi, safi_t safi) */ int peer_advertise_map_set(struct peer *peer, afi_t afi, safi_t safi, const char *advertise_name, - struct route_map *advertise_map, bool condition, + struct route_map *advertise_map, const char *condition_name, - struct route_map *condition_map) + struct route_map *condition_map, bool condition) { - bool filter_exists = false; + uint8_t config_flags = 0; struct peer *member; - struct bgp_filter *filter; struct listnode *node, *nnode; + SET_FLAG(config_flags, BGP_PEER_RMAP_SET); + SET_FLAG(config_flags, BGP_PEER_ADVERTISE_MAP); + if (condition) + SET_FLAG(config_flags, BGP_PEER_CONDITION_EXIST); + /* Set configuration on peer. */ - filter = &peer->filter[afi][safi]; + peer_update_rmap_filter_data(peer, afi, safi, advertise_name, + advertise_map, condition_name, + condition_map, config_flags); - if (filter->advmap.aname) { - /* advertise-map filter is already configured on this peer */ - filter_exists = true; - - XFREE(MTYPE_BGP_FILTER_NAME, filter->advmap.aname); - XFREE(MTYPE_BGP_FILTER_NAME, filter->advmap.cname); - filter->advmap.condition = CONDITION_NON_EXIST; - } - - route_map_counter_decrement(filter->advmap.amap); - filter->advmap.aname = XSTRDUP(MTYPE_BGP_FILTER_NAME, advertise_name); - filter->advmap.cname = XSTRDUP(MTYPE_BGP_FILTER_NAME, condition_name); - filter->advmap.amap = advertise_map; - filter->advmap.cmap = condition_map; - filter->advmap.condition = condition; - route_map_counter_increment(advertise_map); - peer->advmap_config_change[afi][safi] = true; - - /* Check if handling a regular peer. */ + /* Check if handling a regular peer & Skip peer-group mechanics. */ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { /* Set override-flag and process peer route updates. */ SET_FLAG(peer->filter_override[afi][safi][RMAP_OUT], PEER_FT_ADVERTISE_MAP); - - /* Hold peer_on_policy_change() until timer thread is called. - * Increment condition_filter_count and/or create timer. - */ - if (!filter_exists) { - filter->advmap.advertise = ADVERTISE; - bgp_conditional_adv_enable(peer, afi, safi); - } - /* Skip peer-group mechanics for regular peers. */ return 0; } @@ -6653,31 +6685,9 @@ int peer_advertise_map_set(struct peer *peer, afi_t afi, safi_t safi, continue; /* Set configuration on peer-group member. */ - filter = &member->filter[afi][safi]; - if (filter->advmap.aname) { - /* advertise-map filter is already configured. */ - filter_exists = true; - XFREE(MTYPE_BGP_FILTER_NAME, filter->advmap.aname); - XFREE(MTYPE_BGP_FILTER_NAME, filter->advmap.cname); - filter->advmap.condition = CONDITION_NON_EXIST; - } - route_map_counter_decrement(filter->advmap.amap); - filter->advmap.aname = - XSTRDUP(MTYPE_BGP_FILTER_NAME, advertise_name); - filter->advmap.amap = advertise_map; - filter->advmap.cname = - XSTRDUP(MTYPE_BGP_FILTER_NAME, condition_name); - filter->advmap.cmap = condition_map; - filter->advmap.condition = condition; - route_map_counter_increment(advertise_map); - - /* Hold peer_on_policy_change() until timer thread is called. - * Increment condition_filter_count, create timer if 1st one - */ - if (!filter_exists) { - filter->advmap.advertise = ADVERTISE; - bgp_conditional_adv_enable(member, afi, safi); - } + peer_update_rmap_filter_data(member, afi, safi, advertise_name, + advertise_map, condition_name, + condition_map, config_flags); } return 0; @@ -6686,15 +6696,18 @@ int peer_advertise_map_set(struct peer *peer, afi_t afi, safi_t safi, /* Unset advertise-map from the peer. */ int peer_advertise_map_unset(struct peer *peer, afi_t afi, safi_t safi, const char *advertise_name, - struct route_map *advertise_map, bool condition, + struct route_map *advertise_map, const char *condition_name, - struct route_map *condition_map) + struct route_map *condition_map, bool condition) { - bool filter_exists = false; + uint8_t config_flags = 0; struct peer *member; - struct bgp_filter *filter; struct listnode *node, *nnode; + SET_FLAG(config_flags, BGP_PEER_ADVERTISE_MAP); + if (condition) + SET_FLAG(config_flags, BGP_PEER_CONDITION_EXIST); + /* Unset override-flag unconditionally. */ UNSET_FLAG(peer->filter_override[afi][safi][RMAP_OUT], PEER_FT_ADVERTISE_MAP); @@ -6706,33 +6719,15 @@ int peer_advertise_map_unset(struct peer *peer, afi_t afi, safi_t safi, MTYPE_BGP_FILTER_NAME); PEER_ATTR_INHERIT(peer, peer->group, filter[afi][safi].advmap.amap); - } else { - /* Otherwise remove configuration from peer. */ - filter = &peer->filter[afi][safi]; - if (filter->advmap.aname) { - /* advertise-map filter is already configured. */ - filter_exists = true; - XFREE(MTYPE_BGP_FILTER_NAME, filter->advmap.aname); - XFREE(MTYPE_BGP_FILTER_NAME, filter->advmap.cname); - } - route_map_counter_decrement(filter->advmap.amap); - filter->advmap.aname = NULL; - filter->advmap.amap = NULL; - filter->advmap.cname = NULL; - filter->advmap.cmap = NULL; - filter->advmap.condition = CONDITION_NON_EXIST; - } + } else + peer_update_rmap_filter_data(peer, afi, safi, advertise_name, + advertise_map, condition_name, + condition_map, config_flags); - /* Check if handling a regular peer. */ + /* Check if handling a regular peer and skip peer-group mechanics. */ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { /* Process peer route updates. */ peer_on_policy_change(peer, afi, safi, 1); - - /* decrement condition_filter_count delete timer if last one */ - if (filter_exists) - bgp_conditional_adv_disable(peer, afi, safi); - - /* Skip peer-group mechanics for regular peers. */ return 0; } @@ -6745,25 +6740,10 @@ int peer_advertise_map_unset(struct peer *peer, afi_t afi, safi_t safi, if (CHECK_FLAG(member->filter_override[afi][safi][RMAP_OUT], PEER_FT_ADVERTISE_MAP)) continue; - /* Remove configuration on peer-group member. */ - filter = &member->filter[afi][safi]; - if (filter->advmap.aname) { - /* advertise-map filter is already configured. */ - filter_exists = true; - XFREE(MTYPE_BGP_FILTER_NAME, filter->advmap.aname); - XFREE(MTYPE_BGP_FILTER_NAME, filter->advmap.cname); - } - route_map_counter_decrement(filter->advmap.amap); - filter->advmap.aname = NULL; - filter->advmap.amap = NULL; - filter->advmap.cname = NULL; - filter->advmap.cmap = NULL; - filter->advmap.condition = CONDITION_NON_EXIST; - - /* decrement condition_filter_count delete timer if last one */ - if (filter_exists) - bgp_conditional_adv_disable(peer, afi, safi); + peer_update_rmap_filter_data(member, afi, safi, advertise_name, + advertise_map, condition_name, + condition_map, config_flags); /* Process peer route updates. */ peer_on_policy_change(member, afi, safi, 1); diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 05fe2330b4..39efab2899 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -764,10 +764,18 @@ struct bgp_nexthop { #define BGP_GTSM_HOPS_CONNECTED 1 /* Advertise map */ -#define CONDITION_NON_EXIST false -#define CONDITION_EXIST true +#define CONDITION_NON_EXIST false +#define CONDITION_EXIST true -enum advertise { WITHDRAW, ADVERTISE }; +/* BGP peer RMAP options */ +#define BGP_PEER_ADVERTISE_MAP (1 << 0) +#define BGP_PEER_ROUTE_MAP (1 << 1) +#define BGP_PEER_UNSUPPRESS_MAP (1 << 2) +#define BGP_PEER_CONDITION_EXIST (1 << 3) +#define BGP_PEER_RMAP_DIRECTION (1 << 4) +#define BGP_PEER_RMAP_SET (1 << 5) + +enum update_type { WITHDRAW, ADVERTISE }; #include "filter.h" @@ -813,7 +821,7 @@ struct bgp_filter { char *cname; struct route_map *cmap; - enum advertise advertise; + enum update_type advertise; } advmap; }; @@ -1970,8 +1978,9 @@ extern int peer_unsuppress_map_set(struct peer *peer, afi_t afi, safi_t safi, extern int peer_advertise_map_set(struct peer *peer, afi_t afi, safi_t safi, const char *advertise_name, struct route_map *advertise_map, - bool condition, const char *condition_name, - struct route_map *condition_map); + const char *condition_name, + struct route_map *condition_map, + bool condition); extern int peer_password_set(struct peer *, const char *); extern int peer_password_unset(struct peer *); @@ -1981,8 +1990,9 @@ extern int peer_unsuppress_map_unset(struct peer *, afi_t, safi_t); extern int peer_advertise_map_unset(struct peer *peer, afi_t afi, safi_t safi, const char *advertise_name, struct route_map *advertise_map, - bool condition, const char *condition_name, - struct route_map *condition_map); + const char *condition_name, + struct route_map *condition_map, + bool condition); extern int peer_maximum_prefix_set(struct peer *, afi_t, safi_t, uint32_t, uint8_t, int, uint16_t, bool force); From 52b8406259b3a3a6855069f9cd4948e61325bdb0 Mon Sep 17 00:00:00 2001 From: Madhuri Kuruganti Date: Fri, 9 Oct 2020 13:59:49 +0530 Subject: [PATCH 5/8] bgpd: conditional advertisement - comments addressed and few checks Signed-off-by: Madhuri Kuruganti --- bgpd/bgp_conditional_adv.c | 57 ++++++++++++++++++++++++-------------- bgpd/bgp_vty.c | 29 ++++++------------- bgpd/bgpd.c | 5 ++-- 3 files changed, 47 insertions(+), 44 deletions(-) diff --git a/bgpd/bgp_conditional_adv.c b/bgpd/bgp_conditional_adv.c index 89ee71df89..07b3b4143b 100644 --- a/bgpd/bgp_conditional_adv.c +++ b/bgpd/bgp_conditional_adv.c @@ -26,25 +26,31 @@ static route_map_result_t bgp_check_rmap_prefixes_in_bgp_table(struct bgp_table *table, struct route_map *rmap) { + struct attr dummy_attr = {0}; struct bgp_dest *dest; - struct attr dummy_attr; - struct bgp_path_info path; - const struct prefix *dest_p; struct bgp_path_info *pi; - route_map_result_t ret = RMAP_PERMITMATCH; + struct bgp_path_info path = {0}; + struct bgp_path_info_extra path_extra = {0}; + const struct prefix *dest_p; + route_map_result_t ret = RMAP_DENYMATCH; for (dest = bgp_table_top(table); dest; dest = bgp_route_next(dest)) { dest_p = bgp_dest_get_prefix(dest); - if (!dest_p) - continue; + assert(dest_p); for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) { dummy_attr = *pi->attr; - path.peer = pi->peer; - path.attr = &dummy_attr; + + /* Fill temp path_info */ + prep_for_rmap_apply(&path, &path_extra, dest, pi, + pi->peer, &dummy_attr); + + RESET_FLAG(dummy_attr.rmap_change_flags); ret = route_map_apply(rmap, dest_p, RMAP_BGP, &path); - if (ret == RMAP_PERMITMATCH) + if (ret != RMAP_PERMITMATCH) + bgp_attr_flush(&dummy_attr); + else return ret; } } @@ -57,13 +63,14 @@ static void bgp_conditional_adv_routes(struct peer *peer, afi_t afi, enum update_type advertise) { int addpath_capable; - const struct prefix *dest_p; - struct attr dummy_attr, attr; - struct bgp_path_info path; + struct bgp_dest *dest; struct bgp_path_info *pi; - struct peer_af *paf = NULL; - struct bgp_dest *dest = NULL; - struct update_subgroup *subgrp = NULL; + struct bgp_path_info path; + struct peer_af *paf; + const struct prefix *dest_p; + struct update_subgroup *subgrp; + struct attr dummy_attr = {0}, attr = {0}; + struct bgp_path_info_extra path_extra = {0}; paf = peer_af_find(peer, afi, safi); if (!paf) @@ -78,17 +85,22 @@ static void bgp_conditional_adv_routes(struct peer *peer, afi_t afi, for (dest = bgp_table_top(table); dest; dest = bgp_route_next(dest)) { dest_p = bgp_dest_get_prefix(dest); - if (!dest_p) - continue; + assert(dest_p); for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) { dummy_attr = *pi->attr; - path.peer = pi->peer; - path.attr = &dummy_attr; + + /* Fill temp path_info */ + prep_for_rmap_apply(&path, &path_extra, dest, pi, + pi->peer, &dummy_attr); + + RESET_FLAG(dummy_attr.rmap_change_flags); if (route_map_apply(rmap, dest_p, RMAP_BGP, &path) - != RMAP_PERMITMATCH) + != RMAP_PERMITMATCH) { + bgp_attr_flush(&dummy_attr); continue; + } if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED) || (addpath_capable @@ -166,12 +178,15 @@ static int bgp_conditional_adv_timer(struct thread *t) if (!CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE)) continue; + if (peer->status != Established) + continue; + FOREACH_AFI_SAFI (afi, safi) { if (strmatch(get_afi_safi_str(afi, safi, true), "Unknown")) continue; - if (!peer->afc[afi][safi]) + if (!peer->afc_nego[afi][safi]) continue; /* labeled-unicast routes are installed in the unicast diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 765d27c243..17a4411c82 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -7076,47 +7076,34 @@ static int peer_advertise_map_set_vty(struct vty *vty, const char *ip_str, DEFPY (neighbor_advertise_map, neighbor_advertise_map_cmd, - "[no$no] neighbor advertise-map WORD ", + "[no$no] neighbor $neighbor advertise-map WORD$advertise_str $exist WORD$condition_str", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Route-map to conditionally advertise routes\n" "Name of advertise map\n" "Advertise routes only if prefixes in exist-map are installed in BGP table\n" - "Name of the exist map\n" "Advertise routes only if prefixes in non-exist-map are not installed in BGP table\n" - "Name of the non exist map\n") + "Name of the exist or non exist map\n") { - int idx = 0; - int idx_peer = 1; - int idx_advertise_word = 3; - int idx_condition_word = 5; bool condition = CONDITION_EXIST; - if (no) { - idx_peer++; - idx_advertise_word++; - idx_condition_word++; - } - - if (argv_find(argv, argc, "non-exist-map", &idx)) + if (!strcmp(exist, "non-exist-map")) condition = CONDITION_NON_EXIST; - return peer_advertise_map_set_vty( - vty, argv[idx_peer]->arg, bgp_node_afi(vty), bgp_node_safi(vty), - argv[idx_advertise_word]->arg, argv[idx_condition_word]->arg, - condition, !no); + return peer_advertise_map_set_vty(vty, neighbor, bgp_node_afi(vty), + bgp_node_safi(vty), advertise_str, + condition_str, condition, !no); } ALIAS_HIDDEN(neighbor_advertise_map, neighbor_advertise_map_hidden_cmd, - "[no$no] neighbor advertise-map WORD ", + "[no$no] neighbor $neighbor advertise-map WORD$advertise_str $exist WORD$condition_str", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Route-map to conditionally advertise routes\n" "Name of advertise map\n" "Advertise routes only if prefixes in exist-map are installed in BGP table\n" - "Name of the exist map\n" "Advertise routes only if prefixes in non-exist-map are not installed in BGP table\n" - "Name of the non exist map\n") + "Name of the exist or non exist map\n") /* Set route-map to the peer. */ static int peer_route_map_set_vty(struct vty *vty, const char *ip_str, diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index fd4595274d..0e8970d685 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -6611,8 +6611,9 @@ static void peer_update_rmap_filter_data(struct peer *peer, afi_t afi, if (!CHECK_FLAG(config_flags, BGP_PEER_RMAP_SET)) { memset(filter, 0, sizeof(struct bgp_filter)); - /* decrement condition_filter_count delete timer if last - * one */ + /* decrement condition_filter_count delete timer if + * this is the last advertise-map to be removed. + */ if (filter_exists) bgp_conditional_adv_disable(peer, afi, safi); From fa36596cbd4206b59411036d6df8c6dcec88c4b8 Mon Sep 17 00:00:00 2001 From: Madhuri Kuruganti Date: Wed, 14 Oct 2020 01:44:27 +0530 Subject: [PATCH 6/8] bgpd: conditional advertisement - topotests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Router2# show ip bgp neighbors 10.10.20.3 json !--- Output suppressed. "addressFamilyInfo":{ "ipv4Unicast":{ "updateGroupId":2, "subGroupId":2, "packetQueueLength":0, "inboundSoftConfigPermit":true, "commAttriSentToNbr":"extendedAndStandard", "advertiseMap":{ "condition":"NON_EXIST", "conditionMap":"EXIST-MAP", "advertiseMap":"ADV-MAP", "advertiseStatus":"Withdraw" }, "acceptedPrefixCounter":0, "sentPrefixCounter":2 }, "ipv6Unicast":{ "inboundSoftConfigPermit":true, "commAttriSentToNbr":"extendedAndStandard", "advertiseMap":{ "condition":"EXIST", "conditionMap":"ALLOW_ALL", "advertiseMap":"ALLOW_ALL", "advertiseStatus":"Advertise" }, "acceptedPrefixCounter":0 } }, !--- Output suppressed. router@router:~/frr/tests/topotests/bgp_conditional_advertisement$ sudo pytest -s test_bgp_conditional_advertisement.py [sudo] password for router: mkdir: cannot create directory ‘/tmp/topotests’: File exists 2020-10-14 17:00:46,649 INFO: Running environment diagnostics =========================================================================================== test session starts ============================================================================================ platform linux2 -- Python 2.7.17, pytest-4.6.11, py-1.9.0, pluggy-0.13.1 rootdir: /home/router/frr/tests/topotests, inifile: pytest.ini collected 2 items test_bgp_conditional_advertisement.py 2020-10-14 17:00:47,137 INFO: Testsuite start time: Wed Oct 14 17:00:47 2020 2020-10-14 17:00:47,137 INFO: ======================================== 2020-10-14 17:00:47,138 INFO: Running setup_module to create topology 2020-10-14 17:00:48,711 INFO: loading topology: bgp_conditional_advertisement.test_bgp_conditional_advertisement 2020-10-14 17:00:48,712 INFO: starting topology: bgp_conditional_advertisement.test_bgp_conditional_advertisement 2020-10-14 17:00:49,042 INFO: r1: running version: 7.6-dev-MyOwnFRRVersion-gd77fe2dd0 2020-10-14 17:00:51,284 INFO: r2: running version: 7.6-dev-MyOwnFRRVersion-gd77fe2dd0 2020-10-14 17:00:53,582 INFO: r3: running version: 7.6-dev-MyOwnFRRVersion-gd77fe2dd0 2020-10-14 17:00:55,826 INFO: Running setup_module() done 2020-10-14 17:00:57,747 INFO: '_all_routes_advertised' polling started (interval 1 secs, maximum wait 130 secs) 2020-10-14 17:00:58,262 INFO: '_all_routes_advertised' succeeded after 0.52 seconds 2020-10-14 17:00:58,262 INFO: TC11: "router3" BGP convergence - PASSED!!! 2020-10-14 17:00:58,863 INFO: '_exist_map_routes_present' polling started (interval 1 secs, maximum wait 90 secs) 2020-10-14 17:00:59,419 INFO: '_exist_map_routes_present' succeeded after 0.56 seconds 2020-10-14 17:00:59,419 INFO: TC21: exist-map routes present in "router2" BGP table - PASSED!!! 2020-10-14 17:01:00,017 INFO: '_exist_map_routes_not_present' polling started (interval 1 secs, maximum wait 90 secs) 2020-10-14 17:02:00,192 INFO: '_exist_map_routes_not_present' succeeded after 60.18 seconds 2020-10-14 17:02:00,192 INFO: TC22: exist-map routes not present in "router2" BGP table - PASSED!!! 2020-10-14 17:02:00,736 INFO: '_non_exist_map_routes_not_present' polling started (interval 1 secs, maximum wait 90 secs) 2020-10-14 17:02:59,215 INFO: '_non_exist_map_routes_not_present' succeeded after 58.48 seconds 2020-10-14 17:02:59,215 INFO: TC31: non-exist-map routes not present in "router2" BGP table - PASSED!!! 2020-10-14 17:02:59,968 INFO: '_non_exist_map_routes_present' polling started (interval 1 secs, maximum wait 90 secs) 2020-10-14 17:03:59,300 INFO: '_non_exist_map_routes_present' succeeded after 59.33 seconds 2020-10-14 17:03:59,300 INFO: TC32: non-exist-map routes present in "router2" BGP table - PASSED!!! 2020-10-14 17:03:59,919 INFO: '_non_exist_map_no_condition_route_map' polling started (interval 1 secs, maximum wait 90 secs) 2020-10-14 17:05:00,306 INFO: '_non_exist_map_no_condition_route_map' succeeded after 60.39 seconds 2020-10-14 17:05:00,306 INFO: TC41: non-exist-map route-map removed in "router2" - PASSED!!! 2020-10-14 17:05:01,024 INFO: '_exist_map_no_condition_route_map' polling started (interval 1 secs, maximum wait 90 secs) 2020-10-14 17:05:59,405 INFO: '_exist_map_no_condition_route_map' succeeded after 58.38 seconds 2020-10-14 17:05:59,406 INFO: TC42: exist-map route-map removed in "router2" - PASSED!!! 2020-10-14 17:05:59,941 INFO: '_exist_map_routes_present_rmap_filter' polling started (interval 1 secs, maximum wait 90 secs) 2020-10-14 17:06:59,622 INFO: '_exist_map_routes_present_rmap_filter' succeeded after 59.68 seconds 2020-10-14 17:06:59,622 INFO: TC51: exist-map routes present with route-map filter - PASSED!!! 2020-10-14 17:07:00,150 INFO: '_exist_map_routes_present_no_rmap_filter' polling started (interval 1 secs, maximum wait 90 secs) 2020-10-14 17:07:00,688 INFO: '_exist_map_routes_present_no_rmap_filter' succeeded after 0.54 seconds 2020-10-14 17:07:00,688 INFO: TC52: exist-map routes present, no route-map filter - PASSED!!! 2020-10-14 17:07:01,229 INFO: '_non_exist_map_routes_present_rmap_filter' polling started (interval 1 secs, maximum wait 90 secs) 2020-10-14 17:07:01,767 INFO: '_non_exist_map_routes_present_rmap_filter' succeeded after 0.54 seconds 2020-10-14 17:07:01,767 INFO: TC53: non-exist-map routes present, with route-map filter - PASSED!!! 2020-10-14 17:07:02,321 INFO: '_non_exist_map_routes_present_no_rmap_filter' polling started (interval 1 secs, maximum wait 90 secs) 2020-10-14 17:08:00,419 INFO: '_non_exist_map_routes_present_no_rmap_filter' succeeded after 58.10 seconds 2020-10-14 17:08:00,419 INFO: TC54: non-exist-map routes present, no route-map filter - PASSED!!! 2020-10-14 17:08:01,485 INFO: '_exist_map_routes_not_present_rmap_filter' polling started (interval 1 secs, maximum wait 90 secs) 2020-10-14 17:08:02,039 INFO: '_exist_map_routes_not_present_rmap_filter' succeeded after 0.55 seconds 2020-10-14 17:08:02,039 INFO: TC61: exist-map routes not present, route-map filter - PASSED!!! 2020-10-14 17:08:02,568 INFO: '_exist_map_routes_not_present_no_rmap_filter' polling started (interval 1 secs, maximum wait 90 secs) 2020-10-14 17:08:59,147 INFO: '_exist_map_routes_not_present_no_rmap_filter' succeeded after 56.58 seconds 2020-10-14 17:08:59,147 INFO: TC62: exist-map routes not present, no route-map filter - PASSED!!! 2020-10-14 17:08:59,686 INFO: '_non_exist_map_routes_not_present_rmap_filter' polling started (interval 1 secs, maximum wait 90 secs) 2020-10-14 17:09:59,354 INFO: '_non_exist_map_routes_not_present_rmap_filter' succeeded after 59.67 seconds 2020-10-14 17:09:59,354 INFO: TC63: non-exist-map routes not present, route-map filter - PASSED!!! 2020-10-14 17:09:59,886 INFO: '_non_exist_map_routes_not_present_no_rmap_filter' polling started (interval 1 secs, maximum wait 90 secs) 2020-10-14 17:10:00,424 INFO: '_non_exist_map_routes_not_present_no_rmap_filter' succeeded after 0.54 seconds 2020-10-14 17:10:00,424 INFO: TC64: non-exist-map routes not present, no route-map filter - PASSED!!! .2020-10-14 17:10:01,989 INFO: assert skipped at "bgp_conditional_advertisement.test_bgp_conditional_advertisement/test_memory_leak": Memory leak test/report is disabled s2020-10-14 17:10:01,989 INFO: Running teardown_module to delete topology 2020-10-14 17:10:01,990 INFO: stopping topology: bgp_conditional_advertisement.test_bgp_conditional_advertisement 2020-10-14 17:10:01,990 INFO: stopping "s2" 2020-10-14 17:10:01,990 INFO: stopping "s1" 2020-10-14 17:10:01,993 INFO: r1: stopping bgpd 2020-10-14 17:10:01,995 INFO: r1: stopping staticd 2020-10-14 17:10:02,010 INFO: r1: stopping zebra 2020-10-14 17:10:02,013 INFO: r1: stopping bgpd 2020-10-14 17:10:02,015 INFO: r1: stopping zebra 2020-10-14 17:10:02,025 INFO: r1: waiting for daemons stopping: bgpd, zebra (0.1 seconds) 2020-10-14 17:10:02,143 INFO: r2: stopping bgpd 2020-10-14 17:10:02,147 INFO: r2: stopping staticd 2020-10-14 17:10:02,152 INFO: r2: stopping zebra 2020-10-14 17:10:02,156 INFO: r2: stopping bgpd 2020-10-14 17:10:02,164 INFO: r2: stopping zebra 2020-10-14 17:10:02,175 INFO: r2: waiting for daemons stopping: zebra (0.1 seconds) 2020-10-14 17:10:02,291 INFO: r3: stopping bgpd 2020-10-14 17:10:02,302 INFO: r3: stopping staticd 2020-10-14 17:10:02,309 INFO: r3: stopping zebra 2020-10-14 17:10:02,313 INFO: r3: stopping bgpd 2020-10-14 17:10:02,316 INFO: r3: stopping zebra 2020-10-14 17:10:02,323 INFO: r3: waiting for daemons stopping: zebra (0.1 seconds) 2020-10-14 17:10:03,615 INFO: Testsuite end time: Wed Oct 14 17:10:03 2020 2020-10-14 17:10:03,615 INFO: ======================================== ================================================================================== 1 passed, 1 skipped in 556.55 seconds =================================================================================== Signed-off-by: Madhuri Kuruganti temp Signed-off-by: Madhuri Kuruganti --- bgpd/bgp_conditional_adv.c | 6 +- bgpd/bgp_vty.c | 23 +- bgpd/bgpd.c | 113 ++-- bgpd/bgpd.h | 10 +- doc/user/bgp.rst | 114 ++-- .../bgp_conditional_advertisement/__init__.py | 0 .../r1/bgpd.conf | 30 + .../r1/zebra.conf | 19 + .../r2/bgpd.conf | 33 + .../r2/zebra.conf | 15 + .../r3/bgpd.conf | 11 + .../r3/zebra.conf | 12 + .../test_bgp_conditional_advertisement.py | 585 ++++++++++++++++++ 13 files changed, 845 insertions(+), 126 deletions(-) create mode 100644 tests/topotests/bgp_conditional_advertisement/__init__.py create mode 100644 tests/topotests/bgp_conditional_advertisement/r1/bgpd.conf create mode 100644 tests/topotests/bgp_conditional_advertisement/r1/zebra.conf create mode 100644 tests/topotests/bgp_conditional_advertisement/r2/bgpd.conf create mode 100644 tests/topotests/bgp_conditional_advertisement/r2/zebra.conf create mode 100644 tests/topotests/bgp_conditional_advertisement/r3/bgpd.conf create mode 100644 tests/topotests/bgp_conditional_advertisement/r3/zebra.conf create mode 100644 tests/topotests/bgp_conditional_advertisement/test_bgp_conditional_advertisement.py diff --git a/bgpd/bgp_conditional_adv.c b/bgpd/bgp_conditional_adv.c index 07b3b4143b..521c8056f5 100644 --- a/bgpd/bgp_conditional_adv.c +++ b/bgpd/bgp_conditional_adv.c @@ -222,11 +222,11 @@ static int bgp_conditional_adv_timer(struct thread *t) * validation. */ if (filter->advmap.condition == CONDITION_EXIST) - filter->advmap.advertise = + filter->advmap.update_type = (ret == RMAP_PERMITMATCH) ? ADVERTISE : WITHDRAW; else - filter->advmap.advertise = + filter->advmap.update_type = (ret == RMAP_PERMITMATCH) ? WITHDRAW : ADVERTISE; @@ -249,7 +249,7 @@ static int bgp_conditional_adv_timer(struct thread *t) /* Send update as per the conditional advertisement */ bgp_conditional_adv_routes(peer, afi, safi, table, filter->advmap.amap, - filter->advmap.advertise); + filter->advmap.update_type); } peer->advmap_table_change = false; } diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 17a4411c82..bb202718ac 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -10774,6 +10774,7 @@ static void bgp_show_peer_afi(struct vty *vty, struct peer *p, afi_t afi, json_object *json_prefA = NULL; json_object *json_prefB = NULL; json_object *json_addr = NULL; + json_object *json_advmap = NULL; if (use_json) { json_addr = json_object_new_object(); @@ -11048,6 +11049,26 @@ static void bgp_show_peer_afi(struct vty *vty, struct peer *p, afi_t afi, "selectiveUnsuppressRouteMap", filter->usmap.name); + /* advertise-map */ + if (filter->advmap.aname) { + json_advmap = json_object_new_object(); + json_object_string_add(json_advmap, "condition", + filter->advmap.condition + ? "EXIST" + : "NON_EXIST"); + json_object_string_add(json_advmap, "conditionMap", + filter->advmap.cname); + json_object_string_add(json_advmap, "advertiseMap", + filter->advmap.aname); + json_object_string_add(json_advmap, "advertiseStatus", + filter->advmap.update_type + == ADVERTISE + ? "Advertise" + : "Withdraw"); + json_object_object_add(json_addr, "advertiseMap", + json_advmap); + } + /* Receive prefix count */ json_object_int_add(json_addr, "acceptedPrefixCounter", p->pcount[afi][safi]); @@ -11353,7 +11374,7 @@ static void bgp_show_peer_afi(struct vty *vty, struct peer *p, afi_t afi, filter->advmap.cname, filter->advmap.amap ? "*" : "", filter->advmap.aname, - filter->advmap.advertise == ADVERTISE + filter->advmap.update_type == ADVERTISE ? "Advertise" : "Withdraw"); diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 0e8970d685..db72eb1775 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -6586,57 +6586,53 @@ int peer_unsuppress_map_unset(struct peer *peer, afi_t afi, safi_t safi) return 0; } -static void peer_update_rmap_filter_data(struct peer *peer, afi_t afi, - safi_t safi, const char *rmap_name1, - struct route_map *rmap1, - const char *rmap_name2, - struct route_map *rmap2, - uint8_t config_flags) +static void peer_advertise_map_filter_update(struct peer *peer, afi_t afi, + safi_t safi, const char *amap_name, + struct route_map *amap, + const char *cmap_name, + struct route_map *cmap, + bool condition, bool set) { struct bgp_filter *filter; bool filter_exists = false; filter = &peer->filter[afi][safi]; - if (CHECK_FLAG(config_flags, BGP_PEER_ADVERTISE_MAP)) { - /* advertise-map is already configured. */ - if (filter->advmap.aname) { - filter_exists = true; - XFREE(MTYPE_BGP_FILTER_NAME, filter->advmap.aname); - XFREE(MTYPE_BGP_FILTER_NAME, filter->advmap.cname); - } - route_map_counter_decrement(filter->advmap.amap); + /* advertise-map is already configured. */ + if (filter->advmap.aname) { + filter_exists = true; + XFREE(MTYPE_BGP_FILTER_NAME, filter->advmap.aname); + XFREE(MTYPE_BGP_FILTER_NAME, filter->advmap.cname); + } - /* Removed advertise-map configuration */ - if (!CHECK_FLAG(config_flags, BGP_PEER_RMAP_SET)) { - memset(filter, 0, sizeof(struct bgp_filter)); + route_map_counter_decrement(filter->advmap.amap); - /* decrement condition_filter_count delete timer if - * this is the last advertise-map to be removed. - */ - if (filter_exists) - bgp_conditional_adv_disable(peer, afi, safi); + /* Removed advertise-map configuration */ + if (!set) { + memset(filter, 0, sizeof(struct bgp_filter)); - return; - } + /* decrement condition_filter_count delete timer if + * this is the last advertise-map to be removed. + */ + if (filter_exists) + bgp_conditional_adv_disable(peer, afi, safi); - /* Update filter data with newly configured values. */ - filter->advmap.aname = - XSTRDUP(MTYPE_BGP_FILTER_NAME, rmap_name1); - filter->advmap.cname = - XSTRDUP(MTYPE_BGP_FILTER_NAME, rmap_name2); - filter->advmap.amap = rmap1; - filter->advmap.cmap = rmap2; - filter->advmap.condition = - CHECK_FLAG(config_flags, BGP_PEER_CONDITION_EXIST); - route_map_counter_increment(filter->advmap.amap); - peer->advmap_config_change[afi][safi] = true; + return; + } - /* Increment condition_filter_count and/or create timer. */ - if (!filter_exists) { - filter->advmap.advertise = ADVERTISE; - bgp_conditional_adv_enable(peer, afi, safi); - } + /* Update filter data with newly configured values. */ + filter->advmap.aname = XSTRDUP(MTYPE_BGP_FILTER_NAME, amap_name); + filter->advmap.cname = XSTRDUP(MTYPE_BGP_FILTER_NAME, cmap_name); + filter->advmap.amap = amap; + filter->advmap.cmap = cmap; + filter->advmap.condition = condition; + route_map_counter_increment(filter->advmap.amap); + peer->advmap_config_change[afi][safi] = true; + + /* Increment condition_filter_count and/or create timer. */ + if (!filter_exists) { + filter->advmap.update_type = ADVERTISE; + bgp_conditional_adv_enable(peer, afi, safi); } } @@ -6653,19 +6649,13 @@ int peer_advertise_map_set(struct peer *peer, afi_t afi, safi_t safi, const char *condition_name, struct route_map *condition_map, bool condition) { - uint8_t config_flags = 0; struct peer *member; struct listnode *node, *nnode; - SET_FLAG(config_flags, BGP_PEER_RMAP_SET); - SET_FLAG(config_flags, BGP_PEER_ADVERTISE_MAP); - if (condition) - SET_FLAG(config_flags, BGP_PEER_CONDITION_EXIST); - /* Set configuration on peer. */ - peer_update_rmap_filter_data(peer, afi, safi, advertise_name, - advertise_map, condition_name, - condition_map, config_flags); + peer_advertise_map_filter_update(peer, afi, safi, advertise_name, + advertise_map, condition_name, + condition_map, condition, true); /* Check if handling a regular peer & Skip peer-group mechanics. */ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { @@ -6686,9 +6676,9 @@ int peer_advertise_map_set(struct peer *peer, afi_t afi, safi_t safi, continue; /* Set configuration on peer-group member. */ - peer_update_rmap_filter_data(member, afi, safi, advertise_name, - advertise_map, condition_name, - condition_map, config_flags); + peer_advertise_map_filter_update( + member, afi, safi, advertise_name, advertise_map, + condition_name, condition_map, condition, true); } return 0; @@ -6701,13 +6691,12 @@ int peer_advertise_map_unset(struct peer *peer, afi_t afi, safi_t safi, const char *condition_name, struct route_map *condition_map, bool condition) { - uint8_t config_flags = 0; struct peer *member; struct listnode *node, *nnode; - SET_FLAG(config_flags, BGP_PEER_ADVERTISE_MAP); - if (condition) - SET_FLAG(config_flags, BGP_PEER_CONDITION_EXIST); + /* advertise-map is not configured */ + if (!peer->filter[afi][safi].advmap.aname) + return 0; /* Unset override-flag unconditionally. */ UNSET_FLAG(peer->filter_override[afi][safi][RMAP_OUT], @@ -6721,9 +6710,9 @@ int peer_advertise_map_unset(struct peer *peer, afi_t afi, safi_t safi, PEER_ATTR_INHERIT(peer, peer->group, filter[afi][safi].advmap.amap); } else - peer_update_rmap_filter_data(peer, afi, safi, advertise_name, - advertise_map, condition_name, - condition_map, config_flags); + peer_advertise_map_filter_update( + peer, afi, safi, advertise_name, advertise_map, + condition_name, condition_map, condition, false); /* Check if handling a regular peer and skip peer-group mechanics. */ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { @@ -6742,9 +6731,9 @@ int peer_advertise_map_unset(struct peer *peer, afi_t afi, safi_t safi, PEER_FT_ADVERTISE_MAP)) continue; /* Remove configuration on peer-group member. */ - peer_update_rmap_filter_data(member, afi, safi, advertise_name, - advertise_map, condition_name, - condition_map, config_flags); + peer_advertise_map_filter_update( + member, afi, safi, advertise_name, advertise_map, + condition_name, condition_map, condition, false); /* Process peer route updates. */ peer_on_policy_change(member, afi, safi, 1); diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 39efab2899..4eb5bdd018 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -767,14 +767,6 @@ struct bgp_nexthop { #define CONDITION_NON_EXIST false #define CONDITION_EXIST true -/* BGP peer RMAP options */ -#define BGP_PEER_ADVERTISE_MAP (1 << 0) -#define BGP_PEER_ROUTE_MAP (1 << 1) -#define BGP_PEER_UNSUPPRESS_MAP (1 << 2) -#define BGP_PEER_CONDITION_EXIST (1 << 3) -#define BGP_PEER_RMAP_DIRECTION (1 << 4) -#define BGP_PEER_RMAP_SET (1 << 5) - enum update_type { WITHDRAW, ADVERTISE }; #include "filter.h" @@ -821,7 +813,7 @@ struct bgp_filter { char *cname; struct route_map *cmap; - enum update_type advertise; + enum update_type update_type; } advmap; }; diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst index f79d33a260..339be7f4d6 100644 --- a/doc/user/bgp.rst +++ b/doc/user/bgp.rst @@ -2633,16 +2633,22 @@ when the next instance of the BGP scanner occurs. .. index:: [no] neighbor A.B.C.D advertise-map NAME [exist-map|non-exist-map] NAME .. clicmd:: [no] neighbor A.B.C.D advertise-map NAME [exist-map|non-exist-map] NAME - This command enables BGP scanner process to monitor route specified by + This command enables BGP scanner process to monitor routes specified by exist-map or non-exist-map command in BGP table and conditionally advertises - the route specified by advertise-map command. + the routes specified by advertise-map command. Sample Configuration ^^^^^^^^^^^^^^^^^^^^^ .. code-block:: frr + interface enp0s9 + ip address 10.10.10.2/24 + ! + interface enp0s10 + ip address 10.10.20.2/24 + ! interface lo - ip address 2.2.2.2/24 + ip address 203.0.113.1/32 ! router bgp 2 bgp log-neighbor-changes @@ -2651,125 +2657,131 @@ Sample Configuration neighbor 10.10.20.3 remote-as 3 ! address-family ipv4 unicast - network 2.2.2.0/24 - network 20.20.0.0/16 neighbor 10.10.10.1 soft-reconfiguration inbound - neighbor 10.10.10.1 advertise-map ADVERTISE non-exist-map CONDITION neighbor 10.10.20.3 soft-reconfiguration inbound + neighbor 10.10.20.3 advertise-map ADV-MAP non-exist-map EXIST-MAP exit-address-family ! - access-list CONDITION seq 5 permit 3.3.3.0/24 - access-list ADVERTISE seq 5 permit 2.2.2.0/24 + ip prefix-list DEFAULT seq 5 permit 192.0.2.5/32 + ip prefix-list DEFAULT seq 10 permit 192.0.2.1/32 + ip prefix-list EXIST seq 5 permit 10.10.10.10/32 + ip prefix-list DEFAULT-ROUTE seq 5 permit 0.0.0.0/0 + ip prefix-list IP1 seq 5 permit 10.139.224.0/20 ! - route-map ADVERTISE permit 10 - match ip address ADVERTISE + bgp community-list standard DC-ROUTES seq 5 permit 64952:3008 + bgp community-list standard DC-ROUTES seq 10 permit 64671:501 + bgp community-list standard DC-ROUTES seq 15 permit 64950:3009 + bgp community-list standard DEFAULT-ROUTE seq 5 permit 65013:200 ! - route-map CONDITION permit 10 - match ip address CONDITION + route-map ADV-MAP permit 10 + match ip address prefix-list IP1 + ! + route-map ADV-MAP permit 20 + match community DC-ROUTES + ! + route-map EXIST-MAP permit 10 + match community DEFAULT-ROUTE + match ip address prefix-list DEFAULT-ROUTE ! Sample Output ^^^^^^^^^^^^^ -When 3.3.3.0/24 route is in R2'2 BGP rable, 2.2.2/0/24 is not adevrtised to R1. +When default route is present in R2'2 BGP table, 10.139.224.0/20 and 192.0.2.1/32 are not advertised to R3. .. code-block:: frr Router2# show ip bgp - BGP table version is 24, local router ID is 128.16.16.1, vrf id 0 + BGP table version is 20, local router ID is 203.0.113.1, vrf id 0 Default local pref 100, local AS 2 Status codes: s suppressed, d damped, h history, * valid, > best, = multipath, i internal, r RIB-failure, S Stale, R Removed Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self Origin codes: i - IGP, e - EGP, ? - incomplete - Network Next Hop Metric LocPrf Weight Path - *> 1.1.1.0/24 10.10.10.1 0 0 1 i - *> 2.2.2.0/24 0.0.0.0 0 32768 i - *> 3.3.3.0/24 10.10.20.3 0 0 3 i - *> 20.20.0.0/16 0.0.0.0 0 32768 i + Network Next Hop Metric LocPrf Weight Path + *> 0.0.0.0/0 10.10.10.1 0 0 1 i + *> 10.139.224.0/20 10.10.10.1 0 0 1 ? + *> 192.0.2.1/32 10.10.10.1 0 0 1 i + *> 192.0.2.5/32 10.10.10.1 0 0 1 i Displayed 4 routes and 4 total paths - Router2# - - Router2# show ip bgp neighbors 10.10.10.1 + Router2# show ip bgp neighbors 10.10.20.3 !--- Output suppressed. For address family: IPv4 Unicast - Update group 5, subgroup 1 + Update group 7, subgroup 7 Packet Queue length 0 Inbound soft reconfiguration allowed Community attribute sent to this neighbor(all) - Condition NON_EXIST, Condition-map *CONDITION, Advertise-map *ADVERTISE, status: Withdraw - 1 accepted prefixes + Condition NON_EXIST, Condition-map *EXIST-MAP, Advertise-map *ADV-MAP, status: Withdraw + 0 accepted prefixes !--- Output suppressed. - Router2# show ip bgp neighbors 10.10.10.1 advertised-routes - BGP table version is 24, local router ID is 128.16.16.1, vrf id 0 + Router2# show ip bgp neighbors 10.10.20.3 advertised-routes + BGP table version is 20, local router ID is 203.0.113.1, vrf id 0 Default local pref 100, local AS 2 Status codes: s suppressed, d damped, h history, * valid, > best, = multipath, - i internal, r RIB-failure, S Stale, R Removed + i internal, r RIB-failure, S Stale, R Removed Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self Origin codes: i - IGP, e - EGP, ? - incomplete - Network Next Hop Metric LocPrf Weight Path - *> 1.1.1.0/24 0.0.0.0 0 1 i - *> 3.3.3.0/24 0.0.0.0 0 3 i - *> 20.20.0.0/16 0.0.0.0 0 32768 i + Network Next Hop Metric LocPrf Weight Path + *> 0.0.0.0/0 0.0.0.0 0 1 i + *> 192.0.2.5/32 0.0.0.0 0 1 i - Total number of prefixes 3 - Router2# + Total number of prefixes 2 -When 3.3.3.0/24 route is not in R2'2 BGP rable, 2.2.2/0/24 is adevrtised to R1. +When default route is not present in R2'2 BGP table, 10.139.224.0/20 and 192.0.2.1/32 are advertised to R3. .. code-block:: frr Router2# show ip bgp - BGP table version is 25, local router ID is 128.16.16.1, vrf id 0 + BGP table version is 21, local router ID is 203.0.113.1, vrf id 0 Default local pref 100, local AS 2 Status codes: s suppressed, d damped, h history, * valid, > best, = multipath, i internal, r RIB-failure, S Stale, R Removed Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self Origin codes: i - IGP, e - EGP, ? - incomplete - Network Next Hop Metric LocPrf Weight Path - *> 1.1.1.0/24 10.10.10.1 0 0 1 i - *> 2.2.2.0/24 0.0.0.0 0 32768 i - *> 20.20.0.0/16 0.0.0.0 0 32768 i + Network Next Hop Metric LocPrf Weight Path + *> 10.139.224.0/20 10.10.10.1 0 0 1 ? + *> 192.0.2.1/32 10.10.10.1 0 0 1 i + *> 192.0.2.5/32 10.10.10.1 0 0 1 i Displayed 3 routes and 3 total paths - Router2# - Router2# show ip bgp neighbors 10.10.10.1 + Router2# show ip bgp neighbors 10.10.20.3 !--- Output suppressed. For address family: IPv4 Unicast - Update group 5, subgroup 1 + Update group 7, subgroup 7 Packet Queue length 0 Inbound soft reconfiguration allowed Community attribute sent to this neighbor(all) - Condition NON_EXIST, Condition-map *CONDITION, Advertise-map *ADVERTISE, status: Advertise - 1 accepted prefixes + Condition NON_EXIST, Condition-map *EXIST-MAP, Advertise-map *ADV-MAP, status: Advertise + 0 accepted prefixes !--- Output suppressed. - Router2# show ip bgp neighbors 10.10.10.1 advertised-routes - BGP table version is 25, local router ID is 128.16.16.1, vrf id 0 + Router2# show ip bgp neighbors 10.10.20.3 advertised-routes + BGP table version is 21, local router ID is 203.0.113.1, vrf id 0 Default local pref 100, local AS 2 Status codes: s suppressed, d damped, h history, * valid, > best, = multipath, i internal, r RIB-failure, S Stale, R Removed Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self Origin codes: i - IGP, e - EGP, ? - incomplete - Network Next Hop Metric LocPrf Weight Path - *> 1.1.1.0/24 0.0.0.0 0 1 i - *> 2.2.2.0/24 0.0.0.0 0 32768 i - *> 20.20.0.0/16 0.0.0.0 0 32768 i + Network Next Hop Metric LocPrf Weight Path + *> 10.139.224.0/20 0.0.0.0 0 1 ? + *> 192.0.2.1/32 0.0.0.0 0 1 i + *> 192.0.2.5/32 0.0.0.0 0 1 i Total number of prefixes 3 + Router2# .. _bgp-debugging: diff --git a/tests/topotests/bgp_conditional_advertisement/__init__.py b/tests/topotests/bgp_conditional_advertisement/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/topotests/bgp_conditional_advertisement/r1/bgpd.conf b/tests/topotests/bgp_conditional_advertisement/r1/bgpd.conf new file mode 100644 index 0000000000..633d1832fd --- /dev/null +++ b/tests/topotests/bgp_conditional_advertisement/r1/bgpd.conf @@ -0,0 +1,30 @@ +! +ip prefix-list CUST seq 5 permit 10.139.224.0/20 +ip prefix-list DEFAULT seq 5 permit 0.0.0.0/0 +ip prefix-list PL1 seq 5 permit 192.0.2.1/32 +! +route-map CUST permit 10 + match ip address prefix-list CUST + set community 64671:501 +! +route-map RM1 permit 10 + match ip address prefix-list PL1 + set community 64952:3008 +! +route-map DEF permit 10 + match ip address prefix-list DEFAULT + set community 64848:3011 65011:200 65013:200 +! +router bgp 1 + bgp log-neighbor-changes + no bgp ebgp-requires-policy + neighbor 10.10.10.2 remote-as 2 + ! + address-family ipv4 unicast + network 0.0.0.0/0 route-map DEF + network 192.0.2.1/32 route-map RM1 + network 192.0.2.5/32 + redistribute connected route-map CUST + neighbor 10.10.10.2 soft-reconfiguration inbound + exit-address-family +! diff --git a/tests/topotests/bgp_conditional_advertisement/r1/zebra.conf b/tests/topotests/bgp_conditional_advertisement/r1/zebra.conf new file mode 100644 index 0000000000..bb887e41ad --- /dev/null +++ b/tests/topotests/bgp_conditional_advertisement/r1/zebra.conf @@ -0,0 +1,19 @@ +! +hostname Router1 +! +ip route 0.0.0.0/0 blackhole +ip route 192.0.2.1/32 blackhole +ip route 192.0.2.2/32 blackhole +ip route 192.0.2.3/32 blackhole +ip route 192.0.2.4/32 blackhole +ip route 192.0.2.5/32 blackhole +! +interface r1-eth0 + ip address 10.10.10.1/24 +! +interface lo + ip address 10.139.224.1/20 +! +ip forwarding +ipv6 forwarding +! diff --git a/tests/topotests/bgp_conditional_advertisement/r2/bgpd.conf b/tests/topotests/bgp_conditional_advertisement/r2/bgpd.conf new file mode 100644 index 0000000000..c8f4357f99 --- /dev/null +++ b/tests/topotests/bgp_conditional_advertisement/r2/bgpd.conf @@ -0,0 +1,33 @@ +! +ip prefix-list DEFAULT seq 5 permit 192.0.2.5/32 +ip prefix-list DEFAULT seq 10 permit 192.0.2.1/32 +ip prefix-list EXIST seq 5 permit 10.10.10.10/32 +ip prefix-list DEFAULT-ROUTE seq 5 permit 0.0.0.0/0 +ip prefix-list IP1 seq 5 permit 10.139.224.0/20 +! +bgp community-list standard DC-ROUTES seq 5 permit 64952:3008 +bgp community-list standard DC-ROUTES seq 10 permit 64671:501 +bgp community-list standard DC-ROUTES seq 15 permit 64950:3009 +bgp community-list standard DEFAULT-ROUTE seq 5 permit 65013:200 +! +route-map ADV-MAP permit 10 + match ip address prefix-list IP1 +! +route-map ADV-MAP permit 20 + match community DC-ROUTES +! +route-map EXIST-MAP permit 10 + match community DEFAULT-ROUTE + match ip address prefix-list DEFAULT-ROUTE +! +router bgp 2 + bgp log-neighbor-changes + no bgp ebgp-requires-policy + neighbor 10.10.10.1 remote-as 1 + neighbor 10.10.20.3 remote-as 3 + ! + address-family ipv4 unicast + neighbor 10.10.10.1 soft-reconfiguration inbound + neighbor 10.10.20.3 soft-reconfiguration inbound + exit-address-family +! diff --git a/tests/topotests/bgp_conditional_advertisement/r2/zebra.conf b/tests/topotests/bgp_conditional_advertisement/r2/zebra.conf new file mode 100644 index 0000000000..434ab68e3c --- /dev/null +++ b/tests/topotests/bgp_conditional_advertisement/r2/zebra.conf @@ -0,0 +1,15 @@ +! +hostname Router2 +! +interface r2-eth0 + ip address 10.10.10.2/24 +! +interface r2-eth1 + ip address 10.10.20.2/24 +! +interface lo + ip address 203.0.113.1/32 +! +ip forwarding +ipv6 forwarding +! diff --git a/tests/topotests/bgp_conditional_advertisement/r3/bgpd.conf b/tests/topotests/bgp_conditional_advertisement/r3/bgpd.conf new file mode 100644 index 0000000000..2f4f5068d8 --- /dev/null +++ b/tests/topotests/bgp_conditional_advertisement/r3/bgpd.conf @@ -0,0 +1,11 @@ +! +router bgp 3 + bgp log-neighbor-changes + no bgp ebgp-requires-policy + neighbor 10.10.20.2 remote-as 2 + ! + address-family ipv4 unicast + neighbor 10.10.20.2 soft-reconfiguration inbound + exit-address-family +! + diff --git a/tests/topotests/bgp_conditional_advertisement/r3/zebra.conf b/tests/topotests/bgp_conditional_advertisement/r3/zebra.conf new file mode 100644 index 0000000000..0dadfdb3a9 --- /dev/null +++ b/tests/topotests/bgp_conditional_advertisement/r3/zebra.conf @@ -0,0 +1,12 @@ +! +hostname Router3 +! +interface r3-eth0 + ip address 10.10.20.3/24 +! +interface lo + ip address 198.51.100.1/32 +! +ip forwarding +ipv6 forwarding +! diff --git a/tests/topotests/bgp_conditional_advertisement/test_bgp_conditional_advertisement.py b/tests/topotests/bgp_conditional_advertisement/test_bgp_conditional_advertisement.py new file mode 100644 index 0000000000..e509882448 --- /dev/null +++ b/tests/topotests/bgp_conditional_advertisement/test_bgp_conditional_advertisement.py @@ -0,0 +1,585 @@ +#!/usr/bin/env python + +# +# test_bgp_conditional_advertisement.py +# Part of NetDEF Topology Tests +# +# Copyright (c) 2020 by +# Network Device Education Foundation, Inc. ("NetDEF") +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# + +""" +Test BGP conditional advertisement functionality. + + +--------+ +--------+ +--------+ + | | | | | | + | R1 |------------| R2 |------------| R3 | + | | | | | | + +--------+ +--------+ +--------+ + +R2 is DUT and peers with R1 and R3 in default bgp instance. + +Following tests are covered under BGP conditional advertisement functionality. +Conditional advertisement +------------------------- +TC11: R3 BGP convergence, without advertise-map configuration. + All routes are advertised to R3. +TC21: exist-map routes present in R2's BGP table. + advertise-map routes present in R2's BGP table are advertised to R3. +TC22: exist-map routes not present in R2's BGP table + advertise-map routes present in R2's BGP table are withdrawn from R3. +TC31: non-exist-map routes not present in R2's BGP table + advertise-map routes present in R2's BGP table are advertised to R3. +TC32: non-exist-map routes present in R2's BGP table + advertise-map routes present in R2's BGP table are withdrawn from R3. +TC41: non-exist-map route-map configuration removed in R2. + advertise-map routes present in R2's BGP table are advertised to R3. +TC42: exist-map route-map configuration removed in R2 + advertise-map routes present in R2's BGP table are withdrawn from R3. + +Conditional advertisement along with Route-map Filter +----------------------------------------------------- +TC51: exist-map routes present in R2's BGP table, with route-map filter. + All routes are withdrawn from R3 except advertise-map routes. +TC52: exist-map routes present in R2's BGP table, without route-map filter. + All routes are advertised to R3 including advertise-map routes. +TC53: non-exist-map routes present in R2's BGP table, with route-map filter. + All routes are withdrawn from R3 including advertise-map routes. +TC54: non-exist-map routes present in R2's BGP table, without route-map filter. + All routes are advertised to R3 except advertise-map routes. +TC61: exist-map routes not present in R2's BGP table, with route-map filter. + All routes are withdrawn from R3 including advertise-map routes. +TC62: exist-map routes not present in R2's BGP table, without route-map filter. + All routes are advertised to R3 except advertise-map routes. +TC63: non-exist-map routes not present in R2's BGP table, with route-map filter. + All routes are withdrawn from R3 except advertise-map routes. +TC64: non-exist-map routes not present in R2's BGP table, without route-map filter. + All routes are advertised to R3 including advertise-map routes. + + +i.e. ++----------------+-------------------------+------------------------+ +| Routes in | exist-map status | advertise-map status | +| BGP table | | | ++----------------+-------------------------+------------------------+ +| Present | Condition matched | Advertise | ++----------------+-------------------------+------------------------+ +| Not Present | Condition not matched | Withdrawn | ++----------------+-------------------------+------------------------+ +| | non-exist-map status | advertise-map status | +| | | | ++----------------+-------------------------+------------------------+ +| Present | Condition matched | Withdrawn | ++----------------+-------------------------+------------------------+ +| Not Present | Condition not matched | Advertise | ++----------------+-------------------------+------------------------+ +Here in this topology, based on the default route presence in R2 and +the configured condition-map (exist-map/non-exist-map) 10.139.224.0/20 +will be either advertised/withdrawn to/from R3. +""" + +import os +import sys +import json +import time +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.topolog import logger +from mininet.topo import Topo + + +class BgpConditionalAdvertisementTopo(Topo): + def build(self, *_args, **_opts): + tgen = get_topogen(self) + + r1 = tgen.add_router("r1") + r2 = tgen.add_router("r2") + r3 = tgen.add_router("r3") + + switch = tgen.add_switch("s1") + switch.add_link(r1) + switch.add_link(r2) + + switch = tgen.add_switch("s2") + switch.add_link(r2) + switch.add_link(r3) + + +def setup_module(mod): + testsuite_run_time = time.asctime(time.localtime(time.time())) + logger.info("Testsuite start time: {}".format(testsuite_run_time)) + logger.info("=" * 40) + + logger.info("Running setup_module to create topology") + + tgen = Topogen(BgpConditionalAdvertisementTopo, 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)) + ) + + tgen.start_router() + + logger.info("Running setup_module() done") + + +def teardown_module(mod): + """ + Teardown the pytest environment + * `mod`: module name + """ + + logger.info("Running teardown_module to delete topology") + + tgen = get_topogen() + tgen.stop_topology() + + logger.info( + "Testsuite end time: {}".format(time.asctime(time.localtime(time.time()))) + ) + logger.info("=" * 40) + + +def test_bgp_conditional_advertisement(): + """ + Test BGP conditional advertisement functionality. + """ + + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + router1 = tgen.gears["r1"] + router2 = tgen.gears["r2"] + router3 = tgen.gears["r3"] + + passed = "PASSED!!!" + failed = "FAILED!!!" + + def _all_routes_advertised(router): + output = json.loads(router.vtysh_cmd("show ip route json")) + expected = { + "0.0.0.0/0": [{"protocol": "bgp"}], + "192.0.2.1/32": [{"protocol": "bgp"}], + "192.0.2.5/32": [{"protocol": "bgp"}], + "10.139.224.0/20": [{"protocol": "bgp"}], + } + return topotest.json_cmp(output, expected) + + def _all_routes_withdrawn(router): + output = json.loads(router.vtysh_cmd("show ip route json")) + expected = { + "0.0.0.0/0": None, + "192.0.2.1/32": None, + "192.0.2.5/32": None, + "10.139.224.0/20": None, + } + return topotest.json_cmp(output, expected) + + def _exist_map_routes_present(router): + return _all_routes_advertised(router) + + def _exist_map_routes_not_present(router): + output = json.loads(router.vtysh_cmd("show ip route json")) + expected = { + "0.0.0.0/0": None, + "192.0.2.1/32": None, + "192.0.2.5/32": [{"protocol": "bgp"}], + "10.139.224.0/20": None, + } + return topotest.json_cmp(output, expected) + + def _non_exist_map_routes_present(router): + output = json.loads(router.vtysh_cmd("show ip route json")) + expected = { + "0.0.0.0/0": [{"protocol": "bgp"}], + "192.0.2.1/32": None, + "192.0.2.5/32": [{"protocol": "bgp"}], + "10.139.224.0/20": None, + } + return topotest.json_cmp(output, expected) + + def _non_exist_map_routes_not_present(router): + output = json.loads(router.vtysh_cmd("show ip route json")) + expected = { + "0.0.0.0/0": None, + "192.0.2.1/32": [{"protocol": "bgp"}], + "192.0.2.5/32": [{"protocol": "bgp"}], + "10.139.224.0/20": [{"protocol": "bgp"}], + } + return topotest.json_cmp(output, expected) + + def _exist_map_no_condition_route_map(router): + return _non_exist_map_routes_present(router) + + def _non_exist_map_no_condition_route_map(router): + return _all_routes_advertised(router) + + def _exist_map_routes_present_rmap_filter(router): + output = json.loads(router.vtysh_cmd("show ip route json")) + expected = { + "0.0.0.0/0": None, + "192.0.2.1/32": [{"protocol": "bgp"}], + "192.0.2.5/32": None, + "10.139.224.0/20": [{"protocol": "bgp"}], + } + return topotest.json_cmp(output, expected) + + def _exist_map_routes_present_no_rmap_filter(router): + return _all_routes_advertised(router) + + def _non_exist_map_routes_present_rmap_filter(router): + return _all_routes_withdrawn(router) + + def _non_exist_map_routes_present_no_rmap_filter(router): + return _non_exist_map_routes_present(router) + + def _exist_map_routes_not_present_rmap_filter(router): + return _all_routes_withdrawn(router) + + def _exist_map_routes_not_present_no_rmap_filter(router): + return _exist_map_routes_not_present(router) + + def _non_exist_map_routes_not_present_rmap_filter(router): + return _exist_map_routes_present_rmap_filter(router) + + def _non_exist_map_routes_not_present_no_rmap_filter(router): + return _non_exist_map_routes_not_present(router) + + # TC11: R3 BGP convergence, without advertise-map configuration. + # All routes are advertised to R3. + test_func = functools.partial(_all_routes_advertised, router3) + success, result = topotest.run_and_expect(test_func, None, count=130, wait=1) + + msg = 'TC11: "router3" BGP convergence - ' + assert result is None, msg + failed + + logger.info(msg + passed) + + # TC21: exist-map routes present in R2's BGP table. + # advertise-map routes present in R2's BGP table are advertised to R3. + router2.vtysh_cmd( + """ + configure terminal + router bgp 2 + address-family ipv4 unicast + neighbor 10.10.20.3 advertise-map ADV-MAP exist-map EXIST-MAP + """ + ) + + test_func = functools.partial(_exist_map_routes_present, router3) + success, 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 + + logger.info(msg + passed) + + # TC22: exist-map routes not present in R2's BGP table + # advertise-map routes present in R2's BGP table are withdrawn from R3. + router1.vtysh_cmd( + """ + configure terminal + router bgp 1 + address-family ipv4 unicast + no network 0.0.0.0/0 route-map DEF + """ + ) + + test_func = functools.partial(_exist_map_routes_not_present, router3) + success, 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 + + logger.info(msg + passed) + + # TC31: non-exist-map routes not present in R2's BGP table + # advertise-map routes present in R2's BGP table are advertised to R3. + router2.vtysh_cmd( + """ + configure terminal + router bgp 2 + address-family ipv4 unicast + neighbor 10.10.20.3 advertise-map ADV-MAP non-exist-map EXIST-MAP + """ + ) + + test_func = functools.partial(_non_exist_map_routes_not_present, router3) + success, 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 + + logger.info(msg + passed) + + # TC32: non-exist-map routes present in R2's BGP table + # advertise-map routes present in R2's BGP table are withdrawn from R3. + router1.vtysh_cmd( + """ + configure terminal + router bgp 1 + address-family ipv4 unicast + network 0.0.0.0/0 route-map DEF + """ + ) + + test_func = functools.partial(_non_exist_map_routes_present, router3) + success, 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 + + logger.info(msg + passed) + + # TC41: non-exist-map route-map configuration removed in R2. + # advertise-map routes present in R2's BGP table are advertised to R3. + router2.vtysh_cmd( + """ + configure terminal + no route-map EXIST-MAP permit 10 + """ + ) + + 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) + + msg = 'TC41: non-exist-map route-map removed in "router2" - ' + assert result is None, msg + failed + + logger.info(msg + passed) + + # TC42: exist-map route-map configuration removed in R2 + # advertise-map routes present in R2's BGP table are withdrawn from R3. + router2.vtysh_cmd( + """ + configure terminal + router bgp 2 + address-family ipv4 unicast + neighbor 10.10.20.3 advertise-map ADV-MAP exist-map EXIST-MAP + """ + ) + + test_func = functools.partial(_exist_map_no_condition_route_map, router3) + success, 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 + + logger.info(msg + passed) + + # TC51: exist-map routes present in R2's BGP table, with route-map filter. + # All routes are withdrawn from R3 except advertise-map routes. + router2.vtysh_cmd( + """ + configure terminal + route-map EXIST-MAP permit 10 + match community DEFAULT-ROUTE + match ip address prefix-list DEFAULT-ROUTE + ! + route-map RMAP deny 10 + match ip address prefix-list IP1 + ! + router bgp 2 + address-family ipv4 unicast + neighbor 10.10.20.3 route-map RMAP out + """ + ) + + test_func = functools.partial(_exist_map_routes_present_rmap_filter, router3) + success, 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 + + logger.info(msg + passed) + + # TC52: exist-map routes present in R2's BGP table, no route-map filter. + # All routes are advertised to R3 including advertise-map routes. + router2.vtysh_cmd( + """ + configure terminal + router bgp 2 + address-family ipv4 unicast + no neighbor 10.10.20.3 route-map RMAP out + """ + ) + + 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) + + msg = "TC52: exist-map routes present, no route-map filter - " + assert result is None, msg + failed + + logger.info(msg + passed) + + # TC53: non-exist-map routes present in R2's BGP table, with route-map filter. + # All routes are withdrawn from R3 including advertise-map routes. + router2.vtysh_cmd( + """ + configure terminal + router bgp 2 + address-family ipv4 unicast + neighbor 10.10.20.3 route-map RMAP out + neighbor 10.10.20.3 advertise-map ADV-MAP non-exist-map EXIST-MAP + """ + ) + + 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) + + msg = "TC53: non-exist-map routes present, with route-map filter - " + assert result is None, msg + failed + + logger.info(msg + passed) + + # TC54: non-exist-map routes present in R2's BGP table, no route-map filter. + # All routes are advertised to R3 except advertise-map routes. + router2.vtysh_cmd( + """ + configure terminal + router bgp 2 + address-family ipv4 unicast + no neighbor 10.10.20.3 route-map RMAP out + """ + ) + + 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) + + msg = "TC54: non-exist-map routes present, no route-map filter - " + assert result is None, msg + failed + + logger.info(msg + passed) + + # TC61: exist-map routes not present in R2's BGP table, with route-map filter. + # All routes are withdrawn from R3 including advertise-map routes. + router1.vtysh_cmd( + """ + configure terminal + router bgp 1 + address-family ipv4 unicast + no network 0.0.0.0/0 route-map DEF + """ + ) + router2.vtysh_cmd( + """ + configure terminal + router bgp 2 + address-family ipv4 unicast + neighbor 10.10.20.3 route-map RMAP out + neighbor 10.10.20.3 advertise-map ADV-MAP exist-map EXIST-MAP + """ + ) + + 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) + + msg = "TC61: exist-map routes not present, route-map filter - " + assert result is None, msg + failed + + logger.info(msg + passed) + + # TC62: exist-map routes not present in R2's BGP table, without route-map filter. + # All routes are advertised to R3 except advertise-map routes. + router2.vtysh_cmd( + """ + configure terminal + router bgp 2 + address-family ipv4 unicast + no neighbor 10.10.20.3 route-map RMAP out + """ + ) + + 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) + + msg = "TC62: exist-map routes not present, no route-map filter - " + assert result is None, msg + failed + + logger.info(msg + passed) + + # TC63: non-exist-map routes not present in R2's BGP table, with route-map filter. + # All routes are withdrawn from R3 except advertise-map routes. + router2.vtysh_cmd( + """ + configure terminal + router bgp 2 + address-family ipv4 unicast + neighbor 10.10.20.3 route-map RMAP out + neighbor 10.10.20.3 advertise-map ADV-MAP non-exist-map EXIST-MAP + """ + ) + + 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) + + msg = "TC63: non-exist-map routes not present, route-map filter - " + assert result is None, msg + failed + + logger.info(msg + passed) + + # TC64: non-exist-map routes not present in R2's BGP table, without route-map filter. + # All routes are advertised to R3 including advertise-map routes. + router2.vtysh_cmd( + """ + configure terminal + router bgp 2 + address-family ipv4 unicast + no neighbor 10.10.20.3 route-map RMAP out + """ + ) + + 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) + + msg = "TC64: non-exist-map routes not present, no route-map filter - " + assert result is None, msg + failed + + logger.info(msg + passed) + + +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 e73c112ef9ebd5a14b817576e08246267a6811be Mon Sep 17 00:00:00 2001 From: Madhuri Kuruganti Date: Fri, 23 Oct 2020 21:39:12 +0530 Subject: [PATCH 7/8] bgpd: conditional advertisement - topotests-2 Signed-off-by: Madhuri Kuruganti --- bgpd/bgp_conditional_adv.c | 58 ++- bgpd/bgp_route.c | 52 ++- bgpd/bgp_route.h | 2 + bgpd/bgp_updgrp_adv.c | 3 + bgpd/bgpd.c | 10 + bgpd/bgpd.h | 2 +- .../r2/bgpd.conf | 15 +- .../test_bgp_conditional_advertisement.py | 414 +++++++++++++++++- 8 files changed, 504 insertions(+), 52 deletions(-) diff --git a/bgpd/bgp_conditional_adv.c b/bgpd/bgp_conditional_adv.c index 521c8056f5..ff1eb2be20 100644 --- a/bgpd/bgp_conditional_adv.c +++ b/bgpd/bgp_conditional_adv.c @@ -50,17 +50,28 @@ bgp_check_rmap_prefixes_in_bgp_table(struct bgp_table *table, ret = route_map_apply(rmap, dest_p, RMAP_BGP, &path); if (ret != RMAP_PERMITMATCH) bgp_attr_flush(&dummy_attr); - else + else { + if (BGP_DEBUG(update, UPDATE_OUT)) + zlog_debug( + "%s: Condition map routes present in BGP table", + __func__); + return ret; + } } } + + if (BGP_DEBUG(update, UPDATE_OUT)) + zlog_debug("%s: Condition map routes not present in BGP table", + __func__); + return ret; } static void bgp_conditional_adv_routes(struct peer *peer, afi_t afi, safi_t safi, struct bgp_table *table, struct route_map *rmap, - enum update_type advertise) + enum update_type update_type) { int addpath_capable; struct bgp_dest *dest; @@ -81,6 +92,11 @@ static void bgp_conditional_adv_routes(struct peer *peer, afi_t afi, if (!subgrp) return; + if (BGP_DEBUG(update, UPDATE_OUT)) + zlog_debug("%s: %s routes to/from %s for %s", __func__, + update_type == ADVERTISE ? "Advertise" : "Withdraw", + peer->host, get_afi_safi_str(afi, safi, false)); + addpath_capable = bgp_addpath_encode_tx(peer, afi, safi); for (dest = bgp_table_top(table); dest; dest = bgp_route_next(dest)) { @@ -115,7 +131,7 @@ static void bgp_conditional_adv_routes(struct peer *peer, afi_t afi, * on same peer, routes in advertise-map may not * be advertised as expected. */ - if ((advertise == ADVERTISE) + if ((update_type == ADVERTISE) && subgroup_announce_check(dest, pi, subgrp, dest_p, &attr, true)) @@ -165,7 +181,6 @@ static int bgp_conditional_adv_timer(struct thread *t) bgp = THREAD_ARG(t); assert(bgp); - bgp->t_condition_check = NULL; thread_add_timer(bm->master, bgp_conditional_adv_timer, bgp, CONDITIONAL_ROUTES_POLL_TIME, &bgp->t_condition_check); @@ -211,6 +226,19 @@ static int bgp_conditional_adv_timer(struct thread *t) && !peer->advmap_table_change) continue; + if (BGP_DEBUG(update, UPDATE_OUT)) { + if (peer->advmap_table_change) + zlog_debug( + "%s: %s - routes changed in BGP table.", + __func__, peer->host); + if (peer->advmap_config_change[afi][safi]) + zlog_debug( + "%s: %s for %s - advertise/condition map configuration is changed.", + __func__, peer->host, + get_afi_safi_str(afi, safi, + false)); + } + /* cmap (route-map attached to exist-map or * non-exist-map) map validation */ @@ -235,6 +263,14 @@ static int bgp_conditional_adv_timer(struct thread *t) * or route-map filter configuration on the same peer. */ if (peer->advmap_config_change[afi][safi]) { + + if (BGP_DEBUG(update, UPDATE_OUT)) + zlog_debug( + "%s: Configuration is changed on peer %s for %s, send the normal update first.", + __func__, peer->host, + get_afi_safi_str(afi, safi, + false)); + paf = peer_af_find(peer, afi, safi); if (paf) { update_subgroup_split_peer(paf, NULL); @@ -271,8 +307,13 @@ void bgp_conditional_adv_enable(struct peer *peer, afi_t afi, safi_t safi) /* advertise-map is already configured on atleast one of its * neighbors (AFI/SAFI). So just increment the counter. */ - if (++bgp->condition_filter_count > 1) + if (++bgp->condition_filter_count > 1) { + if (BGP_DEBUG(update, UPDATE_OUT)) + zlog_debug("%s: condition_filter_count %d", __func__, + bgp->condition_filter_count); + return; + } /* Register for conditional routes polling timer */ thread_add_timer(bm->master, bgp_conditional_adv_timer, bgp, @@ -289,8 +330,13 @@ void bgp_conditional_adv_disable(struct peer *peer, afi_t afi, safi_t safi) * it is configured on more than one neighbor(AFI/SAFI). * So there's nothing to do except decrementing the counter. */ - if (--bgp->condition_filter_count != 0) + if (--bgp->condition_filter_count != 0) { + if (BGP_DEBUG(update, UPDATE_OUT)) + zlog_debug("%s: condition_filter_count %d", __func__, + bgp->condition_filter_count); + return; + } /* Last filter removed. So cancel conditional routes polling thread. */ THREAD_OFF(bgp->t_condition_check); diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 3074531476..366d96b3a7 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -1657,6 +1657,33 @@ void bgp_attr_add_gshut_community(struct attr *attr) } +/* Notify BGP Conditional advertisement scanner process. */ +void bgp_notify_conditional_adv_scanner(struct update_subgroup *subgrp) +{ + struct peer *temp_peer; + struct peer *peer = SUBGRP_PEER(subgrp); + struct listnode *temp_node, *temp_nnode = NULL; + afi_t afi = SUBGRP_AFI(subgrp); + safi_t safi = SUBGRP_SAFI(subgrp); + struct bgp *bgp = SUBGRP_INST(subgrp); + struct bgp_filter *filter = &peer->filter[afi][safi]; + + if (!ADVERTISE_MAP_NAME(filter)) + return; + + for (ALL_LIST_ELEMENTS(bgp->peer, temp_node, temp_nnode, temp_peer)) { + if (!CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE)) + continue; + + if (peer != temp_peer) + continue; + + temp_peer->advmap_table_change = true; + break; + } +} + + static void subgroup_announce_reset_nhop(uint8_t family, struct attr *attr) { if (family == AF_INET) { @@ -1988,8 +2015,7 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi, /* Route map & unsuppress-map apply. */ if (!skip_rmap_check - && (ROUTE_MAP_OUT_NAME(filter) - || (pi->extra && pi->extra->suppress))) { + && (ROUTE_MAP_OUT_NAME(filter) || bgp_path_suppressed(pi))) { struct bgp_path_info rmap_path = {0}; struct bgp_path_info_extra dummy_rmap_path_extra = {0}; struct attr dummy_attr = {0}; @@ -2030,28 +2056,6 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi, peer->host, p); bgp_attr_flush(attr); - - /* TBD : Not sure if this is the correct way to fetch - * peer from group. - * Notify BGP Conditional advertisement scanner process. - */ - if (ADVERTISE_MAP_NAME(filter) - || CONDITION_MAP_NAME(filter)) { - struct peer *temp_peer; - struct listnode *temp_node, *temp_nnode = NULL; - - for (ALL_LIST_ELEMENTS(bgp->peer, temp_node, - temp_nnode, temp_peer)) { - if (!CHECK_FLAG(peer->flags, - PEER_FLAG_CONFIG_NODE)) - continue; - if (strcmp(peer->host, temp_peer->host) - != 0) - continue; - temp_peer->advmap_table_change = true; - break; - } - } return false; } } diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index f770f9cb8d..206cc82b7b 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -671,6 +671,8 @@ extern void route_vty_out_overlay(struct vty *vty, const struct prefix *p, struct bgp_path_info *path, int display, json_object *json); +extern void bgp_notify_conditional_adv_scanner(struct update_subgroup *subgrp); + extern void subgroup_process_announce_selected(struct update_subgroup *subgrp, struct bgp_path_info *selected, struct bgp_dest *dest, diff --git a/bgpd/bgp_updgrp_adv.c b/bgpd/bgp_updgrp_adv.c index ae1359ae46..ac77ccd8a4 100644 --- a/bgpd/bgp_updgrp_adv.c +++ b/bgpd/bgp_updgrp_adv.c @@ -215,6 +215,9 @@ static int group_announce_route_walkcb(struct update_group *updgrp, void *arg) } } } + + /* Notify BGP Conditional advertisement */ + bgp_notify_conditional_adv_scanner(subgrp); } return UPDWALK_CONTINUE; diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index db72eb1775..cf16378de1 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -6717,6 +6717,11 @@ int peer_advertise_map_unset(struct peer *peer, afi_t afi, safi_t safi, /* Check if handling a regular peer and skip peer-group mechanics. */ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { /* Process peer route updates. */ + if (BGP_DEBUG(update, UPDATE_OUT)) + zlog_debug("%s: Send normal update to %s for %s", + __func__, peer->host, + get_afi_safi_str(afi, safi, false)); + peer_on_policy_change(peer, afi, safi, 1); return 0; } @@ -6736,6 +6741,11 @@ int peer_advertise_map_unset(struct peer *peer, afi_t afi, safi_t safi, condition_name, condition_map, condition, false); /* Process peer route updates. */ + if (BGP_DEBUG(update, UPDATE_OUT)) + zlog_debug("%s: Send normal update to %s for %s ", + __func__, member->host, + get_afi_safi_str(afi, safi, false)); + peer_on_policy_change(member, afi, safi, 1); } diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 4eb5bdd018..74828e91df 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -681,7 +681,7 @@ struct bgp { /* Process Queue for handling routes */ struct work_queue *process_queue; - + /* BGP Conditional advertisement */ uint32_t condition_filter_count; struct thread *t_condition_check; diff --git a/tests/topotests/bgp_conditional_advertisement/r2/bgpd.conf b/tests/topotests/bgp_conditional_advertisement/r2/bgpd.conf index c8f4357f99..c6147fe658 100644 --- a/tests/topotests/bgp_conditional_advertisement/r2/bgpd.conf +++ b/tests/topotests/bgp_conditional_advertisement/r2/bgpd.conf @@ -4,22 +4,32 @@ ip prefix-list DEFAULT seq 10 permit 192.0.2.1/32 ip prefix-list EXIST seq 5 permit 10.10.10.10/32 ip prefix-list DEFAULT-ROUTE seq 5 permit 0.0.0.0/0 ip prefix-list IP1 seq 5 permit 10.139.224.0/20 +ip prefix-list IP2 seq 5 permit 203.0.113.1/32 ! bgp community-list standard DC-ROUTES seq 5 permit 64952:3008 bgp community-list standard DC-ROUTES seq 10 permit 64671:501 bgp community-list standard DC-ROUTES seq 15 permit 64950:3009 bgp community-list standard DEFAULT-ROUTE seq 5 permit 65013:200 ! -route-map ADV-MAP permit 10 +route-map ADV-MAP-1 permit 10 match ip address prefix-list IP1 ! -route-map ADV-MAP permit 20 +route-map ADV-MAP-1 permit 20 match community DC-ROUTES ! +route-map ADV-MAP-2 permit 10 + match ip address prefix-list IP2 +! route-map EXIST-MAP permit 10 match community DEFAULT-ROUTE match ip address prefix-list DEFAULT-ROUTE ! +route-map RMAP-1 deny 10 + match ip address prefix-list IP1 +! +route-map RMAP-2 deny 10 + match ip address prefix-list IP2 +! router bgp 2 bgp log-neighbor-changes no bgp ebgp-requires-policy @@ -27,6 +37,7 @@ router bgp 2 neighbor 10.10.20.3 remote-as 3 ! address-family ipv4 unicast + network 203.0.113.1/32 neighbor 10.10.10.1 soft-reconfiguration inbound neighbor 10.10.20.3 soft-reconfiguration inbound exit-address-family 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 e509882448..99cf08b4f7 100644 --- a/tests/topotests/bgp_conditional_advertisement/test_bgp_conditional_advertisement.py +++ b/tests/topotests/bgp_conditional_advertisement/test_bgp_conditional_advertisement.py @@ -38,6 +38,7 @@ Conditional advertisement ------------------------- TC11: R3 BGP convergence, without advertise-map configuration. All routes are advertised to R3. + TC21: exist-map routes present in R2's BGP table. advertise-map routes present in R2's BGP table are advertised to R3. TC22: exist-map routes not present in R2's BGP table @@ -46,13 +47,14 @@ TC31: non-exist-map routes not present in R2's BGP table advertise-map routes present in R2's BGP table are advertised to R3. TC32: non-exist-map routes present in R2's BGP table advertise-map routes present in R2's BGP table are withdrawn from R3. + TC41: non-exist-map route-map configuration removed in R2. advertise-map routes present in R2's BGP table are advertised to R3. TC42: exist-map route-map configuration removed in R2 advertise-map routes present in R2's BGP table are withdrawn from R3. -Conditional advertisement along with Route-map Filter ------------------------------------------------------ +Conditional advertisement(received routes) along with Route-map Filter +---------------------------------------------------------------------- TC51: exist-map routes present in R2's BGP table, with route-map filter. All routes are withdrawn from R3 except advertise-map routes. TC52: exist-map routes present in R2's BGP table, without route-map filter. @@ -61,6 +63,7 @@ TC53: non-exist-map routes present in R2's BGP table, with route-map filter. All routes are withdrawn from R3 including advertise-map routes. TC54: non-exist-map routes present in R2's BGP table, without route-map filter. All routes are advertised to R3 except advertise-map routes. + TC61: exist-map routes not present in R2's BGP table, with route-map filter. All routes are withdrawn from R3 including advertise-map routes. TC62: exist-map routes not present in R2's BGP table, without route-map filter. @@ -70,6 +73,34 @@ TC63: non-exist-map routes not present in R2's BGP table, with route-map filter. TC64: non-exist-map routes not present in R2's BGP table, without route-map filter. All routes are advertised to R3 including advertise-map routes. +Conditional advertisement(attached routes) along with Route-map Filter +----------------------------------------------------------------- +TC71: exist-map routes present in R2's BGP table, with route-map filter. + All routes are withdrawn from R3 except advertise-map routes. +TC72: exist-map routes present in R2's BGP table, without route-map filter. + All routes are advertised to R3 including advertise-map routes. +TC73: non-exist-map routes present in R2's BGP table, with route-map filter. + All routes are withdrawn from R3 including advertise-map routes. +TC74: non-exist-map routes present in R2's BGP table, without route-map filter. + All routes are advertised to R3 except advertise-map routes. + +TC81: exist-map routes not present in R2's BGP table, with route-map filter. + All routes are withdrawn from R3 including advertise-map routes. +TC82: exist-map routes not present in R2's BGP table, without route-map filter. + All routes are advertised to R3 except advertise-map routes. +TC83: non-exist-map routes not present in R2's BGP table, with route-map filter. + All routes are withdrawn from R3 except advertise-map routes. +TC84: non-exist-map routes not present in R2's BGP table, without route-map filter. + All routes are advertised to R3 including advertise-map routes. + +TC91: exist-map routes present in R2's BGP table, with route-map filter and network. + All routes are advertised to R3 including advertise-map routes. +TC92: exist-map routes present in R2's BGP table, with route-map filter and no network. + All routes are advertised to R3 except advertise-map routes. +TC93: non-exist-map routes not present in R2's BGP table, with route-map filter and network. + All routes are advertised to R3 including advertise-map routes. +TC94: non-exist-map routes not present in R2's BGP table, with route-map filter and no network. + All routes are advertised to R3 except advertise-map routes. i.e. +----------------+-------------------------+------------------------+ @@ -191,6 +222,7 @@ def test_bgp_conditional_advertisement(): "192.0.2.1/32": [{"protocol": "bgp"}], "192.0.2.5/32": [{"protocol": "bgp"}], "10.139.224.0/20": [{"protocol": "bgp"}], + "203.0.113.1/32": [{"protocol": "bgp"}], } return topotest.json_cmp(output, expected) @@ -201,9 +233,12 @@ def test_bgp_conditional_advertisement(): "192.0.2.1/32": None, "192.0.2.5/32": None, "10.139.224.0/20": None, + "203.0.113.1/32": None, } return topotest.json_cmp(output, expected) + # BGP conditional advertisement with route-maps + # EXIST-MAP, ADV-MAP-1 and RMAP-1 def _exist_map_routes_present(router): return _all_routes_advertised(router) @@ -214,6 +249,7 @@ def test_bgp_conditional_advertisement(): "192.0.2.1/32": None, "192.0.2.5/32": [{"protocol": "bgp"}], "10.139.224.0/20": None, + "203.0.113.1/32": [{"protocol": "bgp"}], } return topotest.json_cmp(output, expected) @@ -224,6 +260,7 @@ def test_bgp_conditional_advertisement(): "192.0.2.1/32": None, "192.0.2.5/32": [{"protocol": "bgp"}], "10.139.224.0/20": None, + "203.0.113.1/32": [{"protocol": "bgp"}], } return topotest.json_cmp(output, expected) @@ -234,6 +271,7 @@ def test_bgp_conditional_advertisement(): "192.0.2.1/32": [{"protocol": "bgp"}], "192.0.2.5/32": [{"protocol": "bgp"}], "10.139.224.0/20": [{"protocol": "bgp"}], + "203.0.113.1/32": [{"protocol": "bgp"}], } return topotest.json_cmp(output, expected) @@ -250,6 +288,7 @@ def test_bgp_conditional_advertisement(): "192.0.2.1/32": [{"protocol": "bgp"}], "192.0.2.5/32": None, "10.139.224.0/20": [{"protocol": "bgp"}], + "203.0.113.1/32": None, } return topotest.json_cmp(output, expected) @@ -274,6 +313,68 @@ def test_bgp_conditional_advertisement(): def _non_exist_map_routes_not_present_no_rmap_filter(router): return _non_exist_map_routes_not_present(router) + # BGP conditional advertisement with route-maps + # EXIST-MAP, ADV-MAP-2 and RMAP-2 + def _exist_map_routes_not_present_rmap2_filter(router): + return _all_routes_withdrawn(router) + + def _exist_map_routes_not_present_no_rmap2_filter(router): + output = json.loads(router.vtysh_cmd("show ip route json")) + expected = { + "0.0.0.0/0": None, + "192.0.2.1/32": [{"protocol": "bgp"}], + "192.0.2.5/32": [{"protocol": "bgp"}], + "10.139.224.0/20": [{"protocol": "bgp"}], + "203.0.113.1/32": None, + } + return topotest.json_cmp(output, expected) + + def _non_exist_map_routes_not_present_rmap2_filter(router): + output = json.loads(router.vtysh_cmd("show ip route json")) + expected = { + "0.0.0.0/0": None, + "192.0.2.1/32": None, + "192.0.2.5/32": None, + "10.139.224.0/20": None, + "203.0.113.1/32": [{"protocol": "bgp"}], + } + return topotest.json_cmp(output, expected) + + def _non_exist_map_routes_not_present_no_rmap2_filter(router): + return _non_exist_map_routes_not_present(router) + + def _exist_map_routes_present_rmap2_filter(router): + return _non_exist_map_routes_not_present_rmap2_filter(router) + + def _exist_map_routes_present_no_rmap2_filter(router): + return _all_routes_advertised(router) + + def _non_exist_map_routes_present_rmap2_filter(router): + return _all_routes_withdrawn(router) + + def _non_exist_map_routes_present_no_rmap2_filter(router): + output = json.loads(router.vtysh_cmd("show ip route json")) + expected = { + "0.0.0.0/0": [{"protocol": "bgp"}], + "192.0.2.1/32": [{"protocol": "bgp"}], + "192.0.2.5/32": [{"protocol": "bgp"}], + "10.139.224.0/20": [{"protocol": "bgp"}], + "203.0.113.1/32": None, + } + return topotest.json_cmp(output, expected) + + def _exist_map_routes_present_rmap2_network(router): + return _non_exist_map_routes_not_present_rmap2_filter(router) + + def _exist_map_routes_present_rmap2_no_network(router): + return _all_routes_withdrawn(router) + + def _non_exist_map_routes_not_present_rmap2_network(router): + return _non_exist_map_routes_not_present_rmap2_filter(router) + + def _non_exist_map_routes_not_present_rmap2_no_network(router): + return _all_routes_withdrawn(router) + # TC11: R3 BGP convergence, without advertise-map configuration. # All routes are advertised to R3. test_func = functools.partial(_all_routes_advertised, router3) @@ -291,7 +392,7 @@ def test_bgp_conditional_advertisement(): configure terminal router bgp 2 address-family ipv4 unicast - neighbor 10.10.20.3 advertise-map ADV-MAP exist-map EXIST-MAP + neighbor 10.10.20.3 advertise-map ADV-MAP-1 exist-map EXIST-MAP """ ) @@ -329,7 +430,7 @@ def test_bgp_conditional_advertisement(): configure terminal router bgp 2 address-family ipv4 unicast - neighbor 10.10.20.3 advertise-map ADV-MAP non-exist-map EXIST-MAP + neighbor 10.10.20.3 advertise-map ADV-MAP-1 non-exist-map EXIST-MAP """ ) @@ -384,7 +485,7 @@ def test_bgp_conditional_advertisement(): configure terminal router bgp 2 address-family ipv4 unicast - neighbor 10.10.20.3 advertise-map ADV-MAP exist-map EXIST-MAP + neighbor 10.10.20.3 advertise-map ADV-MAP-1 exist-map EXIST-MAP """ ) @@ -405,12 +506,9 @@ def test_bgp_conditional_advertisement(): match community DEFAULT-ROUTE match ip address prefix-list DEFAULT-ROUTE ! - route-map RMAP deny 10 - match ip address prefix-list IP1 - ! router bgp 2 address-family ipv4 unicast - neighbor 10.10.20.3 route-map RMAP out + neighbor 10.10.20.3 route-map RMAP-1 out """ ) @@ -429,7 +527,7 @@ def test_bgp_conditional_advertisement(): configure terminal router bgp 2 address-family ipv4 unicast - no neighbor 10.10.20.3 route-map RMAP out + no neighbor 10.10.20.3 route-map RMAP-1 out """ ) @@ -448,8 +546,8 @@ def test_bgp_conditional_advertisement(): configure terminal router bgp 2 address-family ipv4 unicast - neighbor 10.10.20.3 route-map RMAP out - neighbor 10.10.20.3 advertise-map ADV-MAP non-exist-map EXIST-MAP + neighbor 10.10.20.3 route-map RMAP-1 out + neighbor 10.10.20.3 advertise-map ADV-MAP-1 non-exist-map EXIST-MAP """ ) @@ -468,7 +566,7 @@ def test_bgp_conditional_advertisement(): configure terminal router bgp 2 address-family ipv4 unicast - no neighbor 10.10.20.3 route-map RMAP out + no neighbor 10.10.20.3 route-map RMAP-1 out """ ) @@ -495,8 +593,8 @@ def test_bgp_conditional_advertisement(): configure terminal router bgp 2 address-family ipv4 unicast - neighbor 10.10.20.3 route-map RMAP out - neighbor 10.10.20.3 advertise-map ADV-MAP exist-map EXIST-MAP + neighbor 10.10.20.3 route-map RMAP-1 out + neighbor 10.10.20.3 advertise-map ADV-MAP-1 exist-map EXIST-MAP """ ) @@ -515,7 +613,7 @@ def test_bgp_conditional_advertisement(): configure terminal router bgp 2 address-family ipv4 unicast - no neighbor 10.10.20.3 route-map RMAP out + no neighbor 10.10.20.3 route-map RMAP-1 out """ ) @@ -534,8 +632,8 @@ def test_bgp_conditional_advertisement(): configure terminal router bgp 2 address-family ipv4 unicast - neighbor 10.10.20.3 route-map RMAP out - neighbor 10.10.20.3 advertise-map ADV-MAP non-exist-map EXIST-MAP + neighbor 10.10.20.3 route-map RMAP-1 out + neighbor 10.10.20.3 advertise-map ADV-MAP-1 non-exist-map EXIST-MAP """ ) @@ -556,7 +654,7 @@ def test_bgp_conditional_advertisement(): configure terminal router bgp 2 address-family ipv4 unicast - no neighbor 10.10.20.3 route-map RMAP out + no neighbor 10.10.20.3 route-map RMAP-1 out """ ) @@ -570,6 +668,284 @@ def test_bgp_conditional_advertisement(): logger.info(msg + passed) + # TC71: exist-map routes present in R2's BGP table, with route-map filter. + # All routes are withdrawn from R3 except advertise-map routes. + router1.vtysh_cmd( + """ + configure terminal + router bgp 1 + address-family ipv4 unicast + network 0.0.0.0/0 route-map DEF + """ + ) + router2.vtysh_cmd( + """ + configure terminal + router bgp 2 + address-family ipv4 unicast + neighbor 10.10.20.3 route-map RMAP-2 out + neighbor 10.10.20.3 advertise-map ADV-MAP-2 exist-map EXIST-MAP + """ + ) + + test_func = functools.partial(_exist_map_routes_present_rmap2_filter, router3) + success, 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 + + logger.info(msg + passed) + + # TC72: exist-map routes present in R2's BGP table, without route-map filter. + # All routes are advertised to R3 including advertise-map routes. + router2.vtysh_cmd( + """ + configure terminal + router bgp 2 + address-family ipv4 unicast + no neighbor 10.10.20.3 route-map RMAP-2 out + """ + ) + + 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) + + msg = "TC72: exist-map routes present, no route-map filter - " + assert result is None, msg + failed + + logger.info(msg + passed) + + # TC73: non-exist-map routes present in R2's BGP table, with route-map filter. + # All routes are advertised to R3 including advertise-map routes. + router2.vtysh_cmd( + """ + configure terminal + router bgp 2 + address-family ipv4 unicast + neighbor 10.10.20.3 route-map RMAP-2 out + neighbor 10.10.20.3 advertise-map ADV-MAP-2 non-exist-map EXIST-MAP + """ + ) + + 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) + + msg = "TC73: non-exist-map routes present, route-map filter - " + assert result is None, msg + failed + + logger.info(msg + passed) + + # TC74: non-exist-map routes present in R2's BGP table, without route-map filter. + # All routes are advertised to R3 including advertise-map routes. + router2.vtysh_cmd( + """ + configure terminal + router bgp 2 + address-family ipv4 unicast + no neighbor 10.10.20.3 route-map RMAP-2 out + """ + ) + + 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) + + msg = "TC74: non-exist-map routes present, no route-map filter - " + assert result is None, msg + failed + + logger.info(msg + passed) + + # TC81: exist-map routes not present in R2's BGP table, with route-map filter. + # All routes are withdrawn from R3 including advertise-map routes. + router1.vtysh_cmd( + """ + configure terminal + router bgp 1 + address-family ipv4 unicast + no network 0.0.0.0/0 route-map DEF + """ + ) + router2.vtysh_cmd( + """ + configure terminal + router bgp 2 + address-family ipv4 unicast + neighbor 10.10.20.3 route-map RMAP-2 out + neighbor 10.10.20.3 advertise-map ADV-MAP-2 exist-map EXIST-MAP + """ + ) + + 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) + + msg = "TC81: exist-map routes not present, route-map filter - " + assert result is None, msg + failed + + logger.info(msg + passed) + + # TC82: exist-map routes not present in R2's BGP table, without route-map filter. + # All routes are advertised to R3 except advertise-map routes. + router2.vtysh_cmd( + """ + configure terminal + router bgp 2 + address-family ipv4 unicast + no neighbor 10.10.20.3 route-map RMAP-2 out + """ + ) + + 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) + + msg = "TC82: exist-map routes not present, no route-map filter - " + assert result is None, msg + failed + + logger.info(msg + passed) + + # TC83: non-exist-map routes not present in R2's BGP table, with route-map filter. + # All routes are advertised to R3 including advertise-map routes. + router2.vtysh_cmd( + """ + configure terminal + router bgp 2 + address-family ipv4 unicast + neighbor 10.10.20.3 route-map RMAP-2 out + neighbor 10.10.20.3 advertise-map ADV-MAP-2 non-exist-map EXIST-MAP + """ + ) + + 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) + + msg = "TC83: non-exist-map routes not present, route-map filter - " + assert result is None, msg + failed + + logger.info(msg + passed) + + # TC84: non-exist-map routes not present in R2's BGP table, without route-map filter. + # All routes are advertised to R3 including advertise-map routes. + router2.vtysh_cmd( + """ + configure terminal + router bgp 2 + address-family ipv4 unicast + no neighbor 10.10.20.3 route-map RMAP-2 out + """ + ) + + 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) + + msg = "TC84: non-exist-map routes not present, no route-map filter - " + assert result is None, msg + failed + + logger.info(msg + passed) + + # TC91: exist-map routes present in R2's BGP table, with route-map filter and network. + # All routes are advertised to R3 including advertise-map routes. + router1.vtysh_cmd( + """ + configure terminal + router bgp 1 + address-family ipv4 unicast + network 0.0.0.0/0 route-map DEF + """ + ) + router2.vtysh_cmd( + """ + configure terminal + router bgp 2 + address-family ipv4 unicast + neighbor 10.10.20.3 route-map RMAP-2 out + neighbor 10.10.20.3 advertise-map ADV-MAP-2 exist-map EXIST-MAP + """ + ) + + test_func = functools.partial(_exist_map_routes_present_rmap2_network, router3) + success, 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 + + logger.info(msg + passed) + + # TC92: exist-map routes present in R2's BGP table, with route-map filter and no network. + # All routes are advertised to R3 except advertise-map routes. + router2.vtysh_cmd( + """ + configure terminal + router bgp 2 + address-family ipv4 unicast + no network 203.0.113.1/32 + """ + ) + + 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) + + msg = "TC92: exist-map routes present, route-map filter and no network - " + assert result is None, msg + failed + + logger.info(msg + passed) + + # TC93: non-exist-map routes not present in R2's BGP table, with route-map filter and network. + # All routes are advertised to R3 including advertise-map routes. + router1.vtysh_cmd( + """ + configure terminal + router bgp 1 + address-family ipv4 unicast + no network 0.0.0.0/0 route-map DEF + """ + ) + router2.vtysh_cmd( + """ + configure terminal + router bgp 2 + address-family ipv4 unicast + network 203.0.113.1/32 + neighbor 10.10.20.3 advertise-map ADV-MAP-2 non-exist-map EXIST-MAP + """ + ) + + 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) + + msg = "TC93: non-exist-map routes not present, route-map filter and network - " + assert result is None, msg + failed + + logger.info(msg + passed) + + # TC94: non-exist-map routes not present in R2's BGP table, with route-map filter and no network. + # All routes are advertised to R3 except advertise-map routes. + router2.vtysh_cmd( + """ + configure terminal + router bgp 2 + address-family ipv4 unicast + no network 203.0.113.1/32 + """ + ) + + 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) + + msg = "TC94: non-exist-map routes not present, route-map filter and no network - " + assert result is None, msg + failed + + logger.info(msg + passed) + def test_memory_leak(): "Run the memory leak test and report results." From 1a0416bd6f332e9238708a042dcb7d754493bea5 Mon Sep 17 00:00:00 2001 From: Madhuri Kuruganti Date: Tue, 27 Oct 2020 16:13:42 +0530 Subject: [PATCH 8/8] bgpd: conditional advertisement - copyright Signed-off-by: Madhuri Kuruganti --- bgpd/bgp_conditional_adv.c | 2 +- bgpd/bgp_conditional_adv.h | 2 +- .../test_bgp_conditional_advertisement.py | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/bgpd/bgp_conditional_adv.c b/bgpd/bgp_conditional_adv.c index ff1eb2be20..0731adcb84 100644 --- a/bgpd/bgp_conditional_adv.c +++ b/bgpd/bgp_conditional_adv.c @@ -1,6 +1,6 @@ /* * BGP Conditional advertisement - * Copyright (C) 2020 Samsung Research Institute Bangalore. + * Copyright (C) 2020 Samsung R&D Institute India - Bangalore. * Madhurilatha Kuruganti * * This program is free software; you can redistribute it and/or modify it diff --git a/bgpd/bgp_conditional_adv.h b/bgpd/bgp_conditional_adv.h index 5dcd3607d9..7b5053de76 100644 --- a/bgpd/bgp_conditional_adv.h +++ b/bgpd/bgp_conditional_adv.h @@ -1,6 +1,6 @@ /* * BGP Conditional advertisement - * Copyright (C) 2020 Samsung Research Institute Bangalore. + * Copyright (C) 2020 Samsung R&D Institute India - Bangalore. * Madhurilatha Kuruganti * * This program is free software; you can redistribute it and/or modify it 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 99cf08b4f7..0e31ab1995 100644 --- a/tests/topotests/bgp_conditional_advertisement/test_bgp_conditional_advertisement.py +++ b/tests/topotests/bgp_conditional_advertisement/test_bgp_conditional_advertisement.py @@ -2,10 +2,10 @@ # # test_bgp_conditional_advertisement.py -# Part of NetDEF Topology Tests # # Copyright (c) 2020 by -# Network Device Education Foundation, Inc. ("NetDEF") +# Samsung R&D Institute India - Bangalore. +# Madhurilatha Kuruganti # # Permission to use, copy, modify, and/or distribute this software # for any purpose with or without fee is hereby granted, provided