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