Refactored SetNs funcs. Implemented ChangeName.

I've refactored NetworkSetNsPid and NetworkSetNsFd following
what we already have in place for Add/Del Ip and Add/Del Link.
I've reimplemented NetworkChangeName function which is now
using netlink for changing the interface name. I added tests too.
I've moved the original syscall implementation at the bottom
to keep it together with the other non-netlink functions.

Signed-off-by: Milos Gajdos <milosgajdos83@gmail.com> (github: milosgajdos83)
This commit is contained in:
Milos Gajdos 2014-09-27 02:27:32 +01:00
parent 30e50af760
commit 267ba8f753
2 changed files with 105 additions and 65 deletions

View File

@ -385,7 +385,7 @@ func nonZeroTerminated(s string) []byte {
}
// Add a new network link of a specified type.
// This is identical to running: ip add link $name type $linkType
// This is identical to running: ip link add $name type $linkType
func NetworkLinkAdd(name string, linkType string) error {
if name == "" || linkType == "" {
return fmt.Errorf("Neither link name nor link type can be empty!")
@ -603,22 +603,18 @@ func NetworkSetNoMaster(iface *net.Interface) error {
return networkMasterAction(iface, data)
}
func NetworkSetNsPid(iface *net.Interface, nspid int) error {
func networkSetNsAction(iface *net.Interface, rtattr *RtAttr) error {
s, err := getNetlinkSocket()
if err != nil {
return err
}
defer s.Close()
wb := newNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
wb := newNetlinkRequest(syscall.RTM_NEWLINK, 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)
wb.AddData(uint32Attr(syscall.IFLA_NET_NS_PID, uint32(nspid)))
wb.AddData(rtattr)
if err := s.Send(wb); err != nil {
return err
@ -627,7 +623,29 @@ func NetworkSetNsPid(iface *net.Interface, nspid int) error {
return s.HandleAck(wb.Seq)
}
// Move a particular network interface to a particular network namespace
// specified by PID. This is idential to running: ip link set dev $name netns $pid
func NetworkSetNsPid(iface *net.Interface, nspid int) error {
data := uint32Attr(syscall.IFLA_NET_NS_PID, uint32(nspid))
return networkSetNsAction(iface, data)
}
// Move a particular network interface to a particular mounted
// network namespace specified by file descriptor.
// This is idential to running: ip link set dev $name netns $fd
func NetworkSetNsFd(iface *net.Interface, fd int) error {
data := uint32Attr(IFLA_NET_NS_FD, uint32(fd))
return networkSetNsAction(iface, data)
}
// Rname a particular interface to a different name
// !!! Note that you can't rename an active interface. You need to bring it down before renaming it.
// This is identical to running: ip link set dev ${oldName} name ${newName}
func NetworkChangeName(iface *net.Interface, newName string) error {
if len(newName) >= IFNAMSIZ {
return fmt.Errorf("Interface name %s too long", newName)
}
s, err := getNetlinkSocket()
if err != nil {
return err
@ -637,12 +655,12 @@ func NetworkSetNsFd(iface *net.Interface, fd int) error {
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)
wb.AddData(uint32Attr(IFLA_NET_NS_FD, uint32(fd)))
nameData := newRtAttr(syscall.IFLA_IFNAME, zeroTerminated(newName))
wb.AddData(nameData)
if err := s.Send(wb); err != nil {
return err
@ -651,6 +669,39 @@ func NetworkSetNsFd(iface *net.Interface, fd int) error {
return s.HandleAck(wb.Seq)
}
// Add a new VETH pair link on the host
// This is identical to running: ip link add name $name type veth peer name $peername
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)
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_INFO_PEER, nil)
newIfInfomsgChild(nest3, syscall.AF_UNSPEC)
newRtAttrChild(nest3, syscall.IFLA_IFNAME, zeroTerminated(name2))
wb.AddData(nest1)
if err := s.Send(wb); err != nil {
return err
}
return s.HandleAck(wb.Seq)
}
func networkLinkIpAction(action, flags int, ifa IfAddr) error {
s, err := getNetlinkSocket()
if err != nil {
@ -906,60 +957,6 @@ func AddDefaultGw(ip, device string) error {
return AddRoute("", "", ip, device)
}
func NetworkChangeName(iface *net.Interface, newName string) error {
if len(newName) >= IFNAMSIZ {
return fmt.Errorf("Interface name %s too long", newName)
}
fd, err := getIfSocket()
if err != nil {
return err
}
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)
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)
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_INFO_PEER, nil)
newIfInfomsgChild(nest3, syscall.AF_UNSPEC)
newRtAttrChild(nest3, syscall.IFLA_IFNAME, zeroTerminated(name2))
wb.AddData(nest1)
if err := s.Send(wb); err != nil {
return err
}
return s.HandleAck(wb.Seq)
}
// THIS CODE DOES NOT COMMUNICATE WITH KERNEL VIA RTNETLINK INTERFACE
// IT IS HERE FOR BACKWARDS COMPATIBILITY WITH OLDER LINUX KERNELS
// WHICH SHIP WITH OLDER NOT ENTIRELY FUNCTIONAL VERSION OF NETLINK
@ -1095,3 +1092,26 @@ func SetMacAddress(name, addr string) error {
}
return nil
}
func ChangeName(iface *net.Interface, newName string) error {
if len(newName) >= IFNAMSIZ {
return fmt.Errorf("Interface name %s too long", newName)
}
fd, err := getIfSocket()
if err != nil {
return err
}
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)
if _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), syscall.SIOCSIFNAME, uintptr(unsafe.Pointer(&data[0]))); errno != 0 {
return errno
}
return nil
}

View File

@ -180,6 +180,26 @@ func TestNetworkSetMasterNoMaster(t *testing.T) {
}
}
func TestNetworkChangeName(t *testing.T) {
if testing.Short() {
return
}
tl := testLink{"tstEth", "dummy"}
newName := "newTst"
addLink(t, tl.name, tl.linkType)
linkIfc := readLink(t, tl.name)
if err := NetworkChangeName(linkIfc, newName); err != nil {
deleteLink(t, tl.name)
t.Fatalf("Could not change %#v interface name to %s: %s", tl, newName, err)
}
readLink(t, newName)
deleteLink(t, newName)
}
func TestAddDelNetworkIp(t *testing.T) {
if testing.Short() {
return