]>
Commit | Line | Data |
---|---|---|
acddc0ed | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
7f7940e6 MK |
2 | /* |
3 | * BGP Conditional advertisement | |
1a0416bd | 4 | * Copyright (C) 2020 Samsung R&D Institute India - Bangalore. |
7f7940e6 | 5 | * Madhurilatha Kuruganti |
7f7940e6 MK |
6 | */ |
7 | ||
1f8031f7 DL |
8 | #include <zebra.h> |
9 | ||
7f7940e6 | 10 | #include "bgpd/bgp_conditional_adv.h" |
3742de8d | 11 | #include "bgpd/bgp_vty.h" |
7f7940e6 | 12 | |
c385f82a | 13 | static route_map_result_t |
7f7940e6 MK |
14 | bgp_check_rmap_prefixes_in_bgp_table(struct bgp_table *table, |
15 | struct route_map *rmap) | |
16 | { | |
52b84062 | 17 | struct attr dummy_attr = {0}; |
c385f82a | 18 | struct bgp_dest *dest; |
c385f82a | 19 | struct bgp_path_info *pi; |
52b84062 MK |
20 | struct bgp_path_info path = {0}; |
21 | struct bgp_path_info_extra path_extra = {0}; | |
22 | const struct prefix *dest_p; | |
23 | route_map_result_t ret = RMAP_DENYMATCH; | |
c385f82a MK |
24 | |
25 | for (dest = bgp_table_top(table); dest; dest = bgp_route_next(dest)) { | |
26 | dest_p = bgp_dest_get_prefix(dest); | |
52b84062 | 27 | assert(dest_p); |
7f7940e6 | 28 | |
c385f82a MK |
29 | for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) { |
30 | dummy_attr = *pi->attr; | |
52b84062 MK |
31 | |
32 | /* Fill temp path_info */ | |
33 | prep_for_rmap_apply(&path, &path_extra, dest, pi, | |
34 | pi->peer, &dummy_attr); | |
35 | ||
36 | RESET_FLAG(dummy_attr.rmap_change_flags); | |
7f7940e6 | 37 | |
1782514f | 38 | ret = route_map_apply(rmap, dest_p, &path); |
ee522f57 IR |
39 | bgp_attr_flush(&dummy_attr); |
40 | ||
41 | if (ret == RMAP_PERMITMATCH) { | |
dc52bece | 42 | bgp_dest_unlock_node(dest); |
8093d799 MK |
43 | bgp_cond_adv_debug( |
44 | "%s: Condition map routes present in BGP table", | |
45 | __func__); | |
e73c112e | 46 | |
c385f82a | 47 | return ret; |
e73c112e | 48 | } |
7f7940e6 | 49 | } |
7f7940e6 | 50 | } |
e73c112e | 51 | |
8093d799 | 52 | bgp_cond_adv_debug("%s: Condition map routes not present in BGP table", |
e73c112e MK |
53 | __func__); |
54 | ||
7f7940e6 MK |
55 | return ret; |
56 | } | |
57 | ||
c385f82a MK |
58 | static void bgp_conditional_adv_routes(struct peer *peer, afi_t afi, |
59 | safi_t safi, struct bgp_table *table, | |
60 | struct route_map *rmap, | |
e73c112e | 61 | enum update_type update_type) |
7f7940e6 | 62 | { |
be92fc9f | 63 | bool addpath_capable; |
52b84062 | 64 | struct bgp_dest *dest; |
c385f82a | 65 | struct bgp_path_info *pi; |
52b84062 MK |
66 | struct bgp_path_info path; |
67 | struct peer_af *paf; | |
68 | const struct prefix *dest_p; | |
69 | struct update_subgroup *subgrp; | |
51c3a7de | 70 | struct attr advmap_attr = {0}, attr = {0}; |
52b84062 | 71 | struct bgp_path_info_extra path_extra = {0}; |
ee522f57 | 72 | route_map_result_t ret; |
7f7940e6 MK |
73 | |
74 | paf = peer_af_find(peer, afi, safi); | |
75 | if (!paf) | |
c385f82a | 76 | return; |
7f7940e6 MK |
77 | |
78 | subgrp = PAF_SUBGRP(paf); | |
79 | /* Ignore if subgroup doesn't exist (implies AF is not negotiated) */ | |
80 | if (!subgrp) | |
c385f82a | 81 | return; |
7f7940e6 | 82 | |
d0bf49ec LS |
83 | subgrp->pscount = 0; |
84 | SET_FLAG(subgrp->sflags, SUBGRP_STATUS_TABLE_REPARSING); | |
85 | ||
8093d799 | 86 | bgp_cond_adv_debug("%s: %s routes to/from %s for %s", __func__, |
ecf2b628 QY |
87 | update_type == UPDATE_TYPE_ADVERTISE ? "Advertise" |
88 | : "Withdraw", | |
e73c112e MK |
89 | peer->host, get_afi_safi_str(afi, safi, false)); |
90 | ||
7f7940e6 MK |
91 | addpath_capable = bgp_addpath_encode_tx(peer, afi, safi); |
92 | ||
c385f82a MK |
93 | for (dest = bgp_table_top(table); dest; dest = bgp_route_next(dest)) { |
94 | dest_p = bgp_dest_get_prefix(dest); | |
52b84062 | 95 | assert(dest_p); |
7f7940e6 | 96 | |
c385f82a | 97 | for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) { |
51c3a7de | 98 | advmap_attr = *pi->attr; |
52b84062 MK |
99 | |
100 | /* Fill temp path_info */ | |
101 | prep_for_rmap_apply(&path, &path_extra, dest, pi, | |
51c3a7de | 102 | pi->peer, &advmap_attr); |
52b84062 | 103 | |
51c3a7de | 104 | RESET_FLAG(advmap_attr.rmap_change_flags); |
7f7940e6 | 105 | |
ee522f57 | 106 | ret = route_map_apply(rmap, dest_p, &path); |
51c3a7de DA |
107 | if (ret != RMAP_PERMITMATCH || |
108 | !bgp_check_selected(pi, peer, addpath_capable, afi, | |
109 | safi)) { | |
110 | bgp_attr_flush(&advmap_attr); | |
7f7940e6 | 111 | continue; |
51c3a7de | 112 | } |
7f7940e6 | 113 | |
51c3a7de DA |
114 | /* Skip route-map checks in |
115 | * subgroup_announce_check while executing from | |
116 | * the conditional advertise scanner process. | |
117 | * otherwise when route-map is also configured | |
118 | * on same peer, routes in advertise-map may not | |
119 | * be advertised as expected. | |
120 | */ | |
ecf2b628 | 121 | if (update_type == UPDATE_TYPE_ADVERTISE && |
51c3a7de DA |
122 | subgroup_announce_check(dest, pi, subgrp, dest_p, |
123 | &attr, &advmap_attr)) { | |
124 | bgp_adj_out_set_subgroup(dest, subgrp, &attr, | |
125 | pi); | |
126 | } else { | |
127 | /* If default originate is enabled for | |
128 | * the peer, do not send explicit | |
129 | * withdraw. This will prevent deletion | |
130 | * of default route advertised through | |
131 | * default originate. | |
c385f82a | 132 | */ |
51c3a7de DA |
133 | if (CHECK_FLAG(peer->af_flags[afi][safi], |
134 | PEER_FLAG_DEFAULT_ORIGINATE) && | |
135 | is_default_prefix(dest_p)) | |
136 | break; | |
137 | ||
138 | bgp_adj_out_unset_subgroup( | |
139 | dest, subgrp, 1, | |
140 | bgp_addpath_id_for_peer( | |
141 | peer, afi, safi, | |
142 | &pi->tx_addpath)); | |
c385f82a | 143 | } |
51c3a7de | 144 | bgp_attr_flush(&advmap_attr); |
7f7940e6 MK |
145 | } |
146 | } | |
d0bf49ec | 147 | UNSET_FLAG(subgrp->sflags, SUBGRP_STATUS_TABLE_REPARSING); |
7f7940e6 MK |
148 | } |
149 | ||
150 | /* Handler of conditional advertisement timer event. | |
151 | * Each route in the condition-map is evaluated. | |
152 | */ | |
cc9f21da | 153 | static void bgp_conditional_adv_timer(struct thread *t) |
7f7940e6 MK |
154 | { |
155 | afi_t afi; | |
156 | safi_t safi; | |
157 | int pfx_rcd_safi; | |
158 | struct bgp *bgp = NULL; | |
159 | struct peer *peer = NULL; | |
160 | struct peer_af *paf = NULL; | |
161 | struct bgp_table *table = NULL; | |
162 | struct bgp_filter *filter = NULL; | |
163 | struct listnode *node, *nnode = NULL; | |
164 | struct update_subgroup *subgrp = NULL; | |
c385f82a | 165 | route_map_result_t ret; |
07753623 | 166 | bool advmap_table_changed = false; |
7f7940e6 MK |
167 | |
168 | bgp = THREAD_ARG(t); | |
169 | assert(bgp); | |
170 | ||
7f7940e6 | 171 | thread_add_timer(bm->master, bgp_conditional_adv_timer, bgp, |
389e4f92 | 172 | bgp->condition_check_period, &bgp->t_condition_check); |
7f7940e6 | 173 | |
07753623 DA |
174 | /* loop through each peer and check if we have peers with |
175 | * advmap_table_change attribute set, to make sure we send | |
176 | * conditional advertisements properly below. | |
177 | * peer->advmap_table_change is added on incoming BGP UPDATES, | |
178 | * but here it's used for outgoing UPDATES, hence we need to | |
179 | * check if at least one peer got advmap_table_change. | |
180 | */ | |
181 | for (ALL_LIST_ELEMENTS_RO(bgp->peer, node, peer)) { | |
182 | if (peer->advmap_table_change) { | |
183 | advmap_table_changed = true; | |
184 | break; | |
185 | } | |
186 | } | |
187 | ||
7f7940e6 MK |
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 | ||
feb17238 | 197 | if (!peer_established(peer)) |
52b84062 MK |
198 | continue; |
199 | ||
c385f82a | 200 | FOREACH_AFI_SAFI (afi, safi) { |
52b84062 | 201 | if (!peer->afc_nego[afi][safi]) |
7f7940e6 MK |
202 | continue; |
203 | ||
c385f82a MK |
204 | /* labeled-unicast routes are installed in the unicast |
205 | * table so in order to display the correct PfxRcd value | |
206 | * we must look at SAFI_UNICAST | |
207 | */ | |
208 | pfx_rcd_safi = (safi == SAFI_LABELED_UNICAST) | |
209 | ? SAFI_UNICAST | |
210 | : safi; | |
211 | ||
212 | table = bgp->rib[afi][pfx_rcd_safi]; | |
213 | if (!table) | |
214 | continue; | |
215 | ||
7f7940e6 MK |
216 | filter = &peer->filter[afi][safi]; |
217 | ||
c385f82a MK |
218 | if (!filter->advmap.aname || !filter->advmap.cname |
219 | || !filter->advmap.amap || !filter->advmap.cmap) | |
220 | continue; | |
221 | ||
07753623 DA |
222 | if (!peer->advmap_config_change[afi][safi] && |
223 | !advmap_table_changed) | |
7f7940e6 MK |
224 | continue; |
225 | ||
8093d799 | 226 | if (BGP_DEBUG(cond_adv, COND_ADV)) { |
e73c112e MK |
227 | if (peer->advmap_table_change) |
228 | zlog_debug( | |
229 | "%s: %s - routes changed in BGP table.", | |
230 | __func__, peer->host); | |
231 | if (peer->advmap_config_change[afi][safi]) | |
232 | zlog_debug( | |
233 | "%s: %s for %s - advertise/condition map configuration is changed.", | |
234 | __func__, peer->host, | |
235 | get_afi_safi_str(afi, safi, | |
236 | false)); | |
237 | } | |
238 | ||
7f7940e6 MK |
239 | /* cmap (route-map attached to exist-map or |
240 | * non-exist-map) map validation | |
241 | */ | |
c385f82a MK |
242 | ret = bgp_check_rmap_prefixes_in_bgp_table( |
243 | table, filter->advmap.cmap); | |
7f7940e6 MK |
244 | |
245 | /* Derive conditional advertisement status from | |
246 | * condition and return value of condition-map | |
247 | * validation. | |
248 | */ | |
c385f82a | 249 | if (filter->advmap.condition == CONDITION_EXIST) |
fa36596c | 250 | filter->advmap.update_type = |
ecf2b628 QY |
251 | (ret == RMAP_PERMITMATCH) |
252 | ? UPDATE_TYPE_ADVERTISE | |
253 | : UPDATE_TYPE_WITHDRAW; | |
c385f82a | 254 | else |
fa36596c | 255 | filter->advmap.update_type = |
ecf2b628 QY |
256 | (ret == RMAP_PERMITMATCH) |
257 | ? UPDATE_TYPE_WITHDRAW | |
258 | : UPDATE_TYPE_ADVERTISE; | |
7f7940e6 | 259 | |
f373ce6c QY |
260 | /* |
261 | * Update condadv update type so | |
262 | * subgroup_announce_check() can properly apply | |
263 | * outbound policy according to advertisement state | |
264 | */ | |
265 | paf = peer_af_find(peer, afi, safi); | |
266 | if (paf && (SUBGRP_PEER(PAF_SUBGRP(paf)) | |
267 | ->filter[afi][safi] | |
268 | .advmap.update_type != | |
269 | filter->advmap.update_type)) { | |
270 | /* Handle change to peer advmap */ | |
8093d799 MK |
271 | bgp_cond_adv_debug( |
272 | "%s: advmap.update_type changed for peer %s, adjusting update_group.", | |
273 | __func__, peer->host); | |
f373ce6c QY |
274 | |
275 | update_group_adjust_peer(paf); | |
276 | } | |
277 | ||
c5aec50b MK |
278 | /* Send regular update as per the existing policy. |
279 | * There is a change in route-map, match-rule, ACLs, | |
280 | * or route-map filter configuration on the same peer. | |
281 | */ | |
c385f82a | 282 | if (peer->advmap_config_change[afi][safi]) { |
e73c112e | 283 | |
8093d799 MK |
284 | bgp_cond_adv_debug( |
285 | "%s: Configuration is changed on peer %s for %s, send the normal update first.", | |
286 | __func__, peer->host, | |
287 | get_afi_safi_str(afi, safi, false)); | |
7f7940e6 MK |
288 | if (paf) { |
289 | update_subgroup_split_peer(paf, NULL); | |
290 | subgrp = paf->subgroup; | |
f373ce6c | 291 | |
7f7940e6 MK |
292 | if (subgrp && subgrp->update_group) |
293 | subgroup_announce_table( | |
294 | paf->subgroup, NULL); | |
295 | } | |
c385f82a | 296 | peer->advmap_config_change[afi][safi] = false; |
7f7940e6 | 297 | } |
c5aec50b MK |
298 | |
299 | /* Send update as per the conditional advertisement */ | |
c385f82a MK |
300 | bgp_conditional_adv_routes(peer, afi, safi, table, |
301 | filter->advmap.amap, | |
fa36596c | 302 | filter->advmap.update_type); |
7f7940e6 | 303 | } |
c385f82a | 304 | peer->advmap_table_change = false; |
7f7940e6 | 305 | } |
7f7940e6 MK |
306 | } |
307 | ||
308 | void bgp_conditional_adv_enable(struct peer *peer, afi_t afi, safi_t safi) | |
309 | { | |
310 | struct bgp *bgp = peer->bgp; | |
311 | ||
312 | assert(bgp); | |
313 | ||
314 | /* This flag is used to monitor conditional routes status in BGP table, | |
315 | * and advertise/withdraw routes only when there is a change in BGP | |
316 | * table w.r.t conditional routes | |
317 | */ | |
c385f82a | 318 | peer->advmap_config_change[afi][safi] = true; |
7f7940e6 | 319 | |
2ef62909 | 320 | /* advertise-map is already configured on at least one of its |
7f7940e6 MK |
321 | * neighbors (AFI/SAFI). So just increment the counter. |
322 | */ | |
e73c112e | 323 | if (++bgp->condition_filter_count > 1) { |
8093d799 | 324 | bgp_cond_adv_debug("%s: condition_filter_count %d", __func__, |
e73c112e MK |
325 | bgp->condition_filter_count); |
326 | ||
7f7940e6 | 327 | return; |
e73c112e | 328 | } |
7f7940e6 MK |
329 | |
330 | /* Register for conditional routes polling timer */ | |
06bb44c8 DA |
331 | if (!thread_is_scheduled(bgp->t_condition_check)) |
332 | thread_add_timer(bm->master, bgp_conditional_adv_timer, bgp, 0, | |
333 | &bgp->t_condition_check); | |
7f7940e6 MK |
334 | } |
335 | ||
336 | void bgp_conditional_adv_disable(struct peer *peer, afi_t afi, safi_t safi) | |
337 | { | |
338 | struct bgp *bgp = peer->bgp; | |
339 | ||
340 | assert(bgp); | |
341 | ||
342 | /* advertise-map is not configured on any of its neighbors or | |
343 | * it is configured on more than one neighbor(AFI/SAFI). | |
344 | * So there's nothing to do except decrementing the counter. | |
345 | */ | |
e73c112e | 346 | if (--bgp->condition_filter_count != 0) { |
8093d799 | 347 | bgp_cond_adv_debug("%s: condition_filter_count %d", __func__, |
e73c112e MK |
348 | bgp->condition_filter_count); |
349 | ||
7f7940e6 | 350 | return; |
e73c112e | 351 | } |
7f7940e6 MK |
352 | |
353 | /* Last filter removed. So cancel conditional routes polling thread. */ | |
354 | THREAD_OFF(bgp->t_condition_check); | |
355 | } | |
e85e4a8d MK |
356 | |
357 | static void peer_advertise_map_filter_update(struct peer *peer, afi_t afi, | |
358 | safi_t safi, const char *amap_name, | |
359 | struct route_map *amap, | |
360 | const char *cmap_name, | |
361 | struct route_map *cmap, | |
362 | bool condition, bool set) | |
363 | { | |
364 | struct bgp_filter *filter; | |
365 | bool filter_exists = false; | |
366 | ||
367 | filter = &peer->filter[afi][safi]; | |
368 | ||
369 | /* advertise-map is already configured. */ | |
370 | if (filter->advmap.aname) { | |
371 | filter_exists = true; | |
372 | XFREE(MTYPE_BGP_FILTER_NAME, filter->advmap.aname); | |
373 | XFREE(MTYPE_BGP_FILTER_NAME, filter->advmap.cname); | |
374 | } | |
375 | ||
376 | route_map_counter_decrement(filter->advmap.amap); | |
377 | ||
378 | /* Removed advertise-map configuration */ | |
379 | if (!set) { | |
380 | memset(&filter->advmap, 0, sizeof(filter->advmap)); | |
381 | ||
382 | /* decrement condition_filter_count delete timer if | |
383 | * this is the last advertise-map to be removed. | |
384 | */ | |
385 | if (filter_exists) | |
386 | bgp_conditional_adv_disable(peer, afi, safi); | |
387 | ||
388 | /* Process peer route updates. */ | |
389 | peer_on_policy_change(peer, afi, safi, 1); | |
390 | ||
391 | return; | |
392 | } | |
393 | ||
394 | /* Update filter data with newly configured values. */ | |
395 | filter->advmap.aname = XSTRDUP(MTYPE_BGP_FILTER_NAME, amap_name); | |
396 | filter->advmap.cname = XSTRDUP(MTYPE_BGP_FILTER_NAME, cmap_name); | |
397 | filter->advmap.amap = amap; | |
398 | filter->advmap.cmap = cmap; | |
399 | filter->advmap.condition = condition; | |
400 | route_map_counter_increment(filter->advmap.amap); | |
401 | peer->advmap_config_change[afi][safi] = true; | |
402 | ||
403 | /* Increment condition_filter_count and/or create timer. */ | |
404 | if (!filter_exists) { | |
405 | filter->advmap.update_type = UPDATE_TYPE_ADVERTISE; | |
406 | bgp_conditional_adv_enable(peer, afi, safi); | |
407 | } | |
408 | ||
409 | /* Process peer route updates. */ | |
410 | peer_on_policy_change(peer, afi, safi, 1); | |
411 | } | |
412 | ||
413 | /* Set advertise-map to the peer. */ | |
414 | int peer_advertise_map_set(struct peer *peer, afi_t afi, safi_t safi, | |
415 | const char *advertise_name, | |
416 | struct route_map *advertise_map, | |
417 | const char *condition_name, | |
418 | struct route_map *condition_map, bool condition) | |
419 | { | |
420 | struct peer *member; | |
421 | struct listnode *node, *nnode; | |
422 | ||
423 | /* Set configuration on peer. */ | |
424 | peer_advertise_map_filter_update(peer, afi, safi, advertise_name, | |
425 | advertise_map, condition_name, | |
426 | condition_map, condition, true); | |
427 | ||
428 | /* Check if handling a regular peer & Skip peer-group mechanics. */ | |
429 | if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { | |
430 | /* Set override-flag and process peer route updates. */ | |
431 | SET_FLAG(peer->filter_override[afi][safi][RMAP_OUT], | |
432 | PEER_FT_ADVERTISE_MAP); | |
433 | return 0; | |
434 | } | |
435 | ||
436 | /* | |
437 | * Set configuration on all peer-group members, unless they are | |
438 | * explicitly overriding peer-group configuration. | |
439 | */ | |
440 | for (ALL_LIST_ELEMENTS(peer->group->peer, node, nnode, member)) { | |
441 | /* Skip peers with overridden configuration. */ | |
442 | if (CHECK_FLAG(member->filter_override[afi][safi][RMAP_OUT], | |
443 | PEER_FT_ADVERTISE_MAP)) | |
444 | continue; | |
445 | ||
446 | /* Set configuration on peer-group member. */ | |
447 | peer_advertise_map_filter_update( | |
448 | member, afi, safi, advertise_name, advertise_map, | |
449 | condition_name, condition_map, condition, true); | |
450 | } | |
451 | ||
452 | return 0; | |
453 | } | |
454 | ||
455 | /* Unset advertise-map from the peer. */ | |
456 | int peer_advertise_map_unset(struct peer *peer, afi_t afi, safi_t safi, | |
457 | const char *advertise_name, | |
458 | struct route_map *advertise_map, | |
459 | const char *condition_name, | |
460 | struct route_map *condition_map, bool condition) | |
461 | { | |
462 | struct peer *member; | |
463 | struct listnode *node, *nnode; | |
464 | ||
465 | /* advertise-map is not configured */ | |
466 | if (!peer->filter[afi][safi].advmap.aname) | |
467 | return 0; | |
468 | ||
469 | /* Unset override-flag unconditionally. */ | |
470 | UNSET_FLAG(peer->filter_override[afi][safi][RMAP_OUT], | |
471 | PEER_FT_ADVERTISE_MAP); | |
472 | ||
473 | /* Inherit configuration from peer-group if peer is member. */ | |
474 | if (peer_group_active(peer)) { | |
475 | PEER_STR_ATTR_INHERIT(peer, peer->group, | |
476 | filter[afi][safi].advmap.aname, | |
477 | MTYPE_BGP_FILTER_NAME); | |
478 | PEER_ATTR_INHERIT(peer, peer->group, | |
479 | filter[afi][safi].advmap.amap); | |
480 | } else | |
481 | peer_advertise_map_filter_update( | |
482 | peer, afi, safi, advertise_name, advertise_map, | |
483 | condition_name, condition_map, condition, false); | |
484 | ||
485 | /* Check if handling a regular peer and skip peer-group mechanics. */ | |
486 | if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { | |
487 | /* Process peer route updates. */ | |
488 | bgp_cond_adv_debug("%s: Send normal update to %s for %s", | |
489 | __func__, peer->host, | |
490 | get_afi_safi_str(afi, safi, false)); | |
491 | ||
492 | return 0; | |
493 | } | |
494 | ||
495 | /* | |
496 | * Remove configuration on all peer-group members, unless they are | |
497 | * explicitly overriding peer-group configuration. | |
498 | */ | |
499 | for (ALL_LIST_ELEMENTS(peer->group->peer, node, nnode, member)) { | |
500 | /* Skip peers with overridden configuration. */ | |
501 | if (CHECK_FLAG(member->filter_override[afi][safi][RMAP_OUT], | |
502 | PEER_FT_ADVERTISE_MAP)) | |
503 | continue; | |
504 | /* Remove configuration on peer-group member. */ | |
505 | peer_advertise_map_filter_update( | |
506 | member, afi, safi, advertise_name, advertise_map, | |
507 | condition_name, condition_map, condition, false); | |
508 | ||
509 | /* Process peer route updates. */ | |
510 | bgp_cond_adv_debug("%s: Send normal update to %s for %s ", | |
511 | __func__, member->host, | |
512 | get_afi_safi_str(afi, safi, false)); | |
513 | } | |
514 | ||
515 | return 0; | |
516 | } |