--- old/usr/src/lib/varpd/svp/common/libvarpd_svp.c	Mon Mar 26 09:58:32 2018
+++ new/usr/src/lib/varpd/svp/common/libvarpd_svp.c	Mon Mar 26 09:58:32 2018
@@ -361,7 +361,7 @@
 	SVP_L_UNKNOWN	= 0x0,
 	SVP_L_VL2	= 0x1,
 	SVP_L_VL3	= 0x2,
-	SVP_L_RVL3	= 0x3
+	SVP_L_ROUTE	= 0x3
 } svp_lookup_type_t;
 
 typedef struct svp_lookup {
@@ -375,11 +375,11 @@
 			varpd_arp_handle_t	*svl_vah;
 			uint8_t			*svl_out;
 		} svl_vl3;
-		struct svl_lookup_rvl3 {
+		struct svl_lookup_route {
 			varpd_query_handle_t	*svl_handle;
 			overlay_target_point_t	*svl_point;
 			overlay_target_route_t	*svl_route;
-		} svl_rvl3;
+		} svl_route;
 	} svl_u;
 	svp_query_t				svl_query;
 } svp_lookup_t;
@@ -390,7 +390,7 @@
 	"svp/underlay_ip",
 	"svp/underlay_port",
 	"svp/dcid",
