Skip to content

Commit

Permalink
Add bridge package
Browse files Browse the repository at this point in the history
The package contains logic to work
with managed OVS bridges.

// DiscoverBridges returns information about managed bridges on the host
DiscoverBridges() (sriovnetworkv1.Bridges, error)
// ConfigureBridge configure managed bridges for the host
ConfigureBridges(bridgesSpec sriovnetworkv1.Bridges, bridgesStatus sriovnetworkv1.Bridges) error
// DetachInterfaceFromManagedBridge detach interface from a managed bridge,
// this step is required before applying some configurations to PF, e.g. changing of eSwitch mode.
// The function detach interface from managed bridges only.
DetachInterfaceFromManagedBridge(pciAddr string) error

Signed-off-by: Yury Kulazhenkov <ykulazhenkov@nvidia.com>
  • Loading branch information
ykulazhenkov committed Jul 16, 2024
1 parent 4daeede commit a801939
Show file tree
Hide file tree
Showing 111 changed files with 17,120 additions and 0 deletions.
6 changes: 6 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@ require (
github.com/coreos/go-systemd/v22 v22.5.0
github.com/fsnotify/fsnotify v1.7.0
github.com/go-logr/logr v1.2.4
github.com/go-logr/stdr v1.2.2
github.com/golang/mock v1.4.4
github.com/google/go-cmp v0.6.0
github.com/google/renameio/v2 v2.0.0
github.com/google/uuid v1.3.1
github.com/hashicorp/go-retryablehttp v0.7.7
github.com/jaypipes/ghw v0.9.0
Expand All @@ -24,6 +26,7 @@ require (
github.com/openshift/api v0.0.0-20230807132801-600991d550ac
github.com/openshift/client-go v0.0.0-20230607134213-3cd0021bbee3
github.com/openshift/machine-config-operator v0.0.1-0.20231024085435-7e1fb719c1ba
github.com/ovn-org/libovsdb v0.6.1-0.20240125124854-03f787b1a892
github.com/pkg/errors v0.9.1
github.com/safchain/ethtool v0.3.0
github.com/spf13/cobra v1.7.0
Expand Down Expand Up @@ -55,6 +58,9 @@ require (
github.com/aws/aws-sdk-go v1.44.204 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/blang/semver/v4 v4.0.0 // indirect
github.com/cenkalti/backoff/v4 v4.2.1 // indirect
github.com/cenkalti/hub v1.0.1 // indirect
github.com/cenkalti/rpc2 v0.0.0-20210604223624-c1acbc6ec984 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/chai2010/gettext-go v1.0.2 // indirect
github.com/clarketm/json v1.17.1 // indirect
Expand Down
15 changes: 15 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,16 @@ github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdn
github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=
github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=
github.com/cenk/hub v1.0.1 h1:RBwXNOF4a8KjD8BJ08XqN8KbrqaGiQLDrgvUGJSHuPA=
github.com/cenk/hub v1.0.1/go.mod h1:rJM1LNAW0ppT8FMMuPK6c2NP/R2nH/UthtuRySSaf6Y=
github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4=
github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=
github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
github.com/cenkalti/hub v1.0.1 h1:UMtjc6dHSaOQTO15SVA50MBIR9zQwvsukQupDrkIRtg=
github.com/cenkalti/hub v1.0.1/go.mod h1:tcYwtS3a2d9NO/0xDXVJWx3IedurUjYCqFCmpi0lpHs=
github.com/cenkalti/rpc2 v0.0.0-20210604223624-c1acbc6ec984 h1:CNwZyGS6KpfaOWbh2yLkSy3rSTUh3jub9CzpFpP6PVQ=
github.com/cenkalti/rpc2 v0.0.0-20210604223624-c1acbc6ec984/go.mod h1:v2npkhrXyk5BCnkNIiPdRI23Uq6uWPUQGL2hnRcRr/M=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
Expand Down Expand Up @@ -149,8 +157,11 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-logr/zapr v1.2.4 h1:QHVo+6stLbfJmYGkQ7uGHUCu5hnAFAj6mDe6Ea0SeOo=
github.com/go-logr/zapr v1.2.4/go.mod h1:FyHWQIzQORZ0QVE1BtVHv3cKtNLuXsbNLtpuhNapBOA=
github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
Expand Down Expand Up @@ -243,6 +254,8 @@ github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLe
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec=
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/renameio/v2 v2.0.0 h1:UifI23ZTGY8Tt29JbYFiuyIU3eX+RNFtUwefq9qAhxg=
github.com/google/renameio/v2 v2.0.0/go.mod h1:BtmJXm5YlszgC+TD4HOEEUFgkJP3nLxehU6hfe7jRt4=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
Expand Down Expand Up @@ -362,6 +375,8 @@ github.com/openshift/library-go v0.0.0-20231020125025-211b32f1a1f2 h1:TWG/YVRhSv
github.com/openshift/library-go v0.0.0-20231020125025-211b32f1a1f2/go.mod h1:ZFwNwC3opc/7aOvzUbU95zp33Lbxet48h80ryH3p6DY=
github.com/openshift/machine-config-operator v0.0.1-0.20231024085435-7e1fb719c1ba h1:WM6K+m2xMAwbQDetKGhV/Rd8yukF3AsU1z74cqoWrz0=
github.com/openshift/machine-config-operator v0.0.1-0.20231024085435-7e1fb719c1ba/go.mod h1:mSt3ACow31pa1hTRONn+yT5e+KFkgi7G2bFEx5Nj+n0=
github.com/ovn-org/libovsdb v0.6.1-0.20240125124854-03f787b1a892 h1:/yg3/z+RH+iDLMxp6FTnmlk5bStK542/Rge5EBjnA9A=
github.com/ovn-org/libovsdb v0.6.1-0.20240125124854-03f787b1a892/go.mod h1:LC5DOvcY58jOG3HTvDyCVidoMJDurPeu+xlxv5Krd9Q=
github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI=
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
github.com/pin/tftp v2.1.0+incompatible/go.mod h1:xVpZOMCXTy+A5QMjEVN0Glwa1sUvaJhFXbr/aAxuxGY=
Expand Down
1 change: 1 addition & 0 deletions pkg/consts/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ const (
PfAppliedConfig = SriovConfBasePath + "/pci"
SriovSwitchDevConfPath = SriovConfBasePath + "/sriov_config.json"
SriovHostSwitchDevConfPath = Host + SriovSwitchDevConfPath
ManagedOVSBridgesPath = SriovConfBasePath + "/managed-ovs-bridges.json"

MachineConfigPoolPausedAnnotation = "sriovnetwork.openshift.io/state"
MachineConfigPoolPausedAnnotationIdle = "Idle"
Expand Down
81 changes: 81 additions & 0 deletions pkg/host/internal/bridge/bridge.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package bridge

import (
"context"

"sigs.k8s.io/controller-runtime/pkg/log"

sriovnetworkv1 "github.com/k8snetworkplumbingwg/sriov-network-operator/api/v1"
"github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/host/internal/bridge/ovs"
ovsStorePkg "github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/host/internal/bridge/ovs/store"
"github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/host/types"
)

type bridge struct {
ovs ovs.Interface
}

// New return default implementation of the BridgeInterface
func New() types.BridgeInterface {
return &bridge{
ovs: ovs.New(ovsStorePkg.New()),
}
}

// DiscoverBridges returns information about managed bridges on the host
func (b *bridge) DiscoverBridges() (sriovnetworkv1.Bridges, error) {
log.Log.V(2).Info("DiscoverBridges(): discover managed bridges")
discoveredOVSBridges, err := b.ovs.GetOVSBridges(context.Background())
if err != nil {
log.Log.Error(err, "DiscoverBridges(): failed to discover managed OVS bridges")
return sriovnetworkv1.Bridges{}, err
}
return sriovnetworkv1.Bridges{OVS: discoveredOVSBridges}, nil
}

// ConfigureBridge configure managed bridges for the host
func (b *bridge) ConfigureBridges(bridgesSpec sriovnetworkv1.Bridges, bridgesStatus sriovnetworkv1.Bridges) error {
log.Log.V(1).Info("ConfigureBridges(): configure bridges")
if len(bridgesSpec.OVS) == 0 && len(bridgesStatus.OVS) == 0 {
// there are no reported OVS bridges in the status and the spec doesn't contains bridges.
// no need to validated configuration
log.Log.V(2).Info("ConfigureBridges(): configuration is not required")
return nil
}
for _, curBr := range bridgesStatus.OVS {
found := false
for _, desiredBr := range bridgesSpec.OVS {
if curBr.Name == desiredBr.Name {
found = true
break
}
}
if !found {
if err := b.ovs.RemoveOVSBridge(context.Background(), curBr.Name); err != nil {
log.Log.Error(err, "ConfigureBridges(): failed to remove OVS bridge", "bridge", curBr.Name)
return err
}
}
}
// create bridges, existing bridges will be updated only if the new config doesn't match current config
for i := range bridgesSpec.OVS {
desiredBr := bridgesSpec.OVS[i]
if err := b.ovs.CreateOVSBridge(context.Background(), &desiredBr); err != nil {
log.Log.Error(err, "ConfigureBridges(): failed to create OVS bridge", "bridge", desiredBr.Name)
return err
}
}
return nil
}

// DetachInterfaceFromManagedBridge detach interface from a managed bridge,
// this step is required before applying some configurations to PF, e.g. changing of eSwitch mode.
// The function detach interface from managed bridges only.
func (b *bridge) DetachInterfaceFromManagedBridge(pciAddr string) error {
log.Log.V(1).Info("DetachInterfaceFromManagedBridge(): detach interface", "pciAddr", pciAddr)
if err := b.ovs.RemoveInterfaceFromOVSBridge(context.Background(), pciAddr); err != nil {
log.Log.Error(err, "DetachInterfaceFromManagedBridge(): failed to detach interface from OVS bridge", "pciAddr", pciAddr)
return err
}
return nil
}
97 changes: 97 additions & 0 deletions pkg/host/internal/bridge/bridge_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package bridge

import (
"fmt"

"github.com/golang/mock/gomock"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"

sriovnetworkv1 "github.com/k8snetworkplumbingwg/sriov-network-operator/api/v1"
ovsMockPkg "github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/host/internal/bridge/ovs/mock"
"github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/host/types"
)

var _ = Describe("Bridge", func() {
var (
testCtrl *gomock.Controller
br types.BridgeInterface
ovsMock *ovsMockPkg.MockInterface
testErr = fmt.Errorf("test")
)
BeforeEach(func() {
testCtrl = gomock.NewController(GinkgoT())
ovsMock = ovsMockPkg.NewMockInterface(testCtrl)
br = &bridge{ovs: ovsMock}
})
AfterEach(func() {
testCtrl.Finish()
})
Context("DiscoverBridges", func() {
It("succeed", func() {
ovsMock.EXPECT().GetOVSBridges(gomock.Any()).Return([]sriovnetworkv1.OVSConfigExt{{Name: "test"}, {Name: "test2"}}, nil)
ret, err := br.DiscoverBridges()
Expect(err).NotTo(HaveOccurred())
Expect(ret.OVS).To(HaveLen(2))
})
It("error", func() {
ovsMock.EXPECT().GetOVSBridges(gomock.Any()).Return(nil, testErr)
_, err := br.DiscoverBridges()
Expect(err).To(MatchError(testErr))
})
})

Context("ConfigureBridges", func() {
It("succeed", func() {
brCreate1 := sriovnetworkv1.OVSConfigExt{Name: "br-to-create-1"}
brCreate2 := sriovnetworkv1.OVSConfigExt{Name: "br-to-create-2"}
brDelete1 := sriovnetworkv1.OVSConfigExt{Name: "br-to-delete-1"}
brDelete2 := sriovnetworkv1.OVSConfigExt{Name: "br-to-delete-2"}

ovsMock.EXPECT().RemoveOVSBridge(gomock.Any(), brDelete1.Name).Return(nil)
ovsMock.EXPECT().RemoveOVSBridge(gomock.Any(), brDelete2.Name).Return(nil)
ovsMock.EXPECT().CreateOVSBridge(gomock.Any(), &brCreate1).Return(nil)
ovsMock.EXPECT().CreateOVSBridge(gomock.Any(), &brCreate2).Return(nil)
err := br.ConfigureBridges(
sriovnetworkv1.Bridges{OVS: []sriovnetworkv1.OVSConfigExt{brCreate1, brCreate2}},
sriovnetworkv1.Bridges{OVS: []sriovnetworkv1.OVSConfigExt{brCreate1, brDelete1, brDelete2}})
Expect(err).NotTo(HaveOccurred())
})
It("empty spec and status", func() {
err := br.ConfigureBridges(
sriovnetworkv1.Bridges{OVS: []sriovnetworkv1.OVSConfigExt{}},
sriovnetworkv1.Bridges{OVS: []sriovnetworkv1.OVSConfigExt{}})
Expect(err).NotTo(HaveOccurred())
})
It("failed on creation", func() {
brCreate1 := sriovnetworkv1.OVSConfigExt{Name: "br-to-create-1"}
ovsMock.EXPECT().CreateOVSBridge(gomock.Any(), &brCreate1).Return(testErr)
err := br.ConfigureBridges(
sriovnetworkv1.Bridges{OVS: []sriovnetworkv1.OVSConfigExt{brCreate1}},
sriovnetworkv1.Bridges{OVS: []sriovnetworkv1.OVSConfigExt{}})
Expect(err).To(MatchError(testErr))
})
It("failed on removal", func() {
brDelete1 := sriovnetworkv1.OVSConfigExt{Name: "br-to-delete-1"}
ovsMock.EXPECT().RemoveOVSBridge(gomock.Any(), brDelete1.Name).Return(testErr)
err := br.ConfigureBridges(
sriovnetworkv1.Bridges{OVS: []sriovnetworkv1.OVSConfigExt{}},
sriovnetworkv1.Bridges{OVS: []sriovnetworkv1.OVSConfigExt{brDelete1}})
Expect(err).To(MatchError(testErr))
})
})

Context("DetachInterfaceFromManagedBridge", func() {
It("succeed", func() {
ovsMock.EXPECT().RemoveInterfaceFromOVSBridge(gomock.Any(), "0000:d8:00.0").Return(nil)
err := br.DetachInterfaceFromManagedBridge("0000:d8:00.0")
Expect(err).NotTo(HaveOccurred())
})
It("error", func() {
ovsMock.EXPECT().RemoveInterfaceFromOVSBridge(gomock.Any(), "0000:d8:00.0").Return(testErr)
err := br.DetachInterfaceFromManagedBridge("0000:d8:00.0")
Expect(err).To(MatchError(testErr))
})
})
})
93 changes: 93 additions & 0 deletions pkg/host/internal/bridge/ovs/mock/mock_ovs.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit a801939

Please sign in to comment.