Re: [EVL] Client UDP not receiving data

Hannes Diethelm <[email protected]>
Newsgroups dev.linux.lists.xenomai
Message-ID <[email protected]>
Am 21.05.26 um 11:49 schrieb Philippe Gerum:
> Hannes Diethelm <[email protected]> writes:
> 
>> Hello
>>
>> I have issue porting an application that runs as an UDP client to OOB networking.
>>
>> The standard client pattern:
>> -connect
>> -oob_sendmsg
>> -oob_recvmsg
>> does not work.
>>
>> In Wireshark, i see the packages going out and returning with the correct ip/port
>> but oob_recvmsg() doesn't return.
>>
>> To debug, I modified the oob-net-udp example, attached. Additionally, I ported it back
>> to posix networking where it works as expected.
>>
>> Send only mode / receive with bind works well.
>>
>> Config:
>> Debian Trixie
>> linux-evl v6.12.y-cip-evl-rebase 569beef0
>> libevl r57 877d5ca
>>
> 
> I believe oob-net-udp does work as is, but not the way you seem to
> expect it, which led your to change the original logic so that two
> instances of this program always run head to tail, each one running a
> sender+receiver loop.
> 
> The original intent was to implement half-duplex roles instead, starting
> each instance either with the -S (send mode) or -R (receive mode,
> default) option switch, in order to explicitly select a role.
> 
> This allows for more configurations, like mixing the network stacks to
> use for testing. For instance, we are currently able to broadcast
> packets to listeners on port #42042 over the wire from a vanilla linux
> system (no evl) to an evl-enabled one, using VLAN-based selection of
> packets:
> 
> /*
>   * From the vanilla system, through VLAN device eno2.1
>   */
> 
> $ echo -n "Hello world" | sudo socat - udp-datagram:255.255.255.255:42042,broadcast,so-bindtodevice=eno2.1
> 
> /*
>   * From the evl system, listening to all oob interfaces using VLAN-based
>   * packet selection.
>   */
> 
> ~# oob-net-udp -R -a broadcast
> == receiver mode (<= broadcast:42042)
> == bound to port 42042
> = 11 bytes received: Hello world
> 
> With a different setup, we could connect two evl-enabled systems, like:
> 
> /*
>   * From the first evl-enabled system, sending through eth1
>   * to 10.10.10.11:42042
>   */
> 
> ~# oob-net-udp -S -a 10.10.10.11
> == sender mode (=> 10.10.10.11:42042)
> 
> /*
>   * From the second evl-enabled system, receiving from eth0,
>   * bound to 10.10.10.11 on port #42042
>   */
> 
> ~# oob-net-udp -R -a 10.10.10.11
> == receiver mode (<= 10.10.10.11:42042)
> == bound to port 42042
> 
> This said, if you believe that a dual role setup like the one you
> suggested would be nice to have to users as well, we could add it to
> oob-net-udp alongside the existing half-duplex modes. For instance,
> omitting the -R and -S keys on the command line currently defaults to
> -R. Instead, we could select the new "dual role" mode.
> 
> PS: please send (diff context, -u or git-diff) formatted patches instead
> of entire modified files, so that we can immediately grasp the essence
> of the proposed changes. Also, please make sure to separate unrelated
> changes sets in distinct patches (e.g. those changing a particular
> aspect of the logic from others which may be coding style
> fixups). Generally speaking, we follow the linux kernel coding style and
> process when it comes to submitting patches [1].
> 
> [1] https://docs.kernel.org/process/submitting-patches.html
> 

Thanks for the detailed answer. I might have been not precise enough.

The -S and the -R mode work as designed. To show the issue with connect() in evl, I changed
the -S mode to:
connect()
while{
   oob_sendmsg()
   oob_recvmsg()
}

This is the classical UDP client pattern. It works with vanilla linux (net-udp.c)
but not with evl (oob-net-udp.c), I do not receive any data.

By just sending the modified code, it is easy to explain and hopefully for you to
reproduce. This is also why I attached the files instead of sending a patch.
Be aware that this is just to demonstrate what is not working, not intended as a patch.

I run Xenomai4 in a VM and communicate with the host for debugging
but I have also a real PC as the final target where I have the same issues.

First start on the host:
echo Hello | nc -u -l 5201

Then in the VM:
sudo evl net -ei enp7s0
sudo oob-net-udp -d -i enp7s0 -a 192.168.122.1 -p 5201 -S

On the host:
Mellow sword!

In the VM:
== bound to enp7s0
== sender mode (=> 192.168.122.1:5201)
--------tx--------
IP-Adresse: 192.168.122.1
Port:       5201
Family:     512
--------rx--------
IP-Adresse: 192.168.122.155
Port:       58422
Family:     512

The package is visible in wireshark but oob_recvmsg does not return:
No "= 6 bytes received: Hello" and no second transmit.

It looks like the auto assigned and bound port from connect() is not forwarded
to the oob stage, so no data is received in oob_recvmsg().

In wireshark in the VM, I see the outgoing package 41626->5201 and the
incoming 5201->41626 where 41626 is an auto assigned port by connect.

With the code ported to vanilla linux:
connect()
while{
   sendmsg()
   recvmsg()
}
it works as expected:

Host:
echo Hello | nc -u -l 5201

VM:
sudo evl net -di enp7s0
net-udp -d -i enp7s0 -a 192.168.122.1 -p 5201 -S

Host:
Mellow sword!
Mellow sword!

VM:
== bound to enp7s0
== client mode (=> 192.168.122.1:5201)
--------tx--------
IP-Adresse: 192.168.122.1
Port:       5201
Family:     512
--------rx--------
IP-Adresse: 192.168.122.155
Port:       43042
Family:     512
= 6 bytes received: Hello

But might be evl was never intended to work using connect() in classical UDP client style?

Meanwhile, I found a workaround. Instead of connect() I just use bind(). The only disadvantage
is, that I have to manually assign a port:

bind()
while{
   oob_sendmsg()
   oob_recvmsg()
}

Normally, bind() is only used for servers and point-to-point connections but you can (miss-) use it
also for clients. A server would be:
bind()
while{
   oob_recvmsg() -> Receives a message from any client
   oob_sendmsg() -> Sends the answer back to the ip/port from the address from recvmsg
}

If you think this this example is useful, I can finalize it (for now with the bind() workaround) and also add a server mode.
So there would be 4 modes in total. With a server mode, you can run the server on one host, the client on the other and continuously
send data forward / backward and measure delays. I would use:
-T send (previously it was -S but then I have nothing for server)
-R receive
-S server: Waits for data and sends a response for each received package.
-C client: Sends data and measures how long it takes for the server to response.

As an alternative, I could just create a second example oob-net-udp-server-client.c. This would result in a bit of duplicated code but not to much.

What do you prefer?

I also created oob-net-ping in the same style as oob-net-icmp but this sends out a ping, receives the response
and measures the delay, similar as the ping command:
./oob-net-ping -i enp7s0 -a 192.168.122.1
[0] count=98, proto=0x800, ifindex=3, type=0, halen=6, mac=52:54:00:6b:05:f1 rtt=317.1us
[1] count=98, proto=0x800, ifindex=3, type=0, halen=6, mac=52:54:00:6b:05:f1 rtt=218.5us
[2] count=98, proto=0x800, ifindex=3, type=0, halen=6, mac=52:54:00:6b:05:f1 rtt=252.5us
[3] count=98, proto=0x800, ifindex=3, type=0, halen=6, mac=52:54:00:6b:05:f1 rtt=320.1us
It has to be cleaned it up a bit and integrated it into the libevl repo but then I will also send a patch.

Regards
Hannes
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.