diff --git a/bridge_linux_test.go b/bridge_linux_test.go index 6fb45b1..710a01b 100644 --- a/bridge_linux_test.go +++ b/bridge_linux_test.go @@ -78,3 +78,38 @@ func TestBridgeVlan(t *testing.T) { } } } + +func TestBridgeGroupFwdMask(t *testing.T) { + minKernelRequired(t, 4, 15) //minimal release for per-port group_fwd_mask + tearDown := setUpNetlinkTest(t) + defer tearDown() + if err := remountSysfs(); err != nil { + t.Fatal(err) + } + bridgeName := "foo" + var mask uint16 = 0xfff0 + bridge := &Bridge{LinkAttrs: LinkAttrs{Name: bridgeName}, GroupFwdMask: &mask} + if err := LinkAdd(bridge); err != nil { + t.Fatal(err) + } + brlink, err := LinkByName(bridgeName) + if err != nil { + t.Fatal(err) + } + if *(brlink.(*Bridge).GroupFwdMask) != mask { + t.Fatalf("created bridge has group_fwd_mask value %x, different from expected %x", + *(brlink.(*Bridge).GroupFwdMask), mask) + } + dummyName := "dm1" + dummy := &Dummy{LinkAttrs: LinkAttrs{Name: dummyName, MasterIndex: brlink.Attrs().Index}} + if err := LinkAdd(dummy); err != nil { + t.Fatal(err) + } + dmLink, err := LinkByName(dummyName) + if err != nil { + t.Fatal(err) + } + if err = LinkSetBRSlaveGroupFwdMask(dmLink, mask); err != nil { + t.Fatal(err) + } +} diff --git a/link.go b/link.go index 5d618ad..260542e 100644 --- a/link.go +++ b/link.go @@ -274,6 +274,7 @@ type Bridge struct { HelloTime *uint32 VlanFiltering *bool VlanDefaultPVID *uint16 + GroupFwdMask *uint16 } func (bridge *Bridge) Attrs() *LinkAttrs { diff --git a/link_linux.go b/link_linux.go index 505d92d..3559484 100644 --- a/link_linux.go +++ b/link_linux.go @@ -2494,6 +2494,16 @@ func (h *Handle) LinkSetGuard(link Link, mode bool) error { return h.setProtinfoAttr(link, mode, nl.IFLA_BRPORT_GUARD) } +// LinkSetBRSlaveGroupFwdMask set the group_fwd_mask of a bridge slave interface +func LinkSetBRSlaveGroupFwdMask(link Link, mask uint16) error { + return pkgHandle.LinkSetBRSlaveGroupFwdMask(link, mask) +} + +// LinkSetBRSlaveGroupFwdMask set the group_fwd_mask of a bridge slave interface +func (h *Handle) LinkSetBRSlaveGroupFwdMask(link Link, mask uint16) error { + return h.setProtinfoAttrRawVal(link, nl.Uint16Attr(mask), nl.IFLA_BRPORT_GROUP_FWD_MASK) +} + func LinkSetFastLeave(link Link, mode bool) error { return pkgHandle.LinkSetFastLeave(link, mode) } @@ -2558,7 +2568,7 @@ func (h *Handle) LinkSetBrNeighSuppress(link Link, mode bool) error { return h.setProtinfoAttr(link, mode, nl.IFLA_BRPORT_NEIGH_SUPPRESS) } -func (h *Handle) setProtinfoAttr(link Link, mode bool, attr int) error { +func (h *Handle) setProtinfoAttrRawVal(link Link, val []byte, attr int) error { base := link.Attrs() h.ensureIndex(base) req := h.newNetlinkRequest(unix.RTM_SETLINK, unix.NLM_F_ACK) @@ -2568,7 +2578,7 @@ func (h *Handle) setProtinfoAttr(link Link, mode bool, attr int) error { req.AddData(msg) br := nl.NewRtAttr(unix.IFLA_PROTINFO|unix.NLA_F_NESTED, nil) - br.AddRtAttr(attr, boolToByte(mode)) + br.AddRtAttr(attr, val) req.AddData(br) _, err := req.Execute(unix.NETLINK_ROUTE, 0) if err != nil { @@ -2576,6 +2586,9 @@ func (h *Handle) setProtinfoAttr(link Link, mode bool, attr int) error { } return nil } +func (h *Handle) setProtinfoAttr(link Link, mode bool, attr int) error { + return h.setProtinfoAttrRawVal(link, boolToByte(mode), attr) +} // LinkSetTxQLen sets the transaction queue length for the link. // Equivalent to: `ip link set $link txqlen $qlen` @@ -3541,6 +3554,9 @@ func addBridgeAttrs(bridge *Bridge, linkInfo *nl.RtAttr) { if bridge.VlanDefaultPVID != nil { data.AddRtAttr(nl.IFLA_BR_VLAN_DEFAULT_PVID, nl.Uint16Attr(*bridge.VlanDefaultPVID)) } + if bridge.GroupFwdMask != nil { + data.AddRtAttr(nl.IFLA_BR_GROUP_FWD_MASK, nl.Uint16Attr(*bridge.GroupFwdMask)) + } } func parseBridgeData(bridge Link, data []syscall.NetlinkRouteAttr) { @@ -3562,6 +3578,9 @@ func parseBridgeData(bridge Link, data []syscall.NetlinkRouteAttr) { case nl.IFLA_BR_VLAN_DEFAULT_PVID: vlanDefaultPVID := native.Uint16(datum.Value[0:2]) br.VlanDefaultPVID = &vlanDefaultPVID + case nl.IFLA_BR_GROUP_FWD_MASK: + mask := native.Uint16(datum.Value[0:2]) + br.GroupFwdMask = &mask } } }