mirror of https://github.com/vishvananda/netlink
Two new functions: LinkSetBondSlave and VethPeerIndex
This commit is contained in:
parent
f67b75edbf
commit
54ad9e3a4c
|
@ -0,0 +1,98 @@
|
||||||
|
package netlink
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ioctl for statistics.
|
||||||
|
const (
|
||||||
|
// ETHTOOL_GSSET_INFO gets string set info
|
||||||
|
ETHTOOL_GSSET_INFO = 0x00000037
|
||||||
|
// SIOCETHTOOL is Ethtool interface
|
||||||
|
SIOCETHTOOL = 0x8946
|
||||||
|
// ETHTOOL_GSTRINGS gets specified string set
|
||||||
|
ETHTOOL_GSTRINGS = 0x0000001b
|
||||||
|
// ETHTOOL_GSTATS gets NIC-specific statistics
|
||||||
|
ETHTOOL_GSTATS = 0x0000001d
|
||||||
|
)
|
||||||
|
|
||||||
|
// string set id.
|
||||||
|
const (
|
||||||
|
// ETH_SS_TEST is self-test result names, for use with %ETHTOOL_TEST
|
||||||
|
ETH_SS_TEST = iota
|
||||||
|
// ETH_SS_STATS statistic names, for use with %ETHTOOL_GSTATS
|
||||||
|
ETH_SS_STATS
|
||||||
|
// ETH_SS_PRIV_FLAGS are driver private flag names
|
||||||
|
ETH_SS_PRIV_FLAGS
|
||||||
|
// _ETH_SS_NTUPLE_FILTERS is deprecated
|
||||||
|
_ETH_SS_NTUPLE_FILTERS
|
||||||
|
// ETH_SS_FEATURES are device feature names
|
||||||
|
ETH_SS_FEATURES
|
||||||
|
// ETH_SS_RSS_HASH_FUNCS is RSS hush function names
|
||||||
|
ETH_SS_RSS_HASH_FUNCS
|
||||||
|
)
|
||||||
|
|
||||||
|
// IfreqSlave is a struct for ioctl bond manipulation syscalls.
|
||||||
|
// It is used to assign slave to bond interface with Name.
|
||||||
|
type IfreqSlave struct {
|
||||||
|
Name [unix.IFNAMSIZ]byte
|
||||||
|
Slave [unix.IFNAMSIZ]byte
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ifreq is a struct for ioctl ethernet manipulation syscalls.
|
||||||
|
type Ifreq struct {
|
||||||
|
Name [unix.IFNAMSIZ]byte
|
||||||
|
Data uintptr
|
||||||
|
}
|
||||||
|
|
||||||
|
// ethtoolSset is a string set information
|
||||||
|
type ethtoolSset struct {
|
||||||
|
cmd uint32
|
||||||
|
reserved uint32
|
||||||
|
mask uint64
|
||||||
|
data [1]uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
// ethtoolGstrings is string set for data tagging
|
||||||
|
type ethtoolGstrings struct {
|
||||||
|
cmd uint32
|
||||||
|
stringSet uint32
|
||||||
|
length uint32
|
||||||
|
data [32]byte
|
||||||
|
}
|
||||||
|
|
||||||
|
type ethtoolStats struct {
|
||||||
|
cmd uint32
|
||||||
|
nStats uint32
|
||||||
|
data [1]uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
// newIocltSlaveReq returns filled IfreqSlave with proper interface names
|
||||||
|
// It is used by ioctl to assign slave to bond master
|
||||||
|
func newIocltSlaveReq(slave, master string) *IfreqSlave {
|
||||||
|
ifreq := &IfreqSlave{}
|
||||||
|
copy(ifreq.Name[:unix.IFNAMSIZ-1], master)
|
||||||
|
copy(ifreq.Slave[:unix.IFNAMSIZ-1], slave)
|
||||||
|
return ifreq
|
||||||
|
}
|
||||||
|
|
||||||
|
// newIocltStringSetReq creates request to get interface string set
|
||||||
|
func newIocltStringSetReq(linkName string) (*Ifreq, *ethtoolSset) {
|
||||||
|
e := ðtoolSset{
|
||||||
|
cmd: ETHTOOL_GSSET_INFO,
|
||||||
|
mask: 1 << ETH_SS_STATS,
|
||||||
|
}
|
||||||
|
|
||||||
|
ifreq := &Ifreq{Data: uintptr(unsafe.Pointer(e))}
|
||||||
|
copy(ifreq.Name[:unix.IFNAMSIZ-1], linkName)
|
||||||
|
return ifreq, e
|
||||||
|
}
|
||||||
|
|
||||||
|
// getSocketUDP returns file descriptor to new UDP socket
|
||||||
|
// It is used for communication with ioctl interface.
|
||||||
|
func getSocketUDP() (int, error) {
|
||||||
|
return syscall.Socket(unix.AF_INET, unix.SOCK_DGRAM, 0)
|
||||||
|
}
|
|
@ -2256,3 +2256,57 @@ func parseGTPData(link Link, data []syscall.NetlinkRouteAttr) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LinkSetBondSlave add slave to bond link via ioctl interface.
|
||||||
|
func LinkSetBondSlave(link Link, master *Bond) error {
|
||||||
|
fd, err := getSocketUDP()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer syscall.Close(fd)
|
||||||
|
|
||||||
|
ifreq := newIocltSlaveReq(link.Attrs().Name, master.Attrs().Name)
|
||||||
|
|
||||||
|
_, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), unix.SIOCBONDENSLAVE, uintptr(unsafe.Pointer(ifreq)))
|
||||||
|
if errno != 0 {
|
||||||
|
return fmt.Errorf("Failed to enslave %q to %q, errno=%v", link.Attrs().Name, master.Attrs().Name, errno)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// VethPeerIndex get veth peer index.
|
||||||
|
func VethPeerIndex(link *Veth) (int, error) {
|
||||||
|
fd, err := getSocketUDP()
|
||||||
|
if err != nil {
|
||||||
|
return -1, err
|
||||||
|
}
|
||||||
|
defer syscall.Close(fd)
|
||||||
|
|
||||||
|
ifreq, sSet := newIocltStringSetReq(link.Name)
|
||||||
|
_, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), SIOCETHTOOL, uintptr(unsafe.Pointer(ifreq)))
|
||||||
|
if errno != 0 {
|
||||||
|
return -1, fmt.Errorf("SIOCETHTOOL request for %q failed, errno=%v", link.Attrs().Name, errno)
|
||||||
|
}
|
||||||
|
|
||||||
|
gstrings := ðtoolGstrings{
|
||||||
|
cmd: ETHTOOL_GSTRINGS,
|
||||||
|
stringSet: ETH_SS_STATS,
|
||||||
|
length: sSet.data[0],
|
||||||
|
}
|
||||||
|
ifreq.Data = uintptr(unsafe.Pointer(gstrings))
|
||||||
|
_, _, errno = syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), SIOCETHTOOL, uintptr(unsafe.Pointer(ifreq)))
|
||||||
|
if errno != 0 {
|
||||||
|
return -1, fmt.Errorf("SIOCETHTOOL request for %q failed, errno=%v", link.Attrs().Name, errno)
|
||||||
|
}
|
||||||
|
|
||||||
|
stats := ðtoolStats{
|
||||||
|
cmd: ETHTOOL_GSTATS,
|
||||||
|
nStats: gstrings.length,
|
||||||
|
}
|
||||||
|
ifreq.Data = uintptr(unsafe.Pointer(stats))
|
||||||
|
_, _, errno = syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), SIOCETHTOOL, uintptr(unsafe.Pointer(ifreq)))
|
||||||
|
if errno != 0 {
|
||||||
|
return -1, fmt.Errorf("SIOCETHTOOL request for %q failed, errno=%v", link.Attrs().Name, errno)
|
||||||
|
}
|
||||||
|
return int(stats.data[0]), nil
|
||||||
|
}
|
||||||
|
|
127
link_test.go
127
link_test.go
|
@ -1544,3 +1544,130 @@ func TestLinkAddDelTuntapMq(t *testing.T) {
|
||||||
Queues: 4,
|
Queues: 4,
|
||||||
Flags: TUNTAP_MULTI_QUEUE_DEFAULTS | TUNTAP_VNET_HDR})
|
Flags: TUNTAP_MULTI_QUEUE_DEFAULTS | TUNTAP_VNET_HDR})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestVethPeerIndex(t *testing.T) {
|
||||||
|
tearDown := setUpNetlinkTest(t)
|
||||||
|
defer tearDown()
|
||||||
|
|
||||||
|
const (
|
||||||
|
vethPeer1 = "vethOne"
|
||||||
|
vethPeer2 = "vethTwo"
|
||||||
|
)
|
||||||
|
|
||||||
|
link := &Veth{
|
||||||
|
LinkAttrs: LinkAttrs{
|
||||||
|
Name: vethPeer1,
|
||||||
|
MTU: 1500,
|
||||||
|
Flags: net.FlagUp,
|
||||||
|
},
|
||||||
|
PeerName: vethPeer2,
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := LinkAdd(link); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
linkOne, err := LinkByName("vethOne")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
linkTwo, err := LinkByName("vethTwo")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
peerIndexOne, err := VethPeerIndex(&Veth{LinkAttrs: *linkOne.Attrs()})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
peerIndexTwo, err := VethPeerIndex(&Veth{LinkAttrs: *linkTwo.Attrs()})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if peerIndexOne != linkTwo.Attrs().Index {
|
||||||
|
t.Errorf("VethPeerIndex(%s) mismatch %d != %d", linkOne.Attrs().Name, peerIndexOne, linkTwo.Attrs().Index)
|
||||||
|
}
|
||||||
|
|
||||||
|
if peerIndexTwo != linkOne.Attrs().Index {
|
||||||
|
t.Errorf("VethPeerIndex(%s) mismatch %d != %d", linkTwo.Attrs().Name, peerIndexTwo, linkOne.Attrs().Index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLinkSetBondSlave(t *testing.T) {
|
||||||
|
minKernelRequired(t, 3, 13)
|
||||||
|
|
||||||
|
tearDown := setUpNetlinkTest(t)
|
||||||
|
defer tearDown()
|
||||||
|
|
||||||
|
const (
|
||||||
|
bondName = "foo"
|
||||||
|
slaveOneName = "fooFoo"
|
||||||
|
slaveTwoName = "fooBar"
|
||||||
|
)
|
||||||
|
|
||||||
|
bond := NewLinkBond(LinkAttrs{Name: bondName})
|
||||||
|
bond.Mode = StringToBondModeMap["802.3ad"]
|
||||||
|
bond.AdSelect = BondAdSelect(BOND_AD_SELECT_BANDWIDTH)
|
||||||
|
bond.AdActorSysPrio = 1
|
||||||
|
bond.AdUserPortKey = 1
|
||||||
|
bond.AdActorSystem, _ = net.ParseMAC("06:aa:bb:cc:dd:ee")
|
||||||
|
|
||||||
|
if err := LinkAdd(bond); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
bondLink, err := LinkByName(bondName)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer LinkDel(bondLink)
|
||||||
|
|
||||||
|
if err := LinkAdd(&Dummy{LinkAttrs{Name: slaveOneName}}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
slaveOneLink, err := LinkByName(slaveOneName)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer LinkDel(slaveOneLink)
|
||||||
|
|
||||||
|
if err := LinkAdd(&Dummy{LinkAttrs{Name: slaveTwoName}}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
slaveTwoLink, err := LinkByName(slaveTwoName)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer LinkDel(slaveTwoLink)
|
||||||
|
|
||||||
|
if err := LinkSetBondSlave(slaveOneLink, &Bond{LinkAttrs: *bondLink.Attrs()}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := LinkSetBondSlave(slaveTwoLink, &Bond{LinkAttrs: *bondLink.Attrs()}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update info about interfaces
|
||||||
|
slaveOneLink, err = LinkByName(slaveOneName)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
slaveTwoLink, err = LinkByName(slaveTwoName)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if slaveOneLink.Attrs().MasterIndex != bondLink.Attrs().Index {
|
||||||
|
t.Errorf("For %s expected %s to be master", slaveOneLink.Attrs().Name, bondLink.Attrs().Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
if slaveTwoLink.Attrs().MasterIndex != bondLink.Attrs().Index {
|
||||||
|
t.Errorf("For %s expected %s to be master", slaveTwoLink.Attrs().Name, bondLink.Attrs().Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue