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

        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()
Example #2
0
        def bind(old_lease, lease):
            self.logger.info('{0} DHCP lease on {1} from {2}, valid for {3} seconds'.format(
                'Renewed' if old_lease else 'Acquired',
                interface,
                client.server_address,
                lease.lifetime,
                interface
            ))

            if old_lease is None or lease.client_ip != old_lease.client_ip:
                self.logger.info('Assigning IP address {0} to interface {1}'.format(lease.client_ip, interface))
                alias = lease.client_interface
                try:
                    iface = netif.get_interface(interface)
                    iface.add_address(netif.InterfaceAddress(netif.AddressFamily.INET, alias))
                except OSError as err:
                    self.logger.error('Cannot add alias to {0}: {1}'.format(interface, err.strerror))

            if lease.router and self.configstore.get('network.dhcp.assign_gateway'):
                try:
                    rtable = netif.RoutingTable()
                    newroute = default_route(lease.router)
                    if rtable.default_route_ipv4 != newroute:
                        if rtable.default_route_ipv4:
                            self.logger.info('DHCP default route changed from {0} to {1}'.format(
                                rtable.default_route_ipv4,
                                newroute
                            ))
                            rtable.delete(rtable.default_route_ipv4)
                            rtable.add(default_route(lease.router))
                        else:
                            self.logger.info('Adding default route via {0}'.format(lease.router))
                            rtable.add(default_route(lease.router))
                except OSError as err:
                    self.logger.error('Cannot configure default route: {0}'.format(err.strerror))

            if lease.dns_addresses and self.configstore.get('network.dhcp.assign_dns'):
                inp = []
                proc = subprocess.Popen(
                    ['/sbin/resolvconf', '-a', interface],
                    stdout=subprocess.PIPE,
                    stdin=subprocess.PIPE
                )

                for i in lease.dns_addresses:
                    # Filter out bogus DNS server addresses
                    if str(i) in ('127.0.0.1', '0.0.0.0', '255.255.255.255'):
                        continue

                    inp.append('nameserver {0}'.format(i))

                if lease.domain_name:
                    inp.append('search {0}'.format(lease.domain_name))

                proc.communicate('\n'.join(inp).encode('ascii'))
                proc.wait()
                self.logger.info('Updated DNS configuration')
            else:
                subprocess.call(['/sbin/resolvconf', '-d', interface])
                self.logger.info('Deleted DNS configuration')
Example #3
0
 def __init__(self, interface, hostname=''):
     self.logger = logging.getLogger(self.__class__.__name__)
     self.interface = interface
     self.bpf = None
     self.port = 68
     self.default_lifetime = 300
     self.listen_thread = None
     self.send_thread = None
     self.t1_timer = None
     self.t2_timer = None
     self.expire_timer = None
     self.client_ident = None
     self.hostname_source = hostname
     self.lease = None
     self.requested_address = None
     self.server_mac = None
     self.server_address = None
     self.server_name = None
     self.server_id = None
     self.cv = threading.Condition()
     self.state = State.INIT
     self.xid = None
     self.error = None
     self.on_bind = lambda old_lease, lease: None
     self.on_unbind = lambda lease, reason: None
     self.on_reject = lambda reason: None
     self.on_state_change = lambda state: None
     self.source_if = netif.get_interface(self.interface)
     self.hwaddr = str(self.source_if.link_address.address)
Example #4
0
    def up_interface(self, name):
        try:
            iface = netif.get_interface(name)
        except NameError:
            raise RpcException(errno.ENOENT, "Interface {0} not found".format(name))

        iface.up()
Example #5
0
File: vm.py Project: binzyw/freenas
    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()
Example #6
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()
Example #7
0
def get_interface(ipaddress):
    get_all_ifaces = netif.list_interfaces()
    ifaces = []
    for iface in get_all_ifaces.keys():
        all_ip = [a.__getstate__()['address'] for a in netif.get_interface(iface).addresses if a.af == netif.AddressFamily.INET]
        is_ip_exist = list(set(ipaddress).intersection(all_ip))
        if is_ip_exist:
            ifaces.append(iface)

    return ifaces
