Skip to content

broadcast (dhcpv4) and multicast (dhcpv6) support + new Linux namespace based test lab - #54

Open
pallotron wants to merge 3 commits into
facebook:mainfrom
pallotron:full_integration_tests
Open

broadcast (dhcpv4) and multicast (dhcpv6) support + new Linux namespace based test lab#54
pallotron wants to merge 3 commits into
facebook:mainfrom
pallotron:full_integration_tests

Conversation

@pallotron

@pallotron pallotron commented Oct 16, 2025

Copy link
Copy Markdown
Contributor

This PR contains two commits:

feat(dhcp): Handle broadcast/multicast and refactor networking

This commit addresses a long-standing limitation (issue #1) where dhcplb could only handle unicast DHCP traffic from relay agents. It now correctly processes direct client communication on the same local L2 network for both DHCPv4 (broadcast) and DHCPv6 (multicast), adopting robust networking patterns inspired by servers like coredhcp and dnsmasq.

To achieve this, the networking layer was refactored from net.UDPConn to the more advanced ipv4.PacketConn and ipv6.PacketConn. This makes the server fully interface-aware, allowing it to determine which network interface received a request and to intelligently select the correct source IP for the reply.

Key Improvements:

  • DHCPv4: Correctly handles broadcast requests. Implements a Layer 2 raw socket mechanism on Linux—mirroring the behavior of dnsmasq and coredhcp—for unicast replies to clients without an IP, with a fallback to broadcast on other platforms.
  • DHCPv6: The server now correctly joins the ff02::1:2 multicast group on startup to handle direct SOLICIT messages from clients. This logic respects the listen_addr configuration: it joins on all interfaces for a wildcard address (::) or on a specific interface if a particular IP is configured.
  • Unified Networking: A new dhcplbConn struct provides a type-safe way to manage the distinct IPv4 and IPv6 connections.
  • Dynamic Replies: The static ReplyAddr configuration has been removed in favor of dynamically determining the reply address based on the ingress packet, making the server more robust and flexible.

New RangeHandler

To make sure that broadcat/multicat feature worked I had to implement a basic DHCPv[46] handler that implements a simple lease based dhcp server. Leases are stored on the file system as JSON files. This actually is a good example of how to extend dhcplb to act as server.

Testing

Testing was done on the subsequent commit where I killed Vagrant for a Linux namespace based test lab and CI. See the example test run this PR kicked.

refactor(tests): replace Vagrant with network namespace-based test lab

The Vagrant-based test setup was slow, resource-intensive, and had several external dependencies, including VirtualBox and Chef. This made it cumbersome for local development and CI.

I need something to test my recent multicast/broadcast changes and I don't have a lab in my current company. Hence this this diff.

This commit replaces the Vagrant environment with a new test lab built on top of Linux network namespaces. This new setup is:

  • Fast: It runs natively on a Linux host without the overhead of virtual machines.
  • Lightweight: It only requires bash and iproute2, which are available on most Linux distributions.
  • Portable: The entire setup is self-contained within the repository and can be easily executed in CI environments.

The new test lab is orchestrated by the tests/setup_lab.sh script, which can configure the environment in two modes:

  • relay: Simulates a network with a DHCP client, a DHCP relay (dnsmasq), dhcplb, and a DHCP server (dnsmasq), each in its own network namespace.
  • server: Simulates a simpler network with a DHCP client and dhcplb acting as a DHCP server.

This change simplifies the development and testing workflow, making it easier to validate dhcplb's functionality in a realistic network environment.

The new test scripts are not compatible with macOS out of the box.
They rely on Linux-specific networking features like network namespaces (ip netns), which are not available on macOS.

To run the test lab on a Mac, you will need to use a Linux virtual machine.
For your own convenience a tests/Makefile has been created to manage the vm using lima and it assumes you have it installed on your macOS.

❯ make help
Makefile for DHCPLB Test Lab

Usage: make [target]

  Primary Targets:
    test-all         - 🧪 Set up and run all test scenarios (relay and server).

  Relay Scenario:
    setup-relay      - 🛠 Set up the relay test lab.
    test-relay-v4    - ▶ Run a DHCPv4 client test in the relay lab.
    test-relay-v6    - ▶ Run a DHCPv6 client test in the relay lab.

  Server Scenario:
    setup-server     - 🛠 Set up the server/broadcast test lab.
    test-server-v4   - ▶ Run a DHCPv4 client test in the server lab.
    test-server-v6   - ▶ Run a DHCPv6 client test in the server lab.

  VM & Debugging:
    start            - 🚀 Start the Lima VM instance 'dhcplb-vm'.
    logs             - 📜 Tail the logs from all services.
    shell            - 💻 Open an interactive shell inside the Lima VM.
    stop             - 🛑 Stop the Lima VM instance.
    delete           - 🗑 Delete the Lima VM instance and all its data.
    delete-lease     - 📄 Force-deletes the client's DHCP lease file

See the example test run this PR kicked:

image

@meta-cla meta-cla Bot added the CLA Signed label Oct 16, 2025
Comment thread lib/config.go Outdated
@pallotron pallotron changed the title broadcast (dhcpv4) and multicast (dhcpv6) support + kill Vagrant setup, replace with Linux namespace "lab" and Github CI broadcast (dhcpv4) and multicast (dhcpv6) support + new Linux namespace based test lab Oct 16, 2025
@pallotron
pallotron force-pushed the full_integration_tests branch from 18183f0 to 085db05 Compare October 18, 2025 07:19
Comment thread lib/duid.go Outdated
Comment thread lib/server.go
return nil, fmt.Errorf("failed to set control message for IPv6: %w", err)
}

