def test_generate_vpp_config(self): tmpdir = tempfile.mkdtemp() config_path = os.path.join(tmpdir, 'startup.conf') with open(config_path, 'w') as f: f.write(_INITIAL_VPP_CONFIG) vpp_exec_path = os.path.join(tmpdir, 'vpp-exec') utils._VPP_EXEC_FILE = vpp_exec_path int1 = objects.VppInterface('em1', options="vlan-strip-offload off") int1.pci_dev = '0000:00:09.0' int2 = objects.VppInterface('em2') int2.pci_dev = '0000:00:09.1' interfaces = [int1, int2] expected_config = ''' unix { exec %s nodaemon log /tmp/vpp.log full-coredump } api-trace { on } api-segment { gid vpp } dpdk { dev 0000:00:09.1 uio-driver vfio-pci dev 0000:00:09.0 {vlan-strip-offload off} } ''' % vpp_exec_path self.assertEqual(expected_config, utils.generate_vpp_config(config_path, interfaces))
def apply(self, cleanup=False, activate=True): """Apply the network configuration. :param cleanup: A boolean which indicates whether any undefined (existing but not present in the object model) interface should be disabled and deleted. :param activate: A boolean which indicates if the config should be activated by stopping/starting interfaces NOTE: if cleanup is specified we will deactivate interfaces even if activate is false :returns: a dict of the format: filename/data which contains info for each file that was changed (or would be changed if in --noop mode). Note the noop mode is set via the constructor noop boolean """ logger.info('applying network configs...') restart_interfaces = [] restart_vlans = [] restart_bridges = [] restart_linux_bonds = [] restart_linux_teams = [] restart_vpp = False update_files = {} all_file_names = [] ivs_uplinks = [] # ivs physical uplinks ivs_interfaces = [] # ivs internal ports nfvswitch_interfaces = [] # nfvswitch physical interfaces nfvswitch_internal_ifaces = [] # nfvswitch internal/management ports stop_dhclient_interfaces = [] ovs_needs_restart = False vpp_interfaces = self.vpp_interface_data.values() for interface_name, iface_data in self.interface_data.items(): route_data = self.route_data.get(interface_name, '') route6_data = self.route6_data.get(interface_name, '') interface_path = self.root_dir + ifcfg_config_path(interface_name) route_path = self.root_dir + route_config_path(interface_name) route6_path = self.root_dir + route6_config_path(interface_name) all_file_names.append(interface_path) all_file_names.append(route_path) all_file_names.append(route6_path) if "IVS_BRIDGE" in iface_data: ivs_uplinks.append(interface_name) if "NFVSWITCH_BRIDGE" in iface_data: nfvswitch_interfaces.append(interface_name) all_file_names.append(route6_path) if (utils.diff(interface_path, iface_data) or utils.diff(route_path, route_data) or utils.diff(route6_path, route6_data)): restart_interfaces.append(interface_name) restart_interfaces.extend(self.child_members(interface_name)) update_files[interface_path] = iface_data update_files[route_path] = route_data update_files[route6_path] = route6_data if "BOOTPROTO=dhcp" not in iface_data: stop_dhclient_interfaces.append(interface_name) # Openvswitch needs to be restarted when OVSDPDKPort or # OVSDPDKBond is added if "OVSDPDK" in iface_data: ovs_needs_restart = True else: logger.info('No changes required for interface: %s' % interface_name) for interface_name, iface_data in self.ivsinterface_data.items(): route_data = self.route_data.get(interface_name, '') route6_data = self.route6_data.get(interface_name, '') interface_path = self.root_dir + ifcfg_config_path(interface_name) route_path = self.root_dir + route_config_path(interface_name) route6_path = self.root_dir + route6_config_path(interface_name) all_file_names.append(interface_path) all_file_names.append(route_path) all_file_names.append(route6_path) ivs_interfaces.append(interface_name) if (utils.diff(interface_path, iface_data) or utils.diff(route_path, route_data)): restart_interfaces.append(interface_name) restart_interfaces.extend(self.child_members(interface_name)) update_files[interface_path] = iface_data update_files[route_path] = route_data update_files[route6_path] = route6_data else: logger.info('No changes required for ivs interface: %s' % interface_name) for iface_name, iface_data in self.nfvswitch_intiface_data.items(): route_data = self.route_data.get(iface_name, '') route6_data = self.route6_data.get(iface_name, '') iface_path = self.root_dir + ifcfg_config_path(iface_name) route_path = self.root_dir + route_config_path(iface_name) route6_path = self.root_dir + route6_config_path(iface_name) all_file_names.append(iface_path) all_file_names.append(route_path) all_file_names.append(route6_path) nfvswitch_internal_ifaces.append(iface_name) if (utils.diff(iface_path, iface_data) or utils.diff(route_path, route_data)): restart_interfaces.append(iface_name) restart_interfaces.extend(self.child_members(iface_name)) update_files[iface_path] = iface_data update_files[route_path] = route_data update_files[route6_path] = route6_data else: logger.info('No changes required for nfvswitch interface: %s' % iface_name) for vlan_name, vlan_data in self.vlan_data.items(): route_data = self.route_data.get(vlan_name, '') route6_data = self.route6_data.get(vlan_name, '') vlan_path = self.root_dir + ifcfg_config_path(vlan_name) vlan_route_path = self.root_dir + route_config_path(vlan_name) vlan_route6_path = self.root_dir + route6_config_path(vlan_name) all_file_names.append(vlan_path) all_file_names.append(vlan_route_path) all_file_names.append(vlan_route6_path) if (utils.diff(vlan_path, vlan_data) or utils.diff(vlan_route_path, route_data)): restart_vlans.append(vlan_name) restart_vlans.extend(self.child_members(vlan_name)) update_files[vlan_path] = vlan_data update_files[vlan_route_path] = route_data update_files[vlan_route6_path] = route6_data else: logger.info('No changes required for vlan interface: %s' % vlan_name) for bridge_name, bridge_data in self.bridge_data.items(): route_data = self.route_data.get(bridge_name, '') route6_data = self.route6_data.get(bridge_name, '') bridge_path = self.root_dir + bridge_config_path(bridge_name) br_route_path = self.root_dir + route_config_path(bridge_name) br_route6_path = self.root_dir + route6_config_path(bridge_name) all_file_names.append(bridge_path) all_file_names.append(br_route_path) all_file_names.append(br_route6_path) if (utils.diff(bridge_path, bridge_data) or utils.diff(br_route_path, route_data) or utils.diff(br_route6_path, route6_data)): restart_bridges.append(bridge_name) # Avoid duplicate interface being added to the restart list children = self.child_members(bridge_name) for child in children: if child not in restart_interfaces: restart_interfaces.append(child) update_files[bridge_path] = bridge_data update_files[br_route_path] = route_data update_files[br_route6_path] = route6_data else: logger.info('No changes required for bridge: %s' % bridge_name) for bridge_name, bridge_data in self.linuxbridge_data.items(): route_data = self.route_data.get(bridge_name, '') route6_data = self.route6_data.get(bridge_name, '') bridge_path = self.root_dir + bridge_config_path(bridge_name) br_route_path = self.root_dir + route_config_path(bridge_name) br_route6_path = self.root_dir + route6_config_path(bridge_name) all_file_names.append(bridge_path) all_file_names.append(br_route_path) all_file_names.append(br_route6_path) if (utils.diff(bridge_path, bridge_data) or utils.diff(br_route_path, route_data) or utils.diff(br_route6_path, route6_data)): restart_bridges.append(bridge_name) restart_interfaces.extend(self.child_members(bridge_name)) update_files[bridge_path] = bridge_data update_files[br_route_path] = route_data update_files[br_route6_path] = route6_data else: logger.info('No changes required for bridge: %s' % bridge_name) for team_name, team_data in self.linuxteam_data.items(): route_data = self.route_data.get(team_name, '') route6_data = self.route6_data.get(team_name, '') team_path = self.root_dir + bridge_config_path(team_name) team_route_path = self.root_dir + route_config_path(team_name) team_route6_path = self.root_dir + route6_config_path(team_name) all_file_names.append(team_path) all_file_names.append(team_route_path) all_file_names.append(team_route6_path) if (utils.diff(team_path, team_data) or utils.diff(team_route_path, route_data) or utils.diff(team_route6_path, route6_data)): restart_linux_teams.append(team_name) restart_interfaces.extend(self.child_members(team_name)) update_files[team_path] = team_data update_files[team_route_path] = route_data update_files[team_route6_path] = route6_data else: logger.info('No changes required for linux team: %s' % team_name) for bond_name, bond_data in self.linuxbond_data.items(): route_data = self.route_data.get(bond_name, '') route6_data = self.route6_data.get(bond_name, '') bond_path = self.root_dir + bridge_config_path(bond_name) bond_route_path = self.root_dir + route_config_path(bond_name) bond_route6_path = self.root_dir + route6_config_path(bond_name) all_file_names.append(bond_path) all_file_names.append(bond_route_path) all_file_names.append(bond_route6_path) if (utils.diff(bond_path, bond_data) or utils.diff(bond_route_path, route_data) or utils.diff(bond_route6_path, route6_data)): restart_linux_bonds.append(bond_name) restart_interfaces.extend(self.child_members(bond_name)) update_files[bond_path] = bond_data update_files[bond_route_path] = route_data update_files[bond_route6_path] = route6_data else: logger.info('No changes required for linux bond: %s' % bond_name) # Infiniband interfaces are handled similarly to Ethernet interfaces for interface_name, iface_data in self.ib_interface_data.items(): route_data = self.route_data.get(interface_name, '') route6_data = self.route6_data.get(interface_name, '') interface_path = self.root_dir + ifcfg_config_path(interface_name) route_path = self.root_dir + route_config_path(interface_name) route6_path = self.root_dir + route6_config_path(interface_name) all_file_names.append(interface_path) all_file_names.append(route_path) all_file_names.append(route6_path) # TODO(dsneddon) determine if InfiniBand can be used with IVS if "IVS_BRIDGE" in iface_data: ivs_uplinks.append(interface_name) all_file_names.append(route6_path) if (utils.diff(interface_path, iface_data) or utils.diff(route_path, route_data) or utils.diff(route6_path, route6_data)): restart_interfaces.append(interface_name) restart_interfaces.extend(self.child_members(interface_name)) update_files[interface_path] = iface_data update_files[route_path] = route_data update_files[route6_path] = route6_data else: logger.info('No changes required for InfiniBand iface: %s' % interface_name) if self.vpp_interface_data: vpp_path = self.root_dir + vpp_config_path() vpp_config = utils.generate_vpp_config(vpp_path, vpp_interfaces) if utils.diff(vpp_path, vpp_config): restart_vpp = True update_files[vpp_path] = vpp_config else: logger.info('No changes required for VPP') if cleanup: for ifcfg_file in glob.iglob(cleanup_pattern()): if ifcfg_file not in all_file_names: interface_name = ifcfg_file[len(cleanup_pattern()) - 1:] if interface_name != 'lo': logger.info('cleaning up interface: %s' % interface_name) self.ifdown(interface_name) self.remove_config(ifcfg_file) if activate: for vlan in restart_vlans: self.ifdown(vlan) for interface in restart_interfaces: self.ifdown(interface) for linux_bond in restart_linux_bonds: self.ifdown(linux_bond) for linux_team in restart_linux_teams: self.ifdown(linux_team) for bridge in restart_bridges: self.ifdown(bridge, iftype='bridge') for vpp_interface in vpp_interfaces: self.ifdown(vpp_interface.name) for oldname, newname in self.renamed_interfaces.items(): self.ifrename(oldname, newname) # DPDK initialization is done before running os-net-config, to make # the DPDK ports available when enabled. DPDK Hotplug support is # supported only in OvS 2.7 version. Until then, OvS needs to be # restarted after adding a DPDK port. This change will be removed on # migration to OvS 2.7 where DPDK Hotplug support is available. if ovs_needs_restart: msg = "Restart openvswitch" self.execute(msg, '/usr/bin/systemctl', 'restart', 'openvswitch') for location, data in update_files.items(): self.write_config(location, data) if ivs_uplinks or ivs_interfaces: location = ivs_config_path() data = self.generate_ivs_config(ivs_uplinks, ivs_interfaces) self.write_config(location, data) if nfvswitch_interfaces or nfvswitch_internal_ifaces: location = nfvswitch_config_path() data = self.generate_nfvswitch_config(nfvswitch_interfaces, nfvswitch_internal_ifaces) self.write_config(location, data) if activate: for linux_team in restart_linux_teams: self.ifup(linux_team) for bridge in restart_bridges: self.ifup(bridge, iftype='bridge') # If dhclient is running and dhcp not set, stop dhclient for interface in stop_dhclient_interfaces: logger.debug("Calling stop_dhclient_interfaces() for %s" % interface) if not self.noop: stop_dhclient_process(interface) for interface in restart_interfaces: self.ifup(interface) for linux_bond in restart_linux_bonds: self.ifup(linux_bond) for bond in self.bond_primary_ifaces: self.ovs_appctl('bond/set-active-slave', bond, self.bond_primary_ifaces[bond]) if ivs_uplinks or ivs_interfaces: logger.info("Attach to ivs with " "uplinks: %s, " "interfaces: %s" % (ivs_uplinks, ivs_interfaces)) for ivs_uplink in ivs_uplinks: self.ifup(ivs_uplink) for ivs_interface in ivs_interfaces: self.ifup(ivs_interface) msg = "Restart ivs" self.execute(msg, '/usr/bin/systemctl', 'restart', 'ivs') if nfvswitch_interfaces or nfvswitch_internal_ifaces: logger.info("Attach to nfvswitch with " "interfaces: %s, " "internal interfaces: %s" % (nfvswitch_interfaces, nfvswitch_internal_ifaces)) for nfvswitch_interface in nfvswitch_interfaces: self.ifup(nfvswitch_interface) for nfvswitch_internal in nfvswitch_internal_ifaces: self.ifup(nfvswitch_internal) msg = "Restart nfvswitch" self.execute(msg, '/usr/bin/systemctl', 'restart', 'nfvswitch') for vlan in restart_vlans: self.ifup(vlan) if not self.noop: if restart_vpp: logger.info('Restarting VPP') utils.restart_vpp(vpp_interfaces) if self.vpp_interface_data: logger.info('Updating VPP mapping') utils.update_vpp_mapping(vpp_interfaces) if self.errors: message = 'Failure(s) occurred when applying configuration' logger.error(message) for e in self.errors: logger.error('stdout: %s, stderr: %s', e.stdout, e.stderr) raise os_net_config.ConfigurationError(message) return update_files
def test_generate_vpp_config(self): tmpdir = tempfile.mkdtemp() config_path = os.path.join(tmpdir, 'startup.conf') with open(config_path, 'w') as f: f.write(_INITIAL_VPP_CONFIG) vpp_exec_path = os.path.join(tmpdir, 'vpp-exec') utils._VPP_EXEC_FILE = vpp_exec_path int1 = objects.VppInterface('em1', options="vlan-strip-offload off") int1.pci_dev = '0000:00:09.0' int2 = objects.VppInterface('em2') int2.pci_dev = '0000:00:09.1' interfaces = [int1, int2] bonds = [] expected_config = ''' unix { exec %s nodaemon log /tmp/vpp.log full-coredump } api-trace { on } api-segment { gid vpp } dpdk { dev 0000:00:09.1 uio-driver vfio-pci dev 0000:00:09.0 {vlan-strip-offload off} } ''' % vpp_exec_path self.assertEqual(expected_config, utils.generate_vpp_config(config_path, interfaces, bonds)) bonds = [objects.VppBond('net_bonding0', members=interfaces, bonding_options='mode=2,xmit_policy=l3')] expected_config = ''' unix { exec %s nodaemon log /tmp/vpp.log full-coredump } api-trace { on } api-segment { gid vpp } dpdk { vdev net_bonding0,slave=0000:00:09.0,slave=0000:00:09.1,mode=2,xmit_policy=l3 dev 0000:00:09.1 uio-driver vfio-pci dev 0000:00:09.0 {vlan-strip-offload off} } ''' % vpp_exec_path self.assertEqual(expected_config, utils.generate_vpp_config(config_path, interfaces, bonds))