{
"ImportPath": "github.com/containernetworking/cni",
"GoVersion": "go1.6",
- "GodepVersion": "v75",
+ "GodepVersion": "v79",
"Packages": [
"./..."
],
"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",
},
{
"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"
}
]
}
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)))
// 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
// 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
+}
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 {
}
}
+ 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)
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:
package netlink
import (
+ "fmt"
"syscall"
+ "time"
"github.com/vishvananda/netlink/nl"
"github.com/vishvananda/netns"
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
--- /dev/null
+// +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
+}
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
}
}
+type LinkStatistics LinkStatistics64
+
/*
Ref: struct rtnl_link_stats {...}
*/
-type LinkStatistics struct {
+type LinkStatistics32 struct {
RxPackets uint32
TxPackets uint32
RxBytes uint32
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
// 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,
}
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 |
"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
TUNTAP_ONE_QUEUE TuntapFlag = syscall.IFF_ONE_QUEUE
)
-var native = nl.NativeEndian()
var lookupByDump = false
var macvlanModes = [...]uint32{
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 {
}
} 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)
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")
// 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():])
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:
link = &Macvtap{}
case "gretap":
link = &Gretap{}
+ case "ipip":
+ link = &Iptun{}
+ case "vti":
+ link = &Vti{}
+ case "vrf":
+ link = &Vrf{}
default:
link = &GenericLink{LinkType: linkType}
}
parseMacvtapData(link, data)
case "gretap":
parseGretapData(link, data)
+ case "ipip":
+ parseIptunData(link, data)
+ case "vti":
+ parseVtiData(link, data)
+ case "vrf":
+ parseVrfData(link, data)
}
}
}
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{}
var res []Link
for _, m := range msgs {
- link, err := linkDeserialize(m)
+ link, err := LinkDeserialize(nil, m)
if err != nil {
return nil, err
}
}
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
}
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)
}
}
-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) {
}
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])
+ }
+ }
+}
// 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
// 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
)
package netlink
-import (
- "errors"
-)
+import "net"
-var (
- ErrNotImplemented = errors.New("not implemented")
-)
+func LinkSetUp(link Link) error {
+ return ErrNotImplemented
+}
+
+func LinkSetDown(link Link) error {
+ return ErrNotImplemented
+}
+
+func LinkSetMTU(link Link, mtu int) error {
+ return ErrNotImplemented
+}
+
+func LinkSetMaster(link Link, master *Link) error {
+ return ErrNotImplemented
+}
+
+func LinkSetNsPid(link Link, nspid int) error {
+ return ErrNotImplemented
+}
+
+func LinkSetNsFd(link Link, fd int) error {
+ return ErrNotImplemented
+}
+
+func LinkSetName(link Link, name string) error {
+ return ErrNotImplemented
+}
+
+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 LinkSetUp(link *Link) error {
+func LinkSetHairpin(link Link, mode bool) error {
return ErrNotImplemented
}
-func LinkSetDown(link *Link) error {
+func LinkSetGuard(link Link, mode bool) error {
return ErrNotImplemented
}
-func LinkSetMTU(link *Link, mtu int) error {
+func LinkSetFastLeave(link Link, mode bool) error {
return ErrNotImplemented
}
-func LinkSetMaster(link *Link, master *Link) error {
+func LinkSetLearning(link Link, mode bool) error {
return ErrNotImplemented
}
-func LinkSetNsPid(link *Link, nspid int) error {
+func LinkSetRootBlock(link Link, mode bool) error {
return ErrNotImplemented
}
-func LinkSetNsFd(link *Link, fd int) error {
+func LinkSetFlood(link Link, mode bool) error {
return ErrNotImplemented
}
-func LinkAdd(link *Link) error {
+func LinkAdd(link Link) error {
return ErrNotImplemented
}
-func LinkDel(link *Link) error {
+func LinkDel(link Link) error {
return ErrNotImplemented
}
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
}
return ErrNotImplemented
}
-func RouteList(link *Link, family int) ([]Route, error) {
+func RouteList(link Link, family int) ([]Route, error) {
return nil, ErrNotImplemented
}
func NeighDeserialize(m []byte) (*Neigh, error) {
return nil, ErrNotImplemented
}
+
+func SocketGet(local, remote net.Addr) (*Socket, error) {
+ return nil, ErrNotImplemented
+}
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
+)
--- /dev/null
+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
+}
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
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 {
--- /dev/null
+// +build !linux
+
+package nl
+
+import "encoding/binary"
+
+var SupportedNlFamilies = []int{}
+
+func NativeEndian() binary.ByteOrder {
+ return nil
+}
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
}
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
+)
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
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];
--- /dev/null
+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)))[:]
+}
)
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 {
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 */
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)))[:]
+}
--- /dev/null
+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)
+}
}
func byteToBool(x byte) bool {
- if uint8(x) != 0 {
- return true
- }
- return false
+ return uint8(x) != 0
}
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
+}
// 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
}
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
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
import (
"fmt"
"net"
+ "strings"
)
// Scope is an enum representing a route scope.
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
Type int
Tos int
Flags int
+ MPLSDst *int
+ NewDst Destination
+ Encap Encap
}
func (r Route) String() string {
+ elems := []string{}
+ if len(r.MultiPath) == 0 {
+ elems = append(elems, fmt.Sprintf("Ifindex: %d", r.LinkIndex))
+ }
+ 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 {
- return fmt.Sprintf("{Dst: %s Src: %s Gw: %s Flags: %s Table: %d}", r.Dst,
- r.Src, r.MultiPath, r.ListFlags(), r.Table)
+ elems = append(elems, fmt.Sprintf("Gw: %s", r.MultiPath))
+ } else {
+ elems = append(elems, fmt.Sprintf("Gw: %s", r.Gw))
}
- 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)
+ 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) {
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, " "))
}
import (
"fmt"
"net"
+ "strings"
"syscall"
"github.com/vishvananda/netlink/nl"
{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 {
// 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())
}
}
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")
}
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 {
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))
}
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
+ }
+ }
}
}
}
}
native := nl.NativeEndian()
+ var encap, encapType syscall.NetlinkRouteAttr
for _, attr := range attrs {
switch attr.Attr.Type {
case syscall.RTA_GATEWAY:
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]))
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
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
}
func (r *Route) ListFlags() []string {
return []string{}
}
+
+func (n *NexthopInfo) ListFlags() []string {
+ return []string{}
+}
--- /dev/null
+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
+}
--- /dev/null
+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
+}
--- /dev/null
+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
+}
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 {
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 {
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 {
}
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)
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`
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()
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
}
}
- return &state, nil
+ return state, nil
}
// XfrmStateFlush will flush the xfrm state on the system.
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
+}
--- /dev/null
+# 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.
--- /dev/null
+# 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.