mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Move helpers to parse netlink message to the separate module
It will be used in following changes. PiperOrigin-RevId: 622287107
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
load("//tools:defs.bzl", "go_library", "go_test")
|
||||
load("//tools:defs.bzl", "go_library")
|
||||
|
||||
package(
|
||||
default_applicable_licenses = ["//:license"],
|
||||
@@ -8,7 +8,6 @@ package(
|
||||
go_library(
|
||||
name = "netlink",
|
||||
srcs = [
|
||||
"message.go",
|
||||
"provider.go",
|
||||
"socket.go",
|
||||
],
|
||||
@@ -16,7 +15,6 @@ go_library(
|
||||
deps = [
|
||||
"//pkg/abi/linux",
|
||||
"//pkg/abi/linux/errno",
|
||||
"//pkg/bits",
|
||||
"//pkg/context",
|
||||
"//pkg/errors/linuxerr",
|
||||
"//pkg/hostarch",
|
||||
@@ -28,6 +26,7 @@ go_library(
|
||||
"//pkg/sentry/kernel/auth",
|
||||
"//pkg/sentry/kernel/time",
|
||||
"//pkg/sentry/socket",
|
||||
"//pkg/sentry/socket/netlink/nlmsg",
|
||||
"//pkg/sentry/socket/netlink/port",
|
||||
"//pkg/sentry/socket/unix",
|
||||
"//pkg/sentry/socket/unix/transport",
|
||||
@@ -38,17 +37,3 @@ go_library(
|
||||
"//pkg/waiter",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "netlink_test",
|
||||
size = "small",
|
||||
srcs = [
|
||||
"message_test.go",
|
||||
],
|
||||
deps = [
|
||||
":netlink",
|
||||
"//pkg/abi/linux",
|
||||
"//pkg/marshal",
|
||||
"//pkg/marshal/primitive",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
load("//tools:defs.bzl", "go_library", "go_test")
|
||||
|
||||
package(
|
||||
default_applicable_licenses = ["//:license"],
|
||||
licenses = ["notice"],
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "nlmsg",
|
||||
srcs = [
|
||||
"message.go",
|
||||
],
|
||||
visibility = ["//pkg/sentry:internal"],
|
||||
deps = [
|
||||
"//pkg/abi/linux",
|
||||
"//pkg/bits",
|
||||
"//pkg/hostarch",
|
||||
"//pkg/marshal",
|
||||
"//pkg/marshal/primitive",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "nlmsg_test",
|
||||
size = "small",
|
||||
srcs = [
|
||||
"message_test.go",
|
||||
],
|
||||
deps = [
|
||||
":nlmsg",
|
||||
"//pkg/abi/linux",
|
||||
"//pkg/marshal",
|
||||
"//pkg/marshal/primitive",
|
||||
],
|
||||
)
|
||||
@@ -12,7 +12,8 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package netlink
|
||||
// Package nlmsg provides helpers to parse and construct netlink messages.
|
||||
package nlmsg
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@@ -268,6 +269,23 @@ func (v AttrsView) ParseFirst() (hdr linux.NetlinkAttrHeader, value []byte, rest
|
||||
return hdr, value, AttrsView(b), ok
|
||||
}
|
||||
|
||||
// Parse parses netlink attributes.
|
||||
func (v AttrsView) Parse() (map[uint16]BytesView, bool) {
|
||||
attrs := make(map[uint16]BytesView)
|
||||
attrsView := v
|
||||
for !attrsView.Empty() {
|
||||
// The index is unspecified, search by the interface name.
|
||||
ahdr, value, rest, ok := attrsView.ParseFirst()
|
||||
if !ok {
|
||||
return nil, false
|
||||
}
|
||||
attrsView = rest
|
||||
attrs[ahdr.Type] = BytesView(value)
|
||||
}
|
||||
return attrs, true
|
||||
|
||||
}
|
||||
|
||||
// BytesView supports extracting data from a byte slice with bounds checking.
|
||||
type BytesView []byte
|
||||
|
||||
@@ -281,3 +299,26 @@ func (v *BytesView) Extract(n int) ([]byte, bool) {
|
||||
*v = (*v)[n:]
|
||||
return extracted, true
|
||||
}
|
||||
|
||||
// String converts the raw attribute value to string.
|
||||
func (v *BytesView) String() string {
|
||||
b := []byte(*v)
|
||||
if len(b) == 0 {
|
||||
return ""
|
||||
}
|
||||
if b[len(b)-1] == 0 {
|
||||
b = b[:len(b)-1]
|
||||
}
|
||||
return string(b)
|
||||
}
|
||||
|
||||
// Uint32 converts the raw attribute value to uint32.
|
||||
func (v *BytesView) Uint32() (uint32, bool) {
|
||||
attr := []byte(*v)
|
||||
val := primitive.Uint32(0)
|
||||
if len(attr) != val.SizeBytes() {
|
||||
return 0, false
|
||||
}
|
||||
val.UnmarshalBytes(attr)
|
||||
return uint32(val), true
|
||||
}
|
||||
+3
-3
@@ -22,7 +22,7 @@ import (
|
||||
"gvisor.dev/gvisor/pkg/abi/linux"
|
||||
"gvisor.dev/gvisor/pkg/marshal"
|
||||
"gvisor.dev/gvisor/pkg/marshal/primitive"
|
||||
"gvisor.dev/gvisor/pkg/sentry/socket/netlink"
|
||||
"gvisor.dev/gvisor/pkg/sentry/socket/netlink/nlmsg"
|
||||
)
|
||||
|
||||
func TestParseMessage(t *testing.T) {
|
||||
@@ -160,7 +160,7 @@ func TestParseMessage(t *testing.T) {
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
msg, rest, ok := netlink.ParseMessage(test.input)
|
||||
msg, rest, ok := nlmsg.ParseMessage(test.input)
|
||||
if ok != test.ok {
|
||||
t.Errorf("%v: got ok = %v, want = %v", test.desc, ok, test.ok)
|
||||
continue
|
||||
@@ -277,7 +277,7 @@ func TestAttrView(t *testing.T) {
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
attrs := netlink.AttrsView(test.input)
|
||||
attrs := nlmsg.AttrsView(test.input)
|
||||
|
||||
// Test ParseFirst().
|
||||
hdr, value, rest, ok := attrs.ParseFirst()
|
||||
@@ -22,6 +22,7 @@ import (
|
||||
"gvisor.dev/gvisor/pkg/sentry/fsimpl/sockfs"
|
||||
"gvisor.dev/gvisor/pkg/sentry/kernel"
|
||||
"gvisor.dev/gvisor/pkg/sentry/socket"
|
||||
"gvisor.dev/gvisor/pkg/sentry/socket/netlink/nlmsg"
|
||||
"gvisor.dev/gvisor/pkg/sentry/vfs"
|
||||
"gvisor.dev/gvisor/pkg/syserr"
|
||||
)
|
||||
@@ -43,7 +44,7 @@ type Protocol interface {
|
||||
// If err == nil, any messages added to ms will be sent back to the
|
||||
// other end of the socket. Setting ms.Multi will cause an NLMSG_DONE
|
||||
// message to be sent even if ms contains no messages.
|
||||
ProcessMessage(ctx context.Context, msg *Message, ms *MessageSet) *syserr.Error
|
||||
ProcessMessage(ctx context.Context, msg *nlmsg.Message, ms *nlmsg.MessageSet) *syserr.Error
|
||||
}
|
||||
|
||||
// Provider is a function that creates a new Protocol for a specific netlink
|
||||
|
||||
@@ -20,6 +20,7 @@ go_library(
|
||||
"//pkg/sentry/kernel",
|
||||
"//pkg/sentry/kernel/auth",
|
||||
"//pkg/sentry/socket/netlink",
|
||||
"//pkg/sentry/socket/netlink/nlmsg",
|
||||
"//pkg/syserr",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -26,6 +26,7 @@ import (
|
||||
"gvisor.dev/gvisor/pkg/sentry/kernel"
|
||||
"gvisor.dev/gvisor/pkg/sentry/kernel/auth"
|
||||
"gvisor.dev/gvisor/pkg/sentry/socket/netlink"
|
||||
"gvisor.dev/gvisor/pkg/sentry/socket/netlink/nlmsg"
|
||||
"gvisor.dev/gvisor/pkg/syserr"
|
||||
)
|
||||
|
||||
@@ -69,7 +70,7 @@ func (p *Protocol) CanSend() bool {
|
||||
}
|
||||
|
||||
// dumpLinks handles RTM_GETLINK dump requests.
|
||||
func (p *Protocol) dumpLinks(ctx context.Context, msg *netlink.Message, ms *netlink.MessageSet) *syserr.Error {
|
||||
func (p *Protocol) dumpLinks(ctx context.Context, msg *nlmsg.Message, ms *nlmsg.MessageSet) *syserr.Error {
|
||||
// NLM_F_DUMP + RTM_GETLINK messages are supposed to include an
|
||||
// ifinfomsg. However, Linux <3.9 only checked for rtgenmsg, and some
|
||||
// userspace applications (including glibc) still include rtgenmsg.
|
||||
@@ -101,7 +102,7 @@ func (p *Protocol) dumpLinks(ctx context.Context, msg *netlink.Message, ms *netl
|
||||
}
|
||||
|
||||
// getLinks handles RTM_GETLINK requests.
|
||||
func (p *Protocol) getLink(ctx context.Context, msg *netlink.Message, ms *netlink.MessageSet) *syserr.Error {
|
||||
func (p *Protocol) getLink(ctx context.Context, msg *nlmsg.Message, ms *nlmsg.MessageSet) *syserr.Error {
|
||||
stack := inet.StackFromContext(ctx)
|
||||
if stack == nil {
|
||||
// No network devices.
|
||||
@@ -161,7 +162,7 @@ func (p *Protocol) getLink(ctx context.Context, msg *netlink.Message, ms *netlin
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Protocol) newLink(ctx context.Context, msg *netlink.Message, ms *netlink.MessageSet) *syserr.Error {
|
||||
func (p *Protocol) newLink(ctx context.Context, msg *nlmsg.Message, ms *nlmsg.MessageSet) *syserr.Error {
|
||||
stack := inet.StackFromContext(ctx)
|
||||
if stack == nil {
|
||||
// No network stack.
|
||||
@@ -228,7 +229,7 @@ func (p *Protocol) newLink(ctx context.Context, msg *netlink.Message, ms *netlin
|
||||
}
|
||||
|
||||
// delLink handles RTM_DELLINK requests.
|
||||
func (p *Protocol) delLink(ctx context.Context, msg *netlink.Message, ms *netlink.MessageSet) *syserr.Error {
|
||||
func (p *Protocol) delLink(ctx context.Context, msg *nlmsg.Message, ms *nlmsg.MessageSet) *syserr.Error {
|
||||
stack := inet.StackFromContext(ctx)
|
||||
if stack == nil {
|
||||
// No network stack.
|
||||
@@ -270,7 +271,7 @@ func (p *Protocol) delLink(ctx context.Context, msg *netlink.Message, ms *netlin
|
||||
|
||||
// addNewLinkMessage appends RTM_NEWLINK message for the given interface into
|
||||
// the message set.
|
||||
func addNewLinkMessage(ms *netlink.MessageSet, idx int32, i inet.Interface) {
|
||||
func addNewLinkMessage(ms *nlmsg.MessageSet, idx int32, i inet.Interface) {
|
||||
m := ms.AddMessage(linux.NetlinkMessageHeader{
|
||||
Type: linux.RTM_NEWLINK,
|
||||
})
|
||||
@@ -298,7 +299,7 @@ func addNewLinkMessage(ms *netlink.MessageSet, idx int32, i inet.Interface) {
|
||||
}
|
||||
|
||||
// dumpAddrs handles RTM_GETADDR dump requests.
|
||||
func (p *Protocol) dumpAddrs(ctx context.Context, msg *netlink.Message, ms *netlink.MessageSet) *syserr.Error {
|
||||
func (p *Protocol) dumpAddrs(ctx context.Context, msg *nlmsg.Message, ms *nlmsg.MessageSet) *syserr.Error {
|
||||
// RTM_GETADDR dump requests need not contain anything more than the
|
||||
// netlink header and 1 byte protocol family common to all
|
||||
// NETLINK_ROUTE requests.
|
||||
@@ -416,7 +417,7 @@ func fillRoute(routes []inet.Route, addr []byte) (inet.Route, *syserr.Error) {
|
||||
}
|
||||
|
||||
// parseForDestination parses a message as format of RouteMessage-RtAttr-dst.
|
||||
func parseForDestination(msg *netlink.Message) ([]byte, *syserr.Error) {
|
||||
func parseForDestination(msg *nlmsg.Message) ([]byte, *syserr.Error) {
|
||||
var rtMsg linux.RouteMessage
|
||||
attrs, ok := msg.GetData(&rtMsg)
|
||||
if !ok {
|
||||
@@ -437,7 +438,7 @@ func parseForDestination(msg *netlink.Message) ([]byte, *syserr.Error) {
|
||||
}
|
||||
|
||||
// dumpRoutes handles RTM_GETROUTE requests.
|
||||
func (p *Protocol) dumpRoutes(ctx context.Context, msg *netlink.Message, ms *netlink.MessageSet) *syserr.Error {
|
||||
func (p *Protocol) dumpRoutes(ctx context.Context, msg *nlmsg.Message, ms *nlmsg.MessageSet) *syserr.Error {
|
||||
// RTM_GETROUTE dump requests need not contain anything more than the
|
||||
// netlink header and 1 byte protocol family common to all
|
||||
// NETLINK_ROUTE requests.
|
||||
@@ -512,7 +513,7 @@ func (p *Protocol) dumpRoutes(ctx context.Context, msg *netlink.Message, ms *net
|
||||
}
|
||||
|
||||
// newAddr handles RTM_NEWADDR requests.
|
||||
func (p *Protocol) newAddr(ctx context.Context, msg *netlink.Message, ms *netlink.MessageSet) *syserr.Error {
|
||||
func (p *Protocol) newAddr(ctx context.Context, msg *nlmsg.Message, ms *nlmsg.MessageSet) *syserr.Error {
|
||||
stack := inet.StackFromContext(ctx)
|
||||
if stack == nil {
|
||||
// No network stack.
|
||||
@@ -562,7 +563,7 @@ func (p *Protocol) newAddr(ctx context.Context, msg *netlink.Message, ms *netlin
|
||||
}
|
||||
|
||||
// delAddr handles RTM_DELADDR requests.
|
||||
func (p *Protocol) delAddr(ctx context.Context, msg *netlink.Message, ms *netlink.MessageSet) *syserr.Error {
|
||||
func (p *Protocol) delAddr(ctx context.Context, msg *nlmsg.Message, ms *nlmsg.MessageSet) *syserr.Error {
|
||||
stack := inet.StackFromContext(ctx)
|
||||
if stack == nil {
|
||||
// No network stack.
|
||||
@@ -608,7 +609,7 @@ func (p *Protocol) delAddr(ctx context.Context, msg *netlink.Message, ms *netlin
|
||||
}
|
||||
|
||||
// ProcessMessage implements netlink.Protocol.ProcessMessage.
|
||||
func (p *Protocol) ProcessMessage(ctx context.Context, msg *netlink.Message, ms *netlink.MessageSet) *syserr.Error {
|
||||
func (p *Protocol) ProcessMessage(ctx context.Context, msg *nlmsg.Message, ms *nlmsg.MessageSet) *syserr.Error {
|
||||
hdr := msg.Header()
|
||||
|
||||
// All messages start with a 1 byte protocol family.
|
||||
|
||||
@@ -32,6 +32,7 @@ import (
|
||||
"gvisor.dev/gvisor/pkg/sentry/kernel/auth"
|
||||
ktime "gvisor.dev/gvisor/pkg/sentry/kernel/time"
|
||||
"gvisor.dev/gvisor/pkg/sentry/socket"
|
||||
"gvisor.dev/gvisor/pkg/sentry/socket/netlink/nlmsg"
|
||||
"gvisor.dev/gvisor/pkg/sentry/socket/netlink/port"
|
||||
"gvisor.dev/gvisor/pkg/sentry/socket/unix"
|
||||
"gvisor.dev/gvisor/pkg/sentry/socket/unix/transport"
|
||||
@@ -650,7 +651,7 @@ func (kernelSCM) Credentials(*kernel.Task) (kernel.ThreadID, auth.UID, auth.GID)
|
||||
var kernelCreds = &kernelSCM{}
|
||||
|
||||
// sendResponse sends the response messages in ms back to userspace.
|
||||
func (s *Socket) sendResponse(ctx context.Context, ms *MessageSet) *syserr.Error {
|
||||
func (s *Socket) sendResponse(ctx context.Context, ms *nlmsg.MessageSet) *syserr.Error {
|
||||
// Linux combines multiple netlink messages into a single datagram.
|
||||
bufs := make([][]byte, 0, len(ms.Messages))
|
||||
for _, m := range ms.Messages {
|
||||
@@ -677,12 +678,12 @@ func (s *Socket) sendResponse(ctx context.Context, ms *MessageSet) *syserr.Error
|
||||
}
|
||||
|
||||
// N.B. multi-part messages should still send NLMSG_DONE even if
|
||||
// MessageSet contains no messages.
|
||||
// nlmsg.MessageSet contains no messages.
|
||||
//
|
||||
// N.B. NLMSG_DONE is always sent in a different datagram. See
|
||||
// net/netlink/af_netlink.c:netlink_dump.
|
||||
if ms.Multi {
|
||||
m := NewMessage(linux.NetlinkMessageHeader{
|
||||
m := nlmsg.NewMessage(linux.NetlinkMessageHeader{
|
||||
Type: linux.NLMSG_DONE,
|
||||
Flags: linux.NLM_F_MULTI,
|
||||
Seq: ms.Seq,
|
||||
@@ -704,7 +705,7 @@ func (s *Socket) sendResponse(ctx context.Context, ms *MessageSet) *syserr.Error
|
||||
return nil
|
||||
}
|
||||
|
||||
func dumpErrorMessage(hdr linux.NetlinkMessageHeader, ms *MessageSet, err *syserr.Error) {
|
||||
func dumpErrorMessage(hdr linux.NetlinkMessageHeader, ms *nlmsg.MessageSet, err *syserr.Error) {
|
||||
m := ms.AddMessage(linux.NetlinkMessageHeader{
|
||||
Type: linux.NLMSG_ERROR,
|
||||
})
|
||||
@@ -714,7 +715,7 @@ func dumpErrorMessage(hdr linux.NetlinkMessageHeader, ms *MessageSet, err *syser
|
||||
})
|
||||
}
|
||||
|
||||
func dumpAckMessage(hdr linux.NetlinkMessageHeader, ms *MessageSet) {
|
||||
func dumpAckMessage(hdr linux.NetlinkMessageHeader, ms *nlmsg.MessageSet) {
|
||||
m := ms.AddMessage(linux.NetlinkMessageHeader{
|
||||
Type: linux.NLMSG_ERROR,
|
||||
})
|
||||
@@ -728,7 +729,7 @@ func dumpAckMessage(hdr linux.NetlinkMessageHeader, ms *MessageSet) {
|
||||
// handler for final handling.
|
||||
func (s *Socket) processMessages(ctx context.Context, buf []byte) *syserr.Error {
|
||||
for len(buf) > 0 {
|
||||
msg, rest, ok := ParseMessage(buf)
|
||||
msg, rest, ok := nlmsg.ParseMessage(buf)
|
||||
if !ok {
|
||||
// Linux ignores messages that are too short. See
|
||||
// net/netlink/af_netlink.c:netlink_rcv_skb.
|
||||
@@ -742,7 +743,7 @@ func (s *Socket) processMessages(ctx context.Context, buf []byte) *syserr.Error
|
||||
continue
|
||||
}
|
||||
|
||||
ms := NewMessageSet(s.portID, hdr.Seq)
|
||||
ms := nlmsg.NewMessageSet(s.portID, hdr.Seq)
|
||||
if err := s.protocol.ProcessMessage(ctx, msg, ms); err != nil {
|
||||
dumpErrorMessage(hdr, ms, err)
|
||||
} else if hdr.Flags&linux.NLM_F_ACK == linux.NLM_F_ACK {
|
||||
|
||||
@@ -14,6 +14,7 @@ go_library(
|
||||
"//pkg/context",
|
||||
"//pkg/sentry/kernel",
|
||||
"//pkg/sentry/socket/netlink",
|
||||
"//pkg/sentry/socket/netlink/nlmsg",
|
||||
"//pkg/syserr",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -23,6 +23,7 @@ import (
|
||||
"gvisor.dev/gvisor/pkg/context"
|
||||
"gvisor.dev/gvisor/pkg/sentry/kernel"
|
||||
"gvisor.dev/gvisor/pkg/sentry/socket/netlink"
|
||||
"gvisor.dev/gvisor/pkg/sentry/socket/netlink/nlmsg"
|
||||
"gvisor.dev/gvisor/pkg/syserr"
|
||||
)
|
||||
|
||||
@@ -49,7 +50,7 @@ func (p *Protocol) CanSend() bool {
|
||||
}
|
||||
|
||||
// ProcessMessage implements netlink.Protocol.ProcessMessage.
|
||||
func (p *Protocol) ProcessMessage(ctx context.Context, msg *netlink.Message, ms *netlink.MessageSet) *syserr.Error {
|
||||
func (p *Protocol) ProcessMessage(ctx context.Context, msg *nlmsg.Message, ms *nlmsg.MessageSet) *syserr.Error {
|
||||
// Silently ignore all messages.
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user