2 * BGP Conditional advertisement
3 * Copyright (C) 2020 Samsung R&D Institute India - Bangalore.
4 * Madhurilatha Kuruganti
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)
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
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
21 #include "bgpd/bgp_conditional_adv.h"
23 const char *get_afi_safi_str(afi_t afi
, safi_t safi
, bool for_json
);
25 static route_map_result_t
26 bgp_check_rmap_prefixes_in_bgp_table(struct bgp_table
*table
,
27 struct route_map
*rmap
)
29 struct attr dummy_attr
= {0};
30 struct bgp_dest
*dest
;
31 struct bgp_path_info
*pi
;
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
;
37 for (dest
= bgp_table_top(table
); dest
; dest
= bgp_route_next(dest
)) {
38 dest_p
= bgp_dest_get_prefix(dest
);
41 for (pi
= bgp_dest_get_bgp_path_info(dest
); pi
; pi
= pi
->next
) {
42 dummy_attr
= *pi
->attr
;
44 /* Fill temp path_info */
45 prep_for_rmap_apply(&path
, &path_extra
, dest
, pi
,
46 pi
->peer
, &dummy_attr
);
48 RESET_FLAG(dummy_attr
.rmap_change_flags
);
50 ret
= route_map_apply(rmap
, dest_p
, &path
);
51 if (ret
!= RMAP_PERMITMATCH
)
52 bgp_attr_flush(&dummy_attr
);
54 bgp_dest_unlock_node(dest
);
55 if (BGP_DEBUG(update
, UPDATE_OUT
))
57 "%s: Condition map routes present in BGP table",
65 if (BGP_DEBUG(update
, UPDATE_OUT
))
66 zlog_debug("%s: Condition map routes not present in BGP table",
72 static void bgp_conditional_adv_routes(struct peer
*peer
, afi_t afi
,
73 safi_t safi
, struct bgp_table
*table
,
74 struct route_map
*rmap
,
75 enum update_type update_type
)
78 struct bgp_dest
*dest
;
79 struct bgp_path_info
*pi
;
80 struct bgp_path_info path
;
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};
87 paf
= peer_af_find(peer
, afi
, safi
);
91 subgrp
= PAF_SUBGRP(paf
);
92 /* Ignore if subgroup doesn't exist (implies AF is not negotiated) */
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));
101 addpath_capable
= bgp_addpath_encode_tx(peer
, afi
, safi
);
103 for (dest
= bgp_table_top(table
); dest
; dest
= bgp_route_next(dest
)) {
104 dest_p
= bgp_dest_get_prefix(dest
);
107 for (pi
= bgp_dest_get_bgp_path_info(dest
); pi
; pi
= pi
->next
) {
108 dummy_attr
= *pi
->attr
;
110 /* Fill temp path_info */
111 prep_for_rmap_apply(&path
, &path_extra
, dest
, pi
,
112 pi
->peer
, &dummy_attr
);
114 RESET_FLAG(dummy_attr
.rmap_change_flags
);
116 if (route_map_apply(rmap
, dest_p
, &path
)
117 != RMAP_PERMITMATCH
) {
118 bgp_attr_flush(&dummy_attr
);
122 if (CHECK_FLAG(pi
->flags
, BGP_PATH_SELECTED
)
124 && bgp_addpath_tx_path(
125 peer
->addpath_type
[afi
][safi
],
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.
135 if ((update_type
== ADVERTISE
)
136 && subgroup_announce_check(dest
, pi
, subgrp
,
139 bgp_adj_out_set_subgroup(dest
, subgrp
,
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
149 peer
->af_flags
[afi
][safi
],
150 PEER_FLAG_DEFAULT_ORIGINATE
)
151 && is_default_prefix(dest_p
))
154 bgp_adj_out_unset_subgroup(
156 bgp_addpath_id_for_peer(
165 /* Handler of conditional advertisement timer event.
166 * Each route in the condition-map is evaluated.
168 static int bgp_conditional_adv_timer(struct thread
*t
)
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
;
180 route_map_result_t ret
;
185 thread_add_timer(bm
->master
, bgp_conditional_adv_timer
, bgp
,
186 CONDITIONAL_ROUTES_POLL_TIME
, &bgp
->t_condition_check
);
188 /* loop through each peer and advertise or withdraw routes if
189 * advertise-map is configured and prefix(es) in condition-map
190 * does exist(exist-map)/not exist(non-exist-map) in BGP table
191 * based on condition(exist-map or non-exist map)
193 for (ALL_LIST_ELEMENTS(bgp
->peer
, node
, nnode
, peer
)) {
194 if (!CHECK_FLAG(peer
->flags
, PEER_FLAG_CONFIG_NODE
))
197 if (peer
->status
!= Established
)
200 FOREACH_AFI_SAFI (afi
, safi
) {
201 if (strmatch(get_afi_safi_str(afi
, safi
, true),
205 if (!peer
->afc_nego
[afi
][safi
])
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
212 pfx_rcd_safi
= (safi
== SAFI_LABELED_UNICAST
)
216 table
= bgp
->rib
[afi
][pfx_rcd_safi
];
220 filter
= &peer
->filter
[afi
][safi
];
222 if (!filter
->advmap
.aname
|| !filter
->advmap
.cname
223 || !filter
->advmap
.amap
|| !filter
->advmap
.cmap
)
226 if (!peer
->advmap_config_change
[afi
][safi
]
227 && !peer
->advmap_table_change
)
230 if (BGP_DEBUG(update
, UPDATE_OUT
)) {
231 if (peer
->advmap_table_change
)
233 "%s: %s - routes changed in BGP table.",
234 __func__
, peer
->host
);
235 if (peer
->advmap_config_change
[afi
][safi
])
237 "%s: %s for %s - advertise/condition map configuration is changed.",
238 __func__
, peer
->host
,
239 get_afi_safi_str(afi
, safi
,
243 /* cmap (route-map attached to exist-map or
244 * non-exist-map) map validation
246 ret
= bgp_check_rmap_prefixes_in_bgp_table(
247 table
, filter
->advmap
.cmap
);
249 /* Derive conditional advertisement status from
250 * condition and return value of condition-map
253 if (filter
->advmap
.condition
== CONDITION_EXIST
)
254 filter
->advmap
.update_type
=
255 (ret
== RMAP_PERMITMATCH
) ? ADVERTISE
258 filter
->advmap
.update_type
=
259 (ret
== RMAP_PERMITMATCH
) ? WITHDRAW
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.
266 if (peer
->advmap_config_change
[afi
][safi
]) {
268 if (BGP_DEBUG(update
, UPDATE_OUT
))
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
,
275 paf
= peer_af_find(peer
, afi
, safi
);
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
);
283 peer
->advmap_config_change
[afi
][safi
] = false;
286 /* Send update as per the conditional advertisement */
287 bgp_conditional_adv_routes(peer
, afi
, safi
, table
,
289 filter
->advmap
.update_type
);
291 peer
->advmap_table_change
= false;
296 void bgp_conditional_adv_enable(struct peer
*peer
, afi_t afi
, safi_t safi
)
298 struct bgp
*bgp
= peer
->bgp
;
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
306 peer
->advmap_config_change
[afi
][safi
] = true;
308 /* advertise-map is already configured on atleast one of its
309 * neighbors (AFI/SAFI). So just increment the counter.
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
);
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
);
324 void bgp_conditional_adv_disable(struct peer
*peer
, afi_t afi
, safi_t safi
)
326 struct bgp
*bgp
= peer
->bgp
;
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.
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
);
342 /* Last filter removed. So cancel conditional routes polling thread. */
343 THREAD_OFF(bgp
->t_condition_check
);