-	"svp/router_mac"
+	"svp/router_oui"
 };
 
 static const uint8_t svp_bcast[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
@@ -437,8 +437,10 @@
 svp_vl3_lookup_cb(svp_t *svp, svp_status_t status, const uint8_t *vl2mac,
     const struct in6_addr *uip, const uint16_t uport, void *arg)
 {
-	overlay_target_point_t point;
+	/* Initialize address-holders to 0 for comparisons-to-zeroes later. */
+	overlay_target_point_t point = { 0 };
 	svp_lookup_t *svl = arg;
+	uint8_t nexthop_mac[6] = { 0, 0, 0, 0, 0, 0 };
 
 	assert(svp != NULL);
 	assert(svl != NULL);
@@ -451,9 +453,35 @@
 	}
 
 	/* Inject the L2 mapping before the L3 */
-	bcopy(uip, &point.otp_ip, sizeof (struct in6_addr));
-	point.otp_port = uport;
-	libvarpd_inject_varp(svp->svp_hdl, vl2mac, &point);
+	if (uport != 0 &&
+	    bcmp(uip, &point.otp_ip, sizeof (struct in6_addr)) != 0) {
+		/* Normal L3 lookup result... */
+		bcopy(uip, &point.otp_ip, sizeof (struct in6_addr));
+		point.otp_port = uport;
+		libvarpd_inject_varp(svp->svp_hdl, vl2mac, &point);
+	} else {
+		/*
+		 * Oh my, we have a next-hop router IP.
+		 * Set the MAC to the ouid+vid concatenated
+		 * special-router-MAC. Overlay down below will know
+		 * that uport == 0 means the MAC is a special one.
+		 */
+		if (bcmp(svp->svp_router_oui, nexthop_mac, ETHERADDRL) == 0) {
+			/*
+			 * We don't have a router_oui, so we can't support
+			 * special-router-MAC.  Drop it.
+			 */
+			libvarpd_plugin_arp_reply(svl->svl_u.svl_vl3.svl_vah,
+			    VARPD_LOOKUP_DROP);
+			umem_cache_free(svp_lookup_cache, svl);
+			return;
+		}
+		bcopy(svp->svp_router_oui, nexthop_mac, 3);
+		nexthop_mac[3] = (svp->svp_vid >> 16) & 0xff;
+		nexthop_mac[4] = (svp->svp_vid >> 8) & 0xff;
+		nexthop_mac[5] = svp->svp_vid & 0xff;
+		vl2mac = nexthop_mac;
+	}
 
 	bcopy(vl2mac, svl->svl_u.svl_vl3.svl_out, ETHERADDRL);
 	libvarpd_plugin_arp_reply(svl->svl_u.svl_vl3.svl_vah,
@@ -494,13 +522,15 @@
     const uint16_t uport)
 {
 	/*
-	 * We should probably do a conditional invlaidation here.
+	 * We should probably do a conditional invalidation here.
 	 */
 	libvarpd_inject_varp(svp->svp_hdl, vl2mac, NULL);
 }
 
 static void
-svp_rvl3_lookup_cb(svp_t *svp, svp_status_t status, /* XXX KEBE SAYS MORE */
+svp_route_lookup_cb(svp_t *svp, svp_status_t status, uint32_t dcid,
+    uint32_t vnetid, uint16_t vlan, uint8_t *srcmac, uint8_t *dstmac,
+    uint16_t ul3_port, uint8_t *ul3_addr, uint8_t srcpfx, uint8_t dstpfx,
     void *arg)
 {
 	svp_lookup_t *svl = arg;
@@ -508,17 +538,26 @@
 	overlay_target_route_t *otr;
 
 	if (status != SVP_S_OK) {
-		libvarpd_plugin_query_reply(svl->svl_u.svl_rvl3.svl_handle,
+		libvarpd_plugin_query_reply(svl->svl_u.svl_route.svl_handle,
 		    VARPD_LOOKUP_DROP);
 		umem_cache_free(svp_lookup_cache, svl);
 		return;
 	}
 
-	otp = svl->svl_u.svl_rvl3.svl_point;
-	otr = svl->svl_u.svl_rvl3.svl_route;
-	/* XXX KEBE SAYS FILL ME IN! */
+	otp = svl->svl_u.svl_route.svl_point;
+	bcopy(dstmac, otp->otp_mac, ETHERADDRL);
+	bcopy(ul3_addr, &otp->otp_ip, sizeof (struct in6_addr));
+	otp->otp_port = ul3_port;
 
-	libvarpd_plugin_query_reply(svl->svl_u.svl_rvl3.svl_handle,
+	otr = svl->svl_u.svl_route.svl_route;
+	otr->otr_vnet = vnetid;
+	otr->otr_vlan = vlan;
+	bcopy(srcmac, otr->otr_srcmac, ETHERADDRL);
+	otr->otr_dcid = dcid;
+	otr->otr_src_prefixlen = srcpfx;
+	otr->otr_dst_prefixlen = dstpfx;
+
+	libvarpd_plugin_query_reply(svl->svl_u.svl_route.svl_handle,
 	    VARPD_LOOKUP_OK);
 	umem_cache_free(svp_lookup_cache, svl);
 }
@@ -529,7 +568,7 @@
 	svp_vl2_invalidate_cb,
 	svp_vl3_inject_cb,
 	svp_shootdown_cb,
-	svp_rvl3_lookup_cb,
+	svp_route_lookup_cb,
 };
 
 static boolean_t
@@ -637,8 +676,7 @@
 	 * going to query (i.e. no caching up here of actual destinations).
 	 *
 	 * Our existing remote sever (svp_remote), but with the new message
-	 * SVP_R_REMOTE_VL3_REQ.  Our naming of these functions already has
-	 * "remote" in it, but we'll use "rvl3" instead of "vl3".
+	 * SVP_R_ROUTE_REQ.
 	 */
 
 	/* XXX KEBE SAYS DO SOME otl verification too... */
@@ -662,13 +700,12 @@
 		return;
 	}
 
-	slp->svl_type = SVP_L_RVL3;
-	slp->svl_u.svl_rvl3.svl_handle = vqh;
-	slp->svl_u.svl_rvl3.svl_point = otp;
-	slp->svl_u.svl_rvl3.svl_route = otr;
+	slp->svl_type = SVP_L_ROUTE;
+	slp->svl_u.svl_route.svl_handle = vqh;
+	slp->svl_u.svl_route.svl_point = otp;
+	slp->svl_u.svl_route.svl_route = otr;
 
-	/* XXX KEBE SAYS FILL IN ARGS PROPERLY... */
-	svp_remote_rvl3_lookup(svp, &slp->svl_query, src, dst, type,
+	svp_remote_route_lookup(svp, &slp->svl_query, src, dst,
 	    otl->otl_vnetid, (uint16_t)otl->otl_vlan, slp);
 }
 
@@ -800,7 +837,7 @@
 		libvarpd_prop_set_range_uint32(vph, 1, UINT32_MAX - 1);
 		break;
 	case 5:
-		/* svp/router_mac */
+		/* svp/router_oui */
 		libvarpd_prop_set_name(vph, varpd_svp_props[5]);
 		libvarpd_prop_set_prot(vph, OVERLAY_PROP_PERM_RRW);
 		libvarpd_prop_set_type(vph, OVERLAY_PROP_T_ETHER);
@@ -911,16 +948,16 @@
 		return (0);
 	}
 
-	/* svp/router_mac */
+	/* svp/router_oui */
 	if (strcmp(pname, varpd_svp_props[5]) == 0) {
 		if (*sizep < ETHERADDRL)
 			return (EOVERFLOW);
 		mutex_enter(&svp->svp_lock);
 
-		if (ether_is_zero(&svp->svp_router_mac)) {
+		if (ether_is_zero(&svp->svp_router_oui)) {
 			*sizep = 0;
 		} else {
-			bcopy(&svp->svp_router_mac, buf, ETHERADDRL);
+			bcopy(&svp->svp_router_oui, buf, ETHERADDRL);
 			*sizep = ETHERADDRL;
 		}
 
@@ -1029,12 +1066,16 @@
 		return (0);
 	}
 
-	/* svp/router_mac */
+	/* svp/router_oui */
 	if (strcmp(pname, varpd_svp_props[5]) == 0) {
 		if (size < ETHERADDRL)
 			return (EOVERFLOW);
 		mutex_enter(&svp->svp_lock);
-		bcopy(buf, &svp->svp_router_mac, ETHERADDRL);
+		bcopy(buf, &svp->svp_router_oui, ETHERADDRL);
+		/* Zero-out the low three bytes. */
+		svp->svp_router_oui[3] = 0;
+		svp->svp_router_oui[4] = 0;
+		svp->svp_router_oui[5] = 0;
 		mutex_exit(&svp->svp_lock);
 		return (0);
 	}
@@ -1101,12 +1142,13 @@
 		}
 	}
 
