Skip to content

ports/*: increase LWIP timers for ports with mDNS support #16623

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 14, 2025

Conversation

tpwrules
Copy link
Contributor

@tpwrules tpwrules commented Jan 22, 2025

Summary

Despite the code comments claiming one is sufficient, the mDNS application is capable of using up to twelve timers. Three per IP protocol are started at once in mdns_start_multicast_timeouts_ipvX, then another two per protocol can be started in mdns_handle_question. Further timers can be started for two additional callbacks.

Having certain timers, such as MDNS_MULTICAST_TIMEOUT, fail to start due to none being free will break mDNS forever as the app will never realize it's safe to transmit a packet.

Testing

This fixes mDNS on W5500_EVB_PICO. Before, mDNS would work for a bit after connection until the host's cache expired a minute or two later. Then the board would never respond to further queries. With this patch, all works well.

Trade-offs and Alternatives

This PR goes somewhat overkill and allocates the maximal amount of timers; it's uncertain if all can run simultaneously, or how many callback timers are needed.

Each timer struct is 16 bytes on standard 32 bit builds. Plus 8 bytes of allocater overhead, that's 288 more bytes of RAM used which shouldn't be too horrible. Users who don't need mDNS can manually disable it to recover the RAM if necessary.

@tpwrules tpwrules force-pushed the pr/lwip-mdns-timers branch from a440899 to 6a8367e Compare January 22, 2025 23:31
@tpwrules tpwrules changed the title ports/*: increase LWIP timeouts for ports with mDNS support ports/*: increase LWIP timers for ports with mDNS support Jan 22, 2025
Copy link

github-actions bot commented Jan 22, 2025

Code size report:

   bare-arm:    +0 +0.000% 
minimal x86:    +0 +0.000% 
   unix x64:    +0 +0.000% standard
      stm32:    +0 +0.000% PYBV10
     mimxrt:    +0 +0.000% TEENSY40
        rp2:  +176 +0.019% RPI_PICO_W[incl +176(bss)]
       samd:    +0 +0.000% ADAFRUIT_ITSYBITSY_M4_EXPRESS
  qemu rv32:    +0 +0.000% VIRT_RV32

@dpgeorge dpgeorge added the ports Relates to multiple ports, or a new/proposed port label Jan 23, 2025
@dpgeorge
Copy link
Member

Thanks for the contribution.

Despite the code comments claiming one is sufficient

Can you point to where the comment says one is sufficient? I could not find it.

Three per IP protocol are started at once per IP protocol in mdns_start_multicast_timeouts_ipvX,

Yes, that looks correct, I can see 3 independent timers in those functions.

then another two per protocol can be started in mdns_set_timeout.

I don't follow this bit, because mdns_set_timeout is a helper function. I think you meant to say this is called from mdns_handle_question()? Then the 5 timers per protocol are:

  • multicast_timeout
  • multicast_probe_timeout
  • multicast_timeout_25TTL
  • unicast_msg_in_use
  • multicast_msg_waiting

And it definitely looks possible to have all 5 of those running at once.

But then there are also additional calls to sys_timeout() in src/apps/mdns/mdns.c:

2164:      sys_timeout(MDNS_RESPONSE_TC_DELAY_MS, mdns_handle_tc_question, pkt);
2319:        sys_timeout(MDNS_PROBE_MAX_CONFLICTS_TIMEOUT, mdns_probe_and_announce, netif);
2322:        sys_timeout(MDNS_PROBE_DELAY_MS, mdns_probe_and_announce, netif);
2348:        sys_timeout(announce_delay, mdns_probe_and_announce, netif);
2786:    sys_timeout(MDNS_PROBE_MAX_CONFLICTS_TIMEOUT, mdns_probe_and_announce, netif);
2790:    sys_timeout(delay, mdns_probe_and_announce, netif);

I'm not sure how to work out which of those can be running together... and in fact those calls could start an arbitrary number of timers if they are called over and over again. But, since there are only two independent callbacks (namely mdns_handle_tc_question and mdns_probe_and_announce) it seems sensible to allow just two timers for these calls. So maybe there needs to be 2 + 5 * (IP4+IP6) timers in total?

(Also, please check the CI code formatting failure.)

@tpwrules
Copy link
Contributor Author

Thanks for checking my work and the quick response.

Can you point to where the comment says one is sufficient? I could not find it.

Line 11 of src/apps/mdns/mdns.c says "You need to increase MEMP_NUM_SYS_TIMEOUT by one if you use MDNS!" I do not know why the number of timers has expanded so dramatically, it's not a super old comment.

I don't follow this bit, because mdns_set_timeout is a helper function. I think you meant to say this is called from mdns_handle_question()? Then the 5 timers per protocol are:
...

Sorry, yes I mis-pasted the function name when writing the message. Those are the same 5 timers I identified.

But then there are also additional calls to sys_timeout() in src/apps/mdns/mdns.c:

I missed these, thank you. It looks like these are used in rarer circumstances, but I agree with your assessment that these could take arbitrary numbers of timers. It is unfortunate that each callback could be queued several times and use up the timer slots for the other processes. I think upstream might need to put some attention here.

I could send an inquiry to their list but I don't think I have bandwidth to fix it up at this time.

(Also, please check the CI code formatting failure.)

I will increase the number of timers and address the failure and test again.

@tpwrules tpwrules force-pushed the pr/lwip-mdns-timers branch 2 times, most recently from 53dbc9a to c6cfe57 Compare January 24, 2025 03:49
@tpwrules
Copy link
Contributor Author

Okay, took a few tries but I think we are good now!

@dpgeorge
Copy link
Member

Thanks for updating.

In order to eliminate code duplication, I made PR #16647 which factors out the common lwIP configuration for these four ports. I think we should merge that first, then this PR becomes simpler, it's just changing one location.

@dpgeorge
Copy link
Member

dpgeorge commented Feb 7, 2025

@tpwrules are you able to update this PR and just make a single change in the consolidated file at extmod/lwip-include/lwipopts_common.h?

@tpwrules tpwrules force-pushed the pr/lwip-mdns-timers branch from c6cfe57 to 75ca40c Compare February 7, 2025 18:38
Copy link

codecov bot commented Feb 7, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 98.53%. Comparing base (842e361) to head (aef6705).
Report is 1 commits behind head on master.

Additional details and impacted files
@@           Coverage Diff           @@
##           master   #16623   +/-   ##
=======================================
  Coverage   98.53%   98.53%           
=======================================
  Files         169      169           
  Lines       21806    21806           
=======================================
  Hits        21487    21487           
  Misses        319      319           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@tpwrules
Copy link
Contributor Author

tpwrules commented Feb 7, 2025

Not sure what to do about the CI failure?

@dpgeorge
Copy link
Member

dpgeorge commented Feb 7, 2025

Not sure what to do about the CI failure?

I reran it, it now passes.

@eightycc
Copy link

eightycc commented Feb 8, 2025

CircuitPython has had similar problems with static memory pool allocations in lwIP. Our solution was to configure lwIP to allocate all of its memory dynamically from our top-level tlsf heap. See adafruit#9837.

@tpwrules tpwrules force-pushed the pr/lwip-mdns-timers branch 2 times, most recently from ef5f1fb to 015d927 Compare February 13, 2025 04:17
Despite the code comments claiming one is sufficient, the mDNS application
is capable of using up to twelve timers.  Three per IP protocol are started
at once in `mdns_start_multicast_timeouts_ipvX`, then another two per
protocol can be started in `mdns_handle_question`.  Further timers can be
started for two additional callbacks.

Having certain timers, such as `MDNS_MULTICAST_TIMEOUT`, fail to start due
to none being free will break mDNS forever as the app will never realize
it's safe to transmit a packet.  Therefore, this commit goes somewhat
overkill and allocates the maximal amount of timers; it's uncertain if all
can run simultaneously, or how many callback timers are needed.

Each timer struct is 16 bytes on standard 32 bit builds.  Plus, say, 8
bytes of allocater overhead, that's 288 more bytes of RAM used which
shouldn't be too horrible.  Users who don't need mDNS can manually disable
it to recover the RAM if necessary.

This fixes mDNS on W5500_EVB_PICO (among other boards).  Before, mDNS would
work for a bit after connection until the host's cache expired a minute or
two later.  Then the board would never respond to further queries.  With
this patch, all works well.

Signed-off-by: Thomas Watson <twatson52@icloud.com>
@dpgeorge dpgeorge force-pushed the pr/lwip-mdns-timers branch from 015d927 to aef6705 Compare February 14, 2025 01:34
@dpgeorge dpgeorge merged commit aef6705 into micropython:master Feb 14, 2025
62 checks passed
@dpgeorge
Copy link
Member

Thanks for updating, now merged.

@tpwrules tpwrules deleted the pr/lwip-mdns-timers branch February 14, 2025 01:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
ports Relates to multiple ports, or a new/proposed port
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants