Skip to content

Commit

Permalink
Add bond slave information
Browse files Browse the repository at this point in the history
This PR refers to PR@lebauce and add some changes.
- Added some tests to retrieve bond slave information.
- Link.BondSlave is changed to LinkSlave interface.
- BondSlaveState.String() returns UPPER case. (same as iproute2)
- BondSlaveMiiStatus.String() returns UPPER case. (same as iproute2)
  • Loading branch information
Takushi Fujiwara authored and aboch committed Sep 16, 2019
1 parent e906d22 commit 205a160
Show file tree
Hide file tree
Showing 4 changed files with 234 additions and 5 deletions.
68 changes: 68 additions & 0 deletions link.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"
"net"
"os"
"strconv"
)

// Link represents a link device from netlink. Shared link attributes
Expand Down Expand Up @@ -45,6 +46,12 @@ type LinkAttrs struct {
GSOMaxSegs uint32
Vfs []VfInfo // virtual functions available on link
Group uint32
Slave LinkSlave
}

// LinkSlave represents a slave device.
type LinkSlave interface {
SlaveType() string
}

// VfInfo represents configuration of virtual function
Expand Down Expand Up @@ -749,6 +756,67 @@ func (bond *Bond) Type() string {
return "bond"
}

// BondSlaveState represents the values of the IFLA_BOND_SLAVE_STATE bond slave
// attribute, which contains the state of the bond slave.
type BondSlaveState uint8

const (
BondStateActive = iota // Link is active.
BondStateBackup // Link is backup.
)

func (s BondSlaveState) String() string {
switch s {
case BondStateActive:
return "ACTIVE"
case BondStateBackup:
return "BACKUP"
default:
return strconv.Itoa(int(s))
}
}

// BondSlaveState represents the values of the IFLA_BOND_SLAVE_MII_STATUS bond slave
// attribute, which contains the status of MII link monitoring
type BondSlaveMiiStatus uint8

const (
BondLinkUp = iota // link is up and running.
BondLinkFail // link has just gone down.
BondLinkDown // link has been down for too long time.
BondLinkBack // link is going back.
)

func (s BondSlaveMiiStatus) String() string {
switch s {
case BondLinkUp:
return "UP"
case BondLinkFail:
return "GOING_DOWN"
case BondLinkDown:
return "DOWN"
case BondLinkBack:
return "GOING_BACK"
default:
return strconv.Itoa(int(s))
}
}

type BondSlave struct {
State BondSlaveState
MiiStatus BondSlaveMiiStatus
LinkFailureCount uint32
PermHardwareAddr net.HardwareAddr
QueueId uint16
AggregatorId uint16
AdActorOperPortState uint8
AdPartnerOperPortState uint16
}

func (b *BondSlave) SlaveType() string {
return "bond"
}

// Gretap devices must specify LocalIP and RemoteIP on create
type Gretap struct {
LinkAttrs
Expand Down
90 changes: 86 additions & 4 deletions link_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -1476,10 +1476,12 @@ func LinkDeserialize(hdr *unix.NlMsghdr, m []byte) (Link, error) {
base.Promisc = 1
}
var (
link Link
stats32 []byte
stats64 []byte
linkType string
link Link
stats32 []byte
stats64 []byte
linkType string
linkSlave LinkSlave
slaveType string
)
for _, attr := range attrs {
switch attr.Attr.Type {
Expand Down Expand Up @@ -1585,6 +1587,21 @@ func LinkDeserialize(hdr *unix.NlMsghdr, m []byte) (Link, error) {
case "ipoib":
parseIPoIBData(link, data)
}
case nl.IFLA_INFO_SLAVE_KIND:
slaveType = string(info.Value[:len(info.Value)-1])
switch slaveType {
case "bond":
linkSlave = &BondSlave{}
}
case nl.IFLA_INFO_SLAVE_DATA:
switch slaveType {
case "bond":
data, err := nl.ParseRouteAttr(info.Value)
if err != nil {
return nil, err
}
parseBondSlaveData(linkSlave, data)
}
}
}
case unix.IFLA_ADDRESS:
Expand Down Expand Up @@ -1667,6 +1684,7 @@ func LinkDeserialize(hdr *unix.NlMsghdr, m []byte) (Link, error) {
link = &Device{}
}
*link.Attrs() = base
link.Attrs().Slave = linkSlave

// If the tuntap attributes are not updated by netlink due to
// an older driver, use sysfs
Expand Down Expand Up @@ -2131,6 +2149,46 @@ func parseBondData(link Link, data []syscall.NetlinkRouteAttr) {
}
}