-	/* svp/router_mac */
-	if (!ether_is_zero(&svp->svp_router_mac)) {
+	/* svp/router_oui */
+	if (!ether_is_zero(&svp->svp_router_oui)) {
 		char buf[ETHERADDRSTRL];
 
 		/* XXX KEBE SAYS See underlay_ip... */
-		if (ether_ntoa_r(&svp->svp_router_mac, buf) == NULL) {
+		if (ether_ntoa_r((struct ether_addr *)&svp->svp_router_oui,
+		    buf) == NULL) {
 			libvarpd_panic("unexpected ether_ntoa_r failure: %d",
 			    errno);
 		}
@@ -1203,7 +1245,7 @@
 		svp->svp_dcid = 0;
 	}
 
-	/* svp/router_mac */
+	/* svp/router_oui */
 	if ((ret = nvlist_lookup_string(nvp, varpd_svp_props[5],
 	    &etherstr)) != 0) {
 		if (ret != ENOENT) {
@@ -1210,8 +1252,9 @@
 			varpd_svp_destroy(svp);
 			return (ret);
 		}
-		bzero(&svp->svp_router_mac, ETHERADDRL);
-	} else if (ether_aton_r(etherstr, &svp->svp_router_mac) == NULL) {
+		bzero(&svp->svp_router_oui, ETHERADDRL);
+	} else if (ether_aton_r(etherstr,
+	    (struct ether_addr *)&svp->svp_router_oui) == NULL) {
 		libvarpd_panic("unexpected ether_aton_r failure: %d", errno);
 	}
 
--- old/usr/src/lib/varpd/svp/common/libvarpd_svp.h	Mon Mar 26 09:58:32 2018
+++ new/usr/src/lib/varpd/svp/common/libvarpd_svp.h	Mon Mar 26 09:58:32 2018
@@ -74,8 +74,8 @@
 	svp_vl3_ack_t	sdq_vl3a;
 	svp_log_req_t	sdq_logr;
 	svp_lrm_ack_t	sdq_lrma;
-	svp_rvl3_req_t	sqd_rvl3r;
-	svp_rvl3_ack_t	sqd_rvl3a;
+	svp_route_req_t	sqd_rr;
+	svp_route_ack_t	sqd_ra;
 } svp_query_data_t;
 
 typedef void (*svp_query_f)(svp_query_t *, void *);
@@ -247,8 +247,9 @@
     const struct in6_addr *, const uint8_t *, const uint8_t *);
 typedef void (*svp_shootdown_f)(svp_t *, const uint8_t *,
     const struct in6_addr *, const uint16_t uport);
