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