diff --git a/debian/control b/debian/control
index d1d1602ae..f8cfb876c 100644
--- a/debian/control
+++ b/debian/control
@@ -1,384 +1,384 @@
 Source: vyos-1x
 Section: contrib/net
 Priority: extra
 Maintainer: VyOS Package Maintainers <maintainers@vyos.net>
 Build-Depends:
   debhelper (>= 9),
   dh-python,
   fakeroot,
   gcc,
   iproute2,
   libvyosconfig0 (>= 0.0.7),
   libzmq3-dev,
   python3 (>= 3.10),
 # For QA
   pylint,
 # For generating command definitions
   python3-lxml,
   python3-xmltodict,
 # For running tests
   python3-coverage,
   python3-hurry.filesize,
   python3-netaddr,
   python3-netifaces,
   python3-nose,
   python3-jinja2,
   python3-paramiko,
   python3-passlib,
   python3-psutil,
   python3-requests,
   python3-setuptools,
   python3-tabulate,
   python3-zmq,
   quilt,
   whois
 Standards-Version: 3.9.6
 
 Package: vyos-1x
 Architecture: amd64 arm64
 Pre-Depends:
   libpam-runtime [amd64],
   libnss-tacplus [amd64],
   libpam-tacplus [amd64],
   libpam-radius-auth [amd64]
 Depends:
 ## Fundamentals
   ${python3:Depends} (>= 3.10),
   dialog,
   libvyosconfig0,
   libpam-cap,
   bash-completion,
   ipvsadm,
   udev,
   less,
   at,
   rsync,
   vyatta-bash,
   vyatta-biosdevname,
   vyatta-cfg,
   vyos-http-api-tools,
   vyos-utils,
 ## End of Fundamentals
 ## Python libraries used in multiple modules and scripts
   python3,
   python3-cryptography,
   python3-hurry.filesize,
   python3-inotify,
   python3-jinja2,
   python3-jmespath,
   python3-netaddr,
   python3-netifaces,
   python3-paramiko,
   python3-passlib,
   python3-pyroute2,
   python3-psutil,
   python3-pyhumps,
   python3-pystache,
   python3-pyudev,
   python3-six,
   python3-tabulate,
   python3-voluptuous,
   python3-xmltodict,
   python3-zmq,
 ## End of Python libraries
 ## Basic System services and utilities
   coreutils,
   sudo,
   systemd,
   bsdmainutils,
   openssl,
   curl,
   dbus,
   file,
   iproute2 (>= 6.0.0),
   linux-cpupower,
 # ipaddrcheck is widely used in IP value validators
   ipaddrcheck,
