DOMAIN(9)
π DOMAIN(9) β kernel socket vibes, explained
okay so this is the domain / protosw page from the Kernel Developer's Manual, and bestie, if you've ever wondered how the kernel actually makes socket(2) happen, this is the whole tea. grab a boba, we're going in π§β¨
β¨ SYNOPSIS β¨
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/protosw.h>
#include <sys/domain.h>
void
domain_add(struct domain *dom);
void
domain_remove(struct domain *dom);
void
DOMAIN_SET(domain);
int
protosw_register(struct domain *dom, struct protosw *pr);
int
protosw_unregister(struct protosw *pr);
π¦ DESCRIPTION π¦
so the domain subsystem is literally the whole reason you can implement communication protocols that userland gets to touch via the socket(2) API. iconic behavior honestly.
when an app does a socket(domain, type, protocol) syscall, the kernel goes on a little scavenger hunt π β first it looks for a domain matching the domain argument, then within that domain it looks for a protocol matching type. and if the third argument, protocol, isn't 0, then that value has to match too, no exceptions. the structure it finds has to implement certain methods, so that the socket(2) API actually works for this particular kind of socket. slay.
a minimal domain structure implementing a domain shall be initialized with a sparse C99 initializer (yes, that's mandatory, not a suggestion π ) and has these public fields:
struct domain {
/*
* Mandatory fields.
*/
int dom_family; /* PF_xxx, first argument of socket(2) */
char *dom_name; /* text name of the domain */
u_int dom_nprotosw; /* length of dom_protosw[] */
/*
* Following methods are optional.
*/
int (*dom_probe)(void); /* check for support */
struct rib_head *(*dom_rtattach)(uint32_t); /* init route table */
void (*dom_rtdetach)(struct rib_head *); /* clean up table */
void *(*dom_ifattach)(struct ifnet *); /* interface attach */
void (*dom_ifdetach)(struct ifnet *, void *);/* & detach callbacks */
int (*dom_ifmtu)(struct ifnet *); /* mtu change */
/*
* Mandatory variable size array of pointers to protosw structs.
*/
struct protosw *dom_protosw[];
};
every domain carries the dom_protosw array of protocol switch structures (struct protosw *) β one for each socket type it supports, bestie. the array may have NULL spacers for loadable protocols (iykyk π«Ά). and yes, sparse C99 initializers shall be used to initialize protosw structures, that's the rule.
the protosw structure has a mandatory field pr_type and a mandatory pr_attach method. the rest of the methods are optional β but like, a meaningful protocol should implement some. no pressure, but also... some pressure β¨
struct protosw {
short pr_type; /* second argument of socket(2) */
short pr_protocol; /* third argument of socket(2) or 0 */
short pr_flags; /* see protosw.h */
pr_soreceive_t *pr_soreceive; /* recv(2) */
pr_rcvd_t *pr_rcvd; /* soreceive_generic() if PR_WANTRCV */
pr_sosend_t *pr_sosend; /* send(2) */
pr_send_t *pr_send; /* send(2) via sosend_generic() */
pr_ready_t *pr_ready; /* sendfile/ktls readyness */
pr_sopoll_t *pr_sopoll; /* poll(2) */
pr_attach_t *pr_attach; /* creation: socreate(), sonewconn() */
pr_detach_t *pr_detach; /* destruction: sofree() */
pr_connect_t *pr_connect; /* connect(2) */
pr_disconnect_t *pr_disconnect; /* sodisconnect() */
pr_close_t *pr_close; /* close(2) */
pr_shutdown_t *pr_shutdown; /* shutdown(2) */
pr_abort_t *pr_abort; /* abrupt tear down: soabort() */
pr_aio_queue_t *pr_aio_queue; /* aio(9) */
pr_bind_t *pr_bind; /* bind(2) */
pr_bindat_t *pr_bindat; /* bindat(2) */
pr_listen_t *pr_listen; /* listen(2) */
pr_accept_t *pr_accept; /* accept(2) */
pr_connectat_t *pr_connectat; /* connectat(2) */
pr_connect2_t *pr_connect2; /* socketpair(2) */
pr_control_t *pr_control; /* ioctl(2) */
pr_rcvoob_t *pr_rcvoob; /* soreceive_rcvoob() */
pr_ctloutput_t *pr_ctloutput; /* control output (from above) */
pr_peeraddr_t *pr_peeraddr; /* getpeername(2) */
pr_sockaddr_t *pr_sockaddr; /* getsockname(2) */
pr_sense_t *pr_sense; /* stat(2) */
};
π the registration functions π
these are the functions that handle registering new domains and protocols:
domain_add()β adds a new protocol domain to the system. in most cases you don't calldomain_add()directly, bestie; instead you useDOMAIN_SET(), which is a wrapper around theSYSINIT()macro. if the new domain has defined adom_proberoutine, that gets called first insidedomain_add()to figure out if the domain should even be supported on the current system. if the probe routine returns a non-0value, the domain will not be added. periodt.domain_remove()β β οΈ experimental, ok? once a domain is added it cannot be completely unloaded. this is because there's no reference counting system in place to determine if there are any active references from sockets within that domain. sodomain_remove()exists, but it's experimental β and unloadable domains may be supported in the future. no cap.protosw_register()β dynamically adds a protocol to a domain, if the domain has an empty slot in itsdom_protosw. a dynamically added protocol can later be unloaded withprotosw_unregister().
π RETURN VALUES π
domain_add() never fails β but ngl, it may just not add a domain if its dom_probe fails. it's giving "no thoughts, head empty, nothing happened."
the protosw_register() function may fail if:
[EEXIST]β a protocol with the same value ofpr_typeandpr_protocolalready exists in the domain. (duplicate detected, not today π«)[ENOMEM]β the domain doesn't have anyNULLslots in itsdom_protosw. (no room, the array is full, it's giving packed elevator π)
π SEE ALSO π
π HISTORY π
the domain subsystem first appeared in 4.3BSD as part of the very first socket(2) API implementation β like, literally og main character energy π
and the domain subsystem and this manual page were significantly rewritten in FreeBSD 14. glow-up era β¨
π AUTHORS π
this manual page was written by Chad David <davidc@acns.ab.ca> and Gleb Smirnoff <glebius@FreeBSD.org>. absolute icons, we stan π«Ά
k that's the whole page, bestie β you're now officially versed in kernel socket implementation. go forth and slay π β¨
xoxo, this page came from the Debian edition of the Kernel Developer's Manual, dated September 14, 2022 π
π¦ where this page comes from
- freebsd 14.5: base 14.5
- freebsd 15.1: base 15.1
- Copyright (C) 2001 Chad David <davidc@acns.ab.ca>. All rights reserved
- Copyright (C) 2022 Gleb Smirnoff <glebius@FreeBSD.org>
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms