Merge pull request #3600 from opensourcerouting/bfd-zebra-if

bfdd: use zebra API to learn about interfaces
This commit is contained in:
Donald Sharp 2019-01-13 19:18:38 -05:00 committed by GitHub
commit 25794e0f15
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 112 additions and 161 deletions

View File

@ -540,6 +540,7 @@ static void bfd_session_free(struct bfd_session *bs)
struct bfd_session *ptm_bfd_sess_new(struct bfd_peer_cfg *bpc)
{
struct bfd_session *bfd, *l_bfd;
struct interface *ifp = NULL;
int psock;
/* check to see if this needs a new session */
@ -552,6 +553,24 @@ struct bfd_session *ptm_bfd_sess_new(struct bfd_peer_cfg *bpc)
return NULL;
}
/*
* No session found, we have to allocate a new one.
*
* First a few critical checks:
*
* * Check that the specified interface exists.
* * Attempt to create the UDP socket (might fail if we exceed
* our limits).
*/
if (bpc->bpc_has_localif) {
ifp = if_lookup_by_name(bpc->bpc_localif, VRF_DEFAULT);
if (ifp == NULL) {
log_error(
"session-new: specified interface doesn't exists.");
return NULL;
}
}
/*
* Get socket for transmitting control packets. Note that if we
* could use the destination port (3784) for the source
@ -574,19 +593,21 @@ struct bfd_session *ptm_bfd_sess_new(struct bfd_peer_cfg *bpc)
return NULL;
}
if (bpc->bpc_has_localif && !bpc->bpc_mhop) {
bfd->ifindex = ptm_bfd_fetch_ifindex(bpc->bpc_localif);
ptm_bfd_fetch_local_mac(bpc->bpc_localif, bfd->local_mac);
}
if (bpc->bpc_has_localif && !bpc->bpc_mhop)
bfd->ifp = ifp;
if (bpc->bpc_ipv4 == false) {
BFD_SET_FLAG(bfd->flags, BFD_SESS_FLAG_IPV6);
/* 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->ifindex;
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->ifindex;
bpc->bpc_peer.sa_sin6.sin6_scope_id =
bfd->ifp != NULL ? bfd->ifp->ifindex
: IFINDEX_INTERNAL;
}
/* Initialize the session */

View File