-  ethtool,
+  ethtool (>= 6.10),
   lm-sensors,
   procps,
   netplug,
   sed,
   ssl-cert,
   tuned,
   beep,
   wide-dhcpv6-client,
 # Generic colorizer
   grc,
 ## End of System services and utilities
 ## For the installer
   fdisk,
   gdisk,
   mdadm,
   efibootmgr,
   libefivar1,
   dosfstools,
   grub-efi-amd64-signed [amd64],
   grub-efi-arm64-bin [arm64],
   mokutil [amd64],
   shim-signed [amd64],
   sbsigntool [amd64],
 # Image signature verification tool
   minisign,
 # Live filesystem tools
   squashfs-tools,
   fuse-overlayfs,
 ## End installer
   auditd,
   iputils-arping,
   iputils-ping,
   isc-dhcp-client,
 # For "vpn pptp", "vpn l2tp", "vpn sstp", "service ipoe-server"
   accel-ppp,
 # End "vpn pptp", "vpn l2tp", "vpn sstp", "service ipoe-server"
   avahi-daemon,
   conntrack,
   conntrackd,
 ## Conf mode features
 # For "interfaces wireless"
   hostapd,
   hsflowd,
   iw,
   wireless-regdb,
   wpasupplicant (>= 0.6.7),
 # End "interfaces wireless"
 # For "interfaces wwan"
   modemmanager,
   usb-modeswitch,
   libqmi-utils,
 # End "interfaces wwan"
 # For "interfaces openvpn"
   openvpn,
   openvpn-auth-ldap,
   openvpn-auth-radius,
   openvpn-otp,
   openvpn-dco,
   libpam-google-authenticator,
 # End "interfaces openvpn"
 # For "interfaces wireguard"
   wireguard-tools,
   qrencode,
 # End "interfaces wireguard"
 # For "interfaces pppoe"
   pppoe,
 # End "interfaces pppoe"
 # For "interfaces sstpc"
   sstp-client,
 # End "interfaces sstpc"
 # For "protocols *"
   frr (>= 9.1),
   frr-pythontools,
   frr-rpki-rtrlib,
   frr-snmp,
 # End "protocols *"
 # For "protocols nhrp" (part of DMVPN)
   opennhrp,
 # End "protocols nhrp"
 # For "protocols igmp-proxy"
   igmpproxy,
 # End "protocols igmp-proxy"
 # For "pki"
   certbot,
 # End "pki"
 # For "service console-server"
   conserver-client,
   conserver-server,
   console-data,
   dropbear,
 # End "service console-server"
 # For "service aws glb"
   aws-gwlbtun,
 # For "service dns dynamic"
   ddclient (>= 3.11.1),
 # End "service dns dynamic"
 # # For "service ids"
   fastnetmon [amd64],
   suricata,
   suricata-update,
 # End "service ids"
 # # For "service ndp-proxy"
   ndppd,
 # End "service ndp-proxy"
 # For "service router-advert"
   radvd,
 # End "service route-advert"
 # For "load-balancing reverse-proxy"
   haproxy,
 # End "load-balancing reverse-proxy"
 # For "load-balancing wan"
   vyatta-wanloadbalance,
 # End "load-balancing wan"
 # For "service dhcp-relay"
   isc-dhcp-relay,
 # For "service dhcp-server"
   kea,
 # End "service dhcp-server"
 # For "service lldp"
   lldpd,
 # End "service lldp"
 # For "service https"
   nginx-light,
 # End "service https"
 # For "service ssh"
   openssh-server,
   sshguard,
 # End "service ssh"
 # For "service salt-minion"
   salt-minion,
 # End "service salt-minion"
 # For "service snmp"
   snmp,
   snmpd,
 # End "service snmp"
 # For "service webproxy"
   squid,
   squidclient,
   squidguard,
 # End "service webproxy"
 # For "service monitoring telegraf"
   telegraf (>= 1.20),
 # End "service monitoring telegraf"
 # For "service monitoring zabbix-agent"
   zabbix-agent2,
 # End "service monitoring zabbix-agent"
 # For "service tftp-server"
   tftpd-hpa,
 # End "service tftp-server"
 # For "service dns forwarding"
   pdns-recursor,
 # End "service dns forwarding"
 # For "service sla owamp"
   owamp-client,
   owamp-server,
 # End "service sla owamp"
 # For "service sla twamp"
   twamp-client,
   twamp-server,
 # End "service sla twamp"
 # For "service broadcast-relay"
   udp-broadcast-relay,
 # End "service broadcast-relay"
 # For "high-availability vrrp"
   keepalived (>=2.0.5),
 # End "high-availability-vrrp"
 # For "system console"
   util-linux,
 # End "system console"
 # For "system task-scheduler"
   cron,
 # End "system task-scheduler"
 # For "system lcd"
   lcdproc,
   lcdproc-extra-drivers,
 # End "system lcd"
 # For "system config-management commit-archive"
   git,
 # End "system config-management commit-archive"
 # For firewall
   libndp-tools,
   libnetfilter-conntrack3,
   libnfnetlink0,
   nfct,
   nftables (>= 0.9.3),
 # For "vpn ipsec"
   strongswan (>= 5.9),
   strongswan-swanctl (>= 5.9),
   charon-systemd,
   libcharon-extra-plugins (>=5.9),
   libcharon-extauth-plugins (>=5.9),
   libstrongswan-extra-plugins (>=5.9),
   libstrongswan-standard-plugins (>=5.9),
   python3-vici (>= 5.7.2),
 # End "vpn ipsec"
 # For "nat64"
   jool,
 # End "nat64"
 # For "system conntrack modules rtsp"
   nat-rtsp,
 # End "system conntrack modules rtsp"
 # For "service ntp"
   chrony,
 # End "system ntp"
 # For "vpn openconnect"
   ocserv,
 # End "vpn openconnect"
 # For "system flow-accounting"
   pmacct (>= 1.6.0),
 # End "system flow-accounting"
 # For "system syslog"
   rsyslog,
 # End "system syslog"
 # For "system option keyboard-layout"
   kbd,
 # End "system option keyboard-layout"
 # For "container"
   podman (>=4.9.5),
   netavark,
   aardvark-dns,
 # iptables is only used for containers now, not the the firewall CLI
   iptables,
 # End container
 ## End Configuration mode
 ## Operational mode
 # Used for hypervisor model in "run show version"
   hvinfo,
 # For "run traceroute"
   traceroute,
 # For "run monitor traffic"
   tcpdump,
 # End "run monitor traffic"
 # For "show hardware dmi"
   dmidecode,
 # For "run show hardware storage smart"
   smartmontools,
 # For "run show hardware scsi"
   lsscsi,
 # For "run show hardware pci"
   pciutils,
 # For "show hardware usb"
   usbutils,
 # For "run show hardware storage nvme"
   nvme-cli,
 # For "run monitor bandwidth-test"
   iperf,
   iperf3,
 # End "run monitor bandwidth-test"
 # For "run wake-on-lan"
   etherwake,
 # For "run force ipv6-nd"
   ndisc6,
 # For "run monitor bandwidth"
   bmon,
 # For "run format disk"
   parted,
 # End Operational mode
 ## TPM tools
   cryptsetup,
   tpm2-tools,
 ## End TPM tools
 ## Optional utilities
   easy-rsa,
   tcptraceroute,
   mtr-tiny,
   telnet,
   stunnel4,
   uidmap
 ## End optional utilities
 Description: VyOS configuration scripts and data
  VyOS configuration scripts, interface definitions, and everything
 
 Package: vyos-1x-vmware
 Architecture: amd64
 Depends:
  vyos-1x,
  open-vm-tools
 Description: VyOS configuration scripts and data for VMware
  Adds configuration files required for VyOS running on VMware hosts.
 
 Package: vyos-1x-smoketest
 Architecture: all
 Depends:
  skopeo,
  snmp,
  vyos-1x
 Description: VyOS build sanity checking toolkit
