xref: /illumos-gate/usr/src/lib/varpd/libvarpd/common/libvarpd_overlay.c (revision dd72704bd9e794056c558153663c739e2012d721)
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 *
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
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
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
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
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
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
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
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
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
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
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
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