mirror of
https://github.com/AdguardTeam/AdGuardHome.git
synced 2026-06-28 03:41:19 +00:00
Pull request 2584: 4923-gopacket-dhcp-vol.20
Updates #4923. Squashed commit of the following: commit 6efeea0845921a6ea20c43d5dd937294c271f800 Author: Eugene Burkov <E.Burkov@AdGuard.COM> Date: Fri Feb 13 16:09:10 2026 +0300 dhcpsvc: imp code commit 50486ed5dbe3ad28a302ab382e5ad3eef4d9712e Author: Eugene Burkov <E.Burkov@AdGuard.COM> Date: Thu Feb 12 17:56:34 2026 +0300 dhcpsvc: close devices
This commit is contained in:
parent
6abc092d6b
commit
81dcf43f2b
3 changed files with 62 additions and 9 deletions
|
|
@ -2,6 +2,7 @@ package dhcpsvc
|
|||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"net/netip"
|
||||
|
||||
"github.com/AdguardTeam/golibs/errors"
|
||||
|
|
@ -28,10 +29,10 @@ func (conf *NetworkDeviceConfig) Validate() (err error) {
|
|||
}
|
||||
|
||||
// NetworkDeviceManager creates and manages network devices.
|
||||
//
|
||||
// TODO(e.burkov): Add device closing method.
|
||||
type NetworkDeviceManager interface {
|
||||
// Open opens a network device. conf must be valid.
|
||||
//
|
||||
// An attempt to open the same device multiple times may return an error.
|
||||
Open(ctx context.Context, conf *NetworkDeviceConfig) (dev NetworkDevice, err error)
|
||||
}
|
||||
|
||||
|
|
@ -59,6 +60,9 @@ func (EmptyNetworkDeviceManager) Open(
|
|||
type NetworkDevice interface {
|
||||
gopacket.PacketDataSource
|
||||
|
||||
// No methods of a device should be called after Close.
|
||||
io.Closer
|
||||
|
||||
// Addresses returns all IP addresses assigned to the device.
|
||||
Addresses() (ips []netip.Addr)
|
||||
|
||||
|
|
@ -82,6 +86,12 @@ func (EmptyNetworkDevice) ReadPacketData() (data []byte, ci gopacket.CaptureInfo
|
|||
return nil, gopacket.CaptureInfo{}, nil
|
||||
}
|
||||
|
||||
// Close implements the [io.Closer] interface for [EmptyNetworkDevice]. It
|
||||
// always returns nil.
|
||||
func (EmptyNetworkDevice) Close() (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Addresses implements the [NetworkDevice] interface for [EmptyNetworkDevice].
|
||||
// It always returns nil.
|
||||
func (EmptyNetworkDevice) Addresses() (ips []netip.Addr) {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,9 @@ package dhcpsvc_test
|
|||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"net/netip"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/dhcpsvc"
|
||||
|
|
@ -41,6 +43,7 @@ func (ndm *testNetworkDeviceManager) Open(
|
|||
// TODO(e.burkov): Move to aghtest.
|
||||
type testNetworkDevice struct {
|
||||
onReadPacketData func() (data []byte, ci gopacket.CaptureInfo, err error)
|
||||
onClose func() (err error)
|
||||
onAddresses func() (ips []netip.Addr)
|
||||
onLinkType func() (lt layers.LinkType)
|
||||
onWritePacketData func(data []byte) (err error)
|
||||
|
|
@ -55,6 +58,11 @@ func (nd *testNetworkDevice) ReadPacketData() (data []byte, ci gopacket.CaptureI
|
|||
return nd.onReadPacketData()
|
||||
}
|
||||
|
||||
// Close implements the [io.Closer] interface for *testNetworkDevice.
|
||||
func (nd *testNetworkDevice) Close() (err error) {
|
||||
return nd.onClose()
|
||||
}
|
||||
|
||||
// Addresses implements the [dhcpsvc.NetworkDevice] interface for
|
||||
// *testNetworkDevice.
|
||||
func (nd *testNetworkDevice) Addresses() (ips []netip.Addr) {
|
||||
|
|
@ -87,13 +95,19 @@ func newTestNetworkDeviceManager(
|
|||
inCh = make(chan gopacket.Packet)
|
||||
outCh = make(chan []byte)
|
||||
|
||||
isOpened := atomic.Bool{}
|
||||
|
||||
pt := testutil.PanicT{}
|
||||
addrs := []netip.Addr{addr}
|
||||
|
||||
dev := &testNetworkDevice{
|
||||
onReadPacketData: func() (data []byte, ci gopacket.CaptureInfo, err error) {
|
||||
pkt, ok := testutil.RequireReceive(pt, inCh, testTimeout)
|
||||
require.True(pt, ok)
|
||||
require.Equal(pt, isOpened.Load(), ok)
|
||||
|
||||
if !ok {
|
||||
return nil, gopacket.CaptureInfo{}, io.EOF
|
||||
}
|
||||
|
||||
data = pkt.Data()
|
||||
ci = gopacket.CaptureInfo{
|
||||
|
|
@ -103,6 +117,12 @@ func newTestNetworkDeviceManager(
|
|||
|
||||
return data, ci, nil
|
||||
},
|
||||
onClose: func() (err error) {
|
||||
isOpened.Store(false)
|
||||
close(inCh)
|
||||
|
||||
return nil
|
||||
},
|
||||
onAddresses: func() (ips []netip.Addr) {
|
||||
return addrs
|
||||
},
|
||||
|
|
@ -121,6 +141,7 @@ func newTestNetworkDeviceManager(
|
|||
_ context.Context,
|
||||
conf *dhcpsvc.NetworkDeviceConfig,
|
||||
) (nd dhcpsvc.NetworkDevice, err error) {
|
||||
isOpened.Store(true)
|
||||
require.Equal(pt, deviceName, conf.Name)
|
||||
|
||||
return dev, nil
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import (
|
|||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/AdguardTeam/golibs/container"
|
||||
"github.com/AdguardTeam/golibs/errors"
|
||||
"github.com/AdguardTeam/golibs/netutil"
|
||||
)
|
||||
|
|
@ -30,6 +31,12 @@ type DHCPServer struct {
|
|||
// deviceManager is the manager of network devices.
|
||||
deviceManager NetworkDeviceManager
|
||||
|
||||
// devices are the network devices opened in [DHCPServer.Start], mapped to
|
||||
// their names. Those are closed in [DHCPServer.Shutdown].
|
||||
//
|
||||
// TODO(e.burkov): Consider storing those within interfaces.
|
||||
devices container.KeyValues[string, NetworkDevice]
|
||||
|
||||
// localTLD is the top-level domain name to use for resolving DHCP clients'
|
||||
// hostnames.
|
||||
localTLD string
|
||||
|
|
@ -137,9 +144,11 @@ func (srv *DHCPServer) Start(ctx context.Context) (err error) {
|
|||
|
||||
var errs []error
|
||||
for _, iface := range srv.interfaces4 {
|
||||
var nd NetworkDevice
|
||||
nd, err = srv.deviceManager.Open(ctx, &NetworkDeviceConfig{
|
||||
Name: iface.common.name,
|
||||
netDevName := iface.common.name
|
||||
|
||||
var netDev NetworkDevice
|
||||
netDev, err = srv.deviceManager.Open(ctx, &NetworkDeviceConfig{
|
||||
Name: netDevName,
|
||||
})
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
|
|
@ -147,7 +156,12 @@ func (srv *DHCPServer) Start(ctx context.Context) (err error) {
|
|||
continue
|
||||
}
|
||||
|
||||
go srv.serveEther4(context.WithoutCancel(ctx), iface, nd)
|
||||
srv.devices = append(srv.devices, container.KeyValue[string, NetworkDevice]{
|
||||
Key: netDevName,
|
||||
Value: netDev,
|
||||
})
|
||||
|
||||
go srv.serveEther4(context.WithoutCancel(ctx), iface, netDev)
|
||||
}
|
||||
|
||||
// TODO(e.burkov): Serve EthernetTypeIPv6.
|
||||
|
|
@ -159,9 +173,17 @@ func (srv *DHCPServer) Start(ctx context.Context) (err error) {
|
|||
func (srv *DHCPServer) Shutdown(ctx context.Context) (err error) {
|
||||
srv.logger.DebugContext(ctx, "shutting down dhcp server")
|
||||
|
||||
// TODO(e.burkov): Close the packet source.
|
||||
var errs []error
|
||||
for _, kv := range srv.devices {
|
||||
netDevName, netDev := kv.Key, kv.Value
|
||||
|
||||
return nil
|
||||
err = netDev.Close()
|
||||
if err != nil {
|
||||
errs = append(errs, fmt.Errorf("closing device %q: %w", netDevName, err))
|
||||
}
|
||||
}
|
||||
|
||||
return errors.Join(errs...)
|
||||
}
|
||||
|
||||
// Enabled implements the [Interface] interface for *DHCPServer.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue