* Bump k8s.io/cri-api to latest version - v0.23.0-alpha.4 * Vendor github.com/vishvananda/netlink for network stats Signed-off-by: David Porter <porterdavid@google.com>
		
			
				
	
	
		
			435 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			435 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
package netlink
 | 
						|
 | 
						|
import (
 | 
						|
	"fmt"
 | 
						|
	"net"
 | 
						|
	"syscall"
 | 
						|
	"unsafe"
 | 
						|
 | 
						|
	"github.com/vishvananda/netlink/nl"
 | 
						|
	"github.com/vishvananda/netns"
 | 
						|
	"golang.org/x/sys/unix"
 | 
						|
)
 | 
						|
 | 
						|
const (
 | 
						|
	NDA_UNSPEC = iota
 | 
						|
	NDA_DST
 | 
						|
	NDA_LLADDR
 | 
						|
	NDA_CACHEINFO
 | 
						|
	NDA_PROBES
 | 
						|
	NDA_VLAN
 | 
						|
	NDA_PORT
 | 
						|
	NDA_VNI
 | 
						|
	NDA_IFINDEX
 | 
						|
	NDA_MASTER
 | 
						|
	NDA_LINK_NETNSID
 | 
						|
	NDA_SRC_VNI
 | 
						|
	NDA_MAX = NDA_SRC_VNI
 | 
						|
)
 | 
						|
 | 
						|
// Neighbor Cache Entry States.
 | 
						|
const (
 | 
						|
	NUD_NONE       = 0x00
 | 
						|
	NUD_INCOMPLETE = 0x01
 | 
						|
	NUD_REACHABLE  = 0x02
 | 
						|
	NUD_STALE      = 0x04
 | 
						|
	NUD_DELAY      = 0x08
 | 
						|
	NUD_PROBE      = 0x10
 | 
						|
	NUD_FAILED     = 0x20
 | 
						|
	NUD_NOARP      = 0x40
 | 
						|
	NUD_PERMANENT  = 0x80
 | 
						|
)
 | 
						|
 | 
						|
// Neighbor Flags
 | 
						|
const (
 | 
						|
	NTF_USE    = 0x01
 | 
						|
	NTF_SELF   = 0x02
 | 
						|
	NTF_MASTER = 0x04
 | 
						|
	NTF_PROXY  = 0x08
 | 
						|
	NTF_ROUTER = 0x80
 | 
						|
)
 | 
						|
 | 
						|
// Ndmsg is for adding, removing or receiving information about a neighbor table entry
 | 
						|
type Ndmsg struct {
 | 
						|
	Family uint8
 | 
						|
	Index  uint32
 | 
						|
	State  uint16
 | 
						|
	Flags  uint8
 | 
						|
	Type   uint8
 | 
						|
}
 | 
						|
 | 
						|
func deserializeNdmsg(b []byte) *Ndmsg {
 | 
						|
	var dummy Ndmsg
 | 
						|
	return (*Ndmsg)(unsafe.Pointer(&b[0:unsafe.Sizeof(dummy)][0]))
 | 
						|
}
 | 
						|
 | 
						|
func (msg *Ndmsg) Serialize() []byte {
 | 
						|
	return (*(*[unsafe.Sizeof(*msg)]byte)(unsafe.Pointer(msg)))[:]
 | 
						|
}
 | 
						|
 | 
						|
func (msg *Ndmsg) Len() int {
 | 
						|
	return int(unsafe.Sizeof(*msg))
 | 
						|
}
 | 
						|
 | 
						|
// NeighAdd will add an IP to MAC mapping to the ARP table
 | 
						|
// Equivalent to: `ip neigh add ....`
 | 
						|
func NeighAdd(neigh *Neigh) error {
 | 
						|
	return pkgHandle.NeighAdd(neigh)
 | 
						|
}
 | 
						|
 | 
						|
// NeighAdd will add an IP to MAC mapping to the ARP table
 | 
						|
// Equivalent to: `ip neigh add ....`
 | 
						|
func (h *Handle) NeighAdd(neigh *Neigh) error {
 | 
						|
	return h.neighAdd(neigh, unix.NLM_F_CREATE|unix.NLM_F_EXCL)
 | 
						|
}
 | 
						|
 | 
						|
// NeighSet will add or replace an IP to MAC mapping to the ARP table
 | 
						|
// Equivalent to: `ip neigh replace....`
 | 
						|
