all lists on lists.proxmox.com
 help / color / mirror / Atom feed
From: Christoph Heiss <c.heiss@proxmox.com>
To: pve-devel@lists.proxmox.com
Subject: [PATCH installer 2/8] install: move network subroutines to Proxmox::Sys::Net
Date: Fri,  8 May 2026 20:44:05 +0200	[thread overview]
Message-ID: <20260508184546.113293-3-c.heiss@proxmox.com> (raw)
In-Reply-To: <20260508184546.113293-1-c.heiss@proxmox.com>

As they are dealing with network, they make more sense over there.

No functional changes.

Signed-off-by: Christoph Heiss <c.heiss@proxmox.com>
---
 Proxmox/Install/RunEnv.pm | 160 ++------------------------------------
 Proxmox/Sys/Net.pm        | 152 +++++++++++++++++++++++++++++++++++-
 2 files changed, 157 insertions(+), 155 deletions(-)

diff --git a/Proxmox/Install/RunEnv.pm b/Proxmox/Install/RunEnv.pm
index 40041ad..b83b9ff 100644
--- a/Proxmox/Install/RunEnv.pm
+++ b/Proxmox/Install/RunEnv.pm
@@ -80,154 +80,6 @@ sub query_cpu_info : prototype() {
     return $cpu_info;
 }
 