// Join DHCPv6 multicast group based on listening address.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the intention to make it work with both unicast and multicast(v6)/broadcast(v4) at the same time?

If dhcplb is running on a rack with many servers and the rack switch has a relay configured I think it might be good to let the relay do its job instead of dhcplb replying directly and the switch also forwarding the request.

Do you need both unicast and broadcast to work at the same time or just one of them at a time?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right now we are a V4 shop... I could split this PR into v4 and v6?
Or keep the PR and make this multicast/broadcast listening logic enabled by a flag?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or have this logic only work when -server is passeed?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also the logic only enables if you have "listen_addr": "::" in the JSON config... you could specify the address to listen taking from /etc/fbwhoami...

let me know which options you prefer :)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or keep the PR and make this multicast/broadcast listening logic enabled by a flag?

This one sounds good to me if current behaviour changes.

also the logic only enables if you have "listen_addr": "::"

Ok, then it should not modify its current behaviour. Thanks for the clarification. So we should be good.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, then it should not modify its current behaviour. Thanks for the clarification. So we should be good.

do you guys listen to specific /etc/fbwhoami address? if so we should be already good. but I would appreciate if you can do some local testing there :)

@meta-codesync

meta-codesync Bot commented Oct 20, 2025

Copy link
Copy Markdown
Contributor

@pmazzini has imported this pull request. If you are a Meta employee, you can view this in D85054422.

@facebook-github-bot

Copy link
Copy Markdown

@pallotron has updated the pull request. You must reimport the pull request before landing.

