From 87df994490b40c9bd1aa5e5b90fd4b14cf435dc4 Mon Sep 17 00:00:00 2001 From: Hubert Krauze Date: Thu, 26 Nov 2015 12:47:18 +0100 Subject: [PATCH] Add scope and flags support for netlink address --- addr.go | 5 ++- addr_linux.go | 14 ++++++++ addr_test.go | 95 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 113 insertions(+), 1 deletion(-) diff --git a/addr.go b/addr.go index ed6769a..c739e9f 100644 --- a/addr.go +++ b/addr.go @@ -10,7 +10,10 @@ import ( // include a mask, so it stores the address as a net.IPNet. type Addr struct { *net.IPNet - Label string + Label string + Flags int + Scope int + FlagsMask int } // String returns $ip/$netmask $label diff --git a/addr_linux.go b/addr_linux.go index 19aac0f..562da59 100644 --- a/addr_linux.go +++ b/addr_linux.go @@ -9,6 +9,9 @@ import ( "github.com/vishvananda/netlink/nl" ) +// IFA_FLAGS is a u32 attribute. +const IFA_FLAGS = 0x8 + // AddrAdd will add an IP address to a link device. // Equivalent to: `ip addr add $addr dev $link` func AddrAdd(link Link, addr *Addr) error { @@ -35,6 +38,7 @@ func addrHandle(link Link, addr *Addr, req *nl.NetlinkRequest) error { msg := nl.NewIfAddrmsg(family) msg.Index = uint32(base.Index) + msg.Scope = uint8(addr.Scope) prefixlen, _ := addr.Mask.Size() msg.Prefixlen = uint8(prefixlen) req.AddData(msg) @@ -52,6 +56,13 @@ func addrHandle(link Link, addr *Addr, req *nl.NetlinkRequest) error { addressData := nl.NewRtAttr(syscall.IFA_ADDRESS, addrData) req.AddData(addressData) + if addr.FlagsMask != 0 { + b := make([]byte, 4) + native.PutUint32(b, uint32(addr.Flags)) + flagsData := nl.NewRtAttr(IFA_FLAGS, b) + req.AddData(flagsData) + } + if addr.Label != "" { labelData := nl.NewRtAttr(syscall.IFA_LABEL, nl.ZeroTerminated(addr.Label)) req.AddData(labelData) @@ -111,6 +122,8 @@ func AddrList(link Link, family int) ([]Addr, error) { } case syscall.IFA_LABEL: addr.Label = string(attr.Value[:len(attr.Value)-1]) + case IFA_FLAGS: + addr.Flags = int(native.Uint32(attr.Value[0:4])) } } @@ -120,6 +133,7 @@ func AddrList(link Link, family int) ([]Addr, error) { } else { addr.IPNet = dst } + addr.Scope = int(msg.Scope) res = append(res, addr) } diff --git a/addr_test.go b/addr_test.go index 45e22c0..9348aac 100644 --- a/addr_test.go +++ b/addr_test.go @@ -1,6 +1,8 @@ package netlink import ( + "net" + "syscall" "testing" ) @@ -43,3 +45,96 @@ func TestAddrAddDel(t *testing.T) { t.Fatal("Address not removed properly") } } + +func TestAddrAddDelScope(t *testing.T) { + tearDown := setUpNetlinkTest(t) + defer tearDown() + + link, err := LinkByName("lo") + if err != nil { + t.Fatal(err) + } + + addr := &Addr{ + IPNet: &net.IPNet{ + IP: net.IPv4(127, 1, 1, 1), + Mask: net.CIDRMask(24, 32), + }, + Scope: syscall.RT_SCOPE_LINK, + } + if err = AddrAdd(link, addr); err != nil { + t.Fatal(err) + } + + addrs, err := AddrList(link, FAMILY_ALL) + if err != nil { + t.Fatal(err) + } + + if len(addrs) != 1 || !addr.Equal(addrs[0]) { + t.Fatal("Address not added properly") + } + + if addrs[0].Scope != addr.Scope { + t.Fatal("Address scope not added properly") + } + + if err = AddrDel(link, addr); err != nil { + t.Fatal(err) + } + addrs, err = AddrList(link, FAMILY_ALL) + if err != nil { + t.Fatal(err) + } + + if len(addrs) != 0 { + t.Fatal("Address not removed properly") + } +} + +func TestAddrAddDelFlags(t *testing.T) { + tearDown := setUpNetlinkTest(t) + defer tearDown() + + link, err := LinkByName("lo") + if err != nil { + t.Fatal(err) + } + + addr := &Addr{ + IPNet: &net.IPNet{ + IP: net.IPv4(127, 1, 1, 1), + Mask: net.CIDRMask(24, 32), + }, + Flags: syscall.IFA_F_PERMANENT, + FlagsMask: syscall.IFA_F_PERMANENT, + } + if err = AddrAdd(link, addr); err != nil { + t.Fatal(err) + } + + addrs, err := AddrList(link, FAMILY_ALL) + if err != nil { + t.Fatal(err) + } + + if len(addrs) != 1 || !addr.Equal(addrs[0]) { + t.Fatal("Address not added properly") + } + + if addrs[0].Flags != addr.Flags { + t.Fatal("Address flags not set properly") + } + + if err = AddrDel(link, addr); err != nil { + t.Fatal(err) + } + addrs, err = AddrList(link, FAMILY_ALL) + if err != nil { + t.Fatal(err) + } + + if len(addrs) != 0 { + t.Fatal("Address not removed properly") + } +}