From 262e1d2528e866d5608a3cf337c7761e35160926 Mon Sep 17 00:00:00 2001 From: Rafael Zalamena Date: Tue, 11 Aug 2020 14:43:56 -0300 Subject: [PATCH] bfdd: implement minimum TTL Initial BFD protocol implementation had a hard coded value of maximum 5 hops, now we have a configurable hop amount with a safe default of 1 hop. Signed-off-by: Rafael Zalamena --- bfdd/bfd.c | 12 ++++++ bfdd/bfd.h | 5 ++- bfdd/bfd_packet.c | 6 +-- bfdd/bfdctl.h | 3 ++ bfdd/bfdd_cli.c | 51 +++++++++++++++++++++++++ bfdd/bfdd_nb.c | 16 ++++++++ bfdd/bfdd_nb.h | 8 ++++ bfdd/bfdd_nb_config.c | 87 +++++++++++++++++++++++++++++++++++++++++++ bfdd/bfdd_vty.c | 4 ++ bfdd/ptm_adapter.c | 14 ++++++- 10 files changed, 200 insertions(+), 6 deletions(-) diff --git a/bfdd/bfd.c b/bfdd/bfd.c index 1fc9224752..2b3caa6fef 100644 --- a/bfdd/bfd.c +++ b/bfdd/bfd.c @@ -89,6 +89,7 @@ static void bfd_profile_set_default(struct bfd_profile *bp) bp->detection_multiplier = BFD_DEFDETECTMULT; bp->echo_mode = false; bp->passive = false; + bp->minimum_ttl = BFD_DEF_MHOP_TTL; bp->min_echo_rx = BFD_DEF_REQ_MIN_ECHO; bp->min_rx = BFD_DEFREQUIREDMINRX; bp->min_tx = BFD_DEFDESIREDMINTX; @@ -190,6 +191,12 @@ void bfd_session_apply(struct bfd_session *bs) bfd_set_echo(bs, bp->echo_mode); else bfd_set_echo(bs, bs->peer_profile.echo_mode); + } else { + /* Configure the TTL packet filter. */ + if (bs->peer_profile.minimum_ttl == BFD_DEF_MHOP_TTL) + bs->mh_ttl = bp->minimum_ttl; + else + bs->mh_ttl = bs->peer_profile.minimum_ttl; } /* Toggle 'passive-mode' if default value. */ @@ -752,6 +759,11 @@ static void _bfd_session_update(struct bfd_session *bs, else UNSET_FLAG(bs->flags, BFD_SESS_FLAG_CBIT); + if (bpc->bpc_has_minimum_ttl) { + bs->mh_ttl = bpc->bpc_minimum_ttl; + bs->peer_profile.minimum_ttl = bpc->bpc_minimum_ttl; + } + bs->peer_profile.echo_mode = bpc->bpc_echo; bfd_set_echo(bs, bpc->bpc_echo); diff --git a/bfdd/bfd.h b/bfdd/bfd.h index 4f88e6b2ec..af3f92d6a8 100644 --- a/bfdd/bfd.h +++ b/bfdd/bfd.h @@ -210,6 +210,8 @@ struct bfd_profile { bool admin_shutdown; /** Passive mode. */ bool passive; + /** Minimum expected TTL value. */ + uint8_t minimum_ttl; /** Echo mode (only applies to single hop). */ bool echo_mode; @@ -331,7 +333,8 @@ TAILQ_HEAD(obslist, bfd_session_observer); #define BFD_DEFREQUIREDMINRX (300 * 1000) /* microseconds. */ #define BFD_DEF_REQ_MIN_ECHO (50 * 1000) /* microseconds. */ #define BFD_DEF_SLOWTX (1000 * 1000) /* microseconds. */ -#define BFD_DEF_MHOP_TTL 5 +/** Minimum multi hop TTL. */ +#define BFD_DEF_MHOP_TTL 254 #define BFD_PKT_LEN 24 /* Length of control packet */ #define BFD_TTL_VAL 255 #define BFD_RCV_TTL_VAL 1 diff --git a/bfdd/bfd_packet.c b/bfdd/bfd_packet.c index 68bdd89bb7..38855acffc 100644 --- a/bfdd/bfd_packet.c +++ b/bfdd/bfd_packet.c @@ -577,7 +577,7 @@ int bfd_recv_cb(struct thread *t) return 0; } - /* Validate packet TTL. */ + /* Validate single hop packet TTL. */ if ((!is_mhop) && (ttl != BFD_TTL_VAL)) { cp_debug(is_mhop, &peer, &local, ifindex, vrfid, "invalid TTL: %d expected %d", ttl, BFD_TTL_VAL); @@ -630,10 +630,10 @@ int bfd_recv_cb(struct thread *t) * Single hop: set local address that received the packet. */ if (is_mhop) { - if ((BFD_TTL_VAL - bfd->mh_ttl) > BFD_TTL_VAL) { + if (ttl < bfd->mh_ttl) { cp_debug(is_mhop, &peer, &local, ifindex, vrfid, "exceeded max hop count (expected %d, got %d)", - bfd->mh_ttl, BFD_TTL_VAL); + bfd->mh_ttl, ttl); return 0; } } else if (bfd->local_address.sa_sin.sin_family == AF_UNSPEC) { diff --git a/bfdd/bfdctl.h b/bfdd/bfdctl.h index 3cb2fba49a..e1cff9a31c 100644 --- a/bfdd/bfdctl.h +++ b/bfdd/bfdctl.h @@ -84,6 +84,9 @@ struct bfd_peer_cfg { bool bpc_has_echointerval; uint64_t bpc_echointerval; + bool bpc_has_minimum_ttl; + uint8_t bpc_minimum_ttl; + bool bpc_echo; bool bpc_createonly; bool bpc_shutdown; diff --git a/bfdd/bfdd_cli.c b/bfdd/bfdd_cli.c index e70354de05..058ce7d1f2 100644 --- a/bfdd/bfdd_cli.c +++ b/bfdd/bfdd_cli.c @@ -286,6 +286,42 @@ void bfd_cli_show_passive(struct vty *vty, struct lyd_node *dnode, yang_dnode_get_bool(dnode, NULL) ? "" : "no "); } +DEFPY_YANG( + bfd_peer_minimum_ttl, bfd_peer_minimum_ttl_cmd, + "[no] minimum-ttl (1-254)$ttl", + NO_STR + "Expect packets with at least this TTL\n" + "Minimum TTL expected\n") +{ + if (no) + nb_cli_enqueue_change(vty, "./minimum-ttl", NB_OP_DESTROY, + NULL); + else + nb_cli_enqueue_change(vty, "./minimum-ttl", NB_OP_MODIFY, + ttl_str); + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY_YANG( + no_bfd_peer_minimum_ttl, no_bfd_peer_minimum_ttl_cmd, + "no minimum-ttl", + NO_STR + "Expect packets with at least this TTL\n") +{ + nb_cli_enqueue_change(vty, "./minimum-ttl", NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} + +void bfd_cli_show_minimum_ttl(struct vty *vty, struct lyd_node *dnode, + bool show_defaults) +{ + if (show_defaults) + vty_out(vty, " minimum-ttl 254\n"); + else + vty_out(vty, " minimum-ttl %s\n", + yang_dnode_get_string(dnode, NULL)); +} + DEFPY_YANG( bfd_peer_mult, bfd_peer_mult_cmd, "detect-multiplier (2-255)$multiplier", @@ -488,6 +524,17 @@ ALIAS_YANG(bfd_peer_passive, bfd_profile_passive_cmd, NO_STR "Don't attempt to start sessions\n") +ALIAS_YANG(bfd_peer_minimum_ttl, bfd_profile_minimum_ttl_cmd, + "[no] minimum-ttl (1-254)$ttl", + NO_STR + "Expect packets with at least this TTL\n" + "Minimum TTL expected\n") + +ALIAS_YANG(no_bfd_peer_minimum_ttl, no_bfd_profile_minimum_ttl_cmd, + "no minimum-ttl", + NO_STR + "Expect packets with at least this TTL\n") + ALIAS_YANG(bfd_peer_echo, bfd_profile_echo_cmd, "[no] echo-mode", NO_STR @@ -557,6 +604,8 @@ bfdd_cli_init(void) install_element(BFD_PEER_NODE, &bfd_peer_echo_interval_cmd); install_element(BFD_PEER_NODE, &bfd_peer_profile_cmd); install_element(BFD_PEER_NODE, &bfd_peer_passive_cmd); + install_element(BFD_PEER_NODE, &bfd_peer_minimum_ttl_cmd); + install_element(BFD_PEER_NODE, &no_bfd_peer_minimum_ttl_cmd); /* Profile commands. */ cmd_variable_handler_register(bfd_vars); @@ -574,4 +623,6 @@ bfdd_cli_init(void) install_element(BFD_PROFILE_NODE, &bfd_profile_echo_cmd); install_element(BFD_PROFILE_NODE, &bfd_profile_echo_interval_cmd); install_element(BFD_PROFILE_NODE, &bfd_profile_passive_cmd); + install_element(BFD_PROFILE_NODE, &bfd_profile_minimum_ttl_cmd); + install_element(BFD_PROFILE_NODE, &no_bfd_profile_minimum_ttl_cmd); } diff --git a/bfdd/bfdd_nb.c b/bfdd/bfdd_nb.c index cf063f82fc..64ba3cf811 100644 --- a/bfdd/bfdd_nb.c +++ b/bfdd/bfdd_nb.c @@ -84,6 +84,14 @@ const struct frr_yang_module_info frr_bfdd_info = { .cli_show = bfd_cli_show_passive, } }, + { + .xpath = "/frr-bfdd:bfdd/bfd/profile/minimum-ttl", + .cbs = { + .modify = bfdd_bfd_profile_minimum_ttl_modify, + .destroy = bfdd_bfd_profile_minimum_ttl_destroy, + .cli_show = bfd_cli_show_minimum_ttl, + } + }, { .xpath = "/frr-bfdd:bfdd/bfd/profile/echo-mode", .cbs = { @@ -349,6 +357,14 @@ const struct frr_yang_module_info frr_bfdd_info = { .cli_show = bfd_cli_show_passive, } }, + { + .xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop/minimum-ttl", + .cbs = { + .modify = bfdd_bfd_sessions_multi_hop_minimum_ttl_modify, + .destroy = bfdd_bfd_sessions_multi_hop_minimum_ttl_destroy, + .cli_show = bfd_cli_show_minimum_ttl, + } + }, { .xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop/stats/local-discriminator", .cbs = { diff --git a/bfdd/bfdd_nb.h b/bfdd/bfdd_nb.h index ec467f357f..fbd557b6b1 100644 --- a/bfdd/bfdd_nb.h +++ b/bfdd/bfdd_nb.h @@ -38,6 +38,8 @@ int bfdd_bfd_profile_required_receive_interval_modify( struct nb_cb_modify_args *args); int bfdd_bfd_profile_administrative_down_modify(struct nb_cb_modify_args *args); int bfdd_bfd_profile_passive_mode_modify(struct nb_cb_modify_args *args); +int bfdd_bfd_profile_minimum_ttl_modify(struct nb_cb_modify_args *args); +int bfdd_bfd_profile_minimum_ttl_destroy(struct nb_cb_destroy_args *args); int bfdd_bfd_profile_echo_mode_modify(struct nb_cb_modify_args *args); int bfdd_bfd_profile_desired_echo_transmission_interval_modify( struct nb_cb_modify_args *args); @@ -134,6 +136,10 @@ int bfdd_bfd_sessions_multi_hop_required_receive_interval_modify( struct nb_cb_modify_args *args); int bfdd_bfd_sessions_multi_hop_administrative_down_modify( struct nb_cb_modify_args *args); +int bfdd_bfd_sessions_multi_hop_minimum_ttl_modify( + struct nb_cb_modify_args *args); +int bfdd_bfd_sessions_multi_hop_minimum_ttl_destroy( + struct nb_cb_destroy_args *args); struct yang_data * bfdd_bfd_sessions_multi_hop_stats_local_discriminator_get_elem( struct nb_cb_get_elem_args *args); @@ -211,5 +217,7 @@ void bfd_cli_peer_profile_show(struct vty *vty, struct lyd_node *dnode, bool show_defaults); void bfd_cli_show_passive(struct vty *vty, struct lyd_node *dnode, bool show_defaults); +void bfd_cli_show_minimum_ttl(struct vty *vty, struct lyd_node *dnode, + bool show_defaults); #endif /* _FRR_BFDD_NB_H_ */ diff --git a/bfdd/bfdd_nb_config.c b/bfdd/bfdd_nb_config.c index 527c6d83ad..0046bc625b 100644 --- a/bfdd/bfdd_nb_config.c +++ b/bfdd/bfdd_nb_config.c @@ -381,6 +381,42 @@ int bfdd_bfd_profile_passive_mode_modify(struct nb_cb_modify_args *args) return NB_OK; } +/* + * XPath: /frr-bfdd:bfdd/bfd/profile/minimum-ttl + */ +int bfdd_bfd_profile_minimum_ttl_modify(struct nb_cb_modify_args *args) +{ + struct bfd_profile *bp; + uint8_t minimum_ttl; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + minimum_ttl = yang_dnode_get_uint8(args->dnode, NULL); + bp = nb_running_get_entry(args->dnode, NULL, true); + if (bp->minimum_ttl == minimum_ttl) + return NB_OK; + + bp->minimum_ttl = minimum_ttl; + bfd_profile_update(bp); + + return NB_OK; +} + +int bfdd_bfd_profile_minimum_ttl_destroy(struct nb_cb_destroy_args *args) +{ + struct bfd_profile *bp; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + bp = nb_running_get_entry(args->dnode, NULL, true); + bp->minimum_ttl = BFD_DEF_MHOP_TTL; + bfd_profile_update(bp); + + return NB_OK; +} + /* * XPath: /frr-bfdd:bfdd/bfd/profile/echo-mode */ @@ -739,3 +775,54 @@ int bfdd_bfd_sessions_multi_hop_destroy(struct nb_cb_destroy_args *args) { return bfd_session_destroy(args->event, args->dnode, true); } + +/* + * XPath: /frr-bfdd:bfdd/bfd/sessions/multi-hop/minimum-ttl + */ +int bfdd_bfd_sessions_multi_hop_minimum_ttl_modify( + struct nb_cb_modify_args *args) +{ + struct bfd_session *bs; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + return NB_OK; + + case NB_EV_APPLY: + break; + + case NB_EV_ABORT: + return NB_OK; + } + + bs = nb_running_get_entry(args->dnode, NULL, true); + bs->peer_profile.minimum_ttl = yang_dnode_get_uint8(args->dnode, NULL); + bfd_session_apply(bs); + + return NB_OK; +} + +int bfdd_bfd_sessions_multi_hop_minimum_ttl_destroy( + struct nb_cb_destroy_args *args) +{ + struct bfd_session *bs; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + return NB_OK; + + case NB_EV_APPLY: + break; + + case NB_EV_ABORT: + return NB_OK; + } + + bs = nb_running_get_entry(args->dnode, NULL, true); + bs->peer_profile.minimum_ttl = BFD_DEF_MHOP_TTL; + bfd_session_apply(bs); + + return NB_OK; +} diff --git a/bfdd/bfdd_vty.c b/bfdd/bfdd_vty.c index a532b76f0e..a3f1638e5f 100644 --- a/bfdd/bfdd_vty.c +++ b/bfdd/bfdd_vty.c @@ -115,6 +115,8 @@ static void _display_peer(struct vty *vty, struct bfd_session *bs) vty_out(vty, "\t\tPassive mode\n"); else vty_out(vty, "\t\tActive mode\n"); + if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) + vty_out(vty, "\t\tMinimum TTL: %d\n", bs->mh_ttl); vty_out(vty, "\t\tStatus: "); switch (bs->ses_state) { @@ -209,6 +211,8 @@ static struct json_object *__display_peer_json(struct bfd_session *bs) json_object_int_add(jo, "remote-id", bs->discrs.remote_discr); json_object_boolean_add(jo, "passive-mode", CHECK_FLAG(bs->flags, BFD_SESS_FLAG_PASSIVE)); + if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) + json_object_int_add(jo, "minimum-ttl", bs->mh_ttl); switch (bs->ses_state) { case PTM_BFD_ADM_DOWN: diff --git a/bfdd/ptm_adapter.c b/bfdd/ptm_adapter.c index 8134807a14..48e55bce37 100644 --- a/bfdd/ptm_adapter.c +++ b/bfdd/ptm_adapter.c @@ -303,7 +303,6 @@ 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; - uint8_t ttl __attribute__((unused)); size_t ifnamelen; /* @@ -375,7 +374,18 @@ static int _ptm_msg_read(struct stream *msg, int command, vrf_id_t vrf_id, if (bpc->bpc_mhop) { /* Read multihop source address and TTL. */ _ptm_msg_read_address(msg, &bpc->bpc_local); - STREAM_GETC(msg, ttl); + STREAM_GETC(msg, bpc->bpc_minimum_ttl); + if (bpc->bpc_minimum_ttl >= BFD_TTL_VAL + || bpc->bpc_minimum_ttl == 0) { + zlog_warn("%s: received invalid TTL configuration %d", + __func__, bpc->bpc_has_minimum_ttl); + bpc->bpc_minimum_ttl = BFD_DEF_MHOP_TTL; + bpc->bpc_has_minimum_ttl = false; + } else { + bpc->bpc_minimum_ttl = + (BFD_TTL_VAL + 1) - bpc->bpc_minimum_ttl; + bpc->bpc_has_minimum_ttl = true; + } } else { /* If target is IPv6, then we must obtain local address. */ if (bpc->bpc_ipv4 == false) -- 2.39.5