mirror of
https://github.com/jsimonetti/rtnetlink.git
synced 2026-03-29 08:51:53 +02:00
Replace type-specific ptrFoo helper functions with a generic one. Signed-off-by: Daniel Swarbrick <daniel.swarbrick@gmail.com>
278 lines
6.5 KiB
Go
278 lines
6.5 KiB
Go
//go:build integration
|
|
// +build integration
|
|
|
|
package driver
|
|
|
|
import (
|
|
"fmt"
|
|
"testing"
|
|
|
|
"github.com/google/go-cmp/cmp"
|
|
"github.com/jsimonetti/rtnetlink/v2"
|
|
"github.com/jsimonetti/rtnetlink/v2/internal/testutils"
|
|
"github.com/mdlayher/netlink"
|
|
)
|
|
|
|
func bridgeT(d rtnetlink.LinkDriver) *Bridge {
|
|
b := d.(*Bridge)
|
|
return &Bridge{
|
|
StpState: b.StpState,
|
|
ForwardDelay: b.ForwardDelay,
|
|
HelloTime: b.HelloTime,
|
|
MaxAge: b.MaxAge,
|
|
VlanFiltering: b.VlanFiltering,
|
|
VlanProtocol: b.VlanProtocol,
|
|
McastSnooping: b.McastSnooping,
|
|
Priority: b.Priority,
|
|
}
|
|
}
|
|
|
|
func bridgePortT(d rtnetlink.LinkDriver) *BridgePort {
|
|
b := d.(*BridgePort)
|
|
return &BridgePort{
|
|
Priority: b.Priority,
|
|
Cost: b.Cost,
|
|
Mode: b.Mode,
|
|
Learning: b.Learning,
|
|
UnicastFlood: b.UnicastFlood,
|
|
BcastFlood: b.BcastFlood,
|
|
}
|
|
}
|
|
|
|
func TestBridge(t *testing.T) {
|
|
conn, err := rtnetlink.Dial(nil)
|
|
if err != nil {
|
|
t.Fatalf("failed to establish netlink socket: %v", err)
|
|
}
|
|
defer conn.Close()
|
|
|
|
connNS, err := rtnetlink.Dial(&netlink.Config{NetNS: testutils.NetNS(t)})
|
|
if err != nil {
|
|
t.Fatalf("failed to establish netlink socket to netns: %v", err)
|
|
}
|
|
defer connNS.Close()
|
|
|
|
var (
|
|
stpEnabled = BridgeStpStateEnabled
|
|
stpDisabled = BridgeStpStateDisabled
|
|
vlanEnabled = BridgeEnableEnabled
|
|
vlanDisabled = BridgeEnableDisabled
|
|
mcastEnabled = BridgeEnableEnabled
|
|
proto8021Q = VlanProtocol8021Q
|
|
u321500 = uint32(1500)
|
|
u32200 = uint32(200)
|
|
u322000 = uint32(2000)
|
|
u1632768 = uint16(32768) // Default bridge priority
|
|
)
|
|
|
|
tests := []struct {
|
|
name string
|
|
conn *rtnetlink.Conn
|
|
driver *Bridge
|
|
bridge *Bridge
|
|
}{
|
|
{
|
|
name: "bridge with STP enabled",
|
|
conn: conn,
|
|
driver: &Bridge{
|
|
StpState: &stpEnabled,
|
|
ForwardDelay: &u321500,
|
|
HelloTime: &u32200,
|
|
MaxAge: &u322000,
|
|
},
|
|
bridge: &Bridge{
|
|
StpState: &stpEnabled,
|
|
ForwardDelay: &u321500,
|
|
HelloTime: &u32200,
|
|
MaxAge: &u322000,
|
|
Priority: &u1632768,
|
|
VlanFiltering: &vlanDisabled,
|
|
VlanProtocol: &proto8021Q,
|
|
McastSnooping: &mcastEnabled,
|
|
},
|
|
},
|
|
{
|
|
name: "bridge with STP disabled",
|
|
conn: connNS,
|
|
driver: &Bridge{
|
|
StpState: &stpDisabled,
|
|
},
|
|
bridge: &Bridge{
|
|
StpState: &stpDisabled,
|
|
ForwardDelay: &u321500,
|
|
HelloTime: &u32200,
|
|
MaxAge: &u322000,
|
|
Priority: &u1632768,
|
|
VlanFiltering: &vlanDisabled,
|
|
VlanProtocol: &proto8021Q,
|
|
McastSnooping: &mcastEnabled,
|
|
},
|
|
},
|
|
{
|
|
name: "VLAN filtering enabled with 802.1Q",
|
|
conn: connNS,
|
|
driver: &Bridge{
|
|
VlanFiltering: &vlanEnabled,
|
|
VlanProtocol: &proto8021Q,
|
|
},
|
|
bridge: &Bridge{
|
|
StpState: &stpDisabled,
|
|
ForwardDelay: &u321500,
|
|
HelloTime: &u32200,
|
|
MaxAge: &u322000,
|
|
Priority: &u1632768,
|
|
VlanFiltering: &vlanEnabled,
|
|
VlanProtocol: &proto8021Q,
|
|
McastSnooping: &mcastEnabled,
|
|
},
|
|
},
|
|
}
|
|
|
|
for i, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
bridgeID := 1200 + uint32(i*10)
|
|
if err := setupInterface(tt.conn, fmt.Sprintf("br%d", bridgeID), bridgeID, 0, tt.driver); err != nil {
|
|
t.Fatalf("failed to setup bridge interface: %v", err)
|
|
}
|
|
defer tt.conn.Link.Delete(bridgeID)
|
|
|
|
msg, err := getInterface(tt.conn, bridgeID)
|
|
if err != nil {
|
|
t.Fatalf("failed to get bridge interface: %v", err)
|
|
}
|
|
if diff := cmp.Diff(tt.bridge, bridgeT(msg.Attributes.Info.Data)); diff != "" {
|
|
t.Error(diff)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestBridgePort(t *testing.T) {
|
|
conn, err := rtnetlink.Dial(nil)
|
|
if err != nil {
|
|
t.Fatalf("failed to establish netlink socket: %v", err)
|
|
}
|
|
defer conn.Close()
|
|
|
|
connNS, err := rtnetlink.Dial(&netlink.Config{NetNS: testutils.NetNS(t)})
|
|
if err != nil {
|
|
t.Fatalf("failed to establish netlink socket to netns: %v", err)
|
|
}
|
|
defer connNS.Close()
|
|
|
|
var (
|
|
enabled = BridgeEnableEnabled
|
|
disabled = BridgeEnableDisabled
|
|
u1632 = uint16(32)
|
|
u32100 = uint32(100)
|
|
)
|
|
|
|
tests := []struct {
|
|
name string
|
|
conn *rtnetlink.Conn
|
|
driver *Bridge
|
|
portCfg *BridgePort
|
|
expected *BridgePort
|
|
}{
|
|
{
|
|
name: "port with cost and priority",
|
|
conn: conn,
|
|
driver: &Bridge{
|
|
StpState: ptr(BridgeStpStateEnabled),
|
|
},
|
|
portCfg: &BridgePort{
|
|
Priority: &u1632,
|
|
Cost: &u32100,
|
|
},
|
|
expected: &BridgePort{
|
|
Priority: &u1632,
|
|
Cost: &u32100,
|
|
Mode: &disabled,
|
|
Learning: &enabled,
|
|
UnicastFlood: &enabled,
|
|
BcastFlood: &enabled,
|
|
},
|
|
},
|
|
{
|
|
name: "port with hairpin mode",
|
|
conn: connNS,
|
|
driver: &Bridge{
|
|
StpState: ptr(BridgeStpStateEnabled),
|
|
},
|
|
portCfg: &BridgePort{
|
|
Mode: &enabled,
|
|
},
|
|
expected: &BridgePort{
|
|
Mode: &enabled,
|
|
Cost: &u32100,
|
|
Priority: &u1632,
|
|
Learning: &enabled,
|
|
UnicastFlood: &enabled,
|
|
BcastFlood: &enabled,
|
|
},
|
|
},
|
|
{
|
|
name: "port with learning and flooding",
|
|
conn: connNS,
|
|
driver: &Bridge{
|
|
StpState: ptr(BridgeStpStateEnabled),
|
|
},
|
|
portCfg: &BridgePort{
|
|
Learning: &enabled,
|
|
UnicastFlood: &enabled,
|
|
BcastFlood: &enabled,
|
|
},
|
|
expected: &BridgePort{
|
|
Learning: &enabled,
|
|
UnicastFlood: &enabled,
|
|
BcastFlood: &enabled,
|
|
Cost: &u32100,
|
|
Priority: &u1632,
|
|
Mode: &disabled,
|
|
},
|
|
},
|
|
}
|
|
|
|
for i, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
bridgeID := 1300 + uint32(i*10)
|
|
if err := setupInterface(tt.conn, fmt.Sprintf("br%d", bridgeID), bridgeID, 0, tt.driver); err != nil {
|
|
t.Fatalf("failed to setup bridge interface: %v", err)
|
|
}
|
|
defer tt.conn.Link.Delete(bridgeID)
|
|
|
|
// Create dummy interface as bridge port
|
|
dummyID := bridgeID + 1
|
|
if err := setupInterface(tt.conn, fmt.Sprintf("d%d", dummyID), dummyID, bridgeID, &rtnetlink.LinkData{Name: "dummy"}); err != nil {
|
|
t.Fatalf("failed to setup dummy interface: %v", err)
|
|
}
|
|
defer tt.conn.Link.Delete(dummyID)
|
|
|
|
// Configure the bridge port
|
|
if tt.portCfg != nil {
|
|
err := tt.conn.Link.Set(&rtnetlink.LinkMessage{
|
|
Index: dummyID,
|
|
Attributes: &rtnetlink.LinkAttributes{
|
|
Info: &rtnetlink.LinkInfo{
|
|
SlaveKind: "bridge",
|
|
SlaveData: tt.portCfg,
|
|
},
|
|
},
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("failed to configure bridge port: %v", err)
|
|
}
|
|
}
|
|
|
|
// Verify bridge port configuration
|
|
msg, err := getInterface(tt.conn, dummyID)
|
|
if err != nil {
|
|
t.Fatalf("failed to get dummy interface: %v", err)
|
|
}
|
|
if diff := cmp.Diff(tt.expected, bridgePortT(msg.Attributes.Info.SlaveData)); diff != "" {
|
|
t.Error(diff)
|
|
}
|
|
})
|
|
}
|
|
}
|