Skip to content
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

Path MTU discovery for IPv6 #3141

Closed
wants to merge 2 commits into from
Closed

Conversation

vanrein
Copy link

@vanrein vanrein commented Jun 11, 2022

Pre-Submission Checklist

  • Commit message has the format required by CONTRIBUTING guide
  • Commits are split per component (core, individual modules, libs, utils, ...)
  • Each component has a single commit (if not, squash them into one commit)
  • No commits to README files for modules (changes must be done to docbook files
    in doc/ subfolder, the README file is autogenerated)

Type Of Change

  • Small bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds new functionality)
  • Breaking change (fix or feature that would change existing functionality)

Checklist:

Description

The IPv6 support for Path MTU discovery is absent, but IPv6 has no DF flag to allow downstream fragmentation. See Issue #3119 for my discovery / learning path. In short, unconnected UDP sockets do not learn Path MTU problems, so a message dropped once will be dropped again on resend. Using IPV6_PMTUDISC_WANT, any knowledge in the kernel can be used to fragment the message at sending time, as intended for IPv6.

These patches actually correct two IPv6-related things in the core/udp_server.c,

  1. Benefit from any kernel knowledge about Path MTU for IPv6
  2. The same option to learn from UDP_ERRORS is now available for IPv6

Do note that the last has not been implemented for IPv4 or IPv6. It is more useful for IPv6, allowing instant "tm" resends for Path MTU, but not "sl" I think. I cannot do that work, but this brings IPv6 to the same level as IPv4.

commit 0f90cff05c1a448eb2f85f83b4c087ab32ede11
Author: Rick van Rein <rick@openfortress.nl>
Date:   Sat Jun 11 10:57:32 2022 +0000

    core: Issue 3119.  Handling ICMPv6 Packet too Big
    
    - This was only defined for IPv4 under flag UDP_ERRORS
    - IPv6 has no toggle DF to clear for en-route fragmentation
    - Kamailio currently does not collect with recvmsg(...,MSG_ERRQUEUE)
    - The benefits of adding that can be instant resends for "tm" messages
    - Note that "sl" messages will have been forgotten at this point

commit 6b404b5f9807174177bee36eaf3543be0794f55e
Author: Rick van Rein <rick@openfortress.nl>
Date:   Sat Jun 11 10:44:27 2022 +0000

    core: Issue #3119.  Path MTU kernel info for IPv6
    
    - For IPv4, DF is an option; for IPv6 it is always active
    - This makes pmtu_discover an IPv4-only option
    - This means that we should set IPV6_MTU_DISCOVER to IPV6_PMTUDISC_WANT
    - Unconnected UDP sockets can now learn from ICMPv6 "Packet too Big"
    - As a result, hitting a Path MTU upper bound is a learning process
    - This should stop consistent SIP packet drops due to Path MTU

- For IPv4, DF is an option; for IPv6 it is always active
- This makes pmtu_discover an IPv4-only option
- This means that we should set IPV6_MTU_DISCOVER to IPV6_PMTUDISC_WANT
- Unconnected UDP sockets can now learn from ICMPv6 "Packet too Big"
- As a result, hitting a Path MTU upper bound is a learning process
- This should stop consistent SIP packet drops due to Path MTU
- This was only defined for IPv4 under flag UDP_ERRORS
- IPv6 has no toggle DF to clear for en-route fragmentation
- Kamailio currently does not collect with recvmsg(...,MSG_ERRQUEUE)
- The benefits of adding that can be instant resends for "tm" messages
- Note that "sl" messages will have been forgotten at this point
@vanrein
Copy link
Author

vanrein commented Jun 11, 2022

  1. Additionally tested on my own IPv6 PBX, no problems.
  2. A bit worried abou tthe long runtime of LGTM on C/C++ and if that is normal
  3. I don't think the open ticks above are a problem

Let me know if I have more work to do; as far as I know everything works fine.

@sergey-safarov
Copy link
Member

Hell @vanrein
I have tested PMTU via IPv4 and found it does not work as expected for me. Is PMTU via IPv4 works for you?

@vanrein
Copy link
Author

vanrein commented Jun 12, 2022 via email

@vanrein
Copy link
Author

vanrein commented Jun 12, 2022

@sergey-safarov You did not say how it "did not work as expected".

With what I've learnt, I was a bit surprised about the IPv4 original code, which says

optval= (pmtu_discovery) ? IP_PMTUDISC_DO : IP_PMTUDISC_DONT;

WIth ptmu_discover != 0 this code sets the DF flag on all IPv4 traffic, and makes it behave like in IPv6 where this is implied. But I am not so sure if it picks up any ICMP messages Fragmentation needed and DF set are processed. An unconnected socket has no way of using that.

Had it been IP_PMTUDISC_WANT, like I used for IPv6, then at least any such messages would have been learnt by the OS for the route and influence the resend.

I did not want to change the existing code, but given that you do not experience a benefit, this might make sense. It is much less clear than in the case for IPv6, though, so I am uncertain.

