diff options
Diffstat (limited to 'src')
| -rwxr-xr-x | src/conf_mode/firewall.py | 37 | ||||
| -rwxr-xr-x | src/conf_mode/interfaces-openvpn.py | 7 | ||||
| -rwxr-xr-x | src/conf_mode/nat.py | 15 | ||||
| -rwxr-xr-x | src/conf_mode/system_frr.py | 25 | ||||
| -rw-r--r-- | src/etc/sysctl.d/30-vyos-router.conf | 10 | ||||
| -rwxr-xr-x | src/init/vyos-router | 13 | ||||
| -rw-r--r-- | src/systemd/vyos-router.service | 1 | 
7 files changed, 56 insertions, 52 deletions
| diff --git a/src/conf_mode/firewall.py b/src/conf_mode/firewall.py index c3b1ee015..769cc598f 100755 --- a/src/conf_mode/firewall.py +++ b/src/conf_mode/firewall.py @@ -26,7 +26,7 @@ from vyos.config import Config  from vyos.configdict import node_changed  from vyos.configdiff import get_config_diff, Diff  from vyos.configdep import set_dependents, call_dependents -# from vyos.configverify import verify_interface_exists +from vyos.configverify import verify_interface_exists  from vyos.firewall import fqdn_config_parse  from vyos.firewall import geoip_update  from vyos.template import render @@ -38,6 +38,7 @@ from vyos.utils.process import process_named_running  from vyos.utils.process import rc_cmd  from vyos import ConfigError  from vyos import airbag +  airbag.enable()  nat_conf_script = 'nat.py' @@ -100,7 +101,7 @@ def geoip_updated(conf, firewall):          elif (path[0] == 'ipv6'):              set_name = f'GEOIP_CC6_{path[1]}_{path[2]}_{path[4]}'              out['ipv6_name'].append(set_name) -             +          updated = True      if 'delete' in node_diff: @@ -140,6 +141,14 @@ def get_config(config=None):      fqdn_config_parse(firewall) +    firewall['flowtable_enabled'] = False +    flow_offload = dict_search_args(firewall, 'global_options', 'flow_offload') +    if flow_offload and 'disable' not in flow_offload: +        for offload_type in ('software', 'hardware'): +            if dict_search_args(flow_offload, offload_type, 'interface'): +                firewall['flowtable_enabled'] = True +                break +      return firewall  def verify_rule(firewall, rule_conf, ipv6): @@ -327,6 +336,14 @@ def verify(firewall):                          for rule_id, rule_conf in name_conf['rule'].items():                              verify_rule(firewall, rule_conf, True) +    # Verify flow offload options +    flow_offload = dict_search_args(firewall, 'global_options', 'flow_offload') +    for offload_type in ('software', 'hardware'): +        interfaces = dict_search_args(flow_offload, offload_type, 'interface') or [] +        for interface in interfaces: +            # nft will raise an error when adding a non-existent interface to a flowtable +            verify_interface_exists(interface) +      return None  def generate(firewall): @@ -336,13 +353,15 @@ def generate(firewall):      # Determine if conntrack is needed      firewall['ipv4_conntrack_action'] = 'return'      firewall['ipv6_conntrack_action'] = 'return' - -    for rules, path in dict_search_recursive(firewall, 'rule'): -        if any(('state' in rule_conf or 'connection_status' in rule_conf) for rule_conf in rules.values()): -            if path[0] == 'ipv4': -                firewall['ipv4_conntrack_action'] = 'accept' -            elif path[0] == 'ipv6': -                firewall['ipv6_conntrack_action'] = 'accept' +    if firewall['flowtable_enabled']:  # Netfilter's flowtable offload requires conntrack +        firewall['ipv4_conntrack_action'] = 'accept' +        firewall['ipv6_conntrack_action'] = 'accept' +    else:  # Check if conntrack is needed by firewall rules +        for proto in ('ipv4', 'ipv6'): +            for rules, _ in dict_search_recursive(firewall.get(proto, {}), 'rule'): +                if any(('state' in rule_conf or 'connection_status' in rule_conf) for rule_conf in rules.values()): +                    firewall[f'{proto}_conntrack_action'] = 'accept' +                    break      render(nftables_conf, 'firewall/nftables.j2', firewall)      return None diff --git a/src/conf_mode/interfaces-openvpn.py b/src/conf_mode/interfaces-openvpn.py index 1d0feb56f..9f4de990c 100755 --- a/src/conf_mode/interfaces-openvpn.py +++ b/src/conf_mode/interfaces-openvpn.py @@ -344,9 +344,6 @@ def verify(openvpn):              if v6_subnets > 1:                  raise ConfigError('Cannot specify more than 1 IPv6 server subnet') -            if v6_subnets > 0 and v4_subnets == 0: -                raise ConfigError('IPv6 server requires an IPv4 server subnet') -              for subnet in tmp:                  if is_ipv4(subnet):                      subnet = IPv4Network(subnet) @@ -388,6 +385,10 @@ def verify(openvpn):                          for v4PoolNet in v4PoolNets:                              if IPv4Address(client['ip'][0]) in v4PoolNet:                                  print(f'Warning: Client "{client["name"]}" IP {client["ip"][0]} is in server IP pool, it is not reserved for this client.') +            # configuring a client_ip_pool will set 'server ... nopool' which is currently incompatible with 'server-ipv6' (probably to be fixed upstream) +            for subnet in (dict_search('server.subnet', openvpn) or []): +                if is_ipv6(subnet): +                    raise ConfigError(f'Setting client-ip-pool is incompatible having an IPv6 server subnet.')          for subnet in (dict_search('server.subnet', openvpn) or []):              if is_ipv6(subnet): diff --git a/src/conf_mode/nat.py b/src/conf_mode/nat.py index 08e96f10b..e37a7011c 100755 --- a/src/conf_mode/nat.py +++ b/src/conf_mode/nat.py @@ -195,11 +195,10 @@ def verify(nat):      if dict_search('source.rule', nat):          for rule, config in dict_search('source.rule', nat).items():              err_msg = f'Source NAT configuration error in rule {rule}:' -            if 'outbound_interface' not in config: -                raise ConfigError(f'{err_msg} outbound-interface not specified') -            if config['outbound_interface'] not in 'any' and config['outbound_interface'] not in interfaces(): -                Warning(f'rule "{rule}" interface "{config["outbound_interface"]}" does not exist on this system') +            if 'outbound_interface' in config: +                if config['outbound_interface'] not in 'any' and config['outbound_interface'] not in interfaces(): +                    Warning(f'rule "{rule}" interface "{config["outbound_interface"]}" does not exist on this system')              if not dict_search('translation.address', config) and not dict_search('translation.port', config):                  if 'exclude' not in config and 'backend' not in config['load_balance']: @@ -218,11 +217,9 @@ def verify(nat):          for rule, config in dict_search('destination.rule', nat).items():              err_msg = f'Destination NAT configuration error in rule {rule}:' -            if 'inbound_interface' not in config: -                raise ConfigError(f'{err_msg}\n' \ -                                  'inbound-interface not specified') -            elif config['inbound_interface'] not in 'any' and config['inbound_interface'] not in interfaces(): -                Warning(f'rule "{rule}" interface "{config["inbound_interface"]}" does not exist on this system') +            if 'inbound_interface' in config: +                if config['inbound_interface'] not in 'any' and config['inbound_interface'] not in interfaces(): +                    Warning(f'rule "{rule}" interface "{config["inbound_interface"]}" does not exist on this system')              if not dict_search('translation.address', config) and not dict_search('translation.port', config) and 'redirect' not in config['translation']:                  if 'exclude' not in config and 'backend' not in config['load_balance']: diff --git a/src/conf_mode/system_frr.py b/src/conf_mode/system_frr.py index fb252238a..d8224b3c3 100755 --- a/src/conf_mode/system_frr.py +++ b/src/conf_mode/system_frr.py @@ -22,17 +22,14 @@ from vyos import airbag  from vyos.config import Config  from vyos.logger import syslog  from vyos.template import render_to_string +from vyos.utils.boot import boot_configuration_complete  from vyos.utils.file import read_file  from vyos.utils.file import write_file -from vyos.utils.process import run +from vyos.utils.process import call  airbag.enable()  # path to daemons config and config status files  config_file = '/etc/frr/daemons' -vyos_status_file = '/tmp/vyos-config-status' -# path to watchfrr for FRR control -watchfrr = '/usr/lib/frr/watchfrr.sh' -  def get_config(config=None):      if config: @@ -45,12 +42,10 @@ def get_config(config=None):      return frr_config -  def verify(frr_config):      # Nothing to verify here      pass -  def generate(frr_config):      # read daemons config file      daemons_config_current = read_file(config_file) @@ -62,25 +57,21 @@ def generate(frr_config):          write_file(config_file, daemons_config_new)          frr_config['config_file_changed'] = True -  def apply(frr_config): -    # check if this is initial commit during boot or intiated by CLI -    # if the file exists, this must be CLI commit -    commit_type_cli = Path(vyos_status_file).exists()      # display warning to user -    if commit_type_cli and frr_config.get('config_file_changed'): +    if boot_configuration_complete() and frr_config.get('config_file_changed'):          # Since FRR restart is not safe thing, better to give          # control over this to users          print('''          You need to reboot a router (preferred) or restart FRR          to apply changes in modules settings          ''') -    # restart FRR automatically. DUring the initial boot this should be -    # safe in most cases -    if not commit_type_cli and frr_config.get('config_file_changed'): -        syslog.warning('Restarting FRR to apply changes in modules') -        run(f'{watchfrr} restart') +    # restart FRR automatically +    # During initial boot this should be safe in most cases +    if not boot_configuration_complete() and frr_config.get('config_file_changed'): +        syslog.warning('Restarting FRR to apply changes in modules') +        call(f'systemctl restart frr.service')  if __name__ == '__main__':      try: diff --git a/src/etc/sysctl.d/30-vyos-router.conf b/src/etc/sysctl.d/30-vyos-router.conf index ad43390bb..fcdc1b21d 100644 --- a/src/etc/sysctl.d/30-vyos-router.conf +++ b/src/etc/sysctl.d/30-vyos-router.conf @@ -98,15 +98,6 @@ net.ipv6.route.skip_notify_on_dev_down=1  # Default value of 20 seems to interfere with larger OSPF and VRRP setups  net.ipv4.igmp_max_memberships = 512 -# Increase default garbage collection thresholds -net.ipv4.neigh.default.gc_thresh1 = 1024 -net.ipv4.neigh.default.gc_thresh2 = 4096 -net.ipv4.neigh.default.gc_thresh3 = 8192 -# -net.ipv6.neigh.default.gc_thresh1 = 1024 -net.ipv6.neigh.default.gc_thresh2 = 4096 -net.ipv6.neigh.default.gc_thresh3 = 8192 -  # Enable global RFS (Receive Flow Steering) configuration. RFS is inactive  # until explicitly configured at the interface level  net.core.rps_sock_flow_entries = 32768 @@ -114,3 +105,4 @@ net.core.rps_sock_flow_entries = 32768  # Congestion control  net.core.default_qdisc=fq  net.ipv4.tcp_congestion_control=bbr + diff --git a/src/init/vyos-router b/src/init/vyos-router index a5d1a31fa..9ef1fa335 100755 --- a/src/init/vyos-router +++ b/src/init/vyos-router @@ -340,16 +340,14 @@ start ()      nfct helper add tns inet6 tcp      nft -f /usr/share/vyos/vyos-firewall-init.conf || log_failure_msg "could not initiate firewall rules" -    rm -f /etc/hostname -    ${vyos_conf_scripts_dir}/host_name.py || log_failure_msg "could not reset host-name" -    systemctl start frr.service -      # As VyOS does not execute commands that are not present in the CLI we call      # the script by hand to have a single source for the login banner and MOTD      ${vyos_conf_scripts_dir}/system_console.py || log_failure_msg "could not reset serial console"      ${vyos_conf_scripts_dir}/system-login.py || log_failure_msg "could not reset system login"      ${vyos_conf_scripts_dir}/system-login-banner.py || log_failure_msg "could not reset motd and issue files"      ${vyos_conf_scripts_dir}/system-option.py || log_failure_msg "could not reset system option files" +    ${vyos_conf_scripts_dir}/system-ip.py || log_failure_msg "could not reset system IPv4 options" +    ${vyos_conf_scripts_dir}/system-ipv6.py || log_failure_msg "could not reset system IPv6 options"      ${vyos_conf_scripts_dir}/conntrack.py || log_failure_msg "could not reset conntrack subsystem"      ${vyos_conf_scripts_dir}/container.py || log_failure_msg "could not reset container subsystem" @@ -376,6 +374,13 @@ start ()        && chgrp ${GROUP} ${vyatta_configdir}      log_action_end_msg $? +    rm -f /etc/hostname +    ${vyos_conf_scripts_dir}/host_name.py || log_failure_msg "could not reset host-name" +    ${vyos_conf_scripts_dir}/system_frr.py || log_failure_msg "could not reset FRR config" +    # If for any reason FRR was not started by system_frr.py - start it anyways. +    # This is a safety net! +    systemctl start frr.service +      disabled bootfile || init_bootfile      cleanup_post_commit_hooks diff --git a/src/systemd/vyos-router.service b/src/systemd/vyos-router.service index 6f683cebb..7a1638f11 100644 --- a/src/systemd/vyos-router.service +++ b/src/systemd/vyos-router.service @@ -1,7 +1,6 @@  [Unit]  Description=VyOS Router  After=systemd-journald-dev-log.socket time-sync.target local-fs.target cloud-config.service -Requires=frr.service  Conflicts=shutdown.target  Before=systemd-user-sessions.service | 
