mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Implement remove multicast route.
Updates #7338. PiperOrigin-RevId: 451162886
This commit is contained in:
@@ -1521,6 +1521,20 @@ func (p *protocol) AddMulticastRoute(addresses stack.UnicastSourceAndMulticastDe
|
||||
return nil
|
||||
}
|
||||
|
||||
// RemoveMulticastRoute implements
|
||||
// stack.MulticastForwardingNetworkProtocol.RemoveMulticastRoute.
|
||||
func (p *protocol) RemoveMulticastRoute(addresses stack.UnicastSourceAndMulticastDestination) tcpip.Error {
|
||||
if err := p.validateUnicastSourceAndMulticastDestination(addresses); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if removed := p.multicastRouteTable.RemoveInstalledRoute(addresses); !removed {
|
||||
return &tcpip.ErrNoRoute{}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *protocol) forwardPendingMulticastPacket(pkt *stack.PacketBuffer, installedRoute *multicast.InstalledRoute) {
|
||||
defer pkt.DecRef()
|
||||
|
||||
|
||||
@@ -2320,6 +2320,20 @@ func (p *protocol) AddMulticastRoute(addresses stack.UnicastSourceAndMulticastDe
|
||||
return nil
|
||||
}
|
||||
|
||||
// RemoveMulticastRoute implements
|
||||
// stack.MulticastForwardingNetworkProtocol.RemoveMulticastRoute.
|
||||
func (p *protocol) RemoveMulticastRoute(addresses stack.UnicastSourceAndMulticastDestination) tcpip.Error {
|
||||
if err := validateUnicastSourceAndMulticastDestination(addresses); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if removed := p.multicastRouteTable.RemoveInstalledRoute(addresses); !removed {
|
||||
return &tcpip.ErrNoRoute{}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *protocol) forwardPendingMulticastPacket(pkt *stack.PacketBuffer, installedRoute *multicast.InstalledRoute) {
|
||||
defer pkt.DecRef()
|
||||
|
||||
|
||||
@@ -802,6 +802,13 @@ type MulticastForwardingNetworkProtocol interface {
|
||||
//
|
||||
// Returns an error if the addresses or route is invalid.
|
||||
AddMulticastRoute(UnicastSourceAndMulticastDestination, MulticastRoute) tcpip.Error
|
||||
|
||||
// RemoveMulticastRoute removes the route matching the provided addresses
|
||||
// from the multicast routing table.
|
||||
//
|
||||
// Returns an error if the addresses are invalid or a matching route is not
|
||||
// found.
|
||||
RemoveMulticastRoute(UnicastSourceAndMulticastDestination) tcpip.Error
|
||||
}
|
||||
|
||||
// NetworkDispatcher contains the methods used by the network stack to deliver
|
||||
|
||||
@@ -564,6 +564,22 @@ func (s *Stack) SetForwardingDefaultAndAllNICs(protocol tcpip.NetworkProtocolNum
|
||||
return nil
|
||||
}
|
||||
|
||||
// RemoveMulticastRoute removes a multicast route that matches the specified
|
||||
// addresses and protocol.
|
||||
func (s *Stack) RemoveMulticastRoute(protocol tcpip.NetworkProtocolNumber, addresses UnicastSourceAndMulticastDestination) tcpip.Error {
|
||||
netProto, ok := s.networkProtocols[protocol]
|
||||
if !ok {
|
||||
return &tcpip.ErrUnknownProtocol{}
|
||||
}
|
||||
|
||||
forwardingNetProto, ok := netProto.(MulticastForwardingNetworkProtocol)
|
||||
if !ok {
|
||||
return &tcpip.ErrNotSupported{}
|
||||
}
|
||||
|
||||
return forwardingNetProto.RemoveMulticastRoute(addresses)
|
||||
}
|
||||
|
||||
// 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 {
|
||||
|
||||
@@ -241,7 +241,8 @@ type fakeNetworkProtocol struct {
|
||||
sendPacketCount [10]int
|
||||
defaultTTL uint8
|
||||
|
||||
addMulticastRouteData addMulticastRouteData
|
||||
addMulticastRouteData addMulticastRouteData
|
||||
removeMulticastRouteData stack.UnicastSourceAndMulticastDestination
|
||||
}
|
||||
|
||||
func (*fakeNetworkProtocol) Number() tcpip.NetworkProtocolNumber {
|
||||
@@ -313,6 +314,13 @@ func (f *fakeNetworkProtocol) AddMulticastRoute(addresses stack.UnicastSourceAnd
|
||||
return nil
|
||||
}
|
||||
|
||||
// RemoveMulticastRoute implements
|
||||
// MulticastForwardingNetworkProtocol.RemoveMulticastRoute.
|
||||
func (f *fakeNetworkProtocol) RemoveMulticastRoute(addresses stack.UnicastSourceAndMulticastDestination) tcpip.Error {
|
||||
f.removeMulticastRouteData = addresses
|
||||
return nil
|
||||
}
|
||||
|
||||
// Forwarding implements stack.ForwardingNetworkEndpoint.
|
||||
func (f *fakeNetworkEndpoint) Forwarding() bool {
|
||||
f.mu.RLock()
|
||||
@@ -4740,6 +4748,58 @@ func TestAddMulticastRoute(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestRemoveMulticastRoute(t *testing.T) {
|
||||
const nicID = 1
|
||||
address := testutil.MustParse4("192.168.1.1")
|
||||
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},
|
||||
})
|
||||
|
||||
err := s.RemoveMulticastRoute(test.netProto, addresses)
|
||||
|
||||
if !cmp.Equal(err, test.wantErr, cmpopts.EquateErrors()) {
|
||||
t.Errorf("s.RemoveMulticastRoute(%d, %#v) = %s, want %s", test.netProto, addresses, err, test.wantErr)
|
||||
}
|
||||
|
||||
if test.wantErr == nil {
|
||||
fakeNet := s.NetworkProtocolInstance(fakeNetNumber).(*fakeNetworkProtocol)
|
||||
if !cmp.Equal(fakeNet.removeMulticastRouteData, addresses) {
|
||||
t.Errorf("fakeNet.removeMulticastRouteData = %#v, want = %#v", fakeNet.removeMulticastRouteData, addresses)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestNICForwarding(t *testing.T) {
|
||||
const nicID = 1
|
||||
|
||||
|
||||
@@ -419,6 +419,170 @@ func TestAddMulticastRoute(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestRemoveMulticastRoute(t *testing.T) {
|
||||
endpointConfigs := map[tcpip.NICID]endpointAddrType{
|
||||
incomingNICID: incomingEndpointAddr,
|
||||
outgoingNICID: outgoingEndpointAddr,
|
||||
otherNICID: otherEndpointAddr,
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
srcAddr, dstAddr addrType
|
||||
wantErr tcpip.Error
|
||||
}{
|
||||
{
|
||||
name: "success",
|
||||
srcAddr: remoteUnicastAddr,
|
||||
dstAddr: multicastAddr,
|
||||
wantErr: nil,
|
||||
},
|
||||
{
|
||||
name: "no matching route",
|
||||
srcAddr: remoteUnicastAddr,
|
||||
dstAddr: otherMulticastAddr,
|
||||
wantErr: &tcpip.ErrNoRoute{},
|
||||
},
|
||||
{
|
||||
name: "multicast source",
|
||||
srcAddr: multicastAddr,
|
||||
dstAddr: multicastAddr,
|
||||
wantErr: &tcpip.ErrBadAddress{},
|
||||
},
|
||||
{
|
||||
name: "any source",
|
||||
srcAddr: anyAddr,
|
||||
dstAddr: multicastAddr,
|
||||
wantErr: &tcpip.ErrBadAddress{},
|
||||
},
|
||||
{
|
||||
name: "link-local unicast source",
|
||||
srcAddr: linkLocalUnicastAddr,
|
||||
dstAddr: multicastAddr,
|
||||
wantErr: &tcpip.ErrBadAddress{},
|
||||
},
|
||||
{
|
||||
name: "empty source",
|
||||
srcAddr: emptyAddr,
|
||||
dstAddr: multicastAddr,
|
||||
wantErr: &tcpip.ErrBadAddress{},
|
||||
},
|
||||
{
|
||||
name: "unicast destination",
|
||||
srcAddr: remoteUnicastAddr,
|
||||
dstAddr: remoteUnicastAddr,
|
||||
wantErr: &tcpip.ErrBadAddress{},
|
||||
},
|
||||
{
|
||||
name: "empty destination",
|
||||
srcAddr: remoteUnicastAddr,
|
||||
dstAddr: emptyAddr,
|
||||
wantErr: &tcpip.ErrBadAddress{},
|
||||
},
|
||||
{
|
||||
name: "link-local multicast destination",
|
||||
srcAddr: remoteUnicastAddr,
|
||||
dstAddr: linkLocalMulticastAddr,
|
||||
wantErr: &tcpip.ErrBadAddress{},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
for _, protocol := range []tcpip.NetworkProtocolNumber{ipv4.ProtocolNumber, ipv6.ProtocolNumber} {
|
||||
t.Run(fmt.Sprintf("%s %d", test.name, protocol), func(t *testing.T) {
|
||||
s := stack.New(stack.Options{
|
||||
NetworkProtocols: []stack.NetworkProtocolFactory{ipv4.NewProtocol, ipv6.NewProtocol},
|
||||
TransportProtocols: []stack.TransportProtocolFactory{udp.NewProtocol},
|
||||
})
|
||||
defer s.Close()
|
||||
|
||||
endpoints := make(map[tcpip.NICID]*channel.Endpoint)
|
||||
for nicID, addrType := range endpointConfigs {
|
||||
ep := channel.New(1, ipv4.MaxTotalSize, "")
|
||||
defer ep.Close()
|
||||
|
||||
if err := s.CreateNIC(nicID, ep); err != nil {
|
||||
t.Fatalf("s.CreateNIC(%d, _): %s", nicID, err)
|
||||
}
|
||||
addr := tcpip.ProtocolAddress{
|
||||
Protocol: protocol,
|
||||
AddressWithPrefix: getEndpointAddr(protocol, addrType),
|
||||
}
|
||||
if err := s.AddProtocolAddress(nicID, addr, stack.AddressProperties{}); err != nil {
|
||||
t.Fatalf("s.AddProtocolAddress(%d, %#v, {}): %s", nicID, addr, err)
|
||||
}
|
||||
s.SetNICMulticastForwarding(nicID, protocol, true /* enabled */)
|
||||
endpoints[nicID] = ep
|
||||
}
|
||||
|
||||
srcAddr := getAddr(protocol, remoteUnicastAddr)
|
||||
dstAddr := getAddr(protocol, multicastAddr)
|
||||
|
||||
outgoingInterfaces := []stack.MulticastRouteOutgoingInterface{
|
||||
{ID: outgoingNICID, MinTTL: routeMinTTL},
|
||||
}
|
||||
|
||||
addresses := stack.UnicastSourceAndMulticastDestination{
|
||||
Source: srcAddr,
|
||||
Destination: dstAddr,
|
||||
}
|
||||
|
||||
route := stack.MulticastRoute{
|
||||
ExpectedInputInterface: incomingNICID,
|
||||
OutgoingInterfaces: outgoingInterfaces,
|
||||
}
|
||||
|
||||
if err := s.AddMulticastRoute(protocol, addresses, route); err != nil {
|
||||
t.Fatalf("got s.AddMulticastRoute(%d, %#v, %#v) = %s, want = nil", protocol, addresses, route, err)
|
||||
}
|
||||
|
||||
addresses = stack.UnicastSourceAndMulticastDestination{
|
||||
Source: getAddr(protocol, test.srcAddr),
|
||||
Destination: getAddr(protocol, test.dstAddr),
|
||||
}
|
||||
err := s.RemoveMulticastRoute(protocol, addresses)
|
||||
|
||||
if !cmp.Equal(err, test.wantErr, cmpopts.EquateErrors()) {
|
||||
t.Errorf("got s.RemoveMulticastRoute(%d, %#v) = %s, want %s", protocol, addresses, err, test.wantErr)
|
||||
}
|
||||
|
||||
incomingEp, ok := endpoints[incomingNICID]
|
||||
if !ok {
|
||||
t.Fatalf("got endpoints[%d] = (_, false), want (_, true)", incomingNICID)
|
||||
}
|
||||
|
||||
injectPacket(incomingEp, protocol, srcAddr, dstAddr, packetTTL)
|
||||
p := incomingEp.Read()
|
||||
|
||||
if p != nil {
|
||||
// An ICMP error should never be sent in response to a multicast
|
||||
// packet.
|
||||
t.Errorf("expected no ICMP packet through incoming NIC, instead found: %#v", p)
|
||||
}
|
||||
|
||||
outgoingEp, ok := endpoints[outgoingNICID]
|
||||
if !ok {
|
||||
t.Fatalf("got endpoints[%d] = (_, false), want (_, true)", outgoingNICID)
|
||||
}
|
||||
|
||||
p = outgoingEp.Read()
|
||||
|
||||
// If the route was successfully removed, then the packet should not be
|
||||
// forwarded.
|
||||
expectForward := test.wantErr != nil
|
||||
if (p != nil) != expectForward {
|
||||
t.Fatalf("got outgoingEp.Read() = %#v, want = (_ == nil) = %t", p, expectForward)
|
||||
}
|
||||
|
||||
if expectForward {
|
||||
checkEchoRequest(t, protocol, p, srcAddr, dstAddr, packetTTL-1)
|
||||
p.DecRef()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMulticastForwarding(t *testing.T) {
|
||||
endpointConfigs := map[tcpip.NICID]endpointAddrType{
|
||||
incomingNICID: incomingEndpointAddr,
|
||||
|
||||
Reference in New Issue
Block a user