Browse code

Vendor netlink @ebdfb74

Signed-off-by: Alessandro Boch <aboch@docker.com>

Alessandro Boch authored on 2017/01/24 15:47:37
Showing 13 changed files
... ...
@@ -32,7 +32,7 @@ github.com/hashicorp/go-multierror fcdddc395df1ddf4247c69bd436e84cfa0733f7e
32 32
 github.com/hashicorp/serf 598c54895cc5a7b1a24a398d635e8c0ea0959870
33 33
 github.com/docker/libkv 1d8431073ae03cdaedb198a89722f3aab6d418ef
34 34
 github.com/vishvananda/netns 604eaf189ee867d8c147fafc28def2394e878d25
35
-github.com/vishvananda/netlink 482f7a52b758233521878cb6c5904b6bd63f3457
35
+github.com/vishvananda/netlink ebdfb7402004b397e6573c71132160d8e23cc12a
36 36
 github.com/BurntSushi/toml f706d00e3de6abe700c994cdd545a1a4915af060
37 37
 github.com/samuel/go-zookeeper d0e0d8e11f318e000a8cc434616d69e329edc374
38 38
 github.com/deckarep/golang-set ef32fa3046d9f249d399f98ebaf9be944430fd1d
... ...
@@ -13,6 +13,7 @@ type Addr struct {
13 13
 	Label string
14 14
 	Flags int
15 15
 	Scope int
16
+	Peer  *net.IPNet
16 17
 }
17 18
 
18 19
 // String returns $ip/$netmask $label
... ...
@@ -43,3 +44,10 @@ func (a Addr) Equal(x Addr) bool {
43 43
 	// ignore label for comparison
44 44
 	return a.IP.Equal(x.IP) && sizea == sizeb
45 45
 }
46
+
47
+func (a Addr) PeerEqual(x Addr) bool {
48
+	sizea, _ := a.Peer.Mask.Size()
49
+	sizeb, _ := x.Peer.Mask.Size()
50
+	// ignore label for comparison
51
+	return a.Peer.IP.Equal(x.Peer.IP) && sizea == sizeb
52
+}
... ...
@@ -56,17 +56,27 @@ func (h *Handle) addrHandle(link Link, addr *Addr, req *nl.NetlinkRequest) error
56 56
 	msg.Prefixlen = uint8(prefixlen)
57 57
 	req.AddData(msg)
58 58
 
59
-	var addrData []byte
59
+	var localAddrData []byte
60 60
 	if family == FAMILY_V4 {
61
-		addrData = addr.IP.To4()
61
+		localAddrData = addr.IP.To4()
62 62
 	} else {
63
-		addrData = addr.IP.To16()
63
+		localAddrData = addr.IP.To16()
64 64
 	}
65 65
 
66
-	localData := nl.NewRtAttr(syscall.IFA_LOCAL, addrData)
66
+	localData := nl.NewRtAttr(syscall.IFA_LOCAL, localAddrData)
67 67
 	req.AddData(localData)
68
+	var peerAddrData []byte
69
+	if addr.Peer != nil {
70
+		if family == FAMILY_V4 {
71
+			peerAddrData = addr.Peer.IP.To4()
72
+		} else {
73
+			peerAddrData = addr.Peer.IP.To16()
74
+		}
75
+	} else {
76
+		peerAddrData = localAddrData
77
+	}
68 78
 
69
-	addressData := nl.NewRtAttr(syscall.IFA_ADDRESS, addrData)
79
+	addressData := nl.NewRtAttr(syscall.IFA_ADDRESS, peerAddrData)
70 80
 	req.AddData(addressData)
71 81
 
