--- old/usr/src/lib/varpd/libvarpd/common/libvarpd_overlay.c	Fri Jun 15 17:50:41 2018
+++ new/usr/src/lib/varpd/libvarpd/common/libvarpd_overlay.c	Fri Jun 15 17:50:41 2018
@@ -562,6 +562,34 @@
 }
 
 void
+libvarpd_route_flush(varpd_provider_handle_t *vph, uint8_t *srcip,
+    uint8_t *dstip, uint8_t src_prefixlen, uint8_t dst_prefixlen,
+    uint16_t vlan_id)
+{
+	varpd_instance_t *inst = (varpd_instance_t *)vph;
+	varpd_impl_t *vip = inst->vri_impl;
+	overlay_targ_cache_net_t otcn;
+	overlay_targ_cache_net_entry_t *otcne;
+	int ret;
+
+	otcn.otcn_linkid = inst->vri_linkid;
+	otcne = &otcn.otcn_entry;
+	bcopy(srcip, &otcne->otcne_src, sizeof (in6_addr_t));
+	bcopy(dstip, &otcne->otcne_dst, sizeof (in6_addr_t));
+	otcne->otcne_vlan = vlan_id;
+	otcne->otcne_src_prefixlen = src_prefixlen;
+	otcne->otcne_dst_prefixlen = dst_prefixlen;
+
+	ret = ioctl(vip->vdi_overlayfd, OVERLAY_TARG_CACHE_REMOVE_NET, &otcn);
+	if (ret != 0) {
+		/* XXX KEBE ASKS, any harmless error cases? */
+		libvarpd_panic("received bad errno from "
+		    "OVERLAY_TARG_CACHE_REMOVE_NET: %d - %s", errno,
+		    strerror(errno));
+	}
+}
+
+void
 libvarpd_fma_degrade(varpd_provider_handle_t *vph, const char *msg)
 {
 	int ret;
--- old/usr/src/lib/varpd/libvarpd/common/libvarpd_provider.h	Fri Jun 15 17:50:41 2018
+++ new/usr/src/lib/varpd/libvarpd/common/libvarpd_provider.h	Fri Jun 15 17:50:41 2018
@@ -413,6 +413,8 @@
     const uint8_t *, const struct in_addr *, const uint8_t *);
 extern void libvarpd_fma_degrade(varpd_provider_handle_t *, const char *);
 extern void libvarpd_fma_restore(varpd_provider_handle_t *);
+extern void libvarpd_route_flush(varpd_provider_handle_t *, uint8_t *,
+    uint8_t *, uint8_t, uint8_t, uint16_t vlan_id);
 
 #ifdef __cplusplus
 }
--- old/usr/src/lib/varpd/libvarpd/common/mapfile-plugin	Fri Jun 15 17:50:41 2018
+++ new/usr/src/lib/varpd/libvarpd/common/mapfile-plugin	Fri Jun 15 17:50:41 2018
@@ -55,4 +55,5 @@
 	libvarpd_prop_set_nodefault	{ FLAGS = EXTERN };
 	libvarpd_prop_set_range_uint32	{ FLAGS = EXTERN };
 	libvarpd_prop_set_rangestr	{ FLAGS = EXTERN };
+	libvarpd_route_flush		{ FLAGS = EXTERN };
 };
--- old/usr/src/lib/varpd/libvarpd/common/mapfile-vers	Fri Jun 15 17:50:42 2018
+++ new/usr/src/lib/varpd/libvarpd/common/mapfile-vers	Fri Jun 15 17:50:42 2018
@@ -65,6 +65,8 @@
 	libvarpd_inject_varp;
 	libvarpd_inject_arp;
 
+	libvarpd_route_flush;
+
 	libvarpd_instance_activate;
 	libvarpd_instance_create;
 	libvarpd_instance_destroy;
--- old/usr/src/lib/varpd/svp/common/libvarpd_svp.c	Fri Jun 15 17:50:42 2018
+++ new/usr/src/lib/varpd/svp/common/libvarpd_svp.c	Fri Jun 15 17:50:42 2018
@@ -315,7 +315,7 @@
  *
  * The shoot down information needs to be done on a per-backend basis. The
  * general design is that we'll have a single query for this which can fire on a
- * 5-10s period, we randmoize the latter part to give us a bit more load
+ * 5-10s period, we randomize the latter part to give us a bit more load
  * spreading. If we complete because there's no work to do, then we wait the
  * normal period. If we complete, but there's still work to do, we'll go again
  * after a second.
