-
Notifications
You must be signed in to change notification settings - Fork 97
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: Handle OobData #210
base: main
Are you sure you want to change the base?
feat: Handle OobData #210
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -19,7 +19,8 @@ var _ Socket = &conn{} | |||||
|
||||||
// A conn is the Linux implementation of a netlink sockets connection. | ||||||
type conn struct { | ||||||
s *socket.Conn | ||||||
s *socket.Conn | ||||||
enableControlMessages bool | ||||||
} | ||||||
|
||||||
// dial is the entry point for Dial. dial opens a netlink socket using | ||||||
|
@@ -70,7 +71,7 @@ func newConn(s *socket.Conn, config *Config) (*conn, uint32, error) { | |||||
return nil, 0, err | ||||||
} | ||||||
|
||||||
c := &conn{s: s} | ||||||
c := &conn{s: s, enableControlMessages: config.EnableControlMessages} | ||||||
if config.Strict { | ||||||
// The caller has requested the strict option set. Historically we have | ||||||
// recommended checking for ENOPROTOOPT if the kernel does not support | ||||||
|
@@ -124,9 +125,6 @@ func (c *conn) Receive() ([]Message, error) { | |||||
b := make([]byte, os.Getpagesize()) | ||||||
for { | ||||||
// Peek at the buffer to see how many bytes are available. | ||||||
// | ||||||
// TODO(mdlayher): deal with OOB message data if available, such as | ||||||
// when PacketInfo ConnOption is true. | ||||||
n, _, _, _, err := c.s.Recvmsg(context.Background(), b, nil, unix.MSG_PEEK) | ||||||
if err != nil { | ||||||
return nil, err | ||||||
|
@@ -141,12 +139,23 @@ func (c *conn) Receive() ([]Message, error) { | |||||
b = make([]byte, len(b)*2) | ||||||
} | ||||||
|
||||||
// Only allocate a buffer for control messages if they are enabled. | ||||||
var oob []byte | ||||||
if c.enableControlMessages { | ||||||
oob = make([]byte, os.Getpagesize()) | ||||||
} | ||||||
|
||||||
// Read out all available messages | ||||||
n, _, _, _, err := c.s.Recvmsg(context.Background(), b, nil, 0) | ||||||
n, oobn, _, _, err := c.s.Recvmsg(context.Background(), b, oob, 0) | ||||||
if err != nil { | ||||||
return nil, err | ||||||
} | ||||||
|
||||||
var rawOob []byte | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
if c.enableControlMessages { | ||||||
rawOob = oob[:cmsgAlign(oobn)] | ||||||
} | ||||||
|
||||||
raw, err := syscall.ParseNetlinkMessage(b[:nlmsgAlign(n)]) | ||||||
if err != nil { | ||||||
return nil, err | ||||||
|
@@ -155,10 +164,10 @@ func (c *conn) Receive() ([]Message, error) { | |||||
msgs := make([]Message, 0, len(raw)) | ||||||
for _, r := range raw { | ||||||
m := Message{ | ||||||
Header: sysToHeader(r.Header), | ||||||
Data: r.Data, | ||||||
Header: sysToHeader(r.Header), | ||||||
Data: r.Data, | ||||||
OobData: rawOob, | ||||||
} | ||||||
|
||||||
msgs = append(msgs, m) | ||||||
} | ||||||
|
||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,6 +6,7 @@ | |
"github.com/mdlayher/netlink" | ||
"github.com/mdlayher/netlink/nlenc" | ||
"github.com/mdlayher/netlink/nltest" | ||
"golang.org/x/sys/unix" | ||
) | ||
|
||
// This example demonstrates using a netlink.Conn to execute requests against | ||
|
@@ -108,3 +109,59 @@ | |
}, | ||
}) | ||
} | ||
|
||
func ExampleConn_listenMulticastAllNSID() { | ||
const ( | ||
// Speak to route netlink using netlink | ||
familyRoute = 0 | ||
|
||
// Listen for events triggered by addition or deletion of | ||
// network interfaces | ||
rtmGroupLink = 0x1 | ||
) | ||
|
||
c, err := netlink.Dial(familyRoute, &netlink.Config{ | ||
// Groups is a bitmask; more than one group can be specified | ||
// by OR'ing multiple group values together | ||
Groups: rtmGroupLink, | ||
// Enable control messages to receive the netnsid | ||
// since we're going to set NETLINK_LISTEN_ALL_NSID | ||
EnableControlMessages: true, | ||
}) | ||
if err != nil { | ||
log.Fatalf("failed to dial netlink: %v", err) | ||
} | ||
defer c.Close() | ||
c.SetOption(netlink.ListenAllNSID, true) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Check error. |
||
|
||
for { | ||
// Listen for netlink messages triggered by multicast groups | ||
msgs, err := c.Receive() | ||
if err != nil { | ||
log.Fatalf("failed to receive messages: %v", err) | ||
} | ||
|
||
// Iterate over recieved messages and print them | ||
for _, msg := range msgs { | ||
// If the message contains oob data, parse it and print the netnsid | ||
if msg.OobData != nil { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Invert conditional and continue if nil rather than adding indentation. |
||
// ParseSocketControlMessage returns a slice of ControlMessages | ||
cmsg, err := unix.ParseSocketControlMessage(msg.OobData) | ||
if err != nil { | ||
log.Printf("Error parsing oob data: %v", err) | ||
continue | ||
} | ||
// Iterate over the control messages, find the | ||
// one with level SOL_NETLINK and type NETLINK_LISTEN_ALL_NSID | ||
for _, oob := range cmsg { | ||
if oob.Header.Level == unix.SOL_NETLINK && oob.Header.Type == unix.NETLINK_LISTEN_ALL_NSID { | ||
Check failure on line 157 in example_test.go GitHub Actions / build (1.20)
|
||
netnsid := int(oob.Data[0]) | ||
log.Printf("netnsid: %d", netnsid) | ||
break | ||
} | ||
} | ||
} | ||
log.Printf("msg: %+v", msg) | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -194,12 +194,14 @@ type Header struct { | |||||
|
||||||
// A Message is a netlink message. It contains a Header and an arbitrary | ||||||
// byte payload, which may be decoded using information from the Header. | ||||||
// It may also contain out-of-band data, which was sent along with the message. | ||||||
// | ||||||
// Data is often populated with netlink attributes. For easy encoding and | ||||||
// decoding of attributes, see the AttributeDecoder and AttributeEncoder types. | ||||||
type Message struct { | ||||||
Header Header | ||||||
Data []byte | ||||||
Header Header | ||||||
Data []byte | ||||||
OobData []byte | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
In canonical Go style. |
||||||
} | ||||||
|
||||||
// MarshalBinary marshals a Message into a byte slice. | ||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add another sentence like: