Skip to content

Commit 4f2580e

Browse files
committed
Add cBPF ops support to BpfFilter
1 parent 63484bb commit 4f2580e

File tree

3 files changed

+155
-0
lines changed

3 files changed

+155
-0
lines changed

filter.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,7 @@ type BpfFilter struct {
394394
DirectAction bool
395395
Id int
396396
Tag string
397+
Ops []SockFilter
397398
}
398399

399400
func (filter *BpfFilter) Type() string {
@@ -418,3 +419,10 @@ func (filter *GenericFilter) Attrs() *FilterAttrs {
418419
func (filter *GenericFilter) Type() string {
419420
return filter.FilterType
420421
}
422+
423+
type SockFilter struct {
424+
Code uint16
425+
Jt uint8
426+
Jf uint8
427+
K uint32
428+
}

filter_linux.go

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"encoding/hex"
77
"errors"
88
"fmt"
9+
"math"
910
"net"
1011
"syscall"
1112

@@ -371,6 +372,18 @@ func (h *Handle) filterModify(filter Filter, proto, flags int) error {
371372
if filter.Fd >= 0 {
372373
options.AddRtAttr(nl.TCA_BPF_FD, nl.Uint32Attr((uint32(filter.Fd))))
373374
}
375+
if len(filter.Ops) > 0 {
376+
if filter.Fd >= 0 {
377+
return fmt.Errorf("only Ops or Fd can be specified on a BpfFilter")
378+
}
379+
380+
opsLen, ops, err := serializeSockFilter(filter.Ops)
381+
if err != nil {
382+
return err
383+
}
384+
options.AddRtAttr(nl.TCA_BPF_OPS_LEN, nl.Uint16Attr(opsLen))
385+
options.AddRtAttr(nl.TCA_BPF_OPS, ops)
386+
}
374387
if filter.Name != "" {
375388
options.AddRtAttr(nl.TCA_BPF_NAME, nl.ZeroTerminated(filter.Name))
376389
}
@@ -934,7 +947,10 @@ func parseFwData(filter Filter, data []syscall.NetlinkRouteAttr) (bool, error) {
934947

935948
func parseBpfData(filter Filter, data []syscall.NetlinkRouteAttr) (bool, error) {
936949
bpf := filter.(*BpfFilter)
950+
bpf.Fd = -1
937951
detailed := true
952+
var opsLen uint16
953+
var ops []byte
938954
for _, datum := range data {
939955
switch datum.Attr.Type {
940956
case nl.TCA_BPF_FD:
@@ -952,6 +968,17 @@ func parseBpfData(filter Filter, data []syscall.NetlinkRouteAttr) (bool, error)
952968
bpf.Id = int(native.Uint32(datum.Value[0:4]))
953969
case nl.TCA_BPF_TAG:
954970
bpf.Tag = hex.EncodeToString(datum.Value)
971+
case nl.TCA_BPF_OPS_LEN:
972+
opsLen = native.Uint16(datum.Value[0:2])
973+
case nl.TCA_BPF_OPS:
974+
ops = datum.Value
975+
}
976+
}
977+
if opsLen > 0 {
978+
var err error
979+
bpf.Ops, err = deserializeSockFilter(opsLen, ops)
980+
if err != nil {
981+
return detailed, err
955982
}
956983
}
957984
return detailed, nil
@@ -1039,3 +1066,42 @@ func SerializeRtab(rtab [256]uint32) []byte {
10391066
_ = binary.Write(&w, native, rtab)
10401067
return w.Bytes()
10411068
}
1069+
1070+
func deserializeSockFilter(opsLen uint16, ops []byte) ([]SockFilter, error) {
1071+
if excp := int(opsLen) * 8; len(ops) != excp {
1072+
return nil, fmt.Errorf("unexpected ops length %d, expected %d", len(ops), excp)
1073+
}
1074+
1075+
ins := make([]SockFilter, opsLen)
1076+
for i := 0; i < len(ins); i++ {
1077+
ins[i] = SockFilter{
1078+
Code: native.Uint16(ops[0:]),
1079+
Jt: ops[2],
1080+
Jf: ops[3],
1081+
K: native.Uint32(ops[4:]),
1082+
}
1083+
1084+
ops = ops[8:]
1085+
}
1086+
1087+
return ins, nil
1088+
}
1089+
1090+
func serializeSockFilter(rawIns []SockFilter) (uint16, []byte, error) {
1091+
opsLen := len(rawIns)
1092+
if opsLen > math.MaxUint16 {
1093+
return 0, nil, fmt.Errorf("too many bpf instructions, max %d", math.MaxUint16)
1094+
}
1095+
1096+
ops := make([]byte, 8*opsLen)
1097+
b := ops
1098+
for _, ins := range rawIns {
1099+
native.PutUint16(b[0:], ins.Code)
1100+
b[2] = ins.Jt
1101+
b[3] = ins.Jf
1102+
native.PutUint32(b[4:], ins.K)
1103+
1104+
b = b[8:]
1105+
}
1106+
return uint16(opsLen), ops, nil
1107+
}

filter_test.go

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1156,6 +1156,87 @@ func TestFilterClsActBpfAddDel(t *testing.T) {
11561156
}
11571157
}
11581158

1159+
func TestFilterClsActCBpfAddDel(t *testing.T) {
1160+
// This feature was added in kernel 4.5
1161+
minKernelRequired(t, 4, 5)
1162+
1163+
tearDown := setUpNetlinkTest(t)
1164+
defer tearDown()
1165+
1166+
qdisc, link := setupLinkForTestWithQdisc(t, "foo")
1167+
filterattrs := FilterAttrs{
1168+
LinkIndex: link.Attrs().Index,
1169+
Parent: HANDLE_MIN_EGRESS,
1170+
Handle: MakeHandle(0, 1),
1171+
Protocol: unix.ETH_P_ALL,
1172+
Priority: 1,
1173+
}
1174+
1175+
filter := &BpfFilter{
1176+
FilterAttrs: filterattrs,
1177+
Fd: -1,
1178+
Name: "simple",
1179+
DirectAction: true,
1180+
Ops: []SockFilter{
1181+
SockFilter{
1182+
Code: 0x0006,
1183+
Jt: 0x00,
1184+
Jf: 0x00,
1185+
K: 0x00000002,
1186+
},
1187+
},
1188+
}
1189+
1190+
if err := FilterAdd(filter); err != nil {
1191+
t.Fatal(err)
1192+
}
1193+
1194+
filters, err := FilterList(link, HANDLE_MIN_EGRESS)
1195+
if err != nil {
1196+
t.Fatal(err)
1197+
}
1198+
if len(filters) != 1 {
1199+
t.Fatal("Failed to add filter")
1200+
}
1201+
bpf, ok := filters[0].(*BpfFilter)
1202+
if !ok {
1203+
t.Fatal("Filter is the wrong type")
1204+
}
1205+
if len(filter.Ops) != 1 ||
1206+
bpf.Ops[0].Code != filter.Ops[0].Code ||
1207+
bpf.Ops[0].Jt != filter.Ops[0].Jt ||
1208+
bpf.Ops[0].Jf != filter.Ops[0].Jf ||
1209+
bpf.Ops[0].K != filter.Ops[0].K {
1210+
1211+
t.Fatal("Filter Ops does not match")
1212+
}
1213+
if bpf.DirectAction != filter.DirectAction {
1214+
t.Fatal("Filter DirectAction does not match")
1215+
}
1216+
1217+
if err := FilterDel(filter); err != nil {
1218+
t.Fatal(err)
1219+
}
1220+
filters, err = FilterList(link, HANDLE_MIN_EGRESS)
1221+
if err != nil {
1222+
t.Fatal(err)
1223+
}
1224+
if len(filters) != 0 {
1225+
t.Fatal("Failed to remove filter")
1226+
}
1227+
1228+
if err := QdiscDel(qdisc); err != nil {
1229+
t.Fatal(err)
1230+
}
1231+
qdiscs, err := SafeQdiscList(link)
1232+
if err != nil {
1233+
t.Fatal(err)
1234+
}
1235+
if len(qdiscs) != 0 {
1236+
t.Fatal("Failed to remove qdisc")
1237+
}
1238+
}
1239+
11591240
func TestFilterMatchAllAddDel(t *testing.T) {
11601241
// This classifier was added in kernel 4.7
11611242
minKernelRequired(t, 4, 7)

0 commit comments

Comments
 (0)