Files
go-alived/internal/vrrp/manager.go
T
loveuer 00eba85e39
Release / Build darwin-amd64 (push) Has been cancelled
Release / Build linux-amd64 (push) Has been cancelled
Release / Build darwin-arm64 (push) Has been cancelled
Release / Build linux-arm64 (push) Has been cancelled
Release / Create Release (push) Has been cancelled
feat: add VRRP unicast peer support for macvlan and restricted network environments
- Add unicast_src_ip and unicast_peers config fields
- NewUnicastSocket binds to source IP for proper packet reception
- SendTo() sends VRRP advertisements directly to peer IPs
- Receive loop filters packets from non-peer sources in unicast mode
- Backward compatible: multicast mode used when unicast_peers is empty
- Add unicast config example (etc/config.unicast.yaml)
- Update README with unicast documentation and examples
2026-06-07 13:14:17 +08:00

118 lines
2.3 KiB
Go

package vrrp
import (
"fmt"
"sync"
"github.com/loveuer/go-alived/pkg/config"
"github.com/loveuer/go-alived/pkg/logger"
)
type Manager struct {
instances map[string]*Instance
mu sync.RWMutex
log *logger.Logger
}
func NewManager(log *logger.Logger) *Manager {
return &Manager{
instances: make(map[string]*Instance),
log: log,
}
}
func (m *Manager) LoadFromConfig(cfg *config.Config) error {
m.mu.Lock()
defer m.mu.Unlock()
for _, vrrpCfg := range cfg.VRRP {
inst, err := NewInstance(
vrrpCfg.Name,
uint8(vrrpCfg.VirtualRouterID),
uint8(vrrpCfg.Priority),
uint8(vrrpCfg.AdvertInterval),
vrrpCfg.Interface,
vrrpCfg.VirtualIPs,
vrrpCfg.AuthType,
vrrpCfg.AuthPass,
vrrpCfg.TrackScripts,
vrrpCfg.UnicastSrcIP,
vrrpCfg.UnicastPeers,
m.log,
)
if err != nil {
return fmt.Errorf("failed to create instance %s: %w", vrrpCfg.Name, err)
}
m.instances[vrrpCfg.Name] = inst
m.log.Info("loaded VRRP instance: %s", vrrpCfg.Name)
}
return nil
}
func (m *Manager) StartAll() error {
m.mu.RLock()
defer m.mu.RUnlock()
for name, inst := range m.instances {
if err := inst.Start(); err != nil {
return fmt.Errorf("failed to start instance %s: %w", name, err)
}
}
m.log.Info("started %d VRRP instance(s)", len(m.instances))
return nil
}
func (m *Manager) StopAll() {
m.mu.RLock()
defer m.mu.RUnlock()
for _, inst := range m.instances {
inst.Stop()
}
m.log.Info("stopped all VRRP instances")
}
func (m *Manager) GetInstance(name string) (*Instance, bool) {
m.mu.RLock()
defer m.mu.RUnlock()
inst, ok := m.instances[name]
return inst, ok
}
func (m *Manager) GetAllInstances() []*Instance {
m.mu.RLock()
defer m.mu.RUnlock()
result := make([]*Instance, 0, len(m.instances))
for _, inst := range m.instances {
result = append(result, inst)
}
return result
}
func (m *Manager) Reload(cfg *config.Config) error {
m.log.Info("reloading VRRP configuration...")
m.StopAll()
m.mu.Lock()
m.instances = make(map[string]*Instance)
m.mu.Unlock()
if err := m.LoadFromConfig(cfg); err != nil {
return fmt.Errorf("failed to load config: %w", err)
}
if err := m.StartAll(); err != nil {
return fmt.Errorf("failed to start instances: %w", err)
}
m.log.Info("VRRP configuration reloaded successfully")
return nil
}