vxlan: add support to modify the VXLAN ID
NetworkManager does not allow to modify the vxlan id of an existing VXLAN. In order to support it, Nmstate is removing the interface and creating it again. Ref: https://bugzilla.redhat.com/1722352 Signed-off-by: Fernando Fernandez Mancera <ffmancera@riseup.net>
This commit is contained in:
parent
a6734598ae
commit
4831c2d456
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2020 Red Hat, Inc.
|
||||
# Copyright (c) 2020-2021 Red Hat, Inc.
|
||||
#
|
||||
# This file is part of nmstate
|
||||
#
|
||||
@ -24,6 +24,10 @@ from .base_iface import BaseIface
|
||||
|
||||
|
||||
class VxlanIface(BaseIface):
|
||||
def __init__(self, info, save_to_disk=True):
|
||||
super().__init__(info, save_to_disk)
|
||||
self._vxlan_id_changed = False
|
||||
|
||||
@property
|
||||
def parent(self):
|
||||
return self._vxlan_config.get(VXLAN.BASE_IFACE)
|
||||
@ -36,6 +40,14 @@ class VxlanIface(BaseIface):
|
||||
def _vxlan_config(self):
|
||||
return self.raw.get(VXLAN.CONFIG_SUBTREE, {})
|
||||
|
||||
@property
|
||||
def vxlan_id(self):
|
||||
return self._vxlan_config.get(VXLAN.ID)
|
||||
|
||||
@property
|
||||
def is_vxlan_id_changed(self):
|
||||
return self._vxlan_id_changed
|
||||
|
||||
@property
|
||||
def is_virtual(self):
|
||||
return True
|
||||
@ -44,6 +56,16 @@ class VxlanIface(BaseIface):
|
||||
def can_have_ip_as_port(self):
|
||||
return False
|
||||
|
||||
def _mark_vxlan_id_changed(self, ifaces):
|
||||
if self.is_up:
|
||||
cur_iface = ifaces.get_cur_iface(self.name, self.type)
|
||||
if cur_iface and self.vxlan_id != cur_iface.vxlan_id:
|
||||
self._vxlan_id_changed = True
|
||||
|
||||
def gen_metadata(self, ifaces):
|
||||
self._mark_vxlan_id_changed(ifaces)
|
||||
super().gen_metadata(ifaces)
|
||||
|
||||
def pre_edit_validation_and_cleanup(self):
|
||||
if self.is_up:
|
||||
self._validate_mandatory_properties()
|
||||
|
@ -243,14 +243,19 @@ class NmProfile:
|
||||
# it again.
|
||||
self._add_action(NmProfile.ACTION_DEACTIVATE_FIRST)
|
||||
|
||||
if (
|
||||
self._iface.is_up
|
||||
and self._iface.type == InterfaceType.VLAN
|
||||
and self._iface.is_vlan_id_changed
|
||||
if self._iface.is_up and (
|
||||
(
|
||||
self._iface.type == InterfaceType.VLAN
|
||||
and self._iface.is_vlan_id_changed
|
||||
)
|
||||
or (
|
||||
self._iface.type == InterfaceType.VXLAN
|
||||
and self._iface.is_vxlan_id_changed
|
||||
)
|
||||
):
|
||||
# NetworkManager does not allow to modify the vlan id of an
|
||||
# existing VLAN. In order to support it, Nmstate is removing the
|
||||
# interface and creating it again.
|
||||
# NetworkManager does not allow to modify the vlan/vxlan id of an
|
||||
# existing VLAN/VXLAN. In order to support it, Nmstate is removing
|
||||
# the interface and creating it again.
|
||||
self._add_action(NmProfile.ACTION_DEACTIVATE_FIRST)
|
||||
|
||||
if (
|
||||
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2019-2020 Red Hat, Inc.
|
||||
# Copyright (c) 2019-2021 Red Hat, Inc.
|
||||
#
|
||||
# This file is part of nmstate
|
||||
#
|
||||
@ -25,6 +25,7 @@ import libnmstate
|
||||
|
||||
from libnmstate.error import NmstateVerificationError
|
||||
from libnmstate.schema import Interface
|
||||
from libnmstate.schema import VXLAN
|
||||
|
||||
from .testlib import assertlib
|
||||
from .testlib.bondlib import bond_interface
|
||||
@ -139,3 +140,18 @@ def test_show_vxlan_with_no_remote(eth1_up):
|
||||
finally:
|
||||
libnmstate.apply(vxlans_absent([vxlan]))
|
||||
assertlib.assert_absent(vxlan.name)
|
||||
|
||||
|
||||
@pytest.mark.tier1
|
||||
def test_add_vxlan_and_modify_vxlan_id(eth1_up):
|
||||
ifname = eth1_up[Interface.KEY][0][Interface.NAME]
|
||||
with vxlan_interfaces(
|
||||
VxlanState(id=VXLAN1_ID, base_if=ifname, remote="192.168.100.1")
|
||||
) as desired_state:
|
||||
assertlib.assert_state(desired_state)
|
||||
desired_state[Interface.KEY][0][VXLAN.CONFIG_SUBTREE][VXLAN.ID] = 200
|
||||
libnmstate.apply(desired_state)
|
||||
assertlib.assert_state(desired_state)
|
||||
|
||||
vxlan1_ifname = desired_state[Interface.KEY][0][Interface.NAME]
|
||||
assertlib.assert_absent(vxlan1_ifname)
|
||||
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2020 Red Hat, Inc.
|
||||
# Copyright (c) 2020-2021 Red Hat, Inc.
|
||||
#
|
||||
# This file is part of nmstate
|
||||
#
|
||||
@ -32,6 +32,7 @@ from ..testlib.constants import IPV4_ADDRESS1
|
||||
from ..testlib.ifacelib import gen_foo_iface_info
|
||||
|
||||
BASE_IFACE_NAME = "base1"
|
||||
VXLAN_ID101 = 101
|
||||
|
||||
|
||||
class TestVxlanIface:
|
||||
@ -45,7 +46,7 @@ class TestVxlanIface:
|
||||
def _gen_iface_info(self):
|
||||
iface_info = gen_foo_iface_info(iface_type=InterfaceType.VXLAN)
|
||||
iface_info[VXLAN.CONFIG_SUBTREE] = {
|
||||
VXLAN.ID: 101,
|
||||
VXLAN.ID: VXLAN_ID101,
|
||||
VXLAN.BASE_IFACE: BASE_IFACE_NAME,
|
||||
VXLAN.REMOTE: IPV4_ADDRESS1,
|
||||
}
|
||||
@ -63,6 +64,18 @@ class TestVxlanIface:
|
||||
def test_can_have_ip_as_port(self):
|
||||
assert not VxlanIface(self._gen_iface_info()).can_have_ip_as_port
|
||||
|
||||
def test_vxlan_id(self):
|
||||
assert VxlanIface(self._gen_iface_info()).vxlan_id == VXLAN_ID101
|
||||
|
||||
def test_is_vxlan_id_changed(self):
|
||||
vxlan101 = VxlanIface(self._gen_iface_info())
|
||||
assert not vxlan101.is_vxlan_id_changed
|
||||
|
||||
vxlan200_info = self._gen_iface_info()
|
||||
vxlan200_info[VXLAN.CONFIG_SUBTREE][VXLAN.ID] = 200
|
||||
vxlan101.gen_metadata(Ifaces([], [vxlan200_info]))
|
||||
assert vxlan101.is_vxlan_id_changed
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"required_field", [VXLAN.ID, VXLAN.REMOTE, VXLAN.BASE_IFACE]
|
||||
)
|
||||
|
Loading…
x
Reference in New Issue
Block a user