diff --git a/link.go b/link.go index 8e6b09e..4963e11a 100644 --- a/link.go +++ b/link.go @@ -266,6 +266,7 @@ type Bridge struct { AgeingTime *uint32 HelloTime *uint32 VlanFiltering *bool + VlanDefaultPVID *uint16 } func (bridge *Bridge) Attrs() *LinkAttrs { @@ -1210,6 +1211,7 @@ func (gtp *GTP) Type() string { } // Virtual XFRM Interfaces +// // Named "xfrmi" to prevent confusion with XFRM objects type Xfrmi struct { LinkAttrs diff --git a/link_linux.go b/link_linux.go index cc80fb6..524a93b 100644 --- a/link_linux.go +++ b/link_linux.go @@ -345,6 +345,16 @@ func (h *Handle) BridgeSetVlanFiltering(link Link, on bool) error { return h.linkModify(bridge, unix.NLM_F_ACK) } +func BridgeSetVlanDefaultPVID(link Link, pvid uint16) error { + return pkgHandle.BridgeSetVlanDefaultPVID(link, pvid) +} + +func (h *Handle) BridgeSetVlanDefaultPVID(link Link, pvid uint16) error { + bridge := link.(*Bridge) + bridge.VlanDefaultPVID = &pvid + return h.linkModify(bridge, unix.NLM_F_ACK) +} + func SetPromiscOn(link Link) error { return pkgHandle.SetPromiscOn(link) } @@ -3184,6 +3194,9 @@ func addBridgeAttrs(bridge *Bridge, linkInfo *nl.RtAttr) { if bridge.VlanFiltering != nil { data.AddRtAttr(nl.IFLA_BR_VLAN_FILTERING, boolToByte(*bridge.VlanFiltering)) } + if bridge.VlanDefaultPVID != nil { + data.AddRtAttr(nl.IFLA_BR_VLAN_DEFAULT_PVID, nl.Uint16Attr(*bridge.VlanDefaultPVID)) + } } func parseBridgeData(bridge Link, data []syscall.NetlinkRouteAttr) { @@ -3202,6 +3215,9 @@ func parseBridgeData(bridge Link, data []syscall.NetlinkRouteAttr) { case nl.IFLA_BR_VLAN_FILTERING: vlanFiltering := datum.Value[0] == 1 br.VlanFiltering = &vlanFiltering + case nl.IFLA_BR_VLAN_DEFAULT_PVID: + vlanDefaultPVID := native.Uint16(datum.Value[0:2]) + br.VlanDefaultPVID = &vlanDefaultPVID } } } diff --git a/link_test.go b/link_test.go index 87f21f8..01ed7dd 100644 --- a/link_test.go +++ b/link_test.go @@ -396,7 +396,7 @@ func compareGretap(t *testing.T, expected, actual *Gretap) { if actual.FlowBased != expected.FlowBased { t.Fatal("Gretap.FlowBased doesn't match") - } + } } func compareGretun(t *testing.T, expected, actual *Gretun) { @@ -2254,6 +2254,34 @@ func TestBridgeSetVlanFiltering(t *testing.T) { } } +func TestBridgeDefaultPVID(t *testing.T) { + minKernelRequired(t, 4, 4) + + tearDown := setUpNetlinkTest(t) + defer tearDown() + + bridgeName := "foo" + bridge := &Bridge{LinkAttrs: LinkAttrs{Name: bridgeName}} + if err := LinkAdd(bridge); err != nil { + t.Fatal(err) + } + expectVlanDefaultPVID(t, bridgeName, 1) + + if err := BridgeSetVlanDefaultPVID(bridge, 100); err != nil { + t.Fatal(err) + } + expectVlanDefaultPVID(t, bridgeName, 100) + + if err := BridgeSetVlanDefaultPVID(bridge, 0); err != nil { + t.Fatal(err) + } + expectVlanDefaultPVID(t, bridgeName, 0) + + if err := LinkDel(bridge); err != nil { + t.Fatal(err) + } +} + func expectVlanFiltering(t *testing.T, linkName string, expected bool) { bridge, err := LinkByName(linkName) if err != nil { @@ -2265,6 +2293,17 @@ func expectVlanFiltering(t *testing.T, linkName string, expected bool) { } } +func expectVlanDefaultPVID(t *testing.T, linkName string, expected uint16) { + bridge, err := LinkByName(linkName) + if err != nil { + t.Fatal(err) + } + + if actual := *bridge.(*Bridge).VlanDefaultPVID; actual != expected { + t.Fatalf("expected %d got %d", expected, actual) + } +} + func TestBridgeCreationWithAgeingTime(t *testing.T) { minKernelRequired(t, 3, 18)