FreeRTOS DNS issue (first request does not send)

Hi!
Every first DNS request after system start does not send . The situation is 100% repeated at the first request after launching the application
I attach log and screenshot from wireshark
This is part of the log of the first failed request:

 [12:51:41:077] > dnscheck google.com
 [12:51:41:083] < 
 [12:51:41:083] < FreeRTOS_FindEndPointOnNetMask[4]: No match for 5fae6002ip
 [12:51:41:083] < ARP 5fae6002ip miss using c0a85801ip
 [12:51:41:083] < FreeRTOS_FindEndPointOnNetMask[11]: No match for 5fae6002ip
 [12:51:46:094] < DNS_ReadReply returns -11
 [12:51:46:094] < prvIncreaseDNS4Index: from 0 to 1
 [12:51:46:094] < FreeRTOS_FindEndPointOnNetMask[4]: No match for 8080808ip
 [12:51:46:094] < ARP 8080808ip miss using c0a85801ip
 [12:51:50:877] < Network buffers: 56 lowest 54
 [12:51:50:877] < pxEasyFit: ARP c0a8586dip -> c0a85801ip
 [12:51:50:877] < ipARP_REPLY from c0a85801ip to c0a8586dip end-point c0a8586dip
 [12:51:51:093] < DNS_ReadReply returns -11
 [12:51:51:093] < prvIncreaseDNS4Index: from 1 to 0
 [12:51:51:093] < REsolved addr:0.0.0.0



log_dns.c (5.4 KB)

Hi, which version of FreeRTOS+TCP and which port are you using?

FreeRTOS TCP version 4.1.0 and custom port for Cortex M4 with zerocopy driver based on STM32F4 port. If you need more debug information (breakpoints, data etc…) dont hesitate to ask-)

It looks like it took some time for the ARP resolution for the default gateway 192.168.88.1? From the logs below, once the ARP resolution for default gateway succeeds, the DNS resolves, which is expected.

[12:51:41:083] < FreeRTOS_FindEndPointOnNetMask[4]: No match for 5fae6002ip
 [12:51:41:083] < ARP 5fae6002ip miss using c0a85801ip
 [12:51:41:083] < FreeRTOS_FindEndPointOnNetMask[11]: No match for 5fae6002ip
 [12:51:46:094] < DNS_ReadReply returns -11
 [12:51:46:094] < prvIncreaseDNS4Index: from 0 to 1
 [12:51:46:094] < FreeRTOS_FindEndPointOnNetMask[4]: No match for 8080808ip
 [12:51:46:094] < ARP 8080808ip miss using c0a85801ip
 [12:51:50:877] < Network buffers: 56 lowest 54
 [12:51:50:877] < pxEasyFit: ARP c0a8586dip -> c0a85801ip
 [12:51:50:877] < ipARP_REPLY from c0a85801ip to c0a8586dip end-point c0a8586dip
 [12:51:51:093] < DNS_ReadReply returns -11
 [12:51:51:093] < prvIncreaseDNS4Index: from 1 to 0
 [12:51:51:093] < REsolved addr:0.0.0.0
 [12:52:08:073] > dnscheck amazon.com
 [12:52:08:088] < 
 [12:52:08:088] < FreeRTOS_FindEndPointOnNetMask[4]: No match for 5fae6002ip
 [12:52:08:088] < ARP 5fae6002ip hit using c0a85801ip
 [12:52:08:104] < FreeRTOS_ProcessDNSCache: add: amazon.com @ 205.251.242.103 (TTL 723)
 [12:52:08:104] < DNS[0xEAE1]: The answer to amazon.com (205.251.242.103) will be stored
 [12:52:08:104] < REsolved addr:205.251.242.103

Can you share the wireshark capture for ARP as well along with DNS? Overall the behavior looks as expected, but might be interesting to see why it took so long for ARP to resolve.
@ActoryOu @moninom1

When FreeRTOS sends a packet to an unresolved IP-address, it will change the UDP packet into an ARP request. This was created in a time that RAM was very expensive :slight_smile:

The UDP packet will not be sent, that is why you must do it a second time.

You can force an ARP lookup of the gateway with this function:

    /* xARPWaitResolution checks if an IPv4 address is already known. If not
     * it may send an ARP request and wait for a reply.  This function will
     * only be called from an application. */
    BaseType_t xARPWaitResolution( uint32_t ulIPAddress,
                                   TickType_t uxTicksToWait );

You can call it like this, as soon as the network is up:

    BaseType_t doARPLookup = pdFALSE;

    void vApplicationIPNetworkEventHook_Multi( eIPCallbackEvent_t eNetworkEvent,
                                               NetworkEndPoint_t *pxEndPoint )
    {
        /* If the network has just come up...*/
        if( eNetworkEvent == eNetworkUp )
        {
            doARPLookup = pdTRUE;
        }
    }
    void main_loop()
    {
        if( doARPLookup == pdTRUE )
        {
            doARPLookup = pdFALSE;
            xARPWaitResolution( pxEndPoint->ipv4_settings.ulGatewayAddress,
                                pdMS_TO_TICKS( 500U ) );
        }

Note that vApplicationIPNetworkEventHook_Multi() is called by the IP-task, and therefore it is not allowed to call xARPWaitResolution() immediately.

Please report back how it goes.

3 Likes

hi! I attach the wireshark capture screen and log. As we can see ARP reply appeared only after 10sec,

dnc+arp.c (6.5 KB)

at first glance it works well
I add this code in the begining of sntp_task (which use dns requests)

            if( doARPLookup == pdTRUE )
            {
            doARPLookup = pdFALSE;
            LogDebug( ( "Waiting for arp gateway..." ) );    
            xARPWaitResolution( endpoint.ipv4_settings.ulGatewayAddress,
                                pdMS_TO_TICKS( 20000U ) );
            } 

and this code from you post in vApplicationIPNetworkEventHook_Multi:

I will add a similar code to the tasks who uses dns (mqtt agent) or can create a high-priority task that will be created in vApplicationIPNetworkEventHook_Multi and executed once and then deleted? What is your opinion?

You need to do gateway resolution once only, so the second option seems better. Have you also thought about adding retries in case of error? This way you won’t have to add extra code for triggering ARP resolution and the normal error handling code would take care of sending the DNS query. Adding retries would also have the benefit of making your application robust in case of unpredictable network errors.