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_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)
 
 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         /*
 
 792                 break;
 793         case 3:
 794                 /* svp/underlay_port */
 795                 libvarpd_prop_set_name(vph, varpd_svp_props[3]);
 796                 libvarpd_prop_set_prot(vph, OVERLAY_PROP_PERM_RRW);
 797                 libvarpd_prop_set_type(vph, OVERLAY_PROP_T_UINT);
 798                 (void) libvarpd_prop_set_default(vph, &svp_defuport,
 799                     sizeof (svp_defuport));
 800                 libvarpd_prop_set_range_uint32(vph, 1, UINT16_MAX);
 801                 break;
 802         case 4:
 803                 /* svp/dcid */
 804                 libvarpd_prop_set_name(vph, varpd_svp_props[4]);
 805                 libvarpd_prop_set_prot(vph, OVERLAY_PROP_PERM_RRW);
 806                 libvarpd_prop_set_type(vph, OVERLAY_PROP_T_UINT);
 807                 libvarpd_prop_set_nodefault(vph);
 808                 /* XXX KEBE ASKS should I just set high to UINT32_MAX? */
 809                 libvarpd_prop_set_range_uint32(vph, 1, UINT32_MAX - 1);
 810                 break;
 811         case 5:
 812                 /* svp/router_mac */
 813                 libvarpd_prop_set_name(vph, varpd_svp_props[5]);
 814                 libvarpd_prop_set_prot(vph, OVERLAY_PROP_PERM_RRW);
 815                 libvarpd_prop_set_type(vph, OVERLAY_PROP_T_ETHER);
 816                 libvarpd_prop_set_nodefault(vph);
 817                 break;
 818         default:
 819                 return (EINVAL);
 820         }
 821         return (0);
 822 }
 823 
 824 static int
 825 varpd_svp_getprop(void *arg, const char *pname, void *buf, uint32_t *sizep)
 826 {
 827         svp_t *svp = arg;
 828 
 829         /* svp/host */
 830         if (strcmp(pname, varpd_svp_props[0]) == 0) {
 831                 size_t len;
 832 
 
 903         /* svp/dcid */
 904         if (strcmp(pname, varpd_svp_props[4]) == 0) {
 905                 uint64_t val;
 906 
 907                 if (*sizep < sizeof (uint64_t))
 908                         return (EOVERFLOW);
 909 
 910                 mutex_enter(&svp->svp_lock);
 911                 if (svp->svp_uport == 0) {
 912                         *sizep = 0;
 913                 } else {
 914                         val = svp->svp_dcid;
 915                         bcopy(&val, buf, sizeof (uint64_t));
 916                         *sizep = sizeof (uint64_t);
 917                 }
 918 
 919                 mutex_exit(&svp->svp_lock);
 920                 return (0);
 921         }
 922 
 923         /* svp/router_mac */
 924         if (strcmp(pname, varpd_svp_props[5]) == 0) {
 925                 if (*sizep < ETHERADDRL)
 926                         return (EOVERFLOW);
 927                 mutex_enter(&svp->svp_lock);
 928 
 929                 if (ether_is_zero(&svp->svp_router_mac)) {
 930                         *sizep = 0;
 931                 } else {
 932                         bcopy(&svp->svp_router_mac, buf, ETHERADDRL);
 933                         *sizep = ETHERADDRL;
 934                 }
 935 
 936                 mutex_exit(&svp->svp_lock);
 937                 return (0);
 938         }
 939         return (EINVAL);
 940 }
 941 
 942 static int
 943 varpd_svp_setprop(void *arg, const char *pname, const void *buf,
 944     const uint32_t size)
 945 {
 946         svp_t *svp = arg;
 947 
 948         /* svp/host */
 949         if (strcmp(pname, varpd_svp_props[0]) == 0) {
 950                 char *dup;
 951                 dup = umem_alloc(size, UMEM_DEFAULT);
 952                 (void) strlcpy(dup, buf, size);
 
1021                 return (0);
1022         }
1023 
1024         /* svp/dcid */
1025         if (strcmp(pname, varpd_svp_props[4]) == 0) {
1026                 const uint64_t *valp = buf;
1027                 if (size < sizeof (uint64_t))
1028                         return (EOVERFLOW);
1029 
1030                 /* XXX KEBE ASKS, use UINT32_MAX instead? */
1031                 if (*valp == 0 || *valp > UINT32_MAX - 1)
1032                         return (EINVAL);
1033 
1034                 mutex_enter(&svp->svp_lock);
1035                 svp->svp_dcid = (uint32_t)*valp;
1036                 mutex_exit(&svp->svp_lock);
1037 
1038                 return (0);
1039         }
1040 
1041         /* svp/router_mac */
1042         if (strcmp(pname, varpd_svp_props[5]) == 0) {
1043                 if (size < ETHERADDRL)
1044                         return (EOVERFLOW);
1045                 mutex_enter(&svp->svp_lock);
1046                 bcopy(buf, &svp->svp_router_mac, ETHERADDRL);
1047                 mutex_exit(&svp->svp_lock);
1048                 return (0);
1049         }
1050 
1051         return (EINVAL);
1052 }
1053 
1054 static int
1055 varpd_svp_save(void *arg, nvlist_t *nvp)
1056 {
1057         int ret;
1058         svp_t *svp = arg;
1059 
1060         mutex_enter(&svp->svp_lock);
1061         /* svp/host */
1062         if (svp->svp_host != NULL) {
1063                 if ((ret = nvlist_add_string(nvp, varpd_svp_props[0],
1064                     svp->svp_host)) != 0) {
1065                         mutex_exit(&svp->svp_lock);
1066                         return (ret);
 
1093         }
1094 
1095         /* svp/underlay_port */
1096         if (svp->svp_uport != 0) {
1097                 if ((ret = nvlist_add_uint16(nvp, varpd_svp_props[3],
1098                     svp->svp_uport)) != 0) {
1099                         mutex_exit(&svp->svp_lock);
1100                         return (ret);
1101                 }
1102         }
1103 
1104         /* svp/dcid */
1105         if (svp->svp_dcid != 0) {
1106                 if ((ret = nvlist_add_uint32(nvp, varpd_svp_props[4],
1107                     svp->svp_dcid)) != 0) {
1108                         mutex_exit(&svp->svp_lock);
1109                         return (ret);
1110                 }
1111         }
1112 
1113         /* svp/router_mac */
1114         if (!ether_is_zero(&svp->svp_router_mac)) {
1115                 char buf[ETHERADDRSTRL];
1116 
1117                 /* XXX KEBE SAYS See underlay_ip... */
1118                 if (ether_ntoa_r(&svp->svp_router_mac, buf) == NULL) {
1119                         libvarpd_panic("unexpected ether_ntoa_r failure: %d",
1120                             errno);
1121                 }
1122 
1123                 if ((ret = nvlist_add_string(nvp, varpd_svp_props[5],
1124                     buf)) != 0) {
1125                         mutex_exit(&svp->svp_lock);
1126                         return (ret);
1127                 }
1128         }
1129 
1130         mutex_exit(&svp->svp_lock);
1131         return (0);
1132 }
1133 
1134 static int
1135 varpd_svp_restore(nvlist_t *nvp, varpd_provider_handle_t *hdl,
1136     overlay_plugin_dest_t dest, void **outp)
1137 {
1138         int ret;
 
1195         /* svp/underlay_port */
1196         if ((ret = nvlist_lookup_uint16(nvp, varpd_svp_props[3],
1197             &svp->svp_uport)) != 0) {
1198                 if (ret != ENOENT) {
1199                         varpd_svp_destroy(svp);
1200                         return (ret);
1201                 }
1202                 svp->svp_uport = 0;
1203         }
1204 
1205         /* svp/dcid */
1206         if ((ret = nvlist_lookup_uint32(nvp, varpd_svp_props[4],
1207             &svp->svp_dcid)) != 0) {
1208                 if (ret != ENOENT) {
1209                         varpd_svp_destroy(svp);
1210                         return (ret);
1211                 }
1212                 svp->svp_dcid = 0;
1213         }
1214 
1215         /* svp/router_mac */
1216         if ((ret = nvlist_lookup_string(nvp, varpd_svp_props[5],
1217             ðerstr)) != 0) {
1218                 if (ret != ENOENT) {
1219                         varpd_svp_destroy(svp);
1220                         return (ret);
1221                 }
1222                 bzero(&svp->svp_router_mac, ETHERADDRL);
1223         } else if (ether_aton_r(etherstr, &svp->svp_router_mac) == NULL) {
1224                 libvarpd_panic("unexpected ether_aton_r failure: %d", errno);
1225         }
1226 
1227         svp->svp_hdl = hdl;
1228         *outp = svp;
1229         return (0);
1230 }
1231 
1232 static void
1233 varpd_svp_arp(void *arg, varpd_arp_handle_t *vah, int type,
1234     const struct sockaddr *sock, uint8_t *out)
1235 {
1236         svp_t *svp = arg;
1237         svp_lookup_t *svl;
1238 
1239         if (type != VARPD_QTYPE_ETHERNET) {
1240                 libvarpd_plugin_arp_reply(vah, VARPD_LOOKUP_DROP);
1241                 return;
1242         }
1243 
 
 | 
 
 
 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)
 
 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         uint8_t nexthop_mac[6] = { 0, 0, 0, 0, 0, 0 };
 443 
 444         assert(svp != NULL);
 445         assert(svl != NULL);
 446 
 447         if (status != SVP_S_OK) {
 448                 libvarpd_plugin_arp_reply(svl->svl_u.svl_vl3.svl_vah,
 449                     VARPD_LOOKUP_DROP);
 450                 umem_cache_free(svp_lookup_cache, svl);
 451                 return;
 452         }
 453 
 454         /* Inject the L2 mapping before the L3 */
 455         bcopy(uip, &point.otp_ip, sizeof (struct in6_addr));
 456         point.otp_port = uport;
 457         if (uport != 0) {
 458                 /* Normal L3 lookup result... */
 459                 libvarpd_inject_varp(svp->svp_hdl, vl2mac, &point);
 460         } else {
 461                 /*
 462                  * Oh my, we have a next-hop router IP.
 463                  * Set the MAC to the ouid+vid concatenated
 464                  * special-router-MAC. Overlay down below will know
 465                  * that uport == 0 means the MAC is a special one.
 466                  */
 467                 if (bcmp(svp->svp_router_oui, nexthop_mac, ETHERADDRL) == 0) {
 468                         /*
 469                          * We don't have a router_oui, so we can't support
 470                          * special-router-MAC.  Drop it.
 471                          */
 472                         libvarpd_plugin_arp_reply(svl->svl_u.svl_vl3.svl_vah,
 473                             VARPD_LOOKUP_DROP);
 474                         umem_cache_free(svp_lookup_cache, svl);
 475                         return;
 476                 }
 477                 vl2mac = nexthop_mac;
 478                 bcopy(svp->svp_router_oui, vl2mac, 3);
 479                 vl2mac[3] = (svp->svp_vid >> 16) & 0xff;
 480                 vl2mac[4] = (svp->svp_vid >> 8) & 0xff;
 481                 vl2mac[5] = svp->svp_vid & 0xff;
 482         }
 483 
 484         bcopy(vl2mac, svl->svl_u.svl_vl3.svl_out, ETHERADDRL);
 485         libvarpd_plugin_arp_reply(svl->svl_u.svl_vl3.svl_vah,
 486             VARPD_LOOKUP_OK);
 487         umem_cache_free(svp_lookup_cache, svl);
 488 }
 489 
 490 static void
 491 svp_vl2_invalidate_cb(svp_t *svp, const uint8_t *vl2mac)
 492 {
 493         libvarpd_inject_varp(svp->svp_hdl, vl2mac, NULL);
 494 }
 495 
 496 static void
 497 svp_vl3_inject_cb(svp_t *svp, const uint16_t vlan, const struct in6_addr *vl3ip,
 498     const uint8_t *vl2mac, const uint8_t *targmac)
 499 {
 500         struct in_addr v4;
 501 
 502         /*
 
 818                 break;
 819         case 3:
 820                 /* svp/underlay_port */
 821                 libvarpd_prop_set_name(vph, varpd_svp_props[3]);
 822                 libvarpd_prop_set_prot(vph, OVERLAY_PROP_PERM_RRW);
 823                 libvarpd_prop_set_type(vph, OVERLAY_PROP_T_UINT);
 824                 (void) libvarpd_prop_set_default(vph, &svp_defuport,
 825                     sizeof (svp_defuport));
 826                 libvarpd_prop_set_range_uint32(vph, 1, UINT16_MAX);
 827                 break;
 828         case 4:
 829                 /* svp/dcid */
 830                 libvarpd_prop_set_name(vph, varpd_svp_props[4]);
 831                 libvarpd_prop_set_prot(vph, OVERLAY_PROP_PERM_RRW);
 832                 libvarpd_prop_set_type(vph, OVERLAY_PROP_T_UINT);
 833                 libvarpd_prop_set_nodefault(vph);
 834                 /* XXX KEBE ASKS should I just set high to UINT32_MAX? */
 835                 libvarpd_prop_set_range_uint32(vph, 1, UINT32_MAX - 1);
 836                 break;
 837         case 5:
 838                 /* svp/router_oui */
 839                 libvarpd_prop_set_name(vph, varpd_svp_props[5]);
 840                 libvarpd_prop_set_prot(vph, OVERLAY_PROP_PERM_RRW);
 841                 libvarpd_prop_set_type(vph, OVERLAY_PROP_T_ETHER);
 842                 libvarpd_prop_set_nodefault(vph);
 843                 break;
 844         default:
 845                 return (EINVAL);
 846         }
 847         return (0);
 848 }
 849 
 850 static int
 851 varpd_svp_getprop(void *arg, const char *pname, void *buf, uint32_t *sizep)
 852 {
 853         svp_t *svp = arg;
 854 
 855         /* svp/host */
 856         if (strcmp(pname, varpd_svp_props[0]) == 0) {
 857                 size_t len;
 858 
 
 929         /* svp/dcid */
 930         if (strcmp(pname, varpd_svp_props[4]) == 0) {
 931                 uint64_t val;
 932 
 933                 if (*sizep < sizeof (uint64_t))
 934                         return (EOVERFLOW);
 935 
 936                 mutex_enter(&svp->svp_lock);
 937                 if (svp->svp_uport == 0) {
 938                         *sizep = 0;
 939                 } else {
 940                         val = svp->svp_dcid;
 941                         bcopy(&val, buf, sizeof (uint64_t));
 942                         *sizep = sizeof (uint64_t);
 943                 }
 944 
 945                 mutex_exit(&svp->svp_lock);
 946                 return (0);
 947         }
 948 
 949         /* svp/router_oui */
 950         if (strcmp(pname, varpd_svp_props[5]) == 0) {
 951                 if (*sizep < ETHERADDRL)
 952                         return (EOVERFLOW);
 953                 mutex_enter(&svp->svp_lock);
 954 
 955                 if (ether_is_zero(&svp->svp_router_oui)) {
 956                         *sizep = 0;
 957                 } else {
 958                         bcopy(&svp->svp_router_oui, buf, ETHERADDRL);
 959                         *sizep = ETHERADDRL;
 960                 }
 961 
 962                 mutex_exit(&svp->svp_lock);
 963                 return (0);
 964         }
 965         return (EINVAL);
 966 }
 967 
 968 static int
 969 varpd_svp_setprop(void *arg, const char *pname, const void *buf,
 970     const uint32_t size)
 971 {
 972         svp_t *svp = arg;
 973 
 974         /* svp/host */
 975         if (strcmp(pname, varpd_svp_props[0]) == 0) {
 976                 char *dup;
 977                 dup = umem_alloc(size, UMEM_DEFAULT);
 978                 (void) strlcpy(dup, buf, size);
 
1047                 return (0);
1048         }
1049 
1050         /* svp/dcid */
1051         if (strcmp(pname, varpd_svp_props[4]) == 0) {
1052                 const uint64_t *valp = buf;
1053                 if (size < sizeof (uint64_t))
1054                         return (EOVERFLOW);
1055 
1056                 /* XXX KEBE ASKS, use UINT32_MAX instead? */
1057                 if (*valp == 0 || *valp > UINT32_MAX - 1)
1058                         return (EINVAL);
1059 
1060                 mutex_enter(&svp->svp_lock);
1061                 svp->svp_dcid = (uint32_t)*valp;
1062                 mutex_exit(&svp->svp_lock);
1063 
1064                 return (0);
1065         }
1066 
1067         /* svp/router_oui */
1068         if (strcmp(pname, varpd_svp_props[5]) == 0) {
1069                 if (size < ETHERADDRL)
1070                         return (EOVERFLOW);
1071                 mutex_enter(&svp->svp_lock);
1072                 bcopy(buf, &svp->svp_router_oui, ETHERADDRL);
1073                 /* Zero-out the low three bytes. */
1074                 svp->svp_router_oui[3] = 0;
1075                 svp->svp_router_oui[4] = 0;
1076                 svp->svp_router_oui[5] = 0;
1077                 mutex_exit(&svp->svp_lock);
1078                 return (0);
1079         }
1080 
1081         return (EINVAL);
1082 }
1083 
1084 static int
1085 varpd_svp_save(void *arg, nvlist_t *nvp)
1086 {
1087         int ret;
1088         svp_t *svp = arg;
1089 
1090         mutex_enter(&svp->svp_lock);
1091         /* svp/host */
1092         if (svp->svp_host != NULL) {
1093                 if ((ret = nvlist_add_string(nvp, varpd_svp_props[0],
1094                     svp->svp_host)) != 0) {
1095                         mutex_exit(&svp->svp_lock);
1096                         return (ret);
 
1123         }
1124 
1125         /* svp/underlay_port */
1126         if (svp->svp_uport != 0) {
1127                 if ((ret = nvlist_add_uint16(nvp, varpd_svp_props[3],
1128                     svp->svp_uport)) != 0) {
1129                         mutex_exit(&svp->svp_lock);
1130                         return (ret);
1131                 }
1132         }
1133 
1134         /* svp/dcid */
1135         if (svp->svp_dcid != 0) {
1136                 if ((ret = nvlist_add_uint32(nvp, varpd_svp_props[4],
1137                     svp->svp_dcid)) != 0) {
1138                         mutex_exit(&svp->svp_lock);
1139                         return (ret);
1140                 }
1141         }
1142 
1143         /* svp/router_oui */
1144         if (!ether_is_zero(&svp->svp_router_oui)) {
1145                 char buf[ETHERADDRSTRL];
1146 
1147                 /* XXX KEBE SAYS See underlay_ip... */
1148                 if (ether_ntoa_r(&svp->svp_router_oui, buf) == NULL) {
1149                         libvarpd_panic("unexpected ether_ntoa_r failure: %d",
1150                             errno);
1151                 }
1152 
1153                 if ((ret = nvlist_add_string(nvp, varpd_svp_props[5],
1154                     buf)) != 0) {
1155                         mutex_exit(&svp->svp_lock);
1156                         return (ret);
1157                 }
1158         }
1159 
1160         mutex_exit(&svp->svp_lock);
1161         return (0);
1162 }
1163 
1164 static int
1165 varpd_svp_restore(nvlist_t *nvp, varpd_provider_handle_t *hdl,
1166     overlay_plugin_dest_t dest, void **outp)
1167 {
1168         int ret;
 
1225         /* svp/underlay_port */
1226         if ((ret = nvlist_lookup_uint16(nvp, varpd_svp_props[3],
1227             &svp->svp_uport)) != 0) {
1228                 if (ret != ENOENT) {
1229                         varpd_svp_destroy(svp);
1230                         return (ret);
1231                 }
1232                 svp->svp_uport = 0;
1233         }
1234 
1235         /* svp/dcid */
1236         if ((ret = nvlist_lookup_uint32(nvp, varpd_svp_props[4],
1237             &svp->svp_dcid)) != 0) {
1238                 if (ret != ENOENT) {
1239                         varpd_svp_destroy(svp);
1240                         return (ret);
1241                 }
1242                 svp->svp_dcid = 0;
1243         }
1244 
1245         /* svp/router_oui */
1246         if ((ret = nvlist_lookup_string(nvp, varpd_svp_props[5],
1247             ðerstr)) != 0) {
1248                 if (ret != ENOENT) {
1249                         varpd_svp_destroy(svp);
1250                         return (ret);
1251                 }
1252                 bzero(&svp->svp_router_oui, ETHERADDRL);
1253         } else if (ether_aton_r(etherstr, &svp->svp_router_oui) == NULL) {
1254                 libvarpd_panic("unexpected ether_aton_r failure: %d", errno);
1255         }
1256 
1257         svp->svp_hdl = hdl;
1258         *outp = svp;
1259         return (0);
1260 }
1261 
1262 static void
1263 varpd_svp_arp(void *arg, varpd_arp_handle_t *vah, int type,
1264     const struct sockaddr *sock, uint8_t *out)
1265 {
1266         svp_t *svp = arg;
1267         svp_lookup_t *svl;
1268 
1269         if (type != VARPD_QTYPE_ETHERNET) {
1270                 libvarpd_plugin_arp_reply(vah, VARPD_LOOKUP_DROP);
1271                 return;
1272         }
1273 
 
 |