diff --git a/python/vyos/ethtool.py b/python/vyos/ethtool.py
index 80bb56fa2..21272cc5b 100644
--- a/python/vyos/ethtool.py
+++ b/python/vyos/ethtool.py
@@ -1,204 +1,200 @@
 # Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io>
 #
 # This library is free software; you can redistribute it and/or
 # modify it under the terms of the GNU Lesser General Public
 # License as published by the Free Software Foundation; either
 # version 2.1 of the License, or (at your option) any later version.
 #
 # This library is distributed in the hope that it will be useful,
 # but WITHOUT ANY WARRANTY; without even the implied warranty of
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 # Lesser General Public License for more details.
 #
 # You should have received a copy of the GNU Lesser General Public
 # License along with this library.  If not, see <http://www.gnu.org/licenses/>.
 
 import re
 
 from json import loads
 from vyos.utils.network import interface_exists
 from vyos.utils.process import popen
 
 # These drivers do not support using ethtool to change the speed, duplex, or
 # flow control settings
 _drivers_without_speed_duplex_flow = ['vmxnet3', 'virtio_net', 'xen_netfront',
                                       'iavf', 'ice', 'i40e', 'hv_netvsc', 'veth', 'ixgbevf',
                                       'tun']
 
 class Ethtool:
     """
     Class is used to retrive and cache information about an ethernet adapter
     """
     # dictionary containing driver featurs, it will be populated on demand and
     # the content will look like:
     # [{'esp-hw-offload': {'active': False, 'fixed': True, 'requested': False},
     #   'esp-tx-csum-hw-offload': {'active': False,
     #                              'fixed': True,
     #                              'requested': False},
     #   'fcoe-mtu': {'active': False, 'fixed': True, 'requested': False},
     #   'generic-receive-offload': {'active': True,
     #                               'fixed': False,
     #                               'requested': True},
     #   'generic-segmentation-offload': {'active': True,
     #                                    'fixed': False,
     #                                    'requested': True},
     #   'highdma': {'active': True, 'fixed': False, 'requested': True},
     #   'ifname': 'eth0',
     #   'l2-fwd-offload': {'active': False, 'fixed': True, 'requested': False},
     #   'large-receive-offload': {'active': False,
     #                             'fixed': False,
     #                             'requested': False},
     # ...
     _features = { }
     # dictionary containing available interface speed and duplex settings
     # {
     #   '10'  : {'full': '', 'half': ''},
     #   '100' : {'full': '', 'half': ''},
     #   '1000': {'full': ''}
     #  }
