Skip to content

Commit c4fa97c

Browse files
committed
[feature] Added support for VXLAN interfaces #186
Related to #186
1 parent b64f837 commit c4fa97c

6 files changed

Lines changed: 218 additions & 0 deletions

File tree

netjsonconfig/backends/base/converter.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,10 @@ def type_cast(self, item, schema=None):
5151
json_type = properties[key]['type']
5252
except KeyError:
5353
json_type = None
54+
# if multiple types are supported, the first
55+
# one takes precedence when parsing
56+
if isinstance(json_type, list) and json_type:
57+
json_type = json_type[0]
5458
if json_type == 'integer' and not isinstance(value, int):
5559
value = int(value)
5660
elif json_type == 'boolean' and not isinstance(value, bool):

netjsonconfig/backends/openwrt/converters/interfaces.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
from ..schema import schema
66
from .base import OpenWrtConverter
7+
from ..schema import schema
78

89

910
class Interfaces(OpenWrtConverter):
@@ -128,6 +129,11 @@ def __intermediate_interface(self, interface, uci_name):
128129
def _intermediate_modem_manager(self, interface):
129130
interface['proto'] = 'modemmanager'
130131
interface['pincode'] = interface.pop('pin', None)
132+
133+
def _intermediate_vxlan(self, interface):
134+
interface['proto'] = 'vxlan'
135+
interface['peeraddr'] = interface.pop('vtep')
136+
interface['vid'] = interface.pop('vni')
131137
return interface
132138

133139
_address_keys = ['address', 'mask', 'family', 'gateway']
@@ -314,6 +320,15 @@ def _netjson_modem_manager(self, interface):
314320

315321
_netjson_modemmanager = _netjson_modem_manager
316322

323+
_vxlan_schema = schema['definitions']['vxlan_interface']['allOf'][0]
324+
325+
def _netjson_vxlan(self, interface):
326+
interface['type'] = interface.pop('proto', None)
327+
interface['vtep'] = interface.pop('peeraddr', None)
328+
interface['vni'] = interface.pop('vid', None)
329+
interface['port'] = interface['port']
330+
return self.type_cast(interface, schema=self._vxlan_schema)
331+
317332
def __netjson_address(self, address, interface):
318333
ip = ip_interface(address)
319334
family = 'ipv{0}'.format(ip.version)

netjsonconfig/backends/openwrt/schema.py

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,75 @@
207207
},
208208
},
209209
},
210+
"vxlan_interface": {
211+
"title": "VXLAN interface",
212+
"required": ["vtep", "port", "vni", "tunlink"],
213+
"allOf": [
214+
{
215+
"properties": {
216+
"type": {
217+
"type": "string",
218+
"enum": ["vxlan"],
219+
"default": "vxlan",
220+
"propertyOrder": 1,
221+
},
222+
"vtep": {
223+
"type": "string",
224+
"format": "hostname",
225+
"title": "VTEP",
226+
"description": "VXLAN Tunnel End Point",
227+
"propertyOrder": 1.1,
228+
},
229+
"port": {
230+
"type": "integer",
231+
"propertyOrder": 1.2,
232+
"default": 4789,
233+
"minimum": 1,
234+
"maximum": 65535,
235+
},
236+
"vni": {
237+
"type": ["integer", "string"],
238+
"title": "VNI",
239+
"description": "VXLAN Network Identifier",
240+
"propertyOrder": 1.3,
241+
"minimum": 1,
242+
"maximum": 16777216,
243+
},
244+
"tunlink": {
245+
"type": "string",
246+
"title": "TUN link",
247+
"description": "Interface to which the VXLAN tunnel will be bound",
248+
"propertyOrder": 1.4,
249+
},
250+
"rxcsum": {
251+
"type": "boolean",
252+
"title": "RX checksum validation",
253+
"description": "Use checksum validation in RX (receiving) direction",
254+
"default": True,
255+
"format": "checkbox",
256+
"propertyOrder": 1.5,
257+
},
258+
"txcsum": {
259+
"type": "boolean",
260+
"title": "TX checksum validation",
261+
"description": "Use checksum validation in TX (transmission) direction",
262+
"default": True,
263+
"format": "checkbox",
264+
"propertyOrder": 1.6,
265+
},
266+
"mtu": {"type": "integer", "default": 1280},
267+
"ttl": {
268+
"type": "integer",
269+
"title": "TTL",
270+
"description": "TTL of the encapsulation packets",
271+
"default": 64,
272+
"propertyOrder": 3,
273+
},
274+
}
275+
},
276+
{"$ref": "#/definitions/interface_settings"},
277+
],
278+
},
210279
"base_radio_settings": {
211280
"properties": {
212281
"driver": {
@@ -265,6 +334,7 @@
265334
"oneOf": [
266335
{"$ref": "#/definitions/dialup_interface"},
267336
{"$ref": "#/definitions/modemmanager_interface"},
337+
{"$ref": "#/definitions/vxlan_interface"},
268338
]
269339
}
270340
},

netjsonconfig/backends/wireguard/schema.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,4 +94,5 @@
9494
}
9595

