mirror of https://github.com/vishvananda/netlink
Add more variant with options to subscribe functions
For link, address, route, add a `WithOptions` variant to the `*Subscribe()` function to specify a namespace and an error callback. Those options can be extended in the future without adding more functions. For example, it could be possible to subscribe only for a given family by adding a `Family` member to the appropriate struct. As a minor change, the private function is always suffixed by `At`, since it was the case for route and raw netlink functions (but not for address and link).
This commit is contained in:
parent
46962a8c5d
commit
c684918a4f
|
@ -236,16 +236,34 @@ type AddrUpdate struct {
|
|||
// AddrSubscribe takes a chan down which notifications will be sent
|
||||
// when addresses change. Close the 'done' chan to stop subscription.
|
||||
func AddrSubscribe(ch chan<- AddrUpdate, done <-chan struct{}) error {
|
||||
return addrSubscribe(netns.None(), netns.None(), ch, done, nil)
|
||||
return addrSubscribeAt(netns.None(), netns.None(), ch, done, nil)
|
||||
}
|
||||
|
||||
// AddrSubscribeAt works like AddrSubscribe plus it allows the caller
|
||||
// to choose the network namespace in which to subscribe (ns).
|
||||
func AddrSubscribeAt(ns netns.NsHandle, ch chan<- AddrUpdate, done <-chan struct{}) error {
|
||||
return addrSubscribe(ns, netns.None(), ch, done, nil)
|
||||
return addrSubscribeAt(ns, netns.None(), ch, done, nil)
|
||||
}
|
||||
|
||||
func addrSubscribe(newNs, curNs netns.NsHandle, ch chan<- AddrUpdate, done <-chan struct{}, cberr func(error)) error {
|
||||
// AddrSubscribeOptions contains a set of options to use with
|
||||
// AddrSubscribeWithOptions.
|
||||
type AddrSubscribeOptions struct {
|
||||
Namespace *netns.NsHandle
|
||||
ErrorCallback func(error)
|
||||
}
|
||||
|
||||
// AddrSubscribeWithOptions work like AddrSubscribe but enable to
|
||||
// provide additional options to modify the behavior. Currently, the
|
||||
// namespace can be provided as well as an error callback.
|
||||
func AddrSubscribeWithOptions(ch chan<- AddrUpdate, done <-chan struct{}, options AddrSubscribeOptions) error {
|
||||
if options.Namespace == nil {
|
||||
none := netns.None()
|
||||
options.Namespace = &none
|
||||
}
|
||||
return addrSubscribeAt(*options.Namespace, netns.None(), ch, done, options.ErrorCallback)
|
||||
}
|
||||
|
||||
func addrSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- AddrUpdate, done <-chan struct{}, cberr func(error)) error {
|
||||
s, err := nl.SubscribeAt(newNs, curNs, syscall.NETLINK_ROUTE, syscall.RTNLGRP_IPV4_IFADDR, syscall.RTNLGRP_IPV6_IFADDR)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
53
addr_test.go
53
addr_test.go
|
@ -7,6 +7,7 @@ import (
|
|||
"os"
|
||||
"syscall"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestAddrAdd(t *testing.T) {
|
||||
|
@ -191,3 +192,55 @@ func TestAddrAddReplace(t *testing.T) {
|
|||
t.Fatal("Address not removed properly")
|
||||
}
|
||||
}
|
||||
|
||||
func expectAddrUpdate(ch <-chan AddrUpdate, add bool, dst net.IP) bool {
|
||||
for {
|
||||
timeout := time.After(time.Minute)
|
||||
select {
|
||||
case update := <-ch:
|
||||
if update.NewAddr == add && update.LinkAddress.IP.Equal(dst) {
|
||||
return true
|
||||
}
|
||||
case <-timeout:
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestAddrSubscribeWithOptions(t *testing.T) {
|
||||
tearDown := setUpNetlinkTest(t)
|
||||
defer tearDown()
|
||||
|
||||
ch := make(chan AddrUpdate)
|
||||
done := make(chan struct{})
|
||||
defer close(done)
|
||||
var lastError error
|
||||
defer func() {
|
||||
if lastError != nil {
|
||||
t.Fatalf("Fatal error received during subscription: %v", lastError)
|
||||
}
|
||||
}()
|
||||
if err := AddrSubscribeWithOptions(ch, done, AddrSubscribeOptions{
|
||||
ErrorCallback: func(err error) {
|
||||
lastError = err
|
||||
},
|
||||
}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// get loopback interface
|
||||
link, err := LinkByName("lo")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// bring the interface up
|
||||
if err = LinkSetUp(link); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
ip := net.IPv4(127, 0, 0, 1)
|
||||
if !expectAddrUpdate(ch, true, ip) {
|
||||
t.Fatal("Add update not received as expected")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1328,16 +1328,34 @@ type LinkUpdate struct {
|
|||
// LinkSubscribe takes a chan down which notifications will be sent
|
||||
// when links change. Close the 'done' chan to stop subscription.
|
||||
func LinkSubscribe(ch chan<- LinkUpdate, done <-chan struct{}) error {
|
||||
return linkSubscribe(netns.None(), netns.None(), ch, done, nil)
|
||||
return linkSubscribeAt(netns.None(), netns.None(), ch, done, nil)
|
||||
}
|
||||
|
||||
// LinkSubscribeAt works like LinkSubscribe plus it allows the caller
|
||||
// to choose the network namespace in which to subscribe (ns).
|
||||
func LinkSubscribeAt(ns netns.NsHandle, ch chan<- LinkUpdate, done <-chan struct{}) error {
|
||||
return linkSubscribe(ns, netns.None(), ch, done, nil)
|
||||
return linkSubscribeAt(ns, netns.None(), ch, done, nil)
|
||||
}
|
||||
|
||||
func linkSubscribe(newNs, curNs netns.NsHandle, ch chan<- LinkUpdate, done <-chan struct{}, cberr func(error)) error {
|
||||
// LinkSubscribeOptions contains a set of options to use with
|
||||
// LinkSubscribeWithOptions.
|
||||
type LinkSubscribeOptions struct {
|
||||
Namespace *netns.NsHandle
|
||||
ErrorCallback func(error)
|
||||
}
|
||||
|
||||
// LinkSubscribeWithOptions work like LinkSubscribe but enable to
|
||||
// provide additional options to modify the behavior. Currently, the
|
||||
// namespace can be provided as well as an error callback.
|
||||
func LinkSubscribeWithOptions(ch chan<- LinkUpdate, done <-chan struct{}, options LinkSubscribeOptions) error {
|
||||
if options.Namespace == nil {
|
||||
none := netns.None()
|
||||
options.Namespace = &none
|
||||
}
|
||||
return linkSubscribeAt(*options.Namespace, netns.None(), ch, done, options.ErrorCallback)
|
||||
}
|
||||
|
||||
func linkSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- LinkUpdate, done <-chan struct{}, cberr func(error)) error {
|
||||
s, err := nl.SubscribeAt(newNs, curNs, syscall.NETLINK_ROUTE, syscall.RTNLGRP_LINK)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
31
link_test.go
31
link_test.go
|
@ -1038,6 +1038,37 @@ func TestLinkSubscribe(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestLinkSubscribeWithOptions(t *testing.T) {
|
||||
tearDown := setUpNetlinkTest(t)
|
||||
defer tearDown()
|
||||
|
||||
ch := make(chan LinkUpdate)
|
||||
done := make(chan struct{})
|
||||
defer close(done)
|
||||
var lastError error
|
||||
defer func() {
|
||||
if lastError != nil {
|
||||
t.Fatalf("Fatal error received during subscription: %v", lastError)
|
||||
}
|
||||
}()
|
||||
if err := LinkSubscribeWithOptions(ch, done, LinkSubscribeOptions{
|
||||
ErrorCallback: func(err error) {
|
||||
lastError = err
|
||||
},
|
||||
}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
link := &Veth{LinkAttrs{Name: "foo", TxQLen: testTxQLen, MTU: 1400}, "bar"}
|
||||
if err := LinkAdd(link); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !expectLinkUpdate(ch, "foo", false) {
|
||||
t.Fatal("Add update not received as expected")
|
||||
}
|
||||
}
|
||||
|
||||
func TestLinkSubscribeAt(t *testing.T) {
|
||||
skipUnlessRoot(t)
|
||||
|
||||
|
|
|
@ -687,6 +687,24 @@ func RouteSubscribeAt(ns netns.NsHandle, ch chan<- RouteUpdate, done <-chan stru
|
|||
return routeSubscribeAt(ns, netns.None(), ch, done, nil)
|
||||
}
|
||||
|
||||
// RouteSubscribeOptions contains a set of options to use with
|
||||
// RouteSubscribeWithOptions.
|
||||
type RouteSubscribeOptions struct {
|
||||
Namespace *netns.NsHandle
|
||||
ErrorCallback func(error)
|
||||
}
|
||||
|
||||
// RouteSubscribeWithOptions work like RouteSubscribe but enable to
|
||||
// provide additional options to modify the behavior. Currently, the
|
||||
// namespace can be provided as well as an error callback.
|
||||
func RouteSubscribeWithOptions(ch chan<- RouteUpdate, done <-chan struct{}, options RouteSubscribeOptions) error {
|
||||
if options.Namespace == nil {
|
||||
none := netns.None()
|
||||
options.Namespace = &none
|
||||
}
|
||||
return routeSubscribeAt(*options.Namespace, netns.None(), ch, done, options.ErrorCallback)
|
||||
}
|
||||
|
||||
func routeSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- RouteUpdate, done <-chan struct{}, cberr func(error)) error {
|
||||
s, err := nl.SubscribeAt(newNs, curNs, syscall.NETLINK_ROUTE, syscall.RTNLGRP_IPV4_ROUTE, syscall.RTNLGRP_IPV6_ROUTE)
|
||||
if err != nil {
|
||||
|
|
|
@ -210,6 +210,55 @@ func TestRouteSubscribe(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestRouteSubscribeWithOptions(t *testing.T) {
|
||||
tearDown := setUpNetlinkTest(t)
|
||||
defer tearDown()
|
||||
|
||||
ch := make(chan RouteUpdate)
|
||||
done := make(chan struct{})
|
||||
defer close(done)
|
||||
var lastError error
|
||||
defer func() {
|
||||
if lastError != nil {
|
||||
t.Fatalf("Fatal error received during subscription: %v", lastError)
|
||||
}
|
||||
}()
|
||||
if err := RouteSubscribeWithOptions(ch, done, RouteSubscribeOptions{
|
||||
ErrorCallback: func(err error) {
|
||||
lastError = err
|
||||
},
|
||||
}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// get loopback interface
|
||||
link, err := LinkByName("lo")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// bring the interface up
|
||||
if err = LinkSetUp(link); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// add a gateway route
|
||||
dst := &net.IPNet{
|
||||
IP: net.IPv4(192, 168, 0, 0),
|
||||
Mask: net.CIDRMask(24, 32),
|
||||
}
|
||||
|
||||
ip := net.IPv4(127, 1, 1, 1)
|
||||
route := Route{LinkIndex: link.Attrs().Index, Dst: dst, Src: ip}
|
||||
if err := RouteAdd(&route); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !expectRouteUpdate(ch, syscall.RTM_NEWROUTE, dst.IP) {
|
||||
t.Fatal("Add update not received as expected")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRouteSubscribeAt(t *testing.T) {
|
||||
skipUnlessRoot(t)
|
||||
|
||||
|
|
Loading…
Reference in New Issue