1package netlink
2
3import (
4	"bytes"
5	"encoding/binary"
6	"fmt"
7	"io/ioutil"
8	"net"
9	"os"
10	"strconv"
11	"strings"
12	"syscall"
13	"unsafe"
14
15	"github.com/vishvananda/netlink/nl"
16	"github.com/vishvananda/netns"
17	"golang.org/x/sys/unix"
18)
19
20const (
21	SizeofLinkStats32 = 0x5c
22	SizeofLinkStats64 = 0xb8
23)
24
25const (
26	TUNTAP_MODE_TUN             TuntapMode = unix.IFF_TUN
27	TUNTAP_MODE_TAP             TuntapMode = unix.IFF_TAP
28	TUNTAP_DEFAULTS             TuntapFlag = unix.IFF_TUN_EXCL | unix.IFF_ONE_QUEUE
29	TUNTAP_VNET_HDR             TuntapFlag = unix.IFF_VNET_HDR
30	TUNTAP_TUN_EXCL             TuntapFlag = unix.IFF_TUN_EXCL
31	TUNTAP_NO_PI                TuntapFlag = unix.IFF_NO_PI
32	TUNTAP_ONE_QUEUE            TuntapFlag = unix.IFF_ONE_QUEUE
33	TUNTAP_MULTI_QUEUE          TuntapFlag = unix.IFF_MULTI_QUEUE
34	TUNTAP_MULTI_QUEUE_DEFAULTS TuntapFlag = TUNTAP_MULTI_QUEUE | TUNTAP_NO_PI
35)
36
37const (
38	VF_LINK_STATE_AUTO    uint32 = 0
39	VF_LINK_STATE_ENABLE  uint32 = 1
40	VF_LINK_STATE_DISABLE uint32 = 2
41)
42
43var lookupByDump = false
44
45var macvlanModes = [...]uint32{
46	0,
47	nl.MACVLAN_MODE_PRIVATE,
48	nl.MACVLAN_MODE_VEPA,
49	nl.MACVLAN_MODE_BRIDGE,
50	nl.MACVLAN_MODE_PASSTHRU,
51	nl.MACVLAN_MODE_SOURCE,
52}
53
54func ensureIndex(link *LinkAttrs) {
55	if link != nil && link.Index == 0 {
56		newlink, _ := LinkByName(link.Name)
57		if newlink != nil {
58			link.Index = newlink.Attrs().Index
59		}
60	}
61}
62
63func (h *Handle) ensureIndex(link *LinkAttrs) {
64	if link != nil && link.Index == 0 {
65		newlink, _ := h.LinkByName(link.Name)
66		if newlink != nil {
67			link.Index = newlink.Attrs().Index
68		}
69	}
70}
71
72func (h *Handle) LinkSetARPOff(link Link) error {
73	base := link.Attrs()
74	h.ensureIndex(base)
75	req := h.newNetlinkRequest(unix.RTM_SETLINK, unix.NLM_F_ACK)
76
77	msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
78	msg.Change |= unix.IFF_NOARP
79	msg.Flags |= unix.IFF_NOARP
80	msg.Index = int32(base.Index)
81	req.AddData(msg)
82
83	_, err := req.Execute(unix.NETLINK_ROUTE, 0)
84	return err
85}
86
87func LinkSetARPOff(link Link) error {
88	return pkgHandle.LinkSetARPOff(link)
89}
90
91func (h *Handle) LinkSetARPOn(link Link) error {
92	base := link.Attrs()
93	h.ensureIndex(base)
94	req := h.newNetlinkRequest(unix.RTM_SETLINK, unix.NLM_F_ACK)
95
96	msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
97	msg.Change |= unix.IFF_NOARP
98	msg.Flags &= ^uint32(unix.IFF_NOARP)
99	msg.Index = int32(base.Index)
100	req.AddData(msg)
101
102	_, err := req.Execute(unix.NETLINK_ROUTE, 0)
103	return err
104}
105
106func LinkSetARPOn(link Link) error {
107	return pkgHandle.LinkSetARPOn(link)
108}
109
110func (h *Handle) SetPromiscOn(link Link) error {
111	base := link.Attrs()
112	h.ensureIndex(base)
113	req := h.newNetlinkRequest(unix.RTM_SETLINK, unix.NLM_F_ACK)
114
115	msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
116	msg.Change = unix.IFF_PROMISC
117	msg.Flags = unix.IFF_PROMISC
118	msg.Index = int32(base.Index)
119	req.AddData(msg)
120
121	_, err := req.Execute(unix.NETLINK_ROUTE, 0)
122	return err
123}
124
125// LinkSetAllmulticastOn enables the reception of all hardware multicast packets for the link device.
126// Equivalent to: `ip link set $link allmulticast on`
127func LinkSetAllmulticastOn(link Link) error {
128	return pkgHandle.LinkSetAllmulticastOn(link)
129}
130
131// LinkSetAllmulticastOn enables the reception of all hardware multicast packets for the link device.
132// Equivalent to: `ip link set $link allmulticast on`
133func (h *Handle) LinkSetAllmulticastOn(link Link) error {
134	base := link.Attrs()
135	h.ensureIndex(base)
136	req := h.newNetlinkRequest(unix.RTM_NEWLINK, unix.NLM_F_ACK)
137
138	msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
139	msg.Change = unix.IFF_ALLMULTI
140	msg.Flags = unix.IFF_ALLMULTI
141
142	msg.Index = int32(base.Index)
143	req.AddData(msg)
144
145	_, err := req.Execute(unix.NETLINK_ROUTE, 0)
146	return err
147}
148
149// LinkSetAllmulticastOff disables the reception of all hardware multicast packets for the link device.
150// Equivalent to: `ip link set $link allmulticast off`
151func LinkSetAllmulticastOff(link Link) error {
152	return pkgHandle.LinkSetAllmulticastOff(link)
153}
154
155// LinkSetAllmulticastOff disables the reception of all hardware multicast packets for the link device.
156// Equivalent to: `ip link set $link allmulticast off`
157func (h *Handle) LinkSetAllmulticastOff(link Link) error {
158	base := link.Attrs()
159	h.ensureIndex(base)
160	req := h.newNetlinkRequest(unix.RTM_NEWLINK, unix.NLM_F_ACK)
161
162	msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
163	msg.Change = unix.IFF_ALLMULTI
164	msg.Index = int32(base.Index)
165	req.AddData(msg)
166
167	_, err := req.Execute(unix.NETLINK_ROUTE, 0)
168	return err
169}
170
171func MacvlanMACAddrAdd(link Link, addr net.HardwareAddr) error {
172	return pkgHandle.MacvlanMACAddrAdd(link, addr)
173}
174
175func (h *Handle) MacvlanMACAddrAdd(link Link, addr net.HardwareAddr) error {
176	return h.macvlanMACAddrChange(link, []net.HardwareAddr{addr}, nl.MACVLAN_MACADDR_ADD)
177}
178
179func MacvlanMACAddrDel(link Link, addr net.HardwareAddr) error {
180	return pkgHandle.MacvlanMACAddrDel(link, addr)
181}
182
183func (h *Handle) MacvlanMACAddrDel(link Link, addr net.HardwareAddr) error {
184	return h.macvlanMACAddrChange(link, []net.HardwareAddr{addr}, nl.MACVLAN_MACADDR_DEL)
185}
186
187func MacvlanMACAddrFlush(link Link) error {
188	return pkgHandle.MacvlanMACAddrFlush(link)
189}
190
191func (h *Handle) MacvlanMACAddrFlush(link Link) error {
192	return h.macvlanMACAddrChange(link, nil, nl.MACVLAN_MACADDR_FLUSH)
193}
194
195func MacvlanMACAddrSet(link Link, addrs []net.HardwareAddr) error {
196	return pkgHandle.MacvlanMACAddrSet(link, addrs)
197}
198
199func (h *Handle) MacvlanMACAddrSet(link Link, addrs []net.HardwareAddr) error {
200	return h.macvlanMACAddrChange(link, addrs, nl.MACVLAN_MACADDR_SET)
201}
202
203func (h *Handle) macvlanMACAddrChange(link Link, addrs []net.HardwareAddr, mode uint32) error {
204	base := link.Attrs()
205	h.ensureIndex(base)
206	req := h.newNetlinkRequest(unix.RTM_NEWLINK, unix.NLM_F_ACK)
207
208	msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
209	msg.Index = int32(base.Index)
210	req.AddData(msg)
211
212	linkInfo := nl.NewRtAttr(unix.IFLA_LINKINFO, nil)
213	linkInfo.AddRtAttr(nl.IFLA_INFO_KIND, nl.NonZeroTerminated(link.Type()))
214	inner := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil)
215
216	// IFLA_MACVLAN_MACADDR_MODE = mode
217	b := make([]byte, 4)
218	native.PutUint32(b, mode)
219	inner.AddRtAttr(nl.IFLA_MACVLAN_MACADDR_MODE, b)
220
221	// populate message with MAC addrs, if necessary
222	switch mode {
223	case nl.MACVLAN_MACADDR_ADD, nl.MACVLAN_MACADDR_DEL:
224		if len(addrs) == 1 {
225			inner.AddRtAttr(nl.IFLA_MACVLAN_MACADDR, []byte(addrs[0]))
226		}
227	case nl.MACVLAN_MACADDR_SET:
228		mad := inner.AddRtAttr(nl.IFLA_MACVLAN_MACADDR_DATA, nil)
229		for _, addr := range addrs {
230			mad.AddRtAttr(nl.IFLA_MACVLAN_MACADDR, []byte(addr))
231		}
232	}
233
234	req.AddData(linkInfo)
235
236	_, err := req.Execute(unix.NETLINK_ROUTE, 0)
237	return err
238}
239
240func BridgeSetMcastSnoop(link Link, on bool) error {
241	return pkgHandle.BridgeSetMcastSnoop(link, on)
242}
243
244func (h *Handle) BridgeSetMcastSnoop(link Link, on bool) error {
245	bridge := link.(*Bridge)
246	bridge.MulticastSnooping = &on
247	return h.linkModify(bridge, unix.NLM_F_ACK)
248}
249
250func SetPromiscOn(link Link) error {
251	return pkgHandle.SetPromiscOn(link)
252}
253
254func (h *Handle) SetPromiscOff(link Link) error {
255	base := link.Attrs()
256	h.ensureIndex(base)
257	req := h.newNetlinkRequest(unix.RTM_SETLINK, unix.NLM_F_ACK)
258
259	msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
260	msg.Change = unix.IFF_PROMISC
261	msg.Index = int32(base.Index)
262	req.AddData(msg)
263
264	_, err := req.Execute(unix.NETLINK_ROUTE, 0)
265	return err
266}
267
268func SetPromiscOff(link Link) error {
269	return pkgHandle.SetPromiscOff(link)
270}
271
272// LinkSetUp enables the link device.
273// Equivalent to: `ip link set $link up`
274func LinkSetUp(link Link) error {
275	return pkgHandle.LinkSetUp(link)
276}
277
278// LinkSetUp enables the link device.
279// Equivalent to: `ip link set $link up`
280func (h *Handle) LinkSetUp(link Link) error {
281	base := link.Attrs()
282	h.ensureIndex(base)
283	req := h.newNetlinkRequest(unix.RTM_NEWLINK, unix.NLM_F_ACK)
284
285	msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
286	msg.Change = unix.IFF_UP
287	msg.Flags = unix.IFF_UP
288	msg.Index = int32(base.Index)
289	req.AddData(msg)
290
291	_, err := req.Execute(unix.NETLINK_ROUTE, 0)
292	return err
293}
294
295// LinkSetDown disables link device.
296// Equivalent to: `ip link set $link down`
297func LinkSetDown(link Link) error {
298	return pkgHandle.LinkSetDown(link)
299}
300
301// LinkSetDown disables link device.
302// Equivalent to: `ip link set $link down`
303func (h *Handle) LinkSetDown(link Link) error {
304	base := link.Attrs()
305	h.ensureIndex(base)
306	req := h.newNetlinkRequest(unix.RTM_NEWLINK, unix.NLM_F_ACK)
307
308	msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
309	msg.Change = unix.IFF_UP
310	msg.Index = int32(base.Index)
311	req.AddData(msg)
312
313	_, err := req.Execute(unix.NETLINK_ROUTE, 0)
314	return err
315}
316
317// LinkSetMTU sets the mtu of the link device.
318// Equivalent to: `ip link set $link mtu $mtu`
319func LinkSetMTU(link Link, mtu int) error {
320	return pkgHandle.LinkSetMTU(link, mtu)
321}
322
323// LinkSetMTU sets the mtu of the link device.
324// Equivalent to: `ip link set $link mtu $mtu`
325func (h *Handle) LinkSetMTU(link Link, mtu int) error {
326	base := link.Attrs()
327	h.ensureIndex(base)
328	req := h.newNetlinkRequest(unix.RTM_SETLINK, unix.NLM_F_ACK)
329
330	msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
331	msg.Index = int32(base.Index)
332	req.AddData(msg)
333
334	b := make([]byte, 4)
335	native.PutUint32(b, uint32(mtu))
336
337	data := nl.NewRtAttr(unix.IFLA_MTU, b)
338	req.AddData(data)
339
340	_, err := req.Execute(unix.NETLINK_ROUTE, 0)
341	return err
342}
343
344// LinkSetName sets the name of the link device.
345// Equivalent to: `ip link set $link name $name`
346func LinkSetName(link Link, name string) error {
347	return pkgHandle.LinkSetName(link, name)
348}
349
350// LinkSetName sets the name of the link device.
351// Equivalent to: `ip link set $link name $name`
352func (h *Handle) LinkSetName(link Link, name string) error {
353	base := link.Attrs()
354	h.ensureIndex(base)
355	req := h.newNetlinkRequest(unix.RTM_SETLINK, unix.NLM_F_ACK)
356
357	msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
358	msg.Index = int32(base.Index)
359	req.AddData(msg)
360
361	data := nl.NewRtAttr(unix.IFLA_IFNAME, []byte(name))
362	req.AddData(data)
363
364	_, err := req.Execute(unix.NETLINK_ROUTE, 0)
365	return err
366}
367
368// LinkSetAlias sets the alias of the link device.
369// Equivalent to: `ip link set dev $link alias $name`
370func LinkSetAlias(link Link, name string) error {
371	return pkgHandle.LinkSetAlias(link, name)
372}
373
374// LinkSetAlias sets the alias of the link device.
375// Equivalent to: `ip link set dev $link alias $name`
376func (h *Handle) LinkSetAlias(link Link, name string) error {
377	base := link.Attrs()
378	h.ensureIndex(base)
379	req := h.newNetlinkRequest(unix.RTM_SETLINK, unix.NLM_F_ACK)
380
381	msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
382	msg.Index = int32(base.Index)
383	req.AddData(msg)
384
385	data := nl.NewRtAttr(unix.IFLA_IFALIAS, []byte(name))
386	req.AddData(data)
387
388	_, err := req.Execute(unix.NETLINK_ROUTE, 0)
389	return err
390}
391
392// LinkSetHardwareAddr sets the hardware address of the link device.
393// Equivalent to: `ip link set $link address $hwaddr`
394func LinkSetHardwareAddr(link Link, hwaddr net.HardwareAddr) error {
395	return pkgHandle.LinkSetHardwareAddr(link, hwaddr)
396}
397
398// LinkSetHardwareAddr sets the hardware address of the link device.
399// Equivalent to: `ip link set $link address $hwaddr`
400func (h *Handle) LinkSetHardwareAddr(link Link, hwaddr net.HardwareAddr) error {
401	base := link.Attrs()
402	h.ensureIndex(base)
403	req := h.newNetlinkRequest(unix.RTM_SETLINK, unix.NLM_F_ACK)
404
405	msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
406	msg.Index = int32(base.Index)
407	req.AddData(msg)
408
409	data := nl.NewRtAttr(unix.IFLA_ADDRESS, []byte(hwaddr))
410	req.AddData(data)
411
412	_, err := req.Execute(unix.NETLINK_ROUTE, 0)
413	return err
414}
415
416// LinkSetVfHardwareAddr sets the hardware address of a vf for the link.
417// Equivalent to: `ip link set $link vf $vf mac $hwaddr`
418func LinkSetVfHardwareAddr(link Link, vf int, hwaddr net.HardwareAddr) error {
419	return pkgHandle.LinkSetVfHardwareAddr(link, vf, hwaddr)
420}
421
422// LinkSetVfHardwareAddr sets the hardware address of a vf for the link.
423// Equivalent to: `ip link set $link vf $vf mac $hwaddr`
424func (h *Handle) LinkSetVfHardwareAddr(link Link, vf int, hwaddr net.HardwareAddr) error {
425	base := link.Attrs()
426	h.ensureIndex(base)
427	req := h.newNetlinkRequest(unix.RTM_SETLINK, unix.NLM_F_ACK)
428
429	msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
430	msg.Index = int32(base.Index)
431	req.AddData(msg)
432
433	data := nl.NewRtAttr(unix.IFLA_VFINFO_LIST, nil)
434	info := data.AddRtAttr(nl.IFLA_VF_INFO, nil)
435	vfmsg := nl.VfMac{
436		Vf: uint32(vf),
437	}
438	copy(vfmsg.Mac[:], []byte(hwaddr))
439	info.AddRtAttr(nl.IFLA_VF_MAC, vfmsg.Serialize())
440	req.AddData(data)
441
442	_, err := req.Execute(unix.NETLINK_ROUTE, 0)
443	return err
444}
445
446// LinkSetVfVlan sets the vlan of a vf for the link.
447// Equivalent to: `ip link set $link vf $vf vlan $vlan`
448func LinkSetVfVlan(link Link, vf, vlan int) error {
449	return pkgHandle.LinkSetVfVlan(link, vf, vlan)
450}
451
452// LinkSetVfVlan sets the vlan of a vf for the link.
453// Equivalent to: `ip link set $link vf $vf vlan $vlan`
454func (h *Handle) LinkSetVfVlan(link Link, vf, vlan int) error {
455	base := link.Attrs()
456	h.ensureIndex(base)
457	req := h.newNetlinkRequest(unix.RTM_SETLINK, unix.NLM_F_ACK)
458
459	msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
460	msg.Index = int32(base.Index)
461	req.AddData(msg)
462
463	data := nl.NewRtAttr(unix.IFLA_VFINFO_LIST, nil)
464	info := data.AddRtAttr(nl.IFLA_VF_INFO, nil)
465	vfmsg := nl.VfVlan{
466		Vf:   uint32(vf),
467		Vlan: uint32(vlan),
468	}
469	info.AddRtAttr(nl.IFLA_VF_VLAN, vfmsg.Serialize())
470	req.AddData(data)
471
472	_, err := req.Execute(unix.NETLINK_ROUTE, 0)
473	return err
474}
475
476// LinkSetVfVlanQos sets the vlan and qos priority of a vf for the link.
477// Equivalent to: `ip link set $link vf $vf vlan $vlan qos $qos`
478func LinkSetVfVlanQos(link Link, vf, vlan, qos int) error {
479	return pkgHandle.LinkSetVfVlanQos(link, vf, vlan, qos)
480}
481
482// LinkSetVfVlanQos sets the vlan and qos priority of a vf for the link.
483// Equivalent to: `ip link set $link vf $vf vlan $vlan qos $qos`
484func (h *Handle) LinkSetVfVlanQos(link Link, vf, vlan, qos int) error {
485	base := link.Attrs()
486	h.ensureIndex(base)
487	req := h.newNetlinkRequest(unix.RTM_SETLINK, unix.NLM_F_ACK)
488
489	msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
490	msg.Index = int32(base.Index)
491	req.AddData(msg)
492
493	data := nl.NewRtAttr(unix.IFLA_VFINFO_LIST, nil)
494	info := nl.NewRtAttrChild(data, nl.IFLA_VF_INFO, nil)
495	vfmsg := nl.VfVlan{
496		Vf:   uint32(vf),
497		Vlan: uint32(vlan),
498		Qos:  uint32(qos),
499	}
500	nl.NewRtAttrChild(info, nl.IFLA_VF_VLAN, vfmsg.Serialize())
501	req.AddData(data)
502
503	_, err := req.Execute(unix.NETLINK_ROUTE, 0)
504	return err
505}
506
507// LinkSetVfTxRate sets the tx rate of a vf for the link.
508// Equivalent to: `ip link set $link vf $vf rate $rate`
509func LinkSetVfTxRate(link Link, vf, rate int) error {
510	return pkgHandle.LinkSetVfTxRate(link, vf, rate)
511}
512
513// LinkSetVfTxRate sets the tx rate of a vf for the link.
514// Equivalent to: `ip link set $link vf $vf rate $rate`
515func (h *Handle) LinkSetVfTxRate(link Link, vf, rate int) error {
516	base := link.Attrs()
517	h.ensureIndex(base)
518	req := h.newNetlinkRequest(unix.RTM_SETLINK, unix.NLM_F_ACK)
519
520	msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
521	msg.Index = int32(base.Index)
522	req.AddData(msg)
523
524	data := nl.NewRtAttr(unix.IFLA_VFINFO_LIST, nil)
525	info := data.AddRtAttr(nl.IFLA_VF_INFO, nil)
526	vfmsg := nl.VfTxRate{
527		Vf:   uint32(vf),
528		Rate: uint32(rate),
529	}
530	info.AddRtAttr(nl.IFLA_VF_TX_RATE, vfmsg.Serialize())
531	req.AddData(data)
532
533	_, err := req.Execute(unix.NETLINK_ROUTE, 0)
534	return err
535}
536
537// LinkSetVfRate sets the min and max tx rate of a vf for the link.
538// Equivalent to: `ip link set $link vf $vf min_tx_rate $min_rate max_tx_rate $max_rate`
539func LinkSetVfRate(link Link, vf, minRate, maxRate int) error {
540	return pkgHandle.LinkSetVfRate(link, vf, minRate, maxRate)
541}
542
543// LinkSetVfRate sets the min and max tx rate of a vf for the link.
544// Equivalent to: `ip link set $link vf $vf min_tx_rate $min_rate max_tx_rate $max_rate`
545func (h *Handle) LinkSetVfRate(link Link, vf, minRate, maxRate int) error {
546	base := link.Attrs()
547	h.ensureIndex(base)
548	req := h.newNetlinkRequest(unix.RTM_SETLINK, unix.NLM_F_ACK)
549
550	msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
551	msg.Index = int32(base.Index)
552	req.AddData(msg)
553
554	data := nl.NewRtAttr(unix.IFLA_VFINFO_LIST, nil)
555	info := data.AddRtAttr(nl.IFLA_VF_INFO, nil)
556	vfmsg := nl.VfRate{
557		Vf:        uint32(vf),
558		MinTxRate: uint32(minRate),
559		MaxTxRate: uint32(maxRate),
560	}
561	info.AddRtAttr(nl.IFLA_VF_RATE, vfmsg.Serialize())
562	req.AddData(data)
563
564	_, err := req.Execute(unix.NETLINK_ROUTE, 0)
565	return err
566}
567
568// LinkSetVfState enables/disables virtual link state on a vf.
569// Equivalent to: `ip link set $link vf $vf state $state`
570func LinkSetVfState(link Link, vf int, state uint32) error {
571	return pkgHandle.LinkSetVfState(link, vf, state)
572}
573
574// LinkSetVfState enables/disables virtual link state on a vf.
575// Equivalent to: `ip link set $link vf $vf state $state`
576func (h *Handle) LinkSetVfState(link Link, vf int, state uint32) error {
577	base := link.Attrs()
578	h.ensureIndex(base)
579	req := h.newNetlinkRequest(unix.RTM_SETLINK, unix.NLM_F_ACK)
580
581	msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
582	msg.Index = int32(base.Index)
583	req.AddData(msg)
584
585	data := nl.NewRtAttr(unix.IFLA_VFINFO_LIST, nil)
586	info := data.AddRtAttr(nl.IFLA_VF_INFO, nil)
587	vfmsg := nl.VfLinkState{
588		Vf:        uint32(vf),
589		LinkState: state,
590	}
591	info.AddRtAttr(nl.IFLA_VF_LINK_STATE, vfmsg.Serialize())
592	req.AddData(data)
593
594	_, err := req.Execute(unix.NETLINK_ROUTE, 0)
595	return err
596}
597
598// LinkSetVfSpoofchk enables/disables spoof check on a vf for the link.
599// Equivalent to: `ip link set $link vf $vf spoofchk $check`
600func LinkSetVfSpoofchk(link Link, vf int, check bool) error {
601	return pkgHandle.LinkSetVfSpoofchk(link, vf, check)
602}
603
604// LinkSetVfSpoofchk enables/disables spoof check on a vf for the link.
605// Equivalent to: `ip link set $link vf $vf spoofchk $check`
606func (h *Handle) LinkSetVfSpoofchk(link Link, vf int, check bool) error {
607	var setting uint32
608	base := link.Attrs()
609	h.ensureIndex(base)
610	req := h.newNetlinkRequest(unix.RTM_SETLINK, unix.NLM_F_ACK)
611
612	msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
613	msg.Index = int32(base.Index)
614	req.AddData(msg)
615
616	data := nl.NewRtAttr(unix.IFLA_VFINFO_LIST, nil)
617	info := data.AddRtAttr(nl.IFLA_VF_INFO, nil)
618	if check {
619		setting = 1
620	}
621	vfmsg := nl.VfSpoofchk{
622		Vf:      uint32(vf),
623		Setting: setting,
624	}
625	info.AddRtAttr(nl.IFLA_VF_SPOOFCHK, vfmsg.Serialize())
626	req.AddData(data)
627
628	_, err := req.Execute(unix.NETLINK_ROUTE, 0)
629	return err
630}
631
632// LinkSetVfTrust enables/disables trust state on a vf for the link.
633// Equivalent to: `ip link set $link vf $vf trust $state`
634func LinkSetVfTrust(link Link, vf int, state bool) error {
635	return pkgHandle.LinkSetVfTrust(link, vf, state)
636}
637
638// LinkSetVfTrust enables/disables trust state on a vf for the link.
639// Equivalent to: `ip link set $link vf $vf trust $state`
640func (h *Handle) LinkSetVfTrust(link Link, vf int, state bool) error {
641	var setting uint32
642	base := link.Attrs()
643	h.ensureIndex(base)
644	req := h.newNetlinkRequest(unix.RTM_SETLINK, unix.NLM_F_ACK)
645
646	msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
647	msg.Index = int32(base.Index)
648	req.AddData(msg)
649
650	data := nl.NewRtAttr(unix.IFLA_VFINFO_LIST, nil)
651	info := data.AddRtAttr(nl.IFLA_VF_INFO, nil)
652	if state {
653		setting = 1
654	}
655	vfmsg := nl.VfTrust{
656		Vf:      uint32(vf),
657		Setting: setting,
658	}
659	info.AddRtAttr(nl.IFLA_VF_TRUST, vfmsg.Serialize())
660	req.AddData(data)
661
662	_, err := req.Execute(unix.NETLINK_ROUTE, 0)
663	return err
664}
665
666// LinkSetVfNodeGUID sets the node GUID of a vf for the link.
667// Equivalent to: `ip link set dev $link vf $vf node_guid $nodeguid`
668func LinkSetVfNodeGUID(link Link, vf int, nodeguid net.HardwareAddr) error {
669	return pkgHandle.LinkSetVfGUID(link, vf, nodeguid, nl.IFLA_VF_IB_NODE_GUID)
670}
671
672// LinkSetVfPortGUID sets the port GUID of a vf for the link.
673// Equivalent to: `ip link set dev $link vf $vf port_guid $portguid`
674func LinkSetVfPortGUID(link Link, vf int, portguid net.HardwareAddr) error {
675	return pkgHandle.LinkSetVfGUID(link, vf, portguid, nl.IFLA_VF_IB_PORT_GUID)
676}
677
678// LinkSetVfGUID sets the node or port GUID of a vf for the link.
679func (h *Handle) LinkSetVfGUID(link Link, vf int, vfGuid net.HardwareAddr, guidType int) error {
680	var err error
681	var guid uint64
682
683	buf := bytes.NewBuffer(vfGuid)
684	err = binary.Read(buf, binary.BigEndian, &guid)
685	if err != nil {
686		return err
687	}
688
689	base := link.Attrs()
690	h.ensureIndex(base)
691	req := h.newNetlinkRequest(unix.RTM_SETLINK, unix.NLM_F_ACK)
692
693	msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
694	msg.Index = int32(base.Index)
695	req.AddData(msg)
696
697	data := nl.NewRtAttr(unix.IFLA_VFINFO_LIST, nil)
698	info := data.AddRtAttr(nl.IFLA_VF_INFO, nil)
699	vfmsg := nl.VfGUID{
700		Vf:   uint32(vf),
701		GUID: guid,
702	}
703	info.AddRtAttr(guidType, vfmsg.Serialize())
704	req.AddData(data)
705
706	_, err = req.Execute(unix.NETLINK_ROUTE, 0)
707	return err
708}
709
710// LinkSetMaster sets the master of the link device.
711// Equivalent to: `ip link set $link master $master`
712func LinkSetMaster(link Link, master Link) error {
713	return pkgHandle.LinkSetMaster(link, master)
714}
715
716// LinkSetMaster sets the master of the link device.
717// Equivalent to: `ip link set $link master $master`
718func (h *Handle) LinkSetMaster(link Link, master Link) error {
719	index := 0
720	if master != nil {
721		masterBase := master.Attrs()
722		h.ensureIndex(masterBase)
723		index = masterBase.Index
724	}
725	if index <= 0 {
726		return fmt.Errorf("Device does not exist")
727	}
728	return h.LinkSetMasterByIndex(link, index)
729}
730
731// LinkSetNoMaster removes the master of the link device.
732// Equivalent to: `ip link set $link nomaster`
733func LinkSetNoMaster(link Link) error {
734	return pkgHandle.LinkSetNoMaster(link)
735}
736
737// LinkSetNoMaster removes the master of the link device.
738// Equivalent to: `ip link set $link nomaster`
739func (h *Handle) LinkSetNoMaster(link Link) error {
740	return h.LinkSetMasterByIndex(link, 0)
741}
742
743// LinkSetMasterByIndex sets the master of the link device.
744// Equivalent to: `ip link set $link master $master`
745func LinkSetMasterByIndex(link Link, masterIndex int) error {
746	return pkgHandle.LinkSetMasterByIndex(link, masterIndex)
747}
748
749// LinkSetMasterByIndex sets the master of the link device.
750// Equivalent to: `ip link set $link master $master`
751func (h *Handle) LinkSetMasterByIndex(link Link, masterIndex int) error {
752	base := link.Attrs()
753	h.ensureIndex(base)
754	req := h.newNetlinkRequest(unix.RTM_SETLINK, unix.NLM_F_ACK)
755
756	msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
757	msg.Index = int32(base.Index)
758	req.AddData(msg)
759
760	b := make([]byte, 4)
761	native.PutUint32(b, uint32(masterIndex))
762
763	data := nl.NewRtAttr(unix.IFLA_MASTER, b)
764	req.AddData(data)
765
766	_, err := req.Execute(unix.NETLINK_ROUTE, 0)
767	return err
768}
769
770// LinkSetNsPid puts the device into a new network namespace. The
771// pid must be a pid of a running process.
772// Equivalent to: `ip link set $link netns $pid`
773func LinkSetNsPid(link Link, nspid int) error {
774	return pkgHandle.LinkSetNsPid(link, nspid)
775}
776
777// LinkSetNsPid puts the device into a new network namespace. The
778// pid must be a pid of a running process.
779// Equivalent to: `ip link set $link netns $pid`
780func (h *Handle) LinkSetNsPid(link Link, nspid int) error {
781	base := link.Attrs()
782	h.ensureIndex(base)
783	req := h.newNetlinkRequest(unix.RTM_SETLINK, unix.NLM_F_ACK)
784
785	msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
786	msg.Index = int32(base.Index)
787	req.AddData(msg)
788
789	b := make([]byte, 4)
790	native.PutUint32(b, uint32(nspid))
791
792	data := nl.NewRtAttr(unix.IFLA_NET_NS_PID, b)
793	req.AddData(data)
794
795	_, err := req.Execute(unix.NETLINK_ROUTE, 0)
796	return err
797}
798
799// LinkSetNsFd puts the device into a new network namespace. The
800// fd must be an open file descriptor to a network namespace.
801// Similar to: `ip link set $link netns $ns`
802func LinkSetNsFd(link Link, fd int) error {
803	return pkgHandle.LinkSetNsFd(link, fd)
804}
805
806// LinkSetNsFd puts the device into a new network namespace. The
807// fd must be an open file descriptor to a network namespace.
808// Similar to: `ip link set $link netns $ns`
809func (h *Handle) LinkSetNsFd(link Link, fd int) error {
810	base := link.Attrs()
811	h.ensureIndex(base)
812	req := h.newNetlinkRequest(unix.RTM_SETLINK, unix.NLM_F_ACK)
813
814	msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
815	msg.Index = int32(base.Index)
816	req.AddData(msg)
817
818	b := make([]byte, 4)
819	native.PutUint32(b, uint32(fd))
820
821	data := nl.NewRtAttr(unix.IFLA_NET_NS_FD, b)
822	req.AddData(data)
823
824	_, err := req.Execute(unix.NETLINK_ROUTE, 0)
825	return err
826}
827
828// LinkSetXdpFd adds a bpf function to the driver. The fd must be a bpf
829// program loaded with bpf(type=BPF_PROG_TYPE_XDP)
830func LinkSetXdpFd(link Link, fd int) error {
831	return LinkSetXdpFdWithFlags(link, fd, 0)
832}
833
834// LinkSetXdpFdWithFlags adds a bpf function to the driver with the given
835// options. The fd must be a bpf program loaded with bpf(type=BPF_PROG_TYPE_XDP)
836func LinkSetXdpFdWithFlags(link Link, fd, flags int) error {
837	base := link.Attrs()
838	ensureIndex(base)
839	req := nl.NewNetlinkRequest(unix.RTM_SETLINK, unix.NLM_F_ACK)
840
841	msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
842	msg.Index = int32(base.Index)
843	req.AddData(msg)
844
845	addXdpAttrs(&LinkXdp{Fd: fd, Flags: uint32(flags)}, req)
846
847	_, err := req.Execute(unix.NETLINK_ROUTE, 0)
848	return err
849}
850
851func boolAttr(val bool) []byte {
852	var v uint8
853	if val {
854		v = 1
855	}
856	return nl.Uint8Attr(v)
857}
858
859type vxlanPortRange struct {
860	Lo, Hi uint16
861}
862
863func addVxlanAttrs(vxlan *Vxlan, linkInfo *nl.RtAttr) {
864	data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil)
865
866	if vxlan.FlowBased {
867		vxlan.VxlanId = 0
868	}
869
870	data.AddRtAttr(nl.IFLA_VXLAN_ID, nl.Uint32Attr(uint32(vxlan.VxlanId)))
871
872	if vxlan.VtepDevIndex != 0 {
873		data.AddRtAttr(nl.IFLA_VXLAN_LINK, nl.Uint32Attr(uint32(vxlan.VtepDevIndex)))
874	}
875	if vxlan.SrcAddr != nil {
876		ip := vxlan.SrcAddr.To4()
877		if ip != nil {
878			data.AddRtAttr(nl.IFLA_VXLAN_LOCAL, []byte(ip))
879		} else {
880			ip = vxlan.SrcAddr.To16()
881			if ip != nil {
882				data.AddRtAttr(nl.IFLA_VXLAN_LOCAL6, []byte(ip))
883			}
884		}
885	}
886	if vxlan.Group != nil {
887		group := vxlan.Group.To4()
888		if group != nil {
889			data.AddRtAttr(nl.IFLA_VXLAN_GROUP, []byte(group))
890		} else {
891			group = vxlan.Group.To16()
892			if group != nil {
893				data.AddRtAttr(nl.IFLA_VXLAN_GROUP6, []byte(group))
894			}
895		}
896	}
897
898	data.AddRtAttr(nl.IFLA_VXLAN_TTL, nl.Uint8Attr(uint8(vxlan.TTL)))
899	data.AddRtAttr(nl.IFLA_VXLAN_TOS, nl.Uint8Attr(uint8(vxlan.TOS)))
900	data.AddRtAttr(nl.IFLA_VXLAN_LEARNING, boolAttr(vxlan.Learning))
901	data.AddRtAttr(nl.IFLA_VXLAN_PROXY, boolAttr(vxlan.Proxy))
902	data.AddRtAttr(nl.IFLA_VXLAN_RSC, boolAttr(vxlan.RSC))
903	data.AddRtAttr(nl.IFLA_VXLAN_L2MISS, boolAttr(vxlan.L2miss))
904	data.AddRtAttr(nl.IFLA_VXLAN_L3MISS, boolAttr(vxlan.L3miss))
905	data.AddRtAttr(nl.IFLA_VXLAN_UDP_ZERO_CSUM6_TX, boolAttr(vxlan.UDP6ZeroCSumTx))
906	data.AddRtAttr(nl.IFLA_VXLAN_UDP_ZERO_CSUM6_RX, boolAttr(vxlan.UDP6ZeroCSumRx))
907
908	if vxlan.UDPCSum {
909		data.AddRtAttr(nl.IFLA_VXLAN_UDP_CSUM, boolAttr(vxlan.UDPCSum))
910	}
911	if vxlan.GBP {
912		data.AddRtAttr(nl.IFLA_VXLAN_GBP, []byte{})
913	}
914	if vxlan.FlowBased {
915		data.AddRtAttr(nl.IFLA_VXLAN_FLOWBASED, boolAttr(vxlan.FlowBased))
916	}
917	if vxlan.NoAge {
918		data.AddRtAttr(nl.IFLA_VXLAN_AGEING, nl.Uint32Attr(0))
919	} else if vxlan.Age > 0 {
920		data.AddRtAttr(nl.IFLA_VXLAN_AGEING, nl.Uint32Attr(uint32(vxlan.Age)))
921	}
922	if vxlan.Limit > 0 {
923		data.AddRtAttr(nl.IFLA_VXLAN_LIMIT, nl.Uint32Attr(uint32(vxlan.Limit)))
924	}
925	if vxlan.Port > 0 {
926		data.AddRtAttr(nl.IFLA_VXLAN_PORT, htons(uint16(vxlan.Port)))
927	}
928	if vxlan.PortLow > 0 || vxlan.PortHigh > 0 {
929		pr := vxlanPortRange{uint16(vxlan.PortLow), uint16(vxlan.PortHigh)}
930
931		buf := new(bytes.Buffer)
932		binary.Write(buf, binary.BigEndian, &pr)
933
934		data.AddRtAttr(nl.IFLA_VXLAN_PORT_RANGE, buf.Bytes())
935	}
936}
937
938func addBondAttrs(bond *Bond, linkInfo *nl.RtAttr) {
939	data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil)
940	if bond.Mode >= 0 {
941		data.AddRtAttr(nl.IFLA_BOND_MODE, nl.Uint8Attr(uint8(bond.Mode)))
942	}
943	if bond.ActiveSlave >= 0 {
944		data.AddRtAttr(nl.IFLA_BOND_ACTIVE_SLAVE, nl.Uint32Attr(uint32(bond.ActiveSlave)))
945	}
946	if bond.Miimon >= 0 {
947		data.AddRtAttr(nl.IFLA_BOND_MIIMON, nl.Uint32Attr(uint32(bond.Miimon)))
948	}
949	if bond.UpDelay >= 0 {
950		data.AddRtAttr(nl.IFLA_BOND_UPDELAY, nl.Uint32Attr(uint32(bond.UpDelay)))
951	}
952	if bond.DownDelay >= 0 {
953		data.AddRtAttr(nl.IFLA_BOND_DOWNDELAY, nl.Uint32Attr(uint32(bond.DownDelay)))
954	}
955	if bond.UseCarrier >= 0 {
956		data.AddRtAttr(nl.IFLA_BOND_USE_CARRIER, nl.Uint8Attr(uint8(bond.UseCarrier)))
957	}
958	if bond.ArpInterval >= 0 {
959		data.AddRtAttr(nl.IFLA_BOND_ARP_INTERVAL, nl.Uint32Attr(uint32(bond.ArpInterval)))
960	}
961	if bond.ArpIpTargets != nil {
962		msg := data.AddRtAttr(nl.IFLA_BOND_ARP_IP_TARGET, nil)
963		for i := range bond.ArpIpTargets {
964			ip := bond.ArpIpTargets[i].To4()
965			if ip != nil {
966				msg.AddRtAttr(i, []byte(ip))
967				continue
968			}
969			ip = bond.ArpIpTargets[i].To16()
970			if ip != nil {
971				msg.AddRtAttr(i, []byte(ip))
972			}
973		}
974	}
975	if bond.ArpValidate >= 0 {
976		data.AddRtAttr(nl.IFLA_BOND_ARP_VALIDATE, nl.Uint32Attr(uint32(bond.ArpValidate)))
977	}
978	if bond.ArpAllTargets >= 0 {
979		data.AddRtAttr(nl.IFLA_BOND_ARP_ALL_TARGETS, nl.Uint32Attr(uint32(bond.ArpAllTargets)))
980	}
981	if bond.Primary >= 0 {
982		data.AddRtAttr(nl.IFLA_BOND_PRIMARY, nl.Uint32Attr(uint32(bond.Primary)))
983	}
984	if bond.PrimaryReselect >= 0 {
985		data.AddRtAttr(nl.IFLA_BOND_PRIMARY_RESELECT, nl.Uint8Attr(uint8(bond.PrimaryReselect)))
986	}
987	if bond.FailOverMac >= 0 {
988		data.AddRtAttr(nl.IFLA_BOND_FAIL_OVER_MAC, nl.Uint8Attr(uint8(bond.FailOverMac)))
989	}
990	if bond.XmitHashPolicy >= 0 {
991		data.AddRtAttr(nl.IFLA_BOND_XMIT_HASH_POLICY, nl.Uint8Attr(uint8(bond.XmitHashPolicy)))
992	}
993	if bond.ResendIgmp >= 0 {
994		data.AddRtAttr(nl.IFLA_BOND_RESEND_IGMP, nl.Uint32Attr(uint32(bond.ResendIgmp)))
995	}
996	if bond.NumPeerNotif >= 0 {
997		data.AddRtAttr(nl.IFLA_BOND_NUM_PEER_NOTIF, nl.Uint8Attr(uint8(bond.NumPeerNotif)))
998	}
999	if bond.AllSlavesActive >= 0 {
1000		data.AddRtAttr(nl.IFLA_BOND_ALL_SLAVES_ACTIVE, nl.Uint8Attr(uint8(bond.AllSlavesActive)))
1001	}
1002	if bond.MinLinks >= 0 {
1003		data.AddRtAttr(nl.IFLA_BOND_MIN_LINKS, nl.Uint32Attr(uint32(bond.MinLinks)))
1004	}
1005	if bond.LpInterval >= 0 {
1006		data.AddRtAttr(nl.IFLA_BOND_LP_INTERVAL, nl.Uint32Attr(uint32(bond.LpInterval)))
1007	}
1008	if bond.PackersPerSlave >= 0 {
1009		data.AddRtAttr(nl.IFLA_BOND_PACKETS_PER_SLAVE, nl.Uint32Attr(uint32(bond.PackersPerSlave)))
1010	}
1011	if bond.LacpRate >= 0 {
1012		data.AddRtAttr(nl.IFLA_BOND_AD_LACP_RATE, nl.Uint8Attr(uint8(bond.LacpRate)))
1013	}
1014	if bond.AdSelect >= 0 {
1015		data.AddRtAttr(nl.IFLA_BOND_AD_SELECT, nl.Uint8Attr(uint8(bond.AdSelect)))
1016	}
1017	if bond.AdActorSysPrio >= 0 {
1018		data.AddRtAttr(nl.IFLA_BOND_AD_ACTOR_SYS_PRIO, nl.Uint16Attr(uint16(bond.AdActorSysPrio)))
1019	}
1020	if bond.AdUserPortKey >= 0 {
1021		data.AddRtAttr(nl.IFLA_BOND_AD_USER_PORT_KEY, nl.Uint16Attr(uint16(bond.AdUserPortKey)))
1022	}
1023	if bond.AdActorSystem != nil {
1024		data.AddRtAttr(nl.IFLA_BOND_AD_ACTOR_SYSTEM, []byte(bond.AdActorSystem))
1025	}
1026	if bond.TlbDynamicLb >= 0 {
1027		data.AddRtAttr(nl.IFLA_BOND_TLB_DYNAMIC_LB, nl.Uint8Attr(uint8(bond.TlbDynamicLb)))
1028	}
1029}
1030
1031func cleanupFds(fds []*os.File) {
1032	for _, f := range fds {
1033		f.Close()
1034	}
1035}
1036
1037// LinkAdd adds a new link device. The type and features of the device
1038// are taken from the parameters in the link object.
1039// Equivalent to: `ip link add $link`
1040func LinkAdd(link Link) error {
1041	return pkgHandle.LinkAdd(link)
1042}
1043
1044// LinkAdd adds a new link device. The type and features of the device
1045// are taken from the parameters in the link object.
1046// Equivalent to: `ip link add $link`
1047func (h *Handle) LinkAdd(link Link) error {
1048	return h.linkModify(link, unix.NLM_F_CREATE|unix.NLM_F_EXCL|unix.NLM_F_ACK)
1049}
1050
1051func (h *Handle) linkModify(link Link, flags int) error {
1052	// TODO: support extra data for macvlan
1053	base := link.Attrs()
1054
1055	// if tuntap, then the name can be empty, OS will provide a name
1056	tuntap, isTuntap := link.(*Tuntap)
1057
1058	if base.Name == "" && !isTuntap {
1059		return fmt.Errorf("LinkAttrs.Name cannot be empty")
1060	}
1061
1062	if isTuntap {
1063		// TODO: support user
1064		// TODO: support group
1065		if tuntap.Mode < unix.IFF_TUN || tuntap.Mode > unix.IFF_TAP {
1066			return fmt.Errorf("Tuntap.Mode %v unknown", tuntap.Mode)
1067		}
1068
1069		queues := tuntap.Queues
1070
1071		var fds []*os.File
1072		var req ifReq
1073		copy(req.Name[:15], base.Name)
1074
1075		req.Flags = uint16(tuntap.Flags)
1076
1077		if queues == 0 { //Legacy compatibility
1078			queues = 1
1079			if tuntap.Flags == 0 {
1080				req.Flags = uint16(TUNTAP_DEFAULTS)
1081			}
1082		} else {
1083			// For best peformance set Flags to TUNTAP_MULTI_QUEUE_DEFAULTS | TUNTAP_VNET_HDR
1084			// when a) KVM has support for this ABI and
1085			//      b) the value of the flag is queryable using the TUNGETIFF ioctl
1086			if tuntap.Flags == 0 {
1087				req.Flags = uint16(TUNTAP_MULTI_QUEUE_DEFAULTS)
1088			}
1089		}
1090
1091		req.Flags |= uint16(tuntap.Mode)
1092
1093		for i := 0; i < queues; i++ {
1094			localReq := req
1095			file, err := os.OpenFile("/dev/net/tun", os.O_RDWR, 0)
1096			if err != nil {
1097				cleanupFds(fds)
1098				return err
1099			}
1100
1101			fds = append(fds, file)
1102			_, _, errno := unix.Syscall(unix.SYS_IOCTL, file.Fd(), uintptr(unix.TUNSETIFF), uintptr(unsafe.Pointer(&localReq)))
1103			if errno != 0 {
1104				cleanupFds(fds)
1105				return fmt.Errorf("Tuntap IOCTL TUNSETIFF failed [%d], errno %v", i, errno)
1106			}
1107			// 1) we only care for the name of the first tap in the multi queue set
1108			// 2) if the original name was empty, the localReq has now the actual name
1109			//
1110			// In addition:
1111			// This ensures that the link name is always identical to what the kernel returns.
1112			// Not only in case of an empty name, but also when using name templates.
1113			// e.g. when the provided name is "tap%d", the kernel replaces %d with the next available number.
1114			if i == 0 {
1115				link.Attrs().Name = strings.Trim(string(localReq.Name[:]), "\x00")
1116			}
1117		}
1118
1119		// only persist interface if NonPersist is NOT set
1120		if !tuntap.NonPersist {
1121			_, _, errno := unix.Syscall(unix.SYS_IOCTL, fds[0].Fd(), uintptr(unix.TUNSETPERSIST), 1)
1122			if errno != 0 {
1123				cleanupFds(fds)
1124				return fmt.Errorf("Tuntap IOCTL TUNSETPERSIST failed, errno %v", errno)
1125			}
1126		}
1127
1128		h.ensureIndex(base)
1129
1130		// can't set master during create, so set it afterwards
1131		if base.MasterIndex != 0 {
1132			// TODO: verify MasterIndex is actually a bridge?
1133			err := h.LinkSetMasterByIndex(link, base.MasterIndex)
1134			if err != nil {
1135				// un-persist (e.g. allow the interface to be removed) the tuntap
1136				// should not hurt if not set prior, condition might be not needed
1137				if !tuntap.NonPersist {
1138					_, _, _ = unix.Syscall(unix.SYS_IOCTL, fds[0].Fd(), uintptr(unix.TUNSETPERSIST), 0)
1139				}
1140				cleanupFds(fds)
1141				return err
1142			}
1143		}
1144
1145		if tuntap.Queues == 0 {
1146			cleanupFds(fds)
1147		} else {
1148			tuntap.Fds = fds
1149		}
1150
1151		return nil
1152	}
1153
1154	req := h.newNetlinkRequest(unix.RTM_NEWLINK, flags)
1155
1156	msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
1157	// TODO: make it shorter
1158	if base.Flags&net.FlagUp != 0 {
1159		msg.Change = unix.IFF_UP
1160		msg.Flags = unix.IFF_UP
1161	}
1162	if base.Flags&net.FlagBroadcast != 0 {
1163		msg.Change |= unix.IFF_BROADCAST
1164		msg.Flags |= unix.IFF_BROADCAST
1165	}
1166	if base.Flags&net.FlagLoopback != 0 {
1167		msg.Change |= unix.IFF_LOOPBACK
1168		msg.Flags |= unix.IFF_LOOPBACK
1169	}
1170	if base.Flags&net.FlagPointToPoint != 0 {
1171		msg.Change |= unix.IFF_POINTOPOINT
1172		msg.Flags |= unix.IFF_POINTOPOINT
1173	}
1174	if base.Flags&net.FlagMulticast != 0 {
1175		msg.Change |= unix.IFF_MULTICAST
1176		msg.Flags |= unix.IFF_MULTICAST
1177	}
1178	if base.Index != 0 {
1179		msg.Index = int32(base.Index)
1180	}
1181
1182	req.AddData(msg)
1183
1184	if base.ParentIndex != 0 {
1185		b := make([]byte, 4)
1186		native.PutUint32(b, uint32(base.ParentIndex))
1187		data := nl.NewRtAttr(unix.IFLA_LINK, b)
1188		req.AddData(data)
1189	} else if link.Type() == "ipvlan" || link.Type() == "ipoib" {
1190		return fmt.Errorf("Can't create %s link without ParentIndex", link.Type())
1191	}
1192
1193	nameData := nl.NewRtAttr(unix.IFLA_IFNAME, nl.ZeroTerminated(base.Name))
1194	req.AddData(nameData)
1195
1196	if base.MTU > 0 {
1197		mtu := nl.NewRtAttr(unix.IFLA_MTU, nl.Uint32Attr(uint32(base.MTU)))
1198		req.AddData(mtu)
1199	}
1200
1201	if base.TxQLen >= 0 {
1202		qlen := nl.NewRtAttr(unix.IFLA_TXQLEN, nl.Uint32Attr(uint32(base.TxQLen)))
1203		req.AddData(qlen)
1204	}
1205
1206	if base.HardwareAddr != nil {
1207		hwaddr := nl.NewRtAttr(unix.IFLA_ADDRESS, []byte(base.HardwareAddr))
1208		req.AddData(hwaddr)
1209	}
1210
1211	if base.NumTxQueues > 0 {
1212		txqueues := nl.NewRtAttr(unix.IFLA_NUM_TX_QUEUES, nl.Uint32Attr(uint32(base.NumTxQueues)))
1213		req.AddData(txqueues)
1214	}
1215
1216	if base.NumRxQueues > 0 {
1217		rxqueues := nl.NewRtAttr(unix.IFLA_NUM_RX_QUEUES, nl.Uint32Attr(uint32(base.NumRxQueues)))
1218		req.AddData(rxqueues)
1219	}
1220
1221	if base.GSOMaxSegs > 0 {
1222		gsoAttr := nl.NewRtAttr(unix.IFLA_GSO_MAX_SEGS, nl.Uint32Attr(base.GSOMaxSegs))
1223		req.AddData(gsoAttr)
1224	}
1225
1226	if base.GSOMaxSize > 0 {
1227		gsoAttr := nl.NewRtAttr(unix.IFLA_GSO_MAX_SIZE, nl.Uint32Attr(base.GSOMaxSize))
1228		req.AddData(gsoAttr)
1229	}
1230
1231	if base.Group > 0 {
1232		groupAttr := nl.NewRtAttr(unix.IFLA_GROUP, nl.Uint32Attr(base.Group))
1233		req.AddData(groupAttr)
1234	}
1235
1236	if base.Namespace != nil {
1237		var attr *nl.RtAttr
1238		switch ns := base.Namespace.(type) {
1239		case NsPid:
1240			val := nl.Uint32Attr(uint32(ns))
1241			attr = nl.NewRtAttr(unix.IFLA_NET_NS_PID, val)
1242		case NsFd:
1243			val := nl.Uint32Attr(uint32(ns))
1244			attr = nl.NewRtAttr(unix.IFLA_NET_NS_FD, val)
1245		}
1246
1247		req.AddData(attr)
1248	}
1249
1250	if base.Xdp != nil {
1251		addXdpAttrs(base.Xdp, req)
1252	}
1253
1254	linkInfo := nl.NewRtAttr(unix.IFLA_LINKINFO, nil)
1255	linkInfo.AddRtAttr(nl.IFLA_INFO_KIND, nl.NonZeroTerminated(link.Type()))
1256
1257	switch link := link.(type) {
1258	case *Vlan:
1259		b := make([]byte, 2)
1260		native.PutUint16(b, uint16(link.VlanId))
1261		data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil)
1262		data.AddRtAttr(nl.IFLA_VLAN_ID, b)
1263
1264		if link.VlanProtocol != VLAN_PROTOCOL_UNKNOWN {
1265			data.AddRtAttr(nl.IFLA_VLAN_PROTOCOL, htons(uint16(link.VlanProtocol)))
1266		}
1267	case *Veth:
1268		data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil)
1269		peer := data.AddRtAttr(nl.VETH_INFO_PEER, nil)
1270		nl.NewIfInfomsgChild(peer, unix.AF_UNSPEC)
1271		peer.AddRtAttr(unix.IFLA_IFNAME, nl.ZeroTerminated(link.PeerName))
1272		if base.TxQLen >= 0 {
1273			peer.AddRtAttr(unix.IFLA_TXQLEN, nl.Uint32Attr(uint32(base.TxQLen)))
1274		}
1275		if base.MTU > 0 {
1276			peer.AddRtAttr(unix.IFLA_MTU, nl.Uint32Attr(uint32(base.MTU)))
1277		}
1278		if link.PeerHardwareAddr != nil {
1279			peer.AddRtAttr(unix.IFLA_ADDRESS, []byte(link.PeerHardwareAddr))
1280		}
1281	case *Vxlan:
1282		addVxlanAttrs(link, linkInfo)
1283	case *Bond:
1284		addBondAttrs(link, linkInfo)
1285	case *IPVlan:
1286		data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil)
1287		data.AddRtAttr(nl.IFLA_IPVLAN_MODE, nl.Uint16Attr(uint16(link.Mode)))
1288		data.AddRtAttr(nl.IFLA_IPVLAN_FLAG, nl.Uint16Attr(uint16(link.Flag)))
1289	case *Macvlan:
1290		if link.Mode != MACVLAN_MODE_DEFAULT {
1291			data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil)
1292			data.AddRtAttr(nl.IFLA_MACVLAN_MODE, nl.Uint32Attr(macvlanModes[link.Mode]))
1293		}
1294	case *Macvtap:
1295		if link.Mode != MACVLAN_MODE_DEFAULT {
1296			data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil)
1297			data.AddRtAttr(nl.IFLA_MACVLAN_MODE, nl.Uint32Attr(macvlanModes[link.Mode]))
1298		}
1299	case *Gretap:
1300		addGretapAttrs(link, linkInfo)
1301	case *Iptun:
1302		addIptunAttrs(link, linkInfo)
1303	case *Ip6tnl:
1304		addIp6tnlAttrs(link, linkInfo)
1305	case *Sittun:
1306		addSittunAttrs(link, linkInfo)
1307	case *Gretun:
1308		addGretunAttrs(link, linkInfo)
1309	case *Vti:
1310		addVtiAttrs(link, linkInfo)
1311	case *Vrf:
1312		addVrfAttrs(link, linkInfo)
1313	case *Bridge:
1314		addBridgeAttrs(link, linkInfo)
1315	case *GTP:
1316		addGTPAttrs(link, linkInfo)
1317	case *Xfrmi:
1318		addXfrmiAttrs(link, linkInfo)
1319	case *IPoIB:
1320		addIPoIBAttrs(link, linkInfo)
1321	}
1322
1323	req.AddData(linkInfo)
1324
1325	_, err := req.Execute(unix.NETLINK_ROUTE, 0)
1326	if err != nil {
1327		return err
1328	}
1329
1330	h.ensureIndex(base)
1331
1332	// can't set master during create, so set it afterwards
1333	if base.MasterIndex != 0 {
1334		// TODO: verify MasterIndex is actually a bridge?
1335		return h.LinkSetMasterByIndex(link, base.MasterIndex)
1336	}
1337	return nil
1338}
1339
1340// LinkDel deletes link device. Either Index or Name must be set in
1341// the link object for it to be deleted. The other values are ignored.
1342// Equivalent to: `ip link del $link`
1343func LinkDel(link Link) error {
1344	return pkgHandle.LinkDel(link)
1345}
1346
1347// LinkDel deletes link device. Either Index or Name must be set in
1348// the link object for it to be deleted. The other values are ignored.
1349// Equivalent to: `ip link del $link`
1350func (h *Handle) LinkDel(link Link) error {
1351	base := link.Attrs()
1352
1353	h.ensureIndex(base)
1354
1355	req := h.newNetlinkRequest(unix.RTM_DELLINK, unix.NLM_F_ACK)
1356
1357	msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
1358	msg.Index = int32(base.Index)
1359	req.AddData(msg)
1360
1361	_, err := req.Execute(unix.NETLINK_ROUTE, 0)
1362	return err
1363}
1364
1365func (h *Handle) linkByNameDump(name string) (Link, error) {
1366	links, err := h.LinkList()
1367	if err != nil {
1368		return nil, err
1369	}
1370
1371	for _, link := range links {
1372		if link.Attrs().Name == name {
1373			return link, nil
1374		}
1375	}
1376	return nil, LinkNotFoundError{fmt.Errorf("Link %s not found", name)}
1377}
1378
1379func (h *Handle) linkByAliasDump(alias string) (Link, error) {
1380	links, err := h.LinkList()
1381	if err != nil {
1382		return nil, err
1383	}
1384
1385	for _, link := range links {
1386		if link.Attrs().Alias == alias {
1387			return link, nil
1388		}
1389	}
1390	return nil, LinkNotFoundError{fmt.Errorf("Link alias %s not found", alias)}
1391}
1392
1393// LinkByName finds a link by name and returns a pointer to the object.
1394func LinkByName(name string) (Link, error) {
1395	return pkgHandle.LinkByName(name)
1396}
1397
1398// LinkByName finds a link by name and returns a pointer to the object.
1399func (h *Handle) LinkByName(name string) (Link, error) {
1400	if h.lookupByDump {
1401		return h.linkByNameDump(name)
1402	}
1403
1404	req := h.newNetlinkRequest(unix.RTM_GETLINK, unix.NLM_F_ACK)
1405
1406	msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
1407	req.AddData(msg)
1408
1409	attr := nl.NewRtAttr(unix.IFLA_EXT_MASK, nl.Uint32Attr(nl.RTEXT_FILTER_VF))
1410	req.AddData(attr)
1411
1412	nameData := nl.NewRtAttr(unix.IFLA_IFNAME, nl.ZeroTerminated(name))
1413	req.AddData(nameData)
1414
1415	link, err := execGetLink(req)
1416	if err == unix.EINVAL {
1417		// older kernels don't support looking up via IFLA_IFNAME
1418		// so fall back to dumping all links
1419		h.lookupByDump = true
1420		return h.linkByNameDump(name)
1421	}
1422
1423	return link, err
1424}
1425
1426// LinkByAlias finds a link by its alias and returns a pointer to the object.
1427// If there are multiple links with the alias it returns the first one
1428func LinkByAlias(alias string) (Link, error) {
1429	return pkgHandle.LinkByAlias(alias)
1430}
1431
1432// LinkByAlias finds a link by its alias and returns a pointer to the object.
1433// If there are multiple links with the alias it returns the first one
1434func (h *Handle) LinkByAlias(alias string) (Link, error) {
1435	if h.lookupByDump {
1436		return h.linkByAliasDump(alias)
1437	}
1438
1439	req := h.newNetlinkRequest(unix.RTM_GETLINK, unix.NLM_F_ACK)
1440
1441	msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
1442	req.AddData(msg)
1443
1444	attr := nl.NewRtAttr(unix.IFLA_EXT_MASK, nl.Uint32Attr(nl.RTEXT_FILTER_VF))
1445	req.AddData(attr)
1446
1447	nameData := nl.NewRtAttr(unix.IFLA_IFALIAS, nl.ZeroTerminated(alias))
1448	req.AddData(nameData)
1449
1450	link, err := execGetLink(req)
1451	if err == unix.EINVAL {
1452		// older kernels don't support looking up via IFLA_IFALIAS
1453		// so fall back to dumping all links
1454		h.lookupByDump = true
1455		return h.linkByAliasDump(alias)
1456	}
1457
1458	return link, err
1459}
1460
1461// LinkByIndex finds a link by index and returns a pointer to the object.
1462func LinkByIndex(index int) (Link, error) {
1463	return pkgHandle.LinkByIndex(index)
1464}
1465
1466// LinkByIndex finds a link by index and returns a pointer to the object.
1467func (h *Handle) LinkByIndex(index int) (Link, error) {
1468	req := h.newNetlinkRequest(unix.RTM_GETLINK, unix.NLM_F_ACK)
1469
1470	msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
1471	msg.Index = int32(index)
1472	req.AddData(msg)
1473	attr := nl.NewRtAttr(unix.IFLA_EXT_MASK, nl.Uint32Attr(nl.RTEXT_FILTER_VF))
1474	req.AddData(attr)
1475
1476	return execGetLink(req)
1477}
1478
1479func execGetLink(req *nl.NetlinkRequest) (Link, error) {
1480	msgs, err := req.Execute(unix.NETLINK_ROUTE, 0)
1481	if err != nil {
1482		if errno, ok := err.(syscall.Errno); ok {
1483			if errno == unix.ENODEV {
1484				return nil, LinkNotFoundError{fmt.Errorf("Link not found")}
1485			}
1486		}
1487		return nil, err
1488	}
1489
1490	switch {
1491	case len(msgs) == 0:
1492		return nil, LinkNotFoundError{fmt.Errorf("Link not found")}
1493
1494	case len(msgs) == 1:
1495		return LinkDeserialize(nil, msgs[0])
1496
1497	default:
1498		return nil, fmt.Errorf("More than one link found")
1499	}
1500}
1501
1502// linkDeserialize deserializes a raw message received from netlink into
1503// a link object.
1504func LinkDeserialize(hdr *unix.NlMsghdr, m []byte) (Link, error) {
1505	msg := nl.DeserializeIfInfomsg(m)
1506
1507	attrs, err := nl.ParseRouteAttr(m[msg.Len():])
1508	if err != nil {
1509		return nil, err
1510	}
1511
1512	base := LinkAttrs{Index: int(msg.Index), RawFlags: msg.Flags, Flags: linkFlags(msg.Flags), EncapType: msg.EncapType()}
1513	if msg.Flags&unix.IFF_PROMISC != 0 {
1514		base.Promisc = 1
1515	}
1516	var (
1517		link      Link
1518		stats32   *LinkStatistics32
1519		stats64   *LinkStatistics64
1520		linkType  string
1521		linkSlave LinkSlave
1522		slaveType string
1523	)
1524	for _, attr := range attrs {
1525		switch attr.Attr.Type {
1526		case unix.IFLA_LINKINFO:
1527			infos, err := nl.ParseRouteAttr(attr.Value)
1528			if err != nil {
1529				return nil, err
1530			}
1531			for _, info := range infos {
1532				switch info.Attr.Type {
1533				case nl.IFLA_INFO_KIND:
1534					linkType = string(info.Value[:len(info.Value)-1])
1535					switch linkType {
1536					case "dummy":
1537						link = &Dummy{}
1538					case "ifb":
1539						link = &Ifb{}
1540					case "bridge":
1541						link = &Bridge{}
1542					case "vlan":
1543						link = &Vlan{}
1544					case "veth":
1545						link = &Veth{}
1546					case "vxlan":
1547						link = &Vxlan{}
1548					case "bond":
1549						link = &Bond{}
1550					case "ipvlan":
1551						link = &IPVlan{}
1552					case "macvlan":
1553						link = &Macvlan{}
1554					case "macvtap":
1555						link = &Macvtap{}
1556					case "gretap":
1557						link = &Gretap{}
1558					case "ip6gretap":
1559						link = &Gretap{}
1560					case "ipip":
1561						link = &Iptun{}
1562					case "ip6tnl":
1563						link = &Ip6tnl{}
1564					case "sit":
1565						link = &Sittun{}
1566					case "gre":
1567						link = &Gretun{}
1568					case "ip6gre":
1569						link = &Gretun{}
1570					case "vti", "vti6":
1571						link = &Vti{}
1572					case "vrf":
1573						link = &Vrf{}
1574					case "gtp":
1575						link = &GTP{}
1576					case "xfrm":
1577						link = &Xfrmi{}
1578					case "tun":
1579						link = &Tuntap{}
1580					case "ipoib":
1581						link = &IPoIB{}
1582					default:
1583						link = &GenericLink{LinkType: linkType}
1584					}
1585				case nl.IFLA_INFO_DATA:
1586					data, err := nl.ParseRouteAttr(info.Value)
1587					if err != nil {
1588						return nil, err
1589					}
1590					switch linkType {
1591					case "vlan":
1592						parseVlanData(link, data)
1593					case "vxlan":
1594						parseVxlanData(link, data)
1595					case "bond":
1596						parseBondData(link, data)
1597					case "ipvlan":
1598						parseIPVlanData(link, data)
1599					case "macvlan":
1600						parseMacvlanData(link, data)
1601					case "macvtap":
1602						parseMacvtapData(link, data)
1603					case "gretap":
1604						parseGretapData(link, data)
1605					case "ip6gretap":
1606						parseGretapData(link, data)
1607					case "ipip":
1608						parseIptunData(link, data)
1609					case "ip6tnl":
1610						parseIp6tnlData(link, data)
1611					case "sit":
1612						parseSittunData(link, data)
1613					case "gre":
1614						parseGretunData(link, data)
1615					case "ip6gre":
1616						parseGretunData(link, data)
1617					case "vti", "vti6":
1618						parseVtiData(link, data)
1619					case "vrf":
1620						parseVrfData(link, data)
1621					case "bridge":
1622						parseBridgeData(link, data)
1623					case "gtp":
1624						parseGTPData(link, data)
1625					case "xfrm":
1626						parseXfrmiData(link, data)
1627					case "tun":
1628						parseTuntapData(link, data)
1629					case "ipoib":
1630						parseIPoIBData(link, data)
1631					}
1632				case nl.IFLA_INFO_SLAVE_KIND:
1633					slaveType = string(info.Value[:len(info.Value)-1])
1634					switch slaveType {
1635					case "bond":
1636						linkSlave = &BondSlave{}
1637					}
1638				case nl.IFLA_INFO_SLAVE_DATA:
1639					switch slaveType {
1640					case "bond":
1641						data, err := nl.ParseRouteAttr(info.Value)
1642						if err != nil {
1643							return nil, err
1644						}
1645						parseBondSlaveData(linkSlave, data)
1646					}
1647				}
1648			}
1649		case unix.IFLA_ADDRESS:
1650			var nonzero bool
1651			for _, b := range attr.Value {
1652				if b != 0 {
1653					nonzero = true
1654				}
1655			}
1656			if nonzero {
1657				base.HardwareAddr = attr.Value[:]
1658			}
1659		case unix.IFLA_IFNAME:
1660			base.Name = string(attr.Value[:len(attr.Value)-1])
1661		case unix.IFLA_MTU:
1662			base.MTU = int(native.Uint32(attr.Value[0:4]))
1663		case unix.IFLA_LINK:
1664			base.ParentIndex = int(native.Uint32(attr.Value[0:4]))
1665		case unix.IFLA_MASTER:
1666			base.MasterIndex = int(native.Uint32(attr.Value[0:4]))
1667		case unix.IFLA_TXQLEN:
1668			base.TxQLen = int(native.Uint32(attr.Value[0:4]))
1669		case unix.IFLA_IFALIAS:
1670			base.Alias = string(attr.Value[:len(attr.Value)-1])
1671		case unix.IFLA_STATS:
1672			stats32 = new(LinkStatistics32)
1673			if err := binary.Read(bytes.NewBuffer(attr.Value[:]), nl.NativeEndian(), stats32); err != nil {
1674				return nil, err
1675			}
1676		case unix.IFLA_STATS64:
1677			stats64 = new(LinkStatistics64)
1678			if err := binary.Read(bytes.NewBuffer(attr.Value[:]), nl.NativeEndian(), stats64); err != nil {
1679				return nil, err
1680			}
1681		case unix.IFLA_XDP:
1682			xdp, err := parseLinkXdp(attr.Value[:])
1683			if err != nil {
1684				return nil, err
1685			}
1686			base.Xdp = xdp
1687		case unix.IFLA_PROTINFO | unix.NLA_F_NESTED:
1688			if hdr != nil && hdr.Type == unix.RTM_NEWLINK &&
1689				msg.Family == unix.AF_BRIDGE {
1690				attrs, err := nl.ParseRouteAttr(attr.Value[:])
1691				if err != nil {
1692					return nil, err
1693				}
1694				protinfo := parseProtinfo(attrs)
1695				base.Protinfo = &protinfo
1696			}
1697		case unix.IFLA_OPERSTATE:
1698			base.OperState = LinkOperState(uint8(attr.Value[0]))
1699		case unix.IFLA_LINK_NETNSID:
1700			base.NetNsID = int(native.Uint32(attr.Value[0:4]))
1701		case unix.IFLA_GSO_MAX_SIZE:
1702			base.GSOMaxSize = native.Uint32(attr.Value[0:4])
1703		case unix.IFLA_GSO_MAX_SEGS:
1704			base.GSOMaxSegs = native.Uint32(attr.Value[0:4])
1705		case unix.IFLA_VFINFO_LIST:
1706			data, err := nl.ParseRouteAttr(attr.Value)
1707			if err != nil {
1708				return nil, err
1709			}
1710			vfs, err := parseVfInfoList(data)
1711			if err != nil {
1712				return nil, err
1713			}
1714			base.Vfs = vfs
1715		case unix.IFLA_NUM_TX_QUEUES:
1716			base.NumTxQueues = int(native.Uint32(attr.Value[0:4]))
1717		case unix.IFLA_NUM_RX_QUEUES:
1718			base.NumRxQueues = int(native.Uint32(attr.Value[0:4]))
1719		case unix.IFLA_GROUP:
1720			base.Group = native.Uint32(attr.Value[0:4])
1721		}
1722	}
1723
1724	if stats64 != nil {
1725		base.Statistics = (*LinkStatistics)(stats64)
1726	} else if stats32 != nil {
1727		base.Statistics = (*LinkStatistics)(stats32.to64())
1728	}
1729
1730	// Links that don't have IFLA_INFO_KIND are hardware devices
1731	if link == nil {
1732		link = &Device{}
1733	}
1734	*link.Attrs() = base
1735	link.Attrs().Slave = linkSlave
1736
1737	// If the tuntap attributes are not updated by netlink due to
1738	// an older driver, use sysfs
1739	if link != nil && linkType == "tun" {
1740		tuntap := link.(*Tuntap)
1741
1742		if tuntap.Mode == 0 {
1743			ifname := tuntap.Attrs().Name
1744			if flags, err := readSysPropAsInt64(ifname, "tun_flags"); err == nil {
1745
1746				if flags&unix.IFF_TUN != 0 {
1747					tuntap.Mode = unix.IFF_TUN
1748				} else if flags&unix.IFF_TAP != 0 {
1749					tuntap.Mode = unix.IFF_TAP
1750				}
1751
1752				tuntap.NonPersist = false
1753				if flags&unix.IFF_PERSIST == 0 {
1754					tuntap.NonPersist = true
1755				}
1756			}
1757
1758			// The sysfs interface for owner/group returns -1 for root user, instead of returning 0.
1759			// So explicitly check for negative value, before assigning the owner uid/gid.
1760			if owner, err := readSysPropAsInt64(ifname, "owner"); err == nil && owner > 0 {
1761				tuntap.Owner = uint32(owner)
1762			}
1763
1764			if group, err := readSysPropAsInt64(ifname, "group"); err == nil && group > 0 {
1765				tuntap.Group = uint32(group)
1766			}
1767		}
1768	}
1769
1770	return link, nil
1771}
1772
1773func readSysPropAsInt64(ifname, prop string) (int64, error) {
1774	fname := fmt.Sprintf("/sys/class/net/%s/%s", ifname, prop)
1775	contents, err := ioutil.ReadFile(fname)
1776	if err != nil {
1777		return 0, err
1778	}
1779
1780	num, err := strconv.ParseInt(strings.TrimSpace(string(contents)), 0, 64)
1781	if err == nil {
1782		return num, nil
1783	}
1784
1785	return 0, err
1786}
1787
1788// LinkList gets a list of link devices.
1789// Equivalent to: `ip link show`
1790func LinkList() ([]Link, error) {
1791	return pkgHandle.LinkList()
1792}
1793
1794// LinkList gets a list of link devices.
1795// Equivalent to: `ip link show`
1796func (h *Handle) LinkList() ([]Link, error) {
1797	// NOTE(vish): This duplicates functionality in net/iface_linux.go, but we need
1798	//             to get the message ourselves to parse link type.
1799	req := h.newNetlinkRequest(unix.RTM_GETLINK, unix.NLM_F_DUMP)
1800
1801	msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
1802	req.AddData(msg)
1803	attr := nl.NewRtAttr(unix.IFLA_EXT_MASK, nl.Uint32Attr(nl.RTEXT_FILTER_VF))
1804	req.AddData(attr)
1805
1806	msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWLINK)
1807	if err != nil {
1808		return nil, err
1809	}
1810
1811	var res []Link
1812	for _, m := range msgs {
1813		link, err := LinkDeserialize(nil, m)
1814		if err != nil {
1815			return nil, err
1816		}
1817		res = append(res, link)
1818	}
1819
1820	return res, nil
1821}
1822
1823// LinkUpdate is used to pass information back from LinkSubscribe()
1824type LinkUpdate struct {
1825	nl.IfInfomsg
1826	Header unix.NlMsghdr
1827	Link
1828}
1829
1830// LinkSubscribe takes a chan down which notifications will be sent
1831// when links change.  Close the 'done' chan to stop subscription.
1832func LinkSubscribe(ch chan<- LinkUpdate, done <-chan struct{}) error {
1833	return linkSubscribeAt(netns.None(), netns.None(), ch, done, nil, false)
1834}
1835
1836// LinkSubscribeAt works like LinkSubscribe plus it allows the caller
1837// to choose the network namespace in which to subscribe (ns).
1838func LinkSubscribeAt(ns netns.NsHandle, ch chan<- LinkUpdate, done <-chan struct{}) error {
1839	return linkSubscribeAt(ns, netns.None(), ch, done, nil, false)
1840}
1841
1842// LinkSubscribeOptions contains a set of options to use with
1843// LinkSubscribeWithOptions.
1844type LinkSubscribeOptions struct {
1845	Namespace     *netns.NsHandle
1846	ErrorCallback func(error)
1847	ListExisting  bool
1848}
1849
1850// LinkSubscribeWithOptions work like LinkSubscribe but enable to
1851// provide additional options to modify the behavior. Currently, the
1852// namespace can be provided as well as an error callback.
1853func LinkSubscribeWithOptions(ch chan<- LinkUpdate, done <-chan struct{}, options LinkSubscribeOptions) error {
1854	if options.Namespace == nil {
1855		none := netns.None()
1856		options.Namespace = &none
1857	}
1858	return linkSubscribeAt(*options.Namespace, netns.None(), ch, done, options.ErrorCallback, options.ListExisting)
1859}
1860
1861func linkSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- LinkUpdate, done <-chan struct{}, cberr func(error), listExisting bool) error {
1862	s, err := nl.SubscribeAt(newNs, curNs, unix.NETLINK_ROUTE, unix.RTNLGRP_LINK)
1863	if err != nil {
1864		return err
1865	}
1866	if done != nil {
1867		go func() {
1868			<-done
1869			s.Close()
1870		}()
1871	}
1872	if listExisting {
1873		req := pkgHandle.newNetlinkRequest(unix.RTM_GETLINK,
1874			unix.NLM_F_DUMP)
1875		msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
1876		req.AddData(msg)
1877		if err := s.Send(req); err != nil {
1878			return err
1879		}
1880	}
1881	go func() {
1882		defer close(ch)
1883		for {
1884			msgs, from, err := s.Receive()
1885			if err != nil {
1886				if cberr != nil {
1887					cberr(err)
1888				}
1889				return
1890			}
1891			if from.Pid != nl.PidKernel {
1892				if cberr != nil {
1893					cberr(fmt.Errorf("Wrong sender portid %d, expected %d", from.Pid, nl.PidKernel))
1894				}
1895				continue
1896			}
1897			for _, m := range msgs {
1898				if m.Header.Type == unix.NLMSG_DONE {
1899					continue
1900				}
1901				if m.Header.Type == unix.NLMSG_ERROR {
1902					native := nl.NativeEndian()
1903					error := int32(native.Uint32(m.Data[0:4]))
1904					if error == 0 {
1905						continue
1906					}
1907					if cberr != nil {
1908						cberr(syscall.Errno(-error))
1909					}
1910					return
1911				}
1912				ifmsg := nl.DeserializeIfInfomsg(m.Data)
1913				header := unix.NlMsghdr(m.Header)
1914				link, err := LinkDeserialize(&header, m.Data)
1915				if err != nil {
1916					if cberr != nil {
1917						cberr(err)
1918					}
1919					return
1920				}
1921				ch <- LinkUpdate{IfInfomsg: *ifmsg, Header: header, Link: link}
1922			}
1923		}
1924	}()
1925
1926	return nil
1927}
1928
1929func LinkSetHairpin(link Link, mode bool) error {
1930	return pkgHandle.LinkSetHairpin(link, mode)
1931}
1932
1933func (h *Handle) LinkSetHairpin(link Link, mode bool) error {
1934	return h.setProtinfoAttr(link, mode, nl.IFLA_BRPORT_MODE)
1935}
1936
1937func LinkSetGuard(link Link, mode bool) error {
1938	return pkgHandle.LinkSetGuard(link, mode)
1939}
1940
1941func (h *Handle) LinkSetGuard(link Link, mode bool) error {
1942	return h.setProtinfoAttr(link, mode, nl.IFLA_BRPORT_GUARD)
1943}
1944
1945func LinkSetFastLeave(link Link, mode bool) error {
1946	return pkgHandle.LinkSetFastLeave(link, mode)
1947}
1948
1949func (h *Handle) LinkSetFastLeave(link Link, mode bool) error {
1950	return h.setProtinfoAttr(link, mode, nl.IFLA_BRPORT_FAST_LEAVE)
1951}
1952
1953func LinkSetLearning(link Link, mode bool) error {
1954	return pkgHandle.LinkSetLearning(link, mode)
1955}
1956
1957func (h *Handle) LinkSetLearning(link Link, mode bool) error {
1958	return h.setProtinfoAttr(link, mode, nl.IFLA_BRPORT_LEARNING)
1959}
1960
1961func LinkSetRootBlock(link Link, mode bool) error {
1962	return pkgHandle.LinkSetRootBlock(link, mode)
1963}
1964
1965func (h *Handle) LinkSetRootBlock(link Link, mode bool) error {
1966	return h.setProtinfoAttr(link, mode, nl.IFLA_BRPORT_PROTECT)
1967}
1968
1969func LinkSetFlood(link Link, mode bool) error {
1970	return pkgHandle.LinkSetFlood(link, mode)
1971}
1972
1973func (h *Handle) LinkSetFlood(link Link, mode bool) error {
1974	return h.setProtinfoAttr(link, mode, nl.IFLA_BRPORT_UNICAST_FLOOD)
1975}
1976
1977func LinkSetBrProxyArp(link Link, mode bool) error {
1978	return pkgHandle.LinkSetBrProxyArp(link, mode)
1979}
1980
1981func (h *Handle) LinkSetBrProxyArp(link Link, mode bool) error {
1982	return h.setProtinfoAttr(link, mode, nl.IFLA_BRPORT_PROXYARP)
1983}
1984
1985func LinkSetBrProxyArpWiFi(link Link, mode bool) error {
1986	return pkgHandle.LinkSetBrProxyArpWiFi(link, mode)
1987}
1988
1989func (h *Handle) LinkSetBrProxyArpWiFi(link Link, mode bool) error {
1990	return h.setProtinfoAttr(link, mode, nl.IFLA_BRPORT_PROXYARP_WIFI)
1991}
1992
1993func (h *Handle) setProtinfoAttr(link Link, mode bool, attr int) error {
1994	base := link.Attrs()
1995	h.ensureIndex(base)
1996	req := h.newNetlinkRequest(unix.RTM_SETLINK, unix.NLM_F_ACK)
1997
1998	msg := nl.NewIfInfomsg(unix.AF_BRIDGE)
1999	msg.Index = int32(base.Index)
2000	req.AddData(msg)
2001
2002	br := nl.NewRtAttr(unix.IFLA_PROTINFO|unix.NLA_F_NESTED, nil)
2003	br.AddRtAttr(attr, boolToByte(mode))
2004	req.AddData(br)
2005	_, err := req.Execute(unix.NETLINK_ROUTE, 0)
2006	if err != nil {
2007		return err
2008	}
2009	return nil
2010}
2011
2012// LinkSetTxQLen sets the transaction queue length for the link.
2013// Equivalent to: `ip link set $link txqlen $qlen`
2014func LinkSetTxQLen(link Link, qlen int) error {
2015	return pkgHandle.LinkSetTxQLen(link, qlen)
2016}
2017
2018// LinkSetTxQLen sets the transaction queue length for the link.
2019// Equivalent to: `ip link set $link txqlen $qlen`
2020func (h *Handle) LinkSetTxQLen(link Link, qlen int) error {
2021	base := link.Attrs()
2022	h.ensureIndex(base)
2023	req := h.newNetlinkRequest(unix.RTM_SETLINK, unix.NLM_F_ACK)
2024
2025	msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
2026	msg.Index = int32(base.Index)
2027	req.AddData(msg)
2028
2029	b := make([]byte, 4)
2030	native.PutUint32(b, uint32(qlen))
2031
2032	data := nl.NewRtAttr(unix.IFLA_TXQLEN, b)
2033	req.AddData(data)
2034
2035	_, err := req.Execute(unix.NETLINK_ROUTE, 0)
2036	return err
2037}
2038
2039// LinkSetGroup sets the link group id which can be used to perform mass actions
2040// with iproute2 as well use it as a reference in nft filters.
2041// Equivalent to: `ip link set $link group $id`
2042func LinkSetGroup(link Link, group int) error {
2043	return pkgHandle.LinkSetGroup(link, group)
2044}
2045
2046// LinkSetGroup sets the link group id which can be used to perform mass actions
2047// with iproute2 as well use it as a reference in nft filters.
2048// Equivalent to: `ip link set $link group $id`
2049func (h *Handle) LinkSetGroup(link Link, group int) error {
2050	base := link.Attrs()
2051	h.ensureIndex(base)
2052	req := h.newNetlinkRequest(unix.RTM_SETLINK, unix.NLM_F_ACK)
2053
2054	msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
2055	msg.Index = int32(base.Index)
2056	req.AddData(msg)
2057
2058	b := make([]byte, 4)
2059	native.PutUint32(b, uint32(group))
2060
2061	data := nl.NewRtAttr(unix.IFLA_GROUP, b)
2062	req.AddData(data)
2063
2064	_, err := req.Execute(unix.NETLINK_ROUTE, 0)
2065	return err
2066}
2067
2068func parseVlanData(link Link, data []syscall.NetlinkRouteAttr) {
2069	vlan := link.(*Vlan)
2070	for _, datum := range data {
2071		switch datum.Attr.Type {
2072		case nl.IFLA_VLAN_ID:
2073			vlan.VlanId = int(native.Uint16(datum.Value[0:2]))
2074		case nl.IFLA_VLAN_PROTOCOL:
2075			vlan.VlanProtocol = VlanProtocol(int(ntohs(datum.Value[0:2])))
2076		}
2077	}
2078}
2079
2080func parseVxlanData(link Link, data []syscall.NetlinkRouteAttr) {
2081	vxlan := link.(*Vxlan)
2082	for _, datum := range data {
2083		switch datum.Attr.Type {
2084		case nl.IFLA_VXLAN_ID:
2085			vxlan.VxlanId = int(native.Uint32(datum.Value[0:4]))
2086		case nl.IFLA_VXLAN_LINK:
2087			vxlan.VtepDevIndex = int(native.Uint32(datum.Value[0:4]))
2088		case nl.IFLA_VXLAN_LOCAL:
2089			vxlan.SrcAddr = net.IP(datum.Value[0:4])
2090		case nl.IFLA_VXLAN_LOCAL6:
2091			vxlan.SrcAddr = net.IP(datum.Value[0:16])
2092		case nl.IFLA_VXLAN_GROUP:
2093			vxlan.Group = net.IP(datum.Value[0:4])
2094		case nl.IFLA_VXLAN_GROUP6:
2095			vxlan.Group = net.IP(datum.Value[0:16])
2096		case nl.IFLA_VXLAN_TTL:
2097			vxlan.TTL = int(datum.Value[0])
2098		case nl.IFLA_VXLAN_TOS:
2099			vxlan.TOS = int(datum.Value[0])
2100		case nl.IFLA_VXLAN_LEARNING:
2101			vxlan.Learning = int8(datum.Value[0]) != 0
2102		case nl.IFLA_VXLAN_PROXY:
2103			vxlan.Proxy = int8(datum.Value[0]) != 0
2104		case nl.IFLA_VXLAN_RSC:
2105			vxlan.RSC = int8(datum.Value[0]) != 0
2106		case nl.IFLA_VXLAN_L2MISS:
2107			vxlan.L2miss = int8(datum.Value[0]) != 0
2108		case nl.IFLA_VXLAN_L3MISS:
2109			vxlan.L3miss = int8(datum.Value[0]) != 0
2110		case nl.IFLA_VXLAN_UDP_CSUM:
2111			vxlan.UDPCSum = int8(datum.Value[0]) != 0
2112		case nl.IFLA_VXLAN_UDP_ZERO_CSUM6_TX:
2113			vxlan.UDP6ZeroCSumTx = int8(datum.Value[0]) != 0
2114		case nl.IFLA_VXLAN_UDP_ZERO_CSUM6_RX:
2115			vxlan.UDP6ZeroCSumRx = int8(datum.Value[0]) != 0
2116		case nl.IFLA_VXLAN_GBP:
2117			vxlan.GBP = true
2118		case nl.IFLA_VXLAN_FLOWBASED:
2119			vxlan.FlowBased = int8(datum.Value[0]) != 0
2120		case nl.IFLA_VXLAN_AGEING:
2121			vxlan.Age = int(native.Uint32(datum.Value[0:4]))
2122			vxlan.NoAge = vxlan.Age == 0
2123		case nl.IFLA_VXLAN_LIMIT:
2124			vxlan.Limit = int(native.Uint32(datum.Value[0:4]))
2125		case nl.IFLA_VXLAN_PORT:
2126			vxlan.Port = int(ntohs(datum.Value[0:2]))
2127		case nl.IFLA_VXLAN_PORT_RANGE:
2128			buf := bytes.NewBuffer(datum.Value[0:4])
2129			var pr vxlanPortRange
2130			if binary.Read(buf, binary.BigEndian, &pr) != nil {
2131				vxlan.PortLow = int(pr.Lo)
2132				vxlan.PortHigh = int(pr.Hi)
2133			}
2134		}
2135	}
2136}
2137
2138func parseBondData(link Link, data []syscall.NetlinkRouteAttr) {
2139	bond := link.(*Bond)
2140	for i := range data {
2141		switch data[i].Attr.Type {
2142		case nl.IFLA_BOND_MODE:
2143			bond.Mode = BondMode(data[i].Value[0])
2144		case nl.IFLA_BOND_ACTIVE_SLAVE:
2145			bond.ActiveSlave = int(native.Uint32(data[i].Value[0:4]))
2146		case nl.IFLA_BOND_MIIMON:
2147			bond.Miimon = int(native.Uint32(data[i].Value[0:4]))
2148		case nl.IFLA_BOND_UPDELAY:
2149			bond.UpDelay = int(native.Uint32(data[i].Value[0:4]))
2150		case nl.IFLA_BOND_DOWNDELAY:
2151			bond.DownDelay = int(native.Uint32(data[i].Value[0:4]))
2152		case nl.IFLA_BOND_USE_CARRIER:
2153			bond.UseCarrier = int(data[i].Value[0])
2154		case nl.IFLA_BOND_ARP_INTERVAL:
2155			bond.ArpInterval = int(native.Uint32(data[i].Value[0:4]))
2156		case nl.IFLA_BOND_ARP_IP_TARGET:
2157			bond.ArpIpTargets = parseBondArpIpTargets(data[i].Value)
2158		case nl.IFLA_BOND_ARP_VALIDATE:
2159			bond.ArpValidate = BondArpValidate(native.Uint32(data[i].Value[0:4]))
2160		case nl.IFLA_BOND_ARP_ALL_TARGETS:
2161			bond.ArpAllTargets = BondArpAllTargets(native.Uint32(data[i].Value[0:4]))
2162		case nl.IFLA_BOND_PRIMARY:
2163			bond.Primary = int(native.Uint32(data[i].Value[0:4]))
2164		case nl.IFLA_BOND_PRIMARY_RESELECT:
2165			bond.PrimaryReselect = BondPrimaryReselect(data[i].Value[0])
2166		case nl.IFLA_BOND_FAIL_OVER_MAC:
2167			bond.FailOverMac = BondFailOverMac(data[i].Value[0])
2168		case nl.IFLA_BOND_XMIT_HASH_POLICY:
2169			bond.XmitHashPolicy = BondXmitHashPolicy(data[i].Value[0])
2170		case nl.IFLA_BOND_RESEND_IGMP:
2171			bond.ResendIgmp = int(native.Uint32(data[i].Value[0:4]))
2172		case nl.IFLA_BOND_NUM_PEER_NOTIF:
2173			bond.NumPeerNotif = int(data[i].Value[0])
2174		case nl.IFLA_BOND_ALL_SLAVES_ACTIVE:
2175			bond.AllSlavesActive = int(data[i].Value[0])
2176		case nl.IFLA_BOND_MIN_LINKS:
2177			bond.MinLinks = int(native.Uint32(data[i].Value[0:4]))
2178		case nl.IFLA_BOND_LP_INTERVAL:
2179			bond.LpInterval = int(native.Uint32(data[i].Value[0:4]))
2180		case nl.IFLA_BOND_PACKETS_PER_SLAVE:
2181			bond.PackersPerSlave = int(native.Uint32(data[i].Value[0:4]))
2182		case nl.IFLA_BOND_AD_LACP_RATE:
2183			bond.LacpRate = BondLacpRate(data[i].Value[0])
2184		case nl.IFLA_BOND_AD_SELECT:
2185			bond.AdSelect = BondAdSelect(data[i].Value[0])
2186		case nl.IFLA_BOND_AD_INFO:
2187			// TODO: implement
2188		case nl.IFLA_BOND_AD_ACTOR_SYS_PRIO:
2189			bond.AdActorSysPrio = int(native.Uint16(data[i].Value[0:2]))
2190		case nl.IFLA_BOND_AD_USER_PORT_KEY:
2191			bond.AdUserPortKey = int(native.Uint16(data[i].Value[0:2]))
2192		case nl.IFLA_BOND_AD_ACTOR_SYSTEM:
2193			bond.AdActorSystem = net.HardwareAddr(data[i].Value[0:6])
2194		case nl.IFLA_BOND_TLB_DYNAMIC_LB:
2195			bond.TlbDynamicLb = int(data[i].Value[0])
2196		}
2197	}
2198}
2199
2200func parseBondArpIpTargets(value []byte) []net.IP {
2201	data, err := nl.ParseRouteAttr(value)
2202	if err != nil {
2203		return nil
2204	}
2205
2206	targets := []net.IP{}
2207	for i := range data {
2208		target := net.IP(data[i].Value)
2209		if ip := target.To4(); ip != nil {
2210			targets = append(targets, ip)
2211			continue
2212		}
2213		if ip := target.To16(); ip != nil {
2214			targets = append(targets, ip)
2215		}
2216	}
2217
2218	return targets
2219}
2220
2221func addBondSlaveAttrs(bondSlave *BondSlave, linkInfo *nl.RtAttr) {
2222	data := linkInfo.AddRtAttr(nl.IFLA_INFO_SLAVE_DATA, nil)
2223
2224	data.AddRtAttr(nl.IFLA_BOND_SLAVE_STATE, nl.Uint8Attr(uint8(bondSlave.State)))
2225	data.AddRtAttr(nl.IFLA_BOND_SLAVE_MII_STATUS, nl.Uint8Attr(uint8(bondSlave.MiiStatus)))
2226	data.AddRtAttr(nl.IFLA_BOND_SLAVE_LINK_FAILURE_COUNT, nl.Uint32Attr(bondSlave.LinkFailureCount))
2227	data.AddRtAttr(nl.IFLA_BOND_SLAVE_QUEUE_ID, nl.Uint16Attr(bondSlave.QueueId))
2228	data.AddRtAttr(nl.IFLA_BOND_SLAVE_AD_AGGREGATOR_ID, nl.Uint16Attr(bondSlave.AggregatorId))
2229	data.AddRtAttr(nl.IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE, nl.Uint8Attr(bondSlave.AdActorOperPortState))
2230	data.AddRtAttr(nl.IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE, nl.Uint16Attr(bondSlave.AdPartnerOperPortState))
2231
2232	if mac := bondSlave.PermHardwareAddr; mac != nil {
2233		data.AddRtAttr(nl.IFLA_BOND_SLAVE_PERM_HWADDR, []byte(mac))
2234	}
2235}
2236
2237func parseBondSlaveData(slave LinkSlave, data []syscall.NetlinkRouteAttr) {
2238	bondSlave := slave.(*BondSlave)
2239	for i := range data {
2240		switch data[i].Attr.Type {
2241		case nl.IFLA_BOND_SLAVE_STATE:
2242			bondSlave.State = BondSlaveState(data[i].Value[0])
2243		case nl.IFLA_BOND_SLAVE_MII_STATUS:
2244			bondSlave.MiiStatus = BondSlaveMiiStatus(data[i].Value[0])
2245		case nl.IFLA_BOND_SLAVE_LINK_FAILURE_COUNT:
2246			bondSlave.LinkFailureCount = native.Uint32(data[i].Value[0:4])
2247		case nl.IFLA_BOND_SLAVE_PERM_HWADDR:
2248			bondSlave.PermHardwareAddr = net.HardwareAddr(data[i].Value[0:6])
2249		case nl.IFLA_BOND_SLAVE_QUEUE_ID:
2250			bondSlave.QueueId = native.Uint16(data[i].Value[0:2])
2251		case nl.IFLA_BOND_SLAVE_AD_AGGREGATOR_ID:
2252			bondSlave.AggregatorId = native.Uint16(data[i].Value[0:2])
2253		case nl.IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE:
2254			bondSlave.AdActorOperPortState = uint8(data[i].Value[0])
2255		case nl.IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE:
2256			bondSlave.AdPartnerOperPortState = native.Uint16(data[i].Value[0:2])
2257		}
2258	}
2259}
2260
2261func parseIPVlanData(link Link, data []syscall.NetlinkRouteAttr) {
2262	ipv := link.(*IPVlan)
2263	for _, datum := range data {
2264		switch datum.Attr.Type {
2265		case nl.IFLA_IPVLAN_MODE:
2266			ipv.Mode = IPVlanMode(native.Uint32(datum.Value[0:4]))
2267		case nl.IFLA_IPVLAN_FLAG:
2268			ipv.Flag = IPVlanFlag(native.Uint32(datum.Value[0:4]))
2269		}
2270	}
2271}
2272
2273func parseMacvtapData(link Link, data []syscall.NetlinkRouteAttr) {
2274	macv := link.(*Macvtap)
2275	parseMacvlanData(&macv.Macvlan, data)
2276}
2277
2278func parseMacvlanData(link Link, data []syscall.NetlinkRouteAttr) {
2279	macv := link.(*Macvlan)
2280	for _, datum := range data {
2281		switch datum.Attr.Type {
2282		case nl.IFLA_MACVLAN_MODE:
2283			switch native.Uint32(datum.Value[0:4]) {
2284			case nl.MACVLAN_MODE_PRIVATE:
2285				macv.Mode = MACVLAN_MODE_PRIVATE
2286			case nl.MACVLAN_MODE_VEPA:
2287				macv.Mode = MACVLAN_MODE_VEPA
2288			case nl.MACVLAN_MODE_BRIDGE:
2289				macv.Mode = MACVLAN_MODE_BRIDGE
2290			case nl.MACVLAN_MODE_PASSTHRU:
2291				macv.Mode = MACVLAN_MODE_PASSTHRU
2292			case nl.MACVLAN_MODE_SOURCE:
2293				macv.Mode = MACVLAN_MODE_SOURCE
2294			}
2295		case nl.IFLA_MACVLAN_MACADDR_COUNT:
2296			macv.MACAddrs = make([]net.HardwareAddr, 0, int(native.Uint32(datum.Value[0:4])))
2297		case nl.IFLA_MACVLAN_MACADDR_DATA:
2298			macs, err := nl.ParseRouteAttr(datum.Value[:])
2299			if err != nil {
2300				panic(fmt.Sprintf("failed to ParseRouteAttr for IFLA_MACVLAN_MACADDR_DATA: %v", err))
2301			}
2302			for _, macDatum := range macs {
2303				macv.MACAddrs = append(macv.MACAddrs, net.HardwareAddr(macDatum.Value[0:6]))
2304			}
2305		}
2306	}
2307}
2308
2309// copied from pkg/net_linux.go
2310func linkFlags(rawFlags uint32) net.Flags {
2311	var f net.Flags
2312	if rawFlags&unix.IFF_UP != 0 {
2313		f |= net.FlagUp
2314	}
2315	if rawFlags&unix.IFF_BROADCAST != 0 {
2316		f |= net.FlagBroadcast
2317	}
2318	if rawFlags&unix.IFF_LOOPBACK != 0 {
2319		f |= net.FlagLoopback
2320	}
2321	if rawFlags&unix.IFF_POINTOPOINT != 0 {
2322		f |= net.FlagPointToPoint
2323	}
2324	if rawFlags&unix.IFF_MULTICAST != 0 {
2325		f |= net.FlagMulticast
2326	}
2327	return f
2328}
2329
2330func addGretapAttrs(gretap *Gretap, linkInfo *nl.RtAttr) {
2331	data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil)
2332
2333	if gretap.FlowBased {
2334		// In flow based mode, no other attributes need to be configured
2335		data.AddRtAttr(nl.IFLA_GRE_COLLECT_METADATA, boolAttr(gretap.FlowBased))
2336		return
2337	}
2338
2339	if ip := gretap.Local; ip != nil {
2340		if ip.To4() != nil {
2341			ip = ip.To4()
2342		}
2343		data.AddRtAttr(nl.IFLA_GRE_LOCAL, []byte(ip))
2344	}
2345
2346	if ip := gretap.Remote; ip != nil {
2347		if ip.To4() != nil {
2348			ip = ip.To4()
2349		}
2350		data.AddRtAttr(nl.IFLA_GRE_REMOTE, []byte(ip))
2351	}
2352
2353	if gretap.IKey != 0 {
2354		data.AddRtAttr(nl.IFLA_GRE_IKEY, htonl(gretap.IKey))
2355		gretap.IFlags |= uint16(nl.GRE_KEY)
2356	}
2357
2358	if gretap.OKey != 0 {
2359		data.AddRtAttr(nl.IFLA_GRE_OKEY, htonl(gretap.OKey))
2360		gretap.OFlags |= uint16(nl.GRE_KEY)
2361	}
2362
2363	data.AddRtAttr(nl.IFLA_GRE_IFLAGS, htons(gretap.IFlags))
2364	data.AddRtAttr(nl.IFLA_GRE_OFLAGS, htons(gretap.OFlags))
2365
2366	if gretap.Link != 0 {
2367		data.AddRtAttr(nl.IFLA_GRE_LINK, nl.Uint32Attr(gretap.Link))
2368	}
2369
2370	data.AddRtAttr(nl.IFLA_GRE_PMTUDISC, nl.Uint8Attr(gretap.PMtuDisc))
2371	data.AddRtAttr(nl.IFLA_GRE_TTL, nl.Uint8Attr(gretap.Ttl))
2372	data.AddRtAttr(nl.IFLA_GRE_TOS, nl.Uint8Attr(gretap.Tos))
2373	data.AddRtAttr(nl.IFLA_GRE_ENCAP_TYPE, nl.Uint16Attr(gretap.EncapType))
2374	data.AddRtAttr(nl.IFLA_GRE_ENCAP_FLAGS, nl.Uint16Attr(gretap.EncapFlags))
2375	data.AddRtAttr(nl.IFLA_GRE_ENCAP_SPORT, htons(gretap.EncapSport))
2376	data.AddRtAttr(nl.IFLA_GRE_ENCAP_DPORT, htons(gretap.EncapDport))
2377}
2378
2379func parseGretapData(link Link, data []syscall.NetlinkRouteAttr) {
2380	gre := link.(*Gretap)
2381	for _, datum := range data {
2382		switch datum.Attr.Type {
2383		case nl.IFLA_GRE_OKEY:
2384			gre.IKey = ntohl(datum.Value[0:4])
2385		case nl.IFLA_GRE_IKEY:
2386			gre.OKey = ntohl(datum.Value[0:4])
2387		case nl.IFLA_GRE_LOCAL:
2388			gre.Local = net.IP(datum.Value)
2389		case nl.IFLA_GRE_REMOTE:
2390			gre.Remote = net.IP(datum.Value)
2391		case nl.IFLA_GRE_ENCAP_SPORT:
2392			gre.EncapSport = ntohs(datum.Value[0:2])
2393		case nl.IFLA_GRE_ENCAP_DPORT:
2394			gre.EncapDport = ntohs(datum.Value[0:2])
2395		case nl.IFLA_GRE_IFLAGS:
2396			gre.IFlags = ntohs(datum.Value[0:2])
2397		case nl.IFLA_GRE_OFLAGS:
2398			gre.OFlags = ntohs(datum.Value[0:2])
2399		case nl.IFLA_GRE_TTL:
2400			gre.Ttl = uint8(datum.Value[0])
2401		case nl.IFLA_GRE_TOS:
2402			gre.Tos = uint8(datum.Value[0])
2403		case nl.IFLA_GRE_PMTUDISC:
2404			gre.PMtuDisc = uint8(datum.Value[0])
2405		case nl.IFLA_GRE_ENCAP_TYPE:
2406			gre.EncapType = native.Uint16(datum.Value[0:2])
2407		case nl.IFLA_GRE_ENCAP_FLAGS:
2408			gre.EncapFlags = native.Uint16(datum.Value[0:2])
2409		case nl.IFLA_GRE_COLLECT_METADATA:
2410			gre.FlowBased = true
2411		}
2412	}
2413}
2414
2415func addGretunAttrs(gre *Gretun, linkInfo *nl.RtAttr) {
2416	data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil)
2417
2418	if ip := gre.Local; ip != nil {
2419		if ip.To4() != nil {
2420			ip = ip.To4()
2421		}
2422		data.AddRtAttr(nl.IFLA_GRE_LOCAL, []byte(ip))
2423	}
2424
2425	if ip := gre.Remote; ip != nil {
2426		if ip.To4() != nil {
2427			ip = ip.To4()
2428		}
2429		data.AddRtAttr(nl.IFLA_GRE_REMOTE, []byte(ip))
2430	}
2431
2432	if gre.IKey != 0 {
2433		data.AddRtAttr(nl.IFLA_GRE_IKEY, htonl(gre.IKey))
2434		gre.IFlags |= uint16(nl.GRE_KEY)
2435	}
2436
2437	if gre.OKey != 0 {
2438		data.AddRtAttr(nl.IFLA_GRE_OKEY, htonl(gre.OKey))
2439		gre.OFlags |= uint16(nl.GRE_KEY)
2440	}
2441
2442	data.AddRtAttr(nl.IFLA_GRE_IFLAGS, htons(gre.IFlags))
2443	data.AddRtAttr(nl.IFLA_GRE_OFLAGS, htons(gre.OFlags))
2444
2445	if gre.Link != 0 {
2446		data.AddRtAttr(nl.IFLA_GRE_LINK, nl.Uint32Attr(gre.Link))
2447	}
2448
2449	data.AddRtAttr(nl.IFLA_GRE_PMTUDISC, nl.Uint8Attr(gre.PMtuDisc))
2450	data.AddRtAttr(nl.IFLA_GRE_TTL, nl.Uint8Attr(gre.Ttl))
2451	data.AddRtAttr(nl.IFLA_GRE_TOS, nl.Uint8Attr(gre.Tos))
2452	data.AddRtAttr(nl.IFLA_GRE_ENCAP_TYPE, nl.Uint16Attr(gre.EncapType))
2453	data.AddRtAttr(nl.IFLA_GRE_ENCAP_FLAGS, nl.Uint16Attr(gre.EncapFlags))
2454	data.AddRtAttr(nl.IFLA_GRE_ENCAP_SPORT, htons(gre.EncapSport))
2455	data.AddRtAttr(nl.IFLA_GRE_ENCAP_DPORT, htons(gre.EncapDport))
2456}
2457
2458func parseGretunData(link Link, data []syscall.NetlinkRouteAttr) {
2459	gre := link.(*Gretun)
2460	for _, datum := range data {
2461		switch datum.Attr.Type {
2462		case nl.IFLA_GRE_IKEY:
2463			gre.IKey = ntohl(datum.Value[0:4])
2464		case nl.IFLA_GRE_OKEY:
2465			gre.OKey = ntohl(datum.Value[0:4])
2466		case nl.IFLA_GRE_LOCAL:
2467			gre.Local = net.IP(datum.Value)
2468		case nl.IFLA_GRE_REMOTE:
2469			gre.Remote = net.IP(datum.Value)
2470		case nl.IFLA_GRE_IFLAGS:
2471			gre.IFlags = ntohs(datum.Value[0:2])
2472		case nl.IFLA_GRE_OFLAGS:
2473			gre.OFlags = ntohs(datum.Value[0:2])
2474		case nl.IFLA_GRE_TTL:
2475			gre.Ttl = uint8(datum.Value[0])
2476		case nl.IFLA_GRE_TOS:
2477			gre.Tos = uint8(datum.Value[0])
2478		case nl.IFLA_GRE_PMTUDISC:
2479			gre.PMtuDisc = uint8(datum.Value[0])
2480		case nl.IFLA_GRE_ENCAP_TYPE:
2481			gre.EncapType = native.Uint16(datum.Value[0:2])
2482		case nl.IFLA_GRE_ENCAP_FLAGS:
2483			gre.EncapFlags = native.Uint16(datum.Value[0:2])
2484		case nl.IFLA_GRE_ENCAP_SPORT:
2485			gre.EncapSport = ntohs(datum.Value[0:2])
2486		case nl.IFLA_GRE_ENCAP_DPORT:
2487			gre.EncapDport = ntohs(datum.Value[0:2])
2488		}
2489	}
2490}
2491
2492func addXdpAttrs(xdp *LinkXdp, req *nl.NetlinkRequest) {
2493	attrs := nl.NewRtAttr(unix.IFLA_XDP|unix.NLA_F_NESTED, nil)
2494	b := make([]byte, 4)
2495	native.PutUint32(b, uint32(xdp.Fd))
2496	attrs.AddRtAttr(nl.IFLA_XDP_FD, b)
2497	if xdp.Flags != 0 {
2498		b := make([]byte, 4)
2499		native.PutUint32(b, xdp.Flags)
2500		attrs.AddRtAttr(nl.IFLA_XDP_FLAGS, b)
2501	}
2502	req.AddData(attrs)
2503}
2504
2505func parseLinkXdp(data []byte) (*LinkXdp, error) {
2506	attrs, err := nl.ParseRouteAttr(data)
2507	if err != nil {
2508		return nil, err
2509	}
2510	xdp := &LinkXdp{}
2511	for _, attr := range attrs {
2512		switch attr.Attr.Type {
2513		case nl.IFLA_XDP_FD:
2514			xdp.Fd = int(native.Uint32(attr.Value[0:4]))
2515		case nl.IFLA_XDP_ATTACHED:
2516			xdp.Attached = attr.Value[0] != 0
2517		case nl.IFLA_XDP_FLAGS:
2518			xdp.Flags = native.Uint32(attr.Value[0:4])
2519		case nl.IFLA_XDP_PROG_ID:
2520			xdp.ProgId = native.Uint32(attr.Value[0:4])
2521		}
2522	}
2523	return xdp, nil
2524}
2525
2526func addIptunAttrs(iptun *Iptun, linkInfo *nl.RtAttr) {
2527	if iptun.FlowBased {
2528		// In flow based mode, no other attributes need to be configured
2529		linkInfo.AddRtAttr(nl.IFLA_IPTUN_COLLECT_METADATA, boolAttr(iptun.FlowBased))
2530		return
2531	}
2532
2533	data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil)
2534
2535	ip := iptun.Local.To4()
2536	if ip != nil {
2537		data.AddRtAttr(nl.IFLA_IPTUN_LOCAL, []byte(ip))
2538	}
2539
2540	ip = iptun.Remote.To4()
2541	if ip != nil {
2542		data.AddRtAttr(nl.IFLA_IPTUN_REMOTE, []byte(ip))
2543	}
2544
2545	if iptun.Link != 0 {
2546		data.AddRtAttr(nl.IFLA_IPTUN_LINK, nl.Uint32Attr(iptun.Link))
2547	}
2548	data.AddRtAttr(nl.IFLA_IPTUN_PMTUDISC, nl.Uint8Attr(iptun.PMtuDisc))
2549	data.AddRtAttr(nl.IFLA_IPTUN_TTL, nl.Uint8Attr(iptun.Ttl))
2550	data.AddRtAttr(nl.IFLA_IPTUN_TOS, nl.Uint8Attr(iptun.Tos))
2551	data.AddRtAttr(nl.IFLA_IPTUN_ENCAP_TYPE, nl.Uint16Attr(iptun.EncapType))
2552	data.AddRtAttr(nl.IFLA_IPTUN_ENCAP_FLAGS, nl.Uint16Attr(iptun.EncapFlags))
2553	data.AddRtAttr(nl.IFLA_IPTUN_ENCAP_SPORT, htons(iptun.EncapSport))
2554	data.AddRtAttr(nl.IFLA_IPTUN_ENCAP_DPORT, htons(iptun.EncapDport))
2555}
2556
2557func parseIptunData(link Link, data []syscall.NetlinkRouteAttr) {
2558	iptun := link.(*Iptun)
2559	for _, datum := range data {
2560		switch datum.Attr.Type {
2561		case nl.IFLA_IPTUN_LOCAL:
2562			iptun.Local = net.IP(datum.Value[0:4])
2563		case nl.IFLA_IPTUN_REMOTE:
2564			iptun.Remote = net.IP(datum.Value[0:4])
2565		case nl.IFLA_IPTUN_TTL:
2566			iptun.Ttl = uint8(datum.Value[0])
2567		case nl.IFLA_IPTUN_TOS:
2568			iptun.Tos = uint8(datum.Value[0])
2569		case nl.IFLA_IPTUN_PMTUDISC:
2570			iptun.PMtuDisc = uint8(datum.Value[0])
2571		case nl.IFLA_IPTUN_ENCAP_SPORT:
2572			iptun.EncapSport = ntohs(datum.Value[0:2])
2573		case nl.IFLA_IPTUN_ENCAP_DPORT:
2574			iptun.EncapDport = ntohs(datum.Value[0:2])
2575		case nl.IFLA_IPTUN_ENCAP_TYPE:
2576			iptun.EncapType = native.Uint16(datum.Value[0:2])
2577		case nl.IFLA_IPTUN_ENCAP_FLAGS:
2578			iptun.EncapFlags = native.Uint16(datum.Value[0:2])
2579		case nl.IFLA_IPTUN_COLLECT_METADATA:
2580			iptun.FlowBased = int8(datum.Value[0]) != 0
2581		}
2582	}
2583}
2584
2585func addIp6tnlAttrs(ip6tnl *Ip6tnl, linkInfo *nl.RtAttr) {
2586	data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil)
2587
2588	if ip6tnl.Link != 0 {
2589		data.AddRtAttr(nl.IFLA_IPTUN_LINK, nl.Uint32Attr(ip6tnl.Link))
2590	}
2591
2592	ip := ip6tnl.Local.To16()
2593	if ip != nil {
2594		data.AddRtAttr(nl.IFLA_IPTUN_LOCAL, []byte(ip))
2595	}
2596
2597	ip = ip6tnl.Remote.To16()
2598	if ip != nil {
2599		data.AddRtAttr(nl.IFLA_IPTUN_REMOTE, []byte(ip))
2600	}
2601
2602	data.AddRtAttr(nl.IFLA_IPTUN_TTL, nl.Uint8Attr(ip6tnl.Ttl))
2603	data.AddRtAttr(nl.IFLA_IPTUN_TOS, nl.Uint8Attr(ip6tnl.Tos))
2604	data.AddRtAttr(nl.IFLA_IPTUN_ENCAP_LIMIT, nl.Uint8Attr(ip6tnl.EncapLimit))
2605	data.AddRtAttr(nl.IFLA_IPTUN_FLAGS, nl.Uint32Attr(ip6tnl.Flags))
2606	data.AddRtAttr(nl.IFLA_IPTUN_PROTO, nl.Uint8Attr(ip6tnl.Proto))
2607	data.AddRtAttr(nl.IFLA_IPTUN_FLOWINFO, nl.Uint32Attr(ip6tnl.FlowInfo))
2608}
2609
2610func parseIp6tnlData(link Link, data []syscall.NetlinkRouteAttr) {
2611	ip6tnl := link.(*Ip6tnl)
2612	for _, datum := range data {
2613		switch datum.Attr.Type {
2614		case nl.IFLA_IPTUN_LOCAL:
2615			ip6tnl.Local = net.IP(datum.Value[:16])
2616		case nl.IFLA_IPTUN_REMOTE:
2617			ip6tnl.Remote = net.IP(datum.Value[:16])
2618		case nl.IFLA_IPTUN_TTL:
2619			ip6tnl.Ttl = uint8(datum.Value[0])
2620		case nl.IFLA_IPTUN_TOS:
2621			ip6tnl.Tos = uint8(datum.Value[0])
2622		case nl.IFLA_IPTUN_ENCAP_LIMIT:
2623			ip6tnl.EncapLimit = uint8(datum.Value[0])
2624		case nl.IFLA_IPTUN_FLAGS:
2625			ip6tnl.Flags = native.Uint32(datum.Value[:4])
2626		case nl.IFLA_IPTUN_PROTO:
2627			ip6tnl.Proto = uint8(datum.Value[0])
2628		case nl.IFLA_IPTUN_FLOWINFO:
2629			ip6tnl.FlowInfo = native.Uint32(datum.Value[:4])
2630		}
2631	}
2632}
2633
2634func addSittunAttrs(sittun *Sittun, linkInfo *nl.RtAttr) {
2635	data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil)
2636
2637	if sittun.Link != 0 {
2638		data.AddRtAttr(nl.IFLA_IPTUN_LINK, nl.Uint32Attr(sittun.Link))
2639	}
2640
2641	ip := sittun.Local.To4()
2642	if ip != nil {
2643		data.AddRtAttr(nl.IFLA_IPTUN_LOCAL, []byte(ip))
2644	}
2645
2646	ip = sittun.Remote.To4()
2647	if ip != nil {
2648		data.AddRtAttr(nl.IFLA_IPTUN_REMOTE, []byte(ip))
2649	}
2650
2651	if sittun.Ttl > 0 {
2652		// Would otherwise fail on 3.10 kernel
2653		data.AddRtAttr(nl.IFLA_IPTUN_TTL, nl.Uint8Attr(sittun.Ttl))
2654	}
2655
2656	data.AddRtAttr(nl.IFLA_IPTUN_TOS, nl.Uint8Attr(sittun.Tos))
2657	data.AddRtAttr(nl.IFLA_IPTUN_PMTUDISC, nl.Uint8Attr(sittun.PMtuDisc))
2658	data.AddRtAttr(nl.IFLA_IPTUN_ENCAP_TYPE, nl.Uint16Attr(sittun.EncapType))
2659	data.AddRtAttr(nl.IFLA_IPTUN_ENCAP_FLAGS, nl.Uint16Attr(sittun.EncapFlags))
2660	data.AddRtAttr(nl.IFLA_IPTUN_ENCAP_SPORT, htons(sittun.EncapSport))
2661	data.AddRtAttr(nl.IFLA_IPTUN_ENCAP_DPORT, htons(sittun.EncapDport))
2662}
2663
2664func parseSittunData(link Link, data []syscall.NetlinkRouteAttr) {
2665	sittun := link.(*Sittun)
2666	for _, datum := range data {
2667		switch datum.Attr.Type {
2668		case nl.IFLA_IPTUN_LOCAL:
2669			sittun.Local = net.IP(datum.Value[0:4])
2670		case nl.IFLA_IPTUN_REMOTE:
2671			sittun.Remote = net.IP(datum.Value[0:4])
2672		case nl.IFLA_IPTUN_TTL:
2673			sittun.Ttl = uint8(datum.Value[0])
2674		case nl.IFLA_IPTUN_TOS:
2675			sittun.Tos = uint8(datum.Value[0])
2676		case nl.IFLA_IPTUN_PMTUDISC:
2677			sittun.PMtuDisc = uint8(datum.Value[0])
2678		case nl.IFLA_IPTUN_ENCAP_TYPE:
2679			sittun.EncapType = native.Uint16(datum.Value[0:2])
2680		case nl.IFLA_IPTUN_ENCAP_FLAGS:
2681			sittun.EncapFlags = native.Uint16(datum.Value[0:2])
2682		case nl.IFLA_IPTUN_ENCAP_SPORT:
2683			sittun.EncapSport = ntohs(datum.Value[0:2])
2684		case nl.IFLA_IPTUN_ENCAP_DPORT:
2685			sittun.EncapDport = ntohs(datum.Value[0:2])
2686		}
2687	}
2688}
2689
2690func addVtiAttrs(vti *Vti, linkInfo *nl.RtAttr) {
2691	data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil)
2692
2693	family := FAMILY_V4
2694	if vti.Local.To4() == nil {
2695		family = FAMILY_V6
2696	}
2697
2698	var ip net.IP
2699
2700	if family == FAMILY_V4 {
2701		ip = vti.Local.To4()
2702	} else {
2703		ip = vti.Local
2704	}
2705	if ip != nil {
2706		data.AddRtAttr(nl.IFLA_VTI_LOCAL, []byte(ip))
2707	}
2708
2709	if family == FAMILY_V4 {
2710		ip = vti.Remote.To4()
2711	} else {
2712		ip = vti.Remote
2713	}
2714	if ip != nil {
2715		data.AddRtAttr(nl.IFLA_VTI_REMOTE, []byte(ip))
2716	}
2717
2718	if vti.Link != 0 {
2719		data.AddRtAttr(nl.IFLA_VTI_LINK, nl.Uint32Attr(vti.Link))
2720	}
2721
2722	data.AddRtAttr(nl.IFLA_VTI_IKEY, htonl(vti.IKey))
2723	data.AddRtAttr(nl.IFLA_VTI_OKEY, htonl(vti.OKey))
2724}
2725
2726func parseVtiData(link Link, data []syscall.NetlinkRouteAttr) {
2727	vti := link.(*Vti)
2728	for _, datum := range data {
2729		switch datum.Attr.Type {
2730		case nl.IFLA_VTI_LOCAL:
2731			vti.Local = net.IP(datum.Value)
2732		case nl.IFLA_VTI_REMOTE:
2733			vti.Remote = net.IP(datum.Value)
2734		case nl.IFLA_VTI_IKEY:
2735			vti.IKey = ntohl(datum.Value[0:4])
2736		case nl.IFLA_VTI_OKEY:
2737			vti.OKey = ntohl(datum.Value[0:4])
2738		}
2739	}
2740}
2741
2742func addVrfAttrs(vrf *Vrf, linkInfo *nl.RtAttr) {
2743	data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil)
2744	b := make([]byte, 4)
2745	native.PutUint32(b, uint32(vrf.Table))
2746	data.AddRtAttr(nl.IFLA_VRF_TABLE, b)
2747}
2748
2749func parseVrfData(link Link, data []syscall.NetlinkRouteAttr) {
2750	vrf := link.(*Vrf)
2751	for _, datum := range data {
2752		switch datum.Attr.Type {
2753		case nl.IFLA_VRF_TABLE:
2754			vrf.Table = native.Uint32(datum.Value[0:4])
2755		}
2756	}
2757}
2758
2759func addBridgeAttrs(bridge *Bridge, linkInfo *nl.RtAttr) {
2760	data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil)
2761	if bridge.MulticastSnooping != nil {
2762		data.AddRtAttr(nl.IFLA_BR_MCAST_SNOOPING, boolToByte(*bridge.MulticastSnooping))
2763	}
2764	if bridge.HelloTime != nil {
2765		data.AddRtAttr(nl.IFLA_BR_HELLO_TIME, nl.Uint32Attr(*bridge.HelloTime))
2766	}
2767	if bridge.VlanFiltering != nil {
2768		data.AddRtAttr(nl.IFLA_BR_VLAN_FILTERING, boolToByte(*bridge.VlanFiltering))
2769	}
2770}
2771
2772func parseBridgeData(bridge Link, data []syscall.NetlinkRouteAttr) {
2773	br := bridge.(*Bridge)
2774	for _, datum := range data {
2775		switch datum.Attr.Type {
2776		case nl.IFLA_BR_HELLO_TIME:
2777			helloTime := native.Uint32(datum.Value[0:4])
2778			br.HelloTime = &helloTime
2779		case nl.IFLA_BR_MCAST_SNOOPING:
2780			mcastSnooping := datum.Value[0] == 1
2781			br.MulticastSnooping = &mcastSnooping
2782		case nl.IFLA_BR_VLAN_FILTERING:
2783			vlanFiltering := datum.Value[0] == 1
2784			br.VlanFiltering = &vlanFiltering
2785		}
2786	}
2787}
2788
2789func addGTPAttrs(gtp *GTP, linkInfo *nl.RtAttr) {
2790	data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil)
2791	data.AddRtAttr(nl.IFLA_GTP_FD0, nl.Uint32Attr(uint32(gtp.FD0)))
2792	data.AddRtAttr(nl.IFLA_GTP_FD1, nl.Uint32Attr(uint32(gtp.FD1)))
2793	data.AddRtAttr(nl.IFLA_GTP_PDP_HASHSIZE, nl.Uint32Attr(131072))
2794	if gtp.Role != nl.GTP_ROLE_GGSN {
2795		data.AddRtAttr(nl.IFLA_GTP_ROLE, nl.Uint32Attr(uint32(gtp.Role)))
2796	}
2797}
2798
2799func parseGTPData(link Link, data []syscall.NetlinkRouteAttr) {
2800	gtp := link.(*GTP)
2801	for _, datum := range data {
2802		switch datum.Attr.Type {
2803		case nl.IFLA_GTP_FD0:
2804			gtp.FD0 = int(native.Uint32(datum.Value))
2805		case nl.IFLA_GTP_FD1:
2806			gtp.FD1 = int(native.Uint32(datum.Value))
2807		case nl.IFLA_GTP_PDP_HASHSIZE:
2808			gtp.PDPHashsize = int(native.Uint32(datum.Value))
2809		case nl.IFLA_GTP_ROLE:
2810			gtp.Role = int(native.Uint32(datum.Value))
2811		}
2812	}
2813}
2814
2815func parseVfInfoList(data []syscall.NetlinkRouteAttr) ([]VfInfo, error) {
2816	var vfs []VfInfo
2817
2818	for i, element := range data {
2819		if element.Attr.Type != nl.IFLA_VF_INFO {
2820			return nil, fmt.Errorf("Incorrect element type in vf info list: %d", element.Attr.Type)
2821		}
2822		vfAttrs, err := nl.ParseRouteAttr(element.Value)
2823		if err != nil {
2824			return nil, err
2825		}
2826		vfs = append(vfs, parseVfInfo(vfAttrs, i))
2827	}
2828	return vfs, nil
2829}
2830
2831func parseVfInfo(data []syscall.NetlinkRouteAttr, id int) VfInfo {
2832	vf := VfInfo{ID: id}
2833	for _, element := range data {
2834		switch element.Attr.Type {
2835		case nl.IFLA_VF_MAC:
2836			mac := nl.DeserializeVfMac(element.Value[:])
2837			vf.Mac = mac.Mac[:6]
2838		case nl.IFLA_VF_VLAN:
2839			vl := nl.DeserializeVfVlan(element.Value[:])
2840			vf.Vlan = int(vl.Vlan)
2841			vf.Qos = int(vl.Qos)
2842		case nl.IFLA_VF_TX_RATE:
2843			txr := nl.DeserializeVfTxRate(element.Value[:])
2844			vf.TxRate = int(txr.Rate)
2845		case nl.IFLA_VF_SPOOFCHK:
2846			sp := nl.DeserializeVfSpoofchk(element.Value[:])
2847			vf.Spoofchk = sp.Setting != 0
2848		case nl.IFLA_VF_LINK_STATE:
2849			ls := nl.DeserializeVfLinkState(element.Value[:])
2850			vf.LinkState = ls.LinkState
2851		case nl.IFLA_VF_RATE:
2852			vfr := nl.DeserializeVfRate(element.Value[:])
2853			vf.MaxTxRate = vfr.MaxTxRate
2854			vf.MinTxRate = vfr.MinTxRate
2855		}
2856	}
2857	return vf
2858}
2859
2860func addXfrmiAttrs(xfrmi *Xfrmi, linkInfo *nl.RtAttr) {
2861	data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil)
2862	data.AddRtAttr(nl.IFLA_XFRM_LINK, nl.Uint32Attr(uint32(xfrmi.ParentIndex)))
2863	data.AddRtAttr(nl.IFLA_XFRM_IF_ID, nl.Uint32Attr(xfrmi.Ifid))
2864
2865}
2866
2867func parseXfrmiData(link Link, data []syscall.NetlinkRouteAttr) {
2868	xfrmi := link.(*Xfrmi)
2869	for _, datum := range data {
2870		switch datum.Attr.Type {
2871		case nl.IFLA_XFRM_LINK:
2872			xfrmi.ParentIndex = int(native.Uint32(datum.Value))
2873		case nl.IFLA_XFRM_IF_ID:
2874			xfrmi.Ifid = native.Uint32(datum.Value)
2875		}
2876	}
2877}
2878
2879// LinkSetBondSlave add slave to bond link via ioctl interface.
2880func LinkSetBondSlave(link Link, master *Bond) error {
2881	fd, err := getSocketUDP()
2882	if err != nil {
2883		return err
2884	}
2885	defer syscall.Close(fd)
2886
2887	ifreq := newIocltSlaveReq(link.Attrs().Name, master.Attrs().Name)
2888
2889	_, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), unix.SIOCBONDENSLAVE, uintptr(unsafe.Pointer(ifreq)))
2890	if errno != 0 {
2891		return fmt.Errorf("Failed to enslave %q to %q, errno=%v", link.Attrs().Name, master.Attrs().Name, errno)
2892	}
2893	return nil
2894}
2895
2896// LinkSetBondSlaveQueueId modify bond slave queue-id.
2897func (h *Handle) LinkSetBondSlaveQueueId(link Link, queueId uint16) error {
2898	base := link.Attrs()
2899	h.ensureIndex(base)
2900	req := h.newNetlinkRequest(unix.RTM_SETLINK, unix.NLM_F_ACK)
2901
2902	msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
2903	msg.Index = int32(base.Index)
2904	req.AddData(msg)
2905
2906	linkInfo := nl.NewRtAttr(unix.IFLA_LINKINFO, nil)
2907	data := linkInfo.AddRtAttr(nl.IFLA_INFO_SLAVE_DATA, nil)
2908	data.AddRtAttr(nl.IFLA_BOND_SLAVE_QUEUE_ID, nl.Uint16Attr(queueId))
2909
2910	req.AddData(linkInfo)
2911	_, err := req.Execute(unix.NETLINK_ROUTE, 0)
2912	return err
2913}
2914
2915// LinkSetBondSlaveQueueId modify bond slave queue-id.
2916func LinkSetBondSlaveQueueId(link Link, queueId uint16) error {
2917	return pkgHandle.LinkSetBondSlaveQueueId(link, queueId)
2918}
2919
2920func vethStatsSerialize(stats ethtoolStats) ([]byte, error) {
2921	statsSize := int(unsafe.Sizeof(stats)) + int(stats.nStats)*int(unsafe.Sizeof(uint64(0)))
2922	b := make([]byte, 0, statsSize)
2923	buf := bytes.NewBuffer(b)
2924	err := binary.Write(buf, nl.NativeEndian(), stats)
2925	return buf.Bytes()[:statsSize], err
2926}
2927
2928type vethEthtoolStats struct {
2929	Cmd    uint32
2930	NStats uint32
2931	Peer   uint64
2932	// Newer kernels have XDP stats in here, but we only care
2933	// to extract the peer ifindex here.
2934}
2935
2936func vethStatsDeserialize(b []byte) (vethEthtoolStats, error) {
2937	var stats = vethEthtoolStats{}
2938	err := binary.Read(bytes.NewReader(b), nl.NativeEndian(), &stats)
2939	return stats, err
2940}
2941
2942// VethPeerIndex get veth peer index.
2943func VethPeerIndex(link *Veth) (int, error) {
2944	fd, err := getSocketUDP()
2945	if err != nil {
2946		return -1, err
2947	}
2948	defer syscall.Close(fd)
2949
2950	ifreq, sSet := newIocltStringSetReq(link.Name)
2951	_, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), SIOCETHTOOL, uintptr(unsafe.Pointer(ifreq)))
2952	if errno != 0 {
2953		return -1, fmt.Errorf("SIOCETHTOOL request for %q failed, errno=%v", link.Attrs().Name, errno)
2954	}
2955
2956	stats := ethtoolStats{
2957		cmd:    ETHTOOL_GSTATS,
2958		nStats: sSet.data[0],
2959	}
2960
2961	buffer, err := vethStatsSerialize(stats)
2962	if err != nil {
2963		return -1, err
2964	}
2965
2966	ifreq.Data = uintptr(unsafe.Pointer(&buffer[0]))
2967	_, _, errno = syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), SIOCETHTOOL, uintptr(unsafe.Pointer(ifreq)))
2968	if errno != 0 {
2969		return -1, fmt.Errorf("SIOCETHTOOL request for %q failed, errno=%v", link.Attrs().Name, errno)
2970	}
2971
2972	vstats, err := vethStatsDeserialize(buffer)
2973	if err != nil {
2974		return -1, err
2975	}
2976
2977	return int(vstats.Peer), nil
2978}
2979
2980func parseTuntapData(link Link, data []syscall.NetlinkRouteAttr) {
2981	tuntap := link.(*Tuntap)
2982	for _, datum := range data {
2983		switch datum.Attr.Type {
2984		case nl.IFLA_TUN_OWNER:
2985			tuntap.Owner = native.Uint32(datum.Value)
2986		case nl.IFLA_TUN_GROUP:
2987			tuntap.Group = native.Uint32(datum.Value)
2988		case nl.IFLA_TUN_TYPE:
2989			tuntap.Mode = TuntapMode(uint8(datum.Value[0]))
2990		case nl.IFLA_TUN_PERSIST:
2991			tuntap.NonPersist = false
2992			if uint8(datum.Value[0]) == 0 {
2993				tuntap.NonPersist = true
2994			}
2995		}
2996	}
2997}
2998
2999func parseIPoIBData(link Link, data []syscall.NetlinkRouteAttr) {
3000	ipoib := link.(*IPoIB)
3001	for _, datum := range data {
3002		switch datum.Attr.Type {
3003		case nl.IFLA_IPOIB_PKEY:
3004			ipoib.Pkey = uint16(native.Uint16(datum.Value))
3005		case nl.IFLA_IPOIB_MODE:
3006			ipoib.Mode = IPoIBMode(native.Uint16(datum.Value))
3007		case nl.IFLA_IPOIB_UMCAST:
3008			ipoib.Umcast = uint16(native.Uint16(datum.Value))
3009		}
3010	}
3011}
3012
3013func addIPoIBAttrs(ipoib *IPoIB, linkInfo *nl.RtAttr) {
3014	data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil)
3015	data.AddRtAttr(nl.IFLA_IPOIB_PKEY, nl.Uint16Attr(uint16(ipoib.Pkey)))
3016	data.AddRtAttr(nl.IFLA_IPOIB_MODE, nl.Uint16Attr(uint16(ipoib.Mode)))
3017	data.AddRtAttr(nl.IFLA_IPOIB_UMCAST, nl.Uint16Attr(uint16(ipoib.Umcast)))
3018}
3019