@vanrein
Copy link
Author

vanrein commented Aug 2, 2022

Please decide on this Pull Request. I did some serious research and removed buggy / overlooked cases for IPv6, while not altering the code for IPv4. Nobody seems to be questioning that, and yet it has stalled?

The original code that I changed was not very good to begin with, but nobody appears to be motivated to fix it for IPv4, which apparently is good enough. For IPv6 the current code is unacceptable and that is fixed by this Pull Request. So, please accept this as the best option available -- the alternative is worse, namely doing nothing and continue with broken support for SIP over IPv6.

Also, this is my first bugfix, I invested seriously by studying Kamailio and exploring the options. I also depend on SIP over IPv6, and generally believe it should be a serious option for all. I have other ideas to extend/improve Kamailio with a few neat modules, but this indecisive handling makes me too nervous to seriously undertake further effort.

@henningw
Copy link
Contributor

henningw commented Aug 3, 2022

@vanrein Thank you for the pull request. It is a bit more complicated one, and it was also not clear to me if the work from your side was already done, as there was an extensive discussion in #3119. Also summer time probably plays a role, with several developers out of the office for some time. I will review it this week and if there are not other comments or objections, probably merge it.

Its always good to send a quick ping if you do not get a reply to a PR for some reasons. Looking forward to other contributions from your side.

@vanrein
Copy link
Author

vanrein commented Aug 3, 2022 via email

henningw added a commit that referenced this pull request Aug 14, 2022
- also set pmtu_discovery core parameter for IPv6
- based on a patch from  Rick van Rein <rick@openfortress.nl>
- probably to be extended further
@henningw
Copy link
Contributor

henningw commented Aug 14, 2022

@vanrein I have pushed a commit based on your PR to the core. Now the core setting pmtu_discovery is also set for IPv6 sockets. I have kept default behaviour for now, so its disabled by default.

In the initial PR you used the option IPV6_PMTUDISC_WANT instead of IPV6_PMTUDISC_DO. Was there a specific reason for that?

@vanrein
Copy link
Author

vanrein commented Aug 18, 2022

Thanks Henning!

The IPV6_PMTUDISC_DO documentation says that it sets the Don't Fragment flag, which is absent in IPv6 because it always behaves that way. The kernel will then refuse larger-MTU frames with EMSGSIZE; using IPV6_PMTUDISC_WANT instead will fragment the frame at Path MTU boundaries. It is doubtful if the _DO setting works for IPv4, but it is not the intention of my PR to question code that has been around for very long.

See ip(7) which is referenced from ipv6(7).

@henningw
Copy link
Contributor

Thank you. I am trying to summarize it

  1. core option pmtu_discovery for IPv4
  • exists a long time
  • sets socket option IP_PMTUDISC_DO
  • sets do not fragment bit in outgoing packets
  • kernel will implement PMTU discovery, initial UDP packets might be dropped while the kernel tries to figure out the MTU
  • if MTU is found, UDP will be delivered and kernel will store the discovered MTU internally
  • further packets will use this value
  • this is probably not really efficient, but probably works
  1. core option pmtu_discovery for IPv6
  • new introduced in this PR
  • set socket option IP_PMTUDISC_DO
  • will not set do not fragment bit in outgoing packets
  • the kernel will refuse larger packets with EMSGSIZE
  • no discovery will take place, Kamailio will probably just stop sending the packet
  1. suggestion in this PR for IPv6
  • use IPV6_PMTUDISC_WANT as socket option
  • will fragment a datagram if needed according to the path MTU for IPv6
  • probably could be set by adding a new core option
  1. suggestion in this PR for IPv4
  • use IP_PMTUDISC_WANT as socket option
  • will fragment a datagram if needed according to the path MTU, or will set the don't-fragment flag otherwise
  • probably could be set by adding a new core option
  1. Additionally Kamailio provide options to manually manage the MTU with usual sockets
  • core setting udp_mtu and udp_mtu_try_proto
  • will try another protocol if MTU exceeded internally
  1. Additionally Kamailio provide options to manually manage the MTU with RAW sockets
  • core option udp4_raw_mtu
  • will fragment the packets internally

My suggestion would be add a new value 2 to the pmtu_discovery core parameter, which sets then the _WANT socket option for IPv4 and IPv6.

@vanrein
Copy link
Author

vanrein commented Aug 21, 2022 via email

henningw added a commit that referenced this pull request Aug 21, 2022
…PV6_PMTUDISC_WANT (GH #3141)

- add pmtu_discovery=2 for IPv4 and IPv6 - set IP_PMTUDISC_WANT/IPV6_PMTUDISC_WANT
- related to GH #3141
- for IPv4: will fragment a datagram if needed according to the path MTU,
  or will set the don't-fragment flag otherwise
- for IPv6: will fragment a datagram if needed according to the path MTU for IPv6
@henningw
Copy link
Contributor

@vanrein Thanks for the correction. New option has been added and documented in devel cookbook. Close PR.

@henningw henningw closed this Aug 21, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants