]> git.puffer.fish Git - mirror/frr.git/commitdiff
bgpd: bgp support for netns
authorPhilippe Guibert <philippe.guibert@6wind.com>
Wed, 20 Dec 2017 11:37:18 +0000 (12:37 +0100)
committerPhilippe Guibert <philippe.guibert@6wind.com>
Tue, 27 Feb 2018 10:11:24 +0000 (11:11 +0100)
The change contained in this commit does the following:
- discovery of vrf id from zebra daemon, and adaptation of bgp contexts
  with BGP.
  The list of network addresses contain a reference to the bgp context
  supporting the vrf.
  The bgp context contains a vrf pointer that gives information about
  the netns path in case the vrf is a netns path.

Only some contexts are impacted, namely socket creation, and retrieval
of local IP settings. ( this requires vrf identifier).

Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
bgpd/bgp_fsm.c
bgpd/bgp_main.c
bgpd/bgp_network.c
bgpd/bgp_network.h
bgpd/bgpd.c

index de453de0c82676328a60e024931f34ae66fdfcf3..79f4b1c91a93f4c203f150ec3a46534dc0705f84 100644 (file)
@@ -1376,6 +1376,15 @@ int bgp_start(struct peer *peer)
                return 0;
        }
 
+       if (peer->bgp &&
+           peer->bgp->vrf_id == VRF_UNKNOWN) {
+               if (bgp_debug_neighbor_events(peer))
+                       zlog_err(
+                                "%s [FSM] In a VRF that is not initialised yet",
+                                peer->host);
+               return -1;
+       }
+
        /* Register to be notified on peer up */
        if (peer->sort == BGP_PEER_EBGP && peer->ttl == 1
            && !CHECK_FLAG(peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK)
index 0508f4846de40d5933d3cbe3ecb7984399c8e74a..b5448b694e064c35af21820ed8d7d0686de16d60 100644 (file)
@@ -41,6 +41,7 @@
 #include "vrf.h"
 #include "bfd.h"
 #include "libfrr.h"
+#include "ns.h"
 
 #include "bgpd/bgpd.h"
 #include "bgpd/bgp_attr.h"
@@ -57,6 +58,7 @@
 #include "bgpd/bgp_zebra.h"
 #include "bgpd/bgp_packet.h"
 #include "bgpd/bgp_keepalives.h"
+#include "bgpd/bgp_network.h"
 
 #ifdef ENABLE_BGP_VNC
 #include "bgpd/rfapi/rfapi_backend.h"
@@ -297,6 +299,7 @@ static int bgp_vrf_disable(struct vrf *vrf)
 
 static void bgp_vrf_init(void)
 {
+       ns_init();
        vrf_init(bgp_vrf_new, bgp_vrf_enable, bgp_vrf_disable, bgp_vrf_delete);
 }
 
index bf39cbe1fcf90fb47dc4023450a625a418349363..e3cca639055723054672dd68ed0f8fd2bb03bd3d 100644 (file)
@@ -34,6 +34,7 @@
 #include "queue.h"
 #include "hash.h"
 #include "filter.h"
+#include "ns.h"
 
 #include "bgpd/bgpd.h"
 #include "bgpd/bgp_open.h"
@@ -51,6 +52,7 @@ struct bgp_listener {
        int fd;
        union sockunion su;
        struct thread *thread;
+       struct bgp *bgp;
 };
 
 /*
@@ -284,6 +286,7 @@ static int bgp_accept(struct thread *thread)
                return -1;
        }
        listener->thread = NULL;
+
        thread_add_read(bm->master, bgp_accept, listener, accept_sock,
                        &listener->thread);
 
@@ -296,8 +299,13 @@ static int bgp_accept(struct thread *thread)
        }
        set_nonblocking(bgp_sock);
 
-       /* Obtain BGP instance this connection is meant for. */
-       if (bgp_get_instance_for_inc_conn(bgp_sock, &bgp)) {
+       /* Obtain BGP instance this connection is meant for.
+        * - if it is a VRF netns sock, then BGP is in listener structure
+        * - otherwise, the bgp instance need to be demultiplexed
+        */
+       if (listener->bgp)
+               bgp = listener->bgp;
+       else if (bgp_get_instance_for_inc_conn(bgp_sock, &bgp)) {
                if (bgp_debug_neighbor_events(NULL))
                        zlog_debug(
                                "[Event] Could not get instance for incoming conn from %s",
@@ -442,10 +450,12 @@ static int bgp_bind(struct peer *peer)
        int myerrno;
        char *name = NULL;
 
-       /* If not bound to an interface or part of a VRF, we don't care. */
-       if (!peer->bgp->vrf_id && !peer->ifname && !peer->conf_if)
+       /* If not bound to an interface or part of a VRF lite, we don't care. */
+       if ((peer->bgp->vrf_id == VRF_DEFAULT) &&
+           !peer->ifname && !peer->conf_if)
+               return 0;
+       if (vrf_is_mapped_on_netns(peer->bgp->vrf_id))
                return 0;
-
        if (peer->su.sa.sa_family != AF_INET
            && peer->su.sa.sa_family != AF_INET6)
                return 0; // unexpected
@@ -558,8 +568,12 @@ int bgp_connect(struct peer *peer)
                zlog_debug("Peer address not learnt: Returning from connect");
                return 0;
        }
+       if (bgpd_privs.change(ZPRIVS_RAISE))
+               zlog_err("Can't raise privileges");
        /* Make socket for the peer. */
-       peer->fd = sockunion_socket(&peer->su);
+       peer->fd = vrf_sockunion_socket(&peer->su, peer->bgp->vrf_id);
+       if (bgpd_privs.change(ZPRIVS_LOWER))
+               zlog_err("Can't lower privileges");
        if (peer->fd < 0)
                return -1;
 
@@ -642,12 +656,12 @@ int bgp_getsockname(struct peer *peer)
                return -1;
 #endif
        }
-
        return 0;
 }
 
 
-static int bgp_listener(int sock, struct sockaddr *sa, socklen_t salen)
+static int bgp_listener(int sock, struct sockaddr *sa, socklen_t salen,
+                       struct bgp *bgp)
 {
        struct bgp_listener *listener;
        int ret, en;
@@ -683,8 +697,14 @@ static int bgp_listener(int sock, struct sockaddr *sa, socklen_t salen)
                return ret;
        }
 
-       listener = XMALLOC(MTYPE_BGP_LISTENER, sizeof(*listener));
+       listener = XCALLOC(MTYPE_BGP_LISTENER, sizeof(*listener));
        listener->fd = sock;
+
+       /* this socket needs a change of ns. record bgp back pointer */
+       if (bgp->vrf_id != VRF_DEFAULT &&
+           vrf_is_mapped_on_netns(bgp->vrf_id))
+               listener->bgp = bgp;
+
        memcpy(&listener->su, sa, salen);
        listener->thread = NULL;
        thread_add_read(bm->master, bgp_accept, listener, sock,
@@ -695,7 +715,7 @@ static int bgp_listener(int sock, struct sockaddr *sa, socklen_t salen)
 }
 
 /* IPv6 supported version of BGP server socket setup.  */
-int bgp_socket(unsigned short port, const char *address)
+int bgp_socket(struct bgp *bgp, unsigned short port, const char *address)
 {
        struct addrinfo *ainfo;
        struct addrinfo *ainfo_save;
@@ -710,7 +730,12 @@ int bgp_socket(unsigned short port, const char *address)
        snprintf(port_str, sizeof(port_str), "%d", port);
        port_str[sizeof(port_str) - 1] = '\0';
 
-       ret = getaddrinfo(address, port_str, &req, &ainfo_save);
+       if (bgpd_privs.change(ZPRIVS_RAISE))
+               zlog_err("Can't raise privileges");
+       ret = vrf_getaddrinfo(address, port_str, &req,
+                             &ainfo_save, bgp->vrf_id);
+       if (bgpd_privs.change(ZPRIVS_LOWER))
+               zlog_err("Can't lower privileges");
        if (ret != 0) {
                zlog_err("getaddrinfo: %s", gai_strerror(ret));
                return -1;
@@ -723,8 +748,12 @@ int bgp_socket(unsigned short port, const char *address)
                if (ainfo->ai_family != AF_INET && ainfo->ai_family != AF_INET6)
                        continue;
 
-               sock = socket(ainfo->ai_family, ainfo->ai_socktype,
-                             ainfo->ai_protocol);
+               if (bgpd_privs.change(ZPRIVS_RAISE))
+                       zlog_err("Can't raise privileges");
+               sock = vrf_socket(ainfo->ai_family, ainfo->ai_socktype,
+                                 ainfo->ai_protocol, bgp->vrf_id);
+               if (bgpd_privs.change(ZPRIVS_LOWER))
+                       zlog_err("Can't lower privileges");
                if (sock < 0) {
                        zlog_err("socket: %s", safe_strerror(errno));
                        continue;
@@ -734,7 +763,8 @@ int bgp_socket(unsigned short port, const char *address)
                 * ttl=255 */
                sockopt_ttl(ainfo->ai_family, sock, MAXTTL);
 
-               ret = bgp_listener(sock, ainfo->ai_addr, ainfo->ai_addrlen);
+               ret = bgp_listener(sock, ainfo->ai_addr,
+                                  ainfo->ai_addrlen, bgp);
                if (ret == 0)
                        ++count;
                else
index 75ff1305c24448f5455a2a1ce45efc6dd444cdd9..5691b73e2225309f74ef9ed7edbf795f4d6072bb 100644 (file)
@@ -23,7 +23,8 @@
 
 #define BGP_SOCKET_SNDBUF_SIZE 65536
 
-extern int bgp_socket(unsigned short, const char *);
+extern int bgp_socket(struct bgp *bgp, unsigned short port,
+                     const char *address);
 extern void bgp_close(void);
 extern int bgp_connect(struct peer *);
 extern int bgp_getsockname(struct peer *);
index 78e748fb6c5d2c5765af9ee67f6121f8b838c9ee..1d44eb76cdbffbbd7b802ad0b07f4da2fd7f340f 100644 (file)
@@ -3035,7 +3035,7 @@ int bgp_get(struct bgp **bgp_val, as_t *as, const char *name,
 
        /* Create BGP server socket, if first instance.  */
        if (list_isempty(bm->bgp) && !bgp_option_check(BGP_OPT_NO_LISTEN)) {
-               if (bgp_socket(bm->port, bm->address) < 0)
+               if (bgp_socket(bgp, bm->port, bm->address) < 0)
                        return BGP_ERR_INVALID_VALUE;
        }
 
@@ -3337,11 +3337,12 @@ struct peer *peer_lookup(struct bgp *bgp, union sockunion *su)
                struct listnode *bgpnode, *nbgpnode;
 
                for (ALL_LIST_ELEMENTS(bm->bgp, bgpnode, nbgpnode, bgp)) {
-                       /* Skip VRFs, this function will not be invoked without
-                        * an instance
+                       /* Skip VRFs Lite only, this function will not be
+                        * invoked without an instance
                         * when examining VRFs.
                         */
-                       if (bgp->inst_type == BGP_INSTANCE_TYPE_VRF)
+                       if ((bgp->inst_type == BGP_INSTANCE_TYPE_VRF) &&
+                           !vrf_is_mapped_on_netns(bgp->vrf_id))
                                continue;
 
                        peer = hash_lookup(bgp->peerhash, &tmp_peer);