Support add/remove IPv6 multicast group sock opt

IPv4 was always supported but UDP never supported joining/leaving IPv6
multicast groups via socket options.

Add: IPPROTO_IPV6, IPV6_JOIN_GROUP/IPV6_ADD_MEMBERSHIP
Remove: IPPROTO_IPV6, IPV6_LEAVE_GROUP/IPV6_DROP_MEMBERSHIP

Test: integration_test.TestUDPAddRemoveMembershipSocketOption
PiperOrigin-RevId: 350396072
This commit is contained in:
Ghanan Gowripalan
2021-01-06 11:41:42 -08:00
committed by gVisor bot
parent 0c4118d5b8
commit abe9d9f67f
15 changed files with 708 additions and 232 deletions
+34 -3
View File
@@ -2091,9 +2091,29 @@ func setSockOptIPv6(t *kernel.Task, s socket.SocketOps, ep commonEndpoint, name
ep.SocketOptions().SetV6Only(v != 0)
return nil
case linux.IPV6_ADD_MEMBERSHIP,
linux.IPV6_DROP_MEMBERSHIP,
linux.IPV6_IPSEC_POLICY,
case linux.IPV6_ADD_MEMBERSHIP:
req, err := copyInMulticastV6Request(optVal)
if err != nil {
return err
}
return syserr.TranslateNetstackError(ep.SetSockOpt(&tcpip.AddMembershipOption{
NIC: tcpip.NICID(req.InterfaceIndex),
MulticastAddr: tcpip.Address(req.MulticastAddr[:]),
}))
case linux.IPV6_DROP_MEMBERSHIP:
req, err := copyInMulticastV6Request(optVal)
if err != nil {
return err
}
return syserr.TranslateNetstackError(ep.SetSockOpt(&tcpip.RemoveMembershipOption{
NIC: tcpip.NICID(req.InterfaceIndex),
MulticastAddr: tcpip.Address(req.MulticastAddr[:]),
}))
case linux.IPV6_IPSEC_POLICY,
linux.IPV6_JOIN_ANYCAST,
linux.IPV6_LEAVE_ANYCAST,
// TODO(b/148887420): Add support for IPV6_PKTINFO.
@@ -2181,6 +2201,7 @@ func setSockOptIPv6(t *kernel.Task, s socket.SocketOps, ep commonEndpoint, name
var (
inetMulticastRequestSize = int(binary.Size(linux.InetMulticastRequest{}))
inetMulticastRequestWithNICSize = int(binary.Size(linux.InetMulticastRequestWithNIC{}))
inet6MulticastRequestSize = int(binary.Size(linux.Inet6MulticastRequest{}))
)
// copyInMulticastRequest copies in a variable-size multicast request. The
@@ -2214,6 +2235,16 @@ func copyInMulticastRequest(optVal []byte, allowAddr bool) (linux.InetMulticastR
return req, nil
}
func copyInMulticastV6Request(optVal []byte) (linux.Inet6MulticastRequest, *syserr.Error) {
if len(optVal) < inet6MulticastRequestSize {
return linux.Inet6MulticastRequest{}, syserr.ErrInvalidArgument
}
var req linux.Inet6MulticastRequest
binary.Unmarshal(optVal[:inet6MulticastRequestSize], usermem.ByteOrder, &req)
return req, nil
}
// parseIntOrChar copies either a 32-bit int or an 8-bit uint out of buf.
//
// net/ipv4/ip_sockglue.c:do_ip_setsockopt does this for its socket options.