all lists on lists.proxmox.com
 help / color / mirror / Atom feed
From: Alexandre Derumier <aderumier@odiso.com>
To: pve-devel@lists.proxmox.com
Subject: [pve-devel] [PATCH pve-network 3/3] controllers: add isis router plugin
Date: Wed, 13 Sep 2023 13:38:45 +0200	[thread overview]
Message-ID: <20230913113845.1066417-7-aderumier@odiso.com> (raw)
In-Reply-To: <20230913113845.1066417-1-aderumier@odiso.com>

---
 src/PVE/Network/SDN/Controllers.pm            |   2 +
 src/PVE/Network/SDN/Controllers/EvpnPlugin.pm |  28 +++-
 src/PVE/Network/SDN/Controllers/IsisPlugin.pm | 123 ++++++++++++++++++
 src/PVE/Network/SDN/Controllers/Makefile      |   2 +-
 src/PVE/Network/SDN/Zones/EvpnPlugin.pm       |  10 +-
 .../evpn/isis/expected_controller_config      |  58 +++++++++
 .../zones/evpn/isis/expected_sdn_interfaces   |  41 ++++++
 src/test/zones/evpn/isis/interfaces           |   7 +
 src/test/zones/evpn/isis/sdn_config           |  49 +++++++
 .../isis_loopback/expected_controller_config  |  59 +++++++++
 .../isis_loopback/expected_sdn_interfaces     |  41 ++++++
 src/test/zones/evpn/isis_loopback/interfaces  |  12 ++
 src/test/zones/evpn/isis_loopback/sdn_config  |  50 +++++++
 13 files changed, 476 insertions(+), 6 deletions(-)
 create mode 100644 src/PVE/Network/SDN/Controllers/IsisPlugin.pm
 create mode 100644 src/test/zones/evpn/isis/expected_controller_config
 create mode 100644 src/test/zones/evpn/isis/expected_sdn_interfaces
 create mode 100644 src/test/zones/evpn/isis/interfaces
 create mode 100644 src/test/zones/evpn/isis/sdn_config
 create mode 100644 src/test/zones/evpn/isis_loopback/expected_controller_config
 create mode 100644 src/test/zones/evpn/isis_loopback/expected_sdn_interfaces
 create mode 100644 src/test/zones/evpn/isis_loopback/interfaces
 create mode 100644 src/test/zones/evpn/isis_loopback/sdn_config

diff --git a/src/PVE/Network/SDN/Controllers.pm b/src/PVE/Network/SDN/Controllers.pm
index a23048e..f5a6b86 100644
--- a/src/PVE/Network/SDN/Controllers.pm
+++ b/src/PVE/Network/SDN/Controllers.pm
@@ -14,10 +14,12 @@ use PVE::Network::SDN::Zones;
 
 use PVE::Network::SDN::Controllers::EvpnPlugin;
 use PVE::Network::SDN::Controllers::BgpPlugin;
+use PVE::Network::SDN::Controllers::IsisPlugin;
 use PVE::Network::SDN::Controllers::FaucetPlugin;
 use PVE::Network::SDN::Controllers::Plugin;
 PVE::Network::SDN::Controllers::EvpnPlugin->register();
 PVE::Network::SDN::Controllers::BgpPlugin->register();
+PVE::Network::SDN::Controllers::IsisPlugin->register();
 PVE::Network::SDN::Controllers::FaucetPlugin->register();
 PVE::Network::SDN::Controllers::Plugin->init();
 
