From a5bf8abb7723ae7d47188ab9f97f06129a53f726 Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Sat, 8 Feb 2014 09:53:04 -0800 Subject: [PATCH 01/14] Add set master for interface Docker-DCO-1.1-Signed-off-by: Michael Crosby (github: crosbymichael) --- netlink/netlink_linux.go | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/netlink/netlink_linux.go b/netlink/netlink_linux.go index 0ea5b4d..01b3ff0 100644 --- a/netlink/netlink_linux.go +++ b/netlink/netlink_linux.go @@ -386,6 +386,39 @@ func NetworkSetMTU(iface *net.Interface, mtu int) error { return s.HandleAck(wb.Seq) } +// same as ip link set $name master $master +func NetworkSetMaster(iface, master *net.Interface) error { + s, err := getNetlinkSocket() + if err != nil { + return err + } + defer s.Close() + + wb := newNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK) + + msg := newIfInfomsg(syscall.AF_UNSPEC) + msg.Type = syscall.RTM_SETLINK + msg.Flags = syscall.NLM_F_REQUEST + msg.Index = int32(iface.Index) + msg.Change = 0xFFFFFFFF + wb.AddData(msg) + + var ( + b = make([]byte, 4) + native = nativeEndian() + ) + native.PutUint32(b, uint32(master.Index)) + + data := newRtAttr(syscall.IFLA_MASTER, b) + wb.AddData(data) + + if err := s.Send(wb); err != nil { + return err + } + + 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 { From 708c7be9d213cdf85c5279d082f480eaf072e6cd Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Sat, 8 Feb 2014 10:03:16 -0800 Subject: [PATCH 02/14] Add network set interface in namespace by pid Docker-DCO-1.1-Signed-off-by: Michael Crosby (github: crosbymichael) --- netlink/netlink_linux.go | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/netlink/netlink_linux.go b/netlink/netlink_linux.go index 01b3ff0..e69635e 100644 --- a/netlink/netlink_linux.go +++ b/netlink/netlink_linux.go @@ -419,6 +419,38 @@ func NetworkSetMaster(iface, master *net.Interface) error { return s.HandleAck(wb.Seq) } +func NetworkSetNsPid(iface *net.Interface, nspid int) error { + s, err := getNetlinkSocket() + if err != nil { + return err + } + defer s.Close() + + wb := newNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK) + + msg := newIfInfomsg(syscall.AF_UNSPEC) + msg.Type = syscall.RTM_SETLINK + msg.Flags = syscall.NLM_F_REQUEST + msg.Index = int32(iface.Index) + msg.Change = 0xFFFFFFFF + wb.AddData(msg) + + var ( + b = make([]byte, 4) + native = nativeEndian() + ) + native.PutUint32(b, uint32(nspid)) + + data := newRtAttr(syscall.IFLA_NET_NS_PID, b) + wb.AddData(data) + + if err := s.Send(wb); err != nil { + return err + } + + 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 { From 971834148cb0c2e688740f2bdac13b1ebae65cd7 Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Sat, 8 Feb 2014 20:44:04 -0800 Subject: [PATCH 03/14] Use c to change interface name Docker-DCO-1.1-Signed-off-by: Michael Crosby (github: crosbymichael) --- netlink/netlink_linux.go | 66 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/netlink/netlink_linux.go b/netlink/netlink_linux.go index e69635e..77ebfcd 100644 --- a/netlink/netlink_linux.go +++ b/netlink/netlink_linux.go @@ -2,6 +2,60 @@ package netlink +/* +#include +#include +#include +#include + +static int get_socket(void) { + int s_errno; + int fd; + + fd = socket(PF_INET, SOCK_DGRAM, 0); + if (fd >= 0) { + return fd; + } + s_errno = errno; + + fd = socket(PF_PACKET, SOCK_DGRAM, 0); + if (fd >= 0) { + return fd; + } + + fd = socket(PF_INET6, SOCK_DGRAM, 0); + if (fd >= 0) { + return fd; + } + errno = s_errno; + return -1; +} + + +static int change_name(const char *old_name, const char *new_name) { + struct ifreq ifr; + int err; + int fd; + + fd = get_socket(); + if (fd < 0) { + return -1; + } + + strncpy(ifr.ifr_name, old_name, IFNAMSIZ); + strncpy(ifr.ifr_newname, new_name, IFNAMSIZ); + + err = ioctl(fd, SIOCSIFNAME, &ifr); + if (err) { + close(fd); + return -1; + } + close(fd); + return err; +} +*/ +import "C" + import ( "encoding/binary" "fmt" @@ -641,3 +695,15 @@ done: return res, nil } + +func NetworkChangeName(oldName, newName string) error { + var ( + cold = C.CString(oldName) + cnew = C.CString(newName) + ) + + if errno := int(C.change_name(cold, cnew)); errno != 0 { + return fmt.Errorf("unable to change name %d", errno) + } + return nil +} From 4f9817a3caabaeba27086187aabf63231034d978 Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Sun, 9 Feb 2014 05:54:13 -0800 Subject: [PATCH 04/14] Replace my C code with tianons Go code Docker-DCO-1.1-Signed-off-by: Michael Crosby (github: crosbymichael) --- netlink/netlink_linux.go | 97 +++++++++++++++------------------------- 1 file changed, 35 insertions(+), 62 deletions(-) diff --git a/netlink/netlink_linux.go b/netlink/netlink_linux.go index 77ebfcd..46bd3d8 100644 --- a/netlink/netlink_linux.go +++ b/netlink/netlink_linux.go @@ -2,60 +2,6 @@ package netlink -/* -#include -#include -#include -#include - -static int get_socket(void) { - int s_errno; - int fd; - - fd = socket(PF_INET, SOCK_DGRAM, 0); - if (fd >= 0) { - return fd; - } - s_errno = errno; - - fd = socket(PF_PACKET, SOCK_DGRAM, 0); - if (fd >= 0) { - return fd; - } - - fd = socket(PF_INET6, SOCK_DGRAM, 0); - if (fd >= 0) { - return fd; - } - errno = s_errno; - return -1; -} - - -static int change_name(const char *old_name, const char *new_name) { - struct ifreq ifr; - int err; - int fd; - - fd = get_socket(); - if (fd < 0) { - return -1; - } - - strncpy(ifr.ifr_name, old_name, IFNAMSIZ); - strncpy(ifr.ifr_newname, new_name, IFNAMSIZ); - - err = ioctl(fd, SIOCSIFNAME, &ifr); - if (err) { - close(fd); - return -1; - } - close(fd); - return err; -} -*/ -import "C" - import ( "encoding/binary" "fmt" @@ -696,14 +642,41 @@ done: return res, nil } -func NetworkChangeName(oldName, newName string) error { - var ( - cold = C.CString(oldName) - cnew = C.CString(newName) - ) - - if errno := int(C.change_name(cold, cnew)); errno != 0 { - return fmt.Errorf("unable to change name %d", errno) +func getIfSocket() (int, error) { + fd, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_DGRAM, 0) + if err == nil { + return fd, err } + sErr := err + + fd, err = syscall.Socket(syscall.AF_PACKET, syscall.SOCK_DGRAM, 0) + if err == nil { + return fd, err + } + + fd, err = syscall.Socket(syscall.AF_INET6, syscall.SOCK_DGRAM, 0) + if err == nil { + return fd, err + } + + return -1, sErr +} + +func NetworkChangeName(oldName, newName string) error { + fd, err := getIfSocket() + if err != nil { + return err + } + defer syscall.Close(fd) + IFNAMSIZ := 16 + + data := [32]byte{} + copy(data[:IFNAMSIZ-1], oldName) + copy(data[IFNAMSIZ:IFNAMSIZ*2-1], newName) + + if _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), syscall.SIOCSIFNAME, uintptr(unsafe.Pointer(&data[0]))); errno != 0 { + return errno + } + return nil } From e44920cbe6770b7df8d50c489dd74ef90b1f8006 Mon Sep 17 00:00:00 2001 From: Tianon Gravi Date: Sun, 9 Feb 2014 18:12:43 -0700 Subject: [PATCH 05/14] Update NetworkChangeName to be more similar to my original (moving IFNAMSIZ constant outside the function like it should've been) Docker-DCO-1.1-Signed-off-by: Andrew Page (github: tianon) --- netlink/netlink_linux.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/netlink/netlink_linux.go b/netlink/netlink_linux.go index 46bd3d8..b94cbf6 100644 --- a/netlink/netlink_linux.go +++ b/netlink/netlink_linux.go @@ -662,15 +662,17 @@ func getIfSocket() (int, error) { return -1, sErr } +// from +const IFNAMSIZ = 16 + func NetworkChangeName(oldName, newName string) error { fd, err := getIfSocket() if err != nil { return err } defer syscall.Close(fd) - IFNAMSIZ := 16 - data := [32]byte{} + data := [IFNAMSIZ * 2]byte{} copy(data[:IFNAMSIZ-1], oldName) copy(data[IFNAMSIZ:IFNAMSIZ*2-1], newName) From 4b4a12a4c3fcab1c06524f38854faa6b25c00e64 Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Mon, 10 Feb 2014 11:36:23 -0800 Subject: [PATCH 06/14] Improve get if socket loop Docker-DCO-1.1-Signed-off-by: Michael Crosby (github: crosbymichael) --- netlink/netlink_linux.go | 43 +++++++++++++++++++--------------------- 1 file changed, 20 insertions(+), 23 deletions(-) diff --git a/netlink/netlink_linux.go b/netlink/netlink_linux.go index b94cbf6..4e091ef 100644 --- a/netlink/netlink_linux.go +++ b/netlink/netlink_linux.go @@ -10,6 +10,12 @@ import ( "unsafe" ) +const ( + IFNAMSIZ = 16 + DEFAULT_CHANGE = 0xFFFFFFFF + IFLA_INFO_KIND = 1 +) + var nextSeqNr int func nativeEndian() binary.ByteOrder { @@ -368,7 +374,7 @@ func NetworkSetMTU(iface *net.Interface, mtu int) error { msg.Type = syscall.RTM_SETLINK msg.Flags = syscall.NLM_F_REQUEST msg.Index = int32(iface.Index) - msg.Change = 0xFFFFFFFF + msg.Change = DEFAULT_CHANGE wb.AddData(msg) var ( @@ -400,7 +406,7 @@ func NetworkSetMaster(iface, master *net.Interface) error { msg.Type = syscall.RTM_SETLINK msg.Flags = syscall.NLM_F_REQUEST msg.Index = int32(iface.Index) - msg.Change = 0xFFFFFFFF + msg.Change = DEFAULT_CHANGE wb.AddData(msg) var ( @@ -432,7 +438,7 @@ func NetworkSetNsPid(iface *net.Interface, nspid int) error { msg.Type = syscall.RTM_SETLINK msg.Flags = syscall.NLM_F_REQUEST msg.Index = int32(iface.Index) - msg.Change = 0xFFFFFFFF + msg.Change = DEFAULT_CHANGE wb.AddData(msg) var ( @@ -524,8 +530,6 @@ func NetworkLinkAdd(name string, linkType string) error { nameData := newRtAttr(syscall.IFLA_IFNAME, zeroTerminated(name)) wb.AddData(nameData) - IFLA_INFO_KIND := 1 - kindData := newRtAttr(IFLA_INFO_KIND, nonZeroTerminated(linkType)) infoData := newRtAttr(syscall.IFLA_LINKINFO, kindData.ToWireFormat()) @@ -642,29 +646,22 @@ done: return res, nil } -func getIfSocket() (int, error) { - fd, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_DGRAM, 0) - if err == nil { - return fd, err +func getIfSocket() (fd int, err error) { + for _, socket := range []int{ + syscall.AF_INET, + syscall.AF_PACKET, + syscall.AF_INET6, + } { + if fd, err = syscall.Socket(socket, syscall.SOCK_DGRAM, 0); err == nil { + break + } } - sErr := err - - fd, err = syscall.Socket(syscall.AF_PACKET, syscall.SOCK_DGRAM, 0) if err == nil { - return fd, err + return fd, nil } - - fd, err = syscall.Socket(syscall.AF_INET6, syscall.SOCK_DGRAM, 0) - if err == nil { - return fd, err - } - - return -1, sErr + return -1, err } -// from -const IFNAMSIZ = 16 - func NetworkChangeName(oldName, newName string) error { fd, err := getIfSocket() if err != nil { From f62dcac1c5ccc9a9a32df6689f7689d181348727 Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Mon, 10 Feb 2014 13:37:16 -0800 Subject: [PATCH 07/14] Create veth pair via netlink Docker-DCO-1.1-Signed-off-by: Michael Crosby (github: crosbymichael) --- netlink/netlink_linux.go | 43 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/netlink/netlink_linux.go b/netlink/netlink_linux.go index 4e091ef..52c77a2 100644 --- a/netlink/netlink_linux.go +++ b/netlink/netlink_linux.go @@ -14,6 +14,8 @@ const ( IFNAMSIZ = 16 DEFAULT_CHANGE = 0xFFFFFFFF IFLA_INFO_KIND = 1 + IFLA_INFO_DATA = 2 + VETH_PEER = 1 ) var nextSeqNr int @@ -197,7 +199,9 @@ func (rr *NetlinkRequest) ToWireFormat() []byte { } func (rr *NetlinkRequest) AddData(data NetlinkRequestData) { - rr.Data = append(rr.Data, data) + if data != nil { + rr.Data = append(rr.Data, data) + } } func newNetlinkRequest(proto, flags int) *NetlinkRequest { @@ -676,6 +680,41 @@ func NetworkChangeName(oldName, newName string) error { if _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), syscall.SIOCSIFNAME, uintptr(unsafe.Pointer(&data[0]))); errno != 0 { return errno } - return nil } + +func NetworkCreateVethPair(name1, name2 string) error { + s, err := getNetlinkSocket() + if err != nil { + return err + } + defer s.Close() + + wb := newNetlinkRequest(syscall.RTM_NEWLINK, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK) + + msg := newIfInfomsg(syscall.AF_UNSPEC) + wb.AddData(msg) + + kindData := newRtAttr(IFLA_INFO_KIND, nonZeroTerminated("veth")) + info := newRtAttr(syscall.IFLA_LINKINFO, kindData.ToWireFormat()) + // wb.AddData(info) + + peerName := newRtAttr(syscall.IFLA_IFNAME, nonZeroTerminated(name2)) + peer := newRtAttr(VETH_PEER, peerName.ToWireFormat()) + // wb.AddData(peer) + + b := []byte{} + b = append(b, peer.ToWireFormat()...) + b = append(b, info.ToWireFormat()...) + + infoData := newRtAttr(IFLA_INFO_DATA, b) + wb.AddData(infoData) + + nameData := newRtAttr(syscall.IFLA_IFNAME, zeroTerminated(name1)) + wb.AddData(nameData) + + if err := s.Send(wb); err != nil { + return err + } + return s.HandleAck(wb.Seq) +} From a37785b64f003c7e55346a14d48018cceee54e33 Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Mon, 10 Feb 2014 16:41:16 -0800 Subject: [PATCH 08/14] Allow add of empty name Docker-DCO-1.1-Signed-off-by: Michael Crosby (github: crosbymichael) --- netlink/netlink_linux.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/netlink/netlink_linux.go b/netlink/netlink_linux.go index 52c77a2..23dba0c 100644 --- a/netlink/netlink_linux.go +++ b/netlink/netlink_linux.go @@ -531,8 +531,10 @@ func NetworkLinkAdd(name string, linkType string) error { msg := newIfInfomsg(syscall.AF_UNSPEC) wb.AddData(msg) - nameData := newRtAttr(syscall.IFLA_IFNAME, zeroTerminated(name)) - wb.AddData(nameData) + if name != "" { + nameData := newRtAttr(syscall.IFLA_IFNAME, zeroTerminated(name)) + wb.AddData(nameData) + } kindData := newRtAttr(IFLA_INFO_KIND, nonZeroTerminated(linkType)) From 1d3028efa35fc58204236c31dbb6293a1ea782d0 Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Mon, 10 Feb 2014 22:32:07 -0800 Subject: [PATCH 09/14] Add more netlink functions for set ns by fd and bring iface down Docker-DCO-1.1-Signed-off-by: Michael Crosby (github: crosbymichael) --- netlink/netlink_linux.go | 61 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 58 insertions(+), 3 deletions(-) diff --git a/netlink/netlink_linux.go b/netlink/netlink_linux.go index 23dba0c..3b21a38 100644 --- a/netlink/netlink_linux.go +++ b/netlink/netlink_linux.go @@ -15,7 +15,8 @@ const ( DEFAULT_CHANGE = 0xFFFFFFFF IFLA_INFO_KIND = 1 IFLA_INFO_DATA = 2 - VETH_PEER = 1 + VETH_INFO_PEER = 1 + IFLA_NET_NS_FD = 28 ) var nextSeqNr int @@ -365,6 +366,28 @@ func NetworkLinkUp(iface *net.Interface) error { return s.HandleAck(wb.Seq) } +func NetworkLinkDown(iface *net.Interface) error { + s, err := getNetlinkSocket() + if err != nil { + return err + } + defer s.Close() + + wb := newNetlinkRequest(syscall.RTM_NEWLINK, syscall.NLM_F_ACK) + + msg := newIfInfomsg(syscall.AF_UNSPEC) + msg.Change = syscall.IFF_UP + msg.Flags = 0 & ^syscall.IFF_UP + msg.Index = int32(iface.Index) + wb.AddData(msg) + + if err := s.Send(wb); err != nil { + return err + } + + return s.HandleAck(wb.Seq) +} + func NetworkSetMTU(iface *net.Interface, mtu int) error { s, err := getNetlinkSocket() if err != nil { @@ -461,6 +484,38 @@ func NetworkSetNsPid(iface *net.Interface, nspid int) error { return s.HandleAck(wb.Seq) } +func NetworkSetNsFd(iface *net.Interface, fd int) error { + s, err := getNetlinkSocket() + if err != nil { + return err + } + defer s.Close() + + wb := newNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK) + + msg := newIfInfomsg(syscall.AF_UNSPEC) + msg.Type = syscall.RTM_SETLINK + msg.Flags = syscall.NLM_F_REQUEST + msg.Index = int32(iface.Index) + msg.Change = DEFAULT_CHANGE + wb.AddData(msg) + + var ( + b = make([]byte, 4) + native = nativeEndian() + ) + native.PutUint32(b, uint32(fd)) + + data := newRtAttr(IFLA_NET_NS_FD, b) + wb.AddData(data) + + if err := s.Send(wb); err != nil { + return err + } + + 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 { @@ -668,7 +723,7 @@ func getIfSocket() (fd int, err error) { return -1, err } -func NetworkChangeName(oldName, newName string) error { +func NetworkChangeName(iface *net.Interface, newName string) error { fd, err := getIfSocket() if err != nil { return err @@ -676,7 +731,7 @@ func NetworkChangeName(oldName, newName string) error { defer syscall.Close(fd) data := [IFNAMSIZ * 2]byte{} - copy(data[:IFNAMSIZ-1], oldName) + copy(data[:IFNAMSIZ-1], iface.Name) copy(data[IFNAMSIZ:IFNAMSIZ*2-1], newName) if _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), syscall.SIOCSIFNAME, uintptr(unsafe.Pointer(&data[0]))); errno != 0 { From f697f1d648b5340474b056cdef61bd350ae21493 Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Tue, 11 Feb 2014 03:32:35 -0800 Subject: [PATCH 10/14] Exec out to ip right now for creating the veth pair Docker-DCO-1.1-Signed-off-by: Michael Crosby (github: crosbymichael) --- netlink/netlink_linux.go | 36 ++++-------------------------------- 1 file changed, 4 insertions(+), 32 deletions(-) diff --git a/netlink/netlink_linux.go b/netlink/netlink_linux.go index 3b21a38..b9e04a3 100644 --- a/netlink/netlink_linux.go +++ b/netlink/netlink_linux.go @@ -6,6 +6,7 @@ import ( "encoding/binary" "fmt" "net" + "os/exec" "syscall" "unsafe" ) @@ -741,37 +742,8 @@ func NetworkChangeName(iface *net.Interface, newName string) error { } func NetworkCreateVethPair(name1, name2 string) error { - s, err := getNetlinkSocket() - if err != nil { - return err + if data, err := exec.Command("ip", "link", "add", name1, "type", "veth", "peer", "name", name2).Output(); err != nil { + return fmt.Errorf("%s %s", data, err) } - defer s.Close() - - wb := newNetlinkRequest(syscall.RTM_NEWLINK, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK) - - msg := newIfInfomsg(syscall.AF_UNSPEC) - wb.AddData(msg) - - kindData := newRtAttr(IFLA_INFO_KIND, nonZeroTerminated("veth")) - info := newRtAttr(syscall.IFLA_LINKINFO, kindData.ToWireFormat()) - // wb.AddData(info) - - peerName := newRtAttr(syscall.IFLA_IFNAME, nonZeroTerminated(name2)) - peer := newRtAttr(VETH_PEER, peerName.ToWireFormat()) - // wb.AddData(peer) - - b := []byte{} - b = append(b, peer.ToWireFormat()...) - b = append(b, info.ToWireFormat()...) - - infoData := newRtAttr(IFLA_INFO_DATA, b) - wb.AddData(infoData) - - nameData := newRtAttr(syscall.IFLA_IFNAME, zeroTerminated(name1)) - wb.AddData(nameData) - - if err := s.Send(wb); err != nil { - return err - } - return s.HandleAck(wb.Seq) + return nil } From 6675d69513ce71e2b4acf35e008922afa132d47d Mon Sep 17 00:00:00 2001 From: Tianon Gravi Date: Mon, 10 Feb 2014 15:11:17 -0700 Subject: [PATCH 11/14] Add comment clarifying null termination Docker-DCO-1.1-Signed-off-by: Andrew Page (github: tianon) --- netlink/netlink_linux.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/netlink/netlink_linux.go b/netlink/netlink_linux.go index 3b21a38..85dac51 100644 --- a/netlink/netlink_linux.go +++ b/netlink/netlink_linux.go @@ -731,6 +731,8 @@ func NetworkChangeName(iface *net.Interface, newName string) error { defer syscall.Close(fd) data := [IFNAMSIZ * 2]byte{} + // the "-1"s here are very important for ensuring we get proper null + // termination of our new C strings copy(data[:IFNAMSIZ-1], iface.Name) copy(data[IFNAMSIZ:IFNAMSIZ*2-1], newName) From 000df043485ae009044172ecd64cd712075f8143 Mon Sep 17 00:00:00 2001 From: "Guillaume J. Charmes" Date: Wed, 12 Feb 2014 04:09:56 -0800 Subject: [PATCH 12/14] Implement create veth Docker-DCO-1.1-Signed-off-by: Guillaume J. Charmes (github: creack) --- netlink/netlink_linux.go | 84 +++++++++++++++++++++++++--------------- 1 file changed, 53 insertions(+), 31 deletions(-) diff --git a/netlink/netlink_linux.go b/netlink/netlink_linux.go index 23dba0c..b16dec0 100644 --- a/netlink/netlink_linux.go +++ b/netlink/netlink_linux.go @@ -142,29 +142,61 @@ func rtaAlignOf(attrlen int) int { type RtAttr struct { syscall.RtAttr - Data []byte + Data []byte + children []*RtAttr + prefix int } func newRtAttr(attrType int, data []byte) *RtAttr { - attr := &RtAttr{} + attr := &RtAttr{ + children: []*RtAttr{}, + } attr.Type = uint16(attrType) attr.Data = data return attr } -func (attr *RtAttr) ToWireFormat() []byte { +func newRtAttrChild(parent *RtAttr, attrType int, data []byte) *RtAttr { + attr := newRtAttr(attrType, data) + parent.children = append(parent.children, attr) + return attr +} + +func (a *RtAttr) length() int { + l := 0 + for _, child := range a.children { + l += child.length() + syscall.SizeofRtAttr + child.prefix + } + if l == 0 { + l++ + } + return rtaAlignOf(l + len(a.Data)) +} + +func (a *RtAttr) ToWireFormat() []byte { native := nativeEndian() - len := syscall.SizeofRtAttr + len(attr.Data) - b := make([]byte, rtaAlignOf(len)) - native.PutUint16(b[0:2], uint16(len)) - native.PutUint16(b[2:4], attr.Type) - for i, d := range attr.Data { - b[4+i] = d + length := a.length() + buf := make([]byte, rtaAlignOf(length+syscall.SizeofRtAttr)) + + if a.Data != nil { + copy(buf[4:], a.Data) + } else { + next := 4 + for _, child := range a.children { + childBuf := child.ToWireFormat() + copy(buf[next+child.prefix:], childBuf) + next += rtaAlignOf(len(childBuf)) + } } - return b + if l := uint16(rtaAlignOf(length)); l != 0 { + native.PutUint16(buf[0:2], l+1) + } + native.PutUint16(buf[2:4], a.Type) + + return buf } type NetlinkRequest struct { @@ -501,12 +533,7 @@ func NetworkLinkAddIp(iface *net.Interface, ip net.IP, ipNet *net.IPNet) error { } func zeroTerminated(s string) []byte { - bytes := make([]byte, len(s)+1) - for i := 0; i < len(s); i++ { - bytes[i] = s[i] - } - bytes[len(s)] = 0 - return bytes + return []byte(s + "\000") } func nonZeroTerminated(s string) []byte { @@ -697,24 +724,19 @@ func NetworkCreateVethPair(name1, name2 string) error { msg := newIfInfomsg(syscall.AF_UNSPEC) wb.AddData(msg) - kindData := newRtAttr(IFLA_INFO_KIND, nonZeroTerminated("veth")) - info := newRtAttr(syscall.IFLA_LINKINFO, kindData.ToWireFormat()) - // wb.AddData(info) - - peerName := newRtAttr(syscall.IFLA_IFNAME, nonZeroTerminated(name2)) - peer := newRtAttr(VETH_PEER, peerName.ToWireFormat()) - // wb.AddData(peer) - - b := []byte{} - b = append(b, peer.ToWireFormat()...) - b = append(b, info.ToWireFormat()...) - - infoData := newRtAttr(IFLA_INFO_DATA, b) - wb.AddData(infoData) - nameData := newRtAttr(syscall.IFLA_IFNAME, zeroTerminated(name1)) wb.AddData(nameData) + nest1 := newRtAttr(syscall.IFLA_LINKINFO, nil) + newRtAttrChild(nest1, IFLA_INFO_KIND, zeroTerminated("veth")) + nest2 := newRtAttrChild(nest1, IFLA_INFO_DATA, nil) + nest3 := newRtAttrChild(nest2, VETH_PEER, nil) + + last := newRtAttrChild(nest3, syscall.IFLA_IFNAME, zeroTerminated(name2)) + last.prefix = syscall.SizeofIfInfomsg + + wb.AddData(nest1) + if err := s.Send(wb); err != nil { return err } From a890f18e9aa26470d435b875c826a2bf1966ee35 Mon Sep 17 00:00:00 2001 From: "Guillaume J. Charmes" Date: Wed, 12 Feb 2014 09:29:06 -0800 Subject: [PATCH 13/14] Simplify code + Allow more generic attr children + remove prefix Docker-DCO-1.1-Signed-off-by: Guillaume J. Charmes (github: creack) --- netlink/netlink.go | 10 ++- netlink/netlink_linux.go | 131 +++++++++++++++++++++------------------ 2 files changed, 79 insertions(+), 62 deletions(-) diff --git a/netlink/netlink.go b/netlink/netlink.go index 5098b4b..5cc7562 100644 --- a/netlink/netlink.go +++ b/netlink/netlink.go @@ -5,7 +5,15 @@ // netlink_darwin.go package netlink -import "net" +import ( + "errors" + "net" +) + +var ( + ErrWrongSockType = errors.New("Wrong socket type") + ErrShortResponse = errors.New("Got short response from netlink") +) // A Route is a subnet associated with the interface to reach it. type Route struct { diff --git a/netlink/netlink_linux.go b/netlink/netlink_linux.go index 1f48a64..f8bb6ba 100644 --- a/netlink/netlink_linux.go +++ b/netlink/netlink_linux.go @@ -45,6 +45,7 @@ func getIpFamily(ip net.IP) int { } type NetlinkRequestData interface { + Len() int ToWireFormat() []byte } @@ -53,21 +54,24 @@ type IfInfomsg struct { } func newIfInfomsg(family int) *IfInfomsg { - msg := &IfInfomsg{} - msg.Family = uint8(family) - msg.Type = uint16(0) - msg.Index = int32(0) - msg.Flags = uint32(0) - msg.Change = uint32(0) + return &IfInfomsg{ + IfInfomsg: syscall.IfInfomsg{ + Family: uint8(family), + }, + } +} +func newIfInfomsgChild(parent *RtAttr, family int) *IfInfomsg { + msg := newIfInfomsg(family) + parent.children = append(parent.children, msg) return msg } func (msg *IfInfomsg) ToWireFormat() []byte { native := nativeEndian() - len := syscall.SizeofIfInfomsg - b := make([]byte, len) + length := syscall.SizeofIfInfomsg + b := make([]byte, length) b[0] = msg.Family b[1] = 0 native.PutUint16(b[2:4], msg.Type) @@ -77,26 +81,27 @@ func (msg *IfInfomsg) ToWireFormat() []byte { return b } +func (msg *IfInfomsg) Len() int { + return syscall.SizeofIfInfomsg +} + type IfAddrmsg struct { syscall.IfAddrmsg } func newIfAddrmsg(family int) *IfAddrmsg { - msg := &IfAddrmsg{} - msg.Family = uint8(family) - msg.Prefixlen = uint8(0) - msg.Flags = uint8(0) - msg.Scope = uint8(0) - msg.Index = uint32(0) - - return msg + return &IfAddrmsg{ + IfAddrmsg: syscall.IfAddrmsg{ + Family: uint8(family), + }, + } } func (msg *IfAddrmsg) ToWireFormat() []byte { native := nativeEndian() - len := syscall.SizeofIfAddrmsg - b := make([]byte, len) + length := syscall.SizeofIfAddrmsg + b := make([]byte, length) b[0] = msg.Family b[1] = msg.Prefixlen b[2] = msg.Flags @@ -105,26 +110,31 @@ func (msg *IfAddrmsg) ToWireFormat() []byte { return b } +func (msg *IfAddrmsg) Len() int { + return syscall.SizeofIfAddrmsg +} + type RtMsg struct { syscall.RtMsg } func newRtMsg(family int) *RtMsg { - msg := &RtMsg{} - msg.Family = uint8(family) - msg.Table = syscall.RT_TABLE_MAIN - msg.Scope = syscall.RT_SCOPE_UNIVERSE - msg.Protocol = syscall.RTPROT_BOOT - msg.Type = syscall.RTN_UNICAST - - return msg + return &RtMsg{ + RtMsg: syscall.RtMsg{ + Family: uint8(family), + Table: syscall.RT_TABLE_MAIN, + Scope: syscall.RT_SCOPE_UNIVERSE, + Protocol: syscall.RTPROT_BOOT, + Type: syscall.RTN_UNICAST, + }, + } } func (msg *RtMsg) ToWireFormat() []byte { native := nativeEndian() - len := syscall.SizeofRtMsg - b := make([]byte, len) + length := syscall.SizeofRtMsg + b := make([]byte, length) b[0] = msg.Family b[1] = msg.Dst_len b[2] = msg.Src_len @@ -137,6 +147,10 @@ func (msg *RtMsg) ToWireFormat() []byte { return b } +func (msg *RtMsg) Len() int { + return syscall.SizeofRtMsg +} + func rtaAlignOf(attrlen int) int { return (attrlen + syscall.RTA_ALIGNTO - 1) & ^(syscall.RTA_ALIGNTO - 1) } @@ -144,18 +158,17 @@ func rtaAlignOf(attrlen int) int { type RtAttr struct { syscall.RtAttr Data []byte - children []*RtAttr - prefix int + children []NetlinkRequestData } func newRtAttr(attrType int, data []byte) *RtAttr { - attr := &RtAttr{ - children: []*RtAttr{}, + return &RtAttr{ + RtAttr: syscall.RtAttr{ + Type: uint16(attrType), + }, + children: []NetlinkRequestData{}, + Data: data, } - attr.Type = uint16(attrType) - attr.Data = data - - return attr } func newRtAttrChild(parent *RtAttr, attrType int, data []byte) *RtAttr { @@ -164,10 +177,10 @@ func newRtAttrChild(parent *RtAttr, attrType int, data []byte) *RtAttr { return attr } -func (a *RtAttr) length() int { +func (a *RtAttr) Len() int { l := 0 for _, child := range a.children { - l += child.length() + syscall.SizeofRtAttr + child.prefix + l += child.Len() + syscall.SizeofRtAttr } if l == 0 { l++ @@ -178,7 +191,7 @@ func (a *RtAttr) length() int { func (a *RtAttr) ToWireFormat() []byte { native := nativeEndian() - length := a.length() + length := a.Len() buf := make([]byte, rtaAlignOf(length+syscall.SizeofRtAttr)) if a.Data != nil { @@ -187,7 +200,7 @@ func (a *RtAttr) ToWireFormat() []byte { next := 4 for _, child := range a.children { childBuf := child.ToWireFormat() - copy(buf[next+child.prefix:], childBuf) + copy(buf[next:], childBuf) next += rtaAlignOf(len(childBuf)) } } @@ -212,7 +225,7 @@ func (rr *NetlinkRequest) ToWireFormat() []byte { dataBytes := make([][]byte, len(rr.Data)) for i, data := range rr.Data { dataBytes[i] = data.ToWireFormat() - length = length + uint32(len(dataBytes[i])) + length += uint32(len(dataBytes[i])) } b := make([]byte, length) native.PutUint32(b[0:4], length) @@ -221,12 +234,10 @@ func (rr *NetlinkRequest) ToWireFormat() []byte { native.PutUint32(b[8:12], rr.Seq) native.PutUint32(b[12:16], rr.Pid) - i := 16 + next := 16 for _, data := range dataBytes { - for _, dataByte := range data { - b[i] = dataByte - i = i + 1 - } + copy(b[next:], data) + next += len(data) } return b } @@ -238,12 +249,14 @@ func (rr *NetlinkRequest) AddData(data NetlinkRequestData) { } func newNetlinkRequest(proto, flags int) *NetlinkRequest { - rr := &NetlinkRequest{} - rr.Len = uint32(syscall.NLMSG_HDRLEN) - rr.Type = uint16(proto) - rr.Flags = syscall.NLM_F_REQUEST | uint16(flags) - rr.Seq = uint32(getSeq()) - return rr + return &NetlinkRequest{ + NlMsghdr: syscall.NlMsghdr{ + Len: uint32(syscall.NLMSG_HDRLEN), + Type: uint16(proto), + Flags: syscall.NLM_F_REQUEST | uint16(flags), + Seq: uint32(getSeq()), + }, + } } type NetlinkSocket struct { @@ -286,7 +299,7 @@ func (s *NetlinkSocket) Receive() ([]syscall.NetlinkMessage, error) { return nil, err } if nr < syscall.NLMSG_HDRLEN { - return nil, fmt.Errorf("Got short response from netlink") + return nil, ErrShortResponse } rb = rb[:nr] return syscall.ParseNetlinkMessage(rb) @@ -301,7 +314,7 @@ func (s *NetlinkSocket) GetPid() (uint32, error) { case *syscall.SockaddrNetlink: return v.Pid, nil } - return 0, fmt.Errorf("Wrong socket type") + return 0, ErrWrongSockType } func (s *NetlinkSocket) HandleAck(seq uint32) error { @@ -592,11 +605,7 @@ func zeroTerminated(s string) []byte { } func nonZeroTerminated(s string) []byte { - bytes := make([]byte, len(s)) - for i := 0; i < len(s); i++ { - bytes[i] = s[i] - } - return bytes + return []byte(s) } // Add a new network link of a specified type. This is identical to @@ -789,8 +798,8 @@ func NetworkCreateVethPair(name1, name2 string) error { nest2 := newRtAttrChild(nest1, IFLA_INFO_DATA, nil) nest3 := newRtAttrChild(nest2, VETH_INFO_PEER, nil) - last := newRtAttrChild(nest3, syscall.IFLA_IFNAME, zeroTerminated(name2)) - last.prefix = syscall.SizeofIfInfomsg + newIfInfomsgChild(nest3, syscall.AF_UNSPEC) + newRtAttrChild(nest3, syscall.IFLA_IFNAME, zeroTerminated(name2)) wb.AddData(nest1) From 3b7915ab05d3c22d860b2b5fe6e796a0af33c2fe Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Fri, 14 Feb 2014 12:12:35 -0800 Subject: [PATCH 14/14] Add new functions to unsupported file Docker-DCO-1.1-Signed-off-by: Michael Crosby (github: crosbymichael) --- netlink/netlink_unsupported.go | 42 ++++++++++++++++++++++++++++------ 1 file changed, 35 insertions(+), 7 deletions(-) diff --git a/netlink/netlink_unsupported.go b/netlink/netlink_unsupported.go index cd796b3..bd9e962 100644 --- a/netlink/netlink_unsupported.go +++ b/netlink/netlink_unsupported.go @@ -3,31 +3,59 @@ package netlink import ( - "fmt" + "errors" "net" ) +var ( + ErrNotImplemented = errors.New("not implemented") +) + func NetworkGetRoutes() ([]Route, error) { - return nil, fmt.Errorf("Not implemented") + return nil, ErrNotImplemented } func NetworkLinkAdd(name string, linkType string) error { - return fmt.Errorf("Not implemented") + return ErrNotImplemented } func NetworkLinkUp(iface *net.Interface) error { - return fmt.Errorf("Not implemented") + return ErrNotImplemented } func NetworkLinkAddIp(iface *net.Interface, ip net.IP, ipNet *net.IPNet) error { - return fmt.Errorf("Not implemented") + return ErrNotImplemented } func AddDefaultGw(ip net.IP) error { - return fmt.Errorf("Not implemented") + return ErrNotImplemented } func NetworkSetMTU(iface *net.Interface, mtu int) error { - return fmt.Errorf("Not implemented") + return ErrNotImplemented +} + +func NetworkCreateVethPair(name1, name2 string) error { + return ErrNotImplemented +} + +func NetworkChangeName(iface *net.Interface, newName string) error { + return ErrNotImplemented +} + +func NetworkSetNsFd(iface *net.Interface, fd int) error { + return ErrNotImplemented +} + +func NetworkSetNsPid(iface *net.Interface, nspid int) error { + return ErrNotImplemented +} + +func NetworkSetMaster(iface, master *net.Interface) error { + return ErrNotImplemented +} + +func NetworkLinkDown(iface *net.Interface) error { + return ErrNotImplemented }