]>
Commit | Line | Data |
---|---|---|
718e3744 | 1 | /* Redistribution Handler |
2 | * Copyright (C) 1998 Kunihiro Ishiguro | |
3 | * | |
4 | * This file is part of GNU Zebra. | |
5 | * | |
6 | * GNU Zebra 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 | |
8 | * Free Software Foundation; either version 2, or (at your option) any | |
9 | * later version. | |
10 | * | |
11 | * GNU Zebra is distributed in the hope that it will be useful, but | |
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
14 | * General Public License for more details. | |
15 | * | |
896014f4 DL |
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 | |
718e3744 | 19 | */ |
20 | ||
21 | #include <zebra.h> | |
22 | ||
23 | #include "vector.h" | |
24 | #include "vty.h" | |
25 | #include "command.h" | |
26 | #include "prefix.h" | |
27 | #include "table.h" | |
28 | #include "stream.h" | |
29 | #include "zclient.h" | |
30 | #include "linklist.h" | |
31 | #include "log.h" | |
b72ede27 | 32 | #include "vrf.h" |
05737783 | 33 | #include "srcdest_table.h" |
718e3744 | 34 | |
35 | #include "zebra/rib.h" | |
161e9ab7 | 36 | #include "zebra/zebra_router.h" |
7c551956 DS |
37 | #include "zebra/zebra_ns.h" |
38 | #include "zebra/zebra_vrf.h" | |
8902474b | 39 | #include "zebra/zebra_routemap.h" |
718e3744 | 40 | #include "zebra/redistribute.h" |
41 | #include "zebra/debug.h" | |
18a6dce6 | 42 | #include "zebra/router-id.h" |
bf094f69 | 43 | #include "zebra/zapi_msg.h" |
4a1ab8e4 | 44 | #include "zebra/zebra_memory.h" |
1a98c087 | 45 | #include "zebra/zebra_vxlan.h" |
364fed6b | 46 | #include "zebra/zebra_errors.h" |
718e3744 | 47 | |
244c1cdc DS |
48 | #define ZEBRA_PTM_SUPPORT |
49 | ||
7a4bb9c5 DS |
50 | /* array holding redistribute info about table redistribution */ |
51 | /* bit AFI is set if that AFI is redistributing routes from this table */ | |
032bfaaf | 52 | static int zebra_import_table_used[AFI_MAX][ZEBRA_KERNEL_TABLE_MAX]; |
d7c0a89a | 53 | static uint32_t zebra_import_table_distance[AFI_MAX][ZEBRA_KERNEL_TABLE_MAX]; |
7a4bb9c5 | 54 | |
fe257ae7 | 55 | int is_zebra_import_table_enabled(afi_t afi, vrf_id_t vrf_id, uint32_t table_id) |
7a4bb9c5 | 56 | { |
1e9f448f DS |
57 | /* |
58 | * Make sure that what we are called with actualy makes sense | |
59 | */ | |
60 | if (afi == AFI_MAX) | |
61 | return 0; | |
62 | ||
95a29032 DS |
63 | if (is_zebra_valid_kernel_table(table_id) && |
64 | table_id < ZEBRA_KERNEL_TABLE_MAX) | |
d62a17ae | 65 | return zebra_import_table_used[afi][table_id]; |
66 | return 0; | |
7a4bb9c5 DS |
67 | } |
68 | ||
d62a17ae | 69 | static void zebra_redistribute_default(struct zserv *client, vrf_id_t vrf_id) |
718e3744 | 70 | { |
d62a17ae | 71 | int afi; |
72 | struct prefix p; | |
73 | struct route_table *table; | |
74 | struct route_node *rn; | |
75 | struct route_entry *newre; | |
76 | ||
77 | for (afi = AFI_IP; afi <= AFI_IP6; afi++) { | |
29a35332 DS |
78 | |
79 | if (!vrf_bitmap_check(client->redist_default[afi], vrf_id)) | |
80 | continue; | |
81 | ||
d62a17ae | 82 | /* Lookup table. */ |
83 | table = zebra_vrf_table(afi, SAFI_UNICAST, vrf_id); | |
84 | if (!table) | |
85 | continue; | |
86 | ||
87 | /* Lookup default route. */ | |
88 | memset(&p, 0, sizeof(p)); | |
89 | p.family = afi2family(afi); | |
90 | rn = route_node_lookup(table, &p); | |
91 | if (!rn) | |
92 | continue; | |
93 | ||
a2addae8 | 94 | RNODE_FOREACH_RE (rn, newre) { |
407c87a6 DS |
95 | if (CHECK_FLAG(newre->flags, ZEBRA_FLAG_SELECTED) |
96 | && newre->distance != DISTANCE_INFINITY) | |
97 | zsend_redistribute_route( | |
a2addae8 RW |
98 | ZEBRA_REDISTRIBUTE_ROUTE_ADD, client, |
99 | &rn->p, NULL, newre); | |
407c87a6 | 100 | } |
d62a17ae | 101 | |
102 | route_unlock_node(rn); | |
103 | } | |
718e3744 | 104 | } |
105 | ||
106 | /* Redistribute routes. */ | |
d7c0a89a QY |
107 | static void zebra_redistribute(struct zserv *client, int type, |
108 | unsigned short instance, vrf_id_t vrf_id, | |
109 | int afi) | |
718e3744 | 110 | { |
d62a17ae | 111 | struct route_entry *newre; |
112 | struct route_table *table; | |
113 | struct route_node *rn; | |
114 | ||
115 | table = zebra_vrf_table(afi, SAFI_UNICAST, vrf_id); | |
116 | if (!table) | |
117 | return; | |
118 | ||
f0c4b8e1 | 119 | for (rn = route_top(table); rn; rn = srcdest_route_next(rn)) |
a2addae8 | 120 | RNODE_FOREACH_RE (rn, newre) { |
86391e56 | 121 | const struct prefix *dst_p, *src_p; |
3e178809 DS |
122 | char buf[PREFIX_STRLEN]; |
123 | ||
d62a17ae | 124 | srcdest_rnode_prefixes(rn, &dst_p, &src_p); |
125 | ||
14a4d9d0 | 126 | if (IS_ZEBRA_DEBUG_RIB) |
d62a17ae | 127 | zlog_debug( |
38bbad1b | 128 | "%s: client %s %s(%u) checking: selected=%d, type=%d, distance=%d, metric=%d zebra_check_addr=%d", |
d62a17ae | 129 | __func__, |
1b6e575b | 130 | zebra_route_string(client->proto), |
3e178809 | 131 | prefix2str(dst_p, buf, sizeof(buf)), |
1b6e575b PZ |
132 | vrf_id, CHECK_FLAG(newre->flags, |
133 | ZEBRA_FLAG_SELECTED), | |
d62a17ae | 134 | newre->type, newre->distance, |
3e178809 | 135 | newre->metric, zebra_check_addr(dst_p)); |
d62a17ae | 136 | |
137 | if (!CHECK_FLAG(newre->flags, ZEBRA_FLAG_SELECTED)) | |
138 | continue; | |
139 | if ((type != ZEBRA_ROUTE_ALL | |
140 | && (newre->type != type | |
141 | || newre->instance != instance))) | |
142 | continue; | |
143 | if (newre->distance == DISTANCE_INFINITY) | |
144 | continue; | |
145 | if (!zebra_check_addr(dst_p)) | |
146 | continue; | |
147 | ||
74489921 RW |
148 | zsend_redistribute_route(ZEBRA_REDISTRIBUTE_ROUTE_ADD, |
149 | client, dst_p, src_p, newre); | |
d62a17ae | 150 | } |
718e3744 | 151 | } |
152 | ||
14fe366e S |
153 | /* |
154 | * Function to check if prefix is candidate for | |
155 | * redistribute. | |
156 | */ | |
157 | static bool zebra_redistribute_check(const struct route_entry *re, | |
158 | struct zserv *client, | |
159 | const struct prefix *p, int afi) | |
160 | { | |
161 | /* Process only if there is valid re */ | |
162 | if (!re) | |
163 | return false; | |
164 | ||
165 | /* If default route and redistributed */ | |
166 | if (is_default_prefix(p) | |
167 | && vrf_bitmap_check(client->redist_default[afi], re->vrf_id)) | |
168 | return true; | |
169 | ||
170 | /* If redistribute in enabled for zebra route all */ | |
171 | if (vrf_bitmap_check(client->redist[afi][ZEBRA_ROUTE_ALL], re->vrf_id)) | |
172 | return true; | |
173 | ||
174 | /* | |
175 | * If multi-instance then check for route | |
176 | * redistribution for given instance. | |
177 | */ | |
178 | if (re->instance | |
179 | && redist_check_instance(&client->mi_redist[afi][re->type], | |
180 | re->instance)) | |
181 | return true; | |
182 | ||
183 | /* If redistribution is enabled for give route type. */ | |
184 | if (vrf_bitmap_check(client->redist[afi][re->type], re->vrf_id)) | |
185 | return true; | |
186 | ||
187 | return false; | |
188 | } | |
189 | ||
c41fc67b | 190 | /* Either advertise a route for redistribution to registered clients or */ |
191 | /* withdraw redistribution if add cannot be done for client */ | |
86391e56 | 192 | void redistribute_update(const struct prefix *p, const struct prefix *src_p, |
40f321c0 MS |
193 | const struct route_entry *re, |
194 | const struct route_entry *prev_re) | |
718e3744 | 195 | { |
d62a17ae | 196 | struct listnode *node, *nnode; |
197 | struct zserv *client; | |
d62a17ae | 198 | int afi; |
3e178809 | 199 | char buf[PREFIX_STRLEN]; |
d62a17ae | 200 | |
201 | if (IS_ZEBRA_DEBUG_RIB) { | |
d62a17ae | 202 | zlog_debug( |
2da33d6b | 203 | "%u:%s: Redist update re %p (%s), old %p (%s)", |
3e178809 | 204 | re->vrf_id, prefix2str(p, buf, sizeof(buf)), |
2da33d6b DS |
205 | re, zebra_route_string(re->type), prev_re, |
206 | prev_re ? zebra_route_string(prev_re->type) : "None"); | |
d62a17ae | 207 | } |
208 | ||
209 | afi = family2afi(p->family); | |
210 | if (!afi) { | |
e914ccbe | 211 | flog_warn(EC_ZEBRA_REDISTRIBUTE_UNKNOWN_AF, |
0767b4f3 | 212 | "%s: Unknown AFI/SAFI prefix received\n", __func__); |
d62a17ae | 213 | return; |
c41fc67b | 214 | } |
79becec8 | 215 | if (!zebra_check_addr(p)) { |
216 | if (IS_ZEBRA_DEBUG_RIB) | |
217 | zlog_debug("Redist update filter prefix %s", | |
218 | prefix2str(p, buf, sizeof(buf))); | |
219 | return; | |
220 | } | |
221 | ||
d62a17ae | 222 | |
161e9ab7 | 223 | for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) { |
14fe366e | 224 | if (zebra_redistribute_check(re, client, p, afi)) { |
14a4d9d0 | 225 | if (IS_ZEBRA_DEBUG_RIB) { |
3e178809 | 226 | zlog_debug( |
38bbad1b | 227 | "%s: client %s %s(%u), type=%d, distance=%d, metric=%d", |
3e178809 DS |
228 | __func__, |
229 | zebra_route_string(client->proto), | |
230 | prefix2str(p, buf, sizeof(buf)), | |
231 | re->vrf_id, re->type, | |
232 | re->distance, re->metric); | |
233 | } | |
74489921 RW |
234 | zsend_redistribute_route(ZEBRA_REDISTRIBUTE_ROUTE_ADD, |
235 | client, p, src_p, re); | |
14fe366e | 236 | } else if (zebra_redistribute_check(prev_re, client, p, afi)) |
74489921 RW |
237 | zsend_redistribute_route(ZEBRA_REDISTRIBUTE_ROUTE_DEL, |
238 | client, p, src_p, prev_re); | |
c41fc67b | 239 | } |
718e3744 | 240 | } |
241 | ||
40f321c0 MS |
242 | /* |
243 | * During a route delete, where 'new_re' is NULL, redist a delete to all | |
244 | * clients registered for the type of 'old_re'. | |
245 | * During a route update, redist a delete to any clients who will not see | |
246 | * an update when the new route is installed. There are cases when a client | |
247 | * may have seen a redist for 'old_re', but will not see | |
248 | * the redist for 'new_re'. | |
249 | */ | |
86391e56 | 250 | void redistribute_delete(const struct prefix *p, const struct prefix *src_p, |
40f321c0 MS |
251 | const struct route_entry *old_re, |
252 | const struct route_entry *new_re) | |
718e3744 | 253 | { |
d62a17ae | 254 | struct listnode *node, *nnode; |
255 | struct zserv *client; | |
d62a17ae | 256 | int afi; |
40f321c0 MS |
257 | char buf[PREFIX_STRLEN]; |
258 | vrf_id_t vrfid; | |
259 | ||
260 | if (old_re) | |
261 | vrfid = old_re->vrf_id; | |
262 | else if (new_re) | |
263 | vrfid = new_re->vrf_id; | |
264 | else | |
265 | return; | |
d62a17ae | 266 | |
267 | if (IS_ZEBRA_DEBUG_RIB) { | |
40f321c0 MS |
268 | zlog_debug( |
269 | "%u:%s: Redist del: re %p (%s), new re %p (%s)", | |
270 | vrfid, prefix2str(p, buf, sizeof(buf)), | |
271 | old_re, | |
272 | old_re ? zebra_route_string(old_re->type) : "None", | |
273 | new_re, | |
274 | new_re ? zebra_route_string(new_re->type) : "None"); | |
d62a17ae | 275 | } |
276 | ||
277 | /* Add DISTANCE_INFINITY check. */ | |
0e965c67 DS |
278 | if (old_re && (old_re->distance == DISTANCE_INFINITY)) { |
279 | if (IS_ZEBRA_DEBUG_RIB) | |
d6951e5e | 280 | zlog_debug(" Skipping due to Infinite Distance"); |
d62a17ae | 281 | return; |
0e965c67 | 282 | } |
d62a17ae | 283 | |
284 | afi = family2afi(p->family); | |
285 | if (!afi) { | |
e914ccbe | 286 | flog_warn(EC_ZEBRA_REDISTRIBUTE_UNKNOWN_AF, |
9df414fe | 287 | "%s: Unknown AFI/SAFI prefix received\n", |
40f321c0 | 288 | __func__); |
d62a17ae | 289 | return; |
290 | } | |
291 | ||
40f321c0 | 292 | /* Skip invalid (e.g. linklocal) prefix */ |
79becec8 | 293 | if (!zebra_check_addr(p)) { |
40f321c0 MS |
294 | if (IS_ZEBRA_DEBUG_RIB) { |
295 | zlog_debug( | |
296 | "%u:%s: Redist del old: skipping invalid prefix", | |
297 | vrfid, prefix2str(p, buf, sizeof(buf))); | |
298 | } | |
79becec8 | 299 | return; |
300 | } | |
301 | ||
161e9ab7 | 302 | for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) { |
17da84a4 KS |
303 | /* Do not send unsolicited messages to synchronous clients. */ |
304 | if (client->synchronous) | |
305 | continue; | |
14fe366e S |
306 | /* |
307 | * Skip this client if it will receive an update for the | |
308 | * 'new' re | |
309 | */ | |
310 | if (zebra_redistribute_check(new_re, client, p, afi)) | |
311 | continue; | |
40f321c0 MS |
312 | |
313 | /* Send a delete for the 'old' re to any subscribed client. */ | |
14fe366e | 314 | if (zebra_redistribute_check(old_re, client, p, afi)) |
74489921 | 315 | zsend_redistribute_route(ZEBRA_REDISTRIBUTE_ROUTE_DEL, |
40f321c0 | 316 | client, p, src_p, old_re); |
1eb8ef25 | 317 | } |
718e3744 | 318 | } |
319 | ||
14fe366e | 320 | |
89f4e507 | 321 | void zebra_redistribute_add(ZAPI_HANDLER_ARGS) |
718e3744 | 322 | { |
ec93aa12 DS |
323 | afi_t afi = 0; |
324 | int type = 0; | |
d7c0a89a | 325 | unsigned short instance; |
d62a17ae | 326 | |
1002497a QY |
327 | STREAM_GETC(msg, afi); |
328 | STREAM_GETC(msg, type); | |
329 | STREAM_GETW(msg, instance); | |
d62a17ae | 330 | |
1b6e575b PZ |
331 | if (IS_ZEBRA_DEBUG_EVENT) |
332 | zlog_debug( | |
c479e756 | 333 | "%s: client proto %s afi=%d, wants %s, vrf %s(%u), instance=%d", |
1b6e575b | 334 | __func__, zebra_route_string(client->proto), afi, |
c479e756 DS |
335 | zebra_route_string(type), VRF_LOGNAME(zvrf->vrf), |
336 | zvrf_id(zvrf), instance); | |
1b6e575b | 337 | |
e1fa928d | 338 | if (afi == 0 || afi >= AFI_MAX) { |
e914ccbe | 339 | flog_warn(EC_ZEBRA_REDISTRIBUTE_UNKNOWN_AF, |
15569c58 | 340 | "%s: Specified afi %d does not exist", __func__, afi); |
d62a17ae | 341 | return; |
ec93aa12 DS |
342 | } |
343 | ||
344 | if (type == 0 || type >= ZEBRA_ROUTE_MAX) { | |
9df414fe | 345 | zlog_debug("%s: Specified Route Type %d does not exist", |
15569c58 | 346 | __func__, type); |
ec93aa12 DS |
347 | return; |
348 | } | |
d62a17ae | 349 | |
350 | if (instance) { | |
351 | if (!redist_check_instance(&client->mi_redist[afi][type], | |
352 | instance)) { | |
353 | redist_add_instance(&client->mi_redist[afi][type], | |
354 | instance); | |
355 | zebra_redistribute(client, type, instance, | |
356 | zvrf_id(zvrf), afi); | |
357 | } | |
358 | } else { | |
359 | if (!vrf_bitmap_check(client->redist[afi][type], | |
360 | zvrf_id(zvrf))) { | |
1b6e575b | 361 | if (IS_ZEBRA_DEBUG_EVENT) |
c479e756 DS |
362 | zlog_debug( |
363 | "%s: setting vrf %s(%u) redist bitmap", | |
364 | __func__, VRF_LOGNAME(zvrf->vrf), | |
365 | zvrf_id(zvrf)); | |
d62a17ae | 366 | vrf_bitmap_set(client->redist[afi][type], |
367 | zvrf_id(zvrf)); | |
368 | zebra_redistribute(client, type, 0, zvrf_id(zvrf), afi); | |
369 | } | |
4e1cadf0 | 370 | } |
ec93aa12 DS |
371 | |
372 | stream_failure: | |
373 | return; | |
ebf08631 | 374 | } |
718e3744 | 375 | |
89f4e507 | 376 | void zebra_redistribute_delete(ZAPI_HANDLER_ARGS) |
718e3744 | 377 | { |
ec93aa12 DS |
378 | afi_t afi = 0; |
379 | int type = 0; | |
d7c0a89a | 380 | unsigned short instance; |
d62a17ae | 381 | |
1002497a QY |
382 | STREAM_GETC(msg, afi); |
383 | STREAM_GETC(msg, type); | |
384 | STREAM_GETW(msg, instance); | |
d62a17ae | 385 | |
e1fa928d | 386 | if (afi == 0 || afi >= AFI_MAX) { |
e914ccbe | 387 | flog_warn(EC_ZEBRA_REDISTRIBUTE_UNKNOWN_AF, |
15569c58 | 388 | "%s: Specified afi %d does not exist", __func__, afi); |
d62a17ae | 389 | return; |
ec93aa12 DS |
390 | } |
391 | ||
392 | if (type == 0 || type >= ZEBRA_ROUTE_MAX) { | |
9df414fe | 393 | zlog_debug("%s: Specified Route Type %d does not exist", |
15569c58 | 394 | __func__, type); |
ec93aa12 DS |
395 | return; |
396 | } | |
d62a17ae | 397 | |
398 | /* | |
399 | * NOTE: no need to withdraw the previously advertised routes. The | |
400 | * clients | |
401 | * themselves should keep track of the received routes from zebra and | |
402 | * withdraw them when necessary. | |
403 | */ | |
404 | if (instance) | |
405 | redist_del_instance(&client->mi_redist[afi][type], instance); | |
406 | else | |
407 | vrf_bitmap_unset(client->redist[afi][type], zvrf_id(zvrf)); | |
ec93aa12 DS |
408 | |
409 | stream_failure: | |
410 | return; | |
ebf08631 | 411 | } |
718e3744 | 412 | |
89f4e507 | 413 | void zebra_redistribute_default_add(ZAPI_HANDLER_ARGS) |
718e3744 | 414 | { |
49db7a7b RW |
415 | afi_t afi = 0; |
416 | ||
417 | STREAM_GETC(msg, afi); | |
418 | ||
419 | if (afi == 0 || afi >= AFI_MAX) { | |
420 | flog_warn(EC_ZEBRA_REDISTRIBUTE_UNKNOWN_AF, | |
15569c58 | 421 | "%s: Specified afi %u does not exist", __func__, afi); |
49db7a7b RW |
422 | return; |
423 | } | |
424 | ||
425 | vrf_bitmap_set(client->redist_default[afi], zvrf_id(zvrf)); | |
d62a17ae | 426 | zebra_redistribute_default(client, zvrf_id(zvrf)); |
49db7a7b RW |
427 | |
428 | stream_failure: | |
429 | return; | |
d62a17ae | 430 | } |
718e3744 | 431 | |
89f4e507 | 432 | void zebra_redistribute_default_delete(ZAPI_HANDLER_ARGS) |
718e3744 | 433 | { |
49db7a7b RW |
434 | afi_t afi = 0; |
435 | ||
436 | STREAM_GETC(msg, afi); | |
437 | ||
438 | if (afi == 0 || afi >= AFI_MAX) { | |
439 | flog_warn(EC_ZEBRA_REDISTRIBUTE_UNKNOWN_AF, | |
15569c58 | 440 | "%s: Specified afi %u does not exist", __func__, afi); |
49db7a7b RW |
441 | return; |
442 | } | |
443 | ||
444 | vrf_bitmap_unset(client->redist_default[afi], zvrf_id(zvrf)); | |
445 | ||
446 | stream_failure: | |
447 | return; | |
d62a17ae | 448 | } |
718e3744 | 449 | |
450 | /* Interface up information. */ | |
d62a17ae | 451 | void zebra_interface_up_update(struct interface *ifp) |
718e3744 | 452 | { |
d62a17ae | 453 | struct listnode *node, *nnode; |
454 | struct zserv *client; | |
455 | ||
456 | if (IS_ZEBRA_DEBUG_EVENT) | |
38bbad1b | 457 | zlog_debug("MESSAGE: ZEBRA_INTERFACE_UP %s(%u)", |
a36898e7 | 458 | ifp->name, ifp->vrf_id); |
d62a17ae | 459 | |
460 | if (ifp->ptm_status || !ifp->ptm_enable) { | |
161e9ab7 | 461 | for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, |
a8a20c4e | 462 | client)) { |
17da84a4 KS |
463 | /* Do not send unsolicited messages to synchronous |
464 | * clients. | |
465 | */ | |
466 | if (client->synchronous) | |
467 | continue; | |
468 | ||
a8a20c4e DS |
469 | zsend_interface_update(ZEBRA_INTERFACE_UP, |
470 | client, ifp); | |
471 | zsend_interface_link_params(client, ifp); | |
472 | } | |
16f1b9ee | 473 | } |
718e3744 | 474 | } |
475 | ||
476 | /* Interface down information. */ | |
d62a17ae | 477 | void zebra_interface_down_update(struct interface *ifp) |
718e3744 | 478 | { |
d62a17ae | 479 | struct listnode *node, *nnode; |
480 | struct zserv *client; | |
718e3744 | 481 | |
d62a17ae | 482 | if (IS_ZEBRA_DEBUG_EVENT) |
38bbad1b | 483 | zlog_debug("MESSAGE: ZEBRA_INTERFACE_DOWN %s(%u)", |
a36898e7 | 484 | ifp->name, ifp->vrf_id); |
718e3744 | 485 | |
161e9ab7 | 486 | for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) { |
17da84a4 KS |
487 | /* Do not send unsolicited messages to synchronous clients. */ |
488 | if (client->synchronous) | |
489 | continue; | |
490 | ||
d62a17ae | 491 | zsend_interface_update(ZEBRA_INTERFACE_DOWN, client, ifp); |
492 | } | |
718e3744 | 493 | } |
494 | ||
495 | /* Interface information update. */ | |
d62a17ae | 496 | void zebra_interface_add_update(struct interface *ifp) |
718e3744 | 497 | { |
d62a17ae | 498 | struct listnode *node, *nnode; |
499 | struct zserv *client; | |
500 | ||
501 | if (IS_ZEBRA_DEBUG_EVENT) | |
38bbad1b | 502 | zlog_debug("MESSAGE: ZEBRA_INTERFACE_ADD %s(%u)", ifp->name, |
a36898e7 | 503 | ifp->vrf_id); |
d62a17ae | 504 | |
a8a20c4e | 505 | for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) { |
17da84a4 KS |
506 | /* Do not send unsolicited messages to synchronous clients. */ |
507 | if (client->synchronous) | |
508 | continue; | |
509 | ||
a8a20c4e DS |
510 | client->ifadd_cnt++; |
511 | zsend_interface_add(client, ifp); | |
512 | zsend_interface_link_params(client, ifp); | |
513 | } | |
718e3744 | 514 | } |
515 | ||
d62a17ae | 516 | void zebra_interface_delete_update(struct interface *ifp) |
718e3744 | 517 | { |
d62a17ae | 518 | struct listnode *node, *nnode; |
519 | struct zserv *client; | |
718e3744 | 520 | |
d62a17ae | 521 | if (IS_ZEBRA_DEBUG_EVENT) |
38bbad1b | 522 | zlog_debug("MESSAGE: ZEBRA_INTERFACE_DELETE %s(%u)", |
a36898e7 | 523 | ifp->name, ifp->vrf_id); |
718e3744 | 524 | |
161e9ab7 | 525 | for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) { |
17da84a4 KS |
526 | /* Do not send unsolicited messages to synchronous clients. */ |
527 | if (client->synchronous) | |
528 | continue; | |
529 | ||
d62a17ae | 530 | client->ifdel_cnt++; |
531 | zsend_interface_delete(client, ifp); | |
532 | } | |
718e3744 | 533 | } |
534 | ||
535 | /* Interface address addition. */ | |
d62a17ae | 536 | void zebra_interface_address_add_update(struct interface *ifp, |
537 | struct connected *ifc) | |
718e3744 | 538 | { |
d62a17ae | 539 | struct listnode *node, *nnode; |
540 | struct zserv *client; | |
541 | struct prefix *p; | |
542 | ||
543 | if (IS_ZEBRA_DEBUG_EVENT) { | |
544 | char buf[PREFIX_STRLEN]; | |
545 | ||
546 | p = ifc->address; | |
38bbad1b DS |
547 | zlog_debug("MESSAGE: ZEBRA_INTERFACE_ADDRESS_ADD %s on %s(%u)", |
548 | prefix2str(p, buf, sizeof(buf)), ifp->name, | |
a36898e7 | 549 | ifp->vrf_id); |
d62a17ae | 550 | } |
551 | ||
552 | if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_REAL)) | |
9df414fe | 553 | flog_warn( |
e914ccbe | 554 | EC_ZEBRA_ADVERTISING_UNUSABLE_ADDR, |
d62a17ae | 555 | "WARNING: advertising address to clients that is not yet usable."); |
556 | ||
1a98c087 MK |
557 | zebra_vxlan_add_del_gw_macip(ifp, ifc->address, 1); |
558 | ||
d62a17ae | 559 | router_id_add_address(ifc); |
560 | ||
17da84a4 KS |
561 | for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) { |
562 | /* Do not send unsolicited messages to synchronous clients. */ | |
563 | if (client->synchronous) | |
564 | continue; | |
565 | ||
d62a17ae | 566 | if (CHECK_FLAG(ifc->conf, ZEBRA_IFC_REAL)) { |
567 | client->connected_rt_add_cnt++; | |
568 | zsend_interface_address(ZEBRA_INTERFACE_ADDRESS_ADD, | |
569 | client, ifp, ifc); | |
570 | } | |
17da84a4 | 571 | } |
718e3744 | 572 | } |
573 | ||
574 | /* Interface address deletion. */ | |
d62a17ae | 575 | void zebra_interface_address_delete_update(struct interface *ifp, |
576 | struct connected *ifc) | |
718e3744 | 577 | { |
d62a17ae | 578 | struct listnode *node, *nnode; |
579 | struct zserv *client; | |
580 | struct prefix *p; | |
581 | ||
582 | if (IS_ZEBRA_DEBUG_EVENT) { | |
583 | char buf[PREFIX_STRLEN]; | |
584 | ||
585 | p = ifc->address; | |
38bbad1b DS |
586 | zlog_debug("MESSAGE: ZEBRA_INTERFACE_ADDRESS_DELETE %s on %s(%u)", |
587 | prefix2str(p, buf, sizeof(buf)), | |
a36898e7 | 588 | ifp->name, ifp->vrf_id); |
d62a17ae | 589 | } |
590 | ||
1a98c087 MK |
591 | zebra_vxlan_add_del_gw_macip(ifp, ifc->address, 0); |
592 | ||
d62a17ae | 593 | router_id_del_address(ifc); |
594 | ||
17da84a4 KS |
595 | for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) { |
596 | /* Do not send unsolicited messages to synchronous clients. */ | |
597 | if (client->synchronous) | |
598 | continue; | |
599 | ||
d62a17ae | 600 | if (CHECK_FLAG(ifc->conf, ZEBRA_IFC_REAL)) { |
601 | client->connected_rt_del_cnt++; | |
602 | zsend_interface_address(ZEBRA_INTERFACE_ADDRESS_DELETE, | |
603 | client, ifp, ifc); | |
604 | } | |
17da84a4 | 605 | } |
718e3744 | 606 | } |
d5a5c8f0 | 607 | |
c8e264b6 | 608 | /* Interface VRF change. May need to delete from clients not interested in |
609 | * the new VRF. Note that this function is invoked *prior* to the VRF change. | |
610 | */ | |
d62a17ae | 611 | void zebra_interface_vrf_update_del(struct interface *ifp, vrf_id_t new_vrf_id) |
c8e264b6 | 612 | { |
d62a17ae | 613 | struct listnode *node, *nnode; |
614 | struct zserv *client; | |
615 | ||
616 | if (IS_ZEBRA_DEBUG_EVENT) | |
617 | zlog_debug( | |
618 | "MESSAGE: ZEBRA_INTERFACE_VRF_UPDATE/DEL %s VRF Id %u -> %u", | |
a36898e7 | 619 | ifp->name, ifp->vrf_id, new_vrf_id); |
d62a17ae | 620 | |
161e9ab7 | 621 | for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) { |
17da84a4 KS |
622 | /* Do not send unsolicited messages to synchronous clients. */ |
623 | if (client->synchronous) | |
624 | continue; | |
625 | ||
d62a17ae | 626 | /* Need to delete if the client is not interested in the new |
627 | * VRF. */ | |
628 | zsend_interface_update(ZEBRA_INTERFACE_DOWN, client, ifp); | |
629 | client->ifdel_cnt++; | |
630 | zsend_interface_delete(client, ifp); | |
631 | zsend_interface_vrf_update(client, ifp, new_vrf_id); | |
632 | } | |
c8e264b6 | 633 | } |
634 | ||
635 | /* Interface VRF change. This function is invoked *post* VRF change and sends an | |
636 | * add to clients who are interested in the new VRF but not in the old VRF. | |
637 | */ | |
d62a17ae | 638 | void zebra_interface_vrf_update_add(struct interface *ifp, vrf_id_t old_vrf_id) |
c8e264b6 | 639 | { |
d62a17ae | 640 | struct listnode *node, *nnode; |
641 | struct zserv *client; | |
642 | ||
643 | if (IS_ZEBRA_DEBUG_EVENT) | |
644 | zlog_debug( | |
645 | "MESSAGE: ZEBRA_INTERFACE_VRF_UPDATE/ADD %s VRF Id %u -> %u", | |
a36898e7 | 646 | ifp->name, old_vrf_id, ifp->vrf_id); |
d62a17ae | 647 | |
161e9ab7 | 648 | for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) { |
17da84a4 KS |
649 | /* Do not send unsolicited messages to synchronous clients. */ |
650 | if (client->synchronous) | |
651 | continue; | |
652 | ||
d62a17ae | 653 | /* Need to add if the client is interested in the new VRF. */ |
654 | client->ifadd_cnt++; | |
655 | zsend_interface_add(client, ifp); | |
656 | zsend_interface_addresses(client, ifp); | |
657 | } | |
c8e264b6 | 658 | } |
659 | ||
fe257ae7 DS |
660 | int zebra_add_import_table_entry(struct zebra_vrf *zvrf, struct route_node *rn, |
661 | struct route_entry *re, const char *rmap_name) | |
7a4bb9c5 | 662 | { |
d62a17ae | 663 | struct route_entry *newre; |
664 | struct route_entry *same; | |
665 | struct prefix p; | |
0eb97b86 | 666 | struct nexthop_group *ng; |
b68885f9 | 667 | route_map_result_t ret = RMAP_PERMITMATCH; |
f8c175f3 | 668 | afi_t afi; |
d62a17ae | 669 | |
f8c175f3 | 670 | afi = family2afi(rn->p.family); |
d62a17ae | 671 | if (rmap_name) |
672 | ret = zebra_import_table_route_map_check( | |
0eb97b86 | 673 | afi, re->type, re->instance, &rn->p, |
c415d895 | 674 | re->nhe->nhg.nexthop, |
fe257ae7 | 675 | zvrf->vrf->vrf_id, re->tag, rmap_name); |
d62a17ae | 676 | |
b68885f9 | 677 | if (ret != RMAP_PERMITMATCH) { |
85c615ac | 678 | UNSET_FLAG(re->flags, ZEBRA_FLAG_SELECTED); |
fe257ae7 | 679 | zebra_del_import_table_entry(zvrf, rn, re); |
20796bc3 DS |
680 | return 0; |
681 | } | |
d62a17ae | 682 | |
f8c175f3 | 683 | prefix_copy(&p, &rn->p); |
d62a17ae | 684 | |
a2addae8 RW |
685 | RNODE_FOREACH_RE (rn, same) { |
686 | if (CHECK_FLAG(same->status, ROUTE_ENTRY_REMOVED)) | |
f8c175f3 | 687 | continue; |
20796bc3 | 688 | |
996c9314 | 689 | if (same->type == re->type && same->instance == re->instance |
f8c175f3 DS |
690 | && same->table == re->table |
691 | && same->type != ZEBRA_ROUTE_CONNECT) | |
692 | break; | |
693 | } | |
20796bc3 | 694 | |
e71c84ca DS |
695 | if (same) { |
696 | UNSET_FLAG(same->flags, ZEBRA_FLAG_SELECTED); | |
fe257ae7 | 697 | zebra_del_import_table_entry(zvrf, rn, same); |
e71c84ca | 698 | } |
f8c175f3 | 699 | |
996c9314 | 700 | newre = XCALLOC(MTYPE_RE, sizeof(struct route_entry)); |
5c4b6e57 DS |
701 | newre->type = ZEBRA_ROUTE_TABLE; |
702 | newre->distance = zebra_import_table_distance[afi][re->table]; | |
703 | newre->flags = re->flags; | |
704 | newre->metric = re->metric; | |
705 | newre->mtu = re->mtu; | |
317c6a10 | 706 | newre->table = zvrf->table_id; |
98572489 | 707 | newre->uptime = monotime(NULL); |
5c4b6e57 | 708 | newre->instance = re->table; |
5c4b6e57 | 709 | |
0eb97b86 | 710 | ng = nexthop_group_new(); |
c415d895 | 711 | copy_nexthops(&ng->nexthop, re->nhe->nhg.nexthop, NULL); |
0eb97b86 MS |
712 | |
713 | rib_add_multipath(afi, SAFI_UNICAST, &p, NULL, newre, ng); | |
5c4b6e57 | 714 | |
d62a17ae | 715 | return 0; |
7a4bb9c5 DS |
716 | } |
717 | ||
fe257ae7 DS |
718 | int zebra_del_import_table_entry(struct zebra_vrf *zvrf, struct route_node *rn, |
719 | struct route_entry *re) | |
7a4bb9c5 | 720 | { |
d62a17ae | 721 | struct prefix p; |
f8c175f3 | 722 | afi_t afi; |
7a4bb9c5 | 723 | |
f8c175f3 DS |
724 | afi = family2afi(rn->p.family); |
725 | prefix_copy(&p, &rn->p); | |
7a4bb9c5 | 726 | |
fe257ae7 | 727 | rib_delete(afi, SAFI_UNICAST, zvrf->vrf->vrf_id, ZEBRA_ROUTE_TABLE, |
c415d895 | 728 | re->table, re->flags, &p, NULL, re->nhe->nhg.nexthop, |
0eb97b86 MS |
729 | re->nhe_id, zvrf->table_id, re->metric, re->distance, |
730 | false); | |
7a4bb9c5 | 731 | |
d62a17ae | 732 | return 0; |
7a4bb9c5 DS |
733 | } |
734 | ||
735 | /* Assuming no one calls this with the main routing table */ | |
fe257ae7 DS |
736 | int zebra_import_table(afi_t afi, vrf_id_t vrf_id, uint32_t table_id, |
737 | uint32_t distance, const char *rmap_name, int add) | |
7a4bb9c5 | 738 | { |
d62a17ae | 739 | struct route_table *table; |
740 | struct route_entry *re; | |
741 | struct route_node *rn; | |
fe257ae7 | 742 | struct zebra_vrf *zvrf = zebra_vrf_lookup_by_id(vrf_id); |
d62a17ae | 743 | |
744 | if (!is_zebra_valid_kernel_table(table_id) | |
c447ad08 | 745 | || (table_id == RT_TABLE_MAIN)) |
95f7965d | 746 | return -1; |
d62a17ae | 747 | |
748 | if (afi >= AFI_MAX) | |
95f7965d | 749 | return -1; |
d62a17ae | 750 | |
c7c0b007 SW |
751 | table = zebra_vrf_get_table_with_table_id(afi, SAFI_UNICAST, vrf_id, |
752 | table_id); | |
d62a17ae | 753 | if (table == NULL) { |
754 | return 0; | |
755 | } else if (IS_ZEBRA_DEBUG_RIB) { | |
756 | zlog_debug("%s routes from table %d", | |
757 | add ? "Importing" : "Unimporting", table_id); | |
7a4bb9c5 DS |
758 | } |
759 | ||
d62a17ae | 760 | if (add) { |
761 | if (rmap_name) | |
762 | zebra_add_import_table_route_map(afi, rmap_name, | |
763 | table_id); | |
764 | else { | |
765 | rmap_name = | |
766 | zebra_get_import_table_route_map(afi, table_id); | |
3660beec | 767 | if (rmap_name) { |
d62a17ae | 768 | zebra_del_import_table_route_map(afi, table_id); |
3660beec DS |
769 | rmap_name = NULL; |
770 | } | |
d62a17ae | 771 | } |
7a4bb9c5 | 772 | |
d62a17ae | 773 | zebra_import_table_used[afi][table_id] = 1; |
774 | zebra_import_table_distance[afi][table_id] = distance; | |
775 | } else { | |
776 | zebra_import_table_used[afi][table_id] = 0; | |
777 | zebra_import_table_distance[afi][table_id] = | |
778 | ZEBRA_TABLE_DISTANCE_DEFAULT; | |
779 | ||
780 | rmap_name = zebra_get_import_table_route_map(afi, table_id); | |
3660beec | 781 | if (rmap_name) { |
d62a17ae | 782 | zebra_del_import_table_route_map(afi, table_id); |
3660beec DS |
783 | rmap_name = NULL; |
784 | } | |
7a4bb9c5 | 785 | } |
7a4bb9c5 | 786 | |
d62a17ae | 787 | for (rn = route_top(table); rn; rn = route_next(rn)) { |
788 | /* For each entry in the non-default routing table, | |
789 | * add the entry in the main table | |
790 | */ | |
791 | if (!rn->info) | |
792 | continue; | |
793 | ||
a2addae8 | 794 | RNODE_FOREACH_RE (rn, re) { |
d62a17ae | 795 | if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED)) |
796 | continue; | |
797 | break; | |
7a4bb9c5 | 798 | } |
8902474b | 799 | |
d62a17ae | 800 | if (!re) |
801 | continue; | |
8902474b | 802 | |
d62a17ae | 803 | if (((afi == AFI_IP) && (rn->p.family == AF_INET)) |
804 | || ((afi == AFI_IP6) && (rn->p.family == AF_INET6))) { | |
805 | if (add) | |
fe257ae7 DS |
806 | zebra_add_import_table_entry(zvrf, rn, re, |
807 | rmap_name); | |
d62a17ae | 808 | else |
fe257ae7 | 809 | zebra_del_import_table_entry(zvrf, rn, re); |
d62a17ae | 810 | } |
811 | } | |
812 | return 0; | |
813 | } | |
814 | ||
fe257ae7 | 815 | int zebra_import_table_config(struct vty *vty, vrf_id_t vrf_id) |
d62a17ae | 816 | { |
817 | int i; | |
818 | afi_t afi; | |
819 | int write = 0; | |
820 | char afi_str[AFI_MAX][10] = {"", "ip", "ipv6", "ethernet"}; | |
821 | const char *rmap_name; | |
822 | ||
823 | for (afi = AFI_IP; afi < AFI_MAX; afi++) { | |
824 | for (i = 1; i < ZEBRA_KERNEL_TABLE_MAX; i++) { | |
fe257ae7 | 825 | if (!is_zebra_import_table_enabled(afi, vrf_id, i)) |
20796bc3 | 826 | continue; |
d62a17ae | 827 | |
20796bc3 DS |
828 | if (zebra_import_table_distance[afi][i] |
829 | != ZEBRA_TABLE_DISTANCE_DEFAULT) { | |
996c9314 | 830 | vty_out(vty, "%s import-table %d distance %d", |
20796bc3 DS |
831 | afi_str[afi], i, |
832 | zebra_import_table_distance[afi][i]); | |
833 | } else { | |
996c9314 LB |
834 | vty_out(vty, "%s import-table %d", afi_str[afi], |
835 | i); | |
d62a17ae | 836 | } |
20796bc3 DS |
837 | |
838 | rmap_name = zebra_get_import_table_route_map(afi, i); | |
839 | if (rmap_name) | |
996c9314 | 840 | vty_out(vty, " route-map %s", rmap_name); |
20796bc3 DS |
841 | |
842 | vty_out(vty, "\n"); | |
843 | write = 1; | |
d62a17ae | 844 | } |
7a4bb9c5 | 845 | } |
7a4bb9c5 | 846 | |
d62a17ae | 847 | return write; |
7a4bb9c5 | 848 | } |
8902474b | 849 | |
fe257ae7 DS |
850 | static void zebra_import_table_rm_update_vrf_afi(struct zebra_vrf *zvrf, |
851 | afi_t afi, int table_id, | |
852 | const char *rmap) | |
8902474b | 853 | { |
d62a17ae | 854 | struct route_table *table; |
855 | struct route_entry *re; | |
856 | struct route_node *rn; | |
857 | const char *rmap_name; | |
858 | ||
fe257ae7 DS |
859 | rmap_name = zebra_get_import_table_route_map(afi, table_id); |
860 | if ((!rmap_name) || (strcmp(rmap_name, rmap) != 0)) | |
861 | return; | |
d62a17ae | 862 | |
c7c0b007 SW |
863 | table = zebra_vrf_get_table_with_table_id(afi, SAFI_UNICAST, |
864 | zvrf->vrf->vrf_id, table_id); | |
fe257ae7 DS |
865 | if (!table) { |
866 | if (IS_ZEBRA_DEBUG_RIB_DETAILED) | |
867 | zlog_debug("%s: Table id=%d not found", __func__, | |
868 | table_id); | |
869 | return; | |
870 | } | |
871 | ||
872 | for (rn = route_top(table); rn; rn = route_next(rn)) { | |
873 | /* | |
874 | * For each entry in the non-default routing table, | |
875 | * add the entry in the main table | |
876 | */ | |
877 | if (!rn->info) | |
878 | continue; | |
879 | ||
880 | RNODE_FOREACH_RE (rn, re) { | |
881 | if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED)) | |
d5b8c216 | 882 | continue; |
fe257ae7 DS |
883 | break; |
884 | } | |
885 | ||
886 | if (!re) | |
887 | continue; | |
888 | ||
889 | if (((afi == AFI_IP) && (rn->p.family == AF_INET)) | |
890 | || ((afi == AFI_IP6) && (rn->p.family == AF_INET6))) | |
891 | zebra_add_import_table_entry(zvrf, rn, re, rmap_name); | |
892 | } | |
893 | ||
894 | return; | |
895 | } | |
896 | ||
897 | static void zebra_import_table_rm_update_vrf(struct zebra_vrf *zvrf, | |
898 | const char *rmap) | |
899 | { | |
900 | afi_t afi; | |
901 | int i; | |
902 | ||
903 | for (afi = AFI_IP; afi < AFI_MAX; afi++) { | |
904 | for (i = 1; i < ZEBRA_KERNEL_TABLE_MAX; i++) { | |
905 | if (!is_zebra_import_table_enabled( | |
906 | afi, zvrf->vrf->vrf_id, i)) | |
2c7ef20d | 907 | continue; |
2c7ef20d | 908 | |
fe257ae7 DS |
909 | zebra_import_table_rm_update_vrf_afi(zvrf, afi, i, |
910 | rmap); | |
d62a17ae | 911 | } |
8902474b | 912 | } |
fe257ae7 | 913 | } |
8902474b | 914 | |
fe257ae7 DS |
915 | void zebra_import_table_rm_update(const char *rmap) |
916 | { | |
917 | struct vrf *vrf; | |
918 | struct zebra_vrf *zvrf; | |
919 | ||
920 | RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { | |
921 | zvrf = vrf->info; | |
922 | ||
923 | if (!zvrf) | |
924 | continue; | |
925 | ||
926 | zebra_import_table_rm_update_vrf(zvrf, rmap); | |
927 | } | |
8902474b | 928 | } |
16f1b9ee OD |
929 | |
930 | /* Interface parameters update */ | |
d62a17ae | 931 | void zebra_interface_parameters_update(struct interface *ifp) |
16f1b9ee | 932 | { |
d62a17ae | 933 | struct listnode *node, *nnode; |
934 | struct zserv *client; | |
16f1b9ee | 935 | |
d62a17ae | 936 | if (IS_ZEBRA_DEBUG_EVENT) |
38bbad1b | 937 | zlog_debug("MESSAGE: ZEBRA_INTERFACE_LINK_PARAMS %s(%u)", |
a36898e7 | 938 | ifp->name, ifp->vrf_id); |
16f1b9ee | 939 | |
17da84a4 KS |
940 | for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) { |
941 | /* Do not send unsolicited messages to synchronous clients. */ | |
942 | if (client->synchronous) | |
943 | continue; | |
944 | ||
a8a20c4e | 945 | zsend_interface_link_params(client, ifp); |
17da84a4 | 946 | } |
16f1b9ee | 947 | } |