FMADIO LXC system high level architecture is shown below.
This provides a full lossless filtered version of data directly into the LXC container for processing.
Backpressure is provided thru the LXC Ring structure, allowing the application to consume data as fast or slow as possible without dropping anything.
Sending Data to LXC Offline
During development its typically easiest to send data into the LXC container in a one time replay operation. This allows sending the same data repeatedly to the application allow the engineers to debug and test the code.
In this example we will use the application "fmadio2pcap" which converts the LXC ring into a standard PCAP formatted stream of data.
Its recommended to start the data consumer aka LXC application first, then start the replay.
Consumer - fmadio2pcap tcpdump
Run the following on the LXC container to generate TCPDUMP output thru the lxc ring named "general"
/opt/fmadio/platform/fmadio2pcap -i /opt/fmadio/queue/lxc_ring_general | tcpdump -r - -nn
It will look similar to the following on startup, it stops because no packets have been sent to the ring.
root@fmadio40v3-440-centos7:/opt/fmadio/platform/fmadio2pcap# ./fmadio2pcap -i /opt/fmadio/queue/lxc_ring_general | tcpdump -r - -nn
fmadio2pcap
FMAD Ring [/opt/fmadio/queue/lxc_ring_general]
Ring size : 12595200 12595200 16777216
Ring Version: 100 100
Ring Depth : 400 400
Ring Mask : 3ff 3ff
RING: Put:1612f 12f
RING: Get:1612f 12f
Producer - stream_cat sending to LXC ring
On the FMADIO Host system find a capture you want to replay. In this example we are using capture named "inetsample_20230615_1513" filename can be found using "stream_dump"
The command is as follows
sudo stream_cat --ring /opt/fmadio/queue/lxc_ring_general --ring-filter-bpf /opt/fmadio/queue/lxc_ring_general "icmp" -v inetsample_20230615_1513
Example output of the command shown below
fmadio@fmadio40v3-440:/mnt/store0/tmp2$ sudo stream_cat --ring /opt/fmadio/queue/lxc_ring_general --ring-filter-bpf /opt/fmadio/queue/lxc_ring_general "icmp" -v inetsample_20230615_1513
Create FMAD Ring:0 [/opt/fmadio/queue/lxc_ring_general]
found ring: [/opt/fmadio/queue/lxc_ring_general] id:0
FMAD Ring:0 [/opt/fmadio/queue/lxc_ring_general] FilterBPF[icmp]
RING[/opt/fmadio/queue/lxc_ring_general ] 00 : CPU: 0 FilterBPF:[icmp] FilterFrame:[(null)]
StartChunkID: 766030
StartChunk: 766030 Offset: 0 Stride: 1
StartChunk: 766030
RING[/opt/fmadio/queue/lxc_ring_general ] Size : 12595200 16777216
RING[/opt/fmadio/queue/lxc_ring_general ] Version: 100 100
RING[/opt/fmadio/queue/lxc_ring_general ] Put:54a 14a 0x7f30c8cc1000
RING[/opt/fmadio/queue/lxc_ring_general ] Get:54a 14a 0x7f30c8cc2000
RING[/opt/fmadio/queue/lxc_ring_general ] thread:0
RING[/opt/fmadio/queue/lxc_ring_general ] worker thread start
0M Offset: 0GB ChunkID:766030 TS:00:00:00.000.000.000 | Pending 31590 MB 0.000Gbps 0.000Mpps CPUIdle:0.000 CPUFetch:0.595 CPUSend:0.000
2M Offset: 2GB ChunkID:776263 TS:00:00:00.000.000.000 | Pending 29032 MB 21.164Gbps 2.311Mpps CPUIdle:0.000 CPUFetch:0.955 CPUSend:0.000
4M Offset: 4GB ChunkID:786596 TS:00:00:00.000.000.000 | Pending 26449 MB 21.374Gbps 2.300Mpps CPUIdle:0.000 CPUFetch:0.957 CPUSend:0.000
6M Offset: 7GB ChunkID:796886 TS:00:00:00.000.000.000 | Pending 23876 MB 21.283Gbps 2.318Mpps CPUIdle:0.000 CPUFetch:0.956 CPUSend:0.000
.
.
.
And on the LXC client side the output will show ICMP packets printed in tcpdump format as shown below
root@fmadio40v3-440-centos7:/opt/fmadio/platform/fmadio2pcap# ./fmadio2pcap -i /opt/fmadio/queue/lxc_ring_general | tcpdump -r - -nn | head -n 1000
fmadio2pcap
FMAD Ring [/opt/fmadio/queue/lxc_ring_general]
Ring size : 12595200 12595200 16777216
Ring Version: 100 100
Ring Depth : 400 400
Ring Mask : 3ff 3ff
RING: Put:29c1 1c1
RING: Get:29c1 1c1
reading from file -, link-type EN10MB (Ethernet)
13:39:53.729815 IP 130.128.35.9 > 210.175.175.21: ICMP echo request, id 4494, seq 1, length 64
13:39:53.731604 IP 210.175.175.21 > 130.128.35.9: ICMP echo reply, id 4494, seq 1, length 64
13:39:53.732577 IP 45.0.191.213 > 8.8.8.8: ICMP echo request, id 13542, seq 25606, length 40
13:39:53.733466 IP 202.17.221.191 > 216.58.200.196: ICMP host 202.17.221.191 unreachable, length 123
13:39:53.733501 IP 202.17.221.191 > 216.58.200.196: ICMP host 202.17.221.191 unreachable, length 123
13:39:53.733641 IP 8.8.8.8 > 45.0.191.213: ICMP echo reply, id 13542, seq 25606, length 40
13:39:53.734071 IP 130.128.255.176 > 103.235.46.39: ICMP echo request, id 65301, seq 2, length 64
13:39:53.744961 IP 130.128.255.81 > 210.175.175.21: ICMP echo request, id 4498, seq 1, length 64
13:39:53.746434 IP 210.175.175.21 > 130.128.255.81: ICMP echo reply, id 4498, seq 1, length 64
13:39:53.762392 IP 12.133.183.36 > 45.0.191.123: ICMP echo reply, id 46807, seq 6777, length 28
13:39:53.770100 IP 45.0.252.242 > 8.8.8.8: ICMP echo request, id 6172, seq 0, length 64
13:39:53.771160 IP 8.8.8.8 > 45.0.252.242: ICMP echo reply, id 6172, seq 0, length 64
13:39:53.775954 IP 130.128.5.7 > 172.21.32.22: ICMP echo request, id 63039, seq 32022, length 40
13:39:53.776217 IP 130.128.5.7 > 172.21.32.21: ICMP echo request, id 63039, seq 32278, length 40
13:39:53.776490 IP 130.128.5.7 > 172.21.32.20: ICMP echo request, id 63039, seq 32534, length 40
13:39:53.776777 IP 130.128.5.7 > 172.21.32.19: ICMP echo request, id 63039, seq 32790, length 40
13:39:53.790153 IP 45.0.191.229 > 8.8.8.8: ICMP echo request, id 34054, seq 39636, length 44
13:39:53.800539 IP 45.0.191.122 > 8.8.8.8: ICMP echo request, id 8265, seq 44218, length 64
13:39:53.801850 IP 8.8.8.8 > 45.0.191.122: ICMP echo reply, id 8265, seq 44218, length 64
.
.
.
Custom Application
For a custom application to directly ingest data, the following reference code is provided
Primary header file with all functions and strcutures inline
https://github.com/fmadio/platform/blob/main/include/fmadio_packet.h
Core example code to retreive packets
https://github.com/fmadio/platform/blob/main/fmadio2pcap/main.c#L160-L185
Core loop snippet, this converts from LXC Ring into standard PCAP Packet format
while (!s_Exit)
{
u64 TS;
PCAPPacket_t* Pkt = (PCAPPacket_t*)PktBuffer;
// fetch packet from ring without blocking
int ret = FMADPacket_RecvV1(s_RING, false, &TS, &Pkt->LengthWire, &Pkt->LengthCapture, NULL, Pkt + 1);
// if it has valid data
if (ret > 0)
{
// convert 64b epoch into sec/subsec for pcap
Pkt->Sec = TS / (u64)1e9;
Pkt->NSec = TS % (u64)1e9;
// write PCAP header and payload
fwrite(PktBuffer, 1, sizeof(PCAPPacket_t) + Pkt->LengthCapture, FPCAP);
// general stats
TotalPkt += 1;
TotalByte += ret;
}
// end of stream
if (ret < 0) break;
}