]> git.proxmox.com Git - mirror_frr.git/commitdiff
Merge pull request #4112 from pguibert6WIND/bfd_vrf
authorRafael Zalamena <rzalamena@users.noreply.github.com>
Tue, 14 May 2019 13:24:56 +0000 (10:24 -0300)
committerGitHub <noreply@github.com>
Tue, 14 May 2019 13:24:56 +0000 (10:24 -0300)
support for BFD VRF

52 files changed:
bfdd/bfd.c
bfdd/bfd.h
bfdd/bfd_packet.c
bfdd/bfdd.c
bfdd/bfdd_vty.c
bfdd/bsd.c [deleted file]
bfdd/config.c
bfdd/linux.c [deleted file]
bfdd/ptm_adapter.c
bfdd/subdir.am
bgpd/bgp_bfd.c
bgpd/bgp_zebra.c
doc/user/bfd.rst
isisd/isis_bfd.c
lib/bfd.c
lib/bfd.h
lib/vrf.c
ospf6d/ospf6_bfd.c
ospf6d/ospf6_zebra.c
ospfd/ospf_bfd.c
ospfd/ospf_zebra.c
pimd/pim_bfd.c
pimd/pim_zebra.c
tests/topotests/bfd-vrf-topo1/__init__.py [new file with mode: 0644]
tests/topotests/bfd-vrf-topo1/r1/bfdd.conf [new file with mode: 0644]
tests/topotests/bfd-vrf-topo1/r1/bgp_prefixes.json [new file with mode: 0644]
tests/topotests/bfd-vrf-topo1/r1/bgp_summary.json [new file with mode: 0644]
tests/topotests/bfd-vrf-topo1/r1/bgpd.conf [new file with mode: 0644]
tests/topotests/bfd-vrf-topo1/r1/peers.json [new file with mode: 0644]
tests/topotests/bfd-vrf-topo1/r1/zebra.conf [new file with mode: 0644]
tests/topotests/bfd-vrf-topo1/r2/bfdd.conf [new file with mode: 0644]
tests/topotests/bfd-vrf-topo1/r2/bgp_prefixes.json [new file with mode: 0644]
tests/topotests/bfd-vrf-topo1/r2/bgp_summary.json [new file with mode: 0644]
tests/topotests/bfd-vrf-topo1/r2/bgpd.conf [new file with mode: 0644]
tests/topotests/bfd-vrf-topo1/r2/peers.json [new file with mode: 0644]
tests/topotests/bfd-vrf-topo1/r2/zebra.conf [new file with mode: 0644]
tests/topotests/bfd-vrf-topo1/r3/bfdd.conf [new file with mode: 0644]
tests/topotests/bfd-vrf-topo1/r3/bgp_prefixes.json [new file with mode: 0644]
tests/topotests/bfd-vrf-topo1/r3/bgp_summary.json [new file with mode: 0644]
tests/topotests/bfd-vrf-topo1/r3/bgpd.conf [new file with mode: 0644]
tests/topotests/bfd-vrf-topo1/r3/peers.json [new file with mode: 0644]
tests/topotests/bfd-vrf-topo1/r3/zebra.conf [new file with mode: 0644]
tests/topotests/bfd-vrf-topo1/r4/bfdd.conf [new file with mode: 0644]
tests/topotests/bfd-vrf-topo1/r4/bgp_prefixes.json [new file with mode: 0644]
tests/topotests/bfd-vrf-topo1/r4/bgp_summary.json [new file with mode: 0644]
tests/topotests/bfd-vrf-topo1/r4/bgpd.conf [new file with mode: 0644]
tests/topotests/bfd-vrf-topo1/r4/peers.json [new file with mode: 0644]
tests/topotests/bfd-vrf-topo1/r4/zebra.conf [new file with mode: 0644]
tests/topotests/bfd-vrf-topo1/test_bfd_vrf_topo1.dot [new file with mode: 0644]
tests/topotests/bfd-vrf-topo1/test_bfd_vrf_topo1.jpg [new file with mode: 0644]
tests/topotests/bfd-vrf-topo1/test_bfd_vrf_topo1.py [new file with mode: 0755]
zebra/zebra_ptm.c

index e9645824f283d406de816b9d113388e50a7cabf9..a2e84e928d15c4cdfa4131a55edea2f79876eced 100644 (file)
@@ -128,15 +128,8 @@ int bfd_session_enable(struct bfd_session *bs)
         * If the interface or VRF doesn't exist, then we must register
         * the session but delay its start.
         */
-       if (bs->key.ifname[0]) {
-               ifp = if_lookup_by_name_all_vrf(bs->key.ifname);
-               if (ifp == NULL) {
-                       log_error(
-                               "session-enable: specified interface doesn't exists.");
-                       return 0;
-               }
-
-               vrf = vrf_lookup_by_id(ifp->vrf_id);
+       if (bs->key.vrfname[0]) {
+               vrf = vrf_lookup_by_name(bs->key.vrfname);
                if (vrf == NULL) {
                        log_error(
                                "session-enable: specified VRF doesn't exists.");
@@ -144,13 +137,24 @@ int bfd_session_enable(struct bfd_session *bs)
                }
        }
 
-       if (bs->key.vrfname[0]) {
-               vrf = vrf_lookup_by_name(bs->key.vrfname);
-               if (vrf == NULL) {
+       if (bs->key.ifname[0]) {
+               if (vrf)
+                       ifp = if_lookup_by_name(bs->key.ifname, vrf->vrf_id);
+               else
+                       ifp = if_lookup_by_name_all_vrf(bs->key.ifname);
+               if (ifp == NULL) {
                        log_error(
-                               "session-enable: specified VRF doesn't exists.");
+                                 "session-enable: specified interface doesn't exists.");
                        return 0;
                }
+               if (bs->key.ifname[0] && !vrf) {
+                       vrf = vrf_lookup_by_id(ifp->vrf_id);
+                       if (vrf == NULL) {
+                               log_error(
+                                         "session-enable: specified VRF doesn't exists.");
+                               return 0;
+                       }
+               }
        }
 
        /* Assign interface/VRF pointers. */
@@ -164,7 +168,7 @@ int bfd_session_enable(struct bfd_session *bs)
 
        /* Sanity check: don't leak open sockets. */
        if (bs->sock != -1) {
-               zlog_debug("session-enable: previous socket open");
+               log_debug("session-enable: previous socket open");
                close(bs->sock);
                bs->sock = -1;
        }
@@ -291,7 +295,7 @@ void ptm_bfd_echo_start(struct bfd_session *bfd)
                ptm_bfd_echo_xmt_TO(bfd);
 }
 
-void ptm_bfd_ses_up(struct bfd_session *bfd)
+void ptm_bfd_sess_up(struct bfd_session *bfd)
 {
        int old_state = bfd->ses_state;
 
@@ -315,7 +319,7 @@ void ptm_bfd_ses_up(struct bfd_session *bfd)
        }
 }
 
-void ptm_bfd_ses_dn(struct bfd_session *bfd, uint8_t diag)
+void ptm_bfd_sess_dn(struct bfd_session *bfd, uint8_t diag)
 {
        int old_state = bfd->ses_state;
 
@@ -432,7 +436,7 @@ int bfd_recvtimer_cb(struct thread *t)
        switch (bs->ses_state) {
        case PTM_BFD_INIT:
        case PTM_BFD_UP:
-               ptm_bfd_ses_dn(bs, BD_CONTROL_EXPIRED);
+               ptm_bfd_sess_dn(bs, BD_CONTROL_EXPIRED);
                bfd_recvtimer_update(bs);
                break;
 
@@ -455,7 +459,7 @@ int bfd_echo_recvtimer_cb(struct thread *t)
        switch (bs->ses_state) {
        case PTM_BFD_INIT:
        case PTM_BFD_UP:
-               ptm_bfd_ses_dn(bs, BD_ECHO_FAILED);
+               ptm_bfd_sess_dn(bs, BD_ECHO_FAILED);
                break;
        }
 
@@ -725,7 +729,7 @@ struct bfd_session *ptm_bfd_sess_new(struct bfd_peer_cfg *bpc)
        return bfd;
 }
 
-int ptm_bfd_ses_del(struct bfd_peer_cfg *bpc)
+int ptm_bfd_sess_del(struct bfd_peer_cfg *bpc)
 {
        struct bfd_session *bs;
 
@@ -805,7 +809,7 @@ static void bs_down_handler(struct bfd_session *bs, int nstate)
                 * Remote peer told us his path is up, lets turn
                 * activate the session.
                 */
-               ptm_bfd_ses_up(bs);
+               ptm_bfd_sess_up(bs);
                break;
 
        default:
@@ -832,7 +836,7 @@ static void bs_init_handler(struct bfd_session *bs, int nstate)
        case PTM_BFD_INIT:
        case PTM_BFD_UP:
                /* We agreed on the settings and the path is up. */
-               ptm_bfd_ses_up(bs);
+               ptm_bfd_sess_up(bs);
                break;
 
        default:
@@ -847,7 +851,7 @@ static void bs_up_handler(struct bfd_session *bs, int nstate)
        case PTM_BFD_ADM_DOWN:
        case PTM_BFD_DOWN:
                /* Peer lost or asked to shutdown connection. */
-               ptm_bfd_ses_dn(bs, BD_NEIGHBOR_DOWN);
+               ptm_bfd_sess_dn(bs, BD_NEIGHBOR_DOWN);
                break;
 
        case PTM_BFD_INIT:
@@ -1197,10 +1201,6 @@ int bs_observer_add(struct bfd_session *bs)
        if (bso->bso_isinterface)
                strlcpy(bso->bso_entryname, bs->key.ifname,
                        sizeof(bso->bso_entryname));
-       else
-               strlcpy(bso->bso_entryname, bs->key.vrfname,
-                       sizeof(bso->bso_entryname));
-
        /* Handle socket binding failures caused by missing local addresses. */
        if (bs->sock == -1) {
                bso->bso_isaddress = true;
@@ -1322,32 +1322,105 @@ struct bfd_session *bfd_id_lookup(uint32_t id)
        return hash_lookup(bfd_id_hash, &bs);
 }
 
+struct bfd_key_walk_partial_lookup {
+       struct bfd_session *given;
+       struct bfd_session *result;
+};
+
+/* ignore some parameters */
+static int bfd_key_lookup_ignore_partial_walker(struct hash_bucket *b, void *data)
+{
+       struct bfd_key_walk_partial_lookup  *ctx =
+               (struct bfd_key_walk_partial_lookup *)data;
+       struct bfd_session *given = ctx->given;
+       struct bfd_session *parsed = b->data;
+
+       if (given->key.family != parsed->key.family)
+               return HASHWALK_CONTINUE;
+       if (given->key.mhop != parsed->key.mhop)
+               return HASHWALK_CONTINUE;
+       if (memcmp(&given->key.peer, &parsed->key.peer, sizeof(struct in6_addr)))
+               return HASHWALK_CONTINUE;
+       if (memcmp(given->key.vrfname, parsed->key.vrfname, MAXNAMELEN))
+               return HASHWALK_CONTINUE;
+       ctx->result = parsed;
+       /* ignore localaddr or interface */
+       return HASHWALK_ABORT;
+}
+
 struct bfd_session *bfd_key_lookup(struct bfd_key key)
 {
        struct bfd_session bs, *bsp;
+       struct bfd_key_walk_partial_lookup ctx;
+       char peer_buf[INET6_ADDRSTRLEN];
 
        bs.key = key;
        bsp = hash_lookup(bfd_key_hash, &bs);
+       if (bsp)
+               return bsp;
 
+       inet_ntop(bs.key.family, &bs.key.peer, peer_buf,
+                 sizeof(peer_buf));
        /* Handle cases where local-address is optional. */
-       if (bsp == NULL && bs.key.family == AF_INET) {
+       if (bs.key.family == AF_INET) {
                memset(&bs.key.local, 0, sizeof(bs.key.local));
                bsp = hash_lookup(bfd_key_hash, &bs);
+               if (bsp) {
+                       char addr_buf[INET6_ADDRSTRLEN];
+
+                       inet_ntop(bs.key.family, &key.local, addr_buf,
+                                 sizeof(addr_buf));
+                       log_debug(" peer %s found, but loc-addr %s ignored",
+                                 peer_buf, addr_buf);
+                       return bsp;
+               }
        }
 
-       /* Handle cases where ifname is optional. */
        bs.key = key;
-       if (bsp == NULL && bs.key.ifname[0]) {
+       /* Handle cases where ifname is optional. */
+       if (bs.key.ifname[0]) {
                memset(bs.key.ifname, 0, sizeof(bs.key.ifname));
                bsp = hash_lookup(bfd_key_hash, &bs);
+               if (bsp) {
+                       log_debug(" peer %s found, but ifp %s ignored",
+                                 peer_buf, key.ifname);
+                       return bsp;
+               }
+       }
 
-               /* Handle cases where local-address and ifname are optional. */
-               if (bsp == NULL && bs.key.family == AF_INET) {
-                       memset(&bs.key.local, 0, sizeof(bs.key.local));
-                       bsp = hash_lookup(bfd_key_hash, &bs);
+       /* Handle cases where local-address and ifname are optional. */
+       if (bs.key.family == AF_INET) {
+               memset(&bs.key.local, 0, sizeof(bs.key.local));
+               bsp = hash_lookup(bfd_key_hash, &bs);
+               if (bsp) {
+                       char addr_buf[INET6_ADDRSTRLEN];
+
+                       inet_ntop(bs.key.family, &bs.key.local, addr_buf,
+                                 sizeof(addr_buf));
+                       log_debug(" peer %s found, but ifp %s"
+                                 " and loc-addr %s ignored",
+                                 peer_buf, key.ifname,
+                                 addr_buf);
+                       return bsp;
                }
        }
+       bs.key = key;
 
+       /* Handle case where a context more complex ctx is present.
+        * input has no iface nor local-address, but a context may
+        * exist
+        */
+       ctx.result = NULL;
+       ctx.given = &bs;
+       hash_walk(bfd_key_hash,
+                 &bfd_key_lookup_ignore_partial_walker,
+                 &ctx);
+       /* change key */
+       if (ctx.result) {
+               bsp = ctx.result;
+               log_debug(" peer %s found, but ifp"
+                         " and/or loc-addr params ignored");
+       }
        return bsp;
 }
 
@@ -1443,3 +1516,125 @@ void bfd_shutdown(void)
        hash_free(bfd_id_hash);
        hash_free(bfd_key_hash);
 }
+
+static int bfd_vrf_new(struct vrf *vrf)
+{
+       log_debug("VRF Created: %s(%u)", vrf->name, vrf->vrf_id);
+       return 0;
+}
+
+static int bfd_vrf_delete(struct vrf *vrf)
+{
+       log_debug("VRF Deletion: %s(%u)", vrf->name, vrf->vrf_id);
+       return 0;
+}
+
+static int bfd_vrf_enable(struct vrf *vrf)
+{
+       struct bfd_vrf_global *bvrf;
+
+       /* a different name */
+       if (!vrf->info) {
+               bvrf = XCALLOC(MTYPE_BFDD_VRF, sizeof(struct bfd_vrf_global));
+               bvrf->vrf = vrf;
+               vrf->info = (void *)bvrf;
+       } else
+               bvrf = vrf->info;
+       log_debug("VRF enable add %s id %u", vrf->name, vrf->vrf_id);
+
+       /* create sockets if needed */
+       if (!bvrf->bg_shop)
+               bvrf->bg_shop = bp_udp_shop(vrf->vrf_id);
+       if (!bvrf->bg_mhop)
+               bvrf->bg_mhop = bp_udp_mhop(vrf->vrf_id);
+       if (!bvrf->bg_shop6)
+               bvrf->bg_shop6 = bp_udp6_shop(vrf->vrf_id);
+       if (!bvrf->bg_mhop6)
+               bvrf->bg_mhop6 = bp_udp6_mhop(vrf->vrf_id);
+       if (!bvrf->bg_echo)
+               bvrf->bg_echo = bp_echo_socket(vrf->vrf_id);
+       if (!bvrf->bg_echov6)
+               bvrf->bg_echov6 = bp_echov6_socket(vrf->vrf_id);
+
+       /* Add descriptors to the event loop. */
+       if (!bvrf->bg_ev[0])
+               thread_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_shop,
+                               &bvrf->bg_ev[0]);
+       if (!bvrf->bg_ev[1])
+               thread_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_mhop,
+                               &bvrf->bg_ev[1]);
+       if (!bvrf->bg_ev[2])
+               thread_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_shop6,
+                               &bvrf->bg_ev[2]);
+       if (!bvrf->bg_ev[3])
+               thread_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_mhop6,
+                               &bvrf->bg_ev[3]);
+       if (!bvrf->bg_ev[4])
+               thread_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_echo,
+                               &bvrf->bg_ev[4]);
+       if (!bvrf->bg_ev[5])
+               thread_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_echov6,
+                               &bvrf->bg_ev[5]);
+
+       if (vrf->vrf_id != VRF_DEFAULT) {
+               bfdd_zclient_register(vrf->vrf_id);
+               bfdd_sessions_enable_vrf(vrf);
+       }
+       return 0;
+}
+
+static int bfd_vrf_disable(struct vrf *vrf)
+{
+       struct bfd_vrf_global *bvrf;
+
+       if (!vrf->info)
+               return 0;
+       bvrf = vrf->info;
+
+       if (vrf->vrf_id != VRF_DEFAULT) {
+               bfdd_sessions_disable_vrf(vrf);
+               bfdd_zclient_unregister(vrf->vrf_id);
+       }
+
+       log_debug("VRF disable %s id %d", vrf->name, vrf->vrf_id);
+       /* Close all descriptors. */
+       socket_close(&bvrf->bg_echo);
+       socket_close(&bvrf->bg_shop);
+       socket_close(&bvrf->bg_mhop);
+       socket_close(&bvrf->bg_shop6);
+       socket_close(&bvrf->bg_mhop6);
+
+       /* free context */
+       XFREE(MTYPE_BFDD_VRF, bvrf);
+       vrf->info = NULL;
+
+       return 0;
+}
+
+void bfd_vrf_init(void)
+{
+       vrf_init(bfd_vrf_new, bfd_vrf_enable, bfd_vrf_disable,
+                bfd_vrf_delete, NULL);
+}
+
+void bfd_vrf_terminate(void)
+{
+       vrf_terminate();
+}
+
+struct bfd_vrf_global *bfd_vrf_look_by_session(struct bfd_session *bfd)
+{
+       struct vrf *vrf;
+
+       if (!vrf_is_backend_netns()) {
+               vrf = vrf_lookup_by_id(VRF_DEFAULT);
+               if (vrf)
+                       return (struct bfd_vrf_global *)vrf->info;
+               return NULL;
+       }
+       if (!bfd)
+               return NULL;
+       if (!bfd->vrf)
+               return NULL;
+       return bfd->vrf->info;
+}
index e08a1ff724e8bec4ec5bafde7a3dd4b432b0a39f..3f3d60383248127272ded2bf08ac1640f06fd238 100644 (file)
@@ -48,6 +48,7 @@ DECLARE_MTYPE(BFDD_LABEL);
 DECLARE_MTYPE(BFDD_CONTROL);
 DECLARE_MTYPE(BFDD_SESSION_OBSERVER);
 DECLARE_MTYPE(BFDD_NOTIFICATION);