Example #8
0
def get_interface(ipaddress):
    get_all_ifaces = netif.list_interfaces()
    ifaces = []
    for iface in get_all_ifaces.keys():
        all_ip = [a.__getstate__()['address'] for a in netif.get_interface(iface).addresses if a.af == netif.AddressFamily.INET]
        is_ip_exist = list(set(ipaddress).intersection(all_ip))
        if is_ip_exist:
            ifaces.append(iface)

    return ifaces
Example #9
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()
 def disable_capabilities(self, iface, capabilities):
     self.middleware.call_sync('interface.get_instance', iface)
     iface = netif.get_interface(iface)
     disabled_capabilities = [
         c.name for c in iface.capabilities if c.name in capabilities
     ]
     iface.capabilities = {
         c
         for c in iface.capabilities if c.name not in capabilities
     }
     if disabled_capabilities:
         self.middleware.logger.debug(
             f'Disabling {",".join(disabled_capabilities)} capabilities for {iface}'
         )
Example #11
0
    def start(self, interface, source_address):
        if not self.server_name:
            raise RuntimeError('Please set server_name')

        if not self.on_request:
            raise RuntimeError('Please set on_request')

        self.address = source_address
        self.source_if = netif.get_interface(interface)
        self.hwaddr = str(self.source_if.link_address.address)
        self.bpf = bpf.BPF()
        self.bpf.open()
        self.bpf.immediate = True
        self.bpf.interface = interface
        self.bpf.apply_filter(BPF_PROGRAM)
Example #12
0
    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
Example #13
0
def iface_addresses(iface_name):
    addresses = []
    try:
        iface = netif.get_interface(iface_name)
    except KeyError:
        return addresses

    for addr in filter(lambda i: isinstance(i.address, ipaddress.IPv4Address),
                       iface.addresses):
        addresses.append({
            'addr': addr.address.exploded,
            'broadcast': addr.broadcast.exploded,
            'carp_ip': bool(addr.vhid),
        })
    return addresses
Example #14
0
    def verify(self, bridge_enable=False):
        vpn_interface = self.configstore.get('service.openvpn.dev')
        if bridge_enable:
            try:
                vpn_interface = netif.get_interface(vpn_interface)

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

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

        return['system']
 def enable_capabilities(self, iface, capabilities):
     enabled = []
     iface = netif.get_interface(iface)
     for capability in map(lambda c: getattr(netif.InterfaceCapability, c),
                           capabilities):
         current = iface.capabilities
         if capability in current:
             continue
         try:
             iface.capabilities = current | {capability}
         except OSError:
             pass
         else:
             enabled.append(capability.name)
     if enabled:
         self.middleware.logger.debug(
             f'Enabled {",".join(enabled)} capabilities for {iface}')
Example #16
0
    def down_interface(self, name):
        try:
            iface = netif.get_interface(name)
        except NameError:
            raise RpcException(errno.ENOENT, "Interface {0} not found".format(name))

        # Remove all IP addresses from interface
        for addr in iface.addresses:
            if addr.af == netif.AddressFamily.LINK:
                continue

            try:
                iface.remove_address(addr)
            except:
                # Continue anyway
                pass

        iface.down()
Example #17
0
    def down_interface(self, name):
        try:
            iface = netif.get_interface(name)
        except NameError:
            raise RpcException(errno.ENOENT, "Interface {0} not found".format(name))

        # Remove all IP addresses from interface
        for addr in iface.addresses:
            if addr.af == netif.AddressFamily.LINK:
                continue

            try:
                iface.remove_address(addr)
            except:
                # Continue anyway
                pass

        iface.down()
