raw icon indicating copy to clipboard operation
raw copied to clipboard

MAC Layer Multicast Group Joining

Open bpillatsch opened this issue 8 years ago • 4 comments

I'd like to submit a PR for Multicast group joining, I have an initial hack at the Linux implementation however I am running into a question of how to proceed for BSD. Because Linux implements multicast join as a setsockopt, that is not an option on the BSD side. There does not appear to be any way with BPF (there are filter commands but they do not add the mcast addr to the interface so they capture nothing... tcpdump -i emx -np ether multicast shows no output until manual addition of mcast groups). BSD does have mtest which takes commands and sends them to ioctl via a AF_LINK socket.

Do you think this should be implemented by opening an AF_LINK socket simply to add the mcast then closing the socket? Also this is a perm add so we'd have to defer a mcast group deletion on thread close.

Example (considering some changes) on the Linux side...

// JoinMulticast joins or drops membership of datalink layer multicast address on interface,
// allowing it to recieve multicast traffic.
func (p *packetConn) SetMulticast(b bool, addr net.Addr) error {
	// Ensure correct Addr type
	a, ok := addr.(*Addr)
	if !ok || len(a.HardwareAddr) < 6 {
		return syscall.EINVAL
	}

	// Convert hardware address back to byte array form
	var baddr [8]byte

	copy(baddr[:], a.HardwareAddr)

	mreq := unix.PacketMreq{
		Ifindex: int32(p.ifi.Index),
		Type:    unix.PACKET_MR_MULTICAST,
		Alen:    uint16(len(a.HardwareAddr)),
		Address: baddr,
	}

	membership := unix.PACKET_ADD_MEMBERSHIP
	if !b {
		membership = unix.PACKET_DROP_MEMBERSHIP
	}

	return p.s.SetSockopt(unix.SOL_PACKET, membership, unsafe.Pointer(&mreq), unix.SizeofPacketMreq)
}

bpillatsch avatar Aug 01 '17 12:08 bpillatsch

Your proposed changes for Linux look fine to me

Do you think this should be implemented by opening an AF_LINK socket simply to add the mcast then closing the socket? Also this is a perm add so we'd have to defer a mcast group deletion on thread close.

Assuming this will provide more or less the same behavior we see on Linux, this also seems reasonable. That said, if it's going to be non-trivial in BSD, I'd be okay with a sentence in the doc comment stating that SetMulticast only works on Linux.

mdlayher avatar Aug 01 '17 14:08 mdlayher

I think i can implement it alright in BSD though making sure it works across BSD platforms would be the trick. At the moment I'm just testing in FreeBSD.

bpillatsch avatar Aug 01 '17 15:08 bpillatsch

Also, in the above Linux implementation I retained your hardware address function argument from your WriteTo() method. However it seems accepting a string and then using net.ParseMAC() might be a more elegant solution, is there a specific reason you chose to implement WriteTo()'s hardware address type acceptance?

bpillatsch avatar Aug 01 '17 15:08 bpillatsch

Yes, because the type must implement https://golang.org/pkg/net/#PacketConn.

IMO it probably makes the most sense to have the parameter be of type net.HardwareAddr.

mdlayher avatar Aug 01 '17 16:08 mdlayher