Skip to content

Commit

Permalink
zebra: add a runtime flag to enable vrf with netns
Browse files Browse the repository at this point in the history
The netns backend is chosen by VRF if a runtime flag named vrfwnetns is
selected when running zebra.
In the case the NETNS backend is chosen, in some case the VRFID value is
being assigned the value of the NSID. Within the perimeter of that work,
this is why the vrf_lookup_by_table function is extended with a new
parameter.

Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
  • Loading branch information
pguibert6WIND committed Feb 27, 2018
1 parent ac3133a commit 78dd30b
Show file tree
Hide file tree
Showing 7 changed files with 65 additions and 20 deletions.
6 changes: 4 additions & 2 deletions lib/ns.c
Expand Up @@ -378,7 +378,9 @@ static int ns_config_write(struct vty *vty)
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;

Expand Down Expand Up @@ -411,7 +413,7 @@ void ns_init(void)
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);
Expand Down
17 changes: 17 additions & 0 deletions lib/vrf.c
Expand Up @@ -44,6 +44,8 @@ RB_GENERATE(vrf_name_head, vrf, name_entry, vrf_name_compare);
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.
Expand Down Expand Up @@ -446,6 +448,21 @@ int vrf_socket(int domain, int type, int protocol, vrf_id_t vrf_id)
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,
Expand Down
6 changes: 6 additions & 0 deletions lib/vrf.h
Expand Up @@ -96,6 +96,9 @@ RB_HEAD(vrf_name_head, vrf);
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;
Expand Down Expand Up @@ -203,6 +206,9 @@ extern void vrf_cmd_init(int (*writefunc)(struct vty *vty));

/* 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
Expand Down
12 changes: 8 additions & 4 deletions zebra/if_netlink.c
Expand Up @@ -615,13 +615,14 @@ static int netlink_interface(struct sockaddr_nl *snl, struct nlmsghdr *h,
}

/* 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)) {
Expand All @@ -631,6 +632,8 @@ static int netlink_interface(struct sockaddr_nl *snl, struct nlmsghdr *h,
} 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])
Expand Down Expand Up @@ -1074,7 +1077,7 @@ int netlink_link_change(struct sockaddr_nl *snl, struct nlmsghdr *h,
}

/* 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;
}
Expand All @@ -1091,7 +1094,8 @@ int netlink_link_change(struct sockaddr_nl *snl, struct nlmsghdr *h,

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]);
Expand Down
9 changes: 8 additions & 1 deletion zebra/main.c
Expand Up @@ -85,6 +85,7 @@ struct option longopts[] = {{"batch", no_argument, NULL, 'b'},
{"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}};
Expand Down Expand Up @@ -205,12 +206,14 @@ int main(int argc, char **argv)
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:"
Expand All @@ -225,6 +228,7 @@ int main(int argc, char **argv)
" -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)
Expand Down Expand Up @@ -279,6 +283,9 @@ int main(int argc, char **argv)
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':
Expand Down
32 changes: 20 additions & 12 deletions zebra/rt_netlink.c
Expand Up @@ -194,16 +194,25 @@ static inline int proto2zebra(int proto, int family)
/*
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;
Expand All @@ -220,7 +229,7 @@ static int netlink_route_change_read_unicast(struct sockaddr_nl *snl,
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};

Expand Down Expand Up @@ -288,7 +297,7 @@ static int netlink_route_change_read_unicast(struct sockaddr_nl *snl,
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))
Expand Down Expand Up @@ -609,7 +618,7 @@ static int netlink_route_change_read_multicast(struct sockaddr_nl *snl,
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)
Expand All @@ -631,7 +640,7 @@ static int netlink_route_change_read_multicast(struct sockaddr_nl *snl,
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]);
Expand Down Expand Up @@ -687,24 +696,23 @@ int netlink_route_change(struct sockaddr_nl *snl, struct nlmsghdr *h,
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. */
Expand Down
3 changes: 2 additions & 1 deletion zebra/zebra_vrf.c
Expand Up @@ -25,8 +25,9 @@
#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"
Expand Down

0 comments on commit 78dd30b

Please sign in to comment.