talos/internal/integration/api/ethernet.go
Andrey Smirnov 716f700da7
feat: provide initial support for ethtool configuration
See https://github.com/siderolabs/ethtool - our fork.

This PR covers only configuring rings, follow-up PRs will address other
pieces: channels and features.

Example:

```
node: 172.20.0.5
metadata:
    namespace: network
    type: EthernetStatuses.net.talos.dev
    id: enp0s2
    version: 4
    owner: network.EthernetStatusController
    phase: running
    created: 2025-02-04T16:03:14Z
    updated: 2025-02-04T16:04:12Z
spec:
    linkState: true
    port: Other
    duplex: Unknown
    rings:
        rx-max: 256
        tx-max: 256
        rx: 128
        tx: 128
        tx-push: false
        rx-push: false
```

Signed-off-by: Andrey Smirnov <andrey.smirnov@siderolabs.com>
2025-02-05 21:28:42 +04:00

133 lines
3.9 KiB
Go

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//go:build integration_api
package api
import (
"context"
"os"
"time"
"github.com/cosi-project/runtime/pkg/resource"
"github.com/cosi-project/runtime/pkg/resource/rtestutils"
"github.com/cosi-project/runtime/pkg/safe"
"github.com/siderolabs/go-pointer"
"github.com/stretchr/testify/assert"
"gopkg.in/yaml.v3"
"github.com/siderolabs/talos/internal/integration/base"
"github.com/siderolabs/talos/pkg/machinery/client"
networkconfig "github.com/siderolabs/talos/pkg/machinery/config/types/network"
"github.com/siderolabs/talos/pkg/machinery/resources/network"
)
// EthernetSuite ...
type EthernetSuite struct {
base.APISuite
ctx context.Context //nolint:containedctx
ctxCancel context.CancelFunc
}
// SuiteName ...
func (suite *EthernetSuite) SuiteName() string {
return "api.EthernetSuite"
}
// SetupTest ...
func (suite *EthernetSuite) SetupTest() {
suite.ctx, suite.ctxCancel = context.WithTimeout(context.Background(), 1*time.Minute)
if suite.Cluster == nil || suite.Cluster.Provisioner() != base.ProvisionerQEMU {
suite.T().Skip("skipping ethernet test since provisioner is not qemu")
}
}
// TearDownTest ...
func (suite *EthernetSuite) TearDownTest() {
if suite.ctxCancel != nil {
suite.ctxCancel()
}
}
// TestEthernetConfig verifies changing Ethernet settings.
func (suite *EthernetSuite) TestEthernetConfig() {
// pick up a random node to test the Ethernet on, and use it throughout the test
node := suite.RandomDiscoveredNodeInternalIP()
suite.T().Logf("testing Ethernet on node %s", node)
// build a Talos API context which is tied to the node
nodeCtx := client.WithNode(suite.ctx, node)
// pick a Ethernet links
ethStatuses, err := safe.StateListAll[*network.EthernetStatus](nodeCtx, suite.Client.COSI)
suite.Require().NoError(err)
var (
linkName string
prevRingConfig *network.EthernetRingsStatus
)
for ethStatus := range ethStatuses.All() {
if ethStatus.TypedSpec().Rings != nil && ethStatus.TypedSpec().Rings.RXMax != nil {
linkName = ethStatus.Metadata().ID()
prevRingConfig = ethStatus.TypedSpec().Rings
marshaled, err := resource.MarshalYAML(ethStatus)
suite.Require().NoError(err)
out, err := yaml.Marshal(marshaled)
suite.Require().NoError(err)
suite.T().Logf("found link %s with: %s", linkName, string(out))
break
}
}
suite.Require().NotEmpty(linkName, "no link provides RX rings")
if os.Getenv("CI") != "" {
suite.T().Skip("skipping ethtool test in CI, as QEMU version doesn't support updating RX rings for virtio")
}
// first, adjust RX rings to be 50% of what it was before
newRX := pointer.SafeDeref(prevRingConfig.RXMax) / 2
cfgDocument := networkconfig.NewEthernetConfigV1Alpha1(linkName)
cfgDocument.RingsConfig = &networkconfig.EthernetRingsConfig{
RX: pointer.To(newRX),
}
suite.PatchMachineConfig(nodeCtx, cfgDocument)
// now EthernetStatus should reflect the new RX rings
rtestutils.AssertResource(nodeCtx, suite.T(), suite.Client.COSI, linkName,
func(ethStatus *network.EthernetStatus, asrt *assert.Assertions) {
asrt.Equal(newRX, pointer.SafeDeref(ethStatus.TypedSpec().Rings.RX))
},
)
// now, let's revert the RX rings to what it was before
cfgDocument.RingsConfig.RX = prevRingConfig.RX
suite.PatchMachineConfig(nodeCtx, cfgDocument)
// now EthernetStatus should reflect the new RX rings
rtestutils.AssertResource(nodeCtx, suite.T(), suite.Client.COSI, linkName,
func(ethStatus *network.EthernetStatus, asrt *assert.Assertions) {
asrt.Equal(pointer.SafeDeref(prevRingConfig.RX), pointer.SafeDeref(ethStatus.TypedSpec().Rings.RX))
},
)
// remove the config document
suite.RemoveMachineConfigDocuments(nodeCtx, cfgDocument.MetaKind)
}
func init() {
allSuites = append(allSuites, new(EthernetSuite))
}