vendor folder bump.

This commit is contained in:
Sebastian Sch 2018-11-18 15:43:35 +02:00
parent 18874aac7d
commit dc536993e2
458 changed files with 66427 additions and 13303 deletions

26
Godeps/Godeps.json generated
View File

@ -1,7 +1,7 @@
{ {
"ImportPath": "github.com/containernetworking/plugins", "ImportPath": "github.com/containernetworking/plugins",
"GoVersion": "go1.7", "GoVersion": "go1.7",
"GodepVersion": "v79", "GodepVersion": "v80",
"Packages": [ "Packages": [
"./..." "./..."
], ],
@ -318,39 +318,45 @@
}, },
{ {
"ImportPath": "github.com/vishvananda/netlink", "ImportPath": "github.com/vishvananda/netlink",
"Rev": "6e453822d85ef5721799774b654d4d02fed62afb" "Comment": "v1.0.0-40-g023a6da",
"Rev": "023a6dafdcdfa7068ac83b260ab7f03cd4131aca"
}, },
{ {
"ImportPath": "github.com/vishvananda/netlink/nl", "ImportPath": "github.com/vishvananda/netlink/nl",
"Rev": "6e453822d85ef5721799774b654d4d02fed62afb" "Comment": "v1.0.0-40-g023a6da",
"Rev": "023a6dafdcdfa7068ac83b260ab7f03cd4131aca"
}, },
{ {
"ImportPath": "github.com/vishvananda/netns", "ImportPath": "github.com/vishvananda/netns",
"Rev": "54f0e4339ce73702a0607f49922aaa1e749b418d" "Rev": "13995c7128ccc8e51e9a6bd2b551020a27180abd"
}, },
{ {
"ImportPath": "golang.org/x/crypto/ssh/terminal", "ImportPath": "golang.org/x/crypto/ssh/terminal",
"Rev": "94eea52f7b742c7cbe0b03b22f0c4c8631ece122" "Rev": "7c1a557ab941a71c619514f229f0b27ccb0c27cf"
}, },
{ {
"ImportPath": "golang.org/x/net/bpf", "ImportPath": "golang.org/x/net/bpf",
"Rev": "e90d6d0afc4c315a0d87a568ae68577cc15149a0" "Rev": "49bb7cea24b1df9410e1712aa6433dae904ff66a"
}, },
{ {
"ImportPath": "golang.org/x/net/internal/iana", "ImportPath": "golang.org/x/net/internal/iana",
"Rev": "e90d6d0afc4c315a0d87a568ae68577cc15149a0" "Rev": "49bb7cea24b1df9410e1712aa6433dae904ff66a"
}, },
{ {
"ImportPath": "golang.org/x/net/ipv4", "ImportPath": "golang.org/x/net/ipv4",
"Rev": "e90d6d0afc4c315a0d87a568ae68577cc15149a0" "Rev": "49bb7cea24b1df9410e1712aa6433dae904ff66a"
}, },
{ {
"ImportPath": "golang.org/x/sys/unix", "ImportPath": "golang.org/x/sys/unix",
"Rev": "d5840adf789d732bc8b00f37b26ca956a7cc8e79" "Rev": "66b7b1311ac80bbafcd2daeef9a5e6e2cd1e2399"
}, },
{ {
"ImportPath": "golang.org/x/sys/windows", "ImportPath": "golang.org/x/sys/windows",
"Rev": "d5840adf789d732bc8b00f37b26ca956a7cc8e79" "Rev": "66b7b1311ac80bbafcd2daeef9a5e6e2cd1e2399"
},
{
"ImportPath": "golang.org/x/net/internal/socket",
"Rev": "49bb7cea24b1df9410e1712aa6433dae904ff66a"
} }
] ]
} }

View File

@ -1,4 +1,7 @@
language: go language: go
go:
- "1.10.x"
- "1.11.x"
before_script: before_script:
# make sure we keep path in tact when we sudo # make sure we keep path in tact when we sudo
- sudo sed -i -e 's/^Defaults\tsecure_path.*$//' /etc/sudoers - sudo sed -i -e 's/^Defaults\tsecure_path.*$//' /etc/sudoers
@ -9,5 +12,6 @@ before_script:
- sudo modprobe nf_conntrack_netlink - sudo modprobe nf_conntrack_netlink
- sudo modprobe nf_conntrack_ipv4 - sudo modprobe nf_conntrack_ipv4
- sudo modprobe nf_conntrack_ipv6 - sudo modprobe nf_conntrack_ipv6
- sudo modprobe sch_hfsc
install: install:
- go get github.com/vishvananda/netns - go get github.com/vishvananda/netns

5
vendor/github.com/vishvananda/netlink/CHANGELOG.md generated vendored Normal file
View File

@ -0,0 +1,5 @@
# Changelog
## 1.0.0 (2018-03-15)
Initial release tagging

View File

@ -3,7 +3,8 @@ DIRS := \
nl nl
DEPS = \ DEPS = \
github.com/vishvananda/netns github.com/vishvananda/netns \
golang.org/x/sys/unix
uniq = $(if $1,$(firstword $1) $(call uniq,$(filter-out $(firstword $1),$1))) uniq = $(if $1,$(firstword $1) $(call uniq,$(filter-out $(firstword $1),$1)))
testdirs = $(call uniq,$(foreach d,$(1),$(dir $(wildcard $(d)/*_test.go)))) testdirs = $(call uniq,$(foreach d,$(1),$(dir $(wildcard $(d)/*_test.go))))
@ -18,7 +19,7 @@ $(call goroot,$(DEPS)):
.PHONY: $(call testdirs,$(DIRS)) .PHONY: $(call testdirs,$(DIRS))
$(call testdirs,$(DIRS)): $(call testdirs,$(DIRS)):
sudo -E go test -test.parallel 4 -timeout 60s -v github.com/vishvananda/netlink/$@ go test -test.exec sudo -test.parallel 4 -timeout 60s -test.v github.com/vishvananda/netlink/$@
$(call fmt,$(call testdirs,$(DIRS))): $(call fmt,$(call testdirs,$(DIRS))):
! gofmt -l $(subst fmt-,,$@)/*.go | grep -q . ! gofmt -l $(subst fmt-,,$@)/*.go | grep -q .

View File

@ -38,15 +38,18 @@ Add a new bridge and add eth1 into it:
package main package main
import ( import (
"net" "fmt"
"github.com/vishvananda/netlink" "github.com/vishvananda/netlink"
) )
func main() { func main() {
la := netlink.NewLinkAttrs() la := netlink.NewLinkAttrs()
la.Name = "foo" la.Name = "foo"
mybridge := &netlink.Bridge{la}} mybridge := &netlink.Bridge{LinkAttrs: la}
_ := netlink.LinkAdd(mybridge) err := netlink.LinkAdd(mybridge)
if err != nil {
fmt.Printf("could not add %s: %v\n", la.Name, err)
}
eth1, _ := netlink.LinkByName("eth1") eth1, _ := netlink.LinkByName("eth1")
netlink.LinkSetMaster(eth1, mybridge) netlink.LinkSetMaster(eth1, mybridge)
} }
@ -63,7 +66,6 @@ Add a new ip address to loopback:
package main package main
import ( import (
"net"
"github.com/vishvananda/netlink" "github.com/vishvananda/netlink"
) )
@ -87,3 +89,4 @@ There are also a few pieces of low level netlink functionality that still
need to be implemented. Routing rules are not in place and some of the need to be implemented. Routing rules are not in place and some of the
more advanced link types. Hopefully there is decent structure and testing more advanced link types. Hopefully there is decent structure and testing
in place to make these fairly straightforward to add. in place to make these fairly straightforward to add.

View File

@ -2,13 +2,13 @@ package netlink
import ( import (
"fmt" "fmt"
"log"
"net" "net"
"strings" "strings"
"syscall" "syscall"
"github.com/vishvananda/netlink/nl" "github.com/vishvananda/netlink/nl"
"github.com/vishvananda/netns" "github.com/vishvananda/netns"
"golang.org/x/sys/unix"
) )
// IFA_FLAGS is a u32 attribute. // IFA_FLAGS is a u32 attribute.
@ -23,7 +23,7 @@ func AddrAdd(link Link, addr *Addr) error {
// AddrAdd will add an IP address to a link device. // AddrAdd will add an IP address to a link device.
// Equivalent to: `ip addr add $addr dev $link` // Equivalent to: `ip addr add $addr dev $link`
func (h *Handle) AddrAdd(link Link, addr *Addr) error { func (h *Handle) AddrAdd(link Link, addr *Addr) error {
req := h.newNetlinkRequest(syscall.RTM_NEWADDR, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK) req := h.newNetlinkRequest(unix.RTM_NEWADDR, unix.NLM_F_CREATE|unix.NLM_F_EXCL|unix.NLM_F_ACK)
return h.addrHandle(link, addr, req) return h.addrHandle(link, addr, req)
} }
@ -36,7 +36,7 @@ func AddrReplace(link Link, addr *Addr) error {
// AddrReplace will replace (or, if not present, add) an IP address on a link device. // AddrReplace will replace (or, if not present, add) an IP address on a link device.
// Equivalent to: `ip addr replace $addr dev $link` // Equivalent to: `ip addr replace $addr dev $link`
func (h *Handle) AddrReplace(link Link, addr *Addr) error { func (h *Handle) AddrReplace(link Link, addr *Addr) error {
req := h.newNetlinkRequest(syscall.RTM_NEWADDR, syscall.NLM_F_CREATE|syscall.NLM_F_REPLACE|syscall.NLM_F_ACK) req := h.newNetlinkRequest(unix.RTM_NEWADDR, unix.NLM_F_CREATE|unix.NLM_F_REPLACE|unix.NLM_F_ACK)
return h.addrHandle(link, addr, req) return h.addrHandle(link, addr, req)
} }
@ -49,7 +49,7 @@ func AddrDel(link Link, addr *Addr) error {
// AddrDel will delete an IP address from a link device. // AddrDel will delete an IP address from a link device.
// Equivalent to: `ip addr del $addr dev $link` // Equivalent to: `ip addr del $addr dev $link`
func (h *Handle) AddrDel(link Link, addr *Addr) error { func (h *Handle) AddrDel(link Link, addr *Addr) error {
req := h.newNetlinkRequest(syscall.RTM_DELADDR, syscall.NLM_F_ACK) req := h.newNetlinkRequest(unix.RTM_DELADDR, unix.NLM_F_ACK)
return h.addrHandle(link, addr, req) return h.addrHandle(link, addr, req)
} }
@ -65,7 +65,11 @@ func (h *Handle) addrHandle(link Link, addr *Addr, req *nl.NetlinkRequest) error
msg := nl.NewIfAddrmsg(family) msg := nl.NewIfAddrmsg(family)
msg.Index = uint32(base.Index) msg.Index = uint32(base.Index)
msg.Scope = uint8(addr.Scope) msg.Scope = uint8(addr.Scope)
prefixlen, _ := addr.Mask.Size() mask := addr.Mask
if addr.Peer != nil {
mask = addr.Peer.Mask
}
prefixlen, masklen := mask.Size()
msg.Prefixlen = uint8(prefixlen) msg.Prefixlen = uint8(prefixlen)
req.AddData(msg) req.AddData(msg)
@ -76,7 +80,7 @@ func (h *Handle) addrHandle(link Link, addr *Addr, req *nl.NetlinkRequest) error
localAddrData = addr.IP.To16() localAddrData = addr.IP.To16()
} }
localData := nl.NewRtAttr(syscall.IFA_LOCAL, localAddrData) localData := nl.NewRtAttr(unix.IFA_LOCAL, localAddrData)
req.AddData(localData) req.AddData(localData)
var peerAddrData []byte var peerAddrData []byte
if addr.Peer != nil { if addr.Peer != nil {
@ -89,7 +93,7 @@ func (h *Handle) addrHandle(link Link, addr *Addr, req *nl.NetlinkRequest) error
peerAddrData = localAddrData peerAddrData = localAddrData
} }
addressData := nl.NewRtAttr(syscall.IFA_ADDRESS, peerAddrData) addressData := nl.NewRtAttr(unix.IFA_ADDRESS, peerAddrData)
req.AddData(addressData) req.AddData(addressData)
if addr.Flags != 0 { if addr.Flags != 0 {
@ -103,16 +107,34 @@ func (h *Handle) addrHandle(link Link, addr *Addr, req *nl.NetlinkRequest) error
} }
} }
if addr.Broadcast != nil { if family == FAMILY_V4 {
req.AddData(nl.NewRtAttr(syscall.IFA_BROADCAST, addr.Broadcast)) if addr.Broadcast == nil {
calcBroadcast := make(net.IP, masklen/8)
for i := range localAddrData {
calcBroadcast[i] = localAddrData[i] | ^mask[i]
}
addr.Broadcast = calcBroadcast
}
req.AddData(nl.NewRtAttr(unix.IFA_BROADCAST, addr.Broadcast))
if addr.Label != "" {
labelData := nl.NewRtAttr(unix.IFA_LABEL, nl.ZeroTerminated(addr.Label))
req.AddData(labelData)
}
} }
if addr.Label != "" { // 0 is the default value for these attributes. However, 0 means "expired", while the least-surprising default
labelData := nl.NewRtAttr(syscall.IFA_LABEL, nl.ZeroTerminated(addr.Label)) // value should be "forever". To compensate for that, only add the attributes if at least one of the values is
req.AddData(labelData) // non-zero, which means the caller has explicitly set them
if addr.ValidLft > 0 || addr.PreferedLft > 0 {
cachedata := nl.IfaCacheInfo{
IfaValid: uint32(addr.ValidLft),
IfaPrefered: uint32(addr.PreferedLft),
}
req.AddData(nl.NewRtAttr(unix.IFA_CACHEINFO, cachedata.Serialize()))
} }
_, err := req.Execute(syscall.NETLINK_ROUTE, 0) _, err := req.Execute(unix.NETLINK_ROUTE, 0)
return err return err
} }
@ -127,11 +149,11 @@ func AddrList(link Link, family int) ([]Addr, error) {
// Equivalent to: `ip addr show`. // Equivalent to: `ip addr show`.
// The list can be filtered by link and ip family. // The list can be filtered by link and ip family.
func (h *Handle) AddrList(link Link, family int) ([]Addr, error) { func (h *Handle) AddrList(link Link, family int) ([]Addr, error) {
req := h.newNetlinkRequest(syscall.RTM_GETADDR, syscall.NLM_F_DUMP) req := h.newNetlinkRequest(unix.RTM_GETADDR, unix.NLM_F_DUMP)
msg := nl.NewIfInfomsg(family) msg := nl.NewIfInfomsg(family)
req.AddData(msg) req.AddData(msg)
msgs, err := req.Execute(syscall.NETLINK_ROUTE, syscall.RTM_NEWADDR) msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWADDR)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -183,21 +205,25 @@ func parseAddr(m []byte) (addr Addr, family, index int, err error) {
var local, dst *net.IPNet var local, dst *net.IPNet
for _, attr := range attrs { for _, attr := range attrs {
switch attr.Attr.Type { switch attr.Attr.Type {
case syscall.IFA_ADDRESS: case unix.IFA_ADDRESS:
dst = &net.IPNet{ dst = &net.IPNet{
IP: attr.Value, IP: attr.Value,
Mask: net.CIDRMask(int(msg.Prefixlen), 8*len(attr.Value)), Mask: net.CIDRMask(int(msg.Prefixlen), 8*len(attr.Value)),
} }
addr.Peer = dst case unix.IFA_LOCAL:
case syscall.IFA_LOCAL: // iproute2 manual:
// If a peer address is specified, the local address
// cannot have a prefix length. The network prefix is
// associated with the peer rather than with the local
// address.
n := 8 * len(attr.Value)
local = &net.IPNet{ local = &net.IPNet{
IP: attr.Value, IP: attr.Value,
Mask: net.CIDRMask(int(msg.Prefixlen), 8*len(attr.Value)), Mask: net.CIDRMask(n, n),
} }
addr.IPNet = local case unix.IFA_BROADCAST:
case syscall.IFA_BROADCAST:
addr.Broadcast = attr.Value addr.Broadcast = attr.Value
case syscall.IFA_LABEL: case unix.IFA_LABEL:
addr.Label = string(attr.Value[:len(attr.Value)-1]) addr.Label = string(attr.Value[:len(attr.Value)-1])
case IFA_FLAGS: case IFA_FLAGS:
addr.Flags = int(native.Uint32(attr.Value[0:4])) addr.Flags = int(native.Uint32(attr.Value[0:4]))
@ -208,12 +234,24 @@ func parseAddr(m []byte) (addr Addr, family, index int, err error) {
} }
} }
// IFA_LOCAL should be there but if not, fall back to IFA_ADDRESS // libnl addr.c comment:
// IPv6 sends the local address as IFA_ADDRESS with no
// IFA_LOCAL, IPv4 sends both IFA_LOCAL and IFA_ADDRESS
// with IFA_ADDRESS being the peer address if they differ
//
// But obviously, as there are IPv6 PtP addresses, too,
// IFA_LOCAL should also be handled for IPv6.
if local != nil { if local != nil {
addr.IPNet = local if family == FAMILY_V4 && local.IP.Equal(dst.IP) {
addr.IPNet = dst
} else {
addr.IPNet = local
addr.Peer = dst
}
} else { } else {
addr.IPNet = dst addr.IPNet = dst
} }
addr.Scope = int(msg.Scope) addr.Scope = int(msg.Scope)
return return
@ -232,17 +270,36 @@ type AddrUpdate struct {
// AddrSubscribe takes a chan down which notifications will be sent // AddrSubscribe takes a chan down which notifications will be sent
// when addresses change. Close the 'done' chan to stop subscription. // when addresses change. Close the 'done' chan to stop subscription.
func AddrSubscribe(ch chan<- AddrUpdate, done <-chan struct{}) error { func AddrSubscribe(ch chan<- AddrUpdate, done <-chan struct{}) error {
return addrSubscribe(netns.None(), netns.None(), ch, done) return addrSubscribeAt(netns.None(), netns.None(), ch, done, nil, false)
} }
// AddrSubscribeAt works like AddrSubscribe plus it allows the caller // AddrSubscribeAt works like AddrSubscribe plus it allows the caller
// to choose the network namespace in which to subscribe (ns). // to choose the network namespace in which to subscribe (ns).
func AddrSubscribeAt(ns netns.NsHandle, ch chan<- AddrUpdate, done <-chan struct{}) error { func AddrSubscribeAt(ns netns.NsHandle, ch chan<- AddrUpdate, done <-chan struct{}) error {
return addrSubscribe(ns, netns.None(), ch, done) return addrSubscribeAt(ns, netns.None(), ch, done, nil, false)
} }
func addrSubscribe(newNs, curNs netns.NsHandle, ch chan<- AddrUpdate, done <-chan struct{}) error { // AddrSubscribeOptions contains a set of options to use with
s, err := nl.SubscribeAt(newNs, curNs, syscall.NETLINK_ROUTE, syscall.RTNLGRP_IPV4_IFADDR, syscall.RTNLGRP_IPV6_IFADDR) // AddrSubscribeWithOptions.
type AddrSubscribeOptions struct {
Namespace *netns.NsHandle
ErrorCallback func(error)
ListExisting bool
}
// AddrSubscribeWithOptions work like AddrSubscribe but enable to
// provide additional options to modify the behavior. Currently, the
// namespace can be provided as well as an error callback.
func AddrSubscribeWithOptions(ch chan<- AddrUpdate, done <-chan struct{}, options AddrSubscribeOptions) error {
if options.Namespace == nil {
none := netns.None()
options.Namespace = &none
}
return addrSubscribeAt(*options.Namespace, netns.None(), ch, done, options.ErrorCallback, options.ListExisting)
}
func addrSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- AddrUpdate, done <-chan struct{}, cberr func(error), listExisting bool) error {
s, err := nl.SubscribeAt(newNs, curNs, unix.NETLINK_ROUTE, unix.RTNLGRP_IPV4_IFADDR, unix.RTNLGRP_IPV6_IFADDR)
if err != nil { if err != nil {
return err return err
} }
@ -252,30 +309,59 @@ func addrSubscribe(newNs, curNs netns.NsHandle, ch chan<- AddrUpdate, done <-cha
s.Close() s.Close()
}() }()
} }
if listExisting {
req := pkgHandle.newNetlinkRequest(unix.RTM_GETADDR,
unix.NLM_F_DUMP)
infmsg := nl.NewIfInfomsg(unix.AF_UNSPEC)
req.AddData(infmsg)
if err := s.Send(req); err != nil {
return err
}
}
go func() { go func() {
defer close(ch) defer close(ch)
for { for {
msgs, err := s.Receive() msgs, err := s.Receive()
if err != nil { if err != nil {
log.Printf("netlink.AddrSubscribe: Receive() error: %v", err) if cberr != nil {
cberr(err)
}
return return
} }
for _, m := range msgs { for _, m := range msgs {
msgType := m.Header.Type if m.Header.Type == unix.NLMSG_DONE {
if msgType != syscall.RTM_NEWADDR && msgType != syscall.RTM_DELADDR {
log.Printf("netlink.AddrSubscribe: bad message type: %d", msgType)
continue continue
} }
if m.Header.Type == unix.NLMSG_ERROR {
native := nl.NativeEndian()
error := int32(native.Uint32(m.Data[0:4]))
if error == 0 {
continue
}
if cberr != nil {
cberr(syscall.Errno(-error))
}
return
}
msgType := m.Header.Type
if msgType != unix.RTM_NEWADDR && msgType != unix.RTM_DELADDR {
if cberr != nil {
cberr(fmt.Errorf("bad message type: %d", msgType))
}
return
}
addr, _, ifindex, err := parseAddr(m.Data) addr, _, ifindex, err := parseAddr(m.Data)
if err != nil { if err != nil {
log.Printf("netlink.AddrSubscribe: could not parse address: %v", err) if cberr != nil {
continue cberr(fmt.Errorf("could not parse address: %v", err))
}
return
} }
ch <- AddrUpdate{LinkAddress: *addr.IPNet, ch <- AddrUpdate{LinkAddress: *addr.IPNet,
LinkIndex: ifindex, LinkIndex: ifindex,
NewAddr: msgType == syscall.RTM_NEWADDR, NewAddr: msgType == unix.RTM_NEWADDR,
Flags: addr.Flags, Flags: addr.Flags,
Scope: addr.Scope, Scope: addr.Scope,
PreferedLft: addr.PreferedLft, PreferedLft: addr.PreferedLft,

View File

@ -1,49 +1,12 @@
package netlink package netlink
/* import (
#include <asm/types.h> "unsafe"
#include <asm/unistd.h>
#include <errno.h>
#include <stdio.h>
#include <stdint.h>
#include <unistd.h>
static int load_simple_bpf(int prog_type, int ret) { "golang.org/x/sys/unix"
#ifdef __NR_bpf )
// { return ret; }
__u64 __attribute__((aligned(8))) insns[] = {
0x00000000000000b7ull | ((__u64)ret<<32),
0x0000000000000095ull,
};
__u8 __attribute__((aligned(8))) license[] = "ASL2";
// Copied from a header file since libc is notoriously slow to update.
// The call will succeed or fail and that will be our indication on
// whether or not it is supported.
struct {
__u32 prog_type;
__u32 insn_cnt;
__u64 insns;
__u64 license;
__u32 log_level;
__u32 log_size;
__u64 log_buf;
__u32 kern_version;
} __attribute__((aligned(8))) attr = {
.prog_type = prog_type,
.insn_cnt = 2,
.insns = (uintptr_t)&insns,
.license = (uintptr_t)&license,
};
return syscall(__NR_bpf, 5, &attr, sizeof(attr));
#else
errno = EINVAL;
return -1;
#endif
}
*/
import "C"
type BpfProgType C.int type BpfProgType uint32
const ( const (
BPF_PROG_TYPE_UNSPEC BpfProgType = iota BPF_PROG_TYPE_UNSPEC BpfProgType = iota
@ -55,8 +18,36 @@ const (
BPF_PROG_TYPE_XDP BPF_PROG_TYPE_XDP
) )
// loadSimpleBpf loads a trivial bpf program for testing purposes type BPFAttr struct {
func loadSimpleBpf(progType BpfProgType, ret int) (int, error) { ProgType uint32
fd, err := C.load_simple_bpf(C.int(progType), C.int(ret)) InsnCnt uint32
return int(fd), err Insns uintptr
License uintptr
LogLevel uint32
LogSize uint32
LogBuf uintptr
KernVersion uint32
}
// loadSimpleBpf loads a trivial bpf program for testing purposes.
func loadSimpleBpf(progType BpfProgType, ret uint32) (int, error) {
insns := []uint64{
0x00000000000000b7 | (uint64(ret) << 32),
0x0000000000000095,
}
license := []byte{'A', 'S', 'L', '2', '\x00'}
attr := BPFAttr{
ProgType: uint32(progType),
InsnCnt: uint32(len(insns)),
Insns: uintptr(unsafe.Pointer(&insns[0])),
License: uintptr(unsafe.Pointer(&license[0])),
}
fd, _, errno := unix.Syscall(unix.SYS_BPF,
5, /* bpf cmd */
uintptr(unsafe.Pointer(&attr)),
unsafe.Sizeof(attr))
if errno != 0 {
return 0, errno
}
return int(fd), nil
} }

View File

@ -2,9 +2,9 @@ package netlink
import ( import (
"fmt" "fmt"
"syscall"
"github.com/vishvananda/netlink/nl" "github.com/vishvananda/netlink/nl"
"golang.org/x/sys/unix"
) )
// BridgeVlanList gets a map of device id to bridge vlan infos. // BridgeVlanList gets a map of device id to bridge vlan infos.
@ -16,12 +16,12 @@ func BridgeVlanList() (map[int32][]*nl.BridgeVlanInfo, error) {
// BridgeVlanList gets a map of device id to bridge vlan infos. // BridgeVlanList gets a map of device id to bridge vlan infos.
// Equivalent to: `bridge vlan show` // Equivalent to: `bridge vlan show`
func (h *Handle) BridgeVlanList() (map[int32][]*nl.BridgeVlanInfo, error) { func (h *Handle) BridgeVlanList() (map[int32][]*nl.BridgeVlanInfo, error) {
req := h.newNetlinkRequest(syscall.RTM_GETLINK, syscall.NLM_F_DUMP) req := h.newNetlinkRequest(unix.RTM_GETLINK, unix.NLM_F_DUMP)
msg := nl.NewIfInfomsg(syscall.AF_BRIDGE) msg := nl.NewIfInfomsg(unix.AF_BRIDGE)
req.AddData(msg) req.AddData(msg)
req.AddData(nl.NewRtAttr(nl.IFLA_EXT_MASK, nl.Uint32Attr(uint32(nl.RTEXT_FILTER_BRVLAN)))) req.AddData(nl.NewRtAttr(unix.IFLA_EXT_MASK, nl.Uint32Attr(uint32(nl.RTEXT_FILTER_BRVLAN))))
msgs, err := req.Execute(syscall.NETLINK_ROUTE, syscall.RTM_NEWLINK) msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWLINK)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -35,7 +35,7 @@ func (h *Handle) BridgeVlanList() (map[int32][]*nl.BridgeVlanInfo, error) {
} }
for _, attr := range attrs { for _, attr := range attrs {
switch attr.Attr.Type { switch attr.Attr.Type {
case nl.IFLA_AF_SPEC: case unix.IFLA_AF_SPEC:
//nested attr //nested attr
nestAttrs, err := nl.ParseRouteAttr(attr.Value) nestAttrs, err := nl.ParseRouteAttr(attr.Value)
if err != nil { if err != nil {
@ -63,7 +63,7 @@ func BridgeVlanAdd(link Link, vid uint16, pvid, untagged, self, master bool) err
// BridgeVlanAdd adds a new vlan filter entry // BridgeVlanAdd adds a new vlan filter entry
// Equivalent to: `bridge vlan add dev DEV vid VID [ pvid ] [ untagged ] [ self ] [ master ]` // Equivalent to: `bridge vlan add dev DEV vid VID [ pvid ] [ untagged ] [ self ] [ master ]`
func (h *Handle) BridgeVlanAdd(link Link, vid uint16, pvid, untagged, self, master bool) error { func (h *Handle) BridgeVlanAdd(link Link, vid uint16, pvid, untagged, self, master bool) error {
return h.bridgeVlanModify(syscall.RTM_SETLINK, link, vid, pvid, untagged, self, master) return h.bridgeVlanModify(unix.RTM_SETLINK, link, vid, pvid, untagged, self, master)
} }
// BridgeVlanDel adds a new vlan filter entry // BridgeVlanDel adds a new vlan filter entry
@ -75,19 +75,19 @@ func BridgeVlanDel(link Link, vid uint16, pvid, untagged, self, master bool) err
// BridgeVlanDel adds a new vlan filter entry // BridgeVlanDel adds a new vlan filter entry
// Equivalent to: `bridge vlan del dev DEV vid VID [ pvid ] [ untagged ] [ self ] [ master ]` // Equivalent to: `bridge vlan del dev DEV vid VID [ pvid ] [ untagged ] [ self ] [ master ]`
func (h *Handle) BridgeVlanDel(link Link, vid uint16, pvid, untagged, self, master bool) error { func (h *Handle) BridgeVlanDel(link Link, vid uint16, pvid, untagged, self, master bool) error {
return h.bridgeVlanModify(syscall.RTM_DELLINK, link, vid, pvid, untagged, self, master) return h.bridgeVlanModify(unix.RTM_DELLINK, link, vid, pvid, untagged, self, master)
} }
func (h *Handle) bridgeVlanModify(cmd int, link Link, vid uint16, pvid, untagged, self, master bool) error { func (h *Handle) bridgeVlanModify(cmd int, link Link, vid uint16, pvid, untagged, self, master bool) error {
base := link.Attrs() base := link.Attrs()
h.ensureIndex(base) h.ensureIndex(base)
req := h.newNetlinkRequest(cmd, syscall.NLM_F_ACK) req := h.newNetlinkRequest(cmd, unix.NLM_F_ACK)
msg := nl.NewIfInfomsg(syscall.AF_BRIDGE) msg := nl.NewIfInfomsg(unix.AF_BRIDGE)
msg.Index = int32(base.Index) msg.Index = int32(base.Index)
req.AddData(msg) req.AddData(msg)
br := nl.NewRtAttr(nl.IFLA_AF_SPEC, nil) br := nl.NewRtAttr(unix.IFLA_AF_SPEC, nil)
var flags uint16 var flags uint16
if self { if self {
flags |= nl.BRIDGE_FLAGS_SELF flags |= nl.BRIDGE_FLAGS_SELF
@ -96,7 +96,7 @@ func (h *Handle) bridgeVlanModify(cmd int, link Link, vid uint16, pvid, untagged
flags |= nl.BRIDGE_FLAGS_MASTER flags |= nl.BRIDGE_FLAGS_MASTER
} }
if flags > 0 { if flags > 0 {
nl.NewRtAttrChild(br, nl.IFLA_BRIDGE_FLAGS, nl.Uint16Attr(flags)) br.AddRtAttr(nl.IFLA_BRIDGE_FLAGS, nl.Uint16Attr(flags))
} }
vlanInfo := &nl.BridgeVlanInfo{Vid: vid} vlanInfo := &nl.BridgeVlanInfo{Vid: vid}
if pvid { if pvid {
@ -105,9 +105,9 @@ func (h *Handle) bridgeVlanModify(cmd int, link Link, vid uint16, pvid, untagged
if untagged { if untagged {
vlanInfo.Flags |= nl.BRIDGE_VLAN_INFO_UNTAGGED vlanInfo.Flags |= nl.BRIDGE_VLAN_INFO_UNTAGGED
} }
nl.NewRtAttrChild(br, nl.IFLA_BRIDGE_VLAN_INFO, vlanInfo.Serialize()) br.AddRtAttr(nl.IFLA_BRIDGE_VLAN_INFO, vlanInfo.Serialize())
req.AddData(br) req.AddData(br)
_, err := req.Execute(syscall.NETLINK_ROUTE, 0) _, err := req.Execute(unix.NETLINK_ROUTE, 0)
if err != nil { if err != nil {
return err return err
} }

View File

@ -4,25 +4,76 @@ import (
"fmt" "fmt"
) )
// Class interfaces for all classes
type Class interface { type Class interface {
Attrs() *ClassAttrs Attrs() *ClassAttrs
Type() string Type() string
} }
// Generic networking statistics for netlink users.
// This file contains "gnet_" prefixed structs and relevant functions.
// See Documentation/networking/getn_stats.txt in Linux source code for more details.
// GnetStatsBasic Ref: struct gnet_stats_basic { ... }
type GnetStatsBasic struct {
Bytes uint64 // number of seen bytes
Packets uint32 // number of seen packets
}
// GnetStatsRateEst Ref: struct gnet_stats_rate_est { ... }
type GnetStatsRateEst struct {
Bps uint32 // current byte rate
Pps uint32 // current packet rate
}
// GnetStatsRateEst64 Ref: struct gnet_stats_rate_est64 { ... }
type GnetStatsRateEst64 struct {
Bps uint64 // current byte rate
Pps uint64 // current packet rate
}
// GnetStatsQueue Ref: struct gnet_stats_queue { ... }
type GnetStatsQueue struct {
Qlen uint32 // queue length
Backlog uint32 // backlog size of queue
Drops uint32 // number of dropped packets
Requeues uint32 // number of requues
Overlimits uint32 // number of enqueues over the limit
}
// ClassStatistics representaion based on generic networking statisticsfor netlink.
// See Documentation/networking/gen_stats.txt in Linux source code for more details.
type ClassStatistics struct {
Basic *GnetStatsBasic
Queue *GnetStatsQueue
RateEst *GnetStatsRateEst
}
// NewClassStatistics Construct a ClassStatistics struct which fields are all initialized by 0.
func NewClassStatistics() *ClassStatistics {
return &ClassStatistics{
Basic: &GnetStatsBasic{},
Queue: &GnetStatsQueue{},
RateEst: &GnetStatsRateEst{},
}
}
// ClassAttrs represents a netlink class. A filter is associated with a link, // ClassAttrs represents a netlink class. A filter is associated with a link,
// has a handle and a parent. The root filter of a device should have a // has a handle and a parent. The root filter of a device should have a
// parent == HANDLE_ROOT. // parent == HANDLE_ROOT.
type ClassAttrs struct { type ClassAttrs struct {
LinkIndex int LinkIndex int
Handle uint32 Handle uint32
Parent uint32 Parent uint32
Leaf uint32 Leaf uint32
Statistics *ClassStatistics
} }
func (q ClassAttrs) String() string { func (q ClassAttrs) String() string {
return fmt.Sprintf("{LinkIndex: %d, Handle: %s, Parent: %s, Leaf: %d}", q.LinkIndex, HandleStr(q.Handle), HandleStr(q.Parent), q.Leaf) return fmt.Sprintf("{LinkIndex: %d, Handle: %s, Parent: %s, Leaf: %d}", q.LinkIndex, HandleStr(q.Handle), HandleStr(q.Parent), q.Leaf)
} }
// HtbClassAttrs stores the attributes of HTB class
type HtbClassAttrs struct { type HtbClassAttrs struct {
// TODO handle all attributes // TODO handle all attributes
Rate uint64 Rate uint64
@ -54,10 +105,12 @@ func (q HtbClass) String() string {
return fmt.Sprintf("{Rate: %d, Ceil: %d, Buffer: %d, Cbuffer: %d}", q.Rate, q.Ceil, q.Buffer, q.Cbuffer) return fmt.Sprintf("{Rate: %d, Ceil: %d, Buffer: %d, Cbuffer: %d}", q.Rate, q.Ceil, q.Buffer, q.Cbuffer)
} }
// Attrs returns the class attributes
func (q *HtbClass) Attrs() *ClassAttrs { func (q *HtbClass) Attrs() *ClassAttrs {
return &q.ClassAttrs return &q.ClassAttrs
} }
// Type return the class type
func (q *HtbClass) Type() string { func (q *HtbClass) Type() string {
return "htb" return "htb"
} }
@ -69,10 +122,90 @@ type GenericClass struct {
ClassType string ClassType string
} }
// Attrs return the class attributes
func (class *GenericClass) Attrs() *ClassAttrs { func (class *GenericClass) Attrs() *ClassAttrs {
return &class.ClassAttrs return &class.ClassAttrs
} }
// Type retrun the class type
func (class *GenericClass) Type() string { func (class *GenericClass) Type() string {
return class.ClassType return class.ClassType
} }
// ServiceCurve is the way the HFSC curve are represented
type ServiceCurve struct {
m1 uint32
d uint32
m2 uint32
}
// Attrs return the parameters of the service curve
func (c *ServiceCurve) Attrs() (uint32, uint32, uint32) {
return c.m1, c.d, c.m2
}
// HfscClass is a representation of the HFSC class
type HfscClass struct {
ClassAttrs
Rsc ServiceCurve
Fsc ServiceCurve
Usc ServiceCurve
}
// SetUsc sets the Usc curve
func (hfsc *HfscClass) SetUsc(m1 uint32, d uint32, m2 uint32) {
hfsc.Usc = ServiceCurve{m1: m1 / 8, d: d, m2: m2 / 8}
}
// SetFsc sets the Fsc curve
func (hfsc *HfscClass) SetFsc(m1 uint32, d uint32, m2 uint32) {
hfsc.Fsc = ServiceCurve{m1: m1 / 8, d: d, m2: m2 / 8}
}
// SetRsc sets the Rsc curve
func (hfsc *HfscClass) SetRsc(m1 uint32, d uint32, m2 uint32) {
hfsc.Rsc = ServiceCurve{m1: m1 / 8, d: d, m2: m2 / 8}
}
// SetSC implements the SC from the tc CLI
func (hfsc *HfscClass) SetSC(m1 uint32, d uint32, m2 uint32) {
hfsc.Rsc = ServiceCurve{m1: m1 / 8, d: d, m2: m2 / 8}
hfsc.Fsc = ServiceCurve{m1: m1 / 8, d: d, m2: m2 / 8}
}
// SetUL implements the UL from the tc CLI
func (hfsc *HfscClass) SetUL(m1 uint32, d uint32, m2 uint32) {
hfsc.Usc = ServiceCurve{m1: m1 / 8, d: d, m2: m2 / 8}
}
// SetLS implemtens the LS from the tc CLI
func (hfsc *HfscClass) SetLS(m1 uint32, d uint32, m2 uint32) {
hfsc.Fsc = ServiceCurve{m1: m1 / 8, d: d, m2: m2 / 8}
}
// NewHfscClass returns a new HFSC struct with the set parameters
func NewHfscClass(attrs ClassAttrs) *HfscClass {
return &HfscClass{
ClassAttrs: attrs,
Rsc: ServiceCurve{},
Fsc: ServiceCurve{},
Usc: ServiceCurve{},
}
}
func (hfsc *HfscClass) String() string {
return fmt.Sprintf(
"{%s -- {RSC: {m1=%d d=%d m2=%d}} {FSC: {m1=%d d=%d m2=%d}} {USC: {m1=%d d=%d m2=%d}}}",
hfsc.Attrs(), hfsc.Rsc.m1*8, hfsc.Rsc.d, hfsc.Rsc.m2*8, hfsc.Fsc.m1*8, hfsc.Fsc.d, hfsc.Fsc.m2*8, hfsc.Usc.m1*8, hfsc.Usc.d, hfsc.Usc.m2*8,
)
}
// Attrs return the Hfsc parameters
func (hfsc *HfscClass) Attrs() *ClassAttrs {
return &hfsc.ClassAttrs
}
// Type return the type of the class
func (hfsc *HfscClass) Type() string {
return "hfsc"
}

View File

@ -1,13 +1,34 @@
package netlink package netlink
import ( import (
"bytes"
"encoding/binary"
"encoding/hex"
"errors" "errors"
"fmt"
"syscall" "syscall"
"github.com/vishvananda/netlink/nl" "github.com/vishvananda/netlink/nl"
"golang.org/x/sys/unix"
) )
// NOTE: function is in here because it uses other linux functions // Internal tc_stats representation in Go struct.
// This is for internal uses only to deserialize the payload of rtattr.
// After the deserialization, this should be converted into the canonical stats
// struct, ClassStatistics, in case of statistics of a class.
// Ref: struct tc_stats { ... }
type tcStats struct {
Bytes uint64 // Number of enqueued bytes
Packets uint32 // Number of enqueued packets
Drops uint32 // Packets dropped because of lack of resources
Overlimits uint32 // Number of throttle events when this flow goes out of allocated bandwidth
Bps uint32 // Current flow byte rate
Pps uint32 // Current flow packet rate
Qlen uint32
Backlog uint32
}
// NewHtbClass NOTE: function is in here because it uses other linux functions
func NewHtbClass(attrs ClassAttrs, cattrs HtbClassAttrs) *HtbClass { func NewHtbClass(attrs ClassAttrs, cattrs HtbClassAttrs) *HtbClass {
mtu := 1600 mtu := 1600
rate := cattrs.Rate / 8 rate := cattrs.Rate / 8
@ -50,7 +71,7 @@ func ClassDel(class Class) error {
// ClassDel will delete a class from the system. // ClassDel will delete a class from the system.
// Equivalent to: `tc class del $class` // Equivalent to: `tc class del $class`
func (h *Handle) ClassDel(class Class) error { func (h *Handle) ClassDel(class Class) error {
return h.classModify(syscall.RTM_DELTCLASS, 0, class) return h.classModify(unix.RTM_DELTCLASS, 0, class)
} }
// ClassChange will change a class in place // ClassChange will change a class in place
@ -64,7 +85,7 @@ func ClassChange(class Class) error {
// Equivalent to: `tc class change $class` // Equivalent to: `tc class change $class`
// The parent and handle MUST NOT be changed. // The parent and handle MUST NOT be changed.
func (h *Handle) ClassChange(class Class) error { func (h *Handle) ClassChange(class Class) error {
return h.classModify(syscall.RTM_NEWTCLASS, 0, class) return h.classModify(unix.RTM_NEWTCLASS, 0, class)
} }
// ClassReplace will replace a class to the system. // ClassReplace will replace a class to the system.
@ -82,7 +103,7 @@ func ClassReplace(class Class) error {
// If a class already exist with this parent/handle pair, the class is changed. // If a class already exist with this parent/handle pair, the class is changed.
// If a class does not already exist with this parent/handle, a new class is created. // If a class does not already exist with this parent/handle, a new class is created.
func (h *Handle) ClassReplace(class Class) error { func (h *Handle) ClassReplace(class Class) error {
return h.classModify(syscall.RTM_NEWTCLASS, syscall.NLM_F_CREATE, class) return h.classModify(unix.RTM_NEWTCLASS, unix.NLM_F_CREATE, class)
} }
// ClassAdd will add a class to the system. // ClassAdd will add a class to the system.
@ -95,14 +116,14 @@ func ClassAdd(class Class) error {
// Equivalent to: `tc class add $class` // Equivalent to: `tc class add $class`
func (h *Handle) ClassAdd(class Class) error { func (h *Handle) ClassAdd(class Class) error {
return h.classModify( return h.classModify(
syscall.RTM_NEWTCLASS, unix.RTM_NEWTCLASS,
syscall.NLM_F_CREATE|syscall.NLM_F_EXCL, unix.NLM_F_CREATE|unix.NLM_F_EXCL,
class, class,
) )
} }
func (h *Handle) classModify(cmd, flags int, class Class) error { func (h *Handle) classModify(cmd, flags int, class Class) error {
req := h.newNetlinkRequest(cmd, flags|syscall.NLM_F_ACK) req := h.newNetlinkRequest(cmd, flags|unix.NLM_F_ACK)
base := class.Attrs() base := class.Attrs()
msg := &nl.TcMsg{ msg := &nl.TcMsg{
Family: nl.FAMILY_ALL, Family: nl.FAMILY_ALL,
@ -112,12 +133,12 @@ func (h *Handle) classModify(cmd, flags int, class Class) error {
} }
req.AddData(msg) req.AddData(msg)
if cmd != syscall.RTM_DELTCLASS { if cmd != unix.RTM_DELTCLASS {
if err := classPayload(req, class); err != nil { if err := classPayload(req, class); err != nil {
return err return err
} }
} }
_, err := req.Execute(syscall.NETLINK_ROUTE, 0) _, err := req.Execute(unix.NETLINK_ROUTE, 0)
return err return err
} }
@ -125,7 +146,9 @@ func classPayload(req *nl.NetlinkRequest, class Class) error {
req.AddData(nl.NewRtAttr(nl.TCA_KIND, nl.ZeroTerminated(class.Type()))) req.AddData(nl.NewRtAttr(nl.TCA_KIND, nl.ZeroTerminated(class.Type())))
options := nl.NewRtAttr(nl.TCA_OPTIONS, nil) options := nl.NewRtAttr(nl.TCA_OPTIONS, nil)
if htb, ok := class.(*HtbClass); ok { switch class.Type() {
case "htb":
htb := class.(*HtbClass)
opt := nl.TcHtbCopt{} opt := nl.TcHtbCopt{}
opt.Buffer = htb.Buffer opt.Buffer = htb.Buffer
opt.Cbuffer = htb.Cbuffer opt.Cbuffer = htb.Cbuffer
@ -141,18 +164,27 @@ func classPayload(req *nl.NetlinkRequest, class Class) error {
var rtab [256]uint32 var rtab [256]uint32
var ctab [256]uint32 var ctab [256]uint32
tcrate := nl.TcRateSpec{Rate: uint32(htb.Rate)} tcrate := nl.TcRateSpec{Rate: uint32(htb.Rate)}
if CalcRtable(&tcrate, rtab, cellLog, uint32(mtu), linklayer) < 0 { if CalcRtable(&tcrate, rtab[:], cellLog, uint32(mtu), linklayer) < 0 {
return errors.New("HTB: failed to calculate rate table") return errors.New("HTB: failed to calculate rate table")
} }
opt.Rate = tcrate opt.Rate = tcrate
tcceil := nl.TcRateSpec{Rate: uint32(htb.Ceil)} tcceil := nl.TcRateSpec{Rate: uint32(htb.Ceil)}
if CalcRtable(&tcceil, ctab, ccellLog, uint32(mtu), linklayer) < 0 { if CalcRtable(&tcceil, ctab[:], ccellLog, uint32(mtu), linklayer) < 0 {
return errors.New("HTB: failed to calculate ceil rate table") return errors.New("HTB: failed to calculate ceil rate table")
} }
opt.Ceil = tcceil opt.Ceil = tcceil
nl.NewRtAttrChild(options, nl.TCA_HTB_PARMS, opt.Serialize()) options.AddRtAttr(nl.TCA_HTB_PARMS, opt.Serialize())
nl.NewRtAttrChild(options, nl.TCA_HTB_RTAB, SerializeRtab(rtab)) options.AddRtAttr(nl.TCA_HTB_RTAB, SerializeRtab(rtab))
nl.NewRtAttrChild(options, nl.TCA_HTB_CTAB, SerializeRtab(ctab)) options.AddRtAttr(nl.TCA_HTB_CTAB, SerializeRtab(ctab))
case "hfsc":
hfsc := class.(*HfscClass)
opt := nl.HfscCopt{}
opt.Rsc.Set(hfsc.Rsc.Attrs())
opt.Fsc.Set(hfsc.Fsc.Attrs())
opt.Usc.Set(hfsc.Usc.Attrs())
options.AddRtAttr(nl.TCA_HFSC_RSC, nl.SerializeHfscCurve(&opt.Rsc))
options.AddRtAttr(nl.TCA_HFSC_FSC, nl.SerializeHfscCurve(&opt.Fsc))
options.AddRtAttr(nl.TCA_HFSC_USC, nl.SerializeHfscCurve(&opt.Usc))
} }
req.AddData(options) req.AddData(options)
return nil return nil
@ -169,7 +201,7 @@ func ClassList(link Link, parent uint32) ([]Class, error) {
// Equivalent to: `tc class show`. // Equivalent to: `tc class show`.
// Generally returns nothing if link and parent are not specified. // Generally returns nothing if link and parent are not specified.
func (h *Handle) ClassList(link Link, parent uint32) ([]Class, error) { func (h *Handle) ClassList(link Link, parent uint32) ([]Class, error) {
req := h.newNetlinkRequest(syscall.RTM_GETTCLASS, syscall.NLM_F_DUMP) req := h.newNetlinkRequest(unix.RTM_GETTCLASS, unix.NLM_F_DUMP)
msg := &nl.TcMsg{ msg := &nl.TcMsg{
Family: nl.FAMILY_ALL, Family: nl.FAMILY_ALL,
Parent: parent, Parent: parent,
@ -181,7 +213,7 @@ func (h *Handle) ClassList(link Link, parent uint32) ([]Class, error) {
} }
req.AddData(msg) req.AddData(msg)
msgs, err := req.Execute(syscall.NETLINK_ROUTE, syscall.RTM_NEWTCLASS) msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWTCLASS)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -196,9 +228,10 @@ func (h *Handle) ClassList(link Link, parent uint32) ([]Class, error) {
} }
base := ClassAttrs{ base := ClassAttrs{
LinkIndex: int(msg.Ifindex), LinkIndex: int(msg.Ifindex),
Handle: msg.Handle, Handle: msg.Handle,
Parent: msg.Parent, Parent: msg.Parent,
Statistics: nil,
} }
var class Class var class Class
@ -210,6 +243,8 @@ func (h *Handle) ClassList(link Link, parent uint32) ([]Class, error) {
switch classType { switch classType {
case "htb": case "htb":
class = &HtbClass{} class = &HtbClass{}
case "hfsc":
class = &HfscClass{}
default: default:
class = &GenericClass{ClassType: classType} class = &GenericClass{ClassType: classType}
} }
@ -224,6 +259,26 @@ func (h *Handle) ClassList(link Link, parent uint32) ([]Class, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
case "hfsc":
data, err := nl.ParseRouteAttr(attr.Value)
if err != nil {
return nil, err
}
_, err = parseHfscClassData(class, data)
if err != nil {
return nil, err
}
}
// For backward compatibility.
case nl.TCA_STATS:
base.Statistics, err = parseTcStats(attr.Value)
if err != nil {
return nil, err
}
case nl.TCA_STATS2:
base.Statistics, err = parseTcStats2(attr.Value)
if err != nil {
return nil, err
} }
} }
} }
@ -252,3 +307,78 @@ func parseHtbClassData(class Class, data []syscall.NetlinkRouteAttr) (bool, erro
} }
return detailed, nil return detailed, nil
} }
func parseHfscClassData(class Class, data []syscall.NetlinkRouteAttr) (bool, error) {
hfsc := class.(*HfscClass)
detailed := false
for _, datum := range data {
m1, d, m2 := nl.DeserializeHfscCurve(datum.Value).Attrs()
switch datum.Attr.Type {
case nl.TCA_HFSC_RSC:
hfsc.Rsc = ServiceCurve{m1: m1, d: d, m2: m2}
case nl.TCA_HFSC_FSC:
hfsc.Fsc = ServiceCurve{m1: m1, d: d, m2: m2}
case nl.TCA_HFSC_USC:
hfsc.Usc = ServiceCurve{m1: m1, d: d, m2: m2}
}
}
return detailed, nil
}
func parseTcStats(data []byte) (*ClassStatistics, error) {
buf := &bytes.Buffer{}
buf.Write(data)
native := nl.NativeEndian()
tcStats := &tcStats{}
if err := binary.Read(buf, native, tcStats); err != nil {
return nil, err
}
stats := NewClassStatistics()
stats.Basic.Bytes = tcStats.Bytes
stats.Basic.Packets = tcStats.Packets
stats.Queue.Qlen = tcStats.Qlen
stats.Queue.Backlog = tcStats.Backlog
stats.Queue.Drops = tcStats.Drops
stats.Queue.Overlimits = tcStats.Overlimits
stats.RateEst.Bps = tcStats.Bps
stats.RateEst.Pps = tcStats.Pps
return stats, nil
}
func parseGnetStats(data []byte, gnetStats interface{}) error {
buf := &bytes.Buffer{}
buf.Write(data)
native := nl.NativeEndian()
return binary.Read(buf, native, gnetStats)
}
func parseTcStats2(data []byte) (*ClassStatistics, error) {
rtAttrs, err := nl.ParseRouteAttr(data)
if err != nil {
return nil, err
}
stats := NewClassStatistics()
for _, datum := range rtAttrs {
switch datum.Attr.Type {
case nl.TCA_STATS_BASIC:
if err := parseGnetStats(datum.Value, stats.Basic); err != nil {
return nil, fmt.Errorf("Failed to parse ClassStatistics.Basic with: %v\n%s",
err, hex.Dump(datum.Value))
}
case nl.TCA_STATS_QUEUE:
if err := parseGnetStats(datum.Value, stats.Queue); err != nil {
return nil, fmt.Errorf("Failed to parse ClassStatistics.Queue with: %v\n%s",
err, hex.Dump(datum.Value))
}
case nl.TCA_STATS_RATE_EST:
if err := parseGnetStats(datum.Value, stats.RateEst); err != nil {
return nil, fmt.Errorf("Failed to parse ClassStatistics.RateEst with: %v\n%s",
err, hex.Dump(datum.Value))
}
}
}
return stats, nil
}

View File

@ -6,9 +6,9 @@ import (
"errors" "errors"
"fmt" "fmt"
"net" "net"
"syscall"
"github.com/vishvananda/netlink/nl" "github.com/vishvananda/netlink/nl"
"golang.org/x/sys/unix"
) )
// ConntrackTableType Conntrack table for the netlink operation // ConntrackTableType Conntrack table for the netlink operation
@ -22,7 +22,11 @@ const (
// https://github.com/torvalds/linux/blob/master/include/uapi/linux/netfilter/nfnetlink.h -> #define NFNL_SUBSYS_CTNETLINK_EXP 2 // https://github.com/torvalds/linux/blob/master/include/uapi/linux/netfilter/nfnetlink.h -> #define NFNL_SUBSYS_CTNETLINK_EXP 2
ConntrackExpectTable = 2 ConntrackExpectTable = 2
) )
const (
// For Parsing Mark
TCP_PROTO = 6
UDP_PROTO = 17
)
const ( const (
// backward compatibility with golang 1.6 which does not have io.SeekCurrent // backward compatibility with golang 1.6 which does not have io.SeekCurrent
seekCurrent = 1 seekCurrent = 1
@ -81,8 +85,8 @@ func (h *Handle) ConntrackTableList(table ConntrackTableType, family InetFamily)
// conntrack -F [table] Flush table // conntrack -F [table] Flush table
// The flush operation applies to all the family types // The flush operation applies to all the family types
func (h *Handle) ConntrackTableFlush(table ConntrackTableType) error { func (h *Handle) ConntrackTableFlush(table ConntrackTableType) error {
req := h.newConntrackRequest(table, syscall.AF_INET, nl.IPCTNL_MSG_CT_DELETE, syscall.NLM_F_ACK) req := h.newConntrackRequest(table, unix.AF_INET, nl.IPCTNL_MSG_CT_DELETE, unix.NLM_F_ACK)
_, err := req.Execute(syscall.NETLINK_NETFILTER, 0) _, err := req.Execute(unix.NETLINK_NETFILTER, 0)
return err return err
} }
@ -98,10 +102,10 @@ func (h *Handle) ConntrackDeleteFilter(table ConntrackTableType, family InetFami
for _, dataRaw := range res { for _, dataRaw := range res {
flow := parseRawData(dataRaw) flow := parseRawData(dataRaw)
if match := filter.MatchConntrackFlow(flow); match { if match := filter.MatchConntrackFlow(flow); match {
req2 := h.newConntrackRequest(table, family, nl.IPCTNL_MSG_CT_DELETE, syscall.NLM_F_ACK) req2 := h.newConntrackRequest(table, family, nl.IPCTNL_MSG_CT_DELETE, unix.NLM_F_ACK)
// skip the first 4 byte that are the netfilter header, the newConntrackRequest is adding it already // skip the first 4 byte that are the netfilter header, the newConntrackRequest is adding it already
req2.AddRawData(dataRaw[4:]) req2.AddRawData(dataRaw[4:])
req2.Execute(syscall.NETLINK_NETFILTER, 0) req2.Execute(unix.NETLINK_NETFILTER, 0)
matched++ matched++
} }
} }
@ -123,34 +127,38 @@ func (h *Handle) newConntrackRequest(table ConntrackTableType, family InetFamily
} }
func (h *Handle) dumpConntrackTable(table ConntrackTableType, family InetFamily) ([][]byte, error) { func (h *Handle) dumpConntrackTable(table ConntrackTableType, family InetFamily) ([][]byte, error) {
req := h.newConntrackRequest(table, family, nl.IPCTNL_MSG_CT_GET, syscall.NLM_F_DUMP) req := h.newConntrackRequest(table, family, nl.IPCTNL_MSG_CT_GET, unix.NLM_F_DUMP)
return req.Execute(syscall.NETLINK_NETFILTER, 0) return req.Execute(unix.NETLINK_NETFILTER, 0)
} }
// The full conntrack flow structure is very complicated and can be found in the file: // The full conntrack flow structure is very complicated and can be found in the file:
// http://git.netfilter.org/libnetfilter_conntrack/tree/include/internal/object.h // http://git.netfilter.org/libnetfilter_conntrack/tree/include/internal/object.h
// For the time being, the structure below allows to parse and extract the base information of a flow // For the time being, the structure below allows to parse and extract the base information of a flow
type ipTuple struct { type ipTuple struct {
SrcIP net.IP Bytes uint64
DstIP net.IP DstIP net.IP
Protocol uint8
SrcPort uint16
DstPort uint16 DstPort uint16
Packets uint64
Protocol uint8
SrcIP net.IP
SrcPort uint16
} }
type ConntrackFlow struct { type ConntrackFlow struct {
FamilyType uint8 FamilyType uint8
Forward ipTuple Forward ipTuple
Reverse ipTuple Reverse ipTuple
Mark uint32
} }
func (s *ConntrackFlow) String() string { func (s *ConntrackFlow) String() string {
// conntrack cmd output: // conntrack cmd output:
// udp 17 src=127.0.0.1 dst=127.0.0.1 sport=4001 dport=1234 [UNREPLIED] src=127.0.0.1 dst=127.0.0.1 sport=1234 dport=4001 // udp 17 src=127.0.0.1 dst=127.0.0.1 sport=4001 dport=1234 packets=5 bytes=532 [UNREPLIED] src=127.0.0.1 dst=127.0.0.1 sport=1234 dport=4001 packets=10 bytes=1078 mark=0
return fmt.Sprintf("%s\t%d src=%s dst=%s sport=%d dport=%d\tsrc=%s dst=%s sport=%d dport=%d", return fmt.Sprintf("%s\t%d src=%s dst=%s sport=%d dport=%d packets=%d bytes=%d\tsrc=%s dst=%s sport=%d dport=%d packets=%d bytes=%d mark=%d",
nl.L4ProtoMap[s.Forward.Protocol], s.Forward.Protocol, nl.L4ProtoMap[s.Forward.Protocol], s.Forward.Protocol,
s.Forward.SrcIP.String(), s.Forward.DstIP.String(), s.Forward.SrcPort, s.Forward.DstPort, s.Forward.SrcIP.String(), s.Forward.DstIP.String(), s.Forward.SrcPort, s.Forward.DstPort, s.Forward.Packets, s.Forward.Bytes,
s.Reverse.SrcIP.String(), s.Reverse.DstIP.String(), s.Reverse.SrcPort, s.Reverse.DstPort) s.Reverse.SrcIP.String(), s.Reverse.DstIP.String(), s.Reverse.SrcPort, s.Reverse.DstPort, s.Reverse.Packets, s.Reverse.Bytes,
s.Mark)
} }
// This method parse the ip tuple structure // This method parse the ip tuple structure
@ -160,7 +168,7 @@ func (s *ConntrackFlow) String() string {
// <len, NLA_F_NESTED|nl.CTA_TUPLE_PROTO, 1 byte for the protocol, 3 bytes of padding> // <len, NLA_F_NESTED|nl.CTA_TUPLE_PROTO, 1 byte for the protocol, 3 bytes of padding>
// <len, CTA_PROTO_SRC_PORT, 2 bytes for the source port, 2 bytes of padding> // <len, CTA_PROTO_SRC_PORT, 2 bytes for the source port, 2 bytes of padding>
// <len, CTA_PROTO_DST_PORT, 2 bytes for the source port, 2 bytes of padding> // <len, CTA_PROTO_DST_PORT, 2 bytes for the source port, 2 bytes of padding>
func parseIpTuple(reader *bytes.Reader, tpl *ipTuple) { func parseIpTuple(reader *bytes.Reader, tpl *ipTuple) uint8 {
for i := 0; i < 2; i++ { for i := 0; i < 2; i++ {
_, t, _, v := parseNfAttrTLV(reader) _, t, _, v := parseNfAttrTLV(reader)
switch t { switch t {
@ -189,6 +197,7 @@ func parseIpTuple(reader *bytes.Reader, tpl *ipTuple) {
// Skip some padding 2 byte // Skip some padding 2 byte
reader.Seek(2, seekCurrent) reader.Seek(2, seekCurrent)
} }
return tpl.Protocol
} }
func parseNfAttrTLV(r *bytes.Reader) (isNested bool, attrType, len uint16, value []byte) { func parseNfAttrTLV(r *bytes.Reader) (isNested bool, attrType, len uint16, value []byte) {
@ -214,8 +223,27 @@ func parseBERaw16(r *bytes.Reader, v *uint16) {
binary.Read(r, binary.BigEndian, v) binary.Read(r, binary.BigEndian, v)
} }
func parseBERaw64(r *bytes.Reader, v *uint64) {
binary.Read(r, binary.BigEndian, v)
}
func parseByteAndPacketCounters(r *bytes.Reader) (bytes, packets uint64) {
for i := 0; i < 2; i++ {
switch _, t, _ := parseNfAttrTL(r); t {
case nl.CTA_COUNTERS_BYTES:
parseBERaw64(r, &bytes)
case nl.CTA_COUNTERS_PACKETS:
parseBERaw64(r, &packets)
default:
return
}
}
return
}
func parseRawData(data []byte) *ConntrackFlow { func parseRawData(data []byte) *ConntrackFlow {
s := &ConntrackFlow{} s := &ConntrackFlow{}
var proto uint8
// First there is the Nfgenmsg header // First there is the Nfgenmsg header
// consume only the family field // consume only the family field
reader := bytes.NewReader(data) reader := bytes.NewReader(data)
@ -231,24 +259,39 @@ func parseRawData(data []byte) *ConntrackFlow {
// <len, NLA_F_NESTED|CTA_TUPLE_IP> 4 bytes // <len, NLA_F_NESTED|CTA_TUPLE_IP> 4 bytes
// flow information of the reverse flow // flow information of the reverse flow
for reader.Len() > 0 { for reader.Len() > 0 {
nested, t, l := parseNfAttrTL(reader) if nested, t, l := parseNfAttrTL(reader); nested {
if nested && t == nl.CTA_TUPLE_ORIG { switch t {
if nested, t, _ = parseNfAttrTL(reader); nested && t == nl.CTA_TUPLE_IP { case nl.CTA_TUPLE_ORIG:
parseIpTuple(reader, &s.Forward) if nested, t, _ = parseNfAttrTL(reader); nested && t == nl.CTA_TUPLE_IP {
} proto = parseIpTuple(reader, &s.Forward)
} else if nested && t == nl.CTA_TUPLE_REPLY { }
if nested, t, _ = parseNfAttrTL(reader); nested && t == nl.CTA_TUPLE_IP { case nl.CTA_TUPLE_REPLY:
parseIpTuple(reader, &s.Reverse) if nested, t, _ = parseNfAttrTL(reader); nested && t == nl.CTA_TUPLE_IP {
parseIpTuple(reader, &s.Reverse)
// Got all the useful information stop parsing } else {
break // Header not recognized skip it
} else { reader.Seek(int64(l), seekCurrent)
// Header not recognized skip it }
reader.Seek(int64(l), seekCurrent) case nl.CTA_COUNTERS_ORIG:
s.Forward.Bytes, s.Forward.Packets = parseByteAndPacketCounters(reader)
case nl.CTA_COUNTERS_REPLY:
s.Reverse.Bytes, s.Reverse.Packets = parseByteAndPacketCounters(reader)
} }
} }
} }
if proto == TCP_PROTO {
reader.Seek(64, seekCurrent)
_, t, _, v := parseNfAttrTLV(reader)
if t == nl.CTA_MARK {
s.Mark = uint32(v[3])
}
} else if proto == UDP_PROTO {
reader.Seek(16, seekCurrent)
_, t, _, v := parseNfAttrTLV(reader)
if t == nl.CTA_MARK {
s.Mark = uint32(v[3])
}
}
return s return s
} }
@ -266,7 +309,7 @@ func parseRawData(data []byte) *ConntrackFlow {
// Common parameters and options: // Common parameters and options:
// -s, --src, --orig-src ip Source address from original direction // -s, --src, --orig-src ip Source address from original direction
// -d, --dst, --orig-dst ip Destination address from original direction // -d, --dst, --orig-dst ip Destination address from original direction
// -r, --reply-src ip Source addres from reply direction // -r, --reply-src ip Source address from reply direction
// -q, --reply-dst ip Destination address from reply direction // -q, --reply-dst ip Destination address from reply direction
// -p, --protonum proto Layer 4 Protocol, eg. 'tcp' // -p, --protonum proto Layer 4 Protocol, eg. 'tcp'
// -f, --family proto Layer 3 Protocol, eg. 'ipv6' // -f, --family proto Layer 3 Protocol, eg. 'ipv6'
@ -283,11 +326,14 @@ func parseRawData(data []byte) *ConntrackFlow {
type ConntrackFilterType uint8 type ConntrackFilterType uint8
const ( const (
ConntrackOrigSrcIP = iota // -orig-src ip Source address from original direction ConntrackOrigSrcIP = iota // -orig-src ip Source address from original direction
ConntrackOrigDstIP // -orig-dst ip Destination address from original direction ConntrackOrigDstIP // -orig-dst ip Destination address from original direction
ConntrackNatSrcIP // -src-nat ip Source NAT ip ConntrackReplySrcIP // --reply-src ip Reply Source IP
ConntrackNatDstIP // -dst-nat ip Destination NAT ip ConntrackReplyDstIP // --reply-dst ip Reply Destination IP
ConntrackNatAnyIP // -any-nat ip Source or destination NAT ip ConntrackReplyAnyIP // Match source or destination reply IP
ConntrackNatSrcIP = ConntrackReplySrcIP // deprecated use instead ConntrackReplySrcIP
ConntrackNatDstIP = ConntrackReplyDstIP // deprecated use instead ConntrackReplyDstIP
ConntrackNatAnyIP = ConntrackReplyAnyIP // deprecated use instaed ConntrackReplyAnyIP
) )
type CustomConntrackFilter interface { type CustomConntrackFilter interface {
@ -332,17 +378,17 @@ func (f *ConntrackFilter) MatchConntrackFlow(flow *ConntrackFlow) bool {
} }
// -src-nat ip Source NAT ip // -src-nat ip Source NAT ip
if elem, found := f.ipFilter[ConntrackNatSrcIP]; match && found { if elem, found := f.ipFilter[ConntrackReplySrcIP]; match && found {
match = match && elem.Equal(flow.Reverse.SrcIP) match = match && elem.Equal(flow.Reverse.SrcIP)
} }
// -dst-nat ip Destination NAT ip // -dst-nat ip Destination NAT ip
if elem, found := f.ipFilter[ConntrackNatDstIP]; match && found { if elem, found := f.ipFilter[ConntrackReplyDstIP]; match && found {
match = match && elem.Equal(flow.Reverse.DstIP) match = match && elem.Equal(flow.Reverse.DstIP)
} }
// -any-nat ip Source or destination NAT ip // Match source or destination reply IP
if elem, found := f.ipFilter[ConntrackNatAnyIP]; match && found { if elem, found := f.ipFilter[ConntrackReplyAnyIP]; match && found {
match = match && (elem.Equal(flow.Reverse.SrcIP) || elem.Equal(flow.Reverse.DstIP)) match = match && (elem.Equal(flow.Reverse.SrcIP) || elem.Equal(flow.Reverse.DstIP))
} }

View File

@ -2,8 +2,6 @@ package netlink
import ( import (
"fmt" "fmt"
"github.com/vishvananda/netlink/nl"
) )
type Filter interface { type Filter interface {
@ -19,7 +17,7 @@ type FilterAttrs struct {
Handle uint32 Handle uint32
Parent uint32 Parent uint32
Priority uint16 // lower is higher priority Priority uint16 // lower is higher priority
Protocol uint16 // syscall.ETH_P_* Protocol uint16 // unix.ETH_P_*
} }
func (q FilterAttrs) String() string { func (q FilterAttrs) String() string {
@ -184,14 +182,6 @@ func NewMirredAction(redirIndex int) *MirredAction {
} }
} }
// Constants used in TcU32Sel.Flags.
const (
TC_U32_TERMINAL = nl.TC_U32_TERMINAL
TC_U32_OFFSET = nl.TC_U32_OFFSET
TC_U32_VAROFFSET = nl.TC_U32_VAROFFSET
TC_U32_EAT = nl.TC_U32_EAT
)
// Sel of the U32 filters that contains multiple TcU32Key. This is the copy // Sel of the U32 filters that contains multiple TcU32Key. This is the copy
// and the frontend representation of nl.TcU32Sel. It is serialized into canonical // and the frontend representation of nl.TcU32Sel. It is serialized into canonical
// nl.TcU32Sel with the appropriate endianness. // nl.TcU32Sel with the appropriate endianness.
@ -222,6 +212,8 @@ type TcU32Key struct {
type U32 struct { type U32 struct {
FilterAttrs FilterAttrs
ClassId uint32 ClassId uint32
Divisor uint32 // Divisor MUST be power of 2.
Hash uint32
RedirIndex int RedirIndex int
Sel *TcU32Sel Sel *TcU32Sel
Actions []Action Actions []Action
@ -235,6 +227,21 @@ func (filter *U32) Type() string {
return "u32" return "u32"
} }
// MatchAll filters match all packets
type MatchAll struct {
FilterAttrs
ClassId uint32
Actions []Action
}
func (filter *MatchAll) Attrs() *FilterAttrs {
return &filter.FilterAttrs
}
func (filter *MatchAll) Type() string {
return "matchall"
}
type FilterFwAttrs struct { type FilterFwAttrs struct {
ClassId uint32 ClassId uint32
InDev string InDev string

View File

@ -9,6 +9,15 @@ import (
"unsafe" "unsafe"
"github.com/vishvananda/netlink/nl" "github.com/vishvananda/netlink/nl"
"golang.org/x/sys/unix"
)
// Constants used in TcU32Sel.Flags.
const (
TC_U32_TERMINAL = nl.TC_U32_TERMINAL
TC_U32_OFFSET = nl.TC_U32_OFFSET
TC_U32_VAROFFSET = nl.TC_U32_VAROFFSET
TC_U32_EAT = nl.TC_U32_EAT
) )
// Fw filter filters on firewall marks // Fw filter filters on firewall marks
@ -47,7 +56,7 @@ func NewFw(attrs FilterAttrs, fattrs FilterFwAttrs) (*Fw, error) {
if police.Rate.Rate != 0 { if police.Rate.Rate != 0 {
police.Rate.Mpu = fattrs.Mpu police.Rate.Mpu = fattrs.Mpu
police.Rate.Overhead = fattrs.Overhead police.Rate.Overhead = fattrs.Overhead
if CalcRtable(&police.Rate, rtab, rcellLog, fattrs.Mtu, linklayer) < 0 { if CalcRtable(&police.Rate, rtab[:], rcellLog, fattrs.Mtu, linklayer) < 0 {
return nil, errors.New("TBF: failed to calculate rate table") return nil, errors.New("TBF: failed to calculate rate table")
} }
police.Burst = uint32(Xmittime(uint64(police.Rate.Rate), uint32(buffer))) police.Burst = uint32(Xmittime(uint64(police.Rate.Rate), uint32(buffer)))
@ -56,7 +65,7 @@ func NewFw(attrs FilterAttrs, fattrs FilterFwAttrs) (*Fw, error) {
if police.PeakRate.Rate != 0 { if police.PeakRate.Rate != 0 {
police.PeakRate.Mpu = fattrs.Mpu police.PeakRate.Mpu = fattrs.Mpu
police.PeakRate.Overhead = fattrs.Overhead police.PeakRate.Overhead = fattrs.Overhead
if CalcRtable(&police.PeakRate, ptab, pcellLog, fattrs.Mtu, linklayer) < 0 { if CalcRtable(&police.PeakRate, ptab[:], pcellLog, fattrs.Mtu, linklayer) < 0 {
return nil, errors.New("POLICE: failed to calculate peak rate table") return nil, errors.New("POLICE: failed to calculate peak rate table")
} }
} }
@ -90,7 +99,7 @@ func FilterDel(filter Filter) error {
// FilterDel will delete a filter from the system. // FilterDel will delete a filter from the system.
// Equivalent to: `tc filter del $filter` // Equivalent to: `tc filter del $filter`
func (h *Handle) FilterDel(filter Filter) error { func (h *Handle) FilterDel(filter Filter) error {
req := h.newNetlinkRequest(syscall.RTM_DELTFILTER, syscall.NLM_F_ACK) req := h.newNetlinkRequest(unix.RTM_DELTFILTER, unix.NLM_F_ACK)
base := filter.Attrs() base := filter.Attrs()
msg := &nl.TcMsg{ msg := &nl.TcMsg{
Family: nl.FAMILY_ALL, Family: nl.FAMILY_ALL,
@ -101,7 +110,7 @@ func (h *Handle) FilterDel(filter Filter) error {
} }
req.AddData(msg) req.AddData(msg)
_, err := req.Execute(syscall.NETLINK_ROUTE, 0) _, err := req.Execute(unix.NETLINK_ROUTE, 0)
return err return err
} }
@ -115,7 +124,7 @@ func FilterAdd(filter Filter) error {
// Equivalent to: `tc filter add $filter` // Equivalent to: `tc filter add $filter`
func (h *Handle) FilterAdd(filter Filter) error { func (h *Handle) FilterAdd(filter Filter) error {
native = nl.NativeEndian() native = nl.NativeEndian()
req := h.newNetlinkRequest(syscall.RTM_NEWTFILTER, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK) req := h.newNetlinkRequest(unix.RTM_NEWTFILTER, unix.NLM_F_CREATE|unix.NLM_F_EXCL|unix.NLM_F_ACK)
base := filter.Attrs() base := filter.Attrs()
msg := &nl.TcMsg{ msg := &nl.TcMsg{
Family: nl.FAMILY_ALL, Family: nl.FAMILY_ALL,
@ -128,9 +137,11 @@ func (h *Handle) FilterAdd(filter Filter) error {
req.AddData(nl.NewRtAttr(nl.TCA_KIND, nl.ZeroTerminated(filter.Type()))) req.AddData(nl.NewRtAttr(nl.TCA_KIND, nl.ZeroTerminated(filter.Type())))
options := nl.NewRtAttr(nl.TCA_OPTIONS, nil) options := nl.NewRtAttr(nl.TCA_OPTIONS, nil)
if u32, ok := filter.(*U32); ok {
switch filter := filter.(type) {
case *U32:
// Convert TcU32Sel into nl.TcU32Sel as it is without copy. // Convert TcU32Sel into nl.TcU32Sel as it is without copy.
sel := (*nl.TcU32Sel)(unsafe.Pointer(u32.Sel)) sel := (*nl.TcU32Sel)(unsafe.Pointer(filter.Sel))
if sel == nil { if sel == nil {
// match all // match all
sel = &nl.TcU32Sel{ sel = &nl.TcU32Sel{
@ -157,64 +168,81 @@ func (h *Handle) FilterAdd(filter Filter) error {
} }
} }
sel.Nkeys = uint8(len(sel.Keys)) sel.Nkeys = uint8(len(sel.Keys))
nl.NewRtAttrChild(options, nl.TCA_U32_SEL, sel.Serialize()) options.AddRtAttr(nl.TCA_U32_SEL, sel.Serialize())
if u32.ClassId != 0 { if filter.ClassId != 0 {
nl.NewRtAttrChild(options, nl.TCA_U32_CLASSID, nl.Uint32Attr(u32.ClassId)) options.AddRtAttr(nl.TCA_U32_CLASSID, nl.Uint32Attr(filter.ClassId))
} }
actionsAttr := nl.NewRtAttrChild(options, nl.TCA_U32_ACT, nil) if filter.Divisor != 0 {
if (filter.Divisor-1)&filter.Divisor != 0 {
return fmt.Errorf("illegal divisor %d. Must be a power of 2", filter.Divisor)
}
options.AddRtAttr(nl.TCA_U32_DIVISOR, nl.Uint32Attr(filter.Divisor))
}
if filter.Hash != 0 {
options.AddRtAttr(nl.TCA_U32_HASH, nl.Uint32Attr(filter.Hash))
}
actionsAttr := options.AddRtAttr(nl.TCA_U32_ACT, nil)
// backwards compatibility // backwards compatibility
if u32.RedirIndex != 0 { if filter.RedirIndex != 0 {
u32.Actions = append([]Action{NewMirredAction(u32.RedirIndex)}, u32.Actions...) filter.Actions = append([]Action{NewMirredAction(filter.RedirIndex)}, filter.Actions...)
} }
if err := EncodeActions(actionsAttr, u32.Actions); err != nil { if err := EncodeActions(actionsAttr, filter.Actions); err != nil {
return err return err
} }
} else if fw, ok := filter.(*Fw); ok { case *Fw:
if fw.Mask != 0 { if filter.Mask != 0 {
b := make([]byte, 4) b := make([]byte, 4)
native.PutUint32(b, fw.Mask) native.PutUint32(b, filter.Mask)
nl.NewRtAttrChild(options, nl.TCA_FW_MASK, b) options.AddRtAttr(nl.TCA_FW_MASK, b)
} }
if fw.InDev != "" { if filter.InDev != "" {
nl.NewRtAttrChild(options, nl.TCA_FW_INDEV, nl.ZeroTerminated(fw.InDev)) options.AddRtAttr(nl.TCA_FW_INDEV, nl.ZeroTerminated(filter.InDev))
} }
if (fw.Police != nl.TcPolice{}) { if (filter.Police != nl.TcPolice{}) {
police := nl.NewRtAttrChild(options, nl.TCA_FW_POLICE, nil) police := options.AddRtAttr(nl.TCA_FW_POLICE, nil)
nl.NewRtAttrChild(police, nl.TCA_POLICE_TBF, fw.Police.Serialize()) police.AddRtAttr(nl.TCA_POLICE_TBF, filter.Police.Serialize())
if (fw.Police.Rate != nl.TcRateSpec{}) { if (filter.Police.Rate != nl.TcRateSpec{}) {
payload := SerializeRtab(fw.Rtab) payload := SerializeRtab(filter.Rtab)
nl.NewRtAttrChild(police, nl.TCA_POLICE_RATE, payload) police.AddRtAttr(nl.TCA_POLICE_RATE, payload)
} }
if (fw.Police.PeakRate != nl.TcRateSpec{}) { if (filter.Police.PeakRate != nl.TcRateSpec{}) {
payload := SerializeRtab(fw.Ptab) payload := SerializeRtab(filter.Ptab)
nl.NewRtAttrChild(police, nl.TCA_POLICE_PEAKRATE, payload) police.AddRtAttr(nl.TCA_POLICE_PEAKRATE, payload)
} }
} }
if fw.ClassId != 0 { if filter.ClassId != 0 {
b := make([]byte, 4) b := make([]byte, 4)
native.PutUint32(b, fw.ClassId) native.PutUint32(b, filter.ClassId)
nl.NewRtAttrChild(options, nl.TCA_FW_CLASSID, b) options.AddRtAttr(nl.TCA_FW_CLASSID, b)
} }
} else if bpf, ok := filter.(*BpfFilter); ok { case *BpfFilter:
var bpfFlags uint32 var bpfFlags uint32
if bpf.ClassId != 0 { if filter.ClassId != 0 {
nl.NewRtAttrChild(options, nl.TCA_BPF_CLASSID, nl.Uint32Attr(bpf.ClassId)) options.AddRtAttr(nl.TCA_BPF_CLASSID, nl.Uint32Attr(filter.ClassId))
} }
if bpf.Fd >= 0 { if filter.Fd >= 0 {
nl.NewRtAttrChild(options, nl.TCA_BPF_FD, nl.Uint32Attr((uint32(bpf.Fd)))) options.AddRtAttr(nl.TCA_BPF_FD, nl.Uint32Attr((uint32(filter.Fd))))
} }
if bpf.Name != "" { if filter.Name != "" {
nl.NewRtAttrChild(options, nl.TCA_BPF_NAME, nl.ZeroTerminated(bpf.Name)) options.AddRtAttr(nl.TCA_BPF_NAME, nl.ZeroTerminated(filter.Name))
} }
if bpf.DirectAction { if filter.DirectAction {
bpfFlags |= nl.TCA_BPF_FLAG_ACT_DIRECT bpfFlags |= nl.TCA_BPF_FLAG_ACT_DIRECT
} }
nl.NewRtAttrChild(options, nl.TCA_BPF_FLAGS, nl.Uint32Attr(bpfFlags)) options.AddRtAttr(nl.TCA_BPF_FLAGS, nl.Uint32Attr(bpfFlags))
case *MatchAll:
actionsAttr := options.AddRtAttr(nl.TCA_MATCHALL_ACT, nil)
if err := EncodeActions(actionsAttr, filter.Actions); err != nil {
return err
}
if filter.ClassId != 0 {
options.AddRtAttr(nl.TCA_MATCHALL_CLASSID, nl.Uint32Attr(filter.ClassId))
}
} }
req.AddData(options) req.AddData(options)
_, err := req.Execute(syscall.NETLINK_ROUTE, 0) _, err := req.Execute(unix.NETLINK_ROUTE, 0)
return err return err
} }
@ -229,7 +257,7 @@ func FilterList(link Link, parent uint32) ([]Filter, error) {
// Equivalent to: `tc filter show`. // Equivalent to: `tc filter show`.
// Generally returns nothing if link and parent are not specified. // Generally returns nothing if link and parent are not specified.
func (h *Handle) FilterList(link Link, parent uint32) ([]Filter, error) { func (h *Handle) FilterList(link Link, parent uint32) ([]Filter, error) {
req := h.newNetlinkRequest(syscall.RTM_GETTFILTER, syscall.NLM_F_DUMP) req := h.newNetlinkRequest(unix.RTM_GETTFILTER, unix.NLM_F_DUMP)
msg := &nl.TcMsg{ msg := &nl.TcMsg{
Family: nl.FAMILY_ALL, Family: nl.FAMILY_ALL,
Parent: parent, Parent: parent,
@ -241,7 +269,7 @@ func (h *Handle) FilterList(link Link, parent uint32) ([]Filter, error) {
} }
req.AddData(msg) req.AddData(msg)
msgs, err := req.Execute(syscall.NETLINK_ROUTE, syscall.RTM_NEWTFILTER) msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWTFILTER)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -277,6 +305,8 @@ func (h *Handle) FilterList(link Link, parent uint32) ([]Filter, error) {
filter = &Fw{} filter = &Fw{}
case "bpf": case "bpf":
filter = &BpfFilter{} filter = &BpfFilter{}
case "matchall":
filter = &MatchAll{}
default: default:
filter = &GenericFilter{FilterType: filterType} filter = &GenericFilter{FilterType: filterType}
} }
@ -301,6 +331,11 @@ func (h *Handle) FilterList(link Link, parent uint32) ([]Filter, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
case "matchall":
detailed, err = parseMatchAllData(filter, data)
if err != nil {
return nil, err
}
default: default:
detailed = true detailed = true
} }
@ -340,34 +375,34 @@ func EncodeActions(attr *nl.RtAttr, actions []Action) error {
default: default:
return fmt.Errorf("unknown action type %s", action.Type()) return fmt.Errorf("unknown action type %s", action.Type())
case *MirredAction: case *MirredAction:
table := nl.NewRtAttrChild(attr, tabIndex, nil) table := attr.AddRtAttr(tabIndex, nil)
tabIndex++ tabIndex++
nl.NewRtAttrChild(table, nl.TCA_ACT_KIND, nl.ZeroTerminated("mirred")) table.AddRtAttr(nl.TCA_ACT_KIND, nl.ZeroTerminated("mirred"))
aopts := nl.NewRtAttrChild(table, nl.TCA_ACT_OPTIONS, nil) aopts := table.AddRtAttr(nl.TCA_ACT_OPTIONS, nil)
mirred := nl.TcMirred{ mirred := nl.TcMirred{
Eaction: int32(action.MirredAction), Eaction: int32(action.MirredAction),
Ifindex: uint32(action.Ifindex), Ifindex: uint32(action.Ifindex),
} }
toTcGen(action.Attrs(), &mirred.TcGen) toTcGen(action.Attrs(), &mirred.TcGen)
nl.NewRtAttrChild(aopts, nl.TCA_MIRRED_PARMS, mirred.Serialize()) aopts.AddRtAttr(nl.TCA_MIRRED_PARMS, mirred.Serialize())
case *BpfAction: case *BpfAction:
table := nl.NewRtAttrChild(attr, tabIndex, nil) table := attr.AddRtAttr(tabIndex, nil)
tabIndex++ tabIndex++
nl.NewRtAttrChild(table, nl.TCA_ACT_KIND, nl.ZeroTerminated("bpf")) table.AddRtAttr(nl.TCA_ACT_KIND, nl.ZeroTerminated("bpf"))
aopts := nl.NewRtAttrChild(table, nl.TCA_ACT_OPTIONS, nil) aopts := table.AddRtAttr(nl.TCA_ACT_OPTIONS, nil)
gen := nl.TcGen{} gen := nl.TcGen{}
toTcGen(action.Attrs(), &gen) toTcGen(action.Attrs(), &gen)
nl.NewRtAttrChild(aopts, nl.TCA_ACT_BPF_PARMS, gen.Serialize()) aopts.AddRtAttr(nl.TCA_ACT_BPF_PARMS, gen.Serialize())
nl.NewRtAttrChild(aopts, nl.TCA_ACT_BPF_FD, nl.Uint32Attr(uint32(action.Fd))) aopts.AddRtAttr(nl.TCA_ACT_BPF_FD, nl.Uint32Attr(uint32(action.Fd)))
nl.NewRtAttrChild(aopts, nl.TCA_ACT_BPF_NAME, nl.ZeroTerminated(action.Name)) aopts.AddRtAttr(nl.TCA_ACT_BPF_NAME, nl.ZeroTerminated(action.Name))
case *GenericAction: case *GenericAction:
table := nl.NewRtAttrChild(attr, tabIndex, nil) table := attr.AddRtAttr(tabIndex, nil)
tabIndex++ tabIndex++
nl.NewRtAttrChild(table, nl.TCA_ACT_KIND, nl.ZeroTerminated("gact")) table.AddRtAttr(nl.TCA_ACT_KIND, nl.ZeroTerminated("gact"))
aopts := nl.NewRtAttrChild(table, nl.TCA_ACT_OPTIONS, nil) aopts := table.AddRtAttr(nl.TCA_ACT_OPTIONS, nil)
gen := nl.TcGen{} gen := nl.TcGen{}
toTcGen(action.Attrs(), &gen) toTcGen(action.Attrs(), &gen)
nl.NewRtAttrChild(aopts, nl.TCA_GACT_PARMS, gen.Serialize()) aopts.AddRtAttr(nl.TCA_GACT_PARMS, gen.Serialize())
} }
} }
return nil return nil
@ -474,6 +509,10 @@ func parseU32Data(filter Filter, data []syscall.NetlinkRouteAttr) (bool, error)
} }
case nl.TCA_U32_CLASSID: case nl.TCA_U32_CLASSID:
u32.ClassId = native.Uint32(datum.Value) u32.ClassId = native.Uint32(datum.Value)
case nl.TCA_U32_DIVISOR:
u32.Divisor = native.Uint32(datum.Value)
case nl.TCA_U32_HASH:
u32.Hash = native.Uint32(datum.Value)
} }
} }
return detailed, nil return detailed, nil
@ -530,6 +569,28 @@ func parseBpfData(filter Filter, data []syscall.NetlinkRouteAttr) (bool, error)
return detailed, nil return detailed, nil
} }
func parseMatchAllData(filter Filter, data []syscall.NetlinkRouteAttr) (bool, error) {
native = nl.NativeEndian()
matchall := filter.(*MatchAll)
detailed := true
for _, datum := range data {
switch datum.Attr.Type {
case nl.TCA_MATCHALL_CLASSID:
matchall.ClassId = native.Uint32(datum.Value[0:4])
case nl.TCA_MATCHALL_ACT:
tables, err := nl.ParseRouteAttr(datum.Value)
if err != nil {
return detailed, err
}
matchall.Actions, err = parseActions(tables)
if err != nil {
return detailed, err
}
}
}
return detailed, nil
}
func AlignToAtm(size uint) uint { func AlignToAtm(size uint) uint {
var linksize, cells int var linksize, cells int
cells = int(size / nl.ATM_CELL_PAYLOAD) cells = int(size / nl.ATM_CELL_PAYLOAD)
@ -552,7 +613,7 @@ func AdjustSize(sz uint, mpu uint, linklayer int) uint {
} }
} }
func CalcRtable(rate *nl.TcRateSpec, rtab [256]uint32, cellLog int, mtu uint32, linklayer int) int { func CalcRtable(rate *nl.TcRateSpec, rtab []uint32, cellLog int, mtu uint32, linklayer int) int {
bps := rate.Rate bps := rate.Rate
mpu := rate.Mpu mpu := rate.Mpu
var sz uint var sz uint

21
vendor/github.com/vishvananda/netlink/fou.go generated vendored Normal file
View File

@ -0,0 +1,21 @@
package netlink
import (
"errors"
)
var (
// ErrAttrHeaderTruncated is returned when a netlink attribute's header is
// truncated.
ErrAttrHeaderTruncated = errors.New("attribute header truncated")
// ErrAttrBodyTruncated is returned when a netlink attribute's body is
// truncated.
ErrAttrBodyTruncated = errors.New("attribute body truncated")
)
type Fou struct {
Family int
Port int
Protocol int
EncapType int
}

215
vendor/github.com/vishvananda/netlink/fou_linux.go generated vendored Normal file
View File

@ -0,0 +1,215 @@
// +build linux
package netlink
import (
"encoding/binary"
"errors"
"github.com/vishvananda/netlink/nl"
"golang.org/x/sys/unix"
)
const (
FOU_GENL_NAME = "fou"
)
const (
FOU_CMD_UNSPEC uint8 = iota
FOU_CMD_ADD
FOU_CMD_DEL
FOU_CMD_GET
FOU_CMD_MAX = FOU_CMD_GET
)
const (
FOU_ATTR_UNSPEC = iota
FOU_ATTR_PORT
FOU_ATTR_AF
FOU_ATTR_IPPROTO
FOU_ATTR_TYPE
FOU_ATTR_REMCSUM_NOPARTIAL
FOU_ATTR_MAX = FOU_ATTR_REMCSUM_NOPARTIAL
)
const (
FOU_ENCAP_UNSPEC = iota
FOU_ENCAP_DIRECT
FOU_ENCAP_GUE
FOU_ENCAP_MAX = FOU_ENCAP_GUE
)
var fouFamilyId int
func FouFamilyId() (int, error) {
if fouFamilyId != 0 {
return fouFamilyId, nil
}
fam, err := GenlFamilyGet(FOU_GENL_NAME)
if err != nil {
return -1, err
}
fouFamilyId = int(fam.ID)
return fouFamilyId, nil
}
func FouAdd(f Fou) error {
return pkgHandle.FouAdd(f)
}
func (h *Handle) FouAdd(f Fou) error {
fam_id, err := FouFamilyId()
if err != nil {
return err
}
// setting ip protocol conflicts with encapsulation type GUE
if f.EncapType == FOU_ENCAP_GUE && f.Protocol != 0 {
return errors.New("GUE encapsulation doesn't specify an IP protocol")
}
req := h.newNetlinkRequest(fam_id, unix.NLM_F_ACK)
// int to byte for port
bp := make([]byte, 2)
binary.BigEndian.PutUint16(bp[0:2], uint16(f.Port))
attrs := []*nl.RtAttr{
nl.NewRtAttr(FOU_ATTR_PORT, bp),
nl.NewRtAttr(FOU_ATTR_TYPE, []byte{uint8(f.EncapType)}),
nl.NewRtAttr(FOU_ATTR_AF, []byte{uint8(f.Family)}),
nl.NewRtAttr(FOU_ATTR_IPPROTO, []byte{uint8(f.Protocol)}),
}
raw := []byte{FOU_CMD_ADD, 1, 0, 0}
for _, a := range attrs {
raw = append(raw, a.Serialize()...)
}
req.AddRawData(raw)
_, err = req.Execute(unix.NETLINK_GENERIC, 0)
if err != nil {
return err
}
return nil
}
func FouDel(f Fou) error {
return pkgHandle.FouDel(f)
}
func (h *Handle) FouDel(f Fou) error {
fam_id, err := FouFamilyId()
if err != nil {
return err
}
req := h.newNetlinkRequest(fam_id, unix.NLM_F_ACK)
// int to byte for port
bp := make([]byte, 2)
binary.BigEndian.PutUint16(bp[0:2], uint16(f.Port))
attrs := []*nl.RtAttr{
nl.NewRtAttr(FOU_ATTR_PORT, bp),
nl.NewRtAttr(FOU_ATTR_AF, []byte{uint8(f.Family)}),
}
raw := []byte{FOU_CMD_DEL, 1, 0, 0}
for _, a := range attrs {
raw = append(raw, a.Serialize()...)
}
req.AddRawData(raw)
_, err = req.Execute(unix.NETLINK_GENERIC, 0)
if err != nil {
return err
}
return nil
}
func FouList(fam int) ([]Fou, error) {
return pkgHandle.FouList(fam)
}
func (h *Handle) FouList(fam int) ([]Fou, error) {
fam_id, err := FouFamilyId()
if err != nil {
return nil, err
}
req := h.newNetlinkRequest(fam_id, unix.NLM_F_DUMP)
attrs := []*nl.RtAttr{
nl.NewRtAttr(FOU_ATTR_AF, []byte{uint8(fam)}),
}
raw := []byte{FOU_CMD_GET, 1, 0, 0}
for _, a := range attrs {
raw = append(raw, a.Serialize()...)
}
req.AddRawData(raw)
msgs, err := req.Execute(unix.NETLINK_GENERIC, 0)
if err != nil {
return nil, err
}
fous := make([]Fou, 0, len(msgs))
for _, m := range msgs {
f, err := deserializeFouMsg(m)
if err != nil {
return fous, err
}
fous = append(fous, f)
}
return fous, nil
}
func deserializeFouMsg(msg []byte) (Fou, error) {
// we'll skip to byte 4 to first attribute
msg = msg[3:]
var shift int
fou := Fou{}
for {
// attribute header is at least 16 bits
if len(msg) < 4 {
return fou, ErrAttrHeaderTruncated
}
lgt := int(binary.BigEndian.Uint16(msg[0:2]))
if len(msg) < lgt+4 {
return fou, ErrAttrBodyTruncated
}
attr := binary.BigEndian.Uint16(msg[2:4])
shift = lgt + 3
switch attr {
case FOU_ATTR_AF:
fou.Family = int(msg[5])
case FOU_ATTR_PORT:
fou.Port = int(binary.BigEndian.Uint16(msg[5:7]))
// port is 2 bytes
shift = lgt + 2
case FOU_ATTR_IPPROTO:
fou.Protocol = int(msg[5])
case FOU_ATTR_TYPE:
fou.EncapType = int(msg[5])
}
msg = msg[shift:]
if len(msg) < 4 {
break
}
}
return fou, nil
}

View File

@ -0,0 +1,15 @@
// +build !linux
package netlink
func FouAdd(f Fou) error {
return ErrNotImplemented
}
func FouDel(f Fou) error {
return ErrNotImplemented
}
func FouList(fam int) ([]Fou, error) {
return nil, ErrNotImplemented
}

View File

@ -5,6 +5,7 @@ import (
"syscall" "syscall"
"github.com/vishvananda/netlink/nl" "github.com/vishvananda/netlink/nl"
"golang.org/x/sys/unix"
) )
type GenlOp struct { type GenlOp struct {
@ -130,9 +131,9 @@ func (h *Handle) GenlFamilyList() ([]*GenlFamily, error) {
Command: nl.GENL_CTRL_CMD_GETFAMILY, Command: nl.GENL_CTRL_CMD_GETFAMILY,
Version: nl.GENL_CTRL_VERSION, Version: nl.GENL_CTRL_VERSION,
} }
req := h.newNetlinkRequest(nl.GENL_ID_CTRL, syscall.NLM_F_DUMP) req := h.newNetlinkRequest(nl.GENL_ID_CTRL, unix.NLM_F_DUMP)
req.AddData(msg) req.AddData(msg)
msgs, err := req.Execute(syscall.NETLINK_GENERIC, 0) msgs, err := req.Execute(unix.NETLINK_GENERIC, 0)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -151,7 +152,7 @@ func (h *Handle) GenlFamilyGet(name string) (*GenlFamily, error) {
req := h.newNetlinkRequest(nl.GENL_ID_CTRL, 0) req := h.newNetlinkRequest(nl.GENL_ID_CTRL, 0)
req.AddData(msg) req.AddData(msg)
req.AddData(nl.NewRtAttr(nl.GENL_CTRL_ATTR_FAMILY_NAME, nl.ZeroTerminated(name))) req.AddData(nl.NewRtAttr(nl.GENL_CTRL_ATTR_FAMILY_NAME, nl.ZeroTerminated(name)))
msgs, err := req.Execute(syscall.NETLINK_GENERIC, 0) msgs, err := req.Execute(unix.NETLINK_GENERIC, 0)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -7,6 +7,7 @@ import (
"syscall" "syscall"
"github.com/vishvananda/netlink/nl" "github.com/vishvananda/netlink/nl"
"golang.org/x/sys/unix"
) )
type PDP struct { type PDP struct {
@ -82,9 +83,9 @@ func (h *Handle) GTPPDPList() ([]*PDP, error) {
Command: nl.GENL_GTP_CMD_GETPDP, Command: nl.GENL_GTP_CMD_GETPDP,
Version: nl.GENL_GTP_VERSION, Version: nl.GENL_GTP_VERSION,
} }
req := h.newNetlinkRequest(int(f.ID), syscall.NLM_F_DUMP) req := h.newNetlinkRequest(int(f.ID), unix.NLM_F_DUMP)
req.AddData(msg) req.AddData(msg)
msgs, err := req.Execute(syscall.NETLINK_GENERIC, 0) msgs, err := req.Execute(unix.NETLINK_GENERIC, 0)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -96,7 +97,7 @@ func GTPPDPList() ([]*PDP, error) {
} }
func gtpPDPGet(req *nl.NetlinkRequest) (*PDP, error) { func gtpPDPGet(req *nl.NetlinkRequest) (*PDP, error) {
msgs, err := req.Execute(syscall.NETLINK_GENERIC, 0) msgs, err := req.Execute(unix.NETLINK_GENERIC, 0)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -182,7 +183,7 @@ func (h *Handle) GTPPDPAdd(link Link, pdp *PDP) error {
Command: nl.GENL_GTP_CMD_NEWPDP, Command: nl.GENL_GTP_CMD_NEWPDP,
Version: nl.GENL_GTP_VERSION, Version: nl.GENL_GTP_VERSION,
} }
req := h.newNetlinkRequest(int(f.ID), syscall.NLM_F_EXCL|syscall.NLM_F_ACK) req := h.newNetlinkRequest(int(f.ID), unix.NLM_F_EXCL|unix.NLM_F_ACK)
req.AddData(msg) req.AddData(msg)
req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_VERSION, nl.Uint32Attr(pdp.Version))) req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_VERSION, nl.Uint32Attr(pdp.Version)))
req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_LINK, nl.Uint32Attr(uint32(link.Attrs().Index)))) req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_LINK, nl.Uint32Attr(uint32(link.Attrs().Index))))
@ -199,7 +200,7 @@ func (h *Handle) GTPPDPAdd(link Link, pdp *PDP) error {
default: default:
return fmt.Errorf("unsupported GTP version: %d", pdp.Version) return fmt.Errorf("unsupported GTP version: %d", pdp.Version)
} }
_, err = req.Execute(syscall.NETLINK_GENERIC, 0) _, err = req.Execute(unix.NETLINK_GENERIC, 0)
return err return err
} }
@ -216,7 +217,7 @@ func (h *Handle) GTPPDPDel(link Link, pdp *PDP) error {
Command: nl.GENL_GTP_CMD_DELPDP, Command: nl.GENL_GTP_CMD_DELPDP,
Version: nl.GENL_GTP_VERSION, Version: nl.GENL_GTP_VERSION,
} }
req := h.newNetlinkRequest(int(f.ID), syscall.NLM_F_EXCL|syscall.NLM_F_ACK) req := h.newNetlinkRequest(int(f.ID), unix.NLM_F_EXCL|unix.NLM_F_ACK)
req.AddData(msg) req.AddData(msg)
req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_VERSION, nl.Uint32Attr(pdp.Version))) req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_VERSION, nl.Uint32Attr(pdp.Version)))
req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_LINK, nl.Uint32Attr(uint32(link.Attrs().Index)))) req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_LINK, nl.Uint32Attr(uint32(link.Attrs().Index))))
@ -229,7 +230,7 @@ func (h *Handle) GTPPDPDel(link Link, pdp *PDP) error {
default: default:
return fmt.Errorf("unsupported GTP version: %d", pdp.Version) return fmt.Errorf("unsupported GTP version: %d", pdp.Version)
} }
_, err = req.Execute(syscall.NETLINK_GENERIC, 0) _, err = req.Execute(unix.NETLINK_GENERIC, 0)
return err return err
} }

View File

@ -2,11 +2,11 @@ package netlink
import ( import (
"fmt" "fmt"
"syscall"
"time" "time"
"github.com/vishvananda/netlink/nl" "github.com/vishvananda/netlink/nl"
"github.com/vishvananda/netns" "github.com/vishvananda/netns"
"golang.org/x/sys/unix"
) )
// Empty handle used by the netlink package methods // Empty handle used by the netlink package methods
@ -43,14 +43,29 @@ func (h *Handle) SetSocketTimeout(to time.Duration) error {
if to < time.Microsecond { if to < time.Microsecond {
return fmt.Errorf("invalid timeout, minimul value is %s", time.Microsecond) return fmt.Errorf("invalid timeout, minimul value is %s", time.Microsecond)
} }
tv := syscall.NsecToTimeval(to.Nanoseconds()) tv := unix.NsecToTimeval(to.Nanoseconds())
for _, sh := range h.sockets { for _, sh := range h.sockets {
fd := sh.Socket.GetFd() if err := sh.Socket.SetSendTimeout(&tv); err != nil {
err := syscall.SetsockoptTimeval(fd, syscall.SOL_SOCKET, syscall.SO_RCVTIMEO, &tv)
if err != nil {
return err return err
} }
err = syscall.SetsockoptTimeval(fd, syscall.SOL_SOCKET, syscall.SO_SNDTIMEO, &tv) if err := sh.Socket.SetReceiveTimeout(&tv); err != nil {
return err
}
}
return nil
}
// SetSocketReceiveBufferSize sets the receive buffer size for each
// socket in the netlink handle. The maximum value is capped by
// /proc/sys/net/core/rmem_max.
func (h *Handle) SetSocketReceiveBufferSize(size int, force bool) error {
opt := unix.SO_RCVBUF
if force {
opt = unix.SO_RCVBUFFORCE
}
for _, sh := range h.sockets {
fd := sh.Socket.GetFd()
err := unix.SetsockoptInt(fd, unix.SOL_SOCKET, opt, size)
if err != nil { if err != nil {
return err return err
} }
@ -58,6 +73,24 @@ func (h *Handle) SetSocketTimeout(to time.Duration) error {
return nil return nil
} }
// GetSocketReceiveBufferSize gets the receiver buffer size for each
// socket in the netlink handle. The retrieved value should be the
// double to the one set for SetSocketReceiveBufferSize.
func (h *Handle) GetSocketReceiveBufferSize() ([]int, error) {
results := make([]int, len(h.sockets))
i := 0
for _, sh := range h.sockets {
fd := sh.Socket.GetFd()
size, err := unix.GetsockoptInt(fd, unix.SOL_SOCKET, unix.SO_RCVBUF)
if err != nil {
return nil, err
}
results[i] = size
i++
}
return results, nil
}
// NewHandle returns a netlink handle on the network namespace // NewHandle returns a netlink handle on the network namespace
// specified by ns. If ns=netns.None(), current network namespace // specified by ns. If ns=netns.None(), current network namespace
// will be assumed // will be assumed
@ -101,10 +134,10 @@ func (h *Handle) newNetlinkRequest(proto, flags int) *nl.NetlinkRequest {
return nl.NewNetlinkRequest(proto, flags) return nl.NewNetlinkRequest(proto, flags)
} }
return &nl.NetlinkRequest{ return &nl.NetlinkRequest{
NlMsghdr: syscall.NlMsghdr{ NlMsghdr: unix.NlMsghdr{
Len: uint32(syscall.SizeofNlMsghdr), Len: uint32(unix.SizeofNlMsghdr),
Type: uint16(proto), Type: uint16(proto),
Flags: syscall.NLM_F_REQUEST | uint16(flags), Flags: unix.NLM_F_REQUEST | uint16(flags),
}, },
Sockets: h.sockets, Sockets: h.sockets,
} }

View File

@ -145,6 +145,10 @@ func (h *Handle) LinkSetFlood(link Link, mode bool) error {
return ErrNotImplemented return ErrNotImplemented
} }
func (h *Handle) LinkSetTxQLen(link Link, qlen int) error {
return ErrNotImplemented
}
func (h *Handle) setProtinfoAttr(link Link, mode bool, attr int) error { func (h *Handle) setProtinfoAttr(link Link, mode bool, attr int) error {
return ErrNotImplemented return ErrNotImplemented
} }
@ -216,3 +220,39 @@ func (h *Handle) NeighList(linkIndex, family int) ([]Neigh, error) {
func (h *Handle) NeighProxyList(linkIndex, family int) ([]Neigh, error) { func (h *Handle) NeighProxyList(linkIndex, family int) ([]Neigh, error) {
return nil, ErrNotImplemented return nil, ErrNotImplemented
} }
func (h *Handle) RouteAdd(route *Route) error {
return ErrNotImplemented
}
func (h *Handle) RouteDel(route *Route) error {
return ErrNotImplemented
}
func (h *Handle) RouteGet(destination net.IP) ([]Route, error) {
return nil, ErrNotImplemented
}
func (h *Handle) RouteList(link Link, family int) ([]Route, error) {
return nil, ErrNotImplemented
}
func (h *Handle) RouteListFiltered(family int, filter *Route, filterMask uint64) ([]Route, error) {
return nil, ErrNotImplemented
}
func (h *Handle) RouteReplace(route *Route) error {
return ErrNotImplemented
}
func (h *Handle) RuleAdd(rule *Rule) error {
return ErrNotImplemented
}
func (h *Handle) RuleDel(rule *Rule) error {
return ErrNotImplemented
}
func (h *Handle) RuleList(family int) ([]Rule, error) {
return nil, ErrNotImplemented
}

98
vendor/github.com/vishvananda/netlink/ioctl_linux.go generated vendored Normal file
View File

@ -0,0 +1,98 @@
package netlink
import (
"syscall"
"unsafe"
"golang.org/x/sys/unix"
)
// ioctl for statistics.
const (
// ETHTOOL_GSSET_INFO gets string set info
ETHTOOL_GSSET_INFO = 0x00000037
// SIOCETHTOOL is Ethtool interface
SIOCETHTOOL = 0x8946
// ETHTOOL_GSTRINGS gets specified string set
ETHTOOL_GSTRINGS = 0x0000001b
// ETHTOOL_GSTATS gets NIC-specific statistics
ETHTOOL_GSTATS = 0x0000001d
)
// string set id.
const (
// ETH_SS_TEST is self-test result names, for use with %ETHTOOL_TEST
ETH_SS_TEST = iota
// ETH_SS_STATS statistic names, for use with %ETHTOOL_GSTATS
ETH_SS_STATS
// ETH_SS_PRIV_FLAGS are driver private flag names
ETH_SS_PRIV_FLAGS
// _ETH_SS_NTUPLE_FILTERS is deprecated
_ETH_SS_NTUPLE_FILTERS
// ETH_SS_FEATURES are device feature names
ETH_SS_FEATURES
// ETH_SS_RSS_HASH_FUNCS is RSS hush function names
ETH_SS_RSS_HASH_FUNCS
)
// IfreqSlave is a struct for ioctl bond manipulation syscalls.
// It is used to assign slave to bond interface with Name.
type IfreqSlave struct {
Name [unix.IFNAMSIZ]byte
Slave [unix.IFNAMSIZ]byte
}
// Ifreq is a struct for ioctl ethernet manipulation syscalls.
type Ifreq struct {
Name [unix.IFNAMSIZ]byte
Data uintptr
}
// ethtoolSset is a string set information
type ethtoolSset struct {
cmd uint32
reserved uint32
mask uint64
data [1]uint32
}
// ethtoolGstrings is string set for data tagging
type ethtoolGstrings struct {
cmd uint32
stringSet uint32
length uint32
data [32]byte
}
type ethtoolStats struct {
cmd uint32
nStats uint32
data [1]uint64
}
// newIocltSlaveReq returns filled IfreqSlave with proper interface names
// It is used by ioctl to assign slave to bond master
func newIocltSlaveReq(slave, master string) *IfreqSlave {
ifreq := &IfreqSlave{}
copy(ifreq.Name[:unix.IFNAMSIZ-1], master)
copy(ifreq.Slave[:unix.IFNAMSIZ-1], slave)
return ifreq
}
// newIocltStringSetReq creates request to get interface string set
func newIocltStringSetReq(linkName string) (*Ifreq, *ethtoolSset) {
e := &ethtoolSset{
cmd: ETHTOOL_GSSET_INFO,
mask: 1 << ETH_SS_STATS,
}
ifreq := &Ifreq{Data: uintptr(unsafe.Pointer(e))}
copy(ifreq.Name[:unix.IFNAMSIZ-1], linkName)
return ifreq, e
}
// getSocketUDP returns file descriptor to new UDP socket
// It is used for communication with ioctl interface.
func getSocketUDP() (int, error) {
return syscall.Socket(unix.AF_INET, unix.SOCK_DGRAM, 0)
}

View File

@ -3,6 +3,7 @@ package netlink
import ( import (
"fmt" "fmt"
"net" "net"
"os"
) )
// Link represents a link device from netlink. Shared link attributes // Link represents a link device from netlink. Shared link attributes
@ -37,6 +38,21 @@ type LinkAttrs struct {
EncapType string EncapType string
Protinfo *Protinfo Protinfo *Protinfo
OperState LinkOperState OperState LinkOperState
NetNsID int
NumTxQueues int
NumRxQueues int
Vfs []VfInfo // virtual functions available on link
}
// VfInfo represents configuration of virtual function
type VfInfo struct {
ID int
Mac net.HardwareAddr
Vlan int
Qos int
TxRate int
Spoofchk bool
LinkState uint32
} }
// LinkOperState represents the values of the IFLA_OPERSTATE link // LinkOperState represents the values of the IFLA_OPERSTATE link
@ -171,6 +187,7 @@ type LinkXdp struct {
Fd int Fd int
Attached bool Attached bool
Flags uint32 Flags uint32
ProgId uint32
} }
// Device links cannot be created via netlink. These links // Device links cannot be created via netlink. These links
@ -218,6 +235,7 @@ type Bridge struct {
LinkAttrs LinkAttrs
MulticastSnooping *bool MulticastSnooping *bool
HelloTime *uint32 HelloTime *uint32
VlanFiltering *bool
} }
func (bridge *Bridge) Attrs() *LinkAttrs { func (bridge *Bridge) Attrs() *LinkAttrs {
@ -257,6 +275,9 @@ const (
type Macvlan struct { type Macvlan struct {
LinkAttrs LinkAttrs
Mode MacvlanMode Mode MacvlanMode
// MACAddrs is only populated for Macvlan SOURCE links
MACAddrs []net.HardwareAddr
} }
func (macvlan *Macvlan) Attrs() *LinkAttrs { func (macvlan *Macvlan) Attrs() *LinkAttrs {
@ -282,8 +303,11 @@ type TuntapFlag uint16
// Tuntap links created via /dev/tun/tap, but can be destroyed via netlink // Tuntap links created via /dev/tun/tap, but can be destroyed via netlink
type Tuntap struct { type Tuntap struct {
LinkAttrs LinkAttrs
Mode TuntapMode Mode TuntapMode
Flags TuntapFlag Flags TuntapFlag
NonPersist bool
Queues int
Fds []*os.File
} }
func (tuntap *Tuntap) Attrs() *LinkAttrs { func (tuntap *Tuntap) Attrs() *LinkAttrs {
@ -325,26 +349,28 @@ func (generic *GenericLink) Type() string {
type Vxlan struct { type Vxlan struct {
LinkAttrs LinkAttrs
VxlanId int VxlanId int
VtepDevIndex int VtepDevIndex int
SrcAddr net.IP SrcAddr net.IP
Group net.IP Group net.IP
TTL int TTL int
TOS int TOS int
Learning bool Learning bool
Proxy bool Proxy bool
RSC bool RSC bool
L2miss bool L2miss bool
L3miss bool L3miss bool
UDPCSum bool UDPCSum bool
NoAge bool UDP6ZeroCSumTx bool
GBP bool UDP6ZeroCSumRx bool
FlowBased bool NoAge bool
Age int GBP bool
Limit int FlowBased bool
Port int Age int
PortLow int Limit int
PortHigh int Port int
PortLow int
PortHigh int
} }
func (vxlan *Vxlan) Attrs() *LinkAttrs { func (vxlan *Vxlan) Attrs() *LinkAttrs {
@ -693,17 +719,25 @@ func (gretap *Gretap) Attrs() *LinkAttrs {
} }
func (gretap *Gretap) Type() string { func (gretap *Gretap) Type() string {
if gretap.Local.To4() == nil {
return "ip6gretap"
}
return "gretap" return "gretap"
} }
type Iptun struct { type Iptun struct {
LinkAttrs LinkAttrs
Ttl uint8 Ttl uint8
Tos uint8 Tos uint8
PMtuDisc uint8 PMtuDisc uint8
Link uint32 Link uint32
Local net.IP Local net.IP
Remote net.IP Remote net.IP
EncapSport uint16
EncapDport uint16
EncapType uint16
EncapFlags uint16
FlowBased bool
} }
func (iptun *Iptun) Attrs() *LinkAttrs { func (iptun *Iptun) Attrs() *LinkAttrs {
@ -714,6 +748,28 @@ func (iptun *Iptun) Type() string {
return "ipip" return "ipip"
} }
type Sittun struct {
LinkAttrs
Link uint32
Local net.IP
Remote net.IP
Ttl uint8
Tos uint8
PMtuDisc uint8
EncapType uint16
EncapFlags uint16
EncapSport uint16
EncapDport uint16
}
func (sittun *Sittun) Attrs() *LinkAttrs {
return &sittun.LinkAttrs
}
func (sittun *Sittun) Type() string {
return "sit"
}
type Vti struct { type Vti struct {
LinkAttrs LinkAttrs
IKey uint32 IKey uint32
@ -727,10 +783,42 @@ func (vti *Vti) Attrs() *LinkAttrs {
return &vti.LinkAttrs return &vti.LinkAttrs
} }
func (iptun *Vti) Type() string { func (vti *Vti) Type() string {
if vti.Local.To4() == nil {
return "vti6"
}
return "vti" return "vti"
} }
type Gretun struct {
LinkAttrs
Link uint32
IFlags uint16
OFlags uint16
IKey uint32
OKey uint32
Local net.IP
Remote net.IP
Ttl uint8
Tos uint8
PMtuDisc uint8
EncapType uint16
EncapFlags uint16
EncapSport uint16
EncapDport uint16
}
func (gretun *Gretun) Attrs() *LinkAttrs {
return &gretun.LinkAttrs
}
func (gretun *Gretun) Type() string {
if gretun.Local.To4() == nil {
return "ip6gre"
}
return "gre"
}
type Vrf struct { type Vrf struct {
LinkAttrs LinkAttrs
Table uint32 Table uint32
@ -763,7 +851,7 @@ func (gtp *GTP) Type() string {
// iproute2 supported devices; // iproute2 supported devices;
// vlan | veth | vcan | dummy | ifb | macvlan | macvtap | // vlan | veth | vcan | dummy | ifb | macvlan | macvtap |
// bridge | bond | ipoib | ip6tnl | ipip | sit | vxlan | // bridge | bond | ipoib | ip6tnl | ipip | sit | vxlan |
// gre | gretap | ip6gre | ip6gretap | vti | nlmon | // gre | gretap | ip6gre | ip6gretap | vti | vti6 | nlmon |
// bond_slave | ipvlan // bond_slave | ipvlan
// LinkNotFoundError wraps the various not found errors when // LinkNotFoundError wraps the various not found errors when

File diff suppressed because it is too large Load Diff

View File

@ -14,9 +14,18 @@ type Neigh struct {
Flags int Flags int
IP net.IP IP net.IP
HardwareAddr net.HardwareAddr HardwareAddr net.HardwareAddr
LLIPAddr net.IP //Used in the case of NHRP
Vlan int
VNI int
} }
// String returns $ip/$hwaddr $label // String returns $ip/$hwaddr $label
func (neigh *Neigh) String() string { func (neigh *Neigh) String() string {
return fmt.Sprintf("%s %s", neigh.IP, neigh.HardwareAddr) return fmt.Sprintf("%s %s", neigh.IP, neigh.HardwareAddr)
} }
// NeighUpdate is sent when a neighbor changes - type is RTM_NEWNEIGH or RTM_DELNEIGH.
type NeighUpdate struct {
Type uint16
Neigh
}

View File

@ -6,6 +6,8 @@ import (
"unsafe" "unsafe"
"github.com/vishvananda/netlink/nl" "github.com/vishvananda/netlink/nl"
"github.com/vishvananda/netns"
"golang.org/x/sys/unix"
) )
const ( const (
@ -73,7 +75,7 @@ func NeighAdd(neigh *Neigh) error {
// NeighAdd will add an IP to MAC mapping to the ARP table // NeighAdd will add an IP to MAC mapping to the ARP table
// Equivalent to: `ip neigh add ....` // Equivalent to: `ip neigh add ....`
func (h *Handle) NeighAdd(neigh *Neigh) error { func (h *Handle) NeighAdd(neigh *Neigh) error {
return h.neighAdd(neigh, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL) return h.neighAdd(neigh, unix.NLM_F_CREATE|unix.NLM_F_EXCL)
} }
// NeighSet will add or replace an IP to MAC mapping to the ARP table // NeighSet will add or replace an IP to MAC mapping to the ARP table
@ -85,7 +87,7 @@ func NeighSet(neigh *Neigh) error {
// NeighSet will add or replace an IP to MAC mapping to the ARP table // NeighSet will add or replace an IP to MAC mapping to the ARP table
// Equivalent to: `ip neigh replace....` // Equivalent to: `ip neigh replace....`
func (h *Handle) NeighSet(neigh *Neigh) error { func (h *Handle) NeighSet(neigh *Neigh) error {
return h.neighAdd(neigh, syscall.NLM_F_CREATE|syscall.NLM_F_REPLACE) return h.neighAdd(neigh, unix.NLM_F_CREATE|unix.NLM_F_REPLACE)
} }
// NeighAppend will append an entry to FDB // NeighAppend will append an entry to FDB
@ -97,7 +99,7 @@ func NeighAppend(neigh *Neigh) error {
// NeighAppend will append an entry to FDB // NeighAppend will append an entry to FDB
// Equivalent to: `bridge fdb append...` // Equivalent to: `bridge fdb append...`
func (h *Handle) NeighAppend(neigh *Neigh) error { func (h *Handle) NeighAppend(neigh *Neigh) error {
return h.neighAdd(neigh, syscall.NLM_F_CREATE|syscall.NLM_F_APPEND) return h.neighAdd(neigh, unix.NLM_F_CREATE|unix.NLM_F_APPEND)
} }
// NeighAppend will append an entry to FDB // NeighAppend will append an entry to FDB
@ -109,7 +111,7 @@ func neighAdd(neigh *Neigh, mode int) error {
// NeighAppend will append an entry to FDB // NeighAppend will append an entry to FDB
// Equivalent to: `bridge fdb append...` // Equivalent to: `bridge fdb append...`
func (h *Handle) neighAdd(neigh *Neigh, mode int) error { func (h *Handle) neighAdd(neigh *Neigh, mode int) error {
req := h.newNetlinkRequest(syscall.RTM_NEWNEIGH, mode|syscall.NLM_F_ACK) req := h.newNetlinkRequest(unix.RTM_NEWNEIGH, mode|unix.NLM_F_ACK)
return neighHandle(neigh, req) return neighHandle(neigh, req)
} }
@ -122,12 +124,13 @@ func NeighDel(neigh *Neigh) error {
// NeighDel will delete an IP address from a link device. // NeighDel will delete an IP address from a link device.
// Equivalent to: `ip addr del $addr dev $link` // Equivalent to: `ip addr del $addr dev $link`
func (h *Handle) NeighDel(neigh *Neigh) error { func (h *Handle) NeighDel(neigh *Neigh) error {
req := h.newNetlinkRequest(syscall.RTM_DELNEIGH, syscall.NLM_F_ACK) req := h.newNetlinkRequest(unix.RTM_DELNEIGH, unix.NLM_F_ACK)
return neighHandle(neigh, req) return neighHandle(neigh, req)
} }
func neighHandle(neigh *Neigh, req *nl.NetlinkRequest) error { func neighHandle(neigh *Neigh, req *nl.NetlinkRequest) error {
var family int var family int
if neigh.Family > 0 { if neigh.Family > 0 {
family = neigh.Family family = neigh.Family
} else { } else {
@ -151,12 +154,25 @@ func neighHandle(neigh *Neigh, req *nl.NetlinkRequest) error {
dstData := nl.NewRtAttr(NDA_DST, ipData) dstData := nl.NewRtAttr(NDA_DST, ipData)
req.AddData(dstData) req.AddData(dstData)
if neigh.Flags != NTF_PROXY || neigh.HardwareAddr != nil { if neigh.LLIPAddr != nil {
llIPData := nl.NewRtAttr(NDA_LLADDR, neigh.LLIPAddr.To4())
req.AddData(llIPData)
} else if neigh.Flags != NTF_PROXY || neigh.HardwareAddr != nil {
hwData := nl.NewRtAttr(NDA_LLADDR, []byte(neigh.HardwareAddr)) hwData := nl.NewRtAttr(NDA_LLADDR, []byte(neigh.HardwareAddr))
req.AddData(hwData) req.AddData(hwData)
} }
_, err := req.Execute(syscall.NETLINK_ROUTE, 0) if neigh.Vlan != 0 {
vlanData := nl.NewRtAttr(NDA_VLAN, nl.Uint16Attr(uint16(neigh.Vlan)))
req.AddData(vlanData)
}
if neigh.VNI != 0 {
vniData := nl.NewRtAttr(NDA_VNI, nl.Uint32Attr(uint32(neigh.VNI)))
req.AddData(vniData)
}
_, err := req.Execute(unix.NETLINK_ROUTE, 0)
return err return err
} }
@ -189,7 +205,7 @@ func (h *Handle) NeighProxyList(linkIndex, family int) ([]Neigh, error) {
} }
func (h *Handle) neighList(linkIndex, family, flags int) ([]Neigh, error) { func (h *Handle) neighList(linkIndex, family, flags int) ([]Neigh, error) {
req := h.newNetlinkRequest(syscall.RTM_GETNEIGH, syscall.NLM_F_DUMP) req := h.newNetlinkRequest(unix.RTM_GETNEIGH, unix.NLM_F_DUMP)
msg := Ndmsg{ msg := Ndmsg{
Family: uint8(family), Family: uint8(family),
Index: uint32(linkIndex), Index: uint32(linkIndex),
@ -197,7 +213,7 @@ func (h *Handle) neighList(linkIndex, family, flags int) ([]Neigh, error) {
} }
req.AddData(&msg) req.AddData(&msg)
msgs, err := req.Execute(syscall.NETLINK_ROUTE, syscall.RTM_NEWNEIGH) msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWNEIGH)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -237,14 +253,130 @@ func NeighDeserialize(m []byte) (*Neigh, error) {
return nil, err return nil, err
} }
// This should be cached for perfomance
// once per table dump
link, err := LinkByIndex(neigh.LinkIndex)
if err != nil {
return nil, err
}
encapType := link.Attrs().EncapType
for _, attr := range attrs { for _, attr := range attrs {
switch attr.Attr.Type { switch attr.Attr.Type {
case NDA_DST: case NDA_DST:
neigh.IP = net.IP(attr.Value) neigh.IP = net.IP(attr.Value)
case NDA_LLADDR: case NDA_LLADDR:
neigh.HardwareAddr = net.HardwareAddr(attr.Value) // BUG: Is this a bug in the netlink library?
// #define RTA_LENGTH(len) (RTA_ALIGN(sizeof(struct rtattr)) + (len))
// #define RTA_PAYLOAD(rta) ((int)((rta)->rta_len) - RTA_LENGTH(0))
attrLen := attr.Attr.Len - unix.SizeofRtAttr
if attrLen == 4 && (encapType == "ipip" ||
encapType == "sit" ||
encapType == "gre") {
neigh.LLIPAddr = net.IP(attr.Value)
} else if attrLen == 16 &&
encapType == "tunnel6" {
neigh.IP = net.IP(attr.Value)
} else {
neigh.HardwareAddr = net.HardwareAddr(attr.Value)
}
case NDA_VLAN:
neigh.Vlan = int(native.Uint16(attr.Value[0:2]))
case NDA_VNI:
neigh.VNI = int(native.Uint32(attr.Value[0:4]))
} }
} }
return &neigh, nil return &neigh, nil
} }
// NeighSubscribe takes a chan down which notifications will be sent
// when neighbors are added or deleted. Close the 'done' chan to stop subscription.
func NeighSubscribe(ch chan<- NeighUpdate, done <-chan struct{}) error {
return neighSubscribeAt(netns.None(), netns.None(), ch, done, nil, false)
}
// NeighSubscribeAt works like NeighSubscribe plus it allows the caller
// to choose the network namespace in which to subscribe (ns).
func NeighSubscribeAt(ns netns.NsHandle, ch chan<- NeighUpdate, done <-chan struct{}) error {
return neighSubscribeAt(ns, netns.None(), ch, done, nil, false)
}
// NeighSubscribeOptions contains a set of options to use with
// NeighSubscribeWithOptions.
type NeighSubscribeOptions struct {
Namespace *netns.NsHandle
ErrorCallback func(error)
ListExisting bool
}
// NeighSubscribeWithOptions work like NeighSubscribe but enable to
// provide additional options to modify the behavior. Currently, the
// namespace can be provided as well as an error callback.
func NeighSubscribeWithOptions(ch chan<- NeighUpdate, done <-chan struct{}, options NeighSubscribeOptions) error {
if options.Namespace == nil {
none := netns.None()
options.Namespace = &none
}
return neighSubscribeAt(*options.Namespace, netns.None(), ch, done, options.ErrorCallback, options.ListExisting)
}
func neighSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- NeighUpdate, done <-chan struct{}, cberr func(error), listExisting bool) error {
s, err := nl.SubscribeAt(newNs, curNs, unix.NETLINK_ROUTE, unix.RTNLGRP_NEIGH)
if err != nil {
return err
}
if done != nil {
go func() {
<-done
s.Close()
}()
}
if listExisting {
req := pkgHandle.newNetlinkRequest(unix.RTM_GETNEIGH,
unix.NLM_F_DUMP)
infmsg := nl.NewIfInfomsg(unix.AF_UNSPEC)
req.AddData(infmsg)
if err := s.Send(req); err != nil {
return err
}
}
go func() {
defer close(ch)
for {
msgs, err := s.Receive()
if err != nil {
if cberr != nil {
cberr(err)
}
return
}
for _, m := range msgs {
if m.Header.Type == unix.NLMSG_DONE {
continue
}
if m.Header.Type == unix.NLMSG_ERROR {
native := nl.NativeEndian()
error := int32(native.Uint32(m.Data[0:4]))
if error == 0 {
continue
}
if cberr != nil {
cberr(syscall.Errno(-error))
}
return
}
neigh, err := NeighDeserialize(m.Data)
if err != nil {
if cberr != nil {
cberr(err)
}
return
}
ch <- NeighUpdate{Type: m.Header.Type, Neigh: *neigh}
}
}
}()
return nil
}

View File

@ -27,7 +27,8 @@ func ParseIPNet(s string) (*net.IPNet, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &net.IPNet{IP: ip, Mask: ipNet.Mask}, nil ipNet.IP = ip
return ipNet, nil
} }
// NewIPNet generates an IPNet from an ip address using a netmask of 32 or 128. // NewIPNet generates an IPNet from an ip address using a netmask of 32 or 128.

View File

@ -108,6 +108,10 @@ func LinkSetFlood(link Link, mode bool) error {
return ErrNotImplemented return ErrNotImplemented
} }
func LinkSetTxQLen(link Link, qlen int) error {
return ErrNotImplemented
}
func LinkAdd(link Link) error { func LinkAdd(link Link) error {
return ErrNotImplemented return ErrNotImplemented
} }

141
vendor/github.com/vishvananda/netlink/netns_linux.go generated vendored Normal file
View File

@ -0,0 +1,141 @@
package netlink
// Network namespace ID functions
//
// The kernel has a weird concept called the network namespace ID.
// This is different from the file reference in proc (and any bind-mounted
// namespaces, etc.)
//
// Instead, namespaces can be assigned a numeric ID at any time. Once set,
// the ID is fixed. The ID can either be set manually by the user, or
// automatically, triggered by certain kernel actions. The most common kernel
// action that triggers namespace ID creation is moving one end of a veth pair
// in to that namespace.
import (
"fmt"
"github.com/vishvananda/netlink/nl"
"golang.org/x/sys/unix"
)
// These can be replaced by the values from sys/unix when it is next released.
const (
_ = iota
NETNSA_NSID
NETNSA_PID
NETNSA_FD
)
// GetNetNsIdByPid looks up the network namespace ID for a given pid (really thread id).
// Returns -1 if the namespace does not have an ID set.
func (h *Handle) GetNetNsIdByPid(pid int) (int, error) {
return h.getNetNsId(NETNSA_PID, uint32(pid))
}
// GetNetNsIdByPid looks up the network namespace ID for a given pid (really thread id).
// Returns -1 if the namespace does not have an ID set.
func GetNetNsIdByPid(pid int) (int, error) {
return pkgHandle.GetNetNsIdByPid(pid)
}
// SetNetNSIdByPid sets the ID of the network namespace for a given pid (really thread id).
// The ID can only be set for namespaces without an ID already set.
func (h *Handle) SetNetNsIdByPid(pid, nsid int) error {
return h.setNetNsId(NETNSA_PID, uint32(pid), uint32(nsid))
}
// SetNetNSIdByPid sets the ID of the network namespace for a given pid (really thread id).
// The ID can only be set for namespaces without an ID already set.
func SetNetNsIdByPid(pid, nsid int) error {
return pkgHandle.SetNetNsIdByPid(pid, nsid)
}
// GetNetNsIdByPid looks up the network namespace ID for a given fd.
// fd must be an open file descriptor to a namespace file.
// Returns -1 if the namespace does not have an ID set.
func (h *Handle) GetNetNsIdByFd(fd int) (int, error) {
return h.getNetNsId(NETNSA_FD, uint32(fd))
}
// GetNetNsIdByPid looks up the network namespace ID for a given fd.
// fd must be an open file descriptor to a namespace file.
// Returns -1 if the namespace does not have an ID set.
func GetNetNsIdByFd(fd int) (int, error) {
return pkgHandle.GetNetNsIdByFd(fd)
}
// SetNetNSIdByFd sets the ID of the network namespace for a given fd.
// fd must be an open file descriptor to a namespace file.
// The ID can only be set for namespaces without an ID already set.
func (h *Handle) SetNetNsIdByFd(fd, nsid int) error {
return h.setNetNsId(NETNSA_FD, uint32(fd), uint32(nsid))
}
// SetNetNSIdByFd sets the ID of the network namespace for a given fd.
// fd must be an open file descriptor to a namespace file.
// The ID can only be set for namespaces without an ID already set.
func SetNetNsIdByFd(fd, nsid int) error {
return pkgHandle.SetNetNsIdByFd(fd, nsid)
}
// getNetNsId requests the netnsid for a given type-val pair
// type should be either NETNSA_PID or NETNSA_FD
func (h *Handle) getNetNsId(attrType int, val uint32) (int, error) {
req := h.newNetlinkRequest(unix.RTM_GETNSID, unix.NLM_F_REQUEST)
rtgen := nl.NewRtGenMsg()
req.AddData(rtgen)
b := make([]byte, 4, 4)
native.PutUint32(b, val)
attr := nl.NewRtAttr(attrType, b)
req.AddData(attr)
msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWNSID)
if err != nil {
return 0, err
}
for _, m := range msgs {
msg := nl.DeserializeRtGenMsg(m)
attrs, err := nl.ParseRouteAttr(m[msg.Len():])
if err != nil {
return 0, err
}
for _, attr := range attrs {
switch attr.Attr.Type {
case NETNSA_NSID:
return int(int32(native.Uint32(attr.Value))), nil
}
}
}
return 0, fmt.Errorf("unexpected empty result")
}
// setNetNsId sets the netnsid for a given type-val pair
// type should be either NETNSA_PID or NETNSA_FD
// The ID can only be set for namespaces without an ID already set
func (h *Handle) setNetNsId(attrType int, val uint32, newnsid uint32) error {
req := h.newNetlinkRequest(unix.RTM_NEWNSID, unix.NLM_F_REQUEST|unix.NLM_F_ACK)
rtgen := nl.NewRtGenMsg()
req.AddData(rtgen)
b := make([]byte, 4, 4)
native.PutUint32(b, val)
attr := nl.NewRtAttr(attrType, b)
req.AddData(attr)
b1 := make([]byte, 4, 4)
native.PutUint32(b1, newnsid)
attr1 := nl.NewRtAttr(NETNSA_NSID, b1)
req.AddData(attr1)
_, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWNSID)
return err
}

View File

@ -0,0 +1,19 @@
// +build !linux
package netlink
func GetNetNsIdByPid(pid int) (int, error) {
return 0, ErrNotImplemented
}
func SetNetNsIdByPid(pid, nsid int) error {
return ErrNotImplemented
}
func GetNetNsIdByFd(fd int) (int, error) {
return 0, ErrNotImplemented
}
func SetNetNsIdByFd(fd, nsid int) error {
return ErrNotImplemented
}

View File

@ -1,17 +1,18 @@
package nl package nl
import ( import (
"syscall"
"unsafe" "unsafe"
"golang.org/x/sys/unix"
) )
type IfAddrmsg struct { type IfAddrmsg struct {
syscall.IfAddrmsg unix.IfAddrmsg
} }
func NewIfAddrmsg(family int) *IfAddrmsg { func NewIfAddrmsg(family int) *IfAddrmsg {
return &IfAddrmsg{ return &IfAddrmsg{
IfAddrmsg: syscall.IfAddrmsg{ IfAddrmsg: unix.IfAddrmsg{
Family: uint8(family), Family: uint8(family),
}, },
} }
@ -35,15 +36,15 @@ func NewIfAddrmsg(family int) *IfAddrmsg {
// SizeofIfAddrmsg = 0x8 // SizeofIfAddrmsg = 0x8
func DeserializeIfAddrmsg(b []byte) *IfAddrmsg { func DeserializeIfAddrmsg(b []byte) *IfAddrmsg {
return (*IfAddrmsg)(unsafe.Pointer(&b[0:syscall.SizeofIfAddrmsg][0])) return (*IfAddrmsg)(unsafe.Pointer(&b[0:unix.SizeofIfAddrmsg][0]))
} }
func (msg *IfAddrmsg) Serialize() []byte { func (msg *IfAddrmsg) Serialize() []byte {
return (*(*[syscall.SizeofIfAddrmsg]byte)(unsafe.Pointer(msg)))[:] return (*(*[unix.SizeofIfAddrmsg]byte)(unsafe.Pointer(msg)))[:]
} }
func (msg *IfAddrmsg) Len() int { func (msg *IfAddrmsg) Len() int {
return syscall.SizeofIfAddrmsg return unix.SizeofIfAddrmsg
} }
// struct ifa_cacheinfo { // struct ifa_cacheinfo {

View File

@ -11,8 +11,8 @@ const (
/* Bridge Flags */ /* Bridge Flags */
const ( const (
BRIDGE_FLAGS_MASTER = iota /* Bridge command to/from master */ BRIDGE_FLAGS_MASTER = iota + 1 /* Bridge command to/from master */
BRIDGE_FLAGS_SELF /* Bridge command to/from lowerdev */ BRIDGE_FLAGS_SELF /* Bridge command to/from lowerdev */
) )
/* Bridge management nested attributes /* Bridge management nested attributes

View File

@ -76,12 +76,14 @@ const (
// __CTA_MAX // __CTA_MAX
// }; // };
const ( const (
CTA_TUPLE_ORIG = 1 CTA_TUPLE_ORIG = 1
CTA_TUPLE_REPLY = 2 CTA_TUPLE_REPLY = 2
CTA_STATUS = 3 CTA_STATUS = 3
CTA_TIMEOUT = 8 CTA_TIMEOUT = 7
CTA_MARK = 9 CTA_MARK = 8
CTA_PROTOINFO = 4 CTA_COUNTERS_ORIG = 9
CTA_COUNTERS_REPLY = 10
CTA_PROTOINFO = 4
) )
// enum ctattr_tuple { // enum ctattr_tuple {
@ -163,6 +165,21 @@ const (
CTA_PROTOINFO_TCP_FLAGS_REPLY = 5 CTA_PROTOINFO_TCP_FLAGS_REPLY = 5
) )
// enum ctattr_counters {
// CTA_COUNTERS_UNSPEC,
// CTA_COUNTERS_PACKETS, /* 64bit counters */
// CTA_COUNTERS_BYTES, /* 64bit counters */
// CTA_COUNTERS32_PACKETS, /* old 32bit counters, unused */
// CTA_COUNTERS32_BYTES, /* old 32bit counters, unused */
// CTA_COUNTERS_PAD,
// __CTA_COUNTERS_M
// };
// #define CTA_COUNTERS_MAX (__CTA_COUNTERS_MAX - 1)
const (
CTA_COUNTERS_PACKETS = 1
CTA_COUNTERS_BYTES = 2
)
// /* General form of address family dependent message. // /* General form of address family dependent message.
// */ // */
// struct nfgenmsg { // struct nfgenmsg {

View File

@ -1,35 +1,11 @@
package nl package nl
import ( import (
"syscall"
"unsafe" "unsafe"
) )
const ( const (
DEFAULT_CHANGE = 0xFFFFFFFF DEFAULT_CHANGE = 0xFFFFFFFF
// doesn't exist in syscall
IFLA_VFINFO_LIST = syscall.IFLA_IFALIAS + 1 + iota
IFLA_STATS64
IFLA_VF_PORTS
IFLA_PORT_SELF
IFLA_AF_SPEC
IFLA_GROUP
IFLA_NET_NS_FD
IFLA_EXT_MASK
IFLA_PROMISCUITY
IFLA_NUM_TX_QUEUES
IFLA_NUM_RX_QUEUES
IFLA_CARRIER
IFLA_PHYS_PORT_ID
IFLA_CARRIER_CHANGES
IFLA_PHYS_SWITCH_ID
IFLA_LINK_NETNSID
IFLA_PHYS_PORT_NAME
IFLA_PROTO_DOWN
IFLA_GSO_MAX_SEGS
IFLA_GSO_MAX_SIZE
IFLA_PAD
IFLA_XDP
) )
const ( const (
@ -118,6 +94,10 @@ const (
IFLA_MACVLAN_UNSPEC = iota IFLA_MACVLAN_UNSPEC = iota
IFLA_MACVLAN_MODE IFLA_MACVLAN_MODE
IFLA_MACVLAN_FLAGS IFLA_MACVLAN_FLAGS
IFLA_MACVLAN_MACADDR_MODE
IFLA_MACVLAN_MACADDR
IFLA_MACVLAN_MACADDR_DATA
IFLA_MACVLAN_MACADDR_COUNT
IFLA_MACVLAN_MAX = IFLA_MACVLAN_FLAGS IFLA_MACVLAN_MAX = IFLA_MACVLAN_FLAGS
) )
@ -129,6 +109,13 @@ const (
MACVLAN_MODE_SOURCE = 16 MACVLAN_MODE_SOURCE = 16
) )
const (
MACVLAN_MACADDR_ADD = iota
MACVLAN_MACADDR_DEL
MACVLAN_MACADDR_FLUSH
MACVLAN_MACADDR_SET
)
const ( const (
IFLA_BOND_UNSPEC = iota IFLA_BOND_UNSPEC = iota
IFLA_BOND_MODE IFLA_BOND_MODE
@ -230,8 +217,11 @@ const (
IFLA_VF_RSS_QUERY_EN /* RSS Redirection Table and Hash Key query IFLA_VF_RSS_QUERY_EN /* RSS Redirection Table and Hash Key query
* on/off switch * on/off switch
*/ */
IFLA_VF_STATS /* network device statistics */ IFLA_VF_STATS /* network device statistics */
IFLA_VF_MAX = IFLA_VF_STATS IFLA_VF_TRUST /* Trust state of VF */
IFLA_VF_IB_NODE_GUID /* VF Infiniband node GUID */
IFLA_VF_IB_PORT_GUID /* VF Infiniband port GUID */
IFLA_VF_MAX = IFLA_VF_IB_PORT_GUID
) )
const ( const (
@ -259,6 +249,8 @@ const (
SizeofVfSpoofchk = 0x08 SizeofVfSpoofchk = 0x08
SizeofVfLinkState = 0x08 SizeofVfLinkState = 0x08
SizeofVfRssQueryEn = 0x08 SizeofVfRssQueryEn = 0x08
SizeofVfTrust = 0x08
SizeofVfGUID = 0x10
) )
// struct ifla_vf_mac { // struct ifla_vf_mac {
@ -419,12 +411,66 @@ func (msg *VfRssQueryEn) Serialize() []byte {
return (*(*[SizeofVfRssQueryEn]byte)(unsafe.Pointer(msg)))[:] return (*(*[SizeofVfRssQueryEn]byte)(unsafe.Pointer(msg)))[:]
} }
// struct ifla_vf_trust {
// __u32 vf;
// __u32 setting;
// };
type VfTrust struct {
Vf uint32
Setting uint32
}
func (msg *VfTrust) Len() int {
return SizeofVfTrust
}
func DeserializeVfTrust(b []byte) *VfTrust {
return (*VfTrust)(unsafe.Pointer(&b[0:SizeofVfTrust][0]))
}
func (msg *VfTrust) Serialize() []byte {
return (*(*[SizeofVfTrust]byte)(unsafe.Pointer(msg)))[:]
}
// struct ifla_vf_guid {
// __u32 vf;
// __u32 rsvd;
// __u64 guid;
// };
type VfGUID struct {
Vf uint32
Rsvd uint32
GUID uint64
}
func (msg *VfGUID) Len() int {
return SizeofVfGUID
}
func DeserializeVfGUID(b []byte) *VfGUID {
return (*VfGUID)(unsafe.Pointer(&b[0:SizeofVfGUID][0]))
}
func (msg *VfGUID) Serialize() []byte {
return (*(*[SizeofVfGUID]byte)(unsafe.Pointer(msg)))[:]
}
const (
XDP_FLAGS_UPDATE_IF_NOEXIST = 1 << iota
XDP_FLAGS_SKB_MODE
XDP_FLAGS_DRV_MODE
XDP_FLAGS_MASK = XDP_FLAGS_UPDATE_IF_NOEXIST | XDP_FLAGS_SKB_MODE | XDP_FLAGS_DRV_MODE
)
const ( const (
IFLA_XDP_UNSPEC = iota IFLA_XDP_UNSPEC = iota
IFLA_XDP_FD /* fd of xdp program to attach, or -1 to remove */ IFLA_XDP_FD /* fd of xdp program to attach, or -1 to remove */
IFLA_XDP_ATTACHED /* read-only bool indicating if prog is attached */ IFLA_XDP_ATTACHED /* read-only bool indicating if prog is attached */
IFLA_XDP_FLAGS /* xdp prog related flags */ IFLA_XDP_FLAGS /* xdp prog related flags */
IFLA_XDP_MAX = IFLA_XDP_FLAGS IFLA_XDP_PROG_ID /* xdp prog id */
IFLA_XDP_MAX = IFLA_XDP_PROG_ID
) )
const ( const (
@ -443,7 +489,12 @@ const (
IFLA_IPTUN_6RD_RELAY_PREFIX IFLA_IPTUN_6RD_RELAY_PREFIX
IFLA_IPTUN_6RD_PREFIXLEN IFLA_IPTUN_6RD_PREFIXLEN
IFLA_IPTUN_6RD_RELAY_PREFIXLEN IFLA_IPTUN_6RD_RELAY_PREFIXLEN
IFLA_IPTUN_MAX = IFLA_IPTUN_6RD_RELAY_PREFIXLEN IFLA_IPTUN_ENCAP_TYPE
IFLA_IPTUN_ENCAP_FLAGS
IFLA_IPTUN_ENCAP_SPORT
IFLA_IPTUN_ENCAP_DPORT
IFLA_IPTUN_COLLECT_METADATA
IFLA_IPTUN_MAX = IFLA_IPTUN_COLLECT_METADATA
) )
const ( const (

View File

@ -13,18 +13,23 @@ import (
"unsafe" "unsafe"
"github.com/vishvananda/netns" "github.com/vishvananda/netns"
"golang.org/x/sys/unix"
) )
const ( const (
// Family type definitions // Family type definitions
FAMILY_ALL = syscall.AF_UNSPEC FAMILY_ALL = unix.AF_UNSPEC
FAMILY_V4 = syscall.AF_INET FAMILY_V4 = unix.AF_INET
FAMILY_V6 = syscall.AF_INET6 FAMILY_V6 = unix.AF_INET6
FAMILY_MPLS = AF_MPLS FAMILY_MPLS = AF_MPLS
// Arbitrary set value (greater than default 4k) to allow receiving
// from kernel more verbose messages e.g. for statistics,
// tc rules or filters, or other more memory requiring data.
RECEIVE_BUFFER_SIZE = 65536
) )
// SupportedNlFamilies contains the list of netlink families this netlink package supports // SupportedNlFamilies contains the list of netlink families this netlink package supports
var SupportedNlFamilies = []int{syscall.NETLINK_ROUTE, syscall.NETLINK_XFRM, syscall.NETLINK_NETFILTER} var SupportedNlFamilies = []int{unix.NETLINK_ROUTE, unix.NETLINK_XFRM, unix.NETLINK_NETFILTER}
var nextSeqNr uint32 var nextSeqNr uint32
@ -77,161 +82,161 @@ type NetlinkRequestData interface {
// IfInfomsg is related to links, but it is used for list requests as well // IfInfomsg is related to links, but it is used for list requests as well
type IfInfomsg struct { type IfInfomsg struct {
syscall.IfInfomsg unix.IfInfomsg
} }
// Create an IfInfomsg with family specified // Create an IfInfomsg with family specified
func NewIfInfomsg(family int) *IfInfomsg { func NewIfInfomsg(family int) *IfInfomsg {
return &IfInfomsg{ return &IfInfomsg{
IfInfomsg: syscall.IfInfomsg{ IfInfomsg: unix.IfInfomsg{
Family: uint8(family), Family: uint8(family),
}, },
} }
} }
func DeserializeIfInfomsg(b []byte) *IfInfomsg { func DeserializeIfInfomsg(b []byte) *IfInfomsg {
return (*IfInfomsg)(unsafe.Pointer(&b[0:syscall.SizeofIfInfomsg][0])) return (*IfInfomsg)(unsafe.Pointer(&b[0:unix.SizeofIfInfomsg][0]))
} }
func (msg *IfInfomsg) Serialize() []byte { func (msg *IfInfomsg) Serialize() []byte {
return (*(*[syscall.SizeofIfInfomsg]byte)(unsafe.Pointer(msg)))[:] return (*(*[unix.SizeofIfInfomsg]byte)(unsafe.Pointer(msg)))[:]
} }
func (msg *IfInfomsg) Len() int { func (msg *IfInfomsg) Len() int {
return syscall.SizeofIfInfomsg return unix.SizeofIfInfomsg
} }
func (msg *IfInfomsg) EncapType() string { func (msg *IfInfomsg) EncapType() string {
switch msg.Type { switch msg.Type {
case 0: case 0:
return "generic" return "generic"
case syscall.ARPHRD_ETHER: case unix.ARPHRD_ETHER:
return "ether" return "ether"
case syscall.ARPHRD_EETHER: case unix.ARPHRD_EETHER:
return "eether" return "eether"
case syscall.ARPHRD_AX25: case unix.ARPHRD_AX25:
return "ax25" return "ax25"
case syscall.ARPHRD_PRONET: case unix.ARPHRD_PRONET:
return "pronet" return "pronet"
case syscall.ARPHRD_CHAOS: case unix.ARPHRD_CHAOS:
return "chaos" return "chaos"
case syscall.ARPHRD_IEEE802: case unix.ARPHRD_IEEE802:
return "ieee802" return "ieee802"
case syscall.ARPHRD_ARCNET: case unix.ARPHRD_ARCNET:
return "arcnet" return "arcnet"
case syscall.ARPHRD_APPLETLK: case unix.ARPHRD_APPLETLK:
return "atalk" return "atalk"
case syscall.ARPHRD_DLCI: case unix.ARPHRD_DLCI:
return "dlci" return "dlci"
case syscall.ARPHRD_ATM: case unix.ARPHRD_ATM:
return "atm" return "atm"
case syscall.ARPHRD_METRICOM: case unix.ARPHRD_METRICOM:
return "metricom" return "metricom"
case syscall.ARPHRD_IEEE1394: case unix.ARPHRD_IEEE1394:
return "ieee1394" return "ieee1394"
case syscall.ARPHRD_INFINIBAND: case unix.ARPHRD_INFINIBAND:
return "infiniband" return "infiniband"
case syscall.ARPHRD_SLIP: case unix.ARPHRD_SLIP:
return "slip" return "slip"
case syscall.ARPHRD_CSLIP: case unix.ARPHRD_CSLIP:
return "cslip" return "cslip"
case syscall.ARPHRD_SLIP6: case unix.ARPHRD_SLIP6:
return "slip6" return "slip6"
case syscall.ARPHRD_CSLIP6: case unix.ARPHRD_CSLIP6:
return "cslip6" return "cslip6"
case syscall.ARPHRD_RSRVD: case unix.ARPHRD_RSRVD:
return "rsrvd" return "rsrvd"
case syscall.ARPHRD_ADAPT: case unix.ARPHRD_ADAPT:
return "adapt" return "adapt"
case syscall.ARPHRD_ROSE: case unix.ARPHRD_ROSE:
return "rose" return "rose"
case syscall.ARPHRD_X25: case unix.ARPHRD_X25:
return "x25" return "x25"
case syscall.ARPHRD_HWX25: case unix.ARPHRD_HWX25:
return "hwx25" return "hwx25"
case syscall.ARPHRD_PPP: case unix.ARPHRD_PPP:
return "ppp" return "ppp"
case syscall.ARPHRD_HDLC: case unix.ARPHRD_HDLC:
return "hdlc" return "hdlc"
case syscall.ARPHRD_LAPB: case unix.ARPHRD_LAPB:
return "lapb" return "lapb"
case syscall.ARPHRD_DDCMP: case unix.ARPHRD_DDCMP:
return "ddcmp" return "ddcmp"
case syscall.ARPHRD_RAWHDLC: case unix.ARPHRD_RAWHDLC:
return "rawhdlc" return "rawhdlc"
case syscall.ARPHRD_TUNNEL: case unix.ARPHRD_TUNNEL:
return "ipip" return "ipip"
case syscall.ARPHRD_TUNNEL6: case unix.ARPHRD_TUNNEL6:
return "tunnel6" return "tunnel6"
case syscall.ARPHRD_FRAD: case unix.ARPHRD_FRAD:
return "frad" return "frad"
case syscall.ARPHRD_SKIP: case unix.ARPHRD_SKIP:
return "skip" return "skip"
case syscall.ARPHRD_LOOPBACK: case unix.ARPHRD_LOOPBACK:
return "loopback" return "loopback"
case syscall.ARPHRD_LOCALTLK: case unix.ARPHRD_LOCALTLK:
return "ltalk" return "ltalk"
case syscall.ARPHRD_FDDI: case unix.ARPHRD_FDDI:
return "fddi" return "fddi"
case syscall.ARPHRD_BIF: case unix.ARPHRD_BIF:
return "bif" return "bif"
case syscall.ARPHRD_SIT: case unix.ARPHRD_SIT:
return "sit" return "sit"
case syscall.ARPHRD_IPDDP: case unix.ARPHRD_IPDDP:
return "ip/ddp" return "ip/ddp"
case syscall.ARPHRD_IPGRE: case unix.ARPHRD_IPGRE:
return "gre" return "gre"
case syscall.ARPHRD_PIMREG: case unix.ARPHRD_PIMREG:
return "pimreg" return "pimreg"
case syscall.ARPHRD_HIPPI: case unix.ARPHRD_HIPPI:
return "hippi" return "hippi"
case syscall.ARPHRD_ASH: case unix.ARPHRD_ASH:
return "ash" return "ash"
case syscall.ARPHRD_ECONET: case unix.ARPHRD_ECONET:
return "econet" return "econet"
case syscall.ARPHRD_IRDA: case unix.ARPHRD_IRDA:
return "irda" return "irda"
case syscall.ARPHRD_FCPP: case unix.ARPHRD_FCPP:
return "fcpp" return "fcpp"
case syscall.ARPHRD_FCAL: case unix.ARPHRD_FCAL:
return "fcal" return "fcal"
case syscall.ARPHRD_FCPL: case unix.ARPHRD_FCPL:
return "fcpl" return "fcpl"
case syscall.ARPHRD_FCFABRIC: case unix.ARPHRD_FCFABRIC:
return "fcfb0" return "fcfb0"
case syscall.ARPHRD_FCFABRIC + 1: case unix.ARPHRD_FCFABRIC + 1:
return "fcfb1" return "fcfb1"
case syscall.ARPHRD_FCFABRIC + 2: case unix.ARPHRD_FCFABRIC + 2:
return "fcfb2" return "fcfb2"
case syscall.ARPHRD_FCFABRIC + 3: case unix.ARPHRD_FCFABRIC + 3:
return "fcfb3" return "fcfb3"
case syscall.ARPHRD_FCFABRIC + 4: case unix.ARPHRD_FCFABRIC + 4:
return "fcfb4" return "fcfb4"
case syscall.ARPHRD_FCFABRIC + 5: case unix.ARPHRD_FCFABRIC + 5:
return "fcfb5" return "fcfb5"
case syscall.ARPHRD_FCFABRIC + 6: case unix.ARPHRD_FCFABRIC + 6:
return "fcfb6" return "fcfb6"
case syscall.ARPHRD_FCFABRIC + 7: case unix.ARPHRD_FCFABRIC + 7:
return "fcfb7" return "fcfb7"
case syscall.ARPHRD_FCFABRIC + 8: case unix.ARPHRD_FCFABRIC + 8:
return "fcfb8" return "fcfb8"
case syscall.ARPHRD_FCFABRIC + 9: case unix.ARPHRD_FCFABRIC + 9:
return "fcfb9" return "fcfb9"
case syscall.ARPHRD_FCFABRIC + 10: case unix.ARPHRD_FCFABRIC + 10:
return "fcfb10" return "fcfb10"
case syscall.ARPHRD_FCFABRIC + 11: case unix.ARPHRD_FCFABRIC + 11:
return "fcfb11" return "fcfb11"
case syscall.ARPHRD_FCFABRIC + 12: case unix.ARPHRD_FCFABRIC + 12:
return "fcfb12" return "fcfb12"
case syscall.ARPHRD_IEEE802_TR: case unix.ARPHRD_IEEE802_TR:
return "tr" return "tr"
case syscall.ARPHRD_IEEE80211: case unix.ARPHRD_IEEE80211:
return "ieee802.11" return "ieee802.11"
case syscall.ARPHRD_IEEE80211_PRISM: case unix.ARPHRD_IEEE80211_PRISM:
return "ieee802.11/prism" return "ieee802.11/prism"
case syscall.ARPHRD_IEEE80211_RADIOTAP: case unix.ARPHRD_IEEE80211_RADIOTAP:
return "ieee802.11/radiotap" return "ieee802.11/radiotap"
case syscall.ARPHRD_IEEE802154: case unix.ARPHRD_IEEE802154:
return "ieee802.15.4" return "ieee802.15.4"
case 65534: case 65534:
@ -243,7 +248,7 @@ func (msg *IfInfomsg) EncapType() string {
} }
func rtaAlignOf(attrlen int) int { func rtaAlignOf(attrlen int) int {
return (attrlen + syscall.RTA_ALIGNTO - 1) & ^(syscall.RTA_ALIGNTO - 1) return (attrlen + unix.RTA_ALIGNTO - 1) & ^(unix.RTA_ALIGNTO - 1)
} }
func NewIfInfomsgChild(parent *RtAttr, family int) *IfInfomsg { func NewIfInfomsgChild(parent *RtAttr, family int) *IfInfomsg {
@ -254,7 +259,7 @@ func NewIfInfomsgChild(parent *RtAttr, family int) *IfInfomsg {
// Extend RtAttr to handle data and children // Extend RtAttr to handle data and children
type RtAttr struct { type RtAttr struct {
syscall.RtAttr unix.RtAttr
Data []byte Data []byte
children []NetlinkRequestData children []NetlinkRequestData
} }
@ -262,7 +267,7 @@ type RtAttr struct {
// Create a new Extended RtAttr object // Create a new Extended RtAttr object
func NewRtAttr(attrType int, data []byte) *RtAttr { func NewRtAttr(attrType int, data []byte) *RtAttr {
return &RtAttr{ return &RtAttr{
RtAttr: syscall.RtAttr{ RtAttr: unix.RtAttr{
Type: uint16(attrType), Type: uint16(attrType),
}, },
children: []NetlinkRequestData{}, children: []NetlinkRequestData{},
@ -270,23 +275,35 @@ func NewRtAttr(attrType int, data []byte) *RtAttr {
} }
} }
// Create a new RtAttr obj anc add it as a child of an existing object // NewRtAttrChild adds an RtAttr as a child to the parent and returns the new attribute
//
// Deprecated: Use AddRtAttr() on the parent object
func NewRtAttrChild(parent *RtAttr, attrType int, data []byte) *RtAttr { func NewRtAttrChild(parent *RtAttr, attrType int, data []byte) *RtAttr {
return parent.AddRtAttr(attrType, data)
}
// AddRtAttr adds an RtAttr as a child and returns the new attribute
func (a *RtAttr) AddRtAttr(attrType int, data []byte) *RtAttr {
attr := NewRtAttr(attrType, data) attr := NewRtAttr(attrType, data)
parent.children = append(parent.children, attr) a.children = append(a.children, attr)
return attr return attr
} }
// AddChild adds an existing NetlinkRequestData as a child.
func (a *RtAttr) AddChild(attr NetlinkRequestData) {
a.children = append(a.children, attr)
}
func (a *RtAttr) Len() int { func (a *RtAttr) Len() int {
if len(a.children) == 0 { if len(a.children) == 0 {
return (syscall.SizeofRtAttr + len(a.Data)) return (unix.SizeofRtAttr + len(a.Data))
} }
l := 0 l := 0
for _, child := range a.children { for _, child := range a.children {
l += rtaAlignOf(child.Len()) l += rtaAlignOf(child.Len())
} }
l += syscall.SizeofRtAttr l += unix.SizeofRtAttr
return rtaAlignOf(l + len(a.Data)) return rtaAlignOf(l + len(a.Data))
} }
@ -319,7 +336,7 @@ func (a *RtAttr) Serialize() []byte {
} }
type NetlinkRequest struct { type NetlinkRequest struct {
syscall.NlMsghdr unix.NlMsghdr
Data []NetlinkRequestData Data []NetlinkRequestData
RawData []byte RawData []byte
Sockets map[int]*SocketHandle Sockets map[int]*SocketHandle
@ -327,7 +344,7 @@ type NetlinkRequest struct {
// Serialize the Netlink Request into a byte array // Serialize the Netlink Request into a byte array
func (req *NetlinkRequest) Serialize() []byte { func (req *NetlinkRequest) Serialize() []byte {
length := syscall.SizeofNlMsghdr length := unix.SizeofNlMsghdr
dataBytes := make([][]byte, len(req.Data)) dataBytes := make([][]byte, len(req.Data))
for i, data := range req.Data { for i, data := range req.Data {
dataBytes[i] = data.Serialize() dataBytes[i] = data.Serialize()
@ -337,8 +354,8 @@ func (req *NetlinkRequest) Serialize() []byte {
req.Len = uint32(length) req.Len = uint32(length)
b := make([]byte, length) b := make([]byte, length)
hdr := (*(*[syscall.SizeofNlMsghdr]byte)(unsafe.Pointer(req)))[:] hdr := (*(*[unix.SizeofNlMsghdr]byte)(unsafe.Pointer(req)))[:]
next := syscall.SizeofNlMsghdr next := unix.SizeofNlMsghdr
copy(b[0:next], hdr) copy(b[0:next], hdr)
for _, data := range dataBytes { for _, data := range dataBytes {
for _, dataByte := range data { for _, dataByte := range data {
@ -354,16 +371,12 @@ func (req *NetlinkRequest) Serialize() []byte {
} }
func (req *NetlinkRequest) AddData(data NetlinkRequestData) { func (req *NetlinkRequest) AddData(data NetlinkRequestData) {
if data != nil { req.Data = append(req.Data, data)
req.Data = append(req.Data, data)
}
} }
// AddRawData adds raw bytes to the end of the NetlinkRequest object during serialization // AddRawData adds raw bytes to the end of the NetlinkRequest object during serialization
func (req *NetlinkRequest) AddRawData(data []byte) { func (req *NetlinkRequest) AddRawData(data []byte) {
if data != nil { req.RawData = append(req.RawData, data...)
req.RawData = append(req.RawData, data...)
}
} }
// Execute the request against a the given sockType. // Execute the request against a the given sockType.
@ -421,10 +434,10 @@ done:
if m.Header.Pid != pid { if m.Header.Pid != pid {
return nil, fmt.Errorf("Wrong pid %d, expected %d", m.Header.Pid, pid) return nil, fmt.Errorf("Wrong pid %d, expected %d", m.Header.Pid, pid)
} }
if m.Header.Type == syscall.NLMSG_DONE { if m.Header.Type == unix.NLMSG_DONE {
break done break done
} }
if m.Header.Type == syscall.NLMSG_ERROR { if m.Header.Type == unix.NLMSG_ERROR {
native := NativeEndian() native := NativeEndian()
error := int32(native.Uint32(m.Data[0:4])) error := int32(native.Uint32(m.Data[0:4]))
if error == 0 { if error == 0 {
@ -436,7 +449,7 @@ done:
continue continue
} }
res = append(res, m.Data) res = append(res, m.Data)
if m.Header.Flags&syscall.NLM_F_MULTI == 0 { if m.Header.Flags&unix.NLM_F_MULTI == 0 {
break done break done
} }
} }
@ -449,10 +462,10 @@ done:
// the message is serialized // the message is serialized
func NewNetlinkRequest(proto, flags int) *NetlinkRequest { func NewNetlinkRequest(proto, flags int) *NetlinkRequest {
return &NetlinkRequest{ return &NetlinkRequest{
NlMsghdr: syscall.NlMsghdr{ NlMsghdr: unix.NlMsghdr{
Len: uint32(syscall.SizeofNlMsghdr), Len: uint32(unix.SizeofNlMsghdr),
Type: uint16(proto), Type: uint16(proto),
Flags: syscall.NLM_F_REQUEST | uint16(flags), Flags: unix.NLM_F_REQUEST | uint16(flags),
Seq: atomic.AddUint32(&nextSeqNr, 1), Seq: atomic.AddUint32(&nextSeqNr, 1),
}, },
} }
@ -460,21 +473,21 @@ func NewNetlinkRequest(proto, flags int) *NetlinkRequest {
type NetlinkSocket struct { type NetlinkSocket struct {
fd int32 fd int32
lsa syscall.SockaddrNetlink lsa unix.SockaddrNetlink
sync.Mutex sync.Mutex
} }
func getNetlinkSocket(protocol int) (*NetlinkSocket, error) { func getNetlinkSocket(protocol int) (*NetlinkSocket, error) {
fd, err := syscall.Socket(syscall.AF_NETLINK, syscall.SOCK_RAW|syscall.SOCK_CLOEXEC, protocol) fd, err := unix.Socket(unix.AF_NETLINK, unix.SOCK_RAW|unix.SOCK_CLOEXEC, protocol)
if err != nil { if err != nil {
return nil, err return nil, err
} }
s := &NetlinkSocket{ s := &NetlinkSocket{
fd: int32(fd), fd: int32(fd),
} }
s.lsa.Family = syscall.AF_NETLINK s.lsa.Family = unix.AF_NETLINK
if err := syscall.Bind(fd, &s.lsa); err != nil { if err := unix.Bind(fd, &s.lsa); err != nil {
syscall.Close(fd) unix.Close(fd)
return nil, err return nil, err
} }
@ -551,21 +564,21 @@ func executeInNetns(newNs, curNs netns.NsHandle) (func(), error) {
// Returns the netlink socket on which Receive() method can be called // Returns the netlink socket on which Receive() method can be called
// to retrieve the messages from the kernel. // to retrieve the messages from the kernel.
func Subscribe(protocol int, groups ...uint) (*NetlinkSocket, error) { func Subscribe(protocol int, groups ...uint) (*NetlinkSocket, error) {
fd, err := syscall.Socket(syscall.AF_NETLINK, syscall.SOCK_RAW, protocol) fd, err := unix.Socket(unix.AF_NETLINK, unix.SOCK_RAW, protocol)
if err != nil { if err != nil {
return nil, err return nil, err
} }
s := &NetlinkSocket{ s := &NetlinkSocket{
fd: int32(fd), fd: int32(fd),
} }
s.lsa.Family = syscall.AF_NETLINK s.lsa.Family = unix.AF_NETLINK
for _, g := range groups { for _, g := range groups {
s.lsa.Groups |= (1 << (g - 1)) s.lsa.Groups |= (1 << (g - 1))
} }
if err := syscall.Bind(fd, &s.lsa); err != nil { if err := unix.Bind(fd, &s.lsa); err != nil {
syscall.Close(fd) unix.Close(fd)
return nil, err return nil, err
} }
@ -586,7 +599,7 @@ func SubscribeAt(newNs, curNs netns.NsHandle, protocol int, groups ...uint) (*Ne
func (s *NetlinkSocket) Close() { func (s *NetlinkSocket) Close() {
fd := int(atomic.SwapInt32(&s.fd, -1)) fd := int(atomic.SwapInt32(&s.fd, -1))
syscall.Close(fd) unix.Close(fd)
} }
func (s *NetlinkSocket) GetFd() int { func (s *NetlinkSocket) GetFd() int {
@ -598,7 +611,7 @@ func (s *NetlinkSocket) Send(request *NetlinkRequest) error {
if fd < 0 { if fd < 0 {
return fmt.Errorf("Send called on a closed socket") return fmt.Errorf("Send called on a closed socket")
} }
if err := syscall.Sendto(fd, request.Serialize(), 0, &s.lsa); err != nil { if err := unix.Sendto(fd, request.Serialize(), 0, &s.lsa); err != nil {
return err return err
} }
return nil return nil
@ -609,26 +622,40 @@ func (s *NetlinkSocket) Receive() ([]syscall.NetlinkMessage, error) {
if fd < 0 { if fd < 0 {
return nil, fmt.Errorf("Receive called on a closed socket") return nil, fmt.Errorf("Receive called on a closed socket")
} }
rb := make([]byte, syscall.Getpagesize()) rb := make([]byte, RECEIVE_BUFFER_SIZE)
nr, _, err := syscall.Recvfrom(fd, rb, 0) nr, _, err := unix.Recvfrom(fd, rb, 0)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if nr < syscall.NLMSG_HDRLEN { if nr < unix.NLMSG_HDRLEN {
return nil, fmt.Errorf("Got short response from netlink") return nil, fmt.Errorf("Got short response from netlink")
} }
rb = rb[:nr] rb = rb[:nr]
return syscall.ParseNetlinkMessage(rb) return syscall.ParseNetlinkMessage(rb)
} }
// SetSendTimeout allows to set a send timeout on the socket
func (s *NetlinkSocket) SetSendTimeout(timeout *unix.Timeval) error {
// Set a send timeout of SOCKET_SEND_TIMEOUT, this will allow the Send to periodically unblock and avoid that a routine
// remains stuck on a send on a closed fd
return unix.SetsockoptTimeval(int(s.fd), unix.SOL_SOCKET, unix.SO_SNDTIMEO, timeout)
}
// SetReceiveTimeout allows to set a receive timeout on the socket
func (s *NetlinkSocket) SetReceiveTimeout(timeout *unix.Timeval) error {
// Set a read timeout of SOCKET_READ_TIMEOUT, this will allow the Read to periodically unblock and avoid that a routine
// remains stuck on a recvmsg on a closed fd
return unix.SetsockoptTimeval(int(s.fd), unix.SOL_SOCKET, unix.SO_RCVTIMEO, timeout)
}
func (s *NetlinkSocket) GetPid() (uint32, error) { func (s *NetlinkSocket) GetPid() (uint32, error) {
fd := int(atomic.LoadInt32(&s.fd)) fd := int(atomic.LoadInt32(&s.fd))
lsa, err := syscall.Getsockname(fd) lsa, err := unix.Getsockname(fd)
if err != nil { if err != nil {
return 0, err return 0, err
} }
switch v := lsa.(type) { switch v := lsa.(type) {
case *syscall.SockaddrNetlink: case *unix.SockaddrNetlink:
return v.Pid, nil return v.Pid, nil
} }
return 0, fmt.Errorf("Wrong socket type") return 0, fmt.Errorf("Wrong socket type")
@ -683,24 +710,24 @@ func Uint64Attr(v uint64) []byte {
func ParseRouteAttr(b []byte) ([]syscall.NetlinkRouteAttr, error) { func ParseRouteAttr(b []byte) ([]syscall.NetlinkRouteAttr, error) {
var attrs []syscall.NetlinkRouteAttr var attrs []syscall.NetlinkRouteAttr
for len(b) >= syscall.SizeofRtAttr { for len(b) >= unix.SizeofRtAttr {
a, vbuf, alen, err := netlinkRouteAttrAndValue(b) a, vbuf, alen, err := netlinkRouteAttrAndValue(b)
if err != nil { if err != nil {
return nil, err return nil, err
} }
ra := syscall.NetlinkRouteAttr{Attr: *a, Value: vbuf[:int(a.Len)-syscall.SizeofRtAttr]} ra := syscall.NetlinkRouteAttr{Attr: syscall.RtAttr(*a), Value: vbuf[:int(a.Len)-unix.SizeofRtAttr]}
attrs = append(attrs, ra) attrs = append(attrs, ra)
b = b[alen:] b = b[alen:]
} }
return attrs, nil return attrs, nil
} }
func netlinkRouteAttrAndValue(b []byte) (*syscall.RtAttr, []byte, int, error) { func netlinkRouteAttrAndValue(b []byte) (*unix.RtAttr, []byte, int, error) {
a := (*syscall.RtAttr)(unsafe.Pointer(&b[0])) a := (*unix.RtAttr)(unsafe.Pointer(&b[0]))
if int(a.Len) < syscall.SizeofRtAttr || int(a.Len) > len(b) { if int(a.Len) < unix.SizeofRtAttr || int(a.Len) > len(b) {
return nil, nil, 0, syscall.EINVAL return nil, nil, 0, unix.EINVAL
} }
return a, b[syscall.SizeofRtAttr:], rtaAlignOf(int(a.Len)), nil return a, b[unix.SizeofRtAttr:], rtaAlignOf(int(a.Len)), nil
} }
// SocketHandle contains the netlink socket and the associated // SocketHandle contains the netlink socket and the associated

View File

@ -0,0 +1,31 @@
package nl
const (
RDMA_NL_GET_CLIENT_SHIFT = 10
)
const (
RDMA_NL_NLDEV = 5
)
const (
RDMA_NLDEV_CMD_GET = 1
RDMA_NLDEV_CMD_SET = 2
)
const (
RDMA_NLDEV_ATTR_DEV_INDEX = 1
RDMA_NLDEV_ATTR_DEV_NAME = 2
RDMA_NLDEV_ATTR_PORT_INDEX = 3
RDMA_NLDEV_ATTR_CAP_FLAGS = 4
RDMA_NLDEV_ATTR_FW_VERSION = 5
RDMA_NLDEV_ATTR_NODE_GUID = 6
RDMA_NLDEV_ATTR_SYS_IMAGE_GUID = 7
RDMA_NLDEV_ATTR_SUBNET_PREFIX = 8
RDMA_NLDEV_ATTR_LID = 9
RDMA_NLDEV_ATTR_SM_LID = 10
RDMA_NLDEV_ATTR_LMC = 11
RDMA_NLDEV_ATTR_PORT_STATE = 12
RDMA_NLDEV_ATTR_PORT_PHYS_STATE = 13
RDMA_NLDEV_ATTR_DEV_NODE_TYPE = 14
)

View File

@ -1,65 +1,66 @@
package nl package nl
import ( import (
"syscall"
"unsafe" "unsafe"
"golang.org/x/sys/unix"
) )
type RtMsg struct { type RtMsg struct {
syscall.RtMsg unix.RtMsg
} }
func NewRtMsg() *RtMsg { func NewRtMsg() *RtMsg {
return &RtMsg{ return &RtMsg{
RtMsg: syscall.RtMsg{ RtMsg: unix.RtMsg{
Table: syscall.RT_TABLE_MAIN, Table: unix.RT_TABLE_MAIN,
Scope: syscall.RT_SCOPE_UNIVERSE, Scope: unix.RT_SCOPE_UNIVERSE,
Protocol: syscall.RTPROT_BOOT, Protocol: unix.RTPROT_BOOT,
Type: syscall.RTN_UNICAST, Type: unix.RTN_UNICAST,
}, },
} }
} }
func NewRtDelMsg() *RtMsg { func NewRtDelMsg() *RtMsg {
return &RtMsg{ return &RtMsg{
RtMsg: syscall.RtMsg{ RtMsg: unix.RtMsg{
Table: syscall.RT_TABLE_MAIN, Table: unix.RT_TABLE_MAIN,
Scope: syscall.RT_SCOPE_NOWHERE, Scope: unix.RT_SCOPE_NOWHERE,
}, },
} }
} }
func (msg *RtMsg) Len() int { func (msg *RtMsg) Len() int {
return syscall.SizeofRtMsg return unix.SizeofRtMsg
} }
func DeserializeRtMsg(b []byte) *RtMsg { func DeserializeRtMsg(b []byte) *RtMsg {
return (*RtMsg)(unsafe.Pointer(&b[0:syscall.SizeofRtMsg][0])) return (*RtMsg)(unsafe.Pointer(&b[0:unix.SizeofRtMsg][0]))
} }
func (msg *RtMsg) Serialize() []byte { func (msg *RtMsg) Serialize() []byte {
return (*(*[syscall.SizeofRtMsg]byte)(unsafe.Pointer(msg)))[:] return (*(*[unix.SizeofRtMsg]byte)(unsafe.Pointer(msg)))[:]
} }
type RtNexthop struct { type RtNexthop struct {
syscall.RtNexthop unix.RtNexthop
Children []NetlinkRequestData Children []NetlinkRequestData
} }
func DeserializeRtNexthop(b []byte) *RtNexthop { func DeserializeRtNexthop(b []byte) *RtNexthop {
return (*RtNexthop)(unsafe.Pointer(&b[0:syscall.SizeofRtNexthop][0])) return (*RtNexthop)(unsafe.Pointer(&b[0:unix.SizeofRtNexthop][0]))
} }
func (msg *RtNexthop) Len() int { func (msg *RtNexthop) Len() int {
if len(msg.Children) == 0 { if len(msg.Children) == 0 {
return syscall.SizeofRtNexthop return unix.SizeofRtNexthop
} }
l := 0 l := 0
for _, child := range msg.Children { for _, child := range msg.Children {
l += rtaAlignOf(child.Len()) l += rtaAlignOf(child.Len())
} }
l += syscall.SizeofRtNexthop l += unix.SizeofRtNexthop
return rtaAlignOf(l) return rtaAlignOf(l)
} }
@ -67,8 +68,8 @@ func (msg *RtNexthop) Serialize() []byte {
length := msg.Len() length := msg.Len()
msg.RtNexthop.Len = uint16(length) msg.RtNexthop.Len = uint16(length)
buf := make([]byte, length) buf := make([]byte, length)
copy(buf, (*(*[syscall.SizeofRtNexthop]byte)(unsafe.Pointer(msg)))[:]) copy(buf, (*(*[unix.SizeofRtNexthop]byte)(unsafe.Pointer(msg)))[:])
next := rtaAlignOf(syscall.SizeofRtNexthop) next := rtaAlignOf(unix.SizeofRtNexthop)
if len(msg.Children) > 0 { if len(msg.Children) > 0 {
for _, child := range msg.Children { for _, child := range msg.Children {
childBuf := child.Serialize() childBuf := child.Serialize()
@ -78,3 +79,29 @@ func (msg *RtNexthop) Serialize() []byte {
} }
return buf return buf
} }
type RtGenMsg struct {
unix.RtGenmsg
}
func NewRtGenMsg() *RtGenMsg {
return &RtGenMsg{
RtGenmsg: unix.RtGenmsg{
Family: unix.AF_UNSPEC,
},
}
}
func (msg *RtGenMsg) Len() int {
return rtaAlignOf(unix.SizeofRtGenmsg)
}
func DeserializeRtGenMsg(b []byte) *RtGenMsg {
return &RtGenMsg{RtGenmsg: unix.RtGenmsg{Family: b[0]}}
}
func (msg *RtGenMsg) Serialize() []byte {
out := make([]byte, msg.Len())
out[0] = msg.Family
return out
}

154
vendor/github.com/vishvananda/netlink/nl/seg6_linux.go generated vendored Normal file
View File

@ -0,0 +1,154 @@
package nl
import (
"errors"
"fmt"
"net"
)
type IPv6SrHdr struct {
nextHdr uint8
hdrLen uint8
routingType uint8
segmentsLeft uint8
firstSegment uint8
flags uint8
reserved uint16
Segments []net.IP
}
func (s1 *IPv6SrHdr) Equal(s2 IPv6SrHdr) bool {
if len(s1.Segments) != len(s2.Segments) {
return false
}
for i := range s1.Segments {
if s1.Segments[i].Equal(s2.Segments[i]) != true {
return false
}
}
return s1.nextHdr == s2.nextHdr &&
s1.hdrLen == s2.hdrLen &&
s1.routingType == s2.routingType &&
s1.segmentsLeft == s2.segmentsLeft &&
s1.firstSegment == s2.firstSegment &&
s1.flags == s2.flags
// reserved doesn't need to be identical.
}
// seg6 encap mode
const (
SEG6_IPTUN_MODE_INLINE = iota
SEG6_IPTUN_MODE_ENCAP
)
// number of nested RTATTR
// from include/uapi/linux/seg6_iptunnel.h
const (
SEG6_IPTUNNEL_UNSPEC = iota
SEG6_IPTUNNEL_SRH
__SEG6_IPTUNNEL_MAX
)
const (
SEG6_IPTUNNEL_MAX = __SEG6_IPTUNNEL_MAX - 1
)
func EncodeSEG6Encap(mode int, segments []net.IP) ([]byte, error) {
nsegs := len(segments) // nsegs: number of segments
if nsegs == 0 {
return nil, errors.New("EncodeSEG6Encap: No Segment in srh")
}
b := make([]byte, 12, 12+len(segments)*16)
native := NativeEndian()
native.PutUint32(b, uint32(mode))
b[4] = 0 // srh.nextHdr (0 when calling netlink)
b[5] = uint8(16 * nsegs >> 3) // srh.hdrLen (in 8-octets unit)
b[6] = IPV6_SRCRT_TYPE_4 // srh.routingType (assigned by IANA)
b[7] = uint8(nsegs - 1) // srh.segmentsLeft
b[8] = uint8(nsegs - 1) // srh.firstSegment
b[9] = 0 // srh.flags (SR6_FLAG1_HMAC for srh_hmac)
// srh.reserved: Defined as "Tag" in draft-ietf-6man-segment-routing-header-07
native.PutUint16(b[10:], 0) // srh.reserved
for _, netIP := range segments {
b = append(b, netIP...) // srh.Segments
}
return b, nil
}
func DecodeSEG6Encap(buf []byte) (int, []net.IP, error) {
native := NativeEndian()
mode := int(native.Uint32(buf))
srh := IPv6SrHdr{
nextHdr: buf[4],
hdrLen: buf[5],
routingType: buf[6],
segmentsLeft: buf[7],
firstSegment: buf[8],
flags: buf[9],
reserved: native.Uint16(buf[10:12]),
}
buf = buf[12:]
if len(buf)%16 != 0 {
err := fmt.Errorf("DecodeSEG6Encap: error parsing Segment List (buf len: %d)\n", len(buf))
return mode, nil, err
}
for len(buf) > 0 {
srh.Segments = append(srh.Segments, net.IP(buf[:16]))
buf = buf[16:]
}
return mode, srh.Segments, nil
}
func DecodeSEG6Srh(buf []byte) ([]net.IP, error) {
native := NativeEndian()
srh := IPv6SrHdr{
nextHdr: buf[0],
hdrLen: buf[1],
routingType: buf[2],
segmentsLeft: buf[3],
firstSegment: buf[4],
flags: buf[5],
reserved: native.Uint16(buf[6:8]),
}
buf = buf[8:]
if len(buf)%16 != 0 {
err := fmt.Errorf("DecodeSEG6Srh: error parsing Segment List (buf len: %d)", len(buf))
return nil, err
}
for len(buf) > 0 {
srh.Segments = append(srh.Segments, net.IP(buf[:16]))
buf = buf[16:]
}
return srh.Segments, nil
}
func EncodeSEG6Srh(segments []net.IP) ([]byte, error) {
nsegs := len(segments) // nsegs: number of segments
if nsegs == 0 {
return nil, errors.New("EncodeSEG6Srh: No Segments")
}
b := make([]byte, 8, 8+len(segments)*16)
native := NativeEndian()
b[0] = 0 // srh.nextHdr (0 when calling netlink)
b[1] = uint8(16 * nsegs >> 3) // srh.hdrLen (in 8-octets unit)
b[2] = IPV6_SRCRT_TYPE_4 // srh.routingType (assigned by IANA)
b[3] = uint8(nsegs - 1) // srh.segmentsLeft
b[4] = uint8(nsegs - 1) // srh.firstSegment
b[5] = 0 // srh.flags (SR6_FLAG1_HMAC for srh_hmac)
// srh.reserved: Defined as "Tag" in draft-ietf-6man-segment-routing-header-07
native.PutUint16(b[6:], 0) // srh.reserved
for _, netIP := range segments {
b = append(b, netIP...) // srh.Segments
}
return b, nil
}
// Helper functions
func SEG6EncapModeString(mode int) string {
switch mode {
case SEG6_IPTUN_MODE_INLINE:
return "inline"
case SEG6_IPTUN_MODE_ENCAP:
return "encap"
}
return "unknown"
}

View File

@ -0,0 +1,76 @@
package nl
import ()
// seg6local parameters
const (
SEG6_LOCAL_UNSPEC = iota
SEG6_LOCAL_ACTION
SEG6_LOCAL_SRH
SEG6_LOCAL_TABLE
SEG6_LOCAL_NH4
SEG6_LOCAL_NH6
SEG6_LOCAL_IIF
SEG6_LOCAL_OIF
__SEG6_LOCAL_MAX
)
const (
SEG6_LOCAL_MAX = __SEG6_LOCAL_MAX
)
// seg6local actions
const (
SEG6_LOCAL_ACTION_END = iota + 1 // 1
SEG6_LOCAL_ACTION_END_X // 2
SEG6_LOCAL_ACTION_END_T // 3
SEG6_LOCAL_ACTION_END_DX2 // 4
SEG6_LOCAL_ACTION_END_DX6 // 5
SEG6_LOCAL_ACTION_END_DX4 // 6
SEG6_LOCAL_ACTION_END_DT6 // 7
SEG6_LOCAL_ACTION_END_DT4 // 8
SEG6_LOCAL_ACTION_END_B6 // 9
SEG6_LOCAL_ACTION_END_B6_ENCAPS // 10
SEG6_LOCAL_ACTION_END_BM // 11
SEG6_LOCAL_ACTION_END_S // 12
SEG6_LOCAL_ACTION_END_AS // 13
SEG6_LOCAL_ACTION_END_AM // 14
__SEG6_LOCAL_ACTION_MAX
)
const (
SEG6_LOCAL_ACTION_MAX = __SEG6_LOCAL_ACTION_MAX - 1
)
// Helper functions
func SEG6LocalActionString(action int) string {
switch action {
case SEG6_LOCAL_ACTION_END:
return "End"
case SEG6_LOCAL_ACTION_END_X:
return "End.X"
case SEG6_LOCAL_ACTION_END_T:
return "End.T"
case SEG6_LOCAL_ACTION_END_DX2:
return "End.DX2"
case SEG6_LOCAL_ACTION_END_DX6:
return "End.DX6"
case SEG6_LOCAL_ACTION_END_DX4:
return "End.DX4"
case SEG6_LOCAL_ACTION_END_DT6:
return "End.DT6"
case SEG6_LOCAL_ACTION_END_DT4:
return "End.DT4"
case SEG6_LOCAL_ACTION_END_B6:
return "End.B6"
case SEG6_LOCAL_ACTION_END_B6_ENCAPS:
return "End.B6.Encaps"
case SEG6_LOCAL_ACTION_END_BM:
return "End.BM"
case SEG6_LOCAL_ACTION_END_S:
return "End.S"
case SEG6_LOCAL_ACTION_END_AS:
return "End.AS"
case SEG6_LOCAL_ACTION_END_AM:
return "End.AM"
}
return "unknown"
}

View File

@ -65,4 +65,15 @@ const (
LWTUNNEL_ENCAP_IP LWTUNNEL_ENCAP_IP
LWTUNNEL_ENCAP_ILA LWTUNNEL_ENCAP_ILA
LWTUNNEL_ENCAP_IP6 LWTUNNEL_ENCAP_IP6
LWTUNNEL_ENCAP_SEG6
LWTUNNEL_ENCAP_BPF
LWTUNNEL_ENCAP_SEG6_LOCAL
)
// routing header types
const (
IPV6_SRCRT_STRICT = 0x01 // Deprecated; will be removed
IPV6_SRCRT_TYPE_0 = 0 // Deprecated; will be removed
IPV6_SRCRT_TYPE_2 = 2 // IPv6 type 2 Routing Header
IPV6_SRCRT_TYPE_4 = 4 // Segment Routing with IPv6
) )

View File

@ -1,6 +1,7 @@
package nl package nl
import ( import (
"encoding/binary"
"unsafe" "unsafe"
) )
@ -64,6 +65,15 @@ const (
TCA_PRIO_MAX = TCA_PRIO_MQ TCA_PRIO_MAX = TCA_PRIO_MQ
) )
const (
TCA_STATS_UNSPEC = iota
TCA_STATS_BASIC
TCA_STATS_RATE_EST
TCA_STATS_QUEUE
TCA_STATS_APP
TCA_STATS_MAX = TCA_STATS_APP
)
const ( const (
SizeofTcMsg = 0x14 SizeofTcMsg = 0x14
SizeofTcActionMsg = 0x04 SizeofTcActionMsg = 0x04
@ -412,6 +422,57 @@ func (x *TcHtbGlob) Serialize() []byte {
return (*(*[SizeofTcHtbGlob]byte)(unsafe.Pointer(x)))[:] return (*(*[SizeofTcHtbGlob]byte)(unsafe.Pointer(x)))[:]
} }
// HFSC
type Curve struct {
m1 uint32
d uint32
m2 uint32
}
type HfscCopt struct {
Rsc Curve
Fsc Curve
Usc Curve
}
func (c *Curve) Attrs() (uint32, uint32, uint32) {
return c.m1, c.d, c.m2
}
func (c *Curve) Set(m1 uint32, d uint32, m2 uint32) {
c.m1 = m1
c.d = d
c.m2 = m2
}
func DeserializeHfscCurve(b []byte) *Curve {
return &Curve{
m1: binary.LittleEndian.Uint32(b[0:4]),
d: binary.LittleEndian.Uint32(b[4:8]),
m2: binary.LittleEndian.Uint32(b[8:12]),
}
}
func SerializeHfscCurve(c *Curve) (b []byte) {
t := make([]byte, binary.MaxVarintLen32)
binary.LittleEndian.PutUint32(t, c.m1)
b = append(b, t[:4]...)
binary.LittleEndian.PutUint32(t, c.d)
b = append(b, t[:4]...)
binary.LittleEndian.PutUint32(t, c.m2)
b = append(b, t[:4]...)
return b
}
type TcHfscOpt struct {
Defcls uint16
}
func (x *TcHfscOpt) Serialize() []byte {
return (*(*[2]byte)(unsafe.Pointer(x)))[:]
}
const ( const (
TCA_U32_UNSPEC = iota TCA_U32_UNSPEC = iota
TCA_U32_CLASSID TCA_U32_CLASSID
@ -673,3 +734,45 @@ const (
TCA_FW_MASK TCA_FW_MASK
TCA_FW_MAX = TCA_FW_MASK TCA_FW_MAX = TCA_FW_MASK
) )
const (
TCA_MATCHALL_UNSPEC = iota
TCA_MATCHALL_CLASSID
TCA_MATCHALL_ACT
TCA_MATCHALL_FLAGS
)
const (
TCA_FQ_UNSPEC = iota
TCA_FQ_PLIMIT // limit of total number of packets in queue
TCA_FQ_FLOW_PLIMIT // limit of packets per flow
TCA_FQ_QUANTUM // RR quantum
TCA_FQ_INITIAL_QUANTUM // RR quantum for new flow
TCA_FQ_RATE_ENABLE // enable/disable rate limiting
TCA_FQ_FLOW_DEFAULT_RATE // obsolete do not use
TCA_FQ_FLOW_MAX_RATE // per flow max rate
TCA_FQ_BUCKETS_LOG // log2(number of buckets)
TCA_FQ_FLOW_REFILL_DELAY // flow credit refill delay in usec
TCA_FQ_ORPHAN_MASK // mask applied to orphaned skb hashes
TCA_FQ_LOW_RATE_THRESHOLD // per packet delay under this rate
)
const (
TCA_FQ_CODEL_UNSPEC = iota
TCA_FQ_CODEL_TARGET
TCA_FQ_CODEL_LIMIT
TCA_FQ_CODEL_INTERVAL
TCA_FQ_CODEL_ECN
TCA_FQ_CODEL_FLOWS
TCA_FQ_CODEL_QUANTUM
TCA_FQ_CODEL_CE_THRESHOLD
TCA_FQ_CODEL_DROP_BATCH_SIZE
TCA_FQ_CODEL_MEMORY_LIMIT
)
const (
TCA_HFSC_UNSPEC = iota
TCA_HFSC_RSC
TCA_HFSC_FSC
TCA_HFSC_USC
)

View File

@ -18,6 +18,10 @@ type Protinfo struct {
// String returns a list of enabled flags // String returns a list of enabled flags
func (prot *Protinfo) String() string { func (prot *Protinfo) String() string {
if prot == nil {
return "<nil>"
}
var boolStrings []string var boolStrings []string
if prot.Hairpin { if prot.Hairpin {
boolStrings = append(boolStrings, "Hairpin") boolStrings = append(boolStrings, "Hairpin")

View File

@ -5,6 +5,7 @@ import (
"syscall" "syscall"
"github.com/vishvananda/netlink/nl" "github.com/vishvananda/netlink/nl"
"golang.org/x/sys/unix"
) )
func LinkGetProtinfo(link Link) (Protinfo, error) { func LinkGetProtinfo(link Link) (Protinfo, error) {
@ -15,10 +16,10 @@ func (h *Handle) LinkGetProtinfo(link Link) (Protinfo, error) {
base := link.Attrs() base := link.Attrs()
h.ensureIndex(base) h.ensureIndex(base)
var pi Protinfo var pi Protinfo
req := h.newNetlinkRequest(syscall.RTM_GETLINK, syscall.NLM_F_DUMP) req := h.newNetlinkRequest(unix.RTM_GETLINK, unix.NLM_F_DUMP)
msg := nl.NewIfInfomsg(syscall.AF_BRIDGE) msg := nl.NewIfInfomsg(unix.AF_BRIDGE)
req.AddData(msg) req.AddData(msg)
msgs, err := req.Execute(syscall.NETLINK_ROUTE, 0) msgs, err := req.Execute(unix.NETLINK_ROUTE, 0)
if err != nil { if err != nil {
return pi, err return pi, err
} }
@ -33,14 +34,14 @@ func (h *Handle) LinkGetProtinfo(link Link) (Protinfo, error) {
return pi, err return pi, err
} }
for _, attr := range attrs { for _, attr := range attrs {
if attr.Attr.Type != syscall.IFLA_PROTINFO|syscall.NLA_F_NESTED { if attr.Attr.Type != unix.IFLA_PROTINFO|unix.NLA_F_NESTED {
continue continue
} }
infos, err := nl.ParseRouteAttr(attr.Value) infos, err := nl.ParseRouteAttr(attr.Value)
if err != nil { if err != nil {
return pi, err return pi, err
} }
pi = *parseProtinfo(infos) pi = parseProtinfo(infos)
return pi, nil return pi, nil
} }
@ -48,8 +49,7 @@ func (h *Handle) LinkGetProtinfo(link Link) (Protinfo, error) {
return pi, fmt.Errorf("Device with index %d not found", base.Index) return pi, fmt.Errorf("Device with index %d not found", base.Index)
} }
func parseProtinfo(infos []syscall.NetlinkRouteAttr) *Protinfo { func parseProtinfo(infos []syscall.NetlinkRouteAttr) (pi Protinfo) {
var pi Protinfo
for _, info := range infos { for _, info := range infos {
switch info.Attr.Type { switch info.Attr.Type {
case nl.IFLA_BRPORT_MODE: case nl.IFLA_BRPORT_MODE:
@ -70,5 +70,5 @@ func parseProtinfo(infos []syscall.NetlinkRouteAttr) *Protinfo {
pi.ProxyArpWiFi = byteToBool(info.Value[0]) pi.ProxyArpWiFi = byteToBool(info.Value[0])
} }
} }
return &pi return
} }

View File

@ -176,6 +176,13 @@ type Netem struct {
CorruptCorr uint32 CorruptCorr uint32
} }
func (netem *Netem) String() string {
return fmt.Sprintf(
"{Latency: %v, Limit: %v, Loss: %v, Gap: %v, Duplicate: %v, Jitter: %v}",
netem.Latency, netem.Limit, netem.Loss, netem.Gap, netem.Duplicate, netem.Jitter,
)
}
func (qdisc *Netem) Attrs() *QdiscAttrs { func (qdisc *Netem) Attrs() *QdiscAttrs {
return &qdisc.QdiscAttrs return &qdisc.QdiscAttrs
} }
@ -230,3 +237,104 @@ func (qdisc *GenericQdisc) Attrs() *QdiscAttrs {
func (qdisc *GenericQdisc) Type() string { func (qdisc *GenericQdisc) Type() string {
return qdisc.QdiscType return qdisc.QdiscType
} }
type Hfsc struct {
QdiscAttrs
Defcls uint16
}
func NewHfsc(attrs QdiscAttrs) *Hfsc {
return &Hfsc{
QdiscAttrs: attrs,
Defcls: 1,
}
}
func (hfsc *Hfsc) Attrs() *QdiscAttrs {
return &hfsc.QdiscAttrs
}
func (hfsc *Hfsc) Type() string {
return "hfsc"
}
func (hfsc *Hfsc) String() string {
return fmt.Sprintf(
"{%v -- default: %d}",
hfsc.Attrs(), hfsc.Defcls,
)
}
// Fq is a classless packet scheduler meant to be mostly used for locally generated traffic.
type Fq struct {
QdiscAttrs
PacketLimit uint32
FlowPacketLimit uint32
// In bytes
Quantum uint32
InitialQuantum uint32
// called RateEnable under the hood
Pacing uint32
FlowDefaultRate uint32
FlowMaxRate uint32
// called BucketsLog under the hood
Buckets uint32
FlowRefillDelay uint32
LowRateThreshold uint32
}
func (fq *Fq) String() string {
return fmt.Sprintf(
"{PacketLimit: %v, FlowPacketLimit: %v, Quantum: %v, InitalQuantum: %v, Pacing: %v, FlowDefaultRate: %v, FlowMaxRate: %v, Buckets: %v, FlowRefillDelay: %v, LowRateTreshold: %v}",
fq.PacketLimit, fq.FlowPacketLimit, fq.Quantum, fq.InitialQuantum, fq.Pacing, fq.FlowDefaultRate, fq.FlowMaxRate, fq.Buckets, fq.FlowRefillDelay, fq.LowRateThreshold,
)
}
func NewFq(attrs QdiscAttrs) *Fq {
return &Fq{
QdiscAttrs: attrs,
Pacing: 1,
}
}
func (qdisc *Fq) Attrs() *QdiscAttrs {
return &qdisc.QdiscAttrs
}
func (qdisc *Fq) Type() string {
return "fq"
}
// FQ_Codel (Fair Queuing Controlled Delay) is queuing discipline that combines Fair Queuing with the CoDel AQM scheme.
type FqCodel struct {
QdiscAttrs
Target uint32
Limit uint32
Interval uint32
ECN uint32
Flows uint32
Quantum uint32
// There are some more attributes here, but support for them seems not ubiquitous
}
func (fqcodel *FqCodel) String() string {
return fmt.Sprintf(
"{%v -- Target: %v, Limit: %v, Interval: %v, ECM: %v, Flows: %v, Quantum: %v}",
fqcodel.Attrs(), fqcodel.Target, fqcodel.Limit, fqcodel.Interval, fqcodel.ECN, fqcodel.Flows, fqcodel.Quantum,
)
}
func NewFqCodel(attrs QdiscAttrs) *FqCodel {
return &FqCodel{
QdiscAttrs: attrs,
ECN: 1,
}
}
func (qdisc *FqCodel) Attrs() *QdiscAttrs {
return &qdisc.QdiscAttrs
}
func (qdisc *FqCodel) Type() string {
return "fq_codel"
}

View File

@ -8,6 +8,7 @@ import (
"syscall" "syscall"
"github.com/vishvananda/netlink/nl" "github.com/vishvananda/netlink/nl"
"golang.org/x/sys/unix"
) )
// NOTE function is here because it uses other linux functions // NOTE function is here because it uses other linux functions
@ -84,7 +85,7 @@ func QdiscDel(qdisc Qdisc) error {
// QdiscDel will delete a qdisc from the system. // QdiscDel will delete a qdisc from the system.
// Equivalent to: `tc qdisc del $qdisc` // Equivalent to: `tc qdisc del $qdisc`
func (h *Handle) QdiscDel(qdisc Qdisc) error { func (h *Handle) QdiscDel(qdisc Qdisc) error {
return h.qdiscModify(syscall.RTM_DELQDISC, 0, qdisc) return h.qdiscModify(unix.RTM_DELQDISC, 0, qdisc)
} }
// QdiscChange will change a qdisc in place // QdiscChange will change a qdisc in place
@ -98,7 +99,7 @@ func QdiscChange(qdisc Qdisc) error {
// Equivalent to: `tc qdisc change $qdisc` // Equivalent to: `tc qdisc change $qdisc`
// The parent and handle MUST NOT be changed. // The parent and handle MUST NOT be changed.
func (h *Handle) QdiscChange(qdisc Qdisc) error { func (h *Handle) QdiscChange(qdisc Qdisc) error {
return h.qdiscModify(syscall.RTM_NEWQDISC, 0, qdisc) return h.qdiscModify(unix.RTM_NEWQDISC, 0, qdisc)
} }
// QdiscReplace will replace a qdisc to the system. // QdiscReplace will replace a qdisc to the system.
@ -113,8 +114,8 @@ func QdiscReplace(qdisc Qdisc) error {
// The handle MUST change. // The handle MUST change.
func (h *Handle) QdiscReplace(qdisc Qdisc) error { func (h *Handle) QdiscReplace(qdisc Qdisc) error {
return h.qdiscModify( return h.qdiscModify(
syscall.RTM_NEWQDISC, unix.RTM_NEWQDISC,
syscall.NLM_F_CREATE|syscall.NLM_F_REPLACE, unix.NLM_F_CREATE|unix.NLM_F_REPLACE,
qdisc) qdisc)
} }
@ -128,13 +129,13 @@ func QdiscAdd(qdisc Qdisc) error {
// Equivalent to: `tc qdisc add $qdisc` // Equivalent to: `tc qdisc add $qdisc`
func (h *Handle) QdiscAdd(qdisc Qdisc) error { func (h *Handle) QdiscAdd(qdisc Qdisc) error {
return h.qdiscModify( return h.qdiscModify(
syscall.RTM_NEWQDISC, unix.RTM_NEWQDISC,
syscall.NLM_F_CREATE|syscall.NLM_F_EXCL, unix.NLM_F_CREATE|unix.NLM_F_EXCL,
qdisc) qdisc)
} }
func (h *Handle) qdiscModify(cmd, flags int, qdisc Qdisc) error { func (h *Handle) qdiscModify(cmd, flags int, qdisc Qdisc) error {
req := h.newNetlinkRequest(cmd, flags|syscall.NLM_F_ACK) req := h.newNetlinkRequest(cmd, flags|unix.NLM_F_ACK)
base := qdisc.Attrs() base := qdisc.Attrs()
msg := &nl.TcMsg{ msg := &nl.TcMsg{
Family: nl.FAMILY_ALL, Family: nl.FAMILY_ALL,
@ -145,13 +146,13 @@ func (h *Handle) qdiscModify(cmd, flags int, qdisc Qdisc) error {
req.AddData(msg) req.AddData(msg)
// When deleting don't bother building the rest of the netlink payload // When deleting don't bother building the rest of the netlink payload
if cmd != syscall.RTM_DELQDISC { if cmd != unix.RTM_DELQDISC {
if err := qdiscPayload(req, qdisc); err != nil { if err := qdiscPayload(req, qdisc); err != nil {
return err return err
} }
} }
_, err := req.Execute(syscall.NETLINK_ROUTE, 0) _, err := req.Execute(unix.NETLINK_ROUTE, 0)
return err return err
} }
@ -160,78 +161,130 @@ func qdiscPayload(req *nl.NetlinkRequest, qdisc Qdisc) error {
req.AddData(nl.NewRtAttr(nl.TCA_KIND, nl.ZeroTerminated(qdisc.Type()))) req.AddData(nl.NewRtAttr(nl.TCA_KIND, nl.ZeroTerminated(qdisc.Type())))
options := nl.NewRtAttr(nl.TCA_OPTIONS, nil) options := nl.NewRtAttr(nl.TCA_OPTIONS, nil)
if prio, ok := qdisc.(*Prio); ok {
switch qdisc := qdisc.(type) {
case *Prio:
tcmap := nl.TcPrioMap{ tcmap := nl.TcPrioMap{
Bands: int32(prio.Bands), Bands: int32(qdisc.Bands),
Priomap: prio.PriorityMap, Priomap: qdisc.PriorityMap,
} }
options = nl.NewRtAttr(nl.TCA_OPTIONS, tcmap.Serialize()) options = nl.NewRtAttr(nl.TCA_OPTIONS, tcmap.Serialize())
} else if tbf, ok := qdisc.(*Tbf); ok { case *Tbf:
opt := nl.TcTbfQopt{} opt := nl.TcTbfQopt{}
opt.Rate.Rate = uint32(tbf.Rate) opt.Rate.Rate = uint32(qdisc.Rate)
opt.Peakrate.Rate = uint32(tbf.Peakrate) opt.Peakrate.Rate = uint32(qdisc.Peakrate)
opt.Limit = tbf.Limit opt.Limit = qdisc.Limit
opt.Buffer = tbf.Buffer opt.Buffer = qdisc.Buffer
nl.NewRtAttrChild(options, nl.TCA_TBF_PARMS, opt.Serialize()) options.AddRtAttr(nl.TCA_TBF_PARMS, opt.Serialize())
if tbf.Rate >= uint64(1<<32) { if qdisc.Rate >= uint64(1<<32) {
nl.NewRtAttrChild(options, nl.TCA_TBF_RATE64, nl.Uint64Attr(tbf.Rate)) options.AddRtAttr(nl.TCA_TBF_RATE64, nl.Uint64Attr(qdisc.Rate))
} }
if tbf.Peakrate >= uint64(1<<32) { if qdisc.Peakrate >= uint64(1<<32) {
nl.NewRtAttrChild(options, nl.TCA_TBF_PRATE64, nl.Uint64Attr(tbf.Peakrate)) options.AddRtAttr(nl.TCA_TBF_PRATE64, nl.Uint64Attr(qdisc.Peakrate))
} }
if tbf.Peakrate > 0 { if qdisc.Peakrate > 0 {
nl.NewRtAttrChild(options, nl.TCA_TBF_PBURST, nl.Uint32Attr(tbf.Minburst)) options.AddRtAttr(nl.TCA_TBF_PBURST, nl.Uint32Attr(qdisc.Minburst))
} }
} else if htb, ok := qdisc.(*Htb); ok { case *Htb:
opt := nl.TcHtbGlob{} opt := nl.TcHtbGlob{}
opt.Version = htb.Version opt.Version = qdisc.Version
opt.Rate2Quantum = htb.Rate2Quantum opt.Rate2Quantum = qdisc.Rate2Quantum
opt.Defcls = htb.Defcls opt.Defcls = qdisc.Defcls
// TODO: Handle Debug properly. For now default to 0 // TODO: Handle Debug properly. For now default to 0
opt.Debug = htb.Debug opt.Debug = qdisc.Debug
opt.DirectPkts = htb.DirectPkts opt.DirectPkts = qdisc.DirectPkts
nl.NewRtAttrChild(options, nl.TCA_HTB_INIT, opt.Serialize()) options.AddRtAttr(nl.TCA_HTB_INIT, opt.Serialize())
// nl.NewRtAttrChild(options, nl.TCA_HTB_DIRECT_QLEN, opt.Serialize()) // options.AddRtAttr(nl.TCA_HTB_DIRECT_QLEN, opt.Serialize())
} else if netem, ok := qdisc.(*Netem); ok { case *Hfsc:
opt := nl.TcHfscOpt{}
opt.Defcls = qdisc.Defcls
options = nl.NewRtAttr(nl.TCA_OPTIONS, opt.Serialize())
case *Netem:
opt := nl.TcNetemQopt{} opt := nl.TcNetemQopt{}
opt.Latency = netem.Latency opt.Latency = qdisc.Latency
opt.Limit = netem.Limit opt.Limit = qdisc.Limit
opt.Loss = netem.Loss opt.Loss = qdisc.Loss
opt.Gap = netem.Gap opt.Gap = qdisc.Gap
opt.Duplicate = netem.Duplicate opt.Duplicate = qdisc.Duplicate
opt.Jitter = netem.Jitter opt.Jitter = qdisc.Jitter
options = nl.NewRtAttr(nl.TCA_OPTIONS, opt.Serialize()) options = nl.NewRtAttr(nl.TCA_OPTIONS, opt.Serialize())
// Correlation // Correlation
corr := nl.TcNetemCorr{} corr := nl.TcNetemCorr{}
corr.DelayCorr = netem.DelayCorr corr.DelayCorr = qdisc.DelayCorr
corr.LossCorr = netem.LossCorr corr.LossCorr = qdisc.LossCorr
corr.DupCorr = netem.DuplicateCorr corr.DupCorr = qdisc.DuplicateCorr
if corr.DelayCorr > 0 || corr.LossCorr > 0 || corr.DupCorr > 0 { if corr.DelayCorr > 0 || corr.LossCorr > 0 || corr.DupCorr > 0 {
nl.NewRtAttrChild(options, nl.TCA_NETEM_CORR, corr.Serialize()) options.AddRtAttr(nl.TCA_NETEM_CORR, corr.Serialize())
} }
// Corruption // Corruption
corruption := nl.TcNetemCorrupt{} corruption := nl.TcNetemCorrupt{}
corruption.Probability = netem.CorruptProb corruption.Probability = qdisc.CorruptProb
corruption.Correlation = netem.CorruptCorr corruption.Correlation = qdisc.CorruptCorr
if corruption.Probability > 0 { if corruption.Probability > 0 {
nl.NewRtAttrChild(options, nl.TCA_NETEM_CORRUPT, corruption.Serialize()) options.AddRtAttr(nl.TCA_NETEM_CORRUPT, corruption.Serialize())
} }
// Reorder // Reorder
reorder := nl.TcNetemReorder{} reorder := nl.TcNetemReorder{}
reorder.Probability = netem.ReorderProb reorder.Probability = qdisc.ReorderProb
reorder.Correlation = netem.ReorderCorr reorder.Correlation = qdisc.ReorderCorr
if reorder.Probability > 0 { if reorder.Probability > 0 {
nl.NewRtAttrChild(options, nl.TCA_NETEM_REORDER, reorder.Serialize()) options.AddRtAttr(nl.TCA_NETEM_REORDER, reorder.Serialize())
} }
} else if _, ok := qdisc.(*Ingress); ok { case *Ingress:
// ingress filters must use the proper handle // ingress filters must use the proper handle
if qdisc.Attrs().Parent != HANDLE_INGRESS { if qdisc.Attrs().Parent != HANDLE_INGRESS {
return fmt.Errorf("Ingress filters must set Parent to HANDLE_INGRESS") return fmt.Errorf("Ingress filters must set Parent to HANDLE_INGRESS")
} }
case *FqCodel:
options.AddRtAttr(nl.TCA_FQ_CODEL_ECN, nl.Uint32Attr((uint32(qdisc.ECN))))
if qdisc.Limit > 0 {
options.AddRtAttr(nl.TCA_FQ_CODEL_LIMIT, nl.Uint32Attr((uint32(qdisc.Limit))))
}
if qdisc.Interval > 0 {
options.AddRtAttr(nl.TCA_FQ_CODEL_INTERVAL, nl.Uint32Attr((uint32(qdisc.Interval))))
}
if qdisc.Flows > 0 {
options.AddRtAttr(nl.TCA_FQ_CODEL_FLOWS, nl.Uint32Attr((uint32(qdisc.Flows))))
}
if qdisc.Quantum > 0 {
options.AddRtAttr(nl.TCA_FQ_CODEL_QUANTUM, nl.Uint32Attr((uint32(qdisc.Quantum))))
}
case *Fq:
options.AddRtAttr(nl.TCA_FQ_RATE_ENABLE, nl.Uint32Attr((uint32(qdisc.Pacing))))
if qdisc.Buckets > 0 {
options.AddRtAttr(nl.TCA_FQ_BUCKETS_LOG, nl.Uint32Attr((uint32(qdisc.Buckets))))
}
if qdisc.LowRateThreshold > 0 {
options.AddRtAttr(nl.TCA_FQ_LOW_RATE_THRESHOLD, nl.Uint32Attr((uint32(qdisc.LowRateThreshold))))
}
if qdisc.Quantum > 0 {
options.AddRtAttr(nl.TCA_FQ_QUANTUM, nl.Uint32Attr((uint32(qdisc.Quantum))))
}
if qdisc.InitialQuantum > 0 {
options.AddRtAttr(nl.TCA_FQ_INITIAL_QUANTUM, nl.Uint32Attr((uint32(qdisc.InitialQuantum))))
}
if qdisc.FlowRefillDelay > 0 {
options.AddRtAttr(nl.TCA_FQ_FLOW_REFILL_DELAY, nl.Uint32Attr((uint32(qdisc.FlowRefillDelay))))
}
if qdisc.FlowPacketLimit > 0 {
options.AddRtAttr(nl.TCA_FQ_FLOW_PLIMIT, nl.Uint32Attr((uint32(qdisc.FlowPacketLimit))))
}
if qdisc.FlowMaxRate > 0 {
options.AddRtAttr(nl.TCA_FQ_FLOW_MAX_RATE, nl.Uint32Attr((uint32(qdisc.FlowMaxRate))))
}
if qdisc.FlowDefaultRate > 0 {
options.AddRtAttr(nl.TCA_FQ_FLOW_DEFAULT_RATE, nl.Uint32Attr((uint32(qdisc.FlowDefaultRate))))
}
default:
options = nil
} }
req.AddData(options) if options != nil {
req.AddData(options)
}
return nil return nil
} }
@ -246,7 +299,7 @@ func QdiscList(link Link) ([]Qdisc, error) {
// Equivalent to: `tc qdisc show`. // Equivalent to: `tc qdisc show`.
// The list can be filtered by link. // The list can be filtered by link.
func (h *Handle) QdiscList(link Link) ([]Qdisc, error) { func (h *Handle) QdiscList(link Link) ([]Qdisc, error) {
req := h.newNetlinkRequest(syscall.RTM_GETQDISC, syscall.NLM_F_DUMP) req := h.newNetlinkRequest(unix.RTM_GETQDISC, unix.NLM_F_DUMP)
index := int32(0) index := int32(0)
if link != nil { if link != nil {
base := link.Attrs() base := link.Attrs()
@ -259,7 +312,7 @@ func (h *Handle) QdiscList(link Link) ([]Qdisc, error) {
} }
req.AddData(msg) req.AddData(msg)
msgs, err := req.Execute(syscall.NETLINK_ROUTE, syscall.RTM_NEWQDISC) msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWQDISC)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -301,6 +354,12 @@ func (h *Handle) QdiscList(link Link) ([]Qdisc, error) {
qdisc = &Ingress{} qdisc = &Ingress{}
case "htb": case "htb":
qdisc = &Htb{} qdisc = &Htb{}
case "fq":
qdisc = &Fq{}
case "hfsc":
qdisc = &Hfsc{}
case "fq_codel":
qdisc = &FqCodel{}
case "netem": case "netem":
qdisc = &Netem{} qdisc = &Netem{}
default: default:
@ -326,6 +385,10 @@ func (h *Handle) QdiscList(link Link) ([]Qdisc, error) {
if err := parseTbfData(qdisc, data); err != nil { if err := parseTbfData(qdisc, data); err != nil {
return nil, err return nil, err
} }
case "hfsc":
if err := parseHfscData(qdisc, attr.Value); err != nil {
return nil, err
}
case "htb": case "htb":
data, err := nl.ParseRouteAttr(attr.Value) data, err := nl.ParseRouteAttr(attr.Value)
if err != nil { if err != nil {
@ -334,6 +397,22 @@ func (h *Handle) QdiscList(link Link) ([]Qdisc, error) {
if err := parseHtbData(qdisc, data); err != nil { if err := parseHtbData(qdisc, data); err != nil {
return nil, err return nil, err
} }
case "fq":
data, err := nl.ParseRouteAttr(attr.Value)
if err != nil {
return nil, err
}
if err := parseFqData(qdisc, data); err != nil {
return nil, err
}
case "fq_codel":
data, err := nl.ParseRouteAttr(attr.Value)
if err != nil {
return nil, err
}
if err := parseFqCodelData(qdisc, data); err != nil {
return nil, err
}
case "netem": case "netem":
if err := parseNetemData(qdisc, attr.Value); err != nil { if err := parseNetemData(qdisc, attr.Value); err != nil {
return nil, err return nil, err
@ -386,6 +465,68 @@ func parseHtbData(qdisc Qdisc, data []syscall.NetlinkRouteAttr) error {
return nil return nil
} }
func parseFqCodelData(qdisc Qdisc, data []syscall.NetlinkRouteAttr) error {
native = nl.NativeEndian()
fqCodel := qdisc.(*FqCodel)
for _, datum := range data {
switch datum.Attr.Type {
case nl.TCA_FQ_CODEL_TARGET:
fqCodel.Target = native.Uint32(datum.Value)
case nl.TCA_FQ_CODEL_LIMIT:
fqCodel.Limit = native.Uint32(datum.Value)
case nl.TCA_FQ_CODEL_INTERVAL:
fqCodel.Interval = native.Uint32(datum.Value)
case nl.TCA_FQ_CODEL_ECN:
fqCodel.ECN = native.Uint32(datum.Value)
case nl.TCA_FQ_CODEL_FLOWS:
fqCodel.Flows = native.Uint32(datum.Value)
case nl.TCA_FQ_CODEL_QUANTUM:
fqCodel.Quantum = native.Uint32(datum.Value)
}
}
return nil
}
func parseHfscData(qdisc Qdisc, data []byte) error {
Hfsc := qdisc.(*Hfsc)
native = nl.NativeEndian()
Hfsc.Defcls = native.Uint16(data)
return nil
}
func parseFqData(qdisc Qdisc, data []syscall.NetlinkRouteAttr) error {
native = nl.NativeEndian()
fq := qdisc.(*Fq)
for _, datum := range data {
switch datum.Attr.Type {
case nl.TCA_FQ_BUCKETS_LOG:
fq.Buckets = native.Uint32(datum.Value)
case nl.TCA_FQ_LOW_RATE_THRESHOLD:
fq.LowRateThreshold = native.Uint32(datum.Value)
case nl.TCA_FQ_QUANTUM:
fq.Quantum = native.Uint32(datum.Value)
case nl.TCA_FQ_RATE_ENABLE:
fq.Pacing = native.Uint32(datum.Value)
case nl.TCA_FQ_INITIAL_QUANTUM:
fq.InitialQuantum = native.Uint32(datum.Value)
case nl.TCA_FQ_ORPHAN_MASK:
// TODO
case nl.TCA_FQ_FLOW_REFILL_DELAY:
fq.FlowRefillDelay = native.Uint32(datum.Value)
case nl.TCA_FQ_FLOW_PLIMIT:
fq.FlowPacketLimit = native.Uint32(datum.Value)
case nl.TCA_FQ_PLIMIT:
fq.PacketLimit = native.Uint32(datum.Value)
case nl.TCA_FQ_FLOW_MAX_RATE:
fq.FlowMaxRate = native.Uint32(datum.Value)
case nl.TCA_FQ_FLOW_DEFAULT_RATE:
fq.FlowDefaultRate = native.Uint32(datum.Value)
}
}
return nil
}
func parseNetemData(qdisc Qdisc, value []byte) error { func parseNetemData(qdisc Qdisc, value []byte) error {
netem := qdisc.(*Netem) netem := qdisc.(*Netem)
opt := nl.DeserializeTcNetemQopt(value) opt := nl.DeserializeTcNetemQopt(value)

View File

@ -0,0 +1,145 @@
package netlink
import (
"bytes"
"encoding/binary"
"fmt"
"net"
"github.com/vishvananda/netlink/nl"
"golang.org/x/sys/unix"
)
// LinkAttrs represents data shared by most link types
type RdmaLinkAttrs struct {
Index uint32
Name string
FirmwareVersion string
NodeGuid string
SysImageGuid string
}
// Link represents a rdma device from netlink.
type RdmaLink struct {
Attrs RdmaLinkAttrs
}
func getProtoField(clientType int, op int) int {
return ((clientType << nl.RDMA_NL_GET_CLIENT_SHIFT) | op)
}
func uint64ToGuidString(guid uint64) string {
//Convert to byte array
sysGuidBytes := new(bytes.Buffer)
binary.Write(sysGuidBytes, binary.LittleEndian, guid)
//Convert to HardwareAddr
sysGuidNet := net.HardwareAddr(sysGuidBytes.Bytes())
//Get the String
return sysGuidNet.String()
}
func executeOneGetRdmaLink(data []byte) (*RdmaLink, error) {
link := RdmaLink{}
reader := bytes.NewReader(data)
for reader.Len() >= 4 {
_, attrType, len, value := parseNfAttrTLV(reader)
switch attrType {
case nl.RDMA_NLDEV_ATTR_DEV_INDEX:
var Index uint32
r := bytes.NewReader(value)
binary.Read(r, nl.NativeEndian(), &Index)
link.Attrs.Index = Index
case nl.RDMA_NLDEV_ATTR_DEV_NAME:
link.Attrs.Name = string(value[0 : len-1])
case nl.RDMA_NLDEV_ATTR_FW_VERSION:
link.Attrs.FirmwareVersion = string(value[0 : len-1])
case nl.RDMA_NLDEV_ATTR_NODE_GUID:
var guid uint64
r := bytes.NewReader(value)
binary.Read(r, nl.NativeEndian(), &guid)
link.Attrs.NodeGuid = uint64ToGuidString(guid)
case nl.RDMA_NLDEV_ATTR_SYS_IMAGE_GUID:
var sysGuid uint64
r := bytes.NewReader(value)
binary.Read(r, nl.NativeEndian(), &sysGuid)
link.Attrs.SysImageGuid = uint64ToGuidString(sysGuid)
}
if (len % 4) != 0 {
// Skip pad bytes
reader.Seek(int64(4-(len%4)), seekCurrent)
}
}
return &link, nil
}
func execRdmaGetLink(req *nl.NetlinkRequest, name string) (*RdmaLink, error) {
msgs, err := req.Execute(unix.NETLINK_RDMA, 0)
if err != nil {
return nil, err
}
for _, m := range msgs {
link, err := executeOneGetRdmaLink(m)
if err != nil {
return nil, err
}
if link.Attrs.Name == name {
return link, nil
}
}
return nil, fmt.Errorf("Rdma device %v not found", name)
}
func execRdmaSetLink(req *nl.NetlinkRequest) error {
_, err := req.Execute(unix.NETLINK_RDMA, 0)
return err
}
// RdmaLinkByName finds a link by name and returns a pointer to the object if
// found and nil error, otherwise returns error code.
func RdmaLinkByName(name string) (*RdmaLink, error) {
return pkgHandle.RdmaLinkByName(name)
}
// RdmaLinkByName finds a link by name and returns a pointer to the object if
// found and nil error, otherwise returns error code.
func (h *Handle) RdmaLinkByName(name string) (*RdmaLink, error) {
proto := getProtoField(nl.RDMA_NL_NLDEV, nl.RDMA_NLDEV_CMD_GET)
req := h.newNetlinkRequest(proto, unix.NLM_F_ACK|unix.NLM_F_DUMP)
return execRdmaGetLink(req, name)
}
// RdmaLinkSetName sets the name of the rdma link device. Return nil on success
// or error otherwise.
// Equivalent to: `rdma dev set $old_devname name $name`
func RdmaLinkSetName(link *RdmaLink, name string) error {
return pkgHandle.RdmaLinkSetName(link, name)
}
// RdmaLinkSetName sets the name of the rdma link device. Return nil on success
// or error otherwise.
// Equivalent to: `rdma dev set $old_devname name $name`
func (h *Handle) RdmaLinkSetName(link *RdmaLink, name string) error {
proto := getProtoField(nl.RDMA_NL_NLDEV, nl.RDMA_NLDEV_CMD_SET)
req := h.newNetlinkRequest(proto, unix.NLM_F_ACK)
b := make([]byte, 4)
native.PutUint32(b, uint32(link.Attrs.Index))
data := nl.NewRtAttr(nl.RDMA_NLDEV_ATTR_DEV_INDEX, b)
req.AddData(data)
b = make([]byte, len(name)+1)
copy(b, name)
data = nl.NewRtAttr(nl.RDMA_NLDEV_ATTR_DEV_NAME, b)
req.AddData(data)
return execRdmaSetLink(req)
}

View File

@ -16,6 +16,7 @@ type Destination interface {
Decode([]byte) error Decode([]byte) error
Encode() ([]byte, error) Encode() ([]byte, error)
String() string String() string
Equal(Destination) bool
} }
type Encap interface { type Encap interface {
@ -23,6 +24,7 @@ type Encap interface {
Decode([]byte) error Decode([]byte) error
Encode() ([]byte, error) Encode() ([]byte, error)
String() string String() string
Equal(Encap) bool
} }
// Route represents a netlink route. // Route represents a netlink route.
@ -43,6 +45,9 @@ type Route struct {
MPLSDst *int MPLSDst *int
NewDst Destination NewDst Destination
Encap Encap Encap Encap
MTU int
AdvMSS int
Hoplimit int
} }
func (r Route) String() string { func (r Route) String() string {
@ -72,6 +77,26 @@ func (r Route) String() string {
return fmt.Sprintf("{%s}", strings.Join(elems, " ")) return fmt.Sprintf("{%s}", strings.Join(elems, " "))
} }
func (r Route) Equal(x Route) bool {
return r.LinkIndex == x.LinkIndex &&
r.ILinkIndex == x.ILinkIndex &&
r.Scope == x.Scope &&
ipNetEqual(r.Dst, x.Dst) &&
r.Src.Equal(x.Src) &&
r.Gw.Equal(x.Gw) &&
nexthopInfoSlice(r.MultiPath).Equal(x.MultiPath) &&
r.Protocol == x.Protocol &&
r.Priority == x.Priority &&
r.Table == x.Table &&
r.Type == x.Type &&
r.Tos == x.Tos &&
r.Hoplimit == x.Hoplimit &&
r.Flags == x.Flags &&
(r.MPLSDst == x.MPLSDst || (r.MPLSDst != nil && x.MPLSDst != nil && *r.MPLSDst == *x.MPLSDst)) &&
(r.NewDst == x.NewDst || (r.NewDst != nil && r.NewDst.Equal(x.NewDst))) &&
(r.Encap == x.Encap || (r.Encap != nil && r.Encap.Equal(x.Encap)))
}
func (r *Route) SetFlag(flag NextHopFlag) { func (r *Route) SetFlag(flag NextHopFlag) {
r.Flags |= int(flag) r.Flags |= int(flag)
} }
@ -110,7 +135,46 @@ func (n *NexthopInfo) String() string {
elems = append(elems, fmt.Sprintf("Encap: %s", n.Encap)) elems = append(elems, fmt.Sprintf("Encap: %s", n.Encap))
} }
elems = append(elems, fmt.Sprintf("Weight: %d", n.Hops+1)) elems = append(elems, fmt.Sprintf("Weight: %d", n.Hops+1))
elems = append(elems, fmt.Sprintf("Gw: %d", n.Gw)) elems = append(elems, fmt.Sprintf("Gw: %s", n.Gw))
elems = append(elems, fmt.Sprintf("Flags: %s", n.ListFlags())) elems = append(elems, fmt.Sprintf("Flags: %s", n.ListFlags()))
return fmt.Sprintf("{%s}", strings.Join(elems, " ")) return fmt.Sprintf("{%s}", strings.Join(elems, " "))
} }
func (n NexthopInfo) Equal(x NexthopInfo) bool {
return n.LinkIndex == x.LinkIndex &&
n.Hops == x.Hops &&
n.Gw.Equal(x.Gw) &&
n.Flags == x.Flags &&
(n.NewDst == x.NewDst || (n.NewDst != nil && n.NewDst.Equal(x.NewDst))) &&
(n.Encap == x.Encap || (n.Encap != nil && n.Encap.Equal(x.Encap)))
}
type nexthopInfoSlice []*NexthopInfo
func (n nexthopInfoSlice) Equal(x []*NexthopInfo) bool {
if len(n) != len(x) {
return false
}
for i := range n {
if n[i] == nil || x[i] == nil {
return false
}
if !n[i].Equal(*x[i]) {
return false
}
}
return true
}
// ipNetEqual returns true iff both IPNet are equal
func ipNetEqual(ipn1 *net.IPNet, ipn2 *net.IPNet) bool {
if ipn1 == ipn2 {
return true
}
if ipn1 == nil || ipn2 == nil {
return false
}
m1, _ := ipn1.Mask.Size()
m2, _ := ipn2.Mask.Size()
return m1 == m2 && ipn1.IP.Equal(ipn2.IP)
}

View File

@ -8,16 +8,17 @@ import (
"github.com/vishvananda/netlink/nl" "github.com/vishvananda/netlink/nl"
"github.com/vishvananda/netns" "github.com/vishvananda/netns"
"golang.org/x/sys/unix"
) )
// RtAttr is shared so it is in netlink_linux.go // RtAttr is shared so it is in netlink_linux.go
const ( const (
SCOPE_UNIVERSE Scope = syscall.RT_SCOPE_UNIVERSE SCOPE_UNIVERSE Scope = unix.RT_SCOPE_UNIVERSE
SCOPE_SITE Scope = syscall.RT_SCOPE_SITE SCOPE_SITE Scope = unix.RT_SCOPE_SITE
SCOPE_LINK Scope = syscall.RT_SCOPE_LINK SCOPE_LINK Scope = unix.RT_SCOPE_LINK
SCOPE_HOST Scope = syscall.RT_SCOPE_HOST SCOPE_HOST Scope = unix.RT_SCOPE_HOST
SCOPE_NOWHERE Scope = syscall.RT_SCOPE_NOWHERE SCOPE_NOWHERE Scope = unix.RT_SCOPE_NOWHERE
) )
const ( const (
@ -31,11 +32,12 @@ const (
RT_FILTER_SRC RT_FILTER_SRC
RT_FILTER_GW RT_FILTER_GW
RT_FILTER_TABLE RT_FILTER_TABLE
RT_FILTER_HOPLIMIT
) )
const ( const (
FLAG_ONLINK NextHopFlag = syscall.RTNH_F_ONLINK FLAG_ONLINK NextHopFlag = unix.RTNH_F_ONLINK
FLAG_PERVASIVE NextHopFlag = syscall.RTNH_F_PERVASIVE FLAG_PERVASIVE NextHopFlag = unix.RTNH_F_PERVASIVE
) )
var testFlags = []flagString{ var testFlags = []flagString{
@ -86,6 +88,34 @@ func (d *MPLSDestination) String() string {
return strings.Join(s, "/") return strings.Join(s, "/")
} }
func (d *MPLSDestination) Equal(x Destination) bool {
o, ok := x.(*MPLSDestination)
if !ok {
return false
}
if d == nil && o == nil {
return true
}
if d == nil || o == nil {
return false
}
if d.Labels == nil && o.Labels == nil {
return true
}
if d.Labels == nil || o.Labels == nil {
return false
}
if len(d.Labels) != len(o.Labels) {
return false
}
for i := range d.Labels {
if d.Labels[i] != o.Labels[i] {
return false
}
}
return true
}
type MPLSEncap struct { type MPLSEncap struct {
Labels []int Labels []int
} }
@ -96,17 +126,17 @@ func (e *MPLSEncap) Type() int {
func (e *MPLSEncap) Decode(buf []byte) error { func (e *MPLSEncap) Decode(buf []byte) error {
if len(buf) < 4 { if len(buf) < 4 {
return fmt.Errorf("Lack of bytes") return fmt.Errorf("lack of bytes")
} }
native := nl.NativeEndian() native := nl.NativeEndian()
l := native.Uint16(buf) l := native.Uint16(buf)
if len(buf) < int(l) { if len(buf) < int(l) {
return fmt.Errorf("Lack of bytes") return fmt.Errorf("lack of bytes")
} }
buf = buf[:l] buf = buf[:l]
typ := native.Uint16(buf[2:]) typ := native.Uint16(buf[2:])
if typ != nl.MPLS_IPTUNNEL_DST { if typ != nl.MPLS_IPTUNNEL_DST {
return fmt.Errorf("Unknown MPLS Encap Type: %d", typ) return fmt.Errorf("unknown MPLS Encap Type: %d", typ)
} }
e.Labels = nl.DecodeMPLSStack(buf[4:]) e.Labels = nl.DecodeMPLSStack(buf[4:])
return nil return nil
@ -129,6 +159,290 @@ func (e *MPLSEncap) String() string {
return strings.Join(s, "/") return strings.Join(s, "/")
} }
func (e *MPLSEncap) Equal(x Encap) bool {
o, ok := x.(*MPLSEncap)
if !ok {
return false
}
if e == nil && o == nil {
return true
}
if e == nil || o == nil {
return false
}
if e.Labels == nil && o.Labels == nil {
return true
}
if e.Labels == nil || o.Labels == nil {
return false
}
if len(e.Labels) != len(o.Labels) {
return false
}
for i := range e.Labels {
if e.Labels[i] != o.Labels[i] {
return false
}
}
return true
}
// SEG6 definitions
type SEG6Encap struct {
Mode int
Segments []net.IP
}
func (e *SEG6Encap) Type() int {
return nl.LWTUNNEL_ENCAP_SEG6
}
func (e *SEG6Encap) Decode(buf []byte) error {
if len(buf) < 4 {
return fmt.Errorf("lack of bytes")
}
native := nl.NativeEndian()
// Get Length(l) & Type(typ) : 2 + 2 bytes
l := native.Uint16(buf)
if len(buf) < int(l) {
return fmt.Errorf("lack of bytes")
}
buf = buf[:l] // make sure buf size upper limit is Length
typ := native.Uint16(buf[2:])
// LWTUNNEL_ENCAP_SEG6 has only one attr type SEG6_IPTUNNEL_SRH
if typ != nl.SEG6_IPTUNNEL_SRH {
return fmt.Errorf("unknown SEG6 Type: %d", typ)
}
var err error
e.Mode, e.Segments, err = nl.DecodeSEG6Encap(buf[4:])
return err
}
func (e *SEG6Encap) Encode() ([]byte, error) {
s, err := nl.EncodeSEG6Encap(e.Mode, e.Segments)
native := nl.NativeEndian()
hdr := make([]byte, 4)
native.PutUint16(hdr, uint16(len(s)+4))
native.PutUint16(hdr[2:], nl.SEG6_IPTUNNEL_SRH)
return append(hdr, s...), err
}
func (e *SEG6Encap) String() string {
segs := make([]string, 0, len(e.Segments))
// append segment backwards (from n to 0) since seg#0 is the last segment.
for i := len(e.Segments); i > 0; i-- {
segs = append(segs, fmt.Sprintf("%s", e.Segments[i-1]))
}
str := fmt.Sprintf("mode %s segs %d [ %s ]", nl.SEG6EncapModeString(e.Mode),
len(e.Segments), strings.Join(segs, " "))
return str
}
func (e *SEG6Encap) Equal(x Encap) bool {
o, ok := x.(*SEG6Encap)
if !ok {
return false
}
if e == o {
return true
}
if e == nil || o == nil {
return false
}
if e.Mode != o.Mode {
return false
}
if len(e.Segments) != len(o.Segments) {
return false
}
for i := range e.Segments {
if !e.Segments[i].Equal(o.Segments[i]) {
return false
}
}
return true
}
// SEG6Local definitions
type SEG6LocalEncap struct {
Flags [nl.SEG6_LOCAL_MAX]bool
Action int
Segments []net.IP // from SRH in seg6_local_lwt
Table int // table id for End.T and End.DT6
InAddr net.IP
In6Addr net.IP
Iif int
Oif int
}
func (e *SEG6LocalEncap) Type() int {
return nl.LWTUNNEL_ENCAP_SEG6_LOCAL
}
func (e *SEG6LocalEncap) Decode(buf []byte) error {
attrs, err := nl.ParseRouteAttr(buf)
if err != nil {
return err
}
native := nl.NativeEndian()
for _, attr := range attrs {
switch attr.Attr.Type {
case nl.SEG6_LOCAL_ACTION:
e.Action = int(native.Uint32(attr.Value[0:4]))
e.Flags[nl.SEG6_LOCAL_ACTION] = true
case nl.SEG6_LOCAL_SRH:
e.Segments, err = nl.DecodeSEG6Srh(attr.Value[:])
e.Flags[nl.SEG6_LOCAL_SRH] = true
case nl.SEG6_LOCAL_TABLE:
e.Table = int(native.Uint32(attr.Value[0:4]))
e.Flags[nl.SEG6_LOCAL_TABLE] = true
case nl.SEG6_LOCAL_NH4:
e.InAddr = net.IP(attr.Value[0:4])
e.Flags[nl.SEG6_LOCAL_NH4] = true
case nl.SEG6_LOCAL_NH6:
e.In6Addr = net.IP(attr.Value[0:16])
e.Flags[nl.SEG6_LOCAL_NH6] = true
case nl.SEG6_LOCAL_IIF:
e.Iif = int(native.Uint32(attr.Value[0:4]))
e.Flags[nl.SEG6_LOCAL_IIF] = true
case nl.SEG6_LOCAL_OIF:
e.Oif = int(native.Uint32(attr.Value[0:4]))
e.Flags[nl.SEG6_LOCAL_OIF] = true
}
}
return err
}
func (e *SEG6LocalEncap) Encode() ([]byte, error) {
var err error
native := nl.NativeEndian()
res := make([]byte, 8)
native.PutUint16(res, 8) // length
native.PutUint16(res[2:], nl.SEG6_LOCAL_ACTION)
native.PutUint32(res[4:], uint32(e.Action))
if e.Flags[nl.SEG6_LOCAL_SRH] {
srh, err := nl.EncodeSEG6Srh(e.Segments)
if err != nil {
return nil, err
}
attr := make([]byte, 4)
native.PutUint16(attr, uint16(len(srh)+4))
native.PutUint16(attr[2:], nl.SEG6_LOCAL_SRH)
attr = append(attr, srh...)
res = append(res, attr...)
}
if e.Flags[nl.SEG6_LOCAL_TABLE] {
attr := make([]byte, 8)
native.PutUint16(attr, 8)
native.PutUint16(attr[2:], nl.SEG6_LOCAL_TABLE)
native.PutUint32(attr[4:], uint32(e.Table))
res = append(res, attr...)
}
if e.Flags[nl.SEG6_LOCAL_NH4] {
attr := make([]byte, 4)
native.PutUint16(attr, 8)
native.PutUint16(attr[2:], nl.SEG6_LOCAL_NH4)
ipv4 := e.InAddr.To4()
if ipv4 == nil {
err = fmt.Errorf("SEG6_LOCAL_NH4 has invalid IPv4 address")
return nil, err
}
attr = append(attr, ipv4...)
res = append(res, attr...)
}
if e.Flags[nl.SEG6_LOCAL_NH6] {
attr := make([]byte, 4)
native.PutUint16(attr, 20)
native.PutUint16(attr[2:], nl.SEG6_LOCAL_NH6)
attr = append(attr, e.In6Addr...)
res = append(res, attr...)
}
if e.Flags[nl.SEG6_LOCAL_IIF] {
attr := make([]byte, 8)
native.PutUint16(attr, 8)
native.PutUint16(attr[2:], nl.SEG6_LOCAL_IIF)
native.PutUint32(attr[4:], uint32(e.Iif))
res = append(res, attr...)
}
if e.Flags[nl.SEG6_LOCAL_OIF] {
attr := make([]byte, 8)
native.PutUint16(attr, 8)
native.PutUint16(attr[2:], nl.SEG6_LOCAL_OIF)
native.PutUint32(attr[4:], uint32(e.Oif))
res = append(res, attr...)
}
return res, err
}
func (e *SEG6LocalEncap) String() string {
strs := make([]string, 0, nl.SEG6_LOCAL_MAX)
strs = append(strs, fmt.Sprintf("action %s", nl.SEG6LocalActionString(e.Action)))
if e.Flags[nl.SEG6_LOCAL_TABLE] {
strs = append(strs, fmt.Sprintf("table %d", e.Table))
}
if e.Flags[nl.SEG6_LOCAL_NH4] {
strs = append(strs, fmt.Sprintf("nh4 %s", e.InAddr))
}
if e.Flags[nl.SEG6_LOCAL_NH6] {
strs = append(strs, fmt.Sprintf("nh6 %s", e.In6Addr))
}
if e.Flags[nl.SEG6_LOCAL_IIF] {
link, err := LinkByIndex(e.Iif)
if err != nil {
strs = append(strs, fmt.Sprintf("iif %d", e.Iif))
} else {
strs = append(strs, fmt.Sprintf("iif %s", link.Attrs().Name))
}
}
if e.Flags[nl.SEG6_LOCAL_OIF] {
link, err := LinkByIndex(e.Oif)
if err != nil {
strs = append(strs, fmt.Sprintf("oif %d", e.Oif))
} else {
strs = append(strs, fmt.Sprintf("oif %s", link.Attrs().Name))
}
}
if e.Flags[nl.SEG6_LOCAL_SRH] {
segs := make([]string, 0, len(e.Segments))
//append segment backwards (from n to 0) since seg#0 is the last segment.
for i := len(e.Segments); i > 0; i-- {
segs = append(segs, fmt.Sprintf("%s", e.Segments[i-1]))
}
strs = append(strs, fmt.Sprintf("segs %d [ %s ]", len(e.Segments), strings.Join(segs, " ")))
}
return strings.Join(strs, " ")
}
func (e *SEG6LocalEncap) Equal(x Encap) bool {
o, ok := x.(*SEG6LocalEncap)
if !ok {
return false
}
if e == o {
return true
}
if e == nil || o == nil {
return false
}
// compare all arrays first
for i := range e.Flags {
if e.Flags[i] != o.Flags[i] {
return false
}
}
if len(e.Segments) != len(o.Segments) {
return false
}
for i := range e.Segments {
if !e.Segments[i].Equal(o.Segments[i]) {
return false
}
}
// compare values
if !e.InAddr.Equal(o.InAddr) || !e.In6Addr.Equal(o.In6Addr) {
return false
}
if e.Action != o.Action || e.Table != o.Table || e.Iif != o.Iif || e.Oif != o.Oif {
return false
}
return true
}
// RouteAdd will add a route to the system. // RouteAdd will add a route to the system.
// Equivalent to: `ip route add $route` // Equivalent to: `ip route add $route`
func RouteAdd(route *Route) error { func RouteAdd(route *Route) error {
@ -138,8 +452,8 @@ func RouteAdd(route *Route) error {
// RouteAdd will add a route to the system. // RouteAdd will add a route to the system.
// Equivalent to: `ip route add $route` // Equivalent to: `ip route add $route`
func (h *Handle) RouteAdd(route *Route) error { func (h *Handle) RouteAdd(route *Route) error {
flags := syscall.NLM_F_CREATE | syscall.NLM_F_EXCL | syscall.NLM_F_ACK flags := unix.NLM_F_CREATE | unix.NLM_F_EXCL | unix.NLM_F_ACK
req := h.newNetlinkRequest(syscall.RTM_NEWROUTE, flags) req := h.newNetlinkRequest(unix.RTM_NEWROUTE, flags)
return h.routeHandle(route, req, nl.NewRtMsg()) return h.routeHandle(route, req, nl.NewRtMsg())
} }
@ -152,8 +466,8 @@ func RouteReplace(route *Route) error {
// RouteReplace will add a route to the system. // RouteReplace will add a route to the system.
// Equivalent to: `ip route replace $route` // Equivalent to: `ip route replace $route`
func (h *Handle) RouteReplace(route *Route) error { func (h *Handle) RouteReplace(route *Route) error {
flags := syscall.NLM_F_CREATE | syscall.NLM_F_REPLACE | syscall.NLM_F_ACK flags := unix.NLM_F_CREATE | unix.NLM_F_REPLACE | unix.NLM_F_ACK
req := h.newNetlinkRequest(syscall.RTM_NEWROUTE, flags) req := h.newNetlinkRequest(unix.RTM_NEWROUTE, flags)
return h.routeHandle(route, req, nl.NewRtMsg()) return h.routeHandle(route, req, nl.NewRtMsg())
} }
@ -166,7 +480,7 @@ func RouteDel(route *Route) error {
// RouteDel will delete a route from the system. // RouteDel will delete a route from the system.
// Equivalent to: `ip route del $route` // Equivalent to: `ip route del $route`
func (h *Handle) RouteDel(route *Route) error { func (h *Handle) RouteDel(route *Route) error {
req := h.newNetlinkRequest(syscall.RTM_DELROUTE, syscall.NLM_F_ACK) req := h.newNetlinkRequest(unix.RTM_DELROUTE, unix.NLM_F_ACK)
return h.routeHandle(route, req, nl.NewRtDelMsg()) return h.routeHandle(route, req, nl.NewRtDelMsg())
} }
@ -189,12 +503,12 @@ func (h *Handle) routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg
} else { } else {
dstData = route.Dst.IP.To16() dstData = route.Dst.IP.To16()
} }
rtAttrs = append(rtAttrs, nl.NewRtAttr(syscall.RTA_DST, dstData)) rtAttrs = append(rtAttrs, nl.NewRtAttr(unix.RTA_DST, dstData))
} else if route.MPLSDst != nil { } else if route.MPLSDst != nil {
family = nl.FAMILY_MPLS family = nl.FAMILY_MPLS
msg.Dst_len = uint8(20) msg.Dst_len = uint8(20)
msg.Type = syscall.RTN_UNICAST msg.Type = unix.RTN_UNICAST
rtAttrs = append(rtAttrs, nl.NewRtAttr(syscall.RTA_DST, nl.EncodeMPLSStack(*route.MPLSDst))) rtAttrs = append(rtAttrs, nl.NewRtAttr(unix.RTA_DST, nl.EncodeMPLSStack(*route.MPLSDst)))
} }
if route.NewDst != nil { if route.NewDst != nil {
@ -232,7 +546,7 @@ func (h *Handle) routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg
srcData = route.Src.To16() srcData = route.Src.To16()
} }
// The commonly used src ip for routes is actually PREFSRC // The commonly used src ip for routes is actually PREFSRC
rtAttrs = append(rtAttrs, nl.NewRtAttr(syscall.RTA_PREFSRC, srcData)) rtAttrs = append(rtAttrs, nl.NewRtAttr(unix.RTA_PREFSRC, srcData))
} }
if route.Gw != nil { if route.Gw != nil {
@ -247,14 +561,14 @@ func (h *Handle) routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg
} else { } else {
gwData = route.Gw.To16() gwData = route.Gw.To16()
} }
rtAttrs = append(rtAttrs, nl.NewRtAttr(syscall.RTA_GATEWAY, gwData)) rtAttrs = append(rtAttrs, nl.NewRtAttr(unix.RTA_GATEWAY, gwData))
} }
if len(route.MultiPath) > 0 { if len(route.MultiPath) > 0 {
buf := []byte{} buf := []byte{}
for _, nh := range route.MultiPath { for _, nh := range route.MultiPath {
rtnh := &nl.RtNexthop{ rtnh := &nl.RtNexthop{
RtNexthop: syscall.RtNexthop{ RtNexthop: unix.RtNexthop{
Hops: uint8(nh.Hops), Hops: uint8(nh.Hops),
Ifindex: int32(nh.LinkIndex), Ifindex: int32(nh.LinkIndex),
Flags: uint8(nh.Flags), Flags: uint8(nh.Flags),
@ -267,9 +581,9 @@ func (h *Handle) routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg
return fmt.Errorf("gateway, source, and destination ip are not the same IP family") return fmt.Errorf("gateway, source, and destination ip are not the same IP family")
} }
if gwFamily == FAMILY_V4 { if gwFamily == FAMILY_V4 {
children = append(children, nl.NewRtAttr(syscall.RTA_GATEWAY, []byte(nh.Gw.To4()))) children = append(children, nl.NewRtAttr(unix.RTA_GATEWAY, []byte(nh.Gw.To4())))
} else { } else {
children = append(children, nl.NewRtAttr(syscall.RTA_GATEWAY, []byte(nh.Gw.To16()))) children = append(children, nl.NewRtAttr(unix.RTA_GATEWAY, []byte(nh.Gw.To16())))
} }
} }
if nh.NewDst != nil { if nh.NewDst != nil {
@ -295,15 +609,15 @@ func (h *Handle) routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg
rtnh.Children = children rtnh.Children = children
buf = append(buf, rtnh.Serialize()...) buf = append(buf, rtnh.Serialize()...)
} }
rtAttrs = append(rtAttrs, nl.NewRtAttr(syscall.RTA_MULTIPATH, buf)) rtAttrs = append(rtAttrs, nl.NewRtAttr(unix.RTA_MULTIPATH, buf))
} }
if route.Table > 0 { if route.Table > 0 {
if route.Table >= 256 { if route.Table >= 256 {
msg.Table = syscall.RT_TABLE_UNSPEC msg.Table = unix.RT_TABLE_UNSPEC
b := make([]byte, 4) b := make([]byte, 4)
native.PutUint32(b, uint32(route.Table)) native.PutUint32(b, uint32(route.Table))
rtAttrs = append(rtAttrs, nl.NewRtAttr(syscall.RTA_TABLE, b)) rtAttrs = append(rtAttrs, nl.NewRtAttr(unix.RTA_TABLE, b))
} else { } else {
msg.Table = uint8(route.Table) msg.Table = uint8(route.Table)
} }
@ -312,7 +626,7 @@ func (h *Handle) routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg
if route.Priority > 0 { if route.Priority > 0 {
b := make([]byte, 4) b := make([]byte, 4)
native.PutUint32(b, uint32(route.Priority)) native.PutUint32(b, uint32(route.Priority))
rtAttrs = append(rtAttrs, nl.NewRtAttr(syscall.RTA_PRIORITY, b)) rtAttrs = append(rtAttrs, nl.NewRtAttr(unix.RTA_PRIORITY, b))
} }
if route.Tos > 0 { if route.Tos > 0 {
msg.Tos = uint8(route.Tos) msg.Tos = uint8(route.Tos)
@ -324,6 +638,29 @@ func (h *Handle) routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg
msg.Type = uint8(route.Type) msg.Type = uint8(route.Type)
} }
var metrics []*nl.RtAttr
// TODO: support other rta_metric values
if route.MTU > 0 {
b := nl.Uint32Attr(uint32(route.MTU))
metrics = append(metrics, nl.NewRtAttr(unix.RTAX_MTU, b))
}
if route.AdvMSS > 0 {
b := nl.Uint32Attr(uint32(route.AdvMSS))
metrics = append(metrics, nl.NewRtAttr(unix.RTAX_ADVMSS, b))
}
if route.Hoplimit > 0 {
b := nl.Uint32Attr(uint32(route.Hoplimit))
metrics = append(metrics, nl.NewRtAttr(unix.RTAX_HOPLIMIT, b))
}
if metrics != nil {
attr := nl.NewRtAttr(unix.RTA_METRICS, nil)
for _, metric := range metrics {
attr.AddChild(metric)
}
rtAttrs = append(rtAttrs, attr)
}
msg.Flags = uint32(route.Flags) msg.Flags = uint32(route.Flags)
msg.Scope = uint8(route.Scope) msg.Scope = uint8(route.Scope)
msg.Family = uint8(family) msg.Family = uint8(family)
@ -338,9 +675,9 @@ func (h *Handle) routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg
) )
native.PutUint32(b, uint32(route.LinkIndex)) native.PutUint32(b, uint32(route.LinkIndex))
req.AddData(nl.NewRtAttr(syscall.RTA_OIF, b)) req.AddData(nl.NewRtAttr(unix.RTA_OIF, b))
_, err := req.Execute(syscall.NETLINK_ROUTE, 0) _, err := req.Execute(unix.NETLINK_ROUTE, 0)
return err return err
} }
@ -373,11 +710,11 @@ func RouteListFiltered(family int, filter *Route, filterMask uint64) ([]Route, e
// RouteListFiltered gets a list of routes in the system filtered with specified rules. // RouteListFiltered gets a list of routes in the system filtered with specified rules.
// All rules must be defined in RouteFilter struct // All rules must be defined in RouteFilter struct
func (h *Handle) RouteListFiltered(family int, filter *Route, filterMask uint64) ([]Route, error) { func (h *Handle) RouteListFiltered(family int, filter *Route, filterMask uint64) ([]Route, error) {
req := h.newNetlinkRequest(syscall.RTM_GETROUTE, syscall.NLM_F_DUMP) req := h.newNetlinkRequest(unix.RTM_GETROUTE, unix.NLM_F_DUMP)
infmsg := nl.NewIfInfomsg(family) infmsg := nl.NewIfInfomsg(family)
req.AddData(infmsg) req.AddData(infmsg)
msgs, err := req.Execute(syscall.NETLINK_ROUTE, syscall.RTM_NEWROUTE) msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWROUTE)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -385,11 +722,11 @@ func (h *Handle) RouteListFiltered(family int, filter *Route, filterMask uint64)
var res []Route var res []Route
for _, m := range msgs { for _, m := range msgs {
msg := nl.DeserializeRtMsg(m) msg := nl.DeserializeRtMsg(m)
if msg.Flags&syscall.RTM_F_CLONED != 0 { if msg.Flags&unix.RTM_F_CLONED != 0 {
// Ignore cloned routes // Ignore cloned routes
continue continue
} }
if msg.Table != syscall.RT_TABLE_MAIN { if msg.Table != unix.RT_TABLE_MAIN {
if filter == nil || filter != nil && filterMask&RT_FILTER_TABLE == 0 { if filter == nil || filter != nil && filterMask&RT_FILTER_TABLE == 0 {
// Ignore non-main tables // Ignore non-main tables
continue continue
@ -401,7 +738,7 @@ func (h *Handle) RouteListFiltered(family int, filter *Route, filterMask uint64)
} }
if filter != nil { if filter != nil {
switch { switch {
case filterMask&RT_FILTER_TABLE != 0 && filter.Table != syscall.RT_TABLE_UNSPEC && route.Table != filter.Table: case filterMask&RT_FILTER_TABLE != 0 && filter.Table != unix.RT_TABLE_UNSPEC && route.Table != filter.Table:
continue continue
case filterMask&RT_FILTER_PROTOCOL != 0 && route.Protocol != filter.Protocol: case filterMask&RT_FILTER_PROTOCOL != 0 && route.Protocol != filter.Protocol:
continue continue
@ -421,21 +758,12 @@ func (h *Handle) RouteListFiltered(family int, filter *Route, filterMask uint64)
continue continue
case filterMask&RT_FILTER_DST != 0: case filterMask&RT_FILTER_DST != 0:
if filter.MPLSDst == nil || route.MPLSDst == nil || (*filter.MPLSDst) != (*route.MPLSDst) { if filter.MPLSDst == nil || route.MPLSDst == nil || (*filter.MPLSDst) != (*route.MPLSDst) {
if filter.Dst == nil { if !ipNetEqual(route.Dst, filter.Dst) {
if route.Dst != nil { continue
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
}
} }
} }
case filterMask&RT_FILTER_HOPLIMIT != 0 && route.Hoplimit != filter.Hoplimit:
continue
} }
} }
res = append(res, route) res = append(res, route)
@ -463,11 +791,11 @@ func deserializeRoute(m []byte) (Route, error) {
var encap, encapType syscall.NetlinkRouteAttr var encap, encapType syscall.NetlinkRouteAttr
for _, attr := range attrs { for _, attr := range attrs {
switch attr.Attr.Type { switch attr.Attr.Type {
case syscall.RTA_GATEWAY: case unix.RTA_GATEWAY:
route.Gw = net.IP(attr.Value) route.Gw = net.IP(attr.Value)
case syscall.RTA_PREFSRC: case unix.RTA_PREFSRC:
route.Src = net.IP(attr.Value) route.Src = net.IP(attr.Value)
case syscall.RTA_DST: case unix.RTA_DST:
if msg.Family == nl.FAMILY_MPLS { if msg.Family == nl.FAMILY_MPLS {
stack := nl.DecodeMPLSStack(attr.Value) stack := nl.DecodeMPLSStack(attr.Value)
if len(stack) == 0 || len(stack) > 1 { if len(stack) == 0 || len(stack) > 1 {
@ -480,36 +808,36 @@ func deserializeRoute(m []byte) (Route, error) {
Mask: net.CIDRMask(int(msg.Dst_len), 8*len(attr.Value)), Mask: net.CIDRMask(int(msg.Dst_len), 8*len(attr.Value)),
} }
} }
case syscall.RTA_OIF: case unix.RTA_OIF:
route.LinkIndex = int(native.Uint32(attr.Value[0:4])) route.LinkIndex = int(native.Uint32(attr.Value[0:4]))
case syscall.RTA_IIF: case unix.RTA_IIF:
route.ILinkIndex = int(native.Uint32(attr.Value[0:4])) route.ILinkIndex = int(native.Uint32(attr.Value[0:4]))
case syscall.RTA_PRIORITY: case unix.RTA_PRIORITY:
route.Priority = int(native.Uint32(attr.Value[0:4])) route.Priority = int(native.Uint32(attr.Value[0:4]))
case syscall.RTA_TABLE: case unix.RTA_TABLE:
route.Table = int(native.Uint32(attr.Value[0:4])) route.Table = int(native.Uint32(attr.Value[0:4]))
case syscall.RTA_MULTIPATH: case unix.RTA_MULTIPATH:
parseRtNexthop := func(value []byte) (*NexthopInfo, []byte, error) { parseRtNexthop := func(value []byte) (*NexthopInfo, []byte, error) {
if len(value) < syscall.SizeofRtNexthop { if len(value) < unix.SizeofRtNexthop {
return nil, nil, fmt.Errorf("Lack of bytes") return nil, nil, fmt.Errorf("lack of bytes")
} }
nh := nl.DeserializeRtNexthop(value) nh := nl.DeserializeRtNexthop(value)
if len(value) < int(nh.RtNexthop.Len) { if len(value) < int(nh.RtNexthop.Len) {
return nil, nil, fmt.Errorf("Lack of bytes") return nil, nil, fmt.Errorf("lack of bytes")
} }
info := &NexthopInfo{ info := &NexthopInfo{
LinkIndex: int(nh.RtNexthop.Ifindex), LinkIndex: int(nh.RtNexthop.Ifindex),
Hops: int(nh.RtNexthop.Hops), Hops: int(nh.RtNexthop.Hops),
Flags: int(nh.RtNexthop.Flags), Flags: int(nh.RtNexthop.Flags),
} }
attrs, err := nl.ParseRouteAttr(value[syscall.SizeofRtNexthop:int(nh.RtNexthop.Len)]) attrs, err := nl.ParseRouteAttr(value[unix.SizeofRtNexthop:int(nh.RtNexthop.Len)])
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
var encap, encapType syscall.NetlinkRouteAttr var encap, encapType syscall.NetlinkRouteAttr
for _, attr := range attrs { for _, attr := range attrs {
switch attr.Attr.Type { switch attr.Attr.Type {
case syscall.RTA_GATEWAY: case unix.RTA_GATEWAY:
info.Gw = net.IP(attr.Value) info.Gw = net.IP(attr.Value)
case nl.RTA_NEWDST: case nl.RTA_NEWDST:
var d Destination var d Destination
@ -566,6 +894,21 @@ func deserializeRoute(m []byte) (Route, error) {
encapType = attr encapType = attr
case nl.RTA_ENCAP: case nl.RTA_ENCAP:
encap = attr encap = attr
case unix.RTA_METRICS:
metrics, err := nl.ParseRouteAttr(attr.Value)
if err != nil {
return route, err
}
for _, metric := range metrics {
switch metric.Attr.Type {
case unix.RTAX_MTU:
route.MTU = int(native.Uint32(metric.Value[0:4]))
case unix.RTAX_ADVMSS:
route.AdvMSS = int(native.Uint32(metric.Value[0:4]))
case unix.RTAX_HOPLIMIT:
route.Hoplimit = int(native.Uint32(metric.Value[0:4]))
}
}
} }
} }
@ -578,6 +921,16 @@ func deserializeRoute(m []byte) (Route, error) {
if err := e.Decode(encap.Value); err != nil { if err := e.Decode(encap.Value); err != nil {
return route, err return route, err
} }
case nl.LWTUNNEL_ENCAP_SEG6:
e = &SEG6Encap{}
if err := e.Decode(encap.Value); err != nil {
return route, err
}
case nl.LWTUNNEL_ENCAP_SEG6_LOCAL:
e = &SEG6LocalEncap{}
if err := e.Decode(encap.Value); err != nil {
return route, err
}
} }
route.Encap = e route.Encap = e
} }
@ -594,7 +947,7 @@ func RouteGet(destination net.IP) ([]Route, error) {
// RouteGet gets a route to a specific destination from the host system. // RouteGet gets a route to a specific destination from the host system.
// Equivalent to: 'ip route get'. // Equivalent to: 'ip route get'.
func (h *Handle) RouteGet(destination net.IP) ([]Route, error) { func (h *Handle) RouteGet(destination net.IP) ([]Route, error) {
req := h.newNetlinkRequest(syscall.RTM_GETROUTE, syscall.NLM_F_REQUEST) req := h.newNetlinkRequest(unix.RTM_GETROUTE, unix.NLM_F_REQUEST)
family := nl.GetIPFamily(destination) family := nl.GetIPFamily(destination)
var destinationData []byte var destinationData []byte
var bitlen uint8 var bitlen uint8
@ -610,10 +963,10 @@ func (h *Handle) RouteGet(destination net.IP) ([]Route, error) {
msg.Dst_len = bitlen msg.Dst_len = bitlen
req.AddData(msg) req.AddData(msg)
rtaDst := nl.NewRtAttr(syscall.RTA_DST, destinationData) rtaDst := nl.NewRtAttr(unix.RTA_DST, destinationData)
req.AddData(rtaDst) req.AddData(rtaDst)
msgs, err := req.Execute(syscall.NETLINK_ROUTE, syscall.RTM_NEWROUTE) msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWROUTE)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -633,17 +986,36 @@ func (h *Handle) RouteGet(destination net.IP) ([]Route, error) {
// RouteSubscribe takes a chan down which notifications will be sent // RouteSubscribe takes a chan down which notifications will be sent
// when routes are added or deleted. Close the 'done' chan to stop subscription. // when routes are added or deleted. Close the 'done' chan to stop subscription.
func RouteSubscribe(ch chan<- RouteUpdate, done <-chan struct{}) error { func RouteSubscribe(ch chan<- RouteUpdate, done <-chan struct{}) error {
return routeSubscribeAt(netns.None(), netns.None(), ch, done) return routeSubscribeAt(netns.None(), netns.None(), ch, done, nil, false)
} }
// RouteSubscribeAt works like RouteSubscribe plus it allows the caller // RouteSubscribeAt works like RouteSubscribe plus it allows the caller
// to choose the network namespace in which to subscribe (ns). // to choose the network namespace in which to subscribe (ns).
func RouteSubscribeAt(ns netns.NsHandle, ch chan<- RouteUpdate, done <-chan struct{}) error { func RouteSubscribeAt(ns netns.NsHandle, ch chan<- RouteUpdate, done <-chan struct{}) error {
return routeSubscribeAt(ns, netns.None(), ch, done) return routeSubscribeAt(ns, netns.None(), ch, done, nil, false)
} }
func routeSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- RouteUpdate, done <-chan struct{}) error { // RouteSubscribeOptions contains a set of options to use with
s, err := nl.SubscribeAt(newNs, curNs, syscall.NETLINK_ROUTE, syscall.RTNLGRP_IPV4_ROUTE, syscall.RTNLGRP_IPV6_ROUTE) // RouteSubscribeWithOptions.
type RouteSubscribeOptions struct {
Namespace *netns.NsHandle
ErrorCallback func(error)
ListExisting bool
}
// RouteSubscribeWithOptions work like RouteSubscribe but enable to
// provide additional options to modify the behavior. Currently, the
// namespace can be provided as well as an error callback.
func RouteSubscribeWithOptions(ch chan<- RouteUpdate, done <-chan struct{}, options RouteSubscribeOptions) error {
if options.Namespace == nil {
none := netns.None()
options.Namespace = &none
}
return routeSubscribeAt(*options.Namespace, netns.None(), ch, done, options.ErrorCallback, options.ListExisting)
}
func routeSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- RouteUpdate, done <-chan struct{}, cberr func(error), listExisting bool) error {
s, err := nl.SubscribeAt(newNs, curNs, unix.NETLINK_ROUTE, unix.RTNLGRP_IPV4_ROUTE, unix.RTNLGRP_IPV6_ROUTE)
if err != nil { if err != nil {
return err return err
} }
@ -653,16 +1025,45 @@ func routeSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- RouteUpdate, done <
s.Close() s.Close()
}() }()
} }
if listExisting {
req := pkgHandle.newNetlinkRequest(unix.RTM_GETROUTE,
unix.NLM_F_DUMP)
infmsg := nl.NewIfInfomsg(unix.AF_UNSPEC)
req.AddData(infmsg)
if err := s.Send(req); err != nil {
return err
}
}
go func() { go func() {
defer close(ch) defer close(ch)
for { for {
msgs, err := s.Receive() msgs, err := s.Receive()
if err != nil { if err != nil {
if cberr != nil {
cberr(err)
}
return return
} }
for _, m := range msgs { for _, m := range msgs {
if m.Header.Type == unix.NLMSG_DONE {
continue
}
if m.Header.Type == unix.NLMSG_ERROR {
native := nl.NativeEndian()
error := int32(native.Uint32(m.Data[0:4]))
if error == 0 {
continue
}
if cberr != nil {
cberr(syscall.Errno(-error))
}
return
}
route, err := deserializeRoute(m.Data) route, err := deserializeRoute(m.Data)
if err != nil { if err != nil {
if cberr != nil {
cberr(err)
}
return return
} }
ch <- RouteUpdate{Type: m.Header.Type, Route: route} ch <- RouteUpdate{Type: m.Header.Type, Route: route}

View File

@ -8,6 +8,7 @@ import (
// Rule represents a netlink rule. // Rule represents a netlink rule.
type Rule struct { type Rule struct {
Priority int Priority int
Family int
Table int Table int
Mark int Mark int
Mask int Mask int
@ -20,6 +21,7 @@ type Rule struct {
OifName string OifName string
SuppressIfgroup int SuppressIfgroup int
SuppressPrefixlen int SuppressPrefixlen int
Invert bool
} }
func (r Rule) String() string { func (r Rule) String() string {

View File

@ -3,11 +3,13 @@ package netlink
import ( import (
"fmt" "fmt"
"net" "net"
"syscall"
"github.com/vishvananda/netlink/nl" "github.com/vishvananda/netlink/nl"
"golang.org/x/sys/unix"
) )
const FibRuleInvert = 0x2
// RuleAdd adds a rule to the system. // RuleAdd adds a rule to the system.
// Equivalent to: ip rule add // Equivalent to: ip rule add
func RuleAdd(rule *Rule) error { func RuleAdd(rule *Rule) error {
@ -17,7 +19,7 @@ func RuleAdd(rule *Rule) error {
// RuleAdd adds a rule to the system. // RuleAdd adds a rule to the system.
// Equivalent to: ip rule add // Equivalent to: ip rule add
func (h *Handle) RuleAdd(rule *Rule) error { func (h *Handle) RuleAdd(rule *Rule) error {
req := h.newNetlinkRequest(syscall.RTM_NEWRULE, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK) req := h.newNetlinkRequest(unix.RTM_NEWRULE, unix.NLM_F_CREATE|unix.NLM_F_EXCL|unix.NLM_F_ACK)
return ruleHandle(rule, req) return ruleHandle(rule, req)
} }
@ -30,15 +32,31 @@ func RuleDel(rule *Rule) error {
// RuleDel deletes a rule from the system. // RuleDel deletes a rule from the system.
// Equivalent to: ip rule del // Equivalent to: ip rule del
func (h *Handle) RuleDel(rule *Rule) error { func (h *Handle) RuleDel(rule *Rule) error {
req := h.newNetlinkRequest(syscall.RTM_DELRULE, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK) req := h.newNetlinkRequest(unix.RTM_DELRULE, unix.NLM_F_ACK)
return ruleHandle(rule, req) return ruleHandle(rule, req)
} }
func ruleHandle(rule *Rule, req *nl.NetlinkRequest) error { func ruleHandle(rule *Rule, req *nl.NetlinkRequest) error {
msg := nl.NewRtMsg() msg := nl.NewRtMsg()
msg.Family = syscall.AF_INET msg.Family = unix.AF_INET
var dstFamily uint8 msg.Protocol = unix.RTPROT_BOOT
msg.Scope = unix.RT_SCOPE_UNIVERSE
msg.Table = unix.RT_TABLE_UNSPEC
msg.Type = unix.RTN_UNSPEC
if req.NlMsghdr.Flags&unix.NLM_F_CREATE > 0 {
msg.Type = unix.RTN_UNICAST
}
if rule.Invert {
msg.Flags |= FibRuleInvert
}
if rule.Family != 0 {
msg.Family = uint8(rule.Family)
}
if rule.Table >= 0 && rule.Table < 256 {
msg.Table = uint8(rule.Table)
}
var dstFamily uint8
var rtAttrs []*nl.RtAttr var rtAttrs []*nl.RtAttr
if rule.Dst != nil && rule.Dst.IP != nil { if rule.Dst != nil && rule.Dst.IP != nil {
dstLen, _ := rule.Dst.Mask.Size() dstLen, _ := rule.Dst.Mask.Size()
@ -46,12 +64,12 @@ func ruleHandle(rule *Rule, req *nl.NetlinkRequest) error {
msg.Family = uint8(nl.GetIPFamily(rule.Dst.IP)) msg.Family = uint8(nl.GetIPFamily(rule.Dst.IP))
dstFamily = msg.Family dstFamily = msg.Family
var dstData []byte var dstData []byte
if msg.Family == syscall.AF_INET { if msg.Family == unix.AF_INET {
dstData = rule.Dst.IP.To4() dstData = rule.Dst.IP.To4()
} else { } else {
dstData = rule.Dst.IP.To16() dstData = rule.Dst.IP.To16()
} }
rtAttrs = append(rtAttrs, nl.NewRtAttr(syscall.RTA_DST, dstData)) rtAttrs = append(rtAttrs, nl.NewRtAttr(unix.RTA_DST, dstData))
} }
if rule.Src != nil && rule.Src.IP != nil { if rule.Src != nil && rule.Src.IP != nil {
@ -62,19 +80,12 @@ func ruleHandle(rule *Rule, req *nl.NetlinkRequest) error {
srcLen, _ := rule.Src.Mask.Size() srcLen, _ := rule.Src.Mask.Size()
msg.Src_len = uint8(srcLen) msg.Src_len = uint8(srcLen)
var srcData []byte var srcData []byte
if msg.Family == syscall.AF_INET { if msg.Family == unix.AF_INET {
srcData = rule.Src.IP.To4() srcData = rule.Src.IP.To4()
} else { } else {
srcData = rule.Src.IP.To16() srcData = rule.Src.IP.To16()
} }
rtAttrs = append(rtAttrs, nl.NewRtAttr(syscall.RTA_SRC, srcData)) rtAttrs = append(rtAttrs, nl.NewRtAttr(unix.RTA_SRC, srcData))
}
if rule.Table >= 0 {
msg.Table = uint8(rule.Table)
if rule.Table >= 256 {
msg.Table = syscall.RT_TABLE_UNSPEC
}
} }
req.AddData(msg) req.AddData(msg)
@ -139,7 +150,7 @@ func ruleHandle(rule *Rule, req *nl.NetlinkRequest) error {
req.AddData(nl.NewRtAttr(nl.FRA_GOTO, b)) req.AddData(nl.NewRtAttr(nl.FRA_GOTO, b))
} }
_, err := req.Execute(syscall.NETLINK_ROUTE, 0) _, err := req.Execute(unix.NETLINK_ROUTE, 0)
return err return err
} }
@ -152,11 +163,11 @@ func RuleList(family int) ([]Rule, error) {
// RuleList lists rules in the system. // RuleList lists rules in the system.
// Equivalent to: ip rule list // Equivalent to: ip rule list
func (h *Handle) RuleList(family int) ([]Rule, error) { func (h *Handle) RuleList(family int) ([]Rule, error) {
req := h.newNetlinkRequest(syscall.RTM_GETRULE, syscall.NLM_F_DUMP|syscall.NLM_F_REQUEST) req := h.newNetlinkRequest(unix.RTM_GETRULE, unix.NLM_F_DUMP|unix.NLM_F_REQUEST)
msg := nl.NewIfInfomsg(family) msg := nl.NewIfInfomsg(family)
req.AddData(msg) req.AddData(msg)
msgs, err := req.Execute(syscall.NETLINK_ROUTE, syscall.RTM_NEWRULE) msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWRULE)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -172,9 +183,11 @@ func (h *Handle) RuleList(family int) ([]Rule, error) {
rule := NewRule() rule := NewRule()
rule.Invert = msg.Flags&FibRuleInvert > 0
for j := range attrs { for j := range attrs {
switch attrs[j].Attr.Type { switch attrs[j].Attr.Type {
case syscall.RTA_TABLE: case unix.RTA_TABLE:
rule.Table = int(native.Uint32(attrs[j].Value[0:4])) rule.Table = int(native.Uint32(attrs[j].Value[0:4]))
case nl.FRA_SRC: case nl.FRA_SRC:
rule.Src = &net.IPNet{ rule.Src = &net.IPNet{

View File

@ -4,9 +4,9 @@ import (
"errors" "errors"
"fmt" "fmt"
"net" "net"
"syscall"
"github.com/vishvananda/netlink/nl" "github.com/vishvananda/netlink/nl"
"golang.org/x/sys/unix"
) )
const ( const (
@ -123,15 +123,15 @@ func SocketGet(local, remote net.Addr) (*Socket, error) {
return nil, ErrNotImplemented return nil, ErrNotImplemented
} }
s, err := nl.Subscribe(syscall.NETLINK_INET_DIAG) s, err := nl.Subscribe(unix.NETLINK_INET_DIAG)
if err != nil { if err != nil {
return nil, err return nil, err
} }
defer s.Close() defer s.Close()
req := nl.NewNetlinkRequest(nl.SOCK_DIAG_BY_FAMILY, 0) req := nl.NewNetlinkRequest(nl.SOCK_DIAG_BY_FAMILY, 0)
req.AddData(&socketRequest{ req.AddData(&socketRequest{
Family: syscall.AF_INET, Family: unix.AF_INET,
Protocol: syscall.IPPROTO_TCP, Protocol: unix.IPPROTO_TCP,
ID: SocketID{ ID: SocketID{
SourcePort: uint16(localTCP.Port), SourcePort: uint16(localTCP.Port),
DestinationPort: uint16(remoteTCP.Port), DestinationPort: uint16(remoteTCP.Port),

View File

@ -2,19 +2,20 @@ package netlink
import ( import (
"fmt" "fmt"
"syscall"
"golang.org/x/sys/unix"
) )
// Proto is an enum representing an ipsec protocol. // Proto is an enum representing an ipsec protocol.
type Proto uint8 type Proto uint8
const ( const (
XFRM_PROTO_ROUTE2 Proto = syscall.IPPROTO_ROUTING XFRM_PROTO_ROUTE2 Proto = unix.IPPROTO_ROUTING
XFRM_PROTO_ESP Proto = syscall.IPPROTO_ESP XFRM_PROTO_ESP Proto = unix.IPPROTO_ESP
XFRM_PROTO_AH Proto = syscall.IPPROTO_AH XFRM_PROTO_AH Proto = unix.IPPROTO_AH
XFRM_PROTO_HAO Proto = syscall.IPPROTO_DSTOPTS XFRM_PROTO_HAO Proto = unix.IPPROTO_DSTOPTS
XFRM_PROTO_COMP Proto = 0x6c // NOTE not defined on darwin XFRM_PROTO_COMP Proto = 0x6c // NOTE not defined on darwin
XFRM_PROTO_IPSEC_ANY Proto = syscall.IPPROTO_RAW XFRM_PROTO_IPSEC_ANY Proto = unix.IPPROTO_RAW
) )
func (p Proto) String() string { func (p Proto) String() string {

View File

@ -2,11 +2,10 @@ package netlink
import ( import (
"fmt" "fmt"
"syscall"
"github.com/vishvananda/netns"
"github.com/vishvananda/netlink/nl" "github.com/vishvananda/netlink/nl"
"github.com/vishvananda/netns"
"golang.org/x/sys/unix"
) )
type XfrmMsg interface { type XfrmMsg interface {
@ -39,7 +38,7 @@ func XfrmMonitor(ch chan<- XfrmMsg, done <-chan struct{}, errorChan chan<- error
if err != nil { if err != nil {
return nil return nil
} }
s, err := nl.SubscribeAt(netns.None(), netns.None(), syscall.NETLINK_XFRM, groups...) s, err := nl.SubscribeAt(netns.None(), netns.None(), unix.NETLINK_XFRM, groups...)
if err != nil { if err != nil {
return err return err
} }

View File

@ -35,6 +35,25 @@ func (d Dir) String() string {
return fmt.Sprintf("socket %d", d-XFRM_SOCKET_IN) return fmt.Sprintf("socket %d", d-XFRM_SOCKET_IN)
} }
// PolicyAction is an enum representing an ipsec policy action.
type PolicyAction uint8
const (
XFRM_POLICY_ALLOW PolicyAction = 0
XFRM_POLICY_BLOCK PolicyAction = 1
)
func (a PolicyAction) String() string {
switch a {
case XFRM_POLICY_ALLOW:
return "allow"
case XFRM_POLICY_BLOCK:
return "block"
default:
return fmt.Sprintf("action %d", a)
}
}
// XfrmPolicyTmpl encapsulates a rule for the base addresses of an ipsec // XfrmPolicyTmpl encapsulates a rule for the base addresses of an ipsec
// policy. These rules are matched with XfrmState to determine encryption // policy. These rules are matched with XfrmState to determine encryption
// and authentication algorithms. // and authentication algorithms.
@ -64,11 +83,13 @@ type XfrmPolicy struct {
Dir Dir Dir Dir
Priority int Priority int
Index int Index int
Action PolicyAction
Ifindex int
Mark *XfrmMark Mark *XfrmMark
Tmpls []XfrmPolicyTmpl Tmpls []XfrmPolicyTmpl
} }
func (p XfrmPolicy) String() string { func (p XfrmPolicy) String() string {
return fmt.Sprintf("{Dst: %v, Src: %v, Proto: %s, DstPort: %d, SrcPort: %d, Dir: %s, Priority: %d, Index: %d, Mark: %s, Tmpls: %s}", return fmt.Sprintf("{Dst: %v, Src: %v, Proto: %s, DstPort: %d, SrcPort: %d, Dir: %s, Priority: %d, Index: %d, Action: %s, Ifindex: %d, Mark: %s, Tmpls: %s}",
p.Dst, p.Src, p.Proto, p.DstPort, p.SrcPort, p.Dir, p.Priority, p.Index, p.Mark, p.Tmpls) p.Dst, p.Src, p.Proto, p.DstPort, p.SrcPort, p.Dir, p.Priority, p.Index, p.Action, p.Ifindex, p.Mark, p.Tmpls)
} }

View File

@ -1,9 +1,8 @@
package netlink package netlink
import ( import (
"syscall"
"github.com/vishvananda/netlink/nl" "github.com/vishvananda/netlink/nl"
"golang.org/x/sys/unix"
) )
func selFromPolicy(sel *nl.XfrmSelector, policy *XfrmPolicy) { func selFromPolicy(sel *nl.XfrmSelector, policy *XfrmPolicy) {
@ -28,6 +27,7 @@ func selFromPolicy(sel *nl.XfrmSelector, policy *XfrmPolicy) {
if sel.Sport != 0 { if sel.Sport != 0 {
sel.SportMask = ^uint16(0) sel.SportMask = ^uint16(0)
} }
sel.Ifindex = int32(policy.Ifindex)
} }
// XfrmPolicyAdd will add an xfrm policy to the system. // XfrmPolicyAdd will add an xfrm policy to the system.
@ -55,13 +55,14 @@ func (h *Handle) XfrmPolicyUpdate(policy *XfrmPolicy) error {
} }
func (h *Handle) xfrmPolicyAddOrUpdate(policy *XfrmPolicy, nlProto int) error { func (h *Handle) xfrmPolicyAddOrUpdate(policy *XfrmPolicy, nlProto int) error {
req := h.newNetlinkRequest(nlProto, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK) req := h.newNetlinkRequest(nlProto, unix.NLM_F_CREATE|unix.NLM_F_EXCL|unix.NLM_F_ACK)
msg := &nl.XfrmUserpolicyInfo{} msg := &nl.XfrmUserpolicyInfo{}
selFromPolicy(&msg.Sel, policy) selFromPolicy(&msg.Sel, policy)
msg.Priority = uint32(policy.Priority) msg.Priority = uint32(policy.Priority)
msg.Index = uint32(policy.Index) msg.Index = uint32(policy.Index)
msg.Dir = uint8(policy.Dir) msg.Dir = uint8(policy.Dir)
msg.Action = uint8(policy.Action)
msg.Lft.SoftByteLimit = nl.XFRM_INF msg.Lft.SoftByteLimit = nl.XFRM_INF
msg.Lft.HardByteLimit = nl.XFRM_INF msg.Lft.HardByteLimit = nl.XFRM_INF
msg.Lft.SoftPacketLimit = nl.XFRM_INF msg.Lft.SoftPacketLimit = nl.XFRM_INF
@ -91,7 +92,7 @@ func (h *Handle) xfrmPolicyAddOrUpdate(policy *XfrmPolicy, nlProto int) error {
req.AddData(out) req.AddData(out)
} }
_, err := req.Execute(syscall.NETLINK_XFRM, 0) _, err := req.Execute(unix.NETLINK_XFRM, 0)
return err return err
} }
@ -121,12 +122,12 @@ func XfrmPolicyList(family int) ([]XfrmPolicy, error) {
// Equivalent to: `ip xfrm policy show`. // Equivalent to: `ip xfrm policy show`.
// The list can be filtered by ip family. // The list can be filtered by ip family.
func (h *Handle) XfrmPolicyList(family int) ([]XfrmPolicy, error) { func (h *Handle) XfrmPolicyList(family int) ([]XfrmPolicy, error) {
req := h.newNetlinkRequest(nl.XFRM_MSG_GETPOLICY, syscall.NLM_F_DUMP) req := h.newNetlinkRequest(nl.XFRM_MSG_GETPOLICY, unix.NLM_F_DUMP)
msg := nl.NewIfInfomsg(family) msg := nl.NewIfInfomsg(family)
req.AddData(msg) req.AddData(msg)
msgs, err := req.Execute(syscall.NETLINK_XFRM, nl.XFRM_MSG_NEWPOLICY) msgs, err := req.Execute(unix.NETLINK_XFRM, nl.XFRM_MSG_NEWPOLICY)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -165,13 +166,13 @@ func XfrmPolicyFlush() error {
// XfrmPolicyFlush will flush the policies on the system. // XfrmPolicyFlush will flush the policies on the system.
// Equivalent to: `ip xfrm policy flush` // Equivalent to: `ip xfrm policy flush`
func (h *Handle) XfrmPolicyFlush() error { func (h *Handle) XfrmPolicyFlush() error {
req := h.newNetlinkRequest(nl.XFRM_MSG_FLUSHPOLICY, syscall.NLM_F_ACK) req := h.newNetlinkRequest(nl.XFRM_MSG_FLUSHPOLICY, unix.NLM_F_ACK)
_, err := req.Execute(syscall.NETLINK_XFRM, 0) _, err := req.Execute(unix.NETLINK_XFRM, 0)
return err return err
} }
func (h *Handle) xfrmPolicyGetOrDelete(policy *XfrmPolicy, nlProto int) (*XfrmPolicy, error) { func (h *Handle) xfrmPolicyGetOrDelete(policy *XfrmPolicy, nlProto int) (*XfrmPolicy, error) {
req := h.newNetlinkRequest(nlProto, syscall.NLM_F_ACK) req := h.newNetlinkRequest(nlProto, unix.NLM_F_ACK)
msg := &nl.XfrmUserpolicyId{} msg := &nl.XfrmUserpolicyId{}
selFromPolicy(&msg.Sel, policy) selFromPolicy(&msg.Sel, policy)
@ -189,7 +190,7 @@ func (h *Handle) xfrmPolicyGetOrDelete(policy *XfrmPolicy, nlProto int) (*XfrmPo
resType = 0 resType = 0
} }
msgs, err := req.Execute(syscall.NETLINK_XFRM, uint16(resType)) msgs, err := req.Execute(unix.NETLINK_XFRM, uint16(resType))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -198,12 +199,7 @@ func (h *Handle) xfrmPolicyGetOrDelete(policy *XfrmPolicy, nlProto int) (*XfrmPo
return nil, err return nil, err
} }
p, err := parseXfrmPolicy(msgs[0], FAMILY_ALL) return parseXfrmPolicy(msgs[0], FAMILY_ALL)
if err != nil {
return nil, err
}
return p, nil
} }
func parseXfrmPolicy(m []byte, family int) (*XfrmPolicy, error) { func parseXfrmPolicy(m []byte, family int) (*XfrmPolicy, error) {
@ -221,9 +217,11 @@ func parseXfrmPolicy(m []byte, family int) (*XfrmPolicy, error) {
policy.Proto = Proto(msg.Sel.Proto) policy.Proto = Proto(msg.Sel.Proto)
policy.DstPort = int(nl.Swap16(msg.Sel.Dport)) policy.DstPort = int(nl.Swap16(msg.Sel.Dport))
policy.SrcPort = int(nl.Swap16(msg.Sel.Sport)) policy.SrcPort = int(nl.Swap16(msg.Sel.Sport))
policy.Ifindex = int(msg.Sel.Ifindex)
policy.Priority = int(msg.Priority) policy.Priority = int(msg.Priority)
policy.Index = int(msg.Index) policy.Index = int(msg.Index)
policy.Dir = Dir(msg.Dir) policy.Dir = Dir(msg.Dir)
policy.Action = PolicyAction(msg.Action)
attrs, err := nl.ParseRouteAttr(m[msg.Len():]) attrs, err := nl.ParseRouteAttr(m[msg.Len():])
if err != nil { if err != nil {

View File

@ -3,6 +3,7 @@ package netlink
import ( import (
"fmt" "fmt"
"net" "net"
"time"
) )
// XfrmStateAlgo represents the algorithm to use for the ipsec encryption. // XfrmStateAlgo represents the algorithm to use for the ipsec encryption.
@ -67,6 +68,19 @@ type XfrmStateLimits struct {
TimeUseHard uint64 TimeUseHard uint64
} }
// XfrmStateStats represents the current number of bytes/packets
// processed by this State, the State's installation and first use
// time and the replay window counters.
type XfrmStateStats struct {
ReplayWindow uint32
Replay uint32
Failed uint32
Bytes uint64
Packets uint64
AddTime uint64
UseTime uint64
}
// XfrmState represents the state of an ipsec policy. It optionally // XfrmState represents the state of an ipsec policy. It optionally
// contains an XfrmStateAlgo for encryption and one for authentication. // contains an XfrmStateAlgo for encryption and one for authentication.
type XfrmState struct { type XfrmState struct {
@ -78,6 +92,7 @@ type XfrmState struct {
Reqid int Reqid int
ReplayWindow int ReplayWindow int
Limits XfrmStateLimits Limits XfrmStateLimits
Statistics XfrmStateStats
Mark *XfrmMark Mark *XfrmMark
Auth *XfrmStateAlgo Auth *XfrmStateAlgo
Crypt *XfrmStateAlgo Crypt *XfrmStateAlgo
@ -94,10 +109,16 @@ func (sa XfrmState) Print(stats bool) string {
if !stats { if !stats {
return sa.String() return sa.String()
} }
at := time.Unix(int64(sa.Statistics.AddTime), 0).Format(time.UnixDate)
return fmt.Sprintf("%s, ByteSoft: %s, ByteHard: %s, PacketSoft: %s, PacketHard: %s, TimeSoft: %d, TimeHard: %d, TimeUseSoft: %d, TimeUseHard: %d", ut := "-"
if sa.Statistics.UseTime > 0 {
ut = time.Unix(int64(sa.Statistics.UseTime), 0).Format(time.UnixDate)
}
return fmt.Sprintf("%s, ByteSoft: %s, ByteHard: %s, PacketSoft: %s, PacketHard: %s, TimeSoft: %d, TimeHard: %d, TimeUseSoft: %d, TimeUseHard: %d, Bytes: %d, Packets: %d, "+
"AddTime: %s, UseTime: %s, ReplayWindow: %d, Replay: %d, Failed: %d",
sa.String(), printLimit(sa.Limits.ByteSoft), printLimit(sa.Limits.ByteHard), printLimit(sa.Limits.PacketSoft), printLimit(sa.Limits.PacketHard), sa.String(), printLimit(sa.Limits.ByteSoft), printLimit(sa.Limits.ByteHard), printLimit(sa.Limits.PacketSoft), printLimit(sa.Limits.PacketHard),
sa.Limits.TimeSoft, sa.Limits.TimeHard, sa.Limits.TimeUseSoft, sa.Limits.TimeUseHard) sa.Limits.TimeSoft, sa.Limits.TimeHard, sa.Limits.TimeUseSoft, sa.Limits.TimeUseHard, sa.Statistics.Bytes, sa.Statistics.Packets, at, ut,
sa.Statistics.ReplayWindow, sa.Statistics.Replay, sa.Statistics.Failed)
} }
func printLimit(lmt uint64) string { func printLimit(lmt uint64) string {

View File

@ -2,10 +2,10 @@ package netlink
import ( import (
"fmt" "fmt"
"syscall"
"unsafe" "unsafe"
"github.com/vishvananda/netlink/nl" "github.com/vishvananda/netlink/nl"
"golang.org/x/sys/unix"
) )
func writeStateAlgo(a *XfrmStateAlgo) []byte { func writeStateAlgo(a *XfrmStateAlgo) []byte {
@ -69,8 +69,10 @@ func writeReplayEsn(replayWindow int) []byte {
ReplayWindow: uint32(replayWindow), ReplayWindow: uint32(replayWindow),
} }
// taken from iproute2/ip/xfrm_state.c: // Linux stores the bitmap to identify the already received sequence packets in blocks of uint32 elements.
replayEsn.BmpLen = uint32((replayWindow + (4 * 8) - 1) / (4 * 8)) // Therefore bitmap length is the minimum number of uint32 elements needed. The following is a ceiling operation.
bytesPerElem := int(unsafe.Sizeof(replayEsn.BmpLen)) // Any uint32 variable is good for this
replayEsn.BmpLen = uint32((replayWindow + (bytesPerElem * 8) - 1) / (bytesPerElem * 8))
return replayEsn.Serialize() return replayEsn.Serialize()
} }
@ -111,7 +113,7 @@ func (h *Handle) xfrmStateAddOrUpdate(state *XfrmState, nlProto int) error {
if state.Spi == 0 { if state.Spi == 0 {
return fmt.Errorf("Spi must be set when adding xfrm state.") 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) req := h.newNetlinkRequest(nlProto, unix.NLM_F_CREATE|unix.NLM_F_EXCL|unix.NLM_F_ACK)
msg := xfrmUsersaInfoFromXfrmState(state) msg := xfrmUsersaInfoFromXfrmState(state)
@ -157,13 +159,13 @@ func (h *Handle) xfrmStateAddOrUpdate(state *XfrmState, nlProto int) error {
req.AddData(out) req.AddData(out)
} }
_, err := req.Execute(syscall.NETLINK_XFRM, 0) _, err := req.Execute(unix.NETLINK_XFRM, 0)
return err return err
} }
func (h *Handle) xfrmStateAllocSpi(state *XfrmState) (*XfrmState, error) { func (h *Handle) xfrmStateAllocSpi(state *XfrmState) (*XfrmState, error) {
req := h.newNetlinkRequest(nl.XFRM_MSG_ALLOCSPI, req := h.newNetlinkRequest(nl.XFRM_MSG_ALLOCSPI,
syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK) unix.NLM_F_CREATE|unix.NLM_F_EXCL|unix.NLM_F_ACK)
msg := &nl.XfrmUserSpiInfo{} msg := &nl.XfrmUserSpiInfo{}
msg.XfrmUsersaInfo = *(xfrmUsersaInfoFromXfrmState(state)) msg.XfrmUsersaInfo = *(xfrmUsersaInfoFromXfrmState(state))
@ -177,17 +179,12 @@ func (h *Handle) xfrmStateAllocSpi(state *XfrmState) (*XfrmState, error) {
req.AddData(out) req.AddData(out)
} }
msgs, err := req.Execute(syscall.NETLINK_XFRM, 0) msgs, err := req.Execute(unix.NETLINK_XFRM, 0)
if err != nil { if err != nil {
return nil, err return nil, err
} }
s, err := parseXfrmState(msgs[0], FAMILY_ALL) return 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 // XfrmStateDel will delete an xfrm state from the system. Note that
@ -216,9 +213,9 @@ func XfrmStateList(family int) ([]XfrmState, error) {
// Equivalent to: `ip xfrm state show`. // Equivalent to: `ip xfrm state show`.
// The list can be filtered by ip family. // The list can be filtered by ip family.
func (h *Handle) XfrmStateList(family int) ([]XfrmState, error) { func (h *Handle) XfrmStateList(family int) ([]XfrmState, error) {
req := h.newNetlinkRequest(nl.XFRM_MSG_GETSA, syscall.NLM_F_DUMP) req := h.newNetlinkRequest(nl.XFRM_MSG_GETSA, unix.NLM_F_DUMP)
msgs, err := req.Execute(syscall.NETLINK_XFRM, nl.XFRM_MSG_NEWSA) msgs, err := req.Execute(unix.NETLINK_XFRM, nl.XFRM_MSG_NEWSA)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -255,7 +252,7 @@ func (h *Handle) XfrmStateGet(state *XfrmState) (*XfrmState, error) {
} }
func (h *Handle) xfrmStateGetOrDelete(state *XfrmState, nlProto int) (*XfrmState, error) { func (h *Handle) xfrmStateGetOrDelete(state *XfrmState, nlProto int) (*XfrmState, error) {
req := h.newNetlinkRequest(nlProto, syscall.NLM_F_ACK) req := h.newNetlinkRequest(nlProto, unix.NLM_F_ACK)
msg := &nl.XfrmUsersaId{} msg := &nl.XfrmUsersaId{}
msg.Family = uint16(nl.GetIPFamily(state.Dst)) msg.Family = uint16(nl.GetIPFamily(state.Dst))
@ -278,7 +275,7 @@ func (h *Handle) xfrmStateGetOrDelete(state *XfrmState, nlProto int) (*XfrmState
resType = 0 resType = 0
} }
msgs, err := req.Execute(syscall.NETLINK_XFRM, uint16(resType)) msgs, err := req.Execute(unix.NETLINK_XFRM, uint16(resType))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -308,6 +305,7 @@ func xfrmStateFromXfrmUsersaInfo(msg *nl.XfrmUsersaInfo) *XfrmState {
state.Reqid = int(msg.Reqid) state.Reqid = int(msg.Reqid)
state.ReplayWindow = int(msg.ReplayWindow) state.ReplayWindow = int(msg.ReplayWindow)
lftToLimits(&msg.Lft, &state.Limits) lftToLimits(&msg.Lft, &state.Limits)
curToStats(&msg.Curlft, &msg.Stats, &state.Statistics)
return &state return &state
} }
@ -386,16 +384,12 @@ func XfrmStateFlush(proto Proto) error {
// proto = 0 means any transformation protocols // proto = 0 means any transformation protocols
// Equivalent to: `ip xfrm state flush [ proto XFRM-PROTO ]` // Equivalent to: `ip xfrm state flush [ proto XFRM-PROTO ]`
func (h *Handle) XfrmStateFlush(proto Proto) error { func (h *Handle) XfrmStateFlush(proto Proto) error {
req := h.newNetlinkRequest(nl.XFRM_MSG_FLUSHSA, syscall.NLM_F_ACK) req := h.newNetlinkRequest(nl.XFRM_MSG_FLUSHSA, unix.NLM_F_ACK)
req.AddData(&nl.XfrmUsersaFlush{Proto: uint8(proto)}) req.AddData(&nl.XfrmUsersaFlush{Proto: uint8(proto)})
_, err := req.Execute(syscall.NETLINK_XFRM, 0) _, err := req.Execute(unix.NETLINK_XFRM, 0)
if err != nil { return err
return err
}
return nil
} }
func limitsToLft(lmts XfrmStateLimits, lft *nl.XfrmLifetimeCfg) { func limitsToLft(lmts XfrmStateLimits, lft *nl.XfrmLifetimeCfg) {
@ -429,6 +423,16 @@ func lftToLimits(lft *nl.XfrmLifetimeCfg, lmts *XfrmStateLimits) {
*lmts = *(*XfrmStateLimits)(unsafe.Pointer(lft)) *lmts = *(*XfrmStateLimits)(unsafe.Pointer(lft))
} }
func curToStats(cur *nl.XfrmLifetimeCur, wstats *nl.XfrmStats, stats *XfrmStateStats) {
stats.Bytes = cur.Bytes
stats.Packets = cur.Packets
stats.AddTime = cur.AddTime
stats.UseTime = cur.UseTime
stats.ReplayWindow = wstats.ReplayWindow
stats.Replay = wstats.Replay
stats.Failed = wstats.IntegrityFailed
}
func xfrmUsersaInfoFromXfrmState(state *XfrmState) *nl.XfrmUsersaInfo { func xfrmUsersaInfoFromXfrmState(state *XfrmState) *nl.XfrmUsersaInfo {
msg := &nl.XfrmUsersaInfo{} msg := &nl.XfrmUsersaInfo{}
msg.Family = uint16(nl.GetIPFamily(state.Dst)) msg.Family = uint16(nl.GetIPFamily(state.Dst))

View File

@ -138,7 +138,9 @@ func getThisCgroup(cgroupType string) (string, error) {
return "", fmt.Errorf("docker pid not found in /var/run/docker.pid") return "", fmt.Errorf("docker pid not found in /var/run/docker.pid")
} }
pid, err := strconv.Atoi(result[0]) pid, err := strconv.Atoi(result[0])
if err != nil {
return "", err
}
output, err := ioutil.ReadFile(fmt.Sprintf("/proc/%d/cgroup", pid)) output, err := ioutil.ReadFile(fmt.Sprintf("/proc/%d/cgroup", pid))
if err != nil { if err != nil {
return "", err return "", err
@ -186,6 +188,12 @@ func getPidForContainer(id string) (int, error) {
filepath.Join(cgroupRoot, "system.slice", "docker-"+id+".scope", "tasks"), filepath.Join(cgroupRoot, "system.slice", "docker-"+id+".scope", "tasks"),
// Even more recent docker versions under cgroup/systemd/docker/<id>/ // Even more recent docker versions under cgroup/systemd/docker/<id>/
filepath.Join(cgroupRoot, "..", "systemd", "docker", id, "tasks"), filepath.Join(cgroupRoot, "..", "systemd", "docker", id, "tasks"),
// Kubernetes with docker and CNI is even more different
filepath.Join(cgroupRoot, "..", "systemd", "kubepods", "*", "pod*", id, "tasks"),
// Another flavor of containers location in recent kubernetes 1.11+
filepath.Join(cgroupRoot, cgroupThis, "kubepods.slice", "kubepods-besteffort.slice", "*", "docker-"+id+".scope", "tasks"),
// When runs inside of a container with recent kubernetes 1.11+
filepath.Join(cgroupRoot, "kubepods.slice", "kubepods-besteffort.slice", "*", "docker-"+id+".scope", "tasks"),
} }
var filename string var filename string

View File

@ -108,9 +108,7 @@ func ReadPassword(fd int) ([]byte, error) {
return nil, err return nil, err
} }
defer func() { defer unix.IoctlSetTermios(fd, ioctlWriteTermios, termios)
unix.IoctlSetTermios(fd, ioctlWriteTermios, termios)
}()
return readPasswordLine(passwordReader(fd)) return readPasswordLine(passwordReader(fd))
} }

View File

@ -14,7 +14,7 @@ import (
// State contains the state of a terminal. // State contains the state of a terminal.
type State struct { type State struct {
state *unix.Termios termios unix.Termios
} }
// IsTerminal returns true if the given file descriptor is a terminal. // IsTerminal returns true if the given file descriptor is a terminal.
@ -75,47 +75,43 @@ func ReadPassword(fd int) ([]byte, error) {
// restored. // restored.
// see http://cr.illumos.org/~webrev/andy_js/1060/ // see http://cr.illumos.org/~webrev/andy_js/1060/
func MakeRaw(fd int) (*State, error) { func MakeRaw(fd int) (*State, error) {
oldTermiosPtr, err := unix.IoctlGetTermios(fd, unix.TCGETS) termios, err := unix.IoctlGetTermios(fd, unix.TCGETS)
if err != nil { if err != nil {
return nil, err return nil, err
} }
oldTermios := *oldTermiosPtr
newTermios := oldTermios oldState := State{termios: *termios}
newTermios.Iflag &^= syscall.IGNBRK | syscall.BRKINT | syscall.PARMRK | syscall.ISTRIP | syscall.INLCR | syscall.IGNCR | syscall.ICRNL | syscall.IXON
newTermios.Oflag &^= syscall.OPOST
newTermios.Lflag &^= syscall.ECHO | syscall.ECHONL | syscall.ICANON | syscall.ISIG | syscall.IEXTEN
newTermios.Cflag &^= syscall.CSIZE | syscall.PARENB
newTermios.Cflag |= syscall.CS8
newTermios.Cc[unix.VMIN] = 1
newTermios.Cc[unix.VTIME] = 0
if err := unix.IoctlSetTermios(fd, unix.TCSETS, &newTermios); err != nil { termios.Iflag &^= unix.IGNBRK | unix.BRKINT | unix.PARMRK | unix.ISTRIP | unix.INLCR | unix.IGNCR | unix.ICRNL | unix.IXON
termios.Oflag &^= unix.OPOST
termios.Lflag &^= unix.ECHO | unix.ECHONL | unix.ICANON | unix.ISIG | unix.IEXTEN
termios.Cflag &^= unix.CSIZE | unix.PARENB
termios.Cflag |= unix.CS8
termios.Cc[unix.VMIN] = 1
termios.Cc[unix.VTIME] = 0
if err := unix.IoctlSetTermios(fd, unix.TCSETS, termios); err != nil {
return nil, err return nil, err
} }
return &State{ return &oldState, nil
state: oldTermiosPtr,
}, nil
} }
// Restore restores the terminal connected to the given file descriptor to a // Restore restores the terminal connected to the given file descriptor to a
// previous state. // previous state.
func Restore(fd int, oldState *State) error { func Restore(fd int, oldState *State) error {
return unix.IoctlSetTermios(fd, unix.TCSETS, oldState.state) return unix.IoctlSetTermios(fd, unix.TCSETS, &oldState.termios)
} }
// GetState returns the current state of a terminal which may be useful to // GetState returns the current state of a terminal which may be useful to
// restore the terminal after a signal. // restore the terminal after a signal.
func GetState(fd int) (*State, error) { func GetState(fd int) (*State, error) {
oldTermiosPtr, err := unix.IoctlGetTermios(fd, unix.TCGETS) termios, err := unix.IoctlGetTermios(fd, unix.TCGETS)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &State{ return &State{termios: *termios}, nil
state: oldTermiosPtr,
}, nil
} }
// GetSize returns the dimensions of the given terminal. // GetSize returns the dimensions of the given terminal.

View File

@ -89,9 +89,15 @@ func ReadPassword(fd int) ([]byte, error) {
return nil, err return nil, err
} }
defer func() { defer windows.SetConsoleMode(windows.Handle(fd), old)
windows.SetConsoleMode(windows.Handle(fd), old)
}()
return readPasswordLine(os.NewFile(uintptr(fd), "stdin")) var h windows.Handle
p, _ := windows.GetCurrentProcess()
if err := windows.DuplicateHandle(p, windows.Handle(fd), p, &h, 0, false, windows.DUPLICATE_SAME_ACCESS); err != nil {
return nil, err
}
f := os.NewFile(uintptr(h), "stdin")
defer f.Close()
return readPasswordLine(f)
} }

View File

@ -38,6 +38,7 @@ const (
type JumpTest uint16 type JumpTest uint16
// Supported operators for conditional jumps. // Supported operators for conditional jumps.
// K can be RegX for JumpIfX
const ( const (
// K == A // K == A
JumpEqual JumpTest = iota JumpEqual JumpTest = iota
@ -70,57 +71,60 @@ type Extension int
// Extension functions available in the Linux kernel. // Extension functions available in the Linux kernel.
const ( const (
// extOffset is the negative maximum number of instructions used
// to load instructions by overloading the K argument.
extOffset = -0x1000
// ExtLen returns the length of the packet. // ExtLen returns the length of the packet.
ExtLen Extension = 1 ExtLen Extension = 1
// ExtProto returns the packet's L3 protocol type. // ExtProto returns the packet's L3 protocol type.
ExtProto = 0 ExtProto Extension = 0
// ExtType returns the packet's type (skb->pkt_type in the kernel) // ExtType returns the packet's type (skb->pkt_type in the kernel)
// //
// TODO: better documentation. How nice an API do we want to // TODO: better documentation. How nice an API do we want to
// provide for these esoteric extensions? // provide for these esoteric extensions?
ExtType = 4 ExtType Extension = 4
// ExtPayloadOffset returns the offset of the packet payload, or // ExtPayloadOffset returns the offset of the packet payload, or
// the first protocol header that the kernel does not know how to // the first protocol header that the kernel does not know how to
// parse. // parse.
ExtPayloadOffset = 52 ExtPayloadOffset Extension = 52
// ExtInterfaceIndex returns the index of the interface on which // ExtInterfaceIndex returns the index of the interface on which
// the packet was received. // the packet was received.
ExtInterfaceIndex = 8 ExtInterfaceIndex Extension = 8
// ExtNetlinkAttr returns the netlink attribute of type X at // ExtNetlinkAttr returns the netlink attribute of type X at
// offset A. // offset A.
ExtNetlinkAttr = 12 ExtNetlinkAttr Extension = 12
// ExtNetlinkAttrNested returns the nested netlink attribute of // ExtNetlinkAttrNested returns the nested netlink attribute of
// type X at offset A. // type X at offset A.
ExtNetlinkAttrNested = 16 ExtNetlinkAttrNested Extension = 16
// ExtMark returns the packet's mark value. // ExtMark returns the packet's mark value.
ExtMark = 20 ExtMark Extension = 20
// ExtQueue returns the packet's assigned hardware queue. // ExtQueue returns the packet's assigned hardware queue.
ExtQueue = 24 ExtQueue Extension = 24
// ExtLinkLayerType returns the packet's hardware address type // ExtLinkLayerType returns the packet's hardware address type
// (e.g. Ethernet, Infiniband). // (e.g. Ethernet, Infiniband).
ExtLinkLayerType = 28 ExtLinkLayerType Extension = 28
// ExtRXHash returns the packets receive hash. // ExtRXHash returns the packets receive hash.
// //
// TODO: figure out what this rxhash actually is. // TODO: figure out what this rxhash actually is.
ExtRXHash = 32 ExtRXHash Extension = 32
// ExtCPUID returns the ID of the CPU processing the current // ExtCPUID returns the ID of the CPU processing the current
// packet. // packet.
ExtCPUID = 36 ExtCPUID Extension = 36
// ExtVLANTag returns the packet's VLAN tag. // ExtVLANTag returns the packet's VLAN tag.
ExtVLANTag = 44 ExtVLANTag Extension = 44
// ExtVLANTagPresent returns non-zero if the packet has a VLAN // ExtVLANTagPresent returns non-zero if the packet has a VLAN
// tag. // tag.
// //
// TODO: I think this might be a lie: it reads bit 0x1000 of the // TODO: I think this might be a lie: it reads bit 0x1000 of the
// VLAN header, which changed meaning in recent revisions of the // VLAN header, which changed meaning in recent revisions of the
// spec - this extension may now return meaningless information. // spec - this extension may now return meaningless information.
ExtVLANTagPresent = 48 ExtVLANTagPresent Extension = 48
// ExtVLANProto returns 0x8100 if the frame has a VLAN header, // ExtVLANProto returns 0x8100 if the frame has a VLAN header,
// 0x88a8 if the frame has a "Q-in-Q" double VLAN header, or some // 0x88a8 if the frame has a "Q-in-Q" double VLAN header, or some
// other value if no VLAN information is present. // other value if no VLAN information is present.
ExtVLANProto = 60 ExtVLANProto Extension = 60
// ExtRand returns a uniformly random uint32. // ExtRand returns a uniformly random uint32.
ExtRand = 56 ExtRand Extension = 56
) )
// The following gives names to various bit patterns used in opcode construction. // The following gives names to various bit patterns used in opcode construction.
@ -131,12 +135,9 @@ const (
opMaskLoadDest = 0x01 opMaskLoadDest = 0x01
opMaskLoadWidth = 0x18 opMaskLoadWidth = 0x18
opMaskLoadMode = 0xe0 opMaskLoadMode = 0xe0
// opClsALU // opClsALU & opClsJump
opMaskOperandSrc = 0x08 opMaskOperand = 0x08
opMaskOperator = 0xf0 opMaskOperator = 0xf0
// opClsJump
opMaskJumpConst = 0x0f
opMaskJumpCond = 0xf0
) )
const ( const (
@ -189,15 +190,21 @@ const (
opLoadWidth1 opLoadWidth1
) )
// Operator defined by ALUOp* // Operand for ALU and Jump instructions
type opOperand uint16
// Supported operand sources.
const ( const (
opALUSrcConstant uint16 = iota << 3 opOperandConstant opOperand = iota << 3
opALUSrcX opOperandX
) )
// An jumpOp is a conditional jump condition.
type jumpOp uint16
// Supported jump conditions.
const ( const (
opJumpAlways = iota << 4 opJumpAlways jumpOp = iota << 4
opJumpEqual opJumpEqual
opJumpGT opJumpGT
opJumpGE opJumpGE

View File

@ -57,6 +57,9 @@ func (ri RawInstruction) Disassemble() Instruction {
} }
return LoadScratch{Dst: reg, N: int(ri.K)} return LoadScratch{Dst: reg, N: int(ri.K)}
case opAddrModeAbsolute: case opAddrModeAbsolute:
if ri.K > extOffset+0xffffffff {
return LoadExtension{Num: Extension(-extOffset + ri.K)}
}
return LoadAbsolute{Size: sz, Off: ri.K} return LoadAbsolute{Size: sz, Off: ri.K}
case opAddrModeIndirect: case opAddrModeIndirect:
return LoadIndirect{Size: sz, Off: ri.K} return LoadIndirect{Size: sz, Off: ri.K}
@ -86,10 +89,14 @@ func (ri RawInstruction) Disassemble() Instruction {
case opClsALU: case opClsALU:
switch op := ALUOp(ri.Op & opMaskOperator); op { switch op := ALUOp(ri.Op & opMaskOperator); op {
case ALUOpAdd, ALUOpSub, ALUOpMul, ALUOpDiv, ALUOpOr, ALUOpAnd, ALUOpShiftLeft, ALUOpShiftRight, ALUOpMod, ALUOpXor: case ALUOpAdd, ALUOpSub, ALUOpMul, ALUOpDiv, ALUOpOr, ALUOpAnd, ALUOpShiftLeft, ALUOpShiftRight, ALUOpMod, ALUOpXor:
if ri.Op&opMaskOperandSrc != 0 { switch operand := opOperand(ri.Op & opMaskOperand); operand {
case opOperandX:
return ALUOpX{Op: op} return ALUOpX{Op: op}
case opOperandConstant:
return ALUOpConstant{Op: op, Val: ri.K}
default:
return ri
} }
return ALUOpConstant{Op: op, Val: ri.K}
case aluOpNeg: case aluOpNeg:
return NegateA{} return NegateA{}
default: default:
@ -97,39 +104,18 @@ func (ri RawInstruction) Disassemble() Instruction {
} }
case opClsJump: case opClsJump:
if ri.Op&opMaskJumpConst != opClsJump { switch op := jumpOp(ri.Op & opMaskOperator); op {
return ri
}
switch ri.Op & opMaskJumpCond {
case opJumpAlways: case opJumpAlways:
return Jump{Skip: ri.K} return Jump{Skip: ri.K}
case opJumpEqual: case opJumpEqual, opJumpGT, opJumpGE, opJumpSet:
return JumpIf{ cond, skipTrue, skipFalse := jumpOpToTest(op, ri.Jt, ri.Jf)
Cond: JumpEqual, switch operand := opOperand(ri.Op & opMaskOperand); operand {
Val: ri.K, case opOperandX:
SkipTrue: ri.Jt, return JumpIfX{Cond: cond, SkipTrue: skipTrue, SkipFalse: skipFalse}
SkipFalse: ri.Jf, case opOperandConstant:
} return JumpIf{Cond: cond, Val: ri.K, SkipTrue: skipTrue, SkipFalse: skipFalse}
case opJumpGT: default:
return JumpIf{ return ri
Cond: JumpGreaterThan,
Val: ri.K,
SkipTrue: ri.Jt,
SkipFalse: ri.Jf,
}
case opJumpGE:
return JumpIf{
Cond: JumpGreaterOrEqual,
Val: ri.K,
SkipTrue: ri.Jt,
SkipFalse: ri.Jf,
}
case opJumpSet:
return JumpIf{
Cond: JumpBitsSet,
Val: ri.K,
SkipTrue: ri.Jt,
SkipFalse: ri.Jf,
} }
default: default:
return ri return ri
@ -160,6 +146,41 @@ func (ri RawInstruction) Disassemble() Instruction {
} }
} }
func jumpOpToTest(op jumpOp, skipTrue uint8, skipFalse uint8) (JumpTest, uint8, uint8) {
var test JumpTest
// Decode "fake" jump conditions that don't appear in machine code
// Ensures the Assemble -> Disassemble stage recreates the same instructions
// See https://github.com/golang/go/issues/18470
if skipTrue == 0 {
switch op {
case opJumpEqual:
test = JumpNotEqual
case opJumpGT:
test = JumpLessOrEqual
case opJumpGE:
test = JumpLessThan
case opJumpSet:
test = JumpBitsNotSet
}
return test, skipFalse, 0
}
switch op {
case opJumpEqual:
test = JumpEqual
case opJumpGT:
test = JumpGreaterThan
case opJumpGE:
test = JumpGreaterOrEqual
case opJumpSet:
test = JumpBitsSet
}
return test, skipTrue, skipFalse
}
// LoadConstant loads Val into register Dst. // LoadConstant loads Val into register Dst.
type LoadConstant struct { type LoadConstant struct {
Dst Register Dst Register
@ -171,6 +192,18 @@ func (a LoadConstant) Assemble() (RawInstruction, error) {
return assembleLoad(a.Dst, 4, opAddrModeImmediate, a.Val) return assembleLoad(a.Dst, 4, opAddrModeImmediate, a.Val)
} }
// String returns the instruction in assembler notation.
func (a LoadConstant) String() string {
switch a.Dst {
case RegA:
return fmt.Sprintf("ld #%d", a.Val)
case RegX:
return fmt.Sprintf("ldx #%d", a.Val)
default:
return fmt.Sprintf("unknown instruction: %#v", a)
}
}
// LoadScratch loads scratch[N] into register Dst. // LoadScratch loads scratch[N] into register Dst.
type LoadScratch struct { type LoadScratch struct {
Dst Register Dst Register
@ -185,6 +218,18 @@ func (a LoadScratch) Assemble() (RawInstruction, error) {
return assembleLoad(a.Dst, 4, opAddrModeScratch, uint32(a.N)) return assembleLoad(a.Dst, 4, opAddrModeScratch, uint32(a.N))
} }
// String returns the instruction in assembler notation.
func (a LoadScratch) String() string {
switch a.Dst {
case RegA:
return fmt.Sprintf("ld M[%d]", a.N)
case RegX:
return fmt.Sprintf("ldx M[%d]", a.N)
default:
return fmt.Sprintf("unknown instruction: %#v", a)
}
}
// LoadAbsolute loads packet[Off:Off+Size] as an integer value into // LoadAbsolute loads packet[Off:Off+Size] as an integer value into
// register A. // register A.
type LoadAbsolute struct { type LoadAbsolute struct {
@ -197,6 +242,23 @@ func (a LoadAbsolute) Assemble() (RawInstruction, error) {
return assembleLoad(RegA, a.Size, opAddrModeAbsolute, a.Off) return assembleLoad(RegA, a.Size, opAddrModeAbsolute, a.Off)
} }
// String returns the instruction in assembler notation.
func (a LoadAbsolute) String() string {
switch a.Size {
case 1: // byte
return fmt.Sprintf("ldb [%d]", a.Off)
case 2: // half word
return fmt.Sprintf("ldh [%d]", a.Off)
case 4: // word
if a.Off > extOffset+0xffffffff {
return LoadExtension{Num: Extension(a.Off + 0x1000)}.String()
}
return fmt.Sprintf("ld [%d]", a.Off)
default:
return fmt.Sprintf("unknown instruction: %#v", a)
}
}
// LoadIndirect loads packet[X+Off:X+Off+Size] as an integer value // LoadIndirect loads packet[X+Off:X+Off+Size] as an integer value
// into register A. // into register A.
type LoadIndirect struct { type LoadIndirect struct {
@ -209,6 +271,20 @@ func (a LoadIndirect) Assemble() (RawInstruction, error) {
return assembleLoad(RegA, a.Size, opAddrModeIndirect, a.Off) return assembleLoad(RegA, a.Size, opAddrModeIndirect, a.Off)
} }
// String returns the instruction in assembler notation.
func (a LoadIndirect) String() string {
switch a.Size {
case 1: // byte
return fmt.Sprintf("ldb [x + %d]", a.Off)
case 2: // half word
return fmt.Sprintf("ldh [x + %d]", a.Off)
case 4: // word
return fmt.Sprintf("ld [x + %d]", a.Off)
default:
return fmt.Sprintf("unknown instruction: %#v", a)
}
}
// LoadMemShift multiplies the first 4 bits of the byte at packet[Off] // LoadMemShift multiplies the first 4 bits of the byte at packet[Off]
// by 4 and stores the result in register X. // by 4 and stores the result in register X.
// //
@ -224,6 +300,11 @@ func (a LoadMemShift) Assemble() (RawInstruction, error) {
return assembleLoad(RegX, 1, opAddrModeMemShift, a.Off) return assembleLoad(RegX, 1, opAddrModeMemShift, a.Off)
} }
// String returns the instruction in assembler notation.
func (a LoadMemShift) String() string {
return fmt.Sprintf("ldx 4*([%d]&0xf)", a.Off)
}
// LoadExtension invokes a linux-specific extension and stores the // LoadExtension invokes a linux-specific extension and stores the
// result in register A. // result in register A.
type LoadExtension struct { type LoadExtension struct {
@ -235,7 +316,47 @@ func (a LoadExtension) Assemble() (RawInstruction, error) {
if a.Num == ExtLen { if a.Num == ExtLen {
return assembleLoad(RegA, 4, opAddrModePacketLen, 0) return assembleLoad(RegA, 4, opAddrModePacketLen, 0)
} }
return assembleLoad(RegA, 4, opAddrModeAbsolute, uint32(-0x1000+a.Num)) return assembleLoad(RegA, 4, opAddrModeAbsolute, uint32(extOffset+a.Num))
}
// String returns the instruction in assembler notation.
func (a LoadExtension) String() string {
switch a.Num {
case ExtLen:
return "ld #len"
case ExtProto:
return "ld #proto"
case ExtType:
return "ld #type"
case ExtPayloadOffset:
return "ld #poff"
case ExtInterfaceIndex:
return "ld #ifidx"
case ExtNetlinkAttr:
return "ld #nla"
case ExtNetlinkAttrNested:
return "ld #nlan"
case ExtMark:
return "ld #mark"
case ExtQueue:
return "ld #queue"
case ExtLinkLayerType:
return "ld #hatype"
case ExtRXHash:
return "ld #rxhash"
case ExtCPUID:
return "ld #cpu"
case ExtVLANTag:
return "ld #vlan_tci"
case ExtVLANTagPresent:
return "ld #vlan_avail"
case ExtVLANProto:
return "ld #vlan_tpid"
case ExtRand:
return "ld #rand"
default:
return fmt.Sprintf("unknown instruction: %#v", a)
}
} }
// StoreScratch stores register Src into scratch[N]. // StoreScratch stores register Src into scratch[N].
@ -265,6 +386,18 @@ func (a StoreScratch) Assemble() (RawInstruction, error) {
}, nil }, nil
} }
// String returns the instruction in assembler notation.
func (a StoreScratch) String() string {
switch a.Src {
case RegA:
return fmt.Sprintf("st M[%d]", a.N)
case RegX:
return fmt.Sprintf("stx M[%d]", a.N)
default:
return fmt.Sprintf("unknown instruction: %#v", a)
}
}
// ALUOpConstant executes A = A <Op> Val. // ALUOpConstant executes A = A <Op> Val.
type ALUOpConstant struct { type ALUOpConstant struct {
Op ALUOp Op ALUOp
@ -274,11 +407,39 @@ type ALUOpConstant struct {
// Assemble implements the Instruction Assemble method. // Assemble implements the Instruction Assemble method.
func (a ALUOpConstant) Assemble() (RawInstruction, error) { func (a ALUOpConstant) Assemble() (RawInstruction, error) {
return RawInstruction{ return RawInstruction{
Op: opClsALU | opALUSrcConstant | uint16(a.Op), Op: opClsALU | uint16(opOperandConstant) | uint16(a.Op),
K: a.Val, K: a.Val,
}, nil }, nil
} }
// String returns the instruction in assembler notation.
func (a ALUOpConstant) String() string {
switch a.Op {
case ALUOpAdd:
return fmt.Sprintf("add #%d", a.Val)
case ALUOpSub:
return fmt.Sprintf("sub #%d", a.Val)
case ALUOpMul:
return fmt.Sprintf("mul #%d", a.Val)
case ALUOpDiv:
return fmt.Sprintf("div #%d", a.Val)
case ALUOpMod:
return fmt.Sprintf("mod #%d", a.Val)
case ALUOpAnd:
return fmt.Sprintf("and #%d", a.Val)
case ALUOpOr:
return fmt.Sprintf("or #%d", a.Val)
case ALUOpXor:
return fmt.Sprintf("xor #%d", a.Val)
case ALUOpShiftLeft:
return fmt.Sprintf("lsh #%d", a.Val)
case ALUOpShiftRight:
return fmt.Sprintf("rsh #%d", a.Val)
default:
return fmt.Sprintf("unknown instruction: %#v", a)
}
}
// ALUOpX executes A = A <Op> X // ALUOpX executes A = A <Op> X
type ALUOpX struct { type ALUOpX struct {
Op ALUOp Op ALUOp
@ -287,10 +448,38 @@ type ALUOpX struct {
// Assemble implements the Instruction Assemble method. // Assemble implements the Instruction Assemble method.
func (a ALUOpX) Assemble() (RawInstruction, error) { func (a ALUOpX) Assemble() (RawInstruction, error) {
return RawInstruction{ return RawInstruction{
Op: opClsALU | opALUSrcX | uint16(a.Op), Op: opClsALU | uint16(opOperandX) | uint16(a.Op),
}, nil }, nil
} }
// String returns the instruction in assembler notation.
func (a ALUOpX) String() string {
switch a.Op {
case ALUOpAdd:
return "add x"
case ALUOpSub:
return "sub x"
case ALUOpMul:
return "mul x"
case ALUOpDiv:
return "div x"
case ALUOpMod:
return "mod x"
case ALUOpAnd:
return "and x"
case ALUOpOr:
return "or x"
case ALUOpXor:
return "xor x"
case ALUOpShiftLeft:
return "lsh x"
case ALUOpShiftRight:
return "rsh x"
default:
return fmt.Sprintf("unknown instruction: %#v", a)
}
}
// NegateA executes A = -A. // NegateA executes A = -A.
type NegateA struct{} type NegateA struct{}
@ -301,6 +490,11 @@ func (a NegateA) Assemble() (RawInstruction, error) {
}, nil }, nil
} }
// String returns the instruction in assembler notation.
func (a NegateA) String() string {
return fmt.Sprintf("neg")
}
// Jump skips the following Skip instructions in the program. // Jump skips the following Skip instructions in the program.
type Jump struct { type Jump struct {
Skip uint32 Skip uint32
@ -309,11 +503,16 @@ type Jump struct {
// Assemble implements the Instruction Assemble method. // Assemble implements the Instruction Assemble method.
func (a Jump) Assemble() (RawInstruction, error) { func (a Jump) Assemble() (RawInstruction, error) {
return RawInstruction{ return RawInstruction{
Op: opClsJump | opJumpAlways, Op: opClsJump | uint16(opJumpAlways),
K: a.Skip, K: a.Skip,
}, nil }, nil
} }
// String returns the instruction in assembler notation.
func (a Jump) String() string {
return fmt.Sprintf("ja %d", a.Skip)
}
// JumpIf skips the following Skip instructions in the program if A // JumpIf skips the following Skip instructions in the program if A
// <Cond> Val is true. // <Cond> Val is true.
type JumpIf struct { type JumpIf struct {
@ -325,11 +524,39 @@ type JumpIf struct {
// Assemble implements the Instruction Assemble method. // Assemble implements the Instruction Assemble method.
func (a JumpIf) Assemble() (RawInstruction, error) { func (a JumpIf) Assemble() (RawInstruction, error) {
return jumpToRaw(a.Cond, opOperandConstant, a.Val, a.SkipTrue, a.SkipFalse)
}
// String returns the instruction in assembler notation.
func (a JumpIf) String() string {
return jumpToString(a.Cond, fmt.Sprintf("#%d", a.Val), a.SkipTrue, a.SkipFalse)
}
// JumpIfX skips the following Skip instructions in the program if A
// <Cond> X is true.
type JumpIfX struct {
Cond JumpTest
SkipTrue uint8
SkipFalse uint8
}
// Assemble implements the Instruction Assemble method.
func (a JumpIfX) Assemble() (RawInstruction, error) {
return jumpToRaw(a.Cond, opOperandX, 0, a.SkipTrue, a.SkipFalse)
}
// String returns the instruction in assembler notation.
func (a JumpIfX) String() string {
return jumpToString(a.Cond, "x", a.SkipTrue, a.SkipFalse)
}
// jumpToRaw assembles a jump instruction into a RawInstruction
func jumpToRaw(test JumpTest, operand opOperand, k uint32, skipTrue, skipFalse uint8) (RawInstruction, error) {
var ( var (
cond uint16 cond jumpOp
flip bool flip bool
) )
switch a.Cond { switch test {
case JumpEqual: case JumpEqual:
cond = opJumpEqual cond = opJumpEqual
case JumpNotEqual: case JumpNotEqual:
@ -347,20 +574,65 @@ func (a JumpIf) Assemble() (RawInstruction, error) {
case JumpBitsNotSet: case JumpBitsNotSet:
cond, flip = opJumpSet, true cond, flip = opJumpSet, true
default: default:
return RawInstruction{}, fmt.Errorf("unknown JumpTest %v", a.Cond) return RawInstruction{}, fmt.Errorf("unknown JumpTest %v", test)
} }
jt, jf := a.SkipTrue, a.SkipFalse jt, jf := skipTrue, skipFalse
if flip { if flip {
jt, jf = jf, jt jt, jf = jf, jt
} }
return RawInstruction{ return RawInstruction{
Op: opClsJump | cond, Op: opClsJump | uint16(cond) | uint16(operand),
Jt: jt, Jt: jt,
Jf: jf, Jf: jf,
K: a.Val, K: k,
}, nil }, nil
} }
// jumpToString converts a jump instruction to assembler notation
func jumpToString(cond JumpTest, operand string, skipTrue, skipFalse uint8) string {
switch cond {
// K == A
case JumpEqual:
return conditionalJump(operand, skipTrue, skipFalse, "jeq", "jneq")
// K != A
case JumpNotEqual:
return fmt.Sprintf("jneq %s,%d", operand, skipTrue)
// K > A
case JumpGreaterThan:
return conditionalJump(operand, skipTrue, skipFalse, "jgt", "jle")
// K < A
case JumpLessThan:
return fmt.Sprintf("jlt %s,%d", operand, skipTrue)
// K >= A
case JumpGreaterOrEqual:
return conditionalJump(operand, skipTrue, skipFalse, "jge", "jlt")
// K <= A
case JumpLessOrEqual:
return fmt.Sprintf("jle %s,%d", operand, skipTrue)
// K & A != 0
case JumpBitsSet:
if skipFalse > 0 {
return fmt.Sprintf("jset %s,%d,%d", operand, skipTrue, skipFalse)
}
return fmt.Sprintf("jset %s,%d", operand, skipTrue)
// K & A == 0, there is no assembler instruction for JumpBitNotSet, use JumpBitSet and invert skips
case JumpBitsNotSet:
return jumpToString(JumpBitsSet, operand, skipFalse, skipTrue)
default:
return fmt.Sprintf("unknown JumpTest %#v", cond)
}
}
func conditionalJump(operand string, skipTrue, skipFalse uint8, positiveJump, negativeJump string) string {
if skipTrue > 0 {
if skipFalse > 0 {
return fmt.Sprintf("%s %s,%d,%d", positiveJump, operand, skipTrue, skipFalse)
}
return fmt.Sprintf("%s %s,%d", positiveJump, operand, skipTrue)
}
return fmt.Sprintf("%s %s,%d", negativeJump, operand, skipFalse)
}
// RetA exits the BPF program, returning the value of register A. // RetA exits the BPF program, returning the value of register A.
type RetA struct{} type RetA struct{}
@ -371,6 +643,11 @@ func (a RetA) Assemble() (RawInstruction, error) {
}, nil }, nil
} }
// String returns the instruction in assembler notation.
func (a RetA) String() string {
return fmt.Sprintf("ret a")
}
// RetConstant exits the BPF program, returning a constant value. // RetConstant exits the BPF program, returning a constant value.
type RetConstant struct { type RetConstant struct {
Val uint32 Val uint32
@ -384,6 +661,11 @@ func (a RetConstant) Assemble() (RawInstruction, error) {
}, nil }, nil
} }
// String returns the instruction in assembler notation.
func (a RetConstant) String() string {
return fmt.Sprintf("ret #%d", a.Val)
}
// TXA copies the value of register X to register A. // TXA copies the value of register X to register A.
type TXA struct{} type TXA struct{}
@ -394,6 +676,11 @@ func (a TXA) Assemble() (RawInstruction, error) {
}, nil }, nil
} }
// String returns the instruction in assembler notation.
func (a TXA) String() string {
return fmt.Sprintf("txa")
}
// TAX copies the value of register A to register X. // TAX copies the value of register A to register X.
type TAX struct{} type TAX struct{}
@ -404,6 +691,11 @@ func (a TAX) Assemble() (RawInstruction, error) {
}, nil }, nil
} }
// String returns the instruction in assembler notation.
func (a TAX) String() string {
return fmt.Sprintf("tax")
}
func assembleLoad(dst Register, loadSize int, mode uint16, k uint32) (RawInstruction, error) { func assembleLoad(dst Register, loadSize int, mode uint16, k uint32) (RawInstruction, error) {
var ( var (
cls uint16 cls uint16

10
vendor/golang.org/x/net/bpf/setter.go generated vendored Normal file
View File

@ -0,0 +1,10 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package bpf
// A Setter is a type which can attach a compiled BPF filter to itself.
type Setter interface {
SetBPF(filter []RawInstruction) error
}

10
vendor/golang.org/x/net/bpf/vm.go generated vendored
View File

@ -35,6 +35,13 @@ func NewVM(filter []Instruction) (*VM, error) {
if check <= int(ins.SkipFalse) { if check <= int(ins.SkipFalse) {
return nil, fmt.Errorf("cannot jump %d instructions in false case; jumping past program bounds", ins.SkipFalse) return nil, fmt.Errorf("cannot jump %d instructions in false case; jumping past program bounds", ins.SkipFalse)
} }
case JumpIfX:
if check <= int(ins.SkipTrue) {
return nil, fmt.Errorf("cannot jump %d instructions in true case; jumping past program bounds", ins.SkipTrue)
}
if check <= int(ins.SkipFalse) {
return nil, fmt.Errorf("cannot jump %d instructions in false case; jumping past program bounds", ins.SkipFalse)
}
// Check for division or modulus by zero // Check for division or modulus by zero
case ALUOpConstant: case ALUOpConstant:
if ins.Val != 0 { if ins.Val != 0 {
@ -109,6 +116,9 @@ func (v *VM) Run(in []byte) (int, error) {
case JumpIf: case JumpIf:
jump := jumpIf(ins, regA) jump := jumpIf(ins, regA)
i += jump i += jump
case JumpIfX:
jump := jumpIfX(ins, regA, regX)
i += jump
case LoadAbsolute: case LoadAbsolute:
regA, ok = loadAbsolute(ins, in) regA, ok = loadAbsolute(ins, in)
case LoadConstant: case LoadConstant:

View File

@ -55,34 +55,41 @@ func aluOpCommon(op ALUOp, regA uint32, value uint32) uint32 {
} }
} }
func jumpIf(ins JumpIf, value uint32) int { func jumpIf(ins JumpIf, regA uint32) int {
var ok bool return jumpIfCommon(ins.Cond, ins.SkipTrue, ins.SkipFalse, regA, ins.Val)
inV := uint32(ins.Val) }
switch ins.Cond { func jumpIfX(ins JumpIfX, regA uint32, regX uint32) int {
return jumpIfCommon(ins.Cond, ins.SkipTrue, ins.SkipFalse, regA, regX)
}
func jumpIfCommon(cond JumpTest, skipTrue, skipFalse uint8, regA uint32, value uint32) int {
var ok bool
switch cond {
case JumpEqual: case JumpEqual:
ok = value == inV ok = regA == value
case JumpNotEqual: case JumpNotEqual:
ok = value != inV ok = regA != value
case JumpGreaterThan: case JumpGreaterThan:
ok = value > inV ok = regA > value
case JumpLessThan: case JumpLessThan:
ok = value < inV ok = regA < value
case JumpGreaterOrEqual: case JumpGreaterOrEqual:
ok = value >= inV ok = regA >= value
case JumpLessOrEqual: case JumpLessOrEqual:
ok = value <= inV ok = regA <= value
case JumpBitsSet: case JumpBitsSet:
ok = (value & inV) != 0 ok = (regA & value) != 0
case JumpBitsNotSet: case JumpBitsNotSet:
ok = (value & inV) == 0 ok = (regA & value) == 0
} }
if ok { if ok {
return int(ins.SkipTrue) return int(skipTrue)
} }
return int(ins.SkipFalse) return int(skipFalse)
} }
func loadAbsolute(ins LoadAbsolute, in []byte) (uint32, bool) { func loadAbsolute(ins LoadAbsolute, in []byte) (uint32, bool) {

View File

@ -1,44 +1,40 @@
// go generate gen.go // go generate gen.go
// GENERATED BY THE COMMAND ABOVE; DO NOT EDIT // Code generated by the command above; DO NOT EDIT.
// Package iana provides protocol number resources managed by the Internet Assigned Numbers Authority (IANA). // Package iana provides protocol number resources managed by the Internet Assigned Numbers Authority (IANA).
package iana package iana
// Differentiated Services Field Codepoints (DSCP), Updated: 2013-06-25 // Differentiated Services Field Codepoints (DSCP), Updated: 2018-05-04
const ( const (
DiffServCS0 = 0x0 // CS0 DiffServCS0 = 0x00 // CS0
DiffServCS1 = 0x20 // CS1 DiffServCS1 = 0x20 // CS1
DiffServCS2 = 0x40 // CS2 DiffServCS2 = 0x40 // CS2
DiffServCS3 = 0x60 // CS3 DiffServCS3 = 0x60 // CS3
DiffServCS4 = 0x80 // CS4 DiffServCS4 = 0x80 // CS4
DiffServCS5 = 0xa0 // CS5 DiffServCS5 = 0xa0 // CS5
DiffServCS6 = 0xc0 // CS6 DiffServCS6 = 0xc0 // CS6
DiffServCS7 = 0xe0 // CS7 DiffServCS7 = 0xe0 // CS7
DiffServAF11 = 0x28 // AF11 DiffServAF11 = 0x28 // AF11
DiffServAF12 = 0x30 // AF12 DiffServAF12 = 0x30 // AF12
DiffServAF13 = 0x38 // AF13 DiffServAF13 = 0x38 // AF13
DiffServAF21 = 0x48 // AF21 DiffServAF21 = 0x48 // AF21
DiffServAF22 = 0x50 // AF22 DiffServAF22 = 0x50 // AF22
DiffServAF23 = 0x58 // AF23 DiffServAF23 = 0x58 // AF23
DiffServAF31 = 0x68 // AF31 DiffServAF31 = 0x68 // AF31
DiffServAF32 = 0x70 // AF32 DiffServAF32 = 0x70 // AF32
DiffServAF33 = 0x78 // AF33 DiffServAF33 = 0x78 // AF33
DiffServAF41 = 0x88 // AF41 DiffServAF41 = 0x88 // AF41
DiffServAF42 = 0x90 // AF42 DiffServAF42 = 0x90 // AF42
DiffServAF43 = 0x98 // AF43 DiffServAF43 = 0x98 // AF43
DiffServEFPHB = 0xb8 // EF PHB DiffServEF = 0xb8 // EF
DiffServVOICEADMIT = 0xb0 // VOICE-ADMIT DiffServVOICEADMIT = 0xb0 // VOICE-ADMIT
NotECNTransport = 0x00 // Not-ECT (Not ECN-Capable Transport)
ECNTransport1 = 0x01 // ECT(1) (ECN-Capable Transport(1))
ECNTransport0 = 0x02 // ECT(0) (ECN-Capable Transport(0))
CongestionExperienced = 0x03 // CE (Congestion Experienced)
) )
// IPv4 TOS Byte and IPv6 Traffic Class Octet, Updated: 2001-09-06 // Protocol Numbers, Updated: 2017-10-13
const (
NotECNTransport = 0x0 // Not-ECT (Not ECN-Capable Transport)
ECNTransport1 = 0x1 // ECT(1) (ECN-Capable Transport(1))
ECNTransport0 = 0x2 // ECT(0) (ECN-Capable Transport(0))
CongestionExperienced = 0x3 // CE (Congestion Experienced)
)
// Protocol Numbers, Updated: 2015-10-06
const ( const (
ProtocolIP = 0 // IPv4 encapsulation, pseudo protocol number ProtocolIP = 0 // IPv4 encapsulation, pseudo protocol number
ProtocolHOPOPT = 0 // IPv6 Hop-by-Hop Option ProtocolHOPOPT = 0 // IPv6 Hop-by-Hop Option
@ -178,3 +174,50 @@ const (
ProtocolROHC = 142 // Robust Header Compression ProtocolROHC = 142 // Robust Header Compression
ProtocolReserved = 255 // Reserved ProtocolReserved = 255 // Reserved
) )
// Address Family Numbers, Updated: 2018-04-02
const (
AddrFamilyIPv4 = 1 // IP (IP version 4)
AddrFamilyIPv6 = 2 // IP6 (IP version 6)
AddrFamilyNSAP = 3 // NSAP
AddrFamilyHDLC = 4 // HDLC (8-bit multidrop)
AddrFamilyBBN1822 = 5 // BBN 1822
AddrFamily802 = 6 // 802 (includes all 802 media plus Ethernet "canonical format")
AddrFamilyE163 = 7 // E.163
AddrFamilyE164 = 8 // E.164 (SMDS, Frame Relay, ATM)
AddrFamilyF69 = 9 // F.69 (Telex)
AddrFamilyX121 = 10 // X.121 (X.25, Frame Relay)
AddrFamilyIPX = 11 // IPX
AddrFamilyAppletalk = 12 // Appletalk
AddrFamilyDecnetIV = 13 // Decnet IV
AddrFamilyBanyanVines = 14 // Banyan Vines
AddrFamilyE164withSubaddress = 15 // E.164 with NSAP format subaddress
AddrFamilyDNS = 16 // DNS (Domain Name System)
AddrFamilyDistinguishedName = 17 // Distinguished Name
AddrFamilyASNumber = 18 // AS Number
AddrFamilyXTPoverIPv4 = 19 // XTP over IP version 4
AddrFamilyXTPoverIPv6 = 20 // XTP over IP version 6
AddrFamilyXTPnativemodeXTP = 21 // XTP native mode XTP
AddrFamilyFibreChannelWorldWidePortName = 22 // Fibre Channel World-Wide Port Name
AddrFamilyFibreChannelWorldWideNodeName = 23 // Fibre Channel World-Wide Node Name
AddrFamilyGWID = 24 // GWID
AddrFamilyL2VPN = 25 // AFI for L2VPN information
AddrFamilyMPLSTPSectionEndpointID = 26 // MPLS-TP Section Endpoint Identifier
AddrFamilyMPLSTPLSPEndpointID = 27 // MPLS-TP LSP Endpoint Identifier
AddrFamilyMPLSTPPseudowireEndpointID = 28 // MPLS-TP Pseudowire Endpoint Identifier
AddrFamilyMTIPv4 = 29 // MT IP: Multi-Topology IP version 4
AddrFamilyMTIPv6 = 30 // MT IPv6: Multi-Topology IP version 6
AddrFamilyEIGRPCommonServiceFamily = 16384 // EIGRP Common Service Family
AddrFamilyEIGRPIPv4ServiceFamily = 16385 // EIGRP IPv4 Service Family
AddrFamilyEIGRPIPv6ServiceFamily = 16386 // EIGRP IPv6 Service Family
AddrFamilyLISPCanonicalAddressFormat = 16387 // LISP Canonical Address Format (LCAF)
AddrFamilyBGPLS = 16388 // BGP-LS
AddrFamily48bitMAC = 16389 // 48-bit MAC
AddrFamily64bitMAC = 16390 // 64-bit MAC
AddrFamilyOUI = 16391 // OUI
AddrFamilyMACFinal24bits = 16392 // MAC/24
AddrFamilyMACFinal40bits = 16393 // MAC/40
AddrFamilyIPv6Initial64bits = 16394 // IPv6/64
AddrFamilyRBridgePortID = 16395 // RBridge Port ID
AddrFamilyTRILLNickname = 16396 // TRILL Nickname
)

View File

@ -1,4 +1,4 @@
// Copyright 2013 The Go Authors. All rights reserved. // Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
@ -28,23 +28,23 @@ var registries = []struct {
parse func(io.Writer, io.Reader) error parse func(io.Writer, io.Reader) error
}{ }{
{ {
"http://www.iana.org/assignments/dscp-registry/dscp-registry.xml", "https://www.iana.org/assignments/dscp-registry/dscp-registry.xml",
parseDSCPRegistry, parseDSCPRegistry,
}, },
{ {
"http://www.iana.org/assignments/ipv4-tos-byte/ipv4-tos-byte.xml", "https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xml",
parseTOSTCByte, parseProtocolNumbers,
}, },
{ {
"http://www.iana.org/assignments/protocol-numbers/protocol-numbers.xml", "https://www.iana.org/assignments/address-family-numbers/address-family-numbers.xml",
parseProtocolNumbers, parseAddrFamilyNumbers,
}, },
} }
func main() { func main() {
var bb bytes.Buffer var bb bytes.Buffer
fmt.Fprintf(&bb, "// go generate gen.go\n") fmt.Fprintf(&bb, "// go generate gen.go\n")
fmt.Fprintf(&bb, "// GENERATED BY THE COMMAND ABOVE; DO NOT EDIT\n\n") fmt.Fprintf(&bb, "// Code generated by the command above; DO NOT EDIT.\n\n")
fmt.Fprintf(&bb, "// Package iana provides protocol number resources managed by the Internet Assigned Numbers Authority (IANA).\n") fmt.Fprintf(&bb, "// Package iana provides protocol number resources managed by the Internet Assigned Numbers Authority (IANA).\n")
fmt.Fprintf(&bb, `package iana // import "golang.org/x/net/internal/iana"`+"\n\n") fmt.Fprintf(&bb, `package iana // import "golang.org/x/net/internal/iana"`+"\n\n")
for _, r := range registries { for _, r := range registries {
@ -81,31 +81,39 @@ func parseDSCPRegistry(w io.Writer, r io.Reader) error {
if err := dec.Decode(&dr); err != nil { if err := dec.Decode(&dr); err != nil {
return err return err
} }
drs := dr.escape()
fmt.Fprintf(w, "// %s, Updated: %s\n", dr.Title, dr.Updated) fmt.Fprintf(w, "// %s, Updated: %s\n", dr.Title, dr.Updated)
fmt.Fprintf(w, "const (\n") fmt.Fprintf(w, "const (\n")
for _, dr := range drs { for _, dr := range dr.escapeDSCP() {
fmt.Fprintf(w, "DiffServ%s = %#x", dr.Name, dr.Value) fmt.Fprintf(w, "DiffServ%s = %#02x", dr.Name, dr.Value)
fmt.Fprintf(w, "// %s\n", dr.OrigName) fmt.Fprintf(w, "// %s\n", dr.OrigName)
} }
for _, er := range dr.escapeECN() {
fmt.Fprintf(w, "%s = %#02x", er.Descr, er.Value)
fmt.Fprintf(w, "// %s\n", er.OrigDescr)
}
fmt.Fprintf(w, ")\n") fmt.Fprintf(w, ")\n")
return nil return nil
} }
type dscpRegistry struct { type dscpRegistry struct {
XMLName xml.Name `xml:"registry"` XMLName xml.Name `xml:"registry"`
Title string `xml:"title"` Title string `xml:"title"`
Updated string `xml:"updated"` Updated string `xml:"updated"`
Note string `xml:"note"` Note string `xml:"note"`
RegTitle string `xml:"registry>title"` Registries []struct {
PoolRecords []struct { Title string `xml:"title"`
Name string `xml:"name"` Registries []struct {
Space string `xml:"space"` Title string `xml:"title"`
} `xml:"registry>record"` Records []struct {
Records []struct { Name string `xml:"name"`
Name string `xml:"name"` Space string `xml:"space"`
Space string `xml:"space"` } `xml:"record"`
} `xml:"registry>registry>record"` } `xml:"registry"`
Records []struct {
Value string `xml:"value"`
Descr string `xml:"description"`
} `xml:"record"`
} `xml:"registry"`
} }
type canonDSCPRecord struct { type canonDSCPRecord struct {
@ -114,92 +122,84 @@ type canonDSCPRecord struct {
Value int Value int
} }
func (drr *dscpRegistry) escape() []canonDSCPRecord { func (drr *dscpRegistry) escapeDSCP() []canonDSCPRecord {
drs := make([]canonDSCPRecord, len(drr.Records)) var drs []canonDSCPRecord
sr := strings.NewReplacer( for _, preg := range drr.Registries {
"+", "", if !strings.Contains(preg.Title, "Differentiated Services Field Codepoints") {
"-", "",
"/", "",
".", "",
" ", "",
)
for i, dr := range drr.Records {
s := strings.TrimSpace(dr.Name)
drs[i].OrigName = s
drs[i].Name = sr.Replace(s)
n, err := strconv.ParseUint(dr.Space, 2, 8)
if err != nil {
continue continue
} }
drs[i].Value = int(n) << 2 for _, reg := range preg.Registries {
if !strings.Contains(reg.Title, "Pool 1 Codepoints") {
continue
}
drs = make([]canonDSCPRecord, len(reg.Records))
sr := strings.NewReplacer(
"+", "",
"-", "",
"/", "",
".", "",
" ", "",
)
for i, dr := range reg.Records {
s := strings.TrimSpace(dr.Name)
drs[i].OrigName = s
drs[i].Name = sr.Replace(s)
n, err := strconv.ParseUint(dr.Space, 2, 8)
if err != nil {
continue
}
drs[i].Value = int(n) << 2
}
}
} }
return drs return drs
} }
func parseTOSTCByte(w io.Writer, r io.Reader) error { type canonECNRecord struct {
dec := xml.NewDecoder(r) OrigDescr string
var ttb tosTCByte Descr string
if err := dec.Decode(&ttb); err != nil { Value int
return err
}
trs := ttb.escape()
fmt.Fprintf(w, "// %s, Updated: %s\n", ttb.Title, ttb.Updated)
fmt.Fprintf(w, "const (\n")
for _, tr := range trs {
fmt.Fprintf(w, "%s = %#x", tr.Keyword, tr.Value)
fmt.Fprintf(w, "// %s\n", tr.OrigKeyword)
}
fmt.Fprintf(w, ")\n")
return nil
} }
type tosTCByte struct { func (drr *dscpRegistry) escapeECN() []canonECNRecord {
XMLName xml.Name `xml:"registry"` var ers []canonECNRecord
Title string `xml:"title"` for _, reg := range drr.Registries {
Updated string `xml:"updated"` if !strings.Contains(reg.Title, "ECN Field") {
Note string `xml:"note"`
RegTitle string `xml:"registry>title"`
Records []struct {
Binary string `xml:"binary"`
Keyword string `xml:"keyword"`
} `xml:"registry>record"`
}
type canonTOSTCByteRecord struct {
OrigKeyword string
Keyword string
Value int
}
func (ttb *tosTCByte) escape() []canonTOSTCByteRecord {
trs := make([]canonTOSTCByteRecord, len(ttb.Records))
sr := strings.NewReplacer(
"Capable", "",
"(", "",
")", "",
"+", "",
"-", "",
"/", "",
".", "",
" ", "",
)
for i, tr := range ttb.Records {
s := strings.TrimSpace(tr.Keyword)
trs[i].OrigKeyword = s
ss := strings.Split(s, " ")
if len(ss) > 1 {
trs[i].Keyword = strings.Join(ss[1:], " ")
} else {
trs[i].Keyword = ss[0]
}
trs[i].Keyword = sr.Replace(trs[i].Keyword)
n, err := strconv.ParseUint(tr.Binary, 2, 8)
if err != nil {
continue continue
} }
trs[i].Value = int(n) ers = make([]canonECNRecord, len(reg.Records))
sr := strings.NewReplacer(
"Capable", "",
"Not-ECT", "",
"ECT(1)", "",
"ECT(0)", "",
"CE", "",
"(", "",
")", "",
"+", "",
"-", "",
"/", "",
".", "",
" ", "",
)
for i, er := range reg.Records {
s := strings.TrimSpace(er.Descr)
ers[i].OrigDescr = s
ss := strings.Split(s, " ")
if len(ss) > 1 {
ers[i].Descr = strings.Join(ss[1:], " ")
} else {
ers[i].Descr = ss[0]
}
ers[i].Descr = sr.Replace(er.Descr)
n, err := strconv.ParseUint(er.Value, 2, 8)
if err != nil {
continue
}
ers[i].Value = int(n)
}
} }
return trs return ers
} }
func parseProtocolNumbers(w io.Writer, r io.Reader) error { func parseProtocolNumbers(w io.Writer, r io.Reader) error {
@ -291,3 +291,93 @@ func (pn *protocolNumbers) escape() []canonProtocolRecord {
} }
return prs return prs
} }
func parseAddrFamilyNumbers(w io.Writer, r io.Reader) error {
dec := xml.NewDecoder(r)
var afn addrFamilylNumbers
if err := dec.Decode(&afn); err != nil {
return err
}
afrs := afn.escape()
fmt.Fprintf(w, "// %s, Updated: %s\n", afn.Title, afn.Updated)
fmt.Fprintf(w, "const (\n")
for _, afr := range afrs {
if afr.Name == "" {
continue
}
fmt.Fprintf(w, "AddrFamily%s = %d", afr.Name, afr.Value)
fmt.Fprintf(w, "// %s\n", afr.Descr)
}
fmt.Fprintf(w, ")\n")
return nil
}
type addrFamilylNumbers struct {
XMLName xml.Name `xml:"registry"`
Title string `xml:"title"`
Updated string `xml:"updated"`
RegTitle string `xml:"registry>title"`
Note string `xml:"registry>note"`
Records []struct {
Value string `xml:"value"`
Descr string `xml:"description"`
} `xml:"registry>record"`
}
type canonAddrFamilyRecord struct {
Name string
Descr string
Value int
}
func (afn *addrFamilylNumbers) escape() []canonAddrFamilyRecord {
afrs := make([]canonAddrFamilyRecord, len(afn.Records))
sr := strings.NewReplacer(
"IP version 4", "IPv4",
"IP version 6", "IPv6",
"Identifier", "ID",
"-", "",
"-", "",
"/", "",
".", "",
" ", "",
)
for i, afr := range afn.Records {
if strings.Contains(afr.Descr, "Unassigned") ||
strings.Contains(afr.Descr, "Reserved") {
continue
}
afrs[i].Descr = afr.Descr
s := strings.TrimSpace(afr.Descr)
switch s {
case "IP (IP version 4)":
afrs[i].Name = "IPv4"
case "IP6 (IP version 6)":
afrs[i].Name = "IPv6"
case "AFI for L2VPN information":
afrs[i].Name = "L2VPN"
case "E.164 with NSAP format subaddress":
afrs[i].Name = "E164withSubaddress"
case "MT IP: Multi-Topology IP version 4":
afrs[i].Name = "MTIPv4"
case "MAC/24":
afrs[i].Name = "MACFinal24bits"
case "MAC/40":
afrs[i].Name = "MACFinal40bits"
case "IPv6/64":
afrs[i].Name = "IPv6Initial64bits"
default:
n := strings.Index(s, "(")
if n > 0 {
s = s[:n]
}
n = strings.Index(s, ":")
if n > 0 {
s = s[:n]
}
afrs[i].Name = sr.Replace(s)
}
afrs[i].Value, _ = strconv.Atoi(afr.Value)
}
return afrs
}

11
vendor/golang.org/x/net/internal/socket/cmsghdr.go generated vendored Normal file
View File

@ -0,0 +1,11 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build darwin dragonfly freebsd linux netbsd openbsd solaris
package socket
func (h *cmsghdr) len() int { return int(h.Len) }
func (h *cmsghdr) lvl() int { return int(h.Level) }
func (h *cmsghdr) typ() int { return int(h.Type) }

13
vendor/golang.org/x/net/internal/socket/cmsghdr_bsd.go generated vendored Normal file
View File

@ -0,0 +1,13 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build darwin dragonfly freebsd netbsd openbsd
package socket
func (h *cmsghdr) set(l, lvl, typ int) {
h.Len = uint32(l)
h.Level = int32(lvl)
h.Type = int32(typ)
}

View File

@ -0,0 +1,14 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build arm mips mipsle 386
// +build linux
package socket
func (h *cmsghdr) set(l, lvl, typ int) {
h.Len = uint32(l)
h.Level = int32(lvl)
h.Type = int32(typ)
}

View File

@ -0,0 +1,14 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build arm64 amd64 ppc64 ppc64le mips64 mips64le s390x
// +build linux
package socket
func (h *cmsghdr) set(l, lvl, typ int) {
h.Len = uint64(l)
h.Level = int32(lvl)
h.Type = int32(typ)
}

View File

@ -0,0 +1,14 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build amd64
// +build solaris
package socket
func (h *cmsghdr) set(l, lvl, typ int) {
h.Len = uint32(l)
h.Level = int32(lvl)
h.Type = int32(typ)
}

View File

@ -0,0 +1,17 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd,!solaris
package socket
type cmsghdr struct{}
const sizeofCmsghdr = 0
func (h *cmsghdr) len() int { return 0 }
func (h *cmsghdr) lvl() int { return 0 }
func (h *cmsghdr) typ() int { return 0 }
func (h *cmsghdr) set(l, lvl, typ int) {}

44
vendor/golang.org/x/net/internal/socket/defs_darwin.go generated vendored Normal file
View File

@ -0,0 +1,44 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build ignore
// +godefs map struct_in_addr [4]byte /* in_addr */
// +godefs map struct_in6_addr [16]byte /* in6_addr */
package socket
/*
#include <sys/socket.h>
#include <netinet/in.h>
*/
import "C"
const (
sysAF_UNSPEC = C.AF_UNSPEC
sysAF_INET = C.AF_INET
sysAF_INET6 = C.AF_INET6
sysSOCK_RAW = C.SOCK_RAW
)
type iovec C.struct_iovec
type msghdr C.struct_msghdr
type cmsghdr C.struct_cmsghdr
type sockaddrInet C.struct_sockaddr_in
type sockaddrInet6 C.struct_sockaddr_in6
const (
sizeofIovec = C.sizeof_struct_iovec
sizeofMsghdr = C.sizeof_struct_msghdr
sizeofCmsghdr = C.sizeof_struct_cmsghdr
sizeofSockaddrInet = C.sizeof_struct_sockaddr_in
sizeofSockaddrInet6 = C.sizeof_struct_sockaddr_in6
)

View File

@ -0,0 +1,44 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build ignore
// +godefs map struct_in_addr [4]byte /* in_addr */
// +godefs map struct_in6_addr [16]byte /* in6_addr */
package socket
/*
#include <sys/socket.h>
#include <netinet/in.h>
*/
import "C"
const (
sysAF_UNSPEC = C.AF_UNSPEC
sysAF_INET = C.AF_INET
sysAF_INET6 = C.AF_INET6
sysSOCK_RAW = C.SOCK_RAW
)
type iovec C.struct_iovec
type msghdr C.struct_msghdr
type cmsghdr C.struct_cmsghdr
type sockaddrInet C.struct_sockaddr_in
type sockaddrInet6 C.struct_sockaddr_in6
const (
sizeofIovec = C.sizeof_struct_iovec
sizeofMsghdr = C.sizeof_struct_msghdr
sizeofCmsghdr = C.sizeof_struct_cmsghdr
sizeofSockaddrInet = C.sizeof_struct_sockaddr_in
sizeofSockaddrInet6 = C.sizeof_struct_sockaddr_in6
)

View File

@ -0,0 +1,44 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build ignore
// +godefs map struct_in_addr [4]byte /* in_addr */
// +godefs map struct_in6_addr [16]byte /* in6_addr */
package socket
/*
#include <sys/socket.h>
#include <netinet/in.h>
*/
import "C"
const (
sysAF_UNSPEC = C.AF_UNSPEC
sysAF_INET = C.AF_INET
sysAF_INET6 = C.AF_INET6
sysSOCK_RAW = C.SOCK_RAW
)
type iovec C.struct_iovec
type msghdr C.struct_msghdr
type cmsghdr C.struct_cmsghdr
type sockaddrInet C.struct_sockaddr_in
type sockaddrInet6 C.struct_sockaddr_in6
const (
sizeofIovec = C.sizeof_struct_iovec
sizeofMsghdr = C.sizeof_struct_msghdr
sizeofCmsghdr = C.sizeof_struct_cmsghdr
sizeofSockaddrInet = C.sizeof_struct_sockaddr_in
sizeofSockaddrInet6 = C.sizeof_struct_sockaddr_in6
)

49
vendor/golang.org/x/net/internal/socket/defs_linux.go generated vendored Normal file
View File

@ -0,0 +1,49 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build ignore
// +godefs map struct_in_addr [4]byte /* in_addr */
// +godefs map struct_in6_addr [16]byte /* in6_addr */
package socket
/*
#include <linux/in.h>
#include <linux/in6.h>
#define _GNU_SOURCE
#include <sys/socket.h>
*/
import "C"
const (
sysAF_UNSPEC = C.AF_UNSPEC
sysAF_INET = C.AF_INET
sysAF_INET6 = C.AF_INET6
sysSOCK_RAW = C.SOCK_RAW
)
type iovec C.struct_iovec
type msghdr C.struct_msghdr
type mmsghdr C.struct_mmsghdr
type cmsghdr C.struct_cmsghdr
type sockaddrInet C.struct_sockaddr_in
type sockaddrInet6 C.struct_sockaddr_in6
const (
sizeofIovec = C.sizeof_struct_iovec
sizeofMsghdr = C.sizeof_struct_msghdr
sizeofMmsghdr = C.sizeof_struct_mmsghdr
sizeofCmsghdr = C.sizeof_struct_cmsghdr
sizeofSockaddrInet = C.sizeof_struct_sockaddr_in
sizeofSockaddrInet6 = C.sizeof_struct_sockaddr_in6
)

47
vendor/golang.org/x/net/internal/socket/defs_netbsd.go generated vendored Normal file
View File

@ -0,0 +1,47 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build ignore
// +godefs map struct_in_addr [4]byte /* in_addr */
// +godefs map struct_in6_addr [16]byte /* in6_addr */
package socket
/*
#include <sys/socket.h>
#include <netinet/in.h>
*/
import "C"
const (
sysAF_UNSPEC = C.AF_UNSPEC
sysAF_INET = C.AF_INET
sysAF_INET6 = C.AF_INET6
sysSOCK_RAW = C.SOCK_RAW
)
type iovec C.struct_iovec
type msghdr C.struct_msghdr
type mmsghdr C.struct_mmsghdr
type cmsghdr C.struct_cmsghdr
type sockaddrInet C.struct_sockaddr_in
type sockaddrInet6 C.struct_sockaddr_in6
const (
sizeofIovec = C.sizeof_struct_iovec
sizeofMsghdr = C.sizeof_struct_msghdr
sizeofMmsghdr = C.sizeof_struct_mmsghdr
sizeofCmsghdr = C.sizeof_struct_cmsghdr
sizeofSockaddrInet = C.sizeof_struct_sockaddr_in
sizeofSockaddrInet6 = C.sizeof_struct_sockaddr_in6
)

View File

@ -0,0 +1,44 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build ignore
// +godefs map struct_in_addr [4]byte /* in_addr */
// +godefs map struct_in6_addr [16]byte /* in6_addr */
package socket
/*
#include <sys/socket.h>
#include <netinet/in.h>
*/
import "C"
const (
sysAF_UNSPEC = C.AF_UNSPEC
sysAF_INET = C.AF_INET
sysAF_INET6 = C.AF_INET6
sysSOCK_RAW = C.SOCK_RAW
)
type iovec C.struct_iovec
type msghdr C.struct_msghdr
type cmsghdr C.struct_cmsghdr
type sockaddrInet C.struct_sockaddr_in
type sockaddrInet6 C.struct_sockaddr_in6
const (
sizeofIovec = C.sizeof_struct_iovec
sizeofMsghdr = C.sizeof_struct_msghdr
sizeofCmsghdr = C.sizeof_struct_cmsghdr
sizeofSockaddrInet = C.sizeof_struct_sockaddr_in
sizeofSockaddrInet6 = C.sizeof_struct_sockaddr_in6
)

View File

@ -0,0 +1,44 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build ignore
// +godefs map struct_in_addr [4]byte /* in_addr */
// +godefs map struct_in6_addr [16]byte /* in6_addr */
package socket
/*
#include <sys/socket.h>
#include <netinet/in.h>
*/
import "C"
const (
sysAF_UNSPEC = C.AF_UNSPEC
sysAF_INET = C.AF_INET
sysAF_INET6 = C.AF_INET6
sysSOCK_RAW = C.SOCK_RAW
)
type iovec C.struct_iovec
type msghdr C.struct_msghdr
type cmsghdr C.struct_cmsghdr
type sockaddrInet C.struct_sockaddr_in
type sockaddrInet6 C.struct_sockaddr_in6
const (
sizeofIovec = C.sizeof_struct_iovec
sizeofMsghdr = C.sizeof_struct_msghdr
sizeofCmsghdr = C.sizeof_struct_cmsghdr
sizeofSockaddrInet = C.sizeof_struct_sockaddr_in
sizeofSockaddrInet6 = C.sizeof_struct_sockaddr_in6
)

31
vendor/golang.org/x/net/internal/socket/error_unix.go generated vendored Normal file
View File

@ -0,0 +1,31 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build darwin dragonfly freebsd linux netbsd openbsd solaris
package socket
import "syscall"
var (
errEAGAIN error = syscall.EAGAIN
errEINVAL error = syscall.EINVAL
errENOENT error = syscall.ENOENT
)
// errnoErr returns common boxed Errno values, to prevent allocations
// at runtime.
func errnoErr(errno syscall.Errno) error {
switch errno {
case 0:
return nil
case syscall.EAGAIN:
return errEAGAIN
case syscall.EINVAL:
return errEINVAL
case syscall.ENOENT:
return errENOENT
}
return errno
}

View File

@ -0,0 +1,26 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package socket
import "syscall"
var (
errERROR_IO_PENDING error = syscall.ERROR_IO_PENDING
errEINVAL error = syscall.EINVAL
)
// errnoErr returns common boxed Errno values, to prevent allocations
// at runtime.
func errnoErr(errno syscall.Errno) error {
switch errno {
case 0:
return nil
case syscall.ERROR_IO_PENDING:
return errERROR_IO_PENDING
case syscall.EINVAL:
return errEINVAL
}
return errno
}

19
vendor/golang.org/x/net/internal/socket/iovec_32bit.go generated vendored Normal file
View File

@ -0,0 +1,19 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build arm mips mipsle 386
// +build darwin dragonfly freebsd linux netbsd openbsd
package socket
import "unsafe"
func (v *iovec) set(b []byte) {
l := len(b)
if l == 0 {
return
}
v.Base = (*byte)(unsafe.Pointer(&b[0]))
v.Len = uint32(l)
}

19
vendor/golang.org/x/net/internal/socket/iovec_64bit.go generated vendored Normal file
View File

@ -0,0 +1,19 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build arm64 amd64 ppc64 ppc64le mips64 mips64le s390x
// +build darwin dragonfly freebsd linux netbsd openbsd
package socket
import "unsafe"
func (v *iovec) set(b []byte) {
l := len(b)
if l == 0 {
return
}
v.Base = (*byte)(unsafe.Pointer(&b[0]))
v.Len = uint64(l)
}

View File

@ -0,0 +1,19 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build amd64
// +build solaris
package socket
import "unsafe"
func (v *iovec) set(b []byte) {
l := len(b)
if l == 0 {
return
}
v.Base = (*int8)(unsafe.Pointer(&b[0]))
v.Len = uint64(l)
}

11
vendor/golang.org/x/net/internal/socket/iovec_stub.go generated vendored Normal file
View File

@ -0,0 +1,11 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd,!solaris
package socket
type iovec struct{}
func (v *iovec) set(b []byte) {}

View File

@ -0,0 +1,21 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !linux,!netbsd
package socket
import "net"
type mmsghdr struct{}
type mmsghdrs []mmsghdr
func (hs mmsghdrs) pack(ms []Message, parseFn func([]byte, string) (net.Addr, error), marshalFn func(net.Addr) []byte) error {
return nil
}
func (hs mmsghdrs) unpack(ms []Message, parseFn func([]byte, string) (net.Addr, error), hint string) error {
return nil
}

View File

@ -0,0 +1,42 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build linux netbsd
package socket
import "net"
type mmsghdrs []mmsghdr
func (hs mmsghdrs) pack(ms []Message, parseFn func([]byte, string) (net.Addr, error), marshalFn func(net.Addr) []byte) error {
for i := range hs {
vs := make([]iovec, len(ms[i].Buffers))
var sa []byte
if parseFn != nil {
sa = make([]byte, sizeofSockaddrInet6)
}
if marshalFn != nil {
sa = marshalFn(ms[i].Addr)
}
hs[i].Hdr.pack(vs, ms[i].Buffers, ms[i].OOB, sa)
}
return nil
}
func (hs mmsghdrs) unpack(ms []Message, parseFn func([]byte, string) (net.Addr, error), hint string) error {
for i := range hs {
ms[i].N = int(hs[i].Len)
ms[i].NN = hs[i].Hdr.controllen()
ms[i].Flags = hs[i].Hdr.flags()
if parseFn != nil {
var err error
ms[i].Addr, err = parseFn(hs[i].Hdr.name(), hint)
if err != nil {
return err
}
}
}
return nil
}

39
vendor/golang.org/x/net/internal/socket/msghdr_bsd.go generated vendored Normal file
View File

@ -0,0 +1,39 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build darwin dragonfly freebsd netbsd openbsd
package socket
import "unsafe"
func (h *msghdr) pack(vs []iovec, bs [][]byte, oob []byte, sa []byte) {
for i := range vs {
vs[i].set(bs[i])
}
h.setIov(vs)
if len(oob) > 0 {
h.Control = (*byte)(unsafe.Pointer(&oob[0]))
h.Controllen = uint32(len(oob))
}
if sa != nil {
h.Name = (*byte)(unsafe.Pointer(&sa[0]))
h.Namelen = uint32(len(sa))
}
}
func (h *msghdr) name() []byte {
if h.Name != nil && h.Namelen > 0 {
return (*[sizeofSockaddrInet6]byte)(unsafe.Pointer(h.Name))[:h.Namelen]
}
return nil
}
func (h *msghdr) controllen() int {
return int(h.Controllen)
}
func (h *msghdr) flags() int {
return int(h.Flags)
}

View File

@ -0,0 +1,16 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build darwin dragonfly freebsd netbsd
package socket
func (h *msghdr) setIov(vs []iovec) {
l := len(vs)
if l == 0 {
return
}
h.Iov = &vs[0]
h.Iovlen = int32(l)
}

View File

@ -0,0 +1,36 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package socket
import "unsafe"
func (h *msghdr) pack(vs []iovec, bs [][]byte, oob []byte, sa []byte) {
for i := range vs {
vs[i].set(bs[i])
}
h.setIov(vs)
if len(oob) > 0 {
h.setControl(oob)
}
if sa != nil {
h.Name = (*byte)(unsafe.Pointer(&sa[0]))
h.Namelen = uint32(len(sa))
}
}
func (h *msghdr) name() []byte {
if h.Name != nil && h.Namelen > 0 {
return (*[sizeofSockaddrInet6]byte)(unsafe.Pointer(h.Name))[:h.Namelen]
}
return nil
}
func (h *msghdr) controllen() int {
return int(h.Controllen)
}
func (h *msghdr) flags() int {
return int(h.Flags)
}

View File

@ -0,0 +1,24 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build arm mips mipsle 386
// +build linux
package socket
import "unsafe"
func (h *msghdr) setIov(vs []iovec) {
l := len(vs)
if l == 0 {
return
}
h.Iov = &vs[0]
h.Iovlen = uint32(l)
}
func (h *msghdr) setControl(b []byte) {
h.Control = (*byte)(unsafe.Pointer(&b[0]))
h.Controllen = uint32(len(b))
}

View File

@ -0,0 +1,24 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build arm64 amd64 ppc64 ppc64le mips64 mips64le s390x
// +build linux
package socket
import "unsafe"
func (h *msghdr) setIov(vs []iovec) {
l := len(vs)
if l == 0 {
return
}
h.Iov = &vs[0]
h.Iovlen = uint64(l)
}
func (h *msghdr) setControl(b []byte) {
h.Control = (*byte)(unsafe.Pointer(&b[0]))
h.Controllen = uint64(len(b))
}

View File

@ -0,0 +1,14 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package socket
func (h *msghdr) setIov(vs []iovec) {
l := len(vs)
if l == 0 {
return
}
h.Iov = &vs[0]
h.Iovlen = uint32(l)
}

View File

@ -0,0 +1,36 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build amd64
// +build solaris
package socket
import "unsafe"
func (h *msghdr) pack(vs []iovec, bs [][]byte, oob []byte, sa []byte) {
for i := range vs {
vs[i].set(bs[i])
}
if len(vs) > 0 {
h.Iov = &vs[0]
h.Iovlen = int32(len(vs))
}
if len(oob) > 0 {
h.Accrights = (*int8)(unsafe.Pointer(&oob[0]))
h.Accrightslen = int32(len(oob))
}
if sa != nil {
h.Name = (*byte)(unsafe.Pointer(&sa[0]))
h.Namelen = uint32(len(sa))
}
}
func (h *msghdr) controllen() int {
return int(h.Accrightslen)
}
func (h *msghdr) flags() int {
return int(NativeEndian.Uint32(h.Pad_cgo_2[:]))
}

14
vendor/golang.org/x/net/internal/socket/msghdr_stub.go generated vendored Normal file
View File

@ -0,0 +1,14 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd,!solaris
package socket
type msghdr struct{}
func (h *msghdr) pack(vs []iovec, bs [][]byte, oob []byte, sa []byte) {}
func (h *msghdr) name() []byte { return nil }
func (h *msghdr) controllen() int { return 0 }
func (h *msghdr) flags() int { return 0 }

66
vendor/golang.org/x/net/internal/socket/rawconn.go generated vendored Normal file
View File

@ -0,0 +1,66 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build go1.9
package socket
import (
"errors"
"net"
"os"
"syscall"
)
// A Conn represents a raw connection.
type Conn struct {
network string
c syscall.RawConn
}
// NewConn returns a new raw connection.
func NewConn(c net.Conn) (*Conn, error) {
var err error
var cc Conn
switch c := c.(type) {
case *net.TCPConn:
cc.network = "tcp"
cc.c, err = c.SyscallConn()
case *net.UDPConn:
cc.network = "udp"
cc.c, err = c.SyscallConn()
case *net.IPConn:
cc.network = "ip"
cc.c, err = c.SyscallConn()
default:
return nil, errors.New("unknown connection type")
}
if err != nil {
return nil, err
}
return &cc, nil
}
func (o *Option) get(c *Conn, b []byte) (int, error) {
var operr error
var n int
fn := func(s uintptr) {
n, operr = getsockopt(s, o.Level, o.Name, b)
}
if err := c.c.Control(fn); err != nil {
return 0, err
}
return n, os.NewSyscallError("getsockopt", operr)
}
func (o *Option) set(c *Conn, b []byte) error {
var operr error
fn := func(s uintptr) {
operr = setsockopt(s, o.Level, o.Name, b)
}
if err := c.c.Control(fn); err != nil {
return err
}
return os.NewSyscallError("setsockopt", operr)
}

View File

@ -0,0 +1,74 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build go1.9
// +build linux
package socket
import (
"net"
"os"
"syscall"
)
func (c *Conn) recvMsgs(ms []Message, flags int) (int, error) {
hs := make(mmsghdrs, len(ms))
var parseFn func([]byte, string) (net.Addr, error)
if c.network != "tcp" {
parseFn = parseInetAddr
}
if err := hs.pack(ms, parseFn, nil); err != nil {
return 0, err
}
var operr error
var n int
fn := func(s uintptr) bool {
n, operr = recvmmsg(s, hs, flags)
if operr == syscall.EAGAIN {
return false
}
return true
}
if err := c.c.Read(fn); err != nil {
return n, err
}
if operr != nil {
return n, os.NewSyscallError("recvmmsg", operr)
}
if err := hs[:n].unpack(ms[:n], parseFn, c.network); err != nil {
return n, err
}
return n, nil
}
func (c *Conn) sendMsgs(ms []Message, flags int) (int, error) {
hs := make(mmsghdrs, len(ms))
var marshalFn func(net.Addr) []byte
if c.network != "tcp" {
marshalFn = marshalInetAddr
}
if err := hs.pack(ms, nil, marshalFn); err != nil {
return 0, err
}
var operr error
var n int
fn := func(s uintptr) bool {
n, operr = sendmmsg(s, hs, flags)
if operr == syscall.EAGAIN {
return false
}
return true
}
if err := c.c.Write(fn); err != nil {
return n, err
}
if operr != nil {
return n, os.NewSyscallError("sendmmsg", operr)
}
if err := hs[:n].unpack(ms[:n], nil, ""); err != nil {
return n, err
}
return n, nil
}

77
vendor/golang.org/x/net/internal/socket/rawconn_msg.go generated vendored Normal file
View File

@ -0,0 +1,77 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build go1.9
// +build darwin dragonfly freebsd linux netbsd openbsd solaris windows
package socket
import (
"os"
"syscall"
)
func (c *Conn) recvMsg(m *Message, flags int) error {
var h msghdr
vs := make([]iovec, len(m.Buffers))
var sa []byte
if c.network != "tcp" {
sa = make([]byte, sizeofSockaddrInet6)
}
h.pack(vs, m.Buffers, m.OOB, sa)
var operr error
var n int
fn := func(s uintptr) bool {
n, operr = recvmsg(s, &h, flags)
if operr == syscall.EAGAIN {
return false
}
return true
}
if err := c.c.Read(fn); err != nil {
return err
}
if operr != nil {
return os.NewSyscallError("recvmsg", operr)
}
if c.network != "tcp" {
var err error
m.Addr, err = parseInetAddr(sa[:], c.network)
if err != nil {
return err
}
}
m.N = n
m.NN = h.controllen()
m.Flags = h.flags()
return nil
}
func (c *Conn) sendMsg(m *Message, flags int) error {
var h msghdr
vs := make([]iovec, len(m.Buffers))
var sa []byte
if m.Addr != nil {
sa = marshalInetAddr(m.Addr)
}
h.pack(vs, m.Buffers, m.OOB, sa)
var operr error
var n int
fn := func(s uintptr) bool {
n, operr = sendmsg(s, &h, flags)
if operr == syscall.EAGAIN {
return false
}
return true
}
if err := c.c.Write(fn); err != nil {
return err
}
if operr != nil {
return os.NewSyscallError("sendmsg", operr)
}
m.N = n
m.NN = len(m.OOB)
return nil
}

View File

@ -0,0 +1,18 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build go1.9
// +build !linux
package socket
import "errors"
func (c *Conn) recvMsgs(ms []Message, flags int) (int, error) {
return 0, errors.New("not implemented")
}
func (c *Conn) sendMsgs(ms []Message, flags int) (int, error) {
return 0, errors.New("not implemented")
}

Some files were not shown because too many files have changed in this diff Show More