func NeighSet(neigh *Neigh) error {
 | 
						|
	return pkgHandle.NeighSet(neigh)
 | 
						|
}
 | 
						|
 | 
						|
// NeighSet will add or replace an IP to MAC mapping to the ARP table
 | 
						|
// Equivalent to: `ip neigh replace....`
 | 
						|
func (h *Handle) NeighSet(neigh *Neigh) error {
 | 
						|
	return h.neighAdd(neigh, unix.NLM_F_CREATE|unix.NLM_F_REPLACE)
 | 
						|
}
 | 
						|
 | 
						|
// NeighAppend will append an entry to FDB
 | 
						|
// Equivalent to: `bridge fdb append...`
 | 
						|
func NeighAppend(neigh *Neigh) error {
 | 
						|
	return pkgHandle.NeighAppend(neigh)
 | 
						|
}
 | 
						|
 | 
						|
// NeighAppend will append an entry to FDB
 | 
						|
// Equivalent to: `bridge fdb append...`
 | 
						|
func (h *Handle) NeighAppend(neigh *Neigh) error {
 | 
						|
	return h.neighAdd(neigh, unix.NLM_F_CREATE|unix.NLM_F_APPEND)
 | 
						|
}
 | 
						|
 | 
						|
// NeighAppend will append an entry to FDB
 | 
						|
// Equivalent to: `bridge fdb append...`
 | 
						|
func neighAdd(neigh *Neigh, mode int) error {
 | 
						|
	return pkgHandle.neighAdd(neigh, mode)
 | 
						|
}
 | 
						|
 | 
						|
// NeighAppend will append an entry to FDB
 | 
						|
// Equivalent to: `bridge fdb append...`
 | 
						|
func (h *Handle) neighAdd(neigh *Neigh, mode int) error {
 | 
						|
	req := h.newNetlinkRequest(unix.RTM_NEWNEIGH, mode|unix.NLM_F_ACK)
 | 
						|
	return neighHandle(neigh, req)
 | 
						|
}
 | 
						|
 | 
						|
// NeighDel will delete an IP address from a link device.
 | 
						|
// Equivalent to: `ip addr del $addr dev $link`
 | 
						|
func NeighDel(neigh *Neigh) error {
 | 
						|
	return pkgHandle.NeighDel(neigh)
 | 
						|
}
 | 
						|
 | 
						|
// NeighDel will delete an IP address from a link device.
 | 
						|
// Equivalent to: `ip addr del $addr dev $link`
 | 
						|
func (h *Handle) NeighDel(neigh *Neigh) error {
 | 
						|
	req := h.newNetlinkRequest(unix.RTM_DELNEIGH, unix.NLM_F_ACK)
 | 
						|
	return neighHandle(neigh, req)
 | 
						|
}
 | 
						|
 | 
						|
func neighHandle(neigh *Neigh, req *nl.NetlinkRequest) error {
 | 
						|
	var family int
 | 
						|
 | 
						|
	if neigh.Family > 0 {
 | 
						|
		family = neigh.Family
 | 
						|
	} else {
 | 
						|
		family = nl.GetIPFamily(neigh.IP)
 | 
						|
	}
 | 
						|
 | 
						|
	msg := Ndmsg{
 | 
						|
		Family: uint8(family),
 | 
						|
		Index:  uint32(neigh.LinkIndex),
 | 
						|
		State:  uint16(neigh.State),
 | 
						|
		Type:   uint8(neigh.Type),
 | 
						|
		Flags:  uint8(neigh.Flags),
 | 
						|
	}
 | 
						|
	req.AddData(&msg)
 | 
						|
 | 
						|
	ipData := neigh.IP.To4()
 | 
						|
	if ipData == nil {
 | 
						|
		ipData = neigh.IP.To16()
 | 
						|
	}
 | 
						|
 | 
						|
	dstData := nl.NewRtAttr(NDA_DST, ipData)
 | 
						|
	req.AddData(dstData)
 | 
						|
 | 
						|
	if neigh.LLIPAddr != nil {
 | 
						|
		llIPData := nl.NewRtAttr(NDA_LLADDR, neigh.LLIPAddr.To4())
 | 
						|
		req.AddData(llIPData)
 | 
						|
	} else if neigh.Flags != NTF_PROXY || neigh.HardwareAddr != nil {
 | 
						|
		hwData := nl.NewRtAttr(NDA_LLADDR, []byte(neigh.HardwareAddr))
 | 
						|
		req.AddData(hwData)
 | 
						|
	}
 | 
						|
 | 
						|
	if neigh.Vlan != 0 {
 | 
						|
		vlanData := nl.NewRtAttr(NDA_VLAN, nl.Uint16Attr(uint16(neigh.Vlan)))
 | 
						|
		req.AddData(vlanData)
 | 
						|
	}
 | 
						|
 | 
						|
	if neigh.VNI != 0 {
 | 
						|
		vniData := nl.NewRtAttr(NDA_VNI, nl.Uint32Attr(uint32(neigh.VNI)))
 | 
						|
		req.AddData(vniData)
 | 
						|
	}
 | 
						|
 | 
						|
	if neigh.MasterIndex != 0 {
 | 
						|
		masterData := nl.NewRtAttr(NDA_MASTER, nl.Uint32Attr(uint32(neigh.MasterIndex)))
 | 
						|
		req.AddData(masterData)
 | 
						|
	}
 | 
						|
 | 
						|
	_, err := req.Execute(unix.NETLINK_ROUTE, 0)
 | 
						|
	return err
 | 
						|
}
 | 
						|
 | 
						|
