mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Add ability to send unicast ARP requests and Neighbor Solicitations
The previous implementation of LinkAddressRequest only supported sending broadcast ARP requests and multicast Neighbor Solicitations. The ability to send these packets as unicast is required for Neighbor Unreachability Detection. Tests: pkg/tcpip/network/arp:arp_test - TestLinkAddressRequest pkg/tcpip/network/ipv6:ipv6_test - TestLinkAddressRequest Updates #1889 Updates #1894 Updates #1895 Updates #1947 Updates #1948 Updates #1949 Updates #1950 PiperOrigin-RevId: 323451569
This commit is contained in:
@@ -160,9 +160,12 @@ func (*protocol) LinkAddressProtocol() tcpip.NetworkProtocolNumber {
|
||||
}
|
||||
|
||||
// LinkAddressRequest implements stack.LinkAddressResolver.LinkAddressRequest.
|
||||
func (*protocol) LinkAddressRequest(addr, localAddr tcpip.Address, linkEP stack.LinkEndpoint) *tcpip.Error {
|
||||
func (*protocol) LinkAddressRequest(addr, localAddr tcpip.Address, remoteLinkAddr tcpip.LinkAddress, linkEP stack.LinkEndpoint) *tcpip.Error {
|
||||
r := &stack.Route{
|
||||
RemoteLinkAddress: header.EthernetBroadcastAddress,
|
||||
RemoteLinkAddress: remoteLinkAddr,
|
||||
}
|
||||
if len(r.RemoteLinkAddress) == 0 {
|
||||
r.RemoteLinkAddress = header.EthernetBroadcastAddress
|
||||
}
|
||||
|
||||
hdr := buffer.NewPrependable(int(linkEP.MaxHeaderLength()) + header.ARPSize)
|
||||
|
||||
@@ -32,10 +32,14 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
stackLinkAddr = tcpip.LinkAddress("\x0a\x0a\x0b\x0b\x0c\x0c")
|
||||
stackAddr1 = tcpip.Address("\x0a\x00\x00\x01")
|
||||
stackAddr2 = tcpip.Address("\x0a\x00\x00\x02")
|
||||
stackAddrBad = tcpip.Address("\x0a\x00\x00\x03")
|
||||
stackLinkAddr1 = tcpip.LinkAddress("\x0a\x0a\x0b\x0b\x0c\x0c")
|
||||
stackLinkAddr2 = tcpip.LinkAddress("\x0b\x0b\x0c\x0c\x0d\x0d")
|
||||
stackAddr1 = tcpip.Address("\x0a\x00\x00\x01")
|
||||
stackAddr2 = tcpip.Address("\x0a\x00\x00\x02")
|
||||
stackAddrBad = tcpip.Address("\x0a\x00\x00\x03")
|
||||
|
||||
defaultChannelSize = 1
|
||||
defaultMTU = 65536
|
||||
)
|
||||
|
||||
type testContext struct {
|
||||
@@ -50,8 +54,7 @@ func newTestContext(t *testing.T) *testContext {
|
||||
TransportProtocols: []stack.TransportProtocol{icmp.NewProtocol4()},
|
||||
})
|
||||
|
||||
const defaultMTU = 65536
|
||||
ep := channel.New(256, defaultMTU, stackLinkAddr)
|
||||
ep := channel.New(defaultChannelSize, defaultMTU, stackLinkAddr1)
|
||||
wep := stack.LinkEndpoint(ep)
|
||||
|
||||
if testing.Verbose() {
|
||||
@@ -119,7 +122,7 @@ func TestDirectRequest(t *testing.T) {
|
||||
if !rep.IsValid() {
|
||||
t.Fatalf("invalid ARP response pi.Pkt.Header.UsedLength()=%d", pi.Pkt.Header.UsedLength())
|
||||
}
|
||||
if got, want := tcpip.LinkAddress(rep.HardwareAddressSender()), stackLinkAddr; got != want {
|
||||
if got, want := tcpip.LinkAddress(rep.HardwareAddressSender()), stackLinkAddr1; got != want {
|
||||
t.Errorf("got HardwareAddressSender = %s, want = %s", got, want)
|
||||
}
|
||||
if got, want := tcpip.Address(rep.ProtocolAddressSender()), tcpip.Address(h.ProtocolAddressTarget()); got != want {
|
||||
@@ -144,3 +147,44 @@ func TestDirectRequest(t *testing.T) {
|
||||
t.Errorf("stackAddrBad: unexpected packet sent, Proto=%v", pkt.Proto)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLinkAddressRequest(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
remoteLinkAddr tcpip.LinkAddress
|
||||
expectLinkAddr tcpip.LinkAddress
|
||||
}{
|
||||
{
|
||||
name: "Unicast",
|
||||
remoteLinkAddr: stackLinkAddr2,
|
||||
expectLinkAddr: stackLinkAddr2,
|
||||
},
|
||||
{
|
||||
name: "Multicast",
|
||||
remoteLinkAddr: "",
|
||||
expectLinkAddr: header.EthernetBroadcastAddress,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
p := arp.NewProtocol()
|
||||
linkRes, ok := p.(stack.LinkAddressResolver)
|
||||
if !ok {
|
||||
t.Fatal("expected ARP protocol to implement stack.LinkAddressResolver")
|
||||
}
|
||||
|
||||
linkEP := channel.New(defaultChannelSize, defaultMTU, stackLinkAddr1)
|
||||
if err := linkRes.LinkAddressRequest(stackAddr1, stackAddr2, test.remoteLinkAddr, linkEP); err != nil {
|
||||
t.Errorf("got p.LinkAddressRequest(%s, %s, %s, _) = %s", stackAddr1, stackAddr2, test.remoteLinkAddr, err)
|
||||
}
|
||||
|
||||
pkt, ok := linkEP.Read()
|
||||
if !ok {
|
||||
t.Fatal("expected to send a link address request")
|
||||
}
|
||||
|
||||
if got, want := pkt.Route.RemoteLinkAddress, test.expectLinkAddr; got != want {
|
||||
t.Errorf("got pkt.Route.RemoteLinkAddress = %s, want = %s", got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -504,7 +504,7 @@ func (*protocol) LinkAddressProtocol() tcpip.NetworkProtocolNumber {
|
||||
}
|
||||
|
||||
// LinkAddressRequest implements stack.LinkAddressResolver.
|
||||
func (*protocol) LinkAddressRequest(addr, localAddr tcpip.Address, linkEP stack.LinkEndpoint) *tcpip.Error {
|
||||
func (*protocol) LinkAddressRequest(addr, localAddr tcpip.Address, remoteLinkAddr tcpip.LinkAddress, linkEP stack.LinkEndpoint) *tcpip.Error {
|
||||
snaddr := header.SolicitedNodeAddr(addr)
|
||||
|
||||
// TODO(b/148672031): Use stack.FindRoute instead of manually creating the
|
||||
@@ -513,8 +513,12 @@ func (*protocol) LinkAddressRequest(addr, localAddr tcpip.Address, linkEP stack.
|
||||
r := &stack.Route{
|
||||
LocalAddress: localAddr,
|
||||
RemoteAddress: snaddr,
|
||||
RemoteLinkAddress: header.EthernetAddressFromMulticastIPv6Address(snaddr),
|
||||
RemoteLinkAddress: remoteLinkAddr,
|
||||
}
|
||||
if len(r.RemoteLinkAddress) == 0 {
|
||||
r.RemoteLinkAddress = header.EthernetAddressFromMulticastIPv6Address(snaddr)
|
||||
}
|
||||
|
||||
hdr := buffer.NewPrependable(int(linkEP.MaxHeaderLength()) + header.IPv6MinimumSize + header.ICMPv6NeighborAdvertSize)
|
||||
pkt := header.ICMPv6(hdr.Prepend(header.ICMPv6NeighborAdvertSize))
|
||||
pkt.SetType(header.ICMPv6NeighborSolicit)
|
||||
|
||||
@@ -34,6 +34,9 @@ const (
|
||||
linkAddr0 = tcpip.LinkAddress("\x02\x02\x03\x04\x05\x06")
|
||||
linkAddr1 = tcpip.LinkAddress("\x0a\x0b\x0c\x0d\x0e\x0e")
|
||||
linkAddr2 = tcpip.LinkAddress("\x0a\x0b\x0c\x0d\x0e\x0f")
|
||||
|
||||
defaultChannelSize = 1
|
||||
defaultMTU = 65536
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -257,8 +260,7 @@ func newTestContext(t *testing.T) *testContext {
|
||||
}),
|
||||
}
|
||||
|
||||
const defaultMTU = 65536
|
||||
c.linkEP0 = channel.New(256, defaultMTU, linkAddr0)
|
||||
c.linkEP0 = channel.New(defaultChannelSize, defaultMTU, linkAddr0)
|
||||
|
||||
wrappedEP0 := stack.LinkEndpoint(endpointWithResolutionCapability{LinkEndpoint: c.linkEP0})
|
||||
if testing.Verbose() {
|
||||
@@ -271,7 +273,7 @@ func newTestContext(t *testing.T) *testContext {
|
||||
t.Fatalf("AddAddress lladdr0: %v", err)
|
||||
}
|
||||
|
||||
c.linkEP1 = channel.New(256, defaultMTU, linkAddr1)
|
||||
c.linkEP1 = channel.New(defaultChannelSize, defaultMTU, linkAddr1)
|
||||
wrappedEP1 := stack.LinkEndpoint(endpointWithResolutionCapability{LinkEndpoint: c.linkEP1})
|
||||
if err := c.s1.CreateNIC(1, wrappedEP1); err != nil {
|
||||
t.Fatalf("CreateNIC failed: %v", err)
|
||||
@@ -951,3 +953,47 @@ func TestICMPChecksumValidationWithPayloadMultipleViews(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLinkAddressRequest(t *testing.T) {
|
||||
snaddr := header.SolicitedNodeAddr(lladdr0)
|
||||
mcaddr := header.EthernetAddressFromMulticastIPv6Address(snaddr)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
remoteLinkAddr tcpip.LinkAddress
|
||||
expectLinkAddr tcpip.LinkAddress
|
||||
}{
|
||||
{
|
||||
name: "Unicast",
|
||||
remoteLinkAddr: linkAddr1,
|
||||
expectLinkAddr: linkAddr1,
|
||||
},
|
||||
{
|
||||
name: "Multicast",
|
||||
remoteLinkAddr: "",
|
||||
expectLinkAddr: mcaddr,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
p := NewProtocol()
|
||||
linkRes, ok := p.(stack.LinkAddressResolver)
|
||||
if !ok {
|
||||
t.Fatalf("expected IPv6 protocol to implement stack.LinkAddressResolver")
|
||||
}
|
||||
|
||||
linkEP := channel.New(defaultChannelSize, defaultMTU, linkAddr0)
|
||||
if err := linkRes.LinkAddressRequest(lladdr0, lladdr1, test.remoteLinkAddr, linkEP); err != nil {
|
||||
t.Errorf("got p.LinkAddressRequest(%s, %s, %s, _) = %s", lladdr0, lladdr1, test.remoteLinkAddr, err)
|
||||
}
|
||||
|
||||
pkt, ok := linkEP.Read()
|
||||
if !ok {
|
||||
t.Fatal("expected to send a link address request")
|
||||
}
|
||||
|
||||
if got, want := pkt.Route.RemoteLinkAddress, test.expectLinkAddr; got != want {
|
||||
t.Errorf("got pkt.Route.RemoteLinkAddress = %s, want = %s", got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,10 +121,12 @@ func (*fwdTestNetworkEndpoint) Close() {}
|
||||
type fwdTestNetworkProtocol struct {
|
||||
addrCache *linkAddrCache
|
||||
addrResolveDelay time.Duration
|
||||
onLinkAddressResolved func(cache *linkAddrCache, addr tcpip.Address)
|
||||
onLinkAddressResolved func(cache *linkAddrCache, addr tcpip.Address, _ tcpip.LinkAddress)
|
||||
onResolveStaticAddress func(tcpip.Address) (tcpip.LinkAddress, bool)
|
||||
}
|
||||
|
||||
var _ LinkAddressResolver = (*fwdTestNetworkProtocol)(nil)
|
||||
|
||||
func (f *fwdTestNetworkProtocol) Number() tcpip.NetworkProtocolNumber {
|
||||
return fwdTestNetNumber
|
||||
}
|
||||
@@ -174,10 +176,10 @@ func (f *fwdTestNetworkProtocol) Close() {}
|
||||
|
||||
func (f *fwdTestNetworkProtocol) Wait() {}
|
||||
|
||||
func (f *fwdTestNetworkProtocol) LinkAddressRequest(addr, localAddr tcpip.Address, linkEP LinkEndpoint) *tcpip.Error {
|
||||
func (f *fwdTestNetworkProtocol) LinkAddressRequest(addr, localAddr tcpip.Address, remoteLinkAddr tcpip.LinkAddress, linkEP LinkEndpoint) *tcpip.Error {
|
||||
if f.addrCache != nil && f.onLinkAddressResolved != nil {
|
||||
time.AfterFunc(f.addrResolveDelay, func() {
|
||||
f.onLinkAddressResolved(f.addrCache, addr)
|
||||
f.onLinkAddressResolved(f.addrCache, addr, remoteLinkAddr)
|
||||
})
|
||||
}
|
||||
return nil
|
||||
@@ -405,7 +407,7 @@ func TestForwardingWithFakeResolver(t *testing.T) {
|
||||
// Create a network protocol with a fake resolver.
|
||||
proto := &fwdTestNetworkProtocol{
|
||||
addrResolveDelay: 500 * time.Millisecond,
|
||||
onLinkAddressResolved: func(cache *linkAddrCache, addr tcpip.Address) {
|
||||
onLinkAddressResolved: func(cache *linkAddrCache, addr tcpip.Address, _ tcpip.LinkAddress) {
|
||||
// Any address will be resolved to the link address "c".
|
||||
cache.add(tcpip.FullAddress{NIC: 2, Addr: addr}, "c")
|
||||
},
|
||||
@@ -463,7 +465,7 @@ func TestForwardingWithFakeResolverPartialTimeout(t *testing.T) {
|
||||
// Create a network protocol with a fake resolver.
|
||||
proto := &fwdTestNetworkProtocol{
|
||||
addrResolveDelay: 500 * time.Millisecond,
|
||||
onLinkAddressResolved: func(cache *linkAddrCache, addr tcpip.Address) {
|
||||
onLinkAddressResolved: func(cache *linkAddrCache, addr tcpip.Address, _ tcpip.LinkAddress) {
|
||||
// Only packets to address 3 will be resolved to the
|
||||
// link address "c".
|
||||
if addr == "\x03" {
|
||||
@@ -515,7 +517,7 @@ func TestForwardingWithFakeResolverTwoPackets(t *testing.T) {
|
||||
// Create a network protocol with a fake resolver.
|
||||
proto := &fwdTestNetworkProtocol{
|
||||
addrResolveDelay: 500 * time.Millisecond,
|
||||
onLinkAddressResolved: func(cache *linkAddrCache, addr tcpip.Address) {
|
||||
onLinkAddressResolved: func(cache *linkAddrCache, addr tcpip.Address, _ tcpip.LinkAddress) {
|
||||
// Any packets will be resolved to the link address "c".
|
||||
cache.add(tcpip.FullAddress{NIC: 2, Addr: addr}, "c")
|
||||
},
|
||||
@@ -559,7 +561,7 @@ func TestForwardingWithFakeResolverManyPackets(t *testing.T) {
|
||||
// Create a network protocol with a fake resolver.
|
||||
proto := &fwdTestNetworkProtocol{
|
||||
addrResolveDelay: 500 * time.Millisecond,
|
||||
onLinkAddressResolved: func(cache *linkAddrCache, addr tcpip.Address) {
|
||||
onLinkAddressResolved: func(cache *linkAddrCache, addr tcpip.Address, _ tcpip.LinkAddress) {
|
||||
// Any packets will be resolved to the link address "c".
|
||||
cache.add(tcpip.FullAddress{NIC: 2, Addr: addr}, "c")
|
||||
},
|
||||
@@ -616,7 +618,7 @@ func TestForwardingWithFakeResolverManyResolutions(t *testing.T) {
|
||||
// Create a network protocol with a fake resolver.
|
||||
proto := &fwdTestNetworkProtocol{
|
||||
addrResolveDelay: 500 * time.Millisecond,
|
||||
onLinkAddressResolved: func(cache *linkAddrCache, addr tcpip.Address) {
|
||||
onLinkAddressResolved: func(cache *linkAddrCache, addr tcpip.Address, _ tcpip.LinkAddress) {
|
||||
// Any packets will be resolved to the link address "c".
|
||||
cache.add(tcpip.FullAddress{NIC: 2, Addr: addr}, "c")
|
||||
},
|
||||
|
||||
@@ -244,7 +244,7 @@ func (c *linkAddrCache) startAddressResolution(k tcpip.FullAddress, linkRes Link
|
||||
for i := 0; ; i++ {
|
||||
// Send link request, then wait for the timeout limit and check
|
||||
// whether the request succeeded.
|
||||
linkRes.LinkAddressRequest(k.Addr, localAddr, linkEP)
|
||||
linkRes.LinkAddressRequest(k.Addr, localAddr, "" /* linkAddr */, linkEP)
|
||||
|
||||
select {
|
||||
case now := <-time.After(c.resolutionTimeout):
|
||||
|
||||
@@ -48,7 +48,7 @@ type testLinkAddressResolver struct {
|
||||
onLinkAddressRequest func()
|
||||
}
|
||||
|
||||
func (r *testLinkAddressResolver) LinkAddressRequest(addr, _ tcpip.Address, _ LinkEndpoint) *tcpip.Error {
|
||||
func (r *testLinkAddressResolver) LinkAddressRequest(addr, _ tcpip.Address, _ tcpip.LinkAddress, _ LinkEndpoint) *tcpip.Error {
|
||||
time.AfterFunc(r.delay, func() { r.fakeRequest(addr) })
|
||||
if f := r.onLinkAddressRequest; f != nil {
|
||||
f()
|
||||
|
||||
@@ -243,7 +243,7 @@ func (*testIPv6Protocol) LinkAddressProtocol() tcpip.NetworkProtocolNumber {
|
||||
}
|
||||
|
||||
// LinkAddressRequest implements LinkAddressResolver.
|
||||
func (*testIPv6Protocol) LinkAddressRequest(_, _ tcpip.Address, _ LinkEndpoint) *tcpip.Error {
|
||||
func (*testIPv6Protocol) LinkAddressRequest(_, _ tcpip.Address, _ tcpip.LinkAddress, _ LinkEndpoint) *tcpip.Error {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -478,12 +478,13 @@ type InjectableLinkEndpoint interface {
|
||||
// A LinkAddressResolver is an extension to a NetworkProtocol that
|
||||
// can resolve link addresses.
|
||||
type LinkAddressResolver interface {
|
||||
// LinkAddressRequest sends a request for the LinkAddress of addr.
|
||||
// The request is sent on linkEP with localAddr as the source.
|
||||
// LinkAddressRequest sends a request for the LinkAddress of addr. Broadcasts
|
||||
// the request on the local network if remoteLinkAddr is the zero value. The
|
||||
// request is sent on linkEP with localAddr as the source.
|
||||
//
|
||||
// A valid response will cause the discovery protocol's network
|
||||
// endpoint to call AddLinkAddress.
|
||||
LinkAddressRequest(addr, localAddr tcpip.Address, linkEP LinkEndpoint) *tcpip.Error
|
||||
LinkAddressRequest(addr, localAddr tcpip.Address, remoteLinkAddr tcpip.LinkAddress, linkEP LinkEndpoint) *tcpip.Error
|
||||
|
||||
// ResolveStaticAddress attempts to resolve address without sending
|
||||
// requests. It either resolves the name immediately or returns the
|
||||
|
||||
Reference in New Issue
Block a user