diff --git a/agent/Cargo.lock b/agent/Cargo.lock index 3baa5fc1388..4ba96fec1d7 100644 --- a/agent/Cargo.lock +++ b/agent/Cargo.lock @@ -1049,6 +1049,7 @@ dependencies = [ "tonic", "tonic-build", "trace-utils", + "tunnel", "uluru", "walkdir", "wasmtime", @@ -4375,6 +4376,10 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" +[[package]] +name = "tunnel" +version = "0.1.0" + [[package]] name = "twox-hash" version = "1.6.3" diff --git a/agent/Cargo.toml b/agent/Cargo.toml index 8992c5250d8..98d7f3fa41a 100644 --- a/agent/Cargo.toml +++ b/agent/Cargo.toml @@ -100,6 +100,7 @@ thiserror = "1.0" time = "0.3.9" tokio = { version = "1.20.1", features = ["full"] } tonic = "0.8.1" +tunnel = { path = "plugins/tunnel" } wasmtime = "12.0.1" wasmtime-wasi = "12.0.1" zstd = "0.13.2" diff --git a/agent/crates/public/src/consts.rs b/agent/crates/public/src/consts.rs index 48256fdc784..1df52cf0bc4 100644 --- a/agent/crates/public/src/consts.rs +++ b/agent/crates/public/src/consts.rs @@ -357,6 +357,20 @@ pub const TCP_DST_OFFSET: usize = IPV4_PACKET_SIZE + tcp::DST_OFFSET; // 36 pub const TCP6_SRC_OFFSET: usize = IPV6_PACKET_SIZE + tcp::SRC_OFFSET; // 54 pub const TCP6_DST_OFFSET: usize = IPV6_PACKET_SIZE + tcp::DST_OFFSET; // 56 +pub const LE_IPV4_PROTO_TYPE_I: u16 = 0x0008; // 0x0008's LittleEndian +pub const LE_IPV6_PROTO_TYPE_I: u16 = 0xDD86; // 0x86dd's LittleEndian +pub const LE_ERSPAN_PROTO_TYPE_II: u16 = 0xBE88; // 0x88BE's LittleEndian +pub const LE_ERSPAN_PROTO_TYPE_III: u16 = 0xEB22; // 0x22EB's LittleEndian +pub const LE_VXLAN_PROTO_UDP_DPORT: u16 = 0xB512; // 0x12B5(4789)'s LittleEndian +pub const LE_GPE_VXLAN_PROTO_UDP_DPORT: u16 = 0xB612; // 0x12B6(4790)'s LittleEndian +pub const LE_VXLAN_PROTO_UDP_DPORT2: u16 = 0x1821; // 0x2118(8472)'s LittleEndian +pub const LE_VXLAN_PROTO_UDP_DPORT3: u16 = 0x801A; // 0x1A80(6784)'s LittleEndian +pub const LE_TRANSPARENT_ETHERNET_BRIDGEING: u16 = 0x5865; // 0x6558(25944)'s LittleEndian +pub const LE_GENEVE_PROTO_UDP_DPORT: u16 = 0xc117; // 0x17c1(6081)'s LittleEndian + +pub const VXLAN_FLAGS: u8 = 8; +pub const TUNNEL_TIER_LIMIT: u8 = 2; + pub const VXLAN_FLAGS_OFFSET: usize = UDP_PACKET_SIZE + vxlan::FLAGS_OFFSET; pub const VXLAN_SEQ_OFFSET: usize = UDP_PACKET_SIZE + vxlan::SEQUENCE_OFFSET; pub const VXLAN_VNI_OFFSET: usize = UDP_PACKET_SIZE + vxlan::VNI_OFFSET; @@ -366,6 +380,51 @@ pub const VXLAN6_SEQ_OFFSET: usize = UDP6_PACKET_SIZE + vxlan::SEQUENCE_OFFSET; pub const VXLAN6_VNI_OFFSET: usize = UDP6_PACKET_SIZE + vxlan::VNI_OFFSET; pub const VXLAN6_DIRECTION_OFFSET: usize = UDP6_PACKET_SIZE + vxlan::DIRECTION_OFFSET; +// GPE_VXLAN: +// +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// |R|R|Ver|I|P|B|O| Reserved |Next Protocol | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | VXLAN Network Identifier (VNI) | Reserved | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +pub const GPE_VXLAN_FLAGS_INSTANCE_MASK: u8 = 0x8; +pub const GPE_VXLAN_FLAGS_PROTOCOL_MASK: u8 = 0x4; +pub const GPE_VXLAN_FLAGS_VERSION_MASK: u8 = 0x30; + +pub const GPE_VXLAN_NEXT_PROTOCOL_NSH: u8 = 4; + +pub const GPE_VXLAN_FLAGS_OFFSET: usize = 0; +pub const GPE_VXLAN_NEXT_PROTOCOL_OFFSET: usize = 3; +pub const GPE_VXLAN_VNI_OFFSET: usize = 4; + +pub const GPE_VXLAN_HEADER_SIZE: usize = 8; +pub const GEP_VXLAN_GRE_HEADER_SIZE: usize = 8; + +// NSH(Network Service Header): +// +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// |Ver|O|U| TTL | Length |U|U|U|U|MD Type| Next Protocol | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Service Path Header | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | | +// ~ Context Header(s) ~ +// | | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +pub const NSH_HEADER_SIZE: usize = 8; + +pub const NSH_FLAGS_OFFSET: usize = 0; +pub const NSH_NEXT_PROTOCOL_OFFSET: usize = 3; + +pub const NSH_FLAGS_BITS_MASK: u16 = 0xf000; +pub const NSH_FLAGS_LENGTH_MASK: u16 = 0x3f; + +pub const NSH_NEXT_PROTOCOL_IPV4: u8 = 1; + pub const GRE4_PROTO_OFFSET: usize = IPV4_PACKET_SIZE + erspan::GRE_PROTO_OFFSET; pub const GRE6_PROTO_OFFSET: usize = IPV6_PACKET_SIZE + erspan::GRE_PROTO_OFFSET; diff --git a/agent/plugins/tunnel/Cargo.toml b/agent/plugins/tunnel/Cargo.toml new file mode 100644 index 00000000000..6d096aeee55 --- /dev/null +++ b/agent/plugins/tunnel/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "tunnel" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/agent/plugins/tunnel/src/lib.rs b/agent/plugins/tunnel/src/lib.rs new file mode 100644 index 00000000000..1c5f0f5144b --- /dev/null +++ b/agent/plugins/tunnel/src/lib.rs @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2024 Yunshan Networks + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +pub fn decapsulate_gpe_vxlan(_packet: &mut [u8], _l2_len: usize) -> Option<(usize, u32)> { + None +} + +pub fn decapsulate_erspan( + _packet: &[u8], + _l2_len: usize, + _flags: u16, + _gre_protocol_type: u16, + _ip_header_size: usize, +) -> Option<(usize, u32)> { + None +} + +pub fn decapsulate_teb( + _packet: &[u8], + _l2_len: usize, + _flags: u16, + _ip_header_size: usize, +) -> Option<(usize, u32)> { + None +} + +pub fn decapsulate_tencent_gre( + _packet: &mut [u8], + _l2_len: usize, + _flags: u16, + _gre_protocol_type: u16, + _ip_header_size: usize, +) -> Option<(usize, u32)> { + None +} diff --git a/agent/resources/test/common/gre-nokey.pcap b/agent/resources/test/common/gre-nokey.pcap deleted file mode 100644 index d3b53e64edf..00000000000 Binary files a/agent/resources/test/common/gre-nokey.pcap and /dev/null differ diff --git a/agent/resources/test/common/tencent-gre.pcap b/agent/resources/test/common/tencent-gre.pcap deleted file mode 100644 index 17fa4376dc4..00000000000 Binary files a/agent/resources/test/common/tencent-gre.pcap and /dev/null differ diff --git a/agent/resources/test/common/vxlan-nsh.pcap b/agent/resources/test/common/vxlan-nsh.pcap new file mode 100644 index 00000000000..54cd194fd82 Binary files /dev/null and b/agent/resources/test/common/vxlan-nsh.pcap differ diff --git a/agent/src/common/decapsulate.rs b/agent/src/common/decapsulate.rs index 69bf663c671..1867303b395 100644 --- a/agent/src/common/decapsulate.rs +++ b/agent/src/common/decapsulate.rs @@ -28,6 +28,8 @@ use serde::Serialize; use public::proto::agent::DecapType; +use tunnel::{decapsulate_erspan, decapsulate_gpe_vxlan, decapsulate_teb, decapsulate_tencent_gre}; + #[derive(Serialize, Debug, Clone, Copy, PartialEq, PartialOrd, TryFromPrimitive)] #[repr(u8)] pub enum TunnelType { @@ -37,8 +39,9 @@ pub enum TunnelType { Ipip = DecapType::Ipip as u8, TencentGre = DecapType::Tencent as u8, Geneve = DecapType::Geneve as u8, - Erspan = DecapType::Geneve as u8 + 1, - Teb = DecapType::Geneve as u8 + 2, + VxlanNsh = DecapType::VxlanNsh as u8, + Erspan = DecapType::VxlanNsh as u8 + 1, + Teb = DecapType::VxlanNsh as u8 + 2, } impl From for TunnelType { @@ -49,6 +52,7 @@ impl From for TunnelType { DecapType::Ipip => TunnelType::Ipip, DecapType::Tencent => TunnelType::TencentGre, DecapType::Geneve => TunnelType::Geneve, + DecapType::VxlanNsh => TunnelType::VxlanNsh, } } } @@ -74,6 +78,7 @@ impl fmt::Display for TunnelType { TunnelType::Ipip => write!(f, "IPIP"), TunnelType::TencentGre => write!(f, "GRE"), TunnelType::Geneve => write!(f, "Geneve"), + TunnelType::VxlanNsh => write!(f, "VXLAN-NSH"), TunnelType::Erspan => write!(f, "ERSPAN"), TunnelType::Teb => write!(f, "TEB"), } @@ -87,6 +92,7 @@ impl From<&str> for TunnelType { "VXLAN" => TunnelType::Vxlan, "ERSPAN" => TunnelType::Erspan, "TEB" => TunnelType::Teb, + "VXLAN-NSH" => TunnelType::VxlanNsh, _ => TunnelType::None, } } @@ -186,19 +192,6 @@ impl fmt::Display for TunnelTypeBitmap { } } -const LE_IPV4_PROTO_TYPE_I: u16 = 0x0008; // 0x0008's LittleEndian -const LE_IPV6_PROTO_TYPE_I: u16 = 0xDD86; // 0x86dd's LittleEndian -const LE_ERSPAN_PROTO_TYPE_II: u16 = 0xBE88; // 0x88BE's LittleEndian -const LE_ERSPAN_PROTO_TYPE_III: u16 = 0xEB22; // 0x22EB's LittleEndian -const LE_VXLAN_PROTO_UDP_DPORT: u16 = 0xB512; // 0x12B5(4789)'s LittleEndian -const LE_VXLAN_PROTO_UDP_DPORT2: u16 = 0x1821; // 0x2118(8472)'s LittleEndian -const LE_VXLAN_PROTO_UDP_DPORT3: u16 = 0x801A; // 0x1A80(6784)'s LittleEndian -const LE_TRANSPARENT_ETHERNET_BRIDGEING: u16 = 0x5865; // 0x6558(25944)'s LittleEndian -const LE_GENEVE_PROTO_UDP_DPORT: u16 = 0xc117; // 0x17c1(6081)'s LittleEndian - -const VXLAN_FLAGS: u8 = 8; -const TUNNEL_TIER_LIMIT: u8 = 2; - #[derive(Clone, Copy, Debug, PartialEq)] pub struct TunnelInfo { pub src: Ipv4Addr, @@ -209,6 +202,7 @@ pub struct TunnelInfo { pub tunnel_type: TunnelType, pub tier: u8, pub is_ipv6: bool, + pub from: u32, // tunnel source ip } impl Default for TunnelInfo { @@ -222,11 +216,22 @@ impl Default for TunnelInfo { tunnel_type: TunnelType::default(), tier: 0, is_ipv6: false, + from: 0, } } } impl TunnelInfo { + pub fn reset_and_retain_erspan_from(&mut self) { + let from = if self.tunnel_type == TunnelType::Erspan { + u32::from_be_bytes(self.src.octets()) + } else { + 0 + }; + *self = Default::default(); + self.from = from; + } + fn decapsulate_addr(&mut self, l3_packet: &[u8]) { self.src = Ipv4Addr::from(bytes::read_u32_be( &l3_packet[FIELD_OFFSET_SIP - ETH_HEADER_SIZE..], @@ -248,7 +253,7 @@ impl TunnelInfo { pub fn decapsulate_udp( &mut self, - packet: &[u8], + packet: &mut [u8], l2_len: usize, tunnel_types: &TunnelTypeBitmap, ) -> usize { @@ -266,6 +271,9 @@ impl TunnelInfo { { return self.decapsulate_vxlan(packet, l2_len); } + LE_GPE_VXLAN_PROTO_UDP_DPORT if tunnel_types.has(TunnelType::VxlanNsh) => { + return self.decapsulate_gpe_vxlan(packet, l2_len); + } LE_GENEVE_PROTO_UDP_DPORT if tunnel_types.has(TunnelType::Geneve) => { return self.decapsulate_geneve(packet, l2_len); } @@ -286,6 +294,22 @@ impl TunnelInfo { 0 } + pub fn decapsulate_gpe_vxlan(&mut self, packet: &mut [u8], l2_len: usize) -> usize { + let Some((offset, id)) = decapsulate_gpe_vxlan(packet, l2_len) else { + return 0; + }; + + if self.tier == 0 { + self.decapsulate_addr(&packet[l2_len..]); + self.decapsulate_mac(packet); + self.tunnel_type = TunnelType::VxlanNsh; + self.id = id; + } + self.tier += 1; + + offset + } + pub fn decapsulate_vxlan(&mut self, packet: &[u8], l2_len: usize) -> usize { let l3_packet = &packet[l2_len..]; if l3_packet.len() < FIELD_OFFSET_VXLAN_FLAGS + VXLAN_HEADER_SIZE { @@ -332,60 +356,21 @@ impl TunnelInfo { gre_protocol_type: u16, ip_header_size: usize, ) -> usize { - let l3_packet = &packet[l2_len..]; - match gre_protocol_type { - // ERSPAN I - LE_ERSPAN_PROTO_TYPE_II if flags == 0 => { - // 仅保存最外层的隧道信息 - if self.tier == 0 { - self.decapsulate_addr(l3_packet); - self.decapsulate_mac(packet); - self.tunnel_type = TunnelType::Erspan; - } - self.tier += 1; - ip_header_size + GRE_HEADER_SIZE_DECAP + ERSPAN_I_HEADER_SIZE - } - // ERSPAN II - LE_ERSPAN_PROTO_TYPE_II => { - let gre_header_size = - GRE_HEADER_SIZE_DECAP + TunnelInfo::calc_gre_option_size(flags); - if self.tier == 0 { - self.decapsulate_addr(l3_packet); - self.decapsulate_mac(packet); - self.tunnel_type = TunnelType::Erspan; - self.id = bytes::read_u32_be( - &l3_packet[ip_header_size + gre_header_size + ERSPAN_ID_OFFSET..], - ) & 0x3ff; - } - self.tier += 1; - ip_header_size + gre_header_size + ERSPAN_II_HEADER_SIZE - } - LE_ERSPAN_PROTO_TYPE_III => { - let gre_header_size = - GRE_HEADER_SIZE_DECAP + TunnelInfo::calc_gre_option_size(flags); - // 仅保存最外层的隧道信息 - if self.tier == 0 { - self.decapsulate_addr(l3_packet); - self.decapsulate_mac(packet); - self.tunnel_type = TunnelType::Erspan; - self.id = bytes::read_u32_be( - &l3_packet[ip_header_size + gre_header_size + ERSPAN_ID_OFFSET..], - ) & 0x3ff; - } - self.tier += 1; - - let flag = - l3_packet[ip_header_size + gre_header_size + ERSPAN_III_FLAGS_OFFSET] & 0x1; - if flag == 0 { - return ip_header_size + gre_header_size + ERSPAN_III_HEADER_SIZE; - } - ip_header_size - + gre_header_size - + ERSPAN_III_HEADER_SIZE - + ERSPAN_III_SUBHEADER_SIZE - } - _ => 0, + let Some((offset, id)) = + decapsulate_erspan(packet, l2_len, flags, gre_protocol_type, ip_header_size) + else { + return 0; + }; + + if self.tier == 0 { + self.decapsulate_addr(&packet[l2_len..]); + self.decapsulate_mac(packet); + self.tunnel_type = TunnelType::Erspan; + self.id = id; } + self.tier += 1; + + offset } pub fn is_gre_pseudo_inner_mac(mac: u64) -> bool { @@ -400,63 +385,21 @@ impl TunnelInfo { gre_protocol_type: u16, ip_header_size: usize, ) -> usize { - // TCE GRE:Version 0、Version 1两种 - if flags & GRE_FLAGS_VER_MASK > 1 { + let Some((offset, id)) = + decapsulate_tencent_gre(packet, l2_len, flags, gre_protocol_type, ip_header_size) + else { return 0; - } - - let has_key = flags & GRE_FLAGS_KEY_MASK > 0; - let gre_header_size = GRE_HEADER_SIZE_DECAP + TunnelInfo::calc_gre_option_size(flags); - let mut gre_key_offset = GRE_KEY_OFFSET; - if flags & GRE_FLAGS_CSUM_MASK != 0 { - gre_key_offset += GRE_CSUM_LEN; - } + }; if self.tier == 0 { + self.decapsulate_addr(&packet[l2_len..]); self.decapsulate_mac(packet); - } - let l3_packet = &mut packet[l2_len..]; - // 仅保存最外层的隧道信息 - if self.tier == 0 { - self.decapsulate_addr(l3_packet); self.tunnel_type = TunnelType::TencentGre; - if has_key { - self.id = bytes::read_u32_be(&l3_packet[ip_header_size + gre_key_offset..]); - } + self.id = id; } self.tier += 1; - let overlay_offset = gre_header_size + ip_header_size - ETH_HEADER_SIZE; // 伪造L2层信息 - - // NOTICE: - // 这里需要将TunnelID封装为Mac Suffix,策略FastPath需要不同的MAC区分不同的VPC。 - // 腾讯GRE流量是通过TunnelID来确认其对应的EPC ID的,这个将TunnelID用作MAC后缀,同 - // 样能在FastPath里面区分不同的VPC。 - // 这样的伪造MAC可以通过IsGrePseudoInnerMac函数判断 - let mut macs = if gre_protocol_type == LE_IPV4_PROTO_TYPE_I { - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x8, 0] - } else { - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x86, 0xdd] - }; - if has_key { - // L2 Header - // - // 0 4 6 10 12 14 - // +-----------------+------------+----------------+------------+--------------+ - // | | 2-Byte Key | | 2-Byte Key | 0x800/0x86dd | - // +-----------------+------------+----------------+------------+--------------+ - // | Dest MAC | Source MAC | EthType | - macs[4..6].copy_from_slice( - &l3_packet - [ip_header_size + gre_key_offset + 2..ip_header_size + gre_key_offset + 4], - ); - macs[10..12].copy_from_slice( - &l3_packet[ip_header_size + gre_key_offset..ip_header_size + gre_key_offset + 2], - ); - } - l3_packet[overlay_offset..overlay_offset + 14].copy_from_slice(&macs[..]); - - overlay_offset + offset } pub fn decapsulate_teb( @@ -466,26 +409,19 @@ impl TunnelInfo { flags: u16, ip_header_size: usize, ) -> usize { - if flags & GRE_FLAGS_VER_MASK != 0 || flags & GRE_FLAGS_KEY_MASK == 0 { + let Some((offset, id)) = decapsulate_teb(packet, l2_len, flags, ip_header_size) else { return 0; - } - - let gre_header_size = GRE_HEADER_SIZE_DECAP + TunnelInfo::calc_gre_option_size(flags); - let mut gre_key_offset = GRE_KEY_OFFSET; - if flags & GRE_FLAGS_CSUM_MASK != 0 { - gre_key_offset += GRE_CSUM_LEN; - } - - let l3_packet = &packet[l2_len..]; + }; // 仅保存最外层的隧道信息 if self.tier == 0 { - self.decapsulate_addr(l3_packet); + self.decapsulate_addr(&packet[l2_len..]); self.decapsulate_mac(packet); self.tunnel_type = TunnelType::Teb; - self.id = bytes::read_u32_be(&l3_packet[ip_header_size + gre_key_offset..]); + self.id = id; } self.tier += 1; - gre_header_size + ip_header_size + + offset } pub fn decapsulate_gre( @@ -850,6 +786,7 @@ mod tests { tunnel_type: TunnelType::Erspan, tier: 1, is_ipv6: false, + from: 0, }; let mut packets: Vec> = Capture::load_pcap( Path::new(PCAP_PATH_PREFIX).join("decapsulate_erspan1.pcap"), @@ -886,6 +823,7 @@ mod tests { tunnel_type: TunnelType::Erspan, tier: 1, is_ipv6: false, + from: 0, }; let mut packets: Vec> = Capture::load_pcap( Path::new(PCAP_PATH_PREFIX).join("decapsulate_test.pcap"), @@ -922,6 +860,7 @@ mod tests { tunnel_type: TunnelType::Erspan, tier: 1, is_ipv6: false, + from: 0, }; let mut packets: Vec> = Capture::load_pcap( Path::new(PCAP_PATH_PREFIX).join("decapsulate_test.pcap"), @@ -951,6 +890,7 @@ mod tests { tunnel_type: TunnelType::Vxlan, tier: 1, is_ipv6: false, + from: 0, }; let mut packets: Vec> = Capture::load_pcap( Path::new(PCAP_PATH_PREFIX).join("decapsulate_test.pcap"), @@ -980,6 +920,7 @@ mod tests { tunnel_type: TunnelType::Vxlan, tier: 1, is_ipv6: false, + from: 0, }; let mut packets: Vec> = Capture::load_pcap(Path::new(PCAP_PATH_PREFIX).join("ff-vxlan.pcap"), None).into(); @@ -993,87 +934,6 @@ mod tests { assert_eq!(actual, expected); } - #[test] - fn test_decapsulate_tencent_gre_nokey() { - let bitmap = TunnelTypeBitmap::new(&vec![TunnelType::TencentGre, TunnelType::Vxlan]); - let expected = TunnelInfo { - src: Ipv4Addr::new(10, 184, 17, 156), - dst: Ipv4Addr::new(10, 128, 48, 25), - mac_src: 0x381fc0f2, - mac_dst: 0xdd09cd02, - id: 65877, - tunnel_type: TunnelType::Vxlan, - tier: 2, - is_ipv6: false, - }; - let expected_overlay = [ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 69, 0, 0, 52, 237, 62, 64, 0, 63, 6, 184, - 251, 10, 185, 192, 25, 10, 129, 192, 54, - ]; - - let mut packets: Vec> = - Capture::load_pcap(Path::new(PCAP_PATH_PREFIX).join("gre-nokey.pcap"), None).into(); - let packet = packets[0].as_mut_slice(); - - let mut actual = TunnelInfo::default(); - let expected_offset = 82; - let mut actual_offset = 0; - for l2_len in vec![22, 14] { - let offset = actual.decapsulate(&mut packet[actual_offset..], l2_len, &bitmap); - if actual.tunnel_type == TunnelType::None { - break; - } - if actual_offset + offset > packet.len() { - break; - } - actual_offset += l2_len + offset; - } - - let actual_overlay: [u8; 34] = packet[actual_offset..actual_offset + 34] - .try_into() - .unwrap(); - assert_eq!(expected_overlay, actual_overlay); - assert_eq!(actual, expected); - assert_eq!(actual_offset, expected_offset); - } - - #[test] - fn test_decapsulate_tencent_gre() { - let bitmap = TunnelTypeBitmap::new(&vec![TunnelType::TencentGre]); - let expected = TunnelInfo { - src: Ipv4Addr::new(10, 19, 0, 21), - dst: Ipv4Addr::new(10, 21, 64, 5), - mac_src: 0xbffac801, - mac_dst: 0x06246b71, - id: 0x10285, - tunnel_type: TunnelType::TencentGre, - tier: 1, - is_ipv6: false, - }; - let expected_overlay = [ - 0x00, 0x00, 0x00, 0x00, 0x02, 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, - 0x45, 0x00, 0x00, 0x28, 0x87, 0x93, 0x40, 0x00, 0x40, 0x06, 0xa8, 0xe7, 0x0a, 0x01, - 0xfb, 0x29, 0x0a, 0x01, 0xfb, 0x29, - ]; - - let mut packets: Vec> = - Capture::load_pcap(Path::new(PCAP_PATH_PREFIX).join("tencent-gre.pcap"), None).into(); - let packet = packets[0].as_mut_slice(); - - let l2_len = 14; - let mut actual = TunnelInfo::default(); - let offset = actual.decapsulate(packet, l2_len, &bitmap); - let expected_offset = 18; - - let actual_overlay: [u8; 34] = packet - [l2_len + expected_offset..l2_len + expected_offset + 34] - .try_into() - .unwrap(); - assert_eq!(expected_overlay, actual_overlay); - assert_eq!(offset, expected_offset); - assert_eq!(actual, expected); - } - #[test] fn test_decapsulate_teb() { let bitmap = TunnelTypeBitmap::new(&vec![TunnelType::Teb]); @@ -1086,6 +946,7 @@ mod tests { tunnel_type: TunnelType::Teb, tier: 1, is_ipv6: false, + from: 0, }; let mut packets: Vec> = Capture::load_pcap( Path::new(PCAP_PATH_PREFIX).join("vmware-gre-teb.pcap"), @@ -1115,6 +976,7 @@ mod tests { tunnel_type: TunnelType::Vxlan, tier: 1, is_ipv6: true, + from: 0, }; let mut packets: Vec> = Capture::load_pcap(Path::new(PCAP_PATH_PREFIX).join("ip6-vxlan.pcap"), None).into(); @@ -1141,6 +1003,7 @@ mod tests { tunnel_type: TunnelType::Ipip, tier: 1, is_ipv6: false, + from: 0, }; let mut packets: Vec> = Capture::load_pcap(Path::new(PCAP_PATH_PREFIX).join("ipip.pcap"), None).into(); @@ -1189,6 +1052,7 @@ mod tests { tunnel_type: TunnelType::Geneve, tier: 1, is_ipv6: false, + from: 0, }; let mut packets: Vec> = Capture::load_pcap(Path::new(PCAP_PATH_PREFIX).join("geneve.pcap"), None).into(); @@ -1199,4 +1063,28 @@ mod tests { assert_eq!(offset, IPV4_HEADER_SIZE + 24); assert_eq!(actual, expected); } + + #[test] + fn test_decapsulate_vxlan_nsh() { + let bitmap = TunnelTypeBitmap::new(&vec![TunnelType::VxlanNsh]); + let expected = TunnelInfo { + src: Ipv4Addr::new(29, 29, 14, 47), + dst: Ipv4Addr::new(29, 29, 14, 211), + mac_src: 0xfd12f40e, + mac_dst: 0x5e000109, + id: 0, + tunnel_type: TunnelType::VxlanNsh, + tier: 1, + is_ipv6: false, + from: 0, + }; + let mut packets: Vec> = + Capture::load_pcap(Path::new(PCAP_PATH_PREFIX).join("vxlan-nsh.pcap"), None).into(); + let packet = packets[0].as_mut_slice(); + + let mut actual = TunnelInfo::default(); + let offset = actual.decapsulate(packet, 14, &bitmap); + assert_eq!(offset, 74); + assert_eq!(actual, expected); + } } diff --git a/agent/src/common/tap_port.rs b/agent/src/common/tap_port.rs index 51aab3c9e27..be2821a21ec 100644 --- a/agent/src/common/tap_port.rs +++ b/agent/src/common/tap_port.rs @@ -117,9 +117,10 @@ impl TapPort { ) } - pub fn from_id(tunnel_type: TunnelType, id: u32) -> Self { + pub fn from_id(tunnel_type: TunnelType, id: u32, tunnel_from: u32) -> Self { Self( - id as u64 + ((id as u64) & 0xff) + | ((tunnel_from << 8) as u64) | ((tunnel_type as u64 & Self::TUNNEL_TYPE_MASK) << Self::TUNNEL_TYPE_OFFSET) | ((Self::FROM_ID as u64) << Self::FROM_OFFSET), ) diff --git a/agent/src/config/config.rs b/agent/src/config/config.rs index aa18bde261d..347feb0c2fa 100644 --- a/agent/src/config/config.rs +++ b/agent/src/config/config.rs @@ -661,6 +661,7 @@ pub struct AfPacket { pub src_interfaces: Vec, pub vlan_pcp_in_physical_mirror_traffic: u16, pub bpf_filter_disabled: bool, + pub skip_npb_bpf: bool, pub tunning: AfPacketTunning, } @@ -674,6 +675,7 @@ impl Default for AfPacket { extra_bpf_filter: "".to_string(), vlan_pcp_in_physical_mirror_traffic: 0, bpf_filter_disabled: false, + skip_npb_bpf: false, tunning: AfPacketTunning::default(), src_interfaces: vec![], } diff --git a/agent/src/config/handler.rs b/agent/src/config/handler.rs index 12bf699bed8..27874e446fa 100755 --- a/agent/src/config/handler.rs +++ b/agent/src/config/handler.rs @@ -330,6 +330,7 @@ pub struct DispatcherConfig { pub proxy_controller_ip: String, pub proxy_controller_port: u16, pub capture_bpf: String, + pub skip_npb_bpf: bool, pub max_memory: u64, pub af_packet_blocks: usize, #[cfg(any(target_os = "linux", target_os = "android"))] @@ -1636,6 +1637,7 @@ impl TryFrom<(Config, UserConfig)> for ModuleConfig { #[cfg(target_os = "linux")] extra_netns_regex: conf.inputs.cbpf.af_packet.extra_netns_regex.clone(), tap_interface_regex: conf.inputs.cbpf.af_packet.interface_regex.clone(), + skip_npb_bpf: conf.inputs.cbpf.af_packet.skip_npb_bpf, if_mac_source: conf.inputs.resources.private_cloud.vm_mac_source.into(), analyzer_ip: dest_ip.clone(), analyzer_port: conf.global.communication.ingester_port, @@ -2601,6 +2603,14 @@ impl ConfigHandler { af_packet.bpf_filter_disabled = new_af_packet.bpf_filter_disabled; restart_agent = !first_run; } + if af_packet.skip_npb_bpf != new_af_packet.skip_npb_bpf { + info!( + "Update inputs.cbpf.af_packet.skip_npb_bpf from {:?} to {:?}.", + af_packet.skip_npb_bpf, new_af_packet.skip_npb_bpf + ); + af_packet.skip_npb_bpf = new_af_packet.skip_npb_bpf; + restart_agent = !first_run; + } if af_packet.bond_interfaces != new_af_packet.bond_interfaces { info!( "Update inputs.cbpf.af_packet.bond_interfaces from {:?} to {:?}.", diff --git a/agent/src/dispatcher/analyzer_mode_dispatcher.rs b/agent/src/dispatcher/analyzer_mode_dispatcher.rs index 5906c3a230b..8b931f98a98 100644 --- a/agent/src/dispatcher/analyzer_mode_dispatcher.rs +++ b/agent/src/dispatcher/analyzer_mode_dispatcher.rs @@ -210,7 +210,7 @@ impl AnalyzerModeDispatcher { Some(vmac) => (true, u64::from(*vmac) as u32), None => (false, 0), }; - let mut tap_port = TapPort::from_id(tunnel_info.tunnel_type, id as u32); + let mut tap_port = TapPort::from_id(tunnel_info.tunnel_type, id as u32, tunnel_info.from); let is_unicast = tunnel_info.tier > 0 || !MacAddr::is_multicast(overlay_packet); // Consider unicast when there is a tunnel if src_remote && dst_remote && is_unicast { diff --git a/agent/src/dispatcher/base_dispatcher.rs b/agent/src/dispatcher/base_dispatcher.rs index b1c57636fb8..2cfc7d119a3 100644 --- a/agent/src/dispatcher/base_dispatcher.rs +++ b/agent/src/dispatcher/base_dispatcher.rs @@ -517,7 +517,7 @@ impl BaseDispatcher { // vxlan-erspan:隧道信息为空 // erspan-vxlan;隧道信息为vxlan,隧道层数为1 // erspan-vxlan-erspan;隧道信息为空 - *tunnel_info = Default::default(); + tunnel_info.reset_and_retain_erspan_from(); } decap_len += offset; } @@ -806,6 +806,7 @@ impl BaseDispatcherListener { proxy_controller_port: self.proxy_controller_port, analyzer_source_ip: source_ip.unwrap(), analyzer_port: self.analyzer_port, + skip_npb_bpf: options.skip_npb_bpf, }; let mut bpf_options = self.bpf_options.lock().unwrap(); diff --git a/agent/src/dispatcher/mod.rs b/agent/src/dispatcher/mod.rs index 0e72e91af8d..874eff36401 100644 --- a/agent/src/dispatcher/mod.rs +++ b/agent/src/dispatcher/mod.rs @@ -573,6 +573,7 @@ pub struct Options { pub fanout_enabled: bool, #[cfg(any(target_os = "linux", target_os = "android"))] pub promisc: bool, + pub skip_npb_bpf: bool, } impl Options { diff --git a/agent/src/dispatcher/recv_engine/bpf.rs b/agent/src/dispatcher/recv_engine/bpf.rs index bd252cc3a46..ff718ce12b7 100644 --- a/agent/src/dispatcher/recv_engine/bpf.rs +++ b/agent/src/dispatcher/recv_engine/bpf.rs @@ -88,6 +88,7 @@ pub(crate) struct Builder { pub proxy_controller_port: u16, pub controller_tls_port: u16, pub analyzer_source_ip: IpAddr, + pub skip_npb_bpf: bool, } #[cfg(any(target_os = "linux", target_os = "android"))] @@ -725,7 +726,9 @@ impl Builder { // 不采集和TSDB通信的流量 bpf_builder.appends(&mut self.skip_ipv4_tsdb()); // 不采集分发流量 - bpf_builder.appends(&mut self.skip_ipv4_npb()); + if self.skip_npb_bpf { + bpf_builder.appends(&mut self.skip_ipv4_npb()); + } return bpf_builder.build(); } @@ -736,7 +739,9 @@ impl Builder { // 不采集和TSDB通信的流量 bpf_builder.appends(&mut self.skip_ipv6_tsdb()); // 不采集分发流量 - bpf_builder.appends(&mut self.skip_ipv6_npb()); + if self.skip_npb_bpf { + bpf_builder.appends(&mut self.skip_ipv6_npb()); + } return bpf_builder.build(); } @@ -779,26 +784,28 @@ impl Builder { ip_version, self.analyzer_source_ip, self.analyzer_port )); - // 不采集分发的VXLAN流量 - conditions.push(format!( - "not (udp and dst port {} and udp[8:1]={:#x})", - self.npb_port, self.vxlan_flags - )); - - // 不采集分发的TCP流量 - conditions.push(format!("not (tcp and port {})", self.npb_port,)); - - // 不采集分发的ERSPANIII - conditions.push(format!( - "not (ip[9:1]={:#x} and ip[22:2]={:#x})", - u8::from(IpProtocol::GRE), - GRE_PROTO_ERSPAN_III - )); - conditions.push(format!( - "not (ip6[6:1]={:#x} and ip6[42:2]={:#x})", - u8::from(IpProtocol::GRE), - GRE_PROTO_ERSPAN_III - )); + if self.skip_npb_bpf { + // 不采集分发的VXLAN流量 + conditions.push(format!( + "not (udp and dst port {} and udp[8:1]={:#x})", + self.npb_port, self.vxlan_flags + )); + + // 不采集分发的TCP流量 + conditions.push(format!("not (tcp and port {})", self.npb_port,)); + + // 不采集分发的ERSPANIII + conditions.push(format!( + "not (ip[9:1]={:#x} and ip[22:2]={:#x})", + u8::from(IpProtocol::GRE), + GRE_PROTO_ERSPAN_III + )); + conditions.push(format!( + "not (ip6[6:1]={:#x} and ip6[42:2]={:#x})", + u8::from(IpProtocol::GRE), + GRE_PROTO_ERSPAN_III + )); + } conditions.join(" and ") } @@ -820,6 +827,7 @@ mod tests { proxy_controller_port: 7788, analyzer_port: 8899, analyzer_source_ip: "1.2.3.4".parse::().unwrap(), + skip_npb_bpf: true, }; let syntax = builder.build_pcap_syntax(); @@ -909,6 +917,7 @@ mod tests { analyzer_source_ip: "9999:aaaa:bbbb:cccc:dddd:eeee:ffff:0000" .parse::() .unwrap(), + skip_npb_bpf: true, }; let syntax = builder.build_pcap_syntax(); diff --git a/agent/src/flow_generator/flow_map.rs b/agent/src/flow_generator/flow_map.rs index d92713bdc5b..343e72d0f30 100644 --- a/agent/src/flow_generator/flow_map.rs +++ b/agent/src/flow_generator/flow_map.rs @@ -33,6 +33,7 @@ use std::{ use ahash::AHashMap; use log::{debug, warn}; use lru::LruCache; +use pnet::packet::icmp::IcmpTypes; use super::{ app_table::AppTable, @@ -1344,6 +1345,10 @@ impl FlowMap { } } node.tagged_flow.flow.direction_score = direction_score; + } else if let ProtocolData::IcmpData(icmp_data) = &meta_packet.protocol_data { + if icmp_data.icmp_type == IcmpTypes::EchoReply.0 { + node.tagged_flow.flow.reverse(true); + } } /* diff --git a/agent/src/flow_generator/flow_node.rs b/agent/src/flow_generator/flow_node.rs index 0304acd5813..7f378aff04b 100644 --- a/agent/src/flow_generator/flow_node.rs +++ b/agent/src/flow_generator/flow_node.rs @@ -281,19 +281,13 @@ impl FlowNode { && flow_key.port_src == meta_lookup_key.src_port && flow_key.port_dst == meta_lookup_key.dst_port { - // l3 protocols, such as icmp, can determine the direction of packets according - // to icmp type, so there is no need to correct the direction of packets - if meta_lookup_key.is_tcp() || meta_lookup_key.is_udp() { - meta_packet.lookup_key.direction = PacketDirection::ClientToServer; - } + meta_packet.lookup_key.direction = PacketDirection::ClientToServer; } else if flow_key.ip_src == meta_lookup_key.dst_ip && flow_key.ip_dst == meta_lookup_key.src_ip && flow_key.port_src == meta_lookup_key.dst_port && flow_key.port_dst == meta_lookup_key.src_port { - if meta_lookup_key.is_tcp() || meta_lookup_key.is_udp() { - meta_packet.lookup_key.direction = PacketDirection::ServerToClient; - } + meta_packet.lookup_key.direction = PacketDirection::ServerToClient; } else { return false; } diff --git a/agent/src/trident.rs b/agent/src/trident.rs index c82472f71ed..999f501725c 100644 --- a/agent/src/trident.rs +++ b/agent/src/trident.rs @@ -2517,6 +2517,7 @@ impl AgentComponents { proxy_controller_port: candidate_config.dispatcher.proxy_controller_port, analyzer_source_ip: source_ip, analyzer_port: candidate_config.dispatcher.analyzer_port, + skip_npb_bpf: candidate_config.dispatcher.skip_npb_bpf, }; let bpf_syntax_str = bpf_builder.build_pcap_syntax_to_str(); #[cfg(any(target_os = "linux", target_os = "android"))] diff --git a/message/agent.proto b/message/agent.proto index 968eb0f925c..e96ff4f8b24 100644 --- a/message/agent.proto +++ b/message/agent.proto @@ -190,6 +190,7 @@ enum DecapType { DECAP_TYPE_IPIP = 2; DECAP_TYPE_TENCENT = 3; DECAP_TYPE_GENEVE = 4; + DECAP_TYPE_VXLAN_NSH = 5; } enum SystemLoadMetric { diff --git a/message/trident.proto b/message/trident.proto index 996c6034b7e..287f8cb318c 100644 --- a/message/trident.proto +++ b/message/trident.proto @@ -189,6 +189,7 @@ enum DecapType { DECAP_TYPE_IPIP = 2; DECAP_TYPE_TENCENT = 3; DECAP_TYPE_GENEVE = 4; + DECAP_TYPE_VXLAN_NSH = 5; } enum SystemLoadMetric { diff --git a/server/agent_config/README-CH.md b/server/agent_config/README-CH.md index ade07dfa0c6..ea77332073b 100644 --- a/server/agent_config/README-CH.md +++ b/server/agent_config/README-CH.md @@ -2368,6 +2368,35 @@ inputs: 内核的 BPF 包过滤能力,而是获取全流量的数据包之后由采集器程序进行过滤。注意,打开此开关将明显 增加 deepflow-agent 的资源消耗。 +#### 跳过 NPB BPF {#inputs.cbpf.af_packet.skip_npb_bpf} + +**标签**: + +agent_restart + +**FQCN**: + +`inputs.cbpf.af_packet.skip_npb_bpf` + +Upgrade from old version: `static_config.skip-npb-bpf` + +**默认值**: +```yaml +inputs: + cbpf: + af_packet: + skip_npb_bpf: false +``` + +**模式**: +| Key | Value | +| ---- | ---------------------------- | +| Type | bool | + +**详细描述**: + +如果采集网卡中有 ERSPAN 流量但是没有分发流量,开启这个开关来采集 ERSPAN 流量。 + #### 调优 {#inputs.cbpf.af_packet.tunning} ##### Socket 版本 {#inputs.cbpf.af_packet.tunning.socket_version} @@ -2949,6 +2978,7 @@ inputs: | 2 | IPIP | | 3 | GRE | | 4 | Geneve | +| 5 | VXLAN-NSH | **模式**: | Key | Value | @@ -2957,7 +2987,7 @@ inputs: **详细描述**: -deepflow-agent 需要对数据包解封装的隧道协议。 +deepflow-agent 需要对数据包解封装的隧道协议,仅企业版本支持解析 GRE 和 VXLAN-NSH。 #### 隧道头剥离协议 {#inputs.cbpf.preprocess.tunnel_trim_protocols} @@ -2994,6 +3024,7 @@ inputs: **详细描述**: 流量镜像(虚拟或物理)模式下,deepflow-agent 需要剥离的隧道头协议类型。 +仅企业版支持解析 ERSPAN 和 TEB。 #### TCP分段重组开关 {#inputs.cbpf.preprocess.packet_segmentation_reassembly} diff --git a/server/agent_config/README.md b/server/agent_config/README.md index d9fdb9cecce..9b894e27311 100644 --- a/server/agent_config/README.md +++ b/server/agent_config/README.md @@ -2422,6 +2422,36 @@ will not use the filtering capabilities of BPF, and will filter by itself after capturing full traffic. Note that this may significantly increase the resource overhead of deepflow-agent. +#### Skip NPB BPF {#inputs.cbpf.af_packet.skip_npb_bpf} + +**Tags**: + +agent_restart + +**FQCN**: + +`inputs.cbpf.af_packet.skip_npb_bpf` + +Upgrade from old version: `static_config.skip-npb-bpf` + +**Default value**: +```yaml +inputs: + cbpf: + af_packet: + skip_npb_bpf: false +``` + +**Schema**: +| Key | Value | +| ---- | ---------------------------- | +| Type | bool | + +**Description**: + +If the NIC on the data plane has ERSPAN tunnel traffic but does not NPB traffic, +enable the switch to collect ERSPAN traffic. + #### Tunning {#inputs.cbpf.af_packet.tunning} ##### Socket Version {#inputs.cbpf.af_packet.tunning.socket_version} @@ -3016,6 +3046,7 @@ inputs: | 2 | IPIP | | 3 | GRE | | 4 | Geneve | +| 5 | VXLAN-NSH | **Schema**: | Key | Value | @@ -3024,7 +3055,7 @@ inputs: **Description**: -Decapsulation tunnel protocols. +Decapsulation tunnel protocols, Only the Enterprise Edition supports decap GRE and VXLAN-NSH. #### Tunnel Trim Protocols {#inputs.cbpf.preprocess.tunnel_trim_protocols} @@ -3061,6 +3092,7 @@ inputs: **Description**: Whether to remove the tunnel header in mirrored traffic. +Only the Enterprise Edition supports decap ERSPAN and TEB. #### Packet Segmentation Reassembly {#inputs.cbpf.preprocess.packet_segmentation_reassembly} diff --git a/server/agent_config/config.go b/server/agent_config/config.go index 8c5cedc7fc5..803efd8c60c 100644 --- a/server/agent_config/config.go +++ b/server/agent_config/config.go @@ -212,6 +212,7 @@ type StaticConfig struct { NtpMinInterval *string `yaml:"ntp-min-interval,omitempty"` DispatcherQueue *bool `yaml:"dispatcher-queue,omitempty"` EbpfCollectorQueueSize *int `yaml:"ebpf-collector-queue-size,omitempty"` + SkipNpbBpf *bool `yaml:"skip-npb-bpf,omitempty"` } type XflowCollectorConfig struct { diff --git a/server/agent_config/example.yaml b/server/agent_config/example.yaml index 7200a8feaa5..9ac524054b3 100644 --- a/server/agent_config/example.yaml +++ b/server/agent_config/example.yaml @@ -170,7 +170,8 @@ capture_socket_type: 0 tap_mode: 0 # Decapsulation Tunnel Protocols -# Default: [1, 2], means VXLAN and IPIP. Options: 1 (VXLAN), 2 (IPIP), 3 (GRE), 4 (Geneve) +# Default: [1, 2], means VXLAN and IPIP. Options: 1 (VXLAN), 2 (IPIP), 3 (GRE), 4 (Geneve) 5 (VXLAN-NSH) +# Note: Only the Enterprise Edition supports decap GRE and VXLAN-NSH. decap_type: - 1 - 2 @@ -1010,6 +1011,13 @@ static_config: # that the VNI bit is set, the value configured here will be used after |= 0x8. vxlan-flags: 0xff + # Capture bpf without npb filter. + # Default: false. Range: [true, false] + # Note: + # If the NIC on the data plane has ERSPAN tunnel traffic but does not NPB traffic, + # enable the switch to collect ERSPAN traffic. + skip-npb-bpf: false + # NPB Packet ignoring VLAN Header in overlay # Default: false. Range: [true, false] # Note: @@ -1023,6 +1031,7 @@ static_config: # Remove Tunnel Header # Default: [], Range: [ERSPAN, VXLAN, TEB] # Note: Whether to remove the tunnel header in mirrored traffic. + # Only the Enterprise Edition supports decap ERSPAN and TEB. trim-tunnel-types: [] ########## diff --git a/server/agent_config/template.yaml b/server/agent_config/template.yaml index 8eb80f031a7..9b43d2a8745 100644 --- a/server/agent_config/template.yaml +++ b/server/agent_config/template.yaml @@ -1651,6 +1651,23 @@ inputs: # 增加 deepflow-agent 的资源消耗。 # upgrade_from: static_config.bpf-disabled bpf_filter_disabled: false + # type: bool + # name: + # en: Skip NPB BPF + # ch: 跳过 NPB BPF + # unit: + # range: [] + # enum_options: [] + # modification: agent_restart + # ee_feature: false + # description: + # en: |- + # If the NIC on the data plane has ERSPAN tunnel traffic but does not NPB traffic, + # enable the switch to collect ERSPAN traffic. + # ch: |- + # 如果采集网卡中有 ERSPAN 流量但是没有分发流量,开启这个开关来采集 ERSPAN 流量。 + # upgrade_from: static_config.skip-npb-bpf + skip_npb_bpf: false # type: section # name: # en: Tunning @@ -2020,13 +2037,14 @@ inputs: # - 2: IPIP # - 3: GRE # - 4: Geneve + # - 5: VXLAN-NSH # modification: hot_update # ee_feature: false # description: # en: |- - # Decapsulation tunnel protocols. + # Decapsulation tunnel protocols, Only the Enterprise Edition supports decap GRE and VXLAN-NSH. # ch: |- - # deepflow-agent 需要对数据包解封装的隧道协议。 + # deepflow-agent 需要对数据包解封装的隧道协议,仅企业版本支持解析 GRE 和 VXLAN-NSH。 # upgrade_from: decap_type tunnel_decap_protocols: [1, 2] # type: string @@ -2041,8 +2059,10 @@ inputs: # description: # en: |- # Whether to remove the tunnel header in mirrored traffic. + # Only the Enterprise Edition supports decap ERSPAN and TEB. # ch: |- # 流量镜像(虚拟或物理)模式下,deepflow-agent 需要剥离的隧道头协议类型。 + # 仅企业版支持解析 ERSPAN 和 TEB。 # upgrade_from: static_config.trim-tunnel-types tunnel_trim_protocols: [] diff --git a/server/querier/db_descriptions/clickhouse/tag/enum/tunnel_type b/server/querier/db_descriptions/clickhouse/tag/enum/tunnel_type index 60cdf598cce..d585d234822 100644 --- a/server/querier/db_descriptions/clickhouse/tag/enum/tunnel_type +++ b/server/querier/db_descriptions/clickhouse/tag/enum/tunnel_type @@ -4,3 +4,4 @@ 2 , IPIP , 3 , GRE , 4 , Geneve , +5 , VXLAN-NSH ,