@ -31,6 +31,7 @@
#include "lib/libfrr.h"
#include "lib/qobj.h"
#include "lib/queue.h"
#include "lib/vrf.h"
#include "bfdctl.h"
@ -237,7 +238,7 @@ struct bfd_session {
struct sockaddr_any local_address;
struct sockaddr_any local_ip;
int ifindex;
struct interface *ifp;
uint8_t local_mac[ETHERNET_ADDRESS_LENGTH];
uint8_t peer_mac[ETHERNET_ADDRESS_LENGTH];
@ -512,7 +513,6 @@ 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 ptm_bfd_ses_up(struct bfd_session *bfd);
void fetch_portname_from_ifindex(int ifindex, char *ifname, size_t ifnamelen);
void ptm_bfd_echo_stop(struct bfd_session *bfd, int polling);
void ptm_bfd_echo_start(struct bfd_session *bfd);
void ptm_bfd_xmt_TO(struct bfd_session *bfd, int fbit);
@ -584,20 +584,4 @@ void bfdd_zclient_stop(void);
int ptm_bfd_notify(struct bfd_session *bs);
/*
* OS compatibility functions.
*/
#if defined(BFD_LINUX) || defined(BFD_BSD)
int ptm_bfd_fetch_ifindex(const char *ifname);
void ptm_bfd_fetch_local_mac(const char *ifname, uint8_t *mac);
void fetch_portname_from_ifindex(int ifindex, char *ifname, size_t ifnamelen);
#endif /* BFD_LINUX || BFD_BSD */
#ifdef BFD_BSD
ssize_t bsd_echo_sock_read(int sd, uint8_t *buf, ssize_t *buflen,
struct sockaddr_storage *ss, socklen_t *sslen,
uint8_t *ttl, uint32_t *id);
#endif /* BFD_BSD */
#endif /* _BFD_H_ */

View File

@ -241,6 +241,7 @@ ssize_t bfd_recv_ipv4(int sd, uint8_t *msgbuf, size_t msgbuflen, uint8_t *ttl,
size_t vrfnamelen, struct sockaddr_any *local,
struct sockaddr_any *peer)
{
struct interface *ifp;
struct cmsghdr *cm;
int ifindex;
ssize_t mlen;
@ -307,8 +308,14 @@ ssize_t bfd_recv_ipv4(int sd, uint8_t *msgbuf, size_t msgbuflen, uint8_t *ttl,
#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
local->sa_sin.sin_len = sizeof(local->sa_sin);
#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
fetch_portname_from_ifindex(pi->ipi_ifindex, port,
portlen);
ifp = if_lookup_by_index(pi->ipi_ifindex, VRF_DEFAULT);
if (ifp == NULL)
break;
if (strlcpy(port, ifp->name, portlen) >= portlen)
log_debug(
"ipv4-recv: interface name truncated");
break;
}
#endif /* BFD_LINUX */
@ -345,8 +352,15 @@ ssize_t bfd_recv_ipv4(int sd, uint8_t *msgbuf, size_t msgbuflen, uint8_t *ttl,
/* OS agnostic way of getting interface name. */
if (port[0] == 0) {
ifindex = getsockopt_ifindex(AF_INET, &msghdr);
if (ifindex > 0)
fetch_portname_from_ifindex(ifindex, port, portlen);
if (ifindex <= 0)
return mlen;
ifp = if_lookup_by_index(ifindex, VRF_DEFAULT);
if (ifp == NULL)
return mlen;
if (strlcpy(port, ifp->name, portlen) >= portlen)
log_debug("ipv4-recv: interface name truncated");
}
return mlen;
@ -357,6 +371,7 @@ ssize_t bfd_recv_ipv6(int sd, uint8_t *msgbuf, size_t msgbuflen, uint8_t *ttl,
size_t vrfnamelen, struct sockaddr_any *local,
struct sockaddr_any *peer)
{
struct interface *ifp;
struct cmsghdr *cm;
struct in6_pktinfo *pi6 = NULL;
int ifindex = 0;
@ -413,9 +428,16 @@ ssize_t bfd_recv_ipv6(int sd, uint8_t *msgbuf, size_t msgbuflen, uint8_t *ttl,
#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
local->sa_sin6.sin6_len = sizeof(local->sa_sin6);
#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
fetch_portname_from_ifindex(pi6->ipi6_ifindex,
port, portlen);
ifindex = pi6->ipi6_ifindex;
ifp = if_lookup_by_index(ifindex, VRF_DEFAULT);
if (ifp == NULL)
break;
if (strlcpy(port, ifp->name, portlen)
>= portlen)
log_debug(
"ipv6-recv: interface name truncated");
}
}
}
@ -610,8 +632,8 @@ int bfd_recv_cb(struct thread *t)
* If no interface was detected, save the interface where the
* packet came in.
*/
if (bfd->ifindex == 0)
bfd->ifindex = ptm_bfd_fetch_ifindex(port);
if (bfd->ifp == NULL)
bfd->ifp = if_lookup_by_name(port, VRF_DEFAULT);
/* Log remote discriminator changes. */
if ((bfd->discrs.remote_discr != 0)
@ -1046,7 +1068,8 @@ int bp_peer_socket(struct bfd_peer_cfg *bpc)
int bp_peer_socketv6(struct bfd_peer_cfg *bpc)
{
int sd, pcount, ifindex;
struct interface *ifp;
int sd, pcount;
struct sockaddr_in6 sin6;
static int srcPort = BFD_SRCPORTINIT;
@ -1076,9 +1099,11 @@ int bp_peer_socketv6(struct bfd_peer_cfg *bpc)
sin6.sin6_len = sizeof(sin6);
#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
sin6 = bpc->bpc_local.sa_sin6;
ifindex = ptm_bfd_fetch_ifindex(bpc->bpc_localif);
if (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr))
sin6.sin6_scope_id = ifindex;
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) {

View File

@ -35,70 +35,6 @@
/*
* Definitions.
*/
int ptm_bfd_fetch_ifindex(const char *ifname)
{
return if_nametoindex(ifname);
}
void ptm_bfd_fetch_local_mac(const char *ifname, uint8_t *mac)
{
struct ifaddrs *ifap, *ifa;
struct if_data *ifi;
struct sockaddr_dl *sdl;
size_t maclen;
/* Always clean the target, zeroed macs mean failure. */
memset(mac, 0, ETHERNET_ADDRESS_LENGTH);
if (getifaddrs(&ifap) != 0)
return;
for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
/* Find interface with that name. */
if (strcmp(ifa->ifa_name, ifname) != 0)
continue;
/* Skip non link addresses. We want the MAC address. */
if (ifa->ifa_addr->sa_family != AF_LINK)
continue;
sdl = (struct sockaddr_dl *)ifa->ifa_addr;
ifi = (struct if_data *)ifa->ifa_data;
/* Skip non ethernet related data. */
if (ifi->ifi_type != IFT_ETHER)
continue;
if (sdl->sdl_alen != ETHERNET_ADDRESS_LENGTH)
log_warning("%s:%d mac address length %d (expected %d)",
__func__, __LINE__, sdl->sdl_alen,
ETHERNET_ADDRESS_LENGTH);
maclen = (sdl->sdl_alen > ETHERNET_ADDRESS_LENGTH)
? ETHERNET_ADDRESS_LENGTH
: sdl->sdl_alen;
memcpy(mac, LLADDR(sdl), maclen);
break;
}
freeifaddrs(ifap);
}
/* Was _fetch_portname_from_ifindex() */
void fetch_portname_from_ifindex(int ifindex, char *ifname, size_t ifnamelen)
{
char ifname_tmp[IF_NAMESIZE];
/* Set ifname to empty to signalize failures. */
memset(ifname, 0, ifnamelen);
if (if_indextoname(ifindex, ifname_tmp) == NULL)
return;
if (strlcpy(ifname, ifname_tmp, ifnamelen) > ifnamelen)
log_warning("%s:%d interface name truncated", __func__,
__LINE__);
}
int bp_bind_dev(int sd, const char *dev)
{
/*

View File

@ -29,64 +29,6 @@
/*
* Definitions.
*/
int ptm_bfd_fetch_ifindex(const char *ifname)
{
struct ifreq ifr;
if (strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name))
> sizeof(ifr.ifr_name))
log_error("interface-to-index: name truncated ('%s' -> '%s')",
ifr.ifr_name, ifname);
if (ioctl(bglobal.bg_shop, SIOCGIFINDEX, &ifr) == -1) {
log_error("interface-to-index: %s translation failed: %s",
ifname, strerror(errno));
return -1;
}
return ifr.ifr_ifindex;
}
void ptm_bfd_fetch_local_mac(const char *ifname, uint8_t *mac)
{
struct ifreq ifr;
if (strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name))
> sizeof(ifr.ifr_name))
log_error("interface-mac: name truncated ('%s' -> '%s')",
ifr.ifr_name, ifname);
if (ioctl(bglobal.bg_shop, SIOCGIFHWADDR, &ifr) == -1) {
log_error("interface-mac: %s MAC retrieval failed: %s", ifname,
strerror(errno));
return;
}
memcpy(mac, ifr.ifr_hwaddr.sa_data, ETHERNET_ADDRESS_LENGTH);
}
/* Was _fetch_portname_from_ifindex() */
void fetch_portname_from_ifindex(int ifindex, char *ifname, size_t ifnamelen)
{
struct ifreq ifr;
ifname[0] = 0;
memset(&ifr, 0, sizeof(ifr));
ifr.ifr_ifindex = ifindex;
if (ioctl(bglobal.bg_shop, SIOCGIFNAME, &ifr) == -1) {
log_error("index-to-interface: index %d failure: %s", ifindex,
strerror(errno));
return;
}
if (strlcpy(ifname, ifr.ifr_name, ifnamelen) >= ifnamelen)
log_debug("index-to-interface: name truncated '%s' -> '%s'",
ifr.ifr_name, ifname);
}
int bp_bind_dev(int sd __attribute__((__unused__)),
const char *dev __attribute__((__unused__)))
{

View File

@ -189,7 +189,10 @@ int ptm_bfd_notify(struct bfd_session *bs)
stream_putl(msg, ZEBRA_INTERFACE_BFD_DEST_UPDATE);
/* NOTE: Interface is a shortcut to avoid comparing source address. */
stream_putl(msg, bs->ifindex);
if (bs->ifp != NULL)
stream_putl(msg, bs->ifp->ifindex);
else
stream_putl(msg, IFINDEX_INTERNAL);
/* BFD destination prefix information. */
if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH))
@ -287,6 +290,7 @@ stream_failure:
static int _ptm_msg_read(struct stream *msg, int command,
struct bfd_peer_cfg *bpc, struct ptm_client **pc)
{
struct interface *ifp;
uint32_t pid;
uint8_t ttl __attribute__((unused));
size_t ifnamelen;
@ -393,9 +397,19 @@ static int _ptm_msg_read(struct stream *msg, int command,
*/
if (bpc->bpc_ipv4 == false
&& IN6_IS_ADDR_LINKLOCAL(
&bpc->bpc_peer.sa_sin6.sin6_addr))
&bpc->bpc_peer.sa_sin6.sin6_addr)) {
ifp = if_lookup_by_name_all_vrf(
bpc->bpc_localif);
if (ifp == NULL) {
log_error(
"ptm-read: interface %s doesn't exists",
bpc->bpc_localif);
return -1;
}
bpc->bpc_peer.sa_sin6.sin6_scope_id =
ptm_bfd_fetch_ifindex(bpc->bpc_localif);
ifp->ifindex;
}
}
}
@ -576,9 +590,34 @@ static void bfdd_zebra_connected(struct zclient *zc)
stream_putl(msg, ZEBRA_BFD_DEST_REPLAY);
stream_putw_at(msg, 0, stream_get_endp(msg));
/* Ask for interfaces information. */
zclient_create_header(msg, ZEBRA_INTERFACE_ADD, VRF_DEFAULT);
/* Send requests. */
zclient_send_message(zclient);
}
static int bfdd_interface_update(int cmd, struct zclient *zc, uint16_t len,
vrf_id_t vrfid)
{
/*
* `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);
return 0;
}
/* Update interface information. */
zebra_interface_state_read(zc->ibuf, vrfid);
/* TODO: stop all sessions using this interface. */
return 0;
}
void bfdd_zclient_init(struct zebra_privs_t *bfdd_priv)
{
zclient = zclient_new(master, &zclient_options_default);
@ -594,6 +633,10 @@ void bfdd_zclient_init(struct zebra_privs_t *bfdd_priv)
/* Send replay request on zebra connect. */
zclient->zebra_connected = bfdd_zebra_connected;
/* Learn interfaces from zebra instead of the OS. */
zclient->interface_add = bfdd_interface_update;
zclient->interface_delete = bfdd_interface_update;
}
void bfdd_zclient_stop(void)