Exemple #1
0
    async def bridge_setup(self, tapname, tap, attach_iface):
        if attach_iface is None:
            # XXX: backward compatibility prior to 11.1-RELEASE.
            try:
                attach_iface = netif.RoutingTable(
                ).default_route_ipv4.interface
            except:
                return

        if_bridge = []
        bridge_enabled = False

        for brgname, iface in list(netif.list_interfaces().items()):
            if brgname.startswith('bridge'):
                if_bridge.append(iface)

        if if_bridge:
            for bridge in if_bridge:
                if attach_iface in bridge.members:
                    bridge_enabled = True
                    self.set_tap_mtu(bridge, tap)
                    bridge.add_member(tapname)
                    break

        if bridge_enabled is False:
            bridge = netif.get_interface(netif.create_interface('bridge'))
            self.set_tap_mtu(bridge, tap)
            bridge.add_member(tapname)
            bridge.add_member(attach_iface)
            bridge.up()
Exemple #2
0
    async def bridge_setup(self, tapname, tap, attach_iface):
        if attach_iface is None:
            # XXX: backward compatibility prior to 11.1-RELEASE.
            try:
                attach_iface = netif.RoutingTable().default_route_ipv4.interface
            except:
                return

        if_bridge = []
        bridge_enabled = False

        for brgname, iface in list(netif.list_interfaces().items()):
            if brgname.startswith('bridge'):
                if_bridge.append(iface)

        if if_bridge:
            for bridge in if_bridge:
                if attach_iface in bridge.members:
                    bridge_enabled = True
                    self.set_tap_mtu(bridge, tap)
                    bridge.add_member(tapname)
                    break

        if bridge_enabled is False:
            bridge = netif.get_interface(netif.create_interface('bridge'))
            self.set_tap_mtu(bridge, tap)
            bridge.add_member(tapname)
            bridge.add_member(attach_iface)
            bridge.up()
Exemple #3
0
    def run(self, bridge_enable=False):
        node = ConfigNode('service.openvpn', self.configstore).__getstate__()
        interface_list = list(netif.list_interfaces().keys())
        default_interface = self.dispatcher.call_sync('networkd.configuration.get_default_interface')

        vpn_interface = netif.get_interface(self.configstore.get('service.openvpn.dev'))	
        vpn_interface.up()

        if 'VPNbridge' not in interface_list:		
            bridge_interface = netif.get_interface(netif.create_interface('bridge'))
            bridge_interface.rename('VPNbridge')
            bridge_interface.description = 'OpenVPN bridge interface'

        else:
            bridge_interface = netif.get_interface('VPNbridge')

	
        if node['server_bridge_extended']:
            subnet = ipaddress.ip_interface('{0}/{1}'.format(node['server_bridge_ip'], bridge_values['server_bridge_netmask']))
            bridge_interface.add_address(netif.InterfaceAddress(
            netif.AddressFamily.INET,
            subnet
            ))

        try:
            bridge_interface.add_member(default_interface)
        
        except FileExistsError as e:
            logger.info('Default interface already bridged: {0}'.format(e))

        except OSError as e:
            raise TaskException(errno.EBUSY, 
                                'Default interface busy - check other bridge interfaces. {0}'.format(e))

        try:
            bridge_interface.add_member(self.configstore.get('service.openvpn.dev'))

        except FileExistsError as e:
            logger.info('OpenVPN interface already bridged: {0}'.format(e))

        except OSError as e:
            raise TaskException(errno.EBUSY,
                                'VPN interface busy - check other bridge interfaces. {0}'.format(e))

        else:
            bridge_interface.up()
Exemple #4
0
    def up(self):
        # Destroy old bridge (if exists)
        try:
            netif.destroy_interface(self.ifname)
        except OSError as err:
            if err.errno != errno.ENXIO:
                raise RuntimeError('Cannot destroy {0}: {1}'.format(self.ifname, str(err)))

        # Setup bridge
        self.bridge_if = netif.get_interface(netif.create_interface('bridge'))
        self.bridge_if.rename(self.ifname)
        self.bridge_if.description = 'containerd management network'
        self.bridge_if.add_address(netif.InterfaceAddress(
            netif.AddressFamily.INET,
            self.subnet
        ))
        self.bridge_if.up()

        self.dhcp_server.server_name = 'FreeNAS'
        self.dhcp_server.on_request = self.dhcp_request
        self.dhcp_server.start(self.ifname, self.subnet.ip)
        self.dhcp_server_thread = gevent.spawn(self.dhcp_worker)
Exemple #5
0
    async def bridge_setup(self, tapname, tap, attach_iface):
        if_bridge = []
        bridge_enabled = False

        if attach_iface is None:
            # XXX: backward compatibility prior to 11.1-RELEASE.
            try:
                attach_iface = netif.RoutingTable().default_route_ipv4.interface
                attach_iface_info = netif.get_interface(attach_iface)
            except:
                return
        else:
            attach_iface_info = netif.get_interface(attach_iface)

        # If for some reason the main iface is down, we need to up it.
        attach_iface_status = netif.InterfaceFlags.UP in attach_iface_info.flags
        if attach_iface_status is False:
            attach_iface_info.up()

        for brgname, iface in list(netif.list_interfaces().items()):
            if brgname.startswith('bridge'):
                if_bridge.append(iface)

        if if_bridge:
            for bridge in if_bridge:
                if attach_iface in bridge.members:
                    bridge_enabled = True
                    self.set_iface_mtu(attach_iface_info, tap)
                    bridge.add_member(tapname)
                    if netif.InterfaceFlags.UP not in bridge.flags:
                        bridge.up()
                    break

        if bridge_enabled is False:
            bridge = netif.get_interface(netif.create_interface('bridge'))
            self.set_iface_mtu(attach_iface_info, tap)
            bridge.add_member(tapname)
            bridge.add_member(attach_iface)
            bridge.up()
Exemple #6
0
    async def bridge_setup(self, tapname, tap, attach_iface):
        if_bridge = []
        bridge_enabled = False

        if attach_iface is None:
            # XXX: backward compatibility prior to 11.1-RELEASE.
            try:
                attach_iface = netif.RoutingTable(
                ).default_route_ipv4.interface
                attach_iface_info = netif.get_interface(attach_iface)
            except:
                return
        else:
            attach_iface_info = netif.get_interface(attach_iface)

        # If for some reason the main iface is down, we need to up it.
        attach_iface_status = netif.InterfaceFlags.UP in attach_iface_info.flags
        if attach_iface_status is False:
            attach_iface_info.up()

        for brgname, iface in list(netif.list_interfaces().items()):
            if brgname.startswith('bridge'):
                if_bridge.append(iface)

        if if_bridge:
            for bridge in if_bridge:
                if attach_iface in bridge.members:
                    bridge_enabled = True
                    self.set_iface_mtu(attach_iface_info, tap)
                    bridge.add_member(tapname)
                    break

        if bridge_enabled is False:
            bridge = netif.get_interface(netif.create_interface('bridge'))
            self.set_iface_mtu(attach_iface_info, tap)
            bridge.add_member(tapname)
            bridge.add_member(attach_iface)
            bridge.up()
    def init_tap(self, name, nic, mac):
        try:
            iface = netif.get_interface(netif.create_interface('tap'))
            iface.description = 'vm:{0}:{1}'.format(self.name, name)
            iface.up()

            if nic['type'] == 'BRIDGE':
                if nic['bridge']:
                        bridge = netif.get_interface(nic['bridge'])
                        bridge.add_member(iface.name)

            if nic['type'] == 'MANAGEMENT':
                mgmt = netif.get_interface('mgmt0', bridge=True)
                mgmt.add_member(iface.name)

            if nic['type'] == 'NAT':
                mgmt = netif.get_interface('nat0', bridge=True)
                mgmt.add_member(iface.name)

            self.tap_interfaces[iface] = mac
            return iface.name
        except (KeyError, OSError) as err:
            self.logger.warning('Cannot initialize NIC {0}: {1}'.format(name, str(err)))
            return
