diff --git a/drivers/net/ovpn/main.c b/drivers/net/ovpn/main.c
index 2e0420febda0..1c5e9666d7b5 100644
--- a/drivers/net/ovpn/main.c
+++ b/drivers/net/ovpn/main.c
@@ -11,6 +11,7 @@
 #include <linux/genetlink.h>
 #include <linux/module.h>
 #include <linux/netdevice.h>
+#include <linux/list.h>
 #include <linux/inetdevice.h>
 #include <net/gro_cells.h>
 #include <net/ip.h>
@@ -26,6 +27,11 @@
 #include "tcp.h"
 #include "udp.h"
 
+/* Self-destroying devices indexed by their rtnetlink socket identity.
+ * Protected by RTNL.
+ */
+static LIST_HEAD(ovpn_lifeline_list);
+
 static void ovpn_priv_free(struct net_device *net)
 {
 	struct ovpn_priv *ovpn = netdev_priv(net);
@@ -108,6 +114,7 @@ static const struct device_type ovpn_type = {
 static const struct nla_policy ovpn_policy[IFLA_OVPN_MAX + 1] = {
 	[IFLA_OVPN_MODE] = NLA_POLICY_RANGE(NLA_U8, OVPN_MODE_P2P,
 					    OVPN_MODE_MP),
+	[IFLA_OVPN_SELFDESTROY] = { .type = NLA_FLAG },
 };
 
 /**
@@ -174,6 +181,19 @@ static void ovpn_setup(struct net_device *dev)
 	SET_NETDEV_DEVTYPE(dev, &ovpn_type);
 }
 
+static void ovpn_lifeline_detach(struct ovpn_priv *ovpn)
+{
+	ASSERT_RTNL();
+
+	if (!ovpn->lifeline.net)
+		return;
+
+	list_del_init(&ovpn->lifeline.node);
+	put_net(ovpn->lifeline.net);
+	ovpn->lifeline.net = NULL;
+	ovpn->lifeline.portid = 0;
+}
+
 static int ovpn_newlink(struct net_device *dev,
 			struct rtnl_newlink_params *params,
 			struct netlink_ext_ack *extack)
@@ -181,14 +201,33 @@ static int ovpn_newlink(struct net_device *dev,
 	struct ovpn_priv *ovpn = netdev_priv(dev);
 	struct nlattr **data = params->data;
 	enum ovpn_mode mode = OVPN_MODE_P2P;
+	struct net *net = NULL;
+	u32 portid = 0;
+	int err;
 
 	if (data && data[IFLA_OVPN_MODE]) {
 		mode = nla_get_u8(data[IFLA_OVPN_MODE]);
 		netdev_dbg(dev, "setting device mode: %u\n", mode);
 	}
 
+	if (data && data[IFLA_OVPN_SELFDESTROY]) {
+		if (!params->portid) {
+			NL_SET_ERR_MSG(extack,
+				       "self-destroy requires a userspace netlink socket");
+			return -EINVAL;
+		}
+		/* save the identifiers for the NETLINK_URELEASE notification */
+		portid = params->portid;
+		net = get_net(params->src_net);
+		netdev_dbg(dev,
+			   "device will be destroyed when the netlink socket used to create it will be closed\n");
+	}
+
 	ovpn->dev = dev;
 	ovpn->mode = mode;
+	ovpn->lifeline.portid = portid;
+	ovpn->lifeline.net = net;
+	INIT_LIST_HEAD(&ovpn->lifeline.node);
 	spin_lock_init(&ovpn->lock);
 	INIT_DELAYED_WORK(&ovpn->keepalive_work, ovpn_peer_keepalive_work);
 
@@ -205,13 +244,27 @@ static int ovpn_newlink(struct net_device *dev,
 	else
 		netif_carrier_off(dev);
 
-	return register_netdevice(dev);
+	err = register_netdevice(dev);
+	if (err < 0) {
+		if (net)
+			put_net(net);
+		return err;
+	}
+
+	/* expose the device to the notifier only after registration succeeds */
+	if (portid) {
+		ASSERT_RTNL();
+		list_add_tail(&ovpn->lifeline.node, &ovpn_lifeline_list);
+	}
+
+	return 0;
 }
 
 static void ovpn_dellink(struct net_device *dev, struct list_head *head)
 {
 	struct ovpn_priv *ovpn = netdev_priv(dev);
 
+	ovpn_lifeline_detach(ovpn);
 	cancel_delayed_work_sync(&ovpn->keepalive_work);
 	ovpn_peers_free(ovpn, NULL, OVPN_DEL_PEER_REASON_TEARDOWN);
 	unregister_netdevice_queue(dev, head);
@@ -221,8 +274,12 @@ static int ovpn_fill_info(struct sk_buff *skb, const struct net_device *dev)
 {
 	struct ovpn_priv *ovpn = netdev_priv(dev);
 
+	ASSERT_RTNL();
+
 	if (nla_put_u8(skb, IFLA_OVPN_MODE, ovpn->mode))
 		return -EMSGSIZE;
+	if (ovpn->lifeline.net && nla_put_flag(skb, IFLA_OVPN_SELFDESTROY))
+		return -EMSGSIZE;
 
 	return 0;
 }
@@ -239,6 +296,46 @@ static struct rtnl_link_ops ovpn_link_ops = {
 	.fill_info = ovpn_fill_info,
 };
 
+static int ovpn_netlink_notify(struct notifier_block *nb, unsigned long action,
+			       void *data)
+{
+	const struct netlink_notify *notify = data;
+	struct ovpn_lifeline_info *entry, *tmp;
+	struct ovpn_priv *ovpn;
+	LIST_HEAD(unreg_list);
+
+	/* A self-destroying ovpn device uses the rtnetlink socket that created
+	 * it as its lifeline. When that socket is released, delete all ovpn
+	 * devices whose saved socket netns and port ID match the notification.
+	 */
+	if (action != NETLINK_URELEASE || notify->protocol != NETLINK_ROUTE)
+		return NOTIFY_DONE;
+
+	rtnl_lock();
+
+	/* ovpn_dellink removes entry->node, so use the safe iterator */
+	list_for_each_entry_safe(entry, tmp, &ovpn_lifeline_list, node) {
+		if (!net_eq(notify->net, entry->net) ||
+		    entry->portid != notify->portid)
+			continue;
+
+		ovpn = container_of(entry, struct ovpn_priv, lifeline);
+		ovpn_dellink(ovpn->dev, &unreg_list);
+	}
+
+	/* One rtnetlink socket may be the lifeline for multiple ovpn devices
+	 * so unregister the whole list built by ovpn_dellink in a batch.
+	 */
+	unregister_netdevice_many(&unreg_list);
+	rtnl_unlock();
+
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block ovpn_netlink_notifier = {
+	.notifier_call = ovpn_netlink_notify,
+};
+
 static int __init ovpn_init(void)
 {
 	int err = rtnl_link_register(&ovpn_link_ops);
@@ -254,6 +351,13 @@ static int __init ovpn_init(void)
 		goto unreg_rtnl;
 	}
 
+	err = netlink_register_notifier(&ovpn_netlink_notifier);
+	if (err) {
+		pr_err("ovpn: can't register netlink notifier: %d\n", err);
+		ovpn_nl_unregister();
+		goto unreg_rtnl;
+	}
+
 	ovpn_tcp_init();
 
 	return 0;
@@ -265,6 +369,7 @@ static int __init ovpn_init(void)
 
 static __exit void ovpn_cleanup(void)
 {
+	netlink_unregister_notifier(&ovpn_netlink_notifier);
 	ovpn_nl_unregister();
 	rtnl_link_unregister(&ovpn_link_ops);
 
diff --git a/drivers/net/ovpn/ovpnpriv.h b/drivers/net/ovpn/ovpnpriv.h
index 5898f6adada7..788ac7022ae0 100644
--- a/drivers/net/ovpn/ovpnpriv.h
+++ b/drivers/net/ovpn/ovpnpriv.h
@@ -10,6 +10,7 @@
 #ifndef _NET_OVPN_OVPNSTRUCT_H_
 #define _NET_OVPN_OVPNSTRUCT_H_
 
+#include <linux/list.h>
 #include <linux/workqueue.h>
 #include <net/gro_cells.h>
 #include <uapi/linux/if_link.h>
@@ -32,11 +33,24 @@ struct ovpn_peer_collection {
 	struct hlist_nulls_head by_transp_addr[1 << 12];
 };
 
+/**
+ * struct ovpn_lifeline_info - rtnetlink socket identity for self-destruction
+ * @node: entry on the module-wide lifeline list
+ * @net: net namespace of the rtnetlink socket
+ * @portid: port ID of the rtnetlink socket
+ */
+struct ovpn_lifeline_info {
+	struct list_head node;
+	struct net *net;
+	u32 portid;
+};
+
 /**
  * struct ovpn_priv - per ovpn interface state
  * @dev: the actual netdev representing the tunnel
  * @mode: device operation mode (i.e. p2p, mp, ..)
  * @lock: protect this object
+ * @lifeline: rtnetlink socket identity for self-destruction
  * @peers: data structures holding multi-peer references
  * @peer: in P2P mode, this is the only remote peer
  * @gro_cells: pointer to the Generic Receive Offload cell
@@ -46,6 +60,7 @@ struct ovpn_priv {
 	struct net_device *dev;
 	enum ovpn_mode mode;
 	spinlock_t lock; /* protect writing to the ovpn_priv object */
+	struct ovpn_lifeline_info lifeline;
 	struct ovpn_peer_collection *peers;
 	struct ovpn_peer __rcu *peer;
 	struct gro_cells gro_cells;
diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h
index 46413392b402..e503d048891f 100644
--- a/include/uapi/linux/if_link.h
+++ b/include/uapi/linux/if_link.h
@@ -2066,6 +2066,7 @@ enum ovpn_mode {
 enum {
 	IFLA_OVPN_UNSPEC,
 	IFLA_OVPN_MODE,
+	IFLA_OVPN_SELFDESTROY,
 	__IFLA_OVPN_MAX,
 };
 
