From mboxrd@z Thu Jan 1 00:00:00 1970 From: Konstantin Khorenko Date: Wed, 12 Aug 2026 15:04:01 +0200 Subject: [Devel] [PATCH DRAFT vz10 5/5] ve/net/ip6_gre: Enable ip6erspan support in Containers under VE_FEATURE_ERSPAN In-Reply-To: <20260812130401.154702-1-khorenko@virtuozzo.com> References: <20260812130401.154702-1-khorenko@virtuozzo.com> Message-ID: <20260812130401.154702-6-khorenko@virtuozzo.com> List-Id: Mirror the IPv4 ERSPAN containerization for IPv6. ip6erspan shares the per-net state (ip6gre_net_id / struct ip6gre_net) and the fallback device gating with ip6gre/ip6gretap, so unlike IPv4 it cannot use a separate pernet id. Instead the shared ign is allocated whenever either VE_FEATURE_IPGRE or VE_FEATURE_ERSPAN is set for the Container, and each rtnl link operation checks its own feature bit via ve_feature_set(). Changes: - ip6gre_init_net() keeps the ign net_generic slot when the CT has VE_FEATURE_IPGRE *or* VE_FEATURE_ERSPAN; otherwise the slot is freed and lookups keep returning NULL as before. - ip6erspan_tap_setup() marks the device NETIF_F_VIRTUAL so that register_netdevice() permits it inside a non-super VE. - ip6gre_newlink()/ip6gre_changelink() now explicitly require VE_FEATURE_IPGRE, and ip6erspan_newlink()/ip6erspan_changelink() require VE_FEATURE_ERSPAN. Since the shared ign may now exist due to either feature, the previous implicit "ign == NULL means no IPGRE" gate is no longer sufficient to tell the two apart, so the per-op feature check is mandatory. The checks sit at the top of each op, before any ign dereference. ERSPAN stays disabled by default for Containers (VE_FEATURES_DEF) and enabled for the host (init_ve has all features), so host behaviour is unchanged. https://virtuozzo.atlassian.net/browse/VSTOR-141173 Feature: net: ERSPAN support in Containers Signed-off-by: Konstantin Khorenko --- net/ipv6/ip6_gre.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c index fe867528a0c5b..ffc1830abed00 100644 --- a/net/ipv6/ip6_gre.c +++ b/net/ipv6/ip6_gre.c @@ -1627,7 +1627,8 @@ static int __net_init ip6gre_init_net(struct net *net) int err; #ifdef CONFIG_VE - if (!(net->owner_ve->features & VE_FEATURE_IPGRE)) { + if (!ve_feature_set(net->owner_ve, IPGRE) && + !ve_feature_set(net->owner_ve, ERSPAN)) { net_generic_free(net, ip6gre_net_id); return 0; } @@ -2042,14 +2043,12 @@ static int ip6gre_newlink(struct net *src_net, struct net_device *dev, struct ip6gre_net *ign; int err; + if (!ve_feature_set(dev_net(dev)->owner_ve, IPGRE)) + return -EACCES; + ip6gre_netlink_parms(data, &nt->parms); ign = net_generic(net, ip6gre_net_id); -#ifdef CONFIG_VE - if (!ign) /* no VE_FEATURE_IPGRE */ - return -EACCES; -#endif - if (nt->parms.collect_md) { if (rtnl_dereference(ign->collect_md_tun)) return -EEXIST; @@ -2109,6 +2108,9 @@ static int ip6gre_changelink(struct net_device *dev, struct nlattr *tb[], struct ip6gre_net *ign = net_generic(t->net, ip6gre_net_id); struct __ip6_tnl_parm p; + if (!ve_feature_set(dev_net(dev)->owner_ve, IPGRE)) + return -EACCES; + t = ip6gre_changelink_common(dev, tb, data, &p, extack); if (IS_ERR(t)) return PTR_ERR(t); @@ -2271,6 +2273,9 @@ static void ip6erspan_tap_setup(struct net_device *dev) dev->pcpu_stat_type = NETDEV_PCPU_STAT_TSTATS; dev->priv_flags &= ~IFF_TX_SKB_SHARING; dev->priv_flags |= IFF_LIVE_ADDR_CHANGE; +#ifdef CONFIG_VE + dev->ve_features = NETIF_F_VIRTUAL; +#endif netif_keep_dst(dev); } @@ -2283,15 +2288,13 @@ static int ip6erspan_newlink(struct net *src_net, struct net_device *dev, struct ip6gre_net *ign; int err; + if (!ve_feature_set(dev_net(dev)->owner_ve, ERSPAN)) + return -EACCES; + ip6gre_netlink_parms(data, &nt->parms); ip6erspan_set_version(data, &nt->parms); ign = net_generic(net, ip6gre_net_id); -#ifdef CONFIG_VE - if (!ign) /* no VE_FEATURE_IPGRE */ - return -EACCES; -#endif - if (nt->parms.collect_md) { if (rtnl_dereference(ign->collect_md_tun_erspan)) return -EEXIST; @@ -2331,6 +2334,9 @@ static int ip6erspan_changelink(struct net_device *dev, struct nlattr *tb[], struct __ip6_tnl_parm p; struct ip6_tnl *t; + if (!ve_feature_set(dev_net(dev)->owner_ve, ERSPAN)) + return -EACCES; + t = ip6gre_changelink_common(dev, tb, data, &p, extack); if (IS_ERR(t)) return PTR_ERR(t); -- 2.43.0