Exemple #8
0
    def sync(self):
        """
        Sync interfaces configured in database to the OS.
        """

        interfaces = [
            i['int_interface'] for i in self.middleware.call(
                'datastore.query', 'network.interfaces')
        ]
        cloned_interfaces = []
        parent_interfaces = []

        # First of all we need to create the virtual interfaces
        # LAGG comes first and then VLAN
        laggs = self.middleware.call('datastore.query',
                                     'network.lagginterface')
        for lagg in laggs:
            name = lagg['lagg_interface']['int_interface']
            cloned_interfaces.append(name)
            self.logger.info('Setting up {}'.format(name))
            try:
                iface = netif.get_interface(name)
            except KeyError:
                netif.create_interface(name)
                iface = netif.get_interface(name)

            if lagg['lagg_protocol'] == 'fec':
                protocol = netif.AggregationProtocol.ETHERCHANNEL
            else:
                protocol = getattr(netif.AggregationProtocol,
                                   lagg['lagg_protocol'].upper())
            if iface.protocol != protocol:
                self.logger.info('{}: changing protocol to {}'.format(
                    name, protocol))
                iface.protocol = protocol

            members_configured = set(p[0] for p in iface.ports)
            members_database = set()
            for member in self.middleware.call(
                    'datastore.query', 'network.lagginterfacemembers',
                [('lagg_interfacegroup_id', '=', lagg['id'])]):
                members_database.add(member['lagg_physnic'])

            # Remeve member configured but not in database
            for member in (members_configured - members_database):
                iface.delete_port(member)

            # Add member in database but not configured
            for member in (members_database - members_configured):
                iface.add_port(member)

            for port in iface.ports:
                try:
                    port_iface = netif.get_interface(port[0])
                except KeyError:
                    self.logger.warn('Could not find {} from {}'.format(
                        port[0], name))
                    continue
                parent_interfaces.append(port[0])
                port_iface.up()

        vlans = self.middleware.call('datastore.query', 'network.vlan')
        for vlan in vlans:
            cloned_interfaces.append(vlan['vlan_vint'])
            self.logger.info('Setting up {}'.format(vlan['vlan_vint']))
            try:
                iface = netif.get_interface(vlan['vlan_vint'])
            except KeyError:
                netif.create_interface(vlan['vlan_vint'])
                iface = netif.get_interface(vlan['vlan_vint'])

            if iface.parent != vlan['vlan_pint'] or iface.tag != vlan[
                    'vlan_tag']:
                iface.unconfigure()
                iface.configure(vlan['vlan_pint'], vlan['vlan_tag'])

            try:
                parent_iface = netif.get_interface(iface.parent)
            except KeyError:
                self.logger.warn('Could not find {} from {}'.format(
                    iface.parent, vlan['vlan_vint']))
                continue
            parent_interfaces.append(iface.parent)
            parent_iface.up()

        self.logger.info('Interfaces in database: {}'.format(
            ', '.join(interfaces) or 'NONE'))
        for interface in interfaces:
            try:
                self.sync_interface(interface)
            except:
                self.logger.error('Failed to configure {}'.format(interface),
                                  exc_info=True)

        internal_interfaces = [
            'lo', 'pflog', 'pfsync', 'tun', 'tap', 'bridge', 'epair'
        ]
        if not self.middleware.call('system.is_freenas'):
            internal_interfaces.extend(
                self.middleware.call('notifier.failover_internal_interfaces')
                or [])
        internal_interfaces = tuple(internal_interfaces)

        # Destroy interfaces which are not in database
        for name, iface in list(netif.list_interfaces().items()):
            # Skip internal interfaces
            if name.startswith(internal_interfaces):
                continue
            # Skip interfaces in database
            if name in interfaces:
                continue

            # Interface not in database lose addresses
            for address in iface.addresses:
                iface.remove_address(address)

            # Kill dhclient if its running for this interface
            dhclient_running, dhclient_pid = dhclient_status(name)
            if dhclient_running:
                os.kill(dhclient_pid, signal.SIGTERM)

            # If we have vlan or lagg not in the database at all
            # It gets destroy, otherwise just bring it down
            if name not in cloned_interfaces and name.startswith(
                ('lagg', 'vlan')):
                netif.destroy_interface(name)
            elif name not in parent_interfaces:
                iface.down()
Exemple #9
0
    async def sync(self):
        """
        Sync interfaces configured in database to the OS.
        """

        interfaces = [
            i['int_interface'] for i in (await self.middleware.call(
                'datastore.query', 'network.interfaces'))
        ]
        cloned_interfaces = []
        parent_interfaces = []

        # First of all we need to create the virtual interfaces
        # LAGG comes first and then VLAN
        laggs = await self.middleware.call('datastore.query',
                                           'network.lagginterface')
        for lagg in laggs:
            name = lagg['lagg_interface']['int_interface']
            cloned_interfaces.append(name)
            self.logger.info('Setting up {}'.format(name))
            try:
                iface = netif.get_interface(name)
            except KeyError:
                netif.create_interface(name)
                iface = netif.get_interface(name)

            protocol = getattr(netif.AggregationProtocol,
                               lagg['lagg_protocol'].upper())
            if iface.protocol != protocol:
                self.logger.info('{}: changing protocol to {}'.format(
                    name, protocol))
                iface.protocol = protocol

            members_database = set()
            members_configured = set(p[0] for p in iface.ports)
            members_changes = []
            # In case there are MTU changes we need to use the lowest MTU between
            # all members and use that.
            lower_mtu = None
            for member in (await self.middleware.call(
                    'datastore.query', 'network.lagginterfacemembers',
                [('lagg_interfacegroup_id', '=', lagg['id'])])):
                members_database.add(member['lagg_physnic'])
                try:
                    member_iface = netif.get_interface(member['lagg_physnic'])
                except KeyError:
                    self.logger.warn('Could not find {} from {}'.format(
                        member['lagg_physnic'], name))
                    continue

                # In case there is no MTU in interface options and it is currently
                # different than the default of 1500, revert it.
                # If there is MTU and its different set it (using member options).
                reg_mtu = RE_MTU.search(member['lagg_deviceoptions'])
                if (reg_mtu and
                    (int(reg_mtu.group(1)) != member_iface.mtu
                     or int(reg_mtu.group(1)) != iface.mtu)) or (
                         not reg_mtu and
                         (member_iface.mtu != 1500 or iface.mtu != 1500)):
                    if not reg_mtu:
                        if not lower_mtu or lower_mtu > 1500:
                            lower_mtu = 1500
                    else:
                        reg_mtu = int(reg_mtu.group(1))
                        if not lower_mtu or lower_mtu > reg_mtu:
                            lower_mtu = reg_mtu

                members_changes.append((member_iface, member['lagg_physnic'],
                                        member['lagg_deviceoptions']))

            for member_iface, member_name, member_options in members_changes:
                # We need to remove interface from LAGG before changing MTU
                if lower_mtu and member_iface.mtu != lower_mtu and member_name in members_configured:
                    iface.delete_port(member_name)
                    members_configured.remove(member_name)
                proc = await Popen(['/sbin/ifconfig', member_name] +
                                   shlex.split(member_options),
                                   stdout=subprocess.PIPE,
                                   stderr=subprocess.PIPE,
                                   close_fds=True)
                err = (await proc.communicate())[1].decode()
                if err:
                    self.logger.info(f'{member_name}: error applying: {err}')
                if lower_mtu and member_iface.mtu != lower_mtu:
                    member_iface.mtu = lower_mtu

            # Remove member configured but not in database
            for member in (members_configured - members_database):
                iface.delete_port(member)

            # Add member in database but not configured
            for member in (members_database - members_configured):
                iface.add_port(member)

            for port in iface.ports:
                try:
                    port_iface = netif.get_interface(port[0])
                except KeyError:
                    self.logger.warn('Could not find {} from {}'.format(
                        port[0], name))
                    continue
                parent_interfaces.append(port[0])
                port_iface.up()

        vlans = await self.middleware.call('datastore.query', 'network.vlan')
        for vlan in vlans:
            cloned_interfaces.append(vlan['vlan_vint'])
            self.logger.info('Setting up {}'.format(vlan['vlan_vint']))
            try:
                iface = netif.get_interface(vlan['vlan_vint'])
            except KeyError:
                netif.create_interface(vlan['vlan_vint'])
                iface = netif.get_interface(vlan['vlan_vint'])

            if iface.parent != vlan['vlan_pint'] or iface.tag != vlan[
                    'vlan_tag'] or iface.pcp != vlan['vlan_pcp']:
                iface.unconfigure()
                iface.configure(vlan['vlan_pint'], vlan['vlan_tag'],
                                vlan['vlan_pcp'])

            try:
                parent_iface = netif.get_interface(iface.parent)
            except KeyError:
                self.logger.warn('Could not find {} from {}'.format(
                    iface.parent, vlan['vlan_vint']))
                continue
            parent_interfaces.append(iface.parent)
            parent_iface.up()

        self.logger.info('Interfaces in database: {}'.format(
            ', '.join(interfaces) or 'NONE'))
        for interface in interfaces:
            try:
                await self.sync_interface(interface)
            except Exception:
                self.logger.error('Failed to configure {}'.format(interface),
                                  exc_info=True)

        internal_interfaces = [
            'lo', 'pflog', 'pfsync', 'tun', 'tap', 'bridge', 'epair'
        ]
        if not await self.middleware.call('system.is_freenas'):
            internal_interfaces.extend(
                await
                self.middleware.call('notifier.failover_internal_interfaces')
                or [])
        internal_interfaces = tuple(internal_interfaces)

        # Destroy interfaces which are not in database
        for name, iface in list(netif.list_interfaces().items()):
            # Skip internal interfaces
            if name.startswith(internal_interfaces):
                continue
            # Skip interfaces in database
            if name in interfaces:
                continue

            # Interface not in database lose addresses
            for address in iface.addresses:
                iface.remove_address(address)

            # Kill dhclient if its running for this interface
            dhclient_running, dhclient_pid = dhclient_status(name)
            if dhclient_running:
                os.kill(dhclient_pid, signal.SIGTERM)

            # If we have vlan or lagg not in the database at all
            # It gets destroy, otherwise just bring it down
            if name not in cloned_interfaces and name.startswith(
                ('lagg', 'vlan')):
                netif.destroy_interface(name)
            elif name not in parent_interfaces:
                iface.down()
