summaryrefslogtreecommitdiffstats
path: root/ospf6d/ospf6_interface.c
diff options
context:
space:
mode:
authorDonald Sharp <sharpd@cumulusnetworks.com>2021-07-13 15:40:13 +0200
committerGitHub <noreply@github.com>2021-07-13 15:40:13 +0200
commit802a83935f57ec9162bbfae61bb5b6231aaf6681 (patch)
treee99e81fd34234442adc39bc213ba36f4aa8a3377 /ospf6d/ospf6_interface.c
parentMerge pull request #9036 from donaldsharp/hash_cmp_stuff (diff)
parentospf6d: fix freebsd mcast group issues (diff)
downloadfrr-802a83935f57ec9162bbfae61bb5b6231aaf6681.tar.xz
frr-802a83935f57ec9162bbfae61bb5b6231aaf6681.zip
Merge pull request #9037 from idryzhov/ospf6-freebsd
ospf6d: fix freebsd mcast group issues
Diffstat (limited to 'ospf6d/ospf6_interface.c')
-rw-r--r--ospf6d/ospf6_interface.c59
1 files changed, 48 insertions, 11 deletions
diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c
index 92c88623a..b52d6af90 100644
--- a/ospf6d/ospf6_interface.c
+++ b/ospf6d/ospf6_interface.c
@@ -680,6 +680,43 @@ static uint8_t dr_election(struct ospf6_interface *oi)
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 */
int interface_up(struct thread *thread)
@@ -693,11 +730,7 @@ int interface_up(struct thread *thread)
if (!oi->type_cfg)
oi->type = ospf6_default_iftype(oi->interface);
- /*
- * 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;
+ thread_cancel(&oi->thread_sso);
if (IS_OSPF6_DEBUG_INTERFACE)
zlog_debug("Interface Event %s: [InterfaceUp]",
@@ -740,13 +773,17 @@ int interface_up(struct thread *thread)
#ifdef __FreeBSD__
/*
- * XXX: Schedule IPv6 group join for later, otherwise we might
- * lose the multicast group registration caused by IPv6 group
- * leave race.
+ * 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. We have to do the join only after
+ * the interface actually left the group.
*/
- if (oi->sso_try_cnt == 0) {
- oi->sso_try_cnt++;
- zlog_info("Scheduling %s for sso", oi->interface->name);
+ if (ifmaddr_check(oi->interface->ifindex, &allspfrouters6)) {
+ zlog_info(
+ "Interface %s is still in all routers group, rescheduling for SSO",
+ oi->interface->name);
thread_add_timer(master, interface_up, oi,
OSPF6_INTERFACE_SSO_RETRY_INT,
&oi->thread_sso);