-/* XXX KEBE SAYS FILL ME IN! */
-typedef void (*svp_rvl3_lookup_f)(svp_t *, svp_status_t, void *);
+typedef void (*svp_route_lookup_f)(svp_t *, svp_status_t, uint32_t, uint32_t,
+    uint16_t, uint8_t *, uint8_t *, uint16_t, uint8_t *, uint8_t, uint8_t,
+    void *);
 
 typedef struct svp_cb {
 	svp_vl2_lookup_f	scb_vl2_lookup;
@@ -256,7 +257,7 @@
 	svp_vl2_invalidation_f	scb_vl2_invalidate;
 	svp_vl3_inject_f	scb_vl3_inject;
 	svp_shootdown_f		scb_shootdown;
-	svp_rvl3_lookup_f	scb_rvl3_lookup;
+	svp_route_lookup_f	scb_route_lookup;
 } svp_cb_t;
 
 /*
@@ -276,7 +277,8 @@
 	uint32_t		svp_dcid;	/* svp_lock (but write-once?) */
 	boolean_t		svp_huip;	/* svp_lock */
 	struct in6_addr		svp_uip;	/* svp_lock */
-	struct ether_addr	svp_router_mac;	/* svp_lock (but write-once?) */
+	/* NOTE: lower-3 bytes are 0s. */
+	uint8_t		svp_router_oui[6];	/* svp_lock (but write-once?) */
 };
 
 extern bunyan_logger_t *svp_bunyan;
@@ -290,8 +292,8 @@
     const struct sockaddr *, void *);
 extern void svp_remote_vl2_lookup(svp_t *, svp_query_t *, const uint8_t *,
     void *);