Exemple #10
0
    def configure_interface(self, name, restart_rtsold=True):
        entity = self.datastore.get_one('network.interfaces', ('id', '=', name))
        if not entity:
            raise RpcException(errno.ENXIO, "Configuration for interface {0} not found".format(name))

        try:
            iface = netif.get_interface(name)
        except KeyError:
            if entity.get('cloned'):
                netif.create_interface(entity['id'])
                iface = netif.get_interface(name)
            else:
                yield errno.ENOENT, "Interface {0} not found".format(name)
                return

        if not entity.get('enabled'):
            self.logger.info('Interface {0} is disabled'.format(name))
            return

        # check whether interface is a lagg member
        for j in netif.list_interfaces().values():
            try:
                if isinstance(j, netif.LaggInterface) and name in [p[0] for p in j.ports]:
                    lagg_member = True
                    break
            except OSError:
                continue
        else:
            lagg_member = False

        try:
            if netif.InterfaceFlags.UP not in iface.flags:
                self.logger.info('Bringing interface {0} up'.format(name))
                iface.up()

            # If it's VLAN, configure parent and tag
            if entity.get('type') == 'VLAN':
                vlan = entity.get('vlan')
                if vlan:
                    parent = vlan.get('parent')
                    tag = vlan.get('tag')

                    if parent != iface.parent or tag != iface.tag:
                        try:
                            tag = int(tag)
                            iface.unconfigure()
                            iface.configure(parent, tag)
                        except OSError as e:
                            yield e.errno, 'Failed to configure VLAN interface {0}: {1}'.format(name, str(e))

            # Configure protocol and member ports for a LAGG
            if entity.get('type') == 'LAGG':
                lagg = entity.get('lagg')
                if lagg:
                    new_protocol = getattr(netif.AggregationProtocol, lagg.get('protocol', 'FAILOVER'))
                    old_ports = set(p[0] for p in iface.ports)
                    new_ports = set(lagg['ports'])

                    if iface.protocol != new_protocol:
                        iface.protocol = new_protocol

                    for port in old_ports - new_ports:
                        iface.delete_port(port)

                    for port in lagg['ports']:
                        if port not in old_ports:
                            iface.add_port(port)

            # Configure member interfaces for a bridge
            if entity.get('type') == 'BRIDGE':
                bridge = entity.get('bridge')
                if bridge:
                    old_members = set(iface.members)
                    new_members = set(bridge['members'])

                    for port in old_members - new_members:
                        iface.delete_member(port)

                    for port in new_members - old_members:
                        iface.add_member(port)

            if entity.get('dhcp'):
                if name in self.context.dhcp_clients:
                    self.logger.info('Interface {0} already configured using DHCP'.format(name))
                else:
                    # Remove all existing aliases
                    for i in iface.addresses:
                        iface.remove_address(i)

                    self.logger.info('Trying to acquire DHCP lease on interface {0}...'.format(name))
                    if not self.context.configure_dhcp(name, True, INITIAL_DHCP_TIMEOUT):
                        yield errno.ENETUNREACH, 'Failed to configure interface {0} using DHCP'.format(name)
            else:
                if name in self.context.dhcp_clients:
                    self.logger.info('Stopping DHCP client on interface {0}'.format(name))
                    self.context.deconfigure_dhcp(name)

                addresses = set(convert_aliases(entity))
                existing_addresses = set([a for a in iface.addresses if a.af != netif.AddressFamily.LINK])

                # Remove orphaned addresses
                for i in existing_addresses - addresses:
                    if i.af == netif.AddressFamily.INET6 and str(i.address).startswith('fe80::'):
                        # skip link-local IPv6 addresses
                        continue

                    self.logger.info('Removing address from interface {0}: {1}'.format(name, i))
                    iface.remove_address(i)

                # Add new or changed addresses
                for i in addresses - existing_addresses:
                    self.logger.info('Adding new address to interface {0}: {1}'.format(name, i))
                    iface.add_address(i)

            # nd6 stuff
            if entity.get('rtadv', False):
                iface.nd6_flags = iface.nd6_flags | {netif.NeighborDiscoveryFlags.ACCEPT_RTADV}
                if restart_rtsold:
                    self.client.call_sync('service.restart', 'rtsold', timeout=300)
            else:
                iface.nd6_flags = iface.nd6_flags - {netif.NeighborDiscoveryFlags.ACCEPT_RTADV}

            if entity.get('noipv6', False):
                iface.nd6_flags = iface.nd6_flags | {netif.NeighborDiscoveryFlags.IFDISABLED}
                iface.nd6_flags = iface.nd6_flags - {netif.NeighborDiscoveryFlags.AUTO_LINKLOCAL}
            else:
                iface.nd6_flags = iface.nd6_flags - {netif.NeighborDiscoveryFlags.IFDISABLED}
                iface.nd6_flags = iface.nd6_flags | {netif.NeighborDiscoveryFlags.AUTO_LINKLOCAL}

            if entity.get('mtu') and not isinstance(iface, netif.LaggInterface) and not lagg_member:
                try:
                    iface.mtu = entity['mtu']
                except OSError as err:
                    yield err.errno, 'Cannot set MTU of {0}: {1}'.format(name, str(err))

            if entity.get('media'):
                iface.media_subtype = entity['media']

            # vlan interfaces don't support capabilities
            if entity.get('capabilities') and not isinstance(iface, (netif.VlanInterface, netif.BridgeInterface)):
                caps = iface.capabilities
                for c in entity['capabilities'].get('add'):
                    caps.add(getattr(netif.InterfaceCapability, c))

                for c in entity['capabilities'].get('del'):
                    caps.remove(getattr(netif.InterfaceCapability, c))

                iface.capabilities = caps

        except OSError as err:
            yield err.errno, err.strerror

        self.client.emit_event('network.interface.configured', {
            'interface': name,
        })
