├── sdbus_async └── networkmanager │ ├── py.typed │ ├── settings │ ├── dummy.py │ ├── ethtool.py │ ├── generic.py │ ├── vrf.py │ ├── veth.py │ ├── ovs_external_ids.py │ ├── bond_port.py │ ├── lowpan.py │ ├── ovs_patch.py │ ├── user.py │ ├── bluetooth.py │ ├── ovs_dpdk.py │ ├── wimax.py │ ├── bond.py │ ├── ovs_interface.py │ ├── olpc_mesh.py │ ├── proxy.py │ ├── wifi_p2p.py │ ├── ovs_bridge.py │ ├── macvlan.py │ ├── tc.py │ ├── serial.py │ ├── wpan.py │ ├── ovs_port.py │ ├── bridge_port.py │ ├── adsl.py │ ├── pppoe.py │ ├── cdma.py │ ├── infiniband.py │ ├── tun.py │ ├── sriov.py │ ├── vpn.py │ ├── macsec.py │ ├── team_port.py │ ├── hostname.py │ ├── vlan.py │ ├── __init__.py │ ├── match.py │ ├── ip_tunnel.py │ ├── vxlan.py │ └── wireguard.py │ └── types.py ├── sdbus_block └── networkmanager │ ├── py.typed │ ├── enums.py │ ├── settings │ ├── types.py │ └── exceptions.py ├── mypy.ini ├── docs ├── requirements.txt ├── index.rst ├── conf.py ├── other_interfaces.rst ├── enums.rst ├── examples.rst ├── device_interfaces.rst ├── objects.rst ├── profile_settings.rst └── quickstart.rst ├── tools └── jinja_templates │ ├── profile_settings.rst.jinja2 │ ├── __init__.py.jinja2 │ └── setting.py.jinja2 ├── .readthedocs.yml ├── pytest.ini ├── tests ├── __init__.py ├── settings │ ├── test_from_dbus_async.py │ └── test_from_dict_async.py └── test_settings_profile.py ├── .gitignore ├── README.md ├── examples ├── 2.0.0 │ ├── async │ │ ├── listen-device-changes-async.py │ │ ├── delete-connection-by-uuid-async.py │ │ ├── list-connections-async.py │ │ ├── update-connection-async.py │ │ ├── device-state-async.py │ │ ├── add-eth-connection-async.py │ │ └── netdevinfo-async.py │ └── block │ │ ├── delete-connection-by-uuid.py │ │ ├── update-connection.py │ │ ├── list-connections.py │ │ ├── device-state.py │ │ ├── add-eth-connection.py │ │ └── netdevinfo.py └── dev │ ├── async │ ├── listen-device-changes-async.py │ ├── delete-connection-by-uuid-async.py │ ├── list-connections-async.py │ ├── update-connection-async.py │ ├── device-state-async.py │ ├── add-eth-connection-async.py │ └── netdevinfo-async.py │ └── block │ ├── delete-connection-by-uuid.py │ ├── update-connection.py │ ├── list-connections.py │ ├── device-state.py │ ├── add-eth-connection.py │ └── netdevinfo.py ├── CHANGELOG.md └── setup.py /sdbus_async/networkmanager/py.typed: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /sdbus_block/networkmanager/py.typed: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /mypy.ini: -------------------------------------------------------------------------------- 1 | [mypy] 2 | namespace_packages = true 3 | 4 | -------------------------------------------------------------------------------- /sdbus_block/networkmanager/enums.py: -------------------------------------------------------------------------------- 1 | ../../sdbus_async/networkmanager/enums.py -------------------------------------------------------------------------------- /sdbus_block/networkmanager/settings: -------------------------------------------------------------------------------- 1 | ../../sdbus_async/networkmanager/settings/ -------------------------------------------------------------------------------- /sdbus_block/networkmanager/types.py: -------------------------------------------------------------------------------- 1 | ../../sdbus_async/networkmanager/types.py -------------------------------------------------------------------------------- /sdbus_block/networkmanager/exceptions.py: -------------------------------------------------------------------------------- 1 | ../../sdbus_async/networkmanager/exceptions.py -------------------------------------------------------------------------------- /docs/requirements.txt: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: LGPL-2.1-or-later 2 | # Copyright (C) 2023 igo95862 3 | sphinx_rtd_theme 4 | sdbus>=0.10.2 5 | -------------------------------------------------------------------------------- /tools/jinja_templates/profile_settings.rst.jinja2: -------------------------------------------------------------------------------- 1 | Connection Profile Settings Helpers 2 | =================================== 3 | 4 | {% for setting in all_settings -%} 5 | .. autoclass:: sdbus_async.networkmanager.settings.{{ setting.python_class_name }} 6 | :members: 7 | 8 | {% endfor %} 9 | -------------------------------------------------------------------------------- /.readthedocs.yml: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: LGPL-2.1-or-later 2 | # Copyright (C) 2023 igo95862 3 | --- 4 | 5 | version: 2 6 | 7 | build: 8 | os: "ubuntu-22.04" 9 | tools: 10 | python: "3.9" 11 | 12 | sphinx: 13 | configuration: "docs/conf.py" 14 | 15 | python: 16 | install: 17 | - requirements: docs/requirements.txt 18 | -------------------------------------------------------------------------------- /sdbus_async/networkmanager/settings/dummy.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: LGPL-2.1-or-later 2 | # This file was generated by tools/generate-settings-dataclasses-jinja.py, 3 | # if possible, please make changes by also updating the script. 4 | from __future__ import annotations 5 | from dataclasses import dataclass, field 6 | from typing import Optional 7 | from .base import NetworkManagerSettingsMixin 8 | 9 | 10 | @dataclass 11 | class DummySettings(NetworkManagerSettingsMixin): 12 | """Dummy Link Settings""" 13 | 14 | -------------------------------------------------------------------------------- /sdbus_async/networkmanager/settings/ethtool.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: LGPL-2.1-or-later 2 | # This file was generated by tools/generate-settings-dataclasses-jinja.py, 3 | # if possible, please make changes by also updating the script. 4 | from __future__ import annotations 5 | from dataclasses import dataclass, field 6 | from typing import Optional 7 | from .base import NetworkManagerSettingsMixin 8 | 9 | 10 | @dataclass 11 | class EthtoolSettings(NetworkManagerSettingsMixin): 12 | """Ethtool Ethernet Settings""" 13 | 14 | -------------------------------------------------------------------------------- /sdbus_async/networkmanager/settings/generic.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: LGPL-2.1-or-later 2 | # This file was generated by tools/generate-settings-dataclasses-jinja.py, 3 | # if possible, please make changes by also updating the script. 4 | from __future__ import annotations 5 | from dataclasses import dataclass, field 6 | from typing import Optional 7 | from .base import NetworkManagerSettingsMixin 8 | 9 | 10 | @dataclass 11 | class GenericSettings(NetworkManagerSettingsMixin): 12 | """Generic Link Settings""" 13 | 14 | -------------------------------------------------------------------------------- /sdbus_async/networkmanager/settings/vrf.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: LGPL-2.1-or-later 2 | # This file was generated by tools/generate-settings-dataclasses-jinja.py, 3 | # if possible, please make changes by also updating the script. 4 | from __future__ import annotations 5 | from dataclasses import dataclass, field 6 | from typing import Optional 7 | from .base import NetworkManagerSettingsMixin 8 | 9 | 10 | @dataclass 11 | class VrfSettings(NetworkManagerSettingsMixin): 12 | """VRF settings""" 13 | 14 | table: Optional[int] = field( 15 | metadata={ 16 | 'dbus_name': 'table', 17 | 'dbus_type': 'u', 18 | }, 19 | default=None, 20 | ) 21 | """The routing table for this VRF.""" 22 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | Network Manager binds for python-sdbus 2 | ====================================== 3 | 4 | This package contains python-sdbus for D-Bus interface 5 | of `NetworkManager `_. 6 | 7 | .. note:: 8 | See `upstream documentation for NetworkManager D-Bus API 9 | `_ 10 | for more detailed documentation. 11 | 12 | .. toctree:: 13 | :maxdepth: 3 14 | :caption: Contents: 15 | 16 | quickstart 17 | objects 18 | examples 19 | device_interfaces 20 | other_interfaces 21 | profile_settings 22 | enums 23 | exceptions 24 | 25 | See `python-sdbus `_ homepage if you are 26 | unfamiliar with python-sdbus. 27 | -------------------------------------------------------------------------------- /sdbus_async/networkmanager/settings/veth.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: LGPL-2.1-or-later 2 | # This file was generated by tools/generate-settings-dataclasses-jinja.py, 3 | # if possible, please make changes by also updating the script. 4 | from __future__ import annotations 5 | from dataclasses import dataclass, field 6 | from typing import Optional 7 | from .base import NetworkManagerSettingsMixin 8 | 9 | 10 | @dataclass 11 | class VethSettings(NetworkManagerSettingsMixin): 12 | """Veth Settings""" 13 | 14 | peer: Optional[str] = field( 15 | metadata={ 16 | 'dbus_name': 'peer', 17 | 'dbus_type': 's', 18 | }, 19 | default=None, 20 | ) 21 | """This property specifies the peer interface name of the veth. This 22 | property is mandatory.""" 23 | -------------------------------------------------------------------------------- /sdbus_async/networkmanager/settings/ovs_external_ids.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: LGPL-2.1-or-later 2 | # This file was generated by tools/generate-settings-dataclasses-jinja.py, 3 | # if possible, please make changes by also updating the script. 4 | from __future__ import annotations 5 | from dataclasses import dataclass, field 6 | from typing import Dict, Optional 7 | from .base import NetworkManagerSettingsMixin 8 | 9 | 10 | @dataclass 11 | class OvsExternalIdsSettings(NetworkManagerSettingsMixin): 12 | """OVS External IDs Settings""" 13 | 14 | data: Optional[Dict[str, str]] = field( 15 | metadata={ 16 | 'dbus_name': 'data', 17 | 'dbus_type': 'a{ss}', 18 | }, 19 | default=None, 20 | ) 21 | """A dictionary of key/value pairs with exernal-ids for OVS.""" 22 | -------------------------------------------------------------------------------- /sdbus_async/networkmanager/settings/bond_port.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: LGPL-2.1-or-later 2 | # This file was generated by tools/generate-settings-dataclasses-jinja.py, 3 | # if possible, please make changes by also updating the script. 4 | from __future__ import annotations 5 | from dataclasses import dataclass, field 6 | from typing import Optional 7 | from .base import NetworkManagerSettingsMixin 8 | 9 | 10 | @dataclass 11 | class BondPortSettings(NetworkManagerSettingsMixin): 12 | """Bond Port Settings""" 13 | 14 | queue_id: Optional[int] = field( 15 | metadata={ 16 | 'dbus_name': 'queue-id', 17 | 'dbus_type': 'u', 18 | }, 19 | default=None, 20 | ) 21 | """The queue ID of this bond port. The maximum value of queue ID is the 22 | number of TX queues currently active in device.""" 23 | -------------------------------------------------------------------------------- /sdbus_async/networkmanager/settings/lowpan.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: LGPL-2.1-or-later 2 | # This file was generated by tools/generate-settings-dataclasses-jinja.py, 3 | # if possible, please make changes by also updating the script. 4 | from __future__ import annotations 5 | from dataclasses import dataclass, field 6 | from typing import Optional 7 | from .base import NetworkManagerSettingsMixin 8 | 9 | 10 | @dataclass 11 | class LowpanSettings(NetworkManagerSettingsMixin): 12 | """6LoWPAN Settings""" 13 | 14 | parent: Optional[str] = field( 15 | metadata={ 16 | 'dbus_name': 'parent', 17 | 'dbus_type': 's', 18 | }, 19 | default=None, 20 | ) 21 | """If given, specifies the parent interface name or parent connection UUID 22 | from which this 6LowPAN interface should be created.""" 23 | -------------------------------------------------------------------------------- /sdbus_async/networkmanager/settings/ovs_patch.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: LGPL-2.1-or-later 2 | # This file was generated by tools/generate-settings-dataclasses-jinja.py, 3 | # if possible, please make changes by also updating the script. 4 | from __future__ import annotations 5 | from dataclasses import dataclass, field 6 | from typing import Optional 7 | from .base import NetworkManagerSettingsMixin 8 | 9 | 10 | @dataclass 11 | class OvsPatchSettings(NetworkManagerSettingsMixin): 12 | """OvsPatch Link Settings""" 13 | 14 | peer: Optional[str] = field( 15 | metadata={ 16 | 'dbus_name': 'peer', 17 | 'dbus_type': 's', 18 | }, 19 | default=None, 20 | ) 21 | """Specifies the name of the interface for the other side of the patch. The 22 | patch on the other side must also set this interface as peer.""" 23 | -------------------------------------------------------------------------------- /pytest.ini: -------------------------------------------------------------------------------- 1 | [pytest] 2 | # 3 | # Newer version of pytest-asyncio issue a DeprecationWarning unless 4 | # asyncio_mode is specified. This is because it is planned to change 5 | # the legacy default of automatically decorating async fixtures from 6 | # automatc to strict (only all functions and fixtures have to be marked). 7 | # 8 | # But only very recent versions of pytest-asyncio versions support 9 | # the asyncio_mode configuration setting and then issue a config warning, 10 | # which can't be filtered. 11 | # 12 | # Thus, filter the Deprecationwarning of pytest-asyncio for some time 13 | # until all users can be assumed to use the latest pytest-asyncio. 14 | # 15 | filterwarnings = 16 | ignore:The 'asyncio_mode' default value will change to 'strict' in future, please explicitly use 'asyncio_mode=strict' or 'asyncio_mode=auto' in pytest configuration file.:DeprecationWarning 17 | 18 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: LGPL-2.1-or-later 2 | 3 | # Copyright (C) 2022 igo95862 4 | 5 | # This file is part of python-sdbus 6 | 7 | # This library is free software; you can redistribute it and/or 8 | # modify it under the terms of the GNU Lesser General Public 9 | # License as published by the Free Software Foundation; either 10 | # version 2.1 of the License, or (at your option) any later version. 11 | 12 | # This library is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | # Lesser General Public License for more details. 16 | 17 | # You should have received a copy of the GNU Lesser General Public 18 | # License along with this library; if not, write to the Free Software 19 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20 | -------------------------------------------------------------------------------- /tools/jinja_templates/__init__.py.jinja2: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: LGPL-2.1-or-later 2 | # This file was generated by tools/generate-settings-dataclasses-jinja.py, 3 | # if possible, please make changes by also updating the script. 4 | from __future__ import annotations 5 | 6 | from .profile import ConnectionProfile 7 | {% for setting in all_settings -%} 8 | from .{{ setting.snake_name }} import {{ setting.python_class_name }} 9 | {% endfor %} 10 | from .datatypes import ( 11 | AddressData, 12 | RouteData, 13 | LinkWatchers, 14 | Vlans, 15 | WireguardPeers, 16 | RoutingRules, 17 | Vfs, 18 | ) 19 | 20 | __all__ = ( 21 | 'ConnectionProfile', 22 | {%- for setting in all_settings %} 23 | '{{ setting.python_class_name }}', 24 | {%- endfor %} 25 | 26 | 'AddressData', 27 | 'RouteData', 28 | 'LinkWatchers', 29 | 'Vlans', 30 | 'WireguardPeers', 31 | 'RoutingRules', 32 | 'Vfs', 33 | ) 34 | 35 | -------------------------------------------------------------------------------- /sdbus_async/networkmanager/settings/user.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: LGPL-2.1-or-later 2 | # This file was generated by tools/generate-settings-dataclasses-jinja.py, 3 | # if possible, please make changes by also updating the script. 4 | from __future__ import annotations 5 | from dataclasses import dataclass, field 6 | from typing import Dict, Optional 7 | from .base import NetworkManagerSettingsMixin 8 | 9 | 10 | @dataclass 11 | class UserSettings(NetworkManagerSettingsMixin): 12 | """General User Profile Settings""" 13 | 14 | data: Optional[Dict[str, str]] = field( 15 | metadata={ 16 | 'dbus_name': 'data', 17 | 'dbus_type': 'a{ss}', 18 | }, 19 | default=None, 20 | ) 21 | """A dictionary of key/value pairs with user data. This data is ignored by 22 | NetworkManager and can be used at the users discretion. The keys 23 | only support a strict ascii format, but the values can be arbitrary 24 | UTF8 strings up to a certain length.""" 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: LGPL-2.1-or-later 2 | 3 | # Copyright (C) 2020, 2021 igo95862 4 | 5 | # This file is part of py_sd_bus 6 | 7 | # This library is free software; you can redistribute it and/or 8 | # modify it under the terms of the GNU Lesser General Public 9 | # License as published by the Free Software Foundation; either 10 | # version 2.1 of the License, or (at your option) any later version. 11 | 12 | # This library is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | # Lesser General Public License for more details. 16 | 17 | # You should have received a copy of the GNU Lesser General Public 18 | # License along with this library; if not, write to the Free Software 19 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20 | .mypy_cache 21 | .vscode 22 | *.pyc 23 | __pycache__ 24 | build 25 | dev* 26 | strace*.txt 27 | *.so 28 | .cache 29 | wheels 30 | -------------------------------------------------------------------------------- /sdbus_async/networkmanager/settings/bluetooth.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: LGPL-2.1-or-later 2 | # This file was generated by tools/generate-settings-dataclasses-jinja.py, 3 | # if possible, please make changes by also updating the script. 4 | from __future__ import annotations 5 | from dataclasses import dataclass, field 6 | from typing import Optional 7 | from .base import NetworkManagerSettingsMixin 8 | 9 | 10 | @dataclass 11 | class BluetoothSettings(NetworkManagerSettingsMixin): 12 | """Bluetooth Settings""" 13 | 14 | bdaddr: Optional[bytes] = field( 15 | metadata={ 16 | 'dbus_name': 'bdaddr', 17 | 'dbus_type': 'ay', 18 | }, 19 | default=None, 20 | ) 21 | """The Bluetooth address of the device.""" 22 | bluetooth_type: Optional[str] = field( 23 | metadata={ 24 | 'dbus_name': 'type', 25 | 'dbus_type': 's', 26 | }, 27 | default=None, 28 | ) 29 | """Either "dun" for Dial-Up Networking connections or "panu" for Personal 30 | Area Networking connections to devices supporting the NAP profile.""" 31 | -------------------------------------------------------------------------------- /sdbus_async/networkmanager/settings/ovs_dpdk.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: LGPL-2.1-or-later 2 | # This file was generated by tools/generate-settings-dataclasses-jinja.py, 3 | # if possible, please make changes by also updating the script. 4 | from __future__ import annotations 5 | from dataclasses import dataclass, field 6 | from typing import Optional 7 | from .base import NetworkManagerSettingsMixin 8 | 9 | 10 | @dataclass 11 | class OvsDpdkSettings(NetworkManagerSettingsMixin): 12 | """OvsDpdk Link Settings""" 13 | 14 | devargs: Optional[str] = field( 15 | metadata={ 16 | 'dbus_name': 'devargs', 17 | 'dbus_type': 's', 18 | }, 19 | default=None, 20 | ) 21 | """Open vSwitch DPDK device arguments.""" 22 | n_rxq: Optional[int] = field( 23 | metadata={ 24 | 'dbus_name': 'n-rxq', 25 | 'dbus_type': 'u', 26 | }, 27 | default=None, 28 | ) 29 | """Open vSwitch DPDK number of rx queues. Defaults to zero which means to 30 | leave the parameter in OVS unspecified and effectively configures 31 | one queue.""" 32 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Documentation Status](https://readthedocs.org/projects/python-sdbus-networkmanager/badge/?version=latest)](https://python-sdbus-networkmanager.readthedocs.io/en/latest/?badge=latest) 2 | # NetworkManager binds for python-sdbus 3 | 4 | Supports both asyncio (under `sdbus_async.networkmanager` module) and blocking (under `sdbus_block.networkmanager` module) 5 | 6 | Implements most NetworkManager dbus interfaces and objects. 7 | 8 | ## Requirements 9 | 10 | * `python-sdbus` version higher than 0.8rc2 11 | 12 | See [python-sdbus requirements](https://github.com/python-sdbus/python-sdbus#requirements). 13 | 14 | ## Installation 15 | 16 | `pip install --only-binary ':all:' sdbus-networkmanager` 17 | 18 | # [Documentation](https://python-sdbus-networkmanager.readthedocs.io/en/latest/) 19 | 20 | See [this quickstart guide for brief introduction to NetworkManager D-Bus API](https://python-sdbus-networkmanager.readthedocs.io/en/latest/quickstart.html). 21 | 22 | This is the sub-project of [python-sdbus](https://github.com/python-sdbus/python-sdbus). 23 | 24 | See the [python-sdbus documentation](https://python-sdbus.readthedocs.io/en/latest/). 25 | -------------------------------------------------------------------------------- /sdbus_async/networkmanager/settings/wimax.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: LGPL-2.1-or-later 2 | # This file was generated by tools/generate-settings-dataclasses-jinja.py, 3 | # if possible, please make changes by also updating the script. 4 | from __future__ import annotations 5 | from dataclasses import dataclass, field 6 | from typing import Optional 7 | from .base import NetworkManagerSettingsMixin 8 | 9 | 10 | @dataclass 11 | class WimaxSettings(NetworkManagerSettingsMixin): 12 | """WiMax Settings""" 13 | 14 | mac_address: Optional[bytes] = field( 15 | metadata={ 16 | 'dbus_name': 'mac-address', 17 | 'dbus_type': 'ay', 18 | }, 19 | default=None, 20 | ) 21 | """If specified, this connection will only apply to the WiMAX device whose 22 | MAC address matches. This property does not change the MAC address 23 | of the device (known as MAC spoofing).""" 24 | network_name: Optional[str] = field( 25 | metadata={ 26 | 'dbus_name': 'network-name', 27 | 'dbus_type': 's', 28 | }, 29 | default=None, 30 | ) 31 | """Network Service Provider (NSP) name of the WiMAX network this connection 32 | should use.""" 33 | -------------------------------------------------------------------------------- /sdbus_async/networkmanager/settings/bond.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: LGPL-2.1-or-later 2 | # This file was generated by tools/generate-settings-dataclasses-jinja.py, 3 | # if possible, please make changes by also updating the script. 4 | from __future__ import annotations 5 | from dataclasses import dataclass, field 6 | from typing import Dict, Optional 7 | from .base import NetworkManagerSettingsMixin 8 | 9 | 10 | @dataclass 11 | class BondSettings(NetworkManagerSettingsMixin): 12 | """Bonding Settings""" 13 | 14 | interface_name: Optional[str] = field( 15 | metadata={ 16 | 'dbus_name': 'interface-name', 17 | 'dbus_type': 's', 18 | }, 19 | default=None, 20 | ) 21 | """Deprecated in favor of connection.interface-name, but can be used for 22 | backward-compatibility with older daemons, to set the bond's 23 | interface name.""" 24 | options: Optional[Dict[str, str]] = field( 25 | metadata={ 26 | 'dbus_name': 'options', 27 | 'dbus_type': 'a{ss}', 28 | }, 29 | default=None, 30 | ) 31 | """Dictionary of key/value pairs of bonding options. Both keys and values 32 | must be strings. Option names must contain only alphanumeric 33 | characters (ie, [a-zA-Z0-9]).""" 34 | -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: LGPL-2.1-or-later 2 | 3 | # Copyright (C) 2020-2023 igo95862 4 | 5 | # This file is part of python-sdbus 6 | 7 | # This library is free software; you can redistribute it and/or 8 | # modify it under the terms of the GNU Lesser General Public 9 | # License as published by the Free Software Foundation; either 10 | # version 2.1 of the License, or (at your option) any later version. 11 | 12 | # This library is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | # Lesser General Public License for more details. 16 | 17 | # You should have received a copy of the GNU Lesser General Public 18 | # License along with this library; if not, write to the Free Software 19 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20 | from os.path import abspath 21 | from sys import path 22 | 23 | project = 'python-sdbus-networkmanager' 24 | author = 'igo95862' 25 | source_suffix = '.rst' 26 | extensions = ['sdbus.autodoc'] 27 | html_theme = "sphinx_rtd_theme" 28 | 29 | autoclass_content = 'both' 30 | autodoc_typehints = 'description' 31 | autodoc_member_order = 'bysource' 32 | 33 | path.insert(0, abspath('..')) 34 | -------------------------------------------------------------------------------- /tools/jinja_templates/setting.py.jinja2: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: LGPL-2.1-or-later 2 | # This file was generated by tools/generate-settings-dataclasses-jinja.py, 3 | # if possible, please make changes by also updating the script. 4 | from __future__ import annotations 5 | from dataclasses import dataclass, field 6 | from typing import {{ setting.typing_imports|sort|join(', ') }} 7 | from .base import NetworkManagerSettingsMixin 8 | {% if setting.datatypes_imports -%} 9 | from .datatypes import {{ setting.datatypes_imports|sort|join(', ') }} 10 | {% endif %} 11 | 12 | @dataclass 13 | class {{ setting.python_class_name }}(NetworkManagerSettingsMixin): 14 | """{{ setting.description }}""" 15 | {%- if setting.secret_fields %} 16 | secret_fields_names = ['{{ setting.secret_fields|sort|join("', '") }}'] 17 | secret_name = '{{ setting.name }}' 18 | {%- endif %} 19 | {% for property in setting.properties %} 20 | {{ property.python_name }}: Optional[{{ property.python_type }}] = field( 21 | metadata={ 22 | 'dbus_name': '{{ property.name }}', 23 | 'dbus_type': '{{ property.dbus_type }}', 24 | {%- if property.python_inner_class %} 25 | 'dbus_inner_class': {{ property.python_inner_class }}, 26 | {%- endif %} 27 | }, 28 | default=None, 29 | ) 30 | """{{property.description}}"""{% endfor %} 31 | 32 | -------------------------------------------------------------------------------- /sdbus_async/networkmanager/settings/ovs_interface.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: LGPL-2.1-or-later 2 | # This file was generated by tools/generate-settings-dataclasses-jinja.py, 3 | # if possible, please make changes by also updating the script. 4 | from __future__ import annotations 5 | from dataclasses import dataclass, field 6 | from typing import Optional 7 | from .base import NetworkManagerSettingsMixin 8 | 9 | 10 | @dataclass 11 | class OvsInterfaceSettings(NetworkManagerSettingsMixin): 12 | """Open vSwitch Interface Settings""" 13 | 14 | ofport_request: Optional[int] = field( 15 | metadata={ 16 | 'dbus_name': 'ofport-request', 17 | 'dbus_type': 'u', 18 | }, 19 | default=None, 20 | ) 21 | """Open vSwitch openflow port number. Defaults to zero which means that 22 | port number will not be specified and it will be chosen randomly by 23 | ovs. OpenFlow ports are the network interfaces for passing packets 24 | between OpenFlow processing and the rest of the network. OpenFlow 25 | switches connect logically to each other via their OpenFlow ports.""" 26 | ovs_interface_type: Optional[str] = field( 27 | metadata={ 28 | 'dbus_name': 'type', 29 | 'dbus_type': 's', 30 | }, 31 | default=None, 32 | ) 33 | """The interface type. Either "internal", "system", "patch", "dpdk", or 34 | empty.""" 35 | -------------------------------------------------------------------------------- /sdbus_async/networkmanager/settings/olpc_mesh.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: LGPL-2.1-or-later 2 | # This file was generated by tools/generate-settings-dataclasses-jinja.py, 3 | # if possible, please make changes by also updating the script. 4 | from __future__ import annotations 5 | from dataclasses import dataclass, field 6 | from typing import Optional 7 | from .base import NetworkManagerSettingsMixin 8 | 9 | 10 | @dataclass 11 | class OlpcMeshSettings(NetworkManagerSettingsMixin): 12 | """OLPC Wireless Mesh Settings""" 13 | 14 | channel: Optional[int] = field( 15 | metadata={ 16 | 'dbus_name': 'channel', 17 | 'dbus_type': 'u', 18 | }, 19 | default=None, 20 | ) 21 | """Channel on which the mesh network to join is located.""" 22 | dhcp_anycast_address: Optional[bytes] = field( 23 | metadata={ 24 | 'dbus_name': 'dhcp-anycast-address', 25 | 'dbus_type': 'ay', 26 | }, 27 | default=None, 28 | ) 29 | """Anycast DHCP MAC address used when requesting an IP address via DHCP. 30 | The specific anycast address used determines which DHCP server class 31 | answers the request. 32 | 33 | This is currently only implemented by dhclient DHCP plugin.""" 34 | ssid: Optional[bytes] = field( 35 | metadata={ 36 | 'dbus_name': 'ssid', 37 | 'dbus_type': 'ay', 38 | }, 39 | default=None, 40 | ) 41 | """SSID of the mesh network to join.""" 42 | -------------------------------------------------------------------------------- /tests/settings/test_from_dbus_async.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # SPDX-License-Identifier: LGPL-2.1-or-later 3 | from sdbus_async.networkmanager import ( 4 | ConnectionProfile, 5 | ) 6 | 7 | 8 | def test_connection_profile_ipv4_from_dbus() -> None: 9 | """Parse connection and ipv4 settings from dbus using ConnectionProfile""" 10 | profile = ConnectionProfile.from_dbus( 11 | { 12 | "connection": { 13 | "id": ("s", 'Test for the connection id'), 14 | "uuid": ("s", '1ba25035-970b-4c4a-bf3c-8c6cdf8ab5d0'), 15 | "type": ("s", "802-3-ethernet"), 16 | "autoconnect": ('b', True), 17 | }, 18 | 'ipv4': { 19 | 'address-data': ( 20 | 'aa{sv}', 21 | [{'address': ('s', '192.0.2.1'), 'prefix': ('u', 24)}], 22 | ) 23 | }, 24 | } 25 | ) 26 | assert profile.connection.connection_id == "Test for the connection id" 27 | assert profile.connection.uuid == "1ba25035-970b-4c4a-bf3c-8c6cdf8ab5d0" 28 | assert profile.connection.connection_type == "802-3-ethernet" 29 | assert profile.connection.autoconnect is True 30 | assert profile.ipv4 31 | assert profile.ipv4.address_data 32 | assert profile.ipv4.address_data[0].address == "192.0.2.1" 33 | assert profile.ipv4.address_data[0].prefix == 24 34 | 35 | 36 | if __name__ == "__main__": 37 | """The tests can be run by pytest (and from IDEs by running this module)""" 38 | test_connection_profile_ipv4_from_dbus() 39 | -------------------------------------------------------------------------------- /sdbus_async/networkmanager/types.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2022 igo95862, bernhardkaindl 2 | 3 | # This file is part of python-sdbus 4 | 5 | # This library is free software; you can redistribute it and/or 6 | # modify it under the terms of the GNU Lesser General Public 7 | # License as published by the Free Software Foundation; either 8 | # version 2.1 of the License, or (at your option) any later version. 9 | 10 | # This library is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | # Lesser General Public License for more details. 14 | 15 | # You should have received a copy of the GNU Lesser General Public 16 | # License along with this library; if not, write to the Free Software 17 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | from typing import Any, Dict, Tuple 19 | 20 | # Type aliases for network connection settings and properties 21 | 22 | # "Any" might be str, int, bool (e.g. autoconnect), List[Ip] and maybe others 23 | NetworkManagerSetting = Tuple[str, Any] 24 | 25 | # A settings domain, e.g. ipv4.*, ipv6.*, 802-11-wireless-security.*, etc: 26 | NetworkManagerSettingsDomain = Dict[str, NetworkManagerSetting] 27 | 28 | # All settings and properties of a connection, e.g. returned by get_settings() 29 | NetworkManagerConnectionProperties = Dict[str, NetworkManagerSettingsDomain] 30 | 31 | # All settings and properties of a connection, but without dbus signatures 32 | SettingsDict = Dict[str, Dict[str, Any]] 33 | -------------------------------------------------------------------------------- /sdbus_async/networkmanager/settings/proxy.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: LGPL-2.1-or-later 2 | # This file was generated by tools/generate-settings-dataclasses-jinja.py, 3 | # if possible, please make changes by also updating the script. 4 | from __future__ import annotations 5 | from dataclasses import dataclass, field 6 | from typing import Optional 7 | from .base import NetworkManagerSettingsMixin 8 | 9 | 10 | @dataclass 11 | class ProxySettings(NetworkManagerSettingsMixin): 12 | """WWW Proxy Settings""" 13 | 14 | browser_only: Optional[bool] = field( 15 | metadata={ 16 | 'dbus_name': 'browser-only', 17 | 'dbus_type': 'b', 18 | }, 19 | default=None, 20 | ) 21 | """Whether the proxy configuration is for browser only.""" 22 | method: Optional[int] = field( 23 | metadata={ 24 | 'dbus_name': 'method', 25 | 'dbus_type': 'i', 26 | }, 27 | default=None, 28 | ) 29 | """Method for proxy configuration, Default is NM_SETTING_PROXY_METHOD_NONE 30 | (0)""" 31 | pac_script: Optional[str] = field( 32 | metadata={ 33 | 'dbus_name': 'pac-script', 34 | 'dbus_type': 's', 35 | }, 36 | default=None, 37 | ) 38 | """PAC script for the connection. This is an UTF-8 encoded javascript code 39 | that defines a FindProxyForURL() function.""" 40 | pac_url: Optional[str] = field( 41 | metadata={ 42 | 'dbus_name': 'pac-url', 43 | 'dbus_type': 's', 44 | }, 45 | default=None, 46 | ) 47 | """PAC URL for obtaining PAC file.""" 48 | -------------------------------------------------------------------------------- /examples/2.0.0/async/listen-device-changes-async.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # SPDX-License-Identifier: LGPL-2.1-or-later 3 | # Copyright (C) 2025 igo95862 4 | # 5 | # Example of listening to device state change signals. 6 | # Also shows the use of enums. 7 | from __future__ import annotations 8 | 9 | import asyncio 10 | from argparse import ArgumentParser 11 | 12 | import sdbus 13 | 14 | from sdbus_async.networkmanager import NetworkDeviceGeneric, NetworkManager 15 | from sdbus_async.networkmanager.enums import DeviceState, DeviceStateReason 16 | 17 | 18 | async def listen_device(device_path: str, device_name: str) -> None: 19 | generic_device = NetworkDeviceGeneric(device_path) 20 | print(f"Listening state changes for device {device_name!r}") 21 | 22 | async for ( 23 | new_state, 24 | old_state, 25 | reason, 26 | ) in generic_device.state_changed.catch(): 27 | print( 28 | f"Now {DeviceState(new_state).name}, " 29 | f"was {DeviceState(old_state).name}, " 30 | f"reason {DeviceStateReason(reason).name}" 31 | ) 32 | 33 | 34 | async def main() -> None: 35 | arg_parser = ArgumentParser() 36 | arg_parser.add_argument("device_name") 37 | 38 | args = arg_parser.parse_args() 39 | 40 | network_manager = NetworkManager() 41 | 42 | device_name = args.device_name 43 | device_path = await network_manager.get_device_by_ip_iface(device_name) 44 | 45 | # If you use create_task() make sure to keep a reference to the 46 | # task or it will get garbage collected. 47 | await listen_device(device_path, device_name) 48 | 49 | 50 | if __name__ == "__main__": 51 | sdbus.set_default_bus(sdbus.sd_bus_open_system()) 52 | asyncio.run(main()) 53 | -------------------------------------------------------------------------------- /examples/dev/async/listen-device-changes-async.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # SPDX-License-Identifier: LGPL-2.1-or-later 3 | # Copyright (C) 2025 igo95862 4 | # 5 | # Example of listening to device state change signals. 6 | # Also shows the use of enums. 7 | from __future__ import annotations 8 | 9 | import asyncio 10 | from argparse import ArgumentParser 11 | 12 | import sdbus 13 | 14 | from sdbus_async.networkmanager import NetworkDeviceGeneric, NetworkManager 15 | from sdbus_async.networkmanager.enums import DeviceState, DeviceStateReason 16 | 17 | 18 | async def listen_device(device_path: str, device_name: str) -> None: 19 | generic_device = NetworkDeviceGeneric(device_path) 20 | print(f"Listening state changes for device {device_name!r}") 21 | 22 | async for ( 23 | new_state, 24 | old_state, 25 | reason, 26 | ) in generic_device.state_changed.catch(): 27 | print( 28 | f"Now {DeviceState(new_state).name}, " 29 | f"was {DeviceState(old_state).name}, " 30 | f"reason {DeviceStateReason(reason).name}" 31 | ) 32 | 33 | 34 | async def main() -> None: 35 | arg_parser = ArgumentParser() 36 | arg_parser.add_argument("device_name") 37 | 38 | args = arg_parser.parse_args() 39 | 40 | network_manager = NetworkManager() 41 | 42 | device_name = args.device_name 43 | device_path = await network_manager.get_device_by_ip_iface(device_name) 44 | 45 | # If you use create_task() make sure to keep a reference to the 46 | # task or it will get garbage collected. 47 | await listen_device(device_path, device_name) 48 | 49 | 50 | if __name__ == "__main__": 51 | sdbus.set_default_bus(sdbus.sd_bus_open_system()) 52 | asyncio.run(main()) 53 | -------------------------------------------------------------------------------- /docs/other_interfaces.rst: -------------------------------------------------------------------------------- 1 | Other interfaces 2 | ============================ 3 | 4 | Non-device interfaces implemented by NetworkManager. 5 | 6 | .. autoclass:: sdbus_async.networkmanager.NetworkManagerInterfaceAsync 7 | :members: 8 | 9 | .. autoclass:: sdbus_async.networkmanager.NetworkManagerWifiP2PPeerInterfaceAsync 10 | :members: 11 | 12 | .. autoclass:: sdbus_async.networkmanager.NetworkManagerVPNPluginInterfaceAsync 13 | :members: 14 | 15 | .. autoclass:: sdbus_async.networkmanager.NetworkManagerSettingsInterfaceAsync 16 | :members: 17 | 18 | .. autoclass:: sdbus_async.networkmanager.NetworkManagerSettingsConnectionInterfaceAsync 19 | :members: 20 | 21 | .. autoclass:: sdbus_async.networkmanager.NetworkManagerSecretAgentInterfaceAsync 22 | :members: 23 | 24 | .. autoclass:: sdbus_async.networkmanager.NetworkManagerIP6ConfigInterfaceAsync 25 | :members: 26 | 27 | .. autoclass:: sdbus_async.networkmanager.NetworkManagerIP4ConfigInterfaceAsync 28 | :members: 29 | 30 | .. autoclass:: sdbus_async.networkmanager.NetworkManagerDnsManagerInterfaceAsync 31 | :members: 32 | 33 | .. autoclass:: sdbus_async.networkmanager.NetworkManagerDHCP6ConfigInterfaceAsync 34 | :members: 35 | 36 | .. autoclass:: sdbus_async.networkmanager.NetworkManagerDHCP4ConfigInterfaceAsync 37 | :members: 38 | 39 | .. autoclass:: sdbus_async.networkmanager.NetworkManagerVPNConnectionInterfaceAsync 40 | :members: 41 | 42 | .. autoclass:: sdbus_async.networkmanager.NetworkManagerConnectionActiveInterfaceAsync 43 | :members: 44 | 45 | .. autoclass:: sdbus_async.networkmanager.NetworkManagerCheckpointInterfaceAsync 46 | :members: 47 | 48 | .. autoclass:: sdbus_async.networkmanager.NetworkManagerSecretAgentManagerInterfaceAsync 49 | :members: 50 | -------------------------------------------------------------------------------- /sdbus_async/networkmanager/settings/wifi_p2p.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: LGPL-2.1-or-later 2 | # This file was generated by tools/generate-settings-dataclasses-jinja.py, 3 | # if possible, please make changes by also updating the script. 4 | from __future__ import annotations 5 | from dataclasses import dataclass, field 6 | from typing import Optional 7 | from .base import NetworkManagerSettingsMixin 8 | 9 | 10 | @dataclass 11 | class WifiP2PSettings(NetworkManagerSettingsMixin): 12 | """Wi-Fi P2P Settings""" 13 | 14 | peer: Optional[str] = field( 15 | metadata={ 16 | 'dbus_name': 'peer', 17 | 'dbus_type': 's', 18 | }, 19 | default=None, 20 | ) 21 | """The P2P device that should be connected to. Currently, this is the only 22 | way to create or join a group.""" 23 | wfd_ies: Optional[bytes] = field( 24 | metadata={ 25 | 'dbus_name': 'wfd-ies', 26 | 'dbus_type': 'ay', 27 | }, 28 | default=None, 29 | ) 30 | """The Wi-Fi Display (WFD) Information Elements (IEs) to set. 31 | 32 | Wi-Fi Display requires a protocol specific information element to be 33 | set in certain Wi-Fi frames. These can be specified here for the 34 | purpose of establishing a connection. This setting is only useful 35 | when implementing a Wi-Fi Display client.""" 36 | wps_method: Optional[int] = field( 37 | metadata={ 38 | 'dbus_name': 'wps-method', 39 | 'dbus_type': 'u', 40 | }, 41 | default=None, 42 | ) 43 | """Flags indicating which mode of WPS is to be used. 44 | 45 | There's little point in changing the default setting as 46 | NetworkManager will automatically determine the best method to use.""" 47 | -------------------------------------------------------------------------------- /examples/2.0.0/block/delete-connection-by-uuid.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # SPDX-License-Identifier: LGPL-2.1-or-later 3 | # 4 | # Create and delete a connection profile using the unique connection uuid 5 | # 6 | import logging 7 | import sdbus 8 | from uuid import uuid4 9 | from argparse import Namespace 10 | from sdbus_block.networkmanager import NetworkManagerSettings 11 | from sdbus_block.networkmanager import NmSettingsInvalidConnectionError 12 | 13 | 14 | def delete_connection_by_uuid(uuid: str) -> bool: 15 | """Find and delete the connection identified by the given UUID""" 16 | try: 17 | NetworkManagerSettings().delete_connection_by_uuid(uuid) 18 | except NmSettingsInvalidConnectionError: 19 | logging.getLogger().fatal(f"Connection {uuid} for deletion not found") 20 | return False 21 | return True 22 | 23 | 24 | def create_and_delete_wifi_psk_connection_async(args: Namespace) -> bool: 25 | """Add a temporary (not yet saved) network connection profile 26 | :param Namespace args: autoconnect, conn_id, psk, save, ssid, uuid 27 | :return: dbus connection path of the created connection profile 28 | """ 29 | add_wifi_psk_connection = __import__("add-wifi-psk-connection") 30 | if not add_wifi_psk_connection.add_wifi_psk_connection(args): 31 | return False 32 | return delete_connection_by_uuid(str(args.uuid)) 33 | 34 | 35 | if __name__ == "__main__": 36 | logging.basicConfig(format="%(message)s", level=logging.WARNING) 37 | sdbus.set_default_bus(sdbus.sd_bus_open_system()) 38 | args = Namespace(conn_id="Example", uuid=uuid4(), ssid="S", psk="Password") 39 | if create_and_delete_wifi_psk_connection_async(args): 40 | print(f"Succeeded in creating and deleting connection {args.uuid}") 41 | -------------------------------------------------------------------------------- /examples/dev/block/delete-connection-by-uuid.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # SPDX-License-Identifier: LGPL-2.1-or-later 3 | # 4 | # Create and delete a connection profile using the unique connection uuid 5 | # 6 | import logging 7 | import sdbus 8 | from uuid import uuid4 9 | from argparse import Namespace 10 | from sdbus_block.networkmanager import NetworkManagerSettings 11 | from sdbus_block.networkmanager import NmSettingsInvalidConnectionError 12 | 13 | 14 | def delete_connection_by_uuid(uuid: str) -> bool: 15 | """Find and delete the connection identified by the given UUID""" 16 | try: 17 | NetworkManagerSettings().delete_connection_by_uuid(uuid) 18 | except NmSettingsInvalidConnectionError: 19 | logging.getLogger().fatal(f"Connection {uuid} for deletion not found") 20 | return False 21 | return True 22 | 23 | 24 | def create_and_delete_wifi_psk_connection_async(args: Namespace) -> bool: 25 | """Add a temporary (not yet saved) network connection profile 26 | :param Namespace args: autoconnect, conn_id, psk, save, ssid, uuid 27 | :return: dbus connection path of the created connection profile 28 | """ 29 | add_wifi_psk_connection = __import__("add-wifi-psk-connection") 30 | if not add_wifi_psk_connection.add_wifi_psk_connection(args): 31 | return False 32 | return delete_connection_by_uuid(str(args.uuid)) 33 | 34 | 35 | if __name__ == "__main__": 36 | logging.basicConfig(format="%(message)s", level=logging.WARNING) 37 | sdbus.set_default_bus(sdbus.sd_bus_open_system()) 38 | args = Namespace(conn_id="Example", uuid=uuid4(), ssid="S", psk="Password") 39 | if create_and_delete_wifi_psk_connection_async(args): 40 | print(f"Succeeded in creating and deleting connection {args.uuid}") 41 | -------------------------------------------------------------------------------- /sdbus_async/networkmanager/settings/ovs_bridge.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: LGPL-2.1-or-later 2 | # This file was generated by tools/generate-settings-dataclasses-jinja.py, 3 | # if possible, please make changes by also updating the script. 4 | from __future__ import annotations 5 | from dataclasses import dataclass, field 6 | from typing import Optional 7 | from .base import NetworkManagerSettingsMixin 8 | 9 | 10 | @dataclass 11 | class OvsBridgeSettings(NetworkManagerSettingsMixin): 12 | """OvsBridge Link Settings""" 13 | 14 | datapath_type: Optional[str] = field( 15 | metadata={ 16 | 'dbus_name': 'datapath-type', 17 | 'dbus_type': 's', 18 | }, 19 | default=None, 20 | ) 21 | """The data path type. One of "system", "netdev" or empty.""" 22 | fail_mode: Optional[str] = field( 23 | metadata={ 24 | 'dbus_name': 'fail-mode', 25 | 'dbus_type': 's', 26 | }, 27 | default=None, 28 | ) 29 | """The bridge failure mode. One of "secure", "standalone" or empty.""" 30 | mcast_snooping_enable: Optional[bool] = field( 31 | metadata={ 32 | 'dbus_name': 'mcast-snooping-enable', 33 | 'dbus_type': 'b', 34 | }, 35 | default=None, 36 | ) 37 | """Enable or disable multicast snooping.""" 38 | rstp_enable: Optional[bool] = field( 39 | metadata={ 40 | 'dbus_name': 'rstp-enable', 41 | 'dbus_type': 'b', 42 | }, 43 | default=None, 44 | ) 45 | """Enable or disable RSTP.""" 46 | stp_enable: Optional[bool] = field( 47 | metadata={ 48 | 'dbus_name': 'stp-enable', 49 | 'dbus_type': 'b', 50 | }, 51 | default=None, 52 | ) 53 | """Enable or disable STP.""" 54 | -------------------------------------------------------------------------------- /sdbus_async/networkmanager/settings/macvlan.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: LGPL-2.1-or-later 2 | # This file was generated by tools/generate-settings-dataclasses-jinja.py, 3 | # if possible, please make changes by also updating the script. 4 | from __future__ import annotations 5 | from dataclasses import dataclass, field 6 | from typing import Optional 7 | from .base import NetworkManagerSettingsMixin 8 | 9 | 10 | @dataclass 11 | class MacvlanSettings(NetworkManagerSettingsMixin): 12 | """MAC VLAN Settings""" 13 | 14 | mode: Optional[int] = field( 15 | metadata={ 16 | 'dbus_name': 'mode', 17 | 'dbus_type': 'u', 18 | }, 19 | default=None, 20 | ) 21 | """The macvlan mode, which specifies the communication mechanism between 22 | multiple macvlans on the same lower device.""" 23 | parent: Optional[str] = field( 24 | metadata={ 25 | 'dbus_name': 'parent', 26 | 'dbus_type': 's', 27 | }, 28 | default=None, 29 | ) 30 | """If given, specifies the parent interface name or parent connection UUID 31 | from which this MAC-VLAN interface should be created. If this 32 | property is not specified, the connection must contain an 33 | "802-3-ethernet" setting with a "mac-address" property.""" 34 | promiscuous: Optional[bool] = field( 35 | metadata={ 36 | 'dbus_name': 'promiscuous', 37 | 'dbus_type': 'b', 38 | }, 39 | default=None, 40 | ) 41 | """Whether the interface should be put in promiscuous mode.""" 42 | tap: Optional[bool] = field( 43 | metadata={ 44 | 'dbus_name': 'tap', 45 | 'dbus_type': 'b', 46 | }, 47 | default=None, 48 | ) 49 | """Whether the interface should be a MACVTAP.""" 50 | -------------------------------------------------------------------------------- /docs/enums.rst: -------------------------------------------------------------------------------- 1 | Enums 2 | ================ 3 | 4 | Python's Enum quick intro 5 | ------------------------- 6 | 7 | There are two types of enums. ``IntEnum`` is used for a discrete values 8 | and ``IntFlag`` is used for bit flags. For example, :py:class:`DeviceType ` 9 | identifies a single device type as a device cannot be of multiple types. 10 | :py:class:`WifiCapabilitiesFlags ` 11 | shows a particular Wifi device capabilities which it can have multiple, for example, supporting 12 | both 5GHz and 2.4GHz radio bands. 13 | 14 | Usually ``IntEnum`` is implied unless the enum's name ends with ``Flag``. 15 | 16 | Example code using enums: 17 | 18 | .. code-block:: python 19 | 20 | from sdbus_async.networkmanager.enums import DeviceType, WifiCapabilitiesFlags 21 | 22 | # Get particular device type from an integer 23 | DeviceType(2) == DeviceType.WIFI 24 | # Returns: True 25 | 26 | # Check if a specific flag is enabled 27 | WifiCapabilitiesFlags.FREQ_2GHZ in WifiCapabilitiesFlags(0x00000400 | 0x00000200) 28 | # Returns: True 29 | 30 | # Iterate over all enabled flags 31 | list(WifiCapabilitiesFlags(0x00000400 | 0x00000200)) 32 | # Returns: [, ] 33 | 34 | `See Python's standard library documentation for more detailed 35 | tutorial and API reference. `_ 36 | 37 | NetworkManager's enums 38 | ------------------------- 39 | 40 | .. automodule:: sdbus_async.networkmanager.enums 41 | :members: 42 | 43 | Helper classes 44 | ----------------------- 45 | 46 | .. py:data:: DEVICE_TYPE_TO_CLASS 47 | :type: Dict[int, class] 48 | 49 | Mapping of NetworkManager device type int to the class. 50 | -------------------------------------------------------------------------------- /examples/2.0.0/async/delete-connection-by-uuid-async.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # SPDX-License-Identifier: LGPL-2.1-or-later 3 | # 4 | # Create and delete a connection profile using the unique connection uuid 5 | # 6 | import asyncio 7 | import logging 8 | import sdbus 9 | from uuid import uuid4 10 | from argparse import Namespace 11 | from sdbus_async.networkmanager import NetworkManagerSettings 12 | from sdbus_async.networkmanager import NmSettingsInvalidConnectionError 13 | 14 | 15 | async def delete_connection_by_uuid(uuid: str) -> bool: 16 | """Find and delete the connection identified by the given UUID""" 17 | try: 18 | await NetworkManagerSettings().delete_connection_by_uuid(uuid) 19 | except NmSettingsInvalidConnectionError: 20 | logging.getLogger().fatal(f"Connection {uuid} for deletion not found") 21 | return False 22 | return True 23 | 24 | 25 | async def create_and_delete_wifi_psk_connection_async(args: Namespace) -> bool: 26 | """Add a temporary (not yet saved) network connection profile 27 | :param Namespace args: autoconnect, conn_id, psk, save, ssid, uuid 28 | :return: dbus connection path of the created connection profile 29 | """ 30 | add_wifi_psk_connection = __import__("add-wifi-psk-connection-async") 31 | if not await add_wifi_psk_connection.add_wifi_psk_connection_async(args): 32 | return False 33 | return await delete_connection_by_uuid(str(args.uuid)) 34 | 35 | 36 | if __name__ == "__main__": 37 | logging.basicConfig(format="%(message)s", level=logging.WARNING) 38 | sdbus.set_default_bus(sdbus.sd_bus_open_system()) 39 | args = Namespace(conn_id="Example", uuid=uuid4(), ssid="S", psk="Password") 40 | if asyncio.run(create_and_delete_wifi_psk_connection_async(args)): 41 | print(f"Succeeded in creating and deleting connection {args.uuid}") 42 | -------------------------------------------------------------------------------- /examples/dev/async/delete-connection-by-uuid-async.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # SPDX-License-Identifier: LGPL-2.1-or-later 3 | # 4 | # Create and delete a connection profile using the unique connection uuid 5 | # 6 | import asyncio 7 | import logging 8 | import sdbus 9 | from uuid import uuid4 10 | from argparse import Namespace 11 | from sdbus_async.networkmanager import NetworkManagerSettings 12 | from sdbus_async.networkmanager import NmSettingsInvalidConnectionError 13 | 14 | 15 | async def delete_connection_by_uuid(uuid: str) -> bool: 16 | """Find and delete the connection identified by the given UUID""" 17 | try: 18 | await NetworkManagerSettings().delete_connection_by_uuid(uuid) 19 | except NmSettingsInvalidConnectionError: 20 | logging.getLogger().fatal(f"Connection {uuid} for deletion not found") 21 | return False 22 | return True 23 | 24 | 25 | async def create_and_delete_wifi_psk_connection_async(args: Namespace) -> bool: 26 | """Add a temporary (not yet saved) network connection profile 27 | :param Namespace args: autoconnect, conn_id, psk, save, ssid, uuid 28 | :return: dbus connection path of the created connection profile 29 | """ 30 | add_wifi_psk_connection = __import__("add-wifi-psk-connection-async") 31 | if not await add_wifi_psk_connection.add_wifi_psk_connection_async(args): 32 | return False 33 | return await delete_connection_by_uuid(str(args.uuid)) 34 | 35 | 36 | if __name__ == "__main__": 37 | logging.basicConfig(format="%(message)s", level=logging.WARNING) 38 | sdbus.set_default_bus(sdbus.sd_bus_open_system()) 39 | args = Namespace(conn_id="Example", uuid=uuid4(), ssid="S", psk="Password") 40 | if asyncio.run(create_and_delete_wifi_psk_connection_async(args)): 41 | print(f"Succeeded in creating and deleting connection {args.uuid}") 42 | -------------------------------------------------------------------------------- /sdbus_async/networkmanager/settings/tc.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: LGPL-2.1-or-later 2 | # This file was generated by tools/generate-settings-dataclasses-jinja.py, 3 | # if possible, please make changes by also updating the script. 4 | from __future__ import annotations 5 | from dataclasses import dataclass, field 6 | from typing import Any, List, Optional, Tuple 7 | from .base import NetworkManagerSettingsMixin 8 | from .datatypes import Qdiscs, Tfilters 9 | 10 | 11 | @dataclass 12 | class TcSettings(NetworkManagerSettingsMixin): 13 | """Linux Traffic Control Settings""" 14 | 15 | qdiscs: Optional[List[Qdiscs]] = field( 16 | metadata={ 17 | 'dbus_name': 'qdiscs', 18 | 'dbus_type': 'aa{sv}', 19 | 'dbus_inner_class': Qdiscs, 20 | }, 21 | default=None, 22 | ) 23 | """Array of TC queueing disciplines. 24 | 25 | When the "tc" setting is present, qdiscs from this property are 26 | applied upon activation. If the property is empty, all qdiscs are 27 | removed and the device will only have the default qdisc assigned by 28 | kernel according to the "net.core.default_qdisc" sysctl. 29 | 30 | If the "tc" setting is not present, NetworkManager doesn't touch the 31 | qdiscs present on the interface.""" 32 | tfilters: Optional[List[Tfilters]] = field( 33 | metadata={ 34 | 'dbus_name': 'tfilters', 35 | 'dbus_type': 'aa{sv}', 36 | 'dbus_inner_class': Tfilters, 37 | }, 38 | default=None, 39 | ) 40 | """Array of TC traffic filters. 41 | 42 | When the "tc" setting is present, filters from this property are 43 | applied upon activation. If the property is empty, NetworkManager 44 | removes all the filters. 45 | 46 | If the "tc" setting is not present, NetworkManager doesn't touch the 47 | filters present on the interface.""" 48 | -------------------------------------------------------------------------------- /sdbus_async/networkmanager/settings/serial.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: LGPL-2.1-or-later 2 | # This file was generated by tools/generate-settings-dataclasses-jinja.py, 3 | # if possible, please make changes by also updating the script. 4 | from __future__ import annotations 5 | from dataclasses import dataclass, field 6 | from typing import Optional 7 | from .base import NetworkManagerSettingsMixin 8 | 9 | 10 | @dataclass 11 | class SerialSettings(NetworkManagerSettingsMixin): 12 | """Serial Link Settings""" 13 | 14 | baud: Optional[int] = field( 15 | metadata={ 16 | 'dbus_name': 'baud', 17 | 'dbus_type': 'u', 18 | }, 19 | default=None, 20 | ) 21 | """Speed to use for communication over the serial port. Note that this 22 | value usually has no effect for mobile broadband modems as they 23 | generally ignore speed settings and use the highest available speed.""" 24 | bits: Optional[int] = field( 25 | metadata={ 26 | 'dbus_name': 'bits', 27 | 'dbus_type': 'u', 28 | }, 29 | default=None, 30 | ) 31 | """Byte-width of the serial communication. The 8 in "8n1" for example.""" 32 | parity: Optional[int] = field( 33 | metadata={ 34 | 'dbus_name': 'parity', 35 | 'dbus_type': 'y', 36 | }, 37 | default=None, 38 | ) 39 | """Parity setting of the serial port.""" 40 | send_delay: Optional[int] = field( 41 | metadata={ 42 | 'dbus_name': 'send-delay', 43 | 'dbus_type': 't', 44 | }, 45 | default=None, 46 | ) 47 | """Time to delay between each byte sent to the modem, in microseconds.""" 48 | stopbits: Optional[int] = field( 49 | metadata={ 50 | 'dbus_name': 'stopbits', 51 | 'dbus_type': 'u', 52 | }, 53 | default=None, 54 | ) 55 | """Number of stop bits for communication on the serial port. Either 1 or 56 | 2. The 1 in "8n1" for example.""" 57 | -------------------------------------------------------------------------------- /sdbus_async/networkmanager/settings/wpan.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: LGPL-2.1-or-later 2 | # This file was generated by tools/generate-settings-dataclasses-jinja.py, 3 | # if possible, please make changes by also updating the script. 4 | from __future__ import annotations 5 | from dataclasses import dataclass, field 6 | from typing import Optional 7 | from .base import NetworkManagerSettingsMixin 8 | 9 | 10 | @dataclass 11 | class WpanSettings(NetworkManagerSettingsMixin): 12 | """IEEE 802.15.4 (WPAN) MAC Settings""" 13 | 14 | channel: Optional[int] = field( 15 | metadata={ 16 | 'dbus_name': 'channel', 17 | 'dbus_type': 'i', 18 | }, 19 | default=None, 20 | ) 21 | """IEEE 802.15.4 channel. A positive integer or -1, meaning "do not set, 22 | use whatever the device is already set to".""" 23 | mac_address: Optional[str] = field( 24 | metadata={ 25 | 'dbus_name': 'mac-address', 26 | 'dbus_type': 's', 27 | }, 28 | default=None, 29 | ) 30 | """If specified, this connection will only apply to the IEEE 802.15.4 31 | (WPAN) MAC layer device whose permanent MAC address matches.""" 32 | page: Optional[int] = field( 33 | metadata={ 34 | 'dbus_name': 'page', 35 | 'dbus_type': 'i', 36 | }, 37 | default=None, 38 | ) 39 | """IEEE 802.15.4 channel page. A positive integer or -1, meaning "do not 40 | set, use whatever the device is already set to".""" 41 | pan_id: Optional[int] = field( 42 | metadata={ 43 | 'dbus_name': 'pan-id', 44 | 'dbus_type': 'u', 45 | }, 46 | default=None, 47 | ) 48 | """IEEE 802.15.4 Personal Area Network (PAN) identifier.""" 49 | short_address: Optional[int] = field( 50 | metadata={ 51 | 'dbus_name': 'short-address', 52 | 'dbus_type': 'u', 53 | }, 54 | default=None, 55 | ) 56 | """Short IEEE 802.15.4 address to be used within a restricted environment.""" 57 | -------------------------------------------------------------------------------- /sdbus_async/networkmanager/settings/ovs_port.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: LGPL-2.1-or-later 2 | # This file was generated by tools/generate-settings-dataclasses-jinja.py, 3 | # if possible, please make changes by also updating the script. 4 | from __future__ import annotations 5 | from dataclasses import dataclass, field 6 | from typing import Optional 7 | from .base import NetworkManagerSettingsMixin 8 | 9 | 10 | @dataclass 11 | class OvsPortSettings(NetworkManagerSettingsMixin): 12 | """OvsPort Link Settings""" 13 | 14 | bond_downdelay: Optional[int] = field( 15 | metadata={ 16 | 'dbus_name': 'bond-downdelay', 17 | 'dbus_type': 'u', 18 | }, 19 | default=None, 20 | ) 21 | """The time port must be inactive in order to be considered down.""" 22 | bond_mode: Optional[str] = field( 23 | metadata={ 24 | 'dbus_name': 'bond-mode', 25 | 'dbus_type': 's', 26 | }, 27 | default=None, 28 | ) 29 | """Bonding mode. One of "active-backup", "balance-slb", or "balance-tcp".""" 30 | bond_updelay: Optional[int] = field( 31 | metadata={ 32 | 'dbus_name': 'bond-updelay', 33 | 'dbus_type': 'u', 34 | }, 35 | default=None, 36 | ) 37 | """The time port must be active before it starts forwarding traffic.""" 38 | lacp: Optional[str] = field( 39 | metadata={ 40 | 'dbus_name': 'lacp', 41 | 'dbus_type': 's', 42 | }, 43 | default=None, 44 | ) 45 | """LACP mode. One of "active", "off", or "passive".""" 46 | tag: Optional[int] = field( 47 | metadata={ 48 | 'dbus_name': 'tag', 49 | 'dbus_type': 'u', 50 | }, 51 | default=None, 52 | ) 53 | """The VLAN tag in the range 0-4095.""" 54 | vlan_mode: Optional[str] = field( 55 | metadata={ 56 | 'dbus_name': 'vlan-mode', 57 | 'dbus_type': 's', 58 | }, 59 | default=None, 60 | ) 61 | """The VLAN mode. One of "access", "native-tagged", "native-untagged", 62 | "trunk" or unset.""" 63 | -------------------------------------------------------------------------------- /examples/2.0.0/block/update-connection.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # SPDX-License-Identifier: LGPL-2.1-or-later 3 | # 4 | # Update a property of a connection profile, looked up by connection id 5 | # 6 | # The IPv4 settings of connections profiles are documented here: 7 | # https://networkmanager.dev/docs/api/latest/settings-ipv4.html 8 | # 9 | 10 | import sdbus 11 | from functools import partial 12 | from sdbus_block.networkmanager import NetworkManagerSettings 13 | from sdbus_block.networkmanager import NetworkConnectionSettings 14 | from pprint import pprint 15 | from typing import Any, Dict 16 | 17 | 18 | def update_connection(args: Dict[str, Any]) -> None: 19 | """Update the settings for [key][entry] of the 1st matching connection""" 20 | con = NetworkManagerSettings().get_connections_by_id(args["connection_id"]) 21 | settings_domain, setting = args["connection_setting"] 22 | if con: 23 | connection_settings = NetworkConnectionSettings(con[0]) 24 | properties = connection_settings.get_settings() 25 | # For compatibility with old tools, NM adds and prefers them, delete: 26 | properties["ipv4"].pop("addresses") # -> Use ["ipv4"]["address-data"] 27 | properties["ipv4"].pop("routes") # ----> Use ["ipv4"]["route-data"] 28 | 29 | # Update the setting's value in the given configuration group: 30 | properties[settings_domain][setting] = args["value"] 31 | connection_settings.update(properties) 32 | 33 | print(f'Updated {properties["connection"]["uuid"]}.{settings_domain}:') 34 | partial(pprint, sort_dicts=False)(properties[settings_domain]) 35 | else: 36 | print(f"No connection matching {id}") 37 | 38 | 39 | if __name__ == "__main__": 40 | sdbus.set_default_bus(sdbus.sd_bus_open_system()) 41 | args = { 42 | # Set MyConnectionExample.ipv4.dns-search to "domain1.com,domain2.com": 43 | "connection_id": "MyConnectionExample", 44 | "connection_setting": ("ipv4", "dns-search"), 45 | # "as" is the so-called DBus signature, it means "array of strings": 46 | "value": ("as", ["domain1.com", "domain2.com"]), 47 | } 48 | update_connection(args) 49 | -------------------------------------------------------------------------------- /examples/dev/block/update-connection.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # SPDX-License-Identifier: LGPL-2.1-or-later 3 | # 4 | # Update a property of a connection profile, looked up by connection id 5 | # 6 | # The IPv4 settings of connections profiles are documented here: 7 | # https://networkmanager.dev/docs/api/latest/settings-ipv4.html 8 | # 9 | 10 | import sdbus 11 | from functools import partial 12 | from sdbus_block.networkmanager import NetworkManagerSettings 13 | from sdbus_block.networkmanager import NetworkConnectionSettings 14 | from pprint import pprint 15 | from typing import Any, Dict 16 | 17 | 18 | def update_connection(args: Dict[str, Any]) -> None: 19 | """Update the settings for [key][entry] of the 1st matching connection""" 20 | con = NetworkManagerSettings().get_connections_by_id(args["connection_id"]) 21 | settings_domain, setting = args["connection_setting"] 22 | if con: 23 | connection_settings = NetworkConnectionSettings(con[0]) 24 | properties = connection_settings.get_settings() 25 | # For compatibility with old tools, NM adds and prefers them, delete: 26 | properties["ipv4"].pop("addresses") # -> Use ["ipv4"]["address-data"] 27 | properties["ipv4"].pop("routes") # ----> Use ["ipv4"]["route-data"] 28 | 29 | # Update the setting's value in the given configuration group: 30 | properties[settings_domain][setting] = args["value"] 31 | connection_settings.update(properties) 32 | 33 | print(f'Updated {properties["connection"]["uuid"]}.{settings_domain}:') 34 | partial(pprint, sort_dicts=False)(properties[settings_domain]) 35 | else: 36 | print(f"No connection matching {id}") 37 | 38 | 39 | if __name__ == "__main__": 40 | sdbus.set_default_bus(sdbus.sd_bus_open_system()) 41 | args = { 42 | # Set MyConnectionExample.ipv4.dns-search to "domain1.com,domain2.com": 43 | "connection_id": "MyConnectionExample", 44 | "connection_setting": ("ipv4", "dns-search"), 45 | # "as" is the so-called DBus signature, it means "array of strings": 46 | "value": ("as", ["domain1.com", "domain2.com"]), 47 | } 48 | update_connection(args) 49 | -------------------------------------------------------------------------------- /sdbus_async/networkmanager/settings/bridge_port.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: LGPL-2.1-or-later 2 | # This file was generated by tools/generate-settings-dataclasses-jinja.py, 3 | # if possible, please make changes by also updating the script. 4 | from __future__ import annotations 5 | from dataclasses import dataclass, field 6 | from typing import Any, List, Optional, Tuple 7 | from .base import NetworkManagerSettingsMixin 8 | from .datatypes import Vlans 9 | 10 | 11 | @dataclass 12 | class BridgePortSettings(NetworkManagerSettingsMixin): 13 | """Bridge Port Settings""" 14 | 15 | hairpin_mode: Optional[bool] = field( 16 | metadata={ 17 | 'dbus_name': 'hairpin-mode', 18 | 'dbus_type': 'b', 19 | }, 20 | default=None, 21 | ) 22 | """Enables or disables "hairpin mode" for the port, which allows frames to 23 | be sent back out through the port the frame was received on.""" 24 | path_cost: Optional[int] = field( 25 | metadata={ 26 | 'dbus_name': 'path-cost', 27 | 'dbus_type': 'u', 28 | }, 29 | default=None, 30 | ) 31 | """The Spanning Tree Protocol (STP) port cost for destinations via this 32 | port.""" 33 | priority: Optional[int] = field( 34 | metadata={ 35 | 'dbus_name': 'priority', 36 | 'dbus_type': 'u', 37 | }, 38 | default=None, 39 | ) 40 | """The Spanning Tree Protocol (STP) priority of this bridge port.""" 41 | vlans: Optional[List[Vlans]] = field( 42 | metadata={ 43 | 'dbus_name': 'vlans', 44 | 'dbus_type': 'aa{sv}', 45 | 'dbus_inner_class': Vlans, 46 | }, 47 | default=None, 48 | ) 49 | """Array of bridge VLAN objects. In addition to the VLANs specified here, 50 | the port will also have the default-pvid VLAN configured on the 51 | bridge by the bridge.vlan-default-pvid property. 52 | 53 | In nmcli the VLAN list can be specified with the following syntax: 54 | 55 | $vid [pvid] [untagged] [, $vid [pvid] [untagged]]... 56 | 57 | where $vid is either a single id between 1 and 4094 or a range, 58 | represented as a couple of ids separated by a dash.""" 59 | -------------------------------------------------------------------------------- /sdbus_async/networkmanager/settings/adsl.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: LGPL-2.1-or-later 2 | # This file was generated by tools/generate-settings-dataclasses-jinja.py, 3 | # if possible, please make changes by also updating the script. 4 | from __future__ import annotations 5 | from dataclasses import dataclass, field 6 | from typing import Optional 7 | from .base import NetworkManagerSettingsMixin 8 | 9 | 10 | @dataclass 11 | class AdslSettings(NetworkManagerSettingsMixin): 12 | """ADSL Settings""" 13 | secret_fields_names = ['password'] 14 | secret_name = 'adsl' 15 | 16 | encapsulation: Optional[str] = field( 17 | metadata={ 18 | 'dbus_name': 'encapsulation', 19 | 'dbus_type': 's', 20 | }, 21 | default=None, 22 | ) 23 | """Encapsulation of ADSL connection. Can be "vcmux" or "llc".""" 24 | password: Optional[str] = field( 25 | metadata={ 26 | 'dbus_name': 'password', 27 | 'dbus_type': 's', 28 | }, 29 | default=None, 30 | ) 31 | """Password used to authenticate with the ADSL service.""" 32 | password_flags: Optional[int] = field( 33 | metadata={ 34 | 'dbus_name': 'password-flags', 35 | 'dbus_type': 'u', 36 | }, 37 | default=None, 38 | ) 39 | """Flags indicating how to handle the "password" property.""" 40 | protocol: Optional[str] = field( 41 | metadata={ 42 | 'dbus_name': 'protocol', 43 | 'dbus_type': 's', 44 | }, 45 | default=None, 46 | ) 47 | """ADSL connection protocol. Can be "pppoa", "pppoe" or "ipoatm".""" 48 | username: Optional[str] = field( 49 | metadata={ 50 | 'dbus_name': 'username', 51 | 'dbus_type': 's', 52 | }, 53 | default=None, 54 | ) 55 | """Username used to authenticate with the ADSL service.""" 56 | vci: Optional[int] = field( 57 | metadata={ 58 | 'dbus_name': 'vci', 59 | 'dbus_type': 'u', 60 | }, 61 | default=None, 62 | ) 63 | """VCI of ADSL connection""" 64 | vpi: Optional[int] = field( 65 | metadata={ 66 | 'dbus_name': 'vpi', 67 | 'dbus_type': 'u', 68 | }, 69 | default=None, 70 | ) 71 | """VPI of ADSL connection""" 72 | -------------------------------------------------------------------------------- /sdbus_async/networkmanager/settings/pppoe.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: LGPL-2.1-or-later 2 | # This file was generated by tools/generate-settings-dataclasses-jinja.py, 3 | # if possible, please make changes by also updating the script. 4 | from __future__ import annotations 5 | from dataclasses import dataclass, field 6 | from typing import Optional 7 | from .base import NetworkManagerSettingsMixin 8 | 9 | 10 | @dataclass 11 | class PppoeSettings(NetworkManagerSettingsMixin): 12 | """PPP-over-Ethernet Settings""" 13 | secret_fields_names = ['password'] 14 | secret_name = 'pppoe' 15 | 16 | parent: Optional[str] = field( 17 | metadata={ 18 | 'dbus_name': 'parent', 19 | 'dbus_type': 's', 20 | }, 21 | default=None, 22 | ) 23 | """If given, specifies the parent interface name on which this PPPoE 24 | connection should be created. If this property is not specified, 25 | the connection is activated on the interface specified in 26 | "interface-name" of NMSettingConnection.""" 27 | password: Optional[str] = field( 28 | metadata={ 29 | 'dbus_name': 'password', 30 | 'dbus_type': 's', 31 | }, 32 | default=None, 33 | ) 34 | """Password used to authenticate with the PPPoE service.""" 35 | password_flags: Optional[int] = field( 36 | metadata={ 37 | 'dbus_name': 'password-flags', 38 | 'dbus_type': 'u', 39 | }, 40 | default=None, 41 | ) 42 | """Flags indicating how to handle the "password" property.""" 43 | service: Optional[str] = field( 44 | metadata={ 45 | 'dbus_name': 'service', 46 | 'dbus_type': 's', 47 | }, 48 | default=None, 49 | ) 50 | """If specified, instruct PPPoE to only initiate sessions with access 51 | concentrators that provide the specified service. For most 52 | providers, this should be left blank. It is only required if there 53 | are multiple access concentrators or a specific service is known to 54 | be required.""" 55 | username: Optional[str] = field( 56 | metadata={ 57 | 'dbus_name': 'username', 58 | 'dbus_type': 's', 59 | }, 60 | default=None, 61 | ) 62 | """Username used to authenticate with the PPPoE service.""" 63 | -------------------------------------------------------------------------------- /sdbus_async/networkmanager/settings/cdma.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: LGPL-2.1-or-later 2 | # This file was generated by tools/generate-settings-dataclasses-jinja.py, 3 | # if possible, please make changes by also updating the script. 4 | from __future__ import annotations 5 | from dataclasses import dataclass, field 6 | from typing import Optional 7 | from .base import NetworkManagerSettingsMixin 8 | 9 | 10 | @dataclass 11 | class CdmaSettings(NetworkManagerSettingsMixin): 12 | """CDMA-based Mobile Broadband Settings""" 13 | secret_fields_names = ['password'] 14 | secret_name = 'cdma' 15 | 16 | mtu: Optional[int] = field( 17 | metadata={ 18 | 'dbus_name': 'mtu', 19 | 'dbus_type': 'u', 20 | }, 21 | default=None, 22 | ) 23 | """If non-zero, only transmit packets of the specified size or smaller, 24 | breaking larger packets up into multiple frames.""" 25 | number: Optional[str] = field( 26 | metadata={ 27 | 'dbus_name': 'number', 28 | 'dbus_type': 's', 29 | }, 30 | default=None, 31 | ) 32 | """The number to dial to establish the connection to the CDMA-based mobile 33 | broadband network, if any. If not specified, the default number 34 | (#777) is used when required.""" 35 | password: Optional[str] = field( 36 | metadata={ 37 | 'dbus_name': 'password', 38 | 'dbus_type': 's', 39 | }, 40 | default=None, 41 | ) 42 | """The password used to authenticate with the network, if required. Many 43 | providers do not require a password, or accept any password. But if 44 | a password is required, it is specified here.""" 45 | password_flags: Optional[int] = field( 46 | metadata={ 47 | 'dbus_name': 'password-flags', 48 | 'dbus_type': 'u', 49 | }, 50 | default=None, 51 | ) 52 | """Flags indicating how to handle the "password" property.""" 53 | username: Optional[str] = field( 54 | metadata={ 55 | 'dbus_name': 'username', 56 | 'dbus_type': 's', 57 | }, 58 | default=None, 59 | ) 60 | """The username used to authenticate with the network, if required. Many 61 | providers do not require a username, or accept any username. But if 62 | a username is required, it is specified here.""" 63 | -------------------------------------------------------------------------------- /sdbus_async/networkmanager/settings/infiniband.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: LGPL-2.1-or-later 2 | # This file was generated by tools/generate-settings-dataclasses-jinja.py, 3 | # if possible, please make changes by also updating the script. 4 | from __future__ import annotations 5 | from dataclasses import dataclass, field 6 | from typing import Optional 7 | from .base import NetworkManagerSettingsMixin 8 | 9 | 10 | @dataclass 11 | class InfinibandSettings(NetworkManagerSettingsMixin): 12 | """Infiniband Settings""" 13 | 14 | mac_address: Optional[bytes] = field( 15 | metadata={ 16 | 'dbus_name': 'mac-address', 17 | 'dbus_type': 'ay', 18 | }, 19 | default=None, 20 | ) 21 | """If specified, this connection will only apply to the IPoIB device whose 22 | permanent MAC address matches. This property does not change the MAC 23 | address of the device (i.e. MAC spoofing).""" 24 | mtu: Optional[int] = field( 25 | metadata={ 26 | 'dbus_name': 'mtu', 27 | 'dbus_type': 'u', 28 | }, 29 | default=None, 30 | ) 31 | """If non-zero, only transmit packets of the specified size or smaller, 32 | breaking larger packets up into multiple frames.""" 33 | p_key: Optional[int] = field( 34 | metadata={ 35 | 'dbus_name': 'p-key', 36 | 'dbus_type': 'i', 37 | }, 38 | default=None, 39 | ) 40 | """The InfiniBand P_Key to use for this device. A value of -1 means to use 41 | the default P_Key (aka "the P_Key at index 0"). Otherwise, it is a 42 | 16-bit unsigned integer, whose high bit is set if it is a "full 43 | membership" P_Key.""" 44 | parent: Optional[str] = field( 45 | metadata={ 46 | 'dbus_name': 'parent', 47 | 'dbus_type': 's', 48 | }, 49 | default=None, 50 | ) 51 | """The interface name of the parent device of this device. Normally NULL, 52 | but if the "p_key" property is set, then you must specify the base 53 | device by setting either this property or "mac-address".""" 54 | transport_mode: Optional[str] = field( 55 | metadata={ 56 | 'dbus_name': 'transport-mode', 57 | 'dbus_type': 's', 58 | }, 59 | default=None, 60 | ) 61 | """The IP-over-InfiniBand transport mode. Either "datagram" or "connected".""" 62 | -------------------------------------------------------------------------------- /docs/examples.rst: -------------------------------------------------------------------------------- 1 | Examples 2 | ================== 3 | 4 | Listing interfaces 5 | ------------------ 6 | 7 | List interface and their IPv4 adress using 8 | blocking API: 9 | 10 | .. code-block:: python 11 | 12 | from sdbus_block.networkmanager import ( 13 | NetworkManager, 14 | NetworkDeviceGeneric, 15 | IPv4Config, 16 | ) 17 | from sdbus import sd_bus_open_system 18 | 19 | system_bus = sd_bus_open_system() # We need system bus 20 | 21 | nm = NetworkManager(system_bus) 22 | 23 | devices_paths = nm.get_devices() 24 | 25 | for device_path in devices_paths: 26 | generic_device = NetworkDeviceGeneric(device_path, system_bus) 27 | print('Device: ', generic_device.interface) 28 | device_ip4_conf_path = generic_device.ip4_config 29 | if device_ip4_conf_path == '/': 30 | # This is how NetworkManager indicates there is no ip config 31 | # for the interface 32 | continue 33 | else: 34 | ip4_conf = IPv4Config(device_ip4_conf_path, system_bus) 35 | for address_data in ip4_conf.address_data: 36 | print(' Ip Adress:', address_data['address'][1]) 37 | 38 | Same but using async API: 39 | 40 | .. code-block:: python 41 | 42 | from sdbus_async.networkmanager import ( 43 | NetworkManager, 44 | NetworkDeviceGeneric, 45 | IPv4Config, 46 | ) 47 | from sdbus import sd_bus_open_system 48 | from asyncio import run as async_run 49 | 50 | system_bus = sd_bus_open_system() # We need system bus 51 | 52 | nm = NetworkManager(system_bus) 53 | 54 | 55 | async def test() -> None: 56 | devices_paths = await nm.get_devices() 57 | for device_path in devices_paths: 58 | generic_device = NetworkDeviceGeneric(device_path, system_bus) 59 | print('Device: ', await generic_device.interface) 60 | device_ip4_conf_path = await generic_device.ip4_config 61 | if device_ip4_conf_path == '/': 62 | # This is how NetworkManager indicates there is no ip config 63 | # for the interface 64 | continue 65 | else: 66 | ip4_conf = IPv4Config(device_ip4_conf_path, system_bus) 67 | for address_data in await ip4_conf.address_data: 68 | print(' Ip Adress:', address_data['address'][1]) 69 | 70 | async_run(test()) 71 | -------------------------------------------------------------------------------- /examples/dev/block/list-connections.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # SPDX-License-Identifier: LGPL-2.1-or-later 3 | # 4 | # Example which lists the details of NetworkManager's connection profiles. 5 | # 6 | # Configuration settings are described at 7 | # https://networkmanager.dev/docs/api/latest/ref-settings.html 8 | # 9 | # Example output: 10 | # | name: Wired connection 1 11 | # | uuid: b2caabdc-98bb-3f88-8d28-d10369d6ded9 12 | # | type: 802-3-ethernet 13 | # | interface-name: enx001e101f0000 14 | # | ipv4: method: manual 15 | # | ipaddr: 192.168.178.34/24 16 | # | route-metric: 200 17 | # | ipv6: method: disabled 18 | import sdbus 19 | from sdbus_block.networkmanager import ( 20 | ConnectionType, 21 | NetworkManagerSettings, 22 | NetworkConnectionSettings, 23 | ) 24 | 25 | 26 | def list_connection_profiles_blocking() -> None: 27 | """Call print_connection_profile_blocking() for all connection profiles""" 28 | networkmanager_settings = NetworkManagerSettings() 29 | for dbus_connection_path in networkmanager_settings.connections: 30 | print_connection_profile_blocking(dbus_connection_path) 31 | 32 | 33 | def print_connection_profile_blocking(connection_path: str) -> None: 34 | """Show the use of NetworkConnectionSettings(path).get_profile()""" 35 | profile = NetworkConnectionSettings(connection_path).get_profile() 36 | print("-------------------------------------------------------------") 37 | print("name:", profile.connection.connection_id) 38 | print("uuid:", profile.connection.uuid) 39 | print("type:", profile.connection.connection_type) 40 | if profile.connection.interface_name: 41 | print(" interface-name:", profile.connection.interface_name) 42 | if profile.ipv4: 43 | print("ipv4: method:", profile.ipv4.method) 44 | if profile.ipv4.address_data: 45 | for address in profile.ipv4.address_data: 46 | print(f' ipaddr: {address.address}/{address.prefix}') 47 | if profile.ipv4.route_metric: 48 | print(f' route-metric: {profile.ipv4.route_metric}') 49 | if profile.ipv6: 50 | print("ipv6: method:", profile.ipv6.method) 51 | if profile.connection.connection_type == ConnectionType.WIFI: 52 | assert profile.wireless 53 | assert profile.wireless.ssid 54 | print("ssid:", profile.wireless.ssid.decode()) 55 | 56 | 57 | if __name__ == "__main__": 58 | sdbus.set_default_bus(sdbus.sd_bus_open_system()) 59 | list_connection_profiles_blocking() 60 | -------------------------------------------------------------------------------- /examples/2.0.0/block/list-connections.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # SPDX-License-Identifier: LGPL-2.1-or-later 3 | # 4 | # Example which lists the details of NetworkManager's connection profiles. 5 | # 6 | # Configuration settings are described at 7 | # https://networkmanager.dev/docs/api/latest/ref-settings.html 8 | # 9 | # Example output: 10 | # | name: Wired connection 1 11 | # | uuid: b2caabdc-98bb-3f88-8d28-d10369d6ded9 12 | # | type: 802-3-ethernet 13 | # | interface-name: enx001e101f0000 14 | # | ipv4: method: manual 15 | # | ipaddr: 192.168.178.34/24 16 | # | route-metric: 200 17 | # | ipv6: method: disabled 18 | import sdbus 19 | from sdbus_block.networkmanager import ( 20 | ConnectionType, 21 | NetworkManagerSettings, 22 | NetworkConnectionSettings, 23 | ) 24 | 25 | 26 | def list_connection_profiles_blocking() -> None: 27 | """Call print_connection_profile_blocking() for all connection profiles""" 28 | networkmanager_settings = NetworkManagerSettings() 29 | for dbus_connection_path in networkmanager_settings.connections: 30 | print_connection_profile_blocking(dbus_connection_path) 31 | 32 | 33 | def print_connection_profile_blocking(connection_path: str) -> None: 34 | """Show the use of NetworkConnectionSettings(path).get_profile()""" 35 | profile = NetworkConnectionSettings(connection_path).get_profile() 36 | print("-------------------------------------------------------------") 37 | print("name:", profile.connection.connection_id) 38 | print("uuid:", profile.connection.uuid) 39 | print("type:", profile.connection.connection_type) 40 | if profile.connection.interface_name: 41 | print(" interface-name:", profile.connection.interface_name) 42 | if profile.ipv4: 43 | print("ipv4: method:", profile.ipv4.method) 44 | if profile.ipv4.address_data: 45 | for address in profile.ipv4.address_data: 46 | print(f' ipaddr: {address.address}/{address.prefix}') 47 | if profile.ipv4.route_metric: 48 | print(f' route-metric: {profile.ipv4.route_metric}') 49 | if profile.ipv6: 50 | print("ipv6: method:", profile.ipv6.method) 51 | if profile.connection.connection_type == ConnectionType.WIFI: 52 | assert profile.wireless 53 | assert profile.wireless.ssid 54 | print("ssid:", profile.wireless.ssid.decode()) 55 | 56 | 57 | if __name__ == "__main__": 58 | sdbus.set_default_bus(sdbus.sd_bus_open_system()) 59 | list_connection_profiles_blocking() 60 | -------------------------------------------------------------------------------- /sdbus_async/networkmanager/settings/tun.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: LGPL-2.1-or-later 2 | # This file was generated by tools/generate-settings-dataclasses-jinja.py, 3 | # if possible, please make changes by also updating the script. 4 | from __future__ import annotations 5 | from dataclasses import dataclass, field 6 | from typing import Optional 7 | from .base import NetworkManagerSettingsMixin 8 | 9 | 10 | @dataclass 11 | class TunSettings(NetworkManagerSettingsMixin): 12 | """Tunnel Settings""" 13 | 14 | group: Optional[str] = field( 15 | metadata={ 16 | 'dbus_name': 'group', 17 | 'dbus_type': 's', 18 | }, 19 | default=None, 20 | ) 21 | """The group ID which will own the device. If set to NULL everyone will be 22 | able to use the device.""" 23 | mode: Optional[int] = field( 24 | metadata={ 25 | 'dbus_name': 'mode', 26 | 'dbus_type': 'u', 27 | }, 28 | default=None, 29 | ) 30 | """The operating mode of the virtual device. Allowed values are 31 | NM_SETTING_TUN_MODE_TUN (1) to create a layer 3 device and 32 | NM_SETTING_TUN_MODE_TAP (2) to create an Ethernet-like layer 2 one.""" 33 | multi_queue: Optional[bool] = field( 34 | metadata={ 35 | 'dbus_name': 'multi-queue', 36 | 'dbus_type': 'b', 37 | }, 38 | default=None, 39 | ) 40 | """If the property is set to TRUE, the interface will support multiple file 41 | descriptors (queues) to parallelize packet sending or receiving. 42 | Otherwise, the interface will only support a single queue.""" 43 | owner: Optional[str] = field( 44 | metadata={ 45 | 'dbus_name': 'owner', 46 | 'dbus_type': 's', 47 | }, 48 | default=None, 49 | ) 50 | """The user ID which will own the device. If set to NULL everyone will be 51 | able to use the device.""" 52 | pi: Optional[bool] = field( 53 | metadata={ 54 | 'dbus_name': 'pi', 55 | 'dbus_type': 'b', 56 | }, 57 | default=None, 58 | ) 59 | """If TRUE the interface will prepend a 4 byte header describing the 60 | physical interface to the packets.""" 61 | vnet_hdr: Optional[bool] = field( 62 | metadata={ 63 | 'dbus_name': 'vnet-hdr', 64 | 'dbus_type': 'b', 65 | }, 66 | default=None, 67 | ) 68 | """If TRUE the IFF_VNET_HDR the tunnel packets will include a virtio 69 | network header.""" 70 | -------------------------------------------------------------------------------- /examples/2.0.0/async/list-connections-async.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # SPDX-License-Identifier: LGPL-2.1-or-later 3 | # 4 | # Example which lists the details of NetworkManager's connection profiles. 5 | # This is the asyncio variant of this example using sdbus_async.networkmanager. 6 | # The blocking variant of this example is examples/block/list-connections.py 7 | # 8 | # Configuration settings are described at 9 | # https://networkmanager.dev/docs/api/latest/ref-settings.html 10 | # 11 | # Example output: 12 | # | name: Wired connection 1 13 | # | uuid: b2caabdc-98bb-3f88-8d28-d10369d6ded9 14 | # | type: 802-3-ethernet 15 | # | interface-name: enx001e101f0000 16 | # | ipv4: method: manual 17 | # | ipaddr: 192.168.178.34/24 18 | # | route-metric: 200 19 | # | ipv6: method: disabled 20 | import asyncio 21 | import sdbus 22 | import pprint 23 | from sdbus_async.networkmanager import ( 24 | NetworkManagerSettings, 25 | NetworkConnectionSettings, 26 | ) 27 | from typing import List 28 | 29 | 30 | async def list_connection_profiles_async() -> None: 31 | networkmanager_settings = NetworkManagerSettings() 32 | connections_paths: List[str] = await networkmanager_settings.connections 33 | for dbus_connection_path in connections_paths: 34 | await print_connection_profile(dbus_connection_path) 35 | 36 | 37 | async def print_connection_profile(connection_path: str) -> None: 38 | connectionsettings_service = NetworkConnectionSettings(connection_path) 39 | profile = await connectionsettings_service.get_profile() 40 | connection = profile.connection 41 | print("-------------------------------------------------------------") 42 | print("name:", connection.connection_id) 43 | print("uuid:", connection.uuid) 44 | print("type:", connection.connection_type) 45 | if connection.interface_name: 46 | print(" interface-name:", connection.interface_name) 47 | if profile.ipv4: 48 | print("ipv4: method:", profile.ipv4.method) 49 | if profile.ipv4.address_data: 50 | for address in profile.ipv4.address_data: 51 | print(f' ipaddr: {address.address}/{address.prefix}') 52 | if profile.ipv4.route_metric: 53 | print(f' route-metric: {profile.ipv4.route_metric}') 54 | if profile.ipv6: 55 | print("ipv6: method:", profile.ipv6.method) 56 | pprint.pprint(profile.to_settings_dict(), sort_dicts=False) 57 | 58 | 59 | if __name__ == "__main__": 60 | sdbus.set_default_bus(sdbus.sd_bus_open_system()) 61 | asyncio.run(list_connection_profiles_async()) 62 | -------------------------------------------------------------------------------- /examples/dev/async/list-connections-async.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # SPDX-License-Identifier: LGPL-2.1-or-later 3 | # 4 | # Example which lists the details of NetworkManager's connection profiles. 5 | # This is the asyncio variant of this example using sdbus_async.networkmanager. 6 | # The blocking variant of this example is examples/block/list-connections.py 7 | # 8 | # Configuration settings are described at 9 | # https://networkmanager.dev/docs/api/latest/ref-settings.html 10 | # 11 | # Example output: 12 | # | name: Wired connection 1 13 | # | uuid: b2caabdc-98bb-3f88-8d28-d10369d6ded9 14 | # | type: 802-3-ethernet 15 | # | interface-name: enx001e101f0000 16 | # | ipv4: method: manual 17 | # | ipaddr: 192.168.178.34/24 18 | # | route-metric: 200 19 | # | ipv6: method: disabled 20 | import asyncio 21 | import sdbus 22 | import pprint 23 | from sdbus_async.networkmanager import ( 24 | NetworkManagerSettings, 25 | NetworkConnectionSettings, 26 | ) 27 | from typing import List 28 | 29 | 30 | async def list_connection_profiles_async() -> None: 31 | networkmanager_settings = NetworkManagerSettings() 32 | connections_paths: List[str] = await networkmanager_settings.connections 33 | for dbus_connection_path in connections_paths: 34 | await print_connection_profile(dbus_connection_path) 35 | 36 | 37 | async def print_connection_profile(connection_path: str) -> None: 38 | connectionsettings_service = NetworkConnectionSettings(connection_path) 39 | profile = await connectionsettings_service.get_profile() 40 | connection = profile.connection 41 | print("-------------------------------------------------------------") 42 | print("name:", connection.connection_id) 43 | print("uuid:", connection.uuid) 44 | print("type:", connection.connection_type) 45 | if connection.interface_name: 46 | print(" interface-name:", connection.interface_name) 47 | if profile.ipv4: 48 | print("ipv4: method:", profile.ipv4.method) 49 | if profile.ipv4.address_data: 50 | for address in profile.ipv4.address_data: 51 | print(f' ipaddr: {address.address}/{address.prefix}') 52 | if profile.ipv4.route_metric: 53 | print(f' route-metric: {profile.ipv4.route_metric}') 54 | if profile.ipv6: 55 | print("ipv6: method:", profile.ipv6.method) 56 | pprint.pprint(profile.to_settings_dict(), sort_dicts=False) 57 | 58 | 59 | if __name__ == "__main__": 60 | sdbus.set_default_bus(sdbus.sd_bus_open_system()) 61 | asyncio.run(list_connection_profiles_async()) 62 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 3.0.0 2 | 3 | ### Breaking changes 4 | 5 | All enums were revisisted and updated in accordance to NetworkManager documentation. 6 | 7 | Some enums and their fields were renamed: 8 | 9 | * `AccessPointCapabilities` -> `WifiAccessPointCapabilities` 10 | * `WirelessCapabilities` -> `WifiCapabilities` 11 | * `WpaSecurityFlags` -> `WifiAccessPointSecurityFlags` 12 | * `P2P_*` -> `PAIR_*` 13 | * `BROADCAST_*` -> `GROUP_*` 14 | * `AUTH_*` -> `KEY_MGMT_*` 15 | * `ConnectionState` -> `ActiveConnectionState` 16 | * `ConnectionStateReason` -> `ActiveConnectionStateReason` 17 | * `ConnectionFlags` -> `SettingsConnectionFlags` 18 | * `ConnectionStateFlags` -> `ActivationStateFlags` 19 | * `DeviceCapabilities` -> `DeviceCapabilitiesFlags` 20 | * `BluetoothCapabilities` -> `BluetoothCapabilitiesFlags` 21 | * `ModemCapabilities` -> `ModemCapabilitiesFlags` 22 | * `SecretAgentCapabilities` -> `SecretAgentCapabilitiesFlags` 23 | * `VpnState` -> `VpnServiceState` 24 | * `VpnFailure` 25 | * `LOGIN_FAILURE` -> `LOGIN_FAILED` 26 | 27 | New enums: 28 | 29 | * `NetworkManagerCapabilities` 30 | * `WimaxNSPNetworkType` 31 | * `SecretAgentGetSecretsFlags` 32 | * `CheckpointCreateFlags` 33 | * `CheckpointRollbackResult` 34 | * `SettingsAddConnection2Flags` 35 | * `SettingsUpdate2Flags` 36 | * `DeviceReapplyFlags` 37 | * `NetworkManagerReloadFlags` 38 | * `RadioFlags` 39 | * `MptcpFlags` 40 | * `VpnConnectionState` 41 | * `VpnConnectionStateReason` 42 | 43 | ## 2.0.0 44 | 45 | ### Warning if you used pre-release version 46 | 47 | `connection_profile` of `NetworkConnectionSettings` object has been replaced with 48 | equivalent `get_profile` method which can also fetch the secrets fields. (you can 49 | use `mypy` to check) 50 | 51 | ### Breaking changes 52 | 53 | * Renamed certain elements of `ConnectionType` enum to match `DeviceType` enum. 54 | 55 | * `WIRED` -> `ETHERNET` 56 | * `GSM` -> `MODEM` 57 | 58 | ### Features 59 | 60 | * Added connection settings dataclasses. 61 | Those dataclasses are found under `networkmanager.settings` sub-package. 62 | They allow for easy and typed reading, modifying and writing connection settings 63 | without dealing with D-Bus variants. 64 | 65 | Thank you @bernhardkaindl for spearheading this feature. 66 | 67 | New methods have been added to existing interfaces that utilize the new dataclasses: 68 | 69 | * `NetworkManagerSettingsConnectionInterface` 70 | 71 | * `get_profile` 72 | * `update_profile` 73 | 74 | * `NetworkManagerSettingsInterface` 75 | 76 | * `add_connection_profile` 77 | 78 | * `NetworkManagerInterfaceAsync` 79 | 80 | * `add_and_activate_connection_profile` 81 | 82 | * Added support for loopback devices from NetworkManager 1.42 83 | 84 | ## 1.1.0 85 | 86 | ### Features 87 | 88 | * Added NetworkManager errors as named exceptions. 89 | 90 | ## 1.0.0 91 | 92 | Initial release. 93 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: LGPL-2.1-or-later 2 | 3 | # Copyright (C) 2020, 2021 igo95862 4 | 5 | # This file is part of python-sdbus 6 | 7 | # This library is free software; you can redistribute it and/or 8 | # modify it under the terms of the GNU Lesser General Public 9 | # License as published by the Free Software Foundation; either 10 | # version 2.1 of the License, or (at your option) any later version. 11 | 12 | # This library is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | # Lesser General Public License for more details. 16 | 17 | # You should have received a copy of the GNU Lesser General Public 18 | # License along with this library; if not, write to the Free Software 19 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20 | from __future__ import annotations 21 | 22 | from setuptools import setup 23 | 24 | with open('./README.md') as f: 25 | long_description = f.read() 26 | 27 | setup( 28 | name='sdbus-networkmanager', 29 | description=('NetworkManager binds for sdbus.'), 30 | long_description=long_description, 31 | long_description_content_type='text/markdown', 32 | version='2.0.0', 33 | url='https://github.com/python-sdbus/python-sdbus-networkmanager', 34 | author='igo95862', 35 | author_email='igo95862@yandex.ru', 36 | license='LGPL-2.1-or-later', 37 | keywords='dbus networkmanager networking linux freedesktop', 38 | project_urls={ 39 | 'Documentation': 'https://python-sdbus-networkmanager.readthedocs.io/en/latest/', 40 | 'Source': 'https://github.com/python-sdbus/python-sdbus-networkmanager/', 41 | 'Tracker': 'https://github.com/python-sdbus/python-sdbus-networkmanager/issues/', 42 | }, 43 | classifiers=[ 44 | 'Development Status :: 4 - Beta', 45 | 'Intended Audience :: Developers', 46 | ( 47 | 'License :: OSI Approved :: ' 48 | 'GNU Lesser General Public License v2 or later (LGPLv2+)' 49 | ), 50 | 'Operating System :: POSIX :: Linux', 51 | 'Programming Language :: Python :: 3 :: Only', 52 | 'Topic :: Software Development :: Libraries :: Python Modules', 53 | ], 54 | packages=['sdbus_async.networkmanager', 55 | 'sdbus_async.networkmanager.settings', 56 | 'sdbus_block.networkmanager', 57 | 'sdbus_block.networkmanager.settings', 58 | ], 59 | package_data={ 60 | 'sdbus_async.networkmanager': [ 61 | 'py.typed', 62 | ], 63 | 'sdbus_block.networkmanager': [ 64 | 'py.typed', 65 | ], 66 | }, 67 | python_requires='>=3.7', 68 | install_requires=[ 69 | 'sdbus>=0.8rc2', 70 | ], 71 | ) 72 | -------------------------------------------------------------------------------- /docs/device_interfaces.rst: -------------------------------------------------------------------------------- 1 | Devices interfaces 2 | ================== 3 | 4 | Contains interfaces for most types of devices. 5 | 6 | .. autoclass:: sdbus_async.networkmanager.NetworkManagerDeviceBluetoothInterfaceAsync 7 | :members: 8 | 9 | .. autoclass:: sdbus_async.networkmanager.NetworkManagerDeviceBondInterfaceAsync 10 | :members: 11 | 12 | .. autoclass:: sdbus_async.networkmanager.NetworkManagerDeviceBridgeInterfaceAsync 13 | :members: 14 | 15 | .. autoclass:: sdbus_async.networkmanager.NetworkManagerDeviceGenericInterfaceAsync 16 | :members: 17 | 18 | .. autoclass:: sdbus_async.networkmanager.NetworkManagerDeviceIPTunnelInterfaceAsync 19 | :members: 20 | 21 | .. autoclass:: sdbus_async.networkmanager.NetworkManagerDeviceLowpanInterfaceAsync 22 | :members: 23 | 24 | .. autoclass:: sdbus_async.networkmanager.NetworkManagerDeviceMacsecInterfaceAsync 25 | :members: 26 | 27 | .. autoclass:: sdbus_async.networkmanager.NetworkManagerDeviceMacvlanInterfaceAsync 28 | :members: 29 | 30 | .. autoclass:: sdbus_async.networkmanager.NetworkManagerDeviceModemInterfaceAsync 31 | :members: 32 | 33 | .. autoclass:: sdbus_async.networkmanager.NetworkManagerDeviceOlpcMeshInterfaceAsync 34 | :members: 35 | 36 | .. autoclass:: sdbus_async.networkmanager.NetworkManagerDeviceOvsBridgeInterfaceAsync 37 | :members: 38 | 39 | .. autoclass:: sdbus_async.networkmanager.NetworkManagerDeviceOvsPortInterfaceAsync 40 | :members: 41 | 42 | .. autoclass:: sdbus_async.networkmanager.NetworkManagerDeviceStatisticsInterfaceAsync 43 | :members: 44 | 45 | .. autoclass:: sdbus_async.networkmanager.NetworkManagerDeviceTeamInterfaceAsync 46 | :members: 47 | 48 | .. autoclass:: sdbus_async.networkmanager.NetworkManagerDeviceTunInterfaceAsync 49 | :members: 50 | 51 | .. autoclass:: sdbus_async.networkmanager.NetworkManagerDeviceVethInterfaceAsync 52 | :members: 53 | 54 | .. autoclass:: sdbus_async.networkmanager.NetworkManagerDeviceVlanInterfaceAsync 55 | :members: 56 | 57 | .. autoclass:: sdbus_async.networkmanager.NetworkManagerDeviceVrfInterfaceAsync 58 | :members: 59 | 60 | .. autoclass:: sdbus_async.networkmanager.NetworkManagerDeviceVxlanInterfaceAsync 61 | :members: 62 | 63 | .. autoclass:: sdbus_async.networkmanager.NetworkManagerDeviceWifiP2PInterfaceAsync 64 | :members: 65 | 66 | .. autoclass:: sdbus_async.networkmanager.NetworkManagerDeviceWiredInterfaceAsync 67 | :members: 68 | 69 | .. autoclass:: sdbus_async.networkmanager.NetworkManagerDeviceWireGuardInterfaceAsync 70 | :members: 71 | 72 | .. autoclass:: sdbus_async.networkmanager.NetworkManagerDeviceWirelessInterfaceAsync 73 | :members: 74 | 75 | .. autoclass:: sdbus_async.networkmanager.NetworkManagerDeviceInterfaceAsync 76 | :members: 77 | 78 | .. autoclass:: sdbus_async.networkmanager.NetworkManagerPPPInterfaceAsync 79 | :members: 80 | 81 | .. autoclass:: sdbus_async.networkmanager.NetworkManagerLoopbackInterfaceAsync 82 | :members: 83 | -------------------------------------------------------------------------------- /sdbus_async/networkmanager/settings/sriov.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: LGPL-2.1-or-later 2 | # This file was generated by tools/generate-settings-dataclasses-jinja.py, 3 | # if possible, please make changes by also updating the script. 4 | from __future__ import annotations 5 | from dataclasses import dataclass, field 6 | from typing import Any, List, Optional, Tuple 7 | from .base import NetworkManagerSettingsMixin 8 | from .datatypes import Vfs 9 | 10 | 11 | @dataclass 12 | class SriovSettings(NetworkManagerSettingsMixin): 13 | """SR-IOV settings""" 14 | 15 | autoprobe_drivers: Optional[int] = field( 16 | metadata={ 17 | 'dbus_name': 'autoprobe-drivers', 18 | 'dbus_type': 'i', 19 | }, 20 | default=None, 21 | ) 22 | """Whether to autoprobe virtual functions by a compatible driver. 23 | 24 | If set to NM_TERNARY_TRUE (1), the kernel will try to bind VFs to a 25 | compatible driver and if this succeeds a new network interface will 26 | be instantiated for each VF. 27 | 28 | If set to NM_TERNARY_FALSE (0), VFs will not be claimed and no 29 | network interfaces will be created for them. 30 | 31 | When set to NM_TERNARY_DEFAULT (-1), the global default is used; in 32 | case the global default is unspecified it is assumed to be 33 | NM_TERNARY_TRUE (1).""" 34 | total_vfs: Optional[int] = field( 35 | metadata={ 36 | 'dbus_name': 'total-vfs', 37 | 'dbus_type': 'u', 38 | }, 39 | default=None, 40 | ) 41 | """The total number of virtual functions to create. 42 | 43 | Note that when the sriov setting is present NetworkManager enforces 44 | the number of virtual functions on the interface (also when it is 45 | zero) during activation and resets it upon deactivation. To prevent 46 | any changes to SR-IOV parameters don't add a sriov setting to the 47 | connection.""" 48 | vfs: Optional[List[Vfs]] = field( 49 | metadata={ 50 | 'dbus_name': 'vfs', 51 | 'dbus_type': 'aa{sv}', 52 | 'dbus_inner_class': Vfs, 53 | }, 54 | default=None, 55 | ) 56 | """Array of virtual function descriptors. 57 | 58 | Each VF descriptor is a dictionary mapping attribute names to 59 | GVariant values. The 'index' entry is mandatory for each VF. 60 | 61 | When represented as string a VF is in the form: 62 | 63 | "INDEX [ATTR=VALUE[ ATTR=VALUE]...]". 64 | 65 | for example: 66 | 67 | "2 mac=00:11:22:33:44:55 spoof-check=true". 68 | 69 | Multiple VFs can be specified using a comma as separator. Currently, 70 | the following attributes are supported: mac, spoof-check, trust, 71 | min-tx-rate, max-tx-rate, vlans. 72 | 73 | The "vlans" attribute is represented as a semicolon-separated list 74 | of VLAN descriptors, where each descriptor has the form 75 | 76 | "ID[.PRIORITY[.PROTO]]". 77 | 78 | PROTO can be either 'q' for 802.1Q (the default) or 'ad' for 79 | 802.1ad.""" 80 | -------------------------------------------------------------------------------- /examples/2.0.0/async/update-connection-async.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # SPDX-License-Identifier: LGPL-2.1-or-later 3 | # 4 | # Update a property of a connection profile, looked up by connection id 5 | # 6 | # This version uses connection_manager.get_profile().to_settings_dict() 7 | # to retrieve the connection profile from NetworkManager as a settings dict. 8 | # 9 | # It then updates it dynamically using the given arguments: 10 | # The default is to set ipv4.dns-search to ["domain1.com", "domain2.com"]. 11 | # 12 | # The dynamically updated dict is then used to update connection profile of NM. 13 | # 14 | # The IPv4 settings of connections profiles are documented here: 15 | # https://networkmanager.dev/docs/api/latest/settings-ipv4.html 16 | # 17 | import asyncio 18 | import sdbus 19 | from functools import partial 20 | from sdbus_async.networkmanager import NetworkManagerSettings 21 | from sdbus_async.networkmanager import NetworkConnectionSettings 22 | from sdbus_async.networkmanager.settings import ConnectionProfile 23 | from pprint import pprint 24 | from typing import Any, Dict 25 | 26 | 27 | async def update_connection_async(args: Dict[str, Any]) -> None: 28 | """Update the settings for [key][entry] of the 1st matching connection""" 29 | 30 | # Get the connection path of the connection(s) with the received id 31 | fn = NetworkManagerSettings().get_connections_by_id(args["connection_id"]) 32 | connection_paths = await fn 33 | if not connection_paths: 34 | print(f"No connection {id}, create with add-wifi-psk-connection-async") 35 | return 36 | 37 | # Get the profile settings of the first connection with given id 38 | connection_manager = NetworkConnectionSettings(connection_paths[0]) 39 | existing_connection_profile = await connection_manager.get_profile() 40 | settings = existing_connection_profile.to_settings_dict() 41 | 42 | # Update the given setting's property using the given value 43 | setting, property = args["connection_setting"] 44 | settings[setting][property] = args["value"] 45 | 46 | # Get a new ConnectionProfile with the change incorporated 47 | new_connection_profile = ConnectionProfile.from_settings_dict(settings) 48 | 49 | # Update the new ConnectionProfile in NetworkManager's configuration 50 | await connection_manager.update(new_connection_profile.to_dbus()) 51 | 52 | print(f'Updated {new_connection_profile.connection.uuid}.{setting}:') 53 | partial(pprint, sort_dicts=False)(settings) 54 | 55 | # Restore the previous connection profile: 56 | await connection_manager.update(existing_connection_profile.to_dbus()) 57 | 58 | 59 | if __name__ == "__main__": 60 | sdbus.set_default_bus(sdbus.sd_bus_open_system()) 61 | args = { 62 | # Set MyConnectionExample.ipv4.dns-search to "domain1.com,domain2.com": 63 | "connection_id": "MyConnectionExample", 64 | "connection_setting": ("ipv4", "dns-search"), 65 | "value": ["domain1.com", "domain2.com"], 66 | } 67 | asyncio.run(update_connection_async(args)) 68 | -------------------------------------------------------------------------------- /examples/dev/async/update-connection-async.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # SPDX-License-Identifier: LGPL-2.1-or-later 3 | # 4 | # Update a property of a connection profile, looked up by connection id 5 | # 6 | # This version uses connection_manager.get_profile().to_settings_dict() 7 | # to retrieve the connection profile from NetworkManager as a settings dict. 8 | # 9 | # It then updates it dynamically using the given arguments: 10 | # The default is to set ipv4.dns-search to ["domain1.com", "domain2.com"]. 11 | # 12 | # The dynamically updated dict is then used to update connection profile of NM. 13 | # 14 | # The IPv4 settings of connections profiles are documented here: 15 | # https://networkmanager.dev/docs/api/latest/settings-ipv4.html 16 | # 17 | import asyncio 18 | import sdbus 19 | from functools import partial 20 | from sdbus_async.networkmanager import NetworkManagerSettings 21 | from sdbus_async.networkmanager import NetworkConnectionSettings 22 | from sdbus_async.networkmanager.settings import ConnectionProfile 23 | from pprint import pprint 24 | from typing import Any, Dict 25 | 26 | 27 | async def update_connection_async(args: Dict[str, Any]) -> None: 28 | """Update the settings for [key][entry] of the 1st matching connection""" 29 | 30 | # Get the connection path of the connection(s) with the received id 31 | fn = NetworkManagerSettings().get_connections_by_id(args["connection_id"]) 32 | connection_paths = await fn 33 | if not connection_paths: 34 | print(f"No connection {id}, create with add-wifi-psk-connection-async") 35 | return 36 | 37 | # Get the profile settings of the first connection with given id 38 | connection_manager = NetworkConnectionSettings(connection_paths[0]) 39 | existing_connection_profile = await connection_manager.get_profile() 40 | settings = existing_connection_profile.to_settings_dict() 41 | 42 | # Update the given setting's property using the given value 43 | setting, property = args["connection_setting"] 44 | settings[setting][property] = args["value"] 45 | 46 | # Get a new ConnectionProfile with the change incorporated 47 | new_connection_profile = ConnectionProfile.from_settings_dict(settings) 48 | 49 | # Update the new ConnectionProfile in NetworkManager's configuration 50 | await connection_manager.update(new_connection_profile.to_dbus()) 51 | 52 | print(f'Updated {new_connection_profile.connection.uuid}.{setting}:') 53 | partial(pprint, sort_dicts=False)(settings) 54 | 55 | # Restore the previous connection profile: 56 | await connection_manager.update(existing_connection_profile.to_dbus()) 57 | 58 | 59 | if __name__ == "__main__": 60 | sdbus.set_default_bus(sdbus.sd_bus_open_system()) 61 | args = { 62 | # Set MyConnectionExample.ipv4.dns-search to "domain1.com,domain2.com": 63 | "connection_id": "MyConnectionExample", 64 | "connection_setting": ("ipv4", "dns-search"), 65 | "value": ["domain1.com", "domain2.com"], 66 | } 67 | asyncio.run(update_connection_async(args)) 68 | -------------------------------------------------------------------------------- /sdbus_async/networkmanager/settings/vpn.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: LGPL-2.1-or-later 2 | # This file was generated by tools/generate-settings-dataclasses-jinja.py, 3 | # if possible, please make changes by also updating the script. 4 | from __future__ import annotations 5 | from dataclasses import dataclass, field 6 | from typing import Dict, Optional 7 | from .base import NetworkManagerSettingsMixin 8 | 9 | 10 | @dataclass 11 | class VpnSettings(NetworkManagerSettingsMixin): 12 | """VPN Settings""" 13 | 14 | data: Optional[Dict[str, str]] = field( 15 | metadata={ 16 | 'dbus_name': 'data', 17 | 'dbus_type': 'a{ss}', 18 | }, 19 | default=None, 20 | ) 21 | """Dictionary of key/value pairs of VPN plugin specific data. Both keys 22 | and values must be strings.""" 23 | persistent: Optional[bool] = field( 24 | metadata={ 25 | 'dbus_name': 'persistent', 26 | 'dbus_type': 'b', 27 | }, 28 | default=None, 29 | ) 30 | """If the VPN service supports persistence, and this property is TRUE, the 31 | VPN will attempt to stay connected across link changes and outages, 32 | until explicitly disconnected.""" 33 | secrets: Optional[Dict[str, str]] = field( 34 | metadata={ 35 | 'dbus_name': 'secrets', 36 | 'dbus_type': 'a{ss}', 37 | }, 38 | default=None, 39 | ) 40 | """Dictionary of key/value pairs of VPN plugin specific secrets like 41 | passwords or private keys. Both keys and values must be strings.""" 42 | service_type: Optional[str] = field( 43 | metadata={ 44 | 'dbus_name': 'service-type', 45 | 'dbus_type': 's', 46 | }, 47 | default=None, 48 | ) 49 | """D-Bus service name of the VPN plugin that this setting uses to connect 50 | to its network. i.e. org.freedesktop.NetworkManager.vpnc for the 51 | vpnc plugin.""" 52 | timeout: Optional[int] = field( 53 | metadata={ 54 | 'dbus_name': 'timeout', 55 | 'dbus_type': 'u', 56 | }, 57 | default=None, 58 | ) 59 | """Timeout for the VPN service to establish the connection. Some services 60 | may take quite a long time to connect. Value of 0 means a default 61 | timeout, which is 60 seconds (unless overridden by vpn.timeout in 62 | configuration file). Values greater than zero mean timeout in 63 | seconds.""" 64 | user_name: Optional[str] = field( 65 | metadata={ 66 | 'dbus_name': 'user-name', 67 | 'dbus_type': 's', 68 | }, 69 | default=None, 70 | ) 71 | """If the VPN connection requires a user name for authentication, that name 72 | should be provided here. If the connection is available to more 73 | than one user, and the VPN requires each user to supply a different 74 | name, then leave this property empty. If this property is empty, 75 | NetworkManager will automatically supply the username of the user 76 | which requested the VPN connection.""" 77 | -------------------------------------------------------------------------------- /examples/2.0.0/block/device-state.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # SPDX-License-Identifier: LGPL-2.1-or-later 3 | # 4 | # Example to list the network devices including type, state, internet 5 | # connectivitycheck state and the identifier of the active connection. 6 | # 7 | # NetworkDeviceGeneric/org.freedesktop.NetworkManager.Device is described at 8 | # https://networkmanager.dev/docs/api/latest/ref-dbus-devices.html 9 | # 10 | # The output resembles the output of the NM CLI command "nmcli device": 11 | # 12 | # Interface Type State Internet Connection 13 | # lo Generic Unmanaged Unknown 14 | # wlp0s20f3 Wifi Activated Full Wolke7 [primary connection] 15 | # docker0 Bridge Activated None docker0 16 | # enx0c3796090408 Ethernet Activated Full enx0c3796090408 17 | # p2p-dev-wlp0s20f3 Wifi_P2P Disconnected None 18 | 19 | import argparse 20 | import sdbus 21 | from sdbus_block.networkmanager import ( 22 | NetworkManager, 23 | NetworkDeviceGeneric, 24 | DeviceState, 25 | DeviceType, 26 | DeviceCapabilities as Capabilities, 27 | ActiveConnection, 28 | ConnectivityState, 29 | ) 30 | from enum import Enum 31 | 32 | 33 | def title(enum: Enum) -> str: 34 | """Get the name of an enum: 1st character is uppercase, rest lowercase""" 35 | return enum.name.title() 36 | 37 | 38 | def list_active_hardware_networkdevice_states(only_hw: bool) -> None: 39 | """Print the list of activated network devices similar to nmcli device""" 40 | nm = NetworkManager() 41 | devices_paths = nm.get_devices() 42 | 43 | print("Interface Type State Internet Connection") 44 | for device_path in devices_paths: 45 | generic_dev = NetworkDeviceGeneric(device_path) 46 | 47 | # Demonstrates an enum to match devices using capabilities: 48 | if only_hw and generic_dev.capabilities & Capabilities.IS_SOFTWARE: 49 | continue 50 | 51 | # Create the strings for the columns using the names of the enums: 52 | dev = generic_dev.interface 53 | type = title(DeviceType(generic_dev.device_type)) 54 | state = title(DeviceState(generic_dev.state)) 55 | connectivity = title(ConnectivityState(generic_dev.ip4_connectivity)) 56 | 57 | if generic_dev.active_connection == "/": # No active connection 58 | id = "" 59 | else: 60 | # ActiveConnection() gets propertites from active connection path: 61 | active_connection = ActiveConnection(generic_dev.active_connection) 62 | id = active_connection.id 63 | if active_connection.default: 64 | id += " [primary connection]" 65 | 66 | print(f"{dev:<17} {type:<8} {state:<12} {connectivity:<8} {id:<14}") 67 | 68 | 69 | if __name__ == "__main__": 70 | p = argparse.ArgumentParser() 71 | p.add_argument("--hw", action="store_true", dest="only_hw", help="Only HW") 72 | args = p.parse_args() 73 | sdbus.set_default_bus(sdbus.sd_bus_open_system()) 74 | list_active_hardware_networkdevice_states(args.only_hw) 75 | -------------------------------------------------------------------------------- /examples/2.0.0/async/device-state-async.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # SPDX-License-Identifier: LGPL-2.1-or-later 3 | # 4 | # Example to list the network devices including type, state, internet 5 | # connectivitycheck state and the identifier of the active connection. 6 | # 7 | # NetworkDeviceGeneric/org.freedesktop.NetworkManager.Device is described at 8 | # https://networkmanager.dev/docs/api/latest/ref-dbus-devices.html 9 | # 10 | # The output resembles the output of the NM CLI command "nmcli device": 11 | # 12 | # Interface Type State Internet Connection 13 | # lo Generic Unmanaged Unknown 14 | # wlp0s20f3 Wifi Activated Full Wolke7 [primary connection] 15 | # docker0 Bridge Activated None docker0 16 | # enx0c3796090408 Ethernet Activated Full enx0c3796090408 17 | # p2p-dev-wlp0s20f3 Wifi_P2P Disconnected None 18 | 19 | import argparse 20 | import asyncio 21 | import sdbus 22 | from sdbus_async.networkmanager import ( 23 | NetworkManager, 24 | NetworkDeviceGeneric, 25 | DeviceState, 26 | DeviceType, 27 | DeviceCapabilities as Capabilities, 28 | ActiveConnection, 29 | ConnectivityState, 30 | ) 31 | from enum import Enum 32 | 33 | 34 | def title(enum: Enum) -> str: 35 | """Get the name of an enum: 1st character is uppercase, rest lowercase""" 36 | return enum.name.title() 37 | 38 | 39 | async def list_active_hardware_networkdevice_states(only_hw: bool) -> None: 40 | """Print the list of activated network devices similar to nmcli device""" 41 | nm = NetworkManager() 42 | devices_paths = await nm.get_devices() 43 | 44 | print("Interface Type State Internet Connection") 45 | for device_path in devices_paths: 46 | generic = NetworkDeviceGeneric(device_path) 47 | 48 | # Demonstrates an enum to match devices using capabilities: 49 | if only_hw and await generic.capabilities & Capabilities.IS_SOFTWARE: 50 | continue 51 | 52 | # Create the strings for the columns using the names of the enums: 53 | dev: str = await generic.interface 54 | dtype = title(DeviceType(await generic.device_type)) 55 | state = title(DeviceState(await generic.state)) 56 | connectivity = title(ConnectivityState(await generic.ip4_connectivity)) 57 | 58 | name: str = "" 59 | if await generic.active_connection != "/": # Connection is active 60 | # ActiveConnection() gets propertites from active connection path: 61 | active_conn = ActiveConnection(await generic.active_connection) 62 | name = await active_conn.id 63 | if await active_conn.default: 64 | name += " [primary connection]" 65 | 66 | print(f"{dev:<17} {dtype:<8} {state:<12} {connectivity:<8} {name:<14}") 67 | 68 | 69 | if __name__ == "__main__": 70 | p = argparse.ArgumentParser() 71 | p.add_argument("--hw", action="store_true", dest="only_hw", help="Only HW") 72 | args = p.parse_args() 73 | sdbus.set_default_bus(sdbus.sd_bus_open_system()) 74 | asyncio.run(list_active_hardware_networkdevice_states(args.only_hw)) 75 | -------------------------------------------------------------------------------- /examples/dev/block/device-state.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # SPDX-License-Identifier: LGPL-2.1-or-later 3 | # 4 | # Example to list the network devices including type, state, internet 5 | # connectivitycheck state and the identifier of the active connection. 6 | # 7 | # NetworkDeviceGeneric/org.freedesktop.NetworkManager.Device is described at 8 | # https://networkmanager.dev/docs/api/latest/ref-dbus-devices.html 9 | # 10 | # The output resembles the output of the NM CLI command "nmcli device": 11 | # 12 | # Interface Type State Internet Connection 13 | # lo Generic Unmanaged Unknown 14 | # wlp0s20f3 Wifi Activated Full Wolke7 [primary connection] 15 | # docker0 Bridge Activated None docker0 16 | # enx0c3796090408 Ethernet Activated Full enx0c3796090408 17 | # p2p-dev-wlp0s20f3 Wifi_P2P Disconnected None 18 | 19 | import argparse 20 | import sdbus 21 | from sdbus_block.networkmanager import ( 22 | NetworkManager, 23 | NetworkDeviceGeneric, 24 | DeviceState, 25 | DeviceType, 26 | DeviceCapabilitiesFlags, 27 | ActiveConnection, 28 | ConnectivityState, 29 | ) 30 | from enum import Enum 31 | 32 | 33 | def title(enum: Enum) -> str: 34 | """Get the name of an enum: 1st character is uppercase, rest lowercase""" 35 | return enum.name.title() 36 | 37 | 38 | def list_active_hardware_networkdevice_states(only_hw: bool) -> None: 39 | """Print the list of activated network devices similar to nmcli device""" 40 | nm = NetworkManager() 41 | devices_paths = nm.get_devices() 42 | 43 | print("Interface Type State Internet Connection") 44 | for device_path in devices_paths: 45 | generic_dev = NetworkDeviceGeneric(device_path) 46 | 47 | # Demonstrates an enum to match devices using capabilities: 48 | if only_hw and ( 49 | DeviceCapabilitiesFlags.IS_SOFTWARE 50 | in DeviceCapabilitiesFlags(generic_dev.capabilities)): 51 | continue 52 | 53 | # Create the strings for the columns using the names of the enums: 54 | dev = generic_dev.interface 55 | type = title(DeviceType(generic_dev.device_type)) 56 | state = title(DeviceState(generic_dev.state)) 57 | connectivity = title(ConnectivityState(generic_dev.ip4_connectivity)) 58 | 59 | if generic_dev.active_connection == "/": # No active connection 60 | id = "" 61 | else: 62 | # ActiveConnection() gets propertites from active connection path: 63 | active_connection = ActiveConnection(generic_dev.active_connection) 64 | id = active_connection.id 65 | if active_connection.default: 66 | id += " [primary connection]" 67 | 68 | print(f"{dev:<17} {type:<8} {state:<12} {connectivity:<8} {id:<14}") 69 | 70 | 71 | if __name__ == "__main__": 72 | p = argparse.ArgumentParser() 73 | p.add_argument("--hw", action="store_true", dest="only_hw", help="Only HW") 74 | args = p.parse_args() 75 | sdbus.set_default_bus(sdbus.sd_bus_open_system()) 76 | list_active_hardware_networkdevice_states(args.only_hw) 77 | -------------------------------------------------------------------------------- /tests/test_settings_profile.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: LGPL-2.1-or-later 2 | 3 | # Copyright (C) 2022 igo95862 4 | 5 | # This file is part of python-sdbus 6 | 7 | # This library is free software; you can redistribute it and/or 8 | # modify it under the terms of the GNU Lesser General Public 9 | # License as published by the Free Software Foundation; either 10 | # version 2.1 of the License, or (at your option) any later version. 11 | 12 | # This library is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | # Lesser General Public License for more details. 16 | 17 | # You should have received a copy of the GNU Lesser General Public 18 | # License along with this library; if not, write to the Free Software 19 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20 | from __future__ import annotations 21 | 22 | from unittest import TestCase 23 | from sdbus_async.networkmanager.settings import ConnectionProfile 24 | 25 | connection_dict = { 26 | 'connection': {'id': 'mlvd-wg', 27 | 'interface-name': 'mlvd-wg', 28 | 'timestamp': 150000, 29 | 'type': 'wireguard', 30 | 'uuid': 'uuid'}, 31 | 'ipv4': {'address-data': [{'address': '10.0.0.1', 'prefix': 32}], 32 | 'dns': [150000], 33 | 'dns-search': ['~'], 34 | 'method': 'manual'}, 35 | 'ipv6': {'addr-gen-mode': 1, 36 | 'address-data': [{'address': 'fc00:1', 37 | 'prefix': 128}], 38 | 'method': 'manual'}, 39 | 'wireguard': { 40 | 'peers': [ 41 | {'allowed-ips': ['::/0', '0.0.0.0/0'], 42 | 'endpoint': '1.1.1.1:51820', 43 | 'public-key': 'public_key'}]}} 44 | 45 | secret_dict = { 46 | 'connection': {}, 47 | 'ipv4': {}, 48 | 'ipv6': {}, 49 | 'proxy': {}, 50 | 'wireguard': { 51 | 'peers': [ 52 | {'public-key': 'public_key'} 53 | ], 54 | 'private-key': 'secret_key'}} 55 | 56 | 57 | class TestSettingsProfile(TestCase): 58 | def test_update(self) -> None: 59 | connection = ConnectionProfile.from_settings_dict(connection_dict) 60 | secrets = ConnectionProfile.from_settings_dict(secret_dict) 61 | 62 | connection.update(secrets) 63 | 64 | self.assertEqual(connection.wireguard.private_key, 'secret_key') 65 | 66 | def test_update_secrets(self) -> None: 67 | connection = ConnectionProfile.from_settings_dict(connection_dict) 68 | secrets = ConnectionProfile.from_settings_dict(secret_dict) 69 | 70 | connection_secret_update_generator = ( 71 | connection.update_secrets_generator() 72 | ) 73 | 74 | setting_name = next(connection_secret_update_generator) 75 | self.assertEqual(setting_name, 'wireguard') 76 | 77 | with self.assertRaises(StopIteration): 78 | connection_secret_update_generator.send(secrets) 79 | 80 | self.assertEqual(connection.wireguard.private_key, 'secret_key') 81 | -------------------------------------------------------------------------------- /examples/dev/async/device-state-async.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # SPDX-License-Identifier: LGPL-2.1-or-later 3 | # 4 | # Example to list the network devices including type, state, internet 5 | # connectivitycheck state and the identifier of the active connection. 6 | # 7 | # NetworkDeviceGeneric/org.freedesktop.NetworkManager.Device is described at 8 | # https://networkmanager.dev/docs/api/latest/ref-dbus-devices.html 9 | # 10 | # The output resembles the output of the NM CLI command "nmcli device": 11 | # 12 | # Interface Type State Internet Connection 13 | # lo Generic Unmanaged Unknown 14 | # wlp0s20f3 Wifi Activated Full Wolke7 [primary connection] 15 | # docker0 Bridge Activated None docker0 16 | # enx0c3796090408 Ethernet Activated Full enx0c3796090408 17 | # p2p-dev-wlp0s20f3 Wifi_P2P Disconnected None 18 | 19 | import argparse 20 | import asyncio 21 | import sdbus 22 | from sdbus_async.networkmanager import ( 23 | NetworkManager, 24 | NetworkDeviceGeneric, 25 | DeviceState, 26 | DeviceType, 27 | DeviceCapabilitiesFlags, 28 | ActiveConnection, 29 | ConnectivityState, 30 | ) 31 | from enum import Enum 32 | 33 | 34 | def title(enum: Enum) -> str: 35 | """Get the name of an enum: 1st character is uppercase, rest lowercase""" 36 | return enum.name.title() 37 | 38 | 39 | async def list_active_hardware_networkdevice_states(only_hw: bool) -> None: 40 | """Print the list of activated network devices similar to nmcli device""" 41 | nm = NetworkManager() 42 | devices_paths = await nm.get_devices() 43 | 44 | print("Interface Type State Internet Connection") 45 | for device_path in devices_paths: 46 | generic = NetworkDeviceGeneric(device_path) 47 | 48 | # Demonstrates an enum to match devices using capabilities: 49 | if only_hw and ( 50 | DeviceCapabilitiesFlags.IS_SOFTWARE 51 | in DeviceCapabilitiesFlags(await generic.capabilities)): 52 | continue 53 | 54 | # Create the strings for the columns using the names of the enums: 55 | dev: str = await generic.interface 56 | dtype = title(DeviceType(await generic.device_type)) 57 | state = title(DeviceState(await generic.state)) 58 | connectivity = title(ConnectivityState(await generic.ip4_connectivity)) 59 | 60 | name: str = "" 61 | if await generic.active_connection != "/": # Connection is active 62 | # ActiveConnection() gets propertites from active connection path: 63 | active_conn = ActiveConnection(await generic.active_connection) 64 | name = await active_conn.id 65 | if await active_conn.default: 66 | name += " [primary connection]" 67 | 68 | print(f"{dev:<17} {dtype:<8} {state:<12} {connectivity:<8} {name:<14}") 69 | 70 | 71 | if __name__ == "__main__": 72 | p = argparse.ArgumentParser() 73 | p.add_argument("--hw", action="store_true", dest="only_hw", help="Only HW") 74 | args = p.parse_args() 75 | sdbus.set_default_bus(sdbus.sd_bus_open_system()) 76 | asyncio.run(list_active_hardware_networkdevice_states(args.only_hw)) 77 | -------------------------------------------------------------------------------- /sdbus_async/networkmanager/settings/macsec.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: LGPL-2.1-or-later 2 | # This file was generated by tools/generate-settings-dataclasses-jinja.py, 3 | # if possible, please make changes by also updating the script. 4 | from __future__ import annotations 5 | from dataclasses import dataclass, field 6 | from typing import Optional 7 | from .base import NetworkManagerSettingsMixin 8 | 9 | 10 | @dataclass 11 | class MacsecSettings(NetworkManagerSettingsMixin): 12 | """MACSec Settings""" 13 | secret_fields_names = ['mka_cak'] 14 | secret_name = 'macsec' 15 | 16 | encrypt: Optional[bool] = field( 17 | metadata={ 18 | 'dbus_name': 'encrypt', 19 | 'dbus_type': 'b', 20 | }, 21 | default=None, 22 | ) 23 | """Whether the transmitted traffic must be encrypted.""" 24 | mka_cak: Optional[str] = field( 25 | metadata={ 26 | 'dbus_name': 'mka-cak', 27 | 'dbus_type': 's', 28 | }, 29 | default=None, 30 | ) 31 | """The pre-shared CAK (Connectivity Association Key) for MACsec Key 32 | Agreement.""" 33 | mka_cak_flags: Optional[int] = field( 34 | metadata={ 35 | 'dbus_name': 'mka-cak-flags', 36 | 'dbus_type': 'u', 37 | }, 38 | default=None, 39 | ) 40 | """Flags indicating how to handle the "mka-cak" property.""" 41 | mka_ckn: Optional[str] = field( 42 | metadata={ 43 | 'dbus_name': 'mka-ckn', 44 | 'dbus_type': 's', 45 | }, 46 | default=None, 47 | ) 48 | """The pre-shared CKN (Connectivity-association Key Name) for MACsec Key 49 | Agreement.""" 50 | mode: Optional[int] = field( 51 | metadata={ 52 | 'dbus_name': 'mode', 53 | 'dbus_type': 'i', 54 | }, 55 | default=None, 56 | ) 57 | """Specifies how the CAK (Connectivity Association Key) for MKA (MACsec Key 58 | Agreement) is obtained.""" 59 | parent: Optional[str] = field( 60 | metadata={ 61 | 'dbus_name': 'parent', 62 | 'dbus_type': 's', 63 | }, 64 | default=None, 65 | ) 66 | """If given, specifies the parent interface name or parent connection UUID 67 | from which this MACSEC interface should be created. If this 68 | property is not specified, the connection must contain an 69 | "802-3-ethernet" setting with a "mac-address" property.""" 70 | port: Optional[int] = field( 71 | metadata={ 72 | 'dbus_name': 'port', 73 | 'dbus_type': 'i', 74 | }, 75 | default=None, 76 | ) 77 | """The port component of the SCI (Secure Channel Identifier), between 1 and 78 | 65534.""" 79 | send_sci: Optional[bool] = field( 80 | metadata={ 81 | 'dbus_name': 'send-sci', 82 | 'dbus_type': 'b', 83 | }, 84 | default=None, 85 | ) 86 | """Specifies whether the SCI (Secure Channel Identifier) is included in 87 | every packet.""" 88 | validation: Optional[int] = field( 89 | metadata={ 90 | 'dbus_name': 'validation', 91 | 'dbus_type': 'i', 92 | }, 93 | default=None, 94 | ) 95 | """Specifies the validation mode for incoming frames.""" 96 | -------------------------------------------------------------------------------- /sdbus_async/networkmanager/settings/team_port.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: LGPL-2.1-or-later 2 | # This file was generated by tools/generate-settings-dataclasses-jinja.py, 3 | # if possible, please make changes by also updating the script. 4 | from __future__ import annotations 5 | from dataclasses import dataclass, field 6 | from typing import Any, List, Optional, Tuple 7 | from .base import NetworkManagerSettingsMixin 8 | from .datatypes import LinkWatchers 9 | 10 | 11 | @dataclass 12 | class TeamPortSettings(NetworkManagerSettingsMixin): 13 | """Team Port Settings""" 14 | 15 | config: Optional[str] = field( 16 | metadata={ 17 | 'dbus_name': 'config', 18 | 'dbus_type': 's', 19 | }, 20 | default=None, 21 | ) 22 | """The JSON configuration for the team port. The property should contain 23 | raw JSON configuration data suitable for teamd, because the value is 24 | passed directly to teamd. If not specified, the default 25 | configuration is used. See man teamd.conf for the format details.""" 26 | lacp_key: Optional[int] = field( 27 | metadata={ 28 | 'dbus_name': 'lacp-key', 29 | 'dbus_type': 'i', 30 | }, 31 | default=None, 32 | ) 33 | """Corresponds to the teamd ports.PORTIFNAME.lacp_key.""" 34 | lacp_prio: Optional[int] = field( 35 | metadata={ 36 | 'dbus_name': 'lacp-prio', 37 | 'dbus_type': 'i', 38 | }, 39 | default=None, 40 | ) 41 | """Corresponds to the teamd ports.PORTIFNAME.lacp_prio.""" 42 | link_watchers: Optional[List[LinkWatchers]] = field( 43 | metadata={ 44 | 'dbus_name': 'link-watchers', 45 | 'dbus_type': 'aa{sv}', 46 | 'dbus_inner_class': LinkWatchers, 47 | }, 48 | default=None, 49 | ) 50 | """Link watchers configuration for the connection: each link watcher is 51 | defined by a dictionary, whose keys depend upon the selected link 52 | watcher. Available link watchers are 'ethtool', 'nsna_ping' and 53 | 'arp_ping' and it is specified in the dictionary with the key 54 | 'name'. Available keys are: ethtool: 'delay-up', 'delay-down', 55 | 'init-wait'; nsna_ping: 'init-wait', 'interval', 'missed-max', 56 | 'target-host'; arp_ping: all the ones in nsna_ping and 'source- 57 | host', 'validate-active', 'validate-inactive', 'send-always'. See 58 | teamd.conf man for more details.""" 59 | prio: Optional[int] = field( 60 | metadata={ 61 | 'dbus_name': 'prio', 62 | 'dbus_type': 'i', 63 | }, 64 | default=None, 65 | ) 66 | """Corresponds to the teamd ports.PORTIFNAME.prio.""" 67 | queue_id: Optional[int] = field( 68 | metadata={ 69 | 'dbus_name': 'queue-id', 70 | 'dbus_type': 'i', 71 | }, 72 | default=None, 73 | ) 74 | """Corresponds to the teamd ports.PORTIFNAME.queue_id. When set to -1 means 75 | the parameter is skipped from the json config.""" 76 | sticky: Optional[bool] = field( 77 | metadata={ 78 | 'dbus_name': 'sticky', 79 | 'dbus_type': 'b', 80 | }, 81 | default=None, 82 | ) 83 | """Corresponds to the teamd ports.PORTIFNAME.sticky.""" 84 | -------------------------------------------------------------------------------- /sdbus_async/networkmanager/settings/hostname.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: LGPL-2.1-or-later 2 | # This file was generated by tools/generate-settings-dataclasses-jinja.py, 3 | # if possible, please make changes by also updating the script. 4 | from __future__ import annotations 5 | from dataclasses import dataclass, field 6 | from typing import Optional 7 | from .base import NetworkManagerSettingsMixin 8 | 9 | 10 | @dataclass 11 | class HostnameSettings(NetworkManagerSettingsMixin): 12 | """Hostname settings""" 13 | 14 | from_dhcp: Optional[int] = field( 15 | metadata={ 16 | 'dbus_name': 'from-dhcp', 17 | 'dbus_type': 'i', 18 | }, 19 | default=None, 20 | ) 21 | """Whether the system hostname can be determined from DHCP on this 22 | connection. 23 | 24 | When set to NM_TERNARY_DEFAULT (-1), the value from global 25 | configuration is used. If the property doesn't have a value in the 26 | global configuration, NetworkManager assumes the value to be 27 | NM_TERNARY_TRUE (1).""" 28 | from_dns_lookup: Optional[int] = field( 29 | metadata={ 30 | 'dbus_name': 'from-dns-lookup', 31 | 'dbus_type': 'i', 32 | }, 33 | default=None, 34 | ) 35 | """Whether the system hostname can be determined from reverse DNS lookup of 36 | addresses on this device. 37 | 38 | When set to NM_TERNARY_DEFAULT (-1), the value from global 39 | configuration is used. If the property doesn't have a value in the 40 | global configuration, NetworkManager assumes the value to be 41 | NM_TERNARY_TRUE (1).""" 42 | only_from_default: Optional[int] = field( 43 | metadata={ 44 | 'dbus_name': 'only-from-default', 45 | 'dbus_type': 'i', 46 | }, 47 | default=None, 48 | ) 49 | """If set to NM_TERNARY_TRUE (1), NetworkManager attempts to get the 50 | hostname via DHCPv4/DHCPv6 or reverse DNS lookup on this device only 51 | when the device has the default route for the given address family 52 | (IPv4/IPv6). 53 | 54 | If set to NM_TERNARY_FALSE (0), the hostname can be set from this 55 | device even if it doesn't have the default route. 56 | 57 | When set to NM_TERNARY_DEFAULT (-1), the value from global 58 | configuration is used. If the property doesn't have a value in the 59 | global configuration, NetworkManager assumes the value to be 60 | NM_TERNARY_FALSE (0).""" 61 | priority: Optional[int] = field( 62 | metadata={ 63 | 'dbus_name': 'priority', 64 | 'dbus_type': 'i', 65 | }, 66 | default=None, 67 | ) 68 | """The relative priority of this connection to determine the system 69 | hostname. A lower numerical value is better (higher priority). A 70 | connection with higher priority is considered before connections 71 | with lower priority. 72 | 73 | If the value is zero, it can be overridden by a global value from 74 | NetworkManager configuration. If the property doesn't have a value 75 | in the global configuration, the value is assumed to be 100. 76 | 77 | Negative values have the special effect of excluding other 78 | connections with a greater numerical priority value; so in presence 79 | of at least one negative priority, only connections with the lowest 80 | priority value will be used to determine the hostname.""" 81 | -------------------------------------------------------------------------------- /sdbus_async/networkmanager/settings/vlan.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: LGPL-2.1-or-later 2 | # This file was generated by tools/generate-settings-dataclasses-jinja.py, 3 | # if possible, please make changes by also updating the script. 4 | from __future__ import annotations 5 | from dataclasses import dataclass, field 6 | from typing import List, Optional 7 | from .base import NetworkManagerSettingsMixin 8 | 9 | 10 | @dataclass 11 | class VlanSettings(NetworkManagerSettingsMixin): 12 | """VLAN Settings""" 13 | 14 | egress_priority_map: Optional[List[str]] = field( 15 | metadata={ 16 | 'dbus_name': 'egress-priority-map', 17 | 'dbus_type': 'as', 18 | }, 19 | default=None, 20 | ) 21 | """For outgoing packets, a list of mappings from Linux SKB priorities to 22 | 802.1p priorities. The mapping is given in the format "from:to" 23 | where both "from" and "to" are unsigned integers, ie "7:3".""" 24 | flags: Optional[int] = field( 25 | metadata={ 26 | 'dbus_name': 'flags', 27 | 'dbus_type': 'u', 28 | }, 29 | default=None, 30 | ) 31 | """One or more flags which control the behavior and features of the VLAN 32 | interface. Flags include NM_VLAN_FLAG_REORDER_HEADERS (0x1) 33 | (reordering of output packet headers), NM_VLAN_FLAG_GVRP (0x2) (use 34 | of the GVRP protocol), and NM_VLAN_FLAG_LOOSE_BINDING (0x4) (loose 35 | binding of the interface to its master device's operating state). 36 | NM_VLAN_FLAG_MVRP (0x8) (use of the MVRP protocol). 37 | 38 | The default value of this property is NM_VLAN_FLAG_REORDER_HEADERS, 39 | but it used to be 0. To preserve backward compatibility, the 40 | default-value in the D-Bus API continues to be 0 and a missing 41 | property on D-Bus is still considered as 0.""" 42 | vlan_id: Optional[int] = field( 43 | metadata={ 44 | 'dbus_name': 'id', 45 | 'dbus_type': 'u', 46 | }, 47 | default=None, 48 | ) 49 | """The VLAN identifier that the interface created by this connection should 50 | be assigned. The valid range is from 0 to 4094, without the reserved 51 | id 4095.""" 52 | ingress_priority_map: Optional[List[str]] = field( 53 | metadata={ 54 | 'dbus_name': 'ingress-priority-map', 55 | 'dbus_type': 'as', 56 | }, 57 | default=None, 58 | ) 59 | """For incoming packets, a list of mappings from 802.1p priorities to Linux 60 | SKB priorities. The mapping is given in the format "from:to" where 61 | both "from" and "to" are unsigned integers, ie "7:3".""" 62 | interface_name: Optional[str] = field( 63 | metadata={ 64 | 'dbus_name': 'interface-name', 65 | 'dbus_type': 's', 66 | }, 67 | default=None, 68 | ) 69 | """Deprecated in favor of connection.interface-name, but can be used for 70 | backward-compatibility with older daemons, to set the vlan's 71 | interface name.""" 72 | parent: Optional[str] = field( 73 | metadata={ 74 | 'dbus_name': 'parent', 75 | 'dbus_type': 's', 76 | }, 77 | default=None, 78 | ) 79 | """If given, specifies the parent interface name or parent connection UUID 80 | from which this VLAN interface should be created. If this property 81 | is not specified, the connection must contain an "802-3-ethernet" 82 | setting with a "mac-address" property.""" 83 | -------------------------------------------------------------------------------- /tests/settings/test_from_dict_async.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # SPDX-License-Identifier: LGPL-2.1-or-later 3 | import asyncio 4 | import contextlib 5 | import sdbus 6 | import pytest 7 | from sdbus_async.networkmanager import ( 8 | ConnectionProfile, 9 | NetworkConnectionSettings, 10 | NetworkManagerSettings as SettingsManager, 11 | NmSettingsInvalidConnectionError, 12 | ) 13 | 14 | # All test coroutines will be treated as marked. 15 | 16 | 17 | def test_wifi_wpa_psk_simple_from_dict() -> ConnectionProfile: 18 | """Parse connection and ipv4 settings from dbus using ConnectionProfile""" 19 | profile = ConnectionProfile.from_settings_dict( 20 | { 21 | "connection": { 22 | "id": "WirelessWpaPskConnection", 23 | "type": "802-11-wireless", 24 | "uuid": "16ea7af1-0e35-4036-831e-ced975f48510", 25 | "autoconnect": False, 26 | }, 27 | "ipv4": {"method": "auto"}, 28 | "ipv6": {"method": "disabled"}, 29 | "802-11-wireless": { 30 | "security": "802-11-wireless-security", 31 | "ssid": b"CafeSSID", 32 | }, 33 | "802-11-wireless-security": {"key-mgmt": "wpa-psk"}, 34 | } 35 | ) 36 | assert profile.connection.connection_id == "WirelessWpaPskConnection" 37 | assert profile.connection.uuid == "16ea7af1-0e35-4036-831e-ced975f48510" 38 | assert profile.connection.connection_type == "802-11-wireless" 39 | assert profile.connection.autoconnect is False 40 | assert profile.ipv4 41 | assert profile.ipv4.method == "auto" 42 | assert profile.ipv4.address_data is None 43 | assert profile.ipv6 44 | assert profile.ipv6.method == "disabled" 45 | return profile 46 | 47 | 48 | async def delete_connection_by_uuid(nmset: SettingsManager, uuid: str) -> None: 49 | dpath = await nmset.get_connection_by_uuid(uuid) 50 | connection_settings = NetworkConnectionSettings(dpath) 51 | await connection_settings.delete() 52 | 53 | 54 | # @pytest_asyncio.fixture 55 | @pytest.mark.asyncio 56 | async def test_add_wifi_wpa_psk_simple_from_dict() -> None: 57 | """Test adding a wireless WPA PSK connection profile(unsaved) from dict""" 58 | profile = test_wifi_wpa_psk_simple_from_dict() 59 | 60 | # If we add many connections passing the same id, things get messy. Check: 61 | sdbus.set_default_bus(sdbus.sd_bus_open_system()) 62 | settings = SettingsManager() 63 | assert profile.connection.uuid 64 | with contextlib.suppress(NmSettingsInvalidConnectionError): 65 | await settings.get_connection_by_uuid(profile.connection.uuid) 66 | print(f"Deleting existing connection with {profile.connection.uuid}") 67 | await delete_connection_by_uuid(settings, profile.connection.uuid) 68 | await settings.add_connection_unsaved(profile.to_dbus()) 69 | await delete_connection_by_uuid(settings, profile.connection.uuid) 70 | 71 | 72 | if __name__ == "__main__": 73 | """The tests can be run by pytest (and from IDEs by running this module)""" 74 | test_wifi_wpa_psk_simple_from_dict() 75 | 76 | # Test using ConnectionProfile.from_dict() to create a ConnectionProfile 77 | # which can be used to add Wireless WPA PSK connection profile from dict 78 | # to a running NetworkManager. Requires access and permissions to access 79 | # a running NetworkManager. The added connection is not saved and deleted 80 | # immediately (and does not have autoconnect enabled): 81 | asyncio.run(test_add_wifi_wpa_psk_simple_from_dict()) 82 | -------------------------------------------------------------------------------- /docs/objects.rst: -------------------------------------------------------------------------------- 1 | Network Manager objects 2 | ======================= 3 | 4 | All objects avaiable in NetworkManager. 5 | 6 | Only the implemented interfaces for each object 7 | are documented. Click on interface link to see 8 | which properties and methods does the interface implements. 9 | 10 | Network Manager main object 11 | --------------------------- 12 | 13 | .. autoclass:: sdbus_async.networkmanager.NetworkManager 14 | :members: 15 | 16 | Network Manager settings 17 | ------------------------ 18 | 19 | .. autoclass:: sdbus_async.networkmanager.NetworkManagerSettings 20 | :members: 21 | 22 | .. autoclass:: sdbus_async.networkmanager.NetworkManagerDnsManager 23 | :members: 24 | 25 | .. autoclass:: sdbus_async.networkmanager.NetworkManagerAgentManager 26 | :members: 27 | 28 | .. autoclass:: sdbus_async.networkmanager.NetworkConnectionSettings 29 | :members: 30 | 31 | Device objects 32 | -------------- 33 | 34 | .. autoclass:: sdbus_async.networkmanager.NetworkDeviceGeneric 35 | :members: 36 | 37 | .. autoclass:: sdbus_async.networkmanager.NetworkDeviceWired 38 | :members: 39 | 40 | .. autoclass:: sdbus_async.networkmanager.NetworkDeviceWireless 41 | :members: 42 | 43 | .. autoclass:: sdbus_async.networkmanager.NetworkDeviceBluetooth 44 | :members: 45 | 46 | .. autoclass:: sdbus_async.networkmanager.NetworkDeviceBond 47 | :members: 48 | 49 | .. autoclass:: sdbus_async.networkmanager.NetworkDeviceBridge 50 | :members: 51 | 52 | .. autoclass:: sdbus_async.networkmanager.NetworkDeviceIpTunnel 53 | :members: 54 | 55 | .. autoclass:: sdbus_async.networkmanager.NetworkDeviceMacsec 56 | :members: 57 | 58 | .. autoclass:: sdbus_async.networkmanager.NetworkDeviceMacvlan 59 | :members: 60 | 61 | .. autoclass:: sdbus_async.networkmanager.NetworkDeviceModem 62 | :members: 63 | 64 | .. autoclass:: sdbus_async.networkmanager.NetworkDeviceOlpcMesh 65 | :members: 66 | 67 | .. autoclass:: sdbus_async.networkmanager.NetworkDeviceOpenVSwitchBridge 68 | :members: 69 | 70 | .. autoclass:: sdbus_async.networkmanager.NetworkDeviceOpenVSwitchPort 71 | :members: 72 | 73 | .. autoclass:: sdbus_async.networkmanager.NetworkDeviceTeam 74 | :members: 75 | 76 | .. autoclass:: sdbus_async.networkmanager.NetworkDeviceTun 77 | :members: 78 | 79 | .. autoclass:: sdbus_async.networkmanager.NetworkDeviceVeth 80 | :members: 81 | 82 | .. autoclass:: sdbus_async.networkmanager.NetworkDeviceVlan 83 | :members: 84 | 85 | .. autoclass:: sdbus_async.networkmanager.NetworkDeviceVrf 86 | :members: 87 | 88 | .. autoclass:: sdbus_async.networkmanager.NetworkDeviceVxlan 89 | :members: 90 | 91 | .. autoclass:: sdbus_async.networkmanager.NetworkDeviceWifiP2P 92 | :members: 93 | 94 | .. autoclass:: sdbus_async.networkmanager.NetworkDeviceWireGuard 95 | :members: 96 | 97 | .. autoclass:: sdbus_async.networkmanager.NetworkDevicePPP 98 | :members: 99 | 100 | .. autoclass:: sdbus_async.networkmanager.NetworkDeviceLoopback 101 | :members: 102 | 103 | Connection configuration objects 104 | -------------------------------- 105 | 106 | .. autoclass:: sdbus_async.networkmanager.ActiveConnection 107 | :members: 108 | 109 | .. autoclass:: sdbus_async.networkmanager.ActiveVPNConnection 110 | :members: 111 | 112 | .. autoclass:: sdbus_async.networkmanager.IPv4Config 113 | :members: 114 | 115 | .. autoclass:: sdbus_async.networkmanager.IPv6Config 116 | :members: 117 | 118 | .. autoclass:: sdbus_async.networkmanager.DHCPv4Config 119 | :members: 120 | 121 | .. autoclass:: sdbus_async.networkmanager.DHCPv6Config 122 | :members: 123 | 124 | Other objects 125 | ------------- 126 | 127 | .. autoclass:: sdbus_async.networkmanager.AccessPoint 128 | :members: 129 | 130 | .. autoclass:: sdbus_async.networkmanager.WiFiP2PPeer 131 | :members: 132 | 133 | .. autoclass:: sdbus_async.networkmanager.ConfigCheckpoint 134 | :members: 135 | -------------------------------------------------------------------------------- /sdbus_async/networkmanager/settings/__init__.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: LGPL-2.1-or-later 2 | # This file was generated by tools/generate-settings-dataclasses-jinja.py, 3 | # if possible, please make changes by also updating the script. 4 | from __future__ import annotations 5 | 6 | from .profile import ConnectionProfile 7 | from .adsl import AdslSettings 8 | from .bluetooth import BluetoothSettings 9 | from .bond import BondSettings 10 | from .bond_port import BondPortSettings 11 | from .bridge import BridgeSettings 12 | from .bridge_port import BridgePortSettings 13 | from .cdma import CdmaSettings 14 | from .connection import ConnectionSettings 15 | from .dcb import DcbSettings 16 | from .dummy import DummySettings 17 | from .eapol import EapolSettings 18 | from .ethernet import EthernetSettings 19 | from .ethtool import EthtoolSettings 20 | from .generic import GenericSettings 21 | from .gsm import GsmSettings 22 | from .hostname import HostnameSettings 23 | from .infiniband import InfinibandSettings 24 | from .ip_tunnel import IpTunnelSettings 25 | from .ipv4 import Ipv4Settings 26 | from .ipv6 import Ipv6Settings 27 | from .lowpan import LowpanSettings 28 | from .macsec import MacsecSettings 29 | from .macvlan import MacvlanSettings 30 | from .match import MatchSettings 31 | from .olpc_mesh import OlpcMeshSettings 32 | from .ovs_bridge import OvsBridgeSettings 33 | from .ovs_dpdk import OvsDpdkSettings 34 | from .ovs_external_ids import OvsExternalIdsSettings 35 | from .ovs_interface import OvsInterfaceSettings 36 | from .ovs_patch import OvsPatchSettings 37 | from .ovs_port import OvsPortSettings 38 | from .ppp import PppSettings 39 | from .pppoe import PppoeSettings 40 | from .proxy import ProxySettings 41 | from .serial import SerialSettings 42 | from .sriov import SriovSettings 43 | from .tc import TcSettings 44 | from .team import TeamSettings 45 | from .team_port import TeamPortSettings 46 | from .tun import TunSettings 47 | from .user import UserSettings 48 | from .veth import VethSettings 49 | from .vlan import VlanSettings 50 | from .vpn import VpnSettings 51 | from .vrf import VrfSettings 52 | from .vxlan import VxlanSettings 53 | from .wifi_p2p import WifiP2PSettings 54 | from .wimax import WimaxSettings 55 | from .wireguard import WireguardSettings 56 | from .wireless import WirelessSettings 57 | from .wireless_security import WirelessSecuritySettings 58 | from .wpan import WpanSettings 59 | 60 | from .datatypes import ( 61 | AddressData, 62 | RouteData, 63 | LinkWatchers, 64 | Vlans, 65 | WireguardPeers, 66 | RoutingRules, 67 | Vfs, 68 | ) 69 | 70 | __all__ = ( 71 | 'ConnectionProfile', 72 | 'AdslSettings', 73 | 'BluetoothSettings', 74 | 'BondSettings', 75 | 'BondPortSettings', 76 | 'BridgeSettings', 77 | 'BridgePortSettings', 78 | 'CdmaSettings', 79 | 'ConnectionSettings', 80 | 'DcbSettings', 81 | 'DummySettings', 82 | 'EapolSettings', 83 | 'EthernetSettings', 84 | 'EthtoolSettings', 85 | 'GenericSettings', 86 | 'GsmSettings', 87 | 'HostnameSettings', 88 | 'InfinibandSettings', 89 | 'IpTunnelSettings', 90 | 'Ipv4Settings', 91 | 'Ipv6Settings', 92 | 'LowpanSettings', 93 | 'MacsecSettings', 94 | 'MacvlanSettings', 95 | 'MatchSettings', 96 | 'OlpcMeshSettings', 97 | 'OvsBridgeSettings', 98 | 'OvsDpdkSettings', 99 | 'OvsExternalIdsSettings', 100 | 'OvsInterfaceSettings', 101 | 'OvsPatchSettings', 102 | 'OvsPortSettings', 103 | 'PppSettings', 104 | 'PppoeSettings', 105 | 'ProxySettings', 106 | 'SerialSettings', 107 | 'SriovSettings', 108 | 'TcSettings', 109 | 'TeamSettings', 110 | 'TeamPortSettings', 111 | 'TunSettings', 112 | 'UserSettings', 113 | 'VethSettings', 114 | 'VlanSettings', 115 | 'VpnSettings', 116 | 'VrfSettings', 117 | 'VxlanSettings', 118 | 'WifiP2PSettings', 119 | 'WimaxSettings', 120 | 'WireguardSettings', 121 | 'WirelessSettings', 122 | 'WirelessSecuritySettings', 123 | 'WpanSettings', 124 | 125 | 'AddressData', 126 | 'RouteData', 127 | 'LinkWatchers', 128 | 'Vlans', 129 | 'WireguardPeers', 130 | 'RoutingRules', 131 | 'Vfs', 132 | ) 133 | -------------------------------------------------------------------------------- /sdbus_async/networkmanager/settings/match.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: LGPL-2.1-or-later 2 | # This file was generated by tools/generate-settings-dataclasses-jinja.py, 3 | # if possible, please make changes by also updating the script. 4 | from __future__ import annotations 5 | from dataclasses import dataclass, field 6 | from typing import List, Optional 7 | from .base import NetworkManagerSettingsMixin 8 | 9 | 10 | @dataclass 11 | class MatchSettings(NetworkManagerSettingsMixin): 12 | """Match settings""" 13 | 14 | driver: Optional[List[str]] = field( 15 | metadata={ 16 | 'dbus_name': 'driver', 17 | 'dbus_type': 'as', 18 | }, 19 | default=None, 20 | ) 21 | """A list of driver names to match. Each element is a shell wildcard 22 | pattern. 23 | 24 | See NMSettingMatch:interface-name for how special characters '|', 25 | '&', '!' and '\\' are used for optional and mandatory matches and 26 | inverting the pattern.""" 27 | interface_name: Optional[List[str]] = field( 28 | metadata={ 29 | 'dbus_name': 'interface-name', 30 | 'dbus_type': 'as', 31 | }, 32 | default=None, 33 | ) 34 | """A list of interface names to match. Each element is a shell wildcard 35 | pattern. 36 | 37 | An element can be prefixed with a pipe symbol (|) or an ampersand 38 | (&). The former means that the element is optional and the latter 39 | means that it is mandatory. If there are any optional elements, than 40 | the match evaluates to true if at least one of the optional element 41 | matches (logical OR). If there are any mandatory elements, then they 42 | all must match (logical AND). By default, an element is optional. 43 | This means that an element "foo" behaves the same as "|foo". An 44 | element can also be inverted with exclamation mark (!) between the 45 | pipe symbol (or the ampersand) and before the pattern. Note that 46 | "!foo" is a shortcut for the mandatory match "&!foo". Finally, a 47 | backslash can be used at the beginning of the element (after the 48 | optional special characters) to escape the start of the pattern. For 49 | example, "&\\!a" is an mandatory match for literally "!a".""" 50 | kernel_command_line: Optional[List[str]] = field( 51 | metadata={ 52 | 'dbus_name': 'kernel-command-line', 53 | 'dbus_type': 'as', 54 | }, 55 | default=None, 56 | ) 57 | """A list of kernel command line arguments to match. This may be used to 58 | check whether a specific kernel command line option is set (or 59 | unset, if prefixed with the exclamation mark). The argument must 60 | either be a single word, or an assignment (i.e. two words, joined by 61 | "="). In the former case the kernel command line is searched for the 62 | word appearing as is, or as left hand side of an assignment. In the 63 | latter case, the exact assignment is looked for with right and left 64 | hand side matching. Wildcard patterns are not supported. 65 | 66 | See NMSettingMatch:interface-name for how special characters '|', 67 | '&', '!' and '\\' are used for optional and mandatory matches and 68 | inverting the match.""" 69 | path: Optional[List[str]] = field( 70 | metadata={ 71 | 'dbus_name': 'path', 72 | 'dbus_type': 'as', 73 | }, 74 | default=None, 75 | ) 76 | """A list of paths to match against the ID_PATH udev property of devices. 77 | ID_PATH represents the topological persistent path of a device. It 78 | typically contains a subsystem string (pci, usb, platform, etc.) and 79 | a subsystem-specific identifier. 80 | 81 | For PCI devices the path has the form 82 | "pci-$domain:$bus:$device.$function", where each variable is an 83 | hexadecimal value; for example "pci-0000:0a:00.0". 84 | 85 | The path of a device can be obtained with "udevadm info 86 | /sys/class/net/$dev | grep ID_PATH=" or by looking at the "path" 87 | property exported by NetworkManager ("nmcli -f general.path device 88 | show $dev"). 89 | 90 | Each element of the list is a shell wildcard pattern. 91 | 92 | See NMSettingMatch:interface-name for how special characters '|', 93 | '&', '!' and '\\' are used for optional and mandatory matches and 94 | inverting the pattern.""" 95 | -------------------------------------------------------------------------------- /examples/2.0.0/block/add-eth-connection.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # SPDX-License-Identifier: LGPL-2.1-or-later 3 | # 4 | # Example to create a new Ethernet network connection profile: 5 | # 6 | # examples/block/add-eth-connection.py --help 7 | # usage: add-eth-connection.py [-h] [-c CONN_ID] [-u UUID] [-i INTERFACE_NAME] 8 | # [-4 IP4] [-g GW] [-a] [--save] 9 | # 10 | # Optional arguments have example values: 11 | # 12 | # optional arguments: 13 | # -h, --help show this help message and exit 14 | # -c CONN_ID Connection Id 15 | # -u UUID Connection UUID 16 | # -i INTERFACE_NAME ethX device 17 | # -4 IP4 IP4/prefix 18 | # -g GW gw/metric 19 | # -a autoconnect 20 | # --save Save 21 | # 22 | # Connection Profile settings are described at: 23 | # https://networkmanager.dev/docs/api/latest/ref-settings.html 24 | 25 | import sdbus 26 | import functools 27 | import logging 28 | import pprint 29 | import sys 30 | from uuid import uuid4 31 | from argparse import ArgumentParser, Namespace 32 | from sdbus_block.networkmanager import NetworkManagerSettings 33 | from sdbus_block.networkmanager import NetworkManagerConnectionProperties 34 | 35 | 36 | def add_ethernet_connection(args: Namespace) -> str: 37 | """Add a (by default) temporary (not yet saved) network connection profile 38 | :param Namespace args: autoconnect, conn_id, psk, save, ssid, uuid 39 | :return: dbus connection path of the created connection profile 40 | """ 41 | info = logging.getLogger().info 42 | 43 | # If we add many connections using the same id, things get messy. Check: 44 | if NetworkManagerSettings().get_connections_by_id(args.conn_id): 45 | info(f'Connections using ID "{args.conn_id}" exist, remove them:') 46 | info(f'Run: nmcli connection delete "{args.conn_id}"') 47 | return "" 48 | 49 | ipaddr, prefix = args.ip4.split("/") 50 | properties: NetworkManagerConnectionProperties = { 51 | "connection": { 52 | "id": ("s", args.conn_id), 53 | "uuid": ("s", str(args.uuid)), 54 | "type": ("s", "802-3-ethernet"), 55 | "autoconnect": ("b", args.auto), 56 | }, 57 | "ipv4": { 58 | "method": ("s", "manual"), 59 | "address-data": ( 60 | "aa{sv}", 61 | [ 62 | { 63 | "address": ("s", ipaddr), 64 | "prefix": ("u", int(prefix)), 65 | }, 66 | ], 67 | ), 68 | }, 69 | "ipv6": {"method": ("s", "disabled")}, 70 | } 71 | if args.interface_name: 72 | properties["connection"]["interface-name"] = ("s", args.interface_name) 73 | if len(sys.argv) == 1 or args.gw != "192.0.2.1/4000": 74 | default_gateway, route_metric = args.gw.split("/") 75 | properties["ipv4"]["gateway"] = ("s", default_gateway) 76 | properties["ipv4"]["route-metric"] = ("u", int(route_metric)) 77 | 78 | s = NetworkManagerSettings() 79 | addconnection = s.add_connection if args.save else s.add_connection_unsaved 80 | connection_settings_dbus_path = addconnection(properties) 81 | created = "created and saved" if args.save else "created" 82 | 83 | info(f"New unsaved connection profile {created}, show it with:") 84 | info(f'nmcli connection show "{args.conn_id}"|grep -v -e -- -e default') 85 | info("Settings used:") 86 | info(functools.partial(pprint.pformat, sort_dicts=False)(properties)) 87 | return connection_settings_dbus_path 88 | 89 | 90 | if __name__ == "__main__": 91 | logging.basicConfig(format="%(message)s", level=logging.INFO) 92 | p = ArgumentParser(description="Optional arguments have example values:") 93 | conn_id = "MyConnectionExample" 94 | p.add_argument("-c", dest="conn_id", default=conn_id, help="Connection Id") 95 | p.add_argument("-u", dest="uuid", default=uuid4(), help="Connection UUID") 96 | p.add_argument("-i", dest="interface_name", default="", help="ethX device") 97 | p.add_argument("-4", dest="ip4", default="192.0.2.8/24", help="IP4/prefix") 98 | p.add_argument("-g", dest="gw", default="192.0.2.1/4000", help="gw/metric") 99 | p.add_argument("-a", dest="auto", action="store_true", help="autoconnect") 100 | p.add_argument("--save", dest="save", action="store_true", help="Save") 101 | args = p.parse_args() 102 | sdbus.set_default_bus(sdbus.sd_bus_open_system()) 103 | if connection_dpath := add_ethernet_connection(args): 104 | print(f"Path of the new connection: {connection_dpath}") 105 | print(f"UUID of the new connection: {args.uuid}") 106 | else: 107 | print("Error: No new connection created.") 108 | -------------------------------------------------------------------------------- /examples/dev/block/add-eth-connection.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # SPDX-License-Identifier: LGPL-2.1-or-later 3 | # 4 | # Example to create a new Ethernet network connection profile: 5 | # 6 | # examples/block/add-eth-connection.py --help 7 | # usage: add-eth-connection.py [-h] [-c CONN_ID] [-u UUID] [-i INTERFACE_NAME] 8 | # [-4 IP4] [-g GW] [-a] [--save] 9 | # 10 | # Optional arguments have example values: 11 | # 12 | # optional arguments: 13 | # -h, --help show this help message and exit 14 | # -c CONN_ID Connection Id 15 | # -u UUID Connection UUID 16 | # -i INTERFACE_NAME ethX device 17 | # -4 IP4 IP4/prefix 18 | # -g GW gw/metric 19 | # -a autoconnect 20 | # --save Save 21 | # 22 | # Connection Profile settings are described at: 23 | # https://networkmanager.dev/docs/api/latest/ref-settings.html 24 | 25 | import sdbus 26 | import functools 27 | import logging 28 | import pprint 29 | import sys 30 | from uuid import uuid4 31 | from argparse import ArgumentParser, Namespace 32 | from sdbus_block.networkmanager import NetworkManagerSettings 33 | from sdbus_block.networkmanager import NetworkManagerConnectionProperties 34 | 35 | 36 | def add_ethernet_connection(args: Namespace) -> str: 37 | """Add a (by default) temporary (not yet saved) network connection profile 38 | :param Namespace args: autoconnect, conn_id, psk, save, ssid, uuid 39 | :return: dbus connection path of the created connection profile 40 | """ 41 | info = logging.getLogger().info 42 | 43 | # If we add many connections using the same id, things get messy. Check: 44 | if NetworkManagerSettings().get_connections_by_id(args.conn_id): 45 | info(f'Connections using ID "{args.conn_id}" exist, remove them:') 46 | info(f'Run: nmcli connection delete "{args.conn_id}"') 47 | return "" 48 | 49 | ipaddr, prefix = args.ip4.split("/") 50 | properties: NetworkManagerConnectionProperties = { 51 | "connection": { 52 | "id": ("s", args.conn_id), 53 | "uuid": ("s", str(args.uuid)), 54 | "type": ("s", "802-3-ethernet"), 55 | "autoconnect": ("b", args.auto), 56 | }, 57 | "ipv4": { 58 | "method": ("s", "manual"), 59 | "address-data": ( 60 | "aa{sv}", 61 | [ 62 | { 63 | "address": ("s", ipaddr), 64 | "prefix": ("u", int(prefix)), 65 | }, 66 | ], 67 | ), 68 | }, 69 | "ipv6": {"method": ("s", "disabled")}, 70 | } 71 | if args.interface_name: 72 | properties["connection"]["interface-name"] = ("s", args.interface_name) 73 | if len(sys.argv) == 1 or args.gw != "192.0.2.1/4000": 74 | default_gateway, route_metric = args.gw.split("/") 75 | properties["ipv4"]["gateway"] = ("s", default_gateway) 76 | properties["ipv4"]["route-metric"] = ("u", int(route_metric)) 77 | 78 | s = NetworkManagerSettings() 79 | addconnection = s.add_connection if args.save else s.add_connection_unsaved 80 | connection_settings_dbus_path = addconnection(properties) 81 | created = "created and saved" if args.save else "created" 82 | 83 | info(f"New unsaved connection profile {created}, show it with:") 84 | info(f'nmcli connection show "{args.conn_id}"|grep -v -e -- -e default') 85 | info("Settings used:") 86 | info(functools.partial(pprint.pformat, sort_dicts=False)(properties)) 87 | return connection_settings_dbus_path 88 | 89 | 90 | if __name__ == "__main__": 91 | logging.basicConfig(format="%(message)s", level=logging.INFO) 92 | p = ArgumentParser(description="Optional arguments have example values:") 93 | conn_id = "MyConnectionExample" 94 | p.add_argument("-c", dest="conn_id", default=conn_id, help="Connection Id") 95 | p.add_argument("-u", dest="uuid", default=uuid4(), help="Connection UUID") 96 | p.add_argument("-i", dest="interface_name", default="", help="ethX device") 97 | p.add_argument("-4", dest="ip4", default="192.0.2.8/24", help="IP4/prefix") 98 | p.add_argument("-g", dest="gw", default="192.0.2.1/4000", help="gw/metric") 99 | p.add_argument("-a", dest="auto", action="store_true", help="autoconnect") 100 | p.add_argument("--save", dest="save", action="store_true", help="Save") 101 | args = p.parse_args() 102 | sdbus.set_default_bus(sdbus.sd_bus_open_system()) 103 | if connection_dpath := add_ethernet_connection(args): 104 | print(f"Path of the new connection: {connection_dpath}") 105 | print(f"UUID of the new connection: {args.uuid}") 106 | else: 107 | print("Error: No new connection created.") 108 | -------------------------------------------------------------------------------- /examples/dev/block/netdevinfo.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # SPDX-License-Identifier: LGPL-2.1-or-later 3 | # 4 | # Example to list the active IPv4 protocol configuration of network devices 5 | # and the current status of WiFi adapters 6 | # 7 | # For IPv4 and org.freedesktop.NetworkManager.Device.Wireless see: 8 | # https://networkmanager.dev/docs/api/latest/settings-ipv4.html 9 | # https://networkmanager.dev/docs/api/latest/ref-dbus-devices.html 10 | import sdbus 11 | from sdbus_block.networkmanager import ( 12 | ConnectionType, 13 | NetworkConnectionSettings, 14 | NetworkManager, 15 | NetworkManagerSettings, 16 | NetworkDeviceGeneric, 17 | IPv4Config, 18 | DeviceType, 19 | NetworkDeviceWireless, 20 | WiFiOperationMode, 21 | AccessPoint, 22 | ) 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: str, dev_type: str) -> 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.get_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())) 61 | 62 | 63 | def list_networkdevice_details_blocking() -> None: 64 | 65 | for device_path in NetworkManager().get_devices(): 66 | generic_device = NetworkDeviceGeneric(device_path) 67 | device_ip4_conf_path: str = generic_device.ip4_config 68 | if device_ip4_conf_path == "/": 69 | 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 75 | 76 | dev_name = generic_device.interface 77 | 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) 82 | 83 | if gateway: 84 | print("Gateway:", gateway) 85 | 86 | address_data: NetworkManagerAddressData = ip4_conf.address_data 87 | for inetaddr in address_data: 88 | print(f'Address: {inetaddr["address"][1]}/{inetaddr["prefix"][1]}') 89 | 90 | nameservers: NetworkManagerAddressData = ip4_conf.nameserver_data 91 | for dns in nameservers: 92 | print("DNS: ", dns["address"][1]) 93 | 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")) 101 | if ap.strength: 102 | 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) 106 | 107 | print("") 108 | 109 | 110 | if __name__ == "__main__": 111 | sdbus.set_default_bus(sdbus.sd_bus_open_system()) 112 | list_networkdevice_details_blocking() 113 | -------------------------------------------------------------------------------- /examples/2.0.0/block/netdevinfo.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # SPDX-License-Identifier: LGPL-2.1-or-later 3 | # 4 | # Example to list the active IPv4 protocol configuration of network devices 5 | # and the current status of WiFi adapters 6 | # 7 | # For IPv4 and org.freedesktop.NetworkManager.Device.Wireless see: 8 | # https://networkmanager.dev/docs/api/latest/settings-ipv4.html 9 | # https://networkmanager.dev/docs/api/latest/ref-dbus-devices.html 10 | import sdbus 11 | from sdbus_block.networkmanager import ( 12 | ConnectionType, 13 | NetworkConnectionSettings, 14 | NetworkManager, 15 | NetworkManagerSettings, 16 | NetworkDeviceGeneric, 17 | IPv4Config, 18 | DeviceType, 19 | NetworkDeviceWireless, 20 | WiFiOperationMode, 21 | AccessPoint, 22 | ) 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: str, dev_type: str) -> 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.get_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())) 61 | 62 | 63 | def list_networkdevice_details_blocking() -> None: 64 | 65 | for device_path in NetworkManager().get_devices(): 66 | generic_device = NetworkDeviceGeneric(device_path) 67 | device_ip4_conf_path: str = generic_device.ip4_config 68 | if device_ip4_conf_path == "/": 69 | 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 75 | 76 | dev_name = generic_device.interface 77 | 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) 82 | 83 | if gateway: 84 | print("Gateway:", gateway) 85 | 86 | address_data: NetworkManagerAddressData = ip4_conf.address_data 87 | for inetaddr in address_data: 88 | print(f'Address: {inetaddr["address"][1]}/{inetaddr["prefix"][1]}') 89 | 90 | nameservers: NetworkManagerAddressData = ip4_conf.nameserver_data 91 | for dns in nameservers: 92 | print("DNS: ", dns["address"][1]) 93 | 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")) 101 | if ap.strength: 102 | 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) 106 | 107 | print("") 108 | 109 | 110 | if __name__ == "__main__": 111 | sdbus.set_default_bus(sdbus.sd_bus_open_system()) 112 | list_networkdevice_details_blocking() 113 | -------------------------------------------------------------------------------- /examples/2.0.0/async/add-eth-connection-async.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # SPDX-License-Identifier: LGPL-2.1-or-later 3 | # 4 | # Example to create a new Ethernet network connection profile: 5 | # 6 | # examples/block/add-eth-connection-async.py --help 7 | # usage: add-eth-connection-async.py [-h] [-c CONN_ID] [-u UUID] [-4 IP4] 8 | # [-i INTERFACE_NAME] [-g GW] [-a] [--save] 9 | # 10 | # Optional arguments have example values: 11 | # 12 | # optional arguments: 13 | # -h, --help show this help message and exit 14 | # -c CONN_ID Connection Id 15 | # -u UUID Connection UUID 16 | # -i INTERFACE_NAME ethX device 17 | # -4 IP4 IP4/prefix 18 | # -g GW gw/metric 19 | # -a autoconnect 20 | # --save Save 21 | # 22 | # Connection Profile settings are described at: 23 | # https://networkmanager.dev/docs/api/latest/ref-settings.html 24 | 25 | import asyncio 26 | import sdbus 27 | import functools 28 | import logging 29 | import pprint 30 | import sys 31 | from uuid import uuid4 32 | from argparse import ArgumentParser, Namespace 33 | from sdbus_async.networkmanager import NetworkManagerSettings 34 | from sdbus_async.networkmanager import NetworkManagerConnectionProperties 35 | 36 | 37 | async def add_ethernet_connection_async(args: Namespace) -> str: 38 | """Add a (by default) temporary (not yet saved) network connection profile 39 | :param Namespace args: autoconnect, conn_id, psk, save, ssid, uuid 40 | :return: dbus connection path of the created connection profile 41 | """ 42 | info = logging.getLogger().info 43 | 44 | # If we add many connections using the same id, things get messy. Check: 45 | if await NetworkManagerSettings().get_connections_by_id(args.conn_id): 46 | info(f'Connections using ID "{args.conn_id}" exist, remove them:') 47 | info(f'Run: nmcli connection delete "{args.conn_id}"') 48 | return "" 49 | 50 | ipaddr, prefix = args.ip4.split("/") 51 | properties: NetworkManagerConnectionProperties = { 52 | "connection": { 53 | "id": ("s", args.conn_id), 54 | "uuid": ("s", str(args.uuid)), 55 | "type": ("s", "802-3-ethernet"), 56 | "autoconnect": ("b", args.auto), 57 | }, 58 | "ipv4": { 59 | "method": ("s", "manual"), 60 | "address-data": ( 61 | "aa{sv}", 62 | [ 63 | { 64 | "address": ("s", ipaddr), 65 | "prefix": ("u", int(prefix)), 66 | }, 67 | ], 68 | ), 69 | }, 70 | "ipv6": {"method": ("s", "disabled")}, 71 | } 72 | if args.interface_name: 73 | properties["connection"]["interface-name"] = ("s", args.interface_name) 74 | if len(sys.argv) == 1 or args.gw != "192.0.2.1/4000": 75 | default_gateway, route_metric = args.gw.split("/") 76 | properties["ipv4"]["gateway"] = ("s", default_gateway) 77 | properties["ipv4"]["route-metric"] = ("u", int(route_metric)) 78 | 79 | s = NetworkManagerSettings() 80 | addconnection = s.add_connection if args.save else s.add_connection_unsaved 81 | connection_settings_dbus_path = await addconnection(properties) 82 | created = "created and saved" if args.save else "created" 83 | 84 | info(f"New unsaved connection profile {created}, show it with:") 85 | info(f'nmcli connection show "{args.conn_id}"|grep -v -e -- -e default') 86 | info("Settings used:") 87 | info(functools.partial(pprint.pformat, sort_dicts=False)(properties)) 88 | return connection_settings_dbus_path 89 | 90 | 91 | if __name__ == "__main__": 92 | logging.basicConfig(format="%(message)s", level=logging.INFO) 93 | p = ArgumentParser(description="Optional arguments have example values:") 94 | conn_id = "MyConnectionExample" 95 | p.add_argument("-c", dest="conn_id", default=conn_id, help="Connection Id") 96 | p.add_argument("-u", dest="uuid", default=uuid4(), help="Connection UUID") 97 | p.add_argument("-i", dest="interface_name", default="", help="ethX device") 98 | p.add_argument("-4", dest="ip4", default="192.0.2.8/24", help="IP4/prefix") 99 | p.add_argument("-g", dest="gw", default="192.0.2.1/4000", help="gw/metric") 100 | p.add_argument("-a", dest="auto", action="store_true", help="autoconnect") 101 | p.add_argument("--save", dest="save", action="store_true", help="Save") 102 | args = p.parse_args() 103 | sdbus.set_default_bus(sdbus.sd_bus_open_system()) 104 | if connection_dpath := asyncio.run(add_ethernet_connection_async(args)): 105 | print(f"Path of the new connection: {connection_dpath}") 106 | print(f"UUID of the new connection: {args.uuid}") 107 | else: 108 | print("Error: No new connection created.") 109 | -------------------------------------------------------------------------------- /examples/dev/async/add-eth-connection-async.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # SPDX-License-Identifier: LGPL-2.1-or-later 3 | # 4 | # Example to create a new Ethernet network connection profile: 5 | # 6 | # examples/block/add-eth-connection-async.py --help 7 | # usage: add-eth-connection-async.py [-h] [-c CONN_ID] [-u UUID] [-4 IP4] 8 | # [-i INTERFACE_NAME] [-g GW] [-a] [--save] 9 | # 10 | # Optional arguments have example values: 11 | # 12 | # optional arguments: 13 | # -h, --help show this help message and exit 14 | # -c CONN_ID Connection Id 15 | # -u UUID Connection UUID 16 | # -i INTERFACE_NAME ethX device 17 | # -4 IP4 IP4/prefix 18 | # -g GW gw/metric 19 | # -a autoconnect 20 | # --save Save 21 | # 22 | # Connection Profile settings are described at: 23 | # https://networkmanager.dev/docs/api/latest/ref-settings.html 24 | 25 | import asyncio 26 | import sdbus 27 | import functools 28 | import logging 29 | import pprint 30 | import sys 31 | from uuid import uuid4 32 | from argparse import ArgumentParser, Namespace 33 | from sdbus_async.networkmanager import NetworkManagerSettings 34 | from sdbus_async.networkmanager import NetworkManagerConnectionProperties 35 | 36 | 37 | async def add_ethernet_connection_async(args: Namespace) -> str: 38 | """Add a (by default) temporary (not yet saved) network connection profile 39 | :param Namespace args: autoconnect, conn_id, psk, save, ssid, uuid 40 | :return: dbus connection path of the created connection profile 41 | """ 42 | info = logging.getLogger().info 43 | 44 | # If we add many connections using the same id, things get messy. Check: 45 | if await NetworkManagerSettings().get_connections_by_id(args.conn_id): 46 | info(f'Connections using ID "{args.conn_id}" exist, remove them:') 47 | info(f'Run: nmcli connection delete "{args.conn_id}"') 48 | return "" 49 | 50 | ipaddr, prefix = args.ip4.split("/") 51 | properties: NetworkManagerConnectionProperties = { 52 | "connection": { 53 | "id": ("s", args.conn_id), 54 | "uuid": ("s", str(args.uuid)), 55 | "type": ("s", "802-3-ethernet"), 56 | "autoconnect": ("b", args.auto), 57 | }, 58 | "ipv4": { 59 | "method": ("s", "manual"), 60 | "address-data": ( 61 | "aa{sv}", 62 | [ 63 | { 64 | "address": ("s", ipaddr), 65 | "prefix": ("u", int(prefix)), 66 | }, 67 | ], 68 | ), 69 | }, 70 | "ipv6": {"method": ("s", "disabled")}, 71 | } 72 | if args.interface_name: 73 | properties["connection"]["interface-name"] = ("s", args.interface_name) 74 | if len(sys.argv) == 1 or args.gw != "192.0.2.1/4000": 75 | default_gateway, route_metric = args.gw.split("/") 76 | properties["ipv4"]["gateway"] = ("s", default_gateway) 77 | properties["ipv4"]["route-metric"] = ("u", int(route_metric)) 78 | 79 | s = NetworkManagerSettings() 80 | addconnection = s.add_connection if args.save else s.add_connection_unsaved 81 | connection_settings_dbus_path = await addconnection(properties) 82 | created = "created and saved" if args.save else "created" 83 | 84 | info(f"New unsaved connection profile {created}, show it with:") 85 | info(f'nmcli connection show "{args.conn_id}"|grep -v -e -- -e default') 86 | info("Settings used:") 87 | info(functools.partial(pprint.pformat, sort_dicts=False)(properties)) 88 | return connection_settings_dbus_path 89 | 90 | 91 | if __name__ == "__main__": 92 | logging.basicConfig(format="%(message)s", level=logging.INFO) 93 | p = ArgumentParser(description="Optional arguments have example values:") 94 | conn_id = "MyConnectionExample" 95 | p.add_argument("-c", dest="conn_id", default=conn_id, help="Connection Id") 96 | p.add_argument("-u", dest="uuid", default=uuid4(), help="Connection UUID") 97 | p.add_argument("-i", dest="interface_name", default="", help="ethX device") 98 | p.add_argument("-4", dest="ip4", default="192.0.2.8/24", help="IP4/prefix") 99 | p.add_argument("-g", dest="gw", default="192.0.2.1/4000", help="gw/metric") 100 | p.add_argument("-a", dest="auto", action="store_true", help="autoconnect") 101 | p.add_argument("--save", dest="save", action="store_true", help="Save") 102 | args = p.parse_args() 103 | sdbus.set_default_bus(sdbus.sd_bus_open_system()) 104 | if connection_dpath := asyncio.run(add_ethernet_connection_async(args)): 105 | print(f"Path of the new connection: {connection_dpath}") 106 | print(f"UUID of the new connection: {args.uuid}") 107 | else: 108 | print("Error: No new connection created.") 109 | -------------------------------------------------------------------------------- /sdbus_async/networkmanager/settings/ip_tunnel.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: LGPL-2.1-or-later 2 | # This file was generated by tools/generate-settings-dataclasses-jinja.py, 3 | # if possible, please make changes by also updating the script. 4 | from __future__ import annotations 5 | from dataclasses import dataclass, field 6 | from typing import Optional 7 | from .base import NetworkManagerSettingsMixin 8 | 9 | 10 | @dataclass 11 | class IpTunnelSettings(NetworkManagerSettingsMixin): 12 | """IP Tunneling Settings""" 13 | 14 | encapsulation_limit: Optional[int] = field( 15 | metadata={ 16 | 'dbus_name': 'encapsulation-limit', 17 | 'dbus_type': 'u', 18 | }, 19 | default=None, 20 | ) 21 | """How many additional levels of encapsulation are permitted to be 22 | prepended to packets. This property applies only to IPv6 tunnels.""" 23 | flags: Optional[int] = field( 24 | metadata={ 25 | 'dbus_name': 'flags', 26 | 'dbus_type': 'u', 27 | }, 28 | default=None, 29 | ) 30 | """Tunnel flags. Currently, the following values are supported: 31 | NM_IP_TUNNEL_FLAG_IP6_IGN_ENCAP_LIMIT (0x1), 32 | NM_IP_TUNNEL_FLAG_IP6_USE_ORIG_TCLASS (0x2), 33 | NM_IP_TUNNEL_FLAG_IP6_USE_ORIG_FLOWLABEL (0x4), 34 | NM_IP_TUNNEL_FLAG_IP6_MIP6_DEV (0x8), 35 | NM_IP_TUNNEL_FLAG_IP6_RCV_DSCP_COPY (0x10), 36 | NM_IP_TUNNEL_FLAG_IP6_USE_ORIG_FWMARK (0x20). They are valid only 37 | for IPv6 tunnels.""" 38 | flow_label: Optional[int] = field( 39 | metadata={ 40 | 'dbus_name': 'flow-label', 41 | 'dbus_type': 'u', 42 | }, 43 | default=None, 44 | ) 45 | """The flow label to assign to tunnel packets. This property applies only 46 | to IPv6 tunnels.""" 47 | input_key: Optional[str] = field( 48 | metadata={ 49 | 'dbus_name': 'input-key', 50 | 'dbus_type': 's', 51 | }, 52 | default=None, 53 | ) 54 | """The key used for tunnel input packets; the property is valid only for 55 | certain tunnel modes (GRE, IP6GRE). If empty, no key is used.""" 56 | local: Optional[str] = field( 57 | metadata={ 58 | 'dbus_name': 'local', 59 | 'dbus_type': 's', 60 | }, 61 | default=None, 62 | ) 63 | """The local endpoint of the tunnel; the value can be empty, otherwise it 64 | must contain an IPv4 or IPv6 address.""" 65 | mode: Optional[int] = field( 66 | metadata={ 67 | 'dbus_name': 'mode', 68 | 'dbus_type': 'u', 69 | }, 70 | default=None, 71 | ) 72 | """The tunneling mode, for example NM_IP_TUNNEL_MODE_IPIP (1) or 73 | NM_IP_TUNNEL_MODE_GRE (2).""" 74 | mtu: Optional[int] = field( 75 | metadata={ 76 | 'dbus_name': 'mtu', 77 | 'dbus_type': 'u', 78 | }, 79 | default=None, 80 | ) 81 | """If non-zero, only transmit packets of the specified size or smaller, 82 | breaking larger packets up into multiple fragments.""" 83 | output_key: Optional[str] = field( 84 | metadata={ 85 | 'dbus_name': 'output-key', 86 | 'dbus_type': 's', 87 | }, 88 | default=None, 89 | ) 90 | """The key used for tunnel output packets; the property is valid only for 91 | certain tunnel modes (GRE, IP6GRE). If empty, no key is used.""" 92 | parent: Optional[str] = field( 93 | metadata={ 94 | 'dbus_name': 'parent', 95 | 'dbus_type': 's', 96 | }, 97 | default=None, 98 | ) 99 | """If given, specifies the parent interface name or parent connection UUID 100 | the new device will be bound to so that tunneled packets will only 101 | be routed via that interface.""" 102 | path_mtu_discovery: Optional[bool] = field( 103 | metadata={ 104 | 'dbus_name': 'path-mtu-discovery', 105 | 'dbus_type': 'b', 106 | }, 107 | default=None, 108 | ) 109 | """Whether to enable Path MTU Discovery on this tunnel.""" 110 | remote: Optional[str] = field( 111 | metadata={ 112 | 'dbus_name': 'remote', 113 | 'dbus_type': 's', 114 | }, 115 | default=None, 116 | ) 117 | """The remote endpoint of the tunnel; the value must contain an IPv4 or 118 | IPv6 address.""" 119 | tos: Optional[int] = field( 120 | metadata={ 121 | 'dbus_name': 'tos', 122 | 'dbus_type': 'u', 123 | }, 124 | default=None, 125 | ) 126 | """The type of service (IPv4) or traffic class (IPv6) field to be set on 127 | tunneled packets.""" 128 | ttl: Optional[int] = field( 129 | metadata={ 130 | 'dbus_name': 'ttl', 131 | 'dbus_type': 'u', 132 | }, 133 | default=None, 134 | ) 135 | """The TTL to assign to tunneled packets. 0 is a special value meaning that 136 | packets inherit the TTL value.""" 137 | -------------------------------------------------------------------------------- /docs/profile_settings.rst: -------------------------------------------------------------------------------- 1 | Connection Profile Settings Helpers 2 | =================================== 3 | 4 | .. autoclass:: sdbus_async.networkmanager.settings.AdslSettings 5 | :members: 6 | 7 | .. autoclass:: sdbus_async.networkmanager.settings.BluetoothSettings 8 | :members: 9 | 10 | .. autoclass:: sdbus_async.networkmanager.settings.BondSettings 11 | :members: 12 | 13 | .. autoclass:: sdbus_async.networkmanager.settings.BondPortSettings 14 | :members: 15 | 16 | .. autoclass:: sdbus_async.networkmanager.settings.BridgeSettings 17 | :members: 18 | 19 | .. autoclass:: sdbus_async.networkmanager.settings.BridgePortSettings 20 | :members: 21 | 22 | .. autoclass:: sdbus_async.networkmanager.settings.CdmaSettings 23 | :members: 24 | 25 | .. autoclass:: sdbus_async.networkmanager.settings.ConnectionSettings 26 | :members: 27 | 28 | .. autoclass:: sdbus_async.networkmanager.settings.DcbSettings 29 | :members: 30 | 31 | .. autoclass:: sdbus_async.networkmanager.settings.DummySettings 32 | :members: 33 | 34 | .. autoclass:: sdbus_async.networkmanager.settings.EapolSettings 35 | :members: 36 | 37 | .. autoclass:: sdbus_async.networkmanager.settings.EthernetSettings 38 | :members: 39 | 40 | .. autoclass:: sdbus_async.networkmanager.settings.EthtoolSettings 41 | :members: 42 | 43 | .. autoclass:: sdbus_async.networkmanager.settings.GenericSettings 44 | :members: 45 | 46 | .. autoclass:: sdbus_async.networkmanager.settings.GsmSettings 47 | :members: 48 | 49 | .. autoclass:: sdbus_async.networkmanager.settings.HostnameSettings 50 | :members: 51 | 52 | .. autoclass:: sdbus_async.networkmanager.settings.InfinibandSettings 53 | :members: 54 | 55 | .. autoclass:: sdbus_async.networkmanager.settings.IpTunnelSettings 56 | :members: 57 | 58 | .. autoclass:: sdbus_async.networkmanager.settings.Ipv4Settings 59 | :members: 60 | 61 | .. autoclass:: sdbus_async.networkmanager.settings.Ipv6Settings 62 | :members: 63 | 64 | .. autoclass:: sdbus_async.networkmanager.settings.LowpanSettings 65 | :members: 66 | 67 | .. autoclass:: sdbus_async.networkmanager.settings.MacsecSettings 68 | :members: 69 | 70 | .. autoclass:: sdbus_async.networkmanager.settings.MacvlanSettings 71 | :members: 72 | 73 | .. autoclass:: sdbus_async.networkmanager.settings.MatchSettings 74 | :members: 75 | 76 | .. autoclass:: sdbus_async.networkmanager.settings.OlpcMeshSettings 77 | :members: 78 | 79 | .. autoclass:: sdbus_async.networkmanager.settings.OvsBridgeSettings 80 | :members: 81 | 82 | .. autoclass:: sdbus_async.networkmanager.settings.OvsDpdkSettings 83 | :members: 84 | 85 | .. autoclass:: sdbus_async.networkmanager.settings.OvsExternalIdsSettings 86 | :members: 87 | 88 | .. autoclass:: sdbus_async.networkmanager.settings.OvsInterfaceSettings 89 | :members: 90 | 91 | .. autoclass:: sdbus_async.networkmanager.settings.OvsPatchSettings 92 | :members: 93 | 94 | .. autoclass:: sdbus_async.networkmanager.settings.OvsPortSettings 95 | :members: 96 | 97 | .. autoclass:: sdbus_async.networkmanager.settings.PppSettings 98 | :members: 99 | 100 | .. autoclass:: sdbus_async.networkmanager.settings.PppoeSettings 101 | :members: 102 | 103 | .. autoclass:: sdbus_async.networkmanager.settings.ProxySettings 104 | :members: 105 | 106 | .. autoclass:: sdbus_async.networkmanager.settings.SerialSettings 107 | :members: 108 | 109 | .. autoclass:: sdbus_async.networkmanager.settings.SriovSettings 110 | :members: 111 | 112 | .. autoclass:: sdbus_async.networkmanager.settings.TcSettings 113 | :members: 114 | 115 | .. autoclass:: sdbus_async.networkmanager.settings.TeamSettings 116 | :members: 117 | 118 | .. autoclass:: sdbus_async.networkmanager.settings.TeamPortSettings 119 | :members: 120 | 121 | .. autoclass:: sdbus_async.networkmanager.settings.TunSettings 122 | :members: 123 | 124 | .. autoclass:: sdbus_async.networkmanager.settings.UserSettings 125 | :members: 126 | 127 | .. autoclass:: sdbus_async.networkmanager.settings.VethSettings 128 | :members: 129 | 130 | .. autoclass:: sdbus_async.networkmanager.settings.VlanSettings 131 | :members: 132 | 133 | .. autoclass:: sdbus_async.networkmanager.settings.VpnSettings 134 | :members: 135 | 136 | .. autoclass:: sdbus_async.networkmanager.settings.VrfSettings 137 | :members: 138 | 139 | .. autoclass:: sdbus_async.networkmanager.settings.VxlanSettings 140 | :members: 141 | 142 | .. autoclass:: sdbus_async.networkmanager.settings.WifiP2PSettings 143 | :members: 144 | 145 | .. autoclass:: sdbus_async.networkmanager.settings.WimaxSettings 146 | :members: 147 | 148 | .. autoclass:: sdbus_async.networkmanager.settings.WireguardSettings 149 | :members: 150 | 151 | .. autoclass:: sdbus_async.networkmanager.settings.WirelessSettings 152 | :members: 153 | 154 | .. autoclass:: sdbus_async.networkmanager.settings.WirelessSecuritySettings 155 | :members: 156 | 157 | .. autoclass:: sdbus_async.networkmanager.settings.WpanSettings 158 | :members: 159 | 160 | -------------------------------------------------------------------------------- /examples/2.0.0/async/netdevinfo-async.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # SPDX-License-Identifier: LGPL-2.1-or-later 3 | # 4 | # Example to list the active IPv4 protocol configuration of network devices 5 | # and the current status of WiFi adapters 6 | # 7 | # For IPv4 and org.freedesktop.NetworkManager.Device.Wireless see: 8 | # https://networkmanager.dev/docs/api/latest/settings-ipv4.html 9 | # https://networkmanager.dev/docs/api/latest/ref-dbus-devices.html 10 | import asyncio 11 | import sdbus 12 | from sdbus_async.networkmanager import ( 13 | ConnectionType, 14 | NetworkConnectionSettings, 15 | NetworkManager, 16 | NetworkManagerSettings, 17 | NetworkDeviceGeneric, 18 | IPv4Config, 19 | DeviceType, 20 | NetworkDeviceWireless, 21 | WiFiOperationMode, 22 | AccessPoint, 23 | ) 24 | from typing import Any, Dict, List, Optional, Tuple 25 | NetworkManagerAddressData = List[Dict[str, Tuple[str, Any]]] 26 | 27 | 28 | async def get_most_recent_connection_id(ifname: str, dev_type: str) -> 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.get_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 | 64 | async def list_networkdevice_details_async() -> None: 65 | nm = NetworkManager() 66 | devices_paths = await nm.get_devices() 67 | 68 | for device_path in devices_paths: 69 | generic_device = NetworkDeviceGeneric(device_path) 70 | device_ip4_conf_path: str = await generic_device.ip4_config 71 | if device_ip4_conf_path == "/": 72 | 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 78 | 79 | dev_name = await generic_device.interface 80 | ip4_conf = IPv4Config(device_ip4_conf_path) 81 | gateway: str = await ip4_conf.gateway 82 | 83 | print("Type: ", dev_type.title()) 84 | print("Name: ", dev_name) 85 | 86 | if gateway: 87 | print("Gateway:", gateway) 88 | 89 | address_data: NetworkManagerAddressData = await ip4_conf.address_data 90 | for inetaddr in address_data: 91 | print(f'Address: {inetaddr["address"][1]}/{inetaddr["prefix"][1]}') 92 | 93 | nameservers: NetworkManagerAddressData = await ip4_conf.nameserver_data 94 | for dns in nameservers: 95 | print("DNS: ", dns["address"][1]) 96 | 97 | if dev_type == DeviceType.WIFI.name: 98 | wifi = NetworkDeviceWireless(device_path) 99 | print("Wifi: ", WiFiOperationMode(await wifi.mode).name.title()) 100 | ap_path = await wifi.active_access_point 101 | if ap_path == "/": 102 | print("No active access point") 103 | else: 104 | ap = AccessPoint(ap_path) 105 | ssid: bytes = await ap.ssid 106 | if ssid: 107 | print("SSID: ", ssid.decode("utf-8", "ignore")) 108 | if await ap.strength: 109 | print("Signal: ", await ap.strength) 110 | connection_id = await get_most_recent_connection_id(dev_name, dev_type) 111 | if connection_id: 112 | print("Profile:", connection_id) 113 | 114 | print("") 115 | 116 | 117 | if __name__ == "__main__": 118 | sdbus.set_default_bus(sdbus.sd_bus_open_system()) 119 | asyncio.run(list_networkdevice_details_async()) 120 | -------------------------------------------------------------------------------- /examples/dev/async/netdevinfo-async.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # SPDX-License-Identifier: LGPL-2.1-or-later 3 | # 4 | # Example to list the active IPv4 protocol configuration of network devices 5 | # and the current status of WiFi adapters 6 | # 7 | # For IPv4 and org.freedesktop.NetworkManager.Device.Wireless see: 8 | # https://networkmanager.dev/docs/api/latest/settings-ipv4.html 9 | # https://networkmanager.dev/docs/api/latest/ref-dbus-devices.html 10 | import asyncio 11 | import sdbus 12 | from sdbus_async.networkmanager import ( 13 | ConnectionType, 14 | NetworkConnectionSettings, 15 | NetworkManager, 16 | NetworkManagerSettings, 17 | NetworkDeviceGeneric, 18 | IPv4Config, 19 | DeviceType, 20 | NetworkDeviceWireless, 21 | WiFiOperationMode, 22 | AccessPoint, 23 | ) 24 | from typing import Any, Dict, List, Optional, Tuple 25 | NetworkManagerAddressData = List[Dict[str, Tuple[str, Any]]] 26 | 27 | 28 | async def get_most_recent_connection_id(ifname: str, dev_type: str) -> 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.get_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 | 64 | async def list_networkdevice_details_async() -> None: 65 | nm = NetworkManager() 66 | devices_paths = await nm.get_devices() 67 | 68 | for device_path in devices_paths: 69 | generic_device = NetworkDeviceGeneric(device_path) 70 | device_ip4_conf_path: str = await generic_device.ip4_config 71 | if device_ip4_conf_path == "/": 72 | 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 78 | 79 | dev_name = await generic_device.interface 80 | ip4_conf = IPv4Config(device_ip4_conf_path) 81 | gateway: str = await ip4_conf.gateway 82 | 83 | print("Type: ", dev_type.title()) 84 | print("Name: ", dev_name) 85 | 86 | if gateway: 87 | print("Gateway:", gateway) 88 | 89 | address_data: NetworkManagerAddressData = await ip4_conf.address_data 90 | for inetaddr in address_data: 91 | print(f'Address: {inetaddr["address"][1]}/{inetaddr["prefix"][1]}') 92 | 93 | nameservers: NetworkManagerAddressData = await ip4_conf.nameserver_data 94 | for dns in nameservers: 95 | print("DNS: ", dns["address"][1]) 96 | 97 | if dev_type == DeviceType.WIFI.name: 98 | wifi = NetworkDeviceWireless(device_path) 99 | print("Wifi: ", WiFiOperationMode(await wifi.mode).name.title()) 100 | ap_path = await wifi.active_access_point 101 | if ap_path == "/": 102 | print("No active access point") 103 | else: 104 | ap = AccessPoint(ap_path) 105 | ssid: bytes = await ap.ssid 106 | if ssid: 107 | print("SSID: ", ssid.decode("utf-8", "ignore")) 108 | if await ap.strength: 109 | print("Signal: ", await ap.strength) 110 | connection_id = await get_most_recent_connection_id(dev_name, dev_type) 111 | if connection_id: 112 | print("Profile:", connection_id) 113 | 114 | print("") 115 | 116 | 117 | if __name__ == "__main__": 118 | sdbus.set_default_bus(sdbus.sd_bus_open_system()) 119 | asyncio.run(list_networkdevice_details_async()) 120 | -------------------------------------------------------------------------------- /sdbus_async/networkmanager/settings/vxlan.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: LGPL-2.1-or-later 2 | # This file was generated by tools/generate-settings-dataclasses-jinja.py, 3 | # if possible, please make changes by also updating the script. 4 | from __future__ import annotations 5 | from dataclasses import dataclass, field 6 | from typing import Optional 7 | from .base import NetworkManagerSettingsMixin 8 | 9 | 10 | @dataclass 11 | class VxlanSettings(NetworkManagerSettingsMixin): 12 | """VXLAN Settings""" 13 | 14 | ageing: Optional[int] = field( 15 | metadata={ 16 | 'dbus_name': 'ageing', 17 | 'dbus_type': 'u', 18 | }, 19 | default=None, 20 | ) 21 | """Specifies the lifetime in seconds of FDB entries learnt by the kernel.""" 22 | destination_port: Optional[int] = field( 23 | metadata={ 24 | 'dbus_name': 'destination-port', 25 | 'dbus_type': 'u', 26 | }, 27 | default=None, 28 | ) 29 | """Specifies the UDP destination port to communicate to the remote VXLAN 30 | tunnel endpoint.""" 31 | vxlan_id: Optional[int] = field( 32 | metadata={ 33 | 'dbus_name': 'id', 34 | 'dbus_type': 'u', 35 | }, 36 | default=None, 37 | ) 38 | """Specifies the VXLAN Network Identifier (or VXLAN Segment Identifier) to 39 | use.""" 40 | l2_miss: Optional[bool] = field( 41 | metadata={ 42 | 'dbus_name': 'l2-miss', 43 | 'dbus_type': 'b', 44 | }, 45 | default=None, 46 | ) 47 | """Specifies whether netlink LL ADDR miss notifications are generated.""" 48 | l3_miss: Optional[bool] = field( 49 | metadata={ 50 | 'dbus_name': 'l3-miss', 51 | 'dbus_type': 'b', 52 | }, 53 | default=None, 54 | ) 55 | """Specifies whether netlink IP ADDR miss notifications are generated.""" 56 | learning: Optional[bool] = field( 57 | metadata={ 58 | 'dbus_name': 'learning', 59 | 'dbus_type': 'b', 60 | }, 61 | default=None, 62 | ) 63 | """Specifies whether unknown source link layer addresses and IP addresses 64 | are entered into the VXLAN device forwarding database.""" 65 | limit: Optional[int] = field( 66 | metadata={ 67 | 'dbus_name': 'limit', 68 | 'dbus_type': 'u', 69 | }, 70 | default=None, 71 | ) 72 | """Specifies the maximum number of FDB entries. A value of zero means that 73 | the kernel will store unlimited entries.""" 74 | local: Optional[str] = field( 75 | metadata={ 76 | 'dbus_name': 'local', 77 | 'dbus_type': 's', 78 | }, 79 | default=None, 80 | ) 81 | """If given, specifies the source IP address to use in outgoing packets.""" 82 | parent: Optional[str] = field( 83 | metadata={ 84 | 'dbus_name': 'parent', 85 | 'dbus_type': 's', 86 | }, 87 | default=None, 88 | ) 89 | """If given, specifies the parent interface name or parent connection UUID.""" 90 | proxy: Optional[bool] = field( 91 | metadata={ 92 | 'dbus_name': 'proxy', 93 | 'dbus_type': 'b', 94 | }, 95 | default=None, 96 | ) 97 | """Specifies whether ARP proxy is turned on.""" 98 | remote: Optional[str] = field( 99 | metadata={ 100 | 'dbus_name': 'remote', 101 | 'dbus_type': 's', 102 | }, 103 | default=None, 104 | ) 105 | """Specifies the unicast destination IP address to use in outgoing packets 106 | when the destination link layer address is not known in the VXLAN 107 | device forwarding database, or the multicast IP address to join.""" 108 | rsc: Optional[bool] = field( 109 | metadata={ 110 | 'dbus_name': 'rsc', 111 | 'dbus_type': 'b', 112 | }, 113 | default=None, 114 | ) 115 | """Specifies whether route short circuit is turned on.""" 116 | source_port_max: Optional[int] = field( 117 | metadata={ 118 | 'dbus_name': 'source-port-max', 119 | 'dbus_type': 'u', 120 | }, 121 | default=None, 122 | ) 123 | """Specifies the maximum UDP source port to communicate to the remote VXLAN 124 | tunnel endpoint.""" 125 | source_port_min: Optional[int] = field( 126 | metadata={ 127 | 'dbus_name': 'source-port-min', 128 | 'dbus_type': 'u', 129 | }, 130 | default=None, 131 | ) 132 | """Specifies the minimum UDP source port to communicate to the remote VXLAN 133 | tunnel endpoint.""" 134 | tos: Optional[int] = field( 135 | metadata={ 136 | 'dbus_name': 'tos', 137 | 'dbus_type': 'u', 138 | }, 139 | default=None, 140 | ) 141 | """Specifies the TOS value to use in outgoing packets.""" 142 | ttl: Optional[int] = field( 143 | metadata={ 144 | 'dbus_name': 'ttl', 145 | 'dbus_type': 'u', 146 | }, 147 | default=None, 148 | ) 149 | """Specifies the time-to-live value to use in outgoing packets.""" 150 | -------------------------------------------------------------------------------- /docs/quickstart.rst: -------------------------------------------------------------------------------- 1 | NetworkManager D-Bus API quickstart 2 | =================================== 3 | 4 | This is a tutorial to understand the structure of the NetworkManager 5 | D-Bus API and how to use it. 6 | 7 | .. note:: 8 | 9 | NetworkManager usually uses the system D-Bus, however, sdbus uses the session 10 | D-Bus by default. It is recommend to call ``sdbus.set_default_bus(sdbus.sd_bus_open_system())`` 11 | to set the system bus as default bus. 12 | 13 | NetworkManager main object 14 | -------------------------- 15 | 16 | This is a static object that contains information about 17 | entire state of NetworkManager. The Python class 18 | :py:class:`NetworkManager ` 19 | has a predefined service name and object path. 20 | 21 | .. code-block:: python 22 | 23 | import sdbus 24 | from sdbus_block.networkmanager import NetworkManager 25 | 26 | sdbus.set_default_bus(sdbus.sd_bus_open_system()) 27 | network_manager = NetworkManager() 28 | 29 | Devices 30 | ------- 31 | 32 | Every device object represents a network device. Device object has a generic 33 | methods and properties that are universal across all device types and 34 | a type specific methods. The :py:class:`NetworkDeviceGeneric 35 | ` implements generic methods 36 | and, for example, :py:class:`NetworkDeviceWireless ` 37 | adds Wi-Fi specific methods. 38 | 39 | The :py:attr:`device_type ` 40 | property and enum :py:class:`DeviceType ` 41 | can be used to determine particular type of a device. 42 | 43 | .. code-block:: python 44 | 45 | import sdbus 46 | 47 | from sdbus_block.networkmanager import ( 48 | NetworkDeviceGeneric, 49 | NetworkDeviceWireless, 50 | NetworkManager, 51 | ) 52 | from sdbus_block.networkmanager.enums import DeviceType 53 | 54 | sdbus.set_default_bus(sdbus.sd_bus_open_system()) 55 | network_manager = NetworkManager() 56 | 57 | all_devices = {path: NetworkDeviceGeneric(path) for path in network_manager.devices} 58 | 59 | wifi_devices = [ 60 | NetworkDeviceWireless(path) 61 | for path, device in all_devices.items() 62 | if device.device_type == DeviceType.WIFI 63 | ] 64 | 65 | Connection 66 | ---------- 67 | 68 | Connection represents a configuration containing an IP address, Wifi password, 69 | proxy settings and etc... The main object to access connections is the 70 | :py:class:`NetworkManagerSettings ` 71 | which has predefined object path. 72 | 73 | Each individual connection has a separate path which can be accessed with 74 | :py:class:`NetworkConnectionSettings ` 75 | class. 76 | 77 | .. code-block:: python 78 | 79 | import sdbus 80 | 81 | from sdbus_block.networkmanager import ( 82 | NetworkConnectionSettings, 83 | NetworkManager, 84 | NetworkManagerSettings, 85 | ) 86 | 87 | sdbus.set_default_bus(sdbus.sd_bus_open_system()) 88 | network_manager = NetworkManager() 89 | 90 | networwork_manager_settings = NetworkManagerSettings() 91 | 92 | all_connections = [ 93 | NetworkConnectionSettings(x) for x in networwork_manager_settings.connections 94 | ] 95 | 96 | The actual connection settings are represented by a complex double nested dictionary 97 | of D-Bus variants. For convenience a `dataclass `_ 98 | based helper is provided. 99 | 100 | The :py:meth:`get_profile ` 101 | and :py:meth:`update_profile ` 102 | are two main methods to interact with connection settings helper. 103 | 104 | .. code-block:: python 105 | 106 | import sdbus 107 | 108 | from sdbus_block.networkmanager import ( 109 | NetworkConnectionSettings, 110 | NetworkManager, 111 | NetworkManagerSettings, 112 | ) 113 | 114 | sdbus.set_default_bus(sdbus.sd_bus_open_system()) 115 | network_manager = NetworkManager() 116 | 117 | networwork_manager_settings = NetworkManagerSettings() 118 | 119 | 120 | connection = NetworkConnectionSettings(networwork_manager_settings.connections[0]) 121 | setting_dataclass = connection.get_profile() 122 | print("uuid:", setting_dataclass.connection.uuid) 123 | 124 | Active Connection 125 | ----------------- 126 | 127 | :py:class:`ActiveConnection ` 128 | is a product of a Connection being applied to a Device. 129 | 130 | For example, :py:meth:`activate_connection ` 131 | of the main NetworkManager object will create new Active Connection 132 | (therefore configuring network on a device) and return its path. 133 | The :py:meth:`deactivate_connection ` 134 | will remove the active connection and remove the device's network configuration. 135 | -------------------------------------------------------------------------------- /sdbus_async/networkmanager/settings/wireguard.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: LGPL-2.1-or-later 2 | # This file was generated by tools/generate-settings-dataclasses-jinja.py, 3 | # if possible, please make changes by also updating the script. 4 | from __future__ import annotations 5 | from dataclasses import dataclass, field 6 | from typing import Any, List, Optional, Tuple 7 | from .base import NetworkManagerSettingsMixin 8 | from .datatypes import WireguardPeers 9 | 10 | 11 | @dataclass 12 | class WireguardSettings(NetworkManagerSettingsMixin): 13 | """WireGuard Settings""" 14 | secret_fields_names = ['private_key'] 15 | secret_name = 'wireguard' 16 | 17 | fwmark: Optional[int] = field( 18 | metadata={ 19 | 'dbus_name': 'fwmark', 20 | 'dbus_type': 'u', 21 | }, 22 | default=None, 23 | ) 24 | """The use of fwmark is optional and is by default off. Setting it to 0 25 | disables it. Otherwise, it is a 32-bit fwmark for outgoing packets. 26 | 27 | Note that "ip4-auto-default-route" or "ip6-auto-default-route" 28 | enabled, implies to automatically choose a fwmark.""" 29 | ip4_auto_default_route: Optional[int] = field( 30 | metadata={ 31 | 'dbus_name': 'ip4-auto-default-route', 32 | 'dbus_type': 'i', 33 | }, 34 | default=None, 35 | ) 36 | """Whether to enable special handling of the IPv4 default route. If 37 | enabled, the IPv4 default route from wireguard.peer-routes will be 38 | placed to a dedicated routing-table and two policy routing rules 39 | will be added. The fwmark number is also used as routing-table for 40 | the default-route, and if fwmark is zero, an unused fwmark/table is 41 | chosen automatically. This corresponds to what wg-quick does with 42 | Table=auto and what WireGuard calls "Improved Rule-based Routing". 43 | 44 | Note that for this automatism to work, you usually don't want to set 45 | ipv4.gateway, because that will result in a conflicting default 46 | route. 47 | 48 | Leaving this at the default will enable this option automatically if 49 | ipv4.never-default is not set and there are any peers that use a 50 | default-route as allowed-ips. Since this automatism only makes sense 51 | if you also have a peer with an /0 allowed-ips, it is usually not 52 | necessary to enable this explicitly. However, you can disable it if 53 | you want to configure your own routing and rules.""" 54 | ip6_auto_default_route: Optional[int] = field( 55 | metadata={ 56 | 'dbus_name': 'ip6-auto-default-route', 57 | 'dbus_type': 'i', 58 | }, 59 | default=None, 60 | ) 61 | """Like ip4-auto-default-route, but for the IPv6 default route.""" 62 | listen_port: Optional[int] = field( 63 | metadata={ 64 | 'dbus_name': 'listen-port', 65 | 'dbus_type': 'u', 66 | }, 67 | default=None, 68 | ) 69 | """The listen-port. If listen-port is not specified, the port will be 70 | chosen randomly when the interface comes up.""" 71 | mtu: Optional[int] = field( 72 | metadata={ 73 | 'dbus_name': 'mtu', 74 | 'dbus_type': 'u', 75 | }, 76 | default=None, 77 | ) 78 | """If non-zero, only transmit packets of the specified size or smaller, 79 | breaking larger packets up into multiple fragments. 80 | 81 | If zero a default MTU is used. Note that contrary to wg-quick's MTU 82 | setting, this does not take into account the current routes at the 83 | time of activation.""" 84 | peer_routes: Optional[bool] = field( 85 | metadata={ 86 | 'dbus_name': 'peer-routes', 87 | 'dbus_type': 'b', 88 | }, 89 | default=None, 90 | ) 91 | """Whether to automatically add routes for the AllowedIPs ranges of the 92 | peers. If TRUE (the default), NetworkManager will automatically add 93 | routes in the routing tables according to ipv4.route-table and 94 | ipv6.route-table. Usually you want this automatism enabled. If 95 | FALSE, no such routes are added automatically. In this case, the 96 | user may want to configure static routes in ipv4.routes and 97 | ipv6.routes, respectively. 98 | 99 | Note that if the peer's AllowedIPs is "0.0.0.0/0" or "::/0" and the 100 | profile's ipv4.never-default or ipv6.never-default setting is 101 | enabled, the peer route for this peer won't be added automatically.""" 102 | peers: Optional[List[WireguardPeers]] = field( 103 | metadata={ 104 | 'dbus_name': 'peers', 105 | 'dbus_type': 'aa{sv}', 106 | 'dbus_inner_class': WireguardPeers, 107 | }, 108 | default=None, 109 | ) 110 | """Array of dictionaries for the WireGuard peers.""" 111 | private_key: Optional[str] = field( 112 | metadata={ 113 | 'dbus_name': 'private-key', 114 | 'dbus_type': 's', 115 | }, 116 | default=None, 117 | ) 118 | """The 256 bit private-key in base64 encoding.""" 119 | private_key_flags: Optional[int] = field( 120 | metadata={ 121 | 'dbus_name': 'private-key-flags', 122 | 'dbus_type': 'u', 123 | }, 124 | default=None, 125 | ) 126 | """Flags indicating how to handle the "private-key" property.""" 127 | --------------------------------------------------------------------------------