-    _speed_duplex = {'auto': {'auto': ''}}
     _ring_buffer = None
     _driver_name = None
-    _auto_negotiation = False
-    _auto_negotiation_supported = None
     _flow_control = None
 
     def __init__(self, ifname):
         # Get driver used for interface
         if not interface_exists(ifname):
             raise ValueError(f'Interface "{ifname}" does not exist!')
 
         out, _ = popen(f'ethtool --driver {ifname}')
         driver = re.search(r'driver:\s(\w+)', out)
         if driver:
             self._driver_name = driver.group(1)
 
         # Build a dictinary of supported link-speed and dupley settings.
-        out, _ = popen(f'ethtool {ifname}')
-        reading = False
-        pattern = re.compile(r'\d+base.*')
-        for line in out.splitlines()[1:]:
-            line = line.lstrip()
-            if 'Supported link modes:' in line:
-                reading = True
-            if 'Supported pause frame use:' in line:
-                reading = False
-            if reading:
-                for block in line.split():
-                    if pattern.search(block):
-                        speed = block.split('base')[0]
-                        duplex = block.split('/')[-1].lower()
-                        if speed not in self._speed_duplex:
-                            self._speed_duplex.update({ speed : {}})
-                        if duplex not in self._speed_duplex[speed]:
-                            self._speed_duplex[speed].update({ duplex : ''})
-            if 'Supports auto-negotiation:' in line:
-                # Split the following string: Auto-negotiation: off
-                # we are only interested in off or on
-                tmp = line.split()[-1]
-                self._auto_negotiation_supported = bool(tmp == 'Yes')
-            # Only read in if Auto-negotiation is supported
-            if self._auto_negotiation_supported and 'Auto-negotiation:' in line:
-                # Split the following string: Auto-negotiation: off
-                # we are only interested in off or on
-                tmp = line.split()[-1]
-                self._auto_negotiation = bool(tmp == 'on')
+        # [ {
+        #     "ifname": "eth0",
+        #     "supported-ports": [ "TP" ],
+        #     "supported-link-modes": [ "10baseT/Half","10baseT/Full","100baseT/Half","100baseT/Full","1000baseT/Full" ],
+        #     "supported-pause-frame-use": "Symmetric",
+        #     "supports-auto-negotiation": true,
+        #     "supported-fec-modes": [ ],
+        #     "advertised-link-modes": [ "10baseT/Half","10baseT/Full","100baseT/Half","100baseT/Full","1000baseT/Full" ],
+        #     "advertised-pause-frame-use": "Symmetric",
+        #     "advertised-auto-negotiation": true,
+        #     "advertised-fec-modes": [ ],
+        #     "speed": 1000,
+        #     "duplex": "Full",
+        #     "auto-negotiation": false,
+        #     "port": "Twisted Pair",
+        #     "phyad": 1,
+        #     "transceiver": "internal",
+        #     "supports-wake-on": "pumbg",
+        #     "wake-on": "g",
+        #     "current-message-level": 7,
+        #     "link-detected": true
+        # } ]
+        out, _ = popen(f'ethtool --json {ifname}')
+        self._base_settings = loads(out)[0]
 
         # Now populate driver features
         out, _ = popen(f'ethtool --json --show-features {ifname}')
-        self._features = loads(out)
+        self._features = loads(out)[0]
 
         # Get information about NIC ring buffers
         out, _ = popen(f'ethtool --json --show-ring {ifname}')