@@ -542,6 +542,18 @@
 	umem_cache_free(svp_lookup_cache, svl);
 }
 
+/*
+ * Tell the overlay instance to flush out entries matcthing this route.
+ * See libvarpd_route_flush() for more.
+ */
+static void
+svp_route_shootdown_cb(svp_t *svp, uint8_t *srcip, uint8_t *dstip,
+    uint8_t src_prefixlen, uint8_t dst_prefixlen, uint16_t vlan_id)
+{
+	libvarpd_route_flush(svp->svp_hdl, srcip, dstip, src_prefixlen,
+	    dst_prefixlen, vlan_id);
+}
+
 static svp_cb_t svp_defops = {
 	svp_vl2_lookup_cb,
 	svp_vl3_lookup_cb,
@@ -549,6 +561,7 @@
 	svp_vl3_inject_cb,
 	svp_shootdown_cb,
 	svp_route_lookup_cb,
+	svp_route_shootdown_cb
 };
 
 static boolean_t
--- old/usr/src/lib/varpd/svp/common/libvarpd_svp.h	Fri Jun 15 17:50:42 2018
+++ new/usr/src/lib/varpd/svp/common/libvarpd_svp.h	Fri Jun 15 17:50:42 2018
@@ -253,6 +253,8 @@
 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 void (*svp_route_shootdown_f)(svp_t *, uint8_t *, uint8_t *, uint8_t,
+    uint8_t, uint16_t);
 
 typedef struct svp_cb {
 	svp_vl2_lookup_f	scb_vl2_lookup;
@@ -261,6 +263,7 @@
 	svp_vl3_inject_f	scb_vl3_inject;
 	svp_shootdown_f		scb_shootdown;
 	svp_route_lookup_f	scb_route_lookup;
+	svp_route_shootdown_f	scb_route_shootdown;
 } svp_cb_t;
 
 /*
@@ -356,11 +359,13 @@
 extern void svp_remote_shootdown_vl3(svp_remote_t *, svp_log_vl3_t *,
     svp_sdlog_t *);
 extern void svp_remote_shootdown_vl2(svp_remote_t *, svp_log_vl2_t *);
+extern void svp_remote_shootdown_route(svp_remote_t *, svp_log_route_t *);
 extern void svp_remote_log_request(svp_remote_t *, svp_query_t *, void *,
     size_t);
 extern void svp_remote_lrm_request(svp_remote_t *, svp_query_t *, void *,
     size_t);
-extern void svp_shootdown_logr_cb(svp_remote_t *, svp_status_t, void *, size_t);
+extern void svp_shootdown_logr_cb(svp_remote_t *, svp_status_t, void *, size_t,
+    uint16_t);
 extern void svp_shootdown_lrm_cb(svp_remote_t *, svp_status_t);
 extern void svp_shootdown_vl3_cb(svp_status_t, svp_log_vl3_t *, svp_sdlog_t *);
 extern int svp_shootdown_init(svp_remote_t *);
--- old/usr/src/lib/varpd/svp/common/libvarpd_svp_remote.c	Fri Jun 15 17:50:42 2018
+++ new/usr/src/lib/varpd/svp/common/libvarpd_svp_remote.c	Fri Jun 15 17:50:42 2018
@@ -300,7 +300,7 @@
 	 * As of v1 -> v2, we really only need to restrict SVP_R_ROUTE_REQ
 	 * as v2-only.  Reflect that here.
 	 *
-	 * NOTE that if any message semantics change between future versions,
+	 * NOTE that if any message semantics change between versions,
 	 * (e.g. "in v3 SVP_R_VL2_REQ takes on additional work"), we'll
 	 * need to more-deeply inspect the query.  It's possible that the
 	 * svp_op space is big enough to just continue op-only inspections.
@@ -312,6 +312,7 @@
 		sqp->sq_header.svp_ver = htons(version);
 		return (B_TRUE);
 	}
+
 	return (B_FALSE);
 }
 
@@ -541,13 +542,22 @@
 svp_remote_log_request_cb(svp_query_t *sqp, void *arg)
 {
 	svp_remote_t *srp = sqp->sq_arg;
+	uint16_t version;
 
+	/*
+	 * Version in request is set in this sqp's read-data/sq_header by
+	 * now.
+	 */
+	assert(sqp->sq_header.svp_op == htons(SVP_R_LOG_REQ));
+	assert(sqp->sq_header.svp_ver != 0);
+	version = htons(sqp->sq_header.svp_ver);
+
 	assert(sqp->sq_wdata != NULL);
 	if (sqp->sq_status == SVP_S_OK)
 		svp_shootdown_logr_cb(srp, sqp->sq_status, sqp->sq_wdata,
-		    sqp->sq_size);
+		    sqp->sq_size, version);
 	else
