dhcpcd icon indicating copy to clipboard operation
dhcpcd copied to clipboard

manager: Fix loosing iface options on CARRIER

Open DanielG opened this issue 1 month ago • 4 comments

When an interface (re-)gains carrier dhcpcd_handlecarrier() runs dhcpcd_initstate() to kick off profile re-selection. Previously this used args originally passed when starting the manager (ctx->argv).

However interfaces started via the manager control interface (dhcpcd_initstate1() in dhcpcd_handleargs()) may be started with different args.

For example if we start a manager with

dhcpcd -M --inactive

and then start only IPv4 on an interface with

dhcpcd -4 iface0

a subsequent CARRIER event will reset the interface to what amounts to "default config + -M --inactive" which in this case will enable ipv6 also!

To fix this we keep a copy of the arguments used to start an interface in the manager (dhcpcd_handleargs()) code path around around (ifp->argv).

In the current implementation args passed during for renew following the initial interface start will not be persisted. This causes the interface to reset to a state of "defaults + config + profile + start-cmdline".

For example (continuing the scenario above) after enabling ipv6 with -n:

$ dhcpcd -6 -n iface0

A subsequent CARRIER event will disable ipv6 again as the effective arguments remain -4 iface0 as passed during interface start.

Note the per-interface daemon code path wasn't affected as ctx->args already contains the interface start args.

DanielG avatar Nov 06 '25 14:11 DanielG

Walkthrough

Adds per-interface argc/argv to struct interface, implements copy_argv()/free_argv_copy(), propagates control-command argv into discovered/activated interfaces during reconf, prefers per-interface argv during init, and frees copied argv on interface teardown. reconf_reboot signature changed.

Changes

Cohort / File(s) Summary
Interface struct & API
src/dhcpcd.h, src/if-options.h
Added int argc; and char **argv; to struct interface. Declared char **copy_argv(int argc, char **argv) and void free_argv_copy(char **argv).
Argv copy/free utilities
src/if-options.c
Added copy_argv() to allocate a contiguous argv copy with a magic sentinel and free_argv_copy() to validate and free it; added assert.h and ARGV_COPY_MAGIC. Note: the ARGV_COPY_MAGIC/copy/free logic appears duplicated within the file.
Init / reconf behavior
src/dhcpcd.c
dhcpcd_initstate now prefers per-interface argv when present. reconf_reboot signature changed to reconf_reboot(struct dhcpcd_ctx *ctx, const int reboot_else_applyaddr, const int argc, char **argv, const int first_iface_arg). New logic detects per-interface argv, checks whether argv references specific interfaces or all, copies control-command argv into newly discovered ifp->argv/ifp->argc when activating interfaces, and either reboots, applies IPv4 addresses, or runs preinit/start using the appropriate argv based on flags and interface state. Calls and comments updated accordingly.
Interface teardown
src/if.c
if_free() now calls free_argv_copy(ifp->argv) when ifp->argv is non-NULL to release copied per-interface argv before freeing the interface.

Sequence Diagram(s)

sequenceDiagram
    participant Control as Control process
    participant Reconf as reconf_reboot
    participant Iface as Interface (ifp)
    participant Init as preinit/start

    Note over Control,Reconf: Control command invokes reconf with argc/argv
    Control->>Reconf: reconf_reboot(reboot_else_applyaddr, argc, argv, first_iface_arg)
    alt ifp already has per-interface argv
        Reconf->>Iface: use existing ifp->argc/ifp->argv
        Reconf->>Init: call preinit/start using ifp->argv
    else interface referenced but not active
        Reconf->>Iface: copy_argv(argc, argv)
        Iface-->>Reconf: store copied argv in ifp->argv/ifp->argc
        Reconf->>Init: activate interface -> preinit/start using ifp->argv
    else interface active but action is apply-address
        Reconf->>Init: apply IPv4 address (no reboot) using context/main argv as appropriate
    end
    Init->>Iface: bring up/apply addresses
    Note right of Iface: on teardown -> free_argv_copy(ifp->argv)

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Review focus:
    • Consolidate duplicate ARGV_COPY_MAGIC / copy_argv / free_argv_copy implementations in src/if-options.c.
    • Verify all init/reconf call paths consistently prefer per-interface argv where intended.
    • Confirm memory management for copied argv across error paths and during teardown (if_free() and reconf error paths).
    • Validate copy_argv() for allocation size, truncation handling, null-termination, alignment, and portability.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 7.69% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: fixing the loss of interface options when a CARRIER event occurs, which is the core issue addressed throughout the changeset.
Description check ✅ Passed The description is comprehensive and directly related to the changeset, explaining the problem scenario, the root cause, and how the solution (per-interface argv copying) addresses it.
✨ Finishing touches
  • [ ] 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • [ ] Create PR with unit tests
  • [ ] Post copyable unit tests in a comment

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

coderabbitai[bot] avatar Nov 06 '25 14:11 coderabbitai[bot]

@DanielG Just to double-check, is this what you attached to this Debian bug?

perkelix avatar Nov 20 '25 18:11 perkelix

@DanielG Just to double-check, is this what you attached to this Debian bug?

Yup.

DanielG avatar Nov 20 '25 20:11 DanielG

@rsmarples, is @DanielG 's response to your change requests adequate?

perkelix avatar Dec 11 '25 10:12 perkelix