NutUdpSendTo taking too long

View: New views
3 Messages — Rating Filter:   Alert me  

NutUdpSendTo taking too long

by jvallet :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hello all.

We have found one weird behaviour of NutUdpSendTo. Basically the problem
is the following.

If we put our Ethernut3 (with NutOS 4.6.4) to send UDP packets in a
network that does NOT have a computer with the IP that the UDP packets
are sent to, after some time (about 15 minutes) the Ethernut gets into a
state where every single execution of NutUdpSendTo takes about 500ms. We
can also see that in this state the microcontroller spends most of the
time idling, which suggests that there is a wait process somewhere. To
my poor understanding, sending a UDP packet is something like simply
dropping the packet into the network, not waiting for anything.

After this, if a computer with the target IP "appears" (in linux I
configure an ip alias), the situation comes back normal immediately,
where it takes usually in the order of milliseconds to execute NutUdpSendTo.

This situation seems to be reproducible. A simple while loop sending UPD
packets and a bit of patience makes the issue to show up. We measure
time by setting pins up and down and with an oscilloscope/logic
analyser. The basic code that we use is the following

-----------------------
#define MY_MAC  "\x00\x06\x98\x30\x00\x35"
#define MY_IPADDR "192.168.0.100"
#define MY_IPMASK "255.255.255.0"

int main(void)
{
   u_long ip_addr = inet_addr(MY_IPADDR);
   u_long ip_mask = inet_addr(MY_IPMASK);
   u_char mac[] = MY_MAC;
   UDPSOCKET *sock=NULL;
   char buf;

   DEBUGPINS_INIT;

   /* Initialize the serial port */
   NutRegisterDevice(&DEV_UART0, 0, 0);
   freopen("uart0", "r+", stdout);
   _ioctl(_fileno(stdout), UART_SETSPEED, &baud);
   printf("\n\nNut/OS %s\n", NutVersionString());

   /* Register the tracer and start the terminal */
   btn_terminal_init(stdout, "[udp]$");
   btn_terminal_register_cmd("trace",NutTraceTerminal);
   btn_terminal_run(BTN_TERMINAL_FORK, 0);

   /* Register Ethernet controller */
   NutRegisterDevice(&DEV_ETHER, 0, 0);
   NutNetIfConfig("eth0", mac, ip_addr, ip_mask);
   sock = NutUdpCreateSocket(LOCAL_PORT);
   if (sock==0)
   {
     DEBUGPINS_SETHIGH(2); //Set the debug pin 2 up
   }
   ip_addr=inet_addr(REMOTE_IP);
   while (1)
   {
     DEBUGPINS_SETHIGH(0); //Set the debug pin 0 up
     if (NutUdpSendTo(sock, ip_addr, REMOTE_PORT, &buf, 1) == -1)
     {
       DEBUGPINS_SETHIGH(3);
       NutSleep(200);
       DEBUGPINS_SETLOW(3);
     }
     DEBUGPINS_SETLOW(0); //Set the debug pin 0 low
     buf++;
   }
}
-----------------------

where the DEBUGPINS_SETHIGH(X) is a macro to put the Xth pin of our
debug connector to 1, and similar with the rest of macros. The pin 1 is
used to indicate when the micro is in the idle thread, and thus cannot
be seen in the code here, as it is in the NutOS sources. As you can see
we are able to use the tracer also in Ethernut3 (thanks to the
modifications of Ernst Stippl) through the btn-terminal for easily
getting the traces. If required we can provide sample traces and
pictures of the measurements with the scope. We can also provide all the
files required to run this code.

Regards
José
_______________________________________________
http://lists.egnite.de/mailman/listinfo/en-nut-discussion

Re: NutUdpSendTo taking too long

by Nathan Moore-5 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hey José,
When you send a IP packet over ethernet you have to know the MAC
address of the recipient.  To find this out the ARP (Address Resolution
Protocol) cache is examined.  If no entry for the destination IP address
is in the ARP cache then an ARP request must be sent over the
local ethernet and then you have to wait for an ARP reply.  If no one
is there with that IP address then you just wait until you finally give up.
In NutOS the sending thread is blocked until the IP packet is either sent
or something goes wrong (in this case no ARP reply).

Nathan
_______________________________________________
http://lists.egnite.de/mailman/listinfo/en-nut-discussion

Re: NutUdpSendTo taking too long

by jvallet :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hello Nathan, and thanks for the explanation. It was a shortcut to the
code that explains it. My friend was called "arpcache.c"

I have still some questions.

Nathan Moore escribió:
> Hey José,
> When you send a IP packet over ethernet you have to know the MAC
> address of the recipient.  To find this out the ARP (Address Resolution
> Protocol) cache is examined.  If no entry for the destination IP address
> is in the ARP cache then an ARP request must be sent over the
> local ethernet and then you have to wait for an ARP reply.  If no one
> is there with that IP address then you just wait until you finally give up.
> In NutOS the sending thread is blocked until the IP packet is either sent
> or something goes wrong (in this case no ARP reply).

And in that case the no ARP reply is not considered an error, so
NutUdpSenTo will peacefully return 0. So it seems to me that for an
application there is no straight way to detect when an ARP entry has
been deteled. Perhaps calling directly ArpCacheLookup, or even
NutArpCacheQuery? Anything against this that I should be aware of?

Another way to solve this issue, I guess, could be to mark the ARP entry
as permanent, so it will not be flushed. Is this correct? It seems that
it would require to manipulate the ARP entry manually, as I couldn't
find any function to add/manipulate entries. Anything against this that
I should be aware of?  In my case it is assumed that the IP of the
machine that the Ethernut sends the UDP packets to has always the same
private IP

Regards!
José


_______________________________________________
http://lists.egnite.de/mailman/listinfo/en-nut-discussion