mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Implement IPv4 multicast forwarding.
This change implements AddMulticastRoute and the requisite routing logic. Subsequent changes will still be needed to: 1. Emit events for missing route or unexpected input interface 2. Implement DelRoute 3. Implement GetRouteStats Updates #7338. PiperOrigin-RevId: 451026594
This commit is contained in:
+33
-27
@@ -25,33 +25,35 @@ import (
|
||||
|
||||
// Mapping for tcpip.Error types.
|
||||
var (
|
||||
ErrUnknownProtocol = New((&tcpip.ErrUnknownProtocol{}).String(), errno.EINVAL)
|
||||
ErrUnknownNICID = New((&tcpip.ErrUnknownNICID{}).String(), errno.ENODEV)
|
||||
ErrUnknownDevice = New((&tcpip.ErrUnknownDevice{}).String(), errno.ENODEV)
|
||||
ErrUnknownProtocolOption = New((&tcpip.ErrUnknownProtocolOption{}).String(), errno.ENOPROTOOPT)
|
||||
ErrDuplicateNICID = New((&tcpip.ErrDuplicateNICID{}).String(), errno.EEXIST)
|
||||
ErrDuplicateAddress = New((&tcpip.ErrDuplicateAddress{}).String(), errno.EEXIST)
|
||||
ErrAlreadyBound = New((&tcpip.ErrAlreadyBound{}).String(), errno.EINVAL)
|
||||
ErrInvalidEndpointState = New((&tcpip.ErrInvalidEndpointState{}).String(), errno.EINVAL)
|
||||
ErrAlreadyConnecting = New((&tcpip.ErrAlreadyConnecting{}).String(), errno.EALREADY)
|
||||
ErrNoPortAvailable = New((&tcpip.ErrNoPortAvailable{}).String(), errno.EAGAIN)
|
||||
ErrPortInUse = New((&tcpip.ErrPortInUse{}).String(), errno.EADDRINUSE)
|
||||
ErrBadLocalAddress = New((&tcpip.ErrBadLocalAddress{}).String(), errno.EADDRNOTAVAIL)
|
||||
ErrClosedForSend = New((&tcpip.ErrClosedForSend{}).String(), errno.EPIPE)
|
||||
ErrClosedForReceive = New((&tcpip.ErrClosedForReceive{}).String(), errno.NOERRNO)
|
||||
ErrTimeout = New((&tcpip.ErrTimeout{}).String(), errno.ETIMEDOUT)
|
||||
ErrAborted = New((&tcpip.ErrAborted{}).String(), errno.EPIPE)
|
||||
ErrConnectStarted = New((&tcpip.ErrConnectStarted{}).String(), errno.EINPROGRESS)
|
||||
ErrDestinationRequired = New((&tcpip.ErrDestinationRequired{}).String(), errno.EDESTADDRREQ)
|
||||
ErrNotSupported = New((&tcpip.ErrNotSupported{}).String(), errno.EOPNOTSUPP)
|
||||
ErrQueueSizeNotSupported = New((&tcpip.ErrQueueSizeNotSupported{}).String(), errno.ENOTTY)
|
||||
ErrNoSuchFile = New((&tcpip.ErrNoSuchFile{}).String(), errno.ENOENT)
|
||||
ErrInvalidOptionValue = New((&tcpip.ErrInvalidOptionValue{}).String(), errno.EINVAL)
|
||||
ErrBroadcastDisabled = New((&tcpip.ErrBroadcastDisabled{}).String(), errno.EACCES)
|
||||
ErrNotPermittedNet = New((&tcpip.ErrNotPermitted{}).String(), errno.EPERM)
|
||||
ErrBadBuffer = New((&tcpip.ErrBadBuffer{}).String(), errno.EFAULT)
|
||||
ErrMalformedHeader = New((&tcpip.ErrMalformedHeader{}).String(), errno.EINVAL)
|
||||
ErrInvalidPortRange = New((&tcpip.ErrInvalidPortRange{}).String(), errno.EINVAL)
|
||||
ErrUnknownProtocol = New((&tcpip.ErrUnknownProtocol{}).String(), errno.EINVAL)
|
||||
ErrUnknownNICID = New((&tcpip.ErrUnknownNICID{}).String(), errno.ENODEV)
|
||||
ErrUnknownDevice = New((&tcpip.ErrUnknownDevice{}).String(), errno.ENODEV)
|
||||
ErrUnknownProtocolOption = New((&tcpip.ErrUnknownProtocolOption{}).String(), errno.ENOPROTOOPT)
|
||||
ErrDuplicateNICID = New((&tcpip.ErrDuplicateNICID{}).String(), errno.EEXIST)
|
||||
ErrDuplicateAddress = New((&tcpip.ErrDuplicateAddress{}).String(), errno.EEXIST)
|
||||
ErrAlreadyBound = New((&tcpip.ErrAlreadyBound{}).String(), errno.EINVAL)
|
||||
ErrInvalidEndpointState = New((&tcpip.ErrInvalidEndpointState{}).String(), errno.EINVAL)
|
||||
ErrAlreadyConnecting = New((&tcpip.ErrAlreadyConnecting{}).String(), errno.EALREADY)
|
||||
ErrNoPortAvailable = New((&tcpip.ErrNoPortAvailable{}).String(), errno.EAGAIN)
|
||||
ErrPortInUse = New((&tcpip.ErrPortInUse{}).String(), errno.EADDRINUSE)
|
||||
ErrBadLocalAddress = New((&tcpip.ErrBadLocalAddress{}).String(), errno.EADDRNOTAVAIL)
|
||||
ErrClosedForSend = New((&tcpip.ErrClosedForSend{}).String(), errno.EPIPE)
|
||||
ErrClosedForReceive = New((&tcpip.ErrClosedForReceive{}).String(), errno.NOERRNO)
|
||||
ErrTimeout = New((&tcpip.ErrTimeout{}).String(), errno.ETIMEDOUT)
|
||||
ErrAborted = New((&tcpip.ErrAborted{}).String(), errno.EPIPE)
|
||||
ErrConnectStarted = New((&tcpip.ErrConnectStarted{}).String(), errno.EINPROGRESS)
|
||||
ErrDestinationRequired = New((&tcpip.ErrDestinationRequired{}).String(), errno.EDESTADDRREQ)
|
||||
ErrNotSupported = New((&tcpip.ErrNotSupported{}).String(), errno.EOPNOTSUPP)
|
||||
ErrQueueSizeNotSupported = New((&tcpip.ErrQueueSizeNotSupported{}).String(), errno.ENOTTY)
|
||||
ErrNoSuchFile = New((&tcpip.ErrNoSuchFile{}).String(), errno.ENOENT)
|
||||
ErrInvalidOptionValue = New((&tcpip.ErrInvalidOptionValue{}).String(), errno.EINVAL)
|
||||
ErrBroadcastDisabled = New((&tcpip.ErrBroadcastDisabled{}).String(), errno.EACCES)
|
||||
ErrNotPermittedNet = New((&tcpip.ErrNotPermitted{}).String(), errno.EPERM)
|
||||
ErrBadBuffer = New((&tcpip.ErrBadBuffer{}).String(), errno.EFAULT)
|
||||
ErrMalformedHeader = New((&tcpip.ErrMalformedHeader{}).String(), errno.EINVAL)
|
||||
ErrInvalidPortRange = New((&tcpip.ErrInvalidPortRange{}).String(), errno.EINVAL)
|
||||
ErrMulticastInputCannotBeOutput = New((&tcpip.ErrMulticastInputCannotBeOutput{}).String(), errno.EINVAL)
|
||||
ErrMissingRequiredFields = New((&tcpip.ErrMissingRequiredFields{}).String(), errno.EINVAL)
|
||||
)
|
||||
|
||||
// TranslateNetstackError converts an error from the tcpip package to a sentry
|
||||
@@ -138,6 +140,10 @@ func TranslateNetstackError(err tcpip.Error) *Error {
|
||||
return ErrMalformedHeader
|
||||
case *tcpip.ErrInvalidPortRange:
|
||||
return ErrInvalidPortRange
|
||||
case *tcpip.ErrMulticastInputCannotBeOutput:
|
||||
return ErrMulticastInputCannotBeOutput
|
||||
case *tcpip.ErrMissingRequiredFields:
|
||||
return ErrMissingRequiredFields
|
||||
default:
|
||||
panic(fmt.Sprintf("unknown error %T", err))
|
||||
}
|
||||
|
||||
@@ -552,4 +552,31 @@ func (*ErrWouldBlock) IgnoreStats() bool {
|
||||
}
|
||||
func (*ErrWouldBlock) String() string { return "operation would block" }
|
||||
|
||||
// ErrMissingRequiredFields indicates that a required field is missing.
|
||||
//
|
||||
// +stateify savable
|
||||
type ErrMissingRequiredFields struct{}
|
||||
|
||||
func (*ErrMissingRequiredFields) isError() {}
|
||||
|
||||
// IgnoreStats implements Error.
|
||||
func (*ErrMissingRequiredFields) IgnoreStats() bool {
|
||||
return true
|
||||
}
|
||||
func (*ErrMissingRequiredFields) String() string { return "mising required fields" }
|
||||
|
||||
// ErrMulticastInputCannotBeOutput indicates that an input interface matches an
|
||||
// output interface in the same multicast route.
|
||||
//
|
||||
// +stateify savable
|
||||
type ErrMulticastInputCannotBeOutput struct{}
|
||||
|
||||
func (*ErrMulticastInputCannotBeOutput) isError() {}
|
||||
|
||||
// IgnoreStats implements Error.
|
||||
func (*ErrMulticastInputCannotBeOutput) IgnoreStats() bool {
|
||||
return true
|
||||
}
|
||||
func (*ErrMulticastInputCannotBeOutput) String() string { return "output cannot contain input" }
|
||||
|
||||
// LINT.ThenChange(../syserr/netstack.go)
|
||||
|
||||
@@ -74,6 +74,33 @@ func (*ErrMessageTooLong) isForwardingError() {}
|
||||
|
||||
func (*ErrMessageTooLong) String() string { return "message too long" }
|
||||
|
||||
// ErrNoMulticastPendingQueueBufferSpace indicates that a multicast packet
|
||||
// could not be added to the pending packet queue due to insufficient buffer
|
||||
// space.
|
||||
//
|
||||
// +stateify savable
|
||||
type ErrNoMulticastPendingQueueBufferSpace struct{}
|
||||
|
||||
func (*ErrNoMulticastPendingQueueBufferSpace) isForwardingError() {}
|
||||
|
||||
func (*ErrNoMulticastPendingQueueBufferSpace) String() string { return "no buffer space" }
|
||||
|
||||
// ErrUnexpectedMulticastInputInterface indicates that the interface that the
|
||||
// packet arrived on did not match the routes expected input interface.
|
||||
type ErrUnexpectedMulticastInputInterface struct{}
|
||||
|
||||
func (*ErrUnexpectedMulticastInputInterface) isForwardingError() {}
|
||||
|
||||
func (*ErrUnexpectedMulticastInputInterface) String() string { return "unexpected input interface" }
|
||||
|
||||
// ErrUnknownOutputEndpoint indicates that the output endpoint associated with
|
||||
// a route could not be found.
|
||||
type ErrUnknownOutputEndpoint struct{}
|
||||
|
||||
func (*ErrUnknownOutputEndpoint) isForwardingError() {}
|
||||
|
||||
func (*ErrUnknownOutputEndpoint) String() string { return "unknown endpoint" }
|
||||
|
||||
// ErrOther indicates the packet coould not be forwarded for a reason
|
||||
// captured by the contained error.
|
||||
type ErrOther struct {
|
||||
|
||||
@@ -51,6 +51,19 @@ type MultiCounterIPForwardingStats struct {
|
||||
// header.
|
||||
ExtensionHeaderProblem tcpip.MultiCounterStat
|
||||
|
||||
// UnexpectedMulticastInputInterface is the number of multicast packets that
|
||||
// were received on an interface that did not match the corresponding route's
|
||||
// expected input interface.
|
||||
UnexpectedMulticastInputInterface tcpip.MultiCounterStat
|
||||
|
||||
// UnknownOutputEndpoint is the number of packets that could not be forwarded
|
||||
// because the output endpoint could not be found.
|
||||
UnknownOutputEndpoint tcpip.MultiCounterStat
|
||||
|
||||
// NoMulticastPendingQueueBufferSpace is the number of multicast packets that
|
||||
// were dropped due to insufficent buffer space in the pending packet queue.
|
||||
NoMulticastPendingQueueBufferSpace tcpip.MultiCounterStat
|
||||
|
||||
// Errors is the number of IP packets received which could not be
|
||||
// successfully forwarded.
|
||||
Errors tcpip.MultiCounterStat
|
||||
@@ -66,6 +79,9 @@ func (m *MultiCounterIPForwardingStats) Init(a, b *tcpip.IPForwardingStats) {
|
||||
m.PacketTooBig.Init(a.PacketTooBig, b.PacketTooBig)
|
||||
m.ExhaustedTTL.Init(a.ExhaustedTTL, b.ExhaustedTTL)
|
||||
m.HostUnreachable.Init(a.HostUnreachable, b.HostUnreachable)
|
||||
m.UnexpectedMulticastInputInterface.Init(a.UnexpectedMulticastInputInterface, b.UnexpectedMulticastInputInterface)
|
||||
m.UnknownOutputEndpoint.Init(a.UnknownOutputEndpoint, b.UnknownOutputEndpoint)
|
||||
m.NoMulticastPendingQueueBufferSpace.Init(a.NoMulticastPendingQueueBufferSpace, b.NoMulticastPendingQueueBufferSpace)
|
||||
}
|
||||
|
||||
// LINT.ThenChange(:MultiCounterIPForwardingStats, ../../../tcpip.go:IPForwardingStats)
|
||||
|
||||
@@ -21,6 +21,7 @@ go_library(
|
||||
"//pkg/tcpip/network/hash",
|
||||
"//pkg/tcpip/network/internal/fragmentation",
|
||||
"//pkg/tcpip/network/internal/ip",
|
||||
"//pkg/tcpip/network/internal/multicast",
|
||||
"//pkg/tcpip/stack",
|
||||
],
|
||||
)
|
||||
@@ -55,6 +56,7 @@ go_test(
|
||||
"//pkg/tcpip/transport/udp",
|
||||
"//pkg/waiter",
|
||||
"@com_github_google_go_cmp//cmp:go_default_library",
|
||||
"@com_github_google_go_cmp//cmp/cmpopts:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
+425
-119
File diff suppressed because it is too large
Load Diff
+789
-287
File diff suppressed because it is too large
Load Diff
@@ -127,6 +127,7 @@ go_test(
|
||||
"//pkg/tcpip/transport/udp",
|
||||
"//pkg/waiter",
|
||||
"@com_github_google_go_cmp//cmp:go_default_library",
|
||||
"@com_github_google_go_cmp//cmp/cmpopts:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
@@ -792,6 +792,18 @@ type MulticastRoute struct {
|
||||
OutgoingInterfaces []MulticastRouteOutgoingInterface
|
||||
}
|
||||
|
||||
// MulticastForwardingNetworkProtocol is the interface that needs to be
|
||||
// implemented by the network protocols that support multicast forwarding.
|
||||
type MulticastForwardingNetworkProtocol interface {
|
||||
NetworkProtocol
|
||||
|
||||
// AddMulticastRoute adds a route to the multicast routing table such that
|
||||
// packets matching the addresses will be forwarded using the provided route.
|
||||
//
|
||||
// Returns an error if the addresses or route is invalid.
|
||||
AddMulticastRoute(UnicastSourceAndMulticastDestination, MulticastRoute) tcpip.Error
|
||||
}
|
||||
|
||||
// NetworkDispatcher contains the methods used by the network stack to deliver
|
||||
// inbound/outbound packets to the appropriate network/packet(if any) endpoints.
|
||||
type NetworkDispatcher interface {
|
||||
|
||||
@@ -564,6 +564,22 @@ func (s *Stack) SetForwardingDefaultAndAllNICs(protocol tcpip.NetworkProtocolNum
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddMulticastRoute adds a multicast route to be used for the specified
|
||||
// addresses and protocol.
|
||||
func (s *Stack) AddMulticastRoute(protocol tcpip.NetworkProtocolNumber, addresses UnicastSourceAndMulticastDestination, route MulticastRoute) tcpip.Error {
|
||||
netProto, ok := s.networkProtocols[protocol]
|
||||
if !ok {
|
||||
return &tcpip.ErrUnknownProtocol{}
|
||||
}
|
||||
|
||||
forwardingNetProto, ok := netProto.(MulticastForwardingNetworkProtocol)
|
||||
if !ok {
|
||||
return &tcpip.ErrNotSupported{}
|
||||
}
|
||||
|
||||
return forwardingNetProto.AddMulticastRoute(addresses, route)
|
||||
}
|
||||
|
||||
// SetNICMulticastForwarding enables or disables multicast packet forwarding on
|
||||
// the specified NIC for the passed protocol.
|
||||
//
|
||||
@@ -1045,6 +1061,22 @@ func (s *Stack) getAddressEP(nic *nic, localAddr, remoteAddr tcpip.Address, netP
|
||||
return nic.findEndpoint(netProto, localAddr, CanBePrimaryEndpoint)
|
||||
}
|
||||
|
||||
// NewRouteForMulticast returns a Route that may be used to forward multicast
|
||||
// packets.
|
||||
//
|
||||
// Returns nil if validation fails.
|
||||
func (s *Stack) NewRouteForMulticast(nicID tcpip.NICID, remoteAddr tcpip.Address, netProto tcpip.NetworkProtocolNumber) *Route {
|
||||
nic, ok := s.nics[nicID]
|
||||
if !ok || !nic.Enabled() {
|
||||
return nil
|
||||
}
|
||||
|
||||
if addressEndpoint := s.getAddressEP(nic, "" /* localAddr */, remoteAddr, netProto); addressEndpoint != nil {
|
||||
return constructAndValidateRoute(netProto, addressEndpoint, nic, nic, "" /* gateway */, "" /* localAddr */, remoteAddr, s.handleLocal, false /* multicastLoop */)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// findLocalRouteFromNICRLocked is like findLocalRouteRLocked but finds a route
|
||||
// from the specified NIC.
|
||||
//
|
||||
|
||||
@@ -27,6 +27,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/google/go-cmp/cmp/cmpopts"
|
||||
"gvisor.dev/gvisor/pkg/rand"
|
||||
"gvisor.dev/gvisor/pkg/sync"
|
||||
"gvisor.dev/gvisor/pkg/tcpip"
|
||||
@@ -225,6 +226,11 @@ type fakeNetworkEndpointStats struct{}
|
||||
// IsNetworkEndpointStats implements stack.NetworkEndpointStats.
|
||||
func (*fakeNetworkEndpointStats) IsNetworkEndpointStats() {}
|
||||
|
||||
type addMulticastRouteData struct {
|
||||
addresses stack.UnicastSourceAndMulticastDestination
|
||||
route stack.MulticastRoute
|
||||
}
|
||||
|
||||
// fakeNetworkProtocol is a network-layer protocol descriptor. It aggregates the
|
||||
// number of packets sent and received via endpoints of this protocol. The index
|
||||
// where packets are added is given by the packet's destination address MOD 10.
|
||||
@@ -234,6 +240,8 @@ type fakeNetworkProtocol struct {
|
||||
packetCount [10]int
|
||||
sendPacketCount [10]int
|
||||
defaultTTL uint8
|
||||
|
||||
addMulticastRouteData addMulticastRouteData
|
||||
}
|
||||
|
||||
func (*fakeNetworkProtocol) Number() tcpip.NetworkProtocolNumber {
|
||||
@@ -298,6 +306,13 @@ func (*fakeNetworkProtocol) Parse(pkt *stack.PacketBuffer) (tcpip.TransportProto
|
||||
return tcpip.TransportProtocolNumber(hdr[protocolNumberOffset]), true, true
|
||||
}
|
||||
|
||||
// AddMulticastRoute implements
|
||||
// MulticastForwardingNetworkProtocol.AddMulticastRoute.
|
||||
func (f *fakeNetworkProtocol) AddMulticastRoute(addresses stack.UnicastSourceAndMulticastDestination, route stack.MulticastRoute) tcpip.Error {
|
||||
f.addMulticastRouteData = addMulticastRouteData{addresses, route}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Forwarding implements stack.ForwardingNetworkEndpoint.
|
||||
func (f *fakeNetworkEndpoint) Forwarding() bool {
|
||||
f.mu.RLock()
|
||||
@@ -4662,6 +4677,69 @@ func TestFindRouteWithForwarding(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestAddMulticastRoute(t *testing.T) {
|
||||
const (
|
||||
incomingNICID = 1
|
||||
outgoingNICID = 2
|
||||
)
|
||||
address := testutil.MustParse4("192.168.1.1")
|
||||
outgoingInterfaces := []stack.MulticastRouteOutgoingInterface{{ID: outgoingNICID, MinTTL: 3}}
|
||||
addresses := stack.UnicastSourceAndMulticastDestination{Source: address, Destination: address}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
netProto tcpip.NetworkProtocolNumber
|
||||
factory stack.NetworkProtocolFactory
|
||||
wantErr tcpip.Error
|
||||
}{
|
||||
{
|
||||
name: "valid",
|
||||
netProto: fakeNetNumber,
|
||||
factory: fakeNetFactory,
|
||||
wantErr: nil,
|
||||
},
|
||||
{
|
||||
name: "unknown protocol",
|
||||
factory: fakeNetFactory,
|
||||
netProto: arp.ProtocolNumber,
|
||||
wantErr: &tcpip.ErrUnknownProtocol{},
|
||||
},
|
||||
{
|
||||
name: "not supported",
|
||||
factory: arp.NewProtocol,
|
||||
netProto: arp.ProtocolNumber,
|
||||
wantErr: &tcpip.ErrNotSupported{},
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
s := stack.New(stack.Options{
|
||||
NetworkProtocols: []stack.NetworkProtocolFactory{test.factory},
|
||||
})
|
||||
|
||||
route := stack.MulticastRoute{
|
||||
ExpectedInputInterface: incomingNICID,
|
||||
OutgoingInterfaces: outgoingInterfaces,
|
||||
}
|
||||
|
||||
err := s.AddMulticastRoute(test.netProto, addresses, route)
|
||||
|
||||
if !cmp.Equal(err, test.wantErr, cmpopts.EquateErrors()) {
|
||||
t.Errorf("s.AddMulticastRoute(%d, %#v, %#v) = %s, want %s", test.netProto, addresses, route, err, test.wantErr)
|
||||
}
|
||||
|
||||
if test.wantErr == nil {
|
||||
fakeNet := s.NetworkProtocolInstance(fakeNetNumber).(*fakeNetworkProtocol)
|
||||
|
||||
expectedAddMulticastRouteData := addMulticastRouteData{addresses, route}
|
||||
if !cmp.Equal(fakeNet.addMulticastRouteData, expectedAddMulticastRouteData, cmp.AllowUnexported(addMulticastRouteData{}, stack.MulticastRoute{})) {
|
||||
t.Errorf("fakeNet.addMulticastRouteData = %#v, want = %#v", fakeNet.addMulticastRouteData, expectedAddMulticastRouteData)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestNICForwarding(t *testing.T) {
|
||||
const nicID = 1
|
||||
|
||||
|
||||
+14
-1
@@ -1698,11 +1698,24 @@ type IPForwardingStats struct {
|
||||
// header.
|
||||
ExtensionHeaderProblem *StatCounter
|
||||
|
||||
// UnexpectedMulticastInputInterface is the number of multicast packets that
|
||||
// were received on an interface that did not match the corresponding route's
|
||||
// expected input interface.
|
||||
UnexpectedMulticastInputInterface *StatCounter
|
||||
|
||||
// UnknownOutputEndpoint is the number of packets that could not be forwarded
|
||||
// because the output endpoint could not be found.
|
||||
UnknownOutputEndpoint *StatCounter
|
||||
|
||||
// NoMulticastPendingQueueBufferSpace is the number of multicast packets that
|
||||
// were dropped due to insufficent buffer space in the pending packet queue.
|
||||
NoMulticastPendingQueueBufferSpace *StatCounter
|
||||
|
||||
// Errors is the number of IP packets received which could not be
|
||||
// successfully forwarded.
|
||||
Errors *StatCounter
|
||||
|
||||
// LINT.ThenChange(network/internal/ip/stats.go:multiCounterIPForwardingStats)
|
||||
// LINT.ThenChange(network/internal/ip/stats.go:MultiCounterIPForwardingStats)
|
||||
}
|
||||
|
||||
// IPStats collects IP-specific stats (both v4 and v6).
|
||||
|
||||
@@ -167,3 +167,24 @@ go_test(
|
||||
"@com_github_google_go_cmp//cmp:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "multicast_forward_test",
|
||||
size = "small",
|
||||
srcs = ["multicast_forward_test.go"],
|
||||
deps = [
|
||||
"//pkg/refs",
|
||||
"//pkg/refsvfs2",
|
||||
"//pkg/tcpip",
|
||||
"//pkg/tcpip/checker",
|
||||
"//pkg/tcpip/header",
|
||||
"//pkg/tcpip/link/channel",
|
||||
"//pkg/tcpip/network/ipv4",
|
||||
"//pkg/tcpip/stack",
|
||||
"//pkg/tcpip/tests/utils",
|
||||
"//pkg/tcpip/testutil",
|
||||
"//pkg/tcpip/transport/udp",
|
||||
"@com_github_google_go_cmp//cmp:go_default_library",
|
||||
"@com_github_google_go_cmp//cmp/cmpopts:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -350,15 +350,14 @@ func TestForwarding(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestMulticastForwarding(t *testing.T) {
|
||||
func TestUnicastForwarding(t *testing.T) {
|
||||
const (
|
||||
nicID1 = 1
|
||||
nicID2 = 2
|
||||
)
|
||||
|
||||
var (
|
||||
ipv4LinkLocalUnicastAddr = testutil.MustParse4("169.254.0.10")
|
||||
ipv4LinkLocalMulticastAddr = testutil.MustParse4("224.0.0.10")
|
||||
ipv4LinkLocalUnicastAddr = testutil.MustParse4("169.254.0.10")
|
||||
|
||||
ipv6LinkLocalUnicastAddr = testutil.MustParse6("fe80::a")
|
||||
ipv6LinkLocalMulticastAddr = testutil.MustParse6("ff02::a")
|
||||
@@ -371,13 +370,6 @@ func TestMulticastForwarding(t *testing.T) {
|
||||
expectForward bool
|
||||
checker func(*testing.T, []byte)
|
||||
}{
|
||||
{
|
||||
name: "IPv4 link-local multicast destination",
|
||||
srcAddr: utils.RemoteIPv4Addr,
|
||||
dstAddr: ipv4LinkLocalMulticastAddr,
|
||||
rx: rxICMPv4EchoRequest,
|
||||
expectForward: false,
|
||||
},
|
||||
{
|
||||
name: "IPv4 link-local source",
|
||||
srcAddr: ipv4LinkLocalUnicastAddr,
|
||||
@@ -402,17 +394,9 @@ func TestMulticastForwarding(t *testing.T) {
|
||||
forwardedICMPv4EchoRequestChecker(t, b, utils.RemoteIPv4Addr, utils.Ipv4Addr2.AddressWithPrefix.Address)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "IPv4 non-link-local multicast",
|
||||
srcAddr: utils.RemoteIPv4Addr,
|
||||
dstAddr: ipv4GlobalMulticastAddr,
|
||||
rx: rxICMPv4EchoRequest,
|
||||
expectForward: true,
|
||||
checker: func(t *testing.T, b []byte) {
|
||||
forwardedICMPv4EchoRequestChecker(t, b, utils.RemoteIPv4Addr, ipv4GlobalMulticastAddr)
|
||||
},
|
||||
},
|
||||
|
||||
// TODO(https://gvisor.dev/issue/7338): Move the IPv6 multicast forwarding
|
||||
// tests to TestMulticastForwarding. Currently, they rely on the unicast
|
||||
// routing table.
|
||||
{
|
||||
name: "IPv6 link-local multicast destination",
|
||||
srcAddr: utils.RemoteIPv6Addr,
|
||||
@@ -420,6 +404,16 @@ func TestMulticastForwarding(t *testing.T) {
|
||||
rx: rxICMPv6EchoRequest,
|
||||
expectForward: false,
|
||||
},
|
||||
{
|
||||
name: "IPv6 non-link-local multicast",
|
||||
srcAddr: utils.RemoteIPv6Addr,
|
||||
dstAddr: ipv6GlobalMulticastAddr,
|
||||
rx: rxICMPv6EchoRequest,
|
||||
expectForward: true,
|
||||
checker: func(t *testing.T, b []byte) {
|
||||
forwardedICMPv6EchoRequestChecker(t, b, utils.RemoteIPv6Addr, ipv6GlobalMulticastAddr)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "IPv6 link-local source",
|
||||
srcAddr: ipv6LinkLocalUnicastAddr,
|
||||
@@ -444,16 +438,6 @@ func TestMulticastForwarding(t *testing.T) {
|
||||
forwardedICMPv6EchoRequestChecker(t, b, utils.RemoteIPv6Addr, utils.Ipv6Addr2.AddressWithPrefix.Address)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "IPv6 non-link-local multicast",
|
||||
srcAddr: utils.RemoteIPv6Addr,
|
||||
dstAddr: ipv6GlobalMulticastAddr,
|
||||
rx: rxICMPv6EchoRequest,
|
||||
expectForward: true,
|
||||
checker: func(t *testing.T, b []byte) {
|
||||
forwardedICMPv6EchoRequestChecker(t, b, utils.RemoteIPv6Addr, ipv6GlobalMulticastAddr)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
@@ -544,16 +528,6 @@ func TestPerInterfaceForwarding(t *testing.T) {
|
||||
forwardedICMPv4EchoRequestChecker(t, b, utils.RemoteIPv4Addr, utils.Ipv4Addr2.AddressWithPrefix.Address)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "IPv4 multicast",
|
||||
srcAddr: utils.RemoteIPv4Addr,
|
||||
dstAddr: ipv4GlobalMulticastAddr,
|
||||
rx: rxICMPv4EchoRequest,
|
||||
checker: func(t *testing.T, b []byte) {
|
||||
forwardedICMPv4EchoRequestChecker(t, b, utils.RemoteIPv4Addr, ipv4GlobalMulticastAddr)
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
name: "IPv6 unicast",
|
||||
srcAddr: utils.RemoteIPv6Addr,
|
||||
@@ -563,6 +537,9 @@ func TestPerInterfaceForwarding(t *testing.T) {
|
||||
forwardedICMPv6EchoRequestChecker(t, b, utils.RemoteIPv6Addr, utils.Ipv6Addr2.AddressWithPrefix.Address)
|
||||
},
|
||||
},
|
||||
// TODO(https://gvisor.dev/issue/7338): Move the IPv6 multicast forwarding
|
||||
// tests to TestMulticastForwarding. Currently, they rely on the unicast
|
||||
// routing table.
|
||||
{
|
||||
name: "IPv6 multicast",
|
||||
srcAddr: utils.RemoteIPv6Addr,
|
||||
@@ -656,7 +633,7 @@ func TestPerInterfaceForwarding(t *testing.T) {
|
||||
{
|
||||
nicID: nicID2,
|
||||
nicEP: e2,
|
||||
otherNICID: nicID2,
|
||||
otherNICID: nicID1,
|
||||
otherNICEP: e1,
|
||||
expectForwarding: false,
|
||||
},
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user