2
0
mirror of https://github.com/xcat2/confluent.git synced 2026-10-20 14:45:45 +00:00

Perodically reopen the multicast sockets

It has been observed there are times where an ethernet switch is partially working with MLD snoop/IGMP snoop.  A workaround for the unreliable behavior seems to be to reassert multicast joins ever so often.

Give it a try to restart the SSDP sockets every minute.
This commit is contained in:
Jarrod Johnson
2026-08-10 11:24:02 -04:00
parent 0c18bc1c01
commit 120050ae78
@@ -135,6 +135,45 @@ async def check_fish_handler(handler, peerdata, known_peers, newmacs, peerbymaca
machandlers[mac] = handler
def _open_snoop_sockets(cloop, pktq):
net6 = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
net6.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 1)
for ifidx in util.list_interface_indexes():
v6grp = ssdp6mcast + struct.pack('=I', ifidx)
net6.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_JOIN_GROUP, v6grp)
net6.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
net4 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
for i4 in util.list_ips():
ssdp4mcast = socket.inet_pton(socket.AF_INET, mcastv4addr) + \
socket.inet_aton(i4['addr'])
try:
net4.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP,
ssdp4mcast)
except socket.error as e:
if e.errno != 98:
# errno 98 can happen if aliased, skip for now
raise
net4.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
net4.bind(('', 1900))
net6.bind(('', 1900))
cloop.add_reader(net4, _relay_pkt, net4, pktq)
cloop.add_reader(net6, _relay_pkt, net6, pktq)
return net4, net6
def _renew_snoop_sockets(cloop, pktq, net4, net6):
for oldsock in (net4, net6):
try:
cloop.remove_reader(oldsock)
except Exception:
pass
try:
oldsock.close()
except Exception:
pass
return _open_snoop_sockets(cloop, pktq)
async def snoop(handler, byehandler=None, protocol=None, uuidlookup=None):
"""Watch for SSDP notify messages
@@ -160,30 +199,9 @@ async def snoop(handler, byehandler=None, protocol=None, uuidlookup=None):
event=log.Events.stacktrace)
known_peers = set([])
recent_peers = set([])
net6 = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
net6.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 1)
for ifidx in util.list_interface_indexes():
v6grp = ssdp6mcast + struct.pack('=I', ifidx)
net6.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_JOIN_GROUP, v6grp)
net6.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
net4 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
for i4 in util.list_ips():
ssdp4mcast = socket.inet_pton(socket.AF_INET, mcastv4addr) + \
socket.inet_aton(i4['addr'])
try:
net4.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP,
ssdp4mcast)
except socket.error as e:
if e.errno != 98:
# errno 98 can happen if aliased, skip for now
raise
net4.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
net4.bind(('', 1900))
net6.bind(('', 1900))
pktq = asyncio.Queue()
cloop = asyncio.get_running_loop()
cloop.add_reader(net4, _relay_pkt, net4, pktq)
cloop.add_reader(net6, _relay_pkt, net6, pktq)
net4, net6 = _open_snoop_sockets(cloop, pktq)
lastrenew = time.time()
peerbymacaddress = {}
newmacs = set([])
deferrednotifies = []
@@ -194,7 +212,20 @@ async def snoop(handler, byehandler=None, protocol=None, uuidlookup=None):
deferrednotifies.clear()
machandlers.clear()
timeout = None
srp = await pktq.get()
# Periodically close and reopen the sockets so that multicast
# group memberships are reasserted, working around switches with
# glitchy MLD/IGMP snooping that would otherwise stop forwarding.
renewwait = lastrenew + 60 - time.time()
if renewwait <= 0:
net4, net6 = _renew_snoop_sockets(cloop, pktq, net4, net6)
lastrenew = time.time()
continue
try:
srp = await asyncio.wait_for(pktq.get(), timeout=renewwait)
except asyncio.exceptions.TimeoutError:
net4, net6 = _renew_snoop_sockets(cloop, pktq, net4, net6)
lastrenew = time.time()
continue
recent_peers.clear()
while srp and len(deferrednotifies) < 256:
srp = None