Skip to content

Commit 1b3442c

Browse files
ckuipershentubot
authored andcommitted
Allow sending of broadcast packets w/o route.
Currently sending a broadcast packet (for DHCP, e.g.) requires a "default route" of the format "0.0.0.0/0 via 0.0.0.0 <intf>". There is no good reason for this and on devices with several ports this creates a rather akward route table with lots of such default routes (which defeats the purpose of a default route). PiperOrigin-RevId: 224378769 Change-Id: Icd7ec8a206eb08083cff9a837f6f9ab231c73a19
1 parent 666db00 commit 1b3442c

File tree

3 files changed

+57
-7
lines changed

3 files changed

+57
-7
lines changed

pkg/tcpip/stack/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ go_test(
4040
":stack",
4141
"//pkg/tcpip",
4242
"//pkg/tcpip/buffer",
43+
"//pkg/tcpip/header",
4344
"//pkg/tcpip/link/channel",
4445
"//pkg/waiter",
4546
],

pkg/tcpip/stack/stack.go

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -716,12 +716,29 @@ func (s *Stack) GetMainNICAddress(id tcpip.NICID, protocol tcpip.NetworkProtocol
716716
return "", tcpip.Subnet{}, tcpip.ErrUnknownNICID
717717
}
718718

719+
func (s *Stack) getRefEP(nic *NIC, localAddr tcpip.Address, netProto tcpip.NetworkProtocolNumber) (ref *referencedNetworkEndpoint) {
720+
if len(localAddr) == 0 {
721+
return nic.primaryEndpoint(netProto)
722+
}
723+
return nic.findEndpoint(netProto, localAddr, CanBePrimaryEndpoint)
724+
}
725+
719726
// FindRoute creates a route to the given destination address, leaving through
720727
// the given nic and local address (if provided).
721728
func (s *Stack) FindRoute(id tcpip.NICID, localAddr, remoteAddr tcpip.Address, netProto tcpip.NetworkProtocolNumber) (Route, *tcpip.Error) {
722729
s.mu.RLock()
723730
defer s.mu.RUnlock()
724731

732+
// We don't require a route in the table to send a broadcast out on a NIC.
733+
if id != 0 && remoteAddr == header.IPv4Broadcast {
734+
if nic, ok := s.nics[id]; ok {
735+
if ref := s.getRefEP(nic, localAddr, netProto); ref != nil {
736+
return makeRoute(netProto, ref.ep.ID().LocalAddress, remoteAddr, nic.linkEP.LinkAddress(), ref), nil
737+
}
738+
}
739+
return Route{}, tcpip.ErrNoRoute
740+
}
741+
725742
for i := range s.routeTable {
726743
if (id != 0 && id != s.routeTable[i].NIC) || (len(remoteAddr) != 0 && !s.routeTable[i].Match(remoteAddr)) {
727744
continue
@@ -732,12 +749,7 @@ func (s *Stack) FindRoute(id tcpip.NICID, localAddr, remoteAddr tcpip.Address, n
732749
continue
733750
}
734751

735-
var ref *referencedNetworkEndpoint
736-
if len(localAddr) != 0 {
737-
ref = nic.findEndpoint(netProto, localAddr, CanBePrimaryEndpoint)
738-
} else {
739-
ref = nic.primaryEndpoint(netProto)
740-
}
752+
ref := s.getRefEP(nic, localAddr, netProto)
741753
if ref == nil {
742754
continue
743755
}

pkg/tcpip/stack/stack_test.go

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import (
2626

2727
"gvisor.googlesource.com/gvisor/pkg/tcpip"
2828
"gvisor.googlesource.com/gvisor/pkg/tcpip/buffer"
29+
"gvisor.googlesource.com/gvisor/pkg/tcpip/header"
2930
"gvisor.googlesource.com/gvisor/pkg/tcpip/link/channel"
3031
"gvisor.googlesource.com/gvisor/pkg/tcpip/stack"
3132
)
@@ -643,6 +644,42 @@ func TestAddressSpoofing(t *testing.T) {
643644
}
644645
}
645646

647+
func TestBroadcastNeedsNoRoute(t *testing.T) {
648+
s := stack.New([]string{"fakeNet"}, nil, stack.Options{})
649+
650+
id, _ := channel.New(10, defaultMTU, "")
651+
if err := s.CreateNIC(1, id); err != nil {
652+
t.Fatalf("CreateNIC failed: %v", err)
653+
}
654+
s.SetRouteTable([]tcpip.Route{})
655+
656+
// If there is no endpoint, it won't work.
657+
if _, err := s.FindRoute(1, header.IPv4Any, header.IPv4Broadcast, fakeNetNumber); err != tcpip.ErrNoRoute {
658+
t.Fatalf("got FindRoute(1, %v, %v, %v) = %v, want = %v", header.IPv4Any, header.IPv4Broadcast, fakeNetNumber, err, tcpip.ErrNoRoute)
659+
}
660+
661+
if err := s.AddAddress(1, fakeNetNumber, header.IPv4Any); err != nil {
662+
t.Fatalf("AddAddress(%v, %v) failed: %v", fakeNetNumber, header.IPv4Any, err)
663+
}
664+
r, err := s.FindRoute(1, header.IPv4Any, header.IPv4Broadcast, fakeNetNumber)
665+
if err != nil {
666+
t.Fatalf("FindRoute(1, %v, %v, %v) failed: %v", header.IPv4Any, header.IPv4Broadcast, fakeNetNumber, err)
667+
}
668+
669+
if r.LocalAddress != header.IPv4Any {
670+
t.Errorf("Bad local address: got %v, want = %v", r.LocalAddress, header.IPv4Any)
671+
}
672+
673+
if r.RemoteAddress != header.IPv4Broadcast {
674+
t.Errorf("Bad remote address: got %v, want = %v", r.RemoteAddress, header.IPv4Broadcast)
675+
}
676+
677+
// If the NIC doesn't exist, it won't work.
678+
if _, err := s.FindRoute(2, header.IPv4Any, header.IPv4Broadcast, fakeNetNumber); err != tcpip.ErrNoRoute {
679+
t.Fatalf("got FindRoute(2, %v, %v, %v) = %v want = %v", header.IPv4Any, header.IPv4Broadcast, fakeNetNumber, err, tcpip.ErrNoRoute)
680+
}
681+
}
682+
646683
// Set the subnet, then check that packet is delivered.
647684
func TestSubnetAcceptsMatchingPacket(t *testing.T) {
648685
s := stack.New([]string{"fakeNet"}, nil, stack.Options{})
@@ -849,7 +886,7 @@ func TestGetMainNICAddressAddPrimaryNonPrimary(t *testing.T) {
849886
if !ok {
850887
t.Fatalf("GetMainNICAddress: got address = %v, wanted any in {%v}", gotAddress, primaryAddrAdded)
851888
}
852-
if expectedSubnet != gotSubnet {
889+
if gotSubnet != expectedSubnet {
853890
t.Fatalf("GetMainNICAddress: got subnet = %v, wanted %v", gotSubnet, expectedSubnet)
854891
}
855892
}

0 commit comments

Comments
 (0)