+DECLARE_MTYPE(BFDD_VRF);
 
 struct bfd_timers {
        uint32_t desired_min_tx;
@@ -379,15 +380,19 @@ int control_accept(struct thread *t);
  *
  * Daemon specific code.
  */
-struct bfd_global {
+struct bfd_vrf_global {
        int bg_shop;
        int bg_mhop;
        int bg_shop6;
        int bg_mhop6;
        int bg_echo;
        int bg_echov6;
+       struct vrf *vrf;
+
        struct thread *bg_ev[6];
+};
 
+struct bfd_global {
        int bg_csock;
        struct thread *bg_csockev;
        struct bcslist bg_bcslist;
@@ -395,6 +400,8 @@ struct bfd_global {
        struct pllist bg_pllist;
 
        struct obslist bg_obslist;
+
+       struct zebra_privs_t bfdd_privs;
 };
 extern struct bfd_global bglobal;
 extern struct bfd_diag_str_list diag_list[];
@@ -459,14 +466,14 @@ int bp_set_tosv6(int sd, uint8_t value);
 int bp_set_tos(int sd, uint8_t value);
 int bp_bind_dev(int sd, const char *dev);
 
-int bp_udp_shop(void);
-int bp_udp_mhop(void);
-int bp_udp6_shop(void);
-int bp_udp6_mhop(void);
+int bp_udp_shop(vrf_id_t vrf_id);
+int bp_udp_mhop(vrf_id_t vrf_id);
+int bp_udp6_shop(vrf_id_t vrf_id);
+int bp_udp6_mhop(vrf_id_t vrf_id);
 int bp_peer_socket(const struct bfd_session *bs);
 int bp_peer_socketv6(const struct bfd_session *bs);
-int bp_echo_socket(void);
-int bp_echov6_socket(void);
+int bp_echo_socket(vrf_id_t vrf_id);
+int bp_echov6_socket(vrf_id_t vrf_id);
 
 void ptm_bfd_snd(struct bfd_session *bfd, int fbit);
 void ptm_bfd_echo_snd(struct bfd_session *bfd);
@@ -505,9 +512,9 @@ void bfd_echo_xmttimer_assign(struct bfd_session *bs, bfd_ev_cb cb);
 int bfd_session_enable(struct bfd_session *bs);
 void bfd_session_disable(struct bfd_session *bs);
 struct bfd_session *ptm_bfd_sess_new(struct bfd_peer_cfg *bpc);
-int ptm_bfd_ses_del(struct bfd_peer_cfg *bpc);
-void ptm_bfd_ses_dn(struct bfd_session *bfd, uint8_t diag);
-void ptm_bfd_ses_up(struct bfd_session *bfd);
+int ptm_bfd_sess_del(struct bfd_peer_cfg *bpc);
+void ptm_bfd_sess_dn(struct bfd_session *bfd, uint8_t diag);
+void ptm_bfd_sess_up(struct bfd_session *bfd);
 void ptm_bfd_echo_stop(struct bfd_session *bfd);
 void ptm_bfd_echo_start(struct bfd_session *bfd);
 void ptm_bfd_xmt_TO(struct bfd_session *bfd, int fbit);
@@ -539,6 +546,9 @@ void bs_to_bpc(struct bfd_session *bs, struct bfd_peer_cfg *bpc);
 /* BFD hash data structures interface */
 void bfd_initialize(void);
 void bfd_shutdown(void);
+void bfd_vrf_init(void);
+void bfd_vrf_terminate(void);
+struct bfd_vrf_global *bfd_vrf_look_by_session(struct bfd_session *bfd);
 struct bfd_session *bfd_id_lookup(uint32_t id);
 struct bfd_session *bfd_key_lookup(struct bfd_key key);
 
@@ -576,6 +586,10 @@ void bfdd_vty_init(void);
  */
 void bfdd_zclient_init(struct zebra_privs_t *bfdd_priv);
 void bfdd_zclient_stop(void);
+void bfdd_zclient_unregister(vrf_id_t vrf_id);
+void bfdd_zclient_register(vrf_id_t vrf_id);
+void bfdd_sessions_enable_vrf(struct vrf *vrf);
+void bfdd_sessions_disable_vrf(struct vrf *vrf);
 
 int ptm_bfd_notify(struct bfd_session *bs);
 
index 93677ec85aceeb7709385a07c652682b843d73aa..8edba05d126d6a531dc1cc502cc4953071733eb3 100644 (file)
 
 #include "bfd.h"
 
-
 /*
  * Prototypes
  */
-static int ptm_bfd_process_echo_pkt(int s);
+static int ptm_bfd_process_echo_pkt(struct bfd_vrf_global *bvrf, int s);
 int _ptm_bfd_send(struct bfd_session *bs, uint16_t *port, const void *data,
                  size_t datalen);
 
-static void bfd_sd_reschedule(int sd);
+static void bfd_sd_reschedule(struct bfd_vrf_global *bvrf, int sd);
 ssize_t bfd_recv_ipv4(int sd, uint8_t *msgbuf, size_t msgbuflen, uint8_t *ttl,
                      ifindex_t *ifindex, struct sockaddr_any *local,
                      struct sockaddr_any *peer);
@@ -54,7 +53,8 @@ ssize_t bfd_recv_ipv6(int sd, uint8_t *msgbuf, size_t msgbuflen, uint8_t *ttl,
                      struct sockaddr_any *peer);
 int bp_udp_send(int sd, uint8_t ttl, uint8_t *data, size_t datalen,
                struct sockaddr *to, socklen_t tolen);
-int bp_bfd_echo_in(int sd, uint8_t *ttl, uint32_t *my_discr);
+int bp_bfd_echo_in(struct bfd_vrf_global *bvrf, int sd,
+                  uint8_t *ttl, uint32_t *my_discr);
 
 /* socket related prototypes */
 static void bp_set_ipopts(int sd);
@@ -129,7 +129,10 @@ void ptm_bfd_echo_snd(struct bfd_session *bfd)
        struct bfd_echo_pkt bep;
        struct sockaddr_in sin;
        struct sockaddr_in6 sin6;
+       struct bfd_vrf_global *bvrf = bfd_vrf_look_by_session(bfd);
 
+       if (!bvrf)
+               return;
        if (!BFD_CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_ECHO_ACTIVE))
                BFD_SET_FLAG(bfd->flags, BFD_SESS_FLAG_ECHO_ACTIVE);
 
@@ -139,7 +142,7 @@ void ptm_bfd_echo_snd(struct bfd_session *bfd)
        bep.my_discr = htonl(bfd->discrs.my_discr);
 
        if (BFD_CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_IPV6)) {
-               sd = bglobal.bg_echov6;
+               sd = bvrf->bg_echov6;
                memset(&sin6, 0, sizeof(sin6));
                sin6.sin6_family = AF_INET6;
                memcpy(&sin6.sin6_addr, &bfd->key.peer, sizeof(sin6.sin6_addr));
@@ -154,7 +157,7 @@ void ptm_bfd_echo_snd(struct bfd_session *bfd)
                sa = (struct sockaddr *)&sin6;
                salen = sizeof(sin6);
        } else {
-               sd = bglobal.bg_echo;
+               sd = bvrf->bg_echo;
                memset(&sin6, 0, sizeof(sin6));
                sin.sin_family = AF_INET;
                memcpy(&sin.sin_addr, &bfd->key.peer, sizeof(sin.sin_addr));
@@ -174,14 +177,14 @@ void ptm_bfd_echo_snd(struct bfd_session *bfd)
        bfd->stats.tx_echo_pkt++;
 }
 
-static int ptm_bfd_process_echo_pkt(int s)
+static int ptm_bfd_process_echo_pkt(struct bfd_vrf_global *bvrf, int s)
 {
        struct bfd_session *bfd;
        uint32_t my_discr = 0;
        uint8_t ttl = 0;
 
        /* Receive and parse echo packet. */
-       if (bp_bfd_echo_in(s, &ttl, &my_discr) == -1)
+       if (bp_bfd_echo_in(bvrf, s, &ttl, &my_discr) == -1)
                return 0;
 
        /* Your discriminator not zero - use it to find session */
@@ -441,32 +444,32 @@ ssize_t bfd_recv_ipv6(int sd, uint8_t *msgbuf, size_t msgbuflen, uint8_t *ttl,
        return mlen;
 }
 
-static void bfd_sd_reschedule(int sd)
+static void bfd_sd_reschedule(struct bfd_vrf_global *bvrf, int sd)
 {
-       if (sd == bglobal.bg_shop) {
-               THREAD_OFF(bglobal.bg_ev[0]);
-               thread_add_read(master, bfd_recv_cb, NULL, bglobal.bg_shop,
-                               &bglobal.bg_ev[0]);
-       } else if (sd == bglobal.bg_mhop) {
-               THREAD_OFF(bglobal.bg_ev[1]);
-               thread_add_read(master, bfd_recv_cb, NULL, bglobal.bg_mhop,
-                               &bglobal.bg_ev[1]);
-       } else if (sd == bglobal.bg_shop6) {
-               THREAD_OFF(bglobal.bg_ev[2]);
-               thread_add_read(master, bfd_recv_cb, NULL, bglobal.bg_shop6,
-                               &bglobal.bg_ev[2]);
-       } else if (sd == bglobal.bg_mhop6) {
-               THREAD_OFF(bglobal.bg_ev[3]);
-               thread_add_read(master, bfd_recv_cb, NULL, bglobal.bg_mhop6,
-                               &bglobal.bg_ev[3]);
-       } else if (sd == bglobal.bg_echo) {
-               THREAD_OFF(bglobal.bg_ev[4]);
-               thread_add_read(master, bfd_recv_cb, NULL, bglobal.bg_echo,
-                               &bglobal.bg_ev[4]);
-       } else if (sd == bglobal.bg_echov6) {
-               THREAD_OFF(bglobal.bg_ev[5]);
-               thread_add_read(master, bfd_recv_cb, NULL, bglobal.bg_echov6,
-                               &bglobal.bg_ev[5]);
+       if (sd == bvrf->bg_shop) {
+               THREAD_OFF(bvrf->bg_ev[0]);
+               thread_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_shop,
+                               &bvrf->bg_ev[0]);
+       } else if (sd == bvrf->bg_mhop) {
+               THREAD_OFF(bvrf->bg_ev[1]);
+               thread_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_mhop,
+                               &bvrf->bg_ev[1]);
+       } else if (sd == bvrf->bg_shop6) {
+               THREAD_OFF(bvrf->bg_ev[2]);
+               thread_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_shop6,
+                               &bvrf->bg_ev[2]);
+       } else if (sd == bvrf->bg_mhop6) {
+               THREAD_OFF(bvrf->bg_ev[3]);
+               thread_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_mhop6,
+                               &bvrf->bg_ev[3]);
+       } else if (sd == bvrf->bg_echo) {
+               THREAD_OFF(bvrf->bg_ev[4]);
+               thread_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_echo,
+                               &bvrf->bg_ev[4]);
+       } else if (sd == bvrf->bg_echov6) {
+               THREAD_OFF(bvrf->bg_ev[5]);
+               thread_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_echov6,
+                               &bvrf->bg_ev[5]);
        }
 }
 