-# Returns a hash.
-#
-# {
-#     <ifname> => {
-#         mac => <mac address>,
-#         index => <index>,
-#         name => <ifname>,
-#         state => <UP|DOWN|LOWERLAYERDOWN|DORMANT|TESTING|NOTPRESENT|UNKNOWN>,
-#         pinned_id => <sequential numerical ID>,
-#         driver => <driver name>,
-#         addresses => [
-#             family => <inet|inet6>,
-#             address => <mac address>,
-#             prefix => <length>,
-#         ],
-#     },
-# }
-my sub query_netdevs : prototype() {
-    my $ifs = {};
-    my $default;
-
-    # FIXME: not the same as the battle proven way we used in the installer for years?
-    my $interfaces = from_json(qx/ip --details --json address show/, { utf8 => 1 });
-
-    my $pinned_counter = 0;
-    for my $if (@$interfaces) {
-        my ($index, $name, $state, $mac, $addresses) =
-            $if->@{qw(ifindex ifname operstate address addr_info)};
-
-        next if !$name || $name eq 'lo'; # could also check flags for LOOPBACK..
-        if (!$mac) {
-            log_info("skipped interface $name, no mac address detected");
-            next;
-        }
-
-        my @valid_addrs;
-        if (uc($state) eq 'UP') {
-            for my $addr (@$addresses) {
-                next if $addr->{scope} eq 'link';
-
-                my ($family, $addr, $prefix) = $addr->@{qw(family local prefixlen)};
-
-                push @valid_addrs,
-                    {
-                        family => $family,
-                        address => $addr,
-                        prefix => $prefix,
-                    };
-            }
-        }
-
-        my $driver = readlink "/sys/class/net/$name/device/driver" || 'unknown';
-        $driver =~ s!^.*/!!;
-
-        $ifs->{$name} = {
-            index => $index,
-            name => $name,
-            mac => $mac,
-            state => uc($state),
-            driver => $driver,
-        };
-        $ifs->{$name}->{addresses} = \@valid_addrs if @valid_addrs;
-
-        # only set the `pinned_id` property if the interface actually can be pinned,
-        # i.e. is a physical link
-        my $is_pinnable =
-            Proxmox::Sys::Net::ip_link_is_physical($if) && !Proxmox::Sys::Net::iface_is_vf($name);
-        if ($is_pinnable) {
-            $ifs->{$name}->{pinned_id} = "${pinned_counter}";
-            $pinned_counter++;
-        }
-    }
-
-    return $ifs;
-}
-
-# Returns a hash.
-#
-# {
-#     gateway4 => {
-#         dst => "default",
-#         gateway => <ipv4>,
-#         dev => <ifname>,
-#     },
-#     gateway6 => {
-#         dst => "default",
-#         gateway => <ipv6>,
-#         dev => <ifname>,
-#     },
-# }
-my sub query_routes : prototype() {
-    my ($gateway4, $gateway6);
-
-    log_info("query routes");
-    my $route4 = from_json(qx/ip -4 --json route show/, { utf8 => 1 });
-    for my $route (@$route4) {
-        if ($route->{dst} eq 'default') {
-            $gateway4 = {
-                dev => $route->{dev},
-                gateway => $route->{gateway},
-            };
-            last;
-        }
-    }
-
-    my $route6 = from_json(qx/ip -6 --json route show/, { utf8 => 1 });
-    for my $route (@$route6) {
-        if ($route->{dst} eq 'default') {
-            $gateway6 = {
-                dev => $route->{dev},
-                gateway => $route->{gateway},
-            };
-            last;
-        }
-    }
-
-    my $routes;
-    $routes->{gateway4} = $gateway4 if $gateway4;
-    $routes->{gateway6} = $gateway6 if $gateway6;
-
-    return $routes;
-}
-
-# If `/etc/resolv.conf` fails to open this returns nothing.
-# Otherwise it returns a hash:
-# {
-#     dns => <first dns entry>,
-#
-my sub query_dns : prototype() {
-    log_info("query DNS from resolv.conf (managed by DHCP client)");
-    open my $fh, '<', '/etc/resolv.conf' or return;
-
-    my @dns;
-    my $domain;
-    while (defined(my $line = <$fh>)) {
-        if ($line =~ /^nameserver\s+(\S+)/) {
-            push @dns, $1;
-        } elsif (!defined($domain) && $line =~ /^domain\s+(\S+)/) {
-            $domain = $1;
-        }
-    }
-
-    my $output = {
-        domain => $domain,
-        @dns ? (dns => \@dns) : (),
-    };
-}
-
 # Uses `traceroute` and `geoiplookup`/`geoiplookup6` to figure out the current country.
 # Has a 10s timeout and uses the stops at the first entry found in the geoip database.
 my sub detect_country_tracing_to : prototype($$) {
@@ -294,9 +146,9 @@ my sub detect_country_tracing_to : prototype($$) {
 #     default_zfs_arc_max => <default upper limit for the ZFS ARC size in MiB>,
 #     disks => <see Proxmox::Sys::Block::hd_list()>,
 #     network => {
-#         interfaces => <see query_netdevs()>,
-#         routes => <see query_routes()>,
-#         dns => <see query_dns()>,
+#         interfaces => <see Proxmox::Sys::Net::query_netdevs()>,
+#         routes => <see Proxmox::Sys::Net::query_routes()>,
+#         dns => <see Proxmox::Sys::Net::query_dns()>,
 #     },
 # }
 sub query_installation_environment : prototype() {
@@ -315,14 +167,14 @@ sub query_installation_environment : prototype() {
     # else re-query everything
     my $output = {};
 
-    my $routes = query_routes();
+    my $routes = Proxmox::Sys::Net::query_routes();
 
     log_info("query block devices");
     $output->{disks} = Proxmox::Sys::Block::get_cached_disks();
     $output->{network} = {
-        interfaces => query_netdevs(),
+        interfaces => Proxmox::Sys::Net::query_netdevs(),
         routes => $routes,
-        dns => query_dns(),
+        dns => Proxmox::Sys::Net::query_dns(),
     };
 
     # avoid serializing out null or an empty string, that can trip up the UIs
diff --git a/Proxmox/Sys/Net.pm b/Proxmox/Sys/Net.pm
index e3b3b56..9571236 100644
--- a/Proxmox/Sys/Net.pm
+++ b/Proxmox/Sys/Net.pm
@@ -3,9 +3,10 @@ package Proxmox::Sys::Net;
 use strict;
 use warnings;
 
+use Proxmox::Log;
 use Proxmox::Sys::Command;
 use Proxmox::Sys::Udev;
-use JSON qw();
+use JSON qw(from_json);
 
 use base qw(Exporter);
 our @EXPORT_OK = qw(
@@ -257,6 +258,155 @@ sub udevadm_netdev_details {
     return $result;
 }
 
+# Returns a hash.
+#
+# {
+#     <ifname> => {
+#         mac => <mac address>,
+#         index => <index>,
+#         name => <ifname>,
+#         state => <UP|DOWN|LOWERLAYERDOWN|DORMANT|TESTING|NOTPRESENT|UNKNOWN>,
+#         pinned_id => <sequential numerical ID>,
+#         driver => <driver name>,
+#         addresses => [
+#             family => <inet|inet6>,
+#             address => <mac address>,
+#             prefix => <length>,
+#         ],
+#     },
+# }
+sub query_netdevs : prototype() {
+    my $ifs = {};
+    my $default;
+
+    # FIXME: not the same as the battle proven way we used in the installer for years?
+    my $interfaces = from_json(qx/ip --details --json address show/, { utf8 => 1 });
+
+    my $pinned_counter = 0;
+    for my $if (@$interfaces) {
+        my ($index, $name, $state, $mac, $addresses) =
+            $if->@{qw(ifindex ifname operstate address addr_info)};
+
+        next if !$name || $name eq 'lo'; # could also check flags for LOOPBACK..
+        if (!$mac) {
+            log_info("skipped interface $name, no mac address detected");
+            next;
+        }
+
+        my @valid_addrs;
+        if (uc($state) eq 'UP') {
+            for my $addr (@$addresses) {
+                next if $addr->{scope} eq 'link';
+
+                my ($family, $addr, $prefix) = $addr->@{qw(family local prefixlen)};
+
+                push @valid_addrs,
+                    {
+                        family => $family,
+                        address => $addr,
+                        prefix => $prefix,
+                    };
+            }
+        }
+
+        my $driver = readlink "/sys/class/net/$name/device/driver" || 'unknown';
+        $driver =~ s!^.*/!!;
+
+        $ifs->{$name} = {
+            index => $index,
+            name => $name,
+            mac => $mac,
+            state => uc($state),
+            driver => $driver,
+        };
+        $ifs->{$name}->{addresses} = \@valid_addrs if @valid_addrs;
+
+        # only set the `pinned_id` property if the interface actually can be pinned,
+        # i.e. is a physical link
+        my $is_pinnable =
+            Proxmox::Sys::Net::ip_link_is_physical($if) && !Proxmox::Sys::Net::iface_is_vf($name);
+        if ($is_pinnable) {
+            $ifs->{$name}->{pinned_id} = "${pinned_counter}";
+            $pinned_counter++;
+        }
+    }
+
+    return $ifs;
+}
+
+# Returns a hash.
+#
+# {
+#     gateway4 => {
+#         dst => "default",
+#         gateway => <ipv4>,
+#         dev => <ifname>,
+#     },
+#     gateway6 => {
+#         dst => "default",
+#         gateway => <ipv6>,
+#         dev => <ifname>,
+#     },
+# }
+sub query_routes : prototype() {
+    my ($gateway4, $gateway6);
+
+    log_info("query routes");
+    my $route4 = from_json(qx/ip -4 --json route show/, { utf8 => 1 });
+    for my $route (@$route4) {
+        if ($route->{dst} eq 'default') {
+            $gateway4 = {
+                dev => $route->{dev},
+                gateway => $route->{gateway},
+            };
+            last;
+        }
+    }
+
+    my $route6 = from_json(qx/ip -6 --json route show/, { utf8 => 1 });
+    for my $route (@$route6) {
+        if ($route->{dst} eq 'default') {
+            $gateway6 = {
+                dev => $route->{dev},
+                gateway => $route->{gateway},
+            };
+            last;
+        }
+    }
+
+    my $routes;
+    $routes->{gateway4} = $gateway4 if $gateway4;
+    $routes->{gateway6} = $gateway6 if $gateway6;
+
+    return $routes;
+}
+
+# If `/etc/resolv.conf` fails to open this returns nothing.
+# Otherwise it returns a hash:
+# {
+#     domain => <domain name or undefined, if not found>
+#     dns => [<dns servers>..],
+# }
+sub query_dns : prototype() {
+    log_info("query DNS from resolv.conf (managed by DHCP client)");
+    open my $fh, '<', '/etc/resolv.conf' or return;
+
+    my @dns;
+    my $domain;
+    while (defined(my $line = <$fh>)) {
+        if ($line =~ /^nameserver\s+(\S+)/) {
+            push @dns, $1;
+        } elsif (!defined($domain) && $line =~ /^domain\s+(\S+)/) {
+            $domain = $1;
+        }
+    }
+
+    my $output = {
+        domain => $domain,
+        @dns ? (dns => \@dns) : (),
+    };
+}
+
 # Tries to detect the hostname for this system given via DHCP, if available.
 # The hostname _might_ also include the local domain name, depending on the
 # concrete DHCP server implementation.
-- 
2.53.0





  parent reply	other threads:[~2026-05-08 18:46 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-05-08 18:44 [PATCH installer 0/8] add IPv6 SLAAC and v6-only support Christoph Heiss
2026-05-08 18:44 ` [PATCH installer 1/8] install: drop trivial fromjs() wrapper and use JSON::from_json() Christoph Heiss
2026-05-08 18:44 ` Christoph Heiss [this message]
2026-05-08 18:44 ` [PATCH installer 3/8] gui: use run_env->{network} instead of old run_env->{ipconf} Christoph Heiss
2026-05-08 18:44 ` [PATCH installer 4/8] sys: net: drop the now-unused `ipconf` runtime environment configuration Christoph Heiss
2026-05-08 18:44 ` [PATCH installer 5/8] sys: net: allow up to /128 netmask for IPv6 Christoph Heiss
2026-05-08 18:44 ` [PATCH RFC installer 6/8] sys: net: ignore ipv6 nameservers with zone identifiers Christoph Heiss
2026-05-08 18:44 ` [PATCH installer 7/8] common: options: rework network address setup to handle ipv6-only Christoph Heiss
2026-05-08 18:44 ` [PATCH installer 8/8] unconfigured: try to retrieve IPv6 SLAAC addresses on startup Christoph Heiss

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=20260508184546.113293-3-c.heiss@proxmox.com \
    --to=c.heiss@proxmox.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