github.com/vishvananda/netlink@v1.3.1/link_linux.go (about)

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