sbfd will use bfdname for key hash, We introduced a bfd-name for every sbfd session, normal BFD sessions can leave it as NULL.
A unique bfd-name can be used to identify a sbfd session quickly. This is quite useful in our Srv6 deployment for path protection case.
For example, if use the sbfd session to protect the SRv6 path A-B-D, we would assign the name 'path-a-b-d' or 'a-b-d' to the session.
Signed-off-by: wumu.zsl <wumu.zsl@alibaba-inc.com>
bfd_session_apply(bs);
}
-void gen_bfd_key(struct bfd_key *key, struct sockaddr_any *peer,
- struct sockaddr_any *local, bool mhop, const char *ifname,
- const char *vrfname)
+void gen_bfd_key(struct bfd_key *key, struct sockaddr_any *peer, struct sockaddr_any *local,
+ bool mhop, const char *ifname, const char *vrfname, const char *bfdname)
{
+ struct vrf *vrf = NULL;
+
memset(key, 0, sizeof(*key));
switch (peer->sa_sin.sin_family) {
key->mhop = mhop;
if (ifname && ifname[0])
strlcpy(key->ifname, ifname, sizeof(key->ifname));
- if (vrfname && vrfname[0])
- strlcpy(key->vrfname, vrfname, sizeof(key->vrfname));
- else
+ if (vrfname && vrfname[0] && strcmp(vrfname, VRF_DEFAULT_NAME) != 0) {
+ vrf = vrf_lookup_by_name(vrfname);
+ if (vrf) {
+ strlcpy(key->vrfname, vrf->name, sizeof(key->vrfname));
+ } else {
+ strlcpy(key->vrfname, vrfname, sizeof(key->vrfname));
+ }
+ } else {
strlcpy(key->vrfname, VRF_DEFAULT_NAME, sizeof(key->vrfname));
+ }
+
+ if (bfdname && bfdname[0]) {
+ strlcpy(key->bfdname, bfdname, sizeof(key->bfdname));
+ }
}
struct bfd_session *bs_peer_find(struct bfd_peer_cfg *bpc)
struct bfd_key key;
/* Otherwise fallback to peer/local hash lookup. */
- gen_bfd_key(&key, &bpc->bpc_peer, &bpc->bpc_local, bpc->bpc_mhop,
- bpc->bpc_localif, bpc->bpc_vrfname);
+ gen_bfd_key(&key, &bpc->bpc_peer, &bpc->bpc_local, bpc->bpc_mhop, bpc->bpc_localif,
+ bpc->bpc_vrfname, bpc->bfd_name);
return bfd_key_lookup(key);
}
vrf = vrf_lookup_by_id(vrfid);
gen_bfd_key(&key, peer, local, is_mhop, ifp ? ifp->name : NULL,
- vrf ? vrf->name : VRF_DEFAULT_NAME);
+ vrf ? vrf->name : VRF_DEFAULT_NAME, NULL);
/* XXX maybe remoteDiscr should be checked for remoteHeard cases. */
return bfd_key_lookup(key);
struct bfd_session_iterator {
int bsi_stop;
bool bsi_mhop;
+ uint32_t bsi_bfdmode;
const struct bfd_session *bsi_bs;
};
/* Previous entry signaled stop. */
if (bsi->bsi_stop == 1) {
/* Match the single/multi hop sessions. */
- if (bs->key.mhop != bsi->bsi_mhop)
+ if ((bs->key.mhop != bsi->bsi_mhop) || (bs->bfd_mode != bsi->bsi_bfdmode))
return HASHWALK_CONTINUE;
bsi->bsi_bs = bs;
bsi->bsi_stop = 1;
/* Set entry to NULL to signal end of list. */
bsi->bsi_bs = NULL;
- } else if (bsi->bsi_bs == NULL && bsi->bsi_mhop == bs->key.mhop) {
+ } else if (bsi->bsi_bs == NULL && bsi->bsi_mhop == bs->key.mhop &&
+ bsi->bsi_bfdmode == bs->bfd_mode) {
/* We want the first list item. */
bsi->bsi_stop = 1;
bsi->bsi_bs = hb->data;
*
* `bs` might point to NULL to get the first item of the data structure.
*/
-const struct bfd_session *bfd_session_next(const struct bfd_session *bs,
- bool mhop)
+const struct bfd_session *bfd_session_next(const struct bfd_session *bs, bool mhop,
+ uint32_t bfd_mode)
{
struct bfd_session_iterator bsi;
bsi.bsi_stop = 0;
bsi.bsi_bs = bs;
bsi.bsi_mhop = mhop;
+ bsi.bsi_bfdmode = bfd_mode;
hash_walk(bfd_key_hash, _bfd_session_next, &bsi);
if (bsi.bsi_stop == 0)
return NULL;
#include "lib/qobj.h"
#include "lib/queue.h"
#include "lib/vrf.h"
+#include "lib/bfd.h"
#ifdef BFD_DEBUG
#define BFDD_JSON_CONV_OPTIONS (JSON_C_TO_STRING_PRETTY)
bool bpc_has_profile;
char bpc_profile[64];
+
+ vrf_id_t vrf_id;
+ char bfd_name[BFD_NAME_SIZE + 1];
+ uint8_t bfd_name_len;
};
/* bfd Authentication Type. */
struct in6_addr local;
char ifname[IFNAMSIZ];
char vrfname[VRF_NAMSIZ];
+ char bfdname[BFD_NAME_SIZE + 1];
} __attribute__((packed));
struct bfd_session_stats {
uint8_t rtt_valid; /* number of valid samples */
uint8_t rtt_index; /* last index added */
uint64_t rtt[BFD_RTT_SAMPLE]; /* RRT in usec for echo to be looped */
+ char bfd_name[BFD_NAME_SIZE + 1];
+
+ uint32_t bfd_mode;
};
struct bfd_diag_str_list {
void bs_to_bpc(struct bfd_session *bs, struct bfd_peer_cfg *bpc);
-void gen_bfd_key(struct bfd_key *key, struct sockaddr_any *peer,
- struct sockaddr_any *local, bool mhop, const char *ifname,
- const char *vrfname);
+void gen_bfd_key(struct bfd_key *key, struct sockaddr_any *peer, struct sockaddr_any *local,
+ bool mhop, const char *ifname, const char *vrfname, const char *bfdname);
struct bfd_session *bfd_session_new(void);
struct bfd_session *bs_registrate(struct bfd_session *bs);
void bfd_session_free(struct bfd_session *bs);
-const struct bfd_session *bfd_session_next(const struct bfd_session *bs,
- bool mhop);
+const struct bfd_session *bfd_session_next(const struct bfd_session *bs, bool mhop,
+ uint32_t bfd_mode);
void bfd_sessions_remove_manual(void);
void bfd_profiles_remove(void);
void bfd_rtt_init(struct bfd_session *bfd);
#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. */
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);
}
struct session_iter {
const void *
bfdd_bfd_sessions_single_hop_get_next(struct nb_cb_get_next_args *args)
{
- return bfd_session_next(args->list_entry, false);
+ return bfd_session_next(args->list_entry, false, BFD_MODE_TYPE_BFD);
}
int bfdd_bfd_sessions_single_hop_get_keys(struct nb_cb_get_keys_args *args)
strtosa(dest_addr, &psa);
memset(&lsa, 0, sizeof(lsa));
- gen_bfd_key(&bk, &psa, &lsa, false, ifname, vrf);
+ gen_bfd_key(&bk, &psa, &lsa, false, ifname, vrf, NULL);
return bfd_key_lookup(bk);
}
const void *
bfdd_bfd_sessions_multi_hop_get_next(struct nb_cb_get_next_args *args)
{
- return bfd_session_next(args->list_entry, true);
+ return bfd_session_next(args->list_entry, true, BFD_MODE_TYPE_BFD);
}
int bfdd_bfd_sessions_multi_hop_get_keys(struct nb_cb_get_keys_args *args)
strtosa(dest_addr, &psa);
strtosa(source_addr, &lsa);
- gen_bfd_key(&bk, &psa, &lsa, true, NULL, vrf);
+ gen_bfd_key(&bk, &psa, &lsa, true, NULL, vrf, NULL);
return bfd_key_lookup(bk);
}
#define BFD_PROFILE_NAME_LEN 64
+#define BFD_NAME_SIZE 255
+
const char *bfd_get_status_str(int status);
extern void bfd_client_sendmsg(struct zclient *zclient, int command,
uint32_t min_tx;
/** Detection multiplier. */
uint32_t detection_multiplier;
+ /* bfd session name*/
+ char bfd_name[BFD_NAME_SIZE + 1];
};
/**