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