-extern void svp_remote_rvl3_lookup(svp_t *, svp_query_t *,
-    const struct in6_addr *, const struct in6_addr *, uint32_t, uint32_t,
+extern void svp_remote_route_lookup(svp_t *, svp_query_t *,
+    const struct in6_addr *, const struct in6_addr *, uint32_t,
     uint16_t, void *);
 
 
--- old/usr/src/lib/varpd/svp/common/libvarpd_svp_prot.h	Mon Mar 26 09:58:33 2018
+++ new/usr/src/lib/varpd/svp/common/libvarpd_svp_prot.h	Mon Mar 26 09:58:33 2018
@@ -61,8 +61,8 @@
 	SVP_R_LOG_RM		= 0x0B,
 	SVP_R_LOG_RM_ACK	= 0x0C,
 	SVP_R_SHOOTDOWN		= 0x0D,
-	SVP_R_REMOTE_VL3_REQ	= 0x0E,
-	SVP_R_REMOTE_VL3_ACK	= 0x0F
+	SVP_R_ROUTE_REQ		= 0x0E,
+	SVP_R_ROUTE_ACK		= 0x0F
 } svp_op_t;
 
 typedef enum svp_status {
@@ -74,7 +74,7 @@
 } svp_status_t;
 
 /*
- * A client issues the SVP_R_VL2_REQ whenever it needs to perform a VLS->UL3
+ * A client issues the SVP_R_VL2_REQ whenever it needs to perform a VL2->UL3
  * lookup. Requests have the following structure:
  */
 typedef struct svp_vl2_req {
@@ -124,34 +124,6 @@
 } svp_vl3_ack_t;
 
 /*
- * A client issues the SVP_R_REMOTE_VL3_REQ for a far-remote (cross-DC) VL3 IP
- * address.  The server may take longer because it may query cross-DC to get
- * the answer for our response.
- */
-typedef struct svp_rvl3_req {
-	uint8_t		srl3r_srcip[16];
-	uint8_t		srl3r_dstip[16];
-	uint32_t	srl3r_type;	/* Same as SVP_R_VL3_REQ */
-	uint32_t	srl3r_vnetid;
-	uint16_t	srl3r_vlan;
-	uint16_t	srl3r_pad;	/* XXX KEBE ASKS, necessary? */
-} svp_rvl3_req_t;
-
-/*
- * The remote-VL3 response contains more than the regular VL3 one, because
- * overlay needs to rewrite the MAC header completely.
- */
-typedef struct svp_rvl3_ack {
-	uint32_t	srl3a_status;
-	uint8_t		srl3a_dstmac[ETHERADDRL]; /* MAC of the target. */
-	uint8_t		srl3a_srcmac[ETHERADDRL]; /* MAC of the target's rtr */
-	uint16_t	srl3a_vlanid;
-	uint16_t	srl3a_uport;
-	uint32_t	srl3a_dcid;	/* Remote Data Center ID. */
-	uint8_t		srl3a_uip[16];
-} svp_rvl3_ack_t;
-
-/*
  * SVP_R_BULK_REQ requests a bulk dump of data. Currently we have two kinds of
  * data tables that we need to dump: VL3->VL2 mappings and VL2->UL3 mappings.
  * The kind that we want is indicated using the svbr_type member.
@@ -261,6 +233,38 @@
 	uint32_t	svsd_vnetid;
 } svp_shootdown_t;
 
+/*
+ * A route-request (SVP_R_ROUTE_REQ) queries the local SVP server to get a
+ * far-remote (i.e. another Triton Data Center, nee. SDC) SVP server for
+ * far-remote networks.  Modern overlay modules will request IP destinations
+ * for remote-Triton networks, but they must know how to reach the
+ * remote-Triton SVP server.
+ */
+typedef struct svp_route_req {
+	uint32_t	srr_vnetid;	/* Requester's vnet ID. */
+	uint16_t	srr_vlan;	/* Requester's VLAN ID. */
+	uint16_t	srr_pad;	/* Zero on xmit, ignore on receipt. */
+	uint8_t		srr_srcip[16];	/* VL3 Source IP. */
+	uint8_t		srr_dstip[16];	/* VL3 Destination IP. */
+} svp_route_req_t;
+
+/*
+ * The far-remote Triton Data Center will answer with the requisite information
+ * to send overlay packets to the appropriate far-remote CNs.
+ */
+typedef struct svp_route_ack {
+	uint32_t	sra_status;	/* Status. */
+	uint32_t	sra_dcid;	/* Far-remote Data Center ID. */
+	uint32_t	sra_vnetid;	/* Far-remote vnet ID. */
+	uint16_t	sra_vlan;	/* Far-remote VLAN ID. */
+	uint16_t	sra_port;	/* Destination UL3 port. */
+	uint8_t		sra_ip[16];	/* Destination UL3 address. */
+	uint8_t	sra_srcmac[ETHERADDRL];	/* Far-remote VL2 source. */
+	uint8_t	sra_dstmac[ETHERADDRL];	/* Far-remote VL2 dest. */
+	uint8_t		sra_src_pfx;	/* Far-remote VL3 source prefix */
+	uint8_t		sra_dst_pfx;	/* Far-remote VL3 dest. prefix */
+} svp_route_ack_t;
+
 #ifdef __cplusplus
 }
 #endif
--- old/usr/src/lib/varpd/svp/common/libvarpd_svp_remote.c	Mon Mar 26 09:58:33 2018
+++ new/usr/src/lib/varpd/svp/common/libvarpd_svp_remote.c	Mon Mar 26 09:58:33 2018
@@ -245,8 +245,8 @@
 		libvarpd_panic("missing callback scb_vl2_invalidate");
 	if (svp->svp_cb.scb_vl3_inject == NULL)
 		libvarpd_panic("missing callback scb_vl3_inject");
-	if (svp->svp_cb.scb_rvl3_lookup == NULL)
-		libvarpd_panic("missing callback scb_rvl3_lookup");
+	if (svp->svp_cb.scb_route_lookup == NULL)
+		libvarpd_panic("missing callback scb_route_lookup");
 
 	check.svp_vid = svp->svp_vid;
 	if (avl_find(&srp->sr_tree, &check, &where) != NULL)
