Skip to content

Commit bf818a5

Browse files
committed
[feature] Added support for modem manager interfaces #167
Closes #167
1 parent b81cfd7 commit bf818a5

5 files changed

Lines changed: 202 additions & 1 deletion

File tree

CHANGES.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ Version 0.9.0 [unreleased]
1010
This change is backward incompatible if the same type of configuration
1111
was achieved using a workaround, in these cases the configuration
1212
will have to be upgraded to use the new format.
13+
- [feature] Added support for modem manager interfaces
1314

1415
Version 0.8.2 [2020-08-17]
1516
--------------------------

docs/source/backends/openwrt.rst

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,7 @@ There are 4 main types of interfaces:
294294
* **wireless interfaces**: must be of type ``wireless``
295295
* **bridge interfaces**: must be of type ``bridge``
296296
* **dialup interfaces**: must be of type ``dialup``
297+
* **modem manager interfaces**: must be of type ``modem-manager``
297298

298299
Interface object extensions
299300
~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -1259,6 +1260,83 @@ Will be rendered as follows::
12591260
option password 'jf93nf82o023$'
12601261
option mtu '1448'
12611262

1263+
Modem Manager settings
1264+
----------------------
1265+
1266+
Interfaces of type ``modem-manager`` contain a few options
1267+
that are specific to modem-manager interfaces (2G, 3G, 4G, LTE, etc).
1268+
1269+
These are the ``OpenWrt`` backend NetJSON extensions for Modem Manager interfaces:
1270+
1271+
+--------------+---------+-----------------+--------------------------------------------+
1272+
| key name | type | default | allowed values |
1273+
+==============+=========+=================+============================================+
1274+
| ``proto`` | string | ``modemanager`` | ``modemanager`` |
1275+
+--------------+---------+-----------------+--------------------------------------------+
1276+
| ``apn`` | string | empty | APN, can be left blank |
1277+
+--------------+---------+-----------------+--------------------------------------------+
1278+
| ``pin`` | string | empty | PIN code, can be left blank |
1279+
+--------------+---------+-----------------+--------------------------------------------+
1280+
| ``device`` | string | empty | path to device (see note below) |
1281+
+--------------+---------+-----------------+--------------------------------------------+
1282+
| ``password`` | string | empty | password, can be left blank |
1283+
+--------------+---------+-----------------+--------------------------------------------+
1284+
| ``username`` | string | empty | username, can be left blank |
1285+
+--------------+---------+-----------------+--------------------------------------------+
1286+
| ``metric`` | integer | ``50`` | metric, can be left blank |
1287+
+--------------+---------+-----------------+--------------------------------------------+
1288+
| ``iptype`` | string | ``ipv4`` | One of ``ipv4``, ``ipv6``, ``ipv4v6`` |
1289+
+--------------+---------+-----------------+--------------------------------------------+
1290+
| ``lowpower`` | boolean | ``False`` | low power mode |
1291+
+--------------+---------+-----------------+--------------------------------------------+
1292+
1293+
.. note::
1294+
``device`` is a required property but can be left empty so that
1295+
the default value supplied by the hardware itself and already
1296+
present on the device can be left untouched by merging the
1297+
configuration generated with netjsonconfig
1298+
(instead of fully overwriting it).
1299+
1300+
Modem Manager interface example
1301+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1302+
1303+
The following *configuration dictionary*:
1304+
1305+
.. code-block:: python
1306+
1307+
{
1308+
"interfaces": [
1309+
{
1310+
"type": "modem-manager",
1311+
"apn": "apn.operator.com",
1312+
"pin": "1234",
1313+
"device": "/sys/devices/platform/ahb/1b000000.usb/usb1/1-1",
1314+
"username": "user123",
1315+
"password": "pwd123456",
1316+
"metric": 50,
1317+
"lowpower": False,
1318+
"name": "modem0",
1319+
"mtu": 1500
1320+
}
1321+
]
1322+
}
1323+
1324+
Will be rendered as follows::
1325+
1326+
package network
1327+
1328+
config interface 'modem0'
1329+
option apn 'apn.operator.com'
1330+
option device '/sys/devices/platform/ahb/1b000000.usb/usb1/1-1'
1331+
option ifname 'wwan0'
1332+
option lowpower '0'
1333+
option metric '50'
1334+
option mtu '1500'
1335+
option password 'pwd123456'
1336+
option pincode '1234'
1337+
option proto 'modemmanager'
1338+
option username 'user123'
1339+
12621340
Radio settings
12631341
--------------
12641342

netjsonconfig/backends/openwrt/converters/interfaces.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from copy import deepcopy
33
from ipaddress import ip_address, ip_interface
44

5+
from ..schema import schema
56
from .base import OpenWrtConverter
67

78

@@ -115,6 +116,10 @@ def __intermediate_interface(self, interface, uci_name):
115116
if method:
116117
interface = method(interface)
117118
return interface
119+
120+
def _intermediate_modem_manager(self, interface):
121+
interface['proto'] = 'modemmanager'
122+
interface['pincode'] = interface.pop('pin', None)
118123
return interface
119124

120125
_address_keys = ['address', 'mask', 'family', 'gateway']
@@ -291,6 +296,16 @@ def _netjson_dialup(self, interface):
291296
interface['type'] = 'dialup'
292297
return interface
293298

