1use anyhow::Context;
2use anyhow::anyhow;
3use aya::maps::perf::PerfEventArrayBuffer;
4use chrono::Local;
5use cortexbrain_common::buffer_type::IpProtocols;
6use cortexbrain_common::buffer_type::PacketLossMetrics;
7use cortexbrain_common::buffer_type::PacketLog;
8use cortexbrain_common::buffer_type::TimeStampMetrics;
9use cortexbrain_common::formatters::{format_ipv4, format_ipv6};
10use cortexbrain_common::map_handlers::load_perf_event_array_from_mapdata;
11use std::str::FromStr;
12use std::sync::Mutex;
13use tonic::{Request, Response, Status};
14use tracing::info;
15
16use aya::maps::MapData;
17use std::result::Result::Ok;
18use tonic::async_trait;
19
20use aya::maps::HashMap as ayaHashMap;
21use std::collections::HashMap;
22use tokio::sync::mpsc;
23use tokio::task;
24
25use crate::agent::{
26 ConnectionEvent, DroppedPacketMetric, DroppedPacketsResponse, LatencyMetric,
27 LatencyMetricsResponse, VethEvent,
28};
29
30use cortexbrain_common::buffer_type::VethLog;
31
32use crate::agent::{
34 ActiveConnectionResponse, AddIpToBlocklistRequest, BlocklistResponse, RequestActiveConnections,
35 RmIpFromBlocklistRequest, RmIpFromBlocklistResponse, VethHashMapResponse, VethResponse,
36 agent_server::Agent,
37};
38use crate::constants::PIN_BLOCKLIST_MAP_PATH;
39
40use crate::helpers::comm_to_string;
41use aya::maps::Map;
42use std::net::Ipv4Addr;
43use tracing::warn;
44
45use cortexbrain_common::buffer_type::BufferSize;
46use cortexbrain_common::buffer_type::fill_buffers;
47
48pub struct AgentApi {
49 active_connection_event_rx: Mutex<mpsc::Receiver<Result<Vec<ConnectionEvent>, Status>>>,
52 pub(crate) active_connection_event_tx: mpsc::Sender<Result<Vec<ConnectionEvent>, Status>>,
53 latency_metrics_rx: Mutex<mpsc::Receiver<Result<Vec<LatencyMetric>, Status>>>,
54 pub(crate) latency_metrics_tx: mpsc::Sender<Result<Vec<LatencyMetric>, Status>>,
55 dropped_packet_metrics_rx: Mutex<mpsc::Receiver<Result<Vec<DroppedPacketMetric>, Status>>>,
56 pub(crate) dropped_packet_metrics_tx: mpsc::Sender<Result<Vec<DroppedPacketMetric>, Status>>,
57 tracked_veth_rx: Mutex<mpsc::Receiver<Result<Vec<VethEvent>, Status>>>,
58 pub(crate) tracked_veth_tx: mpsc::Sender<Result<Vec<VethEvent>, Status>>,
59}
60
61impl Default for AgentApi {
64 fn default() -> Self {
65 let active_connection_events_array =
71 load_perf_event_array_from_mapdata("/sys/fs/bpf/maps/events_map").unwrap();
72 let network_metrics_events_array =
73 load_perf_event_array_from_mapdata("/sys/fs/bpf/trace_maps/net_metrics").unwrap();
74 let time_stamp_events_array =
75 load_perf_event_array_from_mapdata("/sys/fs/bpf/trace_maps/time_stamp_events").unwrap();
76 let tracked_veth_events_array =
77 load_perf_event_array_from_mapdata("/sys/fs/bpf/maps/veth_identity_map").unwrap();
78
79 let (conn_tx, conn_rx) = mpsc::channel(1024);
84 let (lat_tx, lat_rx) = mpsc::channel(2048);
85 let (drop_tx, drop_rx) = mpsc::channel(2048);
86 let (veth_tx, tracked_veth_rx) = mpsc::channel(1024);
87
88 let api = AgentApi {
90 active_connection_event_rx: conn_rx.into(),
91 active_connection_event_tx: conn_tx.clone(),
92 latency_metrics_rx: Mutex::new(lat_rx),
93 latency_metrics_tx: lat_tx.clone(),
94 dropped_packet_metrics_rx: Mutex::new(drop_rx),
95 dropped_packet_metrics_tx: drop_tx.clone(),
96 tracked_veth_rx: Mutex::new(tracked_veth_rx),
97 tracked_veth_tx: veth_tx.clone(),
98 };
99
100 let mut net_events_buffers = BufferSize::TcpEvents.set_buffer();
105 let mut net_metrics_buffers = BufferSize::NetworkMetricsEvents.set_buffer();
106 let mut ts_metrics_buffers = BufferSize::TimeMetricsEvents.set_buffer();
107 let mut veth_metrics_buffers = BufferSize::VethEvents.set_buffer();
108
109 let mut net_events_vec_buffer = Vec::<PerfEventArrayBuffer<MapData>>::new();
112 let mut net_metrics_vec_buffer = Vec::<PerfEventArrayBuffer<MapData>>::new();
113 let mut ts_events_vec_buffer = Vec::<PerfEventArrayBuffer<MapData>>::new();
114 let mut veth_events_vec_buffer = Vec::<PerfEventArrayBuffer<MapData>>::new();
115
116 net_events_vec_buffer = fill_buffers(net_events_vec_buffer, active_connection_events_array);
119 net_metrics_vec_buffer = fill_buffers(net_metrics_vec_buffer, network_metrics_events_array);
120
121 ts_events_vec_buffer = fill_buffers(ts_events_vec_buffer, time_stamp_events_array);
122
123 veth_events_vec_buffer = fill_buffers(veth_events_vec_buffer, tracked_veth_events_array);
124
125 task::spawn(async move {
129 info!("Starting event listener");
130 loop {
132 for buf in net_events_vec_buffer.iter_mut() {
133 match buf.read_events(&mut net_events_buffers) {
134 Ok(events) => {
135 if events.read > 0 {
137 for i in 0..events.read {
138 let data = &net_events_buffers[i];
139 if data.len() >= std::mem::size_of::<PacketLog>() {
140 let pl: PacketLog =
141 unsafe { std::ptr::read(data.as_ptr() as *const _) };
142 let src = Ipv4Addr::from(u32::from_be(pl.src_ip));
143 let dst = Ipv4Addr::from(u32::from_be(pl.dst_ip));
144 let src_port = u16::from_be(pl.src_port as u16);
145 let dst_port = u16::from_be(pl.dst_port as u16);
146 let event_id = pl.pid;
147
148 match IpProtocols::try_from(pl.proto) {
149 Ok(proto) => {
150 info!(
151 "Event Id: {} Protocol: {:?} SRC: {}:{} -> DST: {}:{}",
152 event_id, proto, src, src_port, dst, dst_port
153 );
154 info!("creating vector for the aggregated data");
155 let mut evt = Vec::new();
156 info!("Inserting events into the vector");
158 evt.push(ConnectionEvent {
162 event_id: event_id.to_string(),
163 src_ip_port: format!("{}:{}", src, src_port),
164 dst_ip_port: format!("{}:{}", dst, dst_port),
165 });
166 info!("sending events to the MPSC channel");
167 let _ = conn_tx.send(Ok(evt)).await;
168 }
169 Err(_) => {
170 info!(
171 "Event Id: {} Protocol: Unknown ({})",
172 event_id, pl.proto
173 );
174 }
175 };
176 } else {
177 warn!(
178 "Received packet data too small: {} bytes",
179 data.len()
180 );
181 }
182 }
183 } else if events.lost > 0 {
184 info!("[Agent/API] Lost {} events", events.lost);
185 }
186 }
187 Err(e) => {
188 eprintln!("Error while reading events: {}", e);
189 tokio::time::sleep(tokio::time::Duration::from_millis(100)).await;
190 }
191 }
192 }
193 tokio::time::sleep(tokio::time::Duration::from_millis(100)).await;
195 }
196 });
197
198 task::spawn(async move {
199 info!("Starting network metrics listener");
200
201 loop {
203 for buf in net_metrics_vec_buffer.iter_mut() {
204 match buf.read_events(&mut net_metrics_buffers) {
205 Ok(events) => {
206 if events.read > 0 {
208 for i in 0..events.read {
209 let data = &net_metrics_buffers[i];
210 if data.len() >= std::mem::size_of::<PacketLossMetrics>() {
211 let nm: PacketLossMetrics =
212 unsafe { std::ptr::read(data.as_ptr() as *const _) };
213
214 let dropped_packet_metrics = DroppedPacketMetric {
215 tgid: nm.tgid,
216 process_name: comm_to_string(&nm.comm),
217 sk_drops: nm.sk_drops,
218 sk_err: nm.sk_err,
219 sk_err_soft: nm.sk_err_soft,
220 sk_backlog_len: nm.sk_backlog_len as u32,
221 sk_wmem_queued: nm.sk_write_memory_queued,
222 sk_rcvbuf: nm.sk_receive_buffer_size,
223 sk_ack_backlog: nm.sk_ack_backlog,
224 timestamp_us: nm.ts_us,
225 };
226
227 if dropped_packet_metrics.sk_drops > 0 {
228 let mut evt = Vec::new();
229 info!(
230 "Dropped Packet Metric - tgid: {}, process_name: {}, sk_drops: {}, sk_err: {}, sk_err_soft: {}, sk_backlog_len: {}, sk_wmem_queued: {}, sk_rcvbuf: {}, sk_ack_backlog: {}, timestamp_us: {}",
231 dropped_packet_metrics.tgid,
232 dropped_packet_metrics.process_name,
233 dropped_packet_metrics.sk_drops,
234 dropped_packet_metrics.sk_err,
235 dropped_packet_metrics.sk_err_soft,
236 dropped_packet_metrics.sk_backlog_len,
237 dropped_packet_metrics.sk_wmem_queued,
238 dropped_packet_metrics.sk_rcvbuf,
239 dropped_packet_metrics.sk_ack_backlog,
240 dropped_packet_metrics.timestamp_us
241 );
242 evt.push(dropped_packet_metrics.clone());
243 let _ = drop_tx.send(Ok(evt)).await;
244 }
245 } else {
246 warn!(
247 "Received network metrics data too small: {} bytes",
248 data.len()
249 );
250 }
251 }
252 }
253 }
254 Err(e) => {
255 eprintln!("Errore nella lettura network metrics eventi: {}", e);
256 tokio::time::sleep(tokio::time::Duration::from_millis(100)).await;
257 }
258 }
259 }
260 tokio::time::sleep(tokio::time::Duration::from_millis(100)).await;
262 }
263 });
264
265 task::spawn(async move {
266 info!("Starting time stamp events listener");
267
268 loop {
270 for buf in ts_events_vec_buffer.iter_mut() {
271 match buf.read_events(&mut ts_metrics_buffers) {
272 Ok(events) => {
273 if events.read > 0 {
275 for i in 0..events.read {
276 let data = &ts_metrics_buffers[i];
277 if data.len() >= std::mem::size_of::<TimeStampMetrics>() {
278 let tsm: TimeStampMetrics =
279 unsafe { std::ptr::read(data.as_ptr() as *const _) };
280 let saddr_v6 = tsm.saddr_v6;
281 let daddr_v6 = tsm.daddr_v6;
282 let latency_metric = LatencyMetric {
283 delta_us: tsm.delta_us,
284 timestamp_us: tsm.ts_us,
285 tgid: tsm.tgid,
286 process_name: comm_to_string(&tsm.comm),
287 local_port: tsm.lport as u32,
288 remote_port: tsm.dport_be as u32,
289 address_family: tsm.af as u32,
290 src_address_v4: format_ipv4(tsm.saddr_v4),
291 dst_address_v4: format_ipv4(tsm.daddr_v4),
292 src_address_v6: format_ipv6(&saddr_v6),
293 dst_address_v6: format_ipv6(&daddr_v6),
294 };
295 info!(
296 "Latency Metric - tgid: {}, process_name: {}, delta_us: {}, timestamp_us: {}, local_port: {}, remote_port: {}, address_family: {}, src_address_v4: {}, dst_address_v4: {}, src_address_v6: {}, dst_address_v6: {}",
297 latency_metric.tgid,
298 latency_metric.process_name,
299 latency_metric.delta_us,
300 latency_metric.timestamp_us,
301 latency_metric.local_port,
302 latency_metric.remote_port,
303 latency_metric.address_family,
304 latency_metric.src_address_v4,
305 latency_metric.dst_address_v4,
306 latency_metric.src_address_v6,
307 latency_metric.dst_address_v6
308 );
309 let mut evt = Vec::new();
310 evt.push(latency_metric.clone());
311 let _ = lat_tx.send(Ok(evt)).await;
312 } else {
313 warn!(
314 "Received time stamp metrics data too small: {} bytes",
315 data.len()
316 );
317 }
318 }
319 }
320 }
321 Err(e) => {
322 eprintln!("Errore nella lettura time stamp eventi: {}", e);
323 tokio::time::sleep(tokio::time::Duration::from_millis(100)).await;
324 }
325 }
326 }
327 }
328 });
329
330 task::spawn(async move {
331 info!("Starting time stamp events listener");
332
333 loop {
335 for buf in veth_events_vec_buffer.iter_mut() {
336 match buf.read_events(&mut veth_metrics_buffers) {
337 Ok(events) => {
338 if events.read > 0 {
340 for i in 0..events.read {
341 info!("Found veth events {}", events.read);
342 let data = &veth_metrics_buffers[i];
343 if data.len() >= std::mem::size_of::<VethLog>() {
344 let veth: VethLog =
345 unsafe { std::ptr::read(data.as_ptr() as *const _) };
346 let veth_event = VethEvent {
347 name: String::from_utf8_lossy(unsafe {
348 std::slice::from_raw_parts(
349 veth.name.as_ptr() as *const u8,
350 veth.name.len() * std::mem::size_of::<u32>(),
351 )
352 })
353 .trim_end_matches('\0')
354 .to_string(),
355 state: veth.state,
356 dev_addr: String::from_utf8_lossy(unsafe {
357 std::slice::from_raw_parts(
358 veth.dev_addr.as_ptr() as *const u8,
359 veth.dev_addr.len()
360 * std::mem::size_of::<u32>(),
361 )
362 })
363 .trim_end_matches('\0')
364 .to_string(),
365 event_type: veth.event_type.into(),
366 netns: veth.netns,
367 pid: veth.pid,
368 };
369 info!(
370 "Veth Event - name: {}, state: {}, dev_addr: {}, event_type: {}, netns: {}, pid: {}",
371 veth_event.name,
372 veth_event.state,
373 veth_event.dev_addr,
374 veth_event.event_type,
375 veth_event.netns,
376 veth_event.pid
377 );
378 let mut evt = Vec::new();
379 evt.push(veth_event.clone());
380 let _ = veth_tx.send(Ok(evt)).await;
381 } else {
382 warn!(
383 "Received time stamp metrics data too small: {} bytes",
384 data.len()
385 );
386 }
387 }
388 }
389 }
390 Err(e) => {
391 eprintln!("Errore nella lettura time stamp eventi: {}", e);
392 tokio::time::sleep(tokio::time::Duration::from_millis(100)).await;
393 }
394 }
395 }
396 }
397 });
398
399 api
400 }
401}
402
403#[async_trait]
406impl Agent for AgentApi {
407 async fn active_connections(
410 &self,
411 request: Request<RequestActiveConnections>,
412 ) -> Result<Response<ActiveConnectionResponse>, Status> {
413 let _req = request.into_inner();
415
416 let mut aggregated_events: Vec<ConnectionEvent> = Vec::new();
418
419 while let Ok(evt) = self.active_connection_event_rx.lock().unwrap().try_recv() {
421 if let Ok(vec) = evt {
422 aggregated_events.extend(vec);
423 }
424 }
425
426 info!(
428 "DEBUGGING RESPONSE FROM ACTIVE CONNECTION REQUEST: {:?}",
429 aggregated_events
430 );
431
432 Ok(Response::new(ActiveConnectionResponse {
434 status: "success".to_string(),
435 events: aggregated_events,
436 }))
437 }
438
439 async fn add_ip_to_blocklist(
441 &self,
442 request: Request<AddIpToBlocklistRequest>,
443 ) -> Result<Response<BlocklistResponse>, Status> {
444 let req = request.into_inner();
446
447 let mapdata = MapData::from_pin("/sys/fs/bpf/maps/blocklist_map")
449 .expect("cannot open blocklist_map Mapdata");
450 let blocklist_mapdata = Map::HashMap(mapdata); let mut blocklist_map: ayaHashMap<MapData, [u8; 4], [u8; 4]> =
452 ayaHashMap::try_from(blocklist_mapdata).unwrap();
453
454 if req.ip.is_none() {
455 info!("IP field in request is none");
457 info!("CURRENT BLOCKLIST: {:?}", blocklist_map);
458 } else {
459 let _datetime = Local::now().to_string();
462 let ip = req.ip.unwrap();
463 let u8_4_ip = Ipv4Addr::from_str(&ip).unwrap().octets();
465 blocklist_map
467 .insert(u8_4_ip, u8_4_ip, 0)
468 .map_err(|e| anyhow!("Cannot insert address in the blocklist. Reason: {}", e))
469 .unwrap();
470 info!("CURRENT BLOCKLIST: {:?}", blocklist_map);
471 }
472 let _path = std::env::var(PIN_BLOCKLIST_MAP_PATH)
473 .context("Blocklist map path not found!")
474 .unwrap();
475
476 let mut converted_blocklist_map: HashMap<String, String> = HashMap::new();
478 for item in blocklist_map.iter() {
479 let (k, _v) = item.unwrap();
480 let key = Ipv4Addr::from(k).to_string();
482 let value = Ipv4Addr::from(k).to_string();
483 converted_blocklist_map.insert(key, value);
484 }
485
486 Ok(Response::new(BlocklistResponse {
488 status: "success".to_string(),
489 events: converted_blocklist_map,
490 }))
491 }
492
493 async fn check_blocklist(
494 &self,
495 _request: Request<()>,
496 ) -> Result<Response<BlocklistResponse>, Status> {
497 info!("Returning blocklist hashmap");
498 let mapdata = MapData::from_pin("/sys/fs/bpf/maps/blocklist_map")
500 .expect("cannot open blocklist_map Mapdata");
501 let blocklist_mapdata = Map::HashMap(mapdata); let blocklist_map: ayaHashMap<MapData, [u8; 4], [u8; 4]> =
504 ayaHashMap::try_from(blocklist_mapdata).unwrap();
505
506 let mut converted_blocklist_map: HashMap<String, String> = HashMap::new();
509 for item in blocklist_map.iter() {
510 let (k, _v) = item.unwrap();
511 let key = Ipv4Addr::from(k).to_string();
513 let value = Ipv4Addr::from(k).to_string();
514 converted_blocklist_map.insert(key, value);
515 }
516 Ok(Response::new(BlocklistResponse {
517 status: "success".to_string(),
518 events: converted_blocklist_map,
519 }))
520 }
521 async fn rm_ip_from_blocklist(
522 &self,
523 request: Request<RmIpFromBlocklistRequest>,
524 ) -> Result<Response<RmIpFromBlocklistResponse>, Status> {
525 let req = request.into_inner();
527 info!("Removing ip from blocklist map");
528 let mapdata = MapData::from_pin("/sys/fs/bpf/maps/blocklist_map")
530 .expect("cannot open blocklist_map Mapdata");
531 let blocklist_mapdata = Map::HashMap(mapdata); let mut blocklist_map: ayaHashMap<MapData, [u8; 4], [u8; 4]> =
533 ayaHashMap::try_from(blocklist_mapdata).unwrap();
534 let ip_to_remove = req.ip;
536 let u8_4_ip_to_remove = Ipv4Addr::from_str(&ip_to_remove).unwrap().octets();
537 let _ = blocklist_map.remove(&u8_4_ip_to_remove);
538
539 let mut converted_blocklist_map: HashMap<String, String> = HashMap::new();
541 for item in blocklist_map.iter() {
542 let (k, v) = item.unwrap();
543 let key = Ipv4Addr::from(k).to_string();
545 let value = Ipv4Addr::from(k).to_string();
546 converted_blocklist_map.insert(key, value);
547 }
548
549 Ok(Response::new(RmIpFromBlocklistResponse {
550 status: "Ip removed from blocklist".to_string(),
551 events: converted_blocklist_map,
552 }))
553 }
554
555 async fn get_latency_metrics(
556 &self,
557 request: Request<()>,
558 ) -> Result<Response<LatencyMetricsResponse>, Status> {
559 let _req = request.into_inner();
561 info!("Getting latency metrics");
562
563 let mut aggregated_latency_metrics_events: Vec<LatencyMetric> = Vec::new();
567
568 while let Ok(evt) = self.latency_metrics_rx.lock().unwrap().try_recv() {
569 if let Ok(vec) = evt {
570 aggregated_latency_metrics_events.extend(vec);
571 }
572 }
573
574 let total_count = aggregated_latency_metrics_events.len() as u32;
575
576 let (average_latency_us, min_latency_us, max_latency_us) =
577 if !aggregated_latency_metrics_events.is_empty() {
578 let sum: u64 = aggregated_latency_metrics_events
579 .iter()
580 .map(|m| m.delta_us)
581 .sum();
582 let avg = sum as f64 / aggregated_latency_metrics_events.len() as f64;
583
584 let min = aggregated_latency_metrics_events
585 .iter()
586 .map(|m| m.delta_us)
587 .min()
588 .unwrap_or(0) as f64;
589
590 let max = aggregated_latency_metrics_events
591 .iter()
592 .map(|m| m.delta_us)
593 .max()
594 .unwrap_or(0) as f64;
595
596 (avg, min, max)
597 } else {
598 (0.0, 0.0, 0.0)
599 };
600
601 info!(
602 "Latency metrics - total_count: {}, average: {:.2}us, min: {:.2}us, max: {:.2}us",
603 total_count, average_latency_us, min_latency_us, max_latency_us
604 );
605
606 let response = LatencyMetricsResponse {
607 status: "success".to_string(),
608 metrics: aggregated_latency_metrics_events,
609 total_count,
610 average_latency_us,
611 max_latency_us,
612 min_latency_us,
613 };
614
615 Ok(Response::new(response))
616 }
617
618 async fn get_dropped_packets_metrics(
619 &self,
620 request: Request<()>,
621 ) -> Result<Response<DroppedPacketsResponse>, Status> {
622 let _req = request.into_inner();
624 info!("Getting dropped packets metrics");
625
626 let mut aggregated_dropped_packet_metrics: Vec<DroppedPacketMetric> = Vec::new();
627 let mut total_drops = 0u32;
628
629 while let Ok(evt) = self.dropped_packet_metrics_rx.lock().unwrap().try_recv() {
631 if let Ok(vec) = evt {
632 for metric in vec {
633 total_drops += metric.sk_drops as u32;
634 aggregated_dropped_packet_metrics.push(metric);
635 }
636 }
637 }
638
639 info!(
640 "Dropped packets metrics - total_metrics: {}, total_drops: {}",
641 aggregated_dropped_packet_metrics.len(),
642 total_drops
643 );
644
645 let response = DroppedPacketsResponse {
646 status: "success".to_string(),
647 metrics: aggregated_dropped_packet_metrics,
648 total_drops,
649 };
650
651 Ok(Response::new(response))
652 }
653
654 async fn get_tracked_veth(
655 &self,
656 request: Request<()>,
657 ) -> Result<Response<VethResponse>, Status> {
658 let _req = request.into_inner();
659 info!("Getting tracked veth metrics");
660 let mut tracked_veth = Vec::<VethEvent>::new();
661 let mut tot_veth = 0 as i32;
662
663 while let Ok(evt) = self.tracked_veth_rx.lock().unwrap().try_recv() {
664 if let Ok(vec) = evt {
665 tracked_veth.extend(vec);
666 }
667 }
668 tot_veth = tracked_veth.len() as i32;
669
670 info!("Total tracked veth events: {}", tot_veth);
671 info!("Tracked veth: {:?}", &tracked_veth);
672
673 let veth_names: Vec<String> = tracked_veth.iter().map(|v| v.name.clone()).collect();
674
675 let response = VethResponse {
676 status: "success".to_string(),
677 veth_names,
678 tot_monitored_veth: tot_veth,
679 };
680
681 Ok(Response::new(response))
682 }
683
684 async fn get_tracked_veth_from_hash_map(
685 &self,
686 _request: Request<()>,
687 ) -> Result<Response<VethHashMapResponse>, Status> {
688 info!("Returning veth hashmap");
689 let mapdata = MapData::from_pin("/sys/fs/bpf/maps/tracked_veth")
691 .expect("cannot open tracked_veth Mapdata");
692 let tracked_veth_mapdata = Map::HashMap(mapdata); let tracked_veth_map: ayaHashMap<MapData, [u8; 16], [u8; 8]> =
695 ayaHashMap::try_from(tracked_veth_mapdata).unwrap();
696
697 let mut converted_tracked_veth_map: HashMap<String, String> = HashMap::new();
700 for item in tracked_veth_map.iter() {
701 let (k, v) = item.unwrap();
702 let key = String::from_utf8(k.to_vec()).unwrap();
704 let value = String::from_utf8(v.to_vec()).unwrap();
705 converted_tracked_veth_map.insert(key, value);
706 }
707 Ok(Response::new(VethHashMapResponse {
708 status: "success".to_string(),
709 veths: converted_tracked_veth_map,
710 }))
711 }
712}