def validate_net_configuration(net, attrs, bonds, running_bonds, kernel_nics): """Test if network meets logical Vdsm requiremets. Bridgeless networks are allowed in order to support Engine requirements. Checked by OVS: - only one vlan per tag """ nic = attrs.get('nic') bond = attrs.get('bonding') vlan = attrs.get('vlan') if vlan is None: if nic and nic not in kernel_nics: raise ne.ConfigNetworkError( ne.ERR_BAD_NIC, 'Nic %s does not exist' % nic) running_bond = bond in running_bonds bond2setup = bond in bonds and 'remove' not in bonds[bond] if bond and not running_bond and not bond2setup: raise ne.ConfigNetworkError( ne.ERR_BAD_BONDING, 'Bond %s does not exist' % bond) else: # We do not support ifaceless VLANs in Vdsm, because of legacy VLAN # device requires an iface to lie on. It wouldn't be a problem in OVS, # where we use tagged fake bridges instead of VLANs. However, ifaceless # VLANs are permited in order to keep feature parity. # TODO: This limitation could be dropped in the future. if not nic and not bond: raise ne.ConfigNetworkError( ne.ERR_BAD_VLAN, 'Vlan device requires a nic/bond')
def validate_static_ipv4_config(net_attrs): if 'ipaddr' in net_attrs: try: address = '{}/{}'.format(net_attrs['ipaddr'], net_attrs.get('netmask', '')) IPAddressData(address, device=None) if 'gateway' in net_attrs: IPAddressData(net_attrs['gateway'], device=None) except IPAddressDataError as e: six.reraise( ne.ConfigNetworkError, ne.ConfigNetworkError(ne.ERR_BAD_ADDR, str(e)), ) if net_attrs.get('bootproto') == 'dhcp': raise ne.ConfigNetworkError( ne.ERR_BAD_ADDR, 'mixing static ip configuration with ' 'dhcp is not allowed', ) else: if 'gateway' in net_attrs or 'netmask' in net_attrs: raise ne.ConfigNetworkError( ne.ERR_BAD_ADDR, 'gateway or netmask were given ' 'without ip address', )
def validate_southbound_devices_usages(nets, ni): kernel_config = KernelConfig(ni) for requested_net, net_info in six.viewitems(nets): if 'remove' in net_info: kernel_config.removeNetwork(requested_net) for requested_net, net_info in six.viewitems(nets): if 'remove' in net_info: continue kernel_config.setNetwork(requested_net, net_info) underlying_devices = [] for net_name, net_attrs in six.viewitems(kernel_config.networks): vlan = net_attrs.get('vlan') if 'bonding' in net_attrs: underlying_devices.append((net_attrs['bonding'], vlan)) elif 'nic' in net_attrs: underlying_devices.append((net_attrs['nic'], vlan)) else: if not net_attrs['bridged']: raise ne.ConfigNetworkError( ne.ERR_BAD_PARAMS, 'southbound device not specified for non-bridged ' 'network "{}"'.format(net_name)) if len(set(underlying_devices)) < len(underlying_devices): raise ne.ConfigNetworkError( ne.ERR_BAD_PARAMS, 'multiple networks/similar vlans cannot be' ' defined on a single underlying device. ' 'kernel networks: {}\nrequested networks: {}'.format( kernel_config.networks, nets))
def _validate_bond_addition(nics, kernel_nics): if nics is None or len(nics) < 2: raise ne.ConfigNetworkError(ne.ERR_BAD_BONDING, 'OVS bond requires at least 2 slaves') for nic in nics: if nic not in kernel_nics: raise ne.ConfigNetworkError(ne.ERR_BAD_NIC, 'Nic %s does not exist' % nic)
def _validate_bond_addition(nics, kernel_nics): for nic in nics: if nic not in kernel_nics: raise ne.ConfigNetworkError( ne.ERR_BAD_NIC, 'Nic %s does not exist' % nic) if dpdk.is_dpdk(nic): raise ne.ConfigNetworkError( ne.ERR_BAD_NIC, '%s is a dpdk device and not supported as a slave of bond' % nic)
def _validate_vlan_id(id): MAX_ID = 4094 try: vlan_id = int(id) except ValueError: raise ne.ConfigNetworkError( ne.ERR_BAD_VLAN, 'VLAN id must be a number between 0 and ' + MAX_ID) if not 0 <= vlan_id <= MAX_ID: raise ne.ConfigNetworkError( ne.ERR_BAD_VLAN, 'VLAN id out of range: %r, must be 0..%s' % (id, MAX_ID))
def validate_bond_configuration(bond, attrs, nets, running_nets, kernel_nics): if 'remove' in attrs: _validate_bond_removal(bond, nets, running_nets) elif 'nics' in attrs: _validate_bond_addition(attrs['nics'], kernel_nics) else: raise ne.ConfigNetworkError(ne.ERR_BAD_NIC, 'Missing nics attribute')
def validate_switch_type_change(nets, bonds, running_config): for requests in nets, bonds: for attrs in six.itervalues(requests): if 'remove' in attrs: raise ne.ConfigNetworkError( ne.ERR_BAD_PARAMS, 'Switch type change request cannot contain removals') if frozenset(running_config.networks) != frozenset(nets): raise ne.ConfigNetworkError( ne.ERR_BAD_PARAMS, 'All networks must be reconfigured on switch type change') if frozenset(running_config.bonds) != frozenset(bonds): raise ne.ConfigNetworkError( ne.ERR_BAD_PARAMS, 'All bondings must be reconfigured on switch type change')
def _validate_network_remove(self): net_attrs_set = set(self._attrs) - {'remove', 'custom'} if net_attrs_set: raise ne.ConfigNetworkError( ne.ERR_BAD_PARAMS, 'Cannot specify any attribute when removing (except custom)).', )
def _validate_nameservers_address(nameservers_addr): for addr in nameservers_addr: addr = _normalize_address(addr) try: IPAddressData(addr, device=None) except IPAddressDataError as e: raise ne.ConfigNetworkError(ne.ERR_BAD_ADDR, str(e))
def _validate_bond_removal(bond, nets, running_nets): for net in _nets_with_bond(running_nets, bond): to_be_removed = 'remove' in nets.get(net, {}) if not to_be_removed: raise ne.ConfigNetworkError( ne.ERR_USED_BOND, 'Cannot remove bonding %s: used by ' 'network %s' % (bond, net))
def _validate_bond_removal(bond, desired_nets, current_nets): current_nets_with_bond = { net for net, attrs in six.iteritems(current_nets) if attrs['southbound'] == bond } add_nets_with_bond = set() remove_nets_with_bond = set() for net, attrs in six.iteritems(desired_nets): if 'remove' in attrs: if net in current_nets_with_bond: remove_nets_with_bond.add(net) elif net in current_nets: if net in current_nets_with_bond: remove_nets_with_bond.add(net) if attrs.get('bonding') == bond: add_nets_with_bond.add(net) elif attrs.get('bonding') == bond: add_nets_with_bond.add(net) nets_with_bond = add_nets_with_bond or (current_nets_with_bond - remove_nets_with_bond) if nets_with_bond: raise ne.ConfigNetworkError( ne.ERR_USED_BOND, 'Cannot remove bonding {}: used by network ({}).'.format( bond, nets_with_bond))
def _validate_bond_removal(bond, nets, running_nets): running_nets_with_bond = set([ net for net, attrs in six.iteritems(running_nets) if attrs['bond'] == bond]) add_nets_with_bond = set() remove_nets_with_bond = set() for net, attrs in six.iteritems(nets): if 'remove' in attrs: running_bond = running_nets.get(net, {}).get('bond') if running_bond == bond: remove_nets_with_bond.add(net) elif net in running_nets: running_bond = running_nets[net].get('bond') if running_bond == bond: remove_nets_with_bond.add(net) if attrs.get('bonding') == bond: add_nets_with_bond.add(net) else: if attrs.get('bonding') == bond: add_nets_with_bond.add(net) if (add_nets_with_bond or (running_nets_with_bond - remove_nets_with_bond)): raise ne.ConfigNetworkError( ne.ERR_USED_BOND, 'Cannot remove bonding {}: used by network.'.format(bond))
def run(iface, family=4, default_route=False, duid_source=None, blocking_dhcp=False): dhclient = DhcpClient(iface, family, default_route, duid_source) ret = dhclient.start(blocking_dhcp) if blocking_dhcp and ret[0]: raise ne.ConfigNetworkError( ne.ERR_FAILED_IFUP, 'dhclient%s failed' % family)
def _validate_network_exists(self): if (self._name not in self._net_info.networks and self._name not in self._running_config.networks): raise ne.ConfigNetworkError( ne.ERR_BAD_BRIDGE, 'Cannot delete ' f'network {self._name}: It doesn\'t exist in the system', )
def _validate_default_route(default_route_nets, no_default_route_nets): for net, attrs in six.iteritems(RunningConfig().networks): if attrs['defaultRoute'] and net not in no_default_route_nets: default_route_nets.add(net) if len(default_route_nets) > 1: raise ne.ConfigNetworkError( ne.ERR_BAD_PARAMS, 'Only a single default route network is allowed.')
def validate(nets): for net, attrs in six.iteritems(nets): if 'remove' in attrs: continue elif attrs['nameservers'] and not attrs['defaultRoute']: raise ne.ConfigNetworkError( ne.ERR_BAD_PARAMS, 'Name servers may only be defined on the default host network')
def _validate_bond_addition(nics, current_nics): for nic in nics: _validate_nic_exists(nic, current_nics) if dpdk.is_dpdk(nic): raise ne.ConfigNetworkError( ne.ERR_BAD_NIC, '%s is a dpdk device and not supported as a slave of bond' % nic)
def validate_bond_configuration(bonds): for bond_name, bond_attrs in six.viewitems(bonds): if bond_attrs.get('remove', False): continue nics = bond_attrs.get('nics', []) if not nics: raise ne.ConfigNetworkError(ne.ERR_BAD_PARAMS, '{}: Must specify ' 'nics for bonding'.format(bond_name))
def _validate_network_remove(netname, netattrs, netinfo_networks, running_config_networks): netattrs_set = set(netattrs) is_remove = netattrs.get('remove') if is_remove and netattrs_set - set(['remove', 'custom']): raise ne.ConfigNetworkError( ne.ERR_BAD_PARAMS, 'Cannot specify any attribute when removing (except custom)).', ) if is_remove: if (netname not in netinfo_networks and netname not in running_config_networks): raise ne.ConfigNetworkError( ne.ERR_BAD_BRIDGE, "Cannot delete " "network %r: It doesn't exist in the " "system" % netname, )
def _validate_bond_addition(self): for slave in self._nics: _validate_nic_exists(slave, self._net_info.nics) if dpdk.is_dpdk(slave): raise ne.ConfigNetworkError( ne.ERR_BAD_NIC, '%s is a dpdk device and not supported as a slave of bond' % slave, )
def validate_vlan_configuration(nets): for net_name, net_attrs in six.viewitems(nets): if net_attrs.get('remove', False): continue if 'vlan' in net_attrs: if 'nic' not in net_attrs and 'bonding' not in net_attrs: raise ne.ConfigNetworkError( ne.ERR_BAD_VLAN, '{}: vlan device requires south' 'bound device'.format(net_name))
def _try_writing_single_opt(self, opt, val): try: with open(BRIDGING_OPTS.format(self.name, opt), 'w') as f: f.write(val) except OSError: raise ne.ConfigNetworkError( ne.ERR_BAD_PARAMS, f'Trying to write custom bridge option {opt}={val}' f' that does not exists for bridge {self.name}', )
def store_entry(name, attrs, switch_type): if switch_type is None: store_broken_entry(name, attrs) elif switch_type == legacy_switch.SWITCH_TYPE: legacy_entries[name] = attrs elif switch_type == ovs_switch.SWITCH_TYPE: ovs_entries[name] = attrs else: raise ne.ConfigNetworkError( ne.ERR_BAD_PARAMS, 'Invalid switch type %s' % attrs['switch'])
def _validate_bond_options(bond_options): mode = 'balance-rr' try: for option in bond_options.split(): key, value = option.split('=', 1) if key == 'mode': mode = value except ValueError: raise ne.ConfigNetworkError( ne.ERR_BAD_BONDING, 'Error parsing bonding options: %r' % bond_options) mode = sysfs_options.numerize_bond_mode(mode) defaults = sysfs_options.getDefaultBondingOptions(mode) for option in bond_options.split(): key, _ = option.split('=', 1) if key not in defaults: raise ne.ConfigNetworkError( ne.ERR_BAD_BONDING, '%r is not a valid bonding option' % key)
def validate_bond_configuration(bond, bondattrs, desired_nets, current_nets, current_nics): if 'remove' in bondattrs: _validate_bond_removal(bond, desired_nets, current_nets) elif 'nics' in bondattrs: _validate_bond_addition(bondattrs['nics'], current_nics) else: raise ne.ConfigNetworkError(ne.ERR_BAD_NIC, 'Missing nics attribute') if 'options' in bondattrs: _validate_bond_options(bondattrs['options'])
def validate_bond_names(nets, bonds): bad_bond_names = {bond for bond in bonds if not re.match('^bond\w+$', bond)} bad_bond_names |= {net_attrs['bonding'] for net_attrs in six.viewvalues(nets) if 'bonding' in net_attrs and not re.match('^bond\w+$', net_attrs['bonding'])} if bad_bond_names: raise ne.ConfigNetworkError(ne.ERR_BAD_BONDING, 'bad bond name(s): {}'.format( ', '.join(bad_bond_names)))
def validate_net_configuration(net, attrs, bonds, running_bonds, kernel_nics): """Test if network meets logical Vdsm requiremets. Bridgeless networks are allowed in order to support Engine requirements. Checked by OVS: - only one vlan per tag """ nic = attrs.get('nic') bond = attrs.get('bonding') vlan = attrs.get('vlan') if vlan is None: if nic and nic not in kernel_nics: raise ne.ConfigNetworkError( ne.ERR_BAD_NIC, 'Nic %s does not exist' % nic) running_bond = bond in running_bonds bond2setup = bond in bonds and 'remove' not in bonds[bond] if bond and not running_bond and not bond2setup: raise ne.ConfigNetworkError( ne.ERR_BAD_BONDING, 'Bond %s does not exist' % bond)
def validate(self): if self._remove: self._validate_bond_removal() return if self._nics: self._validate_bond_addition() else: raise ne.ConfigNetworkError(ne.ERR_BAD_NIC, 'Missing nics attribute') if self._options: _validate_bond_options(self._options)
def _validate_bond_removal(self): nets_with_bond = { net for net, attrs in self._desired_config.networks.items() if attrs.get('bonding') == self._name } if nets_with_bond: raise ne.ConfigNetworkError( ne.ERR_USED_BOND, 'Cannot remove bonding {}: used by network ({}).'.format( self._name, nets_with_bond), )