104 lines
2.7 KiB
Go
104 lines
2.7 KiB
Go
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
package vpp
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"log/slog"
|
|
"net"
|
|
|
|
"git.ipng.ch/ipng/vpp-maglev/internal/config"
|
|
ip_types "git.ipng.ch/ipng/vpp-maglev/internal/vpp/binapi/ip_types"
|
|
lb "git.ipng.ch/ipng/vpp-maglev/internal/vpp/binapi/lb"
|
|
)
|
|
|
|
// SetLBConf sends lb_conf to VPP with the global load-balancer settings from
|
|
// cfg. Called on VPP connect (startup and reconnect) and after every
|
|
// successful config reload. Returns nil if VPP is not connected (silently
|
|
// skipped — the next connect will push the conf).
|
|
//
|
|
// The values sent are cached on the Client; if SetLBConf is called twice in
|
|
// a row with unchanged values, no API call is made and no log is emitted.
|
|
func (c *Client) SetLBConf(cfg *config.Config) error {
|
|
if !c.IsConnected() {
|
|
return nil
|
|
}
|
|
|
|
req := &lb.LbConf{
|
|
IP4SrcAddress: ip_types.IP4Address(ip4Bytes(cfg.VPP.LB.IPv4SrcAddress)),
|
|
IP6SrcAddress: ip_types.IP6Address(ip6Bytes(cfg.VPP.LB.IPv6SrcAddress)),
|
|
StickyBucketsPerCore: cfg.VPP.LB.StickyBucketsPerCore,
|
|
FlowTimeout: uint32(cfg.VPP.LB.FlowTimeout.Seconds()),
|
|
}
|
|
|
|
// Skip if nothing changed since the last successful push.
|
|
c.mu.Lock()
|
|
prev := c.lastLBConf
|
|
c.mu.Unlock()
|
|
if prev != nil &&
|
|
bytes.Equal(prev.IP4SrcAddress[:], req.IP4SrcAddress[:]) &&
|
|
bytes.Equal(prev.IP6SrcAddress[:], req.IP6SrcAddress[:]) &&
|
|
prev.StickyBucketsPerCore == req.StickyBucketsPerCore &&
|
|
prev.FlowTimeout == req.FlowTimeout {
|
|
return nil
|
|
}
|
|
|
|
ch, err := c.apiChannel()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer ch.Close()
|
|
|
|
reply := &lb.LbConfReply{}
|
|
if err := ch.SendRequest(req).ReceiveReply(reply); err != nil {
|
|
return fmt.Errorf("lb_conf: %w", err)
|
|
}
|
|
if reply.Retval != 0 {
|
|
return fmt.Errorf("lb_conf: retval=%d", reply.Retval)
|
|
}
|
|
|
|
c.mu.Lock()
|
|
c.lastLBConf = req
|
|
c.mu.Unlock()
|
|
|
|
slog.Info("vpp-lb-conf-set",
|
|
"ipv4-src", ipStringFromCfg(cfg.VPP.LB.IPv4SrcAddress),
|
|
"ipv6-src", ipStringFromCfg(cfg.VPP.LB.IPv6SrcAddress),
|
|
"sticky-buckets-per-core", req.StickyBucketsPerCore,
|
|
"flow-timeout", cfg.VPP.LB.FlowTimeout.String())
|
|
return nil
|
|
}
|
|
|
|
// ip4Bytes returns the 4-byte representation of an IPv4 address, or all-zero
|
|
// if ip is nil/unset.
|
|
func ip4Bytes(ip net.IP) [4]byte {
|
|
var out [4]byte
|
|
if ip == nil {
|
|
return out
|
|
}
|
|
if b := ip.To4(); b != nil {
|
|
copy(out[:], b)
|
|
}
|
|
return out
|
|
}
|
|
|
|
// ip6Bytes returns the 16-byte representation of an IPv6 address, or all-zero
|
|
// if ip is nil/unset.
|
|
func ip6Bytes(ip net.IP) [16]byte {
|
|
var out [16]byte
|
|
if ip == nil {
|
|
return out
|
|
}
|
|
copy(out[:], ip.To16())
|
|
return out
|
|
}
|
|
|
|
// ipStringFromCfg renders an IP for logging; returns "unset" if nil.
|
|
func ipStringFromCfg(ip net.IP) string {
|
|
if ip == nil {
|
|
return "unset"
|
|
}
|
|
return ip.String()
|
|
}
|