diff --git a/link_linux.go b/link_linux.go index d7f79a8..fb2013a 100644 --- a/link_linux.go +++ b/link_linux.go @@ -1288,6 +1288,22 @@ func (h *Handle) LinkSetFlood(link Link, mode bool) error { return h.setProtinfoAttr(link, mode, nl.IFLA_BRPORT_UNICAST_FLOOD) } +func LinkSetBrProxyArp(link Link, mode bool) error { + return pkgHandle.LinkSetBrProxyArp(link, mode) +} + +func (h *Handle) LinkSetBrProxyArp(link Link, mode bool) error { + return h.setProtinfoAttr(link, mode, nl.IFLA_BRPORT_PROXYARP) +} + +func LinkSetBrProxyArpWiFi(link Link, mode bool) error { + return pkgHandle.LinkSetBrProxyArpWiFi(link, mode) +} + +func (h *Handle) LinkSetBrProxyArpWiFi(link Link, mode bool) error { + return h.setProtinfoAttr(link, mode, nl.IFLA_BRPORT_PROXYARP_WIFI) +} + func (h *Handle) setProtinfoAttr(link Link, mode bool, attr int) error { base := link.Attrs() h.ensureIndex(base) diff --git a/nl/link_linux.go b/nl/link_linux.go index 6d9af56..dd03852 100644 --- a/nl/link_linux.go +++ b/nl/link_linux.go @@ -102,7 +102,10 @@ const ( IFLA_BRPORT_FAST_LEAVE IFLA_BRPORT_LEARNING IFLA_BRPORT_UNICAST_FLOOD - IFLA_BRPORT_MAX = IFLA_BRPORT_UNICAST_FLOOD + IFLA_BRPORT_PROXYARP + IFLA_BRPORT_LEARNING_SYNC + IFLA_BRPORT_PROXYARP_WIFI + IFLA_BRPORT_MAX = IFLA_BRPORT_PROXYARP_WIFI ) const ( diff --git a/protinfo.go b/protinfo.go index ead3f2f..0087c44 100644 --- a/protinfo.go +++ b/protinfo.go @@ -6,12 +6,14 @@ import ( // Protinfo represents bridge flags from netlink. type Protinfo struct { - Hairpin bool - Guard bool - FastLeave bool - RootBlock bool - Learning bool - Flood bool + Hairpin bool + Guard bool + FastLeave bool + RootBlock bool + Learning bool + Flood bool + ProxyArp bool + ProxyArpWiFi bool } // String returns a list of enabled flags @@ -35,6 +37,12 @@ func (prot *Protinfo) String() string { if prot.Flood { boolStrings = append(boolStrings, "Flood") } + if prot.ProxyArp { + boolStrings = append(boolStrings, "ProxyArp") + } + if prot.ProxyArpWiFi { + boolStrings = append(boolStrings, "ProxyArpWiFi") + } return strings.Join(boolStrings, " ") } diff --git a/protinfo_linux.go b/protinfo_linux.go index ea72695..10dd0d5 100644 --- a/protinfo_linux.go +++ b/protinfo_linux.go @@ -64,6 +64,10 @@ func parseProtinfo(infos []syscall.NetlinkRouteAttr) *Protinfo { pi.Learning = byteToBool(info.Value[0]) case nl.IFLA_BRPORT_UNICAST_FLOOD: pi.Flood = byteToBool(info.Value[0]) + case nl.IFLA_BRPORT_PROXYARP: + pi.ProxyArp = byteToBool(info.Value[0]) + case nl.IFLA_BRPORT_PROXYARP_WIFI: + pi.ProxyArpWiFi = byteToBool(info.Value[0]) } } return &pi diff --git a/protinfo_test.go b/protinfo_test.go index 8826cd9..680f461 100644 --- a/protinfo_test.go +++ b/protinfo_test.go @@ -2,7 +2,10 @@ package netlink -import "testing" +import ( + "os" + "testing" +) func TestProtinfo(t *testing.T) { tearDown := setUpNetlinkTest(t) @@ -14,6 +17,7 @@ func TestProtinfo(t *testing.T) { iface1 := &Dummy{LinkAttrs{Name: "bar1", MasterIndex: master.Index}} iface2 := &Dummy{LinkAttrs{Name: "bar2", MasterIndex: master.Index}} iface3 := &Dummy{LinkAttrs{Name: "bar3"}} + iface4 := &Dummy{LinkAttrs{Name: "bar4", MasterIndex: master.Index}} if err := LinkAdd(iface1); err != nil { t.Fatal(err) @@ -24,6 +28,9 @@ func TestProtinfo(t *testing.T) { if err := LinkAdd(iface3); err != nil { t.Fatal(err) } + if err := LinkAdd(iface4); err != nil { + t.Fatal(err) + } oldpi1, err := LinkGetProtinfo(iface1) if err != nil { @@ -33,6 +40,10 @@ func TestProtinfo(t *testing.T) { if err != nil { t.Fatal(err) } + oldpi4, err := LinkGetProtinfo(iface4) + if err != nil { + t.Fatal(err) + } if err := LinkSetHairpin(iface1, true); err != nil { t.Fatal(err) @@ -52,6 +63,12 @@ func TestProtinfo(t *testing.T) { if !pi1.RootBlock { t.Fatalf("RootBlock is not enabled for %s, but should", iface1.Name) } + if pi1.ProxyArp != oldpi1.ProxyArp { + t.Fatalf("ProxyArp field was changed for %s but shouldn't", iface1.Name) + } + if pi1.ProxyArpWiFi != oldpi1.ProxyArp { + t.Fatalf("ProxyArpWiFi ProxyArp field was changed for %s but shouldn't", iface1.Name) + } if pi1.Guard != oldpi1.Guard { t.Fatalf("Guard field was changed for %s but shouldn't", iface1.Name) } @@ -81,6 +98,12 @@ func TestProtinfo(t *testing.T) { if !pi2.Guard { t.Fatalf("Guard is not enabled for %s, but should", iface2.Name) } + if pi2.ProxyArp != oldpi2.ProxyArp { + t.Fatalf("ProxyArp field was changed for %s but shouldn't", iface2.Name) + } + if pi2.ProxyArpWiFi != oldpi2.ProxyArpWiFi { + t.Fatalf("ProxyArpWiFi field was changed for %s but shouldn't", iface2.Name) + } if pi2.Learning { t.Fatalf("Learning is enabled for %s, but shouldn't", iface2.Name) } @@ -97,4 +120,44 @@ func TestProtinfo(t *testing.T) { 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) } + + if os.Getenv("TRAVIS_BUILD_DIR") != "" { + t.Skipf("Skipped some tests because travis kernel is to old to support BR_PROXYARP.") + } + + if err := LinkSetBrProxyArp(iface4, true); err != nil { + t.Fatal(err) + } + + if err := LinkSetBrProxyArpWiFi(iface4, true); err != nil { + t.Fatal(err) + } + pi4, err := LinkGetProtinfo(iface4) + if err != nil { + t.Fatal(err) + } + if pi4.Hairpin != oldpi4.Hairpin { + t.Fatalf("Hairpin field was changed for %s but shouldn't", iface4.Name) + } + if pi4.Guard != oldpi4.Guard { + t.Fatalf("Guard field was changed for %s but shouldn't", iface4.Name) + } + if pi4.Learning != oldpi4.Learning { + t.Fatalf("Learning field was changed for %s but shouldn't", iface4.Name) + } + if !pi4.ProxyArp { + t.Fatalf("ProxyArp is not enabled for %s, but should", iface4.Name) + } + if !pi4.ProxyArpWiFi { + t.Fatalf("ProxyArpWiFi is not enabled for %s, but should", iface4.Name) + } + if pi4.RootBlock != oldpi4.RootBlock { + t.Fatalf("RootBlock field was changed for %s but shouldn't", iface4.Name) + } + if pi4.FastLeave != oldpi4.FastLeave { + t.Fatalf("FastLeave field was changed for %s but shouldn't", iface4.Name) + } + if pi4.Flood != oldpi4.Flood { + t.Fatalf("Flood field was changed for %s but shouldn't", iface4.Name) + } }