def veth_pair(prefix='veth_', max_length=15): """ Yield a pair of veth devices. This assumes root privileges (currently required by all tests anyway). Both sides of the pair have a pseudo-random suffix (e.g. veth_m6Lz7uMK9c). """ left_side = random_iface_name(prefix, max_length) right_side = random_iface_name(prefix, max_length) try: linkAdd(left_side, linkType='veth', args=('peer', 'name', right_side)) if nmstate.is_nmstate_backend(): cmd.exec_sync(['nmcli', 'dev', 'set', left_side, 'managed', 'yes']) cmd.exec_sync( ['nmcli', 'dev', 'set', right_side, 'managed', 'yes']) except IPRoute2Error as e: pytest.skip('Failed to create a veth pair: %s', e) try: yield left_side, right_side finally: # the peer device is removed by the kernel linkDel(left_side) if nmstate.is_nmstate_backend(): cmd.exec_sync(['nmcli', 'con', 'del', left_side]) cmd.exec_sync(['nmcli', 'con', 'del', right_side])
def _get(vdsmnets=None): """ Generate a networking report for all devices. In case vdsmnets is provided, it is used in the report instead of retrieving data from the running config. :return: Dict of networking devices with all their details. """ ipaddrs = getIpAddrs() routes = get_routes() devices_info = _devices_report(ipaddrs, routes) nets_info = _networks_report(vdsmnets, routes, ipaddrs, devices_info) add_qos_info_to_devices(nets_info, devices_info) flat_devs_info = _get_flat_devs_info(devices_info) devices = _get_dev_names(nets_info, flat_devs_info) extra_info = {} if nmstate.is_nmstate_backend(): extra_info.update(_get_devices_info_from_nmstate(devices)) else: extra_info.update(dhclient.dhcp_info(devices)) _update_caps_info(nets_info, flat_devs_info, extra_info) networking_report = {'networks': nets_info} networking_report.update(devices_info) if nmstate.is_nmstate_backend(): networking_report['nameservers'] = nmstate.show_nameservers() else: networking_report['nameservers'] = dns.get_host_nameservers() networking_report['supportsIPv6'] = ipv6_supported() return networking_report
def stop_unprivileged_network_components(): if nmstate.is_nmstate_backend(): dhcp_monitor.Monitor.instance().stop() else: dhclient_monitor.stop() bond_monitor.stop()
def _assert_kernel_vs_running_config(self): """ This is a special test, that checks setup integrity through non vdsm api data. The networking configuration relies on a semi-persistent running configuration files, describing the requested configuration. This configuration is checked against the actual caps report. """ running_config = kernelconfig.normalize(self.running_config) running_config = running_config.as_unicode() netinfo = _normalize_caps(self.netinfo) kernel_config = kernelconfig.KernelConfig(netinfo) _extend_with_bridge_opts(kernel_config, running_config) kernel_config = kernel_config.as_unicode() _normalize_bonds((kernel_config, running_config)) self._assert_inclusive_nameservers(kernel_config, running_config) # Do not use KernelConfig.__eq__ to get a better exception if something # breaks. assert running_config['networks'] == kernel_config['networks'] if nmstate.is_nmstate_backend(): self._assert_inclusive_bond_options(kernel_config, running_config) assert running_config['bonds'] == kernel_config['bonds']
def init_unprivileged_network_components(cif, net_api): if nmstate.is_nmstate_backend(): dhcp_monitor.initialize_monitor(cif, net_api) else: _init_sourceroute(net_api) _register_notifications(cif) dhclient_monitor.start()
def __call__(self, networks, bonds, options): self.setup_networks = networks self.setup_bonds = bonds status, msg = self.vdsm_proxy.setupNetworks(networks, bonds, options) if status != SUCCESS: self._update_configs() raise SetupNetworksError(status, msg) if nmstate.is_nmstate_backend(): if self._is_dynamic(): _wait_for_dhcp_response(10) self.vdsm_proxy.refreshNetworkCapabilities() else: if self._is_dynamic_ipv4(): self._wait_for_dhcpv4_response(10) self.vdsm_proxy.refreshNetworkCapabilities() try: self._update_configs() self._assert_configs() except Exception: # Ignore cleanup failure, make sure to re-raise original exception. self._cleanup() raise return self
def __call__(self, networks, bonds, options): self.setup_networks = networks self.setup_bonds = bonds status, msg = self.vdsm_proxy.setupNetworks(networks, bonds, options) if status != SUCCESS: self._update_configs() raise SetupNetworksError(status, msg) if self._is_dynamic_ipv4(): self._wait_for_dhcp_response(10) self.vdsm_proxy.refreshNetworkCapabilities() # FIXME This is just workaround, eventually we need to fix this by # adding proper support for IPv6 dhcp monitoring # (https://projects.engineering.redhat.com/browse/RHV-17589) if self._is_dynamic_ipv6() and nmstate.is_nmstate_backend(): time.sleep(10) self.vdsm_proxy.refreshNetworkCapabilities() try: self._update_configs() self._assert_configs() except Exception: # Ignore cleanup failure, make sure to re-raise original exception. self._cleanup() raise return self
def test_mtu_default_value_of_base_nic_after_all_nets_are_removed( self, switch, bridged, bonded): if switch == 'legacy' and bonded and not nmstate.is_nmstate_backend(): pytest.xfail('BZ#1633528') with dummy_devices(1) as (nic, ): NETWORK1_ATTRS = { 'bridged': bridged, 'vlan': VLAN1, 'mtu': MTU_1600, 'switch': switch, } NETBASE = {NETWORK1_NAME: NETWORK1_ATTRS} default_mtu = {'mtu': DEFAULT_MTU} if bonded: NETWORK1_ATTRS['bonding'] = BOND_NAME BONDBASE = {BOND_NAME: {'nics': [nic], 'switch': switch}} else: NETWORK1_ATTRS['nic'] = nic BONDBASE = {} with adapter.setupNetworks(NETBASE, BONDBASE, nftestlib.NOCHK): adapter.setupNetworks({NETWORK1_NAME: { 'remove': True }}, {}, nftestlib.NOCHK) adapter.assertLinkMtu(nic, default_mtu) if bonded: adapter.assertLinkMtu(BOND_NAME, default_mtu)
def test_move_net_between_bond_and_nic_with_non_default_mtu( self, switch, bridged, bonded, vlan): if switch == 'legacy' and not nmstate.is_nmstate_backend(): pytest.skip('Not supported with ifcfg BZ#1790761') with dummy_devices(2) as (nic1, nic2): net_attrs = {'bridged': bridged, 'mtu': MTU_2000, 'switch': switch} BONDBASE = {BOND_NAME: {'nics': [nic1], 'switch': switch}} default_mtu = {'mtu': DEFAULT_MTU} if bonded: net_attrs['bonding'] = BOND_NAME else: net_attrs['nic'] = nic2 if vlan: net_attrs['vlan'] = VLAN1 with adapter.setupNetworks({NETWORK_NAME: net_attrs}, BONDBASE, nftestlib.NOCHK): if bonded: net_attrs.pop('bonding') net_attrs['nic'] = nic2 else: net_attrs.pop('nic') net_attrs['bonding'] = BOND_NAME adapter.setupNetworks({NETWORK_NAME: net_attrs}, {}, nftestlib.NOCHK) adapter.assertNetwork(NETWORK_NAME, net_attrs) adapter.assertLinkMtu(BOND_NAME, default_mtu if bonded else net_attrs) adapter.assertLinkMtu(nic1, default_mtu if bonded else net_attrs) adapter.assertLinkMtu(nic2, net_attrs if bonded else default_mtu)
def setup(networks, bondings, options, net_info, in_rollback): if nmstate.is_nmstate_backend(): _setup_nmstate(networks, bondings, options, in_rollback) else: _setup(networks, bondings, options, in_rollback, net_info) if options.get('commitOnSuccess'): persist()
def init_unpriviliged_dhclient_monitor_ctx(event_sink, net_api): if nmstate.is_nmstate_backend(): ctx = dhcp_monitor.initialize_monitor_ctx(event_sink, net_api) else: _init_sourceroute(net_api) _register_notifications(event_sink) ctx = dhclient_monitor_ctx() with ctx: yield
def _canonicalize_nameservers(data): if 'nameservers' not in data: # Nameservers are relevant only for the default route network (usually # the management network) if data['defaultRoute'] and data['bootproto'] != 'dhcp': data['nameservers'] = dns.get_host_nameservers() # FIXME https://bugzilla.redhat.com/1816043 if nmstate.is_nmstate_backend(): data['nameservers'] = data['nameservers'][:2] else: data['nameservers'] = []
def create(self): try: linkAdd(self.devName, linkType='dummy') if nmstate.is_nmstate_backend(): cmd.exec_sync( ['nmcli', 'dev', 'set', self.devName, 'managed', 'yes']) except IPRoute2Error as e: pytest.skip('Failed to create a dummy interface %s: %s' % (self.devName, e)) else: return self.devName
def remove(self): """ Remove the dummy interface. This assumes root privileges. """ try: linkDel(self.devName) except IPRoute2Error as e: pytest.skip("Unable to delete the dummy interface %s: %s" % (self.devName, e)) finally: if nmstate.is_nmstate_backend(): cmd.exec_sync(['nmcli', 'con', 'del', self.devName])
def create_tap(): devname = '_tap99' rc, _, err = exec_sync(['ip', 'tuntap', 'add', devname, 'mode', 'tap']) if rc != 0: pytest.fail('Unable to create tap device. err: {}'.format(err)) try: iface(devname).up() yield devname finally: exec_sync(['ip', 'tuntap', 'del', devname, 'mode', 'tap']) if nmstate.is_nmstate_backend(): exec_sync(['nmcli', 'con', 'del', devname])
def test_restore_missing_dynamic_ipv4_network(self, adapter, switch, bridged): if switch == 'ovs': # With OVS, the restoration creates the network without an IP. pytest.xfail('Inconsistent behaviour with OVS') elif bridged and not nmstate.is_nmstate_backend(): pytest.xfail('https://bugzilla.redhat.com/1790392') with veth_pair() as (server, client): linkSet(server, ['up']) linkSet(client, ['up']) SETUP_NET = { NETWORK_NAME: { 'nic': client, 'bridged': bridged, 'bootproto': 'dhcp', 'switch': switch, } } REMOVE_NET = {NETWORK_NAME: {'remove': True}} with adapter.reset_persistent_config(): with adapter.setupNetworks(SETUP_NET, {}, NOCHK): adapter.setSafeNetworkConfig() adapter.setupNetworks(REMOVE_NET, {}, NOCHK) adapter.assertNoNetworkExists(NETWORK_NAME) adapter.restore_nets() if nmstate.is_nmstate_backend(): # nmstate successfully restores a network without # a dhcp server in place. adapter.assertNetworkExists(NETWORK_NAME) else: # Attempt to restore network without dhcp server. # As expected, restoration occurs with # blockingdhcp=True and therefore it should fail the # setup. adapter.assertNoNetworkExists(NETWORK_NAME)
def validate(networks, bondings, net_info): legacy_nets, ovs_nets, legacy_bonds, ovs_bonds = _split_switch_type( networks, bondings, net_info) use_legacy_switch = legacy_nets or legacy_bonds use_ovs_switch = ovs_nets or ovs_bonds if (not nmstate.is_nmstate_backend() and use_legacy_switch and use_ovs_switch): raise ne.ConfigNetworkError( ne.ERR_BAD_PARAMS, 'Mixing of legacy and OVS networks is not supported inside one ' 'setupNetworks() call.', ) validator.validate_network_setup(networks, bondings, net_info) if use_legacy_switch: legacy_switch.validate_network_setup(legacy_nets)
def test_base_iface_mtu_is_preserved_when_not_all_nets_on_top_are_deleted( self, switch, bridged, bonded): if switch == 'legacy' and bonded and not nmstate.is_nmstate_backend(): pytest.xfail('BZ#1633528') common_net_mtu = MTU_1600 with dummy_devices(1) as (nic, ): vlaned_network = { 'bridged': bridged, 'vlan': VLAN1, 'mtu': common_net_mtu, 'switch': switch, } non_vlaned_network = { 'bridged': bridged, 'mtu': common_net_mtu, 'switch': switch, } all_networks = { NETWORK1_NAME: vlaned_network, NETWORK2_NAME: non_vlaned_network, } mtu_to_keep = {'mtu': common_net_mtu} if bonded: vlaned_network['bonding'] = BOND_NAME non_vlaned_network['bonding'] = BOND_NAME bonds = {BOND_NAME: {'nics': [nic], 'switch': switch}} else: vlaned_network['nic'] = nic non_vlaned_network['nic'] = nic bonds = {} with adapter.setupNetworks(all_networks, bonds, nftestlib.NOCHK): adapter.setupNetworks({NETWORK1_NAME: { 'remove': True }}, {}, nftestlib.NOCHK) adapter.assertLinkMtu(nic, mtu_to_keep) if bonded: adapter.assertLinkMtu(BOND_NAME, mtu_to_keep)
def test_move_net_from_one_iface_to_another_with_non_default_mtu( self, switch, bridged, bonded, vlan): if switch == 'legacy' and bonded and not nmstate.is_nmstate_backend(): pytest.skip('Not supported with ifcfg BZ#1790761') with dummy_devices(2) as (nic1, nic2): net_attrs = {'bridged': bridged, 'mtu': MTU_2000, 'switch': switch} default_mtu = {'mtu': DEFAULT_MTU} if bonded: net_attrs['bonding'] = BOND_NAME BONDBASE = { BOND_NAME: { 'nics': [nic1], 'switch': switch }, BOND_NAME2: { 'nics': [nic2], 'switch': switch }, } else: net_attrs['nic'] = nic1 BONDBASE = {} if vlan: net_attrs['vlan'] = VLAN1 with adapter.setupNetworks({NETWORK_NAME: net_attrs}, BONDBASE, nftestlib.NOCHK): if bonded: net_attrs['bonding'] = BOND_NAME2 else: net_attrs['nic'] = nic2 adapter.setupNetworks({NETWORK_NAME: net_attrs}, {}, nftestlib.NOCHK) adapter.assertNetwork(NETWORK_NAME, net_attrs) if bonded: adapter.assertLinkMtu(BOND_NAME, default_mtu) adapter.assertLinkMtu(BOND_NAME2, net_attrs) adapter.assertLinkMtu(nic1, default_mtu) adapter.assertLinkMtu(nic2, net_attrs)
class TestBondBasic(object): def test_add_bond_with_two_nics(self, switch): with dummy_devices(2) as (nic1, nic2): BONDCREATE = {BOND_NAME: {'nics': [nic1, nic2], 'switch': switch}} with adapter.setupNetworks({}, BONDCREATE, NOCHK): adapter.assertBond(BOND_NAME, BONDCREATE[BOND_NAME]) def test_add_bond_with_two_nics_and_options(self, switch): with dummy_devices(2) as (nic1, nic2): BONDCREATE = { BOND_NAME: { 'nics': [nic1, nic2], 'options': 'mode=3 miimon=150', 'switch': switch, } } with adapter.setupNetworks({}, BONDCREATE, NOCHK): adapter.assertBond(BOND_NAME, BONDCREATE[BOND_NAME]) def test_remove_bond(self, switch): with dummy_devices(2) as (nic1, nic2): BONDCREATE = {BOND_NAME: {'nics': [nic1, nic2], 'switch': switch}} BONDREMOVE = {BOND_NAME: {'remove': True}} with adapter.setupNetworks({}, BONDCREATE, NOCHK): adapter.setupNetworks({}, BONDREMOVE, NOCHK) adapter.assertNoBond(BOND_NAME) @pytest.mark.xfail( condition=nmstate.is_nmstate_backend(), reason='Links stability not supported by nmstate/NM', raises=nftestlib.UnexpectedLinkStateChangeError, strict=True, ) def test_change_bond_slaves(self, switch): with dummy_devices(3) as (nic1, nic2, nic3): BONDCREATE = {BOND_NAME: {'nics': [nic1, nic2], 'switch': switch}} BONDEDIT = {BOND_NAME: {'nics': [nic1, nic3], 'switch': switch}} with adapter.setupNetworks({}, BONDCREATE, NOCHK): with nftestlib.monitor_stable_link_state(BOND_NAME): adapter.setupNetworks({}, BONDEDIT, NOCHK) adapter.assertBond(BOND_NAME, BONDEDIT[BOND_NAME]) def test_swap_slaves_between_bonds(self, switch): BOND1 = BOND_NAME + '1' BOND2 = BOND_NAME + '2' with dummy_devices(4) as (nic1, nic2, nic3, nic4): BONDCREATE = { BOND1: {'nics': [nic1, nic2], 'switch': switch}, BOND2: {'nics': [nic3, nic4], 'switch': switch}, } BONDEDIT = { BOND1: {'nics': [nic1, nic3], 'switch': switch}, BOND2: {'nics': [nic2, nic4], 'switch': switch}, } with adapter.setupNetworks({}, BONDCREATE, NOCHK): adapter.setupNetworks({}, BONDEDIT, NOCHK) adapter.assertBond(BOND1, BONDEDIT[BOND1]) adapter.assertBond(BOND2, BONDEDIT[BOND2]) def test_resize_bond(self, switch): with dummy_devices(4) as (nic1, nic2, nic3, nic4): bond = {BOND_NAME: {'nics': [nic1, nic2], 'switch': switch}} with adapter.setupNetworks({}, bond, NOCHK): bond[BOND_NAME]['nics'] += [nic3, nic4] adapter.setupNetworks({}, bond, NOCHK) adapter.assertBond(BOND_NAME, bond[BOND_NAME]) bond[BOND_NAME]['nics'].remove(nic4) adapter.setupNetworks({}, bond, NOCHK) adapter.assertBond(BOND_NAME, bond[BOND_NAME]) def test_add_bond_with_bad_name_fails(self, switch): INVALID_BOND_NAMES = ('bond', 'bond bad', 'jamesbond007') with dummy_devices(2) as (nic1, nic2): for bond_name in INVALID_BOND_NAMES: BONDCREATE = { bond_name: {'nics': [nic1, nic2], 'switch': switch} } with pytest.raises(SetupNetworksError) as cm: with adapter.setupNetworks({}, BONDCREATE, NOCHK): pass assert cm.value.status == ne.ERR_BAD_BONDING def test_add_bond_with_no_nics_fails(self, switch): BONDCREATE = {BOND_NAME: {'nics': [], 'switch': switch}} with pytest.raises(SetupNetworksError) as err: with adapter.setupNetworks({}, BONDCREATE, NOCHK): pass assert err.value.status == ne.ERR_BAD_PARAMS def test_add_bond_with_enforced_mac_address(self, switch): if switch == 'ovs': pytest.xfail( 'Bond mac enforcement is currently not implemented for ovs' ) HWADDRESS = 'ce:0c:46:59:c9:d1' with dummy_devices(2) as (nic1, nic2): BONDCREATE = { BOND_NAME: { 'nics': [nic1, nic2], 'hwaddr': HWADDRESS, 'switch': switch, } } with adapter.setupNetworks({}, BONDCREATE, NOCHK): adapter.assertBond(BOND_NAME, BONDCREATE[BOND_NAME]) def test_bond_slaves_order_does_not_affect_the_mac_address(self, switch): with dummy_devices(2) as (nic1, nic2): bond1 = {BOND_NAME: {'nics': [nic1, nic2], 'switch': switch}} bond2 = {BOND_NAME: {'nics': [nic2, nic1], 'switch': switch}} with adapter.setupNetworks({}, bond1, NOCHK): bond1_hwaddr = adapter.netinfo.bondings[BOND_NAME]['hwaddr'] with adapter.setupNetworks({}, bond2, NOCHK): bond2_hwaddr = adapter.netinfo.bondings[BOND_NAME]['hwaddr'] assert bond1_hwaddr == bond2_hwaddr
def delDevice(self): self._down() linkDel(self.devName) if nmstate.is_nmstate_backend(): cmd.exec_sync(['nmcli', 'con', 'del', self.devName])
def dhcp_client_run(iface, family=4): dhcp_client = (dhcp_nm_client if nmstate.is_nmstate_backend() else dhclient_run) with dhcp_client(iface, family): yield
def is_nmstate_backend(): return nmstate.is_nmstate_backend()
def _notify(**kwargs): if not nmstate.is_nmstate_backend(): # Delay the notification in order to allow the ifup job to finish time.sleep(5) cif.notify('|net|host_conn|no_id')