]> git.proxmox.com Git - mirror_frr.git/blame - bgpd/bgp_conditional_adv.c
zebra: add support for DF delay timer
[mirror_frr.git] / bgpd / bgp_conditional_adv.c
CommitLineData
7f7940e6
MK
1/*
2 * BGP Conditional advertisement
1a0416bd 3 * Copyright (C) 2020 Samsung R&D Institute India - Bangalore.
7f7940e6
MK
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 "bgpd/bgp_conditional_adv.h"
22
23const char *get_afi_safi_str(afi_t afi, safi_t safi, bool for_json);
24
c385f82a 25static route_map_result_t
7f7940e6
MK
26bgp_check_rmap_prefixes_in_bgp_table(struct bgp_table *table,
27 struct route_map *rmap)
28{
52b84062 29 struct attr dummy_attr = {0};
c385f82a 30 struct bgp_dest *dest;
c385f82a 31 struct bgp_path_info *pi;
52b84062
MK
32 struct bgp_path_info path = {0};
33 struct bgp_path_info_extra path_extra = {0};
34 const struct prefix *dest_p;
35 route_map_result_t ret = RMAP_DENYMATCH;
c385f82a
MK
36
37 for (dest = bgp_table_top(table); dest; dest = bgp_route_next(dest)) {
38 dest_p = bgp_dest_get_prefix(dest);
52b84062 39 assert(dest_p);
7f7940e6 40
c385f82a
MK
41 for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) {
42 dummy_attr = *pi->attr;
52b84062
MK
43
44 /* Fill temp path_info */
45 prep_for_rmap_apply(&path, &path_extra, dest, pi,
46 pi->peer, &dummy_attr);
47
48 RESET_FLAG(dummy_attr.rmap_change_flags);
7f7940e6 49
1782514f 50 ret = route_map_apply(rmap, dest_p, &path);
52b84062
MK
51 if (ret != RMAP_PERMITMATCH)
52 bgp_attr_flush(&dummy_attr);
e73c112e 53 else {
dc52bece 54 bgp_dest_unlock_node(dest);
e73c112e
MK
55 if (BGP_DEBUG(update, UPDATE_OUT))
56 zlog_debug(
57 "%s: Condition map routes present in BGP table",
58 __func__);
59
c385f82a 60 return ret;
e73c112e 61 }
7f7940e6 62 }
7f7940e6 63 }
e73c112e
MK
64
65 if (BGP_DEBUG(update, UPDATE_OUT))
66 zlog_debug("%s: Condition map routes not present in BGP table",
67 __func__);
68
7f7940e6
MK
69 return ret;
70}
71
c385f82a
MK
72static void bgp_conditional_adv_routes(struct peer *peer, afi_t afi,
73 safi_t safi, struct bgp_table *table,
74 struct route_map *rmap,
e73c112e 75 enum update_type update_type)
7f7940e6
MK
76{
77 int addpath_capable;
52b84062 78 struct bgp_dest *dest;
c385f82a 79 struct bgp_path_info *pi;
52b84062
MK
80 struct bgp_path_info path;
81 struct peer_af *paf;
82 const struct prefix *dest_p;
83 struct update_subgroup *subgrp;
84 struct attr dummy_attr = {0}, attr = {0};
85 struct bgp_path_info_extra path_extra = {0};
7f7940e6
MK
86
87 paf = peer_af_find(peer, afi, safi);
88 if (!paf)
c385f82a 89 return;
7f7940e6
MK
90
91 subgrp = PAF_SUBGRP(paf);
92 /* Ignore if subgroup doesn't exist (implies AF is not negotiated) */
93 if (!subgrp)
c385f82a 94 return;
7f7940e6 95
e73c112e
MK
96 if (BGP_DEBUG(update, UPDATE_OUT))
97 zlog_debug("%s: %s routes to/from %s for %s", __func__,
98 update_type == ADVERTISE ? "Advertise" : "Withdraw",
99 peer->host, get_afi_safi_str(afi, safi, false));
100
7f7940e6
MK
101 addpath_capable = bgp_addpath_encode_tx(peer, afi, safi);
102
c385f82a
MK
103 for (dest = bgp_table_top(table); dest; dest = bgp_route_next(dest)) {
104 dest_p = bgp_dest_get_prefix(dest);
52b84062 105 assert(dest_p);
7f7940e6 106
c385f82a
MK
107 for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) {
108 dummy_attr = *pi->attr;
52b84062
MK
109
110 /* Fill temp path_info */
111 prep_for_rmap_apply(&path, &path_extra, dest, pi,
112 pi->peer, &dummy_attr);
113
114 RESET_FLAG(dummy_attr.rmap_change_flags);
7f7940e6 115
1782514f 116 if (route_map_apply(rmap, dest_p, &path)
52b84062
MK
117 != RMAP_PERMITMATCH) {
118 bgp_attr_flush(&dummy_attr);
7f7940e6 119 continue;
52b84062 120 }
7f7940e6 121
c385f82a
MK
122 if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED)
123 || (addpath_capable
124 && bgp_addpath_tx_path(
125 peer->addpath_type[afi][safi],
126 pi))) {
127
128 /* Skip route-map checks in
129 * subgroup_announce_check while executing from
130 * the conditional advertise scanner process.
131 * otherwise when route-map is also configured
132 * on same peer, routes in advertise-map may not
133 * be advertised as expected.
134 */
e73c112e 135 if ((update_type == ADVERTISE)
c385f82a
MK
136 && subgroup_announce_check(dest, pi, subgrp,
137 dest_p, &attr,
138 true))
139 bgp_adj_out_set_subgroup(dest, subgrp,
140 &attr, pi);
141 else {
142 /* If default originate is enabled for
143 * the peer, do not send explicit
144 * withdraw. This will prevent deletion
145 * of default route advertised through
146 * default originate.
147 */
148 if (CHECK_FLAG(
149 peer->af_flags[afi][safi],
150 PEER_FLAG_DEFAULT_ORIGINATE)
151 && is_default_prefix(dest_p))
152 break;
153
154 bgp_adj_out_unset_subgroup(
155 dest, subgrp, 1,
156 bgp_addpath_id_for_peer(
157 peer, afi, safi,
158 &pi->tx_addpath));
159 }
160 }
7f7940e6
MK
161 }
162 }
7f7940e6
MK
163}
164
165/* Handler of conditional advertisement timer event.
166 * Each route in the condition-map is evaluated.
167 */
168static int bgp_conditional_adv_timer(struct thread *t)
169{
170 afi_t afi;
171 safi_t safi;
172 int pfx_rcd_safi;
173 struct bgp *bgp = NULL;
174 struct peer *peer = NULL;
175 struct peer_af *paf = NULL;
176 struct bgp_table *table = NULL;
177 struct bgp_filter *filter = NULL;
178 struct listnode *node, *nnode = NULL;
179 struct update_subgroup *subgrp = NULL;
c385f82a 180 route_map_result_t ret;
7f7940e6
MK
181
182 bgp = THREAD_ARG(t);
183 assert(bgp);
184
7f7940e6
MK
185 thread_add_timer(bm->master, bgp_conditional_adv_timer, bgp,
186 CONDITIONAL_ROUTES_POLL_TIME, &bgp->t_condition_check);
187
188 /* loop through each peer and advertise or withdraw routes if
189 * advertise-map is configured and prefix(es) in condition-map
c385f82a
MK
190 * does exist(exist-map)/not exist(non-exist-map) in BGP table
191 * based on condition(exist-map or non-exist map)
7f7940e6 192 */
c385f82a
MK
193 for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
194 if (!CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE))
7f7940e6
MK
195 continue;
196
52b84062
MK
197 if (peer->status != Established)
198 continue;
199
c385f82a
MK
200 FOREACH_AFI_SAFI (afi, safi) {
201 if (strmatch(get_afi_safi_str(afi, safi, true),
202 "Unknown"))
7f7940e6 203 continue;
c385f82a 204
52b84062 205 if (!peer->afc_nego[afi][safi])
7f7940e6
MK
206 continue;
207
c385f82a
MK
208 /* labeled-unicast routes are installed in the unicast
209 * table so in order to display the correct PfxRcd value
210 * we must look at SAFI_UNICAST
211 */
212 pfx_rcd_safi = (safi == SAFI_LABELED_UNICAST)
213 ? SAFI_UNICAST
214 : safi;
215
216 table = bgp->rib[afi][pfx_rcd_safi];
217 if (!table)
218 continue;
219
7f7940e6
MK
220 filter = &peer->filter[afi][safi];
221
c385f82a
MK
222 if (!filter->advmap.aname || !filter->advmap.cname
223 || !filter->advmap.amap || !filter->advmap.cmap)
224 continue;
225
226 if (!peer->advmap_config_change[afi][safi]
227 && !peer->advmap_table_change)
7f7940e6
MK
228 continue;
229
e73c112e
MK
230 if (BGP_DEBUG(update, UPDATE_OUT)) {
231 if (peer->advmap_table_change)
232 zlog_debug(
233 "%s: %s - routes changed in BGP table.",
234 __func__, peer->host);
235 if (peer->advmap_config_change[afi][safi])
236 zlog_debug(
237 "%s: %s for %s - advertise/condition map configuration is changed.",
238 __func__, peer->host,
239 get_afi_safi_str(afi, safi,
240 false));
241 }
242
7f7940e6
MK
243 /* cmap (route-map attached to exist-map or
244 * non-exist-map) map validation
245 */
c385f82a
MK
246 ret = bgp_check_rmap_prefixes_in_bgp_table(
247 table, filter->advmap.cmap);
7f7940e6
MK
248
249 /* Derive conditional advertisement status from
250 * condition and return value of condition-map
251 * validation.
252 */
c385f82a 253 if (filter->advmap.condition == CONDITION_EXIST)
fa36596c 254 filter->advmap.update_type =
c385f82a
MK
255 (ret == RMAP_PERMITMATCH) ? ADVERTISE
256 : WITHDRAW;
257 else
fa36596c 258 filter->advmap.update_type =
c385f82a
MK
259 (ret == RMAP_PERMITMATCH) ? WITHDRAW
260 : ADVERTISE;
7f7940e6 261
c5aec50b
MK
262 /* Send regular update as per the existing policy.
263 * There is a change in route-map, match-rule, ACLs,
264 * or route-map filter configuration on the same peer.
265 */
c385f82a 266 if (peer->advmap_config_change[afi][safi]) {
e73c112e
MK
267
268 if (BGP_DEBUG(update, UPDATE_OUT))
269 zlog_debug(
270 "%s: Configuration is changed on peer %s for %s, send the normal update first.",
271 __func__, peer->host,
272 get_afi_safi_str(afi, safi,
273 false));
274
7f7940e6
MK
275 paf = peer_af_find(peer, afi, safi);
276 if (paf) {
277 update_subgroup_split_peer(paf, NULL);
278 subgrp = paf->subgroup;
279 if (subgrp && subgrp->update_group)
280 subgroup_announce_table(
281 paf->subgroup, NULL);
282 }
c385f82a 283 peer->advmap_config_change[afi][safi] = false;
7f7940e6 284 }
c5aec50b
MK
285
286 /* Send update as per the conditional advertisement */
c385f82a
MK
287 bgp_conditional_adv_routes(peer, afi, safi, table,
288 filter->advmap.amap,
fa36596c 289 filter->advmap.update_type);
7f7940e6 290 }
c385f82a 291 peer->advmap_table_change = false;
7f7940e6
MK
292 }
293 return 0;
294}
295
296void bgp_conditional_adv_enable(struct peer *peer, afi_t afi, safi_t safi)
297{
298 struct bgp *bgp = peer->bgp;
299
300 assert(bgp);
301
302 /* This flag is used to monitor conditional routes status in BGP table,
303 * and advertise/withdraw routes only when there is a change in BGP
304 * table w.r.t conditional routes
305 */
c385f82a 306 peer->advmap_config_change[afi][safi] = true;
7f7940e6
MK
307
308 /* advertise-map is already configured on atleast one of its
309 * neighbors (AFI/SAFI). So just increment the counter.
310 */
e73c112e
MK
311 if (++bgp->condition_filter_count > 1) {
312 if (BGP_DEBUG(update, UPDATE_OUT))
313 zlog_debug("%s: condition_filter_count %d", __func__,
314 bgp->condition_filter_count);
315
7f7940e6 316 return;
e73c112e 317 }
7f7940e6
MK
318
319 /* Register for conditional routes polling timer */
320 thread_add_timer(bm->master, bgp_conditional_adv_timer, bgp,
321 CONDITIONAL_ROUTES_POLL_TIME, &bgp->t_condition_check);
322}
323
324void bgp_conditional_adv_disable(struct peer *peer, afi_t afi, safi_t safi)
325{
326 struct bgp *bgp = peer->bgp;
327
328 assert(bgp);
329
330 /* advertise-map is not configured on any of its neighbors or
331 * it is configured on more than one neighbor(AFI/SAFI).
332 * So there's nothing to do except decrementing the counter.
333 */
e73c112e
MK
334 if (--bgp->condition_filter_count != 0) {
335 if (BGP_DEBUG(update, UPDATE_OUT))
336 zlog_debug("%s: condition_filter_count %d", __func__,
337 bgp->condition_filter_count);
338
7f7940e6 339 return;
e73c112e 340 }
7f7940e6
MK
341
342 /* Last filter removed. So cancel conditional routes polling thread. */
343 THREAD_OFF(bgp->t_condition_check);
344}