From 3d7ffd4ae086149658c708c66d177c1393e62b9f Mon Sep 17 00:00:00 2001 From: Rafael Zalamena Date: Wed, 2 Oct 2024 16:53:05 -0300 Subject: [PATCH] bfdd: disable echo socket when not using it Lets avoid a performance penalty in forwarding when not using the BFD echo feature. The echo socket uses raw packet capturing along with a BPF filter which causes performance issues. Signed-off-by: Rafael Zalamena --- bfdd/bfd.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 66 insertions(+), 10 deletions(-) diff --git a/bfdd/bfd.c b/bfdd/bfd.c index eb9c3003135f..d41f2b4192e4 100644 --- a/bfdd/bfd.c +++ b/bfdd/bfd.c @@ -1149,6 +1149,8 @@ void bs_set_slow_timers(struct bfd_session *bs) bs->xmt_TO = BFD_DEF_SLOWTX; } +static void bfd_vrf_toggle_echo(struct bfd_vrf_global *bfd_vrf); + void bfd_set_echo(struct bfd_session *bs, bool echo) { if (echo) { @@ -1172,6 +1174,8 @@ void bfd_set_echo(struct bfd_session *bs, bool echo) if (bs->bdc == NULL) ptm_bfd_echo_stop(bs); } + + bfd_vrf_toggle_echo(bs->vrf->info); } void bfd_set_shutdown(struct bfd_session *bs, bool shutdown) @@ -1800,6 +1804,67 @@ void bfd_profiles_remove(void) bfd_profile_free(bp); } +struct _bfd_session_has_echo { + /* VRF peers must match */ + struct vrf *vrf; + /* Echo enabled or not */ + bool enabled; +}; + +static int _bfd_session_has_echo(struct hash_bucket *hb, void *arg) +{ + const struct bfd_session *session = hb->data; + struct _bfd_session_has_echo *has_echo = arg; + + if (session->vrf != has_echo->vrf) + return HASHWALK_CONTINUE; + if (!CHECK_FLAG(session->flags, BFD_SESS_FLAG_ECHO)) + return HASHWALK_CONTINUE; + + has_echo->enabled = true; + return HASHWALK_ABORT; +} + +static void bfd_vrf_toggle_echo(struct bfd_vrf_global *bfd_vrf) +{ + struct _bfd_session_has_echo has_echo = {}; + + /* Check for peers using echo */ + hash_walk(bfd_id_hash, _bfd_session_has_echo, &has_echo); + + /* + * No peers using echo, close all echo sockets. + */ + if (!has_echo.enabled) { + if (bfd_vrf->bg_echo != -1) { + close(bfd_vrf->bg_echo); + bfd_vrf->bg_echo = -1; + event_cancel(&bfd_vrf->bg_ev[4]); + } + + if (bfd_vrf->bg_echov6 != -1) { + close(bfd_vrf->bg_echov6); + bfd_vrf->bg_echov6 = -1; + event_cancel(&bfd_vrf->bg_ev[5]); + } + return; + } + + /* + * At least one peer using echo, open echo sockets. + */ + if (bfd_vrf->bg_echo == -1) + bfd_vrf->bg_echo = bp_echo_socket(bfd_vrf->vrf); + + if (bfd_vrf->bg_echov6 == -1) + bfd_vrf->bg_echov6 = bp_echo_socket(bfd_vrf->vrf); + + if (!bfd_vrf->bg_ev[4] && bfd_vrf->bg_echo != -1) + event_add_read(master, bfd_recv_cb, bfd_vrf, bfd_vrf->bg_echo, &bfd_vrf->bg_ev[4]); + if (!bfd_vrf->bg_ev[5] && bfd_vrf->bg_echov6 != -1) + event_add_read(master, bfd_recv_cb, bfd_vrf, bfd_vrf->bg_echov6, &bfd_vrf->bg_ev[5]); +} + /* * Profile related hash functions. */ @@ -1889,10 +1954,7 @@ static int bfd_vrf_enable(struct vrf *vrf) bvrf->bg_shop6 = bp_udp6_shop(vrf); if (!bvrf->bg_mhop6) bvrf->bg_mhop6 = bp_udp6_mhop(vrf); - if (!bvrf->bg_echo) - bvrf->bg_echo = bp_echo_socket(vrf); - if (!bvrf->bg_echov6) - bvrf->bg_echov6 = bp_echov6_socket(vrf); + bfd_vrf_toggle_echo(bvrf); if (!bvrf->bg_ev[0] && bvrf->bg_shop != -1) event_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_shop, @@ -1906,12 +1968,6 @@ static int bfd_vrf_enable(struct vrf *vrf) if (!bvrf->bg_ev[3] && bvrf->bg_mhop6 != -1) event_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_mhop6, &bvrf->bg_ev[3]); - if (!bvrf->bg_ev[4] && bvrf->bg_echo != -1) - event_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_echo, - &bvrf->bg_ev[4]); - if (!bvrf->bg_ev[5] && bvrf->bg_echov6 != -1) - event_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);