@@ -518,13 +521,16 @@ int bfd_recv_cb(struct thread *t)
        ifindex_t ifindex = IFINDEX_INTERNAL;
        struct sockaddr_any local, peer;
        uint8_t msgbuf[1516];
+       struct bfd_vrf_global *bvrf = THREAD_ARG(t);
 
+       if (bvrf)
+               vrfid = bvrf->vrf->vrf_id;
        /* Schedule next read. */
-       bfd_sd_reschedule(sd);
+       bfd_sd_reschedule(bvrf, sd);
 
        /* Handle echo packets. */
-       if (sd == bglobal.bg_echo || sd == bglobal.bg_echov6) {
-               ptm_bfd_process_echo_pkt(sd);
+       if (sd == bvrf->bg_echo || sd == bvrf->bg_echov6) {
+               ptm_bfd_process_echo_pkt(bvrf, sd);
                return 0;
        }
 
@@ -534,12 +540,12 @@ int bfd_recv_cb(struct thread *t)
 
        /* Handle control packets. */
        is_mhop = false;
-       if (sd == bglobal.bg_shop || sd == bglobal.bg_mhop) {
-               is_mhop = sd == bglobal.bg_mhop;
+       if (sd == bvrf->bg_shop || sd == bvrf->bg_mhop) {
+               is_mhop = sd == bvrf->bg_mhop;
                mlen = bfd_recv_ipv4(sd, msgbuf, sizeof(msgbuf), &ttl, &ifindex,
                                     &local, &peer);
-       } else if (sd == bglobal.bg_shop6 || sd == bglobal.bg_mhop6) {
-               is_mhop = sd == bglobal.bg_mhop6;
+       } else if (sd == bvrf->bg_shop6 || sd == bvrf->bg_mhop6) {
+               is_mhop = sd == bvrf->bg_mhop6;
                mlen = bfd_recv_ipv6(sd, msgbuf, sizeof(msgbuf), &ttl, &ifindex,
                                     &local, &peer);
        }
@@ -682,7 +688,8 @@ int bfd_recv_cb(struct thread *t)
  *
  * Returns -1 on error or loopback or 0 on success.
  */
-int bp_bfd_echo_in(int sd, uint8_t *ttl, uint32_t *my_discr)
+int bp_bfd_echo_in(struct bfd_vrf_global *bvrf, int sd,
+                  uint8_t *ttl, uint32_t *my_discr)
 {
        struct bfd_echo_pkt *bep;
        ssize_t rlen;
@@ -691,7 +698,7 @@ int bp_bfd_echo_in(int sd, uint8_t *ttl, uint32_t *my_discr)
        vrf_id_t vrfid = VRF_DEFAULT;
        uint8_t msgbuf[1516];
 
-       if (sd == bglobal.bg_echo)
+       if (sd == bvrf->bg_echo)
                rlen = bfd_recv_ipv4(sd, msgbuf, sizeof(msgbuf), ttl, &ifindex,
                                     &local, &peer);
        else
@@ -709,7 +716,7 @@ int bp_bfd_echo_in(int sd, uint8_t *ttl, uint32_t *my_discr)
        if (*ttl == BFD_TTL_VAL) {
                bp_udp_send(sd, *ttl - 1, msgbuf, rlen,
                            (struct sockaddr *)&peer,
-                           (sd == bglobal.bg_echo) ? sizeof(peer.sa_sin)
+                           (sd == bvrf->bg_echo) ? sizeof(peer.sa_sin)
                                                    : sizeof(peer.sa_sin6));
                return -1;
        }
@@ -872,25 +879,28 @@ static void bp_bind_ip(int sd, uint16_t port)
                log_fatal("bind-ip: bind: %s", strerror(errno));
 }
 
-int bp_udp_shop(void)
+int bp_udp_shop(vrf_id_t vrf_id)
 {
        int sd;
 
-       sd = socket(AF_INET, SOCK_DGRAM, PF_UNSPEC);
+       frr_elevate_privs(&bglobal.bfdd_privs) {
+               sd = vrf_socket(AF_INET, SOCK_DGRAM, PF_UNSPEC, vrf_id, NULL);
+       }
        if (sd == -1)
                log_fatal("udp-shop: socket: %s", strerror(errno));
 
        bp_set_ipopts(sd);
        bp_bind_ip(sd, BFD_DEFDESTPORT);
-
        return sd;
 }
 
-int bp_udp_mhop(void)
+int bp_udp_mhop(vrf_id_t vrf_id)
 {
        int sd;
 
-       sd = socket(AF_INET, SOCK_DGRAM, PF_UNSPEC);
+       frr_elevate_privs(&bglobal.bfdd_privs) {
+               sd = vrf_socket(AF_INET, SOCK_DGRAM, PF_UNSPEC, vrf_id, NULL);
+       }
        if (sd == -1)
                log_fatal("udp-mhop: socket: %s", strerror(errno));
 
@@ -905,8 +915,18 @@ int bp_peer_socket(const struct bfd_session *bs)
        int sd, pcount;
        struct sockaddr_in sin;
        static int srcPort = BFD_SRCPORTINIT;
+       const char *device_to_bind = NULL;
+
+       if (bs->key.ifname[0])
+               device_to_bind = (const char *)bs->key.ifname;
+       else if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)
+           && bs->key.vrfname[0])
+               device_to_bind = (const char *)bs->key.vrfname;
 
-       sd = socket(AF_INET, SOCK_DGRAM, PF_UNSPEC);
+       frr_elevate_privs(&bglobal.bfdd_privs) {
+               sd = vrf_socket(AF_INET, SOCK_DGRAM, PF_UNSPEC,
+                               bs->vrf->vrf_id, device_to_bind);
+       }
        if (sd == -1) {
                log_error("ipv4-new: failed to create socket: %s",
                          strerror(errno));
@@ -925,19 +945,6 @@ int bp_peer_socket(const struct bfd_session *bs)
                return -1;
        }
 
-       if (bs->key.ifname[0]) {
-               if (bp_bind_dev(sd, bs->key.ifname) != 0) {
-                       close(sd);
-                       return -1;
-               }
-       } else if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)
-                  && bs->key.vrfname[0]) {
-               if (bp_bind_dev(sd, bs->key.vrfname) != 0) {
-                       close(sd);
-                       return -1;
-               }
-       }
-
        /* Find an available source port in the proper range */
        memset(&sin, 0, sizeof(sin));
        sin.sin_family = AF_INET;
@@ -975,8 +982,18 @@ int bp_peer_socketv6(const struct bfd_session *bs)
        int sd, pcount;
        struct sockaddr_in6 sin6;
        static int srcPort = BFD_SRCPORTINIT;
+       const char *device_to_bind = NULL;
 
-       sd = socket(AF_INET6, SOCK_DGRAM, PF_UNSPEC);
+       if (bs->key.ifname[0])
+               device_to_bind = (const char *)bs->key.ifname;
+       else if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)
+           && bs->key.vrfname[0])
+               device_to_bind = (const char *)bs->key.vrfname;
+
+       frr_elevate_privs(&bglobal.bfdd_privs) {
+               sd = vrf_socket(AF_INET6, SOCK_DGRAM, PF_UNSPEC,
+                               bs->vrf->vrf_id, device_to_bind);
+       }
        if (sd == -1) {
                log_error("ipv6-new: failed to create socket: %s",
                          strerror(errno));
@@ -1005,19 +1022,6 @@ int bp_peer_socketv6(const struct bfd_session *bs)
        if (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr))
                sin6.sin6_scope_id = bs->ifp->ifindex;
 