Example #18
0
    def __init__(self, *args, **kwargs):
        self.sipcalc = SIPCALC_PATH
        self.args = args
        self.iface = kwargs.get('iface', None)

        self.sipcalc_args = [self.sipcalc]
        for arg in args:
            self.sipcalc_args.append(str(arg))

        network = kwargs.get('network', None)
        if network:
            self.sipcalc_args.append(str(network))

        if self.iface:
            iface = netif.get_interface(self.iface)
            for addr in iface.addresses:
                if addr.af != netif.AddressFamily.INET:
                    continue
                self.sipcalc_args.append(
                    str(
                        ipaddress.IPv4Interface(
                            unicode('{}/{}'.format(str(addr.address),
                                                   str(addr.netmask))))))

        # If we already have the results of the `sipcalc` shell call
        # then do not do a redudant second call
        # For more explanation see the __new__ method of the `sipcalc_type`
        # class.
        self.sipcalc_out = kwargs.get('sipcalc_out', None)
        if self.sipcalc_out is None:
            p1 = pipeopen(
                string.join(self.sipcalc_args, ' '),
                allowfork=True,
                important=False,
            )
            self.sipcalc_out = p1.communicate()
            if self.sipcalc_out:
                self.sipcalc_out = self.sipcalc_out[0]
                if self.sipcalc_out:
                    self.sipcalc_out = self.sipcalc_out.split('\n')
Example #19
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)
Example #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
            ))
Example #21
0
    def sync_interface(self, name):
        try:
            data = self.middleware.call('datastore.query', 'network.interfaces', [('int_interface', '=', name)], {'get': True})
        except IndexError:
            self.logger.info('{} is not in interfaces database'.format(name))
            return

        aliases = self.middleware.call('datastore.query', 'network.alias', [('alias_interface_id', '=', data['id'])])

        iface = netif.get_interface(name)

        addrs_database = set()
        addrs_configured = set([
            a for a in iface.addresses
            if a.af != netif.AddressFamily.LINK
        ])

        has_ipv6 = data['int_ipv6auto'] or False

        if (
            not self.middleware.call('system.is_freenas') and
            self.middleware.call('notifier.failover_node') == 'B'
        ):
            ipv4_field = 'int_ipv4address_b'
            ipv6_field = 'int_ipv6address'
            alias_ipv4_field = 'alias_v4address_b'
            alias_ipv6_field = 'alias_v6address_b'
        else:
            ipv4_field = 'int_ipv4address'
            ipv6_field = 'int_ipv6address'
            alias_ipv4_field = 'alias_v4address'
            alias_ipv6_field = 'alias_v6address'

        dhclient_running, dhclient_pid = dhclient_status(name)
        if dhclient_running and data['int_dhcp']:
            leases = dhclient_leases(name)
            if leases:
                reg_address = re.search(r'fixed-address\s+(.+);', leases)
                reg_netmask = re.search(r'option subnet-mask\s+(.+);', leases)
                if reg_address and reg_netmask:
                    addrs_database.add(self.alias_to_addr({
                        'address': reg_address.group(1),
                        'netmask': reg_netmask.group(1),
                    }))
                else:
                    self.logger.info('Unable to get address from dhclient')
        else:
            if data[ipv4_field]:
                addrs_database.add(self.alias_to_addr({
                    'address': data[ipv4_field],
                    'netmask': data['int_v4netmaskbit'],
                }))
            if data[ipv6_field]:
                addrs_database.add(self.alias_to_addr({
                    'address': data[ipv6_field],
                    'netmask': data['int_v6netmaskbit'],
                }))
                has_ipv6 = True

        carp_vhid = carp_pass = None
        if data['int_vip']:
            addrs_database.add(self.alias_to_addr({
                'address': data['int_vip'],
                'netmask': '32',
                'vhid': data['int_vhid'],
            }))
            carp_vhid = data['int_vhid']
            carp_pass = data['int_pass'] or None

        for alias in aliases:
            if alias[alias_ipv4_field]:
                addrs_database.add(self.alias_to_addr({
                    'address': alias[alias_ipv4_field],
                    'netmask': alias['alias_v4netmaskbit'],
                }))
            if alias[alias_ipv6_field]:
                addrs_database.add(self.alias_to_addr({
                    'address': alias[alias_ipv6_field],
                    'netmask': alias['alias_v6netmaskbit'],
                }))
                has_ipv6 = True

            if alias['alias_vip']:
                addrs_database.add(self.alias_to_addr({
                    'address': alias['alias_vip'],
                    'netmask': '32',
                    'vhid': data['int_vhid'],
                }))

        if has_ipv6:
            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}

        # Remove addresses configured and not in database
        for addr in (addrs_configured - addrs_database):
            if (
                addr.af == netif.AddressFamily.INET6 and
                str(addr.address).startswith('fe80::')
            ):
                continue
            self.logger.debug('{}: removing {}'.format(name, addr))
            iface.remove_address(addr)

        # carp must be configured after removing addresses
        # in case removing the address removes the carp
        if carp_vhid:
            advskew = None
            if not self.middleware.call('notifier.is_freenas'):
                if self.middleware.call('notifier.failover_status') == 'MASTER':
                    advskew = 20
                else:
                    advskew = 80
            iface.carp_config = [netif.CarpConfig(carp_vhid, advskew=advskew, key=carp_pass)]

        # Add addresses in database and not configured
        for addr in (addrs_database - addrs_configured):
            self.logger.debug('{}: adding {}'.format(name, addr))
            iface.add_address(addr)

        # Apply interface options specified in GUI
        if data['int_options']:
            self.logger.info('{}: applying {}'.format(name, data['int_options']))
            proc = Popen('/sbin/ifconfig {} {}'.format(name, data['int_options']), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True)
            err = proc.communicate()[1]
            if err:
                self.logger.info('{}: error applying: {}'.format(name, err))

            # In case there is no MTU in interface options and it is currently
            # different than the default of 1500, revert it
            if data['int_options'].find('mtu') == -1 and iface.mtu != 1500:
                iface.mtu = 1500

        if netif.InterfaceFlags.UP not in iface.flags:
            iface.up()

        # If dhclient is not running and dhcp is configured, lets start it
        if not dhclient_running and data['int_dhcp']:
            self.logger.debug('Starting dhclient for {}'.format(name))
            gevent.spawn(self.dhclient_start, data['int_interface'])
        elif dhclient_running and not data['int_dhcp']:
            self.logger.debug('Killing dhclient for {}'.format(name))
            os.kill(dhclient_pid, signal.SIGTERM)

        if data['int_ipv6auto']:
            iface.nd6_flags = iface.nd6_flags | {netif.NeighborDiscoveryFlags.ACCEPT_RTADV}
            Popen(
                ['/etc/rc.d/rtsold', 'onestart'],
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE,
                close_fds=True,
            ).wait()
        else:
            iface.nd6_flags = iface.nd6_flags - {netif.NeighborDiscoveryFlags.ACCEPT_RTADV}
