Skip to content
This repository was archived by the owner on May 12, 2021. It is now read-only.

Commit a415493

Browse files
committed
wip: network: Wait till link is operationally up.
Although we set the link up with LinkSetup, this function returns before the link is actually up. Additionally, besides the admin state of a network link, we also need to check if the link is operationally up. Namely we need to check if the netlink attribute IFLA_OPERSTATE is set to IF_OPER_UP. Fixes #458 Signed-off-by: Archana Shinde <archana.m.shinde@intel.com>
1 parent 17192be commit a415493

File tree

2 files changed

+51
-2
lines changed

2 files changed

+51
-2
lines changed

network.go

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"os"
1313
"reflect"
1414
"sync"
15+
"time"
1516

1617
"golang.org/x/sys/unix"
1718

@@ -230,6 +231,49 @@ func (s *sandbox) removeInterface(netHandle *netlink.Handle, iface *types.Interf
230231
return nil, nil
231232
}
232233

234+
const linkUpdateTimeout = 5
235+
236+
var linkOperational = true
237+
238+
func expectLinkUpdate(ch <-chan netlink.LinkUpdate, ifaceName string) bool {
239+
for {
240+
timeout := time.After(time.Second * linkUpdateTimeout)
241+
select {
242+
case update := <-ch:
243+
// Reference: https://www.kernel.org/doc/Documentation/networking/operstates.txt
244+
245+
if ifaceName == update.Link.Attrs().Name && (update.IfInfomsg.Flags&unix.IFF_UP != 0) {
246+
if linkOperational == (update.Link.Attrs().OperState == netlink.OperUp) {
247+
return true
248+
}
249+
}
250+
case <-timeout:
251+
return false
252+
}
253+
}
254+
}
255+
256+
func waitForLinkUp(netHandle *netlink.Handle, link netlink.Link, ifaceName string) (err error) {
257+
ch := make(chan netlink.LinkUpdate)
258+
done := make(chan struct{})
259+
defer close(done)
260+
261+
if err = netlink.LinkSubscribe(ch, done); err != nil {
262+
return
263+
}
264+
265+
//put the link back into the up state
266+
if err = netHandle.LinkSetUp(link); err != nil {
267+
return
268+
}
269+
270+
if !expectLinkUpdate(ch, ifaceName) {
271+
err = fmt.Errorf("Link Up update not received as expected for interface %s", ifaceName)
272+
}
273+
274+
return err
275+
}
276+
233277
// updateInterface will update an existing interface with the values provided in the types.Interface. It will identify the
234278
// existing interface via MAC address and will return the state of the interface once the function completes as well an any
235279
// errors observed.
@@ -286,8 +330,8 @@ func (s *sandbox) updateInterface(netHandle *netlink.Handle, iface *types.Interf
286330
} else {
287331
resultingIfc = iface
288332
}
289-
//put the link back into the up state
290-
retErr := netHandle.LinkSetUp(link)
333+
334+
retErr := waitForLinkUp(netHandle, link, iface.Name)
291335

292336
//if we failed to setup the link but already are returning
293337
//with an error, return the original error

network_test.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,11 @@ import (
2222
func TestUpdateRemoveInterface(t *testing.T) {
2323
skipUnlessRoot(t)
2424

25+
linkOperational = false
26+
defer func() {
27+
linkOperational = true
28+
}()
29+
2530
s := sandbox{}
2631

2732
ifc := types.Interface{

0 commit comments

Comments
 (0)