Exemple #11
0
    async def run(self):
        args = [
            'bhyve',
            '-H',
            '-w',
            '-c', str(self.vm['vcpus']),
            '-m', str(self.vm['memory']),
            '-s', '0:0,hostbridge',
            '-s', '31,lpc',
            '-l', 'com1,/dev/nmdm{}A'.format(self.vm['id']),
        ]

        if self.vm['bootloader'] in ('UEFI', 'UEFI_CSM'):
            args += [
                '-l', 'bootrom,/usr/local/share/uefi-firmware/BHYVE_UEFI{}.fd'.format('_CSM' if self.vm['bootloader'] == 'UEFI_CSM' else ''),
            ]

        nid = Nid(3)
        for device in self.vm['devices']:
            if device['dtype'] == 'DISK' or device['dtype'] == 'RAW':

                disk_sector_size = device['attributes'].get('sectorsize', 0)
                if disk_sector_size > 0:
                    sectorsize_args = ",sectorsize=" + str(disk_sector_size)
                else:
                    sectorsize_args = ""

                if device['attributes'].get('type') == 'AHCI':
                    args += ['-s', '{},ahci-hd,{}{}'.format(nid(), device['attributes']['path'], sectorsize_args)]
                else:
                    args += ['-s', '{},virtio-blk,{}{}'.format(nid(), device['attributes']['path'], sectorsize_args)]
            elif device['dtype'] == 'CDROM':
                args += ['-s', '{},ahci-cd,{}'.format(nid(), device['attributes']['path'])]
            elif device['dtype'] == 'NIC':
                attach_iface = device['attributes'].get('nic_attach')

                self.logger.debug('====> NIC_ATTACH: {0}'.format(attach_iface))

                tapname = netif.create_interface('tap')
                tap = netif.get_interface(tapname)
                tap.up()
                self.taps.append(tapname)
                await self.bridge_setup(tapname, tap, attach_iface)

                if device['attributes'].get('type') == 'VIRTIO':
                    nictype = 'virtio-net'
                else:
                    nictype = 'e1000'
                mac_address = device['attributes'].get('mac', None)

                # By default we add one NIC and the MAC address is an empty string.
                # Issue: 24222
                if mac_address == "":
                    mac_address = None

                if mac_address == '00:a0:98:FF:FF:FF' or mac_address is None:
                    args += ['-s', '{},{},{},mac={}'.format(nid(), nictype, tapname, self.random_mac())]
                else:
                    args += ['-s', '{},{},{},mac={}'.format(nid(), nictype, tapname, mac_address)]
            elif device['dtype'] == 'VNC':
                if device['attributes'].get('wait'):
                    wait = 'wait'
                else:
                    wait = ''

                vnc_resolution = device['attributes'].get('vnc_resolution', None)
                vnc_port = int(device['attributes'].get('vnc_port', 5900 + self.vm['id']))
                vnc_bind = device['attributes'].get('vnc_bind', '0.0.0.0')
                vnc_password = device['attributes'].get('vnc_password', None)

                vnc_password_args = ""
                if vnc_password:
                    vnc_password_args = ",password="******"===> Rebooting VM: {0} ID: {1} BHYVE_CODE: {2}".format(self.vm['name'], self.vm['id'], self.bhyve_error))
            await self.manager.restart(self.vm['id'])
            await self.manager.start(self.vm['id'])
        elif self.bhyve_error == 1:
            # XXX: Need a better way to handle the vmm destroy.
            self.logger.info("===> Powered off VM: {0} ID: {1} BHYVE_CODE: {2}".format(self.vm['name'], self.vm['id'], self.bhyve_error))
            await self.destroy_vm()
        elif self.bhyve_error in (2, 3):
            self.logger.info("===> Stopping VM: {0} ID: {1} BHYVE_CODE: {2}".format(self.vm['name'], self.vm['id'], self.bhyve_error))
            await self.manager.stop(self.vm['id'])
        elif self.bhyve_error not in (0, 1, 2, 3, None):
            self.logger.info("===> Error VM: {0} ID: {1} BHYVE_CODE: {2}".format(self.vm['name'], self.vm['id'], self.bhyve_error))
            await self.destroy_vm()
Exemple #12
0
    async def sync(self):
        """
        Sync interfaces configured in database to the OS.
        """

        interfaces = [i['int_interface'] for i in (await self.middleware.call('datastore.query', 'network.interfaces'))]
        cloned_interfaces = []
        parent_interfaces = []

        # First of all we need to create the virtual interfaces
        # LAGG comes first and then VLAN
        laggs = await self.middleware.call('datastore.query', 'network.lagginterface')
        for lagg in laggs:
            name = lagg['lagg_interface']['int_interface']
            cloned_interfaces.append(name)
            self.logger.info('Setting up {}'.format(name))
            try:
                iface = netif.get_interface(name)
            except KeyError:
                netif.create_interface(name)
                iface = netif.get_interface(name)

            protocol = getattr(netif.AggregationProtocol, lagg['lagg_protocol'].upper())
            if iface.protocol != protocol:
                self.logger.info('{}: changing protocol to {}'.format(name, protocol))
                iface.protocol = protocol

            members_database = set()
            members_configured = set(p[0] for p in iface.ports)
            members_changes = []
            # In case there are MTU changes we need to use the lowest MTU between
            # all members and use that.
            lower_mtu = None
            for member in (await self.middleware.call('datastore.query', 'network.lagginterfacemembers', [('lagg_interfacegroup_id', '=', lagg['id'])])):
                members_database.add(member['lagg_physnic'])
                try:
                    member_iface = netif.get_interface(member['lagg_physnic'])
                except KeyError:
                    self.logger.warn('Could not find {} from {}'.format(member['lagg_physnic'], name))
                    continue

                # In case there is no MTU in interface options and it is currently
                # different than the default of 1500, revert it.
                # If there is MTU and its different set it (using member options).
                reg_mtu = RE_MTU.search(member['lagg_deviceoptions'])
                if (
                    reg_mtu and (
                        int(reg_mtu.group(1)) != member_iface.mtu or
                        int(reg_mtu.group(1)) != iface.mtu
                    )
                ) or (not reg_mtu and (member_iface.mtu != 1500 or iface.mtu != 1500)):
                    if not reg_mtu:
                        if not lower_mtu or lower_mtu > 1500:
                            lower_mtu = 1500
                    else:
                        reg_mtu = int(reg_mtu.group(1))
                        if not lower_mtu or lower_mtu > reg_mtu:
                            lower_mtu = reg_mtu

                members_changes.append((member_iface, member['lagg_physnic'], member['lagg_deviceoptions']))

            for member_iface, member_name, member_options in members_changes:
                # We need to remove interface from LAGG before changing MTU
                if lower_mtu and member_iface.mtu != lower_mtu and member_name in members_configured:
                    iface.delete_port(member_name)
                    members_configured.remove(member_name)
                proc = await Popen(['/sbin/ifconfig', member_name] + shlex.split(member_options), stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True)
                err = (await proc.communicate())[1].decode()
                if err:
                    self.logger.info(f'{member_name}: error applying: {err}')
                if lower_mtu and member_iface.mtu != lower_mtu:
                    member_iface.mtu = lower_mtu

            # Remove member configured but not in database
            for member in (members_configured - members_database):
                iface.delete_port(member)

            # Add member in database but not configured
            for member in (members_database - members_configured):
                iface.add_port(member)

            for port in iface.ports:
                try:
                    port_iface = netif.get_interface(port[0])
                except KeyError:
                    self.logger.warn('Could not find {} from {}'.format(port[0], name))
                    continue
                parent_interfaces.append(port[0])
                port_iface.up()

        vlans = await self.middleware.call('datastore.query', 'network.vlan')
        for vlan in vlans:
            cloned_interfaces.append(vlan['vlan_vint'])
            self.logger.info('Setting up {}'.format(vlan['vlan_vint']))
            try:
                iface = netif.get_interface(vlan['vlan_vint'])
            except KeyError:
                netif.create_interface(vlan['vlan_vint'])
                iface = netif.get_interface(vlan['vlan_vint'])

            if iface.parent != vlan['vlan_pint'] or iface.tag != vlan['vlan_tag'] or iface.pcp != vlan['vlan_pcp']:
                iface.unconfigure()
                iface.configure(vlan['vlan_pint'], vlan['vlan_tag'], vlan['vlan_pcp'])

            try:
                parent_iface = netif.get_interface(iface.parent)
            except KeyError:
                self.logger.warn('Could not find {} from {}'.format(iface.parent, vlan['vlan_vint']))
                continue
            parent_interfaces.append(iface.parent)
            parent_iface.up()

        self.logger.info('Interfaces in database: {}'.format(', '.join(interfaces) or 'NONE'))
        for interface in interfaces:
            try:
                await self.sync_interface(interface)
            except Exception:
                self.logger.error('Failed to configure {}'.format(interface), exc_info=True)

        internal_interfaces = ['lo', 'pflog', 'pfsync', 'tun', 'tap', 'bridge', 'epair']
        if not await self.middleware.call('system.is_freenas'):
            internal_interfaces.extend(await self.middleware.call('notifier.failover_internal_interfaces') or [])
        internal_interfaces = tuple(internal_interfaces)

        # Destroy interfaces which are not in database
        for name, iface in list(netif.list_interfaces().items()):
            # Skip internal interfaces
            if name.startswith(internal_interfaces):
                continue
            # Skip interfaces in database
            if name in interfaces:
                continue

            # Interface not in database lose addresses
            for address in iface.addresses:
                iface.remove_address(address)

            # Kill dhclient if its running for this interface
            dhclient_running, dhclient_pid = dhclient_status(name)
            if dhclient_running:
                os.kill(dhclient_pid, signal.SIGTERM)

            # If we have vlan or lagg not in the database at all
            # It gets destroy, otherwise just bring it down
            if name not in cloned_interfaces and name.startswith(('lagg', 'vlan')):
                netif.destroy_interface(name)
            elif name not in parent_interfaces:
                iface.down()