-        self._ring_buffer = loads(out)
+        self._ring_buffer = loads(out)[0]
 
         # Get current flow control settings, but this is not supported by
         # all NICs (e.g. vmxnet3 does not support is)
         out, err = popen(f'ethtool --json --show-pause {ifname}')
         if not bool(err):
-            self._flow_control = loads(out)
+            self._flow_control = loads(out)[0]
 
     def check_auto_negotiation_supported(self):
         """ Check if the NIC supports changing auto-negotiation """
-        return self._auto_negotiation_supported
+        return self._base_settings['supports-auto-negotiation']
 
     def get_auto_negotiation(self):
-        return self._auto_negotiation_supported and self._auto_negotiation
+        return self._base_settings['supports-auto-negotiation'] and self._base_settings['auto-negotiation']
 
     def get_driver_name(self):
         return self._driver_name
 
     def _get_generic(self, feature):
         """
         Generic method to read self._features and return a tuple for feature
         enabled and feature is fixed.
 
         In case of a missing key, return "fixed = True and enabled = False"
         """
         active = False
         fixed = True
-        if feature in self._features[0]:
-            active = bool(self._features[0][feature]['active'])
-            fixed = bool(self._features[0][feature]['fixed'])
+        if feature in self._features:
+            active = bool(self._features[feature]['active'])
+            fixed = bool(self._features[feature]['fixed'])
         return active, fixed
 
     def get_generic_receive_offload(self):
         return self._get_generic('generic-receive-offload')
 
     def get_generic_segmentation_offload(self):
         return self._get_generic('generic-segmentation-offload')
 
     def get_hw_tc_offload(self):
         return self._get_generic('hw-tc-offload')
 
     def get_large_receive_offload(self):
         return self._get_generic('large-receive-offload')
 
     def get_scatter_gather(self):
         return self._get_generic('scatter-gather')
 
     def get_tcp_segmentation_offload(self):
         return self._get_generic('tcp-segmentation-offload')
 
     def get_ring_buffer_max(self, rx_tx):
         # Configuration of RX/TX ring-buffers is not supported on every device,
         # thus when it's impossible return None
         if rx_tx not in ['rx', 'tx']:
             ValueError('Ring-buffer type must be either "rx" or "tx"')
-        return str(self._ring_buffer[0].get(f'{rx_tx}-max', None))
+        return str(self._ring_buffer.get(f'{rx_tx}-max', None))
 
     def get_ring_buffer(self, rx_tx):
         # Configuration of RX/TX ring-buffers is not supported on every device,
         # thus when it's impossible return None
         if rx_tx not in ['rx', 'tx']:
             ValueError('Ring-buffer type must be either "rx" or "tx"')
-        return str(self._ring_buffer[0].get(rx_tx, None))
+        return str(self._ring_buffer.get(rx_tx, None))
 
     def check_speed_duplex(self, speed, duplex):
         """ Check if the passed speed and duplex combination is supported by
         the underlaying network adapter. """
         if isinstance(speed, int):
             speed = str(speed)
         if speed != 'auto' and not speed.isdigit():
             raise ValueError(f'Value "{speed}" for speed is invalid!')
         if duplex not in ['auto', 'full', 'half']:
             raise ValueError(f'Value "{duplex}" for duplex is invalid!')
 
+        if speed == 'auto' and duplex == 'auto':
+            return True
+
         if self.get_driver_name() in _drivers_without_speed_duplex_flow:
             return False
 
-        if speed in self._speed_duplex:
-            if duplex in self._speed_duplex[speed]:
-                return True
+        # ['10baset/half', '10baset/full', '100baset/half', '100baset/full', '1000baset/full']
+        tmp = [x.lower() for x in self._base_settings['supported-link-modes']]
+        if f'{speed}baset/{duplex}' in tmp:
+            return True
         return False
 
     def check_flow_control(self):
         """ Check if the NIC supports flow-control """
         return bool(self._flow_control)
 
     def get_flow_control(self):
         if self._flow_control == None:
             raise ValueError('Interface does not support changing '\
                              'flow-control settings!')
 
-        return 'on' if bool(self._flow_control[0]['autonegotiate']) else 'off'
+        return 'on' if bool(self._flow_control['autonegotiate']) else 'off'