]> git.puffer.fish Git - mirror/frr.git/commitdiff
zebra: add a runtime flag to enable vrf with netns
authorPhilippe Guibert <philippe.guibert@6wind.com>
Mon, 22 Jan 2018 08:42:53 +0000 (09:42 +0100)
committerPhilippe Guibert <philippe.guibert@6wind.com>
Tue, 27 Feb 2018 10:10:41 +0000 (11:10 +0100)
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>
lib/ns.c
lib/vrf.c
lib/vrf.h
zebra/if_netlink.c
zebra/main.c
zebra/rt_netlink.c
zebra/zebra_vrf.c

index 0b2a3bec78d42d18f8da949623b4f8cf9c505434..e3a1d9d0dc3e497fc6061760b1fdbbf039dc9fa1 100644 (file)
--- 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);
index 02946df2bc9b6cd82eae4f93c6a4fae4c92d20e2..c300a87a3683e8d2ee530357f270a4d5be17636f 100644 (file)
--- 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,
index 99c048c7025361987d7ab700fb05d0a2dff2b740..f1dc450194696bdbb7cf3ba01add1e08d7dd1436 100644 (file)
--- 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
index 14905b738bf537929eb5ebb1944472dabd19b833..ef30c7830f5f1fc2dcd083a23334226c7f714244 100644 (file)
@@ -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]);
index 19b16936d9e08900f00351249b8f5dc2eac4f568..a881fcb9c6e50e8831f2f2a00082f7beb7346045 100644 (file)
@@ -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':
index a80ab9d83494305679108440afb9ca09d6389bab..20abd7697374b66ad4d6e53a8364f2148982f5c9 100644 (file)
@@ -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. */
index cd47f212784c58ae33b2db0d57347d4d87d78319..6eec2c18c4d4148f552b4949298b1bf442a46906 100644 (file)
@@ -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"