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 32D051FF141 for ; Mon, 16 Mar 2026 23:28:30 +0100 (CET) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 2D7DC35435; Mon, 16 Mar 2026 23:28:34 +0100 (CET) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1773700102; x=1774304902; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=byiaHhf3CjwuZRGno50RLoWc1+rtbAaONJU3yerVg20=; b=LEjPbOJRiMfxeZGex5EV6zszqnnyAO1Ce63s9r6x38zzfUd+/5UDtnbDlOAUjaQN5i zaIv+5TGd+IB5uohN0bw9KNNOEo+XcFqdrkoi+8u8iCTbD/EYSPQk5xqepSjpgf01y4L GnH96HHH/Z7NF0T9sdsLxadHcSiSguAj1cK9E92cTIU5WB1TptbmJhSS2dEj5kfzW2pI xWYWEF7fOij/HHWGOJ0KPmBO2UmP2Faf7yaTxn5mTcAV4DJAwk8TJzYc4miC+JHQJh7J hYUmGLz5v+lZNc4OtuBkqWfqVbQyeHN0SaZq6cOsPeOVY1NrlicN4b8RL+UoD0zr14s4 4LxA== X-Gm-Message-State: AOJu0YzrPs/Pe9ZfFiERAMtqzo//5iIkqveDs9Ri5adxFYREv8nS180I W7HL8+QXDSRKXL4tXIfCEIUuRo5J0K6b2LwwQhfCvIIkSSD0MKmZn6+8oTxaMz5mwcA7 X-Gm-Gg: ATEYQzyXPiaiHs5sIV8PMOGxNG/aob7XmgVGTVqBQkyMLX3qU/MPYhl8JRDDOxCo+Hj 3yrvQpqMMlmlKk4zNRT7YHqKczF128MhfmUpxpXtVZIb6BOUJJbEc0yE6f8f7HgDOLGfpkks+nN 7o+CBHjSbf/Ck9+Nh/31Boa0ZFCKxSPZs0bIk6sy5YWqGa/j2KgfnG0uaG2Jzffc2Dlj/brYNPF fapUzSCJFekWOdKOUdhnyIssgRYeTagPV7UI21Gz8PbH5KaGQJuHeMPwa44IU71knJ+MByFEwJw BpAiZOzMNSFSeHV3PG2cQvDbFMEaxwdSZihQKlMrjpKvRozU0qQkRPDocNqXbKrmI6zaCZJw1Tu mLd1fFtWNui3G7ykldpf6Lp8RmeRvbzGsf2KBAIHgk7lZbthhsex9yqBOwjZSE/l77/EGtzg67n KhkVFWyyPPJAY+9DhR0fK9MVXrvbgXWtZ/v0B6LqUVXxiePGScrOSegc3jCk8xUF1ccV3wh8PGl Tcj+5OeGxoMCJ9aP94NgCF1SFbFvWsbEbYemgn+1bvjJBADHg== X-Received: by 2002:a17:902:e547:b0:2b0:59c4:e9e2 with SMTP id d9443c01a7336-2b059c4ec03mr43716405ad.2.1773700102165; Mon, 16 Mar 2026 15:28:22 -0700 (PDT) From: Ryosuke Nakayama To: pve-devel@lists.proxmox.com Subject: [RFC PATCH widget-toolkit 2/2] ui: network: add VPP (fd.io) bridge type support Date: Tue, 17 Mar 2026 07:28:16 +0900 Message-ID: <20260316222816.42944-3-ryosuke.nakayama@ryskn.com> X-Mailer: git-send-email 2.50.1 In-Reply-To: <20260316222816.42944-1-ryosuke.nakayama@ryskn.com> References: <20260316222816.42944-1-ryosuke.nakayama@ryskn.com> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-SPAM-LEVEL: Spam detection results: 0 AWL -0.001 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 FREEMAIL_ENVFROM_END_DIGIT 1 Envelope-from freemail username ends in digit FREEMAIL_FORGED_FROMDOMAIN 0.249 2nd level domains in From and EnvelopeFrom freemail headers are different FREEMAIL_FROM 0.001 Sender email is commonly abused enduser mail provider HEADER_FROM_DIFFERENT_DOMAINS 0.25 From and EnvelopeFrom 2nd level mail domains are different KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment RCVD_IN_DNSWL_NONE -0.0001 Sender listed at https://www.dnswl.org/, no trust RCVD_IN_MSPIKE_H3 0.001 Good reputation (+3) RCVD_IN_MSPIKE_WL 0.001 Mailspike good senders 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: BCVKPX3SNVVFHHTFXJ4R3KQAW6UZL2MP X-Message-ID-Hash: BCVKPX3SNVVFHHTFXJ4R3KQAW6UZL2MP X-MailFrom: koyakiu666@gmail.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: From: ryskn Add VPP bridge domain as a creatable/editable network type in the Proxmox node network configuration UI. - Utils.js: add VPPBridge/VPPVlan to network_iface_types with gettext() - NetworkView.js: add 'vpp' to default types list; add VPPBridge and VPPVlan entries to the Create menu; VPPVlan uses a dedicated menu entry (no auto-generated default name); render vlan-raw-device in Ports/Slaves column for VPPVlan; fix VLAN aware column to render vpp_vlan_aware for VPP bridges; declare vpp_bridge/vpp_vlan_aware in the proxmox-networks model - NetworkEdit.js: introduce vppTypes Set as single source of truth for VPP type checks; add vppbrN validator for VPPBridge name field; add vppbrN validator for vpp_bridge field in VPPVlan; increase maxLength to 40 for VPP interface names; hide MTU field for VPP types; exclude Autostart and IP/GW fields for VPP types via vppTypes; use VlanName vtype for VPPVlan to allow dot notation (e.g. tap0.100) Signed-off-by: ryskn --- src/Utils.js | 2 ++ src/node/NetworkEdit.js | 64 ++++++++++++++++++++++++++++++++++------- src/node/NetworkView.js | 35 ++++++++++++++++++---- 3 files changed, 85 insertions(+), 16 deletions(-) diff --git a/src/Utils.js b/src/Utils.js index 5457ffa..fa88fb1 100644 --- a/src/Utils.js +++ b/src/Utils.js @@ -707,6 +707,8 @@ Ext.define('Proxmox.Utils', { OVSBond: 'OVS Bond', OVSPort: 'OVS Port', OVSIntPort: 'OVS IntPort', + VPPBridge: gettext('VPP Bridge'), + VPPVlan: gettext('VPP VLAN'), }, render_network_iface_type: function (value) { diff --git a/src/node/NetworkEdit.js b/src/node/NetworkEdit.js index c945139..c53cd90 100644 --- a/src/node/NetworkEdit.js +++ b/src/node/NetworkEdit.js @@ -21,7 +21,12 @@ Ext.define('Proxmox.node.NetworkEdit', { me.isCreate = !me.iface; + // Canonical set of VPP interface types — used to gate autostart, + // IP config, MTU, and other kernel-only fields. + const vppTypes = new Set(['VPPBridge', 'VPPVlan']); + let iface_vtype; + let iface_validator; // optional extra validator for the Name field if (me.iftype === 'bridge') { iface_vtype = 'BridgeName'; @@ -39,6 +44,12 @@ Ext.define('Proxmox.node.NetworkEdit', { iface_vtype = 'InterfaceName'; } else if (me.iftype === 'OVSPort') { iface_vtype = 'InterfaceName'; + } else if (me.iftype === 'VPPBridge') { + iface_vtype = 'InterfaceName'; + iface_validator = (v) => + /^vppbr\d+$/.test(v) || gettext('Name must match vppbrN format (e.g. vppbr1)'); + } else if (me.iftype === 'VPPVlan') { + iface_vtype = 'VlanName'; } else { console.log(me.iftype); throw 'unknown network device type specified'; @@ -52,7 +63,7 @@ Ext.define('Proxmox.node.NetworkEdit', { advancedColumn1 = [], advancedColumn2 = []; - if (!(me.iftype === 'OVSIntPort' || me.iftype === 'OVSPort' || me.iftype === 'OVSBond')) { + if (!(me.iftype === 'OVSIntPort' || me.iftype === 'OVSPort' || me.iftype === 'OVSBond' || vppTypes.has(me.iftype))) { column2.push({ xtype: 'proxmoxcheckbox', fieldLabel: gettext('Autostart'), @@ -295,6 +306,32 @@ Ext.define('Proxmox.node.NetworkEdit', { fieldLabel: gettext('OVS options'), name: 'ovs_options', }); + } else if (me.iftype === 'VPPBridge') { + column2.push({ + xtype: 'proxmoxcheckbox', + fieldLabel: gettext('VLAN aware'), + name: 'vpp_vlan_aware', + deleteEmpty: !me.isCreate, + }); + } else if (me.iftype === 'VPPVlan') { + column2.push({ + xtype: 'displayfield', + userCls: 'pmx-hint', + value: gettext('Name format: ., e.g. tap0.100'), + }); + column2.push({ + xtype: me.isCreate ? 'textfield' : 'displayfield', + fieldLabel: gettext('Bridge domain'), + name: 'vpp_bridge', + emptyText: gettext('none'), + allowBlank: true, + validator: (v) => + !v || /^vppbr\d+$/.test(v) || gettext('Must match vppbrN format (e.g. vppbr1)'), + autoEl: { + tag: 'div', + 'data-qtip': gettext('VPP bridge domain to attach this VLAN interface to, e.g. vppbr1'), + }, + }); } column2.push({ @@ -328,8 +365,9 @@ Ext.define('Proxmox.node.NetworkEdit', { name: 'iface', value: me.iface, vtype: iface_vtype, + validator: iface_validator, allowBlank: false, - maxLength: iface_vtype === 'BridgeName' ? 10 : 15, + maxLength: iface_vtype === 'BridgeName' ? 10 : (vppTypes.has(me.iftype) ? 40 : 15), autoEl: { tag: 'div', 'data-qtip': gettext('For example, vmbr0.100, vmbr0, vlan0.100, vlan0'), @@ -391,6 +429,8 @@ Ext.define('Proxmox.node.NetworkEdit', { name: 'ovs_bonds', }, ); + } else if (vppTypes.has(me.iftype)) { + // VPP interfaces do not use kernel IP configuration } else { column1.push( { @@ -423,15 +463,17 @@ Ext.define('Proxmox.node.NetworkEdit', { }, ); } - advancedColumn1.push({ - xtype: 'proxmoxintegerfield', - minValue: 1280, - maxValue: 65520, - deleteEmpty: !me.isCreate, - emptyText: 1500, - fieldLabel: 'MTU', - name: 'mtu', - }); + if (!vppTypes.has(me.iftype)) { + advancedColumn1.push({ + xtype: 'proxmoxintegerfield', + minValue: 1280, + maxValue: 65520, + deleteEmpty: !me.isCreate, + emptyText: 1500, + fieldLabel: 'MTU', + name: 'mtu', + }); + } Ext.applyIf(me, { url: url, diff --git a/src/node/NetworkView.js b/src/node/NetworkView.js index 0ff9649..164b349 100644 --- a/src/node/NetworkView.js +++ b/src/node/NetworkView.js @@ -19,6 +19,8 @@ Ext.define('proxmox-networks', { 'type', 'vlan-id', 'vlan-raw-device', + 'vpp_bridge', + 'vpp_vlan_aware', ], idProperty: 'iface', }); @@ -30,7 +32,7 @@ Ext.define('Proxmox.node.NetworkView', { // defines what types of network devices we want to create // order is always the same - types: ['bridge', 'bond', 'vlan', 'ovs'], + types: ['bridge', 'bond', 'vlan', 'ovs', 'vpp'], showApplyBtn: false, @@ -223,6 +225,27 @@ Ext.define('Proxmox.node.NetworkView', { }); } + if (me.types.indexOf('vpp') !== -1) { + if (menu_items.length > 0) { + menu_items.push({ xtype: 'menuseparator' }); + } + + addEditWindowToMenu('VPPBridge', 'vppbr'); + menu_items.push({ + text: Proxmox.Utils.render_network_iface_type('VPPVlan'), + handler: () => + Ext.create('Proxmox.node.NetworkEdit', { + autoShow: true, + nodename: me.nodename, + iftype: 'VPPVlan', + ...me.editOptions, + listeners: { + destroy: () => reload(), + }, + }), + }); + } + let renderer_generator = function (fieldname) { return function (val, metaData, rec) { let tmp = []; @@ -326,14 +349,14 @@ Ext.define('Proxmox.node.NetworkView', { undefinedText: Proxmox.Utils.noText, }, { - xtype: 'booleancolumn', header: gettext('VLAN aware'), width: 80, sortable: true, dataIndex: 'bridge_vlan_aware', - trueText: Proxmox.Utils.yesText, - falseText: Proxmox.Utils.noText, - undefinedText: Proxmox.Utils.noText, + renderer: (value, metaData, { data }) => { + const v = data.bridge_vlan_aware || data.vpp_vlan_aware; + return v ? Proxmox.Utils.yesText : Proxmox.Utils.noText; + }, }, { header: gettext('Ports/Slaves'), @@ -347,6 +370,8 @@ Ext.define('Proxmox.node.NetworkView', { return data.ovs_ports; } else if (value === 'OVSBond') { return data.ovs_bonds; + } else if (value === 'VPPVlan') { + return data['vlan-raw-device']; } return ''; }, -- 2.50.1 (Apple Git-155)