-
Notifications
You must be signed in to change notification settings - Fork 237
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(config): wildcard interface name support & refactor lazybind (#758)
Co-authored-by: mzz <[email protected]>
- Loading branch information
1 parent
79d3fd2
commit fa7318f
Showing
3 changed files
with
212 additions
and
80 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
package component | ||
|
||
import ( | ||
"context" | ||
"path" | ||
"sync" | ||
|
||
"github.com/sirupsen/logrus" | ||
"github.com/vishvananda/netlink" | ||
"golang.org/x/sys/unix" | ||
) | ||
|
||
type callbackSet struct { | ||
pattern string | ||
newCallback func(netlink.Link) | ||
delCallback func(netlink.Link) | ||
} | ||
|
||
type InterfaceManager struct { | ||
log *logrus.Logger | ||
closed context.Context | ||
close context.CancelFunc | ||
mu sync.Mutex | ||
callbacks []callbackSet | ||
upLinks map[string]bool | ||
} | ||
|
||
func NewInterfaceManager(log *logrus.Logger) *InterfaceManager { | ||
closed, toClose := context.WithCancel(context.Background()) | ||
mgr := &InterfaceManager{ | ||
log: log, | ||
callbacks: make([]callbackSet, 0), | ||
closed: closed, | ||
close: toClose, | ||
upLinks: make(map[string]bool), | ||
} | ||
|
||
ch := make(chan netlink.LinkUpdate) | ||
done := make(chan struct{}) | ||
if e := netlink.LinkSubscribeWithOptions(ch, done, netlink.LinkSubscribeOptions{ | ||
ErrorCallback: func(err error) { | ||
log.Debug("LinkSubscribe:", err) | ||
}, | ||
ListExisting: true, | ||
}); e != nil { | ||
log.Errorf("Failed to subscribe to link updates: %v", e) | ||
} | ||
|
||
go mgr.monitor(ch, done) | ||
return mgr | ||
} | ||
|
||
func (m *InterfaceManager) monitor(ch <-chan netlink.LinkUpdate, done chan struct{}) { | ||
for { | ||
select { | ||
case <-m.closed.Done(): | ||
close(done) | ||
return | ||
case update := <-ch: | ||
ifName := update.Link.Attrs().Name | ||
|
||
switch update.Header.Type { | ||
case unix.RTM_NEWLINK: | ||
m.mu.Lock() | ||
_, exists := m.upLinks[ifName] | ||
if exists { | ||
m.mu.Unlock() | ||
continue | ||
} | ||
m.upLinks[ifName] = true | ||
for _, callback := range m.callbacks { | ||
matched, err := path.Match(callback.pattern, ifName) | ||
if err != nil || !matched { | ||
continue | ||
} | ||
if callback.newCallback != nil { | ||
callback.newCallback(update.Link) | ||
} | ||
} | ||
m.mu.Unlock() | ||
|
||
case unix.RTM_DELLINK: | ||
m.mu.Lock() | ||
delete(m.upLinks, ifName) | ||
for _, callback := range m.callbacks { | ||
matched, err := path.Match(callback.pattern, ifName) | ||
if err != nil || !matched { | ||
continue | ||
} | ||
if callback.delCallback != nil { | ||
callback.delCallback(update.Link) | ||
} | ||
} | ||
m.mu.Unlock() | ||
} | ||
} | ||
} | ||
} | ||
|
||
func (m *InterfaceManager) RegisterWithPattern(pattern string, initCallback func(netlink.Link), newCallback func(netlink.Link), delCallback func(netlink.Link)) { | ||
m.mu.Lock() | ||
defer m.mu.Unlock() | ||
|
||
links, err := netlink.LinkList() | ||
if err == nil { | ||
for _, link := range links { | ||
ifname := link.Attrs().Name | ||
if matched, err := path.Match(pattern, ifname); err == nil && matched { | ||
m.upLinks[ifname] = true | ||
|
||
if initCallback != nil { | ||
initCallback(link) | ||
} | ||
} | ||
} | ||
} else { | ||
m.log.Errorf("Failed to get link list: %v", err) | ||
} | ||
|
||
m.callbacks = append(m.callbacks, callbackSet{ | ||
pattern: pattern, | ||
newCallback: newCallback, | ||
delCallback: delCallback, | ||
}) | ||
} | ||
|
||
func (m *InterfaceManager) Register(ifname string, initCallback func(netlink.Link), newCallback func(netlink.Link), delCallback func(netlink.Link)) { | ||
m.mu.Lock() | ||
defer m.mu.Unlock() | ||
|
||
link, err := netlink.LinkByName(ifname) | ||
if err == nil { | ||
m.upLinks[ifname] = true | ||
|
||
if initCallback != nil { | ||
initCallback(link) | ||
} | ||
} | ||
|
||
m.callbacks = append(m.callbacks, callbackSet{ | ||
pattern: ifname, | ||
newCallback: newCallback, | ||
delCallback: delCallback, | ||
}) | ||
} | ||
|
||
// Close cancels the context to stop the monitor goroutine | ||
func (m *InterfaceManager) Close() error { | ||
m.close() | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters