Skip to content

Commit 738c407

Browse files
committed
underlay: sync NetworkManager IP config to OVS bridge (#2949)
1 parent d9bab2e commit 738c407

10 files changed

+317
-80
lines changed

go.mod

+1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ require (
2929
github.com/ovn-org/libovsdb v0.0.0-20221101143603-8f21d188c3a5
3030
github.com/parnurzeal/gorequest v0.2.16
3131
github.com/prometheus/client_golang v1.14.0
32+
github.com/scylladb/go-set v1.0.2
3233
github.com/sirupsen/logrus v1.9.0
3334
github.com/spf13/pflag v1.0.5
3435
github.com/stretchr/testify v1.8.1

go.sum

+4
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,8 @@ github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d h1:105gxyaGwC
476476
github.com/facette/natsort v0.0.0-20181210072756-2cd4dd1e2dcb/go.mod h1:bH6Xx7IW64qjjJq8M2u4dxNaBiDfKK+z/3eGDpXEQhc=
477477
github.com/fatih/camelcase v1.0.0 h1:hxNvNX/xYBp0ovncs8WyWZrOrpBNub/JfaMvbURyft8=
478478
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
479+
github.com/fatih/set v0.2.1 h1:nn2CaJyknWE/6txyUDGwysr3G5QC6xWB/PtVjPBbeaA=
480+
github.com/fatih/set v0.2.1/go.mod h1:+RKtMCH+favT2+3YecHGxcc0b4KyVWA1QWWJUs4E0CI=
479481
github.com/fatih/structtag v1.1.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94=
480482
github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk=
481483
github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
@@ -1226,6 +1228,8 @@ github.com/santhosh-tekuri/jsonschema v1.2.4/go.mod h1:TEAUOeZSmIxTTuHatJzrvARHi
12261228
github.com/satori/go.uuid v0.0.0-20160603004225-b111a074d5ef/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
12271229
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
12281230
github.com/sclevine/spec v1.2.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24q7p+U=
1231+
github.com/scylladb/go-set v1.0.2 h1:SkvlMCKhP0wyyct6j+0IHJkBkSZL+TDzZ4E7f7BCcRE=
1232+
github.com/scylladb/go-set v1.0.2/go.mod h1:DkpGd78rljTxKAnTDPFqXSGxvETQnJyuSOQwsHycqfs=
12291233
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
12301234
github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo=
12311235
github.com/seccomp/libseccomp-golang v0.9.2-0.20220502022130-f33da4d89646 h1:RpforrEYXWkmGwJHIGnLZ3tTWStkjVVstwzNGqxX2Ds=

pkg/daemon/controller.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,7 @@ func (c *Controller) initProviderNetwork(pn *kubeovnv1.ProviderNetwork, node *v1
254254

255255
var mtu int
256256
var err error
257-
if mtu, err = ovsInitProviderNetwork(pn.Name, nic, pn.Spec.ExchangeLinkName, c.config.MacLearningFallback); err != nil {
257+
if mtu, err = c.ovsInitProviderNetwork(pn.Name, nic, pn.Spec.ExchangeLinkName, c.config.MacLearningFallback); err != nil {
258258
if oldLen := len(node.Labels); oldLen != 0 {
259259
delete(node.Labels, fmt.Sprintf(util.ProviderNetworkReadyTemplate, pn.Name))
260260
delete(node.Labels, fmt.Sprintf(util.ProviderNetworkInterfaceTemplate, pn.Name))
@@ -368,15 +368,15 @@ func (c *Controller) cleanProviderNetwork(pn *kubeovnv1.ProviderNetwork, node *v
368368
return err
369369
}
370370

371-
if err = ovsCleanProviderNetwork(pn.Name); err != nil {
371+
if err = c.ovsCleanProviderNetwork(pn.Name); err != nil {
372372
return err
373373
}
374374

375375
return nil
376376
}
377377

378378
func (c *Controller) handleDeleteProviderNetwork(pn *kubeovnv1.ProviderNetwork) error {
379-
if err := ovsCleanProviderNetwork(pn.Name); err != nil {
379+
if err := c.ovsCleanProviderNetwork(pn.Name); err != nil {
380380
return err
381381
}
382382

pkg/daemon/controller_linux.go

+5
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ type ControllerRuntime struct {
3333
iptables map[string]*iptables.IPTables
3434
iptablesObsolete map[string]*iptables.IPTables
3535
ipsets map[string]*ipsets.IPSets
36+
37+
nmSyncer *networkManagerSyncer
3638
}
3739

3840
func evalCommandSymlinks(cmd string) (string, error) {
@@ -103,6 +105,9 @@ func (c *Controller) initRuntime() error {
103105
c.ipsets[kubeovnv1.ProtocolIPv6] = ipsets.NewIPSets(ipsets.NewIPVersionConfig(ipsets.IPFamilyV6, IPSetPrefix, nil, nil))
104106
}
105107

108+
c.nmSyncer = newNetworkManagerSyncer()
109+
c.nmSyncer.Run(c.transferAddrsAndRoutes)
110+
106111
return nil
107112
}
108113

pkg/daemon/init.go

+5-9
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,6 @@ func InitOVSBridges() (map[string]string, error) {
4040
return nil, fmt.Errorf("failed to check vendor of port %s: %v", port, err)
4141
}
4242
if ok {
43-
klog.Infof("config provider nic %s on bridge %s", port, brName)
44-
if _, err = configProviderNic(port, brName); err != nil {
45-
return nil, err
46-
}
4743
mappings[port] = brName
4844
}
4945
}
@@ -97,11 +93,11 @@ func InitMirror(config *Configuration) error {
9793
return configureEmptyMirror(config.MirrorNic, config.MTU)
9894
}
9995

100-
func ovsInitProviderNetwork(provider, nic string, exchangeLinkName, macLearningFallback bool) (int, error) {
96+
func (c *Controller) ovsInitProviderNetwork(provider, nic string, exchangeLinkName, macLearningFallback bool) (int, error) {
10197
// create and configure external bridge
10298
brName := util.ExternalBridgeName(provider)
10399
if exchangeLinkName {
104-
exchanged, err := changeProvideNicName(nic, brName)
100+
exchanged, err := c.changeProvideNicName(nic, brName)
105101
if err != nil {
106102
klog.Errorf("failed to change provider nic name from %s to %s: %v", nic, brName, err)
107103
return 0, err
@@ -126,7 +122,7 @@ func ovsInitProviderNetwork(provider, nic string, exchangeLinkName, macLearningF
126122

127123
// add host nic to the external bridge
128124
klog.Infof("config provider nic %s on bridge %s", nic, brName)
129-
mtu, err := configProviderNic(nic, brName)
125+
mtu, err := c.configProviderNic(nic, brName)
130126
if err != nil {
131127
errMsg := fmt.Errorf("failed to add nic %s to external bridge %s: %v", nic, brName, err)
132128
klog.Error(errMsg)
@@ -136,7 +132,7 @@ func ovsInitProviderNetwork(provider, nic string, exchangeLinkName, macLearningF
136132
return mtu, nil
137133
}
138134

139-
func ovsCleanProviderNetwork(provider string) error {
135+
func (c *Controller) ovsCleanProviderNetwork(provider string) error {
140136
mappings, err := getOvnMappings("ovn-bridge-mappings")
141137
if err != nil {
142138
return err
@@ -189,7 +185,7 @@ func ovsCleanProviderNetwork(provider string) error {
189185
klog.V(3).Infof("ovs bridge %s has been deleted", brName)
190186

191187
if br := util.ExternalBridgeName(provider); br != brName {
192-
if _, err = changeProvideNicName(br, brName); err != nil {
188+
if _, err = c.changeProvideNicName(br, brName); err != nil {
193189
klog.Errorf("failed to change provider nic name from %s to %s: %v", br, brName, err)
194190
return err
195191
}

pkg/daemon/init_linux.go

+3-44
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package daemon
33
import (
44
"time"
55

6-
"github.com/kubeovn/gonetworkmanager/v2"
76
"github.com/vishvananda/netlink"
87
"k8s.io/klog/v2"
98

@@ -17,46 +16,6 @@ var routeScopeOrders = [...]netlink.Scope{
1716
netlink.SCOPE_UNIVERSE,
1817
}
1918

20-
func nmSetManaged(device string, managed bool) error {
21-
nm, err := gonetworkmanager.NewNetworkManager()
22-
if err != nil {
23-
klog.V(5).Infof("failed to connect to NetworkManager: %v", err)
24-
return nil
25-
}
26-
27-
running, err := nm.Running()
28-
if err != nil {
29-
klog.Warningf("failed to check NetworkManager running state: %v", err)
30-
return nil
31-
}
32-
if !running {
33-
klog.V(5).Info("NetworkManager is not running, ignore")
34-
return nil
35-
}
36-
37-
d, err := nm.GetDeviceByIpIface(device)
38-
if err != nil {
39-
klog.Errorf("failed to get device by IP iface %s: %v", device, err)
40-
return err
41-
}
42-
current, err := d.GetPropertyManaged()
43-
if err != nil {
44-
klog.Errorf("failed to get device property managed: %v", err)
45-
return err
46-
}
47-
if current == managed {
48-
return nil
49-
}
50-
51-
klog.Infof(`setting device %s NetworkManager property "managed" to %v`, device, managed)
52-
if err = d.SetPropertyManaged(managed); err != nil {
53-
klog.Errorf("failed to set device property managed to %v: %v", managed, err)
54-
return err
55-
}
56-
57-
return nil
58-
}
59-
6019
// wait systemd-networkd to finish interface configuration
6120
func waitNetworkdConfiguration(linkIndex int) {
6221
done := make(chan struct{})
@@ -90,7 +49,7 @@ func waitNetworkdConfiguration(linkIndex int) {
9049
}
9150
}
9251

93-
func changeProvideNicName(current, target string) (bool, error) {
52+
func (c *Controller) changeProvideNicName(current, target string) (bool, error) {
9453
link, err := netlink.LinkByName(current)
9554
if err != nil {
9655
if _, ok := err.(netlink.LinkNotFoundError); ok {
@@ -117,8 +76,8 @@ func changeProvideNicName(current, target string) (bool, error) {
11776
}
11877

11978
// set link unmanaged by NetworkManager
120-
if err = nmSetManaged(current, false); err != nil {
121-
klog.Errorf("failed set device %s unmanaged by NetworkManager: %v", current, err)
79+
if err = c.nmSyncer.SetManaged(current, false); err != nil {
80+
klog.Errorf("failed to set device %s unmanaged by NetworkManager: %v", current, err)
12281
return false, err
12382
}
12483

pkg/daemon/init_windows.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package daemon
22

3-
func changeProvideNicName(nic, br string) (bool, error) {
3+
func (c *Controller) changeProvideNicName(nic, br string) (bool, error) {
44
// not supported on windows
55
return false, nil
66
}

pkg/daemon/nm_linux.go

+186
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
package daemon
2+
3+
import (
4+
"sync"
5+
6+
"github.com/kubeovn/gonetworkmanager/v2"
7+
"github.com/scylladb/go-set/strset"
8+
"k8s.io/client-go/util/workqueue"
9+
"k8s.io/klog/v2"
10+
)
11+
12+
type networkManagerSyncer struct {
13+
manager gonetworkmanager.NetworkManager
14+
workqueue workqueue.Interface
15+
devicePaths *strset.Set
16+
pathMap map[string]string
17+
bridgeMap map[string]string
18+
lock sync.Mutex
19+
}
20+
21+
func newNetworkManagerSyncer() *networkManagerSyncer {
22+
syncer := &networkManagerSyncer{}
23+
24+
manager, err := gonetworkmanager.NewNetworkManager()
25+
if err != nil {
26+
klog.V(3).Infof("failed to connect to NetworkManager: %v", err)
27+
return syncer
28+
}
29+
30+
running, err := manager.Running()
31+
if err != nil {
32+
klog.V(3).Infof("failed to check NetworkManager running state: %v", err)
33+
return syncer
34+
}
35+
if !running {
36+
klog.V(3).Info("NetworkManager is not running, ignore")
37+
return syncer
38+
}
39+
40+
syncer.manager = manager
41+
syncer.workqueue = workqueue.NewNamed("NetworkManagerSyncer")
42+
syncer.devicePaths = strset.New()
43+
syncer.pathMap = make(map[string]string)
44+
syncer.bridgeMap = make(map[string]string)
45+
return syncer
46+
}
47+
48+
func (n *networkManagerSyncer) Run(handler func(nic, bridge string, delNonExistent bool) (int, error)) {
49+
if n.manager == nil {
50+
return
51+
}
52+
53+
go func() {
54+
for n.ProcessNextItem(handler) {
55+
}
56+
}()
57+
58+
go func() {
59+
ch := n.manager.Subscribe()
60+
defer n.manager.Unsubscribe()
61+
62+
stateChange := gonetworkmanager.DeviceInterface + "." + gonetworkmanager.ActiveConnectionSignalStateChanged
63+
for {
64+
event := <-ch
65+
66+
n.lock.Lock()
67+
if len(event.Body) == 0 || event.Name != stateChange || !n.devicePaths.Has(string(event.Path)) {
68+
n.lock.Unlock()
69+
continue
70+
}
71+
n.lock.Unlock()
72+
73+
state, ok := event.Body[0].(uint32)
74+
if !ok {
75+
klog.Warningf("failed to convert %#v to uint32", event.Body[0])
76+
continue
77+
}
78+
if gonetworkmanager.NmDeviceState(state) != gonetworkmanager.NmDeviceStateActivated {
79+
continue
80+
}
81+
82+
klog.Infof("adding dbus object path %s to workqueue", event.Path)
83+
n.workqueue.Add(string(event.Path))
84+
}
85+
}()
86+
}
87+
88+
func (n *networkManagerSyncer) ProcessNextItem(handler func(nic, bridge string, delNonExistent bool) (int, error)) bool {
89+
item, shutdown := n.workqueue.Get()
90+
if shutdown {
91+
return false
92+
}
93+
defer n.workqueue.Done(item)
94+
95+
klog.Infof("process dbus object path %v", item)
96+
path := item.(string)
97+
n.lock.Lock()
98+
if !n.devicePaths.Has(path) {
99+
n.lock.Unlock()
100+
return true
101+
}
102+
var nic string
103+
for k, v := range n.pathMap {
104+
if v == path {
105+
nic = k
106+
break
107+
}
108+
}
109+
n.lock.Unlock()
110+
111+
bridge := n.bridgeMap[nic]
112+
if _, err := handler(nic, bridge, true); err != nil {
113+
klog.Errorf("failed to handle NetworkManager event for device %s with bridge %s: %v", nic, bridge, err)
114+
}
115+
116+
return true
117+
}
118+
119+
func (n *networkManagerSyncer) AddDevice(nicName, bridge string) error {
120+
if n.manager == nil {
121+
return nil
122+
}
123+
124+
n.lock.Lock()
125+
defer n.lock.Unlock()
126+
127+
if _, ok := n.pathMap[nicName]; ok {
128+
return nil
129+
}
130+
131+
device, err := n.manager.GetDeviceByIpIface(nicName)
132+
if err != nil {
133+
klog.Errorf("failed to get device by IP iface %q: %v", nicName, err)
134+
return err
135+
}
136+
137+
path := string(device.GetPath())
138+
klog.V(3).Infof("adding device %s with dbus object path %s and bridge %s", nicName, path, bridge)
139+
n.devicePaths.Add(path)
140+
n.pathMap[nicName] = path
141+
n.bridgeMap[nicName] = bridge
142+
143+
return nil
144+
}
145+
146+
func (n *networkManagerSyncer) RemoveDevice(nicName string) error {
147+
if n.manager == nil {
148+
return nil
149+
}
150+
151+
n.lock.Lock()
152+
n.devicePaths.Remove(n.pathMap[nicName])
153+
delete(n.pathMap, nicName)
154+
delete(n.bridgeMap, nicName)
155+
n.lock.Unlock()
156+
157+
return nil
158+
}
159+
160+
func (n *networkManagerSyncer) SetManaged(name string, managed bool) error {
161+
if n.manager == nil {
162+
return nil
163+
}
164+
165+
device, err := n.manager.GetDeviceByIpIface(name)
166+
if err != nil {
167+
klog.Errorf("failed to get device by IP iface %q: %v", name, err)
168+
return err
169+
}
170+
current, err := device.GetPropertyManaged()
171+
if err != nil {
172+
klog.Errorf("failed to get device property managed: %v", err)
173+
return err
174+
}
175+
if current == managed {
176+
return nil
177+
}
178+
179+
klog.Infof(`setting device %s NetworkManager property "managed" to %v`, name, managed)
180+
if err = device.SetPropertyManaged(managed); err != nil {
181+
klog.Errorf("failed to set device property managed to %v: %v", managed, err)
182+
return err
183+
}
184+
185+
return nil
186+
}

0 commit comments

Comments
 (0)