func addBondSlaveAttrs(bondSlave *BondSlave, linkInfo *nl.RtAttr) {
data := linkInfo.AddRtAttr(nl.IFLA_INFO_SLAVE_DATA, nil)

data.AddRtAttr(nl.IFLA_BOND_SLAVE_STATE, nl.Uint8Attr(uint8(bondSlave.State)))
data.AddRtAttr(nl.IFLA_BOND_SLAVE_MII_STATUS, nl.Uint8Attr(uint8(bondSlave.MiiStatus)))
data.AddRtAttr(nl.IFLA_BOND_SLAVE_LINK_FAILURE_COUNT, nl.Uint32Attr(bondSlave.LinkFailureCount))
data.AddRtAttr(nl.IFLA_BOND_SLAVE_QUEUE_ID, nl.Uint16Attr(bondSlave.QueueId))
data.AddRtAttr(nl.IFLA_BOND_SLAVE_AD_AGGREGATOR_ID, nl.Uint16Attr(bondSlave.AggregatorId))
data.AddRtAttr(nl.IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE, nl.Uint8Attr(bondSlave.AdActorOperPortState))
data.AddRtAttr(nl.IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE, nl.Uint16Attr(bondSlave.AdPartnerOperPortState))

if mac := bondSlave.PermHardwareAddr; mac != nil {
data.AddRtAttr(nl.IFLA_BOND_SLAVE_PERM_HWADDR, []byte(mac))
}
}

func parseBondSlaveData(slave LinkSlave, data []syscall.NetlinkRouteAttr) {
bondSlave := slave.(*BondSlave)
for i := range data {
switch data[i].Attr.Type {
case nl.IFLA_BOND_SLAVE_STATE:
bondSlave.State = BondSlaveState(data[i].Value[0])
case nl.IFLA_BOND_SLAVE_MII_STATUS:
bondSlave.MiiStatus = BondSlaveMiiStatus(data[i].Value[0])
case nl.IFLA_BOND_SLAVE_LINK_FAILURE_COUNT:
bondSlave.LinkFailureCount = native.Uint32(data[i].Value[0:4])
case nl.IFLA_BOND_SLAVE_PERM_HWADDR:
bondSlave.PermHardwareAddr = net.HardwareAddr(data[i].Value[0:6])
case nl.IFLA_BOND_SLAVE_QUEUE_ID:
bondSlave.QueueId = native.Uint16(data[i].Value[0:2])
case nl.IFLA_BOND_SLAVE_AD_AGGREGATOR_ID:
bondSlave.AggregatorId = native.Uint16(data[i].Value[0:2])
case nl.IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE:
bondSlave.AdActorOperPortState = uint8(data[i].Value[0])
case nl.IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE:
bondSlave.AdPartnerOperPortState = native.Uint16(data[i].Value[0:2])
}
}
}

