1 // Copyright 2011 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
5 // Netlink sockets and messages
11 // Round the length of a netlink message up to align it properly.
12 func nlmAlignOf(msglen
int) int {
13 return (msglen
+ NLMSG_ALIGNTO
- 1) & ^(NLMSG_ALIGNTO
- 1)
16 // Round the length of a netlink route attribute up to align it
18 func rtaAlignOf(attrlen
int) int {
19 return (attrlen
+ RTA_ALIGNTO
- 1) & ^(RTA_ALIGNTO
- 1)
22 // NetlinkRouteRequest represents a request message to receive routing
23 // and link states from the kernel.
24 type NetlinkRouteRequest
struct {
29 func (rr
*NetlinkRouteRequest
) toWireFormat() []byte {
30 b
:= make([]byte, rr
.Header
.Len
)
31 *(*uint32)(unsafe
.Pointer(&b
[0:4][0])) = rr
.Header
.Len
32 *(*uint16)(unsafe
.Pointer(&b
[4:6][0])) = rr
.Header
.Type
33 *(*uint16)(unsafe
.Pointer(&b
[6:8][0])) = rr
.Header
.Flags
34 *(*uint32)(unsafe
.Pointer(&b
[8:12][0])) = rr
.Header
.Seq
35 *(*uint32)(unsafe
.Pointer(&b
[12:16][0])) = rr
.Header
.Pid
36 b
[16] = byte(rr
.Data
.Family
)
40 func newNetlinkRouteRequest(proto
, seq
, family
int) []byte {
41 rr
:= &NetlinkRouteRequest
{}
42 rr
.Header
.Len
= uint32(NLMSG_HDRLEN
+ SizeofRtGenmsg
)
43 rr
.Header
.Type
= uint16(proto
)
44 rr
.Header
.Flags
= NLM_F_DUMP | NLM_F_REQUEST
45 rr
.Header
.Seq
= uint32(seq
)
46 rr
.Data
.Family
= uint8(family
)
47 return rr
.toWireFormat()
50 // NetlinkRIB returns routing information base, as known as RIB, which
51 // consists of network facility information, states and parameters.
52 func NetlinkRIB(proto
, family
int) ([]byte, error
) {
53 s
, err
:= Socket(AF_NETLINK
, SOCK_RAW
, NETLINK_ROUTE
)
58 lsa
:= &SockaddrNetlink
{Family
: AF_NETLINK
}
59 if err
:= Bind(s
, lsa
); err
!= nil {
62 wb
:= newNetlinkRouteRequest(proto
, 1, family
)
63 if err
:= Sendto(s
, wb
, 0, lsa
); err
!= nil {
67 rbNew
:= make([]byte, Getpagesize())
71 nr
, _
, err
:= Recvfrom(s
, rb
, 0)
75 if nr
< NLMSG_HDRLEN
{
79 tab
= append(tab
, rb
...)
80 msgs
, err
:= ParseNetlinkMessage(rb
)
84 for _
, m
:= range msgs
{
85 lsa
, err
:= Getsockname(s
)
89 switch v
:= lsa
.(type) {
90 case *SockaddrNetlink
:
91 if m
.Header
.Seq
!= 1 || m
.Header
.Pid
!= v
.Pid
{
97 if m
.Header
.Type
== NLMSG_DONE
{
100 if m
.Header
.Type
== NLMSG_ERROR
{
108 // NetlinkMessage represents a netlink message.
109 type NetlinkMessage
struct {
114 // ParseNetlinkMessage parses b as an array of netlink messages and
115 // returns the slice containing the NetlinkMessage structures.
116 func ParseNetlinkMessage(b
[]byte) ([]NetlinkMessage
, error
) {
117 var msgs
[]NetlinkMessage
118 for len(b
) >= NLMSG_HDRLEN
{
119 h
, dbuf
, dlen
, err
:= netlinkMessageHeaderAndData(b
)
123 m
:= NetlinkMessage
{Header
: *h
, Data
: dbuf
[:int(h
.Len
)-NLMSG_HDRLEN
]}
124 msgs
= append(msgs
, m
)
130 func netlinkMessageHeaderAndData(b
[]byte) (*NlMsghdr
, []byte, int, error
) {
131 h
:= (*NlMsghdr
)(unsafe
.Pointer(&b
[0]))
132 if int(h
.Len
) < NLMSG_HDRLEN ||
int(h
.Len
) > len(b
) {
133 return nil, nil, 0, EINVAL
135 return h
, b
[NLMSG_HDRLEN
:], nlmAlignOf(int(h
.Len
)), nil
138 // NetlinkRouteAttr represents a netlink route attribute.
139 type NetlinkRouteAttr
struct {
144 // ParseNetlinkRouteAttr parses m's payload as an array of netlink
145 // route attributes and returns the slice containing the
146 // NetlinkRouteAttr structures.
147 func ParseNetlinkRouteAttr(m
*NetlinkMessage
) ([]NetlinkRouteAttr
, error
) {
149 switch m
.Header
.Type
{
150 case RTM_NEWLINK
, RTM_DELLINK
:
151 b
= m
.Data
[SizeofIfInfomsg
:]
152 case RTM_NEWADDR
, RTM_DELADDR
:
153 b
= m
.Data
[SizeofIfAddrmsg
:]
154 case RTM_NEWROUTE
, RTM_DELROUTE
:
155 b
= m
.Data
[SizeofRtMsg
:]
159 var attrs
[]NetlinkRouteAttr
160 for len(b
) >= SizeofRtAttr
{
161 a
, vbuf
, alen
, err
:= netlinkRouteAttrAndValue(b
)
165 ra
:= NetlinkRouteAttr
{Attr
: *a
, Value
: vbuf
[:int(a
.Len
)-SizeofRtAttr
]}
166 attrs
= append(attrs
, ra
)
172 func netlinkRouteAttrAndValue(b
[]byte) (*RtAttr
, []byte, int, error
) {
173 a
:= (*RtAttr
)(unsafe
.Pointer(&b
[0]))
174 if int(a
.Len
) < SizeofRtAttr ||
int(a
.Len
) > len(b
) {
175 return nil, nil, 0, EINVAL
177 return a
, b
[SizeofRtAttr
:], rtaAlignOf(int(a
.Len
)), nil