Skip to content

Commit ed2d179

Browse files
authored
Merge pull request #36 from bernhardkaindl/add-ConnectionTypeByDeviceType
Thank you
2 parents ff50bb4 + 86f78a0 commit ed2d179

File tree

3 files changed

+128
-21
lines changed

3 files changed

+128
-21
lines changed

examples/async/netdevinfo-async.py

Lines changed: 53 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,57 @@
1010
import asyncio
1111
import sdbus
1212
from sdbus_async.networkmanager import (
13+
ConnectionType,
14+
NetworkConnectionSettings,
1315
NetworkManager,
16+
NetworkManagerSettings,
1417
NetworkDeviceGeneric,
1518
IPv4Config,
1619
DeviceType,
1720
NetworkDeviceWireless,
1821
WiFiOperationMode,
1922
AccessPoint,
2023
)
21-
from typing import Any, Dict, List, Tuple
24+
from typing import Any, Dict, List, Optional, Tuple
2225
NetworkManagerAddressData = List[Dict[str, Tuple[str, Any]]]
2326

2427

28+
async def get_most_recent_connection_id(ifname, dev_type) -> Optional[str]:
29+
"""Return the most-recently used connection_id for this device
30+
31+
Besides getting the currently active connection, this will succeed
32+
in getting the most recent connection when a device is not connected
33+
at the moment this function is executed.
34+
35+
It uses getattr(ConnectionType, dev_type) to get the connection_type
36+
used for connection_profiles for this DeviceType.
37+
38+
With a slight modification, this could return the most recent connections
39+
of the given device, ordered by the time of the last use of them.
40+
"""
41+
settings_service = NetworkManagerSettings()
42+
connection_paths: List[str] = await settings_service.connections
43+
conns = {}
44+
for connection_path in connection_paths:
45+
connection_manager = NetworkConnectionSettings(connection_path)
46+
connection = (await connection_manager.connection_profile()).connection
47+
# Filter connection profiles matching the connection type for the device:
48+
if connection.connection_type != getattr(ConnectionType, dev_type):
49+
continue
50+
# If the interface_name of a connection profiles is set, it must match:
51+
if connection.interface_name and connection.interface_name != ifname:
52+
continue
53+
# If connection.timestamp is not set, it was never active. Set it to 0:
54+
if not connection.timestamp:
55+
connection.timestamp = 0
56+
# Record the connection_ids of the matches, and timestamp is the key:
57+
conns[connection.timestamp] = connection.connection_id
58+
if not len(conns):
59+
return None
60+
# Returns the connection_id of the highest timestamp which was found:
61+
return conns.get(max(conns.keys()))
62+
63+
2564
async def list_networkdevice_details_async() -> None:
2665
nm = NetworkManager()
2766
devices_paths = await nm.get_devices()
@@ -31,11 +70,19 @@ async def list_networkdevice_details_async() -> None:
3170
device_ip4_conf_path: str = await generic_device.ip4_config
3271
if device_ip4_conf_path == "/":
3372
continue
73+
if not await generic_device.managed:
74+
continue
75+
dev_type = DeviceType(await generic_device.device_type).name
76+
if dev_type == DeviceType.BRIDGE.name:
77+
continue
3478

79+
dev_name = await generic_device.interface
3580
ip4_conf = IPv4Config(device_ip4_conf_path)
3681
gateway: str = await ip4_conf.gateway
3782

38-
print("Device: ", await generic_device.interface)
83+
print("Type: ", dev_type.title())
84+
print("Name: ", dev_name)
85+
3986
if gateway:
4087
print("Gateway:", gateway)
4188

@@ -47,7 +94,7 @@ async def list_networkdevice_details_async() -> None:
4794
for dns in nameservers:
4895
print("DNS: ", dns["address"][1])
4996