Exemple #13
0
    async def run(self):
        vnc_web = None  # We need to initialize before line 200
        args = [
            'bhyve',
            '-A',
            '-H',
            '-w',
            '-c', str(self.vm['vcpus']),
            '-m', str(self.vm['memory']),
            '-s', '0:0,hostbridge',
            '-s', '31,lpc',
            '-l', 'com1,/dev/nmdm{}A'.format(self.vm['id']),
        ]

        if self.vm['bootloader'] in ('UEFI', 'UEFI_CSM'):
            args += [
                '-l', 'bootrom,/usr/local/share/uefi-firmware/BHYVE_UEFI{}.fd'.format('_CSM' if self.vm['bootloader'] == 'UEFI_CSM' else ''),
            ]

        nid = Nid(3)
        device_map_file = None
        grub_dir = None
        grub_boot_device = False
        for device in self.vm['devices']:
            if device['dtype'] == 'DISK' or device['dtype'] == 'RAW':

                disk_sector_size = device['attributes'].get('sectorsize', 0)
                if disk_sector_size > 0:
                    sectorsize_args = ',sectorsize=' + str(disk_sector_size)
                else:
                    sectorsize_args = ''

                if device['attributes'].get('type') == 'AHCI':
                    args += ['-s', '{},ahci-hd,{}{}'.format(nid(), device['attributes']['path'], sectorsize_args)]
                else:
                    args += ['-s', '{},virtio-blk,{}{}'.format(nid(), device['attributes']['path'], sectorsize_args)]

                if self.vmutils.is_container(self.vm) and \
                    device['attributes'].get('boot', False) is True and \
                        grub_boot_device is False:
                    shared_fs = await self.middleware.call('vm.get_sharefs')
                    device_map_file = self.vmutils.ctn_device_map(shared_fs, self.vm['id'], self.vm['name'], device)
                    grub_dir = self.vmutils.ctn_grub(shared_fs, self.vm['id'], self.vm['name'], device, device['attributes'].get('rootpwd', None), None)
                    grub_boot_device = True
                    self.logger.debug('==> Boot Disk: {0}'.format(device))

            elif device['dtype'] == 'CDROM':
                args += ['-s', '{},ahci-cd,{}'.format(nid(), device['attributes']['path'])]
            elif device['dtype'] == 'NIC':
                attach_iface = device['attributes'].get('nic_attach')

                self.logger.debug('====> NIC_ATTACH: {0}'.format(attach_iface))

                tapname = netif.create_interface('tap')
                tap = netif.get_interface(tapname)
                tap.up()
                self.taps.append(tapname)
                await self.bridge_setup(tapname, tap, attach_iface)

                if device['attributes'].get('type') == 'VIRTIO':
                    nictype = 'virtio-net'
                else:
                    nictype = 'e1000'
                mac_address = device['attributes'].get('mac', None)

                # By default we add one NIC and the MAC address is an empty string.
                # Issue: 24222
                if mac_address == '':
                    mac_address = None

                if mac_address == '00:a0:98:FF:FF:FF' or mac_address is None:
                    random_mac = await self.middleware.call('vm.random_mac')
                    args += ['-s', '{},{},{},mac={}'.format(nid(), nictype, tapname, random_mac)]
                else:
                    args += ['-s', '{},{},{},mac={}'.format(nid(), nictype, tapname, mac_address)]
            elif device['dtype'] == 'VNC':
                if device['attributes'].get('wait'):
                    wait = 'wait'
                else:
                    wait = ''

                vnc_resolution = device['attributes'].get('vnc_resolution', None)
                vnc_port = int(device['attributes'].get('vnc_port', 5900 + self.vm['id']))
                vnc_bind = device['attributes'].get('vnc_bind', '0.0.0.0')
                vnc_password = device['attributes'].get('vnc_password', None)
                vnc_web = device['attributes'].get('vnc_web', None)

                vnc_password_args = ''
                if vnc_password:
                    vnc_password_args = 'password='******'x')
                    width = vnc_resolution[0]
                    height = vnc_resolution[1]

                args += ['-s', '29,fbuf,vncserver,tcp={}:{},w={},h={},{},{}'.format(vnc_bind, vnc_port, width,
                                                                                    height, vnc_password_args, wait),
                         '-s', '30,xhci,tablet', ]

        # grub-bhyve support for containers
        if self.vmutils.is_container(self.vm):
            grub_bhyve_args = [
                'grub-bhyve', '-m', device_map_file,
                '-r', 'host',
                '-M', str(self.vm['memory']),
                '-d', grub_dir,
                str(self.vm['id']) + '_' + self.vm['name'],
            ]

            #  If container has no boot device, we should stop.
            if grub_boot_device is False:
                raise CallError(f'There is no boot disk for vm: {self.vm["name"]}')

            self.logger.debug('Starting grub-bhyve: {}'.format(' '.join(grub_bhyve_args)))
            self.grub_proc = await Popen(grub_bhyve_args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)

            while True:
                line = await self.grub_proc.stdout.readline()
                if line == b'':
                    break

        args.append(str(self.vm['id']) + '_' + self.vm['name'])

        self.logger.debug('Starting bhyve: {}'.format(' '.join(args)))
        self.proc = await Popen(args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)

        if vnc_web:
            split_port = int(str(vnc_port)[:2]) - 1
            vnc_web_port = str(split_port) + str(vnc_port)[2:]

            web_bind = ':{}'.format(vnc_web_port) if vnc_bind is '0.0.0.0' else '{}:{}'.format(vnc_bind, vnc_web_port)

            self.web_proc = await Popen(['/usr/local/libexec/novnc/utils/websockify/run', '--web',
                                         '/usr/local/libexec/novnc/', '--wrap-mode=ignore',
                                         web_bind, '{}:{}'.format(vnc_bind, vnc_port)],
                                        stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
            self.logger.debug('==> Start WEBVNC at port {} with pid number {}'.format(vnc_web_port, self.web_proc.pid))

        output = deque(maxlen=10)

        while True:
            line = await self.proc.stdout.readline()
            if line == b'':
                break
            line = line.decode().rstrip()
            self.logger.debug('{}: {}'.format(self.vm['name'], line))
            output.append(line)

        # bhyve returns the following status code:
        # 0 - VM has been reset
        # 1 - VM has been powered off
        # 2 - VM has been halted
        # 3 - VM generated a triple fault
        # 4 - VM exited due to an error
        # all other non-zero status codes are errors
        self.bhyve_error = await self.proc.wait()
        if self.bhyve_error == 0:
            self.logger.info('===> Rebooting VM: {0} ID: {1} BHYVE_CODE: {2}'.format(self.vm['name'], self.vm['id'], self.bhyve_error))
            await self.manager.restart(self.vm['id'])
            await self.manager.start(self.vm['id'])
        elif self.bhyve_error == 1:
            # XXX: Need a better way to handle the vmm destroy.
            self.logger.info('===> Powered off VM: {0} ID: {1} BHYVE_CODE: {2}'.format(self.vm['name'], self.vm['id'], self.bhyve_error))
            await self.__teardown_guest_vmemory(self.vm['id'])
            await self.destroy_vm()
        elif self.bhyve_error in (2, 3):
            self.logger.info('===> Stopping VM: {0} ID: {1} BHYVE_CODE: {2}'.format(self.vm['name'], self.vm['id'], self.bhyve_error))
            await self.__teardown_guest_vmemory(self.vm['id'])
            await self.manager.stop(self.vm['id'])
        elif self.bhyve_error not in (0, 1, 2, 3, None):
            self.logger.info('===> Error VM: {0} ID: {1} BHYVE_CODE: {2}'.format(self.vm['name'], self.vm['id'], self.bhyve_error))
            await self.__teardown_guest_vmemory(self.vm['id'])
            await self.destroy_vm()
            output = "\n".join(output)
            raise CallError(f'VM {self.vm["name"]} failed to start: {output}')
    def configure_interface(self, name, restart_rtsold=True):
        entity = self.datastore.get_one('network.interfaces', ('id', '=', name))
        if not entity:
            raise RpcException(errno.ENXIO, "Configuration for interface {0} not found".format(name))

        try:
            iface = netif.get_interface(name)
        except KeyError:
            if entity.get('cloned'):
                netif.create_interface(entity['id'])
                iface = netif.get_interface(name)
            else:
                raise RpcException(errno.ENOENT, "Interface {0} not found".format(name))

        if not entity.get('enabled'):
            self.logger.info('Interface {0} is disabled'.format(name))
            return

        # If it's VLAN, configure parent and tag
        if entity.get('type') == 'VLAN':
            vlan = entity.get('vlan')
            if vlan:
                parent = vlan.get('parent')
                tag = vlan.get('tag')

                if parent and tag:
                    try:
                        tag = int(tag)
                        iface.unconfigure()
                        iface.configure(parent, tag)
                    except Exception as e:
                        self.logger.warn('Failed to configure VLAN interface {0}: {1}'.format(name, str(e)))

        # Configure protocol and member ports for a LAGG
        if entity.get('type') == 'LAGG':
            lagg = entity.get('lagg')
            if lagg:
                iface.protocol = getattr(netif.AggregationProtocol, lagg.get('protocol', 'FAILOVER'))
                old_ports = set(iface.ports)
                new_ports = set(lagg['ports'])

                for port in old_ports - new_ports:
                    iface.delete_port(port)

                for port in new_ports - old_ports:
                    iface.add_port(port)

        # Configure member interfaces for a bridge
        if entity.get('type') == 'BRIDGE':
            bridge = entity.get('bridge')
            if bridge:
                old_members = set(iface.members)
                new_members = set(bridge['members'])

                for port in old_members - new_members:
                    iface.delete_member(port)

                for port in new_members - old_members:
                    iface.add_member(port)

        if entity.get('dhcp'):
            if self.context.dhclient_running(name):
                self.logger.info('Interface {0} already configured using DHCP'.format(name))
            else:
                # Remove all existing aliases
                for i in iface.addresses:
                    iface.remove_address(i)

                self.logger.info('Trying to acquire DHCP lease on interface {0}...'.format(name))
                if not self.context.configure_dhcp(name):
                    self.logger.warn('Failed to configure interface {0} using DHCP'.format(name))
        else:
            addresses = set(convert_aliases(entity))
            existing_addresses = set([a for a in iface.addresses if a.af != netif.AddressFamily.LINK])

            # Remove orphaned addresses
            for i in existing_addresses - addresses:
                if i.af == netif.AddressFamily.INET6 and str(i.address).startswith('fe80::'):
                    # skip link-local IPv6 addresses
                    continue

                self.logger.info('Removing address from interface {0}: {1}'.format(name, i))
                iface.remove_address(i)

            # Add new or changed addresses
            for i in addresses - existing_addresses:
                self.logger.info('Adding new address to interface {0}: {1}'.format(name, i))
                iface.add_address(i)

        # nd6 stuff
        if entity.get('rtadv', False):
            iface.nd6_flags = iface.nd6_flags | {netif.NeighborDiscoveryFlags.ACCEPT_RTADV}
            if restart_rtsold:
                self.client.call_sync('service.restart', 'rtsold')
        else:
            iface.nd6_flags = iface.nd6_flags - {netif.NeighborDiscoveryFlags.ACCEPT_RTADV}

        if entity.get('noipv6', False):
            iface.nd6_flags = iface.nd6_flags | {netif.NeighborDiscoveryFlags.IFDISABLED}
            iface.nd6_flags = iface.nd6_flags - {netif.NeighborDiscoveryFlags.AUTO_LINKLOCAL}
        else:
            iface.nd6_flags = iface.nd6_flags - {netif.NeighborDiscoveryFlags.IFDISABLED}
            iface.nd6_flags = iface.nd6_flags | {netif.NeighborDiscoveryFlags.AUTO_LINKLOCAL}

        if entity.get('mtu'):
            iface.mtu = entity['mtu']

        if entity.get('media'):
            iface.media_subtype = entity['media']

        if entity.get('capabilities'):
            caps = iface.capabilities
            for c in entity['capabilities'].get('add'):
                caps.add(getattr(netif.InterfaceCapability, c))

            for c in entity['capabilities'].get('del'):
                caps.remove(getattr(netif.InterfaceCapability, c))

            iface.capabilities = caps

        if netif.InterfaceFlags.UP not in iface.flags:
            self.logger.info('Bringing interface {0} up'.format(name))
            iface.up()

        self.client.emit_event('network.interface.configured', {
            'interface': name,
        })
Exemple #15
0
    def run(self):
        vpn_state = self.dispatcher.call_sync('service.query', [('name', '=', 'openvpn')], {'single': True})
        node = ConfigNode('service.openvpn', self.configstore).__getstate__()

        if vpn_state['state'] != 'RUNNING':
            raise TaskException(errno.EPERM, 'For bridging VPN capabilities openvpn needs to be running.')

        if node['mode'] == 'psk':
            raise TaskException(errno.EPERM, 'Bridging VPN capabilities only in pki mode.')

        # This feels like a not so good solution - feel free to change
        tap_interfaces = netif.get_ifgroup('tap')

        for vpn_interface_name in tap_interfaces:
            tap_pids = system('/usr/bin/fuser', '/dev/' + vpn_interface_name)[0].split()
            if vpn_state['pid'] in tap_pids:
                    break

        try:
            vpn_interface = netif.get_interface(vpn_interface_name)

        except KeyError:
            raise TaskException(
                errno.EINVAL,
                '{0} interface does not exist - Verify OpenVPN status'.format(vpn_interface_name)
            )
        else:
            vpn_interface.up()

        default_interface = self.dispatcher.call_sync('networkd.configuration.get_default_interface')
        if not default_interface:
            raise TaskException(errno.EINVAL, 'No default interface configured. Verify network setup.')

        # Heavily inspired by containterd
        available_bridges = list(b for b in netif.list_interfaces().keys()
                                 if isinstance(netif.get_interface(b), netif.BridgeInterface))

        for b in available_bridges:
            bridge_interface = netif.get_interface(b, bridge=True)
            if default_interface in bridge_interface.members:
                try:
                    bridge_interface.add_member(vpn_interface_name)
                except FileExistsError:
                    pass

                break

        else:
            bridge_interface = netif.get_interface(netif.create_interface('bridge'))
            bridge_interface.rename('brg{0}'.format(len(available_bridges)))
            bridge_interface.description = 'OpenVPN bridge interface'
            bridge_interface.up()
            bridge_interface.add_member(default_interface)
            bridge_interface.add_member(vpn_interface_name)

        if node['server_bridge_extended']:
            subnet = ipaddress.ip_interface('{0}/{1}'.format(node['server_bridge_ip'],
                                                             node['server_bridge_netmask']))
            bridge_interface.add_address(netif.InterfaceAddress(
                netif.AddressFamily.INET,
                subnet
            ))
Exemple #16
0
    async def run(self):
        args = [
            'bhyve',
            '-H',
            '-w',
            '-c',
            str(self.vm['vcpus']),
            '-m',
            str(self.vm['memory']),
            '-s',
            '0:0,hostbridge',
            '-s',
            '31,lpc',
            '-l',
            'com1,/dev/nmdm{}A'.format(self.vm['id']),
        ]

        if self.vm['bootloader'] in ('UEFI', 'UEFI_CSM'):
            args += [
                '-l',
                'bootrom,/usr/local/share/uefi-firmware/BHYVE_UEFI{}.fd'.
                format('_CSM' if self.vm['bootloader'] == 'UEFI_CSM' else ''),
            ]

        nid = Nid(3)
        for device in self.vm['devices']:
            if device['dtype'] == 'DISK' or device['dtype'] == 'RAW':

                disk_sector_size = device['attributes'].get('sectorsize', 0)
                if disk_sector_size > 0:
                    sectorsize_args = ",sectorsize=" + str(disk_sector_size)
                else:
                    sectorsize_args = ""

                if device['attributes'].get('type') == 'AHCI':
                    args += [
                        '-s',
                        '{},ahci-hd,{}{}'.format(nid(),
                                                 device['attributes']['path'],
                                                 sectorsize_args)
                    ]
                else:
                    args += [
                        '-s', '{},virtio-blk,{}{}'.format(
                            nid(), device['attributes']['path'],
                            sectorsize_args)
                    ]
            elif device['dtype'] == 'CDROM':
                args += [
                    '-s', '{},ahci-cd,{}'.format(nid(),
                                                 device['attributes']['path'])
                ]
            elif device['dtype'] == 'NIC':
                attach_iface = device['attributes'].get('nic_attach')

                self.logger.debug('====> NIC_ATTACH: {0}'.format(attach_iface))

                tapname = netif.create_interface('tap')
                tap = netif.get_interface(tapname)
                tap.up()
                self.taps.append(tapname)
                await self.bridge_setup(tapname, tap, attach_iface)

                if device['attributes'].get('type') == 'VIRTIO':
                    nictype = 'virtio-net'
                else:
                    nictype = 'e1000'
                mac_address = device['attributes'].get('mac', None)

                # By default we add one NIC and the MAC address is an empty string.
                # Issue: 24222
                if mac_address == "":
                    mac_address = None

                if mac_address == '00:a0:98:FF:FF:FF' or mac_address is None:
                    args += [
                        '-s', '{},{},{},mac={}'.format(nid(), nictype, tapname,
                                                       self.random_mac())
                    ]
                else:
                    args += [
                        '-s', '{},{},{},mac={}'.format(nid(), nictype, tapname,
                                                       mac_address)
                    ]
            elif device['dtype'] == 'VNC':
                if device['attributes'].get('wait'):
                    wait = 'wait'
                else:
                    wait = ''

                vnc_resolution = device['attributes'].get(
                    'vnc_resolution', None)
                vnc_port = int(device['attributes'].get(
                    'vnc_port', 5900 + self.vm['id']))
                vnc_bind = device['attributes'].get('vnc_bind', '0.0.0.0')
                vnc_password = device['attributes'].get('vnc_password', None)
                vnc_web = device['attributes'].get('vnc_web', None)

                vnc_password_args = ""
                if vnc_password:
                    vnc_password_args = ",password="******"==> Start WEBVNC at port {} with pid number {}".format(
                    vnc_web_port, self.web_proc.pid))

        while True:
            line = await self.proc.stdout.readline()
            if line == b'':
                break
            self.logger.debug('{}: {}'.format(self.vm['name'], line.decode()))

        # bhyve returns the following status code:
        # 0 - VM has been reset
        # 1 - VM has been powered off
        # 2 - VM has been halted
        # 3 - VM generated a triple fault
        # all other non-zero status codes are errors
        self.bhyve_error = await self.proc.wait()
        if self.bhyve_error == 0:
            self.logger.info(
                "===> Rebooting VM: {0} ID: {1} BHYVE_CODE: {2}".format(
                    self.vm['name'], self.vm['id'], self.bhyve_error))
            await self.manager.restart(self.vm['id'])
            await self.manager.start(self.vm['id'])
        elif self.bhyve_error == 1:
            # XXX: Need a better way to handle the vmm destroy.
            self.logger.info(
                "===> Powered off VM: {0} ID: {1} BHYVE_CODE: {2}".format(
                    self.vm['name'], self.vm['id'], self.bhyve_error))
            await self.destroy_vm()
        elif self.bhyve_error in (2, 3):
            self.logger.info(
                "===> Stopping VM: {0} ID: {1} BHYVE_CODE: {2}".format(
                    self.vm['name'], self.vm['id'], self.bhyve_error))
            await self.manager.stop(self.vm['id'])
        elif self.bhyve_error not in (0, 1, 2, 3, None):
            self.logger.info(
                "===> Error VM: {0} ID: {1} BHYVE_CODE: {2}".format(
                    self.vm['name'], self.vm['id'], self.bhyve_error))
            await self.destroy_vm()