-       if (bs->key.ifname[0]) {
-               if (bp_bind_dev(sd, bs->key.ifname) != 0) {
-                       close(sd);
-                       return -1;
-               }
-       } else if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)
-                  && bs->key.vrfname[0]) {
-               if (bp_bind_dev(sd, bs->key.vrfname) != 0) {
-                       close(sd);
-                       return -1;
-               }
-       }
-
        pcount = 0;
        do {
                if ((++pcount) > (BFD_SRCPORTMAX - BFD_SRCPORTINIT)) {
@@ -1102,11 +1106,13 @@ static void bp_bind_ipv6(int sd, uint16_t port)
                log_fatal("bind-ipv6: bind: %s", strerror(errno));
 }
 
-int bp_udp6_shop(void)
+int bp_udp6_shop(vrf_id_t vrf_id)
 {
        int sd;
 
-       sd = socket(AF_INET6, SOCK_DGRAM, PF_UNSPEC);
+       frr_elevate_privs(&bglobal.bfdd_privs) {
+               sd = vrf_socket(AF_INET6, SOCK_DGRAM, PF_UNSPEC, vrf_id, NULL);
+       }
        if (sd == -1)
                log_fatal("udp6-shop: socket: %s", strerror(errno));
 
@@ -1116,11 +1122,13 @@ int bp_udp6_shop(void)
        return sd;
 }
 
-int bp_udp6_mhop(void)
+int bp_udp6_mhop(vrf_id_t vrf_id)
 {
        int sd;
 
-       sd = socket(AF_INET6, SOCK_DGRAM, PF_UNSPEC);
+       frr_elevate_privs(&bglobal.bfdd_privs) {
+               sd = vrf_socket(AF_INET6, SOCK_DGRAM, PF_UNSPEC, vrf_id, NULL);
+       }
        if (sd == -1)
                log_fatal("udp6-mhop: socket: %s", strerror(errno));
 
@@ -1130,11 +1138,13 @@ int bp_udp6_mhop(void)
        return sd;
 }
 
-int bp_echo_socket(void)
+int bp_echo_socket(vrf_id_t vrf_id)
 {
        int s;
 
-       s = socket(AF_INET, SOCK_DGRAM, 0);
+       frr_elevate_privs(&bglobal.bfdd_privs) {
+               s = vrf_socket(AF_INET, SOCK_DGRAM, 0, vrf_id, NULL);
+       }
        if (s == -1)
                log_fatal("echo-socket: socket: %s", strerror(errno));
 
@@ -1144,11 +1154,13 @@ int bp_echo_socket(void)
        return s;
 }
 
-int bp_echov6_socket(void)
+int bp_echov6_socket(vrf_id_t vrf_id)
 {
        int s;
 
-       s = socket(AF_INET6, SOCK_DGRAM, 0);
+       frr_elevate_privs(&bglobal.bfdd_privs) {
+               s = vrf_socket(AF_INET6, SOCK_DGRAM, 0, vrf_id, NULL);
+       }
        if (s == -1)
                log_fatal("echov6-socket: socket: %s", strerror(errno));
 
index 6023b5e4f0a533194727e3ef67f9a2bc9844107d..218f0883c5fbd6c32e8d725a468bfdbaa2a77d89 100644 (file)
@@ -34,25 +34,13 @@ DEFINE_MTYPE(BFDD, BFDD_LABEL, "long-lived label memory");
 DEFINE_MTYPE(BFDD, BFDD_CONTROL, "long-lived control socket memory");
 DEFINE_MTYPE(BFDD, BFDD_SESSION_OBSERVER, "Session observer");
 DEFINE_MTYPE(BFDD, BFDD_NOTIFICATION, "short-lived control notification data");
+DEFINE_MTYPE(BFDD, BFDD_VRF, "BFD VRF");
 
 /* Master of threads. */
 struct thread_master *master;
 
 /* BFDd privileges */
-static zebra_capabilities_t _caps_p[] = {ZCAP_BIND};
-
-struct zebra_privs_t bfdd_privs = {
-#if defined(FRR_USER) && defined(FRR_GROUP)
-       .user = FRR_USER,
-       .group = FRR_GROUP,
-#endif
-#if defined(VTY_GROUP)
-       .vty_group = VTY_GROUP,
-#endif
-       .caps_p = _caps_p,
-       .cap_num_p = array_size(_caps_p),
-       .cap_num_i = 0,
-};
+static zebra_capabilities_t _caps_p[] = {ZCAP_BIND, ZCAP_SYS_ADMIN, ZCAP_NET_RAW};
 
 void socket_close(int *s)
 {
@@ -85,12 +73,7 @@ static void sigterm_handler(void)
        /* Shutdown and free all protocol related memory. */
        bfd_shutdown();
 
-       /* Close all descriptors. */
-       socket_close(&bglobal.bg_echo);
-       socket_close(&bglobal.bg_shop);
-       socket_close(&bglobal.bg_mhop);
-       socket_close(&bglobal.bg_shop6);
-       socket_close(&bglobal.bg_mhop6);
+       bfd_vrf_terminate();
 
        /* Terminate and free() FRR related memory. */
        frr_fini();
@@ -116,7 +99,7 @@ static struct quagga_signal_t bfd_signals[] = {
 FRR_DAEMON_INFO(bfdd, BFD, .vty_port = 2617,
                .proghelp = "Implementation of the BFD protocol.",
                .signals = bfd_signals, .n_signals = array_size(bfd_signals),
-               .privs = &bfdd_privs)
+               .privs = &bglobal.bfdd_privs)
 
 #define OPTION_CTLSOCK 1001
 static struct option longopts[] = {
@@ -153,15 +136,24 @@ struct bfd_state_str_list state_list[] = {
 
 static void bg_init(void)
 {
+       struct zebra_privs_t bfdd_privs = {
+#if defined(FRR_USER) && defined(FRR_GROUP)
+               .user = FRR_USER,
+               .group = FRR_GROUP,
+#endif
+#if defined(VTY_GROUP)
+               .vty_group = VTY_GROUP,
+#endif
+               .caps_p = _caps_p,
+               .cap_num_p = array_size(_caps_p),
+               .cap_num_i = 0,
+       };
+
        TAILQ_INIT(&bglobal.bg_bcslist);
        TAILQ_INIT(&bglobal.bg_obslist);
 
-       bglobal.bg_shop = bp_udp_shop();
-       bglobal.bg_mhop = bp_udp_mhop();
-       bglobal.bg_shop6 = bp_udp6_shop();
-       bglobal.bg_mhop6 = bp_udp6_mhop();
-       bglobal.bg_echo = bp_echo_socket();
-       bglobal.bg_echov6 = bp_echov6_socket();
+       memcpy(&bglobal.bfdd_privs, &bfdd_privs,
+              sizeof(bfdd_privs));
 }
 
 int main(int argc, char *argv[])
@@ -169,6 +161,9 @@ int main(int argc, char *argv[])
        const char *ctl_path = BFDD_CONTROL_SOCKET;
        int opt;
 
+       /* Initialize system sockets. */
+       bg_init();
+
        frr_preinit(&bfdd_di, argc, argv);
        frr_opt_add("", longopts,
                    "      --bfdctl       Specify bfdd control socket\n");
@@ -196,9 +191,6 @@ int main(int argc, char *argv[])
        /* Initialize logging API. */
        log_init(1, BLOG_DEBUG, &bfdd_di);
 
-       /* Initialize system sockets. */
-       bg_init();
-
        /* Initialize control socket. */
        control_init(ctl_path);
 
@@ -208,22 +200,11 @@ int main(int argc, char *argv[])
        /* Initialize BFD data structures. */
        bfd_initialize();
 
+       bfd_vrf_init();
+
        /* Initialize zebra connection. */
-       bfdd_zclient_init(&bfdd_privs);
-
-       /* Add descriptors to the event loop. */
-       thread_add_read(master, bfd_recv_cb, NULL, bglobal.bg_shop,
-                       &bglobal.bg_ev[0]);
-       thread_add_read(master, bfd_recv_cb, NULL, bglobal.bg_mhop,
-                       &bglobal.bg_ev[1]);
-       thread_add_read(master, bfd_recv_cb, NULL, bglobal.bg_shop6,
-                       &bglobal.bg_ev[2]);
-       thread_add_read(master, bfd_recv_cb, NULL, bglobal.bg_mhop6,
-                       &bglobal.bg_ev[3]);
-       thread_add_read(master, bfd_recv_cb, NULL, bglobal.bg_echo,
-                       &bglobal.bg_ev[4]);
-       thread_add_read(master, bfd_recv_cb, NULL, bglobal.bg_echov6,
-                       &bglobal.bg_ev[5]);
+       bfdd_zclient_init(&bglobal.bfdd_privs);
+
        thread_add_read(master, control_accept, NULL, bglobal.bg_csock,
                        &bglobal.bg_csockev);
 
index 4efdd817c1c78a44a22844d84cb9b907fd9f6379..75f6632db03a80b99f0e1ba4d293e3130751ccac 100644 (file)
@@ -64,7 +64,7 @@ static struct json_object *__display_peer_json(struct bfd_session *bs);
 static struct json_object *_peer_json_header(struct bfd_session *bs);
 static void _display_peer_json(struct vty *vty, struct bfd_session *bs);
 static void _display_peer(struct vty *vty, struct bfd_session *bs);
-static void _display_all_peers(struct vty *vty, bool use_json);
+static void _display_all_peers(struct vty *vty, char *vrfname, bool use_json);
 static void _display_peer_iter(struct hash_bucket *hb, void *arg);
 static void _display_peer_json_iter(struct hash_bucket *hb, void *arg);
 static void _display_peer_counter(struct vty *vty, struct bfd_session *bs);
@@ -72,7 +72,7 @@ static struct json_object *__display_peer_counters_json(struct bfd_session *bs);
 static void _display_peer_counters_json(struct vty *vty, struct bfd_session *bs);
 static void _display_peer_counter_iter(struct hash_bucket *hb, void *arg);
 static void _display_peer_counter_json_iter(struct hash_bucket *hb, void *arg);
-static void _display_peers_counter(struct vty *vty, bool use_json);
+static void _display_peers_counter(struct vty *vty, char *vrfname, bool use_json);
 static struct bfd_session *
 _find_peer_or_error(struct vty *vty, int argc, struct cmd_token **argv,
                    const char *label, const char *peer_str,
@@ -90,7 +90,7 @@ DEFUN_NOSH(bfd_enter, bfd_enter_cmd, "bfd", "Configure BFD peers\n")
 
 DEFUN_NOSH(
        bfd_peer_enter, bfd_peer_enter_cmd,
-       "peer <A.B.C.D|X:X::X:X> [{[multihop] local-address <A.B.C.D|X:X::X:X>|interface IFNAME|vrf NAME}]",
+       "peer <A.B.C.D|X:X::X:X> [{multihop|local-address <A.B.C.D|X:X::X:X>|interface IFNAME|vrf NAME}]",
        PEER_STR PEER_IPV4_STR PEER_IPV6_STR
        MHOP_STR
        LOCAL_STR LOCAL_IPV4_STR LOCAL_IPV6_STR
@@ -126,15 +126,6 @@ DEFUN_NOSH(
        if (argv_find(argv, argc, "vrf", &idx))
                vrfname = argv[idx + 1]->arg;
 
-       if (vrfname && ifname) {
-               vty_out(vty, "%% VRF is not mixable with interface\n");
-               return CMD_WARNING_CONFIG_FAILED;
-       }
-       if (vrfname && !mhop) {
-               vty_out(vty, "%% VRF only applies with multihop.\n");
-               return CMD_WARNING_CONFIG_FAILED;
-       }
-
        strtosa(peer, &psa);
        if (local) {
                strtosa(local, &lsa);
@@ -360,7 +351,7 @@ DEFPY(bfd_no_peer, bfd_no_peer_cmd,
                return CMD_WARNING_CONFIG_FAILED;
        }
 
-       if (ptm_bfd_ses_del(&bpc) != 0) {
+       if (ptm_bfd_sess_del(&bpc) != 0) {
                vty_out(vty, "%% Failed to remove peer.\n");
                return CMD_WARNING_CONFIG_FAILED;
        }
@@ -549,19 +540,46 @@ static void _display_peer_json(struct vty *vty, struct bfd_session *bs)
        json_object_free(jo);
 }
 
+struct bfd_vrf_tuple {
+       char *vrfname;
+       struct vty *vty;
+       struct json_object *jo;
+};
+
 static void _display_peer_iter(struct hash_bucket *hb, void *arg)
 {
-       struct vty *vty = arg;
+       struct bfd_vrf_tuple *bvt = (struct bfd_vrf_tuple *)arg;
+       struct vty *vty;
        struct bfd_session *bs = hb->data;
 
+       if (!bvt)
+               return;
+       vty = bvt->vty;
+
+       if (bvt->vrfname) {
+               if (!bs->key.vrfname[0] ||
+                   !strmatch(bs->key.vrfname, bvt->vrfname))
+                       return;
+       }
        _display_peer(vty, bs);
 }
 
 static void _display_peer_json_iter(struct hash_bucket *hb, void *arg)
 {
-       struct json_object *jo = arg, *jon = NULL;
+       struct bfd_vrf_tuple *bvt = (struct bfd_vrf_tuple *)arg;
+       struct json_object *jo, *jon = NULL;
        struct bfd_session *bs = hb->data;
 
+       if (!bvt)
+               return;
+       jo = bvt->jo;
+
+       if (bvt->vrfname) {
+               if (!bs->key.vrfname[0] ||
+                   !strmatch(bs->key.vrfname, bvt->vrfname))
+                       return;
+       }
+
        jon = __display_peer_json(bs);
        if (jon == NULL) {
                log_warning("%s: not enough memory", __func__);
@@ -571,18 +589,24 @@ static void _display_peer_json_iter(struct hash_bucket *hb, void *arg)
        json_object_array_add(jo, jon);
 }
 
-static void _display_all_peers(struct vty *vty, bool use_json)
+static void _display_all_peers(struct vty *vty, char *vrfname, bool use_json)
 {
        struct json_object *jo;
+       struct bfd_vrf_tuple bvt;
+
+       memset(&bvt, 0, sizeof(bvt));
+       bvt.vrfname = vrfname;
 
        if (!use_json) {
+               bvt.vty = vty;
                vty_out(vty, "BFD Peers:\n");
-               bfd_id_iterate(_display_peer_iter, vty);
+               bfd_id_iterate(_display_peer_iter, &bvt);
                return;
        }
 
        jo = json_object_new_array();
-       bfd_id_iterate(_display_peer_json_iter, jo);
+       bvt.jo = jo;
+       bfd_id_iterate(_display_peer_json_iter, &bvt);
 
        vty_out(vty, "%s\n", json_object_to_json_string_ext(jo, 0));
        json_object_free(jo);
@@ -634,16 +658,38 @@ static void _display_peer_counters_json(struct vty *vty, struct bfd_session *bs)
 
 static void _display_peer_counter_iter(struct hash_bucket *hb, void *arg)
 {
-       struct vty *vty = arg;
+       struct bfd_vrf_tuple *bvt = arg;
+       struct vty *vty;
        struct bfd_session *bs = hb->data;
 
+       if (!bvt)
+               return;
+       vty = bvt->vty;
+
+       if (bvt->vrfname) {
+               if (!bs->key.vrfname[0] ||
+                   !strmatch(bs->key.vrfname, bvt->vrfname))
+                       return;
+       }
+
        _display_peer_counter(vty, bs);
 }
 
 static void _display_peer_counter_json_iter(struct hash_bucket *hb, void *arg)
 {
-       struct json_object *jo = arg, *jon = NULL;
+       struct json_object *jo, *jon = NULL;
        struct bfd_session *bs = hb->data;
+       struct bfd_vrf_tuple *bvt = arg;
+
+       if (!bvt)
+               return;
+       jo  = bvt->jo;
+
+       if (bvt->vrfname) {
+               if (!bs->key.vrfname[0] ||
+                   !strmatch(bs->key.vrfname, bvt->vrfname))
+                       return;
+       }
 
        jon = __display_peer_counters_json(bs);
        if (jon == NULL) {
@@ -654,17 +700,22 @@ static void _display_peer_counter_json_iter(struct hash_bucket *hb, void *arg)
        json_object_array_add(jo, jon);
 }
 
-static void _display_peers_counter(struct vty *vty, bool use_json)
+static void _display_peers_counter(struct vty *vty, char *vrfname, bool use_json)
 {
        struct json_object *jo;
+       struct bfd_vrf_tuple bvt;
 
+       memset(&bvt, 0, sizeof(struct bfd_vrf_tuple));
+       bvt.vrfname = vrfname;
        if (!use_json) {
+               bvt.vty = vty;
                vty_out(vty, "BFD Peers:\n");
-               bfd_id_iterate(_display_peer_counter_iter, vty);
+               bfd_id_iterate(_display_peer_counter_iter, &bvt);
                return;
        }
 
        jo = json_object_new_array();
+       bvt.jo = jo;
        bfd_id_iterate(_display_peer_counter_json_iter, jo);
 
        vty_out(vty, "%s\n", json_object_to_json_string_ext(jo, 0));
@@ -734,24 +785,31 @@ _find_peer_or_error(struct vty *vty, int argc, struct cmd_token **argv,
 /*
  * Show commands.
  */
-DEFPY(bfd_show_peers, bfd_show_peers_cmd, "show bfd peers [json]",
+DEFPY(bfd_show_peers, bfd_show_peers_cmd, "show bfd [vrf <NAME>] peers [json]",
       SHOW_STR
       "Bidirection Forwarding Detection\n"
+       VRF_CMD_HELP_STR
       "BFD peers status\n" JSON_STR)
 {
-       _display_all_peers(vty, use_json(argc, argv));
+       char *vrf_name = NULL;
+       int idx_vrf = 0;
+
+       if (argv_find(argv, argc, "vrf", &idx_vrf))
+               vrf_name = argv[idx_vrf + 1]->arg;
+
+       _display_all_peers(vty, vrf_name, use_json(argc, argv));
 
        return CMD_SUCCESS;
 }
 
 DEFPY(bfd_show_peer, bfd_show_peer_cmd,
-      "show bfd peer <WORD$label|<A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname|vrf NAME$vrfname}]> [json]",
+      "show bfd [vrf <NAME$vrfname>] peer <WORD$label|<A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname}]> [json]",
       SHOW_STR
       "Bidirection Forwarding Detection\n"
+      VRF_CMD_HELP_STR
       "BFD peers status\n"
       "Peer label\n" PEER_IPV4_STR PEER_IPV6_STR MHOP_STR LOCAL_STR
-             LOCAL_IPV4_STR LOCAL_IPV6_STR INTERFACE_STR LOCAL_INTF_STR VRF_STR
-                     VRF_NAME_STR JSON_STR)
+             LOCAL_IPV4_STR LOCAL_IPV6_STR INTERFACE_STR LOCAL_INTF_STR JSON_STR)
 {
        struct bfd_session *bs;
 
@@ -772,9 +830,10 @@ DEFPY(bfd_show_peer, bfd_show_peer_cmd,
 }
 
 DEFPY(bfd_show_peer_counters, bfd_show_peer_counters_cmd,
-      "show bfd peer <WORD$label|<A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname|vrf NAME$vrfname}]> counters [json]",
+      "show bfd [vrf <NAME$vrfname>] peer <WORD$label|<A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname}]> counters [json]",
       SHOW_STR
       "Bidirection Forwarding Detection\n"
+      VRF_CMD_HELP_STR
       "BFD peers status\n"
       "Peer label\n"
       PEER_IPV4_STR
@@ -785,8 +844,6 @@ DEFPY(bfd_show_peer_counters, bfd_show_peer_counters_cmd,
       LOCAL_IPV6_STR
       INTERFACE_STR
       LOCAL_INTF_STR
-      VRF_STR
-      VRF_NAME_STR
       "Show BFD peer counters information\n"
       JSON_STR)
 {
@@ -807,14 +864,21 @@ DEFPY(bfd_show_peer_counters, bfd_show_peer_counters_cmd,
 }
 
 DEFPY(bfd_show_peers_counters, bfd_show_peers_counters_cmd,
-      "show bfd peers counters [json]",
+      "show bfd [vrf <NAME>] peers counters [json]",
       SHOW_STR
       "Bidirection Forwarding Detection\n"
+      VRF_CMD_HELP_STR
       "BFD peers status\n"
       "Show BFD peer counters information\n"
       JSON_STR)
 {
-       _display_peers_counter(vty, use_json(argc, argv));
+       char *vrf_name = NULL;
+       int idx_vrf = 0;
+
+       if (argv_find(argv, argc, "vrf", &idx_vrf))
+               vrf_name = argv[idx_vrf + 1]->arg;
+
+       _display_peers_counter(vty, vrf_name, use_json(argc, argv));
 
        return CMD_SUCCESS;
 }
diff --git a/bfdd/bsd.c b/bfdd/bsd.c
deleted file mode 100644 (file)
index 923fbd9..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * *BSD specific code
- *
- * Copyright (C) 2018 Network Device Education Foundation, Inc. ("NetDEF")
- *
- * FRR is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2, or (at your option) any
- * later version.
- *
- * FRR is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with FRR; see the file COPYING.  If not, write to the Free
- * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <zebra.h>
-
-#ifdef BFD_BSD
-
-#include <net/if.h>
-#include <net/if_types.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-
-#include <ifaddrs.h>
-
-#include "bfd.h"
-
-/*
- * Definitions.
- */
-int bp_bind_dev(int sd, const char *dev)
-{
-       /*
-        * *BSDs don't support `SO_BINDTODEVICE`, instead you must
-        * manually specify the main address of the interface or use
-        * BPF on the socket descriptor.
-        */
-       return 0;
-}
-
-#endif /* BFD_BSD */
index cd57ea9fe38b03ecd01aeb7dfe1cf4744b7299d9..74e7d63d0c6ee69790f43fb9085083a94e11f231 100644 (file)
@@ -68,7 +68,7 @@ static int config_add(struct bfd_peer_cfg *bpc,
 static int config_del(struct bfd_peer_cfg *bpc,
                      void *arg __attribute__((unused)))
 {
-       return ptm_bfd_ses_del(bpc) != 0;
+       return ptm_bfd_sess_del(bpc) != 0;
 }
 
 static int parse_config_json(struct json_object *jo, bpc_handle h, void *arg)
diff --git a/bfdd/linux.c b/bfdd/linux.c
deleted file mode 100644 (file)
index 3a76b45..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Linux specific code
- *
- * Copyright (C) 2018 Network Device Education Foundation, Inc. ("NetDEF")
- *
- * FRR is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2, or (at your option) any
- * later version.
- *
- * FRR is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with FRR; see the file COPYING.  If not, write to the Free
- * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <zebra.h>
-
-#ifdef BFD_LINUX
-
-#include "bfd.h"
-
-
-/*
- * Definitions.
- */
-int bp_bind_dev(int sd __attribute__((__unused__)),
-               const char *dev __attribute__((__unused__)))
-{
-       /*
-        * TODO: implement this differently. It is not possible to
-        * SO_BINDTODEVICE after the daemon has dropped its privileges.
-        */
-#if 0
-       size_t devlen = strlen(dev) + 1;
-
-       if (setsockopt(sd, SOL_SOCKET, SO_BINDTODEVICE, dev, devlen) == -1) {
-               log_warning("%s: setsockopt(SO_BINDTODEVICE, \"%s\"): %s",
-                           __func__, dev, strerror(errno));
-               return -1;
-       }
-#endif
-
-       return 0;
-}
-
-#endif /* BFD_LINUX */
index 6f76a15a570a33c126f07dd89b800cfdfe6fa878..a12a3c196b7934bb062d8d56635ae633760c88fc 100644 (file)
@@ -58,7 +58,7 @@ static struct zclient *zclient;
 static int _ptm_msg_address(struct stream *msg, int family, const void *addr);
 
 static void _ptm_msg_read_address(struct stream *msg, struct sockaddr_any *sa);
-static int _ptm_msg_read(struct stream *msg, int command,
+static int _ptm_msg_read(struct stream *msg, int command, vrf_id_t vrf_id,
                         struct bfd_peer_cfg *bpc, struct ptm_client **pc);
 
 static struct ptm_client *pc_lookup(uint32_t pid);
@@ -72,8 +72,8 @@ static struct ptm_client_notification *pcn_lookup(struct ptm_client *pc,
 static void pcn_free(struct ptm_client_notification *pcn);
 
 
-static void bfdd_dest_register(struct stream *msg);
-static void bfdd_dest_deregister(struct stream *msg);
+static void bfdd_dest_register(struct stream *msg, vrf_id_t vrf_id);
+static void bfdd_dest_deregister(struct stream *msg, vrf_id_t vrf_id);
 static void bfdd_client_register(struct stream *msg);
 static void bfdd_client_deregister(struct stream *msg);
 
@@ -182,7 +182,10 @@ int ptm_bfd_notify(struct bfd_session *bs)
        stream_reset(msg);
 
        /* TODO: VRF handling */
-       zclient_create_header(msg, ZEBRA_BFD_DEST_REPLAY, VRF_DEFAULT);
+       if (bs->vrf)
+               zclient_create_header(msg, ZEBRA_BFD_DEST_REPLAY, bs->vrf->vrf_id);
+       else
+               zclient_create_header(msg, ZEBRA_BFD_DEST_REPLAY, VRF_DEFAULT);
 
        /* This header will be handled by `zebra_ptm.c`. */
        stream_putl(msg, ZEBRA_INTERFACE_BFD_DEST_UPDATE);
@@ -256,7 +259,7 @@ stream_failure:
        memset(sa, 0, sizeof(*sa));
 }
 
-static int _ptm_msg_read(struct stream *msg, int command,
+static int _ptm_msg_read(struct stream *msg, int command, vrf_id_t vrf_id,
                         struct bfd_peer_cfg *bpc, struct ptm_client **pc)
 {
        uint32_t pid;
@@ -355,6 +358,18 @@ static int _ptm_msg_read(struct stream *msg, int command,
                        bpc->bpc_localif[ifnamelen] = 0;
                }
        }
+       if (vrf_id != VRF_DEFAULT) {
+               struct vrf *vrf;
+
+               vrf = vrf_lookup_by_id(vrf_id);
+               if (vrf) {
+                       bpc->bpc_has_vrfname = true;
+                       strlcpy(bpc->bpc_vrfname, vrf->name, sizeof(bpc->bpc_vrfname));
+               } else {
+                       log_error("ptm-read: vrf id %u could not be identified", vrf_id);
+                       return -1;
+               }
+       }
 
        /* Sanity check: peer and local address must match IP types. */
        if (bpc->bpc_local.sa_sin.sin_family != 0
@@ -370,7 +385,7 @@ stream_failure:
        return -1;
 }
 
-static void bfdd_dest_register(struct stream *msg)
+static void bfdd_dest_register(struct stream *msg, vrf_id_t vrf_id)
 {
        struct ptm_client *pc;
        struct ptm_client_notification *pcn;
@@ -378,7 +393,7 @@ static void bfdd_dest_register(struct stream *msg)
        struct bfd_peer_cfg bpc;
 
        /* Read the client context and peer data. */
-       if (_ptm_msg_read(msg, ZEBRA_BFD_DEST_REGISTER, &bpc, &pc) == -1)
+       if (_ptm_msg_read(msg, ZEBRA_BFD_DEST_REGISTER, vrf_id, &bpc, &pc) == -1)
                return;
 
        DEBUG_PRINTBPC(&bpc);
@@ -408,7 +423,7 @@ static void bfdd_dest_register(struct stream *msg)
        ptm_bfd_notify(bs);
 }
 
-static void bfdd_dest_deregister(struct stream *msg)
+static void bfdd_dest_deregister(struct stream *msg, vrf_id_t vrf_id)
 {
        struct ptm_client *pc;
        struct ptm_client_notification *pcn;
@@ -416,7 +431,7 @@ static void bfdd_dest_deregister(struct stream *msg)
        struct bfd_peer_cfg bpc;
 
        /* Read the client context and peer data. */
-       if (_ptm_msg_read(msg, ZEBRA_BFD_DEST_DEREGISTER, &bpc, &pc) == -1)
+       if (_ptm_msg_read(msg, ZEBRA_BFD_DEST_DEREGISTER, vrf_id, &bpc, &pc) == -1)
                return;
 
        DEBUG_PRINTBPC(&bpc);
@@ -434,7 +449,7 @@ static void bfdd_dest_deregister(struct stream *msg)
        if (bs->refcount ||
            BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_CONFIG))
                return;
-       ptm_bfd_ses_del(&bpc);
+       ptm_bfd_sess_del(&bpc);
 }
 
 /*
@@ -497,10 +512,10 @@ static int bfdd_replay(ZAPI_CALLBACK_ARGS)
        switch (rcmd) {
        case ZEBRA_BFD_DEST_REGISTER:
        case ZEBRA_BFD_DEST_UPDATE:
-               bfdd_dest_register(msg);
+               bfdd_dest_register(msg, vrf_id);
                break;
        case ZEBRA_BFD_DEST_DEREGISTER:
-               bfdd_dest_deregister(msg);
+               bfdd_dest_deregister(msg, vrf_id);
                break;
        case ZEBRA_BFD_CLIENT_REGISTER:
                bfdd_client_register(msg);
@@ -548,15 +563,21 @@ static void bfdd_sessions_enable_interface(struct interface *ifp)
 {
        struct bfd_session_observer *bso;
        struct bfd_session *bs;
+       struct vrf *vrf;
 
        TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) {
+               bs = bso->bso_bs;
                if (bso->bso_isinterface == false)
                        continue;
-
                /* Interface name mismatch. */
-               bs = bso->bso_bs;
                if (strcmp(ifp->name, bs->key.ifname))
                        continue;
+               vrf = vrf_lookup_by_id(ifp->vrf_id);
+               if (!vrf)
+                       continue;
+               if (bs->key.vrfname[0] &&
+                   strcmp(vrf->name, bs->key.vrfname))
+                       continue;
                /* Skip enabled sessions. */
                if (bs->sock != -1)
                        continue;
@@ -586,7 +607,52 @@ static void bfdd_sessions_disable_interface(struct interface *ifp)
                /* Try to enable it. */
                bfd_session_disable(bs);
 
-               TAILQ_INSERT_HEAD(&bglobal.bg_obslist, bso, bso_entry);
+       }
+}
+
+void bfdd_sessions_enable_vrf(struct vrf *vrf)
+{
+       struct bfd_session_observer *bso;
+       struct bfd_session *bs;
+
+       /* it may affect configs without interfaces */
+       TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) {
+               bs = bso->bso_bs;
+               if (bs->vrf)
+                       continue;
+               if (bs->key.vrfname[0] &&
+                   strcmp(vrf->name, bs->key.vrfname))
+                       continue;
+               /* need to update the vrf information on
+                * bs so that callbacks are handled
+                */
+               bs->vrf = vrf;
+               /* Skip enabled sessions. */
+               if (bs->sock != -1)
+                       continue;
+               /* Try to enable it. */
+               bfd_session_enable(bs);
+       }
+}
+
+void bfdd_sessions_disable_vrf(struct vrf *vrf)
+{
+       struct bfd_session_observer *bso;
+       struct bfd_session *bs;
+
+       TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) {
+               if (bso->bso_isinterface)
+                       continue;
+               bs = bso->bso_bs;
+               if (bs->key.vrfname[0] &&
+                   strcmp(vrf->name, bs->key.vrfname))
+                       continue;
+               /* Skip disabled sessions. */
+               if (bs->sock == -1)
+                       continue;
+
+               /* Try to enable it. */
+               bfd_session_disable(bs);
        }
 }
 
@@ -701,6 +767,20 @@ void bfdd_zclient_init(struct zebra_privs_t *bfdd_priv)
        zclient->interface_address_delete = bfdd_interface_address_update;
 }
 
+void bfdd_zclient_register(vrf_id_t vrf_id)
+{
+       if (!zclient || zclient->sock < 0)
+               return;
+       zclient_send_reg_requests(zclient, vrf_id);
+}
+
+void bfdd_zclient_unregister(vrf_id_t vrf_id)
+{
+       if (!zclient || zclient->sock < 0)
+               return;
+       zclient_send_dereg_requests(zclient, vrf_id);
+}
+
 void bfdd_zclient_stop(void)
 {
        zclient_stop(zclient);
index 334e974b048a9eb1676666b4e63c8eaa65e3d97c..e88b982ec3bfcc5d9260d936f7536a613040cb95 100644 (file)
@@ -14,11 +14,9 @@ bfdd_libbfd_a_SOURCES = \
        bfdd/bfd.c \
        bfdd/bfdd_vty.c \
        bfdd/bfd_packet.c \
-       bfdd/bsd.c \
        bfdd/config.c \
        bfdd/control.c \
        bfdd/event.c \
-       bfdd/linux.c \
        bfdd/log.c \
        bfdd/ptm_adapter.c \
        # end
index 45e45977a4ada851fe0cfcb29e6a5aadd20840de..a9c30acafbf711d7cb314ae7317aa87ea5014403 100644 (file)
@@ -96,13 +96,12 @@ int bgp_bfd_is_peer_multihop(struct peer *peer)
 static void bgp_bfd_peer_sendmsg(struct peer *peer, int command)
 {
        struct bfd_info *bfd_info;
-       vrf_id_t vrf_id = VRF_DEFAULT;
        int multihop;
+       vrf_id_t vrf_id;
 
        bfd_info = (struct bfd_info *)peer->bfd_info;
 
-       if (peer->bgp->inst_type == BGP_INSTANCE_TYPE_VRF)
-               vrf_id = peer->bgp->vrf_id;
+       vrf_id = peer->bgp->vrf_id;
 
        if (command == ZEBRA_BFD_DEST_DEREGISTER) {
                multihop =
@@ -244,7 +243,7 @@ static int bgp_bfd_dest_replay(ZAPI_CALLBACK_ARGS)
                zlog_debug("Zebra: BFD Dest replay request");
 
        /* Send the client registration */
-       bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER);
+       bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, vrf_id);
 
        /* Replay the peer, if BFD is enabled in BGP */
 
index d47c1f96388cb355246158b98cc89d7458b7c9b2..a45480fdc27c0d7a65c3978bc27b985893ca9fdb 100644 (file)
@@ -2441,7 +2441,7 @@ static void bgp_zebra_connected(struct zclient *zclient)
        bgp_zebra_instance_register(bgp);
 
        /* Send the client registration */
-       bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER);
+       bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, bgp->vrf_id);
 
        /* tell label pool that zebra is connected */
        bgp_lp_event_zebra_up();
index 986d1494a5476a782c2cb507bea660f61749082b..a7c5cf28bc5fc09996ad906fdc52bcf9e8a07e27 100644 (file)
@@ -72,8 +72,7 @@ BFDd Commands
    peer listener to and the address we should use to send the packets.
    This option is mandatory for IPv6.
 
-   `interface` selects which interface we should use. This option
-   conflicts with `vrf`.
+   `interface` selects which interface we should use.
 
    `vrf` selects which domain we want to use.
 
@@ -82,13 +81,13 @@ BFDd Commands
 
     Stops and removes the selected peer.
 
-.. index:: show bfd peers [json]
-.. clicmd:: show bfd peers [json]
+.. index:: show bfd [vrf NAME] peers [json]
+.. clicmd:: show bfd [vrf NAME] peers [json]
 
     Show all configured BFD peers information and current status.
 
-.. index:: show bfd peer <WORD$label|<A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname|vrf NAME$vrfname}]> [json]
-.. clicmd:: show bfd peer <WORD$label|<A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname|vrf NAME$vrfname}]> [json]
+.. index:: show bfd [vrf NAME$vrfname] peer <WORD$label|<A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname}]> [json]
+.. clicmd:: show bfd [vrf NAME$vrfname] peer <WORD$label|<A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname}]> [json]
 
     Show status for a specific BFD peer.
 
@@ -296,6 +295,11 @@ Here are the available peer configurations:
      shutdown
     !
 
+    ! configure a peer on an interface from a separate vrf
+    peer 192.168.0.5 interface eth1 vrf vrf2
+     no shutdown
+    !
+
     ! remove a peer
     no peer 192.168.0.3 vrf foo
 
index a98c44eeb0e8094169ae9dffdeb6fa4a9e20606d..fccef0169e77c29c4a0671a94b64473394adf0de 100644 (file)
@@ -139,7 +139,7 @@ static int isis_bfd_interface_dest_update(ZAPI_CALLBACK_ARGS)
 
 static int isis_bfd_nbr_replay(ZAPI_CALLBACK_ARGS)
 {
-       bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER);
+       bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, vrf_id);
 
        struct listnode *anode;
        struct isis_area *area;
@@ -167,7 +167,7 @@ static void isis_bfd_zebra_connected(struct zclient *zclient)
        if (orig_zebra_connected)
                orig_zebra_connected(zclient);
 
-       bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER);
+       bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, VRF_DEFAULT);
 }
 
 static void bfd_debug(struct in_addr *dst, struct in_addr *src,
index 7e27a64de7bcc20f490b61e3240d0fc945977065..a8956c315cc68e2c5c845b6841d6a3aad83c65f9 100644 (file)
--- a/lib/bfd.c
+++ b/lib/bfd.c
@@ -433,7 +433,8 @@ void bfd_show_info(struct vty *vty, struct bfd_info *bfd_info, int multihop,
  * bfd_client_sendmsg - Format and send a client register
  *                    command to Zebra to be forwarded to BFD
  */
-void bfd_client_sendmsg(struct zclient *zclient, int command)
+void bfd_client_sendmsg(struct zclient *zclient, int command,
+                       vrf_id_t vrf_id)
 {
        struct stream *s;
        int ret;
@@ -450,7 +451,7 @@ void bfd_client_sendmsg(struct zclient *zclient, int command)
 
        s = zclient->obuf;
        stream_reset(s);
-       zclient_create_header(s, command, VRF_DEFAULT);
+       zclient_create_header(s, command, vrf_id);
 
        stream_putl(s, getpid());
 
index a93875c4cf80e1a6ef74845f2ca93b681f28ef32..d02110a9970cea35d6833c157fc114bdebe46217 100644 (file)
--- a/lib/bfd.h
+++ b/lib/bfd.h
@@ -102,7 +102,8 @@ extern void bfd_show_info(struct vty *vty, struct bfd_info *bfd_info,
                          int multihop, int extra_space, bool use_json,
                          json_object *json_obj);
 
-extern void bfd_client_sendmsg(struct zclient *zclient, int command);
+extern void bfd_client_sendmsg(struct zclient *zclient, int command,
+                              vrf_id_t vrf_id);
 
 extern void bfd_gbl_init(void);
 
index 6d9ac2e1e44ba15fb6c887752109163b8325439e..6ec3cc8e0d288b4abfc4ca7387129eab5147bcd8 100644 (file)
--- a/lib/vrf.c
+++ b/lib/vrf.c
@@ -904,10 +904,16 @@ vrf_id_t vrf_get_default_id(void)
 int vrf_bind(vrf_id_t vrf_id, int fd, const char *name)
 {
        int ret = 0;
+       struct interface *ifp;
 
        if (fd < 0 || name == NULL)
                return fd;
-       if (vrf_is_backend_netns())
+       /* the device should exist
+        * otherwise we should return
+        * case ifname = vrf in netns mode => return
+        */
+       ifp = if_lookup_by_name(name, vrf_id);
+       if (!ifp)
                return fd;
 #ifdef SO_BINDTODEVICE
        ret = setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, name, strlen(name)+1);
index 3394bd75db854706db7c2ce821dc8fe4ea7199ba..7a26af1f09ac36fb08360fedf14c149c9e28e74f 100644 (file)
@@ -151,7 +151,7 @@ static int ospf6_bfd_nbr_replay(ZAPI_CALLBACK_ARGS)
                zlog_debug("Zebra: BFD Dest replay request");
 
        /* Send the client registration */
-       bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER);
+       bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, vrf_id);
 
        /* Replay the neighbor, if BFD is enabled on the interface*/
        FOR_ALL_INTERFACES (vrf, ifp) {
index 8db4ffef18c603f52b5e3d74a7782a678d293d4f..af16c5aa7cded703f57dfca72dfd986a0347f913 100644 (file)
@@ -571,7 +571,7 @@ uint8_t ospf6_distance_apply(struct prefix_ipv6 *p, struct ospf6_route * or)
 static void ospf6_zebra_connected(struct zclient *zclient)
 {
        /* Send the client registration */
-       bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER);
+       bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, VRF_DEFAULT);
 
        zclient_send_reg_requests(zclient, VRF_DEFAULT);
 }
index 6bff5b8ddbf2951ca514d20ae7b12704273a7db0..c8ad6d04f49ec6de3352bffe4ffccd5f314e9143 100644 (file)
@@ -156,7 +156,7 @@ static int ospf_bfd_nbr_replay(ZAPI_CALLBACK_ARGS)
        }
 
        /* Send the client registration */
