ospf6d: fix freebsd mcast group issues

There's a delay in FreeBSD between issuing a command to leave a
multicast group and an actual leave. If we execute "no router ospf6" and
"router ospf6" fast enough, we can end up in a situation when OS
performs the leave later than it performs the join and the interface
remains without a multicast group.

Instead of counting on a one second delay, we must wait until the
interface actually leaves the group.

Signed-off-by: Igor Ryzhov <iryzhov@nfware.com>
This commit is contained in:
Igor Ryzhov 2021-07-12 22:51:49 +03:00
parent 507559a089
commit 93828a9923

View File

@ -680,6 +680,43 @@ static uint8_t dr_election(struct ospf6_interface *oi)
return next_state; return next_state;
} }
#ifdef __FreeBSD__
#include <ifaddrs.h>
static bool ifmaddr_check(ifindex_t ifindex, struct in6_addr *addr)
{
struct ifmaddrs *ifmap, *ifma;
struct sockaddr_dl *sdl;
struct sockaddr_in6 *sin6;
bool found = false;
if (getifmaddrs(&ifmap) != 0)
return false;
for (ifma = ifmap; ifma; ifma = ifma->ifma_next) {
if (ifma->ifma_name == NULL || ifma->ifma_addr == NULL)
continue;
if (ifma->ifma_name->sa_family != AF_LINK)
continue;
if (ifma->ifma_addr->sa_family != AF_INET6)
continue;
sdl = (struct sockaddr_dl *)ifma->ifma_name;
sin6 = (struct sockaddr_in6 *)ifma->ifma_addr;
if (sdl->sdl_index == ifindex
&& memcmp(&sin6->sin6_addr, addr, IPV6_MAX_BYTELEN) == 0) {
found = true;
break;
}
}
if (ifmap)
freeifmaddrs(ifmap);
return found;
}
#endif /* __FreeBSD__ */
/* Interface State Machine */ /* Interface State Machine */
int interface_up(struct thread *thread) int interface_up(struct thread *thread)
@ -693,11 +730,7 @@ int interface_up(struct thread *thread)
if (!oi->type_cfg) if (!oi->type_cfg)
oi->type = ospf6_default_iftype(oi->interface); oi->type = ospf6_default_iftype(oi->interface);
/* thread_cancel(&oi->thread_sso);
* Remove old pointer. If this thread wasn't a timer this
* operation won't make a difference, because it is already NULL.
*/
oi->thread_sso = NULL;
if (IS_OSPF6_DEBUG_INTERFACE) if (IS_OSPF6_DEBUG_INTERFACE)
zlog_debug("Interface Event %s: [InterfaceUp]", zlog_debug("Interface Event %s: [InterfaceUp]",
@ -740,13 +773,17 @@ int interface_up(struct thread *thread)
#ifdef __FreeBSD__ #ifdef __FreeBSD__
/* /*
* XXX: Schedule IPv6 group join for later, otherwise we might * There's a delay in FreeBSD between issuing a command to leave a
* lose the multicast group registration caused by IPv6 group * multicast group and an actual leave. If we execute "no router ospf6"
* leave race. * and "router ospf6" fast enough, we can end up in a situation when OS
* performs the leave later than it performs the join and the interface
* remains without a multicast group. We have to do the join only after
* the interface actually left the group.
*/ */
if (oi->sso_try_cnt == 0) { if (ifmaddr_check(oi->interface->ifindex, &allspfrouters6)) {
oi->sso_try_cnt++; zlog_info(
zlog_info("Scheduling %s for sso", oi->interface->name); "Interface %s is still in all routers group, rescheduling for SSO",
oi->interface->name);
thread_add_timer(master, interface_up, oi, thread_add_timer(master, interface_up, oi,
OSPF6_INTERFACE_SSO_RETRY_INT, OSPF6_INTERFACE_SSO_RETRY_INT,
&oi->thread_sso); &oi->thread_sso);