Exemple #17
0
    def run(self):
        args = [
            'bhyve',
            '-A',
            '-P',
            '-H',
            '-c', str(self.vm['vcpus']),
            '-m', str(self.vm['memory']),
            '-s', '0:0,hostbridge',
            '-s', '31,lpc',
            '-l', 'com1,/dev/nmdm{}A'.format(self.vm['id']),
        ]

        if self.vm['bootloader'] in ('UEFI', 'UEFI_CSM'):
            args += [
                '-l', 'bootrom,/usr/local/share/uefi-firmware/BHYVE_UEFI{}.fd'.format('_CSM' if self.vm['bootloader'] == 'UEFI_CSM' else ''),
            ]

        nid = Nid(3)
        for device in self.vm['devices']:
            if device['dtype'] == 'DISK':
                if device['attributes'].get('mode') == 'AHCI':
                    args += ['-s', '{},ahci-hd,{}'.format(nid(), device['attributes']['path'])]
                else:
                    args += ['-s', '{},virtio-blk,{}'.format(nid(), device['attributes']['path'])]
            elif device['dtype'] == 'CDROM':
                args += ['-s', '{},ahci-cd,{}'.format(nid(), device['attributes']['path'])]
            elif device['dtype'] == 'NIC':
                tapname = netif.create_interface('tap')
                tap = netif.get_interface(tapname)
                tap.up()
                self.taps.append(tapname)
                # If Bridge
                if True:
                    bridge = None
                    for name, iface in netif.list_interfaces().items():
                        if name.startswith('bridge'):
                            bridge = iface
                            break
                    if not bridge:
                        bridge = netif.get_interface(netif.create_interface('bridge'))
                    bridge.add_member(tapname)

                    defiface = Popen("route -nv show default|grep -w interface|awk '{ print $2 }'", stdout=subprocess.PIPE, shell=True).communicate()[0].strip()
                    if defiface and defiface not in bridge.members:
                        bridge.add_member(defiface)
                    bridge.up()
                if device['attributes'].get('type') == 'VIRTIO':
                    nictype = 'virtio-net'
                else:
                    nictype = 'e1000'
                args += ['-s', '{},{},{}'.format(nid(), nictype, tapname)]
            elif device['dtype'] == 'VNC':
                if device['attributes'].get('wait'):
                    wait = 'wait'
                else:
                    wait = ''
                args += [
                    '-s', '29,fbuf,tcp=0.0.0.0:{},w=1024,h=768,{}'.format(5900 + self.vm['id'], wait),
                    '-s', '30,xhci,tablet',
                ]

        args.append(self.vm['name'])

        self.logger.debug('Starting bhyve: {}'.format(' '.join(args)))
        self.proc = Popen(args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
        for line in self.proc.stdout:
            self.logger.debug('{}: {}'.format(self.vm['name'], line))

        self.proc.wait()

        self.logger.info('Destroying {}'.format(self.vm['name']))

        Popen(['bhyvectl', '--destroy', '--vm={}'.format(self.vm['name'])], stdout=subprocess.PIPE, stderr=subprocess.PIPE).wait()

        while self.taps:
            netif.destroy_interface(self.taps.pop())

        self.manager._vm.pop(self.vm['id'], None)
Exemple #18
0
    def configure_interface(self, name, restart_rtsold=True):
        entity = self.datastore.get_one('network.interfaces', ('id', '=', name))
        if not entity:
            raise RpcException(errno.ENXIO, "Configuration for interface {0} not found".format(name))

        try:
            iface = netif.get_interface(name)
        except KeyError:
            if entity.get('cloned'):
                netif.create_interface(entity['id'])
                iface = netif.get_interface(name)
            else:
                yield errno.ENOENT, "Interface {0} not found".format(name)
                return

        if not entity.get('enabled'):
            self.logger.info('Interface {0} is disabled'.format(name))
            return

        # check whether interface is a lagg member
        for j in netif.list_interfaces().values():
            try:
                if isinstance(j, netif.LaggInterface) and name in [p[0] for p in j.ports]:
                    lagg_member = True
                    break
            except OSError:
                continue
        else:
            lagg_member = False

        try:
            if netif.InterfaceFlags.UP not in iface.flags:
                self.logger.info('Bringing interface {0} up'.format(name))
                iface.up()

            # If it's VLAN, configure parent and tag
            if entity.get('type') == 'VLAN':
                vlan = entity.get('vlan')
                if vlan:
                    parent = vlan.get('parent')
                    tag = vlan.get('tag')

                    if parent != iface.parent or tag != iface.tag:
                        try:
                            tag = int(tag)
                            iface.unconfigure()
                            iface.configure(parent, tag)
                        except OSError as e:
                            yield e.errno, 'Failed to configure VLAN interface {0}: {1}'.format(name, str(e))

            # Configure protocol and member ports for a LAGG
            if entity.get('type') == 'LAGG':
                lagg = entity.get('lagg')
                if lagg:
                    new_protocol = getattr(netif.AggregationProtocol, lagg.get('protocol', 'FAILOVER'))
                    old_ports = set(p[0] for p in iface.ports)
                    new_ports = set(lagg['ports'])

                    if iface.protocol != new_protocol:
                        iface.protocol = new_protocol

                    for port in old_ports - new_ports:
                        iface.delete_port(port)

                    for port in new_ports - old_ports:
                        iface.add_port(port)

            # Configure member interfaces for a bridge
            if entity.get('type') == 'BRIDGE':
                bridge = entity.get('bridge')
                if bridge:
                    old_members = set(iface.members)
                    new_members = set(bridge['members'])

                    for port in old_members - new_members:
                        iface.delete_member(port)

                    for port in new_members - old_members:
                        iface.add_member(port)

            if entity.get('dhcp'):
                if name in self.context.dhcp_clients:
                    self.logger.info('Interface {0} already configured using DHCP'.format(name))
                else:
                    # Remove all existing aliases
                    for i in iface.addresses:
                        iface.remove_address(i)

                    self.logger.info('Trying to acquire DHCP lease on interface {0}...'.format(name))
                    if not self.context.configure_dhcp(name):
                        yield errno.ENETUNREACH, 'Failed to configure interface {0} using DHCP'.format(name)
            else:
                if name in self.context.dhcp_clients:
                    self.logger.info('Stopping DHCP client on interface {0}'.format(name))
                    self.context.deconfigure_dhcp(name)

                addresses = set(convert_aliases(entity))
                existing_addresses = set([a for a in iface.addresses if a.af != netif.AddressFamily.LINK])

                # Remove orphaned addresses
                for i in existing_addresses - addresses:
                    if i.af == netif.AddressFamily.INET6 and str(i.address).startswith('fe80::'):
                        # skip link-local IPv6 addresses
                        continue

                    self.logger.info('Removing address from interface {0}: {1}'.format(name, i))
                    iface.remove_address(i)

                # Add new or changed addresses
                for i in addresses - existing_addresses:
                    self.logger.info('Adding new address to interface {0}: {1}'.format(name, i))
                    iface.add_address(i)

            # nd6 stuff
            if entity.get('rtadv', False):
                iface.nd6_flags = iface.nd6_flags | {netif.NeighborDiscoveryFlags.ACCEPT_RTADV}
                if restart_rtsold:
                    self.client.call_sync('service.restart', 'rtsold')
            else:
                iface.nd6_flags = iface.nd6_flags - {netif.NeighborDiscoveryFlags.ACCEPT_RTADV}

            if entity.get('noipv6', False):
                iface.nd6_flags = iface.nd6_flags | {netif.NeighborDiscoveryFlags.IFDISABLED}
                iface.nd6_flags = iface.nd6_flags - {netif.NeighborDiscoveryFlags.AUTO_LINKLOCAL}
            else:
                iface.nd6_flags = iface.nd6_flags - {netif.NeighborDiscoveryFlags.IFDISABLED}
                iface.nd6_flags = iface.nd6_flags | {netif.NeighborDiscoveryFlags.AUTO_LINKLOCAL}

            if entity.get('mtu') and not isinstance(iface, netif.LaggInterface) and not lagg_member:
                try:
                    iface.mtu = entity['mtu']
                except OSError as err:
                    yield err.errno, 'Cannot set MTU of {0}: {1}'.format(name, str(err))

            if entity.get('media'):
                iface.media_subtype = entity['media']

            # vlan interfaces don't support capabilities
            if entity.get('capabilities') and not isinstance(iface, (netif.VlanInterface, netif.BridgeInterface)):
                caps = iface.capabilities
                for c in entity['capabilities'].get('add'):
                    caps.add(getattr(netif.InterfaceCapability, c))

                for c in entity['capabilities'].get('del'):
                    caps.remove(getattr(netif.InterfaceCapability, c))

                iface.capabilities = caps

        except OSError as err:
            yield err.errno, err.strerror

        self.client.emit_event('network.interface.configured', {
            'interface': name,
        })
Exemple #19
0
    def sync(self):
        """
        Sync interfaces configured in database to the OS.
        """

        interfaces = [i['int_interface'] for i in self.middleware.call('datastore.query', 'network.interfaces')]
        cloned_interfaces = []

        # First of all we need to create the virtual interfaces
        # LAGG comes first and then VLAN
        laggs = self.middleware.call('datastore.query', 'network.lagginterface')
        for lagg in laggs:
            name = lagg['lagg_interface']['int_name']
            cloned_interfaces.append(name)
            self.logger.info('Setting up {}'.format(name))
            try:
                iface = netif.get_interface(name)
            except KeyError:
                netif.create_interface(name)
                iface = netif.get_interface(name)

            if lagg['lagg_protocol'] == 'fec':
                protocol = netif.AggregationProtocol.ETHERCHANNEL
            else:
                protocol = getattr(netif.AggregationProtocol, lagg['lagg_protocol'].upper())
            if iface.protocol != protocol:
                self.logger.info('{}: changing protocol to {}'.format(name, protocol))
                iface.protocol = protocol

            members_configured = set(p[0] for p in iface.ports)
            members_database = set()
            for member in self.middleware.call('datastore.query', 'network.lagginterfacemembers', [('lagg_interfacegroup_id', '=', lagg['id'])]):
                members_database.add(member['lagg_physnic'])

            # Remeve member configured but not in database
            for member in (members_configured - members_database):
                iface.delete_port(member)

            # Add member in database but not configured
            for member in (members_database - members_configured):
                iface.add_port(member)

            for port in iface.ports:
                try:
                    port_iface = netif.get_interface(port[0])
                except KeyError:
                    self.logger.warn('Could not find {} from {}'.format(port[0], name))
                    continue
                port_iface.up()

        vlans = self.middleware.call('datastore.query', 'network.vlan')
        for vlan in vlans:
            cloned_interfaces.append(vlan['vlan_vint'])
            self.logger.info('Setting up {}'.format(vlan['vlan_vint']))
            try:
                iface = netif.get_interface(vlan['vlan_vint'])
            except KeyError:
                netif.create_interface(vlan['vlan_vint'])
                iface = netif.get_interface(vlan['vlan_vint'])

            if iface.parent != vlan['vlan_pint'] or iface.tag != vlan['vlan_tag']:
                iface.unconfigure()
                iface.configure(vlan['vlan_pint'], vlan['vlan_tag'])

            try:
                parent_iface = netif.get_interface(iface.parent)
            except KeyError:
                self.logger.warn('Could not find {} from {}'.format(iface.parent, vlan['vlan_vint']))
                continue
            parent_iface.up()

        self.logger.info('Interfaces in database: {}'.format(', '.join(interfaces) or 'NONE'))
        for interface in interfaces:
            try:
                self.sync_interface(interface)
            except:
                self.logger.error('Failed to configure {}'.format(interface), exc_info=True)

        internal_interfaces = ['lo', 'pflog', 'pfsync', 'tun', 'tap']
        if not self.middleware.call('system.is_freenas'):
            internal_interfaces.extend(self.middleware.call('notifier.failover_internal_interfaces') or [])
        internal_interfaces = tuple(internal_interfaces)

        # Destroy interfaces which are not in database
        for name, iface in list(netif.list_interfaces().items()):
            # Skip internal interfaces
            if name.startswith(internal_interfaces):
                continue
            # Skip interfaces in database
            if name in interfaces:
                continue

            # Interface not in database lose addresses
            for address in iface.addresses:
                iface.remove_address(address)

            # Kill dhclient if its running for this interface
            dhclient_running, dhclient_pid = dhclient_status(name)
            if dhclient_running:
                os.kill(dhclient_pid, signal.SIGTERM)

            # If we have vlan or lagg not in the database at all
            # It gets destroy, otherwise just bring it down
            if name not in cloned_interfaces and name.startswith(('lagg', 'vlan')):
                netif.destroy_interface(name)
            else:
                iface.down()
Exemple #20
0
    def run(self):
        vpn_state = self.dispatcher.call_sync('service.query', [('name', '=', 'openvpn')], {'single': True})
        node = ConfigNode('service.openvpn', self.configstore).__getstate__()

        if vpn_state['state'] != 'RUNNING':
            raise TaskException(errno.EPERM, 'For bridging VPN capabilities openvpn needs to be running.')

        if node['mode'] == 'psk':
            raise TaskException(errno.EPERM, 'Bridging VPN capabilities only in pki mode.')

        # This feels like a not so good solution - feel free to change
        tap_interfaces = netif.get_ifgroup('tap')

        for vpn_interface_name in tap_interfaces:
            tap_pids = system('/usr/bin/fuser', '/dev/' + vpn_interface_name)[0].split()
            if vpn_state['pid'] in tap_pids:
                    break

        try:
            vpn_interface = netif.get_interface(vpn_interface_name)

        except KeyError:
            raise TaskException(
                errno.EINVAL,
                '{0} interface does not exist - Verify OpenVPN status'.format(vpn_interface_name)
            )
        else:
            vpn_interface.up()

        default_interface = self.dispatcher.call_sync('networkd.configuration.get_default_interface')
        if not default_interface:
            raise TaskException(errno.EINVAL, 'No default interface configured. Verify network setup.')

        # Heavily inspired by containterd
        available_bridges = list(b for b in netif.list_interfaces().keys()
                                 if isinstance(netif.get_interface(b), netif.BridgeInterface))

        for b in available_bridges:
            bridge_interface = netif.get_interface(b, bridge=True)
            if default_interface in bridge_interface.members:
                try:
                    bridge_interface.add_member(vpn_interface_name)
                except FileExistsError:
                    pass

                break

        else:
            bridge_interface = netif.get_interface(netif.create_interface('bridge'))
            bridge_interface.rename('brg{0}'.format(len(available_bridges)))
            bridge_interface.description = 'OpenVPN bridge interface'
            bridge_interface.up()
            bridge_interface.add_member(default_interface)
            bridge_interface.add_member(vpn_interface_name)

        if node['server_bridge_extended']:
            subnet = ipaddress.ip_interface('{0}/{1}'.format(node['server_bridge_ip'],
                                                             node['server_bridge_netmask']))
            bridge_interface.add_address(netif.InterfaceAddress(
                netif.AddressFamily.INET,
                subnet
            ))