Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Everton Marques 2016-03-18 14:45:31 -03:00
commit 0499fc4776
13 changed files with 1030 additions and 49 deletions

View File

@ -102,6 +102,10 @@ func AddrList(link Link, family int) ([]Addr, error) {
continue
}
if family != FAMILY_ALL && msg.Family != uint8(family) {
continue
}
attrs, err := nl.ParseRouteAttr(m[msg.Len():])
if err != nil {
return nil, err

View File

@ -77,6 +77,25 @@ func TestAddr(t *testing.T) {
t.Fatalf("Address scope not set properly, got=%d, expected=%d", addrs[0].Scope, tt.expected.Scope)
}
// Pass FAMILY_V4, we should get the same results as FAMILY_ALL
addrs, err = AddrList(link, FAMILY_V4)
if err != nil {
t.Fatal(err)
}
if len(addrs) != 1 {
t.Fatal("Address not added properly")
}
// Pass a wrong family number, we should get nil list
addrs, err = AddrList(link, 0x8)
if err != nil {
t.Fatal(err)
}
if len(addrs) != 0 {
t.Fatal("Address not expected")
}
if err = AddrDel(link, tt.addr); err != nil {
t.Fatal(err)
}

59
bpf_linux.go Normal file
View File

@ -0,0 +1,59 @@
package netlink
/*
#include <asm/types.h>
#include <asm/unistd.h>
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
static int load_simple_bpf(int prog_type) {
#ifdef __NR_bpf
// { return 1; }
__u64 __attribute__((aligned(8))) insns[] = {
0x00000001000000b7ull,
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 = (__u64)&insns,
.license = (__u64)&license,
};
return syscall(__NR_bpf, 5, &attr, sizeof(attr));
#else
errno = EINVAL;
return -1;
#endif
}
*/
import "C"
type BpfProgType C.int
const (
BPF_PROG_TYPE_UNSPEC BpfProgType = iota
BPF_PROG_TYPE_SOCKET_FILTER
BPF_PROG_TYPE_KPROBE
BPF_PROG_TYPE_SCHED_CLS
BPF_PROG_TYPE_SCHED_ACT
)
// loadSimpleBpf loads a trivial bpf program for testing purposes
func loadSimpleBpf(progType BpfProgType) (int, error) {
fd, err := C.load_simple_bpf(C.int(progType))
return int(fd), err
}

View File

@ -26,11 +26,45 @@ func (q FilterAttrs) String() string {
return fmt.Sprintf("{LinkIndex: %d, Handle: %s, Parent: %s, Priority: %d, Protocol: %d}", q.LinkIndex, HandleStr(q.Handle), HandleStr(q.Parent), q.Priority, q.Protocol)
}
// Action represents an action in any supported filter.
type Action interface {
Type() string
}
type BpfAction struct {
nl.TcActBpf
Fd int
Name string
}
func (action *BpfAction) Type() string {
return "bpf"
}
type MirredAction struct {
nl.TcMirred
}
func (action *MirredAction) Type() string {
return "mirred"
}
func NewMirredAction(redirIndex int) *MirredAction {
return &MirredAction{
TcMirred: nl.TcMirred{
TcGen: nl.TcGen{Action: nl.TC_ACT_STOLEN},
Eaction: nl.TCA_EGRESS_REDIR,
Ifindex: uint32(redirIndex),
},
}
}
// U32 filters on many packet related properties
type U32 struct {
FilterAttrs
// Currently only supports redirecting to another interface
ClassId uint32
RedirIndex int
Actions []Action
}
func (filter *U32) Attrs() *FilterAttrs {
@ -124,6 +158,22 @@ func (filter *Fw) Type() string {
return "fw"
}
type BpfFilter struct {
FilterAttrs
ClassId uint32
Fd int
Name string
DirectAction bool
}
func (filter *BpfFilter) Type() string {
return "bpf"
}
func (filter *BpfFilter) Attrs() *FilterAttrs {
return &filter.FilterAttrs
}
// GenericFilter filters represent types that are not currently understood
// by this netlink library.
type GenericFilter struct {

View File

@ -52,17 +52,17 @@ func FilterAdd(filter Filter) error {
}
sel.Keys = append(sel.Keys, nl.TcU32Key{})
nl.NewRtAttrChild(options, nl.TCA_U32_SEL, sel.Serialize())
actions := nl.NewRtAttrChild(options, nl.TCA_U32_ACT, nil)
table := nl.NewRtAttrChild(actions, nl.TCA_ACT_TAB, nil)
nl.NewRtAttrChild(table, nl.TCA_KIND, nl.ZeroTerminated("mirred"))
// redirect to other interface
mir := nl.TcMirred{
Action: nl.TC_ACT_STOLEN,
Eaction: nl.TCA_EGRESS_REDIR,
Ifindex: uint32(u32.RedirIndex),
if u32.ClassId != 0 {
nl.NewRtAttrChild(options, nl.TCA_U32_CLASSID, nl.Uint32Attr(u32.ClassId))
}
actionsAttr := nl.NewRtAttrChild(options, nl.TCA_U32_ACT, nil)
// backwards compatibility
if u32.RedirIndex != 0 {
u32.Actions = append([]Action{NewMirredAction(u32.RedirIndex)}, u32.Actions...)
}
if err := encodeActions(actionsAttr, u32.Actions); err != nil {
return err
}
aopts := nl.NewRtAttrChild(table, nl.TCA_OPTIONS, nil)
nl.NewRtAttrChild(aopts, nl.TCA_MIRRED_PARMS, mir.Serialize())
} else if fw, ok := filter.(*Fw); ok {
if fw.Mask != 0 {
b := make([]byte, 4)
@ -90,6 +90,21 @@ func FilterAdd(filter Filter) error {
native.PutUint32(b, fw.ClassId)
nl.NewRtAttrChild(options, nl.TCA_FW_CLASSID, b)
}
} else if bpf, ok := filter.(*BpfFilter); ok {
var bpf_flags uint32
if bpf.ClassId != 0 {
nl.NewRtAttrChild(options, nl.TCA_BPF_CLASSID, nl.Uint32Attr(bpf.ClassId))
}
if bpf.Fd >= 0 {
nl.NewRtAttrChild(options, nl.TCA_BPF_FD, nl.Uint32Attr((uint32(bpf.Fd))))
}
if bpf.Name != "" {
nl.NewRtAttrChild(options, nl.TCA_BPF_NAME, nl.ZeroTerminated(bpf.Name))
}
if bpf.DirectAction {
bpf_flags |= nl.TCA_BPF_FLAG_ACT_DIRECT
}
nl.NewRtAttrChild(options, nl.TCA_BPF_FLAGS, nl.Uint32Attr(bpf_flags))
}
req.AddData(options)
@ -147,26 +162,29 @@ func FilterList(link Link, parent uint32) ([]Filter, error) {
filter = &U32{}
case "fw":
filter = &Fw{}
case "bpf":
filter = &BpfFilter{}
default:
filter = &GenericFilter{FilterType: filterType}
}
case nl.TCA_OPTIONS:
data, err := nl.ParseRouteAttr(attr.Value)
if err != nil {
return nil, err
}
switch filterType {
case "u32":
data, err := nl.ParseRouteAttr(attr.Value)
if err != nil {
return nil, err
}
detailed, err = parseU32Data(filter, data)
if err != nil {
return nil, err
}
case "fw":
data, err := nl.ParseRouteAttr(attr.Value)
detailed, err = parseFwData(filter, data)
if err != nil {
return nil, err
}
detailed, err = parseFwData(filter, data)
case "bpf":
detailed, err = parseBpfData(filter, data)
if err != nil {
return nil, err
}
@ -183,6 +201,85 @@ func FilterList(link Link, parent uint32) ([]Filter, error) {
return res, nil
}
func encodeActions(attr *nl.RtAttr, actions []Action) error {
tabIndex := int(nl.TCA_ACT_TAB)
for _, action := range actions {
switch action := action.(type) {
default:
return fmt.Errorf("unknown action type %s", action.Type())
case *MirredAction:
table := nl.NewRtAttrChild(attr, tabIndex, nil)
tabIndex++
nl.NewRtAttrChild(table, nl.TCA_ACT_KIND, nl.ZeroTerminated("mirred"))
aopts := nl.NewRtAttrChild(table, nl.TCA_ACT_OPTIONS, nil)
nl.NewRtAttrChild(aopts, nl.TCA_MIRRED_PARMS, action.Serialize())
case *BpfAction:
table := nl.NewRtAttrChild(attr, tabIndex, nil)
tabIndex++
nl.NewRtAttrChild(table, nl.TCA_ACT_KIND, nl.ZeroTerminated("bpf"))
aopts := nl.NewRtAttrChild(table, nl.TCA_ACT_OPTIONS, nil)
nl.NewRtAttrChild(aopts, nl.TCA_ACT_BPF_PARMS, action.Serialize())
nl.NewRtAttrChild(aopts, nl.TCA_ACT_BPF_FD, nl.Uint32Attr(uint32(action.Fd)))
nl.NewRtAttrChild(aopts, nl.TCA_ACT_BPF_NAME, nl.ZeroTerminated(action.Name))
}
}
return nil
}
func parseActions(tables []syscall.NetlinkRouteAttr) ([]Action, error) {
var actions []Action
for _, table := range tables {
var action Action
var actionType string
aattrs, err := nl.ParseRouteAttr(table.Value)
if err != nil {
return nil, err
}
nextattr:
for _, aattr := range aattrs {
switch aattr.Attr.Type {
case nl.TCA_KIND:
actionType = string(aattr.Value[:len(aattr.Value)-1])
// only parse if the action is mirred or bpf
switch actionType {
case "mirred":
action = &MirredAction{}
case "bpf":
action = &BpfAction{}
default:
break nextattr
}
case nl.TCA_OPTIONS:
adata, err := nl.ParseRouteAttr(aattr.Value)
if err != nil {
return nil, err
}
for _, adatum := range adata {
switch actionType {
case "mirred":
switch adatum.Attr.Type {
case nl.TCA_MIRRED_PARMS:
action.(*MirredAction).TcMirred = *nl.DeserializeTcMirred(adatum.Value)
}
case "bpf":
switch adatum.Attr.Type {
case nl.TCA_ACT_BPF_PARMS:
action.(*BpfAction).TcActBpf = *nl.DeserializeTcActBpf(adatum.Value)
case nl.TCA_ACT_BPF_FD:
action.(*BpfAction).Fd = int(native.Uint32(adatum.Value[0:4]))
case nl.TCA_ACT_BPF_NAME:
action.(*BpfAction).Name = string(adatum.Value[:len(adatum.Value)-1])
}
}
}
}
}
actions = append(actions, action)
}
return actions, nil
}
func parseU32Data(filter Filter, data []syscall.NetlinkRouteAttr) (bool, error) {
native = nl.NativeEndian()
u32 := filter.(*U32)
@ -197,34 +294,17 @@ func parseU32Data(filter Filter, data []syscall.NetlinkRouteAttr) (bool, error)
return detailed, nil
}
case nl.TCA_U32_ACT:
table, err := nl.ParseRouteAttr(datum.Value)
tables, err := nl.ParseRouteAttr(datum.Value)
if err != nil {
return detailed, err
}
if len(table) != 1 || table[0].Attr.Type != nl.TCA_ACT_TAB {
return detailed, fmt.Errorf("Action table not formed properly")
u32.Actions, err = parseActions(tables)
if err != nil {
return detailed, err
}
aattrs, err := nl.ParseRouteAttr(table[0].Value)
for _, aattr := range aattrs {
switch aattr.Attr.Type {
case nl.TCA_KIND:
actionType := string(aattr.Value[:len(aattr.Value)-1])
// only parse if the action is mirred
if actionType != "mirred" {
return detailed, nil
}
case nl.TCA_OPTIONS:
adata, err := nl.ParseRouteAttr(aattr.Value)
if err != nil {
return detailed, err
}
for _, adatum := range adata {
switch adatum.Attr.Type {
case nl.TCA_MIRRED_PARMS:
mir := nl.DeserializeTcMirred(adatum.Value)
u32.RedirIndex = int(mir.Ifindex)
}
}
for _, action := range u32.Actions {
if action, ok := action.(*MirredAction); ok {
u32.RedirIndex = int(action.Ifindex)
}
}
}
@ -261,6 +341,28 @@ func parseFwData(filter Filter, data []syscall.NetlinkRouteAttr) (bool, error) {
return detailed, nil
}
func parseBpfData(filter Filter, data []syscall.NetlinkRouteAttr) (bool, error) {
native = nl.NativeEndian()
bpf := filter.(*BpfFilter)
detailed := true
for _, datum := range data {
switch datum.Attr.Type {
case nl.TCA_BPF_FD:
bpf.Fd = int(native.Uint32(datum.Value[0:4]))
case nl.TCA_BPF_NAME:
bpf.Name = string(datum.Value[:len(datum.Value)-1])
case nl.TCA_BPF_CLASSID:
bpf.ClassId = native.Uint32(datum.Value[0:4])
case nl.TCA_BPF_FLAGS:
flags := native.Uint32(datum.Value[0:4])
if (flags & nl.TCA_BPF_FLAG_ACT_DIRECT) != 0 {
bpf.DirectAction = true
}
}
}
return detailed, nil
}
func AlignToAtm(size uint) uint {
var linksize, cells int
cells = int(size / nl.ATM_CELL_PAYLOAD)

View File

@ -246,3 +246,229 @@ func TestFilterFwAddDel(t *testing.T) {
t.Fatal("Failed to remove qdisc")
}
}
func TestFilterU32BpfAddDel(t *testing.T) {
tearDown := setUpNetlinkTest(t)
defer tearDown()
if err := LinkAdd(&Ifb{LinkAttrs{Name: "foo"}}); err != nil {
t.Fatal(err)
}
if err := LinkAdd(&Ifb{LinkAttrs{Name: "bar"}}); err != nil {
t.Fatal(err)
}
link, err := LinkByName("foo")
if err != nil {
t.Fatal(err)
}
if err := LinkSetUp(link); err != nil {
t.Fatal(err)
}
redir, err := LinkByName("bar")
if err != nil {
t.Fatal(err)
}
if err := LinkSetUp(redir); err != nil {
t.Fatal(err)
}
qdisc := &Ingress{
QdiscAttrs: QdiscAttrs{
LinkIndex: link.Attrs().Index,
Handle: MakeHandle(0xffff, 0),
Parent: HANDLE_INGRESS,
},
}
if err := QdiscAdd(qdisc); err != nil {
t.Fatal(err)
}
qdiscs, err := QdiscList(link)
if err != nil {
t.Fatal(err)
}
if len(qdiscs) != 1 {
t.Fatal("Failed to add qdisc")
}
_, ok := qdiscs[0].(*Ingress)
if !ok {
t.Fatal("Qdisc is the wrong type")
}
fd, err := loadSimpleBpf(BPF_PROG_TYPE_SCHED_ACT)
if err != nil {
t.Skipf("Loading bpf program failed: %s", err)
}
filter := &U32{
FilterAttrs: FilterAttrs{
LinkIndex: link.Attrs().Index,
Parent: MakeHandle(0xffff, 0),
Priority: 1,
Protocol: syscall.ETH_P_ALL,
},
ClassId: MakeHandle(1, 1),
Actions: []Action{
&BpfAction{Fd: fd, Name: "simple"},
&MirredAction{
TcMirred: nl.TcMirred{
TcGen: nl.TcGen{Action: nl.TC_ACT_STOLEN},
Eaction: nl.TCA_EGRESS_REDIR,
Ifindex: uint32(redir.Attrs().Index),
},
},
},
}
if err := FilterAdd(filter); err != nil {
t.Fatal(err)
}
filters, err := FilterList(link, MakeHandle(0xffff, 0))
if err != nil {
t.Fatal(err)
}
if len(filters) != 1 {
t.Fatal("Failed to add filter")
}
u32, ok := filters[0].(*U32)
if !ok {
t.Fatal("Filter is the wrong type")
}
if len(u32.Actions) != 2 {
t.Fatalf("Too few Actions in filter")
}
bpfAction, ok := u32.Actions[0].(*BpfAction)
if !ok {
t.Fatal("Action[0] is the wrong type")
}
if bpfAction.Fd != fd {
t.Fatal("Action Fd does not match")
}
if _, ok := u32.Actions[1].(*MirredAction); !ok {
t.Fatal("Action[1] is the wrong type")
}
if err := FilterDel(filter); err != nil {
t.Fatal(err)
}
filters, err = FilterList(link, MakeHandle(0xffff, 0))
if err != nil {
t.Fatal(err)
}
if len(filters) != 0 {
t.Fatal("Failed to remove filter")
}
if err := QdiscDel(qdisc); err != nil {
t.Fatal(err)
}
qdiscs, err = QdiscList(link)
if err != nil {
t.Fatal(err)
}
if len(qdiscs) != 0 {
t.Fatal("Failed to remove qdisc")
}
}
func TestFilterClsActBpfAddDel(t *testing.T) {
tearDown := setUpNetlinkTest(t)
defer tearDown()
if err := LinkAdd(&Ifb{LinkAttrs{Name: "foo"}}); err != nil {
t.Fatal(err)
}
link, err := LinkByName("foo")
if err != nil {
t.Fatal(err)
}
if err := LinkSetUp(link); err != nil {
t.Fatal(err)
}
attrs := QdiscAttrs{
LinkIndex: link.Attrs().Index,
Handle: MakeHandle(0xffff, 0),
Parent: HANDLE_CLSACT,
}
qdisc := &GenericQdisc{
QdiscAttrs: attrs,
QdiscType: "clsact",
}
// This feature was added in kernel 4.5
if err := QdiscAdd(qdisc); err != nil {
t.Skipf("Failed adding clsact qdisc, unsupported kernel")
}
qdiscs, err := QdiscList(link)
if err != nil {
t.Fatal(err)
}
if len(qdiscs) != 1 {
t.Fatal("Failed to add qdisc")
}
if q, ok := qdiscs[0].(*GenericQdisc); !ok || q.Type() != "clsact" {
t.Fatal("qdisc is the wrong type")
}
filterattrs := FilterAttrs{
LinkIndex: link.Attrs().Index,
Parent: HANDLE_MIN_EGRESS,
Handle: MakeHandle(0, 1),
Protocol: syscall.ETH_P_ALL,
Priority: 1,
}
fd, err := loadSimpleBpf(BPF_PROG_TYPE_SCHED_CLS)
if err != nil {
t.Skipf("Loading bpf program failed: %s", err)
}
filter := &BpfFilter{
FilterAttrs: filterattrs,
Fd: fd,
Name: "simple",
DirectAction: true,
}
if filter.Fd < 0 {
t.Skipf("Failed to load bpf program")
}
if err := FilterAdd(filter); err != nil {
t.Fatal(err)
}
filters, err := FilterList(link, HANDLE_MIN_EGRESS)
if err != nil {
t.Fatal(err)
}
if len(filters) != 1 {
t.Fatal("Failed to add filter")
}
bpf, ok := filters[0].(*BpfFilter)
if !ok {
t.Fatal("Filter is the wrong type")
}
if bpf.Fd != filter.Fd {
t.Fatal("Filter Fd does not match")
}
if bpf.DirectAction != filter.DirectAction {
t.Fatal("Filter DirectAction does not match")
}
if err := FilterDel(filter); err != nil {
t.Fatal(err)
}
filters, err = FilterList(link, HANDLE_MIN_EGRESS)
if err != nil {
t.Fatal(err)
}
if len(filters) != 0 {
t.Fatal("Failed to remove filter")
}
if err := QdiscDel(qdisc); err != nil {
t.Fatal(err)
}
qdiscs, err = QdiscList(link)
if err != nil {
t.Fatal(err)
}
if len(qdiscs) != 0 {
t.Fatal("Failed to remove qdisc")
}
}

View File

@ -142,6 +142,54 @@ func LinkSetHardwareAddr(link Link, hwaddr net.HardwareAddr) error {
return err
}
// LinkSetVfHardwareAddr sets the hardware address of a vf for the link.
// Equivalent to: `ip link set $link vf $vf mac $hwaddr`
func LinkSetVfHardwareAddr(link Link, vf int, hwaddr net.HardwareAddr) error {
base := link.Attrs()
ensureIndex(base)
req := nl.NewNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
msg.Index = int32(base.Index)
req.AddData(msg)
data := nl.NewRtAttr(nl.IFLA_VFINFO_LIST, nil)
info := nl.NewRtAttrChild(data, nl.IFLA_VF_INFO, nil)
vfmsg := nl.VfMac{
Vf: uint32(vf),
}
copy(vfmsg.Mac[:], []byte(hwaddr))
nl.NewRtAttrChild(info, nl.IFLA_VF_MAC, vfmsg.Serialize())
req.AddData(data)
_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
return err
}
// LinkSetVfVlan sets the vlan of a vf for the link.
// Equivalent to: `ip link set $link vf $vf vlan $vlan`
func LinkSetVfVlan(link Link, vf, vlan int) error {
base := link.Attrs()
ensureIndex(base)
req := nl.NewNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
msg.Index = int32(base.Index)
req.AddData(msg)
data := nl.NewRtAttr(nl.IFLA_VFINFO_LIST, nil)
info := nl.NewRtAttrChild(data, nl.IFLA_VF_INFO, nil)
vfmsg := nl.VfVlan{
Vf: uint32(vf),
Vlan: uint32(vlan),
}
nl.NewRtAttrChild(info, nl.IFLA_VF_VLAN, vfmsg.Serialize())
req.AddData(data)
_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
return err
}
// LinkSetMaster sets the master of the link device.
// Equivalent to: `ip link set $link master $master`
func LinkSetMaster(link Link, master *Bridge) error {

View File

@ -1,7 +1,13 @@
package nl
import (
"unsafe"
)
const (
DEFAULT_CHANGE = 0xFFFFFFFF
// doesn't exist in syscall
IFLA_VFINFO_LIST = 0x16
)
const (
@ -182,3 +188,209 @@ const (
GRE_FLAGS = 0x00F8
GRE_VERSION = 0x0007
)
const (
IFLA_VF_INFO_UNSPEC = iota
IFLA_VF_INFO
IFLA_VF_INFO_MAX = IFLA_VF_INFO
)
const (
IFLA_VF_UNSPEC = iota
IFLA_VF_MAC /* Hardware queue specific attributes */
IFLA_VF_VLAN
IFLA_VF_TX_RATE /* Max TX Bandwidth Allocation */
IFLA_VF_SPOOFCHK /* Spoof Checking on/off switch */
IFLA_VF_LINK_STATE /* link state enable/disable/auto switch */
IFLA_VF_RATE /* Min and Max TX Bandwidth Allocation */
IFLA_VF_RSS_QUERY_EN /* RSS Redirection Table and Hash Key query
* on/off switch
*/
IFLA_VF_STATS /* network device statistics */
IFLA_VF_MAX = IFLA_VF_STATS
)
const (
IFLA_VF_LINK_STATE_AUTO = iota /* link state of the uplink */
IFLA_VF_LINK_STATE_ENABLE /* link always up */
IFLA_VF_LINK_STATE_DISABLE /* link always down */
IFLA_VF_LINK_STATE_MAX = IFLA_VF_LINK_STATE_DISABLE
)
const (
IFLA_VF_STATS_RX_PACKETS = iota
IFLA_VF_STATS_TX_PACKETS
IFLA_VF_STATS_RX_BYTES
IFLA_VF_STATS_TX_BYTES
IFLA_VF_STATS_BROADCAST
IFLA_VF_STATS_MULTICAST
IFLA_VF_STATS_MAX = IFLA_VF_STATS_MULTICAST
)
const (
SizeofVfMac = 0x24
SizeofVfVlan = 0x0c
SizeofVfTxRate = 0x08
SizeofVfRate = 0x0c
SizeofVfSpoofchk = 0x08
SizeofVfLinkState = 0x08
SizeofVfRssQueryEn = 0x08
)
// struct ifla_vf_mac {
// __u32 vf;
// __u8 mac[32]; /* MAX_ADDR_LEN */
// };
type VfMac struct {
Vf uint32
Mac [32]byte
}
func (msg *VfMac) Len() int {
return SizeofVfMac
}
func DeserializeVfMac(b []byte) *VfMac {
return (*VfMac)(unsafe.Pointer(&b[0:SizeofVfMac][0]))
}
func (msg *VfMac) Serialize() []byte {
return (*(*[SizeofVfMac]byte)(unsafe.Pointer(msg)))[:]
}
// struct ifla_vf_vlan {
// __u32 vf;
// __u32 vlan; /* 0 - 4095, 0 disables VLAN filter */
// __u32 qos;
// };
type VfVlan struct {
Vf uint32
Vlan uint32
Qos uint32
}
func (msg *VfVlan) Len() int {
return SizeofVfVlan
}
func DeserializeVfVlan(b []byte) *VfVlan {
return (*VfVlan)(unsafe.Pointer(&b[0:SizeofVfVlan][0]))
}
func (msg *VfVlan) Serialize() []byte {
return (*(*[SizeofVfVlan]byte)(unsafe.Pointer(msg)))[:]
}
// struct ifla_vf_tx_rate {
// __u32 vf;
// __u32 rate; /* Max TX bandwidth in Mbps, 0 disables throttling */
// };
type VfTxRate struct {
Vf uint32
Rate uint32
}
func (msg *VfTxRate) Len() int {
return SizeofVfTxRate
}
func DeserializeVfTxRate(b []byte) *VfTxRate {
return (*VfTxRate)(unsafe.Pointer(&b[0:SizeofVfTxRate][0]))
}
func (msg *VfTxRate) Serialize() []byte {
return (*(*[SizeofVfTxRate]byte)(unsafe.Pointer(msg)))[:]
}
// struct ifla_vf_rate {
// __u32 vf;
// __u32 min_tx_rate; /* Min Bandwidth in Mbps */
// __u32 max_tx_rate; /* Max Bandwidth in Mbps */
// };
type VfRate struct {
Vf uint32
MinTxRate uint32
MaxTxRate uint32
}
func (msg *VfRate) Len() int {
return SizeofVfRate
}
func DeserializeVfRate(b []byte) *VfRate {
return (*VfRate)(unsafe.Pointer(&b[0:SizeofVfRate][0]))
}
func (msg *VfRate) Serialize() []byte {
return (*(*[SizeofVfRate]byte)(unsafe.Pointer(msg)))[:]
}
// struct ifla_vf_spoofchk {
// __u32 vf;
// __u32 setting;
// };
type VfSpoofchk struct {
Vf uint32
Setting uint32
}
func (msg *VfSpoofchk) Len() int {
return SizeofVfSpoofchk
}
func DeserializeVfSpoofchk(b []byte) *VfSpoofchk {
return (*VfSpoofchk)(unsafe.Pointer(&b[0:SizeofVfSpoofchk][0]))
}
func (msg *VfSpoofchk) Serialize() []byte {
return (*(*[SizeofVfSpoofchk]byte)(unsafe.Pointer(msg)))[:]
}
// struct ifla_vf_link_state {
// __u32 vf;
// __u32 link_state;
// };
type VfLinkState struct {
Vf uint32
LinkState uint32
}
func (msg *VfLinkState) Len() int {
return SizeofVfLinkState
}
func DeserializeVfLinkState(b []byte) *VfLinkState {
return (*VfLinkState)(unsafe.Pointer(&b[0:SizeofVfLinkState][0]))
}
func (msg *VfLinkState) Serialize() []byte {
return (*(*[SizeofVfLinkState]byte)(unsafe.Pointer(msg)))[:]
}
// struct ifla_vf_rss_query_en {
// __u32 vf;
// __u32 setting;
// };
type VfRssQueryEn struct {
Vf uint32
Setting uint32
}
func (msg *VfRssQueryEn) Len() int {
return SizeofVfRssQueryEn
}
func DeserializeVfRssQueryEn(b []byte) *VfRssQueryEn {
return (*VfRssQueryEn)(unsafe.Pointer(&b[0:SizeofVfRssQueryEn][0]))
}
func (msg *VfRssQueryEn) Serialize() []byte {
return (*(*[SizeofVfRssQueryEn]byte)(unsafe.Pointer(msg)))[:]
}

199
nl/link_linux_test.go Normal file
View File

@ -0,0 +1,199 @@
package nl
import (
"bytes"
"crypto/rand"
"encoding/binary"
"testing"
)
func (msg *VfMac) write(b []byte) {
native := NativeEndian()
native.PutUint32(b[0:4], uint32(msg.Vf))
copy(b[4:36], msg.Mac[:])
}
func (msg *VfMac) serializeSafe() []byte {
length := SizeofVfMac
b := make([]byte, length)
msg.write(b)
return b
}
func deserializeVfMacSafe(b []byte) *VfMac {
var msg = VfMac{}
binary.Read(bytes.NewReader(b[0:SizeofVfMac]), NativeEndian(), &msg)
return &msg
}
func TestVfMacDeserializeSerialize(t *testing.T) {
var orig = make([]byte, SizeofVfMac)
rand.Read(orig)
safemsg := deserializeVfMacSafe(orig)
msg := DeserializeVfMac(orig)
testDeserializeSerialize(t, orig, safemsg, msg)
}
func (msg *VfVlan) write(b []byte) {
native := NativeEndian()
native.PutUint32(b[0:4], uint32(msg.Vf))
native.PutUint32(b[4:8], uint32(msg.Vlan))
native.PutUint32(b[8:12], uint32(msg.Qos))
}
func (msg *VfVlan) serializeSafe() []byte {
length := SizeofVfVlan
b := make([]byte, length)
msg.write(b)
return b
}
func deserializeVfVlanSafe(b []byte) *VfVlan {
var msg = VfVlan{}
binary.Read(bytes.NewReader(b[0:SizeofVfVlan]), NativeEndian(), &msg)
return &msg
}
func TestVfVlanDeserializeSerialize(t *testing.T) {
var orig = make([]byte, SizeofVfVlan)
rand.Read(orig)
safemsg := deserializeVfVlanSafe(orig)
msg := DeserializeVfVlan(orig)
testDeserializeSerialize(t, orig, safemsg, msg)
}
func (msg *VfTxRate) write(b []byte) {
native := NativeEndian()
native.PutUint32(b[0:4], uint32(msg.Vf))
native.PutUint32(b[4:8], uint32(msg.Rate))
}
func (msg *VfTxRate) serializeSafe() []byte {
length := SizeofVfTxRate
b := make([]byte, length)
msg.write(b)
return b
}
func deserializeVfTxRateSafe(b []byte) *VfTxRate {
var msg = VfTxRate{}
binary.Read(bytes.NewReader(b[0:SizeofVfTxRate]), NativeEndian(), &msg)
return &msg
}
func TestVfTxRateDeserializeSerialize(t *testing.T) {
var orig = make([]byte, SizeofVfTxRate)
rand.Read(orig)
safemsg := deserializeVfTxRateSafe(orig)
msg := DeserializeVfTxRate(orig)
testDeserializeSerialize(t, orig, safemsg, msg)
}
func (msg *VfRate) write(b []byte) {
native := NativeEndian()
native.PutUint32(b[0:4], uint32(msg.Vf))
native.PutUint32(b[4:8], uint32(msg.MinTxRate))
native.PutUint32(b[8:12], uint32(msg.MaxTxRate))
}
func (msg *VfRate) serializeSafe() []byte {
length := SizeofVfRate
b := make([]byte, length)
msg.write(b)
return b
}
func deserializeVfRateSafe(b []byte) *VfRate {
var msg = VfRate{}
binary.Read(bytes.NewReader(b[0:SizeofVfRate]), NativeEndian(), &msg)
return &msg
}
func TestVfRateDeserializeSerialize(t *testing.T) {
var orig = make([]byte, SizeofVfRate)
rand.Read(orig)
safemsg := deserializeVfRateSafe(orig)
msg := DeserializeVfRate(orig)
testDeserializeSerialize(t, orig, safemsg, msg)
}
func (msg *VfSpoofchk) write(b []byte) {
native := NativeEndian()
native.PutUint32(b[0:4], uint32(msg.Vf))
native.PutUint32(b[4:8], uint32(msg.Setting))
}
func (msg *VfSpoofchk) serializeSafe() []byte {
length := SizeofVfSpoofchk
b := make([]byte, length)
msg.write(b)
return b
}
func deserializeVfSpoofchkSafe(b []byte) *VfSpoofchk {
var msg = VfSpoofchk{}
binary.Read(bytes.NewReader(b[0:SizeofVfSpoofchk]), NativeEndian(), &msg)
return &msg
}
func TestVfSpoofchkDeserializeSerialize(t *testing.T) {
var orig = make([]byte, SizeofVfSpoofchk)
rand.Read(orig)
safemsg := deserializeVfSpoofchkSafe(orig)
msg := DeserializeVfSpoofchk(orig)
testDeserializeSerialize(t, orig, safemsg, msg)
}
func (msg *VfLinkState) write(b []byte) {
native := NativeEndian()
native.PutUint32(b[0:4], uint32(msg.Vf))
native.PutUint32(b[4:8], uint32(msg.LinkState))
}
func (msg *VfLinkState) serializeSafe() []byte {
length := SizeofVfLinkState
b := make([]byte, length)
msg.write(b)
return b
}
func deserializeVfLinkStateSafe(b []byte) *VfLinkState {
var msg = VfLinkState{}
binary.Read(bytes.NewReader(b[0:SizeofVfLinkState]), NativeEndian(), &msg)
return &msg
}
func TestVfLinkStateDeserializeSerialize(t *testing.T) {
var orig = make([]byte, SizeofVfLinkState)
rand.Read(orig)
safemsg := deserializeVfLinkStateSafe(orig)
msg := DeserializeVfLinkState(orig)
testDeserializeSerialize(t, orig, safemsg, msg)
}
func (msg *VfRssQueryEn) write(b []byte) {
native := NativeEndian()
native.PutUint32(b[0:4], uint32(msg.Vf))
native.PutUint32(b[4:8], uint32(msg.Setting))
}
func (msg *VfRssQueryEn) serializeSafe() []byte {
length := SizeofVfRssQueryEn
b := make([]byte, length)
msg.write(b)
return b
}
func deserializeVfRssQueryEnSafe(b []byte) *VfRssQueryEn {
var msg = VfRssQueryEn{}
binary.Read(bytes.NewReader(b[0:SizeofVfRssQueryEn]), NativeEndian(), &msg)
return &msg
}
func TestVfRssQueryEnDeserializeSerialize(t *testing.T) {
var orig = make([]byte, SizeofVfRssQueryEn)
rand.Read(orig)
safemsg := deserializeVfRssQueryEnSafe(orig)
msg := DeserializeVfRssQueryEn(orig)
testDeserializeSerialize(t, orig, safemsg, msg)
}

View File

@ -49,6 +49,15 @@ const (
TCAA_MAX = 1
)
const (
TCA_ACT_UNSPEC = iota
TCA_ACT_KIND
TCA_ACT_OPTIONS
TCA_ACT_INDEX
TCA_ACT_STATS
TCA_ACT_MAX
)
const (
TCA_PRIO_UNSPEC = iota
TCA_PRIO_MQ
@ -69,6 +78,7 @@ const (
SizeofTcHtbGlob = 0x14
SizeofTcU32Key = 0x10
SizeofTcU32Sel = 0x10 // without keys
SizeofTcActBpf = 0x14
SizeofTcMirred = 0x1c
SizeofTcPolice = 2*SizeofTcRateSpec + 0x20
)
@ -533,9 +543,34 @@ const (
TC_ACT_STOLEN = 4
TC_ACT_QUEUED = 5
TC_ACT_REPEAT = 6
TC_ACT_REDIRECT = 7
TC_ACT_JUMP = 0x10000000
)
type TcGen struct {
Index uint32
Capab uint32
Action int32
Refcnt int32
Bindcnt int32
}
type TcActBpf struct {
TcGen
}
func (msg *TcActBpf) Len() int {
return SizeofTcActBpf
}
func DeserializeTcActBpf(b []byte) *TcActBpf {
return (*TcActBpf)(unsafe.Pointer(&b[0:SizeofTcActBpf][0]))
}
func (x *TcActBpf) Serialize() []byte {
return (*(*[SizeofTcActBpf]byte)(unsafe.Pointer(x)))[:]
}
// #define tc_gen \
// __u32 index; \
// __u32 capab; \
@ -549,11 +584,7 @@ const (
// };
type TcMirred struct {
Index uint32
Capab uint32
Action int32
Refcnt int32
Bindcnt int32
TcGen
Eaction int32
Ifindex uint32
}
@ -625,3 +656,31 @@ const (
TCA_FW_MASK
TCA_FW_MAX = TCA_FW_MASK
)
const (
TCA_BPF_FLAG_ACT_DIRECT uint32 = 1 << iota
)
const (
TCA_BPF_UNSPEC = iota
TCA_BPF_ACT
TCA_BPF_POLICE
TCA_BPF_CLASSID
TCA_BPF_OPS_LEN
TCA_BPF_OPS
TCA_BPF_FD
TCA_BPF_NAME
TCA_BPF_FLAGS
TCA_BPF_MAX = TCA_BPF_FLAGS
)
const (
TCA_ACT_BPF_UNSPEC = iota
TCA_ACT_BPF_TM
TCA_ACT_BPF_PARMS
TCA_ACT_BPF_OPS_LEN
TCA_ACT_BPF_OPS
TCA_ACT_BPF_FD
TCA_ACT_BPF_NAME
TCA_ACT_BPF_MAX = TCA_ACT_BPF_NAME
)

View File

@ -8,9 +8,14 @@ import (
const (
HANDLE_NONE = 0
HANDLE_INGRESS = 0xFFFFFFF1
HANDLE_CLSACT = HANDLE_INGRESS
HANDLE_ROOT = 0xFFFFFFFF
PRIORITY_MAP_LEN = 16
)
const (
HANDLE_MIN_INGRESS = 0xFFFFFFF2
HANDLE_MIN_EGRESS = 0xFFFFFFF3
)
type Qdisc interface {
Attrs() *QdiscAttrs

View File

@ -116,6 +116,7 @@ func routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg) error {
msg.Type = uint8(route.Type)
}
msg.Flags = uint32(route.Flags)
msg.Scope = uint8(route.Scope)
msg.Family = uint8(family)
req.AddData(msg)

View File

@ -110,9 +110,6 @@ func XfrmStateDel(state *XfrmState) error {
func XfrmStateList(family int) ([]XfrmState, error) {
req := nl.NewNetlinkRequest(nl.XFRM_MSG_GETSA, syscall.NLM_F_DUMP)
msg := nl.NewIfInfomsg(family)
req.AddData(msg)
msgs, err := req.Execute(syscall.NETLINK_XFRM, nl.XFRM_MSG_NEWSA)
if err != nil {
return nil, err