[Devel] [PATCH DRAFT vz10 2/5] ve/net/gre: Enable ERSPAN support in Containers under VE_FEATURE_ERSPAN

Konstantin Khorenko khorenko at virtuozzo.com
Wed Aug 12 16:03:58 MSK 2026


Commit a6adc8063402 ("ve/net/gre: Disable ERSPAN support in ip_gre
module") compiled ERSPAN out under CONFIG_VE because it was not wired
into the per-Container GRE infrastructure. Its revert brings the code
back; this commit integrates ERSPAN into the Container framework so it
can be used inside a CT, gated by a dedicated feature bit.

ERSPAN is a Cisco-specific traffic mirroring protocol built on top of
GRE, but it is a separate device type from ip_gre/gretap and has its
own pernet id (erspan_net_id). Reusing VE_FEATURE_IPGRE would tie the
two together, so introduce a standalone VE_FEATURE_ERSPAN bit. It is
disabled by default for Containers (VE_FEATURES_DEF) and enabled for
the host (init_ve has all features set), so host behaviour is
unchanged.

Integration mirrors what is already done for ip_gre/gretap:

 - erspan_setup() marks the device NETIF_F_VIRTUAL so that
   register_netdevice() permits it inside a non-super VE;

 - erspan_init_net() frees its net_generic slot and skips device
   creation when the feature is off, so erspan_net_id is NULL for such
   a CT; the lookup path is already guarded against a NULL itn in
   ip_tunnel_lookup(), so the rx/error paths are safe;

 - device creation and reconfiguration (erspan_newlink/changelink)
   reject the operation with -EACCES when the feature is off, before
   reaching ip_tunnel_newlink() which would dereference the NULL
   net_generic slot.

The VE feature check is dropped from ipgre_newlink_encap_setup() and
done explicitly in each rtnl link operation via ve_feature_set(), so
the ip_gre/gretap paths keep checking VE_FEATURE_IPGRE while the erspan
paths check VE_FEATURE_ERSPAN.

https://virtuozzo.atlassian.net/browse/VSTOR-141173

Feature: net: ERSPAN support in Containers
Signed-off-by: Konstantin Khorenko <khorenko at virtuozzo.com>
---
 include/uapi/linux/vzcalluser.h |  1 +
 net/ipv4/ip_gre.c               | 26 +++++++++++++++++++++-----
 2 files changed, 22 insertions(+), 5 deletions(-)

diff --git a/include/uapi/linux/vzcalluser.h b/include/uapi/linux/vzcalluser.h
index 000e3ee107add..a716e0b41ef30 100644
--- a/include/uapi/linux/vzcalluser.h
+++ b/include/uapi/linux/vzcalluser.h
@@ -49,6 +49,7 @@ struct vzctl_ve_configure {
 #define VE_FEATURE_NFSD		(1ULL << 8)
 #define VE_FEATURE_TIME		(1ULL << 9)
 #define VE_FEATURE_BPF		(1ULL << 10)
+#define VE_FEATURE_ERSPAN	(1ULL << 11)
 
 #define VE_FEATURES_OLD		(VE_FEATURE_SYSFS)
 #define VE_FEATURES_DEF		(VE_FEATURE_SYSFS | VE_FEATURE_DEF_PERMS)
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
index d776eb8d9f76c..b4db5112c3853 100644
--- a/net/ipv4/ip_gre.c
+++ b/net/ipv4/ip_gre.c
@@ -1390,11 +1390,6 @@ ipgre_newlink_encap_setup(struct net_device *dev, struct nlattr *data[])
 {
 	struct ip_tunnel_encap ipencap;
 
-#ifdef CONFIG_VE
-	if (!(dev_net(dev)->owner_ve->features & VE_FEATURE_IPGRE))
-		return -EACCES;
-#endif
-
 	if (ipgre_netlink_encap_parms(data, &ipencap)) {
 		struct ip_tunnel *t = netdev_priv(dev);
 		int err = ip_tunnel_encap_setup(t, &ipencap);
@@ -1414,6 +1409,9 @@ static int ipgre_newlink(struct net *src_net, struct net_device *dev,
 	__u32 fwmark = 0;
 	int err;
 
+	if (!ve_feature_set(dev_net(dev)->owner_ve, IPGRE))
+		return -EACCES;
+
 	err = ipgre_newlink_encap_setup(dev, data);
 	if (err)
 		return err;
@@ -1432,6 +1430,9 @@ static int erspan_newlink(struct net *src_net, struct net_device *dev,
 	__u32 fwmark = 0;
 	int err;
 
+	if (!ve_feature_set(dev_net(dev)->owner_ve, ERSPAN))
+		return -EACCES;
+
 	err = ipgre_newlink_encap_setup(dev, data);
 	if (err)
 		return err;
@@ -1451,6 +1452,9 @@ static int ipgre_changelink(struct net_device *dev, struct nlattr *tb[],
 	__u32 fwmark = t->fwmark;
 	int err;
 
+	if (!ve_feature_set(dev_net(dev)->owner_ve, IPGRE))
+		return -EACCES;
+
 	err = ipgre_newlink_encap_setup(dev, data);
 	if (err)
 		return err;
@@ -1480,6 +1484,9 @@ static int erspan_changelink(struct net_device *dev, struct nlattr *tb[],
 	__u32 fwmark = t->fwmark;
 	int err;
 
+	if (!ve_feature_set(dev_net(dev)->owner_ve, ERSPAN))
+		return -EACCES;
+
 	err = ipgre_newlink_encap_setup(dev, data);
 	if (err)
 		return err;
@@ -1631,6 +1638,9 @@ static void erspan_setup(struct net_device *dev)
 	dev->netdev_ops = &erspan_netdev_ops;
 	dev->priv_flags &= ~IFF_TX_SKB_SHARING;
 	dev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
+#ifdef CONFIG_VE
+	dev->ve_features = NETIF_F_VIRTUAL;
+#endif
 	ip_tunnel_setup(dev, erspan_net_id);
 	t->erspan_ver = 1;
 }
@@ -1776,6 +1786,12 @@ static struct pernet_operations ipgre_tap_net_ops = {
 
 static int __net_init erspan_init_net(struct net *net)
 {
+#ifdef CONFIG_VE
+	if (!(net->owner_ve->features & VE_FEATURE_ERSPAN)) {
+		net_generic_free(net, erspan_net_id);
+		return 0;
+	}
+#endif
 	return ip_tunnel_init_net(net, erspan_net_id,
 				  &erspan_link_ops, "erspan0");
 }
-- 
2.43.0



More information about the Devel mailing list