-		svp_shootdown_logr_cb(srp, sqp->sq_status, NULL, 0);
+		svp_shootdown_logr_cb(srp, sqp->sq_status, NULL, 0, 0);
 }
 
 void
@@ -584,7 +594,7 @@
 	mutex_exit(&srp->sr_lock);
 
 	if (queued == B_FALSE)
-		svp_shootdown_logr_cb(srp, SVP_S_FATAL, NULL, 0);
+		svp_shootdown_logr_cb(srp, SVP_S_FATAL, NULL, 0, 0);
 }
 
 static void
@@ -631,7 +641,7 @@
 	mutex_exit(&srp->sr_lock);
 
 	if (queued == B_FALSE)
-		svp_shootdown_logr_cb(srp, SVP_S_FATAL, NULL, 0);
+		svp_shootdown_logr_cb(srp, SVP_S_FATAL, NULL, 0, 0);
 }
 
 /* ARGSUSED */
@@ -891,6 +901,21 @@
 		svp->svp_cb.scb_vl2_invalidate(svp, svl2->svl2_mac);
 	}
 	mutex_exit(&srp->sr_lock);
+}
+
+void
+svp_remote_shootdown_route(svp_remote_t *srp, svp_log_route_t *svlr)
+{
+	svp_t *svp, lookup;
+
+	lookup.svp_vid = ntohl(svlr->svlr_src_vnetid);
+	mutex_enter(&srp->sr_lock);
+	if ((svp = avl_find(&srp->sr_tree, &lookup, NULL)) != NULL) {
+		svp->svp_cb.scb_route_shootdown(svp, svlr->svlr_srcip,
+		    svlr->svlr_dstip, svlr->svlr_src_prefixlen,
+		    svlr->svlr_dst_prefixlen, htons(svlr->svlr_src_vlan));
+	}
+	mutex_exit(&srp->sr_lock);
 }
 
 int
--- old/usr/src/lib/varpd/svp/common/libvarpd_svp_shootdown.c	Fri Jun 15 17:50:42 2018
+++ new/usr/src/lib/varpd/svp/common/libvarpd_svp_shootdown.c	Fri Jun 15 17:50:42 2018
@@ -154,7 +154,7 @@
 	svp_remote_t *srp = sdl->sdl_remote;
 	svp_lrm_req_t *svrr = sdl->sdl_logrm;
 
-	if (type != SVP_LOG_VL2 && type != SVP_LOG_VL3)
+	if (type != SVP_LOG_VL2 && type != SVP_LOG_VL3 && type != SVP_LOG_ROUTE)
 		libvarpd_panic("encountered unknown type: %d\n", type);
 
 	if (type == SVP_LOG_VL2) {
@@ -165,12 +165,21 @@
 		    UUID_LEN);
 		svrr->svrr_count++;
 		mutex_exit(&sdl->sdl_lock);
-	} else {
+	} else if (type == SVP_LOG_VL3) {
 		svp_log_vl3_t *svl3 = data;
 
 		/* Take a hold for the duration of this request */
 		svp_shootdown_ref(sdl);
 		svp_remote_shootdown_vl3(srp, svl3, sdl);
+	} else {
+		svp_log_route_t *svlr = data;
+
+		svp_remote_shootdown_route(srp, svlr);
+		mutex_enter(&sdl->sdl_lock);
+		bcopy(svlr->svlr_id, &svrr->svrr_ids[svrr->svrr_count * 16],
+		    UUID_LEN);
+		svrr->svrr_count++;
+		mutex_exit(&sdl->sdl_lock);
 	}
 
 	return (0);
