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