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