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 <k.madhuri@samsung.com>
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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 <zebra.h>
+#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 */
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;
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};
/* 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,
#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
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);
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;
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);
+ }
}
/**
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);
}
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,
&& 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
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 {
if (subgroup_announce_check(
dest, pi, subgrp,
bgp_dest_get_prefix(dest),
- &attr))
+ &attr, false))
bgp_adj_out_set_subgroup(
dest, subgrp, &attr,
pi);
"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 <A.B.C.D|X:X::X:X|WORD> advertise-map WORD <exist-map WORD|non-exist-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 <A.B.C.D|X:X::X:X|WORD> advertise-map WORD <exist-map WORD|non-exist-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 <A.B.C.D|X:X::X:X|WORD> advertise-map WORD <exist-map WORD|non-exist-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 <A.B.C.D|X:X::X:X|WORD> advertise-map WORD <exist-map WORD|non-exist-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,
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]);
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;
}
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))
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);
#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"
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)
/* Process Queue for handling routes */
struct work_queue *process_queue;
+
+ /* BGP Conditional advertisement */
+ int condition_filter_count;
+ struct thread *t_condition_check;
QOBJ_FIELDS
};
#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. */
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,
#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];
/* 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)
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);
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 \
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 \
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