mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Implement Subnet removal
This was used to implement https://fuchsia-review.googlesource.com/c/garnet/+/177771. PiperOrigin-RevId: 211725098 Change-Id: Ib0acc7c13430b7341e8e0ec6eb5fc35f5cee5083
This commit is contained in:
committed by
Shentubot
parent
b3b66dbd1f
commit
fe8ca76c22
@@ -82,6 +82,52 @@ func (n *NIC) setSpoofing(enable bool) {
|
||||
n.mu.Unlock()
|
||||
}
|
||||
|
||||
func (n *NIC) getMainNICAddress(protocol tcpip.NetworkProtocolNumber) (tcpip.Address, tcpip.Subnet, *tcpip.Error) {
|
||||
n.mu.RLock()
|
||||
defer n.mu.RUnlock()
|
||||
|
||||
var r *referencedNetworkEndpoint
|
||||
|
||||
// Check for a primary endpoint.
|
||||
if list, ok := n.primary[protocol]; ok {
|
||||
for e := list.Front(); e != nil; e = e.Next() {
|
||||
ref := e.(*referencedNetworkEndpoint)
|
||||
if ref.holdsInsertRef && ref.tryIncRef() {
|
||||
r = ref
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// If no primary endpoints then check for other endpoints.
|
||||
if r == nil {
|
||||
for _, ref := range n.endpoints {
|
||||
if ref.holdsInsertRef && ref.tryIncRef() {
|
||||
r = ref
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if r == nil {
|
||||
return "", tcpip.Subnet{}, tcpip.ErrNoLinkAddress
|
||||
}
|
||||
|
||||
address := r.ep.ID().LocalAddress
|
||||
r.decRef()
|
||||
|
||||
// Find the least-constrained matching subnet for the address, if one
|
||||
// exists, and return it.
|
||||
var subnet tcpip.Subnet
|
||||
for _, s := range n.subnets {
|
||||
if s.Contains(address) && !subnet.Contains(s.ID()) {
|
||||
subnet = s
|
||||
}
|
||||
}
|
||||
return address, subnet, nil
|
||||
}
|
||||
|
||||
// primaryEndpoint returns the primary endpoint of n for the given network
|
||||
// protocol.
|
||||
func (n *NIC) primaryEndpoint(protocol tcpip.NetworkProtocolNumber) *referencedNetworkEndpoint {
|
||||
@@ -216,6 +262,29 @@ func (n *NIC) AddSubnet(protocol tcpip.NetworkProtocolNumber, subnet tcpip.Subne
|
||||
n.mu.Unlock()
|
||||
}
|
||||
|
||||
// RemoveSubnet removes the given subnet from n.
|
||||
func (n *NIC) RemoveSubnet(subnet tcpip.Subnet) {
|
||||
n.mu.Lock()
|
||||
|
||||
for i, sub := range n.subnets {
|
||||
if sub == subnet {
|
||||
n.subnets = append(n.subnets[:i], n.subnets[i+1:]...)
|
||||
}
|
||||
}
|
||||
|
||||
n.mu.Unlock()
|
||||
}
|
||||
|
||||
// ContainsSubnet reports whether this NIC contains the given subnet.
|
||||
func (n *NIC) ContainsSubnet(subnet tcpip.Subnet) bool {
|
||||
for _, s := range n.Subnets() {
|
||||
if s == subnet {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Subnets returns the Subnets associated with this NIC.
|
||||
func (n *NIC) Subnets() []tcpip.Subnet {
|
||||
n.mu.RLock()
|
||||
|
||||
@@ -623,13 +623,38 @@ func (s *Stack) AddSubnet(id tcpip.NICID, protocol tcpip.NetworkProtocolNumber,
|
||||
s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
|
||||
nic := s.nics[id]
|
||||
if nic == nil {
|
||||
return tcpip.ErrUnknownNICID
|
||||
if nic, ok := s.nics[id]; ok {
|
||||
nic.AddSubnet(protocol, subnet)
|
||||
return nil
|
||||
}
|
||||
|
||||
nic.AddSubnet(protocol, subnet)
|
||||
return nil
|
||||
return tcpip.ErrUnknownNICID
|
||||
}
|
||||
|
||||
// RemoveSubnet removes the subnet range from the specified NIC.
|
||||
func (s *Stack) RemoveSubnet(id tcpip.NICID, subnet tcpip.Subnet) *tcpip.Error {
|
||||
s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
|
||||
if nic, ok := s.nics[id]; ok {
|
||||
nic.RemoveSubnet(subnet)
|
||||
return nil
|
||||
}
|
||||
|
||||
return tcpip.ErrUnknownNICID
|
||||
}
|
||||
|
||||
// ContainsSubnet reports whether the specified NIC contains the specified
|
||||
// subnet.
|
||||
func (s *Stack) ContainsSubnet(id tcpip.NICID, subnet tcpip.Subnet) (bool, *tcpip.Error) {
|
||||
s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
|
||||
if nic, ok := s.nics[id]; ok {
|
||||
return nic.ContainsSubnet(subnet), nil
|
||||
}
|
||||
|
||||
return false, tcpip.ErrUnknownNICID
|
||||
}
|
||||
|
||||
// RemoveAddress removes an existing network-layer address from the specified
|
||||
@@ -638,12 +663,26 @@ func (s *Stack) RemoveAddress(id tcpip.NICID, addr tcpip.Address) *tcpip.Error {
|
||||
s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
|
||||
nic := s.nics[id]
|
||||
if nic == nil {
|
||||
return tcpip.ErrUnknownNICID
|
||||
if nic, ok := s.nics[id]; ok {
|
||||
return nic.RemoveAddress(addr)
|
||||
}
|
||||
|
||||
return nic.RemoveAddress(addr)
|
||||
return tcpip.ErrUnknownNICID
|
||||
}
|
||||
|
||||
// GetMainNICAddress returns the first primary address (and the subnet that
|
||||
// contains it) for the given NIC and protocol. Returns an arbitrary endpoint's
|
||||
// address if no primary addresses exist. Returns an error if the NIC doesn't
|
||||
// exist or has no endpoints.
|
||||
func (s *Stack) GetMainNICAddress(id tcpip.NICID, protocol tcpip.NetworkProtocolNumber) (tcpip.Address, tcpip.Subnet, *tcpip.Error) {
|
||||
s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
|
||||
if nic, ok := s.nics[id]; ok {
|
||||
return nic.getMainNICAddress(protocol)
|
||||
}
|
||||
|
||||
return "", tcpip.Subnet{}, tcpip.ErrUnknownNICID
|
||||
}
|
||||
|
||||
// FindRoute creates a route to the given destination address, leaving through
|
||||
|
||||
@@ -19,6 +19,7 @@ package stack_test
|
||||
|
||||
import (
|
||||
"math"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"gvisor.googlesource.com/gvisor/pkg/tcpip"
|
||||
@@ -763,6 +764,102 @@ func TestNetworkOptions(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestSubnetAddRemove(t *testing.T) {
|
||||
s := stack.New([]string{"fakeNet"}, nil, stack.Options{})
|
||||
id, _ := channel.New(10, defaultMTU, "")
|
||||
if err := s.CreateNIC(1, id); err != nil {
|
||||
t.Fatalf("CreateNIC failed: %v", err)
|
||||
}
|
||||
|
||||
addr := tcpip.Address("\x01\x01\x01\x01")
|
||||
mask := tcpip.AddressMask(strings.Repeat("\xff", len(addr)))
|
||||
subnet, err := tcpip.NewSubnet(addr, mask)
|
||||
if err != nil {
|
||||
t.Fatalf("NewSubnet failed: %v", err)
|
||||
}
|
||||
|
||||
if contained, err := s.ContainsSubnet(1, subnet); err != nil {
|
||||
t.Fatalf("ContainsSubnet failed: %v", err)
|
||||
} else if contained {
|
||||
t.Fatal("got s.ContainsSubnet(...) = true, want = false")
|
||||
}
|
||||
|
||||
if err := s.AddSubnet(1, fakeNetNumber, subnet); err != nil {
|
||||
t.Fatalf("AddSubnet failed: %v", err)
|
||||
}
|
||||
|
||||
if contained, err := s.ContainsSubnet(1, subnet); err != nil {
|
||||
t.Fatalf("ContainsSubnet failed: %v", err)
|
||||
} else if !contained {
|
||||
t.Fatal("got s.ContainsSubnet(...) = false, want = true")
|
||||
}
|
||||
|
||||
if err := s.RemoveSubnet(1, subnet); err != nil {
|
||||
t.Fatalf("RemoveSubnet failed: %v", err)
|
||||
}
|
||||
|
||||
if contained, err := s.ContainsSubnet(1, subnet); err != nil {
|
||||
t.Fatalf("ContainsSubnet failed: %v", err)
|
||||
} else if contained {
|
||||
t.Fatal("got s.ContainsSubnet(...) = true, want = false")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetMainNICAddress(t *testing.T) {
|
||||
s := stack.New([]string{"fakeNet"}, nil, stack.Options{})
|
||||
id, _ := channel.New(10, defaultMTU, "")
|
||||
if err := s.CreateNIC(1, id); err != nil {
|
||||
t.Fatalf("CreateNIC failed: %v", err)
|
||||
}
|
||||
|
||||
for _, tc := range []struct {
|
||||
name string
|
||||
address tcpip.Address
|
||||
}{
|
||||
{"IPv4", "\x01\x01\x01\x01"},
|
||||
{"IPv6", "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01"},
|
||||
} {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
address := tc.address
|
||||
mask := tcpip.AddressMask(strings.Repeat("\xff", len(address)))
|
||||
subnet, err := tcpip.NewSubnet(address, mask)
|
||||
if err != nil {
|
||||
t.Fatalf("NewSubnet failed: %v", err)
|
||||
}
|
||||
|
||||
if err := s.AddAddress(1, fakeNetNumber, address); err != nil {
|
||||
t.Fatalf("AddAddress failed: %v", err)
|
||||
}
|
||||
|
||||
if err := s.AddSubnet(1, fakeNetNumber, subnet); err != nil {
|
||||
t.Fatalf("AddSubnet failed: %v", err)
|
||||
}
|
||||
|
||||
// Check that we get the right initial address and subnet.
|
||||
if gotAddress, gotSubnet, err := s.GetMainNICAddress(1, fakeNetNumber); err != nil {
|
||||
t.Fatalf("GetMainNICAddress failed: %v", err)
|
||||
} else if gotAddress != address {
|
||||
t.Fatalf("got GetMainNICAddress = (%v, ...), want = (%v, ...)", gotAddress, address)
|
||||
} else if gotSubnet != subnet {
|
||||
t.Fatalf("got GetMainNICAddress = (..., %v), want = (..., %v)", gotSubnet, subnet)
|
||||
}
|
||||
|
||||
if err := s.RemoveSubnet(1, subnet); err != nil {
|
||||
t.Fatalf("RemoveSubnet failed: %v", err)
|
||||
}
|
||||
|
||||
if err := s.RemoveAddress(1, address); err != nil {
|
||||
t.Fatalf("RemoveAddress failed: %v", err)
|
||||
}
|
||||
|
||||
// Check that we get an error after removal.
|
||||
if _, _, err := s.GetMainNICAddress(1, fakeNetNumber); err != tcpip.ErrNoLinkAddress {
|
||||
t.Fatalf("got s.GetMainNICAddress(...) = %v, want = %v", err, tcpip.ErrNoLinkAddress)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
stack.RegisterNetworkProtocolFactory("fakeNet", func() stack.NetworkProtocol {
|
||||
return &fakeNetworkProtocol{}
|
||||
|
||||
Reference in New Issue
Block a user