From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from gate001.proxmox.com (gate001.proxmox.com [45.144.208.40]) by lore.proxmox.com (Postfix) with ESMTPS id 965F51FF0DF for ; Fri, 28 Aug 2026 15:47:15 +0200 (CEST) Received: from gate001.proxmox.com (localhost.localdomain [127.0.0.1]) by gate001.proxmox.com (Proxmox) with ESMTP id B56FA2153C; Fri, 28 Aug 2026 15:47:14 +0200 (CEST) From: Hannes Laimer To: pve-devel@lists.proxmox.com Subject: [PATCH ifupdown2] d/patches: add support for VXLAN-GBP flag Date: Fri, 28 Aug 2026 15:47:08 +0200 Message-ID: <20260828134708.692354-1-h.laimer@proxmox.com> X-Mailer: git-send-email 2.47.3 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Bm-Milter-Handled: 55990f41-d878-4baa-be0a-ee34c49e34d2 X-Bm-Transport-Timestamp: 1787924819695 X-SPAM-LEVEL: Spam detection results: 0 AWL 0.875 Adjusted score from AWL reputation of From: address DMARC_MISSING 0.1 Missing DMARC policy KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment (newer systems) RCVD_IN_DNSWL_MED -2.3 Sender listed at https://www.dnswl.org/, medium trust SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record Message-ID-Hash: 4FSIWXERDB7GYA3V2W4W43BHCAJALVP6 X-Message-ID-Hash: 4FSIWXERDB7GYA3V2W4W43BHCAJALVP6 X-MailFrom: h.laimer@proxmox.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.10 Precedence: list List-Id: Proxmox VE development discussion List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: Add a vxlan-gbp attribute, threading the GBP netlink flag through the netlink and iproute2 create paths, to enable VXLAN-GBP on a VXLAN interface. The flag is create-only, so it is only set on create, with a warning when a running device diverges. As it is encoded by presence, ifquery matches a configured "off" against an absent flag. Signed-off-by: Hannes Laimer --- this was originally part of the microseg series[1], but this also makes sense standalone, and since that series is large enough as is, I decided to send this one on its own changes since the original: - use `self.__get_vxlan_attribute`, so policy.d default are respected - minor wording changes [1] https://lore.proxmox.com/pve-devel/20260709091852.538885-12-h.laimer@proxmox.com/ ...addons-vxlan-add-vxlan-gbp-attribute.patch | 228 ++++++++++++++++++ debian/patches/series | 1 + 2 files changed, 229 insertions(+) create mode 100644 debian/patches/pve/0016-addons-vxlan-add-vxlan-gbp-attribute.patch diff --git a/debian/patches/pve/0016-addons-vxlan-add-vxlan-gbp-attribute.patch b/debian/patches/pve/0016-addons-vxlan-add-vxlan-gbp-attribute.patch new file mode 100644 index 0000000..e671fac --- /dev/null +++ b/debian/patches/pve/0016-addons-vxlan-add-vxlan-gbp-attribute.patch @@ -0,0 +1,228 @@ +From 48fbd1d9d7e9d1e4c9682468ca2dac90d137e33f Mon Sep 17 00:00:00 2001 +From: Hannes Laimer +Date: Fri, 28 Aug 2026 14:42:05 +0200 +Subject: [PATCH] addons: vxlan: add vxlan-gbp attribute + +Add a vxlan-gbp attribute, threading the GBP netlink flag through the +netlink and iproute2 create paths. The flag is create-only, so it is only +set on create, with a warning when a running device diverges. Being +encoded by presence, ifquery matches a configured "off" against an absent +flag. + +Signed-off-by: Hannes Laimer +--- + ifupdown2/addons/vxlan.py | 56 +++++++++++++++++++++++++++++++-- + ifupdown2/lib/iproute2.py | 14 +++++++-- + ifupdown2/nlmanager/nlpacket.py | 20 ++++++++++++ + 3 files changed, 85 insertions(+), 5 deletions(-) + +diff --git a/ifupdown2/addons/vxlan.py b/ifupdown2/addons/vxlan.py +index bb1a6ca..1e1fda3 100644 +--- a/ifupdown2/addons/vxlan.py ++++ b/ifupdown2/addons/vxlan.py +@@ -145,7 +145,14 @@ class vxlan(Vxlan, moduleBase): + "help": "L3 VxLAN interface (vni list and range are supported)", + "validvals": [""], + "example": ["vxlan-vni 42"] +- } ++ }, ++ "vxlan-gbp": { ++ "help": "enable VXLAN Group Based Policy, create-only since the" ++ " kernel cannot toggle it on a running vxlan device", ++ "validvals": ["yes", "no", "on", "off"], ++ "default": "no", ++ "example": ["vxlan-gbp yes"], ++ }, + } + } + +@@ -908,6 +915,28 @@ class vxlan(Vxlan, moduleBase): + self.logger.info("%s: set vxlan-learning %s" % (ifaceobj.name, "on" if vxlan_learning else "off")) + user_request_vxlan_info_data[Link.IFLA_VXLAN_LEARNING] = vxlan_learning + ++ def __config_vxlan_gbp(self, ifaceobj, link_exists, user_request_vxlan_info_data, cached_vxlan_ifla_info_data): ++ vxlan_gbp_str = self.__get_vxlan_attribute(ifaceobj, "vxlan-gbp") ++ if not vxlan_gbp_str: ++ return ++ ++ vxlan_gbp = utils.get_boolean_from_string(vxlan_gbp_str) ++ cached_gbp = bool(cached_vxlan_ifla_info_data.get(Link.IFLA_VXLAN_GBP)) ++ ++ if link_exists and vxlan_gbp != cached_gbp: ++ # IFLA_VXLAN_GBP is a NLA_FLAG and the kernel only honors it at ++ # device creation, changing it on a running vxlan is rejected. ++ self.logger.warning( ++ "%s: vxlan-gbp can only be set at vxlan device creation," ++ " recreate the interface to change it (current %s, requested %s)" ++ % (ifaceobj.name, "on" if cached_gbp else "off", "on" if vxlan_gbp else "off") ++ ) ++ return ++ ++ if vxlan_gbp and not link_exists: ++ self.logger.info("%s: set vxlan-gbp on" % ifaceobj.name) ++ user_request_vxlan_info_data[Link.IFLA_VXLAN_GBP] = True ++ + def __config_vxlan_udp_csum(self, ifaceobj, link_exists, user_request_vxlan_info_data, cached_vxlan_ifla_info_data): + vxlan_udp_csum = ifaceobj.get_attr_value_first('vxlan-udp-csum') + +@@ -1111,6 +1140,7 @@ class vxlan(Vxlan, moduleBase): + self.__config_vxlan_id(ifname, ifaceobj, vxlan_id_str, user_request_vxlan_info_data, cached_vxlan_ifla_info_data) + + self.__config_vxlan_learning(ifaceobj, link_exists, user_request_vxlan_info_data, cached_vxlan_ifla_info_data) ++ self.__config_vxlan_gbp(ifaceobj, link_exists, user_request_vxlan_info_data, cached_vxlan_ifla_info_data) + self.__config_vxlan_ageing(ifname, ifaceobj, link_exists, user_request_vxlan_info_data, cached_vxlan_ifla_info_data) + self.__config_vxlan_port(ifname, ifaceobj, link_exists, user_request_vxlan_info_data, cached_vxlan_ifla_info_data) + vxlan_ttl = self.__config_vxlan_ttl(ifname, ifaceobj, user_request_vxlan_info_data, cached_vxlan_ifla_info_data) +@@ -1182,7 +1212,8 @@ class vxlan(Vxlan, moduleBase): + user_request_vxlan_info_data.get(Link.IFLA_VXLAN_PORT), + vxlan_vnifilter, + vxlan_ttl, +- local.version if local else 4 ++ local.version if local else 4, ++ gbp=bool(user_request_vxlan_info_data.get(Link.IFLA_VXLAN_GBP)) + ) + elif ifaceobj.link_privflags & ifaceLinkPrivFlags.L3VXI: + self.iproute2.link_add_l3vxi( +@@ -1193,7 +1224,8 @@ class vxlan(Vxlan, moduleBase): + vxlan_physdev, + user_request_vxlan_info_data.get(Link.IFLA_VXLAN_PORT), + vxlan_ttl, +- local.version if local else 4 ++ local.version if local else 4, ++ gbp=bool(user_request_vxlan_info_data.get(Link.IFLA_VXLAN_GBP)) + ) + else: + try: +@@ -1514,6 +1546,23 @@ class vxlan(Vxlan, moduleBase): + else: + ifaceobjcurr.update_config_with_status(vxlan_attr_str, cached_vxlan_attr_value or 'None', 1) + ++ # ++ # vxlan-gbp ++ # ++ # IFLA_VXLAN_GBP is a NLA_FLAG, so the attribute is present when on ++ # and absent when off. A missing cached value must compare equal to ++ # "off", which the generic string compare above cannot express, ++ # hence the dedicated check here. ++ # ++ vxlan_gbp_str = self.__get_vxlan_attribute(ifaceobj, "vxlan-gbp") ++ if vxlan_gbp_str: ++ vxlan_gbp = utils.get_boolean_from_string(vxlan_gbp_str) ++ cached_gbp = bool(cached_vxlan_ifla_info_data.get(Link.IFLA_VXLAN_GBP)) ++ if vxlan_gbp == cached_gbp: ++ ifaceobjcurr.update_config_with_status('vxlan-gbp', vxlan_gbp_str, 0) ++ else: ++ ifaceobjcurr.update_config_with_status('vxlan-gbp', 'on' if cached_gbp else 'off', 1) ++ + # + # vxlan-local-tunnelip + # +@@ -1722,6 +1771,7 @@ class vxlan(Vxlan, moduleBase): + ('vxlan-ageing', Link.IFLA_VXLAN_AGEING, str), + ('vxlan-learning', Link.IFLA_VXLAN_LEARNING, lambda value: 'on' if value else 'off'), + ('vxlan-udp-csum', Link.IFLA_VXLAN_UDP_CSUM, lambda value: 'on' if value else 'off'), ++ ('vxlan-gbp', Link.IFLA_VXLAN_GBP, lambda value: 'on' if value else 'off'), + ('vxlan-local-tunnelip', Link.IFLA_VXLAN_LOCAL, str), + ('vxlan-local-tunnelip', Link.IFLA_VXLAN_LOCAL6, str), + ): +diff --git a/ifupdown2/lib/iproute2.py b/ifupdown2/lib/iproute2.py +index 15b581e..c5268ed 100644 +--- a/ifupdown2/lib/iproute2.py ++++ b/ifupdown2/lib/iproute2.py +@@ -280,7 +280,7 @@ class IPRoute2(Cache, Requirements): + + ### + +- def link_add_single_vxlan(self, link_exists, ifname, ip, group, physdev, port, vnifilter="off", ttl=None, ipversion=4): ++ def link_add_single_vxlan(self, link_exists, ifname, ip, group, physdev, port, vnifilter="off", ttl=None, ipversion=4, gbp=False): + cmd = [] + + if ipversion == 6: +@@ -303,6 +303,11 @@ class IPRoute2(Cache, Requirements): + if vnifilter and utils.get_boolean_from_string(vnifilter): + cmd.append("vnifilter") + ++ # GBP, like vnifilter, is a create-only flag and cannot be ++ # toggled on a running device. ++ if gbp: ++ cmd.append("gbp") ++ + if ip: + cmd.append("local %s" % ip) + +@@ -321,7 +326,7 @@ class IPRoute2(Cache, Requirements): + self.__execute_or_batch(utils.ip_cmd, " ".join(cmd)) + self.__update_cache_after_link_creation(ifname, "vxlan") + +- def link_add_l3vxi(self, link_exists, ifname, ip, group, physdev, port, ttl=None, ipversion=4): ++ def link_add_l3vxi(self, link_exists, ifname, ip, group, physdev, port, ttl=None, ipversion=4, gbp=False): + self.logger.info("creating l3vxi device: %s" % ifname) + + cmd = [] +@@ -343,6 +348,11 @@ class IPRoute2(Cache, Requirements): + # So we are only setting this attribute on vxlan creation + cmd.append("link add dev %s type vxlan external vnifilter" % ifname) + ++ # GBP, like vnifilter, is a create-only flag and cannot be ++ # toggled on a running device. ++ if gbp: ++ cmd.append("gbp") ++ + if ip: + cmd.append("local %s" % ip) + +diff --git a/ifupdown2/nlmanager/nlpacket.py b/ifupdown2/nlmanager/nlpacket.py +index c3b0b67..298c641 100644 +--- a/ifupdown2/nlmanager/nlpacket.py ++++ b/ifupdown2/nlmanager/nlpacket.py +@@ -1043,6 +1043,11 @@ class Attribute(object): + return obj(self.value) + return self.value + ++ @staticmethod ++ def decode_flag_attribute(data, _=None): ++ # NLA_FLAG, presence alone means True ++ return True ++ + @staticmethod + def decode_one_byte_attribute(data, _=None): + # we don't need to use the unpack function because bytes are a list of ints +@@ -1146,6 +1151,15 @@ class Attribute(object): + sub_attr_pack_layout.append("Bxxx") + sub_attr_payload.append(info_data_value) + ++ @staticmethod ++ def encode_flag_attribute(sub_attr_pack_layout, sub_attr_payload, info_data_type, info_data_value): ++ # NLA_FLAG carries no payload, presence alone encodes True. ++ if not info_data_value: ++ return ++ sub_attr_pack_layout.append("HH") ++ sub_attr_payload.append(4) # header-only length ++ sub_attr_payload.append(info_data_type) ++ + @staticmethod + def encode_bond_xmit_hash_policy_attribute(sub_attr_pack_layout, sub_attr_payload, info_data_type, info_data_value): + return Attribute.encode_one_byte_attribute( +@@ -2337,6 +2351,9 @@ class AttributeIFLA_LINKINFO(Attribute): + NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_VXLAN_REMCSUM_RX: Attribute.decode_one_byte_attribute, + NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_VXLAN_REPLICATION_TYPE: Attribute.decode_one_byte_attribute, + ++ # flag attributes (zero-length) ################################ ++ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_VXLAN_GBP: Attribute.decode_flag_attribute, ++ + # 2 bytes network byte order attributes ######################## + NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_VXLAN_PORT: Attribute.decode_two_bytes_network_byte_order_attribute, + +@@ -2678,6 +2695,9 @@ class AttributeIFLA_LINKINFO(Attribute): + NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_VXLAN_REMCSUM_RX: Attribute.encode_one_byte_attribute, + NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_VXLAN_REPLICATION_TYPE: Attribute.encode_one_byte_attribute, + ++ # flag attributes (zero-length) ################################ ++ NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_VXLAN_GBP: Attribute.encode_flag_attribute, ++ + # 4 bytes attributes ########################################### + NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_VXLAN_ID: Attribute.encode_four_bytes_attribute, + NetlinkPacket_IFLA_LINKINFO_Attributes.IFLA_VXLAN_LINK: Attribute.encode_four_bytes_attribute, +-- +2.47.3 + diff --git a/debian/patches/series b/debian/patches/series index 2865533..ee2cb46 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -16,3 +16,4 @@ upstream/0001-use-raw-strings-for-regex-to-fix-backslash-interpret.patch upstream/0002-vxlan-add-support-for-IPv6-vxlan-local-tunnelip.patch pve/0014-nlmanager-read-ipv6-devconf-disable_ipv6-attribute-t.patch pve/0015-revert-addons-bond-warn-if-sub-interface-is-detected-on-bond-slave.patch +pve/0016-addons-vxlan-add-vxlan-gbp-attribute.patch -- 2.47.3