Skip to content

Commit 084abd9

Browse files
robmryaboch
authored andcommitted
Add ErrDumpInterrupted
Add a specific error to report that a netlink response had NLM_F_DUMP_INTR set, indicating that the set of results may be incomplete or inconsistent. unix.EINTR was previously returned (with no results) when the NLM_F_DUMP_INTR flag was set. Now, errors.Is(err, unix.EINTR) will still work. But, this will be a breaking change for any code that's checking for equality with unix.EINTR. Return results with ErrDumpInterrupted. Results may be incomplete or inconsistent, but give the caller the option of using them. Look for NLM_F_DUMP_INTR in more places: - linkSubscribeAt, neighSubscribeAt, routeSubscribeAt - can do an initial dump, which may report inconsistent results -> if there's an error callback, call it with ErrDumpInterrupted - socketDiagXDPExecutor - makes an NLM_F_DUMP request, without using Execute() -> give it the same behaviour as functions that do use Execute() Signed-off-by: Rob Murray <[email protected]>
1 parent a018296 commit 084abd9

24 files changed

+465
-146
lines changed

addr_linux.go

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package netlink
22

33
import (
4+
"errors"
45
"fmt"
56
"net"
67
"strings"
@@ -169,21 +170,27 @@ func (h *Handle) addrHandle(link Link, addr *Addr, req *nl.NetlinkRequest) error
169170
// AddrList gets a list of IP addresses in the system.
170171
// Equivalent to: `ip addr show`.
171172
// The list can be filtered by link and ip family.
173+
//
174+
// If the returned error is [ErrDumpInterrupted], results may be inconsistent
175+
// or incomplete.
172176
func AddrList(link Link, family int) ([]Addr, error) {
173177
return pkgHandle.AddrList(link, family)
174178
}
175179

176180
// AddrList gets a list of IP addresses in the system.
177181
// Equivalent to: `ip addr show`.
178182
// The list can be filtered by link and ip family.
183+
//
184+
// If the returned error is [ErrDumpInterrupted], results may be inconsistent
185+
// or incomplete.
179186
func (h *Handle) AddrList(link Link, family int) ([]Addr, error) {
180187
req := h.newNetlinkRequest(unix.RTM_GETADDR, unix.NLM_F_DUMP)
181188
msg := nl.NewIfAddrmsg(family)
182189
req.AddData(msg)
183190

184-
msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWADDR)
185-
if err != nil {
186-
return nil, err
191+
msgs, executeErr := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWADDR)
192+
if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
193+
return nil, executeErr
187194
}
188195

189196
indexFilter := 0
@@ -212,7 +219,7 @@ func (h *Handle) AddrList(link Link, family int) ([]Addr, error) {
212219
res = append(res, addr)
213220
}
214221

215-
return res, nil
222+
return res, executeErr
216223
}
217224

218225
func parseAddr(m []byte) (addr Addr, family int, err error) {

bridge_linux.go

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package netlink
22

33
import (
4+
"errors"
45
"fmt"
56

67
"github.com/vishvananda/netlink/nl"
@@ -9,21 +10,27 @@ import (
910

1011
// BridgeVlanList gets a map of device id to bridge vlan infos.
1112
// Equivalent to: `bridge vlan show`
13+
//
14+
// If the returned error is [ErrDumpInterrupted], results may be inconsistent
15+
// or incomplete.
1216
func BridgeVlanList() (map[int32][]*nl.BridgeVlanInfo, error) {
1317
return pkgHandle.BridgeVlanList()
1418
}
1519

1620
// BridgeVlanList gets a map of device id to bridge vlan infos.
1721
// Equivalent to: `bridge vlan show`
22+
//
23+
// If the returned error is [ErrDumpInterrupted], results may be inconsistent
24+
// or incomplete.
1825
func (h *Handle) BridgeVlanList() (map[int32][]*nl.BridgeVlanInfo, error) {
1926
req := h.newNetlinkRequest(unix.RTM_GETLINK, unix.NLM_F_DUMP)
2027
msg := nl.NewIfInfomsg(unix.AF_BRIDGE)
2128
req.AddData(msg)
2229
req.AddData(nl.NewRtAttr(unix.IFLA_EXT_MASK, nl.Uint32Attr(uint32(nl.RTEXT_FILTER_BRVLAN))))
2330

24-
msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWLINK)
25-
if err != nil {
26-
return nil, err
31+
msgs, executeErr := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWLINK)
32+
if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
33+
return nil, executeErr
2734
}
2835
ret := make(map[int32][]*nl.BridgeVlanInfo)
2936
for _, m := range msgs {
@@ -51,7 +58,7 @@ func (h *Handle) BridgeVlanList() (map[int32][]*nl.BridgeVlanInfo, error) {
5158
}
5259
}
5360
}
54-
return ret, nil
61+
return ret, executeErr
5562
}
5663