50-
if await generic_device.device_type == DeviceType.WIFI:
97+
if dev_type == DeviceType.WIFI.name:
5198
wifi = NetworkDeviceWireless(device_path)
5299
print("Wifi: ", WiFiOperationMode(await wifi.mode).name.title())
53100
ap = AccessPoint(await wifi.active_access_point)
@@ -56,6 +103,9 @@ async def list_networkdevice_details_async() -> None:
56103
print("SSID: ", ssid.decode("utf-8", "ignore"))
57104
if await ap.strength:
58105
print("Signal: ", await ap.strength)
106+
connection_id = await get_most_recent_connection_id(dev_name, dev_type)
107+
if connection_id:
108+
print("Profile:", connection_id)
59109

60110
print("")
61111

examples/block/netdevinfo.py

Lines changed: 70 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,46 +9,100 @@
99
# https://networkmanager.dev/docs/api/latest/ref-dbus-devices.html
1010
import sdbus
1111
from sdbus_block.networkmanager import (
12+
ConnectionType,
13+
NetworkConnectionSettings,
1214
NetworkManager,
15+
NetworkManagerSettings,
1316
NetworkDeviceGeneric,
1417
IPv4Config,
1518
DeviceType,
1619
NetworkDeviceWireless,
1720
WiFiOperationMode,
1821
AccessPoint,
1922
)
23+
from typing import Any, Dict, List, Optional, Tuple
24+
NetworkManagerAddressData = List[Dict[str, Tuple[str, Any]]]
25+
26+
27+
def get_most_recent_connection_id(ifname, dev_type) -> Optional[str]:
28+
"""Return the most-recently used connection_id for this device
29+
30+
Besides getting the currently active connection, this will succeed
31+
in getting the most recent connection when a device is not connected
32+
at the moment this function is executed.
33+
34+
It uses getattr(ConnectionType, dev_type) to get the connection_type
35+
used for connection_profiles for this DeviceType.
36+
37+
With a slight modification, this could return the most recent connections
38+
of the given device, ordered by the time of the last use of them.
39+
"""
40+
settings_service = NetworkManagerSettings()
41+
connection_paths: List[str] = settings_service.connections
42+
conns = {}
43+
for connection_path in connection_paths:
44+
connection_manager = NetworkConnectionSettings(connection_path)
45+
connection = connection_manager.connection_profile().connection
46+
# Filter connection profiles matching the connection type for the device:
47+
if connection.connection_type != getattr(ConnectionType, dev_type):
48+
continue
49+
# If the interface_name of a connection profiles is set, it must match:
50+
if connection.interface_name and connection.interface_name != ifname:
51+
continue
52+
# If connection.timestamp is not set, it was never active. Set it to 0:
53+
if not connection.timestamp:
54+
connection.timestamp = 0
55+
# Record the connection_ids of the matches, and timestamp is the key:
56+
conns[connection.timestamp] = connection.connection_id
57+
if not len(conns):
58+
return None
59+
# Returns the connection_id of the highest timestamp which was found:
60+
return conns.get(max(conns.keys()))
2061

2162

2263
def list_networkdevice_details_blocking() -> None:
23-
nm = NetworkManager()
24-
devices_paths = nm.get_devices()
2564

26-
for device_path in devices_paths:
65+
for device_path in NetworkManager().get_devices():
2766
generic_device = NetworkDeviceGeneric(device_path)
28-
device_ip4_conf_path = generic_device.ip4_config
67+
device_ip4_conf_path: str = generic_device.ip4_config
2968
if device_ip4_conf_path == "/":
3069
continue
70+
if not generic_device.managed:
71+
continue
72+
dev_type = DeviceType(generic_device.device_type).name
73+
if dev_type == DeviceType.BRIDGE.name:
74+
continue
3175

76+
dev_name = generic_device.interface
3277
ip4_conf = IPv4Config(device_ip4_conf_path)
78+
gateway: str = ip4_conf.gateway
79+
80+
print("Type: ", dev_type.title())
81+
print("Name: ", dev_name)
3382

