1
0
mirror of https://github.com/rancher/os.git synced 2025-09-09 18:50:04 +00:00

Add a network test that sets up 2 of 4 ehternet devices, and allows another to use dhcp

Signed-off-by: Sven Dowideit <SvenDowideit@home.org.au>
This commit is contained in:
Sven Dowideit
2017-03-10 21:53:12 +10:00
parent 00af8545d6
commit 17b3589782
56 changed files with 5092 additions and 792 deletions

View File

@@ -6,18 +6,26 @@ import (
"encoding/binary"
"fmt"
"net"
"runtime"
"sync"
"sync/atomic"
"syscall"
"unsafe"
"github.com/vishvananda/netns"
)
const (
// Family type definitions
FAMILY_ALL = syscall.AF_UNSPEC
FAMILY_V4 = syscall.AF_INET
FAMILY_V6 = syscall.AF_INET6
FAMILY_ALL = syscall.AF_UNSPEC
FAMILY_V4 = syscall.AF_INET
FAMILY_V6 = syscall.AF_INET6
FAMILY_MPLS = AF_MPLS
)
// SupportedNlFamilies contains the list of netlink families this netlink package supports
var SupportedNlFamilies = []int{syscall.NETLINK_ROUTE, syscall.NETLINK_XFRM}
var nextSeqNr uint32
// GetIPFamily returns the family type of a net.IP.
@@ -93,6 +101,147 @@ func (msg *IfInfomsg) Len() int {
return syscall.SizeofIfInfomsg
}
func (msg *IfInfomsg) EncapType() string {
switch msg.Type {
case 0:
return "generic"
case syscall.ARPHRD_ETHER:
return "ether"
case syscall.ARPHRD_EETHER:
return "eether"
case syscall.ARPHRD_AX25:
return "ax25"
case syscall.ARPHRD_PRONET:
return "pronet"
case syscall.ARPHRD_CHAOS:
return "chaos"
case syscall.ARPHRD_IEEE802:
return "ieee802"
case syscall.ARPHRD_ARCNET:
return "arcnet"
case syscall.ARPHRD_APPLETLK:
return "atalk"
case syscall.ARPHRD_DLCI:
return "dlci"
case syscall.ARPHRD_ATM:
return "atm"
case syscall.ARPHRD_METRICOM:
return "metricom"
case syscall.ARPHRD_IEEE1394:
return "ieee1394"
case syscall.ARPHRD_INFINIBAND:
return "infiniband"
case syscall.ARPHRD_SLIP:
return "slip"
case syscall.ARPHRD_CSLIP:
return "cslip"
case syscall.ARPHRD_SLIP6:
return "slip6"
case syscall.ARPHRD_CSLIP6:
return "cslip6"
case syscall.ARPHRD_RSRVD:
return "rsrvd"
case syscall.ARPHRD_ADAPT:
return "adapt"
case syscall.ARPHRD_ROSE:
return "rose"
case syscall.ARPHRD_X25:
return "x25"
case syscall.ARPHRD_HWX25:
return "hwx25"
case syscall.ARPHRD_PPP:
return "ppp"
case syscall.ARPHRD_HDLC:
return "hdlc"
case syscall.ARPHRD_LAPB:
return "lapb"
case syscall.ARPHRD_DDCMP:
return "ddcmp"
case syscall.ARPHRD_RAWHDLC:
return "rawhdlc"
case syscall.ARPHRD_TUNNEL:
return "ipip"
case syscall.ARPHRD_TUNNEL6:
return "tunnel6"
case syscall.ARPHRD_FRAD:
return "frad"
case syscall.ARPHRD_SKIP:
return "skip"
case syscall.ARPHRD_LOOPBACK:
return "loopback"
case syscall.ARPHRD_LOCALTLK:
return "ltalk"
case syscall.ARPHRD_FDDI:
return "fddi"
case syscall.ARPHRD_BIF:
return "bif"
case syscall.ARPHRD_SIT:
return "sit"
case syscall.ARPHRD_IPDDP:
return "ip/ddp"
case syscall.ARPHRD_IPGRE:
return "gre"
case syscall.ARPHRD_PIMREG:
return "pimreg"
case syscall.ARPHRD_HIPPI:
return "hippi"
case syscall.ARPHRD_ASH:
return "ash"
case syscall.ARPHRD_ECONET:
return "econet"
case syscall.ARPHRD_IRDA:
return "irda"
case syscall.ARPHRD_FCPP:
return "fcpp"
case syscall.ARPHRD_FCAL:
return "fcal"
case syscall.ARPHRD_FCPL:
return "fcpl"
case syscall.ARPHRD_FCFABRIC:
return "fcfb0"
case syscall.ARPHRD_FCFABRIC + 1:
return "fcfb1"
case syscall.ARPHRD_FCFABRIC + 2:
return "fcfb2"
case syscall.ARPHRD_FCFABRIC + 3:
return "fcfb3"
case syscall.ARPHRD_FCFABRIC + 4:
return "fcfb4"
case syscall.ARPHRD_FCFABRIC + 5:
return "fcfb5"
case syscall.ARPHRD_FCFABRIC + 6:
return "fcfb6"
case syscall.ARPHRD_FCFABRIC + 7:
return "fcfb7"
case syscall.ARPHRD_FCFABRIC + 8:
return "fcfb8"
case syscall.ARPHRD_FCFABRIC + 9:
return "fcfb9"
case syscall.ARPHRD_FCFABRIC + 10:
return "fcfb10"
case syscall.ARPHRD_FCFABRIC + 11:
return "fcfb11"
case syscall.ARPHRD_FCFABRIC + 12:
return "fcfb12"
case syscall.ARPHRD_IEEE802_TR:
return "tr"
case syscall.ARPHRD_IEEE80211:
return "ieee802.11"
case syscall.ARPHRD_IEEE80211_PRISM:
return "ieee802.11/prism"
case syscall.ARPHRD_IEEE80211_RADIOTAP:
return "ieee802.11/radiotap"
case syscall.ARPHRD_IEEE802154:
return "ieee802.15.4"
case 65534:
return "none"
case 65535:
return "void"
}
return fmt.Sprintf("unknown%d", msg.Type)
}
func rtaAlignOf(attrlen int) int {
return (attrlen + syscall.RTA_ALIGNTO - 1) & ^(syscall.RTA_ALIGNTO - 1)
}
@@ -171,7 +320,8 @@ func (a *RtAttr) Serialize() []byte {
type NetlinkRequest struct {
syscall.NlMsghdr
Data []NetlinkRequestData
Data []NetlinkRequestData
Sockets map[int]*SocketHandle
}
// Serialize the Netlink Request into a byte array
@@ -203,14 +353,32 @@ func (req *NetlinkRequest) AddData(data NetlinkRequestData) {
}
// Execute the request against a the given sockType.
// Returns a list of netlink messages in seriaized format, optionally filtered
// Returns a list of netlink messages in serialized format, optionally filtered
// by resType.
func (req *NetlinkRequest) Execute(sockType int, resType uint16) ([][]byte, error) {
s, err := getNetlinkSocket(sockType)
if err != nil {
return nil, err
var (
s *NetlinkSocket
err error
)
if req.Sockets != nil {
if sh, ok := req.Sockets[sockType]; ok {
s = sh.Socket
req.Seq = atomic.AddUint32(&sh.Seq, 1)
}
}
sharedSocket := s != nil
if s == nil {
s, err = getNetlinkSocket(sockType)
if err != nil {
return nil, err
}
defer s.Close()
} else {
s.Lock()
defer s.Unlock()
}
defer s.Close()
if err := s.Send(req); err != nil {
return nil, err
@@ -231,7 +399,10 @@ done:
}
for _, m := range msgs {
if m.Header.Seq != req.Seq {
return nil, fmt.Errorf("Wrong Seq nr %d, expected 1", m.Header.Seq)
if sharedSocket {
continue
}
return nil, fmt.Errorf("Wrong Seq nr %d, expected %d", m.Header.Seq, req.Seq)
}
if m.Header.Pid != pid {
return nil, fmt.Errorf("Wrong pid %d, expected %d", m.Header.Pid, pid)
@@ -276,6 +447,7 @@ func NewNetlinkRequest(proto, flags int) *NetlinkRequest {
type NetlinkSocket struct {
fd int
lsa syscall.SockaddrNetlink
sync.Mutex
}
func getNetlinkSocket(protocol int) (*NetlinkSocket, error) {
@@ -295,6 +467,71 @@ func getNetlinkSocket(protocol int) (*NetlinkSocket, error) {
return s, nil
}
// GetNetlinkSocketAt opens a netlink socket in the network namespace newNs
// and positions the thread back into the network namespace specified by curNs,
// when done. If curNs is close, the function derives the current namespace and
// moves back into it when done. If newNs is close, the socket will be opened
// in the current network namespace.
func GetNetlinkSocketAt(newNs, curNs netns.NsHandle, protocol int) (*NetlinkSocket, error) {
c, err := executeInNetns(newNs, curNs)
if err != nil {
return nil, err
}
defer c()
return getNetlinkSocket(protocol)
}
// executeInNetns sets execution of the code following this call to the
// network namespace newNs, then moves the thread back to curNs if open,
// otherwise to the current netns at the time the function was invoked
// In case of success, the caller is expected to execute the returned function
// at the end of the code that needs to be executed in the network namespace.
// Example:
// func jobAt(...) error {
// d, err := executeInNetns(...)
// if err != nil { return err}
// defer d()
// < code which needs to be executed in specific netns>
// }
// TODO: his function probably belongs to netns pkg.
func executeInNetns(newNs, curNs netns.NsHandle) (func(), error) {
var (
err error
moveBack func(netns.NsHandle) error
closeNs func() error
unlockThd func()
)
restore := func() {
// order matters
if moveBack != nil {
moveBack(curNs)
}
if closeNs != nil {
closeNs()
}
if unlockThd != nil {
unlockThd()
}
}
if newNs.IsOpen() {
runtime.LockOSThread()
unlockThd = runtime.UnlockOSThread
if !curNs.IsOpen() {
if curNs, err = netns.Get(); err != nil {
restore()
return nil, fmt.Errorf("could not get current namespace while creating netlink socket: %v", err)
}
closeNs = curNs.Close
}
if err := netns.Set(newNs); err != nil {
restore()
return nil, fmt.Errorf("failed to set into network namespace %d while creating netlink socket: %v", newNs, err)
}
moveBack = netns.Set
}
return restore, nil
}
// Create a netlink socket with a given protocol (e.g. NETLINK_ROUTE)
// and subscribe it to multicast groups passed in variable argument list.
// Returns the netlink socket on which Receive() method can be called
@@ -321,8 +558,21 @@ func Subscribe(protocol int, groups ...uint) (*NetlinkSocket, error) {
return s, nil
}
// SubscribeAt works like Subscribe plus let's the caller choose the network
// namespace in which the socket would be opened (newNs). Then control goes back
// to curNs if open, otherwise to the netns at the time this function was called.
func SubscribeAt(newNs, curNs netns.NsHandle, protocol int, groups ...uint) (*NetlinkSocket, error) {
c, err := executeInNetns(newNs, curNs)
if err != nil {
return nil, err
}
defer c()
return Subscribe(protocol, groups...)
}
func (s *NetlinkSocket) Close() {
syscall.Close(s.fd)
s.fd = -1
}
func (s *NetlinkSocket) GetFd() int {
@@ -330,6 +580,9 @@ func (s *NetlinkSocket) GetFd() int {
}
func (s *NetlinkSocket) Send(request *NetlinkRequest) error {
if s.fd < 0 {
return fmt.Errorf("Send called on a closed socket")
}
if err := syscall.Sendto(s.fd, request.Serialize(), 0, &s.lsa); err != nil {
return err
}
@@ -337,6 +590,9 @@ func (s *NetlinkSocket) Send(request *NetlinkRequest) error {
}
func (s *NetlinkSocket) Receive() ([]syscall.NetlinkMessage, error) {
if s.fd < 0 {
return nil, fmt.Errorf("Receive called on a closed socket")
}
rb := make([]byte, syscall.Getpagesize())
nr, _, err := syscall.Recvfrom(s.fd, rb, 0)
if err != nil {
@@ -401,6 +657,13 @@ func Uint32Attr(v uint32) []byte {
return bytes
}
func Uint64Attr(v uint64) []byte {
native := NativeEndian()
bytes := make([]byte, 8)
native.PutUint64(bytes, v)
return bytes
}
func ParseRouteAttr(b []byte) ([]syscall.NetlinkRouteAttr, error) {
var attrs []syscall.NetlinkRouteAttr
for len(b) >= syscall.SizeofRtAttr {
@@ -422,3 +685,17 @@ func netlinkRouteAttrAndValue(b []byte) (*syscall.RtAttr, []byte, int, error) {
}
return a, b[syscall.SizeofRtAttr:], rtaAlignOf(int(a.Len)), nil
}
// SocketHandle contains the netlink socket and the associated
// sequence counter for a specific netlink family
type SocketHandle struct {
Seq uint32
Socket *NetlinkSocket
}
// Close closes the netlink socket
func (sh *SocketHandle) Close() {
if sh.Socket != nil {
sh.Socket.Close()
}
}