-       bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER);
+       bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, vrf_id);
 
        /* Replay the neighbor, if BFD is enabled in OSPF */
        for (ALL_LIST_ELEMENTS(om->ospf, node, onode, ospf)) {
index 16796e68fb6ec6c635069863288f6fbe5547a5a7..c178e367d390a032fcc37df14163950328d8ce69 100644 (file)
@@ -1565,7 +1565,7 @@ void ospf_zebra_vrf_deregister(struct ospf *ospf)
 static void ospf_zebra_connected(struct zclient *zclient)
 {
        /* Send the client registration */
-       bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER);
+       bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, VRF_DEFAULT);
 
        zclient_send_reg_requests(zclient, VRF_DEFAULT);
 }
index 82087c4c5635d43704b3093f99c3a07782d530b7..300261e5a996909113c0737bcde1d545d78d75bc 100644 (file)
@@ -297,7 +297,7 @@ static int pim_bfd_nbr_replay(ZAPI_CALLBACK_ARGS)
        struct vrf *vrf = NULL;
 
        /* Send the client registration */
-       bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER);
+       bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, vrf_id);
 
        RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
                FOR_ALL_INTERFACES (vrf, ifp) {
index b27d2e0581b76760073a0c1b72125c88695b7633..25ac307ac43defc1b51e27ba89d169df7da729db 100644 (file)
@@ -780,7 +780,7 @@ void sched_rpf_cache_refresh(struct pim_instance *pim)
 static void pim_zebra_connected(struct zclient *zclient)
 {
        /* Send the client registration */
-       bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER);
+       bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, router->vrf_id);
 
        zclient_send_reg_requests(zclient, router->vrf_id);
 }
