/*
* Prototypes
*/
+struct bfd_session *bs_peer_waiting_find(struct bfd_peer_cfg *);
+
static uint32_t ptm_bfd_gen_ID(void);
static void ptm_bfd_echo_xmt_TO(struct bfd_session *bfd);
static void bfd_session_free(struct bfd_session *bs);
-static struct bfd_session *bfd_session_new(int sd);
+static struct bfd_session *bfd_session_new(void);
static struct bfd_session *bfd_find_disc(struct sockaddr_any *sa,
uint32_t ldisc);
static int bfd_session_update(struct bfd_session *bs, struct bfd_peer_cfg *bpc);
/*
* Functions
*/
+struct bfd_session *bs_peer_waiting_find(struct bfd_peer_cfg *bpc)
+{
+ struct bfd_session_observer *bso;
+ struct bfd_session *bs = NULL;
+ bool is_shop, is_ipv4;
+
+ TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) {
+ bs = bso->bso_bs;
+
+ is_shop = !BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH);
+ is_ipv4 = !BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_IPV6);
+ /* Quick checks first. */
+ if (is_shop != (!bpc->bpc_mhop))
+ continue;
+ if (is_ipv4 != bpc->bpc_ipv4)
+ continue;
+
+ /*
+ * Slow lookup without hash because we don't have all
+ * information yet.
+ */
+ if (is_shop) {
+ if (strcmp(bs->ifname, bpc->bpc_localif))
+ continue;
+ if (memcmp(&bs->shop.peer, &bpc->bpc_peer,
+ sizeof(bs->shop.peer)))
+ continue;
+
+ break;
+ }
+
+ if (strcmp(bs->vrfname, bpc->bpc_vrfname))
+ continue;
+ if (memcmp(&bs->mhop.peer, &bpc->bpc_peer,
+ sizeof(bs->mhop.peer)))
+ continue;
+ if (memcmp(&bs->mhop.local, &bpc->bpc_local,
+ sizeof(bs->mhop.local)))
+ continue;
+
+ break;
+ }
+ if (bso == NULL)
+ bs = NULL;
+
+ return bs;
+}
+
struct bfd_session *bs_peer_find(struct bfd_peer_cfg *bpc)
{
struct bfd_session *bs;
bs = bfd_shop_lookup(shop);
}
- return bs;
+ if (bs != NULL)
+ return bs;
+
+ /* Search for entries that are incomplete. */
+ return bs_peer_waiting_find(bpc);
+}
+
+/*
+ * Starts a disabled BFD session.
+ *
+ * A session is disabled when the specified interface/VRF doesn't exist
+ * yet. It might happen on FRR boot or with virtual interfaces.
+ */
+int bfd_session_enable(struct bfd_session *bs)
+{
+ struct sockaddr_in6 *sin6;
+ struct interface *ifp = NULL;
+ struct vrf *vrf = NULL;
+ int psock;
+
+ /*
+ * If the interface or VRF doesn't exist, then we must register
+ * the session but delay its start.
+ */
+ if (bs->ifname[0] != 0) {
+ ifp = if_lookup_by_name_all_vrf(bs->ifname);
+ if (ifp == NULL) {
+ log_error(
+ "session-enable: specified interface doesn't exists.");
+ return 0;
+ }
+
+ vrf = vrf_lookup_by_id(ifp->vrf_id);
+ if (vrf == NULL) {
+ log_error("session-enable: specified VRF doesn't exists.");
+ return 0;
+ }
+ }
+
+ if (bs->vrfname[0] != 0) {
+ vrf = vrf_lookup_by_name(bs->vrfname);
+ if (vrf == NULL) {
+ log_error("session-enable: specified VRF doesn't exists.");
+ return 0;
+ }
+ }
+
+ /* Assign interface/VRF pointers. */
+ bs->vrf = vrf;
+ if (bs->vrf == NULL)
+ bs->vrf = vrf_lookup_by_id(VRF_DEFAULT);
+
+ if (bs->ifname[0] != 0 &&
+ BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH) == 0)
+ bs->ifp = ifp;
+
+ /* Set the IPv6 scope id for link-local addresses. */
+ if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_IPV6)) {
+ sin6 = &bs->mhop.peer.sa_sin6;
+ if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
+ sin6->sin6_scope_id = bs->ifp != NULL
+ ? bs->ifp->ifindex
+ : IFINDEX_INTERNAL;
+
+ sin6 = &bs->mhop.local.sa_sin6;
+ if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
+ sin6->sin6_scope_id = bs->ifp != NULL
+ ? bs->ifp->ifindex
+ : IFINDEX_INTERNAL;
+
+ bs->local_ip.sa_sin6 = *sin6;
+ bs->local_address.sa_sin6 = *sin6;
+ }
+
+ /*
+ * Get socket for transmitting control packets. Note that if we
+ * could use the destination port (3784) for the source
+ * port we wouldn't need a socket per session.
+ */
+ if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_IPV6) == 0) {
+ psock = bp_peer_socket(bs);
+ if (psock == -1)
+ return -1;
+ } else {
+ psock = bp_peer_socketv6(bs);
+ if (psock == -1)
+ return -1;
+ }
+
+ /*
+ * We've got a valid socket, lets start the timers and the
+ * protocol.
+ */
+ bs->sock = psock;
+ bfd_recvtimer_update(bs);
+ ptm_bfd_start_xmt_timer(bs, false);
+
+ /* Registrate session into data structures. */
+ bs->discrs.my_discr = ptm_bfd_gen_ID();
+ bfd_id_insert(bs);
+ if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) {
+ if (vrf != NULL)
+ bs->mhop.vrfid = vrf->vrf_id;
+ else
+ bs->mhop.vrfid = VRF_DEFAULT;
+
+ bfd_mhop_insert(bs);
+ } else {
+ if (ifp != NULL)
+ bs->shop.ifindex = ifp->ifindex;
+ else
+ bs->shop.ifindex = IFINDEX_INTERNAL;
+
+ bfd_shop_insert(bs);
+ }
+
+ return 0;
+}
+
+/*
+ * Disabled a running BFD session.
+ *
+ * A session is disabled when the specified interface/VRF gets removed
+ * (e.g. virtual interfaces).
+ */
+void bfd_session_disable(struct bfd_session *bs)
+{
+ /* Free up socket resources. */
+ if (bs->sock != -1) {
+ close(bs->sock);
+ bs->sock = -1;
+ }
+
+ /* Disable all timers. */
+ bfd_recvtimer_delete(bs);
+ bfd_echo_recvtimer_delete(bs);
+ bfd_xmttimer_delete(bs);
+ bfd_echo_xmttimer_delete(bs);
+
+ /* Unregister session from hashes to avoid unwanted activation. */
+ bfd_id_delete(bs->discrs.my_discr);
+ if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH))
+ bfd_mhop_delete(bs->mhop);
+ else
+ bfd_shop_delete(bs->shop);
}
static uint32_t ptm_bfd_gen_ID(void)
return 0;
}
-static struct bfd_session *bfd_session_new(int sd)
+static struct bfd_session *bfd_session_new(void)
{
struct bfd_session *bs;
bs->timers.required_min_echo = BFD_DEF_REQ_MIN_ECHO;
bs->detect_mult = BFD_DEFDETECTMULT;
bs->mh_ttl = BFD_DEF_MHOP_TTL;
+ bs->ses_state = PTM_BFD_DOWN;
/* Initiate connection with slow timers. */
bs_set_slow_timers(bs);
bs->remote_timers = bs->cur_timers;
bs->remote_detect_mult = BFD_DEFDETECTMULT;
- bs->sock = sd;
+ bs->sock = -1;
monotime(&bs->uptime);
bs->downtime = bs->uptime;
bs->ses_state = PTM_BFD_ADM_DOWN;
control_notify(bs);
- ptm_bfd_snd(bs, 0);
+ /* Don't try to send packets with a disabled session. */
+ if (bs->sock != -1)
+ ptm_bfd_snd(bs, 0);
} else {
/* Check if already working. */
if (!BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN))
static void bfd_session_free(struct bfd_session *bs)
{
- if (bs->sock != -1)
- close(bs->sock);
+ struct bfd_session_observer *bso;
- bfd_recvtimer_delete(bs);
- bfd_echo_recvtimer_delete(bs);
- bfd_xmttimer_delete(bs);
- bfd_echo_xmttimer_delete(bs);
+ bfd_session_disable(bs);
- bfd_id_delete(bs->discrs.my_discr);
- if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH))
- bfd_mhop_delete(bs->mhop);
- else
- bfd_shop_delete(bs->shop);
+ /* Remove observer if any. */
+ TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) {
+ if (bso->bso_bs != bs)
+ continue;
+
+ break;
+ }
+ if (bso != NULL)
+ bs_observer_del(bso);
pl_free(bs->pl);
struct bfd_session *ptm_bfd_sess_new(struct bfd_peer_cfg *bpc)
{
struct bfd_session *bfd, *l_bfd;
- struct interface *ifp = NULL;
- struct vrf *vrf = NULL;
- int psock;
/* check to see if this needs a new session */
l_bfd = bs_peer_find(bpc);
return NULL;
}
- /*
- * No session found, we have to allocate a new one.
- *
- * First a few critical checks:
- *
- * * Check that the specified interface exists.
- * * Check that the specified VRF exists.
- * * Attempt to create the UDP socket (might fail if we exceed
- * our limits).
- */
- if (bpc->bpc_has_localif) {
- ifp = if_lookup_by_name_all_vrf(bpc->bpc_localif);
- if (ifp == NULL) {
- log_error(
- "session-new: specified interface doesn't exists.");
- return NULL;
- }
-
- vrf = vrf_lookup_by_id(ifp->vrf_id);
- if (vrf == NULL) {
- log_error("session-new: specified VRF doesn't exists.");
- return NULL;
- }
- }
-
- if (bpc->bpc_has_vrfname) {
- vrf = vrf_lookup_by_name(bpc->bpc_vrfname);
- if (vrf == NULL) {
- log_error("session-new: specified VRF doesn't exists.");
- return NULL;
- }
- }
-
- /*
- * Get socket for transmitting control packets. Note that if we
- * could use the destination port (3784) for the source
- * port we wouldn't need a socket per session.
- */
- if (bpc->bpc_ipv4) {
- psock = bp_peer_socket(bpc);
- if (psock == -1)
- return NULL;
- } else {
- psock = bp_peer_socketv6(bpc);
- if (psock == -1)
- return NULL;
- }
-
- /* Get memory */
- bfd = bfd_session_new(psock);
+ /* Get BFD session storage with its defaults. */
+ bfd = bfd_session_new();
if (bfd == NULL) {
log_error("session-new: allocation failed");
return NULL;
}
- /* Assign VRF pointer. */
- bfd->vrf = vrf;
- if (bfd->vrf == NULL)
- bfd->vrf = vrf_lookup_by_id(VRF_DEFAULT);
-
- if (bpc->bpc_has_localif && !bpc->bpc_mhop)
- bfd->ifp = ifp;
+ /*
+ * Store interface/VRF name in case we need to delay session
+ * start. See `bfd_session_enable` for more information.
+ */
+ if (bpc->bpc_has_localif)
+ strlcpy(bfd->ifname, bpc->bpc_localif, sizeof(bfd->ifname));
- if (bpc->bpc_ipv4 == false) {
- BFD_SET_FLAG(bfd->flags, BFD_SESS_FLAG_IPV6);
+ if (bpc->bpc_has_vrfname)
+ strlcpy(bfd->vrfname, bpc->bpc_vrfname, sizeof(bfd->vrfname));
- /* Set the IPv6 scope id for link-local addresses. */
- if (IN6_IS_ADDR_LINKLOCAL(&bpc->bpc_local.sa_sin6.sin6_addr))
- bpc->bpc_local.sa_sin6.sin6_scope_id =
- bfd->ifp != NULL ? bfd->ifp->ifindex
- : IFINDEX_INTERNAL;
- if (IN6_IS_ADDR_LINKLOCAL(&bpc->bpc_peer.sa_sin6.sin6_addr))
- bpc->bpc_peer.sa_sin6.sin6_scope_id =
- bfd->ifp != NULL ? bfd->ifp->ifindex
- : IFINDEX_INTERNAL;
- }
+ /* Add observer if we have moving parts. */
+ if (bfd->ifname[0] || bfd->vrfname[0])
+ bs_observer_add(bfd);
- /* Initialize the session */
- bfd->ses_state = PTM_BFD_DOWN;
- bfd->discrs.my_discr = ptm_bfd_gen_ID();
- bfd->discrs.remote_discr = 0;
- bfd->local_ip = bpc->bpc_local;
- bfd->local_address = bpc->bpc_local;
- bfd_recvtimer_update(bfd);
- ptm_bfd_start_xmt_timer(bfd, false);
-
- /* Registrate session into data structures. */
- bfd_id_insert(bfd);
+ /* Copy remaining data. */
+ if (bpc->bpc_ipv4 == false)
+ BFD_SET_FLAG(bfd->flags, BFD_SESS_FLAG_IPV6);
if (bpc->bpc_mhop) {
BFD_SET_FLAG(bfd->flags, BFD_SESS_FLAG_MH);
bfd->mhop.peer = bpc->bpc_peer;
bfd->mhop.local = bpc->bpc_local;
- if (vrf != NULL)
- bfd->mhop.vrfid = vrf->vrf_id;
- else
- bfd->mhop.vrfid = VRF_DEFAULT;
-
- bfd_mhop_insert(bfd);
} else {
bfd->shop.peer = bpc->bpc_peer;
- if (ifp != NULL)
- bfd->shop.ifindex = ifp->ifindex;
- else
- bfd->shop.ifindex = IFINDEX_INTERNAL;
+ }
- bfd_shop_insert(bfd);
+ bfd->local_ip = bpc->bpc_local;
+ bfd->local_address = bpc->bpc_local;
+
+ /* Try to enable session and schedule for packet receive/send. */
+ if (bfd_session_enable(bfd) == -1) {
+ /* Unrecoverable failure, remove the session/peer. */
+ bfd_session_free(bfd);
+ return NULL;
}
+ /* Apply other configurations. */
_bfd_session_update(bfd, bpc);
log_info("session-new: %s", bs_to_string(bfd));
return buf;
}
+int bs_observer_add(struct bfd_session *bs)
+{
+ struct bfd_session_observer *bso;
+
+ bso = XMALLOC(MTYPE_BFDD_SESSION_OBSERVER, sizeof(*bso));
+ bso->bso_bs = bs;
+ bso->bso_isinterface = !BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH);
+ if (bso->bso_isinterface)
+ strlcpy(bso->bso_entryname, bs->ifname,
+ sizeof(bso->bso_entryname));
+ else
+ strlcpy(bso->bso_entryname, bs->vrfname,
+ sizeof(bso->bso_entryname));
+
+ TAILQ_INSERT_TAIL(&bglobal.bg_obslist, bso, bso_entry);
+
+ return 0;
+}
+
+void bs_observer_del(struct bfd_session_observer *bso)
+{
+ TAILQ_REMOVE(&bglobal.bg_obslist, bso, bso_entry);
+ XFREE(MTYPE_BFDD_SESSION_OBSERVER, bso);
+}
+
/*
* BFD hash data structures to find sessions.
DECLARE_MTYPE(BFDD_CONFIG);
DECLARE_MTYPE(BFDD_LABEL);
DECLARE_MTYPE(BFDD_CONTROL);
+DECLARE_MTYPE(BFDD_SESSION_OBSERVER);
DECLARE_MTYPE(BFDD_NOTIFICATION);
struct bfd_timers {
struct sockaddr_any local_ip;
struct interface *ifp;
struct vrf *vrf;
+ char ifname[MAXNAMELEN];
+ char vrfname[MAXNAMELEN];
uint8_t local_mac[ETHERNET_ADDRESS_LENGTH];
uint8_t peer_mac[ETHERNET_ADDRESS_LENGTH];
int type;
};
+struct bfd_session_observer {
+ struct bfd_session *bso_bs;
+ bool bso_isinterface;
+ char bso_entryname[MAXNAMELEN];
+
+ TAILQ_ENTRY(bfd_session_observer) bso_entry;
+};
+TAILQ_HEAD(obslist, bfd_session_observer);
+
/* States defined per 4.1 */
#define PTM_BFD_ADM_DOWN 0
struct bcslist bg_bcslist;
struct pllist bg_pllist;
+
+ struct obslist bg_obslist;
};
extern struct bfd_global bglobal;
extern struct bfd_diag_str_list diag_list[];
int bp_udp_mhop(void);
int bp_udp6_shop(void);
int bp_udp6_mhop(void);
-int bp_peer_socket(struct bfd_peer_cfg *bpc);
-int bp_peer_socketv6(struct bfd_peer_cfg *bpc);
+int bp_peer_socket(const struct bfd_session *);
+int bp_peer_socketv6(const struct bfd_session *);
int bp_echo_socket(void);
int bp_echov6_socket(void);
*
* BFD protocol specific code.
*/
+int bfd_session_enable(struct bfd_session *);
+void bfd_session_disable(struct bfd_session *);
struct bfd_session *ptm_bfd_sess_new(struct bfd_peer_cfg *bpc);
int ptm_bfd_ses_del(struct bfd_peer_cfg *bpc);
void ptm_bfd_ses_dn(struct bfd_session *bfd, uint8_t diag);
void integer2timestr(uint64_t time, char *buf, size_t buflen);
const char *bs_to_string(struct bfd_session *bs);
+int bs_observer_add(struct bfd_session *);
+void bs_observer_del(struct bfd_session_observer *);
+
/* BFD hash data structures interface */
void bfd_initialize(void);
void bfd_shutdown(void);
return sd;
}
-int bp_peer_socket(struct bfd_peer_cfg *bpc)
+int bp_peer_socket(const struct bfd_session *bs)
{
int sd, pcount;
struct sockaddr_in sin;
return -1;
}
- if (bpc->bpc_has_localif) {
- if (bp_bind_dev(sd, bpc->bpc_localif) != 0) {
+ if (bs->shop.ifindex != IFINDEX_INTERNAL) {
+ if (bp_bind_dev(sd, bs->ifp->name) != 0) {
close(sd);
return -1;
}
- } else if (bpc->bpc_mhop && bpc->bpc_has_vrfname) {
- if (bp_bind_dev(sd, bpc->bpc_vrfname) != 0) {
+ } else if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH) &&
+ bs->mhop.vrfid != VRF_DEFAULT) {
+ if (bp_bind_dev(sd, bs->vrf->name) != 0) {
close(sd);
return -1;
}
}
/* Find an available source port in the proper range */
- memset(&sin, 0, sizeof(sin));
- sin = bpc->bpc_local.sa_sin;
+ sin = bs->local_ip.sa_sin;
sin.sin_family = AF_INET;
#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
sin.sin_len = sizeof(sin);
#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
- if (bpc->bpc_mhop)
- sin.sin_addr = bpc->bpc_local.sa_sin.sin_addr;
- else
+ if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH) == 0)
sin.sin_addr.s_addr = INADDR_ANY;
pcount = 0;
* IPv6 sockets
*/
-int bp_peer_socketv6(struct bfd_peer_cfg *bpc)
+int bp_peer_socketv6(const struct bfd_session *bs)
{
- struct interface *ifp;
int sd, pcount;
struct sockaddr_in6 sin6;
static int srcPort = BFD_SRCPORTINIT;
}
/* Find an available source port in the proper range */
- memset(&sin6, 0, sizeof(sin6));
+ sin6 = bs->local_ip.sa_sin6;
sin6.sin6_family = AF_INET6;
#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
sin6.sin6_len = sizeof(sin6);
#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
- sin6 = bpc->bpc_local.sa_sin6;
- if (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr)) {
- ifp = if_lookup_by_name(bpc->bpc_localif, VRF_DEFAULT);
- sin6.sin6_scope_id =
- (ifp != NULL) ? ifp->ifindex : IFINDEX_INTERNAL;
- }
- if (bpc->bpc_has_localif) {
- if (bp_bind_dev(sd, bpc->bpc_localif) != 0) {
+ if (bs->shop.ifindex != IFINDEX_INTERNAL) {
+ if (bp_bind_dev(sd, bs->ifp->name) != 0) {
close(sd);
return -1;
}
- } else if (bpc->bpc_mhop && bpc->bpc_has_vrfname) {
- if (bp_bind_dev(sd, bpc->bpc_vrfname) != 0) {
+ } else if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH) &&
+ bs->mhop.vrfid != VRF_DEFAULT) {
+ if (bp_bind_dev(sd, bs->vrf->name) != 0) {
close(sd);
return -1;
}
DEFINE_MTYPE(BFDD, BFDD_CONFIG, "long-lived configuration memory");
DEFINE_MTYPE(BFDD, BFDD_LABEL, "long-lived label memory");
DEFINE_MTYPE(BFDD, BFDD_CONTROL, "long-lived control socket memory");
+DEFINE_MTYPE(BFDD, BFDD_SESSION_OBSERVER, "Session observer");
DEFINE_MTYPE(BFDD, BFDD_NOTIFICATION, "short-lived control notification data");
/* Master of threads. */
static void bg_init(void)
{
TAILQ_INIT(&bglobal.bg_bcslist);
+ TAILQ_INIT(&bglobal.bg_obslist);
bglobal.bg_shop = bp_udp_shop();
bglobal.bg_mhop = bp_udp_mhop();
*/
static int bfdd_write_config(struct vty *vty);
static int bfdd_peer_write_config(struct vty *vty);
-static void _bfdd_peer_write_config(struct hash_backet *hb, void *arg);
+static void _bfdd_peer_write_config(struct vty *vty, struct bfd_session *bs);
+static void _bfdd_peer_write_config_iter(struct hash_backet *hb, void *arg);
static int bfd_configure_peer(struct bfd_peer_cfg *bpc, bool mhop,
const struct sockaddr_any *peer,
const struct sockaddr_any *local,
vty_out(vty, "\tpeer %s", satostr(&bs->mhop.peer));
vty_out(vty, " multihop");
vty_out(vty, " local-address %s", satostr(&bs->mhop.local));
- if (bs->mhop.vrfid != VRF_DEFAULT)
- vty_out(vty, " vrf %s", bs->vrf->name);
+ if (bs->vrfname[0])
+ vty_out(vty, " vrf %s", bs->vrfname);
vty_out(vty, "\n");
} else {
vty_out(vty, "\tpeer %s", satostr(&bs->shop.peer));
if (bs->local_address.sa_sin.sin_family != AF_UNSPEC)
vty_out(vty, " local-address %s",
satostr(&bs->local_address));
- if (bs->shop.ifindex != IFINDEX_INTERNAL)
- vty_out(vty, " interface %s", bs->ifp->name);
+ if (bs->ifname[0])
+ vty_out(vty, " interface %s", bs->ifname);
vty_out(vty, "\n");
}
json_object_boolean_true_add(jo, "multihop");
json_object_string_add(jo, "peer", satostr(&bs->mhop.peer));
json_object_string_add(jo, "local", satostr(&bs->mhop.local));
- if (bs->mhop.vrfid != VRF_DEFAULT)
- json_object_string_add(jo, "vrf", bs->vrf->name);
+ if (bs->vrfname[0])
+ json_object_string_add(jo, "vrf", bs->vrfname);
} else {
json_object_boolean_false_add(jo, "multihop");
json_object_string_add(jo, "peer", satostr(&bs->shop.peer));
if (bs->local_address.sa_sin.sin_family != AF_UNSPEC)
json_object_string_add(jo, "local",
satostr(&bs->local_address));
- if (bs->shop.ifindex != IFINDEX_INTERNAL)
- json_object_string_add(jo, "interface", bs->ifp->name);
+ if (bs->ifname[0])
+ json_object_string_add(jo, "interface", bs->ifname);
}
if (bs->pl)
return 0;
}
-static void _bfdd_peer_write_config(struct hash_backet *hb, void *arg)
+static void _bfdd_peer_write_config(struct vty *vty, struct bfd_session *bs)
{
- struct vty *vty = arg;
- struct bfd_session *bs = hb->data;
-
if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) {
vty_out(vty, " peer %s", satostr(&bs->mhop.peer));
vty_out(vty, " multihop");
vty_out(vty, " local-address %s", satostr(&bs->mhop.local));
- if (bs->mhop.vrfid != VRF_DEFAULT)
- vty_out(vty, " vrf %s", bs->vrf->name);
+ if (bs->vrfname[0])
+ vty_out(vty, " vrf %s", bs->vrfname);
vty_out(vty, "\n");
} else {
vty_out(vty, " peer %s", satostr(&bs->shop.peer));
if (bs->local_address.sa_sin.sin_family != AF_UNSPEC)
vty_out(vty, " local-address %s",
satostr(&bs->local_address));
- if (bs->shop.ifindex != IFINDEX_INTERNAL)
- vty_out(vty, " interface %s", bs->ifp->name);
+ if (bs->ifname[0])
+ vty_out(vty, " interface %s", bs->ifname);
vty_out(vty, "\n");
}
+ if (bs->sock == -1)
+ vty_out(vty, " ! vrf or interface doesn't exist\n");
+
if (bs->detect_mult != BPC_DEF_DETECTMULTIPLIER)
vty_out(vty, " detect-multiplier %d\n", bs->detect_mult);
if (bs->timers.required_min_rx != (BPC_DEF_RECEIVEINTERVAL * 1000))
return CMD_SUCCESS;
}
+static void _bfdd_peer_write_config_iter(struct hash_backet *hb, void *arg)
+{
+ struct vty *vty = arg;
+ struct bfd_session *bs = hb->data;
+
+ _bfdd_peer_write_config(vty, bs);
+}
+
static int bfdd_peer_write_config(struct vty *vty)
{
- bfd_id_iterate(_bfdd_peer_write_config, vty);
+ struct bfd_session_observer *bso;
+
+ bfd_id_iterate(_bfdd_peer_write_config_iter, vty);
+ TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) {
+ /* Only print disabled sessions here. */
+ if (bso->bso_bs->sock != -1)
+ continue;
+
+ _bfdd_peer_write_config(vty, bso->bso_bs);
+ }
+
return 1;
}
}
} else {
bpc->bpc_peer = pl->pl_bs->shop.peer;
- if (pl->pl_bs->shop.ifindex != IFINDEX_INTERNAL) {
+ if (pl->pl_bs->ifname[0]) {
bpc->bpc_has_localif = true;
- strlcpy(bpc->bpc_localif, pl->pl_bs->ifp->name,
+ strlcpy(bpc->bpc_localif, pl->pl_bs->ifname,
sizeof(bpc->bpc_localif));
}
}
satostr(&bs->mhop.peer));
json_object_string_add(jo, "local-address",
satostr(&bs->mhop.local));
- if (bs->mhop.vrfid != VRF_DEFAULT)
- json_object_string_add(jo, "vrf-name", bs->vrf->name);
+ if (bs->vrfname[0])
+ json_object_string_add(jo, "vrf-name", bs->vrfname);
} else {
json_object_boolean_false_add(jo, "multihop");
json_object_string_add(jo, "peer-address",
if (bs->local_address.sa_sin.sin_family != AF_UNSPEC)
json_object_string_add(jo, "local-address",
satostr(&bs->local_address));
- if (bs->shop.ifindex != IFINDEX_INTERNAL)
+ if (bs->ifname[0])
json_object_string_add(jo, "local-interface",
- bs->ifp->name);
+ bs->ifname);
}
if (bs->pl)
bfd_recvtimer_delete(bs);
/* Don't add event if peer is deactivated. */
- if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN))
+ if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN) ||
+ bs->sock == -1)
return;
tv_normalize(&tv);
bfd_echo_recvtimer_delete(bs);
/* Don't add event if peer is deactivated. */
- if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN))
+ if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN) ||
+ bs->sock == -1)
return;
tv_normalize(&tv);
bfd_xmttimer_delete(bs);
/* Don't add event if peer is deactivated. */
- if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN))
+ if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN) ||
+ bs->sock == -1)
return;
tv_normalize(&tv);
bfd_echo_xmttimer_delete(bs);
/* Don't add event if peer is deactivated. */
- if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN))
+ if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN) ||
+ bs->sock == -1)
return;
tv_normalize(&tv);
zclient_send_message(zclient);
}
-static int bfdd_interface_update(int cmd, struct zclient *zc, uint16_t len,
+static void bfdd_sessions_enable_interface(struct interface *ifp)
+{
+ struct bfd_session_observer *bso;
+ struct bfd_session *bs;
+
+ TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) {
+ if (bso->bso_isinterface == false)
+ continue;
+
+ /* Interface name mismatch. */
+ bs = bso->bso_bs;
+ if (strcmp(ifp->name, bs->ifname))
+ continue;
+ /* Skip enabled sessions. */
+ if (bs->sock != -1)
+ continue;
+
+ /* Try to enable it. */
+ bfd_session_enable(bs);
+ }
+}
+
+static void bfdd_sessions_disable_interface(struct interface *ifp)
+{
+ struct bfd_session_observer *bso;
+ struct bfd_session *bs;
+
+ TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) {
+ if (bso->bso_isinterface == false)
+ continue;
+
+ /* Interface name mismatch. */
+ bs = bso->bso_bs;
+ if (strcmp(ifp->name, bs->ifname))
+ continue;
+ /* Skip disabled sessions. */
+ if (bs->sock == -1)
+ continue;
+
+ /* Try to enable it. */
+ bfd_session_disable(bs);
+
+ TAILQ_INSERT_HEAD(&bglobal.bg_obslist, bso, bso_entry);
+ }
+}
+
+static int bfdd_interface_update(int cmd, struct zclient *zc,
+ uint16_t len __attribute__((__unused__)),
vrf_id_t vrfid)
{
+ struct interface *ifp;
+
/*
* `zebra_interface_add_read` will handle the interface creation
* on `lib/if.c`. We'll use that data structure instead of
* rolling our own.
*/
if (cmd == ZEBRA_INTERFACE_ADD) {
- zebra_interface_add_read(zc->ibuf, vrfid);
+ ifp = zebra_interface_add_read(zc->ibuf, vrfid);
+ if (ifp == NULL)
+ return 0;
+
+ bfdd_sessions_enable_interface(ifp);
return 0;
}
/* Update interface information. */
- zebra_interface_state_read(zc->ibuf, vrfid);
+ ifp = zebra_interface_state_read(zc->ibuf, vrfid);
+ if (ifp == NULL)
+ return 0;
- /* TODO: stop all sessions using this interface. */
+ bfdd_sessions_disable_interface(ifp);
return 0;
}