9696
schema = deepcopy(base_wireguard_schema)
97+
schema['required'] = ['wireguard']
9798
schema['properties']['files'] = default_schema['properties']['files']

tests/openwrt/test_vxlan.py

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
import unittest
2+
3+
from netjsonconfig import OpenWrt
4+
from netjsonconfig.utils import _TabsMixin
5+
6+
7+
class TestVxlan(unittest.TestCase, _TabsMixin):
8+
maxDiff = None
9+
10+
def test_render_vxlan(self):
11+
o = OpenWrt(
12+
{
13+
"interfaces": [
14+
{
15+
"name": "vxlan1",
16+
"type": "vxlan",
17+
"vtep": "10.0.0.1",
18+
"port": 4789,
19+
"vni": 1,
20+
"tunlink": "wg0",
21+
"rxcsum": True,
22+
"txcsum": True,
23+
"mtu": 1280,
24+
"ttl": 64,
25+
}
26+
]
27+
}
28+
)
29+
expected = self._tabs(
30+
"""package network
31+
32+
config interface 'vxlan1'
33+
option ifname 'vxlan1'
34+
option mtu '1280'
35+
option peeraddr '10.0.0.1'
36+
option port '4789'
37+
option proto 'vxlan'
38+
option rxcsum '1'
39+
option ttl '64'
40+
option tunlink 'wg0'
41+
option txcsum '1'
42+
option vid '1'
43+
"""
44+
)
45+
self.assertEqual(o.render(), expected)
46+
47+
def test_parse_vxlan(self):
48+
native = self._tabs(
49+
"""package network
50+
51+
config interface 'vxlan1'
52+
option ifname 'vxlan1'
53+
option mtu '1280'
54+
option peeraddr '10.0.0.1'
55+
option port '4789'
56+
option proto 'vxlan'
57+
option rxcsum '1'
58+
option ttl '64'
59+
option tunlink 'wg0'
60+
option txcsum '1'
61+
option vid '1'
62+
"""
63+
)
64+
expected = {
65+
"interfaces": [
66+
{
67+
"name": "vxlan1",
68+
"type": "vxlan",
69+
"vtep": "10.0.0.1",
70+
"port": 4789,
71+
"vni": 1,
72+
"tunlink": "wg0",
73+
"rxcsum": True,
74+
"txcsum": True,
75+
"mtu": 1280,
76+
"ttl": 64,
77+
}
78+
]
79+
}
80+
o = OpenWrt(native=native)
81+
self.assertEqual(o.config, expected)
82+
83+
def test_render_vxlan_with_variables(self):
84+
o = OpenWrt(
85+
{
86+
"interfaces": [
87+
{
88+
"type": "vxlan",
89+
"name": "vxlan2",
90+
"vtep": "{{ vtep_e9081f8d67c8470d850ceb9c33bd0314 }}",
91+
"port": 4789,
92+
"vni": "{{ vni_e9081f8d67c8470d850ceb9c33bd0314 }}",
93+
"tunlink": "wg0",
94+
"rxcsum": False,
95+
"txcsum": False,
96+
"mtu": 1280,
97+
"ttl": 64,
98+
}
99+
]
100+
},
101+
context={
102+
"vtep_e9081f8d67c8470d850ceb9c33bd0314": "10.0.0.2",
103+
"vni_e9081f8d67c8470d850ceb9c33bd0314": "2",
104+
},
105+
)
106+
expected = self._tabs(
107+
"""package network
108+
109+
config interface 'vxlan2'
110+
option ifname 'vxlan2'
111+
option mtu '1280'
112+
option peeraddr '10.0.0.2'
113+
option port '4789'
114+
option proto 'vxlan'
115+
option rxcsum '0'
116+
option ttl '64'
117+
option tunlink 'wg0'
118+
option txcsum '0'
119+
option vid '2'
120+
"""
121+
)
122+
self.assertEqual(o.render(), expected)

tests/wireguard/test_backend.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import unittest
33

44
from netjsonconfig import Wireguard
5+
from netjsonconfig.exceptions import ValidationError
56

67

78
class TestBackend(unittest.TestCase):
@@ -11,6 +12,11 @@ class TestBackend(unittest.TestCase):
1112

1213
maxDiff = None
1314

15+
def test_test_schema(self):
16+
with self.assertRaises(ValidationError) as context_manager:
17+
Wireguard({}).validate()
18+
self.assertIn("'wireguard' is a required property", str(context_manager.exception))
19+
1420
def test_confs(self):
1521
c = Wireguard(
1622
{

0 commit comments

Comments
 (0)