diff --git a/share/man/man9/Makefile b/share/man/man9/Makefile --- a/share/man/man9/Makefile +++ b/share/man/man9/Makefile @@ -1011,6 +1011,7 @@ 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 --- 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 @@ 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 @@ .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 --- a/sys/kern/uipc_domain.c +++ b/sys/kern/uipc_domain.c @@ -172,7 +172,11 @@ { 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 @@ { 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 @@ 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 --- a/sys/sys/domain.h +++ b/sys/sys/domain.h @@ -50,8 +50,10 @@ 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 @@ /* 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;