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 <[email protected]>
  • Loading branch information
ykulazhenkov committed Apr 29, 2024
1 parent 2f29a44 commit cdec0b4
Show file tree
Hide file tree
Showing 111 changed files with 17,065 additions and 1 deletion.
8 changes: 7 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,11 @@ 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.0
github.com/jaypipes/ghw v0.9.0
github.com/k8snetworkplumbingwg/network-attachment-definition-client v1.4.0
Expand All @@ -21,6 +24,7 @@ require (
github.com/openshift/api v0.0.0-20221220162201-efeef9d83325
github.com/openshift/client-go v0.0.0-20220831193253-4950ae70c8ea
github.com/openshift/machine-config-operator v0.0.1-0.20230118083703-fc27a2bdaa85
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 @@ -49,6 +53,9 @@ require (
github.com/StackExchange/wmi v1.2.1 // indirect
github.com/ajeddeloh/go-json v0.0.0-20170920214419-6a2fe990e083 // indirect
github.com/beorn7/perks v1.0.1 // 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.14.1 // indirect
Expand Down Expand Up @@ -82,7 +89,6 @@ require (
github.com/google/gofuzz v1.2.0 // indirect
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 // indirect
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
github.com/google/uuid v1.3.1 // indirect
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-hclog v1.2.0 // indirect
Expand Down
15 changes: 15 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,16 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ=
github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
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 @@ -246,6 +257,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 @@ -365,6 +378,8 @@ github.com/openshift/client-go v0.0.0-20220831193253-4950ae70c8ea h1:7JbjIzWt3Q7
github.com/openshift/client-go v0.0.0-20220831193253-4950ae70c8ea/go.mod h1:+J8DqZC60acCdpYkwVy/KH4cudgWiFZRNOBeghCzdGA=
github.com/openshift/machine-config-operator v0.0.1-0.20230118083703-fc27a2bdaa85 h1:iJ6S94vL43WjldQ+6VexZUUbDwymRW38ATCkCKEL3nw=
github.com/openshift/machine-config-operator v0.0.1-0.20230118083703-fc27a2bdaa85/go.mod h1:RP4FG/4aZv2c3QzhOZQn0im1OZqSzicg3aaFqKU9IIA=
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 @@ -54,6 +54,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(2).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 _, desiredBr := range bridgesSpec.OVS {
desiredBr := desiredBr
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(2).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 cdec0b4

Please sign in to comment.