domain: give domains a chance to probe for availability

This gives any given domain a chance to indicate that it's not actually
supported on the current system. If dom_probe isn't supplied, we assume
the domain is universally applicable as most of them are. Keeping
fully-initialized and registered domains around that physically can't
work on a large majority of FreeBSD deployments is sub-optimal and leads
to errors that aren't consistent with the reality of why the socket
can't be created (e.g. ESOCKTNOSUPPORT) because such scenario has to be
caught upon pru_attach, at which point kicking back the more-appropriate
EAFNOSUPPORT would seem weird.

The initial consumer of this will be hvsock, which is only available on
HyperV guests.

Reviewed by:	cem (earlier version), bcr (manpages)
Differential Revision:	https://reviews.freebsd.org/D25062
This commit is contained in:
Kyle Evans 2020-06-25 21:17:47 -05:00
parent 59d1661cd8
commit 239aebee61
4 changed files with 44 additions and 3 deletions

View File

@ -1011,6 +1011,7 @@ MLINKS+=dnv.9 dnvlist.9 \
dnv.9 dnvlist_take_string.9
MLINKS+=domain.9 DOMAIN_SET.9 \
domain.9 domain_add.9 \
domain.9 domain_init.9 \
domain.9 pfctlinput.9 \
domain.9 pffinddomain.9 \
domain.9 pffindproto.9 \

View File

@ -31,6 +31,7 @@
.Os
.Sh NAME
.Nm domain_add ,
.Nm domain_init ,
.Nm pfctlinput ,
.Nm pffinddomain ,
.Nm pffindproto ,
@ -45,6 +46,8 @@
.Ft void
.Fn domain_add "void *data"
.Ft void
.Fn domain_init "void *data"
.Ft void
.Fn pfctlinput "int cmd" "struct sockaddr *sa"
.Ft struct domain *
.Fn pffinddomain "int family"
@ -65,8 +68,10 @@ and
struct domain {
int dom_family; /* AF_xxx */
char *dom_name;
int dom_flags;
void (*dom_init) /* initialize domain data structures */
(void);
int (*dom_probe)(void); /* check for support (optional) */
void (*dom_destroy) /* cleanup structures / state */
(void);
int (*dom_externalize) /* externalize access rights */
@ -143,15 +148,36 @@ is not called directly, instead
.Fn DOMAIN_SET
is used.
.Pp
If the new domain has defined an initialization routine, it is called by
.Fn domain_add ;
If the new domain has defined a probe routine, it is called first in
.Fn domain_add
to determine if the domain should be supported on the current system.
If the probe routine returns a non-0 value, then the domain will not be
marked as supported.
Unsupported domains do not proceed with the initialization process and are not
discoverable by
.Fn pffinddomain ,
.Fn pffindtype ,
or
.Fn pffindproto .
.Pp
.Fn domain_init
is called after
.Fn domain_add
during boot and for each
.Xr vnet 9 .
If the new domain has defined an initialization routine, it is called during
.Fn domain_init ;
as well, each of the protocols within the domain that have defined an
initialization routine will have theirs called.
Note that domain initialization cannot fail at this time.
.Pp
Once a domain is added it cannot be unloaded.
Once a domain is added it cannot be completely unloaded.
This is because there is
no reference counting system in place to determine if there are any
active references from sockets within that domain.
If the domain defines a
.Fn dom_destroy
routine, then it will be invoked during vnet teardown.
.Pp
.Fn pffinddomain
finds a domain by family.

View File

@ -172,7 +172,11 @@ domain_init(void *arg)
{
struct domain *dp = arg;
struct protosw *pr;
int flags;
flags = atomic_load_acq_int(&dp->dom_flags);
if ((flags & DOMF_SUPPORTED) == 0)
return;
if (dp->dom_init)
(*dp->dom_init)();
for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++)
@ -200,6 +204,8 @@ vnet_domain_uninit(void *arg)
{
struct domain *dp = arg;
if ((atomic_load_acq_int(&dp->dom_flags) & DOMF_SUPPORTED) == 0)
return;
if (dp->dom_destroy)
(*dp->dom_destroy)();
}
@ -216,6 +222,9 @@ domain_add(void *data)
struct domain *dp;
dp = (struct domain *)data;
if (dp->dom_probe != NULL && (*dp->dom_probe)() != 0)
return;
atomic_set_rel_int(&dp->dom_flags, DOMF_SUPPORTED);
mtx_lock(&dom_mtx);
dp->dom_next = domains;
domains = dp;

View File

@ -50,8 +50,10 @@ struct rib_head;
struct domain {
int dom_family; /* AF_xxx */
char *dom_name;
int dom_flags;
void (*dom_init) /* initialize domain data structures */
(void);
int (*dom_probe)(void); /* check for support (optional) */
void (*dom_destroy) /* cleanup structures / state */
(void);
int (*dom_externalize) /* externalize access rights */
@ -70,6 +72,9 @@ struct domain {
/* af-dependent data on ifnet */
};
/* dom_flags */
#define DOMF_SUPPORTED 0x0001 /* System supports this domain. */
#ifdef _KERNEL
extern int domain_init_status;
extern struct domain *domains;