diff --git a/lib/ns.c b/lib/ns.c index 0b2a3bec78d4..e3a1d9d0dc3e 100644 --- a/lib/ns.c +++ b/lib/ns.c @@ -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; @@ -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); diff --git a/lib/vrf.c b/lib/vrf.c index 02946df2bc9b..c300a87a3683 100644 --- a/lib/vrf.c +++ b/lib/vrf.c @@ -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. @@ -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, diff --git a/lib/vrf.h b/lib/vrf.h index 99c048c70253..f1dc45019469 100644 --- a/lib/vrf.h +++ b/lib/vrf.h @@ -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; @@ -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 diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c index 14905b738bf5..ef30c7830f5f 100644 --- a/zebra/if_netlink.c +++ b/zebra/if_netlink.c @@ -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)) { @@ -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]) @@ -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; } @@ -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]); diff --git a/zebra/main.c b/zebra/main.c index 19b16936d9e0..a881fcb9c6e5 100644 --- a/zebra/main.c +++ b/zebra/main.c @@ -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}}; @@ -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:" @@ -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) @@ -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': diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index a80ab9d83494..20abd7697374 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -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; @@ -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}; @@ -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)) @@ -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) @@ -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]); @@ -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. */ diff --git a/zebra/zebra_vrf.c b/zebra/zebra_vrf.c index cd47f212784c..6eec2c18c4d4 100644 --- a/zebra/zebra_vrf.c +++ b/zebra/zebra_vrf.c @@ -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"