]>
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 | |
89272910 | 31 | #include "zebra/zebra_router.h" |
df9c8c57 | 32 | #include "zebra/rtadv.h" |
7c551956 | 33 | #include "zebra/debug.h" |
bf094f69 | 34 | #include "zebra/zapi_msg.h" |
7c551956 DS |
35 | #include "zebra/rib.h" |
36 | #include "zebra/zebra_vrf.h" | |
5a8dfcd8 | 37 | #include "zebra/zebra_rnh.h" |
7c551956 | 38 | #include "zebra/router-id.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" |
7cf16e19 | 43 | #include "zebra/zebra_routemap.h" |
37cb0475 IR |
44 | #ifndef VTYSH_EXTRACT_PL |
45 | #include "zebra/zebra_vrf_clippy.c" | |
46 | #endif | |
7c551956 | 47 | |
9d97533e | 48 | static void zebra_vrf_table_create(struct zebra_vrf *zvrf, afi_t afi, |
49 | safi_t safi); | |
50 | static void zebra_rnhtable_node_cleanup(struct route_table *table, | |
51 | struct route_node *node); | |
52 | ||
bf8d3d6a DL |
53 | DEFINE_MTYPE_STATIC(ZEBRA, ZEBRA_VRF, "ZEBRA VRF"); |
54 | DEFINE_MTYPE_STATIC(ZEBRA, OTHER_TABLE, "Other Table"); | |
d8612e65 | 55 | |
7c551956 | 56 | /* VRF information update. */ |
d62a17ae | 57 | static void zebra_vrf_add_update(struct zebra_vrf *zvrf) |
7c551956 | 58 | { |
d62a17ae | 59 | struct listnode *node, *nnode; |
60 | struct zserv *client; | |
7c551956 | 61 | |
d62a17ae | 62 | if (IS_ZEBRA_DEBUG_EVENT) |
63 | zlog_debug("MESSAGE: ZEBRA_VRF_ADD %s", zvrf_name(zvrf)); | |
7c551956 | 64 | |
17da84a4 KS |
65 | for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) { |
66 | /* Do not send unsolicited messages to synchronous clients. */ | |
67 | if (client->synchronous) | |
68 | continue; | |
69 | ||
d62a17ae | 70 | zsend_vrf_add(client, zvrf); |
17da84a4 | 71 | } |
7c551956 DS |
72 | } |
73 | ||
d62a17ae | 74 | static void zebra_vrf_delete_update(struct zebra_vrf *zvrf) |
7c551956 | 75 | { |
d62a17ae | 76 | struct listnode *node, *nnode; |
77 | struct zserv *client; | |
7c551956 | 78 | |
d62a17ae | 79 | if (IS_ZEBRA_DEBUG_EVENT) |
80 | zlog_debug("MESSAGE: ZEBRA_VRF_DELETE %s", zvrf_name(zvrf)); | |
7c551956 | 81 | |
17da84a4 KS |
82 | for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) { |
83 | /* Do not send unsolicited messages to synchronous clients. */ | |
84 | if (client->synchronous) | |
85 | continue; | |
86 | ||
d62a17ae | 87 | zsend_vrf_delete(client, zvrf); |
17da84a4 | 88 | } |
7c551956 DS |
89 | } |
90 | ||
d62a17ae | 91 | void zebra_vrf_update_all(struct zserv *client) |
7c551956 | 92 | { |
d62a17ae | 93 | struct vrf *vrf; |
7c551956 | 94 | |
a2addae8 | 95 | RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) { |
4691b65a | 96 | if (vrf->vrf_id != VRF_UNKNOWN) |
d62a17ae | 97 | zsend_vrf_add(client, vrf_info_lookup(vrf->vrf_id)); |
98 | } | |
7c551956 DS |
99 | } |
100 | ||
101 | /* Callback upon creating a new VRF. */ | |
d62a17ae | 102 | static int zebra_vrf_new(struct vrf *vrf) |
7c551956 | 103 | { |
d62a17ae | 104 | struct zebra_vrf *zvrf; |
7c551956 | 105 | |
d62a17ae | 106 | if (IS_ZEBRA_DEBUG_EVENT) |
14a4d9d0 | 107 | zlog_debug("VRF %s created, id %u", vrf->name, vrf->vrf_id); |
7c551956 | 108 | |
ec64a634 | 109 | zvrf = zebra_vrf_alloc(vrf); |
91b1421e PG |
110 | if (!vrf_is_backend_netns()) |
111 | zvrf->zns = zebra_ns_lookup(NS_DEFAULT); | |
d8612e65 DS |
112 | |
113 | otable_init(&zvrf->other_tables); | |
114 | ||
fbb65ff5 | 115 | router_id_init(zvrf); |
d62a17ae | 116 | return 0; |
7c551956 DS |
117 | } |
118 | ||
119 | /* Callback upon enabling a VRF. */ | |
d62a17ae | 120 | static int zebra_vrf_enable(struct vrf *vrf) |
7c551956 | 121 | { |
d62a17ae | 122 | struct zebra_vrf *zvrf = vrf->info; |
9d97533e | 123 | struct route_table *table; |
d62a17ae | 124 | afi_t afi; |
125 | safi_t safi; | |
126 | ||
127 | assert(zvrf); | |
84915b0a | 128 | if (IS_ZEBRA_DEBUG_EVENT) |
996c9314 LB |
129 | zlog_debug("VRF %s id %u is now active", zvrf_name(zvrf), |
130 | zvrf_id(zvrf)); | |
d62a17ae | 131 | |
fbb65ff5 PG |
132 | if (vrf_is_backend_netns()) |
133 | zvrf->zns = zebra_ns_lookup((ns_id_t)vrf->vrf_id); | |
134 | else | |
135 | zvrf->zns = zebra_ns_lookup(NS_DEFAULT); | |
df9c8c57 | 136 | #if defined(HAVE_RTADV) |
7c2ddfb9 | 137 | rtadv_vrf_init(zvrf); |
df9c8c57 PG |
138 | #endif |
139 | ||
84915b0a | 140 | /* Inform clients that the VRF is now active. This is an |
141 | * add for the clients. | |
142 | */ | |
d62a17ae | 143 | |
8288a24f | 144 | zebra_vrf_add_update(zvrf); |
9d97533e | 145 | /* Allocate tables */ |
146 | for (afi = AFI_IP; afi <= AFI_IP6; afi++) { | |
147 | for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++) | |
148 | zebra_vrf_table_create(zvrf, afi, safi); | |
149 | ||
150 | table = route_table_init(); | |
151 | table->cleanup = zebra_rnhtable_node_cleanup; | |
152 | zvrf->rnh_table[afi] = table; | |
9d97533e | 153 | } |
154 | ||
84915b0a | 155 | /* Kick off any VxLAN-EVPN processing. */ |
156 | zebra_vxlan_vrf_enable(zvrf); | |
157 | ||
d62a17ae | 158 | return 0; |
7c551956 DS |
159 | } |
160 | ||
161 | /* Callback upon disabling a VRF. */ | |
d62a17ae | 162 | static int zebra_vrf_disable(struct vrf *vrf) |
7c551956 | 163 | { |
d62a17ae | 164 | struct zebra_vrf *zvrf = vrf->info; |
9d97533e | 165 | struct interface *ifp; |
d62a17ae | 166 | afi_t afi; |
167 | safi_t safi; | |
9d97533e | 168 | unsigned i; |
d62a17ae | 169 | |
84915b0a | 170 | assert(zvrf); |
171 | if (IS_ZEBRA_DEBUG_EVENT) | |
996c9314 LB |
172 | zlog_debug("VRF %s id %u is now inactive", zvrf_name(zvrf), |
173 | zvrf_id(zvrf)); | |
d62a17ae | 174 | |
84915b0a | 175 | /* Stop any VxLAN-EVPN processing. */ |
176 | zebra_vxlan_vrf_disable(zvrf); | |
d62a17ae | 177 | |
df9c8c57 | 178 | #if defined(HAVE_RTADV) |
aab5893a | 179 | rtadv_vrf_terminate(zvrf); |
df9c8c57 PG |
180 | #endif |
181 | ||
84915b0a | 182 | /* Inform clients that the VRF is now inactive. This is a |
183 | * delete for the clients. | |
184 | */ | |
d62a17ae | 185 | zebra_vrf_delete_update(zvrf); |
186 | ||
9d97533e | 187 | /* If asked to retain routes, there's nothing more to do. */ |
188 | if (CHECK_FLAG(zvrf->flags, ZEBRA_VRF_RETAIN)) | |
189 | return 0; | |
190 | ||
191 | /* Remove all routes. */ | |
192 | for (afi = AFI_IP; afi <= AFI_IP6; afi++) { | |
41dc8c14 DS |
193 | route_table_finish(zvrf->rnh_table[afi]); |
194 | zvrf->rnh_table[afi] = NULL; | |
41dc8c14 | 195 | |
9d97533e | 196 | for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++) |
197 | rib_close_table(zvrf->table[afi][safi]); | |
9d97533e | 198 | } |
199 | ||
200 | /* Cleanup Vxlan, MPLS and PW tables. */ | |
201 | zebra_vxlan_cleanup_tables(zvrf); | |
202 | zebra_mpls_cleanup_tables(zvrf); | |
203 | zebra_pw_exit(zvrf); | |
204 | ||
996c9314 LB |
205 | /* Remove link-local IPv4 addresses created for BGP unnumbered peering. |
206 | */ | |
9d97533e | 207 | FOR_ALL_INTERFACES (vrf, ifp) |
208 | if_nbr_ipv6ll_to_ipv4ll_neigh_del_all(ifp); | |
209 | ||
210 | /* clean-up work queues */ | |
211 | for (i = 0; i < MQ_SIZE; i++) { | |
212 | struct listnode *lnode, *nnode; | |
213 | struct route_node *rnode; | |
214 | rib_dest_t *dest; | |
215 | ||
ea45a4e7 | 216 | for (ALL_LIST_ELEMENTS(zrouter.mq->subq[i], lnode, nnode, |
996c9314 | 217 | rnode)) { |
9d97533e | 218 | dest = rib_dest_from_rnode(rnode); |
219 | if (dest && rib_dest_vrf(dest) == zvrf) { | |
220 | route_unlock_node(rnode); | |
ea45a4e7 DS |
221 | list_delete_node(zrouter.mq->subq[i], lnode); |
222 | zrouter.mq->size--; | |
9d97533e | 223 | } |
d62a17ae | 224 | } |
9d97533e | 225 | } |
7c551956 | 226 | |
9d97533e | 227 | /* Cleanup (free) routing tables and NHT tables. */ |
228 | for (afi = AFI_IP; afi <= AFI_IP6; afi++) { | |
89272910 DS |
229 | /* |
230 | * Set the table pointer to NULL as that | |
231 | * we no-longer need a copy of it, nor do we | |
232 | * own this data, the zebra_router structure | |
233 | * owns these tables. Once we've cleaned up the | |
234 | * table, see rib_close_table above | |
235 | * we no-longer need this pointer. | |
236 | */ | |
bd4fb615 DS |
237 | for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++) { |
238 | zebra_router_release_table(zvrf, zvrf->table_id, afi, | |
239 | safi); | |
9d97533e | 240 | zvrf->table[afi][safi] = NULL; |
bd4fb615 | 241 | } |
5a8dfcd8 RW |
242 | } |
243 | ||
d62a17ae | 244 | return 0; |
7c551956 DS |
245 | } |
246 | ||
d62a17ae | 247 | static int zebra_vrf_delete(struct vrf *vrf) |
7c551956 | 248 | { |
d62a17ae | 249 | struct zebra_vrf *zvrf = vrf->info; |
d8612e65 | 250 | struct other_route_table *otable; |
d62a17ae | 251 | struct route_table *table; |
d62a17ae | 252 | afi_t afi; |
253 | safi_t safi; | |
254 | unsigned i; | |
255 | ||
256 | assert(zvrf); | |
84915b0a | 257 | if (IS_ZEBRA_DEBUG_EVENT) |
996c9314 LB |
258 | zlog_debug("VRF %s id %u deleted", zvrf_name(zvrf), |
259 | zvrf_id(zvrf)); | |
5a8dfcd8 | 260 | |
d62a17ae | 261 | /* clean-up work queues */ |
262 | for (i = 0; i < MQ_SIZE; i++) { | |
263 | struct listnode *lnode, *nnode; | |
264 | struct route_node *rnode; | |
265 | rib_dest_t *dest; | |
266 | ||
ea45a4e7 | 267 | for (ALL_LIST_ELEMENTS(zrouter.mq->subq[i], lnode, nnode, |
996c9314 | 268 | rnode)) { |
d62a17ae | 269 | dest = rib_dest_from_rnode(rnode); |
270 | if (dest && rib_dest_vrf(dest) == zvrf) { | |
271 | route_unlock_node(rnode); | |
ea45a4e7 DS |
272 | list_delete_node(zrouter.mq->subq[i], lnode); |
273 | zrouter.mq->size--; | |
d62a17ae | 274 | } |
275 | } | |
5a8dfcd8 | 276 | } |
5a8dfcd8 | 277 | |
84915b0a | 278 | /* Free Vxlan and MPLS. */ |
279 | zebra_vxlan_close_tables(zvrf); | |
280 | zebra_mpls_close_tables(zvrf); | |
281 | ||
d62a17ae | 282 | /* release allocated memory */ |
283 | for (afi = AFI_IP; afi <= AFI_IP6; afi++) { | |
d62a17ae | 284 | for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++) { |
285 | table = zvrf->table[afi][safi]; | |
9d97533e | 286 | if (table) { |
bd4fb615 DS |
287 | zebra_router_release_table(zvrf, zvrf->table_id, |
288 | afi, safi); | |
289 | zvrf->table[afi][safi] = NULL; | |
9d97533e | 290 | } |
d62a17ae | 291 | } |
5a8dfcd8 | 292 | |
41dc8c14 DS |
293 | if (zvrf->rnh_table[afi]) |
294 | route_table_finish(zvrf->rnh_table[afi]); | |
5a8dfcd8 | 295 | } |
b7cfce93 | 296 | |
d8612e65 DS |
297 | otable = otable_pop(&zvrf->other_tables); |
298 | while (otable) { | |
299 | zebra_router_release_table(zvrf, otable->table_id, | |
300 | otable->afi, otable->safi); | |
301 | XFREE(MTYPE_OTHER_TABLE, otable); | |
302 | ||
303 | otable = otable_pop(&zvrf->other_tables); | |
304 | } | |
305 | ||
84915b0a | 306 | /* Cleanup EVPN states for vrf */ |
b7cfce93 MK |
307 | zebra_vxlan_vrf_delete(zvrf); |
308 | ||
d62a17ae | 309 | list_delete_all_node(zvrf->rid_all_sorted_list); |
310 | list_delete_all_node(zvrf->rid_lo_sorted_list); | |
d8612e65 | 311 | |
cdc09a4b MS |
312 | list_delete_all_node(zvrf->rid6_all_sorted_list); |
313 | list_delete_all_node(zvrf->rid6_lo_sorted_list); | |
314 | ||
d8612e65 | 315 | otable_fini(&zvrf->other_tables); |
d62a17ae | 316 | XFREE(MTYPE_ZEBRA_VRF, zvrf); |
317 | vrf->info = NULL; | |
5a8dfcd8 | 318 | |
d62a17ae | 319 | return 0; |
7c551956 DS |
320 | } |
321 | ||
ecbc5a37 PG |
322 | static int zebra_vrf_update(struct vrf *vrf) |
323 | { | |
324 | struct zebra_vrf *zvrf = vrf->info; | |
325 | ||
326 | assert(zvrf); | |
327 | if (IS_ZEBRA_DEBUG_EVENT) | |
328 | zlog_debug("VRF %s id %u, name updated", vrf->name, | |
329 | zvrf_id(zvrf)); | |
330 | zebra_vrf_add_update(zvrf); | |
331 | return 0; | |
332 | } | |
333 | ||
7c551956 | 334 | /* Lookup the routing table in a VRF based on both VRF-Id and table-id. |
e9748a89 PG |
335 | * NOTE: Table-id is relevant on two modes: |
336 | * - case VRF backend is default : on default VRF only | |
337 | * - case VRF backend is netns : on all VRFs | |
7c551956 | 338 | */ |
c7c0b007 SW |
339 | struct route_table *zebra_vrf_lookup_table_with_table_id(afi_t afi, safi_t safi, |
340 | vrf_id_t vrf_id, | |
341 | uint32_t table_id) | |
7c551956 | 342 | { |
8ab39b7f | 343 | struct zebra_vrf *zvrf = vrf_info_lookup(vrf_id); |
d8612e65 | 344 | struct other_route_table ort, *otable; |
8ab39b7f DS |
345 | |
346 | if (!zvrf) | |
347 | return NULL; | |
d62a17ae | 348 | |
349 | if (afi >= AFI_MAX || safi >= SAFI_MAX) | |
350 | return NULL; | |
351 | ||
8ab39b7f DS |
352 | if (table_id == zvrf->table_id) |
353 | return zebra_vrf_table(afi, safi, vrf_id); | |
d62a17ae | 354 | |
d8612e65 DS |
355 | ort.afi = afi; |
356 | ort.safi = safi; | |
357 | ort.table_id = table_id; | |
358 | otable = otable_find(&zvrf->other_tables, &ort); | |
c7c0b007 | 359 | |
d8612e65 DS |
360 | if (otable) |
361 | return otable->table; | |
362 | ||
c7c0b007 SW |
363 | return NULL; |
364 | } | |
365 | ||
366 | struct route_table *zebra_vrf_get_table_with_table_id(afi_t afi, safi_t safi, | |
367 | vrf_id_t vrf_id, | |
368 | uint32_t table_id) | |
369 | { | |
370 | struct zebra_vrf *zvrf = vrf_info_lookup(vrf_id); | |
371 | struct other_route_table *otable; | |
372 | struct route_table *table; | |
373 | ||
374 | table = zebra_vrf_lookup_table_with_table_id(afi, safi, vrf_id, | |
375 | table_id); | |
376 | ||
377 | if (table) | |
378 | goto done; | |
379 | ||
380 | /* Create it as an `other` table */ | |
d8612e65 DS |
381 | table = zebra_router_get_table(zvrf, table_id, afi, safi); |
382 | ||
383 | otable = XCALLOC(MTYPE_OTHER_TABLE, sizeof(*otable)); | |
384 | otable->afi = afi; | |
385 | otable->safi = safi; | |
386 | otable->table_id = table_id; | |
387 | otable->table = table; | |
388 | otable_add(&zvrf->other_tables, otable); | |
d62a17ae | 389 | |
c7c0b007 | 390 | done: |
d62a17ae | 391 | return table; |
7c551956 DS |
392 | } |
393 | ||
d62a17ae | 394 | static void zebra_rnhtable_node_cleanup(struct route_table *table, |
395 | struct route_node *node) | |
5a8dfcd8 | 396 | { |
d62a17ae | 397 | if (node->info) |
398 | zebra_free_rnh(node->info); | |
5a8dfcd8 RW |
399 | } |
400 | ||
7c551956 DS |
401 | /* |
402 | * Create a routing table for the specific AFI/SAFI in the given VRF. | |
403 | */ | |
d62a17ae | 404 | static void zebra_vrf_table_create(struct zebra_vrf *zvrf, afi_t afi, |
405 | safi_t safi) | |
7c551956 | 406 | { |
c86ba6c2 DS |
407 | struct route_node *rn; |
408 | struct prefix p; | |
409 | ||
d62a17ae | 410 | assert(!zvrf->table[afi][safi]); |
411 | ||
ea66cec4 DS |
412 | zvrf->table[afi][safi] = |
413 | zebra_router_get_table(zvrf, zvrf->table_id, afi, safi); | |
c86ba6c2 DS |
414 | |
415 | memset(&p, 0, sizeof(p)); | |
416 | p.family = afi2family(afi); | |
417 | ||
418 | rn = srcdest_rnode_get(zvrf->table[afi][safi], &p, NULL); | |
419 | zebra_rib_create_dest(rn); | |
7c551956 DS |
420 | } |
421 | ||
422 | /* Allocate new zebra VRF. */ | |
ec64a634 | 423 | struct zebra_vrf *zebra_vrf_alloc(struct vrf *vrf) |
7c551956 | 424 | { |
d62a17ae | 425 | struct zebra_vrf *zvrf; |
d62a17ae | 426 | |
427 | zvrf = XCALLOC(MTYPE_ZEBRA_VRF, sizeof(struct zebra_vrf)); | |
428 | ||
ec64a634 DS |
429 | zvrf->vrf = vrf; |
430 | vrf->info = zvrf; | |
431 | ||
d62a17ae | 432 | zebra_vxlan_init_tables(zvrf); |
433 | zebra_mpls_init_tables(zvrf); | |
6833ae01 | 434 | zebra_pw_init(zvrf); |
e9748a89 PG |
435 | zvrf->table_id = RT_TABLE_MAIN; |
436 | /* by default table ID is default one */ | |
d62a17ae | 437 | return zvrf; |
7c551956 DS |
438 | } |
439 | ||
440 | /* Lookup VRF by identifier. */ | |
d62a17ae | 441 | struct zebra_vrf *zebra_vrf_lookup_by_id(vrf_id_t vrf_id) |
7c551956 | 442 | { |
d62a17ae | 443 | return vrf_info_lookup(vrf_id); |
7c551956 DS |
444 | } |
445 | ||
51bdc5f8 | 446 | /* Lookup VRF by name. */ |
d62a17ae | 447 | struct zebra_vrf *zebra_vrf_lookup_by_name(const char *name) |
871d39b3 | 448 | { |
d62a17ae | 449 | struct vrf *vrf; |
871d39b3 | 450 | |
d62a17ae | 451 | if (!name) |
452 | name = VRF_DEFAULT_NAME; | |
a3d21ef3 | 453 | |
d62a17ae | 454 | vrf = vrf_lookup_by_name(name); |
455 | if (vrf) | |
456 | return ((struct zebra_vrf *)vrf->info); | |
51bdc5f8 | 457 | |
d62a17ae | 458 | return NULL; |
871d39b3 DS |
459 | } |
460 | ||
7c551956 | 461 | /* Lookup the routing table in an enabled VRF. */ |
d62a17ae | 462 | struct route_table *zebra_vrf_table(afi_t afi, safi_t safi, vrf_id_t vrf_id) |
7c551956 | 463 | { |
d62a17ae | 464 | struct zebra_vrf *zvrf = vrf_info_lookup(vrf_id); |
7c551956 | 465 | |
d62a17ae | 466 | if (!zvrf) |
467 | return NULL; | |
7c551956 | 468 | |
d62a17ae | 469 | if (afi >= AFI_MAX || safi >= SAFI_MAX) |
470 | return NULL; | |
7c551956 | 471 | |
d62a17ae | 472 | return zvrf->table[afi][safi]; |
7c551956 DS |
473 | } |
474 | ||
d62a17ae | 475 | static int vrf_config_write(struct vty *vty) |
f30c50b9 | 476 | { |
d62a17ae | 477 | struct vrf *vrf; |
478 | struct zebra_vrf *zvrf; | |
479 | ||
a2addae8 | 480 | RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { |
d62a17ae | 481 | zvrf = vrf->info; |
1e9f448f DS |
482 | |
483 | if (!zvrf) | |
484 | continue; | |
485 | ||
a5654735 MK |
486 | if (zvrf_id(zvrf) == VRF_DEFAULT) { |
487 | if (zvrf->l3vni) | |
8d0f01f1 CS |
488 | vty_out(vty, "vni %u%s\n", zvrf->l3vni, |
489 | is_l3vni_for_prefix_routes_only( | |
490 | zvrf->l3vni) | |
491 | ? " prefix-routes-only" | |
492 | : ""); | |
5a0bdc78 PG |
493 | if (zvrf->zebra_rnh_ip_default_route) |
494 | vty_out(vty, "ip nht resolve-via-default\n"); | |
495 | ||
496 | if (zvrf->zebra_rnh_ipv6_default_route) | |
497 | vty_out(vty, "ipv6 nht resolve-via-default\n"); | |
c319e19d QY |
498 | } else { |
499 | vty_frame(vty, "vrf %s\n", zvrf_name(zvrf)); | |
22bd3e94 | 500 | if (zvrf->l3vni) |
996c9314 LB |
501 | vty_out(vty, " vni %u%s\n", zvrf->l3vni, |
502 | is_l3vni_for_prefix_routes_only( | |
503 | zvrf->l3vni) | |
504 | ? " prefix-routes-only" | |
505 | : ""); | |
b95c1883 | 506 | zebra_ns_config_write(vty, (struct ns *)vrf->ns_ctxt); |
5a0bdc78 PG |
507 | if (zvrf->zebra_rnh_ip_default_route) |
508 | vty_out(vty, " ip nht resolve-via-default\n"); | |
509 | ||
510 | if (zvrf->zebra_rnh_ipv6_default_route) | |
511 | vty_out(vty, " ipv6 nht resolve-via-default\n"); | |
22bd3e94 | 512 | } |
37728041 | 513 | |
5a0bdc78 | 514 | |
7cf16e19 | 515 | zebra_routemap_config_write_protocol(vty, zvrf); |
03fba42e | 516 | router_id_write(vty, zvrf); |
7cf16e19 | 517 | |
c319e19d | 518 | if (zvrf_id(zvrf) != VRF_DEFAULT) |
07679ad9 | 519 | vty_endframe(vty, "exit-vrf\n!\n"); |
7cf16e19 | 520 | else |
521 | vty_out(vty, "!\n"); | |
d62a17ae | 522 | } |
523 | return 0; | |
f30c50b9 RW |
524 | } |
525 | ||
37cb0475 IR |
526 | DEFPY (vrf_netns, |
527 | vrf_netns_cmd, | |
528 | "netns NAME$netns_name", | |
529 | "Attach VRF to a Namespace\n" | |
530 | "The file name in " NS_RUN_DIR ", or a full pathname\n") | |
531 | { | |
532 | char *pathname = ns_netns_pathname(vty, netns_name); | |
533 | int ret; | |
534 | ||
535 | VTY_DECLVAR_CONTEXT(vrf, vrf); | |
536 | ||
537 | if (!pathname) | |
538 | return CMD_WARNING_CONFIG_FAILED; | |
539 | ||
540 | frr_with_privs(&zserv_privs) { | |
541 | ret = vrf_netns_handler_create(vty, vrf, pathname, | |
542 | NS_UNKNOWN, | |
543 | NS_UNKNOWN, | |
544 | NS_UNKNOWN); | |
545 | } | |
546 | ||
547 | return ret; | |
548 | } | |
549 | ||
550 | DEFUN (no_vrf_netns, | |
551 | no_vrf_netns_cmd, | |
552 | "no netns [NAME]", | |
553 | NO_STR | |
554 | "Detach VRF from a Namespace\n" | |
555 | "The file name in " NS_RUN_DIR ", or a full pathname\n") | |
556 | { | |
557 | struct ns *ns = NULL; | |
558 | ||
559 | VTY_DECLVAR_CONTEXT(vrf, vrf); | |
560 | ||
561 | if (!vrf_is_backend_netns()) { | |
562 | vty_out(vty, "VRF backend is not Netns. Aborting\n"); | |
563 | return CMD_WARNING_CONFIG_FAILED; | |
564 | } | |
565 | if (!vrf->ns_ctxt) { | |
566 | vty_out(vty, "VRF %s(%u) is not configured with NetNS\n", | |
567 | vrf->name, vrf->vrf_id); | |
568 | return CMD_WARNING_CONFIG_FAILED; | |
569 | } | |
570 | ||
571 | ns = (struct ns *)vrf->ns_ctxt; | |
572 | ||
573 | ns->vrf_ctxt = NULL; | |
574 | vrf_disable(vrf); | |
575 | /* vrf ID from VRF is necessary for Zebra | |
576 | * so that propagate to other clients is done | |
577 | */ | |
578 | ns_delete(ns); | |
579 | vrf->ns_ctxt = NULL; | |
580 | return CMD_SUCCESS; | |
581 | } | |
582 | ||
7c551956 | 583 | /* Zebra VRF initialization. */ |
d62a17ae | 584 | void zebra_vrf_init(void) |
7c551956 | 585 | { |
996c9314 | 586 | vrf_init(zebra_vrf_new, zebra_vrf_enable, zebra_vrf_disable, |
ecbc5a37 | 587 | zebra_vrf_delete, zebra_vrf_update); |
7c551956 | 588 | |
cfc369c4 | 589 | vrf_cmd_init(vrf_config_write); |
37cb0475 IR |
590 | |
591 | if (vrf_is_backend_netns() && ns_have_netns()) { | |
592 | /* Install NS commands. */ | |
593 | install_element(VRF_NODE, &vrf_netns_cmd); | |
594 | install_element(VRF_NODE, &no_vrf_netns_cmd); | |
595 | } | |
7c551956 | 596 | } |