2 * BGP Conditional advertisement
3 * Copyright (C) 2020 Samsung R&D Institute India - Bangalore.
4 * Madhurilatha Kuruganti
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the Free
8 * Software Foundation; either version 2 of the License, or (at your option)
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 * You should have received a copy of the GNU General Public License along
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23 #include "bgpd/bgp_conditional_adv.h"
24 #include "bgpd/bgp_vty.h"
26 static route_map_result_t
27 bgp_check_rmap_prefixes_in_bgp_table(struct bgp_table
*table
,
28 struct route_map
*rmap
)
30 struct attr dummy_attr
= {0};
31 struct bgp_dest
*dest
;
32 struct bgp_path_info
*pi
;
33 struct bgp_path_info path
= {0};
34 struct bgp_path_info_extra path_extra
= {0};
35 const struct prefix
*dest_p
;
36 route_map_result_t ret
= RMAP_DENYMATCH
;
38 for (dest
= bgp_table_top(table
); dest
; dest
= bgp_route_next(dest
)) {
39 dest_p
= bgp_dest_get_prefix(dest
);
42 for (pi
= bgp_dest_get_bgp_path_info(dest
); pi
; pi
= pi
->next
) {
43 dummy_attr
= *pi
->attr
;
45 /* Fill temp path_info */
46 prep_for_rmap_apply(&path
, &path_extra
, dest
, pi
,
47 pi
->peer
, &dummy_attr
);
49 RESET_FLAG(dummy_attr
.rmap_change_flags
);
51 ret
= route_map_apply(rmap
, dest_p
, &path
);
52 bgp_attr_flush(&dummy_attr
);
54 if (ret
== RMAP_PERMITMATCH
) {
55 bgp_dest_unlock_node(dest
);
56 if (BGP_DEBUG(update
, UPDATE_OUT
))
58 "%s: Condition map routes present in BGP table",
66 if (BGP_DEBUG(update
, UPDATE_OUT
))
67 zlog_debug("%s: Condition map routes not present in BGP table",
73 static void bgp_conditional_adv_routes(struct peer
*peer
, afi_t afi
,
74 safi_t safi
, struct bgp_table
*table
,
75 struct route_map
*rmap
,
76 enum update_type update_type
)
79 struct bgp_dest
*dest
;
80 struct bgp_path_info
*pi
;
81 struct bgp_path_info path
;
83 const struct prefix
*dest_p
;
84 struct update_subgroup
*subgrp
;
85 struct attr dummy_attr
= {0}, attr
= {0};
86 struct bgp_path_info_extra path_extra
= {0};
87 route_map_result_t ret
;
89 paf
= peer_af_find(peer
, afi
, safi
);
93 subgrp
= PAF_SUBGRP(paf
);
94 /* Ignore if subgroup doesn't exist (implies AF is not negotiated) */
98 if (BGP_DEBUG(update
, UPDATE_OUT
))
99 zlog_debug("%s: %s routes to/from %s for %s", __func__
,
100 update_type
== ADVERTISE
? "Advertise" : "Withdraw",
101 peer
->host
, get_afi_safi_str(afi
, safi
, false));
103 addpath_capable
= bgp_addpath_encode_tx(peer
, afi
, safi
);
105 for (dest
= bgp_table_top(table
); dest
; dest
= bgp_route_next(dest
)) {
106 dest_p
= bgp_dest_get_prefix(dest
);
109 for (pi
= bgp_dest_get_bgp_path_info(dest
); pi
; pi
= pi
->next
) {
110 dummy_attr
= *pi
->attr
;
112 /* Fill temp path_info */
113 prep_for_rmap_apply(&path
, &path_extra
, dest
, pi
,
114 pi
->peer
, &dummy_attr
);
116 RESET_FLAG(dummy_attr
.rmap_change_flags
);
118 ret
= route_map_apply(rmap
, dest_p
, &path
);
119 bgp_attr_flush(&dummy_attr
);
121 if (ret
!= RMAP_PERMITMATCH
)
124 if (CHECK_FLAG(pi
->flags
, BGP_PATH_SELECTED
)
126 && bgp_addpath_tx_path(
127 peer
->addpath_type
[afi
][safi
],
130 /* Skip route-map checks in
131 * subgroup_announce_check while executing from
132 * the conditional advertise scanner process.
133 * otherwise when route-map is also configured
134 * on same peer, routes in advertise-map may not
135 * be advertised as expected.
137 if ((update_type
== ADVERTISE
)
138 && subgroup_announce_check(dest
, pi
, subgrp
,
141 bgp_adj_out_set_subgroup(dest
, subgrp
,
144 /* If default originate is enabled for
145 * the peer, do not send explicit
146 * withdraw. This will prevent deletion
147 * of default route advertised through
151 peer
->af_flags
[afi
][safi
],
152 PEER_FLAG_DEFAULT_ORIGINATE
)
153 && is_default_prefix(dest_p
))
156 bgp_adj_out_unset_subgroup(
158 bgp_addpath_id_for_peer(
167 /* Handler of conditional advertisement timer event.
168 * Each route in the condition-map is evaluated.
170 static int bgp_conditional_adv_timer(struct thread
*t
)
175 struct bgp
*bgp
= NULL
;
176 struct peer
*peer
= NULL
;
177 struct peer_af
*paf
= NULL
;
178 struct bgp_table
*table
= NULL
;
179 struct bgp_filter
*filter
= NULL
;
180 struct listnode
*node
, *nnode
= NULL
;
181 struct update_subgroup
*subgrp
= NULL
;
182 route_map_result_t ret
;
187 thread_add_timer(bm
->master
, bgp_conditional_adv_timer
, bgp
,
188 bgp
->condition_check_period
, &bgp
->t_condition_check
);
190 /* loop through each peer and advertise or withdraw routes if
191 * advertise-map is configured and prefix(es) in condition-map
192 * does exist(exist-map)/not exist(non-exist-map) in BGP table
193 * based on condition(exist-map or non-exist map)
195 for (ALL_LIST_ELEMENTS(bgp
->peer
, node
, nnode
, peer
)) {
196 if (!CHECK_FLAG(peer
->flags
, PEER_FLAG_CONFIG_NODE
))
199 if (!peer_established(peer
))
202 FOREACH_AFI_SAFI (afi
, safi
) {
203 if (!peer
->afc_nego
[afi
][safi
])
206 /* labeled-unicast routes are installed in the unicast
207 * table so in order to display the correct PfxRcd value
208 * we must look at SAFI_UNICAST
210 pfx_rcd_safi
= (safi
== SAFI_LABELED_UNICAST
)
214 table
= bgp
->rib
[afi
][pfx_rcd_safi
];
218 filter
= &peer
->filter
[afi
][safi
];
220 if (!filter
->advmap
.aname
|| !filter
->advmap
.cname
221 || !filter
->advmap
.amap
|| !filter
->advmap
.cmap
)
224 if (!peer
->advmap_config_change
[afi
][safi
]
225 && !peer
->advmap_table_change
)
228 if (BGP_DEBUG(update
, UPDATE_OUT
)) {
229 if (peer
->advmap_table_change
)
231 "%s: %s - routes changed in BGP table.",
232 __func__
, peer
->host
);
233 if (peer
->advmap_config_change
[afi
][safi
])
235 "%s: %s for %s - advertise/condition map configuration is changed.",
236 __func__
, peer
->host
,
237 get_afi_safi_str(afi
, safi
,
241 /* cmap (route-map attached to exist-map or
242 * non-exist-map) map validation
244 ret
= bgp_check_rmap_prefixes_in_bgp_table(
245 table
, filter
->advmap
.cmap
);
247 /* Derive conditional advertisement status from
248 * condition and return value of condition-map
251 if (filter
->advmap
.condition
== CONDITION_EXIST
)
252 filter
->advmap
.update_type
=
253 (ret
== RMAP_PERMITMATCH
) ? ADVERTISE
256 filter
->advmap
.update_type
=
257 (ret
== RMAP_PERMITMATCH
) ? WITHDRAW
260 /* Send regular update as per the existing policy.
261 * There is a change in route-map, match-rule, ACLs,
262 * or route-map filter configuration on the same peer.
264 if (peer
->advmap_config_change
[afi
][safi
]) {
266 if (BGP_DEBUG(update
, UPDATE_OUT
))
268 "%s: Configuration is changed on peer %s for %s, send the normal update first.",
269 __func__
, peer
->host
,
270 get_afi_safi_str(afi
, safi
,
273 paf
= peer_af_find(peer
, afi
, safi
);
275 update_subgroup_split_peer(paf
, NULL
);
276 subgrp
= paf
->subgroup
;
277 if (subgrp
&& subgrp
->update_group
)
278 subgroup_announce_table(
279 paf
->subgroup
, NULL
);
281 peer
->advmap_config_change
[afi
][safi
] = false;
284 /* Send update as per the conditional advertisement */
285 bgp_conditional_adv_routes(peer
, afi
, safi
, table
,
287 filter
->advmap
.update_type
);
289 peer
->advmap_table_change
= false;
294 void bgp_conditional_adv_enable(struct peer
*peer
, afi_t afi
, safi_t safi
)
296 struct bgp
*bgp
= peer
->bgp
;
300 /* This flag is used to monitor conditional routes status in BGP table,
301 * and advertise/withdraw routes only when there is a change in BGP
302 * table w.r.t conditional routes
304 peer
->advmap_config_change
[afi
][safi
] = true;
306 /* advertise-map is already configured on atleast one of its
307 * neighbors (AFI/SAFI). So just increment the counter.
309 if (++bgp
->condition_filter_count
> 1) {
310 if (BGP_DEBUG(update
, UPDATE_OUT
))
311 zlog_debug("%s: condition_filter_count %d", __func__
,
312 bgp
->condition_filter_count
);
317 /* Register for conditional routes polling timer */
318 thread_add_timer(bm
->master
, bgp_conditional_adv_timer
, bgp
,
319 bgp
->condition_check_period
, &bgp
->t_condition_check
);
322 void bgp_conditional_adv_disable(struct peer
*peer
, afi_t afi
, safi_t safi
)
324 struct bgp
*bgp
= peer
->bgp
;
328 /* advertise-map is not configured on any of its neighbors or
329 * it is configured on more than one neighbor(AFI/SAFI).
330 * So there's nothing to do except decrementing the counter.
332 if (--bgp
->condition_filter_count
!= 0) {
333 if (BGP_DEBUG(update
, UPDATE_OUT
))
334 zlog_debug("%s: condition_filter_count %d", __func__
,
335 bgp
->condition_filter_count
);
340 /* Last filter removed. So cancel conditional routes polling thread. */
341 THREAD_OFF(bgp
->t_condition_check
);