diff --git a/tests/topotests/bfd-vrf-topo1/__init__.py b/tests/topotests/bfd-vrf-topo1/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/topotests/bfd-vrf-topo1/r1/bfdd.conf b/tests/topotests/bfd-vrf-topo1/r1/bfdd.conf
new file mode 100644 (file)
index 0000000..3466e6a
--- /dev/null
@@ -0,0 +1,6 @@
+bfd
+ peer 192.168.0.2 vrf r1-cust1
+  echo-mode
+  no shutdown
+ !
+!
diff --git a/tests/topotests/bfd-vrf-topo1/r1/bgp_prefixes.json b/tests/topotests/bfd-vrf-topo1/r1/bgp_prefixes.json
new file mode 100644 (file)
index 0000000..4b2cc1a
--- /dev/null
@@ -0,0 +1,52 @@
+{
+  "routes": {
+    "10.254.254.2/32": [
+      {
+        "aspath": "102",
+        "prefix": "10.254.254.2",
+        "valid": true,
+        "peerId": "192.168.0.2",
+        "prefixLen": 32,
+        "nexthops": [
+          {
+            "ip": "192.168.0.2",
+            "used": true,
+            "afi": "ipv4"
+          }
+        ]
+      }
+    ],
+    "10.254.254.3/32": [
+      {
+        "aspath": "102 103",
+        "prefix": "10.254.254.3",
+        "valid": true,
+        "peerId": "192.168.0.2",
+        "prefixLen": 32,
+        "nexthops": [
+          {
+            "ip": "192.168.0.2",
+            "used": true,
+            "afi": "ipv4"
+          }
+        ]
+      }
+    ],
+    "10.254.254.4/32": [
+      {
+        "aspath": "102 104",
+        "prefix": "10.254.254.4",
+        "valid": true,
+        "peerId": "192.168.0.2",
+        "prefixLen": 32,
+        "nexthops": [
+          {
+            "ip": "192.168.0.2",
+            "used": true,
+            "afi": "ipv4"
+          }
+        ]
+      }
+    ]
+  }
+}
diff --git a/tests/topotests/bfd-vrf-topo1/r1/bgp_summary.json b/tests/topotests/bfd-vrf-topo1/r1/bgp_summary.json
new file mode 100644 (file)
index 0000000..fa07d60
--- /dev/null
@@ -0,0 +1,11 @@
+{
+  "ipv4Unicast": {
+    "as": 101,
+    "peers": {
+      "192.168.0.2": {
+        "remoteAs": 102,
+        "state": "Established"
+      }
+    }
+  }
+}
diff --git a/tests/topotests/bfd-vrf-topo1/r1/bgpd.conf b/tests/topotests/bfd-vrf-topo1/r1/bgpd.conf
new file mode 100644 (file)
index 0000000..7ad4e2b
--- /dev/null
@@ -0,0 +1,8 @@
+router bgp 101 vrf r1-cust1
+ neighbor 192.168.0.2 remote-as 102
+! neighbor 192.168.0.2 ebgp-multihop 10
+ neighbor 192.168.0.2 bfd
+ address-family ipv4 unicast
+  network 10.254.254.1/32
+ exit-address-family
+!
diff --git a/tests/topotests/bfd-vrf-topo1/r1/peers.json b/tests/topotests/bfd-vrf-topo1/r1/peers.json
new file mode 100644 (file)
index 0000000..f49768f
--- /dev/null
@@ -0,0 +1,8 @@
+[
+  {
+    "remote-receive-interval": 1000,
+    "remote-transmit-interval": 500,
+    "peer": "192.168.0.2",
+    "status": "up"
+  }
+]
diff --git a/tests/topotests/bfd-vrf-topo1/r1/zebra.conf b/tests/topotests/bfd-vrf-topo1/r1/zebra.conf
new file mode 100644 (file)
index 0000000..fcd1e7d
--- /dev/null
@@ -0,0 +1,3 @@
+interface r1-eth0 vrf r1-cust1
+ ip address 192.168.0.1/24
+!
diff --git a/tests/topotests/bfd-vrf-topo1/r2/bfdd.conf b/tests/topotests/bfd-vrf-topo1/r2/bfdd.conf
new file mode 100644 (file)
index 0000000..3481ea8
--- /dev/null
@@ -0,0 +1,12 @@
+bfd
+ peer 192.168.0.1 vrf r2-cust1
+  receive-interval 1000
+  transmit-interval 500
+  echo-mode
+  no shutdown
+ !
+ peer 192.168.1.1 vrf r2-cust1
+  echo-mode
+  no shutdown
+ !
+!
diff --git a/tests/topotests/bfd-vrf-topo1/r2/bgp_prefixes.json b/tests/topotests/bfd-vrf-topo1/r2/bgp_prefixes.json
new file mode 100644 (file)
index 0000000..39f3c0a
--- /dev/null
@@ -0,0 +1,52 @@
+{
+  "routes": {
+    "10.254.254.1/32": [
+      {
+        "aspath": "101",
+        "prefix": "10.254.254.1",
+        "valid": true,
+        "peerId": "192.168.0.1",
+        "prefixLen": 32,
+        "nexthops": [
+          {
+            "ip": "192.168.0.1",
+            "used": true,
+            "afi": "ipv4"
+          }
+        ]
+      }
+    ],
+    "10.254.254.3/32": [
+      {
+        "aspath": "103",
+        "prefix": "10.254.254.3",
+        "valid": true,
+        "peerId": "192.168.1.1",
+        "prefixLen": 32,
+        "nexthops": [
+          {
+            "ip": "192.168.1.1",
+            "used": true,
+            "afi": "ipv4"
+          }
+        ]
+      }
+    ],
+    "10.254.254.4/32": [
+      {
+        "aspath": "104",
+        "prefix": "10.254.254.4",
+        "valid": true,
+        "peerId": "192.168.2.1",
+        "prefixLen": 32,
+        "nexthops": [
+          {
+            "ip": "192.168.2.1",
+            "used": true,
+            "afi": "ipv4"
+          }
+        ]
+      }
+    ]
+  }
+}
diff --git a/tests/topotests/bfd-vrf-topo1/r2/bgp_summary.json b/tests/topotests/bfd-vrf-topo1/r2/bgp_summary.json
new file mode 100644 (file)
index 0000000..c0ef11a
--- /dev/null
@@ -0,0 +1,19 @@
+{
+  "ipv4Unicast": {
+    "as": 102,
+    "peers": {
+      "192.168.0.1": {
+        "remoteAs": 101,
+        "state": "Established"
+      },
+      "192.168.1.1": {
+        "remoteAs": 103,
+        "state": "Established"
+      },
+      "192.168.2.1": {
+        "remoteAs": 104,
+        "state": "Established"
+      }
+    }
+  }
+}
diff --git a/tests/topotests/bfd-vrf-topo1/r2/bgpd.conf b/tests/topotests/bfd-vrf-topo1/r2/bgpd.conf
new file mode 100644 (file)
index 0000000..0715ea3
--- /dev/null
@@ -0,0 +1,11 @@
+router bgp 102 vrf r2-cust1
+ neighbor 192.168.0.1 remote-as 101
+ neighbor 192.168.0.1 bfd
+ neighbor 192.168.1.1 remote-as 103
+ neighbor 192.168.1.1 bfd
+ neighbor 192.168.2.1 remote-as 104
+ neighbor 192.168.2.1 bfd
+ address-family ipv4 unicast
+  network 10.254.254.2/32
+ exit-address-family
+!
diff --git a/tests/topotests/bfd-vrf-topo1/r2/peers.json b/tests/topotests/bfd-vrf-topo1/r2/peers.json
new file mode 100644 (file)
index 0000000..5035d64
--- /dev/null
@@ -0,0 +1,17 @@
+[
+  {
+    "peer": "192.168.0.1",
+    "status": "up"
+  },
+  {
+    "remote-echo-interval": 100,
+    "peer": "192.168.1.1",
+    "status": "up"
+  },
+  {
+    "remote-transmit-interval": 2000,
+    "remote-receive-interval": 2000,
+    "peer": "192.168.2.1",
+    "status": "up"
+  }
+]
diff --git a/tests/topotests/bfd-vrf-topo1/r2/zebra.conf b/tests/topotests/bfd-vrf-topo1/r2/zebra.conf
new file mode 100644 (file)
index 0000000..daffd19
--- /dev/null
@@ -0,0 +1,9 @@
+interface r2-eth0 vrf r2-cust1
+ ip address 192.168.0.2/24
+!
+interface r2-eth1 vrf r2-cust1
+ ip address 192.168.1.2/24
+!
+interface r2-eth2 vrf r2-cust1
+ ip address 192.168.2.2/24
+!
diff --git a/tests/topotests/bfd-vrf-topo1/r3/bfdd.conf b/tests/topotests/bfd-vrf-topo1/r3/bfdd.conf
new file mode 100644 (file)
index 0000000..f6921b7
--- /dev/null
@@ -0,0 +1,7 @@
+bfd
+ peer 192.168.1.2 vrf r3-cust1
+  echo-interval 100
+  echo-mode
+  no shutdown
+ !
+!
diff --git a/tests/topotests/bfd-vrf-topo1/r3/bgp_prefixes.json b/tests/topotests/bfd-vrf-topo1/r3/bgp_prefixes.json
new file mode 100644 (file)
index 0000000..c92d4e0
--- /dev/null
@@ -0,0 +1,52 @@
+{
+  "routes": {
+    "10.254.254.1/32": [
+      {
+        "aspath": "102 101",
+        "prefix": "10.254.254.1",
+        "valid": true,
+        "peerId": "192.168.1.2",
+        "prefixLen": 32,
+        "nexthops": [
+          {
+            "ip": "192.168.1.2",
+            "used": true,
+            "afi": "ipv4"
+          }
+        ]
+      }
+    ],
+    "10.254.254.2/32": [
+      {
+        "aspath": "102",
+        "prefix": "10.254.254.2",
+        "valid": true,
+        "peerId": "192.168.1.2",
+        "prefixLen": 32,
+        "nexthops": [
+          {
+            "ip": "192.168.1.2",
+            "used": true,
+            "afi": "ipv4"
+          }
+        ]
+      }
+    ],
+    "10.254.254.4/32": [
+      {
+        "aspath": "102 104",
+        "prefix": "10.254.254.4",
+        "valid": true,
+        "peerId": "192.168.1.2",
+        "prefixLen": 32,
+        "nexthops": [
+          {
+            "ip": "192.168.1.2",
+            "used": true,
+            "afi": "ipv4"
+          }
+        ]
+      }
+    ]
+  }
+}
diff --git a/tests/topotests/bfd-vrf-topo1/r3/bgp_summary.json b/tests/topotests/bfd-vrf-topo1/r3/bgp_summary.json
new file mode 100644 (file)
index 0000000..d478333
--- /dev/null
@@ -0,0 +1,11 @@
+{
+  "ipv4Unicast": {
+    "as": 103,
+    "peers": {
+      "192.168.1.2": {
+        "remoteAs": 102,
+        "state": "Established"
+      }
+    }
+  }
+}
diff --git a/tests/topotests/bfd-vrf-topo1/r3/bgpd.conf b/tests/topotests/bfd-vrf-topo1/r3/bgpd.conf
new file mode 100644 (file)
index 0000000..277f027
--- /dev/null
@@ -0,0 +1,7 @@
+router bgp 103 vrf r3-cust1
+ neighbor 192.168.1.2 remote-as 102
+ neighbor 192.168.1.2 bfd
+ address-family ipv4 unicast
+  network 10.254.254.3/32
+ exit-address-family
+!
diff --git a/tests/topotests/bfd-vrf-topo1/r3/peers.json b/tests/topotests/bfd-vrf-topo1/r3/peers.json
new file mode 100644 (file)
index 0000000..ef38008
--- /dev/null
@@ -0,0 +1,6 @@
+[
+  {
+    "peer": "192.168.1.2",
+    "status": "up"
+  }
+]
diff --git a/tests/topotests/bfd-vrf-topo1/r3/zebra.conf b/tests/topotests/bfd-vrf-topo1/r3/zebra.conf
new file mode 100644 (file)
index 0000000..f727c2d
--- /dev/null
@@ -0,0 +1,3 @@
+interface r3-eth0 vrf r3-cust1
+ ip address 192.168.1.1/24
+!
diff --git a/tests/topotests/bfd-vrf-topo1/r4/bfdd.conf b/tests/topotests/bfd-vrf-topo1/r4/bfdd.conf
new file mode 100644 (file)
index 0000000..a56a3a0
--- /dev/null
@@ -0,0 +1,7 @@
+bfd
+ peer 192.168.2.2 vrf r4-cust1
+  transmit-interval 2000
+  receive-interval 2000
+  no shutdown
+ !
+!
diff --git a/tests/topotests/bfd-vrf-topo1/r4/bgp_prefixes.json b/tests/topotests/bfd-vrf-topo1/r4/bgp_prefixes.json
new file mode 100644 (file)
index 0000000..cc8510d
--- /dev/null
@@ -0,0 +1,52 @@
+{
+  "routes": {
+    "10.254.254.1/32": [
+      {
+        "aspath": "102 101",
+        "prefix": "10.254.254.1",
+        "valid": true,
+        "peerId": "192.168.2.2",
+        "prefixLen": 32,
+        "nexthops": [
+          {
+            "ip": "192.168.2.2",
+            "used": true,
+            "afi": "ipv4"
+          }
+        ]
+      }
+    ],
+    "10.254.254.2/32": [
+      {
+        "aspath": "102",
+        "prefix": "10.254.254.2",
+        "valid": true,
+        "peerId": "192.168.2.2",
+        "prefixLen": 32,
+        "nexthops": [
+          {
+            "ip": "192.168.2.2",
+            "used": true,
+            "afi": "ipv4"
+          }
+        ]
+      }
+    ],
+    "10.254.254.3/32": [
+      {
+        "aspath": "102 103",
+        "prefix": "10.254.254.3",
+        "valid": true,
+        "peerId": "192.168.2.2",
+        "prefixLen": 32,
+        "nexthops": [
+          {
+            "ip": "192.168.2.2",
+            "used": true,
+            "afi": "ipv4"
+          }
+        ]
+      }
+    ]
+  }
+}
diff --git a/tests/topotests/bfd-vrf-topo1/r4/bgp_summary.json b/tests/topotests/bfd-vrf-topo1/r4/bgp_summary.json
new file mode 100644 (file)
index 0000000..7d81784
--- /dev/null
@@ -0,0 +1,11 @@
+{
+  "ipv4Unicast": {
+    "as": 104,
+    "peers": {
+      "192.168.2.2": {
+        "remoteAs": 102,
+        "state": "Established"
+      }
+    }
+  }
+}
diff --git a/tests/topotests/bfd-vrf-topo1/r4/bgpd.conf b/tests/topotests/bfd-vrf-topo1/r4/bgpd.conf
new file mode 100644 (file)
index 0000000..66bf285
--- /dev/null
@@ -0,0 +1,7 @@
+router bgp 104 vrf r4-cust1
+ neighbor 192.168.2.2 remote-as 102
+ neighbor 192.168.2.2 bfd
+ address-family ipv4 unicast
+  network 10.254.254.4/32
+ exit-address-family
+!
diff --git a/tests/topotests/bfd-vrf-topo1/r4/peers.json b/tests/topotests/bfd-vrf-topo1/r4/peers.json
new file mode 100644 (file)
index 0000000..3714008
--- /dev/null
@@ -0,0 +1,6 @@
+[
+  {
+    "peer": "192.168.2.2",
+    "status": "up"
+  }
+]
diff --git a/tests/topotests/bfd-vrf-topo1/r4/zebra.conf b/tests/topotests/bfd-vrf-topo1/r4/zebra.conf
new file mode 100644 (file)
index 0000000..69770dd
--- /dev/null
@@ -0,0 +1,3 @@
+interface r4-eth0 vrf r4-cust1
+ ip address 192.168.2.1/24
+!
diff --git a/tests/topotests/bfd-vrf-topo1/test_bfd_vrf_topo1.dot b/tests/topotests/bfd-vrf-topo1/test_bfd_vrf_topo1.dot
new file mode 100644 (file)
index 0000000..c84ace2
--- /dev/null
@@ -0,0 +1,73 @@
+## Color coding:
+#########################
+##  Main FRR: #f08080  red
+##  Switches: #d0e0d0  gray
+##  RIP:      #19e3d9  Cyan
+##  RIPng:    #fcb314  dark yellow
+##  OSPFv2:   #32b835  Green
+##  OSPFv3:   #19e3d9  Cyan
+##  ISIS IPv4 #fcb314  dark yellow
+##  ISIS IPv6 #9a81ec  purple
+##  BGP IPv4  #eee3d3  beige
+##  BGP IPv6  #fdff00  yellow
+##### Colors (see http://www.color-hex.com/)
+
+graph template {
+  label="bfd-topo1";
+
+  # Routers
+  r1 [
+    shape=doubleoctagon,
+    label="r1",
+    fillcolor="#f08080",
+    style=filled,
+  ];
+  r2 [
+    shape=doubleoctagon
+    label="r2",
+    fillcolor="#f08080",
+    style=filled,
+  ];
+  r3 [
+    shape=doubleoctagon
+    label="r3",
+    fillcolor="#f08080",
+    style=filled,
+  ];
+  r4 [
+    shape=doubleoctagon
+    label="r4",
+    fillcolor="#f08080",
+    style=filled,
+  ];
+
+  # Switches
+  sw1 [
+    shape=oval,
+    label="sw1\n192.168.0.0/24",
+    fillcolor="#d0e0d0",
+    style=filled,
+  ];
+  sw2 [
+    shape=oval,
+    label="sw2\n192.168.1.0/24",
+    fillcolor="#d0e0d0",
+    style=filled,
+  ];
+  sw3 [
+    shape=oval,
+    label="sw3\n192.168.2.0/24",
+    fillcolor="#d0e0d0",
+    style=filled,
+  ];
+
+  # Connections
+  r1 -- sw1 [label="eth0\n.1"];
+  r2 -- sw1 [label="eth0\n.2"];
+
+  r3 -- sw2 [label="eth0\n.1"];
+  r2 -- sw2 [label="eth1\n.2"];
+
+  r4 -- sw3 [label="eth0\n.1"];
+  r2 -- sw3 [label="eth2\n.2"];
+}
diff --git a/tests/topotests/bfd-vrf-topo1/test_bfd_vrf_topo1.jpg b/tests/topotests/bfd-vrf-topo1/test_bfd_vrf_topo1.jpg
new file mode 100644 (file)
index 0000000..4d6d56e
Binary files /dev/null and b/tests/topotests/bfd-vrf-topo1/test_bfd_vrf_topo1.jpg differ
diff --git a/tests/topotests/bfd-vrf-topo1/test_bfd_vrf_topo1.py b/tests/topotests/bfd-vrf-topo1/test_bfd_vrf_topo1.py
new file mode 100755 (executable)
index 0000000..e293382
--- /dev/null
@@ -0,0 +1,292 @@
+#!/usr/bin/env python
+
+#
+# test_bfd_vrf_topo1.py
+# Part of NetDEF Topology Tests
+#
+# Copyright (c) 2018 by
+# Network Device Education Foundation, Inc. ("NetDEF")
+# Copyright (c) 2019 by 6WIND
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+"""
+test_bfd_vrf_topo1.py: Test the FRR/Quagga BFD daemon.
+"""
+
+import os
+import sys
+import json
+from functools import partial
+import pytest
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, '../'))
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.topolog import logger
+
+# Required to instantiate the topology builder class.
+from mininet.topo import Topo
+
+class BFDTopo(Topo):
+    "Test topology builder"
+    def build(self, *_args, **_opts):
+        "Build function"
+        tgen = get_topogen(self)
+
+        # Create 4 routers
+        for routern in range(1, 5):
+            tgen.add_router('r{}'.format(routern))
+
+        switch = tgen.add_switch('s1')
+        switch.add_link(tgen.gears['r1'])
+        switch.add_link(tgen.gears['r2'])
+
+        switch = tgen.add_switch('s2')
+        switch.add_link(tgen.gears['r2'])
+        switch.add_link(tgen.gears['r3'])
+
+        switch = tgen.add_switch('s3')
+        switch.add_link(tgen.gears['r2'])
+        switch.add_link(tgen.gears['r4'])
+
+
+def setup_module(mod):
+    "Sets up the pytest environment"
+    tgen = Topogen(BFDTopo, mod.__name__)
+    tgen.start_topology()
+
+    router_list = tgen.routers()
+
+    # check for zebra capability
+    for rname, router in router_list.iteritems():
+        if router.check_capability(
+                TopoRouter.RD_ZEBRA,
+                '--vrfwnetns'
+        ) == False:
+            return  pytest.skip('Skipping BFD Topo1 VRF NETNS feature. VRF NETNS backend not available on FRR')
+
+    if os.system('ip netns list') != 0:
+        return  pytest.skip('Skipping BFD Topo1 VRF NETNS Test. NETNS not available on System')
+
+    logger.info('Testing with VRF Namespace support')
+
+    cmds = ['if [ -e /var/run/netns/{0}-cust1 ] ; then ip netns del {0}-cust1 ; fi',
+            'ip netns add {0}-cust1',
+            'ip link set dev {0}-eth0 netns {0}-cust1',
+            'ip netns exec {0}-cust1 ifconfig {0}-eth0 up']
+    cmds2 = ['ip link set dev {0}-eth1 netns {0}-cust1',
+             'ip netns exec {0}-cust1 ifconfig {0}-eth1 up',
+             'ip link set dev {0}-eth2 netns {0}-cust1',
+             'ip netns exec {0}-cust1 ifconfig {0}-eth2 up']
+
+    for rname, router in router_list.iteritems():
+        # create VRF rx-cust1 and link rx-eth0 to rx-cust1
+        for cmd in cmds:
+            output = tgen.net[rname].cmd(cmd.format(rname))
+        if rname == 'r2':
+            for cmd in cmds2:
+                output = tgen.net[rname].cmd(cmd.format(rname))
+
+    for rname, router in router_list.iteritems():
+        router.load_config(
+            TopoRouter.RD_ZEBRA,
+            os.path.join(CWD, '{}/zebra.conf'.format(rname)),
+            '--vrfwnetns'
+        )
+        router.load_config(
+            TopoRouter.RD_BFD,
+            os.path.join(CWD, '{}/bfdd.conf'.format(rname))
+        )
+        router.load_config(
+            TopoRouter.RD_BGP,
+            os.path.join(CWD, '{}/bgpd.conf'.format(rname))
+        )
+
+    # Initialize all routers.
+    tgen.start_router()
+
+    # Verify that we are using the proper version and that the BFD
+    # daemon exists.
+    for router in router_list.values():
+        # Check for Version
+        if router.has_version('<', '5.1'):
+            tgen.set_error('Unsupported FRR version')
+            break
+
+def teardown_module(_mod):
+    "Teardown the pytest environment"
+    tgen = get_topogen()
+    # move back rx-eth0 to default VRF
+    # delete rx-vrf
+    cmds = ['ip netns exec {0}-cust1 ip link set {0}-eth0 netns 1',
+            'ip netns delete {0}-cust1']
+    cmds2 = ['ip netns exec {0}-cust1 ip link set {0}-eth1 netns 1',
+             'ip netns exec {0}-cust2 ip link set {0}-eth1 netns 1']
+
+    router_list = tgen.routers()
+    for rname, router in router_list.iteritems():
+        if rname == 'r2':
+            for cmd in cmds2:
+                tgen.net[rname].cmd(cmd.format(rname))
+        for cmd in cmds:
+            tgen.net[rname].cmd(cmd.format(rname))
+    tgen.stop_topology()
+
+def test_bfd_connection():
+    "Assert that the BFD peers can find themselves."
+    tgen = get_topogen()
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    logger.info('waiting for bfd peers to go up')
+    for router in tgen.routers().values():
+        json_file = '{}/{}/peers.json'.format(CWD, router.name)
+        expected = json.loads(open(json_file).read())
+
+        test_func = partial(topotest.router_json_cmp,
+            router, 'show bfd peers json', expected)
+        _, result = topotest.run_and_expect(test_func, None, count=8, wait=0.5)
+        assertmsg = '"{}" JSON output mismatches'.format(router.name)
+        assert result is None, assertmsg
+
+
+def test_bgp_convergence():
+    "Assert that BGP is converging."
+    tgen = get_topogen()
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    logger.info('waiting for bgp peers to go up')
+
+    for router in tgen.routers().values():
+        ref_file = '{}/{}/bgp_summary.json'.format(CWD, router.name)
+        expected = json.loads(open(ref_file).read())
+        test_func = partial(topotest.router_json_cmp,
+                            router, 'show ip bgp vrf {}-cust1 summary json'.format(router.name), expected)
+        _, res = topotest.run_and_expect(test_func, None, count=125, wait=1.0)
+        assertmsg = '{}: bgp did not converge'.format(router.name)
+        assert res is None, assertmsg
+
+
+def test_bgp_fast_convergence():
+    "Assert that BGP is converging before setting a link down."
+    tgen = get_topogen()
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    logger.info('waiting for bgp peers converge')
+
+    for router in tgen.routers().values():
+        ref_file = '{}/{}/bgp_prefixes.json'.format(CWD, router.name)
+        expected = json.loads(open(ref_file).read())
+        test_func = partial(topotest.router_json_cmp,
+                            router, 'show ip bgp vrf {}-cust1 json'.format(router.name), expected)
+        _, res = topotest.run_and_expect(test_func, None, count=40, wait=0.5)
+        assertmsg = '{}: bgp did not converge'.format(router.name)
+        assert res is None, assertmsg
+
+
+def test_bfd_fast_convergence():
+    """
+    Assert that BFD notices the link down after simulating network
+    failure.
+    """
+    tgen = get_topogen()
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    # Disable r2-eth0 link
+    router2 = tgen.gears['r2']
+    topotest.interface_set_status(router2, 'r2-eth0', ifaceaction=False, vrf_name='r2-cust1')
+
+    # Wait the minimum time we can before checking that BGP/BFD
+    # converged.
+    logger.info('waiting for BFD converge')
+
+    # Check that BGP converged quickly.
+    for router in tgen.routers().values():
+        json_file = '{}/{}/peers.json'.format(CWD, router.name)
+        expected = json.loads(open(json_file).read())
+
+        # Load the same file as previous test, but expect R1 to be down.
+        if router.name == 'r1':
+            for peer in expected:
+                if peer['peer'] == '192.168.0.2':
+                    peer['status'] = 'down'
+        else:
+            for peer in expected:
+                if peer['peer'] == '192.168.0.1':
+                    peer['status'] = 'down'
+
+        test_func = partial(topotest.router_json_cmp,
+            router, 'show bfd peers json', expected)
+        _, res = topotest.run_and_expect(test_func, None, count=20, wait=0.5)
+        assertmsg = '"{}" JSON output mismatches'.format(router.name)
+        assert res is None, assertmsg
+
+
+def test_bgp_fast_reconvergence():
+    "Assert that BGP is converging after setting a link down."
+    tgen = get_topogen()
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    logger.info('waiting for BGP re convergence')
+
+    # Check that BGP converged quickly.
+    for router in tgen.routers().values():
+        ref_file = '{}/{}/bgp_prefixes.json'.format(CWD, router.name)
+        expected = json.loads(open(ref_file).read())
+
+        # Load the same file as previous test, but set networks to None
+        # to test absence.
+        if router.name == 'r1':
+            expected['routes']['10.254.254.2/32'] = None
+            expected['routes']['10.254.254.3/32'] = None
+            expected['routes']['10.254.254.4/32'] = None
+        else:
+            expected['routes']['10.254.254.1/32'] = None
+
+        test_func = partial(topotest.router_json_cmp,
+                            router, 'show ip bgp vrf {}-cust1 json'.format(router.name), expected)
+        _, res = topotest.run_and_expect(
+            test_func,
+            None,
+            count=3,
+            wait=1
+        )
+        assertmsg = '{}: bgp did not converge'.format(router.name)
+        assert res is None, assertmsg
+
+
+def test_memory_leak():
+    "Run the memory leak test and report results."
+    tgen = get_topogen()
+    if not tgen.is_memleak_enabled():
+        pytest.skip('Memory leak test/report is disabled')
+
+    tgen.report_memory_leaks()
+
+
+if __name__ == '__main__':
+    args = ["-s"] + sys.argv[1:]
+    sys.exit(pytest.main(args))
index bb352dc2ffd698fb3176500324cbf928b4c7979c..d3ecd3695adb6457e3eeb84b46b5eb76e3b65c2a 100644 (file)
@@ -1188,8 +1188,8 @@ static void pp_free_all(void);
 static void zebra_ptm_send_bfdd(struct stream *msg);
 static void zebra_ptm_send_clients(struct stream *msg);
 static int _zebra_ptm_bfd_client_deregister(struct zserv *zs);
