public inbox for pve-devel@lists.proxmox.com
 help / color / mirror / Atom feed
From: Ryosuke Nakayama <ryosuke.nakayama@ryskn.com>
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	[thread overview]
Message-ID: <20260316222816.42944-3-ryosuke.nakayama@ryskn.com> (raw)
In-Reply-To: <20260316222816.42944-1-ryosuke.nakayama@ryskn.com>

From: ryskn <ryosuke.nakayama@ryskn.com>

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 <ryosuke.nakayama@ryskn.com>
---
 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: <parent>.<vlan-id>, 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)




  parent reply	other threads:[~2026-03-16 22:28 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-03-16 22:28 [RFC PATCH 0/2] network: add VPP (fd.io) as alternative dataplane Ryosuke Nakayama
2026-03-16 22:28 ` [RFC PATCH manager 1/2] api: network: add VPP (fd.io) dataplane bridge support Ryosuke Nakayama
2026-03-16 22:28 ` Ryosuke Nakayama [this message]
2026-03-17  6:39 ` [RFC PATCH 0/2] network: add VPP (fd.io) as alternative dataplane Stefan Hanreich
2026-03-17 10:18 ` DERUMIER, Alexandre
2026-03-17 11:14   ` Ryosuke Nakayama
2026-03-17 11:14     ` [RFC PATCH qemu-server 1/2] qemu: add VPP vhost-user dataplane support Ryosuke Nakayama
2026-03-17 11:14     ` [RFC PATCH qemu-server 2/2] qemu: VPP: clean up vhost-user interfaces on stop, fix tx_queue_size Ryosuke Nakayama
2026-03-17 11:26     ` [RFC PATCH qemu-server 1/2] qemu: add VPP vhost-user dataplane support Ryosuke Nakayama
2026-03-17 11:21 ` [RFC PATCH 0/2] network: add VPP (fd.io) as alternative dataplane Ryosuke Nakayama
2026-03-17 11:21   ` [RFC PATCH pve-common] network: add VPP bridge helpers for vhost-user dataplane Ryosuke Nakayama

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260316222816.42944-3-ryosuke.nakayama@ryskn.com \
    --to=ryosuke.nakayama@ryskn.com \
    --cc=pve-devel@lists.proxmox.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal