Skip to content

Commit 8a6b507

Browse files
committed
Cleanup vxlan interfaces inside namespace
If a new network request is received for a prticular vni, cleanup the interface with that vni even if it is inside a namespace. This is done by collecting vni to namespace data during init and later using it to delete the interface. Also fixed a long pending issue of the vxlan interface not getting destroyed even if the sandbox is destroyed. Fixed by first deleting the vxlan interface first before destroying the sandbox. Signed-off-by: Jana Radhakrishnan <[email protected]>
1 parent d3a5167 commit 8a6b507

2 files changed

Lines changed: 104 additions & 8 deletions

File tree

drivers/overlay/ov_network.go

Lines changed: 74 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,14 @@ import (
2121
"github.com/docker/libnetwork/types"
2222
"github.com/vishvananda/netlink"
2323
"github.com/vishvananda/netlink/nl"
24+
"github.com/vishvananda/netns"
2425
)
2526

2627
var (
27-
hostMode bool
28-
hostModeOnce sync.Once
28+
hostMode bool
29+
networkOnce sync.Once
30+
networkMu sync.Mutex
31+
vniTbl = make(map[uint32]string)
2932
)
3033

3134
type networkTable map[string]*network
@@ -249,7 +252,48 @@ func (n *network) destroySandbox() {
249252
}
250253
}
251254

252-
func setHostMode() {
255+
func populateVNITbl() {
256+
filepath.Walk(filepath.Dir(osl.GenerateKey("walk")),
257+
func(path string, info os.FileInfo, err error) error {
258+
_, fname := filepath.Split(path)
259+
260+
if len(strings.Split(fname, "-")) <= 1 {
261+
return nil
262+
}
263+
264+
ns, err := netns.GetFromPath(path)
265+
if err != nil {
266+
logrus.Errorf("Could not open namespace path %s during vni population: %v", path, err)
267+
return nil
268+
}
269+
defer ns.Close()
270+
271+
nlh, err := netlink.NewHandleAt(ns)
272+
if err != nil {
273+
logrus.Errorf("Could not open netlink handle during vni population for ns %s: %v", path, err)
274+
return nil
275+
}
276+
defer nlh.Delete()
277+
278+
links, err := nlh.LinkList()
279+
if err != nil {
280+
logrus.Errorf("Failed to list interfaces during vni population for ns %s: %v", path, err)
281+
return nil
282+
}
283+
284+
for _, l := range links {
285+
if l.Type() == "vxlan" {
286+
vniTbl[uint32(l.(*netlink.Vxlan).VxlanId)] = path
287+
}
288+
}
289+
290+
return nil
291+
})
292+
}
293+
294+
func networkOnceInit() {
295+
populateVNITbl()
296+
253297
if os.Getenv("_OVERLAY_HOST_MODE") != "" {
254298
hostMode = true
255299
return
@@ -330,13 +374,36 @@ func (n *network) initSubnetSandbox(s *subnet) error {
330374
// Try to delete stale bridge interface if it exists
331375
deleteInterface(brName)
332376
// Try to delete the vxlan interface by vni if already present
333-
deleteVxlanByVNI(n.vxlanID(s))
377+
deleteVxlanByVNI("", n.vxlanID(s))
334378

335379
if isOverlap(s.subnetIP) {
336380
return fmt.Errorf("overlay subnet %s has conflicts in the host while running in host mode", s.subnetIP.String())
337381
}
338382
}
339383

384+
if !hostMode {
385+
// Try to find this subnet's vni is being used in some
386+
// other namespace by looking at vniTbl that we just
387+
// populated in the once init. If a hit is found then
388+
// it must a stale namespace from previous
389+
// life. Destroy it completely and reclaim resourced.
390+
networkMu.Lock()
391+
path, ok := vniTbl[n.vxlanID(s)]
392+
networkMu.Unlock()
393+
394+
if ok {
395+
deleteVxlanByVNI(path, n.vxlanID(s))
396+
if err := syscall.Unmount(path, syscall.MNT_FORCE); err != nil {
397+
logrus.Errorf("unmount of %s failed: %v", path, err)
398+
}
399+
os.Remove(path)
400+
401+
networkMu.Lock()
402+
delete(vniTbl, n.vxlanID(s))
403+
networkMu.Unlock()
404+
}
405+
}
406+
340407
// create a bridge and vxlan device for this subnet and move it to the sandbox
341408
sbox := n.sandbox()
342409

@@ -382,6 +449,8 @@ func (n *network) cleanupStaleSandboxes() {
382449

383450
pattern := pList[1]
384451
if strings.Contains(n.id, pattern) {
452+
// Delete all vnis
453+
deleteVxlanByVNI(path, 0)
385454
syscall.Unmount(path, syscall.MNT_DETACH)
386455
os.Remove(path)
387456
}
@@ -395,7 +464,7 @@ func (n *network) initSandbox() error {
395464
n.initEpoch++
396465
n.Unlock()
397466

398-
hostModeOnce.Do(setHostMode)
467+
networkOnce.Do(networkOnceInit)
399468

400469
if hostMode {
401470
if err := addNetworkChain(n.id[:12]); err != nil {

drivers/overlay/ov_utils.go

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"github.com/docker/libnetwork/netutils"
77
"github.com/docker/libnetwork/osl"
88
"github.com/vishvananda/netlink"
9+
"github.com/vishvananda/netns"
910
)
1011

1112
func validateID(nid, eid string) error {
@@ -81,16 +82,42 @@ func deleteInterface(name string) error {
8182
return nil
8283
}
8384

84-
func deleteVxlanByVNI(vni uint32) error {
85+
func deleteVxlanByVNI(path string, vni uint32) error {
8586
defer osl.InitOSContext()()
8687

87-
links, err := netlink.LinkList()
88+
var nlh *netlink.Handle
89+
if path == "" {
90+
var err error
91+
nlh, err = netlink.NewHandle()
92+
if err != nil {
93+
return fmt.Errorf("failed to get netlink handle for current ns: %v", err)
94+
}
95+
} else {
96+
var (
97+
err error
98+
ns netns.NsHandle
99+
)
100+
101+
ns, err = netns.GetFromPath(path)
102+
if err != nil {
103+
return fmt.Errorf("failed to get ns handle for %s: %v", path, err)
104+
}
105+
defer ns.Close()
106+
107+
nlh, err = netlink.NewHandleAt(ns)
108+
if err != nil {
109+
return fmt.Errorf("failed to get netlink handle for ns %s: %v", path, err)
110+
}
111+
}
112+
defer nlh.Delete()
113+
114+
links, err := nlh.LinkList()
88115
if err != nil {
89116
return fmt.Errorf("failed to list interfaces while deleting vxlan interface by vni: %v", err)
90117
}
91118

92119
for _, l := range links {
93-
if l.Type() == "vxlan" && l.(*netlink.Vxlan).VxlanId == int(vni) {
120+
if l.Type() == "vxlan" && (vni == 0 || l.(*netlink.Vxlan).VxlanId == int(vni)) {
94121
err = netlink.LinkDel(l)
95122
if err != nil {
96123
return fmt.Errorf("error deleting vxlan interface with id %d: %v", vni, err)

0 commit comments

Comments
 (0)