]> git.proxmox.com Git - mirror_frr.git/blob - bgpd/bgp_conditional_adv.c
Merge pull request #9416 from pguibert6WIND/vxlan_evpn_updates
[mirror_frr.git] / bgpd / bgp_conditional_adv.c
1 /*
2 * BGP Conditional advertisement
3 * Copyright (C) 2020 Samsung R&D Institute India - Bangalore.
4 * Madhurilatha Kuruganti
5 *
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)
9 * any later version.
10 *
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
14 * more details.
15 *
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
19 */
20
21 #include <zebra.h>
22
23 #include "bgpd/bgp_conditional_adv.h"
24 #include "bgpd/bgp_vty.h"
25
26 static route_map_result_t
27 bgp_check_rmap_prefixes_in_bgp_table(struct bgp_table *table,
28 struct route_map *rmap)
29 {
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;
37
38 for (dest = bgp_table_top(table); dest; dest = bgp_route_next(dest)) {
39 dest_p = bgp_dest_get_prefix(dest);
40 assert(dest_p);
41
42 for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) {
43 dummy_attr = *pi->attr;
44
45 /* Fill temp path_info */
46 prep_for_rmap_apply(&path, &path_extra, dest, pi,
47 pi->peer, &dummy_attr);
48
49 RESET_FLAG(dummy_attr.rmap_change_flags);
50
51 ret = route_map_apply(rmap, dest_p, &path);
52 bgp_attr_flush(&dummy_attr);
53
54 if (ret == RMAP_PERMITMATCH) {
55 bgp_dest_unlock_node(dest);
56 if (BGP_DEBUG(update, UPDATE_OUT))
57 zlog_debug(
58 "%s: Condition map routes present in BGP table",
59 __func__);
60
61 return ret;
62 }
63 }
64 }
65
66 if (BGP_DEBUG(update, UPDATE_OUT))
67 zlog_debug("%s: Condition map routes not present in BGP table",
68 __func__);
69
70 return ret;
71 }
72
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)
77 {
78 int addpath_capable;
79 struct bgp_dest *dest;
80 struct bgp_path_info *pi;
81 struct bgp_path_info path;
82 struct peer_af *paf;
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;
88
89 paf = peer_af_find(peer, afi, safi);
90 if (!paf)
91 return;
92
93 subgrp = PAF_SUBGRP(paf);
94 /* Ignore if subgroup doesn't exist (implies AF is not negotiated) */
95 if (!subgrp)
96 return;
97
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));
102
103 addpath_capable = bgp_addpath_encode_tx(peer, afi, safi);
104
105 for (dest = bgp_table_top(table); dest; dest = bgp_route_next(dest)) {
106 dest_p = bgp_dest_get_prefix(dest);
107 assert(dest_p);
108
109 for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) {
110 dummy_attr = *pi->attr;
111
112 /* Fill temp path_info */
113 prep_for_rmap_apply(&path, &path_extra, dest, pi,
114 pi->peer, &dummy_attr);
115
116 RESET_FLAG(dummy_attr.rmap_change_flags);
117
118 ret = route_map_apply(rmap, dest_p, &path);
119 bgp_attr_flush(&dummy_attr);
120
121 if (ret != RMAP_PERMITMATCH)
122 continue;
123
124 if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED)
125 || (addpath_capable
126 && bgp_addpath_tx_path(
127 peer->addpath_type[afi][safi],
128 pi))) {
129
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.
136 */
137 if ((update_type == ADVERTISE)
138 && subgroup_announce_check(dest, pi, subgrp,
139 dest_p, &attr,
140 true))
141 bgp_adj_out_set_subgroup(dest, subgrp,
142 &attr, pi);
143 else {
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
148 * default originate.
149 */
150 if (CHECK_FLAG(
151 peer->af_flags[afi][safi],
152 PEER_FLAG_DEFAULT_ORIGINATE)
153 && is_default_prefix(dest_p))
154 break;
155
156 bgp_adj_out_unset_subgroup(
157 dest, subgrp, 1,
158 bgp_addpath_id_for_peer(
159 peer, afi, safi,
160 &pi->tx_addpath));
161 }
162 }
163 }
164 }
165 }
166
167 /* Handler of conditional advertisement timer event.
168 * Each route in the condition-map is evaluated.
169 */
170 static int bgp_conditional_adv_timer(struct thread *t)
171 {
172 afi_t afi;
173 safi_t safi;
174 int pfx_rcd_safi;
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;
183
184 bgp = THREAD_ARG(t);
185 assert(bgp);
186
187 thread_add_timer(bm->master, bgp_conditional_adv_timer, bgp,
188 bgp->condition_check_period, &bgp->t_condition_check);
189
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)
194 */
195 for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
196 if (!CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE))
197 continue;
198
199 if (!peer_established(peer))
200 continue;
201
202 FOREACH_AFI_SAFI (afi, safi) {
203 if (!peer->afc_nego[afi][safi])
204 continue;
205
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
209 */
210 pfx_rcd_safi = (safi == SAFI_LABELED_UNICAST)
211 ? SAFI_UNICAST
212 : safi;
213
214 table = bgp->rib[afi][pfx_rcd_safi];
215 if (!table)
216 continue;
217
218 filter = &peer->filter[afi][safi];
219
220 if (!filter->advmap.aname || !filter->advmap.cname
221 || !filter->advmap.amap || !filter->advmap.cmap)
222 continue;
223
224 if (!peer->advmap_config_change[afi][safi]
225 && !peer->advmap_table_change)
226 continue;
227
228 if (BGP_DEBUG(update, UPDATE_OUT)) {
229 if (peer->advmap_table_change)
230 zlog_debug(
231 "%s: %s - routes changed in BGP table.",
232 __func__, peer->host);
233 if (peer->advmap_config_change[afi][safi])
234 zlog_debug(
235 "%s: %s for %s - advertise/condition map configuration is changed.",
236 __func__, peer->host,
237 get_afi_safi_str(afi, safi,
238 false));
239 }
240
241 /* cmap (route-map attached to exist-map or
242 * non-exist-map) map validation
243 */
244 ret = bgp_check_rmap_prefixes_in_bgp_table(
245 table, filter->advmap.cmap);
246
247 /* Derive conditional advertisement status from
248 * condition and return value of condition-map
249 * validation.
250 */
251 if (filter->advmap.condition == CONDITION_EXIST)
252 filter->advmap.update_type =
253 (ret == RMAP_PERMITMATCH) ? ADVERTISE
254 : WITHDRAW;
255 else
256 filter->advmap.update_type =
257 (ret == RMAP_PERMITMATCH) ? WITHDRAW
258 : ADVERTISE;
259
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.
263 */
264 if (peer->advmap_config_change[afi][safi]) {
265
266 if (BGP_DEBUG(update, UPDATE_OUT))
267 zlog_debug(
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,
271 false));
272
273 paf = peer_af_find(peer, afi, safi);
274 if (paf) {
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);
280 }
281 peer->advmap_config_change[afi][safi] = false;
282 }
283
284 /* Send update as per the conditional advertisement */
285 bgp_conditional_adv_routes(peer, afi, safi, table,
286 filter->advmap.amap,
287 filter->advmap.update_type);
288 }
289 peer->advmap_table_change = false;
290 }
291 return 0;
292 }
293
294 void bgp_conditional_adv_enable(struct peer *peer, afi_t afi, safi_t safi)
295 {
296 struct bgp *bgp = peer->bgp;
297
298 assert(bgp);
299
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
303 */
304 peer->advmap_config_change[afi][safi] = true;
305
306 /* advertise-map is already configured on atleast one of its
307 * neighbors (AFI/SAFI). So just increment the counter.
308 */
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);
313
314 return;
315 }
316
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);
320 }
321
322 void bgp_conditional_adv_disable(struct peer *peer, afi_t afi, safi_t safi)
323 {
324 struct bgp *bgp = peer->bgp;
325
326 assert(bgp);
327
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.
331 */
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);
336
337 return;
338 }
339
340 /* Last filter removed. So cancel conditional routes polling thread. */
341 THREAD_OFF(bgp->t_condition_check);
342 }