dotpcap / sharppcap

Official repository - Fully managed, cross platform (Windows, Mac, Linux) .NET library for capturing packets
1.28k stars 267 forks source link

SendPacket latency question #441

Open lk-davidegironi opened 1 year ago

lk-davidegironi commented 1 year ago

Hi all.

I'm using Sharppcap Npcap mode to receive and send Ethernet II RAW packet.

I've notice a behaviour I'm not able to explain myself. I suppose it's related to some kind of queue laying on the underline pcap level, but I'm here to ask you.

First of all my hardware:

Sharppcap function used to read and write packet:

Then my test logic:

Code testing:

Now the behaviour:

The question:

I don't expect a fully working environment, due to the non-real-time nature of the Windows kernel. But that's something "strange" that I can not explain myself. The flyback time should be always as low as the 10kHz time (or slower), the 1kHz flyback time makes me think that packets are send out only after some kind of queue is fulfilled, and of course with 1kHz time this queue takes more to fulfill. There is something I don't catch here, or something I've made wrong. Here I need your help to achive better performance.

Thank you!

Find below the C# code I'm using. This is not the exact code I'm using cause my code is part of and Interface, but is the extract of that code that has some value for the subject.

private Stopwatch _statsStopwatch1 = new Stopwatch();
private ILiveDevice _device = null;
private int _statsPacketInNum = 0;
private long _statsWorkerTimeMs = 0;

private void Initialize() {
  CaptureDeviceList devices = CaptureDeviceList.Instance;
  _device = devices.Where(r => r.Description != null).Where(r => r.Description == description).FirstOrDefault();
  _device.OnPacketArrival += new PacketArrivalEventHandler(OnPacketArrival);
  _device.Open(new DeviceConfiguration { Mode = DeviceModes.Promiscuous, Immediate = true, ReadTimeout = 1 });
  _device.Filter = "ether src host 48-00-00-00-00-00";
  _device.StartCapture();
}

private void OnPacketArrival(object sender, PacketCapture e) {
  _statsPacketInNum++;
  RawCapture rawPacket = e.GetPacket();
  Packet packet = Packet.ParsePacket(rawPacket.LinkLayerType, rawPacket.Data);
  if (packet != null && packet is EthernetPacket eth) {
    EthernetPacket ethpacket = packet as EthernetPacket;
    if (ethpacket.HasPayloadData) {
      byte[] data = ethpacket.PayloadData;
      // edit data packet
      // ...
      // send packet back
      List<byte> packet = new List<byte>();
      packet.AddRange("48-00-00-00-00-00");
      packet.AddRange("00-57-AA-12-66-22");
      packet.AddRange(new byte[] { 0x55, 0x55 });
      packet.AddRange(data);
      _statsStopwatch1.Reset();
      _statsStopwatch1.Start();
      _device.SendPacket(packet.ToArray(), packet.Count);
      _statsStopwatch1.Stop();
      _statsWorkerTimeMs += _statsStopwatch1.ElapsedMilliseconds; // this value is then divided by _statsPacketInNum to get the mean time
   }
}
kayoub5 commented 1 year ago

@lk-davidegironi

lk-davidegironi commented 1 year ago

Thanks @kayoub5 for your interest

One more thing I've try is using an Intel i210 NIC board. Nothing changed. I'll keep you updated... in case I found something usefull.

kayoub5 commented 1 year ago
kayoub5 commented 1 year ago

other things to consider:

lk-davidegironi commented 1 year ago

Thank you @kayoub5

I'm wondering if a plain c/c++ software could help me for tests.

lk-davidegironi commented 1 year ago

Something interesting I've noticed: .NET 5.0, .NET Core 3.0 and 3.1 has almost the same performance .NET 6.0 or .NET 7.0 is almost half the performance of the above

kayoub5 commented 1 year ago

I'm wondering if a plain c/c++ software could help me for tests.

Possible, I would recommend using a different driver (like winpktfilter) or a kernel bypass using dpdk if that does not help.