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
13 // Round the length of a netlink message up to align it properly.
14 func nlmAlignOf(msglen
int) int {
15 return (msglen
+ NLMSG_ALIGNTO
- 1) & ^(NLMSG_ALIGNTO
- 1)
18 // Round the length of a netlink route attribute up to align it
20 func rtaAlignOf(attrlen
int) int {
21 return (attrlen
+ RTA_ALIGNTO
- 1) & ^(RTA_ALIGNTO
- 1)
24 // NetlinkRouteRequest represents the request message to receive
25 // routing and link states from the kernel.
26 type NetlinkRouteRequest
struct {
31 func (rr
*NetlinkRouteRequest
) toWireFormat() []byte {
32 b
:= make([]byte, rr
.Header
.Len
)
33 b
[0] = byte(rr
.Header
.Len
)
34 b
[1] = byte(rr
.Header
.Len
>> 8)
35 b
[2] = byte(rr
.Header
.Len
>> 16)
36 b
[3] = byte(rr
.Header
.Len
>> 24)
37 b
[4] = byte(rr
.Header
.Type
)
38 b
[5] = byte(rr
.Header
.Type
>> 8)
39 b
[6] = byte(rr
.Header
.Flags
)
40 b
[7] = byte(rr
.Header
.Flags
>> 8)
41 b
[8] = byte(rr
.Header
.Seq
)
42 b
[9] = byte(rr
.Header
.Seq
>> 8)
43 b
[10] = byte(rr
.Header
.Seq
>> 16)
44 b
[11] = byte(rr
.Header
.Seq
>> 24)
45 b
[12] = byte(rr
.Header
.Pid
)
46 b
[13] = byte(rr
.Header
.Pid
>> 8)
47 b
[14] = byte(rr
.Header
.Pid
>> 16)
48 b
[15] = byte(rr
.Header
.Pid
>> 24)
49 b
[16] = byte(rr
.Data
.Family
)
53 func newNetlinkRouteRequest(proto
, seq
, family
int) []byte {
54 rr
:= &NetlinkRouteRequest
{}
55 rr
.Header
.Len
= uint32(NLMSG_HDRLEN
+ SizeofRtGenmsg
)
56 rr
.Header
.Type
= uint16(proto
)
57 rr
.Header
.Flags
= NLM_F_DUMP | NLM_F_REQUEST
58 rr
.Header
.Seq
= uint32(seq
)
59 rr
.Data
.Family
= uint8(family
)
60 return rr
.toWireFormat()
63 // NetlinkRIB returns routing information base, as known as RIB,
64 // which consists of network facility information, states and
66 func NetlinkRIB(proto
, family
int) ([]byte, int) {
75 s
, e
= Socket(AF_NETLINK
, SOCK_RAW
, 0)
81 lsanl
.Family
= AF_NETLINK
88 wb
:= newNetlinkRouteRequest(proto
, seq
, family
)
89 e
= Sendto(s
, wb
, 0, &lsanl
)
101 rb
= make([]byte, Getpagesize())
102 nr
, _
, e
= Recvfrom(s
, rb
, 0)
106 if nr
< NLMSG_HDRLEN
{
110 tab
= append(tab
, rb
...)
112 msgs
, _
:= ParseNetlinkMessage(rb
)
113 for _
, m
:= range msgs
{
114 if lsa
, e
= Getsockname(s
); e
!= 0 {
117 switch v
:= lsa
.(type) {
118 case *SockaddrNetlink
:
119 if m
.Header
.Seq
!= uint32(seq
) || m
.Header
.Pid
!= v
.Pid
{
125 if m
.Header
.Type
== NLMSG_DONE
{
128 if m
.Header
.Type
== NLMSG_ERROR
{
138 // NetlinkMessage represents the netlink message.
139 type NetlinkMessage
struct {
144 // ParseNetlinkMessage parses buf as netlink messages and returns
145 // the slice containing the NetlinkMessage structs.
146 func ParseNetlinkMessage(buf
[]byte) ([]NetlinkMessage
, int) {
152 msgs
[]NetlinkMessage
155 for len(buf
) >= NLMSG_HDRLEN
{
156 h
, dbuf
, dlen
, e
= netlinkMessageHeaderAndData(buf
)
160 m
:= NetlinkMessage
{}
162 m
.Data
= dbuf
[:int(h
.Len
)-NLMSG_HDRLEN
]
163 msgs
= append(msgs
, m
)
170 func netlinkMessageHeaderAndData(buf
[]byte) (*NlMsghdr
, []byte, int, int) {
171 h
:= (*NlMsghdr
)(unsafe
.Pointer(&buf
[0]))
172 if int(h
.Len
) < NLMSG_HDRLEN ||
int(h
.Len
) > len(buf
) {
173 return nil, nil, 0, EINVAL
175 return h
, buf
[NLMSG_HDRLEN
:], nlmAlignOf(int(h
.Len
)), 0
178 // NetlinkRouteAttr represents the netlink route attribute.
179 type NetlinkRouteAttr
struct {
184 // ParseNetlinkRouteAttr parses msg's payload as netlink route
185 // attributes and returns the slice containing the NetlinkRouteAttr
187 func ParseNetlinkRouteAttr(msg
*NetlinkMessage
) ([]NetlinkRouteAttr
, int) {
194 attrs
[]NetlinkRouteAttr
197 switch msg
.Header
.Type
{
199 buf
= msg
.Data
[SizeofIfInfomsg
:]
201 buf
= msg
.Data
[SizeofIfAddrmsg
:]
206 for len(buf
) >= SizeofRtAttr
{
207 a
, vbuf
, alen
, e
= netlinkRouteAttrAndValue(buf
)
211 ra
:= NetlinkRouteAttr
{}
213 ra
.Value
= vbuf
[:int(a
.Len
)-SizeofRtAttr
]
214 attrs
= append(attrs
, ra
)
221 func netlinkRouteAttrAndValue(buf
[]byte) (*RtAttr
, []byte, int, int) {
222 h
:= (*RtAttr
)(unsafe
.Pointer(&buf
[0]))
223 if int(h
.Len
) < SizeofRtAttr ||
int(h
.Len
) > len(buf
) {
224 return nil, nil, 0, EINVAL
226 return h
, buf
[SizeofRtAttr
:], rtaAlignOf(int(h
.Len
)), 0