Skip to content

Commit

Permalink
refactor: remove unmaintained github.com/vishvananda/netlink
Browse files Browse the repository at this point in the history
Replace it with other based on mdlayher/netlink packages.

Signed-off-by: Andrey Smirnov <[email protected]>
  • Loading branch information
smira committed Oct 28, 2024
1 parent 78353f7 commit dc0c6ac
Show file tree
Hide file tree
Showing 7 changed files with 202 additions and 77 deletions.
1 change: 0 additions & 1 deletion .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,6 @@ linters-settings:
# fd-leak related replacements: https://github.com/siderolabs/talos/issues/9412
- github.com/insomniacslk/dhcp
- github.com/safchain/ethtool
- github.com/vishvananda/netlink
retract-allow-no-explanation: false
exclude-forbidden: false

Expand Down
6 changes: 2 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,6 @@ replace (

// https://github.com/safchain/ethtool/pull/88
github.com/safchain/ethtool => github.com/smira/ethtool v0.0.0-20241001133415-4d519940893f

// https://github.com/vishvananda/netlink/pull/1023
github.com/vishvananda/netlink => github.com/smira/netlink v0.0.0-20241001134714-cf141a3c404c
)

// Kubernetes dependencies sharing the same version.
Expand Down Expand Up @@ -84,6 +81,7 @@ require (
github.com/dustin/go-humanize v1.0.1
github.com/ecks/uefi v0.0.0-20221116212947-caef65d070eb
github.com/fatih/color v1.17.0
github.com/florianl/go-tc v0.4.4
github.com/foxboron/go-uefi v0.0.0-20240805124652-e2076f0e58ca
github.com/freddierice/go-losetup/v2 v2.0.1
github.com/fsnotify/fsnotify v1.7.0
Expand Down Expand Up @@ -173,7 +171,6 @@ require (
github.com/stretchr/testify v1.9.0
github.com/u-root/u-root v0.14.0
github.com/ulikunitz/xz v0.5.12
github.com/vishvananda/netlink v1.3.0
github.com/vmware/vmw-guestinfo v0.0.0-20220317130741-510905f0efa3
github.com/vultr/metadata v1.1.0
go.etcd.io/etcd/api/v3 v3.5.16
Expand Down Expand Up @@ -339,6 +336,7 @@ require (
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 // indirect
github.com/u-root/uio v0.0.0-20240224005618-d2acac8f3701 // indirect
github.com/vbatts/tar-split v0.11.3 // indirect
github.com/vishvananda/netlink v1.3.0 // indirect
github.com/vishvananda/netns v0.0.4 // indirect
github.com/x448/float16 v0.8.4 // indirect
github.com/xiang90/probing v0.0.0-20221125231312-a49e3df8f510 // indirect
Expand Down
62 changes: 60 additions & 2 deletions go.sum

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion internal/app/machined/pkg/controllers/kubespan/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ type WireguardClient interface {
}

// RulesManagerFactory allows mocking RulesManager.
type RulesManagerFactory func(targetTable, internalMark, markMask int) RulesManager
type RulesManagerFactory func(targetTable uint8, internalMark, markMask uint32) RulesManager

// Inputs implements controller.Controller interface.
func (ctrl *ManagerController) Inputs() []controller.Input {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -397,7 +397,7 @@ func TestManagerSuite(t *testing.T) {
WireguardClientFactory: func() (kubespanctrl.WireguardClient, error) {
return mockWireguard, nil
},
RulesManagerFactory: func(_, _, _ int) kubespanctrl.RulesManager {
RulesManagerFactory: func(_ uint8, _, _ uint32) kubespanctrl.RulesManager {
return mockRulesManager{}
},
PeerReconcileInterval: time.Second,
Expand Down
79 changes: 38 additions & 41 deletions internal/app/machined/pkg/controllers/kubespan/routing_rules.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import (
"os"

"github.com/hashicorp/go-multierror"
"github.com/jsimonetti/rtnetlink/v2"
"github.com/siderolabs/go-pointer"
"github.com/vishvananda/netlink"
"golang.org/x/sys/unix"
)

Expand All @@ -24,7 +24,7 @@ type RulesManager interface {
}

// NewRulesManager initializes new RulesManager.
func NewRulesManager(targetTable, internalMark, markMask int) RulesManager {
func NewRulesManager(targetTable uint8, internalMark, markMask uint32) RulesManager {
return &rulesManager{
TargetTable: targetTable,
InternalMark: internalMark,
Expand All @@ -33,46 +33,44 @@ func NewRulesManager(targetTable, internalMark, markMask int) RulesManager {
}

type rulesManager struct {
TargetTable int
InternalMark int
MarkMask int
TargetTable uint8
InternalMark uint32
MarkMask uint32
}

// Install routing rules.
func (m *rulesManager) Install() error {
nc, err := netlink.NewHandle()
nc, err := rtnetlink.Dial(nil)
if err != nil {
return fmt.Errorf("failed to get netlink handle: %w", err)
}

defer nc.Close()

if err := nc.RuleAdd(&netlink.Rule{
Priority: nextRuleNumber(nc, unix.AF_INET),
Family: unix.AF_INET,
Table: m.TargetTable,
Mark: uint32(m.InternalMark),
Mask: pointer.To(uint32(m.MarkMask)),
Goto: -1,
Flow: -1,
SuppressIfgroup: -1,
SuppressPrefixlen: -1,
defer nc.Close() //nolint:errcheck

if err := nc.Rule.Add(&rtnetlink.RuleMessage{
Family: unix.AF_INET,
Table: m.TargetTable,
Action: unix.RTN_UNICAST,
Attributes: &rtnetlink.RuleAttributes{
FwMark: pointer.To(m.InternalMark),
FwMask: pointer.To(m.MarkMask),
Priority: pointer.To(nextRuleNumber(nc, unix.AF_INET)),
},
}); err != nil {
if !errors.Is(err, os.ErrExist) {
return fmt.Errorf("failed to add IPv4 table-mark rule: %w", err)
}
}

if err := nc.RuleAdd(&netlink.Rule{
Priority: nextRuleNumber(nc, unix.AF_INET6),
Family: unix.AF_INET6,
Table: m.TargetTable,
Mark: uint32(m.InternalMark),
Mask: pointer.To(uint32(m.MarkMask)),
Goto: -1,
Flow: -1,
SuppressIfgroup: -1,
SuppressPrefixlen: -1,
if err := nc.Rule.Add(&rtnetlink.RuleMessage{
Family: unix.AF_INET6,
Table: m.TargetTable,
Action: unix.RTN_UNICAST,
Attributes: &rtnetlink.RuleAttributes{
FwMark: pointer.To(m.InternalMark),
FwMask: pointer.To(m.MarkMask),
Priority: pointer.To(nextRuleNumber(nc, unix.AF_INET)),
},
}); err != nil {
if !errors.Is(err, os.ErrExist) {
return fmt.Errorf("failed to add IPv6 table-mark rule: %w", err)
Expand All @@ -82,20 +80,19 @@ func (m *rulesManager) Install() error {
return nil
}

func (m *rulesManager) deleteRulesFamily(nc *netlink.Handle, family int) error {
func (m *rulesManager) deleteRulesFamily(nc *rtnetlink.Conn, family uint8) error {
var merr *multierror.Error

list, err := nc.RuleList(family)
list, err := nc.Rule.List()
if err != nil {
merr = multierror.Append(merr, fmt.Errorf("failed to get route rules: %w", err))
}

for _, r := range list {
if r.Table == m.TargetTable &&
r.Mark == uint32(m.InternalMark) {
thisRule := r

if err := nc.RuleDel(&thisRule); err != nil {
if r.Family == family &&
r.Table == m.TargetTable &&
pointer.SafeDeref(r.Attributes.FwMark) == m.InternalMark {
if err := nc.Rule.Delete(&r); err != nil {
if !errors.Is(err, os.ErrNotExist) {
merr = multierror.Append(merr, err)
}
Expand All @@ -112,12 +109,12 @@ func (m *rulesManager) deleteRulesFamily(nc *netlink.Handle, family int) error {
func (m *rulesManager) Cleanup() error {
var merr *multierror.Error

nc, err := netlink.NewHandle()
nc, err := rtnetlink.Dial(nil)
if err != nil {
return fmt.Errorf("failed to get netlink handle: %w", err)
}

defer nc.Close()
defer nc.Close() //nolint:errcheck

if err = m.deleteRulesFamily(nc, unix.AF_INET); err != nil {
merr = multierror.Append(merr, fmt.Errorf("failed to delete all IPv4 route rules: %w", err))
Expand All @@ -130,17 +127,17 @@ func (m *rulesManager) Cleanup() error {
return merr.ErrorOrNil()
}

func nextRuleNumber(nc *netlink.Handle, family int) int {
list, err := nc.RuleList(family)
func nextRuleNumber(nc *rtnetlink.Conn, family uint8) uint32 {
list, err := nc.Rule.List()
if err != nil {
return 0
}

for i := 32500; i > 0; i-- {
for i := uint32(32500); i > 0; i-- {
var found bool

for _, r := range list {
if r.Priority == i {
if r.Family == family && pointer.SafeDeref(r.Attributes.Priority) == i {
found = true

break
Expand Down
127 changes: 100 additions & 27 deletions pkg/provision/providers/vm/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,25 @@ import (
"encoding/hex"
"errors"
"fmt"
"math"
"net"
"net/netip"
"os"
"strconv"
"strings"
"text/template"

"github.com/containernetworking/cni/libcni"
"github.com/containernetworking/plugins/pkg/testutils"
"github.com/coreos/go-iptables/iptables"
"github.com/florianl/go-tc"
"github.com/florianl/go-tc/core"
"github.com/google/uuid"
"github.com/jsimonetti/rtnetlink/v2"
"github.com/siderolabs/gen/xslices"
"github.com/siderolabs/go-pointer"
sideronet "github.com/siderolabs/net"
"github.com/vishvananda/netlink"
"golang.org/x/sys/unix"

"github.com/siderolabs/talos/pkg/provision"
)
Expand Down Expand Up @@ -197,13 +202,50 @@ func (p *Provisioner) dropBridgeTrafficRule(bridgeName string) error {
return nil
}

func getTicksInUsec() (float64, error) {
data, err := os.ReadFile("/proc/net/psched")
if err != nil {
return 0, err
}

parts := strings.Split(strings.TrimSpace(string(data)), " ")
if len(parts) < 3 {
return 0, errors.New("unexpected format")
}

var vals [3]uint64

for i := range vals {
vals[i], err = strconv.ParseUint(parts[i], 16, 32)
if err != nil {
return 0, err
}
}

// compatibility
if vals[2] == 1000000000 {
vals[0] = vals[1]
}

clockFactor := float64(vals[2]) / 1000000

return float64(vals[0]) / float64(vals[1]) * clockFactor, nil
}

//nolint:gocyclo
func (p *Provisioner) configureNetworkChaos(network provision.NetworkRequest, state *State, options provision.Options) error {
if (network.Bandwidth != 0) && (network.Latency != 0 || network.Jitter != 0 || network.PacketLoss != 0 || network.PacketReorder != 0 || network.PacketCorrupt != 0) {
return errors.New("bandwidth and other chaos options cannot be used together")
}

link, err := netlink.LinkByName(state.BridgeName)
tcnl, err := tc.Open(&tc.Config{})
if err != nil {
return fmt.Errorf("could not open tc: %v", err)
}

defer tcnl.Close() //nolint:errcheck

link, err := net.InterfaceByName(state.BridgeName)
if err != nil {
return fmt.Errorf("could not get link: %v", err)
}
Expand All @@ -213,24 +255,42 @@ func (p *Provisioner) configureNetworkChaos(network provision.NetworkRequest, st
if network.Bandwidth != 0 {
fmt.Fprintf(options.LogWriter, " bandwidth: %4d kbps\n", network.Bandwidth)

rate := network.Bandwidth * 1000 / 8
ticksInUsec, err := getTicksInUsec()
if err != nil {
return fmt.Errorf("could not get ticks in usec: %w", err)
}

buffer := rate / 10
rate := network.Bandwidth * 1000 / 8 // rate in kbps
latency := 0.2 // 200ms
burst := 50 * 1000 // 50kb

limit := buffer * 5
limit := uint32(float64(rate)*latency + float64(burst))
buffer := uint32(1000000.0 * float64(burst) / float64(rate) * ticksInUsec)

qdisc := &netlink.Tbf{
QdiscAttrs: netlink.QdiscAttrs{
LinkIndex: link.Attrs().Index,
Handle: netlink.MakeHandle(1, 0),
Parent: netlink.HANDLE_ROOT,
qdisc := tc.Object{
Msg: tc.Msg{
Family: unix.AF_UNSPEC,
Ifindex: uint32(link.Index),
Handle: core.BuildHandle(tc.HandleRoot, 0x0),
Parent: tc.HandleRoot,
Info: 0,
},
Attribute: tc.Attribute{
Kind: "tbf",
Tbf: &tc.Tbf{
Parms: &tc.TbfQopt{
Limit: limit,
Rate: tc.RateSpec{
Rate: uint32(rate),
Linklayer: 1,
},
Buffer: buffer,
},
},
},
Rate: uint64(rate),
Buffer: uint32(buffer),
Limit: uint32(limit),
}

if err := netlink.QdiscAdd(qdisc); err != nil {
if err := tcnl.Qdisc().Add(&qdisc); err != nil {
return fmt.Errorf("could not add netem qdisc: %v", err)
}
} else {
Expand All @@ -244,21 +304,34 @@ func (p *Provisioner) configureNetworkChaos(network provision.NetworkRequest, st
fmt.Fprintf(options.LogWriter, " packet reordering: %4v%%\n", packetReorder)
fmt.Fprintf(options.LogWriter, " packet corruption: %4v%%\n", packetCorrupt)

qdisc := netlink.NewNetem(
netlink.QdiscAttrs{
LinkIndex: link.Attrs().Index,
Handle: netlink.MakeHandle(1, 0),
Parent: netlink.HANDLE_ROOT,
qdisc := tc.Object{
Msg: tc.Msg{
Family: unix.AF_UNSPEC,
Ifindex: uint32(link.Index),
Handle: core.BuildHandle(tc.HandleRoot, 0x0),
Parent: tc.HandleRoot,
Info: 0,
},
netlink.NetemQdiscAttrs{
Jitter: uint32(network.Jitter / 1000),
Latency: uint32(network.Latency / 1000),
Loss: float32(packetLoss),
ReorderProb: float32(packetReorder),
CorruptProb: float32(packetCorrupt),
Attribute: tc.Attribute{
Kind: "netem",
Netem: &tc.Netem{
Jitter64: pointer.To(int64(network.Jitter)),
Latency64: pointer.To(int64(network.Latency)),
Qopt: tc.NetemQopt{
Limit: 1000,
Loss: uint32(packetLoss / 100 * math.MaxUint32),
},
Corrupt: &tc.NetemCorrupt{
Probability: uint32(packetCorrupt / 100 * math.MaxUint32),
},
Reorder: &tc.NetemReorder{
Probability: uint32(packetReorder / 100 * math.MaxUint32),
},
},
},
)
if err := netlink.QdiscAdd(qdisc); err != nil {
}

if err := tcnl.Qdisc().Add(&qdisc); err != nil {
return fmt.Errorf("could not add netem qdisc: %v", err)
}
}
Expand Down

0 comments on commit dc0c6ac

Please sign in to comment.