-static void _zebra_ptm_reroute(struct zserv *zs, struct stream *msg,
-                              uint32_t command);
+static void _zebra_ptm_reroute(struct zserv *zs, struct zebra_vrf *zvrf,
+                              struct stream *msg, uint32_t command);
 
 
 /*
@@ -1392,8 +1392,8 @@ void zebra_ptm_finish(void)
 /*
  * Message handling.
  */
-static void _zebra_ptm_reroute(struct zserv *zs, struct stream *msg,
-                              uint32_t command)
+static void _zebra_ptm_reroute(struct zserv *zs, struct zebra_vrf *zvrf,
+                              struct stream *msg, uint32_t command)
 {
        struct stream *msgc;
        size_t zmsglen, zhdrlen;
@@ -1420,7 +1420,7 @@ static void _zebra_ptm_reroute(struct zserv *zs, struct stream *msg,
         * one callback at the `bfdd` side, however the real command
         * number will be included right after the zebra header.
         */
-       zclient_create_header(msgc, ZEBRA_BFD_DEST_REPLAY, 0);
+       zclient_create_header(msgc, ZEBRA_BFD_DEST_REPLAY, zvrf->vrf->vrf_id);
        stream_putl(msgc, command);
 
        /* Update the data pointers. */
@@ -1446,7 +1446,7 @@ void zebra_ptm_bfd_dst_register(ZAPI_HANDLER_ARGS)
                zlog_debug("bfd_dst_register msg from client %s: length=%d",
                           zebra_route_string(client->proto), hdr->length);
 
-       _zebra_ptm_reroute(client, msg, ZEBRA_BFD_DEST_REGISTER);
+       _zebra_ptm_reroute(client, zvrf, msg, ZEBRA_BFD_DEST_REGISTER);
 }
 
 void zebra_ptm_bfd_dst_deregister(ZAPI_HANDLER_ARGS)
@@ -1455,7 +1455,7 @@ void zebra_ptm_bfd_dst_deregister(ZAPI_HANDLER_ARGS)
                zlog_debug("bfd_dst_deregister msg from client %s: length=%d",
                           zebra_route_string(client->proto), hdr->length);
 
-       _zebra_ptm_reroute(client, msg, ZEBRA_BFD_DEST_DEREGISTER);
+       _zebra_ptm_reroute(client, zvrf, msg, ZEBRA_BFD_DEST_DEREGISTER);
 }
 
 void zebra_ptm_bfd_client_register(ZAPI_HANDLER_ARGS)
@@ -1464,7 +1464,7 @@ void zebra_ptm_bfd_client_register(ZAPI_HANDLER_ARGS)
                zlog_debug("bfd_client_register msg from client %s: length=%d",
                           zebra_route_string(client->proto), hdr->length);
 
-       _zebra_ptm_reroute(client, msg, ZEBRA_BFD_CLIENT_REGISTER);
+       _zebra_ptm_reroute(client, zvrf, msg, ZEBRA_BFD_CLIENT_REGISTER);
 }
 
 void zebra_ptm_bfd_dst_replay(ZAPI_HANDLER_ARGS)
@@ -1488,7 +1488,7 @@ void zebra_ptm_bfd_dst_replay(ZAPI_HANDLER_ARGS)
         * special treatment.
         */
        if (client->proto != ZEBRA_ROUTE_BFD) {
-               _zebra_ptm_reroute(client, msg, ZEBRA_BFD_DEST_REPLAY);
+               _zebra_ptm_reroute(client, zvrf, msg, ZEBRA_BFD_DEST_REPLAY);
                return;
        }