1*36589d6bSRobert Mustacchi /*
2*36589d6bSRobert Mustacchi * This file and its contents are supplied under the terms of the
3*36589d6bSRobert Mustacchi * Common Development and Distribution License ("CDDL"), version 1.0.
4*36589d6bSRobert Mustacchi * You may only use this file in accordance with the terms of version
5*36589d6bSRobert Mustacchi * 1.0 of the CDDL.
6*36589d6bSRobert Mustacchi *
7*36589d6bSRobert Mustacchi * A full copy of the text of the CDDL should have accompanied this
8*36589d6bSRobert Mustacchi * source. A copy of the CDDL is also available via the Internet at
9*36589d6bSRobert Mustacchi * http://www.illumos.org/license/CDDL.
10*36589d6bSRobert Mustacchi */
11*36589d6bSRobert Mustacchi
12*36589d6bSRobert Mustacchi /*
13*36589d6bSRobert Mustacchi * Copyright 2015 Joyent, Inc.
14*36589d6bSRobert Mustacchi */
15*36589d6bSRobert Mustacchi
16*36589d6bSRobert Mustacchi /*
17*36589d6bSRobert Mustacchi * Overlay device encapsulation plugin management
18*36589d6bSRobert Mustacchi *
19*36589d6bSRobert Mustacchi * For more information, see the big theory statement in
20*36589d6bSRobert Mustacchi * uts/common/io/overlay/overlay.c
21*36589d6bSRobert Mustacchi */
22*36589d6bSRobert Mustacchi
23*36589d6bSRobert Mustacchi #include <sys/types.h>
24*36589d6bSRobert Mustacchi #include <sys/kmem.h>
25*36589d6bSRobert Mustacchi #include <sys/ddi.h>
26*36589d6bSRobert Mustacchi #include <sys/sunddi.h>
27*36589d6bSRobert Mustacchi #include <sys/errno.h>
28*36589d6bSRobert Mustacchi #include <sys/sysmacros.h>
29*36589d6bSRobert Mustacchi #include <sys/modctl.h>
30*36589d6bSRobert Mustacchi
31*36589d6bSRobert Mustacchi #include <sys/overlay_impl.h>
32*36589d6bSRobert Mustacchi
33*36589d6bSRobert Mustacchi static kmem_cache_t *overlay_plugin_cache;
34*36589d6bSRobert Mustacchi static kmutex_t overlay_plugin_lock;
35*36589d6bSRobert Mustacchi static list_t overlay_plugin_list;
36*36589d6bSRobert Mustacchi
37*36589d6bSRobert Mustacchi #define OVERLAY_MODDIR "overlay"
38*36589d6bSRobert Mustacchi
39*36589d6bSRobert Mustacchi /* ARGSUSED */
40*36589d6bSRobert Mustacchi static int
overlay_plugin_cache_constructor(void * buf,void * arg,int kmflags)41*36589d6bSRobert Mustacchi overlay_plugin_cache_constructor(void *buf, void *arg, int kmflags)
42*36589d6bSRobert Mustacchi {
43*36589d6bSRobert Mustacchi overlay_plugin_t *opp = buf;
44*36589d6bSRobert Mustacchi
45*36589d6bSRobert Mustacchi mutex_init(&opp->ovp_mutex, NULL, MUTEX_DRIVER, NULL);
46*36589d6bSRobert Mustacchi list_link_init(&opp->ovp_link);
47*36589d6bSRobert Mustacchi
48*36589d6bSRobert Mustacchi return (0);
49*36589d6bSRobert Mustacchi }
50*36589d6bSRobert Mustacchi
51*36589d6bSRobert Mustacchi /* ARGSUSED */
52*36589d6bSRobert Mustacchi static void
overlay_plugin_cache_destructor(void * buf,void * arg)53*36589d6bSRobert Mustacchi overlay_plugin_cache_destructor(void *buf, void *arg)
54*36589d6bSRobert Mustacchi {
55*36589d6bSRobert Mustacchi overlay_plugin_t *opp = buf;
56*36589d6bSRobert Mustacchi ASSERT(list_link_active(&opp->ovp_link) == 0);
57*36589d6bSRobert Mustacchi mutex_destroy(&opp->ovp_mutex);
58*36589d6bSRobert Mustacchi }
59*36589d6bSRobert Mustacchi
60*36589d6bSRobert Mustacchi void
overlay_plugin_init(void)61*36589d6bSRobert Mustacchi overlay_plugin_init(void)
62*36589d6bSRobert Mustacchi {
63*36589d6bSRobert Mustacchi mutex_init(&overlay_plugin_lock, NULL, MUTEX_DRIVER, 0);
64*36589d6bSRobert Mustacchi
65*36589d6bSRobert Mustacchi /*
66*36589d6bSRobert Mustacchi * In the future we may want to have a reaper to unload unused modules
67*36589d6bSRobert Mustacchi * to help the kernel be able to reclaim memory.
68*36589d6bSRobert Mustacchi */
69*36589d6bSRobert Mustacchi overlay_plugin_cache = kmem_cache_create("overlay_plugin_cache",
70*36589d6bSRobert Mustacchi sizeof (overlay_plugin_t), 0, overlay_plugin_cache_constructor,
71*36589d6bSRobert Mustacchi overlay_plugin_cache_destructor, NULL, NULL, NULL, 0);
72*36589d6bSRobert Mustacchi list_create(&overlay_plugin_list, sizeof (overlay_plugin_t),
73*36589d6bSRobert Mustacchi offsetof(overlay_plugin_t, ovp_link));
74*36589d6bSRobert Mustacchi }
75*36589d6bSRobert Mustacchi
76*36589d6bSRobert Mustacchi void
overlay_plugin_fini(void)77*36589d6bSRobert Mustacchi overlay_plugin_fini(void)
78*36589d6bSRobert Mustacchi {
79*36589d6bSRobert Mustacchi mutex_enter(&overlay_plugin_lock);
80*36589d6bSRobert Mustacchi VERIFY(list_is_empty(&overlay_plugin_list));
81*36589d6bSRobert Mustacchi mutex_exit(&overlay_plugin_lock);
82*36589d6bSRobert Mustacchi
83*36589d6bSRobert Mustacchi list_destroy(&overlay_plugin_list);
84*36589d6bSRobert Mustacchi kmem_cache_destroy(overlay_plugin_cache);
85*36589d6bSRobert Mustacchi mutex_destroy(&overlay_plugin_lock);
86*36589d6bSRobert Mustacchi }
87*36589d6bSRobert Mustacchi
88*36589d6bSRobert Mustacchi overlay_plugin_register_t *
overlay_plugin_alloc(uint_t version)89*36589d6bSRobert Mustacchi overlay_plugin_alloc(uint_t version)
90*36589d6bSRobert Mustacchi {
91*36589d6bSRobert Mustacchi overlay_plugin_register_t *ovrp;
92*36589d6bSRobert Mustacchi /* Version 1 is the only one that exists */
93*36589d6bSRobert Mustacchi if (version != OVEP_VERSION_ONE)
94*36589d6bSRobert Mustacchi return (NULL);
95*36589d6bSRobert Mustacchi
96*36589d6bSRobert Mustacchi ovrp = kmem_zalloc(sizeof (overlay_plugin_register_t), KM_SLEEP);
97*36589d6bSRobert Mustacchi ovrp->ovep_version = version;
98*36589d6bSRobert Mustacchi return (ovrp);
99*36589d6bSRobert Mustacchi }
100*36589d6bSRobert Mustacchi
101*36589d6bSRobert Mustacchi void
overlay_plugin_free(overlay_plugin_register_t * ovrp)102*36589d6bSRobert Mustacchi overlay_plugin_free(overlay_plugin_register_t *ovrp)
103*36589d6bSRobert Mustacchi {
104*36589d6bSRobert Mustacchi kmem_free(ovrp, sizeof (overlay_plugin_register_t));
105*36589d6bSRobert Mustacchi }
106*36589d6bSRobert Mustacchi
107*36589d6bSRobert Mustacchi int
overlay_plugin_register(overlay_plugin_register_t * ovrp)108*36589d6bSRobert Mustacchi overlay_plugin_register(overlay_plugin_register_t *ovrp)
109*36589d6bSRobert Mustacchi {
110*36589d6bSRobert Mustacchi overlay_plugin_t *opp, *ipp;
111*36589d6bSRobert Mustacchi
112*36589d6bSRobert Mustacchi /* Sanity check parameters of the registration */
113*36589d6bSRobert Mustacchi if (ovrp->ovep_version != OVEP_VERSION_ONE)
114*36589d6bSRobert Mustacchi return (EINVAL);
115*36589d6bSRobert Mustacchi
116*36589d6bSRobert Mustacchi if (ovrp->ovep_name == NULL || ovrp->ovep_ops == NULL)
117*36589d6bSRobert Mustacchi return (EINVAL);
118*36589d6bSRobert Mustacchi
119*36589d6bSRobert Mustacchi if ((ovrp->ovep_flags & ~(OVEP_F_VLAN_TAG)) != 0)
120*36589d6bSRobert Mustacchi return (EINVAL);
121*36589d6bSRobert Mustacchi
122*36589d6bSRobert Mustacchi if (ovrp->ovep_id_size < 1)
123*36589d6bSRobert Mustacchi return (EINVAL);
124*36589d6bSRobert Mustacchi
125*36589d6bSRobert Mustacchi /* Don't support anything that has an id size larger than 8 bytes */
126*36589d6bSRobert Mustacchi if (ovrp->ovep_id_size > 8)
127*36589d6bSRobert Mustacchi return (ENOTSUP);
128*36589d6bSRobert Mustacchi
129*36589d6bSRobert Mustacchi if (ovrp->ovep_dest == OVERLAY_PLUGIN_D_INVALID)
130*36589d6bSRobert Mustacchi return (EINVAL);
131*36589d6bSRobert Mustacchi
132*36589d6bSRobert Mustacchi if ((ovrp->ovep_dest & ~OVERLAY_PLUGIN_D_MASK) != 0)
133*36589d6bSRobert Mustacchi return (EINVAL);
134*36589d6bSRobert Mustacchi
135*36589d6bSRobert Mustacchi if (ovrp->ovep_ops->ovpo_callbacks != 0)
136*36589d6bSRobert Mustacchi return (EINVAL);
137*36589d6bSRobert Mustacchi if (ovrp->ovep_ops->ovpo_init == NULL)
138*36589d6bSRobert Mustacchi return (EINVAL);
139*36589d6bSRobert Mustacchi if (ovrp->ovep_ops->ovpo_fini == NULL)
140*36589d6bSRobert Mustacchi return (EINVAL);
141*36589d6bSRobert Mustacchi if (ovrp->ovep_ops->ovpo_encap == NULL)
142*36589d6bSRobert Mustacchi return (EINVAL);
143*36589d6bSRobert Mustacchi if (ovrp->ovep_ops->ovpo_decap == NULL)
144*36589d6bSRobert Mustacchi return (EINVAL);
145*36589d6bSRobert Mustacchi if (ovrp->ovep_ops->ovpo_socket == NULL)
146*36589d6bSRobert Mustacchi return (EINVAL);
147*36589d6bSRobert Mustacchi if (ovrp->ovep_ops->ovpo_getprop == NULL)
148*36589d6bSRobert Mustacchi return (EINVAL);
149*36589d6bSRobert Mustacchi if (ovrp->ovep_ops->ovpo_setprop == NULL)
150*36589d6bSRobert Mustacchi return (EINVAL);
151*36589d6bSRobert Mustacchi if (ovrp->ovep_ops->ovpo_propinfo == NULL)
152*36589d6bSRobert Mustacchi return (EINVAL);
153*36589d6bSRobert Mustacchi
154*36589d6bSRobert Mustacchi
155*36589d6bSRobert Mustacchi opp = kmem_cache_alloc(overlay_plugin_cache, KM_SLEEP);
156*36589d6bSRobert Mustacchi opp->ovp_active = 0;
157*36589d6bSRobert Mustacchi opp->ovp_name = ovrp->ovep_name;
158*36589d6bSRobert Mustacchi opp->ovp_ops = ovrp->ovep_ops;
159*36589d6bSRobert Mustacchi opp->ovp_props = ovrp->ovep_props;
160*36589d6bSRobert Mustacchi opp->ovp_id_size = ovrp->ovep_id_size;
161*36589d6bSRobert Mustacchi opp->ovp_flags = ovrp->ovep_flags;
162*36589d6bSRobert Mustacchi opp->ovp_dest = ovrp->ovep_dest;
163*36589d6bSRobert Mustacchi
164*36589d6bSRobert Mustacchi opp->ovp_nprops = 0;
165*36589d6bSRobert Mustacchi if (ovrp->ovep_props != NULL) {
166*36589d6bSRobert Mustacchi while (ovrp->ovep_props[opp->ovp_nprops] != NULL) {
167*36589d6bSRobert Mustacchi if (strlen(ovrp->ovep_props[opp->ovp_nprops]) >=
168*36589d6bSRobert Mustacchi OVERLAY_PROP_NAMELEN) {
169*36589d6bSRobert Mustacchi mutex_exit(&overlay_plugin_lock);
170*36589d6bSRobert Mustacchi kmem_cache_free(overlay_plugin_cache, opp);
171*36589d6bSRobert Mustacchi return (EINVAL);
172*36589d6bSRobert Mustacchi }
173*36589d6bSRobert Mustacchi opp->ovp_nprops++;
174*36589d6bSRobert Mustacchi }
175*36589d6bSRobert Mustacchi }
176*36589d6bSRobert Mustacchi
177*36589d6bSRobert Mustacchi mutex_enter(&overlay_plugin_lock);
178*36589d6bSRobert Mustacchi for (ipp = list_head(&overlay_plugin_list); ipp != NULL;
179*36589d6bSRobert Mustacchi ipp = list_next(&overlay_plugin_list, ipp)) {
180*36589d6bSRobert Mustacchi if (strcmp(ipp->ovp_name, opp->ovp_name) == 0) {
181*36589d6bSRobert Mustacchi mutex_exit(&overlay_plugin_lock);
182*36589d6bSRobert Mustacchi kmem_cache_free(overlay_plugin_cache, opp);
183*36589d6bSRobert Mustacchi return (EEXIST);
184*36589d6bSRobert Mustacchi }
185*36589d6bSRobert Mustacchi }
186*36589d6bSRobert Mustacchi list_insert_tail(&overlay_plugin_list, opp);
187*36589d6bSRobert Mustacchi mutex_exit(&overlay_plugin_lock);
188*36589d6bSRobert Mustacchi
189*36589d6bSRobert Mustacchi return (0);
190*36589d6bSRobert Mustacchi }
191*36589d6bSRobert Mustacchi
192*36589d6bSRobert Mustacchi int
overlay_plugin_unregister(const char * name)193*36589d6bSRobert Mustacchi overlay_plugin_unregister(const char *name)
194*36589d6bSRobert Mustacchi {
195*36589d6bSRobert Mustacchi overlay_plugin_t *opp;
196*36589d6bSRobert Mustacchi
197*36589d6bSRobert Mustacchi mutex_enter(&overlay_plugin_lock);
198*36589d6bSRobert Mustacchi for (opp = list_head(&overlay_plugin_list); opp != NULL;
199*36589d6bSRobert Mustacchi opp = list_next(&overlay_plugin_list, opp)) {
200*36589d6bSRobert Mustacchi if (strcmp(opp->ovp_name, name) == 0)
201*36589d6bSRobert Mustacchi break;
202*36589d6bSRobert Mustacchi }
203*36589d6bSRobert Mustacchi
204*36589d6bSRobert Mustacchi if (opp == NULL) {
205*36589d6bSRobert Mustacchi mutex_exit(&overlay_plugin_lock);
206*36589d6bSRobert Mustacchi return (ENOENT);
207*36589d6bSRobert Mustacchi }
208*36589d6bSRobert Mustacchi
209*36589d6bSRobert Mustacchi mutex_enter(&opp->ovp_mutex);
210*36589d6bSRobert Mustacchi if (opp->ovp_active > 0) {
211*36589d6bSRobert Mustacchi mutex_exit(&opp->ovp_mutex);
212*36589d6bSRobert Mustacchi mutex_exit(&overlay_plugin_lock);
213*36589d6bSRobert Mustacchi return (EBUSY);
214*36589d6bSRobert Mustacchi }
215*36589d6bSRobert Mustacchi mutex_exit(&opp->ovp_mutex);
216*36589d6bSRobert Mustacchi
217*36589d6bSRobert Mustacchi list_remove(&overlay_plugin_list, opp);
218*36589d6bSRobert Mustacchi mutex_exit(&overlay_plugin_lock);
219*36589d6bSRobert Mustacchi
220*36589d6bSRobert Mustacchi kmem_cache_free(overlay_plugin_cache, opp);
221*36589d6bSRobert Mustacchi return (0);
222*36589d6bSRobert Mustacchi }
223*36589d6bSRobert Mustacchi
224*36589d6bSRobert Mustacchi overlay_plugin_t *
overlay_plugin_lookup(const char * name)225*36589d6bSRobert Mustacchi overlay_plugin_lookup(const char *name)
226*36589d6bSRobert Mustacchi {
227*36589d6bSRobert Mustacchi overlay_plugin_t *opp;
228*36589d6bSRobert Mustacchi boolean_t trymodload = B_FALSE;
229*36589d6bSRobert Mustacchi
230*36589d6bSRobert Mustacchi for (;;) {
231*36589d6bSRobert Mustacchi mutex_enter(&overlay_plugin_lock);
232*36589d6bSRobert Mustacchi for (opp = list_head(&overlay_plugin_list); opp != NULL;
233*36589d6bSRobert Mustacchi opp = list_next(&overlay_plugin_list, opp)) {
234*36589d6bSRobert Mustacchi if (strcmp(name, opp->ovp_name) == 0) {
235*36589d6bSRobert Mustacchi mutex_enter(&opp->ovp_mutex);
236*36589d6bSRobert Mustacchi opp->ovp_active++;
237*36589d6bSRobert Mustacchi mutex_exit(&opp->ovp_mutex);
238*36589d6bSRobert Mustacchi mutex_exit(&overlay_plugin_lock);
239*36589d6bSRobert Mustacchi return (opp);
240*36589d6bSRobert Mustacchi }
241*36589d6bSRobert Mustacchi }
242*36589d6bSRobert Mustacchi mutex_exit(&overlay_plugin_lock);
243*36589d6bSRobert Mustacchi
244*36589d6bSRobert Mustacchi if (trymodload == B_TRUE)
245*36589d6bSRobert Mustacchi return (NULL);
246*36589d6bSRobert Mustacchi
247*36589d6bSRobert Mustacchi /*
248*36589d6bSRobert Mustacchi * If we didn't find it, it may still exist, but just not have
249*36589d6bSRobert Mustacchi * been a loaded module. In that case, we'll do one attempt to
250*36589d6bSRobert Mustacchi * load it.
251*36589d6bSRobert Mustacchi */
252*36589d6bSRobert Mustacchi if (modload(OVERLAY_MODDIR, (char *)name) == -1)
253*36589d6bSRobert Mustacchi return (NULL);
254*36589d6bSRobert Mustacchi trymodload = B_TRUE;
255*36589d6bSRobert Mustacchi }
256*36589d6bSRobert Mustacchi
257*36589d6bSRobert Mustacchi }
258*36589d6bSRobert Mustacchi
259*36589d6bSRobert Mustacchi void
overlay_plugin_rele(overlay_plugin_t * opp)260*36589d6bSRobert Mustacchi overlay_plugin_rele(overlay_plugin_t *opp)
261*36589d6bSRobert Mustacchi {
262*36589d6bSRobert Mustacchi mutex_enter(&opp->ovp_mutex);
263*36589d6bSRobert Mustacchi ASSERT(opp->ovp_active > 0);
264*36589d6bSRobert Mustacchi opp->ovp_active--;
265*36589d6bSRobert Mustacchi mutex_exit(&opp->ovp_mutex);
266*36589d6bSRobert Mustacchi }
267*36589d6bSRobert Mustacchi
268*36589d6bSRobert Mustacchi void
overlay_plugin_walk(overlay_plugin_walk_f func,void * arg)269*36589d6bSRobert Mustacchi overlay_plugin_walk(overlay_plugin_walk_f func, void *arg)
270*36589d6bSRobert Mustacchi {
271*36589d6bSRobert Mustacchi overlay_plugin_t *opp;
272*36589d6bSRobert Mustacchi mutex_enter(&overlay_plugin_lock);
273*36589d6bSRobert Mustacchi for (opp = list_head(&overlay_plugin_list); opp != NULL;
274*36589d6bSRobert Mustacchi opp = list_next(&overlay_plugin_list, opp)) {
275*36589d6bSRobert Mustacchi if (func(opp, arg) != 0) {
276*36589d6bSRobert Mustacchi mutex_exit(&overlay_plugin_lock);
277*36589d6bSRobert Mustacchi return;
278*36589d6bSRobert Mustacchi }
279*36589d6bSRobert Mustacchi }
280*36589d6bSRobert Mustacchi mutex_exit(&overlay_plugin_lock);
281*36589d6bSRobert Mustacchi }
282