return fmt.Errorf("failed to parse policy verdict: %w", err)
}
eventSubType = pvn.SubType
- packetOffset = monitor.PolicyVerdictNotifyLen
+ packetOffset = int(pvn.DataOffset())
authType = pb.AuthType(pvn.GetAuthType())
case monitorAPI.MessageTypeCapture:
dbg = &monitor.DebugCapture{}
return fmt.Errorf("failed to parse debug capture: %w", err)
}
eventSubType = dbg.SubType
- packetOffset = monitor.DebugCaptureLen
+ packetOffset = int(dbg.DataOffset())
default:
return errors.NewErrInvalidType(eventType)
}
DebugCaptureLen = 24
)
+const DebugCaptureExtensionDisabled = 0
+
+var (
+ // Downstream projects should register introduced extensions length so that
+ // the upstream parsing code still works even if the DP events contain
+ // additional fields.
+ debugCaptureExtensionLengthFromVersion = map[uint8]uint{
+ // The DebugCaptureExtension is intended for downstream extensions and
+ // should not be used in the upstream project.
+ DebugCaptureExtensionDisabled: 0,
+ }
+)
+
// DebugCapture is the metadata sent along with a captured packet frame
type DebugCapture struct {
api.DefaultSrcDstGetter
return nil
}
+// DataOffset returns the offset from the beginning of DebugCapture where the
+// notification data begins.
+func (n *DebugCapture) DataOffset() uint {
+ return DebugCaptureLen + debugCaptureExtensionLengthFromVersion[n.ExtVersion]
+}
+
// DumpInfo prints a summary of the capture messages.
func (n *DebugCapture) DumpInfo(buf *bufio.Writer, data []byte, linkMonitor getters.LinkGetter) {
prefix := n.infoPrefix(linkMonitor)
if len(prefix) > 0 {
- fmt.Fprintf(buf, "%s: %s\n", prefix, GetConnectionSummary(data[DebugCaptureLen:], nil))
+ fmt.Fprintf(buf, "%s: %s\n", prefix, GetConnectionSummary(data[n.DataOffset():], nil))
}
}
func (n *DebugCapture) DumpVerbose(buf *bufio.Writer, dissect bool, data []byte, prefix string) {
fmt.Fprintf(buf, "%s MARK %#x FROM %d DEBUG: %d bytes, %s", prefix, n.Hash, n.Source, n.Len, n.subTypeString())
- if n.Len > 0 && len(data) > DebugCaptureLen {
- Dissect(buf, dissect, data[DebugCaptureLen:], nil)
+ if n.Len > 0 && len(data) > int(n.DataOffset()) {
+ Dissect(buf, dissect, data[n.DataOffset():], nil)
}
}
v := DebugCaptureToVerbose(n, linkMonitor)
v.CPUPrefix = cpuPrefix
- v.Summary = GetConnectionSummary(data[DebugCaptureLen:], nil)
+ v.Summary = GetConnectionSummary(data[n.DataOffset():], nil)
ret, err := json.Marshal(v)
return string(ret), err
require.Equal(t, input.Arg2, output.Arg2)
}
+func TestDecodeDebugCaptureExt(t *testing.T) {
+ setTmpExtVer := func(extVer uint8, extLen uint) {
+ oldLen, ok := debugCaptureExtensionLengthFromVersion[extVer]
+ if !ok {
+ t.Cleanup(func() { delete(debugCaptureExtensionLengthFromVersion, extVer) })
+ } else {
+ t.Cleanup(func() { debugCaptureExtensionLengthFromVersion[extVer] = oldLen })
+ }
+ debugCaptureExtensionLengthFromVersion[extVer] = extLen
+ }
+
+ setTmpExtVer(1, 4)
+ setTmpExtVer(2, 8)
+ setTmpExtVer(3, 16)
+
+ tcs := []struct {
+ name string
+ dc DebugCapture
+ extension []uint32
+ }{
+ {
+ name: "no extension",
+ dc: DebugCapture{
+ Version: 1,
+ ExtVersion: 0,
+ },
+ },
+ {
+ name: "extension 1",
+ dc: DebugCapture{
+ Version: 1,
+ ExtVersion: 1,
+ },
+ extension: []uint32{
+ 0xC0FFEE,
+ },
+ },
+ {
+ name: "extension 2",
+ dc: DebugCapture{
+ Version: 1,
+ ExtVersion: 2,
+ },
+ extension: []uint32{
+ 0xC0FFEE,
+ 0xDECAFBAD,
+ },
+ },
+ {
+ name: "extension 2",
+ dc: DebugCapture{
+ Version: 1,
+ ExtVersion: 3,
+ },
+ extension: []uint32{
+ 0xC0FFEE,
+ 0xDECAFBAD,
+ 0xFA1AFE1,
+ 0xF00DF00D,
+ },
+ },
+ }
+
+ for _, tc := range tcs {
+ buf := bytes.NewBuffer(nil)
+ err := binary.Write(buf, byteorder.Native, tc.dc)
+ require.NoError(t, err)
+ err = binary.Write(buf, byteorder.Native, tc.extension)
+ require.NoError(t, err)
+ err = binary.Write(buf, byteorder.Native, uint32(0xDEADBEEF))
+ require.NoError(t, err)
+
+ output := &DebugCapture{}
+ err = output.Decode(buf.Bytes())
+ require.NoError(t, err)
+
+ require.Equal(t, uint32(0xDEADBEEF), byteorder.Native.Uint32(buf.Bytes()[output.DataOffset():]))
+ }
+}
+
func BenchmarkNewDecodeDebugCapture(b *testing.B) {
input := &DebugCapture{}
buf := bytes.NewBuffer(nil)
}
)
+const DropNotifyExtensionDisabled = 0
+
+var (
+ // Downstream projects should register introduced extensions length so that
+ // the upstream parsing code still works even if the DP events contain
+ // additional fields.
+ dropNotifyExtensionLengthFromVersion = map[uint8]uint{
+ // The DropNotifyExtension is intended for downstream extensions and
+ // should not be used in the upstream project.
+ DropNotifyExtensionDisabled: 0,
+ }
+)
+
// DropNotify is the message format of a drop notification in the BPF ring buffer
type DropNotify struct {
Type uint8 `align:"type"`
//
// Returns zero for invalid or unknown DropNotify messages.
func (n *DropNotify) DataOffset() uint {
- return dropNotifyLengthFromVersion[n.Version]
+ return dropNotifyLengthFromVersion[n.Version] + dropNotifyExtensionLengthFromVersion[n.ExtVersion]
}
// DumpInfo prints a summary of the drop messages.
}
}
+func TestDecodeDropNotifyExtension(t *testing.T) {
+ setTmpExtVer := func(extVer uint8, extLen uint) {
+ oldLen, ok := dropNotifyExtensionLengthFromVersion[extVer]
+ if !ok {
+ t.Cleanup(func() { delete(dropNotifyExtensionLengthFromVersion, extVer) })
+ } else {
+ t.Cleanup(func() { dropNotifyExtensionLengthFromVersion[extVer] = oldLen })
+ }
+ dropNotifyExtensionLengthFromVersion[extVer] = extLen
+ }
+
+ setTmpExtVer(1, 4)
+ setTmpExtVer(2, 8)
+ setTmpExtVer(3, 16)
+
+ tcs := []struct {
+ name string
+ dn DropNotify
+ extension []uint32
+ }{
+ {
+ name: "no extension",
+ dn: DropNotify{
+ Version: 3,
+ ExtVersion: 0,
+ },
+ },
+ {
+ name: "extension 1",
+ dn: DropNotify{
+ Version: 3,
+ ExtVersion: 1,
+ },
+ extension: []uint32{
+ 0xC0FFEE,
+ },
+ },
+ {
+ name: "extension 2",
+ dn: DropNotify{
+ Version: 3,
+ ExtVersion: 2,
+ },
+ extension: []uint32{
+ 0xC0FFEE,
+ 0xDECAFBAD,
+ },
+ },
+ {
+ name: "extension 2",
+ dn: DropNotify{
+ Version: 3,
+ ExtVersion: 3,
+ },
+ extension: []uint32{
+ 0xC0FFEE,
+ 0xDECAFBAD,
+ 0xFA1AFE1,
+ 0xF00DF00D,
+ },
+ },
+ }
+
+ for _, tc := range tcs {
+ buf := bytes.NewBuffer(nil)
+ err := binary.Write(buf, byteorder.Native, tc.dn)
+ require.NoError(t, err)
+ err = binary.Write(buf, byteorder.Native, tc.extension)
+ require.NoError(t, err)
+ err = binary.Write(buf, byteorder.Native, uint32(0xDEADBEEF))
+ require.NoError(t, err)
+
+ output := &DropNotify{}
+ err = output.Decode(buf.Bytes())
+ require.NoError(t, err)
+
+ require.Equal(t, uint32(0xDEADBEEF), byteorder.Native.Uint32(buf.Bytes()[output.DataOffset():]))
+ }
+}
+
func BenchmarkNewDropNotifyV1_Decode(b *testing.B) {
input := DropNotify{}
buf := bytes.NewBuffer(nil)
PolicyVerdictNotifyFlagMatchTypeBitOffset = 3
)
+const PolicyVerdictExtensionDisabled = 0
+
+var (
+ // Downstream projects should register introduced extensions length so that
+ // the upstream parsing code still works even if the DP events contain
+ // additional fields.
+ policyVerdictExtensionLengthFromVersion = map[uint8]uint{
+ // The PolicyVerdictExtension is intended for downstream extensions and
+ // should not be used in the upstream project.
+ PolicyVerdictExtensionDisabled: 0,
+ }
+)
+
// PolicyVerdictNotify is the message format of a policy verdict notification in the bpf ring buffer
type PolicyVerdictNotify struct {
Type uint8 `align:"type"`
return (n.Flags&PolicyVerdictNotifyFlagIsAudited > 0)
}
+// DataOffset returns the offset from the beginning of PolicyVerdictNotify where the
+// notification data begins.
+func (n *PolicyVerdictNotify) DataOffset() uint {
+ return PolicyVerdictNotifyLen + policyVerdictExtensionLengthFromVersion[n.ExtVersion]
+}
+
// GetPolicyActionString returns the action string corresponding to the action
func GetPolicyActionString(verdict int32, audit bool) string {
if audit {
fmt.Fprintf(buf, ", proto %d, %s, action %s, auth: %s, match %s, %s\n", n.Proto, dir,
GetPolicyActionString(n.Verdict, n.IsTrafficAudited()),
n.GetAuthType(), n.GetPolicyMatchType(),
- GetConnectionSummary(data[PolicyVerdictNotifyLen:], &decodeOpts{IsL3Device: n.IsTrafficL3Device(), IsIPv6: n.IsTrafficIPv6()}))
+ GetConnectionSummary(data[n.DataOffset():], &decodeOpts{IsL3Device: n.IsTrafficL3Device(), IsIPv6: n.IsTrafficIPv6()}))
}
require.Equal(t, input.Cookie, output.Cookie)
}
+func TestDecodePolicyVerdictNotifyExtension(t *testing.T) {
+ setTmpExtVer := func(extVer uint8, extLen uint) {
+ oldLen, ok := policyVerdictExtensionLengthFromVersion[extVer]
+ if !ok {
+ t.Cleanup(func() { delete(policyVerdictExtensionLengthFromVersion, extVer) })
+ } else {
+ t.Cleanup(func() { policyVerdictExtensionLengthFromVersion[extVer] = oldLen })
+ }
+ policyVerdictExtensionLengthFromVersion[extVer] = extLen
+ }
+
+ setTmpExtVer(1, 4)
+ setTmpExtVer(2, 8)
+ setTmpExtVer(3, 16)
+
+ tcs := []struct {
+ name string
+ pvn PolicyVerdictNotify
+ extension []uint32
+ }{
+ {
+ name: "no extension",
+ pvn: PolicyVerdictNotify{
+ Version: 1,
+ ExtVersion: 0,
+ },
+ },
+ {
+ name: "extension 1",
+ pvn: PolicyVerdictNotify{
+ Version: 1,
+ ExtVersion: 1,
+ },
+ extension: []uint32{
+ 0xC0FFEE,
+ },
+ },
+ {
+ name: "extension 2",
+ pvn: PolicyVerdictNotify{
+ Version: 3,
+ ExtVersion: 2,
+ },
+ extension: []uint32{
+ 0xC0FFEE,
+ 0xDECAFBAD,
+ },
+ },
+ {
+ name: "extension 2",
+ pvn: PolicyVerdictNotify{
+ Version: 3,
+ ExtVersion: 3,
+ },
+ extension: []uint32{
+ 0xC0FFEE,
+ 0xDECAFBAD,
+ 0xFA1AFE1,
+ 0xF00DF00D,
+ },
+ },
+ }
+
+ for _, tc := range tcs {
+ buf := bytes.NewBuffer(nil)
+ err := binary.Write(buf, byteorder.Native, tc.pvn)
+ require.NoError(t, err)
+ err = binary.Write(buf, byteorder.Native, tc.extension)
+ require.NoError(t, err)
+ err = binary.Write(buf, byteorder.Native, uint32(0xDEADBEEF))
+ require.NoError(t, err)
+
+ output := &PolicyVerdictNotify{}
+ err = output.Decode(buf.Bytes())
+ require.NoError(t, err)
+
+ require.Equal(t, uint32(0xDEADBEEF), byteorder.Native.Uint32(buf.Bytes()[output.DataOffset():]))
+ }
+}
+
func BenchmarkNewDecodePolicyVerdictNotify(b *testing.B) {
input := &PolicyVerdictNotify{}
buf := bytes.NewBuffer(nil)
}
)
+const TraceNotifyExtensionDisabled = 0
+
+var (
+ // Downstream projects should register introduced extensions length so that
+ // the upstream parsing code still works even if the DP events contain
+ // additional fields.
+ traceNotifyExtensionLengthFromVersion = map[uint8]uint{
+ // The TraceNotifyExtension is intended for downstream extensions and
+ // should not be used in the upstream project.
+ TraceNotifyExtensionDisabled: 0,
+ }
+)
+
/* Reasons for forwarding a packet, keep in sync with api/v1/flow/flow.proto */
const (
TraceReasonPolicy = iota
//
// Returns zero for invalid or unknown TraceNotify messages.
func (n *TraceNotify) DataOffset() uint {
- return traceNotifyLength[n.Version]
+ return traceNotifyLength[n.Version] + traceNotifyExtensionLengthFromVersion[n.ExtVersion]
}
// DumpInfo prints a summary of the trace messages.
require.Equal(t, in.IPTraceID, out.IPTraceID)
}
+func TestDecodeTraceNotifyExtension(t *testing.T) {
+ setTmpExtVer := func(extVer uint8, extLen uint) {
+ oldLen, ok := traceNotifyExtensionLengthFromVersion[extVer]
+ if !ok {
+ t.Cleanup(func() { delete(traceNotifyExtensionLengthFromVersion, extVer) })
+ } else {
+ t.Cleanup(func() { traceNotifyExtensionLengthFromVersion[extVer] = oldLen })
+ }
+ traceNotifyExtensionLengthFromVersion[extVer] = extLen
+ }
+
+ setTmpExtVer(1, 4)
+ setTmpExtVer(2, 8)
+ setTmpExtVer(3, 16)
+
+ tcs := []struct {
+ name string
+ tn TraceNotify
+ extension []uint32
+ }{
+ {
+ name: "no extension",
+ tn: TraceNotify{
+ Version: TraceNotifyVersion2,
+ ExtVersion: 0,
+ },
+ },
+ {
+ name: "extension 1",
+ tn: TraceNotify{
+ Version: TraceNotifyVersion2,
+ ExtVersion: 1,
+ },
+ extension: []uint32{
+ 0xC0FFEE,
+ },
+ },
+ {
+ name: "extension 2",
+ tn: TraceNotify{
+ Version: TraceNotifyVersion2,
+ ExtVersion: 2,
+ },
+ extension: []uint32{
+ 0xC0FFEE,
+ 0xDECAFBAD,
+ },
+ },
+ {
+ name: "extension 2",
+ tn: TraceNotify{
+ Version: TraceNotifyVersion2,
+ ExtVersion: 3,
+ },
+ extension: []uint32{
+ 0xC0FFEE,
+ 0xDECAFBAD,
+ 0xFA1AFE1,
+ 0xF00DF00D,
+ },
+ },
+ }
+
+ for _, tc := range tcs {
+ buf := bytes.NewBuffer(nil)
+ err := binary.Write(buf, byteorder.Native, tc.tn)
+ require.NoError(t, err)
+ err = binary.Write(buf, byteorder.Native, tc.extension)
+ require.NoError(t, err)
+ err = binary.Write(buf, byteorder.Native, uint32(0xDEADBEEF))
+ require.NoError(t, err)
+
+ output := &TraceNotify{}
+ err = output.Decode(buf.Bytes())
+ require.NoError(t, err)
+
+ require.Equal(t, uint32(0xDEADBEEF), byteorder.Native.Uint32(buf.Bytes()[output.DataOffset():]))
+ }
+}
+
func TestDecodeTraceNotifyErrors(t *testing.T) {
tn := TraceNotify{}
err := tn.Decode([]byte{})