github.com/sagernet/netlink@v0.0.0-20240612041022-b9a21c07ac6a/link_linux.go (about)

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