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 * Interactions with /dev/overlay
18 */
19
20 #include <sys/types.h>
21 #include <sys/stat.h>
22 #include <fcntl.h>
23 #include <errno.h>
24 #include <assert.h>
25 #include <unistd.h>
26 #include <stdlib.h>
27 #include <stropts.h>
28 #include <strings.h>
29 #include <umem.h>
30
31 #include <libvarpd_impl.h>
32 #include <sys/overlay_target.h>
33
34 #define OVERLAY_PATH "/dev/overlay"
35
36 int
libvarpd_overlay_init(varpd_impl_t * vip)37 libvarpd_overlay_init(varpd_impl_t *vip)
38 {
39 vip->vdi_overlayfd = open(OVERLAY_PATH, O_RDWR | O_EXCL);
40 if (vip->vdi_overlayfd == -1)
41 return (errno);
42 return (0);
43 }
44
45 void
libvarpd_overlay_fini(varpd_impl_t * vip)46 libvarpd_overlay_fini(varpd_impl_t *vip)
47 {
48 assert(vip->vdi_overlayfd > 0);
49 if (close(vip->vdi_overlayfd) != 0)
50 libvarpd_panic("failed to close /dev/overlay fd %d: %d",
51 vip->vdi_overlayfd, errno);
52 }
53
54 int
libvarpd_overlay_info(varpd_impl_t * vip,datalink_id_t linkid,overlay_plugin_dest_t * destp,uint64_t * flags,uint64_t * vnetid)55 libvarpd_overlay_info(varpd_impl_t *vip, datalink_id_t linkid,
56 overlay_plugin_dest_t *destp, uint64_t *flags, uint64_t *vnetid)
57 {
58 overlay_targ_info_t oti;
59
60 oti.oti_linkid = linkid;
61 if (ioctl(vip->vdi_overlayfd, OVERLAY_TARG_INFO, &oti) != 0)
62 return (errno);
63
64 if (destp != NULL)
65 *destp = oti.oti_needs;
66 if (flags != NULL)
67 *flags = oti.oti_flags;
68 if (vnetid != NULL)
69 *vnetid = oti.oti_vnetid;
70 return (0);
71 }
72
73 int
libvarpd_overlay_associate(varpd_instance_t * inst)74 libvarpd_overlay_associate(varpd_instance_t *inst)
75 {
76 overlay_targ_associate_t ota;
77 varpd_impl_t *vip = inst->vri_impl;
78
79 bzero(&ota, sizeof (overlay_targ_associate_t));
80 ota.ota_linkid = inst->vri_linkid;
81 ota.ota_mode = inst->vri_mode;
82 ota.ota_id = inst->vri_id;
83 ota.ota_provides = inst->vri_dest;
84
85 if (ota.ota_mode == OVERLAY_TARGET_POINT) {
86 int ret;
87 ret = inst->vri_plugin->vpp_ops->vpo_default(inst->vri_private,
88 &ota.ota_point);
89 if (ret != VARPD_LOOKUP_OK)
90 return (ret);
91 }
92
93 if (ioctl(vip->vdi_overlayfd, OVERLAY_TARG_ASSOCIATE, &ota) != 0)
94 return (errno);
95
96 return (0);
97 }
98
99 int
libvarpd_overlay_disassociate(varpd_instance_t * inst)100 libvarpd_overlay_disassociate(varpd_instance_t *inst)
101 {
102 overlay_targ_id_t otid;
103 varpd_impl_t *vip = inst->vri_impl;
104
105 otid.otid_linkid = inst->vri_linkid;
106 if (ioctl(vip->vdi_overlayfd, OVERLAY_TARG_DISASSOCIATE, &otid) != 0)
107 return (errno);
108 return (0);
109 }
110
111 int
libvarpd_overlay_degrade_datalink(varpd_impl_t * vip,datalink_id_t linkid,const char * msg)112 libvarpd_overlay_degrade_datalink(varpd_impl_t *vip, datalink_id_t linkid,
113 const char *msg)
114 {
115 overlay_targ_degrade_t otd;
116
117 otd.otd_linkid = linkid;
118 (void) strlcpy(otd.otd_buf, msg, OVERLAY_STATUS_BUFLEN);
119 if (ioctl(vip->vdi_overlayfd, OVERLAY_TARG_DEGRADE, &otd) != 0)
120 return (errno);
121 return (0);
122
123 }
124
125 int
libvarpd_overlay_degrade(varpd_instance_t * inst,const char * msg)126 libvarpd_overlay_degrade(varpd_instance_t *inst, const char *msg)
127 {
128 return (libvarpd_overlay_degrade_datalink(inst->vri_impl,
129 inst->vri_linkid, msg));
130 }
131
132 int
libvarpd_overlay_restore(varpd_instance_t * inst)133 libvarpd_overlay_restore(varpd_instance_t *inst)
134 {
135 overlay_targ_id_t otid;
136 varpd_impl_t *vip = inst->vri_impl;
137
138 otid.otid_linkid = inst->vri_linkid;
139 if (ioctl(vip->vdi_overlayfd, OVERLAY_TARG_RESTORE, &otid) != 0)
140 return (errno);
141 return (0);
142 }
143
144 int
libvarpd_overlay_packet(varpd_impl_t * vip,const overlay_targ_lookup_t * otl,void * buf,size_t * buflen)145 libvarpd_overlay_packet(varpd_impl_t *vip, const overlay_targ_lookup_t *otl,
146 void *buf, size_t *buflen)
147 {
148 int ret;
149 overlay_targ_pkt_t otp;
150
151 otp.otp_linkid = UINT64_MAX;
152 otp.otp_reqid = otl->otl_reqid;
153 otp.otp_size = *buflen;
154 otp.otp_buf = buf;
155
156 do {
157 ret = ioctl(vip->vdi_overlayfd, OVERLAY_TARG_PKT, &otp);
158 } while (ret != 0 && errno == EINTR);
159 if (ret != 0 && errno == EFAULT)
160 libvarpd_panic("OVERLAY_TARG_PKT ioctl efault");
161 else if (ret != 0)
162 ret = errno;
163
164 if (ret == 0)
165 *buflen = otp.otp_size;
166
167 return (ret);
168 }
169
170 static int
libvarpd_overlay_inject_common(varpd_impl_t * vip,varpd_instance_t * inst,const overlay_targ_lookup_t * otl,void * buf,size_t buflen,int cmd)171 libvarpd_overlay_inject_common(varpd_impl_t *vip, varpd_instance_t *inst,
172 const overlay_targ_lookup_t *otl, void *buf, size_t buflen, int cmd)
173 {
174 int ret;
175 overlay_targ_pkt_t otp;
176
177 if (otl == NULL) {
178 otp.otp_linkid = inst->vri_linkid;
179 otp.otp_reqid = 0;
180 } else {
181 otp.otp_linkid = UINT64_MAX;
182 otp.otp_reqid = otl->otl_reqid;
183 }
184 otp.otp_size = buflen;
185 otp.otp_buf = buf;
186
187 do {
188 ret = ioctl(vip->vdi_overlayfd, cmd, &otp);
189 } while (ret != 0 && errno == EINTR);
190 if (ret != 0 && errno == EFAULT)
191 libvarpd_panic("overlay_inject_common ioctl EFAULT");
192 else if (ret != 0)
193 ret = errno;
194
195 return (ret);
196 }
197
198 int
libvarpd_overlay_inject(varpd_impl_t * vip,const overlay_targ_lookup_t * otl,void * buf,size_t buflen)199 libvarpd_overlay_inject(varpd_impl_t *vip, const overlay_targ_lookup_t *otl,
200 void *buf, size_t buflen)
201 {
202 return (libvarpd_overlay_inject_common(vip, NULL, otl, buf, buflen,
203 OVERLAY_TARG_INJECT));
204 }
205
206 int
libvarpd_overlay_instance_inject(varpd_instance_t * inst,void * buf,size_t buflen)207 libvarpd_overlay_instance_inject(varpd_instance_t *inst, void *buf,
208 size_t buflen)
209 {
210 return (libvarpd_overlay_inject_common(inst->vri_impl, inst, NULL, buf,
211 buflen, OVERLAY_TARG_INJECT));
212 }
213
214 int
libvarpd_overlay_resend(varpd_impl_t * vip,const overlay_targ_lookup_t * otl,void * buf,size_t buflen)215 libvarpd_overlay_resend(varpd_impl_t *vip, const overlay_targ_lookup_t *otl,
216 void *buf, size_t buflen)
217 {
218 return (libvarpd_overlay_inject_common(vip, NULL, otl, buf, buflen,
219 OVERLAY_TARG_RESEND));
220 }
221
222 static void
libvarpd_overlay_lookup_reply(varpd_impl_t * vip,const overlay_targ_lookup_t * otl,overlay_targ_resp_t * otr,int cmd)223 libvarpd_overlay_lookup_reply(varpd_impl_t *vip,
224 const overlay_targ_lookup_t *otl, overlay_targ_resp_t *otr, int cmd)
225 {
226 int ret;
227
228 otr->otr_reqid = otl->otl_reqid;
229 do {
230 ret = ioctl(vip->vdi_overlayfd, cmd, otr);
231 } while (ret != 0 && errno == EINTR);
232
233 /*
234 * The only errors that should cause us to end up here are due to
235 * programmer errors. Arguably the EINVAL case indicates that something
236 * is a bit off; however, at this time we don't opt to kill varpd.
237 */
238 if (ret != 0 && errno != EINVAL)
239 libvarpd_panic("received bad errno from lookup_reply "
240 "(cmd %d): %d\n", cmd, errno);
241 }
242
243 static void
libvarpd_overlay_lookup_handle(varpd_impl_t * vip)244 libvarpd_overlay_lookup_handle(varpd_impl_t *vip)
245 {
246 int ret;
247 varpd_query_t *vqp;
248 overlay_targ_lookup_t *otl;
249 overlay_targ_resp_t *otr;
250 varpd_instance_t *inst;
251
252 vqp = umem_cache_alloc(vip->vdi_qcache, UMEM_DEFAULT);
253 otl = &vqp->vq_lookup;
254 otr = &vqp->vq_response;
255 /*
256 * abort doesn't really help here that much, maybe we can instead try
257 * and for a reap or something?
258 */
259 if (vqp == NULL)
260 libvarpd_panic("failed to allocate memory for lookup "
261 "handle..., we should not panic()");
262 ret = ioctl(vip->vdi_overlayfd, OVERLAY_TARG_LOOKUP, otl);
263 if (ret != 0 && errno != ETIME && errno != EINTR)
264 libvarpd_panic("received bad errno from OVERLAY_TARG_LOOKUP: "
265 "%d", errno);
266
267 if (ret != 0) {
268 umem_cache_free(vip->vdi_qcache, vqp);
269 return;
270 }
271
272 inst = (varpd_instance_t *)libvarpd_instance_lookup(
273 (varpd_handle_t *)vip, otl->otl_varpdid);
274 if (inst == NULL) {
275 libvarpd_overlay_lookup_reply(vip, otl, otr,
276 OVERLAY_TARG_DROP);
277 umem_cache_free(vip->vdi_qcache, vqp);
278 return;
279 }
280 vqp->vq_instance = inst;
281
282 inst->vri_plugin->vpp_ops->vpo_lookup(inst->vri_private,
283 (varpd_query_handle_t *)vqp, otl, &otr->otr_answer);
284 }
285
286 /* Use "void *" for vhp here to play nicely with thr_create(). */
287 void *
libvarpd_overlay_lookup_run(void * vhp)288 libvarpd_overlay_lookup_run(void *vhp)
289 {
290 varpd_impl_t *vip = (varpd_impl_t *)vhp;
291
292 mutex_enter(&vip->vdi_lock);
293 if (vip->vdi_lthr_quiesce == B_TRUE) {
294 mutex_exit(&vip->vdi_lock);
295 return (NULL);
296 }
297 vip->vdi_lthr_count++;
298
299 for (;;) {
300 mutex_exit(&vip->vdi_lock);
301 libvarpd_overlay_lookup_handle(vip);
302 mutex_enter(&vip->vdi_lock);
303 if (vip->vdi_lthr_quiesce == B_TRUE)
304 break;
305 }
306 assert(vip->vdi_lthr_count > 0);
307 vip->vdi_lthr_count--;
308 (void) cond_signal(&vip->vdi_lthr_cv);
309 mutex_exit(&vip->vdi_lock);
310 return (NULL);
311 }
312
313 void
libvarpd_overlay_lookup_quiesce(varpd_handle_t * vhp)314 libvarpd_overlay_lookup_quiesce(varpd_handle_t *vhp)
315 {
316 varpd_impl_t *vip = (varpd_impl_t *)vhp;
317
318 mutex_enter(&vip->vdi_lock);
319 if (vip->vdi_lthr_count == 0) {
320 mutex_exit(&vip->vdi_lock);
321 return;
322 }
323 vip->vdi_lthr_quiesce = B_TRUE;
324 while (vip->vdi_lthr_count > 0)
325 (void) cond_wait(&vip->vdi_lthr_cv, &vip->vdi_lock);
326 vip->vdi_lthr_quiesce = B_FALSE;
327 mutex_exit(&vip->vdi_lock);
328 }
329
330 int
libvarpd_overlay_iter(varpd_impl_t * vip,libvarpd_overlay_iter_f func,void * arg)331 libvarpd_overlay_iter(varpd_impl_t *vip, libvarpd_overlay_iter_f func,
332 void *arg)
333 {
334 uint32_t curents = 0, i;
335 size_t size;
336 overlay_targ_list_t *otl;
337
338 for (;;) {
339 size = sizeof (overlay_targ_list_t) +
340 sizeof (uint32_t) * curents;
341 otl = umem_alloc(size, UMEM_DEFAULT);
342 if (otl == NULL)
343 return (ENOMEM);
344
345 otl->otl_nents = curents;
346 if (ioctl(vip->vdi_overlayfd, OVERLAY_TARG_LIST, otl) != 0) {
347 if (errno == EFAULT)
348 libvarpd_panic("OVERLAY_TARG_LIST ioctl "
349 "efault");
350 umem_free(otl, size);
351 if (errno == EINTR)
352 continue;
353 else
354 return (errno);
355 }
356
357 if (otl->otl_nents == curents)
358 break;
359
360 curents = otl->otl_nents;
361 umem_free(otl, size);
362 }
363
364 for (i = 0; i < otl->otl_nents; i++) {
365 if (func(vip, otl->otl_ents[i], arg) != 0)
366 break;
367 }
368 umem_free(otl, size);
369 return (0);
370 }
371
372 int
libvarpd_overlay_cache_flush(varpd_instance_t * inst)373 libvarpd_overlay_cache_flush(varpd_instance_t *inst)
374 {
375 int ret;
376 overlay_targ_cache_t cache;
377 varpd_impl_t *vip = inst->vri_impl;
378
379 bzero(&cache, sizeof (overlay_targ_cache_t));
380 cache.otc_linkid = inst->vri_linkid;
381
382 ret = ioctl(vip->vdi_overlayfd, OVERLAY_TARG_CACHE_FLUSH, &cache);
383 if (ret != 0 && errno == EFAULT)
384 libvarpd_panic("OVERLAY_TARG_CACHE_FLUSH ioctl efault");
385 else if (ret != 0)
386 ret = errno;
387
388 return (ret);
389 }
390
391 int
libvarpd_overlay_cache_delete(varpd_instance_t * inst,const uint8_t * key)392 libvarpd_overlay_cache_delete(varpd_instance_t *inst, const uint8_t *key)
393 {
394 int ret;
395 overlay_targ_cache_t cache;
396 varpd_impl_t *vip = inst->vri_impl;
397
398 bzero(&cache, sizeof (overlay_targ_cache_t));
399 cache.otc_linkid = inst->vri_linkid;
400 bcopy(key, cache.otc_entry.otce_mac, ETHERADDRL);
401
402 ret = ioctl(vip->vdi_overlayfd, OVERLAY_TARG_CACHE_REMOVE, &cache);
403 if (ret != 0 && errno == EFAULT)
404 libvarpd_panic("OVERLAY_TARG_CACHE_REMOVE ioctl efault");
405 else if (ret != 0)
406 ret = errno;
407
408 return (ret);
409
410 }
411
412 int
libvarpd_overlay_cache_get(varpd_instance_t * inst,const uint8_t * key,varpd_client_cache_entry_t * entry)413 libvarpd_overlay_cache_get(varpd_instance_t *inst, const uint8_t *key,
414 varpd_client_cache_entry_t *entry)
415 {
416 int ret;
417 overlay_targ_cache_t cache;
418 varpd_impl_t *vip = inst->vri_impl;
419
420 bzero(&cache, sizeof (overlay_targ_cache_t));
421 cache.otc_linkid = inst->vri_linkid;
422 bcopy(key, cache.otc_entry.otce_mac, ETHERADDRL);
423
424 ret = ioctl(vip->vdi_overlayfd, OVERLAY_TARG_CACHE_GET, &cache);
425 if (ret != 0 && errno == EFAULT)
426 libvarpd_panic("OVERLAY_TARG_CACHE_GET ioctl efault");
427 else if (ret != 0)
428 return (errno);
429
430 bcopy(cache.otc_entry.otce_dest.otp_mac, &entry->vcp_mac, ETHERADDRL);
431 entry->vcp_flags = cache.otc_entry.otce_flags;
432 entry->vcp_ip = cache.otc_entry.otce_dest.otp_ip;
433 entry->vcp_port = cache.otc_entry.otce_dest.otp_port;
434
435 return (0);
436 }
437
438 int
libvarpd_overlay_cache_set(varpd_instance_t * inst,const uint8_t * key,const varpd_client_cache_entry_t * entry)439 libvarpd_overlay_cache_set(varpd_instance_t *inst, const uint8_t *key,
440 const varpd_client_cache_entry_t *entry)
441 {
442 int ret;
443 overlay_targ_cache_t cache;
444 varpd_impl_t *vip = inst->vri_impl;
445
446 bzero(&cache, sizeof (overlay_targ_cache_t));
447 cache.otc_linkid = inst->vri_linkid;
448 bcopy(key, cache.otc_entry.otce_mac, ETHERADDRL);
449 bcopy(&entry->vcp_mac, cache.otc_entry.otce_dest.otp_mac, ETHERADDRL);
450 cache.otc_entry.otce_flags = entry->vcp_flags;
451 cache.otc_entry.otce_dest.otp_ip = entry->vcp_ip;
452 cache.otc_entry.otce_dest.otp_port = entry->vcp_port;
453
454 ret = ioctl(vip->vdi_overlayfd, OVERLAY_TARG_CACHE_SET, &cache);
455 if (ret != 0 && errno == EFAULT)
456 libvarpd_panic("OVERLAY_TARG_CACHE_SET ioctl efault");
457 else if (ret != 0)
458 return (errno);
459
460 return (0);
461 }
462
463 int
libvarpd_overlay_cache_walk_fill(varpd_instance_t * inst,uint64_t * markerp,uint64_t * countp,overlay_targ_cache_entry_t * ents)464 libvarpd_overlay_cache_walk_fill(varpd_instance_t *inst, uint64_t *markerp,
465 uint64_t *countp, overlay_targ_cache_entry_t *ents)
466 {
467 int ret;
468 size_t asize;
469 overlay_targ_cache_iter_t *iter;
470 varpd_impl_t *vip = inst->vri_impl;
471
472 if (*countp > 200)
473 return (E2BIG);
474
475 asize = sizeof (overlay_targ_cache_iter_t) +
476 *countp * sizeof (overlay_targ_cache_entry_t);
477 iter = umem_alloc(asize, UMEM_DEFAULT);
478 if (iter == NULL)
479 return (ENOMEM);
480
481 iter->otci_linkid = inst->vri_linkid;
482 iter->otci_marker = *markerp;
483 iter->otci_count = *countp;
484 ret = ioctl(vip->vdi_overlayfd, OVERLAY_TARG_CACHE_ITER, iter);
485 if (ret != 0 && errno == EFAULT)
486 libvarpd_panic("OVERLAY_TARG_CACHE_ITER ioctl efault");
487 else if (ret != 0) {
488 ret = errno;
489 goto out;
490 }
491
492 *markerp = iter->otci_marker;
493 *countp = iter->otci_count;
494 bcopy(iter->otci_ents, ents,
495 *countp * sizeof (overlay_targ_cache_entry_t));
496 out:
497 umem_free(iter, asize);
498 return (ret);
499 }
500
501 void
libvarpd_plugin_query_reply(varpd_query_handle_t * vqh,int action)502 libvarpd_plugin_query_reply(varpd_query_handle_t *vqh, int action)
503 {
504 varpd_query_t *vqp = (varpd_query_t *)vqh;
505
506 if (vqp == NULL)
507 libvarpd_panic("unknown plugin passed invalid "
508 "varpd_query_handle_t");
509
510 if (action == VARPD_LOOKUP_DROP)
511 libvarpd_overlay_lookup_reply(vqp->vq_instance->vri_impl,
512 &vqp->vq_lookup, &vqp->vq_response, OVERLAY_TARG_DROP);
513 else if (action == VARPD_LOOKUP_OK)
514 libvarpd_overlay_lookup_reply(vqp->vq_instance->vri_impl,
515 &vqp->vq_lookup, &vqp->vq_response, OVERLAY_TARG_RESPOND);
516 else
517 libvarpd_panic("plugin %s passed in an invalid action: %d",
518 vqp->vq_instance->vri_plugin->vpp_name, action);
519
520 umem_cache_free(vqp->vq_instance->vri_impl->vdi_qcache, vqp);
521 }
522
523 void
libvarpd_inject_varp(varpd_provider_handle_t * vph,const uint8_t * mac,const overlay_target_point_t * otp)524 libvarpd_inject_varp(varpd_provider_handle_t *vph, const uint8_t *mac,
525 const overlay_target_point_t *otp)
526 {
527 int ret;
528 overlay_targ_cache_t otc;
529 varpd_instance_t *inst = (varpd_instance_t *)vph;
530 varpd_impl_t *vip = inst->vri_impl;
531
532 if (otp == NULL) {
533 (void) libvarpd_overlay_cache_delete(inst, mac);
534 return;
535 }
536
537 otc.otc_linkid = inst->vri_linkid;
538 otc.otc_entry.otce_flags = 0;
539 bcopy(mac, otc.otc_entry.otce_mac, ETHERADDRL);
540 bcopy(otp, &otc.otc_entry.otce_dest, sizeof (overlay_target_point_t));
541
542 ret = ioctl(vip->vdi_overlayfd, OVERLAY_TARG_CACHE_SET, &otc);
543 if (ret != 0) {
544 switch (errno) {
545 case EBADF:
546 case EFAULT:
547 case ENOTSUP:
548 libvarpd_panic("received bad errno from "
549 "OVERLAY_TARG_CACHE_SET: %d", errno);
550 default:
551 break;
552 }
553 }
554 }
555
556 void
libvarpd_fma_degrade(varpd_provider_handle_t * vph,const char * msg)557 libvarpd_fma_degrade(varpd_provider_handle_t *vph, const char *msg)
558 {
559 int ret;
560 varpd_instance_t *inst = (varpd_instance_t *)vph;
561
562 ret = libvarpd_overlay_degrade(inst, msg);
563 switch (ret) {
564 case ENOENT:
565 case EFAULT:
566 libvarpd_panic("received bad errno from degrade ioctl: %d",
567 errno);
568 default:
569 break;
570 }
571 }
572
573 void
libvarpd_fma_restore(varpd_provider_handle_t * vph)574 libvarpd_fma_restore(varpd_provider_handle_t *vph)
575 {
576 int ret;
577 varpd_instance_t *inst = (varpd_instance_t *)vph;
578
579 ret = libvarpd_overlay_restore(inst);
580 switch (ret) {
581 case ENOENT:
582 case EFAULT:
583 libvarpd_panic("received bad errno from restore ioctl: %d",
584 errno);
585 default:
586 break;
587 }
588 }
589