From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [212.224.123.68]) by lore.proxmox.com (Postfix) with ESMTPS id 5A88E1FF185 for ; Mon, 7 Jul 2025 13:18:24 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 3407F306A0; Mon, 7 Jul 2025 13:19:06 +0200 (CEST) Date: Mon, 7 Jul 2025 13:18:32 +0200 From: Wolfgang Bumiller To: Gabriel Goller Message-ID: References: <20250702145101.894299-1-g.goller@proxmox.com> <20250702145101.894299-12-g.goller@proxmox.com> MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: <20250702145101.894299-12-g.goller@proxmox.com> X-SPAM-LEVEL: Spam detection results: 0 AWL 0.078 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% DMARC_MISSING 0.1 Missing DMARC policy KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment RCVD_IN_VALIDITY_CERTIFIED_BLOCKED 0.001 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 0.001 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 0.001 ADMINISTRATOR NOTICE: The query to Validity was blocked. See https://knowledge.validity.com/hc/en-us/articles/20961730681243 for more information. SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record Subject: Re: [pve-devel] [PATCH proxmox-ve-rs v4 05/22] frr: add common frr types X-BeenThere: pve-devel@lists.proxmox.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Proxmox VE development discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: Proxmox VE development discussion Cc: pve-devel@lists.proxmox.com Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Errors-To: pve-devel-bounces@lists.proxmox.com Sender: "pve-devel" On Wed, Jul 02, 2025 at 04:49:56PM +0200, Gabriel Goller wrote: > Add common FRR configuration types such as FrrWord, > CommonInterfaceName, etc. These are some common types that are used by > both openfabric and ospf and the generic types that span the two > protocols. The FrrWord is a simple primitive in FRR, which is a > ascii-string that doesn't contain whitespaces. > > Signed-off-by: Gabriel Goller > --- > proxmox-frr/src/lib.rs | 118 +++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 118 insertions(+) > > diff --git a/proxmox-frr/src/lib.rs b/proxmox-frr/src/lib.rs > index e69de29bb2d1..5e0b34602cf4 100644 > --- a/proxmox-frr/src/lib.rs > +++ b/proxmox-frr/src/lib.rs > @@ -0,0 +1,118 @@ > +use std::{fmt::Display, str::FromStr}; > + > +use serde::{Deserialize, Serialize}; > +use serde_with::{DeserializeFromStr, SerializeDisplay}; > +use thiserror::Error; > + > +#[derive(Error, Debug)] > +pub enum RouterNameError { > + #[error("invalid name")] > + InvalidName, > + #[error("invalid frr word")] > + FrrWordError(#[from] FrrWordError), > +} > + > +/// The interface name is the same on ospf and openfabric, but it is an enum so we can have two > +/// different entries in the hashmap. This allows us to have an interface in an ospf and openfabric > +/// fabric. > +#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Hash, PartialOrd, Ord)] > +pub enum InterfaceName { > + Openfabric(CommonInterfaceName), > + Ospf(CommonInterfaceName), > +} > + > +impl Display for InterfaceName { > + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { > + match self { > + InterfaceName::Openfabric(frr_word) => frr_word.fmt(f), > + InterfaceName::Ospf(frr_word) => frr_word.fmt(f), > + } > + } > +} > + > +#[derive(Error, Debug)] > +pub enum FrrWordError { > + #[error("word is empty")] > + IsEmpty, > + #[error("word contains invalid character")] > + InvalidCharacter, > +} > + > +/// A simple FRR Word. > +/// > +/// Every string argument or value in FRR is an FrrWord. FrrWords must only contain ascii > +/// characters and must not have a whitespace. > +#[derive( > + Clone, Debug, PartialEq, Eq, Hash, DeserializeFromStr, SerializeDisplay, PartialOrd, Ord, > +)] > +pub struct FrrWord(String); > + > +impl FrrWord { > + pub fn new(name: String) -> Result { > + if name.is_empty() { > + return Err(FrrWordError::IsEmpty); > + } > + > + if name > + .as_bytes() > + .iter() > + .any(|c| !c.is_ascii() || c.is_ascii_whitespace()) > + { > + eprintln!("invalid char in: \"{name}\""); > + return Err(FrrWordError::InvalidCharacter); > + } > + > + Ok(Self(name)) > + } > +} > + > +impl FromStr for FrrWord { > + type Err = FrrWordError; > + > + fn from_str(s: &str) -> Result { > + FrrWord::new(s.to_string()) ^ Let's try to avoid allocating before error-checking. We could move the check out of `new()` into a helper, call that, then just build `Self(s.to_string())`. > + } > +} > + > +impl Display for FrrWord { > + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { > + self.0.fmt(f) > + } > +} > + > +impl AsRef for FrrWord { > + fn as_ref(&self) -> &str { > + &self.0 > + } > +} > + > +#[derive(Error, Debug)] > +pub enum CommonInterfaceNameError { > + #[error("interface name too long")] > + TooLong, > +} > + > +/// Name of a interface, which is common between all protocols. > +/// > +/// FRR itself doesn't enforce any limits, but the kernel does. Linux only allows interface names > +/// to be a maximum of 16 bytes. This is enforced by this struct. > +#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Hash, PartialOrd, Ord)] > +pub struct CommonInterfaceName(String); > + > +impl FromStr for CommonInterfaceName { ^ `FromStr` is not in the prelude. Via prelude this only provides `.parse()`, but we don't really "parse it". IMO this could also be a `new()`, and have `TryFrom` and `TryFrom<&str>`. We can make `fn new + Into>(T)` to be able to run the check before any potential allocation... > + type Err = CommonInterfaceNameError; > + > + fn from_str(s: &str) -> Result { > + if s.len() <= 15 { > + Ok(Self(s.to_owned())) > + } else { > + Err(CommonInterfaceNameError::TooLong) > + } > + } > +} > + > +impl Display for CommonInterfaceName { > + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { > + self.0.fmt(f) > + } > +} > -- > 2.39.5 _______________________________________________ pve-devel mailing list pve-devel@lists.proxmox.com https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel