]>
Commit | Line | Data |
---|---|---|
7c551956 DS |
1 | /* |
2 | * Copyright (C) 2016 CumulusNetworks | |
3 | * Donald Sharp | |
4 | * | |
5 | * This file is part of Quagga | |
6 | * | |
7 | * Quagga is free software; you can redistribute it and/or modify it | |
8 | * under the terms of the GNU General Public License as published by the | |
9 | * Free Software Foundation; either version 2, or (at your option) any | |
10 | * later version. | |
11 | * | |
12 | * Quagga is distributed in the hope that it will be useful, but | |
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 | * General Public License for more details. | |
16 | * | |
896014f4 DL |
17 | * You should have received a copy of the GNU General Public License along |
18 | * with this program; see the file COPYING; if not, write to the Free Software | |
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | |
7c551956 DS |
20 | */ |
21 | #include <zebra.h> | |
22 | ||
23 | #include "log.h" | |
24 | #include "linklist.h" | |
f30c50b9 | 25 | #include "command.h" |
4a1ab8e4 | 26 | #include "memory.h" |
05737783 | 27 | #include "srcdest_table.h" |
78dd30b2 | 28 | #include "vrf.h" |
82f97584 | 29 | #include "vty.h" |
78dd30b2 | 30 | |
7c551956 | 31 | #include "zebra/debug.h" |
bf094f69 | 32 | #include "zebra/zapi_msg.h" |
7c551956 DS |
33 | #include "zebra/rib.h" |
34 | #include "zebra/zebra_vrf.h" | |
5a8dfcd8 | 35 | #include "zebra/zebra_rnh.h" |
7c551956 | 36 | #include "zebra/router-id.h" |
4a1ab8e4 | 37 | #include "zebra/zebra_memory.h" |
28f6dde8 | 38 | #include "zebra/zebra_static.h" |
5a8dfcd8 | 39 | #include "zebra/interface.h" |
7758e3f3 | 40 | #include "zebra/zebra_mpls.h" |
13d60d35 | 41 | #include "zebra/zebra_vxlan.h" |
3bc34908 | 42 | #include "zebra/zebra_netns_notify.h" |
7c551956 DS |
43 | |
44 | extern struct zebra_t zebrad; | |
45 | ||
9d97533e | 46 | static void zebra_vrf_table_create(struct zebra_vrf *zvrf, afi_t afi, |
47 | safi_t safi); | |
48 | static void zebra_rnhtable_node_cleanup(struct route_table *table, | |
49 | struct route_node *node); | |
50 | ||
7c551956 | 51 | /* VRF information update. */ |
d62a17ae | 52 | static void zebra_vrf_add_update(struct zebra_vrf *zvrf) |
7c551956 | 53 | { |
d62a17ae | 54 | struct listnode *node, *nnode; |
55 | struct zserv *client; | |
7c551956 | 56 | |
d62a17ae | 57 | if (IS_ZEBRA_DEBUG_EVENT) |
58 | zlog_debug("MESSAGE: ZEBRA_VRF_ADD %s", zvrf_name(zvrf)); | |
7c551956 | 59 | |
d62a17ae | 60 | for (ALL_LIST_ELEMENTS(zebrad.client_list, node, nnode, client)) |
61 | zsend_vrf_add(client, zvrf); | |
7c551956 DS |
62 | } |
63 | ||
d62a17ae | 64 | static void zebra_vrf_delete_update(struct zebra_vrf *zvrf) |
7c551956 | 65 | { |
d62a17ae | 66 | struct listnode *node, *nnode; |
67 | struct zserv *client; | |
7c551956 | 68 | |
d62a17ae | 69 | if (IS_ZEBRA_DEBUG_EVENT) |
70 | zlog_debug("MESSAGE: ZEBRA_VRF_DELETE %s", zvrf_name(zvrf)); | |
7c551956 | 71 | |
d62a17ae | 72 | for (ALL_LIST_ELEMENTS(zebrad.client_list, node, nnode, client)) |
73 | zsend_vrf_delete(client, zvrf); | |
7c551956 DS |
74 | } |
75 | ||
d62a17ae | 76 | void zebra_vrf_update_all(struct zserv *client) |
7c551956 | 77 | { |
d62a17ae | 78 | struct vrf *vrf; |
7c551956 | 79 | |
a2addae8 | 80 | RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) { |
4691b65a | 81 | if (vrf->vrf_id != VRF_UNKNOWN) |
d62a17ae | 82 | zsend_vrf_add(client, vrf_info_lookup(vrf->vrf_id)); |
83 | } | |
7c551956 DS |
84 | } |
85 | ||
86 | /* Callback upon creating a new VRF. */ | |
d62a17ae | 87 | static int zebra_vrf_new(struct vrf *vrf) |
7c551956 | 88 | { |
d62a17ae | 89 | struct zebra_vrf *zvrf; |
7c551956 | 90 | |
d62a17ae | 91 | if (IS_ZEBRA_DEBUG_EVENT) |
84915b0a | 92 | zlog_info("VRF %s created, id %u", vrf->name, vrf->vrf_id); |
7c551956 | 93 | |
d62a17ae | 94 | zvrf = zebra_vrf_alloc(); |
d62a17ae | 95 | vrf->info = zvrf; |
96 | zvrf->vrf = vrf; | |
fbb65ff5 | 97 | router_id_init(zvrf); |
d62a17ae | 98 | return 0; |
7c551956 DS |
99 | } |
100 | ||
101 | /* Callback upon enabling a VRF. */ | |
d62a17ae | 102 | static int zebra_vrf_enable(struct vrf *vrf) |
7c551956 | 103 | { |
d62a17ae | 104 | struct zebra_vrf *zvrf = vrf->info; |
9d97533e | 105 | struct route_table *table; |
d62a17ae | 106 | afi_t afi; |
107 | safi_t safi; | |
108 | ||
109 | assert(zvrf); | |
84915b0a | 110 | if (IS_ZEBRA_DEBUG_EVENT) |
996c9314 LB |
111 | zlog_debug("VRF %s id %u is now active", zvrf_name(zvrf), |
112 | zvrf_id(zvrf)); | |
d62a17ae | 113 | |
fbb65ff5 PG |
114 | if (vrf_is_backend_netns()) |
115 | zvrf->zns = zebra_ns_lookup((ns_id_t)vrf->vrf_id); | |
116 | else | |
117 | zvrf->zns = zebra_ns_lookup(NS_DEFAULT); | |
84915b0a | 118 | /* Inform clients that the VRF is now active. This is an |
119 | * add for the clients. | |
120 | */ | |
d62a17ae | 121 | |
8288a24f | 122 | zebra_vrf_add_update(zvrf); |
9d97533e | 123 | /* Allocate tables */ |
124 | for (afi = AFI_IP; afi <= AFI_IP6; afi++) { | |
125 | for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++) | |
126 | zebra_vrf_table_create(zvrf, afi, safi); | |
127 | ||
128 | table = route_table_init(); | |
129 | table->cleanup = zebra_rnhtable_node_cleanup; | |
130 | zvrf->rnh_table[afi] = table; | |
131 | ||
132 | table = route_table_init(); | |
133 | table->cleanup = zebra_rnhtable_node_cleanup; | |
134 | zvrf->import_check_table[afi] = table; | |
135 | } | |
136 | ||
90f86c0a | 137 | static_fixup_vrf_ids(zvrf); |
2414ffe5 | 138 | |
4060008b DS |
139 | /* |
140 | * We may have static routes that are now possible to | |
141 | * insert into the appropriate tables | |
142 | */ | |
143 | static_config_install_delayed_routes(zvrf); | |
144 | ||
84915b0a | 145 | /* Kick off any VxLAN-EVPN processing. */ |
146 | zebra_vxlan_vrf_enable(zvrf); | |
147 | ||
d62a17ae | 148 | return 0; |
7c551956 DS |
149 | } |
150 | ||
151 | /* Callback upon disabling a VRF. */ | |
d62a17ae | 152 | static int zebra_vrf_disable(struct vrf *vrf) |
7c551956 | 153 | { |
d62a17ae | 154 | struct zebra_vrf *zvrf = vrf->info; |
9d97533e | 155 | struct route_table *table; |
156 | struct interface *ifp; | |
d62a17ae | 157 | afi_t afi; |
158 | safi_t safi; | |
9d97533e | 159 | unsigned i; |
d62a17ae | 160 | |
84915b0a | 161 | assert(zvrf); |
162 | if (IS_ZEBRA_DEBUG_EVENT) | |
996c9314 LB |
163 | zlog_debug("VRF %s id %u is now inactive", zvrf_name(zvrf), |
164 | zvrf_id(zvrf)); | |
d62a17ae | 165 | |
90f86c0a | 166 | static_cleanup_vrf_ids(zvrf); |
d62a17ae | 167 | |
84915b0a | 168 | /* Stop any VxLAN-EVPN processing. */ |
169 | zebra_vxlan_vrf_disable(zvrf); | |
d62a17ae | 170 | |
84915b0a | 171 | /* Inform clients that the VRF is now inactive. This is a |
172 | * delete for the clients. | |
173 | */ | |
d62a17ae | 174 | zebra_vrf_delete_update(zvrf); |
175 | ||
9d97533e | 176 | /* If asked to retain routes, there's nothing more to do. */ |
177 | if (CHECK_FLAG(zvrf->flags, ZEBRA_VRF_RETAIN)) | |
178 | return 0; | |
179 | ||
180 | /* Remove all routes. */ | |
181 | for (afi = AFI_IP; afi <= AFI_IP6; afi++) { | |
182 | for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++) | |
183 | rib_close_table(zvrf->table[afi][safi]); | |
9d97533e | 184 | } |
185 | ||
186 | /* Cleanup Vxlan, MPLS and PW tables. */ | |
187 | zebra_vxlan_cleanup_tables(zvrf); | |
188 | zebra_mpls_cleanup_tables(zvrf); | |
189 | zebra_pw_exit(zvrf); | |
190 | ||
996c9314 LB |
191 | /* Remove link-local IPv4 addresses created for BGP unnumbered peering. |
192 | */ | |
9d97533e | 193 | FOR_ALL_INTERFACES (vrf, ifp) |
194 | if_nbr_ipv6ll_to_ipv4ll_neigh_del_all(ifp); | |
195 | ||
196 | /* clean-up work queues */ | |
197 | for (i = 0; i < MQ_SIZE; i++) { | |
198 | struct listnode *lnode, *nnode; | |
199 | struct route_node *rnode; | |
200 | rib_dest_t *dest; | |
201 | ||
996c9314 LB |
202 | for (ALL_LIST_ELEMENTS(zebrad.mq->subq[i], lnode, nnode, |
203 | rnode)) { | |
9d97533e | 204 | dest = rib_dest_from_rnode(rnode); |
205 | if (dest && rib_dest_vrf(dest) == zvrf) { | |
206 | route_unlock_node(rnode); | |
207 | list_delete_node(zebrad.mq->subq[i], lnode); | |
208 | zebrad.mq->size--; | |
209 | } | |
d62a17ae | 210 | } |
9d97533e | 211 | } |
7c551956 | 212 | |
9d97533e | 213 | /* Cleanup (free) routing tables and NHT tables. */ |
214 | for (afi = AFI_IP; afi <= AFI_IP6; afi++) { | |
215 | void *table_info; | |
5a8dfcd8 | 216 | |
9d97533e | 217 | for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++) { |
218 | table = zvrf->table[afi][safi]; | |
219 | table_info = table->info; | |
220 | route_table_finish(table); | |
221 | XFREE(MTYPE_RIB_TABLE_INFO, table_info); | |
222 | zvrf->table[afi][safi] = NULL; | |
223 | } | |
224 | ||
9d97533e | 225 | route_table_finish(zvrf->rnh_table[afi]); |
226 | zvrf->rnh_table[afi] = NULL; | |
227 | route_table_finish(zvrf->import_check_table[afi]); | |
228 | zvrf->import_check_table[afi] = NULL; | |
5a8dfcd8 RW |
229 | } |
230 | ||
d62a17ae | 231 | return 0; |
7c551956 DS |
232 | } |
233 | ||
d62a17ae | 234 | static int zebra_vrf_delete(struct vrf *vrf) |
7c551956 | 235 | { |
d62a17ae | 236 | struct zebra_vrf *zvrf = vrf->info; |
237 | struct route_table *table; | |
d62a17ae | 238 | afi_t afi; |
239 | safi_t safi; | |
240 | unsigned i; | |
241 | ||
242 | assert(zvrf); | |
84915b0a | 243 | if (IS_ZEBRA_DEBUG_EVENT) |
996c9314 LB |
244 | zlog_debug("VRF %s id %u deleted", zvrf_name(zvrf), |
245 | zvrf_id(zvrf)); | |
5a8dfcd8 | 246 | |
d62a17ae | 247 | /* clean-up work queues */ |
248 | for (i = 0; i < MQ_SIZE; i++) { | |
249 | struct listnode *lnode, *nnode; | |
250 | struct route_node *rnode; | |
251 | rib_dest_t *dest; | |
252 | ||
996c9314 LB |
253 | for (ALL_LIST_ELEMENTS(zebrad.mq->subq[i], lnode, nnode, |
254 | rnode)) { | |
d62a17ae | 255 | dest = rib_dest_from_rnode(rnode); |
256 | if (dest && rib_dest_vrf(dest) == zvrf) { | |
257 | route_unlock_node(rnode); | |
258 | list_delete_node(zebrad.mq->subq[i], lnode); | |
259 | zebrad.mq->size--; | |
260 | } | |
261 | } | |
5a8dfcd8 | 262 | } |
5a8dfcd8 | 263 | |
84915b0a | 264 | /* Free Vxlan and MPLS. */ |
265 | zebra_vxlan_close_tables(zvrf); | |
266 | zebra_mpls_close_tables(zvrf); | |
267 | ||
d62a17ae | 268 | /* release allocated memory */ |
269 | for (afi = AFI_IP; afi <= AFI_IP6; afi++) { | |
270 | void *table_info; | |
0f124559 | 271 | |
d62a17ae | 272 | for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++) { |
273 | table = zvrf->table[afi][safi]; | |
9d97533e | 274 | if (table) { |
275 | table_info = table->info; | |
276 | route_table_finish(table); | |
277 | XFREE(MTYPE_RIB_TABLE_INFO, table_info); | |
278 | } | |
d62a17ae | 279 | |
280 | table = zvrf->stable[afi][safi]; | |
281 | route_table_finish(table); | |
282 | } | |
5a8dfcd8 | 283 | |
d62a17ae | 284 | route_table_finish(zvrf->rnh_table[afi]); |
285 | route_table_finish(zvrf->import_check_table[afi]); | |
5a8dfcd8 | 286 | } |
b7cfce93 | 287 | |
84915b0a | 288 | /* Cleanup EVPN states for vrf */ |
b7cfce93 MK |
289 | zebra_vxlan_vrf_delete(zvrf); |
290 | ||
d62a17ae | 291 | list_delete_all_node(zvrf->rid_all_sorted_list); |
292 | list_delete_all_node(zvrf->rid_lo_sorted_list); | |
293 | XFREE(MTYPE_ZEBRA_VRF, zvrf); | |
294 | vrf->info = NULL; | |
5a8dfcd8 | 295 | |
d62a17ae | 296 | return 0; |
7c551956 DS |
297 | } |
298 | ||
22bd3e94 | 299 | /* Return if this VRF has any FRR configuration or not. |
300 | * IMPORTANT: This function needs to be updated when additional configuration | |
301 | * is added for a VRF. | |
302 | */ | |
303 | int zebra_vrf_has_config(struct zebra_vrf *zvrf) | |
304 | { | |
305 | afi_t afi; | |
306 | safi_t safi; | |
307 | struct route_table *stable; | |
308 | ||
309 | /* NOTE: This is a don't care for the default VRF, but we go through | |
310 | * the motions to keep things consistent. | |
311 | */ | |
312 | /* Any static routes? */ | |
313 | for (afi = AFI_IP; afi < AFI_MAX; afi++) { | |
314 | for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) { | |
315 | stable = zvrf->stable[afi][safi]; | |
316 | if (!stable) | |
317 | continue; | |
318 | if (route_table_count(stable)) | |
319 | return 1; | |
320 | } | |
321 | } | |
322 | ||
323 | /* EVPN L3-VNI? */ | |
324 | if (zvrf->l3vni) | |
325 | return 1; | |
326 | ||
327 | return 0; | |
328 | } | |
329 | ||
7c551956 DS |
330 | /* Lookup the routing table in a VRF based on both VRF-Id and table-id. |
331 | * NOTE: Table-id is relevant only in the Default VRF. | |
332 | */ | |
d62a17ae | 333 | struct route_table *zebra_vrf_table_with_table_id(afi_t afi, safi_t safi, |
334 | vrf_id_t vrf_id, | |
d7c0a89a | 335 | uint32_t table_id) |
7c551956 | 336 | { |
d62a17ae | 337 | struct route_table *table = NULL; |
338 | ||
339 | if (afi >= AFI_MAX || safi >= SAFI_MAX) | |
340 | return NULL; | |
341 | ||
342 | if (vrf_id == VRF_DEFAULT) { | |
343 | if (table_id == RT_TABLE_MAIN | |
344 | || table_id == zebrad.rtm_table_default) | |
345 | table = zebra_vrf_table(afi, safi, vrf_id); | |
346 | else | |
347 | table = zebra_vrf_other_route_table(afi, table_id, | |
348 | vrf_id); | |
349 | } else | |
350 | table = zebra_vrf_table(afi, safi, vrf_id); | |
351 | ||
352 | return table; | |
7c551956 DS |
353 | } |
354 | ||
5335613b DS |
355 | void zebra_rtable_node_cleanup(struct route_table *table, |
356 | struct route_node *node) | |
5a8dfcd8 | 357 | { |
d62a17ae | 358 | struct route_entry *re, *next; |
5a8dfcd8 | 359 | |
a2addae8 | 360 | RNODE_FOREACH_RE_SAFE (node, re, next) { |
407c87a6 DS |
361 | rib_unlink(node, re); |
362 | } | |
5a8dfcd8 | 363 | |
d62a17ae | 364 | if (node->info) |
365 | XFREE(MTYPE_RIB_DEST, node->info); | |
5a8dfcd8 RW |
366 | } |
367 | ||
d62a17ae | 368 | static void zebra_stable_node_cleanup(struct route_table *table, |
369 | struct route_node *node) | |
5a8dfcd8 | 370 | { |
d62a17ae | 371 | struct static_route *si, *next; |
372 | ||
373 | if (node->info) | |
374 | for (si = node->info; si; si = next) { | |
375 | next = si->next; | |
376 | XFREE(MTYPE_STATIC_ROUTE, si); | |
377 | } | |
5a8dfcd8 RW |
378 | } |
379 | ||
d62a17ae | 380 | static void zebra_rnhtable_node_cleanup(struct route_table *table, |
381 | struct route_node *node) | |
5a8dfcd8 | 382 | { |
d62a17ae | 383 | if (node->info) |
384 | zebra_free_rnh(node->info); | |
5a8dfcd8 RW |
385 | } |
386 | ||
7c551956 DS |
387 | /* |
388 | * Create a routing table for the specific AFI/SAFI in the given VRF. | |
389 | */ | |
d62a17ae | 390 | static void zebra_vrf_table_create(struct zebra_vrf *zvrf, afi_t afi, |
391 | safi_t safi) | |
7c551956 | 392 | { |
d62a17ae | 393 | rib_table_info_t *info; |
394 | struct route_table *table; | |
395 | ||
396 | assert(!zvrf->table[afi][safi]); | |
397 | ||
398 | if (afi == AFI_IP6) | |
399 | table = srcdest_table_init(); | |
400 | else | |
401 | table = route_table_init(); | |
402 | table->cleanup = zebra_rtable_node_cleanup; | |
403 | zvrf->table[afi][safi] = table; | |
404 | ||
405 | info = XCALLOC(MTYPE_RIB_TABLE_INFO, sizeof(*info)); | |
406 | info->zvrf = zvrf; | |
407 | info->afi = afi; | |
408 | info->safi = safi; | |
409 | table->info = info; | |
7c551956 DS |
410 | } |
411 | ||
412 | /* Allocate new zebra VRF. */ | |
d62a17ae | 413 | struct zebra_vrf *zebra_vrf_alloc(void) |
7c551956 | 414 | { |
d62a17ae | 415 | struct zebra_vrf *zvrf; |
416 | afi_t afi; | |
417 | safi_t safi; | |
418 | struct route_table *table; | |
419 | ||
420 | zvrf = XCALLOC(MTYPE_ZEBRA_VRF, sizeof(struct zebra_vrf)); | |
421 | ||
9d97533e | 422 | /* Allocate table for static route configuration. */ |
d62a17ae | 423 | for (afi = AFI_IP; afi <= AFI_IP6; afi++) { |
424 | for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++) { | |
d62a17ae | 425 | if (afi == AFI_IP6) |
426 | table = srcdest_table_init(); | |
427 | else | |
428 | table = route_table_init(); | |
429 | table->cleanup = zebra_stable_node_cleanup; | |
430 | zvrf->stable[afi][safi] = table; | |
431 | } | |
d62a17ae | 432 | } |
433 | ||
434 | zebra_vxlan_init_tables(zvrf); | |
435 | zebra_mpls_init_tables(zvrf); | |
6833ae01 | 436 | zebra_pw_init(zvrf); |
d62a17ae | 437 | |
438 | return zvrf; | |
7c551956 DS |
439 | } |
440 | ||
441 | /* Lookup VRF by identifier. */ | |
d62a17ae | 442 | struct zebra_vrf *zebra_vrf_lookup_by_id(vrf_id_t vrf_id) |
7c551956 | 443 | { |
d62a17ae | 444 | return vrf_info_lookup(vrf_id); |
7c551956 DS |
445 | } |
446 | ||
51bdc5f8 | 447 | /* Lookup VRF by name. */ |
d62a17ae | 448 | struct zebra_vrf *zebra_vrf_lookup_by_name(const char *name) |
871d39b3 | 449 | { |
d62a17ae | 450 | struct vrf *vrf; |
871d39b3 | 451 | |
d62a17ae | 452 | if (!name) |
453 | name = VRF_DEFAULT_NAME; | |
a3d21ef3 | 454 | |
d62a17ae | 455 | vrf = vrf_lookup_by_name(name); |
456 | if (vrf) | |
457 | return ((struct zebra_vrf *)vrf->info); | |
51bdc5f8 | 458 | |
d62a17ae | 459 | return NULL; |
871d39b3 DS |
460 | } |
461 | ||
7c551956 | 462 | /* Lookup the routing table in an enabled VRF. */ |
d62a17ae | 463 | struct route_table *zebra_vrf_table(afi_t afi, safi_t safi, vrf_id_t vrf_id) |
7c551956 | 464 | { |
d62a17ae | 465 | struct zebra_vrf *zvrf = vrf_info_lookup(vrf_id); |
7c551956 | 466 | |
d62a17ae | 467 | if (!zvrf) |
468 | return NULL; | |
7c551956 | 469 | |
d62a17ae | 470 | if (afi >= AFI_MAX || safi >= SAFI_MAX) |
471 | return NULL; | |
7c551956 | 472 | |
d62a17ae | 473 | return zvrf->table[afi][safi]; |
7c551956 DS |
474 | } |
475 | ||
476 | /* Lookup the static routing table in a VRF. */ | |
d62a17ae | 477 | struct route_table *zebra_vrf_static_table(afi_t afi, safi_t safi, |
478 | struct zebra_vrf *zvrf) | |
7c551956 | 479 | { |
d62a17ae | 480 | if (!zvrf) |
481 | return NULL; | |
7c551956 | 482 | |
d62a17ae | 483 | if (afi >= AFI_MAX || safi >= SAFI_MAX) |
484 | return NULL; | |
7c551956 | 485 | |
d62a17ae | 486 | return zvrf->stable[afi][safi]; |
7c551956 DS |
487 | } |
488 | ||
d7c0a89a | 489 | struct route_table *zebra_vrf_other_route_table(afi_t afi, uint32_t table_id, |
d62a17ae | 490 | vrf_id_t vrf_id) |
7c551956 | 491 | { |
d62a17ae | 492 | struct zebra_vrf *zvrf; |
5335613b | 493 | struct zebra_ns *zns; |
d62a17ae | 494 | |
495 | zvrf = vrf_info_lookup(vrf_id); | |
496 | if (!zvrf) | |
497 | return NULL; | |
498 | ||
5335613b DS |
499 | zns = zvrf->zns; |
500 | ||
d62a17ae | 501 | if (afi >= AFI_MAX) |
502 | return NULL; | |
503 | ||
d62a17ae | 504 | if ((vrf_id == VRF_DEFAULT) && (table_id != RT_TABLE_MAIN) |
505 | && (table_id != zebrad.rtm_table_default)) { | |
5335613b | 506 | return zebra_ns_get_table(zns, zvrf, table_id, afi); |
d62a17ae | 507 | } |
508 | ||
509 | return zvrf->table[afi][SAFI_UNICAST]; | |
7c551956 DS |
510 | } |
511 | ||
d62a17ae | 512 | static int vrf_config_write(struct vty *vty) |
f30c50b9 | 513 | { |
d62a17ae | 514 | struct vrf *vrf; |
515 | struct zebra_vrf *zvrf; | |
516 | ||
a2addae8 | 517 | RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { |
d62a17ae | 518 | zvrf = vrf->info; |
1e9f448f DS |
519 | |
520 | if (!zvrf) | |
521 | continue; | |
522 | ||
a5654735 MK |
523 | if (zvrf_id(zvrf) == VRF_DEFAULT) { |
524 | if (zvrf->l3vni) | |
525 | vty_out(vty, "vni %u\n", zvrf->l3vni); | |
526 | vty_out(vty, "!\n"); | |
c319e19d QY |
527 | } else { |
528 | vty_frame(vty, "vrf %s\n", zvrf_name(zvrf)); | |
22bd3e94 | 529 | if (zvrf->l3vni) |
996c9314 LB |
530 | vty_out(vty, " vni %u%s\n", zvrf->l3vni, |
531 | is_l3vni_for_prefix_routes_only( | |
532 | zvrf->l3vni) | |
533 | ? " prefix-routes-only" | |
534 | : ""); | |
b95c1883 | 535 | zebra_ns_config_write(vty, (struct ns *)vrf->ns_ctxt); |
c319e19d | 536 | |
22bd3e94 | 537 | } |
37728041 DS |
538 | |
539 | static_config(vty, zvrf, AFI_IP, SAFI_UNICAST, "ip route"); | |
540 | static_config(vty, zvrf, AFI_IP, SAFI_MULTICAST, "ip mroute"); | |
541 | static_config(vty, zvrf, AFI_IP6, SAFI_UNICAST, "ipv6 route"); | |
ab32921c | 542 | |
c319e19d QY |
543 | if (zvrf_id(zvrf) != VRF_DEFAULT) |
544 | vty_endframe(vty, " exit-vrf\n!\n"); | |
d62a17ae | 545 | } |
546 | return 0; | |
f30c50b9 RW |
547 | } |
548 | ||
7c551956 | 549 | /* Zebra VRF initialization. */ |
d62a17ae | 550 | void zebra_vrf_init(void) |
7c551956 | 551 | { |
996c9314 LB |
552 | vrf_init(zebra_vrf_new, zebra_vrf_enable, zebra_vrf_disable, |
553 | zebra_vrf_delete); | |
7c551956 | 554 | |
3bc34908 | 555 | vrf_cmd_init(vrf_config_write, &zserv_privs); |
7c551956 | 556 | } |