mirror of https://github.com/vishvananda/netlink
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 <rob.murray@docker.com>
This commit is contained in:
parent
a01829657b
commit
084abd93d3
|
@ -1,6 +1,7 @@
|
|||
package netlink
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
|
@ -169,6 +170,9 @@ func (h *Handle) addrHandle(link Link, addr *Addr, req *nl.NetlinkRequest) error
|
|||
// AddrList gets a list of IP addresses in the system.
|
||||
// Equivalent to: `ip addr show`.
|
||||
// The list can be filtered by link and ip family.
|
||||
//
|
||||
// If the returned error is [ErrDumpInterrupted], results may be inconsistent
|
||||
// or incomplete.
|
||||
func AddrList(link Link, family int) ([]Addr, error) {
|
||||
return pkgHandle.AddrList(link, family)
|
||||
}
|
||||
|
@ -176,14 +180,17 @@ func AddrList(link Link, family int) ([]Addr, error) {
|
|||
// AddrList gets a list of IP addresses in the system.
|
||||
// Equivalent to: `ip addr show`.
|
||||
// The list can be filtered by link and ip family.
|
||||
//
|
||||
// If the returned error is [ErrDumpInterrupted], results may be inconsistent
|
||||
// or incomplete.
|
||||
func (h *Handle) AddrList(link Link, family int) ([]Addr, error) {
|
||||
req := h.newNetlinkRequest(unix.RTM_GETADDR, unix.NLM_F_DUMP)
|
||||
msg := nl.NewIfAddrmsg(family)
|
||||
req.AddData(msg)
|
||||
|
||||
msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWADDR)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
msgs, executeErr := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWADDR)
|
||||
if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
|
||||
return nil, executeErr
|
||||
}
|
||||
|
||||
indexFilter := 0
|
||||
|
@ -212,7 +219,7 @@ func (h *Handle) AddrList(link Link, family int) ([]Addr, error) {
|
|||
res = append(res, addr)
|
||||
}
|
||||
|
||||
return res, nil
|
||||
return res, executeErr
|
||||
}
|
||||
|
||||
func parseAddr(m []byte) (addr Addr, family int, err error) {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package netlink
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/vishvananda/netlink/nl"
|
||||
|
@ -9,21 +10,27 @@ import (
|
|||
|
||||
// BridgeVlanList gets a map of device id to bridge vlan infos.
|
||||
// Equivalent to: `bridge vlan show`
|
||||
//
|
||||
// If the returned error is [ErrDumpInterrupted], results may be inconsistent
|
||||
// or incomplete.
|
||||
func BridgeVlanList() (map[int32][]*nl.BridgeVlanInfo, error) {
|
||||
return pkgHandle.BridgeVlanList()
|
||||
}
|
||||
|
||||
// BridgeVlanList gets a map of device id to bridge vlan infos.
|
||||
// Equivalent to: `bridge vlan show`
|
||||
//
|
||||
// If the returned error is [ErrDumpInterrupted], results may be inconsistent
|
||||
// or incomplete.
|
||||
func (h *Handle) BridgeVlanList() (map[int32][]*nl.BridgeVlanInfo, error) {
|
||||
req := h.newNetlinkRequest(unix.RTM_GETLINK, unix.NLM_F_DUMP)
|
||||
msg := nl.NewIfInfomsg(unix.AF_BRIDGE)
|
||||
req.AddData(msg)
|
||||
req.AddData(nl.NewRtAttr(unix.IFLA_EXT_MASK, nl.Uint32Attr(uint32(nl.RTEXT_FILTER_BRVLAN))))
|
||||
|
||||
msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWLINK)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
msgs, executeErr := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWLINK)
|
||||
if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
|
||||
return nil, executeErr
|
||||
}
|
||||
ret := make(map[int32][]*nl.BridgeVlanInfo)
|
||||
for _, m := range msgs {
|
||||
|
@ -51,7 +58,7 @@ func (h *Handle) BridgeVlanList() (map[int32][]*nl.BridgeVlanInfo, error) {
|
|||
}
|
||||
}
|
||||
}
|
||||
return ret, nil
|
||||
return ret, executeErr
|
||||
}
|
||||
|
||||
// BridgeVlanAdd adds a new vlan filter entry
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package netlink
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/vishvananda/netlink/nl"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
@ -56,6 +58,9 @@ func (h *Handle) chainModify(cmd, flags int, link Link, chain Chain) error {
|
|||
// ChainList gets a list of chains in the system.
|
||||
// Equivalent to: `tc chain list`.
|
||||
// The list can be filtered by link.
|
||||
//
|
||||
// If the returned error is [ErrDumpInterrupted], results may be inconsistent
|
||||
// or incomplete.
|
||||
func ChainList(link Link, parent uint32) ([]Chain, error) {
|
||||
return pkgHandle.ChainList(link, parent)
|
||||
}
|
||||
|
@ -63,6 +68,9 @@ func ChainList(link Link, parent uint32) ([]Chain, error) {
|
|||
// ChainList gets a list of chains in the system.
|
||||
// Equivalent to: `tc chain list`.
|
||||
// The list can be filtered by link.
|
||||
//
|
||||
// If the returned error is [ErrDumpInterrupted], results may be inconsistent
|
||||
// or incomplete.
|
||||
func (h *Handle) ChainList(link Link, parent uint32) ([]Chain, error) {
|
||||
req := h.newNetlinkRequest(unix.RTM_GETCHAIN, unix.NLM_F_DUMP)
|
||||
index := int32(0)
|
||||
|
@ -78,9 +86,9 @@ func (h *Handle) ChainList(link Link, parent uint32) ([]Chain, error) {
|
|||
}
|
||||
req.AddData(msg)
|
||||
|
||||
msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWCHAIN)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
msgs, executeErr := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWCHAIN)
|
||||
if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
|
||||
return nil, executeErr
|
||||
}
|
||||
|
||||
var res []Chain
|
||||
|
@ -108,5 +116,5 @@ func (h *Handle) ChainList(link Link, parent uint32) ([]Chain, error) {
|
|||
res = append(res, chain)
|
||||
}
|
||||
|
||||
return res, nil
|
||||
return res, executeErr
|
||||
}
|
||||
|
|
|
@ -201,14 +201,20 @@ func classPayload(req *nl.NetlinkRequest, class Class) error {
|
|||
|
||||
// ClassList gets a list of classes in the system.
|
||||
// Equivalent to: `tc class show`.
|
||||
//
|
||||
// Generally returns nothing if link and parent are not specified.
|
||||
// If the returned error is [ErrDumpInterrupted], results may be inconsistent
|
||||
// or incomplete.
|
||||
func ClassList(link Link, parent uint32) ([]Class, error) {
|
||||
return pkgHandle.ClassList(link, parent)
|
||||
}
|
||||
|
||||
// ClassList gets a list of classes in the system.
|
||||
// Equivalent to: `tc class show`.
|
||||
//
|
||||
// Generally returns nothing if link and parent are not specified.
|
||||
// If the returned error is [ErrDumpInterrupted], results may be inconsistent
|
||||
// or incomplete.
|
||||
func (h *Handle) ClassList(link Link, parent uint32) ([]Class, error) {
|
||||
req := h.newNetlinkRequest(unix.RTM_GETTCLASS, unix.NLM_F_DUMP)
|
||||
msg := &nl.TcMsg{
|
||||
|
@ -222,9 +228,9 @@ func (h *Handle) ClassList(link Link, parent uint32) ([]Class, error) {
|
|||
}
|
||||
req.AddData(msg)
|
||||
|
||||
msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWTCLASS)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
msgs, executeErr := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWTCLASS)
|
||||
if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
|
||||
return nil, executeErr
|
||||
}
|
||||
|
||||
var res []Class
|
||||
|
@ -295,7 +301,7 @@ func (h *Handle) ClassList(link Link, parent uint32) ([]Class, error) {
|
|||
res = append(res, class)
|
||||
}
|
||||
|
||||
return res, nil
|
||||
return res, executeErr
|
||||
}
|
||||
|
||||
func parseHtbClassData(class Class, data []syscall.NetlinkRouteAttr) (bool, error) {
|
||||
|
|
|
@ -45,6 +45,9 @@ type InetFamily uint8
|
|||
|
||||
// ConntrackTableList returns the flow list of a table of a specific family
|
||||
// conntrack -L [table] [options] List conntrack or expectation table
|
||||
//
|
||||
// If the returned error is [ErrDumpInterrupted], results may be inconsistent
|
||||
// or incomplete.
|
||||
func ConntrackTableList(table ConntrackTableType, family InetFamily) ([]*ConntrackFlow, error) {
|
||||
return pkgHandle.ConntrackTableList(table, family)
|
||||
}
|
||||
|
@ -84,10 +87,13 @@ func ConntrackDeleteFilters(table ConntrackTableType, family InetFamily, filters
|
|||
|
||||
// ConntrackTableList returns the flow list of a table of a specific family using the netlink handle passed
|
||||
// conntrack -L [table] [options] List conntrack or expectation table
|
||||
//
|
||||
// If the returned error is [ErrDumpInterrupted], results may be inconsistent
|
||||
// or incomplete.
|
||||
func (h *Handle) ConntrackTableList(table ConntrackTableType, family InetFamily) ([]*ConntrackFlow, error) {
|
||||
res, err := h.dumpConntrackTable(table, family)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res, executeErr := h.dumpConntrackTable(table, family)
|
||||
if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
|
||||
return nil, executeErr
|
||||
}
|
||||
|
||||
// Deserialize all the flows
|
||||
|
@ -96,7 +102,7 @@ func (h *Handle) ConntrackTableList(table ConntrackTableType, family InetFamily)
|
|||
result = append(result, parseRawData(dataRaw))
|
||||
}
|
||||
|
||||
return result, nil
|
||||
return result, executeErr
|
||||
}
|
||||
|
||||
// ConntrackTableFlush flushes all the flows of a specified table using the netlink handle passed
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package netlink
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
|
@ -466,6 +467,8 @@ func (h *Handle) getEswitchAttrs(family *GenlFamily, dev *DevlinkDevice) {
|
|||
|
||||
// DevLinkGetDeviceList provides a pointer to devlink devices and nil error,
|
||||
// otherwise returns an error code.
|
||||
// If the returned error is [ErrDumpInterrupted], results may be inconsistent
|
||||
// or incomplete.
|
||||
func (h *Handle) DevLinkGetDeviceList() ([]*DevlinkDevice, error) {
|
||||
f, err := h.GenlFamilyGet(nl.GENL_DEVLINK_NAME)
|
||||
if err != nil {
|
||||
|
@ -478,9 +481,9 @@ func (h *Handle) DevLinkGetDeviceList() ([]*DevlinkDevice, error) {
|
|||
req := h.newNetlinkRequest(int(f.ID),
|
||||
unix.NLM_F_REQUEST|unix.NLM_F_ACK|unix.NLM_F_DUMP)
|
||||
req.AddData(msg)
|
||||
msgs, err := req.Execute(unix.NETLINK_GENERIC, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
msgs, executeErr := req.Execute(unix.NETLINK_GENERIC, 0)
|
||||
if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
|
||||
return nil, executeErr
|
||||
}
|
||||
devices, err := parseDevLinkDeviceList(msgs)
|
||||
if err != nil {
|
||||
|
@ -489,11 +492,14 @@ func (h *Handle) DevLinkGetDeviceList() ([]*DevlinkDevice, error) {
|
|||
for _, d := range devices {
|
||||
h.getEswitchAttrs(f, d)
|
||||
}
|
||||
return devices, nil
|
||||
return devices, executeErr
|
||||
}
|
||||
|
||||
// DevLinkGetDeviceList provides a pointer to devlink devices and nil error,
|
||||
// otherwise returns an error code.
|
||||
//
|
||||
// If the returned error is [ErrDumpInterrupted], results may be inconsistent
|
||||
// or incomplete.
|
||||
func DevLinkGetDeviceList() ([]*DevlinkDevice, error) {
|
||||
return pkgHandle.DevLinkGetDeviceList()
|
||||
}
|
||||
|
@ -646,6 +652,8 @@ func parseDevLinkAllPortList(msgs [][]byte) ([]*DevlinkPort, error) {
|
|||
|
||||
// DevLinkGetPortList provides a pointer to devlink ports and nil error,
|
||||
// otherwise returns an error code.
|
||||
// If the returned error is [ErrDumpInterrupted], results may be inconsistent
|
||||
// or incomplete.
|
||||
func (h *Handle) DevLinkGetAllPortList() ([]*DevlinkPort, error) {
|
||||
f, err := h.GenlFamilyGet(nl.GENL_DEVLINK_NAME)
|
||||
if err != nil {
|
||||
|
@ -658,19 +666,21 @@ func (h *Handle) DevLinkGetAllPortList() ([]*DevlinkPort, error) {
|
|||
req := h.newNetlinkRequest(int(f.ID),
|
||||
unix.NLM_F_REQUEST|unix.NLM_F_ACK|unix.NLM_F_DUMP)
|
||||
req.AddData(msg)
|
||||
msgs, err := req.Execute(unix.NETLINK_GENERIC, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
msgs, executeErr := req.Execute(unix.NETLINK_GENERIC, 0)
|
||||
if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
|
||||
return nil, executeErr
|
||||
}
|
||||
ports, err := parseDevLinkAllPortList(msgs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ports, nil
|
||||
return ports, executeErr
|
||||
}
|
||||
|
||||
// DevLinkGetPortList provides a pointer to devlink ports and nil error,
|
||||
// otherwise returns an error code.
|
||||
// If the returned error is [ErrDumpInterrupted], results may be inconsistent
|
||||
// or incomplete.
|
||||
func DevLinkGetAllPortList() ([]*DevlinkPort, error) {
|
||||
return pkgHandle.DevLinkGetAllPortList()
|
||||
}
|
||||
|
@ -738,15 +748,18 @@ func (h *Handle) DevlinkGetDeviceResources(bus string, device string) (*DevlinkR
|
|||
|
||||
// DevlinkGetDeviceParams returns parameters for devlink device
|
||||
// Equivalent to: `devlink dev param show <bus>/<device>`
|
||||
//
|
||||
// If the returned error is [ErrDumpInterrupted], results may be inconsistent
|
||||
// or incomplete.
|
||||
func (h *Handle) DevlinkGetDeviceParams(bus string, device string) ([]*DevlinkParam, error) {
|
||||
_, req, err := h.createCmdReq(nl.DEVLINK_CMD_PARAM_GET, bus, device)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.Flags |= unix.NLM_F_DUMP
|
||||
respmsg, err := req.Execute(unix.NETLINK_GENERIC, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
respmsg, executeErr := req.Execute(unix.NETLINK_GENERIC, 0)
|
||||
if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
|
||||
return nil, executeErr
|
||||
}
|
||||
var params []*DevlinkParam
|
||||
for _, m := range respmsg {
|
||||
|
@ -761,11 +774,14 @@ func (h *Handle) DevlinkGetDeviceParams(bus string, device string) ([]*DevlinkPa
|
|||
params = append(params, p)
|
||||
}
|
||||
|
||||
return params, nil
|
||||
return params, executeErr
|
||||
}
|
||||
|
||||
// DevlinkGetDeviceParams returns parameters for devlink device
|
||||
// Equivalent to: `devlink dev param show <bus>/<device>`
|
||||
//
|
||||
// If the returned error is [ErrDumpInterrupted], results may be inconsistent
|
||||
// or incomplete.
|
||||
func DevlinkGetDeviceParams(bus string, device string) ([]*DevlinkParam, error) {
|
||||
return pkgHandle.DevlinkGetDeviceParams(bus, device)
|
||||
}
|
||||
|
|
|
@ -405,14 +405,20 @@ func (h *Handle) filterModify(filter Filter, proto, flags int) error {
|
|||
|
||||
// FilterList gets a list of filters in the system.
|
||||
// Equivalent to: `tc filter show`.
|
||||
//
|
||||
// Generally returns nothing if link and parent are not specified.
|
||||
// If the returned error is [ErrDumpInterrupted], results may be inconsistent
|
||||
// or incomplete.
|
||||
func FilterList(link Link, parent uint32) ([]Filter, error) {
|
||||
return pkgHandle.FilterList(link, parent)
|
||||
}
|
||||
|
||||
// FilterList gets a list of filters in the system.
|
||||
// Equivalent to: `tc filter show`.
|
||||
//
|
||||
// Generally returns nothing if link and parent are not specified.
|
||||
// If the returned error is [ErrDumpInterrupted], results may be inconsistent
|
||||
// or incomplete.
|
||||
func (h *Handle) FilterList(link Link, parent uint32) ([]Filter, error) {
|
||||
req := h.newNetlinkRequest(unix.RTM_GETTFILTER, unix.NLM_F_DUMP)
|
||||
msg := &nl.TcMsg{
|
||||
|
@ -426,9 +432,9 @@ func (h *Handle) FilterList(link Link, parent uint32) ([]Filter, error) {
|
|||
}
|
||||
req.AddData(msg)
|
||||
|
||||
msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWTFILTER)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
msgs, executeErr := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWTFILTER)
|
||||
if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
|
||||
return nil, executeErr
|
||||
}
|
||||
|
||||
var res []Filter
|
||||
|
@ -516,7 +522,7 @@ func (h *Handle) FilterList(link Link, parent uint32) ([]Filter, error) {
|
|||
}
|
||||
}
|
||||
|
||||
return res, nil
|
||||
return res, executeErr
|
||||
}
|
||||
|
||||
func toTcGen(attrs *ActionAttrs, tcgen *nl.TcGen) {
|
||||
|
|
12
fou_linux.go
12
fou_linux.go
|
@ -137,10 +137,14 @@ func (h *Handle) FouDel(f Fou) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// If the returned error is [ErrDumpInterrupted], results may be inconsistent
|
||||
// or incomplete.
|
||||
func FouList(fam int) ([]Fou, error) {
|
||||
return pkgHandle.FouList(fam)
|
||||
}
|
||||
|
||||
// If the returned error is [ErrDumpInterrupted], results may be inconsistent
|
||||
// or incomplete.
|
||||
func (h *Handle) FouList(fam int) ([]Fou, error) {
|
||||
fam_id, err := FouFamilyId()
|
||||
if err != nil {
|
||||
|
@ -159,9 +163,9 @@ func (h *Handle) FouList(fam int) ([]Fou, error) {
|
|||
|
||||
req.AddRawData(raw)
|
||||
|
||||
msgs, err := req.Execute(unix.NETLINK_GENERIC, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
msgs, executeErr := req.Execute(unix.NETLINK_GENERIC, 0)
|
||||
if executeErr != nil && !errors.Is(err, ErrDumpInterrupted) {
|
||||
return nil, executeErr
|
||||
}
|
||||
|
||||
fous := make([]Fou, 0, len(msgs))
|
||||
|
@ -174,7 +178,7 @@ func (h *Handle) FouList(fam int) ([]Fou, error) {
|
|||
fous = append(fous, f)
|
||||
}
|
||||
|
||||
return fous, nil
|
||||
return fous, executeErr
|
||||
}
|
||||
|
||||
func deserializeFouMsg(msg []byte) (Fou, error) {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package netlink
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"syscall"
|
||||
|
||||
|
@ -126,6 +127,8 @@ func parseFamilies(msgs [][]byte) ([]*GenlFamily, error) {
|
|||
return families, nil
|
||||
}
|
||||
|
||||
// If the returned error is [ErrDumpInterrupted], results may be inconsistent
|
||||
// or incomplete.
|
||||
func (h *Handle) GenlFamilyList() ([]*GenlFamily, error) {
|
||||
msg := &nl.Genlmsg{
|
||||
Command: nl.GENL_CTRL_CMD_GETFAMILY,
|
||||
|
@ -133,13 +136,19 @@ func (h *Handle) GenlFamilyList() ([]*GenlFamily, error) {
|
|||
}
|
||||
req := h.newNetlinkRequest(nl.GENL_ID_CTRL, unix.NLM_F_DUMP)
|
||||
req.AddData(msg)
|
||||
msgs, err := req.Execute(unix.NETLINK_GENERIC, 0)
|
||||
msgs, executeErr := req.Execute(unix.NETLINK_GENERIC, 0)
|
||||
if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
|
||||
return nil, executeErr
|
||||
}
|
||||
families, err := parseFamilies(msgs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return parseFamilies(msgs)
|
||||
return families, executeErr
|
||||
}
|
||||
|
||||
// If the returned error is [ErrDumpInterrupted], results may be inconsistent
|
||||
// or incomplete.
|
||||
func GenlFamilyList() ([]*GenlFamily, error) {
|
||||
return pkgHandle.GenlFamilyList()
|
||||
}
|
||||
|
|
13
gtp_linux.go
13
gtp_linux.go
|
@ -1,6 +1,7 @@
|
|||
package netlink
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
|
@ -74,6 +75,8 @@ func parsePDP(msgs [][]byte) ([]*PDP, error) {
|
|||
return pdps, nil
|
||||
}
|
||||
|
||||
// If the returned error is [ErrDumpInterrupted], results may be inconsistent
|
||||
// or incomplete.
|
||||
func (h *Handle) GTPPDPList() ([]*PDP, error) {
|
||||
f, err := h.GenlFamilyGet(nl.GENL_GTP_NAME)
|
||||
if err != nil {
|
||||
|
@ -85,13 +88,19 @@ func (h *Handle) GTPPDPList() ([]*PDP, error) {
|
|||
}
|
||||
req := h.newNetlinkRequest(int(f.ID), unix.NLM_F_DUMP)
|
||||
req.AddData(msg)
|
||||
msgs, err := req.Execute(unix.NETLINK_GENERIC, 0)
|
||||
msgs, executeErr := req.Execute(unix.NETLINK_GENERIC, 0)
|
||||
if executeErr != nil && !errors.Is(err, ErrDumpInterrupted) {
|
||||
return nil, executeErr
|
||||
}
|
||||
pdps, err := parsePDP(msgs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return parsePDP(msgs)
|
||||
return pdps, executeErr
|
||||
}
|
||||
|
||||
// If the returned error is [ErrDumpInterrupted], results may be inconsistent
|
||||
// or incomplete.
|
||||
func GTPPDPList() ([]*PDP, error) {
|
||||
return pkgHandle.GTPPDPList()
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package netlink
|
|||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
|
@ -1807,20 +1808,20 @@ func (h *Handle) LinkDel(link Link) error {
|
|||
}
|
||||
|
||||
func (h *Handle) linkByNameDump(name string) (Link, error) {
|
||||
links, err := h.LinkList()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
links, executeErr := h.LinkList()
|
||||
if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
|
||||
return nil, executeErr
|
||||
}
|
||||
|
||||
for _, link := range links {
|
||||
if link.Attrs().Name == name {
|
||||
return link, nil
|
||||
return link, executeErr
|
||||
}
|
||||
|
||||
// support finding interfaces also via altnames
|
||||
for _, altName := range link.Attrs().AltNames {
|
||||
if altName == name {
|
||||
return link, nil
|
||||
return link, executeErr
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1828,25 +1829,33 @@ func (h *Handle) linkByNameDump(name string) (Link, error) {
|
|||
}
|
||||
|
||||
func (h *Handle) linkByAliasDump(alias string) (Link, error) {
|
||||
links, err := h.LinkList()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
links, executeErr := h.LinkList()
|
||||
if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
|
||||
return nil, executeErr
|
||||
}
|
||||
|
||||
for _, link := range links {
|
||||
if link.Attrs().Alias == alias {
|
||||
return link, nil
|
||||
return link, executeErr
|
||||
}
|
||||
}
|
||||
return nil, LinkNotFoundError{fmt.Errorf("Link alias %s not found", alias)}
|
||||
}
|
||||
|
||||
// LinkByName finds a link by name and returns a pointer to the object.
|
||||
//
|
||||
// If the kernel doesn't support IFLA_IFNAME, this method will fall back to
|
||||
// filtering a dump of all link names. In this case, if the returned error is
|
||||
// [ErrDumpInterrupted] the result may be missing or outdated.
|
||||
func LinkByName(name string) (Link, error) {
|
||||
return pkgHandle.LinkByName(name)
|
||||
}
|
||||
|
||||
// LinkByName finds a link by name and returns a pointer to the object.
|
||||
//
|
||||
// If the kernel doesn't support IFLA_IFNAME, this method will fall back to
|
||||
// filtering a dump of all link names. In this case, if the returned error is
|
||||
// [ErrDumpInterrupted] the result may be missing or outdated.
|
||||
func (h *Handle) LinkByName(name string) (Link, error) {
|
||||
if h.lookupByDump {
|
||||
return h.linkByNameDump(name)
|
||||
|
@ -1879,12 +1888,20 @@ func (h *Handle) LinkByName(name string) (Link, error) {
|
|||
|
||||
// LinkByAlias finds a link by its alias and returns a pointer to the object.
|
||||
// If there are multiple links with the alias it returns the first one
|
||||
//
|
||||
// If the kernel doesn't support IFLA_IFALIAS, this method will fall back to
|
||||
// filtering a dump of all link names. In this case, if the returned error is
|
||||
// [ErrDumpInterrupted] the result may be missing or outdated.
|
||||
func LinkByAlias(alias string) (Link, error) {
|
||||
return pkgHandle.LinkByAlias(alias)
|
||||
}
|
||||
|
||||
// LinkByAlias finds a link by its alias and returns a pointer to the object.
|
||||
// If there are multiple links with the alias it returns the first one
|
||||
//
|
||||
// If the kernel doesn't support IFLA_IFALIAS, this method will fall back to
|
||||
// filtering a dump of all link names. In this case, if the returned error is
|
||||
// [ErrDumpInterrupted] the result may be missing or outdated.
|
||||
func (h *Handle) LinkByAlias(alias string) (Link, error) {
|
||||
if h.lookupByDump {
|
||||
return h.linkByAliasDump(alias)
|
||||
|
@ -2321,6 +2338,9 @@ func LinkList() ([]Link, error) {
|
|||
|
||||
// LinkList gets a list of link devices.
|
||||
// Equivalent to: `ip link show`
|
||||
//
|
||||
// If the returned error is [ErrDumpInterrupted], results may be inconsistent
|
||||
// or incomplete.
|
||||
func (h *Handle) LinkList() ([]Link, error) {
|
||||
// NOTE(vish): This duplicates functionality in net/iface_linux.go, but we need
|
||||
// to get the message ourselves to parse link type.
|
||||
|
@ -2331,9 +2351,9 @@ func (h *Handle) LinkList() ([]Link, error) {
|
|||
attr := nl.NewRtAttr(unix.IFLA_EXT_MASK, nl.Uint32Attr(nl.RTEXT_FILTER_VF))
|
||||
req.AddData(attr)
|
||||
|
||||
msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWLINK)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
msgs, executeErr := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWLINK)
|
||||
if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
|
||||
return nil, executeErr
|
||||
}
|
||||
|
||||
var res []Link
|
||||
|
@ -2345,7 +2365,7 @@ func (h *Handle) LinkList() ([]Link, error) {
|
|||
res = append(res, link)
|
||||
}
|
||||
|
||||
return res, nil
|
||||
return res, executeErr
|
||||
}
|
||||
|
||||
// LinkUpdate is used to pass information back from LinkSubscribe()
|
||||
|
@ -2381,6 +2401,10 @@ type LinkSubscribeOptions struct {
|
|||
// 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.
|
||||
//
|
||||
// When options.ListExisting is true, options.ErrorCallback may be
|
||||
// called with [ErrDumpInterrupted] to indicate that results from
|
||||
// the initial dump of links may be inconsistent or incomplete.
|
||||
func LinkSubscribeWithOptions(ch chan<- LinkUpdate, done <-chan struct{}, options LinkSubscribeOptions) error {
|
||||
if options.Namespace == nil {
|
||||
none := netns.None()
|
||||
|
@ -2440,6 +2464,9 @@ func linkSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- LinkUpdate, done <-c
|
|||
continue
|
||||
}
|
||||
for _, m := range msgs {
|
||||
if m.Header.Flags&unix.NLM_F_DUMP_INTR != 0 && cberr != nil {
|
||||
cberr(ErrDumpInterrupted)
|
||||
}
|
||||
if m.Header.Type == unix.NLMSG_DONE {
|
||||
continue
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package netlink
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"syscall"
|
||||
|
@ -206,6 +207,9 @@ func neighHandle(neigh *Neigh, req *nl.NetlinkRequest) error {
|
|||
// NeighList returns a list of IP-MAC mappings in the system (ARP table).
|
||||
// Equivalent to: `ip neighbor show`.
|
||||
// The list can be filtered by link and ip family.
|
||||
//
|
||||
// If the returned error is [ErrDumpInterrupted], results may be inconsistent
|
||||
// or incomplete.
|
||||
func NeighList(linkIndex, family int) ([]Neigh, error) {
|
||||
return pkgHandle.NeighList(linkIndex, family)
|
||||
}
|
||||
|
@ -213,6 +217,9 @@ func NeighList(linkIndex, family int) ([]Neigh, error) {
|
|||
// NeighProxyList returns a list of neighbor proxies in the system.
|
||||
// Equivalent to: `ip neighbor show proxy`.
|
||||
// The list can be filtered by link and ip family.
|
||||
//
|
||||
// If the returned error is [ErrDumpInterrupted], results may be inconsistent
|
||||
// or incomplete.
|
||||
func NeighProxyList(linkIndex, family int) ([]Neigh, error) {
|
||||
return pkgHandle.NeighProxyList(linkIndex, family)
|
||||
}
|
||||
|
@ -220,6 +227,9 @@ func NeighProxyList(linkIndex, family int) ([]Neigh, error) {
|
|||
// NeighList returns a list of IP-MAC mappings in the system (ARP table).
|
||||
// Equivalent to: `ip neighbor show`.
|
||||
// The list can be filtered by link and ip family.
|
||||
//
|
||||
// If the returned error is [ErrDumpInterrupted], results may be inconsistent
|
||||
// or incomplete.
|
||||
func (h *Handle) NeighList(linkIndex, family int) ([]Neigh, error) {
|
||||
return h.NeighListExecute(Ndmsg{
|
||||
Family: uint8(family),
|
||||
|
@ -230,6 +240,9 @@ func (h *Handle) NeighList(linkIndex, family int) ([]Neigh, error) {
|
|||
// NeighProxyList returns a list of neighbor proxies in the system.
|
||||
// Equivalent to: `ip neighbor show proxy`.
|
||||
// The list can be filtered by link, ip family.
|
||||
//
|
||||
// If the returned error is [ErrDumpInterrupted], results may be inconsistent
|
||||
// or incomplete.
|
||||
func (h *Handle) NeighProxyList(linkIndex, family int) ([]Neigh, error) {
|
||||
return h.NeighListExecute(Ndmsg{
|
||||
Family: uint8(family),
|
||||
|
@ -239,18 +252,24 @@ func (h *Handle) NeighProxyList(linkIndex, family int) ([]Neigh, error) {
|
|||
}
|
||||
|
||||
// NeighListExecute returns a list of neighbour entries filtered by link, ip family, flag and state.
|
||||
//
|
||||
// If the returned error is [ErrDumpInterrupted], results may be inconsistent
|
||||
// or incomplete.
|
||||
func NeighListExecute(msg Ndmsg) ([]Neigh, error) {
|
||||
return pkgHandle.NeighListExecute(msg)
|
||||
}
|
||||
|
||||
// NeighListExecute returns a list of neighbour entries filtered by link, ip family, flag and state.
|
||||
//
|
||||
// If the returned error is [ErrDumpInterrupted], results may be inconsistent
|
||||
// or incomplete.
|
||||
func (h *Handle) NeighListExecute(msg Ndmsg) ([]Neigh, error) {
|
||||
req := h.newNetlinkRequest(unix.RTM_GETNEIGH, unix.NLM_F_DUMP)
|
||||
req.AddData(&msg)
|
||||
|
||||
msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWNEIGH)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
msgs, executeErr := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWNEIGH)
|
||||
if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
|
||||
return nil, executeErr
|
||||
}
|
||||
|
||||
var res []Neigh
|
||||
|
@ -281,7 +300,7 @@ func (h *Handle) NeighListExecute(msg Ndmsg) ([]Neigh, error) {
|
|||
res = append(res, *neigh)
|
||||
}
|
||||
|
||||
return res, nil
|
||||
return res, executeErr
|
||||
}
|
||||
|
||||
func NeighDeserialize(m []byte) (*Neigh, error) {
|
||||
|
@ -364,6 +383,10 @@ type NeighSubscribeOptions struct {
|
|||
// NeighSubscribeWithOptions work like NeighSubscribe but enable to
|
||||
// provide additional options to modify the behavior. Currently, the
|
||||
// namespace can be provided as well as an error callback.
|
||||
//
|
||||
// When options.ListExisting is true, options.ErrorCallback may be
|
||||
// called with [ErrDumpInterrupted] to indicate that results from
|
||||
// the initial dump of links may be inconsistent or incomplete.
|
||||
func NeighSubscribeWithOptions(ch chan<- NeighUpdate, done <-chan struct{}, options NeighSubscribeOptions) error {
|
||||
if options.Namespace == nil {
|
||||
none := netns.None()
|
||||
|
@ -428,6 +451,9 @@ func neighSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- NeighUpdate, done <
|
|||
continue
|
||||
}
|
||||
for _, m := range msgs {
|
||||
if m.Header.Flags&unix.NLM_F_DUMP_INTR != 0 && cberr != nil {
|
||||
cberr(ErrDumpInterrupted)
|
||||
}
|
||||
if m.Header.Type == unix.NLMSG_DONE {
|
||||
if listExisting {
|
||||
// This will be called after handling AF_UNSPEC
|
||||
|
|
|
@ -9,3 +9,6 @@ const (
|
|||
FAMILY_V6 = nl.FAMILY_V6
|
||||
FAMILY_MPLS = nl.FAMILY_MPLS
|
||||
)
|
||||
|
||||
// ErrDumpInterrupted is an alias for [nl.ErrDumpInterrupted].
|
||||
var ErrDumpInterrupted = nl.ErrDumpInterrupted
|
||||
|
|
|
@ -45,6 +45,26 @@ var SocketTimeoutTv = unix.Timeval{Sec: 60, Usec: 0}
|
|||
// ErrorMessageReporting is the default error message reporting configuration for the new netlink sockets
|
||||
var EnableErrorMessageReporting bool = false
|
||||
|
||||
// ErrDumpInterrupted is an instance of errDumpInterrupted, used to report that
|
||||
// a netlink function has set the NLM_F_DUMP_INTR flag in a response message,
|
||||
// indicating that the results may be incomplete or inconsistent.
|
||||
var ErrDumpInterrupted = errDumpInterrupted{}
|
||||
|
||||
// errDumpInterrupted is an error type, used to report that NLM_F_DUMP_INTR was
|
||||
// set in a netlink response.
|
||||
type errDumpInterrupted struct{}
|
||||
|
||||
func (errDumpInterrupted) Error() string {
|
||||
return "results may be incomplete or inconsistent"
|
||||
}
|
||||
|
||||
// Before errDumpInterrupted was introduced, EINTR was returned when a netlink
|
||||
// response had NLM_F_DUMP_INTR. Retain backward compatibility with code that
|
||||
// may be checking for EINTR using Is.
|
||||
func (e errDumpInterrupted) Is(target error) bool {
|
||||
return target == unix.EINTR
|
||||
}
|
||||
|
||||
// GetIPFamily returns the family type of a net.IP.
|
||||
func GetIPFamily(ip net.IP) int {
|
||||
if len(ip) <= net.IPv4len {
|
||||
|
@ -494,22 +514,26 @@ func (req *NetlinkRequest) AddRawData(data []byte) {
|
|||
// Execute the request against the given sockType.
|
||||
// Returns a list of netlink messages in serialized format, optionally filtered
|
||||
// by resType.
|
||||
// If the returned error is [ErrDumpInterrupted], results may be inconsistent
|
||||
// or incomplete.
|
||||
func (req *NetlinkRequest) Execute(sockType int, resType uint16) ([][]byte, error) {
|
||||
var res [][]byte
|
||||
err := req.ExecuteIter(sockType, resType, func(msg []byte) bool {
|
||||
res = append(res, msg)
|
||||
return true
|
||||
})
|
||||
if err != nil {
|
||||
if err != nil && !errors.Is(err, ErrDumpInterrupted) {
|
||||
return nil, err
|
||||
}
|
||||
return res, nil
|
||||
return res, err
|
||||
}
|
||||
|
||||
// ExecuteIter executes the request against the given sockType.
|
||||
// Calls the provided callback func once for each netlink message.
|
||||
// If the callback returns false, it is not called again, but
|
||||
// the remaining messages are consumed/discarded.
|
||||
// If the returned error is [ErrDumpInterrupted], results may be inconsistent
|
||||
// or incomplete.
|
||||
//
|
||||
// Thread safety: ExecuteIter holds a lock on the socket until
|
||||
// it finishes iteration so the callback must not call back into
|
||||
|
@ -561,6 +585,8 @@ func (req *NetlinkRequest) ExecuteIter(sockType int, resType uint16, f func(msg
|
|||
return err
|
||||
}
|
||||
|
||||
dumpIntr := false
|
||||
|
||||
done:
|
||||
for {
|
||||
msgs, from, err := s.Receive()
|
||||
|
@ -582,7 +608,7 @@ done:
|
|||
}
|
||||
|
||||
if m.Header.Flags&unix.NLM_F_DUMP_INTR != 0 {
|
||||
return syscall.Errno(unix.EINTR)
|
||||
dumpIntr = true
|
||||
}
|
||||
|
||||
if m.Header.Type == unix.NLMSG_DONE || m.Header.Type == unix.NLMSG_ERROR {
|
||||
|
@ -636,6 +662,9 @@ done:
|
|||
}
|
||||
}
|
||||
}
|
||||
if dumpIntr {
|
||||
return ErrDumpInterrupted
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package netlink
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"syscall"
|
||||
|
||||
|
@ -8,10 +9,14 @@ import (
|
|||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// If the returned error is [ErrDumpInterrupted], results may be inconsistent
|
||||
// or incomplete.
|
||||
func LinkGetProtinfo(link Link) (Protinfo, error) {
|
||||
return pkgHandle.LinkGetProtinfo(link)
|
||||
}
|
||||
|
||||
// If the returned error is [ErrDumpInterrupted], results may be inconsistent
|
||||
// or incomplete.
|
||||
func (h *Handle) LinkGetProtinfo(link Link) (Protinfo, error) {
|
||||
base := link.Attrs()
|
||||
h.ensureIndex(base)
|
||||
|
@ -19,9 +24,9 @@ func (h *Handle) LinkGetProtinfo(link Link) (Protinfo, error) {
|
|||
req := h.newNetlinkRequest(unix.RTM_GETLINK, unix.NLM_F_DUMP)
|
||||
msg := nl.NewIfInfomsg(unix.AF_BRIDGE)
|
||||
req.AddData(msg)
|
||||
msgs, err := req.Execute(unix.NETLINK_ROUTE, 0)
|
||||
if err != nil {
|
||||
return pi, err
|
||||
msgs, executeErr := req.Execute(unix.NETLINK_ROUTE, 0)
|
||||
if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
|
||||
return pi, executeErr
|
||||
}
|
||||
|
||||
for _, m := range msgs {
|
||||
|
@ -43,7 +48,7 @@ func (h *Handle) LinkGetProtinfo(link Link) (Protinfo, error) {
|
|||
}
|
||||
pi = parseProtinfo(infos)
|
||||
|
||||
return pi, nil
|
||||
return pi, executeErr
|
||||
}
|
||||
}
|
||||
return pi, fmt.Errorf("Device with index %d not found", base.Index)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package netlink
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"strconv"
|
||||
|
@ -338,6 +339,9 @@ func qdiscPayload(req *nl.NetlinkRequest, qdisc Qdisc) error {
|
|||
// QdiscList gets a list of qdiscs in the system.
|
||||
// Equivalent to: `tc qdisc show`.
|
||||
// The list can be filtered by link.
|
||||
//
|
||||
// If the returned error is [ErrDumpInterrupted], results may be inconsistent
|
||||
// or incomplete.
|
||||
func QdiscList(link Link) ([]Qdisc, error) {
|
||||
return pkgHandle.QdiscList(link)
|
||||
}
|
||||
|
@ -345,6 +349,9 @@ func QdiscList(link Link) ([]Qdisc, error) {
|
|||
// QdiscList gets a list of qdiscs in the system.
|
||||
// Equivalent to: `tc qdisc show`.
|
||||
// The list can be filtered by link.
|
||||
//
|
||||
// If the returned error is [ErrDumpInterrupted], results may be inconsistent
|
||||
// or incomplete.
|
||||
func (h *Handle) QdiscList(link Link) ([]Qdisc, error) {
|
||||
req := h.newNetlinkRequest(unix.RTM_GETQDISC, unix.NLM_F_DUMP)
|
||||
index := int32(0)
|
||||
|
@ -359,9 +366,9 @@ func (h *Handle) QdiscList(link Link) ([]Qdisc, error) {
|
|||
}
|
||||
req.AddData(msg)
|
||||
|
||||
msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWQDISC)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
msgs, executeErr := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWQDISC)
|
||||
if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
|
||||
return nil, executeErr
|
||||
}
|
||||
|
||||
var res []Qdisc
|
||||
|
@ -497,7 +504,7 @@ func (h *Handle) QdiscList(link Link) ([]Qdisc, error) {
|
|||
res = append(res, qdisc)
|
||||
}
|
||||
|
||||
return res, nil
|
||||
return res, executeErr
|
||||
}
|
||||
|
||||
func parsePfifoFastData(qdisc Qdisc, value []byte) error {
|
||||
|
|
|
@ -3,6 +3,7 @@ package netlink
|
|||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
|
@ -85,19 +86,25 @@ func execRdmaSetLink(req *nl.NetlinkRequest) error {
|
|||
|
||||
// RdmaLinkList gets a list of RDMA link devices.
|
||||
// Equivalent to: `rdma dev show`
|
||||
//
|
||||
// If the returned error is [ErrDumpInterrupted], results may be inconsistent
|
||||
// or incomplete.
|
||||
func RdmaLinkList() ([]*RdmaLink, error) {
|
||||
return pkgHandle.RdmaLinkList()
|
||||
}
|
||||
|
||||
// RdmaLinkList gets a list of RDMA link devices.
|
||||
// Equivalent to: `rdma dev show`
|
||||
//
|
||||
// If the returned error is [ErrDumpInterrupted], results may be inconsistent
|
||||
// or incomplete.
|
||||
func (h *Handle) RdmaLinkList() ([]*RdmaLink, error) {
|
||||
proto := getProtoField(nl.RDMA_NL_NLDEV, nl.RDMA_NLDEV_CMD_GET)
|
||||
req := h.newNetlinkRequest(proto, unix.NLM_F_ACK|unix.NLM_F_DUMP)
|
||||
|
||||
msgs, err := req.Execute(unix.NETLINK_RDMA, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
msgs, executeErr := req.Execute(unix.NETLINK_RDMA, 0)
|
||||
if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
|
||||
return nil, executeErr
|
||||
}
|
||||
|
||||
var res []*RdmaLink
|
||||
|
@ -109,17 +116,23 @@ func (h *Handle) RdmaLinkList() ([]*RdmaLink, error) {
|
|||
res = append(res, link)
|
||||
}
|
||||
|
||||
return res, nil
|
||||
return res, executeErr
|
||||
}
|
||||
|
||||
// RdmaLinkByName finds a link by name and returns a pointer to the object if
|
||||
// found and nil error, otherwise returns error code.
|
||||
//
|
||||
// If the returned error is [ErrDumpInterrupted], the result may be missing or
|
||||
// outdated and the caller should retry.
|
||||
func RdmaLinkByName(name string) (*RdmaLink, error) {
|
||||
return pkgHandle.RdmaLinkByName(name)
|
||||
}
|
||||
|
||||
// RdmaLinkByName finds a link by name and returns a pointer to the object if
|
||||
// found and nil error, otherwise returns error code.
|
||||
//
|
||||
// If the returned error is [ErrDumpInterrupted], the result may be missing or
|
||||
// outdated and the caller should retry.
|
||||
func (h *Handle) RdmaLinkByName(name string) (*RdmaLink, error) {
|
||||
links, err := h.RdmaLinkList()
|
||||
if err != nil {
|
||||
|
@ -288,6 +301,8 @@ func RdmaLinkDel(name string) error {
|
|||
}
|
||||
|
||||
// RdmaLinkDel deletes an rdma link.
|
||||
//
|
||||
// If the returned error is [ErrDumpInterrupted], the caller should retry.
|
||||
func (h *Handle) RdmaLinkDel(name string) error {
|
||||
link, err := h.RdmaLinkByName(name)
|
||||
if err != nil {
|
||||
|
@ -307,6 +322,7 @@ func (h *Handle) RdmaLinkDel(name string) error {
|
|||
|
||||
// RdmaLinkAdd adds an rdma link for the specified type to the network device.
|
||||
// Similar to: rdma link add NAME type TYPE netdev NETDEV
|
||||
//
|
||||
// NAME - specifies the new name of the rdma link to add
|
||||
// TYPE - specifies which rdma type to use. Link types:
|
||||
// rxe - Soft RoCE driver
|
||||
|
|
|
@ -3,6 +3,7 @@ package netlink
|
|||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"strconv"
|
||||
|
@ -1163,6 +1164,9 @@ func (h *Handle) prepareRouteReq(route *Route, req *nl.NetlinkRequest, msg *nl.R
|
|||
// RouteList gets a list of routes in the system.
|
||||
// Equivalent to: `ip route show`.
|
||||
// The list can be filtered by link and ip family.
|
||||
//
|
||||
// If the returned error is [ErrDumpInterrupted], results may be inconsistent
|
||||
// or incomplete.
|
||||
func RouteList(link Link, family int) ([]Route, error) {
|
||||
return pkgHandle.RouteList(link, family)
|
||||
}
|
||||
|
@ -1170,6 +1174,9 @@ func RouteList(link Link, family int) ([]Route, error) {
|
|||
// RouteList gets a list of routes in the system.
|
||||
// Equivalent to: `ip route show`.
|
||||
// The list can be filtered by link and ip family.
|
||||
//
|
||||
// If the returned error is [ErrDumpInterrupted], results may be inconsistent
|
||||
// or incomplete.
|
||||
func (h *Handle) RouteList(link Link, family int) ([]Route, error) {
|
||||
routeFilter := &Route{}
|
||||
if link != nil {
|
||||
|
@ -1188,6 +1195,9 @@ func RouteListFiltered(family int, filter *Route, filterMask uint64) ([]Route, e
|
|||
|
||||
// RouteListFiltered gets a list of routes in the system filtered with specified rules.
|
||||
// All rules must be defined in RouteFilter struct
|
||||
//
|
||||
// If the returned error is [ErrDumpInterrupted], results may be inconsistent
|
||||
// or incomplete.
|
||||
func (h *Handle) RouteListFiltered(family int, filter *Route, filterMask uint64) ([]Route, error) {
|
||||
var res []Route
|
||||
err := h.RouteListFilteredIter(family, filter, filterMask, func(route Route) (cont bool) {
|
||||
|
@ -1202,17 +1212,22 @@ func (h *Handle) RouteListFiltered(family int, filter *Route, filterMask uint64)
|
|||
|
||||
// RouteListFilteredIter passes each route that matches the filter to the given iterator func. Iteration continues
|
||||
// until all routes are loaded or the func returns false.
|
||||
//
|
||||
// If the returned error is [ErrDumpInterrupted], results may be inconsistent
|
||||
// or incomplete.
|
||||
func RouteListFilteredIter(family int, filter *Route, filterMask uint64, f func(Route) (cont bool)) error {
|
||||
return pkgHandle.RouteListFilteredIter(family, filter, filterMask, f)
|
||||
}
|
||||
|
||||
// If the returned error is [ErrDumpInterrupted], results may be inconsistent
|
||||
// or incomplete.
|
||||
func (h *Handle) RouteListFilteredIter(family int, filter *Route, filterMask uint64, f func(Route) (cont bool)) error {
|
||||
req := h.newNetlinkRequest(unix.RTM_GETROUTE, unix.NLM_F_DUMP)
|
||||
rtmsg := &nl.RtMsg{}
|
||||
rtmsg.Family = uint8(family)
|
||||
|
||||
var parseErr error
|
||||
err := h.routeHandleIter(filter, req, rtmsg, func(m []byte) bool {
|
||||
executeErr := h.routeHandleIter(filter, req, rtmsg, func(m []byte) bool {
|
||||
msg := nl.DeserializeRtMsg(m)
|
||||
if family != FAMILY_ALL && msg.Family != uint8(family) {
|
||||
// Ignore routes not matching requested family
|
||||
|
@ -1270,13 +1285,13 @@ func (h *Handle) RouteListFilteredIter(family int, filter *Route, filterMask uin
|
|||
}
|
||||
return f(route)
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
|
||||
return executeErr
|
||||
}
|
||||
if parseErr != nil {
|
||||
return parseErr
|
||||
}
|
||||
return nil
|
||||
return executeErr
|
||||
}
|
||||
|
||||
// deserializeRoute decodes a binary netlink message into a Route struct
|
||||
|
@ -1684,6 +1699,10 @@ type RouteSubscribeOptions struct {
|
|||
// 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.
|
||||
//
|
||||
// When options.ListExisting is true, options.ErrorCallback may be
|
||||
// called with [ErrDumpInterrupted] to indicate that results from
|
||||
// the initial dump of links may be inconsistent or incomplete.
|
||||
func RouteSubscribeWithOptions(ch chan<- RouteUpdate, done <-chan struct{}, options RouteSubscribeOptions) error {
|
||||
if options.Namespace == nil {
|
||||
none := netns.None()
|
||||
|
@ -1743,6 +1762,9 @@ func routeSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- RouteUpdate, done <
|
|||
continue
|
||||
}
|
||||
for _, m := range msgs {
|
||||
if m.Header.Flags&unix.NLM_F_DUMP_INTR != 0 && cberr != nil {
|
||||
cberr(ErrDumpInterrupted)
|
||||
}
|
||||
if m.Header.Type == unix.NLMSG_DONE {
|
||||
continue
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package netlink
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
|
@ -183,12 +184,18 @@ func ruleHandle(rule *Rule, req *nl.NetlinkRequest) error {
|
|||
|
||||
// RuleList lists rules in the system.
|
||||
// Equivalent to: ip rule list
|
||||
//
|
||||
// If the returned error is [ErrDumpInterrupted], results may be inconsistent
|
||||
// or incomplete.
|
||||
func RuleList(family int) ([]Rule, error) {
|
||||
return pkgHandle.RuleList(family)
|
||||
}
|
||||
|
||||
// RuleList lists rules in the system.
|
||||
// Equivalent to: ip rule list
|
||||
//
|
||||
// If the returned error is [ErrDumpInterrupted], results may be inconsistent
|
||||
// or incomplete.
|
||||
func (h *Handle) RuleList(family int) ([]Rule, error) {
|
||||
return h.RuleListFiltered(family, nil, 0)
|
||||
}
|
||||
|
@ -196,20 +203,26 @@ func (h *Handle) RuleList(family int) ([]Rule, error) {
|
|||
// RuleListFiltered gets a list of rules in the system filtered by the
|
||||
// specified rule template `filter`.
|
||||
// Equivalent to: ip rule list
|
||||
//
|
||||
// If the returned error is [ErrDumpInterrupted], results may be inconsistent
|
||||
// or incomplete.
|
||||
func RuleListFiltered(family int, filter *Rule, filterMask uint64) ([]Rule, error) {
|
||||
return pkgHandle.RuleListFiltered(family, filter, filterMask)
|
||||
}
|
||||
|
||||
// RuleListFiltered lists rules in the system.
|
||||
// Equivalent to: ip rule list
|
||||
//
|
||||
// If the returned error is [ErrDumpInterrupted], results may be inconsistent
|
||||
// or incomplete.
|
||||
func (h *Handle) RuleListFiltered(family int, filter *Rule, filterMask uint64) ([]Rule, error) {
|
||||
req := h.newNetlinkRequest(unix.RTM_GETRULE, unix.NLM_F_DUMP|unix.NLM_F_REQUEST)
|
||||
msg := nl.NewIfInfomsg(family)
|
||||
req.AddData(msg)
|
||||
|
||||
msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWRULE)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
msgs, executeErr := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWRULE)
|
||||
if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
|
||||
return nil, executeErr
|
||||
}
|
||||
|
||||
var res = make([]Rule, 0)
|
||||
|
@ -306,7 +319,7 @@ func (h *Handle) RuleListFiltered(family int, filter *Rule, filterMask uint64) (
|
|||
res = append(res, *rule)
|
||||
}
|
||||
|
||||
return res, nil
|
||||
return res, executeErr
|
||||
}
|
||||
|
||||
func (pr *RulePortRange) toRtAttrData() []byte {
|
||||
|
|
109
socket_linux.go
109
socket_linux.go
|
@ -157,6 +157,9 @@ func (u *UnixSocket) deserialize(b []byte) error {
|
|||
}
|
||||
|
||||
// SocketGet returns the Socket identified by its local and remote addresses.
|
||||
//
|
||||
// If the returned error is [ErrDumpInterrupted], the search for a result may
|
||||
// be incomplete and the caller should retry.
|
||||
func (h *Handle) SocketGet(local, remote net.Addr) (*Socket, error) {
|
||||
var protocol uint8
|
||||
var localIP, remoteIP net.IP
|
||||
|
@ -232,6 +235,9 @@ func (h *Handle) SocketGet(local, remote net.Addr) (*Socket, error) {
|
|||
}
|
||||
|
||||
// SocketGet returns the Socket identified by its local and remote addresses.
|
||||
//
|
||||
// If the returned error is [ErrDumpInterrupted], the search for a result may
|
||||
// be incomplete and the caller should retry.
|
||||
func SocketGet(local, remote net.Addr) (*Socket, error) {
|
||||
return pkgHandle.SocketGet(local, remote)
|
||||
}
|
||||
|
@ -283,6 +289,9 @@ func SocketDestroy(local, remote net.Addr) error {
|
|||
}
|
||||
|
||||
// SocketDiagTCPInfo requests INET_DIAG_INFO for TCP protocol for specified family type and return with extension TCP info.
|
||||
//
|
||||
// If the returned error is [ErrDumpInterrupted], results may be inconsistent
|
||||
// or incomplete.
|
||||
func (h *Handle) SocketDiagTCPInfo(family uint8) ([]*InetDiagTCPInfoResp, error) {
|
||||
// Construct the request
|
||||
req := h.newNetlinkRequest(nl.SOCK_DIAG_BY_FAMILY, unix.NLM_F_DUMP)
|
||||
|
@ -295,9 +304,9 @@ func (h *Handle) SocketDiagTCPInfo(family uint8) ([]*InetDiagTCPInfoResp, error)
|
|||
|
||||
// Do the query and parse the result
|
||||
var result []*InetDiagTCPInfoResp
|
||||
var err error
|
||||
err = req.ExecuteIter(unix.NETLINK_INET_DIAG, nl.SOCK_DIAG_BY_FAMILY, func(msg []byte) bool {
|
||||
executeErr := req.ExecuteIter(unix.NETLINK_INET_DIAG, nl.SOCK_DIAG_BY_FAMILY, func(msg []byte) bool {
|
||||
sockInfo := &Socket{}
|
||||
var err error
|
||||
if err = sockInfo.deserialize(msg); err != nil {
|
||||
return false
|
||||
}
|
||||
|
@ -315,18 +324,24 @@ func (h *Handle) SocketDiagTCPInfo(family uint8) ([]*InetDiagTCPInfoResp, error)
|
|||
return true
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
i |