func parseIPVlanData(link Link, data []syscall.NetlinkRouteAttr) {
ipv := link.(*IPVlan)
for _, datum := range data {
Expand Down Expand Up @@ -2725,6 +2783,30 @@ func LinkSetBondSlave(link Link, master *Bond) error {
return nil
}

// LinkSetBondSlaveQueueId modify bond slave queue-id.
func (h *Handle) LinkSetBondSlaveQueueId(link Link, queueId uint16) error {
base := link.Attrs()
h.ensureIndex(base)
req := h.newNetlinkRequest(unix.RTM_SETLINK, unix.NLM_F_ACK)

msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
msg.Index = int32(base.Index)
req.AddData(msg)

linkInfo := nl.NewRtAttr(unix.IFLA_LINKINFO, nil)
data := linkInfo.AddRtAttr(nl.IFLA_INFO_SLAVE_DATA, nil)
data.AddRtAttr(nl.IFLA_BOND_SLAVE_QUEUE_ID, nl.Uint16Attr(queueId))

req.AddData(linkInfo)
_, err := req.Execute(unix.NETLINK_ROUTE, 0)
return err
}

// LinkSetBondSlaveQueueId modify bond slave queue-id.
func LinkSetBondSlaveQueueId(link Link, queueId uint16) error {
return pkgHandle.LinkSetBondSlaveQueueId(link, queueId)
}

// VethPeerIndex get veth peer index.
func VethPeerIndex(link *Veth) (int, error) {
fd, err := getSocketUDP()
Expand Down
75 changes: 75 additions & 0 deletions link_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2035,6 +2035,81 @@ func TestVethPeerIndex(t *testing.T) {
}
}

func TestLinkSlaveBond(t *testing.T) {
minKernelRequired(t, 3, 13)

tearDown := setUpNetlinkTest(t)
defer tearDown()

const (
bondName = "foo"
slaveName = "fooFoo"
)

bond := NewLinkBond(LinkAttrs{Name: bondName})
bond.Mode = BOND_MODE_BALANCE_RR
if err := LinkAdd(bond); err != nil {
t.Fatal(err)
}
defer LinkDel(bond)

slaveDummy := &Dummy{LinkAttrs{Name: slaveName}}
if err := LinkAdd(slaveDummy); err != nil {
t.Fatal(err)
}
defer LinkDel(slaveDummy)

if err := LinkSetBondSlave(slaveDummy, bond); err != nil {
t.Fatal(err)
}

slaveLink, err := LinkByName(slaveName)
if err != nil {
t.Fatal(err)
}

slave := slaveLink.Attrs().Slave
if slave == nil {
t.Errorf("for %s expected slave is not nil.", slaveName)
}

if slaveType := slave.SlaveType(); slaveType != "bond" {
t.Errorf("for %s expected slave type is 'bond', but '%s'", slaveName, slaveType)
}
}

func TestLinkSetBondSlaveQueueId(t *testing.T) {
minKernelRequired(t, 3, 13)

tearDown := setUpNetlinkTest(t)
defer tearDown()

const (
bondName = "foo"
slave1Name = "fooFoo"
)

bond := NewLinkBond(LinkAttrs{Name: bondName})
if err := LinkAdd(bond); err != nil {
t.Fatal(err)
}
defer LinkDel(bond)

slave := &Dummy{LinkAttrs{Name: slave1Name}}
if err := LinkAdd(slave); err != nil {
t.Fatal(err)
}
defer LinkDel(slave)

if err := LinkSetBondSlave(slave, bond); err != nil {
t.Fatal(err)
}

if err := pkgHandle.LinkSetBondSlaveQueueId(slave, 1); err != nil {
t.Fatal(err)
}
}

func TestLinkSetBondSlave(t *testing.T) {
minKernelRequired(t, 3, 13)

Expand Down
6 changes: 5 additions & 1 deletion nl/link_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ const (
IFLA_INFO_KIND
IFLA_INFO_DATA
IFLA_INFO_XSTATS
IFLA_INFO_MAX = IFLA_INFO_XSTATS
IFLA_INFO_SLAVE_KIND
IFLA_INFO_SLAVE_DATA
IFLA_INFO_MAX = IFLA_INFO_SLAVE_DATA
)

const (
Expand Down Expand Up @@ -165,6 +167,8 @@ const (
IFLA_BOND_SLAVE_PERM_HWADDR
IFLA_BOND_SLAVE_QUEUE_ID
IFLA_BOND_SLAVE_AD_AGGREGATOR_ID
IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE
IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE
)

const (
Expand Down

0 comments on commit 205a160

Please sign in to comment.