72 82
 	if addr.Flags != 0 {
... ...
@@ -161,11 +171,13 @@ func parseAddr(m []byte) (addr Addr, family, index int, err error) {
161 161
 				IP:   attr.Value,
162 162
 				Mask: net.CIDRMask(int(msg.Prefixlen), 8*len(attr.Value)),
163 163
 			}
164
+			addr.Peer = dst
164 165
 		case syscall.IFA_LOCAL:
165 166
 			local = &net.IPNet{
166 167
 				IP:   attr.Value,
167 168
 				Mask: net.CIDRMask(int(msg.Prefixlen), 8*len(attr.Value)),
168 169
 			}
170
+			addr.IPNet = local
169 171
 		case syscall.IFA_LABEL:
170 172
 			addr.Label = string(attr.Value[:len(attr.Value)-1])
171 173
 		case IFA_FLAGS:
172 174
new file mode 100644
... ...
@@ -0,0 +1,218 @@
0
+// +build !linux
1
+
2
+package netlink
3
+
4
+import (
5
+	"net"
6
+	"time"
7
+
8
+	"github.com/vishvananda/netns"
9
+)
10
+
11
+type Handle struct{}
12
+
13
+func NewHandle(nlFamilies ...int) (*Handle, error) {
14
+	return nil, ErrNotImplemented
15
+}
16
+
17
+func NewHandleAt(ns netns.NsHandle, nlFamilies ...int) (*Handle, error) {
18
+	return nil, ErrNotImplemented
19
+}
20
+
21
+func NewHandleAtFrom(newNs, curNs netns.NsHandle) (*Handle, error) {
22
+	return nil, ErrNotImplemented
23
+}
24
+
25
+func (h *Handle) Delete() {}
26
+
27
+func (h *Handle) SupportsNetlinkFamily(nlFamily int) bool {
28
+	return false
29
+}
30
+
31
+func (h *Handle) SetSocketTimeout(to time.Duration) error {
32
+	return ErrNotImplemented
33
+}
34
+
35
+func (h *Handle) SetPromiscOn(link Link) error {
36
+	return ErrNotImplemented
37
+}
38
+
39
+func (h *Handle) SetPromiscOff(link Link) error {
40
+	return ErrNotImplemented
41
+}
42
+
43
+func (h *Handle) LinkSetUp(link Link) error {
44
+	return ErrNotImplemented
45
+}
46
+
47
+func (h *Handle) LinkSetDown(link Link) error {
48
+	return ErrNotImplemented
49
+}
50
+
51
+func (h *Handle) LinkSetMTU(link Link, mtu int) error {
52
+	return ErrNotImplemented
53
+}
54
+
55
+func (h *Handle) LinkSetName(link Link, name string) error {
56
+	return ErrNotImplemented
57
+}
58
+
59
+func (h *Handle) LinkSetAlias(link Link, name string) error {
60
+	return ErrNotImplemented
61
+}
62
+
63
+func (h *Handle) LinkSetHardwareAddr(link Link, hwaddr net.HardwareAddr) error {
64
+	return ErrNotImplemented
65
+}
66
+
67
+func (h *Handle) LinkSetVfHardwareAddr(link Link, vf int, hwaddr net.HardwareAddr) error {
68
+	return ErrNotImplemented
69
+}
70
+
71
+func (h *Handle) LinkSetVfVlan(link Link, vf, vlan int) error {
72
+	return ErrNotImplemented
73
+}
74
+
75
+func (h *Handle) LinkSetVfTxRate(link Link, vf, rate int) error {
76
+	return ErrNotImplemented
77
+}
78
+
79
+func (h *Handle) LinkSetMaster(link Link, master *Bridge) error {
80
+	return ErrNotImplemented
81
+}
82
+
83
+func (h *Handle) LinkSetNoMaster(link Link) error {
84
+	return ErrNotImplemented
85
+}
86
+
87
+func (h *Handle) LinkSetMasterByIndex(link Link, masterIndex int) error {
88
+	return ErrNotImplemented
89
+}
90
+
91
+func (h *Handle) LinkSetNsPid(link Link, nspid int) error {
92
+	return ErrNotImplemented
93
+}
94
+
95
+func (h *Handle) LinkSetNsFd(link Link, fd int) error {
96
+	return ErrNotImplemented
97
+}
98
+
99
+func (h *Handle) LinkAdd(link Link) error {
100
+	return ErrNotImplemented
101
+}
102
+
103
+func (h *Handle) LinkDel(link Link) error {
104
+	return ErrNotImplemented
105
+}
106
+
107
+func (h *Handle) LinkByName(name string) (Link, error) {
108
+	return nil, ErrNotImplemented
109
+}
110
+
111
+func (h *Handle) LinkByAlias(alias string) (Link, error) {
112
+	return nil, ErrNotImplemented
113
+}
114
+
115
+func (h *Handle) LinkByIndex(index int) (Link, error) {
116
+	return nil, ErrNotImplemented
117
+}
118
+
119
+func (h *Handle) LinkList() ([]Link, error) {
120
+	return nil, ErrNotImplemented
121
+}
122
+
123
+func (h *Handle) LinkSetHairpin(link Link, mode bool) error {
124
+	return ErrNotImplemented
125
+}
126
+
127
+func (h *Handle) LinkSetGuard(link Link, mode bool) error {
128
+	return ErrNotImplemented
129
+}
130
+
131
+func (h *Handle) LinkSetFastLeave(link Link, mode bool) error {
132
+	return ErrNotImplemented
133
+}
134
+
135
+func (h *Handle) LinkSetLearning(link Link, mode bool) error {
136
+	return ErrNotImplemented
137
+}
138
+
139
+func (h *Handle) LinkSetRootBlock(link Link, mode bool) error {
140
+	return ErrNotImplemented
141
+}
142
+
143
+func (h *Handle) LinkSetFlood(link Link, mode bool) error {
144
+	return ErrNotImplemented
145
+}
146
+
147
+func (h *Handle) setProtinfoAttr(link Link, mode bool, attr int) error {
148
+	return ErrNotImplemented
149
+}
150
+
151
+func (h *Handle) AddrAdd(link Link, addr *Addr) error {
152
+	return ErrNotImplemented
153
+}
154
+
155
+func (h *Handle) AddrDel(link Link, addr *Addr) error {
156
+	return ErrNotImplemented
157
+}
158
+
159
+func (h *Handle) AddrList(link Link, family int) ([]Addr, error) {
160
+	return nil, ErrNotImplemented
161
+}
162
+
163
+func (h *Handle) ClassDel(class Class) error {
164
+	return ErrNotImplemented
165
+}
166
+
167
+func (h *Handle) ClassChange(class Class) error {
168
+	return ErrNotImplemented
169
+}
170
+
171
+func (h *Handle) ClassReplace(class Class) error {
172
+	return ErrNotImplemented
173
+}
174
+
175
+func (h *Handle) ClassAdd(class Class) error {
176
+	return ErrNotImplemented
177
+}
178
+
179
+func (h *Handle) ClassList(link Link, parent uint32) ([]Class, error) {
180
+	return nil, ErrNotImplemented
181
+}
182
+
183
+func (h *Handle) FilterDel(filter Filter) error {
184
+	return ErrNotImplemented
185
+}
186
+
187
+func (h *Handle) FilterAdd(filter Filter) error {
188
+	return ErrNotImplemented
189
+}
190
+
191
+func (h *Handle) FilterList(link Link, parent uint32) ([]Filter, error) {
192
+	return nil, ErrNotImplemented
193
+}
194
+
195
+func (h *Handle) NeighAdd(neigh *Neigh) error {
196
+	return ErrNotImplemented
197
+}
198
+
199
+func (h *Handle) NeighSet(neigh *Neigh) error {
200
+	return ErrNotImplemented
201
+}
202
+
203
+func (h *Handle) NeighAppend(neigh *Neigh) error {
204
+	return ErrNotImplemented
205
+}
206
+
207
+func (h *Handle) NeighDel(neigh *Neigh) error {
208
+	return ErrNotImplemented
209
+}
210
+
211
+func (h *Handle) NeighList(linkIndex, family int) ([]Neigh, error) {
212
+	return nil, ErrNotImplemented
213
+}
214
+
215
+func (h *Handle) NeighProxyList(linkIndex, family int) ([]Neigh, error) {
216
+	return nil, ErrNotImplemented
217
+}
... ...
@@ -35,6 +35,41 @@ type LinkAttrs struct {
35 35
 	Promisc      int
36 36
 	Xdp          *LinkXdp
37 37
 	EncapType    string
38
+	Protinfo     *Protinfo
39
+	OperState    LinkOperState
40
+}
41
+
42
+// LinkOperState represents the values of the IFLA_OPERSTATE link
43
+// attribute, which contains the RFC2863 state of the interface.
44
+type LinkOperState uint8
45
+
46
+const (
47
+	OperUnknown        = iota // Status can't be determined.
48
+	OperNotPresent            // Some component is missing.
49
+	OperDown                  // Down.
50
+	OperLowerLayerDown        // Down due to state of lower layer.
51
+	OperTesting               // In some test mode.
52
+	OperDormant               // Not up but pending an external event.
53
+	OperUp                    // Up, ready to send packets.
54
+)
55
+
56
+func (s LinkOperState) String() string {
57
+	switch s {
58
+	case OperNotPresent:
59
+		return "not-present"
60
+	case OperDown:
61
+		return "down"
62
+	case OperLowerLayerDown:
63
+		return "lower-layer-down"
64
+	case OperTesting:
65
+		return "testing"
66
+	case OperDormant:
67
+		return "dormant"
68
+	case OperUp:
69
+		return "up"
70
+	default:
71
+		return "unknown"
72
+	}
38 73
 }
39 74
 
40 75
 // NewLinkAttrs returns LinkAttrs structure filled with default values
... ...
@@ -44,10 +79,12 @@ func NewLinkAttrs() LinkAttrs {
44 44
 	}
45 45
 }
