mirror of
https://github.com/jsimonetti/rtnetlink.git
synced 2026-03-28 23:41:57 +01:00
Add drivers for bridge, macvlan, vlan, vxlan and add helpers to LinkService to use them (SetMaster, RemoveMaster) Signed-off-by: Jeroen Simonetti <jeroen@simonetti.nl>
287 lines
7.5 KiB
Go
287 lines
7.5 KiB
Go
package driver
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/jsimonetti/rtnetlink/v2/internal/unix"
|
|
"github.com/mdlayher/netlink"
|
|
)
|
|
|
|
func TestMacvlanEncodeDecode(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
macvlan *Macvlan
|
|
}{
|
|
{
|
|
name: "minimal configuration",
|
|
macvlan: &Macvlan{
|
|
Mode: func() *MacvlanMode { m := MacvlanModeBridge; return &m }(),
|
|
},
|
|
},
|
|
{
|
|
name: "bridge mode with flags",
|
|
macvlan: &Macvlan{
|
|
Mode: func() *MacvlanMode { m := MacvlanModeBridge; return &m }(),
|
|
Flags: func() *MacvlanFlag { f := MacvlanFlagNopromisc; return &f }(),
|
|
},
|
|
},
|
|
{
|
|
name: "vepa mode",
|
|
macvlan: &Macvlan{
|
|
Mode: func() *MacvlanMode { m := MacvlanModeVEPA; return &m }(),
|
|
},
|
|
},
|
|
{
|
|
name: "private mode",
|
|
macvlan: &Macvlan{
|
|
Mode: func() *MacvlanMode { m := MacvlanModePrivate; return &m }(),
|
|
},
|
|
},
|
|
{
|
|
name: "passthru mode",
|
|
macvlan: &Macvlan{
|
|
Mode: func() *MacvlanMode { m := MacvlanModePassthru; return &m }(),
|
|
},
|
|
},
|
|
{
|
|
name: "source mode with MAC addresses",
|
|
macvlan: &Macvlan{
|
|
Mode: func() *MacvlanMode { m := MacvlanModeSource; return &m }(),
|
|
MacaddrMode: func() *MacvlanMacaddrMode { m := MacvlanMacaddrAdd; return &m }(),
|
|
MacaddrData: [][]byte{
|
|
{0x00, 0x11, 0x22, 0x33, 0x44, 0x55},
|
|
{0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff},
|
|
},
|
|
MacaddrCount: func() *uint32 { c := uint32(2); return &c }(),
|
|
},
|
|
},
|
|
{
|
|
name: "full configuration",
|
|
macvlan: &Macvlan{
|
|
Mode: func() *MacvlanMode { m := MacvlanModeBridge; return &m }(),
|
|
Flags: func() *MacvlanFlag { f := MacvlanFlagNopromisc | MacvlanFlagNodst; return &f }(),
|
|
BcQueueLen: func() *uint32 { l := uint32(1000); return &l }(),
|
|
BcQueueLenUsed: func() *uint8 { u := uint8(1); return &u }(),
|
|
BcCutoff: func() *int32 { c := int32(10); return &c }(),
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
// Encode
|
|
ae := netlink.NewAttributeEncoder()
|
|
if err := tt.macvlan.Encode(ae); err != nil {
|
|
t.Fatalf("failed to encode: %v", err)
|
|
}
|
|
|
|
b, err := ae.Encode()
|
|
if err != nil {
|
|
t.Fatalf("failed to encode attributes: %v", err)
|
|
}
|
|
|
|
// Decode
|
|
ad, err := netlink.NewAttributeDecoder(b)
|
|
if err != nil {
|
|
t.Fatalf("failed to create decoder: %v", err)
|
|
}
|
|
|
|
decoded := &Macvlan{}
|
|
if err := decoded.Decode(ad); err != nil {
|
|
t.Fatalf("failed to decode: %v", err)
|
|
}
|
|
|
|
// Verify
|
|
if tt.macvlan.Mode != nil {
|
|
if decoded.Mode == nil {
|
|
t.Errorf("expected Mode %v, got nil", *tt.macvlan.Mode)
|
|
} else if *decoded.Mode != *tt.macvlan.Mode {
|
|
t.Errorf("expected Mode %v, got %v", *tt.macvlan.Mode, *decoded.Mode)
|
|
}
|
|
}
|
|
|
|
if tt.macvlan.Flags != nil {
|
|
if decoded.Flags == nil {
|
|
t.Errorf("expected Flags %v, got nil", *tt.macvlan.Flags)
|
|
} else if *decoded.Flags != *tt.macvlan.Flags {
|
|
t.Errorf("expected Flags %v, got %v", *tt.macvlan.Flags, *decoded.Flags)
|
|
}
|
|
}
|
|
|
|
if tt.macvlan.MacaddrMode != nil {
|
|
if decoded.MacaddrMode == nil {
|
|
t.Errorf("expected MacaddrMode %v, got nil", *tt.macvlan.MacaddrMode)
|
|
} else if *decoded.MacaddrMode != *tt.macvlan.MacaddrMode {
|
|
t.Errorf("expected MacaddrMode %v, got %v", *tt.macvlan.MacaddrMode, *decoded.MacaddrMode)
|
|
}
|
|
}
|
|
|
|
if len(tt.macvlan.MacaddrData) > 0 {
|
|
if len(decoded.MacaddrData) != len(tt.macvlan.MacaddrData) {
|
|
t.Errorf("expected %d MAC addresses, got %d", len(tt.macvlan.MacaddrData), len(decoded.MacaddrData))
|
|
}
|
|
}
|
|
|
|
if tt.macvlan.MacaddrCount != nil {
|
|
if decoded.MacaddrCount == nil {
|
|
t.Errorf("expected MacaddrCount %v, got nil", *tt.macvlan.MacaddrCount)
|
|
} else if *decoded.MacaddrCount != *tt.macvlan.MacaddrCount {
|
|
t.Errorf("expected MacaddrCount %v, got %v", *tt.macvlan.MacaddrCount, *decoded.MacaddrCount)
|
|
}
|
|
}
|
|
|
|
if tt.macvlan.BcQueueLen != nil {
|
|
if decoded.BcQueueLen == nil {
|
|
t.Errorf("expected BcQueueLen %v, got nil", *tt.macvlan.BcQueueLen)
|
|
} else if *decoded.BcQueueLen != *tt.macvlan.BcQueueLen {
|
|
t.Errorf("expected BcQueueLen %v, got %v", *tt.macvlan.BcQueueLen, *decoded.BcQueueLen)
|
|
}
|
|
}
|
|
|
|
if tt.macvlan.BcQueueLenUsed != nil {
|
|
if decoded.BcQueueLenUsed == nil {
|
|
t.Errorf("expected BcQueueLenUsed %v, got nil", *tt.macvlan.BcQueueLenUsed)
|
|
} else if *decoded.BcQueueLenUsed != *tt.macvlan.BcQueueLenUsed {
|
|
t.Errorf("expected BcQueueLenUsed %v, got %v", *tt.macvlan.BcQueueLenUsed, *decoded.BcQueueLenUsed)
|
|
}
|
|
}
|
|
|
|
if tt.macvlan.BcCutoff != nil {
|
|
if decoded.BcCutoff == nil {
|
|
t.Errorf("expected BcCutoff %v, got nil", *tt.macvlan.BcCutoff)
|
|
} else if *decoded.BcCutoff != *tt.macvlan.BcCutoff {
|
|
t.Errorf("expected BcCutoff %v, got %v", *tt.macvlan.BcCutoff, *decoded.BcCutoff)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestMacvlanModeString(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
mode MacvlanMode
|
|
expected string
|
|
}{
|
|
{
|
|
name: "private",
|
|
mode: MacvlanModePrivate,
|
|
expected: "private",
|
|
},
|
|
{
|
|
name: "vepa",
|
|
mode: MacvlanModeVEPA,
|
|
expected: "vepa",
|
|
},
|
|
{
|
|
name: "bridge",
|
|
mode: MacvlanModeBridge,
|
|
expected: "bridge",
|
|
},
|
|
{
|
|
name: "passthru",
|
|
mode: MacvlanModePassthru,
|
|
expected: "passthru",
|
|
},
|
|
{
|
|
name: "source",
|
|
mode: MacvlanModeSource,
|
|
expected: "source",
|
|
},
|
|
{
|
|
name: "unknown",
|
|
mode: MacvlanMode(99),
|
|
expected: "unknown MacvlanMode value (99)",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if got := tt.mode.String(); got != tt.expected {
|
|
t.Errorf("expected %q, got %q", tt.expected, got)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestMacvlanKind(t *testing.T) {
|
|
m := &Macvlan{}
|
|
if got := m.Kind(); got != "macvlan" {
|
|
t.Errorf("expected %q, got %q", "macvlan", got)
|
|
}
|
|
}
|
|
|
|
func TestMacvlanNew(t *testing.T) {
|
|
m := &Macvlan{}
|
|
n := m.New()
|
|
if _, ok := n.(*Macvlan); !ok {
|
|
t.Errorf("expected *Macvlan, got %T", n)
|
|
}
|
|
}
|
|
|
|
func TestMacvlanDecodeRaw(t *testing.T) {
|
|
// Test decoding raw netlink data
|
|
tests := []struct {
|
|
name string
|
|
data []byte
|
|
expected *Macvlan
|
|
}{
|
|
{
|
|
name: "mode only",
|
|
data: func() []byte {
|
|
ae := netlink.NewAttributeEncoder()
|
|
ae.Uint32(unix.IFLA_MACVLAN_MODE, uint32(MacvlanModeBridge))
|
|
b, _ := ae.Encode()
|
|
return b
|
|
}(),
|
|
expected: &Macvlan{
|
|
Mode: func() *MacvlanMode { m := MacvlanModeBridge; return &m }(),
|
|
},
|
|
},
|
|
{
|
|
name: "mode and flags",
|
|
data: func() []byte {
|
|
ae := netlink.NewAttributeEncoder()
|
|
ae.Uint32(unix.IFLA_MACVLAN_MODE, uint32(MacvlanModeVEPA))
|
|
ae.Uint16(unix.IFLA_MACVLAN_FLAGS, uint16(MacvlanFlagNopromisc))
|
|
b, _ := ae.Encode()
|
|
return b
|
|
}(),
|
|
expected: &Macvlan{
|
|
Mode: func() *MacvlanMode { m := MacvlanModeVEPA; return &m }(),
|
|
Flags: func() *MacvlanFlag { f := MacvlanFlagNopromisc; return &f }(),
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
ad, err := netlink.NewAttributeDecoder(tt.data)
|
|
if err != nil {
|
|
t.Fatalf("failed to create decoder: %v", err)
|
|
}
|
|
|
|
m := &Macvlan{}
|
|
if err := m.Decode(ad); err != nil {
|
|
t.Fatalf("failed to decode: %v", err)
|
|
}
|
|
|
|
if tt.expected.Mode != nil {
|
|
if m.Mode == nil {
|
|
t.Errorf("expected Mode %v, got nil", *tt.expected.Mode)
|
|
} else if *m.Mode != *tt.expected.Mode {
|
|
t.Errorf("expected Mode %v, got %v", *tt.expected.Mode, *m.Mode)
|
|
}
|
|
}
|
|
|
|
if tt.expected.Flags != nil {
|
|
if m.Flags == nil {
|
|
t.Errorf("expected Flags %v, got nil", *tt.expected.Flags)
|
|
} else if *m.Flags != *tt.expected.Flags {
|
|
t.Errorf("expected Flags %v, got %v", *tt.expected.Flags, *m.Flags)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|