This commit addresses a long-standing limitation (issue #1) where `dhcplb` could
only handle unicast DHCP traffic from relay agents. It now correctly processes
direct client communication on the same local L2 network for both DHCPv4
(broadcast) and DHCPv6 (multicast), adopting robust networking patterns inspired
by servers like `coredhcp` and `dnsmasq`.

To achieve this, the networking layer was refactored from `net.UDPConn` to the
more advanced `ipv4.PacketConn` and `ipv6.PacketConn`. This makes the server
fully interface-aware, allowing it to determine which network interface received
a request and to intelligently select the correct source IP for the reply.

Key Improvements:
- **DHCPv4:** Correctly handles broadcast requests. Implements a Layer 2 raw
  socket mechanism on Linux—mirroring the behavior of `dnsmasq` and
  `coredhcp`—for unicast replies to clients without an IP, with a fallback to
  broadcast on other platforms.
- **DHCPv6:** The server now correctly joins the `ff02::1:2` multicast group on
  startup to handle direct `SOLICIT` messages from clients. This logic respects
  the `listen_addr` configuration: it joins on all interfaces for a wildcard
  address (`::`) or on a specific interface if a particular IP is configured.
- **Unified Networking:** A new `dhcplbConn` struct provides a type-safe way to
  manage the distinct IPv4 and IPv6 connections.
- **Dynamic Replies:** The static `ReplyAddr` configuration has been removed in
  favor of dynamically determining the reply address based on the ingress
  packet, making the server more robust and flexible.

To make sure that broadcat/multicat feature worked I had to implement a basic
DHCPv[46] handler that implements a simple lease based dhcp server. Leases are
stored on the file system as JSON files. This actually is a good example of how
to extend `dhcplb` to act as server.

Testing is done on the subsequent commits/PRs where I kill Vagrant for a Linux
namespace based test lab and CI.
The Vagrant-based test setup was slow, resource-intensive, and had
several external dependencies, including VirtualBox and Chef.
This made it cumbersome for local development and CI.

I need something to test my recent multicast/broadcast changes and I
don't have a lab in my current company. Hence this this diff.

This commit replaces the Vagrant environment with a new test lab built 
on top of Linux network namespaces. This new setup is:

- **Fast:** It runs natively on a Linux host without the overhead 
  of virtual machines.
- **Lightweight:** It only requires `bash` and `iproute2`, which are
  available on most Linux distributions.
- **Portable:** The entire setup is self-contained within the repository
  and can be easily executed in CI environments.

The new test lab is orchestrated by the `tests/setup_lab.sh` script, which
can configure the environment in two modes:

- **`relay`:** Simulates a network with a DHCP client, a DHCP relay
  (dnsmasq), `dhcplb`, and a DHCP server (dnsmasq), each in its own network 
  namespace. 
- **`server`:** Simulates a simpler network with a DHCP client
  and `dhcplb` acting as a DHCP server.

This change simplifies the development and testing workflow, making it
easier to validate `dhcplb`'s functionality in a realistic network environment.

The new test scripts are not compatible with macOS out of the box.
They rely on Linux-specific networking features like network namespaces (ip netns),
which are not available on macOS.

To run the test lab on a Mac, you will need to use a Linux virtual machine.
For your own convenience a `tests/Makefile` has been created to manage
the vm using [`lima`](https://lima-vm.io/) and it assumes you have it
installed on yoru maOS. 

```bash
❯ make help
Makefile for DHCPLB Test Lab

Usage: make [target]

  Primary Targets:
    test-all         - 🧪 Set up and run all test scenarios (relay and server).

  Relay Scenario:
    setup-relay      - 🛠 Set up the relay test lab.
    test-relay-v4    - ▶ Run a DHCPv4 client test in the relay lab.
    test-relay-v6    - ▶ Run a DHCPv6 client test in the relay lab.

  Server Scenario:
    setup-server     - 🛠 Set up the server/broadcast test lab.
    test-server-v4   - ▶ Run a DHCPv4 client test in the server lab.
    test-server-v6   - ▶ Run a DHCPv6 client test in the server lab.

  VM & Debugging:
    start            - 🚀 Start the Lima VM instance 'dhcplb-vm'.
    logs             - 📜 Tail the logs from all services.
    shell            - 💻 Open an interactive shell inside the Lima VM.
    stop             - 🛑 Stop the Lima VM instance.
    delete           - 🗑 Delete the Lima VM instance and all its data.
    delete-lease     - 📄 Force-deletes the client's DHCP lease file
```
@pallotron
pallotron force-pushed the full_integration_tests branch from d9536a0 to 1949747 Compare October 20, 2025 19:06
@facebook-github-bot

Copy link
Copy Markdown

@pallotron has updated the pull request. You must reimport the pull request before landing.

@pallotron
pallotron force-pushed the full_integration_tests branch from 1949747 to 348fde9 Compare October 20, 2025 19:08
@facebook-github-bot

Copy link
Copy Markdown

@pallotron has updated the pull request. You must reimport the pull request before landing.

@pallotron
pallotron force-pushed the full_integration_tests branch from 348fde9 to ed1ba50 Compare October 20, 2025 19:15
@facebook-github-bot

Copy link
Copy Markdown

@pallotron has updated the pull request. You must reimport the pull request before landing.

@pallotron
pallotron force-pushed the full_integration_tests branch from ed1ba50 to 2ba7b9d Compare October 20, 2025 19:19
@facebook-github-bot

Copy link
Copy Markdown

@pallotron has updated the pull request. You must reimport the pull request before landing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants