diff options
Diffstat (limited to 'bfdd/bfdd_nb_config.c')
| -rw-r--r-- | bfdd/bfdd_nb_config.c | 389 |
1 files changed, 360 insertions, 29 deletions
diff --git a/bfdd/bfdd_nb_config.c b/bfdd/bfdd_nb_config.c index 48fbe7139c..15da1e2440 100644 --- a/bfdd/bfdd_nb_config.c +++ b/bfdd/bfdd_nb_config.c @@ -13,14 +13,50 @@ #include "bfd.h" #include "bfdd_nb.h" +#include <ifaddrs.h> /* * Helpers. */ +static void get_ip_by_interface(const char *ifname, const char *vrfname, int family, char *ifip) +{ + char intfip[INET6_ADDRSTRLEN]; + const struct interface *interface; + const struct connected *connected; + struct vrf *vrf; + + vrf = vrf_lookup_by_name(vrfname ? vrfname : VRF_DEFAULT_NAME); + if (!vrf) + return; + + interface = if_lookup_by_name_vrf(ifname, vrf); + if (interface == NULL) + return; + + frr_each (if_connected_const, interface->connected, connected) { + if (!connected->address) + continue; + + if (family != connected->address->family) + continue; + + if (family == AF_INET6 && IN6_IS_ADDR_LINKLOCAL(&connected->address->u.prefix6)) + continue; + + inet_ntop(family, + family == AF_INET ? (void *)(&connected->address->u.prefix4) + : (void *)(&connected->address->u.prefix6), + intfip, INET6_ADDRSTRLEN); + strlcpy(ifip, intfip, INET6_ADDRSTRLEN - 1); + break; + } +} + static void bfd_session_get_key(bool mhop, const struct lyd_node *dnode, struct bfd_key *bk) { const char *ifname = NULL, *vrfname = NULL; + char ifip[INET6_ADDRSTRLEN] = { 0 }; struct sockaddr_any psa, lsa; /* Required destination parameter. */ @@ -37,10 +73,36 @@ static void bfd_session_get_key(bool mhop, const struct lyd_node *dnode, ifname = yang_dnode_get_string(dnode, "interface"); if (strcmp(ifname, "*") == 0) ifname = NULL; + + if (ifname != NULL && !yang_dnode_exists(dnode, "source-addr") && + psa.sa_sin.sin_family != 0) { + get_ip_by_interface(ifname, vrfname, psa.sa_sin.sin_family, ifip); + strtosa(ifip, &lsa); + } } /* Generate the corresponding key. */ - gen_bfd_key(bk, &psa, &lsa, mhop, ifname, vrfname); + gen_bfd_key(bk, &psa, &lsa, mhop, ifname, vrfname, NULL); +} + +static void sbfd_session_get_key(bool mhop, const struct lyd_node *dnode, struct bfd_key *bk) +{ + const char *ifname = NULL, *vrfname = NULL, *bfdname = NULL; + struct sockaddr_any psa, lsa; + + /* Required source parameter. */ + strtosa(yang_dnode_get_string(dnode, "source-addr"), &lsa); + + strtosa(yang_dnode_get_string(dnode, "dest-addr"), &psa); + + if (yang_dnode_exists(dnode, "bfd-name")) + bfdname = yang_dnode_get_string(dnode, "bfd-name"); + + if (yang_dnode_exists(dnode, "vrf")) + vrfname = yang_dnode_get_string(dnode, "vrf"); + + /* Generate the corresponding key. */ + gen_bfd_key(bk, &psa, &lsa, mhop, ifname, vrfname, bfdname); } struct session_iter { @@ -63,7 +125,25 @@ static int session_iter_cb(const struct lyd_node *dnode, void *arg) return YANG_ITER_CONTINUE; } -static int bfd_session_create(struct nb_cb_create_args *args, bool mhop) +static int segment_list_iter_cb(const struct lyd_node *dnode, void *arg) +{ + struct bfd_session *bs = arg; + uint8_t segnum = bs->segnum; + const char *addr; + struct sockaddr_any sa; + + addr = yang_dnode_get_string(dnode, NULL); + + if (strtosa(addr, &sa) < 0 || sa.sa_sin6.sin6_family != AF_INET6) + return YANG_ITER_STOP; + + memcpy(&bs->seg_list[segnum], &sa.sa_sin6.sin6_addr, sizeof(struct in6_addr)); + bs->segnum = segnum + 1; + + return YANG_ITER_CONTINUE; +} + +static int bfd_session_create(struct nb_cb_create_args *args, bool mhop, uint32_t bfd_mode) { const struct lyd_node *sess_dnode; struct session_iter iter; @@ -73,10 +153,20 @@ static int bfd_session_create(struct nb_cb_create_args *args, bool mhop) const char *vrfname; struct bfd_key bk; struct prefix p; + const char *bfd_name = NULL; + struct sockaddr_any out_sip6; switch (args->event) { case NB_EV_VALIDATE: - yang_dnode_get_prefix(&p, args->dnode, "dest-addr"); + if ((bfd_mode == BFD_MODE_TYPE_SBFD_ECHO) || (bfd_mode == BFD_MODE_TYPE_SBFD_INIT)) { + if (bfd_session_get_by_name(yang_dnode_get_string(args->dnode, "bfd-name"))) { + snprintf(args->errmsg, args->errmsg_len, "bfd name already exist."); + return NB_ERR_VALIDATION; + } + return NB_OK; + } + + yang_dnode_get_prefix(&p, args->dnode, "./dest-addr"); if (mhop) { /* @@ -128,34 +218,123 @@ static int bfd_session_create(struct nb_cb_create_args *args, bool mhop) break; case NB_EV_PREPARE: - bfd_session_get_key(mhop, args->dnode, &bk); - bs = bfd_key_lookup(bk); + if (bfd_mode == BFD_MODE_TYPE_BFD) { + bfd_session_get_key(mhop, args->dnode, &bk); + bs = bfd_key_lookup(bk); + + /* This session was already configured by another daemon. */ + if (bs != NULL) { + /* Now it is configured also by CLI. */ + SET_FLAG(bs->flags, BFD_SESS_FLAG_CONFIG); + bs->refcount++; + + args->resource->ptr = bs; + break; + } + + bs = bfd_session_new(BFD_MODE_TYPE_BFD); - /* This session was already configured by another daemon. */ - if (bs != NULL) { - /* Now it is configured also by CLI. */ + /* Fill the session key. */ + bfd_session_get_key(mhop, args->dnode, &bs->key); + /* Set configuration flags. */ + bs->refcount = 1; SET_FLAG(bs->flags, BFD_SESS_FLAG_CONFIG); - bs->refcount++; + if (mhop) + SET_FLAG(bs->flags, BFD_SESS_FLAG_MH); + if (bs->key.family == AF_INET6) + SET_FLAG(bs->flags, BFD_SESS_FLAG_IPV6); args->resource->ptr = bs; break; - } + } else if (bfd_mode == BFD_MODE_TYPE_SBFD_ECHO || + bfd_mode == BFD_MODE_TYPE_SBFD_INIT) { + sbfd_session_get_key(mhop, args->dnode, &bk); + bs = bfd_key_lookup(bk); + + /* This session was already configured by another daemon. */ + if (bs != NULL) { + /* Now it is configured also by CLI. */ + SET_FLAG(bs->flags, BFD_SESS_FLAG_CONFIG); + bs->refcount++; + + args->resource->ptr = bs; + break; + } - bs = bfd_session_new(); + if (bfd_mode == BFD_MODE_TYPE_SBFD_ECHO && + !yang_dnode_exists(args->dnode, "srv6-encap-data")) { + //srv6-encap-data should not be null for sbfd echo + snprintf(args->errmsg, args->errmsg_len, + "srv6-encap-data should not be null"); + return NB_ERR_RESOURCE; + } - /* Fill the session key. */ - bfd_session_get_key(mhop, args->dnode, &bs->key); + if (bfd_mode == BFD_MODE_TYPE_SBFD_ECHO && + !yang_dnode_exists(args->dnode, "srv6-source-ipv6")) { + snprintf(args->errmsg, args->errmsg_len, + "source_ipv6 should not be null"); + return NB_ERR_RESOURCE; + } - /* Set configuration flags. */ - bs->refcount = 1; - SET_FLAG(bs->flags, BFD_SESS_FLAG_CONFIG); - if (mhop) - SET_FLAG(bs->flags, BFD_SESS_FLAG_MH); - if (bs->key.family == AF_INET6) - SET_FLAG(bs->flags, BFD_SESS_FLAG_IPV6); + if (bfd_mode == BFD_MODE_TYPE_SBFD_INIT) { + if (!yang_dnode_exists(args->dnode, "remote-discr")) { + snprintf(args->errmsg, args->errmsg_len, + "remote-discr should not be null"); + return NB_ERR_RESOURCE; + } + } - args->resource->ptr = bs; - break; + bfd_name = yang_dnode_get_string(args->dnode, "bfd-name"); + + bs = bfd_session_new(bfd_mode); + if (bs == NULL) { + snprintf(args->errmsg, args->errmsg_len, + "session-new: allocation failed"); + return NB_ERR_RESOURCE; + } + /* Fill the session key. */ + sbfd_session_get_key(mhop, args->dnode, &bs->key); + strlcpy(bs->bfd_name, bfd_name, BFD_NAME_SIZE); + + if (yang_dnode_exists(args->dnode, "srv6-encap-data")) { + yang_dnode_iterate(segment_list_iter_cb, bs, args->dnode, + "./srv6-encap-data"); + + + strtosa(yang_dnode_get_string(args->dnode, "./srv6-source-ipv6"), + &out_sip6); + memcpy(&bs->out_sip6, &out_sip6.sa_sin6.sin6_addr, + sizeof(struct in6_addr)); + } + + if (bfd_mode == BFD_MODE_TYPE_SBFD_INIT) { + bs->discrs.remote_discr = yang_dnode_get_uint32(args->dnode, + "./remote-discr"); + } + + /* Set configuration flags. */ + bs->refcount = 1; + SET_FLAG(bs->flags, BFD_SESS_FLAG_CONFIG); + if (mhop) + SET_FLAG(bs->flags, BFD_SESS_FLAG_MH); + + if (bs->key.family == AF_INET6) + SET_FLAG(bs->flags, BFD_SESS_FLAG_IPV6); + + if (bfd_mode == BFD_MODE_TYPE_SBFD_ECHO) { + memcpy(&bs->key.peer, &bs->key.local, sizeof(struct in6_addr)); + } else { + bs->xmt_TO = bs->timers.desired_min_tx; + bs->detect_TO = bs->detect_mult * bs->xmt_TO; + } + + args->resource->ptr = bs; + break; + + } else { + snprintf(args->errmsg, args->errmsg_len, "bfd mode must be bfd or sbfd."); + return NB_ERR_VALIDATION; + } case NB_EV_APPLY: bs = args->resource->ptr; @@ -177,15 +356,19 @@ static int bfd_session_create(struct nb_cb_create_args *args, bool mhop) return NB_OK; } -static int bfd_session_destroy(enum nb_event event, - const struct lyd_node *dnode, bool mhop) +static int bfd_session_destroy(enum nb_event event, const struct lyd_node *dnode, bool mhop, + uint32_t bfd_mode) { struct bfd_session *bs; struct bfd_key bk; switch (event) { case NB_EV_VALIDATE: - bfd_session_get_key(mhop, dnode, &bk); + if (bfd_mode == BFD_MODE_TYPE_BFD) + bfd_session_get_key(mhop, dnode, &bk); + else + sbfd_session_get_key(mhop, dnode, &bk); + if (bfd_key_lookup(bk) == NULL) return NB_ERR_INCONSISTENCY; break; @@ -206,6 +389,12 @@ static int bfd_session_destroy(enum nb_event event, if (bs->refcount > 0) break; + if (bglobal.debug_peer_event) + zlog_info("session destroy: %s", bs_to_string(bs)); + + if (bfd_mode == BFD_MODE_TYPE_SBFD_ECHO || bfd_mode == BFD_MODE_TYPE_SBFD_INIT) + ptm_bfd_notify(bs, PTM_BFD_DOWN); + bfd_session_free(bs); break; @@ -510,12 +699,12 @@ int bfdd_bfd_profile_required_echo_receive_interval_modify( */ int bfdd_bfd_sessions_single_hop_create(struct nb_cb_create_args *args) { - return bfd_session_create(args, false); + return bfd_session_create(args, false, BFD_MODE_TYPE_BFD); } int bfdd_bfd_sessions_single_hop_destroy(struct nb_cb_destroy_args *args) { - return bfd_session_destroy(args->event, args->dnode, false); + return bfd_session_destroy(args->event, args->dnode, false, BFD_MODE_TYPE_BFD); } /* @@ -715,6 +904,45 @@ int bfdd_bfd_sessions_single_hop_passive_mode_modify( } /* + * XPath: /frr-bfdd:bfdd/bfd/sessions/sbfd-init/bfd-mode + * /frr-bfdd:bfdd/bfd/sessions/sbfd-echo/bfd-mode + */ +int bfdd_bfd_sessions_bfd_mode_modify(struct nb_cb_modify_args *args) +{ + uint32_t bfd_mode = yang_dnode_get_uint32(args->dnode, NULL); + struct bfd_session *bs; + + switch (args->event) { + case NB_EV_VALIDATE: + if ((bfd_mode != BFD_MODE_TYPE_BFD) && (bfd_mode != BFD_MODE_TYPE_SBFD_ECHO) && + (bfd_mode != BFD_MODE_TYPE_SBFD_INIT)) { + snprintf(args->errmsg, args->errmsg_len, "bfd mode is invalid."); + return NB_ERR_VALIDATION; + } + return NB_OK; + 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->bfd_mode = bfd_mode; + bfd_session_apply(bs); + + return NB_OK; +} + +int bfdd_bfd_sessions_bfd_mode_destroy(struct nb_cb_destroy_args *args) +{ + return NB_OK; +} + +/* * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop/echo-mode */ int bfdd_bfd_sessions_single_hop_echo_mode_modify( @@ -811,12 +1039,12 @@ int bfdd_bfd_sessions_single_hop_required_echo_receive_interval_modify( */ int bfdd_bfd_sessions_multi_hop_create(struct nb_cb_create_args *args) { - return bfd_session_create(args, true); + return bfd_session_create(args, true, BFD_MODE_TYPE_BFD); } int bfdd_bfd_sessions_multi_hop_destroy(struct nb_cb_destroy_args *args) { - return bfd_session_destroy(args->event, args->dnode, true); + return bfd_session_destroy(args->event, args->dnode, true, BFD_MODE_TYPE_BFD); } /* @@ -845,3 +1073,106 @@ int bfdd_bfd_sessions_multi_hop_minimum_ttl_modify( return NB_OK; } + +/* + * XPath: /frr-bfdd:bfdd/bfd/sessions/sbfd-echo + */ +int bfdd_bfd_sessions_sbfd_echo_create(struct nb_cb_create_args *args) +{ + return bfd_session_create(args, yang_dnode_exists(args->dnode, "multi-hop"), + BFD_MODE_TYPE_SBFD_ECHO); +} + +int bfdd_bfd_sessions_sbfd_echo_destroy(struct nb_cb_destroy_args *args) +{ + return bfd_session_destroy(args->event, args->dnode, + yang_dnode_exists(args->dnode, "multi-hop"), + BFD_MODE_TYPE_SBFD_ECHO); +} + +/* + * XPath: /frr-bfdd:bfdd/bfd/sessions/sbfd-echo/srv6-encap-data + * XPath: /frr-bfdd:bfdd/bfd/sessions/sbfd-init/srv6-encap-data + */ +int bfdd_bfd_sessions_segment_list_create(struct nb_cb_create_args *args) +{ + return NB_OK; +} + +int bfdd_bfd_sessions_segment_list_destroy(struct nb_cb_destroy_args *args) +{ + return NB_OK; +} + +/* + * XPath: /frr-bfdd:bfdd/bfd/sessions/sbfd-echo/dest-addr + */ +int bfdd_bfd_sessions_sbfd_echo_dest_addr_modify(struct nb_cb_modify_args *args) +{ + return NB_OK; +} + +int bfdd_bfd_sessions_sbfd_echo_dest_addr_destroy(struct nb_cb_destroy_args *args) +{ + return NB_OK; +} + +/* + * XPath: /frr-bfdd:bfdd/bfd/sessions/sbfd-echo/echo-mode + */ +int bfdd_bfd_sessions_sbfd_echo_mode_modify(struct nb_cb_modify_args *args) +{ + return NB_OK; +} + +/* + * XPath: /frr-bfdd:bfdd/bfd/sessions/sbfd-echo/srv6-source-ipv6 + * XPath: /frr-bfdd:bfdd/bfd/sessions/sbfd-init/srv6-source-ipv6 + */ +int bfdd_bfd_sessions_sbfd_srv6_source_ipv6_modify(struct nb_cb_modify_args *args) +{ + return NB_OK; +} + +int bfdd_bfd_sessions_sbfd_srv6_source_ipv6_destroy(struct nb_cb_destroy_args *args) +{ + return NB_OK; +} + +/* + * XPath: /frr-bfdd:bfdd/bfd/sessions/sbfd-init + */ +int bfdd_bfd_sessions_sbfd_init_create(struct nb_cb_create_args *args) +{ + return bfd_session_create(args, yang_dnode_exists(args->dnode, "multi-hop"), + BFD_MODE_TYPE_SBFD_INIT); +} + +int bfdd_bfd_sessions_sbfd_init_destroy(struct nb_cb_destroy_args *args) +{ + return bfd_session_destroy(args->event, args->dnode, + yang_dnode_exists(args->dnode, "multi-hop"), + BFD_MODE_TYPE_SBFD_INIT); +} + +/* + * XPath: /frr-bfdd:bfdd/bfd/sessions/sbfd-init/remote-discr + */ +int bfdd_bfd_sessions_sbfd_init_remote_discr_modify(struct nb_cb_modify_args *args) +{ + return NB_OK; +} + +/* + * XPath: /frr-bfdd:bfdd/bfd/sessions/sbfd-echo/multi-hop + * XPath: /frr-bfdd:bfdd/bfd/sessions/sbfd-init/multi-hop + */ +int bfdd_bfd_sessions_sbfd_multi_hop_modify(struct nb_cb_modify_args *args) +{ + return NB_OK; +} + +int bfdd_bfd_sessions_sbfd_multi_hop_destroy(struct nb_cb_destroy_args *args) +{ + return NB_OK; +} |