diff --git a/src/PVE/Network/SDN/Controllers/EvpnPlugin.pm b/src/PVE/Network/SDN/Controllers/EvpnPlugin.pm
index f1dd20f..3ac7d7e 100644
--- a/src/PVE/Network/SDN/Controllers/EvpnPlugin.pm
+++ b/src/PVE/Network/SDN/Controllers/EvpnPlugin.pm
@@ -53,11 +53,15 @@ sub generate_controller_config {
     my $loopback = undef;
     my $autortas = undef;
     my $bgprouter = find_bgp_controller($local_node, $controller_cfg);
+    my $isisrouter = find_isis_controller($local_node, $controller_cfg);
+
     if ($bgprouter) {
 	$ebgp = 1 if $plugin_config->{'asn'} ne $bgprouter->{asn};
 	$loopback = $bgprouter->{loopback} if $bgprouter->{loopback};
 	$asn = $bgprouter->{asn} if $bgprouter->{asn};
 	$autortas = $plugin_config->{'asn'} if $ebgp;
+    } elsif ($isisrouter) {
+	$loopback = $isisrouter->{loopback} if $isisrouter->{loopback};
     }
 
     return if !$asn;
@@ -86,10 +90,8 @@ sub generate_controller_config {
     push @controller_config, "neighbor VTEP remote-as $remoteas";
     push @controller_config, "neighbor VTEP bfd";
 
-    if($ebgp && $loopback) {
-	push @controller_config, "neighbor VTEP ebgp-multihop 10";
-	push @controller_config, "neighbor VTEP update-source $loopback";
-    }
+    push @controller_config, "neighbor VTEP ebgp-multihop 10" if $ebgp && $loopback;
+    push @controller_config, "neighbor VTEP update-source $loopback" if $loopback;
 
     # VTEP peers
     foreach my $address (@peers) {
@@ -136,11 +138,15 @@ sub generate_controller_zone_config {
     my $loopback = undef;
     my $autortas = undef;
     my $bgprouter = find_bgp_controller($local_node, $controller_cfg);
+    my $isisrouter = find_isis_controller($local_node, $controller_cfg);
+
     if($bgprouter) {
         $ebgp = 1 if $controller->{'asn'} ne $bgprouter->{asn};
 	$loopback = $bgprouter->{loopback} if $bgprouter->{loopback};
 	$asn = $bgprouter->{asn} if $bgprouter->{asn};
 	$autortas = $controller->{'asn'} if $ebgp;
+    } elsif ($isisrouter) {
+        $loopback = $isisrouter->{loopback} if $isisrouter->{loopback};
     }
 
     return if !$vrf || !$vrfvxlan || !$asn;
@@ -306,6 +312,20 @@ sub find_bgp_controller {
     return $res;
 }
 
+sub find_isis_controller {
+    my ($nodename, $controller_cfg) = @_;
+
+    my $res = undef;
+    foreach my $id  (keys %{$controller_cfg->{ids}}) {
+	my $controller = $controller_cfg->{ids}->{$id};
+	next if $controller->{type} ne 'isis';
+	next if $controller->{node} ne $nodename;
+	$res = $controller;
+	last;
+    }
+    return $res;
+}
+
 sub generate_frr_recurse{
    my ($final_config, $content, $parentkey, $level) = @_;
 
diff --git a/src/PVE/Network/SDN/Controllers/IsisPlugin.pm b/src/PVE/Network/SDN/Controllers/IsisPlugin.pm
new file mode 100644
index 0000000..afea82e
--- /dev/null
+++ b/src/PVE/Network/SDN/Controllers/IsisPlugin.pm
@@ -0,0 +1,123 @@
+package PVE::Network::SDN::Controllers::IsisPlugin;
+
+use strict;
+use warnings;
+
+use PVE::INotify;
+use PVE::JSONSchema qw(get_standard_option);
+use PVE::Tools qw(run_command file_set_contents file_get_contents);
+
+use PVE::Network::SDN::Controllers::Plugin;
+use PVE::Network::SDN::Zones::Plugin;
+use Net::IP;
+
+use base('PVE::Network::SDN::Controllers::Plugin');
+
+sub type {
+    return 'isis';
+}
+
+sub properties {
+    return {
+	'isis-domain' => {
+	    description => "ISIS domain.",
+	    type => 'string'
+	},
+	'isis-ifaces' => {
+	    description => "ISIS interface.",
+	    type => 'string', format => 'pve-iface-list',
+	},
+	'isis-net' => {
+	    description => "ISIS network entity title.",
+	    type => 'string'
+	},
+    };
+}
+
+sub options {
+    return {
+	'isis-domain' => { optional => 0 },
+	'isis-net' => { optional => 0 },
+	'isis-ifaces' => { optional => 0 },
+        'node' => { optional => 0 },
+        'loopback' => { optional => 1 },
+    };
+}
+
+# Plugin implementation
+sub generate_controller_config {
+    my ($class, $plugin_config, $controller, $id, $uplinks, $config) = @_;
+
+    my $isis_ifaces = $plugin_config->{'isis-ifaces'};
+    my $isis_net = $plugin_config->{'isis-net'};
+    my $isis_domain = $plugin_config->{'isis-domain'};
+    my $local_node = PVE::INotify::nodename();
+
+    return if !$isis_ifaces || !$isis_net || !$isis_domain;
+    return if $local_node ne $plugin_config->{node};
+
+    my @router_config = (
+	"net $isis_net",
+	"redistribute ipv4 connected level-1",
+	"redistribute ipv6 connected level-1",
+	"log-adjacency-changes",
+    );
+
+    push(@{$config->{frr}->{router}->{"isis $isis_domain"}}, @router_config);
+
+    my @iface_config = (
+	"ip router isis $isis_domain"
+    );
+
+    my @ifaces = PVE::Tools::split_list($isis_ifaces);
+    for my $iface (sort @ifaces) {
+	push(@{$config->{frr_interfaces}->{$iface}}, @iface_config);
+    }
+
+    return $config;
+}
+
+sub generate_controller_zone_config {
+    my ($class, $plugin_config, $controller, $controller_cfg, $id, $uplinks, $config) = @_;
+
+}
+
+sub on_delete_hook {
+    my ($class, $controllerid, $zone_cfg) = @_;
+
+}
+
+sub on_update_hook {
+    my ($class, $controllerid, $controller_cfg) = @_;
+
+    # we can only have 1 bgp controller by node
+    my $local_node = PVE::INotify::nodename();
+    my $controllernb = 0;
+    foreach my $id (keys %{$controller_cfg->{ids}}) {
+        next if $id eq $controllerid;
+        my $controller = $controller_cfg->{ids}->{$id};
+        next if $controller->{type} ne "isis";
+        next if $controller->{node} ne $local_node;
+        $controllernb++;
+        die "only 1 bgp or isis controller can be defined" if $controllernb > 1;
+    }
+}
+
+sub generate_controller_rawconfig {
+    my ($class, $plugin_config, $config) = @_;
+    return "";
+}
+
+sub write_controller_config {
+    my ($class, $plugin_config, $config) = @_;
+    return;
+}
+
+sub reload_controller {
+    my ($class) = @_;
+    return;
+}
+
+1;
+
+
diff --git a/src/PVE/Network/SDN/Controllers/Makefile b/src/PVE/Network/SDN/Controllers/Makefile
index 11686a3..fd9f881 100644
--- a/src/PVE/Network/SDN/Controllers/Makefile
+++ b/src/PVE/Network/SDN/Controllers/Makefile
@@ -1,4 +1,4 @@
-SOURCES=Plugin.pm FaucetPlugin.pm EvpnPlugin.pm BgpPlugin.pm
+SOURCES=Plugin.pm FaucetPlugin.pm EvpnPlugin.pm BgpPlugin.pm IsisPlugin.pm
 
 
 PERL5DIR=${DESTDIR}/usr/share/perl5
diff --git a/src/PVE/Network/SDN/Zones/EvpnPlugin.pm b/src/PVE/Network/SDN/Zones/EvpnPlugin.pm
index b155abc..5df05f9 100644
--- a/src/PVE/Network/SDN/Zones/EvpnPlugin.pm
+++ b/src/PVE/Network/SDN/Zones/EvpnPlugin.pm
@@ -119,8 +119,16 @@ sub generate_sdn_config {
     warn "vlan-aware vnet can't be enabled with evpn plugin" if $vnet->{vlanaware};
 
     my @peers = PVE::Tools::split_list($controller->{'peers'});
+
+    my $loopback = undef;
     my $bgprouter = PVE::Network::SDN::Controllers::EvpnPlugin::find_bgp_controller($local_node, $controller_cfg);
-    my $loopback = $bgprouter->{loopback} if $bgprouter->{loopback};
+    my $isisrouter = PVE::Network::SDN::Controllers::EvpnPlugin::find_isis_controller($local_node, $controller_cfg);
+    if ($bgprouter->{loopback}) {
+	$loopback = $bgprouter->{loopback};
+    } elsif ($isisrouter->{loopback}) {
+	$loopback = $isisrouter->{loopback};
+    }
+
     my ($ifaceip, $iface) = PVE::Network::SDN::Zones::Plugin::find_local_ip_interface_peers(\@peers, $loopback);
     my $is_evpn_gateway = $plugin_config->{'exitnodes'}->{$local_node};
     my $exitnodes_local_routing = $plugin_config->{'exitnodes-local-routing'};
diff --git a/src/test/zones/evpn/isis/expected_controller_config b/src/test/zones/evpn/isis/expected_controller_config
new file mode 100644
index 0000000..8d1706a
--- /dev/null
+++ b/src/test/zones/evpn/isis/expected_controller_config
@@ -0,0 +1,58 @@
+frr version 8.5.1
+frr defaults datacenter
+hostname localhost
+log syslog informational
+service integrated-vtysh-config
+!
+!
+vrf vrf_myzone
+ vni 1000
+exit-vrf
+!
+interface eth0
+ ip router isis isis1
+!
+interface eth1
+ ip router isis isis1
+!
+router bgp 65000
+ bgp router-id 192.168.0.1
+ no bgp hard-administrative-reset
+ no bgp graceful-restart notification
+ no bgp default ipv4-unicast
+ coalesce-time 1000
+ neighbor VTEP peer-group
+ neighbor VTEP remote-as 65000
+ neighbor VTEP bfd
+ neighbor 192.168.0.2 peer-group VTEP
+ neighbor 192.168.0.3 peer-group VTEP
+ !
+ address-family l2vpn evpn
+  neighbor VTEP route-map MAP_VTEP_IN in
+  neighbor VTEP route-map MAP_VTEP_OUT out
+  neighbor VTEP activate
+  advertise-all-vni
+ exit-address-family
+exit
+!
+router bgp 65000 vrf vrf_myzone
+ bgp router-id 192.168.0.1
+ no bgp hard-administrative-reset
+ no bgp graceful-restart notification
+exit
+!
+router isis isis1
+ net 47.0023.0000.0000.0000.0000.0000.0000.1900.0004.00
+ redistribute ipv4 connected level-1
+ redistribute ipv6 connected level-1
+ log-adjacency-changes
+exit
+!
+route-map MAP_VTEP_IN permit 1
+exit
+!
+route-map MAP_VTEP_OUT permit 1
+exit
+!
+line vty
+!
\ No newline at end of file
diff --git a/src/test/zones/evpn/isis/expected_sdn_interfaces b/src/test/zones/evpn/isis/expected_sdn_interfaces
new file mode 100644
index 0000000..4cf13e0
--- /dev/null
+++ b/src/test/zones/evpn/isis/expected_sdn_interfaces
@@ -0,0 +1,41 @@
+#version:1
+
+auto myvnet
+iface myvnet
+	address 10.0.0.1/24
+	bridge_ports vxlan_myvnet
+	bridge_stp off
+	bridge_fd 0
+	mtu 1450
+	ip-forward on
+	arp-accept on
+	vrf vrf_myzone
+
+auto vrf_myzone
+iface vrf_myzone
+	vrf-table auto
+	post-up ip route add vrf vrf_myzone unreachable default metric 4278198272
+
+auto vrfbr_myzone
+iface vrfbr_myzone
+	bridge-ports vrfvx_myzone
+	bridge_stp off
+	bridge_fd 0
+	mtu 1450
+	vrf vrf_myzone
+
+auto vrfvx_myzone
+iface vrfvx_myzone
+	vxlan-id 1000
+	vxlan-local-tunnelip 192.168.0.1
+	bridge-learning off
+	bridge-arp-nd-suppress on
+	mtu 1450
+
+auto vxlan_myvnet
+iface vxlan_myvnet
+	vxlan-id 100
+	vxlan-local-tunnelip 192.168.0.1
+	bridge-learning off
+	bridge-arp-nd-suppress on
+	mtu 1450
diff --git a/src/test/zones/evpn/isis/interfaces b/src/test/zones/evpn/isis/interfaces
new file mode 100644
index 0000000..2426e0f
--- /dev/null
+++ b/src/test/zones/evpn/isis/interfaces
@@ -0,0 +1,7 @@
+auto vmbr0
+iface vmbr0 inet static
+	address 192.168.0.1/24
+	gateway 192.168.0.254
+        bridge-ports eth0
+        bridge-stp off
+        bridge-fd 0
\ No newline at end of file
diff --git a/src/test/zones/evpn/isis/sdn_config b/src/test/zones/evpn/isis/sdn_config
new file mode 100644
index 0000000..5963c18
--- /dev/null
+++ b/src/test/zones/evpn/isis/sdn_config
@@ -0,0 +1,49 @@
+{
+    version => 1,
+    vnets => {
+        ids => {
+            myvnet => {
+                tag => "100",
+                type => "vnet",
+                zone => "myzone",
+            },
+        },
+    },
+
+    zones   => {
+        ids => {
+            myzone => {
+                ipam => "pve",
+                type => "evpn",
+                controller => "evpnctl",
+                'vrf-vxlan' => 1000,
+            },
+        },
+    },
+    controllers  => {
+        ids => {
+            evpnctl => {
+                type => "evpn",
+                'peers' => '192.168.0.1,192.168.0.2,192.168.0.3',
+                asn => "65000",
+            },
+            localhost => {
+                type => "isis",
+                'isis-domain' => 'isis1',
+                'isis-ifaces' => 'eth1,eth0',
+                'isis-net' => "47.0023.0000.0000.0000.0000.0000.0000.1900.0004.00",
+                node => "localhost",
+            },
+        },
+    },
+
+    subnets => {
+        ids => {
+            'myzone-10.0.0.0-24' => {
+                'type' => 'subnet',
+                'vnet' => 'myvnet',
+                'gateway' => '10.0.0.1',
+            },
+        },
+    },
+}
diff --git a/src/test/zones/evpn/isis_loopback/expected_controller_config b/src/test/zones/evpn/isis_loopback/expected_controller_config
new file mode 100644
index 0000000..7b034c4
--- /dev/null
+++ b/src/test/zones/evpn/isis_loopback/expected_controller_config
@@ -0,0 +1,59 @@
+frr version 8.5.1
+frr defaults datacenter
+hostname localhost
+log syslog informational
+service integrated-vtysh-config
+!
+!
+vrf vrf_myzone
+ vni 1000
+exit-vrf
+!
+interface eth0
+ ip router isis isis1
+!
+interface eth1
+ ip router isis isis1
+!
+router bgp 65000
+ bgp router-id 10.0.0.1
+ no bgp hard-administrative-reset
+ no bgp graceful-restart notification
+ no bgp default ipv4-unicast
+ coalesce-time 1000
+ neighbor VTEP peer-group
+ neighbor VTEP remote-as 65000
+ neighbor VTEP bfd
+ neighbor VTEP update-source dummy1
+ neighbor 10.0.0.2 peer-group VTEP
+ neighbor 10.0.0.3 peer-group VTEP
+ !
+ address-family l2vpn evpn
+  neighbor VTEP route-map MAP_VTEP_IN in
+  neighbor VTEP route-map MAP_VTEP_OUT out
+  neighbor VTEP activate
+  advertise-all-vni
+ exit-address-family
+exit
+!
+router bgp 65000 vrf vrf_myzone
+ bgp router-id 10.0.0.1
+ no bgp hard-administrative-reset
+ no bgp graceful-restart notification
+exit
+!
+router isis isis1
+ net 47.0023.0000.0000.0000.0000.0000.0000.1900.0004.00
+ redistribute ipv4 connected level-1
+ redistribute ipv6 connected level-1
+ log-adjacency-changes
+exit
+!
+route-map MAP_VTEP_IN permit 1
+exit
+!
+route-map MAP_VTEP_OUT permit 1
+exit
+!
+line vty
+!
\ No newline at end of file
diff --git a/src/test/zones/evpn/isis_loopback/expected_sdn_interfaces b/src/test/zones/evpn/isis_loopback/expected_sdn_interfaces
new file mode 100644
index 0000000..e595dc9
--- /dev/null
+++ b/src/test/zones/evpn/isis_loopback/expected_sdn_interfaces
@@ -0,0 +1,41 @@
+#version:1
+
+auto myvnet
+iface myvnet
+	address 10.0.0.1/24
+	bridge_ports vxlan_myvnet
+	bridge_stp off
+	bridge_fd 0
+	mtu 1450
+	ip-forward on
+	arp-accept on
+	vrf vrf_myzone
+
+auto vrf_myzone
+iface vrf_myzone
+	vrf-table auto
+	post-up ip route add vrf vrf_myzone unreachable default metric 4278198272
+
+auto vrfbr_myzone
+iface vrfbr_myzone
+	bridge-ports vrfvx_myzone
+	bridge_stp off
+	bridge_fd 0
+	mtu 1450
+	vrf vrf_myzone
+
+auto vrfvx_myzone
+iface vrfvx_myzone
+	vxlan-id 1000
+	vxlan-local-tunnelip 10.0.0.1
+	bridge-learning off
+	bridge-arp-nd-suppress on
+	mtu 1450
+
+auto vxlan_myvnet
+iface vxlan_myvnet
+	vxlan-id 100
+	vxlan-local-tunnelip 10.0.0.1
+	bridge-learning off
+	bridge-arp-nd-suppress on
+	mtu 1450
diff --git a/src/test/zones/evpn/isis_loopback/interfaces b/src/test/zones/evpn/isis_loopback/interfaces
new file mode 100644
index 0000000..41ae25f
--- /dev/null
+++ b/src/test/zones/evpn/isis_loopback/interfaces
@@ -0,0 +1,12 @@
+auto vmbr0
+iface vmbr0 inet static
+	address 192.168.0.1/24
+	gateway 192.168.0.254
+        bridge-ports eth0
+        bridge-stp off
+        bridge-fd 0
+
+auto dummy1
+iface dummy1 inet static
+        address 10.0.0.1/32
+        link-type dummy
\ No newline at end of file
diff --git a/src/test/zones/evpn/isis_loopback/sdn_config b/src/test/zones/evpn/isis_loopback/sdn_config
new file mode 100644
index 0000000..786a3e7
--- /dev/null
+++ b/src/test/zones/evpn/isis_loopback/sdn_config
@@ -0,0 +1,50 @@
+{
+    version => 1,
+    vnets => {
+        ids => {
+            myvnet => {
+                tag => "100",
+                type => "vnet",
+                zone => "myzone",
+            },
+        },
+    },
+
+    zones   => {
+        ids => {
+            myzone => {
+                ipam => "pve",
+                type => "evpn",
+                controller => "evpnctl",
+                'vrf-vxlan' => 1000,
+            },
+        },
+    },
+    controllers  => {
+        ids => {
+            evpnctl => {
+                type => "evpn",
+                'peers' => '10.0.0.1,10.0.0.2,10.0.0.3',
+                asn => "65000",
+            },
+            localhost => {
+                type => "isis",
+                'isis-domain' => 'isis1',
+                'isis-ifaces' => 'eth1,eth0',
+                'isis-net' => "47.0023.0000.0000.0000.0000.0000.0000.1900.0004.00",
+		loopback => 'dummy1',
+                node => "localhost",
+            },
+        },
+    },
+
+    subnets => {
+        ids => {
+            'myzone-10.0.0.0-24' => {
+                'type' => 'subnet',
+                'vnet' => 'myvnet',
+                'gateway' => '10.0.0.1',
+            },
+        },
+    },
+}
-- 
2.39.2




  parent reply	other threads:[~2023-09-13 11:39 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-09-13 11:38 [pve-devel] [PATCH-SERIES pve-network/pve-manager/pve-docs] sdn: add isis controller Alexandre Derumier
2023-09-13 11:38 ` [pve-devel] [PATCH pve-network 1/3] controller: evpn: fix find_bgp_controller Alexandre Derumier
2023-09-13 11:38 ` [pve-devel] [PATCH pve-docs 1/2] sdn: add notes about bgp controller Alexandre Derumier
2023-09-13 11:38 ` [pve-devel] [PATCH pve-manager 1/1] sdn: controllers: add isis controller Alexandre Derumier
2023-09-13 11:38 ` [pve-devel] [PATCH pve-network 2/3] controllers: frr: add parsing of "interfaces" section Alexandre Derumier
2023-09-13 11:38 ` [pve-devel] [PATCH pve-docs 2/2] sdn: add isis controller documentation Alexandre Derumier
2023-09-13 11:38 ` Alexandre Derumier [this message]
2023-10-25 11:22 ` [pve-devel] applied-series: [PATCH-SERIES pve-network/pve-manager/pve-docs] sdn: add isis controller Fabian Grünbichler

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=20230913113845.1066417-7-aderumier@odiso.com \
    --to=aderumier@odiso.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal