mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-04-29 23:08:38 +00:00

when the netns backend is selected for VRF, the default VRF is being assigned a NSID. This avoids the need to handle the case where if the incoming NSID was 0 for a non default VRF, then a specific handling had to be done to keep 0 value for default VRF. In most cases, as the first NETNS to get a NSID will be the default VRF, most probably the default VRF will be assigned to 0, while the other ones will have their value incremented. On some cases, where the NSID is already assigned for NETNS, including default VRF, then the default VRF value will be the one derived from the NSID of default VRF, thus keeping consistency between VRF IDs and NETNS IDs. Default NS is attempted to be created. Actually, some VMs may have the netns feature, but the NS initialisation fails because that folder is not present. Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
275 lines
6.4 KiB
C
275 lines
6.4 KiB
C
/* zebra NS Routines
|
|
* Copyright (C) 2016 Cumulus Networks, Inc.
|
|
* Donald Sharp
|
|
* Copyright (C) 2017/2018 6WIND
|
|
*
|
|
* This file is part of Quagga.
|
|
*
|
|
* Quagga is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License as published by the
|
|
* Free Software Foundation; either version 2, or (at your option) any
|
|
* later version.
|
|
*
|
|
* Quagga is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program; see the file COPYING; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
#include "zebra.h"
|
|
|
|
#include "lib/ns.h"
|
|
#include "lib/vrf.h"
|
|
#include "lib/prefix.h"
|
|
#include "lib/memory.h"
|
|
|
|
#include "rtadv.h"
|
|
#include "zebra_ns.h"
|
|
#include "zebra_vrf.h"
|
|
#include "zebra_memory.h"
|
|
#include "rt.h"
|
|
#include "zebra_vxlan.h"
|
|
#include "debug.h"
|
|
#include "zebra_netns_notify.h"
|
|
#include "zebra_netns_id.h"
|
|
|
|
extern struct zebra_privs_t zserv_privs;
|
|
|
|
DEFINE_MTYPE(ZEBRA, ZEBRA_NS, "Zebra Name Space")
|
|
|
|
static inline int
|
|
zebra_ns_table_entry_compare(const struct zebra_ns_table *e1,
|
|
const struct zebra_ns_table *e2);
|
|
|
|
RB_GENERATE(zebra_ns_table_head, zebra_ns_table, zebra_ns_table_entry,
|
|
zebra_ns_table_entry_compare);
|
|
|
|
static struct zebra_ns *dzns;
|
|
|
|
static inline int
|
|
zebra_ns_table_entry_compare(const struct zebra_ns_table *e1,
|
|
const struct zebra_ns_table *e2)
|
|
{
|
|
if (e1->tableid == e2->tableid)
|
|
return (e1->afi - e2->afi);
|
|
|
|
return e1->tableid - e2->tableid;
|
|
}
|
|
|
|
struct zebra_ns *zebra_ns_lookup(ns_id_t ns_id)
|
|
{
|
|
if (ns_id == NS_DEFAULT)
|
|
return dzns;
|
|
struct zebra_ns *info = (struct zebra_ns *)ns_info_lookup(ns_id);
|
|
|
|
return (info == NULL) ? dzns : info;
|
|
}
|
|
|
|
static struct zebra_ns *zebra_ns_alloc(void)
|
|
{
|
|
return XCALLOC(MTYPE_ZEBRA_NS, sizeof(struct zebra_ns));
|
|
}
|
|
|
|
static int zebra_ns_new(struct ns *ns)
|
|
{
|
|
struct zebra_ns *zns;
|
|
|
|
if (IS_ZEBRA_DEBUG_EVENT)
|
|
zlog_info("ZNS %s with id %u (created)", ns->name, ns->ns_id);
|
|
|
|
zns = zebra_ns_alloc();
|
|
ns->info = zns;
|
|
zns->ns = ns;
|
|
|
|
/* Do any needed per-NS data structure allocation. */
|
|
zns->if_table = route_table_init();
|
|
zebra_vxlan_ns_init(zns);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int zebra_ns_delete(struct ns *ns)
|
|
{
|
|
struct zebra_ns *zns = (struct zebra_ns *) ns->info;
|
|
|
|
if (IS_ZEBRA_DEBUG_EVENT)
|
|
zlog_info("ZNS %s with id %u (deleted)", ns->name, ns->ns_id);
|
|
if (!zns)
|
|
return 0;
|
|
XFREE(MTYPE_ZEBRA_NS, zns);
|
|
return 0;
|
|
}
|
|
|
|
static int zebra_ns_enabled(struct ns *ns)
|
|
{
|
|
struct zebra_ns *zns = ns->info;
|
|
|
|
if (IS_ZEBRA_DEBUG_EVENT)
|
|
zlog_info("ZNS %s with id %u (enabled)", ns->name, ns->ns_id);
|
|
if (!zns)
|
|
return 0;
|
|
return zebra_ns_enable(ns->ns_id, (void **)&zns);
|
|
}
|
|
|
|
int zebra_ns_disabled(struct ns *ns)
|
|
{
|
|
struct zebra_ns *zns = ns->info;
|
|
|
|
if (IS_ZEBRA_DEBUG_EVENT)
|
|
zlog_info("ZNS %s with id %u (disabled)", ns->name, ns->ns_id);
|
|
if (!zns)
|
|
return 0;
|
|
return zebra_ns_disable(ns->ns_id, (void **)&zns);
|
|
}
|
|
|
|
/* Do global enable actions - open sockets, read kernel config etc. */
|
|
int zebra_ns_enable(ns_id_t ns_id, void **info)
|
|
{
|
|
struct zebra_ns *zns = (struct zebra_ns *)(*info);
|
|
|
|
zns->ns_id = ns_id;
|
|
|
|
#if defined(HAVE_RTADV)
|
|
rtadv_init(zns);
|
|
#endif
|
|
|
|
kernel_init(zns);
|
|
interface_list(zns);
|
|
route_read(zns);
|
|
|
|
return 0;
|
|
}
|
|
|
|
struct route_table *zebra_ns_find_table(struct zebra_ns *zns,
|
|
uint32_t tableid, afi_t afi)
|
|
{
|
|
struct zebra_ns_table finder;
|
|
struct zebra_ns_table *znst;
|
|
|
|
memset(&finder, 0, sizeof(finder));
|
|
finder.afi = afi;
|
|
finder.tableid = tableid;
|
|
znst = RB_FIND(zebra_ns_table_head, &zns->ns_tables, &finder);
|
|
|
|
if (znst)
|
|
return znst->table;
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
struct route_table *zebra_ns_get_table(struct zebra_ns *zns,
|
|
struct zebra_vrf *zvrf, uint32_t tableid,
|
|
afi_t afi)
|
|
{
|
|
struct zebra_ns_table finder;
|
|
struct zebra_ns_table *znst;
|
|
rib_table_info_t *info;
|
|
|
|
memset(&finder, 0, sizeof(finder));
|
|
finder.afi = afi;
|
|
finder.tableid = tableid;
|
|
znst = RB_FIND(zebra_ns_table_head, &zns->ns_tables, &finder);
|
|
|
|
if (znst)
|
|
return znst->table;
|
|
|
|
znst = XCALLOC(MTYPE_ZEBRA_NS, sizeof(*znst));
|
|
znst->tableid = tableid;
|
|
znst->afi = afi;
|
|
znst->table =
|
|
(afi == AFI_IP6) ? srcdest_table_init() : route_table_init();
|
|
|
|
info = XCALLOC(MTYPE_RIB_TABLE_INFO, sizeof(*info));
|
|
info->zvrf = zvrf;
|
|
info->afi = afi;
|
|
info->safi = SAFI_UNICAST;
|
|
znst->table->info = info;
|
|
znst->table->cleanup = zebra_rtable_node_cleanup;
|
|
|
|
RB_INSERT(zebra_ns_table_head, &zns->ns_tables, znst);
|
|
return znst->table;
|
|
}
|
|
|
|
static void zebra_ns_free_table(struct zebra_ns_table *znst)
|
|
{
|
|
void *table_info;
|
|
|
|
rib_close_table(znst->table);
|
|
|
|
table_info = znst->table->info;
|
|
route_table_finish(znst->table);
|
|
XFREE(MTYPE_RIB_TABLE_INFO, table_info);
|
|
XFREE(MTYPE_ZEBRA_NS, znst);
|
|
}
|
|
|
|
int zebra_ns_disable(ns_id_t ns_id, void **info)
|
|
{
|
|
struct zebra_ns_table *znst;
|
|
struct zebra_ns *zns = (struct zebra_ns *)(*info);
|
|
|
|
while (!RB_EMPTY(zebra_ns_table_head, &zns->ns_tables)) {
|
|
znst = RB_ROOT(zebra_ns_table_head, &zns->ns_tables);
|
|
|
|
RB_REMOVE(zebra_ns_table_head, &zns->ns_tables, znst);
|
|
zebra_ns_free_table(znst);
|
|
}
|
|
route_table_finish(zns->if_table);
|
|
zebra_vxlan_ns_disable(zns);
|
|
#if defined(HAVE_RTADV)
|
|
rtadv_terminate(zns);
|
|
#endif
|
|
|
|
kernel_terminate(zns);
|
|
|
|
zns->ns_id = NS_DEFAULT;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
int zebra_ns_init(void)
|
|
{
|
|
ns_id_t ns_id;
|
|
|
|
dzns = zebra_ns_alloc();
|
|
|
|
if (zserv_privs.change(ZPRIVS_RAISE))
|
|
zlog_err("Can't raise privileges");
|
|
ns_id = zebra_ns_id_get_default();
|
|
if (zserv_privs.change(ZPRIVS_LOWER))
|
|
zlog_err("Can't lower privileges");
|
|
ns_init_zebra(ns_id);
|
|
|
|
ns_init();
|
|
|
|
/* Do any needed per-NS data structure allocation. */
|
|
dzns->if_table = route_table_init();
|
|
zebra_vxlan_ns_init(dzns);
|
|
|
|
/* Register zebra VRF callbacks, create and activate default VRF. */
|
|
zebra_vrf_init();
|
|
|
|
/* Default NS is activated */
|
|
zebra_ns_enable(NS_DEFAULT, (void **)&dzns);
|
|
|
|
if (vrf_is_backend_netns()) {
|
|
ns_add_hook(NS_NEW_HOOK, zebra_ns_new);
|
|
ns_add_hook(NS_ENABLE_HOOK, zebra_ns_enabled);
|
|
ns_add_hook(NS_DISABLE_HOOK, zebra_ns_disabled);
|
|
ns_add_hook(NS_DELETE_HOOK, zebra_ns_delete);
|
|
zebra_ns_notify_parse();
|
|
zebra_ns_notify_init();
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int zebra_ns_config_write(struct vty *vty, struct ns *ns)
|
|
{
|
|
if (ns && ns->name != NULL)
|
|
vty_out(vty, " netns %s\n", ns->name);
|
|
return 0;
|
|
}
|