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