Example #1
0
    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))
Example #2
0
    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
Example #3
0
    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))