vlan: add support to modify VLAN ID
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. Ref: https://bugzilla.redhat.com/1722352 Signed-off-by: Fernando Fernandez Mancera <ffmancera@riseup.net>
This commit is contained in:
parent
75ecf57ac3
commit
a6734598ae
@ -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 VlanIface(BaseIface):
|
||||
def __init__(self, info, save_to_disk=True):
|
||||
super().__init__(info, save_to_disk)
|
||||
self._vlan_id_changed = False
|
||||
|
||||
@property
|
||||
def parent(self):
|
||||
return self._vlan_config.get(VLAN.BASE_IFACE)
|
||||
@ -36,6 +40,14 @@ class VlanIface(BaseIface):
|
||||
def _vlan_config(self):
|
||||
return self.raw.get(VLAN.CONFIG_SUBTREE, {})
|
||||
|
||||
@property
|
||||
def vlan_id(self):
|
||||
return self._vlan_config.get(VLAN.ID)
|
||||
|
||||
@property
|
||||
def is_vlan_id_changed(self):
|
||||
return self._vlan_id_changed
|
||||
|
||||
@property
|
||||
def is_virtual(self):
|
||||
return True
|
||||
@ -56,3 +68,13 @@ class VlanIface(BaseIface):
|
||||
f"VLAN tunnel {self.name} has missing mandatory "
|
||||
f"property: {prop}"
|
||||
)
|
||||
|
||||
def _mark_vlan_id_changed(self, ifaces):
|
||||
if self.is_up:
|
||||
cur_iface = ifaces.get_cur_iface(self.name, self.type)
|
||||
if cur_iface and self.vlan_id != cur_iface.vlan_id:
|
||||
self._vlan_id_changed = True
|
||||
|
||||
def gen_metadata(self, ifaces):
|
||||
self._mark_vlan_id_changed(ifaces)
|
||||
super().gen_metadata(ifaces)
|
||||
|
@ -243,6 +243,16 @@ 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
|
||||
):
|
||||
# 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.
|
||||
self._add_action(NmProfile.ACTION_DEACTIVATE_FIRST)
|
||||
|
||||
if (
|
||||
self._iface.is_down
|
||||
and self._nm_dev
|
||||
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2018-2019 Red Hat, Inc.
|
||||
# Copyright (c) 2018-2021 Red Hat, Inc.
|
||||
#
|
||||
# This file is part of nmstate
|
||||
#
|
||||
@ -206,6 +206,25 @@ def test_add_vlan_with_mismatching_name_and_id(eth1_up):
|
||||
assertlib.assert_state(desired_state)
|
||||
|
||||
|
||||
@pytest.mark.tier1
|
||||
@pytest.mark.xfail(
|
||||
nm_major_minor_version() < 1.31,
|
||||
reason="Ref: https://bugzilla.redhat.com/1907960",
|
||||
raises=NmstateVerificationError,
|
||||
strict=True,
|
||||
)
|
||||
def test_add_vlan_and_modify_vlan_id(eth1_up):
|
||||
with vlan_interface(
|
||||
VLAN_IFNAME, 101, eth1_up[Interface.KEY][0][Interface.NAME]
|
||||
) as desired_state:
|
||||
assertlib.assert_state(desired_state)
|
||||
desired_state[Interface.KEY][0][VLAN.CONFIG_SUBTREE][VLAN.ID] = 200
|
||||
libnmstate.apply(desired_state)
|
||||
assertlib.assert_state(desired_state)
|
||||
|
||||
assertlib.assert_absent(VLAN_IFNAME)
|
||||
|
||||
|
||||
@contextmanager
|
||||
def two_vlans_on_eth1():
|
||||
desired_state = create_two_vlans_state()
|
||||
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2020 Red Hat, Inc.
|
||||
# Copyright (c) 2020-2021 Red Hat, Inc.
|
||||
#
|
||||
# This file is part of nmstate
|
||||
#
|
||||
@ -31,6 +31,7 @@ from libnmstate.ifaces.vlan import VlanIface
|
||||
from ..testlib.ifacelib import gen_foo_iface_info
|
||||
|
||||
BASE_IFACE_NAME = "base1"
|
||||
VLAN_ID101 = 101
|
||||
|
||||
|
||||
class TestVlanIface:
|
||||
@ -44,7 +45,7 @@ class TestVlanIface:
|
||||
def _gen_iface_info(self):
|
||||
iface_info = gen_foo_iface_info(iface_type=InterfaceType.VLAN)
|
||||
iface_info[VLAN.CONFIG_SUBTREE] = {
|
||||
VLAN.ID: 101,
|
||||
VLAN.ID: VLAN_ID101,
|
||||
VLAN.BASE_IFACE: BASE_IFACE_NAME,
|
||||
}
|
||||
return iface_info
|
||||
@ -61,6 +62,18 @@ class TestVlanIface:
|
||||
def test_can_have_ip_as_port(self):
|
||||
assert not VlanIface(self._gen_iface_info()).can_have_ip_as_port
|
||||
|
||||
def test_vlan_id(self):
|
||||
assert VlanIface(self._gen_iface_info()).vlan_id == 101
|
||||
|
||||
def test_is_vlan_id_changed(self):
|
||||
vlan101 = VlanIface(self._gen_iface_info())
|
||||
assert not vlan101.is_vlan_id_changed
|
||||
|
||||
vlan200_info = self._gen_iface_info()
|
||||
vlan200_info[VLAN.CONFIG_SUBTREE][VLAN.ID] = 200
|
||||
vlan101.gen_metadata(Ifaces([], [vlan200_info]))
|
||||
assert vlan101.is_vlan_id_changed
|
||||
|
||||
def test_validate_base_iface_missing(self):
|
||||
iface_info = self._gen_iface_info()
|
||||
iface_info[VLAN.CONFIG_SUBTREE].pop(VLAN.BASE_IFACE)
|
||||
|
Loading…
x
Reference in New Issue
Block a user