vendor: Update vishvanana/netlink dependency
This commit is contained in:
1 parent
7eeb21a999
commit
460e1c5be3
46 files changed
+1772
-229
No files matched your search
Generated
+7
-47
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"ImportPath": "github.com/containernetworking/cni",
|
||||
"GoVersion": "go1.6",
|
||||
"GodepVersion": "v75",
|
||||
"GodepVersion": "v79",
|
||||
"Packages": [
|
||||
"./..."
|
||||
],
|
||||
@@ -39,46 +39,6 @@
|
||||
"Comment": "v1.2.0-29-g7f8ab55",
|
||||
"Rev": "7f8ab55aaf3b86885aa55b762e803744d1674700"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/onsi/ginkgo/ginkgo",
|
||||
"Comment": "v1.2.0-29-g7f8ab55",
|
||||
"Rev": "7f8ab55aaf3b86885aa55b762e803744d1674700"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/onsi/ginkgo/ginkgo/convert",
|
||||
"Comment": "v1.2.0-29-g7f8ab55",
|
||||
"Rev": "7f8ab55aaf3b86885aa55b762e803744d1674700"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/onsi/ginkgo/ginkgo/interrupthandler",
|
||||
"Comment": "v1.2.0-29-g7f8ab55",
|
||||
"Rev": "7f8ab55aaf3b86885aa55b762e803744d1674700"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/onsi/ginkgo/ginkgo/nodot",
|
||||
"Comment": "v1.2.0-29-g7f8ab55",
|
||||
"Rev": "7f8ab55aaf3b86885aa55b762e803744d1674700"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/onsi/ginkgo/ginkgo/testrunner",
|
||||
"Comment": "v1.2.0-29-g7f8ab55",
|
||||
"Rev": "7f8ab55aaf3b86885aa55b762e803744d1674700"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/onsi/ginkgo/ginkgo/testsuite",
|
||||
"Comment": "v1.2.0-29-g7f8ab55",
|
||||
"Rev": "7f8ab55aaf3b86885aa55b762e803744d1674700"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/onsi/ginkgo/ginkgo/watch",
|
||||
"Comment": "v1.2.0-29-g7f8ab55",
|
||||
"Rev": "7f8ab55aaf3b86885aa55b762e803744d1674700"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/onsi/ginkgo/integration",
|
||||
"Comment": "v1.2.0-29-g7f8ab55",
|
||||
"Rev": "7f8ab55aaf3b86885aa55b762e803744d1674700"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/onsi/ginkgo/internal/codelocation",
|
||||
"Comment": "v1.2.0-29-g7f8ab55",
|
||||
@@ -216,19 +176,19 @@
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/vishvananda/netlink",
|
||||
"Rev": "a1f8555521646b5a9800f39c5fd477597697135c"
|
||||
"Rev": "fe3b5664d23a11b52ba59bece4ff29c52772a56b"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/vishvananda/netlink/nl",
|
||||
"Rev": "a1f8555521646b5a9800f39c5fd477597697135c"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/sys/unix",
|
||||
"Rev": "076b546753157f758b316e59bcb51e6807c04057"
|
||||
"Rev": "fe3b5664d23a11b52ba59bece4ff29c52772a56b"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/vishvananda/netns",
|
||||
"Rev": "8ba1072b58e0c2a240eb5f6120165c7776c3e7b8"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/sys/unix",
|
||||
"Rev": "076b546753157f758b316e59bcb51e6807c04057"
|
||||
}
|
||||
]
|
||||
}
|
||||
+1
-1
@@ -21,7 +21,7 @@ $(call testdirs,$(DIRS)):
|
||||
sudo -E go test -test.parallel 4 -timeout 60s -v github.com/vishvananda/netlink/$@
|
||||
|
||||
$(call fmt,$(call testdirs,$(DIRS))):
|
||||
! gofmt -l $(subst fmt-,,$@)/*.go | grep ''
|
||||
! gofmt -l $(subst fmt-,,$@)/*.go | grep -q .
|
||||
|
||||
.PHONY: fmt
|
||||
fmt: $(call fmt,$(call testdirs,$(DIRS)))
|
||||
|
||||
+12
-3
@@ -10,9 +10,11 @@ import (
|
||||
// include a mask, so it stores the address as a net.IPNet.
|
||||
type Addr struct {
|
||||
*net.IPNet
|
||||
Label string
|
||||
Flags int
|
||||
Scope int
|
||||
Label string
|
||||
Flags int
|
||||
Scope int
|
||||
Peer *net.IPNet
|
||||
Broadcast net.IP
|
||||
}
|
||||
|
||||
// String returns $ip/$netmask $label
|
||||
@@ -43,3 +45,10 @@ func (a Addr) Equal(x Addr) bool {
|
||||
// ignore label for comparison
|
||||
return a.IP.Equal(x.IP) && sizea == sizeb
|
||||
}
|
||||
|
||||
func (a Addr) PeerEqual(x Addr) bool {
|
||||
sizea, _ := a.Peer.Mask.Size()
|
||||
sizeb, _ := x.Peer.Mask.Size()
|
||||
// ignore label for comparison
|
||||
return a.Peer.IP.Equal(x.Peer.IP) && sizea == sizeb
|
||||
}
|
||||
+21
-5
@@ -56,17 +56,27 @@ func (h *Handle) addrHandle(link Link, addr *Addr, req *nl.NetlinkRequest) error
|
||||
msg.Prefixlen = uint8(prefixlen)
|
||||
req.AddData(msg)
|
||||
|
||||
var addrData []byte
|
||||
var localAddrData []byte
|
||||
if family == FAMILY_V4 {
|
||||
addrData = addr.IP.To4()
|
||||
localAddrData = addr.IP.To4()
|
||||
} else {
|
||||
addrData = addr.IP.To16()
|
||||
localAddrData = addr.IP.To16()
|
||||
}
|
||||
|
||||
localData := nl.NewRtAttr(syscall.IFA_LOCAL, addrData)
|
||||
localData := nl.NewRtAttr(syscall.IFA_LOCAL, localAddrData)
|
||||
req.AddData(localData)
|
||||
var peerAddrData []byte
|
||||
if addr.Peer != nil {
|
||||
if family == FAMILY_V4 {
|
||||
peerAddrData = addr.Peer.IP.To4()
|
||||
} else {
|
||||
peerAddrData = addr.Peer.IP.To16()
|
||||
}
|
||||
} else {
|
||||
peerAddrData = localAddrData
|
||||
}
|
||||
|
||||
addressData := nl.NewRtAttr(syscall.IFA_ADDRESS, addrData)
|
||||
addressData := nl.NewRtAttr(syscall.IFA_ADDRESS, peerAddrData)
|
||||
req.AddData(addressData)
|
||||
|
||||
if addr.Flags != 0 {
|
||||
@@ -80,6 +90,10 @@ func (h *Handle) addrHandle(link Link, addr *Addr, req *nl.NetlinkRequest) error
|
||||
}
|
||||
}
|
||||
|
||||
if addr.Broadcast != nil {
|
||||
req.AddData(nl.NewRtAttr(syscall.IFA_BROADCAST, addr.Broadcast))
|
||||
}
|
||||
|
||||
if addr.Label != "" {
|
||||
labelData := nl.NewRtAttr(syscall.IFA_LABEL, nl.ZeroTerminated(addr.Label))
|
||||
req.AddData(labelData)
|
||||
@@ -161,11 +175,13 @@ func parseAddr(m []byte) (addr Addr, family, index int, err error) {
|
||||
IP: attr.Value,
|
||||
Mask: net.CIDRMask(int(msg.Prefixlen), 8*len(attr.Value)),
|
||||
}
|
||||
addr.Peer = dst
|
||||
case syscall.IFA_LOCAL:
|
||||
local = &net.IPNet{
|
||||
IP: attr.Value,
|
||||
Mask: net.CIDRMask(int(msg.Prefixlen), 8*len(attr.Value)),
|
||||
}
|
||||
addr.IPNet = local
|
||||
case syscall.IFA_LABEL:
|
||||
addr.Label = string(attr.Value[:len(attr.Value)-1])
|
||||
case IFA_FLAGS:
|
||||
|
||||
+25
@@ -1,7 +1,9 @@
|
||||
package netlink
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/vishvananda/netlink/nl"
|
||||
"github.com/vishvananda/netns"
|
||||
@@ -33,6 +35,29 @@ func NewHandle(nlFamilies ...int) (*Handle, error) {
|
||||
return newHandle(netns.None(), netns.None(), nlFamilies...)
|
||||
}
|
||||
|
||||
// SetSocketTimeout sets the send and receive timeout for each socket in the
|
||||
// netlink handle. Although the socket timeout has granularity of one
|
||||
// microsecond, the effective granularity is floored by the kernel timer tick,
|
||||
// which default value is four milliseconds.
|
||||
func (h *Handle) SetSocketTimeout(to time.Duration) error {
|
||||
if to < time.Microsecond {
|
||||
return fmt.Errorf("invalid timeout, minimul value is %s", time.Microsecond)
|
||||
}
|
||||
tv := syscall.NsecToTimeval(to.Nanoseconds())
|
||||
for _, sh := range h.sockets {
|
||||
fd := sh.Socket.GetFd()
|
||||
err := syscall.SetsockoptTimeval(fd, syscall.SOL_SOCKET, syscall.SO_RCVTIMEO, &tv)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = syscall.SetsockoptTimeval(fd, syscall.SOL_SOCKET, syscall.SO_SNDTIMEO, &tv)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewHandle returns a netlink handle on the network namespace
|
||||
// specified by ns. If ns=netns.None(), current network namespace
|
||||
// will be assumed
|
||||
|
||||
+218
@@ -0,0 +1,218 @@
|
||||
// +build !linux
|
||||
|
||||
package netlink
|
||||
|
||||
import (
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/vishvananda/netns"
|
||||
)
|
||||
|
||||
type Handle struct{}
|
||||
|
||||
func NewHandle(nlFamilies ...int) (*Handle, error) {
|
||||
return nil, ErrNotImplemented
|
||||
}
|
||||
|
||||
func NewHandleAt(ns netns.NsHandle, nlFamilies ...int) (*Handle, error) {
|
||||
return nil, ErrNotImplemented
|
||||
}
|
||||
|
||||
func NewHandleAtFrom(newNs, curNs netns.NsHandle) (*Handle, error) {
|
||||
return nil, ErrNotImplemented
|
||||
}
|
||||
|
||||
func (h *Handle) Delete() {}
|
||||
|
||||
func (h *Handle) SupportsNetlinkFamily(nlFamily int) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (h *Handle) SetSocketTimeout(to time.Duration) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func (h *Handle) SetPromiscOn(link Link) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func (h *Handle) SetPromiscOff(link Link) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func (h *Handle) LinkSetUp(link Link) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func (h *Handle) LinkSetDown(link Link) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func (h *Handle) LinkSetMTU(link Link, mtu int) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func (h *Handle) LinkSetName(link Link, name string) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func (h *Handle) LinkSetAlias(link Link, name string) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func (h *Handle) LinkSetHardwareAddr(link Link, hwaddr net.HardwareAddr) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func (h *Handle) LinkSetVfHardwareAddr(link Link, vf int, hwaddr net.HardwareAddr) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func (h *Handle) LinkSetVfVlan(link Link, vf, vlan int) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func (h *Handle) LinkSetVfTxRate(link Link, vf, rate int) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func (h *Handle) LinkSetMaster(link Link, master *Bridge) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func (h *Handle) LinkSetNoMaster(link Link) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func (h *Handle) LinkSetMasterByIndex(link Link, masterIndex int) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func (h *Handle) LinkSetNsPid(link Link, nspid int) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func (h *Handle) LinkSetNsFd(link Link, fd int) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func (h *Handle) LinkAdd(link Link) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func (h *Handle) LinkDel(link Link) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func (h *Handle) LinkByName(name string) (Link, error) {
|
||||
return nil, ErrNotImplemented
|
||||
}
|
||||
|
||||
func (h *Handle) LinkByAlias(alias string) (Link, error) {
|
||||
return nil, ErrNotImplemented
|
||||
}
|
||||
|
||||
func (h *Handle) LinkByIndex(index int) (Link, error) {
|
||||
return nil, ErrNotImplemented
|
||||
}
|
||||
|
||||
func (h *Handle) LinkList() ([]Link, error) {
|
||||
return nil, ErrNotImplemented
|
||||
}
|
||||
|
||||
func (h *Handle) LinkSetHairpin(link Link, mode bool) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func (h *Handle) LinkSetGuard(link Link, mode bool) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func (h *Handle) LinkSetFastLeave(link Link, mode bool) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func (h *Handle) LinkSetLearning(link Link, mode bool) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func (h *Handle) LinkSetRootBlock(link Link, mode bool) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func (h *Handle) LinkSetFlood(link Link, mode bool) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func (h *Handle) setProtinfoAttr(link Link, mode bool, attr int) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func (h *Handle) AddrAdd(link Link, addr *Addr) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func (h *Handle) AddrDel(link Link, addr *Addr) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func (h *Handle) AddrList(link Link, family int) ([]Addr, error) {
|
||||
return nil, ErrNotImplemented
|
||||
}
|
||||
|
||||
func (h *Handle) ClassDel(class Class) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func (h *Handle) ClassChange(class Class) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func (h *Handle) ClassReplace(class Class) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func (h *Handle) ClassAdd(class Class) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func (h *Handle) ClassList(link Link, parent uint32) ([]Class, error) {
|
||||
return nil, ErrNotImplemented
|
||||
}
|
||||
|
||||
func (h *Handle) FilterDel(filter Filter) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func (h *Handle) FilterAdd(filter Filter) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func (h *Handle) FilterList(link Link, parent uint32) ([]Filter, error) {
|
||||
return nil, ErrNotImplemented
|
||||
}
|
||||
|
||||
func (h *Handle) NeighAdd(neigh *Neigh) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func (h *Handle) NeighSet(neigh *Neigh) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func (h *Handle) NeighAppend(neigh *Neigh) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func (h *Handle) NeighDel(neigh *Neigh) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func (h *Handle) NeighList(linkIndex, family int) ([]Neigh, error) {
|
||||
return nil, ErrNotImplemented
|
||||
}
|
||||
|
||||
func (h *Handle) NeighProxyList(linkIndex, family int) ([]Neigh, error) {
|
||||
return nil, ErrNotImplemented
|
||||
}
|
||||
+147
-5
@@ -35,6 +35,41 @@ type LinkAttrs struct {
|
||||
Promisc int
|
||||
Xdp *LinkXdp
|
||||
EncapType string
|
||||
Protinfo *Protinfo
|
||||
OperState LinkOperState
|
||||
}
|
||||
|
||||
// LinkOperState represents the values of the IFLA_OPERSTATE link
|
||||
// attribute, which contains the RFC2863 state of the interface.
|
||||
type LinkOperState uint8
|
||||
|
||||
const (
|
||||
OperUnknown = iota // Status can't be determined.
|
||||
OperNotPresent // Some component is missing.
|
||||
OperDown // Down.
|
||||
OperLowerLayerDown // Down due to state of lower layer.
|
||||
OperTesting // In some test mode.
|
||||
OperDormant // Not up but pending an external event.
|
||||
OperUp // Up, ready to send packets.
|
||||
)
|
||||
|
||||
func (s LinkOperState) String() string {
|
||||
switch s {
|
||||
case OperNotPresent:
|
||||
return "not-present"
|
||||
case OperDown:
|
||||
return "down"
|
||||
case OperLowerLayerDown:
|
||||
return "lower-layer-down"
|
||||
case OperTesting:
|
||||
return "testing"
|
||||
case OperDormant:
|
||||
return "dormant"
|
||||
case OperUp:
|
||||
return "up"
|
||||
default:
|
||||
return "unknown"
|
||||
}
|
||||
}
|
||||
|
||||
// NewLinkAttrs returns LinkAttrs structure filled with default values
|
||||
@@ -44,10 +79,12 @@ func NewLinkAttrs() LinkAttrs {
|
||||
}
|
||||
}
|
||||
|
||||
type LinkStatistics LinkStatistics64
|
||||
|
||||
/*
|
||||
Ref: struct rtnl_link_stats {...}
|
||||
*/
|
||||
type LinkStatistics struct {
|
||||
type LinkStatistics32 struct {
|
||||
RxPackets uint32
|
||||
TxPackets uint32
|
||||
RxBytes uint32
|
||||
@@ -73,6 +110,63 @@ type LinkStatistics struct {
|
||||
TxCompressed uint32
|
||||
}
|
||||
|
||||
func (s32 LinkStatistics32) to64() *LinkStatistics64 {
|
||||
return &LinkStatistics64{
|
||||
RxPackets: uint64(s32.RxPackets),
|
||||
TxPackets: uint64(s32.TxPackets),
|
||||
RxBytes: uint64(s32.RxBytes),
|
||||
TxBytes: uint64(s32.TxBytes),
|
||||
RxErrors: uint64(s32.RxErrors),
|
||||
TxErrors: uint64(s32.TxErrors),
|
||||
RxDropped: uint64(s32.RxDropped),
|
||||
TxDropped: uint64(s32.TxDropped),
|
||||
Multicast: uint64(s32.Multicast),
|
||||
Collisions: uint64(s32.Collisions),
|
||||
RxLengthErrors: uint64(s32.RxLengthErrors),
|
||||
RxOverErrors: uint64(s32.RxOverErrors),
|
||||
RxCrcErrors: uint64(s32.RxCrcErrors),
|
||||
RxFrameErrors: uint64(s32.RxFrameErrors),
|
||||
RxFifoErrors: uint64(s32.RxFifoErrors),
|
||||
RxMissedErrors: uint64(s32.RxMissedErrors),
|
||||
TxAbortedErrors: uint64(s32.TxAbortedErrors),
|
||||
TxCarrierErrors: uint64(s32.TxCarrierErrors),
|
||||
TxFifoErrors: uint64(s32.TxFifoErrors),
|
||||
TxHeartbeatErrors: uint64(s32.TxHeartbeatErrors),
|
||||
TxWindowErrors: uint64(s32.TxWindowErrors),
|
||||
RxCompressed: uint64(s32.RxCompressed),
|
||||
TxCompressed: uint64(s32.TxCompressed),
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Ref: struct rtnl_link_stats64 {...}
|
||||
*/
|
||||
type LinkStatistics64 struct {
|
||||
RxPackets uint64
|
||||
TxPackets uint64
|
||||
RxBytes uint64
|
||||
TxBytes uint64
|
||||
RxErrors uint64
|
||||
TxErrors uint64
|
||||
RxDropped uint64
|
||||
TxDropped uint64
|
||||
Multicast uint64
|
||||
Collisions uint64
|
||||
RxLengthErrors uint64
|
||||
RxOverErrors uint64
|
||||
RxCrcErrors uint64
|
||||
RxFrameErrors uint64
|
||||
RxFifoErrors uint64
|
||||
RxMissedErrors uint64
|
||||
TxAbortedErrors uint64
|
||||
TxCarrierErrors uint64
|
||||
TxFifoErrors uint64
|
||||
TxHeartbeatErrors uint64
|
||||
TxWindowErrors uint64
|
||||
RxCompressed uint64
|
||||
TxCompressed uint64
|
||||
}
|
||||
|
||||
type LinkXdp struct {
|
||||
Fd int
|
||||
Attached bool
|
||||
@@ -301,31 +395,31 @@ func StringToBondMode(s string) BondMode {
|
||||
|
||||
// Possible BondMode
|
||||
const (
|
||||
BOND_MODE_802_3AD BondMode = iota
|
||||
BOND_MODE_BALANCE_RR
|
||||
BOND_MODE_BALANCE_RR BondMode = iota
|
||||
BOND_MODE_ACTIVE_BACKUP
|
||||
BOND_MODE_BALANCE_XOR
|
||||
BOND_MODE_BROADCAST
|
||||
BOND_MODE_802_3AD
|
||||
BOND_MODE_BALANCE_TLB
|
||||
BOND_MODE_BALANCE_ALB
|
||||
BOND_MODE_UNKNOWN
|
||||
)
|
||||
|
||||
var bondModeToString = map[BondMode]string{
|
||||
BOND_MODE_802_3AD: "802.3ad",
|
||||
BOND_MODE_BALANCE_RR: "balance-rr",
|
||||
BOND_MODE_ACTIVE_BACKUP: "active-backup",
|
||||
BOND_MODE_BALANCE_XOR: "balance-xor",
|
||||
BOND_MODE_BROADCAST: "broadcast",
|
||||
BOND_MODE_802_3AD: "802.3ad",
|
||||
BOND_MODE_BALANCE_TLB: "balance-tlb",
|
||||
BOND_MODE_BALANCE_ALB: "balance-alb",
|
||||
}
|
||||
var StringToBondModeMap = map[string]BondMode{
|
||||
"802.3ad": BOND_MODE_802_3AD,
|
||||
"balance-rr": BOND_MODE_BALANCE_RR,
|
||||
"active-backup": BOND_MODE_ACTIVE_BACKUP,
|
||||
"balance-xor": BOND_MODE_BALANCE_XOR,
|
||||
"broadcast": BOND_MODE_BROADCAST,
|
||||
"802.3ad": BOND_MODE_802_3AD,
|
||||
"balance-tlb": BOND_MODE_BALANCE_TLB,
|
||||
"balance-alb": BOND_MODE_BALANCE_ALB,
|
||||
}
|
||||
@@ -589,6 +683,54 @@ func (gretap *Gretap) Type() string {
|
||||
return "gretap"
|
||||
}
|
||||
|
||||
type Iptun struct {
|
||||
LinkAttrs
|
||||
Ttl uint8
|
||||
Tos uint8
|
||||
PMtuDisc uint8
|
||||
Link uint32
|
||||
Local net.IP
|
||||
Remote net.IP
|
||||
}
|
||||
|
||||
func (iptun *Iptun) Attrs() *LinkAttrs {
|
||||
return &iptun.LinkAttrs
|
||||
}
|
||||
|
||||
func (iptun *Iptun) Type() string {
|
||||
return "ipip"
|
||||
}
|
||||
|
||||
type Vti struct {
|
||||
LinkAttrs
|
||||
IKey uint32
|
||||
OKey uint32
|
||||
Link uint32
|
||||
Local net.IP
|
||||
Remote net.IP
|
||||
}
|
||||
|
||||
func (vti *Vti) Attrs() *LinkAttrs {
|
||||
return &vti.LinkAttrs
|
||||
}
|
||||
|
||||
func (iptun *Vti) Type() string {
|
||||
return "vti"
|
||||
}
|
||||
|
||||
type Vrf struct {
|
||||
LinkAttrs
|
||||
Table uint32
|
||||
}
|
||||
|
||||
func (vrf *Vrf) Attrs() *LinkAttrs {
|
||||
return &vrf.LinkAttrs
|
||||
}
|
||||
|
||||
func (vrf *Vrf) Type() string {
|
||||
return "vrf"
|
||||
}
|
||||
|
||||
// iproute2 supported devices;
|
||||
// vlan | veth | vcan | dummy | ifb | macvlan | macvtap |
|
||||
// bridge | bond | ipoib | ip6tnl | ipip | sit | vxlan |
|
||||
|
||||
+183
-31
@@ -13,7 +13,11 @@ import (
|
||||
"github.com/vishvananda/netns"
|
||||
)
|
||||
|
||||
const SizeofLinkStats = 0x5c
|
||||
const (
|
||||
SizeofLinkStats32 = 0x5c
|
||||
SizeofLinkStats64 = 0xd8
|
||||
IFLA_STATS64 = 0x17 // syscall pkg does not contain this one
|
||||
)
|
||||
|
||||
const (
|
||||
TUNTAP_MODE_TUN TuntapMode = syscall.IFF_TUN
|
||||
@@ -25,7 +29,6 @@ const (
|
||||
TUNTAP_ONE_QUEUE TuntapFlag = syscall.IFF_ONE_QUEUE
|
||||
)
|
||||
|
||||
var native = nl.NativeEndian()
|
||||
var lookupByDump = false
|
||||
|
||||
var macvlanModes = [...]uint32{
|
||||
@@ -298,6 +301,36 @@ func (h *Handle) LinkSetVfVlan(link Link, vf, vlan int) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// LinkSetVfTxRate sets the tx rate of a vf for the link.
|
||||
// Equivalent to: `ip link set $link vf $vf rate $rate`
|
||||
func LinkSetVfTxRate(link Link, vf, rate int) error {
|
||||
return pkgHandle.LinkSetVfTxRate(link, vf, rate)
|
||||
}
|
||||
|
||||
// LinkSetVfTxRate sets the tx rate of a vf for the link.
|
||||
// Equivalent to: `ip link set $link vf $vf rate $rate`
|
||||
func (h *Handle) LinkSetVfTxRate(link Link, vf, rate int) error {
|
||||
base := link.Attrs()
|
||||
h.ensureIndex(base)
|
||||
req := h.newNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
|
||||
|
||||
msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
|
||||
msg.Index = int32(base.Index)
|
||||
req.AddData(msg)
|
||||
|
||||
data := nl.NewRtAttr(nl.IFLA_VFINFO_LIST, nil)
|
||||
info := nl.NewRtAttrChild(data, nl.IFLA_VF_INFO, nil)
|
||||
vfmsg := nl.VfTxRate{
|
||||
Vf: uint32(vf),
|
||||
Rate: uint32(rate),
|
||||
}
|
||||
nl.NewRtAttrChild(info, nl.IFLA_VF_TX_RATE, vfmsg.Serialize())
|
||||
req.AddData(data)
|
||||
|
||||
_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
|
||||
return err
|
||||
}
|
||||
|
||||
// LinkSetMaster sets the master of the link device.
|
||||
// Equivalent to: `ip link set $link master $master`
|
||||
func LinkSetMaster(link Link, master *Bridge) error {
|
||||
@@ -753,6 +786,12 @@ func (h *Handle) LinkAdd(link Link) error {
|
||||
}
|
||||
} else if gretap, ok := link.(*Gretap); ok {
|
||||
addGretapAttrs(gretap, linkInfo)
|
||||
} else if iptun, ok := link.(*Iptun); ok {
|
||||
addIptunAttrs(iptun, linkInfo)
|
||||
} else if vti, ok := link.(*Vti); ok {
|
||||
addVtiAttrs(vti, linkInfo)
|
||||
} else if vrf, ok := link.(*Vrf); ok {
|
||||
addVrfAttrs(vrf, linkInfo)
|
||||
}
|
||||
|
||||
req.AddData(linkInfo)
|
||||
@@ -919,7 +958,7 @@ func execGetLink(req *nl.NetlinkRequest) (Link, error) {
|
||||
return nil, fmt.Errorf("Link not found")
|
||||
|
||||
case len(msgs) == 1:
|
||||
return linkDeserialize(msgs[0])
|
||||
return LinkDeserialize(nil, msgs[0])
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("More than one link found")
|
||||
@@ -928,7 +967,7 @@ func execGetLink(req *nl.NetlinkRequest) (Link, error) {
|
||||
|
||||
// linkDeserialize deserializes a raw message received from netlink into
|
||||
// a link object.
|
||||
func linkDeserialize(m []byte) (Link, error) {
|
||||
func LinkDeserialize(hdr *syscall.NlMsghdr, m []byte) (Link, error) {
|
||||
msg := nl.DeserializeIfInfomsg(m)
|
||||
|
||||
attrs, err := nl.ParseRouteAttr(m[msg.Len():])
|
||||
@@ -940,8 +979,12 @@ func linkDeserialize(m []byte) (Link, error) {
|
||||
if msg.Flags&syscall.IFF_PROMISC != 0 {
|
||||
base.Promisc = 1
|
||||
}
|
||||
var link Link
|
||||
linkType := ""
|
||||
var (
|
||||
link Link
|
||||
stats32 []byte
|
||||
stats64 []byte
|
||||
linkType string
|
||||
)
|
||||
for _, attr := range attrs {
|
||||
switch attr.Attr.Type {
|
||||
case syscall.IFLA_LINKINFO:
|
||||
@@ -976,6 +1019,12 @@ func linkDeserialize(m []byte) (Link, error) {
|
||||
link = &Macvtap{}
|
||||
case "gretap":
|
||||
link = &Gretap{}
|
||||
case "ipip":
|
||||
link = &Iptun{}
|
||||
case "vti":
|
||||
link = &Vti{}
|
||||
case "vrf":
|
||||
link = &Vrf{}
|
||||
default:
|
||||
link = &GenericLink{LinkType: linkType}
|
||||
}
|
||||
@@ -999,6 +1048,12 @@ func linkDeserialize(m []byte) (Link, error) {
|
||||
parseMacvtapData(link, data)
|
||||
case "gretap":
|
||||
parseGretapData(link, data)
|
||||
case "ipip":
|
||||
parseIptunData(link, data)
|
||||
case "vti":
|
||||
parseVtiData(link, data)
|
||||
case "vrf":
|
||||
parseVrfData(link, data)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1025,15 +1080,35 @@ func linkDeserialize(m []byte) (Link, error) {
|
||||
case syscall.IFLA_IFALIAS:
|
||||
base.Alias = string(attr.Value[:len(attr.Value)-1])
|
||||
case syscall.IFLA_STATS:
|
||||
base.Statistics = parseLinkStats(attr.Value[:])
|
||||
stats32 = attr.Value[:]
|
||||
case IFLA_STATS64:
|
||||
stats64 = attr.Value[:]
|
||||
case nl.IFLA_XDP:
|
||||
xdp, err := parseLinkXdp(attr.Value[:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
base.Xdp = xdp
|
||||
case syscall.IFLA_PROTINFO | syscall.NLA_F_NESTED:
|
||||
if hdr != nil && hdr.Type == syscall.RTM_NEWLINK &&
|
||||
msg.Family == syscall.AF_BRIDGE {
|
||||
attrs, err := nl.ParseRouteAttr(attr.Value[:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
base.Protinfo = parseProtinfo(attrs)
|
||||
}
|
||||
case syscall.IFLA_OPERSTATE:
|
||||
base.OperState = LinkOperState(uint8(attr.Value[0]))
|
||||
}
|
||||
}
|
||||
|
||||
if stats64 != nil {
|
||||
base.Statistics = parseLinkStats64(stats64)
|
||||
} else if stats32 != nil {
|
||||
base.Statistics = parseLinkStats32(stats32)
|
||||
}
|
||||
|
||||
// Links that don't have IFLA_INFO_KIND are hardware devices
|
||||
if link == nil {
|
||||
link = &Device{}
|
||||
@@ -1066,7 +1141,7 @@ func (h *Handle) LinkList() ([]Link, error) {
|
||||
|
||||
var res []Link
|
||||
for _, m := range msgs {
|
||||
link, err := linkDeserialize(m)
|
||||
link, err := LinkDeserialize(nil, m)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -1115,7 +1190,7 @@ func linkSubscribe(newNs, curNs netns.NsHandle, ch chan<- LinkUpdate, done <-cha
|
||||
}
|
||||
for _, m := range msgs {
|
||||
ifmsg := nl.DeserializeIfInfomsg(m.Data)
|
||||
link, err := linkDeserialize(m.Data)
|
||||
link, err := LinkDeserialize(&m.Header, m.Data)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@@ -1367,26 +1442,6 @@ func linkFlags(rawFlags uint32) net.Flags {
|
||||
return f
|
||||
}
|
||||
|
||||
func htonl(val uint32) []byte {
|
||||
bytes := make([]byte, 4)
|
||||
binary.BigEndian.PutUint32(bytes, val)
|
||||
return bytes
|
||||
}
|
||||
|
||||
func htons(val uint16) []byte {
|
||||
bytes := make([]byte, 2)
|
||||
binary.BigEndian.PutUint16(bytes, val)
|
||||
return bytes
|
||||
}
|
||||
|
||||
func ntohl(buf []byte) uint32 {
|
||||
return binary.BigEndian.Uint32(buf)
|
||||
}
|
||||
|
||||
func ntohs(buf []byte) uint16 {
|
||||
return binary.BigEndian.Uint16(buf)
|
||||
}
|
||||
|
||||
func addGretapAttrs(gretap *Gretap, linkInfo *nl.RtAttr) {
|
||||
data := nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_DATA, nil)
|
||||
|
||||
@@ -1460,8 +1515,12 @@ func parseGretapData(link Link, data []syscall.NetlinkRouteAttr) {
|
||||
}
|
||||
}
|
||||
|
||||
func parseLinkStats(data []byte) *LinkStatistics {
|
||||
return (*LinkStatistics)(unsafe.Pointer(&data[0:SizeofLinkStats][0]))
|
||||
func parseLinkStats32(data []byte) *LinkStatistics {
|
||||
return (*LinkStatistics)((*LinkStatistics32)(unsafe.Pointer(&data[0:SizeofLinkStats32][0])).to64())
|
||||
}
|
||||
|
||||
func parseLinkStats64(data []byte) *LinkStatistics {
|
||||
return (*LinkStatistics)((*LinkStatistics64)(unsafe.Pointer(&data[0:SizeofLinkStats64][0])))
|
||||
}
|
||||
|
||||
func addXdpAttrs(xdp *LinkXdp, req *nl.NetlinkRequest) {
|
||||
@@ -1488,3 +1547,96 @@ func parseLinkXdp(data []byte) (*LinkXdp, error) {
|
||||
}
|
||||
return xdp, nil
|
||||
}
|
||||
|
||||
func addIptunAttrs(iptun *Iptun, linkInfo *nl.RtAttr) {
|
||||
data := nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_DATA, nil)
|
||||
|
||||
ip := iptun.Local.To4()
|
||||
if ip != nil {
|
||||
nl.NewRtAttrChild(data, nl.IFLA_IPTUN_LOCAL, []byte(ip))
|
||||
}
|
||||
|
||||
ip = iptun.Remote.To4()
|
||||
if ip != nil {
|
||||
nl.NewRtAttrChild(data, nl.IFLA_IPTUN_REMOTE, []byte(ip))
|
||||
}
|
||||
|
||||
if iptun.Link != 0 {
|
||||
nl.NewRtAttrChild(data, nl.IFLA_IPTUN_LINK, nl.Uint32Attr(iptun.Link))
|
||||
}
|
||||
nl.NewRtAttrChild(data, nl.IFLA_IPTUN_PMTUDISC, nl.Uint8Attr(iptun.PMtuDisc))
|
||||
nl.NewRtAttrChild(data, nl.IFLA_IPTUN_TTL, nl.Uint8Attr(iptun.Ttl))
|
||||
nl.NewRtAttrChild(data, nl.IFLA_IPTUN_TOS, nl.Uint8Attr(iptun.Tos))
|
||||
}
|
||||
|
||||
func parseIptunData(link Link, data []syscall.NetlinkRouteAttr) {
|
||||
iptun := link.(*Iptun)
|
||||
for _, datum := range data {
|
||||
switch datum.Attr.Type {
|
||||
case nl.IFLA_IPTUN_LOCAL:
|
||||
iptun.Local = net.IP(datum.Value[0:4])
|
||||
case nl.IFLA_IPTUN_REMOTE:
|
||||
iptun.Remote = net.IP(datum.Value[0:4])
|
||||
case nl.IFLA_IPTUN_TTL:
|
||||
iptun.Ttl = uint8(datum.Value[0])
|
||||
case nl.IFLA_IPTUN_TOS:
|
||||
iptun.Tos = uint8(datum.Value[0])
|
||||
case nl.IFLA_IPTUN_PMTUDISC:
|
||||
iptun.PMtuDisc = uint8(datum.Value[0])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func addVtiAttrs(vti *Vti, linkInfo *nl.RtAttr) {
|
||||
data := nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_DATA, nil)
|
||||
|
||||
ip := vti.Local.To4()
|
||||
if ip != nil {
|
||||
nl.NewRtAttrChild(data, nl.IFLA_VTI_LOCAL, []byte(ip))
|
||||
}
|
||||
|
||||
ip = vti.Remote.To4()
|
||||
if ip != nil {
|
||||
nl.NewRtAttrChild(data, nl.IFLA_VTI_REMOTE, []byte(ip))
|
||||
}
|
||||
|
||||
if vti.Link != 0 {
|
||||
nl.NewRtAttrChild(data, nl.IFLA_VTI_LINK, nl.Uint32Attr(vti.Link))
|
||||
}
|
||||
|
||||
nl.NewRtAttrChild(data, nl.IFLA_VTI_IKEY, htonl(vti.IKey))
|
||||
nl.NewRtAttrChild(data, nl.IFLA_VTI_OKEY, htonl(vti.OKey))
|
||||
}
|
||||
|
||||
func parseVtiData(link Link, data []syscall.NetlinkRouteAttr) {
|
||||
vti := link.(*Vti)
|
||||
for _, datum := range data {
|
||||
switch datum.Attr.Type {
|
||||
case nl.IFLA_VTI_LOCAL:
|
||||
vti.Local = net.IP(datum.Value[0:4])
|
||||
case nl.IFLA_VTI_REMOTE:
|
||||
vti.Remote = net.IP(datum.Value[0:4])
|
||||
case nl.IFLA_VTI_IKEY:
|
||||
vti.IKey = ntohl(datum.Value[0:4])
|
||||
case nl.IFLA_VTI_OKEY:
|
||||
vti.OKey = ntohl(datum.Value[0:4])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func addVrfAttrs(vrf *Vrf, linkInfo *nl.RtAttr) {
|
||||
data := nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_DATA, nil)
|
||||
b := make([]byte, 4)
|
||||
native.PutUint32(b, uint32(vrf.Table))
|
||||
nl.NewRtAttrChild(data, nl.IFLA_VRF_TABLE, b)
|
||||
}
|
||||
|
||||
func parseVrfData(link Link, data []syscall.NetlinkRouteAttr) {
|
||||
vrf := link.(*Vrf)
|
||||
for _, datum := range data {
|
||||
switch datum.Attr.Type {
|
||||
case nl.IFLA_VRF_TABLE:
|
||||
vrf.Table = native.Uint32(datum.Value[0:4])
|
||||
}
|
||||
}
|
||||
}
|
||||
+9
-1
@@ -8,7 +8,15 @@
|
||||
// interface that is loosly modeled on the iproute2 cli.
|
||||
package netlink
|
||||
|
||||
import "net"
|
||||
import (
|
||||
"errors"
|
||||
"net"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrNotImplemented is returned when a requested feature is not implemented.
|
||||
ErrNotImplemented = errors.New("not implemented")
|
||||
)
|
||||
|
||||
// ParseIPNet parses a string in ip/net format and returns a net.IPNet.
|
||||
// This is valuable because addresses in netlink are often IPNets and
|
||||
|
||||
+4
-3
@@ -4,7 +4,8 @@ import "github.com/vishvananda/netlink/nl"
|
||||
|
||||
// Family type definitions
|
||||
const (
|
||||
FAMILY_ALL = nl.FAMILY_ALL
|
||||
FAMILY_V4 = nl.FAMILY_V4
|
||||
FAMILY_V6 = nl.FAMILY_V6
|
||||
FAMILY_ALL = nl.FAMILY_ALL
|
||||
FAMILY_V4 = nl.FAMILY_V4
|
||||
FAMILY_V6 = nl.FAMILY_V6
|
||||
FAMILY_MPLS = nl.FAMILY_MPLS
|
||||
)
|
||||
+89
-19
@@ -2,43 +2,109 @@
|
||||
|
||||
package netlink
|
||||
|
||||
import (
|
||||
"errors"
|
||||
)
|
||||
import "net"
|
||||
|
||||
var (
|
||||
ErrNotImplemented = errors.New("not implemented")
|
||||
)
|
||||
|
||||
func LinkSetUp(link *Link) error {
|
||||
func LinkSetUp(link Link) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func LinkSetDown(link *Link) error {
|
||||
func LinkSetDown(link Link) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func LinkSetMTU(link *Link, mtu int) error {
|
||||
func LinkSetMTU(link Link, mtu int) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func LinkSetMaster(link *Link, master *Link) error {
|
||||
func LinkSetMaster(link Link, master *Link) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func LinkSetNsPid(link *Link, nspid int) error {
|
||||
func LinkSetNsPid(link Link, nspid int) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func LinkSetNsFd(link *Link, fd int) error {
|
||||
func LinkSetNsFd(link Link, fd int) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func LinkAdd(link *Link) error {
|
||||
func LinkSetName(link Link, name string) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func LinkDel(link *Link) error {
|
||||
func LinkSetAlias(link Link, name string) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func LinkSetHardwareAddr(link Link, hwaddr net.HardwareAddr) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func LinkSetVfHardwareAddr(link Link, vf int, hwaddr net.HardwareAddr) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func LinkSetVfVlan(link Link, vf, vlan int) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func LinkSetVfTxRate(link Link, vf, rate int) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func LinkSetNoMaster(link Link) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func LinkSetMasterByIndex(link Link, masterIndex int) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func LinkSetXdpFd(link Link, fd int) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func LinkByName(name string) (Link, error) {
|
||||
return nil, ErrNotImplemented
|
||||
}
|
||||
|
||||
func LinkByAlias(alias string) (Link, error) {
|
||||
return nil, ErrNotImplemented
|
||||
}
|
||||
|
||||
func LinkByIndex(index int) (Link, error) {
|
||||
return nil, ErrNotImplemented
|
||||
}
|
||||
|
||||
func LinkSetHairpin(link Link, mode bool) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func LinkSetGuard(link Link, mode bool) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func LinkSetFastLeave(link Link, mode bool) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func LinkSetLearning(link Link, mode bool) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func LinkSetRootBlock(link Link, mode bool) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func LinkSetFlood(link Link, mode bool) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func LinkAdd(link Link) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func LinkDel(link Link) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
@@ -70,15 +136,15 @@ func LinkList() ([]Link, error) {
|
||||
return nil, ErrNotImplemented
|
||||
}
|
||||
|
||||
func AddrAdd(link *Link, addr *Addr) error {
|
||||
func AddrAdd(link Link, addr *Addr) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func AddrDel(link *Link, addr *Addr) error {
|
||||
func AddrDel(link Link, addr *Addr) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func AddrList(link *Link, family int) ([]Addr, error) {
|
||||
func AddrList(link Link, family int) ([]Addr, error) {
|
||||
return nil, ErrNotImplemented
|
||||
}
|
||||
|
||||
@@ -90,7 +156,7 @@ func RouteDel(route *Route) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func RouteList(link *Link, family int) ([]Route, error) {
|
||||
func RouteList(link Link, family int) ([]Route, error) {
|
||||
return nil, ErrNotImplemented
|
||||
}
|
||||
|
||||
@@ -141,3 +207,7 @@ func NeighList(linkIndex, family int) ([]Neigh, error) {
|
||||
func NeighDeserialize(m []byte) (*Neigh, error) {
|
||||
return nil, ErrNotImplemented
|
||||
}
|
||||
|
||||
func SocketGet(local, remote net.Addr) (*Socket, error) {
|
||||
return nil, ErrNotImplemented
|
||||
}
|
||||
+34
@@ -418,3 +418,37 @@ const (
|
||||
IFLA_XDP_ATTACHED /* read-only bool indicating if prog is attached */
|
||||
IFLA_XDP_MAX = IFLA_XDP_ATTACHED
|
||||
)
|
||||
|
||||
const (
|
||||
IFLA_IPTUN_UNSPEC = iota
|
||||
IFLA_IPTUN_LINK
|
||||
IFLA_IPTUN_LOCAL
|
||||
IFLA_IPTUN_REMOTE
|
||||
IFLA_IPTUN_TTL
|
||||
IFLA_IPTUN_TOS
|
||||
IFLA_IPTUN_ENCAP_LIMIT
|
||||
IFLA_IPTUN_FLOWINFO
|
||||
IFLA_IPTUN_FLAGS
|
||||
IFLA_IPTUN_PROTO
|
||||
IFLA_IPTUN_PMTUDISC
|
||||
IFLA_IPTUN_6RD_PREFIX
|
||||
IFLA_IPTUN_6RD_RELAY_PREFIX
|
||||
IFLA_IPTUN_6RD_PREFIXLEN
|
||||
IFLA_IPTUN_6RD_RELAY_PREFIXLEN
|
||||
IFLA_IPTUN_MAX = IFLA_IPTUN_6RD_RELAY_PREFIXLEN
|
||||
)
|
||||
|
||||
const (
|
||||
IFLA_VTI_UNSPEC = iota
|
||||
IFLA_VTI_LINK
|
||||
IFLA_VTI_IKEY
|
||||
IFLA_VTI_OKEY
|
||||
IFLA_VTI_LOCAL
|
||||
IFLA_VTI_REMOTE
|
||||
IFLA_VTI_MAX = IFLA_VTI_REMOTE
|
||||
)
|
||||
|
||||
const (
|
||||
IFLA_VRF_UNSPEC = iota
|
||||
IFLA_VRF_TABLE
|
||||
)
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
package nl
|
||||
|
||||
import "encoding/binary"
|
||||
|
||||
const (
|
||||
MPLS_LS_LABEL_SHIFT = 12
|
||||
MPLS_LS_S_SHIFT = 8
|
||||
)
|
||||
|
||||
func EncodeMPLSStack(labels ...int) []byte {
|
||||
b := make([]byte, 4*len(labels))
|
||||
for idx, label := range labels {
|
||||
l := label << MPLS_LS_LABEL_SHIFT
|
||||
if idx == len(labels)-1 {
|
||||
l |= 1 << MPLS_LS_S_SHIFT
|
||||
}
|
||||
binary.BigEndian.PutUint32(b[idx*4:], uint32(l))
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func DecodeMPLSStack(buf []byte) []int {
|
||||
if len(buf)%4 != 0 {
|
||||
return nil
|
||||
}
|
||||
stack := make([]int, 0, len(buf)/4)
|
||||
for len(buf) > 0 {
|
||||
l := binary.BigEndian.Uint32(buf[:4])
|
||||
buf = buf[4:]
|
||||
stack = append(stack, int(l)>>MPLS_LS_LABEL_SHIFT)
|
||||
if (l>>MPLS_LS_S_SHIFT)&1 > 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
return stack
|
||||
}
|
||||
+11
-3
@@ -17,9 +17,10 @@ import (
|
||||
|
||||
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
|
||||
@@ -656,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 {
|
||||
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
// +build !linux
|
||||
|
||||
package nl
|
||||
|
||||
import "encoding/binary"
|
||||
|
||||
var SupportedNlFamilies = []int{}
|
||||
|
||||
func NativeEndian() binary.ByteOrder {
|
||||
return nil
|
||||
}
|
||||
+27
-1
@@ -43,12 +43,38 @@ func (msg *RtMsg) Serialize() []byte {
|
||||
|
||||
type RtNexthop struct {
|
||||
syscall.RtNexthop
|
||||
Children []NetlinkRequestData
|
||||
}
|
||||
|
||||
func DeserializeRtNexthop(b []byte) *RtNexthop {
|
||||
return (*RtNexthop)(unsafe.Pointer(&b[0:syscall.SizeofRtNexthop][0]))
|
||||
}
|
||||
|
||||
func (msg *RtNexthop) Len() int {
|
||||
if len(msg.Children) == 0 {
|
||||
return syscall.SizeofRtNexthop
|
||||
}
|
||||
|
||||
l := 0
|
||||
for _, child := range msg.Children {
|
||||
l += rtaAlignOf(child.Len())
|
||||
}
|
||||
l += syscall.SizeofRtNexthop
|
||||
return rtaAlignOf(l)
|
||||
}
|
||||
|
||||
func (msg *RtNexthop) Serialize() []byte {
|
||||
return (*(*[syscall.SizeofRtNexthop]byte)(unsafe.Pointer(msg)))[:]
|
||||
length := msg.Len()
|
||||
msg.RtNexthop.Len = uint16(length)
|
||||
buf := make([]byte, length)
|
||||
copy(buf, (*(*[syscall.SizeofRtNexthop]byte)(unsafe.Pointer(msg)))[:])
|
||||
next := rtaAlignOf(syscall.SizeofRtNexthop)
|
||||
if len(msg.Children) > 0 {
|
||||
for _, child := range msg.Children {
|
||||
childBuf := child.Serialize()
|
||||
copy(buf[next:], childBuf)
|
||||
next += rtaAlignOf(len(childBuf))
|
||||
}
|
||||
}
|
||||
return buf
|
||||
}
|
||||
+31
@@ -35,3 +35,34 @@ const (
|
||||
FR_ACT_UNREACHABLE /* Drop with ENETUNREACH */
|
||||
FR_ACT_PROHIBIT /* Drop with EACCES */
|
||||
)
|
||||
|
||||
// socket diags related
|
||||
const (
|
||||
SOCK_DIAG_BY_FAMILY = 20 /* linux.sock_diag.h */
|
||||
TCPDIAG_NOCOOKIE = 0xFFFFFFFF /* TCPDIAG_NOCOOKIE in net/ipv4/tcp_diag.h*/
|
||||
)
|
||||
|
||||
const (
|
||||
AF_MPLS = 28
|
||||
)
|
||||
|
||||
const (
|
||||
RTA_NEWDST = 0x13
|
||||
RTA_ENCAP_TYPE = 0x15
|
||||
RTA_ENCAP = 0x16
|
||||
)
|
||||
|
||||
// RTA_ENCAP subtype
|
||||
const (
|
||||
MPLS_IPTUNNEL_UNSPEC = iota
|
||||
MPLS_IPTUNNEL_DST
|
||||
)
|
||||
|
||||
// light weight tunnel encap types
|
||||
const (
|
||||
LWTUNNEL_ENCAP_NONE = iota
|
||||
LWTUNNEL_ENCAP_MPLS
|
||||
LWTUNNEL_ENCAP_IP
|
||||
LWTUNNEL_ENCAP_ILA
|
||||
LWTUNNEL_ENCAP_IP6
|
||||
)
|
||||
+46
-26
@@ -11,34 +11,40 @@ const (
|
||||
XFRM_INF = ^uint64(0)
|
||||
)
|
||||
|
||||
type XfrmMsgType uint8
|
||||
|
||||
type XfrmMsg interface {
|
||||
Type() XfrmMsgType
|
||||
}
|
||||
|
||||
// Message Types
|
||||
const (
|
||||
XFRM_MSG_BASE = 0x10
|
||||
XFRM_MSG_NEWSA = 0x10
|
||||
XFRM_MSG_DELSA = 0x11
|
||||
XFRM_MSG_GETSA = 0x12
|
||||
XFRM_MSG_NEWPOLICY = 0x13
|
||||
XFRM_MSG_DELPOLICY = 0x14
|
||||
XFRM_MSG_GETPOLICY = 0x15
|
||||
XFRM_MSG_ALLOCSPI = 0x16
|
||||
XFRM_MSG_ACQUIRE = 0x17
|
||||
XFRM_MSG_EXPIRE = 0x18
|
||||
XFRM_MSG_UPDPOLICY = 0x19
|
||||
XFRM_MSG_UPDSA = 0x1a
|
||||
XFRM_MSG_POLEXPIRE = 0x1b
|
||||
XFRM_MSG_FLUSHSA = 0x1c
|
||||
XFRM_MSG_FLUSHPOLICY = 0x1d
|
||||
XFRM_MSG_NEWAE = 0x1e
|
||||
XFRM_MSG_GETAE = 0x1f
|
||||
XFRM_MSG_REPORT = 0x20
|
||||
XFRM_MSG_MIGRATE = 0x21
|
||||
XFRM_MSG_NEWSADINFO = 0x22
|
||||
XFRM_MSG_GETSADINFO = 0x23
|
||||
XFRM_MSG_NEWSPDINFO = 0x24
|
||||
XFRM_MSG_GETSPDINFO = 0x25
|
||||
XFRM_MSG_MAPPING = 0x26
|
||||
XFRM_MSG_MAX = 0x26
|
||||
XFRM_NR_MSGTYPES = 0x17
|
||||
XFRM_MSG_BASE XfrmMsgType = 0x10
|
||||
XFRM_MSG_NEWSA = 0x10
|
||||
XFRM_MSG_DELSA = 0x11
|
||||
XFRM_MSG_GETSA = 0x12
|
||||
XFRM_MSG_NEWPOLICY = 0x13
|
||||
XFRM_MSG_DELPOLICY = 0x14
|
||||
XFRM_MSG_GETPOLICY = 0x15
|
||||
XFRM_MSG_ALLOCSPI = 0x16
|
||||
XFRM_MSG_ACQUIRE = 0x17
|
||||
XFRM_MSG_EXPIRE = 0x18
|
||||
XFRM_MSG_UPDPOLICY = 0x19
|
||||
XFRM_MSG_UPDSA = 0x1a
|
||||
XFRM_MSG_POLEXPIRE = 0x1b
|
||||
XFRM_MSG_FLUSHSA = 0x1c
|
||||
XFRM_MSG_FLUSHPOLICY = 0x1d
|
||||
XFRM_MSG_NEWAE = 0x1e
|
||||
XFRM_MSG_GETAE = 0x1f
|
||||
XFRM_MSG_REPORT = 0x20
|
||||
XFRM_MSG_MIGRATE = 0x21
|
||||
XFRM_MSG_NEWSADINFO = 0x22
|
||||
XFRM_MSG_GETSADINFO = 0x23
|
||||
XFRM_MSG_NEWSPDINFO = 0x24
|
||||
XFRM_MSG_GETSPDINFO = 0x25
|
||||
XFRM_MSG_MAPPING = 0x26
|
||||
XFRM_MSG_MAX = 0x26
|
||||
XFRM_NR_MSGTYPES = 0x17
|
||||
)
|
||||
|
||||
// Attribute types
|
||||
@@ -81,6 +87,20 @@ const (
|
||||
SizeofXfrmMark = 0x08
|
||||
)
|
||||
|
||||
// Netlink groups
|
||||
const (
|
||||
XFRMNLGRP_NONE = 0x0
|
||||
XFRMNLGRP_ACQUIRE = 0x1
|
||||
XFRMNLGRP_EXPIRE = 0x2
|
||||
XFRMNLGRP_SA = 0x3
|
||||
XFRMNLGRP_POLICY = 0x4
|
||||
XFRMNLGRP_AEVENTS = 0x5
|
||||
XFRMNLGRP_REPORT = 0x6
|
||||
XFRMNLGRP_MIGRATE = 0x7
|
||||
XFRMNLGRP_MAPPING = 0x8
|
||||
__XFRMNLGRP_MAX = 0x9
|
||||
)
|
||||
|
||||
// typedef union {
|
||||
// __be32 a4;
|
||||
// __be32 a6[4];
|
||||
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
package nl
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
SizeofXfrmUserExpire = 0xe8
|
||||
)
|
||||
|
||||
// struct xfrm_user_expire {
|
||||
// struct xfrm_usersa_info state;
|
||||
// __u8 hard;
|
||||
// };
|
||||
|
||||
type XfrmUserExpire struct {
|
||||
XfrmUsersaInfo XfrmUsersaInfo
|
||||
Hard uint8
|
||||
Pad [7]byte
|
||||
}
|
||||
|
||||
func (msg *XfrmUserExpire) Len() int {
|
||||
return SizeofXfrmUserExpire
|
||||
}
|
||||
|
||||
func DeserializeXfrmUserExpire(b []byte) *XfrmUserExpire {
|
||||
return (*XfrmUserExpire)(unsafe.Pointer(&b[0:SizeofXfrmUserExpire][0]))
|
||||
}
|
||||
|
||||
func (msg *XfrmUserExpire) Serialize() []byte {
|
||||
return (*(*[SizeofXfrmUserExpire]byte)(unsafe.Pointer(msg)))[:]
|
||||
}
|
||||
+70
-8
@@ -5,14 +5,27 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
SizeofXfrmUsersaId = 0x18
|
||||
SizeofXfrmStats = 0x0c
|
||||
SizeofXfrmUsersaInfo = 0xe0
|
||||
SizeofXfrmAlgo = 0x44
|
||||
SizeofXfrmAlgoAuth = 0x48
|
||||
SizeofXfrmAlgoAEAD = 0x48
|
||||
SizeofXfrmEncapTmpl = 0x18
|
||||
SizeofXfrmUsersaFlush = 0x8
|
||||
SizeofXfrmUsersaId = 0x18
|
||||
SizeofXfrmStats = 0x0c
|
||||
SizeofXfrmUsersaInfo = 0xe0
|
||||
SizeofXfrmUserSpiInfo = 0xe8
|
||||
SizeofXfrmAlgo = 0x44
|
||||
SizeofXfrmAlgoAuth = 0x48
|
||||
SizeofXfrmAlgoAEAD = 0x48
|
||||
SizeofXfrmEncapTmpl = 0x18
|
||||
SizeofXfrmUsersaFlush = 0x8
|
||||
SizeofXfrmReplayStateEsn = 0x18
|
||||
)
|
||||
|
||||
const (
|
||||
XFRM_STATE_NOECN = 1
|
||||
XFRM_STATE_DECAP_DSCP = 2
|
||||
XFRM_STATE_NOPMTUDISC = 4
|
||||
XFRM_STATE_WILDRECV = 8
|
||||
XFRM_STATE_ICMP = 16
|
||||
XFRM_STATE_AF_UNSPEC = 32
|
||||
XFRM_STATE_ALIGN4 = 64
|
||||
XFRM_STATE_ESN = 128
|
||||
)
|
||||
|
||||
// struct xfrm_usersa_id {
|
||||
@@ -120,6 +133,30 @@ func (msg *XfrmUsersaInfo) Serialize() []byte {
|
||||
return (*(*[SizeofXfrmUsersaInfo]byte)(unsafe.Pointer(msg)))[:]
|
||||
}
|
||||
|
||||
// struct xfrm_userspi_info {
|
||||
// struct xfrm_usersa_info info;
|
||||
// __u32 min;
|
||||
// __u32 max;
|
||||
// };
|
||||
|
||||
type XfrmUserSpiInfo struct {
|
||||
XfrmUsersaInfo XfrmUsersaInfo
|
||||
Min uint32
|
||||
Max uint32
|
||||
}
|
||||
|
||||
func (msg *XfrmUserSpiInfo) Len() int {
|
||||
return SizeofXfrmUserSpiInfo
|
||||
}
|
||||
|
||||
func DeserializeXfrmUserSpiInfo(b []byte) *XfrmUserSpiInfo {
|
||||
return (*XfrmUserSpiInfo)(unsafe.Pointer(&b[0:SizeofXfrmUserSpiInfo][0]))
|
||||
}
|
||||
|
||||
func (msg *XfrmUserSpiInfo) Serialize() []byte {
|
||||
return (*(*[SizeofXfrmUserSpiInfo]byte)(unsafe.Pointer(msg)))[:]
|
||||
}
|
||||
|
||||
// struct xfrm_algo {
|
||||
// char alg_name[64];
|
||||
// unsigned int alg_key_len; /* in bits */
|
||||
@@ -270,3 +307,28 @@ func DeserializeXfrmUsersaFlush(b []byte) *XfrmUsersaFlush {
|
||||
func (msg *XfrmUsersaFlush) Serialize() []byte {
|
||||
return (*(*[SizeofXfrmUsersaFlush]byte)(unsafe.Pointer(msg)))[:]
|
||||
}
|
||||
|
||||
// struct xfrm_replay_state_esn {
|
||||
// unsigned int bmp_len;
|
||||
// __u32 oseq;
|
||||
// __u32 seq;
|
||||
// __u32 oseq_hi;
|
||||
// __u32 seq_hi;
|
||||
// __u32 replay_window;
|
||||
// __u32 bmp[0];
|
||||
// };
|
||||
|
||||
type XfrmReplayStateEsn struct {
|
||||
BmpLen uint32
|
||||
OSeq uint32
|
||||
Seq uint32
|
||||
OSeqHi uint32
|
||||
SeqHi uint32
|
||||
ReplayWindow uint32
|
||||
Bmp []uint32
|
||||
}
|
||||
|
||||
func (msg *XfrmReplayStateEsn) Serialize() []byte {
|
||||
// We deliberately do not pass Bmp, as it gets set by the kernel.
|
||||
return (*(*[SizeofXfrmReplayStateEsn]byte)(unsafe.Pointer(msg)))[:]
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
package netlink
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
|
||||
"github.com/vishvananda/netlink/nl"
|
||||
)
|
||||
|
||||
var (
|
||||
native = nl.NativeEndian()
|
||||
networkOrder = binary.BigEndian
|
||||
)
|
||||
|
||||
func htonl(val uint32) []byte {
|
||||
bytes := make([]byte, 4)
|
||||
binary.BigEndian.PutUint32(bytes, val)
|
||||
return bytes
|
||||
}
|
||||
|
||||
func htons(val uint16) []byte {
|
||||
bytes := make([]byte, 2)
|
||||
binary.BigEndian.PutUint16(bytes, val)
|
||||
return bytes
|
||||
}
|
||||
|
||||
func ntohl(buf []byte) uint32 {
|
||||
return binary.BigEndian.Uint32(buf)
|
||||
}
|
||||
|
||||
func ntohs(buf []byte) uint16 {
|
||||
return binary.BigEndian.Uint16(buf)
|
||||
}
|
||||
+1
-4
@@ -46,8 +46,5 @@ func boolToByte(x bool) []byte {
|
||||
}
|
||||
|
||||
func byteToBool(x byte) bool {
|
||||
if uint8(x) != 0 {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
return uint8(x) != 0
|
||||
}
|
||||
+23
-17
@@ -40,25 +40,31 @@ func (h *Handle) LinkGetProtinfo(link Link) (Protinfo, error) {
|
||||
if err != nil {
|
||||
return pi, err
|
||||
}
|
||||
var pi Protinfo
|
||||
for _, info := range infos {
|
||||
switch info.Attr.Type {
|
||||
case nl.IFLA_BRPORT_MODE:
|
||||
pi.Hairpin = byteToBool(info.Value[0])
|
||||
case nl.IFLA_BRPORT_GUARD:
|
||||
pi.Guard = byteToBool(info.Value[0])
|
||||
case nl.IFLA_BRPORT_FAST_LEAVE:
|
||||
pi.FastLeave = byteToBool(info.Value[0])
|
||||
case nl.IFLA_BRPORT_PROTECT:
|
||||
pi.RootBlock = byteToBool(info.Value[0])
|
||||
case nl.IFLA_BRPORT_LEARNING:
|
||||
pi.Learning = byteToBool(info.Value[0])
|
||||
case nl.IFLA_BRPORT_UNICAST_FLOOD:
|
||||
pi.Flood = byteToBool(info.Value[0])
|
||||
}
|
||||
}
|
||||
pi = *parseProtinfo(infos)
|
||||
|
||||
return pi, nil
|
||||
}
|
||||
}
|
||||
return pi, fmt.Errorf("Device with index %d not found", base.Index)
|
||||
}
|
||||
|
||||
func parseProtinfo(infos []syscall.NetlinkRouteAttr) *Protinfo {
|
||||
var pi Protinfo
|
||||
for _, info := range infos {
|
||||
switch info.Attr.Type {
|
||||
case nl.IFLA_BRPORT_MODE:
|
||||
pi.Hairpin = byteToBool(info.Value[0])
|
||||
case nl.IFLA_BRPORT_GUARD:
|
||||
pi.Guard = byteToBool(info.Value[0])
|
||||
case nl.IFLA_BRPORT_FAST_LEAVE:
|
||||
pi.FastLeave = byteToBool(info.Value[0])
|
||||
case nl.IFLA_BRPORT_PROTECT:
|
||||
pi.RootBlock = byteToBool(info.Value[0])
|
||||
case nl.IFLA_BRPORT_LEARNING:
|
||||
pi.Learning = byteToBool(info.Value[0])
|
||||
case nl.IFLA_BRPORT_UNICAST_FLOOD:
|
||||
pi.Flood = byteToBool(info.Value[0])
|
||||
}
|
||||
}
|
||||
return &pi
|
||||
}
|
||||
+5
-4
@@ -187,10 +187,11 @@ func (qdisc *Netem) Type() string {
|
||||
// Tbf is a classless qdisc that rate limits based on tokens
|
||||
type Tbf struct {
|
||||
QdiscAttrs
|
||||
// TODO: handle 64bit rate properly
|
||||
Rate uint64
|
||||
Limit uint32
|
||||
Buffer uint32
|
||||
Rate uint64
|
||||
Limit uint32
|
||||
Buffer uint32
|
||||
Peakrate uint64
|
||||
Minburst uint32
|
||||
// TODO: handle other settings
|
||||
}
|
||||
|
||||
|
||||
+16
-2
@@ -168,11 +168,20 @@ func qdiscPayload(req *nl.NetlinkRequest, qdisc Qdisc) error {
|
||||
options = nl.NewRtAttr(nl.TCA_OPTIONS, tcmap.Serialize())
|
||||
} else if tbf, ok := qdisc.(*Tbf); ok {
|
||||
opt := nl.TcTbfQopt{}
|
||||
// TODO: handle rate > uint32
|
||||
opt.Rate.Rate = uint32(tbf.Rate)
|
||||
opt.Peakrate.Rate = uint32(tbf.Peakrate)
|
||||
opt.Limit = tbf.Limit
|
||||
opt.Buffer = tbf.Buffer
|
||||
nl.NewRtAttrChild(options, nl.TCA_TBF_PARMS, opt.Serialize())
|
||||
if tbf.Rate >= uint64(1<<32) {
|
||||
nl.NewRtAttrChild(options, nl.TCA_TBF_RATE64, nl.Uint64Attr(tbf.Rate))
|
||||
}
|
||||
if tbf.Peakrate >= uint64(1<<32) {
|
||||
nl.NewRtAttrChild(options, nl.TCA_TBF_PRATE64, nl.Uint64Attr(tbf.Peakrate))
|
||||
}
|
||||
if tbf.Peakrate > 0 {
|
||||
nl.NewRtAttrChild(options, nl.TCA_TBF_PBURST, nl.Uint32Attr(tbf.Minburst))
|
||||
}
|
||||
} else if htb, ok := qdisc.(*Htb); ok {
|
||||
opt := nl.TcHtbGlob{}
|
||||
opt.Version = htb.Version
|
||||
@@ -418,10 +427,15 @@ func parseTbfData(qdisc Qdisc, data []syscall.NetlinkRouteAttr) error {
|
||||
case nl.TCA_TBF_PARMS:
|
||||
opt := nl.DeserializeTcTbfQopt(datum.Value)
|
||||
tbf.Rate = uint64(opt.Rate.Rate)
|
||||
tbf.Peakrate = uint64(opt.Peakrate.Rate)
|
||||
tbf.Limit = opt.Limit
|
||||
tbf.Buffer = opt.Buffer
|
||||
case nl.TCA_TBF_RATE64:
|
||||
tbf.Rate = native.Uint64(datum.Value[0:4])
|
||||
tbf.Rate = native.Uint64(datum.Value[0:8])
|
||||
case nl.TCA_TBF_PRATE64:
|
||||
tbf.Peakrate = native.Uint64(datum.Value[0:8])
|
||||
case nl.TCA_TBF_PBURST:
|
||||
tbf.Minburst = native.Uint32(datum.Value[0:4])
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
||||
+56
-6
@@ -3,6 +3,7 @@ package netlink
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Scope is an enum representing a route scope.
|
||||
@@ -10,6 +11,20 @@ type Scope uint8
|
||||
|
||||
type NextHopFlag int
|
||||
|
||||
type Destination interface {
|
||||
Family() int
|
||||
Decode([]byte) error
|
||||
Encode() ([]byte, error)
|
||||
String() string
|
||||
}
|
||||
|
||||
type Encap interface {
|
||||
Type() int
|
||||
Decode([]byte) error
|
||||
Encode() ([]byte, error)
|
||||
String() string
|
||||
}
|
||||
|
||||
// Route represents a netlink route.
|
||||
type Route struct {
|
||||
LinkIndex int
|
||||
@@ -25,15 +40,36 @@ type Route struct {
|
||||
Type int
|
||||
Tos int
|
||||
Flags int
|
||||
MPLSDst *int
|
||||
NewDst Destination
|
||||
Encap Encap
|
||||
}
|
||||
|
||||
func (r Route) String() string {
|
||||
if len(r.MultiPath) > 0 {
|
||||
return fmt.Sprintf("{Dst: %s Src: %s Gw: %s Flags: %s Table: %d}", r.Dst,
|
||||
r.Src, r.MultiPath, r.ListFlags(), r.Table)
|
||||
elems := []string{}
|
||||
if len(r.MultiPath) == 0 {
|
||||
elems = append(elems, fmt.Sprintf("Ifindex: %d", r.LinkIndex))
|
||||
}
|
||||
return fmt.Sprintf("{Ifindex: %d Dst: %s Src: %s Gw: %s Flags: %s Table: %d}", r.LinkIndex, r.Dst,
|
||||
r.Src, r.Gw, r.ListFlags(), r.Table)
|
||||
if r.MPLSDst != nil {
|
||||
elems = append(elems, fmt.Sprintf("Dst: %d", r.MPLSDst))
|
||||
} else {
|
||||
elems = append(elems, fmt.Sprintf("Dst: %s", r.Dst))
|
||||
}
|
||||
if r.NewDst != nil {
|
||||
elems = append(elems, fmt.Sprintf("NewDst: %s", r.NewDst))
|
||||
}
|
||||
if r.Encap != nil {
|
||||
elems = append(elems, fmt.Sprintf("Encap: %s", r.Encap))
|
||||
}
|
||||
elems = append(elems, fmt.Sprintf("Src: %s", r.Src))
|
||||
if len(r.MultiPath) > 0 {
|
||||
elems = append(elems, fmt.Sprintf("Gw: %s", r.MultiPath))
|
||||
} else {
|
||||
elems = append(elems, fmt.Sprintf("Gw: %s", r.Gw))
|
||||
}
|
||||
elems = append(elems, fmt.Sprintf("Flags: %s", r.ListFlags()))
|
||||
elems = append(elems, fmt.Sprintf("Table: %d", r.Table))
|
||||
return fmt.Sprintf("{%s}", strings.Join(elems, " "))
|
||||
}
|
||||
|
||||
func (r *Route) SetFlag(flag NextHopFlag) {
|
||||
@@ -59,8 +95,22 @@ type NexthopInfo struct {
|
||||
LinkIndex int
|
||||
Hops int
|
||||
Gw net.IP
|
||||
Flags int
|
||||
NewDst Destination
|
||||
Encap Encap
|
||||
}
|
||||
|
||||
func (n *NexthopInfo) String() string {
|
||||
return fmt.Sprintf("{Ifindex: %d Weight: %d, Gw: %s}", n.LinkIndex, n.Hops+1, n.Gw)
|
||||
elems := []string{}
|
||||
elems = append(elems, fmt.Sprintf("Ifindex: %d", n.LinkIndex))
|
||||
if n.NewDst != nil {
|
||||
elems = append(elems, fmt.Sprintf("NewDst: %s", n.NewDst))
|
||||
}
|
||||
if n.Encap != nil {
|
||||
elems = append(elems, fmt.Sprintf("Encap: %s", n.Encap))
|
||||
}
|
||||
elems = append(elems, fmt.Sprintf("Weight: %d", n.Hops+1))
|
||||
elems = append(elems, fmt.Sprintf("Gw: %d", n.Gw))
|
||||
elems = append(elems, fmt.Sprintf("Flags: %s", n.ListFlags()))
|
||||
return fmt.Sprintf("{%s}", strings.Join(elems, " "))
|
||||
}
|
||||
+234
-23
@@ -3,6 +3,7 @@ package netlink
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"github.com/vishvananda/netlink/nl"
|
||||
@@ -42,16 +43,92 @@ var testFlags = []flagString{
|
||||
{f: FLAG_PERVASIVE, s: "pervasive"},
|
||||
}
|
||||
|
||||
func (r *Route) ListFlags() []string {
|
||||
func listFlags(flag int) []string {
|
||||
var flags []string
|
||||
for _, tf := range testFlags {
|
||||
if r.Flags&int(tf.f) != 0 {
|
||||
if flag&int(tf.f) != 0 {
|
||||
flags = append(flags, tf.s)
|
||||
}
|
||||
}
|
||||
return flags
|
||||
}
|
||||
|
||||
func (r *Route) ListFlags() []string {
|
||||
return listFlags(r.Flags)
|
||||
}
|
||||
|
||||
func (n *NexthopInfo) ListFlags() []string {
|
||||
return listFlags(n.Flags)
|
||||
}
|
||||
|
||||
type MPLSDestination struct {
|
||||
Labels []int
|
||||
}
|
||||
|
||||
func (d *MPLSDestination) Family() int {
|
||||
return nl.FAMILY_MPLS
|
||||
}
|
||||
|
||||
func (d *MPLSDestination) Decode(buf []byte) error {
|
||||
d.Labels = nl.DecodeMPLSStack(buf)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *MPLSDestination) Encode() ([]byte, error) {
|
||||
return nl.EncodeMPLSStack(d.Labels...), nil
|
||||
}
|
||||
|
||||
func (d *MPLSDestination) String() string {
|
||||
s := make([]string, 0, len(d.Labels))
|
||||
for _, l := range d.Labels {
|
||||
s = append(s, fmt.Sprintf("%d", l))
|
||||
}
|
||||
return strings.Join(s, "/")
|
||||
}
|
||||
|
||||
type MPLSEncap struct {
|
||||
Labels []int
|
||||
}
|
||||
|
||||
func (e *MPLSEncap) Type() int {
|
||||
return nl.LWTUNNEL_ENCAP_MPLS
|
||||
}
|
||||
|
||||
func (e *MPLSEncap) Decode(buf []byte) error {
|
||||
if len(buf) < 4 {
|
||||
return fmt.Errorf("Lack of bytes")
|
||||
}
|
||||
native := nl.NativeEndian()
|
||||
l := native.Uint16(buf)
|
||||
if len(buf) < int(l) {
|
||||
return fmt.Errorf("Lack of bytes")
|
||||
}
|
||||
buf = buf[:l]
|
||||
typ := native.Uint16(buf[2:])
|
||||
if typ != nl.MPLS_IPTUNNEL_DST {
|
||||
return fmt.Errorf("Unknown MPLS Encap Type: %d", typ)
|
||||
}
|
||||
e.Labels = nl.DecodeMPLSStack(buf[4:])
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *MPLSEncap) Encode() ([]byte, error) {
|
||||
s := nl.EncodeMPLSStack(e.Labels...)
|
||||
native := nl.NativeEndian()
|
||||
hdr := make([]byte, 4)
|
||||
native.PutUint16(hdr, uint16(len(s)+4))
|
||||
native.PutUint16(hdr[2:], nl.MPLS_IPTUNNEL_DST)
|
||||
return append(hdr, s...), nil
|
||||
}
|
||||
|
||||
func (e *MPLSEncap) String() string {
|
||||
s := make([]string, 0, len(e.Labels))
|
||||
for _, l := range e.Labels {
|
||||
s = append(s, fmt.Sprintf("%d", l))
|
||||
}
|
||||
return strings.Join(s, "/")
|
||||
}
|
||||
|
||||
// RouteAdd will add a route to the system.
|
||||
// Equivalent to: `ip route add $route`
|
||||
func RouteAdd(route *Route) error {
|
||||
@@ -61,7 +138,22 @@ func RouteAdd(route *Route) error {
|
||||
// RouteAdd will add a route to the system.
|
||||
// Equivalent to: `ip route add $route`
|
||||
func (h *Handle) RouteAdd(route *Route) error {
|
||||
req := h.newNetlinkRequest(syscall.RTM_NEWROUTE, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
|
||||
flags := syscall.NLM_F_CREATE | syscall.NLM_F_EXCL | syscall.NLM_F_ACK
|
||||
req := h.newNetlinkRequest(syscall.RTM_NEWROUTE, flags)
|
||||
return h.routeHandle(route, req, nl.NewRtMsg())
|
||||
}
|
||||
|
||||
// RouteReplace will add a route to the system.
|
||||
// Equivalent to: `ip route replace $route`
|
||||
func RouteReplace(route *Route) error {
|
||||
return pkgHandle.RouteReplace(route)
|
||||
}
|
||||
|
||||
// RouteReplace will add a route to the system.
|
||||
// Equivalent to: `ip route replace $route`
|
||||
func (h *Handle) RouteReplace(route *Route) error {
|
||||
flags := syscall.NLM_F_CREATE | syscall.NLM_F_REPLACE | syscall.NLM_F_ACK
|
||||
req := h.newNetlinkRequest(syscall.RTM_NEWROUTE, flags)
|
||||
return h.routeHandle(route, req, nl.NewRtMsg())
|
||||
}
|
||||
|
||||
@@ -79,7 +171,7 @@ func (h *Handle) RouteDel(route *Route) error {
|
||||
}
|
||||
|
||||
func (h *Handle) routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg) error {
|
||||
if (route.Dst == nil || route.Dst.IP == nil) && route.Src == nil && route.Gw == nil {
|
||||
if (route.Dst == nil || route.Dst.IP == nil) && route.Src == nil && route.Gw == nil && route.MPLSDst == nil {
|
||||
return fmt.Errorf("one of Dst.IP, Src, or Gw must not be nil")
|
||||
}
|
||||
|
||||
@@ -98,6 +190,33 @@ func (h *Handle) routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg
|
||||
dstData = route.Dst.IP.To16()
|
||||
}
|
||||
rtAttrs = append(rtAttrs, nl.NewRtAttr(syscall.RTA_DST, dstData))
|
||||
} else if route.MPLSDst != nil {
|
||||
family = nl.FAMILY_MPLS
|
||||
msg.Dst_len = uint8(20)
|
||||
msg.Type = syscall.RTN_UNICAST
|
||||
rtAttrs = append(rtAttrs, nl.NewRtAttr(syscall.RTA_DST, nl.EncodeMPLSStack(*route.MPLSDst)))
|
||||
}
|
||||
|
||||
if route.NewDst != nil {
|
||||
if family != -1 && family != route.NewDst.Family() {
|
||||
return fmt.Errorf("new destination and destination are not the same address family")
|
||||
}
|
||||
buf, err := route.NewDst.Encode()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rtAttrs = append(rtAttrs, nl.NewRtAttr(nl.RTA_NEWDST, buf))
|
||||
}
|
||||
|
||||
if route.Encap != nil {
|
||||
buf := make([]byte, 2)
|
||||
native.PutUint16(buf, uint16(route.Encap.Type()))
|
||||
rtAttrs = append(rtAttrs, nl.NewRtAttr(nl.RTA_ENCAP_TYPE, buf))
|
||||
buf, err := route.Encap.Encode()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rtAttrs = append(rtAttrs, nl.NewRtAttr(nl.RTA_ENCAP, buf))
|
||||
}
|
||||
|
||||
if route.Src != nil {
|
||||
@@ -138,26 +257,43 @@ func (h *Handle) routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg
|
||||
RtNexthop: syscall.RtNexthop{
|
||||
Hops: uint8(nh.Hops),
|
||||
Ifindex: int32(nh.LinkIndex),
|
||||
Len: uint16(syscall.SizeofRtNexthop),
|
||||
Flags: uint8(nh.Flags),
|
||||
},
|
||||
}
|
||||
var gwData []byte
|
||||
children := []nl.NetlinkRequestData{}
|
||||
if nh.Gw != nil {
|
||||
gwFamily := nl.GetIPFamily(nh.Gw)
|
||||
if family != -1 && family != gwFamily {
|
||||
return fmt.Errorf("gateway, source, and destination ip are not the same IP family")
|
||||
}
|
||||
var gw *nl.RtAttr
|
||||
if gwFamily == FAMILY_V4 {
|
||||
gw = nl.NewRtAttr(syscall.RTA_GATEWAY, []byte(nh.Gw.To4()))
|
||||
children = append(children, nl.NewRtAttr(syscall.RTA_GATEWAY, []byte(nh.Gw.To4())))
|
||||
} else {
|
||||
gw = nl.NewRtAttr(syscall.RTA_GATEWAY, []byte(nh.Gw.To16()))
|
||||
children = append(children, nl.NewRtAttr(syscall.RTA_GATEWAY, []byte(nh.Gw.To16())))
|
||||
}
|
||||
gwData = gw.Serialize()
|
||||
rtnh.Len += uint16(len(gwData))
|
||||
}
|
||||
if nh.NewDst != nil {
|
||||
if family != -1 && family != nh.NewDst.Family() {
|
||||
return fmt.Errorf("new destination and destination are not the same address family")
|
||||
}
|
||||
buf, err := nh.NewDst.Encode()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
children = append(children, nl.NewRtAttr(nl.RTA_NEWDST, buf))
|
||||
}
|
||||
if nh.Encap != nil {
|
||||
buf := make([]byte, 2)
|
||||
native.PutUint16(buf, uint16(nh.Encap.Type()))
|
||||
rtAttrs = append(rtAttrs, nl.NewRtAttr(nl.RTA_ENCAP_TYPE, buf))
|
||||
buf, err := nh.Encap.Encode()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
children = append(children, nl.NewRtAttr(nl.RTA_ENCAP, buf))
|
||||
}
|
||||
rtnh.Children = children
|
||||
buf = append(buf, rtnh.Serialize()...)
|
||||
buf = append(buf, gwData...)
|
||||
}
|
||||
rtAttrs = append(rtAttrs, nl.NewRtAttr(syscall.RTA_MULTIPATH, buf))
|
||||
}
|
||||
@@ -283,14 +419,22 @@ func (h *Handle) RouteListFiltered(family int, filter *Route, filterMask uint64)
|
||||
continue
|
||||
case filterMask&RT_FILTER_SRC != 0 && !route.Src.Equal(filter.Src):
|
||||
continue
|
||||
case filterMask&RT_FILTER_DST != 0 && filter.Dst != nil:
|
||||
if route.Dst == nil {
|
||||
continue
|
||||
}
|
||||
aMaskLen, aMaskBits := route.Dst.Mask.Size()
|
||||
bMaskLen, bMaskBits := filter.Dst.Mask.Size()
|
||||
if !(route.Dst.IP.Equal(filter.Dst.IP) && aMaskLen == bMaskLen && aMaskBits == bMaskBits) {
|
||||
continue
|
||||
case filterMask&RT_FILTER_DST != 0:
|
||||
if filter.MPLSDst == nil || route.MPLSDst == nil || (*filter.MPLSDst) != (*route.MPLSDst) {
|
||||
if filter.Dst == nil {
|
||||
if route.Dst != nil {
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
if route.Dst == nil {
|
||||
continue
|
||||
}
|
||||
aMaskLen, aMaskBits := route.Dst.Mask.Size()
|
||||
bMaskLen, bMaskBits := filter.Dst.Mask.Size()
|
||||
if !(route.Dst.IP.Equal(filter.Dst.IP) && aMaskLen == bMaskLen && aMaskBits == bMaskBits) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -316,6 +460,7 @@ func deserializeRoute(m []byte) (Route, error) {
|
||||
}
|
||||
|
||||
native := nl.NativeEndian()
|
||||
var encap, encapType syscall.NetlinkRouteAttr
|
||||
for _, attr := range attrs {
|
||||
switch attr.Attr.Type {
|
||||
case syscall.RTA_GATEWAY:
|
||||
@@ -323,9 +468,17 @@ func deserializeRoute(m []byte) (Route, error) {
|
||||
case syscall.RTA_PREFSRC:
|
||||
route.Src = net.IP(attr.Value)
|
||||
case syscall.RTA_DST:
|
||||
route.Dst = &net.IPNet{
|
||||
IP: attr.Value,
|
||||
Mask: net.CIDRMask(int(msg.Dst_len), 8*len(attr.Value)),
|
||||
if msg.Family == nl.FAMILY_MPLS {
|
||||
stack := nl.DecodeMPLSStack(attr.Value)
|
||||
if len(stack) == 0 || len(stack) > 1 {
|
||||
return route, fmt.Errorf("invalid MPLS RTA_DST")
|
||||
}
|
||||
route.MPLSDst = &stack[0]
|
||||
} else {
|
||||
route.Dst = &net.IPNet{
|
||||
IP: attr.Value,
|
||||
Mask: net.CIDRMask(int(msg.Dst_len), 8*len(attr.Value)),
|
||||
}
|
||||
}
|
||||
case syscall.RTA_OIF:
|
||||
route.LinkIndex = int(native.Uint32(attr.Value[0:4]))
|
||||
@@ -347,17 +500,47 @@ func deserializeRoute(m []byte) (Route, error) {
|
||||
info := &NexthopInfo{
|
||||
LinkIndex: int(nh.RtNexthop.Ifindex),
|
||||
Hops: int(nh.RtNexthop.Hops),
|
||||
Flags: int(nh.RtNexthop.Flags),
|
||||
}
|
||||
attrs, err := nl.ParseRouteAttr(value[syscall.SizeofRtNexthop:int(nh.RtNexthop.Len)])
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
var encap, encapType syscall.NetlinkRouteAttr
|
||||
for _, attr := range attrs {
|
||||
switch attr.Attr.Type {
|
||||
case syscall.RTA_GATEWAY:
|
||||
info.Gw = net.IP(attr.Value)
|
||||
case nl.RTA_NEWDST:
|
||||
var d Destination
|
||||
switch msg.Family {
|
||||
case nl.FAMILY_MPLS:
|
||||
d = &MPLSDestination{}
|
||||
}
|
||||
if err := d.Decode(attr.Value); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
info.NewDst = d
|
||||
case nl.RTA_ENCAP_TYPE:
|
||||
encapType = attr
|
||||
case nl.RTA_ENCAP:
|
||||
encap = attr
|
||||
}
|
||||
}
|
||||
|
||||
if len(encap.Value) != 0 && len(encapType.Value) != 0 {
|
||||
typ := int(native.Uint16(encapType.Value[0:2]))
|
||||
var e Encap
|
||||
switch typ {
|
||||
case nl.LWTUNNEL_ENCAP_MPLS:
|
||||
e = &MPLSEncap{}
|
||||
if err := e.Decode(encap.Value); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
info.Encap = e
|
||||
}
|
||||
|
||||
return info, value[int(nh.RtNexthop.Len):], nil
|
||||
}
|
||||
rest := attr.Value
|
||||
@@ -369,8 +552,36 @@ func deserializeRoute(m []byte) (Route, error) {
|
||||
route.MultiPath = append(route.MultiPath, info)
|
||||
rest = buf
|
||||
}
|
||||
case nl.RTA_NEWDST:
|
||||
var d Destination
|
||||
switch msg.Family {
|
||||
case nl.FAMILY_MPLS:
|
||||
d = &MPLSDestination{}
|
||||
}
|
||||
if err := d.Decode(attr.Value); err != nil {
|
||||
return route, err
|
||||
}
|
||||
route.NewDst = d
|
||||
case nl.RTA_ENCAP_TYPE:
|
||||
encapType = attr
|
||||
case nl.RTA_ENCAP:
|
||||
encap = attr
|
||||
}
|
||||
}
|
||||
|
||||
if len(encap.Value) != 0 && len(encapType.Value) != 0 {
|
||||
typ := int(native.Uint16(encapType.Value[0:2]))
|
||||
var e Encap
|
||||
switch typ {
|
||||
case nl.LWTUNNEL_ENCAP_MPLS:
|
||||
e = &MPLSEncap{}
|
||||
if err := e.Decode(encap.Value); err != nil {
|
||||
return route, err
|
||||
}
|
||||
}
|
||||
route.Encap = e
|
||||
}
|
||||
|
||||
return route, nil
|
||||
}
|
||||
|
||||
|
||||
+4
@@ -5,3 +5,7 @@ package netlink
|
||||
func (r *Route) ListFlags() []string {
|
||||
return []string{}
|
||||
}
|
||||
|
||||
func (n *NexthopInfo) ListFlags() []string {
|
||||
return []string{}
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
package netlink
|
||||
|
||||
import "net"
|
||||
|
||||
// SocketID identifies a single socket.
|
||||
type SocketID struct {
|
||||
SourcePort uint16
|
||||
DestinationPort uint16
|
||||
Source net.IP
|
||||
Destination net.IP
|
||||
Interface uint32
|
||||
Cookie [2]uint32
|
||||
}
|
||||
|
||||
// Socket represents a netlink socket.
|
||||
type Socket struct {
|
||||
Family uint8
|
||||
State uint8
|
||||
Timer uint8
|
||||
Retrans uint8
|
||||
ID SocketID
|
||||
Expires uint32
|
||||
RQueue uint32
|
||||
WQueue uint32
|
||||
UID uint32
|
||||
INode uint32
|
||||
}
|
||||
+159
@@ -0,0 +1,159 @@
|
||||
package netlink
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"syscall"
|
||||
|
||||
"github.com/vishvananda/netlink/nl"
|
||||
)
|
||||
|
||||
const (
|
||||
sizeofSocketID = 0x30
|
||||
sizeofSocketRequest = sizeofSocketID + 0x8
|
||||
sizeofSocket = sizeofSocketID + 0x18
|
||||
)
|
||||
|
||||
type socketRequest struct {
|
||||
Family uint8
|
||||
Protocol uint8
|
||||
Ext uint8
|
||||
pad uint8
|
||||
States uint32
|
||||
ID SocketID
|
||||
}
|
||||
|
||||
type writeBuffer struct {
|
||||
Bytes []byte
|
||||
pos int
|
||||
}
|
||||
|
||||
func (b *writeBuffer) Write(c byte) {
|
||||
b.Bytes[b.pos] = c
|
||||
b.pos++
|
||||
}
|
||||
|
||||
func (b *writeBuffer) Next(n int) []byte {
|
||||
s := b.Bytes[b.pos : b.pos+n]
|
||||
b.pos += n
|
||||
return s
|
||||
}
|
||||
|
||||
func (r *socketRequest) Serialize() []byte {
|
||||
b := writeBuffer{Bytes: make([]byte, sizeofSocketRequest)}
|
||||
b.Write(r.Family)
|
||||
b.Write(r.Protocol)
|
||||
b.Write(r.Ext)
|
||||
b.Write(r.pad)
|
||||
native.PutUint32(b.Next(4), r.States)
|
||||
networkOrder.PutUint16(b.Next(2), r.ID.SourcePort)
|
||||
networkOrder.PutUint16(b.Next(2), r.ID.DestinationPort)
|
||||
copy(b.Next(4), r.ID.Source.To4())
|
||||
b.Next(12)
|
||||
copy(b.Next(4), r.ID.Destination.To4())
|
||||
b.Next(12)
|
||||
native.PutUint32(b.Next(4), r.ID.Interface)
|
||||
native.PutUint32(b.Next(4), r.ID.Cookie[0])
|
||||
native.PutUint32(b.Next(4), r.ID.Cookie[1])
|
||||
return b.Bytes
|
||||
}
|
||||
|
||||
func (r *socketRequest) Len() int { return sizeofSocketRequest }
|
||||
|
||||
type readBuffer struct {
|
||||
Bytes []byte
|
||||
pos int
|
||||
}
|
||||
|
||||
func (b *readBuffer) Read() byte {
|
||||
c := b.Bytes[b.pos]
|
||||
b.pos++
|
||||
return c
|
||||
}
|
||||
|
||||
func (b *readBuffer) Next(n int) []byte {
|
||||
s := b.Bytes[b.pos : b.pos+n]
|
||||
b.pos += n
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *Socket) deserialize(b []byte) error {
|
||||
if len(b) < sizeofSocket {
|
||||
return fmt.Errorf("socket data short read (%d); want %d", len(b), sizeofSocket)
|
||||
}
|
||||
rb := readBuffer{Bytes: b}
|
||||
s.Family = rb.Read()
|
||||
s.State = rb.Read()
|
||||
s.Timer = rb.Read()
|
||||
s.Retrans = rb.Read()
|
||||
s.ID.SourcePort = networkOrder.Uint16(rb.Next(2))
|
||||
s.ID.DestinationPort = networkOrder.Uint16(rb.Next(2))
|
||||
s.ID.Source = net.IPv4(rb.Read(), rb.Read(), rb.Read(), rb.Read())
|
||||
rb.Next(12)
|
||||
s.ID.Destination = net.IPv4(rb.Read(), rb.Read(), rb.Read(), rb.Read())
|
||||
rb.Next(12)
|
||||
s.ID.Interface = native.Uint32(rb.Next(4))
|
||||
s.ID.Cookie[0] = native.Uint32(rb.Next(4))
|
||||
s.ID.Cookie[1] = native.Uint32(rb.Next(4))
|
||||
s.Expires = native.Uint32(rb.Next(4))
|
||||
s.RQueue = native.Uint32(rb.Next(4))
|
||||
s.WQueue = native.Uint32(rb.Next(4))
|
||||
s.UID = native.Uint32(rb.Next(4))
|
||||
s.INode = native.Uint32(rb.Next(4))
|
||||
return nil
|
||||
}
|
||||
|
||||
// SocketGet returns the Socket identified by its local and remote addresses.
|
||||
func SocketGet(local, remote net.Addr) (*Socket, error) {
|
||||
localTCP, ok := local.(*net.TCPAddr)
|
||||
if !ok {
|
||||
return nil, ErrNotImplemented
|
||||
}
|
||||
remoteTCP, ok := remote.(*net.TCPAddr)
|
||||
if !ok {
|
||||
return nil, ErrNotImplemented
|
||||
}
|
||||
localIP := localTCP.IP.To4()
|
||||
if localIP == nil {
|
||||
return nil, ErrNotImplemented
|
||||
}
|
||||
remoteIP := remoteTCP.IP.To4()
|
||||
if remoteIP == nil {
|
||||
return nil, ErrNotImplemented
|
||||
}
|
||||
|
||||
s, err := nl.Subscribe(syscall.NETLINK_INET_DIAG)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer s.Close()
|
||||
req := nl.NewNetlinkRequest(nl.SOCK_DIAG_BY_FAMILY, 0)
|
||||
req.AddData(&socketRequest{
|
||||
Family: syscall.AF_INET,
|
||||
Protocol: syscall.IPPROTO_TCP,
|
||||
ID: SocketID{
|
||||
SourcePort: uint16(localTCP.Port),
|
||||
DestinationPort: uint16(remoteTCP.Port),
|
||||
Source: localIP,
|
||||
Destination: remoteIP,
|
||||
Cookie: [2]uint32{nl.TCPDIAG_NOCOOKIE, nl.TCPDIAG_NOCOOKIE},
|
||||
},
|
||||
})
|
||||
s.Send(req)
|
||||
msgs, err := s.Receive()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(msgs) == 0 {
|
||||
return nil, errors.New("no message nor error from netlink")
|
||||
}
|
||||
if len(msgs) > 2 {
|
||||
return nil, fmt.Errorf("multiple (%d) matching sockets", len(msgs))
|
||||
}
|
||||
sock := &Socket{}
|
||||
if err := sock.deserialize(msgs[0].Data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return sock, nil
|
||||
}
|
||||
+98
@@ -0,0 +1,98 @@
|
||||
package netlink
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"syscall"
|
||||
|
||||
"github.com/vishvananda/netns"
|
||||
|
||||
"github.com/vishvananda/netlink/nl"
|
||||
)
|
||||
|
||||
type XfrmMsg interface {
|
||||
Type() nl.XfrmMsgType
|
||||
}
|
||||
|
||||
type XfrmMsgExpire struct {
|
||||
XfrmState *XfrmState
|
||||
Hard bool
|
||||
}
|
||||
|
||||
func (ue *XfrmMsgExpire) Type() nl.XfrmMsgType {
|
||||
return nl.XFRM_MSG_EXPIRE
|
||||
}
|
||||
|
||||
func parseXfrmMsgExpire(b []byte) *XfrmMsgExpire {
|
||||
var e XfrmMsgExpire
|
||||
|
||||
msg := nl.DeserializeXfrmUserExpire(b)
|
||||
e.XfrmState = xfrmStateFromXfrmUsersaInfo(&msg.XfrmUsersaInfo)
|
||||
e.Hard = msg.Hard == 1
|
||||
|
||||
return &e
|
||||
}
|
||||
|
||||
func XfrmMonitor(ch chan<- XfrmMsg, done <-chan struct{}, errorChan chan<- error,
|
||||
types ...nl.XfrmMsgType) error {
|
||||
|
||||
groups, err := xfrmMcastGroups(types)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
s, err := nl.SubscribeAt(netns.None(), netns.None(), syscall.NETLINK_XFRM, groups...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if done != nil {
|
||||
go func() {
|
||||
<-done
|
||||
s.Close()
|
||||
}()
|
||||
|
||||
}
|
||||
|
||||
go func() {
|
||||
defer close(ch)
|
||||
for {
|
||||
msgs, err := s.Receive()
|
||||
if err != nil {
|
||||
errorChan <- err
|
||||
return
|
||||
}
|
||||
for _, m := range msgs {
|
||||
switch m.Header.Type {
|
||||
case nl.XFRM_MSG_EXPIRE:
|
||||
ch <- parseXfrmMsgExpire(m.Data)
|
||||
default:
|
||||
errorChan <- fmt.Errorf("unsupported msg type: %x", m.Header.Type)
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func xfrmMcastGroups(types []nl.XfrmMsgType) ([]uint, error) {
|
||||
groups := make([]uint, 0)
|
||||
|
||||
if len(types) == 0 {
|
||||
return nil, fmt.Errorf("no xfrm msg type specified")
|
||||
}
|
||||
|
||||
for _, t := range types {
|
||||
var group uint
|
||||
|
||||
switch t {
|
||||
case nl.XFRM_MSG_EXPIRE:
|
||||
group = nl.XFRMNLGRP_EXPIRE
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported group: %x", t)
|
||||
}
|
||||
|
||||
groups = append(groups, group)
|
||||
}
|
||||
|
||||
return groups, nil
|
||||
}
|
||||
+3
-2
@@ -83,11 +83,12 @@ type XfrmState struct {
|
||||
Crypt *XfrmStateAlgo
|
||||
Aead *XfrmStateAlgo
|
||||
Encap *XfrmStateEncap
|
||||
ESN bool
|
||||
}
|
||||
|
||||
func (sa XfrmState) String() string {
|
||||
return fmt.Sprintf("Dst: %v, Src: %v, Proto: %s, Mode: %s, SPI: 0x%x, ReqID: 0x%x, ReplayWindow: %d, Mark: %v, Auth: %v, Crypt: %v, Aead: %v,Encap: %v",
|
||||
sa.Dst, sa.Src, sa.Proto, sa.Mode, sa.Spi, sa.Reqid, sa.ReplayWindow, sa.Mark, sa.Auth, sa.Crypt, sa.Aead, sa.Encap)
|
||||
return fmt.Sprintf("Dst: %v, Src: %v, Proto: %s, Mode: %s, SPI: 0x%x, ReqID: 0x%x, ReplayWindow: %d, Mark: %v, Auth: %v, Crypt: %v, Aead: %v, Encap: %v, ESN: %t",
|
||||
sa.Dst, sa.Src, sa.Proto, sa.Mode, sa.Spi, sa.Reqid, sa.ReplayWindow, sa.Mark, sa.Auth, sa.Crypt, sa.Aead, sa.Encap, sa.ESN)
|
||||
}
|
||||
func (sa XfrmState) Print(stats bool) string {
|
||||
if !stats {
|
||||
|
||||
+94
-18
@@ -60,6 +60,21 @@ func writeMark(m *XfrmMark) []byte {
|
||||
return mark.Serialize()
|
||||
}
|
||||
|
||||
func writeReplayEsn(replayWindow int) []byte {
|
||||
replayEsn := &nl.XfrmReplayStateEsn{
|
||||
OSeq: 0,
|
||||
Seq: 0,
|
||||
OSeqHi: 0,
|
||||
SeqHi: 0,
|
||||
ReplayWindow: uint32(replayWindow),
|
||||
}
|
||||
|
||||
// taken from iproute2/ip/xfrm_state.c:
|
||||
replayEsn.BmpLen = uint32((replayWindow + (4 * 8) - 1) / (4 * 8))
|
||||
|
||||
return replayEsn.Serialize()
|
||||
}
|
||||
|
||||
// XfrmStateAdd will add an xfrm state to the system.
|
||||
// Equivalent to: `ip xfrm state add $state`
|
||||
func XfrmStateAdd(state *XfrmState) error {
|
||||
@@ -72,6 +87,12 @@ func (h *Handle) XfrmStateAdd(state *XfrmState) error {
|
||||
return h.xfrmStateAddOrUpdate(state, nl.XFRM_MSG_NEWSA)
|
||||
}
|
||||
|
||||
// XfrmStateAllocSpi will allocate an xfrm state in the system.
|
||||
// Equivalent to: `ip xfrm state allocspi`
|
||||
func XfrmStateAllocSpi(state *XfrmState) (*XfrmState, error) {
|
||||
return pkgHandle.xfrmStateAllocSpi(state)
|
||||
}
|
||||
|
||||
// XfrmStateUpdate will update an xfrm state to the system.
|
||||
// Equivalent to: `ip xfrm state update $state`
|
||||
func XfrmStateUpdate(state *XfrmState) error {
|
||||
@@ -85,21 +106,23 @@ func (h *Handle) XfrmStateUpdate(state *XfrmState) error {
|
||||
}
|
||||
|
||||
func (h *Handle) xfrmStateAddOrUpdate(state *XfrmState, nlProto int) error {
|
||||
|
||||
// A state with spi 0 can't be deleted so don't allow it to be set
|
||||
if state.Spi == 0 {
|
||||
return fmt.Errorf("Spi must be set when adding xfrm state.")
|
||||
}
|
||||
req := h.newNetlinkRequest(nlProto, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
|
||||
|
||||
msg := &nl.XfrmUsersaInfo{}
|
||||
msg.Family = uint16(nl.GetIPFamily(state.Dst))
|
||||
msg.Id.Daddr.FromIP(state.Dst)
|
||||
msg.Saddr.FromIP(state.Src)
|
||||
msg.Id.Proto = uint8(state.Proto)
|
||||
msg.Mode = uint8(state.Mode)
|
||||
msg.Id.Spi = nl.Swap32(uint32(state.Spi))
|
||||
msg.Reqid = uint32(state.Reqid)
|
||||
msg.ReplayWindow = uint8(state.ReplayWindow)
|
||||
msg := xfrmUsersaInfoFromXfrmState(state)
|
||||
|
||||
if state.ESN {
|
||||
if state.ReplayWindow == 0 {
|
||||
return fmt.Errorf("ESN flag set without ReplayWindow")
|
||||
}
|
||||
msg.Flags |= nl.XFRM_STATE_ESN
|
||||
msg.ReplayWindow = 0
|
||||
}
|
||||
|
||||
limitsToLft(state.Limits, &msg.Lft)
|
||||
req.AddData(msg)
|
||||
|
||||
@@ -129,11 +152,44 @@ func (h *Handle) xfrmStateAddOrUpdate(state *XfrmState, nlProto int) error {
|
||||
out := nl.NewRtAttr(nl.XFRMA_MARK, writeMark(state.Mark))
|
||||
req.AddData(out)
|
||||
}
|
||||
if state.ESN {
|
||||
out := nl.NewRtAttr(nl.XFRMA_REPLAY_ESN_VAL, writeReplayEsn(state.ReplayWindow))
|
||||
req.AddData(out)
|
||||
}
|
||||
|
||||
_, err := req.Execute(syscall.NETLINK_XFRM, 0)
|
||||
return err
|
||||
}
|
||||
|
||||
func (h *Handle) xfrmStateAllocSpi(state *XfrmState) (*XfrmState, error) {
|
||||
req := h.newNetlinkRequest(nl.XFRM_MSG_ALLOCSPI,
|
||||
syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
|
||||
|
||||
msg := &nl.XfrmUserSpiInfo{}
|
||||
msg.XfrmUsersaInfo = *(xfrmUsersaInfoFromXfrmState(state))
|
||||
// 1-255 is reserved by IANA for future use
|
||||
msg.Min = 0x100
|
||||
msg.Max = 0xffffffff
|
||||
req.AddData(msg)
|
||||
|
||||
if state.Mark != nil {
|
||||
out := nl.NewRtAttr(nl.XFRMA_MARK, writeMark(state.Mark))
|
||||
req.AddData(out)
|
||||
}
|
||||
|
||||
msgs, err := req.Execute(syscall.NETLINK_XFRM, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s, err := parseXfrmState(msgs[0], FAMILY_ALL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return s, err
|
||||
}
|
||||
|
||||
// XfrmStateDel will delete an xfrm state from the system. Note that
|
||||
// the Algos are ignored when matching the state to delete.
|
||||
// Equivalent to: `ip xfrm state del $state`
|
||||
@@ -241,14 +297,7 @@ func (h *Handle) xfrmStateGetOrDelete(state *XfrmState, nlProto int) (*XfrmState
|
||||
|
||||
var familyError = fmt.Errorf("family error")
|
||||
|
||||
func parseXfrmState(m []byte, family int) (*XfrmState, error) {
|
||||
msg := nl.DeserializeXfrmUsersaInfo(m)
|
||||
|
||||
// This is mainly for the state dump
|
||||
if family != FAMILY_ALL && family != int(msg.Family) {
|
||||
return nil, familyError
|
||||
}
|
||||
|
||||
func xfrmStateFromXfrmUsersaInfo(msg *nl.XfrmUsersaInfo) *XfrmState {
|
||||
var state XfrmState
|
||||
|
||||
state.Dst = msg.Id.Daddr.ToIP()
|
||||
@@ -260,6 +309,19 @@ func parseXfrmState(m []byte, family int) (*XfrmState, error) {
|
||||
state.ReplayWindow = int(msg.ReplayWindow)
|
||||
lftToLimits(&msg.Lft, &state.Limits)
|
||||
|
||||
return &state
|
||||
}
|
||||
|
||||
func parseXfrmState(m []byte, family int) (*XfrmState, error) {
|
||||
msg := nl.DeserializeXfrmUsersaInfo(m)
|
||||
|
||||
// This is mainly for the state dump
|
||||
if family != FAMILY_ALL && family != int(msg.Family) {
|
||||
return nil, familyError
|
||||
}
|
||||
|
||||
state := xfrmStateFromXfrmUsersaInfo(msg)
|
||||
|
||||
attrs, err := nl.ParseRouteAttr(m[nl.SizeofXfrmUsersaInfo:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -310,7 +372,7 @@ func parseXfrmState(m []byte, family int) (*XfrmState, error) {
|
||||
}
|
||||
}
|
||||
|
||||
return &state, nil
|
||||
return state, nil
|
||||
}
|
||||
|
||||
// XfrmStateFlush will flush the xfrm state on the system.
|
||||
@@ -366,3 +428,17 @@ func limitsToLft(lmts XfrmStateLimits, lft *nl.XfrmLifetimeCfg) {
|
||||
func lftToLimits(lft *nl.XfrmLifetimeCfg, lmts *XfrmStateLimits) {
|
||||
*lmts = *(*XfrmStateLimits)(unsafe.Pointer(lft))
|
||||
}
|
||||
|
||||
func xfrmUsersaInfoFromXfrmState(state *XfrmState) *nl.XfrmUsersaInfo {
|
||||
msg := &nl.XfrmUsersaInfo{}
|
||||
msg.Family = uint16(nl.GetIPFamily(state.Dst))
|
||||
msg.Id.Daddr.FromIP(state.Dst)
|
||||
msg.Saddr.FromIP(state.Src)
|
||||
msg.Id.Proto = uint8(state.Proto)
|
||||
msg.Mode = uint8(state.Mode)
|
||||
msg.Id.Spi = nl.Swap32(uint32(state.Spi))
|
||||
msg.Reqid = uint32(state.Reqid)
|
||||
msg.ReplayWindow = uint8(state.ReplayWindow)
|
||||
|
||||
return msg
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
# This source code refers to The Go Authors for copyright purposes.
|
||||
# The master list of authors is in the main Go distribution,
|
||||
# visible at http://tip.golang.org/AUTHORS.
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
# This source code was written by the Go contributors.
|
||||
# The master list of contributors is in the main Go distribution,
|
||||
# visible at http://tip.golang.org/CONTRIBUTORS.
|
||||
File mode changed.
File mode changed.
File mode changed.
File mode changed.
File mode changed.
File mode changed.
File mode changed.
File mode changed.
File mode changed.
File mode changed.
File mode changed.
Reference in new issue
Block a user