Implement remove multicast route.

Updates #7338.

PiperOrigin-RevId: 451162886
This commit is contained in:
Nate Hurley
2022-05-26 08:06:06 -07:00
committed by gVisor bot
parent 49804a0f96
commit 33c6875603
6 changed files with 276 additions and 1 deletions
+14
View File
@@ -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()
+14
View File
@@ -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()
+7
View File
@@ -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
+16
View File
@@ -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 {
+61 -1
View File
@@ -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,