kvm/internal/lldp/lldp.go

107 lines
2.0 KiB
Go

package lldp
import (
"context"
"sync"
"time"
"github.com/google/gopacket"
"github.com/google/gopacket/afpacket"
"github.com/jellydator/ttlcache/v3"
"github.com/jetkvm/kvm/internal/logging"
"github.com/rs/zerolog"
)
var defaultLogger = logging.GetSubsystemLogger("lldp")
type LLDP struct {
l *zerolog.Logger
tPacket *afpacket.TPacket
pktSource *gopacket.PacketSource
rxCtx context.Context
rxCancel context.CancelFunc
rxLock sync.Mutex
enableRx bool
enableTx bool
packets chan gopacket.Packet
interfaceName string
stop chan struct{}
neighbors *ttlcache.Cache[string, Neighbor]
}
type LLDPOptions struct {
InterfaceName string
EnableRx bool
EnableTx bool
Logger *zerolog.Logger
}
func NewLLDP(opts *LLDPOptions) *LLDP {
if opts.Logger == nil {
opts.Logger = defaultLogger
}
if opts.InterfaceName == "" {
opts.Logger.Fatal().Msg("InterfaceName is required")
}
return &LLDP{
interfaceName: opts.InterfaceName,
enableRx: opts.EnableRx,
enableTx: opts.EnableTx,
l: opts.Logger,
neighbors: ttlcache.New(ttlcache.WithTTL[string, Neighbor](1 * time.Hour)),
}
}
func (l *LLDP) Start() error {
l.rxLock.Lock()
defer l.rxLock.Unlock()
if l.rxCtx != nil {
l.l.Info().Msg("LLDP already started")
return nil
}
l.rxCtx, l.rxCancel = context.WithCancel(context.Background())
if l.enableRx {
l.l.Info().Msg("setting up AF_PACKET")
if err := l.setUpCapture(); err != nil {
l.l.Error().Err(err).Msg("unable to set up AF_PACKET")
return err
}
if err := l.startCapture(); err != nil {
l.l.Error().Err(err).Msg("unable to start capture")
return err
}
}
go l.neighbors.Start()
return nil
}
func (l *LLDP) Stop() error {
l.rxLock.Lock()
defer l.rxLock.Unlock()
if l.rxCancel != nil {
l.rxCancel()
l.rxCancel = nil
l.rxCtx = nil
}
if l.enableRx {
_ = l.shutdownCapture()
}
l.neighbors.Stop()
l.neighbors.DeleteAll()
return nil
}