diff --git a/.mk/bc.mk b/.mk/bc.mk index c9f4e0053..a24357f77 100644 --- a/.mk/bc.mk +++ b/.mk/bc.mk @@ -37,8 +37,8 @@ define MAPS "global_counters":"per_cpu_array", "filter_map":"lpm_trie", "peer_filter_map":"lpm_trie", - "sk_buffs_ingress_map":"hash", - "sk_buffs_egress_map":"hash" + "ipsec_ingress_map":"hash", + "ipsec_egress_map":"hash" } endef diff --git a/pkg/agent/agent.go b/pkg/agent/agent.go index 5f5ea757e..5d8d2a78c 100644 --- a/pkg/agent/agent.go +++ b/pkg/agent/agent.go @@ -237,6 +237,7 @@ func FlowsAgent(cfg *Config) (*Flows, error) { EnablePktTranslation: cfg.EnablePktTranslationTracking, UseEbpfManager: cfg.EbpfProgramManagerMode, BpfManBpfFSPath: cfg.BpfManBpfFSPath, + EnableIPsecTracker: cfg.EnableIPsecTracking, FilterConfig: filterRules, } diff --git a/pkg/agent/config.go b/pkg/agent/config.go index 8afaeaa6b..f39483349 100644 --- a/pkg/agent/config.go +++ b/pkg/agent/config.go @@ -236,6 +236,8 @@ type Config struct { BpfManBpfFSPath string `env:"BPFMAN_BPF_FS_PATH" envDefault:"/run/netobserv/maps"` // EnableUDNMapping to allow mapping pod's interface to udn label EnableUDNMapping bool `env:"ENABLE_UDN_MAPPING" envDefault:"false"` + // EnableIPsecTracking enable tracking IPsec flows encryption + EnableIPsecTracking bool `env:"ENABLE_IPSEC_TRACKING" envDefault:"false"` /* Deprecated configs are listed below this line * See manageDeprecatedConfigs function for details */ diff --git a/pkg/decode/decode_protobuf.go b/pkg/decode/decode_protobuf.go index efb723f1b..e02b7f437 100644 --- a/pkg/decode/decode_protobuf.go +++ b/pkg/decode/decode_protobuf.go @@ -141,6 +141,10 @@ func RecordToMap(fr *model.Record) config.GenericMap { out["XlatSrcAddr"] = model.IP(fr.Metrics.AdditionalMetrics.TranslatedFlow.Saddr).String() out["XlatDstAddr"] = model.IP(fr.Metrics.AdditionalMetrics.TranslatedFlow.Daddr).String() } + if fr.Metrics.AdditionalMetrics.FlowEncrypted || fr.Metrics.AdditionalMetrics.FlowEncryptedRet != 0 { + out["EncryptedFlow"] = fr.Metrics.AdditionalMetrics.FlowEncrypted + out["EncryptedFlowRet"] = fr.Metrics.AdditionalMetrics.FlowEncryptedRet + } } if fr.TimeFlowRtt != 0 { diff --git a/pkg/decode/decode_protobuf_test.go b/pkg/decode/decode_protobuf_test.go index 391b42ec7..ddf5f2b38 100644 --- a/pkg/decode/decode_protobuf_test.go +++ b/pkg/decode/decode_protobuf_test.go @@ -96,6 +96,8 @@ func TestPBFlowToMap(t *testing.T) { DstPort: 2, ZoneId: 100, }, + FlowEncrypted: 1, + FlowEncryptedRet: 0, } out := PBFlowToMap(flow) @@ -146,10 +148,12 @@ func TestPBFlowToMap(t *testing.T) { "Direction": "egress", }, }, - "XlatSrcAddr": "1.2.3.4", - "XlatDstAddr": "5.6.7.8", - "XlatSrcPort": uint16(1), - "XlatDstPort": uint16(2), - "ZoneId": uint16(100), + "XlatSrcAddr": "1.2.3.4", + "XlatDstAddr": "5.6.7.8", + "XlatSrcPort": uint16(1), + "XlatDstPort": uint16(2), + "ZoneId": uint16(100), + "EncryptedFlow": true, + "EncryptedFlowRet": uint8(0), }, out) } diff --git a/pkg/exporter/converters_test.go b/pkg/exporter/converters_test.go index cc72779d8..6049b2b4c 100644 --- a/pkg/exporter/converters_test.go +++ b/pkg/exporter/converters_test.go @@ -53,6 +53,7 @@ func TestConversions(t *testing.T) { DnsRecord: ebpf.BpfDnsRecordT{ Errno: 0, }, + FlowEncrypted: true, }, }, Interfaces: []model.IntfDirUdn{model.NewIntfDirUdn("eth0", model.DirectionEgress, nil)}, @@ -61,25 +62,27 @@ func TestConversions(t *testing.T) { AgentIP: net.IPv4(0x0a, 0x0b, 0x0c, 0x0d), }, expected: &config.GenericMap{ - "IfDirections": []int{1}, - "Bytes": 456, - "SrcAddr": "6.7.8.9", - "DstAddr": "10.11.12.13", - "Dscp": 64, - "DstMac": "0A:0B:0C:0D:0E:0F", - "SrcMac": "04:05:06:07:08:09", - "Etype": 2048, - "Packets": 123, - "Proto": 6, - "SrcPort": 23000, - "DstPort": 443, - "Flags": 0x100, - "Sampling": 1, - "TimeFlowStartMs": someTime.UnixMilli(), - "TimeFlowEndMs": someTime.UnixMilli(), - "Interfaces": []string{"eth0"}, - "Udns": []string{""}, - "AgentIP": "10.11.12.13", + "IfDirections": []int{1}, + "Bytes": 456, + "SrcAddr": "6.7.8.9", + "DstAddr": "10.11.12.13", + "Dscp": 64, + "DstMac": "0A:0B:0C:0D:0E:0F", + "SrcMac": "04:05:06:07:08:09", + "Etype": 2048, + "Packets": 123, + "Proto": 6, + "SrcPort": 23000, + "DstPort": 443, + "Flags": 0x100, + "Sampling": 1, + "TimeFlowStartMs": someTime.UnixMilli(), + "TimeFlowEndMs": someTime.UnixMilli(), + "Interfaces": []string{"eth0"}, + "Udns": []string{""}, + "AgentIP": "10.11.12.13", + "EncryptedFlow": true, + "EncryptedFlowRet": 0, }, }, { @@ -345,6 +348,7 @@ func TestConversions(t *testing.T) { LatestState: 6, LatestDropCause: 5, }, + FlowEncrypted: true, }, }, Interfaces: []model.IntfDirUdn{model.NewIntfDirUdn("eth0", model.DirectionEgress, nil)}, @@ -383,6 +387,8 @@ func TestConversions(t *testing.T) { "DnsFlags": 0x8001, "DnsFlagsResponseCode": "FormErr", "TimeFlowRttNs": someDuration.Nanoseconds(), + "EncryptedFlow": true, + "EncryptedFlowRet": 0, }, }, { @@ -409,6 +415,7 @@ func TestConversions(t *testing.T) { DnsRecord: ebpf.BpfDnsRecordT{ Errno: 0, }, + FlowEncrypted: true, }, }, Interfaces: []model.IntfDirUdn{ @@ -420,24 +427,26 @@ func TestConversions(t *testing.T) { AgentIP: net.IPv4(0x0a, 0x0b, 0x0c, 0x0d), }, expected: &config.GenericMap{ - "IfDirections": []int{0, 1}, - "Bytes": 64, - "SrcAddr": "6.7.8.9", - "DstAddr": "10.11.12.13", - "Dscp": 64, - "DstMac": "0A:0B:0C:0D:0E:0F", - "SrcMac": "04:05:06:07:08:09", - "Etype": 2048, - "Packets": 1, - "Proto": 6, - "SrcPort": 23000, - "DstPort": 443, - "Flags": 0x100, - "TimeFlowStartMs": someTime.UnixMilli(), - "TimeFlowEndMs": someTime.UnixMilli(), - "Interfaces": []string{"5e6e92caa1d51cf", "eth0"}, - "Udns": []string{"", ""}, - "AgentIP": "10.11.12.13", + "IfDirections": []int{0, 1}, + "Bytes": 64, + "SrcAddr": "6.7.8.9", + "DstAddr": "10.11.12.13", + "Dscp": 64, + "DstMac": "0A:0B:0C:0D:0E:0F", + "SrcMac": "04:05:06:07:08:09", + "Etype": 2048, + "Packets": 1, + "Proto": 6, + "SrcPort": 23000, + "DstPort": 443, + "Flags": 0x100, + "TimeFlowStartMs": someTime.UnixMilli(), + "TimeFlowEndMs": someTime.UnixMilli(), + "Interfaces": []string{"5e6e92caa1d51cf", "eth0"}, + "Udns": []string{"", ""}, + "AgentIP": "10.11.12.13", + "EncryptedFlow": true, + "EncryptedFlowRet": 0, }, }, } diff --git a/pkg/model/flow_content.go b/pkg/model/flow_content.go index 7157f3ca3..5bded5016 100644 --- a/pkg/model/flow_content.go +++ b/pkg/model/flow_content.go @@ -117,6 +117,13 @@ func (p *BpfFlowContent) AccumulateAdditional(other *ebpf.BpfAdditionalMetrics) if !AllZeroIP(IP(other.TranslatedFlow.Saddr)) && !AllZeroIP(IP(other.TranslatedFlow.Daddr)) { p.AdditionalMetrics.TranslatedFlow = other.TranslatedFlow } + // Encryption + if other.FlowEncrypted { + p.AdditionalMetrics.FlowEncrypted = other.FlowEncrypted + } + if p.AdditionalMetrics.FlowEncryptedRet != other.FlowEncryptedRet { + p.AdditionalMetrics.FlowEncryptedRet = other.FlowEncryptedRet + } } func allZerosMac(s [6]uint8) bool { diff --git a/pkg/pbflow/flow.pb.go b/pkg/pbflow/flow.pb.go index c15908885..a611a1bfb 100644 --- a/pkg/pbflow/flow.pb.go +++ b/pkg/pbflow/flow.pb.go @@ -298,6 +298,8 @@ type Record struct { NetworkEventsMetadata []*NetworkEvent `protobuf:"bytes,27,rep,name=network_events_metadata,json=networkEventsMetadata,proto3" json:"network_events_metadata,omitempty"` Xlat *Xlat `protobuf:"bytes,28,opt,name=xlat,proto3" json:"xlat,omitempty"` Sampling uint32 `protobuf:"varint,29,opt,name=sampling,proto3" json:"sampling,omitempty"` + FlowEncrypted uint32 `protobuf:"varint,30,opt,name=flow_encrypted,json=flowEncrypted,proto3" json:"flow_encrypted,omitempty"` + FlowEncryptedRet uint32 `protobuf:"varint,31,opt,name=flow_encrypted_ret,json=flowEncryptedRet,proto3" json:"flow_encrypted_ret,omitempty"` } func (x *Record) Reset() { @@ -533,6 +535,20 @@ func (x *Record) GetSampling() uint32 { return 0 } +func (x *Record) GetFlowEncrypted() uint32 { + if x != nil { + return x.FlowEncrypted + } + return 0 +} + +func (x *Record) GetFlowEncryptedRet() uint32 { + if x != nil { + return x.FlowEncryptedRet + } + return 0 +} + type DataLink struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -894,7 +910,7 @@ var file_proto_flow_proto_rawDesc = []byte{ 0x0b, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, - 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xc8, 0x09, 0x0a, 0x06, 0x52, 0x65, 0x63, + 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x9d, 0x0a, 0x0a, 0x06, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x65, 0x74, 0x68, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x65, 0x74, 0x68, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x2f, 0x0a, 0x09, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, @@ -971,45 +987,51 @@ var file_proto_flow_proto_rawDesc = []byte{ 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x70, 0x62, 0x66, 0x6c, 0x6f, 0x77, 0x2e, 0x58, 0x6c, 0x61, 0x74, 0x52, 0x04, 0x78, 0x6c, 0x61, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x69, 0x6e, 0x67, 0x18, 0x1d, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x73, 0x61, 0x6d, 0x70, 0x6c, - 0x69, 0x6e, 0x67, 0x22, 0x3c, 0x0a, 0x08, 0x44, 0x61, 0x74, 0x61, 0x4c, 0x69, 0x6e, 0x6b, 0x12, - 0x17, 0x0a, 0x07, 0x73, 0x72, 0x63, 0x5f, 0x6d, 0x61, 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, - 0x52, 0x06, 0x73, 0x72, 0x63, 0x4d, 0x61, 0x63, 0x12, 0x17, 0x0a, 0x07, 0x64, 0x73, 0x74, 0x5f, - 0x6d, 0x61, 0x63, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x64, 0x73, 0x74, 0x4d, 0x61, - 0x63, 0x22, 0x6b, 0x0a, 0x07, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x12, 0x25, 0x0a, 0x08, - 0x73, 0x72, 0x63, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0a, - 0x2e, 0x70, 0x62, 0x66, 0x6c, 0x6f, 0x77, 0x2e, 0x49, 0x50, 0x52, 0x07, 0x73, 0x72, 0x63, 0x41, - 0x64, 0x64, 0x72, 0x12, 0x25, 0x0a, 0x08, 0x64, 0x73, 0x74, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x70, 0x62, 0x66, 0x6c, 0x6f, 0x77, 0x2e, 0x49, - 0x50, 0x52, 0x07, 0x64, 0x73, 0x74, 0x41, 0x64, 0x64, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x73, - 0x63, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x64, 0x73, 0x63, 0x70, 0x22, 0x3d, - 0x0a, 0x02, 0x49, 0x50, 0x12, 0x14, 0x0a, 0x04, 0x69, 0x70, 0x76, 0x34, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x07, 0x48, 0x00, 0x52, 0x04, 0x69, 0x70, 0x76, 0x34, 0x12, 0x14, 0x0a, 0x04, 0x69, 0x70, - 0x76, 0x36, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x04, 0x69, 0x70, 0x76, 0x36, - 0x42, 0x0b, 0x0a, 0x09, 0x69, 0x70, 0x5f, 0x66, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x22, 0x5d, 0x0a, - 0x09, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x72, - 0x63, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x73, 0x72, - 0x63, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x64, 0x73, 0x74, 0x5f, 0x70, 0x6f, 0x72, - 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x64, 0x73, 0x74, 0x50, 0x6f, 0x72, 0x74, - 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x0d, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x22, 0xa3, 0x01, 0x0a, - 0x04, 0x58, 0x6c, 0x61, 0x74, 0x12, 0x25, 0x0a, 0x08, 0x73, 0x72, 0x63, 0x5f, 0x61, 0x64, 0x64, - 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x70, 0x62, 0x66, 0x6c, 0x6f, 0x77, - 0x2e, 0x49, 0x50, 0x52, 0x07, 0x73, 0x72, 0x63, 0x41, 0x64, 0x64, 0x72, 0x12, 0x25, 0x0a, 0x08, - 0x64, 0x73, 0x74, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0a, - 0x2e, 0x70, 0x62, 0x66, 0x6c, 0x6f, 0x77, 0x2e, 0x49, 0x50, 0x52, 0x07, 0x64, 0x73, 0x74, 0x41, - 0x64, 0x64, 0x72, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x72, 0x63, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x73, 0x72, 0x63, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x19, - 0x0a, 0x08, 0x64, 0x73, 0x74, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, - 0x52, 0x07, 0x64, 0x73, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x7a, 0x6f, 0x6e, - 0x65, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x7a, 0x6f, 0x6e, 0x65, - 0x49, 0x64, 0x2a, 0x24, 0x0a, 0x09, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, - 0x0b, 0x0a, 0x07, 0x49, 0x4e, 0x47, 0x52, 0x45, 0x53, 0x53, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, - 0x45, 0x47, 0x52, 0x45, 0x53, 0x53, 0x10, 0x01, 0x32, 0x3e, 0x0a, 0x09, 0x43, 0x6f, 0x6c, 0x6c, - 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x31, 0x0a, 0x04, 0x53, 0x65, 0x6e, 0x64, 0x12, 0x0f, 0x2e, - 0x70, 0x62, 0x66, 0x6c, 0x6f, 0x77, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x1a, 0x16, - 0x2e, 0x70, 0x62, 0x66, 0x6c, 0x6f, 0x77, 0x2e, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x6f, - 0x72, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x42, 0x0a, 0x5a, 0x08, 0x2e, 0x2f, 0x70, 0x62, - 0x66, 0x6c, 0x6f, 0x77, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x69, 0x6e, 0x67, 0x12, 0x25, 0x0a, 0x0e, 0x66, 0x6c, 0x6f, 0x77, 0x5f, 0x65, 0x6e, 0x63, 0x72, + 0x79, 0x70, 0x74, 0x65, 0x64, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0d, 0x66, 0x6c, 0x6f, + 0x77, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x12, 0x2c, 0x0a, 0x12, 0x66, 0x6c, + 0x6f, 0x77, 0x5f, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x5f, 0x72, 0x65, 0x74, + 0x18, 0x1f, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x10, 0x66, 0x6c, 0x6f, 0x77, 0x45, 0x6e, 0x63, 0x72, + 0x79, 0x70, 0x74, 0x65, 0x64, 0x52, 0x65, 0x74, 0x22, 0x3c, 0x0a, 0x08, 0x44, 0x61, 0x74, 0x61, + 0x4c, 0x69, 0x6e, 0x6b, 0x12, 0x17, 0x0a, 0x07, 0x73, 0x72, 0x63, 0x5f, 0x6d, 0x61, 0x63, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x73, 0x72, 0x63, 0x4d, 0x61, 0x63, 0x12, 0x17, 0x0a, + 0x07, 0x64, 0x73, 0x74, 0x5f, 0x6d, 0x61, 0x63, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, + 0x64, 0x73, 0x74, 0x4d, 0x61, 0x63, 0x22, 0x6b, 0x0a, 0x07, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, + 0x6b, 0x12, 0x25, 0x0a, 0x08, 0x73, 0x72, 0x63, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x70, 0x62, 0x66, 0x6c, 0x6f, 0x77, 0x2e, 0x49, 0x50, 0x52, + 0x07, 0x73, 0x72, 0x63, 0x41, 0x64, 0x64, 0x72, 0x12, 0x25, 0x0a, 0x08, 0x64, 0x73, 0x74, 0x5f, + 0x61, 0x64, 0x64, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x70, 0x62, 0x66, + 0x6c, 0x6f, 0x77, 0x2e, 0x49, 0x50, 0x52, 0x07, 0x64, 0x73, 0x74, 0x41, 0x64, 0x64, 0x72, 0x12, + 0x12, 0x0a, 0x04, 0x64, 0x73, 0x63, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x64, + 0x73, 0x63, 0x70, 0x22, 0x3d, 0x0a, 0x02, 0x49, 0x50, 0x12, 0x14, 0x0a, 0x04, 0x69, 0x70, 0x76, + 0x34, 0x18, 0x01, 0x20, 0x01, 0x28, 0x07, 0x48, 0x00, 0x52, 0x04, 0x69, 0x70, 0x76, 0x34, 0x12, + 0x14, 0x0a, 0x04, 0x69, 0x70, 0x76, 0x36, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, + 0x04, 0x69, 0x70, 0x76, 0x36, 0x42, 0x0b, 0x0a, 0x09, 0x69, 0x70, 0x5f, 0x66, 0x61, 0x6d, 0x69, + 0x6c, 0x79, 0x22, 0x5d, 0x0a, 0x09, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x12, + 0x19, 0x0a, 0x08, 0x73, 0x72, 0x63, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0d, 0x52, 0x07, 0x73, 0x72, 0x63, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x64, 0x73, + 0x74, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x64, 0x73, + 0x74, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, + 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, + 0x6c, 0x22, 0xa3, 0x01, 0x0a, 0x04, 0x58, 0x6c, 0x61, 0x74, 0x12, 0x25, 0x0a, 0x08, 0x73, 0x72, + 0x63, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x70, + 0x62, 0x66, 0x6c, 0x6f, 0x77, 0x2e, 0x49, 0x50, 0x52, 0x07, 0x73, 0x72, 0x63, 0x41, 0x64, 0x64, + 0x72, 0x12, 0x25, 0x0a, 0x08, 0x64, 0x73, 0x74, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x70, 0x62, 0x66, 0x6c, 0x6f, 0x77, 0x2e, 0x49, 0x50, 0x52, + 0x07, 0x64, 0x73, 0x74, 0x41, 0x64, 0x64, 0x72, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x72, 0x63, 0x5f, + 0x70, 0x6f, 0x72, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x73, 0x72, 0x63, 0x50, + 0x6f, 0x72, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x64, 0x73, 0x74, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x64, 0x73, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x17, + 0x0a, 0x07, 0x7a, 0x6f, 0x6e, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, + 0x06, 0x7a, 0x6f, 0x6e, 0x65, 0x49, 0x64, 0x2a, 0x24, 0x0a, 0x09, 0x44, 0x69, 0x72, 0x65, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x0b, 0x0a, 0x07, 0x49, 0x4e, 0x47, 0x52, 0x45, 0x53, 0x53, 0x10, + 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x45, 0x47, 0x52, 0x45, 0x53, 0x53, 0x10, 0x01, 0x32, 0x3e, 0x0a, + 0x09, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x31, 0x0a, 0x04, 0x53, 0x65, + 0x6e, 0x64, 0x12, 0x0f, 0x2e, 0x70, 0x62, 0x66, 0x6c, 0x6f, 0x77, 0x2e, 0x52, 0x65, 0x63, 0x6f, + 0x72, 0x64, 0x73, 0x1a, 0x16, 0x2e, 0x70, 0x62, 0x66, 0x6c, 0x6f, 0x77, 0x2e, 0x43, 0x6f, 0x6c, + 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x42, 0x0a, 0x5a, + 0x08, 0x2e, 0x2f, 0x70, 0x62, 0x66, 0x6c, 0x6f, 0x77, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x33, } var ( diff --git a/pkg/pbflow/proto.go b/pkg/pbflow/proto.go index 89a9e231d..bf88f714c 100644 --- a/pkg/pbflow/proto.go +++ b/pkg/pbflow/proto.go @@ -84,6 +84,10 @@ func FlowToPB(fr *model.Record) *Record { DstPort: uint32(fr.Metrics.AdditionalMetrics.TranslatedFlow.Dport), ZoneId: uint32(fr.Metrics.AdditionalMetrics.TranslatedFlow.ZoneId), } + pbflowRecord.FlowEncryptedRet = uint32(fr.Metrics.AdditionalMetrics.FlowEncryptedRet) + if fr.Metrics.AdditionalMetrics.FlowEncrypted { + pbflowRecord.FlowEncrypted = uint32(1) + } } pbflowRecord.DupList = make([]*DupMapEntry, 0) for _, intf := range fr.Interfaces { @@ -166,6 +170,7 @@ func PBToFlow(pb *Record) *model.Record { Dport: uint16(pb.Xlat.GetDstPort()), ZoneId: uint16(pb.Xlat.GetZoneId()), }, + FlowEncryptedRet: uint8(pb.FlowEncryptedRet), }, }, TimeFlowStart: pb.TimeFlowStart.AsTime(), @@ -174,7 +179,9 @@ func PBToFlow(pb *Record) *model.Record { TimeFlowRtt: pb.TimeFlowRtt.AsDuration(), DNSLatency: pb.DnsLatency.AsDuration(), } - + if pb.FlowEncrypted != 0 { + out.Metrics.AdditionalMetrics.FlowEncrypted = true + } if len(pb.GetDupList()) != 0 { for _, entry := range pb.GetDupList() { out.Interfaces = append(out.Interfaces, model.IntfDirUdn{ diff --git a/pkg/tracer/tracer.go b/pkg/tracer/tracer.go index a7e160ad3..8e486f48b 100644 --- a/pkg/tracer/tracer.go +++ b/pkg/tracer/tracer.go @@ -41,6 +41,8 @@ const ( peerFilterMap = "peer_filter_map" globalCountersMap = "global_counters" pcaRecordsMap = "packet_record" + ipsecInputMap = "ipsec_ingress_map" + ipsecOutputMap = "ipsec_egress_map" // constants defined in flows.c as "volatile const" constSampling = "sampling" constHasFilterSampling = "has_filter_sampling" @@ -62,6 +64,7 @@ const ( rhNetworkEventsMonitoringHook = "rh_psample_sample_packet" networkEventsMonitoringHook = "psample_sample_packet" defaultNetworkEventsGroupID = 10 + constEnableIPsec = "enable_ipsec" ) var log = logrus.WithField("component", "ebpf.FlowFetcher") @@ -87,6 +90,10 @@ type FlowFetcher struct { ingressTCXLink map[ifaces.Interface]link.Link networkEventsMonitoringLink link.Link nfNatManIPLink link.Link + xfrmInputKretProbeLink link.Link + xfrmOutputKretProbeLink link.Link + xfrmInputKProbeLink link.Link + xfrmOutputKProbeLink link.Link lookupAndDeleteSupported bool useEbpfManager bool pinDir string @@ -109,6 +116,7 @@ type FlowFetcherConfig struct { EnablePktTranslation bool UseEbpfManager bool BpfManBpfFSPath string + EnableIPsecTracker bool FilterConfig []*FilterConfig } @@ -120,7 +128,8 @@ type variablesMapping struct { // nolint:golint,cyclop func NewFlowFetcher(cfg *FlowFetcherConfig) (*FlowFetcher, error) { var pktDropsLink, networkEventsMonitoringLink, rttFentryLink, rttKprobeLink link.Link - var nfNatManIPLink link.Link + var nfNatManIPLink, xfrmInputKretProbeLink, xfrmOutputKretProbeLink link.Link + var xfrmInputKProbeLink, xfrmOutputKProbeLink link.Link var err error objects := ebpf.BpfObjects{} var pinDir string @@ -152,7 +161,10 @@ func NewFlowFetcher(cfg *FlowFetcherConfig) (*FlowFetcher, error) { filterMap, peerFilterMap, globalCountersMap, - pcaRecordsMap} { + pcaRecordsMap, + ipsecInputMap, + ipsecOutputMap, + } { spec.Maps[m].Pinning = 0 } @@ -243,6 +255,29 @@ func NewFlowFetcher(cfg *FlowFetcherConfig) (*FlowFetcher, error) { return nil, fmt.Errorf("failed to attach the BPF program to nat_manip kprobe: %w", err) } } + + if cfg.EnableIPsecTracker { + xfrmInputKProbeLink, err = link.Kprobe("xfrm_input", objects.XfrmInputKprobe, nil) + if err != nil { + log.Warningf("failed to attach the BPF KProbe program to xfrm_input: %v", err) + return nil, fmt.Errorf("failed to attach the BPF KProbe program to xfrm_input: %w", err) + } + xfrmOutputKProbeLink, err = link.Kprobe("xfrm_output", objects.XfrmOutputKprobe, nil) + if err != nil { + log.Warningf("failed to attach the BPF KProbe program to xfrm_output: %v", err) + return nil, fmt.Errorf("failed to attach the BPF KProbe program to xfrm_output: %w", err) + } + xfrmInputKretProbeLink, err = link.Kretprobe("xfrm_input", objects.XfrmInputKretprobe, nil) + if err != nil { + log.Warningf("failed to attach the BPF KretProbe program to xfrm_input: %v", err) + return nil, fmt.Errorf("failed to attach the BPF KretProbe program to xfrm_input: %w", err) + } + xfrmOutputKretProbeLink, err = link.Kretprobe("xfrm_output", objects.XfrmOutputKretprobe, nil) + if err != nil { + log.Warningf("failed to attach the BPF KretProbe program to xfrm_output: %v", err) + return nil, fmt.Errorf("failed to attach the BPF KretProbe program to xfrm_output: %w", err) + } + } } else { pinDir = cfg.BpfManBpfFSPath opts := &cilium.LoadPinOptions{ @@ -299,6 +334,18 @@ func NewFlowFetcher(cfg *FlowFetcherConfig) (*FlowFetcher, error) { if err != nil { return nil, fmt.Errorf("failed to load %s: %w", mPath, err) } + log.Infof("BPFManager mode: loading skb input pinned maps") + mPath = path.Join(pinDir, ipsecInputMap) + objects.BpfMaps.IpsecIngressMap, err = cilium.LoadPinnedMap(mPath, opts) + if err != nil { + return nil, fmt.Errorf("failed to load %s: %w", mPath, err) + } + log.Infof("BPFManager mode: loading skb output pinned maps") + mPath = path.Join(pinDir, ipsecOutputMap) + objects.BpfMaps.IpsecEgressMap, err = cilium.LoadPinnedMap(mPath, opts) + if err != nil { + return nil, fmt.Errorf("failed to load %s: %w", mPath, err) + } } if filter != nil { @@ -325,6 +372,10 @@ func NewFlowFetcher(cfg *FlowFetcherConfig) (*FlowFetcher, error) { rttFentryLink: rttFentryLink, rttKprobeLink: rttKprobeLink, nfNatManIPLink: nfNatManIPLink, + xfrmInputKretProbeLink: xfrmInputKretProbeLink, + xfrmOutputKretProbeLink: xfrmOutputKretProbeLink, + xfrmInputKProbeLink: xfrmInputKProbeLink, + xfrmOutputKProbeLink: xfrmOutputKProbeLink, egressTCXLink: map[ifaces.Interface]link.Link{}, ingressTCXLink: map[ifaces.Interface]link.Link{}, networkEventsMonitoringLink: networkEventsMonitoringLink, @@ -703,6 +754,31 @@ func (m *FlowFetcher) Close() error { errs = append(errs, err) } } + + if m.xfrmInputKretProbeLink != nil { + if err := m.xfrmInputKretProbeLink.Close(); err != nil { + errs = append(errs, err) + } + } + + if m.xfrmInputKProbeLink != nil { + if err := m.xfrmInputKProbeLink.Close(); err != nil { + errs = append(errs, err) + } + } + + if m.xfrmOutputKretProbeLink != nil { + if err := m.xfrmOutputKretProbeLink.Close(); err != nil { + errs = append(errs, err) + } + } + + if m.xfrmOutputKProbeLink != nil { + if err := m.xfrmOutputKProbeLink.Close(); err != nil { + errs = append(errs, err) + } + } + // m.ringbufReader.Read is a blocking operation, so we need to close the ring buffer // from another goroutine to avoid the system not being able to exit if there // isn't traffic in a given interface @@ -766,6 +842,18 @@ func (m *FlowFetcher) Close() error { if err := m.objects.PeerFilterMap.Close(); err != nil { errs = append(errs, err) } + if err := m.objects.IpsecIngressMap.Unpin(); err != nil { + errs = append(errs, err) + } + if err := m.objects.IpsecIngressMap.Close(); err != nil { + errs = append(errs, err) + } + if err := m.objects.IpsecEgressMap.Unpin(); err != nil { + errs = append(errs, err) + } + if err := m.objects.IpsecEgressMap.Close(); err != nil { + errs = append(errs, err) + } if len(errs) == 0 { m.objects = nil } @@ -1063,6 +1151,10 @@ func kernelSpecificLoadAndAssign(oldKernel, rtKernel, supportNetworkEvents bool, TcxEgressPcaParse *cilium.Program `ebpf:"tcx_egress_pca_parse"` TcxIngressPcaParse *cilium.Program `ebpf:"tcx_ingress_pca_parse"` TrackNatManipPkt *cilium.Program `ebpf:"track_nat_manip_pkt"` + XfrmInputKretprobe *cilium.Program `ebpf:"xfrm_input_kretprobe"` + XfrmOutputKretprobe *cilium.Program `ebpf:"xfrm_output_kretprobe"` + XfrmInputKprobe *cilium.Program `ebpf:"xfrm_input_kprobe"` + XfrmOutputKprobe *cilium.Program `ebpf:"xfrm_output_kprobe"` } type newBpfObjects struct { newBpfPrograms @@ -1088,6 +1180,10 @@ func kernelSpecificLoadAndAssign(oldKernel, rtKernel, supportNetworkEvents bool, TcxEgressPcaParse: newObjects.TcxEgressPcaParse, TcxIngressPcaParse: newObjects.TcxIngressPcaParse, TrackNatManipPkt: newObjects.TrackNatManipPkt, + XfrmInputKretprobe: newObjects.XfrmInputKretprobe, + XfrmOutputKretprobe: newObjects.XfrmOutputKretprobe, + XfrmInputKprobe: newObjects.XfrmInputKprobe, + XfrmOutputKprobe: newObjects.XfrmOutputKprobe, TcpRcvKprobe: nil, TcpRcvFentry: nil, KfreeSkb: nil, @@ -1101,6 +1197,8 @@ func kernelSpecificLoadAndAssign(oldKernel, rtKernel, supportNetworkEvents bool, FilterMap: newObjects.FilterMap, PeerFilterMap: newObjects.PeerFilterMap, GlobalCounters: newObjects.GlobalCounters, + IpsecIngressMap: newObjects.IpsecIngressMap, + IpsecEgressMap: newObjects.IpsecEgressMap, }, } @@ -1116,6 +1214,10 @@ func kernelSpecificLoadAndAssign(oldKernel, rtKernel, supportNetworkEvents bool, TcxIngressPcaParse *cilium.Program `ebpf:"tcx_ingress_pca_parse"` TCPRcvKprobe *cilium.Program `ebpf:"tcp_rcv_kprobe"` TrackNatManipPkt *cilium.Program `ebpf:"track_nat_manip_pkt"` + XfrmInputKretprobe *cilium.Program `ebpf:"xfrm_input_kretprobe"` + XfrmOutputKretprobe *cilium.Program `ebpf:"xfrm_output_kretprobe"` + XfrmInputKprobe *cilium.Program `ebpf:"xfrm_input_kprobe"` + XfrmOutputKprobe *cilium.Program `ebpf:"xfrm_output_kprobe"` } type newBpfObjects struct { newBpfPrograms @@ -1141,6 +1243,10 @@ func kernelSpecificLoadAndAssign(oldKernel, rtKernel, supportNetworkEvents bool, TcxIngressPcaParse: newObjects.TcxIngressPcaParse, TcpRcvKprobe: newObjects.TCPRcvKprobe, TrackNatManipPkt: newObjects.TrackNatManipPkt, + XfrmInputKretprobe: newObjects.XfrmInputKretprobe, + XfrmOutputKretprobe: newObjects.XfrmOutputKretprobe, + XfrmInputKprobe: newObjects.XfrmInputKprobe, + XfrmOutputKprobe: newObjects.XfrmOutputKprobe, TcpRcvFentry: nil, KfreeSkb: nil, RhNetworkEventsMonitoring: nil, @@ -1153,6 +1259,8 @@ func kernelSpecificLoadAndAssign(oldKernel, rtKernel, supportNetworkEvents bool, FilterMap: newObjects.FilterMap, PeerFilterMap: newObjects.PeerFilterMap, GlobalCounters: newObjects.GlobalCounters, + IpsecIngressMap: newObjects.IpsecIngressMap, + IpsecEgressMap: newObjects.IpsecEgressMap, }, } @@ -1168,6 +1276,10 @@ func kernelSpecificLoadAndAssign(oldKernel, rtKernel, supportNetworkEvents bool, TcxIngressPcaParse *cilium.Program `ebpf:"tcx_ingress_pca_parse"` TCPRcvFentry *cilium.Program `ebpf:"tcp_rcv_fentry"` TrackNatManipPkt *cilium.Program `ebpf:"track_nat_manip_pkt"` + XfrmInputKretprobe *cilium.Program `ebpf:"xfrm_input_kretprobe"` + XfrmOutputKretprobe *cilium.Program `ebpf:"xfrm_output_kretprobe"` + XfrmInputKprobe *cilium.Program `ebpf:"xfrm_input_kprobe"` + XfrmOutputKprobe *cilium.Program `ebpf:"xfrm_output_kprobe"` } type newBpfObjects struct { newBpfPrograms @@ -1193,6 +1305,10 @@ func kernelSpecificLoadAndAssign(oldKernel, rtKernel, supportNetworkEvents bool, TcxIngressPcaParse: newObjects.TcxIngressPcaParse, TcpRcvFentry: newObjects.TCPRcvFentry, TrackNatManipPkt: newObjects.TrackNatManipPkt, + XfrmInputKretprobe: newObjects.XfrmInputKretprobe, + XfrmOutputKretprobe: newObjects.XfrmOutputKretprobe, + XfrmInputKprobe: newObjects.XfrmInputKprobe, + XfrmOutputKprobe: newObjects.XfrmOutputKprobe, TcpRcvKprobe: nil, KfreeSkb: nil, RhNetworkEventsMonitoring: nil, @@ -1205,6 +1321,8 @@ func kernelSpecificLoadAndAssign(oldKernel, rtKernel, supportNetworkEvents bool, FilterMap: newObjects.FilterMap, PeerFilterMap: newObjects.PeerFilterMap, GlobalCounters: newObjects.GlobalCounters, + IpsecIngressMap: newObjects.IpsecIngressMap, + IpsecEgressMap: newObjects.IpsecEgressMap, }, } @@ -1222,6 +1340,10 @@ func kernelSpecificLoadAndAssign(oldKernel, rtKernel, supportNetworkEvents bool, TCPRcvKprobe *cilium.Program `ebpf:"tcp_rcv_kprobe"` KfreeSkb *cilium.Program `ebpf:"kfree_skb"` TrackNatManipPkt *cilium.Program `ebpf:"track_nat_manip_pkt"` + XfrmInputKretprobe *cilium.Program `ebpf:"xfrm_input_kretprobe"` + XfrmOutputKretprobe *cilium.Program `ebpf:"xfrm_output_kretprobe"` + XfrmInputKprobe *cilium.Program `ebpf:"xfrm_input_kprobe"` + XfrmOutputKprobe *cilium.Program `ebpf:"xfrm_output_kprobe"` } type newBpfObjects struct { newBpfPrograms @@ -1248,6 +1370,10 @@ func kernelSpecificLoadAndAssign(oldKernel, rtKernel, supportNetworkEvents bool, TcpRcvKprobe: newObjects.TCPRcvKprobe, KfreeSkb: newObjects.KfreeSkb, TrackNatManipPkt: newObjects.TrackNatManipPkt, + XfrmInputKretprobe: newObjects.XfrmInputKretprobe, + XfrmOutputKretprobe: newObjects.XfrmOutputKretprobe, + XfrmInputKprobe: newObjects.XfrmInputKprobe, + XfrmOutputKprobe: newObjects.XfrmOutputKprobe, RhNetworkEventsMonitoring: nil, }, BpfMaps: ebpf.BpfMaps{ @@ -1258,6 +1384,8 @@ func kernelSpecificLoadAndAssign(oldKernel, rtKernel, supportNetworkEvents bool, FilterMap: newObjects.FilterMap, PeerFilterMap: newObjects.PeerFilterMap, GlobalCounters: newObjects.GlobalCounters, + IpsecIngressMap: newObjects.IpsecIngressMap, + IpsecEgressMap: newObjects.IpsecEgressMap, }, } @@ -1353,6 +1481,8 @@ func NewPacketFetcher(cfg *FlowFetcherConfig) (*PacketFetcher, error) { delete(spec.Programs, constEnableFlowFiltering) delete(spec.Programs, constEnableNetworkEventsMonitoring) delete(spec.Programs, constNetworkEventsMonitoringGroupID) + delete(spec.Programs, constEnablePktTranslation) + delete(spec.Programs, constEnableIPsec) if err := spec.LoadAndAssign(&newObjects, &cilium.CollectionOptions{Maps: cilium.MapOptions{PinPath: ""}}); err != nil { var ve *cilium.VerifierError @@ -1838,6 +1968,10 @@ func configureFlowSpecVariables(spec *cilium.CollectionSpec, cfg *FlowFetcherCon if cfg.EnablePktTranslation { enablePktTranslation = 1 } + enableIPsec := 0 + if cfg.EnableIPsecTracker { + enableIPsec = 1 + } // When adding constants here, remember to delete them in NewPacketFetcher variables := []variablesMapping{ {constSampling, uint32(cfg.Sampling)}, @@ -1850,6 +1984,7 @@ func configureFlowSpecVariables(spec *cilium.CollectionSpec, cfg *FlowFetcherCon {constEnableNetworkEventsMonitoring, uint8(enableNetworkEventsMonitoring)}, {constNetworkEventsMonitoringGroupID, uint8(networkEventsMonitoringGroupID)}, {constEnablePktTranslation, uint8(enablePktTranslation)}, + {constEnableIPsec, uint8(enableIPsec)}, } for _, mapping := range variables { diff --git a/proto/flow.proto b/proto/flow.proto index 93c149557..332a40d01 100644 --- a/proto/flow.proto +++ b/proto/flow.proto @@ -68,6 +68,8 @@ message Record { repeated NetworkEvent network_events_metadata = 27; Xlat xlat = 28; uint32 sampling = 29; + uint32 flow_encrypted = 30; + uint32 flow_encrypted_ret = 31; } message DataLink {