From ccc9ada8681471ab6093502686ddd9122058dcbe Mon Sep 17 00:00:00 2001 From: Rafael Zalamena Date: Fri, 15 May 2020 17:38:04 -0300 Subject: [PATCH] bfdd: implement BFD session configuration profiles Allow user to pre-configure peers with a profile. If a peer is using a profile any configuration made to the peer will take precedence over the profile configuration. In order to track the peer configuration we have now an extra copy of the peer configuration in `peer_profile` inside `struct bfd_session`. This information will help the profile functions to detect user configurations and avoid overriding what the user configured. This is especially important for peers created via other protocols where the default `shutdown` state is disabled (peers created manually are `shutdown` by default). Profiles can be used before they exist: if no profile exists then it will use the default configuration. Signed-off-by: Rafael Zalamena --- bfdd/bfd.c | 224 +++++++++++++++++++++++++++++++++++++-- bfdd/bfd.h | 86 +++++++++++++++ bfdd/bfdd_cli.c | 104 +++++++++++++++++- bfdd/bfdd_nb.c | 67 ++++++++++++ bfdd/bfdd_nb.h | 19 ++++ bfdd/bfdd_nb_config.c | 241 ++++++++++++++++++++++++++++++++++++++++++ bfdd/ptm_adapter.c | 3 + 7 files changed, 737 insertions(+), 7 deletions(-) diff --git a/bfdd/bfd.c b/bfdd/bfd.c index e5432af553..770d923d32 100644 --- a/bfdd/bfd.c +++ b/bfdd/bfd.c @@ -33,6 +33,7 @@ #include "bfd.h" DEFINE_MTYPE_STATIC(BFDD, BFDD_CONFIG, "long-lived configuration memory") +DEFINE_MTYPE_STATIC(BFDD, BFDD_PROFILE, "long-lived profile memory") DEFINE_MTYPE_STATIC(BFDD, BFDD_SESSION_OBSERVER, "Session observer") DEFINE_MTYPE_STATIC(BFDD, BFDD_VRF, "BFD VRF") @@ -56,9 +57,173 @@ static void bs_neighbour_admin_down_handler(struct bfd_session *bfd, /* Zeroed array with the size of an IPv6 address. */ struct in6_addr zero_addr; +/** BFD profiles list. */ +struct bfdproflist bplist; + /* * Functions */ +struct bfd_profile *bfd_profile_lookup(const char *name) +{ + struct bfd_profile *bp; + + TAILQ_FOREACH (bp, &bplist, entry) { + if (strcmp(name, bp->name)) + continue; + + return bp; + } + + return NULL; +} + +static void bfd_profile_set_default(struct bfd_profile *bp) +{ + bp->admin_shutdown = true; + bp->detection_multiplier = BFD_DEFDETECTMULT; + bp->echo_mode = false; + bp->min_echo_rx = BFD_DEF_REQ_MIN_ECHO; + bp->min_rx = BFD_DEFREQUIREDMINRX; + bp->min_tx = BFD_DEFDESIREDMINTX; +} + +struct bfd_profile *bfd_profile_new(const char *name) +{ + struct bfd_profile *bp; + + /* Search for duplicates. */ + if (bfd_profile_lookup(name) != NULL) + return NULL; + + /* Allocate, name it and put into list. */ + bp = XCALLOC(MTYPE_BFDD_PROFILE, sizeof(*bp)); + strlcpy(bp->name, name, sizeof(bp->name)); + TAILQ_INSERT_TAIL(&bplist, bp, entry); + + /* Set default values. */ + bfd_profile_set_default(bp); + + return bp; +} + +void bfd_profile_free(struct bfd_profile *bp) +{ + TAILQ_REMOVE(&bplist, bp, entry); + free(bp); +} + +/** + * Removes a profile and tests whether it needs to apply the changes or not. + * + * \param bs the BFD session. + * \param apply whether or not to apply configurations immediately. + */ +static void _bfd_profile_remove(struct bfd_session *bs, bool apply) +{ + struct bfd_profile *bp; + + /* No profile applied, nothing to do. */ + bp = bs->profile; + if (bp == NULL) + return; + + /* Remove the profile association. */ + bs->profile = NULL; + + /* Set multiplier to the default. */ + bs->detect_mult = bs->peer_profile.detection_multiplier; + + /* Set timers back to user configuration. */ + bs->timers.desired_min_tx = bs->peer_profile.min_tx; + bs->timers.required_min_rx = bs->peer_profile.min_rx; + + /* We can only apply echo options on single hop sessions. */ + if (!CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) { + /* Set default echo timer. */ + bs->timers.required_min_echo = bs->peer_profile.min_echo_rx; + + /* Default is no echo mode. */ + if (apply) + bfd_set_echo(bs, bs->peer_profile.echo_mode); + } + + if (apply) + bfd_set_shutdown(bs, bs->peer_profile.admin_shutdown); +} + +void bfd_profile_apply(const char *profname, struct bfd_session *bs) +{ + struct bfd_profile *bp; + + /* Remove previous profile if any. */ + if (bs->profile_name) { + _bfd_profile_remove(bs, false); + + /* We are changing profiles. */ + if (strcmp(bs->profile_name, profname)) { + XFREE(MTYPE_BFDD_PROFILE, bs->profile_name); + bs->profile_name = + XSTRDUP(MTYPE_BFDD_PROFILE, profname); + } + } else /* Save the current profile name (in case it doesn't exist). */ + bs->profile_name = XSTRDUP(MTYPE_BFDD_PROFILE, profname); + + /* Look up new profile to apply. */ + bp = bfd_profile_lookup(profname); + if (bp == NULL) + return; + + /* Point to profile if it exists. */ + bs->profile = bp; + + /* Set multiplier if not the default. */ + if (bs->peer_profile.detection_multiplier == BFD_DEFDETECTMULT) + bs->detect_mult = bp->detection_multiplier; + else + bs->detect_mult = bs->peer_profile.detection_multiplier; + + /* Set timers if not the default. */ + if (bs->peer_profile.min_tx == BFD_DEFDESIREDMINTX) + bs->timers.desired_min_tx = bp->min_tx; + else + bs->timers.desired_min_tx = bs->peer_profile.min_tx; + + if (bs->peer_profile.min_rx == BFD_DEFREQUIREDMINRX) + bs->timers.required_min_rx = bp->min_rx; + else + bs->timers.required_min_rx = bs->peer_profile.min_rx; + + /* We can only apply echo options on single hop sessions. */ + if (!CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) { + /* Configure remote echo if it was default. */ + if (bs->peer_profile.min_echo_rx == BFD_DEF_REQ_MIN_ECHO) + bs->timers.required_min_echo = bp->min_echo_rx; + else + bs->timers.required_min_echo = + bs->peer_profile.min_echo_rx; + + /* Toggle echo if default value. */ + if (bs->peer_profile.echo_mode == false) + bfd_set_echo(bs, bp->echo_mode); + else + bfd_set_echo(bs, bs->peer_profile.echo_mode); + } + + /* Toggle 'no shutdown' if default value. */ + if (bs->peer_profile.admin_shutdown) + bfd_set_shutdown(bs, bp->admin_shutdown); + else + bfd_set_shutdown(bs, bs->peer_profile.admin_shutdown); +} + +void bfd_profile_remove(struct bfd_session *bs) +{ + /* Remove any previous set profile name. */ + XFREE(MTYPE_BFDD_PROFILE, bs->profile_name); + + _bfd_profile_remove(bs, true); +} + void gen_bfd_key(struct bfd_key *key, struct sockaddr_any *peer, struct sockaddr_any *local, bool mhop, const char *ifname, const char *vrfname) @@ -494,6 +659,9 @@ struct bfd_session *bfd_session_new(void) bs = XCALLOC(MTYPE_BFDD_CONFIG, sizeof(*bs)); + /* Set peer session defaults. */ + bfd_profile_set_default(&bs->peer_profile); + bs->timers.desired_min_tx = BFD_DEFDESIREDMINTX; bs->timers.required_min_rx = BFD_DEFREQUIREDMINRX; bs->timers.required_min_echo = BFD_DEF_REQ_MIN_ECHO; @@ -550,17 +718,25 @@ int bfd_session_update_label(struct bfd_session *bs, const char *nlabel) static void _bfd_session_update(struct bfd_session *bs, struct bfd_peer_cfg *bpc) { - if (bpc->bpc_has_txinterval) + if (bpc->bpc_has_txinterval) { bs->timers.desired_min_tx = bpc->bpc_txinterval * 1000; + bs->peer_profile.min_tx = bs->timers.desired_min_tx; + } - if (bpc->bpc_has_recvinterval) + if (bpc->bpc_has_recvinterval) { bs->timers.required_min_rx = bpc->bpc_recvinterval * 1000; + bs->peer_profile.min_rx = bs->timers.required_min_rx; + } - if (bpc->bpc_has_detectmultiplier) + if (bpc->bpc_has_detectmultiplier) { bs->detect_mult = bpc->bpc_detectmultiplier; + bs->peer_profile.detection_multiplier = bs->detect_mult; + } - if (bpc->bpc_has_echointerval) + if (bpc->bpc_has_echointerval) { bs->timers.required_min_echo = bpc->bpc_echointerval * 1000; + bs->peer_profile.min_echo_rx = bs->timers.required_min_echo; + } if (bpc->bpc_has_label) bfd_session_update_label(bs, bpc->bpc_label); @@ -570,12 +746,14 @@ static void _bfd_session_update(struct bfd_session *bs, else UNSET_FLAG(bs->flags, BFD_SESS_FLAG_CBIT); + bs->peer_profile.echo_mode = bpc->bpc_echo; bfd_set_echo(bs, bpc->bpc_echo); /* * Shutdown needs to be the last in order to avoid timers enable when * the session is disabled. */ + bs->peer_profile.admin_shutdown = bpc->bpc_shutdown; bfd_set_shutdown(bs, bpc->bpc_shutdown); } @@ -613,6 +791,7 @@ void bfd_session_free(struct bfd_session *bs) pl_free(bs->pl); + XFREE(MTYPE_BFDD_PROFILE, bs->profile_name); XFREE(MTYPE_BFDD_CONFIG, bs); } @@ -1070,9 +1249,21 @@ void bfd_set_echo(struct bfd_session *bs, bool echo) void bfd_set_shutdown(struct bfd_session *bs, bool shutdown) { + bool is_shutdown; + + /* + * Special case: we are batching changes and the previous state was + * not shutdown. Instead of potentially disconnect a running peer, + * we'll get the current status to validate we were really down. + */ + if (bs->ses_state == PTM_BFD_UP) + is_shutdown = false; + else + is_shutdown = CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN); + if (shutdown) { /* Already shutdown. */ - if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN)) + if (is_shutdown) return; SET_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN); @@ -1092,7 +1283,7 @@ void bfd_set_shutdown(struct bfd_session *bs, bool shutdown) ptm_bfd_snd(bs, 0); } else { /* Already working. */ - if (!CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN)) + if (!is_shutdown) return; UNSET_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN); @@ -1577,6 +1768,7 @@ void bfd_initialize(void) "BFD session discriminator hash"); bfd_key_hash = hash_create(bfd_key_hash_do, bfd_key_hash_cmp, "BFD session hash"); + TAILQ_INIT(&bplist); } static void _bfd_free(struct hash_bucket *hb, @@ -1689,6 +1881,26 @@ void bfd_sessions_remove_manual(void) hash_iterate(bfd_key_hash, _bfd_session_remove_manual, NULL); } +/* + * Profile related hash functions. + */ +static void _bfd_profile_update(struct hash_bucket *hb, void *arg) +{ + struct bfd_profile *bp = arg; + struct bfd_session *bs = hb->data; + + /* This session is not using the profile. */ + if (bs->profile_name == NULL || strcmp(bs->profile_name, bp->name) != 0) + return; + + bfd_profile_apply(bp->name, bs); +} + +void bfd_profile_update(struct bfd_profile *bp) +{ + hash_iterate(bfd_key_hash, _bfd_profile_update, bp); +} + /* * VRF related functions. */ diff --git a/bfdd/bfd.h b/bfdd/bfd.h index 5a81d80424..5984662a01 100644 --- a/bfdd/bfd.h +++ b/bfdd/bfd.h @@ -192,6 +192,34 @@ struct bfd_session_stats { uint64_t znotification; }; +/** + * BFD session profile to override default configurations. + */ +struct bfd_profile { + /** Profile name. */ + char name[64]; + + /** Session detection multiplier. */ + uint8_t detection_multiplier; + /** Desired transmission interval (in microseconds). */ + uint32_t min_tx; + /** Minimum required receive interval (in microseconds). */ + uint32_t min_rx; + /** Administrative state. */ + bool admin_shutdown; + + /** Echo mode (only applies to single hop). */ + bool echo_mode; + /** Minimum required echo receive interval (in microseconds). */ + uint32_t min_echo_rx; + + /** Profile list entry. */ + TAILQ_ENTRY(bfd_profile) entry; +}; + +/** Profile list type. */ +TAILQ_HEAD(bfdproflist, bfd_profile); + /* bfd_session shortcut label forwarding. */ struct peer_label; @@ -210,6 +238,13 @@ struct bfd_session { uint8_t mh_ttl; uint8_t remote_cbit; + /** BFD profile name. */ + char *profile_name; + /** BFD pre configured profile. */ + struct bfd_profile *profile; + /** BFD peer configuration (without profile). */ + struct bfd_profile peer_profile; + /* Timers */ struct bfd_timers timers; struct bfd_timers cur_timers; @@ -597,6 +632,57 @@ int bfd_echo_xmt_cb(struct thread *t); extern struct in6_addr zero_addr; +/** + * Creates a new profile entry and insert into the global list. + * + * \param name the BFD profile name. + * + * \returns `NULL` if it already exists otherwise the new entry. + */ +struct bfd_profile *bfd_profile_new(const char *name); + +/** + * Search for configured BFD profiles (profile name is case insensitive). + * + * \param name the BFD profile name. + * + * \returns `NULL` if it doesn't exist otherwise the entry. + */ +struct bfd_profile *bfd_profile_lookup(const char *name); + +/** + * Removes profile from list and free memory. + * + * \param bp the BFD profile. + */ +void bfd_profile_free(struct bfd_profile *bp); + +/** + * Apply a profile configuration to an existing BFD session. The non default + * values will not be overriden. + * + * NOTE: if the profile doesn't exist yet, then the profile will be applied + * once it begins to exist. + * + * \param profile_name the BFD profile name. + * \param bs the BFD session. + */ +void bfd_profile_apply(const char *profname, struct bfd_session *bs); + +/** + * Remove any applied profile from session and revert the session + * configuration. + * + * \param bs the BFD session. + */ +void bfd_profile_remove(struct bfd_session *bs); + +/** + * Apply new profile values to sessions using it. + * + * \param[in] bp the BFD profile that got updated. + */ +void bfd_profile_update(struct bfd_profile *bp); /* * bfdd_vty.c diff --git a/bfdd/bfdd_cli.c b/bfdd/bfdd_cli.c index eda8166e68..166997e674 100644 --- a/bfdd/bfdd_cli.c +++ b/bfdd/bfdd_cli.c @@ -403,6 +403,19 @@ DEFPY_NOSH(bfd_profile, bfd_profile_cmd, BFD_PROFILE_STR BFD_PROFILE_NAME_STR) { + char xpath[XPATH_MAXLEN]; + int rv; + + snprintf(xpath, sizeof(xpath), "/frr-bfdd:bfdd/bfd/profile[name='%s']", + name); + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + + /* Apply settings immediately. */ + rv = nb_cli_apply_changes(vty, NULL); + if (rv == CMD_SUCCESS) + VTY_PUSH_XPATH(BFD_PROFILE_NODE, xpath); + return CMD_SUCCESS; } @@ -412,7 +425,71 @@ DEFPY(no_bfd_profile, no_bfd_profile_cmd, BFD_PROFILE_STR BFD_PROFILE_NAME_STR) { - return CMD_SUCCESS; + char xpath[XPATH_MAXLEN]; + + snprintf(xpath, sizeof(xpath), "/frr-bfdd:bfdd/bfd/profile[name='%s']", + name); + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + + /* Apply settings immediately. */ + return nb_cli_apply_changes(vty, NULL); +} + +void bfd_cli_show_profile(struct vty *vty, struct lyd_node *dnode, + bool show_defaults) +{ + vty_out(vty, " profile %s\n", yang_dnode_get_string(dnode, "./name")); +} + +ALIAS(bfd_peer_mult, bfd_profile_mult_cmd, + "detect-multiplier (2-255)$multiplier", + "Configure peer detection multiplier\n" + "Configure peer detection multiplier value\n") + +ALIAS(bfd_peer_tx, bfd_profile_tx_cmd, + "transmit-interval (10-60000)$interval", + "Configure peer transmit interval\n" + "Configure peer transmit interval value in milliseconds\n") + +ALIAS(bfd_peer_rx, bfd_profile_rx_cmd, + "receive-interval (10-60000)$interval", + "Configure peer receive interval\n" + "Configure peer receive interval value in milliseconds\n") + +ALIAS(bfd_peer_shutdown, bfd_profile_shutdown_cmd, + "[no] shutdown", + NO_STR + "Disable BFD peer\n") + +ALIAS(bfd_peer_echo, bfd_profile_echo_cmd, + "[no] echo-mode", + NO_STR + "Configure echo mode\n") + +ALIAS(bfd_peer_echo_interval, bfd_profile_echo_interval_cmd, + "echo-interval (10-60000)$interval", + "Configure peer echo interval\n" + "Configure peer echo interval value in milliseconds\n") + +DEFPY(bfd_peer_profile, bfd_peer_profile_cmd, + "[no] profile BFDPROF$pname", + NO_STR + "Use BFD profile settings\n" + BFD_PROFILE_NAME_STR) +{ + if (no) + nb_cli_enqueue_change(vty, "./profile", NB_OP_DESTROY, NULL); + else + nb_cli_enqueue_change(vty, "./profile", NB_OP_MODIFY, pname); + + return nb_cli_apply_changes(vty, NULL); +} + +void bfd_cli_peer_profile_show(struct vty *vty, struct lyd_node *dnode, + bool show_defaults) +{ + vty_out(vty, " profile %s\n", yang_dnode_get_string(dnode, NULL)); } struct cmd_node bfd_profile_node = { @@ -422,6 +499,21 @@ struct cmd_node bfd_profile_node = { .prompt = "%s(config-bfd-profile)# ", }; +static void bfd_profile_var(vector comps, struct cmd_token *token) +{ + extern struct bfdproflist bplist; + struct bfd_profile *bp; + + TAILQ_FOREACH (bp, &bplist, entry) { + vector_set(comps, XSTRDUP(MTYPE_COMPLETION, bp->name)); + } +} + +static const struct cmd_variable_handler bfd_vars[] = { + {.tokenname = "BFDPROF", .completions = bfd_profile_var}, + {.completions = NULL} +}; + void bfdd_cli_init(void) { @@ -437,11 +529,21 @@ bfdd_cli_init(void) install_element(BFD_PEER_NODE, &bfd_peer_tx_cmd); install_element(BFD_PEER_NODE, &bfd_peer_echo_cmd); install_element(BFD_PEER_NODE, &bfd_peer_echo_interval_cmd); + install_element(BFD_PEER_NODE, &bfd_peer_profile_cmd); /* Profile commands. */ + cmd_variable_handler_register(bfd_vars); + install_node(&bfd_profile_node); install_default(BFD_PROFILE_NODE); install_element(BFD_NODE, &bfd_profile_cmd); install_element(BFD_NODE, &no_bfd_profile_cmd); + + install_element(BFD_PROFILE_NODE, &bfd_profile_mult_cmd); + install_element(BFD_PROFILE_NODE, &bfd_profile_tx_cmd); + install_element(BFD_PROFILE_NODE, &bfd_profile_rx_cmd); + install_element(BFD_PROFILE_NODE, &bfd_profile_shutdown_cmd); + install_element(BFD_PROFILE_NODE, &bfd_profile_echo_cmd); + install_element(BFD_PROFILE_NODE, &bfd_profile_echo_interval_cmd); } diff --git a/bfdd/bfdd_nb.c b/bfdd/bfdd_nb.c index 8d46742337..2ff99ca608 100644 --- a/bfdd/bfdd_nb.c +++ b/bfdd/bfdd_nb.c @@ -40,6 +40,57 @@ const struct frr_yang_module_info frr_bfdd_info = { .cli_show_end = bfd_cli_show_header_end, } }, + { + .xpath = "/frr-bfdd:bfdd/bfd/profile", + .cbs = { + .create = bfdd_bfd_profile_create, + .destroy = bfdd_bfd_profile_destroy, + .cli_show = bfd_cli_show_profile, + .cli_show_end = bfd_cli_show_peer_end, + } + }, + { + .xpath = "/frr-bfdd:bfdd/bfd/profile/detection-multiplier", + .cbs = { + .modify = bfdd_bfd_profile_detection_multiplier_modify, + .cli_show = bfd_cli_show_mult, + } + }, + { + .xpath = "/frr-bfdd:bfdd/bfd/profile/desired-transmission-interval", + .cbs = { + .modify = bfdd_bfd_profile_desired_transmission_interval_modify, + .cli_show = bfd_cli_show_tx, + } + }, + { + .xpath = "/frr-bfdd:bfdd/bfd/profile/required-receive-interval", + .cbs = { + .modify = bfdd_bfd_profile_required_receive_interval_modify, + .cli_show = bfd_cli_show_rx, + } + }, + { + .xpath = "/frr-bfdd:bfdd/bfd/profile/administrative-down", + .cbs = { + .modify = bfdd_bfd_profile_administrative_down_modify, + .cli_show = bfd_cli_show_shutdown, + } + }, + { + .xpath = "/frr-bfdd:bfdd/bfd/profile/echo-mode", + .cbs = { + .modify = bfdd_bfd_profile_echo_mode_modify, + .cli_show = bfd_cli_show_echo, + } + }, + { + .xpath = "/frr-bfdd:bfdd/bfd/profile/desired-echo-transmission-interval", + .cbs = { + .modify = bfdd_bfd_profile_desired_echo_transmission_interval_modify, + .cli_show = bfd_cli_show_echo_interval, + } + }, { .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop", .cbs = { @@ -59,6 +110,14 @@ const struct frr_yang_module_info frr_bfdd_info = { .destroy = bfdd_bfd_sessions_single_hop_source_addr_destroy, } }, + { + .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/profile", + .cbs = { + .modify = bfdd_bfd_sessions_single_hop_profile_modify, + .destroy = bfdd_bfd_sessions_single_hop_profile_destroy, + .cli_show = bfd_cli_peer_profile_show, + } + }, { .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/detection-multiplier", .cbs = { @@ -233,6 +292,14 @@ const struct frr_yang_module_info frr_bfdd_info = { .cli_show_end = bfd_cli_show_peer_end, } }, + { + .xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop/profile", + .cbs = { + .modify = bfdd_bfd_sessions_single_hop_profile_modify, + .destroy = bfdd_bfd_sessions_single_hop_profile_destroy, + .cli_show = bfd_cli_peer_profile_show, + } + }, { .xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop/detection-multiplier", .cbs = { diff --git a/bfdd/bfdd_nb.h b/bfdd/bfdd_nb.h index 4fba3a0d30..a379c2135e 100644 --- a/bfdd/bfdd_nb.h +++ b/bfdd/bfdd_nb.h @@ -28,6 +28,18 @@ extern const struct frr_yang_module_info frr_bfdd_info; /* Mandatory callbacks. */ int bfdd_bfd_create(struct nb_cb_create_args *args); int bfdd_bfd_destroy(struct nb_cb_destroy_args *args); +int bfdd_bfd_profile_create(struct nb_cb_create_args *args); +int bfdd_bfd_profile_destroy(struct nb_cb_destroy_args *args); +int bfdd_bfd_profile_detection_multiplier_modify( + struct nb_cb_modify_args *args); +int bfdd_bfd_profile_desired_transmission_interval_modify( + struct nb_cb_modify_args *args); +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_echo_mode_modify(struct nb_cb_modify_args *args); +int bfdd_bfd_profile_desired_echo_transmission_interval_modify( + struct nb_cb_modify_args *args); int bfdd_bfd_sessions_single_hop_create(struct nb_cb_create_args *args); int bfdd_bfd_sessions_single_hop_destroy(struct nb_cb_destroy_args *args); const void * @@ -39,6 +51,9 @@ int bfdd_bfd_sessions_single_hop_source_addr_modify( struct nb_cb_modify_args *args); int bfdd_bfd_sessions_single_hop_source_addr_destroy( struct nb_cb_destroy_args *args); +int bfdd_bfd_sessions_single_hop_profile_modify(struct nb_cb_modify_args *args); +int bfdd_bfd_sessions_single_hop_profile_destroy( + struct nb_cb_destroy_args *args); int bfdd_bfd_sessions_single_hop_detection_multiplier_modify( struct nb_cb_modify_args *args); int bfdd_bfd_sessions_single_hop_desired_transmission_interval_modify( @@ -187,5 +202,9 @@ void bfd_cli_show_echo(struct vty *vty, struct lyd_node *dnode, bool show_defaults); void bfd_cli_show_echo_interval(struct vty *vty, struct lyd_node *dnode, bool show_defaults); +void bfd_cli_show_profile(struct vty *vty, struct lyd_node *dnode, + bool show_defaults); +void bfd_cli_peer_profile_show(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 df8a644e78..de11997d1a 100644 --- a/bfdd/bfdd_nb_config.c +++ b/bfdd/bfdd_nb_config.c @@ -214,6 +214,211 @@ int bfdd_bfd_destroy(struct nb_cb_destroy_args *args) return NB_OK; } +/* + * XPath: /frr-bfdd:bfdd/bfd/profile + */ +int bfdd_bfd_profile_create(struct nb_cb_create_args *args) +{ + struct bfd_profile *bp; + const char *name; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + name = yang_dnode_get_string(args->dnode, "./name"); + bp = bfd_profile_new(name); + nb_running_set_entry(args->dnode, bp); + + return NB_OK; +} + +int bfdd_bfd_profile_destroy(struct nb_cb_destroy_args *args) +{ + struct bfd_profile *bp; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + bp = nb_running_unset_entry(args->dnode); + bfd_profile_free(bp); + + return NB_OK; +} + +/* + * XPath: /frr-bfdd:bfdd/bfd/profile/detection-multiplier + */ +int bfdd_bfd_profile_detection_multiplier_modify(struct nb_cb_modify_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->detection_multiplier = yang_dnode_get_uint8(args->dnode, NULL); + + return NB_OK; +} + +/* + * XPath: /frr-bfdd:bfdd/bfd/profile/desired-transmission-interval + */ +int bfdd_bfd_profile_desired_transmission_interval_modify( + struct nb_cb_modify_args *args) +{ + struct bfd_profile *bp; + uint32_t min_tx; + + switch (args->event) { + case NB_EV_VALIDATE: + min_tx = yang_dnode_get_uint32(args->dnode, NULL); + if (min_tx < 10000 || min_tx > 60000000) + return NB_ERR_VALIDATION; + break; + + case NB_EV_PREPARE: + /* NOTHING */ + break; + + case NB_EV_APPLY: + min_tx = yang_dnode_get_uint32(args->dnode, NULL); + bp = nb_running_get_entry(args->dnode, NULL, true); + if (bp->min_tx == min_tx) + return NB_OK; + + bp->min_tx = min_tx; + bfd_profile_update(bp); + break; + + case NB_EV_ABORT: + /* NOTHING */ + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-bfdd:bfdd/bfd/profile/required-receive-interval + */ +int bfdd_bfd_profile_required_receive_interval_modify( + struct nb_cb_modify_args *args) +{ + struct bfd_profile *bp; + uint32_t min_rx; + + switch (args->event) { + case NB_EV_VALIDATE: + min_rx = yang_dnode_get_uint32(args->dnode, NULL); + if (min_rx < 10000 || min_rx > 60000000) + return NB_ERR_VALIDATION; + break; + + case NB_EV_PREPARE: + /* NOTHING */ + break; + + case NB_EV_APPLY: + min_rx = yang_dnode_get_uint32(args->dnode, NULL); + bp = nb_running_get_entry(args->dnode, NULL, true); + if (bp->min_rx == min_rx) + return NB_OK; + + bp->min_rx = min_rx; + bfd_profile_update(bp); + break; + + case NB_EV_ABORT: + /* NOTHING */ + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-bfdd:bfdd/bfd/profile/administrative-down + */ +int bfdd_bfd_profile_administrative_down_modify(struct nb_cb_modify_args *args) +{ + struct bfd_profile *bp; + bool shutdown; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + shutdown = yang_dnode_get_bool(args->dnode, NULL); + bp = nb_running_get_entry(args->dnode, NULL, true); + if (bp->admin_shutdown == shutdown) + return NB_OK; + + bp->admin_shutdown = shutdown; + bfd_profile_update(bp); + + return NB_OK; +} + +/* + * XPath: /frr-bfdd:bfdd/bfd/profile/echo-mode + */ +int bfdd_bfd_profile_echo_mode_modify(struct nb_cb_modify_args *args) +{ + struct bfd_profile *bp; + bool echo; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + echo = yang_dnode_get_bool(args->dnode, NULL); + bp = nb_running_get_entry(args->dnode, NULL, true); + if (bp->echo_mode == echo) + return NB_OK; + + bp->echo_mode = echo; + bfd_profile_update(bp); + + return NB_OK; +} + +/* + * XPath: /frr-bfdd:bfdd/bfd/profile/desired-echo-echo-transmission-interval + */ +int bfdd_bfd_profile_desired_echo_transmission_interval_modify( + struct nb_cb_modify_args *args) +{ + struct bfd_profile *bp; + uint32_t min_rx; + + switch (args->event) { + case NB_EV_VALIDATE: + min_rx = yang_dnode_get_uint32(args->dnode, NULL); + if (min_rx < 10000 || min_rx > 60000000) + return NB_ERR_VALIDATION; + break; + + case NB_EV_PREPARE: + /* NOTHING */ + break; + + case NB_EV_APPLY: + min_rx = yang_dnode_get_uint32(args->dnode, NULL); + bp = nb_running_get_entry(args->dnode, NULL, true); + if (bp->min_echo_rx == min_rx) + return NB_OK; + + bp->min_echo_rx = min_rx; + bfd_profile_update(bp); + break; + + case NB_EV_ABORT: + /* NOTHING */ + break; + } + + return NB_OK; +} + /* * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop */ @@ -243,6 +448,36 @@ int bfdd_bfd_sessions_single_hop_source_addr_destroy( return NB_OK; } +/* + * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop/profile + */ +int bfdd_bfd_sessions_single_hop_profile_modify(struct nb_cb_modify_args *args) +{ + struct bfd_session *bs; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + bs = nb_running_get_entry(args->dnode, NULL, true); + bfd_profile_apply(yang_dnode_get_string(args->dnode, NULL), bs); + + return NB_OK; +} + +int bfdd_bfd_sessions_single_hop_profile_destroy( + struct nb_cb_destroy_args *args) +{ + struct bfd_session *bs; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + bs = nb_running_get_entry(args->dnode, NULL, true); + bfd_profile_remove(bs); + + return NB_OK; +} + /* * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop/detection-multiplier */ @@ -263,6 +498,7 @@ int bfdd_bfd_sessions_single_hop_detection_multiplier_modify( case NB_EV_APPLY: bs = nb_running_get_entry(args->dnode, NULL, true); bs->detect_mult = detection_multiplier; + bs->peer_profile.detection_multiplier = detection_multiplier; break; case NB_EV_ABORT: @@ -298,6 +534,7 @@ int bfdd_bfd_sessions_single_hop_desired_transmission_interval_modify( return NB_OK; bs->timers.desired_min_tx = tx_interval; + bs->peer_profile.min_tx = tx_interval; bfd_set_polling(bs); break; @@ -334,6 +571,7 @@ int bfdd_bfd_sessions_single_hop_required_receive_interval_modify( return NB_OK; bs->timers.required_min_rx = rx_interval; + bs->peer_profile.min_rx = rx_interval; bfd_set_polling(bs); break; @@ -367,6 +605,7 @@ int bfdd_bfd_sessions_single_hop_administrative_down_modify( } bs = nb_running_get_entry(args->dnode, NULL, true); + bs->peer_profile.admin_shutdown = shutdown; bfd_set_shutdown(bs, shutdown); return NB_OK; @@ -394,6 +633,7 @@ int bfdd_bfd_sessions_single_hop_echo_mode_modify( } bs = nb_running_get_entry(args->dnode, NULL, true); + bs->peer_profile.echo_mode = echo; bfd_set_echo(bs, echo); return NB_OK; @@ -425,6 +665,7 @@ int bfdd_bfd_sessions_single_hop_desired_echo_transmission_interval_modify( return NB_OK; bs->timers.required_min_echo = echo_interval; + bs->peer_profile.min_echo_rx = echo_interval; break; case NB_EV_ABORT: diff --git a/bfdd/ptm_adapter.c b/bfdd/ptm_adapter.c index 7efbd2c7b8..25938dd9f5 100644 --- a/bfdd/ptm_adapter.c +++ b/bfdd/ptm_adapter.c @@ -417,6 +417,9 @@ static void bfdd_dest_register(struct stream *msg, vrf_id_t vrf_id) "ptm-add-dest: failed to create BFD session"); return; } + + /* Protocol created peers are 'no shutdown' by default. */ + bs->peer_profile.admin_shutdown = false; } else { /* Don't try to change echo/shutdown state. */ bpc.bpc_echo = CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO); -- 2.39.5