diff --git a/go.mod b/go.mod index ccbfcef..ec464b0 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ toolchain go1.23.2 require ( github.com/containernetworking/cni v1.2.3 - github.com/containernetworking/plugins v1.6.0 + github.com/containernetworking/plugins v1.6.1 github.com/onsi/ginkgo/v2 v2.22.1 github.com/onsi/gomega v1.36.1 github.com/vishvananda/netlink v1.3.0 @@ -18,11 +18,11 @@ require ( github.com/go-task/slim-sprig/v3 v3.0.0 // indirect github.com/google/go-cmp v0.6.0 // indirect github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad // indirect - github.com/safchain/ethtool v0.4.1 // indirect + github.com/safchain/ethtool v0.5.9 // indirect golang.org/x/net v0.32.0 // indirect golang.org/x/sys v0.28.0 // indirect golang.org/x/text v0.21.0 // indirect golang.org/x/tools v0.28.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - sigs.k8s.io/knftables v0.0.17 // indirect + sigs.k8s.io/knftables v0.0.18 // indirect ) diff --git a/go.sum b/go.sum index 2122dd3..df9a56c 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,7 @@ github.com/containernetworking/cni v1.2.3 h1:hhOcjNVUQTnzdRJ6alC5XF+wd9mfGIUaj8FuJbEslXM= github.com/containernetworking/cni v1.2.3/go.mod h1:DuLgF+aPd3DzcTQTtp/Nvl1Kim23oFKdm2okJzBQA5M= -github.com/containernetworking/plugins v1.6.0 h1:lrsUrLF7QODLx6gncHOqk/pnCiC7c6bvDAskV4KUifQ= -github.com/containernetworking/plugins v1.6.0/go.mod h1:rYLQWMJz/dYuW1XhHdc9xuzdkgbkWEEjwOhUm84+288= +github.com/containernetworking/plugins v1.6.1 h1:bYd2bpE6hEBqexyaiI2/sst0xJ+v7pEMWrjA5qtkxiU= +github.com/containernetworking/plugins v1.6.1/go.mod h1:SP5UG3jDO9LtmfbBJdP+nl3A1atOtbj2MBOYsnaxy64= github.com/coreos/go-iptables v0.8.0 h1:MPc2P89IhuVpLI7ETL/2tx3XZ61VeICZjYqDEgNsPRc= github.com/coreos/go-iptables v0.8.0/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -22,8 +22,8 @@ github.com/onsi/gomega v1.36.1 h1:bJDPBO7ibjxcbHMgSCoo4Yj18UWbKDlLwX1x9sybDcw= github.com/onsi/gomega v1.36.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/safchain/ethtool v0.4.1 h1:S6mEleTADqgynileXoiapt/nKnatyR6bmIHoF+h2ADo= -github.com/safchain/ethtool v0.4.1/go.mod h1:XLLnZmy4OCRTkksP/UiMjij96YmIsBfmBQcs7H6tA48= +github.com/safchain/ethtool v0.5.9 h1://6RvaOKFf3nQ0rl5+8zBbE4/72455VC9Jq61pfq67E= +github.com/safchain/ethtool v0.5.9/go.mod h1:w8oSsZeowyRaM7xJJBAbubzzrOkwO8TBgPSEqPP/5mg= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/vishvananda/netlink v1.3.0 h1:X7l42GfcV4S6E4vHTsw48qbrV+9PVojNfIhZcwQdrZk= @@ -35,7 +35,7 @@ golang.org/x/net v0.32.0 h1:ZqPmj8Kzc+Y6e0+skZsuACbx+wzMgo5MQsJh9Qd6aYI= golang.org/x/net v0.32.0/go.mod h1:CwU0IoeOlnQQWJ6ioyFrfRuomB8GKF6KbYXZVyeXNfs= 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.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= @@ -48,5 +48,5 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -sigs.k8s.io/knftables v0.0.17 h1:wGchTyRF/iGTIjd+vRaR1m676HM7jB8soFtyr/148ic= -sigs.k8s.io/knftables v0.0.17/go.mod h1:f/5ZLKYEUPUhVjUCg6l80ACdL7CIIyeL0DxfgojGRTk= +sigs.k8s.io/knftables v0.0.18 h1:6Duvmu0s/HwGifKrtl6G3AyAPYlWiZqTgS8bkVMiyaE= +sigs.k8s.io/knftables v0.0.18/go.mod h1:f/5ZLKYEUPUhVjUCg6l80ACdL7CIIyeL0DxfgojGRTk= diff --git a/vendor/github.com/containernetworking/plugins/pkg/ip/ipmasq_iptables_linux.go b/vendor/github.com/containernetworking/plugins/pkg/ip/ipmasq_iptables_linux.go index 5c1fcfa..080d4fd 100644 --- a/vendor/github.com/containernetworking/plugins/pkg/ip/ipmasq_iptables_linux.go +++ b/vendor/github.com/containernetworking/plugins/pkg/ip/ipmasq_iptables_linux.go @@ -15,8 +15,10 @@ package ip import ( + "errors" "fmt" "net" + "strings" "github.com/coreos/go-iptables/iptables" @@ -24,17 +26,22 @@ import ( "github.com/containernetworking/plugins/pkg/utils" ) -// setupIPMasqIPTables is the iptables-based implementation of SetupIPMasqForNetwork -func setupIPMasqIPTables(ipn *net.IPNet, network, _, containerID string) error { +// setupIPMasqIPTables is the iptables-based implementation of SetupIPMasqForNetworks +func setupIPMasqIPTables(ipns []*net.IPNet, network, _, containerID string) error { // Note: for historical reasons, the iptables implementation ignores ifname. chain := utils.FormatChainName(network, containerID) comment := utils.FormatComment(network, containerID) - return SetupIPMasq(ipn, chain, comment) + for _, ip := range ipns { + if err := SetupIPMasq(ip, chain, comment); err != nil { + return err + } + } + return nil } // SetupIPMasq installs iptables rules to masquerade traffic // coming from ip of ipn and going outside of ipn. -// Deprecated: This function only supports iptables. Use SetupIPMasqForNetwork, which +// Deprecated: This function only supports iptables. Use SetupIPMasqForNetworks, which // supports both iptables and nftables. func SetupIPMasq(ipn *net.IPNet, chain string, comment string) error { isV6 := ipn.IP.To4() == nil @@ -87,16 +94,28 @@ func SetupIPMasq(ipn *net.IPNet, chain string, comment string) error { return ipt.AppendUnique("nat", "POSTROUTING", "-s", ipn.IP.String(), "-j", chain, "-m", "comment", "--comment", comment) } -// teardownIPMasqIPTables is the iptables-based implementation of TeardownIPMasqForNetwork -func teardownIPMasqIPTables(ipn *net.IPNet, network, _, containerID string) error { +// teardownIPMasqIPTables is the iptables-based implementation of TeardownIPMasqForNetworks +func teardownIPMasqIPTables(ipns []*net.IPNet, network, _, containerID string) error { // Note: for historical reasons, the iptables implementation ignores ifname. chain := utils.FormatChainName(network, containerID) comment := utils.FormatComment(network, containerID) - return TeardownIPMasq(ipn, chain, comment) + + var errs []string + for _, ipn := range ipns { + err := TeardownIPMasq(ipn, chain, comment) + if err != nil { + errs = append(errs, err.Error()) + } + } + + if errs == nil { + return nil + } + return errors.New(strings.Join(errs, "\n")) } // TeardownIPMasq undoes the effects of SetupIPMasq. -// Deprecated: This function only supports iptables. Use TeardownIPMasqForNetwork, which +// Deprecated: This function only supports iptables. Use TeardownIPMasqForNetworks, which // supports both iptables and nftables. func TeardownIPMasq(ipn *net.IPNet, chain string, comment string) error { isV6 := ipn.IP.To4() == nil diff --git a/vendor/github.com/containernetworking/plugins/pkg/ip/ipmasq_linux.go b/vendor/github.com/containernetworking/plugins/pkg/ip/ipmasq_linux.go index bad8354..0063e0a 100644 --- a/vendor/github.com/containernetworking/plugins/pkg/ip/ipmasq_linux.go +++ b/vendor/github.com/containernetworking/plugins/pkg/ip/ipmasq_linux.go @@ -24,11 +24,11 @@ import ( "github.com/containernetworking/plugins/pkg/utils" ) -// SetupIPMasqForNetwork installs rules to masquerade traffic coming from ip of ipn and -// going outside of ipn, using a chain name based on network, ifname, and containerID. The +// SetupIPMasqForNetworks installs rules to masquerade traffic coming from ips of ipns and +// going outside of ipns, using a chain name based on network, ifname, and containerID. The // backend can be either "iptables" or "nftables"; if it is nil, then a suitable default // implementation will be used. -func SetupIPMasqForNetwork(backend *string, ipn *net.IPNet, network, ifname, containerID string) error { +func SetupIPMasqForNetworks(backend *string, ipns []*net.IPNet, network, ifname, containerID string) error { if backend == nil { // Prefer iptables, unless only nftables is available defaultBackend := "iptables" @@ -40,27 +40,27 @@ func SetupIPMasqForNetwork(backend *string, ipn *net.IPNet, network, ifname, con switch *backend { case "iptables": - return setupIPMasqIPTables(ipn, network, ifname, containerID) + return setupIPMasqIPTables(ipns, network, ifname, containerID) case "nftables": - return setupIPMasqNFTables(ipn, network, ifname, containerID) + return setupIPMasqNFTables(ipns, network, ifname, containerID) default: return fmt.Errorf("unknown ipmasq backend %q", *backend) } } -// TeardownIPMasqForNetwork undoes the effects of SetupIPMasqForNetwork -func TeardownIPMasqForNetwork(ipn *net.IPNet, network, ifname, containerID string) error { +// TeardownIPMasqForNetworks undoes the effects of SetupIPMasqForNetworks +func TeardownIPMasqForNetworks(ipns []*net.IPNet, network, ifname, containerID string) error { var errs []string // Do both the iptables and the nftables cleanup, since the pod may have been // created with a different version of this plugin or a different configuration. - err := teardownIPMasqIPTables(ipn, network, ifname, containerID) + err := teardownIPMasqIPTables(ipns, network, ifname, containerID) if err != nil && utils.SupportsIPTables() { errs = append(errs, err.Error()) } - err = teardownIPMasqNFTables(ipn, network, ifname, containerID) + err = teardownIPMasqNFTables(ipns, network, ifname, containerID) if err != nil && utils.SupportsNFTables() { errs = append(errs, err.Error()) } diff --git a/vendor/github.com/containernetworking/plugins/pkg/ip/ipmasq_nftables_linux.go b/vendor/github.com/containernetworking/plugins/pkg/ip/ipmasq_nftables_linux.go index 5c7458c..fd0545e 100644 --- a/vendor/github.com/containernetworking/plugins/pkg/ip/ipmasq_nftables_linux.go +++ b/vendor/github.com/containernetworking/plugins/pkg/ip/ipmasq_nftables_linux.go @@ -72,16 +72,16 @@ func commentForInstance(network, ifname, containerID string) string { return comment } -// setupIPMasqNFTables is the nftables-based implementation of SetupIPMasqForNetwork -func setupIPMasqNFTables(ipn *net.IPNet, network, ifname, containerID string) error { +// setupIPMasqNFTables is the nftables-based implementation of SetupIPMasqForNetworks +func setupIPMasqNFTables(ipns []*net.IPNet, network, ifname, containerID string) error { nft, err := knftables.New(knftables.InetFamily, ipMasqTableName) if err != nil { return err } - return setupIPMasqNFTablesWithInterface(nft, ipn, network, ifname, containerID) + return setupIPMasqNFTablesWithInterface(nft, ipns, network, ifname, containerID) } -func setupIPMasqNFTablesWithInterface(nft knftables.Interface, ipn *net.IPNet, network, ifname, containerID string) error { +func setupIPMasqNFTablesWithInterface(nft knftables.Interface, ipns []*net.IPNet, network, ifname, containerID string) error { staleRules, err := findRules(nft, hashForInstance(network, ifname, containerID)) if err != nil { return err @@ -128,37 +128,39 @@ func setupIPMasqNFTablesWithInterface(nft knftables.Interface, ipn *net.IPNet, n for _, rule := range staleRules { tx.Delete(rule) } - ip := "ip" - if ipn.IP.To4() == nil { - ip = "ip6" - } - - // e.g. if ipn is "192.168.1.4/24", then dstNet is "192.168.1.0/24" - dstNet := &net.IPNet{IP: ipn.IP.Mask(ipn.Mask), Mask: ipn.Mask} + for _, ipn := range ipns { + ip := "ip" + if ipn.IP.To4() == nil { + ip = "ip6" + } - tx.Add(&knftables.Rule{ - Chain: ipMasqChainName, - Rule: knftables.Concat( - ip, "saddr", "==", ipn.IP, - ip, "daddr", "!=", dstNet, - "masquerade", - ), - Comment: knftables.PtrTo(commentForInstance(network, ifname, containerID)), - }) + // e.g. if ipn is "192.168.1.4/24", then dstNet is "192.168.1.0/24" + dstNet := &net.IPNet{IP: ipn.IP.Mask(ipn.Mask), Mask: ipn.Mask} + + tx.Add(&knftables.Rule{ + Chain: ipMasqChainName, + Rule: knftables.Concat( + ip, "saddr", "==", ipn.IP, + ip, "daddr", "!=", dstNet, + "masquerade", + ), + Comment: knftables.PtrTo(commentForInstance(network, ifname, containerID)), + }) + } return nft.Run(context.TODO(), tx) } -// teardownIPMasqNFTables is the nftables-based implementation of TeardownIPMasqForNetwork -func teardownIPMasqNFTables(ipn *net.IPNet, network, ifname, containerID string) error { +// teardownIPMasqNFTables is the nftables-based implementation of TeardownIPMasqForNetworks +func teardownIPMasqNFTables(ipns []*net.IPNet, network, ifname, containerID string) error { nft, err := knftables.New(knftables.InetFamily, ipMasqTableName) if err != nil { return err } - return teardownIPMasqNFTablesWithInterface(nft, ipn, network, ifname, containerID) + return teardownIPMasqNFTablesWithInterface(nft, ipns, network, ifname, containerID) } -func teardownIPMasqNFTablesWithInterface(nft knftables.Interface, _ *net.IPNet, network, ifname, containerID string) error { +func teardownIPMasqNFTablesWithInterface(nft knftables.Interface, _ []*net.IPNet, network, ifname, containerID string) error { rules, err := findRules(nft, hashForInstance(network, ifname, containerID)) if err != nil { return err diff --git a/vendor/github.com/safchain/ethtool/.golangci.yml b/vendor/github.com/safchain/ethtool/.golangci.yml index 77ccf92..65552c9 100644 --- a/vendor/github.com/safchain/ethtool/.golangci.yml +++ b/vendor/github.com/safchain/ethtool/.golangci.yml @@ -1,11 +1,15 @@ linters: - disable: - - gosimple - - unused enable: + - gosimple - gci - gofmt - misspell + - goimports + - staticcheck + - errcheck + - govet + - misspell + - gocritic linters-settings: gci: sections: diff --git a/vendor/github.com/safchain/ethtool/ethtool.go b/vendor/github.com/safchain/ethtool/ethtool.go index f309c50..62df2c1 100644 --- a/vendor/github.com/safchain/ethtool/ethtool.go +++ b/vendor/github.com/safchain/ethtool/ethtool.go @@ -55,12 +55,14 @@ const ( // CMD supported ETHTOOL_GSET = 0x00000001 /* Get settings. */ ETHTOOL_SSET = 0x00000002 /* Set settings. */ + ETHTOOL_GWOL = 0x00000005 /* Get wake-on-lan options. */ + ETHTOOL_SWOL = 0x00000006 /* Set wake-on-lan options. */ ETHTOOL_GDRVINFO = 0x00000003 /* Get driver info. */ ETHTOOL_GMSGLVL = 0x00000007 /* Get driver message level */ ETHTOOL_SMSGLVL = 0x00000008 /* Set driver msg level. */ - /* Get link status for host, i.e. whether the interface *and* the - * physical port (if there is one) are up (ethtool_value). */ + // Get link status for host, i.e. whether the interface *and* the + // physical port (if there is one) are up (ethtool_value). ETHTOOL_GLINK = 0x0000000a ETHTOOL_GCOALESCE = 0x0000000e /* Get coalesce config */ ETHTOOL_SCOALESCE = 0x0000000f /* Set coalesce config */ @@ -207,23 +209,55 @@ type Coalesce struct { RateSampleInterval uint32 } +// WoL options const ( - SOF_TIMESTAMPING_TX_HARDWARE = (1 << 0) - SOF_TIMESTAMPING_TX_SOFTWARE = (1 << 1) - SOF_TIMESTAMPING_RX_HARDWARE = (1 << 2) - SOF_TIMESTAMPING_RX_SOFTWARE = (1 << 3) - SOF_TIMESTAMPING_SOFTWARE = (1 << 4) - SOF_TIMESTAMPING_SYS_HARDWARE = (1 << 5) - SOF_TIMESTAMPING_RAW_HARDWARE = (1 << 6) - SOF_TIMESTAMPING_OPT_ID = (1 << 7) - SOF_TIMESTAMPING_TX_SCHED = (1 << 8) - SOF_TIMESTAMPING_TX_ACK = (1 << 9) - SOF_TIMESTAMPING_OPT_CMSG = (1 << 10) - SOF_TIMESTAMPING_OPT_TSONLY = (1 << 11) - SOF_TIMESTAMPING_OPT_STATS = (1 << 12) - SOF_TIMESTAMPING_OPT_PKTINFO = (1 << 13) - SOF_TIMESTAMPING_OPT_TX_SWHW = (1 << 14) - SOF_TIMESTAMPING_BIND_PHC = (1 << 15) + WAKE_PHY = 1 << 0 + WAKE_UCAST = 1 << 1 + WAKE_MCAST = 1 << 2 + WAKE_BCAST = 1 << 3 + WAKE_ARP = 1 << 4 + WAKE_MAGIC = 1 << 5 + WAKE_MAGICSECURE = 1 << 6 // only meaningful if WAKE_MAGIC +) + +var WoLMap = map[uint32]string{ + WAKE_PHY: "p", // Wake on PHY activity + WAKE_UCAST: "u", // Wake on unicast messages + WAKE_MCAST: "m", // Wake on multicast messages + WAKE_BCAST: "b", // Wake on broadcast messages + WAKE_ARP: "a", // Wake on ARP + WAKE_MAGIC: "g", // Wake on MagicPacket™ + WAKE_MAGICSECURE: "s", // Enable SecureOn™ password for MagicPacket™ + // f Wake on filter(s) + // d Disable (wake on nothing). This option clears all previous options. +} + +// WakeOnLan contains WoL config for an interface +type WakeOnLan struct { + Cmd uint32 // ETHTOOL_GWOL or ETHTOOL_SWOL + Supported uint32 // r/o bitmask of WAKE_* flags for supported WoL modes + Opts uint32 // Bitmask of WAKE_* flags for enabled WoL modes +} + +// Timestamping options +// see: https://www.kernel.org/doc/Documentation/networking/timestamping.txt +const ( + SOF_TIMESTAMPING_TX_HARDWARE = (1 << 0) /* Request tx timestamps generated by the network adapter. */ + SOF_TIMESTAMPING_TX_SOFTWARE = (1 << 1) /* Request tx timestamps when data leaves the kernel. */ + SOF_TIMESTAMPING_RX_HARDWARE = (1 << 2) /* Request rx timestamps generated by the network adapter. */ + SOF_TIMESTAMPING_RX_SOFTWARE = (1 << 3) /* Request rx timestamps when data enters the kernel. */ + SOF_TIMESTAMPING_SOFTWARE = (1 << 4) /* Report any software timestamps when available. */ + SOF_TIMESTAMPING_SYS_HARDWARE = (1 << 5) /* This option is deprecated and ignored. */ + SOF_TIMESTAMPING_RAW_HARDWARE = (1 << 6) /* Report hardware timestamps. */ + SOF_TIMESTAMPING_OPT_ID = (1 << 7) /* Generate a unique identifier along with each packet. */ + SOF_TIMESTAMPING_TX_SCHED = (1 << 8) /* Request tx timestamps prior to entering the packet scheduler. */ + SOF_TIMESTAMPING_TX_ACK = (1 << 9) /* Request tx timestamps when all data in the send buffer has been acknowledged. */ + SOF_TIMESTAMPING_OPT_CMSG = (1 << 10) /* Support recv() cmsg for all timestamped packets. */ + SOF_TIMESTAMPING_OPT_TSONLY = (1 << 11) /* Applies to transmit timestamps only. */ + SOF_TIMESTAMPING_OPT_STATS = (1 << 12) /* Optional stats that are obtained along with the transmit timestamps. */ + SOF_TIMESTAMPING_OPT_PKTINFO = (1 << 13) /* Enable the SCM_TIMESTAMPING_PKTINFO control message for incoming packets with hardware timestamps. */ + SOF_TIMESTAMPING_OPT_TX_SWHW = (1 << 14) /* Request both hardware and software timestamps for outgoing packets when SOF_TIMESTAMPING_TX_HARDWARE and SOF_TIMESTAMPING_TX_SOFTWARE are enabled at the same time. */ + SOF_TIMESTAMPING_BIND_PHC = (1 << 15) /* Bind the socket to a specific PTP Hardware Clock. */ ) const ( @@ -279,6 +313,7 @@ const ( HWTSTAMP_FILTER_NTP_ALL /* NTP, UDP, all versions and packet modes */ ) +// TimestampingInformation contains PTP timetstapming information type TimestampingInformation struct { Cmd uint32 SoTimestamping uint32 /* SOF_TIMESTAMPING_* bitmask */ @@ -349,6 +384,7 @@ type Pause struct { TxPause uint32 } +// Ethtool is a struct that contains the file descriptor for the ethtool type Ethtool struct { fd int } @@ -357,7 +393,7 @@ type Ethtool struct { func goString(s []byte) string { strEnd := bytes.IndexByte(s, 0) if strEnd == -1 { - return string(s[:]) + return string(s) } return string(s[:strEnd]) } @@ -496,6 +532,31 @@ func (e *Ethtool) PermAddr(intf string) (string, error) { ), nil } +// GetWakeOnLan returns the WoL config for the given interface name. +func (e *Ethtool) GetWakeOnLan(intf string) (WakeOnLan, error) { + wol := WakeOnLan{ + Cmd: ETHTOOL_GWOL, + } + + if err := e.ioctl(intf, uintptr(unsafe.Pointer(&wol))); err != nil { + return WakeOnLan{}, err + } + + return wol, nil +} + +// SetWakeOnLan sets the WoL config for the given interface name and +// returns the new WoL config. +func (e *Ethtool) SetWakeOnLan(intf string, wol WakeOnLan) (WakeOnLan, error) { + wol.Cmd = ETHTOOL_SWOL + + if err := e.ioctl(intf, uintptr(unsafe.Pointer(&wol))); err != nil { + return WakeOnLan{}, err + } + + return wol, nil +} + func (e *Ethtool) ioctl(intf string, data uintptr) error { var name [IFNAMSIZ]byte copy(name[:], []byte(intf)) @@ -672,6 +733,7 @@ func isFeatureBitSet(blocks [MAX_FEATURE_BLOCKS]ethtoolGetFeaturesBlock, index u return (blocks)[index/32].active&(1<<(index%32)) != 0 } +// FeatureState contains the state of a feature. type FeatureState struct { Available bool Requested bool @@ -893,7 +955,7 @@ func (e *Ethtool) UpdatePrivFlags(intf string, config map[string]bool) error { return e.ioctl(intf, uintptr(unsafe.Pointer(&update))) } -// Get state of a link. +// LinkState get the state of a link. func (e *Ethtool) LinkState(intf string) (uint32, error) { x := ethtoolLink{ cmd: ETHTOOL_GLINK, @@ -964,7 +1026,7 @@ func (e *Ethtool) Close() { // NewEthtool returns a new ethtool handler func NewEthtool() (*Ethtool, error) { - fd, err := unix.Socket(unix.AF_INET, unix.SOCK_DGRAM, unix.IPPROTO_IP) + fd, err := unix.Socket(unix.AF_INET, unix.SOCK_DGRAM|unix.SOCK_CLOEXEC, unix.IPPROTO_IP) if err != nil { return nil, err } diff --git a/vendor/github.com/safchain/ethtool/ethtool_cmd.go b/vendor/github.com/safchain/ethtool/ethtool_cmd.go index e94d6dd..09499fe 100644 --- a/vendor/github.com/safchain/ethtool/ethtool_cmd.go +++ b/vendor/github.com/safchain/ethtool/ethtool_cmd.go @@ -33,7 +33,9 @@ import ( "golang.org/x/sys/unix" ) -type EthtoolCmd struct { /* ethtool.c: struct ethtool_cmd */ +// EthtoolCmd is the Go version of the Linux kerne ethtool_cmd struct +// see ethtool.c +type EthtoolCmd struct { Cmd uint32 Supported uint32 Advertising uint32 @@ -102,10 +104,6 @@ func (f *EthtoolCmd) reflect(retv *map[string]uint64) { default: (*retv)[typeField.Name+"_unknown_type"] = 0 } - - // tag := typeField.Tag - // fmt.Printf("Field Name: %s,\t Field Value: %v,\t Tag Value: %s\n", - // typeField.Name, valueField.Interface(), tag.Get("tag_name")) } } @@ -198,6 +196,7 @@ func (e *Ethtool) CmdGetMapped(intf string) (map[string]uint64, error) { return result, nil } +// CmdGetMapped returns the interface settings in a map func CmdGetMapped(intf string) (map[string]uint64, error) { e, err := NewEthtool() if err != nil { diff --git a/vendor/modules.txt b/vendor/modules.txt index 879c4ca..e7133f6 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -11,7 +11,7 @@ github.com/containernetworking/cni/pkg/types/create github.com/containernetworking/cni/pkg/types/internal github.com/containernetworking/cni/pkg/utils github.com/containernetworking/cni/pkg/version -# github.com/containernetworking/plugins v1.6.0 +# github.com/containernetworking/plugins v1.6.1 ## explicit; go 1.23 github.com/containernetworking/plugins/pkg/ip github.com/containernetworking/plugins/pkg/ipam @@ -74,7 +74,7 @@ github.com/onsi/gomega/matchers/support/goraph/edge github.com/onsi/gomega/matchers/support/goraph/node github.com/onsi/gomega/matchers/support/goraph/util github.com/onsi/gomega/types -# github.com/safchain/ethtool v0.4.1 +# github.com/safchain/ethtool v0.5.9 ## explicit; go 1.16 github.com/safchain/ethtool # github.com/vishvananda/netlink v1.3.0 @@ -118,6 +118,6 @@ golang.org/x/tools/go/ast/inspector # gopkg.in/yaml.v3 v3.0.1 ## explicit gopkg.in/yaml.v3 -# sigs.k8s.io/knftables v0.0.17 +# sigs.k8s.io/knftables v0.0.18 ## explicit; go 1.20 sigs.k8s.io/knftables diff --git a/vendor/sigs.k8s.io/knftables/CHANGELOG.md b/vendor/sigs.k8s.io/knftables/CHANGELOG.md index 4f1dc3a..e16d197 100644 --- a/vendor/sigs.k8s.io/knftables/CHANGELOG.md +++ b/vendor/sigs.k8s.io/knftables/CHANGELOG.md @@ -1,5 +1,16 @@ # ChangeLog +## v0.0.18 + +- Added locking to `Fake` to allow it to be safely used concurrently. + (`@npinaeva`) + +- Added a `Flowtable` object, and `Fake` support for correctly parsing + flowtable references. (`@aojea`) + +- Fixed a bug in `Fake.ParseDump`, which accidentally required the + table to have a comment. (`@danwinship`) + ## v0.0.17 - `ListRules()` now accepts `""` for the chain name, meaning to list diff --git a/vendor/sigs.k8s.io/knftables/README.md b/vendor/sigs.k8s.io/knftables/README.md index 794b15b..0cb6313 100644 --- a/vendor/sigs.k8s.io/knftables/README.md +++ b/vendor/sigs.k8s.io/knftables/README.md @@ -134,6 +134,7 @@ The `Transaction` methods take arguments of type `knftables.Object`. The currently-supported objects are: - `Table` +- `Flowtable` - `Chain` - `Rule` - `Set` diff --git a/vendor/sigs.k8s.io/knftables/fake.go b/vendor/sigs.k8s.io/knftables/fake.go index 584c27a..6f209f9 100644 --- a/vendor/sigs.k8s.io/knftables/fake.go +++ b/vendor/sigs.k8s.io/knftables/fake.go @@ -23,20 +23,27 @@ import ( "regexp" "sort" "strings" + "sync" ) // Fake is a fake implementation of Interface type Fake struct { nftContext + // mutex is used to protect Table and LastTransaction. + // When Table and LastTransaction are accessed directly, the caller must acquire Fake.RLock + // and release when finished. + sync.RWMutex nextHandle int // Table contains the Interface's table. This will be `nil` until you `tx.Add()` // the table. + // Make sure to acquire Fake.RLock before accessing Table in a concurrent environment. Table *FakeTable // LastTransaction is the last transaction passed to Run(). It will remain set until the // next time Run() is called. (It is not affected by Check().) + // Make sure to acquire Fake.RLock before accessing LastTransaction in a concurrent environment. LastTransaction *Transaction } @@ -44,6 +51,9 @@ type Fake struct { type FakeTable struct { Table + // Flowtables contains the table's flowtables, keyed by name + Flowtables map[string]*FakeFlowtable + // Chains contains the table's chains, keyed by name Chains map[string]*FakeChain @@ -54,6 +64,11 @@ type FakeTable struct { Maps map[string]*FakeMap } +// FakeFlowtable wraps Flowtable for the Fake implementation +type FakeFlowtable struct { + Flowtable +} + // FakeChain wraps Chain for the Fake implementation type FakeChain struct { Chain @@ -94,6 +109,8 @@ var _ Interface = &Fake{} // List is part of Interface. func (fake *Fake) List(_ context.Context, objectType string) ([]string, error) { + fake.RLock() + defer fake.RUnlock() if fake.Table == nil { return nil, notFoundError("no such table %q", fake.table) } @@ -101,6 +118,10 @@ func (fake *Fake) List(_ context.Context, objectType string) ([]string, error) { var result []string switch objectType { + case "flowtable", "flowtables": + for name := range fake.Table.Flowtables { + result = append(result, name) + } case "chain", "chains": for name := range fake.Table.Chains { result = append(result, name) @@ -123,6 +144,8 @@ func (fake *Fake) List(_ context.Context, objectType string) ([]string, error) { // ListRules is part of Interface func (fake *Fake) ListRules(_ context.Context, chain string) ([]*Rule, error) { + fake.RLock() + defer fake.RUnlock() if fake.Table == nil { return nil, notFoundError("no such table %q", fake.table) } @@ -145,6 +168,8 @@ func (fake *Fake) ListRules(_ context.Context, chain string) ([]*Rule, error) { // ListElements is part of Interface func (fake *Fake) ListElements(_ context.Context, objectType, name string) ([]*Element, error) { + fake.RLock() + defer fake.RUnlock() if fake.Table == nil { return nil, notFoundError("no such %s %q", objectType, name) } @@ -169,6 +194,8 @@ func (fake *Fake) NewTransaction() *Transaction { // Run is part of Interface func (fake *Fake) Run(_ context.Context, tx *Transaction) error { + fake.Lock() + defer fake.Unlock() fake.LastTransaction = tx updatedTable, err := fake.run(tx) if err == nil { @@ -179,10 +206,13 @@ func (fake *Fake) Run(_ context.Context, tx *Transaction) error { // Check is part of Interface func (fake *Fake) Check(_ context.Context, tx *Transaction) error { + fake.RLock() + defer fake.RUnlock() _, err := fake.run(tx) return err } +// must be called with fake.lock held func (fake *Fake) run(tx *Transaction) (*FakeTable, error) { if tx.err != nil { return nil, tx.err @@ -218,10 +248,11 @@ func (fake *Fake) run(tx *Transaction) (*FakeTable, error) { table := *obj table.Handle = PtrTo(fake.nextHandle) updatedTable = &FakeTable{ - Table: table, - Chains: make(map[string]*FakeChain), - Sets: make(map[string]*FakeSet), - Maps: make(map[string]*FakeMap), + Table: table, + Flowtables: make(map[string]*FakeFlowtable), + Chains: make(map[string]*FakeChain), + Sets: make(map[string]*FakeSet), + Maps: make(map[string]*FakeMap), } case deleteVerb: updatedTable = nil @@ -229,6 +260,29 @@ func (fake *Fake) run(tx *Transaction) (*FakeTable, error) { return nil, fmt.Errorf("unhandled operation %q", op.verb) } + case *Flowtable: + existingFlowtable := updatedTable.Flowtables[obj.Name] + err := checkExists(op.verb, "flowtable", obj.Name, existingFlowtable != nil) + if err != nil { + return nil, err + } + switch op.verb { + case addVerb, createVerb: + if existingFlowtable != nil { + continue + } + flowtable := *obj + flowtable.Handle = PtrTo(fake.nextHandle) + updatedTable.Flowtables[obj.Name] = &FakeFlowtable{ + Flowtable: flowtable, + } + case deleteVerb: + // FIXME delete-by-handle + delete(updatedTable.Flowtables, obj.Name) + default: + return nil, fmt.Errorf("unhandled operation %q", op.verb) + } + case *Chain: existingChain := updatedTable.Chains[obj.Name] err := checkExists(op.verb, "chain", obj.Name, existingChain != nil) @@ -443,10 +497,14 @@ func checkRuleRefs(rule *Rule, table *FakeTable) error { for i, word := range words { if strings.HasPrefix(word, "@") { name := word[1:] - if i > 0 && (words[i] == "map" || words[i] == "vmap") { + if i > 0 && (words[i-1] == "map" || words[i-1] == "vmap") { if table.Maps[name] == nil { return notFoundError("no such map %q", name) } + } else if i > 0 && words[i-1] == "offload" { + if table.Flowtables[name] == nil { + return notFoundError("no such flowtable %q", name) + } } else { // recent nft lets you use a map in a set lookup if table.Sets[name] == nil && table.Maps[name] == nil { @@ -480,6 +538,8 @@ func checkElementRefs(element *Element, table *FakeTable) error { // Dump dumps the current contents of fake, in a way that looks like an nft transaction. func (fake *Fake) Dump() string { + fake.RLock() + defer fake.RUnlock() if fake.Table == nil { return "" } @@ -487,6 +547,7 @@ func (fake *Fake) Dump() string { buf := &strings.Builder{} table := fake.Table + flowtables := sortKeys(table.Flowtables) chains := sortKeys(table.Chains) sets := sortKeys(table.Sets) maps := sortKeys(table.Maps) @@ -494,6 +555,10 @@ func (fake *Fake) Dump() string { // Write out all of the object adds first. table.writeOperation(addVerb, &fake.nftContext, buf) + for _, fname := range flowtables { + ft := table.Flowtables[fname] + ft.writeOperation(addVerb, &fake.nftContext, buf) + } for _, cname := range chains { ch := table.Chains[cname] ch.writeOperation(addVerb, &fake.nftContext, buf) @@ -550,7 +615,7 @@ func (fake *Fake) ParseDump(data string) (err error) { } }() tx := fake.NewTransaction() - commonRegexp := regexp.MustCompile(fmt.Sprintf(`add %s %s %s (.*)`, noSpaceGroup, fake.family, fake.table)) + commonRegexp := regexp.MustCompile(fmt.Sprintf(`add ([^ ]*) %s %s( (.*))?`, fake.family, fake.table)) for i, line = range lines { line = strings.TrimSpace(line) @@ -565,6 +630,8 @@ func (fake *Fake) ParseDump(data string) (err error) { switch match[1] { case "table": obj = &Table{} + case "flowtable": + obj = &Flowtable{} case "chain": obj = &Chain{} case "rule": @@ -578,7 +645,7 @@ func (fake *Fake) ParseDump(data string) (err error) { default: return fmt.Errorf("unknown object %s", match[1]) } - err = obj.parse(match[2]) + err = obj.parse(match[3]) if err != nil { return err } @@ -623,10 +690,16 @@ func (table *FakeTable) copy() *FakeTable { } tcopy := &FakeTable{ - Table: table.Table, - Chains: make(map[string]*FakeChain), - Sets: make(map[string]*FakeSet), - Maps: make(map[string]*FakeMap), + Table: table.Table, + Flowtables: make(map[string]*FakeFlowtable), + Chains: make(map[string]*FakeChain), + Sets: make(map[string]*FakeSet), + Maps: make(map[string]*FakeMap), + } + for name, flowtable := range table.Flowtables { + tcopy.Flowtables[name] = &FakeFlowtable{ + Flowtable: flowtable.Flowtable, + } } for name, chain := range table.Chains { tcopy.Chains[name] = &FakeChain{ diff --git a/vendor/sigs.k8s.io/knftables/objects.go b/vendor/sigs.k8s.io/knftables/objects.go index 6a62879..ed11db2 100644 --- a/vendor/sigs.k8s.io/knftables/objects.go +++ b/vendor/sigs.k8s.io/knftables/objects.go @@ -579,3 +579,80 @@ func (element *Element) parse(line string) error { } return nil } + +// Object implementation for Flowtable +func (flowtable *Flowtable) validate(verb verb) error { + switch verb { + case addVerb, createVerb: + if flowtable.Name == "" { + return fmt.Errorf("no name specified for flowtable") + } + if flowtable.Handle != nil { + return fmt.Errorf("cannot specify Handle in %s operation", verb) + } + case deleteVerb: + if flowtable.Name == "" && flowtable.Handle == nil { + return fmt.Errorf("must specify either name or handle") + } + default: + return fmt.Errorf("%s is not implemented for flowtables", verb) + } + + return nil +} + +func (flowtable *Flowtable) writeOperation(verb verb, ctx *nftContext, writer io.Writer) { + // Special case for delete-by-handle + if verb == deleteVerb && flowtable.Handle != nil { + fmt.Fprintf(writer, "delete flowtable %s %s handle %d", ctx.family, ctx.table, *flowtable.Handle) + return + } + + fmt.Fprintf(writer, "%s flowtable %s %s %s", verb, ctx.family, ctx.table, flowtable.Name) + if verb == addVerb || verb == createVerb { + fmt.Fprintf(writer, " {") + + if flowtable.Priority != nil { + // since there is only one priority value allowed "filter" just use the value + // provided and not try to parse it. + fmt.Fprintf(writer, " hook ingress priority %s ;", *flowtable.Priority) + } + + if len(flowtable.Devices) > 0 { + fmt.Fprintf(writer, " devices = { %s } ;", strings.Join(flowtable.Devices, ", ")) + } + + fmt.Fprintf(writer, " }") + } + + fmt.Fprintf(writer, "\n") +} + +// nft add flowtable inet example_table example_flowtable { hook ingress priority filter ; devices = { eth0 }; } +var flowtableRegexp = regexp.MustCompile(fmt.Sprintf( + `%s(?: {(?: hook ingress priority %s ;)(?: devices = {(.*)} ;) })?`, + noSpaceGroup, noSpaceGroup)) + +func (flowtable *Flowtable) parse(line string) error { + match := flowtableRegexp.FindStringSubmatch(line) + if match == nil { + return fmt.Errorf("failed parsing flowtableRegexp add command") + } + flowtable.Name = match[1] + if match[2] != "" { + flowtable.Priority = (*FlowtableIngressPriority)(&match[2]) + } + // to avoid complex regular expressions the regex match everything between the brackets + // to match a single interface or a comma separated list of interfaces, and it is postprocessed + // here to remove the whitespaces. + if match[3] != "" { + devices := strings.Split(strings.TrimSpace(match[3]), ",") + for i := range devices { + devices[i] = strings.TrimSpace(devices[i]) + } + if len(devices) > 0 { + flowtable.Devices = devices + } + } + return nil +} diff --git a/vendor/sigs.k8s.io/knftables/types.go b/vendor/sigs.k8s.io/knftables/types.go index d8202bc..1d0da2c 100644 --- a/vendor/sigs.k8s.io/knftables/types.go +++ b/vendor/sigs.k8s.io/knftables/types.go @@ -382,3 +382,30 @@ type Element struct { // Comment is an optional comment for the element Comment *string } + +type FlowtableIngressPriority string + +const ( + // FilterIngressPriority is the priority for the filter value in the Ingress hook + // that stands for 0. + FilterIngressPriority FlowtableIngressPriority = "filter" +) + +// Flowtable represents an nftables flowtable. +// https://wiki.nftables.org/wiki-nftables/index.php/Flowtables +type Flowtable struct { + // Name is the name of the flowtable. + Name string + + // The Priority can be a signed integer or FlowtableIngressPriority which stands for 0. + // Addition and subtraction can be used to set relative priority, e.g. filter + 5 equals to 5. + Priority *FlowtableIngressPriority + + // The Devices are specified as iifname(s) of the input interface(s) of the traffic + // that should be offloaded. + Devices []string + + // Handle is an identifier that can be used to uniquely identify an object when + // deleting it. When adding a new object, this must be nil + Handle *int +}