Skip to content

Hurd: implement selectable_fd.#1565

Open
jlledom wants to merge 2 commits into
the-tcpdump-group:masterfrom
jlledom:jlledom-hurd-selectable-fd
Open

Hurd: implement selectable_fd.#1565
jlledom wants to merge 2 commits into
the-tcpdump-group:masterfrom
jlledom:jlledom-hurd-selectable-fd

Conversation

@jlledom
Copy link
Copy Markdown

@jlledom jlledom commented Oct 16, 2025

This PR implements the selectable_fd feature for the Hurd. This is needed
by some clients like dhcpcd.

In this patch, the approach is to make the data pass through a pipe,
which read end is going to be the selectable_fd. When capture starts, a
new thread gets packets from gnumach BPF and pushes them to the pipe.

@guyharris
Copy link
Copy Markdown
Member

This adds an extra move of the packet data through a pipe, which seems... suboptimal.

Is there a way in Hurd to do a select(), or equivalent, that can wait on file descriptors and Mach ports? (macOS's kqueue implementation supports Mach ports as an item that generates kevents.)

Is there a way to have an "event" descriptor that can be selected on and that can be poked to trigger a select wakeup? (Linux and Windows have that, and they're used in libpcap.)

@jlledom
Copy link
Copy Markdown
Author

jlledom commented Oct 19, 2025

This adds an extra move of the packet data through a pipe, which seems... suboptimal.

Yes, I know, we already discused this in the hurd list: https://www.mail-archive.com/bug-hurd@gnu.org/msg37636.html

Is there a way in Hurd to do a select(), or equivalent, that can wait on file descriptors and Mach ports? (macOS's kqueue implementation supports Mach ports as an item that generates kevents.)

Is there a way to have an "event" descriptor that can be selected on and that can be poked to trigger a select wakeup? (Linux and Windows have that, and they're used in libpcap.)

None of those two, as far as I know. From my current knowledge, I can only think on two solutions:

  1. Actually write the /dev/bpf translator. That would take a lot of time probably. And, in that case, the Hurd module wouldn't be needed at all.
  2. In the hurd module, use the pipe only when a selectable_fd is requested. In that case, pcap_get_selectable_fd function should be modified to something like this:
int
pcap_get_selectable_fd(pcap_t *p)
{
  if (!p->selectable_fd) {
    pcap_init_selectable_fd();
  }
  return (p->selectable_fd);
}

and that pcap_init_selectable_fd would be implemented only on the hurd module and empty in all other platforms. The function would initialize the thread and the pipe. The read method for the hurd would read from the pipe only if the pipe is initialized, otherwise it would read from gnumach directly, as before.

Would you accept something like this?

@sthibaul
Copy link
Copy Markdown
Contributor

sthibaul commented Jan 11, 2026

Is there a way to have an "event" descriptor that can be selected on and that can be poked to trigger a select wakeup?

Not directly with a mach port, but instead of writing the whole packet to the pipe, we could put the packet in a queue and just write one dumb byte to the pipe, the read side would get the packet from the queue.

@guyharris
Copy link
Copy Markdown
Member

Is there a way to have an "event" descriptor that can be selected on and that can be poked to trigger a select wakeup?

Not directly with a mach port, but instead of writing the whole packet to the pipe, we could put the packet in a queue and just write one dumb byte to the pipe, the read side would get the packet from the queue.

I was thinking more of something like a Linux eventfd object, which doesn't have a buffer that can fill up (as pipes do). The limit on the number of events that can be posted on an eventfd object is the size of its counter, which is a 64-bit unsigned number.

A call that can block waiting on a descriptor or a Mach port would also work, such as kevent() in macOS's version of kqueue, which has the advantage of not requiring an extra FD and extra code to post notifications and the disadvantage of requiring a new Hurd-only libpcap API to return a Mach port and a change of event loop code in the Hurd version of a portable application to support either CDs or Mach ports.

@sthibaul
Copy link
Copy Markdown
Contributor

One can use a mach port set to be able to receive messages from either of several mach ports included in the set.

@guyharris
Copy link
Copy Markdown
Member

One can use a mach port set to be able to receive messages from either of several mach ports included in the set.

But what if you have an event loop that would have to wait for events both on descriptors (pipes, sockets, etc.) and on Mach parts? (That's why Apple added EVFILT_MACHPORT to their kqueue code.)

@sthibaul
Copy link
Copy Markdown
Contributor

what if you have an event loop that would have to wait for events both on descriptors (pipes, sockets, etc.) and on Mach parts

One can use _hurd_fd_get and _hurd_port_get to get a mach port from an fd.

@guyharris
Copy link
Copy Markdown
Member

One can use _hurd_fd_get and _hurd_port_get to get a mach port from an fd.

Then we should add a Hurd-specific pcap_get_mach_port() call, which either returns a Mach port or MACH_PORT_NULL; code for the Hurd would call pcap_get_mach_port() first and, if that fails with MACH_PORT_NULL, call pcap_get_selectable_fd() and, if that succeeds, use _hurd_fd_get() and _hurd_port_get() to get a Mach port on that, collect all relevant ports into a port set, and have their event loop do a mach_msg_receive() to wait for any of them to deliver a message.

@guyharris
Copy link
Copy Markdown
Member

Or allocate a Hurd fd for the Mach port with _hurd_alloc_fd(), using the Mach port, and use that for the selectable fd.

@sthibaul
Copy link
Copy Markdown
Contributor

It would need adding io_select RPC support to the network device port.

@guyharris
Copy link
Copy Markdown
Member

It would need adding io_select RPC support to the network device port.

Some *BSDs also have or had bugs in select() support for BPF device FDs (the device timeout wasn't taken into account, so the select would block until enough packets arrived to fill the buffer). Adding that to the network device might not be a bad idea.

Speaking of handling packet capture in event loops, the pcap_t should be in non-blocking mode if that's being done. Non-blocking mode on Hurd would involve doing a non-blocking message receive, in which case if there's a message waiting, it's returned, but if there isn't, the call returns an error indicating that there's no message currently available. Will a timeout of zero do that? (The GNU Mach documentation for the receive operation says that "A zero timeout is legitimate." and a quick look at the GNU Mach code indicates that a zero timeout might mean "if there's no message, fail immediately with MACH_RCV_TIMED_OUT.)

@sthibaul
Copy link
Copy Markdown
Contributor

Will a timeout of zero do that? (The GNU Mach documentation for the receive operation says that "A zero timeout is legitimate." and a quick look at the GNU Mach code indicates that a zero timeout might mean "if there's no message, fail immediately with MACH_RCV_TIMED_OUT.)

Yes, mach_msg with a zero timeout will do a single poll and not block.

* Implement a message queue using STAILQ to pass packets from the
  Mach receive thread to pcap_read_hurd().
* The queue and mutex are per-handle, initialized on activate and
  cleaned up on teardown.
* The pipe remains used only for signaling readiness between threads.
@jlledom
Copy link
Copy Markdown
Author

jlledom commented May 9, 2026

@guyharris @sthibaul I committed some changes to make the messages go through per-handle local queues instead of pipes. Pipes are still used but only for signalling readiness.

After this changes, the selectable_fd libpcap will return is not far from what eventfd would offer in Linux.

I think it's the best thing we can do right now. Alternatives are: either making changes in gnumach to make it notify readiness, or implement something similar to eventfd in the pflocal translator. Both would require such amount of work that I can't tell how long would it take for us to have a port for dhcpcd.

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

Labels

None yet

Development

Successfully merging this pull request may close these issues.

3 participants