mirror of
https://git.proxmox.com/git/mirror_frr
synced 2026-01-03 21:10:33 +00:00
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 <k.madhuri@samsung.com>
This commit is contained in:
parent
c5aec50b81
commit
c385f82af3
@ -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.
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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",
|
||||
|
||||
18
bgpd/bgpd.c
18
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);
|
||||
}
|
||||
}
|
||||
|
||||
17
bgpd/bgpd.h
17
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
|
||||
};
|
||||
|
||||
Loading…
Reference in New Issue
Block a user