aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKyle Evans <kevans@FreeBSD.org>2020-06-26 02:17:47 +0000
committerKyle Evans <kevans@FreeBSD.org>2021-08-16 05:59:56 +0000
commit239aebee61b85d9a050d09a37fce2c2df8f36fc1 (patch)
treef0207a509ba08cd8959afe3cea5f9d74ce14e92b
parent59d1661cd8b02d13bc697e9dc0ff97844e719d9b (diff)
downloadsrc-239aebee61b85d9a050d09a37fce2c2df8f36fc1.tar.gz
src-239aebee61b85d9a050d09a37fce2c2df8f36fc1.zip
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
-rw-r--r--share/man/man9/Makefile1
-rw-r--r--share/man/man9/domain.932
-rw-r--r--sys/kern/uipc_domain.c9
-rw-r--r--sys/sys/domain.h5
4 files changed, 44 insertions, 3 deletions
diff --git a/share/man/man9/Makefile b/share/man/man9/Makefile
index 47c642319049..d7d26419b042 100644
--- a/share/man/man9/Makefile
+++ b/share/man/man9/Makefile
@@ -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 \
diff --git a/share/man/man9/domain.9 b/share/man/man9/domain.9
index e8f97253a1d4..03e83edfc14b 100644
--- a/share/man/man9/domain.9
+++ b/share/man/man9/domain.9
@@ -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.
diff --git a/sys/kern/uipc_domain.c b/sys/kern/uipc_domain.c
index 60e30eb1ae00..50d6c0a9d9f8 100644
--- a/sys/kern/uipc_domain.c
+++ b/sys/kern/uipc_domain.c
@@ -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;
diff --git a/sys/sys/domain.h b/sys/sys/domain.h
index 3d17879f1ccd..a59f4e230a1d 100644
--- a/sys/sys/domain.h
+++ b/sys/sys/domain.h
@@ -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;