From: ryskn <[email protected]>

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 <[email protected]>
---
 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)



Reply via email to