344 #include <netinet/in.h>
345 #include <arpa/inet.h>
346 #include <libnvpair.h>
347 #include <strings.h>
348 #include <string.h>
349 #include <assert.h>
350 #include <unistd.h>
351
352 #include <libvarpd_provider.h>
353 #include "libvarpd_svp.h"
354
355 bunyan_logger_t *svp_bunyan;
356 static int svp_defport = 1296;
357 static int svp_defuport = 1339;
358 static umem_cache_t *svp_lookup_cache;
359
360 typedef enum svp_lookup_type {
361 SVP_L_UNKNOWN = 0x0,
362 SVP_L_VL2 = 0x1,
363 SVP_L_VL3 = 0x2,
364 SVP_L_RVL3 = 0x3
365 } svp_lookup_type_t;
366
367 typedef struct svp_lookup {
368 int svl_type;
369 union {
370 struct svl_lookup_vl2 {
371 varpd_query_handle_t *svl_handle;
372 overlay_target_point_t *svl_point;
373 } svl_vl2;
374 struct svl_lookup_vl3 {
375 varpd_arp_handle_t *svl_vah;
376 uint8_t *svl_out;
377 } svl_vl3;
378 struct svl_lookup_rvl3 {
379 varpd_query_handle_t *svl_handle;
380 overlay_target_point_t *svl_point;
381 overlay_target_route_t *svl_route;
382 } svl_rvl3;
383 } svl_u;
384 svp_query_t svl_query;
385 } svp_lookup_t;
386
387 static const char *varpd_svp_props[] = {
388 "svp/host",
389 "svp/port",
390 "svp/underlay_ip",
391 "svp/underlay_port",
392 "svp/dcid",
393 "svp/router_mac"
394 };
395
396 static const uint8_t svp_bcast[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
397
398 int
399 svp_comparator(const void *l, const void *r)
400 {
401 const svp_t *ls = l;
402 const svp_t *rs = r;
403
404 if (ls->svp_vid > rs->svp_vid)
405 return (1);
406 if (ls->svp_vid < rs->svp_vid)
407 return (-1);
408 return (0);
409 }
410
411 static void
412 svp_vl2_lookup_cb(svp_t *svp, svp_status_t status, const struct in6_addr *uip,
413 const uint16_t uport, void *arg)
420
421 if (status != SVP_S_OK) {
422 libvarpd_plugin_query_reply(svl->svl_u.svl_vl2.svl_handle,
423 VARPD_LOOKUP_DROP);
424 umem_cache_free(svp_lookup_cache, svl);
425 return;
426 }
427
428 otp = svl->svl_u.svl_vl2.svl_point;
429 bcopy(uip, &otp->otp_ip, sizeof (struct in6_addr));
430 otp->otp_port = uport;
431 libvarpd_plugin_query_reply(svl->svl_u.svl_vl2.svl_handle,
432 VARPD_LOOKUP_OK);
433 umem_cache_free(svp_lookup_cache, svl);
434 }
435
436 static void
437 svp_vl3_lookup_cb(svp_t *svp, svp_status_t status, const uint8_t *vl2mac,
438 const struct in6_addr *uip, const uint16_t uport, void *arg)
439 {
440 overlay_target_point_t point;
441 svp_lookup_t *svl = arg;
442
443 assert(svp != NULL);
444 assert(svl != NULL);
445
446 if (status != SVP_S_OK) {
447 libvarpd_plugin_arp_reply(svl->svl_u.svl_vl3.svl_vah,
448 VARPD_LOOKUP_DROP);
449 umem_cache_free(svp_lookup_cache, svl);
450 return;
451 }
452
453 /* Inject the L2 mapping before the L3 */
454 bcopy(uip, &point.otp_ip, sizeof (struct in6_addr));
455 point.otp_port = uport;
456 libvarpd_inject_varp(svp->svp_hdl, vl2mac, &point);
457
458 bcopy(vl2mac, svl->svl_u.svl_vl3.svl_out, ETHERADDRL);
459 libvarpd_plugin_arp_reply(svl->svl_u.svl_vl3.svl_vah,
460 VARPD_LOOKUP_OK);
461 umem_cache_free(svp_lookup_cache, svl);
462 }
463
464 static void
465 svp_vl2_invalidate_cb(svp_t *svp, const uint8_t *vl2mac)
466 {
467 libvarpd_inject_varp(svp->svp_hdl, vl2mac, NULL);
468 }
469
470 static void
471 svp_vl3_inject_cb(svp_t *svp, const uint16_t vlan, const struct in6_addr *vl3ip,
472 const uint8_t *vl2mac, const uint8_t *targmac)
473 {
474 struct in_addr v4;
475
476 /*
477 * At the moment we don't support any IPv6 related log entries, this
478 * will change soon as we develop a bit more of the IPv6 related
479 * infrastructure so we can properly test the injection.
480 */
481 if (IN6_IS_ADDR_V4MAPPED(vl3ip) == 0) {
482 return;
483 } else {
484 IN6_V4MAPPED_TO_INADDR(vl3ip, &v4);
485 if (targmac == NULL)
486 targmac = svp_bcast;
487 libvarpd_inject_arp(svp->svp_hdl, vlan, vl2mac, &v4, targmac);
488 }
489 }
490
491 /* ARGSUSED */
492 static void
493 svp_shootdown_cb(svp_t *svp, const uint8_t *vl2mac, const struct in6_addr *uip,
494 const uint16_t uport)
495 {
496 /*
497 * We should probably do a conditional invlaidation here.
498 */
499 libvarpd_inject_varp(svp->svp_hdl, vl2mac, NULL);
500 }
501
502 static void
503 svp_rvl3_lookup_cb(svp_t *svp, svp_status_t status, /* XXX KEBE SAYS MORE */
504 void *arg)
505 {
506 svp_lookup_t *svl = arg;
507 overlay_target_point_t *otp;
508 overlay_target_route_t *otr;
509
510 if (status != SVP_S_OK) {
511 libvarpd_plugin_query_reply(svl->svl_u.svl_rvl3.svl_handle,
512 VARPD_LOOKUP_DROP);
513 umem_cache_free(svp_lookup_cache, svl);
514 return;
515 }
516
517 otp = svl->svl_u.svl_rvl3.svl_point;
518 otr = svl->svl_u.svl_rvl3.svl_route;
519 /* XXX KEBE SAYS FILL ME IN! */
520
521 libvarpd_plugin_query_reply(svl->svl_u.svl_rvl3.svl_handle,
522 VARPD_LOOKUP_OK);
523 umem_cache_free(svp_lookup_cache, svl);
524 }
525
526 static svp_cb_t svp_defops = {
527 svp_vl2_lookup_cb,
528 svp_vl3_lookup_cb,
529 svp_vl2_invalidate_cb,
530 svp_vl3_inject_cb,
531 svp_shootdown_cb,
532 svp_rvl3_lookup_cb,
533 };
534
535 static boolean_t
536 varpd_svp_valid_dest(overlay_plugin_dest_t dest)
537 {
538 if (dest != (OVERLAY_PLUGIN_D_IP | OVERLAY_PLUGIN_D_PORT))
539 return (B_FALSE);
540
541 return (B_TRUE);
542 }
543
544 static int
545 varpd_svp_create(varpd_provider_handle_t *hdl, void **outp,
546 overlay_plugin_dest_t dest)
547 {
548 int ret;
549 svp_t *svp;
550
551 if (varpd_svp_valid_dest(dest) == B_FALSE)
552 return (ENOTSUP);
620 }
621
622 static void
623 varpd_svp_lookup_l3(svp_t *svp, varpd_query_handle_t *vqh,
624 const overlay_targ_lookup_t *otl, overlay_target_point_t *otp,
625 overlay_target_route_t *otr)
626 {
627 svp_lookup_t *slp;
628 uint32_t type;
629 const struct in6_addr *src = &otl->otl_addru.otlu_l3.otl3_srcip,
630 *dst = &otl->otl_addru.otlu_l3.otl3_dstip;
631
632 /*
633 * otl is an L3 request, so we have src/dst IPs for the inner packet.
634 * We also have the vlan.
635 *
636 * Assume kernel's overlay module is caching well, so we are directly
637 * going to query (i.e. no caching up here of actual destinations).
638 *
639 * Our existing remote sever (svp_remote), but with the new message
640 * SVP_R_REMOTE_VL3_REQ. Our naming of these functions already has
641 * "remote" in it, but we'll use "rvl3" instead of "vl3".
642 */
643
644 /* XXX KEBE SAYS DO SOME otl verification too... */
645 if (IN6_IS_ADDR_V4MAPPED(src)) {
646 if (!IN6_IS_ADDR_V4MAPPED(dst)) {
647 libvarpd_plugin_query_reply(vqh, VARPD_LOOKUP_DROP);
648 return;
649 }
650 type = SVP_VL3_IP;
651 } else {
652 if (IN6_IS_ADDR_V4MAPPED(dst)) {
653 libvarpd_plugin_query_reply(vqh, VARPD_LOOKUP_DROP);
654 return;
655 }
656 type = SVP_VL3_IPV6;
657 }
658
659 slp = umem_cache_alloc(svp_lookup_cache, UMEM_DEFAULT);
660 if (slp == NULL) {
661 libvarpd_plugin_query_reply(vqh, VARPD_LOOKUP_DROP);
662 return;
663 }
664
665 slp->svl_type = SVP_L_RVL3;
666 slp->svl_u.svl_rvl3.svl_handle = vqh;
667 slp->svl_u.svl_rvl3.svl_point = otp;
668 slp->svl_u.svl_rvl3.svl_route = otr;
669
670 /* XXX KEBE SAYS FILL IN ARGS PROPERLY... */
671 svp_remote_rvl3_lookup(svp, &slp->svl_query, src, dst, type,
672 otl->otl_vnetid, (uint16_t)otl->otl_vlan, slp);
673 }
674
675 static void
676 varpd_svp_lookup(void *arg, varpd_query_handle_t *vqh,
677 const overlay_targ_lookup_t *otl, overlay_target_point_t *otp,
678 overlay_target_route_t *otr)
679 {
680 svp_lookup_t *slp;
681 svp_t *svp = arg;
682
683 /*
684 * Shuffle off L3 lookups to their own codepath.
685 */
686 if (otl->otl_l3req) {
687 varpd_svp_lookup_l3(svp, vqh, otl, otp, otr);
688 return;
689 }
690 /*
691 * At this point, the traditional overlay_target_point_t is all that
783 break;
784 case 3:
785 /* svp/underlay_port */
786 libvarpd_prop_set_name(vph, varpd_svp_props[3]);
787 libvarpd_prop_set_prot(vph, OVERLAY_PROP_PERM_RRW);
788 libvarpd_prop_set_type(vph, OVERLAY_PROP_T_UINT);
789 (void) libvarpd_prop_set_default(vph, &svp_defuport,
790 sizeof (svp_defuport));
791 libvarpd_prop_set_range_uint32(vph, 1, UINT16_MAX);
792 break;
793 case 4:
794 /* svp/dcid */
795 libvarpd_prop_set_name(vph, varpd_svp_props[4]);
796 libvarpd_prop_set_prot(vph, OVERLAY_PROP_PERM_RRW);
797 libvarpd_prop_set_type(vph, OVERLAY_PROP_T_UINT);
798 libvarpd_prop_set_nodefault(vph);
799 /* XXX KEBE ASKS should I just set high to UINT32_MAX? */
800 libvarpd_prop_set_range_uint32(vph, 1, UINT32_MAX - 1);
801 break;
802 case 5:
803 /* svp/router_mac */
804 libvarpd_prop_set_name(vph, varpd_svp_props[5]);
805 libvarpd_prop_set_prot(vph, OVERLAY_PROP_PERM_RRW);
806 libvarpd_prop_set_type(vph, OVERLAY_PROP_T_ETHER);
807 libvarpd_prop_set_nodefault(vph);
808 break;
809 default:
810 return (EINVAL);
811 }
812 return (0);
813 }
814
815 static int
816 varpd_svp_getprop(void *arg, const char *pname, void *buf, uint32_t *sizep)
817 {
818 svp_t *svp = arg;
819
820 /* svp/host */
821 if (strcmp(pname, varpd_svp_props[0]) == 0) {
822 size_t len;
823
894 /* svp/dcid */
895 if (strcmp(pname, varpd_svp_props[4]) == 0) {
896 uint64_t val;
897
898 if (*sizep < sizeof (uint64_t))
899 return (EOVERFLOW);
900
901 mutex_enter(&svp->svp_lock);
902 if (svp->svp_uport == 0) {
903 *sizep = 0;
904 } else {
905 val = svp->svp_dcid;
906 bcopy(&val, buf, sizeof (uint64_t));
907 *sizep = sizeof (uint64_t);
908 }
909
910 mutex_exit(&svp->svp_lock);
911 return (0);
912 }
913
914 /* svp/router_mac */
915 if (strcmp(pname, varpd_svp_props[5]) == 0) {
916 if (*sizep < ETHERADDRL)
917 return (EOVERFLOW);
918 mutex_enter(&svp->svp_lock);
919
920 if (ether_is_zero(&svp->svp_router_mac)) {
921 *sizep = 0;
922 } else {
923 bcopy(&svp->svp_router_mac, buf, ETHERADDRL);
924 *sizep = ETHERADDRL;
925 }
926
927 mutex_exit(&svp->svp_lock);
928 return (0);
929 }
930 return (EINVAL);
931 }
932
933 static int
934 varpd_svp_setprop(void *arg, const char *pname, const void *buf,
935 const uint32_t size)
936 {
937 svp_t *svp = arg;
938
939 /* svp/host */
940 if (strcmp(pname, varpd_svp_props[0]) == 0) {
941 char *dup;
942 dup = umem_alloc(size, UMEM_DEFAULT);
943 (void) strlcpy(dup, buf, size);
1012 return (0);
1013 }
1014
1015 /* svp/dcid */
1016 if (strcmp(pname, varpd_svp_props[4]) == 0) {
1017 const uint64_t *valp = buf;
1018 if (size < sizeof (uint64_t))
1019 return (EOVERFLOW);
1020
1021 /* XXX KEBE ASKS, use UINT32_MAX instead? */
1022 if (*valp == 0 || *valp > UINT32_MAX - 1)
1023 return (EINVAL);
1024
1025 mutex_enter(&svp->svp_lock);
1026 svp->svp_dcid = (uint32_t)*valp;
1027 mutex_exit(&svp->svp_lock);
1028
1029 return (0);
1030 }
1031
1032 /* svp/router_mac */
1033 if (strcmp(pname, varpd_svp_props[5]) == 0) {
1034 if (size < ETHERADDRL)
1035 return (EOVERFLOW);
1036 mutex_enter(&svp->svp_lock);
1037 bcopy(buf, &svp->svp_router_mac, ETHERADDRL);
1038 mutex_exit(&svp->svp_lock);
1039 return (0);
1040 }
1041
1042 return (EINVAL);
1043 }
1044
1045 static int
1046 varpd_svp_save(void *arg, nvlist_t *nvp)
1047 {
1048 int ret;
1049 svp_t *svp = arg;
1050
1051 mutex_enter(&svp->svp_lock);
1052 /* svp/host */
1053 if (svp->svp_host != NULL) {
1054 if ((ret = nvlist_add_string(nvp, varpd_svp_props[0],
1055 svp->svp_host)) != 0) {
1056 mutex_exit(&svp->svp_lock);
1057 return (ret);
1084 }
1085
1086 /* svp/underlay_port */
1087 if (svp->svp_uport != 0) {
1088 if ((ret = nvlist_add_uint16(nvp, varpd_svp_props[3],
1089 svp->svp_uport)) != 0) {
1090 mutex_exit(&svp->svp_lock);
1091 return (ret);
1092 }
1093 }
1094
1095 /* svp/dcid */
1096 if (svp->svp_dcid != 0) {
1097 if ((ret = nvlist_add_uint32(nvp, varpd_svp_props[4],
1098 svp->svp_dcid)) != 0) {
1099 mutex_exit(&svp->svp_lock);
1100 return (ret);
1101 }
1102 }
1103
1104 /* svp/router_mac */
1105 if (!ether_is_zero(&svp->svp_router_mac)) {
1106 char buf[ETHERADDRSTRL];
1107
1108 /* XXX KEBE SAYS See underlay_ip... */
1109 if (ether_ntoa_r(&svp->svp_router_mac, buf) == NULL) {
1110 libvarpd_panic("unexpected ether_ntoa_r failure: %d",
1111 errno);
1112 }
1113
1114 if ((ret = nvlist_add_string(nvp, varpd_svp_props[5],
1115 buf)) != 0) {
1116 mutex_exit(&svp->svp_lock);
1117 return (ret);
1118 }
1119 }
1120
1121 mutex_exit(&svp->svp_lock);
1122 return (0);
1123 }
1124
1125 static int
1126 varpd_svp_restore(nvlist_t *nvp, varpd_provider_handle_t *hdl,
1127 overlay_plugin_dest_t dest, void **outp)
1128 {
1129 int ret;
1186 /* svp/underlay_port */
1187 if ((ret = nvlist_lookup_uint16(nvp, varpd_svp_props[3],
1188 &svp->svp_uport)) != 0) {
1189 if (ret != ENOENT) {
1190 varpd_svp_destroy(svp);
1191 return (ret);
1192 }
1193 svp->svp_uport = 0;
1194 }
1195
1196 /* svp/dcid */
1197 if ((ret = nvlist_lookup_uint32(nvp, varpd_svp_props[4],
1198 &svp->svp_dcid)) != 0) {
1199 if (ret != ENOENT) {
1200 varpd_svp_destroy(svp);
1201 return (ret);
1202 }
1203 svp->svp_dcid = 0;
1204 }
1205
1206 /* svp/router_mac */
1207 if ((ret = nvlist_lookup_string(nvp, varpd_svp_props[5],
1208 ðerstr)) != 0) {
1209 if (ret != ENOENT) {
1210 varpd_svp_destroy(svp);
1211 return (ret);
1212 }
1213 bzero(&svp->svp_router_mac, ETHERADDRL);
1214 } else if (ether_aton_r(etherstr, &svp->svp_router_mac) == NULL) {
1215 libvarpd_panic("unexpected ether_aton_r failure: %d", errno);
1216 }
1217
1218 svp->svp_hdl = hdl;
1219 *outp = svp;
1220 return (0);
1221 }
1222
1223 static void
1224 varpd_svp_arp(void *arg, varpd_arp_handle_t *vah, int type,
1225 const struct sockaddr *sock, uint8_t *out)
1226 {
1227 svp_t *svp = arg;
1228 svp_lookup_t *svl;
1229
1230 if (type != VARPD_QTYPE_ETHERNET) {
1231 libvarpd_plugin_arp_reply(vah, VARPD_LOOKUP_DROP);
1232 return;
1233 }
1234
|
344 #include <netinet/in.h>
345 #include <arpa/inet.h>
346 #include <libnvpair.h>
347 #include <strings.h>
348 #include <string.h>
349 #include <assert.h>
350 #include <unistd.h>
351
352 #include <libvarpd_provider.h>
353 #include "libvarpd_svp.h"
354
355 bunyan_logger_t *svp_bunyan;
356 static int svp_defport = 1296;
357 static int svp_defuport = 1339;
358 static umem_cache_t *svp_lookup_cache;
359
360 typedef enum svp_lookup_type {
361 SVP_L_UNKNOWN = 0x0,
362 SVP_L_VL2 = 0x1,
363 SVP_L_VL3 = 0x2,
364 SVP_L_ROUTE = 0x3
365 } svp_lookup_type_t;
366
367 typedef struct svp_lookup {
368 int svl_type;
369 union {
370 struct svl_lookup_vl2 {
371 varpd_query_handle_t *svl_handle;
372 overlay_target_point_t *svl_point;
373 } svl_vl2;
374 struct svl_lookup_vl3 {
375 varpd_arp_handle_t *svl_vah;
376 uint8_t *svl_out;
377 } svl_vl3;
378 struct svl_lookup_route {
379 varpd_query_handle_t *svl_handle;
380 overlay_target_point_t *svl_point;
381 overlay_target_route_t *svl_route;
382 } svl_route;
383 } svl_u;
384 svp_query_t svl_query;
385 } svp_lookup_t;
386
387 static const char *varpd_svp_props[] = {
388 "svp/host",
389 "svp/port",
390 "svp/underlay_ip",
391 "svp/underlay_port",
392 "svp/dcid",
393 "svp/router_oui"
394 };
395
396 static const uint8_t svp_bcast[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
397
398 int
399 svp_comparator(const void *l, const void *r)
400 {
401 const svp_t *ls = l;
402 const svp_t *rs = r;
403
404 if (ls->svp_vid > rs->svp_vid)
405 return (1);
406 if (ls->svp_vid < rs->svp_vid)
407 return (-1);
408 return (0);
409 }
410
411 static void
412 svp_vl2_lookup_cb(svp_t *svp, svp_status_t status, const struct in6_addr *uip,
413 const uint16_t uport, void *arg)
420
421 if (status != SVP_S_OK) {
422 libvarpd_plugin_query_reply(svl->svl_u.svl_vl2.svl_handle,
423 VARPD_LOOKUP_DROP);
424 umem_cache_free(svp_lookup_cache, svl);
425 return;
426 }
427
428 otp = svl->svl_u.svl_vl2.svl_point;
429 bcopy(uip, &otp->otp_ip, sizeof (struct in6_addr));
430 otp->otp_port = uport;
431 libvarpd_plugin_query_reply(svl->svl_u.svl_vl2.svl_handle,
432 VARPD_LOOKUP_OK);
433 umem_cache_free(svp_lookup_cache, svl);
434 }
435
436 static void
437 svp_vl3_lookup_cb(svp_t *svp, svp_status_t status, const uint8_t *vl2mac,
438 const struct in6_addr *uip, const uint16_t uport, void *arg)
439 {
440 /* Initialize address-holders to 0 for comparisons-to-zeroes later. */
441 overlay_target_point_t point = { 0 };
442 svp_lookup_t *svl = arg;
443 uint8_t nexthop_mac[6] = { 0, 0, 0, 0, 0, 0 };
444
445 assert(svp != NULL);
446 assert(svl != NULL);
447
448 if (status != SVP_S_OK) {
449 libvarpd_plugin_arp_reply(svl->svl_u.svl_vl3.svl_vah,
450 VARPD_LOOKUP_DROP);
451 umem_cache_free(svp_lookup_cache, svl);
452 return;
453 }
454
455 /* Inject the L2 mapping before the L3 */
456 if (uport != 0 &&
457 bcmp(uip, &point.otp_ip, sizeof (struct in6_addr)) != 0) {
458 /* Normal L3 lookup result... */
459 bcopy(uip, &point.otp_ip, sizeof (struct in6_addr));
460 point.otp_port = uport;
461 libvarpd_inject_varp(svp->svp_hdl, vl2mac, &point);
462 } else {
463 /*
464 * Oh my, we have a next-hop router IP.
465 * Set the MAC to the ouid+vid concatenated
466 * special-router-MAC. Overlay down below will know
467 * that uport == 0 means the MAC is a special one.
468 */
469 if (bcmp(svp->svp_router_oui, nexthop_mac, ETHERADDRL) == 0) {
470 /*
471 * We don't have a router_oui, so we can't support
472 * special-router-MAC. Drop it.
473 */
474 libvarpd_plugin_arp_reply(svl->svl_u.svl_vl3.svl_vah,
475 VARPD_LOOKUP_DROP);
476 umem_cache_free(svp_lookup_cache, svl);
477 return;
478 }
479 bcopy(svp->svp_router_oui, nexthop_mac, 3);
480 nexthop_mac[3] = (svp->svp_vid >> 16) & 0xff;
481 nexthop_mac[4] = (svp->svp_vid >> 8) & 0xff;
482 nexthop_mac[5] = svp->svp_vid & 0xff;
483 vl2mac = nexthop_mac;
484 }
485
486 bcopy(vl2mac, svl->svl_u.svl_vl3.svl_out, ETHERADDRL);
487 libvarpd_plugin_arp_reply(svl->svl_u.svl_vl3.svl_vah,
488 VARPD_LOOKUP_OK);
489 umem_cache_free(svp_lookup_cache, svl);
490 }
491
492 static void
493 svp_vl2_invalidate_cb(svp_t *svp, const uint8_t *vl2mac)
494 {
495 libvarpd_inject_varp(svp->svp_hdl, vl2mac, NULL);
496 }
497
498 static void
499 svp_vl3_inject_cb(svp_t *svp, const uint16_t vlan, const struct in6_addr *vl3ip,
500 const uint8_t *vl2mac, const uint8_t *targmac)
501 {
502 struct in_addr v4;
503
504 /*
505 * At the moment we don't support any IPv6 related log entries, this
506 * will change soon as we develop a bit more of the IPv6 related
507 * infrastructure so we can properly test the injection.
508 */
509 if (IN6_IS_ADDR_V4MAPPED(vl3ip) == 0) {
510 return;
511 } else {
512 IN6_V4MAPPED_TO_INADDR(vl3ip, &v4);
513 if (targmac == NULL)
514 targmac = svp_bcast;
515 libvarpd_inject_arp(svp->svp_hdl, vlan, vl2mac, &v4, targmac);
516 }
517 }
518
519 /* ARGSUSED */
520 static void
521 svp_shootdown_cb(svp_t *svp, const uint8_t *vl2mac, const struct in6_addr *uip,
522 const uint16_t uport)
523 {
524 /*
525 * We should probably do a conditional invalidation here.
526 */
527 libvarpd_inject_varp(svp->svp_hdl, vl2mac, NULL);
528 }
529
530 static void
531 svp_route_lookup_cb(svp_t *svp, svp_status_t status, uint32_t dcid,
532 uint32_t vnetid, uint16_t vlan, uint8_t *srcmac, uint8_t *dstmac,
533 uint16_t ul3_port, uint8_t *ul3_addr, uint8_t srcpfx, uint8_t dstpfx,
534 void *arg)
535 {
536 svp_lookup_t *svl = arg;
537 overlay_target_point_t *otp;
538 overlay_target_route_t *otr;
539
540 if (status != SVP_S_OK) {
541 libvarpd_plugin_query_reply(svl->svl_u.svl_route.svl_handle,
542 VARPD_LOOKUP_DROP);
543 umem_cache_free(svp_lookup_cache, svl);
544 return;
545 }
546
547 otp = svl->svl_u.svl_route.svl_point;
548 bcopy(dstmac, otp->otp_mac, ETHERADDRL);
549 bcopy(ul3_addr, &otp->otp_ip, sizeof (struct in6_addr));
550 otp->otp_port = ul3_port;
551
552 otr = svl->svl_u.svl_route.svl_route;
553 otr->otr_vnet = vnetid;
554 otr->otr_vlan = vlan;
555 bcopy(srcmac, otr->otr_srcmac, ETHERADDRL);
556 otr->otr_dcid = dcid;
557 otr->otr_src_prefixlen = srcpfx;
558 otr->otr_dst_prefixlen = dstpfx;
559
560 libvarpd_plugin_query_reply(svl->svl_u.svl_route.svl_handle,
561 VARPD_LOOKUP_OK);
562 umem_cache_free(svp_lookup_cache, svl);
563 }
564
565 static svp_cb_t svp_defops = {
566 svp_vl2_lookup_cb,
567 svp_vl3_lookup_cb,
568 svp_vl2_invalidate_cb,
569 svp_vl3_inject_cb,
570 svp_shootdown_cb,
571 svp_route_lookup_cb,
572 };
573
574 static boolean_t
575 varpd_svp_valid_dest(overlay_plugin_dest_t dest)
576 {
577 if (dest != (OVERLAY_PLUGIN_D_IP | OVERLAY_PLUGIN_D_PORT))
578 return (B_FALSE);
579
580 return (B_TRUE);
581 }
582
583 static int
584 varpd_svp_create(varpd_provider_handle_t *hdl, void **outp,
585 overlay_plugin_dest_t dest)
586 {
587 int ret;
588 svp_t *svp;
589
590 if (varpd_svp_valid_dest(dest) == B_FALSE)
591 return (ENOTSUP);
659 }
660
661 static void
662 varpd_svp_lookup_l3(svp_t *svp, varpd_query_handle_t *vqh,
663 const overlay_targ_lookup_t *otl, overlay_target_point_t *otp,
664 overlay_target_route_t *otr)
665 {
666 svp_lookup_t *slp;
667 uint32_t type;
668 const struct in6_addr *src = &otl->otl_addru.otlu_l3.otl3_srcip,
669 *dst = &otl->otl_addru.otlu_l3.otl3_dstip;
670
671 /*
672 * otl is an L3 request, so we have src/dst IPs for the inner packet.
673 * We also have the vlan.
674 *
675 * Assume kernel's overlay module is caching well, so we are directly
676 * going to query (i.e. no caching up here of actual destinations).
677 *
678 * Our existing remote sever (svp_remote), but with the new message
679 * SVP_R_ROUTE_REQ.
680 */
681
682 /* XXX KEBE SAYS DO SOME otl verification too... */
683 if (IN6_IS_ADDR_V4MAPPED(src)) {
684 if (!IN6_IS_ADDR_V4MAPPED(dst)) {
685 libvarpd_plugin_query_reply(vqh, VARPD_LOOKUP_DROP);
686 return;
687 }
688 type = SVP_VL3_IP;
689 } else {
690 if (IN6_IS_ADDR_V4MAPPED(dst)) {
691 libvarpd_plugin_query_reply(vqh, VARPD_LOOKUP_DROP);
692 return;
693 }
694 type = SVP_VL3_IPV6;
695 }
696
697 slp = umem_cache_alloc(svp_lookup_cache, UMEM_DEFAULT);
698 if (slp == NULL) {
699 libvarpd_plugin_query_reply(vqh, VARPD_LOOKUP_DROP);
700 return;
701 }
702
703 slp->svl_type = SVP_L_ROUTE;
704 slp->svl_u.svl_route.svl_handle = vqh;
705 slp->svl_u.svl_route.svl_point = otp;
706 slp->svl_u.svl_route.svl_route = otr;
707
708 svp_remote_route_lookup(svp, &slp->svl_query, src, dst,
709 otl->otl_vnetid, (uint16_t)otl->otl_vlan, slp);
710 }
711
712 static void
713 varpd_svp_lookup(void *arg, varpd_query_handle_t *vqh,
714 const overlay_targ_lookup_t *otl, overlay_target_point_t *otp,
715 overlay_target_route_t *otr)
716 {
717 svp_lookup_t *slp;
718 svp_t *svp = arg;
719
720 /*
721 * Shuffle off L3 lookups to their own codepath.
722 */
723 if (otl->otl_l3req) {
724 varpd_svp_lookup_l3(svp, vqh, otl, otp, otr);
725 return;
726 }
727 /*
728 * At this point, the traditional overlay_target_point_t is all that
820 break;
821 case 3:
822 /* svp/underlay_port */
823 libvarpd_prop_set_name(vph, varpd_svp_props[3]);
824 libvarpd_prop_set_prot(vph, OVERLAY_PROP_PERM_RRW);
825 libvarpd_prop_set_type(vph, OVERLAY_PROP_T_UINT);
826 (void) libvarpd_prop_set_default(vph, &svp_defuport,
827 sizeof (svp_defuport));
828 libvarpd_prop_set_range_uint32(vph, 1, UINT16_MAX);
829 break;
830 case 4:
831 /* svp/dcid */
832 libvarpd_prop_set_name(vph, varpd_svp_props[4]);
833 libvarpd_prop_set_prot(vph, OVERLAY_PROP_PERM_RRW);
834 libvarpd_prop_set_type(vph, OVERLAY_PROP_T_UINT);
835 libvarpd_prop_set_nodefault(vph);
836 /* XXX KEBE ASKS should I just set high to UINT32_MAX? */
837 libvarpd_prop_set_range_uint32(vph, 1, UINT32_MAX - 1);
838 break;
839 case 5:
840 /* svp/router_oui */
841 libvarpd_prop_set_name(vph, varpd_svp_props[5]);
842 libvarpd_prop_set_prot(vph, OVERLAY_PROP_PERM_RRW);
843 libvarpd_prop_set_type(vph, OVERLAY_PROP_T_ETHER);
844 libvarpd_prop_set_nodefault(vph);
845 break;
846 default:
847 return (EINVAL);
848 }
849 return (0);
850 }
851
852 static int
853 varpd_svp_getprop(void *arg, const char *pname, void *buf, uint32_t *sizep)
854 {
855 svp_t *svp = arg;
856
857 /* svp/host */
858 if (strcmp(pname, varpd_svp_props[0]) == 0) {
859 size_t len;
860
931 /* svp/dcid */
932 if (strcmp(pname, varpd_svp_props[4]) == 0) {
933 uint64_t val;
934
935 if (*sizep < sizeof (uint64_t))
936 return (EOVERFLOW);
937
938 mutex_enter(&svp->svp_lock);
939 if (svp->svp_uport == 0) {
940 *sizep = 0;
941 } else {
942 val = svp->svp_dcid;
943 bcopy(&val, buf, sizeof (uint64_t));
944 *sizep = sizeof (uint64_t);
945 }
946
947 mutex_exit(&svp->svp_lock);
948 return (0);
949 }
950
951 /* svp/router_oui */
952 if (strcmp(pname, varpd_svp_props[5]) == 0) {
953 if (*sizep < ETHERADDRL)
954 return (EOVERFLOW);
955 mutex_enter(&svp->svp_lock);
956
957 if (ether_is_zero(&svp->svp_router_oui)) {
958 *sizep = 0;
959 } else {
960 bcopy(&svp->svp_router_oui, buf, ETHERADDRL);
961 *sizep = ETHERADDRL;
962 }
963
964 mutex_exit(&svp->svp_lock);
965 return (0);
966 }
967 return (EINVAL);
968 }
969
970 static int
971 varpd_svp_setprop(void *arg, const char *pname, const void *buf,
972 const uint32_t size)
973 {
974 svp_t *svp = arg;
975
976 /* svp/host */
977 if (strcmp(pname, varpd_svp_props[0]) == 0) {
978 char *dup;
979 dup = umem_alloc(size, UMEM_DEFAULT);
980 (void) strlcpy(dup, buf, size);
1049 return (0);
1050 }
1051
1052 /* svp/dcid */
1053 if (strcmp(pname, varpd_svp_props[4]) == 0) {
1054 const uint64_t *valp = buf;
1055 if (size < sizeof (uint64_t))
1056 return (EOVERFLOW);
1057
1058 /* XXX KEBE ASKS, use UINT32_MAX instead? */
1059 if (*valp == 0 || *valp > UINT32_MAX - 1)
1060 return (EINVAL);
1061
1062 mutex_enter(&svp->svp_lock);
1063 svp->svp_dcid = (uint32_t)*valp;
1064 mutex_exit(&svp->svp_lock);
1065
1066 return (0);
1067 }
1068
1069 /* svp/router_oui */
1070 if (strcmp(pname, varpd_svp_props[5]) == 0) {
1071 if (size < ETHERADDRL)
1072 return (EOVERFLOW);
1073 mutex_enter(&svp->svp_lock);
1074 bcopy(buf, &svp->svp_router_oui, ETHERADDRL);
1075 /* Zero-out the low three bytes. */
1076 svp->svp_router_oui[3] = 0;
1077 svp->svp_router_oui[4] = 0;
1078 svp->svp_router_oui[5] = 0;
1079 mutex_exit(&svp->svp_lock);
1080 return (0);
1081 }
1082
1083 return (EINVAL);
1084 }
1085
1086 static int
1087 varpd_svp_save(void *arg, nvlist_t *nvp)
1088 {
1089 int ret;
1090 svp_t *svp = arg;
1091
1092 mutex_enter(&svp->svp_lock);
1093 /* svp/host */
1094 if (svp->svp_host != NULL) {
1095 if ((ret = nvlist_add_string(nvp, varpd_svp_props[0],
1096 svp->svp_host)) != 0) {
1097 mutex_exit(&svp->svp_lock);
1098 return (ret);
1125 }
1126
1127 /* svp/underlay_port */
1128 if (svp->svp_uport != 0) {
1129 if ((ret = nvlist_add_uint16(nvp, varpd_svp_props[3],
1130 svp->svp_uport)) != 0) {
1131 mutex_exit(&svp->svp_lock);
1132 return (ret);
1133 }
1134 }
1135
1136 /* svp/dcid */
1137 if (svp->svp_dcid != 0) {
1138 if ((ret = nvlist_add_uint32(nvp, varpd_svp_props[4],
1139 svp->svp_dcid)) != 0) {
1140 mutex_exit(&svp->svp_lock);
1141 return (ret);
1142 }
1143 }
1144
1145 /* svp/router_oui */
1146 if (!ether_is_zero(&svp->svp_router_oui)) {
1147 char buf[ETHERADDRSTRL];
1148
1149 /* XXX KEBE SAYS See underlay_ip... */
1150 if (ether_ntoa_r((struct ether_addr *)&svp->svp_router_oui,
1151 buf) == NULL) {
1152 libvarpd_panic("unexpected ether_ntoa_r failure: %d",
1153 errno);
1154 }
1155
1156 if ((ret = nvlist_add_string(nvp, varpd_svp_props[5],
1157 buf)) != 0) {
1158 mutex_exit(&svp->svp_lock);
1159 return (ret);
1160 }
1161 }
1162
1163 mutex_exit(&svp->svp_lock);
1164 return (0);
1165 }
1166
1167 static int
1168 varpd_svp_restore(nvlist_t *nvp, varpd_provider_handle_t *hdl,
1169 overlay_plugin_dest_t dest, void **outp)
1170 {
1171 int ret;
1228 /* svp/underlay_port */
1229 if ((ret = nvlist_lookup_uint16(nvp, varpd_svp_props[3],
1230 &svp->svp_uport)) != 0) {
1231 if (ret != ENOENT) {
1232 varpd_svp_destroy(svp);
1233 return (ret);
1234 }
1235 svp->svp_uport = 0;
1236 }
1237
1238 /* svp/dcid */
1239 if ((ret = nvlist_lookup_uint32(nvp, varpd_svp_props[4],
1240 &svp->svp_dcid)) != 0) {
1241 if (ret != ENOENT) {
1242 varpd_svp_destroy(svp);
1243 return (ret);
1244 }
1245 svp->svp_dcid = 0;
1246 }
1247
1248 /* svp/router_oui */
1249 if ((ret = nvlist_lookup_string(nvp, varpd_svp_props[5],
1250 ðerstr)) != 0) {
1251 if (ret != ENOENT) {
1252 varpd_svp_destroy(svp);
1253 return (ret);
1254 }
1255 bzero(&svp->svp_router_oui, ETHERADDRL);
1256 } else if (ether_aton_r(etherstr,
1257 (struct ether_addr *)&svp->svp_router_oui) == NULL) {
1258 libvarpd_panic("unexpected ether_aton_r failure: %d", errno);
1259 }
1260
1261 svp->svp_hdl = hdl;
1262 *outp = svp;
1263 return (0);
1264 }
1265
1266 static void
1267 varpd_svp_arp(void *arg, varpd_arp_handle_t *vah, int type,
1268 const struct sockaddr *sock, uint8_t *out)
1269 {
1270 svp_t *svp = arg;
1271 svp_lookup_t *svl;
1272
1273 if (type != VARPD_QTYPE_ETHERNET) {
1274 libvarpd_plugin_arp_reply(vah, VARPD_LOOKUP_DROP);
1275 return;
1276 }
1277
|