Add support for multi pref64 in rtadvd and rtadvctl
Details
To test, you need to configure
your rtadvd.conf with a pref64 prefix:
bridge0:\
:raflags="oal":rltime#600:\
:addr="2a01:e140:cafe::":prefixlen#64:\
:pref640="2a01:e140:dead:ff::":\
:pref641="3fff::":pref64len1#64:then simply check the rtadvctl show output.
Also verified with tcpdump.
Diff Detail
- Repository
- rG FreeBSD src repository
- Lint
Lint Passed - Unit
No Test Coverage - Build Status
Buildable 69904 Build 66787: arc lint + arc unit
Event Timeline
Convert action_show_pref64 from int to void and use assertion to address @zlei comment.
| usr.sbin/rtadvctl/rtadvctl.c | ||
|---|---|---|
| 630 | RFC 8781 states in section 5: "This option may appear more than once in an RA" Looking at rtadvd.h it is a list but as I much as I understand here, we would always only print a single prefix? | |
| 631 | What's the point of a separate printf here compared to doing that in action_show_pref64()? File style? | |
| usr.sbin/rtadvctl/rtadvctl.c | ||
|---|---|---|
| 630 | Unfortunately, the current implementation does not work that way. | |
| 925 | The thing that comes to my mind is: /* RFC 8781 Section 4: Map PLC values to prefix lengths */ The RFC 6052 uses a table to describe the values, as there isn't a straightforward algorithm to implement the mapping. | |
| usr.sbin/rtadvctl/rtadvctl.c | ||
|---|---|---|
| 925 | Yes, referencing the RFC that would explain where the values come from should be good enough. | |
Here is the output sample of rtadvctl:
% mdo rtadvctl -v show bridge0: flags=<UP,TRANSITIVE,PERSIST> status=<RA_SEND> mtu 1500 DefaultLifetime: 10m MinAdvInterval/MaxAdvInterval: 3m20s/10m AdvLinkMTU: <none>, Flags: MO, Preference: low ReachableTime: 0s, RetransTimer: 0s, CurHopLimit: 64 AdvIfPrefixes: yes Next RA send: Thu Jan 15 00:58:25 2026 Last RA send: Thu Jan 15 00:58:06 2026 Prefixes (1): 2a01:e140:1234:5678::/64 (CONFIG, vltime=30d, pltime=7d, flags=LA) DNSSL entries: spmzt.net (ltime=15m) PREF64: 2a01:e140:cafe:ff::/96 (ltime: 3m45s) 2a01:e140:dead:ff::/64 (ltime: 3m45s)
@bz: I also tested it and I can confirm that it works using wireshark.
@zlei: I had to rollback the assert part, as there's no need for p64_enabled anymore. so I removed it.
@glebius should these minor changes to the manual be approved by the manpages group?
I also found a bug related to flag inconsistency. However, I will fix it in another revision.
They should automatically receive a notification of a review that touches a manual page. If somebody from the group submits corrections, please follow them. If the manpages is silent in the next couple days while we are reviewing the code, it should be fine to proceed with push without their review.
Thanks a lot for going the extra mile and changing the entire code!
| usr.sbin/rtadvctl/rtadvctl.c | ||
|---|---|---|
| 921 | Just style but usually I/we'd sort; not sure what style.9 thinks about this these days. struct pref64 *prf64; uint16_t *prf64_cnt; char ntopbuf[INET6_ADDRSTRLEN]; char ssbuf[SSBUFLEN]; char *p; int i; uint16_t prf64len; | |
| 931 | That if seems unnecessary given the for loop will otherwise just never be executed? | |
| usr.sbin/rtadvd/config.c | ||
| 962 | Not entirely true anymore as you may already have added a pref64 to the tailq and may add more but I think it's fine. | |
| 974 | No spaces between casts: prf64->p64_sl = (uint16_t)(uint64_t)val64; I am also not sure if you need the (uint64_t) in between? | |
| usr.sbin/rtadvd/control_server.c | ||
| 553 | This seems wrong. If I am correct you only have one prf64_cnt at the beginning of the buffer and nothing further inter-spaced before/after each record? | |
| 571 | In theory that should be "len" as well but there seems to be a possibility in the code that if the count of entries changes between the loops all other kinds of things go wrong as well; seems to not be a concern in this code anywhere (just looked up backwards at dns as well). | |
| usr.sbin/rtadvd/rtadvd.conf.5 | ||
| 452 | This last line is probably a copy&paste error. | |
| 509 | Why not use the well known NAT64 prefix here in the example? 64:ff9b::/96 Maybe put the pref63 on its own line as well to make it more clear? | |
the only purpose that RFC8781 mentions for having multiple PREF64s advertised is renumbering, in which case the lifetime of the deprecated prefixes should be set to zero. iiuc, this diff allows that by setting pref64lifetime0, pref64lifetime1, etc. - can i check i have that right?
P.S. Love the KAME project, but honestly, most of their userland code is weird.
For instance, I also have a branch for mobile ipv6 implementation, where I made a fair amount of changes to rtadvd, rtsold, rtadvctl, and others.
I have to say the layer of indirection in KAME code makes adding a single floating point number almost impossible without refactor.
I don't like their style of coding in userland either. However, To see if I should use our own style or simply follow existing, I checked the other revisions for these toolset found other developers simply didn't touch KAME style.
| usr.sbin/rtadvctl/rtadvctl.c | ||
|---|---|---|
| 921 | You're right, unfortunately none of the KAME code follows our style. | |
| 931 | I thought the same myself. It feels unnecessary. I removed this line before and then rollback it as I didn't want to touch their style. | |
| usr.sbin/rtadvd/config.c | ||
| 962 | Nice catch. I'll see what can I do for it. | |
| 974 | Again it's clearly style violation and the second cast is not required at all. But they've used the exact double casting over and over in the code. | |
| usr.sbin/rtadvd/control_server.c | ||
| 553 | You're right. I'll fix that. | |
No, not really. That is only the example there. Read on further in 5.1. Handling Multiple NAT64 Prefixes.
in which case the lifetime of the deprecated prefixes should be set to zero. iiuc, this diff allows that by setting pref64lifetime0, pref64lifetime1, etc. - can i check i have that right?
You see, my second diff had an unused pref64 declaration that I removed in last change.
That's because I implement your deprecation concern in ra_shutdown first.
But later I found this line:
rfc7050#section-3
A node requiring information about the presence (or absence) of
NAT64, and one or more Pref64::/n used for protocol translation...
And it make sense to me.
We use multiple PREF64 prefixes in our infrastructure as it allows to decide which IPv4 and in which location to use.
I like the idea of having multiple PREF64 option and the RFC allows it too.
| usr.sbin/rtadvd/config.c | ||
|---|---|---|
| 962 | I don't think I can do it cleanly. pref64 and pref640 are separate entries, and if I use i to log with its options number, like this: syslog(LOG_ERR, "prefix (%d) length %" PRIi64 For users who use pref64 instead of pref640, it would report prefix (-1) in the syslog. | |
| usr.sbin/rtadvd/rtadvd.conf.5 | ||
|---|---|---|
| 509 | I can use WKP, but this version was shorter and as you know it's not necessary to use WKP in NAT64. I will update the example prefix to WKP. But I will not include pref64len as IMHO may suggest people to use pref64len option even for 96 prefix length which is the default value. | |
| usr.sbin/rtadvd/rtadvd.conf.5 | ||
|---|---|---|
| 509 | I am just thinking that a more detailed example will let the not too IPv6-firm user less puzzled. Alternatively can you expand the doc prefix to something which resembles a mask /96 and isn't all-zero, like was done for the addr= line above? | |
| usr.sbin/rtadvd/rtadvd.conf.5 | ||
|---|---|---|
| 509 | IMHO, this version is good for a basic example. But I think you're right. re0:\ :raflags="al":rltime#600:\ :addr="3fff:cafe::":prefixlen#64:\ :rdnss0="2620:fe::9":rdnss1="2620:fe::fe":\ :dnssl="freebsd.org": What do you think? | |
| usr.sbin/rtadvd/rtadvd.conf.5 | ||
|---|---|---|
| 509 | I mean: re0:\ :raflags="al":rltime#600:\ :addr="3fff:cafe::":prefixlen#64:\ :rdnss0="2620:fe::9":rdnss1="2620:fe::fe":\ :dnssl="freebsd.org":\ :pref640="64:ff9b::":pref641="3fff:64::":pref64len1#32: ` | |