Join IPv4 all-systems group on NIC enable

Test:
- stack_test.TestJoinLeaveMulticastOnNICEnableDisable
- integration_test.TestIncomingMulticastAndBroadcast
PiperOrigin-RevId: 325185259
This commit is contained in:
Ghanan Gowripalan
2020-08-06 01:32:21 -07:00
committed by gVisor bot
parent 35312a95c4
commit fc4dd3ef45
6 changed files with 161 additions and 79 deletions
+5
View File
@@ -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"
+1 -7
View File
@@ -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.
+12
View File
@@ -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
View File
@@ -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",
-2
View File
@@ -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",