Skip to content

Commit

Permalink
[feature] Added support for VXLAN interfaces #186
Browse files Browse the repository at this point in the history
Related to #186
  • Loading branch information
nemesifier authored and pandafy committed Aug 19, 2021
1 parent dd3238e commit d62ee4d
Show file tree
Hide file tree
Showing 6 changed files with 218 additions and 0 deletions.
4 changes: 4 additions & 0 deletions netjsonconfig/backends/base/converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ def type_cast(self, item, schema=None):
json_type = properties[key]['type']
except KeyError:
json_type = None
# if multiple types are supported, the first
# one takes precedence when parsing
if isinstance(json_type, list) and json_type:
json_type = json_type[0]
if json_type == 'integer' and not isinstance(value, int):
value = int(value)
elif json_type == 'boolean' and not isinstance(value, bool):
Expand Down
15 changes: 15 additions & 0 deletions netjsonconfig/backends/openwrt/converters/interfaces.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

from ..schema import schema
from .base import OpenWrtConverter
from ..schema import schema


class Interfaces(OpenWrtConverter):
Expand Down Expand Up @@ -128,6 +129,11 @@ def __intermediate_interface(self, interface, uci_name):
def _intermediate_modem_manager(self, interface):
interface['proto'] = 'modemmanager'
interface['pincode'] = interface.pop('pin', None)

def _intermediate_vxlan(self, interface):
interface['proto'] = 'vxlan'
interface['peeraddr'] = interface.pop('vtep')
interface['vid'] = interface.pop('vni')
return interface

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

_netjson_modemmanager = _netjson_modem_manager

_vxlan_schema = schema['definitions']['vxlan_interface']['allOf'][0]

def _netjson_vxlan(self, interface):
interface['type'] = interface.pop('proto', None)
interface['vtep'] = interface.pop('peeraddr', None)
interface['vni'] = interface.pop('vid', None)
interface['port'] = interface['port']
return self.type_cast(interface, schema=self._vxlan_schema)

def __netjson_address(self, address, interface):
ip = ip_interface(address)
family = 'ipv{0}'.format(ip.version)
Expand Down
70 changes: 70 additions & 0 deletions netjsonconfig/backends/openwrt/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,75 @@
},
},
},
"vxlan_interface": {
"title": "VXLAN interface",
"required": ["vtep", "port", "vni", "tunlink"],
"allOf": [
{
"properties": {
"type": {
"type": "string",
"enum": ["vxlan"],
"default": "vxlan",
"propertyOrder": 1,
},
"vtep": {
"type": "string",
"format": "hostname",
"title": "VTEP",
"description": "VXLAN Tunnel End Point",
"propertyOrder": 1.1,
},
"port": {
"type": "integer",
"propertyOrder": 1.2,
"default": 4789,
"minimum": 1,
"maximum": 65535,
},
"vni": {
"type": ["integer", "string"],
"title": "VNI",
"description": "VXLAN Network Identifier",
"propertyOrder": 1.3,
"minimum": 1,
"maximum": 16777216,
},
"tunlink": {
"type": "string",
"title": "TUN link",
"description": "Interface to which the VXLAN tunnel will be bound",
"propertyOrder": 1.4,
},
"rxcsum": {
"type": "boolean",
"title": "RX checksum validation",
"description": "Use checksum validation in RX (receiving) direction",
"default": True,
"format": "checkbox",
"propertyOrder": 1.5,
},
"txcsum": {
"type": "boolean",
"title": "TX checksum validation",
"description": "Use checksum validation in TX (transmission) direction",
"default": True,
"format": "checkbox",
"propertyOrder": 1.6,
},
"mtu": {"type": "integer", "default": 1280},
"ttl": {
"type": "integer",
"title": "TTL",
"description": "TTL of the encapsulation packets",
"default": 64,
"propertyOrder": 3,
},
}
},
{"$ref": "#/definitions/interface_settings"},
],
},
"base_radio_settings": {
"properties": {
"driver": {
Expand Down Expand Up @@ -265,6 +334,7 @@
"oneOf": [
{"$ref": "#/definitions/dialup_interface"},
{"$ref": "#/definitions/modemmanager_interface"},
{"$ref": "#/definitions/vxlan_interface"},
]
}
},
Expand Down
1 change: 1 addition & 0 deletions netjsonconfig/backends/wireguard/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,4 +94,5 @@
}