5764
// BridgeVlanAdd adds a new vlan filter entry

chain_linux.go

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package netlink
22

33
import (
4+
"errors"
5+
46
"github.com/vishvananda/netlink/nl"
57
"golang.org/x/sys/unix"
68
)
@@ -56,13 +58,19 @@ func (h *Handle) chainModify(cmd, flags int, link Link, chain Chain) error {
5658
// ChainList gets a list of chains in the system.
5759
// Equivalent to: `tc chain list`.
5860
// The list can be filtered by link.
61+
//
62+
// If the returned error is [ErrDumpInterrupted], results may be inconsistent
63+
// or incomplete.
5964
func ChainList(link Link, parent uint32) ([]Chain, error) {
6065
return pkgHandle.ChainList(link, parent)
6166
}
6267

6368
// ChainList gets a list of chains in the system.
6469
// Equivalent to: `tc chain list`.
6570
// The list can be filtered by link.
71+
//
72+
// If the returned error is [ErrDumpInterrupted], results may be inconsistent
73+
// or incomplete.
6674
func (h *Handle) ChainList(link Link, parent uint32) ([]Chain, error) {
6775
req := h.newNetlinkRequest(unix.RTM_GETCHAIN, unix.NLM_F_DUMP)
6876
index := int32(0)
@@ -78,9 +86,9 @@ func (h *Handle) ChainList(link Link, parent uint32) ([]Chain, error) {
7886
}
7987
req.AddData(msg)
8088

81-
msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWCHAIN)
82-
if err != nil {
83-
return nil, err
89+
msgs, executeErr := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWCHAIN)
90+
if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
91+
return nil, executeErr
8492
}
8593

8694
var res []Chain
@@ -108,5 +116,5 @@ func (h *Handle) ChainList(link Link, parent uint32) ([]Chain, error) {
108116
res = append(res, chain)
109117
}
110118

111-
return res, nil
119+
return res, executeErr
112120
}

class_linux.go

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -201,14 +201,20 @@ func classPayload(req *nl.NetlinkRequest, class Class) error {
201201

202202
// ClassList gets a list of classes in the system.
203203
// Equivalent to: `tc class show`.
204+
//
204205
// Generally returns nothing if link and parent are not specified.
206+
// If the returned error is [ErrDumpInterrupted], results may be inconsistent
207+
// or incomplete.
205208
func ClassList(link Link, parent uint32) ([]Class, error) {
206209
return pkgHandle.ClassList(link, parent)
207210
}
208211

209212
// ClassList gets a list of classes in the system.
210213
// Equivalent to: `tc class show`.
214+
//
211215
// Generally returns nothing if link and parent are not specified.
216+
// If the returned error is [ErrDumpInterrupted], results may be inconsistent
217+
// or incomplete.
212218
func (h *Handle) ClassList(link Link, parent uint32) ([]Class, error) {
213219
req := h.newNetlinkRequest(unix.RTM_GETTCLASS, unix.NLM_F_DUMP)
214220
msg := &nl.TcMsg{
@@ -222,9 +228,9 @@ func (h *Handle) ClassList(link Link, parent uint32) ([]Class, error) {
222228
}
223229
req.AddData(msg)
224230

225-
msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWTCLASS)
226-
if err != nil {
227-
return nil, err
231+
msgs, executeErr := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWTCLASS)
232+
if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
233+
return nil, executeErr
228234
}
229235

230236
var res []Class
@@ -295,7 +301,7 @@ func (h *Handle) ClassList(link Link, parent uint32) ([]Class, error) {
295301
res = append(res, class)
296302
}
297303

298-
return res, nil
304+
return res, executeErr
299305
}
300306

