diff --git a/bfdd/bfd.c b/bfdd/bfd.c index 814366f320..e86659b06d 100644 --- a/bfdd/bfd.c +++ b/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 */ diff --git a/bfdd/bfd.h b/bfdd/bfd.h index 3a58a8d53c..a3e5ad1447 100644 --- a/bfdd/bfd.h +++ b/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_ */ diff --git a/bfdd/bfd_packet.c b/bfdd/bfd_packet.c index 606f739b46..9cfd7e866f 100644 --- a/bfdd/bfd_packet.c +++ b/bfdd/bfd_packet.c @@ -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) { diff --git a/bfdd/bsd.c b/bfdd/bsd.c index e0fb340e30..923fbd909e 100644 --- a/bfdd/bsd.c +++ b/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) { /* diff --git a/bfdd/linux.c b/bfdd/linux.c index e260851ddb..3a76b459d7 100644 --- a/bfdd/linux.c +++ b/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__))) { diff --git a/bfdd/ptm_adapter.c b/bfdd/ptm_adapter.c index f9c7c16fb1..a57167376a 100644 --- a/bfdd/ptm_adapter.c +++ b/bfdd/ptm_adapter.c @@ -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)