46 46
 
47
+type LinkStatistics LinkStatistics64
48
+
47 49
 /*
48 50
 Ref: struct rtnl_link_stats {...}
49 51
 */
50
-type LinkStatistics struct {
52
+type LinkStatistics32 struct {
51 53
 	RxPackets         uint32
52 54
 	TxPackets         uint32
53 55
 	RxBytes           uint32
... ...
@@ -73,6 +110,63 @@ type LinkStatistics struct {
73 73
 	TxCompressed      uint32
74 74
 }
75 75
 
76
+func (s32 LinkStatistics32) to64() *LinkStatistics64 {
77
+	return &LinkStatistics64{
78
+		RxPackets:         uint64(s32.RxPackets),
79
+		TxPackets:         uint64(s32.TxPackets),
80
+		RxBytes:           uint64(s32.RxBytes),
81
+		TxBytes:           uint64(s32.TxBytes),
82
+		RxErrors:          uint64(s32.RxErrors),
83
+		TxErrors:          uint64(s32.TxErrors),
84
+		RxDropped:         uint64(s32.RxDropped),
85
+		TxDropped:         uint64(s32.TxDropped),
86
+		Multicast:         uint64(s32.Multicast),
87
+		Collisions:        uint64(s32.Collisions),
88
+		RxLengthErrors:    uint64(s32.RxLengthErrors),
89
+		RxOverErrors:      uint64(s32.RxOverErrors),
90
+		RxCrcErrors:       uint64(s32.RxCrcErrors),
91
+		RxFrameErrors:     uint64(s32.RxFrameErrors),
92
+		RxFifoErrors:      uint64(s32.RxFifoErrors),
93
+		RxMissedErrors:    uint64(s32.RxMissedErrors),
94
+		TxAbortedErrors:   uint64(s32.TxAbortedErrors),
95
+		TxCarrierErrors:   uint64(s32.TxCarrierErrors),
96
+		TxFifoErrors:      uint64(s32.TxFifoErrors),
97
+		TxHeartbeatErrors: uint64(s32.TxHeartbeatErrors),
98
+		TxWindowErrors:    uint64(s32.TxWindowErrors),
99
+		RxCompressed:      uint64(s32.RxCompressed),
100
+		TxCompressed:      uint64(s32.TxCompressed),
101
+	}
102
+}
103
+
104
+/*
105
+Ref: struct rtnl_link_stats64 {...}
106
+*/
107
+type LinkStatistics64 struct {
108
+	RxPackets         uint64
109
+	TxPackets         uint64
110
+	RxBytes           uint64
111
+	TxBytes           uint64
112
+	RxErrors          uint64
113
+	TxErrors          uint64
114
+	RxDropped         uint64
115
+	TxDropped         uint64
116
+	Multicast         uint64
117
+	Collisions        uint64
118
+	RxLengthErrors    uint64
119
+	RxOverErrors      uint64
120
+	RxCrcErrors       uint64
121
+	RxFrameErrors     uint64
122
+	RxFifoErrors      uint64
123
+	RxMissedErrors    uint64
124
+	TxAbortedErrors   uint64
125
+	TxCarrierErrors   uint64
126
+	TxFifoErrors      uint64
127
+	TxHeartbeatErrors uint64
128
+	TxWindowErrors    uint64
129
+	RxCompressed      uint64
130
+	TxCompressed      uint64
131
+}
132
+
76 133
 type LinkXdp struct {
77 134
 	Fd       int
78 135
 	Attached bool
... ...
@@ -301,31 +395,31 @@ func StringToBondMode(s string) BondMode {
301 301
 
302 302
 // Possible BondMode
303 303
 const (
304
-	BOND_MODE_802_3AD BondMode = iota
305
-	BOND_MODE_BALANCE_RR
304
+	BOND_MODE_BALANCE_RR BondMode = iota
306 305
 	BOND_MODE_ACTIVE_BACKUP
307 306
 	BOND_MODE_BALANCE_XOR
308 307
 	BOND_MODE_BROADCAST
308
+	BOND_MODE_802_3AD
309 309
 	BOND_MODE_BALANCE_TLB
310 310
 	BOND_MODE_BALANCE_ALB
311 311
 	BOND_MODE_UNKNOWN
312 312
 )
313 313
 
314 314
 var bondModeToString = map[BondMode]string{
315
-	BOND_MODE_802_3AD:       "802.3ad",
316 315
 	BOND_MODE_BALANCE_RR:    "balance-rr",
317 316
 	BOND_MODE_ACTIVE_BACKUP: "active-backup",
318 317
 	BOND_MODE_BALANCE_XOR:   "balance-xor",
319 318
 	BOND_MODE_BROADCAST:     "broadcast",
319
+	BOND_MODE_802_3AD:       "802.3ad",
320 320
 	BOND_MODE_BALANCE_TLB:   "balance-tlb",
321 321
 	BOND_MODE_BALANCE_ALB:   "balance-alb",
322 322
 }
323 323
 var StringToBondModeMap = map[string]BondMode{
324
-	"802.3ad":       BOND_MODE_802_3AD,
325 324
 	"balance-rr":    BOND_MODE_BALANCE_RR,
326 325
 	"active-backup": BOND_MODE_ACTIVE_BACKUP,
327 326
 	"balance-xor":   BOND_MODE_BALANCE_XOR,
328 327
 	"broadcast":     BOND_MODE_BROADCAST,
328
+	"802.3ad":       BOND_MODE_802_3AD,
329 329
 	"balance-tlb":   BOND_MODE_BALANCE_TLB,
330 330
 	"balance-alb":   BOND_MODE_BALANCE_ALB,
331 331
 }
... ...
@@ -589,6 +683,54 @@ func (gretap *Gretap) Type() string {
589 589
 	return "gretap"
590 590
 }
591 591
 
592
+type Iptun struct {
593
+	LinkAttrs
594
+	Ttl      uint8
595
+	Tos      uint8
596
+	PMtuDisc uint8
597
+	Link     uint32
598
+	Local    net.IP
599
+	Remote   net.IP
600
+}
601
+
602
+func (iptun *Iptun) Attrs() *LinkAttrs {
603
+	return &iptun.LinkAttrs
604
+}
605
+
606
+func (iptun *Iptun) Type() string {
607
+	return "ipip"
608
+}
609
+
610
+type Vti struct {
611
+	LinkAttrs
612
+	IKey   uint32
613
+	OKey   uint32
614
+	Link   uint32
615
+	Local  net.IP
616
+	Remote net.IP
617
+}
618
+
619
+func (vti *Vti) Attrs() *LinkAttrs {
620
+	return &vti.LinkAttrs
621
+}
622
+
623
+func (iptun *Vti) Type() string {
624
+	return "vti"
625
+}
626
+
627
+type Vrf struct {
628
+	LinkAttrs
629
+	Table uint32
630
+}
631
+
632
+func (vrf *Vrf) Attrs() *LinkAttrs {
633
+	return &vrf.LinkAttrs
634
+}
635
+
636
+func (vrf *Vrf) Type() string {
637
+	return "vrf"
638
+}
639
+
592 640
 // iproute2 supported devices;
593 641
 // vlan | veth | vcan | dummy | ifb | macvlan | macvtap |
594 642
 // bridge | bond | ipoib | ip6tnl | ipip | sit | vxlan |
... ...
@@ -13,7 +13,11 @@ import (
13 13
 	"github.com/vishvananda/netns"
14 14
 )
15 15
 
16
-const SizeofLinkStats = 0x5c
16
+const (
17
+	SizeofLinkStats32 = 0x5c
18
+	SizeofLinkStats64 = 0xd8
19
+	IFLA_STATS64      = 0x17 // syscall pkg does not contain this one
20
+)
17 21
 
18 22
 const (
19 23
 	TUNTAP_MODE_TUN  TuntapMode = syscall.IFF_TUN
... ...
@@ -783,6 +787,12 @@ func (h *Handle) LinkAdd(link Link) error {
783 783
 		}
784 784
 	} else if gretap, ok := link.(*Gretap); ok {
785 785
 		addGretapAttrs(gretap, linkInfo)
786
+	} else if iptun, ok := link.(*Iptun); ok {
787
+		addIptunAttrs(iptun, linkInfo)
788
+	} else if vti, ok := link.(*Vti); ok {
789
+		addVtiAttrs(vti, linkInfo)
790
+	} else if vrf, ok := link.(*Vrf); ok {
791
+		addVrfAttrs(vrf, linkInfo)
786 792
 	}
787 793
 
788 794
 	req.AddData(linkInfo)
... ...
@@ -949,7 +959,7 @@ func execGetLink(req *nl.NetlinkRequest) (Link, error) {
949 949
 		return nil, fmt.Errorf("Link not found")
950 950
 
951 951
 	case len(msgs) == 1:
952
-		return linkDeserialize(msgs[0])
952
+		return LinkDeserialize(nil, msgs[0])
953 953
 
954 954
 	default:
955 955
 		return nil, fmt.Errorf("More than one link found")
... ...
@@ -958,7 +968,7 @@ func execGetLink(req *nl.NetlinkRequest) (Link, error) {
958 958
 
959 959
 // linkDeserialize deserializes a raw message received from netlink into
960 960
 // a link object.
961
-func linkDeserialize(m []byte) (Link, error) {
961
+func LinkDeserialize(hdr *syscall.NlMsghdr, m []byte) (Link, error) {
962 962
 	msg := nl.DeserializeIfInfomsg(m)
963 963
 
964 964
 	attrs, err := nl.ParseRouteAttr(m[msg.Len():])
... ...
@@ -970,8 +980,12 @@ func linkDeserialize(m []byte) (Link, error) {
970 970
 	if msg.Flags&syscall.IFF_PROMISC != 0 {
971 971
 		base.Promisc = 1
972 972
 	}
973
-	var link Link
974
-	linkType := ""
973
+	var (
974
+		link     Link
975
+		stats32  []byte
976
+		stats64  []byte
977
+		linkType string
978
+	)
975 979
 	for _, attr := range attrs {
976 980
 		switch attr.Attr.Type {
977 981
 		case syscall.IFLA_LINKINFO:
... ...
@@ -1006,6 +1020,12 @@ func linkDeserialize(m []byte) (Link, error) {
1006 1006
 						link = &Macvtap{}
1007 1007
 					case "gretap":
1008 1008
 						link = &Gretap{}
1009
+					case "ipip":
1010
+						link = &Iptun{}
1011
+					case "vti":
1012
+						link = &Vti{}
1013
+					case "vrf":
1014
+						link = &Vrf{}
1009 1015
 					default:
1010 1016
 						link = &GenericLink{LinkType: linkType}
1011 1017
 					}
... ...
@@ -1029,6 +1049,12 @@ func linkDeserialize(m []byte) (Link, error) {
1029 1029
 						parseMacvtapData(link, data)
1030 1030
 					case "gretap":
1031 1031
 						parseGretapData(link, data)
1032
+					case "ipip":
1033
+						parseIptunData(link, data)
1034
+					case "vti":
1035
+						parseVtiData(link, data)
1036
+					case "vrf":
1037
+						parseVrfData(link, data)
1032 1038
 					}
1033 1039
 				}
1034 1040
 			}
... ...
@@ -1055,15 +1081,35 @@ func linkDeserialize(m []byte) (Link, error) {
1055 1055
 		case syscall.IFLA_IFALIAS:
1056 1056
 			base.Alias = string(attr.Value[:len(attr.Value)-1])
1057 1057
 		case syscall.IFLA_STATS:
1058
-			base.Statistics = parseLinkStats(attr.Value[:])
1058
+			stats32 = attr.Value[:]
1059
+		case IFLA_STATS64:
1060
+			stats64 = attr.Value[:]
1059 1061
 		case nl.IFLA_XDP:
1060 1062
 			xdp, err := parseLinkXdp(attr.Value[:])
1061 1063
 			if err != nil {
1062 1064
 				return nil, err
1063 1065
 			}
1064 1066
 			base.Xdp = xdp
1067
+		case syscall.IFLA_PROTINFO | syscall.NLA_F_NESTED:
1068
+			if hdr != nil && hdr.Type == syscall.RTM_NEWLINK &&
1069
+				msg.Family == syscall.AF_BRIDGE {
1070
+				attrs, err := nl.ParseRouteAttr(attr.Value[:])
1071
+				if err != nil {
1072
+					return nil, err
1073
+				}
1074
+				base.Protinfo = parseProtinfo(attrs)
1075
+			}
1076
+		case syscall.IFLA_OPERSTATE:
1077
+			base.OperState = LinkOperState(uint8(attr.Value[0]))
1065 1078
 		}
1066 1079
 	}
1080
+
1081
+	if stats64 != nil {
1082
+		base.Statistics = parseLinkStats64(stats64)
1083
+	} else if stats32 != nil {
1084
+		base.Statistics = parseLinkStats32(stats32)
1085
+	}
1086
+
1067 1087
 	// Links that don't have IFLA_INFO_KIND are hardware devices
1068 1088
 	if link == nil {
1069 1089
 		link = &Device{}
... ...
@@ -1096,7 +1142,7 @@ func (h *Handle) LinkList() ([]Link, error) {
1096 1096
 
1097 1097
 	var res []Link
1098 1098
 	for _, m := range msgs {
1099
-		link, err := linkDeserialize(m)
1099
+		link, err := LinkDeserialize(nil, m)
1100 1100
 		if err != nil {
1101 1101
 			return nil, err
1102 1102
 		}
... ...
@@ -1145,7 +1191,7 @@ func linkSubscribe(newNs, curNs netns.NsHandle, ch chan<- LinkUpdate, done <-cha
1145 1145
 			}
1146 1146
 			for _, m := range msgs {
1147 1147
 				ifmsg := nl.DeserializeIfInfomsg(m.Data)
1148
-				link, err := linkDeserialize(m.Data)
1148
+				link, err := LinkDeserialize(&m.Header, m.Data)
1149 1149
 				if err != nil {
1150 1150
 					return
1151 1151
 				}
... ...
@@ -1490,8 +1536,12 @@ func parseGretapData(link Link, data []syscall.NetlinkRouteAttr) {
1490 1490
 	}
1491 1491
 }
1492 1492
 
1493
-func parseLinkStats(data []byte) *LinkStatistics {
1494
-	return (*LinkStatistics)(unsafe.Pointer(&data[0:SizeofLinkStats][0]))
1493
+func parseLinkStats32(data []byte) *LinkStatistics {
1494
+	return (*LinkStatistics)((*LinkStatistics32)(unsafe.Pointer(&data[0:SizeofLinkStats32][0])).to64())
1495
+}
1496
+
1497
+func parseLinkStats64(data []byte) *LinkStatistics {
1498
+	return (*LinkStatistics)((*LinkStatistics64)(unsafe.Pointer(&data[0:SizeofLinkStats64][0])))
1495 1499
 }
1496 1500
 
1497 1501
 func addXdpAttrs(xdp *LinkXdp, req *nl.NetlinkRequest) {
... ...
@@ -1518,3 +1568,96 @@ func parseLinkXdp(data []byte) (*LinkXdp, error) {
1518 1518
 	}
1519 1519
 	return xdp, nil
1520 1520
 }
1521
+
1522
+func addIptunAttrs(iptun *Iptun, linkInfo *nl.RtAttr) {
1523
+	data := nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_DATA, nil)
1524
+
1525
+	ip := iptun.Local.To4()
1526
+	if ip != nil {
1527
+		nl.NewRtAttrChild(data, nl.IFLA_IPTUN_LOCAL, []byte(ip))
1528
+	}
1529
+
1530
+	ip = iptun.Remote.To4()
1531
+	if ip != nil {
1532
+		nl.NewRtAttrChild(data, nl.IFLA_IPTUN_REMOTE, []byte(ip))
1533
+	}
1534
+
1535
+	if iptun.Link != 0 {
1536
+		nl.NewRtAttrChild(data, nl.IFLA_IPTUN_LINK, nl.Uint32Attr(iptun.Link))
1537
+	}
1538
+	nl.NewRtAttrChild(data, nl.IFLA_IPTUN_PMTUDISC, nl.Uint8Attr(iptun.PMtuDisc))
1539
+	nl.NewRtAttrChild(data, nl.IFLA_IPTUN_TTL, nl.Uint8Attr(iptun.Ttl))
1540
+	nl.NewRtAttrChild(data, nl.IFLA_IPTUN_TOS, nl.Uint8Attr(iptun.Tos))
1541
+}
1542
+
1543
+func parseIptunData(link Link, data []syscall.NetlinkRouteAttr) {
1544
+	iptun := link.(*Iptun)
1545
+	for _, datum := range data {
1546
+		switch datum.Attr.Type {
1547
+		case nl.IFLA_IPTUN_LOCAL:
1548
+			iptun.Local = net.IP(datum.Value[0:4])
1549
+		case nl.IFLA_IPTUN_REMOTE:
1550
+			iptun.Remote = net.IP(datum.Value[0:4])
1551
+		case nl.IFLA_IPTUN_TTL:
1552
+			iptun.Ttl = uint8(datum.Value[0])
1553
+		case nl.IFLA_IPTUN_TOS:
1554
+			iptun.Tos = uint8(datum.Value[0])
1555
+		case nl.IFLA_IPTUN_PMTUDISC:
1556
+			iptun.PMtuDisc = uint8(datum.Value[0])
1557
+		}
1558
+	}
1559
+}
1560
+
1561
+func addVtiAttrs(vti *Vti, linkInfo *nl.RtAttr) {
1562
+	data := nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_DATA, nil)
1563
+
1564
+	ip := vti.Local.To4()
1565
+	if ip != nil {
1566
+		nl.NewRtAttrChild(data, nl.IFLA_VTI_LOCAL, []byte(ip))
1567
+	}
1568
+
1569
+	ip = vti.Remote.To4()
1570
+	if ip != nil {
1571
+		nl.NewRtAttrChild(data, nl.IFLA_VTI_REMOTE, []byte(ip))
1572
+	}
1573
+
1574
+	if vti.Link != 0 {
1575
+		nl.NewRtAttrChild(data, nl.IFLA_VTI_LINK, nl.Uint32Attr(vti.Link))
1576
+	}
1577
+
1578
+	nl.NewRtAttrChild(data, nl.IFLA_VTI_IKEY, htonl(vti.IKey))
1579
+	nl.NewRtAttrChild(data, nl.IFLA_VTI_OKEY, htonl(vti.OKey))
1580
+}
1581
+
1582
+func parseVtiData(link Link, data []syscall.NetlinkRouteAttr) {
1583
+	vti := link.(*Vti)
1584
+	for _, datum := range data {
1585
+		switch datum.Attr.Type {
1586
+		case nl.IFLA_VTI_LOCAL:
1587
+			vti.Local = net.IP(datum.Value[0:4])
1588
+		case nl.IFLA_VTI_REMOTE:
1589
+			vti.Remote = net.IP(datum.Value[0:4])
1590
+		case nl.IFLA_VTI_IKEY:
1591
+			vti.IKey = ntohl(datum.Value[0:4])
1592
+		case nl.IFLA_VTI_OKEY:
1593
+			vti.OKey = ntohl(datum.Value[0:4])
1594
+		}
1595
+	}
1596
+}
1597
+
1598
+func addVrfAttrs(vrf *Vrf, linkInfo *nl.RtAttr) {
1599
+	data := nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_DATA, nil)
1600
+	b := make([]byte, 4)
1601
+	native.PutUint32(b, uint32(vrf.Table))
1602
+	nl.NewRtAttrChild(data, nl.IFLA_VRF_TABLE, b)
1603
+}
1604
+
1605
+func parseVrfData(link Link, data []syscall.NetlinkRouteAttr) {
1606
+	vrf := link.(*Vrf)
1607
+	for _, datum := range data {
1608
+		switch datum.Attr.Type {
1609
+		case nl.IFLA_VRF_TABLE:
1610
+			vrf.Table = native.Uint32(datum.Value[0:4])
1611
+		}
1612
+	}
1613
+}
... ...
@@ -4,41 +4,114 @@ package netlink
4 4
 
5 5
 import (
6 6
 	"errors"
7
+	"net"
7 8
 )
8 9
 
9 10
 var (
10 11
 	ErrNotImplemented = errors.New("not implemented")
11 12
 )
12 13
 
13
-func LinkSetUp(link *Link) error {
14
+func LinkSetUp(link Link) error {
14 15
 	return ErrNotImplemented
15 16
 }
16 17
 
17
-func LinkSetDown(link *Link) error {
18
+func LinkSetDown(link Link) error {
18 19
 	return ErrNotImplemented
19 20
 }
20 21
 
21
-func LinkSetMTU(link *Link, mtu int) error {
22
+func LinkSetMTU(link Link, mtu int) error {
22 23
 	return ErrNotImplemented
23 24
 }
24 25
 
25
-func LinkSetMaster(link *Link, master *Link) error {
26
+func LinkSetMaster(link Link, master *Link) error {
26 27
 	return ErrNotImplemented
27 28
 }
28 29
 
29
-func LinkSetNsPid(link *Link, nspid int) error {
30
+func LinkSetNsPid(link Link, nspid int) error {
30 31
 	return ErrNotImplemented
31 32
 }
32 33
 
33
-func LinkSetNsFd(link *Link, fd int) error {
34
+func LinkSetNsFd(link Link, fd int) error {
34 35
 	return ErrNotImplemented
35 36
 }
36 37
 
37
-func LinkAdd(link *Link) error {
38
+func LinkSetName(link Link, name string) error {
38 39
 	return ErrNotImplemented
39 40
 }
40 41
 
41
-func LinkDel(link *Link) error {
42
+func LinkSetAlias(link Link, name string) error {
43
+	return ErrNotImplemented
44
+}
45
+
46
+func LinkSetHardwareAddr(link Link, hwaddr net.HardwareAddr) error {
47
+	return ErrNotImplemented
48
+}
49
+
50
+func LinkSetVfHardwareAddr(link Link, vf int, hwaddr net.HardwareAddr) error {
51
+	return ErrNotImplemented
52
+}
53
+
54
+func LinkSetVfVlan(link Link, vf, vlan int) error {
55
+	return ErrNotImplemented
56
+}
57
+
58
+func LinkSetVfTxRate(link Link, vf, rate int) error {
59
+	return ErrNotImplemented
60
+}
61
+
62
+func LinkSetNoMaster(link Link) error {
63
+	return ErrNotImplemented
64
+}
65
+
66
+func LinkSetMasterByIndex(link Link, masterIndex int) error {
67
+	return ErrNotImplemented
68
+}
69
+
70
+func LinkSetXdpFd(link Link, fd int) error {
71
+	return ErrNotImplemented
72
+}
73
+
74
+func LinkByName(name string) (Link, error) {
75
+	return nil, ErrNotImplemented
76
+}
77
+
78
+func LinkByAlias(alias string) (Link, error) {
79
+	return nil, ErrNotImplemented
80
+}
81
+
82
+func LinkByIndex(index int) (Link, error) {
83
+	return nil, ErrNotImplemented
84
+}
85
+
86
+func LinkSetHairpin(link Link, mode bool) error {
87
+	return ErrNotImplemented
88
+}
89
+
90
+func LinkSetGuard(link Link, mode bool) error {
91
+	return ErrNotImplemented
92
+}
93
+
94
+func LinkSetFastLeave(link Link, mode bool) error {
95
+	return ErrNotImplemented
96
+}
97
+
98
+func LinkSetLearning(link Link, mode bool) error {
99
+	return ErrNotImplemented
100
+}
101
+
102
+func LinkSetRootBlock(link Link, mode bool) error {
103
+	return ErrNotImplemented
104
+}
105
+
106
+func LinkSetFlood(link Link, mode bool) error {
107
+	return ErrNotImplemented
108
+}
109
+
110
+func LinkAdd(link Link) error {
111
+	return ErrNotImplemented
112
+}
113
+
114
+func LinkDel(link Link) error {
42 115
 	return ErrNotImplemented
43 116
 }
44 117
 
... ...
@@ -70,11 +143,11 @@ func LinkList() ([]Link, error) {
70 70
 	return nil, ErrNotImplemented
71 71
 }
72 72
 
73
-func AddrAdd(link *Link, addr *Addr) error {
73
+func AddrAdd(link Link, addr *Addr) error {
74 74
 	return ErrNotImplemented
75 75
 }
76 76
 
77
-func AddrDel(link *Link, addr *Addr) error {
77
+func AddrDel(link Link, addr *Addr) error {
78 78
 	return ErrNotImplemented
79 79
 }
80 80
 
... ...
@@ -90,7 +163,7 @@ func RouteDel(route *Route) error {
90 90
 	return ErrNotImplemented
91 91
 }
92 92
 
93
-func RouteList(link *Link, family int) ([]Route, error) {
93
+func RouteList(link Link, family int) ([]Route, error) {
94 94
 	return nil, ErrNotImplemented
95 95
 }
96 96
 
... ...
@@ -418,3 +418,37 @@ const (
418 418
 	IFLA_XDP_ATTACHED /* read-only bool indicating if prog is attached */
419 419
 	IFLA_XDP_MAX      = IFLA_XDP_ATTACHED
420 420
 )
421
+
422
+const (
423
+	IFLA_IPTUN_UNSPEC = iota
424
+	IFLA_IPTUN_LINK
425
+	IFLA_IPTUN_LOCAL
426
+	IFLA_IPTUN_REMOTE
427
+	IFLA_IPTUN_TTL
428
+	IFLA_IPTUN_TOS
429
+	IFLA_IPTUN_ENCAP_LIMIT
430
+	IFLA_IPTUN_FLOWINFO
431
+	IFLA_IPTUN_FLAGS
432
+	IFLA_IPTUN_PROTO
433
+	IFLA_IPTUN_PMTUDISC
434
+	IFLA_IPTUN_6RD_PREFIX
435
+	IFLA_IPTUN_6RD_RELAY_PREFIX
436
+	IFLA_IPTUN_6RD_PREFIXLEN
437
+	IFLA_IPTUN_6RD_RELAY_PREFIXLEN
438
+	IFLA_IPTUN_MAX = IFLA_IPTUN_6RD_RELAY_PREFIXLEN
439
+)
440
+
441
+const (
442
+	IFLA_VTI_UNSPEC = iota
443
+	IFLA_VTI_LINK
444
+	IFLA_VTI_IKEY
445
+	IFLA_VTI_OKEY
446
+	IFLA_VTI_LOCAL
447
+	IFLA_VTI_REMOTE
448
+	IFLA_VTI_MAX = IFLA_VTI_REMOTE
449
+)
450
+
451
+const (
452
+	IFLA_VRF_UNSPEC = iota
453
+	IFLA_VRF_TABLE
454
+)
... ...
@@ -656,6 +656,13 @@ func Uint32Attr(v uint32) []byte {
656 656
 	return bytes
657 657
 }
658 658
 
659
+func Uint64Attr(v uint64) []byte {
660
+	native := NativeEndian()
661
+	bytes := make([]byte, 8)
662
+	native.PutUint64(bytes, v)
663
+	return bytes
664
+}
665
+
659 666
 func ParseRouteAttr(b []byte) ([]syscall.NetlinkRouteAttr, error) {
660 667
 	var attrs []syscall.NetlinkRouteAttr
661 668
 	for len(b) >= syscall.SizeofRtAttr {
... ...
@@ -46,8 +46,5 @@ func boolToByte(x bool) []byte {
46 46
 }
47 47
 
48 48
 func byteToBool(x byte) bool {
49
-	if uint8(x) != 0 {
50
-		return true
51
-	}
52
-	return false
49
+	return uint8(x) != 0
53 50
 }
... ...
@@ -40,25 +40,31 @@ func (h *Handle) LinkGetProtinfo(link Link) (Protinfo, error) {
40 40
 			if err != nil {
41 41
 				return pi, err
42 42
 			}
43
-			var pi Protinfo
44
-			for _, info := range infos {
45
-				switch info.Attr.Type {
46
-				case nl.IFLA_BRPORT_MODE:
47
-					pi.Hairpin = byteToBool(info.Value[0])
48
-				case nl.IFLA_BRPORT_GUARD:
49
-					pi.Guard = byteToBool(info.Value[0])
50
-				case nl.IFLA_BRPORT_FAST_LEAVE:
51
-					pi.FastLeave = byteToBool(info.Value[0])
52
-				case nl.IFLA_BRPORT_PROTECT:
53
-					pi.RootBlock = byteToBool(info.Value[0])
54
-				case nl.IFLA_BRPORT_LEARNING:
55
-					pi.Learning = byteToBool(info.Value[0])
56
-				case nl.IFLA_BRPORT_UNICAST_FLOOD:
57
-					pi.Flood = byteToBool(info.Value[0])
58
-				}
59
-			}
43
+			pi = *parseProtinfo(infos)
44
+
60 45
 			return pi, nil
61 46
 		}
62 47
 	}
63 48
 	return pi, fmt.Errorf("Device with index %d not found", base.Index)
64 49
 }
50
+
51
+func parseProtinfo(infos []syscall.NetlinkRouteAttr) *Protinfo {
52
+	var pi Protinfo
53
+	for _, info := range infos {
54
+		switch info.Attr.Type {
55
+		case nl.IFLA_BRPORT_MODE:
56
+			pi.Hairpin = byteToBool(info.Value[0])
57
+		case nl.IFLA_BRPORT_GUARD:
58
+			pi.Guard = byteToBool(info.Value[0])
59
+		case nl.IFLA_BRPORT_FAST_LEAVE:
60
+			pi.FastLeave = byteToBool(info.Value[0])
61
+		case nl.IFLA_BRPORT_PROTECT:
62
+			pi.RootBlock = byteToBool(info.Value[0])
63
+		case nl.IFLA_BRPORT_LEARNING:
64
+			pi.Learning = byteToBool(info.Value[0])
65
+		case nl.IFLA_BRPORT_UNICAST_FLOOD:
66
+			pi.Flood = byteToBool(info.Value[0])
67
+		}
68
+	}
69
+	return &pi
70
+}
... ...
@@ -168,11 +168,13 @@ func qdiscPayload(req *nl.NetlinkRequest, qdisc Qdisc) error {
168 168
 		options = nl.NewRtAttr(nl.TCA_OPTIONS, tcmap.Serialize())
169 169
 	} else if tbf, ok := qdisc.(*Tbf); ok {
170 170
 		opt := nl.TcTbfQopt{}
171
-		// TODO: handle rate > uint32
172 171
 		opt.Rate.Rate = uint32(tbf.Rate)
173 172
 		opt.Limit = tbf.Limit
174 173
 		opt.Buffer = tbf.Buffer
175 174
 		nl.NewRtAttrChild(options, nl.TCA_TBF_PARMS, opt.Serialize())
175
+		if tbf.Rate >= uint64(1<<32) {
176
+			nl.NewRtAttrChild(options, nl.TCA_TBF_RATE64, nl.Uint64Attr(tbf.Rate))
177
+		}
176 178
 	} else if htb, ok := qdisc.(*Htb); ok {
177 179
 		opt := nl.TcHtbGlob{}
178 180
 		opt.Version = htb.Version
... ...
@@ -421,7 +423,7 @@ func parseTbfData(qdisc Qdisc, data []syscall.NetlinkRouteAttr) error {
421 421
 			tbf.Limit = opt.Limit
422 422
 			tbf.Buffer = opt.Buffer
423 423
 		case nl.TCA_TBF_RATE64:
424
-			tbf.Rate = native.Uint64(datum.Value[0:4])
424
+			tbf.Rate = native.Uint64(datum.Value[0:8])
425 425
 		}
426 426
 	}
427 427
 	return nil
... ...
@@ -283,14 +283,20 @@ func (h *Handle) RouteListFiltered(family int, filter *Route, filterMask uint64)
283 283
 				continue
284 284
 			case filterMask&RT_FILTER_SRC != 0 && !route.Src.Equal(filter.Src):
285 285
 				continue
286
-			case filterMask&RT_FILTER_DST != 0 && filter.Dst != nil:
287
-				if route.Dst == nil {
288
-					continue
289
-				}
290
-				aMaskLen, aMaskBits := route.Dst.Mask.Size()
291
-				bMaskLen, bMaskBits := filter.Dst.Mask.Size()
292
-				if !(route.Dst.IP.Equal(filter.Dst.IP) && aMaskLen == bMaskLen && aMaskBits == bMaskBits) {
293
-					continue
286
+			case filterMask&RT_FILTER_DST != 0:
287
+				if filter.Dst == nil {
288
+					if route.Dst != nil {
289
+						continue
290
+					}
291
+				} else {
292
+					if route.Dst == nil {
293
+						continue
294
+					}
295
+					aMaskLen, aMaskBits := route.Dst.Mask.Size()
296
+					bMaskLen, bMaskBits := filter.Dst.Mask.Size()
297
+					if !(route.Dst.IP.Equal(filter.Dst.IP) && aMaskLen == bMaskLen && aMaskBits == bMaskBits) {
298
+						continue
299
+					}
294 300
 				}
295 301
 			}
296 302
 		}