301307
func parseHtbClassData(class Class, data []syscall.NetlinkRouteAttr) (bool, error) {

conntrack_linux.go

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ type InetFamily uint8
4545

4646
// ConntrackTableList returns the flow list of a table of a specific family
4747
// conntrack -L [table] [options] List conntrack or expectation table
48+
//
49+
// If the returned error is [ErrDumpInterrupted], results may be inconsistent
50+
// or incomplete.
4851
func ConntrackTableList(table ConntrackTableType, family InetFamily) ([]*ConntrackFlow, error) {
4952
return pkgHandle.ConntrackTableList(table, family)
5053
}
@@ -84,10 +87,13 @@ func ConntrackDeleteFilters(table ConntrackTableType, family InetFamily, filters
8487

8588
// ConntrackTableList returns the flow list of a table of a specific family using the netlink handle passed
8689
// conntrack -L [table] [options] List conntrack or expectation table
90+
//
91+
// If the returned error is [ErrDumpInterrupted], results may be inconsistent
92+
// or incomplete.
8793
func (h *Handle) ConntrackTableList(table ConntrackTableType, family InetFamily) ([]*ConntrackFlow, error) {
88-
res, err := h.dumpConntrackTable(table, family)
89-
if err != nil {
90-
return nil, err
94+
res, executeErr := h.dumpConntrackTable(table, family)
95+
if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
96+
return nil, executeErr
9197
}
9298

9399
// Deserialize all the flows
@@ -96,7 +102,7 @@ func (h *Handle) ConntrackTableList(table ConntrackTableType, family InetFamily)
96102
result = append(result, parseRawData(dataRaw))
97103
}
98104

99-
return result, nil
105+
return result, executeErr
100106
}
101107

102108
// ConntrackTableFlush flushes all the flows of a specified table using the netlink handle passed

devlink_linux.go

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package netlink
22

33
import (
4+
"errors"
45
"fmt"
56
"net"
67
"strings"
@@ -466,6 +467,8 @@ func (h *Handle) getEswitchAttrs(family *GenlFamily, dev *DevlinkDevice) {
466467

467468
// DevLinkGetDeviceList provides a pointer to devlink devices and nil error,
468469
// otherwise returns an error code.
470+
// If the returned error is [ErrDumpInterrupted], results may be inconsistent
471+
// or incomplete.
469472
func (h *Handle) DevLinkGetDeviceList() ([]*DevlinkDevice, error) {
470473
f, err := h.GenlFamilyGet(nl.GENL_DEVLINK_NAME)
471474
if err != nil {
@@ -478,9 +481,9 @@ func (h *Handle) DevLinkGetDeviceList() ([]*DevlinkDevice, error) {
478481
req := h.newNetlinkRequest(int(f.ID),
479482
unix.NLM_F_REQUEST|unix.NLM_F_ACK|unix.NLM_F_DUMP)
480483
req.AddData(msg)
481-
msgs, err := req.Execute(unix.NETLINK_GENERIC, 0)
482-
if err != nil {
483-
return nil, err
484+
msgs, executeErr := req.Execute(unix.NETLINK_GENERIC, 0)
485+
if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
486+
return nil, executeErr
484487
}
485488
devices, err := parseDevLinkDeviceList(msgs)
486489
if err != nil {
@@ -489,11 +492,14 @@ func (h *Handle) DevLinkGetDeviceList() ([]*DevlinkDevice, error) {
489492
for _, d := range devices {
490493
h.getEswitchAttrs(f, d)
491494
}
492-
return devices, nil
495+
return devices, executeErr
493496
}
494497

495498
// DevLinkGetDeviceList provides a pointer to devlink devices and nil error,
496499
// otherwise returns an error code.
500+
//
501+
// If the returned error is [ErrDumpInterrupted], results may be inconsistent
502+
// or incomplete.
497503
func DevLinkGetDeviceList() ([]*DevlinkDevice, error) {
498504
return pkgHandle.DevLinkGetDeviceList()
499505
}
@@ -646,6 +652,8 @@ func parseDevLinkAllPortList(msgs [][]byte) ([]*DevlinkPort, error) {
646652

647653
// DevLinkGetPortList provides a pointer to devlink ports and nil error,
648654
// otherwise returns an error code.
655+
// If the returned error is [ErrDumpInterrupted], results may be inconsistent
656+
// or incomplete.
649657
func (h *Handle) DevLinkGetAllPortList() ([]*DevlinkPort, error) {
650658
f, err := h.GenlFamilyGet(nl.GENL_DEVLINK_NAME)
651659
if err != nil {
@@ -658,19 +666,21 @@ func (h *Handle) DevLinkGetAllPortList() ([]*DevlinkPort, error) {
658666
req := h.newNetlinkRequest(int(f.ID),
659667
unix.NLM_F_REQUEST|unix.NLM_F_ACK|unix.NLM_F_DUMP)
660668
req.AddData(msg)
661-
msgs, err := req.Execute(unix.NETLINK_GENERIC, 0)
662-
if err != nil {
663-
return nil, err
669+
msgs, executeErr := req.Execute(unix.NETLINK_GENERIC, 0)
670+
if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
671+
return nil, executeErr
664672
}
665673
ports, err := parseDevLinkAllPortList(msgs)
666674
if err != nil {
667675
return nil, err
668676
}
669-
return ports, nil
677+
return ports, executeErr
670678
}
671679

672680
// DevLinkGetPortList provides a pointer to devlink ports and nil error,
673681
// otherwise returns an error code.
682+
// If the returned error is [ErrDumpInterrupted], results may be inconsistent
683+
// or incomplete.
674684
func DevLinkGetAllPortList() ([]*DevlinkPort, error) {
675685
return pkgHandle.DevLinkGetAllPortList()
676686
}
@@ -738,15 +748,18 @@ func (h *Handle) DevlinkGetDeviceResources(bus string, device string) (*DevlinkR
738748

739749
// DevlinkGetDeviceParams returns parameters for devlink device
740750
// Equivalent to: `devlink dev param show <bus>/<device>`
751+
//
752+
// If the returned error is [ErrDumpInterrupted], results may be inconsistent
753+
// or incomplete.
741754
func (h *Handle) DevlinkGetDeviceParams(bus string, device string) ([]*DevlinkParam, error) {
742755
_, req, err := h.createCmdReq(nl.DEVLINK_CMD_PARAM_GET, bus, device)
743756
if err != nil {
744757
return nil, err
745758
}
746759
req.Flags |= unix.NLM_F_DUMP
747-
respmsg, err := req.Execute(unix.NETLINK_GENERIC, 0)
748-
if err != nil {
749-
return nil, err
760+
respmsg, executeErr := req.Execute(unix.NETLINK_GENERIC, 0)
761+
if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
762+
return nil, executeErr
750763
}
751764
var params []*DevlinkParam
752765
for _, m := range respmsg {
@@ -761,11 +774,14 @@ func (h *Handle) DevlinkGetDeviceParams(bus string, device string) ([]*DevlinkPa
761774
params = append(params, p)
762775
}
763776

764-
return params, nil
777+
return params, executeErr
765778
}
766779

767780
// DevlinkGetDeviceParams returns parameters for devlink device
768781
// Equivalent to: `devlink dev param show <bus>/<device>`
782+
//
783+
// If the returned error is [ErrDumpInterrupted], results may be inconsistent
784+
// or incomplete.
769785
func DevlinkGetDeviceParams(bus string, device string) ([]*DevlinkParam, error) {
770786
return pkgHandle.DevlinkGetDeviceParams(bus, device)
771787
}

filter_linux.go

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -405,14 +405,20 @@ func (h *Handle) filterModify(filter Filter, proto, flags int) error {
405405

406406
// FilterList gets a list of filters in the system.
407407
// Equivalent to: `tc filter show`.
408+
//
408409
// Generally returns nothing if link and parent are not specified.
410+
// If the returned error is [ErrDumpInterrupted], results may be inconsistent
411+
// or incomplete.
409412
func FilterList(link Link, parent uint32) ([]Filter, error) {
410413
return pkgHandle.FilterList(link, parent)
411414
}
412415

413416
// FilterList gets a list of filters in the system.
414417
// Equivalent to: `tc filter show`.
418+
//
415419
// Generally returns nothing if link and parent are not specified.
420+
// If the returned error is [ErrDumpInterrupted], results may be inconsistent
421+
// or incomplete.
416422
func (h *Handle) FilterList(link Link, parent uint32) ([]Filter, error) {
417423
req := h.newNetlinkRequest(unix.RTM_GETTFILTER, unix.NLM_F_DUMP)
418424
msg := &nl.TcMsg{
@@ -426,9 +432,9 @@ func (h *Handle) FilterList(link Link, parent uint32) ([]Filter, error) {
426432
}
427433
req.AddData(msg)
428434

429-
msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWTFILTER)
430-
if err != nil {
431-
return nil, err
435+
msgs, executeErr := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWTFILTER)
436+
if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
437+
return nil, executeErr
432438
}
433439

434440
var res []Filter
@@ -516,7 +522,7 @@ func (h *Handle) FilterList(link Link, parent uint32) ([]Filter, error) {
516522
}
517523
}
518524

519-
return res, nil
525+
return res, executeErr
520526
}
521527

522528
func toTcGen(attrs *ActionAttrs, tcgen *nl.TcGen) {

0 commit comments

Comments
 (0)