mirror of
https://github.com/FRRouting/frr.git
synced 2025-04-30 05:27:16 +02:00

This list should just be a typesafe list. Signed-off-by: Donald Sharp <donaldsharp72@gmail.com>
677 lines
16 KiB
C
677 lines
16 KiB
C
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
/*
|
|
* Copyright (C) 2016 CumulusNetworks
|
|
* Donald Sharp
|
|
*
|
|
* This file is part of Quagga
|
|
*/
|
|
#include <zebra.h>
|
|
|
|
/* for basename */
|
|
#include <libgen.h>
|
|
|
|
#include "log.h"
|
|
#include "linklist.h"
|
|
#include "command.h"
|
|
#include "memory.h"
|
|
#include "srcdest_table.h"
|
|
#include "vrf.h"
|
|
#include "vty.h"
|
|
|
|
#include "zebra/zebra_router.h"
|
|
#include "zebra/rtadv.h"
|
|
#include "zebra/debug.h"
|
|
#include "zebra/zapi_msg.h"
|
|
#include "zebra/rib.h"
|
|
#include "zebra/zebra_vrf.h"
|
|
#include "zebra/zebra_rnh.h"
|
|
#include "zebra/router-id.h"
|
|
#include "zebra/interface.h"
|
|
#include "zebra/zebra_mpls.h"
|
|
#include "zebra/zebra_vxlan.h"
|
|
#include "zebra/zebra_netns_notify.h"
|
|
#include "zebra/zebra_routemap.h"
|
|
#include "zebra/zebra_vrf_clippy.c"
|
|
#include "zebra/table_manager.h"
|
|
|
|
static void zebra_vrf_table_create(struct zebra_vrf *zvrf, afi_t afi,
|
|
safi_t safi);
|
|
static void zebra_rnhtable_node_cleanup(struct route_table *table,
|
|
struct route_node *node);
|
|
|
|
DEFINE_MTYPE_STATIC(ZEBRA, ZEBRA_VRF, "ZEBRA VRF");
|
|
DEFINE_MTYPE_STATIC(ZEBRA, OTHER_TABLE, "Other Table");
|
|
|
|
/* VRF information update. */
|
|
static void zebra_vrf_add_update(struct zebra_vrf *zvrf)
|
|
{
|
|
struct zserv *client;
|
|
|
|
if (IS_ZEBRA_DEBUG_EVENT)
|
|
zlog_debug("MESSAGE: ZEBRA_VRF_ADD %s", zvrf_name(zvrf));
|
|
|
|
frr_each (zserv_client_list, &zrouter.client_list, client) {
|
|
/* Do not send unsolicited messages to synchronous clients. */
|
|
if (client->synchronous)
|
|
continue;
|
|
|
|
zsend_vrf_add(client, zvrf);
|
|
}
|
|
}
|
|
|
|
static void zebra_vrf_delete_update(struct zebra_vrf *zvrf)
|
|
{
|
|
struct zserv *client;
|
|
|
|
if (IS_ZEBRA_DEBUG_EVENT)
|
|
zlog_debug("MESSAGE: ZEBRA_VRF_DELETE %s", zvrf_name(zvrf));
|
|
|
|
frr_each (zserv_client_list, &zrouter.client_list, client) {
|
|
/* Do not send unsolicited messages to synchronous clients. */
|
|
if (client->synchronous)
|
|
continue;
|
|
|
|
zsend_vrf_delete(client, zvrf);
|
|
}
|
|
}
|
|
|
|
void zebra_vrf_update_all(struct zserv *client)
|
|
{
|
|
struct vrf *vrf;
|
|
|
|
RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) {
|
|
if (vrf->vrf_id != VRF_UNKNOWN)
|
|
zsend_vrf_add(client, vrf_info_lookup(vrf->vrf_id));
|
|
}
|
|
}
|
|
|
|
/* Callback upon creating a new VRF. */
|
|
static int zebra_vrf_new(struct vrf *vrf)
|
|
{
|
|
struct zebra_vrf *zvrf;
|
|
|
|
if (IS_ZEBRA_DEBUG_EVENT)
|
|
zlog_debug("VRF %s created, id %u", vrf->name, vrf->vrf_id);
|
|
|
|
zvrf = zebra_vrf_alloc(vrf);
|
|
if (!vrf_is_backend_netns())
|
|
zvrf->zns = zebra_ns_lookup(NS_DEFAULT);
|
|
else if (vrf->vrf_id == VRF_DEFAULT) {
|
|
struct ns *ns;
|
|
|
|
strlcpy(vrf->data.l.netns_name, VRF_DEFAULT_NAME, NS_NAMSIZ);
|
|
ns = ns_lookup(NS_DEFAULT);
|
|
ns->vrf_ctxt = vrf;
|
|
vrf->ns_ctxt = ns;
|
|
}
|
|
|
|
otable_init(&zvrf->other_tables);
|
|
|
|
router_id_init(zvrf);
|
|
|
|
/* Initiate Table Manager per ZNS */
|
|
table_manager_enable(zvrf);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Callback upon enabling a VRF. */
|
|
static int zebra_vrf_enable(struct vrf *vrf)
|
|
{
|
|
struct zebra_vrf *zvrf = vrf->info;
|
|
struct route_table *table;
|
|
afi_t afi;
|
|
safi_t safi;
|
|
|
|
assert(zvrf);
|
|
if (IS_ZEBRA_DEBUG_EVENT)
|
|
zlog_debug("VRF %s id %u is now active", zvrf_name(zvrf),
|
|
zvrf_id(zvrf));
|
|
|
|
if (vrf_is_backend_netns())
|
|
zvrf->zns = zebra_ns_lookup((ns_id_t)vrf->vrf_id);
|
|
else
|
|
zvrf->zns = zebra_ns_lookup(NS_DEFAULT);
|
|
|
|
rtadv_vrf_init(zvrf);
|
|
|
|
/* Inform clients that the VRF is now active. This is an
|
|
* add for the clients.
|
|
*/
|
|
|
|
zebra_vrf_add_update(zvrf);
|
|
/* Allocate tables */
|
|
for (afi = AFI_IP; afi <= AFI_IP6; afi++) {
|
|
for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++)
|
|
zebra_vrf_table_create(zvrf, afi, safi);
|
|
|
|
table = route_table_init();
|
|
table->cleanup = zebra_rnhtable_node_cleanup;
|
|
zvrf->rnh_table[afi] = table;
|
|
|
|
table = route_table_init();
|
|
table->cleanup = zebra_rnhtable_node_cleanup;
|
|
zvrf->rnh_table_multicast[afi] = table;
|
|
}
|
|
|
|
/* Kick off any VxLAN-EVPN processing. */
|
|
zebra_vxlan_vrf_enable(zvrf);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* update the VRF ID of a routing table and their routing entries */
|
|
static void zebra_vrf_disable_update_vrfid(struct zebra_vrf *zvrf, afi_t afi, safi_t safi)
|
|
{
|
|
struct rib_table_info *info;
|
|
struct route_entry *re, *nre;
|
|
struct route_node *rn, *nrn;
|
|
bool empty_table = true;
|
|
bool rn_delete;
|
|
|
|
/* Assign the table to the default VRF.
|
|
* Although the table is not technically owned by the default VRF,
|
|
* the code assumes that unassigned routing tables are
|
|
* associated with the default VRF.
|
|
*/
|
|
info = route_table_get_info(zvrf->table[afi][safi]);
|
|
info->zvrf = vrf_info_lookup(VRF_DEFAULT);
|
|
|
|
rn = route_top(zvrf->table[afi][safi]);
|
|
if (rn)
|
|
empty_table = false;
|
|
while (rn) {
|
|
if (!rn->info) {
|
|
rn = route_next(rn);
|
|
continue;
|
|
}
|
|
|
|
/* Assign the kernel route entries to the default VRF,
|
|
* even though they are not actually owned by it.
|
|
*
|
|
* Remove route nodes that were created by FRR daemons,
|
|
* unless they are associated with the table rather than the VRF.
|
|
* Routes associated with the VRF are not needed once the VRF is
|
|
* disabled.
|
|
*/
|
|
rn_delete = true;
|
|
RNODE_FOREACH_RE_SAFE (rn, re, nre) {
|
|
if (re->type == ZEBRA_ROUTE_KERNEL ||
|
|
CHECK_FLAG(re->flags, ZEBRA_FLAG_TABLEID)) {
|
|
nexthop_vrf_update(rn, re, VRF_DEFAULT);
|
|
if (CHECK_FLAG(re->flags, ZEBRA_FLAG_TABLEID))
|
|
/* reinstall routes */
|
|
rib_install_kernel(rn, re, NULL);
|
|
rn_delete = false;
|
|
} else
|
|
rib_unlink(rn, re);
|
|
}
|
|
if (rn_delete) {
|
|
nrn = route_next(rn);
|
|
zebra_node_info_cleanup(rn);
|
|
rn->info = NULL;
|
|
route_unlock_node(rn);
|
|
rn = nrn;
|
|
} else {
|
|
empty_table = false;
|
|
rn = route_next(rn);
|
|
}
|
|
}
|
|
|
|
if (empty_table)
|
|
zebra_router_release_table(zvrf, zvrf->table_id, afi, safi);
|
|
zvrf->table[afi][safi] = NULL;
|
|
}
|
|
|
|
/* Callback upon disabling a VRF. */
|
|
static int zebra_vrf_disable(struct vrf *vrf)
|
|
{
|
|
struct zebra_vrf *zvrf = vrf->info;
|
|
struct interface *ifp;
|
|
afi_t afi;
|
|
safi_t safi;
|
|
|
|
assert(zvrf);
|
|
if (IS_ZEBRA_DEBUG_EVENT)
|
|
zlog_debug("VRF %s id %u is now inactive", zvrf_name(zvrf),
|
|
zvrf_id(zvrf));
|
|
|
|
/* Stop any VxLAN-EVPN processing. */
|
|
zebra_vxlan_vrf_disable(zvrf);
|
|
|
|
rtadv_vrf_terminate(zvrf);
|
|
|
|
/* Inform clients that the VRF is now inactive. This is a
|
|
* delete for the clients.
|
|
*/
|
|
zebra_vrf_delete_update(zvrf);
|
|
|
|
/* If asked to retain routes, there's nothing more to do. */
|
|
if (CHECK_FLAG(zvrf->flags, ZEBRA_VRF_RETAIN))
|
|
return 0;
|
|
|
|
/* Remove all routes. */
|
|
for (afi = AFI_IP; afi <= AFI_IP6; afi++) {
|
|
route_table_finish(zvrf->rnh_table[afi]);
|
|
zvrf->rnh_table[afi] = NULL;
|
|
route_table_finish(zvrf->rnh_table_multicast[afi]);
|
|
zvrf->rnh_table_multicast[afi] = NULL;
|
|
|
|
for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++)
|
|
rib_close_table(zvrf->table[afi][safi]);
|
|
}
|
|
|
|
/* Cleanup Vxlan, MPLS and PW tables. */
|
|
zebra_vxlan_cleanup_tables(zvrf);
|
|
zebra_mpls_cleanup_tables(zvrf);
|
|
zebra_pw_exit_vrf(zvrf);
|
|
|
|
/* Remove link-local IPv4 addresses created for BGP unnumbered peering.
|
|
*/
|
|
FOR_ALL_INTERFACES (vrf, ifp)
|
|
if_nbr_ipv6ll_to_ipv4ll_neigh_del_all(ifp);
|
|
|
|
/* clean-up work queues */
|
|
meta_queue_free(zrouter.mq, zvrf);
|
|
|
|
/* Cleanup (free) routing tables and NHT tables. */
|
|
for (afi = AFI_IP; afi <= AFI_IP6; afi++) {
|
|
/*
|
|
* Set the table pointer to NULL as that
|
|
* we no-longer need a copy of it, nor do we
|
|
* own this data, the zebra_router structure
|
|
* owns these tables. Once we've cleaned up the
|
|
* table, see rib_close_table above
|
|
* we no-longer need this pointer.
|
|
*/
|
|
for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++) {
|
|
if (!zvrf->table[afi][safi] || vrf->vrf_id == VRF_DEFAULT) {
|
|
zebra_router_release_table(zvrf, zvrf->table_id, afi, safi);
|
|
zvrf->table[afi][safi] = NULL;
|
|
continue;
|
|
}
|
|
|
|
zebra_vrf_disable_update_vrfid(zvrf, afi, safi);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int zebra_vrf_delete(struct vrf *vrf)
|
|
{
|
|
struct zebra_vrf *zvrf = vrf->info;
|
|
struct other_route_table *otable;
|
|
|
|
assert(zvrf);
|
|
if (IS_ZEBRA_DEBUG_EVENT)
|
|
zlog_debug("VRF %s id %u deleted", zvrf_name(zvrf),
|
|
zvrf_id(zvrf));
|
|
|
|
table_manager_disable(zvrf);
|
|
|
|
/* clean-up work queues */
|
|
meta_queue_free(zrouter.mq, zvrf);
|
|
|
|
/* Free Vxlan and MPLS. */
|
|
zebra_vxlan_close_tables(zvrf);
|
|
zebra_mpls_close_tables(zvrf);
|
|
|
|
otable = otable_pop(&zvrf->other_tables);
|
|
while (otable) {
|
|
zebra_router_release_table(zvrf, otable->table_id,
|
|
otable->afi, otable->safi);
|
|
XFREE(MTYPE_OTHER_TABLE, otable);
|
|
|
|
otable = otable_pop(&zvrf->other_tables);
|
|
}
|
|
|
|
/* Cleanup EVPN states for vrf */
|
|
zebra_vxlan_vrf_delete(zvrf);
|
|
zebra_routemap_vrf_delete(zvrf);
|
|
|
|
list_delete_all_node(zvrf->rid_all_sorted_list);
|
|
list_delete_all_node(zvrf->rid_lo_sorted_list);
|
|
|
|
list_delete_all_node(zvrf->rid6_all_sorted_list);
|
|
list_delete_all_node(zvrf->rid6_lo_sorted_list);
|
|
|
|
otable_fini(&zvrf->other_tables);
|
|
XFREE(MTYPE_ZEBRA_VRF, zvrf);
|
|
|
|
if (vrf->ns_ctxt) {
|
|
ns_delete(vrf->ns_ctxt);
|
|
vrf->ns_ctxt = NULL;
|
|
}
|
|
|
|
vrf->info = NULL;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Lookup the routing table in a VRF based on both VRF-Id and table-id.
|
|
* NOTE: Table-id is relevant on two modes:
|
|
* - case VRF backend is default : on default VRF only
|
|
* - case VRF backend is netns : on all VRFs
|
|
*/
|
|
struct route_table *zebra_vrf_lookup_table_with_table_id(afi_t afi, safi_t safi,
|
|
vrf_id_t vrf_id,
|
|
uint32_t table_id)
|
|
{
|
|
struct zebra_vrf *zvrf = vrf_info_lookup(vrf_id);
|
|
struct other_route_table ort, *otable;
|
|
|
|
if (!zvrf)
|
|
return NULL;
|
|
|
|
if (afi >= AFI_MAX || safi >= SAFI_MAX)
|
|
return NULL;
|
|
|
|
if (table_id == zvrf->table_id)
|
|
return zebra_vrf_table(afi, safi, vrf_id);
|
|
|
|
ort.afi = afi;
|
|
ort.safi = safi;
|
|
ort.table_id = table_id;
|
|
otable = otable_find(&zvrf->other_tables, &ort);
|
|
|
|
if (otable)
|
|
return otable->table;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
struct route_table *zebra_vrf_get_table_with_table_id(afi_t afi, safi_t safi,
|
|
vrf_id_t vrf_id,
|
|
uint32_t table_id)
|
|
{
|
|
struct zebra_vrf *zvrf = vrf_info_lookup(vrf_id);
|
|
struct other_route_table *otable;
|
|
struct route_table *table;
|
|
|
|
table = zebra_vrf_lookup_table_with_table_id(afi, safi, vrf_id,
|
|
table_id);
|
|
|
|
if (table)
|
|
goto done;
|
|
|
|
/* Create it as an `other` table */
|
|
table = zebra_router_get_table(zvrf, table_id, afi, safi);
|
|
|
|
otable = XCALLOC(MTYPE_OTHER_TABLE, sizeof(*otable));
|
|
otable->afi = afi;
|
|
otable->safi = safi;
|
|
otable->table_id = table_id;
|
|
otable->table = table;
|
|
otable_add(&zvrf->other_tables, otable);
|
|
|
|
done:
|
|
return table;
|
|
}
|
|
|
|
static void zebra_rnhtable_node_cleanup(struct route_table *table,
|
|
struct route_node *node)
|
|
{
|
|
if (node->info)
|
|
zebra_free_rnh(node->info);
|
|
}
|
|
|
|
/*
|
|
* Create a routing table for the specific AFI/SAFI in the given VRF.
|
|
*/
|
|
static void zebra_vrf_table_create(struct zebra_vrf *zvrf, afi_t afi,
|
|
safi_t safi)
|
|
{
|
|
vrf_id_t vrf_id = zvrf->vrf->vrf_id;
|
|
struct rib_table_info *info;
|
|
struct route_entry *re;
|
|
struct route_node *rn;
|
|
struct prefix p;
|
|
|
|
assert(!zvrf->table[afi][safi]);
|
|
|
|
/* Attempt to retrieve the Linux routing table using zvrf->table_id.
|
|
* If the table was created before the VRF, it will already exist.
|
|
* Otherwise, create a new table.
|
|
*/
|
|
zvrf->table[afi][safi] =
|
|
zebra_router_get_table(zvrf, zvrf->table_id, afi, safi);
|
|
|
|
/* If the table existed before the VRF was created, info->zvrf was
|
|
* referring to the default VRF.
|
|
* Assign the table to the new VRF.
|
|
* Note: FRR does not allow multiple VRF interfaces to be created with the
|
|
* same table ID.
|
|
*/
|
|
info = route_table_get_info(zvrf->table[afi][safi]);
|
|
info->zvrf = zvrf;
|
|
|
|
/* If the table existed before the VRF was created, their routing entries
|
|
* was owned by the default VRF.
|
|
* Re-assign all the routing entries to the new VRF.
|
|
*/
|
|
for (rn = route_top(zvrf->table[afi][safi]); rn; rn = route_next(rn)) {
|
|
if (!rn->info)
|
|
continue;
|
|
|
|
RNODE_FOREACH_RE (rn, re)
|
|
nexthop_vrf_update(rn, re, vrf_id);
|
|
}
|
|
|
|
memset(&p, 0, sizeof(p));
|
|
p.family = afi2family(afi);
|
|
|
|
/* create a fake default route or get the existing one */
|
|
rn = srcdest_rnode_get(zvrf->table[afi][safi], &p, NULL);
|
|
if (!rn->info)
|
|
/* do not override the existing default route */
|
|
zebra_rib_create_dest(rn);
|
|
}
|
|
|
|
/* Allocate new zebra VRF. */
|
|
struct zebra_vrf *zebra_vrf_alloc(struct vrf *vrf)
|
|
{
|
|
struct zebra_vrf *zvrf;
|
|
|
|
zvrf = XCALLOC(MTYPE_ZEBRA_VRF, sizeof(struct zebra_vrf));
|
|
|
|
zvrf->vrf = vrf;
|
|
vrf->info = zvrf;
|
|
|
|
zebra_vxlan_init_tables(zvrf);
|
|
zebra_mpls_init_tables(zvrf);
|
|
zebra_pw_init_vrf(zvrf);
|
|
zvrf->table_id = rt_table_main_id;
|
|
/* by default table ID is default one */
|
|
|
|
if (DFLT_ZEBRA_IP_NHT_RESOLVE_VIA_DEFAULT) {
|
|
zvrf->zebra_rnh_ip_default_route = true;
|
|
zvrf->zebra_rnh_ipv6_default_route = true;
|
|
}
|
|
|
|
return zvrf;
|
|
}
|
|
|
|
/*
|
|
* Pending: create an efficient table_id (in a tree/hash) based lookup)
|
|
*/
|
|
vrf_id_t zebra_vrf_lookup_by_table(uint32_t table_id, ns_id_t ns_id)
|
|
{
|
|
struct vrf *vrf;
|
|
struct zebra_vrf *zvrf;
|
|
|
|
RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) {
|
|
zvrf = vrf->info;
|
|
|
|
if (zvrf == NULL)
|
|
continue;
|
|
/* case vrf with netns : match the netnsid */
|
|
if (vrf_is_backend_netns()) {
|
|
if (ns_id == zvrf_id(zvrf))
|
|
return zvrf_id(zvrf);
|
|
} else {
|
|
/* VRF is VRF_BACKEND_VRF_LITE */
|
|
if (zvrf->table_id != table_id)
|
|
continue;
|
|
|
|
return zvrf_id(zvrf);
|
|
}
|
|
}
|
|
|
|
return VRF_DEFAULT;
|
|
}
|
|
|
|
/*
|
|
* Lookup tableid by vrfid; handle vrf-lite and vrf-netns cases
|
|
*/
|
|
int zebra_vrf_lookup_tableid(vrf_id_t vrf_id, ns_id_t ns_id)
|
|
{
|
|
struct zebra_vrf *zvrf;
|
|
|
|
/* Handle vrf-lite and vrf-netns */
|
|
if (vrf_is_backend_netns())
|
|
zvrf = vrf_info_lookup(ns_id);
|
|
else
|
|
zvrf = vrf_info_lookup(vrf_id);
|
|
|
|
if (zvrf)
|
|
return zvrf->table_id;
|
|
else
|
|
return ZEBRA_ROUTE_TABLE_UNKNOWN;
|
|
}
|
|
|
|
/* Lookup VRF by identifier. */
|
|
struct zebra_vrf *zebra_vrf_lookup_by_id(vrf_id_t vrf_id)
|
|
{
|
|
return vrf_info_lookup(vrf_id);
|
|
}
|
|
|
|
/* Lookup VRF by name. */
|
|
struct zebra_vrf *zebra_vrf_lookup_by_name(const char *name)
|
|
{
|
|
struct vrf *vrf;
|
|
|
|
if (!name)
|
|
name = VRF_DEFAULT_NAME;
|
|
|
|
vrf = vrf_lookup_by_name(name);
|
|
if (vrf)
|
|
return ((struct zebra_vrf *)vrf->info);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/* Lookup the routing table in an enabled VRF. */
|
|
struct route_table *zebra_vrf_table(afi_t afi, safi_t safi, vrf_id_t vrf_id)
|
|
{
|
|
struct zebra_vrf *zvrf = vrf_info_lookup(vrf_id);
|
|
|
|
if (!zvrf)
|
|
return NULL;
|
|
|
|
if (afi >= AFI_MAX || safi >= SAFI_MAX)
|
|
return NULL;
|
|
|
|
return zvrf->table[afi][safi];
|
|
}
|
|
|
|
/* if ns_id is different and not VRF_UNKNOWN,
|
|
* then update vrf identifier, and enable VRF
|
|
*/
|
|
static void vrf_update_vrf_id(ns_id_t ns_id, void *opaqueptr)
|
|
{
|
|
ns_id_t vrf_id = (vrf_id_t)ns_id;
|
|
vrf_id_t old_vrf_id;
|
|
struct vrf *vrf = (struct vrf *)opaqueptr;
|
|
|
|
if (!vrf)
|
|
return;
|
|
old_vrf_id = vrf->vrf_id;
|
|
if (vrf_id == vrf->vrf_id)
|
|
return;
|
|
if (vrf->vrf_id != VRF_UNKNOWN)
|
|
RB_REMOVE(vrf_id_head, &vrfs_by_id, vrf);
|
|
vrf->vrf_id = vrf_id;
|
|
RB_INSERT(vrf_id_head, &vrfs_by_id, vrf);
|
|
if (old_vrf_id == VRF_UNKNOWN)
|
|
vrf_enable(vrf);
|
|
}
|
|
|
|
int zebra_vrf_netns_handler_create(struct vty *vty, struct vrf *vrf,
|
|
char *pathname, ns_id_t ns_id,
|
|
ns_id_t internal_ns_id,
|
|
ns_id_t rel_def_ns_id)
|
|
{
|
|
struct ns *ns = NULL;
|
|
|
|
if (!vrf)
|
|
return CMD_WARNING_CONFIG_FAILED;
|
|
if (vrf->vrf_id != VRF_UNKNOWN && vrf->ns_ctxt == NULL) {
|
|
if (vty)
|
|
vty_out(vty,
|
|
"VRF %u is already configured with VRF %s\n",
|
|
vrf->vrf_id, vrf->name);
|
|
else
|
|
zlog_info("VRF %u is already configured with VRF %s",
|
|
vrf->vrf_id, vrf->name);
|
|
return CMD_WARNING_CONFIG_FAILED;
|
|
}
|
|
if (vrf->ns_ctxt != NULL) {
|
|
ns = (struct ns *)vrf->ns_ctxt;
|
|
if (!strcmp(ns->name, pathname)) {
|
|
if (vty)
|
|
vty_out(vty,
|
|
"VRF %u already configured with NETNS %s\n",
|
|
vrf->vrf_id, ns->name);
|
|
else
|
|
zlog_info(
|
|
"VRF %u already configured with NETNS %s",
|
|
vrf->vrf_id, ns->name);
|
|
return CMD_WARNING;
|
|
}
|
|
}
|
|
ns = ns_lookup_name(pathname);
|
|
if (ns && ns->vrf_ctxt) {
|
|
struct vrf *vrf2 = (struct vrf *)ns->vrf_ctxt;
|
|
|
|
if (vrf2 == vrf)
|
|
return CMD_SUCCESS;
|
|
if (vty)
|
|
vty_out(vty,
|
|
"NS %s is already configured with VRF %u(%s)\n",
|
|
ns->name, vrf2->vrf_id, vrf2->name);
|
|
else
|
|
zlog_info("NS %s is already configured with VRF %u(%s)",
|
|
ns->name, vrf2->vrf_id, vrf2->name);
|
|
return CMD_WARNING_CONFIG_FAILED;
|
|
}
|
|
ns = ns_get_created(ns, pathname, ns_id);
|
|
ns->internal_ns_id = internal_ns_id;
|
|
ns->relative_default_ns = rel_def_ns_id;
|
|
ns->vrf_ctxt = (void *)vrf;
|
|
vrf->ns_ctxt = (void *)ns;
|
|
/* update VRF netns NAME */
|
|
strlcpy(vrf->data.l.netns_name, basename(pathname), NS_NAMSIZ);
|
|
|
|
if (!ns_enable(ns, vrf_update_vrf_id)) {
|
|
if (vty)
|
|
vty_out(vty, "Can not associate NS %u with NETNS %s\n",
|
|
ns->ns_id, ns->name);
|
|
else
|
|
zlog_info("Can not associate NS %u with NETNS %s",
|
|
ns->ns_id, ns->name);
|
|
return CMD_WARNING_CONFIG_FAILED;
|
|
}
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
/* Zebra VRF initialization. */
|
|
void zebra_vrf_init(void)
|
|
{
|
|
vrf_init(zebra_vrf_new, zebra_vrf_enable, zebra_vrf_disable,
|
|
zebra_vrf_delete);
|
|
|
|
hook_register(zserv_client_close, release_daemon_table_chunks);
|
|
}
|