// NeighList returns a list of IP-MAC mappings in the system (ARP table).
 | 
						|
// Equivalent to: `ip neighbor show`.
 | 
						|
// The list can be filtered by link and ip family.
 | 
						|
func NeighList(linkIndex, family int) ([]Neigh, error) {
 | 
						|
	return pkgHandle.NeighList(linkIndex, family)
 | 
						|
}
 | 
						|
 | 
						|
// NeighProxyList returns a list of neighbor proxies in the system.
 | 
						|
// Equivalent to: `ip neighbor show proxy`.
 | 
						|
// The list can be filtered by link and ip family.
 | 
						|
func NeighProxyList(linkIndex, family int) ([]Neigh, error) {
 | 
						|
	return pkgHandle.NeighProxyList(linkIndex, family)
 | 
						|
}
 | 
						|
 | 
						|
// NeighList returns a list of IP-MAC mappings in the system (ARP table).
 | 
						|
// Equivalent to: `ip neighbor show`.
 | 
						|
// The list can be filtered by link and ip family.
 | 
						|
func (h *Handle) NeighList(linkIndex, family int) ([]Neigh, error) {
 | 
						|
	return h.NeighListExecute(Ndmsg{
 | 
						|
		Family: uint8(family),
 | 
						|
		Index:  uint32(linkIndex),
 | 
						|
	})
 | 
						|
}
 | 
						|
 | 
						|
// NeighProxyList returns a list of neighbor proxies in the system.
 | 
						|
// Equivalent to: `ip neighbor show proxy`.
 | 
						|
// The list can be filtered by link, ip family.
 | 
						|
func (h *Handle) NeighProxyList(linkIndex, family int) ([]Neigh, error) {
 | 
						|
	return h.NeighListExecute(Ndmsg{
 | 
						|
		Family: uint8(family),
 | 
						|
		Index:  uint32(linkIndex),
 | 
						|
		Flags:  NTF_PROXY,
 | 
						|
	})
 | 
						|
}
 | 
						|
 | 
						|
// NeighListExecute returns a list of neighbour entries filtered by link, ip family, flag and state.
 | 
						|
func NeighListExecute(msg Ndmsg) ([]Neigh, error) {
 | 
						|
	return pkgHandle.NeighListExecute(msg)
 | 
						|
}
 | 
						|
 | 
						|
// NeighListExecute returns a list of neighbour entries filtered by link, ip family, flag and state.
 | 
						|
