From 031705c9fc046f05560a2fa3926ead9bc99c96ae Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Fri, 8 Jan 2021 07:51:33 +0000 Subject: [PATCH 1/4] bfdd: socket should be bound to vrf interface by default When running in vrf-lite mode, the socket used in a vrf environment should be bound to an interface belonging to the vrf. If no one is selected, then the vrf interface itself should be bound to that socket, so that outgoing packets are being applied routing rules for that vrf. Signed-off-by: Philippe Guibert --- bfdd/bfd_packet.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/bfdd/bfd_packet.c b/bfdd/bfd_packet.c index 0a71c18a42..10b99a62a9 100644 --- a/bfdd/bfd_packet.c +++ b/bfdd/bfd_packet.c @@ -951,8 +951,9 @@ int bp_peer_socket(const struct bfd_session *bs) if (bs->key.ifname[0]) device_to_bind = (const char *)bs->key.ifname; - else if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH) - && bs->key.vrfname[0]) + else if ((!vrf_is_backend_netns() && bs->vrf->vrf_id != VRF_DEFAULT) + || ((CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH) + && bs->key.vrfname[0]))) device_to_bind = (const char *)bs->key.vrfname; frr_with_privs(&bglobal.bfdd_privs) { @@ -1018,8 +1019,9 @@ int bp_peer_socketv6(const struct bfd_session *bs) if (bs->key.ifname[0]) device_to_bind = (const char *)bs->key.ifname; - else if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH) - && bs->key.vrfname[0]) + else if ((!vrf_is_backend_netns() && bs->vrf->vrf_id != VRF_DEFAULT) + || ((CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH) + && bs->key.vrfname[0]))) device_to_bind = (const char *)bs->key.vrfname; frr_with_privs(&bglobal.bfdd_privs) { From 039c8158f33f75072433ab13f5c4fcb95c394d0b Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Fri, 8 Jan 2021 09:34:20 +0000 Subject: [PATCH 2/4] bfdd: enable bfd session if vrf interface available The vrf interface notification and interface notifications are separated on zapi interface between the system (zebra daemon) and other daemons (bfd for instance). In the case of bfd, the initial code was waiting for vrf notification to create the socket. Actually, in vrf-lite world, we need to wait the vrf interface to be present, in order to create the socket and bind to the vrf interface (this is the usual way to work with vrf-lite). On bfd, the changes consist in delaying the socket creation first, then when interface is created, check the interface name presence instead of checking the interface configuration. Signed-off-by: Philippe Guibert --- bfdd/bfd.c | 7 +++++++ bfdd/ptm_adapter.c | 19 +++++++++++++------ 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/bfdd/bfd.c b/bfdd/bfd.c index 9667ba8708..622b6ef396 100644 --- a/bfdd/bfd.c +++ b/bfdd/bfd.c @@ -313,6 +313,13 @@ int bfd_session_enable(struct bfd_session *bs) } } + if (!vrf_is_backend_netns() && vrf && vrf->vrf_id != VRF_DEFAULT + && !if_lookup_by_name(vrf->name, vrf->vrf_id)) { + zlog_err("session-enable: vrf interface %s not available yet", + vrf->name); + return 0; + } + if (bs->key.ifname[0]) { if (vrf) ifp = if_lookup_by_name(bs->key.ifname, vrf->vrf_id); diff --git a/bfdd/ptm_adapter.c b/bfdd/ptm_adapter.c index 44519c47b5..26ff7bd188 100644 --- a/bfdd/ptm_adapter.c +++ b/bfdd/ptm_adapter.c @@ -669,17 +669,24 @@ static void bfdd_sessions_enable_interface(struct interface *ifp) struct bfd_session *bs; struct vrf *vrf; + vrf = vrf_lookup_by_id(ifp->vrf_id); + if (!vrf) + return; + TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) { bs = bso->bso_bs; - /* Interface name mismatch. */ - if (strcmp(ifp->name, bs->key.ifname)) - continue; - vrf = vrf_lookup_by_id(ifp->vrf_id); - if (!vrf) - continue; + /* check vrf name */ if (bs->key.vrfname[0] && strcmp(vrf->name, bs->key.vrfname)) continue; + + /* If Interface matches vrfname, then bypass iface check */ + if (vrf_is_backend_netns() || strcmp(ifp->name, vrf->name)) { + /* Interface name mismatch. */ + if (strcmp(ifp->name, bs->key.ifname)) + continue; + } + /* Skip enabled sessions. */ if (bs->sock != -1) continue; From 134a53ec48255a492787a711a65693c7201201c7 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Fri, 8 Jan 2021 09:38:04 +0000 Subject: [PATCH 3/4] bfdd: update vrf of received packet on vrf-lite environment, all incoming bfd packets are received by the same socket on the default namespace. the vrfid is not relevant and needs to be updated based on the incoming interface where traffic has been received. If the traffic is received from an interface belonging to a separate vrf, update the vrfid value accordingly. Signed-off-by: Philippe Guibert --- bfdd/bfd_packet.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/bfdd/bfd_packet.c b/bfdd/bfd_packet.c index 10b99a62a9..076318e6ca 100644 --- a/bfdd/bfd_packet.c +++ b/bfdd/bfd_packet.c @@ -543,6 +543,7 @@ int bfd_recv_cb(struct thread *t) ifindex_t ifindex = IFINDEX_INTERNAL; struct sockaddr_any local, peer; uint8_t msgbuf[1516]; + struct interface *ifp = NULL; struct bfd_vrf_global *bvrf = THREAD_ARG(t); vrfid = bvrf->vrf->vrf_id; @@ -572,6 +573,15 @@ int bfd_recv_cb(struct thread *t) &local, &peer); } + /* update vrf-id because when in vrf-lite mode, + * the socket is on default namespace + */ + if (ifindex) { + ifp = if_lookup_by_index(ifindex, vrfid); + if (ifp) + vrfid = ifp->vrf_id; + } + /* Implement RFC 5880 6.8.6 */ if (mlen < BFD_PKT_LEN) { cp_debug(is_mhop, &peer, &local, ifindex, vrfid, From 99950bc559cd2b466e4d02447fa6c1ecc5395270 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Fri, 8 Jan 2021 15:17:28 +0000 Subject: [PATCH 4/4] bfdd: improve some debug messages related to zebra notifications when receiving interface and address notifications, one may be puzzled by the information since for example, the presence of an interface is not enough to use it in a bfd session, simply because the interface is in the wrong vrf. add VRF information on those traces. Signed-off-by: Philippe Guibert --- bfdd/bfd.c | 6 ++++-- bfdd/ptm_adapter.c | 11 ++++++----- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/bfdd/bfd.c b/bfdd/bfd.c index 622b6ef396..ca4bf94955 100644 --- a/bfdd/bfd.c +++ b/bfdd/bfd.c @@ -327,14 +327,16 @@ int bfd_session_enable(struct bfd_session *bs) ifp = if_lookup_by_name_all_vrf(bs->key.ifname); if (ifp == NULL) { zlog_err( - "session-enable: specified interface doesn't exists."); + "session-enable: specified interface %s (VRF %s) doesn't exist.", + bs->key.ifname, vrf ? vrf->name : ""); return 0; } if (bs->key.ifname[0] && !vrf) { vrf = vrf_lookup_by_id(ifp->vrf_id); if (vrf == NULL) { zlog_err( - "session-enable: specified VRF doesn't exists."); + "session-enable: specified VRF %u doesn't exist.", + ifp->vrf_id); return 0; } } diff --git a/bfdd/ptm_adapter.c b/bfdd/ptm_adapter.c index 26ff7bd188..57fb81aa27 100644 --- a/bfdd/ptm_adapter.c +++ b/bfdd/ptm_adapter.c @@ -766,7 +766,8 @@ void bfdd_sessions_disable_vrf(struct vrf *vrf) static int bfd_ifp_destroy(struct interface *ifp) { if (bglobal.debug_zebra) - zlog_debug("zclient: delete interface %s", ifp->name); + zlog_debug("zclient: delete interface %s (VRF %u)", ifp->name, + ifp->vrf_id); bfdd_sessions_disable_interface(ifp); @@ -819,10 +820,10 @@ static int bfdd_interface_address_update(ZAPI_CALLBACK_ARGS) return 0; if (bglobal.debug_zebra) - zlog_debug("zclient: %s local address %pFX", + zlog_debug("zclient: %s local address %pFX (VRF %u)", cmd == ZEBRA_INTERFACE_ADDRESS_ADD ? "add" : "delete", - ifc->address); + ifc->address, vrf_id); if (cmd == ZEBRA_INTERFACE_ADDRESS_ADD) bfdd_sessions_enable_address(ifc); @@ -835,8 +836,8 @@ static int bfdd_interface_address_update(ZAPI_CALLBACK_ARGS) static int bfd_ifp_create(struct interface *ifp) { if (bglobal.debug_zebra) - zlog_debug("zclient: add interface %s", ifp->name); - + zlog_debug("zclient: add interface %s (VRF %u)", ifp->name, + ifp->vrf_id); bfdd_sessions_enable_interface(ifp); return 0;