mirror of
https://github.com/vishvananda/netlink
synced 2025-03-24 03:57:21 +00:00
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
0499fc4776
@ -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
|
||||
|
19
addr_test.go
19
addr_test.go
@ -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
59
bpf_linux.go
Normal 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
|
||||
}
|
52
filter.go
52
filter.go
@ -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 {
|
||||
|
182
filter_linux.go
182
filter_linux.go
@ -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)
|
||||
|
226
filter_test.go
226
filter_test.go
@ -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")
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
212
nl/link_linux.go
212
nl/link_linux.go
@ -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
199
nl/link_linux_test.go
Normal 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)
|
||||
}
|
@ -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
|
||||
)
|
||||
|
5
qdisc.go
5
qdisc.go
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user