Example #22
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()
Example #23
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)
Example #24
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,
        })
Example #25
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
            ))
Example #26
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()
Example #27
0
    def sync_interface(self, name):
        try:
            data = self.middleware.call('datastore.query',
                                        'network.interfaces',
                                        [('int_interface', '=', name)],
                                        {'get': True})
        except IndexError:
            self.logger.info('{} is not in interfaces database'.format(name))
            return

        aliases = self.middleware.call(
            'datastore.query', 'network.alias',
            [('alias_interface_id', '=', data['id'])])

        iface = netif.get_interface(name)

        addrs_database = set()
        addrs_configured = set(
            [a for a in iface.addresses if a.af != netif.AddressFamily.LINK])

        has_ipv6 = data['int_ipv6auto'] or False

        if (not self.middleware.call('system.is_freenas')
                and self.middleware.call('notifier.failover_node') == 'B'):
            ipv4_field = 'int_ipv4address_b'
            ipv6_field = 'int_ipv6address'
            alias_ipv4_field = 'alias_v4address_b'
            alias_ipv6_field = 'alias_v6address_b'
        else:
            ipv4_field = 'int_ipv4address'
            ipv6_field = 'int_ipv6address'
            alias_ipv4_field = 'alias_v4address'
            alias_ipv6_field = 'alias_v6address'

        dhclient_running, dhclient_pid = dhclient_status(name)
        if dhclient_running and data['int_dhcp']:
            leases = dhclient_leases(name)
            if leases:
                reg_address = re.search(r'fixed-address\s+(.+);', leases)
                reg_netmask = re.search(r'option subnet-mask\s+(.+);', leases)
                if reg_address and reg_netmask:
                    addrs_database.add(
                        self.alias_to_addr({
                            'address': reg_address.group(1),
                            'netmask': reg_netmask.group(1),
                        }))
                else:
                    self.logger.info('Unable to get address from dhclient')
            if data[ipv6_field] and has_ipv6 is False:
                addrs_database.add(
                    self.alias_to_addr({
                        'address': data[ipv6_field],
                        'netmask': data['int_v6netmaskbit'],
                    }))
        else:
            if data[ipv4_field]:
                addrs_database.add(
                    self.alias_to_addr({
                        'address': data[ipv4_field],
                        'netmask': data['int_v4netmaskbit'],
                    }))
            if data[ipv6_field] and has_ipv6 is False:
                addrs_database.add(
                    self.alias_to_addr({
                        'address': data[ipv6_field],
                        'netmask': data['int_v6netmaskbit'],
                    }))
                has_ipv6 = True

        carp_vhid = carp_pass = None
        if data['int_vip']:
            addrs_database.add(
                self.alias_to_addr({
                    'address': data['int_vip'],
                    'netmask': '32',
                    'vhid': data['int_vhid'],
                }))
            carp_vhid = data['int_vhid']
            carp_pass = data['int_pass'] or None

        for alias in aliases:
            if alias[alias_ipv4_field]:
                addrs_database.add(
                    self.alias_to_addr({
                        'address': alias[alias_ipv4_field],
                        'netmask': alias['alias_v4netmaskbit'],
                    }))
            if alias[alias_ipv6_field]:
                addrs_database.add(
                    self.alias_to_addr({
                        'address': alias[alias_ipv6_field],
                        'netmask': alias['alias_v6netmaskbit'],
                    }))

            if alias['alias_vip']:
                addrs_database.add(
                    self.alias_to_addr({
                        'address': alias['alias_vip'],
                        'netmask': '32',
                        'vhid': data['int_vhid'],
                    }))

        if carp_vhid:
            advskew = None
            for cc in iface.carp_config:
                if cc.vhid == carp_vhid:
                    advskew = cc.advskew
                    break

        if has_ipv6:
            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
            }

        # Remove addresses configured and not in database
        for addr in (addrs_configured - addrs_database):
            if has_ipv6 and str(addr.address).startswith('fe80::'):
                continue
            self.logger.debug('{}: removing {}'.format(name, addr))
            iface.remove_address(addr)

        # carp must be configured after removing addresses
        # in case removing the address removes the carp
        if carp_vhid:
            if not self.middleware.call('notifier.is_freenas') and not advskew:
                if self.middleware.call('notifier.failover_node') == 'A':
                    advskew = 20
                else:
                    advskew = 80
            iface.carp_config = [
                netif.CarpConfig(carp_vhid, advskew=advskew, key=carp_pass)
            ]

        # Add addresses in database and not configured
        for addr in (addrs_database - addrs_configured):
            self.logger.debug('{}: adding {}'.format(name, addr))
            iface.add_address(addr)

        # Apply interface options specified in GUI
        if data['int_options']:
            self.logger.info('{}: applying {}'.format(name,
                                                      data['int_options']))
            proc = Popen('/sbin/ifconfig {} {}'.format(name,
                                                       data['int_options']),
                         shell=True,
                         stdout=subprocess.PIPE,
                         stderr=subprocess.PIPE,
                         close_fds=True)
            err = proc.communicate()[1]
            if err:
                self.logger.info('{}: error applying: {}'.format(name, err))

            # In case there is no MTU in interface options and it is currently
            # different than the default of 1500, revert it
            if data['int_options'].find('mtu') == -1 and iface.mtu != 1500:
                iface.mtu = 1500

        if netif.InterfaceFlags.UP not in iface.flags:
            iface.up()

        # If dhclient is not running and dhcp is configured, lets start it
        if not dhclient_running and data['int_dhcp']:
            self.logger.debug('Starting dhclient for {}'.format(name))
            gevent.spawn(self.dhclient_start, data['int_interface'])
        elif dhclient_running and not data['int_dhcp']:
            self.logger.debug('Killing dhclient for {}'.format(name))
            os.kill(dhclient_pid, signal.SIGTERM)

        if data['int_ipv6auto']:
            iface.nd6_flags = iface.nd6_flags | {
                netif.NeighborDiscoveryFlags.ACCEPT_RTADV
            }
            Popen(
                ['/etc/rc.d/rtsold', 'onestart'],
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE,
                close_fds=True,
            ).wait()
        else:
            iface.nd6_flags = iface.nd6_flags - {
                netif.NeighborDiscoveryFlags.ACCEPT_RTADV
            }
