mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Join IPv4 all-systems group on NIC enable
Test: - stack_test.TestJoinLeaveMulticastOnNICEnableDisable - integration_test.TestIncomingMulticastAndBroadcast PiperOrigin-RevId: 325185259
This commit is contained in:
committed by
gVisor bot
parent
35312a95c4
commit
fc4dd3ef45
@@ -101,6 +101,11 @@ const (
|
||||
// IPv4Version is the version of the ipv4 protocol.
|
||||
IPv4Version = 4
|
||||
|
||||
// IPv4AllSystems is the all systems IPv4 multicast address as per
|
||||
// IANA's IPv4 Multicast Address Space Registry. See
|
||||
// https://www.iana.org/assignments/multicast-addresses/multicast-addresses.xhtml.
|
||||
IPv4AllSystems tcpip.Address = "\xe0\x00\x00\x01"
|
||||
|
||||
// IPv4Broadcast is the broadcast address of the IPv4 procotol.
|
||||
IPv4Broadcast tcpip.Address = "\xff\xff\xff\xff"
|
||||
|
||||
|
||||
@@ -1689,13 +1689,7 @@ func containsV6Addr(list []tcpip.ProtocolAddress, item tcpip.AddressWithPrefix)
|
||||
AddressWithPrefix: item,
|
||||
}
|
||||
|
||||
for _, i := range list {
|
||||
if i == protocolAddress {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
return containsAddr(list, protocolAddress)
|
||||
}
|
||||
|
||||
// TestNoAutoGenAddr tests that SLAAC is not performed when configured not to.
|
||||
|
||||
@@ -217,6 +217,11 @@ func (n *NIC) disableLocked() *tcpip.Error {
|
||||
}
|
||||
|
||||
if _, ok := n.stack.networkProtocols[header.IPv4ProtocolNumber]; ok {
|
||||
// The NIC may have already left the multicast group.
|
||||
if err := n.leaveGroupLocked(header.IPv4AllSystems, false /* force */); err != nil && err != tcpip.ErrBadLocalAddress {
|
||||
return err
|
||||
}
|
||||
|
||||
// The address may have already been removed.
|
||||
if err := n.removePermanentAddressLocked(ipv4BroadcastAddr.AddressWithPrefix.Address); err != nil && err != tcpip.ErrBadLocalAddress {
|
||||
return err
|
||||
@@ -255,6 +260,13 @@ func (n *NIC) enable() *tcpip.Error {
|
||||
if _, err := n.addAddressLocked(ipv4BroadcastAddr, NeverPrimaryEndpoint, permanent, static, false /* deprecated */); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// As per RFC 1122 section 3.3.7, all hosts should join the all-hosts
|
||||
// multicast group. Note, the IANA calls the all-hosts multicast group the
|
||||
// all-systems multicast group.
|
||||
if err := n.joinGroupLocked(header.IPv4ProtocolNumber, header.IPv4AllSystems); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Join the IPv6 All-Nodes Multicast group if the stack is configured to
|
||||
|
||||
+122
-69
@@ -277,6 +277,17 @@ func (l *linkEPWithMockedAttach) isAttached() bool {
|
||||
return l.attached
|
||||
}
|
||||
|
||||
// Checks to see if list contains an address.
|
||||
func containsAddr(list []tcpip.ProtocolAddress, item tcpip.ProtocolAddress) bool {
|
||||
for _, i := range list {
|
||||
if i == item {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func TestNetworkReceive(t *testing.T) {
|
||||
// Create a stack with the fake network protocol, one nic, and two
|
||||
// addresses attached to it: 1 & 2.
|
||||
@@ -3089,6 +3100,13 @@ func TestIPv6SourceAddressSelectionScopeAndSameAddress(t *testing.T) {
|
||||
|
||||
func TestAddRemoveIPv4BroadcastAddressOnNICEnableDisable(t *testing.T) {
|
||||
const nicID = 1
|
||||
broadcastAddr := tcpip.ProtocolAddress{
|
||||
Protocol: header.IPv4ProtocolNumber,
|
||||
AddressWithPrefix: tcpip.AddressWithPrefix{
|
||||
Address: header.IPv4Broadcast,
|
||||
PrefixLen: 32,
|
||||
},
|
||||
}
|
||||
|
||||
e := loopback.New()
|
||||
s := stack.New(stack.Options{
|
||||
@@ -3099,49 +3117,41 @@ func TestAddRemoveIPv4BroadcastAddressOnNICEnableDisable(t *testing.T) {
|
||||
t.Fatalf("CreateNIC(%d, _, %+v) = %s", nicID, nicOpts, err)
|
||||
}
|
||||
|
||||
allStackAddrs := s.AllAddresses()
|
||||
allNICAddrs, ok := allStackAddrs[nicID]
|
||||
if !ok {
|
||||
t.Fatalf("entry for %d missing from allStackAddrs = %+v", nicID, allStackAddrs)
|
||||
}
|
||||
if l := len(allNICAddrs); l != 0 {
|
||||
t.Fatalf("got len(allNICAddrs) = %d, want = 0", l)
|
||||
{
|
||||
allStackAddrs := s.AllAddresses()
|
||||
if allNICAddrs, ok := allStackAddrs[nicID]; !ok {
|
||||
t.Fatalf("entry for %d missing from allStackAddrs = %+v", nicID, allStackAddrs)
|
||||
} else if containsAddr(allNICAddrs, broadcastAddr) {
|
||||
t.Fatalf("got allNICAddrs = %+v, don't want = %+v", allNICAddrs, broadcastAddr)
|
||||
}
|
||||
}
|
||||
|
||||
// Enabling the NIC should add the IPv4 broadcast address.
|
||||
if err := s.EnableNIC(nicID); err != nil {
|
||||
t.Fatalf("s.EnableNIC(%d): %s", nicID, err)
|
||||
}
|
||||
allStackAddrs = s.AllAddresses()
|
||||
allNICAddrs, ok = allStackAddrs[nicID]
|
||||
if !ok {
|
||||
t.Fatalf("entry for %d missing from allStackAddrs = %+v", nicID, allStackAddrs)
|
||||
}
|
||||
if l := len(allNICAddrs); l != 1 {
|
||||
t.Fatalf("got len(allNICAddrs) = %d, want = 1", l)
|
||||
}
|
||||
want := tcpip.ProtocolAddress{
|
||||
Protocol: header.IPv4ProtocolNumber,
|
||||
AddressWithPrefix: tcpip.AddressWithPrefix{
|
||||
Address: header.IPv4Broadcast,
|
||||
PrefixLen: 32,
|
||||
},
|
||||
}
|
||||
if allNICAddrs[0] != want {
|
||||
t.Fatalf("got allNICAddrs[0] = %+v, want = %+v", allNICAddrs[0], want)
|
||||
|
||||
{
|
||||
allStackAddrs := s.AllAddresses()
|
||||
if allNICAddrs, ok := allStackAddrs[nicID]; !ok {
|
||||
t.Fatalf("entry for %d missing from allStackAddrs = %+v", nicID, allStackAddrs)
|
||||
} else if !containsAddr(allNICAddrs, broadcastAddr) {
|
||||
t.Fatalf("got allNICAddrs = %+v, want = %+v", allNICAddrs, broadcastAddr)
|
||||
}
|
||||
}
|
||||
|
||||
// Disabling the NIC should remove the IPv4 broadcast address.
|
||||
if err := s.DisableNIC(nicID); err != nil {
|
||||
t.Fatalf("s.DisableNIC(%d): %s", nicID, err)
|
||||
}
|
||||
allStackAddrs = s.AllAddresses()
|
||||
allNICAddrs, ok = allStackAddrs[nicID]
|
||||
if !ok {
|
||||
t.Fatalf("entry for %d missing from allStackAddrs = %+v", nicID, allStackAddrs)
|
||||
}
|
||||
if l := len(allNICAddrs); l != 0 {
|
||||
t.Fatalf("got len(allNICAddrs) = %d, want = 0", l)
|
||||
|
||||
{
|
||||
allStackAddrs := s.AllAddresses()
|
||||
if allNICAddrs, ok := allStackAddrs[nicID]; !ok {
|
||||
t.Fatalf("entry for %d missing from allStackAddrs = %+v", nicID, allStackAddrs)
|
||||
} else if containsAddr(allNICAddrs, broadcastAddr) {
|
||||
t.Fatalf("got allNICAddrs = %+v, don't want = %+v", allNICAddrs, broadcastAddr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3189,50 +3199,93 @@ func TestLeaveIPv6SolicitedNodeAddrBeforeAddrRemoval(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestJoinLeaveAllNodesMulticastOnNICEnableDisable(t *testing.T) {
|
||||
func TestJoinLeaveMulticastOnNICEnableDisable(t *testing.T) {
|
||||
const nicID = 1
|
||||
|
||||
e := loopback.New()
|
||||
s := stack.New(stack.Options{
|
||||
NetworkProtocols: []stack.NetworkProtocol{ipv6.NewProtocol()},
|
||||
})
|
||||
nicOpts := stack.NICOptions{Disabled: true}
|
||||
if err := s.CreateNICWithOptions(nicID, e, nicOpts); err != nil {
|
||||
t.Fatalf("CreateNIC(%d, _, %+v) = %s", nicID, nicOpts, err)
|
||||
tests := []struct {
|
||||
name string
|
||||
proto tcpip.NetworkProtocolNumber
|
||||
addr tcpip.Address
|
||||
}{
|
||||
{
|
||||
name: "IPv6 All-Nodes",
|
||||
proto: header.IPv6ProtocolNumber,
|
||||
addr: header.IPv6AllNodesMulticastAddress,
|
||||
},
|
||||
{
|
||||
name: "IPv4 All-Systems",
|
||||
proto: header.IPv4ProtocolNumber,
|
||||
addr: header.IPv4AllSystems,
|
||||
},
|
||||
}
|
||||
|
||||
// Should not be in the IPv6 all-nodes multicast group yet because the NIC has
|
||||
// not been enabled yet.
|
||||
isInGroup, err := s.IsInGroup(nicID, header.IPv6AllNodesMulticastAddress)
|
||||
if err != nil {
|
||||
t.Fatalf("IsInGroup(%d, %s): %s", nicID, header.IPv6AllNodesMulticastAddress, err)
|
||||
}
|
||||
if isInGroup {
|
||||
t.Fatalf("got IsInGroup(%d, %s) = true, want = false", nicID, header.IPv6AllNodesMulticastAddress)
|
||||
}
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
e := loopback.New()
|
||||
s := stack.New(stack.Options{
|
||||
NetworkProtocols: []stack.NetworkProtocol{ipv4.NewProtocol(), ipv6.NewProtocol()},
|
||||
})
|
||||
nicOpts := stack.NICOptions{Disabled: true}
|
||||
if err := s.CreateNICWithOptions(nicID, e, nicOpts); err != nil {
|
||||
t.Fatalf("CreateNIC(%d, _, %+v) = %s", nicID, nicOpts, err)
|
||||
}
|
||||
|
||||
// The all-nodes multicast group should be joined when the NIC is enabled.
|
||||
if err := s.EnableNIC(nicID); err != nil {
|
||||
t.Fatalf("s.EnableNIC(%d): %s", nicID, err)
|
||||
}
|
||||
isInGroup, err = s.IsInGroup(nicID, header.IPv6AllNodesMulticastAddress)
|
||||
if err != nil {
|
||||
t.Fatalf("IsInGroup(%d, %s): %s", nicID, header.IPv6AllNodesMulticastAddress, err)
|
||||
}
|
||||
if !isInGroup {
|
||||
t.Fatalf("got IsInGroup(%d, %s) = false, want = true", nicID, header.IPv6AllNodesMulticastAddress)
|
||||
}
|
||||
// Should not be in the multicast group yet because the NIC has not been
|
||||
// enabled yet.
|
||||
if isInGroup, err := s.IsInGroup(nicID, test.addr); err != nil {
|
||||
t.Fatalf("IsInGroup(%d, %s): %s", nicID, test.addr, err)
|
||||
} else if isInGroup {
|
||||
t.Fatalf("got IsInGroup(%d, %s) = true, want = false", nicID, test.addr)
|
||||
}
|
||||
|
||||
// The all-nodes multicast group should be left when the NIC is disabled.
|
||||
if err := s.DisableNIC(nicID); err != nil {
|
||||
t.Fatalf("s.DisableNIC(%d): %s", nicID, err)
|
||||
}
|
||||
isInGroup, err = s.IsInGroup(nicID, header.IPv6AllNodesMulticastAddress)
|
||||
if err != nil {
|
||||
t.Fatalf("IsInGroup(%d, %s): %s", nicID, header.IPv6AllNodesMulticastAddress, err)
|
||||
}
|
||||
if isInGroup {
|
||||
t.Fatalf("got IsInGroup(%d, %s) = true, want = false", nicID, header.IPv6AllNodesMulticastAddress)
|
||||
// The all-nodes multicast group should be joined when the NIC is enabled.
|
||||
if err := s.EnableNIC(nicID); err != nil {
|
||||
t.Fatalf("s.EnableNIC(%d): %s", nicID, err)
|
||||
}
|
||||
|
||||
if isInGroup, err := s.IsInGroup(nicID, test.addr); err != nil {
|
||||
t.Fatalf("IsInGroup(%d, %s): %s", nicID, test.addr, err)
|
||||
} else if !isInGroup {
|
||||
t.Fatalf("got IsInGroup(%d, %s) = false, want = true", nicID, test.addr)
|
||||
}
|
||||
|
||||
// The multicast group should be left when the NIC is disabled.
|
||||
if err := s.DisableNIC(nicID); err != nil {
|
||||
t.Fatalf("s.DisableNIC(%d): %s", nicID, err)
|
||||
}
|
||||
|
||||
if isInGroup, err := s.IsInGroup(nicID, test.addr); err != nil {
|
||||
t.Fatalf("IsInGroup(%d, %s): %s", nicID, test.addr, err)
|
||||
} else if isInGroup {
|
||||
t.Fatalf("got IsInGroup(%d, %s) = true, want = false", nicID, test.addr)
|
||||
}
|
||||
|
||||
// The all-nodes multicast group should be joined when the NIC is enabled.
|
||||
if err := s.EnableNIC(nicID); err != nil {
|
||||
t.Fatalf("s.EnableNIC(%d): %s", nicID, err)
|
||||
}
|
||||
|
||||
if isInGroup, err := s.IsInGroup(nicID, test.addr); err != nil {
|
||||
t.Fatalf("IsInGroup(%d, %s): %s", nicID, test.addr, err)
|
||||
} else if !isInGroup {
|
||||
t.Fatalf("got IsInGroup(%d, %s) = false, want = true", nicID, test.addr)
|
||||
}
|
||||
|
||||
// Leaving the group before disabling the NIC should not cause an error.
|
||||
if err := s.LeaveGroup(test.proto, nicID, test.addr); err != nil {
|
||||
t.Fatalf("s.LeaveGroup(%d, %d, %s): %s", test.proto, nicID, test.addr, err)
|
||||
}
|
||||
|
||||
if err := s.DisableNIC(nicID); err != nil {
|
||||
t.Fatalf("s.DisableNIC(%d): %s", nicID, err)
|
||||
}
|
||||
|
||||
if isInGroup, err := s.IsInGroup(nicID, test.addr); err != nil {
|
||||
t.Fatalf("IsInGroup(%d, %s): %s", nicID, test.addr, err)
|
||||
} else if isInGroup {
|
||||
t.Fatalf("got IsInGroup(%d, %s) = true, want = false", nicID, test.addr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -31,7 +31,9 @@ import (
|
||||
|
||||
const defaultMTU = 1280
|
||||
|
||||
func TestIncomingSubnetBroadcast(t *testing.T) {
|
||||
// TestIncomingMulticastAndBroadcast tests receiving a packet destined to some
|
||||
// multicast or broadcast address.
|
||||
func TestIncomingMulticastAndBroadcast(t *testing.T) {
|
||||
const (
|
||||
nicID = 1
|
||||
remotePort = 5555
|
||||
@@ -179,6 +181,24 @@ func TestIncomingSubnetBroadcast(t *testing.T) {
|
||||
expectRx: true,
|
||||
},
|
||||
|
||||
{
|
||||
name: "IPv4 all-systems multicast binding to all-systems multicast",
|
||||
bindAddr: header.IPv4AllSystems,
|
||||
dstAddr: header.IPv4AllSystems,
|
||||
expectRx: true,
|
||||
},
|
||||
{
|
||||
name: "IPv4 all-systems multicast binding to wildcard",
|
||||
dstAddr: header.IPv4AllSystems,
|
||||
expectRx: true,
|
||||
},
|
||||
{
|
||||
name: "IPv4 all-systems multicast binding to unicast",
|
||||
bindAddr: ipv4Addr.Address,
|
||||
dstAddr: header.IPv4AllSystems,
|
||||
expectRx: false,
|
||||
},
|
||||
|
||||
// IPv6 has no notion of a broadcast.
|
||||
{
|
||||
name: "IPv6 unicast binding to wildcard",
|
||||
|
||||
@@ -40,8 +40,6 @@ packetimpact_go_test(
|
||||
packetimpact_go_test(
|
||||
name = "udp_recv_mcast_bcast",
|
||||
srcs = ["udp_recv_mcast_bcast_test.go"],
|
||||
# TODO(b/152813495): Fix netstack then remove the line below.
|
||||
expect_netstack_failure = True,
|
||||
deps = [
|
||||
"//pkg/tcpip",
|
||||
"//pkg/tcpip/header",
|
||||
|
||||
Reference in New Issue
Block a user