299+
_modem_manager_schema = schema['definitions']['modemmanager_interface']
300+
301+
def _netjson_modem_manager(self, interface):
302+
del interface['proto']
303+
interface['type'] = 'modem-manager'
304+
interface['pin'] = interface.pop('pincode', None)
305+
return self.type_cast(interface, schema=self._modem_manager_schema)
306+
307+
_netjson_modemmanager = _netjson_modem_manager
308+
294309
def __netjson_address(self, address, interface):
295310
ip = ip_interface(address)
296311
family = 'ipv{0}'.format(ip.version)

netjsonconfig/backends/openwrt/schema.py

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
from .timezones import timezones
88

99
default_radio_driver = "mac80211"
10+
_interface_properties = default_schema["definitions"]["interface_settings"][
11+
"properties"
12+
]
1013

1114

1215
schema = merge_config(
@@ -158,6 +161,53 @@
158161
{"$ref": "#/definitions/interface_settings"},
159162
],
160163
},
164+
"modemmanager_interface": {
165+
"type": "object",
166+
"title": "Modem manager interface",
167+
"required": ["name", "device"],
168+
"properties": {
169+
"name": _interface_properties["name"],
170+
"mtu": _interface_properties["mtu"],
171+
"autostart": _interface_properties["autostart"],
172+
"disabled": _interface_properties["disabled"],
173+
"type": {
174+
"type": "string",
175+
"enum": ["modem-manager"],
176+
"default": "dialup",
177+
"propertyOrder": 1,
178+
},
179+
"apn": {"type": "string", "title": "APN", "propertyOrder": 1.1},
180+
"pin": {
181+
"type": "string",
182+
"title": "PIN code",
183+
"maxLength": 4,
184+
"propertyOrder": 1.2,
185+
},
186+
"device": {
187+
"type": "string",
188+
"description": "Leave blank to use the hardware default",
189+
"propertyOrder": 1.3,
190+
},
191+
"username": {"type": "string", "propertyOrder": 1.4},
192+
"password": {"type": "string", "propertyOrder": 1.5},
193+
"metric": {"type": "integer", "default": 50, "propertyOrder": 1.6},
194+
"iptype": {
195+
"type": "string",
196+
"title": "IP type",
197+
"default": "ipv4",
198+
"enum": ["ipv4", "ipv6", "ipv4v6"],
199+
"options": {"enum_titles": ["IPv4", "IPv6", "IPv4 and IPv6"]},
200+
"propertyOrder": 1.7,
201+
},
202+
"lowpower": {
203+
"type": "boolean",
204+
"title": "Low power mode",
205+
"format": "checkbox",
206+
"default": False,
207+
"propertyOrder": 1.8,
208+
},
209+
},
210+
},
161211
"base_radio_settings": {
162212
"properties": {
163213
"driver": {
@@ -212,7 +262,12 @@
212262
}
213263
},
214264
"interfaces": {
215-
"items": {"oneOf": [{"$ref": "#/definitions/dialup_interface"}]}
265+
"items": {
266+
"oneOf": [
267+
{"$ref": "#/definitions/dialup_interface"},
268+
{"$ref": "#/definitions/modemmanager_interface"},
269+
]
270+
}
216271
},
217272
"routes": {
218273
"items": {

tests/openwrt/test_modemmanager.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import unittest
2+
3+
from netjsonconfig import OpenWrt
4+
from netjsonconfig.utils import _TabsMixin
5+
6+
7+
class TestModemManager(unittest.TestCase, _TabsMixin):
8+
maxDiff = None
9+
10+
_modemmanager_interface_netjson = {
11+
"interfaces": [
12+
{
13+
"name": "wwan0",
14+
"type": "modem-manager",
15+
"apn": "apn.vodafone.com",
16+
"pin": "1234",
17+
"device": "/sys/devices/platform/ahb/1b000000.usb/usb1/1-1",
18+
"username": "user123",
19+
"password": "pwd123456",
20+
"metric": 50,
21+
"iptype": "ipv4v6",
22+
"lowpower": False,
23+
"mtu": 1500,
24+
}
25+
]
26+
}
27+
28+
_modemmanager_interface_uci = """package network
29+
30+
config interface 'wwan0'
31+
option apn 'apn.vodafone.com'
32+
option device '/sys/devices/platform/ahb/1b000000.usb/usb1/1-1'
33+
option ifname 'wwan0'
34+
option iptype 'ipv4v6'
35+
option lowpower '0'
36+
option metric '50'
37+
option mtu '1500'
38+
option password 'pwd123456'
39+
option pincode '1234'
40+
option proto 'modemmanager'
41+
option username 'user123'
42+
"""
43+
44+
def test_render_modemmanager_interface(self):
45+
result = OpenWrt(self._modemmanager_interface_netjson).render()
46+
expected = self._tabs(self._modemmanager_interface_uci)
47+
self.assertEqual(result, expected)
48+
49+
def test_parse_modemmanager_interface(self):
50+
result = OpenWrt(native=self._modemmanager_interface_uci).config
51+
expected = self._modemmanager_interface_netjson
52+
self.assertDictEqual(result, expected)

0 commit comments

Comments
 (0)