func (h *Handle) NeighListExecute(msg Ndmsg) ([]Neigh, error) {
 | 
						|
	req := h.newNetlinkRequest(unix.RTM_GETNEIGH, unix.NLM_F_DUMP)
 | 
						|
	req.AddData(&msg)
 | 
						|
 | 
						|
	msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWNEIGH)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	var res []Neigh
 | 
						|
	for _, m := range msgs {
 | 
						|
		ndm := deserializeNdmsg(m)
 | 
						|
		if msg.Index != 0 && ndm.Index != msg.Index {
 | 
						|
			// Ignore messages from other interfaces
 | 
						|
			continue
 | 
						|
		}
 | 
						|
		if msg.Family != 0 && ndm.Family != msg.Family {
 | 
						|
			continue
 | 
						|
		}
 | 
						|
		if msg.State != 0 && ndm.State != msg.State {
 | 
						|
			continue
 | 
						|
		}
 | 
						|
		if msg.Type != 0 && ndm.Type != msg.Type {
 | 
						|
			continue
 | 
						|
		}
 | 
						|
		if msg.Flags != 0 && ndm.Flags != msg.Flags {
 | 
						|
			continue
 | 
						|
		}
 | 
						|
 | 
						|
		neigh, err := NeighDeserialize(m)
 | 
						|
		if err != nil {
 | 
						|
			continue
 | 
						|
		}
 | 
						|
 | 
						|
		res = append(res, *neigh)
 | 
						|
	}
 | 
						|
 | 
						|
	return res, nil
 | 
						|
}
 | 
						|
 | 
						|