@@ -187,7 +196,7 @@
 
 static int
 svp_shootdown_logr_iter(svp_remote_t *srp, void *buf, size_t len,
-    int (*cb)(void *, svp_log_type_t, void *), void *arg)
+    int (*cb)(void *, svp_log_type_t, void *), void *arg, uint16_t version)
 {
 	int ret;
 	off_t cboff = 0;
@@ -202,6 +211,7 @@
 
 	while (len > 0) {
 		size_t opsz;
+		char *typestring;
 
 		if (len < sizeof (uint32_t)) {
 			(void) bunyan_warn(svp_bunyan,
@@ -216,30 +226,20 @@
 
 		typep = buf + cboff;
 		type = ntohl(*typep);
-		if (type == SVP_LOG_VL2) {
+		switch (type) {
+		case SVP_LOG_VL2:
 			opsz = sizeof (svp_log_vl2_t);
-			if (len < opsz) {
-				(void) bunyan_warn(svp_bunyan,
-				    "not enough data for svp_log_vl2_t",
-				    BUNYAN_T_STRING, "remote_host",
-				    srp->sr_hostname,
-				    BUNYAN_T_INT32, "remote_port",
-				    srp->sr_rport,
-				    BUNYAN_T_INT32, "response_size",
-				    cboff + len,
-				    BUNYAN_T_INT32, "response_offset", cboff,
-				    BUNYAN_T_END);
-				return (-1);
-			}
-			svl2 = (void *)typep;
-			if ((ret = cb(svl2, type, arg)) != 0)
-				return (ret);
-		} else if (type == SVP_LOG_VL3) {
-
+			typestring = "svp_log_vl2_t";
+			break;
+		case SVP_LOG_VL3:
 			opsz = sizeof (svp_log_vl3_t);
-			if (len < opsz) {
+			typestring = "svp_log_vl3_t";
+			break;
+		case SVP_LOG_ROUTE:
+			if (version < SVP_VERSION_TWO) {
 				(void) bunyan_warn(svp_bunyan,
-				    "not enough data for svp_log_vl3_t",
+				    "insufficient version for SVP_LOG_ROUTE",
+				    BUNYAN_T_UINT32, "version", version,
 				    BUNYAN_T_STRING, "remote_host",
 				    srp->sr_hostname,
 				    BUNYAN_T_INT32, "remote_port",
@@ -250,10 +250,10 @@
 				    BUNYAN_T_END);
 				return (-1);
 			}
-			svl3 = (void *)typep;
-			if ((ret = cb(svl3, type, arg)) != 0)
-				return (ret);
-		} else {
+			opsz = sizeof (svp_log_route_t);
+			typestring = "svp_log_route_t";
+			break;
+		default:
 			(void) bunyan_warn(svp_bunyan,
 			    "unknown log structure type",
 			    BUNYAN_T_STRING, "remote_host",
@@ -265,6 +265,20 @@
 			    BUNYAN_T_END);
 			return (-1);
 		}
+		if (len < opsz) {
+			(void) bunyan_warn(svp_bunyan,
+			    "not enough data for",
+			    BUNYAN_T_STRING, "", typestring,
+			    BUNYAN_T_STRING, "remote_host", srp->sr_hostname,
+			    BUNYAN_T_INT32, "remote_port", srp->sr_rport,
+			    BUNYAN_T_INT32, "response_size", cboff + len,
+			    BUNYAN_T_INT32, "response_offset", cboff,
+			    BUNYAN_T_END);
+			return (-1);
+		}
+		if ((ret = cb((void *)typep, type, arg)) != 0)
+			return (ret);
+
 		len -= opsz;
 		cboff += opsz;
 	}
@@ -274,7 +288,7 @@
 
 void
 svp_shootdown_logr_cb(svp_remote_t *srp, svp_status_t status, void *cbdata,
-    size_t cbsize)
+    size_t cbsize, uint16_t version)
 {
 	uint_t count;
 	svp_sdlog_t *sdl = &srp->sr_shoot;
@@ -301,7 +315,7 @@
 	 */
 	count = 0;
 	if ((svp_shootdown_logr_iter(srp, cbdata, cbsize,
-	    svp_shootdown_logr_count, &count)) != 0) {
+		svp_shootdown_logr_count, &count, version)) != 0) {
 		mutex_enter(&sdl->sdl_lock);
 		sdl->sdl_flags &= ~SVP_SD_RUNNING;
 		svp_shootdown_schedule(sdl, B_FALSE);
@@ -337,7 +351,7 @@
 	 * is how many entries we have to remove.
 	 */
 	(void) svp_shootdown_logr_iter(srp, cbdata, cbsize,
-	    svp_shootdown_logr_shoot, sdl);
+	    svp_shootdown_logr_shoot, sdl, version);
 
 	/*
 	 * Now that we're done with our work, release the hold. If we don't have
