Procházet zdrojové kódy

Merge pull request #4011 from crosbymichael/add-netlink-functions

Add more netlink functions
Michael Crosby před 11 roky
rodič
revize
113629efb1

+ 9 - 1
pkg/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 {

+ 303 - 71
pkg/netlink/netlink_linux.go

@@ -10,6 +10,15 @@ import (
 	"unsafe"
 )
 
+const (
+	IFNAMSIZ       = 16
+	DEFAULT_CHANGE = 0xFFFFFFFF
+	IFLA_INFO_KIND = 1
+	IFLA_INFO_DATA = 2
+	VETH_INFO_PEER = 1
+	IFLA_NET_NS_FD = 28
+)
+
 var nextSeqNr int
 
 func nativeEndian() binary.ByteOrder {
@@ -36,6 +45,7 @@ func getIpFamily(ip net.IP) int {
 }
 
 type NetlinkRequestData interface {
+	Len() int
 	ToWireFormat() []byte
 }
 
@@ -44,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)
@@ -68,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
@@ -96,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
@@ -128,35 +147,70 @@ 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)
 }
 
 type RtAttr struct {
 	syscall.RtAttr
-	Data []byte
+	Data     []byte
+	children []NetlinkRequestData
 }
 
 func newRtAttr(attrType int, data []byte) *RtAttr {
-	attr := &RtAttr{}
-	attr.Type = uint16(attrType)
-	attr.Data = data
+	return &RtAttr{
+		RtAttr: syscall.RtAttr{
+			Type: uint16(attrType),
+		},
+		children: []NetlinkRequestData{},
+		Data:     data,
+	}
+}
 
+func newRtAttrChild(parent *RtAttr, attrType int, data []byte) *RtAttr {
+	attr := newRtAttr(attrType, data)
+	parent.children = append(parent.children, attr)
 	return attr
 }
 
-func (attr *RtAttr) ToWireFormat() []byte {
+func (a *RtAttr) Len() int {
+	l := 0
+	for _, child := range a.children {
+		l += child.Len() + syscall.SizeofRtAttr
+	}
+	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.Len()
+	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:], 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 {
@@ -171,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)
@@ -180,27 +234,29 @@ 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
 }
 
 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 {
-	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 {
@@ -243,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)
@@ -258,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 {
@@ -355,6 +411,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 {
@@ -368,7 +446,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 (
@@ -386,6 +464,103 @@ 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 = DEFAULT_CHANGE
+	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)
+}
+
+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 = DEFAULT_CHANGE
+	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)
+}
+
+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 {
@@ -426,20 +601,11 @@ 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 {
-	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
@@ -456,10 +622,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)
-
-	IFLA_INFO_KIND := 1
+	if name != "" {
+		nameData := newRtAttr(syscall.IFLA_IFNAME, zeroTerminated(name))
+		wb.AddData(nameData)
+	}
 
 	kindData := newRtAttr(IFLA_INFO_KIND, nonZeroTerminated(linkType))
 
@@ -576,3 +742,69 @@ done:
 
 	return res, nil
 }
+
+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
+		}
+	}
+	if err == nil {
+		return fd, nil
+	}
+	return -1, err
+}
+
+func NetworkChangeName(iface *net.Interface, newName string) error {
+	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)
+}

+ 35 - 7
pkg/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
 }