From 356d006895b6d22858543e37a2629159109d9bea Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Fri, 8 Aug 2014 02:37:38 +0100 Subject: [PATCH] This is a modification of erikh/netlink-remove-address PR This is a modification of original PR by @erikh (R118) to keep the netlink codebase more consistent and my OCD under control :-) Docker-DCO-1.1-Signed-off-by: Milos Gajdos (github: milosgajdos83) --- Makefile | 5 ++-- netlink/netlink.go | 7 ++++++ netlink/netlink_linux.go | 36 ++++++++++++++++++++------- netlink/netlink_linux_test.go | 46 +++++++++++++++++++++++++++++++++++ 4 files changed, 82 insertions(+), 12 deletions(-) diff --git a/Makefile b/Makefile index f7b3031b..c4c1857f 100644 --- a/Makefile +++ b/Makefile @@ -2,9 +2,8 @@ all: docker build -t docker/libcontainer . -test: - # we need NET_ADMIN for the netlink tests and SYS_ADMIN for mounting - docker run --rm -it --cap-add NET_ADMIN --cap-add SYS_ADMIN docker/libcontainer +test: build + docker run --rm --privileged docker/libcontainer sh: docker run --rm -it --cap-add NET_ADMIN --cap-add SYS_ADMIN -w /busybox docker/libcontainer nsinit exec sh diff --git a/netlink/netlink.go b/netlink/netlink.go index 5cc75625..dd9b1c16 100644 --- a/netlink/netlink.go +++ b/netlink/netlink.go @@ -21,3 +21,10 @@ type Route struct { Iface *net.Interface Default bool } + +// An IfAddr defines IP network settings for a given network interface +type IfAddr struct { + Iface *net.Interface + IP net.IP + IPNet *net.IPNet +} diff --git a/netlink/netlink_linux.go b/netlink/netlink_linux.go index 5fcc817a..215fb178 100644 --- a/netlink/netlink_linux.go +++ b/netlink/netlink_linux.go @@ -651,30 +651,28 @@ func NetworkSetNsFd(iface *net.Interface, fd int) error { return s.HandleAck(wb.Seq) } -// Add an Ip address to an interface. This is identical to: -// ip addr add $ip/$ipNet dev $iface -func NetworkLinkAddIp(iface *net.Interface, ip net.IP, ipNet *net.IPNet) error { +func networkLinkIpAction(action, flags int, ifa IfAddr) error { s, err := getNetlinkSocket() if err != nil { return err } defer s.Close() - family := getIpFamily(ip) + family := getIpFamily(ifa.IP) - wb := newNetlinkRequest(syscall.RTM_NEWADDR, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK) + wb := newNetlinkRequest(action, flags) msg := newIfAddrmsg(family) - msg.Index = uint32(iface.Index) - prefixLen, _ := ipNet.Mask.Size() + msg.Index = uint32(ifa.Iface.Index) + prefixLen, _ := ifa.IPNet.Mask.Size() msg.Prefixlen = uint8(prefixLen) wb.AddData(msg) var ipData []byte if family == syscall.AF_INET { - ipData = ip.To4() + ipData = ifa.IP.To4() } else { - ipData = ip.To16() + ipData = ifa.IP.To16() } localData := newRtAttr(syscall.IFA_LOCAL, ipData) @@ -690,6 +688,26 @@ func NetworkLinkAddIp(iface *net.Interface, ip net.IP, ipNet *net.IPNet) error { return s.HandleAck(wb.Seq) } +// Delete an IP address from an interface. This is identical to: +// ip addr del $ip/$ipNet dev $iface +func NetworkLinkDelIp(iface *net.Interface, ip net.IP, ipNet *net.IPNet) error { + return networkLinkIpAction( + syscall.RTM_DELADDR, + syscall.NLM_F_ACK, + IfAddr{iface, ip, ipNet}, + ) +} + +// Add an Ip address to an interface. This is identical to: +// ip addr add $ip/$ipNet dev $iface +func NetworkLinkAddIp(iface *net.Interface, ip net.IP, ipNet *net.IPNet) error { + return networkLinkIpAction( + syscall.RTM_NEWADDR, + syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK, + IfAddr{iface, ip, ipNet}, + ) +} + func zeroTerminated(s string) []byte { return []byte(s + "\000") } diff --git a/netlink/netlink_linux_test.go b/netlink/netlink_linux_test.go index a25f2861..0ba88453 100644 --- a/netlink/netlink_linux_test.go +++ b/netlink/netlink_linux_test.go @@ -2,9 +2,55 @@ package netlink import ( "net" + "strings" "testing" ) +func ipAssingned(iface *net.Interface, ip net.IP) bool { + addrs, _ := iface.Addrs() + + for _, addr := range addrs { + args := strings.SplitN(addr.String(), "/", 2) + if args[0] == ip.String() { + return true + } + } + + return false +} + +func TestAddDelNetworkIp(t *testing.T) { + if testing.Short() { + return + } + + ifaceName := "lo" + ip := net.ParseIP("127.0.1.1") + mask := net.IPv4Mask(255, 255, 255, 255) + ipNet := &net.IPNet{ip, mask} + + iface, err := net.InterfaceByName(ifaceName) + if err != nil { + t.Skip("No 'lo' interface; skipping tests") + } + + if err := NetworkLinkAddIp(iface, ip, ipNet); err != nil { + t.Fatal(err) + } + + if !ipAssingned(iface, ip) { + t.Fatalf("Could not locate address '%s' in lo address list.", ip.String()) + } + + if err := NetworkLinkDelIp(iface, ip, ipNet); err != nil { + t.Fatal(err) + } + + if ipAssingned(iface, ip) { + t.Fatal("Located address '%s' in lo address list after removal.", ip.String()) + } +} + func TestCreateBridgeWithMac(t *testing.T) { if testing.Short() { return