mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-05 11:48:50 +00:00
Merge pull request #3600 from opensourcerouting/bfd-zebra-if
bfdd: use zebra API to learn about interfaces
This commit is contained in:
commit
25794e0f15
33
bfdd/bfd.c
33
bfdd/bfd.c
@ -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 */
|
||||
|
20
bfdd/bfd.h
20
bfdd/bfd.h
@ -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_ */
|
||||
|
@ -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) {
|
||||
|
64
bfdd/bsd.c
64
bfdd/bsd.c
@ -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)
|
||||
{
|
||||
/*
|
||||
|
58
bfdd/linux.c
58
bfdd/linux.c
@ -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__)))
|
||||
{
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user