1 /*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
5 * 1.0 of the CDDL.
6 *
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
10 */
11
12 /*
13 * Copyright 2015 Joyent, Inc.
14 */
15
16 /*
17 * varpd library
18 */
19
20 #include <stdlib.h>
21 #include <errno.h>
22 #include <umem.h>
23 #include <sys/types.h>
24 #include <unistd.h>
25 #include <sys/avl.h>
26 #include <stddef.h>
27 #include <stdio.h>
28 #include <strings.h>
29
30 #include <libvarpd_impl.h>
31
32 static int
libvarpd_instance_comparator(const void * lp,const void * rp)33 libvarpd_instance_comparator(const void *lp, const void *rp)
34 {
35 const varpd_instance_t *lpp, *rpp;
36 lpp = lp;
37 rpp = rp;
38
39 if (lpp->vri_id > rpp->vri_id)
40 return (1);
41 if (lpp->vri_id < rpp->vri_id)
42 return (-1);
43 return (0);
44 }
45
46 static int
libvarpd_instance_lcomparator(const void * lp,const void * rp)47 libvarpd_instance_lcomparator(const void *lp, const void *rp)
48 {
49 const varpd_instance_t *lpp, *rpp;
50 lpp = lp;
51 rpp = rp;
52
53 if (lpp->vri_linkid > rpp->vri_linkid)
54 return (1);
55 if (lpp->vri_linkid < rpp->vri_linkid)
56 return (-1);
57 return (0);
58 }
59
60 int
libvarpd_create(varpd_handle_t ** vphp)61 libvarpd_create(varpd_handle_t **vphp)
62 {
63 int ret;
64 varpd_impl_t *vip;
65 char buf[32];
66
67 if (vphp == NULL)
68 return (EINVAL);
69
70 *vphp = NULL;
71 vip = umem_alloc(sizeof (varpd_impl_t), UMEM_DEFAULT);
72 if (vip == NULL)
73 return (errno);
74
75 bzero(vip, sizeof (varpd_impl_t));
76 (void) snprintf(buf, sizeof (buf), "varpd_%p", vip);
77 vip->vdi_idspace = id_space_create(buf, LIBVARPD_ID_MIN,
78 LIBVARPD_ID_MAX);
79 if (vip->vdi_idspace == NULL) {
80 int ret = errno;
81 umem_free(vip, sizeof (varpd_impl_t));
82 return (ret);
83 }
84
85 vip->vdi_qcache = umem_cache_create("query", sizeof (varpd_query_t), 0,
86 NULL, NULL, NULL, NULL, NULL, 0);
87 if (vip->vdi_qcache == NULL) {
88 int ret = errno;
89 id_space_destroy(vip->vdi_idspace);
90 umem_free(vip, sizeof (varpd_impl_t));
91 return (ret);
92 }
93
94 if ((ret = libvarpd_overlay_init(vip)) != 0) {
95 umem_cache_destroy(vip->vdi_qcache);
96 id_space_destroy(vip->vdi_idspace);
97 umem_free(vip, sizeof (varpd_impl_t));
98 return (ret);
99 }
100
101 libvarpd_persist_init(vip);
102
103 avl_create(&vip->vdi_plugins, libvarpd_plugin_comparator,
104 sizeof (varpd_plugin_t), offsetof(varpd_plugin_t, vpp_node));
105
106 avl_create(&vip->vdi_instances, libvarpd_instance_comparator,
107 sizeof (varpd_instance_t), offsetof(varpd_instance_t, vri_inode));
108 avl_create(&vip->vdi_linstances, libvarpd_instance_lcomparator,
109 sizeof (varpd_instance_t), offsetof(varpd_instance_t, vri_lnode));
110
111 if (mutex_init(&vip->vdi_lock, USYNC_THREAD | LOCK_ERRORCHECK,
112 NULL) != 0)
113 libvarpd_panic("failed to create mutex: %d", errno);
114
115 vip->vdi_doorfd = -1;
116 *vphp = (varpd_handle_t *)vip;
117 return (0);
118 }
119
120 void
libvarpd_destroy(varpd_handle_t * vhp)121 libvarpd_destroy(varpd_handle_t *vhp)
122 {
123 varpd_impl_t *vip = (varpd_impl_t *)vhp;
124
125 libvarpd_overlay_lookup_quiesce(vhp);
126 if (mutex_destroy(&vip->vdi_lock) != 0)
127 libvarpd_panic("failed to destroy mutex: %d", errno);
128 libvarpd_persist_fini(vip);
129 libvarpd_overlay_fini(vip);
130 umem_cache_destroy(vip->vdi_qcache);
131 id_space_destroy(vip->vdi_idspace);
132 umem_free(vip, sizeof (varpd_impl_t));
133 }
134
135 int
libvarpd_instance_create(varpd_handle_t * vhp,datalink_id_t linkid,const char * pname,varpd_instance_handle_t ** outp)136 libvarpd_instance_create(varpd_handle_t *vhp, datalink_id_t linkid,
137 const char *pname, varpd_instance_handle_t **outp)
138 {
139 int ret;
140 varpd_impl_t *vip = (varpd_impl_t *)vhp;
141 varpd_plugin_t *plugin;
142 varpd_instance_t *inst, lookup;
143 overlay_plugin_dest_t dest;
144 uint64_t vid;
145
146 /*
147 * We should really have our own errnos.
148 */
149 plugin = libvarpd_plugin_lookup(vip, pname);
150 if (plugin == NULL)
151 return (ENOENT);
152
153 if ((ret = libvarpd_overlay_info(vip, linkid, &dest, NULL, &vid)) != 0)
154 return (ret);
155
156 inst = umem_alloc(sizeof (varpd_instance_t), UMEM_DEFAULT);
157 if (inst == NULL)
158 return (ENOMEM);
159
160 inst->vri_id = id_alloc(vip->vdi_idspace);
161 if (inst->vri_id == -1)
162 libvarpd_panic("failed to allocate id from vdi_idspace: %d",
163 errno);
164 inst->vri_linkid = linkid;
165 inst->vri_vnetid = vid;
166 inst->vri_mode = plugin->vpp_mode;
167 inst->vri_dest = dest;
168 inst->vri_plugin = plugin;
169 inst->vri_impl = vip;
170 inst->vri_flags = 0;
171 if ((ret = plugin->vpp_ops->vpo_create((varpd_provider_handle_t *)inst,
172 &inst->vri_private, dest)) != 0) {
173 id_free(vip->vdi_idspace, inst->vri_id);
174 umem_free(inst, sizeof (varpd_instance_t));
175 return (ret);
176 }
177
178 if (mutex_init(&inst->vri_lock, USYNC_THREAD | LOCK_ERRORCHECK,
179 NULL) != 0)
180 libvarpd_panic("failed to create mutex: %d", errno);
181
182 mutex_enter(&vip->vdi_lock);
183 lookup.vri_id = inst->vri_id;
184 if (avl_find(&vip->vdi_instances, &lookup, NULL) != NULL)
185 libvarpd_panic("found duplicate instance with id %d",
186 lookup.vri_id);
187 avl_add(&vip->vdi_instances, inst);
188 lookup.vri_linkid = inst->vri_linkid;
189 if (avl_find(&vip->vdi_linstances, &lookup, NULL) != NULL)
190 libvarpd_panic("found duplicate linstance with id %d",
191 lookup.vri_linkid);
192 avl_add(&vip->vdi_linstances, inst);
193 mutex_exit(&vip->vdi_lock);
194 *outp = (varpd_instance_handle_t *)inst;
195 return (0);
196 }
197
198 uint64_t
libvarpd_instance_id(varpd_instance_handle_t * ihp)199 libvarpd_instance_id(varpd_instance_handle_t *ihp)
200 {
201 varpd_instance_t *inst = (varpd_instance_t *)ihp;
202 return (inst->vri_id);
203 }
204
205 uint64_t
libvarpd_plugin_vnetid(varpd_provider_handle_t * vhp)206 libvarpd_plugin_vnetid(varpd_provider_handle_t *vhp)
207 {
208 varpd_instance_t *inst = (varpd_instance_t *)vhp;
209 return (inst->vri_vnetid);
210 }
211
212 varpd_instance_handle_t *
libvarpd_instance_lookup(varpd_handle_t * vhp,uint64_t id)213 libvarpd_instance_lookup(varpd_handle_t *vhp, uint64_t id)
214 {
215 varpd_impl_t *vip = (varpd_impl_t *)vhp;
216 varpd_instance_t lookup, *retp;
217
218 lookup.vri_id = id;
219 mutex_enter(&vip->vdi_lock);
220 retp = avl_find(&vip->vdi_instances, &lookup, NULL);
221 mutex_exit(&vip->vdi_lock);
222 return ((varpd_instance_handle_t *)retp);
223 }
224
225 /*
226 * If this function becomes external to varpd, we need to change it to return a
227 * varpd_instance_handle_t.
228 */
229 varpd_instance_t *
libvarpd_instance_lookup_by_dlid(varpd_impl_t * vip,datalink_id_t linkid)230 libvarpd_instance_lookup_by_dlid(varpd_impl_t *vip, datalink_id_t linkid)
231 {
232 varpd_instance_t lookup, *retp;
233
234 lookup.vri_linkid = linkid;
235 mutex_enter(&vip->vdi_lock);
236 retp = avl_find(&vip->vdi_linstances, &lookup, NULL);
237 mutex_exit(&vip->vdi_lock);
238 return (retp);
239 }
240
241 /*
242 * When an instance is being destroyed, that means we should deactivate it, as
243 * well as clean it up. That means here, the proper order is calling the plug-in
244 * stop and then the destroy function.
245 */
246 void
libvarpd_instance_destroy(varpd_instance_handle_t * ihp)247 libvarpd_instance_destroy(varpd_instance_handle_t *ihp)
248 {
249 varpd_instance_t *inst = (varpd_instance_t *)ihp;
250 varpd_impl_t *vip = inst->vri_impl;
251
252 /*
253 * First things first, remove it from global visibility.
254 */
255 mutex_enter(&vip->vdi_lock);
256 avl_remove(&vip->vdi_instances, inst);
257 avl_remove(&vip->vdi_linstances, inst);
258 mutex_exit(&vip->vdi_lock);
259
260 mutex_enter(&inst->vri_lock);
261
262 /*
263 * We need to clean up this instance, that means remove it from
264 * persistence and stopping it. Then finally we'll have to clean it up
265 * entirely.
266 */
267 if (inst->vri_flags & VARPD_INSTANCE_F_ACTIVATED) {
268 inst->vri_flags &= ~VARPD_INSTANCE_F_ACTIVATED;
269 libvarpd_torch_instance(vip, inst);
270 inst->vri_plugin->vpp_ops->vpo_stop(inst->vri_private);
271 inst->vri_plugin->vpp_ops->vpo_destroy(inst->vri_private);
272 inst->vri_private = NULL;
273 }
274 mutex_exit(&inst->vri_lock);
275
276 /* Do the full clean up of the instance */
277 if (mutex_destroy(&inst->vri_lock) != 0)
278 libvarpd_panic("failed to destroy instance vri_lock");
279 id_free(vip->vdi_idspace, inst->vri_id);
280 umem_free(inst, sizeof (varpd_instance_t));
281 }
282
283 int
libvarpd_instance_activate(varpd_instance_handle_t * ihp)284 libvarpd_instance_activate(varpd_instance_handle_t *ihp)
285 {
286 int ret;
287 varpd_instance_t *inst = (varpd_instance_t *)ihp;
288
289 mutex_enter(&inst->vri_lock);
290
291 if (inst->vri_flags & VARPD_INSTANCE_F_ACTIVATED) {
292 ret = EEXIST;
293 goto out;
294 }
295
296 if ((ret = inst->vri_plugin->vpp_ops->vpo_start(inst->vri_private)) !=
297 0)
298 goto out;
299
300 if ((ret = libvarpd_persist_instance(inst->vri_impl, inst)) != 0)
301 goto out;
302
303 /*
304 * If this fails, we don't need to call stop, as the caller should end
305 * up calling destroy on the instance, which takes care of calling stop
306 * and destroy.
307 */
308 if ((ret = libvarpd_overlay_associate(inst)) != 0)
309 goto out;
310
311 inst->vri_flags |= VARPD_INSTANCE_F_ACTIVATED;
312
313 out:
314 mutex_exit(&inst->vri_lock);
315 return (ret);
316 }
317
318 static void
libvarpd_prefork(void)319 libvarpd_prefork(void)
320 {
321 libvarpd_plugin_prefork();
322 }
323
324 static void
libvarpd_postfork(void)325 libvarpd_postfork(void)
326 {
327 libvarpd_plugin_postfork();
328 }
329
330 #pragma init(libvarpd_init)
331 static void
libvarpd_init(void)332 libvarpd_init(void)
333 {
334 libvarpd_plugin_init();
335 if (pthread_atfork(libvarpd_prefork, libvarpd_postfork,
336 libvarpd_postfork) != 0)
337 libvarpd_panic("failed to create varpd atfork: %d", errno);
338 }
339
340 #pragma fini(libvarpd_fini)
341 static void
libvarpd_fini(void)342 libvarpd_fini(void)
343 {
344 libvarpd_plugin_fini();
345 }
346