From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [IPv6:2a01:7e0:0:424::9]) by lore.proxmox.com (Postfix) with ESMTPS id 46B201FF137 for ; Tue, 31 Mar 2026 23:15:25 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 4E2C57D58; Tue, 31 Mar 2026 23:15:52 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=rchrist.io; s=default; t=1774991745; bh=VfeCmO8o4cy7knfEL40g5VZnbOY7E8qK0LdLC8MMvzU=; h=Date:From:To:Subject:From; b=oYnAMfdxPFFNcL5ecYlIEZ11vpcnA80MYKfZtf+b1g3vukQRo8jhbulr6ur9VrFmT wqejxITwbUGvUOIgHlAjO4Y3ZgVyTCkmo8594bkpE835BySAtUmknCFU9PdQIhSjwe I2RL6/iM8Nkoj6QqyWNaexRS2/DeVFiAeGuVfj2C80cefjaqjQdM6Ha6TPLrbJR9bY Gn0edSkjmKm5KBwAidkr8n1jvdxMNGrylYPeV/3nJrw3qh9HSGoBxSNSSndUO7zeUJ UTNweVuQlBMYyS5jxNFWUDGfNTi8wd7eT++42kdg+IUITR9tqJ/QpgIAboB6A3H0ja Uo61RyVgSo3bg== Mime-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset=UTF-8 Date: Tue, 31 Mar 2026 23:15:40 +0200 Message-Id: From: "Robin Christ" To: Subject: ifupdown2: Severe race conditions and architectural issues due to async usage of netlink X-Mailer: aerc 0.20.1-270-g2fb08ac189a1 X-SPAM-LEVEL: Spam detection results: 0 AWL -0.900 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% DKIM_SIGNED 0.1 Message has a DKIM or DK signature, not necessarily valid DKIM_VALID -0.1 Message has at least one valid DKIM or DK signature DKIM_VALID_AU -0.1 Message has a valid DKIM or DK signature from author's domain DKIM_VALID_EF -0.1 Message has a valid DKIM or DK signature from envelope-from domain DMARC_MISSING 0.1 Missing DMARC policy RCVD_IN_DNSWL_NONE -0.0001 Sender listed at https://www.dnswl.org/, no trust RCVD_IN_VALIDITY_CERTIFIED_BLOCKED 1 ADMINISTRATOR NOTICE: The query to Validity was blocked. See https://knowledge.validity.com/hc/en-us/articles/20961730681243 for more information. RCVD_IN_VALIDITY_RPBL_BLOCKED 1 ADMINISTRATOR NOTICE: The query to Validity was blocked. See https://knowledge.validity.com/hc/en-us/articles/20961730681243 for more information. RCVD_IN_VALIDITY_SAFE_BLOCKED 1 ADMINISTRATOR NOTICE: The query to Validity was blocked. See https://knowledge.validity.com/hc/en-us/articles/20961730681243 for more information. SPF_HELO_PASS -0.001 SPF: HELO matches SPF record SPF_PASS -0.001 SPF: sender matches SPF record Message-ID-Hash: E2RRB32QM455VG2HZ2CJKUC55RK7MYFB X-Message-ID-Hash: E2RRB32QM455VG2HZ2CJKUC55RK7MYFB X-MailFrom: robin@rchrist.io 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: Hey folks, While trying to debug a seemingly harmless issue "info: : ipv6 add= rgen is disabled on device with MTU lower than 1280 (current mtu 0): cannot= set addrgen off", I realized ifupdown2 has severe race conditions and arch= itectural issues. The issue mentioned above happens due to the following sequence: 1. Enqueue interface creation, async! Put a barebones version of the interface into the cache to signal that the = interface creation has been started and make the interface generally known. 2. Enqueue MTU change, async! address.py "self.process_mtu(ifaceobj, ifaceobj_getfunc)" is called immedia= tely after The RTM_NEWLINK most likely has **not yet** arrived This will ultimately call "link_set_mtu(self, ifname, mtu)" in nlcache.py, = which in turn calls "self.cache.override_link_mtu(ifname, mtu)". This call will fail: self._link_cache[ifname].attributes[Link.IFLA_MTU].value =3D mtu attributes[Link.IFLA_MTU] is **not yet** present, because the cache only ha= s the barebones version, which does not have this attribute 3. Immediately call self.up_ipv6_addrgen(ifaceobj) This will cause the abovementioned error, as it tries to read the MTU from = the interface.. Which most likely is **still not present** because the RTM_= NEWLINK most likely has **not yet** arrived and thus fail as it gets the "d= efault" value of 0 as return from get_link_mtu. 4. At some point, receive RTM_NEWLINK This will update the cache, but to a **stale** MTU value, this MTU value is= maybe correct at the time of receiving the RTM_NEWLINK message, but it is = not the intended or final MTU, so any other method reading this MTU will no= w get a stale value (just as worse as getting NO value) 5. At some point, receive RTM_NEWNETCONF This will update the cache, and now the MTU is correct. As you can see, we have lots of race conditions here due to the underlying = architectural issue, which is that interface intended state is held in the = netlink cache. =20 Even if you patch override_link_mtu to have a conditional self._link_cache[= ifname].add_attribute(Link.IFLA_MTU, mtu), you still have this window betwe= en step 4 and 5 where you will have a stale MTU value in the cache. I am considering a shitfix for up_ipv6_addrgen, or specifically link_set_ip= v6_addrgen, which just adds an optional "intended_mtu" argument. But this o= nly solves the issue for this specific function call in this specific seque= nce. There are several other places which use "get_link_mtu()" Additionally, the bridge MTU logic appears to be a bit inconsistent (broken= ). Commit a3df9e6930b2000d0ca104a317214f65ab94ed15 ("addons: address: mtu: = set bridge mtu with policy default") resets bridge MTU to default unless ex= plicitly set... But when you explicitly set the bridge MTU, you get a nice = "bridge inherits mtu from its ports. There is no need to assign mtu on a br= idge" warning (or syntax validation error). As far as I'm aware, bridge MTU doesn't have an impact on bridged traffic i= tself (only the interfaces through which the traffic exits matter), and onl= y matters for locally originated IP traffic through bridge interfaces / SVI= s, netfilter stuff (again: interface MTU?) and IGMP / MLD query generation. BUT it matters for Proxmox, as Proxmox automatically sets the interface MTU= based on the bridge. Wouldn't it make sense to set the bridge MTU, unless overridden manually, t= o the lowest MTU of any enslaved interface that is **specified in the ifupd= own2 config** (to avoid issues with VM interfaces, that have a lower MTU, l= owering the overall bridge MTU)? Given the overall bad shape of ifupdown2 - What is the way forward? Will if= updown2 be replaced in the not-so-distant future? Cheers, Robin