Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ module github.com/moby/ipvs
go 1.23

require (
github.com/sirupsen/logrus v1.10.2
github.com/vishvananda/netlink v1.3.1
github.com/vishvananda/netns v0.0.5
golang.org/x/sys v0.13.0
Expand Down
6 changes: 0 additions & 6 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,13 +1,7 @@
github.com/sirupsen/logrus v1.10.2 h1:G2SED73/qrAu6YwbdxOD6peLkCBI3z7L+ykJFTXJBBo=
github.com/sirupsen/logrus v1.10.2/go.mod h1:SLEg8TqYulVKKfIGHldVp2K2aYz2DKSVBq4g/H5bR7Q=
github.com/stretchr/testify v1.12.1 h1:EuwCh5fleGS7H32xRwO3wRGT7DxrDhLAT6FF8MpWDWE=
github.com/stretchr/testify v1.12.1/go.mod h1:MDEgiDPPsNp5cuIrHPPCyornHKgEVbtFUmoNlxoYthg=
github.com/vishvananda/netlink v1.3.1 h1:3AEMt62VKqz90r0tmNhog0r/PpWKmrEShJU0wJW6bV0=
github.com/vishvananda/netlink v1.3.1/go.mod h1:ARtKouGSTGchR8aMwmkzC0qiNPrrWO5JS/XMVl45+b4=
github.com/vishvananda/netns v0.0.5 h1:DfiHV+j8bA32MFM7bfEunvT8IAqQ/NzSJHtcmW5zdEY=
github.com/vishvananda/netns v0.0.5/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
go.yaml.in/yaml/v3 v3.0.5 h1:N6y/pJk8buWs9NY5ERU2HSMfm+IuD/OtfdAnq6kESPw=
go.yaml.in/yaml/v3 v3.0.5/go.mod h1:HVTZu1O7/Vkt2N+BFy8Zza+lnLsABggaTM2ZpNIGuKg=
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
Expand Down
6 changes: 4 additions & 2 deletions ipvs_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,9 @@ type Handle struct {
// passed path. It will return a valid handle or an error in case an
// error occurred while creating the handle.
func New(path string) (*Handle, error) {
setup()
if _, err := ipvsFamily(); err != nil {
return nil, err
}

n := netns.None()
if path != "" {
Expand All @@ -93,8 +95,8 @@ func New(path string) (*Handle, error) {
if err != nil {
return nil, err
}
defer func() { _ = n.Close() }()
}
defer n.Close()

sock, err := nl.GetNetlinkSocketAt(n, netns.None(), unix.NETLINK_GENERIC)
if err != nil {
Expand Down
43 changes: 23 additions & 20 deletions netlink_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,24 +8,18 @@ import (
"math"
"net"
"os/exec"
"strings"
"sync"
"sync/atomic"
"syscall"
"time"

"github.com/sirupsen/logrus"
"github.com/vishvananda/netlink/nl"
"github.com/vishvananda/netns"
"golang.org/x/sys/unix"
)

// For Quick Reference IPVS related netlink message is described at the end of this file.
var (
native = nl.NativeEndian()
ipvsFamily int
ipvsOnce sync.Once
)
var native = nl.NativeEndian()

// genlMsgHdrLen is the serialized size of genlMsgHdr. Keep this explicit
// rather than deriving it with unsafe.Sizeof so the wire format does not
Expand Down Expand Up @@ -71,19 +65,27 @@ func (*ipvsFlags) Len() int {
return ipvsFlagsLen
}

func setup() {
ipvsOnce.Do(func() {
var err error
if out, err := exec.Command("modprobe", "-va", "ip_vs").CombinedOutput(); err != nil {
logrus.Warnf("Running modprobe ip_vs failed with message: `%s`, error: %v", strings.TrimSpace(string(out)), err)
}
// ipvsFamily lazily discovers and caches the IPVS generic-netlink family ID
// and any initialization error.
var ipvsFamily = sync.OnceValues(func() (int, error) {
family, err := getIPVSFamily()
if err == nil {
return family, nil
}

ipvsFamily, err = getIPVSFamily()
if err != nil {
logrus.Error("Could not get ipvs family information from the kernel. It is possible that ipvs is not enabled in your kernel. Native loadbalancing will not work until this is fixed.")
}
})
}
// Linux 5.17 added automatic loading of ip_vs through generic-netlink
// family discovery. Older kernels, including RHEL 8's 4.18 kernel,
// may still require explicit module loading.
//
// See https://lists.openwall.net/netdev/2021/11/01/229
_, _ = exec.Command("modprobe", "-va", "ip_vs").CombinedOutput()

family, err = getIPVSFamily()
if err != nil {
return 0, fmt.Errorf("get IPVS generic-netlink family: %w", err)
}
Comment on lines +81 to +86
return family, nil
})

func fillService(s *Service) nl.NetlinkRequestData {
cmdAttr := nl.NewRtAttr(int(ipvsCmdAttrService), nil)
Expand Down Expand Up @@ -218,7 +220,8 @@ func rawIPData(ip net.IP) []byte {
}

func newIPVSRequest(cmd ipvsCmd) *nl.NetlinkRequest {
return newGenlRequest(ipvsFamily, uint8(cmd))
family, _ := ipvsFamily()
return newGenlRequest(family, uint8(cmd))
}

func newGenlRequest(familyID int, cmd uint8) *nl.NetlinkRequest {
Expand Down
Loading