diff --git a/link_linux.go b/link_linux.go index 8ae7cb5..aedea16 100644 --- a/link_linux.go +++ b/link_linux.go @@ -560,6 +560,52 @@ func LinkList() ([]Link, error) { return res, nil } +func LinkSetHairpin(link Link, mode bool) error { + return setProtinfoAttr(link, mode, nl.IFLA_BRPORT_MODE) +} + +func LinkSetGuard(link Link, mode bool) error { + return setProtinfoAttr(link, mode, nl.IFLA_BRPORT_GUARD) +} + +func LinkSetFastLeave(link Link, mode bool) error { + return setProtinfoAttr(link, mode, nl.IFLA_BRPORT_FAST_LEAVE) +} + +func LinkSetLearning(link Link, mode bool) error { + return setProtinfoAttr(link, mode, nl.IFLA_BRPORT_LEARNING) +} + +func LinkSetRootBlock(link Link, mode bool) error { + return setProtinfoAttr(link, mode, nl.IFLA_BRPORT_PROTECT) +} + +func LinkSetFlood(link Link, mode bool) error { + return setProtinfoAttr(link, mode, nl.IFLA_BRPORT_UNICAST_FLOOD) +} + +func setProtinfoAttr(link Link, mode bool, attr int) error { + base := link.Attrs() + ensureIndex(base) + req := nl.NewNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK) + + msg := nl.NewIfInfomsg(syscall.AF_BRIDGE) + msg.Type = syscall.RTM_SETLINK + msg.Flags = syscall.NLM_F_REQUEST + msg.Index = int32(base.Index) + msg.Change = nl.DEFAULT_CHANGE + req.AddData(msg) + + br := nl.NewRtAttr(syscall.IFLA_PROTINFO|syscall.NLA_F_NESTED, nil) + nl.NewRtAttrChild(br, attr, boolToByte(mode)) + req.AddData(br) + _, err := req.Execute(syscall.NETLINK_ROUTE, 0) + if err != nil { + return err + } + return nil +} + func parseVlanData(link Link, data []syscall.NetlinkRouteAttr) { vlan := link.(*Vlan) for _, datum := range data { diff --git a/netlink_unspecified.go b/netlink_unspecified.go index 7a081d7..10c49c1 100644 --- a/netlink_unspecified.go +++ b/netlink_unspecified.go @@ -42,6 +42,30 @@ func LinkDel(link *Link) error { return ErrNotImplemented } +func SetHairpin(link Link, mode bool) error { + return ErrNotImplemented +} + +func SetGuard(link Link, mode bool) error { + return ErrNotImplemented +} + +func SetFastLeave(link Link, mode bool) error { + return ErrNotImplemented +} + +func SetLearning(link Link, mode bool) error { + return ErrNotImplemented +} + +func SetRootBlock(link Link, mode bool) error { + return ErrNotImplemented +} + +func SetFlood(link Link, mode bool) error { + return ErrNotImplemented +} + func LinkList() ([]Link, error) { return nil, ErrNotImplemented } diff --git a/protinfo.go b/protinfo.go index 8631a80..a5d330c 100644 --- a/protinfo.go +++ b/protinfo.go @@ -81,30 +81,3 @@ func LinkGetProtinfo(link Link) (Protinfo, error) { } return pi, fmt.Errorf("Device with index %d not found", base.Index) } - -func LinkSetProtinfo(link Link, p Protinfo) error { - base := link.Attrs() - ensureIndex(base) - req := nl.NewNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK) - - msg := nl.NewIfInfomsg(syscall.AF_BRIDGE) - msg.Type = syscall.RTM_SETLINK - msg.Flags = syscall.NLM_F_REQUEST - msg.Index = int32(base.Index) - msg.Change = nl.DEFAULT_CHANGE - req.AddData(msg) - - br := nl.NewRtAttr(syscall.IFLA_PROTINFO|syscall.NLA_F_NESTED, nil) - nl.NewRtAttrChild(br, nl.IFLA_BRPORT_MODE, boolToByte(p.Hairpin)) - nl.NewRtAttrChild(br, nl.IFLA_BRPORT_GUARD, boolToByte(p.Guard)) - nl.NewRtAttrChild(br, nl.IFLA_BRPORT_FAST_LEAVE, boolToByte(p.FastLeave)) - nl.NewRtAttrChild(br, nl.IFLA_BRPORT_PROTECT, boolToByte(p.RootBlock)) - nl.NewRtAttrChild(br, nl.IFLA_BRPORT_LEARNING, boolToByte(p.Learning)) - nl.NewRtAttrChild(br, nl.IFLA_BRPORT_UNICAST_FLOOD, boolToByte(p.Flood)) - req.AddData(br) - _, err := req.Execute(syscall.NETLINK_ROUTE, 0) - if err != nil { - return err - } - return nil -} diff --git a/protinfo_test.go b/protinfo_test.go index 54bec93..f94c42b 100644 --- a/protinfo_test.go +++ b/protinfo_test.go @@ -23,54 +23,76 @@ func TestProtinfo(t *testing.T) { t.Fatal(err) } - pi1 := Protinfo{ - Hairpin: true, - RootBlock: true, - } - - pi2 := Protinfo{ - Guard: true, - Learning: false, - } - - pi3 := Protinfo{} - - if err := LinkSetProtinfo(iface1, pi1); err != nil { - t.Fatal(err) - } - - gpi1, err := LinkGetProtinfo(iface1) + oldpi1, err := LinkGetProtinfo(iface1) if err != nil { t.Fatal(err) } - if !gpi1.Hairpin { + oldpi2, err := LinkGetProtinfo(iface2) + if err != nil { + t.Fatal(err) + } + + if err := LinkSetHairpin(iface1, true); err != nil { + t.Fatal(err) + } + + if err := LinkSetRootBlock(iface1, true); err != nil { + t.Fatal(err) + } + + pi1, err := LinkGetProtinfo(iface1) + if err != nil { + t.Fatal(err) + } + if !pi1.Hairpin { t.Fatalf("Hairpin mode is not enabled for %s, but should", iface1.Name) } - - if !gpi1.RootBlock { + if !pi1.RootBlock { t.Fatalf("RootBlock is not enabled for %s, but should", iface1.Name) } + if pi1.Guard != oldpi1.Guard { + t.Fatalf("Guard field was changed for %s but shouldn't", iface1.Name) + } + if pi1.FastLeave != oldpi1.FastLeave { + t.Fatalf("FastLeave field was changed for %s but shouldn't", iface1.Name) + } + if pi1.Learning != oldpi1.Learning { + t.Fatalf("Learning field was changed for %s but shouldn't", iface1.Name) + } + if pi1.Flood != oldpi1.Flood { + t.Fatalf("Flood field was changed for %s but shouldn't", iface1.Name) + } - if err := LinkSetProtinfo(iface2, pi2); err != nil { + if err := LinkSetGuard(iface2, true); err != nil { t.Fatal(err) } - gpi2, err := LinkGetProtinfo(iface2) + if err := LinkSetLearning(iface2, false); err != nil { + t.Fatal(err) + } + pi2, err := LinkGetProtinfo(iface2) if err != nil { t.Fatal(err) } - if gpi2.Hairpin { + if pi2.Hairpin { t.Fatalf("Hairpin mode is enabled for %s, but shouldn't", iface2.Name) } - - if !gpi2.Guard { + if !pi2.Guard { t.Fatalf("Guard is not enabled for %s, but should", iface2.Name) } - - if gpi2.Learning { + if pi2.Learning { t.Fatalf("Learning is enabled for %s, but shouldn't", iface2.Name) } + if pi2.RootBlock != oldpi2.RootBlock { + t.Fatalf("RootBlock field was changed for %s but shouldn't", iface2.Name) + } + if pi2.FastLeave != oldpi2.FastLeave { + t.Fatalf("FastLeave field was changed for %s but shouldn't", iface2.Name) + } + if pi2.Flood != oldpi2.Flood { + t.Fatalf("Flood field was changed for %s but shouldn't", iface2.Name) + } - if err := LinkSetProtinfo(iface3, pi3); err == nil || err.Error() != "operation not supported" { - t.Fatalf("Set protinfo for link without master is not supported, but err: %s", err) + if err := LinkSetHairpin(iface3, true); err == nil || err.Error() != "operation not supported" { + t.Fatalf("Set protinfo attrs for link without master is not supported, but err: %s", err) } }