@@ -354,48 +354,51 @@
 }
 
 static void
-svp_remote_rvl3_lookup_cb(svp_query_t *sqp, void *arg)
+svp_remote_route_lookup_cb(svp_query_t *sqp, void *arg)
 {
 	svp_t *svp = sqp->sq_svp;
-	svp_rvl3_ack_t *rvl3a = (svp_rvl3_ack_t *)sqp->sq_wdata;
+	svp_route_ack_t *sra = (svp_route_ack_t *)sqp->sq_wdata;
 
 	if (sqp->sq_status == SVP_S_OK) {
-		svp->svp_cb.scb_rvl3_lookup(svp, sqp->sq_status,
-		    /* XXX KEBE SAYS MORE HERE */ arg);
+		svp->svp_cb.scb_route_lookup(svp, sqp->sq_status,
+		    sra->sra_dcid, sra->sra_vnetid, sra->sra_vlan,
+		    sra->sra_srcmac, sra->sra_dstmac, sra->sra_port,
+		    sra->sra_ip, sra->sra_src_pfx, sra->sra_dst_pfx, arg);
 	} else {
+		svp->svp_cb.scb_route_lookup(svp, sqp->sq_status,
+		    0, 0, 0, NULL, NULL, 0, NULL, 0, 0, arg);
 	}
 }
 
 void
-svp_remote_rvl3_lookup(svp_t *svp, svp_query_t *sqp, const struct in6_addr *src,
-    const struct in6_addr *dst, uint32_t type, uint32_t vnetid, uint16_t vlan,
-    void *arg)
+svp_remote_route_lookup(svp_t *svp, svp_query_t *sqp,
+    const struct in6_addr *src, const struct in6_addr *dst, uint32_t vnetid,
+    uint16_t vlan, void *arg)
 {
 	svp_remote_t *srp;
-	svp_rvl3_req_t *rvl3r = &sqp->sq_rdun.sqd_rvl3r;
+	svp_route_req_t *srr = &sqp->sq_rdun.sqd_rr;
 
 	srp = svp->svp_remote;
-	sqp->sq_func = svp_remote_rvl3_lookup_cb;
+	sqp->sq_func = svp_remote_route_lookup_cb;
 	sqp->sq_arg = arg;
 	sqp->sq_svp = svp;
 	sqp->sq_state = SVP_QUERY_INIT;
 	sqp->sq_header.svp_ver = htons(SVP_CURRENT_VERSION);
-	sqp->sq_header.svp_op = htons(SVP_R_REMOTE_VL3_REQ);
-	sqp->sq_header.svp_size = htonl(sizeof (svp_vl2_req_t));
+	sqp->sq_header.svp_op = htons(SVP_R_ROUTE_REQ);
+	sqp->sq_header.svp_size = htonl(sizeof (svp_route_req_t));
 	sqp->sq_header.svp_id = id_alloc(svp_idspace);
 	if (sqp->sq_header.svp_id == (id_t)-1)
 		libvarpd_panic("failed to allcoate from svp_idspace: %d",
 		    errno);
 	sqp->sq_header.svp_crc32 = htonl(0);
-	sqp->sq_rdata = rvl3r;
+	sqp->sq_rdata = srr;
 
-	bcopy(src, rvl3r->srl3r_srcip, sizeof (struct in6_addr));
-	bcopy(dst, rvl3r->srl3r_dstip, sizeof (struct in6_addr));
+	bcopy(src, srr->srr_srcip, sizeof (struct in6_addr));
+	bcopy(dst, srr->srr_dstip, sizeof (struct in6_addr));
 	/* Caller should've checked both are the same type... */
-	rvl3r->srl3r_type = type;
-	rvl3r->srl3r_vnetid = vnetid;
-	rvl3r->srl3r_vlan = vlan;
-	rvl3r->srl3r_pad = 0;
+	srr->srr_vnetid = vnetid;
+	srr->srr_vlan = vlan;
+	srr->srr_pad = 0;
 
 	mutex_enter(&srp->sr_lock);
 	if (!svp_remote_conn_queue(srp, sqp)) {
