struct ns *ns;
int write = 0;
- RB_FOREACH (ns, ns_head, &ns_tree) {
+ if (vrf_is_backend_netns())
+ return 0;
+ RB_FOREACH(ns, ns_head, &ns_tree) {
if (ns->ns_id == NS_DEFAULT || ns->name == NULL)
continue;
exit(1);
}
- if (have_netns()) {
+ if (have_netns() && !vrf_is_backend_netns()) {
/* Install NS commands. */
install_node(&ns_node, ns_config_write);
install_element(CONFIG_NODE, &ns_netns_cmd);
struct vrf_id_head vrfs_by_id = RB_INITIALIZER(&vrfs_by_id);
struct vrf_name_head vrfs_by_name = RB_INITIALIZER(&vrfs_by_name);
+static int vrf_backend;
+
/*
* Turn on/off debug code
* for vrf.
return ret;
}
+int vrf_is_backend_netns(void)
+{
+ return (vrf_backend == VRF_BACKEND_NETNS);
+}
+
+int vrf_get_backend(void)
+{
+ return vrf_backend;
+}
+
+void vrf_configure_backend(int vrf_backend_netns)
+{
+ vrf_backend = vrf_backend_netns;
+}
+
/* vrf CLI commands */
DEFUN_NOSH (vrf,
vrf_cmd,
RB_PROTOTYPE(vrf_name_head, vrf, name_entry, vrf_name_compare)
DECLARE_QOBJ_TYPE(vrf)
+/* Allow VRF with netns as backend */
+#define VRF_BACKEND_VRF_LITE 0
+#define VRF_BACKEND_NETNS 1
extern struct vrf_id_head vrfs_by_id;
extern struct vrf_name_head vrfs_by_name;
/* Create a socket serving for the given VRF */
extern int vrf_socket(int, int, int, vrf_id_t);
+extern void vrf_configure_backend(int vrf_backend_netns);
+extern int vrf_get_backend(void);
+extern int vrf_is_backend_netns(void);
/*
* VRF Debugging
}
/* If VRF, create the VRF structure itself. */
- if (zif_type == ZEBRA_IF_VRF) {
+ if (zif_type == ZEBRA_IF_VRF && !vrf_is_backend_netns()) {
netlink_vrf_change(h, tb[IFLA_LINKINFO], name);
vrf_id = (vrf_id_t)ifi->ifi_index;
}
if (tb[IFLA_MASTER]) {
- if (slave_kind && (strcmp(slave_kind, "vrf") == 0)) {
+ if (slave_kind && (strcmp(slave_kind, "vrf") == 0)
+ && !vrf_is_backend_netns()) {
zif_slave_type = ZEBRA_IF_SLAVE_VRF;
vrf_id = *(u_int32_t *)RTA_DATA(tb[IFLA_MASTER]);
} else if (slave_kind && (strcmp(slave_kind, "bridge") == 0)) {
} else
zif_slave_type = ZEBRA_IF_SLAVE_OTHER;
}
+ if (vrf_is_backend_netns())
+ vrf_id = (vrf_id_t)ns_id;
/* If linking to another interface, note it. */
if (tb[IFLA_LINK])
}
/* If VRF, create or update the VRF structure itself. */
- if (zif_type == ZEBRA_IF_VRF) {
+ if (zif_type == ZEBRA_IF_VRF && !vrf_is_backend_netns()) {
netlink_vrf_change(h, tb[IFLA_LINKINFO], name);
vrf_id = (vrf_id_t)ifi->ifi_index;
}
if (h->nlmsg_type == RTM_NEWLINK) {
if (tb[IFLA_MASTER]) {
- if (slave_kind && (strcmp(slave_kind, "vrf") == 0)) {
+ if (slave_kind && (strcmp(slave_kind, "vrf") == 0)
+ && !vrf_is_backend_netns()) {
zif_slave_type = ZEBRA_IF_SLAVE_VRF;
vrf_id =
*(u_int32_t *)RTA_DATA(tb[IFLA_MASTER]);
{"label_socket", no_argument, NULL, 'l'},
{"retain", no_argument, NULL, 'r'},
#ifdef HAVE_NETLINK
+ {"vrfwnetns", no_argument, NULL, 'n'},
{"nl-bufsize", required_argument, NULL, 's'},
#endif /* HAVE_NETLINK */
{0}};
char *fuzzing = NULL;
#endif
+ vrf_configure_backend(VRF_BACKEND_VRF_LITE);
+
frr_preinit(&zebra_di, argc, argv);
frr_opt_add(
"bakz:e:l:r"
#ifdef HAVE_NETLINK
- "s:"
+ "s:n"
#endif
#if defined(HANDLE_ZAPI_FUZZING)
"c:"
" -k, --keep_kernel Don't delete old routes which installed by zebra.\n"
" -r, --retain When program terminates, retain added route by zebra.\n"
#ifdef HAVE_NETLINK
+ " -n, --vrfwnetns Set VRF with NetNS\n"
" -s, --nl-bufsize Set netlink receive buffer size\n"
#endif /* HAVE_NETLINK */
#if defined(HANDLE_ZAPI_FUZZING)
case 's':
nl_rcvbufsize = atoi(optarg);
break;
+ case 'n':
+ vrf_configure_backend(VRF_BACKEND_NETNS);
+ break;
#endif /* HAVE_NETLINK */
#if defined(HANDLE_ZAPI_FUZZING)
case 'c':
/*
Pending: create an efficient table_id (in a tree/hash) based lookup)
*/
-static vrf_id_t vrf_lookup_by_table(u_int32_t table_id)
+static vrf_id_t vrf_lookup_by_table(u_int32_t table_id, ns_id_t ns_id)
{
struct vrf *vrf;
struct zebra_vrf *zvrf;
RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) {
- if ((zvrf = vrf->info) == NULL || (zvrf->table_id != table_id))
+ zvrf = vrf->info;
+ if (zvrf == NULL)
continue;
-
- return zvrf_id(zvrf);
+ /* 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;
u_char flags = 0;
struct prefix p;
struct prefix_ipv6 src_p = {};
- vrf_id_t vrf_id = VRF_DEFAULT;
+ vrf_id_t vrf_id;
char anyaddr[16] = {0};
table = rtm->rtm_table;
/* Map to VRF */
- vrf_id = vrf_lookup_by_table(table);
+ vrf_id = vrf_lookup_by_table(table, ns_id);
if (vrf_id == VRF_DEFAULT) {
if (!is_zebra_valid_kernel_table(table)
&& !is_zebra_main_routing_table(table))
char sbuf[40];
char gbuf[40];
char oif_list[256] = "\0";
- vrf_id_t vrf = ns_id;
+ vrf_id_t vrf;
int table;
if (mroute)
else
table = rtm->rtm_table;
- vrf = vrf_lookup_by_table(table);
+ vrf = vrf_lookup_by_table(table, ns_id);
if (tb[RTA_IIF])
iif = *(int *)RTA_DATA(tb[RTA_IIF]);
ns_id_t ns_id, int startup)
{
int len;
- vrf_id_t vrf_id = ns_id;
struct rtmsg *rtm;
rtm = NLMSG_DATA(h);
if (!(h->nlmsg_type == RTM_NEWROUTE || h->nlmsg_type == RTM_DELROUTE)) {
/* If this is not route add/delete message print warning. */
- zlog_warn("Kernel message: %d vrf %u\n", h->nlmsg_type, vrf_id);
+ zlog_warn("Kernel message: %d NS %u\n", h->nlmsg_type, ns_id);
return 0;
}
/* Connected route. */
if (IS_ZEBRA_DEBUG_KERNEL)
- zlog_debug("%s %s %s proto %s vrf %u",
+ zlog_debug("%s %s %s proto %s NS %u",
nl_msg_type_to_str(h->nlmsg_type),
nl_family_to_str(rtm->rtm_family),
nl_rttype_to_str(rtm->rtm_type),
- nl_rtproto_to_str(rtm->rtm_protocol), vrf_id);
+ nl_rtproto_to_str(rtm->rtm_protocol), ns_id);
/* We don't care about change notifications for the MPLS table. */
/* TODO: Revisit this. */
#include "command.h"
#include "memory.h"
#include "srcdest_table.h"
-
+#include "vrf.h"
#include "vty.h"
+
#include "zebra/debug.h"
#include "zebra/zserv.h"
#include "zebra/rib.h"