34-
print("Device: ", generic_device.interface)
35-
if ip4_conf.gateway:
36-
print("Gateway:", ip4_conf.gateway)
83+
if gateway:
84+
print("Gateway:", gateway)
3785

38-
for ip4addr in ip4_conf.address_data:
39-
print(f'Address: {ip4addr["address"][1]}/{ip4addr["prefix"][1]}')
86+
address_data: NetworkManagerAddressData = ip4_conf.address_data
87+
for inetaddr in address_data:
88+
print(f'Address: {inetaddr["address"][1]}/{inetaddr["prefix"][1]}')
4089

41-
for dns in ip4_conf.nameserver_data:
90+
nameservers: NetworkManagerAddressData = ip4_conf.nameserver_data
91+
for dns in nameservers:
4292
print("DNS: ", dns["address"][1])
4393

44-
if generic_device.device_type == DeviceType.WIFI:
45-
wifidevice = NetworkDeviceWireless(device_path)
46-
print("Wifi: ", WiFiOperationMode(wifidevice.mode).name.title())
47-
ap = AccessPoint(wifidevice.active_access_point)
48-
if ap.ssid:
49-
print("SSID: ", ap.ssid.decode("utf-8", "ignore"))
94+
if dev_type == DeviceType.WIFI.name:
95+
wifi = NetworkDeviceWireless(device_path)
96+
print("Wifi: ", WiFiOperationMode(wifi.mode).name.title())
97+
ap = AccessPoint(wifi.active_access_point)
98+
ssid: bytes = ap.ssid
99+
if ssid:
100+
print("SSID: ", ssid.decode("utf-8", "ignore"))
50101
if ap.strength:
51102
print("Signal: ", ap.strength)
103+
connection_id = get_most_recent_connection_id(dev_name, dev_type)
104+
if connection_id:
105+
print("Profile:", connection_id)
52106

53107
print("")
54108

sdbus_async/networkmanager/enums.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -489,6 +489,9 @@ class DeviceStateReason(IntEnum):
489489
# sed 's/#define //;s/_SETTING_NAME//;s/ /=/' >.setting_defines
490490
# grep -f .connection_is_type .setting_defines |
491491
# sed 's/NM_SETTING_/ /;s/6L/SIXL/;/GENERIC/d;s/=/ = /'
492+
# Manual edit: This resulted in WIRED instead of ETHERNET, but
493+
# ETHERNET is the name used for DeviceType, so use ETHERNET instead to
494+
# be able to lookup connection profiles for Ethernet using DeviceType.
492495
#
493496
# One src/core/nm-device-*.c can support more than one ConnectionType,
494497
# thus there are more ConnectionTypes than DeviceTypes:
@@ -503,6 +506,7 @@ class ConnectionType(str, Enum):
503506
* BRIDGE
504507
* CDMA
505508
* DUMMY
509+
* ETHERNET
506510
* GSM
507511
* INFINIBAND
508512
* IP_TUNNEL
@@ -522,7 +526,6 @@ class ConnectionType(str, Enum):
522526
* VRF
523527
* VXLAN
524528
* WIFI_P2P
525-
* WIRED
526529
* WIREGUARD
527530
* WIFI
528531
* WPAN
@@ -533,6 +536,7 @@ class ConnectionType(str, Enum):
533536
BRIDGE = "bridge"
534537
CDMA = "cdma"
535538
DUMMY = "dummy"
539+
ETHERNET = "802-3-ethernet"
536540
GSM = "gsm"
537541
INFINIBAND = "infiniband"
538542
IP_TUNNEL = "ip-tunnel"
@@ -552,7 +556,6 @@ class ConnectionType(str, Enum):
552556
VRF = "vrf"
553557
VXLAN = "vxlan"
554558
WIFI_P2P = "wifi-p2p"
555-
WIRED = "802-3-ethernet"
556559
WIREGUARD = "wireguard"
557560
WIFI = "802-11-wireless"
558561
WPAN = "wpan"

0 commit comments

Comments
 (0)