keep acquisition timestamp when route isn't updated - #686
Conversation
RFC 4861 specifies that router advertisements should be sent no more than once every MIN_DELAY_BETWEEN_RAS (3 seconds). In practice though, there are several ISPs (Comcast, Spectrum, Vodafone) that send out router advertisements at higher rates. Previously this caused dhcpcd to never update the route until it eventually expired and was removed by the kernel. This happened because the rt_acquired timestamp was out of sync with the kernel expiry tracking. rt_acquired was updated every time a router advertisement was processed **even when the route wasn't updated in the kernel**. When router advertisements were sent out frequently, rt_acquired was updated frequently, the difference between the old and new rt_acquired values never became great enough for rt_cmp_lifetime to return 1 and the kernel's routing table was never updated. To fix this, keep the old rt_acquired value iff the kernel's routing table wasn't updated. This ensures that rt_acquired stays in sync with the expiry value in the kernel's routing table.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
💤 Files with no reviewable changes (1)
WalkthroughThe route acquisition timestamp field is renamed from ChangesRoute lifetime handling
CI package setup
Estimated code review effort: 2 (Simple) | ~10 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
It's very hard to follow the logic of how this code is supposed to work. It looks like:
I'm struggling to figure out why (b). The reason I'm trying to puzzle this out is that I'm not sure that modifying the newly-acquired route to match the original one is the right solution. I think it'll work, but AFAICT it's the only place where the newly-acquired route is synthetically modified, which feels like the wrong solution here. It seems like the right class of solution here is to leave the original route in place when doroute thinks nothing has changed, whereupon eventually the acquisition time difference will exceed DEV_MAX, and the route will be replaced, both in the internal tables and the kernel. But to be confident about this, I first need to understand why (b) above. Can any of the core devs for dhcpcd explain that logic? |
We return true on no change so we can update our internal tables.
I think the change makes sense and I've added a supporting comment for it. |
|
It's your code. 🤷♂️ I'm mainly worried about adding another layer of complexity to the onion, in a place where there have been subtle logic problems in the past. But I do agree that this PR will likely fix the immediate issue. |
|
I guess I can outline how I would manage routes if I were writing this from scratch. This is just me opining. Feel free to ignore. ;-) Essentially, whenever receiving an RA, for the default route:
You can do the same basic thing for RIOs. PIOs for SLAAC networks are a little more complicated, but the same general idea applies (don't replace too often on networks that flood RAs). |
This is essentially what we do now.
We actively want to avoid this on BSD as any route change will flush the internal ARP tables.
Yes a metric change is complicated and is somewhat supported in dhcpcd.
For dhcpcd it's just a route. The route code is agnostic to its source and works for IPv4 and IPv6. Thanks for your comments :) |
It flushes the entire ARP table/ND table for all interfaces whenever any route changes? Wow.
dhcpcd does set Anyway, thanks for the quick reply. |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
.github/workflows/build.yml (1)
54-55: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick winAvoid upgrading the entire CI runner.
apt upgrade -ychanges every preinstalled package on both matrix jobs. This increases build time and reduces reproducibility. Refreshing the indexes before installinglibudev-devis sufficient.Proposed fix
- - name: Upgrade packages - run: sudo apt upgrade -y🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.github/workflows/build.yml around lines 54 - 55, Remove the broad package upgrade step from the workflow and update the dependency-installation flow to refresh apt indexes before installing libudev-dev. Keep the existing matrix jobs and install only the required package to preserve CI reproducibility.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In @.github/workflows/build.yml:
- Around line 54-55: Remove the broad package upgrade step from the workflow and
update the dependency-installation flow to refresh apt indexes before installing
libudev-dev. Keep the existing matrix jobs and install only the required package
to preserve CI reproducibility.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 695133c7-44e9-4dd4-9799-91373532fba7
📒 Files selected for processing (1)
.github/workflows/build.yml
Only for entries attached to the route. To get the same behaviour (which is important for multi-homed hosts) I need to delete and re-add the route.
Ah let me rephrase. dhcpcd routing takes routes from many sources - RA PIO is just one, it could also be RA Route Information Option (RIO), or any number of DHCP options such as Classless Static Routing. The routing logic is agnostic to all of this. |
RFC 4861 specifies that router advertisements should be sent no more than once every MIN_DELAY_BETWEEN_RAS (3 seconds). In practice though, there are several ISPs (Comcast, Spectrum, Vodafone) that send out router advertisements at higher rates.
Previously this caused dhcpcd to never update the route until it eventually expired and was removed by the kernel.
This happened because the rt_acquired timestamp was out of sync with the kernel expiry tracking. rt_acquired was updated every time a router advertisement was processed even when the route wasn't updated in the kernel. When router advertisements were sent out frequently, rt_acquired was updated frequently, the difference between the old and new rt_acquired values never became great enough for rt_cmp_lifetime to return 1 and the kernel's routing table was never updated.
To fix this, keep the old rt_acquired value iff the kernel's routing table wasn't updated. This ensures that rt_acquired stays in sync with the expiry value in the kernel's routing table.
Closes #681
Cc @squarooticus