func NeighDeserialize(m []byte) (*Neigh, error) {
 | 
						|
	msg := deserializeNdmsg(m)
 | 
						|
 | 
						|
	neigh := Neigh{
 | 
						|
		LinkIndex: int(msg.Index),
 | 
						|
		Family:    int(msg.Family),
 | 
						|
		State:     int(msg.State),
 | 
						|
		Type:      int(msg.Type),
 | 
						|
		Flags:     int(msg.Flags),
 | 
						|
	}
 | 
						|
 | 
						|
	attrs, err := nl.ParseRouteAttr(m[msg.Len():])
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	for _, attr := range attrs {
 | 
						|
		switch attr.Attr.Type {
 | 
						|
		case NDA_DST:
 | 
						|
			neigh.IP = net.IP(attr.Value)
 | 
						|
		case NDA_LLADDR:
 | 
						|
			// BUG: Is this a bug in the netlink library?
 | 
						|
			// #define RTA_LENGTH(len) (RTA_ALIGN(sizeof(struct rtattr)) + (len))
 | 
						|
			// #define RTA_PAYLOAD(rta) ((int)((rta)->rta_len) - RTA_LENGTH(0))
 | 
						|
			attrLen := attr.Attr.Len - unix.SizeofRtAttr
 | 
						|
			if attrLen == 4 {
 | 
						|
				neigh.LLIPAddr = net.IP(attr.Value)
 | 
						|
			} else if attrLen == 16 {
 | 
						|
				// Can be IPv6 or FireWire HWAddr
 | 
						|
				link, err := LinkByIndex(neigh.LinkIndex)
 | 
						|
				if err == nil && link.Attrs().EncapType == "tunnel6" {
 | 
						|
					neigh.IP = net.IP(attr.Value)
 | 
						|
				} else {
 | 
						|
					neigh.HardwareAddr = net.HardwareAddr(attr.Value)
 | 
						|
				}
 | 
						|
			} else {
 | 
						|
				neigh.HardwareAddr = net.HardwareAddr(attr.Value)
 | 
						|
			}
 | 
						|
		case NDA_VLAN:
 | 
						|
			neigh.Vlan = int(native.Uint16(attr.Value[0:2]))
 | 
						|
		case NDA_VNI:
 | 
						|
			neigh.VNI = int(native.Uint32(attr.Value[0:4]))
 | 
						|
		case NDA_MASTER:
 | 
						|
			neigh.MasterIndex = int(native.Uint32(attr.Value[0:4]))
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return &neigh, nil
 | 
						|
}
 | 
						|
 | 
						|
// NeighSubscribe takes a chan down which notifications will be sent
 | 
						|
// when neighbors are added or deleted. Close the 'done' chan to stop subscription.
 | 
						|
func NeighSubscribe(ch chan<- NeighUpdate, done <-chan struct{}) error {
 | 
						|
	return neighSubscribeAt(netns.None(), netns.None(), ch, done, nil, false)
 | 
						|
}
 | 
						|
 | 
						|
// NeighSubscribeAt works like NeighSubscribe plus it allows the caller
 | 
						|
// to choose the network namespace in which to subscribe (ns).
 | 
						|
func NeighSubscribeAt(ns netns.NsHandle, ch chan<- NeighUpdate, done <-chan struct{}) error {
 | 
						|
	return neighSubscribeAt(ns, netns.None(), ch, done, nil, false)
 | 
						|
}
 | 
						|
 | 
						|
// NeighSubscribeOptions contains a set of options to use with
 | 
						|
// NeighSubscribeWithOptions.
 | 
						|
type NeighSubscribeOptions struct {
 | 
						|
	Namespace     *netns.NsHandle
 | 
						|
	ErrorCallback func(error)
 | 
						|
	ListExisting  bool
 | 
						|
}
 | 
						|
 | 
						|
// NeighSubscribeWithOptions work like NeighSubscribe but enable to
 | 
						|
// provide additional options to modify the behavior. Currently, the
 | 
						|
// namespace can be provided as well as an error callback.
 | 
						|
func NeighSubscribeWithOptions(ch chan<- NeighUpdate, done <-chan struct{}, options NeighSubscribeOptions) error {
 | 
						|
	if options.Namespace == nil {
 | 
						|
		none := netns.None()
 | 
						|
		options.Namespace = &none
 | 
						|
	}
 | 
						|
	return neighSubscribeAt(*options.Namespace, netns.None(), ch, done, options.ErrorCallback, options.ListExisting)
 | 
						|
}
 | 
						|
 | 
						|
func neighSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- NeighUpdate, done <-chan struct{}, cberr func(error), listExisting bool) error {
 | 
						|
	s, err := nl.SubscribeAt(newNs, curNs, unix.NETLINK_ROUTE, unix.RTNLGRP_NEIGH)
 | 
						|
	makeRequest := func(family int) error {
 | 
						|
		req := pkgHandle.newNetlinkRequest(unix.RTM_GETNEIGH,
 | 
						|
			unix.NLM_F_DUMP)
 | 
						|
		infmsg := nl.NewIfInfomsg(family)
 | 
						|
		req.AddData(infmsg)
 | 
						|
		if err := s.Send(req); err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
		return nil
 | 
						|
	}
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	if done != nil {
 | 
						|
		go func() {
 | 
						|
			<-done
 | 
						|
			s.Close()
 | 
						|
		}()
 | 
						|
	}
 | 
						|
	if listExisting {
 | 
						|
		if err := makeRequest(unix.AF_UNSPEC); err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
		// We have to wait for NLMSG_DONE before making AF_BRIDGE request
 | 
						|
	}
 | 
						|
	go func() {
 | 
						|
		defer close(ch)
 | 
						|
		for {
 | 
						|
			msgs, from, err := s.Receive()
 | 
						|
			if err != nil {
 | 
						|
				if cberr != nil {
 | 
						|
					cberr(err)
 | 
						|
				}
 | 
						|
				return
 | 
						|
			}
 | 
						|
			if from.Pid != nl.PidKernel {
 | 
						|
				if cberr != nil {
 | 
						|
					cberr(fmt.Errorf("Wrong sender portid %d, expected %d", from.Pid, nl.PidKernel))
 | 
						|
				}
 | 
						|
				continue
 | 
						|
			}
 | 
						|
			for _, m := range msgs {
 | 
						|
				if m.Header.Type == unix.NLMSG_DONE {
 | 
						|
					if listExisting {
 | 
						|
						// This will be called after handling AF_UNSPEC
 | 
						|
						// list request, we have to wait for NLMSG_DONE
 | 
						|
						// before making another request
 | 
						|
						if err := makeRequest(unix.AF_BRIDGE); err != nil {
 | 
						|
							if cberr != nil {
 | 
						|
								cberr(err)
 | 
						|
							}
 | 
						|
							return
 | 
						|
						}
 | 
						|
						listExisting = false
 | 
						|
					}
 | 
						|
					continue
 | 
						|
				}
 | 
						|
				if m.Header.Type == unix.NLMSG_ERROR {
 | 
						|
					native := nl.NativeEndian()
 | 
						|
					error := int32(native.Uint32(m.Data[0:4]))
 | 
						|
					if error == 0 {
 | 
						|
						continue
 | 
						|
					}
 | 
						|
					if cberr != nil {
 | 
						|
						cberr(syscall.Errno(-error))
 | 
						|
					}
 | 
						|
					return
 | 
						|
				}
 | 
						|
				neigh, err := NeighDeserialize(m.Data)
 | 
						|
				if err != nil {
 | 
						|
					if cberr != nil {
 | 
						|
						cberr(err)
 | 
						|
					}
 | 
						|
					return
 | 
						|
				}
 | 
						|
				ch <- NeighUpdate{Type: m.Header.Type, Neigh: *neigh}
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}()
 | 
						|
 | 
						|
	return nil
 | 
						|
}
 |