schema = deepcopy(base_wireguard_schema)
schema['required'] = ['wireguard']
schema['properties']['files'] = default_schema['properties']['files']
122 changes: 122 additions & 0 deletions tests/openwrt/test_vxlan.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import unittest

from netjsonconfig import OpenWrt
from netjsonconfig.utils import _TabsMixin


class TestVxlan(unittest.TestCase, _TabsMixin):
maxDiff = None

def test_render_vxlan(self):
o = OpenWrt(
{
"interfaces": [
{
"name": "vxlan1",
"type": "vxlan",
"vtep": "10.0.0.1",
"port": 4789,
"vni": 1,
"tunlink": "wg0",
"rxcsum": True,
"txcsum": True,
"mtu": 1280,
"ttl": 64,
}
]
}
)
expected = self._tabs(
"""package network
config interface 'vxlan1'
option ifname 'vxlan1'
option mtu '1280'
option peeraddr '10.0.0.1'
option port '4789'
option proto 'vxlan'
option rxcsum '1'
option ttl '64'
option tunlink 'wg0'
option txcsum '1'
option vid '1'
"""
)
self.assertEqual(o.render(), expected)

def test_parse_vxlan(self):
native = self._tabs(
"""package network
config interface 'vxlan1'
option ifname 'vxlan1'
option mtu '1280'
option peeraddr '10.0.0.1'
option port '4789'
option proto 'vxlan'
option rxcsum '1'
option ttl '64'
option tunlink 'wg0'
option txcsum '1'
option vid '1'
"""
)
expected = {
"interfaces": [
{
"name": "vxlan1",
"type": "vxlan",
"vtep": "10.0.0.1",
"port": 4789,
"vni": 1,
"tunlink": "wg0",
"rxcsum": True,
"txcsum": True,
"mtu": 1280,
"ttl": 64,
}
]
}
o = OpenWrt(native=native)
self.assertEqual(o.config, expected)

def test_render_vxlan_with_variables(self):
o = OpenWrt(
{
"interfaces": [
{
"type": "vxlan",
"name": "vxlan2",
"vtep": "{{ vtep_e9081f8d67c8470d850ceb9c33bd0314 }}",
"port": 4789,
"vni": "{{ vni_e9081f8d67c8470d850ceb9c33bd0314 }}",
"tunlink": "wg0",
"rxcsum": False,
"txcsum": False,
"mtu": 1280,
"ttl": 64,
}
]
},
context={
"vtep_e9081f8d67c8470d850ceb9c33bd0314": "10.0.0.2",
"vni_e9081f8d67c8470d850ceb9c33bd0314": "2",
},
)
expected = self._tabs(
"""package network
config interface 'vxlan2'
option ifname 'vxlan2'
option mtu '1280'
option peeraddr '10.0.0.2'
option port '4789'
option proto 'vxlan'
option rxcsum '0'
option ttl '64'
option tunlink 'wg0'
option txcsum '0'
option vid '2'
"""
)
self.assertEqual(o.render(), expected)
6 changes: 6 additions & 0 deletions tests/wireguard/test_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import unittest

from netjsonconfig import Wireguard
from netjsonconfig.exceptions import ValidationError


class TestBackend(unittest.TestCase):
Expand All @@ -11,6 +12,11 @@ class TestBackend(unittest.TestCase):

maxDiff = None

def test_test_schema(self):
with self.assertRaises(ValidationError) as context_manager:
Wireguard({}).validate()
self.assertIn("'wireguard' is a required property", str(context_manager.exception))

def test_confs(self):
c = Wireguard(
{
Expand Down

0 comments on commit d62ee4d

Please sign in to comment.