Example #28
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()
Example #29
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:
                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,
        })
Example #30
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()
Example #31
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()
Example #32
0
        def bind(old_lease, lease):
            self.logger.info('{0} DHCP lease on {1} from {2}, valid for {3} seconds'.format(
                'Renewed' if old_lease else 'Acquired',
                interface,
                client.server_address,
                lease.lifetime,
                interface
            ))

            if old_lease is None or lease.client_ip != old_lease.client_ip:
                self.logger.info('Assigning IP address {0} to interface {1}'.format(lease.client_ip, interface))
                alias = lease.client_interface
                iface = netif.get_interface(interface)

                if old_lease:
                    try:
                        addr = first_or_default(lambda a: a.address == old_lease.client_ip, iface.addresses)
                        if addr:
                            iface.remove_address(addr)
                    except OSError as err:
                        self.logger.error('Cannot remove alias {0}: {1}'.format(old_lease.client_ip, err.strerror))

                try:
                    iface.add_address(netif.InterfaceAddress(netif.AddressFamily.INET, alias))
                except OSError as err:
                    self.logger.error('Cannot add alias to {0}: {1}'.format(interface, err.strerror))

            if lease.router and self.configstore.get('network.dhcp.assign_gateway'):
                try:
                    rtable = netif.RoutingTable()
                    newroute = default_route(lease.router)
                    if rtable.default_route_ipv4 != newroute:
                        if rtable.default_route_ipv4:
                            self.logger.info('DHCP default route changed from {0} to {1}'.format(
                                rtable.default_route_ipv4,
                                newroute
                            ))
                            rtable.delete(rtable.default_route_ipv4)
                            rtable.add(default_route(lease.router))
                        else:
                            self.logger.info('Adding default route via {0}'.format(lease.router))
                            rtable.add(default_route(lease.router))
                except OSError as err:
                    self.logger.error('Cannot configure default route: {0}'.format(err.strerror))

            if lease.dns_addresses and self.configstore.get('network.dhcp.assign_dns'):
                inp = []
                addrs = []
                proc = subprocess.Popen(
                    ['/sbin/resolvconf', '-a', interface],
                    stdout=subprocess.PIPE,
                    stdin=subprocess.PIPE
                )

                for i in lease.dns_addresses:
                    # Filter out bogus DNS server addresses
                    if str(i) in ('127.0.0.1', '0.0.0.0', '255.255.255.255'):
                        continue

                    inp.append('nameserver {0}'.format(i))
                    addrs.append(i)

                if lease.domain_name:
                    inp.append('search {0}'.format(lease.domain_name))

                proc.communicate('\n'.join(inp).encode('ascii'))
                proc.wait()
                self.client.emit_event('network.dns.configured', {
                    'addresses': addrs,
                })
                self.logger.info('Updated DNS configuration')
            else:
                subprocess.call(['/sbin/resolvconf', '-d', interface])
                self.client.emit_event('network.dns.configured', {
                    'addresses': [],
                })
                self.logger.info('Deleted DNS configuration')
Example #33
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}')
Example #34
0
File: vm.py Project: binzyw/freenas
    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()
Example #35
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,
        })