Skip to content

Commit

Permalink
feat: add LinkSetBondSlaveActive()/LinkDelBondSlave()
Browse files Browse the repository at this point in the history
Signed-off-by: Jason Joo <[email protected]>
  • Loading branch information
jasonjoo2010 authored and aboch committed Aug 6, 2024
1 parent a57a7bd commit 4317e32
Show file tree
Hide file tree
Showing 2 changed files with 134 additions and 5 deletions.
37 changes: 32 additions & 5 deletions link_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -3704,19 +3704,46 @@ func parseXfrmiData(link Link, data []syscall.NetlinkRouteAttr) {
}
}

// LinkSetBondSlave add slave to bond link via ioctl interface.
func LinkSetBondSlave(link Link, master *Bond) error {
func ioctlBondSlave(cmd uintptr, 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)))
_, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), cmd, 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 fmt.Errorf("errno=%v", errno)
}
return nil
}

// LinkSetBondSlaveActive sets specified slave to ACTIVE in an `active-backup` bond link via ioctl interface.
//
// Multiple calls keeps the status unchanged(shown in the unit test).
func LinkSetBondSlaveActive(link Link, master *Bond) error {
err := ioctlBondSlave(unix.SIOCBONDCHANGEACTIVE, link, master)
if err != nil {
return fmt.Errorf("Failed to set slave %q active in %q, %v", link.Attrs().Name, master.Attrs().Name, err)
}
return nil
}

// LinkSetBondSlave add slave to bond link via ioctl interface.
func LinkSetBondSlave(link Link, master *Bond) error {
err := ioctlBondSlave(unix.SIOCBONDENSLAVE, link, master)
if err != nil {
return fmt.Errorf("Failed to enslave %q to %q, %v", link.Attrs().Name, master.Attrs().Name, err)
}
return nil
}

// LinkSetBondSlave removes specified slave from bond link via ioctl interface.
func LinkDelBondSlave(link Link, master *Bond) error {
err := ioctlBondSlave(unix.SIOCBONDRELEASE, link, master)
if err != nil {
return fmt.Errorf("Failed to del slave %q from %q, %v", link.Attrs().Name, master.Attrs().Name, err)
}
return nil
}
Expand Down
102 changes: 102 additions & 0 deletions link_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3205,6 +3205,108 @@ func TestLinkSetBondSlave(t *testing.T) {
}
}

func testFailover(t *testing.T, slaveName, bondName string) {
slaveLink, err := LinkByName(slaveName)
if err != nil {
t.Fatal(err)
}

bondLink, err := LinkByName(bondName)
if err != nil {
t.Fatal(err)
}

err = LinkSetBondSlaveActive(slaveLink, &Bond{LinkAttrs: *bondLink.Attrs()})
if err != nil {
t.Errorf("set slave link active failed: %v", err)
return
}

bondLink, err = LinkByName(bondName)
if err != nil {
t.Fatal(err)
}
bond := bondLink.(*Bond)
if bond.ActiveSlave != slaveLink.Attrs().Index {
t.Errorf("the current active slave %d is not expected as %d", bond.ActiveSlave, slaveLink.Attrs().Index)
}
}

func TestLinkFailover(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["active-backup"]
bond.Miimon = 100

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)
}

testFailover(t, slaveOneName, bondName)
testFailover(t, slaveTwoName, bondName)
testFailover(t, slaveTwoName, bondName)

// del slave from bond
slaveOneLink, err = LinkByName(slaveOneName)
if err != nil {
t.Fatal(err)
}
err = LinkDelBondSlave(slaveOneLink, &Bond{LinkAttrs: *bondLink.Attrs()})
if err != nil {
t.Errorf("Remove slave %s from bond failed: %v", slaveOneName, err)
}
slaveOneLink, err = LinkByName(slaveOneName)
if err != nil {
t.Fatal(err)
}
if slaveOneLink.Attrs().MasterIndex > 0 {
t.Errorf("The nic %s is still a slave of %d", slaveOneName, slaveOneLink.Attrs().MasterIndex)
}
}

func TestLinkSetAllmulticast(t *testing.T) {
tearDown := setUpNetlinkTest(t)
defer tearDown()
Expand Down

0 comments on commit 4317e32

Please sign in to comment.