Use netlink attribute en-/decoder infrastructure (#61)

Use netlink attribute en-/decoder infrastructure

This should pave the way for endian aware code.
Ref #56 

Signed-off-by: Jeroen Simonetti <jeroen@simonetti.nl>
This commit is contained in:
Jeroen Simonetti 2019-10-09 17:41:08 +02:00 committed by GitHub
parent 9eab139ca7
commit 5df73f7be7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
133 changed files with 302 additions and 408 deletions

View File

@ -6,7 +6,6 @@ import (
"net"
"github.com/mdlayher/netlink"
"github.com/mdlayher/netlink/nlenc"
"golang.org/x/sys/unix"
)
@ -49,9 +48,16 @@ func (m *AddressMessage) MarshalBinary() ([]byte, error) {
b[1] = m.PrefixLength
b[2] = m.Flags
b[3] = m.Scope
nlenc.PutUint32(b[4:8], m.Index)
nativeEndian.PutUint32(b[4:8], m.Index)
a, err := m.Attributes.MarshalBinary()
ae := netlink.NewAttributeEncoder()
ae.ByteOrder = nativeEndian
err := m.Attributes.encode(ae)
if err != nil {
return nil, err
}
a, err := ae.Encode()
if err != nil {
return nil, err
}
@ -70,11 +76,16 @@ func (m *AddressMessage) UnmarshalBinary(b []byte) error {
m.PrefixLength = uint8(b[1])
m.Flags = uint8(b[2])
m.Scope = uint8(b[3])
m.Index = nlenc.Uint32(b[4:8])
m.Index = nativeEndian.Uint32(b[4:8])
if l > unix.SizeofIfAddrmsg {
m.Attributes = AddressAttributes{}
err := m.Attributes.UnmarshalBinary(b[unix.SizeofIfAddrmsg:])
ad, err := netlink.NewAttributeDecoder(b[unix.SizeofIfAddrmsg:])
if err != nil {
return err
}
ad.ByteOrder = nativeEndian
err = m.Attributes.decode(ad)
if err != nil {
return err
}
@ -143,99 +154,74 @@ type AddressAttributes struct {
Flags uint32 // Address flags
}
// UnmarshalBinary unmarshals the contents of a byte slice into a AddressMessage.
func (a *AddressAttributes) UnmarshalBinary(b []byte) error {
attrs, err := netlink.UnmarshalAttributes(b)
if err != nil {
return err
}
for _, attr := range attrs {
switch attr.Type {
func (a *AddressAttributes) decode(ad *netlink.AttributeDecoder) error {
for ad.Next() {
switch ad.Type() {
case unix.IFA_UNSPEC:
//unused attribute
// unused attribute
case unix.IFA_ADDRESS:
if len(attr.Data) != 4 && len(attr.Data) != 16 {
l := len(ad.Bytes())
if l != 4 && l != 16 {
return errInvalidAddressMessageAttr
}
a.Address = attr.Data
a.Address = ad.Bytes()
case unix.IFA_LOCAL:
if len(attr.Data) != 4 {
if len(ad.Bytes()) != 4 {
return errInvalidAddressMessageAttr
}
a.Local = attr.Data
a.Local = ad.Bytes()
case unix.IFA_LABEL:
a.Label = nlenc.String(attr.Data)
a.Label = ad.String()
case unix.IFA_BROADCAST:
if len(attr.Data) != 4 {
if len(ad.Bytes()) != 4 {
return errInvalidAddressMessageAttr
}
a.Broadcast = attr.Data
a.Broadcast = ad.Bytes()
case unix.IFA_ANYCAST:
if len(attr.Data) != 4 && len(attr.Data) != 16 {
l := len(ad.Bytes())
if l != 4 && l != 16 {
return errInvalidAddressMessageAttr
}
a.Anycast = attr.Data
a.Anycast = ad.Bytes()
case unix.IFA_CACHEINFO:
if len(attr.Data) != 16 {
if len(ad.Bytes()) != 16 {
return errInvalidAddressMessageAttr
}
err := a.CacheInfo.UnmarshalBinary(attr.Data)
err := a.CacheInfo.unmarshalBinary(ad.Bytes())
if err != nil {
return err
}
case unix.IFA_MULTICAST:
if len(attr.Data) != 4 && len(attr.Data) != 16 {
l := len(ad.Bytes())
if l != 4 && l != 16 {
return errInvalidAddressMessageAttr
}
a.Multicast = attr.Data
a.Multicast = ad.Bytes()
case unix.IFA_FLAGS:
if len(attr.Data) != 4 {
if len(ad.Bytes()) != 4 {
return errInvalidAddressMessageAttr
}
a.Flags = nlenc.Uint32(attr.Data)
a.Flags = ad.Uint32()
}
}
return nil
}
// MarshalBinary marshals a AddressAttributes into a byte slice.
func (a *AddressAttributes) MarshalBinary() ([]byte, error) {
attrs := []netlink.Attribute{
{
Type: unix.IFA_UNSPEC,
Data: nlenc.Uint16Bytes(0),
},
{
Type: unix.IFA_ADDRESS,
Data: a.Address,
},
{
Type: unix.IFA_BROADCAST,
Data: a.Broadcast,
},
{
Type: unix.IFA_ANYCAST,
Data: a.Anycast,
},
{
Type: unix.IFA_MULTICAST,
Data: a.Multicast,
},
{
Type: unix.IFA_FLAGS,
Data: nlenc.Uint32Bytes(a.Flags),
},
}
func (a *AddressAttributes) encode(ae *netlink.AttributeEncoder) error {
ae.Uint16(unix.IFA_UNSPEC, 0)
ae.Bytes(unix.IFA_ADDRESS, a.Address)
ae.Bytes(unix.IFA_BROADCAST, a.Broadcast)
ae.Bytes(unix.IFA_ANYCAST, a.Anycast)
ae.Bytes(unix.IFA_MULTICAST, a.Multicast)
ae.Uint32(unix.IFA_FLAGS, a.Flags)
if a.Local != nil {
attrs = append(attrs, netlink.Attribute{
Type: unix.IFA_LOCAL,
Data: a.Local,
})
ae.Bytes(unix.IFA_LOCAL, a.Local)
}
return netlink.MarshalAttributes(attrs)
return nil
}
// CacheInfo contains address information
@ -246,16 +232,16 @@ type CacheInfo struct {
Updated uint32
}
// UnmarshalBinary unmarshals the contents of a byte slice into a LinkMessage.
func (c *CacheInfo) UnmarshalBinary(b []byte) error {
// unmarshalBinary unmarshals the contents of a byte slice into a LinkMessage.
func (c *CacheInfo) unmarshalBinary(b []byte) error {
if len(b) != 16 {
return fmt.Errorf("incorrect size, want: 16, got: %d", len(b))
}
c.Prefered = nlenc.Uint32(b[0:4])
c.Valid = nlenc.Uint32(b[4:8])
c.Created = nlenc.Uint32(b[8:12])
c.Updated = nlenc.Uint32(b[12:16])
c.Prefered = nativeEndian.Uint32(b[0:4])
c.Valid = nativeEndian.Uint32(b[4:8])
c.Created = nativeEndian.Uint32(b[8:12])
c.Updated = nativeEndian.Uint32(b[12:16])
return nil
}

13
endian.go Normal file
View File

@ -0,0 +1,13 @@
package rtnetlink
import (
"encoding/binary"
"github.com/mdlayher/netlink/nlenc"
)
var nativeEndian binary.ByteOrder
func init() {
nativeEndian = nlenc.NativeEndian()
}

9
go.mod
View File

@ -3,10 +3,7 @@ module github.com/jsimonetti/rtnetlink
go 1.12
require (
github.com/dvyukov/go-fuzz v0.0.0-20191007191509-7002bfe060a6 // indirect
github.com/elazarl/go-bindata-assetfs v1.0.0 // indirect
github.com/mdlayher/netlink v0.0.0-20190409211403-11939a169225
github.com/stephens2424/writerset v1.0.2 // indirect
golang.org/x/sys v0.0.0-20190411185658-b44545bcd369
golang.org/x/tools v0.0.0-20191007185444-6536af71d98a // indirect
github.com/mdlayher/netlink v0.0.0-20191008140946-2a17fd90af51
golang.org/x/net v0.0.0-20191007182048-72f939374954 // indirect
golang.org/x/sys v0.0.0-20191008105621-543471e840be
)

31
go.sum
View File

@ -1,31 +1,26 @@
github.com/Julusian/godocdown v0.0.0-20170816220326-6d19f8ff2df8/go.mod h1:INZr5t32rG59/5xeltqoCJoNY7e5x/3xoY9WSWVWg74=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dvyukov/go-fuzz v0.0.0-20191007191509-7002bfe060a6 h1:O02wb/njBnaCguhlHO/qh1aF8F0KhMCy9OUiEybe7NE=
github.com/dvyukov/go-fuzz v0.0.0-20191007191509-7002bfe060a6/go.mod h1:11Gm+ccJnvAhCNLlf5+cS9KjtbaD5I5zaZpFMsTHWTw=
github.com/elazarl/go-bindata-assetfs v1.0.0 h1:G/bYguwHIzWq9ZoyUQqrjTmJbbYn3j3CKKpKinvZLFk=
github.com/elazarl/go-bindata-assetfs v1.0.0/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4=
github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/jsimonetti/rtnetlink v0.0.0-20190606172950-9527aa82566a/go.mod h1:Oz+70psSo5OFh8DBl0Zv2ACw7Esh6pPUphlvZG9x7uw=
github.com/mdlayher/netlink v0.0.0-20190409211403-11939a169225 h1:CxV4h424xakl+HjTCCwbXmDK8Qu/w+rRl2+cw1HDZyM=
github.com/mdlayher/netlink v0.0.0-20190409211403-11939a169225/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/robertkrimen/godocdown v0.0.0-20130622164427-0bfa04905481/go.mod h1:C9WhFzY47SzYBIvzFqSvHIR6ROgDo4TtdTuRaOMjF/s=
github.com/stephens2424/writerset v1.0.2 h1:znRLgU6g8RS5euYRcy004XeE4W+Tu44kALzy7ghPif8=
github.com/stephens2424/writerset v1.0.2/go.mod h1:aS2JhsMn6eA7e82oNmW4rfsgAOp9COBTTl8mzkwADnc=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/mdlayher/netlink v0.0.0-20191008140946-2a17fd90af51 h1:rP02cBlv8sk9kC1iRINOapZNB9B5S6JChwmYXDiFKpU=
github.com/mdlayher/netlink v0.0.0-20191008140946-2a17fd90af51/go.mod h1:KxeJAFOFLG6AjpyDkQ/iIhxygIUKD+vcwqcnu43w/+M=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k2fySZ1zf2zCjvQCiIM=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191007182048-72f939374954 h1:JGZucVF/L/TotR719NbujzadOZ2AgnYlqphQGHDCKaU=
golang.org/x/net v0.0.0-20191007182048-72f939374954/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313 h1:pczuHS43Cp2ktBEEmLwScxgjWsBSzdaQiKzUyf3DTTc=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190411185658-b44545bcd369 h1:aBlRBZoCuZNRDClvfkDoklQqdLzBaA3uViASg2z2p24=
golang.org/x/sys v0.0.0-20190411185658-b44545bcd369/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456 h1:ng0gs1AKnRRuEMZoTLLlbOd+C17zUDepwGQBb/n+JVg=
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191008105621-543471e840be h1:QAcqgptGM8IQBC9K/RC4o+O9YmqEm0diQn9QmZw/0mU=
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20191007185444-6536af71d98a h1:mtF1GhqcFEC1RVSQxvgrZWOM22dax6fiM9VfcQoTv6U=
golang.org/x/tools v0.0.0-20191007185444-6536af71d98a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

313
link.go
View File

@ -6,7 +6,6 @@ import (
"net"
"github.com/mdlayher/netlink"
"github.com/mdlayher/netlink/nlenc"
"golang.org/x/sys/unix"
)
@ -47,15 +46,22 @@ type LinkMessage struct {
func (m *LinkMessage) MarshalBinary() ([]byte, error) {
b := make([]byte, unix.SizeofIfInfomsg)
b[0] = 0 //Family
b[1] = 0 //reserved
nlenc.PutUint16(b[2:4], m.Type)
nlenc.PutUint32(b[4:8], m.Index)
nlenc.PutUint32(b[8:12], m.Flags)
nlenc.PutUint32(b[12:16], m.Change)
b[0] = 0 // Family
b[1] = 0 // reserved
nativeEndian.PutUint16(b[2:4], m.Type)
nativeEndian.PutUint32(b[4:8], m.Index)
nativeEndian.PutUint32(b[8:12], m.Flags)
nativeEndian.PutUint32(b[12:16], m.Change)
if m.Attributes != nil {
a, err := m.Attributes.MarshalBinary()
ae := netlink.NewAttributeEncoder()
ae.ByteOrder = nativeEndian
err := m.Attributes.encode(ae)
if err != nil {
return nil, err
}
a, err := ae.Encode()
if err != nil {
return nil, err
}
@ -73,15 +79,20 @@ func (m *LinkMessage) UnmarshalBinary(b []byte) error {
return errInvalidLinkMessage
}
m.Family = nlenc.Uint16(b[0:2])
m.Type = nlenc.Uint16(b[2:4])
m.Index = nlenc.Uint32(b[4:8])
m.Flags = nlenc.Uint32(b[8:12])
m.Change = nlenc.Uint32(b[12:16])
m.Family = nativeEndian.Uint16(b[0:2])
m.Type = nativeEndian.Uint16(b[2:4])
m.Index = nativeEndian.Uint32(b[4:8])
m.Flags = nativeEndian.Uint32(b[8:12])
m.Change = nativeEndian.Uint32(b[12:16])
if l > unix.SizeofIfInfomsg {
m.Attributes = &LinkAttributes{}
err := m.Attributes.UnmarshalBinary(b[16:])
ad, err := netlink.NewAttributeDecoder(b[16:])
if err != nil {
return err
}
ad.ByteOrder = nativeEndian
err = m.Attributes.decode(ad)
if err != nil {
return err
}
@ -205,71 +216,52 @@ const (
OperStateUp // interface is in a state to send and receive packets
)
// UnmarshalBinary unmarshals the contents of a byte slice into a LinkMessage.
func (a *LinkAttributes) UnmarshalBinary(b []byte) error {
attrs, err := netlink.UnmarshalAttributes(b)
if err != nil {
return err
}
// unmarshalBinary unmarshals the contents of a byte slice into a LinkMessage.
func (a *LinkAttributes) decode(ad *netlink.AttributeDecoder) error {
for _, attr := range attrs {
switch attr.Type {
for ad.Next() {
switch ad.Type() {
case unix.IFLA_UNSPEC:
//unused attribute
// unused attribute
case unix.IFLA_ADDRESS:
l := len(attr.Data)
l := len(ad.Bytes())
if l < 4 || l > 32 {
return errInvalidLinkMessageAttr
}
a.Address = attr.Data
a.Address = ad.Bytes()
case unix.IFLA_BROADCAST:
l := len(attr.Data)
l := len(ad.Bytes())
if l < 4 || l > 32 {
return errInvalidLinkMessageAttr
}
a.Broadcast = attr.Data
a.Broadcast = ad.Bytes()
case unix.IFLA_IFNAME:
a.Name = nlenc.String(attr.Data)
a.Name = ad.String()
case unix.IFLA_MTU:
if len(attr.Data) != 4 {
return errInvalidLinkMessageAttr
}
a.MTU = nlenc.Uint32(attr.Data)
a.MTU = ad.Uint32()
case unix.IFLA_LINK:
if len(attr.Data) != 4 {
return errInvalidLinkMessageAttr
}
a.Type = nlenc.Uint32(attr.Data)
a.Type = ad.Uint32()
case unix.IFLA_QDISC:
a.QueueDisc = nlenc.String(attr.Data)
a.QueueDisc = ad.String()
case unix.IFLA_OPERSTATE:
if len(attr.Data) != 1 {
return errInvalidLinkMessageAttr
}
a.OperationalState = OperationalState(nlenc.Uint8(attr.Data))
a.OperationalState = OperationalState(ad.Uint8())
case unix.IFLA_STATS:
a.Stats = &LinkStats{}
err := a.Stats.UnmarshalBinary(attr.Data)
err := a.Stats.unmarshalBinary(ad.Bytes())
if err != nil {
return err
}
case unix.IFLA_STATS64:
a.Stats64 = &LinkStats64{}
err := a.Stats64.UnmarshalBinary(attr.Data)
err := a.Stats64.unmarshalBinary(ad.Bytes())
if err != nil {
return err
}
case unix.IFLA_LINKINFO:
a.Info = &LinkInfo{}
err := a.Info.UnmarshalBinary(attr.Data)
if err != nil {
return err
}
ad.Nested(a.Info.decode)
case unix.IFLA_MASTER:
if len(attr.Data) != 4 {
return errInvalidLinkMessageAttr
}
v := nlenc.Uint32(attr.Data)
v := ad.Uint32()
a.Master = &v
}
}
@ -278,73 +270,48 @@ func (a *LinkAttributes) UnmarshalBinary(b []byte) error {
}
// MarshalBinary marshals a LinkAttributes into a byte slice.
func (a *LinkAttributes) MarshalBinary() ([]byte, error) {
attrs := []netlink.Attribute{
{
Type: unix.IFLA_UNSPEC,
Data: nlenc.Uint16Bytes(0),
},
{
Type: unix.IFLA_IFNAME,
Data: nlenc.Bytes(a.Name),
},
{
Type: unix.IFLA_LINK,
Data: nlenc.Uint32Bytes(a.Type),
},
{
Type: unix.IFLA_QDISC,
Data: nlenc.Bytes(a.QueueDisc),
},
}
func (a *LinkAttributes) encode(ae *netlink.AttributeEncoder) error {
ae.Uint16(unix.IFLA_UNSPEC, 0)
ae.String(unix.IFLA_IFNAME, a.Name)
ae.Uint32(unix.IFLA_LINK, a.Type)
ae.String(unix.IFLA_QDISC, a.QueueDisc)
if a.MTU != 0 {
attrs = append(attrs, netlink.Attribute{
Type: unix.IFLA_MTU,
Data: nlenc.Uint32Bytes(a.MTU),
})
ae.Uint32(unix.IFLA_MTU, a.MTU)
}
if len(a.Address) != 0 {
attrs = append(attrs, netlink.Attribute{
Type: unix.IFLA_ADDRESS,
Data: a.Address,
})
ae.Bytes(unix.IFLA_ADDRESS, a.Address)
}
if len(a.Broadcast) != 0 {
attrs = append(attrs, netlink.Attribute{
Type: unix.IFLA_BROADCAST,
Data: a.Broadcast,
})
ae.Bytes(unix.IFLA_BROADCAST, a.Broadcast)
}
if a.OperationalState != OperStateUnknown {
attrs = append(attrs, netlink.Attribute{
Type: unix.IFLA_OPERSTATE,
Data: nlenc.Uint8Bytes(uint8(a.OperationalState)),
})
ae.Uint8(unix.IFLA_OPERSTATE, uint8(a.OperationalState))
}
if a.Info != nil {
info, err := a.Info.MarshalBinary()
nae := netlink.NewAttributeEncoder()
nae.ByteOrder = ae.ByteOrder
err := a.Info.encode(nae)
if err != nil {
return nil, err
return err
}
attrs = append(attrs, netlink.Attribute{
Type: unix.IFLA_LINKINFO,
Data: info,
})
b, err := nae.Encode()
if err != nil {
return err
}
ae.Bytes(unix.IFLA_LINKINFO, b)
}
if a.Master != nil {
attrs = append(attrs, netlink.Attribute{
Type: unix.IFLA_MASTER,
Data: nlenc.Uint32Bytes(*a.Master),
})
ae.Uint32(unix.IFLA_MASTER, *a.Master)
}
return netlink.MarshalAttributes(attrs)
return nil
}
// LinkStats contains packet statistics
@ -382,42 +349,42 @@ type LinkStats struct {
RXNoHandler uint32 // dropped, no handler found
}
// UnmarshalBinary unmarshals the contents of a byte slice into a LinkMessage.
func (a *LinkStats) UnmarshalBinary(b []byte) error {
// unmarshalBinary unmarshals the contents of a byte slice into a LinkMessage.
func (a *LinkStats) unmarshalBinary(b []byte) error {
l := len(b)
if l != 92 && l != 96 {
return fmt.Errorf("incorrect size, want: 92 or 96")
}
a.RXPackets = nlenc.Uint32(b[0:4])
a.TXPackets = nlenc.Uint32(b[4:8])
a.RXBytes = nlenc.Uint32(b[8:12])
a.TXBytes = nlenc.Uint32(b[12:16])
a.RXErrors = nlenc.Uint32(b[16:20])
a.TXErrors = nlenc.Uint32(b[20:24])
a.RXDropped = nlenc.Uint32(b[24:28])
a.TXDropped = nlenc.Uint32(b[28:32])
a.Multicast = nlenc.Uint32(b[32:36])
a.Collisions = nlenc.Uint32(b[36:40])
a.RXPackets = nativeEndian.Uint32(b[0:4])
a.TXPackets = nativeEndian.Uint32(b[4:8])
a.RXBytes = nativeEndian.Uint32(b[8:12])
a.TXBytes = nativeEndian.Uint32(b[12:16])
a.RXErrors = nativeEndian.Uint32(b[16:20])
a.TXErrors = nativeEndian.Uint32(b[20:24])
a.RXDropped = nativeEndian.Uint32(b[24:28])
a.TXDropped = nativeEndian.Uint32(b[28:32])
a.Multicast = nativeEndian.Uint32(b[32:36])
a.Collisions = nativeEndian.Uint32(b[36:40])
a.RXLengthErrors = nlenc.Uint32(b[40:44])
a.RXOverErrors = nlenc.Uint32(b[44:48])
a.RXCRCErrors = nlenc.Uint32(b[48:52])
a.RXFrameErrors = nlenc.Uint32(b[52:56])
a.RXFIFOErrors = nlenc.Uint32(b[56:60])
a.RXMissedErrors = nlenc.Uint32(b[60:64])
a.RXLengthErrors = nativeEndian.Uint32(b[40:44])
a.RXOverErrors = nativeEndian.Uint32(b[44:48])
a.RXCRCErrors = nativeEndian.Uint32(b[48:52])
a.RXFrameErrors = nativeEndian.Uint32(b[52:56])
a.RXFIFOErrors = nativeEndian.Uint32(b[56:60])
a.RXMissedErrors = nativeEndian.Uint32(b[60:64])
a.TXAbortedErrors = nlenc.Uint32(b[64:68])
a.TXCarrierErrors = nlenc.Uint32(b[68:72])
a.TXFIFOErrors = nlenc.Uint32(b[72:76])
a.TXHeartbeatErrors = nlenc.Uint32(b[76:80])
a.TXWindowErrors = nlenc.Uint32(b[80:84])
a.TXAbortedErrors = nativeEndian.Uint32(b[64:68])
a.TXCarrierErrors = nativeEndian.Uint32(b[68:72])
a.TXFIFOErrors = nativeEndian.Uint32(b[72:76])
a.TXHeartbeatErrors = nativeEndian.Uint32(b[76:80])
a.TXWindowErrors = nativeEndian.Uint32(b[80:84])
a.RXCompressed = nlenc.Uint32(b[84:88])
a.TXCompressed = nlenc.Uint32(b[88:92])
a.RXCompressed = nativeEndian.Uint32(b[84:88])
a.TXCompressed = nativeEndian.Uint32(b[88:92])
if l == 96 {
a.RXNoHandler = nlenc.Uint32(b[92:96])
a.RXNoHandler = nativeEndian.Uint32(b[92:96])
}
return nil
@ -458,42 +425,42 @@ type LinkStats64 struct {
RXNoHandler uint64 // dropped, no handler found
}
// UnmarshalBinary unmarshals the contents of a byte slice into a LinkMessage.
func (a *LinkStats64) UnmarshalBinary(b []byte) error {
// unmarshalBinary unmarshals the contents of a byte slice into a LinkMessage.
func (a *LinkStats64) unmarshalBinary(b []byte) error {
l := len(b)
if l != 184 && l != 192 {
return fmt.Errorf("incorrect size, want: 184 or 192")
}
a.RXPackets = nlenc.Uint64(b[0:8])
a.TXPackets = nlenc.Uint64(b[8:16])
a.RXBytes = nlenc.Uint64(b[16:24])
a.TXBytes = nlenc.Uint64(b[24:32])
a.RXErrors = nlenc.Uint64(b[32:40])
a.TXErrors = nlenc.Uint64(b[40:48])
a.RXDropped = nlenc.Uint64(b[48:56])
a.TXDropped = nlenc.Uint64(b[56:64])
a.Multicast = nlenc.Uint64(b[64:72])
a.Collisions = nlenc.Uint64(b[72:80])
a.RXPackets = nativeEndian.Uint64(b[0:8])
a.TXPackets = nativeEndian.Uint64(b[8:16])
a.RXBytes = nativeEndian.Uint64(b[16:24])
a.TXBytes = nativeEndian.Uint64(b[24:32])
a.RXErrors = nativeEndian.Uint64(b[32:40])
a.TXErrors = nativeEndian.Uint64(b[40:48])
a.RXDropped = nativeEndian.Uint64(b[48:56])
a.TXDropped = nativeEndian.Uint64(b[56:64])
a.Multicast = nativeEndian.Uint64(b[64:72])
a.Collisions = nativeEndian.Uint64(b[72:80])
a.RXLengthErrors = nlenc.Uint64(b[80:88])
a.RXOverErrors = nlenc.Uint64(b[88:96])
a.RXCRCErrors = nlenc.Uint64(b[96:104])
a.RXFrameErrors = nlenc.Uint64(b[104:112])
a.RXFIFOErrors = nlenc.Uint64(b[112:120])
a.RXMissedErrors = nlenc.Uint64(b[120:128])
a.RXLengthErrors = nativeEndian.Uint64(b[80:88])
a.RXOverErrors = nativeEndian.Uint64(b[88:96])
a.RXCRCErrors = nativeEndian.Uint64(b[96:104])
a.RXFrameErrors = nativeEndian.Uint64(b[104:112])
a.RXFIFOErrors = nativeEndian.Uint64(b[112:120])
a.RXMissedErrors = nativeEndian.Uint64(b[120:128])
a.TXAbortedErrors = nlenc.Uint64(b[128:136])
a.TXCarrierErrors = nlenc.Uint64(b[136:144])
a.TXFIFOErrors = nlenc.Uint64(b[144:152])
a.TXHeartbeatErrors = nlenc.Uint64(b[152:160])
a.TXWindowErrors = nlenc.Uint64(b[160:168])
a.TXAbortedErrors = nativeEndian.Uint64(b[128:136])
a.TXCarrierErrors = nativeEndian.Uint64(b[136:144])
a.TXFIFOErrors = nativeEndian.Uint64(b[144:152])
a.TXHeartbeatErrors = nativeEndian.Uint64(b[152:160])
a.TXWindowErrors = nativeEndian.Uint64(b[160:168])
a.RXCompressed = nlenc.Uint64(b[168:176])
a.TXCompressed = nlenc.Uint64(b[176:184])
a.RXCompressed = nativeEndian.Uint64(b[168:176])
a.TXCompressed = nativeEndian.Uint64(b[176:184])
if l == 192 {
a.RXNoHandler = nlenc.Uint64(b[184:192])
a.RXNoHandler = nativeEndian.Uint64(b[184:192])
}
return nil
@ -507,54 +474,32 @@ type LinkInfo struct {
SlaveData []byte // Slave driver specific configuration
}
// UnmarshalBinary unmarshals the contents of a byte slice into a LinkInfo.
func (i *LinkInfo) UnmarshalBinary(b []byte) error {
attrs, err := netlink.UnmarshalAttributes(b)
if err != nil {
return err
}
func (i *LinkInfo) decode(ad *netlink.AttributeDecoder) error {
for _, attr := range attrs {
switch attr.Type {
for ad.Next() {
switch ad.Type() {
case unix.IFLA_INFO_KIND:
i.Kind = nlenc.String(attr.Data)
i.Kind = ad.String()
case unix.IFLA_INFO_SLAVE_KIND:
i.SlaveKind = nlenc.String(attr.Data)
i.SlaveKind = ad.String()
case unix.IFLA_INFO_DATA:
i.Data = attr.Data
i.Data = ad.Bytes()
case unix.IFLA_INFO_SLAVE_DATA:
i.SlaveData = attr.Data
i.SlaveData = ad.Bytes()
}
}
return nil
}
// MarshalBinary marshals a LinkInfo into a byte slice.
func (i *LinkInfo) MarshalBinary() ([]byte, error) {
attrs := []netlink.Attribute{
{
Type: unix.IFLA_INFO_KIND,
Data: nlenc.Bytes(i.Kind),
},
{
Type: unix.IFLA_INFO_DATA,
Data: i.Data,
},
}
func (i *LinkInfo) encode(ae *netlink.AttributeEncoder) error {
ae.String(unix.IFLA_INFO_KIND, i.Kind)
ae.Bytes(unix.IFLA_INFO_DATA, i.Data)
if len(i.SlaveData) > 0 {
attrs = append(attrs,
netlink.Attribute{
Type: unix.IFLA_INFO_SLAVE_KIND,
Data: nlenc.Bytes(i.SlaveKind),
},
netlink.Attribute{
Type: unix.IFLA_INFO_SLAVE_DATA,
Data: i.SlaveData,
},
)
ae.String(unix.IFLA_INFO_SLAVE_KIND, i.SlaveKind)
ae.Bytes(unix.IFLA_INFO_SLAVE_DATA, i.SlaveData)
}
return netlink.MarshalAttributes(attrs)
return nil
}

View File

@ -488,7 +488,7 @@ func TestLinkStatsUnmarshalBinary(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
m := &LinkStats{}
err := (m).UnmarshalBinary(tt.b)
err := (m).unmarshalBinary(tt.b)
if err != nil {
if want, got := fmt.Sprintf("%s", tt.err), fmt.Sprintf("%s", err); want != got {
@ -643,7 +643,7 @@ func TestLinkStats64UnmarshalBinary(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
m := &LinkStats64{}
err := (m).UnmarshalBinary(tt.b)
err := (m).unmarshalBinary(tt.b)
if err != nil {
if want, got := fmt.Sprintf("%s", tt.err), fmt.Sprintf("%s", err); want != got {

View File

@ -6,7 +6,6 @@ import (
"net"
"github.com/mdlayher/netlink"
"github.com/mdlayher/netlink/nlenc"
"golang.org/x/sys/unix"
)
@ -45,15 +44,22 @@ type NeighMessage struct {
func (m *NeighMessage) MarshalBinary() ([]byte, error) {
b := make([]byte, unix.SizeofNdMsg)
nlenc.PutUint16(b[0:2], m.Family)
nativeEndian.PutUint16(b[0:2], m.Family)
// bytes 3 and 4 are padding
nlenc.PutUint32(b[4:8], m.Index)
nlenc.PutUint16(b[8:10], m.State)
nativeEndian.PutUint32(b[4:8], m.Index)
nativeEndian.PutUint16(b[8:10], m.State)
b[10] = m.Flags
b[11] = m.Type
if m.Attributes != nil {
a, err := m.Attributes.MarshalBinary()
ae := netlink.NewAttributeEncoder()
ae.ByteOrder = nativeEndian
err := m.Attributes.encode(ae)
if err != nil {
return nil, err
}
a, err := ae.Encode()
if err != nil {
return nil, err
}
@ -70,15 +76,20 @@ func (m *NeighMessage) UnmarshalBinary(b []byte) error {
return errInvalidNeighMessage
}
m.Family = nlenc.Uint16(b[0:2])
m.Index = nlenc.Uint32(b[4:8])
m.State = nlenc.Uint16(b[8:10])
m.Family = nativeEndian.Uint16(b[0:2])
m.Index = nativeEndian.Uint32(b[4:8])
m.State = nativeEndian.Uint16(b[8:10])
m.Flags = b[10]
m.Type = b[11]
if l > unix.SizeofNdMsg {
m.Attributes = &NeighAttributes{}
err := m.Attributes.UnmarshalBinary(b[unix.SizeofNdMsg:])
ad, err := netlink.NewAttributeDecoder(b[unix.SizeofNdMsg:])
if err != nil {
return err
}
ad.ByteOrder = nativeEndian
err = m.Attributes.decode(ad)
if err != nil {
return err
}
@ -147,15 +158,15 @@ type NeighCacheInfo struct {
}
// UnmarshalBinary unmarshals the contents of a byte slice into a NeighMessage.
func (n *NeighCacheInfo) UnmarshalBinary(b []byte) error {
func (n *NeighCacheInfo) unmarshalBinary(b []byte) error {
if len(b) != 16 {
return fmt.Errorf("incorrect size, want: 16, got: %d", len(b))
}
n.Confirmed = nlenc.Uint32(b[0:4])
n.Used = nlenc.Uint32(b[4:8])
n.Updated = nlenc.Uint32(b[8:12])
n.RefCount = nlenc.Uint32(b[12:16])
n.Confirmed = nativeEndian.Uint32(b[0:4])
n.Used = nativeEndian.Uint32(b[4:8])
n.Updated = nativeEndian.Uint32(b[8:12])
n.RefCount = nativeEndian.Uint32(b[12:16])
return nil
}
@ -168,64 +179,42 @@ type NeighAttributes struct {
IfIndex uint32
}
// NeighAttributes unmarshals the contents of a byte slice into a NeighMessage.
func (a *NeighAttributes) UnmarshalBinary(b []byte) error {
attrs, err := netlink.UnmarshalAttributes(b)
if err != nil {
return err
}
func (a *NeighAttributes) decode(ad *netlink.AttributeDecoder) error {
for _, attr := range attrs {
switch attr.Type {
for ad.Next() {
switch ad.Type() {
case unix.NDA_UNSPEC:
//unused attribute
// unused attribute
case unix.NDA_DST:
if len(attr.Data) != 4 && len(attr.Data) != 16 {
l := len(ad.Bytes())
if l != 4 && l != 16 {
return errInvalidNeighMessageAttr
}
a.Address = attr.Data
a.Address = ad.Bytes()
case unix.NDA_LLADDR:
if len(attr.Data) != 6 {
if len(ad.Bytes()) != 6 {
return errInvalidNeighMessageAttr
}
a.LLAddress = attr.Data
a.LLAddress = ad.Bytes()
case unix.NDA_CACHEINFO:
a.CacheInfo = &NeighCacheInfo{}
err := a.CacheInfo.UnmarshalBinary(attr.Data)
err := a.CacheInfo.unmarshalBinary(ad.Bytes())
if err != nil {
return err
}
case unix.NDA_IFINDEX:
if len(attr.Data) != 4 {
return errInvalidNeighMessageAttr
}
a.IfIndex = nlenc.Uint32(attr.Data)
a.IfIndex = ad.Uint32()
}
}
return nil
}
// MarshalBinary marshals a NeighAttributes into a byte slice.
func (a *NeighAttributes) MarshalBinary() ([]byte, error) {
attrs := []netlink.Attribute{
{
Type: unix.NDA_UNSPEC,
Data: nlenc.Uint16Bytes(0),
},
{
Type: unix.NDA_DST,
Data: a.Address,
},
{
Type: unix.NDA_LLADDR,
Data: a.LLAddress,
},
{
Type: unix.NDA_IFINDEX,
Data: nlenc.Uint32Bytes(a.IfIndex),
},
}
func (a *NeighAttributes) encode(ae *netlink.AttributeEncoder) error {
ae.Uint16(unix.NDA_UNSPEC, 0)
ae.Bytes(unix.NDA_DST, a.Address)
ae.Bytes(unix.NDA_LLADDR, a.LLAddress)
ae.Uint32(unix.NDA_IFINDEX, a.IfIndex)
return netlink.MarshalAttributes(attrs)
return nil
}

123
route.go
View File

@ -5,7 +5,6 @@ import (
"net"
"github.com/mdlayher/netlink"
"github.com/mdlayher/netlink/nlenc"
"golang.org/x/sys/unix"
)
@ -44,9 +43,16 @@ func (m *RouteMessage) MarshalBinary() ([]byte, error) {
b[5] = m.Protocol
b[6] = m.Scope
b[7] = m.Type
nlenc.PutUint32(b[8:12], m.Flags)
nativeEndian.PutUint32(b[8:12], m.Flags)
a, err := m.Attributes.MarshalBinary()
ae := netlink.NewAttributeEncoder()
ae.ByteOrder = nativeEndian
err := m.Attributes.encode(ae)
if err != nil {
return nil, err
}
a, err := ae.Encode()
if err != nil {
return nil, err
}
@ -68,11 +74,16 @@ func (m *RouteMessage) UnmarshalBinary(b []byte) error {
m.Protocol = uint8(b[5])
m.Scope = uint8(b[6])
m.Type = uint8(b[7])
m.Flags = nlenc.Uint32(b[8:12])
m.Flags = nativeEndian.Uint32(b[8:12])
if l > unix.SizeofRtMsg {
m.Attributes = RouteAttributes{}
err := m.Attributes.UnmarshalBinary(b[unix.SizeofRtMsg:])
ad, err := netlink.NewAttributeDecoder(b[unix.SizeofRtMsg:])
ad.ByteOrder = nativeEndian
if err != nil {
return err
}
err = m.Attributes.decode(ad)
if err != nil {
return err
}
@ -156,49 +167,38 @@ type RouteAttributes struct {
Expires *uint32
}
func (a *RouteAttributes) UnmarshalBinary(b []byte) error {
attrs, err := netlink.UnmarshalAttributes(b)
if err != nil {
return err
}
for _, attr := range attrs {
switch attr.Type {
func (a *RouteAttributes) decode(ad *netlink.AttributeDecoder) error {
for ad.Next() {
switch ad.Type() {
case unix.RTA_UNSPEC:
//unused attribute
case unix.RTA_DST:
if len(attr.Data) != 4 && len(attr.Data) != 16 {
l := len(ad.Bytes())
if l != 4 && l != 16 {
return errInvalidRouteMessageAttr
}
a.Dst = attr.Data
a.Dst = ad.Bytes()
case unix.RTA_PREFSRC:
if len(attr.Data) != 4 && len(attr.Data) != 16 {
l := len(ad.Bytes())
if l != 4 && l != 16 {
return errInvalidRouteMessageAttr
}
a.Src = attr.Data
a.Src = ad.Bytes()
case unix.RTA_GATEWAY:
if len(attr.Data) != 4 && len(attr.Data) != 16 {
l := len(ad.Bytes())
if l != 4 && l != 16 {
return errInvalidRouteMessageAttr
}
a.Gateway = attr.Data
a.Gateway = ad.Bytes()
case unix.RTA_OIF:
if len(attr.Data) != 4 {
return errInvalidRouteMessageAttr
}
a.OutIface = nlenc.Uint32(attr.Data)
a.OutIface = ad.Uint32()
case unix.RTA_PRIORITY:
if len(attr.Data) != 4 {
return errInvalidRouteMessageAttr
}
a.Priority = nlenc.Uint32(attr.Data)
a.Priority = ad.Uint32()
case unix.RTA_TABLE:
if len(attr.Data) != 4 {
return errInvalidRouteMessageAttr
}
a.Table = nlenc.Uint32(attr.Data)
a.Table = ad.Uint32()
case unix.RTA_EXPIRES:
if len(attr.Data) != 4 {
return errInvalidRouteMessageAttr
}
timeout := nlenc.Uint32(attr.Data)
timeout := ad.Uint32()
a.Expires = &timeout
}
}
@ -206,84 +206,53 @@ func (a *RouteAttributes) UnmarshalBinary(b []byte) error {
return nil
}
func (a *RouteAttributes) MarshalBinary() ([]byte, error) {
attrs := make([]netlink.Attribute, 0)
func (a *RouteAttributes) encode(ae *netlink.AttributeEncoder) error {
if a.Dst != nil {
if ipv4 := a.Dst.To4(); ipv4 == nil {
// Dst Addr is IPv6
attrs = append(attrs, netlink.Attribute{
Type: unix.RTA_DST,
Data: a.Dst,
})
ae.Bytes(unix.RTA_DST, a.Dst)
} else {
// Dst Addr is IPv4
attrs = append(attrs, netlink.Attribute{
Type: unix.RTA_DST,
Data: ipv4,
})
ae.Bytes(unix.RTA_DST, ipv4)
}
}
if a.Src != nil {
if ipv4 := a.Src.To4(); ipv4 == nil {
// Src Addr is IPv6
attrs = append(attrs, netlink.Attribute{
Type: unix.RTA_PREFSRC,
Data: a.Src,
})
ae.Bytes(unix.RTA_PREFSRC, a.Src)
} else {
// Src Addr is IPv4
attrs = append(attrs, netlink.Attribute{
Type: unix.RTA_PREFSRC,
Data: ipv4,
})
ae.Bytes(unix.RTA_PREFSRC, ipv4)
}
}
if a.Gateway != nil {
if ipv4 := a.Gateway.To4(); ipv4 == nil {
// Gateway Addr is IPv6
attrs = append(attrs, netlink.Attribute{
Type: unix.RTA_GATEWAY,
Data: a.Gateway,
})
ae.Bytes(unix.RTA_GATEWAY, a.Gateway)
} else {
// Gateway Addr is IPv4
attrs = append(attrs, netlink.Attribute{
Type: unix.RTA_GATEWAY,
Data: ipv4,
})
ae.Bytes(unix.RTA_GATEWAY, ipv4)
}
}
if a.OutIface != 0 {
attrs = append(attrs, netlink.Attribute{
Type: unix.RTA_OIF,
Data: nlenc.Uint32Bytes(a.OutIface),
})
ae.Uint32(unix.RTA_OIF, a.OutIface)
}
if a.Priority != 0 {
attrs = append(attrs, netlink.Attribute{
Type: unix.RTA_PRIORITY,
Data: nlenc.Uint32Bytes(a.Priority),
})
ae.Uint32(unix.RTA_PRIORITY, a.Priority)
}
if a.Table != 0 {
attrs = append(attrs, netlink.Attribute{
Type: unix.RTA_TABLE,
Data: nlenc.Uint32Bytes(a.Table),
})
ae.Uint32(unix.RTA_TABLE, a.Table)
}
if a.Expires != nil {
attrs = append(attrs, netlink.Attribute{
Type: unix.RTA_EXPIRES,
Data: nlenc.Uint32Bytes(*a.Expires),
})
ae.Uint32(unix.RTA_EXPIRES, *a.Expires)
}
return netlink.MarshalAttributes(attrs)
return nil
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More